click <code> icon on the right corner to view the source code

1 Background

Back to Home

1.1 company

Lending Club is a peer to peer lending company based in the United States, in which investors provide funds for potential borrowers and investors earn a profit depending on the risk they take (the borrowers credit score). Lending Club provides the “bridge” between investors and borrowers. For more basic information about the company please check out the wikipedia article about the company.

1.2 task

SIB(Small Industries Bank) loans money to companies in exchange for the promise of repayment. Some will default on the loans, being unable to repay them for some reason. The bank maintains insurance to reduce their risk of loss in the event of default. The insured amount may cover all or just some part of the loan amount. SIB wants to predict which companies will default on their loans based on their financial information. They have provided you with a dataset that consists of loan related information such as loan amount, term, and state. Also, there is company information such as the number of employees, operating sector, etc.

Using machine learning, predict which companies will default on their loans and explain how different features impact the predictions.

3 Data preparations

Back to Home

3.1 data loading

there are two datasets:

  • train.csv
  • test.csv

In train.csv:

  • there are 2402 records (companys) in total
  • they are from 16 distinct industries
  • they are from 50 different states
  • the duration of data provided is 1 year, request date is from 2009-10-01 to 2010-09-30
  • average term is ~ 87
  • average employee count is ~ 9
  • majority (70%) of companies are new business
  • majority (94.5%) of companies are from type - 0
  • 27.5% of the companies are having other loans
  • average default rate is 32.2%
  • train set is pretty complete, only 1 missing record from industry

the first 6 rows of train.csv look like this:

raw data
industry state request_date term employee_count business_new business_type location other_loans loan_amount insured_amount default_status
Others VA 27-Apr-10 34 4 New 0 Rural N $35,000.00 $35,000.00 1
Manufacturing CA 05-Nov-09 107 1 New 0 Rural N $15,000.00 $13,500.00 1
Trading CA 26-Feb-10 84 1 New 0 Rural Y $265,000.00 $100,000.00 0
Engineering MI 10-Jun-10 240 21 New 0 Rural N $255,000.00 $255,000.00 0
Education NH 23-Sep-10 36 1 Existing 0 Rural N $13,300.00 $6,650.00 0
Administration VA 24-Dec-09 60 42 New 0 Rural Y $40,000.00 $20,000.00 0

3.2 data cleansing

The given data is Some column type conversion was done to clean the data:

  • convert the date column to Date type: “30-Dec-09” => “2019-12-30”
  • convert currency column to numeric: “$35,000.00” => “35000.00”

cleaned data
industry state request_date term employee_count business_new business_type location other_loans loan_amount insured_amount default_status
Others VA 2010-04-27 34 4 New 0 Rural N 35000 35000 1
Manufacturing CA 2009-11-05 107 1 New 0 Rural N 15000 13500 1
Trading CA 2010-02-26 84 1 New 0 Rural Y 265000 100000 0
Engineering MI 2010-06-10 240 21 New 0 Rural N 255000 255000 0
Education NH 2010-09-23 36 1 Existing 0 Rural N 13300 6650 0
Administration VA 2009-12-24 60 42 New 0 Rural Y 40000 20000 0

3.3 data summary

summary of train.csv

  • # of rows: 2402
  • # of columns: 14
No Variable Stats / Values Freqs (% of Valid) Graph Valid Missing
1 industry
[character]
1. Trading
2. Construction
3. Consulting
4. Hotel
5. Manufacturing
6. Healthcare
7. Others
8. Administration
9. Transportation
10. Agriculture
[ 7 others ]
508 (21.1%)
275 (11.4%)
267 (11.1%)
245 (10.2%)
245 (10.2%)
219 ( 9.1%)
168 ( 7.0%)
125 ( 5.2%)
106 ( 4.4%)
58 ( 2.4%)
186 ( 7.7%)
IIII
II
II
II
II
I
I
I


I
2402
(100%)
0
(0%)
2 state
[character]
1. CA
2. TX
3. NY
4. OH
5. FL
6. MN
7. WI
8. IL
9. UT
10. MA
[ 40 others ]
293 (12.2%)
191 ( 8.0%)
133 ( 5.5%)
102 ( 4.2%)
95 ( 4.0%)
91 ( 3.8%)
80 ( 3.3%)
79 ( 3.3%)
77 ( 3.2%)
74 ( 3.1%)
1187 (49.4%)
II
I
I







IIIIIIIII
2402
(100%)
0
(0%)
3 request_date
[Date]
min : 2009-10-01
med : 2010-03-11
max : 2010-09-30
range : 11m 29d
271 distinct values
:
: : . : : : .
: : : : : : : . : :
: : : : : : : : : :
: : : : : : : : : :
2402
(100%)
0
(0%)
4 term
[integer]
Mean (sd) : 87.6 (62.7)
min < med < max:
1 < 84 < 312
IQR (CV) : 43 (0.7)
155 distinct values
    :
  : :
  : :
. : : :
: : : :       .   .
2402
(100%)
0
(0%)
5 employee_count
[integer]
Mean (sd) : 9.3 (21.2)
min < med < max:
0 < 4 < 500
IQR (CV) : 7 (2.3)
88 distinct values
:
:
:
:
:
2402
(100%)
0
(0%)
6 business_new
[character]
1. Existing
2. New
715 (29.8%)
1687 (70.2%)
IIIII
IIIIIIIIIIIIII
2402
(100%)
0
(0%)
7 business_type
[integer]
Min : 0
Mean : 0.1
Max : 1
0 : 2270 (94.5%)
1 : 132 ( 5.5%)
IIIIIIIIIIIIIIIIII
I
2402
(100%)
0
(0%)
8 location
[character]
1. Rural 2402 (100.0%) IIIIIIIIIIIIIIIIIIII 2402
(100%)
0
(0%)
9 other_loans
[character]
1. N
2. Y
1741 (72.5%)
661 (27.5%)
IIIIIIIIIIIIII
IIIII
2402
(100%)
0
(0%)
10 loan_amount
[numeric]
Mean (sd) : 204487.7 (364335.6)
min < med < max:
100 < 50000 < 4e+06
IQR (CV) : 191492.5 (1.8)
1031 distinct values
:
:
:
:
: .
2402
(100%)
0
(0%)
11 insured_amount
[numeric]
Mean (sd) : 155016.7 (311422.7)
min < med < max:
1700 < 35000 < 4e+06
IQR (CV) : 112250 (2)
735 distinct values
:
:
:
:
: .
2402
(100%)
0
(0%)
12 default_status
[integer]
Min : 0
Mean : 0.3
Max : 1
0 : 1629 (67.8%)
1 : 773 (32.2%)
IIIIIIIIIIIII
IIIIII
2402
(100%)
0
(0%)

4 Descriptive analysis

Back to Home

4.3 default rate

5 Predictive modelling

Back to Home

5.1 Preparations

5.1.2 Launch H2O and set up

 Connection successful!

R is connected to the H2O cluster: 
    H2O cluster uptime:         2 minutes 47 seconds 
    H2O cluster timezone:       Asia/Shanghai 
    H2O data parsing timezone:  UTC 
    H2O cluster version:        3.26.0.2 
    H2O cluster version age:    7 months and 10 days !!! 
    H2O cluster name:           H2O_started_from_R_xuelin_tms177 
    H2O cluster total nodes:    1 
    H2O cluster total memory:   1.77 GB 
    H2O cluster total cores:    4 
    H2O cluster allowed cores:  4 
    H2O cluster healthy:        TRUE 
    H2O Connection ip:          localhost 
    H2O Connection port:        54321 
    H2O Connection proxy:       NA 
    H2O Internal Security:      FALSE 
    H2O API Extensions:         Amazon S3, XGBoost, Algos, AutoML, Core V3, Core V4 
    R Version:                  R version 3.6.1 (2019-07-05) 

5.2 Baseline: Logisitc Regression

5.2.2 variable importance

Logistic Regression Variable Importance
variable relative_importance scaled_importance percentage
state.AZ 0.9324776 1.0000000 0.0400847
term 0.8169718 0.8761302 0.0351194
state.GA 0.7939451 0.8514361 0.0341296
loan_amount 0.7502973 0.8046277 0.0322533
industry.Agriculture 0.7413452 0.7950274 0.0318684
employee_count 0.7084459 0.7597458 0.0304542
industry.Hotel 0.6575193 0.7051314 0.0282650
state.MA 0.5651523 0.6060760 0.0242944
state.FL 0.5474091 0.5870480 0.0235316
state.NH 0.5375559 0.5764813 0.0231081

5.3 Xgboost model

5.3.2 variable importance

Xgboost Variable Importance
variable relative_importance scaled_importance percentage
term 7935.17871 1.0000000 0.5450172
loan_amount 2975.59180 0.3749874 0.2043746
insured_amount 1447.49463 0.1824149 0.0994192
employee_count 602.33594 0.0759070 0.0413706
other_loans.N 275.76093 0.0347517 0.0189403
industry.Trading 109.14555 0.0137546 0.0074965
business_new.Existing 91.52952 0.0115347 0.0062866
industry.Hotel 87.39921 0.0110141 0.0060029
state.GA 75.84157 0.0095576 0.0052091
request_ym.2010-01 56.33741 0.0070997 0.0038695

5.4 Model selection

Xgboost model is much better than Logistic Regression in terms of AUC. The ranking of top variables in the variable importance for both methods are generally aligned. Term, loan amount and insured amount are the most important variables in predicting the default status for a loan. Therefore, xgboost model is used for prediction.

5.4.1 make prediction

Let’s view the sample of predictions from xgboost model.

caveat: a threshold of 0.5 was assumed to output the prediction class

xgboost model prediction
id p0 p1 predict
0 0.46 0.54 default
0 1.00 0.00 repaid
0 0.99 0.01 repaid
0 0.72 0.28 repaid
0 1.00 0.00 repaid
0 0.02 0.98 default
0 0.93 0.07 repaid
0 1.00 0.00 repaid
0 0.01 0.99 default
0 1.00 0.00 repaid
LS0tCnRpdGxlOiAiTG9hbiBEZWZhdWx0IHByZWRpY3Rpb24gZm9yIExlbmRpbmcgQ2x1YiIKYXV0aG9yOiBieSBYdWVsaW4gPHh1ZWxpbi1hbXlAZ21haWwuY29tPgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCi0tLQoKX2NsaWNrIGA8Y29kZT4gaWNvbmAgb24gdGhlIHJpZ2h0IGNvcm5lciB0byB2aWV3IHRoZSBzb3VyY2UgY29kZV8KCiMgQmFja2dyb3VuZAoKPHAgYWxpZ249InJpZ2h0Ij4KX19bQmFjayB0byBIb21lXShodHRwczovL3h1ZWxpbi1hbXkuZ2l0aHViLmlvL3BsYXlncm91bmQvZmVhdHVyZWQvKV9fPC9wPgoKIyMgY29tcGFueQoKTGVuZGluZyBDbHViIGlzIGEgcGVlciB0byBwZWVyIGxlbmRpbmcgY29tcGFueSBiYXNlZCBpbiB0aGUgVW5pdGVkIFN0YXRlcywgaW4gd2hpY2ggaW52ZXN0b3JzIHByb3ZpZGUgZnVuZHMgZm9yIHBvdGVudGlhbCBib3Jyb3dlcnMgYW5kIGludmVzdG9ycyBlYXJuIGEgcHJvZml0IGRlcGVuZGluZyBvbiB0aGUgcmlzayB0aGV5IHRha2UgKHRoZSBib3Jyb3dlcnMgY3JlZGl0IHNjb3JlKS4gTGVuZGluZyBDbHViIHByb3ZpZGVzIHRoZSAiYnJpZGdlIiBiZXR3ZWVuIGludmVzdG9ycyBhbmQgYm9ycm93ZXJzLiBGb3IgbW9yZSBiYXNpYyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY29tcGFueSBwbGVhc2UgY2hlY2sgb3V0IHRoZSB3aWtpcGVkaWEgYXJ0aWNsZSBhYm91dCB0aGUgY29tcGFueS4KCiMjIHRhc2sKClNJQihTbWFsbCBJbmR1c3RyaWVzIEJhbmspIGxvYW5zIG1vbmV5IHRvIGNvbXBhbmllcyBpbiBleGNoYW5nZSBmb3IgdGhlIHByb21pc2Ugb2YgcmVwYXltZW50LiBTb21lIHdpbGwgZGVmYXVsdCBvbiB0aGUgbG9hbnMsIGJlaW5nIHVuYWJsZSB0byByZXBheSB0aGVtIGZvciBzb21lIHJlYXNvbi4gVGhlIGJhbmsgbWFpbnRhaW5zIGluc3VyYW5jZSB0byByZWR1Y2UgdGhlaXIgcmlzayBvZiBsb3NzIGluIHRoZSBldmVudCBvZiBkZWZhdWx0LiBUaGUgaW5zdXJlZCBhbW91bnQgbWF5IGNvdmVyIGFsbCBvciBqdXN0IHNvbWUgcGFydCBvZiB0aGUgbG9hbiBhbW91bnQuIFNJQiB3YW50cyB0byBwcmVkaWN0IHdoaWNoIGNvbXBhbmllcyB3aWxsIGRlZmF1bHQgb24gdGhlaXIgbG9hbnMgYmFzZWQgb24gdGhlaXIgZmluYW5jaWFsIGluZm9ybWF0aW9uLiBUaGV5IGhhdmUgcHJvdmlkZWQgeW91IHdpdGggYSBkYXRhc2V0IHRoYXQgY29uc2lzdHMgb2YgbG9hbiByZWxhdGVkIGluZm9ybWF0aW9uIHN1Y2ggYXMgbG9hbiBhbW91bnQsIHRlcm0sIGFuZCBzdGF0ZS4gQWxzbywgdGhlcmUgaXMgY29tcGFueSBpbmZvcm1hdGlvbiBzdWNoIGFzIHRoZSBudW1iZXIgb2YgZW1wbG95ZWVzLCBvcGVyYXRpbmcgc2VjdG9yLCBldGMuCgpVc2luZyBtYWNoaW5lIGxlYXJuaW5nLCBwcmVkaWN0IHdoaWNoIGNvbXBhbmllcyB3aWxsIGRlZmF1bHQgb24gdGhlaXIgbG9hbnMgYW5kIGV4cGxhaW4gaG93IGRpZmZlcmVudCBmZWF0dXJlcyBpbXBhY3QgdGhlIHByZWRpY3Rpb25zLgoKIyBTZXR1cCB7LnRhYnNldH0KCjxwIGFsaWduPSJyaWdodCI+Cl9fW0JhY2sgdG8gSG9tZV0oaHR0cHM6Ly94dWVsaW4tYW15LmdpdGh1Yi5pby9wbGF5Z3JvdW5kL2ZlYXR1cmVkLylfXzwvcD4KCiMjIG5vdGVib29rIHNldHVwCgpub3RlYm9vayBzZXR1cCB0byBoaWRlIG1lc3NhZ2VzIGFuZCB3YXJuaW5ncy4KCmZpZ3VyZSBzaXplIHdhcyBzZXQgdG8gNCB4IDIgaW5jaC4KCnNldCB1cCBnZ3Bsb3QgdGhlbWUgZm9yIG5vdGVib29rLgoKYGBge3Igc2V0dXB9CmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodD0yLCAKICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aD00KQoKIyBzZXQgdXAgdGhlbWUgZm9yIGdncGxvdApteS50aGVtZSA8LSB0aGVtZSgKICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiKSwgIyBiZyBvZiB0aGUgcGFuZWwKICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIpLCAjIGJnIG9mIHRoZSBwbG90CiAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgIyBnZXQgcmlkIG9mIG1ham9yIGdyaWQKICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCAjIGdldCByaWQgb2YgbWlub3IgZ3JpZAogIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvciA9IE5BKSwgIyBnZXQgcmlkIG9mIGxlZ2VuZCBiZwogIGxlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgY29sb3IgPSBOQSkpICMgZ2V0IHJpZCBvZiBsZWdlbmQgcGFuZWwKCmBgYAoKIyMgbG9hZCBwYWNrYWdzCmBgYHtyfQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoc3VtbWFyeXRvb2xzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmBgYAoKIyMgaGVscCBmdW5jdGlvbnMKCmBgYHtyfQoKYGBgCgoKIyBEYXRhIHByZXBhcmF0aW9ucyB7LnRhYnNldH0KCjxwIGFsaWduPSJyaWdodCI+Cl9fW0JhY2sgdG8gSG9tZV0oaHR0cHM6Ly94dWVsaW4tYW15LmdpdGh1Yi5pby9wbGF5Z3JvdW5kL2ZlYXR1cmVkLylfXzwvcD4KCiMjIGRhdGEgbG9hZGluZwoKdGhlcmUgYXJlIHR3byBkYXRhc2V0czoKCiogdHJhaW4uY3N2CiogdGVzdC5jc3YKCkluIGB0cmFpbi5jc3ZgOgoKKiB0aGVyZSBhcmUgX18yNDAyX18gcmVjb3JkcyAoY29tcGFueXMpIGluIHRvdGFsCiogdGhleSBhcmUgZnJvbSAxNiBkaXN0aW5jdCBpbmR1c3RyaWVzCiogdGhleSBhcmUgZnJvbSA1MCBkaWZmZXJlbnQgc3RhdGVzCiogdGhlIGR1cmF0aW9uIG9mIGRhdGEgcHJvdmlkZWQgaXMgX18xIHllYXJfXywgcmVxdWVzdCBkYXRlIGlzIGZyb20gMjAwOS0xMC0wMSB0byAyMDEwLTA5LTMwCiogYXZlcmFnZSB0ZXJtIGlzIH4gX184N19fCiogYXZlcmFnZSBlbXBsb3llZSBjb3VudCBpcyB+IF9fOV9fCiogbWFqb3JpdHkgKDcwJSkgb2YgY29tcGFuaWVzIGFyZSBfX25ldyBidXNpbmVzc19fCiogbWFqb3JpdHkgKDk0LjUlKSBvZiBjb21wYW5pZXMgYXJlIGZyb20gX190eXBlIC0gMF9fCiogMjcuNSUgb2YgdGhlIGNvbXBhbmllcyBhcmUgaGF2aW5nIG90aGVyIGxvYW5zCiogYXZlcmFnZSBkZWZhdWx0IHJhdGUgaXMgX18zMi4yJV9fCiogdHJhaW4gc2V0IGlzIHByZXR0eSBjb21wbGV0ZSwgb25seSAxIG1pc3NpbmcgcmVjb3JkIGZyb20gaW5kdXN0cnkKCnRoZSBmaXJzdCA2IHJvd3Mgb2YgdHJhaW4uY3N2IGxvb2sgbGlrZSB0aGlzOgoKYGBge3IgfQpkZiA8LSBmcmVhZCgnLi9kYXRhL3RyYWluLmNzdicpCmRmICU+JQogIHNlbGVjdCgtaWQpICU+JQogIGhlYWQoKSAlPiUKICBrYWJsZShjYXB0aW9uID0gJ3JhdyBkYXRhJykgJT4lCiAga2FibGVfc3R5bGluZygnc3RyaXBlZCcsZnVsbF93aWR0aCA9IFQpCmBgYAoKIyMgZGF0YSBjbGVhbnNpbmcKClRoZSBnaXZlbiBkYXRhIGlzIApTb21lIGNvbHVtbiB0eXBlIGNvbnZlcnNpb24gd2FzIGRvbmUgdG8gY2xlYW4gdGhlIGRhdGE6CgoqIGNvbnZlcnQgdGhlIGRhdGUgY29sdW1uIHRvIGBEYXRlYCB0eXBlOiAiMzAtRGVjLTA5IiA9PiAiMjAxOS0xMi0zMCIKKiBjb252ZXJ0IGN1cnJlbmN5IGNvbHVtbiB0byBudW1lcmljOiAiJDM1LDAwMC4wMCIgPT4gIjM1MDAwLjAwIgoKYGBge3J9CmNsZWFuX2RhdGEgPC0gZnVuY3Rpb24oZGYpewogIGRmICU+JQogICAgbXV0YXRlKAogICAgICByZXF1ZXN0X2RhdGUgPSBhcy5EYXRlKHJlcXVlc3RfZGF0ZSwgZm9ybWF0ID0gJyVkLSVCLSV5JyksCiAgICAgIGxvYW5fYW1vdW50ID0gYXMubnVtZXJpYyhnc3ViKCdbJCxdJywnJywgbG9hbl9hbW91bnQpKSwKICAgICAgaW5zdXJlZF9hbW91bnQgPSBhcy5udW1lcmljKGdzdWIoJ1skLF0nLCcnLCBpbnN1cmVkX2Ftb3VudCkpKQp9CmRmIDwtIGNsZWFuX2RhdGEoZGYpCmRmICU+JQogIHNlbGVjdCgtaWQpICU+JQogIGhlYWQoKSAlPiUKICBrYWJsZShjYXB0aW9uID0gJ2NsZWFuZWQgZGF0YScpICU+JQogIGthYmxlX3N0eWxpbmcoJ3N0cmlwZWQnLGZ1bGxfd2lkdGggPSBUKQoKYGBgCgojIyBkYXRhIHN1bW1hcnkKCnN1bW1hcnkgb2YgYHRyYWluLmNzdmAKCiogX18jIG9mIHJvd3M6X18gYHIgbnJvdyhkZilgCiogX18jIG9mIGNvbHVtbnM6X18gYHIgbmNvbChkZilgCgpgYGB7ciByZXN1bHRzPSdhc2lzJ30KZGYgJT4lIAogIHNlbGVjdCgtaWQpICU+JQogIGRmU3VtbWFyeShzdHlsZSA9ICdncmlkJywgcGxhaW4uYXNjaWkgPSBGLCB0bXAuaW1nLmRpciA9ICcuL3RtcCcsIGhlYWRpbmdzID0gRikKYGBgCgojIERlc2NyaXB0aXZlIGFuYWx5c2lzCgo8cCBhbGlnbj0icmlnaHQiPgpfX1tCYWNrIHRvIEhvbWVdKGh0dHBzOi8veHVlbGluLWFteS5naXRodWIuaW8vcGxheWdyb3VuZC9mZWF0dXJlZC8pX188L3A+CgojIyAgdGVybSBvZiBsb2FuCgpDb21wYXJlZCB3aXRoIG5vbi1kZWZhdWx0IGxvYW5zLCB0aGUgZGVmYXVsdCBsb2FucyBoYWQgcmVsYXRpdmVseSBsb3dlciB0ZXJtcy4gCgpgYGB7cn0KIyA0LjEgdGVybSBoaXN0b2dyYW0KZGYgJT4lIAogIG11dGF0ZShkZWZhdWx0X3N0YXR1cyA9IGZhY3RvcihkZWZhdWx0X3N0YXR1cykpICU+JQogIGdncGxvdChhZXMoeD0gdGVybSwgZmlsbD0gZGVmYXVsdF9zdGF0dXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucz01MCkgKwogIGZhY2V0X2dyaWQofmRlZmF1bHRfc3RhdHVzKSArCiAgbXkudGhlbWUKYGBgCgojIyBsb2FuIGFtb3VudCB7LnRhYnNldH0KCiMjIyBkaXN0cmlidXRpb24KCkxvYW4gYW1vdW50IGFuZCBJbnN1cmVkIGFtb3VudCBhcmUgYm90aCBoYXZpbmcgc2tld2VkIGRpc3RyaWJ1dGlvbi4gTG9nYXJpdGhtIHRyYW5zZm9ybWF0aW9uIGlzIGFwcGxpZWQgdG8gYnJpbmcgdGhlbSB0byBub3JtYWwtbGlrZSBkaXN0cmlidXRpb24uCgoKYGBge3J9CnAxIDwtIGRmICU+JSAKICBnZ3Bsb3QoYWVzKHg9bG9hbl9hbW91bnQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBmaWxsPSdsaWdodGJsdWUnKSArCiAgbGFicyh0aXRsZSA9ICdMb2FuIEFtb3VudCcpICsKICBteS50aGVtZQpwMiA8LSBkZiAlPiUKICBnZ3Bsb3QoYWVzKHg9aW5zdXJlZF9hbW91bnQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBmaWxsPSdsaWdodGJsdWUnKSArCiAgbGFicyh0aXRsZSA9ICdJbnN1cmVkIEFtb3VudCcpICsKICBteS50aGVtZQpwMyA8LSBwMSArIHNjYWxlX3hfbG9nMTAoKSArIGxhYnModGl0bGUgPSAnTG9hbiBBbW91bnQgKGxvZyBzY2FsZSknKQpwNCA8LSBwMiArIHNjYWxlX3hfbG9nMTAoKSArIGxhYnModGl0bGUgPSAnSW5zdXJlZCBBbW91bnQgKGxvZyBzY2FsZSknKQpnZ2FycmFuZ2UocDEscDIscDMscDQsIG5jb2wgPSAyLCBucm93ID0gMikKYGBgCgojIyMgY29ycmVsYXRpb24KClRoZSBpbnN1cmVkIGFtb3VudCBmb3IgdGhlIGRlZmF1bHQgaW5zdXJhbmNlIGlzIGRpcmVjdGx5IGNvcnJlbGF0ZWQgd2l0aCBsb2FuIGFtb3VudCBvZiB0aGUgbG9hbi4KCmBgYHtyfQpkZiAlPiUKZ2dwbG90KGFlcyh4ID0gbG9hbl9hbW91bnQsIHkgPSBpbnN1cmVkX2Ftb3VudCkpICsgCmdlb21fcG9pbnQoY29sb3IgPSAnbGlnaHRibHVlJykgKwpnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGNvbG9yID0gJ3JlZCcsIGxpbmV0eXBlID0gJ2Rhc2hlZCcpICsKbGFicyh0aXRsZSA9ICdJbnN1cmVkIEFtb3VudCB2cy4gTG9hbiBBbW91bnQnLAogICAgIHggPSAnbG9hbiBhbW91bnQnLAogICAgIHkgPSAnaW5zdXJlZCBhbW91bnQnKSArCiAgbXkudGhlbWUKYGBgCgojIyMgZWZmZWN0IG9uIGRlZmF1bHQKCkxvd2VyIGxvYW4gYW1vdW50IHRlbmRzIHRvIGhhdmUgaGlnaCBkZWZhdWx0IHJhdGUKCmBgYHtyfQojIExvYW4gQW1vdW50IGVmZmVjdCBvbiBkZWZhdWx0CmRmICU+JQpnZ3Bsb3QoYWVzKHggPSBsb2cxMChsb2FuX2Ftb3VudCksIGZpbGwgPSBmYWN0b3IoZGVmYXVsdF9zdGF0dXMpKSkgKwpnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUpICsKbGFicyhmaWxsID0gJ2RlZmF1bHQgc3RhdHVzJykrCiAgbXkudGhlbWUKYGBgCgojIyBkZWZhdWx0IHJhdGUgey50YWJzZXR9CgojIyMgYnkgbW9udGgKClRoZSBkZWZhdWx0IHJhdGUgaXMgb2JzZXJ2ZWQgc3RhYmxlIGZyb20gMjAxOS0xMCB0byAyMDEwLTA5LCB0aG91Z2ggdGhlIHZvbHVtZSBvZiBsb2FucyBzaG93ZWQgc29tZSB2YXJpYXRpb24gaW4gbW9udGhzLgoKYGBge3J9CnJlcyA8LSBkZiAlPiUgCiAgbXV0YXRlKHltID0gZm9ybWF0KHJlcXVlc3RfZGF0ZSwgJyVZLSVtLTAxJyksCiAgICAgICAgIHltID0gYXMuRGF0ZSh5bSkpICU+JQogIGdyb3VwX2J5KHltKSAlPiUgCiAgc3VtbWFyaXNlKHZvbHVtZSA9IG4oKSwKICAgICAgICAgICAgZGVmYXVsdF9yYXRlID0gbWVhbihkZWZhdWx0X3N0YXR1cykpCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHg9IHltLCB5PXZvbHVtZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JywgZmlsbCA9ICdvcmFuZ2UnLCBncm91cD0gMSkgKwogIGdlb21fbGluZShhZXMoeSA9IGRlZmF1bHRfcmF0ZSAvIG1heChyZXMkZGVmYXVsdF9yYXRlKSAqIG1heChyZXMkdm9sdW1lKSksIHN0YXQgPSAnaWRlbnRpdHknLCBjb2xvcj0ncmVkJywgZ3JvdXAgPSAxKSArCiAgZ2VvbV9wb2ludChhZXMoeSA9IGRlZmF1bHRfcmF0ZSAvIG1heChyZXMkZGVmYXVsdF9yYXRlKSAqIG1heChyZXMkdm9sdW1lKSksIHN0YXQgPSAnaWRlbnRpdHknLCBjb2xvcj0ncmVkJywgZ3JvdXAgPSAxKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKGkpIGZvcm1hdChpLCBiaWcubWFyayA9ICcsJyksCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4vbWF4KHJlcyR2b2x1bWUpICogbWF4KHJlcyRkZWZhdWx0X3JhdGUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gJ0RlZmF1bHQgUmF0ZScKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSArCiAgc2NhbGVfeF9kYXRlKCkrCiAgbGFicyh4PSdSZXF1ZXN0ZWQgRGF0ZScseT0nVm9sdW1lJykgKwogIG15LnRoZW1lICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQpgYGAKCiogYmFycyByZXByZXNlbnQgdGhlIHZvbHVtZSBvZiBsb2FucyBpbiBlYWNoIG1vbnRoCiogbGluZSByZXByZXNlbnRzIHRoZSBkZWZhdWx0IHJhdGUgaW4gZWFjaCBtb250aAoKIyMjIGJ5IGluZHVzdHJ5CgpDb25zdHJ1Y3Rpb24gaW5kdXN0cnkgaGFzIGhpZ2hlc3QgZGVmYXVsdCByYXRlLCB3aGlsZSBlbmVyZ3kgaW5kdXN0cnkgaGFzIHRoZSBsb3dlc3QKCgpgYGB7cn0KZGYgJT4lCiAgZ3JvdXBfYnkoaW5kdXN0cnkpICU+JQogIHN1bW1hcmlzZShkZWZhdWx0X3JhdGU9IG1lYW4oZGVmYXVsdF9zdGF0dXMpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihpbmR1c3RyeSwgZGVmYXVsdF9yYXRlKSwgeT1kZWZhdWx0X3JhdGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICdpZGVudGl0eScsIGZpbGw9J29yYW5nZScpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgbGFicyh4PSdJbmR1c3RyeScsIHk9J0RlZmF1bHQgUmF0ZScpICsKICBjb29yZF9mbGlwKGV4cGFuZCA9IEYpICArCiAgbXkudGhlbWUKYGBgCgojIyMgYnkgYnVzaW5lc3MgdHlwZQoKTmV3IGJ1c2luZXNzIHRlbmRzIHRvIGhhdmUgaGlnaGVyIGRlZmF1bHQgcmF0ZQoKYGBge3J9CnAxIDwtIGRmICU+JQogIGdyb3VwX2J5KGJ1c2luZXNzX25ldykgJT4lCiAgc3VtbWFyaXNlKGRlZmF1bHRfcmF0ZSA9IG1lYW4oZGVmYXVsdF9zdGF0dXMpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9YnVzaW5lc3NfbmV3LCB5PWRlZmF1bHRfcmF0ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JywgZmlsbD0nb3JhbmdlJykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9c2NhbGVzOjpwZXJjZW50KSArCiAgbGFicyh0aXRsZSA9ICdOZXcgQnVzaW5lc3MgVHlwZScsIHg9J05ldyBCdXNpbmVzcycseT0nRGVmYXVsdCBSYXRlJykgKwogIGNvb3JkX2ZsaXAoKSArCiAgbXkudGhlbWUKCnAyIDwtIGRmICU+JQogIGdyb3VwX2J5KGJ1c2luZXNzX3R5cGUpICU+JQogIHN1bW1hcmlzZShkZWZhdWx0X3JhdGUgPSBtZWFuKGRlZmF1bHRfc3RhdHVzKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYnVzaW5lc3NfdHlwZSwgeSA9IGRlZmF1bHRfcmF0ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JywgZmlsbCA9ICdsaWdodGJsdWUnKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKyAKICBsYWJzKHRpdGxlID0gJ0J1c2luZXNzIFR5cGUgRWZmZWN0JywgeCA9ICdCdXNpbmVzcyBUeXBlJywgeSA9ICdEZWZhdWx0IFJhdGUnKSArCiAgY29vcmRfZmxpcCgpICsKICBteS50aGVtZQoKZ2dhcnJhbmdlKHAxLHAyLCBuY29sID0gMikKCmBgYAoKIyBQcmVkaWN0aXZlIG1vZGVsbGluZwoKPHAgYWxpZ249InJpZ2h0Ij4KX19bQmFjayB0byBIb21lXShodHRwczovL3h1ZWxpbi1hbXkuZ2l0aHViLmlvL3BsYXlncm91bmQvZmVhdHVyZWQvKV9fPC9wPgoKIyMgUHJlcGFyYXRpb25zIHsudGFic2V0fQoKIyMjIE1lcmdlIHRyYWluL3Rlc3Qgc2V0CgpDb21iaW5pbmcgdHJhaW4gJiB0ZXN0IGRhdGEgZm9yIGRhdGEgY2xlYW5zaW5nIGFuZCBmZWF0dXJlIGVuZ2luZWVyaW5nLgoKYGBge3J9CgojIyBjb21iaW5lIHRyYWluIGFuZCB2YWxpZCBiZWZvcmUgY29udmVydCB0byBmYWN0b3IKCmRmJGZsYWcgPC0gJ3RyYWluJwpkZi50ZXN0IDwtIGZyZWFkKCcuL2RhdGEvdGVzdC5jc3YnKSAlPiUgCiAgY2xlYW5fZGF0YSgpICU+JQogIG11dGF0ZShkZWZhdWx0X3N0YXR1cyA9IDAsIGZsYWc9J3Rlc3QnKQpkZi5mdWxsIDwtcmJpbmQoZGYsZGYudGVzdCkKCiNjcmVhdCBmZWF0dXJlcyBmcm9tIHJlcXVlc3QgZGF0YQpkZi5mdWxsIDwtIGRmLmZ1bGwgJT4lCiAgbXV0YXRlKHJlcXVlc3RfeW0gPSBmb3JtYXQocmVxdWVzdF9kYXRlLCAnJVktJW0nKSkKYGBgCgojIyMgTGF1bmNoIEgyTyBhbmQgc2V0IHVwCgpgYGB7cn0KIyBpbml0IGgybyBsaWJyYXJ5CmxpYnJhcnkoaDJvKQpoMm8uaW5pdChudGhyZWFkcyA9IDQsIG1heF9tZW1fc2l6ZSA9ICc0ZycpCmgyby5ub19wcm9ncmVzcygpCiNjb252ZXJ0IGRhdGEudGFibGUgdG8gaDJvLmZyYW1lCmZ1bGwuaGV4IDwtIGFzLmgybyhkZi5mdWxsKQoKI2NvbnZlcnQgY2F0ZWdvcmljYWwgdmFyaWFibGVzIHRvIGZhY3RvcgpmdWxsLmhleCRsYWJlbCA8LSBoMm8uYXNmYWN0b3IoZnVsbC5oZXgkZGVmYXVsdF9zdGF0dXMpCmZ1bGwuaGV4JGluZHVzdHJ5IDwtIGgyby5hc2ZhY3RvcihmdWxsLmhleCRpbmR1c3RyeSkKZnVsbC5oZXgkc3RhdGUgPC0gaDJvLmFzZmFjdG9yKGZ1bGwuaGV4JHN0YXRlKQpmdWxsLmhleCRidXNpbmVzc19uZXcgPC0gaDJvLmFzZmFjdG9yKGZ1bGwuaGV4JGJ1c2luZXNzX25ldykKZnVsbC5oZXgkb3RoZXJfbG9hbnMgPC0gaDJvLmFzZmFjdG9yKGZ1bGwuaGV4JG90aGVyX2xvYW5zKQpmdWxsLmhleCRyZXF1ZXN0X3ltIDwtIGgyby5hc2ZhY3RvcihmdWxsLmhleCRyZXF1ZXN0X3ltKQoKI3NwbGl0IHRyYWluLCB0ZXN0CnRyYWluLmhleCA8LSBmdWxsLmhleFtmdWxsLmhleCRmbGFnID09ICd0cmFpbicsXQp0ZXN0LmhleCA8LSBmdWxsLmhleFtmdWxsLmhleCRmbGFnID09ICd0ZXN0JyxdCgojZGVmaW5lIGZlYXR1cmUgc2V0CmZlYXR1cmUubmFtZXMgPC0gYygnaW5kdXN0cnknLCdzdGF0ZScsJ3Rlcm0nLCdlbXBsb3llZV9jb3VudCcsJ3JlcXVlc3RfeW0nLCdidXNpbmVzc19uZXcnLCAKICAgICAgICAgICAgICAgICAgICdidXNpbmVzc190eXBlJywgJ290aGVyX2xvYW5zJywnbG9hbl9hbW91bnQnLCdpbnN1cmVkX2Ftb3VudCcpCmBgYAoKIyMgQmFzZWxpbmU6IExvZ2lzaXRjIFJlZ3Jlc3Npb24gey50YWJzZXR9CgojIyMgbW9kZWwgcGVyZm9ybWFuY2UKYGBge3J9CiMgNS4xIExpbmVhciBNb2RlbC0gTG9naXN0aWMgUmVncmVzc2lvbiBCYXNlbGluZQptb2RlbF9yaWRnZSA8LSBoMm8uZ2xtKHg9ZmVhdHVyZS5uYW1lcywgeT0nbGFiZWwnLCAKICAgICAgICAgICAgICAgICAgICAgICB0cmFpbmluZ19mcmFtZSA9IHRyYWluLmhleCwgCiAgICAgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gJ2Jpbm9taWFsJywKICAgICAgICAgICAgICAgICAgICAgICBuZm9sZHMgPSA1LCBhbHBoYSA9IDAsIGxhbWJkYV9zZWFyY2ggPSBUKQoKIyBhdWMKcmVzX3JpZGdlIDwtIGgyby5hdWMobW9kZWxfcmlkZ2UsIHRyYWluPVQsIHh2YWwgPSBUKQpgYGAKCkFVQyBvZiBST0MgLSBMb2dpc3RpYyByZWdyZXNzaW9uCgoqIHRyYWluIHNldDogYHIgcm91bmQocmVzX3JpZGdlWyd0cmFpbiddLDIpYAoqIHZhbGlkIHNldDogYHIgcm91bmQocmVzX3JpZGdlWyd4dmFsJ10sMilgCgp0cmFpbiBoaXN0b3J5OgoKYGBge3J9Cm1vZGVsX3JpZGdlQG1vZGVsJHNjb3JpbmdfaGlzdG9yeSAlPiUKICBzZWxlY3QoaXRlcmF0aW9uLCBkZXZpYW5jZV90cmFpbiwgZGV2aWFuY2VfeHZhbCkgJT4lCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gLWl0ZXJhdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICdkYXRhJywKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICdsb3NzJykgJT4lCiAgZ2dwbG90KGFlcyh4ID0gaXRlcmF0aW9uLCB5ID0gbG9zcywgY29sb3IgPSBkYXRhKSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBteS50aGVtZSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpCmBgYAoKCiMjIyB2YXJpYWJsZSBpbXBvcnRhbmNlCgpgYGB7cn0KaDJvLnZhcmltcChtb2RlbF9yaWRnZSkgJT4lIApoZWFkKDEwKSAlPiUKZ2dwbG90KGFlcyh4ID0gcmVvcmRlcih2YXJpYWJsZSwgc2NhbGVkX2ltcG9ydGFuY2UpLCB5ID0gc2NhbGVkX2ltcG9ydGFuY2UpKSArCmdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCBmaWxsID0gJ2xpZ2h0Ymx1ZScpICsKY29vcmRfZmxpcChleHBhbmQgPSBGKSArCmxhYnMoeCA9ICd2YXJpYWJsZScpKwpteS50aGVtZSAgCgpoMm8udmFyaW1wKG1vZGVsX3JpZGdlKSAlPiUgaGVhZCgxMCkgJT4lCiAga2FibGUoY2FwdGlvbiA9ICdMb2dpc3RpYyBSZWdyZXNzaW9uIFZhcmlhYmxlIEltcG9ydGFuY2UnKSAlPiUKICBrYWJsZV9zdHlsaW5nKCdzdHJpcGVkJykKYGBgCgoKIyMgWGdib29zdCBtb2RlbCB7LnRhYnNldH0KCmBgYHtyfQojIDUuMiBYZ2Jvb3N0IE1vZGVsIC1UcmVlIEJhc2VkIEVuc2VtYmxlIE1vZGVsCm1vZGVsX3hnYiA8LSBoMm8ueGdib29zdCh4PWZlYXR1cmUubmFtZXMseT0nbGFiZWwnLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHRyYWluaW5nX2ZyYW1lID0gdHJhaW4uaGV4LAogICAgICAgICAgICAgICAgICAgICAgICAgbWF4X2RlcHRoID0gNiwgZXRhID0gMC4xLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHN0b3BwaW5nX21ldHJpYyA9ICdBVUMnLHN0b3BwaW5nX3JvdW5kcyA9IDIxLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG50cmVlcyA9IDUwMCwgbmZvbGRzID0gNSkKI2F1YwpyZXNfeGdib29zdCA8LSBoMm8uYXVjKG1vZGVsX3hnYiwgdHJhaW4gPSBULCB4dmFsID0gVCkKYGBgCgojIyMgbW9kZWwgcGVyZm9ybWFuY2UKCkFVQyBvZiBST0MgLSBYZ2Jvb3N0CgoqIHRyYWluIHNldDogYHIgcm91bmQocmVzX3hnYm9vc3RbJ3RyYWluJ10sMilgCiogdmFsaWQgc2V0OiBgciByb3VuZChyZXNfeGdib29zdFsneHZhbCddLDIpYAoKdHJhaW4gaGlzdG9yeToKCmBgYHtyfQptb2RlbF94Z2JAbW9kZWwkc2NvcmluZ19oaXN0b3J5ICU+JQogIHNlbGVjdChudW1iZXJfb2ZfdHJlZXMsIHRyYWluaW5nX2xvZ2xvc3MsIHRyYWluaW5nX2F1YykgJT4lCiAgdGlkeXI6OnBpdm90X2xvbmdlcihjb2xzID0gLW51bWJlcl9vZl90cmVlcywgCiAgICAgICAgICAgICAgICAgICAgICBuYW1lc190byA9ICdkYXRhJywKICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICdsb3NzJykgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbnVtYmVyX29mX3RyZWVzLCB5ID0gbG9zcywgY29sb3IgPSBkYXRhKSkgKyAKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBteS50aGVtZSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpCmBgYAoKIyMjIHZhcmlhYmxlIGltcG9ydGFuY2UKCmBgYHtyfQpoMm8udmFyaW1wKG1vZGVsX3hnYikgJT4lIApoZWFkKDEwKSAlPiUKZ2dwbG90KGFlcyh4ID0gcmVvcmRlcih2YXJpYWJsZSwgc2NhbGVkX2ltcG9ydGFuY2UpLCB5ID0gc2NhbGVkX2ltcG9ydGFuY2UpKSArCmdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknLCBmaWxsID0gJ2xpZ2h0Ymx1ZScpICsKY29vcmRfZmxpcChleHBhbmQgPSBGKSArCmxhYnModGl0bGUgPSAndmFyaWFibGUgaW1wb3J0YW5jZSBvZiBYZ2Jvb3N0IG1vZGVsJywgeCA9ICd2YXJpYWJsZScpICsgbXkudGhlbWUKaDJvLnZhcmltcChtb2RlbF94Z2IpICU+JSBoZWFkKDEwKSAlPiUKICBrYWJsZShjYXB0aW9uID0gJ1hnYm9vc3QgVmFyaWFibGUgSW1wb3J0YW5jZScpICU+JQogIGthYmxlX3N0eWxpbmcoJ3N0cmlwZWQnKQpgYGAKCiMjIE1vZGVsIHNlbGVjdGlvbgoKWGdib29zdCBtb2RlbCBpcyBtdWNoIGJldHRlciB0aGFuIExvZ2lzdGljIFJlZ3Jlc3Npb24gaW4gdGVybXMgb2YgQVVDLiBUaGUgcmFua2luZyBvZiB0b3AgdmFyaWFibGVzIGluIHRoZSB2YXJpYWJsZSBpbXBvcnRhbmNlIGZvciBib3RoIG1ldGhvZHMgYXJlIGdlbmVyYWxseSBhbGlnbmVkLiBUZXJtLCBsb2FuIGFtb3VudCBhbmQgaW5zdXJlZCBhbW91bnQgYXJlIHRoZSBtb3N0IGltcG9ydGFudCB2YXJpYWJsZXMgaW4gcHJlZGljdGluZyB0aGUgZGVmYXVsdCBzdGF0dXMgZm9yIGEgbG9hbi4gVGhlcmVmb3JlLCB4Z2Jvb3N0IG1vZGVsIGlzIHVzZWQgZm9yIHByZWRpY3Rpb24uCgojIyMgbWFrZSBwcmVkaWN0aW9uCgpMZXQncyB2aWV3IHRoZSBzYW1wbGUgb2YgcHJlZGljdGlvbnMgZnJvbSB4Z2Jvb3N0IG1vZGVsLgoKKmNhdmVhdDogYSB0aHJlc2hvbGQgb2YgMC41IHdhcyBhc3N1bWVkIHRvIG91dHB1dCB0aGUgcHJlZGljdGlvbiBjbGFzcyoKCmBgYHtyfQpwcmVkcyA8LSBwcmVkaWN0KG1vZGVsX3hnYiwgdGVzdC5oZXgpCnByZWRzIDwtIGgyby5jYmluZCh0ZXN0LmhleCRpZCwgcHJlZHMpCnByZWRzICU+JQogIGhlYWQoMTApICU+JQogIHNlbGVjdChpZCwgcDAscDEscHJlZGljdCkgJT4lCiAgbXV0YXRlKHByZWRpY3QgPSBpZmVsc2UocHJlZGljdCA9PSAxLCAnZGVmYXVsdCcsJ3JlcGFpZCcpKSAlPiUKICBrYWJsZShjYXB0aW9uID0gJ3hnYm9vc3QgbW9kZWwgcHJlZGljdGlvbicsIGRpZ2l0cyA9IDIpICU+JQogIGthYmxlX3N0eWxpbmcoJ3N0cmlwZWQnLHBvc2l0aW9uID0gJ2xlZnQnLCBmdWxsX3dpZHRoID0gRikKYGBgCgoKYGBge3IgaW5jbHVkZT1GQUxTRX0KaDJvLnNodXRkb3duKEYpCmBgYAoK