Appendix - Code
> ## ----include=FALSE, echo=FALSE-------------------------------------------
> knitr::opts_chunk$set(comment = "", prompt = TRUE, out.width = 400, fig.height = 4, fig.width = 4)
> library(knitr)
> Sys.setlocale("LC_ALL", "eng")
> setwd("E:/Dropbox/00.2018/01.2018_1_semester/01.DataMining/04.HW/HW3")
>
> ## ----echo=FALSE----------------------------------------------------------
> library(ISLR)
> data(Default)
> kable(head(Default), caption = "head(Default)")
> str(Default)
>
> ## ----echo=FALSE----------------------------------------------------------
> library(MVN)
> ks.test(x = rnorm(10 ^ 4), Default$balance, alternative = "two.sided")
> ks.test(x = rnorm(10 ^ 4), Default$income, alternative = "two.sided")
>
>
> ## ----echo=FALSE----------------------------------------------------------
>
> n <- dim(Default)[1]
>
> table1 <- array(NA, c(2, 2, 30))
> error.rate.of.lda.vs <- rep(NA, 30)
>
> for (i in 1:30) {
+ set.seed(i)
+ train <- sample(1:n, n / 2)
+ default.train <- Default[train, ]
+ default.test <- Default[-train, ]
+ fit2 <- lda(default~ balance + income, data = Default, subset = train)
+ pred.lda <- predict(fit2, Default[-train, ])$class
+ table1[, , i] <- table(pred = pred.lda, true = Default[-train, 1])
+ error.rate.of.lda.vs[i] <- mean(pred.lda != Default[-train, 1])
+ }
>
> ## ----echo=FALSE----------------------------------------------------------
> # apply(table1,1:2,mean)
>
> tmp1 <- apply(table, 1:2, mean)
> dimnames(tmp1) <- list(c("No", "Yes"), c("No", "Yes"))
> kable(tmp1, "html", digits = 1) %>%
+ kable_styling(full_width = F)
>
> ## ------------------------------------------------------------------------
> mean(error.rate.of.lda.vs)
>
>
> ## ----echo=FALSE----------------------------------------------------------
> plot(
+ error.rate.of.lda.vs, type = "l",
+ ylim = c(min(error.rate.of.lda.vs) * 0.9, max(error.rate.of.lda.vs) * 1.1),
+ ylab = "Error Rate",
+ xlab = "K"
+ )
> abline(h = mean(error.rate.of.lda.vs), lty = 2, col = 2)
>
> ## ----echo=FALSE----------------------------------------------------------
>
> table2 <- array(NA, c(2, 2, 30))
> error.rate.of.qda.vs <- rep(NA, 30)
>
> for (i in 1:30) {
+ set.seed(i)
+ train <- sample(1:n, n / 2)
+ fit2 <- qda(default~ balance + income, data = Default, subset = train)
+ pred.qda <- predict(fit2, Default[-train, ])$class
+ table2[, , i] <- table(pred = pred.qda, true = Default[-train, 1])
+ error.rate.of.qda.vs[i] <- mean(pred.qda != Default[-train, 1])
+ }
>
> ## ----echo=FALSE----------------------------------------------------------
> # apply(table2,1:2, mean)
>
> tmp2 <- apply(table2, 1:2, mean)
> dimnames(tmp2) <- list(c("No", "Yes"), c("No", "Yes"))
> kable(tmp2, "html", digits = 1) %>%
+ kable_styling(full_width = F)
>
> ## ------------------------------------------------------------------------
> mean(error.rate.of.qda.vs)
>
> ## ----echo=FALSE----------------------------------------------------------
> plot(
+ error.rate.of.qda.vs, type = "l",
+ ylim = c(min(error.rate.of.qda.vs) * 0.9, max(error.rate.of.qda.vs) * 1.1),
+ ylab = "Error Rate",
+ xlab = "K"
+ )
> abline(h = mean(error.rate.of.qda.vs), lty = 2, col = 2)
>
> ## ------------------------------------------------------------------------
> Y.pred.loocv <- rep(NA, n)
> pprob <- tmp.cv.lda$posterior
>
> for (i in 1:n) Y.pred.loocv[i] <- which.max(pprob[i, ])
> Y.hat.loocv <- character(length(Y.pred.loocv))
> Y.hat.loocv[Y.pred.loocv == 1] <- "No"
> Y.hat.loocv[Y.pred.loocv == 2] <- "Yes"
> Y.hat.loocv <- factor(Y.hat.loocv, levels = c("No", "Yes"))
>
> kable(table(pred = Y.hat.loocv, true = Default[, 1]), "html") %>%
+ kable_styling(full_width = F)
>
> ## ------------------------------------------------------------------------
> mean(Y.hat.loocv != Default[, 1])
>
> ## ----echo=FALSE----------------------------------------------------------
> Y.pred.loocv.qda <- rep(NA, n)
> pprob.qda <- tmp.cv.qda$posterior
>
> for (i in 1:n) Y.pred.loocv.qda[i] <- which.max(pprob.qda[i, ])
> Y.hat.loocv.qda <- character(length(Y.pred.loocv.qda))
> Y.hat.loocv.qda[Y.pred.loocv.qda == 1] <- "No"
> Y.hat.loocv.qda[Y.pred.loocv.qda == 2] <- "Yes"
>
> kable(table(pred = Y.hat.loocv.qda, true = Default[, 1]), "html") %>%
+ kable_styling(full_width = F)
>
> ## ------------------------------------------------------------------------
> mean(Y.hat.loocv.qda != Default[, 1])
>
> ## ----echo=FALSE----------------------------------------------------------
> # K-fold CV
> K <- 10
> ind <- (1:n) %% K + 1
> set.seed(1 * i)
> folds <- sample(ind, n)
> predcv <- character(n)
> for (k in 1:K) {
+ fit <- lda(default~income + balance, data = Default, subset = which(ind != k))
+ predcv[ind == k] <- as.character(predict(fit, Default[ind == k, ])$class)
+ }
> table.10fold.lda <- table(pred = predcv, true = Default[, 1])
> kable(table.10fold.lda, "html") %>%
+ kable_styling(full_width = F)
>
>
> ## ------------------------------------------------------------------------
> error.rate.10fold <- mean(predcv != Default[, 1])
> error.rate.10fold
>
> ## ----echo=FALSE----------------------------------------------------------
> # K-fold CV
> K <- 10
> ind <- (1:n) %% K + 1
> set.seed(1 * i)
> folds <- sample(ind, n)
> predcv.qda <- character(n)
> for (k in 1:K) {
+ fit <- lda(default~income + balance, data = Default, subset = which(ind != k))
+ predcv.qda[ind == k] <- as.character(predict(fit, Default[ind == k, ])$class)
+ }
> table.10fold.qda <- table(pred = predcv.qda, true = Default[, 1])
> kable(table.10fold.qda, "html") %>%
+ kable_styling(full_width = F)
>
>
> ## ------------------------------------------------------------------------
> error.rate.10fold.qda <- mean(predcv.qda != Default[, 1])
> error.rate.10fold.qda
>
> ## ----echo=FALSE, message=FALSE, warning=FALSE----------------------------
> library(MASS)
> library(naivebayes)
> library(e1071)
>
> error.rate.nb.vs <- rep(NA, 30)
> n <- dim(Default)[1]
> table <- array(NA, c(2, 2, 30))
>
> for (i in 1:30) {
+ set.seed(i)
+ train <- sample(1:n, n / 2)
+ fit.nb.vs <- naiveBayes(default ~ ., data = Default[train, ])
+ pred.nb.vs <- predict(fit.nb.vs, newdata = Default[-train, ])
+ table[, , i] <- as.matrix(table(pred = pred.nb.vs, true = Default[-train, 1]))
+ error.rate.nb.vs[i] <- mean(pred1 != Default[-train, ]$default)
+ }
>
>
> ## ----echo=FALSE----------------------------------------------------------
> tmp <- apply(table, 1:2, mean)
> dimnames(tmp) <- list(c("No", "Yes"), c("No", "Yes"))
> kable(tmp, "html", digits = 1) %>%
+ kable_styling(full_width = F)
>
> ## ------------------------------------------------------------------------
> mean(error.rate.nb.vs)
>
> ## ----echo=FALSE----------------------------------------------------------
> plot(
+ error.rate.nb.vs, type = "l",
+ ylim = c(min(error.rate) * 0.9, max(error.rate) * 1.1),
+ ylab = "Error Rate",
+ xlab = "K"
+ )
> abline(h = mean(error.rate), lty = 2, col = 2)
>
> ## ----echo=FALSE, message=FALSE, warning=FALSE----------------------------
>
> n <- nrow(Default)
> error.loocv <- vector(mode = "logical", n)
> pred.nb.loocv <- rep(NA, n)
>
> for (i in 1:n) {
+ fit.loocv <- naiveBayes(default ~ ., data = Default[-i, ])
+ pred2 <- predict(fit.loocv, newdata = Default[i, ])
+ pred.nb.loocv[i] <- as.character(pred2)
+ error.loocv[i] <- (pred2 != Default[i, ]$default)
+ }
>
>
> ## ----echo=FALSE----------------------------------------------------------
> tab.loocv <- table(pred = pred.nb.loocv, true = Default[, 1])
> kable(tab.loocv, "html") %>%
+ kable_styling(full_width = F)
>
> ## ------------------------------------------------------------------------
>
> mean(error.loocv)
>
> ## ----echo=FALSE----------------------------------------------------------
>
> library(leaps)
>
> k <- 10
> error.kfold <- rep(NA, k)
> n <- dim(Default)[1]
> set.seed(1)
>
> pred.10fold <- character(n)
> folds <- sample(1:k, nrow(Default), replace = TRUE, prob = rep(1 / k, k))
>
> for (i in 1:k) {
+ fit.10fold <- naive_bayes(default ~ ., data = Default[folds != i, ])
+ pred.10fold[folds == i] <- as.character(predict(fit.10fold, newdata = Default[folds == i, ]))
+ }
>
>
> ## ----echo=FALSE----------------------------------------------------------
> tab1 <- table(pred = pred.10fold, true = Default[, 1])
> kable(tab1, "html") %>%
+ kable_styling(full_width = F)
>
> ## ------------------------------------------------------------------------
> error.kfold <- pred.10fold != Default[, 1]
> mean(error.kfold)
LS0tDQp0aXRsZTogIkRhdGEgbWluaW5nIEhXMzogWWVyaW0gTGltIg0KQXV0aG9yOiAiWWVyaW0gTGltIg0KRGF0ZTogIjIwMTjrhYQgNeyblCAxOOydvCINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogIHByZXR0eWRvYzo6aHRtbF9wcmV0dHk6DQogICAgaGlnaGxpZ2h0OiBnaXRodWINCiAgICB0aGVtZTogYXJjaGl0ZWN0DQogICAgdG9jOiB5ZXMNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHllcw0KLS0tDQpgYGB7ciBpbmNsdWRlPUZBTFNFLCBlY2hvPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNvbW1lbnQgPSAiIiAsIHByb21wdCA9IFRSVUUsIG91dC53aWR0aCA9IDMwMCwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDMpDQpsaWJyYXJ5KGtuaXRyKQ0KU3lzLnNldGxvY2FsZSgiTENfQUxMIiwgImVuZyIpDQpzZXR3ZCgiRTovRHJvcGJveC8wMC4yMDE4LzAxLjIwMThfMV9zZW1lc3Rlci8wMS5EYXRhTWluaW5nLzA0LkhXL0hXMyIpDQpgYGAgDQoNCiMg66y47KCcMQ0KDQpDb25zdHJ1Y3QgYSBCYXllcycgY2xhc3NpZmllciB0byBwcmVkaWN0ICJkZWZhdWx0IiB1c2luZyAiYmFsYW5jZSIgYW5kICJpbmNvbWUiIHZhcmlhYmxlcy4gRXN0aW1hdGUgdGhlIHRlc3QgZXJyb3IgcmF0ZSB1c2luZyBmb2xsb3dpbmcgbWV0aG9kcy4NCg0KKGkpIFZTIGFwcHJvYWNoLCANCihpaSkgTE9PQ1YsIGFuZCANCihpaWkpIDEwLWZvbGQgQ1YuDQoNCg0KDQojIyDrjbDsnbTthLAg7IK07Y6067O06riwIA0K642w7J207YSw66W8IOyCtO2OtOuztOyekC4gPGJyLz4NCuy0nSA06rCcIOuzgOyImOuhnCDsnbTro6jslrTsoLjsnojqs6AsIOunjOqxtOydmCDqtIDsuKHsuZjqsIAg7J6I64ukLiA8YnIvPg0KZGVmYXVsdOuKlCDssYTrrLTrtojsnbTtloksIHN0dWRlbnTripQg7ZWZ7IOd7Jes67aALCBiYWxhbmNl64qUIO2Gteyepe2Pieq3oOyelOqzoCwgaW5jb21l7J2AIOyImOyeheydhCDsnZjrr7jtlZzri6QuIA0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KbGlicmFyeShJU0xSKQ0KZGF0YShEZWZhdWx0KQ0Ka2FibGUoaGVhZChEZWZhdWx0KSwgY2FwdGlvbiA9ICJoZWFkKERlZmF1bHQpIikNCnN0cihEZWZhdWx0KQ0KYGBgDQoNCg0KIyMg7KCV6rec7ISxIOqygOyglQ0KDQotIEJheWVzIGNsYXNzaWZpZXLsnZgg6rK97JqwIOygleq3nOyEseydhCDrsJjrk5zsi5wg66eM7KGx7Iuc7Lyc7JW8IO2VmOuKlCDqsoPsnYAg7JWE64uI64ukLiANCi0gKirtlZjsp4Drp4wsIOygleq3nOyEseydtCDrp4zsobHrkKAg65WMIGVycm9y66W8IOy1nOyGjOuhnCDspITsnbwg7IiYIOyeiOqzoCwg6re4IOqysOqzvOuPhCDslYjsoJXsoIHsnbTri6QuKiogPGJyLz4NCi0g65Sw65287IScIOydtOyZleydtOuptCDsoJXqt5zshLHsnbQg66eM7KGx65CY66m0IOuNlCDsoovri6Tqs6Ag7ZWc64ukLiANCjxici8+DQoNCi0g7JWI7YOA6rmd6rKM64+ELCDsmrDrpqzsnZgg642w7J207YSw64qUIOygleq3nOyEseydhCDrp4zsobHtlZjsp4Ag66q77ZaI64ukLiANCi0gYmFsYW5jZeyZgCBpbmNvbWXsl5Ag64yA7ZWcIHAtdmFsdWU9PDAuMDAw7J206rOgLCBOb3JtYWxpdHnqsIAg66eM7KGx65CY7KeAIOyViuyVmOuLpC4gDQoNCjxici8+DQoNCi0g7Jes7Jyg6rCAIOuQnOuLpOuptCBib3hjb3ggdHJhbnNmb3JtYXRpb24g65Ox7J2EIOydtOyaqe2VtCDsoJXqt5zshLHsnbQg66eM7KGx65CY64qUIO2Yle2DnOuhnCDrsJTqvrjslrTspIDri6TrqbQg67aE7ISdIOqysOqzvOqwgCDrjZQg7J6YIOuCmOyYrCDsiJgg7J6I7J2EIOqygyDqsJnri6QuIA0KLSDsp4DquIjsnYAsIOq3uOuDpSDsnbTrjIDroZwg67aE7ISd7J2EIOynhO2Wie2VmOuPhOuhnSDtlZjsnpAuIA0KDQogDQpgYGB7ciBlY2hvPUZBTFNFfQ0KbGlicmFyeShNVk4pDQprcy50ZXN0KHg9cm5vcm0oMTBeNCksRGVmYXVsdCRiYWxhbmNlLGFsdGVybmF0aXZlPSd0d28uc2lkZWQnKQ0Ka3MudGVzdCh4PXJub3JtKDEwXjQpLERlZmF1bHQkaW5jb21lLGFsdGVybmF0aXZlPSd0d28uc2lkZWQnKQ0KDQpgYGANCg0KDQoNCg0KPGJyLz4NCg0KIyMgVmFsaWRhdGlvbiBTZXQgQXBwcm9hY2guDQoNCiMjIyBWUyAtIExEQQ0KLSDrqLzsoIBMREHroZwg67aE7ISd7J2EIO2VtOuztOyekC4gDQotIHZhbGlkYXRpb24gc2V0IGFwcHJvYWNo64qUIHNhbXBsaW5n7JeQIOyYge2WpeydhCDrp47snbQg67Cb7Jy866+A66GcLCDqt7gg7JiB7Zal7J2EIOy1nOyGjO2ZlO2VmOq4sCDsnITtlbQgMzDrsogg67CY67O17Lih7KCV7ZaI64ukLiAgDQotIExEQeyXkCDsnZjtlbQg67aE7ISd7ZWcIOqysOqzvOulvCDslYTrnpggY29uZnVzaW9uIG1hdHJpeOuhnCDsoJXrpqztlbTrs7TslZjri6QuIA0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQoNCm4gPC0gZGltKERlZmF1bHQpWzFdDQoNCnRhYmxlMSA8LSBhcnJheShOQSxjKDIsMiwzMCkpDQplcnJvci5yYXRlLm9mLmxkYS52cyA8LSByZXAoTkEsMzApDQoNCmZvcihpIGluIDE6MzApew0Kc2V0LnNlZWQoaSkNCnRyYWluIDwtIHNhbXBsZSgxOm4sIG4vMikNCmRlZmF1bHQudHJhaW4gPC0gRGVmYXVsdFt0cmFpbixdDQpkZWZhdWx0LnRlc3QgPC0gRGVmYXVsdFstdHJhaW4sXQ0KZml0MjwtbGRhKGRlZmF1bHR+IGJhbGFuY2UraW5jb21lLGRhdGE9RGVmYXVsdCxzdWJzZXQ9dHJhaW4pDQpwcmVkLmxkYTwtcHJlZGljdChmaXQyLERlZmF1bHRbLXRyYWluLF0pJGNsYXNzDQp0YWJsZTFbLCxpXSA8LSB0YWJsZShwcmVkID0gcHJlZC5sZGEsIHRydWU9IERlZmF1bHRbLXRyYWluLDFdKQ0KZXJyb3IucmF0ZS5vZi5sZGEudnNbaV0gPC0gbWVhbihwcmVkLmxkYSE9RGVmYXVsdFstdHJhaW4sMV0pDQp9DQpgYGANCg0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQojIGFwcGx5KHRhYmxlMSwxOjIsbWVhbikNCg0KdG1wMSA8LSBhcHBseSh0YWJsZSwgMToyICxtZWFuKQ0KZGltbmFtZXModG1wMSkgPC0gbGlzdChjKCJObyIsIlllcyIpLGMoIk5vIiwiWWVzIikpDQprYWJsZSh0bXAxLCAiaHRtbCIsIGRpZ2l0cyA9IDEpICU+JSANCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoPUYpDQpgYGANCg0KLSDsi6TsoJwg7LGE66y067aI7J207ZaJ7J6Q7J24642wLCDsmIjsuKHqsrDqs7zroZzripQg7LGE66y067aI7J207ZaJ7J6Q6rCAICoq7JWE64uI65286rOgKiog64KY7JioIOyCrOuejOydtCDslb0gMTIx66qF7J2064KYIOyeiOuLpC4gDQotIOyggeygiO2VnCDrtoTrpZjqsIAg7JWE64uMIOqygyDqsJnri6QuIA0KDQpgYGB7cn0NCm1lYW4oZXJyb3IucmF0ZS5vZi5sZGEudnMpDQoNCmBgYA0KLSAzMOuyiCDrsJjrs7XsuKHsoJXtlZwgZXJyb3IgcmF0ZeydmCDtj4nqt6DsnYAgICoqMC4wMjczKirroZwg64KY7Jio64ukLg0KLSBlcnJvciByYXRl7J2AIOyekeqyjCDrgpjsmZTsnLzrgpgsIGNvbmZ1c2lvbiBtYXRyaXjrpbwg6rOg66Ck7ZWY66m0IOq3uOumrCDsoovsnYAg67aE7ISd7J2AIOyVhOuLjCDqsoPsnYQg7JWMIOyImCDsnojri6QuIA0KDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCnBsb3QoZXJyb3IucmF0ZS5vZi5sZGEudnMgLHR5cGU9ImwiLCANCiAgICAgeWxpbT1jKG1pbihlcnJvci5yYXRlLm9mLmxkYS52cykqMC45LG1heChlcnJvci5yYXRlLm9mLmxkYS52cykqMS4xKSwNCiAgICAgeWxhYj0iRXJyb3IgUmF0ZSIsDQogICAgIHhsYWI9IksiKQ0KYWJsaW5lKGg9bWVhbihlcnJvci5yYXRlLm9mLmxkYS52cyksIGx0eT0yLCBjb2w9MikNCmBgYA0KLSDsnIQg6re4656Y7ZSE64qUIOyDiOuhnOyatCBzYW1wbGluZyDtlaDrlYzrp4jri6Qg7Ja77J2AIGVycm9yIHJhdGXsnbTri6QuIOuMgOyytOuhnCAwLjAyNuyjvOuzgOydhCDrp7Trj4jri6QuIA0KPGJyLz4NCg0KIyMjIFZTIC0gUURBDQotIOyVhOuemOuKlCBRREHroZwg67aE7ISd7ZWcIOqysOqzvOuLpC4gTERB7JmAIOywqOydtOqwgCDrp47snbQg64KY7KeAIOyViuuKlOuLpC4gDQpgYGB7ciBlY2hvPUZBTFNFfQ0KDQp0YWJsZTIgPC0gYXJyYXkoTkEsYygyLDIsMzApKQ0KZXJyb3IucmF0ZS5vZi5xZGEudnMgPC0gcmVwKE5BLDMwKQ0KDQpmb3IoaSBpbiAxOjMwKXsNCiAgc2V0LnNlZWQoaSkNCiAgdHJhaW4gPC0gc2FtcGxlKDE6biwgbi8yKQ0KICBmaXQyPC1xZGEoZGVmYXVsdH4gYmFsYW5jZStpbmNvbWUsZGF0YT1EZWZhdWx0LHN1YnNldD10cmFpbikNCiAgcHJlZC5xZGE8LXByZWRpY3QoZml0MixEZWZhdWx0Wy10cmFpbixdKSRjbGFzcw0KICB0YWJsZTJbLCxpXSA8LSB0YWJsZShwcmVkPSBwcmVkLnFkYSx0cnVlID0gRGVmYXVsdFstdHJhaW4sMV0pDQogIGVycm9yLnJhdGUub2YucWRhLnZzW2ldIDwtIG1lYW4ocHJlZC5xZGEhPURlZmF1bHRbLXRyYWluLDFdKQ0KfQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGFwcGx5KHRhYmxlMiwxOjIsIG1lYW4pDQoNCnRtcDIgPC0gYXBwbHkodGFibGUyLCAxOjIgLG1lYW4pDQpkaW1uYW1lcyh0bXAyKSA8LSBsaXN0KGMoIk5vIiwiWWVzIiksYygiTm8iLCJZZXMiKSkNCmthYmxlKHRtcDIsICJodG1sIiwgZGlnaXRzID0gMSkgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGg9RikNCmBgYA0KLSBMREHsmYAg67mE6rWQ7ZWY7JesIOyigCDrjZQg7J6Q7IS47ZWY6rKMIOuztOyekOuptCwgDQogICAgKyBObyAtPiBOT+uhnCDrtoTrpZjtlZwg7LyA7J207Iqk6rCAIOunjuyVhOyhjOqzoCwgDQogICAgKyBZZXMgLT4gWWVz66GcIOu2hOulmO2VnCDsvIDsnbTsiqTqsIAg7KSE7JeI64ukLiANCi0g7J2A7ZaJ7J6F7J6l7JeQ7ISgIFllc+ulvCBZZXPrnbzqs6Ag7KCc64yA66GcIOu2hOulmO2VmOuKlCDqsoPsnbQg7KSR7JqU7ZWc642wIFFEQeuKlCDsnbTrpbwg7J6YIOu2hOulmO2VmOyngCDrqrvtlZjripQg6rKDIOqwmeuLpC4gDQoNCg0KYGBge3IgfQ0KbWVhbihlcnJvci5yYXRlLm9mLnFkYS52cykNCmBgYA0KLSBRREHsl5DshJwgMzDrsogg67CY67O17Lih7KCV7ZWcIGVycm9yIHJhdGXsnZgg7Y+J6reg7J2AICAqKjAuMDI2OSoq66GcIOuCmOyYqOuLpC4NCg0KYGBge3IgZWNobz1GQUxTRX0NCnBsb3QoZXJyb3IucmF0ZS5vZi5xZGEudnMgLHR5cGU9ImwiLCANCiAgICAgeWxpbT1jKG1pbihlcnJvci5yYXRlLm9mLnFkYS52cykqMC45LG1heChlcnJvci5yYXRlLm9mLnFkYS52cykqMS4xKSwNCiAgICAgeWxhYj0iRXJyb3IgUmF0ZSIsDQogICAgIHhsYWI9IksiKQ0KYWJsaW5lKGg9bWVhbihlcnJvci5yYXRlLm9mLnFkYS52cyksIGx0eT0yLCBjb2w9MikNCmBgYA0KLSDsnIQg6re4656Y7ZSE64qUIOqwgSAgc2FtcGxpbmfsl5DshJwg7Ja77J2AIGVycm9yIHJhdGXsnbTri6QuIA0KDQogPGJyLz4NCg0KLSBlcnJvciByYXRl7J20IDAuMDI2fiAwLjI4IOyjvOuzgOydhCDrp7Trj4jri6QuIOyYpOu2hOulmCDruYTsnKjsnbQgMn4zJeuCtOyZuOydtOuvgOuhnCDqvaQg7J6R7J2AIO2OuOydtOuLpC4gIA0KLSDtlZjsp4Drp4wg7Jik67mE7Jyo7J20IOyekeuLpOqzoCDri6Qg7KKL7J2AIOqyg+ydgCDslYTri4jri6QuIA0KLSDsnpjrqrsg67aE66WY7ZWcIOqyg+yXkCDrjIDtlZwg67mE7Jqp64+EIOyDneqwge2VtOyVvO2VnOuLpC4gDQotIOydtOulvCDqs6DroKTtlZjrqbQgYmF5ZXMgY2xhc3NpZmllcuuhnCDsiJjtlontlZwg67aE66WY67aE7ISd7J20ICoq7JWE7KO8IOyii+ydgCDqsoPsnYAg7JWE64uYKirsnYQg7IOd6rCB7ZW067O8IOyImCDsnojri6QuIA0KDQoNCjxici8+DQoNCi0gTERB7J2YIGVycm9yIHJhdGXqsIAg642UIOuCruycvOuvgOuhnCwgTERB66GcIOu2hOyEne2VmOuKlCDqsoPsnbQg642UIOyii+yVhOuztOyduOuLpC4gDQotICoq7Iuk7KCcLCAgTERB7JmAIFFEQeydmCDqsrDqs7zqsIAg7YGs6rKMIOywqOydtOuCmOyngCDslYrsnLzri4gg7Ja064qQIOqyg+ydhCDsgqzsmqntlbTrj4Qg7IOB6rSA7JeG64ukLiDtlZjsp4Drp4wg7J207JmV7J2066m067mE6rWQ7KCBIOuLqOyInO2VnCDrqqjtmJXsnLzroZwgY2xhc3NpZmljYXRpb27snYQg7IiY7ZaJ7ZWY64qUIOqyg+ydtCDsoovri6QuKiogDQoNCg0KPGJyLz4NCg0KIyMgTE9PQ1YNCiMjIyBMT09DVi0gTERBDQpgYGB7cn0NClkucHJlZC5sb29jdiA8LSByZXAoTkEsbikNCnBwcm9iIDwtIHRtcC5jdi5sZGEkcG9zdGVyaW9yDQoNCmZvcihpIGluIDE6bikgWS5wcmVkLmxvb2N2W2ldPC13aGljaC5tYXgocHByb2JbaSxdKQ0KWS5oYXQubG9vY3Y8LWNoYXJhY3RlcihsZW5ndGgoWS5wcmVkLmxvb2N2KSkNClkuaGF0Lmxvb2N2W1kucHJlZC5sb29jdj09MV08LSJObyINClkuaGF0Lmxvb2N2W1kucHJlZC5sb29jdj09Ml08LSJZZXMiDQpZLmhhdC5sb29jdiA8LSBmYWN0b3IoWS5oYXQubG9vY3YsIGxldmVscz1jKCJObyIsIlllcyIpKQ0KDQprYWJsZSh0YWJsZShwcmVkPVkuaGF0Lmxvb2N2LCB0cnVlPURlZmF1bHRbLDFdKSwgImh0bWwiKSAlPiUgDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aD1GKQ0KYGBgDQoNCg0KYGBge3J9DQptZWFuKFkuaGF0Lmxvb2N2ICE9IERlZmF1bHRbLDFdKQ0KYGBgDQotIExPT0NW66W8IOydtOyaqe2VtCBMREHsnZggZXJyb3IgcmF0ZeulvCDqtaztlZwg6rKw6rO864ukLiANCi0gZXJyb3IgcmF0ZeqwgCAqKjAuMDI3Nioq7J2064ukLiANCg0KPGJyLz48YnIvPg0KDQojIyMgTE9PQ1YtIFFEQQ0KLSBMT09DVuulvCDsnbTsmqntlbQgUURB7J2YIGVycm9yIHJhdGXrpbwg6rWs7ZWcIOqysOqzvOuLpC4gDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpZLnByZWQubG9vY3YucWRhIDwtIHJlcChOQSxuKQ0KcHByb2IucWRhIDwtIHRtcC5jdi5xZGEkcG9zdGVyaW9yDQoNCmZvcihpIGluIDE6bikgWS5wcmVkLmxvb2N2LnFkYVtpXTwtd2hpY2gubWF4KHBwcm9iLnFkYVtpLF0pDQpZLmhhdC5sb29jdi5xZGE8LWNoYXJhY3RlcihsZW5ndGgoWS5wcmVkLmxvb2N2LnFkYSkpDQpZLmhhdC5sb29jdi5xZGFbWS5wcmVkLmxvb2N2LnFkYT09MV08LSJObyINClkuaGF0Lmxvb2N2LnFkYVtZLnByZWQubG9vY3YucWRhPT0yXTwtIlllcyINCg0Ka2FibGUodGFibGUocHJlZD1ZLmhhdC5sb29jdi5xZGEsdHJ1ZT1EZWZhdWx0WywxXSksICJodG1sIikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGg9RikNCmBgYA0KDQpgYGB7cn0NCm1lYW4oWS5oYXQubG9vY3YucWRhICE9IERlZmF1bHRbLDFdKQ0KYGBgDQotIGVycm9yIHJhdGXqsIAgKiowLjAyNzIqKuydtOuLpC4gDQotIOyXrOq4sOyEnOuPhCDsl63si5zrgpgsIExEQeyZgCBRREHsnZgg6rKw6rO87IKs7J207JeQIO2BsCDssKjsnbTqsIAg7JeG64ukLiDrlLDrnbzshJwg7IOB64yA7KCB7Jy866GcIOuLqOyInO2VnCBMREHrqqjtmJXsnYQg7IKs7Jqp7ZWY64qUIOqyg+ydtCDsoovqsqDri6QuIA0KDQo8YnIvPg0KDQojIyAxMC1mb2xkIENWIA0KIyMjIDEwLWZvbGQgQ1YgLSBMREENCi0gMTAgZm9sZCDrpbwg7J207Jqp7ZW0IOq1rO2VnCBMREHsnZgg6rKw6rO864ukLiANCmBgYHtyIGVjaG89RkFMU0V9DQojSy1mb2xkIENWDQpLPC0xMA0KaW5kPC0oMTpuKSUlSysxDQpzZXQuc2VlZCgxKmkpDQpmb2xkczwtc2FtcGxlKGluZCxuKQ0KcHJlZGN2PC1jaGFyYWN0ZXIobikNCmZvciAoayBpbiAxOkspew0KCWZpdDwtbGRhKGRlZmF1bHR+aW5jb21lK2JhbGFuY2UsZGF0YT1EZWZhdWx0LHN1YnNldD13aGljaChpbmQhPWspKQ0KCXByZWRjdltpbmQ9PWtdPC1hcy5jaGFyYWN0ZXIocHJlZGljdChmaXQsRGVmYXVsdFtpbmQ9PWssXSkkY2xhc3MpDQp9DQp0YWJsZS4xMGZvbGQubGRhIDwtIHRhYmxlKHByZWQ9IHByZWRjdix0cnVlID0gRGVmYXVsdFssMV0pDQprYWJsZSh0YWJsZS4xMGZvbGQubGRhLCAiaHRtbCIpICU+JSANCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoPUYpDQoNCmBgYA0KDQpgYGB7cn0NCmVycm9yLnJhdGUuMTBmb2xkIDwtIG1lYW4ocHJlZGN2IT1EZWZhdWx0WywxXSkNCmVycm9yLnJhdGUuMTBmb2xkDQpgYGANCi0gZXJyb3IgcmF0ZeuKlCAqKjAuMDI3NSoq7J2064ukLiANCg0KDQoNCiMjIyAxMC1mb2xkIENWIC0gUURBDQpgYGB7ciBlY2hvPUZBTFNFfQ0KI0stZm9sZCBDVg0KSzwtMTANCmluZDwtKDE6biklJUsrMQ0Kc2V0LnNlZWQoMSppKQ0KZm9sZHM8LXNhbXBsZShpbmQsbikNCnByZWRjdi5xZGE8LWNoYXJhY3RlcihuKQ0KZm9yIChrIGluIDE6Syl7DQoJZml0PC1sZGEoZGVmYXVsdH5pbmNvbWUrYmFsYW5jZSxkYXRhPURlZmF1bHQsc3Vic2V0PXdoaWNoKGluZCE9aykpDQoJcHJlZGN2LnFkYVtpbmQ9PWtdPC1hcy5jaGFyYWN0ZXIocHJlZGljdChmaXQsRGVmYXVsdFtpbmQ9PWssXSkkY2xhc3MpDQp9DQp0YWJsZS4xMGZvbGQucWRhIDwtIHRhYmxlKHByZWQ9IHByZWRjdi5xZGEsdHJ1ZSA9IERlZmF1bHRbLDFdKQ0Ka2FibGUodGFibGUuMTBmb2xkLnFkYSwgImh0bWwiKSAlPiUgDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aD1GKQ0KDQpgYGANCg0KYGBge3J9DQplcnJvci5yYXRlLjEwZm9sZC5xZGEgPC0gbWVhbihwcmVkY3YucWRhIT1EZWZhdWx0WywxXSkNCmVycm9yLnJhdGUuMTBmb2xkLnFkYQ0KYGBgDQotIGVycm9yIHJhdGXqsIAgKiowLjAyNzUqKuydtOuLpC4gDQotIDEwLWZvbGTsl5DshJwg7Lih7KCV7ZWcIGVycm9yIHJhdGXsnYAgTERB64KYLCBRREHrgpgg6re4IOqysOqzvOqwgCDqsJnri6QuIA0KLSDqt7jrn6zri4gg7J207JmV7J2066m0IOuLqOyInO2VnCDrqqjtmJXsnbggTERB66W8IOyCrOyaqe2VmOuKlCDqsoPsnbQg7KKL6rKg64ukLiANCg0KDQo8YnIvPg0KPGJyLz4NCg0KKioqDQoNCjxici8+DQoNCiMg66y47KCcIDINCg0KQ29uc3RydWN0IGEgbmFpdmUgQmF5ZXMncyBjbGFzc2lmaWVyIHRvIHByZWRpY3QgImRlZmF1bHQiIHVzaW5nICJzdHVkZW50IiwgImJhbGFuY2UiLCBhbmQgImluY29tZSIgdmFyaWFibGVzLiBFc3RpbWF0ZSB0aGUgdGVzdCBlcnJvciByYXRlIHVzaW5nIGZvbGxvd2luZyBtZXRob2RzLg0KDQooaSkgVlMgYXBwcm9hY2gsIA0KKGlpKSBMT09DViwgYW5kIA0KKGlpaSkgMTAtZm9sZCBDVi4NCg0KIyMgVmFsaWRhdGlvbiBTZXQgYXBwcm9hY2gNCi0gVlPrpbwg7J207Jqp7ZW0IE5haXZlIEJheWVz7J2YIGVycm9yIHJhdGXrpbwg7IK07Y6067O07JWY64ukLiANCi0gVlMgYXBwcm9hY2jqsIAgc2FtcGxpbmfsl5Ag65Sw6528IOunjuydgCDsmIHtlqXsnYQg67Cb7Jy866+A66GcLCBzYW1wbGluZ+yXkCDsnZjtlZwg7JiB7Zal7J2EIOykhOydtOq4sCDsnITtlbQgc2FtcGxpbmfsnYQgMTDrsogg67CY67O17ZaI64ukLiANCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoTUFTUykNCmxpYnJhcnkobmFpdmViYXllcykNCmxpYnJhcnkoZTEwNzEpDQoNCmVycm9yLnJhdGUubmIudnMgPC0gcmVwKE5BLCAzMCkNCm4gPC0gZGltKERlZmF1bHQpWzFdDQp0YWJsZSA8LSBhcnJheShOQSwgYygyLDIsMzApKQ0KDQpmb3IoaSBpbiAxOjMwKXsNCiAgc2V0LnNlZWQoaSkNCiAgdHJhaW4gPC0gc2FtcGxlKDE6biwgbi8yKQ0KICBmaXQubmIudnMgPC0gbmFpdmVCYXllcyhkZWZhdWx0IH4gLiwgZGF0YT1EZWZhdWx0W3RyYWluLF0pDQogIHByZWQubmIudnMgPC0gcHJlZGljdChmaXQubmIudnMsIG5ld2RhdGE9RGVmYXVsdFstdHJhaW4sXSkNCiAgdGFibGVbLCxpXSA8LSBhcy5tYXRyaXgodGFibGUocHJlZCA9IHByZWQubmIudnMsIHRydWUgPSBEZWZhdWx0Wy10cmFpbiwxXSkpDQogIGVycm9yLnJhdGUubmIudnNbaV0gPC0gbWVhbihwcmVkMSAhPSBEZWZhdWx0Wy10cmFpbixdJGRlZmF1bHQpDQp9DQoNCmBgYA0KDQoNCg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KdG1wIDwtIGFwcGx5KHRhYmxlLCAxOjIgLG1lYW4pDQpkaW1uYW1lcyh0bXApIDwtIGxpc3QoYygiTm8iLCJZZXMiKSxjKCJObyIsIlllcyIpKQ0Ka2FibGUodG1wLCJodG1sIiwgZGlnaXRzID0gMSkgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGg9RikNCmBgYA0KLSBjb25mdXN0aW9uIG1hdHJpeA0KDQpgYGB7ciB9DQptZWFuKGVycm9yLnJhdGUubmIudnMpDQpgYGANCi0gIGVycm9yIHJhdGXsnYAgKiowLjA0NSoq7J2064ukLiANCi0gYmF5ZXMgY2xhc3NpZmllcuuztOuLpCBuYWl2ZSBiYXllc+ulvCDsgqzsmqntlojsnYQg65WMIGVycm9yIHJhdGXsnbQg642UIOuGkuuLpC4gDQotIOydtOqyg+ydgCDslYTrp4gsIG5haXZlIGJheWVz7JeQ7IScIOqwgOygle2VmOuKlCDrs4DsiJjrk6TsnZgg64+F66a97ISx7Jy866GcIOyduO2VtCDsoJXrs7TqsIAg7IaQ7Iuk65CY7Ja0IOuCmO2DgOuCnCDsmIHtlqXsnbgg6rKDIOqwmeuLpC4NCg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcGxvdChlcnJvci5yYXRlLm5iLnZzICx0eXBlPSJsIiwgDQogICAgIHlsaW09YyhtaW4oZXJyb3IucmF0ZSkqMC45LG1heChlcnJvci5yYXRlKSoxLjEpLA0KICAgICB5bGFiPSJFcnJvciBSYXRlIiwNCiAgICAgeGxhYj0iSyIpDQphYmxpbmUoaD1tZWFuKGVycm9yLnJhdGUpLCBsdHk9MiwgY29sPTIpDQpgYGANCi0gMzDrsogg67CY67O1IOy4oeygle2VoCDrlYzrp4jri6Qg7Ja77J2AIGVycm9yIHJhdGXrpbwgcGxvdOycvOuhnCDrgpjtg4DrgrTrs7TslZjri6QuIA0KDQoNCg0KPGJyLz48YnIvPg0KDQojIyBMT09DVg0KLSBMT09DVuulvCDsnbTsmqntlbQg6rWs7ZWcICBOYWl2ZSBCYXllc+ydmCAgZXJyb3IgcmF0ZeulvCDsgrTtjrTrs7TsnpAuIA0KIA0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KbiA8LSBucm93KERlZmF1bHQpDQplcnJvci5sb29jdiA8LSB2ZWN0b3IobW9kZSA9ICJsb2dpY2FsIiwgbikNCnByZWQubmIubG9vY3YgPC0gcmVwKE5BLG4pDQoNCmZvciggaSBpbiAxOm4pew0KICBmaXQubG9vY3YgPC0gbmFpdmVCYXllcyhkZWZhdWx0IH4gLiwgZGF0YT1EZWZhdWx0Wy1pLF0pDQogIHByZWQyIDwtIHByZWRpY3QoZml0Lmxvb2N2LCBuZXdkYXRhPURlZmF1bHRbaSxdKQ0KICBwcmVkLm5iLmxvb2N2W2ldIDwtIGFzLmNoYXJhY3RlcihwcmVkMikNCiAgZXJyb3IubG9vY3ZbaV0gPC0gKHByZWQyICE9IERlZmF1bHRbaSxdJGRlZmF1bHQpDQp9DQoNCmBgYA0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQp0YWIubG9vY3Y8LSB0YWJsZShwcmVkID0gcHJlZC5uYi5sb29jdiwgdHJ1ZSA9IERlZmF1bHRbLDFdKQ0Ka2FibGUodGFiLmxvb2N2LCJodG1sIikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGg9RikNCmBgYA0KDQpgYGB7cn0NCg0KbWVhbihlcnJvci5sb29jdikNCmBgYA0KLSBlcnJvciByYXRl64qUICoqMC4wMjk1KirroZwg64KY7YOA64Ks64ukLg0KLSBCYXllcyBDbGFzc2lmaWVy7J2YIGVycm9yIHJhdGXrs7Tri6Qg7YGs64ukLiANCi0g7J206rKD7J2AIOyVhOuniCwgbmFpdmUgYmF5ZXPsl5DshJwg6rCA7KCV7ZWY64qUIOuzgOyImOuTpOydmCDrj4Xrpr3shLHsnLzroZwg7J247ZW0IOygleuztOqwgCDshpDsi6TrkJjslrQg64KY7YOA64KcIOyYge2WpeyduCDqsoMg6rCZ64ukLg0KDQoNCjxici8+DQoNCi0gVlPsl5DshJwg7Ja77J2AIGVycm9yIHJhdGXsnYAgKiowLjA0NSoq7J24642wLCBMT09DVuyXkOyEnCDqtaztlZwgZXJyb3IgcmF0ZeydgCAqKjAuMDI5NSoq7J2064ukLiDruYTqtZDsoIEg7J6R64ukLiANCi0gVlPsnYAg642w7J207YSw7J2YIOygiOuwmOunjCDsgqzsmqntlZjripQg67CY66m0LCBMT09DVuuKlCDrjbDsnbTthLDrpbwg66qo65GQIOuLpCDsgqzsmqntlZjquLAg65WM66y47JeQIOuCmO2DgOuCnCDtmITsg4Hsnbgg6rKDIOqwmeuLpC4gDQoNCg0KPGJyLz4NCg0KIyMgMTAtZm9sZCBDVg0KLSAxMC1mb2xkIENW66W8IOydtOyaqe2VtCBOYWl2ZSBCYXllc+ydmCDqsrDqs7zrpbwg7IK07Y6067O07JWY64ukLiANCg0KYGBge3IgZWNobz1GQUxTRX0NCg0KbGlicmFyeShsZWFwcykNCg0KayA8LSAxMA0KZXJyb3Iua2ZvbGQgPC0gcmVwKE5BLCBrKQ0KbiA8LSBkaW0oRGVmYXVsdClbMV0NCnNldC5zZWVkKDEpDQoNCnByZWQuMTBmb2xkIDwtIGNoYXJhY3RlcihuKQ0KZm9sZHMgPC0gc2FtcGxlKDE6aywgbnJvdyhEZWZhdWx0KSwgcmVwbGFjZSA9IFRSVUUsIHByb2IgPSByZXAoMSAvIGssIGspKQ0KDQpmb3IoaSBpbiAxOmspew0KICBmaXQuMTBmb2xkIDwtIG5haXZlX2JheWVzKGRlZmF1bHQgfiAuLCBkYXRhPURlZmF1bHRbZm9sZHMhPWksXSkNCiAgcHJlZC4xMGZvbGRbZm9sZHM9PWldIDwtIGFzLmNoYXJhY3RlcihwcmVkaWN0KGZpdC4xMGZvbGQsIG5ld2RhdGE9RGVmYXVsdFtmb2xkcz09aSxdKSkNCn0NCg0KYGBgDQoNCg0KDQoNCg0KYGBge3IgZWNobz1GQUxTRX0NCnRhYjEgPC0gdGFibGUocHJlZCA9IHByZWQuMTBmb2xkLCB0cnVlID0gRGVmYXVsdFssMV0pDQprYWJsZSh0YWIxLCJodG1sIikgJT4lIA0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGg9RikNCmBgYA0KDQpgYGB7cn0NCmVycm9yLmtmb2xkIDwtIHByZWQuMTBmb2xkICE9IERlZmF1bHRbLDFdDQptZWFuKGVycm9yLmtmb2xkKSANCmBgYA0KLSBlcnJvciByYXRl64qUICoqMC4wMjkzKirroZwg64KY7YOA64Ks64ukLiANCi0g7J2064qUIExPT0NW7JmAIOu5hOyKt+2VnCDqsrDqs7zri6QuIGdvb2QhIA0KDQo8YnIvPg0KPGJyLz4NCg0KDQojIOu2hOyEneqysOqzvCDsooXtlakNCi0gTmFpdmUgQmF5ZXPrs7Tri6QgQmF5ZXMgQ2xhc3NpZmllcuulvCDsgqzsmqntlojsnYQg65WMIGVycm9yIHJhdGXqsIAg7KCB7JeI64ukLiANCg0KPiDrgpgg6rCZ7Jy866m0IExEQeulvCDsnbTsmqntlZjsl6wgY2xhc3NpZmljYXRpb27snYQg7ZWgIOqygyDqsJnri6QuIGVycm9yIHJhdGXsnbQg7J6R6rOgLCDrqqjtmJXrj4Qg67mE6rWQ7KCBIOuLqOyInO2VmOq4sCDrlYzrrLjsnbTri6QuIA0KDQotIEJheWVzIENsYXNzaWZpZXLsnZgg6rK97JqwLCBRREHrpbwg7IKs7Jqp7ZWY64KYLCBMREHrpbwg7IKs7Jqp7ZWY64KYIO2BsCDssKjsnbTqsIAg7JeG7JeI64ukLg0KLSDqs6DroZwgTERB66W8IOydtOyaqe2VnCAgY2xhc3NpZmljYXRpb27snbQg642UIOyggeygiO2VmOqyoOuLpOqzoCDtjJDri6jtlZjsmIDri6QuIA0KDQotIE5haXZlIEJheWVz66W8IOyCrOyaqe2WiOydhCDrlYwsIGVycm9yIHJhdGXqsIAg642UIOuGkuydgCDqsoPsnYAsIOuzgOyImOqwhCDrj4Xrpr3snYQg6rCA7KCV7ZWY64qUIOqzvOygleyXkCDsoJXrs7TqsIAg7IaQ7Iuk65CY7Ja0IOyDneq4tCDqsoPsnbwg7IiYIOyeiOydhOqxsOudvCDstpTsuKHtlbTrs7jri6QuIA0KDQo8YnIvPg0KDQoNCg0KIyBBcHBlbmRpeCAtIENvZGUNCg0KYGBge3IgZWNobz1UUlVFLCBldmFsPUZBTFNFLGluY2x1ZGU9VFJVRX0NCg0KIyMgLS0tLWluY2x1ZGU9RkFMU0UsIGVjaG89RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQprbml0cjo6b3B0c19jaHVuayRzZXQoY29tbWVudCA9ICIiLCBwcm9tcHQgPSBUUlVFLCBvdXQud2lkdGggPSA0MDAsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA0KQ0KbGlicmFyeShrbml0cikNClN5cy5zZXRsb2NhbGUoIkxDX0FMTCIsICJlbmciKQ0Kc2V0d2QoIkU6L0Ryb3Bib3gvMDAuMjAxOC8wMS4yMDE4XzFfc2VtZXN0ZXIvMDEuRGF0YU1pbmluZy8wNC5IVy9IVzMiKQ0KDQojIyAtLS0tZWNobz1GQUxTRS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmxpYnJhcnkoSVNMUikNCmRhdGEoRGVmYXVsdCkNCmthYmxlKGhlYWQoRGVmYXVsdCksIGNhcHRpb24gPSAiaGVhZChEZWZhdWx0KSIpDQpzdHIoRGVmYXVsdCkNCg0KIyMgLS0tLWVjaG89RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpsaWJyYXJ5KE1WTikNCmtzLnRlc3QoeCA9IHJub3JtKDEwIF4gNCksIERlZmF1bHQkYmFsYW5jZSwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIikNCmtzLnRlc3QoeCA9IHJub3JtKDEwIF4gNCksIERlZmF1bHQkaW5jb21lLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiKQ0KDQoNCiMjIC0tLS1lY2hvPUZBTFNFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpuIDwtIGRpbShEZWZhdWx0KVsxXQ0KDQp0YWJsZTEgPC0gYXJyYXkoTkEsIGMoMiwgMiwgMzApKQ0KZXJyb3IucmF0ZS5vZi5sZGEudnMgPC0gcmVwKE5BLCAzMCkNCg0KZm9yIChpIGluIDE6MzApIHsNCiAgc2V0LnNlZWQoaSkNCiAgdHJhaW4gPC0gc2FtcGxlKDE6biwgbiAvIDIpDQogIGRlZmF1bHQudHJhaW4gPC0gRGVmYXVsdFt0cmFpbiwgXQ0KICBkZWZhdWx0LnRlc3QgPC0gRGVmYXVsdFstdHJhaW4sIF0NCiAgZml0MiA8LSBsZGEoZGVmYXVsdH4gYmFsYW5jZSArIGluY29tZSwgZGF0YSA9IERlZmF1bHQsIHN1YnNldCA9IHRyYWluKQ0KICBwcmVkLmxkYSA8LSBwcmVkaWN0KGZpdDIsIERlZmF1bHRbLXRyYWluLCBdKSRjbGFzcw0KICB0YWJsZTFbLCAsIGldIDwtIHRhYmxlKHByZWQgPSBwcmVkLmxkYSwgdHJ1ZSA9IERlZmF1bHRbLXRyYWluLCAxXSkNCiAgZXJyb3IucmF0ZS5vZi5sZGEudnNbaV0gPC0gbWVhbihwcmVkLmxkYSAhPSBEZWZhdWx0Wy10cmFpbiwgMV0pDQp9DQoNCiMjIC0tLS1lY2hvPUZBTFNFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBhcHBseSh0YWJsZTEsMToyLG1lYW4pDQoNCnRtcDEgPC0gYXBwbHkodGFibGUsIDE6MiwgbWVhbikNCmRpbW5hbWVzKHRtcDEpIDwtIGxpc3QoYygiTm8iLCAiWWVzIiksIGMoIk5vIiwgIlllcyIpKQ0Ka2FibGUodG1wMSwgImh0bWwiLCBkaWdpdHMgPSAxKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRikNCg0KIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQptZWFuKGVycm9yLnJhdGUub2YubGRhLnZzKQ0KDQoNCiMjIC0tLS1lY2hvPUZBTFNFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KcGxvdCgNCiAgZXJyb3IucmF0ZS5vZi5sZGEudnMsIHR5cGUgPSAibCIsDQogIHlsaW0gPSBjKG1pbihlcnJvci5yYXRlLm9mLmxkYS52cykgKiAwLjksIG1heChlcnJvci5yYXRlLm9mLmxkYS52cykgKiAxLjEpLA0KICB5bGFiID0gIkVycm9yIFJhdGUiLA0KICB4bGFiID0gIksiDQopDQphYmxpbmUoaCA9IG1lYW4oZXJyb3IucmF0ZS5vZi5sZGEudnMpLCBsdHkgPSAyLCBjb2wgPSAyKQ0KDQojIyAtLS0tZWNobz1GQUxTRS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KdGFibGUyIDwtIGFycmF5KE5BLCBjKDIsIDIsIDMwKSkNCmVycm9yLnJhdGUub2YucWRhLnZzIDwtIHJlcChOQSwgMzApDQoNCmZvciAoaSBpbiAxOjMwKSB7DQogIHNldC5zZWVkKGkpDQogIHRyYWluIDwtIHNhbXBsZSgxOm4sIG4gLyAyKQ0KICBmaXQyIDwtIHFkYShkZWZhdWx0fiBiYWxhbmNlICsgaW5jb21lLCBkYXRhID0gRGVmYXVsdCwgc3Vic2V0ID0gdHJhaW4pDQogIHByZWQucWRhIDwtIHByZWRpY3QoZml0MiwgRGVmYXVsdFstdHJhaW4sIF0pJGNsYXNzDQogIHRhYmxlMlssICwgaV0gPC0gdGFibGUocHJlZCA9IHByZWQucWRhLCB0cnVlID0gRGVmYXVsdFstdHJhaW4sIDFdKQ0KICBlcnJvci5yYXRlLm9mLnFkYS52c1tpXSA8LSBtZWFuKHByZWQucWRhICE9IERlZmF1bHRbLXRyYWluLCAxXSkNCn0NCg0KIyMgLS0tLWVjaG89RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIGFwcGx5KHRhYmxlMiwxOjIsIG1lYW4pDQoNCnRtcDIgPC0gYXBwbHkodGFibGUyLCAxOjIsIG1lYW4pDQpkaW1uYW1lcyh0bXAyKSA8LSBsaXN0KGMoIk5vIiwgIlllcyIpLCBjKCJObyIsICJZZXMiKSkNCmthYmxlKHRtcDIsICJodG1sIiwgZGlnaXRzID0gMSkgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpDQoNCiMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KbWVhbihlcnJvci5yYXRlLm9mLnFkYS52cykNCg0KIyMgLS0tLWVjaG89RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpwbG90KA0KICBlcnJvci5yYXRlLm9mLnFkYS52cywgdHlwZSA9ICJsIiwNCiAgeWxpbSA9IGMobWluKGVycm9yLnJhdGUub2YucWRhLnZzKSAqIDAuOSwgbWF4KGVycm9yLnJhdGUub2YucWRhLnZzKSAqIDEuMSksDQogIHlsYWIgPSAiRXJyb3IgUmF0ZSIsDQogIHhsYWIgPSAiSyINCikNCmFibGluZShoID0gbWVhbihlcnJvci5yYXRlLm9mLnFkYS52cyksIGx0eSA9IDIsIGNvbCA9IDIpDQoNCiMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KWS5wcmVkLmxvb2N2IDwtIHJlcChOQSwgbikNCnBwcm9iIDwtIHRtcC5jdi5sZGEkcG9zdGVyaW9yDQoNCmZvciAoaSBpbiAxOm4pIFkucHJlZC5sb29jdltpXSA8LSB3aGljaC5tYXgocHByb2JbaSwgXSkNClkuaGF0Lmxvb2N2IDwtIGNoYXJhY3RlcihsZW5ndGgoWS5wcmVkLmxvb2N2KSkNClkuaGF0Lmxvb2N2W1kucHJlZC5sb29jdiA9PSAxXSA8LSAiTm8iDQpZLmhhdC5sb29jdltZLnByZWQubG9vY3YgPT0gMl0gPC0gIlllcyINClkuaGF0Lmxvb2N2IDwtIGZhY3RvcihZLmhhdC5sb29jdiwgbGV2ZWxzID0gYygiTm8iLCAiWWVzIikpDQoNCmthYmxlKHRhYmxlKHByZWQgPSBZLmhhdC5sb29jdiwgdHJ1ZSA9IERlZmF1bHRbLCAxXSksICJodG1sIikgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpDQoNCiMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KbWVhbihZLmhhdC5sb29jdiAhPSBEZWZhdWx0WywgMV0pDQoNCiMjIC0tLS1lY2hvPUZBTFNFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KWS5wcmVkLmxvb2N2LnFkYSA8LSByZXAoTkEsIG4pDQpwcHJvYi5xZGEgPC0gdG1wLmN2LnFkYSRwb3N0ZXJpb3INCg0KZm9yIChpIGluIDE6bikgWS5wcmVkLmxvb2N2LnFkYVtpXSA8LSB3aGljaC5tYXgocHByb2IucWRhW2ksIF0pDQpZLmhhdC5sb29jdi5xZGEgPC0gY2hhcmFjdGVyKGxlbmd0aChZLnByZWQubG9vY3YucWRhKSkNClkuaGF0Lmxvb2N2LnFkYVtZLnByZWQubG9vY3YucWRhID09IDFdIDwtICJObyINClkuaGF0Lmxvb2N2LnFkYVtZLnByZWQubG9vY3YucWRhID09IDJdIDwtICJZZXMiDQoNCmthYmxlKHRhYmxlKHByZWQgPSBZLmhhdC5sb29jdi5xZGEsIHRydWUgPSBEZWZhdWx0WywgMV0pLCAiaHRtbCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGKQ0KDQojIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCm1lYW4oWS5oYXQubG9vY3YucWRhICE9IERlZmF1bHRbLCAxXSkNCg0KIyMgLS0tLWVjaG89RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEstZm9sZCBDVg0KSyA8LSAxMA0KaW5kIDwtICgxOm4pICUlIEsgKyAxDQpzZXQuc2VlZCgxICogaSkNCmZvbGRzIDwtIHNhbXBsZShpbmQsIG4pDQpwcmVkY3YgPC0gY2hhcmFjdGVyKG4pDQpmb3IgKGsgaW4gMTpLKSB7DQogIGZpdCA8LSBsZGEoZGVmYXVsdH5pbmNvbWUgKyBiYWxhbmNlLCBkYXRhID0gRGVmYXVsdCwgc3Vic2V0ID0gd2hpY2goaW5kICE9IGspKQ0KICBwcmVkY3ZbaW5kID09IGtdIDwtIGFzLmNoYXJhY3RlcihwcmVkaWN0KGZpdCwgRGVmYXVsdFtpbmQgPT0gaywgXSkkY2xhc3MpDQp9DQp0YWJsZS4xMGZvbGQubGRhIDwtIHRhYmxlKHByZWQgPSBwcmVkY3YsIHRydWUgPSBEZWZhdWx0WywgMV0pDQprYWJsZSh0YWJsZS4xMGZvbGQubGRhLCAiaHRtbCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGKQ0KDQoNCiMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KZXJyb3IucmF0ZS4xMGZvbGQgPC0gbWVhbihwcmVkY3YgIT0gRGVmYXVsdFssIDFdKQ0KZXJyb3IucmF0ZS4xMGZvbGQNCg0KIyMgLS0tLWVjaG89RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEstZm9sZCBDVg0KSyA8LSAxMA0KaW5kIDwtICgxOm4pICUlIEsgKyAxDQpzZXQuc2VlZCgxICogaSkNCmZvbGRzIDwtIHNhbXBsZShpbmQsIG4pDQpwcmVkY3YucWRhIDwtIGNoYXJhY3RlcihuKQ0KZm9yIChrIGluIDE6Sykgew0KICBmaXQgPC0gbGRhKGRlZmF1bHR+aW5jb21lICsgYmFsYW5jZSwgZGF0YSA9IERlZmF1bHQsIHN1YnNldCA9IHdoaWNoKGluZCAhPSBrKSkNCiAgcHJlZGN2LnFkYVtpbmQgPT0ga10gPC0gYXMuY2hhcmFjdGVyKHByZWRpY3QoZml0LCBEZWZhdWx0W2luZCA9PSBrLCBdKSRjbGFzcykNCn0NCnRhYmxlLjEwZm9sZC5xZGEgPC0gdGFibGUocHJlZCA9IHByZWRjdi5xZGEsIHRydWUgPSBEZWZhdWx0WywgMV0pDQprYWJsZSh0YWJsZS4xMGZvbGQucWRhLCAiaHRtbCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGKQ0KDQoNCiMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KZXJyb3IucmF0ZS4xMGZvbGQucWRhIDwtIG1lYW4ocHJlZGN2LnFkYSAhPSBEZWZhdWx0WywgMV0pDQplcnJvci5yYXRlLjEwZm9sZC5xZGENCg0KIyMgLS0tLWVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpsaWJyYXJ5KE1BU1MpDQpsaWJyYXJ5KG5haXZlYmF5ZXMpDQpsaWJyYXJ5KGUxMDcxKQ0KDQplcnJvci5yYXRlLm5iLnZzIDwtIHJlcChOQSwgMzApDQpuIDwtIGRpbShEZWZhdWx0KVsxXQ0KdGFibGUgPC0gYXJyYXkoTkEsIGMoMiwgMiwgMzApKQ0KDQpmb3IgKGkgaW4gMTozMCkgew0KICBzZXQuc2VlZChpKQ0KICB0cmFpbiA8LSBzYW1wbGUoMTpuLCBuIC8gMikNCiAgZml0Lm5iLnZzIDwtIG5haXZlQmF5ZXMoZGVmYXVsdCB+IC4sIGRhdGEgPSBEZWZhdWx0W3RyYWluLCBdKQ0KICBwcmVkLm5iLnZzIDwtIHByZWRpY3QoZml0Lm5iLnZzLCBuZXdkYXRhID0gRGVmYXVsdFstdHJhaW4sIF0pDQogIHRhYmxlWywgLCBpXSA8LSBhcy5tYXRyaXgodGFibGUocHJlZCA9IHByZWQubmIudnMsIHRydWUgPSBEZWZhdWx0Wy10cmFpbiwgMV0pKQ0KICBlcnJvci5yYXRlLm5iLnZzW2ldIDwtIG1lYW4ocHJlZDEgIT0gRGVmYXVsdFstdHJhaW4sIF0kZGVmYXVsdCkNCn0NCg0KDQojIyAtLS0tZWNobz1GQUxTRS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnRtcCA8LSBhcHBseSh0YWJsZSwgMToyLCBtZWFuKQ0KZGltbmFtZXModG1wKSA8LSBsaXN0KGMoIk5vIiwgIlllcyIpLCBjKCJObyIsICJZZXMiKSkNCmthYmxlKHRtcCwgImh0bWwiLCBkaWdpdHMgPSAxKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRikNCg0KIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQptZWFuKGVycm9yLnJhdGUubmIudnMpDQoNCiMjIC0tLS1lY2hvPUZBTFNFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KcGxvdCgNCiAgZXJyb3IucmF0ZS5uYi52cywgdHlwZSA9ICJsIiwNCiAgeWxpbSA9IGMobWluKGVycm9yLnJhdGUpICogMC45LCBtYXgoZXJyb3IucmF0ZSkgKiAxLjEpLA0KICB5bGFiID0gIkVycm9yIFJhdGUiLA0KICB4bGFiID0gIksiDQopDQphYmxpbmUoaCA9IG1lYW4oZXJyb3IucmF0ZSksIGx0eSA9IDIsIGNvbCA9IDIpDQoNCiMjIC0tLS1lY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpuIDwtIG5yb3coRGVmYXVsdCkNCmVycm9yLmxvb2N2IDwtIHZlY3Rvcihtb2RlID0gImxvZ2ljYWwiLCBuKQ0KcHJlZC5uYi5sb29jdiA8LSByZXAoTkEsIG4pDQoNCmZvciAoaSBpbiAxOm4pIHsNCiAgZml0Lmxvb2N2IDwtIG5haXZlQmF5ZXMoZGVmYXVsdCB+IC4sIGRhdGEgPSBEZWZhdWx0Wy1pLCBdKQ0KICBwcmVkMiA8LSBwcmVkaWN0KGZpdC5sb29jdiwgbmV3ZGF0YSA9IERlZmF1bHRbaSwgXSkNCiAgcHJlZC5uYi5sb29jdltpXSA8LSBhcy5jaGFyYWN0ZXIocHJlZDIpDQogIGVycm9yLmxvb2N2W2ldIDwtIChwcmVkMiAhPSBEZWZhdWx0W2ksIF0kZGVmYXVsdCkNCn0NCg0KDQojIyAtLS0tZWNobz1GQUxTRS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCnRhYi5sb29jdiA8LSB0YWJsZShwcmVkID0gcHJlZC5uYi5sb29jdiwgdHJ1ZSA9IERlZmF1bHRbLCAxXSkNCmthYmxlKHRhYi5sb29jdiwgImh0bWwiKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRikNCg0KIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCm1lYW4oZXJyb3IubG9vY3YpDQoNCiMjIC0tLS1lY2hvPUZBTFNFLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpsaWJyYXJ5KGxlYXBzKQ0KDQprIDwtIDEwDQplcnJvci5rZm9sZCA8LSByZXAoTkEsIGspDQpuIDwtIGRpbShEZWZhdWx0KVsxXQ0Kc2V0LnNlZWQoMSkNCg0KcHJlZC4xMGZvbGQgPC0gY2hhcmFjdGVyKG4pDQpmb2xkcyA8LSBzYW1wbGUoMTprLCBucm93KERlZmF1bHQpLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IHJlcCgxIC8gaywgaykpDQoNCmZvciAoaSBpbiAxOmspIHsNCiAgZml0LjEwZm9sZCA8LSBuYWl2ZV9iYXllcyhkZWZhdWx0IH4gLiwgZGF0YSA9IERlZmF1bHRbZm9sZHMgIT0gaSwgXSkNCiAgcHJlZC4xMGZvbGRbZm9sZHMgPT0gaV0gPC0gYXMuY2hhcmFjdGVyKHByZWRpY3QoZml0LjEwZm9sZCwgbmV3ZGF0YSA9IERlZmF1bHRbZm9sZHMgPT0gaSwgXSkpDQp9DQoNCg0KIyMgLS0tLWVjaG89RkFMU0UtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQp0YWIxIDwtIHRhYmxlKHByZWQgPSBwcmVkLjEwZm9sZCwgdHJ1ZSA9IERlZmF1bHRbLCAxXSkNCmthYmxlKHRhYjEsICJodG1sIikgJT4lDQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEYpDQoNCiMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KZXJyb3Iua2ZvbGQgPC0gcHJlZC4xMGZvbGQgIT0gRGVmYXVsdFssIDFdDQptZWFuKGVycm9yLmtmb2xkKQ0KDQoNCmBgYA==