Introduction
About Prosper
From the Prosper website. Prosper is America’s first marketplace lending platform, with over $10 billion in funded loans.
Prosper allows people to invest in each other in a way that is financially and socially rewarding. On Prosper, borrowers list loan requests between $2,000 and $35,000 and individual investors invest as little as $25 in each loan listing they select. Prosper handles the servicing of the loan on behalf of the matched borrowers and investors.
Overview
From Udacity:
This data set contains 113,937 loans with 81 variables on each loan, including loan amount, borrower rate (or interest rate), current loan status, borrower income, borrower employment status, borrower credit history, and the latest payment information.
Setup & General
Select Categories of Interest
The dataframe has been reduced from 81 to 22 categories that may be evaluated as parameters of interest within the scope of the data-set options.
prosper <- prosper[c(3, 5, 6, 9, 13, 15:18, 20, 26, 35:36, 41:42, 46:50, 53:54)]
colnames(prosper)
[1] "ListingCreationDate" "Term" "LoanStatus" "BorrowerRate"
[5] "EstimatedReturn" "ProsperRating..Alpha." "ProsperScore" "ListingCategory..numeric."
[9] "BorrowerState" "EmploymentStatus" "CreditScoreRangeLower" "TotalInquiries"
[13] "CurrentDelinquencies" "RevolvingCreditBalance" "BankcardUtilization" "TradesOpenedLast6Months"
[17] "DebtToIncomeRatio" "IncomeRange" "IncomeVerifiable" "StatedMonthlyIncome"
[21] "TotalProsperPaymentsBilled" "OnTimeProsperPayments"
Data Transformations
as.factor
prosper$ProsperScore <- as.factor(prosper$ProsperScore)
prosper$ListingCategory..numeric. <- as.factor(prosper$ListingCategory..numeric.)
prosper$Term <- as.factor(prosper$Term)
prosper$ProsperRating..Alpha. <- factor(prosper$ProsperRating..Alpha.,
levels = c('AA', 'A', 'B', 'C', 'D',
'E', 'HR'), ordered = TRUE)
Calculated Yearly Income
prosper$CalcYearlyIncome <- prosper$StatedMonthlyIncome * 12
Remove 2005
There are very few loans in 2005
prosper <- subset(prosper, ListingCreationYear != 2005)
Create a new Delinquent category based upon LoanStatus
# Used for filling histograms
prosper$Delinquent <- ifelse(
prosper$LoanStatus == 'Completed' |
prosper$LoanStatus == 'Current' |
prosper$LoanStatus == 'FinalPaymentInProgress',
'False', 'True')
prosper$Delinquent <- factor(prosper$Delinquent)
# Used in calculating correlations
prosper$DelinquentNum <- as.numeric(prosper$Delinquent,
levels = c('False', 'True'))
Replace DC with MD
DC is not a state
prosper$BorrowerState[prosper$BorrowerState == 'DC'] <- 'MD'
as.numeric
prosper$ProsperScore..numeric. <- as.numeric(prosper$ProsperScore,
levels = c(1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11))
Create ListingCategory from ListingCategory..numeric..
categories = c('NA', 'Debt Consol', 'Home Improvement', 'Business', 'Personal',
'Student', 'Auto', 'Other', 'Baby', 'Boat', 'Cosmetic',
'Engagement', 'Green', 'Household', 'Large Purchases',
'Medical/Dental', 'Motorcycle', 'RV', 'Taxes', 'Vacation',
'Wedding')
prosper$ListingCategory <- prosper$ListingCategory..numeric.
levels(prosper$ListingCategory) <- categories
Create Ratio_PL_Pay_OT - Ratio of Prosper Loan Payments Paid On Time
# Used for linear model
prosper$Ratio_PL_Pay_OT <- prosper$OnTimeProsperPayments/
prosper$TotalProsperPaymentsBilled
prosper$Ratio_PL_Pay_OT[is.na(prosper$Ratio_PL_Pay_OT)] <- 0
Inquiry
Correlation Matrix
Generated to provide a high level view of possibly interrelated metrics.
Listing Creation Date
ListingCreationYear colored by LoanStatus & Delinquent - Univariate
For the purpose of this analysis, all categories of LoanStatus except Completed, Current & FinalPaymentInProgress are True in the Delinquent category.
Listing Creation Year with Delinquency
2006 2007 2008 2009 2010 2011 2012 2013 2014
6213 11557 11263 2206 5530 11442 19556 35413 10734
ListingCreationYear colored by Delinquent - Univariate
A view of the absolute number of loans and delinquencies. As will hold true for all further discussions, delinquencies is a reflection of the loan status through 2014. The loan terms are for 1, 3 and 5 years, so the final closed status can only be determined for most loans through 2011 (i.e. most loan terms are 3 years). Note the increasing number of loans following the 2007 downturn, which acccording to Wikipedia, ended in June 2009 (by economic measures). This graph also shows a decrease in the proportion of delinquencies after 2008.
Pearson's product-moment correlation
data: ListingCreationYear and DelinquentNum
t = -126.88, df = 113910, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.3569634 -0.3467873
sample estimates:
cor
-0.3518858
ListingCreationDate - Univariate
[1] "2006-01-06"
[1] "2014-03-10"
[1] "2008-10-16"
[1] "2009-04-28"
[1] "2009-07-13"
2005 has been excluded from this data-set because of the small quantity of loans; analysis will cover 2006/01/06 through 2014/03/10. Almost no lending occurred from 2008/10/16 through 2009/07/13 because the U.S. Securities and Exchange Commision required peer-to-peer companies to undergo the arduous process of registering their offerings as securities Wikipedia.
Income
IncomeRange (original factors) by EmploymentStatus - Bivariate
CalcYearlyIncome by IncomeRange (original factors) - Bivariate
Income Range (old) by Employment Status shows EmploymentStatus of Not Employed primarily overlaps with IncomeRange_old Not employed. However, CalcYearlyIncome by IncomeRange_old shows IncomeRange_old Not employed and Not displayed are composed of many incomes when cross referenced by CalcYearlyIncome (\(StatedMonthlyIncome * 12\)). Not displayed is only shown for 2006 and 2007. From 2007 - 2009, Not employed doesn’t necessarily mean $0 income. From 2010 - 2013 there is still a range of Not employed, but as the boxplot shows, Not Employed = $0 income. As such, EmployementStatus and IncomeRange_old will not be used for further analysis. IncomeRange has been reformatted to provide better resolution, as shown in the table below.
Income Range colored with Delinquency - Univariate
(0,10000] (10000,20000] (20000,30000] (30000,40000] (40000,50000] (50000,60000] (60000,70000] (70000,80000]
1448 3377 11189 15242 12576 18533 11052 7875
(80000,90000] (90000,100000] (100000,200000] (200000,21000036]
9070 5661 14282 2215
Note the significant delinquencies immediately preceeding and during the economic downturn and the reduction in the number of loans for 2009 and 2010.
Income Range colored with Income Verifiable - Univariate
Most incomes after 2007, are verifiable.
Calculated Yearly Income with Delinquency - Univariate
[1] 2006
cor
-0.08971717
[1] 2007
cor
-0.03187157
[1] 2008
cor
-0.03178269
[1] 2009
cor
-0.047712
[1] 2010
cor
-0.08174338
[1] 2011
cor
-0.06460819
[1] 2012
cor
-0.03531746
[1] 2013
cor
-0.02890103
[1] 2014
cor
-0.005390592
Income is not correlated to delinquencies. In general, delinquency count follows income count. The y-axis scale is maintained as static to more easily observe the difference in the number of loans per year.
Proportion Delinquent
Proportion Delinquent by Income Range - Bivariate
Pearson's product-moment correlation
data: prop_del and as.numeric(IncomeRange)
t = -9.0583, df = 10, p-value = 3.904e-06
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.9845578 -0.8080484
sample estimates:
cor
-0.9441224
Proportion Delinquent by Income Range - Bivariate, supported by the calculated correlation of -0.944, demonstrates a negative relationship between income range and the proportion of delinquencies. As IncomeRange increases, ProportionDelinquent decreases.
Proportion Delinquent by Year
Proportion Delinquent by Income Range colored by Year - Multivariate
The relationship between Proportion Delinquent and the grouping of the years could be attributable to the loan term length. The majority of loans have a term length of 3 years and some extend to 5 years. Explicit data for the full loan term only exists for loans originating from 2006 until 2009. A mostly complete set of data existis for loans originiating to 2011. A concluding comparison between loans created from 2012 with those created prior to 2012 is not feasable with the available data. Additionally, Prosper introduced new methods for assessing risk (ProsperScore), which subsequently helped to reduce the number of delinquent accounts.
Retrun to Final Plots & Summary
Debt to Income Ratio
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
0.000 0.140 0.220 0.276 0.320 10.010 8554
Debt to Income Ratio colored by Delinquent - Univariate
The DebtToIncomeRatio range has been limited to a maximum of 1 in the visualization. The actual range extends to 10, causing positive skewing.
Revolving Credit Balance
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
0 3121 8549 17599 19521 1435667 7581
RevolvingCreditBalance colored by Delinqent - Univariate
A \(Log_{10}\) scaling of the x-axis produces a normal distribution of Revolving Credit Balance, otherwise positively skewed becasue of large valued outliers.
RevolvingCreditBalance by IncomeRange - Bivariate
Pearson's product-moment correlation
data: as.numeric(IncomeRange) and RevolvingCreditBalance
t = 103.67, df = 104980, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.2992509 0.3102254
sample estimates:
cor
0.3047483
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
0 493 2416 8864 8105 248115 291
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
0 11838 34205 72937 79185 1435667 145
From the lowest to highest IncomeRange, we can see an increase in median RevolvingCreditBalance from $2,416 to $34,205. The summary shows, in the case of the RevolvingCreditBalance for lowest and highest IncomeRange, a positive skew because the mean is significantly greater than the median.
Loan Term
12 36 60
1614 87755 24545
Loan Term colored by Delinquency - Univariate
ListingCreationYear colored by Term - Univariate
Most loans are for 36 months, as such, most delinquencies occured on 36 month loans.
ProsperScore (Risk)
1 2 3 4 5 6 7 8 9 10 11
992 5766 7642 12595 9813 12278 10597 12053 6911 4750 1456
ProsperScore (Risk) with Delinquency - Univariate
Pearson's product-moment correlation
data: ProsperScore..numeric. and DelinquentNum
t = -24.981, df = 84851, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.09212228 -0.07876361
sample estimates:
cor
-0.08544678
There’s no noticible correlation between prosper risk score (11 is the best score) and delinquency. The distribution changes from negatively skewed to normalishly skewed after 2012. The largest number of borrowers are assigned a risk score of 4 after 2012 and there is a significant reduction in delinquent accounts.
Delinquencies by State
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.09496 0.12252 0.15242 0.16358 0.17871 0.36634
Delinqencies by State Heat Map - Bivariate
Proportion Delinquent by State Heat Map - Bivariate
Any interesting observations from the number of delinquencies depicted in the first choropleth map are surpassed by the proportion delinquent choropleth map, which gives a better understanding of the deliquency distribution by state. Delinquencies range between 9.5% and 36.6% with a mean of 16.5%.
Retrun to Final Plots & Summary
Listing Category
NA Debt Consol Home Improvement Business Personal Student Auto Other
16942 58308 7433 7189 2395 756 2572 10494
Baby Boat Cosmetic Engagement Green Household Large Purchases Medical/Dental
199 85 91 217 59 1996 876 1522
Motorcycle RV Taxes Vacation Wedding
304 52 885 768 771
ListingCategory colored by Delinquent - Univariate
The quantity of Debt Consolidation loans is so large compared to the other listing categories, that ListingCategory is rendered uninteresting as a metric for analysing the Prosper dataset. NA, Other and Personal are useless for providing any insight other than the borrower didn’t want to divulge the reason for the loan.
Borrower Rate
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.1340 0.1840 0.1928 0.2500 0.4975
Borrower Rate filled by Delinquent Status across Creation Year - Univariate
Borrower Rate count colored by delinquent statues across listing creation year.
Estimated Return by Borrower Rate - Multivariate
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0400 0.1359 0.1875 0.1960 0.2574 0.3600
Pearson's product-moment correlation
data: BorrowerRate and EstimatedReturn
t = 413.73, df = 84851, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.8154276 0.8198876
sample estimates:
cor
0.8176699
As stated in the Prosper Variable Definition spreadsheet, ProsperScore is a custom risk score built using historical Prosper data and is applicable to loans originiating after 2009/07/31. 11 and 1 are the lowest and highest risk respectively. The data show lower risk borrowers have a lower BorrowerRate. Following 2010, there’s a significant reduction in the number of higher risk loans and Estimated Return is greater than 0; note the estimated losses in 2009 and 2010.
Retrun to Final Plots & Summary
Estimated Return by Prosper Score (Risk) - Multivariate
This visualization demonstrates how Prosper has adjusted their process to receive the highest estimated returns from the highest risk borrowers.
[1] 2009
cor
-0.01232269
[1] 2010
cor
-0.1603571
[1] 2011
cor
-0.6098998
[1] 2012
cor
-0.5255901
[1] 2013
cor
-0.701346
[1] 2014
cor
-0.7280618
For the most part, with each year, ProsperScore becomes a better predictor of EstimatedReturn (i.e. the lowest risk borrowers (11) have the lowest EstimatedReturn).
Retrun to Final Plots & Summary
Stated Monthly Income by Estimated Return - Multivariate
Min. 1st Qu. Median Mean 3rd Qu. Max.
0 3200 4667 5607 6817 1750003
Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
-0.183 0.074 0.092 0.096 0.117 0.284 29061
A density plot is useful for dealing with overplotting. There is evidence of change in the method of determining EstimatedReturn. Initially there was a negitive estimated return for the highest risk borrowers, compared to later years with the highest risk customers having the highest estimated return rate. The dotted blue lines represent 1st quartile, median and 3rd quartile overall for the respective axis.
Retrun to Final Plots & Summary
Stated Monthly Income by ProsperScore (Risk) - Multivariate
Pearson's product-moment correlation
data: ProsperScore..numeric. and StatedMonthlyIncome
t = 24.484, df = 84851, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.07707163 0.09043415
sample estimates:
cor
0.08375665
As demonstrated by the visualization, there is no correlation between income and prosper score.
Density plot of DebtToIncomeRatio by StatedMonthlyIncome colored by Delinquent - Multivariate
Min. 1st Qu. Median Mean 3rd Qu. Max.
0 3200 4667 5607 6817 1750003
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000 0.140 0.220 0.276 0.320 10.010
Pearson's product-moment correlation
data: StatedMonthlyIncome and DebtToIncomeRatio
t = -39.632, df = 77555, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.1477838 -0.1339875
sample estimates:
cor
-0.1408925
DebtToIncomeRatio has been limited to a maximum of 1 and StatedMonthlyIncome has been limited to $15000. Except for 2014 the distribution of delinquent and non-delinqent accounts is very similar. The dotted blue lines represent 1st quartile, median and 3rd quartile overall for the respective axis. There is some tendency for lower income borrowers to have a higher debt to income ratio.
DebtToIncomeRatio by ListingCreationYear - Multivariate
Again Debt to Income Ratio is limited to 1. Except for the two lowest income ranges, across all years the median Debt to Income Ratio is below 0.25 and gets lower the greater the income range.
ProsperRating by ProsperScore - Multivariate
[1] 2009
cor
-0.8652869
[1] 2010
cor
-0.9212265
[1] 2011
cor
-0.8788855
[1] 2012
cor
-0.8079254
[1] 2013
cor
-0.7896682
[1] 2014
cor
-0.7526703
The Prosper variable definitions state, ProsperScore is a risk score. ProsperRating is an estimation of the borrower’s estimated loss rate and is determined by (1) credit score and (2) Prosper Score. Prosper Ratings, from lowest-risk to highest-risk, are labeled AA, A, B, C, D, E, and HR (“High Risk”). There is a strong negative correlation for each year. Prosper may use a slightly different method for combining ProsperScore & CreditScroreRangeLower.
AA |
0.00-1.99% |
A |
2.00-3.99% |
B |
4.00-5.99% |
C |
6.00-8.99% |
D |
9.00-11.99% |
E |
12.00-14.99% |
HR |
15.00%+ |
Retrun to Final Plots & Summary
Linear Model to Predict Prosper Score
This is more a demonstration of the difficulties of using a linear model to predict an outcome when there is a large number of variables to consider.
Call:
lm(formula = ProsperScore..numeric. ~ TotalInquiries + CurrentDelinquencies +
TradesOpenedLast6Months + BankcardUtilization + DebtToIncomeRatio +
exp(Ratio_PL_Pay_OT), data = subset(prosper, !is.na(ProsperScore..numeric.) &
ListingCreationDate <= "2011-04-30" & ListingCreationDate >=
"2008-04-01"))
Residuals:
Min 1Q Median 3Q Max
-6.822 -1.150 0.266 1.258 8.284
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.18459 0.04980 184.441 < 2e-16 ***
TotalInquiries -0.08443 0.00414 -20.391 < 2e-16 ***
CurrentDelinquencies -0.38781 0.01613 -24.044 < 2e-16 ***
TradesOpenedLast6Months -0.43137 0.01939 -22.251 < 2e-16 ***
BankcardUtilization -1.41114 0.05384 -26.210 < 2e-16 ***
DebtToIncomeRatio -0.73725 0.06224 -11.845 < 2e-16 ***
exp(Ratio_PL_Pay_OT) -0.11566 0.02254 -5.132 2.92e-07 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 1.711 on 9373 degrees of freedom
(1135 observations deleted due to missingness)
Multiple R-squared: 0.2248, Adjusted R-squared: 0.2243
F-statistic: 453.1 on 6 and 9373 DF, p-value: < 2.2e-16
Calls:
lmodel: lm(formula = ProsperScore..numeric. ~ TotalInquiries + CurrentDelinquencies +
TradesOpenedLast6Months + BankcardUtilization + DebtToIncomeRatio +
exp(Ratio_PL_Pay_OT), data = subset(prosper, !is.na(ProsperScore..numeric.) &
ListingCreationDate <= "2011-04-30" & ListingCreationDate >=
"2008-04-01"))
==========================================
(Intercept) 9.185***
(0.050)
TotalInquiries -0.084***
(0.004)
CurrentDelinquencies -0.388***
(0.016)
TradesOpenedLast6Months -0.431***
(0.019)
BankcardUtilization -1.411***
(0.054)
DebtToIncomeRatio -0.737***
(0.062)
exp(Ratio_PL_Pay_OT) -0.116***
(0.023)
------------------------------------------
R-squared 0.225
adj. R-squared 0.224
sigma 1.711
F 453.122
p 0.000
Log-likelihood -18341.688
Deviance 27426.518
AIC 36699.376
BIC 36756.547
N 9380
==========================================
fit lwr upr
1 6.570083 3.2164 9.923766
fit lwr upr
1 7.764011 4.410197 11.11783
fit lwr upr
1 1.237484 -2.14071 4.615678
The expected result(s) are 6, 10, and 3 compared to those received (6.6, 7.76 and 1.24). We can see the predictive power of the model requires refinement. Perhaps it could be improved by adding more variables to the model or variable transformation (i.e. \(Log_{10}(var)\), \(\sqrt[3]{var}\), etc). More likely, this is an instance where success can be gained by applying machine learning methodologies. The variables chosen and the ListingCreationDate used, came from Prosper Score.
Final Plots & Summary
Plot 1
Code Plot 1
The relationship between Proportion Delinquent and the grouping of the years could be attributable to the loan term length. The majority of loans have a term length of 3 years and some extend to 5 years. Explicit data for the full loan term only exists for loans originating from 2006 until 2009. A mostly complete set of data existis for loans originiating to 2011. A concluding comparison between loans created from 2012 with those created prior to 2012 is not feasable with the available data. Additionally, Prosper introduced new methods for assessing risk (ProsperScore), which subsequently helped to reduce the number of delinquent accounts.
Plot 2
Code Plot 2
[1] 2009
cor
0.6435063
[1] 2010
cor
0.6483637
[1] 2011
cor
0.860636
[1] 2012
cor
0.8054026
[1] 2013
cor
0.9136454
[1] 2014
cor
0.9727477
As stated in the Prosper Variable Definition spreadsheet, ProsperScore is a custom risk score built using historical Prosper data and is applicable to loans originiating after 2009/07/31. 11 and 1 are the lowest and highest risk respectively. The data show lower risk borrowers have a lower BorrowerRate. Following 2010, there’s a significant reduction in the number of higher risk loans and Estimated Return is greater than 0; note the estimated losses in 2009 and 2010. Borrower Rate is an increasingly strong predictor of Estimated Return.
Plot 3
Code Plot 3
[1] 2009
cor
-0.8652869
[1] 2010
cor
-0.9212265
[1] 2011
cor
-0.8788855
[1] 2012
cor
-0.8079254
[1] 2013
cor
-0.7896682
[1] 2014
cor
-0.7526703
ProsperScore is a risk score from 1 (highest risk) to 11 (lowest risk). ProsperRating is an estimation of the borrower’s estimated loss rate and is determined by (1) credit score and (2) Prosper Score. Prosper Ratings, from lowest-risk to highest-risk, are labeled AA, A, B, C, D, E, and HR (“High Risk”). There is a strong negative correlation for each year. Prosper may use a slightly different method for combining ProsperScore & CreditScroreRangeLower.
AA |
0.00-1.99% |
A |
2.00-3.99% |
B |
4.00-5.99% |
C |
6.00-8.99% |
D |
9.00-11.99% |
E |
12.00-14.99% |
HR |
15.00%+ |
Reflection
The initial direction of the investigation was an attempt to ascertain which metrics were most attributable to delinquency. It quickly became apparent that yearly changes made for more interesting observations. An important observation was that univariate visualizations offered very little categorical insight until facet wrapped by listing creation year. The data set begins with the inception of Prosper and spans several tumultuous years for financial markets in general, and for Prospers’ business model. Except Plot 2, the final visualizations demonstrate significant year-over-year change. The most significant change, seems to be the method by which Prosper evaluates risk, by adding Prosper Score in 2009. Additionally, lack of business, likely attributable to the 2007 recession, is evident, as is the 2008-2009 cessation of lending cause by regulatory changes.
The attempt to model the Prosper Score with this Linear Model was unsuccessful. My approach was to introduce transformations to the independent variables in hopes of creating a stronger delineation between each factor of Prosper Score. Specifically, \(f(x) = e^x\) was used to mitigate the introduction of a 0 factor into the model. Perhaps it will be an instructive endevour to apply machine learning to this data-set following that class.
As stated previously, I struggled and was ultimatly unsuccessful in accuratly modeling the Prosper Score.
I enjoyed a modicum of success with the strong correclation shown between Prosper Rating and the combined metric of Prosper Score * Credit Score.
LS0tDQp0aXRsZTogIlVEQUNJVFkgUiBEYXRhIEFuYWx5c2lzIFByb2plY3QgLSBQcm9zcGVyIFBlZXIgdG8gUGVlciBMZW5kaW5nIERhdGEtc2V0IEV4cGxvcmF0aW9uIg0KYXV0aG9yOiAiVHJlbnRvbiBKLiBNY0tpbm5leSINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHRydWUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0aGVtZTogImNlcnVsZWFuIg0KICAgIGZpZ193aWR0aDogMTANCi0tLQ0KKioqDQojIyBJbnRyb2R1Y3Rpb24NCioqQWJvdXQgUHJvc3BlcioqDQoNCkZyb20gdGhlIFtQcm9zcGVyXShodHRwczovL3d3dy5wcm9zcGVyLmNvbS8pIHdlYnNpdGUuICBQcm9zcGVyIGlzIEFtZXJpY2EncyBmaXJzdCBbbWFya2V0cGxhY2UgbGVuZGluZyBwbGF0Zm9ybV0oaHR0cHM6Ly93d3cucHJvc3Blci5jb20vcGxwL2hvdy1pdC13b3JrcyksIHdpdGggb3ZlciAkMTAgYmlsbGlvbiBpbiBmdW5kZWQgbG9hbnMuDQoNClByb3NwZXIgYWxsb3dzIHBlb3BsZSB0byBpbnZlc3QgaW4gZWFjaCBvdGhlciBpbiBhIHdheSB0aGF0IGlzIGZpbmFuY2lhbGx5IGFuZCBzb2NpYWxseSByZXdhcmRpbmcuIE9uIFByb3NwZXIsIGJvcnJvd2VycyBsaXN0IGxvYW4gcmVxdWVzdHMgYmV0d2VlbiBcJDIsMDAwIGFuZCBcJDM1LDAwMCBhbmQgaW5kaXZpZHVhbCBpbnZlc3RvcnMgaW52ZXN0IGFzIGxpdHRsZSBhcyBcJDI1IGluIGVhY2ggbG9hbiBsaXN0aW5nIHRoZXkgc2VsZWN0LiBQcm9zcGVyIGhhbmRsZXMgdGhlIHNlcnZpY2luZyBvZiB0aGUgbG9hbiBvbiBiZWhhbGYgb2YgdGhlIG1hdGNoZWQgYm9ycm93ZXJzIGFuZCBpbnZlc3RvcnMuDQoNCioqT3ZlcnZpZXcqKg0KDQpGcm9tIFVkYWNpdHk6DQoNCipUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIDExMyw5MzcgbG9hbnMgd2l0aCA4MSB2YXJpYWJsZXMgb24gZWFjaCBsb2FuLCBpbmNsdWRpbmcgbG9hbiBhbW91bnQsIGJvcnJvd2VyIHJhdGUgKG9yIGludGVyZXN0IHJhdGUpLCBjdXJyZW50IGxvYW4gc3RhdHVzLCBib3Jyb3dlciBpbmNvbWUsIGJvcnJvd2VyIGVtcGxveW1lbnQgc3RhdHVzLCBib3Jyb3dlciBjcmVkaXQgaGlzdG9yeSwgYW5kIHRoZSBsYXRlc3QgcGF5bWVudCBpbmZvcm1hdGlvbi4qDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KHRpYmJsZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGx5cikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkobWVtaXNjKQ0KbGlicmFyeShyZXNoYXBlMikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShhbHIzKQ0KbGlicmFyeShyaW8pDQpsaWJyYXJ5KEdHYWxseSkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkobWFwcykNCmxpYnJhcnkoZmlmdHlzdGF0ZXIpDQpgYGANCg0KKioqDQojIyBTZXR1cCAmIEdlbmVyYWwNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KcHJvc3BlciA8LSByZWFkLmNzdignLi4vUHJvamVjdC9EYXRhL3Byb3NwZXJMb2FuRGF0YS5jc3YnKQ0KYGBgDQoNCiMjIyBTZWxlY3QgQ2F0ZWdvcmllcyBvZiBJbnRlcmVzdA0KVGhlIGRhdGFmcmFtZSBoYXMgYmVlbiByZWR1Y2VkIGZyb20gODEgdG8gMjIgY2F0ZWdvcmllcyB0aGF0IG1heSBiZSBldmFsdWF0ZWQgYXMgcGFyYW1ldGVycyBvZiBpbnRlcmVzdCB3aXRoaW4gdGhlIHNjb3BlIG9mIHRoZSBkYXRhLXNldCBvcHRpb25zLg0KYGBge3J9DQpwcm9zcGVyIDwtIHByb3NwZXJbYygzLCA1LCA2LCA5LCAxMywgMTU6MTgsIDIwLCAyNiwgMzU6MzYsIDQxOjQyLCA0Njo1MCwgNTM6NTQpXQ0KYGBgDQoNCmBgYHtyfQ0KY29sbmFtZXMocHJvc3BlcikNCmBgYA0KDQojIyBEYXRhIFRyYW5zZm9ybWF0aW9ucw0KIyMjIGFzLmZhY3Rvcg0KYGBge3J9DQpwcm9zcGVyJFByb3NwZXJTY29yZSA8LSBhcy5mYWN0b3IocHJvc3BlciRQcm9zcGVyU2NvcmUpDQpwcm9zcGVyJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4gPC0gYXMuZmFjdG9yKHByb3NwZXIkTGlzdGluZ0NhdGVnb3J5Li5udW1lcmljLikNCnByb3NwZXIkVGVybSA8LSBhcy5mYWN0b3IocHJvc3BlciRUZXJtKQ0KcHJvc3BlciRQcm9zcGVyUmF0aW5nLi5BbHBoYS4gPC0gZmFjdG9yKHByb3NwZXIkUHJvc3BlclJhdGluZy4uQWxwaGEuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoJ0FBJywgJ0EnLCAnQicsICdDJywgJ0QnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0UnLCAnSFInKSwgb3JkZXJlZCA9IFRSVUUpDQpgYGANCg0KIyMjIENhbGN1bGF0ZWQgWWVhcmx5IEluY29tZQ0KYGBge3J9DQpwcm9zcGVyJENhbGNZZWFybHlJbmNvbWUgPC0gcHJvc3BlciRTdGF0ZWRNb250aGx5SW5jb21lICogMTINCmBgYA0KDQojIyMgUmVmb3JtYXQgSW5jb21lIFJhbmdlDQpDcmVhdGUgYSBtb3JlIHJlZmluZWQgdmlldyBvZiBpbmNvbWUgcmFuZ2UgYmFzZWQgdXBvbiBTdGF0ZWRNb25seUluY29tZSAqIDEyDQpgYGB7cn0NCnByb3NwZXIkSW5jb21lUmFuZ2Vfb2xkIDwtIHByb3NwZXIkSW5jb21lUmFuZ2UNCnByb3NwZXIkSW5jb21lUmFuZ2UgPC0gY3V0KHByb3NwZXIkQ2FsY1llYXJseUluY29tZSwgZGlnLmxhYiA9IDEwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygwLCAxMDAwMCwgMjAwMDAsIDMwMDAwLCA0MDAwMCwgNTAwMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDYwMDAwLCA3MDAwMCwgODAwMDAsIDkwMDAwLCAxMDAwMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDIwMDAwMCwgMjEwMDAwMzYuKSkNCmBgYA0KDQojIyMgUmVmb3JtYXQgRGF0ZSBjYXRlZ29yaWVzIGFzLkRhdGUNCmBgYHtyfQ0KcHJvc3BlciRMaXN0aW5nQ3JlYXRpb25EYXRlIDwtIGFzLkRhdGUocHJvc3BlciRMaXN0aW5nQ3JlYXRpb25EYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0ID0gJyVZLSVtLSVkJykNCnByb3NwZXIkTGlzdGluZ0NyZWF0aW9uWWVhciA8LSB5ZWFyKHByb3NwZXIkTGlzdGluZ0NyZWF0aW9uRGF0ZSkNCmBgYA0KDQojIyMgUmVtb3ZlIDIwMDUNClRoZXJlIGFyZSB2ZXJ5IGZldyBsb2FucyBpbiAyMDA1DQpgYGB7cn0NCnByb3NwZXIgPC0gc3Vic2V0KHByb3NwZXIsIExpc3RpbmdDcmVhdGlvblllYXIgIT0gMjAwNSkNCmBgYA0KDQojIyMgQ3JlYXRlIGEgbmV3IERlbGlucXVlbnQgY2F0ZWdvcnkgYmFzZWQgdXBvbiBMb2FuU3RhdHVzDQpgYGB7cn0NCiMgVXNlZCBmb3IgZmlsbGluZyBoaXN0b2dyYW1zDQpwcm9zcGVyJERlbGlucXVlbnQgPC0gaWZlbHNlKA0KICBwcm9zcGVyJExvYW5TdGF0dXMgPT0gJ0NvbXBsZXRlZCcgfA0KICBwcm9zcGVyJExvYW5TdGF0dXMgPT0gJ0N1cnJlbnQnIHwNCiAgcHJvc3BlciRMb2FuU3RhdHVzID09ICdGaW5hbFBheW1lbnRJblByb2dyZXNzJywNCiAgJ0ZhbHNlJywgJ1RydWUnKQ0KDQpwcm9zcGVyJERlbGlucXVlbnQgPC0gZmFjdG9yKHByb3NwZXIkRGVsaW5xdWVudCkNCmBgYA0KDQpgYGB7cn0NCiMgVXNlZCBpbiBjYWxjdWxhdGluZyBjb3JyZWxhdGlvbnMNCnByb3NwZXIkRGVsaW5xdWVudE51bSA8LSBhcy5udW1lcmljKHByb3NwZXIkRGVsaW5xdWVudCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoJ0ZhbHNlJywgJ1RydWUnKSkNCmBgYA0KDQojIyMgUmVwbGFjZSBEQyB3aXRoIE1EDQpEQyBpcyBub3QgYSBzdGF0ZQ0KYGBge3J9DQpwcm9zcGVyJEJvcnJvd2VyU3RhdGVbcHJvc3BlciRCb3Jyb3dlclN0YXRlID09ICdEQyddIDwtICdNRCcNCmBgYA0KDQojIyMgYXMubnVtZXJpYw0KYGBge3J9DQpwcm9zcGVyJFByb3NwZXJTY29yZS4ubnVtZXJpYy4gPC0gYXMubnVtZXJpYyhwcm9zcGVyJFByb3NwZXJTY29yZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSwgNiwgNywgOCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOSwgMTAsIDExKSkNCmBgYA0KDQojIyMgQ3JlYXRlIExpc3RpbmdDYXRlZ29yeSBmcm9tIExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4uDQpgYGB7cn0NCmNhdGVnb3JpZXMgPSBjKCdOQScsICdEZWJ0IENvbnNvbCcsICdIb21lIEltcHJvdmVtZW50JywgJ0J1c2luZXNzJywgJ1BlcnNvbmFsJywNCiAgICAgICAgICAgICAgICdTdHVkZW50JywgJ0F1dG8nLCAnT3RoZXInLCAnQmFieScsICdCb2F0JywgJ0Nvc21ldGljJywNCiAgICAgICAgICAgICAgICdFbmdhZ2VtZW50JywgJ0dyZWVuJywgJ0hvdXNlaG9sZCcsICdMYXJnZSBQdXJjaGFzZXMnLA0KICAgICAgICAgICAgICAgJ01lZGljYWwvRGVudGFsJywgJ01vdG9yY3ljbGUnLCAnUlYnLCAnVGF4ZXMnLCAnVmFjYXRpb24nLA0KICAgICAgICAgICAgICAgJ1dlZGRpbmcnKQ0KDQpwcm9zcGVyJExpc3RpbmdDYXRlZ29yeSA8LSBwcm9zcGVyJExpc3RpbmdDYXRlZ29yeS4ubnVtZXJpYy4NCmxldmVscyhwcm9zcGVyJExpc3RpbmdDYXRlZ29yeSkgPC0gY2F0ZWdvcmllcw0KYGBgDQoNCiMjIyBDcmVhdGUgUmF0aW9fUExfUGF5X09UIC0gUmF0aW8gb2YgUHJvc3BlciBMb2FuIFBheW1lbnRzIFBhaWQgT24gVGltZQ0KYGBge3J9DQojIFVzZWQgZm9yIGxpbmVhciBtb2RlbA0KcHJvc3BlciRSYXRpb19QTF9QYXlfT1QgPC0gcHJvc3BlciRPblRpbWVQcm9zcGVyUGF5bWVudHMvDQogIHByb3NwZXIkVG90YWxQcm9zcGVyUGF5bWVudHNCaWxsZWQNCnByb3NwZXIkUmF0aW9fUExfUGF5X09UW2lzLm5hKHByb3NwZXIkUmF0aW9fUExfUGF5X09UKV0gPC0gMA0KYGBgDQoNCg0KIyMjIEhlYWQNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KaGVhZChwcm9zcGVyKQ0KYGBgDQoNCioqKg0KIyMgSW5xdWlyeQ0KIyMjIENvcnJlbGF0aW9uIE1hdHJpeA0KYGBge3IsIGZpZy53aWR0aD05LCByZXN1bHRzPSdoaWRlJywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0NCmdnY29ycihwcm9zcGVyLCBsYWJlbCA9IFRSVUUsIGxhYmVsX3NpemUgPSAyLA0KICAgICAgIGhqdXN0ID0gMC44LCBzaXplID0gMiwgY29sb3IgPSAiYmxhY2siLCBsYXlvdXQuZXhwID0gMikgKw0KICBnZ3RpdGxlKCdQcm9zcGVyIENvcnJlbGF0aW9uIE1hdHJpeCcpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCkdlbmVyYXRlZCB0byBwcm92aWRlIGEgaGlnaCBsZXZlbCB2aWV3IG9mIHBvc3NpYmx5IGludGVycmVsYXRlZCBtZXRyaWNzLg0KDQoqKioNCiMjIyBMaXN0aW5nIENyZWF0aW9uIERhdGUNCiMjIyMgTGlzdGluZ0NyZWF0aW9uWWVhciBjb2xvcmVkIGJ5IExvYW5TdGF0dXMgJiBEZWxpbnF1ZW50IC0gVW5pdmFyaWF0ZQ0KYGBge3IsIGVjaG89RkFMU0V9DQpnZ3Bsb3QocHJvc3BlciwgYWVzKHggPSBhcy5mYWN0b3IoTGlzdGluZ0NyZWF0aW9uWWVhciksDQogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBpbnRlcmFjdGlvbihMb2FuU3RhdHVzLCBEZWxpbnF1ZW50KSkpICsNCiAgZ2VvbV9iYXIoY29sb3IgPSAnYmxhY2snKSArDQogIHhsYWIoJ0xpc3RpbmcgQ3JlYXRpb24gWWVhcicpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2d0aXRsZSgnTGlzdGluZyBDcmVhdGlvbiBZZWFyIC1cbkludGVyYWN0aW9uIG9mIExvYW4gU3RhdHVzIGFuZCBEZWxpbnF1ZW50JykNCmBgYA0KRm9yIHRoZSBwdXJwb3NlIG9mIHRoaXMgYW5hbHlzaXMsIGFsbCBjYXRlZ29yaWVzIG9mIExvYW5TdGF0dXMgZXhjZXB0IENvbXBsZXRlZCwgQ3VycmVudCAmIEZpbmFsUGF5bWVudEluUHJvZ3Jlc3MgYXJlIFRydWUgaW4gdGhlIERlbGlucXVlbnQgY2F0ZWdvcnkuDQoNCiMjIyMgTGlzdGluZyBDcmVhdGlvbiBZZWFyIHdpdGggRGVsaW5xdWVuY3kNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KdGFibGUocHJvc3BlciRMaXN0aW5nQ3JlYXRpb25ZZWFyKQ0KYGBgDQoNCiMjIyMgTGlzdGluZ0NyZWF0aW9uWWVhciBjb2xvcmVkIGJ5IERlbGlucXVlbnQgLSBVbml2YXJpYXRlDQpgYGB7ciwgZWNobz1GQUxTRX0NCmdncGxvdChkYXRhID0gcHJvc3BlciwgYWVzKHggPSBMaXN0aW5nQ3JlYXRpb25ZZWFyLCBmaWxsID0gRGVsaW5xdWVudCkpICsNCiAgZ2VvbV9iYXIoKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9Li5jb3VudC4uKSwgc3RhdD0iY291bnQiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKCkpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJBY2NlbnQiKSArDQogIHhsYWIoJ0xpc3RpbmcgQ3JlYXRpb24gWWVhcicpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgyMDA2LCAyMDE0LCAxKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAzNjAwMCksIGJyZWFrcyA9IHNlcSgwLCAzNjAwMCwgMjAwMCkpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2d0aXRsZSgnTGlzdGluZyBDcmVhdGlvbiBZZWFyIC0gRGVsaW5xdWVudCcpDQpgYGANCkEgdmlldyBvZiB0aGUgYWJzb2x1dGUgbnVtYmVyIG9mIGxvYW5zIGFuZCBkZWxpbnF1ZW5jaWVzLiAgQXMgd2lsbCBob2xkIHRydWUgZm9yIGFsbCBmdXJ0aGVyIGRpc2N1c3Npb25zLCBkZWxpbnF1ZW5jaWVzIGlzIGEgcmVmbGVjdGlvbiBvZiB0aGUgbG9hbiBzdGF0dXMgdGhyb3VnaCAyMDE0LiAgVGhlIGxvYW4gdGVybXMgYXJlIGZvciAxLCAzIGFuZCA1IHllYXJzLCBzbyB0aGUgZmluYWwgY2xvc2VkIHN0YXR1cyBjYW4gb25seSBiZSBkZXRlcm1pbmVkIGZvciBtb3N0IGxvYW5zIHRocm91Z2ggMjAxMSAoaS5lLiBtb3N0IGxvYW4gdGVybXMgYXJlIDMgeWVhcnMpLiAgTm90ZSB0aGUgaW5jcmVhc2luZyBudW1iZXIgb2YgbG9hbnMgZm9sbG93aW5nIHRoZSAyMDA3IGRvd250dXJuLCB3aGljaCBhY2Njb3JkaW5nIHRvIFtXaWtpcGVkaWFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dyZWF0X1JlY2Vzc2lvbiksIGVuZGVkIGluIEp1bmUgMjAwOSAoYnkgZWNvbm9taWMgbWVhc3VyZXMpLiAgVGhpcyBncmFwaCBhbHNvIHNob3dzIGEgZGVjcmVhc2UgaW4gdGhlIHByb3BvcnRpb24gb2YgZGVsaW5xdWVuY2llcyBhZnRlciAyMDA4Lg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCndpdGgocHJvc3BlciwgY29yLnRlc3QoTGlzdGluZ0NyZWF0aW9uWWVhciwgRGVsaW5xdWVudE51bSwgbWV0aG9kID0gJ3BlYXJzb24nKSkNCmBgYA0KDQojIyMjIExpc3RpbmdDcmVhdGlvbkRhdGUgLSBVbml2YXJpYXRlDQpgYGB7ciwgZWNobz1GQUxTRX0NCmdncGxvdChwcm9zcGVyLCBhZXMoeCA9IExpc3RpbmdDcmVhdGlvbkRhdGUpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9ICdwdXJwbGUnKSArDQogIHNjYWxlX3hfZGF0ZShkYXRlX2JyZWFrcyA9ICc0IG1vbnRoJykgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBnZ3RpdGxlKCdMaXN0aW5nIENyZWF0aW9uIERhdGUgSGlzdG9ncmFtJykNCiAgDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQojIGRldGVybWluZSBiZWdpbm5pbmcgYW5kIGVuZCBkYXRlIG9mIGRhdGEtc2V0DQptaW4ocHJvc3BlciRMaXN0aW5nQ3JlYXRpb25EYXRlKQ0KbWF4KHByb3NwZXIkTGlzdGluZ0NyZWF0aW9uRGF0ZSkNCg0KIyBkZXRlcm1pbmUgYnJlYWsgcmFuZ2UNCm1heChzdWJzZXQocHJvc3BlciRMaXN0aW5nQ3JlYXRpb25EYXRlLCBwcm9zcGVyJExpc3RpbmdDcmVhdGlvblllYXIgPT0gMjAwOCkpDQptaW4oc3Vic2V0KHByb3NwZXIkTGlzdGluZ0NyZWF0aW9uRGF0ZSwgcHJvc3BlciRMaXN0aW5nQ3JlYXRpb25ZZWFyID09IDIwMDkpKQ0KDQptaW4oc3Vic2V0KHByb3NwZXIkTGlzdGluZ0NyZWF0aW9uRGF0ZSwNCiAgICAgICAgICAgcHJvc3BlciRMaXN0aW5nQ3JlYXRpb25EYXRlID49ICcyMDA5LTA1LTE1JykpDQpgYGANCjIwMDUgaGFzIGJlZW4gZXhjbHVkZWQgZnJvbSB0aGlzIGRhdGEtc2V0IGJlY2F1c2Ugb2YgdGhlIHNtYWxsIHF1YW50aXR5IG9mIGxvYW5zOyBhbmFseXNpcyB3aWxsIGNvdmVyIDIwMDYvMDEvMDYgdGhyb3VnaCAyMDE0LzAzLzEwLiAgQWxtb3N0IG5vIGxlbmRpbmcgb2NjdXJyZWQgZnJvbSAyMDA4LzEwLzE2IHRocm91Z2ggMjAwOS8wNy8xMyBiZWNhdXNlIHRoZSBVLlMuIFNlY3VyaXRpZXMgYW5kIEV4Y2hhbmdlIENvbW1pc2lvbiByZXF1aXJlZCBwZWVyLXRvLXBlZXIgY29tcGFuaWVzIHRvIHVuZGVyZ28gdGhlIGFyZHVvdXMgcHJvY2VzcyBvZiByZWdpc3RlcmluZyB0aGVpciBvZmZlcmluZ3MgYXMgc2VjdXJpdGllcyBbV2lraXBlZGlhXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9QZWVyLXRvLXBlZXJfbGVuZGluZyNVbml0ZWRfU3RhdGVzKS4NCg0KKioqDQojIyMgSW5jb21lDQojIyMjIDxhIGlkPSJpci1vbGRfZXMiPjwvYT5JbmNvbWVSYW5nZSAob3JpZ2luYWwgZmFjdG9ycykgYnkgRW1wbG95bWVudFN0YXR1cyAtIEJpdmFyaWF0ZQ0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMCwgZWNobz1GQUxTRX0NCmdncGxvdChkYXRhID0gcHJvc3BlciwgYWVzKHggPSBFbXBsb3ltZW50U3RhdHVzLCB5ID0gSW5jb21lUmFuZ2Vfb2xkKSkgKw0KICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBJbmNvbWVSYW5nZV9vbGQpLCBjb2xvciA9ICdibGFjaycpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGZhY2V0X3dyYXAofkxpc3RpbmdDcmVhdGlvblllYXIpICsNCiAgZ2d0aXRsZSgnSW5jb21lIFJhbmdlIGJ5IEVtcGxveW1lbnQgU3RhdHVzIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyJykNCmBgYA0KDQojIyMjIDxhIGlkPSJjeWlfaXItb2xkIj48L2E+Q2FsY1llYXJseUluY29tZSBieSBJbmNvbWVSYW5nZSAob3JpZ2luYWwgZmFjdG9ycykgLSBCaXZhcmlhdGUNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHByb3NwZXIsIGFlcyh4ID0gSW5jb21lUmFuZ2Vfb2xkLCB5ID0gQ2FsY1llYXJseUluY29tZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gSW5jb21lUmFuZ2Vfb2xkKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAnc2VxJykgKw0KICBzY2FsZV95X2xvZzEwKGxhYmVscyA9IGRvbGxhcikgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBmYWNldF93cmFwKH5MaXN0aW5nQ3JlYXRpb25ZZWFyLCBzY2FsZXMgPSAnZnJlZV95JykgKw0KICB4bGFiKCdJbmNvbWUgUmFuZ2UgKG9yaWdpbmFsIGZhY3RvcnMpJykgKw0KICBnZ3RpdGxlKCdDYWxjdWxhdGVkIFllYXJseSBJbmNvbWUgYnkgSW5jb21lIFJhbmdlIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyJykNCmBgYA0KW0luY29tZSBSYW5nZSAob2xkKSBieSBFbXBsb3ltZW50IFN0YXR1c10oI2lyLW9sZF9lcykgc2hvd3MgRW1wbG95bWVudFN0YXR1cyBvZiBOb3QgRW1wbG95ZWQgcHJpbWFyaWx5IG92ZXJsYXBzIHdpdGggSW5jb21lUmFuZ2Vfb2xkIE5vdCBlbXBsb3llZC4gIEhvd2V2ZXIsIFtDYWxjWWVhcmx5SW5jb21lIGJ5IEluY29tZVJhbmdlX29sZF0oI2N5aV9pci1vbGQpIHNob3dzIEluY29tZVJhbmdlX29sZCBOb3QgZW1wbG95ZWQgYW5kIE5vdCBkaXNwbGF5ZWQgYXJlIGNvbXBvc2VkIG9mIG1hbnkgaW5jb21lcyB3aGVuIGNyb3NzIHJlZmVyZW5jZWQgYnkgQ2FsY1llYXJseUluY29tZSAoJFN0YXRlZE1vbnRobHlJbmNvbWUgKiAxMiQpLiAgTm90IGRpc3BsYXllZCBpcyBvbmx5IHNob3duIGZvciAyMDA2IGFuZCAyMDA3LiAgRnJvbSAyMDA3IC0gMjAwOSwgTm90IGVtcGxveWVkIGRvZXNuJ3QgbmVjZXNzYXJpbHkgbWVhbiBcJDAgaW5jb21lLiAgRnJvbSAyMDEwIC0gMjAxMyB0aGVyZSBpcyBzdGlsbCBhIHJhbmdlIG9mIE5vdCBlbXBsb3llZCwgYnV0IGFzIHRoZSBib3hwbG90IHNob3dzLCBOb3QgRW1wbG95ZWQgPSBcJDAgaW5jb21lLiAgQXMgc3VjaCwgRW1wbG95ZW1lbnRTdGF0dXMgYW5kIEluY29tZVJhbmdlX29sZCB3aWxsIG5vdCBiZSB1c2VkIGZvciBmdXJ0aGVyIGFuYWx5c2lzLiAgSW5jb21lUmFuZ2UgaGFzIGJlZW4gcmVmb3JtYXR0ZWQgdG8gcHJvdmlkZSBiZXR0ZXIgcmVzb2x1dGlvbiwgYXMgc2hvd24gaW4gdGhlIHRhYmxlIGJlbG93Lg0KDQoNCiMjIyMgSW5jb21lIFJhbmdlIGNvbG9yZWQgd2l0aCBEZWxpbnF1ZW5jeSAtIFVuaXZhcmlhdGUNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KdGFibGUocHJvc3BlciRJbmNvbWVSYW5nZSkNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBlY2hvPUZBTFNFfQ0KZ2dwbG90KGRhdGEgPSBzdWJzZXQocHJvc3BlciwgIWlzLm5hKEluY29tZVJhbmdlKSksIGFlcyhJbmNvbWVSYW5nZSkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBEZWxpbnF1ZW50KSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayhyZXZlcnNlID0gVFJVRSkpICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhcikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkFjY2VudCIpICsNCiAgZ2d0aXRsZSgnSW5jb21lIFJhbmdlIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyICYgRGVsaW5xdWVudCcpDQpgYGANCk5vdGUgdGhlIHNpZ25pZmljYW50IGRlbGlucXVlbmNpZXMgaW1tZWRpYXRlbHkgcHJlY2VlZGluZyBhbmQgZHVyaW5nIHRoZSBlY29ub21pYyBkb3dudHVybiBhbmQgdGhlIHJlZHVjdGlvbiBpbiB0aGUgbnVtYmVyIG9mIGxvYW5zIGZvciAyMDA5IGFuZCAyMDEwLg0KDQojIyMjIEluY29tZSBSYW5nZSBjb2xvcmVkIHdpdGggSW5jb21lIFZlcmlmaWFibGUgLSBVbml2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBlY2hvPUZBTFNFfQ0KZ2dwbG90KGRhdGEgPSBzdWJzZXQocHJvc3BlciwgIWlzLm5hKEluY29tZVJhbmdlKSksIGFlcyhJbmNvbWVSYW5nZSkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBJbmNvbWVWZXJpZmlhYmxlKSkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkFjY2VudCIpICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhciwgc2NhbGVzID0gJ2ZyZWVfeScpICsNCiAgZ2d0aXRsZSgnSW5jb21lIFJhbmdlIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyICYgSW5jb21lIFZlcmlmaWFibGUnKQ0KYGBgDQpNb3N0IGluY29tZXMgYWZ0ZXIgMjAwNywgYXJlIHZlcmlmaWFibGUuDQoNCiMjIyMgQ2FsY3VsYXRlZCBZZWFybHkgSW5jb21lIHdpdGggRGVsaW5xdWVuY3kgLSBVbml2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTksIGVjaG89RkFMU0V9DQpnZ3Bsb3QocHJvc3BlciwgYWVzKENhbGNZZWFybHlJbmNvbWUpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNDAwMCwgYWVzKGZpbGwgPSBEZWxpbnF1ZW50KSwgY29sb3IgPSAnYmxhY2snKSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBkb2xsYXIsIGxpbWl0cyA9IGMoMCwgMjAwMDAwKSwNCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAyMDAwMDAsIDIwMDAwKSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkFjY2VudCIpICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhcikgKw0KICBnZ3RpdGxlKCdDYWxjdWxhdGVkIFllYXJseSBJbmNvbWUgLSBMaXN0aW5nIENyZWF0aW9uIFllYXIgJiBEZWxpbnF1ZW50JykNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnllYXJzID0gc2VxKDIwMDYsIDIwMTQsIDEpDQoNCmZvciAoeSBpbiB5ZWFycykgew0KICByZXN1bHQgPC0gd2l0aChzdWJzZXQocHJvc3BlciwgTGlzdGluZ0NyZWF0aW9uWWVhciA9PSB5KSwNCiAgICAgICAgICAgICAgICAgY29yLnRlc3QoU3RhdGVkTW9udGhseUluY29tZSwgRGVsaW5xdWVudE51bSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gJ3BlYXJzb24nKSkNCiAgcHJpbnQoeSkNCiAgcHJpbnQocmVzdWx0JGVzdGltYXRlKQ0KfQ0KYGBgDQpJbmNvbWUgaXMgbm90IGNvcnJlbGF0ZWQgdG8gZGVsaW5xdWVuY2llcy4gIEluIGdlbmVyYWwsIGRlbGlucXVlbmN5IGNvdW50IGZvbGxvd3MgaW5jb21lIGNvdW50LiAgVGhlIHktYXhpcyBzY2FsZSBpcyBtYWludGFpbmVkIGFzIHN0YXRpYyB0byBtb3JlIGVhc2lseSBvYnNlcnZlIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBudW1iZXIgb2YgbG9hbnMgcGVyIHllYXIuDQoNCioqKg0KIyMjIFByb3BvcnRpb24gRGVsaW5xdWVudA0KYGBge3IsIGVjaG89RkFMU0V9DQpkZWxfaW5jb21lIDwtIHByb3NwZXIgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKEluY29tZVJhbmdlKSkgJT4lIA0KICBncm91cF9ieShJbmNvbWVSYW5nZSwgRGVsaW5xdWVudCkgJT4lIA0KICBzdW1tYXJpc2UobiA9IG4oKSkNCg0KZGVsX2luY29tZQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KZGVsX2luY29tZS53aWRlIDwtIGRjYXN0KGRlbF9pbmNvbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgSW5jb21lUmFuZ2UgfiBEZWxpbnF1ZW50LA0KICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlLnZhciA9ICduJykNCg0KZGVsX2luY29tZS53aWRlJHByb3BfZGVsIDwtIGRlbF9pbmNvbWUud2lkZSRUcnVlIC8gKGRlbF9pbmNvbWUud2lkZSRUcnVlICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbF9pbmNvbWUud2lkZSRGYWxzZSkNCg0KZGVsX2luY29tZS53aWRlDQpgYGANCg0KIyMjIyA8YSBpZD0icHJvcF9kZWxfYnlfaXIiPjwvYT5Qcm9wb3J0aW9uIERlbGlucXVlbnQgYnkgSW5jb21lIFJhbmdlIC0gQml2YXJpYXRlDQpgYGB7ciwgZWNobz1GQUxTRX0NCmdncGxvdChkYXRhID0gZGVsX2luY29tZS53aWRlLCBhZXMoeCA9IEluY29tZVJhbmdlLCB5ID0gcHJvcF9kZWwpKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAncHVycGxlJykgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICB5bGFiKCdQcm9wb3J0aW9uIERlbGlucXVlbnQnKSArIHhsYWIoJ0luY29tZSBSYW5nZScpICsNCiAgZ2d0aXRsZSgnUHJvcG9ydGlvbiBEZWxpbnF1ZW50IGJ5IEluY29tZSBSYW5nZScpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQp3aXRoKGRlbF9pbmNvbWUud2lkZSwgY29yLnRlc3QocHJvcF9kZWwsIGFzLm51bWVyaWMoSW5jb21lUmFuZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICdwZWFyc29uJykpDQpgYGANCltQcm9wb3J0aW9uIERlbGlucXVlbnQgYnkgSW5jb21lIFJhbmdlIC0gQml2YXJpYXRlXSgjcHJvcF9kZWxfYnlfaXIpLCBzdXBwb3J0ZWQgYnkgdGhlIGNhbGN1bGF0ZWQgY29ycmVsYXRpb24gb2YgLTAuOTQ0LCBkZW1vbnN0cmF0ZXMgYSBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBpbmNvbWUgcmFuZ2UgYW5kIHRoZSBwcm9wb3J0aW9uIG9mIGRlbGlucXVlbmNpZXMuICBBcyBJbmNvbWVSYW5nZSBpbmNyZWFzZXMsIFByb3BvcnRpb25EZWxpbnF1ZW50IGRlY3JlYXNlcy4NCg0KIyMjIFByb3BvcnRpb24gRGVsaW5xdWVudCBieSBZZWFyDQpgYGB7ciwgZWNobz1GQUxTRX0NCmRlbF95ZWFyX2luY29tZSA8LSBwcm9zcGVyICU+JSANCiAgZmlsdGVyKCFpcy5uYShJbmNvbWVSYW5nZSkpICU+JSANCiAgZ3JvdXBfYnkoTGlzdGluZ0NyZWF0aW9uWWVhciwgSW5jb21lUmFuZ2UsIERlbGlucXVlbnQpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBuKCkpDQoNCmRlbF95ZWFyX2luY29tZQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KZGVsX3llYXJfaW5jb21lLndpZGUgPC0gZGNhc3QoZGVsX3llYXJfaW5jb21lLA0KICAgICAgICAgICAgICAgICAgICAgICAgIExpc3RpbmdDcmVhdGlvblllYXIgKyBJbmNvbWVSYW5nZSB+IERlbGlucXVlbnQsDQogICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUudmFyID0gJ24nKQ0KDQojIHNvbWUgcmFuZ2VzIGhhZCBOQSBkZWxpbnF1ZW5jaWVzLCBpbnRlcnByZXRlZCBhcyAwIGZvciBjYWxjdWxhdGlvbg0KZGVsX3llYXJfaW5jb21lLndpZGVbaXMubmEoZGVsX3llYXJfaW5jb21lLndpZGUpXSA8LSAwIA0KZGVsX3llYXJfaW5jb21lLndpZGUkcHJvcF9kZWwgPC0gZGVsX3llYXJfaW5jb21lLndpZGUkVHJ1ZSAvDQogIChkZWxfeWVhcl9pbmNvbWUud2lkZSRUcnVlICsgZGVsX3llYXJfaW5jb21lLndpZGUkRmFsc2UpDQpkZWxfeWVhcl9pbmNvbWUud2lkZQ0KYGBgDQoNCiMjIyMgPGEgaWQ9InAudXNlMSI+PC9hPlByb3BvcnRpb24gRGVsaW5xdWVudCBieSBJbmNvbWUgUmFuZ2UgY29sb3JlZCBieSBZZWFyIC0gTXVsdGl2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBlY2hvPUZBTFNFfQ0KcC51c2UxIDwtIGdncGxvdChkYXRhID0gZGVsX3llYXJfaW5jb21lLndpZGUsIGFlcyh4ID0gSW5jb21lUmFuZ2UsIHkgPSBwcm9wX2RlbCkpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBzdWJzZXQoZGVsX3llYXJfaW5jb21lLndpZGUpLA0KICAgICAgICAgICAgYWVzKHggPSBJbmNvbWVSYW5nZSwgeSA9IHByb3BfZGVsLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gTGlzdGluZ0NyZWF0aW9uWWVhciwNCiAgICAgICAgICAgICAgICBjb2xvciA9IGFzLmZhY3RvcihMaXN0aW5nQ3JlYXRpb25ZZWFyKSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIodHlwZT0nc2VxJyApICsNCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICdMaXN0aW5nXG5DcmVhdGlvblxuWWVhcicpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgeWxhYignUHJvcG9ydGlvbiBEZWxpbnF1ZW50JykgKyB4bGFiKCdJbmNvbWUgUmFuZ2UnKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDAuNTUpLCBicmVha3MgPSBzZXEoMCwgMC41NSwgMC4wNSkpICsNCiAgZ2d0aXRsZSgnUHJvcG9ydGlvbiBEZWxpbnF1ZW50IGJ5IEluY29tZSBSYW5nZSAtIExpc3RpbmcgQ3JlYXRpb24gWWVhcicpDQoNCnAudXNlMQ0KYGBgDQpUaGUgcmVsYXRpb25zaGlwIGJldHdlZW4gUHJvcG9ydGlvbiBEZWxpbnF1ZW50IGFuZCB0aGUgZ3JvdXBpbmcgb2YgdGhlIHllYXJzIGNvdWxkIGJlIGF0dHJpYnV0YWJsZSB0byB0aGUgbG9hbiB0ZXJtIGxlbmd0aC4gIFRoZSBtYWpvcml0eSBvZiBsb2FucyBoYXZlIGEgdGVybSBsZW5ndGggb2YgMyB5ZWFycyBhbmQgc29tZSBleHRlbmQgdG8gNSB5ZWFycy4gIEV4cGxpY2l0IGRhdGEgZm9yIHRoZSBmdWxsIGxvYW4gdGVybSBvbmx5IGV4aXN0cyBmb3IgbG9hbnMgb3JpZ2luYXRpbmcgZnJvbSAyMDA2IHVudGlsIDIwMDkuICBBIG1vc3RseSBjb21wbGV0ZSBzZXQgb2YgZGF0YSBleGlzdGlzIGZvciBsb2FucyBvcmlnaW5pYXRpbmcgdG8gMjAxMS4gIEEgY29uY2x1ZGluZyBjb21wYXJpc29uIGJldHdlZW4gbG9hbnMgY3JlYXRlZCBmcm9tIDIwMTIgd2l0aCB0aG9zZSBjcmVhdGVkIHByaW9yIHRvIDIwMTIgaXMgbm90IGZlYXNhYmxlIHdpdGggdGhlIGF2YWlsYWJsZSBkYXRhLiBBZGRpdGlvbmFsbHksIFByb3NwZXIgaW50cm9kdWNlZCBuZXcgbWV0aG9kcyBmb3IgYXNzZXNzaW5nIHJpc2sgKFByb3NwZXJTY29yZSksIHdoaWNoIHN1YnNlcXVlbnRseSBoZWxwZWQgdG8gcmVkdWNlIHRoZSBudW1iZXIgb2YgZGVsaW5xdWVudCBhY2NvdW50cy4NCg0KW1JldHJ1biB0byBGaW5hbCBQbG90cyAmIFN1bW1hcnldKCNmaW5hbCkNCg0KIyMjIyA8YSBpZD0ibWVhbl9wcm9wX2RlbF9ieV9pciI+PC9hPk1lYW4gUHJvcG9ydGlvbiBEZWxpbnF1ZW50IGJ5IEluY29tZSBSYW5nZSAtIEJpdmFyaWF0ZQ0KYGBge3IsIGZpZy53aWR0aD04LCBlY2hvPUZBTFNFfQ0KZ2dwbG90KGRhdGEgPSBkZWxfeWVhcl9pbmNvbWUud2lkZSwgYWVzKHggPSBJbmNvbWVSYW5nZSwgeSA9IHByb3BfZGVsKSkgKw0KICBzdGF0X3N1bW1hcnkoZnVuLnkgPSAnbWVhbicsIGdlb20gPSAncG9pbnQnLCBjb2xvciA9ICdwdXJwbGUnKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIHlsYWIoJ1Byb3BvcnRpb24gRGVsaW5xdWVudCcpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMC4xLCAwLjIyNSksIGJyZWFrcyA9IHNlcSgwLjEsIDAuMjI1LCAwLjAyNSkpICsNCiAgeGxhYignSW5jb21lIFJhbmdlJykgKyB5bGFiKCdNZWFuIFByb3BvcnRpb24gRGVsaW5xdWVudCcpICsNCiAgZ2d0aXRsZSgnTWVhbiBQcm9wb3J0aW9uIERlbGlucXVlbnQgYnkgSW5jb21lIFJhbmdlJykNCmBgYA0KTm90ZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIFtNZWFuIFByb3BvcnRpb24gRGVsaW5xdWVudCBieSBJbmNvbWUgUmFuZ2UgLSBCaXZhcmlhdGVdKCNtZWFuX3Byb3BfZGVsX2J5X2lyKSBhbmQgW1Byb3BvcnRpb24gRGVsaW5xdWVudCBieSBJbmNvbWUgUmFuZ2UgLSBCaXZhcmlhdGVdKCNwcm9wX2RlbF9ieV9pcikuICBUaGUgbWVhbiBwcm9wb3J0aW9uIGRlbGlucXVlbnQgZGVtb25zdHJhdGVzIGxlc3MgdmFyaWFuY2UgYWNyb3NzIGluY29tZSByYW5nZXMuICBUaGUgbWVhbiBpcyBvZiB0aGUgUHJvcG9ydGlvbkRlbGlucXVlbnQgYnkgSW5jb21lUmFuZ2UgZm9yIGVhY2ggTGlzdGluZ0NyZWF0aW9uWWVhci4NCg0KKioqDQojIyMgRGVidCB0byBJbmNvbWUgUmF0aW8NCmBgYHtyLCBlY2hvPUZBTFNFfQ0KDQpzdW1tYXJ5KHByb3NwZXIkRGVidFRvSW5jb21lUmF0aW8pDQpgYGANCg0KIyMjIyBEZWJ0IHRvIEluY29tZSBSYXRpbyBjb2xvcmVkIGJ5IERlbGlucXVlbnQgLSBVbml2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTksIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25ZZWFyID4gMjAwNSAmDQogICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShEZWJ0VG9JbmNvbWVSYXRpbykpLA0KICAgICAgIGFlcyh5ID0gRGVidFRvSW5jb21lUmF0aW8sIGZpbGwgPSBEZWxpbnF1ZW50KSkgKw0KICAjZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAyLCBjb2xvciA9ICdibGFjaycpICsNCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gRGVsaW5xdWVudCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMSkpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJBY2NlbnQiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGZhY2V0X3dyYXAofkxpc3RpbmdDcmVhdGlvblllYXIsIHNjYWxlcyA9ICdmcmVlX3knKSArDQogIGdndGl0bGUoJ0RlYnQgdG8gSW5jb21lIFJhdGlvIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyICYgRGVsaW5xdWVudCcpDQpgYGANClRoZSBEZWJ0VG9JbmNvbWVSYXRpbyByYW5nZSBoYXMgYmVlbiBsaW1pdGVkIHRvIGEgbWF4aW11bSBvZiAxIGluIHRoZSB2aXN1YWxpemF0aW9uLiAgVGhlIGFjdHVhbCByYW5nZSBleHRlbmRzIHRvIDEwLCBjYXVzaW5nIHBvc2l0aXZlIHNrZXdpbmcuDQoNCioqKg0KIyMjIFJldm9sdmluZyBDcmVkaXQgQmFsYW5jZQ0KYGBge3IsIGVjaG89RkFMU0V9DQpzdW1tYXJ5KHByb3NwZXIkUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSkNCmBgYA0KDQojIyMjIFJldm9sdmluZ0NyZWRpdEJhbGFuY2UgY29sb3JlZCBieSBEZWxpbnFlbnQgLSBVbml2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTksIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCAhaXMubmEoUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSkgJg0KICAgICAgICAgICAgICAgICAgICAgICBSZXZvbHZpbmdDcmVkaXRCYWxhbmNlICE9IDApLA0KICAgICAgIGFlcyhSZXZvbHZpbmdDcmVkaXRCYWxhbmNlLCBmaWxsID0gRGVsaW5xdWVudCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3IgPSAnYmxhY2snKSArDQogIHNjYWxlX3hfbG9nMTAoZXhwcmVzc2lvbihwYXN0ZShMb2dbMTBdLCAnIG9mIFJldm9sdmluZyBDcmVkaXQgQmFsYW5jZScpKSwNCiAgICAgICAgICAgICAgICBicmVha3MgPSBzY2FsZXM6OnRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54KSwNCiAgICAgICAgICAgICAgICBsYWJlbHMgPSBkb2xsYXIpICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhciwgc2NhbGVzID0gJ2ZyZWVfeScpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJBY2NlbnQiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGdndGl0bGUoYnF1b3RlKHBhc3RlKExvZ1sxMF0sICcgb2YgUmV2b2x2aW5nIENyZWRpdCBCYWxhbmNlIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyICYgRGVsaW5xdWVudCcpKSkNCmBgYA0KQSAkTG9nX3sxMH0kIHNjYWxpbmcgb2YgdGhlIHgtYXhpcyBwcm9kdWNlcyBhIG5vcm1hbCBkaXN0cmlidXRpb24gb2YgUmV2b2x2aW5nIENyZWRpdCBCYWxhbmNlLCBvdGhlcndpc2UgcG9zaXRpdmVseSBza2V3ZWQgYmVjYXN1ZSBvZiBsYXJnZSB2YWx1ZWQgb3V0bGllcnMuDQoNCiMjIyMgUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSBieSBJbmNvbWVSYW5nZSAtIEJpdmFyaWF0ZQ0KYGBge3IsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCAhaXMubmEoSW5jb21lUmFuZ2UpICYNCiAgICAgICAgICAgICAgICAgICAgICAgUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSAhPSAwKSwNCiAgICAgICBhZXMoSW5jb21lUmFuZ2UsIFJldm9sdmluZ0NyZWRpdEJhbGFuY2UsIGNvbG9yID0gSW5jb21lUmFuZ2UpKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgc2NhbGVfeV9sb2cxMChsYWJlbHMgPSBkb2xsYXIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygyNDE2LCAzNDIwNSksIGNvbG9yPScjMDAzM0ZGJywNCiAgICAgICAgICAgICBsaW5ldHlwZT0zLCBzaXplID0gMSkgKw0KICBnZ3RpdGxlKCdSZXZvbHZpbmcgQ3JlZGl0IEJhbGFuY2UgYnkgSW5jb21lIFJhbmdlJykNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCndpdGgoc3Vic2V0KHByb3NwZXIsICFpcy5uYShJbmNvbWVSYW5nZSkpLA0KICAgICBjb3IudGVzdChhcy5udW1lcmljKEluY29tZVJhbmdlKSwgUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSwNCiAgICAgICAgICAgICAgbWV0aG9kID0gJ3BlYXJzb24nKSkNCnN1bW1hcnkoc3Vic2V0KHByb3NwZXIsIEluY29tZVJhbmdlID09ICcoMCwxMDAwMF0nKSRSZXZvbHZpbmdDcmVkaXRCYWxhbmNlKQ0Kc3VtbWFyeShzdWJzZXQocHJvc3BlciwNCiAgICAgICAgICAgICAgIEluY29tZVJhbmdlID09ICcoMjAwMDAwLDIxMDAwMDM2XScpJFJldm9sdmluZ0NyZWRpdEJhbGFuY2UpDQpgYGANCkZyb20gdGhlIGxvd2VzdCB0byBoaWdoZXN0IEluY29tZVJhbmdlLCB3ZSBjYW4gc2VlIGFuIGluY3JlYXNlIGluIG1lZGlhbiBSZXZvbHZpbmdDcmVkaXRCYWxhbmNlIGZyb20gXCQyLDQxNiB0byBcJDM0LDIwNS4gIFRoZSBzdW1tYXJ5IHNob3dzLCBpbiB0aGUgY2FzZSBvZiB0aGUgUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSBmb3IgbG93ZXN0IGFuZCBoaWdoZXN0IEluY29tZVJhbmdlLCBhIHBvc2l0aXZlIHNrZXcgYmVjYXVzZSB0aGUgbWVhbiBpcyBzaWduaWZpY2FudGx5IGdyZWF0ZXIgdGhhbiB0aGUgbWVkaWFuLg0KDQoqKioNCiMjIyBMb2FuIFRlcm0NCmBgYHtyLCBlY2hvPUZBTFNFfQ0KdGFibGUocHJvc3BlciRUZXJtKQ0KYGBgDQoNCiMjIyMgTG9hbiBUZXJtIGNvbG9yZWQgYnkgRGVsaW5xdWVuY3kgLSBVbml2YXJpYXRlDQpgYGB7ciwgZWNobz1GQUxTRX0NCmdncGxvdChkYXRhID0gcHJvc3BlciwgYWVzKHggPSBUZXJtLCBmaWxsID0gRGVsaW5xdWVudCkpICsNCiAgZ2VvbV9iYXIoKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDg4MDAwKSwgYnJlYWtzID0gc2VxKDAsIDg4MDAwLCA4MDAwKSkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkFjY2VudCIpICsNCiAgeGxhYignTG9hbiBUZXJtIChNb250aHMpJykgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBnZ3RpdGxlKCdMb2FuIFRlcm0gKG1vbnRocykgLSBEZWxpbnF1ZW50JykNCmBgYA0KDQojIyMjICBMaXN0aW5nQ3JlYXRpb25ZZWFyIGNvbG9yZWQgYnkgVGVybSAtIFVuaXZhcmlhdGUNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KZ2dwbG90KHByb3NwZXIsIGFlcyh4ID0gYXMuZmFjdG9yKExpc3RpbmdDcmVhdGlvblllYXIpLCBmaWxsID0gVGVybSkpICsNCiAgZ2VvbV9iYXIoKSArDQogIHhsYWIoJ0xpc3RpbmcgQ3JlYXRpb24gWWVhcicpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAzNTAwMCwgMjUwMCkpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZmFjZXRfd3JhcCh+RGVsaW5xdWVudCkgKw0KICBnZ3RpdGxlKCdMaXN0aW5nIENyZWF0aW9uIC0gRGVsaW5xdWVudCAmIFRlcm0gbGVuZ3RoJykNCmBgYA0KTW9zdCBsb2FucyBhcmUgZm9yIDM2IG1vbnRocywgYXMgc3VjaCwgbW9zdCBkZWxpbnF1ZW5jaWVzIG9jY3VyZWQgb24gMzYgbW9udGggbG9hbnMuDQoNCioqKg0KIyMjIFByb3NwZXJTY29yZSAoUmlzaykNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KdGFibGUocHJvc3BlciRQcm9zcGVyU2NvcmUpDQpgYGANCg0KIyMjIyBQcm9zcGVyU2NvcmUgKFJpc2spIHdpdGggRGVsaW5xdWVuY3kgLSBVbml2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTksIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25EYXRlID4gMjAwOS0wNy0zMSAmDQogICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShQcm9zcGVyU2NvcmUpKSwNCiAgICAgICBhZXMoeCA9IFByb3NwZXJTY29yZSwgZmlsbCA9IERlbGlucXVlbnQpKSArDQogIGdlb21fYmFyKCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkFjY2VudCIpICsNCiAgeGxhYignUHJvc3BlciAoUmlzaykgU2NvcmUnKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGZhY2V0X3dyYXAofkxpc3RpbmdDcmVhdGlvblllYXIsIHNjYWxlcyA9ICdmcmVlX3knKSArDQogIGdndGl0bGUoJ1Byb3NwZXIgU2NvcmUgKHJpc2spIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyICYgRGVsaW5xdWVudCcpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQp3aXRoKHN1YnNldChwcm9zcGVyLCAhaXMubmEoUHJvc3BlclNjb3JlKSksDQogICAgIGNvci50ZXN0KFByb3NwZXJTY29yZS4ubnVtZXJpYy4sIERlbGlucXVlbnROdW0sIG1ldGhvZCA9ICdwZWFyc29uJykpDQpgYGANClRoZXJlJ3Mgbm8gbm90aWNpYmxlIGNvcnJlbGF0aW9uIGJldHdlZW4gcHJvc3BlciByaXNrIHNjb3JlICgxMSBpcyB0aGUgYmVzdCBzY29yZSkgYW5kIGRlbGlucXVlbmN5LiAgVGhlIGRpc3RyaWJ1dGlvbiBjaGFuZ2VzIGZyb20gbmVnYXRpdmVseSBza2V3ZWQgdG8gbm9ybWFsaXNobHkgc2tld2VkIGFmdGVyIDIwMTIuICBUaGUgbGFyZ2VzdCBudW1iZXIgb2YgYm9ycm93ZXJzIGFyZSBhc3NpZ25lZCBhIHJpc2sgc2NvcmUgb2YgNCBhZnRlciAyMDEyIGFuZCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IHJlZHVjdGlvbiBpbiBkZWxpbnF1ZW50IGFjY291bnRzLg0KDQoqKioNCiMjIyBEZWxpbnF1ZW5jaWVzIGJ5IFN0YXRlDQpgYGB7ciwgZWNobz1GQUxTRX0NCm1hcC5kZiA8LSBwcm9zcGVyICU+JSANCiAgZmlsdGVyKCFpcy5uYShCb3Jyb3dlclN0YXRlKSwgIWlzLm5hKERlbGlucXVlbnQpKSAlPiUgDQogIGdyb3VwX2J5KEJvcnJvd2VyU3RhdGUsIERlbGlucXVlbnQpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBuKCkpDQoNCiMgcmVtb3ZlIHJvdyB3aXRoIGVtcHR5IHN0YXRlICh3YXNuJ3QgYWJsZSB0byBmaWx0ZXIgaXQgb3V0KQ0KbWFwLmRmIDwtIG1hcC5kZlstYygxLCAyKSxdIA0KIyBhZGQgY29sdW1uIHdpdGggZnVsbCBzdGF0ZSBuYW1lDQptYXAuZGYkc3RhdGUgPC0gc3RhdGUubmFtZVttYXRjaChtYXAuZGYkQm9ycm93ZXJTdGF0ZSwgc3RhdGUuYWJiKV0gDQptYXAuZGYkc3RhdGUgPC0gdG9sb3dlcihtYXAuZGYkc3RhdGUpICMgdG8gbG93ZXJjYXNlDQptYXAuZGYgPC0gbWFwLmRmW2MoMjo0KV0gIyBrZWVwIHR3byBjb2x1bW5zDQptYXAuZGYNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCm1hcC5kZi53aWRlIDwtIGRjYXN0KG1hcC5kZiwNCiAgICAgICAgICAgICAgICAgICAgIHN0YXRlIH4gRGVsaW5xdWVudCwNCiAgICAgICAgICAgICAgICAgICAgIHZhbHVlLnZhciA9ICduJykNCg0KbWFwLmRmLndpZGVbaXMubmEobWFwLmRmLndpZGUpXSA8LSAwDQptYXAuZGYud2lkZSRwcm9wX2RlbCA8LSBtYXAuZGYud2lkZSRUcnVlIC8NCiAgKG1hcC5kZi53aWRlJFRydWUgKyBtYXAuZGYud2lkZSRGYWxzZSkNCm1hcC5kZi53aWRlDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpzdW1tYXJ5KG1hcC5kZi53aWRlJHByb3BfZGVsKQ0KYGBgDQoNCiMjIyMgPGEgaWQ9InAuY291bnRyeSI+PC9hPkRlbGlucWVuY2llcyBieSBTdGF0ZSBIZWF0IE1hcCAtIEJpdmFyaWF0ZQ0KYGBge3IsIHJlc3VsdHM9J2hpZGUnLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQ0Kc3RhdGVzIDwtIGRhdGEuZnJhbWUoc3RhdGUuY2VudGVyLCBzdGF0ZS5hYmIpDQpzdGF0ZXMgPC0gc3RhdGVzWyEoc3RhdGVzJHN0YXRlLmFiYiAlaW4lIGMoIkFLIiwgIkhJIikpLF0NCg0Kc3RhdGVzX21hcCA8LSBtYXBfZGF0YSgic3RhdGUiKQ0KDQpwMSA8LSBnZ3Bsb3QoKQ0KIyBib3JkZXJzDQpwMSA8LSBwMSArIGdlb21fbWFwKGRhdGE9c3RhdGVzX21hcCwgbWFwPWZpZnR5X3N0YXRlcywgYWVzKG1hcF9pZD1yZWdpb24pLA0KICAgICAgICAgICAgICAgICAgICBjb2xvcj0id2hpdGUiLCBzaXplPTAuMTUpDQojIGZpbGxzDQpwMSA8LSBwMSArIGdlb21fbWFwKGRhdGE9c3Vic2V0KG1hcC5kZiwgRGVsaW5xdWVudCA9PSAnVHJ1ZScpLCBtYXA9ZmlmdHlfc3RhdGVzLA0KICAgICAgICAgICAgICAgICAgICBhZXMoZmlsbD1uLCBtYXBfaWQ9c3RhdGUpLCBjb2xvcj0id2hpdGUiLCBzaXplPTAuMTUpDQojIGxhYmVscw0KcDEgPC0gcDEgKyBnZW9tX3RleHQoZGF0YT1zdGF0ZXMsIGFlcyh4PXgsIHk9eSwgbGFiZWw9c3RhdGUuYWJiLCBncm91cD1OVUxMKSwNCiAgICAgICAgICAgICAgICAgICAgIHNpemU9MikNCiMgZGVjZW50IHByb2plY3Rpb24NCnAxIDwtIHAxICsgY29vcmRfbWFwKCJhbGJlcnMiLCBsYXQwPTM5LCBsYXQxPTQ1KQ0KcDEgPC0gcDEgKyBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlPSJQdVJkIikNCiMgYmV0dGVyIHRoZW1lDQpwMSA8LSBwMSArIGxhYnMoeD1OVUxMLCB5PU5VTEwpDQpwMSA8LSBwMSArIHRoZW1lX2J3KCkNCnAxIDwtIHAxICsgdGhlbWUocGFuZWwuZ3JpZD1lbGVtZW50X2JsYW5rKCkpDQpwMSA8LSBwMSArIHRoZW1lKHBhbmVsLmJvcmRlcj1lbGVtZW50X2JsYW5rKCkpDQpwMSA8LSBwMSArIHRoZW1lKGF4aXMudGlja3M9ZWxlbWVudF9ibGFuaygpKQ0KcDEgPC0gcDEgKyB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBnZ3RpdGxlKCdUb3RhbCBEZWxpbnF1ZW50JykgKyBmaWZ0eV9zdGF0ZXNfaW5zZXRfYm94ZXMoKQ0KDQojcDENCmBgYA0KDQojIyMjIFByb3BvcnRpb24gRGVsaW5xdWVudCBieSBTdGF0ZSBIZWF0IE1hcCAtIEJpdmFyaWF0ZQ0KYGBge3IsIHJlc3VsdHM9J2hpZGUnLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFfQ0KcDIgPC0gZ2dwbG90KCkNCiMgYm9yZGVycw0KcDIgPC0gcDIgKyBnZW9tX21hcChkYXRhPXN0YXRlc19tYXAsIG1hcD1maWZ0eV9zdGF0ZXMsIGFlcyhtYXBfaWQ9cmVnaW9uKSwNCiAgICAgICAgICAgICAgICAgICAgY29sb3I9IndoaXRlIiwgc2l6ZT0wLjE1KQ0KIyBmaWxscw0KcDIgPC0gcDIgKyBnZW9tX21hcChkYXRhPW1hcC5kZi53aWRlLCBtYXA9ZmlmdHlfc3RhdGVzLA0KICAgICAgICAgICAgICAgICAgICBhZXMoZmlsbD1wcm9wX2RlbCwgbWFwX2lkPXN0YXRlKSwgY29sb3I9IndoaXRlIiwgc2l6ZT0wLjE1KQ0KIyBsYWJlbHMNCnAyIDwtIHAyICsgZ2VvbV90ZXh0KGRhdGE9c3RhdGVzLA0KICAgICAgICAgICAgICAgICAgICAgYWVzKHg9eCwgeT15LCBsYWJlbD1zdGF0ZS5hYmIsIGdyb3VwPU5VTEwpLCBzaXplPTIpDQojIGRlY2VudCBwcm9qZWN0aW9uDQpwMiA8LSBwMiArIGNvb3JkX21hcCgiYWxiZXJzIiwgbGF0MD0zOSwgbGF0MT00NSkNCnAyIDwtIHAyICsgc2NhbGVfZmlsbF9kaXN0aWxsZXIocGFsZXR0ZT0iUHVSZCIpDQojIGJldHRlciB0aGVtZQ0KcDIgPC0gcDIgKyBsYWJzKHg9TlVMTCwgeT1OVUxMKQ0KcDIgPC0gcDIgKyB0aGVtZV9idygpDQpwMiA8LSBwMiArIHRoZW1lKHBhbmVsLmdyaWQ9ZWxlbWVudF9ibGFuaygpKQ0KcDIgPC0gcDIgKyB0aGVtZShwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpKQ0KcDIgPC0gcDIgKyB0aGVtZShheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSkNCnAyIDwtIHAyICsgdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2d0aXRsZSgnUHJvcG9ydGlvbiBEZWxpbnF1ZW50JykgKyBmaWZ0eV9zdGF0ZXNfaW5zZXRfYm94ZXMoKQ0KDQojcDINCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCByZXN1bHRzPSdoaWRlJywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRX0NCmdyaWQuYXJyYW5nZShwMSwgcDIsIG5jb2wgPSAxKQ0KYGBgDQpBbnkgaW50ZXJlc3Rpbmcgb2JzZXJ2YXRpb25zIGZyb20gdGhlIG51bWJlciBvZiBkZWxpbnF1ZW5jaWVzIGRlcGljdGVkIGluIHRoZSBmaXJzdCBjaG9yb3BsZXRoIG1hcCBhcmUgc3VycGFzc2VkIGJ5IHRoZSBwcm9wb3J0aW9uIGRlbGlucXVlbnQgY2hvcm9wbGV0aCBtYXAsIHdoaWNoIGdpdmVzIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGRlbGlxdWVuY3kgZGlzdHJpYnV0aW9uIGJ5IHN0YXRlLiAgRGVsaW5xdWVuY2llcyByYW5nZSBiZXR3ZWVuIDkuNSUgYW5kIDM2LjYlIHdpdGggYSBtZWFuIG9mIDE2LjUlLg0KDQpbUmV0cnVuIHRvIEZpbmFsIFBsb3RzICYgU3VtbWFyeV0oI2ZpbmFsKQ0KDQoqKioNCiMjIyBMaXN0aW5nIENhdGVnb3J5DQpgYGB7ciwgZWNobz1GQUxTRX0NCnN1bW1hcnkocHJvc3BlciRMaXN0aW5nQ2F0ZWdvcnkpDQpgYGANCg0KIyMjIyBMaXN0aW5nQ2F0ZWdvcnkgY29sb3JlZCBieSBEZWxpbnF1ZW50IC0gVW5pdmFyaWF0ZQ0KYGBge3IsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHByb3NwZXIsIGFlcyh4ID0gTGlzdGluZ0NhdGVnb3J5LCBmaWxsID0gRGVsaW5xdWVudCkpICsNCiAgZ2VvbV9iYXIoKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDYwMDAwKSwgYnJlYWtzID0gc2VxKDAsIDYwMDAwLCA1MDAwKSkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkFjY2VudCIpICsNCiAgeGxhYignTGlzdGluZyBDYXRlZ29yeScpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLCB2anVzdCA9IDApLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICBnZ3RpdGxlKCdMaXN0aW5nIENhdGVnb3J5IC0gRGVsaW5xdWVudCcpDQpgYGANClRoZSBxdWFudGl0eSBvZiBEZWJ0IENvbnNvbGlkYXRpb24gbG9hbnMgaXMgc28gbGFyZ2UgY29tcGFyZWQgdG8gdGhlIG90aGVyIGxpc3RpbmcgY2F0ZWdvcmllcywgdGhhdCBMaXN0aW5nQ2F0ZWdvcnkgaXMgcmVuZGVyZWQgdW5pbnRlcmVzdGluZyBhcyBhIG1ldHJpYyBmb3IgYW5hbHlzaW5nIHRoZSBQcm9zcGVyIGRhdGFzZXQuICBOQSwgT3RoZXIgYW5kIFBlcnNvbmFsIGFyZSB1c2VsZXNzIGZvciBwcm92aWRpbmcgYW55IGluc2lnaHQgb3RoZXIgdGhhbiB0aGUgYm9ycm93ZXIgZGlkbid0IHdhbnQgdG8gZGl2dWxnZSB0aGUgcmVhc29uIGZvciB0aGUgbG9hbi4NCg0KKioqDQojIyMgQm9ycm93ZXIgUmF0ZQ0KYGBge3IsIGVjaG89RkFMU0V9DQpzdW1tYXJ5KHByb3NwZXIkQm9ycm93ZXJSYXRlKQ0KYGBgDQoNCiMjIyMgQm9ycm93ZXIgUmF0ZSBmaWxsZWQgYnkgRGVsaW5xdWVudCBTdGF0dXMgYWNyb3NzIENyZWF0aW9uIFllYXIgLSBVbml2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTksIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHByb3NwZXIsIGFlcyh4ID0gQm9ycm93ZXJSYXRlLCBmaWxsID0gRGVsaW5xdWVudCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjAwNSwgY29sb3IgPSAnYmxhY2snKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAuMDQsIDAuMzYpLCBicmVha3MgPSBzZXEoMC4wNCwgMC4zNiwgMC4wNCkpICsNCiAgeGxhYignQm9ycm93ZXIgUmF0ZScpICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhciwgc2NhbGVzID0gJ2ZyZWVfeScpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2d0aXRsZSgnQm9ycm93ZXIgUmF0ZSAtIExpc3RpbmcgQ3JlYXRpb24gWWVhciAmIERlbGlucXVlbnQnKQ0KYGBgDQpCb3Jyb3dlciBSYXRlIGNvdW50IGNvbG9yZWQgYnkgZGVsaW5xdWVudCBzdGF0dWVzIGFjcm9zcyBsaXN0aW5nIGNyZWF0aW9uIHllYXIuDQoNCiMjIyMgPGEgaWQ9InAudXNlMyI+PC9hPkVzdGltYXRlZCBSZXR1cm4gYnkgQm9ycm93ZXIgUmF0ZSAtIE11bHRpdmFyaWF0ZQ0KYGBge3IsIGVjaG89RkFMU0V9DQpzdW1tYXJ5KHN1YnNldChwcm9zcGVyJEJvcnJvd2VyUmF0ZSwNCiAgICAgICAgICAgICAgIHByb3NwZXIkTGlzdGluZ0NyZWF0aW9uRGF0ZSA+IDIwMDktMDctMzEgJg0KICAgICAgICAgICAgICAgICAhaXMubmEocHJvc3BlciRQcm9zcGVyU2NvcmUpKSkNCmBgYA0KDQpgYGB7ciwgZmlnLndpZHRoPTksIGZpZy5oZWlnaHQ9NywgZWNobz1GQUxTRX0NCnAudXNlMyA8LSBnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25EYXRlID4gMjAwOS0wNy0zMSAmDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoUHJvc3BlclNjb3JlKSksDQogICAgICAgYWVzKHggPSBCb3Jyb3dlclJhdGUsIHkgPSBFc3RpbWF0ZWRSZXR1cm4sIGNvbG9yID0gUHJvc3BlclNjb3JlKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcih0eXBlPSdzZXEnICkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLjA0LCAwLjM2KSwgYnJlYWtzID0gc2VxKDAuMDQsIDAuMzYsIDAuMDQpKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhciwgc2NhbGVzID0gJ2ZyZWVfeScpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2d0aXRsZSgnRXN0aW1hdGVkIFJldHVybiBieSBCb3Jyb3dlciBSYXRlJykgKw0KICB4bGFiKCdCb3Jyb3dlciBSYXRlJykgKyB5bGFiKCdFc3RpbWF0ZWQgUmV0dXJuJykNCg0KcC51c2UzDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQp3aXRoKHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25EYXRlID4gMjAwOS0wNy0zMSksDQogICAgIGNvci50ZXN0KEJvcnJvd2VyUmF0ZSwgRXN0aW1hdGVkUmV0dXJuLCBtZXRob2QgPSAncGVhcnNvbicpKQ0KYGBgDQpBcyBzdGF0ZWQgaW4gdGhlIFByb3NwZXIgVmFyaWFibGUgRGVmaW5pdGlvbiBzcHJlYWRzaGVldCwgUHJvc3BlclNjb3JlIGlzIGEgY3VzdG9tIHJpc2sgc2NvcmUgYnVpbHQgdXNpbmcgaGlzdG9yaWNhbCBQcm9zcGVyIGRhdGEgYW5kIGlzIGFwcGxpY2FibGUgdG8gbG9hbnMgb3JpZ2luaWF0aW5nIGFmdGVyIDIwMDkvMDcvMzEuICAxMSBhbmQgMSBhcmUgdGhlIGxvd2VzdCBhbmQgaGlnaGVzdCByaXNrIHJlc3BlY3RpdmVseS4gIFRoZSBkYXRhIHNob3cgbG93ZXIgcmlzayBib3Jyb3dlcnMgaGF2ZSBhIGxvd2VyIEJvcnJvd2VyUmF0ZS4gIEZvbGxvd2luZyAyMDEwLCB0aGVyZSdzIGEgc2lnbmlmaWNhbnQgcmVkdWN0aW9uIGluIHRoZSBudW1iZXIgb2YgaGlnaGVyIHJpc2sgbG9hbnMgYW5kIEVzdGltYXRlZCBSZXR1cm4gaXMgZ3JlYXRlciB0aGFuIDA7IG5vdGUgdGhlIGVzdGltYXRlZCBsb3NzZXMgaW4gMjAwOSBhbmQgMjAxMC4NCg0KW1JldHJ1biB0byBGaW5hbCBQbG90cyAmIFN1bW1hcnldKCNmaW5hbCkNCg0KKioqDQojIyMgPGEgaWQ9InAudXNlNCI+PC9hPkVzdGltYXRlZCBSZXR1cm4gYnkgUHJvc3BlciBTY29yZSAoUmlzaykgLSBNdWx0aXZhcmlhdGUNCmBgYHtyLCBmaWcud2lkdGg9OSwgZWNobz1GQUxTRX0NCnAudXNlNCA8LSBnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCAhaXMubmEoUHJvc3BlclNjb3JlKSksDQogICAgICAgYWVzKHggPSBQcm9zcGVyU2NvcmUsIHkgPSBFc3RpbWF0ZWRSZXR1cm4sIGNvbG9yID0gUHJvc3BlclNjb3JlKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGZhY2V0X3dyYXAofkxpc3RpbmdDcmVhdGlvblllYXIsIHNjYWxlcyA9ICdmcmVlJykgKw0KICB4bGFiKCdQcm9zcGVyIFNjb3JlIChSaXNrKSAxOkhpZ2VzdCwgMTE6TG93ZXN0JykgKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICB5bGFiKCdFc3RpbWF0ZWQgUmV0dXJuJykgKw0KICBnZ3RpdGxlKCdFc3RpbWF0ZWQgUmV0dXJuIGJ5IFByb3NwZXIgU2NvcmUgKFJpc2spIC0gTGlzdGluZyBDcmVhdGlvbiBZZWFyJykNCg0KcC51c2U0DQpgYGANClRoaXMgdmlzdWFsaXphdGlvbiBkZW1vbnN0cmF0ZXMgaG93IFByb3NwZXIgaGFzIGFkanVzdGVkIHRoZWlyIHByb2Nlc3MgdG8gcmVjZWl2ZSB0aGUgaGlnaGVzdCBlc3RpbWF0ZWQgcmV0dXJucyBmcm9tIHRoZSBoaWdoZXN0IHJpc2sgYm9ycm93ZXJzLg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnllYXJzID0gc2VxKDIwMDksIDIwMTQsIDEpDQoNCmZvcih5IGluIHllYXJzKSB7DQogIHByaW50KHkpDQogIHJlc3VsdCA8LSB3aXRoKHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25ZZWFyID09IHkpLA0KICAgICAgICAgICAgIGNvci50ZXN0KFByb3NwZXJTY29yZS4ubnVtZXJpYy4sIEVzdGltYXRlZFJldHVybiwNCiAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAncGVhcnNvbicpKQ0KICBwcmludChyZXN1bHQkZXN0aW1hdGUpDQp9DQpgYGANCkZvciB0aGUgbW9zdCBwYXJ0LCB3aXRoIGVhY2ggeWVhciwgUHJvc3BlclNjb3JlIGJlY29tZXMgYSBiZXR0ZXIgcHJlZGljdG9yIG9mIEVzdGltYXRlZFJldHVybiAoaS5lLiB0aGUgbG93ZXN0IHJpc2sgYm9ycm93ZXJzICgxMSkgaGF2ZSB0aGUgbG93ZXN0IEVzdGltYXRlZFJldHVybikuDQoNCltSZXRydW4gdG8gRmluYWwgUGxvdHMgJiBTdW1tYXJ5XSgjZmluYWwpDQoNCioqKg0KIyMjIDxhIGlkPSJwLnVzZTUiPjwvYT5TdGF0ZWQgTW9udGhseSBJbmNvbWUgYnkgRXN0aW1hdGVkIFJldHVybiAtIE11bHRpdmFyaWF0ZQ0KYGBge3IsIGVjaG89RkFMU0V9DQpzdW1tYXJ5KHByb3NwZXIkU3RhdGVkTW9udGhseUluY29tZSkNCnN1bW1hcnkocHJvc3BlciRFc3RpbWF0ZWRSZXR1cm4pDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD05LCBlY2hvPUZBTFNFfQ0KcC51c2U1IDwtIGdncGxvdChkYXRhID0gc3Vic2V0KHByb3NwZXIsIExpc3RpbmdDcmVhdGlvbkRhdGUgPiAyMDA5LTA3LTMxICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShQcm9zcGVyU2NvcmUpICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXRlZE1vbnRobHlJbmNvbWUgPiAxMCksDQogICAgICAgYWVzKHkgPSBFc3RpbWF0ZWRSZXR1cm4sIHggPSBTdGF0ZWRNb250aGx5SW5jb21lLA0KICAgICAgICAgICBjb2xvciA9IFByb3NwZXJTY29yZSkpICsNCiAgZ2VvbV9kZW5zaXR5XzJkKCkgKw0KICBzY2FsZV94X2xvZzEwKGV4cHJlc3Npb24ocGFzdGUoTG9nWzEwXSwgJyBvZiBTdGF0ZWQgTW9udGhseSBJbmNvbWUnKSksDQogICAgICAgICAgICAgICAgYnJlYWtzID0gc2NhbGVzOjp0cmFuc19icmVha3MoImxvZzEwIiwgZnVuY3Rpb24oeCkgMTBeeCksDQogICAgICAgICAgICAgICAgbGFiZWxzID0gZG9sbGFyKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMzIwMCwgNDY2NywgNjgxNyksIGNvbG9yPScjMDAzM0ZGJywNCiAgICAgICAgICAgICBsaW5ldHlwZT0zLCBzaXplID0gMSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKDAuMDc0LCAwLjA5MiwgMC4xMTcpLCBjb2xvcj0nIzAwMzNGRicsDQogICAgICAgICAgICAgbGluZXR5cGU9Mywgc2l6ZSA9IDEpICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhciwgc2NhbGVzID0gJ2ZyZWVfeScpICsNCiAgeGxhYignRXN0aW1hdGVkIFJldHVybicpICsgeWxhYignRXN0aW1hdGVkIFJldHVybicpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsNCiAgZ2d0aXRsZSgnRXN0aW1hdGVkIFJldHVybiBieSBTdGF0ZWQgTW9udGhseSBJbmNvbWUnKQ0KDQpwLnVzZTUNCmBgYA0KQSBkZW5zaXR5IHBsb3QgaXMgdXNlZnVsIGZvciBkZWFsaW5nIHdpdGggb3ZlcnBsb3R0aW5nLiAgVGhlcmUgaXMgZXZpZGVuY2Ugb2YgY2hhbmdlIGluIHRoZSBtZXRob2Qgb2YgZGV0ZXJtaW5pbmcgRXN0aW1hdGVkUmV0dXJuLiAgSW5pdGlhbGx5IHRoZXJlIHdhcyBhIG5lZ2l0aXZlIGVzdGltYXRlZCByZXR1cm4gZm9yIHRoZSBoaWdoZXN0IHJpc2sgYm9ycm93ZXJzLCBjb21wYXJlZCB0byBsYXRlciB5ZWFycyB3aXRoIHRoZSBoaWdoZXN0IHJpc2sgY3VzdG9tZXJzIGhhdmluZyB0aGUgaGlnaGVzdCBlc3RpbWF0ZWQgcmV0dXJuIHJhdGUuICBUaGUgZG90dGVkIGJsdWUgbGluZXMgcmVwcmVzZW50IDFzdCBxdWFydGlsZSwgbWVkaWFuIGFuZCAzcmQgcXVhcnRpbGUgb3ZlcmFsbCBmb3IgdGhlIHJlc3BlY3RpdmUgYXhpcy4NCg0KW1JldHJ1biB0byBGaW5hbCBQbG90cyAmIFN1bW1hcnldKCNmaW5hbCkNCg0KKioqDQojIyMgU3RhdGVkIE1vbnRobHkgSW5jb21lIGJ5IFByb3NwZXJTY29yZSAoUmlzaykgLSBNdWx0aXZhcmlhdGUNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25EYXRlID4gMjAwOS0wNy0zMSAmDQogICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShQcm9zcGVyU2NvcmUpICYgU3RhdGVkTW9udGhseUluY29tZSA+IDEwKSwNCiAgICAgICBhZXMoeCA9IFByb3NwZXJTY29yZSwgeSA9IFN0YXRlZE1vbnRobHlJbmNvbWUsIGNvbG9yID0gUHJvc3BlclNjb3JlKSkgKw0KICBnZW9tX2JveHBsb3QobmEucm0gPSBUUlVFKSArDQogIHNjYWxlX3lfbG9nMTAoZXhwcmVzc2lvbihwYXN0ZShMb2dbMTBdLCAnIG9mIFN0YXRlZCBNb250aGx5IEluY29tZScpKSwNCiAgICAgICAgICAgICAgICBicmVha3MgPSBzY2FsZXM6OnRyYW5zX2JyZWFrcygibG9nMTAiLCBmdW5jdGlvbih4KSAxMF54KSwNCiAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6OnRyYW5zX2Zvcm1hdCgibG9nMTAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlczo6bWF0aF9mb3JtYXQoMTBeLngpKSkgKw0KICBmYWNldF93cmFwKH5MaXN0aW5nQ3JlYXRpb25ZZWFyLCBzY2FsZXMgPSAnZnJlZScpICsNCiAgeGxhYignUHJvc3BlciBTY29yZSAoUmlzaykgMTpIaWdlc3QsIDExOkxvd2VzdCcpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgZ2d0aXRsZShleHByZXNzaW9uKA0KICAgIHBhc3RlKExvZ1sxMF0sICcgb2YgU3RhdGVkIE1vbnRobHkgSW5jb21lIGJ5IFByb3NwZXIgU2NvcmUgKFJpc2spJykpKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Kd2l0aChzdWJzZXQocHJvc3BlciwgTGlzdGluZ0NyZWF0aW9uRGF0ZSA+IDIwMDktMDctMzEpLA0KICAgICBjb3IudGVzdChQcm9zcGVyU2NvcmUuLm51bWVyaWMuLCBTdGF0ZWRNb250aGx5SW5jb21lLCBtZXRob2QgPSAncGVhcnNvbicpKQ0KYGBgDQpBcyBkZW1vbnN0cmF0ZWQgYnkgdGhlIHZpc3VhbGl6YXRpb24sIHRoZXJlIGlzIG5vIGNvcnJlbGF0aW9uIGJldHdlZW4gaW5jb21lIGFuZCBwcm9zcGVyIHNjb3JlLg0KDQoqKioNCiMjIyBEZW5zaXR5IHBsb3Qgb2YgRGVidFRvSW5jb21lUmF0aW8gYnkgU3RhdGVkTW9udGhseUluY29tZSBjb2xvcmVkIGJ5IERlbGlucXVlbnQgLSBNdWx0aXZhcmlhdGUNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Kc3VtbWFyeShzdWJzZXQocHJvc3BlciwgIWlzLm5hKFN0YXRlZE1vbnRobHlJbmNvbWUpKSRTdGF0ZWRNb250aGx5SW5jb21lKQ0Kc3VtbWFyeShzdWJzZXQocHJvc3BlciwgIWlzLm5hKERlYnRUb0luY29tZVJhdGlvKSkkRGVidFRvSW5jb21lUmF0aW8pDQpgYGANCg0KYGBge3IsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTksIGVjaG89RkFMU0V9DQpnZ3Bsb3QoZGF0YSA9IHN1YnNldChwcm9zcGVyLCBTdGF0ZWRNb250aGx5SW5jb21lIDw9IDE1MDAwICYNCiAgICAgICAgICAgICAgICAgICAgICAgRGVidFRvSW5jb21lUmF0aW8gPD0gMS4wKSwNCiAgICAgICBhZXMoeCA9IFN0YXRlZE1vbnRobHlJbmNvbWUsIHkgPSBEZWJ0VG9JbmNvbWVSYXRpbywNCiAgICAgICAgICAgY29sb3IgPSBEZWxpbnF1ZW50KSkgKw0KICBnZW9tX2RlbnNpdHlfMmQoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTUwMDAsIDI1MDApLCBsYWJlbHMgPSBkb2xsYXIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAwLjgsIDAuMSkpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygwLjE0LCAwLjIyLCAwLjMyKSwgY29sb3I9JyMwMDMzRkYnLA0KICAgICAgICAgICAgIGxpbmV0eXBlPTMsIHNpemUgPSAxKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMzIwMCwgNDY2NywgNjgxNyksIGNvbG9yPScjMDAzM0ZGJywNCiAgICAgICAgICAgICBsaW5ldHlwZT0zLCBzaXplID0gMSkgKw0KICBmYWNldF93cmFwKH5MaXN0aW5nQ3JlYXRpb25ZZWFyKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArDQogIGdndGl0bGUoJ0RlYnQgVG8gSW5jb21lIFJhdGlvIGJ5IFN0YXRlZCBNb250aGx5IEluY29tZScpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQp3aXRoKHN1YnNldChwcm9zcGVyLCAhaXMubmEoUHJvc3BlclNjb3JlKSksDQogICAgIGNvci50ZXN0KFN0YXRlZE1vbnRobHlJbmNvbWUsIERlYnRUb0luY29tZVJhdGlvLCBtZXRob2QgPSAncGVhcnNvbicpKQ0KYGBgDQpEZWJ0VG9JbmNvbWVSYXRpbyBoYXMgYmVlbiBsaW1pdGVkIHRvIGEgbWF4aW11bSBvZiAxIGFuZCBTdGF0ZWRNb250aGx5SW5jb21lIGhhcyBiZWVuIGxpbWl0ZWQgdG8gJDE1MDAwLiAgRXhjZXB0IGZvciAyMDE0IHRoZSBkaXN0cmlidXRpb24gb2YgZGVsaW5xdWVudCBhbmQgbm9uLWRlbGlucWVudCBhY2NvdW50cyBpcyB2ZXJ5IHNpbWlsYXIuICBUaGUgZG90dGVkIGJsdWUgbGluZXMgcmVwcmVzZW50IDFzdCBxdWFydGlsZSwgbWVkaWFuIGFuZCAzcmQgcXVhcnRpbGUgb3ZlcmFsbCBmb3IgdGhlIHJlc3BlY3RpdmUgYXhpcy4gIFRoZXJlIGlzIHNvbWUgdGVuZGVuY3kgZm9yIGxvd2VyIGluY29tZSBib3Jyb3dlcnMgdG8gaGF2ZSBhIGhpZ2hlciBkZWJ0IHRvIGluY29tZSByYXRpby4NCg0KKioqDQojIyMgRGVidFRvSW5jb21lUmF0aW8gYnkgTGlzdGluZ0NyZWF0aW9uWWVhciAtIE11bHRpdmFyaWF0ZQ0KYGBge3IsIGZpZy53aWR0aD0xMCwgZWNobz1GQUxTRX0NCmdncGxvdChzdWJzZXQocHJvc3BlciwgIWlzLm5hKEluY29tZVJhbmdlKSksDQogICAgICAgYWVzKHggPSBhcy5mYWN0b3IoTGlzdGluZ0NyZWF0aW9uWWVhciksIHkgPSBEZWJ0VG9JbmNvbWVSYXRpbykpICsNCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gYXMuZmFjdG9yKExpc3RpbmdDcmVhdGlvblllYXIpKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCAxKSkgKw0KICBmYWNldF93cmFwKH5JbmNvbWVSYW5nZSwgc2NhbGVzID0gJ2ZyZWVfeScpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lID0gJ0xpc3RpbmdcbkNyZWF0aW9uXG5ZZWFyJykgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKw0KICB4bGFiKCdMaXN0aW5nIENyZWF0aW9uIFllYXInKSArDQogIGdndGl0bGUoJ0RlYnQgdG8gSW5jb21lIFJhdGlvIGJ5IExpc3RpbmcgQ3JlYXRpb24gWWVhciAtIEluY29tZSBSYW5nZScpDQpgYGANCkFnYWluIERlYnQgdG8gSW5jb21lIFJhdGlvIGlzIGxpbWl0ZWQgdG8gMS4gIEV4Y2VwdCBmb3IgdGhlIHR3byBsb3dlc3QgaW5jb21lIHJhbmdlcywgYWNyb3NzIGFsbCB5ZWFycyB0aGUgbWVkaWFuIERlYnQgdG8gSW5jb21lIFJhdGlvIGlzIGJlbG93IDAuMjUgYW5kIGdldHMgbG93ZXIgdGhlIGdyZWF0ZXIgdGhlIGluY29tZSByYW5nZS4NCg0KKioqDQojIyMgPGEgaWQ9InAudXNlNiI+PC9hPlByb3NwZXJSYXRpbmcgYnkgUHJvc3BlclNjb3JlIC0gTXVsdGl2YXJpYXRlDQpgYGB7ciwgZmlnLndpZHRoPTksIGVjaG89RkFMU0V9DQpwLnVzZTYgPC0gZ2dwbG90KGRhdGEgPSBzdWJzZXQocHJvc3BlciwgIWlzLm5hKFByb3NwZXJTY29yZSkpLA0KICAgICAgIGFlcyhQcm9zcGVyU2NvcmUuLm51bWVyaWMuICogQ3JlZGl0U2NvcmVSYW5nZUxvd2VyLA0KICAgICAgICAgICBQcm9zcGVyUmF0aW5nLi5BbHBoYS4sIGNvbG9yID0gUHJvc3BlclNjb3JlKSkgKw0KICBnZW9tX2ppdHRlcihhbHBoYSA9IDEvMjApICsNCiAgZmFjZXRfd3JhcCh+TGlzdGluZ0NyZWF0aW9uWWVhcikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgeGxhYignUHJvc3BlciBTY29yZSAoUmlzaykgKiBDcmVkaXQgU2NvcmUgUmFuZ2UgTG93ZXInKSArDQogIHlsYWIoJ1Byb3NwZXIgUmF0aW5nJykgKw0KICBnZ3RpdGxlKCdQcm9zcGVyIFJhdGluZyBieSAoUHJvc3BlciBTY29yZSAqIENyZWRpdCBTY29yZSBSYW5nZSBMb3dlciknKQ0KDQpwLnVzZTYNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnllYXJzID0gc2VxKDIwMDksIDIwMTQsIDEpDQoNCmZvcih5IGluIHllYXJzKSB7DQogIHByaW50KHkpDQogIHJlc3VsdCA8LSB3aXRoKHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25ZZWFyID09IHkgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoUHJvc3BlclNjb3JlKSksDQogICAgICAgICAgICAgY29yLnRlc3QoUHJvc3BlclNjb3JlLi5udW1lcmljLiAqIENyZWRpdFNjb3JlUmFuZ2VMb3dlciwNCiAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKFByb3NwZXJSYXRpbmcuLkFscGhhLiksIG1ldGhvZCA9ICdwZWFyc29uJykpDQogIHByaW50KHJlc3VsdCRlc3RpbWF0ZSkNCn0NCmBgYA0KVGhlIFByb3NwZXIgdmFyaWFibGUgZGVmaW5pdGlvbnMgc3RhdGUsIFByb3NwZXJTY29yZSBpcyBhIHJpc2sgc2NvcmUuICBbUHJvc3BlclJhdGluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUHJvc3Blcl9NYXJrZXRwbGFjZSNQcm9zcGVyX1JhdGluZ3MpIGlzIGFuIGVzdGltYXRpb24gb2YgdGhlIGJvcnJvd2VyJ3MgZXN0aW1hdGVkIGxvc3MgcmF0ZSBhbmQgaXMgZGV0ZXJtaW5lZCBieSAoMSkgY3JlZGl0IHNjb3JlIGFuZCAoMikgUHJvc3BlciBTY29yZS4gIFByb3NwZXIgUmF0aW5ncywgZnJvbSBsb3dlc3QtcmlzayB0byBoaWdoZXN0LXJpc2ssIGFyZSBsYWJlbGVkIEFBLCBBLCBCLCBDLCBELCBFLCBhbmQgSFIgKCJIaWdoIFJpc2siKS4gIFRoZXJlIGlzIGEgc3Ryb25nIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGZvciBlYWNoIHllYXIuIFByb3NwZXIgbWF5IHVzZSBhIHNsaWdodGx5IGRpZmZlcmVudCBtZXRob2QgZm9yIGNvbWJpbmluZyBQcm9zcGVyU2NvcmUgJiBDcmVkaXRTY3JvcmVSYW5nZUxvd2VyLg0KDQpQcm9zcGVyIFJhdGluZ3xFc3RpbWF0ZWQgQXZlcmFnZSBBbm51YWwgTG9zcyBSYXRlDQotLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpBQSAgICAgICAgICAgIHwwLjAwLTEuOTklDQpBICAgICAgICAgICAgIHwyLjAwLTMuOTklDQpCICAgICAgICAgICAgIHw0LjAwLTUuOTklDQpDICAgICAgICAgICAgIHw2LjAwLTguOTklDQpEICAgICAgICAgICAgIHw5LjAwLTExLjk5JQ0KRSAgICAgICAgICAgICB8MTIuMDAtMTQuOTklDQpIUiAgICAgICAgICAgIHwxNS4wMCUrDQoNCltSZXRydW4gdG8gRmluYWwgUGxvdHMgJiBTdW1tYXJ5XSgjZmluYWwpDQoNCioqKg0KIyMgPGEgaWQ9ImxpbmVhcl9tb2RlbCI+PC9hPkxpbmVhciBNb2RlbCB0byBQcmVkaWN0IFByb3NwZXIgU2NvcmUNClRoaXMgaXMgbW9yZSBhIGRlbW9uc3RyYXRpb24gb2YgdGhlIGRpZmZpY3VsdGllcyBvZiB1c2luZyBhIGxpbmVhciBtb2RlbCB0byBwcmVkaWN0IGFuIG91dGNvbWUgd2hlbiB0aGVyZSBpcyBhIGxhcmdlIG51bWJlciBvZiB2YXJpYWJsZXMgdG8gY29uc2lkZXIuDQpgYGB7ciwgZWNobz1GQUxTRX0NCmxtb2RlbCA8LSBsbShQcm9zcGVyU2NvcmUuLm51bWVyaWMuIH4NCiAgICAgICAgICAgICAgIFRvdGFsSW5xdWlyaWVzICsNCiAgICAgICAgICAgICAgIEN1cnJlbnREZWxpbnF1ZW5jaWVzICsNCiAgICAgICAgICAgICAgIFRyYWRlc09wZW5lZExhc3Q2TW9udGhzICsNCiAgICAgICAgICAgICAgIEJhbmtjYXJkVXRpbGl6YXRpb24gKw0KICAgICAgICAgICAgICAgRGVidFRvSW5jb21lUmF0aW8gKw0KICAgICAgICAgICAgICAgZXhwKFJhdGlvX1BMX1BheV9PVCksDQogICAgICAgICAgICAgZGF0YSA9IHN1YnNldChwcm9zcGVyLCAhaXMubmEoUHJvc3BlclNjb3JlLi5udW1lcmljLikgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMaXN0aW5nQ3JlYXRpb25EYXRlIDw9ICcyMDExLTA0LTMwJyAmDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIExpc3RpbmdDcmVhdGlvbkRhdGUgPj0gJzIwMDgtMDQtMDEnKSkNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnN1bW1hcnkobG1vZGVsKQ0KbXRhYmxlKGxtb2RlbCkNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmdncGxvdChkYXRhID0gc3Vic2V0KHByb3NwZXIsICFpcy5uYShQcm9zcGVyU2NvcmUpKSwNCiAgICAgICBhZXMoeSA9IFByb3NwZXJTY29yZSwgeCA9IDkuMTg1ICsgKC0wLjA4NCkqVG90YWxJbnF1aXJpZXMgKw0KICAgICAgICAgICAgICAgKC0wLjM4OCkqQ3VycmVudERlbGlucXVlbmNpZXMgKw0KICAgICAgICAgICAgICAgKC0wLjQzMSkqQmFua2NhcmRVdGlsaXphdGlvbiArDQogICAgICAgICAgICAgICAoLTEuNDExKSpUcmFkZXNPcGVuZWRMYXN0Nk1vbnRocyArDQogICAgICAgICAgICAgICAoLTAuNzM3KSpEZWJ0VG9JbmNvbWVSYXRpbyArDQogICAgICAgICAgICAgICAoLTAuMTE2KSpleHAoUmF0aW9fUExfUGF5X09UKSwgY29sb3IgPSBQcm9zcGVyU2NvcmUpKSArDQogIGdlb21faml0dGVyKGFscGhhID0gMS8yMCkgKw0KICBnZW9tX2FibGluZShjb2xvciA9ICdwdXJwbGUnLCBzaXplID0gMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtNSwgMTApKSArDQogIHhsYWIoJ0xpbmVhciBNb2RlbCcpICsgeWxhYignUHJvc3BlciBTY29yZScpICsNCiAgZ2d0aXRsZSgnUHJvc3BlciBTY29yZSBieSBFeHBlcmltZW50YWwgTGluZWFyIE1vZGVsJykNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCnByb3NwZXJbYygzNDQsIDYwNywgNzU0KSxdDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQojIHVzZSByb3cgMzQ0LCA2MDcgYW5kIDc1NCBmb3IgdGVzdCBkYXRhDQoNCnRlc3QuZGF0YTEgPSBkYXRhLmZyYW1lKFRvdGFsSW5xdWlyaWVzID0gOSwNCiAgICAgICAgICAgICAgICAgICAgICAgQ3VycmVudERlbGlucXVlbmNpZXMgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICBCYW5rY2FyZFV0aWxpemF0aW9uID0gMC42LA0KICAgICAgICAgICAgICAgICAgICAgICBUcmFkZXNPcGVuZWRMYXN0Nk1vbnRocyA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgIERlYnRUb0luY29tZVJhdGlvID0gMC40NSwNCiAgICAgICAgICAgICAgICAgICAgICAgUmF0aW9fUExfUGF5X09UID0gMC43NSkNCg0KdGVzdC5kYXRhMiA9IGRhdGEuZnJhbWUoVG90YWxJbnF1aXJpZXMgPSAyLA0KICAgICAgICAgICAgICAgICAgICAgICBDdXJyZW50RGVsaW5xdWVuY2llcyA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgIEJhbmtjYXJkVXRpbGl6YXRpb24gPSAwLjMxLA0KICAgICAgICAgICAgICAgICAgICAgICBUcmFkZXNPcGVuZWRMYXN0Nk1vbnRocyA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgIERlYnRUb0luY29tZVJhdGlvID0gMC4xMywNCiAgICAgICAgICAgICAgICAgICAgICAgUmF0aW9fUExfUGF5X09UID0gMC45MDkpDQoNCnRlc3QuZGF0YTMgPSBkYXRhLmZyYW1lKFRvdGFsSW5xdWlyaWVzID0gNCwNCiAgICAgICAgICAgICAgICAgICAgICAgQ3VycmVudERlbGlucXVlbmNpZXMgPSAxMywNCiAgICAgICAgICAgICAgICAgICAgICAgQmFua2NhcmRVdGlsaXphdGlvbiA9IDAuODIsDQogICAgICAgICAgICAgICAgICAgICAgIFRyYWRlc09wZW5lZExhc3Q2TW9udGhzID0gMiwNCiAgICAgICAgICAgICAgICAgICAgICAgRGVidFRvSW5jb21lUmF0aW8gPSAwLjM3LA0KICAgICAgICAgICAgICAgICAgICAgICBSYXRpb19QTF9QYXlfT1QgPSAwLjg2NykNCg0KbW9kZWxFc3RpbWF0ZTEgPSBwcmVkaWN0KGxtb2RlbCwgbmV3ZGF0YSA9IHRlc3QuZGF0YTEsDQogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnZhbCA9ICdwcmVkaWN0aW9uJywgbGV2ZWwgPSAwLjk1KQ0KbW9kZWxFc3RpbWF0ZTIgPSBwcmVkaWN0KGxtb2RlbCwgbmV3ZGF0YSA9IHRlc3QuZGF0YTIsDQogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnZhbCA9ICdwcmVkaWN0aW9uJywgbGV2ZWwgPSAwLjk1KQ0KbW9kZWxFc3RpbWF0ZTMgPSBwcmVkaWN0KGxtb2RlbCwgbmV3ZGF0YSA9IHRlc3QuZGF0YTMsDQogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnZhbCA9ICdwcmVkaWN0aW9uJywgbGV2ZWwgPSAwLjk1KQ0KDQptb2RlbEVzdGltYXRlMQ0KbW9kZWxFc3RpbWF0ZTINCm1vZGVsRXN0aW1hdGUzDQpgYGANClRoZSBleHBlY3RlZCByZXN1bHQocykgYXJlIDYsIDEwLCBhbmQgMyBjb21wYXJlZCB0byB0aG9zZSByZWNlaXZlZCAoNi42LCA3Ljc2IGFuZCAxLjI0KS4gIFdlIGNhbiBzZWUgdGhlIHByZWRpY3RpdmUgcG93ZXIgb2YgdGhlIG1vZGVsIHJlcXVpcmVzIHJlZmluZW1lbnQuICBQZXJoYXBzIGl0IGNvdWxkIGJlIGltcHJvdmVkIGJ5IGFkZGluZyBtb3JlIHZhcmlhYmxlcyB0byB0aGUgbW9kZWwgb3IgdmFyaWFibGUgdHJhbnNmb3JtYXRpb24gKGkuZS4gJExvZ197MTB9KHZhcikkLCAkXHNxcnRbM117dmFyfSQsIGV0YykuICBNb3JlIGxpa2VseSwgdGhpcyBpcyBhbiBpbnN0YW5jZSB3aGVyZSBzdWNjZXNzIGNhbiBiZSBnYWluZWQgYnkgYXBwbHlpbmcgbWFjaGluZSBsZWFybmluZyBtZXRob2RvbG9naWVzLiAgVGhlIHZhcmlhYmxlcyBjaG9zZW4gYW5kIHRoZSBMaXN0aW5nQ3JlYXRpb25EYXRlIHVzZWQsIGNhbWUgZnJvbSBbUHJvc3BlciBTY29yZV0oaHR0cHM6Ly93d3cucHJvc3Blci5jb20vcGxwL2dlbmVyYWwtcHJvc3Blcl9zY29yZS8pLg0KDQoqKioNCiMjIDxhIGlkPSJmaW5hbCI+PC9hPkZpbmFsIFBsb3RzICYgU3VtbWFyeQ0KIyMjIFBsb3QgMQ0KW0NvZGUgUGxvdCAxXSgjcC51c2UxKQ0KYGBge3IsIGZpZy53aWR0aD05LCBlY2hvPUZBTFNFfQ0KcC51c2UxDQpgYGANClRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBQcm9wb3J0aW9uIERlbGlucXVlbnQgYW5kIHRoZSBncm91cGluZyBvZiB0aGUgeWVhcnMgY291bGQgYmUgYXR0cmlidXRhYmxlIHRvIHRoZSBsb2FuIHRlcm0gbGVuZ3RoLiBUaGUgbWFqb3JpdHkgb2YgbG9hbnMgaGF2ZSBhIHRlcm0gbGVuZ3RoIG9mIDMgeWVhcnMgYW5kIHNvbWUgZXh0ZW5kIHRvIDUgeWVhcnMuIEV4cGxpY2l0IGRhdGEgZm9yIHRoZSBmdWxsIGxvYW4gdGVybSBvbmx5IGV4aXN0cyBmb3IgbG9hbnMgb3JpZ2luYXRpbmcgZnJvbSAyMDA2IHVudGlsIDIwMDkuIEEgbW9zdGx5IGNvbXBsZXRlIHNldCBvZiBkYXRhIGV4aXN0aXMgZm9yIGxvYW5zIG9yaWdpbmlhdGluZyB0byAyMDExLiBBIGNvbmNsdWRpbmcgY29tcGFyaXNvbiBiZXR3ZWVuIGxvYW5zIGNyZWF0ZWQgZnJvbSAyMDEyIHdpdGggdGhvc2UgY3JlYXRlZCBwcmlvciB0byAyMDEyIGlzIG5vdCBmZWFzYWJsZSB3aXRoIHRoZSBhdmFpbGFibGUgZGF0YS4gQWRkaXRpb25hbGx5LCBQcm9zcGVyIGludHJvZHVjZWQgbmV3IG1ldGhvZHMgZm9yIGFzc2Vzc2luZyByaXNrIChQcm9zcGVyU2NvcmUpLCB3aGljaCBzdWJzZXF1ZW50bHkgaGVscGVkIHRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIGRlbGlucXVlbnQgYWNjb3VudHMuDQoNCg0KIyMjIFBsb3QgMg0KW0NvZGUgUGxvdCAyXSgjcC51c2UzKQ0KYGBge3IsIGZpZy53aWR0aD05LCBlY2hvPUZBTFNFfQ0KcC51c2UzDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQp5ZWFycyA9IHNlcSgyMDA5LCAyMDE0LCAxKQ0KZm9yKHkgaW4geWVhcnMpIHsNCiAgcHJpbnQoeSkNCiAgcmVzdWx0IDwtIHdpdGgoc3Vic2V0KHByb3NwZXIsIExpc3RpbmdDcmVhdGlvblllYXIgPT0geSAmDQogICAgICAgICAgICAgICAgICAgICAgICAgICFpcy5uYShQcm9zcGVyU2NvcmUpKSwNCiAgICAgICAgICAgICBjb3IudGVzdChCb3Jyb3dlclJhdGUsIEVzdGltYXRlZFJldHVybiwgbWV0aG9kID0gJ3BlYXJzb24nKSkNCiAgcHJpbnQocmVzdWx0JGVzdGltYXRlKQ0KfQ0KYGBgDQpBcyBzdGF0ZWQgaW4gdGhlIFByb3NwZXIgVmFyaWFibGUgRGVmaW5pdGlvbiBzcHJlYWRzaGVldCwgUHJvc3BlclNjb3JlIGlzIGEgY3VzdG9tIHJpc2sgc2NvcmUgYnVpbHQgdXNpbmcgaGlzdG9yaWNhbCBQcm9zcGVyIGRhdGEgYW5kIGlzIGFwcGxpY2FibGUgdG8gbG9hbnMgb3JpZ2luaWF0aW5nIGFmdGVyIDIwMDkvMDcvMzEuIDExIGFuZCAxIGFyZSB0aGUgbG93ZXN0IGFuZCBoaWdoZXN0IHJpc2sgcmVzcGVjdGl2ZWx5LiBUaGUgZGF0YSBzaG93IGxvd2VyIHJpc2sgYm9ycm93ZXJzIGhhdmUgYSBsb3dlciBCb3Jyb3dlclJhdGUuIEZvbGxvd2luZyAyMDEwLCB0aGVyZSdzIGEgc2lnbmlmaWNhbnQgcmVkdWN0aW9uIGluIHRoZSBudW1iZXIgb2YgaGlnaGVyIHJpc2sgbG9hbnMgYW5kIEVzdGltYXRlZCBSZXR1cm4gaXMgZ3JlYXRlciB0aGFuIDA7IG5vdGUgdGhlIGVzdGltYXRlZCBsb3NzZXMgaW4gMjAwOSBhbmQgMjAxMC4gIEJvcnJvd2VyIFJhdGUgaXMgYW4gaW5jcmVhc2luZ2x5IHN0cm9uZyBwcmVkaWN0b3Igb2YgRXN0aW1hdGVkIFJldHVybi4gDQoNCiMjIyBQbG90IDMNCltDb2RlIFBsb3QgM10oI3AudXNlNikNCmBgYHtyLCBmaWcud2lkdGg9OSwgZWNobz1GQUxTRX0NCnAudXNlNg0KYGBgDQpgYGB7ciwgZWNobz1GQUxTRX0NCnllYXJzID0gc2VxKDIwMDksIDIwMTQsIDEpDQoNCmZvcih5IGluIHllYXJzKSB7DQogIHByaW50KHkpDQogIHJlc3VsdCA8LSB3aXRoKHN1YnNldChwcm9zcGVyLCBMaXN0aW5nQ3JlYXRpb25ZZWFyID09IHkgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAhaXMubmEoUHJvc3BlclNjb3JlKSksDQogICAgICAgICAgICAgY29yLnRlc3QoUHJvc3BlclNjb3JlLi5udW1lcmljLiAqIENyZWRpdFNjb3JlUmFuZ2VMb3dlciwNCiAgICAgICAgICAgICAgICAgICAgICBhcy5udW1lcmljKFByb3NwZXJSYXRpbmcuLkFscGhhLiksIG1ldGhvZCA9ICdwZWFyc29uJykpDQogIHByaW50KHJlc3VsdCRlc3RpbWF0ZSkNCn0NCmBgYA0KUHJvc3BlclNjb3JlIGlzIGEgcmlzayBzY29yZSBmcm9tIDEgKGhpZ2hlc3QgcmlzaykgdG8gMTEgKGxvd2VzdCByaXNrKS4gIFtQcm9zcGVyUmF0aW5nXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Qcm9zcGVyX01hcmtldHBsYWNlI1Byb3NwZXJfUmF0aW5ncykgaXMgYW4gZXN0aW1hdGlvbiBvZiB0aGUgYm9ycm93ZXIncyBlc3RpbWF0ZWQgbG9zcyByYXRlIGFuZCBpcyBkZXRlcm1pbmVkIGJ5ICgxKSBjcmVkaXQgc2NvcmUgYW5kICgyKSBQcm9zcGVyIFNjb3JlLiAgUHJvc3BlciBSYXRpbmdzLCBmcm9tIGxvd2VzdC1yaXNrIHRvIGhpZ2hlc3QtcmlzaywgYXJlIGxhYmVsZWQgQUEsIEEsIEIsIEMsIEQsIEUsIGFuZCBIUiAoIkhpZ2ggUmlzayIpLiAgVGhlcmUgaXMgYSBzdHJvbmcgbmVnYXRpdmUgY29ycmVsYXRpb24gZm9yIGVhY2ggeWVhci4gIFByb3NwZXIgbWF5IHVzZSBhIHNsaWdodGx5IGRpZmZlcmVudCBtZXRob2QgZm9yIGNvbWJpbmluZyBQcm9zcGVyU2NvcmUgJiBDcmVkaXRTY3JvcmVSYW5nZUxvd2VyLg0KDQpQcm9zcGVyIFJhdGluZ3xFc3RpbWF0ZWQgQXZlcmFnZSBBbm51YWwgTG9zcyBSYXRlDQotLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpBQSAgICAgICAgICAgIHwwLjAwLTEuOTklDQpBICAgICAgICAgICAgIHwyLjAwLTMuOTklDQpCICAgICAgICAgICAgIHw0LjAwLTUuOTklDQpDICAgICAgICAgICAgIHw2LjAwLTguOTklDQpEICAgICAgICAgICAgIHw5LjAwLTExLjk5JQ0KRSAgICAgICAgICAgICB8MTIuMDAtMTQuOTklDQpIUiAgICAgICAgICAgIHwxNS4wMCUrDQoNCioqKg0KIyMgUmVmbGVjdGlvbg0KVGhlIGluaXRpYWwgZGlyZWN0aW9uIG9mIHRoZSBpbnZlc3RpZ2F0aW9uIHdhcyBhbiBhdHRlbXB0IHRvIGFzY2VydGFpbiB3aGljaCBtZXRyaWNzIHdlcmUgbW9zdCBhdHRyaWJ1dGFibGUgdG8gZGVsaW5xdWVuY3kuICBJdCBxdWlja2x5IGJlY2FtZSBhcHBhcmVudCB0aGF0IHllYXJseSBjaGFuZ2VzIG1hZGUgZm9yIG1vcmUgaW50ZXJlc3Rpbmcgb2JzZXJ2YXRpb25zLiAgQW4gaW1wb3J0YW50IG9ic2VydmF0aW9uIHdhcyB0aGF0IHVuaXZhcmlhdGUgdmlzdWFsaXphdGlvbnMgb2ZmZXJlZCB2ZXJ5IGxpdHRsZSBjYXRlZ29yaWNhbCBpbnNpZ2h0IHVudGlsIGZhY2V0IHdyYXBwZWQgYnkgbGlzdGluZyBjcmVhdGlvbiB5ZWFyLiAgVGhlIGRhdGEgc2V0IGJlZ2lucyB3aXRoIHRoZSBpbmNlcHRpb24gb2YgUHJvc3BlciBhbmQgc3BhbnMgc2V2ZXJhbCB0dW11bHR1b3VzIHllYXJzIGZvciBmaW5hbmNpYWwgbWFya2V0cyBpbiBnZW5lcmFsLCBhbmQgZm9yIFByb3NwZXJzJyBidXNpbmVzcyBtb2RlbC4gIEV4Y2VwdCBQbG90IDIsIHRoZSBmaW5hbCB2aXN1YWxpemF0aW9ucyBkZW1vbnN0cmF0ZSBzaWduaWZpY2FudCB5ZWFyLW92ZXIteWVhciBjaGFuZ2UuICBUaGUgbW9zdCBzaWduaWZpY2FudCBjaGFuZ2UsIHNlZW1zIHRvIGJlIHRoZSBtZXRob2QgYnkgd2hpY2ggUHJvc3BlciBldmFsdWF0ZXMgcmlzaywgYnkgYWRkaW5nIFByb3NwZXIgU2NvcmUgaW4gMjAwOS4gIEFkZGl0aW9uYWxseSwgbGFjayBvZiBidXNpbmVzcywgbGlrZWx5IGF0dHJpYnV0YWJsZSB0byB0aGUgMjAwNyByZWNlc3Npb24sIGlzIGV2aWRlbnQsIGFzIGlzIHRoZSAyMDA4LTIwMDkgY2Vzc2F0aW9uIG9mIGxlbmRpbmcgY2F1c2UgYnkgcmVndWxhdG9yeSBjaGFuZ2VzLg0KDQpUaGUgYXR0ZW1wdCB0byBtb2RlbCB0aGUgUHJvc3BlciBTY29yZSB3aXRoIHRoaXMgW0xpbmVhciBNb2RlbF0oI2xpbmVhcl9tb2RlbCkgd2FzIHVuc3VjY2Vzc2Z1bC4gIE15IGFwcHJvYWNoIHdhcyB0byBpbnRyb2R1Y2UgdHJhbnNmb3JtYXRpb25zIHRvIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgaW4gaG9wZXMgb2YgY3JlYXRpbmcgYSBzdHJvbmdlciBkZWxpbmVhdGlvbiBiZXR3ZWVuIGVhY2ggZmFjdG9yIG9mIFByb3NwZXIgU2NvcmUuICBTcGVjaWZpY2FsbHksICRmKHgpICA9IGVeeCQgd2FzIHVzZWQgdG8gbWl0aWdhdGUgdGhlIGludHJvZHVjdGlvbiBvZiBhIDAgZmFjdG9yIGludG8gdGhlIG1vZGVsLiAgUGVyaGFwcyBpdCB3aWxsIGJlIGFuIGluc3RydWN0aXZlIGVuZGV2b3VyIHRvIGFwcGx5IG1hY2hpbmUgbGVhcm5pbmcgdG8gdGhpcyBkYXRhLXNldCBmb2xsb3dpbmcgdGhhdCBjbGFzcy4NCg0KQXMgc3RhdGVkIHByZXZpb3VzbHksIEkgc3RydWdnbGVkIGFuZCB3YXMgdWx0aW1hdGx5IHVuc3VjY2Vzc2Z1bCBpbiBhY2N1cmF0bHkgbW9kZWxpbmcgdGhlIFByb3NwZXIgU2NvcmUuICANCg0KSSBlbmpveWVkIGEgbW9kaWN1bSBvZiBzdWNjZXNzIHdpdGggdGhlIHN0cm9uZyBjb3JyZWNsYXRpb24gc2hvd24gYmV0d2VlbiBQcm9zcGVyIFJhdGluZyBhbmQgdGhlIGNvbWJpbmVkIG1ldHJpYyBvZiBQcm9zcGVyIFNjb3JlICogQ3JlZGl0IFNjb3JlLg0KDQoqKioNCiMjIFJlZmVyZW5jZXMNCg0KMS4gW1JEb2N1bWVudGF0aW9uIC0gSFRNTCBOb3RlYm9va10oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3JtYXJrZG93bi92ZXJzaW9ucy8xLjgvdG9waWNzL2h0bWxfbm90ZWJvb2spDQoyLiBbUiBNYXJrZG93biAtIEhUTUwgRG9jdW1lbnRzXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2h0bWxfZG9jdW1lbnRfZm9ybWF0Lmh0bWwpDQozLiBbUi1ibG9nZ2VyczogT3JkaWFuYXJ5IExlYXN0IFNxdWFyZXMgUmVncmVzc2lvbl0oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vb3JkaW5hcnktbGVhc3Qtc3F1YXJlcy1vbHMtbGluZWFyLXJlZ3Jlc3Npb24taW4tci8pDQo0LiBbUiBHcmFwaGljcyBDb29rYm9va10oaHR0cDovL3d3dy5jb29rYm9vay1yLmNvbSkNCjUuIFtXaWtpcGVkaWFdKGh0dHBzOi8vd3d3Lndpa2lwZWRpYS5vcmcvKQ0KNi4gW1Byb3NwZXIgU2NvcmVdKCNodHRwczovL3d3dy5wcm9zcGVyLmNvbS9wbHAvZ2VuZXJhbC1wcm9zcGVyX3Njb3JlLykNCg0KDQoNCg==