Cyclist MidBlock
Analysis for Cyclist MidBlock
This analysis focuses on mode: cyclist | intersection: no |
| Variable |
Level |
Injury |
p0 |
Non-Injury |
p1 |
OddsRatio |
Lower |
Upper |
P-Value |
| oneway |
No |
167 |
0.9598 |
72 |
0.9863 |
1 |
|
|
|
|
Yes |
7 |
0.0402 |
1 |
0.0137 |
0.3313 |
0.04 |
2.7424 |
0.4424 |
| twoways |
No |
6 |
0.0345 |
0 |
0 |
1 |
|
|
|
|
Yes |
168 |
0.9655 |
73 |
1 |
Inf |
|
Inf |
0.1837 |
| clearzone |
No |
174 |
1 |
71 |
0.9726 |
1 |
|
|
|
|
Yes |
0 |
0 |
2 |
0.0274 |
Inf |
|
Inf |
0.0865 |
| onstreetparking |
No |
97 |
0.5575 |
33 |
0.4521 |
1 |
|
|
|
|
Yes |
77 |
0.4425 |
40 |
0.5479 |
1.527 |
0.8814 |
2.6452 |
0.1624 |
| parkinglotgarage |
No |
57 |
0.3276 |
31 |
0.4247 |
1 |
|
|
|
|
Yes |
117 |
0.6724 |
42 |
0.5753 |
0.66 |
0.3764 |
1.1576 |
0.1491 |
| concretebarrier |
No |
172 |
0.9885 |
73 |
1 |
1 |
|
|
|
|
Yes |
2 |
0.0115 |
0 |
0 |
0 |
0 |
|
1 |
| laneofparkedcars |
No |
170 |
0.977 |
73 |
1 |
1 |
|
|
|
|
Yes |
4 |
0.023 |
0 |
0 |
0 |
0 |
|
0.3224 |
| bikelanewithbarrier |
No |
174 |
1 |
71 |
0.9726 |
1 |
|
|
|
|
Yes |
0 |
0 |
2 |
0.0274 |
Inf |
|
Inf |
0.0865 |
| offroadbikepathcycletrack |
No |
172 |
0.9885 |
73 |
1 |
1 |
|
|
|
|
Yes |
2 |
0.0115 |
0 |
0 |
0 |
0 |
|
1 |
| raisedbikelane |
No |
171 |
0.9828 |
72 |
0.9863 |
1 |
|
|
|
|
Yes |
3 |
0.0172 |
1 |
0.0137 |
0.7917 |
0.081 |
7.7388 |
1 |
| twowayprotectedbicyclelane |
No |
171 |
0.9828 |
72 |
0.9863 |
1 |
|
|
|
|
Yes |
3 |
0.0172 |
1 |
0.0137 |
0.7917 |
0.081 |
7.7388 |
1 |
| onewayprotectedbicyclelane |
No |
174 |
1 |
72 |
0.9863 |
1 |
|
|
|
|
Yes |
0 |
0 |
1 |
0.0137 |
Inf |
|
Inf |
0.2955 |
| bufferedbicyclelaneadjacenttocurb |
No |
169 |
0.9713 |
72 |
0.9863 |
1 |
|
|
|
|
Yes |
5 |
0.0287 |
1 |
0.0137 |
0.4694 |
0.0539 |
4.0897 |
0.6732 |
| bufferedbicyclelaneoffsetfromcurb |
No |
174 |
1 |
72 |
0.9863 |
1 |
|
|
|
|
Yes |
0 |
0 |
1 |
0.0137 |
Inf |
|
Inf |
0.2955 |
| paintedbicyclelaneadjacenttocurb |
No |
138 |
0.7931 |
57 |
0.7808 |
1 |
|
|
|
|
Yes |
36 |
0.2069 |
16 |
0.2192 |
1.076 |
0.5535 |
2.092 |
0.8648 |
| paintedbicyclelaneoffsetfromcurb |
No |
165 |
0.9483 |
68 |
0.9315 |
1 |
|
|
|
|
Yes |
9 |
0.0517 |
5 |
0.0685 |
1.348 |
0.4358 |
4.1694 |
0.5621 |
| bikeaccessibleshoulder |
No |
162 |
0.931 |
68 |
0.9315 |
1 |
|
|
|
|
Yes |
12 |
0.069 |
5 |
0.0685 |
0.9926 |
0.3368 |
2.926 |
1 |
| sharedlanewithmarkings |
No |
166 |
0.954 |
72 |
0.9863 |
1 |
|
|
|
|
Yes |
8 |
0.046 |
1 |
0.0137 |
0.2882 |
0.0354 |
2.3468 |
0.2884 |
NULL
if (nrow(odds_ratios_data) > 0) {
odds_ratios_restructured <- odds_ratios_data %>%
filter(!is.na(OddsRatio)) %>%
mutate(Reference = ifelse(Level == "No", "Yes", "No")) %>%
select(Variable, Level, Reference, OddsRatio, Lower, Upper, PValue)
odds_ratios_restructured$Variable <- factor(odds_ratios_restructured$Variable, levels = unique(odds_ratios_restructured$Variable))
restructured_table_html <- odds_ratios_restructured %>%
kable("html", caption = "Restructured Odds Ratio Analysis for Medical Interpretation",
col.names = c("Variable", "Level", "Reference", "Odds Ratio", "Lower 95% CI", "Upper 95% CI", "P-Value")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, background = "#333333", color = "white") %>%
row_spec(1:nrow(odds_ratios_restructured), background = rep(c("#f9f9f9", "#ffffff"), length.out = nrow(odds_ratios_restructured))) %>%
add_header_above(c(" " = 3, "Odds Ratio Analysis" = 5))
print(restructured_table_html)
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring. Skipping this section.</p><br>")
}
Restructured Odds Ratio Analysis for Medical Interpretation
|
Odds Ratio Analysis |
| |
Variable |
Level |
Reference |
Odds Ratio |
Lower 95% CI |
Upper 95% CI |
P-Value |
| oneway.No |
oneway |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| oneway.Yes |
|
Yes |
No |
0.3313 |
0.0400 |
2.7424 |
0.4424 |
| twoways.No |
twoways |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| twoways.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.1837 |
| clearzone.No |
clearzone |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| clearzone.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.0865 |
| onstreetparking.No |
onstreetparking |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| onstreetparking.Yes |
|
Yes |
No |
1.5270 |
0.8814 |
2.6452 |
0.1624 |
| parkinglotgarage.No |
parkinglotgarage |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| parkinglotgarage.Yes |
|
Yes |
No |
0.6600 |
0.3764 |
1.1576 |
0.1491 |
| concretebarrier.No |
concretebarrier |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| concretebarrier.Yes |
|
Yes |
No |
0.0000 |
0.0000 |
NaN |
1.0000 |
| laneofparkedcars.No |
laneofparkedcars |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| laneofparkedcars.Yes |
|
Yes |
No |
0.0000 |
0.0000 |
NaN |
0.3224 |
| bikelanewithbarrier.No |
bikelanewithbarrier |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bikelanewithbarrier.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.0865 |
| offroadbikepathcycletrack.No |
offroadbikepathcycletrack |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| offroadbikepathcycletrack.Yes |
|
Yes |
No |
0.0000 |
0.0000 |
NaN |
1.0000 |
| raisedbikelane.No |
raisedbikelane |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| raisedbikelane.Yes |
|
Yes |
No |
0.7917 |
0.0810 |
7.7388 |
1.0000 |
| twowayprotectedbicyclelane.No |
twowayprotectedbicyclelane |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| twowayprotectedbicyclelane.Yes |
|
Yes |
No |
0.7917 |
0.0810 |
7.7388 |
1.0000 |
| onewayprotectedbicyclelane.No |
onewayprotectedbicyclelane |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| onewayprotectedbicyclelane.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.2955 |
| bufferedbicyclelaneadjacenttocurb.No |
bufferedbicyclelaneadjacenttocurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bufferedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
0.4694 |
0.0539 |
4.0897 |
0.6732 |
| bufferedbicyclelaneoffsetfromcurb.No |
bufferedbicyclelaneoffsetfromcurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bufferedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.2955 |
| paintedbicyclelaneadjacenttocurb.No |
paintedbicyclelaneadjacenttocurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| paintedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
1.0760 |
0.5535 |
2.0920 |
0.8648 |
| paintedbicyclelaneoffsetfromcurb.No |
paintedbicyclelaneoffsetfromcurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| paintedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
1.3480 |
0.4358 |
4.1694 |
0.5621 |
| bikeaccessibleshoulder.No |
bikeaccessibleshoulder |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bikeaccessibleshoulder.Yes |
|
Yes |
No |
0.9926 |
0.3368 |
2.9260 |
1.0000 |
| sharedlanewithmarkings.No |
sharedlanewithmarkings |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| sharedlanewithmarkings.Yes |
|
Yes |
No |
0.2882 |
0.0354 |
2.3468 |
0.2884 |
NULL
if (nrow(odds_ratios_data) > 0) {
odds_ratios_restructured <- odds_ratios_data %>%
filter(!is.na(OddsRatio)) %>%
mutate(Reference = ifelse(Level == "No", "Yes", "No")) %>%
select(Variable, Level, Reference, OddsRatio, Lower, Upper, PValue)
odds_ratios_restructured$Variable <- factor(odds_ratios_restructured$Variable, levels = unique(odds_ratios_restructured$Variable))
restructured_table_html <- odds_ratios_restructured %>%
kable("html", caption = "Restructured Odds Ratio Analysis for Medical Interpretation",
col.names = c("Variable", "Level", "Reference", "Odds Ratio", "Lower 95% CI", "Upper 95% CI", "P-Value")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, background = "#333333", color = "white") %>%
row_spec(1:nrow(odds_ratios_restructured), background = rep(c("#f9f9f9", "#ffffff"), length.out = nrow(odds_ratios_restructured)))
print(restructured_table_html)
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring. Skipping this section.</p><br>")
}
Restructured Odds Ratio Analysis for Medical Interpretation
| |
Variable |
Level |
Reference |
Odds Ratio |
Lower 95% CI |
Upper 95% CI |
P-Value |
| oneway.No |
oneway |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| oneway.Yes |
|
Yes |
No |
0.3313 |
0.0400 |
2.7424 |
0.4424 |
| twoways.No |
twoways |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| twoways.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.1837 |
| clearzone.No |
clearzone |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| clearzone.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.0865 |
| onstreetparking.No |
onstreetparking |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| onstreetparking.Yes |
|
Yes |
No |
1.5270 |
0.8814 |
2.6452 |
0.1624 |
| parkinglotgarage.No |
parkinglotgarage |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| parkinglotgarage.Yes |
|
Yes |
No |
0.6600 |
0.3764 |
1.1576 |
0.1491 |
| concretebarrier.No |
concretebarrier |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| concretebarrier.Yes |
|
Yes |
No |
0.0000 |
0.0000 |
NaN |
1.0000 |
| laneofparkedcars.No |
laneofparkedcars |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| laneofparkedcars.Yes |
|
Yes |
No |
0.0000 |
0.0000 |
NaN |
0.3224 |
| bikelanewithbarrier.No |
bikelanewithbarrier |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bikelanewithbarrier.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.0865 |
| offroadbikepathcycletrack.No |
offroadbikepathcycletrack |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| offroadbikepathcycletrack.Yes |
|
Yes |
No |
0.0000 |
0.0000 |
NaN |
1.0000 |
| raisedbikelane.No |
raisedbikelane |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| raisedbikelane.Yes |
|
Yes |
No |
0.7917 |
0.0810 |
7.7388 |
1.0000 |
| twowayprotectedbicyclelane.No |
twowayprotectedbicyclelane |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| twowayprotectedbicyclelane.Yes |
|
Yes |
No |
0.7917 |
0.0810 |
7.7388 |
1.0000 |
| onewayprotectedbicyclelane.No |
onewayprotectedbicyclelane |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| onewayprotectedbicyclelane.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.2955 |
| bufferedbicyclelaneadjacenttocurb.No |
bufferedbicyclelaneadjacenttocurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bufferedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
0.4694 |
0.0539 |
4.0897 |
0.6732 |
| bufferedbicyclelaneoffsetfromcurb.No |
bufferedbicyclelaneoffsetfromcurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bufferedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
Inf |
NaN |
Inf |
0.2955 |
| paintedbicyclelaneadjacenttocurb.No |
paintedbicyclelaneadjacenttocurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| paintedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
1.0760 |
0.5535 |
2.0920 |
0.8648 |
| paintedbicyclelaneoffsetfromcurb.No |
paintedbicyclelaneoffsetfromcurb |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| paintedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
1.3480 |
0.4358 |
4.1694 |
0.5621 |
| bikeaccessibleshoulder.No |
bikeaccessibleshoulder |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| bikeaccessibleshoulder.Yes |
|
Yes |
No |
0.9926 |
0.3368 |
2.9260 |
1.0000 |
| sharedlanewithmarkings.No |
sharedlanewithmarkings |
No |
Yes |
1.0000 |
NA |
NA |
NA |
| sharedlanewithmarkings.Yes |
|
Yes |
No |
0.2882 |
0.0354 |
2.3468 |
0.2884 |
NULL
if (nrow(odds_ratios_data) > 0) {
odds_ratios_restructured <- odds_ratios_data %>%
filter(!is.na(OddsRatio)) %>%
mutate(
Reference = ifelse(Level == "No", "Yes", "No"),
Significant = ifelse(PValue < 0.05, TRUE, FALSE),
CI_95 = ifelse(!is.na(Lower) & !is.na(Upper), paste0("(", round(Lower, 2), ", ", round(Upper, 2), ")"), "NA")
) %>%
select(Variable, Level, Reference, OddsRatio, CI_95, PValue, Significant)
odds_ratios_restructured_filtered <- odds_ratios_restructured %>%
filter(!(OddsRatio == 1 & CI_95 == "NA"))
odds_ratios_restructured_filtered$Variable <- factor(odds_ratios_restructured_filtered$Variable, levels = unique(odds_ratios_restructured_filtered$Variable))
if (nrow(odds_ratios_restructured_filtered) > 0) {
odds_ratios_restructured_filtered_for_table <- odds_ratios_restructured_filtered %>%
select(-Significant)
restructured_table_html <- odds_ratios_restructured_filtered_for_table %>%
kable("html", caption = "Restructured Odds Ratio Analysis for Medical Interpretation",
col.names = c("Variable", "Level", "Reference", "Odds Ratio", "CI (95%)", "P-Value")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, background = "#333333", color = "white")
if (any(odds_ratios_restructured_filtered$Significant == TRUE)) {
restructured_table_html <- restructured_table_html %>%
row_spec(
which(odds_ratios_restructured_filtered$Significant == TRUE),
background = "#ffcccc"
)
}
restructured_table_html <- restructured_table_html %>%
row_spec(1:nrow(odds_ratios_restructured_filtered_for_table), background = rep(c("#f9f9f9", "#ffffff"), length.out = nrow(odds_ratios_restructured_filtered_for_table)))
print(restructured_table_html)
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring after filtering. Skipping this section.</p><br>")
}
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring. Skipping this section.</p><br>")
}
Restructured Odds Ratio Analysis for Medical Interpretation
| |
Variable |
Level |
Reference |
Odds Ratio |
CI (95%) |
P-Value |
| oneway.Yes |
|
Yes |
No |
0.3313 |
(0.04, 2.74) |
0.4424 |
| twoways.Yes |
|
Yes |
No |
Inf |
NA |
0.1837 |
| clearzone.Yes |
|
Yes |
No |
Inf |
NA |
0.0865 |
| onstreetparking.Yes |
|
Yes |
No |
1.5270 |
(0.88, 2.65) |
0.1624 |
| parkinglotgarage.Yes |
|
Yes |
No |
0.6600 |
(0.38, 1.16) |
0.1491 |
| concretebarrier.Yes |
|
Yes |
No |
0.0000 |
NA |
1.0000 |
| laneofparkedcars.Yes |
|
Yes |
No |
0.0000 |
NA |
0.3224 |
| bikelanewithbarrier.Yes |
|
Yes |
No |
Inf |
NA |
0.0865 |
| offroadbikepathcycletrack.Yes |
|
Yes |
No |
0.0000 |
NA |
1.0000 |
| raisedbikelane.Yes |
|
Yes |
No |
0.7917 |
(0.08, 7.74) |
1.0000 |
| twowayprotectedbicyclelane.Yes |
|
Yes |
No |
0.7917 |
(0.08, 7.74) |
1.0000 |
| onewayprotectedbicyclelane.Yes |
|
Yes |
No |
Inf |
NA |
0.2955 |
| bufferedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
0.4694 |
(0.05, 4.09) |
0.6732 |
| bufferedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
Inf |
NA |
0.2955 |
| paintedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
1.0760 |
(0.55, 2.09) |
0.8648 |
| paintedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
1.3480 |
(0.44, 4.17) |
0.5621 |
| bikeaccessibleshoulder.Yes |
|
Yes |
No |
0.9926 |
(0.34, 2.93) |
1.0000 |
| sharedlanewithmarkings.Yes |
|
Yes |
No |
0.2882 |
(0.04, 2.35) |
0.2884 |
NULL
if (nrow(odds_ratios_data) > 0) {
odds_ratios_restructured <- odds_ratios_data %>%
filter(!is.na(OddsRatio)) %>%
mutate(
Reference = ifelse(Level == "No", "Yes", "No"),
Significant = ifelse(!is.na(PValue) & PValue < 0.05, TRUE, FALSE),
CI_95 = ifelse(!is.na(Lower) & !is.na(Upper), paste0("(", round(Lower, 2), ", ", round(Upper, 2), ")"), "NA")
) %>%
select(Variable, Level, Reference, OddsRatio, CI_95, PValue, Significant)
odds_ratios_restructured$Variable <- factor(odds_ratios_restructured$Variable, levels = unique(odds_ratios_restructured$Variable))
if (nrow(odds_ratios_restructured) > 0) {
odds_ratios_restructured_for_table <- odds_ratios_restructured %>%
select(-Significant)
restructured_table_html <- odds_ratios_restructured_for_table %>%
kable("html", caption = "Restructured Odds Ratio Analysis for Medical Interpretation (Showing Both Levels)",
col.names = c("Variable", "Level", "Reference", "Odds Ratio", "CI (95%)", "P-Value")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = FALSE) %>%
row_spec(0, bold = TRUE, background = "#333333", color = "white")
if (any(odds_ratios_restructured$Significant == TRUE, na.rm = TRUE)) {
restructured_table_html <- restructured_table_html %>%
row_spec(
which(odds_ratios_restructured$Significant == TRUE),
background = "#ffcccc"
)
}
restructured_table_html <- restructured_table_html %>%
row_spec(1:nrow(odds_ratios_restructured_for_table), background = rep(c("#f9f9f9", "#ffffff"), length.out = nrow(odds_ratios_restructured_for_table)))
print(restructured_table_html)
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring after filtering. Skipping this section.</p><br>")
}
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring. Skipping this section.</p><br>")
}
Restructured Odds Ratio Analysis for Medical Interpretation (Showing Both Levels)
| |
Variable |
Level |
Reference |
Odds Ratio |
CI (95%) |
P-Value |
| oneway.No |
oneway |
No |
Yes |
1.0000 |
NA |
NA |
| oneway.Yes |
|
Yes |
No |
0.3313 |
(0.04, 2.74) |
0.4424 |
| twoways.No |
twoways |
No |
Yes |
1.0000 |
NA |
NA |
| twoways.Yes |
|
Yes |
No |
Inf |
NA |
0.1837 |
| clearzone.No |
clearzone |
No |
Yes |
1.0000 |
NA |
NA |
| clearzone.Yes |
|
Yes |
No |
Inf |
NA |
0.0865 |
| onstreetparking.No |
onstreetparking |
No |
Yes |
1.0000 |
NA |
NA |
| onstreetparking.Yes |
|
Yes |
No |
1.5270 |
(0.88, 2.65) |
0.1624 |
| parkinglotgarage.No |
parkinglotgarage |
No |
Yes |
1.0000 |
NA |
NA |
| parkinglotgarage.Yes |
|
Yes |
No |
0.6600 |
(0.38, 1.16) |
0.1491 |
| concretebarrier.No |
concretebarrier |
No |
Yes |
1.0000 |
NA |
NA |
| concretebarrier.Yes |
|
Yes |
No |
0.0000 |
NA |
1.0000 |
| laneofparkedcars.No |
laneofparkedcars |
No |
Yes |
1.0000 |
NA |
NA |
| laneofparkedcars.Yes |
|
Yes |
No |
0.0000 |
NA |
0.3224 |
| bikelanewithbarrier.No |
bikelanewithbarrier |
No |
Yes |
1.0000 |
NA |
NA |
| bikelanewithbarrier.Yes |
|
Yes |
No |
Inf |
NA |
0.0865 |
| offroadbikepathcycletrack.No |
offroadbikepathcycletrack |
No |
Yes |
1.0000 |
NA |
NA |
| offroadbikepathcycletrack.Yes |
|
Yes |
No |
0.0000 |
NA |
1.0000 |
| raisedbikelane.No |
raisedbikelane |
No |
Yes |
1.0000 |
NA |
NA |
| raisedbikelane.Yes |
|
Yes |
No |
0.7917 |
(0.08, 7.74) |
1.0000 |
| twowayprotectedbicyclelane.No |
twowayprotectedbicyclelane |
No |
Yes |
1.0000 |
NA |
NA |
| twowayprotectedbicyclelane.Yes |
|
Yes |
No |
0.7917 |
(0.08, 7.74) |
1.0000 |
| onewayprotectedbicyclelane.No |
onewayprotectedbicyclelane |
No |
Yes |
1.0000 |
NA |
NA |
| onewayprotectedbicyclelane.Yes |
|
Yes |
No |
Inf |
NA |
0.2955 |
| bufferedbicyclelaneadjacenttocurb.No |
bufferedbicyclelaneadjacenttocurb |
No |
Yes |
1.0000 |
NA |
NA |
| bufferedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
0.4694 |
(0.05, 4.09) |
0.6732 |
| bufferedbicyclelaneoffsetfromcurb.No |
bufferedbicyclelaneoffsetfromcurb |
No |
Yes |
1.0000 |
NA |
NA |
| bufferedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
Inf |
NA |
0.2955 |
| paintedbicyclelaneadjacenttocurb.No |
paintedbicyclelaneadjacenttocurb |
No |
Yes |
1.0000 |
NA |
NA |
| paintedbicyclelaneadjacenttocurb.Yes |
|
Yes |
No |
1.0760 |
(0.55, 2.09) |
0.8648 |
| paintedbicyclelaneoffsetfromcurb.No |
paintedbicyclelaneoffsetfromcurb |
No |
Yes |
1.0000 |
NA |
NA |
| paintedbicyclelaneoffsetfromcurb.Yes |
|
Yes |
No |
1.3480 |
(0.44, 4.17) |
0.5621 |
| bikeaccessibleshoulder.No |
bikeaccessibleshoulder |
No |
Yes |
1.0000 |
NA |
NA |
| bikeaccessibleshoulder.Yes |
|
Yes |
No |
0.9926 |
(0.34, 2.93) |
1.0000 |
| sharedlanewithmarkings.No |
sharedlanewithmarkings |
No |
Yes |
1.0000 |
NA |
NA |
| sharedlanewithmarkings.Yes |
|
Yes |
No |
0.2882 |
(0.04, 2.35) |
0.2884 |
NULL
if (nrow(odds_ratios_data) > 0) {
odds_ratios_restructured <- odds_ratios_data %>%
filter(!is.na(OddsRatio)) %>%
mutate(
Reference = ifelse(Level == "No", "Yes", "No"),
Significant = ifelse(!is.na(PValue) & PValue < 0.05, TRUE, FALSE),
CI_95 = ifelse(!is.na(Lower) & !is.na(Upper), paste0("(", round(Lower, 2), ", ", round(Upper, 2), ")"), "-"),
PValue = ifelse(is.na(PValue), "-", as.character(round(PValue, 4))),
OddsRatio = ifelse(is.na(OddsRatio), "-", as.character(round(OddsRatio, 4))),
NonInjury = ifelse(is.na(NonInjury), "-", as.character(NonInjury)),
p1 = ifelse(is.na(p1), "-", paste0(round(as.numeric(p1) * 100, 2), "%"))
) %>%
select(Variable, Level, Reference, NonInjury, p1, OddsRatio, CI_95, PValue, Significant)
odds_ratios_grouped <- odds_ratios_restructured %>%
arrange(Variable) %>%
group_by(Variable) %>%
mutate(
Level_Grouped = paste(Level, collapse = " / "),
OddsRatio_Grouped = paste(OddsRatio, collapse = " / "),
CI_95_Grouped = paste(CI_95, collapse = " / "),
PValue_Grouped = paste(PValue, collapse = " / "),
NonInjury_Grouped = paste(NonInjury, collapse = " / "),
p1_Grouped = paste(p1, collapse = " / ")
) %>%
slice(1) %>%
ungroup() %>%
select(Variable, Level_Grouped, Reference, NonInjury_Grouped, p1_Grouped, OddsRatio_Grouped, CI_95_Grouped, PValue_Grouped, Significant)
odds_ratios_grouped$Variable <- factor(odds_ratios_grouped$Variable, levels = unique(odds_ratios_grouped$Variable))
if (nrow(odds_ratios_grouped) > 0) {
odds_ratios_for_table <- odds_ratios_grouped %>%
select(-Significant)
restructured_table_html <- odds_ratios_for_table %>%
kable("html", caption = "Restructured Odds Ratio Analysis for Medical Interpretation (Grouped Levels)",
col.names = c("Variable", "Level (Yes / No)", "Reference", "Non-Injury (Count)", "Non-Injury (%)", "Odds Ratio (Yes / No)", "CI (95%) (Yes / No)", "P-Value (Yes / No)")) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"), full_width = FALSE, position = "center") %>%
row_spec(0, bold = TRUE, background = "#333333", color = "white") %>%
column_spec(1:8, width = "5em", border_left = TRUE, border_right = TRUE)
if (any(odds_ratios_grouped$Significant == TRUE, na.rm = TRUE)) {
restructured_table_html <- restructured_table_html %>%
row_spec(
which(odds_ratios_grouped$Significant == TRUE),
background = "#ffcccc"
)
}
restructured_table_html <- restructured_table_html %>%
row_spec(1:nrow(odds_ratios_for_table), background = rep(c("#f9f9f9", "#ffffff"), length.out = nrow(odds_ratios_for_table)))
print(restructured_table_html)
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring after filtering. Skipping this section.</p><br>")
}
} else {
cat("<p><strong>Warning:</strong> No data available for restructuring. Skipping this section.</p><br>")
}
Error in `mutate()`:
ℹ In argument: `NonInjury = ifelse(is.na(NonInjury), "-", as.character(NonInjury))`.
Caused by error:
! object 'NonInjury' not found
Backtrace:
1. ... %>% ...
10. base::ifelse(is.na(NonInjury), "-", as.character(NonInjury))
LS0tCnRpdGxlOiAiQWNjaWRlbnQgQW5hbHlzaXM6IEN5Y2xpc3RzIGFuZCBQZWRlc3RyaWFucyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAyCiAgICB0aGVtZTogY29zbW8KICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogJzInCi0tLQoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGVwaXRvb2xzKQpsaWJyYXJ5KGh0bWxUYWJsZSkKbGlicmFyeShodG1sdG9vbHMpCgpkYXRhIDwtIHJlYWQuY3N2KCIvVXNlcnMvbmF0YWxpb2Nob2EvUm9hZFNhZmV0eS9SZXN1bHRzSUNCQy5jc3YiKQpgYGAKCiMjIyMjIyBDeWNsaXN0IE1pZEJsb2NrCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBGaWx0ZXIgZGF0YSBmb3IgQ3ljbGlzdCBNaWRCbG9jayAKZ3JvdXBfZGF0YSA8LSBkYXRhICU+JQogIGZpbHRlcihtb2RlID09ICJDeWNsaXN0IiwgaW50ZXJzZWN0aW9uID09ICJObyIpCgppZiAobnJvdyhncm91cF9kYXRhKSA+IDApIHsKICAjIFNwZWNpZnkgdGhlIHZhcmlhYmxlcyB0byBhbmFseXplIGZvciBDeWNsaXN0IE1pZEJsb2NrIAogIGdyb3VwX3ZhcnMgPC0gYygib25ld2F5IiwgInR3b3dheXMiLCAiY2xlYXJ6b25lIiwgIm9uc3RyZWV0cGFya2luZyIsIAogICAgICAgICAgICAgICAgICAicGFya2luZ2xvdGdhcmFnZSIsICJjb25jcmV0ZWJhcnJpZXIiLCAibGFuZW9mcGFya2VkY2FycyIsIAogICAgICAgICAgICAgICAgICAiYmlrZWxhbmV3aXRoYmFycmllciIsICJvZmZyb2FkYmlrZXBhdGhjeWNsZXRyYWNrIiwgCiAgICAgICAgICAgICAgICAgICJyYWlzZWRiaWtlbGFuZSIsICJ0d293YXlwcm90ZWN0ZWRiaWN5Y2xlbGFuZSIsIAogICAgICAgICAgICAgICAgICAib25ld2F5cHJvdGVjdGVkYmljeWNsZWxhbmUiLCAiYnVmZmVyZWRiaWN5Y2xlbGFuZWFkamFjZW50dG9jdXJiIiwgCiAgICAgICAgICAgICAgICAgICJidWZmZXJlZGJpY3ljbGVsYW5lb2Zmc2V0ZnJvbWN1cmIiLCAKICAgICAgICAgICAgICAgICAgInBhaW50ZWRiaWN5Y2xlbGFuZWFkamFjZW50dG9jdXJiIiwgCiAgICAgICAgICAgICAgICAgICJwYWludGVkYmljeWNsZWxhbmVvZmZzZXRmcm9tY3VyYiIsICJiaWtlYWNjZXNzaWJsZXNob3VsZGVyIiwgCiAgICAgICAgICAgICAgICAgICJzaGFyZWRsYW5ld2l0aG1hcmtpbmdzIikKCiAgb2Rkc19yYXRpb3NfbGlzdCA8LSBsaXN0KCkKICBzdGFuZGFyZF9jb2x1bW5zIDwtIGMoIlZhcmlhYmxlIiwgIkxldmVsIiwgIkluanVyeSIsICJwMCIsICJOb24tSW5qdXJ5IiwgInAxIiwgIk9kZHNSYXRpbyIsICJMb3dlciIsICJVcHBlciIsICJQVmFsdWUiKQoKICBmb3IgKHZhciBpbiBncm91cF92YXJzKSB7CiAgICBpZiAodmFyICVpbiUgbmFtZXMoZ3JvdXBfZGF0YSkpIHsKICAgICAgb2Rkc19yYXRpb19yZXN1bHQgPC0gdHJ5Q2F0Y2goewogICAgICAgIGlmIChuX2Rpc3RpbmN0KGdyb3VwX2RhdGFbW3Zhcl1dKSA9PSAyKSB7CiAgICAgICAgICBvZGRzX2RhdGEgPC0gZ3JvdXBfZGF0YSAlPiUKICAgICAgICAgICAgc2VsZWN0KGFsbF9vZih2YXIpLCBjcmFzaHNldmVyaXR5KSAlPiUKICAgICAgICAgICAgdGFibGUoKSAlPiUKICAgICAgICAgICAgYXMubWF0cml4KCkKICAgICAgICAgIAogICAgICAgICAgb2Rkc19yYXRpb190YWJsZSA8LSBhcy5kYXRhLmZyYW1lKGVwaXRhYihvZGRzX2RhdGEsIG1ldGhvZCA9ICJvZGRzcmF0aW8iKSR0YWIpICU+JQogICAgICAgICAgICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCByb3VuZCwgNCkpCiAgICAgICAgICAKICAgICAgICAgIG9kZHNfcmF0aW9fdGFibGUgPC0gY2JpbmQoVmFyaWFibGUgPSB2YXIsIExldmVsID0gcm93bmFtZXMob2Rkc19yYXRpb190YWJsZSksIG9kZHNfcmF0aW9fdGFibGUpCiAgICAgICAgICBuYW1lcyhvZGRzX3JhdGlvX3RhYmxlKSA8LSBzdGFuZGFyZF9jb2x1bW5zCiAgICAgICAgICBvZGRzX3JhdGlvX3RhYmxlCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgICAgIFZhcmlhYmxlID0gdmFyLCBMZXZlbCA9IE5BLCBJbmp1cnkgPSAiTm90IGFwcGxpY2FibGUiLCAKICAgICAgICAgICAgcDAgPSBOQSwgTm9uSW5qdXJ5ID0gTkEsIHAxID0gTkEsIE9kZHNSYXRpbyA9IE5BLCAKICAgICAgICAgICAgTG93ZXIgPSBOQSwgVXBwZXIgPSBOQSwgUFZhbHVlID0gTkEsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQogICAgICAgICAgKQogICAgICAgIH0KICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiAgICAgICAgZGF0YS5mcmFtZSgKICAgICAgICAgIFZhcmlhYmxlID0gdmFyLCBMZXZlbCA9IE5BLCBJbmp1cnkgPSAiTm90IGFwcGxpY2FibGUiLCAKICAgICAgICAgIHAwID0gTkEsIE5vbkluanVyeSA9IE5BLCBwMSA9IE5BLCBPZGRzUmF0aW8gPSBOQSwgCiAgICAgICAgICBMb3dlciA9IE5BLCBVcHBlciA9IE5BLCBQVmFsdWUgPSBOQSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgICAgICAgKQogICAgICB9KQogICAgICAKICAgICAgb2Rkc19yYXRpb3NfbGlzdFtbdmFyXV0gPC0gb2Rkc19yYXRpb19yZXN1bHQKICAgIH0KICB9CiAgCiAgb2Rkc19yYXRpb3NfZGF0YSA8LSBkby5jYWxsKHJiaW5kLCBvZGRzX3JhdGlvc19saXN0KQogIHJvd19jb2xvcnMgPC0gcmVwKGMoIiNmOWY5ZjkiLCAiI2ZmZmZmZiIpLCBsZW5ndGgub3V0ID0gbnJvdyhvZGRzX3JhdGlvc19kYXRhKSkKICBvZGRzX3JhdGlvc19kYXRhJFZhcmlhYmxlIDwtIGlmZWxzZShkdXBsaWNhdGVkKG9kZHNfcmF0aW9zX2RhdGEkVmFyaWFibGUpLCAiIiwgb2Rkc19yYXRpb3NfZGF0YSRWYXJpYWJsZSkKCiAgZmluYWxfdGFibGVfaHRtbCA8LSBodG1sVGFibGUoCiAgICBvZGRzX3JhdGlvc19kYXRhLAogICAgaGVhZGVyID0gYygiVmFyaWFibGUiLCAiTGV2ZWwiLCAiSW5qdXJ5IiwgInAwIiwgIk5vbi1Jbmp1cnkiLCAicDEiLCAiT2Rkc1JhdGlvIiwgIkxvd2VyIiwgIlVwcGVyIiwgIlAtVmFsdWUiKSwKICAgIGFsaWduID0gJ2xjY2NjY2NjY2MnLAogICAgcm5hbWVzID0gRkFMU0UsCiAgICBjc3MuY2VsbCA9ICJ0ZXh0LWFsaWduOiBjZW50ZXI7IHBhZGRpbmc6IDEycHggMTVweDsgZm9udC1zaXplOiAxMnB4OyB3aGl0ZS1zcGFjZTogbm93cmFwOyIsCiAgICBjc3Mucm93ID0gc3ByaW50ZigiYmFja2dyb3VuZC1jb2xvcjogJXM7Iiwgcm93X2NvbG9ycyksCiAgICBoZWFkZXIuY3NzID0gImJhY2tncm91bmQtY29sb3I6ICMzMzMzMzM7IGZvbnQtc2l6ZTogMTRweDsgdGV4dC1hbGlnbjogY2VudGVyOyBjb2xvcjogd2hpdGU7IiwKICAgIGNhcHRpb24gPSAiPGgzIHN0eWxlPSd0ZXh0LWFsaWduOiBjZW50ZXI7Jz5BbmFseXNpcyBmb3IgQ3ljbGlzdCBNaWRCbG9jazwvaDM+CiAgICAgICAgICAgICAgIDxwIHN0eWxlPSd0ZXh0LWFsaWduOiBjZW50ZXI7Jz48ZW0+VGhpcyBhbmFseXNpcyBmb2N1c2VzIG9uIG1vZGU6IGN5Y2xpc3QgfCBpbnRlcnNlY3Rpb246IG5vPC9lbT48L3A+IgogICkKCiAgcHJpbnQoSFRNTChmaW5hbF90YWJsZV9odG1sKSkKfSBlbHNlIHsKICBjYXQoIjxwPjxzdHJvbmc+V2FybmluZzo8L3N0cm9uZz4gTm8gZGF0YSBhdmFpbGFibGUgZm9yIEN5Y2xpc3QgTWlkQmxvY2suIFNraXBwaW5nIGFuYWx5c2lzIGZvciB0aGlzIGdyb3VwLjwvcD48YnI+IikKfQoKYGBgCgpgYGB7cn0KCmlmIChucm93KG9kZHNfcmF0aW9zX2RhdGEpID4gMCkgewogIAoKICBvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQgPC0gb2Rkc19yYXRpb3NfZGF0YSAlPiUKICAgIGZpbHRlcighaXMubmEoT2Rkc1JhdGlvKSkgJT4lICAKICAgIG11dGF0ZShSZWZlcmVuY2UgPSBpZmVsc2UoTGV2ZWwgPT0gIk5vIiwgIlllcyIsICJObyIpKSAlPiUgIAogICAgc2VsZWN0KFZhcmlhYmxlLCBMZXZlbCwgUmVmZXJlbmNlLCBPZGRzUmF0aW8sIExvd2VyLCBVcHBlciwgUFZhbHVlKQoKICAKICBvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQkVmFyaWFibGUgPC0gZmFjdG9yKG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCRWYXJpYWJsZSwgbGV2ZWxzID0gdW5pcXVlKG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCRWYXJpYWJsZSkpCiAgCiAgCiAgcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgPC0gb2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkICU+JQogICAga2FibGUoImh0bWwiLCBjYXB0aW9uID0gIlJlc3RydWN0dXJlZCBPZGRzIFJhdGlvIEFuYWx5c2lzIGZvciBNZWRpY2FsIEludGVycHJldGF0aW9uIiwKICAgICAgICAgIGNvbC5uYW1lcyA9IGMoIlZhcmlhYmxlIiwgIkxldmVsIiwgIlJlZmVyZW5jZSIsICJPZGRzIFJhdGlvIiwgIkxvd2VyIDk1JSBDSSIsICJVcHBlciA5NSUgQ0kiLCAiUC1WYWx1ZSIpKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiksIGZ1bGxfd2lkdGggPSBGQUxTRSkgJT4lCiAgICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjMzMzMzMzIiwgY29sb3IgPSAid2hpdGUiKSAlPiUKICAgIHJvd19zcGVjKDE6bnJvdyhvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQpLCBiYWNrZ3JvdW5kID0gcmVwKGMoIiNmOWY5ZjkiLCAiI2ZmZmZmZiIpLCBsZW5ndGgub3V0ID0gbnJvdyhvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQpKSkgJT4lCiAgICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMywgIk9kZHMgUmF0aW8gQW5hbHlzaXMiID0gNSkpIAoKICBwcmludChyZXN0cnVjdHVyZWRfdGFibGVfaHRtbCkKfSBlbHNlIHsKICBjYXQoIjxwPjxzdHJvbmc+V2FybmluZzo8L3N0cm9uZz4gTm8gZGF0YSBhdmFpbGFibGUgZm9yIHJlc3RydWN0dXJpbmcuIFNraXBwaW5nIHRoaXMgc2VjdGlvbi48L3A+PGJyPiIpCn0KCmBgYAoKYGBge3J9CgppZiAobnJvdyhvZGRzX3JhdGlvc19kYXRhKSA+IDApIHsKICAKIAogIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCA8LSBvZGRzX3JhdGlvc19kYXRhICU+JQogICAgZmlsdGVyKCFpcy5uYShPZGRzUmF0aW8pKSAlPiUgIAogICAgbXV0YXRlKFJlZmVyZW5jZSA9IGlmZWxzZShMZXZlbCA9PSAiTm8iLCAiWWVzIiwgIk5vIikpICU+JSAgCiAgICBzZWxlY3QoVmFyaWFibGUsIExldmVsLCBSZWZlcmVuY2UsIE9kZHNSYXRpbywgTG93ZXIsIFVwcGVyLCBQVmFsdWUpCgogIAogIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCRWYXJpYWJsZSA8LSBmYWN0b3Iob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkJFZhcmlhYmxlLCBsZXZlbHMgPSB1bmlxdWUob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkJFZhcmlhYmxlKSkKICAKICAKICByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCA8LSBvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQgJT4lCiAgICBrYWJsZSgiaHRtbCIsIGNhcHRpb24gPSAiUmVzdHJ1Y3R1cmVkIE9kZHMgUmF0aW8gQW5hbHlzaXMgZm9yIE1lZGljYWwgSW50ZXJwcmV0YXRpb24iLAogICAgICAgICAgY29sLm5hbWVzID0gYygiVmFyaWFibGUiLCAiTGV2ZWwiLCAiUmVmZXJlbmNlIiwgIk9kZHMgUmF0aW8iLCAiTG93ZXIgOTUlIENJIiwgIlVwcGVyIDk1JSBDSSIsICJQLVZhbHVlIikpICU+JQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSwgZnVsbF93aWR0aCA9IEZBTFNFKSAlPiUKICAgIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBiYWNrZ3JvdW5kID0gIiMzMzMzMzMiLCBjb2xvciA9ICJ3aGl0ZSIpICU+JQogICAgcm93X3NwZWMoMTpucm93KG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCksIGJhY2tncm91bmQgPSByZXAoYygiI2Y5ZjlmOSIsICIjZmZmZmZmIiksIGxlbmd0aC5vdXQgPSBucm93KG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCkpKQoKICBwcmludChyZXN0cnVjdHVyZWRfdGFibGVfaHRtbCkKfSBlbHNlIHsKICBjYXQoIjxwPjxzdHJvbmc+V2FybmluZzo8L3N0cm9uZz4gTm8gZGF0YSBhdmFpbGFibGUgZm9yIHJlc3RydWN0dXJpbmcuIFNraXBwaW5nIHRoaXMgc2VjdGlvbi48L3A+PGJyPiIpCn0KCmBgYAoKCmBgYHtyfQoKaWYgKG5yb3cob2Rkc19yYXRpb3NfZGF0YSkgPiAwKSB7CiAgCiAgCiAgb2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkIDwtIG9kZHNfcmF0aW9zX2RhdGEgJT4lCiAgICBmaWx0ZXIoIWlzLm5hKE9kZHNSYXRpbykpICU+JSAKICAgIG11dGF0ZSgKICAgICAgUmVmZXJlbmNlID0gaWZlbHNlKExldmVsID09ICJObyIsICJZZXMiLCAiTm8iKSwgCiAgICAgIFNpZ25pZmljYW50ID0gaWZlbHNlKFBWYWx1ZSA8IDAuMDUsIFRSVUUsIEZBTFNFKSwgIAogICAgICBDSV85NSA9IGlmZWxzZSghaXMubmEoTG93ZXIpICYgIWlzLm5hKFVwcGVyKSwgcGFzdGUwKCIoIiwgcm91bmQoTG93ZXIsIDIpLCAiLCAiLCByb3VuZChVcHBlciwgMiksICIpIiksICJOQSIpIAogICAgKSAlPiUKICAgIHNlbGVjdChWYXJpYWJsZSwgTGV2ZWwsIFJlZmVyZW5jZSwgT2Rkc1JhdGlvLCBDSV85NSwgUFZhbHVlLCBTaWduaWZpY2FudCkgIAoKIAogIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZF9maWx0ZXJlZCA8LSBvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQgJT4lCiAgICBmaWx0ZXIoIShPZGRzUmF0aW8gPT0gMSAmIENJXzk1ID09ICJOQSIpKQoKIAogIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZF9maWx0ZXJlZCRWYXJpYWJsZSA8LSBmYWN0b3Iob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkX2ZpbHRlcmVkJFZhcmlhYmxlLCBsZXZlbHMgPSB1bmlxdWUob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkX2ZpbHRlcmVkJFZhcmlhYmxlKSkKICAKIAogIGlmIChucm93KG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZF9maWx0ZXJlZCkgPiAwKSB7CiAgICAKICAgIAogICAgb2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkX2ZpbHRlcmVkX2Zvcl90YWJsZSA8LSBvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWRfZmlsdGVyZWQgJT4lCiAgICAgIHNlbGVjdCgtU2lnbmlmaWNhbnQpCgogICAgCiAgICByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCA8LSBvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWRfZmlsdGVyZWRfZm9yX3RhYmxlICU+JQogICAgICBrYWJsZSgiaHRtbCIsIGNhcHRpb24gPSAiUmVzdHJ1Y3R1cmVkIE9kZHMgUmF0aW8gQW5hbHlzaXMgZm9yIE1lZGljYWwgSW50ZXJwcmV0YXRpb24iLAogICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJWYXJpYWJsZSIsICJMZXZlbCIsICJSZWZlcmVuY2UiLCAiT2RkcyBSYXRpbyIsICJDSSAoOTUlKSIsICJQLVZhbHVlIikpICU+JQogICAgICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLCBmdWxsX3dpZHRoID0gRkFMU0UpICU+JQogICAgICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjMzMzMzMzIiwgY29sb3IgPSAid2hpdGUiKQogICAgCiAgIAogICAgaWYgKGFueShvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWRfZmlsdGVyZWQkU2lnbmlmaWNhbnQgPT0gVFJVRSkpIHsKICAgICAgcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgPC0gcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgJT4lCiAgICAgICAgcm93X3NwZWMoCiAgICAgICAgICB3aGljaChvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWRfZmlsdGVyZWQkU2lnbmlmaWNhbnQgPT0gVFJVRSksIAogICAgICAgICAgYmFja2dyb3VuZCA9ICIjZmZjY2NjIiAgCiAgICAgICAgKQogICAgfQogICAgCiAgIAogICAgcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgPC0gcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgJT4lCiAgICAgIHJvd19zcGVjKDE6bnJvdyhvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWRfZmlsdGVyZWRfZm9yX3RhYmxlKSwgYmFja2dyb3VuZCA9IHJlcChjKCIjZjlmOWY5IiwgIiNmZmZmZmYiKSwgbGVuZ3RoLm91dCA9IG5yb3cob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkX2ZpbHRlcmVkX2Zvcl90YWJsZSkpKQoKICAgIAogICAgcHJpbnQocmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwpCiAgfSBlbHNlIHsKICAgIGNhdCgiPHA+PHN0cm9uZz5XYXJuaW5nOjwvc3Ryb25nPiBObyBkYXRhIGF2YWlsYWJsZSBmb3IgcmVzdHJ1Y3R1cmluZyBhZnRlciBmaWx0ZXJpbmcuIFNraXBwaW5nIHRoaXMgc2VjdGlvbi48L3A+PGJyPiIpCiAgfQogIAp9IGVsc2UgewogIGNhdCgiPHA+PHN0cm9uZz5XYXJuaW5nOjwvc3Ryb25nPiBObyBkYXRhIGF2YWlsYWJsZSBmb3IgcmVzdHJ1Y3R1cmluZy4gU2tpcHBpbmcgdGhpcyBzZWN0aW9uLjwvcD48YnI+IikKfQoKCmBgYApgYGB7cn0KCmlmIChucm93KG9kZHNfcmF0aW9zX2RhdGEpID4gMCkgewogIAogIAogIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCA8LSBvZGRzX3JhdGlvc19kYXRhICU+JQogICAgZmlsdGVyKCFpcy5uYShPZGRzUmF0aW8pKSAlPiUgIAogICAgbXV0YXRlKAogICAgICBSZWZlcmVuY2UgPSBpZmVsc2UoTGV2ZWwgPT0gIk5vIiwgIlllcyIsICJObyIpLCAKICAgICAgU2lnbmlmaWNhbnQgPSBpZmVsc2UoIWlzLm5hKFBWYWx1ZSkgJiBQVmFsdWUgPCAwLjA1LCBUUlVFLCBGQUxTRSksICAKICAgICAgQ0lfOTUgPSBpZmVsc2UoIWlzLm5hKExvd2VyKSAmICFpcy5uYShVcHBlciksIHBhc3RlMCgiKCIsIHJvdW5kKExvd2VyLCAyKSwgIiwgIiwgcm91bmQoVXBwZXIsIDIpLCAiKSIpLCAiTkEiKSAgCiAgICApICU+JQogICAgc2VsZWN0KFZhcmlhYmxlLCBMZXZlbCwgUmVmZXJlbmNlLCBPZGRzUmF0aW8sIENJXzk1LCBQVmFsdWUsIFNpZ25pZmljYW50KSAgCgogIAogIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCRWYXJpYWJsZSA8LSBmYWN0b3Iob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkJFZhcmlhYmxlLCBsZXZlbHMgPSB1bmlxdWUob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkJFZhcmlhYmxlKSkKICAKICBpZiAobnJvdyhvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQpID4gMCkgewogICAgCiAgICAKICAgIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZF9mb3JfdGFibGUgPC0gb2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkICU+JQogICAgICBzZWxlY3QoLVNpZ25pZmljYW50KQoKICAgIAogICAgcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgPC0gb2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkX2Zvcl90YWJsZSAlPiUKICAgICAga2FibGUoImh0bWwiLCBjYXB0aW9uID0gIlJlc3RydWN0dXJlZCBPZGRzIFJhdGlvIEFuYWx5c2lzIGZvciBNZWRpY2FsIEludGVycHJldGF0aW9uIChTaG93aW5nIEJvdGggTGV2ZWxzKSIsCiAgICAgICAgICAgIGNvbC5uYW1lcyA9IGMoIlZhcmlhYmxlIiwgIkxldmVsIiwgIlJlZmVyZW5jZSIsICJPZGRzIFJhdGlvIiwgIkNJICg5NSUpIiwgIlAtVmFsdWUiKSkgJT4lCiAgICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiksIGZ1bGxfd2lkdGggPSBGQUxTRSkgJT4lCiAgICAgIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBiYWNrZ3JvdW5kID0gIiMzMzMzMzMiLCBjb2xvciA9ICJ3aGl0ZSIpCiAgICAKICAgIAogICAgaWYgKGFueShvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQkU2lnbmlmaWNhbnQgPT0gVFJVRSwgbmEucm0gPSBUUlVFKSkgewogICAgICByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCA8LSByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCAlPiUKICAgICAgICByb3dfc3BlYygKICAgICAgICAgIHdoaWNoKG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCRTaWduaWZpY2FudCA9PSBUUlVFKSwgCiAgICAgICAgICBiYWNrZ3JvdW5kID0gIiNmZmNjY2MiIAogICAgICAgICkKICAgIH0KICAgIAogICAKICAgIHJlc3RydWN0dXJlZF90YWJsZV9odG1sIDwtIHJlc3RydWN0dXJlZF90YWJsZV9odG1sICU+JQogICAgICByb3dfc3BlYygxOm5yb3cob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkX2Zvcl90YWJsZSksIGJhY2tncm91bmQgPSByZXAoYygiI2Y5ZjlmOSIsICIjZmZmZmZmIiksIGxlbmd0aC5vdXQgPSBucm93KG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZF9mb3JfdGFibGUpKSkKCiAgIAogICAgcHJpbnQocmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwpCiAgfSBlbHNlIHsKICAgIGNhdCgiPHA+PHN0cm9uZz5XYXJuaW5nOjwvc3Ryb25nPiBObyBkYXRhIGF2YWlsYWJsZSBmb3IgcmVzdHJ1Y3R1cmluZyBhZnRlciBmaWx0ZXJpbmcuIFNraXBwaW5nIHRoaXMgc2VjdGlvbi48L3A+PGJyPiIpCiAgfQogIAp9IGVsc2UgewogIGNhdCgiPHA+PHN0cm9uZz5XYXJuaW5nOjwvc3Ryb25nPiBObyBkYXRhIGF2YWlsYWJsZSBmb3IgcmVzdHJ1Y3R1cmluZy4gU2tpcHBpbmcgdGhpcyBzZWN0aW9uLjwvcD48YnI+IikKfQoKYGBgCgoKYGBge3J9CgppZiAobnJvdyhvZGRzX3JhdGlvc19kYXRhKSA+IDApIHsKICAKICAKICBvZGRzX3JhdGlvc19yZXN0cnVjdHVyZWQgPC0gb2Rkc19yYXRpb3NfZGF0YSAlPiUKICAgIGZpbHRlcighaXMubmEoT2Rkc1JhdGlvKSkgJT4lIAogICAgbXV0YXRlKAogICAgICBSZWZlcmVuY2UgPSBpZmVsc2UoTGV2ZWwgPT0gIk5vIiwgIlllcyIsICJObyIpLCAgCiAgICAgIFNpZ25pZmljYW50ID0gaWZlbHNlKCFpcy5uYShQVmFsdWUpICYgUFZhbHVlIDwgMC4wNSwgVFJVRSwgRkFMU0UpLCAgCiAgICAgIENJXzk1ID0gaWZlbHNlKCFpcy5uYShMb3dlcikgJiAhaXMubmEoVXBwZXIpLCBwYXN0ZTAoIigiLCByb3VuZChMb3dlciwgMiksICIsICIsIHJvdW5kKFVwcGVyLCAyKSwgIikiKSwgIi0iKSwgIAogICAgICBQVmFsdWUgPSBpZmVsc2UoaXMubmEoUFZhbHVlKSwgIi0iLCBhcy5jaGFyYWN0ZXIocm91bmQoUFZhbHVlLCA0KSkpLCAgCiAgICAgIE9kZHNSYXRpbyA9IGlmZWxzZShpcy5uYShPZGRzUmF0aW8pLCAiLSIsIGFzLmNoYXJhY3Rlcihyb3VuZChPZGRzUmF0aW8sIDQpKSksICAKICAgICAgTm9uSW5qdXJ5ID0gaWZlbHNlKGlzLm5hKE5vbkluanVyeSksICItIiwgYXMuY2hhcmFjdGVyKE5vbkluanVyeSkpLCAKICAgICAgcDEgPSBpZmVsc2UoaXMubmEocDEpLCAiLSIsIHBhc3RlMChyb3VuZChhcy5udW1lcmljKHAxKSAqIDEwMCwgMiksICIlIikpICAKICAgICkgJT4lCiAgICBzZWxlY3QoVmFyaWFibGUsIExldmVsLCBSZWZlcmVuY2UsIE5vbkluanVyeSwgcDEsIE9kZHNSYXRpbywgQ0lfOTUsIFBWYWx1ZSwgU2lnbmlmaWNhbnQpCgogIAogIG9kZHNfcmF0aW9zX2dyb3VwZWQgPC0gb2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkICU+JQogICAgYXJyYW5nZShWYXJpYWJsZSkgJT4lCiAgICBncm91cF9ieShWYXJpYWJsZSkgJT4lCiAgICBtdXRhdGUoCiAgICAgIExldmVsX0dyb3VwZWQgPSBwYXN0ZShMZXZlbCwgY29sbGFwc2UgPSAiIC8gIiksICAKICAgICAgT2Rkc1JhdGlvX0dyb3VwZWQgPSBwYXN0ZShPZGRzUmF0aW8sIGNvbGxhcHNlID0gIiAvICIpLAogICAgICBDSV85NV9Hcm91cGVkID0gcGFzdGUoQ0lfOTUsIGNvbGxhcHNlID0gIiAvICIpLAogICAgICBQVmFsdWVfR3JvdXBlZCA9IHBhc3RlKFBWYWx1ZSwgY29sbGFwc2UgPSAiIC8gIiksCiAgICAgIE5vbkluanVyeV9Hcm91cGVkID0gcGFzdGUoTm9uSW5qdXJ5LCBjb2xsYXBzZSA9ICIgLyAiKSwKICAgICAgcDFfR3JvdXBlZCA9IHBhc3RlKHAxLCBjb2xsYXBzZSA9ICIgLyAiKQogICAgKSAlPiUKICAgIHNsaWNlKDEpICU+JSAgCiAgICB1bmdyb3VwKCkgJT4lCiAgICBzZWxlY3QoVmFyaWFibGUsIExldmVsX0dyb3VwZWQsIFJlZmVyZW5jZSwgTm9uSW5qdXJ5X0dyb3VwZWQsIHAxX0dyb3VwZWQsIE9kZHNSYXRpb19Hcm91cGVkLCBDSV85NV9Hcm91cGVkLCBQVmFsdWVfR3JvdXBlZCwgU2lnbmlmaWNhbnQpCgogCiAgb2Rkc19yYXRpb3NfZ3JvdXBlZCRWYXJpYWJsZSA8LSBmYWN0b3Iob2Rkc19yYXRpb3NfZ3JvdXBlZCRWYXJpYWJsZSwgbGV2ZWxzID0gdW5pcXVlKG9kZHNfcmF0aW9zX2dyb3VwZWQkVmFyaWFibGUpKQogIAogCiAgaWYgKG5yb3cob2Rkc19yYXRpb3NfZ3JvdXBlZCkgPiAwKSB7CiAgICAKICAKICAgIG9kZHNfcmF0aW9zX2Zvcl90YWJsZSA8LSBvZGRzX3JhdGlvc19ncm91cGVkICU+JQogICAgICBzZWxlY3QoLVNpZ25pZmljYW50KQoKICAKICAgIHJlc3RydWN0dXJlZF90YWJsZV9odG1sIDwtIG9kZHNfcmF0aW9zX2Zvcl90YWJsZSAlPiUKICAgICAga2FibGUoImh0bWwiLCBjYXB0aW9uID0gIlJlc3RydWN0dXJlZCBPZGRzIFJhdGlvIEFuYWx5c2lzIGZvciBNZWRpY2FsIEludGVycHJldGF0aW9uIChHcm91cGVkIExldmVscykiLAogICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJWYXJpYWJsZSIsICJMZXZlbCAoWWVzIC8gTm8pIiwgIlJlZmVyZW5jZSIsICJOb24tSW5qdXJ5IChDb3VudCkiLCAiTm9uLUluanVyeSAoJSkiLCAiT2RkcyBSYXRpbyAoWWVzIC8gTm8pIiwgIkNJICg5NSUpIChZZXMgLyBObykiLCAiUC1WYWx1ZSAoWWVzIC8gTm8pIikpICU+JQogICAgICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpLCBmdWxsX3dpZHRoID0gRkFMU0UsIHBvc2l0aW9uID0gImNlbnRlciIpICU+JQogICAgICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjMzMzMzMzIiwgY29sb3IgPSAid2hpdGUiKSAlPiUKICAgICAgY29sdW1uX3NwZWMoMTo4LCB3aWR0aCA9ICI1ZW0iLCBib3JkZXJfbGVmdCA9IFRSVUUsIGJvcmRlcl9yaWdodCA9IFRSVUUpICAKCiAgICAKICAgIGlmIChhbnkob2Rkc19yYXRpb3NfZ3JvdXBlZCRTaWduaWZpY2FudCA9PSBUUlVFLCBuYS5ybSA9IFRSVUUpKSB7CiAgICAgIHJlc3RydWN0dXJlZF90YWJsZV9odG1sIDwtIHJlc3RydWN0dXJlZF90YWJsZV9odG1sICU+JQogICAgICAgIHJvd19zcGVjKAogICAgICAgICAgd2hpY2gob2Rkc19yYXRpb3NfZ3JvdXBlZCRTaWduaWZpY2FudCA9PSBUUlVFKSwgCiAgICAgICAgICBiYWNrZ3JvdW5kID0gIiNmZmNjY2MiICAKICAgICAgICApCiAgICB9CiAgICAgIAogICAgcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgPC0gcmVzdHJ1Y3R1cmVkX3RhYmxlX2h0bWwgJT4lCiAgICAgIHJvd19zcGVjKDE6bnJvdyhvZGRzX3JhdGlvc19mb3JfdGFibGUpLCBiYWNrZ3JvdW5kID0gcmVwKGMoIiNmOWY5ZjkiLCAiI2ZmZmZmZiIpLCBsZW5ndGgub3V0ID0gbnJvdyhvZGRzX3JhdGlvc19mb3JfdGFibGUpKSkKCiAgICAKICAgIHByaW50KHJlc3RydWN0dXJlZF90YWJsZV9odG1sKQogIH0gZWxzZSB7CiAgICBjYXQoIjxwPjxzdHJvbmc+V2FybmluZzo8L3N0cm9uZz4gTm8gZGF0YSBhdmFpbGFibGUgZm9yIHJlc3RydWN0dXJpbmcgYWZ0ZXIgZmlsdGVyaW5nLiBTa2lwcGluZyB0aGlzIHNlY3Rpb24uPC9wPjxicj4iKQogIH0KICAKfSBlbHNlIHsKICBjYXQoIjxwPjxzdHJvbmc+V2FybmluZzo8L3N0cm9uZz4gTm8gZGF0YSBhdmFpbGFibGUgZm9yIHJlc3RydWN0dXJpbmcuIFNraXBwaW5nIHRoaXMgc2VjdGlvbi48L3A+PGJyPiIpCn0KCmBgYAoKYGBge3J9CgppZiAobnJvdyhvZGRzX3JhdGlvc19kYXRhKSA+IDApIHsKICAKIAogIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCA8LSBvZGRzX3JhdGlvc19kYXRhICU+JQogICAgZmlsdGVyKCFpcy5uYShPZGRzUmF0aW8pKSAlPiUgIAogICAgbXV0YXRlKAogICAgICBSZWZlcmVuY2UgPSBpZmVsc2UoTGV2ZWwgPT0gIk5vIiwgIlllcyIsICJObyIpLCAgCiAgICAgIFNpZ25pZmljYW50ID0gaWZlbHNlKCFpcy5uYShQVmFsdWUpICYgUFZhbHVlIDwgMC4wNSwgVFJVRSwgRkFMU0UpLCAgCiAgICAgIENJXzk1ID0gaWZlbHNlKCFpcy5uYShMb3dlcikgJiAhaXMubmEoVXBwZXIpLCBwYXN0ZTAoIigiLCByb3VuZChMb3dlciwgMiksICIsICIsIHJvdW5kKFVwcGVyLCAyKSwgIikiKSwgIi0iKSwgIAogICAgICBQVmFsdWUgPSBpZmVsc2UoaXMubmEoUFZhbHVlKSwgIi0iLCBhcy5jaGFyYWN0ZXIocm91bmQoUFZhbHVlLCA0KSkpLCAKICAgICAgT2Rkc1JhdGlvID0gaWZlbHNlKGlzLm5hKE9kZHNSYXRpbyksICItIiwgYXMuY2hhcmFjdGVyKHJvdW5kKE9kZHNSYXRpbywgNCkpKSwgIAogICAgICBOb25Jbmp1cnkgPSBpZmVsc2UoaXMubmEoTm9uSW5qdXJ5KSwgIi0iLCBhcy5jaGFyYWN0ZXIoTm9uSW5qdXJ5KSksICAKICAgICAgcDEgPSBpZmVsc2UoaXMubmEocDEpLCAiLSIsIHBhc3RlMChyb3VuZChhcy5udW1lcmljKHAxKSAqIDEwMCwgMiksICIlIikpICAKICAgICkgJT4lCiAgICBzZWxlY3QoVmFyaWFibGUsIExldmVsLCBSZWZlcmVuY2UsIE5vbkluanVyeSwgcDEsIE9kZHNSYXRpbywgQ0lfOTUsIFBWYWx1ZSwgU2lnbmlmaWNhbnQpCgogIAogIG9kZHNfcmF0aW9zX2NsZWFuIDwtIG9kZHNfcmF0aW9zX3Jlc3RydWN0dXJlZCAlPiUKICAgIGFycmFuZ2UoVmFyaWFibGUsIExldmVsKSAlPiUKICAgIHNlbGVjdChWYXJpYWJsZSwgTGV2ZWwsIFJlZmVyZW5jZSwgTm9uSW5qdXJ5LCBwMSwgT2Rkc1JhdGlvLCBDSV85NSwgUFZhbHVlKQoKCiAgaWYgKG5yb3cob2Rkc19yYXRpb3NfY2xlYW4pID4gMCkgewoKICAgIHJlc3RydWN0dXJlZF90YWJsZV9odG1sIDwtIG9kZHNfcmF0aW9zX2NsZWFuICU+JQogICAgICBrYWJsZSgiaHRtbCIsIGNhcHRpb24gPSAiUmVzdHJ1Y3R1cmVkIE9kZHMgUmF0aW8gQW5hbHlzaXMgZm9yIE1lZGljYWwgSW50ZXJwcmV0YXRpb24gKFNlcGFyYXRlZCBZZXMgYW5kIE5vIExldmVscykiLAogICAgICAgICAgICBjb2wubmFtZXMgPSBjKCJWYXJpYWJsZSIsICJMZXZlbCIsICJSZWZlcmVuY2UiLCAiTm9uLUluanVyeSBDb3VudCIsICJOb24tSW5qdXJ5ICglKSIsICJPZGRzIFJhdGlvIiwgIkNJICg5NSUpIiwgIlAtVmFsdWUiKSkgJT4lCiAgICAgIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIiksIGZ1bGxfd2lkdGggPSBGQUxTRSwgcG9zaXRpb24gPSAiY2VudGVyIikgJT4lCiAgICAgIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBiYWNrZ3JvdW5kID0gIiMzMzMzMzMiLCBjb2xvciA9ICJ3aGl0ZSIpICU+JQogICAgICBjb2x1bW5fc3BlYygxOjgsIHdpZHRoID0gIjVlbSIsIGJvcmRlcl9sZWZ0ID0gVFJVRSwgYm9yZGVyX3JpZ2h0ID0gVFJVRSkgICMKICAgIHNpZ25pZmljYW50X3Jvd3MgPC0gd2hpY2gob2Rkc19yYXRpb3NfcmVzdHJ1Y3R1cmVkJFNpZ25pZmljYW50ID09IFRSVUUpCiAgICBpZiAobGVuZ3RoKHNpZ25pZmljYW50X3Jvd3MpID4gMCkgewogICAgICByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCA8LSByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCAlPiUKICAgICAgICByb3dfc3BlYyhzaWduaWZpY2FudF9yb3dzLCBiYWNrZ3JvdW5kID0gIiNmZmNjY2MiKSAKICAgIH0KCiAgCiAgICByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCA8LSByZXN0cnVjdHVyZWRfdGFibGVfaHRtbCAlPiUKICAgICAgcm93X3NwZWMoMTpucm93KG9kZHNfcmF0aW9zX2NsZWFuKSwgYmFja2dyb3VuZCA9IHJlcChjKCIjZjlmOWY5IiwgIiNmZmZmZmYiKSwgbGVuZ3RoLm91dCA9IG5yb3cob2Rkc19yYXRpb3NfY2xlYW4pKSkKCiAgCiAgICBwcmludChyZXN0cnVjdHVyZWRfdGFibGVfaHRtbCkKICB9IGVsc2UgewogICAgY2F0KCI8cD48c3Ryb25nPldhcm5pbmc6PC9zdHJvbmc+IE5vIGRhdGEgYXZhaWxhYmxlIGZvciByZXN0cnVjdHVyaW5nIGFmdGVyIGZpbHRlcmluZy4gU2tpcHBpbmcgdGhpcyBzZWN0aW9uLjwvcD48YnI+IikKICB9CiAgCn0gZWxzZSB7CiAgY2F0KCI8cD48c3Ryb25nPldhcm5pbmc6PC9zdHJvbmc+IE5vIGRhdGEgYXZhaWxhYmxlIGZvciByZXN0cnVjdHVyaW5nLiBTa2lwcGluZyB0aGlzIHNlY3Rpb24uPC9wPjxicj4iKQp9CgpgYGAKCgoKCgojIyMjIyMgQ3ljbGlzdCBJbnRlcnNlY3Rpb24KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmN5Y2xpc3RfaW50ZXJzZWN0aW9uX2RhdGEgPC0gZGF0YSAlPiUKICBmaWx0ZXIobW9kZSA9PSAiQ3ljbGlzdCIsIGludGVyc2VjdGlvbiA9PSAiWWVzIikKCmlmIChucm93KGN5Y2xpc3RfaW50ZXJzZWN0aW9uX2RhdGEpID4gMCkgewogIGN5Y2xpc3RfaW50ZXJzZWN0aW9uX3ZhcnMgPC0gYygic2lnbmFsaXplZCIsICJzdG9wc2lnbnMiLCAicm91bmRhYm91dCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGhyZWVsZWdzIiwgImZvdXJsZWdzIiwgImZvdXJtbGVncyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGVkaWNhdGVkc2lnbmFsZm9yY3ljbGlzdHMiLCAiYmlrZWJveGVzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0d29zdGFnZXR1cm5ib3giLCAicHJvdGVjdGVkb3JkZWRpY2F0ZWRpbnRlcnNlY3Rpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm1lZGlhbmlzbGFuZGRpdmVydGVyIiwgImNvbWJpbmVkYmlrZWxhbmV0dXJubGFuZSIsICJ0aHJvdWdoYmlrZWxhbmUiKQoKICBvZGRzX3JhdGlvc19saXN0IDwtIGxpc3QoKQogIHN0YW5kYXJkX2NvbHVtbnMgPC0gYygiVmFyaWFibGUiLCAiTGV2ZWwiLCAiSW5qdXJ5IiwgInAwIiwgIk5vbi1Jbmp1cnkiLCAicDEiLCAiT2Rkc1JhdGlvIiwgIkxvd2VyIiwgIlVwcGVyIiwgIlBWYWx1ZSIpCgogIGZvciAodmFyIGluIGN5Y2xpc3RfaW50ZXJzZWN0aW9uX3ZhcnMpIHsKICAgIGlmICh2YXIgJWluJSBuYW1lcyhjeWNsaXN0X2ludGVyc2VjdGlvbl9kYXRhKSkgewogICAgICBvZGRzX3JhdGlvX3Jlc3VsdCA8LSB0cnlDYXRjaCh7CiAgICAgICAgaWYgKG5fZGlzdGluY3QoY3ljbGlzdF9pbnRlcnNlY3Rpb25fZGF0YVtbdmFyXV0pID09IDIpIHsKICAgICAgICAgIG9kZHNfZGF0YSA8LSBjeWNsaXN0X2ludGVyc2VjdGlvbl9kYXRhICU+JQogICAgICAgICAgICBzZWxlY3QoYWxsX29mKHZhciksIGNyYXNoc2V2ZXJpdHkpICU+JQogICAgICAgICAgICB0YWJsZSgpICU+JQogICAgICAgICAgICBhcy5tYXRyaXgoKQogICAgICAgICAgCiAgICAgICAgICBvZGRzX3JhdGlvX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoZXBpdGFiKG9kZHNfZGF0YSwgbWV0aG9kID0gIm9kZHNyYXRpbyIpJHRhYikgJT4lCiAgICAgICAgICAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCA0KSkKICAgICAgICAgIAogICAgICAgICAgb2Rkc19yYXRpb190YWJsZSA8LSBjYmluZChWYXJpYWJsZSA9IHZhciwgTGV2ZWwgPSByb3duYW1lcyhvZGRzX3JhdGlvX3RhYmxlKSwgb2Rkc19yYXRpb190YWJsZSkKICAgICAgICAgIG5hbWVzKG9kZHNfcmF0aW9fdGFibGUpIDwtIHN0YW5kYXJkX2NvbHVtbnMKICAgICAgICAgIG9kZHNfcmF0aW9fdGFibGUKICAgICAgICB9IGVsc2UgewogICAgICAgICAgZGF0YS5mcmFtZSgKICAgICAgICAgICAgVmFyaWFibGUgPSB2YXIsIExldmVsID0gTkEsIEluanVyeSA9ICJOb3QgYXBwbGljYWJsZSIsIAogICAgICAgICAgICBwMCA9IE5BLCBOb25Jbmp1cnkgPSBOQSwgcDEgPSBOQSwgT2Rkc1JhdGlvID0gTkEsIAogICAgICAgICAgICBMb3dlciA9IE5BLCBVcHBlciA9IE5BLCBQVmFsdWUgPSBOQSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgICAgICAgICApCiAgICAgICAgfQogICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAgICAgICBkYXRhLmZyYW1lKAogICAgICAgICAgVmFyaWFibGUgPSB2YXIsIExldmVsID0gTkEsIEluanVyeSA9ICJOb3QgYXBwbGljYWJsZSIsIAogICAgICAgICAgcDAgPSBOQSwgTm9uSW5qdXJ5ID0gTkEsIHAxID0gTkEsIE9kZHNSYXRpbyA9IE5BLCAKICAgICAgICAgIExvd2VyID0gTkEsIFVwcGVyID0gTkEsIFBWYWx1ZSA9IE5BLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICAgICAgICApCiAgICAgIH0pCiAgICAgIAogICAgICBvZGRzX3JhdGlvc19saXN0W1t2YXJdXSA8LSBvZGRzX3JhdGlvX3Jlc3VsdAogICAgfQogIH0KICAKICBvZGRzX3JhdGlvc19kYXRhIDwtIGRvLmNhbGwocmJpbmQsIG9kZHNfcmF0aW9zX2xpc3QpCiAgcm93X2NvbG9ycyA8LSByZXAoYygiI2Y5ZjlmOSIsICIjZmZmZmZmIiksIGxlbmd0aC5vdXQgPSBucm93KG9kZHNfcmF0aW9zX2RhdGEpKQogIG9kZHNfcmF0aW9zX2RhdGEkVmFyaWFibGUgPC0gaWZlbHNlKGR1cGxpY2F0ZWQob2Rkc19yYXRpb3NfZGF0YSRWYXJpYWJsZSksICIiLCBvZGRzX3JhdGlvc19kYXRhJFZhcmlhYmxlKQoKICBmaW5hbF90YWJsZV9odG1sIDwtIGh0bWxUYWJsZSgKICAgIG9kZHNfcmF0aW9zX2RhdGEsCiAgICBoZWFkZXIgPSBjKCJWYXJpYWJsZSIsICJMZXZlbCIsICJJbmp1cnkiLCAicDAiLCAiTm9uLUluanVyeSIsICJwMSIsICJPZGRzUmF0aW8iLCAiTG93ZXIiLCAiVXBwZXIiLCAiUC1WYWx1ZSIpLAogICAgYWxpZ24gPSAnbGNjY2NjY2NjYycsCiAgICBybmFtZXMgPSBGQUxTRSwKICAgIGNzcy5jZWxsID0gInRleHQtYWxpZ246IGNlbnRlcjsgcGFkZGluZzogMTJweCAxNXB4OyBmb250LXNpemU6IDEycHg7IHdoaXRlLXNwYWNlOiBub3dyYXA7IiwKICAgIGNzcy5yb3cgPSBzcHJpbnRmKCJiYWNrZ3JvdW5kLWNvbG9yOiAlczsiLCByb3dfY29sb3JzKSwKICAgIGhlYWRlci5jc3MgPSAiYmFja2dyb3VuZC1jb2xvcjogIzAwMzM2NjsgZm9udC1zaXplOiAxNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGNvbG9yOiB3aGl0ZTsiLAogICAgY2FwdGlvbiA9ICI8aDMgc3R5bGU9J3RleHQtYWxpZ246IGNlbnRlcjsnPkFuYWx5c2lzIGZvciBDeWNsaXN0IEludGVyc2VjdGlvbjwvaDM+CiAgICAgICAgICAgICAgIDxwIHN0eWxlPSd0ZXh0LWFsaWduOiBjZW50ZXI7Jz48ZW0+VGhpcyBhbmFseXNpcyBmb2N1c2VzIG9uIG1vZGU6IGN5Y2xpc3QgfCBpbnRlcnNlY3Rpb246IHllczwvZW0+PC9wPiIKICApCgogIHByaW50KEhUTUwoZmluYWxfdGFibGVfaHRtbCkpCn0gZWxzZSB7CiAgY2F0KCI8cD48c3Ryb25nPldhcm5pbmc6PC9zdHJvbmc+IE5vIGRhdGEgYXZhaWxhYmxlIGZvciBDeWNsaXN0IEludGVyc2VjdGlvbi4gU2tpcHBpbmcgYW5hbHlzaXMgZm9yIHRoaXMgZ3JvdXAuPC9wPjxicj4iKQp9CmBgYAoKIyMjIyMjIHBlZGVzdHJpYW5fbWlkYmxvY2tfZGF0YQoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwZWRlc3RyaWFuX21pZGJsb2NrX2RhdGEgPC0gZGF0YSAlPiUKICBmaWx0ZXIobW9kZSA9PSAiUGVkZXN0cmlhbiIsIGludGVyc2VjdGlvbiA9PSAiTm8iKQoKaWYgKG5yb3cocGVkZXN0cmlhbl9taWRibG9ja19kYXRhKSA+IDApIHsKICBwZWRlc3RyaWFuX21pZGJsb2NrX3ZhcnMgPC0gYygib25lbGFuZSIsICJ0d29sYW5lcyIsICJ0aHJlZWxhbmVzIiwgImZvdXJsYW5lcyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmaXZlbGFuZXMiLCAic2l4bGFuZXMiLCAib25ld2F5IiwgInR3b3dheXMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY2xlYXJ6b25lIiwgIm9uc3RyZWV0cGFya2luZyIsICJhY2Nlc3NpYmxlc2hvdWxkZXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2lkZXdhbGtzIiwgInNwZWVkaHVtcCIsICJzdGFuZGFyZHBhaW50IiwgInNvbGlkcGFpbnQiLCAic3RyaXBlZCIpCgogIG9kZHNfcmF0aW9zX2xpc3QgPC0gbGlzdCgpCiAgc3RhbmRhcmRfY29sdW1ucyA8LSBjKCJWYXJpYWJsZSIsICJMZXZlbCIsICJJbmp1cnkiLCAicDAiLCAiTm9uLUluanVyeSIsICJwMSIsICJPZGRzUmF0aW8iLCAiTG93ZXIiLCAiVXBwZXIiLCAiUFZhbHVlIikKCiAgZm9yICh2YXIgaW4gcGVkZXN0cmlhbl9taWRibG9ja192YXJzKSB7CiAgICBpZiAodmFyICVpbiUgbmFtZXMocGVkZXN0cmlhbl9taWRibG9ja19kYXRhKSkgewogICAgICBvZGRzX3JhdGlvX3Jlc3VsdCA8LSB0cnlDYXRjaCh7CiAgICAgICAgaWYgKG5fZGlzdGluY3QocGVkZXN0cmlhbl9taWRibG9ja19kYXRhW1t2YXJdXSkgPT0gMikgewogICAgICAgICAgb2Rkc19kYXRhIDwtIHBlZGVzdHJpYW5fbWlkYmxvY2tfZGF0YSAlPiUKICAgICAgICAgICAgc2VsZWN0KGFsbF9vZih2YXIpLCBjcmFzaHNldmVyaXR5KSAlPiUKICAgICAgICAgICAgdGFibGUoKSAlPiUKICAgICAgICAgICAgYXMubWF0cml4KCkKICAgICAgICAgIAogICAgICAgICAgb2Rkc19yYXRpb190YWJsZSA8LSBhcy5kYXRhLmZyYW1lKGVwaXRhYihvZGRzX2RhdGEsIG1ldGhvZCA9ICJvZGRzcmF0aW8iKSR0YWIpICU+JQogICAgICAgICAgICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCByb3VuZCwgNCkpCiAgICAgICAgICAKICAgICAgICAgIG9kZHNfcmF0aW9fdGFibGUgPC0gY2JpbmQoVmFyaWFibGUgPSB2YXIsIExldmVsID0gcm93bmFtZXMob2Rkc19yYXRpb190YWJsZSksIG9kZHNfcmF0aW9fdGFibGUpCiAgICAgICAgICBuYW1lcyhvZGRzX3JhdGlvX3RhYmxlKSA8LSBzdGFuZGFyZF9jb2x1bW5zCiAgICAgICAgICBvZGRzX3JhdGlvX3RhYmxlCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgICAgIFZhcmlhYmxlID0gdmFyLCBMZXZlbCA9IE5BLCBJbmp1cnkgPSAiTm90IGFwcGxpY2FibGUiLCAKICAgICAgICAgICAgcDAgPSBOQSwgTm9uSW5qdXJ5ID0gTkEsIHAxID0gTkEsIE9kZHNSYXRpbyA9IE5BLCAKICAgICAgICAgICAgTG93ZXIgPSBOQSwgVXBwZXIgPSBOQSwgUFZhbHVlID0gTkEsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQogICAgICAgICAgKQogICAgICAgIH0KICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiAgICAgICAgZGF0YS5mcmFtZSgKICAgICAgICAgIFZhcmlhYmxlID0gdmFyLCBMZXZlbCA9IE5BLCBJbmp1cnkgPSAiTm90IGFwcGxpY2FibGUiLCAKICAgICAgICAgIHAwID0gTkEsIE5vbkluanVyeSA9IE5BLCBwMSA9IE5BLCBPZGRzUmF0aW8gPSBOQSwgCiAgICAgICAgICBMb3dlciA9IE5BLCBVcHBlciA9IE5BLCBQVmFsdWUgPSBOQSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgICAgICAgKQogICAgICB9KQogICAgICAKICAgICAgb2Rkc19yYXRpb3NfbGlzdFtbdmFyXV0gPC0gb2Rkc19yYXRpb19yZXN1bHQKICAgIH0KICB9CiAgCiAgb2Rkc19yYXRpb3NfZGF0YSA8LSBkby5jYWxsKHJiaW5kLCBvZGRzX3JhdGlvc19saXN0KQogIHJvd19jb2xvcnMgPC0gcmVwKGMoIiNmOWY5ZjkiLCAiI2ZmZmZmZiIpLCBsZW5ndGgub3V0ID0gbnJvdyhvZGRzX3JhdGlvc19kYXRhKSkKICBvZGRzX3JhdGlvc19kYXRhJFZhcmlhYmxlIDwtIGlmZWxzZShkdXBsaWNhdGVkKG9kZHNfcmF0aW9zX2RhdGEkVmFyaWFibGUpLCAiIiwgb2Rkc19yYXRpb3NfZGF0YSRWYXJpYWJsZSkKCiAgZmluYWxfdGFibGVfaHRtbCA8LSBodG1sVGFibGUoCiAgICBvZGRzX3JhdGlvc19kYXRhLAogICAgaGVhZGVyID0gYygiVmFyaWFibGUiLCAiTGV2ZWwiLCAiSW5qdXJ5IiwgInAwIiwgIk5vbi1Jbmp1cnkiLCAicDEiLCAiT2Rkc1JhdGlvIiwgIkxvd2VyIiwgIlVwcGVyIiwgIlAtVmFsdWUiKSwKICAgIGFsaWduID0gJ2xjY2NjY2NjY2MnLAogICAgcm5hbWVzID0gRkFMU0UsCiAgICBjc3MuY2VsbCA9ICJ0ZXh0LWFsaWduOiBjZW50ZXI7IHBhZGRpbmc6IDEycHggMTVweDsgZm9udC1zaXplOiAxMnB4OyB3aGl0ZS1zcGFjZTogbm93cmFwOyIsCiAgICBjc3Mucm93ID0gc3ByaW50ZigiYmFja2dyb3VuZC1jb2xvcjogJXM7Iiwgcm93X2NvbG9ycyksCiAgICBoZWFkZXIuY3NzID0gImJhY2tncm91bmQtY29sb3I6ICMwMDMzNjY7IGZvbnQtc2l6ZTogMTRweDsgdGV4dC1hbGlnbjogY2VudGVyOyBjb2xvcjogd2hpdGU7IiwKICAgIGNhcHRpb24gPSAiPGgzIHN0eWxlPSd0ZXh0LWFsaWduOiBjZW50ZXI7Jz5BbmFseXNpcyBmb3IgUGVkZXN0cmlhbiBNaWRCbG9jazwvaDM+CiAgICAgICAgICAgICAgIDxwIHN0eWxlPSd0ZXh0LWFsaWduOiBjZW50ZXI7Jz48ZW0+VGhpcyBhbmFseXNpcyBmb2N1c2VzIG9uIG1vZGU6IHBlZGVzdHJpYW4gfCBpbnRlcnNlY3Rpb246IG5vPC9lbT48L3A+IgogICkKCiAgcHJpbnQoSFRNTChmaW5hbF90YWJsZV9odG1sKSkKfSBlbHNlIHsKICBjYXQoIjxwPjxzdHJvbmc+V2FybmluZzo8L3N0cm9uZz4gTm8gZGF0YSBhdmFpbGFibGUgZm9yIFBlZGVzdHJpYW4gTWlkQmxvY2suIFNraXBwaW5nIGFuYWx5c2lzIGZvciB0aGlzIGdyb3VwLjwvcD48YnI+IikKfQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMjIyMjIFBlZGVzdHJpYW4gSW50ZXJzZWN0aW9uCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcGVkZXN0cmlhbl9pbnRlcnNlY3Rpb25fZGF0YSA8LSBkYXRhICU+JQogIGZpbHRlcihtb2RlID09ICJQZWRlc3RyaWFuIiwgaW50ZXJzZWN0aW9uID09ICJZZXMiKQoKaWYgKG5yb3cocGVkZXN0cmlhbl9pbnRlcnNlY3Rpb25fZGF0YSkgPiAwKSB7CiAgcGVkZXN0cmlhbl9pbnRlcnNlY3Rpb25fdmFycyA8LSBjKCJzaWduYWxpemVkIiwgInN0b3BzaWducyIsICJyb3VuZGFib3V0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aHJlZWxlZ3MiLCAiZm91cmxlZ3MiLCAiZm91cm1sZWdzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ1bnNpZ25hbGl6ZWRjcm9zc3dhbGsiLCAic2lnbmFsaXplZGNyb3Nzd2Fsa3N0cmVldCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic3RhbmRhcmRwYWludCIsICJzb2xpZHBhaW50IiwgInN0cmlwZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBlZGVzdHJpYW5yZWZ1Z2VzdHJpcGVkIiwgInJhcGlkcmVjdGFuZ3VsYXJmbGFzaGluZ2JlYWNvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVkZXN0cmlhbmNyb3NzZWRzaWduYWwiKQoKICBvZGRzX3JhdGlvc19saXN0IDwtIGxpc3QoKQogIHN0YW5kYXJkX2NvbHVtbnMgPC0gYygiVmFyaWFibGUiLCAiTGV2ZWwiLCAiSW5qdXJ5IiwgInAwIiwgIk5vbi1Jbmp1cnkiLCAicDEiLCAiT2Rkc1JhdGlvIiwgIkxvd2VyIiwgIlVwcGVyIiwgIlBWYWx1ZSIpCgogIGZvciAodmFyIGluIHBlZGVzdHJpYW5faW50ZXJzZWN0aW9uX3ZhcnMpIHsKICAgIGlmICh2YXIgJWluJSBuYW1lcyhwZWRlc3RyaWFuX2ludGVyc2VjdGlvbl9kYXRhKSkgewogICAgICBvZGRzX3JhdGlvX3Jlc3VsdCA8LSB0cnlDYXRjaCh7CiAgICAgICAgaWYgKG5fZGlzdGluY3QocGVkZXN0cmlhbl9pbnRlcnNlY3Rpb25fZGF0YVtbdmFyXV0pID09IDIpIHsKICAgICAgICAgIG9kZHNfZGF0YSA8LSBwZWRlc3RyaWFuX2ludGVyc2VjdGlvbl9kYXRhICU+JQogICAgICAgICAgICBzZWxlY3QoYWxsX29mKHZhciksIGNyYXNoc2V2ZXJpdHkpICU+JQogICAgICAgICAgICB0YWJsZSgpICU+JQogICAgICAgICAgICBhcy5tYXRyaXgoKQogICAgICAgICAgCiAgICAgICAgICBvZGRzX3JhdGlvX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoZXBpdGFiKG9kZHNfZGF0YSwgbWV0aG9kID0gIm9kZHNyYXRpbyIpJHRhYikgJT4lCiAgICAgICAgICAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIHJvdW5kLCA0KSkKICAgICAgICAgIAogICAgICAgICAgb2Rkc19yYXRpb190YWJsZSA8LSBjYmluZChWYXJpYWJsZSA9IHZhciwgTGV2ZWwgPSByb3duYW1lcyhvZGRzX3JhdGlvX3RhYmxlKSwgb2Rkc19yYXRpb190YWJsZSkKICAgICAgICAgIG5hbWVzKG9kZHNfcmF0aW9fdGFibGUpIDwtIHN0YW5kYXJkX2NvbHVtbnMKICAgICAgICAgIG9kZHNfcmF0aW9fdGFibGUKICAgICAgICB9IGVsc2UgewogICAgICAgICAgZGF0YS5mcmFtZSgKICAgICAgICAgICAgVmFyaWFibGUgPSB2YXIsIExldmVsID0gTkEsIEluanVyeSA9ICJOb3QgYXBwbGljYWJsZSIsIAogICAgICAgICAgICBwMCA9IE5BLCBOb25Jbmp1cnkgPSBOQSwgcDEgPSBOQSwgT2Rkc1JhdGlvID0gTkEsIAogICAgICAgICAgICBMb3dlciA9IE5BLCBVcHBlciA9IE5BLCBQVmFsdWUgPSBOQSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCiAgICAgICAgICApCiAgICAgICAgfQogICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAgICAgICBkYXRhLmZyYW1lKAogICAgICAgICAgVmFyaWFibGUgPSB2YXIsIExldmVsID0gTkEsIEluanVyeSA9ICJOb3QgYXBwbGljYWJsZSIsIAogICAgICAgICAgcDAgPSBOQSwgTm9uSW5qdXJ5ID0gTkEsIHAxID0gTkEsIE9kZHNSYXRpbyA9IE5BLCAKICAgICAgICAgIExvd2VyID0gTkEsIFVwcGVyID0gTkEsIFBWYWx1ZSA9IE5BLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICAgICAgICApCiAgICAgIH0pCiAgICAgIAogICAgICBvZGRzX3JhdGlvc19saXN0W1t2YXJdXSA8LSBvZGRzX3JhdGlvX3Jlc3VsdAogICAgfQogIH0KICAKICBvZGRzX3JhdGlvc19kYXRhIDwtIGRvLmNhbGwocmJpbmQsIG9kZHNfcmF0aW9zX2xpc3QpCiAgcm93X2NvbG9ycyA8LSByZXAoYygiI2Y5ZjlmOSIsICIjZmZmZmZmIiksIGxlbmd0aC5vdXQgPSBucm93KG9kZHNfcmF0aW9zX2RhdGEpKQogIG9kZHNfcmF0aW9zX2RhdGEkVmFyaWFibGUgPC0gaWZlbHNlKGR1cGxpY2F0ZWQob2Rkc19yYXRpb3NfZGF0YSRWYXJpYWJsZSksICIiLCBvZGRzX3JhdGlvc19kYXRhJFZhcmlhYmxlKQoKICBmaW5hbF90YWJsZV9odG1sIDwtIGh0bWxUYWJsZSgKICAgIG9kZHNfcmF0aW9zX2RhdGEsCiAgICBoZWFkZXIgPSBjKCJWYXJpYWJsZSIsICJMZXZlbCIsICJJbmp1cnkiLCAicDAiLCAiTm9uLUluanVyeSIsICJwMSIsICJPZGRzUmF0aW8iLCAiTG93ZXIiLCAiVXBwZXIiLCAiUC1WYWx1ZSIpLAogICAgYWxpZ24gPSAnbGNjY2NjY2NjYycsCiAgICBybmFtZXMgPSBGQUxTRSwKICAgIGNzcy5jZWxsID0gInRleHQtYWxpZ246IGNlbnRlcjsgcGFkZGluZzogMTJweCAxNXB4OyBmb250LXNpemU6IDEycHg7IHdoaXRlLXNwYWNlOiBub3dyYXA7IiwKICAgIGNzcy5yb3cgPSBzcHJpbnRmKCJiYWNrZ3JvdW5kLWNvbG9yOiAlczsiLCByb3dfY29sb3JzKSwKICAgIGhlYWRlci5jc3MgPSAiYmFja2dyb3VuZC1jb2xvcjogIzAwMzM2NjsgZm9udC1zaXplOiAxNHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7IGNvbG9yOiB3aGl0ZTsiLAogICAgY2FwdGlvbiA9ICI8aDMgc3R5bGU9J3RleHQtYWxpZ246IGNlbnRlcjsnPkFuYWx5c2lzIGZvciBQZWRlc3RyaWFuIEludGVyc2VjdGlvbjwvaDM+CiAgICAgICAgICAgICAgIDxwIHN0eWxlPSd0ZXh0LWFsaWduOiBjZW50ZXI7Jz48ZW0+VGhpcyBhbmFseXNpcyBmb2N1c2VzIG9uIG1vZGU6IHBlZGVzdHJpYW4gfCBpbnRlcnNlY3Rpb246IHllczwvZW0+PC9wPiIKICApCgogIHByaW50KEhUTUwoZmluYWxfdGFibGVfaHRtbCkpCn0gZWxzZSB7IiIKfQpgYGAKClwKXApbXjFdCgpbXjFdOiBXaGVuIHVzaW5nIHRoZSBlcGl0YWIgZnVuY3Rpb24gZnJvbSB0aGUgZXBpdG9vbHMgcGFja2FnZSBpbiBSIHRvIGNhbGN1bGF0ZSBvZGRzIHJhdGlvcyAoT1IpLCBpdCBnZW5lcmF0ZXMgc2V2ZXJhbCBpbXBvcnRhbnQgc3RhdGlzdGljcyBhbmQgbWVhc3VyZXMgdGhhdCBoZWxwIGludGVycHJldCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYW4gZXhwb3N1cmUgKGUuZy4sIGEgcGFydGljdWxhciByb2FkIGZlYXR1cmUpIGFuZCBhbiBvdXRjb21lIChlLmcuLCBpbmp1cnkpLgoKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IDEuICBPZGRzUmF0aW86ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAtICAgVGhpcyB2YWx1ZSBtZWFzdXJlcyB0aGUgb2RkcyBvZiB0aGUgZXZlbnQgKGUuZy4sIGluanVyeSkgb2NjdXJyaW5nIGluIHRoZSBleHBvc2VkIGdyb3VwIGNvbXBhcmVkIHRvIHRoZSB1bmV4cG9zZWQgZ3JvdXAuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAtICAgQW4gT1Igb2YgMSBpbmRpY2F0ZXMgbm8gZGlmZmVyZW5jZSBpbiBvZGRzIGJldHdlZW4gdGhlIGdyb3Vwcy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgIC0gICBBbiBPUiBncmVhdGVyIHRoYW4gMSBzdWdnZXN0cyB0aGF0IGV4cG9zdXJlIGlzIGFzc29jaWF0ZWQgd2l0aCBoaWdoZXIgb2RkcyBvZiB0aGUgZXZlbnQuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgLSAgIEFuIE9SIGxlc3MgdGhhbiAxIGluZGljYXRlcyB0aGF0IHRoZSBleHBvc3VyZSBtYXkgYmUgcHJvdGVjdGl2ZSBvciByZWR1Y2UgdGhlIG9kZHMgb2YgdGhlIGV2ZW50LiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKfCAyLiAgTG93ZXIgYW5kIFVwcGVyIChDb25maWRlbmNlIEludGVydmFsKTogICAgICAgICAgICAgICAgICAgICAgICAgIHwgLSAgIFRoZXNlIHZhbHVlcyByZXByZXNlbnQgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgKHR5cGljYWxseSA5NSUpIGFyb3VuZCB0aGUgb2RkcyByYXRpby4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgLSAgIEEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgbWVhbnMgd2UgYXJlIDk1JSBjb25maWRlbnQgdGhhdCB0aGUgdHJ1ZSBPUiBsaWVzIHdpdGhpbiB0aGlzIHJhbmdlLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAtICAgSWYgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaW5jbHVkZXMgdGhlIHZhbHVlIDEsIHRoZSBPUiBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCAoaS5lLiwgdGhlcmUgaXMgbm90IGVub3VnaCBldmlkZW5jZSB0byBzdGF0ZSB0aGVyZeKAmXMgYSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGdyb3VwcykuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgLSAgIFRoZSBMb3dlciBsaW1pdCBpcyB0aGUgbG93ZXIgYm91bmQgb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwsIGFuZCB0aGUgVXBwZXIgbGltaXQgaXMgdGhlIHVwcGVyIGJvdW5kLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKfCAzLiAgUC1WYWx1ZTogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgLSAgIFRoaXMgdmFsdWUgaW5kaWNhdGVzIHRoZSBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2Ugb2YgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gZXhwb3N1cmUgYW5kIHRoZSBvdXRjb21lLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgLSAgIEEgbG93IHAtdmFsdWUgKHVzdWFsbHkgbGVzcyB0aGFuIDAuMDUpIHN1Z2dlc3RzIHRoYXQgdGhlcmUgaXMgc3VmZmljaWVudCBldmlkZW5jZSB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcywgaW5kaWNhdGluZyBhIHNpZ25pZmljYW50IGFzc29jaWF0aW9uIGJldHdlZW4gZXhwb3N1cmUgYW5kIHRoZSBvdXRjb21lLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAtICAgQSBoaWdoIHAtdmFsdWUgaW1wbGllcyB0aGF0IHRoZSBhc3NvY2lhdGlvbiBpcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IDQuICBJbmp1cnkgKENhc2VzIHdpdGggZXZlbnQpIGFuZCBOb24tSW5qdXJ5IChDYXNlcyB3aXRob3V0IGV2ZW50KTogfCAtICAgVGhlc2UgYXJlIHRoZSBjb3VudHMgb2YgY2FzZXMgaW4gZWFjaCBjYXRlZ29yeSAoZXhwb3NlZCBhbmQgdW5leHBvc2VkKSB0aGF0IGhhdmUgb3IgZG8gbm90IGhhdmUgdGhlIGV2ZW50IG9mIGludGVyZXN0IChpbmp1cnkpLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAtICAgVGhlc2UgdmFsdWVzIHNob3cgdGhlIHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBncm91cCwgYXJlIGhlbHBmdWwgaW4gYXNzZXNzaW5nIHRoZSBzdGFiaWxpdHkgb2YgdGhlIHJlc3VsdHMgc2luY2UgdmVyeSBsb3cgY291bnRzIGNhbiBpbmRpY2F0ZSBhbiBpbnN1ZmZpY2llbnQgc2FtcGxlIHNpemUgdG8gZXN0aW1hdGUgdGhlIE9SIGFjY3VyYXRlbHkuIHwKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IDUuICBwMCBhbmQgcDE6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAtICAgVGhlc2UgcmVwcmVzZW50IHRoZSBwcm9wb3J0aW9ucyBvZiBjYXNlcyB3aXRoIHRoZSBldmVudCAoaW5qdXJ5KSBhbmQgd2l0aG91dCB0aGUgZXZlbnQgd2l0aGluIGVhY2ggZ3JvdXAuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAtICAgcDAgaXMgdGhlIHByb3BvcnRpb24gb2YgY2FzZXMgaW4gdGhlIHVuZXhwb3NlZCBncm91cCB0aGF0IGhhdmUgdGhlIGV2ZW50IG9mIGludGVyZXN0LiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgIC0gICAgcDEgaXMgdGhlIHByb3BvcnRpb24gb2YgY2FzZXMgaW4gdGhlIGV4cG9zZWQgZ3JvdXAgdGhhdCBoYXZlIHRoZSBldmVudCBvZiBpbnRlcmVzdC4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgLSAgICBUaGVzZSBwcm9wb3J0aW9ucyBhbGxvdyBmb3IgYSBxdWljayB2aXN1YWxpemF0aW9uIG9mIHRoZSBkaWZmZXJlbmNlIGluIGV2ZW50IHJhdGVzIGJldHdlZW4gdGhlIGdyb3Vwcy4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKCjogT2RkcyByYXRpbyBJbnRlcnByZXRhdGlvbgoKKkV4YW1wbGUgSW50ZXJwcmV0YXRpb246KgoKKklmIHlvdSBvYnRhaW4gYW4gT1Igb2YgMS41IHdpdGggYSBjb25maWRlbmNlIGludGVydmFsIG9mIDEuMiB0byAxLjggYW5kIGEgcC12YWx1ZSBvZiAwLjAxLCB5b3UgY291bGQgaW50ZXJwcmV0IHRoaXMgYXM6IFwqIFRoZXJlIGlzIGEgc2lnbmlmaWNhbnQgYXNzb2NpYXRpb24gKHAtdmFsdWUgXDwgMC4wNSkgYmV0d2VlbiB0aGUgZXhwb3N1cmUgYW5kIHRoZSBldmVudC4gXCogVGhlIGV4cG9zZWQgZ3JvdXAgaGFzIGEgNTAlIGhpZ2hlciBjaGFuY2Ugb2YgZXhwZXJpZW5jaW5nIHRoZSBldmVudCAoaW5qdXJ5KSBjb21wYXJlZCB0byB0aGUgdW5leHBvc2VkIGdyb3VwLiBcKiBTaW5jZSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBkb2VzIG5vdCBpbmNsdWRlIDEsIHRoaXMgcmVsYXRpb25zaGlwIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuKgoKKk9uIHRoZSBvdGhlciBoYW5kLCBpZiB0aGUgT1IgaXMgY2xvc2UgdG8gMSwgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaW5jbHVkZXMgMSAoZS5nLiwgT1IgPSAxLjEsIENJID0gMC45IHRvIDEuMyksIGFuZCB0aGUgcC12YWx1ZSBpcyBoaWdoIChcPiAwLjA1KSwgdGhlbiB0aGVyZSBpcyBub3QgZW5vdWdoIGV2aWRlbmNlIHRvIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgYW4gYXNzb2NpYXRpb24gYmV0d2VlbiB0aGUgZXhwb3N1cmUgYW5kIHRoZSBvdXRjb21lLipcCg==