Introduction

Bike share is a dock-based sharing system, which is also a sustainable and convenient transportation option. The system can provide access to bikes for short-term use, ranging from several minutes to hours. However, the most difficult operational problems is the need to re-balance bikes across the network. As bike share is not useful if a dock has no bikes to pick up, nor if there are no opening docking spaces to deposit. Therefore, the re-balancing is the practice of anticipating bike share demand for all docks at all times and manually redistributing bikes to ensure a bike or a docking space is available when needed.

In this assignment, I’ll dive into the bike share system in New York City (Citi Bike) and forecast space/time demand for bike share pickups. My focused area and time frame is Manhattan, May 2023. By developing an algorithm to predict the trip starts across time and space, I try to en-vision and inform a bike re-balancing plan to ensure supply and enhance efficiency.

Specifically, several mechanisms will be taken in light of expected outcomes. For example, there will be trucks to move bikes between different locations. Also, some incentives will be offered if riders manage to move a bike from place to place.

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()`).

Conclusion

In this project, the focus was on developing a predictive model for bike rebalancing within New York City’s Citi Bike system using a combination of serial data, spatial characteristics, and time-lag variables. The incorporation of amenity features did not significantly enhance the model’s performance, indicating that the selected variables were already sufficient in capturing the patterns necessary for accurate bike-share ridership predictions. Despite encountering space-time errors, with a tendency to underpredict overall ridership, the model demonstrates effectiveness and provides a solid basis for planning and optimizing Citi Bike’s rebalancing operations.

To further improve the model’s accuarcy and generalizabilty, more deeper analysis into the temporal patterns and spatial distributions of ridership can be taken into consideration.

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=