r = getOption("repos")
r["CRAN"] = "http://cran.us.r-project.org"
options(repos = r)
install.packages("rpart.plot")
Installing package into 㤼㸱C:/Users/Toby/Documents/R/win-library/3.6㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'http://cran.us.r-project.org/bin/windows/contrib/3.6/rpart.plot_3.0.8.zip'
Content type 'application/zip' length 1078195 bytes (1.0 MB)
downloaded 1.0 MB
package ‘rpart.plot’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\Toby\AppData\Local\Temp\Rtmp21Xoj7\downloaded_packages
install.packages("ggplot2")
Installing package into 㤼㸱C:/Users/Toby/Documents/R/win-library/3.6㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'http://cran.us.r-project.org/bin/windows/contrib/3.6/ggplot2_3.2.1.zip'
Content type 'application/zip' length 3975792 bytes (3.8 MB)
downloaded 3.8 MB
package ‘ggplot2’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\Toby\AppData\Local\Temp\Rtmp21Xoj7\downloaded_packages
install.packages("e1071")
Installing package into 㤼㸱C:/Users/Toby/Documents/R/win-library/3.6㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'http://cran.us.r-project.org/bin/windows/contrib/3.6/e1071_1.7-2.zip'
Content type 'application/zip' length 1021928 bytes (997 KB)
downloaded 997 KB
package ‘e1071’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\Toby\AppData\Local\Temp\Rtmp21Xoj7\downloaded_packages
library(ggplot2)
package 㤼㸱ggplot2㤼㸲 was built under R version 3.6.1Registered S3 method overwritten by 'dplyr':
method from
print.rowwise_df
getwd()
[1] "C:/Users/Toby/Downloads"
setwd("C:/Users/Toby/Downloads")
cc <- read.csv("UCI_Credit_Card.csv")
cc$default.payment.next.month <- factor(cc$default.payment.next.month, levels = c(0,1), labels = c("No","Yes"))
Education may impact payment defaults due to the limitations of having financial education or a certain education level. People with lower education may not know how to deal with paying debt or how credit cards are used properly. People with a lower education perhaps do not have high paying jobs that support their lifestyle.
Marriage may have an impact on payment default due to financial burdens. A two person house does not necessarily mean that there are two incomes. One spouse may have to support themselves and the other spouse.
Sex may have an impact on payment default due to higher spending habits. Females may have higher spending habits. Perhaps males are more impulsive and buy items with a higher price tag. But perhaps these two statements could be stereotypes.
Age may also have an impact on payment default due to experience with finance. Younger people may not know the risks of debt and credit card spending.
ggplot(cc, aes(x = SEX, fill = default.payment.next.month, color = default.payment.next.month)) + geom_histogram(binwidth = 1, position = "stack") + scale_color_manual(values = c("black", "black")) + scale_fill_manual(values = c("blue", "purple"))

I chose sex and default payment next month variables to create a histogram. In this distribution, males which are 1.0 on the x-axis have more “No” than “Yes”. But the overall counts of males are lower than females. Females have a higher count and there are more “No” than “Yes”. I believe that this variable cannot help to predict the default payment next month. The number of males and females in this dataset are not equal. If there were more males in this data, perhaps we could more Sex as a predictor but the data for both sexes are too uneven to tell.
ggplot(cc, aes(x = MARRIAGE, fill = default.payment.next.month, color = default.payment.next.month)) + geom_histogram(binwidth = 1, position = "stack") + scale_color_manual(values = c("black", "black")) + scale_fill_manual(values = c("green", "grey"))

I chose Marriage to examine default payment next month. In this distribution, those who are married in the 1 of the x-axis stated “No” more than “Yes”. Similarily, those who are single state “No” more than “Yes”. Also others who are on the 3 of the x-axis chosen “No” in a larger number. Overall all three marriage levels chose “No” more than they chose “Yes”. But I believe that Marriage cannot be used as a predictor of default payment next month. The counts of all three levels are not similar. If the counts were more equal, perhaps a decision can be made. But currently, Marriage is not a good predictor of default payment next month.
Payment status data may impact payment default due to certain times in the year. Perhaps at the end of the year, there are increased bonuses. Perhaps during the summer, more money is used to go on vacation and enjoy the heat.
ggplot(cc, aes(x = PAY_0, fill = default.payment.next.month, color = default.payment.next.month)) + geom_histogram(binwidth = 1, position = "stack") + scale_color_manual(values = c("black", "black")) + scale_fill_manual(values = c("darkred", "darkgreen"))

I chosen Pay_0 to examine with the default payment next month variable. In this distribution, most people paid duly and the least repaid a month or two months late. There were more people who chose “No” instead of “Yes” that will default payment next month. There were 15000 people that were paid duly and not months late. Perhaps unlike the other variable, there seems to be a possible correlation that when people do not pay duly, it is possible that they will not default payment next month.
ggplot(cc, aes(x = PAY_2, fill = default.payment.next.month, color = default.payment.next.month)) + geom_histogram(binwidth = 1, position = "stack") + scale_color_manual(values = c("black", "black")) + scale_fill_manual(values = c("pink", "blue"))

I chose the Pay_2 variable to examine with the default payment next month. In this distribution, most people chose “No” than “Yes” to default payment next month. It seems that most people paid duly and did not miss one month but more likely that they missed two months of repayment. Pay_2 describes the repayment status in August 2005. This variable could perhaps help to predict the default payment next month. There are more people who chose “Yes” to default payment next month when missing two months of repayment. Although not as good as Pay_0, this Pay_2 still could be a good predictor.
ggplot(cc, aes(x = PAY_6, fill = default.payment.next.month, color = default.payment.next.month)) + geom_histogram(binwidth = 1, position = "stack") + scale_color_manual(values = c("black", "black")) + scale_fill_manual(values = c("yellow", "violet"))

I chose Pay_6 to examine the default payment next month. In this distribution, there were more “No” than “Yes” for default payment next month. More people who pay duly did not default payment next month. But those who were 2 to 3 month late of repayment chose “Yes” for default payment next month. It seems that Pay_6 may be a good predictor of default payment next month. Those who missed repayment for 2-3 months most likely will default payment next month.
Variables that should be nominal:
Sex, Education, Marriage
cc$SEX <- factor(cc$SEX, levels=c(1,2), labels=c("Male", "Female"))
cc$EDUCATION <- factor(cc$EDUCATION, levels=c(1,2,3,4,5,6), labels=c("Graduate School", "University", "High School", "Others", "Unknown_1", "Unknown_2"))
cc$MARRIAGE <- factor(cc$MARRIAGE, levels=c(1,2,3), labels=c("Married", "Single", "Others"))
View(cc)
Choose 5000 random rows:
train <- cc[sample(nrow(cc), 5000),]
View(train)
Choose two random numbers:
test <- cc[c(9,25432),]
test
library(e1071)
package 㤼㸱e1071㤼㸲 was built under R version 3.6.1
nbDem <- naiveBayes(default.payment.next.month ~ SEX + EDUCATION + MARRIAGE, train)
nbDem
Naive Bayes Classifier for Discrete Predictors
Call:
naiveBayes.default(x = X, y = Y, laplace = laplace)
A-priori probabilities:
Y
No Yes
0.7824 0.2176
Conditional probabilities:
SEX
Y Male Female
No 0.3826687 0.6173313
Yes 0.4319853 0.5680147
EDUCATION
Y Graduate School University High School Others Unknown_1 Unknown_2
No 0.3832779340 0.4502684735 0.1457427768 0.0063922271 0.0127844541 0.0015341345
Yes 0.3134191176 0.4972426471 0.1819852941 0.0009191176 0.0055147059 0.0009191176
MARRIAGE
Y Married Single Others
No 0.435851472 0.554417414 0.009731114
Yes 0.452117864 0.536832413 0.011049724
Examining the conditional probabilities of Sex, the results are very interesting. It makes sense when comparing “Yes” of Female to Male. There are more Females that chose “Yes” than Males. But when examining the “No” for Male to Female. There are also more females that said “No” compared to “Male”. I think that I would need more analysis of Sex compared to default payment next month. It does not quite make sense for me.
When examining Education compared to default payment next month, the probabilities for education is a mixed of making sense and not quite enough information to make a statement. The highest probability for “Yes” are those in University but “Yes” and “No” the probability is quite similar. In both “No” and “Yes” for all levels of education, the probability seem quite similar. These probabilities are a little bit confusing to examine.
predict(nbDem, test[1,])
[1] No
Levels: No Yes
I believe that the predictions are correct. Test 1 is a female, with a high school education and married. Females based on the conditional probability states “No” more likely than “Yes” to default payment next month. As for education, those with high school educations it seems that those in that level of education have a lower probability in both “No” and “Yes”. As for marriage status, test 1 is married and those that all married state higher “Yes”. I do not know if I can say that the predictions are true. But there is evidence of it the prediction being assumed correct.
predict(nbDem, test[2,])
[1] No
Levels: No Yes
I believe that the predictions are correct. Test 2 is a female, with a university education and single. Females based on the conditional probabilities are more likely to state “No” than “Yes” to default payment next month. But for university education and marriage status, both have higher probabilities to state “Yes”. This may impact the correct prediction. But there is evidence that the prediction may be correct due to the Sex.
nbPay <- naiveBayes(default.payment.next.month ~ PAY_0 + PAY_2 + PAY_6, train)
nbPay
Naive Bayes Classifier for Discrete Predictors
Call:
naiveBayes.default(x = X, y = Y, laplace = laplace)
A-priori probabilities:
Y
No Yes
0.7824 0.2176
Conditional probabilities:
PAY_0
Y [,1] [,2]
No -0.2287832 0.9674105
Yes 0.6452206 1.3662562
PAY_2
Y [,1] [,2]
No -0.3284765 1.045978
Yes 0.4761029 1.455055
PAY_6
Y [,1] [,2]
No -0.4123211 1.010040
Yes 0.1654412 1.445171
For this conditional probability, it examines three payment status which have multiple levels. I am not sure about which levels of repayment is analyzed into the prediction. But looking at the probabilities I am assuming ,1 is stating paid duly and ,2 is months paid late. The probabilities do not make sense due to the negatives and some probabilities are higher than 1.
predict(nbPay, test[1,])
[1] No
Levels: No Yes
When examining Test 1’s answers about Pay_0, Pay_2 and Pay_6, all of the repayment status are 0. 0 means that Test 1 has paid duly for all three of these repayment dates. The prediction is correct to assume “No” to payment default next month due to these results. I believe that you can use these repayment status as a predictor to the variable payment default next month.
predict(nbPay, test[2,])
[1] No
Levels: No Yes
When examining Test 2’s anwers about Pay_0, Pay_2 and Pay_6, all of the repayment status are 0 or -1. -1 and 0 states that the payment were duly. Likewise with Test 1, the prediction is correct to assume “No” to payment default next month due to these results. I believe that you can these repayment status as a predictor to the variable payment default next month.
nbPay <- naiveBayes(default.payment.next.month ~ PAY_0 + PAY_2 + PAY_6, train, laplace = 1.5)
nbPay
Naive Bayes Classifier for Discrete Predictors
Call:
naiveBayes.default(x = X, y = Y, laplace = laplace)
A-priori probabilities:
Y
No Yes
0.7824 0.2176
Conditional probabilities:
PAY_0
Y [,1] [,2]
No -0.2287832 0.9674105
Yes 0.6452206 1.3662562
PAY_2
Y [,1] [,2]
No -0.3284765 1.045978
Yes 0.4761029 1.455055
PAY_6
Y [,1] [,2]
No -0.4123211 1.010040
Yes 0.1654412 1.445171
When examining the smoothed Naive Bayes, the conditional probabilities did not change. Laplace smoothing is used to keep probabilities from equaling zero. A zero is not well regarded to assumptions that even if something is a slightly possiblity the probability should not be zero. But laplace may assigned too much probability to a unseen event. Above, the probability did not change from the former.
predict(nbPay, test[1,])
[1] No
Levels: No Yes
It was yet again predicted to be “No” to default payment next month. The laplace smoothing did not change the outcome and the prediction of “No” seems to be correct.
predict(nbPay, test[2,])
[1] No
Levels: No Yes
For test 2, the prediction to default payment next month is “No”. The laplace smoothing did not change the prediction thus I making me believe that the prediction is correct.
DECISION TREE
library("rpart")
library("rpart.plot")
package 㤼㸱rpart.plot㤼㸲 was built under R version 3.6.1
dtPay <- rpart(default.payment.next.month ~ PAY_0 + PAY_2 + PAY_6, method = "class", data = train, parms = list(split = 'information'), minsplit = 20, cp = 0.02)
rpart.plot(dtPay, type = 4, extra = 1)

?rpart.control
In this decision tree, it examines the number of counts that Pay_0 (September 2005) was less than one month late. If the answer is “Yes”, people are assigned to the left side. If the answer is “No”, people are assigned to the right side. Then if Pay_0 was less than two months late, then people are assigned to the left side and people that are not two months late are assigned to the right. Each node contains two numbers, the right number agrees with the node statement at the top (“Yes” or “No”). The left number disagrees with the node statement at the top. The numbers seem reasonable except I do wonder about the left bottom left. Those who have Pay_0 more than two months, the majority count is that they will not default payment next month.
predict(nbPay, test[1,])
[1] No
Levels: No Yes
predict(dtPay, test[1,])
No Yes
9 0.8380549 0.1619451
The prediction is most likely “No” that Test 1 will default payment next month. I believe that these predictions will be correct and Test 1 will not default payment next month Both predictions believe that Test 1 will not default.
predict(nbPay, test[2,])
[1] No
Levels: No Yes
predict(dtPay, test[2,])
No Yes
25432 0.8380549 0.1619451
For Test 2, similar to Test 1 both predictions believe that they will not default payment next month. Based on the predict function and the high probability it states “No”. I believe that the prediction is correct and Test 2 will not default payment next month.
dtPay <- rpart(default.payment.next.month ~ PAY_0 + PAY_2 + PAY_6, method = "class", data = train, parms = list(split = 'information'), minsplit = 20, cp = 0.001)
rpart.plot(dtPay, type = 1, extra =1)

In this decision tree, people with Pay_0 less than one month late are assigned to the left. Those more than one month late assigned to the right. If Pay_0 is less than 2, they assigned to the left and those with more to the right. Both nodes are asked Pay_6 (April 2005) is less than one, agreed people are to the left and disagree is to the right. People who have Pay_2 (August 2005) more than 4 months are to the left and those who disagree to the right. I noticed that there were a few people that their Pay_2 is more than 4 months who believe they will not default payment next month. But other than that, I believe that the data is reasonable.
predict(dtPay, test[1,])
No Yes
9 0.8618838 0.1381162
predict(nbPay, test[1,])
[1] No
Levels: No Yes
In both prediction, Test 1 has been decided to be “No” for defaulting payment next month. Due to the high probability of Test 1 choosing “No”, I believe that the predictions are correct.
predict(dtPay, test[2,])
No Yes
25432 0.8618838 0.1381162
predict(nbPay, test[2,])
[1] No
Levels: No Yes
In this prediction, Test 2 has been decided “No” for defaulting payment next month. Similarly to Test 1, Test 2 has high probability of choosing “No” to default payment next month. From this evidence, I believe that the model is correct and the prediction will be true.
Conclusion
I believe that the Naive Bayes model is good but not visually easy to examine the data. The Naive Bayes model I believe is not as indepth as the Decision Tree. The decision tree identifies the data and the counts are assigned to a node based on the data. The decision tree separates the data by the three payment variables. It is more visually appealing to examine the three variables within each node. Both models predicted the same results as decided that Test 1 and Test 2 would state “No” to default payment next month. I do question why the decision tree’s data does not use probability and instead it uses counts.
Perhaps variables that should be examined in the classification model is the bill amount and the pay amount. It would help to identify how much someones’ bills is and how each person paid to examine the difference. Perhaps another decision tree or Naive Bayes model can be used to examine these variables with the default payment next month.
LS0tDQp0aXRsZTogIklORk8gQXNzaWdubWVudCAyIg0KYXV0aG9yOiAiVG9ieSBTaGV1bmciDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KYGBge3J9DQpyID0gZ2V0T3B0aW9uKCJyZXBvcyIpDQpyWyJDUkFOIl0gPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyINCm9wdGlvbnMocmVwb3MgPSByKQ0KDQppbnN0YWxsLnBhY2thZ2VzKCJycGFydC5wbG90IikNCmluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KaW5zdGFsbC5wYWNrYWdlcygiZTEwNzEiKQ0KDQpsaWJyYXJ5KGdncGxvdDIpDQpnZXR3ZCgpDQpzZXR3ZCgiQzovVXNlcnMvVG9ieS9Eb3dubG9hZHMiKQ0KY2MgPC0gcmVhZC5jc3YoIlVDSV9DcmVkaXRfQ2FyZC5jc3YiKQ0KY2MkZGVmYXVsdC5wYXltZW50Lm5leHQubW9udGggPC0gZmFjdG9yKGNjJGRlZmF1bHQucGF5bWVudC5uZXh0Lm1vbnRoLCBsZXZlbHMgPSBjKDAsMSksIGxhYmVscyA9IGMoIk5vIiwiWWVzIikpDQpgYGANCg0KRWR1Y2F0aW9uIG1heSBpbXBhY3QgcGF5bWVudCBkZWZhdWx0cyBkdWUgdG8gdGhlIGxpbWl0YXRpb25zIG9mIGhhdmluZyBmaW5hbmNpYWwgZWR1Y2F0aW9uIG9yIGEgY2VydGFpbiBlZHVjYXRpb24gbGV2ZWwuIFBlb3BsZSB3aXRoIGxvd2VyIGVkdWNhdGlvbiBtYXkgbm90IGtub3cgaG93IHRvIGRlYWwgd2l0aCBwYXlpbmcgZGVidCBvciBob3cgY3JlZGl0IGNhcmRzIGFyZSB1c2VkIHByb3Blcmx5LiBQZW9wbGUgd2l0aCBhIGxvd2VyIGVkdWNhdGlvbiBwZXJoYXBzIGRvIG5vdCBoYXZlIGhpZ2ggcGF5aW5nIGpvYnMgdGhhdCBzdXBwb3J0IHRoZWlyIGxpZmVzdHlsZS4gDQoNCk1hcnJpYWdlIG1heSBoYXZlIGFuIGltcGFjdCBvbiBwYXltZW50IGRlZmF1bHQgZHVlIHRvIGZpbmFuY2lhbCBidXJkZW5zLiBBIHR3byBwZXJzb24gaG91c2UgZG9lcyBub3QgbmVjZXNzYXJpbHkgbWVhbiB0aGF0IHRoZXJlIGFyZSB0d28gaW5jb21lcy4gT25lIHNwb3VzZSBtYXkgaGF2ZSB0byBzdXBwb3J0IHRoZW1zZWx2ZXMgYW5kIHRoZSBvdGhlciBzcG91c2UuIA0KDQpTZXggbWF5IGhhdmUgYW4gaW1wYWN0IG9uIHBheW1lbnQgZGVmYXVsdCBkdWUgdG8gaGlnaGVyIHNwZW5kaW5nIGhhYml0cy4gRmVtYWxlcyBtYXkgaGF2ZSBoaWdoZXIgc3BlbmRpbmcgaGFiaXRzLiBQZXJoYXBzIG1hbGVzIGFyZSBtb3JlIGltcHVsc2l2ZSBhbmQgYnV5IGl0ZW1zIHdpdGggYSBoaWdoZXIgcHJpY2UgdGFnLiBCdXQgcGVyaGFwcyB0aGVzZSB0d28gc3RhdGVtZW50cyBjb3VsZCBiZSBzdGVyZW90eXBlcy4gDQoNCkFnZSBtYXkgYWxzbyBoYXZlIGFuIGltcGFjdCBvbiBwYXltZW50IGRlZmF1bHQgZHVlIHRvIGV4cGVyaWVuY2Ugd2l0aCBmaW5hbmNlLiBZb3VuZ2VyIHBlb3BsZSBtYXkgbm90IGtub3cgdGhlIHJpc2tzIG9mIGRlYnQgYW5kIGNyZWRpdCBjYXJkIHNwZW5kaW5nLiANCg0KYGBge3J9DQpnZ3Bsb3QoY2MsIGFlcyh4ID0gU0VYLCBmaWxsID0gZGVmYXVsdC5wYXltZW50Lm5leHQubW9udGgsIGNvbG9yID0gZGVmYXVsdC5wYXltZW50Lm5leHQubW9udGgpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgcG9zaXRpb24gPSAic3RhY2siKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJibGFjayIpKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiLCAicHVycGxlIikpDQpgYGANCkkgY2hvc2Ugc2V4IGFuZCBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aCB2YXJpYWJsZXMgdG8gY3JlYXRlIGEgaGlzdG9ncmFtLiBJbiB0aGlzIGRpc3RyaWJ1dGlvbiwgbWFsZXMgd2hpY2ggYXJlIDEuMCBvbiB0aGUgeC1heGlzIGhhdmUgbW9yZSAiTm8iIHRoYW4gIlllcyIuIEJ1dCB0aGUgb3ZlcmFsbCBjb3VudHMgb2YgbWFsZXMgYXJlIGxvd2VyIHRoYW4gZmVtYWxlcy4gRmVtYWxlcyBoYXZlIGEgaGlnaGVyIGNvdW50IGFuZCB0aGVyZSBhcmUgbW9yZSAiTm8iIHRoYW4gIlllcyIuIEkgYmVsaWV2ZSB0aGF0IHRoaXMgdmFyaWFibGUgY2Fubm90IGhlbHAgdG8gcHJlZGljdCB0aGUgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIFRoZSBudW1iZXIgb2YgbWFsZXMgYW5kIGZlbWFsZXMgaW4gdGhpcyBkYXRhc2V0IGFyZSBub3QgZXF1YWwuIElmIHRoZXJlIHdlcmUgbW9yZSBtYWxlcyBpbiB0aGlzIGRhdGEsIHBlcmhhcHMgd2UgY291bGQgbW9yZSBTZXggYXMgYSBwcmVkaWN0b3IgYnV0IHRoZSBkYXRhIGZvciBib3RoIHNleGVzIGFyZSB0b28gdW5ldmVuIHRvIHRlbGwuIA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGNjLCBhZXMoeCA9IE1BUlJJQUdFLCBmaWxsID0gZGVmYXVsdC5wYXltZW50Lm5leHQubW9udGgsIGNvbG9yID0gZGVmYXVsdC5wYXltZW50Lm5leHQubW9udGgpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgcG9zaXRpb24gPSAic3RhY2siKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJibGFjayIpKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZWVuIiwgImdyZXkiKSkNCmBgYA0KDQpJIGNob3NlIE1hcnJpYWdlIHRvIGV4YW1pbmUgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIEluIHRoaXMgZGlzdHJpYnV0aW9uLCB0aG9zZSB3aG8gYXJlIG1hcnJpZWQgaW4gdGhlIDEgb2YgdGhlIHgtYXhpcyBzdGF0ZWQgIk5vIiBtb3JlIHRoYW4gIlllcyIuIFNpbWlsYXJpbHksIHRob3NlIHdobyBhcmUgc2luZ2xlIHN0YXRlICJObyIgbW9yZSB0aGFuICJZZXMiLiBBbHNvIG90aGVycyB3aG8gYXJlIG9uIHRoZSAzIG9mIHRoZSB4LWF4aXMgY2hvc2VuICJObyIgaW4gYSBsYXJnZXIgbnVtYmVyLiBPdmVyYWxsIGFsbCB0aHJlZSBtYXJyaWFnZSBsZXZlbHMgY2hvc2UgIk5vIiBtb3JlIHRoYW4gdGhleSBjaG9zZSAiWWVzIi4gQnV0IEkgYmVsaWV2ZSB0aGF0IE1hcnJpYWdlIGNhbm5vdCBiZSB1c2VkIGFzIGEgcHJlZGljdG9yIG9mIGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiBUaGUgY291bnRzIG9mIGFsbCB0aHJlZSBsZXZlbHMgYXJlIG5vdCBzaW1pbGFyLiBJZiB0aGUgY291bnRzIHdlcmUgbW9yZSBlcXVhbCwgcGVyaGFwcyBhIGRlY2lzaW9uIGNhbiBiZSBtYWRlLiBCdXQgY3VycmVudGx5LCBNYXJyaWFnZSBpcyBub3QgYSBnb29kIHByZWRpY3RvciBvZiBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aC4gDQoNClBheW1lbnQgc3RhdHVzIGRhdGEgbWF5IGltcGFjdCBwYXltZW50IGRlZmF1bHQgZHVlIHRvIGNlcnRhaW4gdGltZXMgaW4gdGhlIHllYXIuIFBlcmhhcHMgYXQgdGhlIGVuZCBvZiB0aGUgeWVhciwgdGhlcmUgYXJlIGluY3JlYXNlZCBib251c2VzLiBQZXJoYXBzIGR1cmluZyB0aGUgc3VtbWVyLCBtb3JlIG1vbmV5IGlzIHVzZWQgdG8gZ28gb24gdmFjYXRpb24gYW5kIGVuam95IHRoZSBoZWF0LiANCg0KDQpgYGB7cn0NCiBnZ3Bsb3QoY2MsIGFlcyh4ID0gUEFZXzAsIGZpbGwgPSBkZWZhdWx0LnBheW1lbnQubmV4dC5tb250aCwgY29sb3IgPSBkZWZhdWx0LnBheW1lbnQubmV4dC5tb250aCkpICsgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxLCBwb3NpdGlvbiA9ICJzdGFjayIpICsgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgImJsYWNrIikpICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZGFya3JlZCIsICJkYXJrZ3JlZW4iKSkNCg0KYGBgDQoNCkkgY2hvc2VuIFBheV8wIHRvIGV4YW1pbmUgd2l0aCB0aGUgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGggdmFyaWFibGUuIEluIHRoaXMgZGlzdHJpYnV0aW9uLCBtb3N0IHBlb3BsZSBwYWlkIGR1bHkgYW5kIHRoZSBsZWFzdCByZXBhaWQgYSBtb250aCBvciB0d28gbW9udGhzIGxhdGUuIFRoZXJlIHdlcmUgbW9yZSBwZW9wbGUgd2hvIGNob3NlICJObyIgaW5zdGVhZCBvZiAiWWVzIiB0aGF0IHdpbGwgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIFRoZXJlIHdlcmUgMTUwMDAgcGVvcGxlIHRoYXQgd2VyZSBwYWlkIGR1bHkgYW5kIG5vdCBtb250aHMgbGF0ZS4gUGVyaGFwcyB1bmxpa2UgdGhlIG90aGVyIHZhcmlhYmxlLCB0aGVyZSBzZWVtcyB0byBiZSBhIHBvc3NpYmxlIGNvcnJlbGF0aW9uIHRoYXQgd2hlbiBwZW9wbGUgZG8gbm90IHBheSBkdWx5LCBpdCBpcyBwb3NzaWJsZSB0aGF0IHRoZXkgd2lsbCBub3QgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGNjLCBhZXMoeCA9IFBBWV8yLCBmaWxsID0gZGVmYXVsdC5wYXltZW50Lm5leHQubW9udGgsIGNvbG9yID0gZGVmYXVsdC5wYXltZW50Lm5leHQubW9udGgpKSArIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgcG9zaXRpb24gPSAic3RhY2siKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJibGFjayIpKSArIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInBpbmsiLCAiYmx1ZSIpKQ0KDQpgYGANCg0KSSBjaG9zZSB0aGUgUGF5XzIgdmFyaWFibGUgdG8gZXhhbWluZSB3aXRoIHRoZSBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aC4gSW4gdGhpcyBkaXN0cmlidXRpb24sIG1vc3QgcGVvcGxlIGNob3NlICJObyIgdGhhbiAiWWVzIiB0byBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aC4gSXQgc2VlbXMgdGhhdCBtb3N0IHBlb3BsZSBwYWlkIGR1bHkgYW5kIGRpZCBub3QgbWlzcyBvbmUgbW9udGggYnV0IG1vcmUgbGlrZWx5IHRoYXQgdGhleSBtaXNzZWQgdHdvIG1vbnRocyBvZiByZXBheW1lbnQuIFBheV8yIGRlc2NyaWJlcyB0aGUgcmVwYXltZW50IHN0YXR1cyBpbiBBdWd1c3QgMjAwNS4gVGhpcyB2YXJpYWJsZSBjb3VsZCBwZXJoYXBzIGhlbHAgdG8gcHJlZGljdCB0aGUgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIFRoZXJlIGFyZSBtb3JlIHBlb3BsZSB3aG8gY2hvc2UgIlllcyIgdG8gZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGggd2hlbiBtaXNzaW5nIHR3byBtb250aHMgb2YgcmVwYXltZW50LiBBbHRob3VnaCBub3QgYXMgZ29vZCBhcyBQYXlfMCwgdGhpcyBQYXlfMiBzdGlsbCBjb3VsZCBiZSBhIGdvb2QgcHJlZGljdG9yLiAgDQoNCg0KDQpgYGB7cn0NCmdncGxvdChjYywgYWVzKHggPSBQQVlfNiwgZmlsbCA9IGRlZmF1bHQucGF5bWVudC5uZXh0Lm1vbnRoLCBjb2xvciA9IGRlZmF1bHQucGF5bWVudC5uZXh0Lm1vbnRoKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIHBvc2l0aW9uID0gInN0YWNrIikgKyBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCAiYmxhY2siKSkgKyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJ5ZWxsb3ciLCAidmlvbGV0IikpDQoNCg0KYGBgDQoNCkkgY2hvc2UgUGF5XzYgdG8gZXhhbWluZSB0aGUgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIEluIHRoaXMgZGlzdHJpYnV0aW9uLCB0aGVyZSB3ZXJlIG1vcmUgIk5vIiB0aGFuICJZZXMiIGZvciBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aC4gTW9yZSBwZW9wbGUgd2hvIHBheSBkdWx5IGRpZCBub3QgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIEJ1dCB0aG9zZSB3aG8gd2VyZSAyIHRvIDMgbW9udGggbGF0ZSBvZiByZXBheW1lbnQgY2hvc2UgIlllcyIgZm9yIGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiBJdCBzZWVtcyB0aGF0IFBheV82IG1heSBiZSBhIGdvb2QgcHJlZGljdG9yIG9mIGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiBUaG9zZSB3aG8gbWlzc2VkIHJlcGF5bWVudCBmb3IgMi0zIG1vbnRocyBtb3N0IGxpa2VseSB3aWxsIGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiANCg0KVmFyaWFibGVzIHRoYXQgc2hvdWxkIGJlIG5vbWluYWw6DQoNClNleCwgRWR1Y2F0aW9uLCBNYXJyaWFnZQ0KDQpgYGB7cn0NCmNjJFNFWCA8LSBmYWN0b3IoY2MkU0VYLCBsZXZlbHM9YygxLDIpLCBsYWJlbHM9YygiTWFsZSIsICJGZW1hbGUiKSkNCg0KY2MkRURVQ0FUSU9OIDwtIGZhY3RvcihjYyRFRFVDQVRJT04sIGxldmVscz1jKDEsMiwzLDQsNSw2KSwgbGFiZWxzPWMoIkdyYWR1YXRlIFNjaG9vbCIsICJVbml2ZXJzaXR5IiwgIkhpZ2ggU2Nob29sIiwgIk90aGVycyIsICJVbmtub3duXzEiLCAiVW5rbm93bl8yIikpDQoNCmNjJE1BUlJJQUdFIDwtIGZhY3RvcihjYyRNQVJSSUFHRSwgbGV2ZWxzPWMoMSwyLDMpLCBsYWJlbHM9YygiTWFycmllZCIsICJTaW5nbGUiLCAiT3RoZXJzIikpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KVmlldyhjYykNCmBgYA0KDQpDaG9vc2UgNTAwMCByYW5kb20gcm93czoNCmBgYHtyfQ0KdHJhaW4gPC0gY2Nbc2FtcGxlKG5yb3coY2MpLCA1MDAwKSxdDQpWaWV3KHRyYWluKQ0KYGBgDQoNCkNob29zZSB0d28gcmFuZG9tIG51bWJlcnM6DQpgYGB7cn0NCnRlc3QgPC0gY2NbYyg5LDI1NDMyKSxdDQp0ZXN0DQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGUxMDcxKQ0KbmJEZW0gPC0gbmFpdmVCYXllcyhkZWZhdWx0LnBheW1lbnQubmV4dC5tb250aCB+IFNFWCArIEVEVUNBVElPTiArIE1BUlJJQUdFLCB0cmFpbikNCm5iRGVtDQpgYGANCg0KRXhhbWluaW5nIHRoZSBjb25kaXRpb25hbCBwcm9iYWJpbGl0aWVzIG9mIFNleCwgdGhlIHJlc3VsdHMgYXJlIHZlcnkgaW50ZXJlc3RpbmcuIEl0IG1ha2VzIHNlbnNlIHdoZW4gY29tcGFyaW5nICJZZXMiIG9mIEZlbWFsZSB0byBNYWxlLiBUaGVyZSBhcmUgbW9yZSBGZW1hbGVzIHRoYXQgY2hvc2UgIlllcyIgdGhhbiBNYWxlcy4gQnV0IHdoZW4gZXhhbWluaW5nIHRoZSAiTm8iIGZvciBNYWxlIHRvIEZlbWFsZS4gVGhlcmUgYXJlIGFsc28gbW9yZSBmZW1hbGVzIHRoYXQgc2FpZCAiTm8iIGNvbXBhcmVkIHRvICJNYWxlIi4gSSB0aGluayB0aGF0IEkgd291bGQgbmVlZCBtb3JlIGFuYWx5c2lzIG9mIFNleCBjb21wYXJlZCB0byBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aC4gSXQgZG9lcyBub3QgcXVpdGUgbWFrZSBzZW5zZSBmb3IgbWUuIA0KDQpXaGVuIGV4YW1pbmluZyBFZHVjYXRpb24gY29tcGFyZWQgdG8gZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGgsIHRoZSBwcm9iYWJpbGl0aWVzIGZvciBlZHVjYXRpb24gaXMgYSBtaXhlZCBvZiBtYWtpbmcgc2Vuc2UgYW5kIG5vdCBxdWl0ZSBlbm91Z2ggaW5mb3JtYXRpb24gdG8gbWFrZSBhIHN0YXRlbWVudC4gVGhlIGhpZ2hlc3QgcHJvYmFiaWxpdHkgZm9yICJZZXMiIGFyZSB0aG9zZSBpbiBVbml2ZXJzaXR5IGJ1dCAiWWVzIiBhbmQgIk5vIiB0aGUgcHJvYmFiaWxpdHkgaXMgcXVpdGUgc2ltaWxhci4gSW4gYm90aCAiTm8iIGFuZCAiWWVzIiBmb3IgYWxsIGxldmVscyBvZiBlZHVjYXRpb24sIHRoZSBwcm9iYWJpbGl0eSBzZWVtIHF1aXRlIHNpbWlsYXIuIFRoZXNlIHByb2JhYmlsaXRpZXMgYXJlIGEgbGl0dGxlIGJpdCBjb25mdXNpbmcgdG8gZXhhbWluZS4gDQoNCmBgYHtyfQ0KcHJlZGljdChuYkRlbSwgdGVzdFsxLF0pDQpgYGANCg0KSSBiZWxpZXZlIHRoYXQgdGhlIHByZWRpY3Rpb25zIGFyZSBjb3JyZWN0LiBUZXN0IDEgaXMgYSBmZW1hbGUsIHdpdGggYSBoaWdoIHNjaG9vbCBlZHVjYXRpb24gYW5kIG1hcnJpZWQuIEZlbWFsZXMgYmFzZWQgb24gdGhlIGNvbmRpdGlvbmFsIHByb2JhYmlsaXR5IHN0YXRlcyAiTm8iIG1vcmUgbGlrZWx5IHRoYW4gIlllcyIgdG8gZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIEFzIGZvciBlZHVjYXRpb24sIHRob3NlIHdpdGggaGlnaCBzY2hvb2wgZWR1Y2F0aW9ucyBpdCBzZWVtcyB0aGF0IHRob3NlIGluIHRoYXQgbGV2ZWwgb2YgZWR1Y2F0aW9uIGhhdmUgYSBsb3dlciBwcm9iYWJpbGl0eSBpbiBib3RoICJObyIgYW5kICJZZXMiLiBBcyBmb3IgbWFycmlhZ2Ugc3RhdHVzLCB0ZXN0IDEgaXMgbWFycmllZCBhbmQgdGhvc2UgdGhhdCBhbGwgbWFycmllZCBzdGF0ZSBoaWdoZXIgIlllcyIuIEkgZG8gbm90IGtub3cgaWYgSSBjYW4gc2F5IHRoYXQgdGhlIHByZWRpY3Rpb25zIGFyZSB0cnVlLiBCdXQgdGhlcmUgaXMgZXZpZGVuY2Ugb2YgaXQgdGhlIHByZWRpY3Rpb24gYmVpbmcgYXNzdW1lZCBjb3JyZWN0LiANCg0KYGBge3J9DQpwcmVkaWN0KG5iRGVtLCB0ZXN0WzIsXSkNCmBgYA0KDQpJIGJlbGlldmUgdGhhdCB0aGUgcHJlZGljdGlvbnMgYXJlIGNvcnJlY3QuIFRlc3QgMiBpcyBhIGZlbWFsZSwgd2l0aCBhIHVuaXZlcnNpdHkgZWR1Y2F0aW9uIGFuZCBzaW5nbGUuIEZlbWFsZXMgYmFzZWQgb24gdGhlIGNvbmRpdGlvbmFsIHByb2JhYmlsaXRpZXMgYXJlIG1vcmUgbGlrZWx5IHRvIHN0YXRlICJObyIgdGhhbiAiWWVzIiB0byBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aC4gDQpCdXQgZm9yIHVuaXZlcnNpdHkgZWR1Y2F0aW9uIGFuZCBtYXJyaWFnZSBzdGF0dXMsIGJvdGggaGF2ZSBoaWdoZXIgcHJvYmFiaWxpdGllcyB0byBzdGF0ZSAiWWVzIi4gVGhpcyBtYXkgaW1wYWN0IHRoZSBjb3JyZWN0IHByZWRpY3Rpb24uIEJ1dCB0aGVyZSBpcyBldmlkZW5jZSB0aGF0IHRoZSBwcmVkaWN0aW9uIG1heSBiZSBjb3JyZWN0IGR1ZSB0byB0aGUgU2V4LiANCg0KYGBge3J9DQpuYlBheSA8LSBuYWl2ZUJheWVzKGRlZmF1bHQucGF5bWVudC5uZXh0Lm1vbnRoIH4gUEFZXzAgKyBQQVlfMiArIFBBWV82LCB0cmFpbikNCm5iUGF5DQpgYGANCg0KRm9yIHRoaXMgY29uZGl0aW9uYWwgcHJvYmFiaWxpdHksIGl0IGV4YW1pbmVzIHRocmVlIHBheW1lbnQgc3RhdHVzIHdoaWNoIGhhdmUgbXVsdGlwbGUgbGV2ZWxzLiBJIGFtIG5vdCBzdXJlIGFib3V0IHdoaWNoIGxldmVscyBvZiByZXBheW1lbnQgaXMgYW5hbHl6ZWQgaW50byB0aGUgcHJlZGljdGlvbi4gQnV0IGxvb2tpbmcgYXQgdGhlIHByb2JhYmlsaXRpZXMgSSBhbSBhc3N1bWluZyAsMSBpcyBzdGF0aW5nIHBhaWQgZHVseSBhbmQgLDIgaXMgbW9udGhzIHBhaWQgbGF0ZS4gVGhlIHByb2JhYmlsaXRpZXMgZG8gbm90IG1ha2Ugc2Vuc2UgZHVlIHRvIHRoZSBuZWdhdGl2ZXMgYW5kIHNvbWUgcHJvYmFiaWxpdGllcyBhcmUgaGlnaGVyIHRoYW4gMS4gDQoNCmBgYHtyfQ0KcHJlZGljdChuYlBheSwgdGVzdFsxLF0pDQpgYGANCg0KV2hlbiBleGFtaW5pbmcgVGVzdCAxJ3MgYW5zd2VycyBhYm91dCBQYXlfMCwgUGF5XzIgYW5kIFBheV82LCBhbGwgb2YgdGhlIHJlcGF5bWVudCBzdGF0dXMgYXJlIDAuIDAgbWVhbnMgdGhhdCBUZXN0IDEgaGFzIHBhaWQgZHVseSBmb3IgYWxsIHRocmVlIG9mIHRoZXNlIHJlcGF5bWVudCBkYXRlcy4gVGhlIHByZWRpY3Rpb24gaXMgY29ycmVjdCB0byBhc3N1bWUgIk5vIiB0byBwYXltZW50IGRlZmF1bHQgbmV4dCBtb250aCBkdWUgdG8gdGhlc2UgcmVzdWx0cy4gSSBiZWxpZXZlIHRoYXQgeW91IGNhbiB1c2UgdGhlc2UgcmVwYXltZW50IHN0YXR1cyBhcyBhIHByZWRpY3RvciB0byB0aGUgdmFyaWFibGUgcGF5bWVudCBkZWZhdWx0IG5leHQgbW9udGguICANCg0KDQpgYGB7cn0NCnByZWRpY3QobmJQYXksIHRlc3RbMixdKQ0KYGBgDQoNCldoZW4gZXhhbWluaW5nIFRlc3QgMidzIGFud2VycyBhYm91dCBQYXlfMCwgUGF5XzIgYW5kIFBheV82LCBhbGwgb2YgdGhlIHJlcGF5bWVudCBzdGF0dXMgYXJlIDAgb3IgLTEuIC0xIGFuZCAwIHN0YXRlcyB0aGF0IHRoZSBwYXltZW50IHdlcmUgZHVseS4gTGlrZXdpc2Ugd2l0aCBUZXN0IDEsIHRoZSBwcmVkaWN0aW9uIGlzIGNvcnJlY3QgdG8gYXNzdW1lICJObyIgdG8gcGF5bWVudCBkZWZhdWx0IG5leHQgbW9udGggZHVlIHRvIHRoZXNlIHJlc3VsdHMuIEkgYmVsaWV2ZSB0aGF0IHlvdSBjYW4gdGhlc2UgcmVwYXltZW50IHN0YXR1cyBhcyBhIHByZWRpY3RvciB0byB0aGUgdmFyaWFibGUgcGF5bWVudCBkZWZhdWx0IG5leHQgbW9udGguIA0KDQoNCmBgYHtyfQ0KbmJQYXkgPC0gbmFpdmVCYXllcyhkZWZhdWx0LnBheW1lbnQubmV4dC5tb250aCB+IFBBWV8wICsgUEFZXzIgKyBQQVlfNiwgdHJhaW4sIGxhcGxhY2UgPSAxLjUpDQpuYlBheQ0KYGBgDQoNCldoZW4gZXhhbWluaW5nIHRoZSBzbW9vdGhlZCBOYWl2ZSBCYXllcywgdGhlIGNvbmRpdGlvbmFsIHByb2JhYmlsaXRpZXMgZGlkIG5vdCBjaGFuZ2UuIExhcGxhY2Ugc21vb3RoaW5nIGlzIHVzZWQgdG8ga2VlcCBwcm9iYWJpbGl0aWVzIGZyb20gZXF1YWxpbmcgemVyby4gQSB6ZXJvIGlzIG5vdCB3ZWxsIHJlZ2FyZGVkIHRvIGFzc3VtcHRpb25zIHRoYXQgZXZlbiBpZiBzb21ldGhpbmcgaXMgYSBzbGlnaHRseSBwb3NzaWJsaXR5IHRoZSBwcm9iYWJpbGl0eSBzaG91bGQgbm90IGJlIHplcm8uIEJ1dCBsYXBsYWNlIG1heSBhc3NpZ25lZCB0b28gbXVjaCBwcm9iYWJpbGl0eSB0byBhIHVuc2VlbiBldmVudC4gQWJvdmUsIHRoZSBwcm9iYWJpbGl0eSBkaWQgbm90IGNoYW5nZSBmcm9tIHRoZSBmb3JtZXIuICANCg0KDQpgYGB7cn0NCnByZWRpY3QobmJQYXksIHRlc3RbMSxdKQ0KYGBgDQoNCkl0IHdhcyB5ZXQgYWdhaW4gcHJlZGljdGVkIHRvIGJlICJObyIgdG8gZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIFRoZSBsYXBsYWNlIHNtb290aGluZyBkaWQgbm90IGNoYW5nZSB0aGUgb3V0Y29tZSBhbmQgdGhlIHByZWRpY3Rpb24gb2YgIk5vIiBzZWVtcyB0byBiZSBjb3JyZWN0LiANCg0KYGBge3J9DQpwcmVkaWN0KG5iUGF5LCB0ZXN0WzIsXSkNCmBgYA0KDQpGb3IgdGVzdCAyLCB0aGUgcHJlZGljdGlvbiB0byBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aCBpcyAiTm8iLiBUaGUgbGFwbGFjZSBzbW9vdGhpbmcgZGlkIG5vdCBjaGFuZ2UgdGhlIHByZWRpY3Rpb24gdGh1cyBJIG1ha2luZyBtZSBiZWxpZXZlIHRoYXQgdGhlIHByZWRpY3Rpb24gaXMgY29ycmVjdC4gDQoNCg0KIyNERUNJU0lPTiBUUkVFDQoNCmBgYHtyfQ0KbGlicmFyeSgicnBhcnQiKQ0KbGlicmFyeSgicnBhcnQucGxvdCIpDQpkdFBheSA8LSBycGFydChkZWZhdWx0LnBheW1lbnQubmV4dC5tb250aCB+IFBBWV8wICsgUEFZXzIgKyBQQVlfNiwgbWV0aG9kID0gImNsYXNzIiwgZGF0YSA9IHRyYWluLCBwYXJtcyA9IGxpc3Qoc3BsaXQgPSAnaW5mb3JtYXRpb24nKSwgbWluc3BsaXQgPSAyMCwgY3AgPSAwLjAyKQ0KYGBgDQoNCmBgYHtyfQ0KcnBhcnQucGxvdChkdFBheSwgdHlwZSA9IDQsIGV4dHJhID0gMSkNCj9ycGFydC5jb250cm9sDQoNCmBgYA0KDQpJbiB0aGlzIGRlY2lzaW9uIHRyZWUsIGl0IGV4YW1pbmVzIHRoZSBudW1iZXIgb2YgY291bnRzIHRoYXQgUGF5XzAgKFNlcHRlbWJlciAyMDA1KSB3YXMgbGVzcyB0aGFuIG9uZSBtb250aCBsYXRlLiBJZiB0aGUgYW5zd2VyIGlzICJZZXMiLCBwZW9wbGUgYXJlIGFzc2lnbmVkIHRvIHRoZSBsZWZ0IHNpZGUuIElmIHRoZSBhbnN3ZXIgaXMgIk5vIiwgcGVvcGxlIGFyZSBhc3NpZ25lZCB0byB0aGUgcmlnaHQgc2lkZS4gVGhlbiBpZiBQYXlfMCB3YXMgbGVzcyB0aGFuIHR3byBtb250aHMgbGF0ZSwgdGhlbiBwZW9wbGUgYXJlIGFzc2lnbmVkIHRvIHRoZSBsZWZ0IHNpZGUgYW5kIHBlb3BsZSB0aGF0IGFyZSBub3QgdHdvIG1vbnRocyBsYXRlIGFyZSBhc3NpZ25lZCB0byB0aGUgcmlnaHQuIEVhY2ggbm9kZSBjb250YWlucyB0d28gbnVtYmVycywgdGhlIHJpZ2h0IG51bWJlciBhZ3JlZXMgd2l0aCB0aGUgbm9kZSBzdGF0ZW1lbnQgYXQgdGhlIHRvcCAoIlllcyIgb3IgIk5vIikuIFRoZSBsZWZ0IG51bWJlciBkaXNhZ3JlZXMgd2l0aCB0aGUgbm9kZSBzdGF0ZW1lbnQgYXQgdGhlIHRvcC4gVGhlIG51bWJlcnMgc2VlbSByZWFzb25hYmxlIGV4Y2VwdCBJIGRvIHdvbmRlciBhYm91dCB0aGUgbGVmdCBib3R0b20gbGVmdC4gVGhvc2Ugd2hvIGhhdmUgUGF5XzAgbW9yZSB0aGFuIHR3byBtb250aHMsIHRoZSBtYWpvcml0eSBjb3VudCBpcyB0aGF0IHRoZXkgd2lsbCBub3QgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguICAgDQoNCg0KYGBge3J9DQpwcmVkaWN0KG5iUGF5LCB0ZXN0WzEsXSkNCmBgYA0KYGBge3J9DQpwcmVkaWN0KGR0UGF5LCB0ZXN0WzEsXSkNCmBgYA0KVGhlIHByZWRpY3Rpb24gaXMgbW9zdCBsaWtlbHkgIk5vIiB0aGF0IFRlc3QgMSB3aWxsIGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiBJIGJlbGlldmUgdGhhdCB0aGVzZSBwcmVkaWN0aW9ucyB3aWxsIGJlIGNvcnJlY3QgYW5kIFRlc3QgMSB3aWxsIG5vdCBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aCBCb3RoIHByZWRpY3Rpb25zIGJlbGlldmUgdGhhdCBUZXN0IDEgd2lsbCBub3QgZGVmYXVsdC4gICANCg0KDQpgYGB7cn0NCnByZWRpY3QobmJQYXksIHRlc3RbMixdKQ0KYGBgDQoNCmBgYHtyfQ0KcHJlZGljdChkdFBheSwgdGVzdFsyLF0pDQpgYGANCkZvciBUZXN0IDIsIHNpbWlsYXIgdG8gVGVzdCAxIGJvdGggcHJlZGljdGlvbnMgYmVsaWV2ZSB0aGF0IHRoZXkgd2lsbCBub3QgZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIEJhc2VkIG9uIHRoZSBwcmVkaWN0IGZ1bmN0aW9uIGFuZCB0aGUgaGlnaCBwcm9iYWJpbGl0eSBpdCBzdGF0ZXMgIk5vIi4gSSBiZWxpZXZlIHRoYXQgdGhlIHByZWRpY3Rpb24gaXMgY29ycmVjdCBhbmQgVGVzdCAyIHdpbGwgbm90IGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiANCg0KDQpgYGB7cn0NCmR0UGF5IDwtIHJwYXJ0KGRlZmF1bHQucGF5bWVudC5uZXh0Lm1vbnRoIH4gUEFZXzAgKyBQQVlfMiArIFBBWV82LCBtZXRob2QgPSAiY2xhc3MiLCBkYXRhID0gdHJhaW4sIHBhcm1zID0gbGlzdChzcGxpdCA9ICdpbmZvcm1hdGlvbicpLCBtaW5zcGxpdCA9IDIwLCBjcCA9IDAuMDAxKQ0KcnBhcnQucGxvdChkdFBheSwgdHlwZSA9IDEsIGV4dHJhID0xKQ0KYGBgDQoNCkluIHRoaXMgZGVjaXNpb24gdHJlZSwgcGVvcGxlIHdpdGggUGF5XzAgbGVzcyB0aGFuIG9uZSBtb250aCBsYXRlIGFyZSBhc3NpZ25lZCB0byB0aGUgbGVmdC4gVGhvc2UgbW9yZSB0aGFuIG9uZSBtb250aCBsYXRlIGFzc2lnbmVkIHRvIHRoZSByaWdodC4gSWYgUGF5XzAgaXMgbGVzcyB0aGFuIDIsIHRoZXkgYXNzaWduZWQgdG8gdGhlIGxlZnQgYW5kIHRob3NlIHdpdGggbW9yZSB0byB0aGUgcmlnaHQuIEJvdGggbm9kZXMgYXJlIGFza2VkIFBheV82IChBcHJpbCAyMDA1KSBpcyBsZXNzIHRoYW4gb25lLCBhZ3JlZWQgcGVvcGxlIGFyZSB0byB0aGUgbGVmdCBhbmQgZGlzYWdyZWUgaXMgdG8gdGhlIHJpZ2h0LiBQZW9wbGUgd2hvIGhhdmUgUGF5XzIgKEF1Z3VzdCAyMDA1KSBtb3JlIHRoYW4gNCBtb250aHMgYXJlIHRvIHRoZSBsZWZ0IGFuZCB0aG9zZSB3aG8gZGlzYWdyZWUgdG8gdGhlIHJpZ2h0LiBJIG5vdGljZWQgdGhhdCB0aGVyZSB3ZXJlIGEgZmV3IHBlb3BsZSB0aGF0IHRoZWlyIFBheV8yIGlzIG1vcmUgdGhhbiA0IG1vbnRocyB3aG8gYmVsaWV2ZSB0aGV5IHdpbGwgbm90IGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiBCdXQgb3RoZXIgdGhhbiB0aGF0LCBJIGJlbGlldmUgdGhhdCB0aGUgZGF0YSBpcyByZWFzb25hYmxlLiAgIA0KDQoNCmBgYHtyfQ0KcHJlZGljdChkdFBheSwgdGVzdFsxLF0pDQoNCmBgYA0KYGBge3J9DQpwcmVkaWN0KG5iUGF5LCB0ZXN0WzEsXSkNCg0KYGBgDQpJbiBib3RoIHByZWRpY3Rpb24sIFRlc3QgMSBoYXMgYmVlbiBkZWNpZGVkIHRvIGJlICJObyIgZm9yIGRlZmF1bHRpbmcgcGF5bWVudCBuZXh0IG1vbnRoLiBEdWUgdG8gdGhlIGhpZ2ggcHJvYmFiaWxpdHkgb2YgVGVzdCAxIGNob29zaW5nICJObyIsIEkgYmVsaWV2ZSB0aGF0IHRoZSBwcmVkaWN0aW9ucyBhcmUgY29ycmVjdC4gDQoNCg0KYGBge3J9DQpwcmVkaWN0KGR0UGF5LCB0ZXN0WzIsXSkNCmBgYA0KYGBge3J9DQpwcmVkaWN0KG5iUGF5LCB0ZXN0WzIsXSkNCg0KYGBgDQpJbiB0aGlzIHByZWRpY3Rpb24sIFRlc3QgMiBoYXMgYmVlbiBkZWNpZGVkICJObyIgZm9yIGRlZmF1bHRpbmcgcGF5bWVudCBuZXh0IG1vbnRoLiBTaW1pbGFybHkgdG8gVGVzdCAxLCBUZXN0IDIgaGFzIGhpZ2ggcHJvYmFiaWxpdHkgb2YgY2hvb3NpbmcgIk5vIiB0byBkZWZhdWx0IHBheW1lbnQgbmV4dCBtb250aC4gRnJvbSB0aGlzIGV2aWRlbmNlLCBJIGJlbGlldmUgdGhhdCB0aGUgbW9kZWwgaXMgY29ycmVjdCBhbmQgdGhlIHByZWRpY3Rpb24gd2lsbCBiZSB0cnVlLiANCg0KIyNDb25jbHVzaW9uIA0KDQpJIGJlbGlldmUgdGhhdCB0aGUgTmFpdmUgQmF5ZXMgbW9kZWwgaXMgZ29vZCBidXQgbm90IHZpc3VhbGx5IGVhc3kgdG8gZXhhbWluZSB0aGUgZGF0YS4gVGhlIE5haXZlIEJheWVzIG1vZGVsIEkgYmVsaWV2ZSBpcyBub3QgYXMgaW5kZXB0aCBhcyB0aGUgRGVjaXNpb24gVHJlZS4gVGhlIGRlY2lzaW9uIHRyZWUgaWRlbnRpZmllcyB0aGUgZGF0YSBhbmQgdGhlIGNvdW50cyBhcmUgYXNzaWduZWQgdG8gYSBub2RlIGJhc2VkIG9uIHRoZSBkYXRhLiBUaGUgZGVjaXNpb24gdHJlZSBzZXBhcmF0ZXMgdGhlIGRhdGEgYnkgdGhlIHRocmVlIHBheW1lbnQgdmFyaWFibGVzLiBJdCBpcyBtb3JlIHZpc3VhbGx5IGFwcGVhbGluZyB0byBleGFtaW5lIHRoZSB0aHJlZSB2YXJpYWJsZXMgd2l0aGluIGVhY2ggbm9kZS4gQm90aCBtb2RlbHMgcHJlZGljdGVkIHRoZSBzYW1lIHJlc3VsdHMgYXMgZGVjaWRlZCB0aGF0IFRlc3QgMSBhbmQgVGVzdCAyIHdvdWxkIHN0YXRlICJObyIgdG8gZGVmYXVsdCBwYXltZW50IG5leHQgbW9udGguIEkgZG8gcXVlc3Rpb24gd2h5IHRoZSBkZWNpc2lvbiB0cmVlJ3MgZGF0YSBkb2VzIG5vdCB1c2UgcHJvYmFiaWxpdHkgYW5kIGluc3RlYWQgaXQgdXNlcyBjb3VudHMuIA0KDQpQZXJoYXBzIHZhcmlhYmxlcyB0aGF0IHNob3VsZCBiZSBleGFtaW5lZCBpbiB0aGUgY2xhc3NpZmljYXRpb24gbW9kZWwgaXMgdGhlIGJpbGwgYW1vdW50IGFuZCB0aGUgcGF5IGFtb3VudC4gSXQgd291bGQgaGVscCB0byBpZGVudGlmeSBob3cgbXVjaCBzb21lb25lcycgYmlsbHMgaXMgYW5kIGhvdyBlYWNoIHBlcnNvbiBwYWlkIHRvIGV4YW1pbmUgdGhlIGRpZmZlcmVuY2UuIFBlcmhhcHMgYW5vdGhlciBkZWNpc2lvbiB0cmVlIG9yIE5haXZlIEJheWVzIG1vZGVsIGNhbiBiZSB1c2VkIHRvIGV4YW1pbmUgdGhlc2UgdmFyaWFibGVzIHdpdGggdGhlIGRlZmF1bHQgcGF5bWVudCBuZXh0IG1vbnRoLiAgDQoNCg0KDQoNCg0KDQoNCg0K