This assignment focuses on analyzing public transport operations in
Mumbai. You are provided with a dataset containing trip details,
passenger counts, and weather conditions.
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.]
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=