Pansy Schulman, DUE Methods I, 2021

Project Statement and Background

For this project, I wanted to answer the question: How did deindustrialization affect New York demographically and geographically? How do once-industrial areas reflect their history in terms of demographics, income, and geographic makeup?

The purpose of this research is to show how an economic shift manifested itself in New York’s landscape from 1970 to today. I looked at three geographic levels in my data analysis: first, for the entire city, or “place” in census definition, next for each individual county in the city, before finally zooming in on the neighborhoods of Red Hook, Sunset Park, and Gowanus in Brooklyn, alll of which were once major industry hubs and have seen major economic and demographic change over this time.

Red Hook and Sunset Park are on the western waterfront of Brooklyn, and thus historically their ports attracted an influx of manufacturing and industrial businesses in the late 19th and 20th century. All three of these neighborhoods were hubs for Brooklyn’s maritime shipping and industrial activites; they have hosted cement works, paint factories, tanneries, coal yards, warehouses, mills, and textile production amongst many other industrial sites in their history. The Gowanus Canal, which runs through the neighborhood, was used to conduit building materials to and from various factories in the area. Sunset Park was home to the Brooklyn Army Terminal, which was a major manufacturing hub for army supplies, as well as many other piers and factories. Immigrants, who made up a large part of the city’s industrial workforce, settled in these areas of Brooklyn with their families.

Manufacturing employment in New York City peaked in the late 1940s. In 1953, manufacturing accounted for 40% of all jobs, by 1994 this number dipped to 17%. New York City lost more than 700,000 manufacturing jobs between 1953 and 1995. This economic change was guided by city policy as well as larger global and national economic trends.

An industrial map of New York City from 1919, courtesy of the New York Public Library.

Rezoning industrial areas began in the 1950s and continued and escalated through the end of the 20th century to today. “Planned shrinkage” in the 1970s cut off municipal resources to poor and working-class areas and factories moved out of the city. Financial and real estate operations toppled the once-industrial city, making New York a global financial hub instead.

I chose this topic because I was interested in how the evolution of a neighborhood and city’s working class was involved in gentrification and other processes that have changed the demographic makeup of New York city communities over the past 50 years.

For the purposes of this project, I chose to incorporate not only those working in manufacturing, but in industry-related occupations, such as warehousing, wholesale trade, and trucking, so as to encompass all the people impacted by this economic shift.

The first variable I looked at was the percentage of manufacturing jobs in relation to the total working population. Generally, I used census data from the National Historical Geographical Information System for data from before 2010, and tidycensus to pull data from the 5-year American Community Survey for the most recent data.

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.

Conclusion and Next Steps:

This research project demonstrated the dramatic destruction of New York City’s industrial nature over the second half of the 20th century. It marks how the industrial nature of specific neighborhoods, who are currently undergoing dramatic transformation, can still persist in demographic data.

For next steps it would be interesting to dig even deeper into these three neighborhoods, further looking at economic and demographic data, to dig out the complex character of their change over time. Zoning maps would serve as a useful resource to mark exactly when factories and warehouses moved out of these areas.

Another project idea would be to look at the actual physical industrial structures that have lingered in the neighborhoods. Projects like the Highline in Manhattan show how adaptive reuse can anchor a neighborhood’s industrial past in the present, while exponentially boosting nearby real estate values. The redevelopment of post-industrial neighborhoods has been a prevalent theme in recent urbanism.

Another remaining question is, where did industrial workers go? There are some lingering industrial remnants in Queens it seems, but it would be interesting to move this analysis to New Jersey, for instance, where many factories eventually moved to.

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