1 Introduction

The data set for this study was collected from the Traffic Information Management System. It keeps track of the number of cyclists entering and leaving the Queensboro Bridge from the dates July 1st to July 31st. This data set includes a total of 31 observations and seven variables. The response variable is the total number of cyclist that pass through the Queensboro bridge on each given day. The explanatory variables for this data set involve the specific conditions of each day, such as the weather.

1.1 Variable Description

Here are what the seven variables in the data set represent:

  • Date (x1) - note this represents the observation ID

  • Day (x2) - The day of the week

  • HighTemp (x3) - the temperature high for the day in degrees Fahrenheit

  • LowTemp (x4) - the temperature high for the day in degrees Fahrenheit

  • Precipitation (x5) - the total precipitation for the day in inches

  • Queensboro Bridge (Y) - The number of cyclists on the Queensboro bridge.

  • Total (x6) - the total number of cyclists who enter and leave the bridges in NYC each day

1.2 Practical Question

Do the conditions surrounding the day the cyclists are recorded affect the number of them enter and leave the QueensboroBridge?

2 EDA and Feature Engineering

First, we are going to download the data. The variable “Date” will be dropped because it is the observation ID, Since it is a small data set, we can look at the data and conclude there are no missing values. We are also going to remove to commas from the variables “Total” and “QueensboroBridge” so R Studio classifies them as numeric.

cycle <- read.csv("https://raw.githubusercontent.com/AvaDeSt/STA-321/refs/heads/main/Assignment%205%20data(Sheet1).csv", header = TRUE)[,-1]
          
cycle$Total <- as.numeric(gsub(",", "", cycle$Total))
cycle$QueensboroBridge <- as.numeric(gsub(",", "", cycle$QueensboroBridge))


data(cycle)
kable(head(cycle), caption = "First few records in the data set")
First few records in the data set
Day HighTemp LowTemp Precipitation QueensboroBridge Total
Saturday 84.9 72.0 0.23 3216 11867
Sunday 87.1 73.0 0.00 3579 13995
Monday 87.1 71.1 0.45 4230 16067
Tuesday 82.9 70.0 0.00 3861 13925
Wednesday 84.9 71.1 0.00 5862 23110
Thursday 75.0 71.1 0.00 5251 21861

Now that we have the data, we are going to create a new data set called “cycle.new” that contains the variable AvgTemp. This variable will take the average temperature in degrees farenheit of the variables HighTemp and LowTemp.

cycle.new<- cycle %>%
  mutate(AvgTemp = (HighTemp + LowTemp) / 2)

Next We are going to discretize the variable Precipitation. This will mark any observation with 0 precipitation as “0”, and any observations with precipitation levels greater than 0 as “1”.

cycle.new$NewPrecip = ifelse(cycle.new$Precipitation > 0, 1, 0)

data(cycle.new)
kable(head(cycle.new), caption = "First few records in the data set")
First few records in the data set
Day HighTemp LowTemp Precipitation QueensboroBridge Total AvgTemp NewPrecip
Saturday 84.9 72.0 0.23 3216 11867 78.45 1
Sunday 87.1 73.0 0.00 3579 13995 80.05 0
Monday 87.1 71.1 0.45 4230 16067 79.10 1
Tuesday 82.9 70.0 0.00 3861 13925 76.45 0
Wednesday 84.9 71.1 0.00 5862 23110 78.00 0
Thursday 75.0 71.1 0.00 5251 21861 73.05 0

3 Model Building

For this study, a poisson regression and a quasi poisson model will be used. The quasi poisson model is similar to a poisson model except that it corrects for over dispersion. This occurs when the mean and variance of the data is not equal.The poisson regression model has four basic assumptions that are as follows:

  • The response variable is a count per unit of time or space. ( In our case it is the count of cyclists per day).

  • The observations are independent of one another.

  • The mean of the poisson random variable is equal to the variance. (for a quasi poisson model, this does not have to be the case)

  • The log of the mean rate, log(λ), is a linear function of x

3.1 Poisson Model

First, we will build a standard poisson model using our new variables “AvgTemp” and “NewPrecip” as well as the original one “Day”. We will also be extracting the pearson and deviance dispersion.

Note that ϕ = variance / mean. So a dispersion equal to one means that the variance is equal to the mean. Anything not equal to one indicates dispersion.

pois.model = glm(QueensboroBridge ~ factor(Day) + AvgTemp + NewPrecip, 
                 family = poisson(link="log"), data =cycle.new) 
summary(pois.model)
## 
## Call:
## glm(formula = QueensboroBridge ~ factor(Day) + AvgTemp + NewPrecip, 
##     family = poisson(link = "log"), data = cycle.new)
## 
## Coefficients:
##                        Estimate Std. Error z value Pr(>|z|)    
## (Intercept)           7.9739275  0.0431838 184.651   <2e-16 ***
## factor(Day)Monday     0.1586579  0.0102399  15.494   <2e-16 ***
## factor(Day)Saturday  -0.0989334  0.0107978  -9.162   <2e-16 ***
## factor(Day)Sunday    -0.1283273  0.0108855 -11.789   <2e-16 ***
## factor(Day)Thursday   0.1686654  0.0106693  15.809   <2e-16 ***
## factor(Day)Tuesday    0.0934492  0.0109975   8.497   <2e-16 ***
## factor(Day)Wednesday  0.1894845  0.0107878  17.565   <2e-16 ***
## AvgTemp               0.0060353  0.0005483  11.007   <2e-16 ***
## NewPrecip            -0.3189133  0.0072562 -43.950   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for poisson family taken to be 1)
## 
##     Null deviance: 7891  on 30  degrees of freedom
## Residual deviance: 2466  on 22  degrees of freedom
## AIC: 2801.1
## 
## Number of Fisher Scoring iterations: 4
## predicted y: yhat
yhat = pois.model$fitted.values
pearson.resid = (cycle.new$QueensboroBridge - 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
109.1148 112.0891

We can see from the summary table that all of the p values indicate that each variable is highly significant. However, both the pearson and deviance dispersion are way more than one, both exceeding one hundred. This indicates that this poisson model seriously violates that assumption of equal mean and variance. This suggests that the p values from this model are not reliable in the first place. We can see that the coefficient for the AvgTemp is about 0.006. This means that for every one degree increase in the temperature high, the log of the expected count of cyclists increases by 0.006. Since exp(0.006) = 1.006, for each one-unit increase in the predictor variable, the expected count of the outcome variable increases by about 10.06%, holding other variables constant.

3.2 Poisson Regression on Rates

This model and analysis is similar to the regular poisson model except it will take into account the total number of cycles who cross other major bridges in New York.

model.rates <- glm(QueensboroBridge ~ Day + AvgTemp + factor(NewPrecip), offset = log(Total), 
                   family = poisson(link = "log"), data = cycle.new)
kable(summary(model.rates)$coef, caption = "Poisson regression on the rate of cyclists.")
Poisson regression on the rate of cyclists.
Estimate Std. Error z value Pr(>|z|)
(Intercept) -1.2569023 0.0432727 -29.046054 0.0000000
DayMonday -0.0678714 0.0102390 -6.628717 0.0000000
DaySaturday -0.0357733 0.0107891 -3.315688 0.0009142
DaySunday -0.0817864 0.0108370 -7.546972 0.0000000
DayThursday -0.0350102 0.0105830 -3.308148 0.0009392
DayTuesday -0.0477855 0.0109113 -4.379469 0.0000119
DayWednesday -0.0433977 0.0106518 -4.074197 0.0000462
AvgTemp -0.0016134 0.0005475 -2.946729 0.0032115
factor(NewPrecip)1 0.0476215 0.0071899 6.623369 0.0000000
yhat = model.rates$fitted.values
pearson.resid = (cycle.new$QueensboroBridge - yhat)/sqrt(yhat)
Pearson.disp = sum(pearson.resid^2)/model.rates$df.residual
##
Deviance.disp = (model.rates$deviance)/model.rates$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
15.23799 15.02153

We can see that similar to the first model, that all of the p values indicate that each variable is highly significant. However, both the pearson and deviance dispersion are also way more than one, but they are also significantly less than the dispersion from the previous poisson regression model. This indicates that our poisson model on rates still violates that assumption of equal mean and variance. This suggests that the p values from this model are not reliable in the first place.

The table also shows that the log of bikers crossing the bridge is not the same across all days of the week. The log rates for the day Friday are higher than the rest of the days of the week. The intercept represents the log base cyclist rate for the baseline day Friday. The rest of the coefficients are the difference of log rates between the baseline day Friday and the rest of the days of the week. We can see from the table that -0.067 is the coefficient for Monday so:

log(RMonday / RFriday) = -0.067 ⇒ RMonday / RFriday = e^−0.067 ≈ 0.935

This means that the rate of bikers on Monday is about 6.5% lower on Monday than on Friday.

3.3 Quasi Poisson Model

Since the dispersion from the previous model was very high, we are going to instead use a quasi poisson model. This model does not require an equal mean and variance.

quasi.model = glm(QueensboroBridge ~ Day + AvgTemp + factor(NewPrecip), 
                 family = quasipoisson, data = cycle.new)  

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) 7.9739275 0.4510894 17.6770432 0.0000000
DayMonday 0.1586579 0.1069643 1.4832787 0.1521859
DaySaturday -0.0989334 0.1127917 -0.8771338 0.3898920
DaySunday -0.1283273 0.1137081 -1.1285685 0.2712370
DayThursday 0.1686654 0.1114490 1.5133867 0.1444160
DayTuesday 0.0934492 0.1148775 0.8134680 0.4246668
DayWednesday 0.1894845 0.1126871 1.6815099 0.1068069
AvgTemp 0.0060353 0.0057277 1.0537146 0.3034495
factor(NewPrecip)1 -0.3189133 0.0757971 -4.2074578 0.0003635

We can see from the table above that the variables “Day” and “AvgTemp” are not significant but the variable “NewPrcip” is. This could be a concern. But first, we are going to look at the dispersion parameter.

Next, we will calculate the dispersion index of our quasi poisson model.

ydif=cycle.new$QueensboroBridge-exp(quasi.model$linear.predictors)  # diff between y and yhat
prsd = ydif/sqrt(exp(quasi.model$linear.predictors))   # Pearson residuals
phi = sum(prsd^2)/15          # Dispersion index: 24-9 = 15  
pander(cbind(Dispersion = phi))
Dispersion
160

The dispersion index for this model is very high. But given what we know of the dispersion from the origional poisson model this is to be expected.

3.4 Quasi Poisson model on Rates

Similar to the last section, we are going to build another quasi poisson regression model but this time, based on the rates of the total number of cyclists crossing several major bridges in New York. We will also calculate the dispersion for this model.

quasimodel.rates <- glm(QueensboroBridge ~ Day + AvgTemp + factor(NewPrecip), offset = log(Total), 
                   family = quasipoisson, data = cycle.new)
pander(summary(quasimodel.rates)$coef, caption = "Quasi-Poisson regression on the Number of Cyclists")
Quasi-Poisson regression on the Number of Cyclists
  Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.257 0.1689 -7.441 1.923e-07
DayMonday -0.06787 0.03997 -1.698 0.1036
DaySaturday -0.03577 0.04212 -0.8494 0.4048
DaySunday -0.08179 0.0423 -1.933 0.06617
DayThursday -0.03501 0.04131 -0.8475 0.4059
DayTuesday -0.04779 0.04259 -1.122 0.274
DayWednesday -0.0434 0.04158 -1.044 0.308
AvgTemp -0.001613 0.002137 -0.7549 0.4583
factor(NewPrecip)1 0.04762 0.02807 1.697 0.1039
ydif=cycle.new$QueensboroBridge-exp(quasimodel.rates$linear.predictors)  # diff between y and yhat
prsd = ydif/sqrt(exp(quasimodel.rates$linear.predictors))   # Pearson residuals
phi = sum(prsd^2)/15          # Dispersion index: 24-9 = 15  
pander(cbind(Dispersion = phi))
Dispersion
22.35

From the table above, we can see that none of the p values are significant. The dispersion index is still very high but not nearly as high as the one from the regular quasi poisson model.

3.5 Final Model

The final model chosen for this analysis will be the quasi poisson model on rates. Despite the quasi models having less significant p values, they do not require equal mean and variance. We have seen from calculating the dispersion of the poisson models that the means and variances for both the poisson and poisson rates models were not at all equal with very high dispersion. The rate quasi poisson model on rates will be used because despite still having a high dispersion index, it was much closer to one than on the regular The final model can be written as:

rate = exp(-1.257 -0.0818 * DaySunday - 0.0679 * DayMonday - 0.0478 * DayTuesday - 0.0434 * DayWednesday - 0.035 * DayThursday - 0.0358 * DaySaturday) x (0.0016 * AvgTemp) x (0.0476 * NewPrecip)

3.6 Some Visual Comparisons

Now, we will create a visual representation of how the explanatory variables affect the actual number of cyclists on the Queensboro Bridge. Each line on the graph will represent a day of the week. We will visualize what effect day and average temperature have on them.

Sunday = c(exp(-1.257+7), exp(-1.257-0.0818-0.0016),   
               exp(-1.257-0.0818+0.0476))

Monday = c(exp(-1.257+0.001815), exp(-1.257+0.0679-0.0016),   
               exp(-1.257+0.0679+0.0476))


Tuesday = c(exp(-1.257+0.02529), exp(-1.257-0.0478-0.0016),   
               exp(-1.257-0.0478+0.0476))


Wednesday= c(exp(-1.257+0.01835), exp(-1.257-0.0434-0.0016),   
               exp(-1.257-0.0434+0.0476))


Thursday = c(exp(-1.257+0.0237), exp(-1.257-0.035-0.0016),   
               exp(-1.257-0.035+0.0476))


Friday = c(exp(-1.257), exp(-1.257-0.0016),   
               exp(-1.257+0.0476))


Saturday = c(exp(-1.257+0.03454), exp(-1.257-0.0358-0.0016),   
               exp(-1.257-0.0358+0.0476))

minmax = range(c(Monday,Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday))
plot(1:3, Friday, type="l", lty =1, col="red", xlab="", 
               ylab="Bike Rate", xlim=c(0,6), ylim=c(0.2, 0.35), axes=FALSE )
axis(2)
axis(1, labels=c("AvgTemp", "NewPrecip"), at = 1:2)
points(1:3,Friday, pch=19, col="red")
##
lines(1:3, Saturday, lty =2, col="green")
points(1:3, Saturday, pch=20, col="green")
##
lines(1:3, Sunday, lty =3, col="purple")
points(1:3, Sunday, pch=21, col="purple")
###
lines(1:3, Monday, lty =4, col="black")
points(1:3, Monday, pch=22, col="black")
##
lines(1:3, Tuesday, lty =5, col="blue")
points(1:3, Tuesday, pch=23, col="blue")
##
lines(1:3, Wednesday, lty =6, col="orange")
points(1:3, Wednesday, pch=24, col="orange")
##
lines(1:3, Thursday, lty =7, col="turquoise")
points(1:3, Thursday, pch=25, col="turquoise")
##


legend("topright", c("Friday","Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday" ),
                  pch=19:22, lty=1:7,  bty="n", 
        col=c("red", "green", "purple", "black", "blue", "orange", "turquoise"))

From the graph we can see a few things:

  • The most bikers cross the Queensboro Bridge on Monday on average.

  • There is a positive relationship between average temperature and the number of cyclists.

4 Summary and Conclusion

To summarize, we looked at a data set that looks at how many bikers cross over the Queensboro Bridge in NYC every day for the month of July, leaving us with 31 observations. The 4 explanatory variables look at the day of the week and the weather conditions on each day. We created two new variables in the data set and used them in all our models along with the variable ’Day”. One was called “AvgTemp” and it took the average temperature of the high and low temperature variables. The other variable “NewPrecip” categorized the variable “Precipitation” as: if Precipitation = 0, then NewPrecip = 0; if Precipitation > 0, then NewPrecip = 1 Our goal was to see what the relationship was between these variables and the number of cyclists. We also wanted to see if taking into account the total number of cyclists that cross several major bridges in NYC. To figure this out, we built a Poisson frequency regression model, a Poisson Model on rates, and a quasi poisson model, and a quasi poisson regression model on rates.

We found from calculating the dispersion of the poisson model that the mean and variance were not equal. Because of this, we decided this was not the best model. The final model chosen was the quasi poisson model on rates.Despite the quasi models having less significant p values, they do not require equal mean and variance. A recommendation for further research is to try to find how truly significant the explanatory variables. With each model we used, the p values changed, so they were not very meaningful.

LS0tDQp0aXRsZTogJ0Rpc3BlcnNlZCBQb2lzc29uIFJlZ3Jlc3Npb24gb24gTmV3IFlvcmsgQ3ljbGlzdHMnDQphdXRob3I6ICdBdmEgRGVTdGVmYW5vJw0KZGF0ZTogIjEwLTI5LTI0Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX3dpZHRoOiA2DQogICAgZmlnX2hlaWdodDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogNQ0KICAgIGZpZ19oZWlnaHQ6IDQNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIycHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCjwvc3R5bGU+DQpgYGANCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoIklTd1IiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiSVN3UiIpDQogICBsaWJyYXJ5KElTd1IpDQp9DQppZiAoIXJlcXVpcmUoIk1BU1MiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiTUFTUyIpDQogICBsaWJyYXJ5KE1BU1MpDQp9DQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoImRwbHlyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCiAgIGxpYnJhcnkoZHBseXIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ249J2NlbnRlcicsIA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5wb3MgPSAnaCcNCiAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICkgIA0KYGBgDQoNCiMgSW50cm9kdWN0aW9uIA0KDQpUaGUgZGF0YSBzZXQgZm9yIHRoaXMgc3R1ZHkgd2FzIGNvbGxlY3RlZCBmcm9tIHRoZSBUcmFmZmljIEluZm9ybWF0aW9uIE1hbmFnZW1lbnQgU3lzdGVtLiBJdCBrZWVwcyB0cmFjayBvZiB0aGUgbnVtYmVyIG9mIGN5Y2xpc3RzIGVudGVyaW5nIGFuZCBsZWF2aW5nIHRoZSBRdWVlbnNib3JvIEJyaWRnZSBmcm9tIHRoZSBkYXRlcyBKdWx5IDFzdCB0byBKdWx5IDMxc3QuIFRoaXMgZGF0YSBzZXQgaW5jbHVkZXMgYSB0b3RhbCBvZiAzMSBvYnNlcnZhdGlvbnMgYW5kIHNldmVuIHZhcmlhYmxlcy4gVGhlIHJlc3BvbnNlIHZhcmlhYmxlIGlzIHRoZSB0b3RhbCBudW1iZXIgb2YgY3ljbGlzdCB0aGF0IHBhc3MgdGhyb3VnaCB0aGUgIFF1ZWVuc2Jvcm8gYnJpZGdlIG9uIGVhY2ggZ2l2ZW4gZGF5LiBUaGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGZvciB0aGlzIGRhdGEgc2V0IGludm9sdmUgdGhlIHNwZWNpZmljIGNvbmRpdGlvbnMgb2YgZWFjaCBkYXksIHN1Y2ggYXMgdGhlIHdlYXRoZXIuDQoNCiMjIFZhcmlhYmxlIERlc2NyaXB0aW9uDQoNCkhlcmUgYXJlIHdoYXQgdGhlIHNldmVuIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBzZXQgcmVwcmVzZW50Og0KDQoqIERhdGUgKHgxKSAtIG5vdGUgdGhpcyByZXByZXNlbnRzIHRoZSBvYnNlcnZhdGlvbiBJRA0KDQoqIERheSAoeDIpIC0gVGhlIGRheSBvZiB0aGUgd2Vlaw0KDQoqIEhpZ2hUZW1wICh4MykgLSB0aGUgdGVtcGVyYXR1cmUgaGlnaCBmb3IgdGhlIGRheSBpbiBkZWdyZWVzIEZhaHJlbmhlaXQNCg0KKiBMb3dUZW1wICh4NCkgLSB0aGUgdGVtcGVyYXR1cmUgaGlnaCBmb3IgdGhlIGRheSBpbiBkZWdyZWVzIEZhaHJlbmhlaXQNCg0KKiBQcmVjaXBpdGF0aW9uICh4NSkgLSB0aGUgdG90YWwgcHJlY2lwaXRhdGlvbiBmb3IgdGhlIGRheSBpbiBpbmNoZXMNCg0KKiBRdWVlbnNib3JvIEJyaWRnZSAoWSkgLSBUaGUgbnVtYmVyIG9mIGN5Y2xpc3RzIG9uIHRoZSBRdWVlbnNib3JvIGJyaWRnZS4NCg0KKiBUb3RhbCAoeDYpIC0gdGhlIHRvdGFsIG51bWJlciBvZiBjeWNsaXN0cyB3aG8gZW50ZXIgYW5kIGxlYXZlIHRoZSBicmlkZ2VzIGluIE5ZQyBlYWNoIGRheQ0KDQojIyBQcmFjdGljYWwgUXVlc3Rpb24gDQoNCkRvIHRoZSBjb25kaXRpb25zIHN1cnJvdW5kaW5nIHRoZSBkYXkgdGhlIGN5Y2xpc3RzIGFyZSByZWNvcmRlZCBhZmZlY3QgdGhlIG51bWJlciBvZiB0aGVtIGVudGVyIGFuZCBsZWF2ZSB0aGUgUXVlZW5zYm9yb0JyaWRnZT8NCg0KIyBFREEgYW5kIEZlYXR1cmUgRW5naW5lZXJpbmcgDQoNCkZpcnN0LCB3ZSBhcmUgZ29pbmcgdG8gZG93bmxvYWQgdGhlIGRhdGEuIFRoZSB2YXJpYWJsZSAiRGF0ZSIgd2lsbCBiZSBkcm9wcGVkIGJlY2F1c2UgaXQgaXMgdGhlIG9ic2VydmF0aW9uIElELCBTaW5jZSBpdCBpcyBhIHNtYWxsIGRhdGEgc2V0LCB3ZSBjYW4gbG9vayBhdCB0aGUgZGF0YSBhbmQgY29uY2x1ZGUgdGhlcmUgYXJlIG5vIG1pc3NpbmcgdmFsdWVzLiBXZSBhcmUgYWxzbyBnb2luZyB0byByZW1vdmUgdG8gY29tbWFzIGZyb20gdGhlIHZhcmlhYmxlcyAiVG90YWwiIGFuZCAiUXVlZW5zYm9yb0JyaWRnZSIgc28gUiBTdHVkaW8gY2xhc3NpZmllcyB0aGVtIGFzIG51bWVyaWMuIA0KDQpgYGB7cn0NCmN5Y2xlIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQXZhRGVTdC9TVEEtMzIxL3JlZnMvaGVhZHMvbWFpbi9Bc3NpZ25tZW50JTIwNSUyMGRhdGEoU2hlZXQxKS5jc3YiLCBoZWFkZXIgPSBUUlVFKVssLTFdDQogICAgICAgICAgDQpjeWNsZSRUb3RhbCA8LSBhcy5udW1lcmljKGdzdWIoIiwiLCAiIiwgY3ljbGUkVG90YWwpKQ0KY3ljbGUkUXVlZW5zYm9yb0JyaWRnZSA8LSBhcy5udW1lcmljKGdzdWIoIiwiLCAiIiwgY3ljbGUkUXVlZW5zYm9yb0JyaWRnZSkpDQoNCg0KZGF0YShjeWNsZSkNCmthYmxlKGhlYWQoY3ljbGUpLCBjYXB0aW9uID0gIkZpcnN0IGZldyByZWNvcmRzIGluIHRoZSBkYXRhIHNldCIpDQoNCmBgYA0KDQoNCg0KTm93IHRoYXQgd2UgaGF2ZSB0aGUgZGF0YSwgd2UgYXJlIGdvaW5nIHRvIGNyZWF0ZSBhIG5ldyBkYXRhIHNldCBjYWxsZWQgImN5Y2xlLm5ldyIgdGhhdCBjb250YWlucyB0aGUgdmFyaWFibGUgQXZnVGVtcC4gVGhpcyB2YXJpYWJsZSB3aWxsIHRha2UgdGhlIGF2ZXJhZ2UgdGVtcGVyYXR1cmUgaW4gZGVncmVlcyBmYXJlbmhlaXQgb2YgdGhlIHZhcmlhYmxlcyBIaWdoVGVtcCBhbmQgTG93VGVtcC4NCg0KYGBge3J9DQpjeWNsZS5uZXc8LSBjeWNsZSAlPiUNCiAgbXV0YXRlKEF2Z1RlbXAgPSAoSGlnaFRlbXAgKyBMb3dUZW1wKSAvIDIpDQoNCmBgYA0KDQpOZXh0IFdlIGFyZSBnb2luZyB0byBkaXNjcmV0aXplIHRoZSB2YXJpYWJsZSBQcmVjaXBpdGF0aW9uLiBUaGlzIHdpbGwgbWFyayBhbnkgb2JzZXJ2YXRpb24gd2l0aCAwIHByZWNpcGl0YXRpb24gYXMgIjAiLCBhbmQgYW55IG9ic2VydmF0aW9ucyB3aXRoIHByZWNpcGl0YXRpb24gbGV2ZWxzIGdyZWF0ZXIgdGhhbiAwIGFzICIxIi4gDQoNCmBgYHtyfQ0KY3ljbGUubmV3JE5ld1ByZWNpcCA9IGlmZWxzZShjeWNsZS5uZXckUHJlY2lwaXRhdGlvbiA+IDAsIDEsIDApDQoNCmRhdGEoY3ljbGUubmV3KQ0Ka2FibGUoaGVhZChjeWNsZS5uZXcpLCBjYXB0aW9uID0gIkZpcnN0IGZldyByZWNvcmRzIGluIHRoZSBkYXRhIHNldCIpDQoNCmBgYA0KDQojIE1vZGVsIEJ1aWxkaW5nDQoNCkZvciB0aGlzIHN0dWR5LCBhIHBvaXNzb24gcmVncmVzc2lvbiBhbmQgYSBxdWFzaSBwb2lzc29uIG1vZGVsIHdpbGwgYmUgdXNlZC4gVGhlIHF1YXNpIHBvaXNzb24gbW9kZWwgaXMgc2ltaWxhciB0byBhIHBvaXNzb24gbW9kZWwgZXhjZXB0IHRoYXQgaXQgY29ycmVjdHMgZm9yIG92ZXIgZGlzcGVyc2lvbi4gVGhpcyBvY2N1cnMgd2hlbiB0aGUgbWVhbiBhbmQgdmFyaWFuY2Ugb2YgdGhlIGRhdGEgaXMgbm90IGVxdWFsLlRoZSBwb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwgaGFzIGZvdXIgYmFzaWMgYXNzdW1wdGlvbnMgdGhhdCBhcmUgYXMgZm9sbG93czoNCg0KLSBUaGUgcmVzcG9uc2UgdmFyaWFibGUgaXMgYSBjb3VudCBwZXIgdW5pdCBvZiB0aW1lIG9yIHNwYWNlLiAoIEluIG91ciBjYXNlIGl0IGlzIHRoZSBjb3VudCBvZiBjeWNsaXN0cyBwZXIgZGF5KS4NCg0KLSBUaGUgb2JzZXJ2YXRpb25zIGFyZSBpbmRlcGVuZGVudCBvZiBvbmUgYW5vdGhlci4NCg0KLSBUaGUgbWVhbiBvZiB0aGUgcG9pc3NvbiByYW5kb20gdmFyaWFibGUgaXMgZXF1YWwgdG8gdGhlIHZhcmlhbmNlLiAoZm9yIGEgcXVhc2kgcG9pc3NvbiBtb2RlbCwgdGhpcyBkb2VzIG5vdCBoYXZlIHRvIGJlIHRoZSBjYXNlKQ0KDQotIFRoZSBsb2cgb2YgdGhlIG1lYW4gcmF0ZSwgbG9nKM67KSwgaXMgYSBsaW5lYXIgZnVuY3Rpb24gb2YgeA0KDQojIyBQb2lzc29uIE1vZGVsDQoNCkZpcnN0LCB3ZSB3aWxsIGJ1aWxkIGEgc3RhbmRhcmQgcG9pc3NvbiBtb2RlbCB1c2luZyBvdXIgbmV3IHZhcmlhYmxlcyAiQXZnVGVtcCIgYW5kICJOZXdQcmVjaXAiIGFzIHdlbGwgYXMgdGhlIG9yaWdpbmFsIG9uZSAiRGF5Ii4gIFdlIHdpbGwgYWxzbyBiZSBleHRyYWN0aW5nIHRoZSBwZWFyc29uIGFuZCBkZXZpYW5jZSBkaXNwZXJzaW9uLg0KDQpOb3RlIHRoYXQgz5UgPSB2YXJpYW5jZSAvIG1lYW4uIFNvIGEgZGlzcGVyc2lvbiBlcXVhbCB0byBvbmUgbWVhbnMgdGhhdCB0aGUgdmFyaWFuY2UgaXMgZXF1YWwgdG8gdGhlIG1lYW4uIEFueXRoaW5nIG5vdCBlcXVhbCB0byBvbmUgaW5kaWNhdGVzIGRpc3BlcnNpb24uIA0KDQpgYGB7cn0NCnBvaXMubW9kZWwgPSBnbG0oUXVlZW5zYm9yb0JyaWRnZSB+IGZhY3RvcihEYXkpICsgQXZnVGVtcCArIE5ld1ByZWNpcCwgDQogICAgICAgICAgICAgICAgIGZhbWlseSA9IHBvaXNzb24obGluaz0ibG9nIiksIGRhdGEgPWN5Y2xlLm5ldykgDQpzdW1tYXJ5KHBvaXMubW9kZWwpDQoNCiMjIHByZWRpY3RlZCB5OiB5aGF0DQp5aGF0ID0gcG9pcy5tb2RlbCRmaXR0ZWQudmFsdWVzDQpwZWFyc29uLnJlc2lkID0gKGN5Y2xlLm5ldyRRdWVlbnNib3JvQnJpZGdlIC0geWhhdCkvc3FydCh5aGF0KQ0KUGVhcnNvbi5kaXNwID0gc3VtKHBlYXJzb24ucmVzaWReMikvcG9pcy5tb2RlbCRkZi5yZXNpZHVhbA0KIyMNCkRldmlhbmNlLmRpc3AgPSAocG9pcy5tb2RlbCRkZXZpYW5jZSkvcG9pcy5tb2RlbCRkZi5yZXNpZHVhbA0KIyMNCmRpc3AgPSBjYmluZChQZWFyc29uLmRpc3AgPSBQZWFyc29uLmRpc3AsIERldmlhbmNlLmRpc3AgPSBEZXZpYW5jZS5kaXNwKQ0Ka2FibGUoZGlzcCwgY2FwdGlvbj0iRGlzcGVyc2lvbiBwYXJhbWV0ZXIiLCBhbGlnbiA9ICdjJykNCmBgYA0KV2UgY2FuIHNlZSBmcm9tIHRoZSBzdW1tYXJ5IHRhYmxlIHRoYXQgYWxsIG9mIHRoZSBwIHZhbHVlcyBpbmRpY2F0ZSB0aGF0IGVhY2ggdmFyaWFibGUgaXMgaGlnaGx5IHNpZ25pZmljYW50LiBIb3dldmVyLCBib3RoIHRoZSBwZWFyc29uIGFuZCBkZXZpYW5jZSBkaXNwZXJzaW9uIGFyZSB3YXkgbW9yZSB0aGFuIG9uZSwgYm90aCBleGNlZWRpbmcgb25lIGh1bmRyZWQuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhpcyBwb2lzc29uIG1vZGVsIHNlcmlvdXNseSB2aW9sYXRlcyB0aGF0IGFzc3VtcHRpb24gb2YgZXF1YWwgbWVhbiBhbmQgdmFyaWFuY2UuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGUgcCB2YWx1ZXMgZnJvbSB0aGlzIG1vZGVsIGFyZSBub3QgcmVsaWFibGUgaW4gdGhlIGZpcnN0IHBsYWNlLiBXZSBjYW4gc2VlIHRoYXQgdGhlIGNvZWZmaWNpZW50IGZvciB0aGUgQXZnVGVtcCBpcyBhYm91dCAwLjAwNi4gVGhpcyBtZWFucyB0aGF0IGZvciBldmVyeSBvbmUgZGVncmVlIGluY3JlYXNlIGluIHRoZSB0ZW1wZXJhdHVyZSBoaWdoLCB0aGUgbG9nIG9mIHRoZSBleHBlY3RlZCBjb3VudCBvZiBjeWNsaXN0cyBpbmNyZWFzZXMgYnkgMC4wMDYuIFNpbmNlIGV4cCgwLjAwNikgPSAxLjAwNiwgZm9yIGVhY2ggb25lLXVuaXQgaW5jcmVhc2UgaW4gdGhlIHByZWRpY3RvciB2YXJpYWJsZSwgdGhlIGV4cGVjdGVkIGNvdW50IG9mIHRoZSBvdXRjb21lIHZhcmlhYmxlIGluY3JlYXNlcyBieSBhYm91dCAxMC4wNiUsIGhvbGRpbmcgb3RoZXIgdmFyaWFibGVzIGNvbnN0YW50Lg0KDQojIyBQb2lzc29uIFJlZ3Jlc3Npb24gb24gUmF0ZXMNCg0KVGhpcyBtb2RlbCBhbmQgYW5hbHlzaXMgaXMgc2ltaWxhciB0byB0aGUgcmVndWxhciBwb2lzc29uIG1vZGVsIGV4Y2VwdCBpdCB3aWxsIHRha2UgaW50byBhY2NvdW50IHRoZSB0b3RhbCBudW1iZXIgb2YgY3ljbGVzIHdobyBjcm9zcyBvdGhlciBtYWpvciBicmlkZ2VzIGluIE5ldyBZb3JrLg0KDQpgYGB7cn0NCm1vZGVsLnJhdGVzIDwtIGdsbShRdWVlbnNib3JvQnJpZGdlIH4gRGF5ICsgQXZnVGVtcCArIGZhY3RvcihOZXdQcmVjaXApLCBvZmZzZXQgPSBsb2coVG90YWwpLCANCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIiksIGRhdGEgPSBjeWNsZS5uZXcpDQprYWJsZShzdW1tYXJ5KG1vZGVsLnJhdGVzKSRjb2VmLCBjYXB0aW9uID0gIlBvaXNzb24gcmVncmVzc2lvbiBvbiB0aGUgcmF0ZSBvZiBjeWNsaXN0cy4iKQ0KDQoNCg0KeWhhdCA9IG1vZGVsLnJhdGVzJGZpdHRlZC52YWx1ZXMNCnBlYXJzb24ucmVzaWQgPSAoY3ljbGUubmV3JFF1ZWVuc2Jvcm9CcmlkZ2UgLSB5aGF0KS9zcXJ0KHloYXQpDQpQZWFyc29uLmRpc3AgPSBzdW0ocGVhcnNvbi5yZXNpZF4yKS9tb2RlbC5yYXRlcyRkZi5yZXNpZHVhbA0KIyMNCkRldmlhbmNlLmRpc3AgPSAobW9kZWwucmF0ZXMkZGV2aWFuY2UpL21vZGVsLnJhdGVzJGRmLnJlc2lkdWFsDQojIw0KZGlzcCA9IGNiaW5kKFBlYXJzb24uZGlzcCA9IFBlYXJzb24uZGlzcCwgRGV2aWFuY2UuZGlzcCA9IERldmlhbmNlLmRpc3ApDQprYWJsZShkaXNwLCBjYXB0aW9uPSJEaXNwZXJzaW9uIHBhcmFtZXRlciIsIGFsaWduID0gJ2MnKQ0KYGBgDQpXZSBjYW4gc2VlIHRoYXQgc2ltaWxhciB0byB0aGUgZmlyc3QgbW9kZWwsIHRoYXQgYWxsIG9mIHRoZSBwIHZhbHVlcyBpbmRpY2F0ZSB0aGF0IGVhY2ggdmFyaWFibGUgaXMgaGlnaGx5IHNpZ25pZmljYW50LiBIb3dldmVyLCBib3RoIHRoZSBwZWFyc29uIGFuZCBkZXZpYW5jZSBkaXNwZXJzaW9uIGFyZSBhbHNvIHdheSBtb3JlIHRoYW4gb25lLCBidXQgdGhleSBhcmUgYWxzbyBzaWduaWZpY2FudGx5IGxlc3MgdGhhbiB0aGUgZGlzcGVyc2lvbiBmcm9tIHRoZSBwcmV2aW91cyBwb2lzc29uIHJlZ3Jlc3Npb24gbW9kZWwuIFRoaXMgaW5kaWNhdGVzIHRoYXQgb3VyIHBvaXNzb24gIG1vZGVsIG9uIHJhdGVzIHN0aWxsIHZpb2xhdGVzIHRoYXQgYXNzdW1wdGlvbiBvZiBlcXVhbCBtZWFuIGFuZCB2YXJpYW5jZS4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZSBwIHZhbHVlcyBmcm9tIHRoaXMgbW9kZWwgYXJlIG5vdCByZWxpYWJsZSBpbiB0aGUgZmlyc3QgcGxhY2UuIA0KDQpUaGUgdGFibGUgYWxzbyBzaG93cyB0aGF0IHRoZSBsb2cgb2YgYmlrZXJzIGNyb3NzaW5nIHRoZSBicmlkZ2UgaXMgbm90IHRoZSBzYW1lIGFjcm9zcyBhbGwgZGF5cyBvZiB0aGUgd2Vlay4gVGhlIGxvZyByYXRlcyBmb3IgdGhlIGRheSBGcmlkYXkgYXJlIGhpZ2hlciB0aGFuIHRoZSByZXN0IG9mIHRoZSBkYXlzIG9mIHRoZSB3ZWVrLiBUaGUgaW50ZXJjZXB0IHJlcHJlc2VudHMgdGhlIGxvZyBiYXNlIGN5Y2xpc3QgcmF0ZSBmb3IgdGhlIGJhc2VsaW5lIGRheSBGcmlkYXkuIFRoZSByZXN0IG9mIHRoZSBjb2VmZmljaWVudHMgYXJlIHRoZSBkaWZmZXJlbmNlIG9mIGxvZyByYXRlcyBiZXR3ZWVuIHRoZSBiYXNlbGluZSBkYXkgRnJpZGF5IGFuZCB0aGUgcmVzdCBvZiB0aGUgZGF5cyBvZiB0aGUgd2Vlay4gV2UgY2FuIHNlZSBmcm9tIHRoZSB0YWJsZSB0aGF0IC0wLjA2NyBpcyB0aGUgY29lZmZpY2llbnQgZm9yIE1vbmRheSBzbzoNCg0KbG9nKFJNb25kYXkgLyBSRnJpZGF5KSA9IC0wLjA2NyDih5IgICBSTW9uZGF5IC8gUkZyaWRheSA9IGVe4oiSMC4wNjcg4omIIDAuOTM1DQoNClRoaXMgbWVhbnMgdGhhdCB0aGUgcmF0ZSBvZiBiaWtlcnMgb24gTW9uZGF5IGlzIGFib3V0IDYuNSUgbG93ZXIgb24gTW9uZGF5IHRoYW4gb24gRnJpZGF5Lg0KDQojIyBRdWFzaSBQb2lzc29uIE1vZGVsDQoNClNpbmNlIHRoZSBkaXNwZXJzaW9uIGZyb20gdGhlIHByZXZpb3VzIG1vZGVsIHdhcyB2ZXJ5IGhpZ2gsIHdlIGFyZSBnb2luZyB0byBpbnN0ZWFkIHVzZSBhIHF1YXNpIHBvaXNzb24gbW9kZWwuIFRoaXMgbW9kZWwgZG9lcyBub3QgcmVxdWlyZSBhbiBlcXVhbCBtZWFuIGFuZCB2YXJpYW5jZS4gDQoNCmBgYHtyfQ0KcXVhc2kubW9kZWwgPSBnbG0oUXVlZW5zYm9yb0JyaWRnZSB+IERheSArIEF2Z1RlbXAgKyBmYWN0b3IoTmV3UHJlY2lwKSwgDQogICAgICAgICAgICAgICAgIGZhbWlseSA9IHF1YXNpcG9pc3NvbiwgZGF0YSA9IGN5Y2xlLm5ldykgIA0KDQpTRS5xdWFzaS5wb2lzID0gc3VtbWFyeShxdWFzaS5tb2RlbCkkY29lZg0Ka2FibGUoU0UucXVhc2kucG9pcywgY2FwdGlvbiA9ICJTdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgcXVhc2ktcG9pc3NvbiByZWdyZXNzaW9uIG1vZGVsIikNCg0KYGBgDQpXZSBjYW4gc2VlIGZyb20gdGhlIHRhYmxlIGFib3ZlIHRoYXQgdGhlIHZhcmlhYmxlcyAiRGF5IiBhbmQgIkF2Z1RlbXAiIGFyZSBub3Qgc2lnbmlmaWNhbnQgYnV0IHRoZSB2YXJpYWJsZSAiTmV3UHJjaXAiIGlzLiBUaGlzIGNvdWxkIGJlIGEgY29uY2Vybi4gQnV0IGZpcnN0LCB3ZSBhcmUgZ29pbmcgdG8gbG9vayBhdCB0aGUgZGlzcGVyc2lvbiBwYXJhbWV0ZXIuDQoNCk5leHQsIHdlIHdpbGwgY2FsY3VsYXRlIHRoZSBkaXNwZXJzaW9uIGluZGV4IG9mIG91ciBxdWFzaSBwb2lzc29uIG1vZGVsLiANCg0KYGBge3J9DQp5ZGlmPWN5Y2xlLm5ldyRRdWVlbnNib3JvQnJpZGdlLWV4cChxdWFzaS5tb2RlbCRsaW5lYXIucHJlZGljdG9ycykgICMgZGlmZiBiZXR3ZWVuIHkgYW5kIHloYXQNCnByc2QgPSB5ZGlmL3NxcnQoZXhwKHF1YXNpLm1vZGVsJGxpbmVhci5wcmVkaWN0b3JzKSkgICAjIFBlYXJzb24gcmVzaWR1YWxzDQpwaGkgPSBzdW0ocHJzZF4yKS8xNSAgICAgICAgICAjIERpc3BlcnNpb24gaW5kZXg6IDI0LTkgPSAxNSAgDQpwYW5kZXIoY2JpbmQoRGlzcGVyc2lvbiA9IHBoaSkpDQoNCmBgYA0KVGhlIGRpc3BlcnNpb24gaW5kZXggZm9yIHRoaXMgbW9kZWwgaXMgdmVyeSBoaWdoLiBCdXQgZ2l2ZW4gd2hhdCB3ZSBrbm93IG9mIHRoZSBkaXNwZXJzaW9uIGZyb20gdGhlIG9yaWdpb25hbCBwb2lzc29uIG1vZGVsIHRoaXMgaXMgdG8gYmUgZXhwZWN0ZWQuIA0KDQojIyBRdWFzaSBQb2lzc29uIG1vZGVsIG9uIFJhdGVzDQoNClNpbWlsYXIgdG8gdGhlIGxhc3Qgc2VjdGlvbiwgd2UgYXJlIGdvaW5nIHRvIGJ1aWxkIGFub3RoZXIgcXVhc2kgcG9pc3NvbiByZWdyZXNzaW9uIG1vZGVsIGJ1dCB0aGlzIHRpbWUsIGJhc2VkIG9uIHRoZSByYXRlcyBvZiB0aGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIGNyb3NzaW5nIHNldmVyYWwgbWFqb3IgYnJpZGdlcyBpbiBOZXcgWW9yay4gV2Ugd2lsbCBhbHNvIGNhbGN1bGF0ZSB0aGUgZGlzcGVyc2lvbiBmb3IgdGhpcyBtb2RlbC4NCg0KYGBge3J9DQpxdWFzaW1vZGVsLnJhdGVzIDwtIGdsbShRdWVlbnNib3JvQnJpZGdlIH4gRGF5ICsgQXZnVGVtcCArIGZhY3RvcihOZXdQcmVjaXApLCBvZmZzZXQgPSBsb2coVG90YWwpLCANCiAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSBxdWFzaXBvaXNzb24sIGRhdGEgPSBjeWNsZS5uZXcpDQpwYW5kZXIoc3VtbWFyeShxdWFzaW1vZGVsLnJhdGVzKSRjb2VmLCBjYXB0aW9uID0gIlF1YXNpLVBvaXNzb24gcmVncmVzc2lvbiBvbiB0aGUgTnVtYmVyIG9mIEN5Y2xpc3RzIikNCg0KeWRpZj1jeWNsZS5uZXckUXVlZW5zYm9yb0JyaWRnZS1leHAocXVhc2ltb2RlbC5yYXRlcyRsaW5lYXIucHJlZGljdG9ycykgICMgZGlmZiBiZXR3ZWVuIHkgYW5kIHloYXQNCnByc2QgPSB5ZGlmL3NxcnQoZXhwKHF1YXNpbW9kZWwucmF0ZXMkbGluZWFyLnByZWRpY3RvcnMpKSAgICMgUGVhcnNvbiByZXNpZHVhbHMNCnBoaSA9IHN1bShwcnNkXjIpLzE1ICAgICAgICAgICMgRGlzcGVyc2lvbiBpbmRleDogMjQtOSA9IDE1ICANCnBhbmRlcihjYmluZChEaXNwZXJzaW9uID0gcGhpKSkNCmBgYA0KRnJvbSB0aGUgdGFibGUgYWJvdmUsIHdlIGNhbiBzZWUgdGhhdCBub25lIG9mIHRoZSBwIHZhbHVlcyBhcmUgc2lnbmlmaWNhbnQuIFRoZSBkaXNwZXJzaW9uIGluZGV4IGlzIHN0aWxsIHZlcnkgaGlnaCBidXQgbm90IG5lYXJseSBhcyBoaWdoIGFzIHRoZSBvbmUgZnJvbSB0aGUgcmVndWxhciBxdWFzaSBwb2lzc29uIG1vZGVsLiANCg0KIyMgRmluYWwgTW9kZWwNCg0KVGhlIGZpbmFsIG1vZGVsIGNob3NlbiBmb3IgdGhpcyBhbmFseXNpcyB3aWxsIGJlIHRoZSBxdWFzaSBwb2lzc29uIG1vZGVsIG9uIHJhdGVzLiBEZXNwaXRlIHRoZSBxdWFzaSBtb2RlbHMgaGF2aW5nIGxlc3Mgc2lnbmlmaWNhbnQgcCB2YWx1ZXMsIHRoZXkgZG8gbm90IHJlcXVpcmUgZXF1YWwgbWVhbiBhbmQgdmFyaWFuY2UuIFdlIGhhdmUgc2VlbiBmcm9tIGNhbGN1bGF0aW5nIHRoZSBkaXNwZXJzaW9uIG9mIHRoZSBwb2lzc29uIG1vZGVscyB0aGF0IHRoZSBtZWFucyBhbmQgdmFyaWFuY2VzIGZvciBib3RoIHRoZSBwb2lzc29uIGFuZCBwb2lzc29uIHJhdGVzIG1vZGVscyB3ZXJlIG5vdCBhdCBhbGwgZXF1YWwgd2l0aCB2ZXJ5IGhpZ2ggZGlzcGVyc2lvbi4gVGhlIHJhdGUgcXVhc2kgcG9pc3NvbiBtb2RlbCBvbiByYXRlcyB3aWxsIGJlIHVzZWQgYmVjYXVzZSBkZXNwaXRlIHN0aWxsIGhhdmluZyBhIGhpZ2ggZGlzcGVyc2lvbiBpbmRleCwgaXQgd2FzIG11Y2ggY2xvc2VyIHRvIG9uZSB0aGFuIG9uIHRoZSByZWd1bGFyICBUaGUgZmluYWwgbW9kZWwgY2FuIGJlIHdyaXR0ZW4gYXM6DQoNCnJhdGUgPSBleHAoLTEuMjU3IC0wLjA4MTggKiBEYXlTdW5kYXkgLSAwLjA2NzkgKiBEYXlNb25kYXkgLSAwLjA0NzggKiBEYXlUdWVzZGF5IC0gMC4wNDM0ICogRGF5V2VkbmVzZGF5IC0gMC4wMzUgKiBEYXlUaHVyc2RheSAtIDAuMDM1OCAqIERheVNhdHVyZGF5KSB4ICgwLjAwMTYgKiBBdmdUZW1wKSB4ICgwLjA0NzYgKiBOZXdQcmVjaXApDQoNCiMjIFNvbWUgVmlzdWFsIENvbXBhcmlzb25zIA0KDQpOb3csIHdlIHdpbGwgY3JlYXRlIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIGhvdyB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzIGFmZmVjdCB0aGUgYWN0dWFsIG51bWJlciBvZiBjeWNsaXN0cyBvbiB0aGUgUXVlZW5zYm9ybyBCcmlkZ2UuIEVhY2ggbGluZSBvbiB0aGUgZ3JhcGggd2lsbCByZXByZXNlbnQgYSBkYXkgb2YgdGhlIHdlZWsuIFdlIHdpbGwgdmlzdWFsaXplIHdoYXQgZWZmZWN0IGRheSBhbmQgYXZlcmFnZSB0ZW1wZXJhdHVyZSBoYXZlIG9uIHRoZW0uICANCg0KYGBge3J9DQpTdW5kYXkgPSBjKGV4cCgtMS4yNTcrNyksIGV4cCgtMS4yNTctMC4wODE4LTAuMDAxNiksICAgDQogICAgICAgICAgICAgICBleHAoLTEuMjU3LTAuMDgxOCswLjA0NzYpKQ0KDQpNb25kYXkgPSBjKGV4cCgtMS4yNTcrMC4wMDE4MTUpLCBleHAoLTEuMjU3KzAuMDY3OS0wLjAwMTYpLCAgIA0KICAgICAgICAgICAgICAgZXhwKC0xLjI1NyswLjA2NzkrMC4wNDc2KSkNCg0KDQpUdWVzZGF5ID0gYyhleHAoLTEuMjU3KzAuMDI1MjkpLCBleHAoLTEuMjU3LTAuMDQ3OC0wLjAwMTYpLCAgIA0KICAgICAgICAgICAgICAgZXhwKC0xLjI1Ny0wLjA0NzgrMC4wNDc2KSkNCg0KDQpXZWRuZXNkYXk9IGMoZXhwKC0xLjI1NyswLjAxODM1KSwgZXhwKC0xLjI1Ny0wLjA0MzQtMC4wMDE2KSwgICANCiAgICAgICAgICAgICAgIGV4cCgtMS4yNTctMC4wNDM0KzAuMDQ3NikpDQoNCg0KVGh1cnNkYXkgPSBjKGV4cCgtMS4yNTcrMC4wMjM3KSwgZXhwKC0xLjI1Ny0wLjAzNS0wLjAwMTYpLCAgIA0KICAgICAgICAgICAgICAgZXhwKC0xLjI1Ny0wLjAzNSswLjA0NzYpKQ0KDQoNCkZyaWRheSA9IGMoZXhwKC0xLjI1NyksIGV4cCgtMS4yNTctMC4wMDE2KSwgICANCiAgICAgICAgICAgICAgIGV4cCgtMS4yNTcrMC4wNDc2KSkNCg0KDQpTYXR1cmRheSA9IGMoZXhwKC0xLjI1NyswLjAzNDU0KSwgZXhwKC0xLjI1Ny0wLjAzNTgtMC4wMDE2KSwgICANCiAgICAgICAgICAgICAgIGV4cCgtMS4yNTctMC4wMzU4KzAuMDQ3NikpDQoNCm1pbm1heCA9IHJhbmdlKGMoTW9uZGF5LFR1ZXNkYXksIFdlZG5lc2RheSwgVGh1cnNkYXksIEZyaWRheSwgU2F0dXJkYXksIFN1bmRheSkpDQoNCmBgYA0KDQpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTZ9DQpwbG90KDE6MywgRnJpZGF5LCB0eXBlPSJsIiwgbHR5ID0xLCBjb2w9InJlZCIsIHhsYWI9IiIsIA0KICAgICAgICAgICAgICAgeWxhYj0iQmlrZSBSYXRlIiwgeGxpbT1jKDAsNiksIHlsaW09YygwLjIsIDAuMzUpLCBheGVzPUZBTFNFICkNCmF4aXMoMikNCmF4aXMoMSwgbGFiZWxzPWMoIkF2Z1RlbXAiLCAiTmV3UHJlY2lwIiksIGF0ID0gMToyKQ0KcG9pbnRzKDE6MyxGcmlkYXksIHBjaD0xOSwgY29sPSJyZWQiKQ0KIyMNCmxpbmVzKDE6MywgU2F0dXJkYXksIGx0eSA9MiwgY29sPSJncmVlbiIpDQpwb2ludHMoMTozLCBTYXR1cmRheSwgcGNoPTIwLCBjb2w9ImdyZWVuIikNCiMjDQpsaW5lcygxOjMsIFN1bmRheSwgbHR5ID0zLCBjb2w9InB1cnBsZSIpDQpwb2ludHMoMTozLCBTdW5kYXksIHBjaD0yMSwgY29sPSJwdXJwbGUiKQ0KIyMjDQpsaW5lcygxOjMsIE1vbmRheSwgbHR5ID00LCBjb2w9ImJsYWNrIikNCnBvaW50cygxOjMsIE1vbmRheSwgcGNoPTIyLCBjb2w9ImJsYWNrIikNCiMjDQpsaW5lcygxOjMsIFR1ZXNkYXksIGx0eSA9NSwgY29sPSJibHVlIikNCnBvaW50cygxOjMsIFR1ZXNkYXksIHBjaD0yMywgY29sPSJibHVlIikNCiMjDQpsaW5lcygxOjMsIFdlZG5lc2RheSwgbHR5ID02LCBjb2w9Im9yYW5nZSIpDQpwb2ludHMoMTozLCBXZWRuZXNkYXksIHBjaD0yNCwgY29sPSJvcmFuZ2UiKQ0KIyMNCmxpbmVzKDE6MywgVGh1cnNkYXksIGx0eSA9NywgY29sPSJ0dXJxdW9pc2UiKQ0KcG9pbnRzKDE6MywgVGh1cnNkYXksIHBjaD0yNSwgY29sPSJ0dXJxdW9pc2UiKQ0KIyMNCg0KDQpsZWdlbmQoInRvcHJpZ2h0IiwgYygiRnJpZGF5IiwiU2F0dXJkYXkiLCAiU3VuZGF5IiwgIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIgKSwNCiAgICAgICAgICAgICAgICAgIHBjaD0xOToyMiwgbHR5PTE6NywgIGJ0eT0ibiIsIA0KICAgICAgICBjb2w9YygicmVkIiwgImdyZWVuIiwgInB1cnBsZSIsICJibGFjayIsICJibHVlIiwgIm9yYW5nZSIsICJ0dXJxdW9pc2UiKSkNCmBgYA0KDQoNCkZyb20gdGhlIGdyYXBoIHdlIGNhbiBzZWUgYSBmZXcgdGhpbmdzOg0KDQotIFRoZSBtb3N0IGJpa2VycyBjcm9zcyB0aGUgUXVlZW5zYm9ybyBCcmlkZ2Ugb24gTW9uZGF5IG9uIGF2ZXJhZ2UuDQoNCi0gVGhlcmUgaXMgYSBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhdmVyYWdlIHRlbXBlcmF0dXJlIGFuZCB0aGUgbnVtYmVyIG9mIGN5Y2xpc3RzLg0KDQoNCg0KIyBTdW1tYXJ5IGFuZCBDb25jbHVzaW9uDQoNClRvIHN1bW1hcml6ZSwgd2UgbG9va2VkIGF0IGEgZGF0YSBzZXQgdGhhdCBsb29rcyBhdCBob3cgbWFueSBiaWtlcnMgY3Jvc3Mgb3ZlciB0aGUgUXVlZW5zYm9ybyBCcmlkZ2UgaW4gTllDIGV2ZXJ5IGRheSBmb3IgdGhlIG1vbnRoIG9mIEp1bHksIGxlYXZpbmcgdXMgd2l0aCAzMSBvYnNlcnZhdGlvbnMuIFRoZSA0IGV4cGxhbmF0b3J5IHZhcmlhYmxlcyBsb29rIGF0IHRoZSBkYXkgb2YgdGhlIHdlZWsgYW5kIHRoZSB3ZWF0aGVyIGNvbmRpdGlvbnMgb24gZWFjaCBkYXkuIFdlIGNyZWF0ZWQgdHdvIG5ldyB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgc2V0IGFuZCB1c2VkIHRoZW0gaW4gYWxsIG91ciBtb2RlbHMgYWxvbmcgd2l0aCB0aGUgdmFyaWFibGUgJ0RheSIuIE9uZSB3YXMgY2FsbGVkICJBdmdUZW1wIiBhbmQgaXQgdG9vayB0aGUgYXZlcmFnZSB0ZW1wZXJhdHVyZSBvZiB0aGUgaGlnaCBhbmQgbG93IHRlbXBlcmF0dXJlIHZhcmlhYmxlcy4gVGhlIG90aGVyIHZhcmlhYmxlICJOZXdQcmVjaXAiIGNhdGVnb3JpemVkIHRoZSB2YXJpYWJsZSAiUHJlY2lwaXRhdGlvbiIgYXM6IGlmIFByZWNpcGl0YXRpb24gPSAwLCB0aGVuIE5ld1ByZWNpcCA9IDA7IGlmIFByZWNpcGl0YXRpb24gPiAwLCB0aGVuIE5ld1ByZWNpcCA9IDEgT3VyIGdvYWwgd2FzIHRvIHNlZSB3aGF0IHRoZSByZWxhdGlvbnNoaXAgd2FzIGJldHdlZW4gdGhlc2UgdmFyaWFibGVzIGFuZCB0aGUgbnVtYmVyIG9mIGN5Y2xpc3RzLiBXZSBhbHNvIHdhbnRlZCB0byBzZWUgaWYgdGFraW5nIGludG8gYWNjb3VudCB0aGUgdG90YWwgbnVtYmVyIG9mIGN5Y2xpc3RzIHRoYXQgY3Jvc3Mgc2V2ZXJhbCBtYWpvciBicmlkZ2VzIGluIE5ZQy4gVG8gZmlndXJlIHRoaXMgb3V0LCB3ZSBidWlsdCBhIFBvaXNzb24gZnJlcXVlbmN5IHJlZ3Jlc3Npb24gbW9kZWwsIGEgUG9pc3NvbiBNb2RlbCBvbiByYXRlcywgYW5kIGEgcXVhc2kgcG9pc3NvbiBtb2RlbCwgYW5kIGEgcXVhc2kgcG9pc3NvbiByZWdyZXNzaW9uIG1vZGVsIG9uIHJhdGVzLiANCg0KV2UgZm91bmQgZnJvbSBjYWxjdWxhdGluZyB0aGUgZGlzcGVyc2lvbiBvZiB0aGUgcG9pc3NvbiBtb2RlbCB0aGF0IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSB3ZXJlIG5vdCBlcXVhbC4gQmVjYXVzZSBvZiB0aGlzLCB3ZSBkZWNpZGVkIHRoaXMgd2FzIG5vdCB0aGUgYmVzdCBtb2RlbC4gVGhlIGZpbmFsIG1vZGVsIGNob3NlbiB3YXMgdGhlIHF1YXNpIHBvaXNzb24gbW9kZWwgb24gcmF0ZXMuRGVzcGl0ZSB0aGUgcXVhc2kgbW9kZWxzIGhhdmluZyBsZXNzIHNpZ25pZmljYW50IHAgdmFsdWVzLCB0aGV5IGRvIG5vdCByZXF1aXJlIGVxdWFsIG1lYW4gYW5kIHZhcmlhbmNlLiBBIHJlY29tbWVuZGF0aW9uIGZvciBmdXJ0aGVyIHJlc2VhcmNoIGlzIHRvIHRyeSB0byBmaW5kIGhvdyB0cnVseSBzaWduaWZpY2FudCB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGVzLiBXaXRoIGVhY2ggbW9kZWwgd2UgdXNlZCwgdGhlIHAgdmFsdWVzIGNoYW5nZWQsIHNvIHRoZXkgd2VyZSBub3QgdmVyeSBtZWFuaW5nZnVsLiANCg0KDQoNCg0K