Data Analysis
We will first get a brief summary of our data to get a good scope of
the data set.
Cyclists <- read.csv("https://raw.githubusercontent.com/TylerBattaglini/STA-321/refs/heads/main/ManhattanBridge.csv", header = TRUE)
summary(Cyclists)
X Date Day HighTemp LowTemp
Min. : 1.0 Min. :43009 Min. :43009 Min. :54.00 Min. :43.00
1st Qu.: 8.5 1st Qu.:43017 1st Qu.:43017 1st Qu.:64.90 1st Qu.:52.00
Median :16.0 Median :43024 Median :43024 Median :71.10 Median :57.00
Mean :16.0 Mean :43024 Mean :43024 Mean :69.84 Mean :57.92
3rd Qu.:23.5 3rd Qu.:43032 3rd Qu.:43032 3rd Qu.:75.45 3rd Qu.:64.90
Max. :31.0 Max. :43039 Max. :43039 Max. :82.00 Max. :72.00
Precipitation ManhattanBridge Total
Min. :0.0000 Min. : 661 Min. : 2835
1st Qu.:0.0000 1st Qu.:4530 1st Qu.:15956
Median :0.0000 Median :5610 Median :19939
Mean :0.1365 Mean :5298 Mean :18652
3rd Qu.:0.0550 3rd Qu.:6640 3rd Qu.:22977
Max. :3.0300 Max. :7691 Max. :26050
var(Cyclists)
X Date Day HighTemp
X 82.666667 82.666667 82.666667 -39.7333333
Date 82.666667 82.666667 82.666667 -39.7333333
Day 82.666667 82.666667 82.666667 -39.7333333
HighTemp -39.733333 -39.733333 -39.733333 61.4503656
LowTemp -25.286667 -25.286667 -25.286667 48.4430753
Precipitation 1.337333 1.337333 1.337333 -0.4978032
ManhattanBridge -4998.000000 -4998.000000 -4998.000000 1855.0206452
Total -16000.166667 -16000.166667 -16000.166667 6982.1644086
LowTemp Precipitation ManhattanBridge Total
X -2.528667e+01 1.3373333 -4998.0000 -16000.167
Date -2.528667e+01 1.3373333 -4998.0000 -16000.167
Day -2.528667e+01 1.3373333 -4998.0000 -16000.167
HighTemp 4.844308e+01 -0.4978032 1855.0206 6982.164
LowTemp 6.296340e+01 0.5293258 -3489.4718 -10768.102
Precipitation 5.293258e-01 0.2946570 -556.8061 -1890.055
ManhattanBridge -3.489472e+03 -556.8060645 2923576.0129 9607968.955
Total -1.076810e+04 -1890.0554409 9607968.9548 31808787.525
Poisson Regression on
Cyclists Count
We first build a Poisson regression with counts as our response and
also leaving out the Total. We use Poisson regression for this model
because this is a count data, which shows the number of occurrences of
an event, in this case cyclist counts, within a fixed interval of time.
We assume that our counts are independent from one another and also that
our variance and mean are equal to each other.
model.freq <- glm(ManhattanBridge~ HighTemp + Precipitation + LowTemp + Day, family = poisson(link = "log"), data = Cyclists)
pois.count.coef = summary(model.freq)$coef
kable(pois.count.coef, caption = "The Poisson regression model for the counts of cyclists entering the bridge vs the tempature, precipitation, and day.")
The Poisson regression model for the counts of cyclists
entering the bridge vs the tempature, precipitation, and day.
(Intercept) |
218.5321098 |
14.1546585 |
15.43888 |
0 |
HighTemp |
0.0163560 |
0.0005981 |
27.34862 |
0 |
Precipitation |
-0.9591493 |
0.0194684 |
-49.26688 |
0 |
LowTemp |
-0.0206914 |
0.0005624 |
-36.79199 |
0 |
Day |
-0.0048775 |
0.0003287 |
-14.83949 |
0 |
The above data above shows that all our data above is significant at
an alpha level of .05. This means that we have statistical evidence to
draw conclusions. Each coefficient represents the log change in the
expected count for one unit increase in our predictor value while
assuming all other values are constant.For example we can expect when
precipitation goes up by one unit we can expect our count to go down by
-.959. Some other findings we can see from our output above is that
precipitation is our biggest influence on the count because its absolute
value is the highest out all the coefficients. We also see when
comparing low temperature with high temperature that a lower temperature
will tend to have more affect on our count rather than high temperatures
because the low temperature has a higher absolute value.
Poisson Rregression
on Rates
The following model has the same variables but we are offsetting with
the Total count. By taking the logarithm of Total count as the offset,
we are adjusting the counts of cyclists on the Manhattan Bridge for the
total number of cyclists across all bridges. This means that if the
total number of cyclists varies significantly from day to day, the model
will account for that variability.
model.rates <- glm(ManhattanBridge ~ HighTemp + Precipitation + LowTemp + Day, offset = log(Total),
family = poisson(link = "log"), data = Cyclists)
kable(summary(model.rates)$coef, caption = "Poisson regression on the rate of the
the cyclists entering and leaving the Brooklyn Bridge.")
Poisson regression on the rate of the the cyclists entering and
leaving the Brooklyn Bridge.
(Intercept) |
59.9613619 |
14.6285560 |
4.0989255 |
0.0000415 |
HighTemp |
0.0000196 |
0.0006049 |
0.0324407 |
0.9741206 |
Precipitation |
-0.0707936 |
0.0130863 |
-5.4097362 |
0.0000001 |
LowTemp |
-0.0018394 |
0.0005745 |
-3.2018355 |
0.0013655 |
Day |
-0.0014205 |
0.0003397 |
-4.1817681 |
0.0000289 |
We see from the above output that all of our p-values are blow a
significance level of .01 except for High temp. We also see that all of
our coefficients have changed to a lower absolute value. One change that
stood out to me was the decrease of high temp, compared to the other
coefficients this one dropped the most and is basically a non factor in
predicting the model.
EDA and Feature
Engineering
Since low temp and high temp are very similar variables we combine to
make average temperature. This will give us a better understanding of
how many people go cycling on the bridge given the average temperature
of the day not just high and low temp. So we add up the two variables
and then divide by two to get the days average. We then change our
precipitation variable for the purpose of seeing if any type of
precipitation throughout the day changed our totals. So what we do is
assign a 0 if there was no rain on a day and then a 1 if there was any
precipitation on that day.
Cyclists$AvgTemp <- (Cyclists$HighTemp + Cyclists$LowTemp) / 2
Cyclists$NewPrecip <- ifelse(Cyclists$Precipitation > 0, 1, 0)
Cyclists$NewPrecip <- as.factor(Cyclists$NewPrecip)
Cyclists<- Cyclists[, !(names(Cyclists) %in% c("HighTemp", "LowTemp", "Precipitation"))]
head(Cyclists)
X Date Day ManhattanBridge Total AvgTemp NewPrecip
1 1 43009 43009 4540 15975 58.45 0
2 2 43010 43010 7059 23784 62.00 0
3 3 43011 43011 7370 25280 63.50 0
4 4 43012 43012 7691 25477 65.45 0
5 5 43013 43013 7034 23942 73.45 0
6 6 43014 43014 6204 22197 75.05 0
New Variables
Date - The date in which the total number of bikes was recorded and
is our observation ID. Day - The day of the given by a number AvgTemp -
The average temperature of a given day. numerical NewPrecp - Gives us a
1 or a 0 if there is precipitation or none. 1 for precip and 0 for none
ManhattanBridge - The total number of cyclists on the bridge on a
certain day. numerical Total - The total number of bikes recorded on all
the bridges in a certain day. numerical
Dispersion Index
Next, we extract the approximated dispersion index using both Pearson
and deviance residuals
pois.model = glm(ManhattanBridge ~ Day + AvgTemp+ NewPrecip,
family = poisson(link="log"), data =Cyclists)
yhat = pois.model$fitted.values
pearson.resid = (Cyclists$ManhattanBridge - yhat)/sqrt(yhat)
Pearson.disp = sum(pearson.resid^2)/pois.model$df.residual
Deviance.disp = (pois.model$deviance)/pois.model$df.residual
disp = cbind(Pearson.disp = Pearson.disp, Deviance.disp = Deviance.disp)
kable(disp, caption="Dispersion parameter", align = 'c')
Dispersion parameter
324.1135 |
358.387 |
From the output above our Poison assumption is seriously violated.
Our dispersion output is very far off our value of 1 so we will continue
and use a Quasi poisson regression model to account for our variation
being bigger than our mean.
Quasi Model
We now summarize our inferential statistics
quasi.model = glm(ManhattanBridge ~ Day + AvgTemp + NewPrecip,
family = quasipoisson, data =Cyclists)
summary(quasi.model )
Call:
glm(formula = ManhattanBridge ~ Day + AvgTemp + NewPrecip, family = quasipoisson,
data = Cyclists)
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 507.263386 236.058816 2.149 0.0408 *
Day -0.011580 0.005482 -2.112 0.0441 *
AvgTemp -0.005623 0.006963 -0.808 0.4264
NewPrecip1 -0.503976 0.109360 -4.608 8.72e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for quasipoisson family taken to be 324.1152)
Null deviance: 19829.5 on 30 degrees of freedom
Residual deviance: 9676.5 on 27 degrees of freedom
AIC: NA
Number of Fisher Scoring iterations: 4
We see from the above output that our Avgtemp is not significant.
Even though this is concerning we know that average temperature does
have an affect on whether or not cyclists enter and leave the bridge. So
we continue but be careful of our output and its significance.
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) |
507.2633860 |
236.0588157 |
2.1488856 |
0.0407684 |
Day |
-0.0115796 |
0.0054821 |
-2.1122515 |
0.0440572 |
AvgTemp |
-0.0056231 |
0.0069633 |
-0.8075388 |
0.4264135 |
NewPrecip1 |
-0.5039760 |
0.1093600 |
-4.6084131 |
0.0000872 |
This is our final model. Since our model is in log scale we need to
show these values in a way we can draw actual conclusions from. For
example, the coefficient for Newprecip is -0.504. This is the estimated
Poisson regression coefficient comparing precipitation or none, given
the other variables are held constant in the model. The difference in
the logs of expected publications is expected to be 0.504 units lower
for precipitation compared to none while holding the other variables
constant in the model. What we can do to make this easier to understand
is make visual aids to help us see what is actually happening.
Visual Aid
Next, we make a visualization to show how the explanatory variables
in the final working model affect the actual number of cyclists. We
exponentiate the log count of cyclists and make two graphs showcasing
precipitation. Both graphs will show the amount of cyclists given the x
axis of either days and average temperature. The first graph will hold
temperature constant and showcase as days progress how many cyclists are
there while also showing the affect of precipitation and no
precipitation. The second graph will hold days constant while also
showcasing the affect of temperature on the cyclist count and also
showing precipitation
day_range <- seq(min(Cyclists$Day), max(Cyclists$Day), length.out = 100) # Days from min to max
temp_range <- seq(min(Cyclists$AvgTemp), 90, length.out = 100) # Temperature from min to 90 degrees
# Create a new data frame for predictions
pred_data <- data.frame(Day = rep(day_range, each = 2), # Two rows for each day, for both Precipitation 0 and 1
AvgTemp = rep(mean(Cyclists$AvgTemp), 200), # Hold AvgTemp constant
NewPrecip1 = rep(c(0, 1), each = 100)) # Precipitation 0 and 1
# Calculate predicted cyclist counts for both conditions (no precipitation and precipitation)
pred_data$Cyclists_Predicted <- exp(507.2633860 - 0.0115796 * pred_data$Day -
0.0056231 * pred_data$AvgTemp -
0.5039760 * pred_data$NewPrecip1)
# Plot the effect of Day on predicted cyclist counts for both Precipitation 0 and 1
ggplot(pred_data, aes(x = Day, y = Cyclists_Predicted, color = factor(NewPrecip1))) +
geom_line() +
scale_color_manual(values = c("red", "blue"), labels = c("No Precipitation", "Precipitation")) +
labs(title = "Effect of Day on Predicted Cyclist Counts",
x = "Day",
y = "Predicted Cyclist Counts",
color = "Precipitation") +
theme_minimal()

# Now plot the effect of AvgTemp on predicted cyclist counts for both Precipitation 0 and 1
pred_data$AvgTemp <- temp_range
pred_data$Cyclists_Predicted <- exp(507.2633860 - 0.0115796 * pred_data$Day -
0.0056231 * pred_data$AvgTemp -
0.5039760 * pred_data$NewPrecip1)
ggplot(pred_data, aes(x = AvgTemp, y = Cyclists_Predicted, color = factor(NewPrecip1))) +
geom_line() +
scale_color_manual(values = c("red", "blue"), labels = c("No Precipitation", "Precipitation")) +
labs(title = "Effect of AvgTemp on Predicted Cyclist Counts",
x = "Average Temperature (\u00b0F)", # Using Unicode for degree symbol
y = "Predicted Cyclist Counts",
color = "Precipitation") +
scale_x_continuous(limits = c(min(Cyclists$AvgTemp), 80)) + # Set x-axis to go up to 90 degrees
theme_minimal()
Warning: Removed 50 rows containing missing values or values outside the scale range
(`geom_line()`).

We see from the graph above that precipitation has a major effect on
both of the graphs. From the red and the blue lines are drastically
different, the red line is way above the blue line showing that the
predicted counts go down when there is precipitation. The first graph
showcases the Days, shows that there is a decrease when the days goes
up. Also from the second graph we see that again when the temperature
goes up the predicted count of cyclists goes down.
LS0tDQp0aXRsZTogIlBvaXNzb24gUmVncmVzc2lvbiBvZiBNYW5oYXR0YW4gQnJpZGdlIg0KYXV0aG9yOiAnVHlsZXIgQmF0dGFnbGluaScNCmRhdGU6ICIyMDI0LTExLTMiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBmaWdfd2lkdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCmFsd2F5c19hbGxvd19odG1sOiB0cnVlDQotLS0NCg0KYGBgez1odG1sfQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQovKiBDYXNjYWRpbmcgU3R5bGUgU2hlZXRzIChDU1MpIGlzIGEgc3R5bGVzaGVldCBsYW5ndWFnZSB1c2VkIHRvIGRlc2NyaWJlIHRoZSBwcmVzZW50YXRpb24gb2YgYSBkb2N1bWVudCB3cml0dGVuIGluIEhUTUwgb3IgWE1MLiBpdCBpcyBhIHNpbXBsZSBtZWNoYW5pc20gZm9yIGFkZGluZyBzdHlsZSAoZS5nLiwgZm9udHMsIGNvbG9ycywgc3BhY2luZykgdG8gV2ViIGRvY3VtZW50cy4gKi8NCg0KaDEudGl0bGUgeyAgLyogVGl0bGUgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIHRoZSByZXBvcnQgdGl0bGUgKi8NCiAgZm9udC1zaXplOiAyNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDEgeyAvKiBIZWFkZXIgMSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDEgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KaDIgeyAvKiBIZWFkZXIgMiAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDIgc2VjdGlvbiB0aXRsZSAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCAzIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KPC9zdHlsZT4NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgRGV0ZWN0LCBpbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzIGlmIG5lZWRlZC4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgibmxlcXNsdiIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJubGVxc2x2IikNCiAgIGxpYnJhcnkobmxlcXNsdikNCn0NCiMNCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCg0KaWYgKCFyZXF1aXJlKCJwc3ljaCIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoInBzeWNoIikNCiAgIGxpYnJhcnkocHN5Y2gpDQp9DQppZiAoIXJlcXVpcmUoIk1BU1MiKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICAgbGlicmFyeShnZ3Bsb3QyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJHR2FsbHkiKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQ0KICAgbGlicmFyeShHR2FsbHkpDQp9DQppZiAoIXJlcXVpcmUoImNhciIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoImNhciIpDQogICBsaWJyYXJ5KGNhcikNCn0NCmlmICghcmVxdWlyZSgiZHBseXIiKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQogICBsaWJyYXJ5KGRwbHlyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjYXJldCIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoImNhcmV0IikNCiAgIGxpYnJhcnkoY2FyZXQpDQp9DQppZiAoIXJlcXVpcmUoInJlYWR4bCIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoInJlYWR4bCIpDQogICBsaWJyYXJ5KHJlYWR4bCkNCn0NCmlmICghcmVxdWlyZSgib3Blbnhsc3giKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJvcGVueGxzeCIpDQogICBsaWJyYXJ5KG9wZW54bHN4KQ0KfQ0KIyBzcGVjaWZpY2F0aW9ucyBvZiBvdXRwdXRzIG9mIGNvZGUgaW4gY29kZSBjaHVua3MNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncyA9IEZBTFNFLCAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZXMgPSBGQUxTRSwgICMNCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEgICAgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgICkgICANCmBgYA0KDQojIEludHJvZHVjdGlvbg0KDQojIyBEZXNjcmlwdGlvbg0KDQpUaGUgZGFpbHkgdG90YWwgb2YgYmlrZSBjb3VudHMgd2FzIGNvbmR1Y3RlZCBtb250aGx5IG9uIHRoZSBNYW5oYXR0YW4gQnJpZGdlLiBUbyBrZWVwIGNvdW50IG9mIGN5Y2xpc3RzIGVudGVyaW5nIGFuZCBsZWF2aW5nIHRoZSBNYW5oYXR0YW4gYnJpZGdlIHRoZSBUcmFmZmljIEluZm9ybWF0aW9uIE1hbmFnZW1lbnQgU3lzdGVtIChUSU1TKSBjb2xsZWN0cyB0aGUgY291bnQgZGF0YS4gRWFjaCByZWNvcmQgcmVwcmVzZW50cyB0aGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIHBlciAyNCBob3VycyBhdCBCcm9va2x5biBCcmlkZ2UNCg0KRGF0ZSAtIFRoZSBkYXRlIGluIHdoaWNoIHRoZSB0b3RhbCBudW1iZXIgb2YgYmlrZXMgd2FzIHJlY29yZGVkIGFuZCBpcyBvdXIgb2JzZXJ2YXRpb24gSUQuDQpEYXkgLSBUaGUgZGF5IG9mIHRoZSB3ZWVrIE1vbmRheSB0aHJvdWdoIFN1bmRheQ0KSGlnaFRlbXAgLSBUaGUgaGlnaGVzdCB0aGUgdGVtcGVyYXR1cmUgb24gYSBjZXJ0YWluIGRheQ0KTG93VGVtcCAtIFRoZSBsb3cgdGVtcGVyYXR1cmUgb24gYSBjZXJ0YWluIGRheQ0KUHJlY2lwaXRhdGlvbiAtIFRoZSBhbW91bnQgb2YgcmFpbiByZWNvcmRlZCBmb3IgdGhhdCBkYXksIG1vc3QgbGlrZWx5IGluIGluY2hlcyBvZiByYWluDQpNYW5oYXR0YW5CcmlkZ2UgLSBUaGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIG9uIHRoZSBicmlkZ2Ugb24gYSBjZXJ0YWluIGRheQ0KVG90YWwgLSBUaGUgdG90YWwgbnVtYmVyIG9mIGJpa2VzIHJlY29yZGVkIG9uIGFsbCB0aGUgYnJpZGdlcyBpbiBhIGNlcnRhaW4gZGF5DQoNCiMjIFJlc2VhcmNoIFF1ZXN0aW9uDQpIb3cgZG8gdmFyaW91cyBwcmVkaWN0b3JzIGFmZmVjdCB0aGUgYW1vdW50IG9mIGN5Y2xpc3RzIG9uIHRoaXMgY2l0eSdzIGJyaWRnZXMuIFRoaXMgYW5hbHlzaXMgYWltcyB0byBpZGVudGlmeSBzaWduaWZpY2FudCBwcmVkaWN0b3JzIG9mIGN5Y2xpc3QgdG90YWxzIHVzaW5nIFBvaXNzb24gcmVncmVzc2lvbiBhbmQgZm9jdXNpbmcgb24gdmFyaWFibGVzIHN1Y2ggYXMgdGVtcGVyYXR1cmUsIGRheSwgYW5kIHByZWNpcGl0YXRpb24uIE91ciByZXNwb25zZSB2YXJpYWJsZSBmb3IgdGhpcyBhbmFseXNpcyBpcyB0b3RhbCBudW1iZXIgb2YgY3ljbGlzdHMNCg0KIyBEYXRhIEFuYWx5c2lzDQoNCldlIHdpbGwgZmlyc3QgZ2V0IGEgYnJpZWYgc3VtbWFyeSBvZiBvdXIgZGF0YSB0byBnZXQgYSBnb29kIHNjb3BlIG9mIHRoZSBkYXRhIHNldC4gDQoNCmBgYHtyfQ0KQ3ljbGlzdHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9UeWxlckJhdHRhZ2xpbmkvU1RBLTMyMS9yZWZzL2hlYWRzL21haW4vTWFuaGF0dGFuQnJpZGdlLmNzdiIsIGhlYWRlciA9IFRSVUUpDQpzdW1tYXJ5KEN5Y2xpc3RzKQ0KdmFyKEN5Y2xpc3RzKQ0KYGBgDQoNCiMjIFBvaXNzb24gUmVncmVzc2lvbiBvbiBDeWNsaXN0cyBDb3VudA0KDQpXZSBmaXJzdCBidWlsZCBhIFBvaXNzb24gcmVncmVzc2lvbiB3aXRoIGNvdW50cyBhcyBvdXIgcmVzcG9uc2UgYW5kIGFsc28gbGVhdmluZyBvdXQgdGhlIFRvdGFsLiBXZSB1c2UgUG9pc3NvbiByZWdyZXNzaW9uIGZvciB0aGlzIG1vZGVsIGJlY2F1c2UgdGhpcyBpcyBhIGNvdW50IGRhdGEsIHdoaWNoIHNob3dzIHRoZSBudW1iZXIgb2Ygb2NjdXJyZW5jZXMgb2YgYW4gZXZlbnQsIGluIHRoaXMgY2FzZSBjeWNsaXN0IGNvdW50cywgd2l0aGluIGEgZml4ZWQgaW50ZXJ2YWwgb2YgdGltZS4gV2UgYXNzdW1lIHRoYXQgb3VyIGNvdW50cyBhcmUgaW5kZXBlbmRlbnQgZnJvbSBvbmUgYW5vdGhlciBhbmQgYWxzbyB0aGF0IG91ciB2YXJpYW5jZSBhbmQgbWVhbiBhcmUgZXF1YWwgdG8gZWFjaCBvdGhlci4NCg0KYGBge3J9DQptb2RlbC5mcmVxIDwtIGdsbShNYW5oYXR0YW5CcmlkZ2V+IEhpZ2hUZW1wICsgUHJlY2lwaXRhdGlvbiArIExvd1RlbXAgKyBEYXksIGZhbWlseSA9IHBvaXNzb24obGluayA9ICJsb2ciKSwgZGF0YSA9IEN5Y2xpc3RzKQ0KcG9pcy5jb3VudC5jb2VmID0gc3VtbWFyeShtb2RlbC5mcmVxKSRjb2VmDQprYWJsZShwb2lzLmNvdW50LmNvZWYsIGNhcHRpb24gPSAiVGhlIFBvaXNzb24gcmVncmVzc2lvbiBtb2RlbCBmb3IgdGhlIGNvdW50cyBvZiBjeWNsaXN0cyBlbnRlcmluZyB0aGUgYnJpZGdlIHZzIHRoZSB0ZW1wYXR1cmUsIHByZWNpcGl0YXRpb24sIGFuZCBkYXkuIikNCg0KYGBgDQoNClRoZSBhYm92ZSBkYXRhIGFib3ZlIHNob3dzIHRoYXQgYWxsIG91ciBkYXRhIGFib3ZlIGlzIHNpZ25pZmljYW50IGF0IGFuIGFscGhhIGxldmVsIG9mIC4wNS4gVGhpcyBtZWFucyB0aGF0IHdlIGhhdmUgc3RhdGlzdGljYWwgZXZpZGVuY2UgdG8gZHJhdyBjb25jbHVzaW9ucy4gRWFjaCBjb2VmZmljaWVudCByZXByZXNlbnRzIHRoZSBsb2cgY2hhbmdlIGluIHRoZSBleHBlY3RlZCBjb3VudCBmb3Igb25lIHVuaXQgaW5jcmVhc2UgaW4gb3VyIHByZWRpY3RvciB2YWx1ZSB3aGlsZSBhc3N1bWluZyBhbGwgb3RoZXIgdmFsdWVzIGFyZSBjb25zdGFudC5Gb3IgZXhhbXBsZSB3ZSBjYW4gZXhwZWN0IHdoZW4gcHJlY2lwaXRhdGlvbiBnb2VzIHVwIGJ5IG9uZSB1bml0IHdlIGNhbiBleHBlY3Qgb3VyIGNvdW50IHRvIGdvIGRvd24gYnkgLS45NTkuIFNvbWUgb3RoZXIgZmluZGluZ3Mgd2UgY2FuIHNlZSBmcm9tIG91ciBvdXRwdXQgYWJvdmUgaXMgdGhhdCBwcmVjaXBpdGF0aW9uIGlzIG91ciBiaWdnZXN0IGluZmx1ZW5jZSBvbiB0aGUgY291bnQgYmVjYXVzZSBpdHMgYWJzb2x1dGUgdmFsdWUgaXMgdGhlIGhpZ2hlc3Qgb3V0IGFsbCB0aGUgY29lZmZpY2llbnRzLiBXZSBhbHNvIHNlZSB3aGVuIGNvbXBhcmluZyBsb3cgdGVtcGVyYXR1cmUgd2l0aCBoaWdoIHRlbXBlcmF0dXJlIHRoYXQgYSBsb3dlciB0ZW1wZXJhdHVyZSB3aWxsIHRlbmQgdG8gaGF2ZSBtb3JlIGFmZmVjdCBvbiBvdXIgY291bnQgcmF0aGVyIHRoYW4gaGlnaCB0ZW1wZXJhdHVyZXMgYmVjYXVzZSB0aGUgbG93IHRlbXBlcmF0dXJlIGhhcyBhIGhpZ2hlciBhYnNvbHV0ZSB2YWx1ZS4gDQoNCiMjIFBvaXNzb24gUnJlZ3Jlc3Npb24gb24gUmF0ZXMNCg0KVGhlIGZvbGxvd2luZyBtb2RlbCBoYXMgdGhlIHNhbWUgdmFyaWFibGVzIGJ1dCB3ZSBhcmUgb2Zmc2V0dGluZyB3aXRoIHRoZSBUb3RhbCBjb3VudC4gQnkgdGFraW5nIHRoZSBsb2dhcml0aG0gb2YgVG90YWwgY291bnQgYXMgdGhlIG9mZnNldCwgd2UgYXJlIGFkanVzdGluZyB0aGUgY291bnRzIG9mIGN5Y2xpc3RzIG9uIHRoZSBNYW5oYXR0YW4gQnJpZGdlIGZvciB0aGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIGFjcm9zcyBhbGwgYnJpZGdlcy4gVGhpcyBtZWFucyB0aGF0IGlmIHRoZSB0b3RhbCBudW1iZXIgb2YgY3ljbGlzdHMgdmFyaWVzIHNpZ25pZmljYW50bHkgZnJvbSBkYXkgdG8gZGF5LCB0aGUgbW9kZWwgd2lsbCBhY2NvdW50IGZvciB0aGF0IHZhcmlhYmlsaXR5Lg0KDQpgYGB7cn0NCm1vZGVsLnJhdGVzIDwtIGdsbShNYW5oYXR0YW5CcmlkZ2UgfiBIaWdoVGVtcCArIFByZWNpcGl0YXRpb24gKyBMb3dUZW1wICsgRGF5LCBvZmZzZXQgPSBsb2coVG90YWwpLCANCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIiksIGRhdGEgPSBDeWNsaXN0cykNCmthYmxlKHN1bW1hcnkobW9kZWwucmF0ZXMpJGNvZWYsIGNhcHRpb24gPSAiUG9pc3NvbiByZWdyZXNzaW9uIG9uIHRoZSByYXRlIG9mIHRoZSANCiAgICAgIHRoZSBjeWNsaXN0cyBlbnRlcmluZyBhbmQgbGVhdmluZyB0aGUgQnJvb2tseW4gQnJpZGdlLiIpDQpgYGANCg0KV2Ugc2VlIGZyb20gdGhlIGFib3ZlIG91dHB1dCB0aGF0IGFsbCBvZiBvdXIgcC12YWx1ZXMgYXJlIGJsb3cgYSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgLjAxIGV4Y2VwdCBmb3IgSGlnaCB0ZW1wLiBXZSBhbHNvIHNlZSB0aGF0IGFsbCBvZiBvdXIgY29lZmZpY2llbnRzIGhhdmUgY2hhbmdlZCB0byBhIGxvd2VyIGFic29sdXRlIHZhbHVlLiBPbmUgY2hhbmdlIHRoYXQgc3Rvb2Qgb3V0IHRvIG1lIHdhcyB0aGUgZGVjcmVhc2Ugb2YgaGlnaCB0ZW1wLCBjb21wYXJlZCB0byB0aGUgb3RoZXIgY29lZmZpY2llbnRzIHRoaXMgb25lIGRyb3BwZWQgdGhlIG1vc3QgYW5kIGlzIGJhc2ljYWxseSBhIG5vbiBmYWN0b3IgaW4gcHJlZGljdGluZyB0aGUgbW9kZWwuDQoNCiMjIEVEQSBhbmQgRmVhdHVyZSBFbmdpbmVlcmluZw0KDQpTaW5jZSBsb3cgdGVtcCBhbmQgaGlnaCB0ZW1wIGFyZSB2ZXJ5IHNpbWlsYXIgdmFyaWFibGVzIHdlIGNvbWJpbmUgdG8gbWFrZSBhdmVyYWdlIHRlbXBlcmF0dXJlLiBUaGlzIHdpbGwgZ2l2ZSB1cyBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIGhvdyBtYW55IHBlb3BsZSBnbyBjeWNsaW5nIG9uIHRoZSBicmlkZ2UgZ2l2ZW4gdGhlIGF2ZXJhZ2UgdGVtcGVyYXR1cmUgb2YgdGhlIGRheSBub3QganVzdCBoaWdoIGFuZCBsb3cgdGVtcC4gU28gd2UgYWRkIHVwIHRoZSB0d28gdmFyaWFibGVzIGFuZCB0aGVuIGRpdmlkZSBieSB0d28gdG8gZ2V0IHRoZSBkYXlzIGF2ZXJhZ2UuIFdlIHRoZW4gY2hhbmdlIG91ciBwcmVjaXBpdGF0aW9uIHZhcmlhYmxlIGZvciB0aGUgcHVycG9zZSBvZiBzZWVpbmcgaWYgYW55IHR5cGUgb2YgcHJlY2lwaXRhdGlvbiB0aHJvdWdob3V0IHRoZSBkYXkgY2hhbmdlZCBvdXIgdG90YWxzLiBTbyB3aGF0IHdlIGRvIGlzIGFzc2lnbiBhIDAgaWYgdGhlcmUgd2FzIG5vIHJhaW4gb24gYSBkYXkgYW5kIHRoZW4gYSAxIGlmIHRoZXJlIHdhcyBhbnkgcHJlY2lwaXRhdGlvbiBvbiB0aGF0IGRheS4NCg0KDQpgYGB7cn0NCkN5Y2xpc3RzJEF2Z1RlbXAgPC0gKEN5Y2xpc3RzJEhpZ2hUZW1wICsgQ3ljbGlzdHMkTG93VGVtcCkgLyAyDQoNCkN5Y2xpc3RzJE5ld1ByZWNpcCA8LSBpZmVsc2UoQ3ljbGlzdHMkUHJlY2lwaXRhdGlvbiA+IDAsIDEsIDApDQpDeWNsaXN0cyROZXdQcmVjaXAgPC0gYXMuZmFjdG9yKEN5Y2xpc3RzJE5ld1ByZWNpcCkNCg0KDQpDeWNsaXN0czwtIEN5Y2xpc3RzWywgIShuYW1lcyhDeWNsaXN0cykgJWluJSBjKCJIaWdoVGVtcCIsICJMb3dUZW1wIiwgIlByZWNpcGl0YXRpb24iKSldDQoNCmhlYWQoQ3ljbGlzdHMpDQoNCmBgYA0KDQojIyBOZXcgVmFyaWFibGVzDQoNCkRhdGUgLSBUaGUgZGF0ZSBpbiB3aGljaCB0aGUgdG90YWwgbnVtYmVyIG9mIGJpa2VzIHdhcyByZWNvcmRlZCBhbmQgaXMgb3VyIG9ic2VydmF0aW9uIElELg0KRGF5IC0gVGhlIGRheSBvZiB0aGUgZ2l2ZW4gYnkgYSBudW1iZXINCkF2Z1RlbXAgLSBUaGUgYXZlcmFnZSB0ZW1wZXJhdHVyZSBvZiBhIGdpdmVuIGRheS4gbnVtZXJpY2FsDQpOZXdQcmVjcCAtIEdpdmVzIHVzIGEgMSBvciBhIDAgaWYgdGhlcmUgaXMgcHJlY2lwaXRhdGlvbiBvciBub25lLiAxIGZvciBwcmVjaXAgYW5kIDAgZm9yIG5vbmUNCk1hbmhhdHRhbkJyaWRnZSAtIFRoZSB0b3RhbCBudW1iZXIgb2YgY3ljbGlzdHMgb24gdGhlIGJyaWRnZSBvbiBhIGNlcnRhaW4gZGF5LiBudW1lcmljYWwgDQpUb3RhbCAtIFRoZSB0b3RhbCBudW1iZXIgb2YgYmlrZXMgcmVjb3JkZWQgb24gYWxsIHRoZSBicmlkZ2VzIGluIGEgY2VydGFpbiBkYXkuIG51bWVyaWNhbA0KDQojIyBEaXNwZXJzaW9uIEluZGV4DQoNCk5leHQsIHdlIGV4dHJhY3QgdGhlIGFwcHJveGltYXRlZCBkaXNwZXJzaW9uIGluZGV4IHVzaW5nIGJvdGggUGVhcnNvbiBhbmQgZGV2aWFuY2UgcmVzaWR1YWxzDQoNCmBgYHtyfQ0KcG9pcy5tb2RlbCA9IGdsbShNYW5oYXR0YW5CcmlkZ2UgfiBEYXkgKyBBdmdUZW1wKyBOZXdQcmVjaXAsIA0KICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbms9ImxvZyIpLCBkYXRhID1DeWNsaXN0cykgIA0KeWhhdCA9IHBvaXMubW9kZWwkZml0dGVkLnZhbHVlcw0KcGVhcnNvbi5yZXNpZCA9IChDeWNsaXN0cyRNYW5oYXR0YW5CcmlkZ2UgLSB5aGF0KS9zcXJ0KHloYXQpDQpQZWFyc29uLmRpc3AgPSBzdW0ocGVhcnNvbi5yZXNpZF4yKS9wb2lzLm1vZGVsJGRmLnJlc2lkdWFsDQoNCkRldmlhbmNlLmRpc3AgPSAocG9pcy5tb2RlbCRkZXZpYW5jZSkvcG9pcy5tb2RlbCRkZi5yZXNpZHVhbA0KDQpkaXNwID0gY2JpbmQoUGVhcnNvbi5kaXNwID0gUGVhcnNvbi5kaXNwLCBEZXZpYW5jZS5kaXNwID0gRGV2aWFuY2UuZGlzcCkNCmthYmxlKGRpc3AsIGNhcHRpb249IkRpc3BlcnNpb24gcGFyYW1ldGVyIiwgYWxpZ24gPSAnYycpDQoNCmBgYA0KDQpGcm9tIHRoZSBvdXRwdXQgYWJvdmUgb3VyIFBvaXNvbiBhc3N1bXB0aW9uIGlzIHNlcmlvdXNseSB2aW9sYXRlZC4gT3VyIGRpc3BlcnNpb24gb3V0cHV0IGlzIHZlcnkgZmFyIG9mZiBvdXIgdmFsdWUgb2YgMSBzbyB3ZSB3aWxsIGNvbnRpbnVlIGFuZCB1c2UgYSBRdWFzaSBwb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwgdG8gYWNjb3VudCBmb3Igb3VyIHZhcmlhdGlvbiBiZWluZyBiaWdnZXIgdGhhbiBvdXIgbWVhbi4NCg0KIyMgUXVhc2kgTW9kZWwNCg0KV2Ugbm93IHN1bW1hcml6ZSBvdXIgaW5mZXJlbnRpYWwgc3RhdGlzdGljcw0KDQpgYGB7cn0NCnF1YXNpLm1vZGVsID0gZ2xtKE1hbmhhdHRhbkJyaWRnZSB+IERheSArIEF2Z1RlbXAgKyBOZXdQcmVjaXAsIA0KICAgICAgICAgICAgICAgICBmYW1pbHkgPSBxdWFzaXBvaXNzb24sIGRhdGEgPUN5Y2xpc3RzKSAgDQpzdW1tYXJ5KHF1YXNpLm1vZGVsICkNCg0KYGBgDQpXZSBzZWUgZnJvbSB0aGUgYWJvdmUgb3V0cHV0IHRoYXQgb3VyIEF2Z3RlbXAgaXMgbm90IHNpZ25pZmljYW50LiBFdmVuIHRob3VnaCB0aGlzIGlzIGNvbmNlcm5pbmcgd2Uga25vdyB0aGF0IGF2ZXJhZ2UgdGVtcGVyYXR1cmUgZG9lcyBoYXZlIGFuIGFmZmVjdCBvbiB3aGV0aGVyIG9yIG5vdCBjeWNsaXN0cyBlbnRlciBhbmQgbGVhdmUgdGhlIGJyaWRnZS4gU28gd2UgY29udGludWUgYnV0IGJlIGNhcmVmdWwgb2Ygb3VyIG91dHB1dCBhbmQgaXRzIHNpZ25pZmljYW5jZS4gDQoNCmBgYHtyfQ0KU0UucXVhc2kucG9pcyA9IHN1bW1hcnkocXVhc2kubW9kZWwpJGNvZWYNCmthYmxlKFNFLnF1YXNpLnBvaXMsIGNhcHRpb24gPSAiU3VtbWFyeSBzdGF0aXN0aWNzIG9mIHF1YXNpLXBvaXNzb24gcmVncmVzc2lvbiBtb2RlbCIpDQoNCmBgYA0KDQpUaGlzIGlzIG91ciBmaW5hbCBtb2RlbC4gU2luY2Ugb3VyIG1vZGVsIGlzIGluIGxvZyBzY2FsZSB3ZSBuZWVkIHRvIHNob3cgdGhlc2UgdmFsdWVzIGluIGEgd2F5IHdlIGNhbiBkcmF3IGFjdHVhbCBjb25jbHVzaW9ucyBmcm9tLiBGb3IgZXhhbXBsZSwgdGhlIGNvZWZmaWNpZW50IGZvciBOZXdwcmVjaXAgaXMgLTAuNTA0LiBUaGlzIGlzIHRoZSBlc3RpbWF0ZWQgUG9pc3NvbiByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGNvbXBhcmluZyBwcmVjaXBpdGF0aW9uIG9yIG5vbmUsIGdpdmVuIHRoZSBvdGhlciB2YXJpYWJsZXMgYXJlIGhlbGQgY29uc3RhbnQgaW4gdGhlIG1vZGVsLiBUaGUgZGlmZmVyZW5jZSBpbiB0aGUgbG9ncyBvZiBleHBlY3RlZCBwdWJsaWNhdGlvbnMgaXMgZXhwZWN0ZWQgdG8gYmUgMC41MDQgdW5pdHMgbG93ZXIgZm9yIHByZWNpcGl0YXRpb24gY29tcGFyZWQgdG8gbm9uZSB3aGlsZSBob2xkaW5nIHRoZSBvdGhlciB2YXJpYWJsZXMgY29uc3RhbnQgaW4gdGhlIG1vZGVsLiBXaGF0IHdlIGNhbiBkbyB0byBtYWtlIHRoaXMgZWFzaWVyIHRvIHVuZGVyc3RhbmQgaXMgbWFrZSB2aXN1YWwgYWlkcyB0byBoZWxwIHVzIHNlZSB3aGF0IGlzIGFjdHVhbGx5IGhhcHBlbmluZy4NCg0KIyMgVmlzdWFsIEFpZA0KDQpOZXh0LCB3ZSBtYWtlIGEgdmlzdWFsaXphdGlvbiB0byBzaG93IGhvdyB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGluIHRoZSBmaW5hbCB3b3JraW5nIG1vZGVsIGFmZmVjdCB0aGUgYWN0dWFsIG51bWJlciBvZiBjeWNsaXN0cy4gDQpXZSBleHBvbmVudGlhdGUgdGhlIGxvZyBjb3VudCBvZiBjeWNsaXN0cyBhbmQgbWFrZSB0d28gZ3JhcGhzIHNob3djYXNpbmcgcHJlY2lwaXRhdGlvbi4gQm90aCBncmFwaHMgd2lsbCBzaG93IHRoZSBhbW91bnQgb2YgY3ljbGlzdHMgZ2l2ZW4gdGhlIHggYXhpcyBvZiBlaXRoZXIgZGF5cyBhbmQgYXZlcmFnZSB0ZW1wZXJhdHVyZS4gVGhlIGZpcnN0IGdyYXBoIHdpbGwgaG9sZCB0ZW1wZXJhdHVyZSBjb25zdGFudCBhbmQgc2hvd2Nhc2UgYXMgZGF5cyBwcm9ncmVzcyBob3cgbWFueSBjeWNsaXN0cyBhcmUgdGhlcmUgd2hpbGUgYWxzbyBzaG93aW5nIHRoZSBhZmZlY3Qgb2YgcHJlY2lwaXRhdGlvbiBhbmQgbm8gcHJlY2lwaXRhdGlvbi4gVGhlIHNlY29uZCBncmFwaCB3aWxsIGhvbGQgZGF5cyBjb25zdGFudCB3aGlsZSBhbHNvIHNob3djYXNpbmcgdGhlIGFmZmVjdCBvZiB0ZW1wZXJhdHVyZSBvbiB0aGUgY3ljbGlzdCBjb3VudCBhbmQgYWxzbyBzaG93aW5nIHByZWNpcGl0YXRpb24NCg0KDQoNCmBgYHtyfQ0KZGF5X3JhbmdlIDwtIHNlcShtaW4oQ3ljbGlzdHMkRGF5KSwgbWF4KEN5Y2xpc3RzJERheSksIGxlbmd0aC5vdXQgPSAxMDApICAjIERheXMgZnJvbSBtaW4gdG8gbWF4DQp0ZW1wX3JhbmdlIDwtIHNlcShtaW4oQ3ljbGlzdHMkQXZnVGVtcCksIDkwLCBsZW5ndGgub3V0ID0gMTAwKSAgIyBUZW1wZXJhdHVyZSBmcm9tIG1pbiB0byA5MCBkZWdyZWVzDQoNCiMgQ3JlYXRlIGEgbmV3IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpwcmVkX2RhdGEgPC0gZGF0YS5mcmFtZShEYXkgPSByZXAoZGF5X3JhbmdlLCBlYWNoID0gMiksICAjIFR3byByb3dzIGZvciBlYWNoIGRheSwgZm9yIGJvdGggUHJlY2lwaXRhdGlvbiAwIGFuZCAxDQogICAgICAgICAgICAgICAgICAgICAgICBBdmdUZW1wID0gcmVwKG1lYW4oQ3ljbGlzdHMkQXZnVGVtcCksIDIwMCksICAjIEhvbGQgQXZnVGVtcCBjb25zdGFudA0KICAgICAgICAgICAgICAgICAgICAgICAgTmV3UHJlY2lwMSA9IHJlcChjKDAsIDEpLCBlYWNoID0gMTAwKSkgICMgUHJlY2lwaXRhdGlvbiAwIGFuZCAxDQoNCiMgQ2FsY3VsYXRlIHByZWRpY3RlZCBjeWNsaXN0IGNvdW50cyBmb3IgYm90aCBjb25kaXRpb25zIChubyBwcmVjaXBpdGF0aW9uIGFuZCBwcmVjaXBpdGF0aW9uKQ0KcHJlZF9kYXRhJEN5Y2xpc3RzX1ByZWRpY3RlZCA8LSBleHAoNTA3LjI2MzM4NjAgLSAwLjAxMTU3OTYgKiBwcmVkX2RhdGEkRGF5IC0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4wMDU2MjMxICogcHJlZF9kYXRhJEF2Z1RlbXAgLSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjUwMzk3NjAgKiBwcmVkX2RhdGEkTmV3UHJlY2lwMSkNCg0KIyBQbG90IHRoZSBlZmZlY3Qgb2YgRGF5IG9uIHByZWRpY3RlZCBjeWNsaXN0IGNvdW50cyBmb3IgYm90aCBQcmVjaXBpdGF0aW9uIDAgYW5kIDENCmdncGxvdChwcmVkX2RhdGEsIGFlcyh4ID0gRGF5LCB5ID0gQ3ljbGlzdHNfUHJlZGljdGVkLCBjb2xvciA9IGZhY3RvcihOZXdQcmVjaXAxKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicmVkIiwgImJsdWUiKSwgbGFiZWxzID0gYygiTm8gUHJlY2lwaXRhdGlvbiIsICJQcmVjaXBpdGF0aW9uIikpICsNCiAgbGFicyh0aXRsZSA9ICJFZmZlY3Qgb2YgRGF5IG9uIFByZWRpY3RlZCBDeWNsaXN0IENvdW50cyIsDQogICAgICAgeCA9ICJEYXkiLA0KICAgICAgIHkgPSAiUHJlZGljdGVkIEN5Y2xpc3QgQ291bnRzIiwNCiAgICAgICBjb2xvciA9ICJQcmVjaXBpdGF0aW9uIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBOb3cgcGxvdCB0aGUgZWZmZWN0IG9mIEF2Z1RlbXAgb24gcHJlZGljdGVkIGN5Y2xpc3QgY291bnRzIGZvciBib3RoIFByZWNpcGl0YXRpb24gMCBhbmQgMQ0KcHJlZF9kYXRhJEF2Z1RlbXAgPC0gdGVtcF9yYW5nZQ0KcHJlZF9kYXRhJEN5Y2xpc3RzX1ByZWRpY3RlZCA8LSBleHAoNTA3LjI2MzM4NjAgLSAwLjAxMTU3OTYgKiBwcmVkX2RhdGEkRGF5IC0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4wMDU2MjMxICogcHJlZF9kYXRhJEF2Z1RlbXAgLSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjUwMzk3NjAgKiBwcmVkX2RhdGEkTmV3UHJlY2lwMSkNCg0KZ2dwbG90KHByZWRfZGF0YSwgYWVzKHggPSBBdmdUZW1wLCB5ID0gQ3ljbGlzdHNfUHJlZGljdGVkLCBjb2xvciA9IGZhY3RvcihOZXdQcmVjaXAxKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicmVkIiwgImJsdWUiKSwgbGFiZWxzID0gYygiTm8gUHJlY2lwaXRhdGlvbiIsICJQcmVjaXBpdGF0aW9uIikpICsNCiAgbGFicyh0aXRsZSA9ICJFZmZlY3Qgb2YgQXZnVGVtcCBvbiBQcmVkaWN0ZWQgQ3ljbGlzdCBDb3VudHMiLA0KICAgICAgIHggPSAiQXZlcmFnZSBUZW1wZXJhdHVyZSAoXHUwMGIwRikiLCAgIyBVc2luZyBVbmljb2RlIGZvciBkZWdyZWUgc3ltYm9sDQogICAgICAgeSA9ICJQcmVkaWN0ZWQgQ3ljbGlzdCBDb3VudHMiLA0KICAgICAgIGNvbG9yID0gIlByZWNpcGl0YXRpb24iKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKG1pbihDeWNsaXN0cyRBdmdUZW1wKSwgODApKSArICAjIFNldCB4LWF4aXMgdG8gZ28gdXAgdG8gOTAgZGVncmVlcw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpXZSBzZWUgZnJvbSB0aGUgZ3JhcGggYWJvdmUgdGhhdCBwcmVjaXBpdGF0aW9uIGhhcyBhIG1ham9yIGVmZmVjdCBvbiBib3RoIG9mIHRoZSBncmFwaHMuIEZyb20gdGhlIHJlZCBhbmQgdGhlIGJsdWUgbGluZXMgYXJlIGRyYXN0aWNhbGx5IGRpZmZlcmVudCwgdGhlIHJlZCBsaW5lIGlzIHdheSBhYm92ZSB0aGUgYmx1ZSBsaW5lIHNob3dpbmcgdGhhdCB0aGUgcHJlZGljdGVkIGNvdW50cyBnbyBkb3duIHdoZW4gdGhlcmUgaXMgcHJlY2lwaXRhdGlvbi4gVGhlIGZpcnN0IGdyYXBoIHNob3djYXNlcyB0aGUgRGF5cywgc2hvd3MgdGhhdCB0aGVyZSBpcyBhIGRlY3JlYXNlIHdoZW4gdGhlIGRheXMgZ29lcyB1cC4gQWxzbyBmcm9tIHRoZSBzZWNvbmQgZ3JhcGggd2Ugc2VlIHRoYXQgYWdhaW4gd2hlbiB0aGUgdGVtcGVyYXR1cmUgZ29lcyB1cCB0aGUgcHJlZGljdGVkIGNvdW50IG9mIGN5Y2xpc3RzIGdvZXMgZG93bi4NCg0KDQoNCg0KIyBDb25jbHVzaW9uDQoNCldlIGRvIG5vdCB1c2Ugb3VyIG9yaWdpbmFsIFBvaXNzb24gcmVncmVzc2lvbiBiZWNhdXNlIG9mIG91ciBiaWcgdmFsdWUgb2Ygb3VyIGRpc3BlcnNpb24uIFRoaXMgYmlnIGRpc3BlcnNpb24gdmFsdWUgbWVhbnMgdGhhdCBvdXIgdmFyaWFuY2UgaXMgYSBsb3QgYmlnZ2VyIHRoYW4gb3VyIG1lYW4uIFNvIHdlIHRoZW4gdXNlIGEgUXVhc2kgUG9pc3NvbiBtb2RlbCB0byBhY2NvdW50IGZvciB0aGlzIG92ZXIgZGlzcGVyc2lvbiBieSBpbnRyb2R1Y2luZyBhIGRpc3BlcnNpb24gcGFyYW1ldGVyLiBUaGlzIG1vZGVsIGdhdmUgdXMgbW9yZSBhY2N1cmF0ZSBwLXZhbHVlcy4gSnVkZ2luZyBmcm9tIG91ciBncmFwaHMgYW5kIG91dHB1dCBhYm92ZSB3ZSBzZWUgdGhhdCBwcmVjaXBpdGF0aW9uIGhhcyB0aGUgYmlnZ2VzdCBpbmZsdWVuY2UuIFByZWNpcGl0YXRpb24gaGFzIHRoZSBiaWdnZXN0IGFic29sdXRlIHZhbHVlIGNvZWZmaWNpZW50IGFuZCBhbHNvIHNob3dzIHRoZSBiaWdnZXN0IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIHNpZGVzIG9mIG91ciB2YXJpYWJsZXMuIFRoZXJlIGlzIGFsc28gYSBncmFkdWFsIGRlY3JlYXNlIGluIGJvdGggb2YgdGhlIGdyYXBocy4gV2hlbiBib3RoIGRheXMgYW5kIHRlbXBlcmF0dXJlIGdvIHVwIGluIHRoZWlyIHJlc3BlY3RpdmUgZ3JhcGhzIHRoZSBjb3VudCBvZiBjeWNsaXN0cyBnb2VzIGRvd24uIA==