This assignment focuses on analyzing public transport operations in Mumbai. You are provided with a dataset containing trip details, passenger counts, and weather conditions.

Instructions:

  1. Complete the R code for each question. The code block must contain clean, commented R code.
  2. Handle “dirty data” (negative values, inconsistent casing, missing values) in the pre-processing section.
  3. Provide a 2-3 sentence interpretation of the visualization. The visualization must have clear labels, appropriate scales, and a professional theme (e.g., theme_minimal()).
  4. Provide an analytical interpretation of each visualization. A brief paragraph explaining what the plot reveals about Mumbai’s transport system.
  5. Submit the R notebook containing the R code and the interpretation. The notebook should execute without any errors. Also submit a rendered version of the notebook, preferably in PDF format (Rmd -> HTML -> PDF).

For more information on R notebooks, visit the following link: https://bookdown.org/yihui/rmarkdown/notebook.html

Part 1: Data Pre-processing

Before plotting, clean the dataset. Handle the negative boarding counts, inconsistent weather names (e.g., ‘monsoon’ vs ‘Monsoon’), and convert time strings into usable time objects.

df$weather_condition <- tolower(df$weather_condition)

df$passenger_count_boarding[df$passenger_count_boarding < 0] <- NA
df$passenger_count_alighting[df$passenger_count_alighting < 0] <- NA

df$date <- ymd(df$date)

df$arrival_time_scheduled   <- hms(df$arrival_time_scheduled)
df$arrival_time_actual      <- hms(df$arrival_time_actual)
df$departure_time_scheduled <- hms(df$departure_time_scheduled)
df$departure_time_actual    <- hms(df$departure_time_actual)

df_clean <- df[complete.cases(
  df$passenger_count_boarding,
  df$passenger_count_alighting,
  df$arrival_time_scheduled,
  df$arrival_time_actual,
  df$weather_condition), ]

df_clean$boarding_num <- suppressWarnings(
  as.numeric(as.character(df_clean$passenger_count_boarding)) )

#Data Clean check
nrow(df)
[1] 1500
nrow(df_clean)
[1] 1249
sum(is.na(df_clean$passenger_count_boarding))
[1] 0
sum(is.na(df_clean$passenger_count_alighting))
[1] 0

Part 2: Visualizing with ggplot2

Q1. Distribution of Boarding by Route (Faceting)

Create a histogram for passenger_count_boarding. Use faceting to display a separate plot for each route_id.

df_clean$route_type <- ifelse(
  df_clean$route_id %in% c("MUM_Route_C", "MUM_Route_E"),
  "High variability routes",
  "Stable routes" )

ggplot( df_clean,
  aes( x = boarding_num,
    fill = route_type ) ) +
  geom_histogram(
    bins = 15,
    color = "white",
    na.rm = TRUE ) +
  facet_wrap(~ route_id, scales = "free_y") +
  scale_fill_manual(
    values = c(
      "High variability routes" = "#E67E22",
      "Stable routes" = "#628141" ) ) +
  labs(
    title = "Distribution of Passenger Boarding by Route",
    subtitle = "Routes C and E show higher variability and demand spikes",
    x = "Passenger Boarding Count",
    y = "Frequency",
    fill = "Route Type" ) +
  theme_minimal()

Interpretation: [Routes C and E exhibit greater variability in passenger boarding, with longer right tails and higher-frequency peaks at larger boarding values. This indicates intermittent demand surges, possibly driven by land-use concentration or transfer activity along these corridors. In contrast, the remaining routes display more consistent and evenly distributed boarding patterns, suggesting steadier demand across time.]

Q2. Ridership Dynamics (Conditional Coloring)

Create a scatter plot showing Boarding Count vs. Alighting Count. Color the points based on weather_condition.

ggplot(df_clean,
       aes(x = passenger_count_boarding,
           y = passenger_count_alighting,
           color = ifelse(weather_condition %in% c("monsoon","rainy"),
                          "Greater impact weather",
                          "Less impact weather"))) +
  geom_point(alpha = 0.6) +
  facet_wrap(~weather_condition) +
  scale_color_manual(values = c("Greater impact weather" = "#E67E22",
                                "Less impact weather" = "#628141")) +
  labs(title = "Boarding vs Alighting Across Weather Conditions",
       subtitle = "Monsoon and rainy conditions show greater impact on passenger movement",
       x = "Passenger Boarding Count",
       y = "Passenger Alighting Count",
       color = "Weather Impact") +
  theme_minimal()

Interpretation: [Passenger boarding and alighting patterns show greater dispersion during monsoon and rainy conditions, indicating increased variability in passenger movement due to weather-related disruptions. In contrast, sunny, cloudy, and partly cloudy conditions exhibit more stable and predictable passenger flows, suggesting minimal weather impact. These patterns highlight the need for weather-responsive operational planning, such as flexible scheduling and buffer capacity during adverse weather conditions.]

Q3. Hourly Peak Demand (Faceting)

Extract the hour from arrival_time_scheduled. Create a bar chart of total boarding per hour, faceted by day_of_week.

df_clean$arrival_hour <- hour(df_clean$arrival_time_actual)
df_clean$day_type <- ifelse(
  df_clean$day_of_week %in% c("Saturday", "Sunday"),
  "Weekend",
  "Weekday" )

hourly_boarding_type <- aggregate(
  passenger_count_boarding ~ arrival_hour + day_type,
  data = df_clean,
  sum,
  na.rm = TRUE )

ggplot( hourly_boarding_type,
  aes(
    x = arrival_hour,
    y = passenger_count_boarding,
    fill = day_type ) ) +
  geom_col(position = "dodge") +
  scale_fill_manual(
    values = c(
      "Weekday" = "#628141",
      "Weekend" = "#E67E22" ) ) +
  labs(
    title = "Hourly Passenger Boarding: Weekdays vs Weekends",
    subtitle = "Weekday passenger boarding is consistently higher",
    x = "Hour of Day",
    y = "Total Passenger Boarding",
    fill = "Day Type"
  ) +
  theme_minimal()

Interpretation: [Hourly passenger boarding on weekdays is consistently higher than weekends across all hours, with pronounced peaks during typical commuting periods. Weekend demand remains lower and flatter, indicating predominantly discretionary travel. This pattern supports higher peak-hour frequencies and greater fleet deployment on weekdays, while reduced or evenly spaced headway on weekends can improve operational efficiency without affecting service quality.]

Q4. Delay Distribution

Calculate delay_minutes (Actual - Scheduled). Create a scatter plot of Scheduled Time vs Actual Time, coloring points by whether the bus was “Late” (delay > 5 mins) or “On-Time”.

df_clean$scheduled_minutes <-
  as.numeric(df_clean$arrival_time_scheduled) / 60

df_clean$actual_minutes <-
  as.numeric(df_clean$arrival_time_actual) / 60

df_clean$delay_status <- ifelse(
  df_clean$actual_minutes > df_clean$scheduled_minutes,
  "Late",
  "OnTime" )

df_clean$delay_status <- factor(
  df_clean$delay_status,
  levels = c("OnTime", "Late") )

ggplot(df_clean, aes(
  x = scheduled_minutes,
  y = actual_minutes,
  color = delay_status )) +
  geom_point(alpha = 0.6) +
  geom_abline(
    intercept = 0,
    slope = 1,
    linetype = "dashed",
    color = "black" ) +
  coord_cartesian(
    xlim = c(350, 1150),
    ylim = c(350, 1150) ) +
  scale_color_manual(values = c(
    "OnTime" = "#628141",
    "Late"   = "#E67E22" )) +
  labs(
    title = "Scheduled vs Actual Arrival Time (Focused View)",
    subtitle = "Deviations from the 45-degree line indicate delays",
    x = "Scheduled Arrival Time (minutes from midnight)",
    y = "Actual Arrival Time (minutes from midnight)",
    color = "Status" ) +
  theme_minimal()

Interpretation: [The majority of trips lie close to the 45-degree reference line, indicating good schedule adherence during active service hours. However, consistent deviations above the line reflect systematic late arrivals, particularly as scheduled times increase, suggesting cumulative delays over the service period. This indicates a need for schedule recovery time or headway adjustments to improve reliability.]


Part 3: Conditioning with Lattice

Q5. Density Conditioning

Using the lattice package, create a density plot (densityplot) of passenger_count_boarding conditioned on day_of_week.

df_clean$day_of_week <- factor(
  df_clean$day_of_week,
  levels = c("Monday", "Tuesday", "Wednesday",
             "Thursday", "Friday", "Saturday", "Sunday") )
densityplot(
  ~ passenger_count_boarding | day_of_week,
  data = df_clean,
  layout = c(4, 2),
  groups = ifelse(day_of_week %in% c("Saturday", "Sunday"),
                  "Weekend", "Weekday"),
  plot.points = FALSE,
  col = c("#628141", "#E67E22"),
  lwd = 3,
  main = "Passenger Boarding Density by Day of Week",
  xlab = "Passenger Boarding Count",
  ylab = "Density",
  auto.key = TRUE )

Interpretation: [Weekdays exhibit consistent and sharply peaked boarding densities, reflecting stable commuter-driven demand, with mid-week days showing the highest reliability. In contrast, weekends display broader and flatter distributions, indicating lower but more evenly spread travel demand. This suggests the need for peak-oriented scheduling on weekdays and flexible service provision on weekends.]

Q6. Using Shingles for Temporal Analysis

Create a shingle for the arrival_time_scheduled variable (e.g., 3-4 overlapping windows). Use xyplot to plot passenger_count_boarding vs. passenger_count_alighting conditioned on the time shingles.

df_clean$arrival_minutes <- as.numeric(df_clean$arrival_time_actual)
df_clean$time_of_day <- cut(
  df_clean$arrival_minutes,
  breaks = c(0, 6*3600, 10*3600, 15*3600, 24*3600),
  labels = c("Early Morning", "Morning Peak", "Midday", "Evening"),
  include.lowest = TRUE )

xyplot(
passenger_count_alighting ~ passenger_count_boarding | time_of_day,
data = df_clean,
groups = factor(
ifelse(df_clean$time_of_day == "Evening",
"Evening", "Other Periods"),
levels = c("Evening", "Other Periods") ),
  xlab = "Passenger Boarding Count",
  ylab = "Passenger Alighting Count",
  main = "Boarding vs Alighting by Time of Day",
  pch = 16,
  col = c("#E67E22", "#628141"),
  alpha = 0.6,
  auto.key = list(title = "Time Period", columns = 1) )

Interpretation: [The evening period exhibits the highest simultaneous levels and widest dispersion of passenger boarding and alighting, indicating intense bidirectional movement associated with return trips, transfers, and activity-based travel. In contrast, morning peak demand is more directional, with comparatively constrained alighting relative to boarding, while early morning and midday show lower and more stable interactions. This suggests that evening operations require greater dwell-time management, platform capacity, and schedule recovery buffers than other time periods.]

Q7. Route Performance (Lattice Boxplots)

Use bwplot to compare the distribution of passenger_count_boarding conditioned on route_id.

df_clean$route_highlight <- ifelse(
  df_clean$route_id %in% c("MUM_Route_C", "MUM_Route_E"),
  "Higher Variability Routes",
  "Other Routes" )
bwplot(
  passenger_count_boarding ~ route_id,
  data = df_clean,
  groups = df_clean$route_highlight,
  box.width = 0.7,
  lwd = 2,
  auto.key = list(
    space = "right",
    title = "Route Category" ),
  xlab = "Route ID",
  ylab = "Passenger Boarding Count",
  main = "Passenger Boarding Distribution by Route",
  par.settings = list(
    box.rectangle = list(col = c("#628141", "#E67E22")),
    box.umbrella  = list(col = c("#628141", "#E67E22")),
    plot.symbol   = list(col = c("#628141", "#E67E22")) ) )

Interpretation: [MUM_Route_C and MUM_Route_E has greater demand variability and pronounced peak loads. In contrast, MUM_Route_A, MUM_Route_B, and MUM_Route_D has stable and predictable passenger demand. This suggests that Routes C and E require flexible headways or higher-capacity vehicles, while Routes A, B, and D can be efficiently operated with fixed schedules and standard fleet deployment.]


Part 4: Synthesis & Operations

Q8. Dwell Time and Weather (ggplot2)

Calculate “Dwell Time” (Actual Departure - Actual Arrival). Create a scatter plot of Boarding Count vs. Dwell Time. Facet by weather_condition and color by route_id.

df_clean$dwell_time_minutes <-
as.numeric(df_clean$departure_time_actual - df_clean$arrival_time_actual) / 60

df_clean_q8 <- df_clean %>%
filter(dwell_time_minutes >= 0, dwell_time_minutes <= 30)

ggplot(
  df_clean_q8,
  aes(
    x = passenger_count_boarding,
    y = dwell_time_minutes) ) +
  geom_point(color = "#628141", alpha = 0.5) +
  geom_smooth(method = "lm", se = FALSE, color = "#E67E22") +
  facet_wrap(~ weather_condition) +
  labs(
title = "Impact of Boarding Volume on Dwell Time Across Weather Conditions",
subtitle = "Weather influences how boarding volumes translate into dwell time",
    x = "Passenger Boarding Count",
    y = "Dwell Time (minutes)" ) +
  theme_minimal()

Interpretation: [During monsoon and rainy weather, buses take longer to stop even when there are not many passengers, showing that rain slows down boarding and operations more than passenger numbers do.

In sunny and partly cloudy weather, boarding is quicker and dwell time increases gradually as passenger numbers increase, indicating smoother and more efficient movement.

This shows that weather itself affects bus stopping time, not just how many people are boarding.

Therefore, bus schedules should allow extra stopping time during bad weather, instead of using the same assumptions for all conditions.]

Q9. Specific Stop Analysis (Lattice)

Filter data for the top 3 busiest stops. Create an xyplot showing boarding counts over date, conditioned on stop_name.

df_clean$temp_index <- seq_len(nrow(df_clean))

top_stops <- df_clean %>%
  group_by(stop_name) %>%
  summarise(
    total_boarding = sum(passenger_count_boarding, na.rm = TRUE)
  ) %>%
  arrange(desc(total_boarding)) %>%
  slice(1:3) %>%
  pull(stop_name)

df_top_stops <- df_clean %>%
  filter(stop_name %in% top_stops)

xyplot(
  passenger_count_boarding ~ temp_index | stop_name,
  data = df_top_stops,
  type = c("p", "l"),
  pch = 16,
  col = "#628141",
  alpha = 0.6,
  layout = c(1, 3),
  xlab = "Observation Sequence (Time Proxy)",
  ylab = "Passenger Boarding Count",
  main = "Passenger Boarding Trends at Top 3 Busiest Stops",
  panel = function(x, y, ...) 
    { panel.xyplot(x, y, ...)
    panel.rect(
    xleft = min(x),
    ybottom = 20,
    xright = max(x),
    ytop = 50,
    border = "black",
    lty = 2 ) } )

Interpretation: [Nerul, Borivali, and Belapur consistently operate within a common high-demand boarding range, indicating persistent passenger pressure at these locations rather than occasional spikes.

Borivali and Belapur exhibit higher variability and more frequent peaks, suggesting stronger sensitivity to time-of-day effects, surrounding land-use activity, or transfer movements.

Nerul shows comparatively steadier boarding levels, indicating a more predictable demand pattern.

The repeated clustering of observations within the highlighted demand band confirms that these stops act as structural demand anchors in the network.

From an operational perspective, these stops should be prioritised for capacity management, dwell-time control, and passenger facility upgrades, as congestion or delay here is likely to propagate along the route.]

Q10. Reliability Heatmap (ggplot2)

Create a heatmap (geom_tile) where the X-axis is day_of_week, the Y-axis is route_id, and the fill color represents the average delay.

df_clean$delay_minutes <-
  (as.numeric(df_clean$arrival_time_actual) -
  as.numeric(df_clean$arrival_time_scheduled)) / 60
delay_summary <- df_clean %>%
  group_by(route_id, day_of_week) %>%
  summarise(
    avg_delay = mean(delay_minutes, na.rm = TRUE),
    .groups = "drop" )

network_avg <- mean(delay_summary$avg_delay, na.rm = TRUE)

delay_summary <- delay_summary %>%
  mutate( delay_vs_network = avg_delay - network_avg )

ggplot( delay_summary,
  aes(
    x = day_of_week,
    y = route_id,
    fill = delay_vs_network ) ) +
  geom_tile(color = "white") +
  scale_fill_gradientn(
    colours = c("#40513B", "#628141", "#E5D9B6", "#E67E22"),
    values = scales::rescale(c(
      min(delay_summary$delay_vs_network),
      -5, 0,
      max(delay_summary$delay_vs_network) )),
    name = "Deviation from\nNetwork Avg (min)" ) +
  labs(
    title = "Route Reliability Relative to Network Average",
    subtitle = "Routes performing better or worse than network average by day",
    x = "Day of Week",
    y = "Route ID"
  ) +
  theme_minimal()

Interpretation: [MUM_Route_B and MUM_Route_D perform better than the network average on multiple weekdays, suggesting more stable operations and better schedule adherence.

MUM_Route_E shows comparatively poorer reliability on certain mid-week days, indicating recurring operational constraints that may be linked to congestion or route design.

MUM_Route_C exhibits strong performance on some days but deteriorates on others, reflecting inconsistent reliability rather than persistent underperformance.

These patterns highlight the need for route- and day-specific reliability interventions, such as targeted schedule adjustments, fleet allocation, or operational priority measures, instead of uniform system-wide solutions.] ```

LS0tDQp0aXRsZTogJ0Fzc2lnbm1lbnQgIzInDQpzdWJ0aXRsZTogRGF0YSBWaXN1YWxpemF0aW9uDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgd29yZF9kb2N1bWVudDogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KICANCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBMb2FkaW5nIG5lY2Vzc2FyeSBsaWJyYXJpZXMNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGxhdHRpY2UpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCg0Kc2V0d2QoIkQ6XFxDRVBUXFw0dGhfU2VtXFxEYXRhX0FuYWx5c2lzXFxVVDQ2MDktMjAyNi1tYWluXFxVVDQ2MDktMjAyNi1tYWluIikNCiNmaWxlbmFtZTwtIm11bWJhaV9idXNfZGF0YS5jc3YiDQoNCmRmIDwtcmVhZC5jc3YoIm11bWJhaV9idXNfZGF0YS5jc3YiKQ0KDQpgYGANCg0KDQpUaGlzIGFzc2lnbm1lbnQgZm9jdXNlcyBvbiBhbmFseXppbmcgcHVibGljIHRyYW5zcG9ydCBvcGVyYXRpb25zIGluIE11bWJhaS4gWW91IGFyZSBwcm92aWRlZCB3aXRoIGEgZGF0YXNldCBjb250YWluaW5nIHRyaXAgZGV0YWlscywgcGFzc2VuZ2VyIGNvdW50cywgYW5kIHdlYXRoZXIgY29uZGl0aW9ucy4gDQoNCioqSW5zdHJ1Y3Rpb25zOioqDQoNCjEuIENvbXBsZXRlIHRoZSBSIGNvZGUgZm9yIGVhY2ggcXVlc3Rpb24uIFRoZSBjb2RlIGJsb2NrIG11c3QgY29udGFpbiBjbGVhbiwgY29tbWVudGVkIFIgY29kZS4NCjEuIEhhbmRsZSAiZGlydHkgZGF0YSIgKG5lZ2F0aXZlIHZhbHVlcywgaW5jb25zaXN0ZW50IGNhc2luZywgbWlzc2luZyB2YWx1ZXMpIGluIHRoZSBwcmUtcHJvY2Vzc2luZyBzZWN0aW9uLg0KMS4gUHJvdmlkZSBhIDItMyBzZW50ZW5jZSBpbnRlcnByZXRhdGlvbiBvZiB0aGUgdmlzdWFsaXphdGlvbi4gVGhlIHZpc3VhbGl6YXRpb24gbXVzdCBoYXZlIGNsZWFyIGxhYmVscywgYXBwcm9wcmlhdGUgc2NhbGVzLCBhbmQgYSBwcm9mZXNzaW9uYWwgdGhlbWUgKGUuZy4sIHRoZW1lX21pbmltYWwoKSkuDQoxLiBQcm92aWRlIGFuIGFuYWx5dGljYWwgaW50ZXJwcmV0YXRpb24gb2YgZWFjaCB2aXN1YWxpemF0aW9uLiBBIGJyaWVmIHBhcmFncmFwaCBleHBsYWluaW5nIHdoYXQgdGhlIHBsb3QgcmV2ZWFscyBhYm91dCBNdW1iYWkncyB0cmFuc3BvcnQgc3lzdGVtLg0KMS4gU3VibWl0IHRoZSBSIG5vdGVib29rIGNvbnRhaW5pbmcgdGhlIFIgY29kZSBhbmQgdGhlIGludGVycHJldGF0aW9uLiBUaGUgbm90ZWJvb2sgc2hvdWxkIGV4ZWN1dGUgd2l0aG91dCBhbnkgZXJyb3JzLiBBbHNvIHN1Ym1pdCBhICpyZW5kZXJlZCogdmVyc2lvbiBvZiB0aGUgbm90ZWJvb2ssIHByZWZlcmFibHkgaW4gUERGIGZvcm1hdCAoUm1kIC0+IEhUTUwgLT4gUERGKS4NCg0KRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gUiBub3RlYm9va3MsIHZpc2l0IHRoZSBmb2xsb3dpbmcgbGluazoNCmh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9ub3RlYm9vay5odG1sDQoNCiMjIFBhcnQgMTogRGF0YSBQcmUtcHJvY2Vzc2luZw0KQmVmb3JlIHBsb3R0aW5nLCBjbGVhbiB0aGUgZGF0YXNldC4gSGFuZGxlIHRoZSBuZWdhdGl2ZSBib2FyZGluZyBjb3VudHMsIGluY29uc2lzdGVudCB3ZWF0aGVyIG5hbWVzIChlLmcuLCAnbW9uc29vbicgdnMgJ01vbnNvb24nKSwgYW5kIGNvbnZlcnQgdGltZSBzdHJpbmdzIGludG8gdXNhYmxlIHRpbWUgb2JqZWN0cy4NCg0KYGBge3IgY2xlYW5pbmd9DQpkZiR3ZWF0aGVyX2NvbmRpdGlvbiA8LSB0b2xvd2VyKGRmJHdlYXRoZXJfY29uZGl0aW9uKQ0KDQpkZiRwYXNzZW5nZXJfY291bnRfYm9hcmRpbmdbZGYkcGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nIDwgMF0gPC0gTkENCmRmJHBhc3Nlbmdlcl9jb3VudF9hbGlnaHRpbmdbZGYkcGFzc2VuZ2VyX2NvdW50X2FsaWdodGluZyA8IDBdIDwtIE5BDQoNCmRmJGRhdGUgPC0geW1kKGRmJGRhdGUpDQoNCmRmJGFycml2YWxfdGltZV9zY2hlZHVsZWQgICA8LSBobXMoZGYkYXJyaXZhbF90aW1lX3NjaGVkdWxlZCkNCmRmJGFycml2YWxfdGltZV9hY3R1YWwgICAgICA8LSBobXMoZGYkYXJyaXZhbF90aW1lX2FjdHVhbCkNCmRmJGRlcGFydHVyZV90aW1lX3NjaGVkdWxlZCA8LSBobXMoZGYkZGVwYXJ0dXJlX3RpbWVfc2NoZWR1bGVkKQ0KZGYkZGVwYXJ0dXJlX3RpbWVfYWN0dWFsICAgIDwtIGhtcyhkZiRkZXBhcnR1cmVfdGltZV9hY3R1YWwpDQoNCmRmX2NsZWFuIDwtIGRmW2NvbXBsZXRlLmNhc2VzKA0KICBkZiRwYXNzZW5nZXJfY291bnRfYm9hcmRpbmcsDQogIGRmJHBhc3Nlbmdlcl9jb3VudF9hbGlnaHRpbmcsDQogIGRmJGFycml2YWxfdGltZV9zY2hlZHVsZWQsDQogIGRmJGFycml2YWxfdGltZV9hY3R1YWwsDQogIGRmJHdlYXRoZXJfY29uZGl0aW9uKSwgXQ0KDQpkZl9jbGVhbiRib2FyZGluZ19udW0gPC0gc3VwcHJlc3NXYXJuaW5ncygNCiAgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZGZfY2xlYW4kcGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nKSkgKQ0KDQojRGF0YSBDbGVhbiBjaGVjaw0KbnJvdyhkZikNCm5yb3coZGZfY2xlYW4pDQpzdW0oaXMubmEoZGZfY2xlYW4kcGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nKSkNCnN1bShpcy5uYShkZl9jbGVhbiRwYXNzZW5nZXJfY291bnRfYWxpZ2h0aW5nKSkNCg0KYGBgDQoNCi0tLQ0KICANCiMjIFBhcnQgMjogVmlzdWFsaXppbmcgd2l0aCBnZ3Bsb3QyDQogIA0KIyMjIyBRMS4gRGlzdHJpYnV0aW9uIG9mIEJvYXJkaW5nIGJ5IFJvdXRlIChGYWNldGluZykNCkNyZWF0ZSBhIGhpc3RvZ3JhbSBmb3IgYHBhc3Nlbmdlcl9jb3VudF9ib2FyZGluZ2AuIFVzZSAqKmZhY2V0aW5nKiogdG8gZGlzcGxheSBhIHNlcGFyYXRlIHBsb3QgZm9yIGVhY2ggYHJvdXRlX2lkYC4NCg0KYGBge3IgcTF9DQpkZl9jbGVhbiRyb3V0ZV90eXBlIDwtIGlmZWxzZSgNCiAgZGZfY2xlYW4kcm91dGVfaWQgJWluJSBjKCJNVU1fUm91dGVfQyIsICJNVU1fUm91dGVfRSIpLA0KICAiSGlnaCB2YXJpYWJpbGl0eSByb3V0ZXMiLA0KICAiU3RhYmxlIHJvdXRlcyIgKQ0KDQpnZ3Bsb3QoIGRmX2NsZWFuLA0KICBhZXMoIHggPSBib2FyZGluZ19udW0sDQogICAgZmlsbCA9IHJvdXRlX3R5cGUgKSApICsNCiAgZ2VvbV9oaXN0b2dyYW0oDQogICAgYmlucyA9IDE1LA0KICAgIGNvbG9yID0gIndoaXRlIiwNCiAgICBuYS5ybSA9IFRSVUUgKSArDQogIGZhY2V0X3dyYXAofiByb3V0ZV9pZCwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwoDQogICAgdmFsdWVzID0gYygNCiAgICAgICJIaWdoIHZhcmlhYmlsaXR5IHJvdXRlcyIgPSAiI0U2N0UyMiIsDQogICAgICAiU3RhYmxlIHJvdXRlcyIgPSAiIzYyODE0MSIgKSApICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUGFzc2VuZ2VyIEJvYXJkaW5nIGJ5IFJvdXRlIiwNCiAgICBzdWJ0aXRsZSA9ICJSb3V0ZXMgQyBhbmQgRSBzaG93IGhpZ2hlciB2YXJpYWJpbGl0eSBhbmQgZGVtYW5kIHNwaWtlcyIsDQogICAgeCA9ICJQYXNzZW5nZXIgQm9hcmRpbmcgQ291bnQiLA0KICAgIHkgPSAiRnJlcXVlbmN5IiwNCiAgICBmaWxsID0gIlJvdXRlIFR5cGUiICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoqKkludGVycHJldGF0aW9uOioqIFtSb3V0ZXMgQyBhbmQgRSBleGhpYml0IGdyZWF0ZXIgdmFyaWFiaWxpdHkgaW4gcGFzc2VuZ2VyIGJvYXJkaW5nLCB3aXRoIGxvbmdlciByaWdodCB0YWlscyBhbmQgaGlnaGVyLWZyZXF1ZW5jeSBwZWFrcyBhdCBsYXJnZXIgYm9hcmRpbmcgdmFsdWVzLiBUaGlzIGluZGljYXRlcyBpbnRlcm1pdHRlbnQgZGVtYW5kIHN1cmdlcywgcG9zc2libHkgZHJpdmVuIGJ5IGxhbmQtdXNlIGNvbmNlbnRyYXRpb24gb3IgdHJhbnNmZXIgYWN0aXZpdHkgYWxvbmcgdGhlc2UgY29ycmlkb3JzLiBJbiBjb250cmFzdCwgdGhlIHJlbWFpbmluZyByb3V0ZXMgZGlzcGxheSBtb3JlIGNvbnNpc3RlbnQgYW5kIGV2ZW5seSBkaXN0cmlidXRlZCBib2FyZGluZyBwYXR0ZXJucywgc3VnZ2VzdGluZyBzdGVhZGllciBkZW1hbmQgYWNyb3NzIHRpbWUuXQ0KDQojIyMjIFEyLiBSaWRlcnNoaXAgRHluYW1pY3MgKENvbmRpdGlvbmFsIENvbG9yaW5nKQ0KQ3JlYXRlIGEgc2NhdHRlciBwbG90IHNob3dpbmcgQm9hcmRpbmcgQ291bnQgdnMuIEFsaWdodGluZyBDb3VudC4gKipDb2xvciB0aGUgcG9pbnRzKiogYmFzZWQgb24gYHdlYXRoZXJfY29uZGl0aW9uYC4NCg0KYGBge3IgcTJ9DQpnZ3Bsb3QoZGZfY2xlYW4sDQogICAgICAgYWVzKHggPSBwYXNzZW5nZXJfY291bnRfYm9hcmRpbmcsDQogICAgICAgICAgIHkgPSBwYXNzZW5nZXJfY291bnRfYWxpZ2h0aW5nLA0KICAgICAgICAgICBjb2xvciA9IGlmZWxzZSh3ZWF0aGVyX2NvbmRpdGlvbiAlaW4lIGMoIm1vbnNvb24iLCJyYWlueSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiR3JlYXRlciBpbXBhY3Qgd2VhdGhlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJMZXNzIGltcGFjdCB3ZWF0aGVyIikpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsNCiAgZmFjZXRfd3JhcCh+d2VhdGhlcl9jb25kaXRpb24pICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIkdyZWF0ZXIgaW1wYWN0IHdlYXRoZXIiID0gIiNFNjdFMjIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGVzcyBpbXBhY3Qgd2VhdGhlciIgPSAiIzYyODE0MSIpKSArDQogIGxhYnModGl0bGUgPSAiQm9hcmRpbmcgdnMgQWxpZ2h0aW5nIEFjcm9zcyBXZWF0aGVyIENvbmRpdGlvbnMiLA0KICAgICAgIHN1YnRpdGxlID0gIk1vbnNvb24gYW5kIHJhaW55IGNvbmRpdGlvbnMgc2hvdyBncmVhdGVyIGltcGFjdCBvbiBwYXNzZW5nZXIgbW92ZW1lbnQiLA0KICAgICAgIHggPSAiUGFzc2VuZ2VyIEJvYXJkaW5nIENvdW50IiwNCiAgICAgICB5ID0gIlBhc3NlbmdlciBBbGlnaHRpbmcgQ291bnQiLA0KICAgICAgIGNvbG9yID0gIldlYXRoZXIgSW1wYWN0IikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KKipJbnRlcnByZXRhdGlvbjoqKiBbUGFzc2VuZ2VyIGJvYXJkaW5nIGFuZCBhbGlnaHRpbmcgcGF0dGVybnMgc2hvdyBncmVhdGVyIGRpc3BlcnNpb24gZHVyaW5nIG1vbnNvb24gYW5kIHJhaW55IGNvbmRpdGlvbnMsIGluZGljYXRpbmcgaW5jcmVhc2VkIHZhcmlhYmlsaXR5IGluIHBhc3NlbmdlciBtb3ZlbWVudCBkdWUgdG8gd2VhdGhlci1yZWxhdGVkIGRpc3J1cHRpb25zLiBJbiBjb250cmFzdCwgc3VubnksIGNsb3VkeSwgYW5kIHBhcnRseSBjbG91ZHkgY29uZGl0aW9ucyBleGhpYml0IG1vcmUgc3RhYmxlIGFuZCBwcmVkaWN0YWJsZSBwYXNzZW5nZXIgZmxvd3MsIHN1Z2dlc3RpbmcgbWluaW1hbCB3ZWF0aGVyIGltcGFjdC4gVGhlc2UgcGF0dGVybnMgaGlnaGxpZ2h0IHRoZSBuZWVkIGZvciB3ZWF0aGVyLXJlc3BvbnNpdmUgb3BlcmF0aW9uYWwgcGxhbm5pbmcsIHN1Y2ggYXMgZmxleGlibGUgc2NoZWR1bGluZyBhbmQgYnVmZmVyIGNhcGFjaXR5IGR1cmluZyBhZHZlcnNlIHdlYXRoZXIgY29uZGl0aW9ucy5dDQoNCiMjIyMgUTMuIEhvdXJseSBQZWFrIERlbWFuZCAoRmFjZXRpbmcpDQpFeHRyYWN0IHRoZSBob3VyIGZyb20gYGFycml2YWxfdGltZV9zY2hlZHVsZWRgLiBDcmVhdGUgYSBiYXIgY2hhcnQgb2YgdG90YWwgYm9hcmRpbmcgcGVyIGhvdXIsICoqZmFjZXRlZCBieSoqIGBkYXlfb2Zfd2Vla2AuDQoNCmBgYHtyIHEzfQ0KZGZfY2xlYW4kYXJyaXZhbF9ob3VyIDwtIGhvdXIoZGZfY2xlYW4kYXJyaXZhbF90aW1lX2FjdHVhbCkNCmRmX2NsZWFuJGRheV90eXBlIDwtIGlmZWxzZSgNCiAgZGZfY2xlYW4kZGF5X29mX3dlZWsgJWluJSBjKCJTYXR1cmRheSIsICJTdW5kYXkiKSwNCiAgIldlZWtlbmQiLA0KICAiV2Vla2RheSIgKQ0KDQpob3VybHlfYm9hcmRpbmdfdHlwZSA8LSBhZ2dyZWdhdGUoDQogIHBhc3Nlbmdlcl9jb3VudF9ib2FyZGluZyB+IGFycml2YWxfaG91ciArIGRheV90eXBlLA0KICBkYXRhID0gZGZfY2xlYW4sDQogIHN1bSwNCiAgbmEucm0gPSBUUlVFICkNCg0KZ2dwbG90KCBob3VybHlfYm9hcmRpbmdfdHlwZSwNCiAgYWVzKA0KICAgIHggPSBhcnJpdmFsX2hvdXIsDQogICAgeSA9IHBhc3Nlbmdlcl9jb3VudF9ib2FyZGluZywNCiAgICBmaWxsID0gZGF5X3R5cGUgKSApICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKA0KICAgIHZhbHVlcyA9IGMoDQogICAgICAiV2Vla2RheSIgPSAiIzYyODE0MSIsDQogICAgICAiV2Vla2VuZCIgPSAiI0U2N0UyMiIgKSApICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJIb3VybHkgUGFzc2VuZ2VyIEJvYXJkaW5nOiBXZWVrZGF5cyB2cyBXZWVrZW5kcyIsDQogICAgc3VidGl0bGUgPSAiV2Vla2RheSBwYXNzZW5nZXIgYm9hcmRpbmcgaXMgY29uc2lzdGVudGx5IGhpZ2hlciIsDQogICAgeCA9ICJIb3VyIG9mIERheSIsDQogICAgeSA9ICJUb3RhbCBQYXNzZW5nZXIgQm9hcmRpbmciLA0KICAgIGZpbGwgPSAiRGF5IFR5cGUiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KKipJbnRlcnByZXRhdGlvbjoqKiBbSG91cmx5IHBhc3NlbmdlciBib2FyZGluZyBvbiB3ZWVrZGF5cyBpcyBjb25zaXN0ZW50bHkgaGlnaGVyIHRoYW4gd2Vla2VuZHMgYWNyb3NzIGFsbCBob3Vycywgd2l0aCBwcm9ub3VuY2VkIHBlYWtzIGR1cmluZyB0eXBpY2FsIGNvbW11dGluZyBwZXJpb2RzLiBXZWVrZW5kIGRlbWFuZCByZW1haW5zIGxvd2VyIGFuZCBmbGF0dGVyLCBpbmRpY2F0aW5nIHByZWRvbWluYW50bHkgZGlzY3JldGlvbmFyeSB0cmF2ZWwuIFRoaXMgcGF0dGVybiBzdXBwb3J0cyBoaWdoZXIgcGVhay1ob3VyIGZyZXF1ZW5jaWVzIGFuZCBncmVhdGVyIGZsZWV0IGRlcGxveW1lbnQgb24gd2Vla2RheXMsIHdoaWxlIHJlZHVjZWQgb3IgZXZlbmx5IHNwYWNlZCBoZWFkd2F5IG9uIHdlZWtlbmRzIGNhbiBpbXByb3ZlIG9wZXJhdGlvbmFsIGVmZmljaWVuY3kgd2l0aG91dCBhZmZlY3Rpbmcgc2VydmljZSBxdWFsaXR5Ll0NCg0KIyMjIyBRNC4gRGVsYXkgRGlzdHJpYnV0aW9uDQpDYWxjdWxhdGUgYGRlbGF5X21pbnV0ZXNgIChBY3R1YWwgLSBTY2hlZHVsZWQpLiBDcmVhdGUgYSBzY2F0dGVyIHBsb3Qgb2YgU2NoZWR1bGVkIFRpbWUgdnMgQWN0dWFsIFRpbWUsICoqY29sb3JpbmcgcG9pbnRzKiogYnkgd2hldGhlciB0aGUgYnVzIHdhcyAiTGF0ZSIgKGRlbGF5ID4gNSBtaW5zKSBvciAiT24tVGltZSIuDQoNCmBgYHtyIHE0fQ0KZGZfY2xlYW4kc2NoZWR1bGVkX21pbnV0ZXMgPC0NCiAgYXMubnVtZXJpYyhkZl9jbGVhbiRhcnJpdmFsX3RpbWVfc2NoZWR1bGVkKSAvIDYwDQoNCmRmX2NsZWFuJGFjdHVhbF9taW51dGVzIDwtDQogIGFzLm51bWVyaWMoZGZfY2xlYW4kYXJyaXZhbF90aW1lX2FjdHVhbCkgLyA2MA0KDQpkZl9jbGVhbiRkZWxheV9zdGF0dXMgPC0gaWZlbHNlKA0KICBkZl9jbGVhbiRhY3R1YWxfbWludXRlcyA+IGRmX2NsZWFuJHNjaGVkdWxlZF9taW51dGVzLA0KICAiTGF0ZSIsDQogICJPblRpbWUiICkNCg0KZGZfY2xlYW4kZGVsYXlfc3RhdHVzIDwtIGZhY3RvcigNCiAgZGZfY2xlYW4kZGVsYXlfc3RhdHVzLA0KICBsZXZlbHMgPSBjKCJPblRpbWUiLCAiTGF0ZSIpICkNCg0KZ2dwbG90KGRmX2NsZWFuLCBhZXMoDQogIHggPSBzY2hlZHVsZWRfbWludXRlcywNCiAgeSA9IGFjdHVhbF9taW51dGVzLA0KICBjb2xvciA9IGRlbGF5X3N0YXR1cyApKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsNCiAgZ2VvbV9hYmxpbmUoDQogICAgaW50ZXJjZXB0ID0gMCwNCiAgICBzbG9wZSA9IDEsDQogICAgbGluZXR5cGUgPSAiZGFzaGVkIiwNCiAgICBjb2xvciA9ICJibGFjayIgKSArDQogIGNvb3JkX2NhcnRlc2lhbigNCiAgICB4bGltID0gYygzNTAsIDExNTApLA0KICAgIHlsaW0gPSBjKDM1MCwgMTE1MCkgKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKA0KICAgICJPblRpbWUiID0gIiM2MjgxNDEiLA0KICAgICJMYXRlIiAgID0gIiNFNjdFMjIiICkpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJTY2hlZHVsZWQgdnMgQWN0dWFsIEFycml2YWwgVGltZSAoRm9jdXNlZCBWaWV3KSIsDQogICAgc3VidGl0bGUgPSAiRGV2aWF0aW9ucyBmcm9tIHRoZSA0NS1kZWdyZWUgbGluZSBpbmRpY2F0ZSBkZWxheXMiLA0KICAgIHggPSAiU2NoZWR1bGVkIEFycml2YWwgVGltZSAobWludXRlcyBmcm9tIG1pZG5pZ2h0KSIsDQogICAgeSA9ICJBY3R1YWwgQXJyaXZhbCBUaW1lIChtaW51dGVzIGZyb20gbWlkbmlnaHQpIiwNCiAgICBjb2xvciA9ICJTdGF0dXMiICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KKipJbnRlcnByZXRhdGlvbjoqKiBbVGhlIG1ham9yaXR5IG9mIHRyaXBzIGxpZSBjbG9zZSB0byB0aGUgNDUtZGVncmVlIHJlZmVyZW5jZSBsaW5lLCBpbmRpY2F0aW5nIGdvb2Qgc2NoZWR1bGUgYWRoZXJlbmNlIGR1cmluZyBhY3RpdmUgc2VydmljZSBob3Vycy4gSG93ZXZlciwgY29uc2lzdGVudCBkZXZpYXRpb25zIGFib3ZlIHRoZSBsaW5lIHJlZmxlY3Qgc3lzdGVtYXRpYyBsYXRlIGFycml2YWxzLCBwYXJ0aWN1bGFybHkgYXMgc2NoZWR1bGVkIHRpbWVzIGluY3JlYXNlLCBzdWdnZXN0aW5nIGN1bXVsYXRpdmUgZGVsYXlzIG92ZXIgdGhlIHNlcnZpY2UgcGVyaW9kLiBUaGlzIGluZGljYXRlcyBhIG5lZWQgZm9yIHNjaGVkdWxlIHJlY292ZXJ5IHRpbWUgb3IgaGVhZHdheSBhZGp1c3RtZW50cyB0byBpbXByb3ZlIHJlbGlhYmlsaXR5Ll0NCg0KLS0tDQoNCiMjIFBhcnQgMzogQ29uZGl0aW9uaW5nIHdpdGggTGF0dGljZQ0KICANCiMjIyMgUTUuIERlbnNpdHkgQ29uZGl0aW9uaW5nDQoNClVzaW5nIHRoZSBgbGF0dGljZWAgcGFja2FnZSwgY3JlYXRlIGEgZGVuc2l0eSBwbG90IChgZGVuc2l0eXBsb3RgKSBvZiBgcGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nYCAqKmNvbmRpdGlvbmVkIG9uKiogYGRheV9vZl93ZWVrYC4NCg0KYGBge3IgcTV9DQpkZl9jbGVhbiRkYXlfb2Zfd2VlayA8LSBmYWN0b3IoDQogIGRmX2NsZWFuJGRheV9vZl93ZWVrLA0KICBsZXZlbHMgPSBjKCJNb25kYXkiLCAiVHVlc2RheSIsICJXZWRuZXNkYXkiLA0KICAgICAgICAgICAgICJUaHVyc2RheSIsICJGcmlkYXkiLCAiU2F0dXJkYXkiLCAiU3VuZGF5IikgKQ0KZGVuc2l0eXBsb3QoDQogIH4gcGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nIHwgZGF5X29mX3dlZWssDQogIGRhdGEgPSBkZl9jbGVhbiwNCiAgbGF5b3V0ID0gYyg0LCAyKSwNCiAgZ3JvdXBzID0gaWZlbHNlKGRheV9vZl93ZWVrICVpbiUgYygiU2F0dXJkYXkiLCAiU3VuZGF5IiksDQogICAgICAgICAgICAgICAgICAiV2Vla2VuZCIsICJXZWVrZGF5IiksDQogIHBsb3QucG9pbnRzID0gRkFMU0UsDQogIGNvbCA9IGMoIiM2MjgxNDEiLCAiI0U2N0UyMiIpLA0KICBsd2QgPSAzLA0KICBtYWluID0gIlBhc3NlbmdlciBCb2FyZGluZyBEZW5zaXR5IGJ5IERheSBvZiBXZWVrIiwNCiAgeGxhYiA9ICJQYXNzZW5nZXIgQm9hcmRpbmcgQ291bnQiLA0KICB5bGFiID0gIkRlbnNpdHkiLA0KICBhdXRvLmtleSA9IFRSVUUgKQ0KYGBgDQoqKkludGVycHJldGF0aW9uOioqIFtXZWVrZGF5cyBleGhpYml0IGNvbnNpc3RlbnQgYW5kIHNoYXJwbHkgcGVha2VkIGJvYXJkaW5nIGRlbnNpdGllcywgcmVmbGVjdGluZyBzdGFibGUgY29tbXV0ZXItZHJpdmVuIGRlbWFuZCwgd2l0aCBtaWQtd2VlayBkYXlzIHNob3dpbmcgdGhlIGhpZ2hlc3QgcmVsaWFiaWxpdHkuIEluIGNvbnRyYXN0LCB3ZWVrZW5kcyBkaXNwbGF5IGJyb2FkZXIgYW5kIGZsYXR0ZXIgZGlzdHJpYnV0aW9ucywgaW5kaWNhdGluZyBsb3dlciBidXQgbW9yZSBldmVubHkgc3ByZWFkIHRyYXZlbCBkZW1hbmQuIFRoaXMgc3VnZ2VzdHMgdGhlIG5lZWQgZm9yIHBlYWstb3JpZW50ZWQgc2NoZWR1bGluZyBvbiB3ZWVrZGF5cyBhbmQgZmxleGlibGUgc2VydmljZSBwcm92aXNpb24gb24gd2Vla2VuZHMuXQ0KDQojIyMjIFE2LiBVc2luZyBTaGluZ2xlcyBmb3IgVGVtcG9yYWwgQW5hbHlzaXMNCkNyZWF0ZSBhICoqc2hpbmdsZSoqIGZvciB0aGUgYGFycml2YWxfdGltZV9zY2hlZHVsZWRgIHZhcmlhYmxlIChlLmcuLCAzLTQgb3ZlcmxhcHBpbmcgd2luZG93cykuIFVzZSBgeHlwbG90YCB0byBwbG90IGBwYXNzZW5nZXJfY291bnRfYm9hcmRpbmdgIHZzLiBgcGFzc2VuZ2VyX2NvdW50X2FsaWdodGluZ2AgKipjb25kaXRpb25lZCBvbiB0aGUgdGltZSBzaGluZ2xlcyoqLg0KDQpgYGB7ciBxNn0NCmRmX2NsZWFuJGFycml2YWxfbWludXRlcyA8LSBhcy5udW1lcmljKGRmX2NsZWFuJGFycml2YWxfdGltZV9hY3R1YWwpDQpkZl9jbGVhbiR0aW1lX29mX2RheSA8LSBjdXQoDQogIGRmX2NsZWFuJGFycml2YWxfbWludXRlcywNCiAgYnJlYWtzID0gYygwLCA2KjM2MDAsIDEwKjM2MDAsIDE1KjM2MDAsIDI0KjM2MDApLA0KICBsYWJlbHMgPSBjKCJFYXJseSBNb3JuaW5nIiwgIk1vcm5pbmcgUGVhayIsICJNaWRkYXkiLCAiRXZlbmluZyIpLA0KICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUgKQ0KDQp4eXBsb3QoDQpwYXNzZW5nZXJfY291bnRfYWxpZ2h0aW5nIH4gcGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nIHwgdGltZV9vZl9kYXksDQpkYXRhID0gZGZfY2xlYW4sDQpncm91cHMgPSBmYWN0b3IoDQppZmVsc2UoZGZfY2xlYW4kdGltZV9vZl9kYXkgPT0gIkV2ZW5pbmciLA0KIkV2ZW5pbmciLCAiT3RoZXIgUGVyaW9kcyIpLA0KbGV2ZWxzID0gYygiRXZlbmluZyIsICJPdGhlciBQZXJpb2RzIikgKSwNCiAgeGxhYiA9ICJQYXNzZW5nZXIgQm9hcmRpbmcgQ291bnQiLA0KICB5bGFiID0gIlBhc3NlbmdlciBBbGlnaHRpbmcgQ291bnQiLA0KICBtYWluID0gIkJvYXJkaW5nIHZzIEFsaWdodGluZyBieSBUaW1lIG9mIERheSIsDQogIHBjaCA9IDE2LA0KICBjb2wgPSBjKCIjRTY3RTIyIiwgIiM2MjgxNDEiKSwNCiAgYWxwaGEgPSAwLjYsDQogIGF1dG8ua2V5ID0gbGlzdCh0aXRsZSA9ICJUaW1lIFBlcmlvZCIsIGNvbHVtbnMgPSAxKSApDQpgYGANCioqSW50ZXJwcmV0YXRpb246KiogW1RoZSBldmVuaW5nIHBlcmlvZCBleGhpYml0cyB0aGUgaGlnaGVzdCBzaW11bHRhbmVvdXMgbGV2ZWxzIGFuZCB3aWRlc3QgZGlzcGVyc2lvbiBvZiBwYXNzZW5nZXIgYm9hcmRpbmcgYW5kIGFsaWdodGluZywgaW5kaWNhdGluZyBpbnRlbnNlIGJpZGlyZWN0aW9uYWwgbW92ZW1lbnQgYXNzb2NpYXRlZCB3aXRoIHJldHVybiB0cmlwcywgdHJhbnNmZXJzLCBhbmQgYWN0aXZpdHktYmFzZWQgdHJhdmVsLiBJbiBjb250cmFzdCwgbW9ybmluZyBwZWFrIGRlbWFuZCBpcyBtb3JlIGRpcmVjdGlvbmFsLCB3aXRoIGNvbXBhcmF0aXZlbHkgY29uc3RyYWluZWQgYWxpZ2h0aW5nIHJlbGF0aXZlIHRvIGJvYXJkaW5nLCB3aGlsZSBlYXJseSBtb3JuaW5nIGFuZCBtaWRkYXkgc2hvdyBsb3dlciBhbmQgbW9yZSBzdGFibGUgaW50ZXJhY3Rpb25zLiBUaGlzIHN1Z2dlc3RzIHRoYXQgZXZlbmluZyBvcGVyYXRpb25zIHJlcXVpcmUgZ3JlYXRlciBkd2VsbC10aW1lIG1hbmFnZW1lbnQsIHBsYXRmb3JtIGNhcGFjaXR5LCBhbmQgc2NoZWR1bGUgcmVjb3ZlcnkgYnVmZmVycyB0aGFuIG90aGVyIHRpbWUgcGVyaW9kcy5dDQoNCiMjIyMgUTcuIFJvdXRlIFBlcmZvcm1hbmNlIChMYXR0aWNlIEJveHBsb3RzKQ0KVXNlIGBid3Bsb3RgIHRvIGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBgcGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nYCAqKmNvbmRpdGlvbmVkIG9uKiogYHJvdXRlX2lkYC4NCg0KYGBge3IgcTd9DQpkZl9jbGVhbiRyb3V0ZV9oaWdobGlnaHQgPC0gaWZlbHNlKA0KICBkZl9jbGVhbiRyb3V0ZV9pZCAlaW4lIGMoIk1VTV9Sb3V0ZV9DIiwgIk1VTV9Sb3V0ZV9FIiksDQogICJIaWdoZXIgVmFyaWFiaWxpdHkgUm91dGVzIiwNCiAgIk90aGVyIFJvdXRlcyIgKQ0KYndwbG90KA0KICBwYXNzZW5nZXJfY291bnRfYm9hcmRpbmcgfiByb3V0ZV9pZCwNCiAgZGF0YSA9IGRmX2NsZWFuLA0KICBncm91cHMgPSBkZl9jbGVhbiRyb3V0ZV9oaWdobGlnaHQsDQogIGJveC53aWR0aCA9IDAuNywNCiAgbHdkID0gMiwNCiAgYXV0by5rZXkgPSBsaXN0KA0KICAgIHNwYWNlID0gInJpZ2h0IiwNCiAgICB0aXRsZSA9ICJSb3V0ZSBDYXRlZ29yeSIgKSwNCiAgeGxhYiA9ICJSb3V0ZSBJRCIsDQogIHlsYWIgPSAiUGFzc2VuZ2VyIEJvYXJkaW5nIENvdW50IiwNCiAgbWFpbiA9ICJQYXNzZW5nZXIgQm9hcmRpbmcgRGlzdHJpYnV0aW9uIGJ5IFJvdXRlIiwNCiAgcGFyLnNldHRpbmdzID0gbGlzdCgNCiAgICBib3gucmVjdGFuZ2xlID0gbGlzdChjb2wgPSBjKCIjNjI4MTQxIiwgIiNFNjdFMjIiKSksDQogICAgYm94LnVtYnJlbGxhICA9IGxpc3QoY29sID0gYygiIzYyODE0MSIsICIjRTY3RTIyIikpLA0KICAgIHBsb3Quc3ltYm9sICAgPSBsaXN0KGNvbCA9IGMoIiM2MjgxNDEiLCAiI0U2N0UyMiIpKSApICkNCmBgYA0KKipJbnRlcnByZXRhdGlvbjoqKiBbTVVNX1JvdXRlX0MgYW5kIE1VTV9Sb3V0ZV9FIGhhcyBncmVhdGVyIGRlbWFuZCB2YXJpYWJpbGl0eSBhbmQgcHJvbm91bmNlZCBwZWFrIGxvYWRzLiBJbiBjb250cmFzdCwgTVVNX1JvdXRlX0EsIE1VTV9Sb3V0ZV9CLCBhbmQgTVVNX1JvdXRlX0QgaGFzIHN0YWJsZSBhbmQgcHJlZGljdGFibGUgcGFzc2VuZ2VyIGRlbWFuZC4gVGhpcyBzdWdnZXN0cyB0aGF0IFJvdXRlcyBDIGFuZCBFIHJlcXVpcmUgZmxleGlibGUgaGVhZHdheXMgb3IgaGlnaGVyLWNhcGFjaXR5IHZlaGljbGVzLCB3aGlsZSBSb3V0ZXMgQSwgQiwgYW5kIEQgY2FuIGJlIGVmZmljaWVudGx5IG9wZXJhdGVkIHdpdGggZml4ZWQgc2NoZWR1bGVzIGFuZCBzdGFuZGFyZCBmbGVldCBkZXBsb3ltZW50Ll0NCg0KLS0tDQogIA0KIyMgUGFydCA0OiBTeW50aGVzaXMgJiBPcGVyYXRpb25zDQogIA0KIyMjIyBROC4gRHdlbGwgVGltZSBhbmQgV2VhdGhlciAoZ2dwbG90MikNCg0KQ2FsY3VsYXRlICJEd2VsbCBUaW1lIiAoQWN0dWFsIERlcGFydHVyZSAtIEFjdHVhbCBBcnJpdmFsKS4gQ3JlYXRlIGEgc2NhdHRlciBwbG90IG9mIEJvYXJkaW5nIENvdW50IHZzLiBEd2VsbCBUaW1lLiAqKkZhY2V0IGJ5KiogYHdlYXRoZXJfY29uZGl0aW9uYCBhbmQgKipjb2xvciBieSoqIGByb3V0ZV9pZGAuDQoNCmBgYHtyIHE4fQ0KZGZfY2xlYW4kZHdlbGxfdGltZV9taW51dGVzIDwtDQphcy5udW1lcmljKGRmX2NsZWFuJGRlcGFydHVyZV90aW1lX2FjdHVhbCAtIGRmX2NsZWFuJGFycml2YWxfdGltZV9hY3R1YWwpIC8gNjANCg0KZGZfY2xlYW5fcTggPC0gZGZfY2xlYW4gJT4lDQpmaWx0ZXIoZHdlbGxfdGltZV9taW51dGVzID49IDAsIGR3ZWxsX3RpbWVfbWludXRlcyA8PSAzMCkNCg0KZ2dwbG90KA0KICBkZl9jbGVhbl9xOCwNCiAgYWVzKA0KICAgIHggPSBwYXNzZW5nZXJfY291bnRfYm9hcmRpbmcsDQogICAgeSA9IGR3ZWxsX3RpbWVfbWludXRlcykgKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiIzYyODE0MSIsIGFscGhhID0gMC41KSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gIiNFNjdFMjIiKSArDQogIGZhY2V0X3dyYXAofiB3ZWF0aGVyX2NvbmRpdGlvbikgKw0KICBsYWJzKA0KdGl0bGUgPSAiSW1wYWN0IG9mIEJvYXJkaW5nIFZvbHVtZSBvbiBEd2VsbCBUaW1lIEFjcm9zcyBXZWF0aGVyIENvbmRpdGlvbnMiLA0Kc3VidGl0bGUgPSAiV2VhdGhlciBpbmZsdWVuY2VzIGhvdyBib2FyZGluZyB2b2x1bWVzIHRyYW5zbGF0ZSBpbnRvIGR3ZWxsIHRpbWUiLA0KICAgIHggPSAiUGFzc2VuZ2VyIEJvYXJkaW5nIENvdW50IiwNCiAgICB5ID0gIkR3ZWxsIFRpbWUgKG1pbnV0ZXMpIiApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCioqSW50ZXJwcmV0YXRpb246KiogW0R1cmluZyBtb25zb29uIGFuZCByYWlueSB3ZWF0aGVyLCBidXNlcyB0YWtlIGxvbmdlciB0byBzdG9wIGV2ZW4gd2hlbiB0aGVyZSBhcmUgbm90IG1hbnkgcGFzc2VuZ2Vycywgc2hvd2luZyB0aGF0IHJhaW4gc2xvd3MgZG93biBib2FyZGluZyBhbmQgb3BlcmF0aW9ucyBtb3JlIHRoYW4gcGFzc2VuZ2VyIG51bWJlcnMgZG8uDQoNCkluIHN1bm55IGFuZCBwYXJ0bHkgY2xvdWR5IHdlYXRoZXIsIGJvYXJkaW5nIGlzIHF1aWNrZXIgYW5kIGR3ZWxsIHRpbWUgaW5jcmVhc2VzIGdyYWR1YWxseSBhcyBwYXNzZW5nZXIgbnVtYmVycyBpbmNyZWFzZSwgaW5kaWNhdGluZyBzbW9vdGhlciBhbmQgbW9yZSBlZmZpY2llbnQgbW92ZW1lbnQuDQoNClRoaXMgc2hvd3MgdGhhdCB3ZWF0aGVyIGl0c2VsZiBhZmZlY3RzIGJ1cyBzdG9wcGluZyB0aW1lLCBub3QganVzdCBob3cgbWFueSBwZW9wbGUgYXJlIGJvYXJkaW5nLg0KDQpUaGVyZWZvcmUsIGJ1cyBzY2hlZHVsZXMgc2hvdWxkIGFsbG93IGV4dHJhIHN0b3BwaW5nIHRpbWUgZHVyaW5nIGJhZCB3ZWF0aGVyLCBpbnN0ZWFkIG9mIHVzaW5nIHRoZSBzYW1lIGFzc3VtcHRpb25zIGZvciBhbGwgY29uZGl0aW9ucy5dDQoNCiMjIyMgUTkuIFNwZWNpZmljIFN0b3AgQW5hbHlzaXMgKExhdHRpY2UpDQpGaWx0ZXIgZGF0YSBmb3IgdGhlIHRvcCAzIGJ1c2llc3Qgc3RvcHMuIENyZWF0ZSBhbiBgeHlwbG90YCBzaG93aW5nIGJvYXJkaW5nIGNvdW50cyBvdmVyIGBkYXRlYCwgKipjb25kaXRpb25lZCBvbioqIGBzdG9wX25hbWVgLg0KDQpgYGB7ciBxOX0NCmRmX2NsZWFuJHRlbXBfaW5kZXggPC0gc2VxX2xlbihucm93KGRmX2NsZWFuKSkNCg0KdG9wX3N0b3BzIDwtIGRmX2NsZWFuICU+JQ0KICBncm91cF9ieShzdG9wX25hbWUpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgdG90YWxfYm9hcmRpbmcgPSBzdW0ocGFzc2VuZ2VyX2NvdW50X2JvYXJkaW5nLCBuYS5ybSA9IFRSVUUpDQogICkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbF9ib2FyZGluZykpICU+JQ0KICBzbGljZSgxOjMpICU+JQ0KICBwdWxsKHN0b3BfbmFtZSkNCg0KZGZfdG9wX3N0b3BzIDwtIGRmX2NsZWFuICU+JQ0KICBmaWx0ZXIoc3RvcF9uYW1lICVpbiUgdG9wX3N0b3BzKQ0KDQp4eXBsb3QoDQogIHBhc3Nlbmdlcl9jb3VudF9ib2FyZGluZyB+IHRlbXBfaW5kZXggfCBzdG9wX25hbWUsDQogIGRhdGEgPSBkZl90b3Bfc3RvcHMsDQogIHR5cGUgPSBjKCJwIiwgImwiKSwNCiAgcGNoID0gMTYsDQogIGNvbCA9ICIjNjI4MTQxIiwNCiAgYWxwaGEgPSAwLjYsDQogIGxheW91dCA9IGMoMSwgMyksDQogIHhsYWIgPSAiT2JzZXJ2YXRpb24gU2VxdWVuY2UgKFRpbWUgUHJveHkpIiwNCiAgeWxhYiA9ICJQYXNzZW5nZXIgQm9hcmRpbmcgQ291bnQiLA0KICBtYWluID0gIlBhc3NlbmdlciBCb2FyZGluZyBUcmVuZHMgYXQgVG9wIDMgQnVzaWVzdCBTdG9wcyIsDQogIHBhbmVsID0gZnVuY3Rpb24oeCwgeSwgLi4uKSANCiAgICB7IHBhbmVsLnh5cGxvdCh4LCB5LCAuLi4pDQogICAgcGFuZWwucmVjdCgNCiAgICB4bGVmdCA9IG1pbih4KSwNCiAgICB5Ym90dG9tID0gMjAsDQogICAgeHJpZ2h0ID0gbWF4KHgpLA0KICAgIHl0b3AgPSA1MCwNCiAgICBib3JkZXIgPSAiYmxhY2siLA0KICAgIGx0eSA9IDIgKSB9ICkNCmBgYA0KKipJbnRlcnByZXRhdGlvbjoqKiBbTmVydWwsIEJvcml2YWxpLCBhbmQgQmVsYXB1ciBjb25zaXN0ZW50bHkgb3BlcmF0ZSB3aXRoaW4gYSBjb21tb24gaGlnaC1kZW1hbmQgYm9hcmRpbmcgcmFuZ2UsIGluZGljYXRpbmcgcGVyc2lzdGVudCBwYXNzZW5nZXIgcHJlc3N1cmUgYXQgdGhlc2UgbG9jYXRpb25zIHJhdGhlciB0aGFuIG9jY2FzaW9uYWwgc3Bpa2VzLg0KDQpCb3JpdmFsaSBhbmQgQmVsYXB1ciBleGhpYml0IGhpZ2hlciB2YXJpYWJpbGl0eSBhbmQgbW9yZSBmcmVxdWVudCBwZWFrcywgc3VnZ2VzdGluZyBzdHJvbmdlciBzZW5zaXRpdml0eSB0byB0aW1lLW9mLWRheSBlZmZlY3RzLCBzdXJyb3VuZGluZyBsYW5kLXVzZSBhY3Rpdml0eSwgb3IgdHJhbnNmZXIgbW92ZW1lbnRzLg0KDQpOZXJ1bCBzaG93cyBjb21wYXJhdGl2ZWx5IHN0ZWFkaWVyIGJvYXJkaW5nIGxldmVscywgaW5kaWNhdGluZyBhIG1vcmUgcHJlZGljdGFibGUgZGVtYW5kIHBhdHRlcm4uDQoNClRoZSByZXBlYXRlZCBjbHVzdGVyaW5nIG9mIG9ic2VydmF0aW9ucyB3aXRoaW4gdGhlIGhpZ2hsaWdodGVkIGRlbWFuZCBiYW5kIGNvbmZpcm1zIHRoYXQgdGhlc2Ugc3RvcHMgYWN0IGFzIHN0cnVjdHVyYWwgZGVtYW5kIGFuY2hvcnMgaW4gdGhlIG5ldHdvcmsuDQoNCkZyb20gYW4gb3BlcmF0aW9uYWwgcGVyc3BlY3RpdmUsIHRoZXNlIHN0b3BzIHNob3VsZCBiZSBwcmlvcml0aXNlZCBmb3IgY2FwYWNpdHkgbWFuYWdlbWVudCwgZHdlbGwtdGltZSBjb250cm9sLCBhbmQgcGFzc2VuZ2VyIGZhY2lsaXR5IHVwZ3JhZGVzLCBhcyBjb25nZXN0aW9uIG9yIGRlbGF5IGhlcmUgaXMgbGlrZWx5IHRvIHByb3BhZ2F0ZSBhbG9uZyB0aGUgcm91dGUuXQ0KDQojIyMjIFExMC4gUmVsaWFiaWxpdHkgSGVhdG1hcCAoZ2dwbG90MikNCkNyZWF0ZSBhIGhlYXRtYXAgKGBnZW9tX3RpbGVgKSB3aGVyZSB0aGUgWC1heGlzIGlzIGBkYXlfb2Zfd2Vla2AsIHRoZSBZLWF4aXMgaXMgYHJvdXRlX2lkYCwgYW5kIHRoZSAqKmZpbGwgY29sb3IqKiByZXByZXNlbnRzIHRoZSBhdmVyYWdlIGRlbGF5Lg0KDQpgYGB7ciBxMTB9DQpkZl9jbGVhbiRkZWxheV9taW51dGVzIDwtDQogIChhcy5udW1lcmljKGRmX2NsZWFuJGFycml2YWxfdGltZV9hY3R1YWwpIC0NCiAgYXMubnVtZXJpYyhkZl9jbGVhbiRhcnJpdmFsX3RpbWVfc2NoZWR1bGVkKSkgLyA2MA0KZGVsYXlfc3VtbWFyeSA8LSBkZl9jbGVhbiAlPiUNCiAgZ3JvdXBfYnkocm91dGVfaWQsIGRheV9vZl93ZWVrKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGF2Z19kZWxheSA9IG1lYW4oZGVsYXlfbWludXRlcywgbmEucm0gPSBUUlVFKSwNCiAgICAuZ3JvdXBzID0gImRyb3AiICkNCg0KbmV0d29ya19hdmcgPC0gbWVhbihkZWxheV9zdW1tYXJ5JGF2Z19kZWxheSwgbmEucm0gPSBUUlVFKQ0KDQpkZWxheV9zdW1tYXJ5IDwtIGRlbGF5X3N1bW1hcnkgJT4lDQogIG11dGF0ZSggZGVsYXlfdnNfbmV0d29yayA9IGF2Z19kZWxheSAtIG5ldHdvcmtfYXZnICkNCg0KZ2dwbG90KCBkZWxheV9zdW1tYXJ5LA0KICBhZXMoDQogICAgeCA9IGRheV9vZl93ZWVrLA0KICAgIHkgPSByb3V0ZV9pZCwNCiAgICBmaWxsID0gZGVsYXlfdnNfbmV0d29yayApICkgKw0KICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKA0KICAgIGNvbG91cnMgPSBjKCIjNDA1MTNCIiwgIiM2MjgxNDEiLCAiI0U1RDlCNiIsICIjRTY3RTIyIiksDQogICAgdmFsdWVzID0gc2NhbGVzOjpyZXNjYWxlKGMoDQogICAgICBtaW4oZGVsYXlfc3VtbWFyeSRkZWxheV92c19uZXR3b3JrKSwNCiAgICAgIC01LCAwLA0KICAgICAgbWF4KGRlbGF5X3N1bW1hcnkkZGVsYXlfdnNfbmV0d29yaykgKSksDQogICAgbmFtZSA9ICJEZXZpYXRpb24gZnJvbVxuTmV0d29yayBBdmcgKG1pbikiICkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlJvdXRlIFJlbGlhYmlsaXR5IFJlbGF0aXZlIHRvIE5ldHdvcmsgQXZlcmFnZSIsDQogICAgc3VidGl0bGUgPSAiUm91dGVzIHBlcmZvcm1pbmcgYmV0dGVyIG9yIHdvcnNlIHRoYW4gbmV0d29yayBhdmVyYWdlIGJ5IGRheSIsDQogICAgeCA9ICJEYXkgb2YgV2VlayIsDQogICAgeSA9ICJSb3V0ZSBJRCINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoqKkludGVycHJldGF0aW9uOioqIFtNVU1fUm91dGVfQiBhbmQgTVVNX1JvdXRlX0QgcGVyZm9ybSBiZXR0ZXIgdGhhbiB0aGUgbmV0d29yayBhdmVyYWdlIG9uIG11bHRpcGxlIHdlZWtkYXlzLCBzdWdnZXN0aW5nIG1vcmUgc3RhYmxlIG9wZXJhdGlvbnMgYW5kIGJldHRlciBzY2hlZHVsZSBhZGhlcmVuY2UuDQoNCk1VTV9Sb3V0ZV9FIHNob3dzIGNvbXBhcmF0aXZlbHkgcG9vcmVyIHJlbGlhYmlsaXR5IG9uIGNlcnRhaW4gbWlkLXdlZWsgZGF5cywgaW5kaWNhdGluZyByZWN1cnJpbmcgb3BlcmF0aW9uYWwgY29uc3RyYWludHMgdGhhdCBtYXkgYmUgbGlua2VkIHRvIGNvbmdlc3Rpb24gb3Igcm91dGUgZGVzaWduLg0KDQpNVU1fUm91dGVfQyBleGhpYml0cyBzdHJvbmcgcGVyZm9ybWFuY2Ugb24gc29tZSBkYXlzIGJ1dCBkZXRlcmlvcmF0ZXMgb24gb3RoZXJzLCByZWZsZWN0aW5nIGluY29uc2lzdGVudCByZWxpYWJpbGl0eSByYXRoZXIgdGhhbiBwZXJzaXN0ZW50IHVuZGVycGVyZm9ybWFuY2UuDQoNClRoZXNlIHBhdHRlcm5zIGhpZ2hsaWdodCB0aGUgbmVlZCBmb3Igcm91dGUtIGFuZCBkYXktc3BlY2lmaWMgcmVsaWFiaWxpdHkgaW50ZXJ2ZW50aW9ucywgc3VjaCBhcyB0YXJnZXRlZCBzY2hlZHVsZSBhZGp1c3RtZW50cywgZmxlZXQgYWxsb2NhdGlvbiwgb3Igb3BlcmF0aW9uYWwgcHJpb3JpdHkgbWVhc3VyZXMsIGluc3RlYWQgb2YgdW5pZm9ybSBzeXN0ZW0td2lkZSBzb2x1dGlvbnMuXQ0KYGBgDQo=