1 Introduction

1.1 Description

The daily total of bike counts was conducted monthly on the Manhattan Bridge. To keep count of cyclists entering and leaving the Manhattan bridge the Traffic Information Management System (TIMS) collects the count data. Each record represents the total number of cyclists per 24 hours at Brooklyn Bridge

Date - The date in which the total number of bikes was recorded and is our observation ID. Day - The day of the week Monday through Sunday HighTemp - The highest the temperature on a certain day LowTemp - The low temperature on a certain day Precipitation - The amount of rain recorded for that day, most likely in inches of rain ManhattanBridge - The total number of cyclists on the bridge on a certain day Total - The total number of bikes recorded on all the bridges in a certain day

1.2 Research Question

How do various predictors affect the amount of cyclists on this city’s bridges. This analysis aims to identify significant predictors of cyclist totals using Poisson regression and focusing on variables such as temperature, day, and precipitation. Our response variable for this analysis is total number of cyclists

2 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

2.1 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.
Estimate Std. Error z value Pr(>|z|)
(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.

2.2 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.
Estimate Std. Error z value Pr(>|z|)
(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.

2.3 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

2.4 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

2.5 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
Pearson.disp Deviance.disp
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.

2.6 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
Estimate Std. Error t value Pr(>|t|)
(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.

2.7 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.

3 Conclusion

We do not use our original Poisson regression because of our big value of our dispersion. This big dispersion value means that our variance is a lot bigger than our mean. So we then use a Quasi Poisson model to account for this over dispersion by introducing a dispersion parameter. This model gave us more accurate p-values. Judging from our graphs and output above we see that precipitation has the biggest influence. Precipitation has the biggest absolute value coefficient and also shows the biggest difference between the two sides of our variables. There is also a gradual decrease in both of the graphs. When both days and temperature go up in their respective graphs the count of cyclists goes down.

LS0tDQp0aXRsZTogIlBvaXNzb24gUmVncmVzc2lvbiBvZiBNYW5oYXR0YW4gQnJpZGdlIg0KYXV0aG9yOiAnVHlsZXIgQmF0dGFnbGluaScNCmRhdGU6ICIyMDI0LTExLTMiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBmaWdfd2lkdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCmFsd2F5c19hbGxvd19odG1sOiB0cnVlDQotLS0NCg0KYGBgez1odG1sfQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQovKiBDYXNjYWRpbmcgU3R5bGUgU2hlZXRzIChDU1MpIGlzIGEgc3R5bGVzaGVldCBsYW5ndWFnZSB1c2VkIHRvIGRlc2NyaWJlIHRoZSBwcmVzZW50YXRpb24gb2YgYSBkb2N1bWVudCB3cml0dGVuIGluIEhUTUwgb3IgWE1MLiBpdCBpcyBhIHNpbXBsZSBtZWNoYW5pc20gZm9yIGFkZGluZyBzdHlsZSAoZS5nLiwgZm9udHMsIGNvbG9ycywgc3BhY2luZykgdG8gV2ViIGRvY3VtZW50cy4gKi8NCg0KaDEudGl0bGUgeyAgLyogVGl0bGUgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIHRoZSByZXBvcnQgdGl0bGUgKi8NCiAgZm9udC1zaXplOiAyNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgdGhlIGRhdGUgICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDEgeyAvKiBIZWFkZXIgMSAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDEgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KaDIgeyAvKiBIZWFkZXIgMiAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDIgc2VjdGlvbiB0aXRsZSAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCAzIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KPC9zdHlsZT4NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgRGV0ZWN0LCBpbnN0YWxsIGFuZCBsb2FkIHBhY2thZ2VzIGlmIG5lZWRlZC4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgibmxlcXNsdiIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJubGVxc2x2IikNCiAgIGxpYnJhcnkobmxlcXNsdikNCn0NCiMNCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCg0KaWYgKCFyZXF1aXJlKCJwc3ljaCIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoInBzeWNoIikNCiAgIGxpYnJhcnkocHN5Y2gpDQp9DQppZiAoIXJlcXVpcmUoIk1BU1MiKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgIGxpYnJhcnkoTUFTUykNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICAgbGlicmFyeShnZ3Bsb3QyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJHR2FsbHkiKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQ0KICAgbGlicmFyeShHR2FsbHkpDQp9DQppZiAoIXJlcXVpcmUoImNhciIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoImNhciIpDQogICBsaWJyYXJ5KGNhcikNCn0NCmlmICghcmVxdWlyZSgiZHBseXIiKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQogICBsaWJyYXJ5KGRwbHlyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjYXJldCIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoImNhcmV0IikNCiAgIGxpYnJhcnkoY2FyZXQpDQp9DQppZiAoIXJlcXVpcmUoInJlYWR4bCIpKSB7ICAgDQogIGluc3RhbGwucGFja2FnZXMoInJlYWR4bCIpDQogICBsaWJyYXJ5KHJlYWR4bCkNCn0NCmlmICghcmVxdWlyZSgib3Blbnhsc3giKSkgeyAgIA0KICBpbnN0YWxsLnBhY2thZ2VzKCJvcGVueGxzeCIpDQogICBsaWJyYXJ5KG9wZW54bHN4KQ0KfQ0KIyBzcGVjaWZpY2F0aW9ucyBvZiBvdXRwdXRzIG9mIGNvZGUgaW4gY29kZSBjaHVua3MNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5ncyA9IEZBTFNFLCAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZXMgPSBGQUxTRSwgICMNCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEgICAgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgICkgICANCmBgYA0KDQojIEludHJvZHVjdGlvbg0KDQojIyBEZXNjcmlwdGlvbg0KDQpUaGUgZGFpbHkgdG90YWwgb2YgYmlrZSBjb3VudHMgd2FzIGNvbmR1Y3RlZCBtb250aGx5IG9uIHRoZSBNYW5oYXR0YW4gQnJpZGdlLiBUbyBrZWVwIGNvdW50IG9mIGN5Y2xpc3RzIGVudGVyaW5nIGFuZCBsZWF2aW5nIHRoZSBNYW5oYXR0YW4gYnJpZGdlIHRoZSBUcmFmZmljIEluZm9ybWF0aW9uIE1hbmFnZW1lbnQgU3lzdGVtIChUSU1TKSBjb2xsZWN0cyB0aGUgY291bnQgZGF0YS4gRWFjaCByZWNvcmQgcmVwcmVzZW50cyB0aGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIHBlciAyNCBob3VycyBhdCBCcm9va2x5biBCcmlkZ2UNCg0KRGF0ZSAtIFRoZSBkYXRlIGluIHdoaWNoIHRoZSB0b3RhbCBudW1iZXIgb2YgYmlrZXMgd2FzIHJlY29yZGVkIGFuZCBpcyBvdXIgb2JzZXJ2YXRpb24gSUQuDQpEYXkgLSBUaGUgZGF5IG9mIHRoZSB3ZWVrIE1vbmRheSB0aHJvdWdoIFN1bmRheQ0KSGlnaFRlbXAgLSBUaGUgaGlnaGVzdCB0aGUgdGVtcGVyYXR1cmUgb24gYSBjZXJ0YWluIGRheQ0KTG93VGVtcCAtIFRoZSBsb3cgdGVtcGVyYXR1cmUgb24gYSBjZXJ0YWluIGRheQ0KUHJlY2lwaXRhdGlvbiAtIFRoZSBhbW91bnQgb2YgcmFpbiByZWNvcmRlZCBmb3IgdGhhdCBkYXksIG1vc3QgbGlrZWx5IGluIGluY2hlcyBvZiByYWluDQpNYW5oYXR0YW5CcmlkZ2UgLSBUaGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIG9uIHRoZSBicmlkZ2Ugb24gYSBjZXJ0YWluIGRheQ0KVG90YWwgLSBUaGUgdG90YWwgbnVtYmVyIG9mIGJpa2VzIHJlY29yZGVkIG9uIGFsbCB0aGUgYnJpZGdlcyBpbiBhIGNlcnRhaW4gZGF5DQoNCiMjIFJlc2VhcmNoIFF1ZXN0aW9uDQpIb3cgZG8gdmFyaW91cyBwcmVkaWN0b3JzIGFmZmVjdCB0aGUgYW1vdW50IG9mIGN5Y2xpc3RzIG9uIHRoaXMgY2l0eSdzIGJyaWRnZXMuIFRoaXMgYW5hbHlzaXMgYWltcyB0byBpZGVudGlmeSBzaWduaWZpY2FudCBwcmVkaWN0b3JzIG9mIGN5Y2xpc3QgdG90YWxzIHVzaW5nIFBvaXNzb24gcmVncmVzc2lvbiBhbmQgZm9jdXNpbmcgb24gdmFyaWFibGVzIHN1Y2ggYXMgdGVtcGVyYXR1cmUsIGRheSwgYW5kIHByZWNpcGl0YXRpb24uIE91ciByZXNwb25zZSB2YXJpYWJsZSBmb3IgdGhpcyBhbmFseXNpcyBpcyB0b3RhbCBudW1iZXIgb2YgY3ljbGlzdHMNCg0KIyBEYXRhIEFuYWx5c2lzDQoNCldlIHdpbGwgZmlyc3QgZ2V0IGEgYnJpZWYgc3VtbWFyeSBvZiBvdXIgZGF0YSB0byBnZXQgYSBnb29kIHNjb3BlIG9mIHRoZSBkYXRhIHNldC4gDQoNCmBgYHtyfQ0KQ3ljbGlzdHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9UeWxlckJhdHRhZ2xpbmkvU1RBLTMyMS9yZWZzL2hlYWRzL21haW4vTWFuaGF0dGFuQnJpZGdlLmNzdiIsIGhlYWRlciA9IFRSVUUpDQpzdW1tYXJ5KEN5Y2xpc3RzKQ0KdmFyKEN5Y2xpc3RzKQ0KYGBgDQoNCiMjIFBvaXNzb24gUmVncmVzc2lvbiBvbiBDeWNsaXN0cyBDb3VudA0KDQpXZSBmaXJzdCBidWlsZCBhIFBvaXNzb24gcmVncmVzc2lvbiB3aXRoIGNvdW50cyBhcyBvdXIgcmVzcG9uc2UgYW5kIGFsc28gbGVhdmluZyBvdXQgdGhlIFRvdGFsLiBXZSB1c2UgUG9pc3NvbiByZWdyZXNzaW9uIGZvciB0aGlzIG1vZGVsIGJlY2F1c2UgdGhpcyBpcyBhIGNvdW50IGRhdGEsIHdoaWNoIHNob3dzIHRoZSBudW1iZXIgb2Ygb2NjdXJyZW5jZXMgb2YgYW4gZXZlbnQsIGluIHRoaXMgY2FzZSBjeWNsaXN0IGNvdW50cywgd2l0aGluIGEgZml4ZWQgaW50ZXJ2YWwgb2YgdGltZS4gV2UgYXNzdW1lIHRoYXQgb3VyIGNvdW50cyBhcmUgaW5kZXBlbmRlbnQgZnJvbSBvbmUgYW5vdGhlciBhbmQgYWxzbyB0aGF0IG91ciB2YXJpYW5jZSBhbmQgbWVhbiBhcmUgZXF1YWwgdG8gZWFjaCBvdGhlci4NCg0KYGBge3J9DQptb2RlbC5mcmVxIDwtIGdsbShNYW5oYXR0YW5CcmlkZ2V+IEhpZ2hUZW1wICsgUHJlY2lwaXRhdGlvbiArIExvd1RlbXAgKyBEYXksIGZhbWlseSA9IHBvaXNzb24obGluayA9ICJsb2ciKSwgZGF0YSA9IEN5Y2xpc3RzKQ0KcG9pcy5jb3VudC5jb2VmID0gc3VtbWFyeShtb2RlbC5mcmVxKSRjb2VmDQprYWJsZShwb2lzLmNvdW50LmNvZWYsIGNhcHRpb24gPSAiVGhlIFBvaXNzb24gcmVncmVzc2lvbiBtb2RlbCBmb3IgdGhlIGNvdW50cyBvZiBjeWNsaXN0cyBlbnRlcmluZyB0aGUgYnJpZGdlIHZzIHRoZSB0ZW1wYXR1cmUsIHByZWNpcGl0YXRpb24sIGFuZCBkYXkuIikNCg0KYGBgDQoNClRoZSBhYm92ZSBkYXRhIGFib3ZlIHNob3dzIHRoYXQgYWxsIG91ciBkYXRhIGFib3ZlIGlzIHNpZ25pZmljYW50IGF0IGFuIGFscGhhIGxldmVsIG9mIC4wNS4gVGhpcyBtZWFucyB0aGF0IHdlIGhhdmUgc3RhdGlzdGljYWwgZXZpZGVuY2UgdG8gZHJhdyBjb25jbHVzaW9ucy4gRWFjaCBjb2VmZmljaWVudCByZXByZXNlbnRzIHRoZSBsb2cgY2hhbmdlIGluIHRoZSBleHBlY3RlZCBjb3VudCBmb3Igb25lIHVuaXQgaW5jcmVhc2UgaW4gb3VyIHByZWRpY3RvciB2YWx1ZSB3aGlsZSBhc3N1bWluZyBhbGwgb3RoZXIgdmFsdWVzIGFyZSBjb25zdGFudC5Gb3IgZXhhbXBsZSB3ZSBjYW4gZXhwZWN0IHdoZW4gcHJlY2lwaXRhdGlvbiBnb2VzIHVwIGJ5IG9uZSB1bml0IHdlIGNhbiBleHBlY3Qgb3VyIGNvdW50IHRvIGdvIGRvd24gYnkgLS45NTkuIFNvbWUgb3RoZXIgZmluZGluZ3Mgd2UgY2FuIHNlZSBmcm9tIG91ciBvdXRwdXQgYWJvdmUgaXMgdGhhdCBwcmVjaXBpdGF0aW9uIGlzIG91ciBiaWdnZXN0IGluZmx1ZW5jZSBvbiB0aGUgY291bnQgYmVjYXVzZSBpdHMgYWJzb2x1dGUgdmFsdWUgaXMgdGhlIGhpZ2hlc3Qgb3V0IGFsbCB0aGUgY29lZmZpY2llbnRzLiBXZSBhbHNvIHNlZSB3aGVuIGNvbXBhcmluZyBsb3cgdGVtcGVyYXR1cmUgd2l0aCBoaWdoIHRlbXBlcmF0dXJlIHRoYXQgYSBsb3dlciB0ZW1wZXJhdHVyZSB3aWxsIHRlbmQgdG8gaGF2ZSBtb3JlIGFmZmVjdCBvbiBvdXIgY291bnQgcmF0aGVyIHRoYW4gaGlnaCB0ZW1wZXJhdHVyZXMgYmVjYXVzZSB0aGUgbG93IHRlbXBlcmF0dXJlIGhhcyBhIGhpZ2hlciBhYnNvbHV0ZSB2YWx1ZS4gDQoNCiMjIFBvaXNzb24gUnJlZ3Jlc3Npb24gb24gUmF0ZXMNCg0KVGhlIGZvbGxvd2luZyBtb2RlbCBoYXMgdGhlIHNhbWUgdmFyaWFibGVzIGJ1dCB3ZSBhcmUgb2Zmc2V0dGluZyB3aXRoIHRoZSBUb3RhbCBjb3VudC4gQnkgdGFraW5nIHRoZSBsb2dhcml0aG0gb2YgVG90YWwgY291bnQgYXMgdGhlIG9mZnNldCwgd2UgYXJlIGFkanVzdGluZyB0aGUgY291bnRzIG9mIGN5Y2xpc3RzIG9uIHRoZSBNYW5oYXR0YW4gQnJpZGdlIGZvciB0aGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIGFjcm9zcyBhbGwgYnJpZGdlcy4gVGhpcyBtZWFucyB0aGF0IGlmIHRoZSB0b3RhbCBudW1iZXIgb2YgY3ljbGlzdHMgdmFyaWVzIHNpZ25pZmljYW50bHkgZnJvbSBkYXkgdG8gZGF5LCB0aGUgbW9kZWwgd2lsbCBhY2NvdW50IGZvciB0aGF0IHZhcmlhYmlsaXR5Lg0KDQpgYGB7cn0NCm1vZGVsLnJhdGVzIDwtIGdsbShNYW5oYXR0YW5CcmlkZ2UgfiBIaWdoVGVtcCArIFByZWNpcGl0YXRpb24gKyBMb3dUZW1wICsgRGF5LCBvZmZzZXQgPSBsb2coVG90YWwpLCANCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIiksIGRhdGEgPSBDeWNsaXN0cykNCmthYmxlKHN1bW1hcnkobW9kZWwucmF0ZXMpJGNvZWYsIGNhcHRpb24gPSAiUG9pc3NvbiByZWdyZXNzaW9uIG9uIHRoZSByYXRlIG9mIHRoZSANCiAgICAgIHRoZSBjeWNsaXN0cyBlbnRlcmluZyBhbmQgbGVhdmluZyB0aGUgQnJvb2tseW4gQnJpZGdlLiIpDQpgYGANCg0KV2Ugc2VlIGZyb20gdGhlIGFib3ZlIG91dHB1dCB0aGF0IGFsbCBvZiBvdXIgcC12YWx1ZXMgYXJlIGJsb3cgYSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgLjAxIGV4Y2VwdCBmb3IgSGlnaCB0ZW1wLiBXZSBhbHNvIHNlZSB0aGF0IGFsbCBvZiBvdXIgY29lZmZpY2llbnRzIGhhdmUgY2hhbmdlZCB0byBhIGxvd2VyIGFic29sdXRlIHZhbHVlLiBPbmUgY2hhbmdlIHRoYXQgc3Rvb2Qgb3V0IHRvIG1lIHdhcyB0aGUgZGVjcmVhc2Ugb2YgaGlnaCB0ZW1wLCBjb21wYXJlZCB0byB0aGUgb3RoZXIgY29lZmZpY2llbnRzIHRoaXMgb25lIGRyb3BwZWQgdGhlIG1vc3QgYW5kIGlzIGJhc2ljYWxseSBhIG5vbiBmYWN0b3IgaW4gcHJlZGljdGluZyB0aGUgbW9kZWwuDQoNCiMjIEVEQSBhbmQgRmVhdHVyZSBFbmdpbmVlcmluZw0KDQpTaW5jZSBsb3cgdGVtcCBhbmQgaGlnaCB0ZW1wIGFyZSB2ZXJ5IHNpbWlsYXIgdmFyaWFibGVzIHdlIGNvbWJpbmUgdG8gbWFrZSBhdmVyYWdlIHRlbXBlcmF0dXJlLiBUaGlzIHdpbGwgZ2l2ZSB1cyBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIGhvdyBtYW55IHBlb3BsZSBnbyBjeWNsaW5nIG9uIHRoZSBicmlkZ2UgZ2l2ZW4gdGhlIGF2ZXJhZ2UgdGVtcGVyYXR1cmUgb2YgdGhlIGRheSBub3QganVzdCBoaWdoIGFuZCBsb3cgdGVtcC4gU28gd2UgYWRkIHVwIHRoZSB0d28gdmFyaWFibGVzIGFuZCB0aGVuIGRpdmlkZSBieSB0d28gdG8gZ2V0IHRoZSBkYXlzIGF2ZXJhZ2UuIFdlIHRoZW4gY2hhbmdlIG91ciBwcmVjaXBpdGF0aW9uIHZhcmlhYmxlIGZvciB0aGUgcHVycG9zZSBvZiBzZWVpbmcgaWYgYW55IHR5cGUgb2YgcHJlY2lwaXRhdGlvbiB0aHJvdWdob3V0IHRoZSBkYXkgY2hhbmdlZCBvdXIgdG90YWxzLiBTbyB3aGF0IHdlIGRvIGlzIGFzc2lnbiBhIDAgaWYgdGhlcmUgd2FzIG5vIHJhaW4gb24gYSBkYXkgYW5kIHRoZW4gYSAxIGlmIHRoZXJlIHdhcyBhbnkgcHJlY2lwaXRhdGlvbiBvbiB0aGF0IGRheS4NCg0KDQpgYGB7cn0NCkN5Y2xpc3RzJEF2Z1RlbXAgPC0gKEN5Y2xpc3RzJEhpZ2hUZW1wICsgQ3ljbGlzdHMkTG93VGVtcCkgLyAyDQoNCkN5Y2xpc3RzJE5ld1ByZWNpcCA8LSBpZmVsc2UoQ3ljbGlzdHMkUHJlY2lwaXRhdGlvbiA+IDAsIDEsIDApDQpDeWNsaXN0cyROZXdQcmVjaXAgPC0gYXMuZmFjdG9yKEN5Y2xpc3RzJE5ld1ByZWNpcCkNCg0KDQpDeWNsaXN0czwtIEN5Y2xpc3RzWywgIShuYW1lcyhDeWNsaXN0cykgJWluJSBjKCJIaWdoVGVtcCIsICJMb3dUZW1wIiwgIlByZWNpcGl0YXRpb24iKSldDQoNCmhlYWQoQ3ljbGlzdHMpDQoNCmBgYA0KDQojIyBOZXcgVmFyaWFibGVzDQoNCkRhdGUgLSBUaGUgZGF0ZSBpbiB3aGljaCB0aGUgdG90YWwgbnVtYmVyIG9mIGJpa2VzIHdhcyByZWNvcmRlZCBhbmQgaXMgb3VyIG9ic2VydmF0aW9uIElELg0KRGF5IC0gVGhlIGRheSBvZiB0aGUgZ2l2ZW4gYnkgYSBudW1iZXINCkF2Z1RlbXAgLSBUaGUgYXZlcmFnZSB0ZW1wZXJhdHVyZSBvZiBhIGdpdmVuIGRheS4gbnVtZXJpY2FsDQpOZXdQcmVjcCAtIEdpdmVzIHVzIGEgMSBvciBhIDAgaWYgdGhlcmUgaXMgcHJlY2lwaXRhdGlvbiBvciBub25lLiAxIGZvciBwcmVjaXAgYW5kIDAgZm9yIG5vbmUNCk1hbmhhdHRhbkJyaWRnZSAtIFRoZSB0b3RhbCBudW1iZXIgb2YgY3ljbGlzdHMgb24gdGhlIGJyaWRnZSBvbiBhIGNlcnRhaW4gZGF5LiBudW1lcmljYWwgDQpUb3RhbCAtIFRoZSB0b3RhbCBudW1iZXIgb2YgYmlrZXMgcmVjb3JkZWQgb24gYWxsIHRoZSBicmlkZ2VzIGluIGEgY2VydGFpbiBkYXkuIG51bWVyaWNhbA0KDQojIyBEaXNwZXJzaW9uIEluZGV4DQoNCk5leHQsIHdlIGV4dHJhY3QgdGhlIGFwcHJveGltYXRlZCBkaXNwZXJzaW9uIGluZGV4IHVzaW5nIGJvdGggUGVhcnNvbiBhbmQgZGV2aWFuY2UgcmVzaWR1YWxzDQoNCmBgYHtyfQ0KcG9pcy5tb2RlbCA9IGdsbShNYW5oYXR0YW5CcmlkZ2UgfiBEYXkgKyBBdmdUZW1wKyBOZXdQcmVjaXAsIA0KICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbms9ImxvZyIpLCBkYXRhID1DeWNsaXN0cykgIA0KeWhhdCA9IHBvaXMubW9kZWwkZml0dGVkLnZhbHVlcw0KcGVhcnNvbi5yZXNpZCA9IChDeWNsaXN0cyRNYW5oYXR0YW5CcmlkZ2UgLSB5aGF0KS9zcXJ0KHloYXQpDQpQZWFyc29uLmRpc3AgPSBzdW0ocGVhcnNvbi5yZXNpZF4yKS9wb2lzLm1vZGVsJGRmLnJlc2lkdWFsDQoNCkRldmlhbmNlLmRpc3AgPSAocG9pcy5tb2RlbCRkZXZpYW5jZSkvcG9pcy5tb2RlbCRkZi5yZXNpZHVhbA0KDQpkaXNwID0gY2JpbmQoUGVhcnNvbi5kaXNwID0gUGVhcnNvbi5kaXNwLCBEZXZpYW5jZS5kaXNwID0gRGV2aWFuY2UuZGlzcCkNCmthYmxlKGRpc3AsIGNhcHRpb249IkRpc3BlcnNpb24gcGFyYW1ldGVyIiwgYWxpZ24gPSAnYycpDQoNCmBgYA0KDQpGcm9tIHRoZSBvdXRwdXQgYWJvdmUgb3VyIFBvaXNvbiBhc3N1bXB0aW9uIGlzIHNlcmlvdXNseSB2aW9sYXRlZC4gT3VyIGRpc3BlcnNpb24gb3V0cHV0IGlzIHZlcnkgZmFyIG9mZiBvdXIgdmFsdWUgb2YgMSBzbyB3ZSB3aWxsIGNvbnRpbnVlIGFuZCB1c2UgYSBRdWFzaSBwb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwgdG8gYWNjb3VudCBmb3Igb3VyIHZhcmlhdGlvbiBiZWluZyBiaWdnZXIgdGhhbiBvdXIgbWVhbi4NCg0KIyMgUXVhc2kgTW9kZWwNCg0KV2Ugbm93IHN1bW1hcml6ZSBvdXIgaW5mZXJlbnRpYWwgc3RhdGlzdGljcw0KDQpgYGB7cn0NCnF1YXNpLm1vZGVsID0gZ2xtKE1hbmhhdHRhbkJyaWRnZSB+IERheSArIEF2Z1RlbXAgKyBOZXdQcmVjaXAsIA0KICAgICAgICAgICAgICAgICBmYW1pbHkgPSBxdWFzaXBvaXNzb24sIGRhdGEgPUN5Y2xpc3RzKSAgDQpzdW1tYXJ5KHF1YXNpLm1vZGVsICkNCg0KYGBgDQpXZSBzZWUgZnJvbSB0aGUgYWJvdmUgb3V0cHV0IHRoYXQgb3VyIEF2Z3RlbXAgaXMgbm90IHNpZ25pZmljYW50LiBFdmVuIHRob3VnaCB0aGlzIGlzIGNvbmNlcm5pbmcgd2Uga25vdyB0aGF0IGF2ZXJhZ2UgdGVtcGVyYXR1cmUgZG9lcyBoYXZlIGFuIGFmZmVjdCBvbiB3aGV0aGVyIG9yIG5vdCBjeWNsaXN0cyBlbnRlciBhbmQgbGVhdmUgdGhlIGJyaWRnZS4gU28gd2UgY29udGludWUgYnV0IGJlIGNhcmVmdWwgb2Ygb3VyIG91dHB1dCBhbmQgaXRzIHNpZ25pZmljYW5jZS4gDQoNCmBgYHtyfQ0KU0UucXVhc2kucG9pcyA9IHN1bW1hcnkocXVhc2kubW9kZWwpJGNvZWYNCmthYmxlKFNFLnF1YXNpLnBvaXMsIGNhcHRpb24gPSAiU3VtbWFyeSBzdGF0aXN0aWNzIG9mIHF1YXNpLXBvaXNzb24gcmVncmVzc2lvbiBtb2RlbCIpDQoNCmBgYA0KDQpUaGlzIGlzIG91ciBmaW5hbCBtb2RlbC4gU2luY2Ugb3VyIG1vZGVsIGlzIGluIGxvZyBzY2FsZSB3ZSBuZWVkIHRvIHNob3cgdGhlc2UgdmFsdWVzIGluIGEgd2F5IHdlIGNhbiBkcmF3IGFjdHVhbCBjb25jbHVzaW9ucyBmcm9tLiBGb3IgZXhhbXBsZSwgdGhlIGNvZWZmaWNpZW50IGZvciBOZXdwcmVjaXAgaXMgLTAuNTA0LiBUaGlzIGlzIHRoZSBlc3RpbWF0ZWQgUG9pc3NvbiByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGNvbXBhcmluZyBwcmVjaXBpdGF0aW9uIG9yIG5vbmUsIGdpdmVuIHRoZSBvdGhlciB2YXJpYWJsZXMgYXJlIGhlbGQgY29uc3RhbnQgaW4gdGhlIG1vZGVsLiBUaGUgZGlmZmVyZW5jZSBpbiB0aGUgbG9ncyBvZiBleHBlY3RlZCBwdWJsaWNhdGlvbnMgaXMgZXhwZWN0ZWQgdG8gYmUgMC41MDQgdW5pdHMgbG93ZXIgZm9yIHByZWNpcGl0YXRpb24gY29tcGFyZWQgdG8gbm9uZSB3aGlsZSBob2xkaW5nIHRoZSBvdGhlciB2YXJpYWJsZXMgY29uc3RhbnQgaW4gdGhlIG1vZGVsLiBXaGF0IHdlIGNhbiBkbyB0byBtYWtlIHRoaXMgZWFzaWVyIHRvIHVuZGVyc3RhbmQgaXMgbWFrZSB2aXN1YWwgYWlkcyB0byBoZWxwIHVzIHNlZSB3aGF0IGlzIGFjdHVhbGx5IGhhcHBlbmluZy4NCg0KIyMgVmlzdWFsIEFpZA0KDQpOZXh0LCB3ZSBtYWtlIGEgdmlzdWFsaXphdGlvbiB0byBzaG93IGhvdyB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGluIHRoZSBmaW5hbCB3b3JraW5nIG1vZGVsIGFmZmVjdCB0aGUgYWN0dWFsIG51bWJlciBvZiBjeWNsaXN0cy4gDQpXZSBleHBvbmVudGlhdGUgdGhlIGxvZyBjb3VudCBvZiBjeWNsaXN0cyBhbmQgbWFrZSB0d28gZ3JhcGhzIHNob3djYXNpbmcgcHJlY2lwaXRhdGlvbi4gQm90aCBncmFwaHMgd2lsbCBzaG93IHRoZSBhbW91bnQgb2YgY3ljbGlzdHMgZ2l2ZW4gdGhlIHggYXhpcyBvZiBlaXRoZXIgZGF5cyBhbmQgYXZlcmFnZSB0ZW1wZXJhdHVyZS4gVGhlIGZpcnN0IGdyYXBoIHdpbGwgaG9sZCB0ZW1wZXJhdHVyZSBjb25zdGFudCBhbmQgc2hvd2Nhc2UgYXMgZGF5cyBwcm9ncmVzcyBob3cgbWFueSBjeWNsaXN0cyBhcmUgdGhlcmUgd2hpbGUgYWxzbyBzaG93aW5nIHRoZSBhZmZlY3Qgb2YgcHJlY2lwaXRhdGlvbiBhbmQgbm8gcHJlY2lwaXRhdGlvbi4gVGhlIHNlY29uZCBncmFwaCB3aWxsIGhvbGQgZGF5cyBjb25zdGFudCB3aGlsZSBhbHNvIHNob3djYXNpbmcgdGhlIGFmZmVjdCBvZiB0ZW1wZXJhdHVyZSBvbiB0aGUgY3ljbGlzdCBjb3VudCBhbmQgYWxzbyBzaG93aW5nIHByZWNpcGl0YXRpb24NCg0KDQoNCmBgYHtyfQ0KZGF5X3JhbmdlIDwtIHNlcShtaW4oQ3ljbGlzdHMkRGF5KSwgbWF4KEN5Y2xpc3RzJERheSksIGxlbmd0aC5vdXQgPSAxMDApICAjIERheXMgZnJvbSBtaW4gdG8gbWF4DQp0ZW1wX3JhbmdlIDwtIHNlcShtaW4oQ3ljbGlzdHMkQXZnVGVtcCksIDkwLCBsZW5ndGgub3V0ID0gMTAwKSAgIyBUZW1wZXJhdHVyZSBmcm9tIG1pbiB0byA5MCBkZWdyZWVzDQoNCiMgQ3JlYXRlIGEgbmV3IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpwcmVkX2RhdGEgPC0gZGF0YS5mcmFtZShEYXkgPSByZXAoZGF5X3JhbmdlLCBlYWNoID0gMiksICAjIFR3byByb3dzIGZvciBlYWNoIGRheSwgZm9yIGJvdGggUHJlY2lwaXRhdGlvbiAwIGFuZCAxDQogICAgICAgICAgICAgICAgICAgICAgICBBdmdUZW1wID0gcmVwKG1lYW4oQ3ljbGlzdHMkQXZnVGVtcCksIDIwMCksICAjIEhvbGQgQXZnVGVtcCBjb25zdGFudA0KICAgICAgICAgICAgICAgICAgICAgICAgTmV3UHJlY2lwMSA9IHJlcChjKDAsIDEpLCBlYWNoID0gMTAwKSkgICMgUHJlY2lwaXRhdGlvbiAwIGFuZCAxDQoNCiMgQ2FsY3VsYXRlIHByZWRpY3RlZCBjeWNsaXN0IGNvdW50cyBmb3IgYm90aCBjb25kaXRpb25zIChubyBwcmVjaXBpdGF0aW9uIGFuZCBwcmVjaXBpdGF0aW9uKQ0KcHJlZF9kYXRhJEN5Y2xpc3RzX1ByZWRpY3RlZCA8LSBleHAoNTA3LjI2MzM4NjAgLSAwLjAxMTU3OTYgKiBwcmVkX2RhdGEkRGF5IC0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4wMDU2MjMxICogcHJlZF9kYXRhJEF2Z1RlbXAgLSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjUwMzk3NjAgKiBwcmVkX2RhdGEkTmV3UHJlY2lwMSkNCg0KIyBQbG90IHRoZSBlZmZlY3Qgb2YgRGF5IG9uIHByZWRpY3RlZCBjeWNsaXN0IGNvdW50cyBmb3IgYm90aCBQcmVjaXBpdGF0aW9uIDAgYW5kIDENCmdncGxvdChwcmVkX2RhdGEsIGFlcyh4ID0gRGF5LCB5ID0gQ3ljbGlzdHNfUHJlZGljdGVkLCBjb2xvciA9IGZhY3RvcihOZXdQcmVjaXAxKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicmVkIiwgImJsdWUiKSwgbGFiZWxzID0gYygiTm8gUHJlY2lwaXRhdGlvbiIsICJQcmVjaXBpdGF0aW9uIikpICsNCiAgbGFicyh0aXRsZSA9ICJFZmZlY3Qgb2YgRGF5IG9uIFByZWRpY3RlZCBDeWNsaXN0IENvdW50cyIsDQogICAgICAgeCA9ICJEYXkiLA0KICAgICAgIHkgPSAiUHJlZGljdGVkIEN5Y2xpc3QgQ291bnRzIiwNCiAgICAgICBjb2xvciA9ICJQcmVjaXBpdGF0aW9uIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBOb3cgcGxvdCB0aGUgZWZmZWN0IG9mIEF2Z1RlbXAgb24gcHJlZGljdGVkIGN5Y2xpc3QgY291bnRzIGZvciBib3RoIFByZWNpcGl0YXRpb24gMCBhbmQgMQ0KcHJlZF9kYXRhJEF2Z1RlbXAgPC0gdGVtcF9yYW5nZQ0KcHJlZF9kYXRhJEN5Y2xpc3RzX1ByZWRpY3RlZCA8LSBleHAoNTA3LjI2MzM4NjAgLSAwLjAxMTU3OTYgKiBwcmVkX2RhdGEkRGF5IC0gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC4wMDU2MjMxICogcHJlZF9kYXRhJEF2Z1RlbXAgLSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjUwMzk3NjAgKiBwcmVkX2RhdGEkTmV3UHJlY2lwMSkNCg0KZ2dwbG90KHByZWRfZGF0YSwgYWVzKHggPSBBdmdUZW1wLCB5ID0gQ3ljbGlzdHNfUHJlZGljdGVkLCBjb2xvciA9IGZhY3RvcihOZXdQcmVjaXAxKSkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygicmVkIiwgImJsdWUiKSwgbGFiZWxzID0gYygiTm8gUHJlY2lwaXRhdGlvbiIsICJQcmVjaXBpdGF0aW9uIikpICsNCiAgbGFicyh0aXRsZSA9ICJFZmZlY3Qgb2YgQXZnVGVtcCBvbiBQcmVkaWN0ZWQgQ3ljbGlzdCBDb3VudHMiLA0KICAgICAgIHggPSAiQXZlcmFnZSBUZW1wZXJhdHVyZSAoXHUwMGIwRikiLCAgIyBVc2luZyBVbmljb2RlIGZvciBkZWdyZWUgc3ltYm9sDQogICAgICAgeSA9ICJQcmVkaWN0ZWQgQ3ljbGlzdCBDb3VudHMiLA0KICAgICAgIGNvbG9yID0gIlByZWNpcGl0YXRpb24iKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKG1pbihDeWNsaXN0cyRBdmdUZW1wKSwgODApKSArICAjIFNldCB4LWF4aXMgdG8gZ28gdXAgdG8gOTAgZGVncmVlcw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpXZSBzZWUgZnJvbSB0aGUgZ3JhcGggYWJvdmUgdGhhdCBwcmVjaXBpdGF0aW9uIGhhcyBhIG1ham9yIGVmZmVjdCBvbiBib3RoIG9mIHRoZSBncmFwaHMuIEZyb20gdGhlIHJlZCBhbmQgdGhlIGJsdWUgbGluZXMgYXJlIGRyYXN0aWNhbGx5IGRpZmZlcmVudCwgdGhlIHJlZCBsaW5lIGlzIHdheSBhYm92ZSB0aGUgYmx1ZSBsaW5lIHNob3dpbmcgdGhhdCB0aGUgcHJlZGljdGVkIGNvdW50cyBnbyBkb3duIHdoZW4gdGhlcmUgaXMgcHJlY2lwaXRhdGlvbi4gVGhlIGZpcnN0IGdyYXBoIHNob3djYXNlcyB0aGUgRGF5cywgc2hvd3MgdGhhdCB0aGVyZSBpcyBhIGRlY3JlYXNlIHdoZW4gdGhlIGRheXMgZ29lcyB1cC4gQWxzbyBmcm9tIHRoZSBzZWNvbmQgZ3JhcGggd2Ugc2VlIHRoYXQgYWdhaW4gd2hlbiB0aGUgdGVtcGVyYXR1cmUgZ29lcyB1cCB0aGUgcHJlZGljdGVkIGNvdW50IG9mIGN5Y2xpc3RzIGdvZXMgZG93bi4NCg0KDQoNCg0KIyBDb25jbHVzaW9uDQoNCldlIGRvIG5vdCB1c2Ugb3VyIG9yaWdpbmFsIFBvaXNzb24gcmVncmVzc2lvbiBiZWNhdXNlIG9mIG91ciBiaWcgdmFsdWUgb2Ygb3VyIGRpc3BlcnNpb24uIFRoaXMgYmlnIGRpc3BlcnNpb24gdmFsdWUgbWVhbnMgdGhhdCBvdXIgdmFyaWFuY2UgaXMgYSBsb3QgYmlnZ2VyIHRoYW4gb3VyIG1lYW4uIFNvIHdlIHRoZW4gdXNlIGEgUXVhc2kgUG9pc3NvbiBtb2RlbCB0byBhY2NvdW50IGZvciB0aGlzIG92ZXIgZGlzcGVyc2lvbiBieSBpbnRyb2R1Y2luZyBhIGRpc3BlcnNpb24gcGFyYW1ldGVyLiBUaGlzIG1vZGVsIGdhdmUgdXMgbW9yZSBhY2N1cmF0ZSBwLXZhbHVlcy4gSnVkZ2luZyBmcm9tIG91ciBncmFwaHMgYW5kIG91dHB1dCBhYm92ZSB3ZSBzZWUgdGhhdCBwcmVjaXBpdGF0aW9uIGhhcyB0aGUgYmlnZ2VzdCBpbmZsdWVuY2UuIFByZWNpcGl0YXRpb24gaGFzIHRoZSBiaWdnZXN0IGFic29sdXRlIHZhbHVlIGNvZWZmaWNpZW50IGFuZCBhbHNvIHNob3dzIHRoZSBiaWdnZXN0IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIHNpZGVzIG9mIG91ciB2YXJpYWJsZXMuIFRoZXJlIGlzIGFsc28gYSBncmFkdWFsIGRlY3JlYXNlIGluIGJvdGggb2YgdGhlIGdyYXBocy4gV2hlbiBib3RoIGRheXMgYW5kIHRlbXBlcmF0dXJlIGdvIHVwIGluIHRoZWlyIHJlc3BlY3RpdmUgZ3JhcGhzIHRoZSBjb3VudCBvZiBjeWNsaXN0cyBnb2VzIGRvd24uIA==