To Be Or Not To Be: Profit

Xếp hạn tín dụng. Xếp hạn tín dụng (Credit Classificatin hay Credit Scoring) đóng một vai trò quan trọng đối với lợi nhuận và phát triển bền vững của ngân hàng nói riêng cũng như các tổ chức tài chính cho vay khác. Sự kiện cuộc khủng hoảng tài chính dẫn đến sự sụp đổ của một loạt các định chế tài chính nói chung và ngân hàng nói riêng đã thức tỉnh các tổ chức này chú trọng hơn đến vai trò của thẩm định tín dụng trong hoạt động của mình. Hầu hết lợi nhuận của các ngân hàng đến từ hoạt động cấp tín dụng và cho vay. Cấp tín dụng là một trong những hoạt động tạo ra một tỉ trọng lớn về doanh thu và lợi nhuận cho ngân hàng nhưng cũng tiềm ẩn rất nhiều rủi ro (Zakrzewska, 2007). Theo Thomas et al. (2002), các ngân hàng cần một phương pháp xếp hạng tín dụng mà thỏa mãn những đòi hỏi sau: (1) chi phí rẻ và dễ vận hành, (2) nhanh chóng và ổn định, (3) đưa ra những quyết định nhất quán dựa trên các thông tin khách quan không phụ thuộc vào cảm xúc và tình cảm chủ quan của con người, và (4) hiệu quả của hệ phương pháp xếp hạng tín dụng có thể dễ dàng kiểm tra, điều chỉnh ở bất kì thời điểm nào nhằm điều chỉnh kịp thời với những thay đổi về chính sách hoặc điều kiện của nền kinh tế.

Cách tiếp cận thường thấy. Xếp hạng tín dụng là một bài toán mà tổ chức tín dụng - ngân hàng đã xây dựng và áp dụng. Tuy vậy hầu hết hướng đi hoặc triển khai - áp dụng chỉ mới tập trung vào việc so sánh mức độ chính xác chung (Accuracy) hoặc AUC/Gini giữa các mô hình rồi đưa ra khuyến cáo lựa chọn và triển khai sử dụng mô hình. Đây là một hướng tiếp cận chưa đúng vì nó bỏ qua mục tiêu cơ bản của một tổ chức hoạt động vì lợi nhuận. Điều này được giải thích ở mục ngay dưới đây.

Cách tiếp cận mới: Hướng đến lợi nhuận. Một mô hình hoặc cách tiếp cận có Accuracy, thậm chí là AUC/Gini cao lại là mô hình mang lại nhiều thiệt hại về tiền cho tổ chức sử dụng. Nguyên nhân là các mô hình / cách tiếp cận gần như quên mất rằng các tổ chức hoạt động vì lợi nhuận thì mục tiêu hàng đầu là PROFIT chứ không phải là Accuracy, AUC hay Gini. AUC/Gini chỉ là điều kiện cần, là dấu hiệu của một mô hình tốt về mặt lợi nhuận cho tổ chức sử dụng. Để minh họa chúng ta xét bộ dữ liệu giả định chỉ có 9 khách hàng xin vay tín dụng với số tiền vay đề xuất thể hiện ở cột LOAN. Cột Model1 và Model2 lần lượt là nhãn được dự báo từ mô hình cận 1 và mô hình 2 còn Actual là nhãn thực tế:

ID Loan Actual Model1 Model2
1 1000 Good Good Bad
2 800 Bad Good Bad
3 1200 Good Good Bad
4 800 Good Bad Bad
5 2000 Good Good Good
6 1500 Good Good Bad
7 1700 Good Good Good
8 3000 Bad Bad Bad
9 1200 Good Good Good

Accuracy là 77.78% và 55.56% lần lượt cho Model 1 và Model 2 như chúng ta có thể thấy qua, ví dụ, ma trận nhầm lẫn:

## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Bad Good
##       Bad    1    1
##       Good   1    6
##                                           
##                Accuracy : 0.7778          
##                  95% CI : (0.3999, 0.9719)
##     No Information Rate : 0.7778          
##     P-Value [Acc > NIR] : 0.6781          
##                                           
##                   Kappa : 0.3571          
##                                           
##  Mcnemar's Test P-Value : 1.0000          
##                                           
##             Sensitivity : 0.5000          
##             Specificity : 0.8571          
##          Pos Pred Value : 0.5000          
##          Neg Pred Value : 0.8571          
##              Prevalence : 0.2222          
##          Detection Rate : 0.1111          
##    Detection Prevalence : 0.2222          
##       Balanced Accuracy : 0.6786          
##                                           
##        'Positive' Class : Bad             
## 
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction Bad Good
##       Bad    2    4
##       Good   0    3
##                                         
##                Accuracy : 0.5556        
##                  95% CI : (0.212, 0.863)
##     No Information Rate : 0.7778        
##     P-Value [Acc > NIR] : 0.9696        
##                                         
##                   Kappa : 0.25          
##                                         
##  Mcnemar's Test P-Value : 0.1336        
##                                         
##             Sensitivity : 1.0000        
##             Specificity : 0.4286        
##          Pos Pred Value : 0.3333        
##          Neg Pred Value : 1.0000        
##              Prevalence : 0.2222        
##          Detection Rate : 0.2222        
##    Detection Prevalence : 0.6667        
##       Balanced Accuracy : 0.7143        
##                                         
##        'Positive' Class : Bad           
## 

Nếu căn cứ vào Accuracy chúng ta dễ bị lôi kéo với nhận định rằng mô hình 1 sẽ nên được áp dụng và triển khai cho việc cấp tín dụng. Tuy nhiên đây lại là một nhận định sai. Thực vậy nếu chúng ta giả thiết rằng: (1) nếu hồ sơ xin vay thực sự là tốt và mô hình dự đoán đúng là tốt thì lợi nhuận thu về sẽ là 10% của khoản vay, (2) nếu hồ sơ thực sự là xấu nhưng mô hình dự đoán nhầm thành tốt thì mất hoàn toàn khoản đã cho vay, và (3) tất cả các trường hợp mà mô hình dự đoán là xấu thì sẽ không cho vay và do vậy lợi nhuận là 0. Dưới đây là tính toán lợi nhuận tương ứng cho mô hình 1 và mô hình 2 đối với từng khách hàng:

ID Loan Actual Model1 Model2 Profit1 Profit2
1 1000 Good Good Bad 100 0
2 800 Bad Good Bad -800 0
3 1200 Good Good Bad 120 0
4 800 Good Bad Bad 0 0
5 2000 Good Good Good 200 200
6 1500 Good Good Bad 150 0
7 1700 Good Good Good 170 170
8 3000 Bad Bad Bad 0 0
9 1200 Good Good Good 120 120

Mô hình 1 dự báo sai cho khách hàng thứ 3 và do vậy ngân hàng mất trắng 800$ khi cho khách hàng này vay. Thành thử dù rằng mô hình 1 có Accuracy cao nhưng lợi nhuận mang về nếu sử dụng mô hình 1 chi chưa bằng 1 / 8 nếu sử dụng mô hình 2 như ta có thể thấy:

## Profit1 Profit2 
##      60     490

Điều tương tự cũng áp dụng cho nếu lựa chọn mô hình căn cứ vào AUC/Gini: không có gì đảm bảo rằng một mô hình có AUC/Gini cao lại là mô hình mang lại nhiều lợi nhuận cho tổ chức sử dụng và điều này càng đúng trong tình huống mà bộ dữ liệu là mất cân bằng ở mức cao (như bộ dữ liệu từ cuộc thi Kalapa’s Credit Scoring Challenge). Nhắc lại: đó chỉ mới là điều kiện cần. Một mô hình tuy có AUC/Gini thấp nhưng lại có thể dự báo tốt đối với nhóm khách hàng xấu (tức Recall cao) thì đó có thể là mô hình nên được sử dụng.

Nguyên nhân là sai lầm loại I và sai lầm loại II đi kèm với cái giá phải trả là khác nhau. Nhân chuyện Virut Corona đang là hot trend thì nói thế này cho đẽ nhớ: nếu một người bị nhiễm Corona nhưng mô hình chẩn đoán sai thành không nhiễm thì cái giá phải trả đắt hơn nhiều một người không bị Corona nhưng bị chẩn đoán sai thành nhiễm Corona. Tương tự, nếu dự báo nhầm một khách hàng tốt thành khách hàng xấu thì ngân hàng bỏ lỡ một cơ hội kiếm lãi trên khoản tiền cho vay nhưng dự báo sai một khách hàng xấu thành tốt thì sẽ mất trắng khoản đầu tư của mình.

Tiêu chí lựa chọn và đánh giá phẩm chất của mô hình phân cho bài toán Credit Scoring có thể tham khảo chi tiết ở trang 260, chương 11 (Measuring Performance in Classification Models) cuốn Applied Predictive Modeling.

Bayesian Optimization for Searching Cutoff Maximizes Profit

Các bước thực hiện Bayesian Optimization ở post trước có thể được áp dụng để tìm kiếm ngưỡng phân loại (Classification Cutoff) sao cho tối đa hóa lợi nhuận. Trước hết sử dụng lại một số codes từ post này từ bước chuẩn bị dữ liệu đến huấn luyện Xgboost mặc định:

## 
## Missing value imputation by random forests
## 
##   Variables to impute:       MORTDUE, VALUE, REASON, JOB, YOJ, DEROG, DELINQ, CLAGE, NINQ, CLNO, DEBTINC
##   Variables used to impute:  BAD, LOAN, MORTDUE, VALUE, REASON, JOB, YOJ, DEROG, DELINQ, CLAGE, NINQ, CLNO, DEBTINC
## iter 1:  ...........
## iter 2:  ...........
## iter 3:  ...........

Các mô Machine Learning - kể cả Xgboost sẽ tính toán xác suất vỡ nợ PD (Probability of Default) và sử dụng ngưỡng mặc định là 0.5 để dự báo nhãn rồi tính toán ma trận nhầm lẫn (hàm confusion_matrix() của Python và confusionMatrix() của R). Tất cả các tool khác đều mặc định sử dụng ngưỡng này. Do vậy, để khảo sát lợi nhuận tương ứng với mỗi ngưỡng chúng ta phải viết một hàm. Dưới đây chúng ta viết một hàm tính toán lợi nhuận cho 1000 khách hàng xin vay từ 1788 khách hàng ở bộ dữ liệu test theo phương pháp lấy mẫu ngẫu nhiên rồi lặp lại quá trình này 100 lần để tính lợi nhuận (Profit) trung bình tương ứng với một ngưỡng cutoff được chọn. Các giả thiết khách là:

  1. Lãi suất là 10% cho các khoản vay được cấp.
  2. Nếu một khách hàng xấu (Bad) nhưng mô hình Xgboost dự bao sai thành tốt (Good) thì ngân hàng mất trắng khoản vay.
  3. Với các khách hàng mà Xgboost dự báo là xấu thì ngân hàng không cấp khoản vay (đương nhiên rồi).

Hàm đó như sau:

Kế tiếp thực hiện Bayesian Optimization theo các thủ tục như đã được trình bày ở post trước:

## 
##  Best Parameters Found: 
## Round = 16   cutoff = 0.1229 Value = 989.0822
##     user   system  elapsed 
## 6308.511 5889.070  537.624

kết quả ngưỡng tối ưu và lợi nhuận trung bình tương ứng là:

##    cutoff 
## 0.1228951

chúng ta có theo dõi sự thay đổi của lợi nhuận trung bình này tương ứng với cutoff được chọn trong đó ngưỡng mà tối đa lợi nhuận trung bình này là điểm màu đỏ:

NSử dụng ngưỡng bestRate tối ưu tìm được để sử dụng cho quyết định cho một khách hàng cụ thể được vay hay không và so sánh với phương án sử dụng ngưỡng mặc định. Trước hết tính toán lợi nhuận của hai phương án (ProfitDefault và ProfitCutoff) tướng ứng với việc sử dụng ngưỡng mặc định (Des1) và ngưỡng tối ưu (Des2):

BAD LOAN PD Rate Des1 Des2 ProfitDefault ProfitCutoff
1 1300 0.8565313 0.1 Bad Bad 0 0
1 1800 0.9763749 0.1 Bad Bad 0 0
1 2000 0.9932522 0.1 Bad Bad 0 0
1 2000 0.8356385 0.1 Bad Bad 0 0
1 2000 0.9899027 0.1 Bad Bad 0 0
1 2000 0.9504011 0.1 Bad Bad 0 0
1 2000 0.8772576 0.1 Bad Bad 0 0
0 2300 0.0774459 0.1 Good Good 230 230
1 2300 0.9933444 0.1 Bad Bad 0 0
1 2400 0.9401898 0.1 Bad Bad 0 0

Lợi nhuận của việc sử dụng ngưỡng tối ưu cho Creding Scoring là vượt trội so với sử dụng ngưỡng mặc định như chúng ta có thể thấy trong Figure 2:

Một lần nữa chúng ta có thể xác nhận rằng cách tiếp cận 1 (hay rộng hơn là mô hình 1) sử dụng ngưỡng mặc định có Accuracy cao hơn hẳn dù đây là cách tiếp cận tạo ra lợi nhuận không cao:

## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  Bad Good
##       Bad   248   20
##       Good  104 1416
##                                          
##                Accuracy : 0.9306         
##                  95% CI : (0.9179, 0.942)
##     No Information Rate : 0.8031         
##     P-Value [Acc > NIR] : < 2.2e-16      
##                                          
##                   Kappa : 0.759          
##                                          
##  Mcnemar's Test P-Value : 9.081e-14      
##                                          
##             Sensitivity : 0.7045         
##             Specificity : 0.9861         
##          Pos Pred Value : 0.9254         
##          Neg Pred Value : 0.9316         
##              Prevalence : 0.1969         
##          Detection Rate : 0.1387         
##    Detection Prevalence : 0.1499         
##       Balanced Accuracy : 0.8453         
##                                          
##        'Positive' Class : Bad            
## 
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  Bad Good
##       Bad   316  202
##       Good   36 1234
##                                           
##                Accuracy : 0.8669          
##                  95% CI : (0.8503, 0.8823)
##     No Information Rate : 0.8031          
##     P-Value [Acc > NIR] : 7.8e-13         
##                                           
##                   Kappa : 0.6427          
##                                           
##  Mcnemar's Test P-Value : < 2e-16         
##                                           
##             Sensitivity : 0.8977          
##             Specificity : 0.8593          
##          Pos Pred Value : 0.6100          
##          Neg Pred Value : 0.9717          
##              Prevalence : 0.1969          
##          Detection Rate : 0.1767          
##    Detection Prevalence : 0.2897          
##       Balanced Accuracy : 0.8785          
##                                           
##        'Positive' Class : Bad             
## 

Nguyên nhân là mô hình sử dụng Optimal cutoff = bestRate tuy có Accuracy thấp hơn nhưng đây chính lại là mô hình có Recall (hay Sensitivity) cao hơn. Nhắc lại rằng Recall/Sensitivity là thước đo đánh giá khả năng phân biệt - dự báo nhóm khách hàng xấu.

Như đã phân tích ở mục trước, nguyên nhân là, ví dụ, khách hàng ở dòng đầu tiên thì sử dụng ngưỡng mặc định 0.5 sẽ được cho là khách hàng tốt (vì PD < 0.5) nhưng thực tế đây là khách hàng xấu (BAD = 1) nên khi cấp một khoản vay cho khách hàng này ngân hàng sẽ mất trắng vốn (lợi nhuận tương ứng của khách hàng này mang dấu âm trên cột ProfitCutoff) trong khi đó “mô hình” phân loại sử dụng ngưỡng tối ưu sẽ xếp khách này là xấu (và thực tế đúng là vậy) như ta thấy:

BAD LOAN PD Rate Des1 Des2 ProfitDefault ProfitCutoff TrueLabel
1 5000 0.4625529 0.1 Good Bad -5000 0 Bad
1 5000 0.3907019 0.1 Good Bad -5000 0 Bad
1 5700 0.3001138 0.1 Good Bad -5700 0 Bad
1 7000 0.3496028 0.1 Good Bad -7000 0 Bad
1 8600 0.3134321 0.1 Good Bad -8600 0 Bad
1 8700 0.1312989 0.1 Good Bad -8700 0 Bad

Brief Summary

  1. Bayesian Optimization không chỉ được sử dụng để tinh chỉnh và tìm kiếm tham số tối ưu cho các mô hình Machine Learning mà còn có thể được sử dụng để tối ưu hóa Lợi Nhuận - một mục tiêu cụ thể và đặc thù của bài toán Credit Scoring.

  2. Với các tổ chức hoạt động vì lợi nhuận thì Accuracy, AUC/Gini hay bất cứ tiêu chí gì có thể nghĩ ra mà không cải thiện được lợi nhuận của tổ chức thì cũng không có ý nghĩa nhiều ngoài giá trị tham khảo. Trong một số tình huống cụ thể như kinh tế bất ổn cần siết chặt tín dụng và hoạt động cho vay thì rủi ro về tổn thất vốn là mục tiêu hàng đầu lúc đó thì Recall/Sensitivity - chỉ tiêu đánh chất lượng phân loại cho nhóm khách hàng xấu có thể được ưu tiên hàng đầu.

  3. Ngoài sử dụng Bayesian Optimization chúng ta có thể tìm ngưỡng tối ưu một cách thủ công (nhưng hiệu quả) nếu sử dụng R hoặc sử dụng Python

References

  1. Martens, D., B. Baesens, T. Van Gestel, and J. Vanthienen. 2007. “Comprehensible Credit Scoring Models Using Rule Extraction from Support Vector Machines.” European Journal of Operational Research 183:1466–1476.

  2. Baesens, B., Roesch, D., & Scheule, H. (2016). Credit risk analytics: Measurement techniques, applications, and examples in SAS. John Wiley & Sons.

  3. Siddiqi, N. (2012). Credit risk scorecards: developing and implementing intelligent credit scoring. John Wiley & Sons.

  4. Anderson R (2007): The Credit Scoring Toolkit: Theory and Practice for Retail Credit Risk Management and Decision Automation. Oxford, Oxford University Press.

  5. Thomas LC (2009): Consumer Credit Models: Pricing, Profit, and Portfolio. Oxford, Oxford University Press.

  6. Ben-David, A., & Frank, E. (2009). Accuracy of machine learning models versus “hand crafted” expert systems–a credit scoring case study. Expert Systems with Applications, 36(3), 5264-5271.

LS0tCnRpdGxlOiAnQ2xhc3NpZmljYXRpb24gQ3V0b2ZmIE1heGltaXplcyBQcm9maXQgdXNpbmcgQmF5ZXNpYW4gT3B0aW1pemF0aW9uJwphdXRob3I6ICdBdXRob3I6IE5ndXllbiBDaGkgRHVuZycKc3VidGl0bGU6ICJSIE1hY2hpbmUgTGVhcm5pbmcgU2VyaWVzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAjY29kZV9mb2xkaW5nOiBoaWRlCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4KICAgICMgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiAiZmxhdGx5IgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKLS0tCgpgYGB7ciBzZXR1cCxpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcud2lkdGggPSAxMCwgZmlnLmhlaWdodCA9IDYpCmBgYAoKIVtdKC9ob21lL2NoaWR1bmcvRG9jdW1lbnRzL2xvYW4ucG5nKQoKCiMgVG8gQmUgT3IgTm90IFRvIEJlOiBQcm9maXQKCioqWOG6v3AgaOG6oW4gdMOtbiBk4bulbmcqKi4gWOG6v3AgaOG6oW4gdMOtbiBk4bulbmcgKENyZWRpdCBDbGFzc2lmaWNhdGluIGhheSBDcmVkaXQgU2NvcmluZykgxJHDs25nIG3hu5l0IHZhaSB0csOyIHF1YW4gdHLhu41uZyDEkeG7kWkgduG7m2kgbOG7o2kgbmh14bqtbiB2w6AgcGjDoXQgdHJp4buDbiBi4buBbiB24buvbmcgY+G7p2EgbmfDom4gaMOgbmcgbsOzaSByacOqbmcgY8WpbmcgbmjGsCBjw6FjIHThu5UgY2jhu6ljIHTDoGkgY2jDrW5oIGNobyB2YXkga2jDoWMuIFPhu7Ega2nhu4duIGN14buZYyBraOG7p25nIGhv4bqjbmcgdMOgaSBjaMOtbmggZOG6q24gxJHhur9uIHPhu7Egc+G7pXAgxJHhu5UgY+G7p2EgbeG7mXQgbG/huqF0IGPDoWMgxJHhu4tuaCBjaOG6vyB0w6BpIGNow61uaCBuw7NpIGNodW5nIHbDoCBuZ8OibiBow6BuZyBuw7NpIHJpw6puZyDEkcOjIHRo4bupYyB04buJbmggY8OhYyB04buVIGNo4bupYyBuw6B5IGNow7ogdHLhu41uZyBoxqFuIMSR4bq/biB2YWkgdHLDsiBj4bunYSB0aOG6qW0gxJHhu4tuaCB0w61uIGThu6VuZyB0cm9uZyBob+G6oXQgxJHhu5luZyBj4bunYSBtw6xuaC4gSOG6p3UgaOG6v3QgbOG7o2kgbmh14bqtbiBj4bunYSBjw6FjIG5nw6JuIGjDoG5nIMSR4bq/biB04burIGhv4bqhdCDEkeG7mW5nIGPhuqVwIHTDrW4gZOG7pW5nIHbDoCBjaG8gdmF5LiBD4bqlcCB0w61uIGThu6VuZyBsw6AgbeG7mXQgdHJvbmcgbmjhu69uZyBob+G6oXQgxJHhu5luZyB04bqhbyByYSBt4buZdCB04buJIHRy4buNbmcgbOG7m24gduG7gSBkb2FuaCB0aHUgdsOgIGzhu6NpIG5odeG6rW4gY2hvIG5nw6JuIGjDoG5nIG5oxrBuZyBjxaluZyB0aeG7gW0g4bqpbiBy4bqldCBuaGnhu4F1IHLhu6dpIHJvIChaYWtyemV3c2thLCAyMDA3KS4gIFRoZW8gVGhvbWFzIGV0IGFsLiAoMjAwMiksIGPDoWMgbmfDom4gaMOgbmcgY+G6p24gbeG7mXQgcGjGsMahbmcgcGjDoXAgeOG6v3AgaOG6oW5nIHTDrW4gZOG7pW5nIG3DoCB0aOG7j2EgbcOjbiBuaOG7r25nIMSRw7JpIGjhu49pIHNhdTogKDEpIGNoaSBwaMOtIHLhursgdsOgIGThu4UgduG6rW4gaMOgbmgsICgyKSBuaGFuaCBjaMOzbmcgdsOgIOG7lW4gxJHhu4tuaCwgKDMpIMSRxrBhIHJhIG5o4buvbmcgcXV54bq/dCDEkeG7i25oIG5o4bqldCBxdcOhbiBk4buxYSB0csOqbiBjw6FjIHRow7RuZyB0aW4ga2jDoWNoIHF1YW4ga2jDtG5nIHBo4bulIHRodeG7mWMgdsOgbyBj4bqjbSB4w7pjIHbDoCB0w6xuaCBj4bqjbSBjaOG7pyBxdWFuIGPhu6dhIGNvbiBuZ8aw4budaSwgdsOgICg0KSBoaeG7h3UgcXXhuqMgY+G7p2EgaOG7hyBwaMawxqFuZyBwaMOhcCB44bq/cCBo4bqhbmcgdMOtbiBk4bulbmcgY8OzIHRo4buDIGThu4UgZMOgbmcga2nhu4NtIHRyYSwgxJFp4buBdSBjaOG7iW5oIOG7nyBi4bqldCBrw6wgdGjhu51pIMSRaeG7g20gbsOgbyBuaOG6sW0gxJFp4buBdSBjaOG7iW5oIGvhu4twIHRo4budaSB24bubaSBuaOG7r25nIHRoYXkgxJHhu5VpIHbhu4EgY2jDrW5oIHPDoWNoIGhv4bq3YyDEkWnhu4F1IGtp4buHbiBj4bunYSBu4buBbiBraW5oIHThur8uCgoqKkPDoWNoIHRp4bq/cCBj4bqtbiB0aMaw4budbmcgdGjhuqV5KiouIFjhur9wIGjhuqFuZyB0w61uIGThu6VuZyBsw6AgbeG7mXQgYsOgaSB0b8OhbiBtw6AgdOG7lSBjaOG7qWMgdMOtbiBk4bulbmcgLSBuZ8OibiBow6BuZyDEkcOjIHjDonkgZOG7sW5nIHbDoCDDoXAgZOG7pW5nLiBUdXkgduG6rXkgaOG6p3UgaOG6v3QgaMaw4bubbmcgxJFpIGhv4bq3YyB0cmnhu4NuIGtoYWkgLSDDoXAgZOG7pW5nIGNo4buJIG3hu5tpIHThuq1wIHRydW5nIHbDoG8gdmnhu4djIHNvIHPDoW5oIG3hu6ljIMSR4buZIGNow61uaCB4w6FjIGNodW5nIChBY2N1cmFjeSkgaG/hurdjIEFVQy9HaW5pIGdp4buvYSBjw6FjIG3DtCBow6xuaCBy4buTaSDEkcawYSByYSBraHV54bq/biBjw6FvIGzhu7FhIGNo4buNbiB2w6AgdHJp4buDbiBraGFpIHPhu60gZOG7pW5nIG3DtCBow6xuaC4gxJDDonkgbMOgIG3hu5l0IGjGsOG7m25nIHRp4bq/cCBj4bqtbiBjaMawYSDEkcO6bmcgdsOsIG7DsyBi4buPIHF1YSBt4bulYyB0acOqdSBjxqEgYuG6o24gY+G7p2EgbeG7mXQgdOG7lSBjaOG7qWMgaG/huqF0IMSR4buZbmcgdsOsIGzhu6NpIG5odeG6rW4uIMSQaeG7gXUgbsOgeSDEkcaw4bujYyBnaeG6o2kgdGjDrWNoIOG7nyBt4bulYyBuZ2F5IGTGsOG7m2kgxJHDonkuIAoKKipDw6FjaCB0aeG6v3AgY+G6rW4gbeG7m2k6IEjGsOG7m25nIMSR4bq/biBs4bujaSBuaHXhuq1uKiouIE3hu5l0IG3DtCBow6xuaCBob+G6t2MgY8OhY2ggdGnhur9wIGPhuq1uIGPDsyBBY2N1cmFjeSwgdGjhuq1tIGNow60gbMOgIEFVQy9HaW5pIGNhbyBs4bqhaSBsw6AgbcO0IGjDrG5oIG1hbmcgbOG6oWkgbmhp4buBdSB0aGnhu4d0IGjhuqFpIHbhu4EgdGnhu4FuIGNobyB04buVIGNo4bupYyBz4butIGThu6VuZy4gTmd1ecOqbiBuaMOibiBsw6AgY8OhYyBtw7QgaMOsbmggLyBjw6FjaCB0aeG6v3AgY+G6rW4gZ+G6p24gbmjGsCBxdcOqbiBt4bqldCBy4bqxbmcgY8OhYyB04buVIGNo4bupYyBob+G6oXQgxJHhu5luZyB2w6wgbOG7o2kgbmh14bqtbiB0aMOsIG3hu6VjIHRpw6p1IGjDoG5nIMSR4bqndSBsw6AgUFJPRklUIGNo4bupIGtow7RuZyBwaOG6o2kgbMOgIEFjY3VyYWN5LCBBVUMgaGF5IEdpbmkuIEFVQy9HaW5pIGNo4buJIGzDoCDEkWnhu4F1IGtp4buHbiBj4bqnbiwgbMOgIGThuqV1IGhp4buHdSBj4bunYSBt4buZdCBtw7QgaMOsbmggdOG7kXQgduG7gSAgbeG6t3QgbOG7o2kgbmh14bqtbiBjaG8gdOG7lSBjaOG7qWMgc+G7rSBk4bulbmcuIMSQ4buDIG1pbmggaOG7jWEgY2jDum5nIHRhIHjDqXQgYuG7mSBk4buvIGxp4buHdSBnaeG6oyDEkeG7i25oIGNo4buJIGPDsyA5IGtow6FjaCBow6BuZyB4aW4gdmF5IHTDrW4gZOG7pW5nIHbhu5tpIHPhu5EgdGnhu4FuIHZheSDEkeG7gSB4deG6pXQgdGjhu4MgaGnhu4duIOG7nyBj4buZdCBMT0FOLiBD4buZdCBNb2RlbDEgdsOgIE1vZGVsMiBs4bqnbiBsxrDhu6N0IGzDoCBuaMOjbiDEkcaw4bujYyBk4buxIGLDoW8gdOG7qyBtw7QgaMOsbmggY+G6rW4gMSB2w6AgbcO0IGjDrG5oIDIgY8OybiBBY3R1YWwgbMOgIG5ow6NuIHRo4buxYyB04bq/OiAKCgpgYGB7cn0KIyBMb2FkIHNvbWUgcGFja2FnZXM6IApsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShrbml0cikKCiMgQXJ0aWZpY2lhbCBkYXRhc2V0OiAKbG9hbl9pbmZvIDwtIHRpYmJsZShJRCA9IDE6OSwgCiAgICAgICAgICAgICAgICAgICAgTG9hbiA9IGMoMTAwMCwgODAwLCAxMjAwLCA4MDAsIDIwMDAsIDE1MDAsIDE3MDAsIDMwMDAsIDEyMDApLCAKICAgICAgICAgICAgICAgICAgICBBY3R1YWwgPSBjKCJHb29kIiwgIkJhZCIsICJHb29kIiwgIkdvb2QiLCAiR29vZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdvb2QiLCAiR29vZCIsICJCYWQiLCAiR29vZCIpLCAKICAgICAgICAgICAgICAgICAgICBNb2RlbDEgPSBjKCJHb29kIiwgIkdvb2QiLCAiR29vZCIsICJCYWQiLCAiR29vZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdvb2QiLCAiR29vZCIsICJCYWQiLCAiR29vZCIpLCAKICAgICAgICAgICAgICAgICAgICBNb2RlbDIgPSBjKCJCYWQiLCAiQmFkIiwgIkJhZCIsICJCYWQiLCAiR29vZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJhZCIsICJHb29kIiwgIkJhZCIsICJHb29kIikpCgojIE91ciBkYXRhOiAKbG9hbl9pbmZvICU+JSAKICBtdXRhdGVfaWYoaXMuY2hhcmFjdGVyLCBhcy5mYWN0b3IpIC0+IGxvYW5faW5mbwoKbG9hbl9pbmZvICU+JSAKICBrYWJsZSgpCmBgYAoKQWNjdXJhY3kgbMOgIDc3Ljc4JSB2w6AgNTUuNTYlIGzhuqduIGzGsOG7o3QgY2hvIE1vZGVsIDEgdsOgIE1vZGVsIDIgbmjGsCBjaMO6bmcgdGEgY8OzIHRo4buDIHRo4bqleSBxdWEsIHbDrSBk4bulLCBtYSB0cuG6rW4gbmjhuqdtIGzhuqtuOiAKCgpgYGB7cn0KbGlicmFyeShjYXJldCkKCmNvbmZ1c2lvbk1hdHJpeChsb2FuX2luZm8kTW9kZWwxLCBsb2FuX2luZm8kQWN0dWFsKSAjIE1vZGVsIDEuCmNvbmZ1c2lvbk1hdHJpeChsb2FuX2luZm8kTW9kZWwyLCBsb2FuX2luZm8kQWN0dWFsKSAjIE1vZGVsIDIuIAoKYGBgCgpO4bq/dSBjxINuIGPhu6kgdsOgbyBBY2N1cmFjeSBjaMO6bmcgdGEgZOG7hSBi4buLIGzDtGkga8OpbyB24bubaSBuaOG6rW4gxJHhu4tuaCBy4bqxbmcgbcO0IGjDrG5oIDEgc+G6vSBuw6puIMSRxrDhu6NjIMOhcCBk4bulbmcgdsOgIHRyaeG7g24ga2hhaSBjaG8gdmnhu4djIGPhuqVwIHTDrW4gZOG7pW5nLiBUdXkgbmhpw6puIMSRw6J5IGzhuqFpIGzDoCBt4buZdCBuaOG6rW4gxJHhu4tuaCBzYWkuIFRo4buxYyB24bqteSBu4bq/dSBjaMO6bmcgdGEgZ2nhuqMgdGhp4bq/dCBy4bqxbmc6ICgxKSBu4bq/dSBo4buTIHPGoSB4aW4gdmF5IHRo4buxYyBz4buxIGzDoCB04buRdCB2w6AgbcO0IGjDrG5oIGThu7EgxJFvw6FuIMSRw7puZyBsw6AgdOG7kXQgdGjDrCBs4bujaSBuaHXhuq1uIHRodSB24buBIHPhur0gbMOgIDEwJSBj4bunYSBraG/huqNuIHZheSwgKDIpIG7hur91IGjhu5Mgc8ahIHRo4buxYyBz4buxIGzDoCB44bqldSBuaMawbmcgbcO0IGjDrG5oIGThu7EgxJFvw6FuIG5o4bqnbSB0aMOgbmggdOG7kXQgdGjDrCBt4bqldCBob8OgbiB0b8OgbiBraG/huqNuIMSRw6MgY2hvIHZheSwgdsOgICgzKSB04bqldCBj4bqjIGPDoWMgdHLGsOG7nW5nIGjhu6NwIG3DoCBtw7QgaMOsbmggZOG7sSDEkW/DoW4gbMOgIHjhuqV1IHRow6wgc+G6vSBraMO0bmcgY2hvIHZheSB2w6AgZG8gduG6rXkgbOG7o2kgbmh14bqtbiBsw6AgMC4gRMaw4bubaSDEkcOieSBsw6AgdMOtbmggdG/DoW4gbOG7o2kgbmh14bqtbiB0xrDGoW5nIOG7qW5nIGNobyBtw7QgaMOsbmggMSB2w6AgbcO0IGjDrG5oIDIgxJHhu5FpIHbhu5tpIHThu6tuZyBraMOhY2ggaMOgbmc6IAoKCmBgYHtyfQpsb2FuX2luZm8gJT4lIAogIG11dGF0ZShQcm9maXQxID0gY2FzZV93aGVuKE1vZGVsMSA9PSAiR29vZCIgJiBBY3R1YWwgPT0gIkdvb2QiIH4gMC4xKkxvYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kZWwxID09ICJHb29kIiAmIEFjdHVhbCA9PSAiQmFkIiB+IC0xKkxvYW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAwKSkgJT4lIAogIG11dGF0ZShQcm9maXQyID0gY2FzZV93aGVuKE1vZGVsMiA9PSAiR29vZCIgJiBBY3R1YWwgPT0gIkdvb2QiIH4gMC4xKkxvYW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kZWwyID09ICJHb29kIiAmIEFjdHVhbCA9PSAiQmFkIiB+IC0xKkxvYW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAwKSkgLT4gZGZfcHJvZml0CgpkZl9wcm9maXQgJT4lIAogIGthYmxlKCkKYGBgCgpNw7QgaMOsbmggMSBk4buxIGLDoW8gc2FpIGNobyBraMOhY2ggaMOgbmcgdGjhu6kgMyB2w6AgZG8gduG6rXkgbmfDom4gaMOgbmcgbeG6pXQgdHLhuq9uZyA4MDAkIGtoaSBjaG8ga2jDoWNoIGjDoG5nIG7DoHkgdmF5LiBUaMOgbmggdGjhu60gZMO5IHLhurFuZyBtw7QgaMOsbmggMSBjw7MgQWNjdXJhY3kgY2FvIG5oxrBuZyBs4bujaSBuaHXhuq1uIG1hbmcgduG7gSBu4bq/dSBz4butIGThu6VuZyBtw7QgaMOsbmggMSBjaGkgY2jGsGEgYuG6sW5nIDEgLyA4IG7hur91IHPhu60gZOG7pW5nIG3DtCBow6xuaCAyIG5oxrAgdGEgY8OzIHRo4buDIHRo4bqleTogCgpgYGB7cn0Kc2FwcGx5KGRmX3Byb2ZpdCAlPiUgc2VsZWN0KGNvbnRhaW5zKCJQcm8iKSksIHN1bSkKYGBgCgrEkGnhu4F1IHTGsMahbmcgdOG7sSBjxaluZyDDoXAgZOG7pW5nIGNobyBu4bq/dSBs4buxYSBjaOG7jW4gbcO0IGjDrG5oIGPEg24gY+G7qSB2w6BvIEFVQy9HaW5pOiBraMO0bmcgY8OzIGfDrCDEkeG6o20gYuG6o28gcuG6sW5nIG3hu5l0IG3DtCBow6xuaCBjw7MgQVVDL0dpbmkgY2FvIGzhuqFpIGzDoCBtw7QgaMOsbmggbWFuZyBs4bqhaSBuaGnhu4F1IGzhu6NpIG5odeG6rW4gY2hvIHThu5UgY2jhu6ljIHPhu60gZOG7pW5nIHbDoCDEkWnhu4F1IG7DoHkgY8OgbmcgxJHDum5nIHRyb25nIHTDrG5oIGh14buRbmcgbcOgIGLhu5kgZOG7ryBsaeG7h3UgbMOgIG3huqV0IGPDom4gYuG6sW5nIOG7nyBt4bupYyBjYW8gKG5oxrAgYuG7mSBk4buvIGxp4buHdSB04burIGN14buZYyB0aGkgW0thbGFwYSdzIENyZWRpdCBTY29yaW5nIENoYWxsZW5nZV0oaHR0cHM6Ly9jaGFsbGVuZ2Uua2FsYXBhLnZuLykpLiBOaOG6r2MgbOG6oWk6IMSRw7MgY2jhu4kgbeG7m2kgbMOgIMSRaeG7gXUga2nhu4duIGPhuqduLiBN4buZdCBtw7QgaMOsbmggdHV5IGPDsyBBVUMvR2luaSB0aOG6pXAgbmjGsG5nIGzhuqFpIGPDsyB0aOG7gyBk4buxIGLDoW8gdOG7kXQgxJHhu5FpIHbhu5tpIG5ow7NtIGtow6FjaCBow6BuZyB44bqldSAodOG7qWMgUmVjYWxsIGNhbykgdGjDrCDEkcOzIGPDsyB0aOG7gyBsw6AgbcO0IGjDrG5oIG7Dqm4gxJHGsOG7o2Mgc+G7rSBk4bulbmcuIAoKCk5ndXnDqm4gbmjDom4gbMOgIHNhaSBs4bqnbSBsb+G6oWkgSSB2w6Agc2FpIGzhuqdtIGxv4bqhaSBJSSDEkWkga8OobSB24bubaSBjw6FpIGdpw6EgcGjhuqNpIHRy4bqjIGzDoCBraMOhYyBuaGF1LiBOaMOibiBjaHV54buHbiBWaXJ1dCBDb3JvbmEgxJFhbmcgbMOgIGhvdCB0cmVuZCB0aMOsIG7Ds2kgdGjhur8gbsOgeSBjaG8gxJHhur0gbmjhu5s6ICpu4bq/dSBt4buZdCBuZ8aw4budaSBi4buLIG5oaeG7hW0gQ29yb25hIG5oxrBuZyBtw7QgaMOsbmggY2jhuqluIMSRb8OhbiBzYWkgdGjDoG5oIGtow7RuZyBuaGnhu4VtIHRow6wgY8OhaSBnacOhIHBo4bqjaSB0cuG6oyDEkeG6r3QgaMahbiBuaGnhu4F1IG3hu5l0IG5nxrDhu51pIGtow7RuZyBi4buLIENvcm9uYSBuaMawbmcgYuG7iyBjaOG6qW4gxJFvw6FuIHNhaSB0aMOgbmggbmhp4buFbSBDb3JvbmEqLiBUxrDGoW5nIHThu7EsIG7hur91IGThu7EgYsOhbyBuaOG6p20gbeG7mXQga2jDoWNoIGjDoG5nIHThu5F0IHRow6BuaCBraMOhY2ggaMOgbmcgeOG6pXUgdGjDrCBuZ8OibiBow6BuZyBi4buPIGzhu6EgbeG7mXQgY8ahIGjhu5lpIGtp4bq/bSBsw6NpIHRyw6puIGtob+G6o24gdGnhu4FuIGNobyB2YXkgbmjGsG5nIGThu7EgYsOhbyBzYWkgbeG7mXQga2jDoWNoIGjDoG5nIHjhuqV1IHRow6BuaCB04buRdCB0aMOsIHPhur0gbeG6pXQgdHLhuq9uZyBraG/huqNuIMSR4bqndSB0xrAgY+G7p2EgbcOsbmguIAoKClRpw6p1IGNow60gbOG7sWEgY2jhu41uIHbDoCDEkcOhbmggZ2nDoSBwaOG6qW0gY2jhuqV0IGPhu6dhIG3DtCBow6xuaCBwaMOibiBjaG8gYsOgaSB0b8OhbiBDcmVkaXQgU2NvcmluZyBjw7MgdGjhu4MgdGhhbSBraOG6o28gY2hpIHRp4bq/dCDhu58gdHJhbmcgMjYwLCBjaMawxqFuZyAxMSAoTWVhc3VyaW5nIFBlcmZvcm1hbmNlIGluIENsYXNzaWZpY2F0aW9uIE1vZGVscykgY3Xhu5FuIFtBcHBsaWVkIFByZWRpY3RpdmUgTW9kZWxpbmddKGh0dHBzOi8vd3d3LnNwcmluZ2VyLmNvbS9ncC9ib29rLzk3ODE0NjE0Njg0ODYpLiAKCiMgQmF5ZXNpYW4gT3B0aW1pemF0aW9uIGZvciBTZWFyY2hpbmcgQ3V0b2ZmIE1heGltaXplcyBQcm9maXQKCkPDoWMgYsaw4bubYyB0aOG7sWMgaGnhu4duIEJheWVzaWFuIE9wdGltaXphdGlvbiDhu58gW3Bvc3QgdHLGsOG7m2NdKGh0dHBzOi8vcnB1YnMuY29tL2NoaWR1bmdrdC81NzczMzQpIGPDsyB0aOG7gyDEkcaw4bujYyDDoXAgZOG7pW5nIMSR4buDIHTDrG0ga2nhur9tIG5nxrDhu6FuZyBwaMOibiBsb+G6oWkgKENsYXNzaWZpY2F0aW9uIEN1dG9mZikgc2FvIGNobyB04buRaSDEkWEgaMOzYSBs4bujaSBuaHXhuq1uLiBUcsaw4bubYyBo4bq/dCBz4butIGThu6VuZyBs4bqhaSBt4buZdCBz4buRIGNvZGVzIHThu6sgcG9zdCBuw6B5IHThu6sgYsaw4bubYyBjaHXhuqluIGLhu4sgZOG7ryBsaeG7h3UgxJHhur9uIGh14bqlbiBsdXnhu4duIFhnYm9vc3QgbeG6t2MgxJHhu4tuaDogCgoKYGBge3J9CgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgICAgICAgRGF0YSBQcmUtcHJvY2Vzc2luZwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIENsZWFyIHdvcmtzcGFjZTogCnJtKGxpc3QgPSBscygpKQoKIyBJbXBvcnQgZGF0YTogCmhtZXEgPC0gcmVhZF9jc3YoImh0dHA6Ly93d3cuY3JlZGl0cmlza2FuYWx5dGljcy5uZXQvdXBsb2Fkcy8xLzkvNS8xLzE5NTExNjAxL2htZXEuY3N2IikKCiMgRHRhZ2UgMSAtIEltcHV0ZSBtaXNzaW5nIGRhdGE6IApsaWJyYXJ5KG1pc3NSYW5nZXIpCgptaXNzUmFuZ2VyKGhtZXEsIHNlZWQgPSAyOSkgLT4gaG1lcV9pbXB1dGVkCgojIFN0YWdlIDIgLSBDb25kdWN0IG9uZS1ob3QgZW5jb2RpbmcgcHJvY2VzczogCgpkdW1taWVzIDwtIGR1bW15VmFycyh+IFJFQVNPTiArIEpPQiwgZGF0YSA9IGhtZXFfaW1wdXRlZCkKcHJlZGljdChkdW1taWVzLCBobWVxX2ltcHV0ZWQpICU+JSBhcy5kYXRhLmZyYW1lKCkgLT4gZmVhdHVyZXNfb25lSG90CgojIEZpbmFsIGRhdGEgZm9yIG1vZGVsbGluZzogCmhtZXFfaW1wdXRlZCAlPiUgCiAgc2VsZWN0X2lmKGlzLm51bWVyaWMpICU+JSAKICBiaW5kX2NvbHMoZmVhdHVyZXNfb25lSG90KSAtPiBkZl9maW5hbAoKIyBTcGxpdCBkYXRhOiAKCnNldC5zZWVkKDEpCmlkIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oZGZfZmluYWwkQkFELCBwID0gMC43LCBsaXN0ID0gRkFMU0UpCnRyYWluIDwtIGRmX2ZpbmFsW2lkLCBdCnRlc3QgPC0gZGZfZmluYWxbLWlkLCBdCgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PQojICAgTW9kZWxsaW5nIHdpdGggWEdCb29zdAojPT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKIyBDb252ZXJ0IHRvIERNYXRyaXggZm9ybSBmb3IgdHJhaW4gZGF0YTogCgpYX3RyYWluIDwtIHRyYWluICU+JSAKICBzZWxlY3QoLUJBRCkgJT4lIAogIGFzLm1hdHJpeCgpCgpZX3RyYWluIDwtIHRyYWluICU+JSAKICBwdWxsKEJBRCkKCmxpYnJhcnkoeGdib29zdCkKZHRyYWluIDwtIHhnYi5ETWF0cml4KGRhdGEgPSBYX3RyYWluLCBsYWJlbCA9IFlfdHJhaW4pCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiMgICBUcmFpbiBYR0Jvb3N0IHdpdGggZGVmYXVsdCBwYXJhbWV0ZXJzCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgVHJhaW4gYSBkZWZhdWx0IFhHQm9vc3Q6IAp4Z2IxIDwtIHhnYm9vc3QoZGF0YSA9IGR0cmFpbiwgCiAgICAgICAgICAgICAgICBvYmplY3RpdmUgPSAiYmluYXJ5OmxvZ2lzdGljIiwgCiAgICAgICAgICAgICAgICB2ZXJib3NlID0gMCwgCiAgICAgICAgICAgICAgICBucm91bmQgPSAzMCkKCmBgYAoKQ8OhYyBtw7QgTWFjaGluZSBMZWFybmluZyAtIGvhu4MgY+G6oyBYZ2Jvb3N0IHPhur0gdMOtbmggdG/DoW4geMOhYyBzdeG6pXQgduG7oSBu4bujIFBEIChQcm9iYWJpbGl0eSBvZiBEZWZhdWx0KSB2w6Agc+G7rSBk4bulbmcgbmfGsOG7oW5nIG3hurdjIMSR4buLbmggbMOgIDAuNSDEkeG7gyBk4buxIGLDoW8gbmjDo24gcuG7k2kgdMOtbmggdG/DoW4gbWEgdHLhuq1uIG5o4bqnbSBs4bqrbiAoaMOgbSAqY29uZnVzaW9uX21hdHJpeCgpKiBj4bunYSBQeXRob24gdsOgICpjb25mdXNpb25NYXRyaXgoKSogY+G7p2EgUikuIFThuqV0IGPhuqMgY8OhYyB0b29sIGtow6FjIMSR4buBdSBt4bq3YyDEkeG7i25oIHPhu60gZOG7pW5nIG5nxrDhu6FuZyBuw6B5LiBEbyB24bqteSwgxJHhu4Mga2jhuqNvIHPDoXQgbOG7o2kgbmh14bqtbiB0xrDGoW5nIOG7qW5nIHbhu5tpIG3hu5dpIG5nxrDhu6FuZyBjaMO6bmcgdGEgcGjhuqNpIHZp4bq/dCBt4buZdCBow6BtLiBExrDhu5tpIMSRw6J5IGNow7puZyB0YSB2aeG6v3QgbeG7mXQgaMOgbSB0w61uaCB0b8OhbiBs4bujaSBuaHXhuq1uIGNobyAxMDAwIGtow6FjaCBow6BuZyB4aW4gdmF5IHThu6sgMTc4OCBraMOhY2ggaMOgbmcg4bufIGLhu5kgZOG7ryBsaeG7h3UgdGVzdCB0aGVvIHBoxrDGoW5nIHBow6FwIGzhuqV5IG3huqt1IG5n4bqrdSBuaGnDqm4gcuG7k2kgbOG6t3AgbOG6oWkgcXXDoSB0csOsbmggbsOgeSAxMDAgbOG6p24gxJHhu4MgdMOtbmggbOG7o2kgbmh14bqtbiAoUHJvZml0KSB0cnVuZyBiw6xuaCB0xrDGoW5nIOG7qW5nIHbhu5tpIG3hu5l0IG5nxrDhu6FuZyBjdXRvZmYgxJHGsOG7o2MgY2jhu41uLiBDw6FjIGdp4bqjIHRoaeG6v3Qga2jDoWNoIGzDoDogCgoxLiBMw6NpIHN14bqldCBsw6AgMTAlIGNobyBjw6FjIGtob+G6o24gdmF5IMSRxrDhu6NjIGPhuqVwLiAKMi4gTuG6v3UgbeG7mXQga2jDoWNoIGjDoG5nIHjhuqV1IChCYWQpIG5oxrBuZyBtw7QgaMOsbmggWGdib29zdCBk4buxIGJhbyBzYWkgdGjDoG5oIHThu5F0IChHb29kKSB0aMOsIG5nw6JuIGjDoG5nIG3huqV0IHRy4bqvbmcga2hv4bqjbiB2YXkuIAozLiBW4bubaSBjw6FjIGtow6FjaCBow6BuZyBtw6AgWGdib29zdCBk4buxIGLDoW8gbMOgIHjhuqV1IHRow6wgbmfDom4gaMOgbmcga2jDtG5nIGPhuqVwIGtob+G6o24gdmF5ICjEkcawxqFuZyBuaGnDqm4gcuG7k2kpLiAKCgpIw6BtIMSRw7MgbmjGsCBzYXU6IAoKCmBgYHtyfQoKIyBGdW5jdGlvbiBjYWxjdWxhdGVzIG1lYW4gcHJvZml0IGZvciAxMDAwIGNhc2UgCiMgcmFuZG9tbHkgc2VsZWN0ZWQgd2l0aCBhIHNwZWNpZmljIGN1dG9mZjogCgpnZXRfcHJvZml0IDwtIGZ1bmN0aW9uKGN1dG9mZikgewogIAogIHJhdGUgPC0gMC4xCiAgCiAgcCA8LSAxMDAwIC8gbnJvdyh0ZXN0KQogIAogIHByb2Zfc3BhY2UgPC0gYygpCiAgCiAgZm9yIChqIGluIDE6MTAwKSB7CiAgICAKICAgIHNldC5zZWVkKGopCiAgICAKICAgIGlkIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24odGVzdCRCQUQsIHAgPSBwLCBsaXN0ID0gRkFMU0UpCiAgICAKICAgIHRlc3RfbWluaSA8LSB0ZXN0W2lkLCBdCiAgICAKICAgIHBkIDwtIHByZWRpY3QoeGdiMSwgdGVzdF9taW5pICU+JSBzZWxlY3QoLUJBRCkgJT4lIGFzLm1hdHJpeCgpKQogICAgCiAgICBsYWJlbF9wcmVkIDwtIGNhc2Vfd2hlbihwZCA+PSBjdXRvZmYgfiAiQmFkIiwgVFJVRSB+ICJHb29kIikKICAgIAogICAgdGVzdF9taW5pICU+JSAKICAgICAgbXV0YXRlKExhYmVsUHJlZCA9IGxhYmVsX3ByZWQpICU+JSAKICAgICAgc2VsZWN0KEJBRCwgTGFiZWxQcmVkLCBMT0FOKSAlPiUgCiAgICAgIG11dGF0ZShQcm9maXQgPSBjYXNlX3doZW4oTGFiZWxQcmVkID09ICJHb29kIiAmIEJBRCA9PSAwIH4gcmF0ZSpMT0FOLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMYWJlbFByZWQgPT0gIkdvb2QiICYgQkFEID09IDEgfiAtMSpMT0FOLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gMCkpIC0+IGRmX3Byb2ZpdAogICAgCiAgICBkZl9wcm9maXQgJT4lIHB1bGwoUHJvZml0KSAlPiUgc3VtKCkgLT4gdG90YWxfcHJvZml0CiAgICAKICAgIHByb2Zfc3BhY2UgPC0gYyhwcm9mX3NwYWNlLCB0b3RhbF9wcm9maXQpCiAgICAKICB9CiAgCiAgcmV0dXJuKGxpc3QoU2NvcmUgPSBtZWFuKHByb2Zfc3BhY2UpIC8gMTAwMCwgUHJlZCA9IE5VTEwpKQp9CgpgYGAKCkvhur8gdGnhur9wIHRo4buxYyBoaeG7h24gQmF5ZXNpYW4gT3B0aW1pemF0aW9uIHRoZW8gY8OhYyB0aOG7pyB04bulYyBuaMawIMSRw6MgxJHGsOG7o2MgdHLDrG5oIGLDoHkg4bufIHBvc3QgdHLGsOG7m2M6IAoKYGBge3J9CgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgIFNlYXJjaCBiZXN0IGN1dG9mZiB0aGF0IG1heGltaXplcyBwcm9maXQKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKIyBTcGFjZSBvZiByYXRlOiAKCm15X3JhdGUgPC0gbGlzdChjdXRvZmYgPSBjKDAsIDEpKQoKIyBTZWFyY2ggb3B0aW1hbCBoeXBlcnBhcmFtZXRlciBieSBCYXllc2lhbiBPcHRpbWl6YXRpb246IApsaWJyYXJ5KHJCYXllc2lhbk9wdGltaXphdGlvbikKCnN5c3RlbS50aW1lKE9QVF9SZXMgPC0gQmF5ZXNpYW5PcHRpbWl6YXRpb24oZ2V0X3Byb2ZpdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm91bmRzID0gbXlfcmF0ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdF9wb2ludHMgPSAxMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbl9pdGVyID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNxID0gInVjYiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthcHBhID0gMi41NzYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVwcyA9IDAuMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gRkFMU0UpKQoKYGBgCgpr4bq/dCBxdeG6oyBuZ8aw4buhbmcgdOG7kWkgxrB1IHbDoCBs4bujaSBuaHXhuq1uIHRydW5nIGLDrG5oIHTGsMahbmcg4bupbmcgbMOgOiAKCmBgYHtyfQoKIyBSYXRlIHRoYXQgbWF4aW1pemVzIHByb2ZpdCBmb3IgYmFuazogCmJlc3RSYXRlIDwtIE9QVF9SZXMkQmVzdF9QYXIKYmVzdFJhdGUKYGBgCgpjaMO6bmcgdGEgY8OzIHRoZW8gZMO1aSBz4buxIHRoYXkgxJHhu5VpIGPhu6dhIGzhu6NpIG5odeG6rW4gdHJ1bmcgYsOsbmggbsOgeSB0xrDGoW5nIOG7qW5nIHbhu5tpIGN1dG9mZiDEkcaw4bujYyBjaOG7jW4gdHJvbmcgxJHDsyBuZ8aw4buhbmcgbcOgIHThu5FpIMSRYSBs4bujaSBuaHXhuq1uIHRydW5nIGLDrG5oIG7DoHkgbMOgIMSRaeG7g20gbcOgdSDEkeG7jzogCgpgYGB7cn0KT1BUX1JlcyRIaXN0b3J5ICU+JSAKICBkYXRhLmZyYW1lKCkgJT4lIAogIG11dGF0ZShNZWFuUHJvZml0ID0gVmFsdWUgLyAxMDAwKSAtPiBtZWFuX3Byb19kZgoKCm1lYW5fcHJvX2RmICU+JSAKICBnZ3Bsb3QoYWVzKGN1dG9mZiwgTWVhblByb2ZpdCkpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBtZWFuX3Byb19kZiAlPiUgZHBseXI6OnNsaWNlKC13aGljaC5tYXgoTWVhblByb2ZpdCkpLCBjb2xvciA9ICJibHVlIikgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBtZWFuX3Byb19kZiAlPiUgZHBseXI6OnNsaWNlKHdoaWNoLm1heChNZWFuUHJvZml0KSksIGNvbG9yID0gInJlZCIpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgCiAgbGFicyh4ID0gIkN1dG9mZiIsIAogICAgICAgdGl0bGUgPSAiRmlndXJlIDE6IE9wdGltYWwgY3V0b2ZmIHRoYXQgbWF4aW1pemVzIHByb2ZpdCBmb3IgWEdCb29zdCIpIC0+IHAKCgpwbG90bHk6OmdncGxvdGx5KHApCgpgYGAKCk5T4butIGThu6VuZyBuZ8aw4buhbmcgYGJlc3RSYXRlYCB04buRaSDGsHUgdMOsbSDEkcaw4bujYyDEkeG7gyBz4butIGThu6VuZyBjaG8gcXV54bq/dCDEkeG7i25oIGNobyBt4buZdCBraMOhY2ggaMOgbmcgY+G7pSB0aOG7gyDEkcaw4bujYyB2YXkgaGF5IGtow7RuZyB2w6Agc28gc8OhbmggduG7m2kgcGjGsMahbmcgw6FuIHPhu60gZOG7pW5nIG5nxrDhu6FuZyBt4bq3YyDEkeG7i25oLiBUcsaw4bubYyBo4bq/dCB0w61uaCB0b8OhbiBs4bujaSBuaHXhuq1uIGPhu6dhIGhhaSBwaMawxqFuZyDDoW4gKFByb2ZpdERlZmF1bHQgdsOgIFByb2ZpdEN1dG9mZikgdMaw4bubbmcg4bupbmcgduG7m2kgdmnhu4djIHPhu60gZOG7pW5nIG5nxrDhu6FuZyBt4bq3YyDEkeG7i25oIChEZXMxKSB2w6AgbmfGsOG7oW5nIHThu5FpIMawdSAoRGVzMik6IAoKYGBge3J9CgojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgIENvbXBhcmUgcHJvZml0IGJldHdlZW4gdGhlIHR3byBTY2VuYXJpb3MKIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKIyBDYWxjdWxhdGUgUHJvYmFiaWxpdHkgb2YgRGVmYXVsdCAoUEQpOiAKcGQgPC0gcHJlZGljdCh4Z2IxLCB0ZXN0ICU+JSBzZWxlY3QoLUJBRCkgJT4lIGFzLm1hdHJpeCgpKQoKCiMgQ2FsY3VsYXRlIHByb2ZpdDogCgp0ZXN0ICU+JSAKICBtdXRhdGUoUEQgPSBwZCwgUmF0ZSA9IDAuMSkgJT4lIAogIHNlbGVjdChCQUQsIExPQU4sIFBELCBSYXRlKSAlPiUgCiAgbXV0YXRlKERlczEgPSBjYXNlX3doZW4oUEQgPj0gMC41IH4gIkJhZCIsIFRSVUUgfiAiR29vZCIpLCAKICAgICAgICAgRGVzMiA9IGNhc2Vfd2hlbihQRCA+PSBiZXN0UmF0ZSB+ICJCYWQiLCBUUlVFIH4gIkdvb2QiKSkgJT4lIAogIG11dGF0ZShQcm9maXREZWZhdWx0ID0gY2FzZV93aGVuKERlczEgPT0gIkdvb2QiICYgQkFEID09IDAgfiBSYXRlKkxPQU4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlczEgPT0gIkdvb2QiICYgQkFEID09IDEgfiAtMSpMT0FOLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gMCkpICU+JSAKICBtdXRhdGUoUHJvZml0Q3V0b2ZmID0gY2FzZV93aGVuKERlczIgPT0gIkdvb2QiICYgQkFEID09IDAgfiBSYXRlKkxPQU4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVzMiA9PSAiR29vZCIgJiBCQUQgPT0gMSB+IC0xKkxPQU4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IDApKSAtPiBkZl9wcm9maXQKCiMgU2hvdyBzb21lIGNhc2VzOiAKZGZfcHJvZml0ICU+JSAKICBoZWFkKG4gPSAxMCkgJT4lIAogIGthYmxlKCkKCmBgYAoKTOG7o2kgbmh14bqtbiBj4bunYSB2aeG7h2Mgc+G7rSBk4bulbmcgbmfGsOG7oW5nIHThu5FpIMawdSBjaG8gQ3JlZGluZyBTY29yaW5nIGzDoCB2xrDhu6N0IHRy4buZaSBzbyB24bubaSBz4butIGThu6VuZyBuZ8aw4buhbmcgbeG6t2MgxJHhu4tuaCBuaMawIGNow7puZyB0YSBjw7MgdGjhu4MgdGjhuqV5IHRyb25nIEZpZ3VyZSAyOiAKCmBgYHtyfQojIENvbXBhcmUgcHJvZml0OiAKCmRmX3Byb2ZpdCAlPiUgCiAgc2VsZWN0KGNvbnRhaW5zKCJQcm8iKSkgJT4lIAogIGdhdGhlcihrZXkgPSAiU2NlbmFyaW8iLCB2YWx1ZSA9ICJQcm9maXQiKSAlPiUgCiAgZ3JvdXBfYnkoU2NlbmFyaW8pICU+JSAKICBzdW1tYXJpc2UoUHJvZml0ID0gc3VtKFByb2ZpdCkgLyAxMDAwKSAlPiUgCiAgZ2dwbG90KGFlcyhTY2VuYXJpbywgUHJvZml0LCBmaWxsID0gU2NlbmFyaW8pKSArIAogIGdlb21fY29sKCkgKyAKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArIAogIGxhYnMoeCA9IE5VTEwsIHRpdGxlID0gIkZpZ3VyZSAyOiBQcm9maXQgYmV0d2VlbiB0d28gc2NlbmFyaW9zIikgLT4gZwoKCnBsb3RseTo6Z2dwbG90bHkoZykKCmBgYAoKTeG7mXQgbOG6p24gbuG7r2EgY2jDum5nIHRhIGPDsyB0aOG7gyB4w6FjIG5o4bqtbiBy4bqxbmcgY8OhY2ggdGnhur9wIGPhuq1uIDEgKGhheSBy4buZbmcgaMahbiBsw6AgbcO0IGjDrG5oIDEpIHPhu60gZOG7pW5nIG5nxrDhu6FuZyBt4bq3YyDEkeG7i25oIGPDsyBBY2N1cmFjeSBjYW8gaMahbiBo4bqzbiBkw7kgxJHDonkgbMOgIGPDoWNoIHRp4bq/cCBj4bqtbiB04bqhbyByYSBs4bujaSBuaHXhuq1uIGtow7RuZyBjYW86IAoKYGBge3J9CgojIENvbmZ1c2lvbiBtYXRyaXggd2hlbiBjdXRvZmYgPSAwLjUgYW5kIGN1dG9mZiA9IGJlc3RSYXRlOiAKZGZfcHJvZml0ICU+JSAKICBtdXRhdGUoVHJ1ZUxhYmVsID0gY2FzZV93aGVuKEJBRCA9PSAxIH4gIkJhZCIsIFRSVUUgfiAiR29vZCIpKSAlPiUgCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgYXMuZmFjdG9yKSAtPiBkZl9wcm9maXQKCgpjb25mdXNpb25NYXRyaXgoZGZfcHJvZml0JERlczEsIGRmX3Byb2ZpdCRUcnVlTGFiZWwsIHBvc2l0aXZlID0gIkJhZCIpICMgRGVmYXVsdCBjdXRvZmYuIApjb25mdXNpb25NYXRyaXgoZGZfcHJvZml0JERlczIsIGRmX3Byb2ZpdCRUcnVlTGFiZWwsIHBvc2l0aXZlID0gIkJhZCIpICMgT3B0aW1hbCBjdXRvZmYuIAoKYGBgCgpOZ3V5w6puIG5ow6JuIGzDoCBtw7QgaMOsbmggc+G7rSBk4bulbmcgT3B0aW1hbCBjdXRvZmYgPSBgYmVzdFJhdGVgIHR1eSBjw7MgQWNjdXJhY3kgdGjhuqVwIGjGoW4gbmjGsG5nIMSRw6J5IGNow61uaCBs4bqhaSBsw6AgbcO0IGjDrG5oIGPDsyBSZWNhbGwgKGhheSBTZW5zaXRpdml0eSkgY2FvIGjGoW4uIE5o4bqvYyBs4bqhaSBy4bqxbmcgUmVjYWxsL1NlbnNpdGl2aXR5IGzDoCB0aMaw4bubYyDEkW8gxJHDoW5oIGdpw6Ega2jhuqMgbsSDbmcgcGjDom4gYmnhu4d0IC0gZOG7sSBiw6FvIG5ow7NtIGtow6FjaCBow6BuZyB44bqldS4gCgoKTmjGsCDEkcOjIHBow6JuIHTDrWNoIOG7nyBt4bulYyB0csaw4bubYywgbmd1ecOqbiBuaMOibiBsw6AsIHbDrSBk4bulLCBraMOhY2ggaMOgbmcg4bufIGTDsm5nIMSR4bqndSB0acOqbiB0aMOsIHPhu60gZOG7pW5nIG5nxrDhu6FuZyBt4bq3YyDEkeG7i25oIDAuNSBz4bq9IMSRxrDhu6NjIGNobyBsw6Aga2jDoWNoIGjDoG5nIHThu5F0ICh2w6wgUEQgPCAwLjUpIG5oxrBuZyB0aOG7sWMgdOG6vyDEkcOieSBsw6Aga2jDoWNoIGjDoG5nIHjhuqV1IChCQUQgPSAxKSBuw6puIGtoaSBj4bqlcCBt4buZdCBraG/huqNuIHZheSBjaG8gIGtow6FjaCBow6BuZyBuw6B5IG5nw6JuIGjDoG5nIHPhur0gbeG6pXQgdHLhuq9uZyB24buRbiAobOG7o2kgbmh14bqtbiB0xrDGoW5nIOG7qW5nIGPhu6dhIGtow6FjaCBow6BuZyBuw6B5IG1hbmcgZOG6pXUgw6JtIHRyw6puIGPhu5l0IFByb2ZpdEN1dG9mZikgdHJvbmcga2hpIMSRw7MgIm3DtCBow6xuaCIgcGjDom4gbG/huqFpIHPhu60gZOG7pW5nIG5nxrDhu6FuZyB04buRaSDGsHUgc+G6vSB44bq/cCBraMOhY2ggbsOgeSBsw6AgeOG6pXUgKHbDoCB0aOG7sWMgdOG6vyDEkcO6bmcgbMOgIHbhuq15KSBuaMawIHRhIHRo4bqleTogCgoKYGBge3J9CgpkZl9wcm9maXQgJT4lIAogIGZpbHRlcihEZXMxID09ICJHb29kIiwgRGVzMiA9PSAiQmFkIiwgVHJ1ZUxhYmVsID09ICJCYWQiKSAlPiUgCiAgaGVhZCgpICU+JSAKICBrbml0cjo6a2FibGUoKQoKYGBgCgoKIyBCcmllZiBTdW1tYXJ5CgoxLiBCYXllc2lhbiBPcHRpbWl6YXRpb24ga2jDtG5nIGNo4buJIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIHRpbmggY2jhu4luaCB2w6AgdMOsbSBraeG6v20gdGhhbSBz4buRIHThu5FpIMawdSBjaG8gY8OhYyBtw7QgaMOsbmggTWFjaGluZSBMZWFybmluZyBtw6AgY8OybiBjw7MgdGjhu4MgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdOG7kWkgxrB1IGjDs2EgTOG7o2kgTmh14bqtbiAtIG3hu5l0IG3hu6VjIHRpw6p1IGPhu6UgdGjhu4MgdsOgIMSR4bq3YyB0aMO5IGPhu6dhIGLDoGkgdG/DoW4gQ3JlZGl0IFNjb3JpbmcuIAoKMi4gVuG7m2kgY8OhYyB04buVIGNo4bupYyBob+G6oXQgxJHhu5luZyB2w6wgbOG7o2kgbmh14bqtbiB0aMOsIEFjY3VyYWN5LCBBVUMvR2luaSBoYXkgYuG6pXQgY+G7qSB0acOqdSBjaMOtIGfDrCBjw7MgdGjhu4MgbmdoxKkgcmEgbcOgIGtow7RuZyBj4bqjaSB0aGnhu4duIMSRxrDhu6NjIGzhu6NpIG5odeG6rW4gY+G7p2EgdOG7lSBjaOG7qWMgdGjDrCBjxaluZyBraMO0bmcgY8OzIMO9IG5naMSpYSBuaGnhu4F1IG5nb8OgaSBnacOhIHRy4buLIHRoYW0ga2jhuqNvLiBUcm9uZyBt4buZdCBz4buRIHTDrG5oIGh14buRbmcgY+G7pSB0aOG7gyBuaMawIGtpbmggdOG6vyBi4bqldCDhu5VuIGPhuqduIHNp4bq/dCBjaOG6t3QgdMOtbiBk4bulbmcgdsOgIGhv4bqhdCDEkeG7mW5nIGNobyB2YXkgdGjDrCBy4bunaSBybyB24buBIHThu5VuIHRo4bqldCB24buRbiBsw6AgbeG7pWMgdGnDqnUgaMOgbmcgxJHhuqd1IGzDumMgxJHDsyB0aMOsIFJlY2FsbC9TZW5zaXRpdml0eSAtIGNo4buJIHRpw6p1IMSRw6FuaCBjaOG6pXQgbMaw4bujbmcgcGjDom4gbG/huqFpIGNobyBuaMOzbSBraMOhY2ggaMOgbmcgeOG6pXUgY8OzIHRo4buDIMSRxrDhu6NjIMawdSB0acOqbiBow6BuZyDEkeG6p3UuIAoKMy4gTmdvw6BpIHPhu60gZOG7pW5nIEJheWVzaWFuIE9wdGltaXphdGlvbiBjaMO6bmcgdGEgY8OzIHRo4buDIHTDrG0gbmfGsOG7oW5nIHThu5FpIMawdSBt4buZdCBjw6FjaCB0aOG7pyBjw7RuZyAobmjGsG5nIGhp4buHdSBxdeG6oykgbuG6v3UgW3Phu60gZOG7pW5nIFJdKGh0dHBzOi8vcnB1YnMuY29tL2NoaWR1bmdrdC80ODc5MTIpIGhv4bq3YyBbc+G7rSBk4bulbmcgUHl0aG9uXShodHRwczovL2dpdGh1Yi5jb20vQ2hpRHVuZ05ndXllbi9DaGFwdGVyNV9UdXJuaW5nX1BhcmFtZXRlcnNfYnlfUHJvZml0L2Jsb2IvbWFzdGVyL0NoYXB0ZXI1X1R1cm5pbmdfcGFyYW1ldGVyc19ieV9Qcm9maXQuaXB5bmIpCgoKIyBSZWZlcmVuY2VzCgoxLiBNYXJ0ZW5zLCBELiwgQi4gQmFlc2VucywgVC4gVmFuIEdlc3RlbCwgYW5kIEouIFZhbnRoaWVuZW4uIDIwMDcuIOKAnENvbXByZWhlbnNpYmxlIENyZWRpdCBTY29yaW5nIE1vZGVscyBVc2luZyBSdWxlIEV4dHJhY3Rpb24gZnJvbSBTdXBwb3J0IFZlY3RvciBNYWNoaW5lcy7igJ0gRXVyb3BlYW4gSm91cm5hbCBvZiBPcGVyYXRpb25hbCBSZXNlYXJjaCAxODM6MTQ2NuKAkzE0NzYuCgoyLiBCYWVzZW5zLCBCLiwgUm9lc2NoLCBELiwgJiBTY2hldWxlLCBILiAoMjAxNikuIENyZWRpdCByaXNrIGFuYWx5dGljczogTWVhc3VyZW1lbnQgdGVjaG5pcXVlcywgYXBwbGljYXRpb25zLCBhbmQgZXhhbXBsZXMgaW4gU0FTLiBKb2huIFdpbGV5ICYgU29ucy4KCjMuIFNpZGRpcWksIE4uICgyMDEyKS4gQ3JlZGl0IHJpc2sgc2NvcmVjYXJkczogZGV2ZWxvcGluZyBhbmQgaW1wbGVtZW50aW5nIGludGVsbGlnZW50IGNyZWRpdCBzY29yaW5nLiBKb2huIFdpbGV5ICYgU29ucy4KCjQuIEFuZGVyc29uIFIgKDIwMDcpOiBUaGUgQ3JlZGl0IFNjb3JpbmcgVG9vbGtpdDogVGhlb3J5IGFuZCBQcmFjdGljZSBmb3IgUmV0YWlsIENyZWRpdCBSaXNrIE1hbmFnZW1lbnQgYW5kIERlY2lzaW9uIEF1dG9tYXRpb24uIE94Zm9yZCwgT3hmb3JkIFVuaXZlcnNpdHkgUHJlc3MuCgo1LiBUaG9tYXMgTEMgKDIwMDkpOiBDb25zdW1lciBDcmVkaXQgTW9kZWxzOiBQcmljaW5nLCBQcm9maXQsIGFuZCBQb3J0Zm9saW8uIE94Zm9yZCwgT3hmb3JkIFVuaXZlcnNpdHkgUHJlc3MuCgo2LiBCZW4tRGF2aWQsIEEuLCAmIEZyYW5rLCBFLiAoMjAwOSkuIEFjY3VyYWN5IG9mIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzIHZlcnN1cyDigJxoYW5kIGNyYWZ0ZWTigJ0gZXhwZXJ0IHN5c3RlbXPigJNhIGNyZWRpdCBzY29yaW5nIGNhc2Ugc3R1ZHkuIEV4cGVydCBTeXN0ZW1zIHdpdGggQXBwbGljYXRpb25zLCAzNigzKSwgNTI2NC01MjcxLgoKCgoK