Data and Methodology
#Importing and processing 1970 data from NHGIS :
##I used raw employment numbers from "Sex by Age" in employed persons over the age of 16 to get the total working population of areas to account for people having multiple jobs in the Occupation and Industry tables, I noticed a discrepancy when I compared the totals from the two tables I used.
placeworkforceraw70 <- read.csv("data/raw/nhgis0005_ds99_1970_place.csv") %>%
filter(AREANAME == "New York City") %>%
select(GISJOIN, STATE, PLACE, C24001,C24002,C24003,C24004,C24005,C24006,C24007,C24008,C24009,C24010,C24011,C24012,C24013,C24014,C24015,C24016) %>%
mutate(totalworkerpop = rowSums(across(where(is.numeric))))
placeworkforce70 <- placeworkforceraw70 %>%
select(PLACE, totalworkerpop)
countyworkforceraw70 <- read.csv("data/raw/nhgis0006_ds99_1970_county.csv") %>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens") %>%
select(GISJOIN, STATE, COUNTY, C24001,C24002,C24003,C24004,C24005,C24006,C24007,C24008,C24009,C24010,C24011,C24012,C24013,C24014,C24015,C24016) %>%
mutate(totalworkerpop = rowSums(across(where(is.numeric))))
countyworkforce70 <- countyworkforceraw70 %>%
select(COUNTY, totalworkerpop)
tractworkforceraw70 <- read.csv("data/raw/nhgis0006_ds99_1970_tract.csv") %>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens") %>%
select(GISJOIN, STATE, COUNTY, AREANAME, C24001,C24002,C24003,C24004,C24005,C24006,C24007,C24008,C24009,C24010,C24011,C24012,C24013,C24014,C24015,C24016) %>%
mutate(totalworkerpop = rowSums(across(where(is.numeric))))
tractworkforce70 <- tractworkforceraw70 %>%
select(GISJOIN, totalworkerpop) %>%
drop_na()
## For 70s employment figures I used the Industry Table for Employed Persons 16 years and over and isolated the following variables:
## C3B004: Furniture and lumber and wood products
## C3B005: Primary metal industries
## C3B006: Fabricated metal industries (including not specified metals)
## C3B007: Machinery, except electrical
## C3B008: Electrical machinery, equipment and supplies
## C3B009: Motor vehicles and other transportation equipment
## C3B010: Other durable goods
## C3B011: Food and kindred products
## C3B012: Textile mill and other fabricated textile products
## C3B013: Printing, publishing, and allied industries
## C3B014: Chemical and allied products
## C3B015: Other nondurable goods (including specified manufacturing industries)
## C3B017: Trucking service and warehousing
## C3B021: Wholesale trade
raw70laborplace <- read.csv("data/raw/1970/nhgis0011_ds99_1970_place.csv") %>%
filter(AREANAME == "New York City") %>%
select(GISJOIN, STATE, PLACE, C3B004,C3B005, C3B006, C3B007, C3B008, C3B009, C3B010, C3B011, C3B012, C3B013, C3B014, C3B015, C3B017, C3B021)
labor70place <- raw70laborplace %>%
mutate(total_man = rowSums(across(where(is.numeric)))) %>%
left_join(placeworkforce70, by = "PLACE") %>%
mutate(pct_man = (total_man/totalworkerpop)) %>%
select(PLACE, pct_man) %>%
rename('1970' = pct_man) %>%
mutate(PLACE = str_remove_all(PLACE, " City"))
raw70countylabor <- read.csv("data/raw/1970/nhgis0011_ds99_1970_county.csv") %>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens")
county70labortrue <- raw70countylabor %>%
select(GISJOIN, STATE, COUNTY, AREANAME, C3B004,C3B005, C3B006, C3B007, C3B008, C3B009, C3B010, C3B011, C3B012, C3B013, C3B014, C3B015, C3B017, C3B021) %>%
mutate(total_man = rowSums(across(where(is.numeric)))) %>%
left_join(countyworkforce70, by = "COUNTY") %>%
mutate(pct_man = (total_man/totalworkerpop)) %>%
select(COUNTY, pct_man) %>%
rename('1970' = pct_man)
raw70tractlabor <-read.csv("data/raw/1970/nhgis0011_ds99_1970_tract.csv") %>%
filter(STATE == "New York", COUNTY == "Kings")
tract70labortrue <- raw70tractlabor %>%
select(GISJOIN, STATE, COUNTY, AREANAME, C3B004,C3B005, C3B006, C3B007, C3B008, C3B009, C3B010, C3B011, C3B012, C3B013, C3B014, C3B015, C3B017, C3B021) %>%
mutate(total_man = rowSums(across(where(is.numeric)))) %>%
left_join(tractworkforce70, by = "GISJOIN") %>%
mutate(pct_man = (total_man/totalworkerpop)) %>%
select(GISJOIN, pct_man, total_man, totalworkerpop) %>%
rename(totalworkerpop_70 = totalworkerpop,
totalman_70 = total_man,
pctman_70 = pct_man,
GISJOIN.y = GISJOIN)
##Importing and processing 1980 data for NHGIS
##Using labor force totals from Table "Persons 16 yrs and over by labor force," variable used:
##B84AD1980:1980:Persons: 16 years and over ~ In labor force--Civilian--Employed
##I realized there was no longer a discrepency in the data so I stopped finding the workforce totals seperately from industry tables
##Using Industry table for industrial employment totals, I isolated the following variables:
## DIA003: Manufacturing: Nondurable goods (codes 100-222)
## DIA004: Manufacturing: Durable goods (codes 230-392)
## DIA007: Wholesale trade (codes 500-571)
raw80laborplace <- read.csv("data/raw/1980/nhgis0013_csv/nhgis0013_ds107_1980_place.csv") %>%
filter(PLACE == "New York") %>%
mutate(total_worker_pop = sum(c_across(DIA001:DIA015)))
labor80place <- raw80laborplace %>%
select(GISJOIN, STATE, PLACE, AREANAME, DIA003, DIA004, DIA007, total_worker_pop) %>%
mutate(total_man = (DIA003 + DIA004 + DIA007)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
select(PLACE, pct_man) %>%
rename('1980' = pct_man)
raw80laborcounty <- read.csv("data/raw/1980/nhgis0013_csv/nhgis0013_ds107_1980_county.csv") %>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens") %>%
select(GISJOIN, STATE, COUNTY, DIA001, DIA002, DIA003, DIA004, DIA005, DIA006, DIA007, DIA008, DIA009, DIA010, DIA011, DIA012, DIA013, DIA014, DIA015) %>%
mutate(total_worker_pop = rowSums(across(where(is.numeric))))
labor80county <- raw80laborcounty %>%
mutate(total_man = (DIA003 + DIA004 + DIA007)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
select(COUNTY, pct_man) %>%
rename('1980' = pct_man)
raw80labortract <- read.csv("data/raw/1980/nhgis0013_csv/nhgis0013_ds107_1980_tract.csv") %>%
filter(STATE == "New York",COUNTY == "Kings") %>%
select(GISJOIN, STATE, COUNTY, DIA001, DIA002, DIA003, DIA004, DIA005, DIA006, DIA007, DIA008, DIA009, DIA010, DIA011, DIA012, DIA013, DIA014, DIA015) %>%
mutate(total_worker_pop = rowSums(across(where(is.numeric))))
labor80tract <- raw80labortract %>%
mutate(total_man = (DIA003 + DIA004 + DIA007)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
rename(totalworkerpop_80 = total_worker_pop,
totalman_80 = total_man,
pctman_80 = pct_man) %>%
select(GISJOIN, totalman_80, totalworkerpop_80, pctman_80) %>%
rename(GISJOIN.y = GISJOIN)
##Importing and processing 1990 data from NHGIS
##Imported tables combine "Sex by Employment status" (variables E4I001- E4I008) and "Industry" (variables E4P001-E4P017), selecting totals from following columns to calculate total industrial employment:
## E4P004: Manufacturing, nondurable goods (100-229)
## E4P005: Manufacturing, durable goods (230-399)
## E4P008: Wholesale trade (500-579)
##Calculating total working population come from sum of:
## E4I002: Male >> In labor force: Civilian: Employed
## E4I006: Female >> In labor force: Civilian: Employed
raw90placelabor <- read.csv("data/raw/1990/nhgis0008_ds123_1990_place.csv") %>%
filter(PLACE == "New York city") %>%
select(GISJOIN, PLACE, STATE, E4I001, E4I002, E4I003, E4I005, E4I006, E4P004,E4P005, E4P008)
placelabor90 <- raw90placelabor %>%
mutate(total_worker_pop = (E4I002 +E4I006)) %>%
mutate(total_man = (E4P004 + E4P005 + E4P008)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
select(PLACE, pct_man) %>%
rename('1990' = pct_man)
raw90countylabor <- read.csv("data/raw/1990/nhgis0008_ds123_1990_county.csv") %>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens") %>%
select(GISJOIN, STATE, COUNTY, E4I001, E4I002, E4I003, E4I005, E4I006, E4P004, E4P005, E4P008)
countylabor90 <- raw90countylabor %>%
mutate(total_worker_pop = (E4I002 +E4I006)) %>%
mutate(total_man = (E4P004 + E4P005 + E4P008)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
select(COUNTY, pct_man) %>%
rename('1990' = pct_man)
raw90tractlabor <- read.csv("data/raw/1990/nhgis0008_ds123_1990_tract.csv") %>%
filter(STATE == "New York", COUNTY == "Kings") %>%
select(GISJOIN, STATE, ANPSADPI, COUNTY, E4I001, E4I002, E4I003, E4I005, E4I006, E4P004, E4P005, E4P008)
tractlabor90 <- raw90tractlabor %>%
mutate(total_worker_pop = (E4I002 +E4I006)) %>%
mutate(total_man = (E4P004 + E4P005 + E4P008)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
filter(pct_man != "NaN") %>%
select(GISJOIN, ANPSADPI, total_man, total_worker_pop, pct_man) %>%
rename(NAME = ANPSADPI) %>%
rename(totalworkerpop_90 = total_worker_pop,
totalman_90 = total_man,
pctman_90 = pct_man)
##Importing and processing 2000 data, Again I noticed a discrepancy with the total working population which distorted the data so imported table so I imported table: "Total Workers 16 years and Over to get working total first:
totalworkforce00place <- read.csv("data/raw/2000/nhgis0019_csv/nhgis0019_ds151_2000_place.csv") %>%
filter(PLACE == "New York city") %>%
select(PLACE, GJU001 ) %>%
rename(total_worker_pop = GJU001)
totalworkforce00county <- read.csv("data/raw/2000/nhgis0019_csv/nhgis0019_ds151_2000_county.csv")%>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens") %>%
select(COUNTY, GJU001 ) %>%
rename(total_worker_pop = GJU001)
totalworkforce00tract <- read.csv("data/raw/2000/nhgis0019_csv/nhgis0019_ds151_2000_tract.csv") %>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens") %>%
select(GISJOIN, GJU001) %>%
rename(total_worker_pop =GJU001)
##Industrial employement data from table "Sex by Industry Type: Employed Civilian Persons 16 Years and Over in Selected Industry Categories:"
## GMH003:Male >> Manufacturing
## GMH004:Male >> Wholesale trade
## GMH016:Female >> Manufacturing
## GMH017:Female >> Wholesale trade
raw2000laborplace <- read.csv("data/raw/2000/nhgis0016_csv/nhgis0016_ds151_2000_place.csv") %>%
filter(PLACE == "New York city") %>%
select(GISJOIN, PLACE, STATE, GMH001, GMH002, GMH003, GMH004, GMH005, GMH006, GMH007, GMH008, GMH009, GMH010, GMH011, GMH012, GMH013, GMH014, GMH015, GMH016, GMH017, GMH018, GMH019)
labor2000place <- raw2000laborplace %>%
left_join(totalworkforce00place, by = "PLACE") %>%
mutate(total_man = (GMH003 + GMH004 + GMH016 + GMH017)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
select(PLACE, pct_man) %>%
rename('2000' = pct_man)
raw2000laborcounty <- read.csv("data/raw/2000/nhgis0016_csv/nhgis0016_ds151_2000_county.csv") %>%
filter(STATE == "New York", COUNTY == "New York" | COUNTY == "Bronx" | COUNTY == "Kings" | COUNTY == "Queens") %>%
select(GISJOIN, STATE, COUNTY, GMH001, GMH002, GMH003, GMH004, GMH005, GMH006, GMH007, GMH008, GMH009, GMH010, GMH011, GMH012, GMH013, GMH014, GMH015, GMH016, GMH017, GMH018, GMH019)
labor2000county <- raw2000laborcounty %>%
left_join(totalworkforce00county, by = "COUNTY") %>%
mutate(total_man = (GMH003 + GMH004 + GMH016 + GMH017)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
select(COUNTY, pct_man) %>%
rename('2000' = pct_man)
raw2000labortract <- read.csv("data/raw/2000/nhgis0016_csv/nhgis0016_ds151_2000_tract.csv") %>%
filter(STATE == "New York", COUNTY == "Kings") %>%
select(GISJOIN, STATE, COUNTY, NAME, GMH001, GMH002, GMH003, GMH004, GMH005, GMH006, GMH007, GMH008, GMH009, GMH010, GMH011, GMH012, GMH013, GMH014, GMH015, GMH016, GMH017, GMH018, GMH019)
labor2000tract <- raw2000labortract %>%
left_join(totalworkforce00tract, by = "GISJOIN") %>%
mutate(total_man = (GMH003 + GMH004 + GMH016 + GMH017)) %>%
mutate(pct_man = (total_man/total_worker_pop)) %>%
filter(pct_man != "NaN") %>%
select(GISJOIN, NAME, total_man, pct_man, total_worker_pop)
##Importing and processing 2010 data from table "Means of Transportation to Work by Industry,Universe:Workers 16 years and over:" Variable for total working pop is:
## JZNE001:Total
##Total manufacturing employment from:
## JZNE004:Manufacturing
## JZNE005:Wholesale trade
rawtestlabor10place <- read.csv("data/raw/2010/nhgis0010_csv/nhgis0010_ds177_20105_place.csv") %>%
filter(PLACE == "New York city") %>%
select(GISJOIN, PLACE, JZNE001, JZNE002, JZNE003, JZNE004, JZNE005, JZNE006, JZNE007, JZNE008, JZNE009, JZNE010, JZNE011, JZNE012, JZNE013, JZNE014, JZNE015, JZNE016)
labor10place <- rawtestlabor10place %>%
rename(total_worker_pop = JZNE001) %>%
mutate(total_man = (JZNE004 + JZNE005),
pct_man = (total_man/total_worker_pop))
rawlabor10county <- read.csv("data/raw/2010/nhgis0010_csv/nhgis0010_ds177_20105_county.csv") %>%
filter(STATE == "New York", COUNTY == "New York County" | COUNTY == "Bronx County" | COUNTY == "Kings County" | COUNTY == "Queens County") %>%
select(GISJOIN, STATE, COUNTY, JZNE001, JZNE002, JZNE003, JZNE004, JZNE005, JZNE006, JZNE007, JZNE008, JZNE009, JZNE010, JZNE011, JZNE012, JZNE013, JZNE014, JZNE015, JZNE016)
labor10county <- rawlabor10county %>%
rename(total_worker_pop = JZNE001) %>%
mutate(total_man = (JZNE004 + JZNE005),
pct_man = (total_man/total_worker_pop))
rawlabor10tract <- read.csv("data/raw/2010/nhgis0010_csv/nhgis0010_ds177_20105_tract.csv") %>%
filter(STATE == "New York", COUNTY == "Kings County") %>%
select(GISJOIN, STATE, COUNTY, NAME_E, JZNE001, JZNE002, JZNE003, JZNE004, JZNE005, JZNE006, JZNE007, JZNE008, JZNE009, JZNE010, JZNE011, JZNE012, JZNE013, JZNE014, JZNE015, JZNE016)
labor10tract <- rawlabor10tract %>%
rename(total_worker_pop = JZNE001) %>%
mutate(total_man = (JZNE004 + JZNE005),
pct_man = (total_man/total_worker_pop)) %>%
rename(NAME = NAME_E)
Results:
##First for the city as a whole:
totalaborplace <- labor10place %>%
select(GISJOIN, PLACE, total_worker_pop, total_man, pct_man) %>%
rename('2010' = pct_man) %>%
left_join(labor2000place, by = "PLACE") %>%
left_join(placelabor90, by = "PLACE") %>%
select(PLACE, '2010', '2000', '1990') %>%
mutate(PLACE = str_remove_all(PLACE, " city")) %>%
left_join(labor80place, by = "PLACE") %>%
left_join(labor70place, by = "PLACE") %>%
pivot_longer(-c(PLACE), names_to = "year")
## Next for the counties:
totallaborcounty <- labor10county %>%
select(COUNTY, pct_man) %>%
rename('2010' = pct_man) %>%
mutate(COUNTY = str_remove_all(COUNTY, " County")) %>%
left_join(labor2000county, by = "COUNTY") %>%
left_join(countylabor90, by = "COUNTY") %>%
left_join(labor80county, by = "COUNTY") %>%
left_join(county70labortrue, by = "COUNTY") %>%
pivot_longer(-c(COUNTY), names_to = "year")
##Finally for tract, in order to isolate the neighborhoods I wanted, I used a spatial join with the Neighborhood Tabulation tables from NYC Open Data. I had to pull just the shape files from the census in order to match everything up.
##Importing and processing Neighborhood Tabulation Tables:
raw_nabes <- st_read("data/raw/nynta2010_21d/nynta2010.shp")
## Reading layer `nynta2010' from data source
## `/Users/pansyschulman/Dropbox/Mac/Desktop/Grad School/Methods/Final Project/data/raw/nynta2010_21d/nynta2010.shp'
## using driver `ESRI Shapefile'
## Simple feature collection with 195 features and 7 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 913175.1 ymin: 120128.4 xmax: 1067383 ymax: 272844.3
## Projected CRS: NAD83 / New York Long Island (ftUS)
nabes <- raw_nabes %>%
filter(BoroName == "Brooklyn") %>%
filter(NTAName == "Carroll Gardens-Columbia Street-Red Hook" | NTAName == "Park Slope-Gowanus" | NTAName == "Sunset Park East" | NTAName == "Sunset Park West") %>%
select(BoroName, CountyFIPS, NTAName)
##importing geometry of 2010 tracts from Tidy Census and transforming in order to fit the NABES file.
rawlabor10tractshp <- get_acs(geography = "tract",
variables = "B24012_001",
year = 2010,
state = "NY",
county = "Kings",
geometry = TRUE) %>%
select(NAME, geometry) %>%
st_transform(2263)
## Getting data from the 2006-2010 5-year ACS
labor10tractshp <- rawlabor10tractshp %>%
right_join(labor10tract, by = "NAME") %>%
select(GISJOIN, NAME, total_man, pct_man, total_worker_pop, geometry) %>%
st_join(nabes, join = st_intersects) %>%
drop_na() %>%
rename(totalman_10 = total_man,
totalworkerpop_10 = total_worker_pop,
pctman_10 = pct_man)
##Finally putting together total historical data for the tract geographical level:
totaltractlabordata <- labor10tractshp %>%
left_join(labor2000tract, by = "GISJOIN") %>%
rename(totalworkerpop_00 = total_worker_pop,
totalman_00 = total_man,
pctman_00 = pct_man) %>%
mutate(NAME = str_remove_all(NAME.y, "Census ")) %>%
left_join(tractlabor90, by = "NAME") %>%
left_join(labor80tract, by = "GISJOIN.y") %>%
left_join(tract70labortrue, by = "GISJOIN.y") %>%
drop_na() %>%
select(GISJOIN.y, NAME.x, NTAName, totalworkerpop_70, totalworkerpop_80, totalworkerpop_90, totalworkerpop_00, totalworkerpop_10, totalman_70, totalman_80, totalman_90, totalman_00, totalman_10, pctman_70, pctman_80, pctman_90, pctman_00, pctman_10, geometry) %>%
rename(GISJOIN = GISJOIN.y,
NAME = NAME.x)
PLOTtotaltractlabot <- st_drop_geometry(totaltractlabordata) %>%
mutate('1970' = mean(pctman_70),
'1980' = mean(pctman_80),
'1990' = mean(pctman_90),
'2000' = mean(pctman_00),
'2010' = mean(pctman_10)) %>%
select(NAME, '1970', '1980', '1990', '2000', '2010') %>%
filter(NAME == "Census Tract 104, Kings County, New York") %>%
pivot_longer(-c(NAME), names_to = "year")
PLOTtotaltract2 <- st_drop_geometry(totaltractlabordata) %>%
select(NAME, pctman_70, pctman_80, pctman_90, pctman_00, pctman_10) %>%
rename('1970' = pctman_70,
'1980' = pctman_80,
'1990' = pctman_90,
'2000' = pctman_00,
'2010' = pctman_10) %>%
pivot_longer(-c(NAME), names_to = "year")
summary(totalaborplace)
## PLACE year value
## Length:5 Length:5 Min. :0.07037
## Class :character Class :character 1st Qu.:0.10006
## Mode :character Mode :character Median :0.15452
## Mean :0.16048
## 3rd Qu.:0.22164
## Max. :0.25580
summary(totallaborcounty)
## COUNTY year value
## Length:20 Length:20 Min. :0.06221
## Class :character Class :character 1st Qu.:0.09111
## Mode :character Mode :character Median :0.15597
## Mean :0.16112
## 3rd Qu.:0.22629
## Max. :0.27618
summary(PLOTtotaltract2)
## NAME year value
## Length:515 Length:515 Min. :0.007401
## Class :character Class :character 1st Qu.:0.111621
## Mode :character Mode :character Median :0.199712
## Mean :0.198194
## 3rd Qu.:0.269133
## Max. :0.593810
Visualization:
##My map to compare the decline in industrial employment since 1970.
totallaboryears <- ggplot() +
scale_y_continuous(labels = percent_format(accuracy = 1)) +
geom_point(data = PLOTtotaltractlabot, mapping = aes(x = year, y = value), color = "green") +
geom_line(data = PLOTtotaltractlabot, mapping = aes(x= year, y = value,), color = "green", group = 1)+
geom_text(data = subset(PLOTtotaltractlabot, year == "1990"), mapping =aes(x= year, y = value), color = "green", label = "Red Hook/Gowanus/Sunset Park", hjust = -.2) +
geom_point(data = totalaborplace, mapping = aes(x = year, y = value), color = "red", size = 2) +
geom_line(data = totalaborplace, mapping = aes(x= year, y = value,), color = "red", group = 1, size = 5, alpha = .5) +
geom_text(data = subset(totalaborplace, year == "1980"), aes(x= year, y = value), label = "New York City", color = "red", hjust = -.2) +
geom_point(data = totallaborcounty, mapping = aes(x = year, y = value, color = COUNTY)) +
geom_line(data = totallaborcounty, mapping = aes(x = year, y = value, color = COUNTY, group = COUNTY), linetype = "dotdash") +
geom_text(data = subset(totallaborcounty, year == "1970"), aes(label = COUNTY, x= year, y = value, color = COUNTY), hjust = 1.1) +
scale_color_manual(values = c("tomato3", "steelblue2",
"seagreen3", "orchid1")) +
labs(x = "Year", y = "Industrial Employment (%)", title = "Industrial Employment in New York City since 1970", caption = "Sources: The US Census and American Community Survey", color = "County")
ggplotly(totallaboryears)
Observations:
This chart shows a clear and steady decline in industrial employment since the 1970s, confirming the background historical information that I gathered. The three neighborhoods I isolated had a much larger share of industrial employment than the entire city but saw a much steeper drop between 1980 and 1990. Of the four boroughs, Brooklyn had an initially higher share of industrial employment, but by 2010 it was eclipsed by Queens with a small but significant margin.
Next I looked at contemporary geographic data for the neighborhoods I selected to better contextualize my historical data.
#Processing the demographic data of median income and median home value in Red Hook, Gowanus, and Sunset Park from 2010.
rawmedianincome <- get_acs(geography = "tract",
variables = "B19013_001",
year = 2010,
state = "NY",
county = "Kings",
geometry = TRUE)
## Getting data from the 2006-2010 5-year ACS
medianincome <- rawmedianincome %>%
select(GEOID, NAME, estimate, geometry) %>%
rename(medianincome = estimate)
medianincomecorrectedshp <- medianincome %>%
st_transform(2263)
median_income_nabes <- medianincomecorrectedshp %>%
st_join(nabes, join = st_intersects) %>%
drop_na()
median_incomemap <- ggplot() +
geom_sf(data = median_income_nabes, mapping = aes(fill = medianincome), color = "#ffffff") +
scale_fill_gradient2(name="Median Income ($)", labels=dollar_format(accuracy = 1L)) +
labs(title = "Median Income in Red Hook, Sunset Park, and Gowanus (2010)", caption = "Sources: American Community Survey") +
theme_void()
rawhomevalue <- get_acs(geography = "tract",
variables = "B25077_001",
year = 2010,
state = "NY",
county = "Kings",
geometry = TRUE)
## Getting data from the 2006-2010 5-year ACS
medianhomevalue <- rawhomevalue %>%
select(GEOID, NAME, estimate, geometry) %>%
rename(medianvalue = estimate)
medianvalueecorrectedshp <- medianhomevalue %>%
st_transform(2263)
median_value_nabes <- medianvalueecorrectedshp %>%
st_join(nabes, join = st_intersects) %>%
drop_na()
options(scipen = 100)
median_valuemap <- ggplot() +
geom_sf(data = median_value_nabes, mapping = aes(fill = medianvalue), color = "#ffffff") +
scale_fill_gradient(name="Median Home Value ($)", labels=dollar_format(accuracy = 1L)) +
labs(title = "Median Home Value in Red Hook, Sunset Park, and Gowanus (2010)", direction = 1, caption = "Sources: American Community Survey") +
theme_void()
median_incomemap

median_valuemap

Observations:
These two maps show the current economic condition of these neighborhoods. They both reveal the prevalent gentrification in the neighborhoods of Red Hook and Gowanus, as higher median incomes and home values are clustered there. Sunset Park, however has maintained more of its working-class character. In the 1980s, Sunset Park became the borough’s first Chinatown; the neighborhood’s population of immigrants from China is still growing. As of 2010, the neighborhood’s population is 14.5% White, 35.2% Asian, and 46.4% Latino.
Next I pulled the historical data from previous years to see the change that resulted over time to the current state illustrated by the above maps:
##I used a table series table for median income only, as median home value wasn't recorded consistently according to NHGIS. In retrospect, I did not adjust for inflation so unsure how well this series can inform my findings.
rawmedianincome_8090000 <- read_csv("data/raw/medianincome/nhgis0018_ts_nominal_tract.csv") %>%
filter(STATE == "New York", COUNTY == "Kings County")
## Rows: 105385 Columns: 21
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (16): NHGISCODE, GJOIN1980, GJOIN1990, GJOIN2000, GJOIN2012, STATE, STAT...
## dbl (5): B79AA1980, B79AA1990, B79AA2000, B79AA125, B79AA125M
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
medianincome_8090000 <- rawmedianincome_8090000 %>%
rename(medianincome_80 = B79AA1980,
medianincome_90 = B79AA1990,
medianincome_00 = B79AA2000) %>%
select(NAME2012, medianincome_80, medianincome_90, medianincome_00) %>%
drop_na() %>%
rename(NAME = NAME2012)
median_income_nabesyears <- st_drop_geometry(median_income_nabes) %>%
left_join(medianincome_8090000, by = "NAME") %>%
rename(medianincome_10 = medianincome) %>%
drop_na() %>%
mutate('1980' = medianincome_80,
'1990' = medianincome_90,
'2000' = medianincome_00,
'2010' = medianincome_10) %>%
select(NAME, NTAName, '1980', '1990', '2000', '2010')%>%
pivot_longer(-c(NAME, NTAName), names_to = "year")
medianincomePLOTyears <- median_income_nabesyears %>%
mutate('1980' = mean('1980'),
'1990' = mean('1990'),
'2000' = mean('2000'),
'2010' = mean('2010')) %>%
select(NAME,'1980', '1990', '2000', '2010') %>%
pivot_longer(-c(NAME), names_to = "year") %>%
filter(NAME == "Census Tract 104, Kings County, New York")
## Warning in mean.default("1980"): argument is not numeric or logical: returning
## NA
## Warning in mean.default("1990"): argument is not numeric or logical: returning
## NA
## Warning in mean.default("2000"): argument is not numeric or logical: returning
## NA
## Warning in mean.default("2010"): argument is not numeric or logical: returning
## NA
medianincometime <- ggplot(aes(x = year, y = value), data = median_income_nabesyears) +
scale_y_continuous(labels = dollar_format(accuracy = 1)) +
scale_x_discrete('year') +
scale_color_discrete(name = "Neighborhood", labels = c("Red Hook", "Gowanus", "Sunset Park East", "Sunset Park West")) +
geom_smooth(aes(group = NTAName, color = NTAName), method = 'lm', alpha = .2, formula = y ~x) +
geom_point(mapping = aes(color = NTAName)) +
labs(x = "Year", y = "Median Income ($)", title = "Median Income in Industrial Brooklyn (1980-2010)", caption = "Sources: US Census and American Community Survey")
medianincometime
## Observations:
As illustrated by the previous maps, it seems as if median income in the neighhborhoods of Red Hook and Gownanus have risen far more sharply than in Sunset Park. Currently, Red Hook and Gowanus are popular neighborhoods for restaurants and for going out. As compared to Sunset Park, the racial makeup of Red Hook and Gowanus is far whiter (60.9% and 46% respectively) in addition to being more affluent. Additionally, Sunset Park is a little further away from Manhattan and other more gentrified sections of Brooklyn, which may also explain why the young urban professionals who make up the current gentrifying class may be less likely to settle there.
The last variable I looked at it is how people’s commutes have changed over time. Previously, industrial workers would live close to their workplaces, in the post-industrial era there is often a greater physical seperation between ones home and workplace, especially as rents have dramatically increased in downtown business districts.
Looking at how this variable changed over time may complement the data of declining industrial employment in these neighborhoods.
rawtraveltime <- get_acs(geography = "tract",
table = "B08012",
year = 2010,
state = "NY",
county = "Kings",
geometry = FALSE)
## Getting data from the 2006-2010 5-year ACS
## Loading ACS5 variables for 2010 from table B08012. To cache this dataset for faster access to ACS tables in the future, run this function with `cache_table = TRUE`. You only need to do this once per ACS dataset.
acs5variable <- load_variables(2010, "acs5", cache = FALSE)
traveltime <- rawtraveltime %>%
pivot_wider(names_from = variable, values_from = c(estimate, moe)) %>%
select(GEOID, NAME, estimate_B08012_001, estimate_B08012_002, estimate_B08012_003, estimate_B08012_004, estimate_B08012_005, estimate_B08012_006, estimate_B08012_007, estimate_B08012_008, estimate_B08012_009, estimate_B08012_010, estimate_B08012_011, estimate_B08012_012, estimate_B08012_013) %>%
rename(totalworkerpop = estimate_B08012_001,
lessthan5 = estimate_B08012_002,
fivetonine = estimate_B08012_003,
ten_fourteen = estimate_B08012_004,
fifteen_nineteen = estimate_B08012_005,
twenty_twenfour = estimate_B08012_006,
twenfive_twennine = estimate_B08012_007,
thirty_thirfour = estimate_B08012_008,
thirfive_thirnine = estimate_B08012_009,
forty_fourtfour = estimate_B08012_010,
fourtfive_fiftnine = estimate_B08012_011,
sixt_eightnine = estimate_B08012_012,
ninety_plus = estimate_B08012_013) %>%
mutate(lessthan30 = (lessthan5 + fivetonine + ten_fourteen + fifteen_nineteen + twenty_twenfour + twenfive_twennine),
thirty_fourfour = (thirty_thirfour + thirfive_thirnine + forty_fourtfour),
fourtfiveplue = (fourtfive_fiftnine + sixt_eightnine + ninety_plus)) %>%
mutate(perlessthan30_10 = (lessthan30/totalworkerpop),
per304_10 = (thirty_fourfour/totalworkerpop),
per45_10 = (fourtfiveplue/totalworkerpop))
#Importing historical travel time data from NHGIS
traveltime8090 <- read_csv("data/raw/traveltime/nhgis0017_ts_nominal_tract.csv") %>%
filter(STATE == "New York",
COUNTY == "Kings County")
## Rows: 106145 Columns: 56
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (16): NHGISCODE, GJOIN1980, GJOIN1990, GJOIN2000, GJOIN2012, STATE, STAT...
## dbl (40): C50AA1980, C50AA1990, C50AA2000, C50AA125, C50AA125M, C50AB1980, C...
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
traveltime8090proc <- traveltime8090 %>%
mutate(lessthan30_80 = (C50AA1980 + C50AB1980 + C50AC1980 + C50AD1980 + C50AE1980),
thirty_fourtyfour_80 = C50AF1980,
fourtyfiveplue_80 = (C50AG1980 + C50AH1980)) %>%
mutate(totalworkerpop_80 = (C50AA1980 + C50AB1980 + C50AC1980 + C50AD1980 + C50AE1980 + C50AF1980 + C50AG1980 + C50AH1980)) %>%
mutate(lessthan30_90 = (C50AA1990 + C50AB1990 + C50AC1990 + C50AD1990 + C50AE1990),
thirty_fourtyfour_90 = C50AF1990,
fourtyfiveplue_90 = (C50AG1990 + C50AH1990)) %>%
mutate(totalworkerpop_90 = (C50AA1990 + C50AB1990 + C50AC1990 + C50AD1990 + C50AE1990 + C50AF1990 + C50AG1990 + C50AH1990)) %>%
mutate(lessthan30_00 = (C50AG2000 + C50AH2000),
thirty_fourtyfour_00 = C50AF2000,
fourtyfiveplue_00 = (C50AG2000 + C50AH2000)) %>%
mutate(totalworkerpop_00 = (C50AA2000 + C50AB2000 + C50AC2000 + C50AD2000 + C50AE2000 + C50AF2000 + C50AG2000 + C50AH2000))
perctraveltime809000 <- traveltime8090proc %>%
select(NAME2012, lessthan30_80, lessthan30_90, lessthan30_00, totalworkerpop_80, totalworkerpop_90, totalworkerpop_00, thirty_fourtyfour_80, thirty_fourtyfour_90, thirty_fourtyfour_00, fourtyfiveplue_80, fourtyfiveplue_90, fourtyfiveplue_00) %>%
mutate(perlessthan30_80 = (lessthan30_80/totalworkerpop_80),
per304_80 = (thirty_fourtyfour_80/totalworkerpop_80),
per45_80 = (fourtyfiveplue_80/totalworkerpop_80)) %>%
mutate(perlessthan30_90 = (lessthan30_90/totalworkerpop_90),
per304_90 = (thirty_fourtyfour_90/totalworkerpop_90),
per45_90 = (fourtyfiveplue_90/totalworkerpop_90)) %>%
mutate(perlessthan30_00 = (lessthan30_00/totalworkerpop_00),
per304_00 = (thirty_fourtyfour_00/totalworkerpop_00),
per45_00 = (fourtyfiveplue_00/totalworkerpop_00))
traveltime809000 <- perctraveltime809000 %>%
select(NAME2012, perlessthan30_80, per304_80, per45_80, perlessthan30_90, per304_90, per45_90, perlessthan30_00, per304_00, per45_00) %>%
drop_na() %>%
rename(NAME = NAME2012)
traveltimeyears <- traveltime %>%
select(NAME, perlessthan30_10, per304_10, per45_10) %>%
left_join(traveltime809000, by = "NAME") %>%
drop_na()
traveltimeshp <- get_acs(geography = "tract",
variables = "B08012_001",
year = 2010,
state = "NY",
county = "Kings",
geometry = TRUE)
## Getting data from the 2006-2010 5-year ACS
traveltimeyearsfinal <- traveltimeshp %>%
select(NAME, geometry) %>%
right_join(traveltimeyears, by = "NAME") %>%
st_transform(2263) %>%
st_join(nabes, join = st_intersects) %>%
drop_na()
traveltimeyearsfinalPLOT <- st_drop_geometry(traveltimeyearsfinal) %>%
select(NAME, NTAName, perlessthan30_80, per304_80, per45_80, perlessthan30_90, per304_90, per45_90, perlessthan30_00, per304_00, per45_00, perlessthan30_10, per304_10, per45_10) %>%
rename('029.2010' = perlessthan30_10,
'029.2000' = perlessthan30_00,
'029.1990' = perlessthan30_90,
'029.1980' = perlessthan30_80,
'3044.2010' = per304_10,
'3044.2000' = per304_00,
'3044.1990' = per304_90,
'3044.1980' = per304_80,
'4500.2010' = per45_10,
'4500.2000' = per45_00,
'4500.1990' = per45_90,
'4500.1980' = per45_80) %>%
pivot_longer(-c(NAME, NTAName), names_to = "year") %>%
separate(year, c('Time', 'Year')) %>%
arrange(Time)
commuteline <- ggplot(aes(x = Year, y = value), data = traveltimeyearsfinalPLOT) +
scale_y_continuous(labels = percent_format(accuracy = 1)) +
scale_color_discrete(name = "Commute Time", labels = c("< 30 Minutes", "30-44 minutes", "45+ minutes")) +
labs(x = "Year", y = "Percentage of Working Population (%)", title = "Commuting Times in West Brooklyn (1980-2010)", caption = "Sources: US Census and American Community Survey") +
geom_smooth(mapping = aes(group = Time, color = Time), method = 'lm', alpha = .2, formula = y ~x) +
facet_wrap(~ NTAName, nrow= 2)
commutebar <- ggplot(data = subset(traveltimeyearsfinalPLOT), mapping = aes(x= Year, y = value, fill = Time)) +
labs(x = "Year", y = "Percentage of Working Population (%)", title = "Commuting Times in West Brooklyn (1980-2010)", caption = "Sources: US Census and American Community Survey") +
scale_fill_discrete(name = "Commute Time", labels = c("< 30 Minutes", "30-44 minutes", "45+ minutes")) +
geom_col(position = "dodge")
commutebar

ggplotly(commuteline)
Observations:
Looking at the change in these four areas, the most dramatic shift is in the population share with a less than 30 minute commute in the Red Hook area (from over 40% in 1980 to ~32% by 2010) This could be directly attributed to the loss of industrial employment as factories left the area in the latter half of the 20th century. Longer commutes rose in conjunction with this fall. The Gowanus area shows a similar trend, but it is less pronounced. Sunset Park seems to have always had a higher share of longer than 45 minute commutes, this may be due to its industrial nature devolving more quickly than the other neighborhoods, as the Brooklyn Army Terminal, its main industrial hub, largely went into disuse after World War II. It is interesting that the population share with shorter commutes has remained somewhat stagnant. I speculate that may be in part due to the large immigrant population who own and work at local businesses.
LS0tCnRpdGxlOiAiRGVpbmR1c3RyaWFsaXphdGlvbiBpbiBOZXcgWW9yayBDaXR5IDE5NzAgdG8gMjAxMCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgpgYGBgYHtyLCBlY2hvPSBGQUxTRSwgbWVzc2FnZT1GLCB3YXJuaW5nID0gRn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpsaWJyYXJ5KHRpZHljZW5zdXMpCmxpYnJhcnkodGlkeXZlcnNlKQpvcHRpb25zKHRpZ3Jpc191c2VfY2FjaGUgPSBUUlVFKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkodmlyaWRpcykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKYGBgCiMjIyMjIyBQYW5zeSBTY2h1bG1hbiwgRFVFIE1ldGhvZHMgSSwgMjAyMQoKIyBQcm9qZWN0IFN0YXRlbWVudCBhbmQgQmFja2dyb3VuZAoKICBGb3IgdGhpcyBwcm9qZWN0LCBJIHdhbnRlZCB0byBhbnN3ZXIgdGhlIHF1ZXN0aW9uOiBIb3cgZGlkIGRlaW5kdXN0cmlhbGl6YXRpb24gYWZmZWN0IE5ldyBZb3JrIGRlbW9ncmFwaGljYWxseSBhbmQgZ2VvZ3JhcGhpY2FsbHk/IEhvdyBkbyBvbmNlLWluZHVzdHJpYWwgYXJlYXMgcmVmbGVjdCB0aGVpciBoaXN0b3J5IGluIHRlcm1zIG9mIGRlbW9ncmFwaGljcywgaW5jb21lLCBhbmQgZ2VvZ3JhcGhpYyBtYWtldXA/CiAgCiAgVGhlIHB1cnBvc2Ugb2YgdGhpcyByZXNlYXJjaCBpcyB0byBzaG93IGhvdyBhbiBlY29ub21pYyBzaGlmdCBtYW5pZmVzdGVkIGl0c2VsZiBpbiBOZXcgWW9yaydzIGxhbmRzY2FwZSBmcm9tIDE5NzAgdG8gdG9kYXkuICBJIGxvb2tlZCBhdCB0aHJlZSBnZW9ncmFwaGljIGxldmVscyBpbiBteSBkYXRhIGFuYWx5c2lzOiBmaXJzdCwgZm9yIHRoZSBlbnRpcmUgY2l0eSwgb3IgInBsYWNlIiBpbiBjZW5zdXMgZGVmaW5pdGlvbiwgbmV4dCBmb3IgZWFjaCBpbmRpdmlkdWFsIGNvdW50eSBpbiB0aGUgY2l0eSwgYmVmb3JlIGZpbmFsbHkgem9vbWluZyBpbiBvbiB0aGUgbmVpZ2hib3Job29kcyBvZiBSZWQgSG9vaywgU3Vuc2V0IFBhcmssIGFuZCBHb3dhbnVzIGluIEJyb29rbHluLCBhbGxsIG9mIHdoaWNoIHdlcmUgb25jZSBtYWpvciBpbmR1c3RyeSBodWJzIGFuZCBoYXZlIHNlZW4gbWFqb3IgZWNvbm9taWMgYW5kIGRlbW9ncmFwaGljIGNoYW5nZSBvdmVyIHRoaXMgdGltZS4KICAKICBSZWQgSG9vayBhbmQgU3Vuc2V0IFBhcmsgYXJlIG9uIHRoZSB3ZXN0ZXJuIHdhdGVyZnJvbnQgb2YgQnJvb2tseW4sIGFuZCB0aHVzIGhpc3RvcmljYWxseSB0aGVpciBwb3J0cyBhdHRyYWN0ZWQgYW4gaW5mbHV4IG9mIG1hbnVmYWN0dXJpbmcgYW5kIGluZHVzdHJpYWwgYnVzaW5lc3NlcyBpbiB0aGUgbGF0ZSAxOXRoIGFuZCAyMHRoIGNlbnR1cnkuIEFsbCB0aHJlZSBvZiB0aGVzZSBuZWlnaGJvcmhvb2RzIHdlcmUgaHVicyBmb3IgQnJvb2tseW4ncyBtYXJpdGltZSBzaGlwcGluZyBhbmQgaW5kdXN0cmlhbCBhY3Rpdml0ZXM7IHRoZXkgaGF2ZSBob3N0ZWQgY2VtZW50IHdvcmtzLCBwYWludCBmYWN0b3JpZXMsIHRhbm5lcmllcywgY29hbCB5YXJkcywgd2FyZWhvdXNlcywgbWlsbHMsIGFuZCB0ZXh0aWxlIHByb2R1Y3Rpb24gYW1vbmdzdCBtYW55IG90aGVyIGluZHVzdHJpYWwgc2l0ZXMgaW4gdGhlaXIgaGlzdG9yeS4gVGhlIEdvd2FudXMgQ2FuYWwsIHdoaWNoIHJ1bnMgdGhyb3VnaCB0aGUgbmVpZ2hib3Job29kLCB3YXMgdXNlZCB0byBjb25kdWl0IGJ1aWxkaW5nIG1hdGVyaWFscyB0byBhbmQgZnJvbSB2YXJpb3VzIGZhY3RvcmllcyBpbiB0aGUgYXJlYS4gU3Vuc2V0IFBhcmsgd2FzIGhvbWUgdG8gdGhlIEJyb29rbHluIEFybXkgVGVybWluYWwsIHdoaWNoIHdhcyBhIG1ham9yIG1hbnVmYWN0dXJpbmcgaHViIGZvciBhcm15IHN1cHBsaWVzLCBhcyB3ZWxsIGFzIG1hbnkgb3RoZXIgcGllcnMgYW5kIGZhY3Rvcmllcy4gSW1taWdyYW50cywgd2hvIG1hZGUgdXAgYSBsYXJnZSBwYXJ0IG9mIHRoZSBjaXR5J3MgaW5kdXN0cmlhbCB3b3JrZm9yY2UsIHNldHRsZWQgaW4gdGhlc2UgYXJlYXMgb2YgQnJvb2tseW4gd2l0aCB0aGVpciBmYW1pbGllcy4KICAKIE1hbnVmYWN0dXJpbmcgZW1wbG95bWVudCBpbiBOZXcgWW9yayBDaXR5IHBlYWtlZCBpbiB0aGUgbGF0ZSAxOTQwcy4gSW4gMTk1MywgbWFudWZhY3R1cmluZyBhY2NvdW50ZWQgZm9yIDQwJSBvZiBhbGwgam9icywgYnkgMTk5NCB0aGlzIG51bWJlciBkaXBwZWQgdG8gMTclLiBOZXcgWW9yayBDaXR5IGxvc3QgbW9yZSB0aGFuIDcwMCwwMDAgbWFudWZhY3R1cmluZyBqb2JzIGJldHdlZW4gMTk1MyBhbmQgMTk5NS4gVGhpcyBlY29ub21pYyBjaGFuZ2Ugd2FzIGd1aWRlZCBieSBjaXR5IHBvbGljeSBhcyB3ZWxsIGFzIGxhcmdlciBnbG9iYWwgYW5kIG5hdGlvbmFsIGVjb25vbWljIHRyZW5kcy4gCiAKICFbKkFuIGluZHVzdHJpYWwgbWFwIG9mIE5ldyBZb3JrIENpdHkgZnJvbSAxOTE5LCBjb3VydGVzeSBvZiB0aGUgTmV3IFlvcmsgUHVibGljIExpYnJhcnkuKl0obWFudWZhY3R1cmluZ21hcC5qcGVnKQoKICAKICBSZXpvbmluZyBpbmR1c3RyaWFsIGFyZWFzIGJlZ2FuIGluIHRoZSAxOTUwcyBhbmQgY29udGludWVkIGFuZCBlc2NhbGF0ZWQgdGhyb3VnaCB0aGUgZW5kIG9mIHRoZSAyMHRoIGNlbnR1cnkgdG8gdG9kYXkuICJQbGFubmVkIHNocmlua2FnZSIgaW4gdGhlIDE5NzBzIGN1dCBvZmYgbXVuaWNpcGFsIHJlc291cmNlcyB0byBwb29yIGFuZCB3b3JraW5nLWNsYXNzIGFyZWFzIGFuZCBmYWN0b3JpZXMgbW92ZWQgb3V0IG9mIHRoZSBjaXR5LiBGaW5hbmNpYWwgYW5kIHJlYWwgZXN0YXRlIG9wZXJhdGlvbnMgdG9wcGxlZCB0aGUgb25jZS1pbmR1c3RyaWFsIGNpdHksIG1ha2luZyBOZXcgWW9yayBhIGdsb2JhbCBmaW5hbmNpYWwgaHViIGluc3RlYWQuIAogIAogIEkgY2hvc2UgdGhpcyB0b3BpYyBiZWNhdXNlIEkgd2FzIGludGVyZXN0ZWQgaW4gaG93IHRoZSBldm9sdXRpb24gb2YgYSBuZWlnaGJvcmhvb2QgYW5kIGNpdHkncyB3b3JraW5nIGNsYXNzIHdhcyBpbnZvbHZlZCBpbiBnZW50cmlmaWNhdGlvbiBhbmQgb3RoZXIgcHJvY2Vzc2VzIHRoYXQgaGF2ZSBjaGFuZ2VkIHRoZSBkZW1vZ3JhcGhpYyBtYWtldXAgb2YgTmV3IFlvcmsgY2l0eSBjb21tdW5pdGllcyBvdmVyIHRoZSBwYXN0IDUwIHllYXJzLgogIAogIEZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBwcm9qZWN0LCBJIGNob3NlIHRvIGluY29ycG9yYXRlIG5vdCBvbmx5IHRob3NlIHdvcmtpbmcgaW4gbWFudWZhY3R1cmluZywgYnV0IGluIGluZHVzdHJ5LXJlbGF0ZWQgb2NjdXBhdGlvbnMsIHN1Y2ggYXMgd2FyZWhvdXNpbmcsIHdob2xlc2FsZSB0cmFkZSwgYW5kIHRydWNraW5nLCBzbyBhcyB0byBlbmNvbXBhc3MgYWxsIHRoZSBwZW9wbGUgaW1wYWN0ZWQgYnkgdGhpcyBlY29ub21pYyBzaGlmdC4KICAKICBUaGUgZmlyc3QgdmFyaWFibGUgSSBsb29rZWQgYXQgd2FzIHRoZSBwZXJjZW50YWdlIG9mIG1hbnVmYWN0dXJpbmcgam9icyBpbiByZWxhdGlvbiB0byB0aGUgdG90YWwgd29ya2luZyBwb3B1bGF0aW9uLgpHZW5lcmFsbHksIEkgdXNlZCBjZW5zdXMgZGF0YSBmcm9tIHRoZSBOYXRpb25hbCBIaXN0b3JpY2FsIEdlb2dyYXBoaWNhbCBJbmZvcm1hdGlvbiBTeXN0ZW0gZm9yIGRhdGEgZnJvbSBiZWZvcmUgMjAxMCwgYW5kIHRpZHljZW5zdXMgdG8gcHVsbCBkYXRhIGZyb20gdGhlIDUteWVhciBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IGZvciB0aGUgbW9zdCByZWNlbnQgZGF0YS4KCiMgRGF0YSBhbmQgTWV0aG9kb2xvZ3kKCmBgYHtyfQojSW1wb3J0aW5nIGFuZCBwcm9jZXNzaW5nIDE5NzAgZGF0YSBmcm9tIE5IR0lTIDoKIyNJIHVzZWQgcmF3IGVtcGxveW1lbnQgbnVtYmVycyBmcm9tICJTZXggYnkgQWdlIiBpbiBlbXBsb3llZCBwZXJzb25zIG92ZXIgdGhlIGFnZSBvZiAxNiB0byBnZXQgdGhlIHRvdGFsIHdvcmtpbmcgcG9wdWxhdGlvbiBvZiBhcmVhcyB0byBhY2NvdW50IGZvciBwZW9wbGUgaGF2aW5nIG11bHRpcGxlIGpvYnMgaW4gdGhlIE9jY3VwYXRpb24gYW5kIEluZHVzdHJ5IHRhYmxlcywgSSBub3RpY2VkIGEgZGlzY3JlcGFuY3kgd2hlbiBJIGNvbXBhcmVkIHRoZSB0b3RhbHMgZnJvbSB0aGUgdHdvIHRhYmxlcyBJIHVzZWQuCnBsYWNld29ya2ZvcmNlcmF3NzAgPC0gcmVhZC5jc3YoImRhdGEvcmF3L25oZ2lzMDAwNV9kczk5XzE5NzBfcGxhY2UuY3N2IikgJT4lIAogIGZpbHRlcihBUkVBTkFNRSA9PSAiTmV3IFlvcmsgQ2l0eSIpICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgU1RBVEUsIFBMQUNFLCBDMjQwMDEsQzI0MDAyLEMyNDAwMyxDMjQwMDQsQzI0MDA1LEMyNDAwNixDMjQwMDcsQzI0MDA4LEMyNDAwOSxDMjQwMTAsQzI0MDExLEMyNDAxMixDMjQwMTMsQzI0MDE0LEMyNDAxNSxDMjQwMTYpICU+JSAKICBtdXRhdGUodG90YWx3b3JrZXJwb3AgPSByb3dTdW1zKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSkpKQoKcGxhY2V3b3JrZm9yY2U3MCA8LSBwbGFjZXdvcmtmb3JjZXJhdzcwICU+JSAKICBzZWxlY3QoUExBQ0UsIHRvdGFsd29ya2VycG9wKQoKY291bnR5d29ya2ZvcmNlcmF3NzAgPC0gcmVhZC5jc3YoImRhdGEvcmF3L25oZ2lzMDAwNl9kczk5XzE5NzBfY291bnR5LmNzdiIpICU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIiwgQ09VTlRZID09ICJOZXcgWW9yayIgfCBDT1VOVFkgPT0gIkJyb254IiB8IENPVU5UWSA9PSAiS2luZ3MiIHwgQ09VTlRZID09ICJRdWVlbnMiKSAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIFNUQVRFLCBDT1VOVFksIEMyNDAwMSxDMjQwMDIsQzI0MDAzLEMyNDAwNCxDMjQwMDUsQzI0MDA2LEMyNDAwNyxDMjQwMDgsQzI0MDA5LEMyNDAxMCxDMjQwMTEsQzI0MDEyLEMyNDAxMyxDMjQwMTQsQzI0MDE1LEMyNDAxNikgJT4lIAogIG11dGF0ZSh0b3RhbHdvcmtlcnBvcCA9IHJvd1N1bXMoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpKSkpCgpjb3VudHl3b3JrZm9yY2U3MCA8LSBjb3VudHl3b3JrZm9yY2VyYXc3MCAlPiUgCiAgc2VsZWN0KENPVU5UWSwgdG90YWx3b3JrZXJwb3ApCgp0cmFjdHdvcmtmb3JjZXJhdzcwIDwtIHJlYWQuY3N2KCJkYXRhL3Jhdy9uaGdpczAwMDZfZHM5OV8xOTcwX3RyYWN0LmNzdiIpICU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIiwgQ09VTlRZID09ICJOZXcgWW9yayIgfCBDT1VOVFkgPT0gIkJyb254IiB8IENPVU5UWSA9PSAiS2luZ3MiIHwgQ09VTlRZID09ICJRdWVlbnMiKSAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIFNUQVRFLCBDT1VOVFksIEFSRUFOQU1FLCBDMjQwMDEsQzI0MDAyLEMyNDAwMyxDMjQwMDQsQzI0MDA1LEMyNDAwNixDMjQwMDcsQzI0MDA4LEMyNDAwOSxDMjQwMTAsQzI0MDExLEMyNDAxMixDMjQwMTMsQzI0MDE0LEMyNDAxNSxDMjQwMTYpICU+JSAKICBtdXRhdGUodG90YWx3b3JrZXJwb3AgPSByb3dTdW1zKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSkpKQoKdHJhY3R3b3JrZm9yY2U3MCA8LSB0cmFjdHdvcmtmb3JjZXJhdzcwICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgdG90YWx3b3JrZXJwb3ApICU+JSAKICBkcm9wX25hKCkKCiMjIEZvciA3MHMgZW1wbG95bWVudCBmaWd1cmVzIEkgdXNlZCB0aGUgSW5kdXN0cnkgVGFibGUgZm9yIEVtcGxveWVkIFBlcnNvbnMgMTYgeWVhcnMgYW5kIG92ZXIgYW5kIGlzb2xhdGVkIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOgojIyBDM0IwMDQ6IEZ1cm5pdHVyZSBhbmQgbHVtYmVyIGFuZCB3b29kIHByb2R1Y3RzCiMjIEMzQjAwNTogUHJpbWFyeSBtZXRhbCBpbmR1c3RyaWVzCiMjIEMzQjAwNjogRmFicmljYXRlZCBtZXRhbCBpbmR1c3RyaWVzIChpbmNsdWRpbmcgbm90IHNwZWNpZmllZCBtZXRhbHMpCiMjIEMzQjAwNzogTWFjaGluZXJ5LCBleGNlcHQgZWxlY3RyaWNhbAojIyBDM0IwMDg6IEVsZWN0cmljYWwgbWFjaGluZXJ5LCBlcXVpcG1lbnQgYW5kIHN1cHBsaWVzCiMjIEMzQjAwOTogTW90b3IgdmVoaWNsZXMgYW5kIG90aGVyIHRyYW5zcG9ydGF0aW9uIGVxdWlwbWVudAojIyBDM0IwMTA6IE90aGVyIGR1cmFibGUgZ29vZHMKIyMgQzNCMDExOiBGb29kIGFuZCBraW5kcmVkIHByb2R1Y3RzCiMjIEMzQjAxMjogVGV4dGlsZSBtaWxsIGFuZCBvdGhlciBmYWJyaWNhdGVkIHRleHRpbGUgcHJvZHVjdHMKIyMgQzNCMDEzOiBQcmludGluZywgcHVibGlzaGluZywgYW5kIGFsbGllZCBpbmR1c3RyaWVzCiMjIEMzQjAxNDogQ2hlbWljYWwgYW5kIGFsbGllZCBwcm9kdWN0cwojIyBDM0IwMTU6IE90aGVyIG5vbmR1cmFibGUgZ29vZHMgKGluY2x1ZGluZyBzcGVjaWZpZWQgbWFudWZhY3R1cmluZyBpbmR1c3RyaWVzKQojIyBDM0IwMTc6IFRydWNraW5nIHNlcnZpY2UgYW5kIHdhcmVob3VzaW5nCiMjIEMzQjAyMTogV2hvbGVzYWxlIHRyYWRlCgpyYXc3MGxhYm9ycGxhY2UgPC0gcmVhZC5jc3YoImRhdGEvcmF3LzE5NzAvbmhnaXMwMDExX2RzOTlfMTk3MF9wbGFjZS5jc3YiKSAlPiUgCiAgZmlsdGVyKEFSRUFOQU1FID09ICJOZXcgWW9yayBDaXR5IikgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBTVEFURSwgUExBQ0UsIEMzQjAwNCxDM0IwMDUsIEMzQjAwNiwgQzNCMDA3LCBDM0IwMDgsIEMzQjAwOSwgQzNCMDEwLCBDM0IwMTEsIEMzQjAxMiwgQzNCMDEzLCBDM0IwMTQsIEMzQjAxNSwgQzNCMDE3LCBDM0IwMjEpCgpsYWJvcjcwcGxhY2UgPC0gcmF3NzBsYWJvcnBsYWNlICU+JQogIG11dGF0ZSh0b3RhbF9tYW4gPSByb3dTdW1zKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSkpKSAlPiUgCiAgbGVmdF9qb2luKHBsYWNld29ya2ZvcmNlNzAsIGJ5ID0gIlBMQUNFIikgJT4lIAogIG11dGF0ZShwY3RfbWFuID0gKHRvdGFsX21hbi90b3RhbHdvcmtlcnBvcCkpICU+JSAKICBzZWxlY3QoUExBQ0UsIHBjdF9tYW4pICU+JSAKICByZW5hbWUoJzE5NzAnID0gcGN0X21hbikgJT4lIAogIG11dGF0ZShQTEFDRSA9IHN0cl9yZW1vdmVfYWxsKFBMQUNFLCAiIENpdHkiKSkKCnJhdzcwY291bnR5bGFib3IgPC0gcmVhZC5jc3YoImRhdGEvcmF3LzE5NzAvbmhnaXMwMDExX2RzOTlfMTk3MF9jb3VudHkuY3N2IikgJT4lIAogIGZpbHRlcihTVEFURSA9PSAiTmV3IFlvcmsiLCBDT1VOVFkgPT0gIk5ldyBZb3JrIiB8IENPVU5UWSA9PSAiQnJvbngiIHwgQ09VTlRZID09ICJLaW5ncyIgfCBDT1VOVFkgPT0gIlF1ZWVucyIpCgpjb3VudHk3MGxhYm9ydHJ1ZSA8LSAgcmF3NzBjb3VudHlsYWJvciAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIFNUQVRFLCBDT1VOVFksIEFSRUFOQU1FLCBDM0IwMDQsQzNCMDA1LCBDM0IwMDYsIEMzQjAwNywgQzNCMDA4LCBDM0IwMDksIEMzQjAxMCwgQzNCMDExLCBDM0IwMTIsIEMzQjAxMywgQzNCMDE0LCBDM0IwMTUsIEMzQjAxNywgQzNCMDIxKSAlPiUgCiAgbXV0YXRlKHRvdGFsX21hbiA9IHJvd1N1bXMoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpKSkpICU+JSAKICBsZWZ0X2pvaW4oY291bnR5d29ya2ZvcmNlNzAsIGJ5ID0gIkNPVU5UWSIpICU+JSAKICBtdXRhdGUocGN0X21hbiA9ICh0b3RhbF9tYW4vdG90YWx3b3JrZXJwb3ApKSAlPiUgCiAgc2VsZWN0KENPVU5UWSwgcGN0X21hbikgJT4lIAogIHJlbmFtZSgnMTk3MCcgPSBwY3RfbWFuKQoKcmF3NzB0cmFjdGxhYm9yIDwtcmVhZC5jc3YoImRhdGEvcmF3LzE5NzAvbmhnaXMwMDExX2RzOTlfMTk3MF90cmFjdC5jc3YiKSAlPiUgCiAgZmlsdGVyKFNUQVRFID09ICJOZXcgWW9yayIsIENPVU5UWSA9PSAiS2luZ3MiKQoKdHJhY3Q3MGxhYm9ydHJ1ZSA8LSByYXc3MHRyYWN0bGFib3IgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBTVEFURSwgQ09VTlRZLCBBUkVBTkFNRSwgQzNCMDA0LEMzQjAwNSwgQzNCMDA2LCBDM0IwMDcsIEMzQjAwOCwgQzNCMDA5LCBDM0IwMTAsIEMzQjAxMSwgQzNCMDEyLCBDM0IwMTMsIEMzQjAxNCwgQzNCMDE1LCBDM0IwMTcsIEMzQjAyMSkgJT4lIAogIG11dGF0ZSh0b3RhbF9tYW4gPSByb3dTdW1zKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSkpKSAlPiUgCiAgbGVmdF9qb2luKHRyYWN0d29ya2ZvcmNlNzAsIGJ5ID0gIkdJU0pPSU4iKSAlPiUgCiAgbXV0YXRlKHBjdF9tYW4gPSAodG90YWxfbWFuL3RvdGFsd29ya2VycG9wKSkgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBwY3RfbWFuLCB0b3RhbF9tYW4sIHRvdGFsd29ya2VycG9wKSAlPiUgCiAgcmVuYW1lKHRvdGFsd29ya2VycG9wXzcwID0gdG90YWx3b3JrZXJwb3AsIAogICAgICAgICB0b3RhbG1hbl83MCA9IHRvdGFsX21hbiwKICAgICAgICAgcGN0bWFuXzcwID0gcGN0X21hbiwgCiAgICAgICAgIEdJU0pPSU4ueSA9IEdJU0pPSU4pCgojI0ltcG9ydGluZyBhbmQgcHJvY2Vzc2luZyAxOTgwIGRhdGEgZm9yIE5IR0lTCiMjVXNpbmcgbGFib3IgZm9yY2UgdG90YWxzIGZyb20gVGFibGUgIlBlcnNvbnMgMTYgeXJzIGFuZCBvdmVyIGJ5IGxhYm9yIGZvcmNlLCIgdmFyaWFibGUgdXNlZDoKIyNCODRBRDE5ODA6MTk4MDpQZXJzb25zOiAxNiB5ZWFycyBhbmQgb3ZlciB+IEluIGxhYm9yIGZvcmNlLS1DaXZpbGlhbi0tRW1wbG95ZWQKIyNJIHJlYWxpemVkIHRoZXJlIHdhcyBubyBsb25nZXIgYSBkaXNjcmVwZW5jeSBpbiB0aGUgZGF0YSBzbyBJIHN0b3BwZWQgZmluZGluZyB0aGUgd29ya2ZvcmNlIHRvdGFscyBzZXBlcmF0ZWx5IGZyb20gaW5kdXN0cnkgdGFibGVzCgojI1VzaW5nIEluZHVzdHJ5IHRhYmxlIGZvciBpbmR1c3RyaWFsIGVtcGxveW1lbnQgdG90YWxzLCBJIGlzb2xhdGVkIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOiAKIyMgRElBMDAzOiBNYW51ZmFjdHVyaW5nOiBOb25kdXJhYmxlIGdvb2RzIChjb2RlcyAxMDAtMjIyKQojIyBESUEwMDQ6IE1hbnVmYWN0dXJpbmc6IER1cmFibGUgZ29vZHMgKGNvZGVzIDIzMC0zOTIpCiMjIERJQTAwNzogV2hvbGVzYWxlIHRyYWRlIChjb2RlcyA1MDAtNTcxKQoKcmF3ODBsYWJvcnBsYWNlIDwtIHJlYWQuY3N2KCJkYXRhL3Jhdy8xOTgwL25oZ2lzMDAxM19jc3YvbmhnaXMwMDEzX2RzMTA3XzE5ODBfcGxhY2UuY3N2IikgJT4lIAogIGZpbHRlcihQTEFDRSA9PSAiTmV3IFlvcmsiKSAlPiUgCiAgbXV0YXRlKHRvdGFsX3dvcmtlcl9wb3AgPSBzdW0oY19hY3Jvc3MoRElBMDAxOkRJQTAxNSkpKQoKbGFib3I4MHBsYWNlIDwtIHJhdzgwbGFib3JwbGFjZSAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIFNUQVRFLCBQTEFDRSwgQVJFQU5BTUUsIERJQTAwMywgRElBMDA0LCBESUEwMDcsIHRvdGFsX3dvcmtlcl9wb3ApICU+JSAKICBtdXRhdGUodG90YWxfbWFuID0gKERJQTAwMyArIERJQTAwNCArIERJQTAwNykpICU+JSAKICBtdXRhdGUocGN0X21hbiA9ICh0b3RhbF9tYW4vdG90YWxfd29ya2VyX3BvcCkpICU+JSAKICBzZWxlY3QoUExBQ0UsIHBjdF9tYW4pICU+JSAKICByZW5hbWUoJzE5ODAnID0gcGN0X21hbikKCnJhdzgwbGFib3Jjb3VudHkgPC0gcmVhZC5jc3YoImRhdGEvcmF3LzE5ODAvbmhnaXMwMDEzX2Nzdi9uaGdpczAwMTNfZHMxMDdfMTk4MF9jb3VudHkuY3N2IikgJT4lIAogIGZpbHRlcihTVEFURSA9PSAiTmV3IFlvcmsiLCBDT1VOVFkgPT0gIk5ldyBZb3JrIiB8IENPVU5UWSA9PSAiQnJvbngiIHwgQ09VTlRZID09ICJLaW5ncyIgfCBDT1VOVFkgPT0gIlF1ZWVucyIpICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgU1RBVEUsIENPVU5UWSwgRElBMDAxLCBESUEwMDIsIERJQTAwMywgRElBMDA0LCBESUEwMDUsIERJQTAwNiwgRElBMDA3LCBESUEwMDgsIERJQTAwOSwgRElBMDEwLCBESUEwMTEsIERJQTAxMiwgRElBMDEzLCBESUEwMTQsIERJQTAxNSkgJT4lIAogIG11dGF0ZSh0b3RhbF93b3JrZXJfcG9wID0gcm93U3VtcyhhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykpKSkKCmxhYm9yODBjb3VudHkgPC0gcmF3ODBsYWJvcmNvdW50eSAlPiUgCiAgbXV0YXRlKHRvdGFsX21hbiA9IChESUEwMDMgKyBESUEwMDQgKyBESUEwMDcpKSAlPiUgCiAgbXV0YXRlKHBjdF9tYW4gPSAodG90YWxfbWFuL3RvdGFsX3dvcmtlcl9wb3ApKSAlPiUgCiAgc2VsZWN0KENPVU5UWSwgcGN0X21hbikgJT4lIAogIHJlbmFtZSgnMTk4MCcgPSBwY3RfbWFuKSAKCnJhdzgwbGFib3J0cmFjdCA8LSByZWFkLmNzdigiZGF0YS9yYXcvMTk4MC9uaGdpczAwMTNfY3N2L25oZ2lzMDAxM19kczEwN18xOTgwX3RyYWN0LmNzdiIpICU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIixDT1VOVFkgPT0gIktpbmdzIikgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBTVEFURSwgQ09VTlRZLCBESUEwMDEsIERJQTAwMiwgRElBMDAzLCBESUEwMDQsIERJQTAwNSwgRElBMDA2LCBESUEwMDcsIERJQTAwOCwgRElBMDA5LCBESUEwMTAsIERJQTAxMSwgRElBMDEyLCBESUEwMTMsIERJQTAxNCwgRElBMDE1KSAlPiUgCiAgbXV0YXRlKHRvdGFsX3dvcmtlcl9wb3AgPSByb3dTdW1zKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSkpKQoKbGFib3I4MHRyYWN0IDwtIHJhdzgwbGFib3J0cmFjdCAlPiUgCiAgbXV0YXRlKHRvdGFsX21hbiA9IChESUEwMDMgKyBESUEwMDQgKyBESUEwMDcpKSAlPiUgCiAgbXV0YXRlKHBjdF9tYW4gPSAodG90YWxfbWFuL3RvdGFsX3dvcmtlcl9wb3ApKSAlPiUgCiAgcmVuYW1lKHRvdGFsd29ya2VycG9wXzgwID0gdG90YWxfd29ya2VyX3BvcCwKICAgICAgICAgdG90YWxtYW5fODAgPSB0b3RhbF9tYW4sCiAgICAgICAgIHBjdG1hbl84MCA9IHBjdF9tYW4pICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgdG90YWxtYW5fODAsIHRvdGFsd29ya2VycG9wXzgwLCBwY3RtYW5fODApICU+JSAKICByZW5hbWUoR0lTSk9JTi55ID0gR0lTSk9JTikKCiMjSW1wb3J0aW5nIGFuZCBwcm9jZXNzaW5nIDE5OTAgZGF0YSBmcm9tIE5IR0lTCiMjSW1wb3J0ZWQgdGFibGVzIGNvbWJpbmUgIlNleCBieSBFbXBsb3ltZW50IHN0YXR1cyIgKHZhcmlhYmxlcyBFNEkwMDEtIEU0STAwOCkgYW5kICJJbmR1c3RyeSIgKHZhcmlhYmxlcyBFNFAwMDEtRTRQMDE3KSwgc2VsZWN0aW5nIHRvdGFscyBmcm9tIGZvbGxvd2luZyBjb2x1bW5zIHRvIGNhbGN1bGF0ZSB0b3RhbCBpbmR1c3RyaWFsIGVtcGxveW1lbnQ6CiMjIEU0UDAwNDogTWFudWZhY3R1cmluZywgbm9uZHVyYWJsZSBnb29kcyAoMTAwLTIyOSkKIyMgRTRQMDA1OiBNYW51ZmFjdHVyaW5nLCBkdXJhYmxlIGdvb2RzICgyMzAtMzk5KQojIyBFNFAwMDg6IFdob2xlc2FsZSB0cmFkZSAoNTAwLTU3OSkKIyNDYWxjdWxhdGluZyB0b3RhbCB3b3JraW5nIHBvcHVsYXRpb24gY29tZSBmcm9tIHN1bSBvZjoKIyMgRTRJMDAyOiBNYWxlID4+IEluIGxhYm9yIGZvcmNlOiBDaXZpbGlhbjogRW1wbG95ZWQKIyMgRTRJMDA2OiBGZW1hbGUgPj4gSW4gbGFib3IgZm9yY2U6IENpdmlsaWFuOiBFbXBsb3llZAoKcmF3OTBwbGFjZWxhYm9yIDwtIHJlYWQuY3N2KCJkYXRhL3Jhdy8xOTkwL25oZ2lzMDAwOF9kczEyM18xOTkwX3BsYWNlLmNzdiIpICU+JSAKICBmaWx0ZXIoUExBQ0UgPT0gIk5ldyBZb3JrIGNpdHkiKSAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIFBMQUNFLCBTVEFURSwgRTRJMDAxLCBFNEkwMDIsIEU0STAwMywgRTRJMDA1LCBFNEkwMDYsIEU0UDAwNCxFNFAwMDUsIEU0UDAwOCkKCnBsYWNlbGFib3I5MCA8LSByYXc5MHBsYWNlbGFib3IgJT4lIAogIG11dGF0ZSh0b3RhbF93b3JrZXJfcG9wID0gKEU0STAwMiArRTRJMDA2KSkgJT4lIAogIG11dGF0ZSh0b3RhbF9tYW4gPSAoRTRQMDA0ICsgRTRQMDA1ICsgRTRQMDA4KSkgJT4lIAogIG11dGF0ZShwY3RfbWFuID0gKHRvdGFsX21hbi90b3RhbF93b3JrZXJfcG9wKSkgJT4lIAogIHNlbGVjdChQTEFDRSwgcGN0X21hbikgJT4lIAogIHJlbmFtZSgnMTk5MCcgPSBwY3RfbWFuKQoKcmF3OTBjb3VudHlsYWJvciA8LSByZWFkLmNzdigiZGF0YS9yYXcvMTk5MC9uaGdpczAwMDhfZHMxMjNfMTk5MF9jb3VudHkuY3N2IikgJT4lIAogIGZpbHRlcihTVEFURSA9PSAiTmV3IFlvcmsiLCBDT1VOVFkgPT0gIk5ldyBZb3JrIiB8IENPVU5UWSA9PSAiQnJvbngiIHwgQ09VTlRZID09ICJLaW5ncyIgfCBDT1VOVFkgPT0gIlF1ZWVucyIpICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgU1RBVEUsIENPVU5UWSwgRTRJMDAxLCBFNEkwMDIsIEU0STAwMywgRTRJMDA1LCBFNEkwMDYsIEU0UDAwNCwgRTRQMDA1LCBFNFAwMDgpCgpjb3VudHlsYWJvcjkwIDwtIHJhdzkwY291bnR5bGFib3IgJT4lIAogIG11dGF0ZSh0b3RhbF93b3JrZXJfcG9wID0gKEU0STAwMiArRTRJMDA2KSkgJT4lIAogIG11dGF0ZSh0b3RhbF9tYW4gPSAoRTRQMDA0ICsgRTRQMDA1ICsgRTRQMDA4KSkgJT4lIAogIG11dGF0ZShwY3RfbWFuID0gKHRvdGFsX21hbi90b3RhbF93b3JrZXJfcG9wKSkgJT4lIAogIHNlbGVjdChDT1VOVFksIHBjdF9tYW4pICU+JSAKICByZW5hbWUoJzE5OTAnID0gcGN0X21hbikKCnJhdzkwdHJhY3RsYWJvciA8LSByZWFkLmNzdigiZGF0YS9yYXcvMTk5MC9uaGdpczAwMDhfZHMxMjNfMTk5MF90cmFjdC5jc3YiKSAlPiUgCiAgZmlsdGVyKFNUQVRFID09ICJOZXcgWW9yayIsIENPVU5UWSA9PSAiS2luZ3MiKSAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIFNUQVRFLCBBTlBTQURQSSwgQ09VTlRZLCBFNEkwMDEsIEU0STAwMiwgRTRJMDAzLCBFNEkwMDUsIEU0STAwNiwgRTRQMDA0LCBFNFAwMDUsIEU0UDAwOCkKCnRyYWN0bGFib3I5MCA8LSByYXc5MHRyYWN0bGFib3IgJT4lIAogIG11dGF0ZSh0b3RhbF93b3JrZXJfcG9wID0gKEU0STAwMiArRTRJMDA2KSkgJT4lIAogIG11dGF0ZSh0b3RhbF9tYW4gPSAoRTRQMDA0ICsgRTRQMDA1ICsgRTRQMDA4KSkgJT4lIAogIG11dGF0ZShwY3RfbWFuID0gKHRvdGFsX21hbi90b3RhbF93b3JrZXJfcG9wKSkgJT4lIAogIGZpbHRlcihwY3RfbWFuICE9ICJOYU4iKSAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIEFOUFNBRFBJLCB0b3RhbF9tYW4sIHRvdGFsX3dvcmtlcl9wb3AsIHBjdF9tYW4pICU+JSAKICByZW5hbWUoTkFNRSA9IEFOUFNBRFBJKSAlPiUgCiAgcmVuYW1lKHRvdGFsd29ya2VycG9wXzkwID0gdG90YWxfd29ya2VyX3BvcCwKICAgICAgICAgdG90YWxtYW5fOTAgPSB0b3RhbF9tYW4sIAogICAgICAgICBwY3RtYW5fOTAgPSBwY3RfbWFuKQoKIyNJbXBvcnRpbmcgYW5kIHByb2Nlc3NpbmcgMjAwMCBkYXRhLCAgQWdhaW4gSSBub3RpY2VkIGEgZGlzY3JlcGFuY3kgd2l0aCB0aGUgdG90YWwgd29ya2luZyBwb3B1bGF0aW9uIHdoaWNoIGRpc3RvcnRlZCB0aGUgZGF0YSBzbyBpbXBvcnRlZCB0YWJsZSBzbyBJIGltcG9ydGVkIHRhYmxlOiAiVG90YWwgV29ya2VycyAxNiB5ZWFycyBhbmQgT3ZlciB0byBnZXQgd29ya2luZyB0b3RhbCBmaXJzdDogCgp0b3RhbHdvcmtmb3JjZTAwcGxhY2UgPC0gcmVhZC5jc3YoImRhdGEvcmF3LzIwMDAvbmhnaXMwMDE5X2Nzdi9uaGdpczAwMTlfZHMxNTFfMjAwMF9wbGFjZS5jc3YiKSAlPiUgCiAgZmlsdGVyKFBMQUNFID09ICJOZXcgWW9yayBjaXR5IikgJT4lIAogIHNlbGVjdChQTEFDRSwgR0pVMDAxICkgJT4lIAogIHJlbmFtZSh0b3RhbF93b3JrZXJfcG9wID0gR0pVMDAxKQoKdG90YWx3b3JrZm9yY2UwMGNvdW50eSA8LSByZWFkLmNzdigiZGF0YS9yYXcvMjAwMC9uaGdpczAwMTlfY3N2L25oZ2lzMDAxOV9kczE1MV8yMDAwX2NvdW50eS5jc3YiKSU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIiwgQ09VTlRZID09ICJOZXcgWW9yayIgfCBDT1VOVFkgPT0gIkJyb254IiB8IENPVU5UWSA9PSAiS2luZ3MiIHwgQ09VTlRZID09ICJRdWVlbnMiKSAlPiUKICBzZWxlY3QoQ09VTlRZLCBHSlUwMDEgKSAlPiUgCiAgcmVuYW1lKHRvdGFsX3dvcmtlcl9wb3AgPSBHSlUwMDEpCgp0b3RhbHdvcmtmb3JjZTAwdHJhY3QgPC0gcmVhZC5jc3YoImRhdGEvcmF3LzIwMDAvbmhnaXMwMDE5X2Nzdi9uaGdpczAwMTlfZHMxNTFfMjAwMF90cmFjdC5jc3YiKSAlPiUgCiAgZmlsdGVyKFNUQVRFID09ICJOZXcgWW9yayIsIENPVU5UWSA9PSAiTmV3IFlvcmsiIHwgQ09VTlRZID09ICJCcm9ueCIgfCBDT1VOVFkgPT0gIktpbmdzIiB8IENPVU5UWSA9PSAiUXVlZW5zIikgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBHSlUwMDEpICU+JSAKICByZW5hbWUodG90YWxfd29ya2VyX3BvcCA9R0pVMDAxKQoKCiMjSW5kdXN0cmlhbCBlbXBsb3llbWVudCBkYXRhIGZyb20gdGFibGUgIlNleCBieSBJbmR1c3RyeSBUeXBlOiBFbXBsb3llZCBDaXZpbGlhbiBQZXJzb25zIDE2IFllYXJzIGFuZCBPdmVyIGluIFNlbGVjdGVkIEluZHVzdHJ5IENhdGVnb3JpZXM6IgojIyBHTUgwMDM6TWFsZSA+PiBNYW51ZmFjdHVyaW5nCiMjIEdNSDAwNDpNYWxlID4+IFdob2xlc2FsZSB0cmFkZQojIyBHTUgwMTY6RmVtYWxlID4+IE1hbnVmYWN0dXJpbmcKIyMgR01IMDE3OkZlbWFsZSA+PiBXaG9sZXNhbGUgdHJhZGUKcmF3MjAwMGxhYm9ycGxhY2UgPC0gcmVhZC5jc3YoImRhdGEvcmF3LzIwMDAvbmhnaXMwMDE2X2Nzdi9uaGdpczAwMTZfZHMxNTFfMjAwMF9wbGFjZS5jc3YiKSAlPiUgCiAgZmlsdGVyKFBMQUNFID09ICJOZXcgWW9yayBjaXR5IikgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBQTEFDRSwgU1RBVEUsIEdNSDAwMSwgR01IMDAyLCBHTUgwMDMsIEdNSDAwNCwgR01IMDA1LCBHTUgwMDYsIEdNSDAwNywgR01IMDA4LCBHTUgwMDksIEdNSDAxMCwgR01IMDExLCBHTUgwMTIsIEdNSDAxMywgR01IMDE0LCBHTUgwMTUsIEdNSDAxNiwgR01IMDE3LCBHTUgwMTgsIEdNSDAxOSkKCmxhYm9yMjAwMHBsYWNlIDwtIHJhdzIwMDBsYWJvcnBsYWNlICU+JSAKICBsZWZ0X2pvaW4odG90YWx3b3JrZm9yY2UwMHBsYWNlLCBieSA9ICJQTEFDRSIpICU+JSAKICBtdXRhdGUodG90YWxfbWFuID0gKEdNSDAwMyArIEdNSDAwNCArIEdNSDAxNiArIEdNSDAxNykpICU+JSAKICBtdXRhdGUocGN0X21hbiA9ICh0b3RhbF9tYW4vdG90YWxfd29ya2VyX3BvcCkpICU+JSAKICBzZWxlY3QoUExBQ0UsIHBjdF9tYW4pICU+JSAKICByZW5hbWUoJzIwMDAnID0gcGN0X21hbikKCgpyYXcyMDAwbGFib3Jjb3VudHkgPC0gcmVhZC5jc3YoImRhdGEvcmF3LzIwMDAvbmhnaXMwMDE2X2Nzdi9uaGdpczAwMTZfZHMxNTFfMjAwMF9jb3VudHkuY3N2IikgJT4lIAogIGZpbHRlcihTVEFURSA9PSAiTmV3IFlvcmsiLCBDT1VOVFkgPT0gIk5ldyBZb3JrIiB8IENPVU5UWSA9PSAiQnJvbngiIHwgQ09VTlRZID09ICJLaW5ncyIgfCBDT1VOVFkgPT0gIlF1ZWVucyIpICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgU1RBVEUsIENPVU5UWSwgR01IMDAxLCBHTUgwMDIsIEdNSDAwMywgR01IMDA0LCBHTUgwMDUsIEdNSDAwNiwgR01IMDA3LCBHTUgwMDgsIEdNSDAwOSwgR01IMDEwLCBHTUgwMTEsIEdNSDAxMiwgR01IMDEzLCBHTUgwMTQsIEdNSDAxNSwgR01IMDE2LCBHTUgwMTcsIEdNSDAxOCwgR01IMDE5KQoKbGFib3IyMDAwY291bnR5IDwtIHJhdzIwMDBsYWJvcmNvdW50eSAlPiUgCiAgbGVmdF9qb2luKHRvdGFsd29ya2ZvcmNlMDBjb3VudHksIGJ5ID0gIkNPVU5UWSIpICU+JSAKICBtdXRhdGUodG90YWxfbWFuID0gKEdNSDAwMyArIEdNSDAwNCArIEdNSDAxNiArIEdNSDAxNykpICU+JSAKICBtdXRhdGUocGN0X21hbiA9ICh0b3RhbF9tYW4vdG90YWxfd29ya2VyX3BvcCkpICU+JSAKICBzZWxlY3QoQ09VTlRZLCBwY3RfbWFuKSAlPiUgCiAgcmVuYW1lKCcyMDAwJyA9IHBjdF9tYW4pCgpyYXcyMDAwbGFib3J0cmFjdCA8LSByZWFkLmNzdigiZGF0YS9yYXcvMjAwMC9uaGdpczAwMTZfY3N2L25oZ2lzMDAxNl9kczE1MV8yMDAwX3RyYWN0LmNzdiIpICU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIiwgQ09VTlRZID09ICJLaW5ncyIpICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgU1RBVEUsIENPVU5UWSwgTkFNRSwgR01IMDAxLCBHTUgwMDIsIEdNSDAwMywgR01IMDA0LCBHTUgwMDUsIEdNSDAwNiwgR01IMDA3LCBHTUgwMDgsIEdNSDAwOSwgR01IMDEwLCBHTUgwMTEsIEdNSDAxMiwgR01IMDEzLCBHTUgwMTQsIEdNSDAxNSwgR01IMDE2LCBHTUgwMTcsIEdNSDAxOCwgR01IMDE5KQoKbGFib3IyMDAwdHJhY3QgPC0gcmF3MjAwMGxhYm9ydHJhY3QgJT4lIAogIGxlZnRfam9pbih0b3RhbHdvcmtmb3JjZTAwdHJhY3QsIGJ5ID0gIkdJU0pPSU4iKSAlPiUgCiAgbXV0YXRlKHRvdGFsX21hbiA9IChHTUgwMDMgKyBHTUgwMDQgKyBHTUgwMTYgKyBHTUgwMTcpKSAlPiUgCiAgbXV0YXRlKHBjdF9tYW4gPSAodG90YWxfbWFuL3RvdGFsX3dvcmtlcl9wb3ApKSAlPiUgCiAgZmlsdGVyKHBjdF9tYW4gIT0gIk5hTiIpICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgTkFNRSwgdG90YWxfbWFuLCBwY3RfbWFuLCB0b3RhbF93b3JrZXJfcG9wKSAKCiMjSW1wb3J0aW5nIGFuZCBwcm9jZXNzaW5nIDIwMTAgZGF0YSBmcm9tIHRhYmxlICJNZWFucyBvZiBUcmFuc3BvcnRhdGlvbiB0byBXb3JrIGJ5IEluZHVzdHJ5LFVuaXZlcnNlOldvcmtlcnMgMTYgeWVhcnMgYW5kIG92ZXI6IiBWYXJpYWJsZSBmb3IgdG90YWwgd29ya2luZyBwb3AgaXM6CiMjIEpaTkUwMDE6VG90YWwKIyNUb3RhbCBtYW51ZmFjdHVyaW5nIGVtcGxveW1lbnQgZnJvbToKIyMgSlpORTAwNDpNYW51ZmFjdHVyaW5nCiMjIEpaTkUwMDU6V2hvbGVzYWxlIHRyYWRlCgpyYXd0ZXN0bGFib3IxMHBsYWNlIDwtIHJlYWQuY3N2KCJkYXRhL3Jhdy8yMDEwL25oZ2lzMDAxMF9jc3YvbmhnaXMwMDEwX2RzMTc3XzIwMTA1X3BsYWNlLmNzdiIpICU+JSAKZmlsdGVyKFBMQUNFID09ICJOZXcgWW9yayBjaXR5IikgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBQTEFDRSwgSlpORTAwMSwgSlpORTAwMiwgSlpORTAwMywgSlpORTAwNCwgSlpORTAwNSwgSlpORTAwNiwgSlpORTAwNywgSlpORTAwOCwgSlpORTAwOSwgSlpORTAxMCwgSlpORTAxMSwgSlpORTAxMiwgSlpORTAxMywgSlpORTAxNCwgSlpORTAxNSwgSlpORTAxNikKCmxhYm9yMTBwbGFjZSA8LSByYXd0ZXN0bGFib3IxMHBsYWNlICU+JSAKICByZW5hbWUodG90YWxfd29ya2VyX3BvcCA9IEpaTkUwMDEpICU+JSAKICBtdXRhdGUodG90YWxfbWFuID0gKEpaTkUwMDQgKyBKWk5FMDA1KSwKICAgICAgICAgcGN0X21hbiA9ICh0b3RhbF9tYW4vdG90YWxfd29ya2VyX3BvcCkpCgpyYXdsYWJvcjEwY291bnR5IDwtIHJlYWQuY3N2KCJkYXRhL3Jhdy8yMDEwL25oZ2lzMDAxMF9jc3YvbmhnaXMwMDEwX2RzMTc3XzIwMTA1X2NvdW50eS5jc3YiKSAlPiUgCiAgZmlsdGVyKFNUQVRFID09ICJOZXcgWW9yayIsIENPVU5UWSA9PSAiTmV3IFlvcmsgQ291bnR5IiB8IENPVU5UWSA9PSAiQnJvbnggQ291bnR5IiB8IENPVU5UWSA9PSAiS2luZ3MgQ291bnR5IiB8IENPVU5UWSA9PSAiUXVlZW5zIENvdW50eSIpICU+JSAKICBzZWxlY3QoR0lTSk9JTiwgU1RBVEUsIENPVU5UWSwgSlpORTAwMSwgSlpORTAwMiwgSlpORTAwMywgSlpORTAwNCwgSlpORTAwNSwgSlpORTAwNiwgSlpORTAwNywgSlpORTAwOCwgSlpORTAwOSwgSlpORTAxMCwgSlpORTAxMSwgSlpORTAxMiwgSlpORTAxMywgSlpORTAxNCwgSlpORTAxNSwgSlpORTAxNikKCmxhYm9yMTBjb3VudHkgPC0gcmF3bGFib3IxMGNvdW50eSAlPiUgCiAgcmVuYW1lKHRvdGFsX3dvcmtlcl9wb3AgPSBKWk5FMDAxKSAlPiUgCiAgbXV0YXRlKHRvdGFsX21hbiA9IChKWk5FMDA0ICsgSlpORTAwNSksCiAgICAgICAgIHBjdF9tYW4gPSAodG90YWxfbWFuL3RvdGFsX3dvcmtlcl9wb3ApKQoKcmF3bGFib3IxMHRyYWN0IDwtIHJlYWQuY3N2KCJkYXRhL3Jhdy8yMDEwL25oZ2lzMDAxMF9jc3YvbmhnaXMwMDEwX2RzMTc3XzIwMTA1X3RyYWN0LmNzdiIpICU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIiwgQ09VTlRZID09ICAiS2luZ3MgQ291bnR5IikgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBTVEFURSwgQ09VTlRZLCBOQU1FX0UsIEpaTkUwMDEsIEpaTkUwMDIsIEpaTkUwMDMsIEpaTkUwMDQsIEpaTkUwMDUsIEpaTkUwMDYsIEpaTkUwMDcsIEpaTkUwMDgsIEpaTkUwMDksIEpaTkUwMTAsIEpaTkUwMTEsIEpaTkUwMTIsIEpaTkUwMTMsIEpaTkUwMTQsIEpaTkUwMTUsIEpaTkUwMTYpCgpsYWJvcjEwdHJhY3QgPC0gcmF3bGFib3IxMHRyYWN0ICU+JSAKICByZW5hbWUodG90YWxfd29ya2VyX3BvcCA9IEpaTkUwMDEpICU+JSAKICBtdXRhdGUodG90YWxfbWFuID0gKEpaTkUwMDQgKyBKWk5FMDA1KSwKICAgICAgICAgcGN0X21hbiA9ICh0b3RhbF9tYW4vdG90YWxfd29ya2VyX3BvcCkpICU+JSAKICByZW5hbWUoTkFNRSA9IE5BTUVfRSkKYGBgCgoKIyMgUmVzdWx0czoKCmBgYHtyfQojI0ZpcnN0IGZvciB0aGUgY2l0eSBhcyBhIHdob2xlOgp0b3RhbGFib3JwbGFjZSA8LSBsYWJvcjEwcGxhY2UgJT4lIAogIHNlbGVjdChHSVNKT0lOLCBQTEFDRSwgdG90YWxfd29ya2VyX3BvcCwgdG90YWxfbWFuLCBwY3RfbWFuKSAlPiUgCiAgcmVuYW1lKCcyMDEwJyA9IHBjdF9tYW4pICU+JSAKICBsZWZ0X2pvaW4obGFib3IyMDAwcGxhY2UsIGJ5ID0gIlBMQUNFIikgJT4lIAogIGxlZnRfam9pbihwbGFjZWxhYm9yOTAsIGJ5ID0gIlBMQUNFIikgJT4lIAogIHNlbGVjdChQTEFDRSwgJzIwMTAnLCAnMjAwMCcsICcxOTkwJykgJT4lIAogIG11dGF0ZShQTEFDRSA9IHN0cl9yZW1vdmVfYWxsKFBMQUNFLCAiIGNpdHkiKSkgJT4lIAogIGxlZnRfam9pbihsYWJvcjgwcGxhY2UsIGJ5ID0gIlBMQUNFIikgJT4lIAogIGxlZnRfam9pbihsYWJvcjcwcGxhY2UsIGJ5ID0gIlBMQUNFIikgJT4lIAogIHBpdm90X2xvbmdlcigtYyhQTEFDRSksIG5hbWVzX3RvID0gInllYXIiKQoKICAKIyMgTmV4dCBmb3IgdGhlIGNvdW50aWVzOiAKdG90YWxsYWJvcmNvdW50eSA8LSBsYWJvcjEwY291bnR5ICU+JSAKICBzZWxlY3QoQ09VTlRZLCBwY3RfbWFuKSAlPiUgCiAgcmVuYW1lKCcyMDEwJyA9IHBjdF9tYW4pICU+JQogIG11dGF0ZShDT1VOVFkgPSBzdHJfcmVtb3ZlX2FsbChDT1VOVFksICIgQ291bnR5IikpICU+JSAKICBsZWZ0X2pvaW4obGFib3IyMDAwY291bnR5LCBieSA9ICJDT1VOVFkiKSAlPiUgCiAgbGVmdF9qb2luKGNvdW50eWxhYm9yOTAsIGJ5ID0gIkNPVU5UWSIpICU+JSAKICBsZWZ0X2pvaW4obGFib3I4MGNvdW50eSwgYnkgPSAiQ09VTlRZIikgJT4lIAogIGxlZnRfam9pbihjb3VudHk3MGxhYm9ydHJ1ZSwgYnkgPSAiQ09VTlRZIikgJT4lIAogIHBpdm90X2xvbmdlcigtYyhDT1VOVFkpLCBuYW1lc190byA9ICJ5ZWFyIikKCgojI0ZpbmFsbHkgZm9yIHRyYWN0LCBpbiBvcmRlciB0byBpc29sYXRlIHRoZSBuZWlnaGJvcmhvb2RzIEkgd2FudGVkLCBJIHVzZWQgYSBzcGF0aWFsIGpvaW4gd2l0aCB0aGUgTmVpZ2hib3Job29kIFRhYnVsYXRpb24gdGFibGVzIGZyb20gTllDIE9wZW4gRGF0YS4gSSBoYWQgdG8gcHVsbCBqdXN0IHRoZSBzaGFwZSBmaWxlcyBmcm9tIHRoZSBjZW5zdXMgaW4gb3JkZXIgdG8gbWF0Y2ggZXZlcnl0aGluZyB1cC4KCiMjSW1wb3J0aW5nIGFuZCBwcm9jZXNzaW5nIE5laWdoYm9yaG9vZCBUYWJ1bGF0aW9uIFRhYmxlczoKCnJhd19uYWJlcyA8LSBzdF9yZWFkKCJkYXRhL3Jhdy9ueW50YTIwMTBfMjFkL255bnRhMjAxMC5zaHAiKQoKbmFiZXMgPC0gcmF3X25hYmVzICU+JSAKICBmaWx0ZXIoQm9yb05hbWUgPT0gIkJyb29rbHluIikgJT4lIAogIGZpbHRlcihOVEFOYW1lID09ICJDYXJyb2xsIEdhcmRlbnMtQ29sdW1iaWEgU3RyZWV0LVJlZCBIb29rIiB8IE5UQU5hbWUgPT0gIlBhcmsgU2xvcGUtR293YW51cyIgfCBOVEFOYW1lID09ICJTdW5zZXQgUGFyayBFYXN0IiB8IE5UQU5hbWUgPT0gIlN1bnNldCBQYXJrIFdlc3QiKSAlPiUgCiAgc2VsZWN0KEJvcm9OYW1lLCBDb3VudHlGSVBTLCBOVEFOYW1lKQoKIyNpbXBvcnRpbmcgZ2VvbWV0cnkgb2YgMjAxMCB0cmFjdHMgZnJvbSBUaWR5IENlbnN1cyBhbmQgdHJhbnNmb3JtaW5nIGluIG9yZGVyIHRvIGZpdCB0aGUgTkFCRVMgZmlsZS4KCnJhd2xhYm9yMTB0cmFjdHNocCA8LSBnZXRfYWNzKGdlb2dyYXBoeSA9ICJ0cmFjdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcyA9ICJCMjQwMTJfMDAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IDIwMTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9ICJOWSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50eSA9ICJLaW5ncyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gVFJVRSkgJT4lIAogIHNlbGVjdChOQU1FLCBnZW9tZXRyeSkgJT4lIAogIHN0X3RyYW5zZm9ybSgyMjYzKQoKbGFib3IxMHRyYWN0c2hwIDwtIHJhd2xhYm9yMTB0cmFjdHNocCAlPiUgCiAgcmlnaHRfam9pbihsYWJvcjEwdHJhY3QsIGJ5ID0gIk5BTUUiKSAlPiUgCiAgc2VsZWN0KEdJU0pPSU4sIE5BTUUsIHRvdGFsX21hbiwgcGN0X21hbiwgdG90YWxfd29ya2VyX3BvcCwgZ2VvbWV0cnkpICU+JSAKICBzdF9qb2luKG5hYmVzLCBqb2luID0gc3RfaW50ZXJzZWN0cykgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgcmVuYW1lKHRvdGFsbWFuXzEwID0gdG90YWxfbWFuLAogICAgICAgICB0b3RhbHdvcmtlcnBvcF8xMCA9IHRvdGFsX3dvcmtlcl9wb3AsCiAgICAgICAgIHBjdG1hbl8xMCA9IHBjdF9tYW4pCgojI0ZpbmFsbHkgcHV0dGluZyB0b2dldGhlciB0b3RhbCBoaXN0b3JpY2FsIGRhdGEgZm9yIHRoZSB0cmFjdCBnZW9ncmFwaGljYWwgbGV2ZWw6Cgp0b3RhbHRyYWN0bGFib3JkYXRhIDwtIGxhYm9yMTB0cmFjdHNocCAlPiUKICBsZWZ0X2pvaW4obGFib3IyMDAwdHJhY3QsIGJ5ID0gIkdJU0pPSU4iKSAlPiUgCiAgcmVuYW1lKHRvdGFsd29ya2VycG9wXzAwID0gdG90YWxfd29ya2VyX3BvcCwKICAgICAgICAgdG90YWxtYW5fMDAgPSB0b3RhbF9tYW4sCiAgICAgICAgIHBjdG1hbl8wMCA9IHBjdF9tYW4pICU+JSAKICBtdXRhdGUoTkFNRSA9IHN0cl9yZW1vdmVfYWxsKE5BTUUueSwgIkNlbnN1cyAiKSkgJT4lIAogIGxlZnRfam9pbih0cmFjdGxhYm9yOTAsIGJ5ID0gIk5BTUUiKSAlPiUgCiAgbGVmdF9qb2luKGxhYm9yODB0cmFjdCwgYnkgPSAiR0lTSk9JTi55IikgJT4lIAogIGxlZnRfam9pbih0cmFjdDcwbGFib3J0cnVlLCBieSA9ICJHSVNKT0lOLnkiKSAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBzZWxlY3QoR0lTSk9JTi55LCBOQU1FLngsIE5UQU5hbWUsIHRvdGFsd29ya2VycG9wXzcwLCB0b3RhbHdvcmtlcnBvcF84MCwgdG90YWx3b3JrZXJwb3BfOTAsIHRvdGFsd29ya2VycG9wXzAwLCB0b3RhbHdvcmtlcnBvcF8xMCwgdG90YWxtYW5fNzAsIHRvdGFsbWFuXzgwLCB0b3RhbG1hbl85MCwgdG90YWxtYW5fMDAsIHRvdGFsbWFuXzEwLCBwY3RtYW5fNzAsIHBjdG1hbl84MCwgcGN0bWFuXzkwLCBwY3RtYW5fMDAsIHBjdG1hbl8xMCwgZ2VvbWV0cnkpICU+JSAKICByZW5hbWUoR0lTSk9JTiA9IEdJU0pPSU4ueSwKICAgICAgICAgTkFNRSA9IE5BTUUueCkKUExPVHRvdGFsdHJhY3RsYWJvdCA8LSBzdF9kcm9wX2dlb21ldHJ5KHRvdGFsdHJhY3RsYWJvcmRhdGEpICU+JSAKICBtdXRhdGUoJzE5NzAnID0gbWVhbihwY3RtYW5fNzApLAogICAgICAgICAnMTk4MCcgPSBtZWFuKHBjdG1hbl84MCksCiAgICAgICAgICcxOTkwJyA9IG1lYW4ocGN0bWFuXzkwKSwgCiAgICAgICAgICcyMDAwJyA9IG1lYW4ocGN0bWFuXzAwKSwKICAgICAgICAgJzIwMTAnID0gbWVhbihwY3RtYW5fMTApKSAlPiUgCiAgc2VsZWN0KE5BTUUsICcxOTcwJywgJzE5ODAnLCAnMTk5MCcsICcyMDAwJywgJzIwMTAnKSAlPiUgCiAgZmlsdGVyKE5BTUUgPT0gIkNlbnN1cyBUcmFjdCAxMDQsIEtpbmdzIENvdW50eSwgTmV3IFlvcmsiKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1jKE5BTUUpLCBuYW1lc190byA9ICJ5ZWFyIikKClBMT1R0b3RhbHRyYWN0MiA8LSBzdF9kcm9wX2dlb21ldHJ5KHRvdGFsdHJhY3RsYWJvcmRhdGEpICU+JSAKICBzZWxlY3QoTkFNRSwgcGN0bWFuXzcwLCBwY3RtYW5fODAsIHBjdG1hbl85MCwgcGN0bWFuXzAwLCBwY3RtYW5fMTApICU+JSAKICByZW5hbWUoJzE5NzAnID0gcGN0bWFuXzcwLAogICAgICAgICAnMTk4MCcgPSBwY3RtYW5fODAsCiAgICAgICAgICcxOTkwJyA9IHBjdG1hbl85MCwgCiAgICAgICAgICcyMDAwJyA9IHBjdG1hbl8wMCwKICAgICAgICAgJzIwMTAnID0gcGN0bWFuXzEwKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1jKE5BTUUpLCBuYW1lc190byA9ICJ5ZWFyIikKCnN1bW1hcnkodG90YWxhYm9ycGxhY2UpCnN1bW1hcnkodG90YWxsYWJvcmNvdW50eSkKc3VtbWFyeShQTE9UdG90YWx0cmFjdDIpCgpgYGAKCiMjIFZpc3VhbGl6YXRpb246CgpgYGB7cn0KCiMjTXkgbWFwIHRvIGNvbXBhcmUgdGhlIGRlY2xpbmUgaW4gaW5kdXN0cmlhbCBlbXBsb3ltZW50IHNpbmNlIDE5NzAuCnRvdGFsbGFib3J5ZWFycyA8LSBnZ3Bsb3QoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBnZW9tX3BvaW50KGRhdGEgPSBQTE9UdG90YWx0cmFjdGxhYm90LCBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUpLCBjb2xvciA9ICJncmVlbiIpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSBQTE9UdG90YWx0cmFjdGxhYm90LCAgbWFwcGluZyA9IGFlcyh4PSB5ZWFyLCB5ID0gdmFsdWUsKSwgY29sb3IgPSAiZ3JlZW4iLCBncm91cCA9IDEpKyAKICBnZW9tX3RleHQoZGF0YSA9IHN1YnNldChQTE9UdG90YWx0cmFjdGxhYm90LCB5ZWFyID09ICIxOTkwIiksIG1hcHBpbmcgPWFlcyh4PSB5ZWFyLCB5ID0gdmFsdWUpLCBjb2xvciA9ICJncmVlbiIsIGxhYmVsID0gIlJlZCBIb29rL0dvd2FudXMvU3Vuc2V0IFBhcmsiLCBoanVzdCA9IC0uMikgKwogIGdlb21fcG9pbnQoZGF0YSA9IHRvdGFsYWJvcnBsYWNlLCBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUpLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMikgKwogIGdlb21fbGluZShkYXRhID0gdG90YWxhYm9ycGxhY2UsIG1hcHBpbmcgPSBhZXMoeD0geWVhciwgeSA9IHZhbHVlLCksIGNvbG9yID0gInJlZCIsIGdyb3VwID0gMSwgc2l6ZSA9IDUsIGFscGhhID0gLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IHN1YnNldCh0b3RhbGFib3JwbGFjZSwgeWVhciA9PSAiMTk4MCIpLCBhZXMoeD0geWVhciwgeSA9IHZhbHVlKSwgbGFiZWwgPSAiTmV3IFlvcmsgQ2l0eSIsIGNvbG9yID0gInJlZCIsIGhqdXN0ID0gLS4yKSArCiAgZ2VvbV9wb2ludChkYXRhID0gdG90YWxsYWJvcmNvdW50eSwgbWFwcGluZyA9IGFlcyh4ID0geWVhciwgeSA9IHZhbHVlLCBjb2xvciA9IENPVU5UWSkpICsgCiAgZ2VvbV9saW5lKGRhdGEgPSB0b3RhbGxhYm9yY291bnR5LCBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGNvbG9yID0gQ09VTlRZLCBncm91cCA9IENPVU5UWSksIGxpbmV0eXBlID0gImRvdGRhc2giKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBzdWJzZXQodG90YWxsYWJvcmNvdW50eSwgeWVhciA9PSAiMTk3MCIpLCBhZXMobGFiZWwgPSBDT1VOVFksIHg9IHllYXIsIHkgPSB2YWx1ZSwgY29sb3IgPSBDT1VOVFkpLCBoanVzdCA9IDEuMSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygidG9tYXRvMyIsICJzdGVlbGJsdWUyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2VhZ3JlZW4zIiwgIm9yY2hpZDEiKSkgKwogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJJbmR1c3RyaWFsIEVtcGxveW1lbnQgKCUpIiwgdGl0bGUgPSAiSW5kdXN0cmlhbCBFbXBsb3ltZW50IGluIE5ldyBZb3JrIENpdHkgc2luY2UgMTk3MCIsIGNhcHRpb24gPSAiU291cmNlczogVGhlIFVTIENlbnN1cyBhbmQgQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSIsIGNvbG9yID0gIkNvdW50eSIpCmdncGxvdGx5KHRvdGFsbGFib3J5ZWFycykgCmBgYAoKIyMgT2JzZXJ2YXRpb25zOiAKVGhpcyBjaGFydCBzaG93cyBhIGNsZWFyIGFuZCBzdGVhZHkgZGVjbGluZSBpbiBpbmR1c3RyaWFsIGVtcGxveW1lbnQgc2luY2UgdGhlIDE5NzBzLCBjb25maXJtaW5nIHRoZSBiYWNrZ3JvdW5kIGhpc3RvcmljYWwgaW5mb3JtYXRpb24gdGhhdCBJIGdhdGhlcmVkLiBUaGUgdGhyZWUgbmVpZ2hib3Job29kcyBJIGlzb2xhdGVkIGhhZCBhIG11Y2ggbGFyZ2VyIHNoYXJlIG9mIGluZHVzdHJpYWwgZW1wbG95bWVudCB0aGFuIHRoZSBlbnRpcmUgY2l0eSBidXQgc2F3IGEgbXVjaCBzdGVlcGVyIGRyb3AgYmV0d2VlbiAxOTgwIGFuZCAxOTkwLiBPZiB0aGUgZm91ciBib3JvdWdocywgQnJvb2tseW4gaGFkIGFuIGluaXRpYWxseSBoaWdoZXIgc2hhcmUgb2YgaW5kdXN0cmlhbCBlbXBsb3ltZW50LCBidXQgYnkgMjAxMCBpdCB3YXMgZWNsaXBzZWQgYnkgUXVlZW5zIHdpdGggYSBzbWFsbCBidXQgc2lnbmlmaWNhbnQgbWFyZ2luLgoKCiMjIyMjIyBOZXh0IEkgbG9va2VkIGF0IGNvbnRlbXBvcmFyeSBnZW9ncmFwaGljIGRhdGEgZm9yIHRoZSBuZWlnaGJvcmhvb2RzIEkgc2VsZWN0ZWQgdG8gYmV0dGVyIGNvbnRleHR1YWxpemUgbXkgaGlzdG9yaWNhbCBkYXRhLiAKCgpgYGB7cn0KI1Byb2Nlc3NpbmcgdGhlIGRlbW9ncmFwaGljIGRhdGEgb2YgbWVkaWFuIGluY29tZSBhbmQgbWVkaWFuIGhvbWUgdmFsdWUgaW4gUmVkIEhvb2ssIEdvd2FudXMsIGFuZCBTdW5zZXQgUGFyayBmcm9tIDIwMTAuCnJhd21lZGlhbmluY29tZSA8LSBnZXRfYWNzKGdlb2dyYXBoeSA9ICJ0cmFjdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcyA9ICJCMTkwMTNfMDAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IDIwMTAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9ICJOWSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHkgPSAiS2luZ3MiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbWV0cnkgPSBUUlVFKQoKbWVkaWFuaW5jb21lIDwtIHJhd21lZGlhbmluY29tZSAlPiUgCiAgc2VsZWN0KEdFT0lELCBOQU1FLCBlc3RpbWF0ZSwgZ2VvbWV0cnkpICU+JSAKICByZW5hbWUobWVkaWFuaW5jb21lID0gZXN0aW1hdGUpCgptZWRpYW5pbmNvbWVjb3JyZWN0ZWRzaHAgPC0gbWVkaWFuaW5jb21lICU+JSAKICBzdF90cmFuc2Zvcm0oMjI2MykKCm1lZGlhbl9pbmNvbWVfbmFiZXMgPC0gbWVkaWFuaW5jb21lY29ycmVjdGVkc2hwICU+JQogIHN0X2pvaW4obmFiZXMsIGpvaW4gPSBzdF9pbnRlcnNlY3RzKSAlPiUgCiAgZHJvcF9uYSgpCgptZWRpYW5faW5jb21lbWFwIDwtIGdncGxvdCgpICArIAogIGdlb21fc2YoZGF0YSA9IG1lZGlhbl9pbmNvbWVfbmFiZXMsIG1hcHBpbmcgPSBhZXMoZmlsbCA9IG1lZGlhbmluY29tZSksIGNvbG9yID0gIiNmZmZmZmYiKSArIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKG5hbWU9Ik1lZGlhbiBJbmNvbWUgKCQpIiwgbGFiZWxzPWRvbGxhcl9mb3JtYXQoYWNjdXJhY3kgPSAxTCkpICsKICBsYWJzKHRpdGxlID0gIk1lZGlhbiBJbmNvbWUgaW4gUmVkIEhvb2ssIFN1bnNldCBQYXJrLCBhbmQgR293YW51cyAoMjAxMCkiLCBjYXB0aW9uID0gIlNvdXJjZXM6IEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkiKSArCiAgdGhlbWVfdm9pZCgpCgpyYXdob21ldmFsdWUgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAidHJhY3QiLAogICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZXMgPSAiQjI1MDc3XzAwMSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSAyMDEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgc3RhdGUgPSAiTlkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgY291bnR5ID0gIktpbmdzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gVFJVRSkKCm1lZGlhbmhvbWV2YWx1ZSA8LSByYXdob21ldmFsdWUgJT4lIAogIHNlbGVjdChHRU9JRCwgTkFNRSwgZXN0aW1hdGUsIGdlb21ldHJ5KSAlPiUgCiAgcmVuYW1lKG1lZGlhbnZhbHVlID0gZXN0aW1hdGUpCm1lZGlhbnZhbHVlZWNvcnJlY3RlZHNocCA8LSBtZWRpYW5ob21ldmFsdWUgJT4lIAogIHN0X3RyYW5zZm9ybSgyMjYzKQptZWRpYW5fdmFsdWVfbmFiZXMgPC0gbWVkaWFudmFsdWVlY29ycmVjdGVkc2hwICU+JQogIHN0X2pvaW4obmFiZXMsIGpvaW4gPSBzdF9pbnRlcnNlY3RzKSAlPiUgCiAgZHJvcF9uYSgpCm9wdGlvbnMoc2NpcGVuID0gMTAwKQptZWRpYW5fdmFsdWVtYXAgPC0gZ2dwbG90KCkgICsgCiAgZ2VvbV9zZihkYXRhID0gbWVkaWFuX3ZhbHVlX25hYmVzLCBtYXBwaW5nID0gYWVzKGZpbGwgPSBtZWRpYW52YWx1ZSksIGNvbG9yID0gIiNmZmZmZmYiKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChuYW1lPSJNZWRpYW4gSG9tZSBWYWx1ZSAoJCkiLCBsYWJlbHM9ZG9sbGFyX2Zvcm1hdChhY2N1cmFjeSA9IDFMKSkgKwogIGxhYnModGl0bGUgPSAiTWVkaWFuIEhvbWUgVmFsdWUgaW4gUmVkIEhvb2ssIFN1bnNldCBQYXJrLCBhbmQgR293YW51cyAoMjAxMCkiLCBkaXJlY3Rpb24gPSAxLCBjYXB0aW9uID0gIlNvdXJjZXM6IEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkiKSArCiAgdGhlbWVfdm9pZCgpCgptZWRpYW5faW5jb21lbWFwCm1lZGlhbl92YWx1ZW1hcApgYGAKCiMjIE9ic2VydmF0aW9uczogClRoZXNlIHR3byBtYXBzIHNob3cgdGhlIGN1cnJlbnQgZWNvbm9taWMgY29uZGl0aW9uIG9mIHRoZXNlIG5laWdoYm9yaG9vZHMuIFRoZXkgYm90aCByZXZlYWwgdGhlIHByZXZhbGVudCBnZW50cmlmaWNhdGlvbiBpbiB0aGUgbmVpZ2hib3Job29kcyBvZiBSZWQgSG9vayBhbmQgR293YW51cywgYXMgaGlnaGVyIG1lZGlhbiBpbmNvbWVzIGFuZCBob21lIHZhbHVlcyBhcmUgY2x1c3RlcmVkIHRoZXJlLiBTdW5zZXQgUGFyaywgaG93ZXZlciBoYXMgbWFpbnRhaW5lZCBtb3JlIG9mIGl0cyB3b3JraW5nLWNsYXNzIGNoYXJhY3Rlci4gSW4gdGhlIDE5ODBzLCBTdW5zZXQgUGFyayBiZWNhbWUgdGhlIGJvcm91Z2gncyBmaXJzdCBDaGluYXRvd247IHRoZSBuZWlnaGJvcmhvb2QncyBwb3B1bGF0aW9uIG9mIGltbWlncmFudHMgZnJvbSBDaGluYSBpcyBzdGlsbCBncm93aW5nLiBBcyBvZiAyMDEwLCB0aGUgbmVpZ2hib3Job29kJ3MgcG9wdWxhdGlvbiBpcyAxNC41JSBXaGl0ZSwgMzUuMiUgQXNpYW4sIGFuZCA0Ni40JSBMYXRpbm8uIAoKCiMjIyMjIyBOZXh0IEkgcHVsbGVkIHRoZSBoaXN0b3JpY2FsIGRhdGEgZnJvbSBwcmV2aW91cyB5ZWFycyB0byBzZWUgdGhlIGNoYW5nZSB0aGF0IHJlc3VsdGVkIG92ZXIgdGltZSB0byB0aGUgY3VycmVudCBzdGF0ZSBpbGx1c3RyYXRlZCBieSB0aGUgYWJvdmUgbWFwczoKCmBgYHtyfQojI0kgdXNlZCBhIHRhYmxlIHNlcmllcyB0YWJsZSBmb3IgbWVkaWFuIGluY29tZSBvbmx5LCBhcyBtZWRpYW4gaG9tZSB2YWx1ZSB3YXNuJ3QgcmVjb3JkZWQgY29uc2lzdGVudGx5IGFjY29yZGluZyB0byBOSEdJUy4gSW4gcmV0cm9zcGVjdCwgSSBkaWQgbm90IGFkanVzdCBmb3IgaW5mbGF0aW9uIHNvIHVuc3VyZSBob3cgd2VsbCB0aGlzIHNlcmllcyBjYW4gaW5mb3JtIG15IGZpbmRpbmdzLgpyYXdtZWRpYW5pbmNvbWVfODA5MDAwMCA8LSByZWFkX2NzdigiZGF0YS9yYXcvbWVkaWFuaW5jb21lL25oZ2lzMDAxOF90c19ub21pbmFsX3RyYWN0LmNzdiIpICU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIiwgQ09VTlRZID09ICJLaW5ncyBDb3VudHkiKQoKbWVkaWFuaW5jb21lXzgwOTAwMDAgPC0gcmF3bWVkaWFuaW5jb21lXzgwOTAwMDAgJT4lIAogIHJlbmFtZShtZWRpYW5pbmNvbWVfODAgPSBCNzlBQTE5ODAsCiAgICAgICAgIG1lZGlhbmluY29tZV85MCA9IEI3OUFBMTk5MCwKICAgICAgICAgbWVkaWFuaW5jb21lXzAwID0gQjc5QUEyMDAwKSAlPiUgCiAgc2VsZWN0KE5BTUUyMDEyLCBtZWRpYW5pbmNvbWVfODAsIG1lZGlhbmluY29tZV85MCwgbWVkaWFuaW5jb21lXzAwKSAlPiUKICBkcm9wX25hKCkgJT4lIAogIHJlbmFtZShOQU1FID0gTkFNRTIwMTIpCgptZWRpYW5faW5jb21lX25hYmVzeWVhcnMgPC0gc3RfZHJvcF9nZW9tZXRyeShtZWRpYW5faW5jb21lX25hYmVzKSAlPiUgCiAgbGVmdF9qb2luKG1lZGlhbmluY29tZV84MDkwMDAwLCBieSA9ICJOQU1FIikgJT4lIAogIHJlbmFtZShtZWRpYW5pbmNvbWVfMTAgPSBtZWRpYW5pbmNvbWUpICU+JSAKICBkcm9wX25hKCkgJT4lIAogIG11dGF0ZSgnMTk4MCcgPSBtZWRpYW5pbmNvbWVfODAsCiAgICAgICAgICcxOTkwJyA9IG1lZGlhbmluY29tZV85MCwgCiAgICAgICAgICcyMDAwJyA9IG1lZGlhbmluY29tZV8wMCwKICAgICAgICAgJzIwMTAnID0gbWVkaWFuaW5jb21lXzEwKSAlPiUgCiAgc2VsZWN0KE5BTUUsIE5UQU5hbWUsICcxOTgwJywgJzE5OTAnLCAnMjAwMCcsICcyMDEwJyklPiUgCiAgcGl2b3RfbG9uZ2VyKC1jKE5BTUUsIE5UQU5hbWUpLCBuYW1lc190byA9ICJ5ZWFyIikKCm1lZGlhbmluY29tZVBMT1R5ZWFycyA8LSBtZWRpYW5faW5jb21lX25hYmVzeWVhcnMgJT4lIAogIG11dGF0ZSgnMTk4MCcgPSBtZWFuKCcxOTgwJyksCiAgICAgICAgICcxOTkwJyA9IG1lYW4oJzE5OTAnKSwgCiAgICAgICAgICcyMDAwJyA9IG1lYW4oJzIwMDAnKSwKICAgICAgICAgJzIwMTAnID0gbWVhbignMjAxMCcpKSAlPiUgCiAgc2VsZWN0KE5BTUUsJzE5ODAnLCAnMTk5MCcsICcyMDAwJywgJzIwMTAnKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1jKE5BTUUpLCBuYW1lc190byA9ICJ5ZWFyIikgJT4lIAogIGZpbHRlcihOQU1FID09ICJDZW5zdXMgVHJhY3QgMTA0LCBLaW5ncyBDb3VudHksIE5ldyBZb3JrIikKCm1lZGlhbmluY29tZXRpbWUgPC0gZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHZhbHVlKSwgZGF0YSA9IG1lZGlhbl9pbmNvbWVfbmFiZXN5ZWFycykgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZG9sbGFyX2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZSgneWVhcicpICsKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIk5laWdoYm9yaG9vZCIsIGxhYmVscyA9IGMoIlJlZCBIb29rIiwgIkdvd2FudXMiLCAiU3Vuc2V0IFBhcmsgRWFzdCIsICJTdW5zZXQgUGFyayBXZXN0IikpICsKICBnZW9tX3Ntb290aChhZXMoZ3JvdXAgPSBOVEFOYW1lLCBjb2xvciA9IE5UQU5hbWUpLCBtZXRob2QgPSAnbG0nLCBhbHBoYSA9IC4yLCBmb3JtdWxhID0gIHkgfngpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBOVEFOYW1lKSkgKyAKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiTWVkaWFuIEluY29tZSAoJCkiLCB0aXRsZSA9ICJNZWRpYW4gSW5jb21lIGluIEluZHVzdHJpYWwgQnJvb2tseW4gKDE5ODAtMjAxMCkiLCBjYXB0aW9uID0gIlNvdXJjZXM6IFVTIENlbnN1cyBhbmQgQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSIpCgogIG1lZGlhbmluY29tZXRpbWUKICAKYGBgCiMjIE9ic2VydmF0aW9uczogCgpBcyBpbGx1c3RyYXRlZCBieSB0aGUgcHJldmlvdXMgbWFwcywgaXQgc2VlbXMgYXMgaWYgbWVkaWFuIGluY29tZSBpbiB0aGUgbmVpZ2hoYm9yaG9vZHMgb2YgUmVkIEhvb2sgYW5kIEdvd25hbnVzIGhhdmUgcmlzZW4gZmFyIG1vcmUgc2hhcnBseSB0aGFuIGluIFN1bnNldCBQYXJrLiBDdXJyZW50bHksIFJlZCBIb29rIGFuZCBHb3dhbnVzIGFyZSBwb3B1bGFyIG5laWdoYm9yaG9vZHMgZm9yIHJlc3RhdXJhbnRzIGFuZCBmb3IgZ29pbmcgb3V0LiBBcyBjb21wYXJlZCB0byBTdW5zZXQgUGFyaywgdGhlIHJhY2lhbCBtYWtldXAgb2YgUmVkIEhvb2sgYW5kIEdvd2FudXMgaXMgZmFyIHdoaXRlciAoNjAuOSUgYW5kIDQ2JSByZXNwZWN0aXZlbHkpIGluIGFkZGl0aW9uIHRvIGJlaW5nIG1vcmUgYWZmbHVlbnQuIEFkZGl0aW9uYWxseSwgU3Vuc2V0IFBhcmsgaXMgYSBsaXR0bGUgZnVydGhlciBhd2F5IGZyb20gTWFuaGF0dGFuIGFuZCBvdGhlciBtb3JlIGdlbnRyaWZpZWQgc2VjdGlvbnMgb2YgQnJvb2tseW4sIHdoaWNoIG1heSBhbHNvIGV4cGxhaW4gd2h5IHRoZSB5b3VuZyB1cmJhbiBwcm9mZXNzaW9uYWxzIHdobyBtYWtlIHVwIHRoZSBjdXJyZW50IGdlbnRyaWZ5aW5nIGNsYXNzIG1heSBiZSBsZXNzIGxpa2VseSB0byBzZXR0bGUgdGhlcmUuIAoKIyMjIyMjIFRoZSBsYXN0ICB2YXJpYWJsZSBJIGxvb2tlZCBhdCBpdCBpcyBob3cgcGVvcGxlJ3MgY29tbXV0ZXMgaGF2ZSBjaGFuZ2VkIG92ZXIgdGltZS4gUHJldmlvdXNseSwgaW5kdXN0cmlhbCB3b3JrZXJzIHdvdWxkIGxpdmUgY2xvc2UgdG8gdGhlaXIgd29ya3BsYWNlcywgaW4gdGhlIHBvc3QtaW5kdXN0cmlhbCBlcmEgdGhlcmUgaXMgb2Z0ZW4gYSBncmVhdGVyIHBoeXNpY2FsIHNlcGVyYXRpb24gYmV0d2VlbiBvbmVzIGhvbWUgYW5kIHdvcmtwbGFjZSwgZXNwZWNpYWxseSBhcyByZW50cyBoYXZlIGRyYW1hdGljYWxseSBpbmNyZWFzZWQgaW4gZG93bnRvd24gYnVzaW5lc3MgZGlzdHJpY3RzLgoKIyMjIyMjIExvb2tpbmcgYXQgaG93IHRoaXMgdmFyaWFibGUgY2hhbmdlZCBvdmVyIHRpbWUgbWF5IGNvbXBsZW1lbnQgdGhlIGRhdGEgb2YgZGVjbGluaW5nIGluZHVzdHJpYWwgZW1wbG95bWVudCBpbiB0aGVzZSBuZWlnaGJvcmhvb2RzLgoKYGBge3J9CgpyYXd0cmF2ZWx0aW1lIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gInRyYWN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIHRhYmxlID0gIkIwODAxMiIsCiAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gMjAxMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9ICJOWSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgY291bnR5ID0gIktpbmdzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IEZBTFNFKQphY3M1dmFyaWFibGUgPC0gbG9hZF92YXJpYWJsZXMoMjAxMCwgImFjczUiLCBjYWNoZSA9IEZBTFNFKQoKCnRyYXZlbHRpbWUgPC0gcmF3dHJhdmVsdGltZSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHZhcmlhYmxlLCB2YWx1ZXNfZnJvbSA9IGMoZXN0aW1hdGUsIG1vZSkpICU+JSAKICBzZWxlY3QoR0VPSUQsIE5BTUUsIGVzdGltYXRlX0IwODAxMl8wMDEsIGVzdGltYXRlX0IwODAxMl8wMDIsIGVzdGltYXRlX0IwODAxMl8wMDMsIGVzdGltYXRlX0IwODAxMl8wMDQsIGVzdGltYXRlX0IwODAxMl8wMDUsIGVzdGltYXRlX0IwODAxMl8wMDYsIGVzdGltYXRlX0IwODAxMl8wMDcsIGVzdGltYXRlX0IwODAxMl8wMDgsIGVzdGltYXRlX0IwODAxMl8wMDksIGVzdGltYXRlX0IwODAxMl8wMTAsIGVzdGltYXRlX0IwODAxMl8wMTEsIGVzdGltYXRlX0IwODAxMl8wMTIsIGVzdGltYXRlX0IwODAxMl8wMTMpICU+JSAKICByZW5hbWUodG90YWx3b3JrZXJwb3AgPSBlc3RpbWF0ZV9CMDgwMTJfMDAxLAogICAgICAgICBsZXNzdGhhbjUgPSBlc3RpbWF0ZV9CMDgwMTJfMDAyLCAKICAgICAgICAgZml2ZXRvbmluZSA9IGVzdGltYXRlX0IwODAxMl8wMDMsIAogICAgICAgICB0ZW5fZm91cnRlZW4gPSBlc3RpbWF0ZV9CMDgwMTJfMDA0LAogICAgICAgICBmaWZ0ZWVuX25pbmV0ZWVuID0gZXN0aW1hdGVfQjA4MDEyXzAwNSwgCiAgICAgICAgIHR3ZW50eV90d2VuZm91ciA9IGVzdGltYXRlX0IwODAxMl8wMDYsIAogICAgICAgICB0d2VuZml2ZV90d2VubmluZSA9IGVzdGltYXRlX0IwODAxMl8wMDcsIAogICAgICAgICB0aGlydHlfdGhpcmZvdXIgPSBlc3RpbWF0ZV9CMDgwMTJfMDA4LCAKICAgICAgICAgdGhpcmZpdmVfdGhpcm5pbmUgPSBlc3RpbWF0ZV9CMDgwMTJfMDA5LAogICAgICAgICBmb3J0eV9mb3VydGZvdXIgPSBlc3RpbWF0ZV9CMDgwMTJfMDEwLAogICAgICAgICBmb3VydGZpdmVfZmlmdG5pbmUgPSBlc3RpbWF0ZV9CMDgwMTJfMDExLAogICAgICAgICBzaXh0X2VpZ2h0bmluZSA9IGVzdGltYXRlX0IwODAxMl8wMTIsCiAgICAgICAgIG5pbmV0eV9wbHVzID0gZXN0aW1hdGVfQjA4MDEyXzAxMykgJT4lIAogIG11dGF0ZShsZXNzdGhhbjMwID0gKGxlc3N0aGFuNSArIGZpdmV0b25pbmUgKyB0ZW5fZm91cnRlZW4gKyBmaWZ0ZWVuX25pbmV0ZWVuICsgdHdlbnR5X3R3ZW5mb3VyICsgdHdlbmZpdmVfdHdlbm5pbmUpLAogICAgICAgICB0aGlydHlfZm91cmZvdXIgPSAodGhpcnR5X3RoaXJmb3VyICsgdGhpcmZpdmVfdGhpcm5pbmUgKyBmb3J0eV9mb3VydGZvdXIpLAogICAgICAgICBmb3VydGZpdmVwbHVlID0gKGZvdXJ0Zml2ZV9maWZ0bmluZSArIHNpeHRfZWlnaHRuaW5lICsgbmluZXR5X3BsdXMpKSAlPiUgCiAgbXV0YXRlKHBlcmxlc3N0aGFuMzBfMTAgPSAobGVzc3RoYW4zMC90b3RhbHdvcmtlcnBvcCksCiAgICAgICAgIHBlcjMwNF8xMCA9ICh0aGlydHlfZm91cmZvdXIvdG90YWx3b3JrZXJwb3ApLCAKICAgICAgICAgcGVyNDVfMTAgPSAoZm91cnRmaXZlcGx1ZS90b3RhbHdvcmtlcnBvcCkpCgojSW1wb3J0aW5nIGhpc3RvcmljYWwgdHJhdmVsIHRpbWUgZGF0YSBmcm9tIE5IR0lTCnRyYXZlbHRpbWU4MDkwIDwtIHJlYWRfY3N2KCJkYXRhL3Jhdy90cmF2ZWx0aW1lL25oZ2lzMDAxN190c19ub21pbmFsX3RyYWN0LmNzdiIpICU+JSAKICBmaWx0ZXIoU1RBVEUgPT0gIk5ldyBZb3JrIiwKICAgICAgICAgQ09VTlRZID09ICJLaW5ncyBDb3VudHkiKQoKdHJhdmVsdGltZTgwOTBwcm9jIDwtIHRyYXZlbHRpbWU4MDkwICU+JSAgCiAgbXV0YXRlKGxlc3N0aGFuMzBfODAgPSAoQzUwQUExOTgwICsgQzUwQUIxOTgwICsgQzUwQUMxOTgwICsgQzUwQUQxOTgwICsgQzUwQUUxOTgwKSwKICAgICAgICAgdGhpcnR5X2ZvdXJ0eWZvdXJfODAgPSBDNTBBRjE5ODAsIAogICAgICAgICBmb3VydHlmaXZlcGx1ZV84MCA9IChDNTBBRzE5ODAgKyBDNTBBSDE5ODApKSAlPiUKICBtdXRhdGUodG90YWx3b3JrZXJwb3BfODAgPSAoQzUwQUExOTgwICsgQzUwQUIxOTgwICsgQzUwQUMxOTgwICsgQzUwQUQxOTgwICsgQzUwQUUxOTgwICsgQzUwQUYxOTgwICsgQzUwQUcxOTgwICsgQzUwQUgxOTgwKSkgJT4lIAogIG11dGF0ZShsZXNzdGhhbjMwXzkwID0gKEM1MEFBMTk5MCArIEM1MEFCMTk5MCArIEM1MEFDMTk5MCArIEM1MEFEMTk5MCArIEM1MEFFMTk5MCksCiAgICAgICAgIHRoaXJ0eV9mb3VydHlmb3VyXzkwID0gQzUwQUYxOTkwLAogICAgICAgICBmb3VydHlmaXZlcGx1ZV85MCA9IChDNTBBRzE5OTAgKyBDNTBBSDE5OTApKSAlPiUgCiAgbXV0YXRlKHRvdGFsd29ya2VycG9wXzkwID0gKEM1MEFBMTk5MCArIEM1MEFCMTk5MCArIEM1MEFDMTk5MCArIEM1MEFEMTk5MCArIEM1MEFFMTk5MCArIEM1MEFGMTk5MCArIEM1MEFHMTk5MCArIEM1MEFIMTk5MCkpICU+JSAKICBtdXRhdGUobGVzc3RoYW4zMF8wMCA9IChDNTBBRzIwMDAgKyBDNTBBSDIwMDApLAogICAgICAgICB0aGlydHlfZm91cnR5Zm91cl8wMCA9IEM1MEFGMjAwMCwKICAgICAgICAgZm91cnR5Zml2ZXBsdWVfMDAgPSAoQzUwQUcyMDAwICsgQzUwQUgyMDAwKSkgJT4lIAogIG11dGF0ZSh0b3RhbHdvcmtlcnBvcF8wMCA9IChDNTBBQTIwMDAgKyBDNTBBQjIwMDAgKyBDNTBBQzIwMDAgKyBDNTBBRDIwMDAgKyBDNTBBRTIwMDAgKyBDNTBBRjIwMDAgKyBDNTBBRzIwMDAgKyBDNTBBSDIwMDApKQogIApwZXJjdHJhdmVsdGltZTgwOTAwMCA8LSB0cmF2ZWx0aW1lODA5MHByb2MgJT4lIAogIHNlbGVjdChOQU1FMjAxMiwgbGVzc3RoYW4zMF84MCwgbGVzc3RoYW4zMF85MCwgbGVzc3RoYW4zMF8wMCwgdG90YWx3b3JrZXJwb3BfODAsIHRvdGFsd29ya2VycG9wXzkwLCB0b3RhbHdvcmtlcnBvcF8wMCwgdGhpcnR5X2ZvdXJ0eWZvdXJfODAsIHRoaXJ0eV9mb3VydHlmb3VyXzkwLCB0aGlydHlfZm91cnR5Zm91cl8wMCwgZm91cnR5Zml2ZXBsdWVfODAsIGZvdXJ0eWZpdmVwbHVlXzkwLCBmb3VydHlmaXZlcGx1ZV8wMCkgJT4lIAogIG11dGF0ZShwZXJsZXNzdGhhbjMwXzgwID0gKGxlc3N0aGFuMzBfODAvdG90YWx3b3JrZXJwb3BfODApLAogICAgICAgICBwZXIzMDRfODAgPSAodGhpcnR5X2ZvdXJ0eWZvdXJfODAvdG90YWx3b3JrZXJwb3BfODApLAogICAgICAgICBwZXI0NV84MCA9IChmb3VydHlmaXZlcGx1ZV84MC90b3RhbHdvcmtlcnBvcF84MCkpICU+JSAKICBtdXRhdGUocGVybGVzc3RoYW4zMF85MCA9IChsZXNzdGhhbjMwXzkwL3RvdGFsd29ya2VycG9wXzkwKSwKICAgICAgICAgcGVyMzA0XzkwID0gKHRoaXJ0eV9mb3VydHlmb3VyXzkwL3RvdGFsd29ya2VycG9wXzkwKSwKICAgICAgICAgcGVyNDVfOTAgPSAoZm91cnR5Zml2ZXBsdWVfOTAvdG90YWx3b3JrZXJwb3BfOTApKSAlPiUgCiAgbXV0YXRlKHBlcmxlc3N0aGFuMzBfMDAgPSAobGVzc3RoYW4zMF8wMC90b3RhbHdvcmtlcnBvcF8wMCksCiAgICAgICAgIHBlcjMwNF8wMCA9ICh0aGlydHlfZm91cnR5Zm91cl8wMC90b3RhbHdvcmtlcnBvcF8wMCksCiAgICAgICAgIHBlcjQ1XzAwID0gKGZvdXJ0eWZpdmVwbHVlXzAwL3RvdGFsd29ya2VycG9wXzAwKSkgCgp0cmF2ZWx0aW1lODA5MDAwIDwtIHBlcmN0cmF2ZWx0aW1lODA5MDAwICU+JSAKICBzZWxlY3QoTkFNRTIwMTIsIHBlcmxlc3N0aGFuMzBfODAsIHBlcjMwNF84MCwgcGVyNDVfODAsIHBlcmxlc3N0aGFuMzBfOTAsIHBlcjMwNF85MCwgcGVyNDVfOTAsIHBlcmxlc3N0aGFuMzBfMDAsIHBlcjMwNF8wMCwgcGVyNDVfMDApICU+JSAKICBkcm9wX25hKCkgJT4lIAogIHJlbmFtZShOQU1FID0gTkFNRTIwMTIpCgp0cmF2ZWx0aW1leWVhcnMgPC0gdHJhdmVsdGltZSAlPiUgCiAgc2VsZWN0KE5BTUUsIHBlcmxlc3N0aGFuMzBfMTAsIHBlcjMwNF8xMCwgcGVyNDVfMTApICU+JSAKICBsZWZ0X2pvaW4odHJhdmVsdGltZTgwOTAwMCwgYnkgPSAiTkFNRSIpICU+JSAKICBkcm9wX25hKCkgCgp0cmF2ZWx0aW1lc2hwIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gInRyYWN0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcyA9ICJCMDgwMTJfMDAxIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSAyMDEwLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlID0gIk5ZIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHkgPSAiS2luZ3MiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gVFJVRSkKCnRyYXZlbHRpbWV5ZWFyc2ZpbmFsIDwtIHRyYXZlbHRpbWVzaHAgJT4lIAogIHNlbGVjdChOQU1FLCBnZW9tZXRyeSkgJT4lIAogIHJpZ2h0X2pvaW4odHJhdmVsdGltZXllYXJzLCBieSA9ICJOQU1FIikgJT4lIAogIHN0X3RyYW5zZm9ybSgyMjYzKSAlPiUgCiAgc3Rfam9pbihuYWJlcywgam9pbiA9IHN0X2ludGVyc2VjdHMpICU+JSAKICBkcm9wX25hKCkKCnRyYXZlbHRpbWV5ZWFyc2ZpbmFsUExPVCA8LSBzdF9kcm9wX2dlb21ldHJ5KHRyYXZlbHRpbWV5ZWFyc2ZpbmFsKSAlPiUgCiAgc2VsZWN0KE5BTUUsIE5UQU5hbWUsIHBlcmxlc3N0aGFuMzBfODAsIHBlcjMwNF84MCwgcGVyNDVfODAsIHBlcmxlc3N0aGFuMzBfOTAsIHBlcjMwNF85MCwgcGVyNDVfOTAsIHBlcmxlc3N0aGFuMzBfMDAsIHBlcjMwNF8wMCwgcGVyNDVfMDAsIHBlcmxlc3N0aGFuMzBfMTAsIHBlcjMwNF8xMCwgcGVyNDVfMTApICU+JSAKICByZW5hbWUoJzAyOS4yMDEwJyA9IHBlcmxlc3N0aGFuMzBfMTAsCiAgICAgICAgICcwMjkuMjAwMCcgPSBwZXJsZXNzdGhhbjMwXzAwLAogICAgICAgICAnMDI5LjE5OTAnID0gcGVybGVzc3RoYW4zMF85MCwKICAgICAgICAgJzAyOS4xOTgwJyA9IHBlcmxlc3N0aGFuMzBfODAsCiAgICAgICAgICczMDQ0LjIwMTAnID0gcGVyMzA0XzEwLAogICAgICAgICAnMzA0NC4yMDAwJyA9IHBlcjMwNF8wMCwKICAgICAgICAgJzMwNDQuMTk5MCcgPSBwZXIzMDRfOTAsCiAgICAgICAgICczMDQ0LjE5ODAnID0gcGVyMzA0XzgwLAogICAgICAgICAnNDUwMC4yMDEwJyA9IHBlcjQ1XzEwLAogICAgICAgICAnNDUwMC4yMDAwJyA9IHBlcjQ1XzAwLAogICAgICAgICAnNDUwMC4xOTkwJyA9IHBlcjQ1XzkwLAogICAgICAgICAnNDUwMC4xOTgwJyA9IHBlcjQ1XzgwKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1jKE5BTUUsIE5UQU5hbWUpLCBuYW1lc190byA9ICJ5ZWFyIikgJT4lIAogIHNlcGFyYXRlKHllYXIsIGMoJ1RpbWUnLCAnWWVhcicpKSAlPiUgCiAgYXJyYW5nZShUaW1lKQoKY29tbXV0ZWxpbmUgPC0gZ2dwbG90KGFlcyh4ID0gWWVhciwgeSA9IHZhbHVlKSwgZGF0YSA9IHRyYXZlbHRpbWV5ZWFyc2ZpbmFsUExPVCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiQ29tbXV0ZSBUaW1lIiwgbGFiZWxzID0gYygiPCAzMCBNaW51dGVzIiwgIjMwLTQ0IG1pbnV0ZXMiLCAiNDUrIG1pbnV0ZXMiKSkgKwogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJQZXJjZW50YWdlIG9mIFdvcmtpbmcgUG9wdWxhdGlvbiAoJSkiLCB0aXRsZSA9ICJDb21tdXRpbmcgVGltZXMgaW4gV2VzdCBCcm9va2x5biAoMTk4MC0yMDEwKSIsIGNhcHRpb24gPSAiU291cmNlczogVVMgQ2Vuc3VzIGFuZCBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IikgKwogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoZ3JvdXAgPSBUaW1lLCBjb2xvciA9IFRpbWUpLCBtZXRob2QgPSAnbG0nLCBhbHBoYSA9IC4yLCBmb3JtdWxhID0gIHkgfngpICsgCiAgZmFjZXRfd3JhcCh+IE5UQU5hbWUsIG5yb3c9IDIpCgpjb21tdXRlYmFyIDwtIGdncGxvdChkYXRhID0gc3Vic2V0KHRyYXZlbHRpbWV5ZWFyc2ZpbmFsUExPVCksIG1hcHBpbmcgPSBhZXMoeD0gWWVhciwgeSA9IHZhbHVlLCBmaWxsID0gVGltZSkpICsKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiUGVyY2VudGFnZSBvZiBXb3JraW5nIFBvcHVsYXRpb24gKCUpIiwgdGl0bGUgPSAiQ29tbXV0aW5nIFRpbWVzIGluIFdlc3QgQnJvb2tseW4gKDE5ODAtMjAxMCkiLCBjYXB0aW9uID0gIlNvdXJjZXM6IFVTIENlbnN1cyBhbmQgQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSIpICsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiQ29tbXV0ZSBUaW1lIiwgbGFiZWxzID0gYygiPCAzMCBNaW51dGVzIiwgIjMwLTQ0IG1pbnV0ZXMiLCAiNDUrIG1pbnV0ZXMiKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgIAoKY29tbXV0ZWJhcgpnZ3Bsb3RseShjb21tdXRlbGluZSkKYGBgCgojIyBPYnNlcnZhdGlvbnM6IApMb29raW5nIGF0IHRoZSBjaGFuZ2UgaW4gdGhlc2UgZm91ciBhcmVhcywgdGhlIG1vc3QgZHJhbWF0aWMgc2hpZnQgaXMgaW4gdGhlIHBvcHVsYXRpb24gc2hhcmUgd2l0aCBhIGxlc3MgdGhhbiAzMCBtaW51dGUgY29tbXV0ZSBpbiB0aGUgUmVkIEhvb2sgYXJlYSAoZnJvbSBvdmVyIDQwJSBpbiAxOTgwIHRvIH4zMiUgYnkgMjAxMCkgVGhpcyBjb3VsZCBiZSBkaXJlY3RseSBhdHRyaWJ1dGVkIHRvIHRoZSBsb3NzIG9mIGluZHVzdHJpYWwgZW1wbG95bWVudCBhcyBmYWN0b3JpZXMgbGVmdCB0aGUgYXJlYSBpbiB0aGUgbGF0dGVyIGhhbGYgb2YgdGhlIDIwdGggY2VudHVyeS4gTG9uZ2VyIGNvbW11dGVzIHJvc2UgaW4gY29uanVuY3Rpb24gd2l0aCB0aGlzIGZhbGwuIFRoZSBHb3dhbnVzIGFyZWEgc2hvd3MgYSBzaW1pbGFyIHRyZW5kLCBidXQgaXQgaXMgbGVzcyBwcm9ub3VuY2VkLiBTdW5zZXQgUGFyayBzZWVtcyB0byBoYXZlIGFsd2F5cyBoYWQgYSBoaWdoZXIgc2hhcmUgb2YgbG9uZ2VyIHRoYW4gNDUgbWludXRlIGNvbW11dGVzLCB0aGlzIG1heSBiZSBkdWUgdG8gaXRzIGluZHVzdHJpYWwgbmF0dXJlIGRldm9sdmluZyBtb3JlIHF1aWNrbHkgdGhhbiB0aGUgb3RoZXIgbmVpZ2hib3Job29kcywgYXMgdGhlIEJyb29rbHluIEFybXkgVGVybWluYWwsIGl0cyBtYWluIGluZHVzdHJpYWwgaHViLCBsYXJnZWx5IHdlbnQgaW50byBkaXN1c2UgYWZ0ZXIgV29ybGQgV2FyIElJLiBJdCBpcyBpbnRlcmVzdGluZyB0aGF0IHRoZSBwb3B1bGF0aW9uIHNoYXJlIHdpdGggc2hvcnRlciBjb21tdXRlcyBoYXMgcmVtYWluZWQgc29tZXdoYXQgc3RhZ25hbnQuIEkgc3BlY3VsYXRlIHRoYXQgbWF5IGJlIGluIHBhcnQgZHVlIHRvIHRoZSBsYXJnZSBpbW1pZ3JhbnQgcG9wdWxhdGlvbiB3aG8gb3duIGFuZCB3b3JrIGF0IGxvY2FsIGJ1c2luZXNzZXMuCgoKIyBDb25jbHVzaW9uIGFuZCBOZXh0IFN0ZXBzOgoKVGhpcyByZXNlYXJjaCBwcm9qZWN0IGRlbW9uc3RyYXRlZCB0aGUgZHJhbWF0aWMgZGVzdHJ1Y3Rpb24gb2YgTmV3IFlvcmsgQ2l0eSdzIGluZHVzdHJpYWwgbmF0dXJlIG92ZXIgdGhlIHNlY29uZCBoYWxmIG9mIHRoZSAyMHRoIGNlbnR1cnkuIEl0IG1hcmtzIGhvdyB0aGUgaW5kdXN0cmlhbCBuYXR1cmUgb2Ygc3BlY2lmaWMgbmVpZ2hib3Job29kcywgd2hvIGFyZSBjdXJyZW50bHkgdW5kZXJnb2luZyBkcmFtYXRpYyB0cmFuc2Zvcm1hdGlvbiwgY2FuIHN0aWxsIHBlcnNpc3QgaW4gZGVtb2dyYXBoaWMgZGF0YS4gCgpGb3IgbmV4dCBzdGVwcyBpdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBkaWcgZXZlbiBkZWVwZXIgaW50byB0aGVzZSB0aHJlZSBuZWlnaGJvcmhvb2RzLCBmdXJ0aGVyIGxvb2tpbmcgYXQgZWNvbm9taWMgYW5kIGRlbW9ncmFwaGljIGRhdGEsIHRvIGRpZyBvdXQgdGhlIGNvbXBsZXggY2hhcmFjdGVyIG9mIHRoZWlyIGNoYW5nZSBvdmVyIHRpbWUuIFpvbmluZyBtYXBzIHdvdWxkIHNlcnZlIGFzIGEgdXNlZnVsIHJlc291cmNlIHRvIG1hcmsgZXhhY3RseSB3aGVuIGZhY3RvcmllcyBhbmQgd2FyZWhvdXNlcyBtb3ZlZCBvdXQgb2YgdGhlc2UgYXJlYXMuIAoKQW5vdGhlciBwcm9qZWN0IGlkZWEgd291bGQgYmUgdG8gbG9vayBhdCB0aGUgYWN0dWFsIHBoeXNpY2FsIGluZHVzdHJpYWwgc3RydWN0dXJlcyB0aGF0IGhhdmUgbGluZ2VyZWQgaW4gdGhlIG5laWdoYm9yaG9vZHMuIFByb2plY3RzIGxpa2UgdGhlIEhpZ2hsaW5lIGluIE1hbmhhdHRhbiBzaG93IGhvdyBhZGFwdGl2ZSByZXVzZSBjYW4gYW5jaG9yIGEgbmVpZ2hib3Job29kJ3MgaW5kdXN0cmlhbCBwYXN0IGluIHRoZSBwcmVzZW50LCB3aGlsZSBleHBvbmVudGlhbGx5IGJvb3N0aW5nIG5lYXJieSByZWFsIGVzdGF0ZSB2YWx1ZXMuIFRoZSByZWRldmVsb3BtZW50IG9mIHBvc3QtaW5kdXN0cmlhbCBuZWlnaGJvcmhvb2RzIGhhcyBiZWVuIGEgcHJldmFsZW50IHRoZW1lIGluIHJlY2VudCB1cmJhbmlzbS4gCgpBbm90aGVyIHJlbWFpbmluZyBxdWVzdGlvbiBpcywgd2hlcmUgZGlkIGluZHVzdHJpYWwgd29ya2VycyBnbz8gVGhlcmUgYXJlIHNvbWUgbGluZ2VyaW5nIGluZHVzdHJpYWwgcmVtbmFudHMgaW4gUXVlZW5zIGl0IHNlZW1zLCBidXQgaXQgd291bGQgYmUgaW50ZXJlc3RpbmcgdG8gbW92ZSB0aGlzIGFuYWx5c2lzIHRvIE5ldyBKZXJzZXksIGZvciBpbnN0YW5jZSwgd2hlcmUgbWFueSBmYWN0b3JpZXMgZXZlbnR1YWxseSBtb3ZlZCB0by4K