Data Wrangling
In this assignment,I forecast space/time demand for bike share
pickups in New York City and designed an algorithm to inform a bike
re-balancing plan. The data I use here is obtained from Citi Bike Trip
Data that contains the latest monthly record of Citi Bike usage in
New York City.
My model will take a low resolution approach, reducing millions of
NYC ride share trips from May through June, 2023, into a 15% subsample
and aggregating to hourly intervals and a subset of New York City Census
tracts.
Trip Data
Census Data
Several census geography and variables are loaded and wrangled to
test generalizability later. Among them, there are Population, Race,
Means of Transport, Mean Commute Time, % of taking public transit,
etc.
Weather Data
Furthermore, I have incorporated weather data from JFK Airport into
my analysis. To be specific, I imported hourly data related to
temperature, wind speed, and precipitation. I have also created
visualizations to illustrate the trends in temperature and precipitation
throughout the duration of my study period.
weather.Panel <-
riem_measures(station = "JFK", date_start = "2023-05-01", date_end = "2023-05-31") %>%
dplyr::select(valid, tmpf, p01i, sknt)%>%
replace(is.na(.), 0) %>%
mutate(interval60 = ymd_h(substr(valid,1,13))) %>%
mutate(week = week(interval60),
dotw = wday(interval60, label=TRUE)) %>%
group_by(interval60) %>%
summarize(Temperature = max(tmpf),
Precipitation = sum(p01i),
Wind_Speed = max(sknt)) %>%
mutate(Temperature = ifelse(Temperature == 0, 42, Temperature))
glimpse(weather.Panel)
## Rows: 721
## Columns: 4
## $ interval60 <dttm> 2023-05-01 00:00:00, 2023-05-01 01:00:00, 2023-05-01 02…
## $ Temperature <dbl> 56, 54, 52, 50, 50, 50, 51, 55, 57, 59, 60, 59, 58, 59, …
## $ Precipitation <dbl> 3e-02, 1e-04, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, 0e+00, …
## $ Wind_Speed <dbl> 14, 19, 21, 16, 19, 19, 18, 17, 15, 18, 15, 18, 20, 17, …
grid.arrange(
ggplot(weather.Panel, aes(interval60,Precipitation)) + geom_line(color="#FF759F") +
labs(title="Percipitation", x="Hour", y="Perecipitation") + plotTheme(),
ggplot(weather.Panel, aes(interval60,Wind_Speed)) + geom_line(color="#FF759F") +
labs(title="Wind Speed", x="Hour", y="Wind Speed") + plotTheme(),
ggplot(weather.Panel, aes(interval60,Temperature)) + geom_line(color="#FF759F") +
labs(title="Temperature", x="Hour", y="Temperature") + plotTheme(),
top="Weather Data - NYC JFK - May, 2023")

Amenity Data
In addition, I incorporated amenity data into my analysis, as it has
the potential to significantly impact the bike re-balancing process. For
instance, the proximity of various points of interest such as landmarks,
markets, bus stations, and colleges can influence the demand for shared
bikes. Therefore, I included these amenity features as variables in my
analysis. To further refine the analysis, I employed the k-nearest
neighbor (k=1) method to calculate the nearest landmark, market, bus
station, and college for each bike station. This helps to account for
the influence of these amenities on bike station usage and re-balancing
strategies.
Space-Time Panel
I created a data frame panel which has each unique space/time
observations. Then the trip counts were summarized by station for each
time interval. Also, the socio-economic information and
latitude/longitude information were also kept for future data
integration and analysis.
length(unique(dat_census$interval60)) * length(unique(dat_census$start_station_id))
## [1] 494760
study.panel <-
expand.grid(interval60=unique(dat_census$interval60),
start_station_id = unique(dat_census$start_station_id)) %>%
left_join(., dat_census %>%
select(start_station_id, start_station_name, Origin.Tract, start_lng, start_lat )%>%
distinct() %>%
group_by(start_station_id) %>%
slice(1)) %>%
left_join(.,amenity_nn %>%
select(start_station_id, Landmarks.nn, Markets.nn, Bus_Stations.nn, College.nn)%>%
distinct() %>%
group_by(start_station_id) %>%
slice(1))
## Joining with `by = join_by(start_station_id)`
## Joining with `by = join_by(start_station_id)`
nrow(study.panel)
## [1] 494760
Time Lags
Moreover, time lag variables about the demand during a given time
period are also added. by evaluating the correlations in the lags, we
can tell that some of the lags are pretty strong. For example, there’s a
Pearson’s R of 0.87 and 0.86 for the lagHour
and
lag1day
respectively, indicating that the demand for an
hour ago and a day ago is strongly correlated with the demand now.
However, the 12-hour lag exhibits an opposite relationship in terms of
demand.
## # A tibble: 6 × 2
## Variable correlation
## <fct> <dbl>
## 1 lagHour 0.87
## 2 lag2Hours 0.64
## 3 lag3Hours 0.41
## 4 lag4Hours 0.21
## 5 lag12Hours -0.49
## 6 lag1day 0.85
Exploratory Analysis
Serial Autocorrelation
I begin by examining the time and frequency components of the data.
First, from the overall time pattern - there is clearly a daily
periodicity and there are lull periods on weekends. Also, the weekend
near the 22th of May doesn’t have the same dip in activity due to the
extreme weather.

By examining the distribution of trip volume by station for different
times of the day, it’s clear that there are a few high volume periods
but mostly low volume.


I’ve also analyzed the daily trends in ridership, differentiating
between days of the week and distinguishing between weekends and
weekdays. The temporal patterns are quite apparent, with weekdays
exhibiting the highest trip counts. Furthermore, among weekdays, the
peak in trip counts aligns with commuting hours, indicating a strong
correlation between ridership and typical commuting times.



The figure below plots out the aggregate number of trips as a
function of date. The vertical lines indicate Mondays. From it, the
weekly pattern is obvious that there are peaks and troughs within a week
and a day.
## `summarise()` has grouped output by 'Legend'. You can override using the
## `.groups` argument.

Further, I plot the ridershare trip count as a function of spatial
lags to check the correlation. The analysis reveals a robust correlation
between trip initiations and lag features. However, this correlation
gradually diminishes as the lag period increases within a single day.
Notably, a lag of 12 hours exhibits no statistically significant
relationship with trip initiations. However, a lag of 1 day has.
## `geom_smooth()` using formula = 'y ~ x'

Spatial Correlation
Then it comes to spatial correlation, the bike-share ridership also
shows spatial autocorrelation. The maps below further show the sum of
bike share trips by station and by days of the week, indicating that the
majority of trips start in midtown & lower Manhattan.
## `summarise()` has grouped output by 'week', 'Origin.Tract', 'start_lng'. You
## can override using the `.groups` argument.

## `summarise()` has grouped output by 'dotw', 'Origin.Tract', 'start_lng'. You
## can override using the `.groups` argument.

Space/time correlation
Again, the bike share ridership also exhibits strong space/time
correlation. To show, I pick up one day in NYC in May, 2023 to visualize
the relationship with 15-minute intervals via an animation.

Weather
As for the effect of weather, obviously ridership also varies with
precipitation and temperature.

The average number of trips per week seems to trend upward as the
temperature increases. This trend is pretty consistent across all
panels.
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 24 rows containing non-finite values (`stat_smooth()`).
## Warning: Removed 24 rows containing missing values (`geom_point()`).

Modeling and Validation
In this part, I split the data into a training and a test set and
created five linear models using the lm
funtion. The first
models include only temporal controls, but the later ones contain all of
our lag information or amenities.
Five linear regressions are further estimated on bike-share train
data, each with different fixed effects: 1. reg 1 focuses on just time,
including hour fixed effects, day of the week, and Temperature. 2. reg 2
further adds space effects for the across-station differences. 3. reg 3
combines the time and space effects, and also adds more weather effects,
such as precipitation. 4. reg 4 takes time lag features into
consideration. 5. reg 5 further adds more amenities effects, such as
landmarks, markets, colleges, and bus stations.
##Predict for test data
ride.Test.weekNest <-
ride.Test %>%
nest(-week)
ride.Test.weekNest
## # A tibble: 2 × 2
## week data
## <dbl> <list>
## 1 18 <tibble [95,760 × 34]>
## 2 19 <tibble [111,720 × 34]>
## # A tibble: 10 × 8
## week data Regression Prediction Observed Absolute_Error MAE sd_AE
## <dbl> <list> <chr> <list> <list> <list> <dbl> <dbl>
## 1 18 <tibble> ATime_FE <dbl> <dbl> <dbl [95,760]> 0.401 0.651
## 2 19 <tibble> ATime_FE <dbl> <dbl> <dbl> 0.558 0.698
## 3 18 <tibble> BSpace_FE <dbl> <dbl> <dbl [95,760]> 0.398 0.581
## 4 19 <tibble> BSpace_FE <dbl> <dbl> <dbl> 0.475 0.649
## 5 18 <tibble> CTime_Space_FE <dbl> <dbl> <dbl [95,760]> 0.391 0.576
## 6 19 <tibble> CTime_Space_FE <dbl> <dbl> <dbl> 0.479 0.636
## 7 18 <tibble> DTime_Space_FE… <dbl> <dbl> <dbl [95,760]> 0.340 0.546
## 8 19 <tibble> DTime_Space_FE… <dbl> <dbl> <dbl> 0.400 0.606
## 9 18 <tibble> ETime_Space_FE… <dbl> <dbl> <dbl [95,760]> 0.340 0.546
## 10 19 <tibble> ETime_Space_FE… <dbl> <dbl> <dbl> 0.400 0.606
Examine Error Metrics for Accuracy
By plotting MAE by model by week, the spatial fixed effects and
temporal+spatial fixed effects do a similar job in predicting.However,
the model starts to become more accurate when lag effects are taken into
consideration, with a MAE under 0.4, which is exactly same as the model
which further takes amenities features into consideration.

From the predicting performances plot, the model is getting more
accurate and generalizable after applying time, space, lag features. The
lag model does a good performance in predicting the bike share in first
two weeks of May, although it loses some observations at the beginning
of the month and also underestimates a little bit.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id)) %>%
dplyr::select(interval60, start_station_id, Observed, Prediction, Regression) %>%
unnest() %>%
gather(Variable, Value, -Regression, -interval60, -start_station_id) %>%
group_by(Regression, Variable, interval60) %>%
summarize(Value = sum(Value)) %>%
ggplot(aes(interval60, Value, colour=Variable)) +
geom_line(size = 1.1) +
facet_wrap(~Regression, ncol=1) +
scale_color_manual(values = palette2) +
labs(title = "Predicted/Observed bike share time series", subtitle = "New York City; A test set of 2 weeks", x = "Hour", y= "Station Trips") +
plotTheme()
## `summarise()` has grouped output by 'Regression', 'Variable'. You can override
## using the `.groups` argument.

Based on the Space_Time_Lag(_amenity) model(Reg4/Reg5) which seems to
have the best goodness of fit generally, we can observe some spatial
patterns from the mean absolute errors by station. Specifically, the
stations with higher MAE are aggregated in Midtown & Lower
Manhattan.
## `summarise()` has grouped output by 'start_station_id', 'start_lng'. You can
## override using the `.groups` argument.

Space-Time Error Evaluation
By comparing observed versus predicted ridership for various times of
day across weekdays and weekends, the presence of space-time errors
becomes apparent. The majority of the data points falling below the
identity line suggests that the model generally underestimates
bike-share usage. This trend is particularly pronounced during the
weekday morning rush hours. Furthermore, the slope of the best fit
linek
varies across different time slots for both weekdays
and weekends, indicating fluctuations in the model’s predictive accuracy
dependent on the specific time period being analyzed. Therefore, more
factors should be taken into consideration.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id),
start_lat = map(data, pull, start_lat),
start_lng = map(data, pull, start_lng),
dotw = map(data, pull, dotw)) %>%
select(interval60, start_station_id, start_lng,
start_lat, Observed, Prediction, Regression,
dotw) %>%
unnest() %>%
filter(Regression == "DTime_Space_FE_timeLags")%>%
mutate(weekend = ifelse(dotw %in% c("周日", "周六"), "Weekend", "Weekday"),
time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 19 ~ "Overnight",
hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
hour(interval60) >= 15 & hour(interval60) <= 19 ~ "PM Rush"))%>%
ggplot()+
geom_point(aes(x= Observed, y = Prediction))+
geom_smooth(aes(x= Observed, y= Prediction), method = "lm", se = FALSE, color = "#FFA7C4" )+
geom_abline(slope = 1, intercept = 0,color="#622A8C")+
facet_grid(time_of_day~weekend)+
labs(title="Observed vs Predicted by the day of the week and hour",
x="Observed trips",
y="Predicted trips")+
plotTheme()
## `geom_smooth()` using formula = 'y ~ x'

These maps further show that high errors are concentrated in midtown
& lower Manhattan - where bike-share riderships are also high.
## `summarise()` has grouped output by 'start_station_id', 'weekend',
## 'time_of_day', 'start_lng'. You can override using the `.groups` argument.

Focusing on the morning commute, the model doesn’t perform well for
specific socio-economic groups characterized by higher income, lower
public transit usage, and higher white population %.
week_predictions %>%
mutate(interval60 = map(data, pull, interval60),
start_station_id = map(data, pull, start_station_id),
start_lat = map(data, pull, start_lat),
start_lng = map(data, pull, start_lng),
dotw = map(data, pull, dotw),
Percent_Taking_Public_Trans = map(data, pull, Percent_Taking_Public_Trans),
Med_Inc = map(data, pull, Med_Inc),
Percent_White = map(data, pull, Percent_White)) %>%
select(interval60, start_station_id, start_lng,
start_lat, Observed, Prediction, Regression,
dotw, Percent_Taking_Public_Trans, Med_Inc, Percent_White) %>%
unnest() %>%
filter(Regression == "DTime_Space_FE_timeLags")%>%
mutate(weekend = ifelse(dotw %in% c("周日", "周六"), "Weekend", "Weekday"),
time_of_day = case_when(hour(interval60) < 7 | hour(interval60) > 19 ~ "Overnight",
hour(interval60) >= 7 & hour(interval60) < 10 ~ "AM Rush",
hour(interval60) >= 10 & hour(interval60) < 15 ~ "Mid-Day",
hour(interval60) >= 15 & hour(interval60) <= 19 ~ "PM Rush")) %>%
filter(time_of_day == "AM Rush") %>%
group_by(start_station_id, Percent_Taking_Public_Trans, Med_Inc, Percent_White) %>%
summarize(MAE = mean(abs(Observed-Prediction), na.rm = TRUE))%>%
gather(-start_station_id, -MAE, key = "variable", value = "value")%>%
ggplot(.)+
geom_point(aes(x = value, y = MAE), alpha = 0.4)+
geom_smooth(aes(x = value, y = MAE,color="#622A8C"), method = "lm", se= FALSE)+
facet_wrap(~variable, scales = "free")+
labs(title="Errors as a function of socio-economic variables",
y="Mean Absolute Error (Trips)")+
plotTheme()

Cross-validation
To further validate the generalizability of the model, I cross
validate the model by time and space. To manage the large number of data
points, the model deemed most effective was subjected to a 50-fold
cross-validation. This means that the data was divided into 50 parts,
with the model being trained on 49 parts and tested on the 1 remaining
part, this process being repeated 50 times with different parts each
time.
As we can see, the mean absolute error is slightly over 0.37. In
terms of the CV goodness of fit metrics,the metrics are clusterd close
to the man, suggesting that the model performs consistently and shows
good generalizabilty.
## Linear Regression
##
## 287712 samples
## 10 predictor
##
## No pre-processing
## Resampling: Cross-Validated (50 fold)
## Summary of sample sizes: 281958, 281958, 281957, 281957, 281957, 281958, ...
## Resampling results:
##
## RMSE Rsquared MAE
## 0.6887728 0.3352304 0.3676375
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
Mean Absolute Error
|
Standard Deviation of MAE
|
0.3676375
|
0.0079647
|
dplyr::select(cvFit$resample, -Resample) %>%
gather(metric, value) %>%
left_join(gather(cvFit$results[2:4], metric, mean)) %>%
ggplot(aes(value)) +
geom_histogram(bins=35, fill = "#FFA7C4") +
facet_wrap(~metric) +
geom_vline(aes(xintercept = mean), colour = "#B14A90", linetype = 3, size = 1.5) +
scale_x_continuous(limits = c(0, 1)) +
labs(x="Goodness of Fit", y="Count", title="CV Goodness of Fit Metrics",
subtitle = "50 folds, Across-fold mean reprented as dotted lines") +
plotTheme()
## Joining with `by = join_by(metric)`
## Warning: Removed 6 rows containing missing values (`geom_bar()`).

LS0tDQp0aXRsZTogIlNwYWNlLVRpbWUgUHJlZGljdGlvbiBvZiBCaWtlIFNoYXJlIERlbWFuZCBpbiBOWUMiDQphdXRob3I6ICJMaW5nIENoZW4iDQpkYXRlOiAiTm92ZW1iZXIgMjIsIDIwMjMiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogImhpZGUiDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCiMgSW50cm9kdWN0aW9uDQoNCkJpa2Ugc2hhcmUgaXMgYSBkb2NrLWJhc2VkIHNoYXJpbmcgc3lzdGVtLCB3aGljaCBpcyBhbHNvIGEgc3VzdGFpbmFibGUgYW5kIGNvbnZlbmllbnQgdHJhbnNwb3J0YXRpb24gb3B0aW9uLiBUaGUgc3lzdGVtIGNhbiBwcm92aWRlIGFjY2VzcyB0byBiaWtlcyBmb3Igc2hvcnQtdGVybSB1c2UsIHJhbmdpbmcgZnJvbSBzZXZlcmFsIG1pbnV0ZXMgdG8gaG91cnMuIEhvd2V2ZXIsIHRoZSBtb3N0IGRpZmZpY3VsdCBvcGVyYXRpb25hbCBwcm9ibGVtcyBpcyB0aGUgbmVlZCB0byByZS1iYWxhbmNlIGJpa2VzIGFjcm9zcyB0aGUgbmV0d29yay4gQXMgYmlrZSBzaGFyZSBpcyBub3QgdXNlZnVsIGlmIGEgZG9jayBoYXMgbm8gYmlrZXMgdG8gcGljayB1cCwgbm9yIGlmIHRoZXJlIGFyZSBubyBvcGVuaW5nIGRvY2tpbmcgc3BhY2VzIHRvIGRlcG9zaXQuIFRoZXJlZm9yZSwgdGhlIHJlLWJhbGFuY2luZyBpcyB0aGUgcHJhY3RpY2Ugb2YgYW50aWNpcGF0aW5nIGJpa2Ugc2hhcmUgZGVtYW5kIGZvciBhbGwgZG9ja3MgYXQgYWxsIHRpbWVzIGFuZCBtYW51YWxseSByZWRpc3RyaWJ1dGluZyBiaWtlcyB0byBlbnN1cmUgYSBiaWtlIG9yIGEgZG9ja2luZyBzcGFjZSBpcyBhdmFpbGFibGUgd2hlbiBuZWVkZWQuDQoNCkluIHRoaXMgYXNzaWdubWVudCwgSSdsbCBkaXZlIGludG8gdGhlIGJpa2Ugc2hhcmUgc3lzdGVtIGluIE5ldyBZb3JrIENpdHkgKENpdGkgQmlrZSkgYW5kIGZvcmVjYXN0IHNwYWNlL3RpbWUgZGVtYW5kIGZvciBiaWtlIHNoYXJlIHBpY2t1cHMuIE15IGZvY3VzZWQgYXJlYSBhbmQgdGltZSBmcmFtZSBpcyBNYW5oYXR0YW4sIE1heSAyMDIzLiBCeSBkZXZlbG9waW5nIGFuIGFsZ29yaXRobSB0byBwcmVkaWN0IHRoZSB0cmlwIHN0YXJ0cyBhY3Jvc3MgdGltZSBhbmQgc3BhY2UsIEkgdHJ5IHRvIGVuLXZpc2lvbiBhbmQgaW5mb3JtIGEgYmlrZSByZS1iYWxhbmNpbmcgcGxhbiB0byBlbnN1cmUgc3VwcGx5IGFuZCBlbmhhbmNlIGVmZmljaWVuY3kuDQoNClNwZWNpZmljYWxseSwgc2V2ZXJhbCBtZWNoYW5pc21zIHdpbGwgYmUgdGFrZW4gaW4gbGlnaHQgb2YgZXhwZWN0ZWQgb3V0Y29tZXMuIEZvciBleGFtcGxlLCB0aGVyZSB3aWxsIGJlIHRydWNrcyB0byBtb3ZlIGJpa2VzIGJldHdlZW4gZGlmZmVyZW50IGxvY2F0aW9ucy4gQWxzbywgc29tZSBpbmNlbnRpdmVzIHdpbGwgYmUgb2ZmZXJlZCBpZiByaWRlcnMgbWFuYWdlIHRvIG1vdmUgYSBiaWtlIGZyb20gcGxhY2UgdG8gcGxhY2UuDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KbGlicmFyeShkcGx5cikNCmBgYA0KDQpgYGB7ciBzZXR1cF8xMywgbWVzc2FnZT1GQUxTRSxpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHRpZ3JpcykNCmxpYnJhcnkodGlkeWNlbnN1cykNCmxpYnJhcnkodmlyaWRpcykNCmxpYnJhcnkocmllbSkNCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkoUlNvY3JhdGEpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdnYW5pbWF0ZSkNCmxpYnJhcnkoZ2lmc2tpKQ0KbGlicmFyeShGTk4pDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobWFncml0dHIpDQoNCnBsb3RUaGVtZSA8LSB0aGVtZSgNCiAgcGxvdC50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemU9MTIpLA0KICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9OCksDQogIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksDQogIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICMgU2V0IHRoZSBlbnRpcmUgY2hhcnQgcmVnaW9uIHRvIGJsYW5rDQogIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICBwbG90LmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICAjcGFuZWwuYm9yZGVyPWVsZW1lbnRfcmVjdChjb2xvdXI9IiNGMEYwRjAiKSwNCiAgIyBGb3JtYXQgdGhlIGdyaWQNCiAgcGFuZWwuZ3JpZC5tYWpvcj1lbGVtZW50X2xpbmUoY29sb3VyPSIjRDBEMEQwIixzaXplPS4yKSwNCiAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCkpDQoNCm1hcFRoZW1lIDwtIHRoZW1lKHBsb3QudGl0bGUgPWVsZW1lbnRfdGV4dChzaXplPTEyKSwNCiAgICAgICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksDQogICAgICAgICAgICAgICAgICBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICAgICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9saW5lKGNvbG91ciA9ICd0cmFuc3BhcmVudCcpLA0KICAgICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIiwgDQogICAgICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgICAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSwgJ2NtJyksDQogICAgICAgICAgICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMSwgImNtIiksIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDAuMiwgImNtIikpDQoNCnBhbGV0dGU3IDwtIGMoIiNGRkU2RUQiLCAiI0ZGQTdDNCIsICIjRkY3NTlGIiwgIiNCMTRBOTAiLCAiIzYyMkE4QyIsIiM0NTA3NUIiLCAiIzI2MDEzQyIpDQpwYWxldHRlNSA8LSBjKCIjRkZFNkVEIiwgIiNGRkE3QzQiLCAiI0ZGNzU5RiIsICIjQjE0QTkwIiwgIiM2MjJBOEMiKQ0KcGFsZXR0ZTQgPC0gYygiI0ZGRDlFNiIsICIjRkZBN0M0IiwgIiNGRjc1OUYiLCAiI0IxNEE5MCIpDQpwYWxldHRlMiA8LSBjKCIjRkZBN0M0IiwgIiNCMTRBOTAiKQ0KDQoNCm9wdGlvbnModGlncmlzX2NsYXNzID0gInNmIikNCnNvdXJjZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3VyYmFuU3BhdGlhbC9QdWJsaWMtUG9saWN5LUFuYWx5dGljcy1MYW5kaW5nL21hc3Rlci9mdW5jdGlvbnMuciIpDQoNCmBgYA0KDQpgYGB7ciBpbnN0YWxsX2NlbnN1c19BUElfa2V5LCB3YXJuaW5nID0gRkFMU0UsIGluY2x1ZGU9RkFMU0UsIGV2YWwgPSBUUlVFfQ0KIyBJbnN0YWxsIENlbnN1cyBBUEkgS2V5DQp0aWR5Y2Vuc3VzOjpjZW5zdXNfYXBpX2tleSgiYWNjNzg2NWJiYjc1ZDc0M2RhMzBiNGMxMjc4YjBkOTVjYjMwNjJkYiIsIG92ZXJ3cml0ZSA9IFRSVUUsIGluc3RhbGwgPSBUUlVFKQ0KYGBgDQoNCiMgRGF0YSBXcmFuZ2xpbmcNCg0KSW4gdGhpcyBhc3NpZ25tZW50LEkgZm9yZWNhc3Qgc3BhY2UvdGltZSBkZW1hbmQgZm9yIGJpa2Ugc2hhcmUgcGlja3VwcyBpbiBOZXcgWW9yayBDaXR5IGFuZCBkZXNpZ25lZCBhbiBhbGdvcml0aG0gdG8gaW5mb3JtIGEgYmlrZSByZS1iYWxhbmNpbmcgcGxhbi4NClRoZSBkYXRhIEkgdXNlIGhlcmUgaXMgb2J0YWluZWQgZnJvbSBbQ2l0aSBCaWtlIFRyaXAgRGF0YV0oaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3RyaXBkYXRhL2luZGV4Lmh0bWwpIHRoYXQgY29udGFpbnMgdGhlIGxhdGVzdCBtb250aGx5IHJlY29yZCBvZiBDaXRpIEJpa2UgdXNhZ2UgaW4gTmV3IFlvcmsgQ2l0eS4NCg0KTXkgbW9kZWwgd2lsbCB0YWtlIGEgbG93IHJlc29sdXRpb24gYXBwcm9hY2gsIHJlZHVjaW5nIG1pbGxpb25zIG9mIE5ZQyByaWRlIHNoYXJlIHRyaXBzIGZyb20gTWF5IHRocm91Z2ggSnVuZSwgMjAyMywgaW50byBhIDE1JSBzdWJzYW1wbGUgYW5kIGFnZ3JlZ2F0aW5nIHRvIGhvdXJseSBpbnRlcnZhbHMgYW5kIGEgc3Vic2V0IG9mIE5ldyBZb3JrIENpdHkgQ2Vuc3VzIHRyYWN0cy4NCg0KIyMgVHJpcCBEYXRhDQpgYGB7ciByZWFkX2RhdCwgaW5jbHVkZT1GQUxTRX0NCmRhdGE8LSByZWFkLmNzdigiRDovMDBQZW5uLeWtpuS5oC9NVVNBNTA4L211c2FfNTA4MF8yMDIzLW1haW4vSFc2X0Jpa2VTaGFyZS9kYXRhLzIwMjMwNS1jaXRpYmlrZS10cmlwZGF0YS5jc3YiKQ0KZGF0YSRzdGFydF9sYXQgPC0gYXMubnVtZXJpYyhkYXRhJHN0YXJ0X2xhdCkNCmRhdGEkc3RhcnRfbG5nIDwtIGFzLm51bWVyaWMoZGF0YSRzdGFydF9sbmcpDQpkYXRhJGVuZF9sYXQgPC0gYXMubnVtZXJpYyhkYXRhJGVuZF9sYXQpDQpkYXRhJGVuZF9sbmcgPC0gYXMubnVtZXJpYyhkYXRhJGVuZF9sbmcpDQoNCnNhbXBsaW5nX3JhdGUgPC0gMC4xNQ0Kc2FtcGxlX3NpemUgPC0gcm91bmQobnJvdyhkYXRhKSAqIHNhbXBsaW5nX3JhdGUpDQoNCmRhdCA8LSBkYXRhLmZyYW1lKCkNCndoaWxlIChucm93KGRhdCkgPCBzYW1wbGVfc2l6ZSkgew0KICBiYXRjaCA8LSBkYXRhICU+JQ0KICAgIHNhbXBsZV9uKHNpemUgPSBtaW4oc2FtcGxlX3NpemUgLSBucm93KGRhdCksIG5yb3coZGF0YSkpKQ0KICBkYXQgPC0gYmluZF9yb3dzKGRhdCwgYmF0Y2gpDQp9DQoNCmRhdCA8LSBkYXQgJT4lDQogIGZpbHRlcihyaWRlYWJsZV90eXBlID09ICJjbGFzc2ljX2Jpa2UiKQ0KDQpkYXQyIDwtIGRhdCAlPiUNCiAgbXV0YXRlKGludGVydmFsNjAgPSBmbG9vcl9kYXRlKHltZF9obXMoc3RhcnRlZF9hdCksIHVuaXQgPSAiaG91ciIpLA0KICAgICAgICAgaW50ZXJ2YWwxNSA9IGZsb29yX2RhdGUoeW1kX2htcyhlbmRlZF9hdCksIHVuaXQgPSAiMTUgbWlucyIpLA0KICAgICAgICAgd2VlayA9IHdlZWsoaW50ZXJ2YWw2MCksDQogICAgICAgICBkb3R3ID0gd2RheShpbnRlcnZhbDYwLCBsYWJlbD1UUlVFKSkNCg0Kcm0oZGF0YSkNCnJtKGRhdCkNCg0KbnJvdyhkYXQyKQ0KZ2xpbXBzZShkYXQyKQ0KDQpgYGANCg0KDQojIyBDZW5zdXMgRGF0YQ0KDQpTZXZlcmFsIGNlbnN1cyBnZW9ncmFwaHkgYW5kIHZhcmlhYmxlcyBhcmUgbG9hZGVkIGFuZCB3cmFuZ2xlZCB0byB0ZXN0IGdlbmVyYWxpemFiaWxpdHkgbGF0ZXIuIEFtb25nIHRoZW0sIHRoZXJlIGFyZSBQb3B1bGF0aW9uLCBSYWNlLCBNZWFucyBvZiBUcmFuc3BvcnQsIE1lYW4gQ29tbXV0ZSBUaW1lLCAlIG9mIHRha2luZyBwdWJsaWMgdHJhbnNpdCwgZXRjLg0KDQpgYGB7ciBnZXRfY2Vuc3VzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFLCBpbmNsdWRlPUZBTFNFfQ0KTllDZW5zdXMgPC0gDQogIGdldF9hY3MoZ2VvZ3JhcGh5ID0gInRyYWN0IiwgDQogICAgICAgICAgdmFyaWFibGVzID0gYygiQjAxMDAzXzAwMSIsICJCMTkwMTNfMDAxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAiQjAyMDAxXzAwMiIsICJCMDgwMTNfMDAxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJCMDgwMTJfMDAxIiwgIkIwODMwMV8wMDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICJCMDgzMDFfMDEwIiwgIkIwMTAwMl8wMDEiKSwgDQogICAgICAgICAgeWVhciA9IDIwMjEsIA0KICAgICAgICAgIHN0YXRlID0gIk5ZIiwgDQogICAgICAgICAgZ2VvbWV0cnkgPSBUUlVFLCANCiAgICAgICAgICBjb3VudHk9YygnTmV3IFlvcmsnKSwNCiAgICAgICAgICBvdXRwdXQgPSAid2lkZSIpICU+JQ0KICByZW5hbWUoVG90YWxfUG9wID0gIEIwMTAwM18wMDFFLA0KICAgICAgICAgTWVkX0luYyA9IEIxOTAxM18wMDFFLA0KICAgICAgICAgTWVkX0FnZSA9IEIwMTAwMl8wMDFFLA0KICAgICAgICAgV2hpdGVfUG9wID0gQjAyMDAxXzAwMkUsDQogICAgICAgICBUcmF2ZWxfVGltZSA9IEIwODAxM18wMDFFLA0KICAgICAgICAgTnVtX0NvbW11dGVycyA9IEIwODAxMl8wMDFFLA0KICAgICAgICAgTWVhbnNfb2ZfVHJhbnNwb3J0ID0gQjA4MzAxXzAwMUUsDQogICAgICAgICBUb3RhbF9QdWJsaWNfVHJhbnMgPSBCMDgzMDFfMDEwRSkgJT4lDQogIHNlbGVjdChUb3RhbF9Qb3AsIE1lZF9JbmMsIFdoaXRlX1BvcCwgVHJhdmVsX1RpbWUsDQogICAgICAgICBNZWFuc19vZl9UcmFuc3BvcnQsIFRvdGFsX1B1YmxpY19UcmFucywNCiAgICAgICAgIE1lZF9BZ2UsDQogICAgICAgICBHRU9JRCwgZ2VvbWV0cnkpICU+JQ0KICBtdXRhdGUoUGVyY2VudF9XaGl0ZSA9IFdoaXRlX1BvcCAvIFRvdGFsX1BvcCwNCiAgICAgICAgIE1lYW5fQ29tbXV0ZV9UaW1lID0gVHJhdmVsX1RpbWUgLyBUb3RhbF9QdWJsaWNfVHJhbnMsDQogICAgICAgICBQZXJjZW50X1Rha2luZ19QdWJsaWNfVHJhbnMgPSBUb3RhbF9QdWJsaWNfVHJhbnMgLyBNZWFuc19vZl9UcmFuc3BvcnQpDQpgYGANCg0KYGBge3IgZXh0cmFjdF9nZW9tZXRyaWVzLCBpbmNsdWRlPUZBTFNFfQ0KTllUcmFjdHMgPC0gDQogIE5ZQ2Vuc3VzICU+JQ0KICBhcy5kYXRhLmZyYW1lKCkgJT4lDQogIGRpc3RpbmN0KEdFT0lELCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgc2VsZWN0KEdFT0lELCBnZW9tZXRyeSkgJT4lIA0KICBzdF9zZg0KYGBgDQoNCmBgYHtyIGFkZF9jZW5zdXNfdHJhY3RzLHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpkYXRfY2Vuc3VzIDwtIHN0X2pvaW4oZGF0MiAlPiUgDQogICAgICAgICAgZmlsdGVyKGlzLm5hKHN0YXJ0X2xuZykgPT0gRkFMU0UgJg0KICAgICAgICAgICAgICAgICAgIGlzLm5hKHN0YXJ0X2xhdCkgPT0gRkFMU0UgJg0KICAgICAgICAgICAgICAgICAgIGlzLm5hKGVuZF9sYXQpID09IEZBTFNFICYNCiAgICAgICAgICAgICAgICAgICBpcy5uYShlbmRfbG5nKSA9PSBGQUxTRSkgJT4lDQogICAgICAgICAgc3RfYXNfc2YoLiwgY29vcmRzID0gYygic3RhcnRfbG5nIiwgInN0YXJ0X2xhdCIpLCBjcnMgPSA0MzI2KSwNCiAgICAgICAgTllUcmFjdHMgJT4lDQogICAgICAgICAgc3RfdHJhbnNmb3JtKGNycz00MzI2KSwNCiAgICAgICAgam9pbj1zdF9pbnRlcnNlY3RzLA0KICAgICAgICAgICAgICBsZWZ0ID0gVFJVRSkgJT4lDQogIHJlbmFtZShPcmlnaW4uVHJhY3QgPSBHRU9JRCkgJT4lDQogIG11dGF0ZShzdGFydF9sbmcgPSB1bmxpc3QobWFwKGdlb21ldHJ5LCAxKSksDQogICAgICAgICBzdGFydF9sYXQgPSB1bmxpc3QobWFwKGdlb21ldHJ5LCAyKSkpJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgDQogIHNlbGVjdCgtZ2VvbWV0cnkpJT4lDQogIHN0X2FzX3NmKC4sIGNvb3JkcyA9IGMoImVuZF9sbmciLCAiZW5kX2xhdCIpLCBjcnMgPSA0MzI2KSAlPiUNCiAgc3Rfam9pbiguLCBOWVRyYWN0cyAlPiUNCiAgICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnM9NDMyNiksDQogICAgICAgICAgam9pbj1zdF9pbnRlcnNlY3RzLA0KICAgICAgICAgIGxlZnQgPSBUUlVFKSAlPiUNCiAgcmVuYW1lKERlc3RpbmF0aW9uLlRyYWN0ID0gR0VPSUQpICAlPiUNCiAgbXV0YXRlKGVuZF9sbmcgPSB1bmxpc3QobWFwKGdlb21ldHJ5LCAxKSksDQogICAgICAgICBlbmRfbGF0ID0gdW5saXN0KG1hcChnZW9tZXRyeSwgMikpKSU+JQ0KICBmaWx0ZXIoc3Vic3RyKE9yaWdpbi5UcmFjdCwgMSwgNikgPT0gIjM2MDYxMCIpICU+JQ0KICBmaWx0ZXIoc3Vic3RyKERlc3RpbmF0aW9uLlRyYWN0LCAxLCA2KSA9PSAiMzYwNjEwIikgJT4lDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUNCiAgc2VsZWN0KC1nZW9tZXRyeSkNCmBgYA0KDQojIyBXZWF0aGVyIERhdGENCg0KRnVydGhlcm1vcmUsIEkgaGF2ZSBpbmNvcnBvcmF0ZWQgd2VhdGhlciBkYXRhIGZyb20gSkZLIEFpcnBvcnQgaW50byBteSBhbmFseXNpcy4gVG8gYmUgc3BlY2lmaWMsIEkgaW1wb3J0ZWQgaG91cmx5IGRhdGEgcmVsYXRlZCB0byB0ZW1wZXJhdHVyZSwgd2luZCBzcGVlZCwgYW5kIHByZWNpcGl0YXRpb24uIEkgaGF2ZSBhbHNvIGNyZWF0ZWQgdmlzdWFsaXphdGlvbnMgdG8gaWxsdXN0cmF0ZSB0aGUgdHJlbmRzIGluIHRlbXBlcmF0dXJlIGFuZCBwcmVjaXBpdGF0aW9uIHRocm91Z2hvdXQgdGhlIGR1cmF0aW9uIG9mIG15IHN0dWR5IHBlcmlvZC4NCg0KYGBge3IgaW1wb3J0X3dlYXRoZXIsIHdhcm5pbmc9RkFMU0V9DQp3ZWF0aGVyLlBhbmVsIDwtIA0KICByaWVtX21lYXN1cmVzKHN0YXRpb24gPSAiSkZLIiwgZGF0ZV9zdGFydCA9ICIyMDIzLTA1LTAxIiwgZGF0ZV9lbmQgPSAiMjAyMy0wNS0zMSIpICU+JQ0KICBkcGx5cjo6c2VsZWN0KHZhbGlkLCB0bXBmLCBwMDFpLCBza250KSU+JQ0KICByZXBsYWNlKGlzLm5hKC4pLCAwKSAlPiUNCiAgICBtdXRhdGUoaW50ZXJ2YWw2MCA9IHltZF9oKHN1YnN0cih2YWxpZCwxLDEzKSkpICU+JQ0KICAgIG11dGF0ZSh3ZWVrID0gd2VlayhpbnRlcnZhbDYwKSwNCiAgICAgICAgICAgZG90dyA9IHdkYXkoaW50ZXJ2YWw2MCwgbGFiZWw9VFJVRSkpICU+JQ0KICAgIGdyb3VwX2J5KGludGVydmFsNjApICU+JQ0KICAgIHN1bW1hcml6ZShUZW1wZXJhdHVyZSA9IG1heCh0bXBmKSwNCiAgICAgICAgICAgICAgUHJlY2lwaXRhdGlvbiA9IHN1bShwMDFpKSwNCiAgICAgICAgICAgICAgV2luZF9TcGVlZCA9IG1heChza250KSkgJT4lDQogICAgbXV0YXRlKFRlbXBlcmF0dXJlID0gaWZlbHNlKFRlbXBlcmF0dXJlID09IDAsIDQyLCBUZW1wZXJhdHVyZSkpDQoNCmdsaW1wc2Uod2VhdGhlci5QYW5lbCkNCmBgYA0KDQpgYGB7ciBwbG90X3dlYXRoZXIsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTgsd2FybmluZz1GQUxTRX0NCmdyaWQuYXJyYW5nZSgNCiAgZ2dwbG90KHdlYXRoZXIuUGFuZWwsIGFlcyhpbnRlcnZhbDYwLFByZWNpcGl0YXRpb24pKSArIGdlb21fbGluZShjb2xvcj0iI0ZGNzU5RiIpICsgDQogIGxhYnModGl0bGU9IlBlcmNpcGl0YXRpb24iLCB4PSJIb3VyIiwgeT0iUGVyZWNpcGl0YXRpb24iKSArIHBsb3RUaGVtZSgpLA0KICBnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsV2luZF9TcGVlZCkpICsgZ2VvbV9saW5lKGNvbG9yPSIjRkY3NTlGIikgKyANCiAgICBsYWJzKHRpdGxlPSJXaW5kIFNwZWVkIiwgeD0iSG91ciIsIHk9IldpbmQgU3BlZWQiKSArIHBsb3RUaGVtZSgpLA0KICBnZ3Bsb3Qod2VhdGhlci5QYW5lbCwgYWVzKGludGVydmFsNjAsVGVtcGVyYXR1cmUpKSArIGdlb21fbGluZShjb2xvcj0iI0ZGNzU5RiIpICsgDQogICAgbGFicyh0aXRsZT0iVGVtcGVyYXR1cmUiLCB4PSJIb3VyIiwgeT0iVGVtcGVyYXR1cmUiKSArIHBsb3RUaGVtZSgpLA0KICB0b3A9IldlYXRoZXIgRGF0YSAtIE5ZQyBKRksgLSBNYXksIDIwMjMiKQ0KYGBgDQoNCg0KIyMgQW1lbml0eSBEYXRhDQoNCkluIGFkZGl0aW9uLCBJIGluY29ycG9yYXRlZCBhbWVuaXR5IGRhdGEgaW50byBteSBhbmFseXNpcywgYXMgaXQgaGFzIHRoZSBwb3RlbnRpYWwgdG8gc2lnbmlmaWNhbnRseSBpbXBhY3QgdGhlIGJpa2UgcmUtYmFsYW5jaW5nIHByb2Nlc3MuIEZvciBpbnN0YW5jZSwgdGhlIHByb3hpbWl0eSBvZiB2YXJpb3VzIHBvaW50cyBvZiBpbnRlcmVzdCBzdWNoIGFzIGxhbmRtYXJrcywgbWFya2V0cywgYnVzIHN0YXRpb25zLCBhbmQgY29sbGVnZXMgY2FuIGluZmx1ZW5jZSB0aGUgZGVtYW5kIGZvciBzaGFyZWQgYmlrZXMuIFRoZXJlZm9yZSwgSSBpbmNsdWRlZCB0aGVzZSBhbWVuaXR5IGZlYXR1cmVzIGFzIHZhcmlhYmxlcyBpbiBteSBhbmFseXNpcy4gVG8gZnVydGhlciByZWZpbmUgdGhlIGFuYWx5c2lzLCBJIGVtcGxveWVkIHRoZSBrLW5lYXJlc3QgbmVpZ2hib3IgKGs9MSkgbWV0aG9kIHRvIGNhbGN1bGF0ZSB0aGUgbmVhcmVzdCBsYW5kbWFyaywgbWFya2V0LCBidXMgc3RhdGlvbiwgYW5kIGNvbGxlZ2UgZm9yIGVhY2ggYmlrZSBzdGF0aW9uLiBUaGlzIGhlbHBzIHRvIGFjY291bnQgZm9yIHRoZSBpbmZsdWVuY2Ugb2YgdGhlc2UgYW1lbml0aWVzIG9uIGJpa2Ugc3RhdGlvbiB1c2FnZSBhbmQgcmUtYmFsYW5jaW5nIHN0cmF0ZWdpZXMuDQoNCmBgYHtyIGltcG9ydF9hbWVuaXR5LCAgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCk1hcmtldHMgPC0gc3RfcmVhZCgiaHR0cHM6Ly9kYXRhLmNpdHlvZm5ld3lvcmsudXMvcmVzb3VyY2UvOHZ3ay02aXoyLmdlb2pzb24iKSAlPiUNCiAgZmlsdGVyKGJvcm91Z2ggPT0gIk1hbmhhdHRhbiIpICU+JQ0KICBzZWxlY3QobWFya2V0bmFtZSxsYXRpdHVkZSxsb25naXR1ZGUsZ2VvbWV0cnkpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIHN0X3RyYW5zZm9ybShjcnM9NDMyNikNCg0KQ29sbGVnZSA8LSBzdF9yZWFkKCJEOi8wMFBlbm4t5a2m5LmgL01VU0E1MDgvbXVzYV81MDgwXzIwMjMtbWFpbi9IVzZfQmlrZVNoYXJlL2RhdGEvQ29sbGVnZXMgYW5kIFVuaXZlcnNpdGllcy5nZW9qc29uIikgJT4lDQogIGZpbHRlcihjaXR5ID09ICJOZXcgWW9yayIpICU+JQ0KICBzZWxlY3QobmFtZSxnZW9tZXRyeSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgc3RfdHJhbnNmb3JtKGNycz00MzI2KQ0KDQpMYW5kbWFya3MgPC0gc3RfcmVhZCgiRDovMDBQZW5uLeWtpuS5oC9NVVNBNTA4L211c2FfNTA4MF8yMDIzLW1haW4vSFc2X0Jpa2VTaGFyZS9kYXRhL0luZGl2aWR1YWwgTGFuZG1hcmsgU2l0ZXMuZ2VvanNvbiIpICU+JQ0KICBmaWx0ZXIoYm9yb3VnaCA9PSAiTU4iKSAlPiUNCiAgc2VsZWN0KGxwY19uYW1lLGdlb21ldHJ5KSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBzdF90cmFuc2Zvcm0oY3JzPTQzMjYpDQoNCkJ1c19TdGF0aW9ucyA8LSBzdF9yZWFkKCJEOi8wMFBlbm4t5a2m5LmgL01VU0E1MDgvbXVzYV81MDgwXzIwMjMtbWFpbi9IVzZfQmlrZVNoYXJlL2RhdGEvQnVzIFN0b3AgU2hlbHRlcnMuZ2VvanNvbiIpICU+JQ0KICBmaWx0ZXIoYm9yb19uYW1lID09ICJNYW5oYXR0YW4iKSAlPiUNCiAgc2VsZWN0KHNoZWx0ZXJfaWQsbGF0aXR1ZGUsbG9uZ2l0dWRlLGdlb21ldHJ5KSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBzdF90cmFuc2Zvcm0oY3JzPTQzMjYpDQoNCkxhbmRtYXJrcy5zZiA8LSBzdF9jZW50cm9pZChMYW5kbWFya3MpDQpgYGANCg0KYGBge3Iga25uLCBpbmNsdWRlPUZBTFNFfQ0KDQphbWVuaXR5X25uIDwtIGRhdDIgJT4lDQogIHN0X2FzX3NmKGNvb3JkcyA9Yygic3RhcnRfbG5nIiwic3RhcnRfbGF0IiksY3JzPTQzMjYpIA0KDQpzdF9jIDwtIHN0X2Nvb3JkaW5hdGVzDQoNCmFtZW5pdHlfbm4gPC0gYW1lbml0eV9ubiAlPiUNCiAgbXV0YXRlKA0KICAgIExhbmRtYXJrcy5ubiA9DQogICAgICBubl9mdW5jdGlvbihzdF9jKGFtZW5pdHlfbm4pLCBzdF9jKExhbmRtYXJrcy5zZiksMSksDQogICAgTWFya2V0cy5ubiA9IA0KICAgICAgbm5fZnVuY3Rpb24oc3RfYyhhbWVuaXR5X25uKSwgc3RfYyhNYXJrZXRzKSwxKSwNCiAgICBCdXNfU3RhdGlvbnMubm4gPSANCiAgICAgIG5uX2Z1bmN0aW9uKHN0X2MoYW1lbml0eV9ubiksIHN0X2MoQnVzX1N0YXRpb25zKSwxKSwNCiAgICBDb2xsZWdlLm5uID0NCiAgICAgIG5uX2Z1bmN0aW9uKHN0X2MoYW1lbml0eV9ubiksIHN0X2MoQ29sbGVnZSksMSksDQogICAgKQ0KDQphbWVuaXR5X25uIDwtDQogIGFtZW5pdHlfbm4gJT4lDQogIGRwbHlyOjpzZWxlY3Qoc3RhcnRfc3RhdGlvbl9pZCwgZW5kX3N0YXRpb25faWQsIExhbmRtYXJrcy5ubiwgTWFya2V0cy5ubiwgQnVzX1N0YXRpb25zLm5uLCBDb2xsZWdlLm5uLCBpbnRlcnZhbDYwLCBpbnRlcnZhbDE1LCB3ZWVrLCBkb3R3KQ0KDQpgYGANCg0KDQojIyBTcGFjZS1UaW1lIFBhbmVsDQoNCkkgY3JlYXRlZCBhIGRhdGEgZnJhbWUgcGFuZWwgd2hpY2ggaGFzIGVhY2ggdW5pcXVlIHNwYWNlL3RpbWUgb2JzZXJ2YXRpb25zLiBUaGVuIHRoZSB0cmlwIGNvdW50cyB3ZXJlIHN1bW1hcml6ZWQgYnkgc3RhdGlvbiBmb3IgZWFjaCB0aW1lIGludGVydmFsLiBBbHNvLCB0aGUgc29jaW8tZWNvbm9taWMgaW5mb3JtYXRpb24gYW5kIGxhdGl0dWRlL2xvbmdpdHVkZSBpbmZvcm1hdGlvbiB3ZXJlIGFsc28ga2VwdCBmb3IgZnV0dXJlIGRhdGEgaW50ZWdyYXRpb24gYW5kIGFuYWx5c2lzLg0KDQpgYGB7ciBwYW5lbF9sZW5ndGhfY2hlY2sgLHdhcm5pbmcgPSBGQUxTRX0NCmxlbmd0aCh1bmlxdWUoZGF0X2NlbnN1cyRpbnRlcnZhbDYwKSkgKiBsZW5ndGgodW5pcXVlKGRhdF9jZW5zdXMkc3RhcnRfc3RhdGlvbl9pZCkpDQoNCg0Kc3R1ZHkucGFuZWwgPC0gDQogIGV4cGFuZC5ncmlkKGludGVydmFsNjA9dW5pcXVlKGRhdF9jZW5zdXMkaW50ZXJ2YWw2MCksIA0KICAgICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gdW5pcXVlKGRhdF9jZW5zdXMkc3RhcnRfc3RhdGlvbl9pZCkpICU+JQ0KICBsZWZ0X2pvaW4oLiwgZGF0X2NlbnN1cyAlPiUNCiAgICAgICAgICAgICAgc2VsZWN0KHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X3N0YXRpb25fbmFtZSwgT3JpZ2luLlRyYWN0LCBzdGFydF9sbmcsIHN0YXJ0X2xhdCApJT4lDQogICAgICAgICAgICAgIGRpc3RpbmN0KCkgJT4lDQogICAgICAgICAgICAgIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25faWQpICU+JQ0KICAgICAgICAgICAgICBzbGljZSgxKSkgJT4lDQogIGxlZnRfam9pbiguLGFtZW5pdHlfbm4gJT4lDQogICAgICAgICAgICAgIHNlbGVjdChzdGFydF9zdGF0aW9uX2lkLCBMYW5kbWFya3Mubm4sIE1hcmtldHMubm4sIEJ1c19TdGF0aW9ucy5ubiwgQ29sbGVnZS5ubiklPiUNCiAgICAgICAgICAgICAgZGlzdGluY3QoKSAlPiUNCiAgICAgICAgICAgICAgZ3JvdXBfYnkoc3RhcnRfc3RhdGlvbl9pZCkgJT4lDQogICAgICAgICAgICAgIHNsaWNlKDEpKQ0KDQpucm93KHN0dWR5LnBhbmVsKSAgICAgIA0KYGBgDQoNCmBgYHtyIGNyZWF0ZV9wYW5lbCwgaW5jbHVkZT1GQUxTRX0NCnJpZGUucGFuZWwgPC0gDQogIGRhdF9jZW5zdXMgJT4lDQogIG11dGF0ZShUcmlwX0NvdW50ZXIgPSAxKSAlPiUNCiAgcmlnaHRfam9pbihzdHVkeS5wYW5lbCkgJT4lIA0KICBncm91cF9ieShpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9zdGF0aW9uX25hbWUsIE9yaWdpbi5UcmFjdCwgc3RhcnRfbG5nLCBzdGFydF9sYXQsIExhbmRtYXJrcy5ubiwgTWFya2V0cy5ubiwgQnVzX1N0YXRpb25zLm5uLCBDb2xsZWdlLm5uKSAlPiUNCiAgc3VtbWFyaXplKFRyaXBfQ291bnQgPSBzdW0oVHJpcF9Db3VudGVyLCBuYS5ybT1UKSkgJT4lDQogIGxlZnRfam9pbih3ZWF0aGVyLlBhbmVsKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBmaWx0ZXIoaXMubmEoc3RhcnRfc3RhdGlvbl9pZCkgPT0gRkFMU0UpICU+JQ0KICBtdXRhdGUod2VlayA9IHdlZWsoaW50ZXJ2YWw2MCksDQogICAgICAgICBkb3R3ID0gd2RheShpbnRlcnZhbDYwLCBsYWJlbCA9IFRSVUUpKSAlPiUNCiAgZmlsdGVyKGlzLm5hKE9yaWdpbi5UcmFjdCkgPT0gRkFMU0UpIA0KYGBgDQoNCmBgYHtyIGNlbnN1c19hbmRfcGFuZWwsaW5jbHVkZT1GQUxTRX0NCnJpZGUucGFuZWwgPC0gDQogIGxlZnRfam9pbihyaWRlLnBhbmVsLCBOWUNlbnN1cyAlPiUNCiAgICAgICAgICAgICAgYXMuZGF0YS5mcmFtZSgpICU+JQ0KICAgICAgICAgICAgICBzZWxlY3QoLWdlb21ldHJ5KSwgYnkgPSBjKCJPcmlnaW4uVHJhY3QiID0gIkdFT0lEIikpIA0KYGBgDQoNCmBgYHtyIHRyYWluX3Rlc3QwLCBpbmNsdWRlPUZBTFNFfQ0KcmlkZS5UcmFpbiA8LSBmaWx0ZXIocmlkZS5wYW5lbCwgd2VlayA+PSAyMCkNCnJpZGUuVGVzdCA8LSBmaWx0ZXIocmlkZS5wYW5lbCwgd2VlayA8IDIwKQ0KYGBgDQoNCiMjIFRpbWUgTGFncw0KDQpNb3Jlb3ZlciwgdGltZSBsYWcgdmFyaWFibGVzIGFib3V0IHRoZSBkZW1hbmQgZHVyaW5nIGEgZ2l2ZW4gdGltZSBwZXJpb2QgYXJlIGFsc28gYWRkZWQuIGJ5IGV2YWx1YXRpbmcgdGhlIGNvcnJlbGF0aW9ucyBpbiB0aGUgbGFncywgd2UgY2FuIHRlbGwgdGhhdCBzb21lIG9mIHRoZSBsYWdzIGFyZSBwcmV0dHkgc3Ryb25nLiBGb3IgZXhhbXBsZSwgdGhlcmUncyBhIFBlYXJzb24ncyBSIG9mIDAuODcgYW5kIDAuODYgZm9yIHRoZSBgbGFnSG91cmAgYW5kIGBsYWcxZGF5YCByZXNwZWN0aXZlbHksIGluZGljYXRpbmcgdGhhdCB0aGUgZGVtYW5kIGZvciBhbiBob3VyIGFnbyBhbmQgYSBkYXkgYWdvIGlzIHN0cm9uZ2x5IGNvcnJlbGF0ZWQgd2l0aCB0aGUgZGVtYW5kIG5vdy4gSG93ZXZlciwgdGhlIDEyLWhvdXIgbGFnIGV4aGliaXRzIGFuIG9wcG9zaXRlIHJlbGF0aW9uc2hpcCBpbiB0ZXJtcyBvZiBkZW1hbmQuDQpgYGB7ciB0aW1lX2xhZ3MsaW5jbHVkZT1GQUxTRX0NCnJpZGUucGFuZWwgPC0gDQogIHJpZGUucGFuZWwgJT4lIA0KICBhcnJhbmdlKHN0YXJ0X3N0YXRpb25faWQsIGludGVydmFsNjApICU+JSANCiAgbXV0YXRlKGxhZ0hvdXIgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMSksDQogICAgICAgICBsYWcySG91cnMgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMiksDQogICAgICAgICBsYWczSG91cnMgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMyksDQogICAgICAgICBsYWc0SG91cnMgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsNCksDQogICAgICAgICBsYWcxMkhvdXJzID0gZHBseXI6OmxhZyhUcmlwX0NvdW50LDEyKSwNCiAgICAgICAgIGxhZzFkYXkgPSBkcGx5cjo6bGFnKFRyaXBfQ291bnQsMjQpLA0KICAgICAgICAgaG9saWRheSA9IGlmZWxzZSh5ZGF5KGludGVydmFsNjApID09IDE0OSwxLDApKSAlPiUNCiAgIG11dGF0ZShkYXkgPSB5ZGF5KGludGVydmFsNjApKSAlPiUNCiAgIG11dGF0ZShob2xpZGF5TGFnID0gY2FzZV93aGVuKGRwbHlyOjpsYWcoaG9saWRheSwgMSkgPT0gMSB+ICJQbHVzT25lRGF5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpsYWcoaG9saWRheSwgMikgPT0gMSB+ICJQbHVzdFR3b0RheXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmxhZyhob2xpZGF5LCAzKSA9PSAxIH4gIlBsdXN0VGhyZWVEYXlzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpsZWFkKGhvbGlkYXksIDEpID09IDEgfiAiTWludXNPbmVEYXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmxlYWQoaG9saWRheSwgMikgPT0gMSB+ICJNaW51c1R3b0RheXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OmxlYWQoaG9saWRheSwgMykgPT0gMSB+ICJNaW51c1RocmVlRGF5cyIpLA0KICAgICAgICAgaG9saWRheUxhZyA9IGlmZWxzZShpcy5uYShob2xpZGF5TGFnKSA9PSBUUlVFLCAwLCBob2xpZGF5TGFnKSkgDQoNCmBgYA0KDQpgYGB7ciBldmFsdWF0ZV9sYWdzLCBlY2hvPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQphcy5kYXRhLmZyYW1lKHJpZGUucGFuZWwpICU+JQ0KICAgIGdyb3VwX2J5KGludGVydmFsNjApICU+JSANCiAgICBzdW1tYXJpc2VfYXQodmFycyhzdGFydHNfd2l0aCgibGFnIiksICJUcmlwX0NvdW50IiksIG1lYW4sIG5hLnJtID0gVFJVRSkgJT4lDQogICAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLWludGVydmFsNjAsIC1UcmlwX0NvdW50KSAlPiUNCiAgICBtdXRhdGUoVmFyaWFibGUgPSBmYWN0b3IoVmFyaWFibGUsIGxldmVscz1jKCJsYWdIb3VyIiwibGFnMkhvdXJzIiwibGFnM0hvdXJzIiwibGFnNEhvdXJzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsYWcxMkhvdXJzIiwibGFnMWRheSIpKSklPiUNCiAgICBncm91cF9ieShWYXJpYWJsZSkgJT4lICANCiAgICBzdW1tYXJpemUoY29ycmVsYXRpb24gPSByb3VuZChjb3IoVmFsdWUsIFRyaXBfQ291bnQpLDIpKQ0KYGBgDQoNCiMgRXhwbG9yYXRvcnkgQW5hbHlzaXMNCg0KIyMgU2VyaWFsIEF1dG9jb3JyZWxhdGlvbg0KDQpJIGJlZ2luIGJ5IGV4YW1pbmluZyB0aGUgdGltZSBhbmQgZnJlcXVlbmN5IGNvbXBvbmVudHMgb2YgdGhlIGRhdGEuIEZpcnN0LCBmcm9tIHRoZSBvdmVyYWxsIHRpbWUgcGF0dGVybiAtIHRoZXJlIGlzIGNsZWFybHkgYSBkYWlseSBwZXJpb2RpY2l0eSBhbmQgdGhlcmUgYXJlIGx1bGwgcGVyaW9kcyBvbiB3ZWVrZW5kcy4gQWxzbywgdGhlIHdlZWtlbmQgbmVhciB0aGUgMjJ0aCBvZiBNYXkgZG9lc24ndCBoYXZlIHRoZSBzYW1lIGRpcCBpbiBhY3Rpdml0eSBkdWUgdG8gdGhlIGV4dHJlbWUgd2VhdGhlci4NCg0KYGBge3IgdHJpcF90aW1lc2VyaWVzLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00fQ0KZ2dwbG90KGRhdF9jZW5zdXMgJT4lDQogICAgICAgICBncm91cF9ieShpbnRlcnZhbDYwKSAlPiUNCiAgICAgICAgIHRhbGx5KCkpKw0KICBnZW9tX2xpbmUoYWVzKHggPSBpbnRlcnZhbDYwLCB5ID0gbiksY29sb3I9IiM2MjJBOEMiKSsNCiAgbGFicyh0aXRsZT0iQmlrZSBzaGFyZSB0cmlwcyBwZXIgaHIuIE5ldyBZb3JrIENpdHksIE1heSwgMjAyMyIsDQogICAgICAgeD0iRGF0ZSIsIA0KICAgICAgIHk9Ik51bWJlciBvZiB0cmlwcyIpKw0KICBwbG90VGhlbWUoKQ0KYGBgDQoNCkJ5IGV4YW1pbmluZyB0aGUgZGlzdHJpYnV0aW9uIG9mIHRyaXAgdm9sdW1lIGJ5IHN0YXRpb24gZm9yIGRpZmZlcmVudCB0aW1lcyBvZiB0aGUgZGF5LCBpdCdzIGNsZWFyIHRoYXQgdGhlcmUgYXJlIGEgZmV3IGhpZ2ggdm9sdW1lIHBlcmlvZHMgYnV0IG1vc3RseSBsb3cgdm9sdW1lLg0KYGBge3IgbWVhbl90cmlwc19oaXN0LCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0X2NlbnN1cyAlPiUNCiAgICAgICAgbXV0YXRlKHRpbWVfb2ZfZGF5ID0gY2FzZV93aGVuKGhvdXIoaW50ZXJ2YWw2MCkgPCA3IHwgaG91cihpbnRlcnZhbDYwKSA+IDE5IH4gIk92ZXJuaWdodCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDcgJiBob3VyKGludGVydmFsNjApIDwgMTAgfiAiQU0gUnVzaCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDEwICYgaG91cihpbnRlcnZhbDYwKSA8IDE1IH4gIk1pZC1EYXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxNSAmIGhvdXIoaW50ZXJ2YWw2MCkgPD0gMTkgfiAiUE0gUnVzaCIpKSU+JQ0KICAgICAgICAgZ3JvdXBfYnkoaW50ZXJ2YWw2MCwgc3RhcnRfc3RhdGlvbl9uYW1lLCB0aW1lX29mX2RheSkgJT4lDQogICAgICAgICB0YWxseSgpJT4lDQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25fbmFtZSwgdGltZV9vZl9kYXkpJT4lDQogIHN1bW1hcml6ZShtZWFuX3RyaXBzID0gbWVhbihuKSklPiUNCiAgZ2dwbG90KCkrDQogIGdlb21faGlzdG9ncmFtKGFlcyhtZWFuX3RyaXBzKSwgYmlud2lkdGggPSAxLGZpbGw9IiNGRkE3QzQiKSsNCiAgbGFicyh0aXRsZT0iTWVhbiBOdW1iZXIgb2YgSG91cmx5IFRyaXBzIFBlciBTdGF0aW9uLiBOZXcgWW9yayBDaXR5LCBNYXksIDIwMjMiLA0KICAgICAgIHg9Ik51bWJlciBvZiB0cmlwcyIsIA0KICAgICAgIHk9IkZyZXF1ZW5jeSIpKw0KICBmYWNldF93cmFwKH50aW1lX29mX2RheSkrDQogIHBsb3RUaGVtZSgpDQpgYGANCg0KYGBge3IgdHJpcHNfc3RhdGlvbl9kb3R3LCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00fQ0KZ2dwbG90KGRhdF9jZW5zdXMgJT4lDQogICAgICAgICBncm91cF9ieShpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX25hbWUpICU+JQ0KICAgICAgICAgdGFsbHkoKSkrDQogIGdlb21faGlzdG9ncmFtKGFlcyhuKSwgYmlud2lkdGggPSA1LGZpbGw9IiNGRkE3QzQiKSsNCiAgbGFicyh0aXRsZT0iQmlrZSBzaGFyZSB0cmlwcyBwZXIgaHIgYnkgc3RhdGlvbi4gTmV3IFlvcmsgQ2l0eSwgTWF5LCAyMDIzIiwNCiAgICAgICB4PSJUcmlwIENvdW50cyIsIA0KICAgICAgIHk9Ik51bWJlciBvZiBTdGF0aW9ucyIpKw0KICBwbG90VGhlbWUoKQ0KYGBgDQoNCg0KSSd2ZSBhbHNvIGFuYWx5emVkIHRoZSBkYWlseSB0cmVuZHMgaW4gcmlkZXJzaGlwLCBkaWZmZXJlbnRpYXRpbmcgYmV0d2VlbiBkYXlzIG9mIHRoZSB3ZWVrIGFuZCBkaXN0aW5ndWlzaGluZyBiZXR3ZWVuIHdlZWtlbmRzIGFuZCB3ZWVrZGF5cy4gVGhlIHRlbXBvcmFsIHBhdHRlcm5zIGFyZSBxdWl0ZSBhcHBhcmVudCwgd2l0aCB3ZWVrZGF5cyBleGhpYml0aW5nIHRoZSBoaWdoZXN0IHRyaXAgY291bnRzLiBGdXJ0aGVybW9yZSwgYW1vbmcgd2Vla2RheXMsIHRoZSBwZWFrIGluIHRyaXAgY291bnRzIGFsaWducyB3aXRoIGNvbW11dGluZyBob3VycywgaW5kaWNhdGluZyBhIHN0cm9uZyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHJpZGVyc2hpcCBhbmQgdHlwaWNhbCBjb21tdXRpbmcgdGltZXMuDQpgYGB7ciB0cmlwc19ob3VyX2RvdHcsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTh9DQpnZ3Bsb3QoZGF0X2NlbnN1cyAlPiUgbXV0YXRlKGhvdXIgPSBob3VyKHN0YXJ0ZWRfYXQpKSkrDQogICAgIGdlb21fZnJlcXBvbHkoYWVzKGhvdXIsIGNvbG9yID0gZG90dyksIGJpbndpZHRoID0gMSkrDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJldihwYWxldHRlNykNCiAgICAsbGFiZWxzID0gYygiU3VuIiwiTW9uIiwgIlR1ZSIsICJXZWQiLCAiVGh1ciIsICJGcmkiLCAiU2F0IikNCiAgKSArDQogIGxhYnModGl0bGU9IkJpa2Ugc2hhcmUgdHJpcHMgaW4gTmV3IFlvcmsgQ2l0eSwgYnkgZGF5IG9mIHRoZSB3ZWVrLCBNYXksIDIwMjMiLA0KICAgICAgIHg9IkhvdXIiLCANCiAgICAgICB5PSJUcmlwIENvdW50cyIpKw0KICAgICBwbG90VGhlbWUoKQ0KDQoNCmdncGxvdChkYXRfY2Vuc3VzICU+JSANCiAgICAgICAgIG11dGF0ZShob3VyID0gaG91cihzdGFydGVkX2F0KSwNCiAgICAgICAgICAgICAgICB3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCLlkajlha0iLCAi5ZGo5pelIiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSkpKw0KICAgICBnZW9tX2ZyZXFwb2x5KGFlcyhob3VyLCBjb2xvciA9IHdlZWtlbmQpLCBiaW53aWR0aCA9IDEpKw0KICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSByZXYocGFsZXR0ZTIpKSArDQogIGxhYnModGl0bGU9IkJpa2Ugc2hhcmUgdHJpcHMgaW4gTmV3IFlvcmsgQ2l0eSAtIHdlZWtlbmQgdnMgd2Vla2RheSwgTWF5LCAyMDIzIiwNCiAgICAgICB4PSJIb3VyIiwgDQogICAgICAgeT0iVHJpcCBDb3VudHMiKSsNCiAgICAgcGxvdFRoZW1lKCkNCmBgYA0KDQpgYGB7ciBvcmlnaW5fbWFwLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KZ2dwbG90KCkrDQogIGdlb21fc2YoZGF0YSA9IE5ZVHJhY3RzICU+JQ0KICAgICAgICAgIHN0X3RyYW5zZm9ybShjcnM9NDMyNikpKw0KICBnZW9tX3BvaW50KGRhdGEgPSBkYXRfY2Vuc3VzICU+JSANCiAgICAgICAgICAgIG11dGF0ZShob3VyID0gaG91cihzdGFydGVkX2F0KSwNCiAgICAgICAgICAgICAgICB3ZWVrZW5kID0gaWZlbHNlKGRvdHcgJWluJSBjKCLlkajlha0iLCAi5ZGo5pelIiksICJXZWVrZW5kIiwgIldlZWtkYXkiKSwNCiAgICAgICAgICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOSB+ICJPdmVybmlnaHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxMCAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxNSB+ICJNaWQtRGF5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE5IH4gIlBNIFJ1c2giKSklPiUNCiAgICAgICAgICAgICAgZ3JvdXBfYnkoc3RhcnRfc3RhdGlvbl9pZCwgc3RhcnRfbGF0LCBzdGFydF9sbmcsIHdlZWtlbmQsIHRpbWVfb2ZfZGF5KSAlPiUNCiAgICAgICAgICAgICAgdGFsbHkoKSwNCiAgICAgICAgICAgIGFlcyh4PXN0YXJ0X2xuZywgeSA9IHN0YXJ0X2xhdCwgY29sb3IgPSBuKSwgDQogICAgICAgICAgICBmaWxsID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjQsIHNpemUgPSAwLjMpKw0KICBzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdyA9ICIjRkZEOUU2IiwgaGlnaCA9ICIjNjIyQThDIiwgbmFtZT0gIk1BRSIpKw0KICB5bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xhdCksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xhdCkpKw0KICB4bGltKG1pbihkYXRfY2Vuc3VzJHN0YXJ0X2xuZyksIG1heChkYXRfY2Vuc3VzJHN0YXJ0X2xuZykpKw0KICBmYWNldF9ncmlkKHdlZWtlbmQgfiB0aW1lX29mX2RheSkrDQogIGxhYnModGl0bGU9IkJpa2Ugc2hhcmUgdHJpcHMgcGVyIGhyIGJ5IHN0YXRpb24uIE5ldyBZb3JrIENpdHksIE1heSwgMjAyMyIpKw0KICBtYXBUaGVtZSgpDQpgYGANCg0KVGhlIGZpZ3VyZSBiZWxvdyBwbG90cyBvdXQgdGhlIGFnZ3JlZ2F0ZSBudW1iZXIgb2YgdHJpcHMgYXMgYSBmdW5jdGlvbiBvZiBkYXRlLiBUaGUgdmVydGljYWwgbGluZXMgaW5kaWNhdGUgTW9uZGF5cy4gRnJvbSBpdCwgdGhlIHdlZWtseSBwYXR0ZXJuIGlzIG9idmlvdXMgdGhhdCB0aGVyZSBhcmUgcGVha3MgYW5kIHRyb3VnaHMgd2l0aGluIGEgd2VlayBhbmQgYSBkYXkuDQpgYGB7ciB0cmlwc19ieV93ZWVrLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMH0NCm1vbmRheXMgPC0gDQogIG11dGF0ZShyaWRlLnBhbmVsLA0KICAgICAgICAgbW9uZGF5ID0gaWZlbHNlKGRvdHcgPT0gIuWRqOS4gCIgJiBob3VyKGludGVydmFsNjApID09IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJ2YWw2MCwgMCkpICU+JQ0KICBmaWx0ZXIobW9uZGF5ICE9IDApIA0KDQpNZW1vcmlhbCA8LSBhcy5QT1NJWGN0KCIyMDIzLTA1LTI5IDAxOjAwOjAwIFVUQyIpDQoNCnN0X2Ryb3BfZ2VvbWV0cnkocmJpbmQoDQogIG11dGF0ZShyaWRlLlRyYWluLCBMZWdlbmQgPSAiVHJhaW5pbmciKSwgDQogIG11dGF0ZShyaWRlLlRlc3QsIExlZ2VuZCA9ICJUZXN0aW5nIikpKSAlPiUNCiAgICBncm91cF9ieShMZWdlbmQsIGludGVydmFsNjApICU+JSANCiAgICAgIHN1bW1hcml6ZShUcmlwX0NvdW50ID0gc3VtKFRyaXBfQ291bnQpKSAlPiUNCiAgICAgIHVuZ3JvdXAoKSAlPiUgDQogICAgICBnZ3Bsb3QoYWVzKGludGVydmFsNjAsIFRyaXBfQ291bnQsIGNvbG91ciA9IExlZ2VuZCkpICsgZ2VvbV9saW5lKCkgKw0KICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUyKSArDQogICAgICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IE1lbW9yaWFsLCBsaW5ldHlwZSA9ICJkb3R0ZWQiKSArDQogICAgICAgIGdlb21fdmxpbmUoZGF0YSA9IG1vbmRheXMsIGFlcyh4aW50ZXJjZXB0ID0gbW9uZGF5KSkgKw0KICAgICAgICBsYWJzKHRpdGxlPSJSaWRlc2hhcmUgdHJpcHMgYnkgd2VlazogTWF5IiwNCiAgICAgICAgICAgICBzdWJ0aXRsZT0iRG90dGVkIGxpbmVzIGZvciBNZW1vcmlhbCBEYXkiLCANCiAgICAgICAgICAgICB4PSJEYXkiLCB5PSJUcmlwIENvdW50IikgKw0KICAgICAgICAgIG1hcFRoZW1lKCkNCg0KYGBgDQoNCkZ1cnRoZXIsIEkgcGxvdCB0aGUgcmlkZXJzaGFyZSB0cmlwIGNvdW50IGFzIGEgZnVuY3Rpb24gb2Ygc3BhdGlhbCBsYWdzIHRvIGNoZWNrIHRoZSAgY29ycmVsYXRpb24uIFRoZSBhbmFseXNpcyByZXZlYWxzIGEgcm9idXN0IGNvcnJlbGF0aW9uIGJldHdlZW4gdHJpcCBpbml0aWF0aW9ucyBhbmQgbGFnIGZlYXR1cmVzLiBIb3dldmVyLCB0aGlzIGNvcnJlbGF0aW9uIGdyYWR1YWxseSBkaW1pbmlzaGVzIGFzIHRoZSBsYWcgcGVyaW9kIGluY3JlYXNlcyB3aXRoaW4gYSBzaW5nbGUgZGF5LiBOb3RhYmx5LCBhIGxhZyBvZiAxMiBob3VycyBleGhpYml0cyBubyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHJlbGF0aW9uc2hpcCB3aXRoIHRyaXAgaW5pdGlhdGlvbnMuIEhvd2V2ZXIsIGEgbGFnIG9mIDEgZGF5IGhhcy4NCmBgYHtyIHRyaXBjb3VudF90aW1lbGFncywgZWNobz1GQUxTRSwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9OH0NCnBsb3REYXRhLmxhZyA8LQ0KICBmaWx0ZXIoYXMuZGF0YS5mcmFtZShyaWRlLnBhbmVsKSwgd2VlayA9PSAyMCkgJT4lDQogIGRwbHlyOjpzZWxlY3Qoc3RhcnRzX3dpdGgoImxhZyIpLCBUcmlwX0NvdW50KSAlPiUNCiAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLVRyaXBfQ291bnQpICU+JQ0KICBtdXRhdGUoVmFyaWFibGUgPSBmY3RfcmVsZXZlbChWYXJpYWJsZSwgImxhZ0hvdXIiLCJsYWcySG91cnMiLCJsYWczSG91cnMiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsYWc0SG91cnMiLCJsYWcxMkhvdXJzIiwibGFnMWRheSIpKQ0KDQpjb3JyZWxhdGlvbi5sYWcgPC0NCiAgZ3JvdXBfYnkocGxvdERhdGEubGFnLCBWYXJpYWJsZSkgJT4lDQogICAgc3VtbWFyaXplKGNvcnJlbGF0aW9uID0gcm91bmQoY29yKFZhbHVlLCBUcmlwX0NvdW50LCB1c2UgPSAiY29tcGxldGUub2JzIiksIDIpKQ0KI3doeSB0aGUgdHJpcCBjb3VudHMgc2VlbSBzbyB3ZWlyZCAtPiBsZXNzIGRhdGFwb2ludHM/DQpnZ3Bsb3QocGxvdERhdGEubGFnLCBhZXMoVmFsdWUsVHJpcF9Db3VudCkpKw0KICBnZW9tX3BvaW50KHNpemUgPSAwLjEpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBjb3JyZWxhdGlvbi5sYWcsIGFlcyhsYWJlbCA9IHBhc3RlKCJyID0iLCByb3VuZChjb3JyZWxhdGlvbiwgMikpKSwNCiAgICAgICAgICAgIHg9LUluZiwgeT1JbmYsIHZqdXN0ID0gMS41LCBoanVzdCA9IC0uMSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nLCBzZT1GQUxTRSwgY29sb3IgPSIjRkY3NTlGIikrDQogIGZhY2V0X3dyYXAoflZhcmlhYmxlLCBuY29sID0gMywgc2NhbGVzID0gJ2ZyZWUnKSArDQogIGxhYnModGl0bGUgPSAiUmlkZXJzaGFyZSB0cmlwIGNvdW50IGFzIGEgZnVuY3Rpb24gb2Ygc3BhdGlhbCBsYWdzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJPbmUgd2VlayBpbiBNYXksIDIwMjMiKSArDQogIG1hcFRoZW1lKCkNCiAgDQpgYGANCg0KIyMgU3BhdGlhbCBDb3JyZWxhdGlvbg0KDQpUaGVuIGl0IGNvbWVzIHRvIHNwYXRpYWwgY29ycmVsYXRpb24sIHRoZSBiaWtlLXNoYXJlIHJpZGVyc2hpcCBhbHNvIHNob3dzIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLiBUaGUgbWFwcyBiZWxvdyBmdXJ0aGVyIHNob3cgdGhlIHN1bSBvZiBiaWtlIHNoYXJlIHRyaXBzIGJ5IHN0YXRpb24gYW5kIGJ5IGRheXMgb2YgdGhlIHdlZWssIGluZGljYXRpbmcgdGhhdCB0aGUgbWFqb3JpdHkgb2YgdHJpcHMgc3RhcnQgaW4gbWlkdG93biAmIGxvd2VyIE1hbmhhdHRhbi4NCmBgYHtyIFNBX3dlZWssIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQpTQSA8LSByaWRlLnBhbmVsICU+JQ0KZ3JvdXBfYnkod2VlayxPcmlnaW4uVHJhY3Qsc3RhcnRfbG5nLHN0YXJ0X2xhdCkgJT4lDQogIHN1bW1hcml6ZShTdW1fVHJpcF9Db3VudCA9IHN1bShUcmlwX0NvdW50KSkgDQogIA0KZ2dwbG90KCkrDQogIGdlb21fc2YoZGF0YSA9IE5ZVHJhY3RzLCBjb2xvciA9ICJncmV5MzAiLCBsd2QgPSAwLjEsIGZpbGwgPSAiZ3JleTkwIikrDQogIGdlb21fcG9pbnQoZGF0YSA9IFNBICwNCiAgICAgICAgICAgICBhZXMoeCA9IHN0YXJ0X2xuZywgeSA9IHN0YXJ0X2xhdCwgY29sb3IgPSBTdW1fVHJpcF9Db3VudCksIA0KICAgICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBhbHBoYSA9IDAuNiwgc2l6ZSA9IDAuNikrDQogIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93ID0gIiNGRkQ5RTYiLCBoaWdoID0gIiM2MjJBOEMiLCBuYW1lPSAiTUFFIikrDQogIHlsaW0obWluKFNBJHN0YXJ0X2xhdCksIG1heChTQSRzdGFydF9sYXQpKSsNCiAgeGxpbShtaW4oU0Ekc3RhcnRfbG5nKSwgbWF4KFNBJHN0YXJ0X2xuZykpKw0KICBmYWNldF93cmFwKH53ZWVrLCBuY29sID0gNykgKw0KICBsYWJzKHRpdGxlPSJTdW0gb2YgQmlrZSBTaGFyZSBUcmlwcyBieSBTdGF0aW9uIGFuZCBXZWVrIGluIE5ZQyIsDQogICAgICAgc3VidGl0bGUgPSAiTWF5LCAyMDIzIiwNCiAgICAgICBjYXB0aW9uID0gIkRhdGE6IENpdGkgQmlrZSBUcmlwIERhdGEiKSArDQogIG1hcFRoZW1lKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KDQpgYGB7ciBTQV9kYXksIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyfQ0KU0EyIDwtIHJpZGUucGFuZWwgJT4lDQpncm91cF9ieShkb3R3LE9yaWdpbi5UcmFjdCxzdGFydF9sbmcsc3RhcnRfbGF0KSAlPiUNCiAgc3VtbWFyaXplKFN1bV9UcmlwX0NvdW50ID0gc3VtKFRyaXBfQ291bnQpKSANCiAgDQpnZ3Bsb3QoKSsNCiAgZ2VvbV9zZihkYXRhID0gTllUcmFjdHMsIGNvbG9yID0gImdyZXkzMCIsIGx3ZCA9IDAuMSwgZmlsbCA9ICJncmV5OTAiKSsNCiAgZ2VvbV9wb2ludChkYXRhID0gU0EyICwNCiAgICAgICAgICAgICBhZXMoeCA9IHN0YXJ0X2xuZywgeSA9IHN0YXJ0X2xhdCwgY29sb3IgPSBTdW1fVHJpcF9Db3VudCksIA0KICAgICAgICAgICAgIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBhbHBoYSA9IDAuNiwgc2l6ZSA9IDAuNikrDQogIHlsaW0obWluKFNBJHN0YXJ0X2xhdCksIG1heChTQSRzdGFydF9sYXQpKSsNCiAgeGxpbShtaW4oU0Ekc3RhcnRfbG5nKSwgbWF4KFNBJHN0YXJ0X2xuZykpKw0KICBmYWNldF93cmFwKH5kb3R3LCBuY29sID0gNywgbGFiZWxsZXIgPSBsYWJlbGxlcihkb3R3ID0gc2V0TmFtZXMoYygiTW9uIiwgIlR1ZSIsICJXZWQiLCAiVGh1ciIsICJGcmkiLCAiU2F0IiwgIlN1biIpLGMoIuWRqOS4gCIsICLlkajkuowiLCAi5ZGo5LiJIiwgIuWRqOWbmyIsICLlkajkupQiLCAi5ZGo5YWtIiwgIuWRqOaXpSIpKSkpICsNCiAgc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAiI0ZGRDlFNiIsIGhpZ2ggPSAiIzYyMkE4QyIsIG5hbWU9ICJNQUUiKSsNCiAgbGFicyh0aXRsZT0iU3VtIG9mIEJpa2UgU2hhcmUgVHJpcHMgYnkgU3RhdGlvbiBhbmQgZGF5IG9mIHRoZSBXZWVrIGluIE5ZQyIsDQogICAgICAgc3VidGl0bGUgPSAiTWF5LCAyMDIzIiwNCiAgICAgICBjYXB0aW9uID0gIkRhdGE6IENpdGkgQmlrZSBUcmlwIERhdGEiKSArDQogIG1hcFRoZW1lKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KDQojIyBTcGFjZS90aW1lIGNvcnJlbGF0aW9uDQoNCkFnYWluLCB0aGUgYmlrZSBzaGFyZSByaWRlcnNoaXAgYWxzbyBleGhpYml0cyBzdHJvbmcgc3BhY2UvdGltZSBjb3JyZWxhdGlvbi4NClRvIHNob3csIEkgcGljayB1cCBvbmUgZGF5IGluIE5ZQyBpbiBNYXksIDIwMjMgdG8gdmlzdWFsaXplIHRoZSByZWxhdGlvbnNoaXAgd2l0aCAxNS1taW51dGUgaW50ZXJ2YWxzIHZpYSBhbiBhbmltYXRpb24uDQoNCmBgYHtyIHNwYWNlX3RpbWVfY29yMSwgaW5jbHVkZT1GQUxTRX0NCg0Kd2VlazIwIDwtIGZpbHRlcihkYXRfY2Vuc3VzLCB3ZWVrID09IDIwICYgZG90dyA9PSAi5ZGo5LiAIikNCndlZWsyMC5wYW5lbCA8LSBleHBhbmQuZ3JpZCgNCiAgaW50ZXJ2YWwxNSA9IHVuaXF1ZSh3ZWVrMjAkaW50ZXJ2YWwxNSksDQogIE9yaWdpbi5UcmFjdCA9IHVuaXF1ZShkYXRfY2Vuc3VzJE9yaWdpbi5UcmFjdCkpDQpgYGANCg0KYGBge3Igc3BhY2VfdGltZV9jb3IyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBpbmNsdWRlPUZBTFNFfQ0KDQpyaWRlLmFuaW1hdGlvbi5kYXRhIDwtDQogIG11dGF0ZSh3ZWVrMjAsIFRyaXBfQ291bnRlciA9MSkgJT4lDQogIHJpZ2h0X2pvaW4od2VlazIwLnBhbmVsKSAlPiUNCiAgZ3JvdXBfYnkoaW50ZXJ2YWwxNSwgT3JpZ2luLlRyYWN0KSAlPiUNCiAgc3VtbWFyaXplKFRyaXBfQ291bnQgPSBzdW0oVHJpcF9Db3VudGVyLG5hLnJtPVQpKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBsZWZ0X2pvaW4oTllUcmFjdHMsYnk9YygiT3JpZ2luLlRyYWN0Ij0iR0VPSUQiKSkgJT4lDQogIHN0X3NmKCklPiUNCiAgbXV0YXRlKFRyaXBzID0gY2FzZV93aGVuKFRyaXBfQ291bnQgPT0gMCB+ICIwIHRyaXBzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyaXBfQ291bnQgPiAwICYgVHJpcF9Db3VudCA8PSAzIH4gIjEtMyB0cmlwcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBUcmlwX0NvdW50ID4gMyAmIFRyaXBfQ291bnQgPD0gNiB+ICI0LTYgdHJpcHMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgVHJpcF9Db3VudCA+IDYgJiBUcmlwX0NvdW50IDw9IDEwIH4gIjctMTAgdHJpcHMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRyaXBfQ291bnQgPiAxMCAgfiAiMTErIHRyaXBzIikpICU+JQ0KICBtdXRhdGUoVHJpcHMgPSBmY3RfcmVsZXZlbChUcmlwcywiMCB0cmlwcyIsIjEtMyB0cmlwcyIsIjQtNiB0cmlwcyIsIjctMTAgdHJpcHMiLCIxMSsgdHJpcHMiICkpDQpgYGANCg0KYGBge3Igc3BhY2VfdGltZV9jb3IzLCBlY2hvPUZBTFNFfQ0KDQpyaWRlc2hhcmVfYW5pbWF0aW9uIDwtIGdncGxvdCgpKw0KICBnZW9tX3NmKGRhdGEgPSBOWVRyYWN0cywgY29sb3IgPSAiZ3JleTMwIiwgbHdkID0gMC4xLCBmaWxsID0gImdyZXkiKSsNCiAgZ2VvbV9zZihkYXRhID0gcmlkZS5hbmltYXRpb24uZGF0YSxhZXMoZmlsbD1UcmlwcykpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlNSkrDQogIGxhYnModGl0bGUgPSJSaWRlc2hhcmUgcGlja3VwcyBmb3Igb25lIGRheSBpbiBOWUMgaW4gTWF5LCAyMDIzIiwNCiAgICAgICBzdWJ0aXRsZSA9IjE1IG1pbiBpbnRlcnZhbHM6e2N1cnJlbnRfZnJhbWV9IikrDQogIHRyYW5zaXRpb25fbWFudWFsKGludGVydmFsMTUpKw0KICBtYXBUaGVtZSgpDQoNCmFuaW1hdGUocmlkZXNoYXJlX2FuaW1hdGlvbiwgZHVyYXRpb249MjAsIHJlbmRlcmVyID0gZ2lmc2tpX3JlbmRlcmVyKCkpDQoNCmBgYA0KDQojIyBXZWF0aGVyDQoNCkFzIGZvciB0aGUgZWZmZWN0IG9mIHdlYXRoZXIsIG9idmlvdXNseSByaWRlcnNoaXAgYWxzbyB2YXJpZXMgd2l0aCBwcmVjaXBpdGF0aW9uIGFuZCB0ZW1wZXJhdHVyZS4NCmBgYHtyIHdlYXRoZXJfLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00fQ0Kc3RfZHJvcF9nZW9tZXRyeShyaWRlLnBhbmVsKSAlPiUNCiAgZ3JvdXBfYnkoaW50ZXJ2YWw2MCkgJT4lIA0KICBzdW1tYXJpemUoVHJpcF9Db3VudCA9IG1lYW4oVHJpcF9Db3VudCksDQogICAgICAgICAgICBQcmVjaXBpdGF0aW9uID0gZmlyc3QoUHJlY2lwaXRhdGlvbikpICU+JQ0KICBtdXRhdGUoaXNQcmVjaXAgPSBpZmVsc2UoUHJlY2lwaXRhdGlvbiA+IDAsIlJhaW4vU25vdyIsICJOb25lIikpICU+JQ0KICBncm91cF9ieShpc1ByZWNpcCkgJT4lDQogIHN1bW1hcml6ZShNZWFuX1RyaXBfQ291bnQgPSBtZWFuKFRyaXBfQ291bnQsIG5hLnJtID0gVCkpICU+JQ0KICAgIGdncGxvdChhZXMoaXNQcmVjaXAsIE1lYW5fVHJpcF9Db3VudCkpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsZmlsbD0iI0ZGQTdDNCIpICsNCiAgICAgIGxhYnModGl0bGU9IkRvZXMgcmlkZXJzaGlwIHZhcnkgd2l0aCBwcmVjaXBpdGF0aW9uPyIsDQogICAgICAgICAgIHg9IlBlcmNpcGl0YXRpb24iLCB5PSJNZWFuIFRyaXAgQ291bnQiKSArDQogICAgICBwbG90VGhlbWUoKQ0KYGBgDQoNClRoZSBhdmVyYWdlIG51bWJlciBvZiB0cmlwcyBwZXIgd2VlayBzZWVtcyB0byB0cmVuZCB1cHdhcmQgYXMgdGhlIHRlbXBlcmF0dXJlIGluY3JlYXNlcy4gVGhpcyB0cmVuZCBpcyBwcmV0dHkgY29uc2lzdGVudCBhY3Jvc3MgYWxsIHBhbmVscy4NCmBgYHtyIHdlYXRoZXJfMiwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCnN0X2Ryb3BfZ2VvbWV0cnkocmlkZS5wYW5lbCkgJT4lDQogIGdyb3VwX2J5KGludGVydmFsNjApICU+JSANCiAgc3VtbWFyaXplKFRyaXBfQ291bnQgPSBtZWFuKFRyaXBfQ291bnQpLA0KICAgICAgICAgICAgVGVtcGVyYXR1cmUgPSBmaXJzdChUZW1wZXJhdHVyZSkpICU+JQ0KICBtdXRhdGUod2VlayA9IHdlZWsoaW50ZXJ2YWw2MCkpICU+JQ0KICBnZ3Bsb3QoYWVzKFRlbXBlcmF0dXJlLCBUcmlwX0NvdW50KSkgKyANCiAgICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT0gRkFMU0UsY29sb3I9IiNGRjc1OUYiKSArDQogICAgZmFjZXRfd3JhcCh+d2VlaywgbmNvbD01KSArIA0KICAgIGxhYnModGl0bGU9IlRyaXAgQ291bnQgYXMgYSBmdWN0aW9uIG9mIFRlbXBlcmF0dXJlIGJ5IHdlZWsiLA0KICAgICAgICAgeD0iVGVtcGVyYXR1cmUiLCB5PSJNZWFuIFRyaXAgQ291bnQiKSArDQogICAgcGxvdFRoZW1lKCkgDQpgYGANCg0KIyBNb2RlbGluZyBhbmQgVmFsaWRhdGlvbg0KDQpJbiB0aGlzIHBhcnQsIEkgc3BsaXQgdGhlIGRhdGEgaW50byBhIHRyYWluaW5nIGFuZCBhIHRlc3Qgc2V0IGFuZCBjcmVhdGVkIGZpdmUgbGluZWFyIG1vZGVscyB1c2luZyB0aGUgYGxtYCBmdW50aW9uLiBUaGUgZmlyc3QgbW9kZWxzIGluY2x1ZGUgb25seSB0ZW1wb3JhbCBjb250cm9scywgYnV0IHRoZSBsYXRlciBvbmVzIGNvbnRhaW4gYWxsIG9mIG91ciBsYWcgaW5mb3JtYXRpb24gb3IgYW1lbml0aWVzLg0KDQpgYGB7ciB0cmFpbl90ZXN0LCBpbmNsdWRlPUZBTFNFfQ0KcmlkZS5UcmFpbiA8LSBmaWx0ZXIocmlkZS5wYW5lbCwgd2VlayA+PSAyMCkNCnJpZGUuVGVzdCA8LSBmaWx0ZXIocmlkZS5wYW5lbCwgd2VlayA8IDIwKQ0KYGBgDQoNCkZpdmUgbGluZWFyIHJlZ3Jlc3Npb25zIGFyZSBmdXJ0aGVyIGVzdGltYXRlZCBvbiBiaWtlLXNoYXJlIHRyYWluIGRhdGEsIGVhY2ggd2l0aCBkaWZmZXJlbnQgZml4ZWQgZWZmZWN0czoNCjEuIHJlZyAxIGZvY3VzZXMgb24ganVzdCB0aW1lLCBpbmNsdWRpbmcgaG91ciBmaXhlZCBlZmZlY3RzLCBkYXkgb2YgdGhlIHdlZWssIGFuZCBUZW1wZXJhdHVyZS4NCjIuIHJlZyAyIGZ1cnRoZXIgYWRkcyBzcGFjZSBlZmZlY3RzIGZvciB0aGUgYWNyb3NzLXN0YXRpb24gZGlmZmVyZW5jZXMuDQozLiByZWcgMyBjb21iaW5lcyB0aGUgdGltZSBhbmQgc3BhY2UgZWZmZWN0cywgYW5kIGFsc28gYWRkcyBtb3JlIHdlYXRoZXIgZWZmZWN0cywgc3VjaCBhcyBwcmVjaXBpdGF0aW9uLg0KNC4gcmVnIDQgdGFrZXMgdGltZSBsYWcgZmVhdHVyZXMgaW50byBjb25zaWRlcmF0aW9uLg0KNS4gcmVnIDUgZnVydGhlciBhZGRzIG1vcmUgYW1lbml0aWVzIGVmZmVjdHMsIHN1Y2ggYXMgbGFuZG1hcmtzLCBtYXJrZXRzLCBjb2xsZWdlcywgYW5kIGJ1cyBzdGF0aW9ucy4NCg0KYGBge3IgZml2ZV9tb2RlbHMsIGluY2x1ZGU9RkFMU0V9DQpyZWcxIDwtIA0KICBsbShUcmlwX0NvdW50IH4gIGhvdXIoaW50ZXJ2YWw2MCkgKyBkb3R3ICsgVGVtcGVyYXR1cmUsICBkYXRhPXJpZGUuVHJhaW4lPiUgc2VsZWN0KFRyaXBfQ291bnQsIGludGVydmFsNjAsIGRvdHcsIFRlbXBlcmF0dXJlKSkNCg0KcmVnMiA8LSANCiAgbG0oVHJpcF9Db3VudCB+ICBzdGFydF9zdGF0aW9uX25hbWUgKyBkb3R3ICsgVGVtcGVyYXR1cmUsICBkYXRhPXJpZGUuVHJhaW4pDQoNCnJlZzMgPC0gDQogIGxtKFRyaXBfQ291bnQgfiAgc3RhcnRfc3RhdGlvbl9uYW1lICsgaG91cihpbnRlcnZhbDYwKSArIGRvdHcgKyBUZW1wZXJhdHVyZSArIFByZWNpcGl0YXRpb24sIA0KICAgICBkYXRhPXJpZGUuVHJhaW4pDQoNCnJlZzQgPC0gDQogIGxtKFRyaXBfQ291bnQgfiAgc3RhcnRfc3RhdGlvbl9uYW1lICsgIGhvdXIoaW50ZXJ2YWw2MCkgKyBkb3R3ICsgVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uICsgbGFnSG91ciArIGxhZzJIb3VycyArbGFnM0hvdXJzICsgbGFnMTJIb3VycyArIGxhZzFkYXksIA0KICAgICBkYXRhPXJpZGUuVHJhaW4pDQoNCnJlZzUgPC0gDQogIGxtKFRyaXBfQ291bnQgfiAgc3RhcnRfc3RhdGlvbl9uYW1lICsgIGhvdXIoaW50ZXJ2YWw2MCkgKyBkb3R3ICsgVGVtcGVyYXR1cmUgKyBQcmVjaXBpdGF0aW9uICsgbGFnSG91ciArIGxhZzJIb3VycyArbGFnM0hvdXJzICsgbGFnMTJIb3VycyArIGxhZzFkYXkgK0xhbmRtYXJrcy5ubisgTWFya2V0cy5ubisgQnVzX1N0YXRpb25zLm5uKyBDb2xsZWdlLm5uLA0KICAgICBkYXRhPXJpZGUuVHJhaW4pDQpgYGANCg0KYGBge3IgcmVnX3NhdmUsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQojc2F2ZShyZWcxLCBmaWxlID0gInJlZzEuUkRhdGEiKQ0KI3NhdmUocmVnMiwgZmlsZSA9ICJyZWcyLlJEYXRhIikNCiNzYXZlKHJlZzMsIGZpbGUgPSAicmVnMy5SRGF0YSIpDQojc2F2ZShyZWc0LCBmaWxlID0gInJlZzQuUkRhdGEiKQ0KI3NhdmUocmVnNSwgZmlsZSA9ICJyZWc1LlJEYXRhIikNCg0KbG9hZCgicmVnMS5SRGF0YSIpDQpsb2FkKCJyZWcyLlJEYXRhIikNCmxvYWQoInJlZzMuUkRhdGEiKQ0KbG9hZCgicmVnNC5SRGF0YSIpDQpsb2FkKCJyZWc1LlJEYXRhIikNCg0KYGBgDQoNCiMjUHJlZGljdCBmb3IgdGVzdCBkYXRhDQoNCmBgYHtyIG5lc3RfZGF0YSAsIHdhcm5pbmcgPSBGQUxTRX0NCnJpZGUuVGVzdC53ZWVrTmVzdCA8LSANCiAgcmlkZS5UZXN0ICU+JQ0KICBuZXN0KC13ZWVrKSANCg0KcmlkZS5UZXN0LndlZWtOZXN0DQpgYGANCg0KYGBge3IgcHJlZGljdF9mdW5jdGlvbiwgaW5jbHVkZT1GQUxTRX0NCm1vZGVsX3ByZWQgPC0gZnVuY3Rpb24oZGF0LCBmaXQpew0KICAgcHJlZCA8LSBwcmVkaWN0KGZpdCwgbmV3ZGF0YSA9IGRhdCl9DQpgYGANCg0KYGBge3IgZG9fcHJlZGljaXRvbnMsIGVjaG89RkFMU0V9DQp3ZWVrX3ByZWRpY3Rpb25zIDwtIA0KICByaWRlLlRlc3Qud2Vla05lc3QgJT4lIA0KICAgIG11dGF0ZShBVGltZV9GRSA9IG1hcCgueCA9IGRhdGEsIGZpdCA9IHJlZzEsIC5mID0gbW9kZWxfcHJlZCksDQogICAgICAgICAgIEJTcGFjZV9GRSA9IG1hcCgueCA9IGRhdGEsIGZpdCA9IHJlZzIsIC5mID0gbW9kZWxfcHJlZCksDQogICAgICAgICAgIENUaW1lX1NwYWNlX0ZFID0gbWFwKC54ID0gZGF0YSwgZml0ID0gcmVnMywgLmYgPSBtb2RlbF9wcmVkKSwNCiAgICAgICAgICAgRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MgPSBtYXAoLnggPSBkYXRhLCBmaXQgPSByZWc0LCAuZiA9IG1vZGVsX3ByZWQpLA0KICAgICAgICAgICBFVGltZV9TcGFjZV9GRV90aW1lTGFnc19hbWVudGl0aWVzID0gbWFwKC54ID0gZGF0YSwgZml0ID0gcmVnNSwgLmYgPSBtb2RlbF9wcmVkKSkgJT4lIA0KICAgIGdhdGhlcihSZWdyZXNzaW9uLCBQcmVkaWN0aW9uLCAtZGF0YSwgLXdlZWspICU+JQ0KICAgIG11dGF0ZShPYnNlcnZlZCA9IG1hcChkYXRhLCBwdWxsLCBUcmlwX0NvdW50KSwNCiAgICAgICAgICAgQWJzb2x1dGVfRXJyb3IgPSBtYXAyKE9ic2VydmVkLCBQcmVkaWN0aW9uLCAgfiBhYnMoLnggLSAueSkpLA0KICAgICAgICAgICBNQUUgPSBtYXBfZGJsKEFic29sdXRlX0Vycm9yLCBtZWFuLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICBzZF9BRSA9IG1hcF9kYmwoQWJzb2x1dGVfRXJyb3IsIHNkLCBuYS5ybSA9IFRSVUUpKQ0KDQp3ZWVrX3ByZWRpY3Rpb25zDQpgYGANCg0KIyMgRXhhbWluZSBFcnJvciBNZXRyaWNzIGZvciBBY2N1cmFjeQ0KDQpCeSBwbG90dGluZyBNQUUgYnkgbW9kZWwgYnkgd2VlaywgdGhlIHNwYXRpYWwgZml4ZWQgZWZmZWN0cyBhbmQgdGVtcG9yYWwrc3BhdGlhbCBmaXhlZCBlZmZlY3RzIGRvIGEgc2ltaWxhciBqb2IgaW4gcHJlZGljdGluZy5Ib3dldmVyLCB0aGUgbW9kZWwgc3RhcnRzIHRvIGJlY29tZSBtb3JlIGFjY3VyYXRlIHdoZW4gbGFnIGVmZmVjdHMgYXJlIHRha2VuIGludG8gY29uc2lkZXJhdGlvbiwgd2l0aCBhIE1BRSB1bmRlciAwLjQsIHdoaWNoIGlzIGV4YWN0bHkgc2FtZSBhcyB0aGUgbW9kZWwgd2hpY2ggZnVydGhlciB0YWtlcyBhbWVuaXRpZXMgZmVhdHVyZXMgaW50byBjb25zaWRlcmF0aW9uLg0KDQpgYGB7ciBwbG90X2Vycm9yc19ieV9tb2RlbCwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9Nn0NCndlZWtfcHJlZGljdGlvbnMgJT4lDQogIGRwbHlyOjpzZWxlY3Qod2VlaywgUmVncmVzc2lvbiwgTUFFKSAlPiUNCiAgZ2F0aGVyKFZhcmlhYmxlLCBNQUUsIC1SZWdyZXNzaW9uLCAtd2VlaykgJT4lDQogIGdncGxvdChhZXMod2VlaywgTUFFKSkgKyANCiAgICBnZW9tX2JhcihhZXMoZmlsbCA9IFJlZ3Jlc3Npb24pLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQ9ImlkZW50aXR5IikgKw0KICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGU1KSArDQogICAgbGFicyh0aXRsZSA9ICJNZWFuIEFic29sdXRlIEVycm9ycyBieSBtb2RlbCBzcGVjaWZpY2F0aW9uIGFuZCB3ZWVrIikgKw0KICBwbG90VGhlbWUoKQ0KYGBgDQoNCkZyb20gdGhlIHByZWRpY3RpbmcgcGVyZm9ybWFuY2VzIHBsb3QsIHRoZSBtb2RlbCBpcyBnZXR0aW5nIG1vcmUgYWNjdXJhdGUgYW5kIGdlbmVyYWxpemFibGUgYWZ0ZXIgYXBwbHlpbmcgdGltZSwgc3BhY2UsIGxhZyBmZWF0dXJlcy4gVGhlIGxhZyBtb2RlbCBkb2VzIGEgZ29vZCBwZXJmb3JtYW5jZSBpbiBwcmVkaWN0aW5nIHRoZSBiaWtlIHNoYXJlIGluIGZpcnN0IHR3byB3ZWVrcyBvZiBNYXksIGFsdGhvdWdoIGl0IGxvc2VzIHNvbWUgb2JzZXJ2YXRpb25zIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIG1vbnRoIGFuZCBhbHNvIHVuZGVyZXN0aW1hdGVzIGEgbGl0dGxlIGJpdC4NCg0KYGBge3IgZXJyb3JfdnNfYWN0dWFsX3RpbWVzZXJpZXMsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTgsIHdhcm5pbmc9RkFMU0V9DQp3ZWVrX3ByZWRpY3Rpb25zICU+JSANCiAgICBtdXRhdGUoaW50ZXJ2YWw2MCA9IG1hcChkYXRhLCBwdWxsLCBpbnRlcnZhbDYwKSwNCiAgICAgICAgICAgc3RhcnRfc3RhdGlvbl9pZCA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9zdGF0aW9uX2lkKSkgJT4lDQogICAgZHBseXI6OnNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBPYnNlcnZlZCwgUHJlZGljdGlvbiwgUmVncmVzc2lvbikgJT4lDQogICAgdW5uZXN0KCkgJT4lDQogICAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLVJlZ3Jlc3Npb24sIC1pbnRlcnZhbDYwLCAtc3RhcnRfc3RhdGlvbl9pZCkgJT4lDQogICAgZ3JvdXBfYnkoUmVncmVzc2lvbiwgVmFyaWFibGUsIGludGVydmFsNjApICU+JQ0KICAgIHN1bW1hcml6ZShWYWx1ZSA9IHN1bShWYWx1ZSkpICU+JQ0KICAgIGdncGxvdChhZXMoaW50ZXJ2YWw2MCwgVmFsdWUsIGNvbG91cj1WYXJpYWJsZSkpICsgDQogICAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuMSkgKyANCiAgICAgIGZhY2V0X3dyYXAoflJlZ3Jlc3Npb24sIG5jb2w9MSkgKw0KICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUyKSArDQogICAgICBsYWJzKHRpdGxlID0gIlByZWRpY3RlZC9PYnNlcnZlZCBiaWtlIHNoYXJlIHRpbWUgc2VyaWVzIiwgc3VidGl0bGUgPSAiTmV3IFlvcmsgQ2l0eTsgQSB0ZXN0IHNldCBvZiAyIHdlZWtzIiwgIHggPSAiSG91ciIsIHk9ICJTdGF0aW9uIFRyaXBzIikgKw0KICAgICAgcGxvdFRoZW1lKCkNCmBgYA0KDQpCYXNlZCBvbiB0aGUgU3BhY2VfVGltZV9MYWcoX2FtZW5pdHkpIG1vZGVsKFJlZzQvUmVnNSkgd2hpY2ggc2VlbXMgdG8gaGF2ZSB0aGUgYmVzdCBnb29kbmVzcyBvZiBmaXQgZ2VuZXJhbGx5LCB3ZSBjYW4gb2JzZXJ2ZSBzb21lIHNwYXRpYWwgcGF0dGVybnMgZnJvbSB0aGUgbWVhbiBhYnNvbHV0ZSBlcnJvcnMgYnkgc3RhdGlvbi4gU3BlY2lmaWNhbGx5LCB0aGUgc3RhdGlvbnMgd2l0aCBoaWdoZXIgTUFFIGFyZSBhZ2dyZWdhdGVkIGluIE1pZHRvd24gJiBMb3dlciBNYW5oYXR0YW4uDQoNCmBgYHtyIGVycm9yc19ieV9zdGF0aW9uLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD00LCB3YXJuaW5nPUZBTFNFfQ0Kd2Vla19wcmVkaWN0aW9ucyAlPiUgDQogICAgbXV0YXRlKGludGVydmFsNjAgPSBtYXAoZGF0YSwgcHVsbCwgaW50ZXJ2YWw2MCksDQogICAgICAgICAgIHN0YXJ0X3N0YXRpb25faWQgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfc3RhdGlvbl9pZCksIA0KICAgICAgICAgICBzdGFydF9sYXQgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfbGF0KSwgDQogICAgICAgICAgIHN0YXJ0X2xuZyA9IG1hcChkYXRhLCBwdWxsLCBzdGFydF9sbmcpKSAlPiUNCiAgICBzZWxlY3QoaW50ZXJ2YWw2MCwgc3RhcnRfc3RhdGlvbl9pZCwgc3RhcnRfbG5nLCBzdGFydF9sYXQsIE9ic2VydmVkLCBQcmVkaWN0aW9uLCBSZWdyZXNzaW9uKSAlPiUNCiAgICB1bm5lc3QoKSAlPiUNCiAgZmlsdGVyKFJlZ3Jlc3Npb24gPT0gIkRUaW1lX1NwYWNlX0ZFX3RpbWVMYWdzIikgJT4lDQogIGdyb3VwX2J5KHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2xuZywgc3RhcnRfbGF0KSAlPiUNCiAgc3VtbWFyaXplKE1BRSA9IG1lYW4oYWJzKE9ic2VydmVkLVByZWRpY3Rpb24pLCBuYS5ybSA9IFRSVUUpKSU+JQ0KICANCmdncGxvdCguKSsNCiAgZ2VvbV9zZihkYXRhID0gTllDZW5zdXMsIGNvbG9yID0gImdyZXkiLCBmaWxsID0gInRyYW5zcGFyZW50IikrDQogIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFKSwgDQogICAgICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGFscGhhID0gMC40KSsNCiAgc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAiI0ZGRDlFNiIsIGhpZ2ggPSAiIzYyMkE4QyIsIG5hbWU9ICJNQUUiKSsNCiAgI3NjYWxlX2NvbG91cl92aXJpZGlzKGRpcmVjdGlvbiA9IC0xLGRpc2NyZXRlID0gRkFMU0UsIG9wdGlvbiA9ICJEIikrDQogIHlsaW0obWluKGRhdF9jZW5zdXMkc3RhcnRfbGF0KSwgbWF4KGRhdF9jZW5zdXMkc3RhcnRfbGF0KSkrDQogIHhsaW0obWluKGRhdF9jZW5zdXMkc3RhcnRfbG5nKSwgbWF4KGRhdF9jZW5zdXMkc3RhcnRfbG5nKSkrDQogIGxhYnModGl0bGU9Ik1lYW4gQWJzIEVycm9yLCBUZXN0IFNldCwgTW9kZWwgNCIpKw0KICBtYXBUaGVtZSgpDQpgYGANCg0KIyMgU3BhY2UtVGltZSBFcnJvciBFdmFsdWF0aW9uDQoNCkJ5IGNvbXBhcmluZyBvYnNlcnZlZCB2ZXJzdXMgcHJlZGljdGVkIHJpZGVyc2hpcCBmb3IgdmFyaW91cyB0aW1lcyBvZiBkYXkgYWNyb3NzIHdlZWtkYXlzIGFuZCB3ZWVrZW5kcywgdGhlIHByZXNlbmNlIG9mIHNwYWNlLXRpbWUgZXJyb3JzIGJlY29tZXMgYXBwYXJlbnQuIFRoZSBtYWpvcml0eSBvZiB0aGUgZGF0YSBwb2ludHMgZmFsbGluZyBiZWxvdyB0aGUgaWRlbnRpdHkgbGluZSBzdWdnZXN0cyB0aGF0IHRoZSBtb2RlbCBnZW5lcmFsbHkgdW5kZXJlc3RpbWF0ZXMgYmlrZS1zaGFyZSB1c2FnZS4gVGhpcyB0cmVuZCBpcyBwYXJ0aWN1bGFybHkgcHJvbm91bmNlZCBkdXJpbmcgdGhlIHdlZWtkYXkgbW9ybmluZyBydXNoIGhvdXJzLiBGdXJ0aGVybW9yZSwgdGhlIHNsb3BlIG9mIHRoZSBiZXN0IGZpdCBsaW5lYGtgIHZhcmllcyBhY3Jvc3MgZGlmZmVyZW50IHRpbWUgc2xvdHMgZm9yIGJvdGggd2Vla2RheXMgYW5kIHdlZWtlbmRzLCBpbmRpY2F0aW5nIGZsdWN0dWF0aW9ucyBpbiB0aGUgbW9kZWwncyBwcmVkaWN0aXZlIGFjY3VyYWN5IGRlcGVuZGVudCBvbiB0aGUgc3BlY2lmaWMgdGltZSBwZXJpb2QgYmVpbmcgYW5hbHl6ZWQuIFRoZXJlZm9yZSwgbW9yZSBmYWN0b3JzIHNob3VsZCBiZSB0YWtlbiBpbnRvIGNvbnNpZGVyYXRpb24uDQoNCmBgYHtyIG9ic19wcmVkX2FsbCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OCwgd2FybmluZz1GQUxTRSwgY2FjaGU9VFJVRX0NCndlZWtfcHJlZGljdGlvbnMgJT4lIA0KICAgIG11dGF0ZShpbnRlcnZhbDYwID0gbWFwKGRhdGEsIHB1bGwsIGludGVydmFsNjApLA0KICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X3N0YXRpb25faWQpLCANCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIA0KICAgICAgICAgICBzdGFydF9sbmcgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfbG5nKSwNCiAgICAgICAgICAgZG90dyA9IG1hcChkYXRhLCBwdWxsLCBkb3R3KSkgJT4lDQogICAgc2VsZWN0KGludGVydmFsNjAsIHN0YXJ0X3N0YXRpb25faWQsIHN0YXJ0X2xuZywgDQogICAgICAgICAgIHN0YXJ0X2xhdCwgT2JzZXJ2ZWQsIFByZWRpY3Rpb24sIFJlZ3Jlc3Npb24sDQogICAgICAgICAgIGRvdHcpICU+JQ0KICAgIHVubmVzdCgpICU+JQ0KICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSU+JQ0KICBtdXRhdGUod2Vla2VuZCA9IGlmZWxzZShkb3R3ICVpbiUgYygi5ZGo5pelIiwgIuWRqOWFrSIpLCAiV2Vla2VuZCIsICJXZWVrZGF5IiksDQogICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOSB+ICJPdmVybmlnaHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxMCAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxNSB+ICJNaWQtRGF5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE5IH4gIlBNIFJ1c2giKSklPiUNCiAgZ2dwbG90KCkrDQogIGdlb21fcG9pbnQoYWVzKHg9IE9ic2VydmVkLCB5ID0gUHJlZGljdGlvbikpKw0KICAgIGdlb21fc21vb3RoKGFlcyh4PSBPYnNlcnZlZCwgeT0gUHJlZGljdGlvbiksIG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gIiNGRkE3QzQiICkrDQogICAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLGNvbG9yPSIjNjIyQThDIikrDQogIGZhY2V0X2dyaWQodGltZV9vZl9kYXl+d2Vla2VuZCkrDQogIGxhYnModGl0bGU9Ik9ic2VydmVkIHZzIFByZWRpY3RlZCBieSB0aGUgZGF5IG9mIHRoZSB3ZWVrIGFuZCBob3VyIiwNCiAgICAgICB4PSJPYnNlcnZlZCB0cmlwcyIsIA0KICAgICAgIHk9IlByZWRpY3RlZCB0cmlwcyIpKw0KICBwbG90VGhlbWUoKQ0KYGBgDQoNClRoZXNlIG1hcHMgZnVydGhlciBzaG93IHRoYXQgaGlnaCBlcnJvcnMgYXJlIGNvbmNlbnRyYXRlZCBpbiBtaWR0b3duICYgbG93ZXIgTWFuaGF0dGFuIC0gd2hlcmUgYmlrZS1zaGFyZSByaWRlcnNoaXBzIGFyZSBhbHNvIGhpZ2guDQoNCmBgYHtyIHN0YXRpb25fc3VtbWFyeSwgZWNobz1GQUxTRSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OCwgd2FybmluZz1GQUxTRX0NCndlZWtfcHJlZGljdGlvbnMgJT4lIA0KICAgIG11dGF0ZShpbnRlcnZhbDYwID0gbWFwKGRhdGEsIHB1bGwsIGludGVydmFsNjApLA0KICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X3N0YXRpb25faWQpLCANCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIA0KICAgICAgICAgICBzdGFydF9sbmcgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfbG5nKSwNCiAgICAgICAgICAgZG90dyA9IG1hcChkYXRhLCBwdWxsLCBkb3R3KSApICU+JQ0KICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIA0KICAgICAgICAgICBzdGFydF9sYXQsIE9ic2VydmVkLCBQcmVkaWN0aW9uLCBSZWdyZXNzaW9uLA0KICAgICAgICAgICBkb3R3KSAlPiUNCiAgICB1bm5lc3QoKSAlPiUNCiAgZmlsdGVyKFJlZ3Jlc3Npb24gPT0gIkRUaW1lX1NwYWNlX0ZFX3RpbWVMYWdzIiklPiUNCiAgbXV0YXRlKHdlZWtlbmQgPSBpZmVsc2UoZG90dyAlaW4lIGMoIuWRqOaXpSIsICLlkajlha0iKSwgIldlZWtlbmQiLCAiV2Vla2RheSIpLA0KICAgICAgICAgdGltZV9vZl9kYXkgPSBjYXNlX3doZW4oaG91cihpbnRlcnZhbDYwKSA8IDcgfCBob3VyKGludGVydmFsNjApID4gMTkgfiAiT3Zlcm5pZ2h0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gNyAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxMCB+ICJBTSBSdXNoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTAgJiBob3VyKGludGVydmFsNjApIDwgMTUgfiAiTWlkLURheSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob3VyKGludGVydmFsNjApID49IDE1ICYgaG91cihpbnRlcnZhbDYwKSA8PSAxOSB+ICJQTSBSdXNoIikpICU+JQ0KICBncm91cF9ieShzdGFydF9zdGF0aW9uX2lkLCB3ZWVrZW5kLCB0aW1lX29mX2RheSwgc3RhcnRfbG5nLCBzdGFydF9sYXQpICU+JQ0KICBzdW1tYXJpemUoTUFFID0gbWVhbihhYnMoT2JzZXJ2ZWQtUHJlZGljdGlvbiksIG5hLnJtID0gVFJVRSkpJT4lDQogIGdncGxvdCguKSsNCiAgZ2VvbV9zZihkYXRhID0gTllDZW5zdXMsIGNvbG9yID0gImdyZXkiLCBmaWxsID0gInRyYW5zcGFyZW50IikrDQogIGdlb21fcG9pbnQoYWVzKHggPSBzdGFydF9sbmcsIHkgPSBzdGFydF9sYXQsIGNvbG9yID0gTUFFKSwgDQogICAgICAgICAgICAgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIHNpemUgPSAwLjUsIGFscGhhID0gMC40KSsNCiAgc2NhbGVfY29sb3JfY29udGludW91cyhsb3cgPSAiI0ZGRDlFNiIsIGhpZ2ggPSAiIzYyMkE4QyIsIG5hbWU9ICJNQUUiKSsNCiAgeWxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sYXQpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sYXQpKSsNCiAgeGxpbShtaW4oZGF0X2NlbnN1cyRzdGFydF9sbmcpLCBtYXgoZGF0X2NlbnN1cyRzdGFydF9sbmcpKSsNCiAgZmFjZXRfZ3JpZCh3ZWVrZW5kfnRpbWVfb2ZfZGF5KSsNCiAgbGFicyh0aXRsZT0iTWVhbiBBYnNvbHV0ZSBFcnJvcnMgYnkgc3RhdGlvbiBhbmQgdGhlIGRheSBvZiB0aGUgd2VlaywgVGVzdCBTZXQiKSsNCiAgbWFwVGhlbWUoKQ0KICANCmBgYA0KDQpGb2N1c2luZyBvbiB0aGUgbW9ybmluZyBjb21tdXRlLCB0aGUgbW9kZWwgZG9lc24ndCBwZXJmb3JtIHdlbGwgZm9yIHNwZWNpZmljIHNvY2lvLWVjb25vbWljIGdyb3VwcyBjaGFyYWN0ZXJpemVkIGJ5IGhpZ2hlciBpbmNvbWUsIGxvd2VyIHB1YmxpYyB0cmFuc2l0IHVzYWdlLCBhbmQgaGlnaGVyIHdoaXRlIHBvcHVsYXRpb24gJS4NCg0KYGBge3Igc3RhdGlvbl9zdW1tYXJ5Miwgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFIH0NCndlZWtfcHJlZGljdGlvbnMgJT4lIA0KICAgIG11dGF0ZShpbnRlcnZhbDYwID0gbWFwKGRhdGEsIHB1bGwsIGludGVydmFsNjApLA0KICAgICAgICAgICBzdGFydF9zdGF0aW9uX2lkID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X3N0YXRpb25faWQpLCANCiAgICAgICAgICAgc3RhcnRfbGF0ID0gbWFwKGRhdGEsIHB1bGwsIHN0YXJ0X2xhdCksIA0KICAgICAgICAgICBzdGFydF9sbmcgPSBtYXAoZGF0YSwgcHVsbCwgc3RhcnRfbG5nKSwNCiAgICAgICAgICAgZG90dyA9IG1hcChkYXRhLCBwdWxsLCBkb3R3KSwNCiAgICAgICAgICAgUGVyY2VudF9UYWtpbmdfUHVibGljX1RyYW5zID0gbWFwKGRhdGEsIHB1bGwsIFBlcmNlbnRfVGFraW5nX1B1YmxpY19UcmFucyksDQogICAgICAgICAgIE1lZF9JbmMgPSBtYXAoZGF0YSwgcHVsbCwgTWVkX0luYyksDQogICAgICAgICAgIFBlcmNlbnRfV2hpdGUgPSBtYXAoZGF0YSwgcHVsbCwgUGVyY2VudF9XaGl0ZSkpICU+JQ0KICAgIHNlbGVjdChpbnRlcnZhbDYwLCBzdGFydF9zdGF0aW9uX2lkLCBzdGFydF9sbmcsIA0KICAgICAgICAgICBzdGFydF9sYXQsIE9ic2VydmVkLCBQcmVkaWN0aW9uLCBSZWdyZXNzaW9uLA0KICAgICAgICAgICBkb3R3LCBQZXJjZW50X1Rha2luZ19QdWJsaWNfVHJhbnMsIE1lZF9JbmMsIFBlcmNlbnRfV2hpdGUpICU+JQ0KICAgIHVubmVzdCgpICU+JQ0KICBmaWx0ZXIoUmVncmVzc2lvbiA9PSAiRFRpbWVfU3BhY2VfRkVfdGltZUxhZ3MiKSU+JQ0KICBtdXRhdGUod2Vla2VuZCA9IGlmZWxzZShkb3R3ICVpbiUgYygi5ZGo5pelIiwgIuWRqOWFrSIpLCAiV2Vla2VuZCIsICJXZWVrZGF5IiksDQogICAgICAgICB0aW1lX29mX2RheSA9IGNhc2Vfd2hlbihob3VyKGludGVydmFsNjApIDwgNyB8IGhvdXIoaW50ZXJ2YWw2MCkgPiAxOSB+ICJPdmVybmlnaHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSA3ICYgaG91cihpbnRlcnZhbDYwKSA8IDEwIH4gIkFNIFJ1c2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaG91cihpbnRlcnZhbDYwKSA+PSAxMCAmIGhvdXIoaW50ZXJ2YWw2MCkgPCAxNSB+ICJNaWQtRGF5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhvdXIoaW50ZXJ2YWw2MCkgPj0gMTUgJiBob3VyKGludGVydmFsNjApIDw9IDE5IH4gIlBNIFJ1c2giKSkgJT4lDQogIGZpbHRlcih0aW1lX29mX2RheSA9PSAiQU0gUnVzaCIpICU+JQ0KICBncm91cF9ieShzdGFydF9zdGF0aW9uX2lkLCBQZXJjZW50X1Rha2luZ19QdWJsaWNfVHJhbnMsIE1lZF9JbmMsIFBlcmNlbnRfV2hpdGUpICU+JQ0KICBzdW1tYXJpemUoTUFFID0gbWVhbihhYnMoT2JzZXJ2ZWQtUHJlZGljdGlvbiksIG5hLnJtID0gVFJVRSkpJT4lDQogIGdhdGhlcigtc3RhcnRfc3RhdGlvbl9pZCwgLU1BRSwga2V5ID0gInZhcmlhYmxlIiwgdmFsdWUgPSAidmFsdWUiKSU+JQ0KICBnZ3Bsb3QoLikrDQogIGdlb21fcG9pbnQoYWVzKHggPSB2YWx1ZSwgeSA9IE1BRSksIGFscGhhID0gMC40KSsNCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSB2YWx1ZSwgeSA9IE1BRSxjb2xvcj0iIzYyMkE4QyIpLCBtZXRob2QgPSAibG0iLCBzZT0gRkFMU0UpKw0KICBmYWNldF93cmFwKH52YXJpYWJsZSwgc2NhbGVzID0gImZyZWUiKSsNCiAgbGFicyh0aXRsZT0iRXJyb3JzIGFzIGEgZnVuY3Rpb24gb2Ygc29jaW8tZWNvbm9taWMgdmFyaWFibGVzIiwNCiAgICAgICB5PSJNZWFuIEFic29sdXRlIEVycm9yIChUcmlwcykiKSsNCiAgcGxvdFRoZW1lKCkNCiAgDQpgYGANCg0KIyMgQ3Jvc3MtdmFsaWRhdGlvbg0KDQpUbyBmdXJ0aGVyIHZhbGlkYXRlIHRoZSBnZW5lcmFsaXphYmlsaXR5IG9mIHRoZSBtb2RlbCwgSSBjcm9zcyB2YWxpZGF0ZSB0aGUgbW9kZWwgYnkgdGltZSBhbmQgc3BhY2UuIFRvIG1hbmFnZSB0aGUgbGFyZ2UgbnVtYmVyIG9mIGRhdGEgcG9pbnRzLCB0aGUgbW9kZWwgZGVlbWVkIG1vc3QgZWZmZWN0aXZlIHdhcyBzdWJqZWN0ZWQgdG8gYSA1MC1mb2xkIGNyb3NzLXZhbGlkYXRpb24uIFRoaXMgbWVhbnMgdGhhdCB0aGUgZGF0YSB3YXMgZGl2aWRlZCBpbnRvIDUwIHBhcnRzLCB3aXRoIHRoZSBtb2RlbCBiZWluZyB0cmFpbmVkIG9uIDQ5IHBhcnRzIGFuZCB0ZXN0ZWQgb24gdGhlIDEgcmVtYWluaW5nIHBhcnQsIHRoaXMgcHJvY2VzcyBiZWluZyByZXBlYXRlZCA1MCB0aW1lcyB3aXRoIGRpZmZlcmVudCBwYXJ0cyBlYWNoIHRpbWUuDQoNCkFzIHdlIGNhbiBzZWUsIHRoZSBtZWFuIGFic29sdXRlIGVycm9yIGlzIHNsaWdodGx5IG92ZXIgMC4zNy4gSW4gdGVybXMgb2YgdGhlIENWIGdvb2RuZXNzIG9mIGZpdCBtZXRyaWNzLHRoZSBtZXRyaWNzIGFyZSBjbHVzdGVyZCBjbG9zZSB0byB0aGUgbWFuLCBzdWdnZXN0aW5nIHRoYXQgdGhlIG1vZGVsIHBlcmZvcm1zIGNvbnNpc3RlbnRseSBhbmQgc2hvd3MgZ29vZCBnZW5lcmFsaXphYmlsdHkuDQpgYGB7ciBDViwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmN0cmwgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDUwKQ0KDQpjdkZpdCA8LSB0cmFpbihUcmlwX0NvdW50IH4gIHN0YXJ0X3N0YXRpb25fbmFtZSArICBob3VyKGludGVydmFsNjApICsgZG90dyArIFRlbXBlcmF0dXJlICsgUHJlY2lwaXRhdGlvbiArIGxhZ0hvdXIgKyBsYWcySG91cnMgK2xhZzNIb3VycyArIGxhZzEySG91cnMgKyBsYWcxZGF5ICwNCiAgICAgZGF0YT1yaWRlLlRyYWluJT4lc2VsZWN0KFRyaXBfQ291bnQsIHN0YXJ0X3N0YXRpb25fbmFtZSxpbnRlcnZhbDYwLGRvdHcsVGVtcGVyYXR1cmUsUHJlY2lwaXRhdGlvbixsYWdIb3VyLGxhZzJIb3VycyxsYWczSG91cnMsbGFnMTJIb3VycyxsYWcxZGF5KSwgbWV0aG9kID0ibG0iLCB0ckNvbnRyb2wgPSBjdHJsLCBuYS5hY3Rpb24gPSBuYS5wYXNzKQ0KDQpjdkZpdA0KDQpzYXZlUkRTKGN2Rml0LCBmaWxlID0gImN2Rml0X21vZGVsLnJkcyIpDQoNCmBgYA0KDQpgYGB7ciBsb2FkX0NWLCBlY2hvPUZBTFNFfQ0KY3ZGaXQgPC0gcmVhZFJEUyhmaWxlID0gImN2Rml0X21vZGVsLnJkcyIpDQpjdkZpdA0KYGBgDQoNCmBgYHtyIENWX2thYmxlLCBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD02fQ0KY3ZGaXQkcmVzYW1wbGUgJT4lDQogIHN1bW1hcmlzZShNQUUgPSBtZWFuKGN2Rml0JHJlc2FtcGxlWywzXSksDQogICAgICAgICAgICBzZChjdkZpdCRyZXNhbXBsZVssM10pKSU+JQ0KICBrYmwoY29sLm5hbWVzID0gYygiTWVhbiBBYnNvbHV0ZSBFcnJvciIsIlN0YW5kYXJkIERldmlhdGlvbiBvZiBNQUUiKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKQ0KICANCmBgYA0KDQpgYGB7cn0NCmRwbHlyOjpzZWxlY3QoY3ZGaXQkcmVzYW1wbGUsIC1SZXNhbXBsZSkgJT4lDQogIGdhdGhlcihtZXRyaWMsIHZhbHVlKSAlPiUNCiAgbGVmdF9qb2luKGdhdGhlcihjdkZpdCRyZXN1bHRzWzI6NF0sIG1ldHJpYywgbWVhbikpICU+JQ0KICBnZ3Bsb3QoYWVzKHZhbHVlKSkgKyANCiAgICBnZW9tX2hpc3RvZ3JhbShiaW5zPTM1LCBmaWxsID0gIiNGRkE3QzQiKSArDQogICAgZmFjZXRfd3JhcCh+bWV0cmljKSArDQogICAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lYW4pLCBjb2xvdXIgPSAiI0IxNEE5MCIsIGxpbmV0eXBlID0gMywgc2l6ZSA9IDEuNSkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDEpKSArDQogICAgbGFicyh4PSJHb29kbmVzcyBvZiBGaXQiLCB5PSJDb3VudCIsIHRpdGxlPSJDViBHb29kbmVzcyBvZiBGaXQgTWV0cmljcyIsDQogICAgICAgICBzdWJ0aXRsZSA9ICI1MCBmb2xkcywgQWNyb3NzLWZvbGQgbWVhbiByZXByZW50ZWQgYXMgZG90dGVkIGxpbmVzIikgKw0KICAgIHBsb3RUaGVtZSgpDQpgYGANCg0KIyBDb25jbHVzaW9uDQoNCkluIHRoaXMgcHJvamVjdCwgdGhlIGZvY3VzIHdhcyBvbiBkZXZlbG9waW5nIGEgcHJlZGljdGl2ZSBtb2RlbCBmb3IgYmlrZSByZWJhbGFuY2luZyB3aXRoaW4gTmV3IFlvcmsgQ2l0eSdzIENpdGkgQmlrZSBzeXN0ZW0gdXNpbmcgYSBjb21iaW5hdGlvbiBvZiBzZXJpYWwgZGF0YSwgc3BhdGlhbCBjaGFyYWN0ZXJpc3RpY3MsIGFuZCB0aW1lLWxhZyB2YXJpYWJsZXMuIFRoZSBpbmNvcnBvcmF0aW9uIG9mIGFtZW5pdHkgZmVhdHVyZXMgZGlkIG5vdCBzaWduaWZpY2FudGx5IGVuaGFuY2UgdGhlIG1vZGVsJ3MgcGVyZm9ybWFuY2UsIGluZGljYXRpbmcgdGhhdCB0aGUgc2VsZWN0ZWQgdmFyaWFibGVzIHdlcmUgYWxyZWFkeSBzdWZmaWNpZW50IGluIGNhcHR1cmluZyB0aGUgcGF0dGVybnMgbmVjZXNzYXJ5IGZvciBhY2N1cmF0ZSBiaWtlLXNoYXJlIHJpZGVyc2hpcCBwcmVkaWN0aW9ucy4gRGVzcGl0ZSBlbmNvdW50ZXJpbmcgc3BhY2UtdGltZSBlcnJvcnMsIHdpdGggYSB0ZW5kZW5jeSB0byB1bmRlcnByZWRpY3Qgb3ZlcmFsbCByaWRlcnNoaXAsIHRoZSBtb2RlbCBkZW1vbnN0cmF0ZXMgZWZmZWN0aXZlbmVzcyBhbmQgcHJvdmlkZXMgYSBzb2xpZCBiYXNpcyBmb3IgcGxhbm5pbmcgYW5kIG9wdGltaXppbmcgQ2l0aSBCaWtlJ3MgcmViYWxhbmNpbmcgb3BlcmF0aW9ucy4NCg0KVG8gZnVydGhlciBpbXByb3ZlIHRoZSBtb2RlbCdzIGFjY3VhcmN5IGFuZCBnZW5lcmFsaXphYmlsdHksIG1vcmUgZGVlcGVyIGFuYWx5c2lzIGludG8gdGhlIHRlbXBvcmFsIHBhdHRlcm5zIGFuZCBzcGF0aWFsIGRpc3RyaWJ1dGlvbnMgb2YgcmlkZXJzaGlwIGNhbiBiZSB0YWtlbiBpbnRvIGNvbnNpZGVyYXRpb24uDQo=