Residual plot là gì
Sử dụng để dự báo 1 biến phụ thuộc (dependent variable, response variable) dựa vào 1 hay nhiều biến độc lập (independent variables, predictor variables, explanatory variables) Ví dụ 1: Phân tích khi tăng 1 nhân viên thì lợi nhuận ngân hàng tăng hay giảm bao nhiêu tiền. Biến phụ thuộc là lợi nhuận ngân hàng, biến độc lập là số lượng nhân viên (simple linear) Ví dụ 2: Tính toán xem khi tăng 1 cây ATM thì lợi nhuận ngân hàng tăng hay giảm bao nhiêu phần trăm. Biến phụ thuôc là log(lợi nhuận), biến độc lập có thể là số lượng máy ATM, số lượng máy ATM bình phương (Polynomial) Ví dụ 3: Dự báo khả năng phát sinh nợ xấu của khách hàng. Biến phụ thuộc là khả năng phát sinh nợ xấu, biến độc lập ví dụ: tuổi, giới tính, trình độ học vấn (Multiple linear) Ví dụ 4: Dự báo giá cổ phiếu của ngân hàng tại các thời điểm trong tương lai. Biến phụ thuộc là giá cổ phiếu, biến độc lập có thể có là trễ của biến giá, hoặc 1 số yếu tố như GPD, lạm phát (Time-series) Có rất nhiều loại hồi quy như: Simple linear, Polynomial, Multiple linear, Multilevel, Multivariate, Logistic, Poisson, Cox proportional hazards, Time-series, Nonlinear, Nonparametric Trong đó, 4 loại phổ biến hay được sử dụng là type_model <- data.frame(Type = c("Simple linear",
"Multiple linear",
"Logistic",
"Time-series"),
`Typical use` = c("Predicting a quantitative response variable from a quantitative explanatory variable",
"Predicting a quantitative response variable from two or more explanatory variables",
"Predicting a categorical response variable from one or more explanatory variables",
"Modeling time-series data with correlated errors"))
type_model %>% datatable() data.frame(Function = c("summary()", "coefficients()", "confint()", "fitted()", "residuals()", "anova()",
"vcov()", "AIC()", "plot()", "predict()"),
Action =
c("Displays detailed results for the fitted model", "Lists the model parameters (intercept and slopes) for the fitted model", "Provides confidence intervals for the model parameters (95% by default)",
"Lists the predicted values in a fitted model", "Lists the residual values in a fitted model", "Generates an ANOVA table for a fitted model, or an ANOVA table comparing two or more fitted models", "Lists the covariance matrix for model parameters", "Prints Akaikes Information Criterion", "Generates diagnostic plots for evaluating the fit of a model", "Uses a fitted model to predict response values for a new dataset")) %>% datatable() Là mô hình hồi quy với 1 biến phụ thuộc, 1 biến độc lập. Hàm hồi quy có dạng Y = a + bX Y là biến phụ thuộc, X là biến độc lập, a là hệ số chặn (intercept), b là hệ số góc (coefficient) Ví dụ: Với bộ dữ liệu women, có 2 biến là chiều cao, cân nặng của phụ nữ. Muốn dự báo cân nặng của phụ nữ dựa vào chiều cao của họ ta xây dựng mô hình hồi quy đơn ## height weight ## 1 58 115 ## 2 59 117 ## 3 60 120 ## 4 61 123 ## 5 62 126 ## 6 63 129women %>%
ggplot(aes(x = height, y = weight))+
geom_point()+
labs(x = "height (in inches)",
y = "weight (in pounds)") fit <- lm(weight ~ height, data=women) Sử dụng phương pháp bình phương nhỏ nhất OLS (Ordinary least squares) ## ## Call: ## lm(formula = weight ~ height, data = women) ## ## Residuals: ## Min 1Q Median 3Q Max ## -1.7333 -1.1333 -0.3833 0.7417 3.1167 ## ## Coefficients: ## Estimate Std. Error t value Pr(>|t|) ## (Intercept) -87.51667 5.93694 -14.74 1.71e-09 *** ## height 3.45000 0.09114 37.85 1.09e-14 *** ## --- ## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 ## ## Residual standard error: 1.525 on 13 degrees of freedom ## Multiple R-squared: 0.991, Adjusted R-squared: 0.9903 ## F-statistic: 1433 on 1 and 13 DF, p-value: 1.091e-14Như vậy phương trình hồi quy có dạng \[ \hat{weight} = -87.51 + 3.45 * height \] Dự báo (fitted) ## 1 2 3 4 5 6 7 8 ## 112.5833 116.0333 119.4833 122.9333 126.3833 129.8333 133.2833 136.7333 ## 9 10 11 12 13 14 15 ## 140.1833 143.6333 147.0833 150.5333 153.9833 157.4333 160.8833women$weight_pre <- fitted(fit) Phần dư (sai lệch) ## 1 2 3 4 5 6 ## 2.41666667 0.96666667 0.51666667 0.06666667 -0.38333333 -0.83333333 ## 7 8 9 10 11 12 ## -1.28333333 -1.73333333 -1.18333333 -1.63333333 -1.08333333 -0.53333333 ## 13 14 15 ## 0.01666667 1.56666667 3.11666667women$res <- residuals(fit) women %>%
ggplot()+
geom_point(aes(x = height, y = weight), color = "blue")+
geom_point(aes(x = height, y = weight_pre), color = "red")+
labs(x = "height (in inches)",
y = "weight (in pounds)") Mô hình hồi quy dạng: \[\hat{Y} = \beta_{0} + \beta_{1}X_{1} + \beta_{2}X_{2} + \beta_{3}X_{3} + ...\] Ví dụ lấy bộ số liệu giết người ở các bang của Mỹ state.x77 states <- as.data.frame(state.x77[,c("Murder", "Population", "Illiteracy", "Income", "Frost")])
states %>% head() ## Murder Population Illiteracy Income Frost
## Alabama 15.1 3615 2.1 3624 20
## Alaska 11.3 365 1.5 6315 152
## Arizona 7.8 2212 1.8 4530 15
## Arkansas 10.1 2110 1.9 3378 65
## California 10.3 21198 1.1 5114 20
## Colorado 6.8 2541 0.7 4884 166chart.Correlation(states, histogram=TRUE, pch="+") fit <- lm(Murder ~ Population + Illiteracy + Income + Frost, data = states)
summary(fit) ##
## Call:
## lm(formula = Murder ~ Population + Illiteracy + Income + Frost,
## data = states)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.7960 -1.6495 -0.0811 1.4815 7.6210
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.235e+00 3.866e+00 0.319 0.7510
## Population 2.237e-04 9.052e-05 2.471 0.0173 *
## Illiteracy 4.143e+00 8.744e-01 4.738 2.19e-05 ***
## Income 6.442e-05 6.837e-04 0.094 0.9253
## Frost 5.813e-04 1.005e-02 0.058 0.9541
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.535 on 45 degrees of freedom
## Multiple R-squared: 0.567, Adjusted R-squared: 0.5285
## F-statistic: 14.73 on 4 and 45 DF, p-value: 9.133e-08states$pre <- fitted(fit)
states$res <- residuals(fit) Giá trị p-value Income và Frost > 0.05. Vì vậy, với mức ý nghĩa 0.05 có thể kết luận hệ số của 2 biến này bằng 0
Thay vì việc nhìn vào pvalue ở mô hình hồi quy, khoảng tin cậy của hệ số hồi quy cho phép đánh giá xem hệ số hồi quy có khác 0 hay không. Khoảng tin cậy của Hệ số của Intercept, Income, Frost có cận dưới < 0, trong khi cận trên > 0 > nhìn vào đây có thể biết được 3 hệ số này = 0 với mức ý nghĩa 0.05% par(mfrow=c(2,2))
plot(fit)
res <- residuals(fit)
t.test(res, mu = 0) ##
## One Sample t-test
##
## data: res
## t = 6.5292e-16, df = 49, p-value = 1
## alternative hypothesis: true mean is not equal to 0
## 95 percent confidence interval:
## -0.6903919 0.6903919
## sample estimates:
## mean of x
## 2.243128e-16p-value = 1: mô hình thỏa mãn giả thiết 2 H0: phương sai sai số không đổi Ha: Phương sai sai số thay đổi ## Non-constant Variance Score Test ## Variance formula: ~ fitted.values ## Chisquare = 1.746514, Df = 1, p = 0.18632p-value = 0.18, có thể kết luận phương sai sai số không đổi với mức ý nghĩa < 0.18 ## Population Illiteracy Income Frost
## 1.245282 2.165848 1.345822 2.082547 vif < 10 cho thấy các biến độc lập không có đa cộng tuyến Sau khi kiểm định các giả thiết của mô hình OLS, thử nghiệm trường hợp bỏ 2 biến Income, Frost ra khỏi mô hình fit <- lm(Murder ~ Population + Illiteracy, data = states)
summary(fit) ##
## Call:
## lm(formula = Murder ~ Population + Illiteracy, data = states)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.7652 -1.6561 -0.0898 1.4570 7.6758
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.652e+00 8.101e-01 2.039 0.04713 *
## Population 2.242e-04 7.984e-05 2.808 0.00724 **
## Illiteracy 4.081e+00 5.848e-01 6.978 8.83e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.481 on 47 degrees of freedom
## Multiple R-squared: 0.5668, Adjusted R-squared: 0.5484
## F-statistic: 30.75 on 2 and 47 DF, p-value: 2.893e-09par(mfrow=c(2,2))
plot(fit) LS0tDQp0aXRsZTogIlBow6JuIHTDrWNoIGjhu5NpIHF1eSB2w6AgdMawxqFuZyBxdWFuIg0KYXV0aG9yOiAiTmd1eeG7hW4gTmfhu41jIELDrG5oIg0KZGF0ZTogIk9jdG9iZXIgMTYsIDIwMTgiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIHRoZW1lOiAiZGVmYXVsdCINCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogbm8NCiAgICAgIHNtb290aF9zY3JvbGw6IG5vDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICBmaWdfd2lkdGg6IDkgDQogIGZpZ19oZWlnaHQ6IDYgDQogIGZpZy5jYXAgOiAiU291cmNlOiBCSSAtIFNlQWJhbmsgIg0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h2bmskc2V0KGVjaG8gPSBUUlVFKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkocHN5Y2gpDQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KbGlicmFyeShjYXIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KGdncmVwZWwpDQoNCg0KdGhlbWVfc2V0KHRoZW1lX2xpZ2h0KCkpDQpgYGANCg0KDQojIFBow6JuIHTDrWNoIHTGsMahbmcgcXVhbg0KDQojIyBWw60gZOG7pToNCg0KYGBge3IsIGVjaG89RkFMU0V9DQpyIDwtIGRhdGEuZnJhbWUoeTAgPSBybm9ybSgxMDAsIG1lYW4gPSAyLCBzZCA9IDEpKSAlPiUgDQogIG11dGF0ZShgTGluZWFyIGNvcnJlbGF0aW9uYCA9IC0geTAgKiAxMCArIHJub3JtKDEwMCksDQogICAgICAgICBgTm9ubGluZWFyIGNvcnJlbGF0aW9uYCA9IHkwXjIgKyBybm9ybSgxMDApLA0KICAgICAgICAgYE5vIGNvcnJlbGF0aW9uYCA9IHJub3JtKDEwMCkpIA0KDQpyICU+JSBnYXRoZXIoa2V5ID0gImtleSIsIHZhbHVlID0geCwgLXkwKSAlPiUgDQogIG11dGF0ZShrZXkgPSBmYWN0b3Ioa2V5LCANCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJMaW5lYXIgY29ycmVsYXRpb24iLCAiTm9ubGluZWFyIGNvcnJlbGF0aW9uIiwgIk5vIGNvcnJlbGF0aW9uIiksDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiTGluZWFyIGNvcnJlbGF0aW9uIiwgIk5vbmxpbmVhciBjb3JyZWxhdGlvbiIsICJObyBjb3JyZWxhdGlvbiIpKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB4LCB5ID0geTAsIGZpbGwgPSBrZXksIGNvbG9yID0ga2V5KSkrDQogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSkrDQogIGZhY2V0X3dyYXAofmtleSwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlX3giKSArDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gZ3JhZGllbnQiLA0KICAgICAgIHggPSBOVUxMLA0KICAgICAgIHkgPSBOVUxMLA0KICAgICAgIGNhcHRpb24gPSAiQXV0aG9yOiBOTkIiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygic2xhdGVibHVlNCIsICJzbGF0ZWJsdWUyIiwgInNsYXRlYmx1ZSIpKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoInNsYXRlYmx1ZTQiLCAic2xhdGVibHVlMiIsICJzbGF0ZWJsdWUiKSkrDQogIHRoZW1lX2xpZ2h0KCkrDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiksDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAic2xhdGVibHVlNCIpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAic2xhdGVibHVlNCIpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbD0ic2xhdGVibHVlIiksDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gJ3NsYXRlYmx1ZTQnLCBzaXplID0gMTIpKSANCg0KYGBgDQoNCiMjIEjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gdHV54bq/biB0w61uaCAoQ29ycmVsYXRpb24gY29lZmZpY2llbnQpDQoNCkjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gxJFvIGzGsOG7nW5nIG3hu6ljIMSR4buZIHF1YW4gaOG7hyB0dXnhur9uIHTDrW5oIGdp4buvYSBoYWkgYmnhur9uLCBraMO0bmcgcGjDom4gYmnhu4d0IGJp4bq/biBuw6B5IHBo4bulIHRodeG7mWMgdsOgbyBiaeG6v24ga2lhDQoNCiMjIMOQ4bq3YyB0w61uaCBj4bunYSBo4buHIHPhu5EgdMawxqFuZyBxdWFuDQoNCiAgLSBI4buHIHPhu5EgdMawxqFuZyBxdWFuIGtow7RuZyBjw7MgxJHGoW4gduG7iw0KICAtIEjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gKHIpIG7hurFtIHRyb25nIGtob+G6o25nIFstMSwxXQ0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmNvcl9zdHJlIDwtIGRhdGEuZnJhbWUoY29lZiA9IHNlcSgtMSwgMSwgYnkgPSAwLjEpKSANCg0KY29yX3N0cmUgPC0gY29yX3N0cmUgJT4lIA0KICBtdXRhdGUoc3RyZSA9IGNhc2Vfd2hlbihhYnMoY29lZikgPT0xIH4gIlBlcmZlY3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMoY29lZikgPj0gMC42NSB+ICJTdHJvbmciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhYnMoY29lZikgPj0gMC40NSB+ICJNb2RlcmF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFicyhjb2VmKSA+PSAwLjE1IH4gIldlYWsiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gIk5vbmUiKSwNCiAgICAgICAgIHN0cmUgPSBmYWN0b3Ioc3RyZSwgDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk5vbmUiLCAiV2VhayIsICJNb2RlcmF0ZSIsICJTdHJvbmciLCAiUGVyZmVjdCIpLA0KICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJOb25lIiwgIldlYWsiLCAiTW9kZXJhdGUiLCAiU3Ryb25nIiwgIlBlcmZlY3QiKSksDQogICAgICAgICBhYnNfY29lZiA9IGFicyhjb2VmKSkgJT4lIA0KICBncm91cF9ieShzdHJlKSAlPiUgDQogIG11dGF0ZSh5bWF4ID0gY2FzZV93aGVuKHN0cmUgJWluJSAiUGVyZmVjdCIgfiBJbmYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmUgJWluJSAiU3Ryb25nIiB+IDAuOTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmUgJWluJSAiTW9kZXJhdGUiIH4gMC42NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyZSAlaW4lICJXZWFrIiB+IDAuNDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAwLjE1KSwNCiAgICAgICAgIHltaW4gPSBjYXNlX3doZW4oc3RyZSAlaW4lICJQZXJmZWN0IiB+IDAuOTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmUgJWluJSAiU3Ryb25nIiB+IDAuNjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmUgJWluJSAiTW9kZXJhdGUiIH4gMC40NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyZSAlaW4lICJXZWFrIiB+IDAuMTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAtSW5mKSkNCg0KY29yX3N0cmUgJT4lIGdncGxvdChhZXMoeCA9IGNvZWYsIHkgPSBhYnNfY29lZikpKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3JlY3QoYWVzKHhtYXggPSBJbmYsIHhtaW4gPSAtSW5mLCB5bWF4ID0geW1heCwgeW1pbiA9IHltaW4sIGZpbGwgPSBzdHJlKSwgYWxwaGEgPSAwLjMpKw0KICBnZW9tX2xhYmVsKGFlcyhsYWJlbCA9IGNvZWYsIGNvbG9yID0gc3RyZSkpKw0KICBsYWJzKHRpdGxlID0gIlN0cmVuZ3RoIG9mIGNvcnJlbGF0aW9uIiwNCiAgICAgICB4ID0gTlVMTCwNCiAgICAgICB5ID0gTlVMTCwNCiAgICAgICBjYXB0aW9uID0gIkF1dGhvcjogTk5CIikgKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJkb2RnZXJibHVlNCIpKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEuNSwgMSkpKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikgKw0KICBhbm5vdGF0ZSgidGV4dCIsIHggPSAtMS4yLCB5ID0gYygwLjA1LCAwLjMsIDAuNTUsIDAuOCwgMSksIGxhYmVsID0gYygiTm9uZSIsICJXZWFrIiwgIk1vZGVyYXRlIiwgIlN0cm9uZyIsICJQZXJmZWN0IikpDQpgYGANCg0KICAtIHIgPiAwOiB0xrDGoW5nIHF1YW4gZMawxqFuZw0KICAtIHIgPCAwOiB0xrDGoW5nIHF1YW4gw6JtDQogIC0gciA9IDA6IGtow7RuZyB0xrDGoW5nIHF1YW4NCg0KYGBge3IsIGVjaG89RkFMU0V9DQpyIDwtIGRhdGEuZnJhbWUoeTAgPSBybm9ybSgxMDAsIG1lYW4gPSA1LCBzZCA9IDEpKSAlPiUgDQogIG11dGF0ZShgUG9zaXRpdmUgY29ycmVsYXRpb25gID0geTAgKiAxMCArIHJub3JtKDEwMCksDQogICAgICAgICBgTmVnYXRpdmUgY29ycmVsYXRpb25gID0geTAgKiAoLTUpICsgcm5vcm0oMTAwLCAyKSwNCiAgICAgICAgIGBObyBjb3JyZWxhdGlvbmAgPSBybm9ybSgxMDApKSANCg0KciAlPiUgZ2F0aGVyKGtleSA9ICJrZXkiLCB2YWx1ZSA9IHgsIC15MCkgJT4lIA0KICBtdXRhdGUoa2V5ID0gZmFjdG9yKGtleSwgDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiUG9zaXRpdmUgY29ycmVsYXRpb24iLCAiTmVnYXRpdmUgY29ycmVsYXRpb24iLCAiTm8gY29ycmVsYXRpb24iKSwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJQb3NpdGl2ZSBjb3JyZWxhdGlvbiIsICJOZWdhdGl2ZSBjb3JyZWxhdGlvbiIsICJObyBjb3JyZWxhdGlvbiIpKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB4LCB5ID0geTAsIGZpbGwgPSBrZXksIGNvbG9yID0ga2V5KSkrDQogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSkrDQogIGZhY2V0X3dyYXAofmtleSwgbmNvbCA9IDMsIHNjYWxlcyA9ICJmcmVlX3giKSArDQogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gZ3JhZGllbnQiLA0KICAgICAgIHggPSBOVUxMLA0KICAgICAgIHkgPSBOVUxMLA0KICAgICAgIGNhcHRpb24gPSAiQXV0aG9yOiBOTkIiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZG9kZ2VyYmx1ZTQiLCAiZG9kZ2VyYmx1ZTIiLCAiZG9kZ2VyYmx1ZSIpKSsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImRvZGdlcmJsdWU0IiwgImRvZGdlcmJsdWUyIiwgImRvZGdlcmJsdWUiKSkrDQogIHRoZW1lX2xpZ2h0KCkrDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiksDQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiZG9kZ2VyYmx1ZTQiKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImRvZGdlcmJsdWU0IiksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJkb2RnZXJibHVlIiksDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gJ3doaXRlJywgc2l6ZSA9IDEyKSkgDQoNCmBgYA0KDQojIyBDw6FjIHBoxrDGoW5nIHBow6FwIHTDrW5oIHTGsMahbmcgcXVhbg0KDQogICMjIyBQZWFyc29uJ3Mgcg0KICAtIMSQw6FuaCBnacOhIG3hu6ljIMSR4buZIHTGsMahbmcgcXVhbiB0dXnhur9uIHTDrW5oIGPhu6dhIDIgYmnhur9uIMSR4buLbmggbMaw4bujbmcNCiAgDQogIFxbIHJfe3h5fSA9IFxmcmFje1xzdW1fe2k9MX1ee259KHhfaSAtIFxiYXJ7eH0pKHlfaSAtIFxiYXJ7eX0pfXtcc3FydFtde1xzdW1fe2k9MX1ee259KHhfaSAtIFxiYXJ7eH0pXjIgXHN1bV97aT0xfV57bn0oeV9pIC0gXGJhcnt5fSleMn19IFxdDQogIA0KICAtIFbDrSBk4bulOiBT4butIGThu6VuZyBz4buRIGxp4buHdSBkw6JuIHPhu5EgdsOgIHRodSBuaOG6rXAgY+G7p2EgNTAgYmFuZyBj4bunYSBN4bu5DQpgYGB7cn0NCnN0YXRlcyA8LSBzdGF0ZS54NzdbLGMoMToyKV0gDQpoZWFkKHN0YXRlcykNCg0KYGBgDQoNCiAgLSBDw7RuZyB0aOG7qWMgdMOtbmggaOG7hyBz4buRIHTGsMahbmcgcXVhbiBQZWFyc29uIHRyw6puIFI6IGNvcihkZiwgbWV0aG9kID0gInBlYXJzb24iKQ0KDQpgYGB7cn0NCk0gPC0gY29yKHN0YXRlcykNCk0NCmBgYA0KICAgIA0KIyMjIFTGsMahbmcgcXVhbiBo4bqhbmcgKHNwZWFybWFuKQ0KICAtIMSQw6FuaCBnacOhIG3hu6ljIMSR4buZIHTGsMahbmcgcXVhbiBj4bunYSAyIGjhuqFuZyBj4bunYSAyIGJp4bq/biAocmFuay1vcmRlcmVkIHZhcmlhYmxlcyksIHPhu60gZOG7pW5nICBraGkgcGjDom4gcGjhu5FpIGPhu6dhIHThu5VuZyB0aOG7gyDEkcaw4bujYyBnaeG6oyBz4butIGtow7RuZyBwaOG6o2kgbMOgIHBow6JuIHBo4buRaSBjaHXhuqluIGhv4bq3YyB0cm9uZyB0csaw4budbmcgaOG7o3AgY8OzIGPDoWMgZ2nDoSB0cuG7iyBxdWFuIHPDoXQgYuG6pXQgdGjGsOG7nW5nIChs4bubbiBxdcOhIGhv4bq3YyBuaOG7jyBxdcOhKSANCiAgDQogIFxbIDEtXGZyYWN7NlxzdW1faV5uIGRfe2l9XjJ9e24obl4yLTEpfVxdDQogIA0KICBkaTogaGnhu4d1IGjhuqFuZyBj4bunYSAyIGJp4bq/bg0KICANCiAgXFsgZF97aX0gPSByZ1hfe2l9IC0gcmdZX3tpfVxdIA0KICANCiAgLSBDw7RuZyB0aOG7qWMgdMOtbmggdHLDqm4gUjogY29yKGRmLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KICANCiAgLSBNaW5oIGjhu41hIGLhurFuZyBi4bqjbmcgdMOtbmg6DQogIA0KICANCmBgYHtyfQ0Kc3RhdGVzIDwtIHN0YXRlLng3N1ssYygxOjIpXSANCmhlYWQoc3RhdGVzKQ0KbiA8LSBkaW0oc3RhdGVzKVsxXQ0KDQpzdGF0ZXMgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICBtdXRhdGUocmdYID0gcmFuayhQb3B1bGF0aW9uLCB0aWVzLm1ldGhvZD0gImZpcnN0IiksDQogICAgICAgICByZ1kgPSByYW5rKEluY29tZSwgdGllcy5tZXRob2Q9ICJmaXJzdCIpLA0KICAgICAgICAgZCA9IHJnWCAtIHJnWSwNCiAgICAgICAgIGQyID0gZF4yKSAlPiUgDQogIG11dGF0ZShTcGVhcm1hbl9jb3IgPSAxIC0gNiAqIHN1bShkMikvKG4gKiAobl4yIC0xKSkpICU+JSANCiAgZGF0YXRhYmxlKCkNCg0KTSA8LSBjb3Ioc3RhdGVzWyxjKCJQb3B1bGF0aW9uIiwgIkluY29tZSIpXSwgbWV0aG9kID0gInNwZWFybWFuIikNCk0NCg0KYGBgDQogICANCiMjIyBUxrDGoW5nIHF1YW4gaOG6oW5nIChrZW5kYWxsKQ0KICAtIMSQw6FuaCBnacOhIG3hu6ljIMSR4buZIHTGsMahbmcgcXVhbiBj4bunYSAyIGjhuqFuZyBj4bunYSAyIGJp4bq/biAocmFuay1vcmRlcmVkIHZhcmlhYmxlcyksIGjhu4cgc+G7kSBuw6B5IMSRxrDhu6NjIHPhu60gZOG7pW5nIHTGsMahbmcgdOG7sSBuaMawIHNwZWFybWFuLCB0aMO0bmcgdGjGsOG7nW5nIGjhu4cgc+G7kSBuw6B5IG5o4buPIGjGoW4gc3BlYXJtYW4gDQoNCiAgLSBI4buHIHPhu5Ega2VuZGFsbCDDrXQgZMO5bmcgaMahbiBzbyB24bubaSAyIGjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gdHLDqm4NCg0KICAtIEPDtG5nIHRo4bupYyB0w61uaCB0csOqbiBSOiBjb3IoZGYsIG1ldGhvZCA9ICJrZW5kYWxsIikgIA0KICANCmBgYHtyfQ0KTSA8LSBjb3Ioc3RhdGVzLCBtZXRob2QgPSAia2VuZGFsbCIpDQpNDQpgYGANCiAgDQojIyBLaeG7g20gxJHhu4tuaCB4ZW0gMiBiaeG6v24gY8OzIHTGsMahbmcgcXVhbiB24bubaSBuaGF1IGtow7RuZw0KDQogICogIEPFqW5nIG5oxrAgcGjGsMahbmcgcGjDoXAgdMOtbmgsIGtp4buDbSDEkeG7i25oIGPFqW5nIGPDsyAzIG1ldGhvZDogUGVhcnNvbiwgU3BlYXJtYW4sIEtlbmRhbGwNCiAgDQogICogR2nhuqMgdGhp4bq/dCBraeG7g20gxJHhu4tuaDoNCiAgDQogICAgIC0gSDA6IEtow7RuZyBjw7MgdMawxqFuZyBxdWFuICho4buHIHPhu5EgdMawxqFuZyBxdWFuID0gMCkNCiAgICAgLSBIYTogQ8OzIHTGsMahbmcgcXVhbg0KDQogICogVsOtIGThu6U6IFPhu60gZOG7pW5nIGjDoG0gY29yLnRlc3QgY+G7p2EgZ8OzaSBzdGF0cw0KICANCmBgYHtyfQ0Kc3RhdGVzIDwtIHN0YXRlLng3Nw0Kc3RhdGVzWyxjKDMsNSldICU+JSBjb3IoKQ0KDQpjb3IudGVzdChzdGF0ZXNbLDNdLCBzdGF0ZXNbLDVdKQ0KYGBgDQoNCkjDoG0gbsOgeSBjaOG7iSBkw7luZyDEkcaw4bujYyB24bubaSAyIGJp4bq/bi4gVHJvbmcgdHLGsOG7nW5nIGjhu6NwIG114buRbiB0aOG7sWMgaGnhu4duIHbhu5tpIG5oaeG7gXUgYmnhur9uIGPDsyB0aOG7gyBz4butIGThu6VuZyBow6BtIGNvcnIudGVzdCBj4bunYSBwYWNrYWdlIHBzeWNoDQoNCiAgKiBWw60gZOG7pSBz4butIGThu6VuZyBow6BtIGNvcnIudGVzdA0KDQpgYGB7cn0NCmNvcnIudGVzdChzdGF0ZXNbLDE6NV0sIHVzZSA9ICJjb21wbGV0ZSIsIG1ldGhvZCA9ICJwZWFyc29uIiApDQpgYGANCg0KSMOgbSBuw6B5IGNobyByYSBr4bq/dCBxdeG6oyBj4bunYSBj4bqjIGjhu4cgc+G7kSB0xrDGoW5nIHF1YW4gdsOgIHjDoWMgc3XhuqV0IGtp4buDbSDEkeG7i25oDQoNCljDoWMgc3XhuqV0ID4gbeG7qWMgw70gbmdoxKlhIGFscGhhICg9IDAuMDUpIGPDsyB0aOG7gyBr4bq/dCBsdeG6rW4gaOG7hyBz4buRIHTGsMahbmcgcXVhbiA9IDAgduG7m2kgbeG7qWMgw70gbmdoxKlhIGFscGhhDQoNCiMjIE3hu5l0IHPhu5EgxJHhu5MgdGjhu4sgdHJvbmcgcGjDom4gdMOtY2ggdMawxqFuZyBxdWFuDQoNCiAgLSBjb3JycGxvdCAocGFja2FnZTogY29ycnBsb3QpDQogIA0KYGBge3J9DQpzdGF0ZXMgPC0gc3RhdGUueDc3DQpNIDwtIGNvcihzdGF0ZXMpDQpjb3JycGxvdChNLCBtZXRob2QgPSAiY2lyY2xlIikNCmBgYA0KDQogIC0gY29ycnBsb3QubWl4ZWQgKHBhY2thZ2U6IGNvcnJwbG90KQ0KICANCmBgYHtyfQ0KY29ycnBsb3QubWl4ZWQoTSkNCmBgYA0KDQogIC0gY2hhcnQuQ29ycmVsYXRpb24gKHBhY2thZ2U6IFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KICANCmBgYHtyfQ0KZGF0YShtYW5hZ2VycykNCmNoYXJ0LkNvcnJlbGF0aW9uKG1hbmFnZXJzWywxOjhdLCBoaXN0b2dyYW09VFJVRSwgcGNoPSIrIikNCmBgYA0KDQpIw6BtIG7DoHkgdMawxqFuZyBuaMawOiBwc3ljaDo6cGFpcnMucGFuZWxzLCBHR2FsbHk6OmdncGFpcnMsIGNvcnJyOjpjb3JyZWxhdGUNCg0KIyBQaMOibiB0w61jaCBo4buTaSBxdXkgKHJlZ3Jlc3Npb24gYW5hbHlzaXMpDQoNClPhu60gZOG7pW5nIMSR4buDIGThu7EgYsOhbyAxIGJp4bq/biBwaOG7pSB0aHXhu5ljIChkZXBlbmRlbnQgdmFyaWFibGUsIHJlc3BvbnNlIHZhcmlhYmxlKSBk4buxYSB2w6BvIDEgaGF5IG5oaeG7gXUgYmnhur9uIMSR4buZYyBs4bqtcCAoaW5kZXBlbmRlbnQgdmFyaWFibGVzLCBwcmVkaWN0b3IgdmFyaWFibGVzLCBleHBsYW5hdG9yeSB2YXJpYWJsZXMpDQoNClbDrSBk4bulIDE6IFBow6JuIHTDrWNoIGtoaSB0xINuZyAxIG5ow6JuIHZpw6puIHRow6wgbOG7o2kgbmh24bqtbiBuZ8OibiBow6BuZyB0xINuZyBoYXkgZ2nhuqNtIGJhbyBuaGnDqnUgdGnhu4FuLiBCaeG6v24gcGjhu6UgdGh24buZYyBsw6AgbOG7o2kgbmh24bqtbiBuZ8OibiBow6BuZywgYmnhur9uIMSR4buZYyBs4bqtcCBsw6Agc+G7kSBsxrDhu6NuZyBuaMOibiB2acOqbiAoc2ltcGxlIGxpbmVhcikNCg0KVsOtIGThu6UgMjogVMOtbmggdG/DoW4geGVtIGtoaSB0xINuZyAxIGPDonkgQVRNIHRow6wgbOG7o2kgbmh24bqtbiBuZ8OibiBow6BuZyB0xINuZyBoYXkgZ2nhuqNtIGJhbyBuaGnDqnUgcGjhuqduIHRyxINtLiBCaeG6v24gcGjhu6UgdGh2w7RjIGzDoCBsb2cobOG7o2kgbmh24bqtbiksIGJp4bq/biDEkeG7mWMgbOG6rXAgY8OzIHRo4buDIGzDoCBz4buRIGzGsOG7o25nIG3DoXkgQVRNLCBz4buRIGzGsOG7o25nIG3DoXkgQVRNIGLDrG5oIHBoxrDGoW5nIChQb2x5bm9taWFsKQ0KDQpWw60gZOG7pSAzOiBE4buxIGLDoW8ga2jhuqMgbsSDbmcgcGjDoXQgc2luaCBu4bujIHjhuqV1IGPhu6dhIGtow6FjaCBow6BuZy4gQmnhur9uIHBo4bulIHRodeG7mWMgbMOgIGto4bqjIG7Eg25nIHBow6F0IHNpbmggbuG7oyB44bqldSwgYmnhur9uIMSR4buZYyBs4bqtcCB2w60gZOG7pTogdHXhu5VpLCBnaeG7m2kgdMOtbmgsIHRyw6xuaCDEkeG7mSBo4buNYyB24bqlbiAuLi4gKE11bHRpcGxlIGxpbmVhcikNCg0KVsOtIGThu6UgNDogROG7sSBiw6FvIGdpw6EgY+G7lSBwaGnhur91IGPhu6dhIG5nw6JuIGjDoG5nIHThuqFpIGPDoWMgdGjhu51pIMSRaeG7g20gdHJvbmcgdMawxqFuZyBsYWkuIEJp4bq/biBwaOG7pSB0aHXhu5ljIGzDoCBnacOhIGPhu5UgcGhp4bq/dSwgYmnhur9uIMSR4buZYyBs4bqtcCBjw7MgdGjhu4MgY8OzIGzDoCB0cuG7hSBj4bunYSBiaeG6v24gZ2nDoSwgaG/hurdjIDEgc+G7kSB54bq/dSB04buRIG5oxrAgR1BELCBs4bqhbSBwaMOhdCAuLi4gKFRpbWUtc2VyaWVzKQ0KDQpDw7MgcuG6pXQgbmhp4buBdSBsb+G6oWkgaOG7k2kgcXV5IG5oxrA6IFNpbXBsZSBsaW5lYXIsIFBvbHlub21pYWwsIE11bHRpcGxlIGxpbmVhciwgTXVsdGlsZXZlbCwgTXVsdGl2YXJpYXRlLCBMb2dpc3RpYywgUG9pc3NvbiwgQ294IHByb3BvcnRpb25hbCBoYXphcmRzLCBUaW1lLXNlcmllcywgTm9ubGluZWFyLCBOb25wYXJhbWV0cmljDQoNClRyb25nIMSRw7MsIDQgbG/huqFpIHBo4buVIGJp4bq/biBoYXkgxJHGsOG7o2Mgc+G7rSBk4bulbmcgbMOgDQoNCmBgYHtyfQ0KdHlwZV9tb2RlbCA8LSBkYXRhLmZyYW1lKFR5cGUgPSBjKCJTaW1wbGUgbGluZWFyIiwgDQogICAgICAgICAgICAgICAgICAgICJNdWx0aXBsZSBsaW5lYXIiLA0KICAgICAgICAgICAgICAgICAgICAiTG9naXN0aWMiLA0KICAgICAgICAgICAgICAgICAgICAiVGltZS1zZXJpZXMiKSwNCiAgICAgICAgICAgYFR5cGljYWwgdXNlYCA9IGMoIlByZWRpY3RpbmcgYSBxdWFudGl0YXRpdmUgcmVzcG9uc2UgdmFyaWFibGUgZnJvbSBhIHF1YW50aXRhdGl2ZSBleHBsYW5hdG9yeSB2YXJpYWJsZSIsDQoiUHJlZGljdGluZyBhIHF1YW50aXRhdGl2ZSByZXNwb25zZSB2YXJpYWJsZSBmcm9tIHR3byBvciBtb3JlIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyIsDQoiUHJlZGljdGluZyBhIGNhdGVnb3JpY2FsIHJlc3BvbnNlIHZhcmlhYmxlIGZyb20gb25lIG9yIG1vcmUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIiwNCiJNb2RlbGluZyB0aW1lLXNlcmllcyBkYXRhIHdpdGggY29ycmVsYXRlZCBlcnJvcnMiKSkNCg0KdHlwZV9tb2RlbCAlPiUgZGF0YXRhYmxlKCkNCg0KYGBgDQoNCiMjIE5o4buvbmcgaMOgbSB0aMaw4budbmcgZMO5bmcgxJHhu5FpIHbhu5tpIGjhu5NpIHF1eSB0dXnhur9uIHTDrW5oDQoNCmBgYHtyfQ0KZGF0YS5mcmFtZShGdW5jdGlvbiA9IGMoInN1bW1hcnkoKSIsICJjb2VmZmljaWVudHMoKSIsICJjb25maW50KCkiLCAiZml0dGVkKCkiLCAicmVzaWR1YWxzKCkiLCAiYW5vdmEoKSIsIA0KInZjb3YoKSIsICJBSUMoKSIsICJwbG90KCkiLCAicHJlZGljdCgpIiksIA0KQWN0aW9uID0NCmMoIkRpc3BsYXlzIGRldGFpbGVkIHJlc3VsdHMgZm9yIHRoZSBmaXR0ZWQgbW9kZWwiLCAiTGlzdHMgdGhlIG1vZGVsIHBhcmFtZXRlcnMgKGludGVyY2VwdCBhbmQgc2xvcGVzKSBmb3IgdGhlIGZpdHRlZCBtb2RlbCIsICJQcm92aWRlcyBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIG1vZGVsIHBhcmFtZXRlcnMgKDk1JSBieSBkZWZhdWx0KSIsDQogICJMaXN0cyB0aGUgcHJlZGljdGVkIHZhbHVlcyBpbiBhIGZpdHRlZCBtb2RlbCIsICJMaXN0cyB0aGUgcmVzaWR1YWwgdmFsdWVzIGluIGEgZml0dGVkIG1vZGVsIiwgIkdlbmVyYXRlcyBhbiBBTk9WQSB0YWJsZSBmb3IgYSBmaXR0ZWQgbW9kZWwsIG9yIGFuIEFOT1ZBIHRhYmxlIGNvbXBhcmluZyB0d28gb3IgbW9yZSBmaXR0ZWQgbW9kZWxzIiwgIkxpc3RzIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCBmb3IgbW9kZWwgcGFyYW1ldGVycyIsICJQcmludHMgQWthaWtl4oCZcyBJbmZvcm1hdGlvbiBDcml0ZXJpb24iLCAiR2VuZXJhdGVzIGRpYWdub3N0aWMgcGxvdHMgZm9yIGV2YWx1YXRpbmcgdGhlIGZpdCBvZiBhIG1vZGVsIiwgIlVzZXMgYSBmaXR0ZWQgbW9kZWwgdG8gcHJlZGljdCByZXNwb25zZSB2YWx1ZXMgZm9yIGEgbmV3IGRhdGFzZXQiKSkgICU+JSAgZGF0YXRhYmxlKCkNCmBgYA0KDQoNCiMjIEjhu5NpIHF1eSB0dXnhur9uIHTDrW5oIMSRxqFuIGJp4bq/biAoU2ltcGxlIGxpbmVhcikNCg0KTMOgIG3DtCBow6xuaCBo4buTaSBxdXkgduG7m2kgMSBiaeG6v24gcGjhu6UgdGh24buZYywgMSBiaeG6v24gxJHhu5ljIGzhuq1wLiBIw6BtIGjhu5NpIHF1eSBjw7MgZOG6oW5nIFkgPSBhICsgYlgNCg0KWSBsw6AgYmnhur9uIHBo4bulIHRodeG7mWMsIFggbMOgIGJp4bq/biDEkeG7mWMgbOG6rXAsIGEgbMOgIGjhu4cgc+G7kSBjaOG6t24gKGludGVyY2VwdCksIGIgbMOgIGjhu4cgc+G7kSBnw7NjIChjb2VmZmljaWVudCkNCg0KVsOtIGThu6U6IFbhu5tpIGLhu5kgZOG7ryBsaeG7h3Ugd29tZW4sIGPDsyAyIGJp4bq/biBsw6AgY2hp4buBdSBjYW8sIGPDom4gbuG6t25nIGPhu6dhIHBo4bulIG7hu68uIE114buRbiBk4buxIGLDoW8gY8OibiBu4bq3bmcgY+G7p2EgcGjhu6UgbuG7ryBk4buxYSB2w6BvIGNoaeG7gXUgY2FvIGPhu6dhIGjhu40gdGEgeMOieSBk4buxbmcgbcO0IGjDrG5oIGjhu5NpIHF1eSDEkcahbg0KDQpgYGB7cn0NCmRhdGEod29tZW4pDQoNCmhlYWQod29tZW4pDQoNCndvbWVuICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gaGVpZ2h0LCB5ID0gd2VpZ2h0KSkrDQogIGdlb21fcG9pbnQoKSsNCiAgbGFicyh4ID0gImhlaWdodCAoaW4gaW5jaGVzKSIsDQogICAgICAgeSA9ICJ3ZWlnaHQgKGluIHBvdW5kcykiKQ0KDQpmaXQgPC0gbG0od2VpZ2h0IH4gaGVpZ2h0LCBkYXRhPXdvbWVuKQ0KYGBgDQoNClPhu60gZOG7pW5nIHBoxrDGoW5nIHBow6FwIGLDrG5oIHBoxrDGoW5nIG5o4buPIG5o4bqldCBPTFMgKE9yZGluYXJ5IGxlYXN0IHNxdWFyZXMpDQoNCmBgYHtyfQ0Kc3VtbWFyeShmaXQpDQpgYGANCg0KTmjGsCB24bqteSBwaMawxqFuZyB0csOsbmggaOG7k2kgcXV5IGPDsyBk4bqhbmcgDQoNClxbIFxoYXR7d2VpZ2h0fSA9IC04Ny41MSArIDMuNDUgKiBoZWlnaHQgXF0NCg0KROG7sSBiw6FvIChmaXR0ZWQpDQoNCmBgYHtyfQ0KZml0dGVkKGZpdCkNCg0Kd29tZW4kd2VpZ2h0X3ByZSA8LSBmaXR0ZWQoZml0KQ0KYGBgDQoNClBo4bqnbiBkxrAgKHNhaSBs4buHY2gpDQpgYGB7cn0NCnJlc2lkdWFscyhmaXQpDQoNCndvbWVuJHJlcyA8LSByZXNpZHVhbHMoZml0KQ0KYGBgDQoNCmBgYHtyfQ0Kd29tZW4gJT4lIA0KICBnZ3Bsb3QoKSsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGhlaWdodCwgeSA9IHdlaWdodCksIGNvbG9yID0gImJsdWUiKSsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IGhlaWdodCwgeSA9IHdlaWdodF9wcmUpLCBjb2xvciA9ICJyZWQiKSsNCiAgbGFicyh4ID0gImhlaWdodCAoaW4gaW5jaGVzKSIsDQogICAgICAgeSA9ICJ3ZWlnaHQgKGluIHBvdW5kcykiKQ0KYGBgDQoNCg0KIyMgSOG7k2kgcXV5IHR1eeG6v24gdMOtbmggxJFhIGJp4bq/bg0KDQpNw7QgaMOsbmggaOG7k2kgcXV5IGThuqFuZzogXFtcaGF0e1l9ID0gXGJldGFfezB9ICsgXGJldGFfezF9WF97MX0gKyBcYmV0YV97Mn1YX3syfSArIFxiZXRhX3szfVhfezN9ICsgLi4uXF0NCg0KVsOtIGThu6UgbOG6pXkgYuG7mSBz4buRIGxp4buHdSBnaeG6v3QgbmfGsOG7nWkg4bufIGPDoWMgYmFuZyBj4bunYSBN4bu5IHN0YXRlLng3Nw0KDQpgYGB7cn0NCnN0YXRlcyA8LSBhcy5kYXRhLmZyYW1lKHN0YXRlLng3N1ssYygiTXVyZGVyIiwgIlBvcHVsYXRpb24iLCAiSWxsaXRlcmFjeSIsICJJbmNvbWUiLCAiRnJvc3QiKV0pDQoNCnN0YXRlcyAlPiUgaGVhZCgpDQpgYGANCg0KICAtIFBow6JuIHTDrWNoIHTGsMahbmcgcXVhbg0KYGBge3J9DQpjaGFydC5Db3JyZWxhdGlvbihzdGF0ZXMsIGhpc3RvZ3JhbT1UUlVFLCBwY2g9IisiKQ0KYGBgDQoNCg0KYGBge3J9DQpmaXQgPC0gbG0oTXVyZGVyIH4gUG9wdWxhdGlvbiArIElsbGl0ZXJhY3kgKyBJbmNvbWUgKyBGcm9zdCwgZGF0YSA9IHN0YXRlcykNCnN1bW1hcnkoZml0KQ0KDQpzdGF0ZXMkcHJlIDwtIGZpdHRlZChmaXQpDQpzdGF0ZXMkcmVzIDwtIHJlc2lkdWFscyhmaXQpDQpgYGANCg0KR2nDoSB0cuG7iyBwLXZhbHVlICBJbmNvbWUgdsOgIEZyb3N0ID4gMC4wNS4gVsOsIHbhuq15LCB24bubaSBt4bupYyDDvSBuZ2jEqWEgMC4wNSBjw7MgdGjhu4Mga+G6v3QgbHXhuq1uIGjhu4cgc+G7kSBj4bunYSAyIGJp4bq/biBuw6B5IGLhurFuZyAwDQoNCi0gS2hv4bqjbmcgdGluIGPhuq15IGPhu6dhIGjhu4cgc+G7kSBo4buTaSBxdXkNCg0KYGBge3J9DQpjb25maW50KGZpdCkNCmBgYA0KDQpUaGF5IHbDrCB2aeG7h2MgbmjDrG4gdsOgbyBwdmFsdWUg4bufIG3DtCBow6xuaCBo4buTaSBxdXksIGtob+G6o25nIHRpbiBj4bqteSBj4bunYSBo4buHIHPhu5EgaOG7k2kgcXV5IGNobyBwaMOpcCDEkcOhbmggZ2nDoSB4ZW0gaOG7hyBz4buRIGjhu5NpIHF1eSBjw7Mga2jDoWMgMCBoYXkga2jDtG5nLg0KDQpLaG/huqNuZyB0aW4gY+G6rXkgY+G7p2EgSOG7hyBz4buRIGPhu6dhIEludGVyY2VwdCwgSW5jb21lLCBGcm9zdCBjw7MgY+G6rW4gZMaw4bubaSA8IDAsIHRyb25nIGtoaSBj4bqtbiB0csOqbiA+IDAgLS0+IG5ow6xuIHbDoG8gxJHDonkgY8OzIHRo4buDIGJp4bq/dCDEkcaw4bujYyAzIGjhu4cgc+G7kSBuw6B5ID0gMCB24bubaSBt4bupYyDDvSBuZ2jEqWEgMC4wNSUgDQoNCg0KYGBge3J9DQpwYXIobWZyb3c9YygyLDIpKQ0KcGxvdChmaXQpDQoNCnBhcihtZnJvdz1jKDEsMSkpDQpgYGANCiMjIEtp4buDbSDEkeG7i25oIHbDoCBs4buxYSBjaOG7jW4gbcO0IGjDrG5oDQoNCiMjIyBE4buxYSB2w6BvIMSR4buTIHRo4buLIHBo4bqnbiBkxrANCg0KICAtIEJp4buDdSDEkeG7kyAxOiBW4bq9IHTGsMahbmcgcXVhbiBnaeG7r2EgcGjhuqduIGTGsCB2w6Aga+G6v3QgcXXhuqMgZOG7sSBiw6FvLCBnacOhIHRy4buLIHBo4bqnbiBkxrAgY8Ogbmcg4bufIHF1YW5oIG3hu6ljIDAga+G6v3QgcXXhuqMgZOG7sSBiw6FvIGPDoG5nIHThu5F0LiBOaMawIHbhuq15LCB04bu3IGzhu4cgZ2nhur90IG5nxrDhu51pIMSRYW5nIMSRxrDhu6NjIGThu7EgYsOhbyBxdcOhIGNhbyBzbyB24bubaSB0aOG7sWMgdOG6vyB04bqhaSAyIGJhbmcgUmhvZGUgSXNsYW5kIHbDoCBNYXNzY2h2c2V0dHMsIGThu7EgYsOhbyBxdcOhIHRo4bqlcCB04bqhaSBiYW5nIE5ldmFkYQ0KICANCiAgLSBCaeG7g3UgxJHhu5MgMjogS2nhu4NtIHRyYSB4ZW0gcGjhuqduIGTGsCBjw7MgcGjDom4gcGjhu5FpIGNodeG6qW4gTigwLDEpIGhheSBraMO0bmcsIGvhur90IHF14bqjIGNobyB0aOG6pXkgcGjhuqduIGTGsCB04bqhaSAzIGJhbmcgTmV2YWRhIHbDoCBSaG9kZSBJc2xhbmQgdsOgIEFsYXNrYSDEkWFuZyBrbyB0aGVvIHF1eSBsdeG6rXQgcGjDom4gcGjhu5FpIGNodeG6qW4NCiAgDQogIC0gQmnhu4N1IMSR4buTIDM6IMSQw6FuaCBnacOhIHBoxrDGoW5nIHNhaSBj4bunYSBwaOG6p24gZMawIGPDsyDEkeG7k25nIG5o4bqldCBoYXkga2jDtG5nDQogIA0KICAtIEJp4buBdSDEkeG7kyA0OiBDaG8gcGjDqXAgcGjDoXQgaGnhu4duIHJhIGPDoWMgb3V0bGllcnMgdHJvbmcgcGjhuqduIGTGsA0KDQojIyMgROG7sWEgdsOgbyBjw6FjIGtp4buDbSDEkeG7i25oDQoNCiMjIyBHaeG6oyB0aGnhur90IDE6IFNhaSBz4buRIG5n4bqrdSBuaGnDqm4gY8OzIHBow6JuIHBo4buRaSBjaHXhuqluDQoNCiMjIyBHaeG6oyB0aGnhur90IDI6IEvhu7MgduG7jW5nIGPhu6dhIHNhaSBz4buRIG5n4bqrdSBuaGnDqm4gdOG6oWkgbeG7l2kgZ2nDoSB0cuG7iyBi4bqxbmcgMA0KDQpgYGB7cn0NCnJlcyA8LSByZXNpZHVhbHMoZml0KQ0KDQp0LnRlc3QocmVzLCBtdSA9IDApDQpgYGANCg0KcC12YWx1ZSA9IDE6IG3DtCBow6xuaCB0aOG7j2EgbcOjbiBnaeG6oyB0aGnhur90IDINCg0KIyMjIEdp4bqjIHRoaeG6v3QgMzogUGjGsMahbmcgc2FpIGPhu6dhIHNhaSBz4buRIG5n4bqrdSBuaGnDqm4ga2jDtG5nIMSR4buVaSANCkgwOiBwaMawxqFuZyBzYWkgc2FpIHPhu5Ega2jDtG5nIMSR4buVaQ0KSGE6IFBoxrDGoW5nIHNhaSBzYWkgc+G7kSB0aGF5IMSR4buVaQ0KDQpgYGB7cn0NCm5jdlRlc3QoZml0KQ0KYGBgDQoNCnAtdmFsdWUgPSAwLjE4LCBjw7MgdGjhu4Mga+G6v3QgbHXhuq1uIHBoxrDGoW5nIHNhaSBzYWkgc+G7kSBraMO0bmcgxJHhu5VpIHbhu5tpIG3hu6ljIMO9IG5naMSpYSA8IDAuMTgNCg0KIyMjIEdp4bqjIHRoaeG6v3QgNDogR2nhu69hIGPDoWMgYmnhur9uIMSR4buZYyBs4bqtcCBraMO0bmcgY8OzIG3hu5FpIHF1YW4gaOG7hyDEkWEgY+G7mW5nIHR1eeG6v24gaG/DoG4gaOG6o28NCg0KYGBge3J9DQp2aWYoZml0KQ0KYGBgDQoNCnZpZiA8IDEwIGNobyB0aOG6pXkgY8OhYyBiaeG6v24gxJHhu5ljIGzhuq1wIGtow7RuZyBjw7MgxJFhIGPhu5luZyB0dXnhur9uDQoNCiMjIEzhu7FhIGNo4buNbiBtw7QgaMOsbmgNClNhdSBraGkga2nhu4NtIMSR4buLbmggY8OhYyBnaeG6oyB0aGnhur90IGPhu6dhIG3DtCBow6xuaCBPTFMsIHRo4butIG5naGnhu4dtIHRyxrDhu51uZyBo4bujcCBi4buPIDIgYmnhur9uIEluY29tZSwgRnJvc3QgcmEga2jhu49pIG3DtCBow6xuaA0KDQpgYGB7cn0NCmZpdCA8LSBsbShNdXJkZXIgfiBQb3B1bGF0aW9uICsgSWxsaXRlcmFjeSwgZGF0YSA9IHN0YXRlcykNCnN1bW1hcnkoZml0KQ0KYGBgDQoNCmBgYHtyfQ0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QoZml0KQ0KDQpwYXIobWZyb3c9YygxLDEpKQ0KYGBgDQoNCg== |