Introduction

Xếp hạng tín dụng (Credit Scoring / Scocard Modelling) đó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 khác. Hiện nay cách tiếp cận theo phương pháp học máy (Machine Learning) đã chứng tỏ nhiều ưu thế về mức độ chính xác cũng như tin cậy so với một số mô hình phân loại theo phương pháp thống kê truyền thống.

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). Rủi ro chính của ngân hàng là khả năng khách hàng không có khả năng hoàn trả lại khoản vay mà ngân hàng đã cấp. Mặt khác, quyết định có hay không cung cấp một khoản vay cho khách hàng thường phụ thuộc nhiều vào trình độ cũng như kinh nghiệm của cán nhân viên thẩm định tín dụng (Thomas, 2000). Ngoài ra, căn cứ để cấp tín dụng cho một khách hàng còn căn cứ vào một số tiêu chí xếp hạng mà một số trong số đó là rất khó đo lường, hoặc khó có thể đo lường chính xác. Chẳng hạn tiêu chuẩn 5C khi cấp tín dụng là dựa trên những đánh giá của ngân hàng về tư cách, năng lực, vốn, tài sản thế chấp, và điều kiện của người xin vay (Abrahams & Zhang, 2008). Rõ ràng một số tiêu chí, chẳng hạn như tư cách và năng lực của người vay là một nhân tố khó đánh giá và do vậy có thể dẫn đến các sai sót khi quyết định cho vay. Ngoài ra phương pháp đánh giá xếp hạng tín dụng dựa trên tiêu chuẩn 5C là có chi phí cao và có thể xẩy ra sự không nhất quán về việc cho vay hay không giữa những nhân viên thẩm định tín dụng khác nhau đối với cùng một hồ sơ xin vay. Vì những hạn chế này, các ngân hàng cũng như các tổ chức tài chính cần sử dụng các phương pháp thẩm định và xếp hạng tín dụng tin cậy, khách quan và chi phí thấp nhằm giúp những tổ chức này quyết định có hay không cấp tín dụng cho các hồ sơ xin vay (Akhavein, Frame, & White, 2005; Chye, Chin, & Peng, 2004). Hơn nữa, theo Thomas và ctg (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ế.

Đối với vấn đề phân loại tín dụng, cách tiếp cận truyền thống là dựa vào các phương pháp thống kê thuần túy như hồi quy tuyến tính đa biến (Meyer & Pifer, 1970), phân tích khác biệt (Altman, 1968; Banasik, Crook, & Thomas, 2003), và hồi quy Logistic (Desai, Crook, & Overstreet, 1996; Dimitras, Zanakis, & Zopounidis, 1996; Elliott & Filinkov, 2008; Lee, Chiu, Lu, & Chen, 2002). Tuy nhiên những yêu cầu của hội đồng Basel về giám sát hoạt động ngân hàng (the Basel Committee on Banking Supervision) ban hành năm 2004 đòi hỏi các ngân hàng cũng như các tổ chức tài chính phải sử dụng những mô hình phân loại tín dụng tin cậy hơn nhằm nâng cao hiệu quả của việc phân bổ vốn. Nhằm đáp ứng những đòi hỏi trên, trong những năm gần đây đã xuất hiện một số mô hình phân loại tín dụng mới theo cách tiếp cận của học máy (Machine Learning) và trí thông minh nhân tạo (Artificial Intelligence). Không giống như các tiếp cận trước đây, các phương pháp mới này không đưa ra bất kì giả thiết chặt chẽ nào như đòi hỏi của các cách tiếp cận theo phương pháp thống kê. Thay vào đó, các tiếp cận mới này cố gắng khai thác và đưa ra các kiến thức, các thông tin đầu ra chỉ dựa vào các thông tin đầu vào là các quan sát, các thông tin trong quá khứ. Với bài toán phân loại tín dụng, một số mô hình thuộc học máy như mạng trí tuệ nhân tạo ANN (Artificial Neural Network), Máy Hỗ Trợ Véctơ SVM (Support Vector Machines), K láng giềng gần nhất KNN (K-Nearest Neighbors), rừng ngẫu nhiên RF (Random Forest), cây quyết định DT (Decision Tree) chẳng hạn đã chứng tỏ nhiều ưu thế về mức độ chính xác cũng như tin cậy so với một số mô hình phân loại truyền thống (Chi & Hsu, 2012; Huang et.all, 2004; Huang, Chen, & Wang, 2007; Ince & Aktan, 2009; Martens và et al., 2010).

Post này sẽ trình bày quá trình xây dựng mô hình xếp hạng theo thẻ điểm (thường gọi là Scorecard Modelling / Credit Scoring) đồng thời so sánh khả năng phân biệt của cả hai cách tiếp cận là hồi quy Logistic với biến được thực hiện WOE Transformation và Random Forest - một cách tiếp cận của Machine Learning với bộ số liệu hmeq.csv của cuốn sách Credit Risk Analytics: Measurement Techniques, Applications, and Examples in SAS.

Process of Developing The Scorecard Model

Bất kể cách tiếp cận được sử dụng cho Scorecard Modelling là thống kê truyền thống (như sử dụng Logistic Regression) hay Machine Learning thì các bước xây dựng mô hình thường tuân theo các bước với thứ tự như sau:

  1. Lên sách sách các biến có thể được sử dụng cho mô hình. Danh sách biến này gọi là long list of variables (gọi tắt là long list).
  2. Thực hiện phân tích đơn biến (single-variable Analysis) để rút gọn danh sách biến ở long list. Thực chất đây là quá trình phân tích nhằm lựa chọn biến số cho mô hình dựa trên một số tiêu chuẩn nào đó, ví dụ, như là Information Value (IV). Bước này ta sẽ thu được cái gọi là short list.
  3. Với các biến thuộc danh sách short list, thực hiện phân tích đa biến (Multivariable Analysis). Bước này được thực hiện để, ví dụ, phát hiện ra biến tương quan cao và lựa chọn biến nào cho mô hình là hợp lí nếu chúng ta có, ví dụ, một cặp biến tương quan cao trên một ngưỡng định trước nào đó.
  4. Xây dựng mô hình và hiệu chỉnh.
  5. Đánh giá chất lượng (và so sánh) chất lượng của các mô hình dựa trên một hoặc một số tiêu chí được sử dụng phổ biến như AUC chẳng hạn.

Các bước mô tả ở trên là không cố định và có thể có một số tùy biến tùy biến. Bạn đọc quan tâm có thể tham khảo kĩ hơn từ:

  1. Credit Risk Analytics: Measurement Techniques, Applications, and Examples in SAS.

  2. IFRS 9 and CECL Credit Risk Modelling and Validation.

  3. Credit Scoring: The Development Process from End to End.

  4. A Step-by-Step Guide To Creating Credit Scoring Model From Scratch.

R Codes for Scorecard Modelling

Dưới đây là R codes cho Scorecard Modelling. Trước hết (và luôn làm đầu tiên) là thực hiện tiền xử lí - làm sạch số liệu:

Thực hiện phân tích lựa chọn biến số dựa trên tiêu chuẩn IV như mô tả bởi Bellini (2019) và Baesens et al. (2013):

## [INFO] creating woe binning ...

Theo thông lệ, chỉ có các biến có IV lớn hơn 0.1 mới được sử dụng cho mô hình. Trong post này thì tất cả các biến sẽ được sử dụng. Dưới đây là R Codes cho thực hiện Logistic Regression với biến đã thực hiện WOE Transformation:

## [INFO] converting into woe values ... 
## [INFO] converting into woe values ...
Table 1: Coefficients from Logistic Models Based on WOE Transformation Variables
term estimate std.error statistic p.value
(Intercept) -1.417 0.064 -22.030 0.000
LOAN_woe -0.606 0.149 -4.079 0.000
MORTDUE_woe -0.821 0.270 -3.040 0.002
VALUE_woe -0.558 0.158 -3.535 0.000
REASON_woe -0.835 0.483 -1.727 0.084
JOB_woe -0.976 0.264 -3.702 0.000
YOJ_woe -0.917 0.204 -4.490 0.000
DEROG_woe -0.692 0.093 -7.442 0.000
DELINQ_woe -0.936 0.083 -11.245 0.000
CLAGE_woe -0.842 0.138 -6.104 0.000
NINQ_woe -0.294 0.166 -1.765 0.078
CLNO_woe -0.959 0.192 -4.999 0.000
DEBTINC_woe -0.917 0.047 -19.561 0.000

Scorecard của mỗi một hồ sơ xin vay được tính toán dựa trên Probability of Default (PD) được dự báo từ mô hình. Trước hết viết hàm tính toán Scorecard Point dựa trên PD như mô tả của Bellini (2019) và Baesens et al. (2013):

Với Scorecard Point dựa trên PD dự báo từ mô hình Logistic thì điểm trung bình cho hai nhóm hồ sơ Bad và Good rõ ràng có sự khác biệt. Sự khác biệt này mà càng lớn thì đó là dấu hiệu của một mô hình phân loại tốt:

Table 2: Scorecad Points by Group for Test Data
BAD min max median mean n
Bad 45 744 382 393 612
Good 213 831 615 593 2368

Chúng ta có thể hình ảnh hóa khả năng phân biệt hai nhóm Bad và Good dựa trên Scorecard Point bằng công cụ hình ảnh:

Theo thông lệ, AUC (và biến thể của nó là GINI Index = 2*AUC - 1) là một tiêu chí được sử dụng để đánh giá mô hình phân loại. Dưới đây là giá trị AUC và ROC curve của mô hình Logistic:

Giá trị AUC trên test data là 87.8% (một con số rất cao) và theo quy ước thì giá trị này là dấu hiệu cho thấy rằng cách tiếp cận mà chúng ta sử dụng (mô hình Logistic với biến WOE Transformation) là tốt.

Nhưng sử dụng Random Forest - một cách tiếp cận của Machine Learning còn tốt hơn nữa - thể hiện qua khả năng xác định (detect) các hồ sơ là Bad và cả AUC.

Machine Learning Approach to Scorecard Modelling

Trước hết chúng ta huấn luyện RF trên cùng một bộ dữ liệu như đã sử dụng để xây dựng mô hình Logistic ở trên:

Dựa trên 25 thử nghiệm thì giá trị AUC của mô hình RF là 95.4%:

Table 3: Model Performance by AUC
Model Average AUC
ranger 0.954

AUC cao hơn nghĩa là PD dự báo từ RF là tốt hơn so với Logistic. Điều này được thấy qua sự khác biệt về điểm giữa hai nhóm:

Table 4: Scorecad Points by Group for Test Data
BAD min max median mean n
Bad 81 836 356 365 612
Good 304 836 621 623 2368

Phân phối về điểm cho hai nhóm hồ sơ của mô hình RF:

AUC của RF cũng cao hơn và đương nhiên giá trị này, dù chưa tính thì chúng ta cũng có thể kì vọng là không khác biệt quá nhiều so với con số 0.954 đã biết:

Các ngân hàng lựa chọn AUC/ROC để đánh giá và so sách khả năng phân loại của các mô hình cạnh tranh nhau (như Logistic và RF) nhưng đồng thời chúng cũng quan tâm đến một khía cạnh thực tế sau đó là khả năng cover / detect các hồ sơ là Bad trong tổng số, ví dụ, 500 hồ sơ được xét.

Bằng chứng bằng số dưới đây chỉ ra rằng khả năng detect các hồ sơ Bad của RF luôn cao hơn Logistic

# Comparision based on PD predicted: 

df_test_ml %>% 
  mutate(PD_glm = pd_logit, PD_rf = pd_rf, 
         Score_glm = scaled_score(pd_logit), 
         Score_rf = scaled_score(pd_rf)) -> df_results

# Function for ranking by PD: 

coverBad_byPD <- function(n_cases) {
  
  df_cover_glm <- df_results %>% 
    arrange(-PD_glm) %>% 
    slice(1:n_cases) %>% 
    group_by(BAD) %>% 
    count() %>% 
    ungroup() %>% 
    mutate(Model = "GLM")
  
  df_cover_rf <- df_results %>% 
    arrange(-PD_rf) %>% 
    slice(1:n_cases) %>% 
    group_by(BAD) %>% 
    count() %>% 
    ungroup() %>% 
    mutate(Model = "RF")

  return(bind_rows(df_cover_glm, df_cover_rf) %>% mutate(N = n_cases))
  
}

# Function for ranking by scorecard score: 
coverBad_byScore <- function(n_cases) {
  
  df_cover_glm <- df_results %>% 
    arrange(Score_glm) %>% 
    slice(1:n_cases) %>% 
    group_by(BAD) %>% 
    count() %>% 
    ungroup() %>% 
    mutate(Model = "GLM")
  
  df_cover_rf <- df_results %>% 
    arrange(Score_rf) %>% 
    slice(1:n_cases) %>% 
    group_by(BAD) %>% 
    count() %>% 
    ungroup() %>% 
    mutate(Model = "RF")

  return(bind_rows(df_cover_glm, df_cover_rf) %>% mutate(N = n_cases))
  
}


# Use the functions:   

df_cover_socre <- do.call("bind_rows", lapply(seq(200, 1000, 100), coverBad_byScore))
df_cover_pd <- do.call("bind_rows", lapply(seq(200, 1000, 100), coverBad_byPD))

# http://bradleyboehmke.github.io/tutorials/barchart

df_cover_socre %>% 
  filter(BAD == "Bad") %>% 
  ggplot(aes(x = N, y = n, fill = Model)) + 
  geom_bar(stat = "identity", position = "dodge") + 
  scale_x_continuous(breaks = seq(200, 1000, 100)) + 
  scale_y_continuous(breaks = seq(0, 600, 100)) + 
  geom_text(aes(label = n), position = position_dodge(0.9), vjust = 1.2) + 
  theme(panel.grid.major.x = element_blank()) + 
  theme(panel.grid.minor.x = element_blank()) + 
  labs(x = "Number of Cases Classified", y = "Number of Bad Cases", 
       caption = "Data Source: http://www.creditriskanalytics.net/", 
       title = "Figure 5: Ability to Distinguish Bad Cases by the two Models")

Ví dụ, trong 200 hồ sơ có điểm Scorecard thấp nhất thì nếu sử dụng RF ngân hàng sẽ xác định được 198 cases là Bad trong khi con số này là 176 nếu sử dụng Scorecard thu được từ mô hình Logistic.

Nghĩa là tỉ lệ xác định các hồ sơ Bad của RF luôn cao hơn Logistic:

Figure 5 chỉ ra rằng nếu ngân hàng xét 500 cases dựa trên điểm Scorecard từ hai mô hình thì RF sẽ xác định hơn 70% là Bad trong khi Logistic chỉ xác định được gần 60%.

Đương nhiên nếu chúng ta căn cứ vào PD thì kết quả cũng không khác biệt. Vì Scorecard chỉ là cách diễn giải khác (là một biến thể) của PD như chúng ta có thể thấy qua công thức chuyển hóa điểm Scorecard từ PD.

Nếu muốn kiểm tra chúng ta có thể sử dụng codes sau:

Final Conclusions

Bằng chứng thực nghiệm dựa trên bộ số liệu hmeq.csv đã chỉ ra rằng Scorecard Point dựa trên PD được dự báo từ Random Forest là hiệu quả hơn so với Logistic Regrassion ở cả hai tiêu chuẩn: (1) tiêu chuẩn thống kê AUC/ROC, và (2) khả năng cover (phân loại) hồ sơ Bad.

Một số vấn đề khác khi xây dựng Scorecard Modelling / Credit Scoring chưa được thảo luận và làm rõ trong post này là:

  1. Accuracy chỉ là điều kiện cần chứ không phải là tiêu chuẩn để căn cứ cho việc lựa chọn mô hình. Chi tiết xem thêm ở đây.

  2. Nếu có thêm thông tin (như mỗi hồ sơ duyệt vay được vay bao nhiêu và với lãi suất bao nhiêu) thì bank sẽ lựa chọn và đánh giá tác động của mô hình căn cứ vào tiêu chuẩn lợi nhuận. Chi tiết xem thêm ở đây.

  3. Các tiêu chuẩn dựa trên thống kê như AUC (hay Accuracy) chỉ là một trong số các tiêu chí thường được sử dụng khi đánh giá và lựa chọn các mô hình cạnh tranh khác nhau.. Chi tiết xem thêm ở đây.

  4. Lựa chọn biến căn cứ vào WOE / IV được trình bày và giải thích chi tiết ở đây, ở đâyở đây.

  5. Theo thông lệ, các hồ sơ xin vay được dán các nhãn xanh - đỏ - vàng với hàm ý các hồ sơ nhãn xanh (nhóm điểm cao) là tốt, ít rủi ro nhất còn nhãn đỏ (nhóm điểm thấp) là rủi ro nhất còn vàng là nhóm trung gian chuyên tiếp. Việc dán nhãn xanh - đỏ - vàng dựa trên Scorecard Point sẽ phụ thuộc vào nhiều yếu tố bao gồm cả định hướng và mức độ ưa thích rủi ro của tổ chức sử dụng mô hình.

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. Bellini, T. (2019). IFRS 9 and CECL Credit Risk Modelling and Validation: A Practical Guide with Examples Worked in R and SAS. Academic Press.

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

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

  6. Hand DJ, Henley WE (1997): Statistical Classification Methods in Consumer Credit Scoring: a review. Journal. of the Royal Statistical Society, Series A, 160(3):523–541.

  7. Thomas LC (2000): A survey of credit and behavioural scoring: forecasting financial risk of lending to consumers. International Journal of Forecasting, 16(2):149–172 .

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

  9. Crook JN, Edelman DB, Thomas LC (2007): Recent developments in consumer credit risk assessment. European Journal of Operational Research, 183(3):1447–1465.

  10. Van Gestel, T., B. Baesens, P. Van Dijcke, J. Suykens, J. Garcia, and T. Alderweireld. 2005. “Linear and Nonlinear Credit Scoring by Combining Logistic Regression and Support Vector Machines.” Journal of Credit Risk 1, no. 4.

  11. 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.

LS0tDQp0aXRsZTogIkEgRGV0YWlsZWQgQ29tcGFyaXNvbiBCZXR3ZWVuIE1hY2hpbmUgTGVhcm5pbmcgYW5kIExvZ2lzdGljIEFwcHJvYWNoIHRvIFNjb3JlY2FyZCBNb2RlbGxpbmcvQ3JlZGl0IFNjb3JpbmciIA0Kc3VidGl0bGU6ICJSIGZvciBQbGVhc3VyZSINCmF1dGhvcjogIk5ndXllbiBDaGkgRHVuZyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICAjIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6ICJmbGF0bHkiDQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KDQohW10oQzpcXFVzZXJzXFxaYm9va1xcRGVza3RvcFxccGljXFxzY29yZWNhcmQucG5nKQ0KDQojIEludHJvZHVjdGlvbg0KDQpY4bq/cCBo4bqhbmcgdMOtbiBk4bulbmcgKENyZWRpdCBTY29yaW5nIC8gU2NvY2FyZCBNb2RlbGxpbmcpIMSRw7NuZyBt4buZdCB2YWkgdHLDsiBxdWFuIHRy4buNbmcgxJHhu5FpIHbhu5tpIGzhu6NpIG5odeG6rW4gdsOgIHBow6F0IHRyaeG7g24gYuG7gW4gduG7r25nIGPhu6dhIG5nw6JuIGjDoG5nIG7Ds2kgcmnDqm5nIGPFqW5nIG5oxrAgY8OhYyB04buVIGNo4bupYyB0w6BpIGNow61uaCBraMOhYy4gSGnhu4duIG5heSBjw6FjaCB0aeG6v3AgY+G6rW4gdGhlbyBwaMawxqFuZyBwaMOhcCBo4buNYyBtw6F5IChNYWNoaW5lIExlYXJuaW5nKSDEkcOjIGNo4bupbmcgdOG7jyBuaGnhu4F1IMawdSB0aOG6vyB24buBIG3hu6ljIMSR4buZIGNow61uaCB4w6FjIGPFqW5nIG5oxrAgdGluIGPhuq15IHNvIHbhu5tpIG3hu5l0IHPhu5EgbcO0IGjDrG5oIHBow6JuIGxv4bqhaSB0aGVvIHBoxrDGoW5nIHBow6FwIHRo4buRbmcga8OqIHRydXnhu4FuIHRo4buRbmcuDQoNClPhu7Ega2nhu4duIGN14buZYyBraOG7p25nIGhv4bqjbmcgdMOgaSBjaMOtbmggZOG6q24gxJHhur9uIHPhu7Egc+G7pXAgxJHhu5UgY+G7p2EgbeG7mXQgbG/huqF0IGPDoWMgxJHhu4tuaCBjaOG6vyB0w6BpIGNow61uaCBuw7NpIGNodW5nIHbDoCBuZ8OibiBow6BuZyBuw7NpIHJpw6puZyDEkcOjIHRo4bupYyB04buJbmggY8OhYyB04buVIGNo4bupYyBuw6B5IGNow7ogdHLhu41uZyBoxqFuIMSR4bq/biB2YWkgdHLDsiBj4bunYSB0aOG6qW0gxJHhu4tuaCB0w61uIGThu6VuZyB0cm9uZyBob+G6oXQgxJHhu5luZyBj4bunYSBtw6xuaC4gSOG6p3UgaOG6v3QgbOG7o2kgbmh14bqtbiBj4bunYSBjw6FjIG5nw6JuIGjDoG5nIMSR4bq/biB04burIGhv4bqhdCDEkeG7mW5nIGPhuqVwIHTDrW4gZOG7pW5nIHbDoCBjaG8gdmF5LiBD4bqlcCB0w61uIGThu6VuZyBsw6AgbeG7mXQgdHJvbmcgbmjhu69uZyBob+G6oXQgxJHhu5luZyB04bqhbyByYSBt4buZdCB04buJIHRy4buNbmcgbOG7m24gduG7gSBkb2FuaCB0aHUgdsOgIGzhu6NpIG5odeG6rW4gY2hvIG5nw6JuIGjDoG5nIG5oxrBuZyBjxaluZyB0aeG7gW0g4bqpbiBy4bqldCBuaGnhu4F1IHLhu6dpIHJvIChaYWtyemV3c2thLCAyMDA3KS4gUuG7p2kgcm8gY2jDrW5oIGPhu6dhIG5nw6JuIGjDoG5nIGzDoCBraOG6oyBuxINuZyBraMOhY2ggaMOgbmcga2jDtG5nIGPDsyBraOG6oyBuxINuZyBob8OgbiB0cuG6oyBs4bqhaSBraG/huqNuIHZheSBtw6AgbmfDom4gaMOgbmcgxJHDoyBj4bqlcC4gTeG6t3Qga2jDoWMsIHF1eeG6v3QgxJHhu4tuaCBjw7MgaGF5IGtow7RuZyBjdW5nIGPhuqVwIG3hu5l0IGtob+G6o24gdmF5IGNobyBraMOhY2ggaMOgbmcgdGjGsOG7nW5nIHBo4bulIHRodeG7mWMgbmhp4buBdSB2w6BvIHRyw6xuaCDEkeG7mSBjxaluZyBuaMawIGtpbmggbmdoaeG7h20gY+G7p2EgY8OhbiBuaMOibiB2acOqbiB0aOG6qW0gxJHhu4tuaCB0w61uIGThu6VuZyAoVGhvbWFzLCAyMDAwKS4gTmdvw6BpIHJhLCBjxINuIGPhu6kgxJHhu4MgY+G6pXAgdMOtbiBk4bulbmcgY2hvIG3hu5l0IGtow6FjaCBow6BuZyBjw7JuIGPEg24gY+G7qSB2w6BvIG3hu5l0IHPhu5EgdGnDqnUgY2jDrSB44bq/cCBo4bqhbmcgbcOgIG3hu5l0IHPhu5EgdHJvbmcgc+G7kSDEkcOzIGzDoCBy4bqldCBraMOzIMSRbyBsxrDhu51uZywgaG/hurdjIGtow7MgY8OzIHRo4buDIMSRbyBsxrDhu51uZyBjaMOtbmggeMOhYy4gQ2jhurNuZyBo4bqhbiB0acOqdSBjaHXhuqluIDVDIGtoaSBj4bqlcCB0w61uIGThu6VuZyBsw6AgZOG7sWEgdHLDqm4gbmjhu69uZyDEkcOhbmggZ2nDoSBj4bunYSBuZ8OibiBow6BuZyB24buBIHTGsCBjw6FjaCwgbsSDbmcgbOG7sWMsIHbhu5FuLCB0w6BpIHPhuqNuIHRo4bq/IGNo4bqlcCwgdsOgIMSRaeG7gXUga2nhu4duIGPhu6dhIG5nxrDhu51pIHhpbiB2YXkgKEFicmFoYW1zICYgWmhhbmcsIDIwMDgpLiBSw7UgcsOgbmcgbeG7mXQgc+G7kSB0acOqdSBjaMOtLCBjaOG6s25nIGjhuqFuIG5oxrAgdMawIGPDoWNoIHbDoCBuxINuZyBs4buxYyBj4bunYSBuZ8aw4budaSB2YXkgbMOgIG3hu5l0IG5ow6JuIHThu5Ega2jDsyDEkcOhbmggZ2nDoSB2w6AgZG8gduG6rXkgY8OzIHRo4buDIGThuqtuIMSR4bq/biBjw6FjIHNhaSBzw7N0IGtoaSBxdXnhur90IMSR4buLbmggY2hvIHZheS4gTmdvw6BpIHJhIHBoxrDGoW5nIHBow6FwIMSRw6FuaCBnacOhIHjhur9wIGjhuqFuZyB0w61uIGThu6VuZyBk4buxYSB0csOqbiB0acOqdSBjaHXhuqluIDVDIGzDoCBjw7MgY2hpIHBow60gY2FvIHbDoCBjw7MgdGjhu4MgeOG6qXkgcmEgc+G7sSBraMO0bmcgbmjhuqV0IHF1w6FuIHbhu4Egdmnhu4djIGNobyB2YXkgaGF5IGtow7RuZyBnaeG7r2Egbmjhu69uZyBuaMOibiB2acOqbiB0aOG6qW0gxJHhu4tuaCB0w61uIGThu6VuZyBraMOhYyBuaGF1IMSR4buRaSB24bubaSBjw7luZyBt4buZdCBo4buTIHPGoSB4aW4gdmF5LiBWw6wgbmjhu69uZyBo4bqhbiBjaOG6vyBuw6B5LCBjw6FjIG5nw6JuIGjDoG5nIGPFqW5nIG5oxrAgY8OhYyB04buVIGNo4bupYyB0w6BpIGNow61uaCBj4bqnbiBz4butIGThu6VuZyBjw6FjIHBoxrDGoW5nIHBow6FwIHRo4bqpbSDEkeG7i25oIHbDoCB44bq/cCBo4bqhbmcgdMOtbiBk4bulbmcgdGluIGPhuq15LCBraMOhY2ggcXVhbiB2w6AgY2hpIHBow60gdGjhuqVwIG5o4bqxbSBnacO6cCBuaOG7r25nIHThu5UgY2jhu6ljIG7DoHkgcXV54bq/dCDEkeG7i25oIGPDsyBoYXkga2jDtG5nIGPhuqVwIHTDrW4gZOG7pW5nIGNobyBjw6FjIGjhu5Mgc8ahIHhpbiB2YXkgKEFraGF2ZWluLCBGcmFtZSwgJiBXaGl0ZSwgMjAwNTsgQ2h5ZSwgQ2hpbiwgJiBQZW5nLCAyMDA0KS4gSMahbiBu4buvYSwgdGhlbyBUaG9tYXMgdsOgIGN0ZyAoMjAwMiksIGPDoWMgbmfDom4gaMOgbmcgY+G6p24gbeG7mXQgcGjGsMahbmcgcGjDoXAgeOG6v3AgaOG6oW5nIHTDrW4gZOG7pW5nIG3DoCB0aOG7j2EgbcOjbiBuaOG7r25nIMSRw7JpIGjhu49pIHNhdTogKDEpIGNoaSBwaMOtIHLhursgdsOgIGThu4UgduG6rW4gaMOgbmgsICgyKSBuaGFuaCBjaMOzbmcgdsOgIOG7lW4gxJHhu4tuaCwgKDMpIMSRxrBhIHJhIG5o4buvbmcgcXV54bq/dCDEkeG7i25oIG5o4bqldCBxdcOhbiBk4buxYSB0csOqbiBjw6FjIHRow7RuZyB0aW4ga2jDoWNoIHF1YW4ga2jDtG5nIHBo4bulIHRodeG7mWMgdsOgbyBj4bqjbSB4w7pjIHbDoCB0w6xuaCBj4bqjbSBjaOG7pyBxdWFuIGPhu6dhIGNvbiBuZ8aw4budaSwgdsOgICg0KSBoaeG7h3UgcXXhuqMgY+G7p2EgaOG7hyBwaMawxqFuZyBwaMOhcCB44bq/cCBo4bqhbmcgdMOtbiBk4bulbmcgY8OzIHRo4buDIGThu4UgZMOgbmcga2nhu4NtIHRyYSwgxJFp4buBdSBjaOG7iW5oIOG7nyBi4bqldCBrw6wgdGjhu51pIMSRaeG7g20gbsOgbyBuaOG6sW0gxJFp4buBdSBjaOG7iW5oIGvhu4twIHRo4budaSB24bubaSBuaOG7r25nIHRoYXkgxJHhu5VpIHbhu4EgY2jDrW5oIHPDoWNoIGhv4bq3YyDEkWnhu4F1IGtp4buHbiBj4bunYSBu4buBbiBraW5oIHThur8uDQoNCsSQ4buRaSB24bubaSB24bqlbiDEkeG7gSBwaMOibiBsb+G6oWkgdMOtbiBk4bulbmcsIGPDoWNoIHRp4bq/cCBj4bqtbiB0cnV54buBbiB0aOG7kW5nIGzDoCBk4buxYSB2w6BvIGPDoWMgcGjGsMahbmcgcGjDoXAgdGjhu5FuZyBrw6ogdGh14bqnbiB0w7p5IG5oxrAgaOG7k2kgcXV5IHR1eeG6v24gdMOtbmggxJFhIGJp4bq/biAoTWV5ZXIgJiBQaWZlciwgMTk3MCksIHBow6JuIHTDrWNoIGtow6FjIGJp4buHdCAoQWx0bWFuLCAxOTY4OyBCYW5hc2lrLCBDcm9vaywgJiBUaG9tYXMsIDIwMDMpLCB2w6AgaOG7k2kgcXV5IExvZ2lzdGljIChEZXNhaSwgQ3Jvb2ssICYgT3ZlcnN0cmVldCwgMTk5NjsgRGltaXRyYXMsIFphbmFraXMsICYgWm9wb3VuaWRpcywgMTk5NjsgRWxsaW90dCAmIEZpbGlua292LCAyMDA4OyBMZWUsIENoaXUsIEx1LCAmIENoZW4sIDIwMDIpLiBUdXkgbmhpw6puIG5o4buvbmcgecOqdSBj4bqndSBj4bunYSBo4buZaSDEkeG7k25nIEJhc2VsIHbhu4EgZ2nDoW0gc8OhdCBob+G6oXQgxJHhu5luZyBuZ8OibiBow6BuZyAodGhlIEJhc2VsIENvbW1pdHRlZSBvbiBCYW5raW5nIFN1cGVydmlzaW9uKSBiYW4gaMOgbmggbsSDbSAyMDA0IMSRw7JpIGjhu49pIGPDoWMgbmfDom4gaMOgbmcgY8WpbmcgbmjGsCBjw6FjIHThu5UgY2jhu6ljIHTDoGkgY2jDrW5oIHBo4bqjaSBz4butIGThu6VuZyBuaOG7r25nIG3DtCBow6xuaCBwaMOibiBsb+G6oWkgdMOtbiBk4bulbmcgdGluIGPhuq15IGjGoW4gbmjhurFtIG7Dom5nIGNhbyBoaeG7h3UgcXXhuqMgY+G7p2Egdmnhu4djIHBow6JuIGLhu5UgduG7kW4uIE5o4bqxbSDEkcOhcCDhu6luZyBuaOG7r25nIMSRw7JpIGjhu49pIHRyw6puLCB0cm9uZyBuaOG7r25nIG7Eg20gZ+G6p24gxJHDonkgxJHDoyB4deG6pXQgaGnhu4duIG3hu5l0IHPhu5EgbcO0IGjDrG5oIHBow6JuIGxv4bqhaSB0w61uIGThu6VuZyBt4bubaSB0aGVvIGPDoWNoIHRp4bq/cCBj4bqtbiBj4bunYSBo4buNYyBtw6F5IChNYWNoaW5lIExlYXJuaW5nKSB2w6AgdHLDrSB0aMO0bmcgbWluaCBuaMOibiB04bqhbyAoQXJ0aWZpY2lhbCBJbnRlbGxpZ2VuY2UpLiBLaMO0bmcgZ2nhu5FuZyBuaMawIGPDoWMgdGnhur9wIGPhuq1uIHRyxrDhu5tjIMSRw6J5LCBjw6FjIHBoxrDGoW5nIHBow6FwIG3hu5tpIG7DoHkga2jDtG5nIMSRxrBhIHJhIGLhuqV0IGvDrCBnaeG6oyB0aGnhur90IGNo4bq3dCBjaOG6vSBuw6BvIG5oxrAgxJHDsmkgaOG7j2kgY+G7p2EgY8OhYyBjw6FjaCB0aeG6v3AgY+G6rW4gdGhlbyBwaMawxqFuZyBwaMOhcCB0aOG7kW5nIGvDqi4gVGhheSB2w6BvIMSRw7MsIGPDoWMgdGnhur9wIGPhuq1uIG3hu5tpIG7DoHkgY+G7kSBn4bqvbmcga2hhaSB0aMOhYyB2w6AgxJHGsGEgcmEgY8OhYyBraeG6v24gdGjhu6ljLCBjw6FjIHRow7RuZyB0aW4gxJHhuqd1IHJhIGNo4buJIGThu7FhIHbDoG8gY8OhYyB0aMO0bmcgdGluIMSR4bqndSB2w6BvIGzDoCBjw6FjIHF1YW4gc8OhdCwgY8OhYyB0aMO0bmcgdGluIHRyb25nIHF1w6Ega2jhu6kuIFbhu5tpIGLDoGkgdG/DoW4gcGjDom4gbG/huqFpIHTDrW4gZOG7pW5nLCBt4buZdCBz4buRIG3DtCBow6xuaCB0aHXhu5ljIGjhu41jIG3DoXkgbmjGsCBt4bqhbmcgdHLDrSB0deG7hyBuaMOibiB04bqhbyBBTk4gKEFydGlmaWNpYWwgTmV1cmFsIE5ldHdvcmspLCBNw6F5IEjhu5cgVHLhu6MgVsOpY3TGoSBTVk0gKFN1cHBvcnQgVmVjdG9yIE1hY2hpbmVzKSwgSyBsw6FuZyBnaeG7gW5nIGfhuqduIG5o4bqldCBLTk4gKEstTmVhcmVzdCBOZWlnaGJvcnMpLCBy4burbmcgbmfhuqt1IG5oacOqbiBSRiAoUmFuZG9tIEZvcmVzdCksIGPDonkgcXV54bq/dCDEkeG7i25oIERUIChEZWNpc2lvbiBUcmVlKSBjaOG6s25nIGjhuqFuIMSRw6MgY2jhu6luZyB04buPIG5oaeG7gXUgxrB1IHRo4bq/IHbhu4EgbeG7qWMgxJHhu5kgY2jDrW5oIHjDoWMgY8WpbmcgbmjGsCB0aW4gY+G6rXkgc28gduG7m2kgbeG7mXQgc+G7kSBtw7QgaMOsbmggcGjDom4gbG/huqFpIHRydXnhu4FuIHRo4buRbmcgKENoaSAmIEhzdSwgMjAxMjsgSHVhbmcgZXQuYWxsLCAyMDA0OyBIdWFuZywgQ2hlbiwgJiBXYW5nLCAyMDA3OyBJbmNlICYgQWt0YW4sIDIwMDk7IE1hcnRlbnMgdsOgIGV0IGFsLiwgMjAxMCkuDQoNCg0KUG9zdCBuw6B5IHPhur0gdHLDrG5oIGLDoHkgcXXDoSB0csOsbmggeMOieSBk4buxbmcgbcO0IGjDrG5oIHjhur9wIGjhuqFuZyB0aGVvIHRo4bq7IMSRaeG7g20gKHRoxrDhu51uZyBn4buNaSBsw6AgU2NvcmVjYXJkIE1vZGVsbGluZyAvIENyZWRpdCBTY29yaW5nKSDEkeG7k25nIHRo4budaSBzbyBzw6FuaCBraOG6oyBuxINuZyBwaMOibiBiaeG7h3QgY+G7p2EgY+G6oyBoYWkgY8OhY2ggdGnhur9wIGPhuq1uIGzDoCBo4buTaSBxdXkgTG9naXN0aWMgduG7m2kgYmnhur9uIMSRxrDhu6NjIHRo4buxYyBoaeG7h24gIFdPRSBUcmFuc2Zvcm1hdGlvbiB2w6AgUmFuZG9tIEZvcmVzdCAtIG3hu5l0IGPDoWNoIHRp4bq/cCBj4bqtbiBj4bunYSBNYWNoaW5lIExlYXJuaW5nIHbhu5tpIGLhu5kgc+G7kSBsaeG7h3UgaG1lcS5jc3YgY+G7p2EgY3Xhu5FuIHPDoWNoIFtDcmVkaXQgUmlzayBBbmFseXRpY3M6IE1lYXN1cmVtZW50IFRlY2huaXF1ZXMsIEFwcGxpY2F0aW9ucywgYW5kIEV4YW1wbGVzIGluIFNBU10oaHR0cHM6Ly93d3cuYW1hem9uLmNvbS9DcmVkaXQtUmlzay1BbmFseXRpY3MtTWVhc3VyZW1lbnQtQXBwbGljYXRpb25zL2RwLzExMTkxNDM5ODUpLiANCg0KIyBQcm9jZXNzIG9mIERldmVsb3BpbmcgVGhlIFNjb3JlY2FyZCBNb2RlbA0KDQpC4bqldCBr4buDIGPDoWNoIHRp4bq/cCBj4bqtbiDEkcaw4bujYyBz4butIGThu6VuZyBjaG8gU2NvcmVjYXJkIE1vZGVsbGluZyBsw6AgdGjhu5FuZyBrw6ogdHJ1eeG7gW4gdGjhu5FuZyAobmjGsCBz4butIGThu6VuZyBMb2dpc3RpYyBSZWdyZXNzaW9uKSBoYXkgTWFjaGluZSBMZWFybmluZyB0aMOsIGPDoWMgYsaw4bubYyB4w6J5IGThu7FuZyBtw7QgaMOsbmggdGjGsOG7nW5nIHR1w6JuIHRoZW8gY8OhYyBixrDhu5tjIHbhu5tpIHRo4bupIHThu7EgbmjGsCBzYXU6IA0KDQoxLiBMw6puIHPDoWNoIHPDoWNoIGPDoWMgYmnhur9uIGPDsyB0aOG7gyDEkcaw4bujYyBz4butIGThu6VuZyBjaG8gbcO0IGjDrG5oLiBEYW5oIHPDoWNoIGJp4bq/biBuw6B5IGfhu41pIGzDoCBsb25nIGxpc3Qgb2YgdmFyaWFibGVzIChn4buNaSB04bqvdCBsw6AgbG9uZyBsaXN0KS4gDQoyLiBUaOG7sWMgaGnhu4duIHBow6JuIHTDrWNoIMSRxqFuIGJp4bq/biAoc2luZ2xlLXZhcmlhYmxlIEFuYWx5c2lzKSDEkeG7gyByw7p0IGfhu41uIGRhbmggc8OhY2ggYmnhur9uIOG7nyBsb25nIGxpc3QuIFRo4buxYyBjaOG6pXQgxJHDonkgbMOgIHF1w6EgdHLDrG5oIHBow6JuIHTDrWNoIG5o4bqxbSBs4buxYSBjaOG7jW4gYmnhur9uIHPhu5EgY2hvIG3DtCBow6xuaCBk4buxYSB0csOqbiBt4buZdCBz4buRIHRpw6p1IGNodeG6qW4gbsOgbyDEkcOzLCB2w60gZOG7pSwgbmjGsCBsw6AgSW5mb3JtYXRpb24gVmFsdWUgKElWKS4gQsaw4bubYyBuw6B5IHRhIHPhur0gdGh1IMSRxrDhu6NjIGPDoWkgZ+G7jWkgbMOgIHNob3J0IGxpc3QuIA0KMy4gVuG7m2kgY8OhYyBiaeG6v24gdGh14buZYyBkYW5oIHPDoWNoIHNob3J0IGxpc3QsIHRo4buxYyBoaeG7h24gcGjDom4gdMOtY2ggxJFhIGJp4bq/biAoTXVsdGl2YXJpYWJsZSBBbmFseXNpcykuIELGsOG7m2MgbsOgeSDEkcaw4bujYyB0aOG7sWMgaGnhu4duIMSR4buDLCB2w60gZOG7pSwgcGjDoXQgaGnhu4duIHJhIGJp4bq/biB0xrDGoW5nIHF1YW4gY2FvIHbDoCBs4buxYSBjaOG7jW4gYmnhur9uIG7DoG8gY2hvIG3DtCBow6xuaCBsw6AgaOG7o3AgbMOtIG7hur91IGNow7puZyB0YSBjw7MsIHbDrSBk4bulLCBt4buZdCBj4bq3cCBiaeG6v24gdMawxqFuZyBxdWFuIGNhbyB0csOqbiBt4buZdCBuZ8aw4buhbmcgxJHhu4tuaCB0csaw4bubYyBuw6BvIMSRw7MuIA0KNC4gWMOieSBk4buxbmcgbcO0IGjDrG5oIHbDoCBoaeG7h3UgY2jhu4luaC4gDQo1LiDEkMOhbmggZ2nDoSBjaOG6pXQgbMaw4bujbmcgKHbDoCBzbyBzw6FuaCkgY2jhuqV0IGzGsOG7o25nIGPhu6dhIGPDoWMgbcO0IGjDrG5oIGThu7FhIHRyw6puIG3hu5l0IGhv4bq3YyBt4buZdCBz4buRIHRpw6p1IGNow60gxJHGsOG7o2Mgc+G7rSBk4bulbmcgcGjhu5UgYmnhur9uIG5oxrAgQVVDIGNo4bqzbmcgaOG6oW4uIA0KDQpDw6FjIGLGsOG7m2MgbcO0IHThuqMg4bufIHRyw6puIGzDoCBraMO0bmcgY+G7kSDEkeG7i25oIHbDoCBjw7MgdGjhu4MgY8OzIG3hu5l0IHPhu5EgdMO5eSBiaeG6v24gdMO5eSBiaeG6v24uIELhuqFuIMSR4buNYyBxdWFuIHTDom0gY8OzIHRo4buDIHRoYW0ga2jhuqNvIGvEqSBoxqFuIHThu6s6IA0KDQoxLiBbQ3JlZGl0IFJpc2sgQW5hbHl0aWNzOiBNZWFzdXJlbWVudCBUZWNobmlxdWVzLCBBcHBsaWNhdGlvbnMsIGFuZCBFeGFtcGxlcyBpbiBTQVNdKGh0dHBzOi8vd3d3LmFtYXpvbi5jb20vQ3JlZGl0LVJpc2stQW5hbHl0aWNzLU1lYXN1cmVtZW50LUFwcGxpY2F0aW9ucy9kcC8xMTE5MTQzOTg1KS4gDQoNCjIuIFtJRlJTIDkgYW5kIENFQ0wgQ3JlZGl0IFJpc2sgTW9kZWxsaW5nIGFuZCBWYWxpZGF0aW9uXShodHRwczovL3d3dy5hbWF6b24uY29tL0lGUlMtQ0VDTC1DcmVkaXQtTW9kZWxsaW5nLVZhbGlkYXRpb24tZWJvb2svZHAvQjA3TVYxUlE5TSkuIA0KDQoNCjMuIFtDcmVkaXQgU2NvcmluZzogVGhlIERldmVsb3BtZW50IFByb2Nlc3MgZnJvbSBFbmQgdG8gRW5kXShodHRwczovL3d3dy53b3JsZHByb2dyYW1taW5nLmNvbS9ibG9nL2NyZWRpdF9zY29yaW5nX2RldmVsb3BtZW50X3B0MSkuIA0KDQo0LiBbQSBTdGVwLWJ5LVN0ZXAgR3VpZGUgVG8gQ3JlYXRpbmcgQ3JlZGl0IFNjb3JpbmcgTW9kZWwgRnJvbSBTY3JhdGNoXShodHRwczovL3d3dy5hbmFseXRpY3NpbmRpYW1hZy5jb20vYS1zdGVwLWJ5LXN0ZXAtdG8tY3JlYXRpbmctY3JlZGl0LXNjb3JpbmctbW9kZWwtZnJvbS1zY3JhdGNoLykuIA0KDQoNCiMgUiBDb2RlcyBmb3IgU2NvcmVjYXJkIE1vZGVsbGluZw0KDQpExrDhu5tpIMSRw6J5IGzDoCBSIGNvZGVzIGNobyBTY29yZWNhcmQgTW9kZWxsaW5nLiBUcsaw4bubYyBo4bq/dCAodsOgIGx1w7RuIGzDoG0gxJHhuqd1IHRpw6puKSBsw6AgdGjhu7FjIGhp4buHbiB0aeG7gW4geOG7rSBsw60gLSBsw6BtIHPhuqFjaCBz4buRIGxp4buHdTogDQoNCmBgYHtyfQ0KDQoNCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgIFN0YXRlIDE6IERhdGEgUHJlLXByb2Nlc3NpbmcNCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyBMb2FkIHNvbWUgcGFja2FnZXMgZm9yIGRhdGEgbWFuaXB1bGF0aW9uOiANCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KGNhcmV0RW5zZW1ibGUpDQpsaWJyYXJ5KGJyb29tKQ0KbGlicmFyeShrbml0cikNCg0KIyBDbGVhciB3b3Jrc3BhY2U6IA0Kcm0obGlzdCA9IGxzKCkpDQoNCiMgSW1wb3J0IGRhdGE6IA0KaG1lcSA8LSByZWFkLmNzdigiaHR0cDovL3d3dy5jcmVkaXRyaXNrYW5hbHl0aWNzLm5ldC91cGxvYWRzLzEvOS81LzEvMTk1MTE2MDEvaG1lcS5jc3YiKQ0KDQojIEZ1bmN0aW9uIHJlcGxhY2VzIE5BIGJ5IG1lYW46IA0KcmVwbGFjZV9ieV9tZWFuIDwtIGZ1bmN0aW9uKHgpIHsNCiAgeFtpcy5uYSh4KV0gPC0gbWVhbih4LCBuYS5ybSA9IFRSVUUpDQogIHJldHVybih4KQ0KfQ0KDQojIEEgZnVuY3Rpb24gaW1wdXRlcyBOQSBvYnNlcnZhdGlvbnMgZm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlczogDQoNCnJlcGxhY2VfbmFfY2F0ZWdvcmljYWwgPC0gZnVuY3Rpb24oeCkgew0KICB4ICU+JSANCiAgICB0YWJsZSgpICU+JSANCiAgICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICAgIGFycmFuZ2UoLUZyZXEpIC0+PiBteV9kZg0KICANCiAgbl9vYnMgPC0gc3VtKG15X2RmJEZyZXEpDQogIHBvcCA8LSBteV9kZiQuICU+JSBhcy5jaGFyYWN0ZXIoKQ0KICBzZXQuc2VlZCgyOSkNCiAgeFtpcy5uYSh4KV0gPC0gc2FtcGxlKHBvcCwgc3VtKGlzLm5hKHgpKSwgcmVwbGFjZSA9IFRSVUUsIHByb2IgPSBteV9kZiRGcmVxKQ0KICByZXR1cm4oeCkNCn0NCg0KIyBVc2UgdGhlIHR3byBmdW5jdGlvbnM6IA0KZGYgPC0gaG1lcSAlPiUgDQogIG11dGF0ZV9pZihpcy5mYWN0b3IsIGFzLmNoYXJhY3RlcikgJT4lIA0KICBtdXRhdGUoUkVBU09OID0gY2FzZV93aGVuKFJFQVNPTiA9PSAiIiB+IE5BX2NoYXJhY3Rlcl8sIFRSVUUgfiBSRUFTT04pLCANCiAgICAgICAgIEpPQiA9IGNhc2Vfd2hlbihKT0IgPT0gIiIgfiBOQV9jaGFyYWN0ZXJfLCBUUlVFIH4gSk9CKSkgJT4lDQogIG11dGF0ZV9pZihpc19jaGFyYWN0ZXIsIGFzLmZhY3RvcikgJT4lIA0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgcmVwbGFjZV9ieV9tZWFuKSAlPiUgDQogIG11dGF0ZV9pZihpcy5mYWN0b3IsIHJlcGxhY2VfbmFfY2F0ZWdvcmljYWwpDQoNCg0KIyBTcGxpdCBkYXRhOiANCnNldC5zZWVkKDEpDQppZCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKHkgPSBkZiRCQUQsIHAgPSAwLjUsIGxpc3QgPSBGQUxTRSkNCg0KZGZfdHJhaW4gPC0gZGZbaWQsIF0gIyBUcmFpbiBkYXRhIGZvciBXT0UgdHJhbnNmb3JtYXRpb24gYW5kIExvZ2lzdGljIE1vZGVsLiANCmRmX3Rlc3QgPC0gZGZbLWlkLCBdICMgVGVzdCBkYXRhIGZvciBXT0UgdHJhbnNmb3JtYXRpb24gYW5kIExvZ2lzdGljIE1vZGVsLiANCg0KYGBgDQoNClRo4buxYyBoaeG7h24gcGjDom4gdMOtY2ggbOG7sWEgY2jhu41uIGJp4bq/biBz4buRIGThu7FhIHRyw6puIHRpw6p1IGNodeG6qW4gSVYgbmjGsCBtw7QgdOG6oyBi4bufaSBCZWxsaW5pICgyMDE5KSB2w6AgQmFlc2VucyBldCBhbC4gKDIwMTMpOiANCg0KDQpgYGB7cn0NCiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojICAgICAgRGV2ZWxvcCBhIHNjb3JlY2FyZCBNb2RlbCBhcyBkZXNjcmliZWQgYnkgQmVsbGluaSBhbmQgQmFlc2VucyBldCBhbC4gDQojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KHNjb3JlY2FyZCkNCg0KIyBHZW5lcmF0ZXMgb3B0aW1hbCBiaW5uaW5nIGZvciBudW1lcmljYWwsIGZhY3RvciBhbmQgY2F0ZWdvcmljYWwgdmFyaWFibGVzOiANCmJpbnNfdmFyIDwtIHdvZWJpbihkZl90cmFpbiwgeSA9ICJCQUQiLCBub19jb3JlcyA9IDgsIHBvc2l0aXZlID0gIkJBRHwxIikNCg0KIyBJViBmb3IgdmFyaWFibGVzOiANCg0KZG8uY2FsbCgicmJpbmQiLCBiaW5zX3ZhcikgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICBmaWx0ZXIoIWR1cGxpY2F0ZWQodmFyaWFibGUpKSAlPiUgDQogIHJlbmFtZShpdl92YXIgPSB0b3RhbF9pdikgJT4lIA0KICBhcnJhbmdlKGl2X3ZhcikgJT4lIA0KICBtdXRhdGUodmFyaWFibGUgPSBmYWN0b3IodmFyaWFibGUsIGxldmVscyA9IHZhcmlhYmxlKSkgLT4gaXZfdmFsdWVzDQoNCnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpDQoNCml2X3ZhbHVlcyAlPiUgDQogIGdncGxvdChhZXModmFyaWFibGUsIGl2X3ZhcikpICsgDQogIGdlb21fY29sKGZpbGwgPSAiIzM3N2ViOCIpICsgDQogIGNvb3JkX2ZsaXAoKSArIA0KICBnZW9tX2NvbChkYXRhID0gaXZfdmFsdWVzICU+JSBmaWx0ZXIoaXZfdmFyIDwgMC4xKSwgYWVzKHZhcmlhYmxlLCBpdl92YXIpLCBmaWxsID0gImdyZXk2MCIpICsgDQogIGdlb21fdGV4dChkYXRhID0gaXZfdmFsdWVzICU+JSBmaWx0ZXIoaXZfdmFyIDwgMC4xKSwgYWVzKGxhYmVsID0gcm91bmQoaXZfdmFyLCAzKSksIA0KICAgICAgICAgICAgaGp1c3QgPSAtMC4xLCBzaXplID0gNSwgY29sb3IgPSAiZ3JleTQwIikgKyANCiAgZ2VvbV90ZXh0KGRhdGEgPSBpdl92YWx1ZXMgJT4lIGZpbHRlcihpdl92YXIgPj0gMC4xKSwgYWVzKGxhYmVsID0gcm91bmQoaXZfdmFyLCAzKSksIA0KICAgICAgICAgICAgaGp1c3QgPSAtLjEsIHNpemUgPSA1LCBjb2xvciA9ICIjMzc3ZWI4IikgKyANCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgMTogSW5mb3JtYXRpb24gVmFsdWUgKElWKSBmb3IgVmFyaWFibGVzIiwgDQogICAgICAgeCA9IE5VTEwsIHkgPSAiSW5mb3JtYXRpb24gVmFsdWUgKElWKSIpICsgDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsIDApLCBsaW1pdHMgPSBjKDAsIDEuOCkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgdGhlbWUocGxvdC5tYXJnaW4gPSB1bml0KGMoMSwgMSwgMSwgMSksICJjbSIpKQ0KDQpgYGANCg0KVGhlbyB0aMO0bmcgbOG7hywgY2jhu4kgY8OzIGPDoWMgYmnhur9uIGPDsyBJViBs4bubbiBoxqFuIDAuMSBt4bubaSDEkcaw4bujYyBz4butIGThu6VuZyAgY2hvIG3DtCBow6xuaC4gVHJvbmcgcG9zdCBuw6B5IHRow6wgdOG6pXQgY+G6oyBjw6FjIGJp4bq/biBz4bq9IMSRxrDhu6NjIHPhu60gZOG7pW5nLiBExrDhu5tpIMSRw6J5IGzDoCBSIENvZGVzIGNobyB0aOG7sWMgaGnhu4duIExvZ2lzdGljIFJlZ3Jlc3Npb24gduG7m2kgYmnhur9uIMSRw6MgdGjhu7FjIGhp4buHbiBXT0UgVHJhbnNmb3JtYXRpb246IA0KDQoNCg0KYGBge3J9DQojIEEgZnVuY3Rpb24gZm9yIGNvbmR1Y3RpbmcgYmlubmluZyBhbmQgV09FIHRyYW5zZm9ybWF0aW9uOiANCg0KbXlfYmlubmluZ0RhdGEgPC0gZnVuY3Rpb24oLi4uKSB7DQogIA0KICBkZl90cmFpbl93b2UgPC0gd29lYmluX3BseShkZl90cmFpbiwgYmluc192YXIpDQogIGRmX3Rlc3Rfd29lIDwtIHdvZWJpbl9wbHkoZGZfdGVzdCwgYmluc192YXIpDQogIA0KICBkZl90cmFpbl93b2UgJT4lIA0KICAgIG11dGF0ZShCQUQgPSBOVUxMKSAlPiUgDQogICAgbXV0YXRlX2FsbChmdW5jdGlvbih4KSB7LTEqeH0pICU+JSANCiAgICBtdXRhdGUoQkFEID0gZGZfdHJhaW5fd29lJEJBRCkgLT4gdHJhaW5fd29lDQogIA0KICBkZl90ZXN0X3dvZSAlPiUgDQogICAgbXV0YXRlKEJBRCA9IE5VTEwpICU+JSANCiAgICBtdXRhdGVfYWxsKGZ1bmN0aW9uKHgpIHstMSp4fSkgJT4lIA0KICAgIG11dGF0ZShCQUQgPSBkZl90ZXN0X3dvZSRCQUQpIC0+IHRlc3Rfd29lDQogIA0KICByZXR1cm4obGlzdChkZl90cmFpbl93b2UgPSB0cmFpbl93b2UsIGRmX3Rlc3Rfd29lID0gdGVzdF93b2UpKQ0KICANCn0NCg0KIyBVc2UgdGhpcyBmdW5jdGlvbjogDQoNCndvZV9mb3JfYm90aCA8LSBteV9iaW5uaW5nRGF0YSgpDQoNCiMgVHJhaW4gYW5kIFRlc3QgRGF0YSB3aXRoIFdPRSB0cmFuc2Zvcm1hdGlvbiB2YXJpYWJsZXM6IA0KZGZfdHJhaW5fd29lIDwtIHdvZV9mb3JfYm90aFtbMV1dDQpkZl90ZXN0X3dvZSA8LSB3b2VfZm9yX2JvdGhbWzJdXQ0KDQojIExvZ2lzdGljIFJlZ3Jlc3Npb24gYW5kIHJlc3VsdHM6IA0KbXlfbG9naXN0aWMgPC0gZ2xtKEJBRCB+IC4sIGZhbWlseSA9IGJpbm9taWFsLCBkYXRhID0gZGZfdHJhaW5fd29lKQ0KDQpteV9sb2dpc3RpYyAlPiUgDQogIHRpZHkoKSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5jdGlvbih4KSB7cm91bmQoeCwgMyl9KSAlPiUgDQogIGthYmxlKGNhcHRpb24gPSAiVGFibGUgMTogQ29lZmZpY2llbnRzIGZyb20gTG9naXN0aWMgTW9kZWxzIEJhc2VkIG9uIFdPRSBUcmFuc2Zvcm1hdGlvbiBWYXJpYWJsZXMiKQ0KICANCmBgYA0KDQoNClNjb3JlY2FyZCBj4bunYSBt4buXaSBt4buZdCBo4buTIHPGoSB4aW4gdmF5IMSRxrDhu6NjIHTDrW5oIHRvw6FuIGThu7FhIHRyw6puIFByb2JhYmlsaXR5IG9mIERlZmF1bHQgKFBEKSDEkcaw4bujYyBk4buxIGLDoW8gdOG7qyBtw7QgaMOsbmguIFRyxrDhu5tjIGjhur90IHZp4bq/dCBow6BtIHTDrW5oIHRvw6FuIFNjb3JlY2FyZCBQb2ludCBk4buxYSB0csOqbiBQRCBuaMawIG3DtCB04bqjIGPhu6dhIEJlbGxpbmkgKDIwMTkpIHbDoCBCYWVzZW5zIGV0IGFsLiAoMjAxMyk6IA0KDQpgYGB7cn0NCg0KIyBVc2UgTG9naXQgTW9kZWwgZm9yIHByZWRpY3RpbmcgUEQgKFByb2JhYmlsaXR5IG9mIERlZmF1bHQpOiANCnBkX2xvZ2l0IDwtIHByZWRpY3QobXlfbG9naXN0aWMsIGRmX3Rlc3Rfd29lLCB0eXBlID0gInJlc3BvbnNlIikNCg0KIyBGdW5jdGlvbiBmb3Igc2NvcmluZyBiYXNlZCBvbiBQRCBwcmVkaWN0ZWQ6IA0KDQpzY2FsZWRfc2NvcmUgPC0gZnVuY3Rpb24ocGRfc2VsZWN0ZWQpIHsNCiAgb2RkcyA8LSAxOQ0KICBteV9vZmZzZXQgPC0gNjAwDQogIHBkbyA8LSA1MA0KICBiIDwtIHBkbyAvIGxvZygyKQ0KICBhIDwtIG15X29mZnNldCAtIGIqbG9nKG9kZHMpDQogIA0KICBzY29yZXMgPC0gYSArIGIqbG9nKCgxIC0gcGRfc2VsZWN0ZWQpIC8gcGRfc2VsZWN0ZWQpDQogIHJldHVybihyb3VuZChzY29yZXMsIDApKQ0KICANCn0NCg0KIyBDb252ZXJ0IHRvIFNjb3JlY2FyZCBwb2ludCBiYXNlZCBvbiBQRDogDQoNClNDT1JFIDwtIHNjYWxlZF9zY29yZShwZF9sb2dpdCkNCmBgYA0KDQpW4bubaSBTY29yZWNhcmQgUG9pbnQgZOG7sWEgdHLDqm4gUEQgZOG7sSBiw6FvIHThu6sgbcO0IGjDrG5oIExvZ2lzdGljIHRow6wgxJFp4buDbSB0cnVuZyBiw6xuaCBjaG8gaGFpIG5ow7NtIGjhu5Mgc8ahIEJhZCB2w6AgR29vZCByw7UgcsOgbmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0LiBT4buxIGtow6FjIGJp4buHdCBuw6B5IG3DoCBjw6BuZyBs4bubbiB0aMOsIMSRw7MgbMOgIGThuqV1IGhp4buHdSBj4bunYSBt4buZdCBtw7QgaMOsbmggcGjDom4gbG/huqFpIHThu5F0OiANCg0KDQpgYGB7cn0NCg0KZGZfc2NvcmVkX3Rlc3QgPC0gZGZfdGVzdCAlPiUgDQogIG11dGF0ZShTQ09SRSA9IFNDT1JFKSAlPiUgDQogIG11dGF0ZShCQUQgPSBjYXNlX3doZW4oQkFEID09IDEgfiAiQmFkIiwgVFJVRSB+ICJHb29kIikpIA0KDQpkZl9zY29yZWRfdGVzdCAlPiUgDQogIGdyb3VwX2J5KEJBRCkgJT4lIA0KICBzdW1tYXJpc2VfZWFjaChmdW5zKG1pbiwgbWF4LCBtZWRpYW4sIG1lYW4sIG4oKSksIFNDT1JFKSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5jdGlvbih4KSB7cm91bmQoeCwgMCl9KSAlPiUgDQogIGtuaXRyOjprYWJsZShjYXB0aW9uID0gIlRhYmxlIDI6IFNjb3JlY2FkIFBvaW50cyBieSBHcm91cCBmb3IgVGVzdCBEYXRhIikNCmBgYA0KDQoNCkNow7puZyB0YSBjw7MgdGjhu4MgaMOsbmgg4bqjbmggaMOzYSBraOG6oyBuxINuZyBwaMOibiBiaeG7h3QgaGFpIG5ow7NtIEJhZCB2w6AgR29vZCBk4buxYSB0csOqbiBTY29yZWNhcmQgUG9pbnQgYuG6sW5nIGPDtG5nIGPhu6UgaMOsbmgg4bqjbmg6IA0KDQpgYGB7cn0NCmRmX3Njb3JlZF90ZXN0ICU+JSANCiAgZ3JvdXBfYnkoQkFEKSAlPiUgDQogIHN1bW1hcmlzZSh0YiA9IG1lYW4oU0NPUkUpKSAlPiUgDQogIHVuZ3JvdXAoKSAtPiBtZWFuX3Njb3JlX3Rlc3QNCg0KDQpkZl9zY29yZWRfdGVzdCAlPiUgDQogIGdncGxvdChhZXMoU0NPUkUsIGNvbG9yID0gQkFELCBmaWxsID0gQkFEKSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4zKSArIA0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbl9zY29yZV90ZXN0JHRiWzFdKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikgKyANCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lYW5fc2NvcmVfdGVzdCR0YlsyXSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsdWUiKSArIA0KICBnZW9tX3RleHQoYWVzKHggPSBtZWFuX3Njb3JlX3Rlc3QkdGJbMV0gLSAyNSwgeSA9IDAuMDAyLCBsYWJlbCA9IG1lYW5fc2NvcmVfdGVzdCR0YlsxXSAlPiUgcm91bmQoMCkpLCBjb2xvciA9ICJyZWQiLCBzaXplID0gNCkgKyANCiAgZ2VvbV90ZXh0KGFlcyh4ID0gbWVhbl9zY29yZV90ZXN0JHRiWzJdICsgMjUsIHkgPSAwLjAwMiwgbGFiZWwgPSBtZWFuX3Njb3JlX3Rlc3QkdGJbMl0gJT4lIHJvdW5kKDApKSwgY29sb3IgPSAiYmx1ZSIsIHNpemUgPSA0KSArIA0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC4yLCAwLjgpKSArIA0KICB0aGVtZShwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYygxLjMsIDEuMywgMS4zLCAxLjMpLCAiY20iKSkgKyANCiAgbGFicyh4ID0gIlNjb3JlY2FyZCBQb2ludCIsIHkgPSBOVUxMLCANCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBodHRwOi8vd3d3LmNyZWRpdHJpc2thbmFseXRpY3MubmV0LyIsIA0KICAgICAgIHRpdGxlID0gIkZpZ3VyZSAyOiBTY29yZWNhcmQgRGlzdHJpYnV0aW9uIGJ5IEdyb3VwLCBMb2dpc3RpYyBNb2RlbCIsIA0KICAgICAgIHN1YnRpdGxlID0gIlRoZSBzY29yZWNhcmQgcG9pbnQgaXMgYSBudW1lcmljIGV4cHJlc3Npb24gbWVhc3VyaW5nIGNyZWRpdHdvcnRoaW5lc3MuIENvbW1lcmNpYWwgQmFua3NcbnVzdWFsbHkgdXRpbGl6ZSBpdCBhcyBhIG1ldGhvZCB0byBzdXBwb3J0IHRoZSBkZWNpc2lvbi1tYWtpbmcgYWJvdXQgY3JlZGl0IGFwcGxpY2F0aW9ucy4iKQ0KDQpgYGANCg0KVGhlbyB0aMO0bmcgbOG7hywgQVVDICh2w6AgYmnhur9uIHRo4buDIGPhu6dhIG7DsyBsw6AgR0lOSSBJbmRleCA9IDIqQVVDIC0gMSkgbMOgIG3hu5l0IHRpw6p1IGNow60gxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgxJHDoW5oIGdpw6EgbcO0IGjDrG5oIHBow6JuIGxv4bqhaS4gRMaw4bubaSDEkcOieSBsw6AgZ2nDoSB0cuG7iyBBVUMgdsOgIFJPQyBjdXJ2ZSBj4bunYSBtw7QgaMOsbmggTG9naXN0aWM6IA0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gZm9yIGNhbGN1YWx0aW5nIEFVQy9ST0M6IA0KDQphdWNfZm9yX3Rlc3QgPC0gZnVuY3Rpb24ocGRfc2VsZWN0ZWQpIHsNCiAgcmV0dXJuKHBST0M6OnJvYyhkZl90ZXN0JEJBRCwgcGRfc2VsZWN0ZWQpKQ0KfQ0KDQoNCiMgRnVuY3Rpb24gZm9yIHByZXNlbnRpbmcgQVVDL1JPQyBjdXJ2ZToNCm15X1JPQ19jdXJ2ZSA8LSBmdW5jdGlvbihhdWNfb2JqZWN0KSB7DQogIA0KICBzZW5fc3BlY19kZiA8LSBkYXRhX2ZyYW1lKFRQUiA9IGF1Y19vYmplY3Qkc2Vuc2l0aXZpdGllcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRlBSID0gMSAtIGF1Y19vYmplY3Qkc3BlY2lmaWNpdGllcykNCiAgDQogIHNlbl9zcGVjX2RmICU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSBGUFIsIHltaW4gPSAwLCB5bWF4ID0gVFBSKSkrDQogICAgZ2VvbV9wb2x5Z29uKGFlcyh5ID0gVFBSKSwgZmlsbCA9ICJyZWQiLCBhbHBoYSA9IDAuMykrDQogICAgZ2VvbV9wYXRoKGFlcyh5ID0gVFBSKSwgY29sID0gImZpcmVicmljayIsIHNpemUgPSAxLjIpICsNCiAgICBnZW9tX2FibGluZShpbnRlcmNlcHQgPSAwLCBzbG9wZSA9IDEsIGNvbG9yID0gImdyYXkzNyIsIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKyANCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArIA0KICAgIHRoZW1lX2J3KCkgKw0KICAgIGNvb3JkX2VxdWFsKCkgJT4lIA0KICAgIHJldHVybigpDQp9DQoNCg0KIyBQbG90IFJPQyBjdXJ2ZSBhbmQgc2hvdyBBVUMgdmFsdWU6IA0KDQpteV9hdWNfbG9naXQgPC0gYXVjX2Zvcl90ZXN0KHBkX2xvZ2l0KQ0KDQpteV9hdWNfbG9naXQgJT4lIA0KICBteV9ST0NfY3VydmUoKSArIA0KICBsYWJzKHggPSAiRlBSICgxIC0gU3BlY2lmaWNpdHkpIiwgDQogICAgICAgeSA9ICJUUFIgKFNlbnNpdGl2aXR5KSIsIA0KICAgICAgIHRpdGxlID0gIkZpZ3VyZSAzOiBNb2RlbCBQZXJmb3JtYW5jZSBCYXNlZCBvbiBUZXN0IERhdGEiLCANCiAgICAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiQVVDIFZhbHVlIGZvciBMb2dpc3RpYyBBcHByb2FjaDogIiwgbXlfYXVjX2xvZ2l0JGF1YyAlPiUgcm91bmQoMykpKQ0KDQoNCmBgYA0KDQpHacOhIHRy4buLIEFVQyB0csOqbiB0ZXN0IGRhdGEgbMOgIDg3LjglICht4buZdCBjb24gc+G7kSBy4bqldCBjYW8pIHbDoCB0aGVvIHF1eSDGsOG7m2MgdGjDrCBnacOhIHRy4buLIG7DoHkgbMOgIGThuqV1IGhp4buHdSBjaG8gdGjhuqV5IHLhurFuZyBjw6FjaCB0aeG6v3AgY+G6rW4gbcOgIGNow7puZyB0YSBz4butIGThu6VuZyAobcO0IGjDrG5oIExvZ2lzdGljIHbhu5tpIGJp4bq/biBXT0UgVHJhbnNmb3JtYXRpb24pIGzDoCB04buRdC4gDQoNCk5oxrBuZyBz4butIGThu6VuZyBSYW5kb20gRm9yZXN0IC0gbeG7mXQgY8OhY2ggdGnhur9wIGPhuq1uIGPhu6dhIE1hY2hpbmUgTGVhcm5pbmcgY8OybiB04buRdCBoxqFuIG7hu69hIC0gdGjhu4MgaGnhu4duIHF1YSBraOG6oyBuxINuZyB4w6FjIMSR4buLbmggKGRldGVjdCkgY8OhYyBo4buTIHPGoSBsw6AgQmFkIHbDoCBj4bqjIEFVQy4gDQoNCiMgTWFjaGluZSBMZWFybmluZyBBcHByb2FjaCB0byBTY29yZWNhcmQgTW9kZWxsaW5nDQoNCg0KVHLGsOG7m2MgaOG6v3QgY2jDum5nIHRhIGh14bqlbiBsdXnhu4duIFJGIHRyw6puIGPDuW5nIG3hu5l0IGLhu5kgZOG7ryBsaeG7h3UgbmjGsCDEkcOjIHPhu60gZOG7pW5nIMSR4buDIHjDonkgZOG7sW5nIG3DtCBow6xuaCBMb2dpc3RpYyDhu58gdHLDqm46IA0KDQpgYGB7cn0NCg0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojICAgTWFjaGluZSBMZWFybmluZyBBcHByb2FjaA0KIz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgQ29udmVydCBCQUQgdG8gZmFjdG9yIGFuZCBzY2FsZSAwIC0xIGRhdGEgc2V0OiANCmRmX2Zvcl9tbCA8LSBkZiAlPiUgDQogIG11dGF0ZShCQUQgPSBjYXNlX3doZW4oQkFEID09IDEgfiAiQmFkIiwgVFJVRSB+ICJHb29kIikgJT4lIGFzLmZhY3RvcigpKSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5jdGlvbih4KSB7KHggLSBtaW4oeCkpIC8gKG1heCh4KSAtIG1pbih4KSl9KQ0KDQojIFByZXBhcmUgZGF0YSBmb3IgUmFuZG9tIEZvcmVzdDogDQoNCmRmX3RyYWluX21sIDwtIGRmX2Zvcl9tbFtpZCwgXQ0KZGZfdGVzdF9tbCA8LSBkZl9mb3JfbWxbLWlkLCBdDQoNCiMgU2V0IGNvbmRpdGlvbnMgZm9yIHRyYWluaW5nIG1vZGVsIGFuZCBjcm9zcy12YWxpZGF0aW9uOiANCg0Kc2V0LnNlZWQoMSkNCm51bWJlciA8LSA1DQpyZXBlYXRzIDwtIDUNCmNvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJyZXBlYXRlZGN2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICBudW1iZXIgPSBudW1iZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgcmVwZWF0cyA9IHJlcGVhdHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgY2xhc3NQcm9icyA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgc2F2ZVByZWRpY3Rpb25zID0gImZpbmFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICBpbmRleCA9IGNyZWF0ZVJlc2FtcGxlKGRmX3RyYWluX21sJEJBRCwgbnVtYmVyKnJlcGVhdHMpLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcnlGdW5jdGlvbiA9IG11bHRpQ2xhc3NTdW1tYXJ5LCANCiAgICAgICAgICAgICAgICAgICAgICAgIGFsbG93UGFyYWxsZWwgPSBUUlVFKQ0KDQojIFVzZSBQYXJhbGxlbCBjb21wdXRpbmcgKEkgdXNlIDggQ1BVIGNvcmVzIGZvciB0cmFpbmluZyBNTCBNb2RlbHMpOiANCmxpYnJhcnkoZG9QYXJhbGxlbCkNCnJlZ2lzdGVyRG9QYXJhbGxlbChjb3JlcyA9IDgpDQoNCiMgUnVuIFJhbmRvbSBGb3Jlc3Q6IA0KDQpzZXQuc2VlZCgxKQ0KDQojIG15X21vZGVscyA8LSBjKCJyZiIsICJhZGFib29zdCIsICJrbm4iLCAic3ZtUmFkaWFsIiwgImdsbSIsICJuYiIpDQpteV9tb2RlbHMgPC0gYygicmFuZ2VyIikNCm1vZGVsX2xpc3QxIDwtIGNhcmV0TGlzdChCQUQgfi4sIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBkZl90cmFpbl9tbCwNCiAgICAgICAgICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBjb250cm9sLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpYyA9ICJBY2N1cmFjeSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZExpc3QgPSBteV9tb2RlbHMpDQoNCg0KIyBFeHRyYWN0IGFsbCByZXN1bHRzOiANCg0KbGlzdF9vZl9yZXN1bHRzIDwtIGxhcHBseShteV9tb2RlbHMsIGZ1bmN0aW9uKHgpIHttb2RlbF9saXN0MVtbeF1dJHJlc2FtcGxlfSkNCg0KIyBDb252ZXJ0IHRvIGRhdGEgZnJhbWU6IA0KdG90YWxfZGYgPC0gZG8uY2FsbCgiYmluZF9yb3dzIiwgbGlzdF9vZl9yZXN1bHRzKQ0KdG90YWxfZGYgJTw+JSBtdXRhdGUoTW9kZWwgPSBsYXBwbHkobXlfbW9kZWxzLCBmdW5jdGlvbih4KSB7cmVwKHgsIG51bWJlcipyZXBlYXRzKX0pICU+JSB1bmxpc3QoKSkNCmBgYA0KDQpE4buxYSB0csOqbiAyNSB0aOG7rSBuZ2hp4buHbSB0aMOsIGdpw6EgdHLhu4sgQVVDIGPhu6dhIG3DtCBow6xuaCBSRiBsw6AgOTUuNCU6IA0KDQpgYGB7cn0NCiMgQWNjdXJhY3kgYmFzZWQgb24gMjUgc2FtcGxlcyBmb3IgdGhlc2UgbW9kZWxzOiANCg0KdG90YWxfZGYgJT4lIA0KICBzZWxlY3QoQVVDLCBNb2RlbCkgJT4lIA0KICBncm91cF9ieShNb2RlbCkgJT4lIA0KICBzdW1tYXJpc2UoYXZnX2F1YyA9IG1lYW4oQVVDKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBhcnJhbmdlKC1hdmdfYXVjKSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5jdGlvbih4KSB7cm91bmQoeCwgMyl9KSAlPiUgDQogIGthYmxlKGNhcHRpb24gPSAiVGFibGUgMzogTW9kZWwgUGVyZm9ybWFuY2UgYnkgQVVDIiwgDQogICAgICAgIGNvbC5uYW1lcyA9IGMoIk1vZGVsIiwgIkF2ZXJhZ2UgQVVDIikpDQoNCmBgYA0KDQpBVUMgY2FvIGjGoW4gbmdoxKlhIGzDoCBQRCBk4buxIGLDoW8gdOG7qyBSRiBsw6AgdOG7kXQgaMahbiBzbyB24bubaSBMb2dpc3RpYy4gxJBp4buBdSBuw6B5IMSRxrDhu6NjIHRo4bqleSBxdWEgc+G7sSBraMOhYyBiaeG7h3QgduG7gSDEkWnhu4NtIGdp4buvYSBoYWkgbmjDs206IA0KDQpgYGB7cn0NCg0KIyBDYWxjdWxhdGUgUEQgcHJlZGljdGVkIGZyb20gUmFuZG9tIEZvcmVzdDogDQoNCnBkX3JmIDwtIHByZWRpY3QobW9kZWxfbGlzdDEkcmFuZ2VyLCBkZl90ZXN0X21sLCB0eXBlID0gInByb2IiKSAlPiUgcHVsbChCYWQpDQoNCiMgQXNzaWduIHNjb3JlIGZvciB0ZXN0IGRhdGEgdXNpbmcgUEQgcHJlZGljdGVkIGZyb20gUmFuZG9tIEZvcmVzdDogDQpTQ09SRSA8LSBzY2FsZWRfc2NvcmUocGRfcmYpDQpTQ09SRSA8LSBjYXNlX3doZW4oaXMuaW5maW5pdGUoU0NPUkUpIH4gbWF4KFNDT1JFWyFpcy5pbmZpbml0ZShTQ09SRSldKSwgVFJVRSB+IFNDT1JFKQ0KDQpkZl9zY29yZWRfdGVzdCA8LSBkZl90ZXN0ICU+JSANCiAgbXV0YXRlKFNDT1JFID0gU0NPUkUpICU+JSANCiAgbXV0YXRlKEJBRCA9IGNhc2Vfd2hlbihCQUQgPT0gMSB+ICJCYWQiLCBUUlVFIH4gIkdvb2QiKSkgDQoNCmRmX3Njb3JlZF90ZXN0ICU+JSANCiAgZ3JvdXBfYnkoQkFEKSAlPiUgDQogIHN1bW1hcmlzZV9lYWNoKGZ1bnMobWluLCBtYXgsIG1lZGlhbiwgbWVhbiwgbigpKSwgU0NPUkUpICU+JSANCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bmN0aW9uKHgpIHtyb3VuZCh4LCAwKX0pICU+JSANCiAga25pdHI6OmthYmxlKGNhcHRpb24gPSAiVGFibGUgNDogU2NvcmVjYWQgUG9pbnRzIGJ5IEdyb3VwIGZvciBUZXN0IERhdGEiKQ0KDQoNCmBgYA0KDQpQaMOibiBwaOG7kWkgduG7gSDEkWnhu4NtIGNobyBoYWkgbmjDs20gaOG7kyBzxqEgY+G7p2EgbcO0IGjDrG5oIFJGOiANCg0KYGBge3J9DQoNCg0KZGZfc2NvcmVkX3Rlc3QgJT4lIA0KICBncm91cF9ieShCQUQpICU+JSANCiAgc3VtbWFyaXNlKHRiID0gbWVhbihTQ09SRSkpICU+JSANCiAgdW5ncm91cCgpIC0+IG1lYW5fc2NvcmVfdGVzdA0KDQoNCmRmX3Njb3JlZF90ZXN0ICU+JSANCiAgZ2dwbG90KGFlcyhTQ09SRSwgY29sb3IgPSBCQUQsIGZpbGwgPSBCQUQpKSArIA0KICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjMpICsgDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSBtZWFuX3Njb3JlX3Rlc3QkdGJbMV0pLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSArIA0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbl9zY29yZV90ZXN0JHRiWzJdKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmx1ZSIpICsgDQogIGdlb21fdGV4dChhZXMoeCA9IG1lYW5fc2NvcmVfdGVzdCR0YlsxXSAtIDI1LCB5ID0gMC4wMDIsIGxhYmVsID0gbWVhbl9zY29yZV90ZXN0JHRiWzFdICU+JSByb3VuZCgwKSksIGNvbG9yID0gInJlZCIsIHNpemUgPSA0KSArIA0KICBnZW9tX3RleHQoYWVzKHggPSBtZWFuX3Njb3JlX3Rlc3QkdGJbMl0gKyAyNSwgeSA9IDAuMDAyLCBsYWJlbCA9IG1lYW5fc2NvcmVfdGVzdCR0YlsyXSAlPiUgcm91bmQoMCkpLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDQpICsgDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYygwLjIsIDAuOCkpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKDEuMywgMS4zLCAxLjMsIDEuMyksICJjbSIpKSArIA0KICBsYWJzKHggPSAiU2NvcmVjYXJkIFBvaW50IiwgeSA9IE5VTEwsIA0KICAgICAgIGNhcHRpb24gPSAiRGF0YSBTb3VyY2U6IGh0dHA6Ly93d3cuY3JlZGl0cmlza2FuYWx5dGljcy5uZXQvIiwgDQogICAgICAgdGl0bGUgPSAiRmlndXJlIDQ6IFNjb3JlY2FyZCBEaXN0cmlidXRpb24gYnkgR3JvdXAsIFJhbmRvbSBGb3Jlc3QgTW9kZWwiLCANCiAgICAgICBzdWJ0aXRsZSA9ICJOb3RlOiBJbmZpbml0aXZlIFNjb3JlcyBBcmUgQ29udmVydGVkIHRvIE1heC4iKQ0KYGBgDQoNCkFVQyBj4bunYSBSRiBjxaluZyBjYW8gaMahbiB2w6AgxJHGsMahbmcgbmhpw6puIGdpw6EgdHLhu4sgbsOgeSwgZMO5IGNoxrBhIHTDrW5oIHRow6wgY2jDum5nIHRhIGPFqW5nIGPDsyB0aOG7gyBrw6wgduG7jW5nIGzDoCBraMO0bmcga2jDoWMgYmnhu4d0IHF1w6Egbmhp4buBdSBzbyB24bubaSBjb24gc+G7kSAwLjk1NCDEkcOjIGJp4bq/dDogDQoNCmBgYHtyfQ0KDQoNCiMgUGxvdCBBVUMgY3VydmUgYW5kIHNob3cgQVVDOiANCg0KbXlfYXVjX3JmIDwtIGF1Y19mb3JfdGVzdChwZF9yZikNCm15X2F1Y19yZiAlPiUgDQogIG15X1JPQ19jdXJ2ZSgpICsgDQogIGxhYnMoeCA9ICJGUFIgKDEgLSBTcGVjaWZpY2l0eSkiLCANCiAgICAgICB5ID0gIlRQUiAoU2Vuc2l0aXZpdHkpIiwgDQogICAgICAgdGl0bGUgPSAiRmlndXJlIDU6IE1vZGVsIFBlcmZvcm1hbmNlIEJhc2VkIG9uIFRlc3QgRGF0YSIsIA0KICAgICAgIHN1YnRpdGxlID0gcGFzdGUwKCJBVUMgVmFsdWUgZm9yIFJhbmRvbSBGb3Jlc3QgQXBwcm9hY2g6ICIsIG15X2F1Y19yZiRhdWMgJT4lIHJvdW5kKDMpKSkNCg0KYGBgDQoNCkPDoWMgbmfDom4gaMOgbmcgbOG7sWEgY2jhu41uIEFVQy9ST0MgxJHhu4MgxJHDoW5oIGdpw6EgdsOgIHNvIHPDoWNoIGto4bqjIG7Eg25nIHBow6JuIGxv4bqhaSBj4bunYSBjw6FjIG3DtCBow6xuaCBj4bqhbmggdHJhbmggbmhhdSAobmjGsCBMb2dpc3RpYyB2w6AgUkYpIG5oxrBuZyDEkeG7k25nIHRo4budaSBjaMO6bmcgY8WpbmcgcXVhbiB0w6JtIMSR4bq/biBt4buZdCBraMOtYSBj4bqhbmggdGjhu7FjIHThur8gc2F1IMSRw7MgbMOgICoqa2jhuqMgbsSDbmcgY292ZXIgLyBkZXRlY3QgY8OhYyBo4buTIHPGoSBsw6AgQmFkIHRyb25nIHThu5VuZyBz4buRLCB2w60gZOG7pSwgNTAwIGjhu5Mgc8ahIMSRxrDhu6NjIHjDqXQqKi4gDQoNCkLhurFuZyBjaOG7qW5nIGLhurFuZyBz4buRIGTGsOG7m2kgxJHDonkgY2jhu4kgcmEgcuG6sW5nIGto4bqjIG7Eg25nIGRldGVjdCBjw6FjIGjhu5Mgc8ahIEJhZCBj4bunYSBSRiBsdcO0biBjYW8gaMahbiBMb2dpc3RpYw0KDQoNCg0KDQpgYGB7cn0NCg0KIyBDb21wYXJpc2lvbiBiYXNlZCBvbiBQRCBwcmVkaWN0ZWQ6IA0KDQpkZl90ZXN0X21sICU+JSANCiAgbXV0YXRlKFBEX2dsbSA9IHBkX2xvZ2l0LCBQRF9yZiA9IHBkX3JmLCANCiAgICAgICAgIFNjb3JlX2dsbSA9IHNjYWxlZF9zY29yZShwZF9sb2dpdCksIA0KICAgICAgICAgU2NvcmVfcmYgPSBzY2FsZWRfc2NvcmUocGRfcmYpKSAtPiBkZl9yZXN1bHRzDQoNCiMgRnVuY3Rpb24gZm9yIHJhbmtpbmcgYnkgUEQ6IA0KDQpjb3ZlckJhZF9ieVBEIDwtIGZ1bmN0aW9uKG5fY2FzZXMpIHsNCiAgDQogIGRmX2NvdmVyX2dsbSA8LSBkZl9yZXN1bHRzICU+JSANCiAgICBhcnJhbmdlKC1QRF9nbG0pICU+JSANCiAgICBzbGljZSgxOm5fY2FzZXMpICU+JSANCiAgICBncm91cF9ieShCQUQpICU+JSANCiAgICBjb3VudCgpICU+JSANCiAgICB1bmdyb3VwKCkgJT4lIA0KICAgIG11dGF0ZShNb2RlbCA9ICJHTE0iKQ0KICANCiAgZGZfY292ZXJfcmYgPC0gZGZfcmVzdWx0cyAlPiUgDQogICAgYXJyYW5nZSgtUERfcmYpICU+JSANCiAgICBzbGljZSgxOm5fY2FzZXMpICU+JSANCiAgICBncm91cF9ieShCQUQpICU+JSANCiAgICBjb3VudCgpICU+JSANCiAgICB1bmdyb3VwKCkgJT4lIA0KICAgIG11dGF0ZShNb2RlbCA9ICJSRiIpDQoNCiAgcmV0dXJuKGJpbmRfcm93cyhkZl9jb3Zlcl9nbG0sIGRmX2NvdmVyX3JmKSAlPiUgbXV0YXRlKE4gPSBuX2Nhc2VzKSkNCiAgDQp9DQoNCiMgRnVuY3Rpb24gZm9yIHJhbmtpbmcgYnkgc2NvcmVjYXJkIHNjb3JlOiANCmNvdmVyQmFkX2J5U2NvcmUgPC0gZnVuY3Rpb24obl9jYXNlcykgew0KICANCiAgZGZfY292ZXJfZ2xtIDwtIGRmX3Jlc3VsdHMgJT4lIA0KICAgIGFycmFuZ2UoU2NvcmVfZ2xtKSAlPiUgDQogICAgc2xpY2UoMTpuX2Nhc2VzKSAlPiUgDQogICAgZ3JvdXBfYnkoQkFEKSAlPiUgDQogICAgY291bnQoKSAlPiUgDQogICAgdW5ncm91cCgpICU+JSANCiAgICBtdXRhdGUoTW9kZWwgPSAiR0xNIikNCiAgDQogIGRmX2NvdmVyX3JmIDwtIGRmX3Jlc3VsdHMgJT4lIA0KICAgIGFycmFuZ2UoU2NvcmVfcmYpICU+JSANCiAgICBzbGljZSgxOm5fY2FzZXMpICU+JSANCiAgICBncm91cF9ieShCQUQpICU+JSANCiAgICBjb3VudCgpICU+JSANCiAgICB1bmdyb3VwKCkgJT4lIA0KICAgIG11dGF0ZShNb2RlbCA9ICJSRiIpDQoNCiAgcmV0dXJuKGJpbmRfcm93cyhkZl9jb3Zlcl9nbG0sIGRmX2NvdmVyX3JmKSAlPiUgbXV0YXRlKE4gPSBuX2Nhc2VzKSkNCiAgDQp9DQoNCg0KIyBVc2UgdGhlIGZ1bmN0aW9uczogICANCg0KZGZfY292ZXJfc29jcmUgPC0gZG8uY2FsbCgiYmluZF9yb3dzIiwgbGFwcGx5KHNlcSgyMDAsIDEwMDAsIDEwMCksIGNvdmVyQmFkX2J5U2NvcmUpKQ0KZGZfY292ZXJfcGQgPC0gZG8uY2FsbCgiYmluZF9yb3dzIiwgbGFwcGx5KHNlcSgyMDAsIDEwMDAsIDEwMCksIGNvdmVyQmFkX2J5UEQpKQ0KDQojIGh0dHA6Ly9icmFkbGV5Ym9laG1rZS5naXRodWIuaW8vdHV0b3JpYWxzL2JhcmNoYXJ0DQoNCmRmX2NvdmVyX3NvY3JlICU+JSANCiAgZmlsdGVyKEJBRCA9PSAiQmFkIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBOLCB5ID0gbiwgZmlsbCA9IE1vZGVsKSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDAsIDEwMDAsIDEwMCkpICsgDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgNjAwLCAxMDApKSArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC45KSwgdmp1c3QgPSAxLjIpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSArIA0KICBsYWJzKHggPSAiTnVtYmVyIG9mIENhc2VzIENsYXNzaWZpZWQiLCB5ID0gIk51bWJlciBvZiBCYWQgQ2FzZXMiLCANCiAgICAgICBjYXB0aW9uID0gIkRhdGEgU291cmNlOiBodHRwOi8vd3d3LmNyZWRpdHJpc2thbmFseXRpY3MubmV0LyIsIA0KICAgICAgIHRpdGxlID0gIkZpZ3VyZSA1OiBBYmlsaXR5IHRvIERpc3Rpbmd1aXNoIEJhZCBDYXNlcyBieSB0aGUgdHdvIE1vZGVscyIpDQoNCmBgYA0KDQpWw60gZOG7pSwgdHJvbmcgMjAwIGjhu5Mgc8ahIGPDsyDEkWnhu4NtIFNjb3JlY2FyZCB0aOG6pXAgbmjhuqV0IHRow6wgbuG6v3Ugc+G7rSBk4bulbmcgUkYgbmfDom4gaMOgbmcgc+G6vSB4w6FjIMSR4buLbmggxJHGsOG7o2MgMTk4IGNhc2VzIGzDoCBCYWQgdHJvbmcga2hpIGNvbiBz4buRIG7DoHkgbMOgIDE3NiBu4bq/dSBz4butIGThu6VuZyBTY29yZWNhcmQgdGh1IMSRxrDhu6NjIHThu6sgbcO0IGjDrG5oIExvZ2lzdGljLiANCg0KTmdoxKlhIGzDoCB04buJIGzhu4cgeMOhYyDEkeG7i25oIGPDoWMgaOG7kyBzxqEgQmFkIGPhu6dhIFJGIGx1w7RuIGNhbyBoxqFuIExvZ2lzdGljOiANCg0KDQpgYGB7cn0NCg0KbXlfY29sb3JzIDwtIGMoIiNlNDFhMWMiLCAiIzM3N2ViOCIpDQoNCmRmX2NvdmVyX3NvY3JlICU+JSANCiAgZmlsdGVyKEJBRCA9PSAiQmFkIikgJT4lIA0KICBtdXRhdGUoY292ZXJfcmF0ZSA9IG4gLyBzdW0oZGZfcmVzdWx0cyRCQUQgPT0gIkJhZCIpKSAlPiUgDQogIGdncGxvdChhZXMoTiwgY292ZXJfcmF0ZSwgY29sb3IgPSBNb2RlbCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsgDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBteV9jb2xvcnMpICsgDQogIHRoZW1lKHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsgDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMjAwLCAxMDAwLCAxMDApKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCBicmVha3MgPSBzZXEoMC4yLCAxLCAwLjEpKSArIA0KICBsYWJzKHggPSAiTnVtYmVyIG9mIENhc2VzIENsYXNzaWZpZWQiLCB5ID0gIkJhZCBSYXRlIiwgDQogICAgICAgY2FwdGlvbiA9ICJEYXRhIFNvdXJjZTogaHR0cDovL3d3dy5jcmVkaXRyaXNrYW5hbHl0aWNzLm5ldC8iLCANCiAgICAgICB0aXRsZSA9ICJGaWd1cmUgNjogQWJpbGl0eSB0byBEZXRlY3QgQmFkIENhc2VzIGJ5IFRoZSBUd28gTW9kZWxzIikNCg0KYGBgDQoNCkZpZ3VyZSA1IGNo4buJIHJhIHLhurFuZyBu4bq/dSBuZ8OibiBow6BuZyB4w6l0IDUwMCBjYXNlcyBk4buxYSB0csOqbiDEkWnhu4NtIFNjb3JlY2FyZCB04burIGhhaSBtw7QgaMOsbmggdGjDrCBSRiBz4bq9IHjDoWMgxJHhu4tuaCBoxqFuIDcwJSBsw6AgQmFkIHRyb25nIGtoaSBMb2dpc3RpYyBjaOG7iSB4w6FjIMSR4buLbmggxJHGsOG7o2MgZ+G6p24gNjAlLiANCg0KDQrEkMawxqFuZyBuaGnDqm4gbuG6v3UgY2jDum5nIHRhIGPEg24gY+G7qSB2w6BvIFBEIHRow6wga+G6v3QgcXXhuqMgY8Wpbmcga2jDtG5nIGtow6FjIGJp4buHdC4gVsOsIFNjb3JlY2FyZCBjaOG7iSBsw6AgY8OhY2ggZGnhu4VuIGdp4bqjaSBraMOhYyAobMOgIG3hu5l0IGJp4bq/biB0aOG7gykgY+G7p2EgUEQgbmjGsCBjaMO6bmcgdGEgY8OzIHRo4buDIHRo4bqleSBxdWEgY8O0bmcgdGjhu6ljIGNodXnhu4NuIGjDs2EgxJFp4buDbSBTY29yZWNhcmQgdOG7qyBQRC4gDQoNCk7hur91IG114buRbiBraeG7g20gdHJhIGNow7puZyB0YSBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgY29kZXMgc2F1OiANCg0KYGBge3IsIGV2YWw9RkFMU0V9DQoNCmRmX2NvdmVyX3BkICU+JSANCiAgZmlsdGVyKEJBRCA9PSAiQmFkIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBOLCB5ID0gbiwgZmlsbCA9IE1vZGVsKSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDAsIDEwMDAsIDEwMCkpICsgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLCB2anVzdCA9IDEuMikgDQoNCmBgYA0KDQoNCiMgRmluYWwgQ29uY2x1c2lvbnMNCg0KQuG6sW5nIGNo4bupbmcgdGjhu7FjIG5naGnhu4dtIGThu7FhIHRyw6puIGLhu5kgc+G7kSBsaeG7h3UgaG1lcS5jc3YgxJHDoyBjaOG7iSByYSBy4bqxbmcgKipTY29yZWNhcmQgUG9pbnQgZOG7sWEgdHLDqm4gUEQgxJHGsOG7o2MgZOG7sSBiw6FvIHThu6sgUmFuZG9tIEZvcmVzdCBsw6AgaGnhu4d1IHF14bqjIGjGoW4gc28gduG7m2kgTG9naXN0aWMgUmVncmFzc2lvbiDhu58gY+G6oyBoYWkgdGnDqnUgY2h14bqpbjogKDEpIHRpw6p1IGNodeG6qW4gdGjhu5FuZyBrw6ogQVVDL1JPQywgdsOgICgyKSBraOG6oyBuxINuZyBjb3ZlciAocGjDom4gbG/huqFpKSBo4buTIHPGoSBCYWQuKioNCg0KTeG7mXQgc+G7kSB24bqlbiDEkeG7gSBraMOhYyBraGkgeMOieSBk4buxbmcgU2NvcmVjYXJkIE1vZGVsbGluZyAvIENyZWRpdCBTY29yaW5nIGNoxrBhIMSRxrDhu6NjIHRo4bqjbyBsdeG6rW4gdsOgIGzDoG0gcsO1IHRyb25nIHBvc3QgbsOgeSBsw6A6IA0KDQoxLiAqKkFjY3VyYWN5IGNo4buJIGzDoCDEkWnhu4F1IGtp4buHbiBj4bqnbiBjaOG7qSBraMO0bmcgcGjhuqNpIGzDoCB0acOqdSBjaHXhuqluIMSR4buDIGPEg24gY+G7qSBjaG8gdmnhu4djIGzhu7FhIGNo4buNbiBtw7QgaMOsbmgqKi4gQ2hpIHRp4bq/dCB4ZW0gdGjDqm0gW+G7nyDEkcOieV0oaHR0cDovL3JwdWJzLmNvbS9jaGlkdW5na3QvMjk3ODI1KS4gDQoNCjIuIE7hur91IGPDsyB0aMOqbSB0aMO0bmcgdGluIChuaMawIG3hu5dpIGjhu5Mgc8ahIGR1eeG7h3QgdmF5IMSRxrDhu6NjIHZheSBiYW8gbmhpw6p1IHbDoCB24bubaSBsw6NpIHN14bqldCBiYW8gbmhpw6p1KSB0aMOsICoqYmFuayBz4bq9IGzhu7FhIGNo4buNbiB2w6AgxJHDoW5oIGdpw6EgdMOhYyDEkeG7mW5nIGPhu6dhIG3DtCBow6xuaCBjxINuIGPhu6kgdsOgbyB0acOqdSBjaHXhuqluIGzhu6NpIG5odeG6rW4uKiogQ2hpIHRp4bq/dCB4ZW0gdGjDqm0gW+G7nyDEkcOieV0oaHR0cDovL3JwdWJzLmNvbS9jaGlkdW5na3QvNDg3OTEyKS4gDQoNCjMuICoqQ8OhYyB0acOqdSBjaHXhuqluIGThu7FhIHRyw6puIHRo4buRbmcga8OqIG5oxrAgQVVDIChoYXkgQWNjdXJhY3kpIGNo4buJIGzDoCBt4buZdCB0cm9uZyBz4buRIGPDoWMgdGnDqnUgY2jDrSB0aMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcga2hpIMSRw6FuaCBnacOhIHbDoCBs4buxYSBjaOG7jW4gY8OhYyBtw7QgaMOsbmggY+G6oW5oIHRyYW5oIGtow6FjIG5oYXUuKiouIENoaSB0aeG6v3QgeGVtIHRow6ptIFvhu58gxJHDonldKGh0dHA6Ly9ycHVicy5jb20vY2hpZHVuZ2t0LzQ0Nzk4OSkuIA0KDQo0LiBM4buxYSBjaOG7jW4gYmnhur9uIGPEg24gY+G7qSB2w6BvIFdPRSAvIElWIMSRxrDhu6NjIHRyw6xuaCBiw6B5IHbDoCBnaeG6o2kgdGjDrWNoIGNoaSB0aeG6v3QgW+G7nyDEkcOieV0oaHR0cDovL3JwdWJzLmNvbS9jaGlkdW5na3QvNDgyMTYzKSwgIFvhu58gxJHDonldKGh0dHA6Ly9ycHVicy5jb20vY2hpZHVuZ2t0LzQ3ODY2OSkgdsOgIFvhu58gxJHDonldKGh0dHA6Ly9ycHVicy5jb20vY2hpZHVuZ2t0LzQ5NjA2OCkuIA0KDQo1LiBUaGVvIHRow7RuZyBs4buHLCBjw6FjIGjhu5Mgc8ahIHhpbiB2YXkgxJHGsOG7o2MgZMOhbiBjw6FjIG5ow6NuIHhhbmggLSDEkeG7jyAtIHbDoG5nIHbhu5tpIGjDoG0gw70gY8OhYyBo4buTIHPGoSBuaMOjbiB4YW5oIChuaMOzbSDEkWnhu4NtIGNhbykgbMOgIHThu5F0LCDDrXQgcuG7p2kgcm8gbmjhuqV0IGPDsm4gbmjDo24gxJHhu48gKG5ow7NtIMSRaeG7g20gdGjhuqVwKSBsw6AgcuG7p2kgcm8gbmjhuqV0IGPDsm4gdsOgbmcgbMOgIG5ow7NtIHRydW5nIGdpYW4gY2h1ecOqbiB0aeG6v3AuIFZp4buHYyBkw6FuIG5ow6NuIHhhbmggLSDEkeG7jyAtIHbDoG5nIGThu7FhIHRyw6puIFNjb3JlY2FyZCBQb2ludCBz4bq9IHBo4bulIHRodeG7mWMgdsOgbyBuaGnhu4F1IHnhur91IHThu5EgYmFvIGfhu5NtIGPhuqMgxJHhu4tuaCBoxrDhu5tuZyB2w6AgbeG7qWMgxJHhu5kgxrBhIHRow61jaCBy4bunaSBybyBj4bunYSB04buVIGNo4bupYyBz4butIGThu6VuZyBtw7QgaMOsbmguDQoNCg0KIyBSZWZlcmVuY2VzDQoNCg0KMS4gTWFydGVucywgRC4sIEIuIEJhZXNlbnMsIFQuIFZhbiBHZXN0ZWwsIGFuZCBKLiBWYW50aGllbmVuLiAyMDA3LiDigJxDb21wcmVoZW5zaWJsZSBDcmVkaXQgU2NvcmluZyBNb2RlbHMgVXNpbmcgUnVsZSBFeHRyYWN0aW9uIGZyb20gU3VwcG9ydCBWZWN0b3IgTWFjaGluZXMu4oCdIEV1cm9wZWFuIEpvdXJuYWwgb2YgT3BlcmF0aW9uYWwgUmVzZWFyY2ggMTgzOjE0NjbigJMxNDc2Lg0KDQoyLiBCYWVzZW5zLCBCLiwgUm9lc2NoLCBELiwgJiBTY2hldWxlLCBILiAoMjAxNikuIENyZWRpdCByaXNrIGFuYWx5dGljczogTWVhc3VyZW1lbnQgdGVjaG5pcXVlcywgYXBwbGljYXRpb25zLCBhbmQgZXhhbXBsZXMgaW4gU0FTLiBKb2huIFdpbGV5ICYgU29ucy4NCg0KMy4gQmVsbGluaSwgVC4gKDIwMTkpLiBJRlJTIDkgYW5kIENFQ0wgQ3JlZGl0IFJpc2sgTW9kZWxsaW5nIGFuZCBWYWxpZGF0aW9uOiBBIFByYWN0aWNhbCBHdWlkZSB3aXRoIEV4YW1wbGVzIFdvcmtlZCBpbiBSIGFuZCBTQVMuIEFjYWRlbWljIFByZXNzLg0KDQo0LiBTaWRkaXFpLCBOLiAoMjAxMikuIENyZWRpdCByaXNrIHNjb3JlY2FyZHM6IGRldmVsb3BpbmcgYW5kIGltcGxlbWVudGluZyBpbnRlbGxpZ2VudCBjcmVkaXQgc2NvcmluZy4gSm9obiBXaWxleSAmIFNvbnMuDQoNCjUuIEFuZGVyc29uIFIgKDIwMDcpOiBUaGUgQ3JlZGl0IFNjb3JpbmcgVG9vbGtpdDogVGhlb3J5IGFuZCBQcmFjdGljZSBmb3IgUmV0YWlsIENyZWRpdCBSaXNrIE1hbmFnZW1lbnQgYW5kIERlY2lzaW9uIEF1dG9tYXRpb24uIE94Zm9yZCwgT3hmb3JkIFVuaXZlcnNpdHkgUHJlc3MuDQoNCjYuIEhhbmQgREosIEhlbmxleSBXRSAoMTk5Nyk6IFN0YXRpc3RpY2FsIENsYXNzaWZpY2F0aW9uIE1ldGhvZHMgaW4gQ29uc3VtZXIgQ3JlZGl0IFNjb3Jpbmc6IGEgcmV2aWV3LiBKb3VybmFsLiBvZiB0aGUgUm95YWwgU3RhdGlzdGljYWwgU29jaWV0eSwgU2VyaWVzIEEsIDE2MCgzKTo1MjPigJM1NDEuDQoNCjcuIFRob21hcyBMQyAoMjAwMCk6IEEgc3VydmV5IG9mIGNyZWRpdCBhbmQgYmVoYXZpb3VyYWwgc2NvcmluZzogZm9yZWNhc3RpbmcgZmluYW5jaWFsIHJpc2sgb2YgbGVuZGluZyB0byBjb25zdW1lcnMuIEludGVybmF0aW9uYWwgSm91cm5hbCBvZiBGb3JlY2FzdGluZywgMTYoMik6MTQ54oCTMTcyIC4NCg0KOC4gVGhvbWFzIExDICgyMDA5KTogQ29uc3VtZXIgQ3JlZGl0IE1vZGVsczogUHJpY2luZywgUHJvZml0LCBhbmQgUG9ydGZvbGlvLiBPeGZvcmQsIE94Zm9yZCBVbml2ZXJzaXR5IFByZXNzLg0KDQo5LiBDcm9vayBKTiwgRWRlbG1hbiBEQiwgVGhvbWFzIExDICgyMDA3KTogUmVjZW50IGRldmVsb3BtZW50cyBpbiBjb25zdW1lciBjcmVkaXQgcmlzayBhc3Nlc3NtZW50LiBFdXJvcGVhbiBKb3VybmFsIG9mIE9wZXJhdGlvbmFsIFJlc2VhcmNoLCAxODMoMyk6MTQ0N+KAkzE0NjUuDQoNCjEwLiBWYW4gR2VzdGVsLCBULiwgQi4gQmFlc2VucywgUC4gVmFuIERpamNrZSwgSi4gU3V5a2VucywgSi4gR2FyY2lhLCBhbmQgVC4gQWxkZXJ3ZWlyZWxkLiAyMDA1LiDigJxMaW5lYXIgYW5kIE5vbmxpbmVhciBDcmVkaXQgU2NvcmluZyBieSBDb21iaW5pbmcgTG9naXN0aWMgUmVncmVzc2lvbiBhbmQgU3VwcG9ydCBWZWN0b3IgTWFjaGluZXMu4oCdIEpvdXJuYWwgb2YgQ3JlZGl0IFJpc2sgMSwgbm8uIDQuDQoNCjExLiBCZW4tRGF2aWQsIEEuLCAmIEZyYW5rLCBFLiAoMjAwOSkuIEFjY3VyYWN5IG9mIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWxzIHZlcnN1cyDigJxoYW5kIGNyYWZ0ZWTigJ0gZXhwZXJ0IHN5c3RlbXPigJNhIGNyZWRpdCBzY29yaW5nIGNhc2Ugc3R1ZHkuIEV4cGVydCBTeXN0ZW1zIHdpdGggQXBwbGljYXRpb25zLCAzNigzKSwgNTI2NC01MjcxLg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K