1 Introduction

This assignment will further analyze bike count data for several bridges, keeping a count of cyclists entering and leaving the bridge. This assignment will utilize a dispersed poisson regression to look at the cyclist count for a particular bridge on different days of the week. Additionally, this assignment will modify some of the variables to better fit a dispersed poisson regression analysis.

2 Materials

2.1 Data Set

A daily total bike count was conducted monthly on four different bridges in New York, the Brooklyn Bridge, Manhattan Bridge, Williamsburg Bridge, and Queensboro Bridge. The bike total kept count of the total cyclists entering and leaving each bridge on a given day. The count data was collected by the Traffic Information Management System (TIMS). Each recorded response represents the total number of cyclists that entered and left that bridge in a 24 hour period.

url="https://ChloeWinters79.github.io/STA321/Data/QueensboroBridge.csv"
bridge = read.csv(url, header = TRUE)

This project did a random assignment of a specific subset of the data for our analysis. The subset is for one of the four bridges over a one month period from the first day of the month to last day of the month. The specific subset assigned for this project was for the Queensboro bridge for the month of April. The data set is called bridge and consists of 7 variables and 30 total observations. When the data set is first read in the variables are as followed.

  1. Date: (chr) Used as the ID variable, the date that the observation was recorded
  2. Day (chr) The day of the week the observation was recorded
  3. HighTemp (num) The high temperature on the date of the observation
  4. LowTemp (num) The low temperature on the date of the observation
  5. Precipitation (num) The amount of precipitation received on the date of the observation
  6. QueensboroBridge (int) The total amount of cyclists who entered and exited the Queensboro Bridge on the date of the observation
  7. Total (int) The total amount of cyclists who entered and exited any of the four bridges on the date of the observation

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

4 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
Pearson.disp.1 Deviance.disp.1
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
Pearson.disp.2 Deviance.disp.2
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
Estimate Std. Error t value Pr(>|t|)
(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.
Estimate Std. Error t value Pr(>|t|)
(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.

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

5 Results & Conclusion

The best model for total cyclists on the Queensboro bridge, is a poisson model that offsets with the log of the total cyclists and uses NewPrecip and AvgTemp as predictors variables and with the variable Day being dropped for lacking statistical significance across all factors. Additionally, the graph shows that the relationship between AvgTemp and QueensboroBridge, while statistically significant, is not linear. The graph also shows that while the variable NewPrecip is statistically significant in predicting the total cyclists on the Queensboro Bridge, they different levels do not appear to be largely different from each other.

6 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