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

Reformat Income Range

Create a more refined view of income range based upon StatedMonlyIncome * 12

prosper$IncomeRange_old <- prosper$IncomeRange
prosper$IncomeRange <- cut(prosper$CalcYearlyIncome, dig.lab = 10,
                           breaks = c(0, 10000, 20000, 30000, 40000, 50000,
                                      60000, 70000, 80000, 90000, 100000,
                                      200000, 21000036.))

Reformat Date categories as.Date

prosper$ListingCreationDate <- as.Date(prosper$ListingCreationDate,
                                       format = '%Y-%m-%d')
prosper$ListingCreationYear <- year(prosper$ListingCreationDate)

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

Mean Proportion Delinquent by Income Range - Bivariate

Note the difference between Mean Proportion Delinquent by Income Range - Bivariate and Proportion Delinquent by Income Range - Bivariate. The mean proportion delinquent demonstrates less variance across income ranges. The mean is of the ProportionDelinquent by IncomeRange for each ListingCreationYear.


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.

Prosper Rating Estimated Average Annual Loss Rate
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.

Prosper Rating Estimated Average Annual Loss Rate
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==