Susmita Barua

Student, University of Chittagong

The ‘diabetes’ is a dataset that determines the outcome of the suspected patients based on several ‘features’ either as ‘No diabetes = 0’ or as ‘Diabetes = 1’.

nume_column = sapply(diabetes, is.numeric)
nume_column_name = names(nume_column)
nume_column_name
[1] "Pregnancies"              "Glucose"                  "BloodPressure"            "SkinThickness"           
[5] "Insulin"                  "BMI"                      "DiabetesPedigreeFunction" "Age"                     
[9] "Outcome"                 

There are total 9 numerical columns and 0 categorical column in the ‘diabetes’ dataset.The target variable of the dataset is the ‘Outcome’ column.

diabetes = read.csv('diabetes.csv')
diabetes

Basic Plot

a) Scatter plot

result_color = as.numeric(factor(diabetes$Outcome)) 
plot(diabetes$BMI, diabetes$Glucose, 
     col = result_color,
     pch = 20,
     xlab = substitute(paste(bold("BMI (kg/m^2)"))),
     ylab = substitute(paste(bold("Glucose (mmol/L)"))),
     main = 'BMI Vs Glucose',
     col.main = 'black',
     cex.main = 1.5
    ) 

The scatter plot represents the relationship between BMI and Glucose level of suspected diabetes patients. Each dot demonstrates the outcome as no diabetes (0) and diabetes(1) based on the two features.

b) Histogram Plot

hist(diabetes$Insulin,
     main = "Histogram plot of Insulin",
     col = "pink",
     xlab = "Insulin Level (IU/mL)")

The histogram is a graphical representation of the distribution of ‘diabetes’ dataset. Here, the x-axis represents insulin level range and the y-axis shows the frequency of individuals falling within each range.

c) Box Plot

boxplot(diabetes$Age,
        main = 'Box plot',
        col = 'aquamarine',
        xlab = substitute(paste(bold('Age'))),
        ylab = substitute(paste(bold('Years')))
)

The boxplot displays key statistics such as median, quartiles and potential outliers. This boxplot represents the age distribution of ‘diabetes’ dataset showing their maximum and minimum value within a certain range, the interquartile range with a line inside indicating the median age. The points beyond the maximum range are considered as outliers.

ggplot

a) Scatter Plot

library(ggplot2)

diabetes$Outcome = as.character(diabetes$Outcome)
ggplot(diabetes, aes(x = BMI, y = Glucose, color = Outcome)) + geom_point(size = 1.5) + 
  labs(title = 'BMI Vs Glucose (Using ggplot)',
       x = 'BMI (Kg/m^2)',
       y = 'Glucose (mmol/L)',
       caption = 'Source: Iskulghar') +
  scale_color_manual(values = c("0" = "maroon", "1" = "royalblue"))+
  theme_minimal() +
  theme(
    legend.position = "top",
    text = element_text(colour = 'darkslategray', size = 13), 
         )

The association between a suspected diabetes patient’s BMI and glucose level is shown in a scatter plot. Based on the two attributes, each dot represents the conclusion as either no diabetes (0) or diabetes (1).

b) Box Plot

diabetes$Outcome = as.character(diabetes$Outcome)
ggplot(diabetes, aes(x = Outcome, y = Pregnancies, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "Pregnancies",
       y = "value",
       caption = "Source: Iskulghar") +
  
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))


ggplot(diabetes, aes(x = Outcome, y = Glucose, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "Glucose",
       y = "value",
       caption = "Source: Iskulghar") +
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))


ggplot(diabetes, aes(x = Outcome, y = BloodPressure, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "BloodPressure",
       y = "value",
       caption = "Source: Iskulghar") +
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))


ggplot(diabetes, aes(x = Outcome, y = SkinThickness, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "SkinThickness",
       y = "value",
       caption = "Source: Iskulghar") +
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))


ggplot(diabetes, aes(x = Outcome, y = Insulin, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "Insulin",
       y = "value",
       caption = "Source: Iskulghar") +
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))


ggplot(diabetes, aes(x = Outcome, y = BMI, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "BMI",
       y = "value",
       caption = "Source: Iskulghar") +
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))


ggplot(diabetes, aes(x = Outcome, y = DiabetesPedigreeFunction, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "DiabetesPedigreeFunction",
       y = "value",
       caption = "Source: Iskulghar") +
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))


ggplot(diabetes, aes(x = Outcome, y = Age, fill = Outcome)) +
geom_boxplot() +

  labs(title = "Bloxplot using ggplot",
       x = "Age",
       y = "value",
       caption = "Source: Iskulghar") +
  theme(
    legend.position = "top", 
    text = element_text(colour = 'black', size = 14))

The interquartile range, which includes a line representing the median age, is used to illustrate the distribution of the all columns of “diabetes” dataset. It also shows the maximum and minimum values within that range. Any point that falls outside of the range are considered as outliers.

Interactive violin plot

library(plotly)
plot_ly(data= diabetes, x = ~Outcome, y = ~Pregnancies, type = 'violin') 
library(plotly)
plot_ly(data= diabetes, x = ~Outcome, y = ~Glucose, type = 'violin') 
library(plotly)
plot_ly(data= diabetes, x = ~Outcome, y = ~BloodPressure, type = 'violin') 
library(plotly)
plot_ly(data= diabetes, x = ~Outcome, y = ~Insulin, type = 'violin') 
library(plotly)
plot_ly(data= diabetes, x = ~Outcome, y = ~BMI, type = 'violin') 
library(plotly)
plot_ly(data= diabetes, x = ~Outcome, y = ~DiabetesPedigreeFunction, type = 'violin') 
library(plotly)
plot_ly(data= diabetes, x = ~Outcome, y = ~BMI, type = 'violin')
library(plotly)
plot_ly(data = diabetes, x = ~Outcome, y = ~Pregnancies, type = 'box')
library(plotly)
plot_ly(data = diabetes, x = ~Outcome, y = ~Glucose, type = 'box')
library(plotly)
plot_ly(data = diabetes, x = ~Outcome, y = ~BloodPressure, type = 'box')
library(plotly)
plot_ly(data = diabetes, x = ~Outcome, y = ~Insulin, type = 'box')
library(plotly)
plot_ly(data = diabetes, x = ~Outcome, y = ~BMI, type = 'box')
library(plotly)
plot_ly(data = diabetes, x = ~Outcome, y = ~DiabetesPedigreeFunction, type = 'box')
library(plotly)
plot_ly(data = diabetes, x = ~Outcome, y = ~Age, type = 'box')

Correlation matrix

cor_matrix = cor(diabetes[ ,1:8])
print(cor_matrix)
                         Pregnancies    Glucose BloodPressure SkinThickness     Insulin        BMI DiabetesPedigreeFunction
Pregnancies               1.00000000 0.12945867    0.14128198   -0.08167177 -0.07353461 0.01768309              -0.03352267
Glucose                   0.12945867 1.00000000    0.15258959    0.05732789  0.33135711 0.22107107               0.13733730
BloodPressure             0.14128198 0.15258959    1.00000000    0.20737054  0.08893338 0.28180529               0.04126495
SkinThickness            -0.08167177 0.05732789    0.20737054    1.00000000  0.43678257 0.39257320               0.18392757
Insulin                  -0.07353461 0.33135711    0.08893338    0.43678257  1.00000000 0.19785906               0.18507093
BMI                       0.01768309 0.22107107    0.28180529    0.39257320  0.19785906 1.00000000               0.14064695
DiabetesPedigreeFunction -0.03352267 0.13733730    0.04126495    0.18392757  0.18507093 0.14064695               1.00000000
Age                       0.54434123 0.26351432    0.23952795   -0.11397026 -0.04216295 0.03624187               0.03356131
                                 Age
Pregnancies               0.54434123
Glucose                   0.26351432
BloodPressure             0.23952795
SkinThickness            -0.11397026
Insulin                  -0.04216295
BMI                       0.03624187
DiabetesPedigreeFunction  0.03356131
Age                       1.00000000

Correlation matrix plot

library(ggcorrplot)
ggcorrplot(cor_matrix, 
               type = "lower",
               colors = c("blue", "white", "maroon"),
               lab = TRUE)

Pair plot

library(GGally)
ggpairs(diabetes, aes(colour = Outcome))

PCA

library(stats)

diabetes_pca = prcomp(diabetes[ , -9], scale = TRUE, center = TRUE)
diabetes_pca
Standard deviations (1, .., p=8):
[1] 1.4471973 1.3157546 1.0147068 0.9356971 0.8731234 0.8262133 0.6479322 0.6359733

Rotation (n x k) = (8 x 8):
                                PC1        PC2         PC3         PC4        PC5          PC6         PC7          PC8
Pregnancies              -0.1284321  0.5937858 -0.01308692  0.08069115 -0.4756057  0.193598168 -0.58879003 -0.117840984
Glucose                  -0.3930826  0.1740291  0.46792282 -0.40432871  0.4663280  0.094161756 -0.06015291 -0.450355256
BloodPressure            -0.3600026  0.1838921 -0.53549442  0.05598649  0.3279531 -0.634115895 -0.19211793  0.011295538
SkinThickness            -0.4398243 -0.3319653 -0.23767380  0.03797608 -0.4878621  0.009589438  0.28221253 -0.566283799
Insulin                  -0.4350262 -0.2507811  0.33670893 -0.34994376 -0.3469348 -0.270650609 -0.13200992  0.548621381
BMI                      -0.4519413 -0.1009598 -0.36186463  0.05364595  0.2532038  0.685372179 -0.03536644  0.341517637
DiabetesPedigreeFunction -0.2706114 -0.1220690  0.43318905  0.83368010  0.1198105 -0.085784088 -0.08609107  0.008258731
Age                      -0.1980271  0.6205885  0.07524755  0.07120060 -0.1092900 -0.033357170  0.71208542  0.211661979
pca_12 = data.frame(diabetes_pca$x[ , 1:2])
head(pca_12)
pca_12_out = cbind(pca_12, Outcome = diabetes$Outcome)
pca_12_out

Bar plot of PCAs

library(factoextra)
fviz_eig(diabetes_pca, addlabels = TRUE)

Contribution plot (Circular plot)

fviz_pca_var(diabetes_pca, col.var = "contrib")

Contribution plot as heatmap

library("corrplot")
var = get_pca_var(diabetes_pca)
corrplot(var$cos2)

Cluster plot

fviz_pca_ind(diabetes_pca,
             geom.ind = "point",
             col.ind = diabetes$Outcome,
             addEllipses = TRUE)

SVM Model

library(lattice)
library(e1071)
library(caret)

train_ix = createDataPartition(diabetes$Outcome, p = 0.8, list = FALSE)
train_data = diabetes[train_ix, ]
test_data = diabetes[-train_ix, ]

train_data
test_data

diabetes$Outcome = as.factor(diabetes$Outcome)
svm_model = svm(Outcome ~ Pregnancies+Glucose+BloodPressure+SkinThickness+Insulin+BMI+DiabetesPedigreeFunction
+Age, data = train_data, kernel = "linear")
test_data[2, ]
predict(svm_model, newdata = test_data[2, -9])
5 
1 
Levels: 0 1

Confusion matrix

predictions = predict(svm_model, newdata = test_data)
confusion_mat = confusionMatrix(predictions, test_data$Outcome)
confusion_mat
Confusion Matrix and Statistics

          Reference
Prediction  0  1
         0 87 21
         1 13 32
                                          
               Accuracy : 0.7778          
                 95% CI : (0.7036, 0.8409)
    No Information Rate : 0.6536          
    P-Value [Acc > NIR] : 0.000586        
                                          
                  Kappa : 0.4912          
                                          
 Mcnemar's Test P-Value : 0.229949        
                                          
            Sensitivity : 0.8700          
            Specificity : 0.6038          
         Pos Pred Value : 0.8056          
         Neg Pred Value : 0.7111          
             Prevalence : 0.6536          
         Detection Rate : 0.5686          
   Detection Prevalence : 0.7059          
      Balanced Accuracy : 0.7369          
                                          
       'Positive' Class : 0               
                                          
com = as.data.frame(confusion_mat$table)

ggplot(com, aes(Prediction, Reference, fill = Freq)) + 
  geom_tile() +
  geom_text(aes(label = Freq)) + 
  scale_fill_gradient(low="navy", high="aquamarine")

US Admission dataset

us_ad = read.csv('US Admission.csv')
us_ad

Removal of Serial.No column

us_ad_new = us_ad[ ,-1]
us_ad_new

Pair plot

library(GGally)
ggpairs(us_ad_new, cardinality_threshold = NULL ) 

Linear regression

x = us_ad_new$GRE.Score
y = us_ad_new$Chance.of.Admit

plot(x~y, xlab = "Chance of Admission", ylab = "GRE Score", main = "Linear Regression of GRE Score and Chance of Admission", pch = 20, col = 'blue')


x = us_ad_new$TOEFL.Score
y = us_ad_new$Chance.of.Admit

plot(x~y, xlab = "Chance of Admission", ylab = "TOEFL Score", main = "Linear Regression of TOEFL Score and Chance of Admission", pch = 20, col = 'red')


x = us_ad_new$University.Rating
y = us_ad_new$Chance.of.Admit

plot(x~y, xlab = "Chance of Admission", ylab = "University Rating", main = "Linear Regression of University Rating and Chance of Admission", pch = 20, col = 'purple')


x = us_ad_new$SOP
y = us_ad_new$Chance.of.Admit

plot(x~y, xlab = "Chance of Admission", ylab = "SOP", main = "Linear Regression of SOP and Chance of Admission", pch = 20, col = 'maroon')


x = us_ad_new$LOR
y = us_ad_new$Chance.of.Admit

plot(x~y, xlab = "Chance of Admission", ylab = "LOR", main = "Linear Regression of LOR and Chance of Admission", pch = 20, col = 'navy')


x = us_ad_new$CGPA
y = us_ad_new$Chance.of.Admit

plot(x~y, xlab = "Chance of Admission", ylab = "CGPA", main = "Linear Regression of CGPA and Chance of Admission", pch = 20, col = 'brown')


x = us_ad_new$Research
y = us_ad_new$Chance.of.Admit

plot(x~y, xlab = "Chance of Admission", ylab = "Research", main = "Linear Regression of Research and Chance of Admission", pch = 20, col = 'black')

Polynomial regression

library(ggplot2)
ggplot(us_ad_new, aes(x = GRE.Score, y = TOEFL.Score), color = Chance.of.Admit ) + 
  geom_point() +
  geom_smooth(method = "lm", formula = y~poly(x, 2), level = 0.95) +
  theme_minimal()


ggplot(us_ad_new, aes(x = GRE.Score, y =University.Rating), color = Chance.of.Admit ) + 
  geom_point() +
  geom_smooth(method = "lm", formula = y~poly(x, 2), level = 0.95) +
  theme_minimal()


ggplot(us_ad_new, aes(x = GRE.Score, y = SOP), color = Chance.of.Admit ) + 
  geom_point() +
  geom_smooth(method = "lm", formula = y~poly(x, 2), level = 0.95) +
  theme_minimal()


ggplot(us_ad_new, aes(x = GRE.Score, y = LOR), color = Chance.of.Admit ) + 
  geom_point() +
  geom_smooth(method = "lm", formula = y~poly(x, 2), level = 0.95) +
  theme_minimal()


ggplot(us_ad_new, aes(x = GRE.Score, y = CGPA), color = Chance.of.Admit ) + 
  geom_point() +
  geom_smooth(method = "lm", formula = y~poly(x, 2), level = 0.95) +
  theme_minimal()


ggplot(us_ad_new, aes(x = GRE.Score, y = Research), color = Chance.of.Admit ) + 
  geom_point() +
  geom_smooth(method = "lm", formula = y~poly(x, 2), level = 0.95) +
  theme_minimal()

Regression model

library(datasets)
data(us_ad_new)
Warning: data set ‘us_ad_new’ not found
lm_model = lm(Chance.of.Admit ~ GRE.Score+TOEFL.Score+University.Rating+SOP+LOR+CGPA+Research, data = us_ad_new)
summary(lm_model)

Call:
lm(formula = Chance.of.Admit ~ GRE.Score + TOEFL.Score + University.Rating + 
    SOP + LOR + CGPA + Research, data = us_ad_new)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.26259 -0.02103  0.01005  0.03628  0.15928 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -1.2594325  0.1247307 -10.097  < 2e-16 ***
GRE.Score          0.0017374  0.0005979   2.906  0.00387 ** 
TOEFL.Score        0.0029196  0.0010895   2.680  0.00768 ** 
University.Rating  0.0057167  0.0047704   1.198  0.23150    
SOP               -0.0033052  0.0055616  -0.594  0.55267    
LOR                0.0223531  0.0055415   4.034  6.6e-05 ***
CGPA               0.1189395  0.0122194   9.734  < 2e-16 ***
Research           0.0245251  0.0079598   3.081  0.00221 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06378 on 392 degrees of freedom
Multiple R-squared:  0.8035,    Adjusted R-squared:    0.8 
F-statistic: 228.9 on 7 and 392 DF,  p-value: < 2.2e-16
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIFN1c21pdGEgQmFydWENCiMjIFN0dWRlbnQsIFVuaXZlcnNpdHkgb2YgQ2hpdHRhZ29uZw0KDQoNCiMjIFRoZSAnZGlhYmV0ZXMnIGlzIGEgZGF0YXNldCB0aGF0IGRldGVybWluZXMgdGhlIG91dGNvbWUgb2YgdGhlIHN1c3BlY3RlZCBwYXRpZW50cyBiYXNlZCBvbiBzZXZlcmFsICdmZWF0dXJlcycgZWl0aGVyIGFzICdObyBkaWFiZXRlcyA9IDAnIG9yIGFzICdEaWFiZXRlcyA9IDEnLiANCg0KYGBge3J9DQpudW1lX2NvbHVtbiA9IHNhcHBseShkaWFiZXRlcywgaXMubnVtZXJpYykNCm51bWVfY29sdW1uX25hbWUgPSBuYW1lcyhudW1lX2NvbHVtbikNCm51bWVfY29sdW1uX25hbWUNCmBgYA0KDQojIyBUaGVyZSBhcmUgdG90YWwgOSBudW1lcmljYWwgY29sdW1ucyBhbmQgMCBjYXRlZ29yaWNhbCBjb2x1bW4gaW4gdGhlICdkaWFiZXRlcycgZGF0YXNldC5UaGUgdGFyZ2V0IHZhcmlhYmxlIG9mIHRoZSBkYXRhc2V0IGlzIHRoZSAnT3V0Y29tZScgY29sdW1uLg0KDQpgYGB7cn0NCmRpYWJldGVzID0gcmVhZC5jc3YoJ2RpYWJldGVzLmNzdicpDQpkaWFiZXRlcw0KYGBgDQojIEJhc2ljIFBsb3QNCg0KIyMgYSkgU2NhdHRlciBwbG90DQoNCmBgYHtyfQ0KcmVzdWx0X2NvbG9yID0gYXMubnVtZXJpYyhmYWN0b3IoZGlhYmV0ZXMkT3V0Y29tZSkpIA0KcGxvdChkaWFiZXRlcyRCTUksIGRpYWJldGVzJEdsdWNvc2UsIA0KICAgICBjb2wgPSByZXN1bHRfY29sb3IsDQogICAgIHBjaCA9IDIwLA0KICAgICB4bGFiID0gc3Vic3RpdHV0ZShwYXN0ZShib2xkKCJCTUkgKGtnL21eMikiKSkpLA0KICAgICB5bGFiID0gc3Vic3RpdHV0ZShwYXN0ZShib2xkKCJHbHVjb3NlIChtbW9sL0wpIikpKSwNCiAgICAgbWFpbiA9ICdCTUkgVnMgR2x1Y29zZScsDQogICAgIGNvbC5tYWluID0gJ2JsYWNrJywNCiAgICAgY2V4Lm1haW4gPSAxLjUNCiAgICApIA0KYGBgDQojIyBUaGUgc2NhdHRlciBwbG90IHJlcHJlc2VudHMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIEJNSSBhbmQgR2x1Y29zZSBsZXZlbCBvZiBzdXNwZWN0ZWQgZGlhYmV0ZXMgcGF0aWVudHMuIEVhY2ggZG90IGRlbW9uc3RyYXRlcyB0aGUgb3V0Y29tZSBhcyBubyBkaWFiZXRlcyAoMCkgYW5kIGRpYWJldGVzKDEpIGJhc2VkIG9uIHRoZSB0d28gZmVhdHVyZXMuDQoNCiMjIGIpIEhpc3RvZ3JhbSBQbG90DQoNCmBgYHtyfQ0KaGlzdChkaWFiZXRlcyRJbnN1bGluLA0KICAgICBtYWluID0gIkhpc3RvZ3JhbSBwbG90IG9mIEluc3VsaW4iLA0KICAgICBjb2wgPSAicGluayIsDQogICAgIHhsYWIgPSAiSW5zdWxpbiBMZXZlbCAoSVUvbUwpIikNCmBgYA0KIyMgVGhlIGhpc3RvZ3JhbSBpcyBhIGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGlzdHJpYnV0aW9uIG9mICdkaWFiZXRlcycgZGF0YXNldC4gSGVyZSwgdGhlIHgtYXhpcyByZXByZXNlbnRzIGluc3VsaW4gbGV2ZWwgcmFuZ2UgYW5kIHRoZSB5LWF4aXMgc2hvd3MgdGhlIGZyZXF1ZW5jeSBvZiBpbmRpdmlkdWFscyBmYWxsaW5nIHdpdGhpbiBlYWNoIHJhbmdlLg0KDQojIyBjKSBCb3ggUGxvdA0KYGBge3J9DQpib3hwbG90KGRpYWJldGVzJEFnZSwNCiAgICAgICAgbWFpbiA9ICdCb3ggcGxvdCcsDQogICAgICAgIGNvbCA9ICdhcXVhbWFyaW5lJywNCiAgICAgICAgeGxhYiA9IHN1YnN0aXR1dGUocGFzdGUoYm9sZCgnQWdlJykpKSwNCiAgICAgICAgeWxhYiA9IHN1YnN0aXR1dGUocGFzdGUoYm9sZCgnWWVhcnMnKSkpDQopDQpgYGANCiMjIFRoZSBib3hwbG90IGRpc3BsYXlzIGtleSBzdGF0aXN0aWNzIHN1Y2ggYXMgbWVkaWFuLCBxdWFydGlsZXMgYW5kIHBvdGVudGlhbCBvdXRsaWVycy4gVGhpcyBib3hwbG90IHJlcHJlc2VudHMgdGhlIGFnZSBkaXN0cmlidXRpb24gb2YgJ2RpYWJldGVzJyBkYXRhc2V0IHNob3dpbmcgdGhlaXIgbWF4aW11bSBhbmQgbWluaW11bSB2YWx1ZSB3aXRoaW4gYSBjZXJ0YWluIHJhbmdlLCB0aGUgaW50ZXJxdWFydGlsZSByYW5nZSB3aXRoICBhIGxpbmUgaW5zaWRlIGluZGljYXRpbmcgdGhlIG1lZGlhbiBhZ2UuIFRoZSBwb2ludHMgYmV5b25kIHRoZSBtYXhpbXVtIHJhbmdlIGFyZSBjb25zaWRlcmVkIGFzIG91dGxpZXJzLg0KDQojIGdncGxvdA0KDQojIyBhKSBTY2F0dGVyIFBsb3QNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpkaWFiZXRlcyRPdXRjb21lID0gYXMuY2hhcmFjdGVyKGRpYWJldGVzJE91dGNvbWUpDQpnZ3Bsb3QoZGlhYmV0ZXMsIGFlcyh4ID0gQk1JLCB5ID0gR2x1Y29zZSwgY29sb3IgPSBPdXRjb21lKSkgKyBnZW9tX3BvaW50KHNpemUgPSAxLjUpICsgDQogIGxhYnModGl0bGUgPSAnQk1JIFZzIEdsdWNvc2UgKFVzaW5nIGdncGxvdCknLA0KICAgICAgIHggPSAnQk1JIChLZy9tXjIpJywNCiAgICAgICB5ID0gJ0dsdWNvc2UgKG1tb2wvTCknLA0KICAgICAgIGNhcHRpb24gPSAnU291cmNlOiBJc2t1bGdoYXInKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwIiA9ICJtYXJvb24iLCAiMSIgPSAicm95YWxibHVlIikpKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwNCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdkYXJrc2xhdGVncmF5Jywgc2l6ZSA9IDEzKSwgDQogICAgICAgICApDQpgYGANCiMjIFRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIGEgc3VzcGVjdGVkIGRpYWJldGVzIHBhdGllbnQncyBCTUkgYW5kIGdsdWNvc2UgbGV2ZWwgaXMgc2hvd24gaW4gYSBzY2F0dGVyIHBsb3QuIEJhc2VkIG9uIHRoZSB0d28gYXR0cmlidXRlcywgZWFjaCBkb3QgcmVwcmVzZW50cyB0aGUgY29uY2x1c2lvbiBhcyBlaXRoZXIgbm8gZGlhYmV0ZXMgKDApIG9yIGRpYWJldGVzICgxKS4NCg0KIyMgYikgQm94IFBsb3QNCmBgYHtyfQ0KZGlhYmV0ZXMkT3V0Y29tZSA9IGFzLmNoYXJhY3RlcihkaWFiZXRlcyRPdXRjb21lKQ0KZ2dwbG90KGRpYWJldGVzLCBhZXMoeCA9IE91dGNvbWUsIHkgPSBQcmVnbmFuY2llcywgZmlsbCA9IE91dGNvbWUpKSArDQpnZW9tX2JveHBsb3QoKSArDQoNCiAgbGFicyh0aXRsZSA9ICJCbG94cGxvdCB1c2luZyBnZ3Bsb3QiLA0KICAgICAgIHggPSAiUHJlZ25hbmNpZXMiLA0KICAgICAgIHkgPSAidmFsdWUiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBJc2t1bGdoYXIiKSArDQogIA0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgDQogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAnYmxhY2snLCBzaXplID0gMTQpKQ0KDQpnZ3Bsb3QoZGlhYmV0ZXMsIGFlcyh4ID0gT3V0Y29tZSwgeSA9IEdsdWNvc2UsIGZpbGwgPSBPdXRjb21lKSkgKw0KZ2VvbV9ib3hwbG90KCkgKw0KDQogIGxhYnModGl0bGUgPSAiQmxveHBsb3QgdXNpbmcgZ2dwbG90IiwNCiAgICAgICB4ID0gIkdsdWNvc2UiLA0KICAgICAgIHkgPSAidmFsdWUiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBJc2t1bGdoYXIiKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCANCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdibGFjaycsIHNpemUgPSAxNCkpDQoNCmdncGxvdChkaWFiZXRlcywgYWVzKHggPSBPdXRjb21lLCB5ID0gQmxvb2RQcmVzc3VyZSwgZmlsbCA9IE91dGNvbWUpKSArDQpnZW9tX2JveHBsb3QoKSArDQoNCiAgbGFicyh0aXRsZSA9ICJCbG94cGxvdCB1c2luZyBnZ3Bsb3QiLA0KICAgICAgIHggPSAiQmxvb2RQcmVzc3VyZSIsDQogICAgICAgeSA9ICJ2YWx1ZSIsDQogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IElza3VsZ2hhciIpICsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIA0KICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gJ2JsYWNrJywgc2l6ZSA9IDE0KSkNCg0KZ2dwbG90KGRpYWJldGVzLCBhZXMoeCA9IE91dGNvbWUsIHkgPSBTa2luVGhpY2tuZXNzLCBmaWxsID0gT3V0Y29tZSkpICsNCmdlb21fYm94cGxvdCgpICsNCg0KICBsYWJzKHRpdGxlID0gIkJsb3hwbG90IHVzaW5nIGdncGxvdCIsDQogICAgICAgeCA9ICJTa2luVGhpY2tuZXNzIiwNCiAgICAgICB5ID0gInZhbHVlIiwNCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogSXNrdWxnaGFyIikgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgDQogICAgdGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAnYmxhY2snLCBzaXplID0gMTQpKQ0KDQpnZ3Bsb3QoZGlhYmV0ZXMsIGFlcyh4ID0gT3V0Y29tZSwgeSA9IEluc3VsaW4sIGZpbGwgPSBPdXRjb21lKSkgKw0KZ2VvbV9ib3hwbG90KCkgKw0KDQogIGxhYnModGl0bGUgPSAiQmxveHBsb3QgdXNpbmcgZ2dwbG90IiwNCiAgICAgICB4ID0gIkluc3VsaW4iLA0KICAgICAgIHkgPSAidmFsdWUiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBJc2t1bGdoYXIiKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCANCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdibGFjaycsIHNpemUgPSAxNCkpDQoNCmdncGxvdChkaWFiZXRlcywgYWVzKHggPSBPdXRjb21lLCB5ID0gQk1JLCBmaWxsID0gT3V0Y29tZSkpICsNCmdlb21fYm94cGxvdCgpICsNCg0KICBsYWJzKHRpdGxlID0gIkJsb3hwbG90IHVzaW5nIGdncGxvdCIsDQogICAgICAgeCA9ICJCTUkiLA0KICAgICAgIHkgPSAidmFsdWUiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBJc2t1bGdoYXIiKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCANCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdibGFjaycsIHNpemUgPSAxNCkpDQoNCmdncGxvdChkaWFiZXRlcywgYWVzKHggPSBPdXRjb21lLCB5ID0gRGlhYmV0ZXNQZWRpZ3JlZUZ1bmN0aW9uLCBmaWxsID0gT3V0Y29tZSkpICsNCmdlb21fYm94cGxvdCgpICsNCg0KICBsYWJzKHRpdGxlID0gIkJsb3hwbG90IHVzaW5nIGdncGxvdCIsDQogICAgICAgeCA9ICJEaWFiZXRlc1BlZGlncmVlRnVuY3Rpb24iLA0KICAgICAgIHkgPSAidmFsdWUiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBJc2t1bGdoYXIiKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCANCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdibGFjaycsIHNpemUgPSAxNCkpDQoNCmdncGxvdChkaWFiZXRlcywgYWVzKHggPSBPdXRjb21lLCB5ID0gQWdlLCBmaWxsID0gT3V0Y29tZSkpICsNCmdlb21fYm94cGxvdCgpICsNCg0KICBsYWJzKHRpdGxlID0gIkJsb3hwbG90IHVzaW5nIGdncGxvdCIsDQogICAgICAgeCA9ICJBZ2UiLA0KICAgICAgIHkgPSAidmFsdWUiLA0KICAgICAgIGNhcHRpb24gPSAiU291cmNlOiBJc2t1bGdoYXIiKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCANCiAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdibGFjaycsIHNpemUgPSAxNCkpDQpgYGANCg0KIyMgVGhlIGludGVycXVhcnRpbGUgcmFuZ2UsIHdoaWNoIGluY2x1ZGVzIGEgbGluZSByZXByZXNlbnRpbmcgdGhlIG1lZGlhbiBhZ2UsIGlzIHVzZWQgdG8gaWxsdXN0cmF0ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBhbGwgY29sdW1ucyBvZiAiZGlhYmV0ZXMiIGRhdGFzZXQuIEl0IGFsc28gc2hvd3MgdGhlIG1heGltdW0gYW5kIG1pbmltdW0gdmFsdWVzIHdpdGhpbiB0aGF0IHJhbmdlLiBBbnkgcG9pbnQgdGhhdCBmYWxscyBvdXRzaWRlIG9mIHRoZSByYW5nZSBhcmUgY29uc2lkZXJlZCBhcyBvdXRsaWVycy4NCg0KIyMgSW50ZXJhY3RpdmUgdmlvbGluIHBsb3QNCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQpwbG90X2x5KGRhdGE9IGRpYWJldGVzLCB4ID0gfk91dGNvbWUsIHkgPSB+UHJlZ25hbmNpZXMsIHR5cGUgPSAndmlvbGluJykgDQpgYGANCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQpwbG90X2x5KGRhdGE9IGRpYWJldGVzLCB4ID0gfk91dGNvbWUsIHkgPSB+R2x1Y29zZSwgdHlwZSA9ICd2aW9saW4nKSANCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHBsb3RseSkNCnBsb3RfbHkoZGF0YT0gZGlhYmV0ZXMsIHggPSB+T3V0Y29tZSwgeSA9IH5CbG9vZFByZXNzdXJlLCB0eXBlID0gJ3Zpb2xpbicpIA0KYGBgDQpgYGB7cn0NCmxpYnJhcnkocGxvdGx5KQ0KcGxvdF9seShkYXRhPSBkaWFiZXRlcywgeCA9IH5PdXRjb21lLCB5ID0gfkluc3VsaW4sIHR5cGUgPSAndmlvbGluJykgDQpgYGANCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQpwbG90X2x5KGRhdGE9IGRpYWJldGVzLCB4ID0gfk91dGNvbWUsIHkgPSB+Qk1JLCB0eXBlID0gJ3Zpb2xpbicpIA0KYGBgDQpgYGB7cn0NCmxpYnJhcnkocGxvdGx5KQ0KcGxvdF9seShkYXRhPSBkaWFiZXRlcywgeCA9IH5PdXRjb21lLCB5ID0gfkRpYWJldGVzUGVkaWdyZWVGdW5jdGlvbiwgdHlwZSA9ICd2aW9saW4nKSANCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHBsb3RseSkNCnBsb3RfbHkoZGF0YT0gZGlhYmV0ZXMsIHggPSB+T3V0Y29tZSwgeSA9IH5CTUksIHR5cGUgPSAndmlvbGluJykNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQpwbG90X2x5KGRhdGEgPSBkaWFiZXRlcywgeCA9IH5PdXRjb21lLCB5ID0gflByZWduYW5jaWVzLCB0eXBlID0gJ2JveCcpDQpgYGANCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQpwbG90X2x5KGRhdGEgPSBkaWFiZXRlcywgeCA9IH5PdXRjb21lLCB5ID0gfkdsdWNvc2UsIHR5cGUgPSAnYm94JykNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHBsb3RseSkNCnBsb3RfbHkoZGF0YSA9IGRpYWJldGVzLCB4ID0gfk91dGNvbWUsIHkgPSB+Qmxvb2RQcmVzc3VyZSwgdHlwZSA9ICdib3gnKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkocGxvdGx5KQ0KcGxvdF9seShkYXRhID0gZGlhYmV0ZXMsIHggPSB+T3V0Y29tZSwgeSA9IH5JbnN1bGluLCB0eXBlID0gJ2JveCcpDQpgYGANCmBgYHtyfQ0KbGlicmFyeShwbG90bHkpDQpwbG90X2x5KGRhdGEgPSBkaWFiZXRlcywgeCA9IH5PdXRjb21lLCB5ID0gfkJNSSwgdHlwZSA9ICdib3gnKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkocGxvdGx5KQ0KcGxvdF9seShkYXRhID0gZGlhYmV0ZXMsIHggPSB+T3V0Y29tZSwgeSA9IH5EaWFiZXRlc1BlZGlncmVlRnVuY3Rpb24sIHR5cGUgPSAnYm94JykNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHBsb3RseSkNCnBsb3RfbHkoZGF0YSA9IGRpYWJldGVzLCB4ID0gfk91dGNvbWUsIHkgPSB+QWdlLCB0eXBlID0gJ2JveCcpDQpgYGANCg0KIyMgQ29ycmVsYXRpb24gbWF0cml4DQpgYGB7cn0NCmNvcl9tYXRyaXggPSBjb3IoZGlhYmV0ZXNbICwxOjhdKQ0KcHJpbnQoY29yX21hdHJpeCkNCmBgYA0KIyMgQ29ycmVsYXRpb24gbWF0cml4IHBsb3QNCmBgYHtyfQ0KbGlicmFyeShnZ2NvcnJwbG90KQ0KZ2djb3JycGxvdChjb3JfbWF0cml4LCANCgkgICAgICAgICAgIHR5cGUgPSAibG93ZXIiLA0KCSAgICAgICAgICAgY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJtYXJvb24iKSwNCgkgICAgICAgICAgIGxhYiA9IFRSVUUpDQpgYGANCg0KIyMgUGFpciBwbG90DQpgYGB7cn0NCmxpYnJhcnkoR0dhbGx5KQ0KZ2dwYWlycyhkaWFiZXRlcywgYWVzKGNvbG91ciA9IE91dGNvbWUpKQ0KYGBgDQoNCiMjIFBDQQ0KYGBge3J9DQpsaWJyYXJ5KHN0YXRzKQ0KDQpkaWFiZXRlc19wY2EgPSBwcmNvbXAoZGlhYmV0ZXNbICwgLTldLCBzY2FsZSA9IFRSVUUsIGNlbnRlciA9IFRSVUUpDQpkaWFiZXRlc19wY2ENCmBgYA0KYGBge3J9DQpwY2FfMTIgPSBkYXRhLmZyYW1lKGRpYWJldGVzX3BjYSR4WyAsIDE6Ml0pDQpoZWFkKHBjYV8xMikNCmBgYA0KYGBge3J9DQpwY2FfMTJfb3V0ID0gY2JpbmQocGNhXzEyLCBPdXRjb21lID0gZGlhYmV0ZXMkT3V0Y29tZSkNCnBjYV8xMl9vdXQNCmBgYA0KIyMgQmFyIHBsb3Qgb2YgUENBcw0KYGBge3J9DQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpmdml6X2VpZyhkaWFiZXRlc19wY2EsIGFkZGxhYmVscyA9IFRSVUUpDQpgYGANCiMjIENvbnRyaWJ1dGlvbiBwbG90IChDaXJjdWxhciBwbG90KQ0KYGBge3J9DQpmdml6X3BjYV92YXIoZGlhYmV0ZXNfcGNhLCBjb2wudmFyID0gImNvbnRyaWIiKQ0KYGBgDQojIyBDb250cmlidXRpb24gcGxvdCBhcyBoZWF0bWFwDQpgYGB7cn0NCmxpYnJhcnkoImNvcnJwbG90IikNCnZhciA9IGdldF9wY2FfdmFyKGRpYWJldGVzX3BjYSkNCmNvcnJwbG90KHZhciRjb3MyKQ0KYGBgDQojIyBDbHVzdGVyIHBsb3QNCmBgYHtyfQ0KZnZpel9wY2FfaW5kKGRpYWJldGVzX3BjYSwNCiAgICAgICAgICAgICBnZW9tLmluZCA9ICJwb2ludCIsDQogICAgICAgICAgICAgY29sLmluZCA9IGRpYWJldGVzJE91dGNvbWUsDQogICAgICAgICAgICAgYWRkRWxsaXBzZXMgPSBUUlVFKQ0KYGBgDQojIyBTVk0gTW9kZWwNCmBgYHtyfQ0KbGlicmFyeShsYXR0aWNlKQ0KbGlicmFyeShlMTA3MSkNCmxpYnJhcnkoY2FyZXQpDQoNCnRyYWluX2l4ID0gY3JlYXRlRGF0YVBhcnRpdGlvbihkaWFiZXRlcyRPdXRjb21lLCBwID0gMC44LCBsaXN0ID0gRkFMU0UpDQp0cmFpbl9kYXRhID0gZGlhYmV0ZXNbdHJhaW5faXgsIF0NCnRlc3RfZGF0YSA9IGRpYWJldGVzWy10cmFpbl9peCwgXQ0KDQp0cmFpbl9kYXRhDQp0ZXN0X2RhdGENCg0KZGlhYmV0ZXMkT3V0Y29tZSA9IGFzLmZhY3RvcihkaWFiZXRlcyRPdXRjb21lKQ0Kc3ZtX21vZGVsID0gc3ZtKE91dGNvbWUgfiBQcmVnbmFuY2llcytHbHVjb3NlK0Jsb29kUHJlc3N1cmUrU2tpblRoaWNrbmVzcytJbnN1bGluK0JNSStEaWFiZXRlc1BlZGlncmVlRnVuY3Rpb24NCitBZ2UsIGRhdGEgPSB0cmFpbl9kYXRhLCBrZXJuZWwgPSAibGluZWFyIikNCmBgYA0KYGBge3J9DQp0ZXN0X2RhdGFbMiwgXQ0KYGBgDQoNCmBgYHtyfQ0KcHJlZGljdChzdm1fbW9kZWwsIG5ld2RhdGEgPSB0ZXN0X2RhdGFbMiwgLTldKQ0KYGBgDQojIyBDb25mdXNpb24gbWF0cml4DQoNCmBgYHtyfQ0KcHJlZGljdGlvbnMgPSBwcmVkaWN0KHN2bV9tb2RlbCwgbmV3ZGF0YSA9IHRlc3RfZGF0YSkNCmNvbmZ1c2lvbl9tYXQgPSBjb25mdXNpb25NYXRyaXgocHJlZGljdGlvbnMsIHRlc3RfZGF0YSRPdXRjb21lKQ0KY29uZnVzaW9uX21hdA0KY29tID0gYXMuZGF0YS5mcmFtZShjb25mdXNpb25fbWF0JHRhYmxlKQ0KDQpnZ3Bsb3QoY29tLCBhZXMoUHJlZGljdGlvbiwgUmVmZXJlbmNlLCBmaWxsID0gRnJlcSkpICsgDQogIGdlb21fdGlsZSgpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpKSArIA0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdz0ibmF2eSIsIGhpZ2g9ImFxdWFtYXJpbmUiKQ0KYGBgDQojIyBVUyBBZG1pc3Npb24gZGF0YXNldA0KYGBge3J9DQp1c19hZCA9IHJlYWQuY3N2KCdVUyBBZG1pc3Npb24uY3N2JykNCnVzX2FkDQpgYGANCiMjIFJlbW92YWwgb2YgU2VyaWFsLk5vIGNvbHVtbg0KYGBge3J9DQp1c19hZF9uZXcgPSB1c19hZFsgLC0xXQ0KdXNfYWRfbmV3DQpgYGANCiMjIFBhaXIgcGxvdA0KYGBge3J9DQpsaWJyYXJ5KEdHYWxseSkNCmdncGFpcnModXNfYWRfbmV3LCBjYXJkaW5hbGl0eV90aHJlc2hvbGQgPSBOVUxMICkgDQpgYGANCiMjIExpbmVhciByZWdyZXNzaW9uDQpgYGB7cn0NCnggPSB1c19hZF9uZXckR1JFLlNjb3JlDQp5ID0gdXNfYWRfbmV3JENoYW5jZS5vZi5BZG1pdA0KDQpwbG90KHh+eSwgeGxhYiA9ICJDaGFuY2Ugb2YgQWRtaXNzaW9uIiwgeWxhYiA9ICJHUkUgU2NvcmUiLCBtYWluID0gIkxpbmVhciBSZWdyZXNzaW9uIG9mIEdSRSBTY29yZSBhbmQgQ2hhbmNlIG9mIEFkbWlzc2lvbiIsIHBjaCA9IDIwLCBjb2wgPSAnYmx1ZScpDQoNCnggPSB1c19hZF9uZXckVE9FRkwuU2NvcmUNCnkgPSB1c19hZF9uZXckQ2hhbmNlLm9mLkFkbWl0DQoNCnBsb3QoeH55LCB4bGFiID0gIkNoYW5jZSBvZiBBZG1pc3Npb24iLCB5bGFiID0gIlRPRUZMIFNjb3JlIiwgbWFpbiA9ICJMaW5lYXIgUmVncmVzc2lvbiBvZiBUT0VGTCBTY29yZSBhbmQgQ2hhbmNlIG9mIEFkbWlzc2lvbiIsIHBjaCA9IDIwLCBjb2wgPSAncmVkJykNCg0KeCA9IHVzX2FkX25ldyRVbml2ZXJzaXR5LlJhdGluZw0KeSA9IHVzX2FkX25ldyRDaGFuY2Uub2YuQWRtaXQNCg0KcGxvdCh4fnksIHhsYWIgPSAiQ2hhbmNlIG9mIEFkbWlzc2lvbiIsIHlsYWIgPSAiVW5pdmVyc2l0eSBSYXRpbmciLCBtYWluID0gIkxpbmVhciBSZWdyZXNzaW9uIG9mIFVuaXZlcnNpdHkgUmF0aW5nIGFuZCBDaGFuY2Ugb2YgQWRtaXNzaW9uIiwgcGNoID0gMjAsIGNvbCA9ICdwdXJwbGUnKQ0KDQp4ID0gdXNfYWRfbmV3JFNPUA0KeSA9IHVzX2FkX25ldyRDaGFuY2Uub2YuQWRtaXQNCg0KcGxvdCh4fnksIHhsYWIgPSAiQ2hhbmNlIG9mIEFkbWlzc2lvbiIsIHlsYWIgPSAiU09QIiwgbWFpbiA9ICJMaW5lYXIgUmVncmVzc2lvbiBvZiBTT1AgYW5kIENoYW5jZSBvZiBBZG1pc3Npb24iLCBwY2ggPSAyMCwgY29sID0gJ21hcm9vbicpDQoNCnggPSB1c19hZF9uZXckTE9SDQp5ID0gdXNfYWRfbmV3JENoYW5jZS5vZi5BZG1pdA0KDQpwbG90KHh+eSwgeGxhYiA9ICJDaGFuY2Ugb2YgQWRtaXNzaW9uIiwgeWxhYiA9ICJMT1IiLCBtYWluID0gIkxpbmVhciBSZWdyZXNzaW9uIG9mIExPUiBhbmQgQ2hhbmNlIG9mIEFkbWlzc2lvbiIsIHBjaCA9IDIwLCBjb2wgPSAnbmF2eScpDQoNCnggPSB1c19hZF9uZXckQ0dQQQ0KeSA9IHVzX2FkX25ldyRDaGFuY2Uub2YuQWRtaXQNCg0KcGxvdCh4fnksIHhsYWIgPSAiQ2hhbmNlIG9mIEFkbWlzc2lvbiIsIHlsYWIgPSAiQ0dQQSIsIG1haW4gPSAiTGluZWFyIFJlZ3Jlc3Npb24gb2YgQ0dQQSBhbmQgQ2hhbmNlIG9mIEFkbWlzc2lvbiIsIHBjaCA9IDIwLCBjb2wgPSAnYnJvd24nKQ0KDQp4ID0gdXNfYWRfbmV3JFJlc2VhcmNoDQp5ID0gdXNfYWRfbmV3JENoYW5jZS5vZi5BZG1pdA0KDQpwbG90KHh+eSwgeGxhYiA9ICJDaGFuY2Ugb2YgQWRtaXNzaW9uIiwgeWxhYiA9ICJSZXNlYXJjaCIsIG1haW4gPSAiTGluZWFyIFJlZ3Jlc3Npb24gb2YgUmVzZWFyY2ggYW5kIENoYW5jZSBvZiBBZG1pc3Npb24iLCBwY2ggPSAyMCwgY29sID0gJ2JsYWNrJykNCmBgYA0KIyMgUG9seW5vbWlhbCByZWdyZXNzaW9uDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdCh1c19hZF9uZXcsIGFlcyh4ID0gR1JFLlNjb3JlLCB5ID0gVE9FRkwuU2NvcmUpLCBjb2xvciA9IENoYW5jZS5vZi5BZG1pdCApICsgDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5fnBvbHkoeCwgMiksIGxldmVsID0gMC45NSkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KZ2dwbG90KHVzX2FkX25ldywgYWVzKHggPSBHUkUuU2NvcmUsIHkgPVVuaXZlcnNpdHkuUmF0aW5nKSwgY29sb3IgPSBDaGFuY2Uub2YuQWRtaXQgKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geX5wb2x5KHgsIDIpLCBsZXZlbCA9IDAuOTUpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmdncGxvdCh1c19hZF9uZXcsIGFlcyh4ID0gR1JFLlNjb3JlLCB5ID0gU09QKSwgY29sb3IgPSBDaGFuY2Uub2YuQWRtaXQgKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geX5wb2x5KHgsIDIpLCBsZXZlbCA9IDAuOTUpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmdncGxvdCh1c19hZF9uZXcsIGFlcyh4ID0gR1JFLlNjb3JlLCB5ID0gTE9SKSwgY29sb3IgPSBDaGFuY2Uub2YuQWRtaXQgKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geX5wb2x5KHgsIDIpLCBsZXZlbCA9IDAuOTUpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmdncGxvdCh1c19hZF9uZXcsIGFlcyh4ID0gR1JFLlNjb3JlLCB5ID0gQ0dQQSksIGNvbG9yID0gQ2hhbmNlLm9mLkFkbWl0ICkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHl+cG9seSh4LCAyKSwgbGV2ZWwgPSAwLjk1KSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpnZ3Bsb3QodXNfYWRfbmV3LCBhZXMoeCA9IEdSRS5TY29yZSwgeSA9IFJlc2VhcmNoKSwgY29sb3IgPSBDaGFuY2Uub2YuQWRtaXQgKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geX5wb2x5KHgsIDIpLCBsZXZlbCA9IDAuOTUpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCiMjIFJlZ3Jlc3Npb24gbW9kZWwNCmBgYHtyfQ0KbGlicmFyeShkYXRhc2V0cykNCmRhdGEodXNfYWRfbmV3KQ0KDQpsbV9tb2RlbCA9IGxtKENoYW5jZS5vZi5BZG1pdCB+IEdSRS5TY29yZStUT0VGTC5TY29yZStVbml2ZXJzaXR5LlJhdGluZytTT1ArTE9SK0NHUEErUmVzZWFyY2gsIGRhdGEgPSB1c19hZF9uZXcpDQpzdW1tYXJ5KGxtX21vZGVsKQ0KYGBgDQoNCg==