EDA & Feature
Engineering
Before conducting the analysis it is important to make some edits to
the variables in the data set. First, starting with the variable Day, it
is currently a character variable, meaning we can not really use it to
conduct meaningful analysis. To fix the variable to make it more useful,
it needs to be changed to a factor variable, where each day of the week
is its own factor, “Monday”, “Tuesday”, etc. Next, we are going to
combine the variables HighTemp and LowTemp to create a new variable
called AvgTemp, which will take the average of the high and low
temperature.
bridge.new = bridge
bridge.new$Day = as.factor(bridge$Day)
bridge.new$AvgTemp = (bridge$HighTemp + bridge$LowTemp)/2
bridge.new$NewPrecip <- NA
for(i in 1:nrow(bridge)) {
if (bridge$Precipitation[i] > 0) {
bridge.new$NewPrecip[i] <- 1
} else if (bridge$Precipitation[i] == 0) {
bridge.new$NewPrecip[i] <- 0
}
}
bridge.final = subset(bridge.new, select = -c(HighTemp, LowTemp, Precipitation))
Now, we have our final data set, bridge.final which still consists of
the same 30 observations but now only has 6 variables which are as
followed. 1. Date: (chr) Used as the ID variable, the date that the
observation was recorded 2. Day (factor) The day of the week the
observation was recorded 3. QueensboroBridge (int) The total amount of
cyclists who entered and exited the Queensboro Bridge on the date of the
observation 4. Total (int) The total amount of cyclists who entered and
exited any of the four bridges on the date of the observation 5. AvgTemp
(num) The average of the HighTemp and LowTemp variables. 6. NewPrecip
(int) This is a binary categorical variable, if NewPrecip equals 0 that
means there was no precipitation on that day. If NewPrecip equals 1 that
means there was precipitation on that day.
Methodology &
Analysis
pois.model.1 = glm(QueensboroBridge ~ Day + AvgTemp + NewPrecip,
family = poisson(link="log"), data =bridge.final)
yhat.1 = pois.model.1$fitted.values
pearson.resid.1 = (bridge.final$QueensboroBridge - yhat.1)/sqrt(yhat.1)
Pearson.disp.1 = sum(pearson.resid.1^2)/pois.model.1$df.residual
Deviance.disp.1 = (pois.model.1$deviance)/pois.model.1$df.residual
disp = cbind(Pearson.disp.1 = Pearson.disp.1, Deviance.disp.1 = Deviance.disp.1)
kable(disp, caption="Dispersion parameter for Primary Model", align = 'c')
Dispersion parameter for Primary Model
154.3321 |
158.8547 |
As seen above the poisson model resulted in a Pearson Dispersion of
154.3321 and a Residual Dispersion of 158.8547. Considering that the
preferred dispersion is 1, this model highly violates the model
assumptions. Since the model assumptions are so heavily violated, we
have to look into using a different model. Considering the models we
used in the previous assignment, the next model we are going to test is
going to consider the total cyclists that day.
pois.model.2 = glm(QueensboroBridge ~ Day + AvgTemp + NewPrecip, offset = log(Total),
family = poisson(link = "log"), data = bridge.final)
yhat.2 = pois.model.2$fitted.values
pearson.resid.2 = (bridge.final$QueensboroBridge - yhat.2)/sqrt(yhat.2)
Pearson.disp.2 = sum(pearson.resid.2^2)/pois.model.2$df.residual
Deviance.disp.2 = (pois.model.2$deviance)/pois.model.2$df.residual
disp = cbind(Pearson.disp.2 = Pearson.disp.2, Deviance.disp.2 = Deviance.disp.2)
kable(disp, caption="Dispersion parameter for Secondary Model", align = 'c')
Dispersion parameter for Secondary Model
7.059385 |
6.980342 |
As seen above, the secondary model, which considers an offset of the
Total, produced a much better dispersion parameter, compared to the
primary model. The Pearson Dispersion for the model is 7.059385, and the
Deviance Dispersion is 6.980342. While still not ideal dispersion
parameters, considering that the previous model had dispersion
parameters in the 150s, these single digit dispersion parameters clearly
show that this second model is the better model. To help adjust for the
standard error, we are going to be fitting the quasi-poisson model when
summarizing the inferential statistics.
The next step will be to summarize the inferential statistics in the
table below.
quasi.model = glm(QueensboroBridge ~ Day + AvgTemp + NewPrecip, offset = log(Total),
family = quasipoisson, data =bridge.new)
summary(quasi.model)
##
## Call:
## glm(formula = QueensboroBridge ~ Day + AvgTemp + NewPrecip, family = quasipoisson,
## data = bridge.new, offset = log(Total))
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.226290 0.066584 -18.417 1.94e-14 ***
## DayMonday -0.030650 0.030089 -1.019 0.31997
## DaySaturday -0.020246 0.031527 -0.642 0.52771
## DaySunday -0.046129 0.031043 -1.486 0.15215
## DayThursday -0.001740 0.031739 -0.055 0.95679
## DayTuesday -0.001009 0.031764 -0.032 0.97495
## DayWednesday -0.016404 0.031554 -0.520 0.60859
## AvgTemp -0.003966 0.001048 -3.783 0.00109 **
## NewPrecip 0.054764 0.020018 2.736 0.01239 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for quasipoisson family taken to be 7.059392)
##
## Null deviance: 412.64 on 29 degrees of freedom
## Residual deviance: 146.59 on 21 degrees of freedom
## AIC: NA
##
## Number of Fisher Scoring iterations: 3
SE.quasi.pois = summary(quasi.model)$coef
kable(SE.quasi.pois, caption = "Summary statistics of quasi-poisson regression model")
Summary statistics of quasi-poisson regression model
(Intercept) |
-1.2262901 |
0.0665841 |
-18.4171596 |
0.0000000 |
DayMonday |
-0.0306504 |
0.0300895 |
-1.0186431 |
0.3199652 |
DaySaturday |
-0.0202462 |
0.0315274 |
-0.6421772 |
0.5277070 |
DaySunday |
-0.0461286 |
0.0310428 |
-1.4859659 |
0.1521474 |
DayThursday |
-0.0017402 |
0.0317393 |
-0.0548269 |
0.9567946 |
DayTuesday |
-0.0010095 |
0.0317640 |
-0.0317805 |
0.9749472 |
DayWednesday |
-0.0164039 |
0.0315536 |
-0.5198750 |
0.6085879 |
AvgTemp |
-0.0039665 |
0.0010484 |
-3.7833396 |
0.0010893 |
NewPrecip |
0.0547639 |
0.0200177 |
2.7357770 |
0.0123852 |
The estimated dispersion index based on the Pearson residuals is
7.06. Looking at the quasi-poisson regression above, all of the factors
for Day variable are insignificant, with p-values ranging from p-value =
0.15215 to p-value = 0.97495. Since all the factors are insignificant,
we are going to refit the quasi-poisson model by dropping the variable
Day.
quasi.model.new = glm(QueensboroBridge ~ AvgTemp + NewPrecip, offset = log(Total),
family = quasipoisson, data =bridge.final)
kable(summary(quasi.model.new)$coef, caption = "Inferential statistics of
the Quasi-Poisson regression coefficients in the final model.")
Inferential statistics of the Quasi-Poisson regression
coefficients in the final model.
(Intercept) |
-1.2462434 |
0.0604994 |
-20.599270 |
0.0000000 |
AvgTemp |
-0.0039704 |
0.0009886 |
-4.016345 |
0.0004238 |
NewPrecip |
0.0619572 |
0.0171914 |
3.603953 |
0.0012491 |
The new model, shown above, that has been refitted without the
variable day, will be used as the final model. Since the response
variable of the model is on a log scale, and additionally there is an
offset of the log Total, the interpretation of the regression
coefficient of the poisson model is not a simple or straightforward
procedure.
In context, the coefficient for NewPrecip is 0.0619572, this is the
estimated poisson regression coefficient comparing days with and without
precipitation, given the other variable are being held constant. The
difference in log of cyclists on the Queensboro Bridge, offset by the
log of total cyclists, is expected to be 0.0619572 units higher on days
with precipitation compared to days without precipitation while other
variables are held constant in the model.
Visual Analysis
To conduct this visual analysis there is going to be an additional
breakdown of the model. A new variable called HighLowTemp is going to be
created. This variable will be a binary categorical variable in which
the variable will equal 0 if the AvgTemp was lower than the mean
temperature across the entire month of April and it will equal 1 if it
is higher or equal to the mean temperature. After running some
additional code, it has been calculated that the mean temperature for
the month of April is 57.23 degrees Fahrenheit.
mean(bridge.new$AvgTemp)
## [1] 57.23167
for(i in 1:nrow(bridge)) {
if (bridge.new$AvgTemp[i] >= 57.23) {
bridge.final$HighLowTemp[i] <- 1
} else if (bridge.new$AvgTemp[i] < 57.23) {
bridge.final$HighLowTemp[i] <- 0
}
}
quasi.model.new = glm(QueensboroBridge ~ AvgTemp + NewPrecip, offset = log(Total),
family = quasipoisson, data =bridge.final)
kable(summary(quasi.model.new)$coef, caption = "Inferential statistics of
the Quasi-Poisson regression coefficients in the final model.")
Inferential statistics of the Quasi-Poisson regression
coefficients in the final model.
(Intercept) |
-1.2462434 |
0.0604994 |
-20.599270 |
0.0000000 |
AvgTemp |
-0.0039704 |
0.0009886 |
-4.016345 |
0.0004238 |
NewPrecip |
0.0619572 |
0.0171914 |
3.603953 |
0.0012491 |
After readjusting AvgTemp to HighLowTemp, we can see that the
variable is still statistically significant and we can move forward with
the visual analysis that is planned.
The goal of the visualization is to show how the explanatory
variables in the final model impact the actual number of cyclists on the
Queensboro Bridge.
For this visualization all days will be classified as one of four of
the following groups, by precipitation and temperature.
day.0 = days with no precipitation
day.1 = days with precipitation
Now, it is time to exponentiate the log count of cyclists on the
Queensboro Bridge to the actual number of cyclists. Then we will create
a graph that shows the relationship between cyclists and different
weather conditions in terms of number of cyclists riding in each of the
groups above.
temp = range(bridge.final$AvgTemp)[1]:range(bridge.final$AvgTemp)[2]
day.0 = -1.2462434 - 0.0039704*temp + (offset = log(bridge.final$Total))
day.1 = -1.2462434 + 0.0619572 - 0.0039704*temp + (offset = log(bridge.final$Total))
##
plot(temp, exp(day.0), ylim=c(0,6000),
type = "l",
col = "red",
lty = 1,
ylab = "Queensboro Bridge Cyclists",
xlab = "Average Temperature",
main = "Factors That Impact Cyclist Turnout")
lines(temp, exp(day.1), col = "blue", lty = 2)
legend("topleft", c("no precipitation", "precipitation"),
col=c("red", "blue"), lty=1:2, bty="n", cex=0.8)

The graph shows there does not seem to be a large significant
difference between days with no precipitation vs days with
precipitation. However, out of the two there does to be slightly less
cyclist turnout on days without precipitation. Additionally, the graph
shows that there is not a consistent increase or decrease in cyclist
turnout as average temperature increases or decreases. Instead, the
cyclist turnout seems to have a very sporadic relationship to average
temperature, with high spikes and low divots.
General
Discussions
It is important to acknowledge the shortcomings of this model,
starting with the dispersion parameters. While a dispersion parameter of
approximately 7 looked great in comparison to the first models
dispersion parameter of over 150, a 7 is still without side a preferred
range. Ideally, since getting a dispersion parameter any closer to 1
seems highly unlikely, especially considering this project had variable
parameters that were required, realistically a different model should
have been used, most likely a negative binomial. However, since this
project requested a poisson model be used we stuck with the model that
had the least egregious model assumptions.
This project also required the creation and use of two new variables
in our model, AvgTemp and NewPrecip. These new variables were meant to
replace the variables HighTemp, LowTemp and Precipitation, and to me
used in the model building with the variable Day. In our previous
analysis, we saw some factors of the variable day have some statistical
significance, and even talked about making an argument for grouping them
with further analysis. Unfortunately, in this analysis, the new model
with the new variables did not result in any of the factors of the
variable day yielding any statistical significance, making grouping a
moot point. Since none of the factors were statistically significant, we
had to drop the variable Day, leaving us with only two variables, which
is less than ideal. Only analysis two variables gives us less
opportunities to analyse the relationship to other variables and the
response, so ideally it would have been better to use a model that
showed at least some of the factors of day to be significant so the
variable did not have to be dropped.
Finally, as mentioned earlier and in the previous report, this is a
subset of a much larger data set. This subset only covers one month for
one bridge, of a data set that spans one year and covers four different
bridges. Without being able to compare this to other sections of the
data set we are missing crucial information. How does the Queensboro
Bridge compare in cyclist count to other bridges? How does the month of
April compare in cyclist counts to other months? Is the Queensboro
Bridge or the month of April and outlier? Seeing a significantly higher
or lower amount of cyclists compared to other bridges or months. This is
information we can not know without being able to analyze, the full, or
at the very least additionally subsets of, the data set. For the
conclusions drawn regarding this subset to be meaningful and hold proper
importance, it needs to be interpreted in comparison to the larger data
set so that both those conducting the analysis and those reading the
report have the best understanding of the context surrounding the data
set.
Overall, while not the perfect model or perfect circumstances for
analysis, we have to make the best conclusions with the information we
have. Thus, this model dictates that the AvgTemp and NewPrecip have a
statisticaly significant impact on the cyclist turnout for the
Queensboro Bridge in April.
LS0tCnRpdGxlOiAiRGlzcGVyc2VkIFBvaXNzb24gUmVncmVzc2lvbiBmb3IgQ3ljbGlzdCBDb3VudCIKYXV0aG9yOiAiQ2hsb8OpIFdpbnRlcnMiCmRhdGU6ICIxMS8xMC8yMDI0IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfd2lkdGg6IDYKICAgIGZpZ19oZWlnaHQ6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHBkZl9kb2N1bWVudDogCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnNCcKLS0tCmBgYHs9aHRtbH0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CgovKiBDYXNjYWRpbmcgU3R5bGUgU2hlZXRzIChDU1MpIGlzIGEgc3R5bGVzaGVldCBsYW5ndWFnZSB1c2VkIHRvIGRlc2NyaWJlIHRoZSBwcmVzZW50YXRpb24gb2YgYSBkb2N1bWVudCB3cml0dGVuIGluIEhUTUwgb3IgWE1MLiBpdCBpcyBhIHNpbXBsZSBtZWNoYW5pc20gZm9yIGFkZGluZyBzdHlsZSAoZS5nLiwgZm9udHMsIGNvbG9ycywgc3BhY2luZykgdG8gV2ViIGRvY3VtZW50cy4gKi8KCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovCiAgZm9udC1zaXplOiAyNHB4OwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7Cn0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLwogIGZvbnQtc2l6ZTogMjBweDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDIycHg7CiAgICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IG5hdnk7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgpoMyB7IC8qIEhlYWRlciAzIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCAzIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDE4cHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgNCBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9CgouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQoKcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0KCjwvc3R5bGU+CmBgYApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KCiMKIyBzcGVjaWZpY2F0aW9ucyBvZiBvdXRwdXRzIG9mIGNvZGUgaW4gY29kZSBjaHVua3MKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgIAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCAgCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzICA9IFRSVUUgICAgIAogICAgICAgICAgICAgICAgICAgICAgKSAgIAoKbGlicmFyeShrbml0cikKbGlicmFyeShwYW5kZXIpCmxpYnJhcnkobWxiZW5jaCkKbGlicmFyeShNQVNTKQpsaWJyYXJ5KG9wZW54bHN4KQpgYGAKCiMgSW50cm9kdWN0aW9uCgpUaGlzIGFzc2lnbm1lbnQgd2lsbCBmdXJ0aGVyIGFuYWx5emUgYmlrZSBjb3VudCBkYXRhIGZvciBzZXZlcmFsIGJyaWRnZXMsIGtlZXBpbmcgYSBjb3VudCBvZiBjeWNsaXN0cyBlbnRlcmluZyBhbmQgbGVhdmluZyB0aGUgYnJpZGdlLiBUaGlzIGFzc2lnbm1lbnQgd2lsbCB1dGlsaXplIGEgZGlzcGVyc2VkIHBvaXNzb24gcmVncmVzc2lvbiB0byBsb29rIGF0IHRoZSBjeWNsaXN0IGNvdW50IGZvciBhIHBhcnRpY3VsYXIgYnJpZGdlIG9uIGRpZmZlcmVudCBkYXlzIG9mIHRoZSB3ZWVrLiBBZGRpdGlvbmFsbHksIHRoaXMgYXNzaWdubWVudCB3aWxsIG1vZGlmeSBzb21lIG9mIHRoZSB2YXJpYWJsZXMgdG8gYmV0dGVyIGZpdCBhIGRpc3BlcnNlZCBwb2lzc29uIHJlZ3Jlc3Npb24gYW5hbHlzaXMuIAoKCgojIE1hdGVyaWFscwoKIyMgRGF0YSBTZXQKCkEgZGFpbHkgdG90YWwgYmlrZSBjb3VudCB3YXMgY29uZHVjdGVkIG1vbnRobHkgb24gZm91ciBkaWZmZXJlbnQgYnJpZGdlcyBpbiBOZXcgWW9yaywgdGhlIEJyb29rbHluIEJyaWRnZSwgTWFuaGF0dGFuIEJyaWRnZSwgV2lsbGlhbXNidXJnIEJyaWRnZSwgYW5kIFF1ZWVuc2Jvcm8gQnJpZGdlLiBUaGUgYmlrZSB0b3RhbCBrZXB0IGNvdW50IG9mIHRoZSB0b3RhbCBjeWNsaXN0cyBlbnRlcmluZyBhbmQgbGVhdmluZyBlYWNoIGJyaWRnZSBvbiBhIGdpdmVuIGRheS4gVGhlIGNvdW50IGRhdGEgd2FzIGNvbGxlY3RlZCBieSB0aGUgVHJhZmZpYyBJbmZvcm1hdGlvbiBNYW5hZ2VtZW50IFN5c3RlbSAoVElNUykuIEVhY2ggcmVjb3JkZWQgcmVzcG9uc2UgcmVwcmVzZW50cyB0aGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIHRoYXQgZW50ZXJlZCBhbmQgbGVmdCB0aGF0IGJyaWRnZSBpbiBhIDI0IGhvdXIgcGVyaW9kLiAKCgpgYGB7cn0KdXJsPSJodHRwczovL0NobG9lV2ludGVyczc5LmdpdGh1Yi5pby9TVEEzMjEvRGF0YS9RdWVlbnNib3JvQnJpZGdlLmNzdiIKYnJpZGdlID0gcmVhZC5jc3YodXJsLCBoZWFkZXIgPSBUUlVFKQpgYGAKCgpUaGlzIHByb2plY3QgZGlkIGEgcmFuZG9tIGFzc2lnbm1lbnQgb2YgYSBzcGVjaWZpYyBzdWJzZXQgb2YgdGhlIGRhdGEgZm9yIG91ciBhbmFseXNpcy4gVGhlIHN1YnNldCBpcyBmb3Igb25lIG9mIHRoZSBmb3VyIGJyaWRnZXMgb3ZlciBhIG9uZSBtb250aCBwZXJpb2QgZnJvbSB0aGUgZmlyc3QgZGF5IG9mIHRoZSBtb250aCB0byBsYXN0IGRheSBvZiB0aGUgbW9udGguIFRoZSBzcGVjaWZpYyBzdWJzZXQgYXNzaWduZWQgZm9yIHRoaXMgcHJvamVjdCB3YXMgZm9yIHRoZSBRdWVlbnNib3JvIGJyaWRnZSBmb3IgdGhlIG1vbnRoIG9mIEFwcmlsLiBUaGUgZGF0YSBzZXQgaXMgY2FsbGVkIGJyaWRnZSBhbmQgY29uc2lzdHMgb2YgNyB2YXJpYWJsZXMgYW5kIDMwIHRvdGFsIG9ic2VydmF0aW9ucy4gV2hlbiB0aGUgZGF0YSBzZXQgaXMgZmlyc3QgcmVhZCBpbiB0aGUgdmFyaWFibGVzIGFyZSBhcyBmb2xsb3dlZC4gCgoxLiAgRGF0ZTogKGNocikgVXNlZCBhcyB0aGUgSUQgdmFyaWFibGUsIHRoZSBkYXRlIHRoYXQgdGhlIG9ic2VydmF0aW9uIHdhcyByZWNvcmRlZAoyLiAgRGF5IChjaHIpIFRoZSBkYXkgb2YgdGhlIHdlZWsgdGhlIG9ic2VydmF0aW9uIHdhcyByZWNvcmRlZAozLiAgSGlnaFRlbXAgKG51bSkgVGhlIGhpZ2ggdGVtcGVyYXR1cmUgb24gdGhlIGRhdGUgb2YgdGhlIG9ic2VydmF0aW9uCjQuICBMb3dUZW1wIChudW0pIFRoZSBsb3cgdGVtcGVyYXR1cmUgb24gdGhlIGRhdGUgb2YgdGhlIG9ic2VydmF0aW9uCjUuICBQcmVjaXBpdGF0aW9uIChudW0pIFRoZSBhbW91bnQgb2YgcHJlY2lwaXRhdGlvbiByZWNlaXZlZCBvbiB0aGUgZGF0ZSBvZiB0aGUgb2JzZXJ2YXRpb24KNi4gIFF1ZWVuc2Jvcm9CcmlkZ2UgKGludCkgVGhlIHRvdGFsIGFtb3VudCBvZiBjeWNsaXN0cyB3aG8gZW50ZXJlZCBhbmQgZXhpdGVkIHRoZSBRdWVlbnNib3JvIEJyaWRnZSBvbiB0aGUgZGF0ZSBvZiB0aGUgb2JzZXJ2YXRpb24KNy4gVG90YWwgKGludCkgVGhlIHRvdGFsIGFtb3VudCBvZiBjeWNsaXN0cyB3aG8gZW50ZXJlZCBhbmQgZXhpdGVkIGFueSBvZiB0aGUgZm91ciBicmlkZ2VzIG9uIHRoZSBkYXRlIG9mIHRoZSBvYnNlcnZhdGlvbgoKIyBFREEgJiBGZWF0dXJlIEVuZ2luZWVyaW5nCgpCZWZvcmUgY29uZHVjdGluZyB0aGUgYW5hbHlzaXMgaXQgaXMgaW1wb3J0YW50IHRvIG1ha2Ugc29tZSBlZGl0cyB0byB0aGUgdmFyaWFibGVzIGluIHRoZSBkYXRhIHNldC4gRmlyc3QsIHN0YXJ0aW5nIHdpdGggdGhlIHZhcmlhYmxlIERheSwgaXQgaXMgY3VycmVudGx5IGEgY2hhcmFjdGVyIHZhcmlhYmxlLCBtZWFuaW5nIHdlIGNhbiBub3QgcmVhbGx5IHVzZSBpdCB0byBjb25kdWN0IG1lYW5pbmdmdWwgYW5hbHlzaXMuIFRvIGZpeCB0aGUgdmFyaWFibGUgdG8gbWFrZSBpdCBtb3JlIHVzZWZ1bCwgaXQgbmVlZHMgdG8gYmUgY2hhbmdlZCB0byBhIGZhY3RvciB2YXJpYWJsZSwgd2hlcmUgZWFjaCBkYXkgb2YgdGhlIHdlZWsgaXMgaXRzIG93biBmYWN0b3IsICJNb25kYXkiLCAiVHVlc2RheSIsIGV0Yy4gTmV4dCwgd2UgYXJlIGdvaW5nIHRvIGNvbWJpbmUgdGhlIHZhcmlhYmxlcyBIaWdoVGVtcCBhbmQgTG93VGVtcCB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUgY2FsbGVkIEF2Z1RlbXAsIHdoaWNoIHdpbGwgdGFrZSB0aGUgYXZlcmFnZSBvZiB0aGUgaGlnaCBhbmQgbG93IHRlbXBlcmF0dXJlLiAKCmBgYHtyfQpicmlkZ2UubmV3ID0gYnJpZGdlCmJyaWRnZS5uZXckRGF5ID0gYXMuZmFjdG9yKGJyaWRnZSREYXkpCmJyaWRnZS5uZXckQXZnVGVtcCA9IChicmlkZ2UkSGlnaFRlbXAgKyBicmlkZ2UkTG93VGVtcCkvMgpicmlkZ2UubmV3JE5ld1ByZWNpcCA8LSBOQQoKZm9yKGkgaW4gMTpucm93KGJyaWRnZSkpIHsKICBpZiAoYnJpZGdlJFByZWNpcGl0YXRpb25baV0gPiAwKSB7CiAgICBicmlkZ2UubmV3JE5ld1ByZWNpcFtpXSA8LSAxICAKICB9IGVsc2UgaWYgKGJyaWRnZSRQcmVjaXBpdGF0aW9uW2ldID09IDApIHsKICAgIGJyaWRnZS5uZXckTmV3UHJlY2lwW2ldIDwtIDAgIAogIH0KfQoKYnJpZGdlLmZpbmFsID0gc3Vic2V0KGJyaWRnZS5uZXcsIHNlbGVjdCA9IC1jKEhpZ2hUZW1wLCBMb3dUZW1wLCBQcmVjaXBpdGF0aW9uKSkKYGBgCgpOb3csIHdlIGhhdmUgb3VyIGZpbmFsIGRhdGEgc2V0LCBicmlkZ2UuZmluYWwgd2hpY2ggc3RpbGwgY29uc2lzdHMgb2YgdGhlIHNhbWUgMzAgb2JzZXJ2YXRpb25zIGJ1dCBub3cgb25seSBoYXMgNiB2YXJpYWJsZXMgd2hpY2ggYXJlIGFzIGZvbGxvd2VkLiAKMS4gIERhdGU6IChjaHIpIFVzZWQgYXMgdGhlIElEIHZhcmlhYmxlLCB0aGUgZGF0ZSB0aGF0IHRoZSBvYnNlcnZhdGlvbiB3YXMgcmVjb3JkZWQKMi4gIERheSAoZmFjdG9yKSBUaGUgZGF5IG9mIHRoZSB3ZWVrIHRoZSBvYnNlcnZhdGlvbiB3YXMgcmVjb3JkZWQKMy4gIFF1ZWVuc2Jvcm9CcmlkZ2UgKGludCkgVGhlIHRvdGFsIGFtb3VudCBvZiBjeWNsaXN0cyB3aG8gZW50ZXJlZCBhbmQgZXhpdGVkIHRoZSBRdWVlbnNib3JvIEJyaWRnZSBvbiB0aGUgZGF0ZSBvZiB0aGUgb2JzZXJ2YXRpb24KNC4gVG90YWwgKGludCkgVGhlIHRvdGFsIGFtb3VudCBvZiBjeWNsaXN0cyB3aG8gZW50ZXJlZCBhbmQgZXhpdGVkIGFueSBvZiB0aGUgZm91ciBicmlkZ2VzIG9uIHRoZSBkYXRlIG9mIHRoZSBvYnNlcnZhdGlvbgo1LiBBdmdUZW1wIChudW0pIFRoZSBhdmVyYWdlIG9mIHRoZSBIaWdoVGVtcCBhbmQgTG93VGVtcCB2YXJpYWJsZXMuIAo2LiBOZXdQcmVjaXAgKGludCkgVGhpcyBpcyBhIGJpbmFyeSBjYXRlZ29yaWNhbCB2YXJpYWJsZSwgaWYgTmV3UHJlY2lwIGVxdWFscyAwIHRoYXQgbWVhbnMgdGhlcmUgd2FzIG5vIHByZWNpcGl0YXRpb24gb24gdGhhdCBkYXkuIElmIE5ld1ByZWNpcCBlcXVhbHMgMSB0aGF0IG1lYW5zIHRoZXJlIHdhcyBwcmVjaXBpdGF0aW9uIG9uIHRoYXQgZGF5LgoKIyBNZXRob2RvbG9neSAmIEFuYWx5c2lzCgpgYGB7cn0KcG9pcy5tb2RlbC4xID0gZ2xtKFF1ZWVuc2Jvcm9CcmlkZ2UgfiBEYXkgKyBBdmdUZW1wICsgTmV3UHJlY2lwLCAKICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbms9ImxvZyIpLCBkYXRhID1icmlkZ2UuZmluYWwpICAKCnloYXQuMSA9IHBvaXMubW9kZWwuMSRmaXR0ZWQudmFsdWVzCnBlYXJzb24ucmVzaWQuMSA9IChicmlkZ2UuZmluYWwkUXVlZW5zYm9yb0JyaWRnZSAtIHloYXQuMSkvc3FydCh5aGF0LjEpClBlYXJzb24uZGlzcC4xID0gc3VtKHBlYXJzb24ucmVzaWQuMV4yKS9wb2lzLm1vZGVsLjEkZGYucmVzaWR1YWwKCkRldmlhbmNlLmRpc3AuMSA9IChwb2lzLm1vZGVsLjEkZGV2aWFuY2UpL3BvaXMubW9kZWwuMSRkZi5yZXNpZHVhbAoKZGlzcCA9IGNiaW5kKFBlYXJzb24uZGlzcC4xID0gUGVhcnNvbi5kaXNwLjEsIERldmlhbmNlLmRpc3AuMSA9IERldmlhbmNlLmRpc3AuMSkKa2FibGUoZGlzcCwgY2FwdGlvbj0iRGlzcGVyc2lvbiBwYXJhbWV0ZXIgZm9yIFByaW1hcnkgTW9kZWwiLCBhbGlnbiA9ICdjJykKYGBgCgoKQXMgc2VlbiBhYm92ZSB0aGUgcG9pc3NvbiBtb2RlbCByZXN1bHRlZCBpbiBhIFBlYXJzb24gRGlzcGVyc2lvbiBvZiAxNTQuMzMyMSBhbmQgYSBSZXNpZHVhbCBEaXNwZXJzaW9uIG9mIDE1OC44NTQ3LiBDb25zaWRlcmluZyB0aGF0IHRoZSBwcmVmZXJyZWQgZGlzcGVyc2lvbiBpcyAxLCB0aGlzIG1vZGVsIGhpZ2hseSB2aW9sYXRlcyB0aGUgbW9kZWwgYXNzdW1wdGlvbnMuIFNpbmNlIHRoZSBtb2RlbCBhc3N1bXB0aW9ucyBhcmUgc28gaGVhdmlseSB2aW9sYXRlZCwgd2UgaGF2ZSB0byBsb29rIGludG8gdXNpbmcgYSBkaWZmZXJlbnQgbW9kZWwuIENvbnNpZGVyaW5nIHRoZSBtb2RlbHMgd2UgdXNlZCBpbiB0aGUgcHJldmlvdXMgYXNzaWdubWVudCwgdGhlIG5leHQgbW9kZWwgd2UgYXJlIGdvaW5nIHRvIHRlc3QgaXMgZ29pbmcgdG8gY29uc2lkZXIgdGhlIHRvdGFsIGN5Y2xpc3RzIHRoYXQgZGF5LiAKCmBgYHtyfQpwb2lzLm1vZGVsLjIgPSBnbG0oUXVlZW5zYm9yb0JyaWRnZSB+IERheSArIEF2Z1RlbXAgKyBOZXdQcmVjaXAsIG9mZnNldCA9IGxvZyhUb3RhbCksIAogICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpLCBkYXRhID0gYnJpZGdlLmZpbmFsKSAgCgp5aGF0LjIgPSBwb2lzLm1vZGVsLjIkZml0dGVkLnZhbHVlcwpwZWFyc29uLnJlc2lkLjIgPSAoYnJpZGdlLmZpbmFsJFF1ZWVuc2Jvcm9CcmlkZ2UgLSB5aGF0LjIpL3NxcnQoeWhhdC4yKQpQZWFyc29uLmRpc3AuMiA9IHN1bShwZWFyc29uLnJlc2lkLjJeMikvcG9pcy5tb2RlbC4yJGRmLnJlc2lkdWFsCgpEZXZpYW5jZS5kaXNwLjIgPSAocG9pcy5tb2RlbC4yJGRldmlhbmNlKS9wb2lzLm1vZGVsLjIkZGYucmVzaWR1YWwKCmRpc3AgPSBjYmluZChQZWFyc29uLmRpc3AuMiA9IFBlYXJzb24uZGlzcC4yLCBEZXZpYW5jZS5kaXNwLjIgPSBEZXZpYW5jZS5kaXNwLjIpCmthYmxlKGRpc3AsIGNhcHRpb249IkRpc3BlcnNpb24gcGFyYW1ldGVyIGZvciBTZWNvbmRhcnkgTW9kZWwiLCBhbGlnbiA9ICdjJykKYGBgCgpBcyBzZWVuIGFib3ZlLCB0aGUgc2Vjb25kYXJ5IG1vZGVsLCB3aGljaCBjb25zaWRlcnMgYW4gb2Zmc2V0IG9mIHRoZSBUb3RhbCwgcHJvZHVjZWQgYSBtdWNoIGJldHRlciBkaXNwZXJzaW9uIHBhcmFtZXRlciwgY29tcGFyZWQgdG8gdGhlIHByaW1hcnkgbW9kZWwuIFRoZSBQZWFyc29uIERpc3BlcnNpb24gZm9yIHRoZSBtb2RlbCBpcyA3LjA1OTM4NSwgYW5kIHRoZSBEZXZpYW5jZSBEaXNwZXJzaW9uIGlzIDYuOTgwMzQyLiBXaGlsZSBzdGlsbCBub3QgaWRlYWwgZGlzcGVyc2lvbiBwYXJhbWV0ZXJzLCBjb25zaWRlcmluZyB0aGF0IHRoZSBwcmV2aW91cyBtb2RlbCBoYWQgZGlzcGVyc2lvbiBwYXJhbWV0ZXJzIGluIHRoZSAxNTBzLCB0aGVzZSBzaW5nbGUgZGlnaXQgZGlzcGVyc2lvbiBwYXJhbWV0ZXJzIGNsZWFybHkgc2hvdyB0aGF0IHRoaXMgc2Vjb25kIG1vZGVsIGlzIHRoZSBiZXR0ZXIgbW9kZWwuIFRvIGhlbHAgYWRqdXN0IGZvciB0aGUgc3RhbmRhcmQgZXJyb3IsIHdlIGFyZSBnb2luZyB0byBiZSBmaXR0aW5nIHRoZSBxdWFzaS1wb2lzc29uIG1vZGVsIHdoZW4gc3VtbWFyaXppbmcgdGhlIGluZmVyZW50aWFsIHN0YXRpc3RpY3MuCgpUaGUgbmV4dCBzdGVwIHdpbGwgYmUgdG8gc3VtbWFyaXplIHRoZSBpbmZlcmVudGlhbCBzdGF0aXN0aWNzIGluIHRoZSB0YWJsZSBiZWxvdy4gCgpgYGB7cn0KcXVhc2kubW9kZWwgPSBnbG0oUXVlZW5zYm9yb0JyaWRnZSB+IERheSArIEF2Z1RlbXAgKyBOZXdQcmVjaXAsIG9mZnNldCA9IGxvZyhUb3RhbCksCiAgICAgICAgICAgICAgICAgZmFtaWx5ID0gcXVhc2lwb2lzc29uLCBkYXRhID1icmlkZ2UubmV3KSAgCnN1bW1hcnkocXVhc2kubW9kZWwpCmBgYApgYGB7cn0KU0UucXVhc2kucG9pcyA9IHN1bW1hcnkocXVhc2kubW9kZWwpJGNvZWYKa2FibGUoU0UucXVhc2kucG9pcywgY2FwdGlvbiA9ICJTdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgcXVhc2ktcG9pc3NvbiByZWdyZXNzaW9uIG1vZGVsIikKYGBgCgpUaGUgZXN0aW1hdGVkIGRpc3BlcnNpb24gaW5kZXggYmFzZWQgb24gdGhlIFBlYXJzb24gcmVzaWR1YWxzIGlzIDcuMDYuCkxvb2tpbmcgYXQgdGhlIHF1YXNpLXBvaXNzb24gcmVncmVzc2lvbiBhYm92ZSwgYWxsIG9mIHRoZSBmYWN0b3JzIGZvciBEYXkgdmFyaWFibGUgYXJlIGluc2lnbmlmaWNhbnQsIHdpdGggcC12YWx1ZXMgcmFuZ2luZyBmcm9tIHAtdmFsdWUgPSAwLjE1MjE1IHRvIHAtdmFsdWUgPSAwLjk3NDk1LiBTaW5jZSBhbGwgdGhlIGZhY3RvcnMgYXJlIGluc2lnbmlmaWNhbnQsIHdlIGFyZSBnb2luZyB0byByZWZpdCB0aGUgcXVhc2ktcG9pc3NvbiBtb2RlbCBieSBkcm9wcGluZyB0aGUgdmFyaWFibGUgRGF5LiAKCmBgYHtyfQpxdWFzaS5tb2RlbC5uZXcgPSBnbG0oUXVlZW5zYm9yb0JyaWRnZSB+IEF2Z1RlbXAgKyBOZXdQcmVjaXAsIG9mZnNldCA9IGxvZyhUb3RhbCksCiAgICAgICAgICAgICAgICAgZmFtaWx5ID0gcXVhc2lwb2lzc29uLCBkYXRhID1icmlkZ2UuZmluYWwpCmthYmxlKHN1bW1hcnkocXVhc2kubW9kZWwubmV3KSRjb2VmLCBjYXB0aW9uID0gIkluZmVyZW50aWFsIHN0YXRpc3RpY3Mgb2YgCnRoZSBRdWFzaS1Qb2lzc29uIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIGluIHRoZSBmaW5hbCBtb2RlbC4iKQpgYGAKClRoZSBuZXcgbW9kZWwsIHNob3duIGFib3ZlLCB0aGF0IGhhcyBiZWVuIHJlZml0dGVkIHdpdGhvdXQgdGhlIHZhcmlhYmxlIGRheSwgd2lsbCBiZSB1c2VkIGFzIHRoZSBmaW5hbCBtb2RlbC4gU2luY2UgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIG9mIHRoZSBtb2RlbCBpcyBvbiBhIGxvZyBzY2FsZSwgYW5kIGFkZGl0aW9uYWxseSB0aGVyZSBpcyBhbiBvZmZzZXQgb2YgdGhlIGxvZyBUb3RhbCwgdGhlIGludGVycHJldGF0aW9uIG9mIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50IG9mIHRoZSBwb2lzc29uIG1vZGVsIGlzIG5vdCBhIHNpbXBsZSBvciBzdHJhaWdodGZvcndhcmQgcHJvY2VkdXJlLiAKCkluIGNvbnRleHQsIHRoZSBjb2VmZmljaWVudCBmb3IgTmV3UHJlY2lwIGlzIDAuMDYxOTU3MiwgdGhpcyBpcyB0aGUgZXN0aW1hdGVkIHBvaXNzb24gcmVncmVzc2lvbiBjb2VmZmljaWVudCBjb21wYXJpbmcgZGF5cyB3aXRoIGFuZCB3aXRob3V0IHByZWNpcGl0YXRpb24sIGdpdmVuIHRoZSBvdGhlciB2YXJpYWJsZSBhcmUgYmVpbmcgaGVsZCBjb25zdGFudC4gVGhlIGRpZmZlcmVuY2UgaW4gbG9nIG9mIGN5Y2xpc3RzIG9uIHRoZSBRdWVlbnNib3JvIEJyaWRnZSwgb2Zmc2V0IGJ5IHRoZSBsb2cgb2YgdG90YWwgY3ljbGlzdHMsIGlzIGV4cGVjdGVkIHRvIGJlIDAuMDYxOTU3MiB1bml0cyBoaWdoZXIgb24gZGF5cyB3aXRoIHByZWNpcGl0YXRpb24gY29tcGFyZWQgdG8gZGF5cyB3aXRob3V0IHByZWNpcGl0YXRpb24gd2hpbGUgb3RoZXIgdmFyaWFibGVzIGFyZSBoZWxkIGNvbnN0YW50IGluIHRoZSBtb2RlbC4gCgoKIyMgVmlzdWFsIEFuYWx5c2lzIAoKVG8gY29uZHVjdCB0aGlzIHZpc3VhbCBhbmFseXNpcyB0aGVyZSBpcyBnb2luZyB0byBiZSBhbiBhZGRpdGlvbmFsIGJyZWFrZG93biBvZiB0aGUgbW9kZWwuIEEgbmV3IHZhcmlhYmxlIGNhbGxlZCBIaWdoTG93VGVtcCBpcyBnb2luZyB0byBiZSBjcmVhdGVkLiBUaGlzIHZhcmlhYmxlIHdpbGwgYmUgYSBiaW5hcnkgY2F0ZWdvcmljYWwgdmFyaWFibGUgaW4gd2hpY2ggdGhlIHZhcmlhYmxlIHdpbGwgZXF1YWwgMCBpZiB0aGUgQXZnVGVtcCB3YXMgbG93ZXIgdGhhbiB0aGUgbWVhbiB0ZW1wZXJhdHVyZSBhY3Jvc3MgdGhlIGVudGlyZSBtb250aCBvZiBBcHJpbCBhbmQgaXQgd2lsbCBlcXVhbCAxIGlmIGl0IGlzIGhpZ2hlciBvciBlcXVhbCB0byB0aGUgbWVhbiB0ZW1wZXJhdHVyZS4gQWZ0ZXIgcnVubmluZyBzb21lIGFkZGl0aW9uYWwgY29kZSwgaXQgaGFzIGJlZW4gY2FsY3VsYXRlZCB0aGF0IHRoZSBtZWFuIHRlbXBlcmF0dXJlIGZvciB0aGUgbW9udGggb2YgQXByaWwgaXMgNTcuMjMgZGVncmVlcyBGYWhyZW5oZWl0LiAKCmBgYHtyfQptZWFuKGJyaWRnZS5uZXckQXZnVGVtcCkKCmZvcihpIGluIDE6bnJvdyhicmlkZ2UpKSB7CiAgaWYgKGJyaWRnZS5uZXckQXZnVGVtcFtpXSA+PSA1Ny4yMykgewogICAgYnJpZGdlLmZpbmFsJEhpZ2hMb3dUZW1wW2ldIDwtIDEgIAogIH0gZWxzZSBpZiAoYnJpZGdlLm5ldyRBdmdUZW1wW2ldIDwgNTcuMjMpIHsKICAgIGJyaWRnZS5maW5hbCRIaWdoTG93VGVtcFtpXSA8LSAwICAKICB9Cn0KCmBgYAoKYGBge3J9CnF1YXNpLm1vZGVsLm5ldyA9IGdsbShRdWVlbnNib3JvQnJpZGdlIH4gQXZnVGVtcCArIE5ld1ByZWNpcCwgb2Zmc2V0ID0gbG9nKFRvdGFsKSwKICAgICAgICAgICAgICAgICBmYW1pbHkgPSBxdWFzaXBvaXNzb24sIGRhdGEgPWJyaWRnZS5maW5hbCkKa2FibGUoc3VtbWFyeShxdWFzaS5tb2RlbC5uZXcpJGNvZWYsIGNhcHRpb24gPSAiSW5mZXJlbnRpYWwgc3RhdGlzdGljcyBvZiAKdGhlIFF1YXNpLVBvaXNzb24gcmVncmVzc2lvbiBjb2VmZmljaWVudHMgaW4gdGhlIGZpbmFsIG1vZGVsLiIpCgpgYGAKCgpBZnRlciByZWFkanVzdGluZyBBdmdUZW1wIHRvIEhpZ2hMb3dUZW1wLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHZhcmlhYmxlIGlzIHN0aWxsIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYW5kIHdlIGNhbiBtb3ZlIGZvcndhcmQgd2l0aCB0aGUgdmlzdWFsIGFuYWx5c2lzIHRoYXQgaXMgcGxhbm5lZC4gCgpUaGUgZ29hbCBvZiB0aGUgdmlzdWFsaXphdGlvbiBpcyB0byBzaG93IGhvdyB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGluIHRoZSBmaW5hbCBtb2RlbCBpbXBhY3QgdGhlIGFjdHVhbCBudW1iZXIgb2YgY3ljbGlzdHMgb24gdGhlIFF1ZWVuc2Jvcm8gQnJpZGdlLiAKCkZvciB0aGlzIHZpc3VhbGl6YXRpb24gYWxsIGRheXMgd2lsbCBiZSBjbGFzc2lmaWVkIGFzIG9uZSBvZiBmb3VyIG9mIHRoZSBmb2xsb3dpbmcgZ3JvdXBzLCBieSBwcmVjaXBpdGF0aW9uIGFuZCB0ZW1wZXJhdHVyZS4gCgpkYXkuMCA9IGRheXMgd2l0aCBubyBwcmVjaXBpdGF0aW9uCgpkYXkuMSA9IGRheXMgd2l0aCBwcmVjaXBpdGF0aW9uCgpOb3csIGl0IGlzIHRpbWUgdG8gZXhwb25lbnRpYXRlIHRoZSBsb2cgY291bnQgb2YgY3ljbGlzdHMgb24gdGhlIFF1ZWVuc2Jvcm8gQnJpZGdlIHRvIHRoZSBhY3R1YWwgbnVtYmVyIG9mIGN5Y2xpc3RzLiBUaGVuIHdlIHdpbGwgY3JlYXRlIGEgZ3JhcGggdGhhdCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gY3ljbGlzdHMgYW5kIGRpZmZlcmVudCB3ZWF0aGVyIGNvbmRpdGlvbnMgaW4gdGVybXMgb2YgbnVtYmVyIG9mIGN5Y2xpc3RzIHJpZGluZyBpbiBlYWNoIG9mIHRoZSBncm91cHMgYWJvdmUuIAoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD00fQp0ZW1wID0gIHJhbmdlKGJyaWRnZS5maW5hbCRBdmdUZW1wKVsxXTpyYW5nZShicmlkZ2UuZmluYWwkQXZnVGVtcClbMl0KZGF5LjAgPSAtMS4yNDYyNDM0IC0gMC4wMDM5NzA0KnRlbXAgKyAob2Zmc2V0ID0gbG9nKGJyaWRnZS5maW5hbCRUb3RhbCkpCmRheS4xID0gLTEuMjQ2MjQzNCArIDAuMDYxOTU3MiAgLSAwLjAwMzk3MDQqdGVtcCArIChvZmZzZXQgPSBsb2coYnJpZGdlLmZpbmFsJFRvdGFsKSkKCiMjCnBsb3QodGVtcCwgZXhwKGRheS4wKSwgeWxpbT1jKDAsNjAwMCksCiAgICAgdHlwZSA9ICJsIiwKICAgICBjb2wgPSAicmVkIiwKICAgICBsdHkgPSAxLAogICAgIHlsYWIgPSAiUXVlZW5zYm9ybyBCcmlkZ2UgQ3ljbGlzdHMiLAogICAgIHhsYWIgPSAiQXZlcmFnZSBUZW1wZXJhdHVyZSIsCiAgICAgbWFpbiA9ICJGYWN0b3JzIFRoYXQgSW1wYWN0IEN5Y2xpc3QgVHVybm91dCIpCmxpbmVzKHRlbXAsIGV4cChkYXkuMSksIGNvbCA9ICJibHVlIiwgbHR5ID0gMikKbGVnZW5kKCJ0b3BsZWZ0IiwgYygibm8gcHJlY2lwaXRhdGlvbiIsICJwcmVjaXBpdGF0aW9uIiksIAogICAgICAgY29sPWMoInJlZCIsICJibHVlIiksICBsdHk9MToyLCBidHk9Im4iLCBjZXg9MC44KQpgYGAKCgpUaGUgZ3JhcGggc2hvd3MgdGhlcmUgZG9lcyBub3Qgc2VlbSB0byBiZSBhIGxhcmdlIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiBkYXlzIHdpdGggbm8gcHJlY2lwaXRhdGlvbiB2cyBkYXlzIHdpdGggcHJlY2lwaXRhdGlvbi4gSG93ZXZlciwgb3V0IG9mIHRoZSB0d28gdGhlcmUgZG9lcyB0byBiZSBzbGlnaHRseSBsZXNzIGN5Y2xpc3QgdHVybm91dCBvbiBkYXlzIHdpdGhvdXQgcHJlY2lwaXRhdGlvbi4gQWRkaXRpb25hbGx5LCB0aGUgZ3JhcGggc2hvd3MgdGhhdCB0aGVyZSBpcyBub3QgYSBjb25zaXN0ZW50IGluY3JlYXNlIG9yIGRlY3JlYXNlIGluIGN5Y2xpc3QgdHVybm91dCBhcyBhdmVyYWdlIHRlbXBlcmF0dXJlIGluY3JlYXNlcyBvciBkZWNyZWFzZXMuIEluc3RlYWQsIHRoZSBjeWNsaXN0IHR1cm5vdXQgc2VlbXMgdG8gaGF2ZSBhIHZlcnkgc3BvcmFkaWMgcmVsYXRpb25zaGlwIHRvIGF2ZXJhZ2UgdGVtcGVyYXR1cmUsIHdpdGggaGlnaCBzcGlrZXMgYW5kIGxvdyBkaXZvdHMuIAoKCiMgUmVzdWx0cyAmIENvbmNsdXNpb24KClRoZSBiZXN0IG1vZGVsIGZvciB0b3RhbCBjeWNsaXN0cyBvbiB0aGUgUXVlZW5zYm9ybyBicmlkZ2UsIGlzIGEgcG9pc3NvbiBtb2RlbCB0aGF0IG9mZnNldHMgd2l0aCB0aGUgbG9nIG9mIHRoZSB0b3RhbCBjeWNsaXN0cyBhbmQgdXNlcyBOZXdQcmVjaXAgYW5kIEF2Z1RlbXAgYXMgcHJlZGljdG9ycyB2YXJpYWJsZXMgYW5kIHdpdGggdGhlIHZhcmlhYmxlIERheSBiZWluZyBkcm9wcGVkIGZvciBsYWNraW5nIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBhY3Jvc3MgYWxsIGZhY3RvcnMuIEFkZGl0aW9uYWxseSwgdGhlIGdyYXBoIHNob3dzIHRoYXQgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIEF2Z1RlbXAgYW5kIFF1ZWVuc2Jvcm9CcmlkZ2UsIHdoaWxlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIGlzIG5vdCBsaW5lYXIuIFRoZSBncmFwaCBhbHNvIHNob3dzIHRoYXQgd2hpbGUgdGhlIHZhcmlhYmxlIE5ld1ByZWNpcCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGluIHByZWRpY3RpbmcgdGhlIHRvdGFsIGN5Y2xpc3RzIG9uIHRoZSBRdWVlbnNib3JvIEJyaWRnZSwgdGhleSBkaWZmZXJlbnQgbGV2ZWxzIGRvIG5vdCBhcHBlYXIgdG8gYmUgbGFyZ2VseSBkaWZmZXJlbnQgZnJvbSBlYWNoIG90aGVyLiAKCiMgR2VuZXJhbCBEaXNjdXNzaW9ucwoKSXQgaXMgaW1wb3J0YW50IHRvIGFja25vd2xlZGdlIHRoZSBzaG9ydGNvbWluZ3Mgb2YgdGhpcyBtb2RlbCwgc3RhcnRpbmcgd2l0aCB0aGUgZGlzcGVyc2lvbiBwYXJhbWV0ZXJzLiBXaGlsZSBhIGRpc3BlcnNpb24gcGFyYW1ldGVyIG9mIGFwcHJveGltYXRlbHkgNyBsb29rZWQgZ3JlYXQgaW4gY29tcGFyaXNvbiB0byB0aGUgZmlyc3QgbW9kZWxzIGRpc3BlcnNpb24gcGFyYW1ldGVyIG9mIG92ZXIgMTUwLCBhIDcgaXMgc3RpbGwgd2l0aG91dCBzaWRlIGEgcHJlZmVycmVkIHJhbmdlLiBJZGVhbGx5LCBzaW5jZSBnZXR0aW5nIGEgZGlzcGVyc2lvbiBwYXJhbWV0ZXIgYW55IGNsb3NlciB0byAxIHNlZW1zIGhpZ2hseSB1bmxpa2VseSwgZXNwZWNpYWxseSBjb25zaWRlcmluZyB0aGlzIHByb2plY3QgaGFkIHZhcmlhYmxlIHBhcmFtZXRlcnMgdGhhdCB3ZXJlIHJlcXVpcmVkLCByZWFsaXN0aWNhbGx5IGEgZGlmZmVyZW50IG1vZGVsIHNob3VsZCBoYXZlIGJlZW4gdXNlZCwgbW9zdCBsaWtlbHkgYSBuZWdhdGl2ZSBiaW5vbWlhbC4gSG93ZXZlciwgc2luY2UgdGhpcyBwcm9qZWN0IHJlcXVlc3RlZCBhIHBvaXNzb24gbW9kZWwgYmUgdXNlZCB3ZSBzdHVjayB3aXRoIHRoZSBtb2RlbCB0aGF0IGhhZCB0aGUgbGVhc3QgZWdyZWdpb3VzIG1vZGVsIGFzc3VtcHRpb25zLiAKClRoaXMgcHJvamVjdCBhbHNvIHJlcXVpcmVkIHRoZSBjcmVhdGlvbiBhbmQgdXNlIG9mIHR3byBuZXcgdmFyaWFibGVzIGluIG91ciBtb2RlbCwgQXZnVGVtcCBhbmQgTmV3UHJlY2lwLiBUaGVzZSBuZXcgdmFyaWFibGVzIHdlcmUgbWVhbnQgdG8gcmVwbGFjZSB0aGUgdmFyaWFibGVzIEhpZ2hUZW1wLCBMb3dUZW1wIGFuZCBQcmVjaXBpdGF0aW9uLCBhbmQgdG8gbWUgdXNlZCBpbiB0aGUgbW9kZWwgYnVpbGRpbmcgd2l0aCB0aGUgdmFyaWFibGUgRGF5LiBJbiBvdXIgcHJldmlvdXMgYW5hbHlzaXMsIHdlIHNhdyBzb21lIGZhY3RvcnMgb2YgdGhlIHZhcmlhYmxlIGRheSBoYXZlIHNvbWUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlLCBhbmQgZXZlbiB0YWxrZWQgYWJvdXQgbWFraW5nIGFuIGFyZ3VtZW50IGZvciBncm91cGluZyB0aGVtIHdpdGggZnVydGhlciBhbmFseXNpcy4gVW5mb3J0dW5hdGVseSwgaW4gdGhpcyBhbmFseXNpcywgdGhlIG5ldyBtb2RlbCB3aXRoIHRoZSBuZXcgdmFyaWFibGVzIGRpZCBub3QgcmVzdWx0IGluIGFueSBvZiB0aGUgZmFjdG9ycyBvZiB0aGUgdmFyaWFibGUgZGF5IHlpZWxkaW5nIGFueSBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UsIG1ha2luZyBncm91cGluZyBhIG1vb3QgcG9pbnQuIFNpbmNlIG5vbmUgb2YgdGhlIGZhY3RvcnMgd2VyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCB3ZSBoYWQgdG8gZHJvcCB0aGUgdmFyaWFibGUgRGF5LCBsZWF2aW5nIHVzIHdpdGggb25seSB0d28gdmFyaWFibGVzLCB3aGljaCBpcyBsZXNzIHRoYW4gaWRlYWwuIE9ubHkgYW5hbHlzaXMgdHdvIHZhcmlhYmxlcyBnaXZlcyB1cyBsZXNzIG9wcG9ydHVuaXRpZXMgdG8gYW5hbHlzZSB0aGUgcmVsYXRpb25zaGlwIHRvIG90aGVyIHZhcmlhYmxlcyBhbmQgdGhlIHJlc3BvbnNlLCBzbyBpZGVhbGx5IGl0IHdvdWxkIGhhdmUgYmVlbiBiZXR0ZXIgdG8gdXNlIGEgbW9kZWwgdGhhdCBzaG93ZWQgYXQgbGVhc3Qgc29tZSBvZiB0aGUgZmFjdG9ycyBvZiBkYXkgdG8gYmUgc2lnbmlmaWNhbnQgc28gdGhlIHZhcmlhYmxlIGRpZCBub3QgaGF2ZSB0byBiZSBkcm9wcGVkLiAKCkZpbmFsbHksIGFzIG1lbnRpb25lZCBlYXJsaWVyIGFuZCBpbiB0aGUgcHJldmlvdXMgcmVwb3J0LCB0aGlzIGlzIGEgc3Vic2V0IG9mIGEgbXVjaCBsYXJnZXIgZGF0YSBzZXQuIFRoaXMgc3Vic2V0IG9ubHkgY292ZXJzIG9uZSBtb250aCBmb3Igb25lIGJyaWRnZSwgb2YgYSBkYXRhIHNldCB0aGF0IHNwYW5zIG9uZSB5ZWFyIGFuZCBjb3ZlcnMgZm91ciBkaWZmZXJlbnQgYnJpZGdlcy4gV2l0aG91dCBiZWluZyBhYmxlIHRvIGNvbXBhcmUgdGhpcyB0byBvdGhlciBzZWN0aW9ucyBvZiB0aGUgZGF0YSBzZXQgd2UgYXJlIG1pc3NpbmcgY3J1Y2lhbCBpbmZvcm1hdGlvbi4gSG93IGRvZXMgdGhlIFF1ZWVuc2Jvcm8gQnJpZGdlIGNvbXBhcmUgaW4gY3ljbGlzdCBjb3VudCB0byBvdGhlciBicmlkZ2VzPyBIb3cgZG9lcyB0aGUgbW9udGggb2YgQXByaWwgY29tcGFyZSBpbiBjeWNsaXN0IGNvdW50cyB0byBvdGhlciBtb250aHM/IElzIHRoZSBRdWVlbnNib3JvIEJyaWRnZSBvciB0aGUgbW9udGggb2YgQXByaWwgYW5kIG91dGxpZXI/IFNlZWluZyBhIHNpZ25pZmljYW50bHkgaGlnaGVyIG9yIGxvd2VyIGFtb3VudCBvZiBjeWNsaXN0cyBjb21wYXJlZCB0byBvdGhlciBicmlkZ2VzIG9yIG1vbnRocy4gVGhpcyBpcyBpbmZvcm1hdGlvbiB3ZSBjYW4gbm90IGtub3cgd2l0aG91dCBiZWluZyBhYmxlIHRvIGFuYWx5emUsIHRoZSBmdWxsLCBvciBhdCB0aGUgdmVyeSBsZWFzdCBhZGRpdGlvbmFsbHkgc3Vic2V0cyBvZiwgdGhlIGRhdGEgc2V0LiBGb3IgdGhlIGNvbmNsdXNpb25zIGRyYXduIHJlZ2FyZGluZyB0aGlzIHN1YnNldCB0byBiZSBtZWFuaW5nZnVsIGFuZCBob2xkIHByb3BlciBpbXBvcnRhbmNlLCBpdCBuZWVkcyB0byBiZSBpbnRlcnByZXRlZCBpbiBjb21wYXJpc29uIHRvIHRoZSBsYXJnZXIgZGF0YSBzZXQgc28gdGhhdCBib3RoIHRob3NlIGNvbmR1Y3RpbmcgdGhlIGFuYWx5c2lzIGFuZCB0aG9zZSByZWFkaW5nIHRoZSByZXBvcnQgaGF2ZSB0aGUgYmVzdCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBjb250ZXh0IHN1cnJvdW5kaW5nIHRoZSBkYXRhIHNldC4gCgpPdmVyYWxsLCB3aGlsZSBub3QgdGhlIHBlcmZlY3QgbW9kZWwgb3IgcGVyZmVjdCBjaXJjdW1zdGFuY2VzIGZvciBhbmFseXNpcywgd2UgaGF2ZSB0byBtYWtlIHRoZSBiZXN0IGNvbmNsdXNpb25zIHdpdGggdGhlIGluZm9ybWF0aW9uIHdlIGhhdmUuIFRodXMsIHRoaXMgbW9kZWwgZGljdGF0ZXMgdGhhdCB0aGUgQXZnVGVtcCBhbmQgTmV3UHJlY2lwIGhhdmUgYSBzdGF0aXN0aWNhbHkgc2lnbmlmaWNhbnQgaW1wYWN0IG9uIHRoZSBjeWNsaXN0IHR1cm5vdXQgZm9yIHRoZSBRdWVlbnNib3JvIEJyaWRnZSBpbiBBcHJpbC4g