Motivation

I would like to come up with an investing strategy for Prosper, a peer-to-peer lending platform. Unlike Lending Club, Prosper has no gross income or net worth requirements for the state of Florida.

Data Source

The data was offered by Udacity for a project in one of their courses. You can find it here or here. Although I did not take the course myself, I find the data very useful, indeed, and am very grateful to Udacity for making it available!

Github repository

The Prosper dataset and the R notebook are here.

Data exploration

Going through the dataset dictionary here or here, I want to better acquaint myself with the data, since I have never either borrowed or lent on a peer-to-peer lending platform.

Start by loading the data:

loans <- read.csv("prosperLoanData.csv")

How large is our dataset?

cat("We have", dim(loans)[1], "observations of", dim(loans)[2], "variables.")
We have 113937 observations of 81 variables.

We can use histograms and barplots to get an idea of how some of the key variables are distributed. The following code generates the histogram for the loan amounts.

library(ggplot2)
theme_set(theme_gray(base_size = 10))
loan_amount_hist <- ggplot(loans, aes(LoanOriginalAmount)) + geom_histogram(binwidth=750, fill="#E69F00", colour="black") + xlim(2500,25000)
loan_amount_hist <- loan_amount_hist + xlab("Amount borrowed (USD)") + ylab("Number of loans") + ggtitle("Histogram of loan amounts")
loans_median_amount <- median(loans$LoanOriginalAmount)
loan_amount_hist <- loan_amount_hist + geom_vline(xintercept=loans_median_amount)
loan_amount_hist <- loan_amount_hist + annotate("text", x = loans_median_amount + 4800, y = 17000, label = paste("Median =",loans_median_amount, "USD"), size=3)

We can do similarly for other variables. I will not show the code here as it’s repetitive.

We can plot multiple graphs in an array using Winston Chang’s multiplot().

multiplot(loan_amount_hist, loan_rate_hist, loan_income_hist, loan_credit_scores_hist, cols=2)

The median income of potential borrowers is pretty healthy at $56,000/year. The median credit score is pretty close to 700, and in fact almost half (~47%) of the records have a credit score of 700 or higher. Mind, this is using the lowest credit score reported, as given by the variable CreditScoreRangeLower. The median interest, at 18.4%, seems really high but since the loans are typically for relatively short terms (see below) it might turn out to be not too onerous on borrowers. A $6,500 loan (the median amount requested) at 18.4% paid over 3 years will pay about $2,000 in interest in addition to the principal.

Variables related to credit utilization:

Other variables of interest:

About 75% of loans are 3-year loans. Similarly, about 75% of applicants have no delinquencies on their current accounts, which we would expect, and about 75% of them have had their credit pulled two or fewer times in the last 6 months. Home ownership is evenly split among applicants.

Data munging

Response variable

The response variable, LoanStatus, has several outcomes:

table(loans$LoanStatus)

             Cancelled             Chargedoff              Completed                Current 
                     5                  11992                  38074                  56576 
             Defaulted FinalPaymentInProgress   Past Due (>120 days)   Past Due (1-15 days) 
                  5018                    205                     16                    806 
 Past Due (16-30 days)  Past Due (31-60 days)  Past Due (61-90 days) Past Due (91-120 days) 
                   265                    363                    313                    304 

We would like to use a binomial model, so we will label all the loans that are either “Completed” or “Current” with a ‘1’ and loans that were charged off or in which the borrowed defaulted or is somehow late will be labelled with a ‘0’.

#Convert to character and back to factor
#http://programming-r-pro-bro.blogspot.com/2013/04/editingadding-factor-levels-in-r.html
loans$LoanStatus <- as.character(loans$LoanStatus)
#Usage of grepl to test if sub-string in string
#http://stackoverflow.com/questions/10128617/test-if-characters-in-string-in-r
loans$LoanStatus[loans$LoanStatus == "Cancelled" | loans$LoanStatus == "Chargedoff" | loans$LoanStatus == "Defaulted" | grepl("Past Due", loans$LoanStatus)] <- "0"
loans$LoanStatus[loans$LoanStatus == "Completed" | loans$LoanStatus == "Current" | loans$LoanStatus == "FinalPaymentInProgress" ] <- "1"
loans$LoanStatus <- as.factor(loans$LoanStatus)
table(loans$LoanStatus)

    0     1 
19082 94855 

About 83% of the loans are in good status.

Predictors

We will base our choice of predictors based on several factors. One is our familiarity with the data, e.g., we expect income and credit score to be good predictors of a borrower’s ability to repay a loan. We will leave out predictors that are likely to be heavily correlated with another we did include, e.g., take CreditScoreRangeLower and leave out CreditScoreRangeUpper. We will also leave out predictors we are not familiar with, e.g. trades.

We will use the following predictors:

Term, the length of the loan: 12, 36, or 60 months

BorrowerRate, the interest rate of the loan

CreditScoreRangeLower, the borrower’s lowest reported credit score

DebtToIncomeRatio, self-explanatory

EmploymentStatusDuration, how long has the borrower been at his current employment, in months

IsBorrowerHomeowner, self-explanatory, true or false

CurrentCreditLines, number of current credit lines at the time the credit profile was pulled.

TotalCreditLinespast7years, number of credit lines in the past seven years at the time the credit profile was pulled.

OpenRevolvingAccounts, number of borrower’s open accounts

OpenRevolvingMonthlyPayment, total monthly payment on open accounts

InquiriesLast6Months, number of credit inquiries in the last 6 months

TotalInquiries, total number of credit inquiries (all-time?)

CurrentDelinquencies, number of accounts delinquent at the time the credit profile was pulled

AmountDelinquent, total current dollar amount of delinquencies

DelinquenciesLast7Years, number of deliquencies in the last 7 years

PublicRecordsLast10Years, number of public records in the last 10 years

PublicRecordsLast12Months, number of public records in the last year

RevolvingCreditBalance, total dollar amount carried from one month to the next

BankcardUtilization, the percentage of available revolving credit that is utilized

AvailableBankcardCredit, total available credit via credit cards

IncomeVerifiable, whether borrower stated he/she had evidence to support the stated income

StatedMonthlyIncome, the borrower’s monthly income

Some of these predictors have missing data, several thousand of them in some cases. Rather than ignoring them, we try to impute them simply by sampling. I also tried the mice library, but it takes several minutes to run on a dataset as large as this one, even when I used the method ‘norm’.

#Replacing NA's in CreditScoreRangeLower:
#Getting number of NA's
num_NA <- length(loans$CreditScoreRangeLower[is.na(loans$CreditScoreRangeLower)])
#Sampling CreditScoreRangeLower
set.seed(123)#reproducibility
sample_vector <- sample(x=loans$CreditScoreRangeLower[!is.na(loans$CreditScoreRangeLower)], size=num_NA)
#Replace
loans$CreditScoreRangeLower[is.na(loans$CreditScoreRangeLower)] <- sample_vector

We can do similarly for the other predictors that have missing data. It’s pretty repetitive, so it will not be shown here.

Building the logistic regression model

First, a little more data munging

We can try to see what happens if we ask R to generate the logistic regression model using glm().

predictors_vector <- c("Term", "BorrowerRate", "CreditScoreRangeLower", "DebtToIncomeRatio", "EmploymentStatusDuration", "IsBorrowerHomeowner", "CurrentCreditLines", "TotalCreditLinespast7years", "OpenRevolvingAccounts", "OpenRevolvingMonthlyPayment", "InquiriesLast6Months", "TotalInquiries", "CurrentDelinquencies", "AmountDelinquent", "DelinquenciesLast7Years", "PublicRecordsLast10Years", "PublicRecordsLast12Months", "RevolvingCreditBalance", "BankcardUtilization", "AvailableBankcardCredit", "IncomeVerifiable", "StatedMonthlyIncome")
predictors_vector_sum <- paste(predictors_vector, collapse="+")
logReg_model_fmla <- as.formula(paste("LoanStatus ~ ", predictors_vector_sum))
logReg_model <- glm(logReg_model_fmla, data=loans, family=binomial)
glm.fit: fitted probabilities numerically 0 or 1 occurred

R returns a warning: glm.fit: fitted probabilities numerically 0 or 1 occurred. This has to do with being able to perfectly separate the response based on the value of the predictors. In fact, if we try to generate a model using just the predictor StatedMonthlyIncome, we get the same warning.

temp_model <- summary(glm(LoanStatus ~ StatedMonthlyIncome, data=loans, family=binomial))
Warning: glm.fit: fitted probabilities numerically 0 or 1 occurred

Among the possible solutions to this issue, binning the predictor values seems like the easiest thing to do.

Let’s start with StatedMonthlyIncome. We can try to split StatedMonthlyIncome into $1,000 bins using cut().

Monthly_Income_Ranges <- c("$0 - $1,999", "$2,000 - $2,999", "$3,000 - $3,999", "$4,000 - $4,999", "$5,000 - $5,999", "$6,000 - $6,999", "$7,000 - $7,999", "$8,000 - $8,999", "$9,000 - $9,999", "$10,000 - $10,999", "$11,000 - $11,999", "$12,000 - $12,999", "$13,000 - $13,999", "$14,000 - $14,999", "$15,000 or more")
loans$StatedMonthlyIncome <- cut(loans$StatedMonthlyIncome, c(-Inf, seq(2000,15000,1000), Inf), labels=Monthly_Income_Ranges, right=F)

We can bin other variables as well. I will skip the actual code since it’s very similar to what we just did for StatedMotnhlyIncome. The following variables will be binned: InquiriesLast6Months, TotalInquiries, CurrentDelinquencies, AmountDelinquent, DelinquenciesLast7Years, PublicRecordsLast10Years, and PublicRecordsLast12Months.

We can try again:

logReg_model <- glm(logReg_model_fmla, data=loans, family=binomial)

We no longer get the glm.fit warning.

Using summary(logReg_model), we note that some of the predictors were found to be not statistically significant in determining the probability of a loan being repaid. These were PublicRecordsLast12Months, AmountDelinquent, TotalCreditLinespast7years, and DelinquenciesLast7Years. This might have been because they are related to other predictors in the model and thus add little of value to it. Let’s remove them from our model formula:

remove_predictors <- c ("PublicRecordsLast12Months", "AmountDelinquent", "TotalCreditLinespast7years", "DelinquenciesLast7Years")
predictors_vector <- setdiff(predictors_vector, remove_predictors)
predictors_vector_sum <- paste(predictors_vector, collapse="+")
logReg_model_fmla <- as.formula(paste("LoanStatus ~ ", predictors_vector_sum))

Training and testing the model

Splitting the dataset into training and testing sets

Let’s split the data into training and test sets, using the library caTools()

library(caTools)
set.seed(144)
spl = sample.split(loans$LoanStatus, 0.7)
train_set = subset(loans, spl == TRUE)
test_set = subset(loans, spl == FALSE)

Confusion matrix and model accuracy

Training the model on the split dataset, we can tabulate the confusion matrix by evaluating the model performance on the test set, using a threshold for labelling the loans of 0.5:

logReg_model <- glm(logReg_model_fmla, data=train_set, family=binomial)
# Evaluate the performance on test dataset
# test_set$predicted.risk is a vector of probabilities
# According to our model, the higher the probability the more likely the loan will be good
test_set$predicted.risk = predict(logReg_model, newdata=test_set, type="response")
#Confusion Matrix using a threshold of 0.5
threshold = 0.5
confusion_matrix <- table(test_set$LoanStatus, as.numeric(test_set$predicted.risk >= threshold))
confusion_matrix
   
        0     1
  0  1036  4689
  1   692 27765

The rows in the confusion matrix represent the “truth”. We have 1036 + 4689 = 5725 total bad loans, of which 4689 were labelled, incorrectly, as good loans. That’s over 80% of the bad loans that were labelled as good. This is our False Positive Rat, or FPR. Similarly, there are 692 + 27765 = 28457 total good loans, of which 27765 were labelled, correctly, as good loans. Over 97% of the good loans were labelled correctly. This is our True Positive Rate, or TPR. We will see shortly how the choice of threshold allows us to trade FPR with TPR.

Using the confusion matrix, we can compute the accuracy of our model on the test set as the ratio of loans that were labelled correctly divided by the total number of loans. Here we have 1036 + 27765 = 28801 loans that were labelled correctly, out of a total of 34182 loans in the test set, so the accuracy is 0.842578.

ROC curve and AUC

The ROC (Receiver Operator Characteristic) curve plots the True Positive Rate (TPR) versus the False Positive Rate (FPR). The TPR is the fraction of good loans in the test set that were labelled correctly (1), whereas the FPR is the fraction of bad loans that were labelled, incorrectly, as good. It allows us to visualize how the choice of threshold allows us to trade off TPR with FPR.

library(ROCR)
ROCRpred = prediction(test_set$predicted.risk, test_set$LoanStatus)
# Performance function
ROCRperf = performance(ROCRpred, "tpr", "fpr")
# Plot ROC curve
plot(ROCRperf, colorize=TRUE, print.cutoffs.at=seq(0,1,by=0.1), text.adj=c(-0.2,1.7))
grid()

We can compute the area under the ROC curve, or AUC:

#AUC
AUC <- as.numeric(performance(ROCRpred, "auc")@y.values)
AUC
[1] 0.7698326

We want the AUC to be significantly larger than 0.5.

Exploring different thresholds

We can see that using a threshold of 0.5 to label the loans would just about “catch” all the good loans since the TPR is almost 1.0, but it also means we have to eat more than 80% of the bad loans. A choice of threshold of 0.8 or even 0.7 would lead to catching 80% or more of the good loans while discarding between 40% and 60% of the bad ones Let’s try using a threshold of 0.8:

threshold2 = 0.8
confusion_matrix2 <- table(test_set$LoanStatus, as.numeric(test_set$predicted.risk >= threshold2))
confusion_matrix2
   
        0     1
  0  3385  2340
  1  5960 22497

We can see that choosing a threshold of 0.8 means we would pass on, i.e., not invest in, 5960 good loans. Our TPR is lower: 79%, versus more than 97% with a threshold of 0.5. However, the FPR is much better now, as we are only mislabelling ~40% of the bad loans, versus more than 80% with the 0.5 threshold. Although our accuracy has dropped from 84% to about 75%, I think using a threshold of 0.8 or 0.7 is preferable to using 0.5.

Cross-validation

We can use the caret package to perform k-fold cross-validation. The data is split in k folds and the model is generated using k-1 folds of the data as a training set, and tested on the remaining fold. This is done k times, once for each fold. caret computes and reports the accuracy of the model each time. We can compare the accuracies with the 70-30 split of the data we did earlier.

For logistic regression, caret uses a hardwired threshold of 0.5 to compute the accuracy. Although we cannot change it, we can cross-check the accuracy numbers it reports with what we got earlier using a threshold of 0.5.

Experience has shown that 10-fold cross-validation gives the best estimate of error, so we will use k=10 folds.

library(caret)
fitControl = trainControl( method = "cv", number = 10, p = 0.70 )
logReg_model_cv <- train(logReg_model_fmla, data=train_set, method = "bayesglm", trControl = fitControl)
logReg_model_cv$resample$Accuracy
 [1] 0.8450351 0.8427586 0.8420063 0.8454112 0.8429897 0.8440321 0.8416499 0.8410231 0.8437813
[10] 0.8466458

We see that the model accuracy is about 84% each time, which matches what we did earlier using a 0.5 threshold.

References

  1. R Notebooks. Retrieved from http://rmarkdown.rstudio.com

  2. Prosper loan data. Retrieved from https://docs.google.com

  3. Prosper loan data - variable definitions. Retrieved from https://docs.google.com

  4. Lending Club State and Financial Suitability conditions. Retrieved from https://help.lendingclub.com

  5. Prosper State Financial Suitability Requirements. Retrieved from https://www.prosper.com

  6. Chang, Winston. Cookbook for R. Sebastopol: O’Reilly Media, 2013. Retrieved from http://www.cookbook-r.com/

  7. MaikelS. Set NA to 0 in R. Retrieved from http://stackoverflow.com.

  8. mike and smu. Test if characters in string in R. Retrieved from http://stackoverflow.com.

  9. Shreyes. Editing/Adding factor levels in R. Retrieved from http://programming-r-pro-bro.blogspot.com

  10. Harding, Ted. glm.fit: fitted probabilities numerically 0 or 1 occurr. Retrieved from https://stat.ethz.ch

  11. user333 and Scortchi. How to deal with perfect separation in logistic regression? Retrieved from http://stats.stackexchange.com

  12. grautur and juba. how to succinctly write a formula with many variables from a data frame? Retrieved from http://stackoverflow.com.

  13. Bertsimas, D., O’Hair, A. The Analytics Edge. Spring 2014. edX.org.

  14. jeannot and Luciano Selzer. How to change the default font size in ggplot2. Retrieved from http://stackoverflow.com.

  15. Dail and Brian Diggs. How to delete multiple values from a vector?. Retrieved from http://stackoverflow.com.

  16. Witten, I., Frank, E., Hall, M. Data Mining: Practical Machine Learning Tools and Techniques, Third Edition. Burlington: Elsevier, 2011. PDF.

  17. Çetinkaya-Rundel, M. Data Analysis and Statistical Inference. Spring 2014. www.coursera.org.

LS0tDQp0aXRsZTogIlByZWRpY3RpbmcgdGhlIHBlcmZvcm1hbmNlIG9mIFByb3NwZXIgbG9hbnMgdXNpbmcgbG9naXN0aWMgcmVncmVzc2lvbiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiNNb3RpdmF0aW9uDQpJIHdvdWxkIGxpa2UgdG8gY29tZSB1cCB3aXRoIGFuIGludmVzdGluZyBzdHJhdGVneSBmb3IgW1Byb3NwZXJdKGh0dHA6Ly93d3cucHJvc3Blci5jb20pLCBhIHBlZXItdG8tcGVlciBsZW5kaW5nIHBsYXRmb3JtLiBVbmxpa2UgW0xlbmRpbmcgQ2x1Yl0oaHR0cHM6Ly9oZWxwLmxlbmRpbmdjbHViLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMTYwOTI5NTctV2hhdC1hcmUtdGhlLWN1cnJlbnQtU3RhdGUtYW5kLUZpbmFuY2lhbC1TdWl0YWJpbGl0eS1jb25kaXRpb25zLSksIFtQcm9zcGVyXShodHRwczovL3d3dy5wcm9zcGVyLmNvbS9wbHAvbGVnYWwvZmluYW5jaWFsLXN1aXRhYmlsaXR5LykgaGFzIG5vIGdyb3NzIGluY29tZSBvciBuZXQgd29ydGggcmVxdWlyZW1lbnRzIGZvciB0aGUgc3RhdGUgb2YgRmxvcmlkYS4NCg0KI0RhdGEgU291cmNlDQpUaGUgZGF0YSB3YXMgb2ZmZXJlZCBieSBbVWRhY2l0eV0oaHR0cDovL3d3dy51ZGFjaXR5LmNvbSkgZm9yIGEgcHJvamVjdCBpbiBvbmUgb2YgdGhlaXIgY291cnNlcy4gWW91IGNhbiBmaW5kIGl0IFtoZXJlXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9kb2N1bWVudC9kLzFxRWN3bHRCTWxSWVpULWw2OTktNzFUekluV2ZrNFc5cTVyVENTdkRWTXBjL3B1Yj9lbWJlZGRlZD10cnVlKSBvciBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2pvYXNoeHUvcHJvc3Blci1sb2FuLWRhdGEvdHJlZS9tYXN0ZXIvZGF0YXNldCkuIEFsdGhvdWdoIEkgZGlkIG5vdCB0YWtlIHRoZSBjb3Vyc2UgbXlzZWxmLCBJIGZpbmQgdGhlIGRhdGEgdmVyeSB1c2VmdWwsIGluZGVlZCwgYW5kIGFtIHZlcnkgZ3JhdGVmdWwgdG8gVWRhY2l0eSBmb3IgbWFraW5nIGl0IGF2YWlsYWJsZSENCg0KIyMgR2l0aHViIHJlcG9zaXRvcnkNClRoZSBQcm9zcGVyIGRhdGFzZXQgYW5kIHRoZSBSIG5vdGVib29rIGFyZSBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2Nhcmxvc3Jvci9wcm9zcGVyX2xvYW5zKS4NCg0KI0RhdGEgZXhwbG9yYXRpb24NCkdvaW5nIHRocm91Z2ggdGhlIGRhdGFzZXQgZGljdGlvbmFyeSBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2pvYXNoeHUvcHJvc3Blci1sb2FuLWRhdGEvdHJlZS9tYXN0ZXIvZGF0YXNldCkgb3IgW2hlcmVdKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFnRHlpX0w0VXZJckxURUM2V3JpNW5iYU1ta0dtTFFCay1ZeDN6MFhERXRJL2VkaXQjZ2lkPTApLCBJIHdhbnQgdG8gYmV0dGVyIGFjcXVhaW50IG15c2VsZiB3aXRoIHRoZSBkYXRhLCBzaW5jZSBJIGhhdmUgbmV2ZXIgZWl0aGVyIGJvcnJvd2VkIG9yIGxlbnQgb24gYSBwZWVyLXRvLXBlZXIgbGVuZGluZyBwbGF0Zm9ybS4NCjxici8+ICANClN0YXJ0IGJ5IGxvYWRpbmcgdGhlIGRhdGE6DQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxvYW5zIDwtIHJlYWQuY3N2KCJwcm9zcGVyTG9hbkRhdGEuY3N2IikNCmBgYA0KSG93IGxhcmdlIGlzIG91ciBkYXRhc2V0Pw0KYGBge3J9DQpjYXQoIldlIGhhdmUiLCBkaW0obG9hbnMpWzFdLCAib2JzZXJ2YXRpb25zIG9mIiwgZGltKGxvYW5zKVsyXSwgInZhcmlhYmxlcy4iKQ0KYGBgDQoNCldlIGNhbiB1c2UgaGlzdG9ncmFtcyBhbmQgYmFycGxvdHMgdG8gZ2V0IGFuIGlkZWEgb2YgaG93IHNvbWUgb2YgdGhlIGtleSB2YXJpYWJsZXMgYXJlIGRpc3RyaWJ1dGVkLiBUaGUgZm9sbG93aW5nIGNvZGUgZ2VuZXJhdGVzIHRoZSBoaXN0b2dyYW0gZm9yIHRoZSBsb2FuIGFtb3VudHMuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KdGhlbWVfc2V0KHRoZW1lX2dyYXkoYmFzZV9zaXplID0gMTApKQ0KbG9hbl9hbW91bnRfaGlzdCA8LSBnZ3Bsb3QobG9hbnMsIGFlcyhMb2FuT3JpZ2luYWxBbW91bnQpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTc1MCwgZmlsbD0iI0U2OUYwMCIsIGNvbG91cj0iYmxhY2siKSArIHhsaW0oMjUwMCwyNTAwMCkNCmxvYW5fYW1vdW50X2hpc3QgPC0gbG9hbl9hbW91bnRfaGlzdCArIHhsYWIoIkFtb3VudCBib3Jyb3dlZCAoVVNEKSIpICsgeWxhYigiTnVtYmVyIG9mIGxvYW5zIikgKyBnZ3RpdGxlKCJIaXN0b2dyYW0gb2YgbG9hbiBhbW91bnRzIikNCmxvYW5zX21lZGlhbl9hbW91bnQgPC0gbWVkaWFuKGxvYW5zJExvYW5PcmlnaW5hbEFtb3VudCkNCmxvYW5fYW1vdW50X2hpc3QgPC0gbG9hbl9hbW91bnRfaGlzdCArIGdlb21fdmxpbmUoeGludGVyY2VwdD1sb2Fuc19tZWRpYW5fYW1vdW50KQ0KbG9hbl9hbW91bnRfaGlzdCA8LSBsb2FuX2Ftb3VudF9oaXN0ICsgYW5ub3RhdGUoInRleHQiLCB4ID0gbG9hbnNfbWVkaWFuX2Ftb3VudCArIDQ4MDAsIHkgPSAxNzAwMCwgbGFiZWwgPSBwYXN0ZSgiTWVkaWFuID0iLGxvYW5zX21lZGlhbl9hbW91bnQsICJVU0QiKSwgc2l6ZT0zKQ0KYGBgDQogV2UgY2FuIGRvIHNpbWlsYXJseSBmb3Igb3RoZXIgdmFyaWFibGVzLiBJIHdpbGwgbm90IHNob3cgdGhlIGNvZGUgaGVyZSBhcyBpdCdzIHJlcGV0aXRpdmUuDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmxvYW5fcmF0ZV9oaXN0IDwtIGdncGxvdChsb2FucywgYWVzKEJvcnJvd2VyUmF0ZSoxMDAuMCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MS4wLCBmaWxsPSIjRTY5RjAwIiwgY29sb3VyPSJibGFjayIpICsgeGxpbSg1LjAsMzUuMCkNCmxvYW5fcmF0ZV9oaXN0IDwtIGxvYW5fcmF0ZV9oaXN0ICsgeGxhYigiSW50ZXJlc3QgUmF0ZXMgKCUpIikgKyB5bGFiKCJOdW1iZXIgb2YgbG9hbnMiKSArIGdndGl0bGUoIkhpc3RvZ3JhbSBvZiBpbnRlcmVzdCByYXRlcyIpDQpsb2FuX21lZGlhbl9yYXRlIDwtIDEwMC4wICogbWVkaWFuKGxvYW5zJEJvcnJvd2VyUmF0ZSkNCmxvYW5fcmF0ZV9oaXN0IDwtIGxvYW5fcmF0ZV9oaXN0ICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWxvYW5fbWVkaWFuX3JhdGUpDQpsb2FuX3JhdGVfaGlzdCA8LSBsb2FuX3JhdGVfaGlzdCArIGFubm90YXRlKCJ0ZXh0IiwgeCA9IGxvYW5fbWVkaWFuX3JhdGUgKyA1LjUsIHkgPSA2NzAwLCBsYWJlbCA9IHBhc3RlKCJNZWRpYW4gPSIsbG9hbl9tZWRpYW5fcmF0ZSwgIiUiKSwgc2l6ZSA9IDMpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpsb2FuX2NyZWRpdF9zY29yZXNfaGlzdCA8LSBnZ3Bsb3QobG9hbnMsIGFlcyhDcmVkaXRTY29yZVJhbmdlTG93ZXIpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMjAsIGZpbGw9IiNFNjlGMDAiLCBjb2xvdXI9ImJsYWNrIikgKyB4bGltKDQwMCw5MDApDQpsb2FuX2NyZWRpdF9zY29yZXNfaGlzdCA8LSBsb2FuX2NyZWRpdF9zY29yZXNfaGlzdCArIHhsYWIoIkNyZWRpdCBzY29yZXMiKSArIHlsYWIoIk51bWJlciBvZiBsb2FucyIpICsgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIGNyZWRpdCBzY29yZXMiKQ0KbG9hbl9tZWRpYW5fY3JlZGl0X3Njb3JlIDwtIG1lZGlhbihsb2FucyRDcmVkaXRTY29yZVJhbmdlTG93ZXIsIG5hLnJtPVQpDQpsb2FuX2NyZWRpdF9zY29yZXNfaGlzdCA8LSBsb2FuX2NyZWRpdF9zY29yZXNfaGlzdCArIGdlb21fdmxpbmUoeGludGVyY2VwdD1sb2FuX21lZGlhbl9jcmVkaXRfc2NvcmUpDQpsb2FuX2NyZWRpdF9zY29yZXNfaGlzdCA8LSBsb2FuX2NyZWRpdF9zY29yZXNfaGlzdCArIGFubm90YXRlKCJ0ZXh0IiwgeCA9IGxvYW5fbWVkaWFuX2NyZWRpdF9zY29yZSArIDgwLCB5ID0gMTgwMDAsIGxhYmVsID0gcGFzdGUoIk1lZGlhbiA9Iixsb2FuX21lZGlhbl9jcmVkaXRfc2NvcmUpLCBzaXplID0gMykNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmxvYW5faW5jb21lX2hpc3QgPC0gZ2dwbG90KGxvYW5zLCBhZXMoU3RhdGVkTW9udGhseUluY29tZSkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9NTAwLCBmaWxsPSIjRTY5RjAwIiwgY29sb3VyPSJibGFjayIpICsgeGxpbSgwLDIwMDAwKQ0KbG9hbl9pbmNvbWVfaGlzdCA8LSBsb2FuX2luY29tZV9oaXN0ICsgeGxhYigiU3RhdGVkIE1vbnRobHkgSW5jb21lIChVU0QpIikgKyB5bGFiKCJOdW1iZXIgb2YgbG9hbnMiKSArIGdndGl0bGUoIkhpc3RvZ3JhbSBvZiBtb250aHkgaW5jb21lcyIpDQpsb2FuX21lZGlhbl9tb250aGx5X2luY29tZSA8LSByb3VuZChtZWRpYW4obG9hbnMkU3RhdGVkTW9udGhseUluY29tZSkpDQpsb2FuX2luY29tZV9oaXN0IDwtIGxvYW5faW5jb21lX2hpc3QgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bG9hbl9tZWRpYW5fbW9udGhseV9pbmNvbWUpDQpsb2FuX2luY29tZV9oaXN0IDwtIGxvYW5faW5jb21lX2hpc3QgKyBhbm5vdGF0ZSgidGV4dCIsIHggPSBsb2FuX21lZGlhbl9tb250aGx5X2luY29tZSArIDQyMDAsIHkgPSAxMjAwMCwgbGFiZWwgPSBwYXN0ZSgiTWVkaWFuID0iLGxvYW5fbWVkaWFuX21vbnRobHlfaW5jb21lLCAiVVNEIiksIHNpemU9MykNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCiMgQ29udmVydCB0aGUgVGVybSBjb2x1bW4gdG8gZmFjdG9yDQpsb2FucyRUZXJtIDwtIGFzLmZhY3Rvcihsb2FucyRUZXJtKQ0KbG9hbnNfdGVybXNfYmFycGxvdCA8LSBnZ3Bsb3QobG9hbnMsIGFlcyhUZXJtKSkgKyBnZW9tX2JhcihmaWxsPSIjRTY5RjAwIiwgY29sb3VyPSJibGFjayIpDQpsb2Fuc190ZXJtc19iYXJwbG90IDwtIGxvYW5zX3Rlcm1zX2JhcnBsb3QgKyB4bGFiKCJMb2FuIHRlcm0gaW4gbW9udGhzIikgKyB5bGFiKCJOdW1iZXIgb2YgbG9hbnMiKSArIGdndGl0bGUoIkJhcnBsb3Qgb2YgbG9hbiB0ZXJtcyIpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQojIENvbnZlcnQgdGhlIFRlcm0gY29sdW1uIHRvIGZhY3Rvcg0KaG9tZV9vd25lcnNoaXBfYmFycGxvdCA8LSBnZ3Bsb3QobG9hbnMsIGFlcyhJc0JvcnJvd2VySG9tZW93bmVyKSkgKyBnZW9tX2JhcihmaWxsPSIjRTY5RjAwIiwgY29sb3VyPSJibGFjayIpDQpob21lX293bmVyc2hpcF9iYXJwbG90IDwtIGhvbWVfb3duZXJzaGlwX2JhcnBsb3QgKyB4bGFiKCJCb3Jyb3dlciBvd25zIGhvbWU/IikgKyB5bGFiKCJOdW1iZXIgb2YgbG9hbnMiKSArIGdndGl0bGUoIkJhcnBsb3Qgb2YgaG9tZS1vd25lcnNoaXAiKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KY3VycmVudF9kZWxpbnFfaGlzdCA8LSBnZ3Bsb3QobG9hbnMsIGFlcyhDdXJyZW50RGVsaW5xdWVuY2llcykpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGg9MS4wLCBmaWxsPSIjRTY5RjAwIiwgY29sb3VyPSJibGFjayIpICsgeGxpbSgtMSw1KQ0KY3VycmVudF9kZWxpbnFfaGlzdCA8LSBjdXJyZW50X2RlbGlucV9oaXN0ICsgeGxhYigiTnVtYmVyIG9mIGN1cnJlbnQgZGVsaW5xdWVuY2llcyIpICsgeWxhYigiTnVtYmVyIG9mIGxvYW5zIikgKyBnZ3RpdGxlKCJIaXN0b2dyYW0gb2YgY3VycmVudCBkZWxpbnF1ZW5jaWVzIikNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmlucXVpcmllc182bW9udGhzX2hpc3QgPC0gZ2dwbG90KGxvYW5zLCBhZXMoSW5xdWlyaWVzTGFzdDZNb250aHMpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEuMCwgZmlsbD0iI0U2OUYwMCIsIGNvbG91cj0iYmxhY2siKSArIHhsaW0oLTEsNSkNCmlucXVpcmllc182bW9udGhzX2hpc3QgPC0gaW5xdWlyaWVzXzZtb250aHNfaGlzdCArIHhsYWIoIkNyZWRpdCBpbnF1aXJpZXMgaW4gbGFzdCA2IG1vbnRocyIpICsgeWxhYigiTnVtYmVyIG9mIGxvYW5zIikgKyBnZ3RpdGxlKCJIaXN0b2dyYW0gb2YgcmVjZW50IGNyZWRpdCBpbnF1aXJpZXMiKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KY3VycmVudF9jcmVkaXRfbGluZXNfaGlzdCA8LSBnZ3Bsb3QobG9hbnMsIGFlcyhDdXJyZW50Q3JlZGl0TGluZXMpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEuMCwgZmlsbD0iI0U2OUYwMCIsIGNvbG91cj0iYmxhY2siKSArIHhsaW0oMCwzMCkNCmN1cnJlbnRfY3JlZGl0X2xpbmVzX2hpc3QgPC0gY3VycmVudF9jcmVkaXRfbGluZXNfaGlzdCArIHhsYWIoIkN1cnJlbnQgY3JlZGl0IGxpbmVzIG9wZW4iKSArIHlsYWIoIk51bWJlciBvZiBsb2FucyIpICsgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIGN1cnJlbnQgY3JlZGl0IGxpbmVzIikNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCnJldm9sdmluZ19wYXltZW50X2hpc3QgPC0gZ2dwbG90KGxvYW5zLCBhZXMoT3BlblJldm9sdmluZ01vbnRobHlQYXltZW50KSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD0yNTAsIGZpbGw9IiNFNjlGMDAiLCBjb2xvdXI9ImJsYWNrIikgKyB4bGltKDAsMjAwMCkNCnJldm9sdmluZ19wYXltZW50X2hpc3QgPC0gcmV2b2x2aW5nX3BheW1lbnRfaGlzdCArIHhsYWIoIlJldm9sdmluZyBtb250aGx5IHBheW1lbnQiKSArIHlsYWIoIk51bWJlciBvZiBsb2FucyIpICsgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIHJldm9sdmluZyBtb250aGx5IHBheW1lbnQiKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KYXZhaWxfY3JlZGl0X2hpc3QgPC0gZ2dwbG90KGxvYW5zLCBhZXMoQXZhaWxhYmxlQmFua2NhcmRDcmVkaXQpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPTEwMDAsIGZpbGw9IiNFNjlGMDAiLCBjb2xvdXI9ImJsYWNrIikgKyB4bGltKC01MDAsIDMwMDAwKQ0KYXZhaWxfY3JlZGl0X2hpc3QgPC0gYXZhaWxfY3JlZGl0X2hpc3QgKyB4bGFiKCJBdmFpbGFibGUgY3JlZGl0IikgKyB5bGFiKCJOdW1iZXIgb2YgbG9hbnMiKSArIGdndGl0bGUoIkhpc3RvZ3JhbSBvZiBhdmFpbGFibGUgY3JlZGl0IikNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmNyZWRpdF91dGlsX2hpc3QgPC0gZ2dwbG90KGxvYW5zLCBhZXMoMTAwLjAgKiBCYW5rY2FyZFV0aWxpemF0aW9uKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aD04LCBmaWxsPSIjRTY5RjAwIiwgY29sb3VyPSJibGFjayIpICsgeGxpbSgwLDEwMCkNCmNyZWRpdF91dGlsX2hpc3QgPC0gY3JlZGl0X3V0aWxfaGlzdCArIHhsYWIoIkNyZWRpdCB1dGlsaXphdGlvbiAoJSkiKSArIHlsYWIoIk51bWJlciBvZiBsb2FucyIpICsgZ2d0aXRsZSgiSGlzdG9ncmFtIG9mIGNyZWRpdCB1dGlsaXphdGlvbiIpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQojIE11bHRpcGxlIHBsb3QgZnVuY3Rpb24NCiMNCiMgZ2dwbG90IG9iamVjdHMgY2FuIGJlIHBhc3NlZCBpbiAuLi4sIG9yIHRvIHBsb3RsaXN0IChhcyBhIGxpc3Qgb2YgZ2dwbG90IG9iamVjdHMpDQojIC0gY29sczogICBOdW1iZXIgb2YgY29sdW1ucyBpbiBsYXlvdXQNCiMgLSBsYXlvdXQ6IEEgbWF0cml4IHNwZWNpZnlpbmcgdGhlIGxheW91dC4gSWYgcHJlc2VudCwgJ2NvbHMnIGlzIGlnbm9yZWQuDQojDQojIElmIHRoZSBsYXlvdXQgaXMgc29tZXRoaW5nIGxpa2UgbWF0cml4KGMoMSwyLDMsMyksIG5yb3c9MiwgYnlyb3c9VFJVRSksDQojIHRoZW4gcGxvdCAxIHdpbGwgZ28gaW4gdGhlIHVwcGVyIGxlZnQsIDIgd2lsbCBnbyBpbiB0aGUgdXBwZXIgcmlnaHQsIGFuZA0KIyAzIHdpbGwgZ28gYWxsIHRoZSB3YXkgYWNyb3NzIHRoZSBib3R0b20uDQojDQptdWx0aXBsb3QgPC0gZnVuY3Rpb24oLi4uLCBwbG90bGlzdD1OVUxMLCBmaWxlLCBjb2xzPTEsIGxheW91dD1OVUxMKSB7DQogIGxpYnJhcnkoZ3JpZCkNCg0KICAjIE1ha2UgYSBsaXN0IGZyb20gdGhlIC4uLiBhcmd1bWVudHMgYW5kIHBsb3RsaXN0DQogIHBsb3RzIDwtIGMobGlzdCguLi4pLCBwbG90bGlzdCkNCg0KICBudW1QbG90cyA9IGxlbmd0aChwbG90cykNCg0KICAjIElmIGxheW91dCBpcyBOVUxMLCB0aGVuIHVzZSAnY29scycgdG8gZGV0ZXJtaW5lIGxheW91dA0KICBpZiAoaXMubnVsbChsYXlvdXQpKSB7DQogICAgIyBNYWtlIHRoZSBwYW5lbA0KICAgICMgbmNvbDogTnVtYmVyIG9mIGNvbHVtbnMgb2YgcGxvdHMNCiAgICAjIG5yb3c6IE51bWJlciBvZiByb3dzIG5lZWRlZCwgY2FsY3VsYXRlZCBmcm9tICMgb2YgY29scw0KICAgIGxheW91dCA8LSBtYXRyaXgoc2VxKDEsIGNvbHMgKiBjZWlsaW5nKG51bVBsb3RzL2NvbHMpKSwNCiAgICAgICAgICAgICAgICAgICAgbmNvbCA9IGNvbHMsIG5yb3cgPSBjZWlsaW5nKG51bVBsb3RzL2NvbHMpKQ0KICB9DQoNCiBpZiAobnVtUGxvdHM9PTEpIHsNCiAgICBwcmludChwbG90c1tbMV1dKQ0KDQogIH0gZWxzZSB7DQogICAgIyBTZXQgdXAgdGhlIHBhZ2UNCiAgICBncmlkLm5ld3BhZ2UoKQ0KICAgIHB1c2hWaWV3cG9ydCh2aWV3cG9ydChsYXlvdXQgPSBncmlkLmxheW91dChucm93KGxheW91dCksIG5jb2wobGF5b3V0KSkpKQ0KDQogICAgIyBNYWtlIGVhY2ggcGxvdCwgaW4gdGhlIGNvcnJlY3QgbG9jYXRpb24NCiAgICBmb3IgKGkgaW4gMTpudW1QbG90cykgew0KICAgICAgIyBHZXQgdGhlIGksaiBtYXRyaXggcG9zaXRpb25zIG9mIHRoZSByZWdpb25zIHRoYXQgY29udGFpbiB0aGlzIHN1YnBsb3QNCiAgICAgIG1hdGNoaWR4IDwtIGFzLmRhdGEuZnJhbWUod2hpY2gobGF5b3V0ID09IGksIGFyci5pbmQgPSBUUlVFKSkNCg0KICAgICAgcHJpbnQocGxvdHNbW2ldXSwgdnAgPSB2aWV3cG9ydChsYXlvdXQucG9zLnJvdyA9IG1hdGNoaWR4JHJvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0LnBvcy5jb2wgPSBtYXRjaGlkeCRjb2wpKQ0KICAgIH0NCiAgfQ0KfQ0KYGBgDQoNCldlIGNhbiBwbG90IG11bHRpcGxlIGdyYXBocyBpbiBhbiBhcnJheSB1c2luZyBbV2luc3RvbiBDaGFuZydzIGBtdWx0aXBsb3QoKWBdKGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vR3JhcGhzL011bHRpcGxlX2dyYXBoc19vbl9vbmVfcGFnZV8oZ2dwbG90MikvKS4NCg0KYGBge3J9DQptdWx0aXBsb3QobG9hbl9hbW91bnRfaGlzdCwgbG9hbl9yYXRlX2hpc3QsIGxvYW5faW5jb21lX2hpc3QsIGxvYW5fY3JlZGl0X3Njb3Jlc19oaXN0LCBjb2xzPTIpDQpgYGANClRoZSBtZWRpYW4gaW5jb21lIG9mIHBvdGVudGlhbCBib3Jyb3dlcnMgaXMgcHJldHR5IGhlYWx0aHkgYXQgXCQ1NiwwMDAveWVhci4gVGhlIG1lZGlhbiBjcmVkaXQgc2NvcmUgaXMgcHJldHR5IGNsb3NlIHRvIDcwMCwgYW5kIGluIGZhY3QgYWxtb3N0IGhhbGYgKH40NyUpIG9mIHRoZSByZWNvcmRzIGhhdmUgYSBjcmVkaXQgc2NvcmUgb2YgNzAwIG9yIGhpZ2hlci4gTWluZCwgdGhpcyBpcyB1c2luZyB0aGUgKmxvd2VzdCogY3JlZGl0IHNjb3JlIHJlcG9ydGVkLCBhcyBnaXZlbiBieSB0aGUgdmFyaWFibGUgKioqQ3JlZGl0U2NvcmVSYW5nZUxvd2VyKioqLiBUaGUgbWVkaWFuIGludGVyZXN0LCBhdCAxOC40JSwgc2VlbXMgcmVhbGx5IGhpZ2ggYnV0IHNpbmNlIHRoZSBsb2FucyBhcmUgdHlwaWNhbGx5IGZvciByZWxhdGl2ZWx5IHNob3J0IHRlcm1zIChzZWUgYmVsb3cpIGl0IG1pZ2h0IHR1cm4gb3V0IHRvIGJlIG5vdCB0b28gb25lcm91cyBvbiBib3Jyb3dlcnMuIEEgXCQ2LDUwMCBsb2FuICh0aGUgbWVkaWFuIGFtb3VudCByZXF1ZXN0ZWQpIGF0IDE4LjQlIHBhaWQgb3ZlciAzIHllYXJzIFt3aWxsIHBheSBhYm91dCBcJDIsMDAwIGluIGludGVyZXN0IGluIGFkZGl0aW9uIHRvIHRoZSBwcmluY2lwYWxdKGh0dHA6Ly93d3cuYmFua3JhdGUuY29tL2NhbGN1bGF0b3JzL21vcnRnYWdlcy9sb2FuLWNhbGN1bGF0b3IuYXNweD9sb2FuQW1vdW50PTY1MDAmeWVhcnM9My4wMDAmdGVybXM9MzYmaW50ZXJlc3RSYXRlPTE4LjQwMCZsb2FuU3RhcnREYXRlPTMwK0RlYysyMDE2JnNob3c9ZmFsc2Umc2hvd1J0PXRydWUmcHJvZHM9Mzg4Jm1vbnRobHlBZGRpdGlvbmFsQW1vdW50PTAmeWVhcmx5QWRkaXRpb25hbEFtb3VudD0wJnllYXJseVBheW1lbnRNb250aD0mb25lVGltZUFkZGl0aW9uYWxQYXltZW50PTAmb25lVGltZUFkZGl0aW9uYWxQYXltZW50SW5NWT0maWNfaWQ9bXRnX2xvYW5fY2FsY19jYWxjdWxhdGVfYnRuKS4NCg0KVmFyaWFibGVzIHJlbGF0ZWQgdG8gY3JlZGl0IHV0aWxpemF0aW9uOg0KYGBge3IsIGVjaG89RkFMU0V9DQptdWx0aXBsb3QoY3VycmVudF9jcmVkaXRfbGluZXNfaGlzdCwgcmV2b2x2aW5nX3BheW1lbnRfaGlzdCwgYXZhaWxfY3JlZGl0X2hpc3QsIGNyZWRpdF91dGlsX2hpc3QsICBjb2xzPTIpDQoNCmBgYA0KDQpPdGhlciB2YXJpYWJsZXMgb2YgaW50ZXJlc3Q6DQpgYGB7ciwgZWNobz1GQUxTRX0NCm11bHRpcGxvdChsb2Fuc190ZXJtc19iYXJwbG90LCBob21lX293bmVyc2hpcF9iYXJwbG90LCBjdXJyZW50X2RlbGlucV9oaXN0LCBpbnF1aXJpZXNfNm1vbnRoc19oaXN0LCBjb2xzPTIpDQpgYGANCkFib3V0IDc1JSBvZiBsb2FucyBhcmUgMy15ZWFyIGxvYW5zLiBTaW1pbGFybHksIGFib3V0IDc1JSBvZiBhcHBsaWNhbnRzIGhhdmUgbm8gZGVsaW5xdWVuY2llcyBvbiB0aGVpciBjdXJyZW50IGFjY291bnRzLCB3aGljaCB3ZSB3b3VsZCBleHBlY3QsIGFuZCBhYm91dCA3NSUgb2YgdGhlbSBoYXZlIGhhZCB0aGVpciBjcmVkaXQgcHVsbGVkIHR3byBvciBmZXdlciB0aW1lcyBpbiB0aGUgbGFzdCA2IG1vbnRocy4gSG9tZSBvd25lcnNoaXAgaXMgZXZlbmx5IHNwbGl0IGFtb25nIGFwcGxpY2FudHMuDQoNCiMgRGF0YSBtdW5naW5nDQojIyBSZXNwb25zZSB2YXJpYWJsZQ0KVGhlIHJlc3BvbnNlIHZhcmlhYmxlLCAqKipMb2FuU3RhdHVzKioqLCBoYXMgc2V2ZXJhbCBvdXRjb21lczoNCmBgYHtyfQ0KdGFibGUobG9hbnMkTG9hblN0YXR1cykNCmBgYA0KV2Ugd291bGQgbGlrZSB0byB1c2UgYSBiaW5vbWlhbCBtb2RlbCwgc28gd2Ugd2lsbCBsYWJlbCBhbGwgdGhlIGxvYW5zIHRoYXQgYXJlIGVpdGhlciAiQ29tcGxldGVkIiBvciAiQ3VycmVudCIgd2l0aCBhICcxJyBhbmQgbG9hbnMgdGhhdCB3ZXJlIGNoYXJnZWQgb2ZmIG9yIGluIHdoaWNoIHRoZSBib3Jyb3dlZCBkZWZhdWx0ZWQgb3IgaXMgc29tZWhvdyBsYXRlIHdpbGwgYmUgbGFiZWxsZWQgd2l0aCBhICcwJy4NCmBgYHtyfQ0KI0NvbnZlcnQgdG8gY2hhcmFjdGVyIGFuZCBiYWNrIHRvIGZhY3Rvcg0KI2h0dHA6Ly9wcm9ncmFtbWluZy1yLXByby1icm8uYmxvZ3Nwb3QuY29tLzIwMTMvMDQvZWRpdGluZ2FkZGluZy1mYWN0b3ItbGV2ZWxzLWluLXIuaHRtbA0KbG9hbnMkTG9hblN0YXR1cyA8LSBhcy5jaGFyYWN0ZXIobG9hbnMkTG9hblN0YXR1cykNCiNVc2FnZSBvZiBncmVwbCB0byB0ZXN0IGlmIHN1Yi1zdHJpbmcgaW4gc3RyaW5nDQojaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMDEyODYxNy90ZXN0LWlmLWNoYXJhY3RlcnMtaW4tc3RyaW5nLWluLXINCmxvYW5zJExvYW5TdGF0dXNbbG9hbnMkTG9hblN0YXR1cyA9PSAiQ2FuY2VsbGVkIiB8IGxvYW5zJExvYW5TdGF0dXMgPT0gIkNoYXJnZWRvZmYiIHwgbG9hbnMkTG9hblN0YXR1cyA9PSAiRGVmYXVsdGVkIiB8IGdyZXBsKCJQYXN0IER1ZSIsIGxvYW5zJExvYW5TdGF0dXMpXSA8LSAiMCINCmxvYW5zJExvYW5TdGF0dXNbbG9hbnMkTG9hblN0YXR1cyA9PSAiQ29tcGxldGVkIiB8IGxvYW5zJExvYW5TdGF0dXMgPT0gIkN1cnJlbnQiIHwgbG9hbnMkTG9hblN0YXR1cyA9PSAiRmluYWxQYXltZW50SW5Qcm9ncmVzcyIgXSA8LSAiMSINCmxvYW5zJExvYW5TdGF0dXMgPC0gYXMuZmFjdG9yKGxvYW5zJExvYW5TdGF0dXMpDQp0YWJsZShsb2FucyRMb2FuU3RhdHVzKQ0KYGBgDQpBYm91dCA4MyUgb2YgdGhlIGxvYW5zIGFyZSBpbiBnb29kIHN0YXR1cy4NCg0KIyMgUHJlZGljdG9ycw0KV2Ugd2lsbCBiYXNlIG91ciBjaG9pY2Ugb2YgcHJlZGljdG9ycyBiYXNlZCBvbiBzZXZlcmFsIGZhY3RvcnMuIE9uZSBpcyBvdXIgZmFtaWxpYXJpdHkgd2l0aCB0aGUgZGF0YSwgZS5nLiwgd2UgZXhwZWN0IGluY29tZSBhbmQgY3JlZGl0IHNjb3JlIHRvIGJlIGdvb2QgcHJlZGljdG9ycyBvZiBhIGJvcnJvd2VyJ3MgYWJpbGl0eSB0byByZXBheSBhIGxvYW4uIFdlIHdpbGwgbGVhdmUgb3V0IHByZWRpY3RvcnMgdGhhdCBhcmUgbGlrZWx5IHRvIGJlIGhlYXZpbHkgY29ycmVsYXRlZCB3aXRoIGFub3RoZXIgd2UgZGlkIGluY2x1ZGUsIGUuZy4sIHRha2UgKkNyZWRpdFNjb3JlUmFuZ2VMb3dlciogYW5kIGxlYXZlIG91dCAqQ3JlZGl0U2NvcmVSYW5nZVVwcGVyKi4gV2Ugd2lsbCBhbHNvIGxlYXZlIG91dCBwcmVkaWN0b3JzIHdlIGFyZSBub3QgZmFtaWxpYXIgd2l0aCwgZS5nLiBbdHJhZGVzXShodHRwOi8vZm9ydW0ubGVuZGFjYWRlbXkuY29tL2luZGV4LnBocC90b3BpYyw0MjIzLm1zZzM5MDY4Lmh0bWwpLg0KDQpXZSB3aWxsIHVzZSB0aGUgZm9sbG93aW5nIHByZWRpY3RvcnM6DQoNCioqKlRlcm0qKiosIHRoZSBsZW5ndGggb2YgdGhlIGxvYW46IDEyLCAzNiwgb3IgNjAgbW9udGhzDQoNCioqKkJvcnJvd2VyUmF0ZSoqKiwgdGhlIGludGVyZXN0IHJhdGUgb2YgdGhlIGxvYW4NCg0KKioqQ3JlZGl0U2NvcmVSYW5nZUxvd2VyKioqLCB0aGUgYm9ycm93ZXIncyBsb3dlc3QgcmVwb3J0ZWQgY3JlZGl0IHNjb3JlDQoNCioqKkRlYnRUb0luY29tZVJhdGlvKioqLCBzZWxmLWV4cGxhbmF0b3J5DQoNCioqKkVtcGxveW1lbnRTdGF0dXNEdXJhdGlvbioqKiwgaG93IGxvbmcgaGFzIHRoZSBib3Jyb3dlciBiZWVuIGF0IGhpcyBjdXJyZW50IGVtcGxveW1lbnQsIGluIG1vbnRocw0KDQoqKipJc0JvcnJvd2VySG9tZW93bmVyKioqLCBzZWxmLWV4cGxhbmF0b3J5LCB0cnVlIG9yIGZhbHNlDQoNCioqKkN1cnJlbnRDcmVkaXRMaW5lcyoqKiwgbnVtYmVyIG9mIGN1cnJlbnQgY3JlZGl0IGxpbmVzIGF0IHRoZSB0aW1lIHRoZSBjcmVkaXQgcHJvZmlsZSB3YXMgcHVsbGVkLg0KDQoqKipUb3RhbENyZWRpdExpbmVzcGFzdDd5ZWFycyoqKiwgbnVtYmVyIG9mIGNyZWRpdCBsaW5lcyBpbiB0aGUgcGFzdCBzZXZlbiB5ZWFycyBhdCB0aGUgdGltZSB0aGUgY3JlZGl0IHByb2ZpbGUgd2FzIHB1bGxlZC4NCg0KKioqT3BlblJldm9sdmluZ0FjY291bnRzKioqLCBudW1iZXIgb2YgYm9ycm93ZXIncyBvcGVuIGFjY291bnRzDQoNCioqKk9wZW5SZXZvbHZpbmdNb250aGx5UGF5bWVudCoqKiwgdG90YWwgbW9udGhseSBwYXltZW50IG9uIG9wZW4gYWNjb3VudHMNCg0KKioqSW5xdWlyaWVzTGFzdDZNb250aHMqKiosIG51bWJlciBvZiBjcmVkaXQgaW5xdWlyaWVzIGluIHRoZSBsYXN0IDYgbW9udGhzDQoNCioqKlRvdGFsSW5xdWlyaWVzKioqLCB0b3RhbCBudW1iZXIgb2YgY3JlZGl0IGlucXVpcmllcyAoYWxsLXRpbWU/KQ0KDQoqKipDdXJyZW50RGVsaW5xdWVuY2llcyoqKiwgbnVtYmVyIG9mIGFjY291bnRzIGRlbGlucXVlbnQgYXQgdGhlIHRpbWUgdGhlIGNyZWRpdCBwcm9maWxlIHdhcyBwdWxsZWQNCg0KKioqQW1vdW50RGVsaW5xdWVudCoqKiwgdG90YWwgY3VycmVudCBkb2xsYXIgYW1vdW50IG9mIGRlbGlucXVlbmNpZXMNCg0KKioqRGVsaW5xdWVuY2llc0xhc3Q3WWVhcnMqKiosIG51bWJlciBvZiBkZWxpcXVlbmNpZXMgaW4gdGhlIGxhc3QgNyB5ZWFycw0KDQoqKipQdWJsaWNSZWNvcmRzTGFzdDEwWWVhcnMqKiosIG51bWJlciBvZiBbcHVibGljIHJlY29yZHNdKGh0dHBzOi8vd3d3LmNyZWRpdGthcm1hLmNvbS9hcnRpY2xlL3B1YmxpYy1yZWNvcmRzLW9uLWNyZWRpdC1yZXBvcnQpIGluIHRoZSBsYXN0IDEwIHllYXJzDQoNCioqKlB1YmxpY1JlY29yZHNMYXN0MTJNb250aHMqKiosIG51bWJlciBvZiBwdWJsaWMgcmVjb3JkcyBpbiB0aGUgbGFzdCB5ZWFyDQoNCioqKlJldm9sdmluZ0NyZWRpdEJhbGFuY2UqKiosIHRvdGFsIGRvbGxhciBhbW91bnQgY2FycmllZCBmcm9tIG9uZSBtb250aCB0byB0aGUgbmV4dA0KDQoqKipCYW5rY2FyZFV0aWxpemF0aW9uKioqLCB0aGUgcGVyY2VudGFnZSBvZiBhdmFpbGFibGUgcmV2b2x2aW5nIGNyZWRpdCB0aGF0IGlzIHV0aWxpemVkDQoNCioqKkF2YWlsYWJsZUJhbmtjYXJkQ3JlZGl0KioqLCB0b3RhbCBhdmFpbGFibGUgY3JlZGl0IHZpYSBjcmVkaXQgY2FyZHMNCg0KKioqSW5jb21lVmVyaWZpYWJsZSoqKiwgd2hldGhlciBib3Jyb3dlciBzdGF0ZWQgaGUvc2hlIGhhZCBldmlkZW5jZSB0byBzdXBwb3J0IHRoZSBzdGF0ZWQgaW5jb21lDQoNCioqKlN0YXRlZE1vbnRobHlJbmNvbWUqKiosIHRoZSBib3Jyb3dlcidzIG1vbnRobHkgaW5jb21lDQoNClNvbWUgb2YgdGhlc2UgcHJlZGljdG9ycyBoYXZlIG1pc3NpbmcgZGF0YSwgc2V2ZXJhbCB0aG91c2FuZCBvZiB0aGVtIGluIHNvbWUgY2FzZXMuIFJhdGhlciB0aGFuIGlnbm9yaW5nIHRoZW0sIHdlIHRyeSB0byBpbXB1dGUgdGhlbSBzaW1wbHkgYnkgc2FtcGxpbmcuIEkgYWxzbyB0cmllZCB0aGUgW21pY2VdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9taWNlL21pY2UucGRmKSBsaWJyYXJ5LCBidXQgaXQgdGFrZXMgc2V2ZXJhbCBtaW51dGVzIHRvIHJ1biBvbiBhIGRhdGFzZXQgYXMgbGFyZ2UgYXMgdGhpcyBvbmUsIGV2ZW4gd2hlbiBJIHVzZWQgW3RoZSBtZXRob2QgJ25vcm0gJ10oaHR0cDovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy8yMDk4MTEvaG93LXRvLWltcHJvdmUtcnVubmluZy10aW1lLWZvci1yLW1pY2UtZGF0YS1pbXB1dGF0aW9uKS4NCg0KYGBge3IsIGVjaG89VFJVRX0NCiNSZXBsYWNpbmcgTkEncyBpbiBDcmVkaXRTY29yZVJhbmdlTG93ZXI6DQojR2V0dGluZyBudW1iZXIgb2YgTkEncw0KbnVtX05BIDwtIGxlbmd0aChsb2FucyRDcmVkaXRTY29yZVJhbmdlTG93ZXJbaXMubmEobG9hbnMkQ3JlZGl0U2NvcmVSYW5nZUxvd2VyKV0pDQojU2FtcGxpbmcgQ3JlZGl0U2NvcmVSYW5nZUxvd2VyDQpzZXQuc2VlZCgxMjMpI3JlcHJvZHVjaWJpbGl0eQ0Kc2FtcGxlX3ZlY3RvciA8LSBzYW1wbGUoeD1sb2FucyRDcmVkaXRTY29yZVJhbmdlTG93ZXJbIWlzLm5hKGxvYW5zJENyZWRpdFNjb3JlUmFuZ2VMb3dlcildLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRDcmVkaXRTY29yZVJhbmdlTG93ZXJbaXMubmEobG9hbnMkQ3JlZGl0U2NvcmVSYW5nZUxvd2VyKV0gPC0gc2FtcGxlX3ZlY3Rvcg0KYGBgDQoNCldlIGNhbiBkbyBzaW1pbGFybHkgZm9yIHRoZSBvdGhlciBwcmVkaWN0b3JzIHRoYXQgaGF2ZSBtaXNzaW5nIGRhdGEuIEl0J3MgcHJldHR5IHJlcGV0aXRpdmUsIHNvIGl0IHdpbGwgbm90IGJlIHNob3duIGhlcmUuDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCiNSZXBsYWNpbmcgTkEncyBpbiBJbnF1aXJpZXNMYXN0Nk1vbnRoczoNCiNHZXR0aW5nIG51bWJlciBvZiBOQSdzDQpudW1fTkEgPC0gbGVuZ3RoKGxvYW5zJElucXVpcmllc0xhc3Q2TW9udGhzW2lzLm5hKGxvYW5zJElucXVpcmllc0xhc3Q2TW9udGhzKV0pDQojU2FtcGxpbmcgSW5xdWlyaWVzTGFzdDZNb250aHMNCnNldC5zZWVkKDEyMykjcmVwcm9kdWNpYmlsaXR5DQpzYW1wbGVfdmVjdG9yIDwtIHNhbXBsZSh4PWxvYW5zJElucXVpcmllc0xhc3Q2TW9udGhzWyFpcy5uYShsb2FucyRJbnF1aXJpZXNMYXN0Nk1vbnRocyldLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRJbnF1aXJpZXNMYXN0Nk1vbnRoc1tpcy5uYShsb2FucyRJbnF1aXJpZXNMYXN0Nk1vbnRocyldIDwtIHNhbXBsZV92ZWN0b3INCg0KI1JlcGxhY2luZyBOQSdzIGluIFRvdGFsSW5xdWlyaWVzOg0KI0dldHRpbmcgbnVtYmVyIG9mIE5BJ3MNCm51bV9OQSA8LSBsZW5ndGgobG9hbnMkVG90YWxJbnF1aXJpZXNbaXMubmEobG9hbnMkVG90YWxJbnF1aXJpZXMpXSkNCiNTYW1wbGluZyBUb3RhbElucXVpcmllcw0Kc2V0LnNlZWQoMTIzKSNyZXByb2R1Y2liaWxpdHkNCnNhbXBsZV92ZWN0b3IgPC0gc2FtcGxlKHg9bG9hbnMkVG90YWxJbnF1aXJpZXNbIWlzLm5hKGxvYW5zJFRvdGFsSW5xdWlyaWVzKV0sIHNpemU9bnVtX05BKQ0KI1JlcGxhY2UNCmxvYW5zJFRvdGFsSW5xdWlyaWVzW2lzLm5hKGxvYW5zJFRvdGFsSW5xdWlyaWVzKV0gPC0gc2FtcGxlX3ZlY3Rvcg0KDQojUmVwbGFjaW5nIE5BJ3MgaW4gRGVidFRvSW5jb21lUmF0aW86DQojR2V0dGluZyBudW1iZXIgb2YgTkEncw0KbnVtX05BIDwtIGxlbmd0aChsb2FucyREZWJ0VG9JbmNvbWVSYXRpb1tpcy5uYShsb2FucyREZWJ0VG9JbmNvbWVSYXRpbyldKQ0KI1NhbXBsaW5nIERlYnRUb0luY29tZVJhdGlvDQpzZXQuc2VlZCgxMjMpI3JlcHJvZHVjaWJpbGl0eQ0Kc2FtcGxlX3ZlY3RvciA8LSBzYW1wbGUoeD1sb2FucyREZWJ0VG9JbmNvbWVSYXRpb1shaXMubmEobG9hbnMkRGVidFRvSW5jb21lUmF0aW8pXSwgc2l6ZT1udW1fTkEpDQojUmVwbGFjZQ0KbG9hbnMkRGVidFRvSW5jb21lUmF0aW9baXMubmEobG9hbnMkRGVidFRvSW5jb21lUmF0aW8pXSA8LSBzYW1wbGVfdmVjdG9yDQoNCiNSZXBsYWNpbmcgTkEncyBpbiBFbXBsb3ltZW50U3RhdHVzRHVyYXRpb246DQojR2V0dGluZyBudW1iZXIgb2YgTkEncw0KbnVtX05BIDwtIGxlbmd0aChsb2FucyRFbXBsb3ltZW50U3RhdHVzRHVyYXRpb25baXMubmEobG9hbnMkRW1wbG95bWVudFN0YXR1c0R1cmF0aW9uKV0pDQojU2FtcGxpbmcgRW1wbG95bWVudFN0YXR1c0R1cmF0aW9uDQpzZXQuc2VlZCgxMjMpI3JlcHJvZHVjaWJpbGl0eQ0Kc2FtcGxlX3ZlY3RvciA8LSBzYW1wbGUoeD1sb2FucyRFbXBsb3ltZW50U3RhdHVzRHVyYXRpb25bIWlzLm5hKGxvYW5zJEVtcGxveW1lbnRTdGF0dXNEdXJhdGlvbildLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRFbXBsb3ltZW50U3RhdHVzRHVyYXRpb25baXMubmEobG9hbnMkRW1wbG95bWVudFN0YXR1c0R1cmF0aW9uKV0gPC0gc2FtcGxlX3ZlY3Rvcg0KDQojUmVwbGFjaW5nIE5BJ3MgaW4gQ3VycmVudENyZWRpdExpbmVzOg0KI0dldHRpbmcgbnVtYmVyIG9mIE5BJ3MNCm51bV9OQSA8LSBsZW5ndGgobG9hbnMkQ3VycmVudENyZWRpdExpbmVzW2lzLm5hKGxvYW5zJEN1cnJlbnRDcmVkaXRMaW5lcyldKQ0KI1NhbXBsaW5nIEN1cnJlbnRDcmVkaXRMaW5lcw0Kc2V0LnNlZWQoMTIzKSNyZXByb2R1Y2liaWxpdHkNCnNhbXBsZV92ZWN0b3IgPC0gc2FtcGxlKHg9bG9hbnMkQ3VycmVudENyZWRpdExpbmVzWyFpcy5uYShsb2FucyRDdXJyZW50Q3JlZGl0TGluZXMpXSwgc2l6ZT1udW1fTkEpDQojUmVwbGFjZQ0KbG9hbnMkQ3VycmVudENyZWRpdExpbmVzW2lzLm5hKGxvYW5zJEN1cnJlbnRDcmVkaXRMaW5lcyldIDwtIHNhbXBsZV92ZWN0b3INCg0KI1JlcGxhY2luZyBOQSdzIGluIFRvdGFsQ3JlZGl0TGluZXNwYXN0N3llYXJzOg0KI0dldHRpbmcgbnVtYmVyIG9mIE5BJ3MNCm51bV9OQSA8LSBsZW5ndGgobG9hbnMkVG90YWxDcmVkaXRMaW5lc3Bhc3Q3eWVhcnNbaXMubmEobG9hbnMkVG90YWxDcmVkaXRMaW5lc3Bhc3Q3eWVhcnMpXSkNCiNTYW1wbGluZyBUb3RhbENyZWRpdExpbmVzcGFzdDd5ZWFycw0Kc2V0LnNlZWQoMTIzKSNyZXByb2R1Y2liaWxpdHkNCnNhbXBsZV92ZWN0b3IgPC0gc2FtcGxlKHg9bG9hbnMkVG90YWxDcmVkaXRMaW5lc3Bhc3Q3eWVhcnNbIWlzLm5hKGxvYW5zJFRvdGFsQ3JlZGl0TGluZXNwYXN0N3llYXJzKV0sIHNpemU9bnVtX05BKQ0KI1JlcGxhY2UNCmxvYW5zJFRvdGFsQ3JlZGl0TGluZXNwYXN0N3llYXJzW2lzLm5hKGxvYW5zJFRvdGFsQ3JlZGl0TGluZXNwYXN0N3llYXJzKV0gPC0gc2FtcGxlX3ZlY3Rvcg0KDQojUmVwbGFjaW5nIE5BJ3MgaW4gQ3VycmVudERlbGlucXVlbmNpZXM6DQojR2V0dGluZyBudW1iZXIgb2YgTkEncw0KbnVtX05BIDwtIGxlbmd0aChsb2FucyRDdXJyZW50RGVsaW5xdWVuY2llc1tpcy5uYShsb2FucyRDdXJyZW50RGVsaW5xdWVuY2llcyldKQ0KI1NhbXBsaW5nIEN1cnJlbnREZWxpbnF1ZW5jaWVzDQpzZXQuc2VlZCgxMjMpI3JlcHJvZHVjaWJpbGl0eQ0Kc2FtcGxlX3ZlY3RvciA8LSBzYW1wbGUoeD1sb2FucyRDdXJyZW50RGVsaW5xdWVuY2llc1shaXMubmEobG9hbnMkQ3VycmVudERlbGlucXVlbmNpZXMpXSwgc2l6ZT1udW1fTkEpDQojUmVwbGFjZQ0KbG9hbnMkQ3VycmVudERlbGlucXVlbmNpZXNbaXMubmEobG9hbnMkQ3VycmVudERlbGlucXVlbmNpZXMpXSA8LSBzYW1wbGVfdmVjdG9yDQoNCiNSZXBsYWNpbmcgTkEncyBpbiBBbW91bnREZWxpbnF1ZW50Og0KI0dldHRpbmcgbnVtYmVyIG9mIE5BJ3MNCm51bV9OQSA8LSBsZW5ndGgobG9hbnMkQW1vdW50RGVsaW5xdWVudFtpcy5uYShsb2FucyRBbW91bnREZWxpbnF1ZW50KV0pDQojU2FtcGxpbmcgQW1vdW50RGVsaW5xdWVudA0Kc2V0LnNlZWQoMTIzKSNyZXByb2R1Y2liaWxpdHkNCnNhbXBsZV92ZWN0b3IgPC0gc2FtcGxlKHg9bG9hbnMkQW1vdW50RGVsaW5xdWVudFshaXMubmEobG9hbnMkQW1vdW50RGVsaW5xdWVudCldLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRBbW91bnREZWxpbnF1ZW50W2lzLm5hKGxvYW5zJEFtb3VudERlbGlucXVlbnQpXSA8LSBzYW1wbGVfdmVjdG9yDQoNCiNSZXBsYWNpbmcgTkEncyBpbiBEZWxpbnF1ZW5jaWVzTGFzdDdZZWFyczoNCiNHZXR0aW5nIG51bWJlciBvZiBOQSdzDQpudW1fTkEgPC0gbGVuZ3RoKGxvYW5zJERlbGlucXVlbmNpZXNMYXN0N1llYXJzW2lzLm5hKGxvYW5zJERlbGlucXVlbmNpZXNMYXN0N1llYXJzKV0pDQojU2FtcGxpbmcgRGVsaW5xdWVuY2llc0xhc3Q3WWVhcnMNCnNldC5zZWVkKDEyMykjcmVwcm9kdWNpYmlsaXR5DQpzYW1wbGVfdmVjdG9yIDwtIHNhbXBsZSh4PWxvYW5zJERlbGlucXVlbmNpZXNMYXN0N1llYXJzWyFpcy5uYShsb2FucyREZWxpbnF1ZW5jaWVzTGFzdDdZZWFycyldLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyREZWxpbnF1ZW5jaWVzTGFzdDdZZWFyc1tpcy5uYShsb2FucyREZWxpbnF1ZW5jaWVzTGFzdDdZZWFycyldIDwtIHNhbXBsZV92ZWN0b3INCg0KI1JlcGxhY2luZyBOQSdzIGluIFB1YmxpY1JlY29yZHNMYXN0MTBZZWFyczoNCiNHZXR0aW5nIG51bWJlciBvZiBOQSdzDQpudW1fTkEgPC0gbGVuZ3RoKGxvYW5zJFB1YmxpY1JlY29yZHNMYXN0MTBZZWFyc1tpcy5uYShsb2FucyRQdWJsaWNSZWNvcmRzTGFzdDEwWWVhcnMpXSkNCiNTYW1wbGluZyBQdWJsaWNSZWNvcmRzTGFzdDEwWWVhcnMNCnNldC5zZWVkKDEyMykjcmVwcm9kdWNpYmlsaXR5DQpzYW1wbGVfdmVjdG9yIDwtIHNhbXBsZSh4PWxvYW5zJFB1YmxpY1JlY29yZHNMYXN0MTBZZWFyc1shaXMubmEobG9hbnMkUHVibGljUmVjb3Jkc0xhc3QxMFllYXJzKV0sIHNpemU9bnVtX05BKQ0KI1JlcGxhY2UNCmxvYW5zJFB1YmxpY1JlY29yZHNMYXN0MTBZZWFyc1tpcy5uYShsb2FucyRQdWJsaWNSZWNvcmRzTGFzdDEwWWVhcnMpXSA8LSBzYW1wbGVfdmVjdG9yDQoNCiNSZXBsYWNpbmcgTkEncyBpbiBQdWJsaWNSZWNvcmRzTGFzdDEyTW9udGhzOg0KI0dldHRpbmcgbnVtYmVyIG9mIE5BJ3MNCm51bV9OQSA8LSBsZW5ndGgobG9hbnMkUHVibGljUmVjb3Jkc0xhc3QxMk1vbnRoc1tpcy5uYShsb2FucyRQdWJsaWNSZWNvcmRzTGFzdDEyTW9udGhzKV0pDQojU2FtcGxpbmcgUHVibGljUmVjb3Jkc0xhc3QxMk1vbnRocw0Kc2V0LnNlZWQoMTIzKSNyZXByb2R1Y2liaWxpdHkNCnNhbXBsZV92ZWN0b3IgPC0gc2FtcGxlKHg9bG9hbnMkUHVibGljUmVjb3Jkc0xhc3QxMk1vbnRoc1shaXMubmEobG9hbnMkUHVibGljUmVjb3Jkc0xhc3QxMk1vbnRocyldLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRQdWJsaWNSZWNvcmRzTGFzdDEyTW9udGhzW2lzLm5hKGxvYW5zJFB1YmxpY1JlY29yZHNMYXN0MTJNb250aHMpXSA8LSBzYW1wbGVfdmVjdG9yDQoNCiNSZXBsYWNpbmcgTkEncyBpbiBSZXZvbHZpbmdDcmVkaXRCYWxhbmNlOg0KI0dldHRpbmcgbnVtYmVyIG9mIE5BJ3MNCm51bV9OQSA8LSBsZW5ndGgobG9hbnMkUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZVtpcy5uYShsb2FucyRSZXZvbHZpbmdDcmVkaXRCYWxhbmNlKV0pDQojU2FtcGxpbmcgUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZQ0Kc2V0LnNlZWQoMTIzKSNyZXByb2R1Y2liaWxpdHkNCnNhbXBsZV92ZWN0b3IgPC0gc2FtcGxlKHg9bG9hbnMkUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZVshaXMubmEobG9hbnMkUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSldLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRSZXZvbHZpbmdDcmVkaXRCYWxhbmNlW2lzLm5hKGxvYW5zJFJldm9sdmluZ0NyZWRpdEJhbGFuY2UpXSA8LSBzYW1wbGVfdmVjdG9yDQoNCiNSZXBsYWNpbmcgTkEncyBpbiBCYW5rY2FyZFV0aWxpemF0aW9uOg0KI0dldHRpbmcgbnVtYmVyIG9mIE5BJ3MNCm51bV9OQSA8LSBsZW5ndGgobG9hbnMkQmFua2NhcmRVdGlsaXphdGlvbltpcy5uYShsb2FucyRCYW5rY2FyZFV0aWxpemF0aW9uKV0pDQojU2FtcGxpbmcgQmFua2NhcmRVdGlsaXphdGlvbg0Kc2V0LnNlZWQoMTIzKSNyZXByb2R1Y2liaWxpdHkNCnNhbXBsZV92ZWN0b3IgPC0gc2FtcGxlKHg9bG9hbnMkQmFua2NhcmRVdGlsaXphdGlvblshaXMubmEobG9hbnMkQmFua2NhcmRVdGlsaXphdGlvbildLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRCYW5rY2FyZFV0aWxpemF0aW9uW2lzLm5hKGxvYW5zJEJhbmtjYXJkVXRpbGl6YXRpb24pXSA8LSBzYW1wbGVfdmVjdG9yDQoNCiNSZXBsYWNpbmcgTkEncyBpbiBBdmFpbGFibGVCYW5rY2FyZENyZWRpdDoNCiNHZXR0aW5nIG51bWJlciBvZiBOQSdzDQpudW1fTkEgPC0gbGVuZ3RoKGxvYW5zJEF2YWlsYWJsZUJhbmtjYXJkQ3JlZGl0W2lzLm5hKGxvYW5zJEF2YWlsYWJsZUJhbmtjYXJkQ3JlZGl0KV0pDQojU2FtcGxpbmcgQXZhaWxhYmxlQmFua2NhcmRDcmVkaXQNCnNldC5zZWVkKDEyMykjcmVwcm9kdWNpYmlsaXR5DQpzYW1wbGVfdmVjdG9yIDwtIHNhbXBsZSh4PWxvYW5zJEF2YWlsYWJsZUJhbmtjYXJkQ3JlZGl0WyFpcy5uYShsb2FucyRBdmFpbGFibGVCYW5rY2FyZENyZWRpdCldLCBzaXplPW51bV9OQSkNCiNSZXBsYWNlDQpsb2FucyRBdmFpbGFibGVCYW5rY2FyZENyZWRpdFtpcy5uYShsb2FucyRBdmFpbGFibGVCYW5rY2FyZENyZWRpdCldIDwtIHNhbXBsZV92ZWN0b3INCmBgYA0KDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KcHJlZGljdG9ycyA8LSBjb2xuYW1lcyhsb2FucykNCnByZWRpY3RvcnMgPC0gcHJlZGljdG9yc1twcmVkaWN0b3JzICE9ICJMb2FuU3RhdHVzIl0NCmZvciAocHJlZGljdG9yIGluIGMoIlRlcm0iLCAiQm9ycm93ZXJSYXRlIiwgIkNyZWRpdFNjb3JlUmFuZ2VMb3dlciIsICJEZWJ0VG9JbmNvbWVSYXRpbyIsICJFbXBsb3ltZW50U3RhdHVzRHVyYXRpb24iLCAiSXNCb3Jyb3dlckhvbWVvd25lciIsICJDdXJyZW50Q3JlZGl0TGluZXMiLCAiVG90YWxDcmVkaXRMaW5lc3Bhc3Q3eWVhcnMiLCAiT3BlblJldm9sdmluZ0FjY291bnRzIiwgIk9wZW5SZXZvbHZpbmdNb250aGx5UGF5bWVudCIsICJJbnF1aXJpZXNMYXN0Nk1vbnRocyIsICJUb3RhbElucXVpcmllcyIsICJDdXJyZW50RGVsaW5xdWVuY2llcyIsICJBbW91bnREZWxpbnF1ZW50IiwgIkRlbGlucXVlbmNpZXNMYXN0N1llYXJzIiwgIlB1YmxpY1JlY29yZHNMYXN0MTBZZWFycyIsICJQdWJsaWNSZWNvcmRzTGFzdDEyTW9udGhzIiwgIlJldm9sdmluZ0NyZWRpdEJhbGFuY2UiLCAiQmFua2NhcmRVdGlsaXphdGlvbiIsICJBdmFpbGFibGVCYW5rY2FyZENyZWRpdCIsICJJbmNvbWVWZXJpZmlhYmxlIiwgIlN0YXRlZE1vbnRobHlJbmNvbWUiKSkgew0KICBsb2dfbW9kZWwgPC0gZ2xtKGxvYW5zJExvYW5TdGF0dXMgfiBsb2Fuc1twcmVkaWN0b3JdWywxXSwgZmFtaWx5ID0gYmlub21pYWwpDQogIGNhdChwYXN0ZSgiU2lnbmlmaWNhbmNlIGxldmVsIG9mIHByZWRpY3RvciIsIHByZWRpY3Rvciwgc3VtbWFyeShsb2dfbW9kZWwpJGNvZWZmaWNpZW50c1ssNF0sICJcbiIpKQ0KfQ0KI2xvYW5zX2xvZ19tb2RlbF8xIDwtIGdsbShMb2FuU3RhdHVzIH4gQ3JlZGl0U2NvcmVSYW5nZUxvd2VyLCBkYXRhPWxvYW5zKQ0KI3N1bW1hcnkobG9hbnNfbG9nX21vZGVsXzEpDQpgYGANCiMgQnVpbGRpbmcgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwNCiMjIEZpcnN0LCBhIGxpdHRsZSBtb3JlIGRhdGEgbXVuZ2luZw0KDQpXZSBjYW4gdHJ5IHRvIHNlZSB3aGF0IGhhcHBlbnMgaWYgd2UgYXNrIFIgdG8gZ2VuZXJhdGUgdGhlIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwgdXNpbmcgYGdsbSgpYC4NCmBgYHtyfQ0KcHJlZGljdG9yc192ZWN0b3IgPC0gYygiVGVybSIsICJCb3Jyb3dlclJhdGUiLCAiQ3JlZGl0U2NvcmVSYW5nZUxvd2VyIiwgIkRlYnRUb0luY29tZVJhdGlvIiwgIkVtcGxveW1lbnRTdGF0dXNEdXJhdGlvbiIsICJJc0JvcnJvd2VySG9tZW93bmVyIiwgIkN1cnJlbnRDcmVkaXRMaW5lcyIsICJUb3RhbENyZWRpdExpbmVzcGFzdDd5ZWFycyIsICJPcGVuUmV2b2x2aW5nQWNjb3VudHMiLCAiT3BlblJldm9sdmluZ01vbnRobHlQYXltZW50IiwgIklucXVpcmllc0xhc3Q2TW9udGhzIiwgIlRvdGFsSW5xdWlyaWVzIiwgIkN1cnJlbnREZWxpbnF1ZW5jaWVzIiwgIkFtb3VudERlbGlucXVlbnQiLCAiRGVsaW5xdWVuY2llc0xhc3Q3WWVhcnMiLCAiUHVibGljUmVjb3Jkc0xhc3QxMFllYXJzIiwgIlB1YmxpY1JlY29yZHNMYXN0MTJNb250aHMiLCAiUmV2b2x2aW5nQ3JlZGl0QmFsYW5jZSIsICJCYW5rY2FyZFV0aWxpemF0aW9uIiwgIkF2YWlsYWJsZUJhbmtjYXJkQ3JlZGl0IiwgIkluY29tZVZlcmlmaWFibGUiLCAiU3RhdGVkTW9udGhseUluY29tZSIpDQoNCnByZWRpY3RvcnNfdmVjdG9yX3N1bSA8LSBwYXN0ZShwcmVkaWN0b3JzX3ZlY3RvciwgY29sbGFwc2U9IisiKQ0KDQpsb2dSZWdfbW9kZWxfZm1sYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJMb2FuU3RhdHVzIH4gIiwgcHJlZGljdG9yc192ZWN0b3Jfc3VtKSkNCmxvZ1JlZ19tb2RlbCA8LSBnbG0obG9nUmVnX21vZGVsX2ZtbGEsIGRhdGE9bG9hbnMsIGZhbWlseT1iaW5vbWlhbCkNCg0KYGBgDQoNCg0KUiByZXR1cm5zIGEgd2FybmluZzogZ2xtLmZpdDogZml0dGVkIHByb2JhYmlsaXRpZXMgbnVtZXJpY2FsbHkgMCBvciAxIG9jY3VycmVkLiBUaGlzIGhhcyB0byBkbyB3aXRoIFtiZWluZyBhYmxlIHRvIHBlcmZlY3RseSBzZXBhcmF0ZSB0aGUgcmVzcG9uc2UgYmFzZWQgb24gdGhlIHZhbHVlIG9mIHRoZSBwcmVkaWN0b3JzXShodHRwczovL3N0YXQuZXRoei5jaC9waXBlcm1haWwvci1oZWxwLzIwMDgtTWFyY2gvMTU2ODY4Lmh0bWwpLiBJbiBmYWN0LCBpZiB3ZSB0cnkgdG8gZ2VuZXJhdGUgYSBtb2RlbCB1c2luZyBqdXN0IHRoZSBwcmVkaWN0b3IgKioqU3RhdGVkTW9udGhseUluY29tZSoqKiwgd2UgZ2V0IHRoZSBzYW1lIHdhcm5pbmcuDQpgYGB7cn0NCnRlbXBfbW9kZWwgPC0gc3VtbWFyeShnbG0oTG9hblN0YXR1cyB+IFN0YXRlZE1vbnRobHlJbmNvbWUsIGRhdGE9bG9hbnMsIGZhbWlseT1iaW5vbWlhbCkpDQpgYGANCg0KQW1vbmcgdGhlIFtwb3NzaWJsZSBzb2x1dGlvbnMgdG8gdGhpcyBpc3N1ZV0oaHR0cDovL3N0YXRzLnN0YWNrZXhjaGFuZ2UuY29tL3F1ZXN0aW9ucy8xMTEwOS9ob3ctdG8tZGVhbC13aXRoLXBlcmZlY3Qtc2VwYXJhdGlvbi1pbi1sb2dpc3RpYy1yZWdyZXNzaW9uKSwgYmlubmluZyB0aGUgcHJlZGljdG9yIHZhbHVlcyBzZWVtcyBsaWtlIHRoZSBlYXNpZXN0IHRoaW5nIHRvIGRvLg0KDQpMZXQncyBzdGFydCB3aXRoICoqKlN0YXRlZE1vbnRobHlJbmNvbWUqKiouIA0KV2UgY2FuIHRyeSB0byBzcGxpdCAqU3RhdGVkTW9udGhseUluY29tZSogaW50byAkMSwwMDAgYmlucyB1c2luZyBgY3V0KClgLg0KYGBge3J9DQpNb250aGx5X0luY29tZV9SYW5nZXMgPC0gYygiJDAgLSAkMSw5OTkiLCAiJDIsMDAwIC0gJDIsOTk5IiwgIiQzLDAwMCAtICQzLDk5OSIsICIkNCwwMDAgLSAkNCw5OTkiLCAiJDUsMDAwIC0gJDUsOTk5IiwgIiQ2LDAwMCAtICQ2LDk5OSIsICIkNywwMDAgLSAkNyw5OTkiLCAiJDgsMDAwIC0gJDgsOTk5IiwgIiQ5LDAwMCAtICQ5LDk5OSIsICIkMTAsMDAwIC0gJDEwLDk5OSIsICIkMTEsMDAwIC0gJDExLDk5OSIsICIkMTIsMDAwIC0gJDEyLDk5OSIsICIkMTMsMDAwIC0gJDEzLDk5OSIsICIkMTQsMDAwIC0gJDE0LDk5OSIsICIkMTUsMDAwIG9yIG1vcmUiKQ0KbG9hbnMkU3RhdGVkTW9udGhseUluY29tZSA8LSBjdXQobG9hbnMkU3RhdGVkTW9udGhseUluY29tZSwgYygtSW5mLCBzZXEoMjAwMCwxNTAwMCwxMDAwKSwgSW5mKSwgbGFiZWxzPU1vbnRobHlfSW5jb21lX1JhbmdlcywgcmlnaHQ9RikNCmBgYA0KV2UgY2FuIGJpbiBvdGhlciB2YXJpYWJsZXMgYXMgd2VsbC4gSSB3aWxsIHNraXAgdGhlIGFjdHVhbCBjb2RlIHNpbmNlIGl0J3MgdmVyeSBzaW1pbGFyIHRvIHdoYXQgd2UganVzdCBkaWQgZm9yICoqKlN0YXRlZE1vdG5obHlJbmNvbWUqKiouIFRoZSBmb2xsb3dpbmcgdmFyaWFibGVzIHdpbGwgYmUgYmlubmVkOiAqKipJbnF1aXJpZXNMYXN0Nk1vbnRocyoqKiwgKioqVG90YWxJbnF1aXJpZXMqKiosICoqKkN1cnJlbnREZWxpbnF1ZW5jaWVzKioqLCAqKipBbW91bnREZWxpbnF1ZW50KioqLCAqKipEZWxpbnF1ZW5jaWVzTGFzdDdZZWFycyoqKiwgKioqUHVibGljUmVjb3Jkc0xhc3QxMFllYXJzKioqLCBhbmQgKioqUHVibGljUmVjb3Jkc0xhc3QxMk1vbnRocyoqKi4NCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpJbnF1aXJpZXNMYXN0Nk1vbnRoc19CaW5zIDwtIGMoIjAiLCAiMSIsICIyIiwgIjMiLCAiNCIsICI1IG9yIG1vcmUiKQ0KbG9hbnMkSW5xdWlyaWVzTGFzdDZNb250aHMgPC0gY3V0KGxvYW5zJElucXVpcmllc0xhc3Q2TW9udGhzLCBjKC1JbmYsIHNlcSgxLDUsMSksIEluZiksIGxhYmVscz1JbnF1aXJpZXNMYXN0Nk1vbnRoc19CaW5zLCByaWdodD1GKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KVG90YWxJbnF1aXJpZXNfQmlucyA8LSBjKCIwIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIsICI2IiwgIjciLCAiOCIsICI5IiwgIjEwIG9yIG1vcmUiKQ0KbG9hbnMkVG90YWxJbnF1aXJpZXMgPC0gY3V0KGxvYW5zJFRvdGFsSW5xdWlyaWVzLCBjKC1JbmYsIHNlcSgxLDEwLDEpLCBJbmYpLCBsYWJlbHM9VG90YWxJbnF1aXJpZXNfQmlucywgcmlnaHQ9RikNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCkN1cnJlbnREZWxpbnF1ZW5jaWVzX0JpbnMgPC0gYygiMCIsICIxIiwgIjIiLCAiMyBvciBtb3JlIikNCmxvYW5zJEN1cnJlbnREZWxpbnF1ZW5jaWVzIDwtIGN1dChsb2FucyRDdXJyZW50RGVsaW5xdWVuY2llcywgYygtSW5mLCBzZXEoMSwzLDEpLCBJbmYpLCBsYWJlbHM9Q3VycmVudERlbGlucXVlbmNpZXNfQmlucywgcmlnaHQ9RikNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCiNNYWtpbmcgaXQgYm9vbGVhbiwgc2luY2UgfjgwJSBib3Jyb3dlcnMgaGF2ZSBubyBkZWxpcXVlbnQgYW1vdW50cw0KbG9hbnMkQW1vdW50RGVsaW5xdWVudCA8LSBhcy5sb2dpY2FsKGxvYW5zJEFtb3VudERlbGlucXVlbnQpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpEZWxpbnF1ZW5jaWVzTGFzdDdZZWFyc19CaW5zIDwtIGMoIjAiLCAiMSIsICIyIiwgIjMiLCAiNCIsICI1IiwgIjYiLCAiNyIsICI4IiwgIjkiLCAiMTAgb3IgbW9yZSIpDQpsb2FucyREZWxpbnF1ZW5jaWVzTGFzdDdZZWFycyA8LSBjdXQobG9hbnMkRGVsaW5xdWVuY2llc0xhc3Q3WWVhcnMsIGMoLUluZiwgc2VxKDEsMTAsMSksIEluZiksIGxhYmVscz1EZWxpbnF1ZW5jaWVzTGFzdDdZZWFyc19CaW5zLCByaWdodD1GKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KUHVibGljUmVjb3Jkc0xhc3QxMFllYXJzX0JpbnMgPC0gYygiMCIsICIxIiwgIjIgb3IgbW9yZSIpDQpsb2FucyRQdWJsaWNSZWNvcmRzTGFzdDEwWWVhcnMgPC0gY3V0KGxvYW5zJFB1YmxpY1JlY29yZHNMYXN0MTBZZWFycywgYygtSW5mLCBzZXEoMSwyLDEpLCBJbmYpLCBsYWJlbHM9UHVibGljUmVjb3Jkc0xhc3QxMFllYXJzX0JpbnMsIHJpZ2h0PUYpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQojQWxzbyBtYWtpbmcgaXQgYm9vbGVhbg0KbG9hbnMkUHVibGljUmVjb3Jkc0xhc3QxMk1vbnRocyA8LSBhcy5sb2dpY2FsKGxvYW5zJFB1YmxpY1JlY29yZHNMYXN0MTJNb250aHMpDQpgYGANCldlIGNhbiB0cnkgYWdhaW46DQpgYGB7cn0NCmxvZ1JlZ19tb2RlbCA8LSBnbG0obG9nUmVnX21vZGVsX2ZtbGEsIGRhdGE9bG9hbnMsIGZhbWlseT1iaW5vbWlhbCkNCmBgYA0KV2Ugbm8gbG9uZ2VyIGdldCB0aGUgZ2xtLmZpdCB3YXJuaW5nLg0KDQpVc2luZyBgc3VtbWFyeShsb2dSZWdfbW9kZWwpYCwgd2Ugbm90ZSB0aGF0IHNvbWUgb2YgdGhlIHByZWRpY3RvcnMgd2VyZSBmb3VuZCB0byBiZSBub3QgW3N0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnRdKGh0dHBzOi8vd3d3LmNvdXJzZXJhLm9yZy9sZWFybi9saW5lYXItcmVncmVzc2lvbi1tb2RlbCkgaW4gZGV0ZXJtaW5pbmcgdGhlIHByb2JhYmlsaXR5IG9mIGEgbG9hbiBiZWluZyByZXBhaWQuIFRoZXNlIHdlcmUgKioqUHVibGljUmVjb3Jkc0xhc3QxMk1vbnRocyoqKiwgKioqQW1vdW50RGVsaW5xdWVudCoqKiwgKioqVG90YWxDcmVkaXRMaW5lc3Bhc3Q3eWVhcnMqKiosIGFuZCAqKipEZWxpbnF1ZW5jaWVzTGFzdDdZZWFycyoqKi4gVGhpcyBtaWdodCBoYXZlIGJlZW4gYmVjYXVzZSB0aGV5IGFyZSByZWxhdGVkIHRvIG90aGVyIHByZWRpY3RvcnMgaW4gdGhlIG1vZGVsIGFuZCB0aHVzIGFkZCBsaXR0bGUgb2YgdmFsdWUgdG8gaXQuIExldCdzIHJlbW92ZSB0aGVtIGZyb20gb3VyIG1vZGVsIGZvcm11bGE6DQoNCmBgYHtyfQ0KcmVtb3ZlX3ByZWRpY3RvcnMgPC0gYyAoIlB1YmxpY1JlY29yZHNMYXN0MTJNb250aHMiLCAiQW1vdW50RGVsaW5xdWVudCIsICJUb3RhbENyZWRpdExpbmVzcGFzdDd5ZWFycyIsICJEZWxpbnF1ZW5jaWVzTGFzdDdZZWFycyIpDQpwcmVkaWN0b3JzX3ZlY3RvciA8LSBzZXRkaWZmKHByZWRpY3RvcnNfdmVjdG9yLCByZW1vdmVfcHJlZGljdG9ycykNCnByZWRpY3RvcnNfdmVjdG9yX3N1bSA8LSBwYXN0ZShwcmVkaWN0b3JzX3ZlY3RvciwgY29sbGFwc2U9IisiKQ0KbG9nUmVnX21vZGVsX2ZtbGEgPC0gYXMuZm9ybXVsYShwYXN0ZSgiTG9hblN0YXR1cyB+ICIsIHByZWRpY3RvcnNfdmVjdG9yX3N1bSkpDQpgYGANCg0KDQojIyBUcmFpbmluZyBhbmQgdGVzdGluZyB0aGUgbW9kZWwNCiMjIyBTcGxpdHRpbmcgdGhlIGRhdGFzZXQgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXRzDQpMZXQncyBbc3BsaXQgdGhlIGRhdGEgaW50byB0cmFpbmluZyBhbmQgdGVzdCBzZXRzXShodHRwczovL3d3dy5lZHgub3JnL2NvdXJzZS9hbmFseXRpY3MtZWRnZS1taXR4LTE1LTA3MXgtMiksIHVzaW5nIHRoZSBsaWJyYXJ5IGBjYVRvb2xzKClgDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoY2FUb29scykNCnNldC5zZWVkKDE0NCkNCnNwbCA9IHNhbXBsZS5zcGxpdChsb2FucyRMb2FuU3RhdHVzLCAwLjcpDQp0cmFpbl9zZXQgPSBzdWJzZXQobG9hbnMsIHNwbCA9PSBUUlVFKQ0KdGVzdF9zZXQgPSBzdWJzZXQobG9hbnMsIHNwbCA9PSBGQUxTRSkNCmBgYA0KIyMjIENvbmZ1c2lvbiBtYXRyaXggYW5kIG1vZGVsIGFjY3VyYWN5DQpUcmFpbmluZyB0aGUgbW9kZWwgb24gdGhlIHNwbGl0IGRhdGFzZXQsIHdlIGNhbiB0YWJ1bGF0ZSB0aGUgY29uZnVzaW9uIG1hdHJpeCBieSBldmFsdWF0aW5nIHRoZSBtb2RlbCBwZXJmb3JtYW5jZSBvbiB0aGUgdGVzdCBzZXQsIHVzaW5nIGEgdGhyZXNob2xkIGZvciBsYWJlbGxpbmcgdGhlIGxvYW5zIG9mIDAuNToNCmBgYHtyfQ0KbG9nUmVnX21vZGVsIDwtIGdsbShsb2dSZWdfbW9kZWxfZm1sYSwgZGF0YT10cmFpbl9zZXQsIGZhbWlseT1iaW5vbWlhbCkNCiMgRXZhbHVhdGUgdGhlIHBlcmZvcm1hbmNlIG9uIHRlc3QgZGF0YXNldA0KIyB0ZXN0X3NldCRwcmVkaWN0ZWQucmlzayBpcyBhIHZlY3RvciBvZiBwcm9iYWJpbGl0aWVzDQojIEFjY29yZGluZyB0byBvdXIgbW9kZWwsIHRoZSBoaWdoZXIgdGhlIHByb2JhYmlsaXR5IHRoZSBtb3JlIGxpa2VseSB0aGUgbG9hbiB3aWxsIGJlIGdvb2QNCnRlc3Rfc2V0JHByZWRpY3RlZC5yaXNrID0gcHJlZGljdChsb2dSZWdfbW9kZWwsIG5ld2RhdGE9dGVzdF9zZXQsIHR5cGU9InJlc3BvbnNlIikNCiNDb25mdXNpb24gTWF0cml4IHVzaW5nIGEgdGhyZXNob2xkIG9mIDAuNQ0KdGhyZXNob2xkID0gMC41DQpjb25mdXNpb25fbWF0cml4IDwtIHRhYmxlKHRlc3Rfc2V0JExvYW5TdGF0dXMsIGFzLm51bWVyaWModGVzdF9zZXQkcHJlZGljdGVkLnJpc2sgPj0gdGhyZXNob2xkKSkNCmNvbmZ1c2lvbl9tYXRyaXgNCmBgYA0KVGhlIHJvd3MgaW4gdGhlIGNvbmZ1c2lvbiBtYXRyaXggcmVwcmVzZW50IHRoZSAidHJ1dGgiLiBXZSBoYXZlIGByIGNvbmZ1c2lvbl9tYXRyaXhbMSwxXWAgKyBgciBjb25mdXNpb25fbWF0cml4WzEsMl1gID0gYHIgc3VtKGNvbmZ1c2lvbl9tYXRyaXhbMSwxXSArIGNvbmZ1c2lvbl9tYXRyaXhbMSwyXSlgIHRvdGFsIGJhZCBsb2Fucywgb2Ygd2hpY2ggYHIgY29uZnVzaW9uX21hdHJpeFsxLDJdYCB3ZXJlIGxhYmVsbGVkLCBpbmNvcnJlY3RseSwgYXMgZ29vZCBsb2Fucy4gVGhhdCdzIG92ZXIgODAlIG9mIHRoZSBiYWQgbG9hbnMgdGhhdCB3ZXJlIGxhYmVsbGVkIGFzIGdvb2QuIFRoaXMgaXMgb3VyIEZhbHNlIFBvc2l0aXZlIFJhdCwgb3IgRlBSLiBTaW1pbGFybHksIHRoZXJlIGFyZSBgciBjb25mdXNpb25fbWF0cml4WzIsMV1gICsgYHIgY29uZnVzaW9uX21hdHJpeFsyLDJdYCA9IGByIHN1bShjb25mdXNpb25fbWF0cml4WzIsMV0gKyBjb25mdXNpb25fbWF0cml4WzIsMl0pYCB0b3RhbCBnb29kIGxvYW5zLCBvZiB3aGljaCBgciBjb25mdXNpb25fbWF0cml4WzIsMl1gIHdlcmUgbGFiZWxsZWQsIGNvcnJlY3RseSwgYXMgZ29vZCBsb2Fucy4gT3ZlciA5NyUgb2YgdGhlIGdvb2QgbG9hbnMgd2VyZSBsYWJlbGxlZCBjb3JyZWN0bHkuIFRoaXMgaXMgb3VyIFRydWUgUG9zaXRpdmUgUmF0ZSwgb3IgVFBSLiBXZSB3aWxsIHNlZSBzaG9ydGx5IGhvdyB0aGUgY2hvaWNlIG9mIHRocmVzaG9sZCBhbGxvd3MgdXMgdG8gdHJhZGUgRlBSIHdpdGggVFBSLg0KDQpVc2luZyB0aGUgY29uZnVzaW9uIG1hdHJpeCwgd2UgY2FuIGNvbXB1dGUgdGhlIGFjY3VyYWN5IG9mIG91ciBtb2RlbCBvbiB0aGUgdGVzdCBzZXQgYXMgdGhlIHJhdGlvIG9mIGxvYW5zIHRoYXQgd2VyZSBsYWJlbGxlZCBjb3JyZWN0bHkgZGl2aWRlZCBieSB0aGUgdG90YWwgbnVtYmVyIG9mIGxvYW5zLiBIZXJlIHdlIGhhdmUgYHIgY29uZnVzaW9uX21hdHJpeFsxLDFdYCArIGByIGNvbmZ1c2lvbl9tYXRyaXhbMiwyXWAgPSBgciBzdW0oY29uZnVzaW9uX21hdHJpeFsxLDFdICsgY29uZnVzaW9uX21hdHJpeFsyLDJdKWAgbG9hbnMgdGhhdCB3ZXJlIGxhYmVsbGVkIGNvcnJlY3RseSwgb3V0IG9mIGEgdG90YWwgb2YgYHIgc3VtKGNvbmZ1c2lvbl9tYXRyaXgpYCBsb2FucyBpbiB0aGUgdGVzdCBzZXQsIHNvIHRoZSBhY2N1cmFjeSBpcyBgciBzdW0oY29uZnVzaW9uX21hdHJpeFsxLDFdICsgY29uZnVzaW9uX21hdHJpeFsyLDJdKSAvIHN1bShjb25mdXNpb25fbWF0cml4KWAuDQoNCiMjIyBST0MgY3VydmUgYW5kIEFVQw0KVGhlIFJPQyAoUmVjZWl2ZXIgT3BlcmF0b3IgQ2hhcmFjdGVyaXN0aWMpIGN1cnZlIHBsb3RzIHRoZSBUcnVlIFBvc2l0aXZlIFJhdGUgKFRQUikgdmVyc3VzIHRoZSBGYWxzZSBQb3NpdGl2ZSBSYXRlIChGUFIpLiBUaGUgVFBSIGlzIHRoZSBmcmFjdGlvbiBvZiBnb29kIGxvYW5zIGluIHRoZSB0ZXN0IHNldCB0aGF0IHdlcmUgbGFiZWxsZWQgY29ycmVjdGx5ICgxKSwgd2hlcmVhcyB0aGUgRlBSIGlzIHRoZSBmcmFjdGlvbiBvZiBiYWQgbG9hbnMgdGhhdCB3ZXJlIGxhYmVsbGVkLCBpbmNvcnJlY3RseSwgYXMgZ29vZC4gSXQgYWxsb3dzIHVzIHRvIHZpc3VhbGl6ZSBob3cgdGhlIGNob2ljZSBvZiB0aHJlc2hvbGQgYWxsb3dzIHVzIHRvIHRyYWRlIG9mZiBUUFIgd2l0aCBGUFIuDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoUk9DUikNClJPQ1JwcmVkID0gcHJlZGljdGlvbih0ZXN0X3NldCRwcmVkaWN0ZWQucmlzaywgdGVzdF9zZXQkTG9hblN0YXR1cykNCg0KIyBQZXJmb3JtYW5jZSBmdW5jdGlvbg0KUk9DUnBlcmYgPSBwZXJmb3JtYW5jZShST0NScHJlZCwgInRwciIsICJmcHIiKQ0KIyBQbG90IFJPQyBjdXJ2ZQ0KcGxvdChST0NScGVyZiwgY29sb3JpemU9VFJVRSwgcHJpbnQuY3V0b2Zmcy5hdD1zZXEoMCwxLGJ5PTAuMSksIHRleHQuYWRqPWMoLTAuMiwxLjcpKQ0KZ3JpZCgpDQpgYGANCldlIGNhbiBjb21wdXRlIHRoZSBhcmVhIHVuZGVyIHRoZSBST0MgY3VydmUsIG9yIEFVQzoNCmBgYHtyfQ0KI0FVQw0KQVVDIDwtIGFzLm51bWVyaWMocGVyZm9ybWFuY2UoUk9DUnByZWQsICJhdWMiKUB5LnZhbHVlcykNCkFVQw0KYGBgDQpXZSB3YW50IHRoZSBBVUMgdG8gYmUgc2lnbmlmaWNhbnRseSBsYXJnZXIgdGhhbiAwLjUuDQoNCiMjIyBFeHBsb3JpbmcgZGlmZmVyZW50IHRocmVzaG9sZHMNCg0KV2UgY2FuIHNlZSB0aGF0IHVzaW5nIGEgdGhyZXNob2xkIG9mIDAuNSB0byBsYWJlbCB0aGUgbG9hbnMgd291bGQganVzdCBhYm91dCAiY2F0Y2giIGFsbCB0aGUgZ29vZCBsb2FucyBzaW5jZSB0aGUgVFBSIGlzIGFsbW9zdCAxLjAsIGJ1dCBpdCBhbHNvIG1lYW5zIHdlIGhhdmUgdG8gZWF0IG1vcmUgdGhhbiA4MCUgb2YgdGhlIGJhZCBsb2Fucy4gQSBjaG9pY2Ugb2YgdGhyZXNob2xkIG9mIDAuOCBvciBldmVuIDAuNyB3b3VsZCBsZWFkIHRvIGNhdGNoaW5nIDgwJSBvciBtb3JlIG9mIHRoZSBnb29kIGxvYW5zIHdoaWxlIGRpc2NhcmRpbmcgYmV0d2VlbiA0MCUgYW5kIDYwJSBvZiB0aGUgYmFkIG9uZXMgTGV0J3MgdHJ5IHVzaW5nIGEgdGhyZXNob2xkIG9mIDAuODoNCg0KYGBge3J9DQp0aHJlc2hvbGQyID0gMC44DQpjb25mdXNpb25fbWF0cml4MiA8LSB0YWJsZSh0ZXN0X3NldCRMb2FuU3RhdHVzLCBhcy5udW1lcmljKHRlc3Rfc2V0JHByZWRpY3RlZC5yaXNrID49IHRocmVzaG9sZDIpKQ0KY29uZnVzaW9uX21hdHJpeDINCmBgYA0KV2UgY2FuIHNlZSB0aGF0IGNob29zaW5nIGEgdGhyZXNob2xkIG9mIDAuOCBtZWFucyB3ZSB3b3VsZCBwYXNzIG9uLCBpLmUuLCBub3QgaW52ZXN0IGluLCBgciBjb25mdXNpb25fbWF0cml4MlsyLDFdYCBnb29kIGxvYW5zLiBPdXIgVFBSIGlzIGxvd2VyOiA3OSUsIHZlcnN1cyBtb3JlIHRoYW4gOTclIHdpdGggYSB0aHJlc2hvbGQgb2YgMC41LiBIb3dldmVyLCB0aGUgRlBSIGlzIG11Y2ggYmV0dGVyIG5vdywgYXMgd2UgYXJlIG9ubHkgbWlzbGFiZWxsaW5nIH40MCUgb2YgdGhlIGJhZCBsb2FucywgdmVyc3VzIG1vcmUgdGhhbiA4MCUgd2l0aCB0aGUgMC41IHRocmVzaG9sZC4gQWx0aG91Z2ggb3VyIGFjY3VyYWN5IGhhcyBkcm9wcGVkIGZyb20gODQlIHRvIGFib3V0IDc1JSwgSSB0aGluayB1c2luZyBhIHRocmVzaG9sZCBvZiAwLjggb3IgMC43IGlzIHByZWZlcmFibGUgdG8gdXNpbmcgMC41Lg0KDQojIENyb3NzLXZhbGlkYXRpb24NCldlIGNhbiB1c2UgdGhlIGBjYXJldGAgcGFja2FnZSB0byBwZXJmb3JtIGstZm9sZCBjcm9zcy12YWxpZGF0aW9uLiBUaGUgZGF0YSBpcyBzcGxpdCBpbiAqayogZm9sZHMgYW5kIHRoZSBtb2RlbCBpcyBnZW5lcmF0ZWQgdXNpbmcgKmstMSogZm9sZHMgb2YgdGhlIGRhdGEgYXMgYSB0cmFpbmluZyBzZXQsIGFuZCB0ZXN0ZWQgb24gdGhlIHJlbWFpbmluZyBmb2xkLiBUaGlzIGlzIGRvbmUgKmsqIHRpbWVzLCBvbmNlIGZvciBlYWNoIGZvbGQuIGBjYXJldGAgY29tcHV0ZXMgYW5kIHJlcG9ydHMgdGhlIGFjY3VyYWN5IG9mIHRoZSBtb2RlbCBlYWNoIHRpbWUuIFdlIGNhbiBjb21wYXJlIHRoZSBhY2N1cmFjaWVzIHdpdGggdGhlIDcwLTMwIHNwbGl0IG9mIHRoZSBkYXRhIHdlIGRpZCBlYXJsaWVyLg0KDQpGb3IgbG9naXN0aWMgcmVncmVzc2lvbiwgYGNhcmV0YCB1c2VzIGEgaGFyZHdpcmVkIHRocmVzaG9sZCBvZiAwLjUgdG8gY29tcHV0ZSB0aGUgYWNjdXJhY3kuIEFsdGhvdWdoIHdlIGNhbm5vdCBjaGFuZ2UgaXQsIHdlIGNhbiBjcm9zcy1jaGVjayB0aGUgYWNjdXJhY3kgbnVtYmVycyBpdCByZXBvcnRzIHdpdGggd2hhdCB3ZSBnb3QgZWFybGllciB1c2luZyBhIHRocmVzaG9sZCBvZiAwLjUuDQoNCltFeHBlcmllbmNlIGhhcyBzaG93bl0oaHR0cHM6Ly93d3cuYW1hem9uLmNvbS9EYXRhLU1pbmluZy1QcmFjdGljYWwtVGVjaG5pcXVlcy1NYW5hZ2VtZW50L2RwLzAxMjM3NDg1NjkpIHRoYXQgMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uIGdpdmVzIHRoZSBiZXN0IGVzdGltYXRlIG9mIGVycm9yLCBzbyB3ZSB3aWxsIHVzZSAqaz0xMCogZm9sZHMuDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoY2FyZXQpDQpmaXRDb250cm9sID0gdHJhaW5Db250cm9sKCBtZXRob2QgPSAiY3YiLCBudW1iZXIgPSAxMCwgcCA9IDAuNzAgKQ0KbG9nUmVnX21vZGVsX2N2IDwtIHRyYWluKGxvZ1JlZ19tb2RlbF9mbWxhLCBkYXRhPXRyYWluX3NldCwgbWV0aG9kID0gImJheWVzZ2xtIiwgdHJDb250cm9sID0gZml0Q29udHJvbCkNCmxvZ1JlZ19tb2RlbF9jdiRyZXNhbXBsZSRBY2N1cmFjeQ0KYGBgDQpXZSBzZWUgdGhhdCB0aGUgbW9kZWwgYWNjdXJhY3kgaXMgYWJvdXQgODQlIGVhY2ggdGltZSwgd2hpY2ggbWF0Y2hlcyB3aGF0IHdlIGRpZCBlYXJsaWVyIHVzaW5nIGEgMC41IHRocmVzaG9sZC4NCg0KIyBSZWZlcmVuY2VzDQoNCjEuICoqKlIgTm90ZWJvb2tzKioqLiBSZXRyaWV2ZWQgZnJvbSBbaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbV0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9yX25vdGVib29rcy5odG1sKQ0KDQoyLiAqKipQcm9zcGVyIGxvYW4gZGF0YSoqKi4gUmV0cmlldmVkIGZyb20gW2h0dHBzOi8vZG9jcy5nb29nbGUuY29tXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9kb2N1bWVudC9kLzFxRWN3bHRCTWxSWVpULWw2OTktNzFUekluV2ZrNFc5cTVyVENTdkRWTXBjL3B1Yj9lbWJlZGRlZD10cnVlKQ0KDQozLiAqKipQcm9zcGVyIGxvYW4gZGF0YSAtIHZhcmlhYmxlIGRlZmluaXRpb25zKioqLiBSZXRyaWV2ZWQgZnJvbSBbaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb21dKGh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFnRHlpX0w0VXZJckxURUM2V3JpNW5iYU1ta0dtTFFCay1ZeDN6MFhERXRJL2VkaXQjZ2lkPTApDQoNCjQuICoqKkxlbmRpbmcgQ2x1YiBTdGF0ZSBhbmQgRmluYW5jaWFsIFN1aXRhYmlsaXR5IGNvbmRpdGlvbnMqKiouIFJldHJpZXZlZCBmcm9tIFtodHRwczovL2hlbHAubGVuZGluZ2NsdWIuY29tXShodHRwczovL2hlbHAubGVuZGluZ2NsdWIuY29tL2hjL2VuLXVzL2FydGljbGVzLzIxNjA5Mjk1Ny1XaGF0LWFyZS10aGUtY3VycmVudC1TdGF0ZS1hbmQtRmluYW5jaWFsLVN1aXRhYmlsaXR5LWNvbmRpdGlvbnMtKQ0KDQo1LiAqKipQcm9zcGVyIFN0YXRlIEZpbmFuY2lhbCBTdWl0YWJpbGl0eSBSZXF1aXJlbWVudHMqKiouIFJldHJpZXZlZCBmcm9tIFtodHRwczovL3d3dy5wcm9zcGVyLmNvbV0oaHR0cHM6Ly93d3cucHJvc3Blci5jb20vcGxwL2xlZ2FsL2ZpbmFuY2lhbC1zdWl0YWJpbGl0eS8pDQoNCjYuIENoYW5nLCBXaW5zdG9uLiAqKipDb29rYm9vayBmb3IgUioqKi4gU2ViYXN0b3BvbDogTydSZWlsbHkgTWVkaWEsIDIwMTMuIFJldHJpZXZlZCBmcm9tIGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vDQoNCjcuIE1haWtlbFMuICoqKlNldCBOQSB0byAwIGluIFIqKiouIFJldHJpZXZlZCBmcm9tIFtodHRwOi8vc3RhY2tvdmVyZmxvdy5jb21dKGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTAxMzkyODQvc2V0LW5hLXRvLTAtaW4tcikuDQoNCjguIG1pa2UgYW5kIHNtdS4gKioqVGVzdCBpZiBjaGFyYWN0ZXJzIGluIHN0cmluZyBpbiBSKioqLiBSZXRyaWV2ZWQgZnJvbSBbaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tXShodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEwMTI4NjE3L3Rlc3QtaWYtY2hhcmFjdGVycy1pbi1zdHJpbmctaW4tcikuDQoNCjkuIFNocmV5ZXMuICoqKkVkaXRpbmcvQWRkaW5nIGZhY3RvciBsZXZlbHMgaW4gUioqKi4gUmV0cmlldmVkIGZyb20gW2h0dHA6Ly9wcm9ncmFtbWluZy1yLXByby1icm8uYmxvZ3Nwb3QuY29tXShodHRwOi8vcHJvZ3JhbW1pbmctci1wcm8tYnJvLmJsb2dzcG90LmNvbS8yMDEzLzA0L2VkaXRpbmdhZGRpbmctZmFjdG9yLWxldmVscy1pbi1yLmh0bWwpDQoNCjEwLiBIYXJkaW5nLCBUZWQuICoqKmdsbS5maXQ6IGZpdHRlZCBwcm9iYWJpbGl0aWVzIG51bWVyaWNhbGx5IDAgb3IgMSBvY2N1cnIqKiouIFJldHJpZXZlZCBmcm9tIFtodHRwczovL3N0YXQuZXRoei5jaF0oaHR0cHM6Ly9zdGF0LmV0aHouY2gvcGlwZXJtYWlsL3ItaGVscC8yMDA4LU1hcmNoLzE1Njg2OC5odG1sKQ0KDQoxMS4gdXNlcjMzMyBhbmQgU2NvcnRjaGkuICoqKkhvdyB0byBkZWFsIHdpdGggcGVyZmVjdCBzZXBhcmF0aW9uIGluIGxvZ2lzdGljIHJlZ3Jlc3Npb24/KioqIFJldHJpZXZlZCBmcm9tIFtodHRwOi8vc3RhdHMuc3RhY2tleGNoYW5nZS5jb21dKGh0dHA6Ly9zdGF0cy5zdGFja2V4Y2hhbmdlLmNvbS9xdWVzdGlvbnMvMTExMDkvaG93LXRvLWRlYWwtd2l0aC1wZXJmZWN0LXNlcGFyYXRpb24taW4tbG9naXN0aWMtcmVncmVzc2lvbikNCg0KMTIuIGdyYXV0dXIgYW5kIGp1YmEuICoqKmhvdyB0byBzdWNjaW5jdGx5IHdyaXRlIGEgZm9ybXVsYSB3aXRoIG1hbnkgdmFyaWFibGVzIGZyb20gYSBkYXRhIGZyYW1lPyoqKiBSZXRyaWV2ZWQgZnJvbSBbaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tXShodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzUyNTE1MDcvaG93LXRvLXN1Y2NpbmN0bHktd3JpdGUtYS1mb3JtdWxhLXdpdGgtbWFueS12YXJpYWJsZXMtZnJvbS1hLWRhdGEtZnJhbWUpLg0KDQoxMy4gQmVydHNpbWFzLCBELiwgTydIYWlyLCBBLiAqKipUaGUgQW5hbHl0aWNzIEVkZ2UqKiouIFNwcmluZyAyMDE0LiBbZWRYLm9yZ10od3d3LmVkWC5vcmcpLg0KDQoxNC4gamVhbm5vdCBhbmQgTHVjaWFubyBTZWx6ZXIuICoqKkhvdyB0byBjaGFuZ2UgdGhlIGRlZmF1bHQgZm9udCBzaXplIGluIGdncGxvdDIqKiouIFJldHJpZXZlZCBmcm9tIFtodHRwOi8vc3RhY2tvdmVyZmxvdy5jb21dKGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTE5NTUyMjkvaG93LXRvLWNoYW5nZS10aGUtZGVmYXVsdC1mb250LXNpemUtaW4tZ2dwbG90MikuDQoNCjE1LiBEYWlsIGFuZCBCcmlhbiBEaWdncy4gKioqSG93IHRvIGRlbGV0ZSBtdWx0aXBsZSB2YWx1ZXMgZnJvbSBhIHZlY3Rvcj8qKiouIFJldHJpZXZlZCBmcm9tIFtodHRwOi8vc3RhY2tvdmVyZmxvdy5jb21dKGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvOTY2NTk4NC9ob3ctdG8tZGVsZXRlLW11bHRpcGxlLXZhbHVlcy1mcm9tLWEtdmVjdG9yKS4NCg0KMTYuIFdpdHRlbiwgSS4sIEZyYW5rLCBFLiwgSGFsbCwgTS4gKioqRGF0YSBNaW5pbmc6IFByYWN0aWNhbCBNYWNoaW5lIExlYXJuaW5nIFRvb2xzIGFuZCBUZWNobmlxdWVzLCBUaGlyZCBFZGl0aW9uKioqLiBCdXJsaW5ndG9uOiBFbHNldmllciwgMjAxMS4gUERGLg0KDQoxNy4gw4dldGlua2F5YS1SdW5kZWwsIE0uICoqKkRhdGEgQW5hbHlzaXMgYW5kIFN0YXRpc3RpY2FsIEluZmVyZW5jZSoqKi4gU3ByaW5nIDIwMTQuIFt3d3cuY291cnNlcmEub3JnXSh3d3cuY291cnNlcmEub3JnKS4=