Materials
Description of Data
Set
This data set, Diabetes Prediction, is a combination of both
demographic and medical data from over 100,000 patients including their
diabetic status, which indicates whether or not the patient has diabetes
but not what type of diabetes the patient has. The data set on diabetes
prediction contains the following variables,
gender: chr
age: num
hypertension: int
heart_disease: int
smoking_history: chr
bmi: num
HbA1c_level: num
blood_glucose_level: int
diabetes: int
However, while this data set was created with the original intention
of helping predict whether or not a patient has diabetes, it will have a
different purpose in this assignment. Instead, we will be looking at if
variables like blood_glucose_level, heart_disease, diabetes,
hypertension, and HbA1C_level can be used to predict a patients bmi.
Exploratory Data
Analysis
HbA1c <- bmi.diabetes$HbA1c_level
Diabetic <- bmi.diabetes$diabetes
BloodGlucose <- bmi.diabetes$blood_glucose_level
Using the variables, HbA1c_level, blood_glucose_level, and diabetes
to define the variable prediabetic as follows, prediabetic = TRUE if
HbA1c_level > 5.69, blood_glucose_level > 99 & diabetes <
1; prediabetic = FALSE otherwise.
According to the American Diabetes Association (ADA), a normal HbA1c
level is under 5.7, while prediabetic is between 5.7 and 6.5, and
anything above 6.5 is considered diabetic. Additionally, the ADA finds
blood glucose levels under 100 to be withing the normal range, levels
from 100 to 125 as prediabetic, and anything 126 or over as
diabetic.
Using these parameters the variable prediabetic was created to look
at patients who had both HbA1c_ and blood glucose levels that fell
outside the normal range but were not diagnosed diabetics.
prediabetic = (HbA1c > 5.69) & (BloodGlucose > 99) & (Diabetic < 1 )
bmi.diabetes$prediabetic = as.character(prediabetic)
final.data = bmi.diabetes[, -c(1,5)]
kable(head(final.data))
| 80 |
0 |
1 |
25.19 |
6.6 |
140 |
0 |
TRUE |
| 54 |
0 |
0 |
27.32 |
6.6 |
80 |
0 |
FALSE |
| 28 |
0 |
0 |
27.32 |
5.7 |
158 |
0 |
TRUE |
| 36 |
0 |
0 |
23.45 |
5.0 |
155 |
0 |
FALSE |
| 76 |
1 |
1 |
20.14 |
4.8 |
155 |
0 |
FALSE |
| 20 |
0 |
0 |
27.32 |
6.6 |
85 |
0 |
FALSE |
Methodology and
Analysis
Model and
Diagnostics
full.model = lm(bmi ~ ., data = final.data)
kable(summary(full.model)$coef, caption ="Statistics of Regression Coefficients")
Statistics of Regression Coefficients
| (Intercept) |
23.3978892 |
0.1742104 |
134.3082107 |
0.0000000 |
| age |
0.0881169 |
0.0009342 |
94.3215337 |
0.0000000 |
| hypertension |
1.2788508 |
0.0775352 |
16.4938182 |
0.0000000 |
| heart_disease |
-1.2847612 |
0.1040464 |
-12.3479645 |
0.0000000 |
| HbA1c_level |
-0.0176640 |
0.0274817 |
-0.6427553 |
0.5203844 |
| blood_glucose_level |
0.0000913 |
0.0005897 |
0.1548745 |
0.8769206 |
| diabetes |
3.2022017 |
0.1124902 |
28.4664906 |
0.0000000 |
| prediabeticTRUE |
-0.0005028 |
0.0601540 |
-0.0083593 |
0.9933303 |
par(mfrow=c(2,2))
plot(full.model)

Looking at the residual plots above there are some violations
present. First, the variance of the residuals on the Residuals vs Fitted
plot are not constant. Looking at the Q-Q plot, it clearly diverts off
from a normal distribution. Additionally, there is some curvature
present on the residual plot.
vif(full.model)
## age hypertension heart_disease HbA1c_level
## 1.160913 1.092179 1.075466 2.271378
## blood_glucose_level diabetes prediabetic
## 1.511673 2.582034 2.300982
Since none of the variables depict a variance inflation factor (VIF)
above 4 there does not appear to be any significant multicollinearity
issues. We can use a bar plot to further confirm this information.
barplot(vif(full.model), main = "Diabetes Prediction VIF Values", horiz = FALSE)

The bar plot also depicts no variables with a VIF above 4, which
further confirms that there are no significant multicollinearity
issues.
Box-Cox
Transformation
par(pty = "s", mfrow = c(2, 2), oma=c(.1,.1,.1,.1), mar=c(4, 0, 2, 0))
##
boxcox(bmi ~ age + hypertension + heart_disease + HbA1c_level
+ log(blood_glucose_level) + diabetes + prediabetic, data = final.data, lambda = seq(-1, 1, length = 10),
xlab=expression(paste(lambda, ": log blood_glucose_level")))
##
boxcox(bmi ~ age + hypertension + heart_disease + HbA1c_level
+ blood_glucose_level + diabetes + prediabetic, data = final.data, lambda = seq(-1, 1, length = 10),
xlab=expression(paste(lambda, ": blood_glucose_level")))
##
boxcox(bmi ~ age + hypertension + heart_disease + log(HbA1c_level)
+ blood_glucose_level + diabetes + prediabetic, data = final.data, lambda = seq(-1, 1, length = 10),
xlab=expression(paste(lambda, ": log HbA1C_level")))
##
boxcox(bmi ~ age + hypertension + heart_disease + log(HbA1c_level)
+ log(blood_glucose_level) + diabetes + prediabetic, data = final.data, lambda = seq(-1, 1, length = 10),
xlab=expression(paste(lambda, ": log HbA1C_Levels, log blood_glucose_level")))

##
boxcox(bmi ~ log(age) + hypertension + heart_disease + HbA1c_level
+ blood_glucose_level + diabetes + prediabetic, data = final.data, lambda = seq(-1.5, 1, length = 10),
xlab=expression(paste(lambda, ": log age")))
##
boxcox(bmi ~ log(age) + hypertension + heart_disease + log(HbA1c_level)
+ blood_glucose_level + diabetes + prediabetic, data = final.data, lambda = seq(-1.5, 1, length = 10),
xlab=expression(paste(lambda, ": log age, log HbA1c_level")))
##
boxcox(bmi ~ log(age) + hypertension + heart_disease + HbA1c_level
+ log(blood_glucose_level) + diabetes + prediabetic, data = final.data, lambda = seq(-1.5, 1, length = 10),
xlab=expression(paste(lambda, ": log age, log blood_glucose_level")))
##
boxcox(bmi ~ log(age) + hypertension + heart_disease + log(HbA1c_level)
+ log(blood_glucose_level) + diabetes + prediabetic, data = final.data, lambda = seq(-1.5, 1, length = 10),
xlab=expression(paste(lambda, ": log age, log HbA1c_level, log blood_glucose_level")))

The Box-cox transformation plots are used to determine the optimal
under different transformed variables. The log transformation on age
impacts the coefficient of the power transformation .
Square-root
Transformation
Now it is time to depict the Box-Cox transformation with
log-transformed age on the following model,
bmi.log.age = lm((bmi)^-0.5 ~ log(age) + hypertension + heart_disease + HbA1c_level
+ blood_glucose_level + diabetes + prediabetic, data = final.data)
kable(summary(bmi.log.age)$coef, caption = "Age Log-Transformed Model")
Age Log-Transformed Model
| (Intercept) |
0.2421664 |
0.0005924 |
408.7822241 |
0.0000000 |
| log(age) |
-0.0133497 |
0.0000692 |
-192.8523791 |
0.0000000 |
| hypertension |
-0.0027677 |
0.0002457 |
-11.2636679 |
0.0000000 |
| heart_disease |
0.0040241 |
0.0003292 |
12.2222941 |
0.0000000 |
| HbA1c_level |
0.0000510 |
0.0000879 |
0.5801947 |
0.5617846 |
| blood_glucose_level |
-0.0000001 |
0.0000019 |
-0.0617243 |
0.9507825 |
| diabetes |
-0.0079106 |
0.0003583 |
-22.0761603 |
0.0000000 |
| prediabeticTRUE |
-0.0000032 |
0.0001923 |
-0.0163902 |
0.9869231 |
par(mfrow = c(2,2))
plot(bmi.log.age)

After the log-transformation there is some clear improvements to the
residual diagnostic plots. The Q-Q plots depicts a significant
improvement from the previous graph, but still has room to improve.
Additionally the Residuals vs Fitted plot depicts more constant and
equal variances, and it appears that the weak curvature has flattened
out.
In an effort to no have any violation with the assumption of
normality, we can take a log transformation of bmi and build a model
based on log bmi.
log.bmi = lm(log(bmi) ~ age + hypertension + heart_disease + HbA1c_level
+ blood_glucose_level + diabetes + prediabetic, data = final.data)
kable(summary(log.bmi)$coef, caption = "BMI Log-Transformed Model")
BMI Log-Transformed Model
| (Intercept) |
3.1078109 |
0.0061400 |
506.1547793 |
0.0000000 |
| age |
0.0039233 |
0.0000329 |
119.1524965 |
0.0000000 |
| hypertension |
0.0353802 |
0.0027327 |
12.9468457 |
0.0000000 |
| heart_disease |
-0.0508245 |
0.0036671 |
-13.8595347 |
0.0000000 |
| HbA1c_level |
-0.0003969 |
0.0009686 |
-0.4097767 |
0.6819707 |
| blood_glucose_level |
0.0000068 |
0.0000208 |
0.3252589 |
0.7449858 |
| diabetes |
0.0934044 |
0.0039647 |
23.5589130 |
0.0000000 |
| prediabeticTRUE |
-0.0005694 |
0.0021201 |
-0.2685502 |
0.7882764 |
par(mfrow = c(2,2))
plot(log.bmi)

The residual diagnostic plots for the log(bmi) model do not depict a
significant improvement for the assumption of normality, and brings back
some of the weak curvature from the original models. This means that
none of the three models statisfy the assumption of normality.
#define plotting area
par(pty = "s", mfrow = c(1, 3))
#Q-Q plot for original model
qqnorm(full.model$residuals, main = "Full-Model")
qqline(full.model$residuals)
#Q-Q plot for Box-Cox transformed model
qqnorm(log.bmi$residuals, main = "Log BMI")
qqline(log.bmi$residuals)
#display both Q-Q plots
qqnorm(bmi.log.age$residuals, main = "BMI log Age")
qqline(bmi.log.age$residuals)

Goodness-of-Fit
select=function(m){ # m is an object: model
e = m$resid # residuals
n0 = length(e) # sample size
SSE=(m$df)*(summary(m)$sigma)^2 # sum of squared error
R.sq=summary(m)$r.squared # Coefficient of determination: R square!
R.adj=summary(m)$adj.r # Adjusted R square
MSE=(summary(m)$sigma)^2 # square error
Cp=(SSE/MSE)-(n0-2*(n0-m$df)) # Mellow's p
AIC=n0*log(SSE)-n0*log(n0)+2*(n0-m$df) # Akaike information criterion
SBC=n0*log(SSE)-n0*log(n0)+(log(n0))*(n0-m$df) # Schwarz Bayesian Information criterion
X=model.matrix(m) # design matrix of the model
H=X%*%solve(t(X)%*%X)%*%t(X) # hat matrix
d=e/(1-diag(H))
PRESS=t(d)%*%d # predicted residual error sum of squares (PRESS)- a cross-validation measure
tbl = as.data.frame(cbind(SSE=SSE, R.sq=R.sq, R.adj = R.adj, Cp = Cp, AIC = AIC, SBC = SBC, PRD = PRESS))
names(tbl)=c("SSE", "R.sq", "R.adj", "Cp", "AIC", "SBC", "PRESS")
tbl
}
Note: Due to the size of the data set RStudio was unable to fun the
code on Goodness of Fit could not run without crashing RStudio or
exhausting the memory vector. To remedy this issue, a random sample of
10,000 observations was taken from the data set and used for the the
following code. Anything using this random sample data set is depicted
by ending in .rand. Due to this change in the data set, the Q-Q plots
were reprinted to make sure this smaller sample of the data was still an
accurate representation of the larger data set.
final.data.rand <- final.data[sample(nrow(final.data), size = 10000, replace = FALSE), ]
full.model.rand = lm(bmi ~ ., data = final.data.rand)
log.bmi.rand = lm(log(bmi) ~ age + hypertension + heart_disease + HbA1c_level
+ blood_glucose_level + diabetes + prediabetic, data = final.data.rand)
bmi.log.age.rand = lm((bmi)^-0.5 ~ log(age) + hypertension + heart_disease + HbA1c_level
+ blood_glucose_level + diabetes + prediabetic, data = final.data.rand)
par(pty = "s", mfrow = c(1, 3))
#Q-Q plot for original model
qqnorm(full.model.rand$residuals, main = "Full-Model")
qqline(full.model.rand$residuals)
#Q-Q plot for Box-Cox transformed model
qqnorm(log.bmi.rand$residuals, main = "Log BMI")
qqline(log.bmi$residuals)
#display both Q-Q plots
qqnorm(bmi.log.age.rand$residuals, main = "BMI log Age")
qqline(bmi.log.age$residuals)

The Q-Q plots for the 10,000 observation data set is similar to the
Q-Q plots for the 100,000 observation data set. Now, it is possible to
move forward with the Goodness-of-Fit tests.
output.sum = rbind(select(full.model.rand), select(bmi.log.age.rand), select(log.bmi.rand))
row.names(output.sum) = c("full.model.rand", "bmi.log.age.rand", "log.bmi.rand")
kable(output.sum, caption = "Goodness-of-fit Measures of Candidate Models")
Goodness-of-fit Measures of Candidate Models
| full.model.rand |
3.907917e+05 |
0.1286410 |
0.1280306 |
8 |
36671.90 |
36729.58 |
3.914916e+05 |
| bmi.log.age.rand |
3.934383e+00 |
0.3061495 |
0.3056634 |
8 |
-78389.86 |
-78332.18 |
3.940886e+00 |
| log.bmi.rand |
4.810988e+02 |
0.1668803 |
0.1662967 |
8 |
-30326.68 |
-30269.00 |
4.819005e+02 |
Looking at the outputs for \(R^2,
R^2_{adj}\), and \(C_p\) it is clear that the second
model, bmi.log.age.rand is the best of the three models. This means the
second model will be the final model.
Final Model
kable(summary(bmi.log.age)$coef, caption = "Inferential Statistics on the Final Model")
Inferential Statistics on the Final Model
| (Intercept) |
0.2421664 |
0.0005924 |
408.7822241 |
0.0000000 |
| log(age) |
-0.0133497 |
0.0000692 |
-192.8523791 |
0.0000000 |
| hypertension |
-0.0027677 |
0.0002457 |
-11.2636679 |
0.0000000 |
| heart_disease |
0.0040241 |
0.0003292 |
12.2222941 |
0.0000000 |
| HbA1c_level |
0.0000510 |
0.0000879 |
0.5801947 |
0.5617846 |
| blood_glucose_level |
-0.0000001 |
0.0000019 |
-0.0617243 |
0.9507825 |
| diabetes |
-0.0079106 |
0.0003583 |
-22.0761603 |
0.0000000 |
| prediabeticTRUE |
-0.0000032 |
0.0001923 |
-0.0163902 |
0.9869231 |
Due the data set has over 100,000 observations the Central Limit
Theorem can be used as the argument for validating the p-values. The
variables log(age), hypertension, heart_disease, and diabetes all depict
p-values close to zero meaning their coefficients are signifcantly
differnt from 0. However, the variables HbA1c_level,
blood_glucose_level, and prediabetic have p-values much higher than 0
which means these variables are not statistically significant when it
comes to the prediction of bmi.
General Discussion
Several regression techniques, including the Box-cox transformation
was used to determine the final model in this study. While the final
data set consists of 8 variables, 3 of them were not statistically
significant and thus were not used in the final model. All of the models
that were compared using the goodness-of-fit measure model criteria
consisted of the same 8 variables.
However, due to the size of the original final data set being
significantly large, with over 100,000 observations, a smaller random
sample of the final data set, consisting of 10,000 observations was
created to run the goodness-of-fit measure in a way that did not
shutdown RStudio. Additionally, the goodness-of-fit measure was used due
to the fact that the violation to the normality assumption on the
residuals. This normality assumption remains uncorrected even after
several transformation techniques were used on the data set. The central
limit theorem (CLT) was used to base inferences on the regression
coefficients.
The final model used the log(age) Box-cox transformation with a -0.5
adjustment on bmi. This model was selected over the full model and the
log(bmi) model because even though none of the models met the normality
assumption the log(age) model had the best \(R^2, R^2_{adj}\), and \(C_p\) outputs after running the
goodness-of-fit measure on all three models. Additionally, from the
selected final model, three variables were removed from the original
eight due to them having non-significant p-values. After removing those
variables the final model was complete.
LS0tCnRpdGxlOiAnU1RBMzIxOiBXZWVrICMwNCBBc3NpZ25tZW50JwphdXRob3I6ICdDaGxvZSBXaW50ZXJzJwpkYXRlOiAiOS8yMi8yMDI0IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfd2lkdGg6IDYKICAgIGZpZ19oZWlnaHQ6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHBkZl9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnNCcKLS0tCmBgYHs9aHRtbH0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CgovKiBDYXNjYWRpbmcgU3R5bGUgU2hlZXRzIChDU1MpIGlzIGEgc3R5bGVzaGVldCBsYW5ndWFnZSB1c2VkIHRvIGRlc2NyaWJlIHRoZSBwcmVzZW50YXRpb24gb2YgYSBkb2N1bWVudCB3cml0dGVuIGluIEhUTUwgb3IgWE1MLiBpdCBpcyBhIHNpbXBsZSBtZWNoYW5pc20gZm9yIGFkZGluZyBzdHlsZSAoZS5nLiwgZm9udHMsIGNvbG9ycywgc3BhY2luZykgdG8gV2ViIGRvY3VtZW50cy4gKi8KCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovCiAgZm9udC1zaXplOiAyNHB4OwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7Cn0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLwogIGZvbnQtc2l6ZTogMjBweDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDIycHg7CiAgICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoMyB7IC8qIEhlYWRlciAzIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCAzIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgNCBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCjwvc3R5bGU+CmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCAKIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuCmxpYnJhcnkoa25pdHIpCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZ3MgPSBGQUxTRSwgICAgICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiAKICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFICAgICAgICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuCiAgICAgICAgICAgICAgICAgICAgICApICAgCgpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoY2FyKQpsaWJyYXJ5KCJzY2FsZXMiKSAKCmBgYAoKCgpgYGB7cn0KdXJsID0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DaGxvZVdpbnRlcnM3OS9TVEEzMjEvcmVmcy9oZWFkcy9tYWluL0RhdGEvZGlhYmV0ZXNfcHJlZGljdGlvbl9kYXRhc2V0LmNzdiIKCmJtaS5kaWFiZXRlcyA9IHJlYWQuY3N2KHVybCwgaGVhZGVyID0gVFJVRSkKCmBgYAoKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGFzc2lnbm1lbnQgaXMgZ29pbmcgdG8gbG9vayBpbnRvIGltcGxlbWVudGluZyB2YXJpb3VzIGRpZmZlcmVudCBtb2RlbC1idWlsZGluZyB0ZWNobmlxdWVzIGluIG9yZGVyIHRvIGZpbmQgdGhlIGJlc3QgbW9kZWwuIAoKCiMgTWF0ZXJpYWxzIAoKIyMgRGVzY3JpcHRpb24gb2YgRGF0YSBTZXQKClRoaXMgZGF0YSBzZXQsIERpYWJldGVzIFByZWRpY3Rpb24sIGlzIGEgY29tYmluYXRpb24gb2YgYm90aCBkZW1vZ3JhcGhpYyBhbmQgbWVkaWNhbCBkYXRhIGZyb20gb3ZlciAxMDAsMDAwIHBhdGllbnRzIGluY2x1ZGluZyB0aGVpciBkaWFiZXRpYyBzdGF0dXMsIHdoaWNoIGluZGljYXRlcyB3aGV0aGVyIG9yIG5vdCB0aGUgcGF0aWVudCBoYXMgZGlhYmV0ZXMgYnV0IG5vdCB3aGF0IHR5cGUgb2YgZGlhYmV0ZXMgdGhlIHBhdGllbnQgaGFzLiBUaGUgZGF0YSBzZXQgb24gZGlhYmV0ZXMgcHJlZGljdGlvbiBjb250YWlucyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcywgCgpnZW5kZXI6IGNocgoKYWdlOiBudW0KCmh5cGVydGVuc2lvbjogaW50CgpoZWFydF9kaXNlYXNlOiBpbnQKCnNtb2tpbmdfaGlzdG9yeTogY2hyCgpibWk6IG51bQoKSGJBMWNfbGV2ZWw6IG51bQoKYmxvb2RfZ2x1Y29zZV9sZXZlbDogaW50CgpkaWFiZXRlczogaW50CgpIb3dldmVyLCB3aGlsZSB0aGlzIGRhdGEgc2V0IHdhcyBjcmVhdGVkIHdpdGggdGhlIG9yaWdpbmFsIGludGVudGlvbiBvZiBoZWxwaW5nIHByZWRpY3Qgd2hldGhlciBvciBub3QgYSBwYXRpZW50IGhhcyBkaWFiZXRlcywgaXQgd2lsbCBoYXZlIGEgZGlmZmVyZW50IHB1cnBvc2UgaW4gdGhpcyBhc3NpZ25tZW50LiBJbnN0ZWFkLCB3ZSB3aWxsIGJlIGxvb2tpbmcgYXQgaWYgdmFyaWFibGVzIGxpa2UgYmxvb2RfZ2x1Y29zZV9sZXZlbCwgaGVhcnRfZGlzZWFzZSwgZGlhYmV0ZXMsIGh5cGVydGVuc2lvbiwgYW5kIEhiQTFDX2xldmVsIGNhbiBiZSB1c2VkIHRvIHByZWRpY3QgYSBwYXRpZW50cyBibWkuIAoKIyMgRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcwoKYGBge3J9CkhiQTFjIDwtIGJtaS5kaWFiZXRlcyRIYkExY19sZXZlbAoKRGlhYmV0aWMgPC0gYm1pLmRpYWJldGVzJGRpYWJldGVzCgpCbG9vZEdsdWNvc2UgPC0gYm1pLmRpYWJldGVzJGJsb29kX2dsdWNvc2VfbGV2ZWwKCmBgYAoKVXNpbmcgdGhlIHZhcmlhYmxlcywgSGJBMWNfbGV2ZWwsIGJsb29kX2dsdWNvc2VfbGV2ZWwsIGFuZCBkaWFiZXRlcyB0byBkZWZpbmUgdGhlIHZhcmlhYmxlIHByZWRpYWJldGljIGFzIGZvbGxvd3MsIHByZWRpYWJldGljID0gVFJVRSBpZiBIYkExY19sZXZlbCA+IDUuNjksICBibG9vZF9nbHVjb3NlX2xldmVsID4gOTkgJiBkaWFiZXRlcyA8IDE7IHByZWRpYWJldGljID0gRkFMU0Ugb3RoZXJ3aXNlLiAKCkFjY29yZGluZyB0byB0aGUgQW1lcmljYW4gRGlhYmV0ZXMgQXNzb2NpYXRpb24gKEFEQSksIGEgbm9ybWFsIEhiQTFjIGxldmVsIGlzIHVuZGVyIDUuNywgd2hpbGUgcHJlZGlhYmV0aWMgaXMgYmV0d2VlbiA1LjcgYW5kIDYuNSwgYW5kIGFueXRoaW5nIGFib3ZlIDYuNSBpcyBjb25zaWRlcmVkIGRpYWJldGljLiBBZGRpdGlvbmFsbHksIHRoZSBBREEgZmluZHMgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgdW5kZXIgMTAwIHRvIGJlIHdpdGhpbmcgdGhlIG5vcm1hbCByYW5nZSwgbGV2ZWxzIGZyb20gMTAwIHRvIDEyNSBhcyBwcmVkaWFiZXRpYywgYW5kIGFueXRoaW5nIDEyNiBvciBvdmVyIGFzIGRpYWJldGljLiAKClVzaW5nIHRoZXNlIHBhcmFtZXRlcnMgdGhlIHZhcmlhYmxlIHByZWRpYWJldGljIHdhcyBjcmVhdGVkIHRvIGxvb2sgYXQgcGF0aWVudHMgd2hvIGhhZCBib3RoIEhiQTFjXyBhbmQgYmxvb2QgZ2x1Y29zZSBsZXZlbHMgdGhhdCBmZWxsIG91dHNpZGUgdGhlIG5vcm1hbCByYW5nZSBidXQgd2VyZSBub3QgZGlhZ25vc2VkIGRpYWJldGljcy4gCgpgYGB7cn0KCnByZWRpYWJldGljID0gKEhiQTFjID4gNS42OSkgICYgKEJsb29kR2x1Y29zZSA+IDk5KSAmIChEaWFiZXRpYyA8IDEgKQoKYm1pLmRpYWJldGVzJHByZWRpYWJldGljID0gYXMuY2hhcmFjdGVyKHByZWRpYWJldGljKQoKYGBgCgpgYGB7cn0KZmluYWwuZGF0YSA9IGJtaS5kaWFiZXRlc1ssIC1jKDEsNSldCgprYWJsZShoZWFkKGZpbmFsLmRhdGEpKQpgYGAKCiMgTWV0aG9kb2xvZ3kgYW5kIEFuYWx5c2lzIAoKIyMgTW9kZWwgYW5kIERpYWdub3N0aWNzCgpgYGB7cn0KZnVsbC5tb2RlbCA9IGxtKGJtaSB+IC4sIGRhdGEgPSBmaW5hbC5kYXRhKQprYWJsZShzdW1tYXJ5KGZ1bGwubW9kZWwpJGNvZWYsIGNhcHRpb24gPSJTdGF0aXN0aWNzIG9mIFJlZ3Jlc3Npb24gQ29lZmZpY2llbnRzIikKYGBgCmBgYCB7cn0KCnBhcihtZnJvdz1jKDIsMikpCnBsb3QoZnVsbC5tb2RlbCkKCmBgYAogCkxvb2tpbmcgYXQgdGhlIHJlc2lkdWFsIHBsb3RzIGFib3ZlIHRoZXJlIGFyZSBzb21lIHZpb2xhdGlvbnMgcHJlc2VudC4gRmlyc3QsIHRoZSB2YXJpYW5jZSBvZiB0aGUgcmVzaWR1YWxzIG9uIHRoZSBSZXNpZHVhbHMgdnMgRml0dGVkIHBsb3QgYXJlIG5vdCBjb25zdGFudC4gTG9va2luZyBhdCB0aGUgUS1RIHBsb3QsIGl0IGNsZWFybHkgZGl2ZXJ0cyBvZmYgZnJvbSBhIG5vcm1hbCBkaXN0cmlidXRpb24uIEFkZGl0aW9uYWxseSwgdGhlcmUgaXMgc29tZSBjdXJ2YXR1cmUgcHJlc2VudCBvbiB0aGUgcmVzaWR1YWwgcGxvdC4gCiAKCmBgYHtyfQoKdmlmKGZ1bGwubW9kZWwpCgpgYGAKClNpbmNlIG5vbmUgb2YgdGhlIHZhcmlhYmxlcyBkZXBpY3QgYSB2YXJpYW5jZSBpbmZsYXRpb24gZmFjdG9yIChWSUYpIGFib3ZlIDQgdGhlcmUgZG9lcyBub3QgYXBwZWFyIHRvIGJlIGFueSBzaWduaWZpY2FudCBtdWx0aWNvbGxpbmVhcml0eSBpc3N1ZXMuIFdlIGNhbiB1c2UgYSBiYXIgcGxvdCB0byBmdXJ0aGVyIGNvbmZpcm0gdGhpcyBpbmZvcm1hdGlvbi4KCmBgYCB7cn0KCmJhcnBsb3QodmlmKGZ1bGwubW9kZWwpLCBtYWluID0gIkRpYWJldGVzIFByZWRpY3Rpb24gVklGIFZhbHVlcyIsIGhvcml6ID0gRkFMU0UpCgpgYGAKClRoZSBiYXIgcGxvdCBhbHNvIGRlcGljdHMgbm8gdmFyaWFibGVzIHdpdGggYSBWSUYgYWJvdmUgNCwgd2hpY2ggZnVydGhlciBjb25maXJtcyB0aGF0IHRoZXJlIGFyZSBubyBzaWduaWZpY2FudCBtdWx0aWNvbGxpbmVhcml0eSBpc3N1ZXMuIAoKIyMgQm94LUNveCBUcmFuc2Zvcm1hdGlvbgoKYGBgIHtyfQpwYXIocHR5ID0gInMiLCBtZnJvdyA9IGMoMiwgMiksIG9tYT1jKC4xLC4xLC4xLC4xKSwgbWFyPWMoNCwgMCwgMiwgMCkpCiMjCmJveGNveChibWkgfiBhZ2UgKyBoeXBlcnRlbnNpb24gKyBoZWFydF9kaXNlYXNlICsgIEhiQTFjX2xldmVsCiAgICAgICArIGxvZyhibG9vZF9nbHVjb3NlX2xldmVsKSArIGRpYWJldGVzICsgcHJlZGlhYmV0aWMsIGRhdGEgPSBmaW5hbC5kYXRhLCBsYW1iZGEgPSBzZXEoLTEsIDEsIGxlbmd0aCA9IDEwKSwgCiAgICAgICB4bGFiPWV4cHJlc3Npb24ocGFzdGUobGFtYmRhLCAiOiBsb2cgYmxvb2RfZ2x1Y29zZV9sZXZlbCIpKSkKIyMKYm94Y294KGJtaSB+IGFnZSArIGh5cGVydGVuc2lvbiArIGhlYXJ0X2Rpc2Vhc2UgKyBIYkExY19sZXZlbCAgCiAgICAgICArIGJsb29kX2dsdWNvc2VfbGV2ZWwgKyBkaWFiZXRlcyArIHByZWRpYWJldGljLCBkYXRhID0gZmluYWwuZGF0YSwgbGFtYmRhID0gc2VxKC0xLCAxLCBsZW5ndGggPSAxMCksIAogICAgICAgeGxhYj1leHByZXNzaW9uKHBhc3RlKGxhbWJkYSwgIjogYmxvb2RfZ2x1Y29zZV9sZXZlbCIpKSkKIyMKYm94Y294KGJtaSB+IGFnZSArIGh5cGVydGVuc2lvbiArIGhlYXJ0X2Rpc2Vhc2UgKyAgbG9nKEhiQTFjX2xldmVsKSAgCiAgICAgICArIGJsb29kX2dsdWNvc2VfbGV2ZWwgKyBkaWFiZXRlcyArIHByZWRpYWJldGljLCBkYXRhID0gZmluYWwuZGF0YSwgbGFtYmRhID0gc2VxKC0xLCAxLCBsZW5ndGggPSAxMCksIAogICAgICAgeGxhYj1leHByZXNzaW9uKHBhc3RlKGxhbWJkYSwgIjogbG9nIEhiQTFDX2xldmVsIikpKQojIwpib3hjb3goYm1pIH4gYWdlICsgaHlwZXJ0ZW5zaW9uICsgaGVhcnRfZGlzZWFzZSArICBsb2coSGJBMWNfbGV2ZWwpICAKICAgICAgICsgbG9nKGJsb29kX2dsdWNvc2VfbGV2ZWwpICsgZGlhYmV0ZXMgKyBwcmVkaWFiZXRpYywgZGF0YSA9IGZpbmFsLmRhdGEsIGxhbWJkYSA9IHNlcSgtMSwgMSwgbGVuZ3RoID0gMTApLCAKICAgICAgeGxhYj1leHByZXNzaW9uKHBhc3RlKGxhbWJkYSwgIjogbG9nIEhiQTFDX0xldmVscywgbG9nIGJsb29kX2dsdWNvc2VfbGV2ZWwiKSkpCiMjCmJveGNveChibWkgfiBsb2coYWdlKSArIGh5cGVydGVuc2lvbiArIGhlYXJ0X2Rpc2Vhc2UgKyAgSGJBMWNfbGV2ZWwgCiAgICAgICArIGJsb29kX2dsdWNvc2VfbGV2ZWwgKyBkaWFiZXRlcyArIHByZWRpYWJldGljLCBkYXRhID0gZmluYWwuZGF0YSwgbGFtYmRhID0gc2VxKC0xLjUsIDEsIGxlbmd0aCA9IDEwKSwgCiAgICAgIHhsYWI9ZXhwcmVzc2lvbihwYXN0ZShsYW1iZGEsICI6IGxvZyBhZ2UiKSkpCiMjCmJveGNveChibWkgfiBsb2coYWdlKSArIGh5cGVydGVuc2lvbiArIGhlYXJ0X2Rpc2Vhc2UgKyAgbG9nKEhiQTFjX2xldmVsKSAgCiAgICAgICArIGJsb29kX2dsdWNvc2VfbGV2ZWwgKyBkaWFiZXRlcyArIHByZWRpYWJldGljLCBkYXRhID0gZmluYWwuZGF0YSwgbGFtYmRhID0gc2VxKC0xLjUsIDEsIGxlbmd0aCA9IDEwKSwgCiAgICAgIHhsYWI9ZXhwcmVzc2lvbihwYXN0ZShsYW1iZGEsICI6IGxvZyBhZ2UsIGxvZyBIYkExY19sZXZlbCIpKSkKCiMjCmJveGNveChibWkgfiBsb2coYWdlKSArIGh5cGVydGVuc2lvbiArIGhlYXJ0X2Rpc2Vhc2UgKyAgSGJBMWNfbGV2ZWwgIAogICAgICAgKyBsb2coYmxvb2RfZ2x1Y29zZV9sZXZlbCkgKyBkaWFiZXRlcyArIHByZWRpYWJldGljLCBkYXRhID0gZmluYWwuZGF0YSwgbGFtYmRhID0gc2VxKC0xLjUsIDEsIGxlbmd0aCA9IDEwKSwgCiAgICAgIHhsYWI9ZXhwcmVzc2lvbihwYXN0ZShsYW1iZGEsICI6IGxvZyBhZ2UsIGxvZyBibG9vZF9nbHVjb3NlX2xldmVsIikpKQoKIyMgCgpib3hjb3goYm1pIH4gbG9nKGFnZSkgKyBoeXBlcnRlbnNpb24gKyBoZWFydF9kaXNlYXNlICsgIGxvZyhIYkExY19sZXZlbCkgIAogICAgICAgKyBsb2coYmxvb2RfZ2x1Y29zZV9sZXZlbCkgKyBkaWFiZXRlcyArIHByZWRpYWJldGljLCBkYXRhID0gZmluYWwuZGF0YSwgbGFtYmRhID0gc2VxKC0xLjUsIDEsIGxlbmd0aCA9IDEwKSwgCiAgICAgIHhsYWI9ZXhwcmVzc2lvbihwYXN0ZShsYW1iZGEsICI6IGxvZyBhZ2UsIGxvZyBIYkExY19sZXZlbCwgbG9nIGJsb29kX2dsdWNvc2VfbGV2ZWwiKSkpCgpgYGAKClRoZSBCb3gtY294IHRyYW5zZm9ybWF0aW9uIHBsb3RzIGFyZSB1c2VkIHRvIGRldGVybWluZSB0aGUgb3B0aW1hbCBcbGFtZGEgdW5kZXIgZGlmZmVyZW50IHRyYW5zZm9ybWVkIHZhcmlhYmxlcy4gVGhlIGxvZyB0cmFuc2Zvcm1hdGlvbiBvbiBhZ2UgaW1wYWN0cyB0aGUgY29lZmZpY2llbnQgb2YgdGhlIHBvd2VyIHRyYW5zZm9ybWF0aW9uIFxsYW1kYS4gCgojIyBTcXVhcmUtcm9vdCBUcmFuc2Zvcm1hdGlvbgoKTm93IGl0IGlzIHRpbWUgdG8gZGVwaWN0IHRoZSBCb3gtQ294IHRyYW5zZm9ybWF0aW9uIHdpdGggbG9nLXRyYW5zZm9ybWVkIGFnZSBvbiB0aGUgZm9sbG93aW5nIG1vZGVsLCAKCmBgYHtyfQoKYm1pLmxvZy5hZ2UgPSBsbSgoYm1pKV4tMC41IH4gbG9nKGFnZSkgKyBoeXBlcnRlbnNpb24gKyBoZWFydF9kaXNlYXNlICsgIEhiQTFjX2xldmVsCiAgICAgICArIGJsb29kX2dsdWNvc2VfbGV2ZWwgKyBkaWFiZXRlcyArIHByZWRpYWJldGljLCBkYXRhID0gZmluYWwuZGF0YSkKa2FibGUoc3VtbWFyeShibWkubG9nLmFnZSkkY29lZiwgY2FwdGlvbiA9ICJBZ2UgTG9nLVRyYW5zZm9ybWVkIE1vZGVsIikKCmBgYAoKYGBge3J9CnBhcihtZnJvdyA9IGMoMiwyKSkKcGxvdChibWkubG9nLmFnZSkKCmBgYAoKCkFmdGVyIHRoZSBsb2ctdHJhbnNmb3JtYXRpb24gdGhlcmUgaXMgc29tZSBjbGVhciBpbXByb3ZlbWVudHMgdG8gdGhlIHJlc2lkdWFsIGRpYWdub3N0aWMgcGxvdHMuIFRoZSBRLVEgcGxvdHMgZGVwaWN0cyBhIHNpZ25pZmljYW50IGltcHJvdmVtZW50IGZyb20gdGhlIHByZXZpb3VzIGdyYXBoLCBidXQgc3RpbGwgaGFzIHJvb20gdG8gaW1wcm92ZS4gQWRkaXRpb25hbGx5IHRoZSBSZXNpZHVhbHMgdnMgRml0dGVkIHBsb3QgZGVwaWN0cyBtb3JlIGNvbnN0YW50IGFuZCBlcXVhbCB2YXJpYW5jZXMsIGFuZCBpdCBhcHBlYXJzIHRoYXQgdGhlIHdlYWsgY3VydmF0dXJlIGhhcyBmbGF0dGVuZWQgb3V0LgoKSW4gYW4gZWZmb3J0IHRvIG5vIGhhdmUgYW55IHZpb2xhdGlvbiB3aXRoIHRoZSBhc3N1bXB0aW9uIG9mIG5vcm1hbGl0eSwgd2UgY2FuIHRha2UgYSBsb2cgdHJhbnNmb3JtYXRpb24gb2YgYm1pIGFuZCBidWlsZCBhIG1vZGVsIGJhc2VkIG9uIGxvZyBibWkuIAoKYGBge3J9CmxvZy5ibWkgPSBsbShsb2coYm1pKSB+IGFnZSArIGh5cGVydGVuc2lvbiArIGhlYXJ0X2Rpc2Vhc2UgKyAgSGJBMWNfbGV2ZWwKICAgICAgICsgYmxvb2RfZ2x1Y29zZV9sZXZlbCArIGRpYWJldGVzICsgcHJlZGlhYmV0aWMsIGRhdGEgPSBmaW5hbC5kYXRhKQoKa2FibGUoc3VtbWFyeShsb2cuYm1pKSRjb2VmLCBjYXB0aW9uID0gIkJNSSBMb2ctVHJhbnNmb3JtZWQgTW9kZWwiKQoKYGBgCmBgYHtyfQpwYXIobWZyb3cgPSBjKDIsMikpCnBsb3QobG9nLmJtaSkKCmBgYAoKClRoZSByZXNpZHVhbCBkaWFnbm9zdGljIHBsb3RzIGZvciB0aGUgbG9nKGJtaSkgbW9kZWwgZG8gbm90IGRlcGljdCBhIHNpZ25pZmljYW50IGltcHJvdmVtZW50IGZvciB0aGUgYXNzdW1wdGlvbiBvZiBub3JtYWxpdHksIGFuZCBicmluZ3MgYmFjayBzb21lIG9mIHRoZSB3ZWFrIGN1cnZhdHVyZSBmcm9tIHRoZSBvcmlnaW5hbCBtb2RlbHMuIFRoaXMgbWVhbnMgdGhhdCBub25lIG9mIHRoZSB0aHJlZSBtb2RlbHMgc3RhdGlzZnkgdGhlIGFzc3VtcHRpb24gb2Ygbm9ybWFsaXR5LiAKCgpgYGB7cn0KI2RlZmluZSBwbG90dGluZyBhcmVhCnBhcihwdHkgPSAicyIsIG1mcm93ID0gYygxLCAzKSkKI1EtUSBwbG90IGZvciBvcmlnaW5hbCBtb2RlbApxcW5vcm0oZnVsbC5tb2RlbCRyZXNpZHVhbHMsIG1haW4gPSAiRnVsbC1Nb2RlbCIpCnFxbGluZShmdWxsLm1vZGVsJHJlc2lkdWFscykKI1EtUSBwbG90IGZvciBCb3gtQ294IHRyYW5zZm9ybWVkIG1vZGVsCnFxbm9ybShsb2cuYm1pJHJlc2lkdWFscywgbWFpbiA9ICJMb2cgQk1JIikKcXFsaW5lKGxvZy5ibWkkcmVzaWR1YWxzKQojZGlzcGxheSBib3RoIFEtUSBwbG90cwpxcW5vcm0oYm1pLmxvZy5hZ2UkcmVzaWR1YWxzLCBtYWluID0gIkJNSSBsb2cgQWdlIikKcXFsaW5lKGJtaS5sb2cuYWdlJHJlc2lkdWFscykKYGBgCgoKIyMgR29vZG5lc3Mtb2YtRml0CgpgYGB7cn0Kc2VsZWN0PWZ1bmN0aW9uKG0peyAjIG0gaXMgYW4gb2JqZWN0OiBtb2RlbAogZSA9IG0kcmVzaWQgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJlc2lkdWFscwogbjAgPSBsZW5ndGgoZSkgICAgICAgICAgICAgICAgICAgICAgICAjIHNhbXBsZSBzaXplCiBTU0U9KG0kZGYpKihzdW1tYXJ5KG0pJHNpZ21hKV4yICAgICAgICMgc3VtIG9mIHNxdWFyZWQgZXJyb3IKIFIuc3E9c3VtbWFyeShtKSRyLnNxdWFyZWQgICAgICAgICAgICAgIyBDb2VmZmljaWVudCBvZiBkZXRlcm1pbmF0aW9uOiBSIHNxdWFyZSEKIFIuYWRqPXN1bW1hcnkobSkkYWRqLnIgICAgICAgICAgICAgICAgIyBBZGp1c3RlZCBSIHNxdWFyZQogTVNFPShzdW1tYXJ5KG0pJHNpZ21hKV4yICAgICAgICAgICAgICAjIHNxdWFyZSBlcnJvcgogQ3A9KFNTRS9NU0UpLShuMC0yKihuMC1tJGRmKSkgICAgICAgICAjIE1lbGxvdydzIHAKIEFJQz1uMCpsb2coU1NFKS1uMCpsb2cobjApKzIqKG4wLW0kZGYpICAgICAgICAgICMgQWthaWtlIGluZm9ybWF0aW9uIGNyaXRlcmlvbgogU0JDPW4wKmxvZyhTU0UpLW4wKmxvZyhuMCkrKGxvZyhuMCkpKihuMC1tJGRmKSAgIyBTY2h3YXJ6IEJheWVzaWFuIEluZm9ybWF0aW9uIGNyaXRlcmlvbgogWD1tb2RlbC5tYXRyaXgobSkgICAgICAgICAgICAgICAgICAgICAjIGRlc2lnbiBtYXRyaXggb2YgdGhlIG1vZGVsCiBIPVglKiVzb2x2ZSh0KFgpJSolWCklKiV0KFgpICAgICAgICAgICMgaGF0IG1hdHJpeAogZD1lLygxLWRpYWcoSCkpICAgICAgICAgICAgICAgICAgICAgICAKIFBSRVNTPXQoZCklKiVkICAgIyBwcmVkaWN0ZWQgcmVzaWR1YWwgZXJyb3Igc3VtIG9mIHNxdWFyZXMgKFBSRVNTKS0gYSBjcm9zcy12YWxpZGF0aW9uIG1lYXN1cmUKIHRibCA9IGFzLmRhdGEuZnJhbWUoY2JpbmQoU1NFPVNTRSwgUi5zcT1SLnNxLCBSLmFkaiA9IFIuYWRqLCBDcCA9IENwLCBBSUMgPSBBSUMsIFNCQyA9IFNCQywgUFJEID0gUFJFU1MpKQogbmFtZXModGJsKT1jKCJTU0UiLCAiUi5zcSIsICJSLmFkaiIsICJDcCIsICJBSUMiLCAiU0JDIiwgIlBSRVNTIikKIHRibAogfQoKYGBgCgoKTm90ZTogRHVlIHRvIHRoZSBzaXplIG9mIHRoZSBkYXRhIHNldCBSU3R1ZGlvIHdhcyB1bmFibGUgdG8gZnVuIHRoZSBjb2RlIG9uIEdvb2RuZXNzIG9mIEZpdCBjb3VsZCBub3QgcnVuIHdpdGhvdXQgY3Jhc2hpbmcgUlN0dWRpbyBvciBleGhhdXN0aW5nIHRoZSBtZW1vcnkgdmVjdG9yLiBUbyByZW1lZHkgdGhpcyBpc3N1ZSwgYSByYW5kb20gc2FtcGxlIG9mIDEwLDAwMCBvYnNlcnZhdGlvbnMgd2FzIHRha2VuIGZyb20gdGhlIGRhdGEgc2V0IGFuZCB1c2VkIGZvciB0aGUgdGhlIGZvbGxvd2luZyBjb2RlLiBBbnl0aGluZyB1c2luZyB0aGlzIHJhbmRvbSBzYW1wbGUgZGF0YSBzZXQgaXMgZGVwaWN0ZWQgYnkgZW5kaW5nIGluIC5yYW5kLiBEdWUgdG8gdGhpcyBjaGFuZ2UgaW4gdGhlIGRhdGEgc2V0LCB0aGUgUS1RIHBsb3RzIHdlcmUgcmVwcmludGVkIHRvIG1ha2Ugc3VyZSB0aGlzIHNtYWxsZXIgc2FtcGxlIG9mIHRoZSBkYXRhIHdhcyBzdGlsbCBhbiBhY2N1cmF0ZSByZXByZXNlbnRhdGlvbiBvZiB0aGUgbGFyZ2VyIGRhdGEgc2V0LgoKYGBge3J9CgpmaW5hbC5kYXRhLnJhbmQgPC0gZmluYWwuZGF0YVtzYW1wbGUobnJvdyhmaW5hbC5kYXRhKSwgc2l6ZSA9IDEwMDAwLCByZXBsYWNlID0gRkFMU0UpLCBdCmZ1bGwubW9kZWwucmFuZCA9IGxtKGJtaSB+IC4sIGRhdGEgPSBmaW5hbC5kYXRhLnJhbmQpCmxvZy5ibWkucmFuZCA9IGxtKGxvZyhibWkpIH4gYWdlICsgaHlwZXJ0ZW5zaW9uICsgaGVhcnRfZGlzZWFzZSArICBIYkExY19sZXZlbAogICAgICAgKyBibG9vZF9nbHVjb3NlX2xldmVsICsgZGlhYmV0ZXMgKyBwcmVkaWFiZXRpYywgZGF0YSA9IGZpbmFsLmRhdGEucmFuZCkKYm1pLmxvZy5hZ2UucmFuZCA9IGxtKChibWkpXi0wLjUgfiBsb2coYWdlKSArIGh5cGVydGVuc2lvbiArIGhlYXJ0X2Rpc2Vhc2UgKyAgSGJBMWNfbGV2ZWwKICAgICAgICsgYmxvb2RfZ2x1Y29zZV9sZXZlbCArIGRpYWJldGVzICsgcHJlZGlhYmV0aWMsIGRhdGEgPSBmaW5hbC5kYXRhLnJhbmQpCgpgYGAKCgpgYGB7cn0KCnBhcihwdHkgPSAicyIsIG1mcm93ID0gYygxLCAzKSkKI1EtUSBwbG90IGZvciBvcmlnaW5hbCBtb2RlbApxcW5vcm0oZnVsbC5tb2RlbC5yYW5kJHJlc2lkdWFscywgbWFpbiA9ICJGdWxsLU1vZGVsIikKcXFsaW5lKGZ1bGwubW9kZWwucmFuZCRyZXNpZHVhbHMpCiNRLVEgcGxvdCBmb3IgQm94LUNveCB0cmFuc2Zvcm1lZCBtb2RlbApxcW5vcm0obG9nLmJtaS5yYW5kJHJlc2lkdWFscywgbWFpbiA9ICJMb2cgQk1JIikKcXFsaW5lKGxvZy5ibWkkcmVzaWR1YWxzKQojZGlzcGxheSBib3RoIFEtUSBwbG90cwpxcW5vcm0oYm1pLmxvZy5hZ2UucmFuZCRyZXNpZHVhbHMsIG1haW4gPSAiQk1JIGxvZyBBZ2UiKQpxcWxpbmUoYm1pLmxvZy5hZ2UkcmVzaWR1YWxzKQpgYGAKClRoZSBRLVEgcGxvdHMgZm9yIHRoZSAxMCwwMDAgb2JzZXJ2YXRpb24gZGF0YSBzZXQgaXMgc2ltaWxhciB0byB0aGUgUS1RIHBsb3RzIGZvciB0aGUgMTAwLDAwMCBvYnNlcnZhdGlvbiBkYXRhIHNldC4gTm93LCBpdCBpcyBwb3NzaWJsZSB0byBtb3ZlIGZvcndhcmQgd2l0aCB0aGUgR29vZG5lc3Mtb2YtRml0IHRlc3RzLgoKCgpgYGAge3J9Cm91dHB1dC5zdW0gPSByYmluZChzZWxlY3QoZnVsbC5tb2RlbC5yYW5kKSwgc2VsZWN0KGJtaS5sb2cuYWdlLnJhbmQpLCBzZWxlY3QobG9nLmJtaS5yYW5kKSkKcm93Lm5hbWVzKG91dHB1dC5zdW0pID0gYygiZnVsbC5tb2RlbC5yYW5kIiwgImJtaS5sb2cuYWdlLnJhbmQiLCAibG9nLmJtaS5yYW5kIikKa2FibGUob3V0cHV0LnN1bSwgY2FwdGlvbiA9ICJHb29kbmVzcy1vZi1maXQgTWVhc3VyZXMgb2YgQ2FuZGlkYXRlIE1vZGVscyIpCmBgYAoKTG9va2luZyBhdCB0aGUgb3V0cHV0cyBmb3IgKiokUl4yLCBSXjJfe2Fkan0kLCBhbmQgJENfcCQqKiBpdCBpcyBjbGVhciB0aGF0IHRoZSBzZWNvbmQgbW9kZWwsIGJtaS5sb2cuYWdlLnJhbmQgaXMgdGhlIGJlc3Qgb2YgdGhlIHRocmVlIG1vZGVscy4gVGhpcyBtZWFucyB0aGUgc2Vjb25kIG1vZGVsIHdpbGwgYmUgdGhlIGZpbmFsIG1vZGVsLiAKCiMjIEZpbmFsIE1vZGVsCgpgYGAge3J9CgprYWJsZShzdW1tYXJ5KGJtaS5sb2cuYWdlKSRjb2VmLCBjYXB0aW9uID0gIkluZmVyZW50aWFsIFN0YXRpc3RpY3Mgb24gdGhlIEZpbmFsIE1vZGVsIikKCmBgYAoKRHVlIHRoZSBkYXRhIHNldCBoYXMgb3ZlciAxMDAsMDAwIG9ic2VydmF0aW9ucyB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtIGNhbiBiZSB1c2VkIGFzIHRoZSBhcmd1bWVudCBmb3IgdmFsaWRhdGluZyB0aGUgcC12YWx1ZXMuIFRoZSB2YXJpYWJsZXMgbG9nKGFnZSksIGh5cGVydGVuc2lvbiwgaGVhcnRfZGlzZWFzZSwgYW5kIGRpYWJldGVzIGFsbCBkZXBpY3QgcC12YWx1ZXMgY2xvc2UgdG8gemVybyBtZWFuaW5nIHRoZWlyIGNvZWZmaWNpZW50cyBhcmUgc2lnbmlmY2FudGx5IGRpZmZlcm50IGZyb20gMC4gSG93ZXZlciwgdGhlIHZhcmlhYmxlcyBIYkExY19sZXZlbCwgYmxvb2RfZ2x1Y29zZV9sZXZlbCwgYW5kIHByZWRpYWJldGljIGhhdmUgcC12YWx1ZXMgbXVjaCBoaWdoZXIgdGhhbiAwIHdoaWNoIG1lYW5zIHRoZXNlIHZhcmlhYmxlcyBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgd2hlbiBpdCBjb21lcyB0byB0aGUgcHJlZGljdGlvbiBvZiBibWkuICAKCgojIFJlc3VsdHMgYW5kIENvbmNsdXNpb24KCiMjIFN1bW1hcnkgb2YgTW9kZWwgCgpUaGUgZmluYWwgbW9kZWwgY2FuIGJlIHdyaXR0ZW4gYXMgZm9sbG93cywgCgpibWkgPSAwLjI0MjIgLSAwLjAxMzM1IHggbG9nKGFnZSkgLSAwLjAwMjc2OCB4IGh5cGVydGVuc2lvbiArIDAuMDA0MDI0IHggaGVhcnRfZGlzZWFzZSAtIDAuMDA3OTExIHggZGlhYmV0ZXMKClRoZSB2YXJpYWJsZXMgbG9nKGFnZSksIGhweWVydGVuc2lvbiBhbmQgZGlhYmV0ZXMgYWxsIGhhdmUgYSBuZWdhdGl2ZSBhc3NvY2lhdGlvbiB3aXRoIGJtaSB3aGlsZSBoZWFydF9kaXNlYXNlIGlzIHRoZSBvbmx5IHZhcmlhYmxlIHdpdGggYSBwb3NpdGl2ZSBhc3NvY2lhdGlvbi4gCgojIEdlbmVyYWwgRGlzY3Vzc2lvbiAKClNldmVyYWwgcmVncmVzc2lvbiB0ZWNobmlxdWVzLCBpbmNsdWRpbmcgdGhlIEJveC1jb3ggdHJhbnNmb3JtYXRpb24gd2FzIHVzZWQgdG8gZGV0ZXJtaW5lIHRoZSBmaW5hbCBtb2RlbCBpbiB0aGlzIHN0dWR5LiBXaGlsZSB0aGUgZmluYWwgZGF0YSBzZXQgY29uc2lzdHMgb2YgOCB2YXJpYWJsZXMsIDMgb2YgdGhlbSB3ZXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGFuZCB0aHVzIHdlcmUgbm90IHVzZWQgaW4gdGhlIGZpbmFsIG1vZGVsLiBBbGwgb2YgdGhlIG1vZGVscyB0aGF0IHdlcmUgY29tcGFyZWQgdXNpbmcgdGhlIGdvb2RuZXNzLW9mLWZpdCBtZWFzdXJlIG1vZGVsIGNyaXRlcmlhIGNvbnNpc3RlZCBvZiB0aGUgc2FtZSA4IHZhcmlhYmxlcy4gCgpIb3dldmVyLCBkdWUgdG8gdGhlIHNpemUgb2YgdGhlIG9yaWdpbmFsIGZpbmFsIGRhdGEgc2V0IGJlaW5nIHNpZ25pZmljYW50bHkgbGFyZ2UsIHdpdGggb3ZlciAxMDAsMDAwIG9ic2VydmF0aW9ucywgYSBzbWFsbGVyIHJhbmRvbSBzYW1wbGUgb2YgdGhlIGZpbmFsIGRhdGEgc2V0LCBjb25zaXN0aW5nIG9mIDEwLDAwMCBvYnNlcnZhdGlvbnMgd2FzIGNyZWF0ZWQgdG8gcnVuIHRoZSBnb29kbmVzcy1vZi1maXQgbWVhc3VyZSBpbiBhIHdheSB0aGF0IGRpZCBub3Qgc2h1dGRvd24gUlN0dWRpby4gQWRkaXRpb25hbGx5LCB0aGUgZ29vZG5lc3Mtb2YtZml0IG1lYXN1cmUgd2FzIHVzZWQgZHVlIHRvIHRoZSBmYWN0IHRoYXQgdGhlIHZpb2xhdGlvbiB0byB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gb24gdGhlIHJlc2lkdWFscy4gVGhpcyBub3JtYWxpdHkgYXNzdW1wdGlvbiByZW1haW5zIHVuY29ycmVjdGVkIGV2ZW4gYWZ0ZXIgc2V2ZXJhbCB0cmFuc2Zvcm1hdGlvbiB0ZWNobmlxdWVzIHdlcmUgdXNlZCBvbiB0aGUgZGF0YSBzZXQuIFRoZSBjZW50cmFsIGxpbWl0IHRoZW9yZW0gKENMVCkgd2FzIHVzZWQgdG8gYmFzZSBpbmZlcmVuY2VzIG9uIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cy4gCgpUaGUgZmluYWwgbW9kZWwgdXNlZCB0aGUgbG9nKGFnZSkgQm94LWNveCB0cmFuc2Zvcm1hdGlvbiB3aXRoIGEgLTAuNSBhZGp1c3RtZW50IG9uIGJtaS4gVGhpcyBtb2RlbCB3YXMgc2VsZWN0ZWQgb3ZlciB0aGUgZnVsbCBtb2RlbCBhbmQgdGhlIGxvZyhibWkpIG1vZGVsIGJlY2F1c2UgZXZlbiB0aG91Z2ggbm9uZSBvZiB0aGUgbW9kZWxzIG1ldCB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gdGhlIGxvZyhhZ2UpIG1vZGVsIGhhZCB0aGUgYmVzdCAqKiRSXjIsIFJeMl97YWRqfSQsIGFuZCAkQ19wJCoqIG91dHB1dHMgYWZ0ZXIgcnVubmluZyB0aGUgZ29vZG5lc3Mtb2YtZml0IG1lYXN1cmUgb24gYWxsIHRocmVlIG1vZGVscy4gQWRkaXRpb25hbGx5LCBmcm9tIHRoZSBzZWxlY3RlZCBmaW5hbCBtb2RlbCwgdGhyZWUgdmFyaWFibGVzIHdlcmUgcmVtb3ZlZCBmcm9tIHRoZSBvcmlnaW5hbCBlaWdodCBkdWUgdG8gdGhlbSBoYXZpbmcgbm9uLXNpZ25pZmljYW50IHAtdmFsdWVzLiBBZnRlciByZW1vdmluZyB0aG9zZSB2YXJpYWJsZXMgdGhlIGZpbmFsIG1vZGVsIHdhcyBjb21wbGV0ZS4gCgojIFJlZmVyZW5jZXMKCkFtZXJpY2FuIERpYWJldGVzIEFzc29jaWF0aW9uLiAoMjAyMykuIFVuZGVyc3RhbmRpbmcgRGlhYmV0ZXMgRGlhZ25vc2lzLiBEaWFiZXRlcy5vcmcuIGh0dHBzOi8vZGlhYmV0ZXMub3JnL2Fib3V0LWRpYWJldGVzL2RpYWdub3NpcwoKCgo=