Version 1.0 | First Created Sep 15, 2023 | Updated Sep 20, 2023

Keywords: Multiple Ring Buffer, Indicators, Transit Oriented Development, Gentrification, Boston

Introduction

In city planning, transit-oriented development (TOD) is a type of urban development practice that aims to maximize the amount of residential, business, and leisure space within walking distance of public transport. TOD offers a range of benefits that all contribute to creating a more vibrant, sustainable, and inclusive communities. For example, a community with a strong and dependable transit system and streetscaping elements can discourage vehicle dependence and congestion. This further leads to reduction in greenhouse gas emissions per capita and a smaller carbon footprint. In addition, as cities become more walkable, TOD can stimulate economic growth by attracting business and creating jobs. This includes bringing in mixed-use developments, such as retail, dining, and entertainment options within easy reach of resident. Moreover, TOD increases property values in surrounding areas, which is particularly important for real-estate developers and governments.

Transit oriented development has been a large part of Boston’s growth. The Boston Redevelopment Authority has been undertaking a TOD initiative to build on and reinforce Boston’s existing and emerging neighborhood centers. Their goal is to connect all neighborhood centers into a comprehensive transit network and to support that network with appropriate development patterns near these neighborhood centers. To contribute to theri work, this report conducts a comprehensive analysis of existing TOD patterns in Boston. Through visualizing temporal changes in demographic, social, and economic characteristics of neighborhoods across Boston, examining the spatial distribution of transit stops, and comparing the differences of development patterns between TOD and Non-TOD tracts, we aim to address the following questions:

  1. Who is living around transit stations in Boston?

  2. How does the social, economic, and demographic characteristics of households living near transit stations in Boston change over time?

  3. Are Bostonians willing to pay a premium to live in transit-rich areas? If residents value these locations, officials should consider changing the zoning code to allow increased density around transit.

  4. How can planners in Boston be more strategic about developments in transit-rich neighborhoods in order to satisfy the needs of those who favor transit proximity?

The GitHub repository for this report is available here.

Data Manipulation

Before we begin our analysis and visualization, there are a couple of data cleaning and manipulation steps that we need to perform as well as some analytical decisions to specify.

ACS Data

We are using the America Community Survey (5-year estimate) for year 2010 and 2019 in this report. We chose the ACS data because it collects detailed demographic, social, economic, and housing data on a wide range of topics, providing a more comprehensive view of a community’s characteristics in Boston. We chose 2019 as the end year because COVID-19 since 2020 has drastically changed people’s work and travel behaviors: the widespread adoption of remote work during the pandemic would certainly led to decline in the demand for office space and the need for transit-oriented office developments. In order to better understand if there’s a difference between individuals living in TOD and Non-TOD neighborhood over time, we chose the following ACS variables, categorized into demographic, social, and economic characteristics, for our analysis.

Variable Name ACS Name
Demographic
Total Population B02001_001
White Population B02001_002
Black Population B02001_003
Asian Population B02001_005
Latinx Population B03002_012
Male 70-74 B01001_022
Male 75-79 B01001_023
Male 80-84 B01001_024
Male over 85 B01001_025
Female 70-74 B01001_046
Female 75-79 B01001_047
Female 80-84 B01001_048
Female over 85 B01001_049
Non-US Citizen B05001_006
Economic
Median Household Income B19013_001
Median Rent B25058_001
Population under Poverty B06012_002
Social
Bachelor Degree B06009_005
Graduate Degree B06009_006
Renter Occupied Household B25026_009
Population without Vehicle B08014_002

Based on these ACS variables, we further computed the following variables:

  • PctMinority : percentage of minority population, where minority here refers to anyone who is Asian, Latinx, or Black.

  • PctAging: percentage of aging population, where aging here refers to anyone who is over 70 years old.

  • PctForeign: percentage of population who are non-US citizens.

  • PctBachelors: percentage of population with at least a Bachelor’s degree.

  • PctRenter: percentage of renter occupied households.

  • PctNoCar:percentage of population without a vehicle.

  • PctPoverty: poverty rate.

The following code gives an example of the data cleaning steps we performed using 2010 ACS data, where we downloaded the ACS data, reprojected the data, removed areas outside of Boston, renamed the columns, performed additional data manipulations, and discarded unnecessary variables.

boston10 <- 
  get_acs(geography = "tract", variables = acs_var, 
          year=2010, state='MA', county=025, geometry=T, output="wide") %>% 
  st_transform('EPSG:26986') %>% 
  filter(!(GEOID %in% remove)) %>% 
  rename(TotalPop = B02001_001E, 
         Whites = B02001_002E,
         African_Americans = B02001_003E,
         Asians = B02001_005E,
         Latinx = B03002_012E,
         M70_74 = B01001_022E,
         M75_79 = B01001_023E,
         M80_85 = B01001_024E,
         M85 = B01001_025E,
         FM70_74 = B01001_046E,
         FM75_79 = B01001_047E,
         FM80_85 = B01001_048E,
         FM85 = B01001_049E,
         MedHHInc = B19013_001E, 
         MedRent = B25058_001E,
         TotalPoverty = B06012_002E,
         College = B06009_005E,
         Graduate = B06009_006E,
         NoCar = B08014_002E,
         Renter = B25026_009E,
         Foreigner = B05001_006E
         ) %>% 
  dplyr::select(-starts_with("B"))%>%
  mutate(pctWhite = ifelse(TotalPop > 0, Whites / TotalPop, 0),
         pctMinority = ifelse(TotalPop > 0, (African_Americans + Asians + Latinx ) / TotalPop, 0),
         pctAging = ifelse(TotalPop > 0, (M70_74 + M75_79 + M80_85 + M85 + FM70_74 + FM75_79 + FM80_85 + FM85 ) / TotalPop, 0),
         pctBachelors = ifelse(TotalPop > 0, ((College + Graduate) / TotalPop), 0),
         pctPoverty = ifelse(TotalPop > 0, TotalPoverty / TotalPop, 0),
         pctNoCar = ifelse(TotalPop > 0, NoCar / TotalPop, 0),
         pctRenter = ifelse(TotalPop > 0, Renter / TotalPop, 0),
         pctForeigner = ifelse(TotalPop > 0, Foreigner / TotalPop, 0),
         year = "2010") %>% 
  dplyr::select(-Whites,-African_Americans, -Asians, -Latinx, -M70_74, -M75_79, -M80_85, -M85, -FM70_74, -FM75_79, -FM80_85, -FM85, -College, -Graduate, -TotalPoverty, -NoCar, -Renter, -Foreigner)

Note: Boston city is part of the larger Suffolk county in Massachusetts, which also includes the city of Chelsea, Revere, and Winthrop. To limit our analysis within Boston, we removed all areas outside Boston. The map below shows Boston relative to other cities in Suffolk county.

ggplot() + 
  geom_sf(data=st_union(Suffolk), fill= "#D3D3D3", color = "white", size = 2) +
  geom_sf(data=st_union(boston10), fill= "#bd7ebe", color = "white", size = 2) +
  labs(title = "Boston City in Suffolk County",
       caption = "Data: American Community Survey 2010 and 2019",
       color = "Boston") +
  theme_light() +
  theme(plot.title = element_text(size = 12, face = "bold")) +
  annotate(geom = "text",x = -71.10,y = 42.3, size = 4, label = "Boston",color = "white") +
  annotate(geom = "text",x = -71.04,y = 42.40, size = 3, label = "Chelsea",color = "black") +
  annotate(geom = "text",x = -71.01,y = 42.42, size = 3, label = "Revere",color = "black") +
  annotate(geom = "text",x = -70.97,y = 42.38, size = 3, label = "Winthrop",color = "black") 

Now, we repeat the same process to obtain the 2019 ACS data and combine it with the 2010 data.

boston19 <- 
  get_acs(geography = "tract", variables = acs_var, 
          year=2019, state='MA', county=025, geometry=T, output="wide") %>% 
  st_transform('EPSG:26986') %>% 
  filter(!(GEOID %in% remove)) %>% 
  rename(TotalPop = B02001_001E, 
         Whites = B02001_002E,
         African_Americans = B02001_003E,
         Asians = B02001_005E,
         Latinx = B03002_012E,
         M70_74 = B01001_022E,
         M75_79 = B01001_023E,
         M80_85 = B01001_024E,
         M85 = B01001_025E,
         FM70_74 = B01001_046E,
         FM75_79 = B01001_047E,
         FM80_85 = B01001_048E,
         FM85 = B01001_049E,
         MedHHInc = B19013_001E, 
         MedRent = B25058_001E,
         TotalPoverty = B06012_002E,
         College = B06009_005E,
         Graduate = B06009_006E,
         NoCar = B08014_002E,
         Renter = B25026_009E,
         Foreigner = B05001_006E
         ) %>% 
  dplyr::select(-starts_with("B")) %>% 
    mutate(pctWhite = ifelse(TotalPop > 0, Whites / TotalPop, 0),
         pctMinority = ifelse(TotalPop > 0, (African_Americans + Asians + Latinx ) / TotalPop, 0),
         pctAging = ifelse(TotalPop > 0, (M70_74 + M75_79 + M80_85 + M85 + FM70_74 + FM75_79 + FM80_85 + FM85 ) / TotalPop, 0),
         pctBachelors = ifelse(TotalPop > 0, ((College + Graduate) / TotalPop), 0),
         pctPoverty = ifelse(TotalPop > 0, TotalPoverty / TotalPop, 0),
         pctNoCar = ifelse(TotalPop > 0, NoCar / TotalPop, 0),
         pctRenter = ifelse(TotalPop > 0, Renter / TotalPop, 0),
         pctForeigner = ifelse(TotalPop > 0, Foreigner / TotalPop, 0),
         year = "2019") %>% 
  dplyr::select(-Whites,-African_Americans, -Asians, -Latinx, -M70_74, -M75_79, -M80_85, -M85, -FM70_74, -FM75_79, -FM80_85, -FM85, -College, -Graduate, -TotalPoverty, -NoCar, -Renter, -Foreigner)

allTracts <- rbind(boston10,boston19)

Transit Data

The Boston transit data is provided by MassGIS, through which we downloaded the raw file and uploaded it to our GitHub repository. To ensure data consistency, we have repojected this layer for it to match with our census data, and have re-categorized transit lines.

boston_stops <- st_read("https://raw.githubusercontent.com/emilyzhou112/MUSA5080-Boston-TOD/main/data/boston_stps.geojson") %>%
  st_transform(st_crs(boston10)) %>% 
  mutate(stops = ifelse(grepl("/", LINE), "OTHER", LINE)) 

The MBTA Rapid Transit layers represent the core subway system lines and stations within the Greater Boston area. There are five subways lines in Boston: Red, Green, Orange, Blue, and Silver, which services many Boston neighborhoods plus parts of Cambridge, Somerville, Revere, Malden, Brookline, Newton, Milton, and Quincy. To limit our scope of analysis within Boston, we have removed subway stations outside of Boston. The map below shows transit stops used in our study as well as those that we have excluded.

MBTA <- st_read("https://raw.githubusercontent.com/emilyzhou112/MUSA5080-Boston-TOD/main/data/MBTA_node.geojson") %>%
  st_transform(st_crs(boston10))

ggplot() + 
  geom_sf(data=st_union(boston10), fill= "#D3D3D3", color = "white", size = 2) +
  geom_sf(data=MBTA, color = "black", size= 1) + 
  geom_sf(data=boston_stops, 
          aes(colour = stops %>% str_to_title()),
          show.legend = "point", size= 1.5) + 
  scale_colour_manual(values = c("#7eb0d5","#b2e061", "#ffb55a", "#ffee65", "#fd7f6f", "#bd7ebe")) +
  labs(title = "Boston MBTA Rapid Transit Stops",
       caption = "Data: MassGIS 2022",
       colour = "Lines") +
  theme_light() +
  theme(plot.title = element_text(size = 12, face = "bold"))

To delineate census tracts that are in close proximity to transit stations, we delineated a half mile area for each transit stations, and compared them to all the centroids (center ponits) of census tracts. If the centroid is located within the half mile area, we categorize that tract as “TOD”; otherwise, this tract is considered “Non-TOD”. An additional data manipulation here is to adjust median rent and median household income for inflation.

stops_buffer <- st_union(st_buffer(boston_stops, 804)) %>% st_sf() 

allTracts.group <- 
  rbind(
    st_centroid(allTracts)[stops_buffer,] %>%
      st_drop_geometry() %>%
      left_join(allTracts) %>%
      st_sf() %>%
      mutate(TOD = "TOD"),
    st_centroid(allTracts)[stops_buffer, op = st_disjoint] %>%
      st_drop_geometry() %>%
      left_join(allTracts) %>%
      st_sf() %>%
      mutate(TOD = "Non-TOD")) %>%
  mutate(MedRent.inf = ifelse(year == "2010", MedRent * 1.17, MedRent)) %>% 
  mutate(MedHHInc.inf = ifelse(year == "2010", MedHHInc * 1.17, MedHHInc)) 

The map below shows the distribution of TOD and Non-TOD tracts in Boston, using the above method.

allTracts.group %>% 
  filter(year == 2010 ) %>% 
  ggplot() + 
  geom_sf(aes(fill = TOD), color = "transparent") +
  scale_fill_manual(values = c("#7eb0d5", "#b2e061")) + 
  geom_sf(data=boston_stops, 
          color = "#fd7f6f", size= 0.8)+
  labs(title = "Transient Oriented Development Tracts",
       subtitle = "Tracts within 0.5 mile of transit stops",
       caption = "Data: American Community Survey 2010 and 2019",
       fill = "Tracts Types") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"))

Data Analysis

Demographic Characteristics

We first looked at the temporal changes in aging population distribution. The map below reveals that the number of populations that are 70 and above increases in Boston overall. Yet, most aging population live in Non-TOD tracts. This pattern is consistent through the years as we can see that TOD tracts are relatively “younger” than Non-TOD tracts. This loosely implies that in Boston, transit-rich neighborhoods are favored by the younger cohort, probably because those people have a higher demand for transit to get to school and work.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=pctAging), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "blue4", name= "Percentage Aging", breaks = c(0, 0.1, 0.2, 0.3))+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
  theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Percentage of Aging Population in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022") 

We then looked at the distribution of Non-US citizens in Boston. We selected this demographic variable because we expected that non-US citizens are more likely to live in transit-rich neighborhoods because these places often provide easy access to major job centers, business districts, and employment opportunities, which is especially attractive to foreigners seeking employment in urban areas. Yet, the map below reveals only a slight difference between number of non-US citizens between TOD and Non-TOD tracts, where TOD tracts attract slightly more foreigners than Non-TOD tracts, and this pattern is consistent throughout years.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=pctForeigner), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "blue4", name= "Percentage Foreigner", breaks = c(0, 0.2, 0.4, 0.6))+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
 theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Percentage of Non-US Citizens in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022") 

We also looked at the distribution of racial minority population in Boston. The map below shows that minority population are concentrated in southern Boston, mainly in Roxbury and Dorchester. More importantly, these neighborhoods are mostly made up of Non-TOD tracts. This pattern is consistent over time and in 2019, we are seeing an increasing number of minority population living in the same neighborhoods as in 2010.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=pctMinority), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "blue4", name= "Percentage Minority", breaks = c(0, 0.3, 0.6, 0.9))+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
 theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Percentage of Minorities in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022") 

Economic Characteristics

For economic variables, we first looked at median rent in Boston. The map below reveals that rent is significantly higher in TOD tracts than Non-TOD tracts in both 2010 and 2019. This implies that transit-rich neighborhoods are also more expensive. In addition, after adjusting for inflation, we also see that median rent has increased significantly in all census tracts in Boston, and this increase in rent is most salient in city center, where multiple transit lines meet.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=MedRent.inf), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "seagreen4", name= "Rent")+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
   theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Median Rent in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops \n2019 data adjusted for inflation",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022") 

Looking at the percentage of people under poverty in Boston, we can see that in both 2010 and 2019, neighborhoods in southern Boston (Roxbury and Dorchester) have higher poverty rates than other neighborhoods. These neighborhoods are mostly located in Non-TOD tracts. Yet, we are also able to see poverty rate is decreasing over the years. In 2010, a significant number of TOD tracts in western Boston have higher poverty rate than others. In 2019, however, we see that the condition improved, with most census tract with higher poverty rate concentrated in south Boston.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=pctPoverty), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "seagreen4", name= "Percentage Poverty")+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
 theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Percentage Poverty in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022")

The median household income data is not ideal as it contains a lot of missing data entries. However, it still informs us that in both 2010 and 2019, households living in TOD tracts have higher median household income. This is consistent with previous maps, where TOD tracts also have higher rent and lower poverty rates. It is also worth pointing out that median household income in TOD tracts is the highest in the city center. As the distance from city center increases, the difference in median household income between TOD and Non-TOD tracts become less prominent.

allTracts.group %>% 
  mutate(inc = MedHHInc.inf/1000) %>% 
  ggplot()+
  geom_sf(aes(fill=inc), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "seagreen4", name= "Income (thousands)")+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
  theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Median Household Income in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops\n2019 data adjusted for inflation",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022")

Social Characteristics

From the map below, we can see that in both 2010 and 2019, the majority of houses in Boston are renter occupied, with houses in TOD tracts, especially those tracts in city center, appear slightly more preferable to renters. Considering that there are a lot of universities in Boston and that some of these universities have their own transit station on campus, we suspect that a large number of renters of students, who chose to live around.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=pctRenter), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "#0047AB", name= "Percentage Renters")+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
   theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Percentage Renters in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022") 

We see a clear difference in spatial pattern here when considering whether people living in Boston own a car or not. Compared to Non-TOD tracts, a significantly higher number of people in TOD tracts do not have a car. This could imply that people chose to live in transit-rich neighborhood because of the “transit” itself.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=pctNoCar), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "#0047AB", name= "Percentage No Vehicle", breaks = c(0, 0.2, 0.4, 0.6))+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
   theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Percentage of Population without Car in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022") 

Lastly, we looked at education attainment for Bostonians. From 2010 to 2019, the number of people with a least a bachelor’s degree increased in Boston, and this increase is the most salient in TOD tracts. Again, census tracts with low education attainment are Non-TOD tracts, and are concentrated in south Boston.

allTracts.group %>% 
  ggplot()+
  geom_sf(aes(fill=pctBachelors), color="transparent") +
  scale_fill_continuous(low = "#FAF9F6", high = "#0047AB", name= "Percentage Bachelors", breaks = c(0, 0.3, 0.6, 0.9))+
  facet_wrap(~year) +
  geom_sf(data=stops_buffer, color = "red", fill = "transparent", linewidth = 0.4) +
   theme(legend.position = "bottom",
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) + 
  labs(title = "Percentage of Population with at Least a Bacehlor's Degree in Boston",
       subtitle = "Red circles indicate areas within 0.5 mile of a transit stops",
       caption = "Data: American Community Survey 2010 and 2019 \n MassGIS 2022") 

Quick Summary

To support our observations above, we further calculated the mean for all of our variables, which allows us to better examine changes in population characteristics across space and time as a whole.

allTracts.Summary <- 
  st_drop_geometry(allTracts.group) %>%
  group_by(year, TOD) %>%
  summarize(Rent = mean(MedRent.inf, na.rm = T),
            Income = mean(MedHHInc.inf, na.rm = T),
            Pop = mean(TotalPop, na.rm = T),
            PctMinority = mean(pctMinority, na.rm = T),
            PctAging = mean(pctAging, na.rm = T),
            PctBach = mean(pctBachelors, na.rm = T),
            PctPoverty = mean(pctPoverty, na.rm = T),
            PctNoCar = mean(pctNoCar, na.rm = T),
            PctRenter = mean(pctRenter, na.rm = T),
            PctForeign = mean(pctForeigner, na.rm = T))

The result is shown in the table as well as the chart below.

kable(allTracts.Summary, format = "html") %>%
 kable_styling(full_width = T, 
               bootstrap_options = c("striped", "hover"),
               font_size = 12) %>% 
  footnote(general_title = "\n",
           general = "Table 1: Comparaing Population Characteristics Across Space and Time ") %>% 
  row_spec(0, font_size = 14) %>% 
  row_spec(1, color = "white", background = "#7eb0d5") %>% 
  row_spec(2, color = "white", background = "#b2e061") %>% 
  row_spec(3, color = "white", background = "#7eb0d5") %>% 
  row_spec(4, color = "white", background = "#b2e061") %>% 
  column_spec(1:2, bold = T)
year TOD Rent Income Pop PctMinority PctAging PctBach PctPoverty PctNoCar PctRenter PctForeign
2010 Non-TOD 1152 66652 3272 0.551 0.074 0.210 0.168 0.056 0.471 0.118
2010 TOD 1310 61120 3402 0.423 0.063 0.330 0.214 0.170 0.629 0.154
2019 Non-TOD 1367 74354 3856 0.570 0.077 0.262 0.166 0.058 0.476 0.111
2019 TOD 1567 74538 3761 0.456 0.072 0.412 0.175 0.170 0.624 0.146

Table 1: Comparaing Population Characteristics Across Space and Time
# 

Who is living around transit stations in Boston, what are their social, economic, and demographic characteristics, and do they vary across time? Our analysis have found the following to answer our first and second questions: 1) Populations living in transit-rich neighborhoods in Boston are of relatively younger age, are mostly renters, have higher education attainment, have higher median household income, and do not own any vehicles. 2) On the other hand, Non-TOD neighborhoods in Boston tend to have higher concentration of aging population and minority population as well as lower education attainment. 3) Gentrification remains prevalent in the city as we see citywide increase in median household rent and median household income. In addition, the city is becoming more and more diverse; its poverty rate has been reducing while overall and individuals’ education attainment has been increasing.

allTracts.Summary %>%
  gather(Variable, Value, -year, -TOD) %>%
  ggplot(aes(year, Value, fill = TOD)) +
  geom_bar(stat = "identity", position = "dodge") +
  facet_wrap(~Variable, scales = "free", ncol=5) +
  scale_fill_manual(values = c("#7eb0d5", "#b2e061")) +  
  labs(title = "Indicator Differences Across Time and Space",
       caption = "Data: American Community Survey 2010 and 2019") +
  theme(legend.position = "bottom",
        axis.ticks.x=element_blank(),
        axis.ticks.y=element_blank(),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) 

Further Analysis

We did some further analysis to rearrange our tables and calculate percentage point change. This includes pivoting the table twice to make year 2010 and 2019 two separate columns

allTracts.Long <- allTracts.Summary %>%
  pivot_longer(cols = c(Rent, Income, Pop, PctMinority, PctAging, PctBach, PctPoverty, PctNoCar, PctRenter, PctForeign), names_to = "Variable", values_to = "Value") %>%
  pivot_wider(names_from = year, values_from = Value, names_prefix = "Year") %>% 
  mutate(pct_change = (Year2019-Year2010) / Year2010)

Looking at the percentage change of variables between Non-TOD and TOD tracts, we may see that from 2010 to 2019, 1) median house rent and median household income increases significantly in TOD tracts compared to Non-TOD, 2) poverty rate was significantly reduced in TOD tracts compared to Non-TOD, 3) population increase is more salient in Non-TOD tracts than TOD.

allTracts.Long %>% 
  ggplot() +
  geom_bar(aes(x = Variable, y = pct_change, fill = TOD),
           stat = "identity") +
  facet_wrap(~TOD) +
  coord_flip() +
  scale_fill_manual(values = c("#7eb0d5", "#b2e061")) +  
  labs(title = "Percentage Change 2010-2019 for TOD and Non-TOD Tracts",
       caption = "Data: American Community Survey 2010 and 2019") +
  ylab ("Percentage Change") +
  theme(legend.position = "bottom",
        axis.ticks.x=element_blank(),
        axis.ticks.y=element_blank(),
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) 

We also looked into see if there’s intra-regional variations of our variables among TOD tracts, using population and median house rent as an example. To achieve that, we joined the centroids of census tracts into the half mile buffer of transit stations, which we then summarized the total population and median rent within half mile of each transit station.

boston_stops$ID <- seq_along(boston_stops$STATION) # unique id for each station

stop_attributes <- st_buffer(boston_stops, 804) %>% 
  st_sf() %>% 
  st_intersection(st_centroid(boston10)) %>% 
  st_drop_geometry() %>% 
  group_by(ID) %>% 
  summarize(
    total_population = sum(TotalPop),
    median_rent = mean(MedRent, na.rm = T))

stops_summary <- boston_stops %>% 
  left_join(stop_attributes, by = "ID")

Not surprisingly, the map below shows that transit station in city center attracts more people to live nearby while as distance from the city center gets greater, the dot size becomes smaller, meaning there’s less people living nearby.

ggplot() +
  geom_sf(data=st_union(boston10_4326), fill= "#D3D3D3", color = "white", size = 2) +
  geom_point(data = stops_summary_df, aes(x = X, y = Y, size = total_population, color = str_to_title(stops))) +
  scale_size(range = c(0.5, 4.5), name = "Population") +    
  scale_colour_manual(values = c("#7eb0d5","#b2e061", "#ffb55a", "#ffee65", "#fd7f6f", "#bd7ebe"), name = "Stops") +
  labs(title = "Population within 0.5 Mile of Tansit Stops",
       subtitle = "Dot size proportional to population",
       caption = "Data: American Community Survey 2019") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"))

Similarly, median rent is the highest around transit stations in the city center.This shows that the influence of transit station on nearby population and settlements characteristics are not the same throughout the city.

ggplot() +
  geom_sf(data=st_union(boston10_4326), fill= "#D3D3D3", color = "white", size = 2) +
  geom_point(data = stops_summary_df, aes(x = X, y = Y, size = rent, color = str_to_title(stops))) +
  scale_size(range = c(0.5, 4), name = "Rent") +    
  scale_colour_manual(values = c("#7eb0d5","#b2e061", "#ffb55a", "#ffee65", "#fd7f6f", "#bd7ebe"), name = "Stops") +
  labs(title = "Median Rent within 0.5 Mile of Tansit Stops",
       subtitle = "Dot size proportional to rent",
       caption = "Data: American Community Survey 2019") +
  theme_light() +   
  theme(plot.subtitle = element_text(size = 9,face = "italic"),
        plot.title = element_text(size = 12, face = "bold"))

Moreover, we were curious if there is a linear relationship between distance from transit stops and rent? We therefore created a multiple ring buffer, where each buffer is of half a mile distance to the previous one, to answer this question.

boston_MRB <- multipleRingBuffer(st_union(boston_stops), 14484, 804)
ggplot() +
    geom_sf(data=boston_MRB, aes(fill = distance), color = "#708090") +
    scale_fill_continuous(low = "#FAF9F6", high = "#beb9db", name= "Distance")+
    geom_sf(data=st_union(boston10), fill= "#D3D3D3", color = "white", size = 2) +
    geom_sf(data=boston_stops, 
          color = "#fd7f6f", size= 0.8) +    
    labs(title="Half Mile Buffers",
         subtitle = "Distance in-between each buffer is 0.5 mile",
         caption = "Data: American Community Survey 2010 and 2019 \nMassGIS 2022") +
    theme_light() +   
    theme(plot.subtitle = element_text(size = 9,face = "italic"),
          plot.title = element_text(size = 12, face = "bold"))

The figure below shows that overall, rent decreases as distance from transit stops gets greater. However, the relationship is not linear as we see that rent is increasing from 2500 to 4000 meters. This implies that transit stations is not the only factor defining rent. In other words, it could be households are willing to pay more for transit amenities, or that they pay for other types of amenities in neighborhoods that happen to also be transit-rich: proximity to transit station only partially influence their decisions to live in nearby locations.

allTracts.rings <-
  st_join(st_centroid(dplyr::select(allTracts, GEOID, year)),
          boston_MRB) %>%
  st_drop_geometry() %>%
  left_join(dplyr::select(allTracts, GEOID, MedRent, year), 
            by=c("GEOID"="GEOID", "year"="year")) %>%
  st_sf() 


allTracts.rings.summary <- st_drop_geometry(allTracts.rings) %>%
  group_by(distance, year) %>%
  summarize(Mean_Rent = mean(MedRent, na.rm=T))


ggplot(allTracts.rings.summary, aes(x = distance, y = Mean_Rent)) + 
  geom_line(aes(color = year), size = 2) + 
  scale_color_manual(values = c("#7eb0d5", "#b2e061"), name = "Year") +
  labs(title = "Mean Rent as a Function of Distance to Subway Stations",
       caption = "Data: American Community Survey 2010 and 2019") +
  xlab ("Distance from Transit Stops") +
  ylab("Mean Rent") + 
  theme(legend.position = "bottom",
        plot.title = element_text(size = 12, face = "bold"),
        panel.background = element_blank(),
        panel.border = element_rect(colour = "grey", fill=NA, size=0.8)
        ) 

Future Planning

To quickly summarize, Boston is gentrifying between 2010 and 2019, with increasing population, diversity, median household income, median rent, and education attainment as well as decreasing poverty rate throughout the city. There’s difference in terms of population characteristics between TOD and Non-TOD regions, where TOD attracts mostly renters who are younger, wealthier, and well-educated, whereas Non-TOD tracts’ households consist larger concentration of minority and aging population with lower education attainment.

In addition, there’s intra-regional difference within TOD tracts, where median rent for houses next to transit stations that are in city center being the most expensive. Further, rent did not only decrease as we move away from transit stations. This leads us to conclude that not all transit stations are as appealing as each other. Proximity to transit station only affects people’s decision to live in nearby locations to a certain extent. TOD neighborhoods in Boston is able to attract younger and wealthier individual not only because they offer convenience in public transportation, but also could because Bostonians value the cultural amenities, entertainment & nightlife, as well as employment and academic opportunities that are happened to be within half a mile of these transit stops.

While Boston is a highly walkable city, planning official should still work towards making public transportation more accessible to neighborhoods that are currently. Non-TOD and developing parcels near transit stations, which could alleviate the housing and amenity shortages at city center and reduce intra-regional disparities. Despite that Non-TOD neighborhood have higher car ownecrship rate, this does not mean that public transportation planning is not important in these neighborhoods. For places like the city center where it is hard to get to through driving and where business and intellectual opportunities accumulate, public transportation is the best way to connect different neighborhoods together. Indeed, this aligns with the city’s goal to “connect all neighborhood centers into a comprehensive transit network”.

With the current data we have, how do we improve public transit accessibility in Non-TOD neighborhoods in Boston? We attempted to answer this question with a bivariate map, considering the possibility of extending existing transit lines and adding a transit station in Non-TOD neighborhoods where there’s both a high concentration of aging and minority population (two population subgroups that are often excluded in TOD).The map below highlights an area in southern Boston with high number of both population subgroups. We encouraged transportation planners to further investigate the possibility of future transit developments in these locations.

bi_data <- bi_class(boston19, x = pctMinority, y = pctAging, style = "quantile", dim = 3) #  a 3*3 color-schemed bi-variate choropleth 


bi_map <- ggplot() +
  geom_sf(data = bi_data, mapping = aes(fill = bi_class), color = "transparent", show.legend = FALSE) +
  bi_scale_fill(pal = "DkCyan", dim = 3) + 
  labs(title = "Bivariate Choropleth of Pct Minority over Pct Aging Population") + 
  geom_sf(data = boston_stops, colour = "yellow", alpha = 0.8, size = 0.5) +
  labs(caption = "Data: American Community Survey 2019") +
  theme_light() +
  theme(plot.title = element_text(size = 12, face = "bold"))

legend <- bi_legend(pal = "DkCyan",
                    dim = 3,
                    xlab = "PctMinority ",
                    ylab = "PctAging ",
                    size = 5.8)

ggdraw() +
  draw_plot(bi_map, 0, 0, 1, 1) +
  draw_plot(legend, 0.1, 0.2, 1.2, 0.23)

Finally, there is one important limitation of this study that has to be addressed. We mentioned before that the MBTA transit lines go beyond the boundary of Boston cities. In this case, it is likely that some census tracts at the edge of Boston that are categorized as Non-TOD are actually TOD.Future study at a regional scale should consider examine TOD development in Boston considering all transit stops in the Greater Boston Areas as well as all types of transit stops.

LS0tCnRpdGxlOiAiVHJhbnNpdCBPcmllbnRlZCBEZXZlbG9wbWVudCBpbiBCb3N0b24iCmF1dGhvcjogIkVtaWx5IFpob3UiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogc2ltcGxleAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIGNhY2hlPVRSVUV9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgpWZXJzaW9uIDEuMCBcfCBGaXJzdCBDcmVhdGVkIFNlcCAxNSwgMjAyMyBcfCBVcGRhdGVkIFNlcCAyMCwgMjAyMwoKS2V5d29yZHM6IE11bHRpcGxlIFJpbmcgQnVmZmVyLCBJbmRpY2F0b3JzLCBUcmFuc2l0IE9yaWVudGVkIERldmVsb3BtZW50LCBHZW50cmlmaWNhdGlvbiwgQm9zdG9uCgojIEludHJvZHVjdGlvbgoKSW4gY2l0eSBwbGFubmluZywgdHJhbnNpdC1vcmllbnRlZCBkZXZlbG9wbWVudCAoVE9EKSBpcyBhIHR5cGUgb2YgdXJiYW4gZGV2ZWxvcG1lbnQgcHJhY3RpY2UgdGhhdCBhaW1zIHRvIG1heGltaXplIHRoZSBhbW91bnQgb2YgcmVzaWRlbnRpYWwsIGJ1c2luZXNzLCBhbmQgbGVpc3VyZSBzcGFjZSB3aXRoaW4gd2Fsa2luZyBkaXN0YW5jZSBvZiBwdWJsaWMgdHJhbnNwb3J0LiBUT0Qgb2ZmZXJzIGEgcmFuZ2Ugb2YgYmVuZWZpdHMgdGhhdCBhbGwgY29udHJpYnV0ZSB0byBjcmVhdGluZyBhIG1vcmUgdmlicmFudCwgc3VzdGFpbmFibGUsIGFuZCBpbmNsdXNpdmUgY29tbXVuaXRpZXMuIEZvciBleGFtcGxlLCBhIGNvbW11bml0eSB3aXRoIGEgc3Ryb25nIGFuZCBkZXBlbmRhYmxlIHRyYW5zaXQgc3lzdGVtIGFuZCBzdHJlZXRzY2FwaW5nIGVsZW1lbnRzIGNhbiBkaXNjb3VyYWdlIHZlaGljbGUgZGVwZW5kZW5jZSBhbmQgY29uZ2VzdGlvbi4gVGhpcyBmdXJ0aGVyIGxlYWRzIHRvIHJlZHVjdGlvbiBpbiBncmVlbmhvdXNlIGdhcyBlbWlzc2lvbnMgcGVyIGNhcGl0YSBhbmQgYSBzbWFsbGVyIGNhcmJvbiBmb290cHJpbnQuIEluIGFkZGl0aW9uLCBhcyBjaXRpZXMgYmVjb21lIG1vcmUgd2Fsa2FibGUsIFRPRCBjYW4gc3RpbXVsYXRlIGVjb25vbWljIGdyb3d0aCBieSBhdHRyYWN0aW5nIGJ1c2luZXNzIGFuZCBjcmVhdGluZyBqb2JzLiBUaGlzIGluY2x1ZGVzIGJyaW5naW5nIGluIG1peGVkLXVzZSBkZXZlbG9wbWVudHMsIHN1Y2ggYXMgcmV0YWlsLCBkaW5pbmcsIGFuZCBlbnRlcnRhaW5tZW50IG9wdGlvbnMgd2l0aGluIGVhc3kgcmVhY2ggb2YgcmVzaWRlbnQuIE1vcmVvdmVyLCBUT0QgaW5jcmVhc2VzIHByb3BlcnR5IHZhbHVlcyBpbiBzdXJyb3VuZGluZyBhcmVhcywgd2hpY2ggaXMgcGFydGljdWxhcmx5IGltcG9ydGFudCBmb3IgcmVhbC1lc3RhdGUgZGV2ZWxvcGVycyBhbmQgZ292ZXJubWVudHMuIAoKVHJhbnNpdCBvcmllbnRlZCBkZXZlbG9wbWVudCBoYXMgYmVlbiBhIGxhcmdlIHBhcnQgb2YgQm9zdG9u4oCZcyBncm93dGguIFRoZSBbQm9zdG9uIFJlZGV2ZWxvcG1lbnQgQXV0aG9yaXR5XShodHRwczovL3d3dy5ib3N0b25wbGFucy5vcmcvcGxhbm5pbmcvcGxhbm5pbmctaW5pdGlhdGl2ZXMvZm9zdGVyaW5nLXRyYW5zaXQpIGhhcyBiZWVuIHVuZGVydGFraW5nIGEgVE9EIGluaXRpYXRpdmUgdG8gYnVpbGQgb24gYW5kIHJlaW5mb3JjZSBCb3N0b24ncyBleGlzdGluZyBhbmQgZW1lcmdpbmcgbmVpZ2hib3Job29kIGNlbnRlcnMuIFRoZWlyIGdvYWwgaXMgdG8gKipjb25uZWN0IGFsbCBuZWlnaGJvcmhvb2QgY2VudGVycyBpbnRvIGEgY29tcHJlaGVuc2l2ZSB0cmFuc2l0IG5ldHdvcmsqKiBhbmQgdG8gKipzdXBwb3J0IHRoYXQgbmV0d29yayB3aXRoIGFwcHJvcHJpYXRlIGRldmVsb3BtZW50IHBhdHRlcm5zIG5lYXIgdGhlc2UgbmVpZ2hib3Job29kIGNlbnRlcnMqKi4gVG8gY29udHJpYnV0ZSB0byB0aGVyaSB3b3JrLCB0aGlzIHJlcG9ydCBjb25kdWN0cyBhIGNvbXByZWhlbnNpdmUgYW5hbHlzaXMgb2YgZXhpc3RpbmcgVE9EIHBhdHRlcm5zIGluIEJvc3Rvbi4gVGhyb3VnaCB2aXN1YWxpemluZyB0ZW1wb3JhbCBjaGFuZ2VzIGluIGRlbW9ncmFwaGljLCBzb2NpYWwsIGFuZCBlY29ub21pYyBjaGFyYWN0ZXJpc3RpY3Mgb2YgbmVpZ2hib3Job29kcyBhY3Jvc3MgQm9zdG9uLCBleGFtaW5pbmcgdGhlIHNwYXRpYWwgZGlzdHJpYnV0aW9uIG9mIHRyYW5zaXQgc3RvcHMsIGFuZCBjb21wYXJpbmcgdGhlIGRpZmZlcmVuY2VzIG9mIGRldmVsb3BtZW50IHBhdHRlcm5zIGJldHdlZW4gVE9EIGFuZCBOb24tVE9EIHRyYWN0cywgd2UgYWltIHRvIGFkZHJlc3MgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6IAoKMS4gV2hvIGlzIGxpdmluZyBhcm91bmQgdHJhbnNpdCBzdGF0aW9ucyBpbiBCb3N0b24/IAoKMi4gSG93IGRvZXMgdGhlIHNvY2lhbCwgZWNvbm9taWMsIGFuZCBkZW1vZ3JhcGhpYyBjaGFyYWN0ZXJpc3RpY3Mgb2YgaG91c2Vob2xkcyBsaXZpbmcgbmVhciB0cmFuc2l0IHN0YXRpb25zIGluIEJvc3RvbiBjaGFuZ2Ugb3ZlciB0aW1lPyAKCjMuIEFyZSBCb3N0b25pYW5zIHdpbGxpbmcgdG8gcGF5IGEgcHJlbWl1bSB0byBsaXZlIGluIHRyYW5zaXQtcmljaCBhcmVhcz8gSWYgcmVzaWRlbnRzIHZhbHVlIHRoZXNlIGxvY2F0aW9ucywgb2ZmaWNpYWxzIHNob3VsZCBjb25zaWRlciBjaGFuZ2luZyB0aGUgem9uaW5nIGNvZGUgdG8gYWxsb3cgaW5jcmVhc2VkIGRlbnNpdHkgYXJvdW5kIHRyYW5zaXQuCgo0LiBIb3cgY2FuIHBsYW5uZXJzIGluIEJvc3RvbiBiZSBtb3JlIHN0cmF0ZWdpYyBhYm91dCBkZXZlbG9wbWVudHMgaW4gdHJhbnNpdC1yaWNoIG5laWdoYm9yaG9vZHMgaW4gb3JkZXIgdG8gc2F0aXNmeSB0aGUgbmVlZHMgb2YgdGhvc2Ugd2hvIGZhdm9yIHRyYW5zaXQgcHJveGltaXR5PyAKClRoZSBHaXRIdWIgcmVwb3NpdG9yeSBmb3IgdGhpcyByZXBvcnQgaXMgYXZhaWxhYmxlIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vZW1pbHl6aG91MTEyL01VU0E1MDgwLUJvc3Rvbi1UT0QpLiAKCiMgRGF0YSBNYW5pcHVsYXRpb24KCkJlZm9yZSB3ZSBiZWdpbiBvdXIgYW5hbHlzaXMgYW5kIHZpc3VhbGl6YXRpb24sIHRoZXJlIGFyZSBhIGNvdXBsZSBvZiBkYXRhIGNsZWFuaW5nIGFuZCBtYW5pcHVsYXRpb24gc3RlcHMgdGhhdCB3ZSBuZWVkIHRvIHBlcmZvcm0gYXMgd2VsbCBhcyBzb21lIGFuYWx5dGljYWwgZGVjaXNpb25zIHRvIHNwZWNpZnkuICAKCmBgYHtyIHNldHVwX3BhY2thZ2VzLCB3YXJuaW5nID0gRkFMU0UsIGluY2x1ZGU9RkFMU0V9CgojIGxpc3Qgb2YgcmVxdWlyZWQgcGFja2FnZXMKcGFja2FnZXMgPC0gYyggInRpZHl2ZXJzZSIsICJnZ3Bsb3QyIiwgInN2RGlhbG9ncyIsICJ0aWR5Y2Vuc3VzIiwgInNmIiwgImtuaXRyIiwgInJtYXJrZG93biIsICJrYWJsZUV4dHJhIiwgInN0cmluZ3IiLCAiYmlzY2FsZSIsICJjb3dwbG90IikKCiMgaW5zdGFsbCBhbmQgbG9hZCByZXF1aXJlZCBwYWNrYWdlcwpwYWNrYWdlLmNoZWNrIDwtIGxhcHBseSgKICBwYWNrYWdlcywKICBGVU4gPSBmdW5jdGlvbih4KSB7CiAgICBpZiAoIXJlcXVpcmUoeCwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSkgewogICAgICBpbnN0YWxsLnBhY2thZ2VzKHgsIGRlcGVuZGVuY2llcyA9IFRSVUUsIHF1aWV0bHk9VFJVRSkKICAgICAgbGlicmFyeSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpCiAgICB9CiAgfQopCgojIGdsb2JhbCBvcHRpb25zIApvcHRpb25zKHNjaXBlbj05OTkpCm9wdGlvbnModGlncmlzX2NsYXNzID0gInNmIikKb3B0aW9ucyhkaWdpdHMgPSAzKQoKIyBsb2FkIGluIG11bHRpcGxlIHJpbmcgYnVmZmVyIGZ1bmN0aW9uCnNvdXJjZSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3VyYmFuU3BhdGlhbC9QdWJsaWMtUG9saWN5LUFuYWx5dGljcy1MYW5kaW5nL21hc3Rlci9mdW5jdGlvbnMuciIpCgpgYGAKCgpgYGB7ciBsb2FkX2tleSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKY2Vuc3VzX2FwaV9rZXkoZGxnSW5wdXQoCiAgIkVudGVyIGEgQ2Vuc3VzIEFQSSBLZXkiLCAjIGFzayBmb3IgYW4gYXBpIGtleQogIFN5cy5nZXRlbnYoIkNFTlNVU19BUElfS0VZIikKKSRyZXMsCm92ZXJ3cml0ZSA9IFRSVUUpCgpgYGAKCiMjIEFDUyBEYXRhCgpXZSBhcmUgdXNpbmcgdGhlIEFtZXJpY2EgQ29tbXVuaXR5IFN1cnZleSAoNS15ZWFyIGVzdGltYXRlKSBmb3IgeWVhciAyMDEwIGFuZCAyMDE5IGluIHRoaXMgcmVwb3J0LiBXZSBjaG9zZSB0aGUgQUNTIGRhdGEgYmVjYXVzZSBpdCBjb2xsZWN0cyBkZXRhaWxlZCBkZW1vZ3JhcGhpYywgc29jaWFsLCBlY29ub21pYywgYW5kIGhvdXNpbmcgZGF0YSBvbiBhIHdpZGUgcmFuZ2Ugb2YgdG9waWNzLCBwcm92aWRpbmcgYSBtb3JlIGNvbXByZWhlbnNpdmUgdmlldyBvZiBhIGNvbW11bml0eSdzIGNoYXJhY3RlcmlzdGljcyBpbiBCb3N0b24uIFdlIGNob3NlIDIwMTkgYXMgdGhlIGVuZCB5ZWFyIGJlY2F1c2UgQ09WSUQtMTkgc2luY2UgMjAyMCBoYXMgZHJhc3RpY2FsbHkgY2hhbmdlZCBwZW9wbGUncyB3b3JrIGFuZCB0cmF2ZWwgYmVoYXZpb3JzOiB0aGUgd2lkZXNwcmVhZCBhZG9wdGlvbiBvZiByZW1vdGUgd29yayBkdXJpbmcgdGhlIHBhbmRlbWljIHdvdWxkIGNlcnRhaW5seSBsZWQgdG8gZGVjbGluZSBpbiB0aGUgZGVtYW5kIGZvciBvZmZpY2Ugc3BhY2UgYW5kIHRoZSBuZWVkIGZvciB0cmFuc2l0LW9yaWVudGVkIG9mZmljZSBkZXZlbG9wbWVudHMuIEluIG9yZGVyIHRvIGJldHRlciB1bmRlcnN0YW5kIGlmIHRoZXJlJ3MgYSBkaWZmZXJlbmNlIGJldHdlZW4gaW5kaXZpZHVhbHMgbGl2aW5nIGluIFRPRCBhbmQgTm9uLVRPRCBuZWlnaGJvcmhvb2Qgb3ZlciB0aW1lLCB3ZSBjaG9zZSB0aGUgZm9sbG93aW5nIEFDUyB2YXJpYWJsZXMsIGNhdGVnb3JpemVkIGludG8gZGVtb2dyYXBoaWMsIHNvY2lhbCwgYW5kIGVjb25vbWljIGNoYXJhY3RlcmlzdGljcywgZm9yIG91ciBhbmFseXNpcy4gCgp8IFZhcmlhYmxlIE5hbWUgICAgICAgICAgICAgIHwgQUNTIE5hbWUgICAgfCAKfCA6LS0tLS0tLS0tLTogfCA6LS0tLS0tLS0tLTp8ICAKfCAqKkRlbW9ncmFwaGljKiogICAgICAgICAgICB8ICAgICAgICAgICAgIHwKfCBUb3RhbCBQb3B1bGF0aW9uICAgICAgICAgICB8IEIwMjAwMV8wMDEgIHwKfCBXaGl0ZSBQb3B1bGF0aW9uICAgICAgICAgICB8IEIwMjAwMV8wMDIgIHwKfCBCbGFjayBQb3B1bGF0aW9uICAgICAgICAgICB8IEIwMjAwMV8wMDMgIHwKfCBBc2lhbiBQb3B1bGF0aW9uICAgICAgICAgICB8IEIwMjAwMV8wMDUgIHwKfCBMYXRpbnggUG9wdWxhdGlvbiAgICAgICAgICB8IEIwMzAwMl8wMTIgIHwKfCBNYWxlIDcwLTc0ICAgICAgICAgICAgICAgICB8IEIwMTAwMV8wMjIgIHwKfCBNYWxlIDc1LTc5ICAgICAgICAgICAgICAgICB8IEIwMTAwMV8wMjMgIHwKfCBNYWxlIDgwLTg0ICAgICAgICAgICAgICAgICB8IEIwMTAwMV8wMjQgIHwKfCBNYWxlIG92ZXIgODUgICAgICAgICAgICAgICB8IEIwMTAwMV8wMjUgIHwKfCBGZW1hbGUgNzAtNzQgICAgICAgICAgICAgICB8IEIwMTAwMV8wNDYgIHwKfCBGZW1hbGUgNzUtNzkgICAgICAgICAgICAgICB8IEIwMTAwMV8wNDcgIHwKfCBGZW1hbGUgODAtODQgICAgICAgICAgICAgICB8IEIwMTAwMV8wNDggIHwKfCBGZW1hbGUgb3ZlciA4NSAgICAgICAgICAgICB8IEIwMTAwMV8wNDkgIHwKfCBOb24tVVMgQ2l0aXplbiAgICAgICAgICAgICB8IEIwNTAwMV8wMDYgIHwKfCAqKkVjb25vbWljKiogICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwKfCBNZWRpYW4gSG91c2Vob2xkIEluY29tZSAgICB8IEIxOTAxM18wMDEgIHwKfCBNZWRpYW4gUmVudCAgICAgICAgICAgICAgICB8IEIyNTA1OF8wMDEgIHwKfCBQb3B1bGF0aW9uIHVuZGVyIFBvdmVydHkgICB8IEIwNjAxMl8wMDIgIHwKfCAqKlNvY2lhbCoqICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgIHwKfCBCYWNoZWxvciBEZWdyZWUgICAgICAgICAgICB8IEIwNjAwOV8wMDUgIHwKfCBHcmFkdWF0ZSBEZWdyZWUgICAgICAgICAgICB8IEIwNjAwOV8wMDYgIHwKfCBSZW50ZXIgT2NjdXBpZWQgSG91c2Vob2xkICB8IEIyNTAyNl8wMDkgIHwKfCBQb3B1bGF0aW9uIHdpdGhvdXQgVmVoaWNsZSB8IEIwODAxNF8wMDIgIHwKCkJhc2VkIG9uIHRoZXNlIEFDUyB2YXJpYWJsZXMsIHdlIGZ1cnRoZXIgY29tcHV0ZWQgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6CgoKLSAqKlBjdE1pbm9yaXR5KiogOiBwZXJjZW50YWdlIG9mIG1pbm9yaXR5IHBvcHVsYXRpb24sIHdoZXJlIG1pbm9yaXR5IGhlcmUgcmVmZXJzIHRvIGFueW9uZSB3aG8gaXMgQXNpYW4sIExhdGlueCwgb3IgQmxhY2suICAgIAotICoqUGN0QWdpbmcqKjogcGVyY2VudGFnZSBvZiBhZ2luZyBwb3B1bGF0aW9uLCB3aGVyZSBhZ2luZyBoZXJlIHJlZmVycyB0byBhbnlvbmUgd2hvIGlzIG92ZXIgNzAgeWVhcnMgb2xkLiAgIAoKLSAqKlBjdEZvcmVpZ24qKjogcGVyY2VudGFnZSBvZiBwb3B1bGF0aW9uIHdobyBhcmUgbm9uLVVTIGNpdGl6ZW5zLiAgIAoKLSAqKlBjdEJhY2hlbG9ycyoqOiBwZXJjZW50YWdlIG9mIHBvcHVsYXRpb24gd2l0aCBhdCBsZWFzdCBhIEJhY2hlbG9yJ3MgZGVncmVlLiAgIAoKLSAqKlBjdFJlbnRlcioqOiBwZXJjZW50YWdlIG9mIHJlbnRlciBvY2N1cGllZCBob3VzZWhvbGRzLiAgIAoKLSAqKlBjdE5vQ2FyKio6cGVyY2VudGFnZSBvZiBwb3B1bGF0aW9uIHdpdGhvdXQgYSB2ZWhpY2xlLiAKCi0gKipQY3RQb3ZlcnR5Kio6IHBvdmVydHkgcmF0ZS4gIAoKVGhlIGZvbGxvd2luZyBjb2RlIGdpdmVzIGFuIGV4YW1wbGUgb2YgdGhlIGRhdGEgY2xlYW5pbmcgc3RlcHMgd2UgcGVyZm9ybWVkIHVzaW5nIDIwMTAgQUNTIGRhdGEsIHdoZXJlIHdlIGRvd25sb2FkZWQgdGhlIEFDUyBkYXRhLCByZXByb2plY3RlZCB0aGUgZGF0YSwgcmVtb3ZlZCBhcmVhcyBvdXRzaWRlIG9mIEJvc3RvbiwgcmVuYW1lZCB0aGUgY29sdW1ucywgcGVyZm9ybWVkIGFkZGl0aW9uYWwgZGF0YSBtYW5pcHVsYXRpb25zLCBhbmQgZGlzY2FyZGVkIHVubmVjZXNzYXJ5IHZhcmlhYmxlcy4gCgpgYGB7ciBkZWZpbmVfYWNzX3ZhciwgaW5jbHVkZT1GQUxTRX0KCmFjc192YXIgPSBjKCJCMDIwMDFfMDAxRSIsICMgdG90YWwgcG9wdWxhdGlvbgogICAgICAgICAgICAiQjAyMDAxXzAwMkUiLCAjIHdoaXRlIHBvcHVsYXRpb24KICAgICAgICAgICAgIkIwMjAwMV8wMDNFIiwgIyBibGFjayBwb3B1bGF0aW9uCiAgICAgICAgICAgICJCMDIwMDFfMDA1RSIsICMgYXNpYW4gcG9wdWxhdGlvbgogICAgICAgICAgICAiQjAzMDAyXzAxMkUiLCAjIGxhdGlueCBwb3B1bGF0aW9uCiAgICAgICAgICAgICJCMDEwMDFfMDIyRSIsICMgbWFsZSA3MC03NAogICAgICAgICAgICAiQjAxMDAxXzAyM0UiLCAjIG1hbGUgNzUtNzkKICAgICAgICAgICAgIkIwMTAwMV8wMjRFIiwgIyBtYWxlIDgwLTg1CiAgICAgICAgICAgICJCMDEwMDFfMDI1RSIsICMgbWFsZSBvdmVyIDg1CiAgICAgICAgICAgICJCMDEwMDFfMDQ2RSIsICMgZmVtYWxlIDcwLTc0CiAgICAgICAgICAgICJCMDEwMDFfMDQ3RSIsICMgZmVtYWxlIDc1LTc5CiAgICAgICAgICAgICJCMDEwMDFfMDQ4RSIsICMgZmVtYWxlIDgwLTg1CiAgICAgICAgICAgICJCMDEwMDFfMDQ5RSIsICMgZmVtYWxlIG92ZXIgODUKICAgICAgICAgICAgIkIxOTAxM18wMDFFIiwgIyBtZWRpYW4gaG91c2Vob2xkIGluY29tZQogICAgICAgICAgICAiQjI1MDU4XzAwMUUiLCAjIG1lZGlhbiByZW50CiAgICAgICAgICAgICJCMDYwMTJfMDAyRSIsICMgdG90YWwgcG92ZXJ0eQogICAgICAgICAgICAiQjA2MDA5XzAwNUUiLCAjIGJhY2hlbG9yCiAgICAgICAgICAgICJCMDYwMDlfMDA2RSIsICMgZ3JhZHVhdGUKICAgICAgICAgICAgIkIwODAxNF8wMDJFIiwgIyBubyBjYXIKICAgICAgICAgICAgIkIyNTAyNl8wMDlFIiwgIyByZW50ZXIKICAgICAgICAgICAgIkIwNTAwMV8wMDZFIiAjIG5vbi11cyBjaXRpemVuCiAgICAgICAgICAgICkKCmBgYAoKCmBgYHtyIG5vbl9ib3N0b25fY291bnR5LCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CgpyZW1vdmUgPC0gYygiMjUwMjUxODA0MDAiLCAiMjUwMjU5OTAxMDEiLCAiMjUwMjUxODAzMDEiLCAiMjUwMjUxNjA0MDAiLCAiMjUwMjUxODA1MDAiLCAiMjUwMjUxNjA2MDEiLCAiMjUwMjUxODAyMDAiLCAiMjUwMjUxNjAzMDAiLCAiMjUwMjUxNjAyMDAiLCAiMjUwMjUxODAxMDEiLCAiMjUwMjUxNzA1MDIiLCAiMjUwMjUxNjA1MDIiLCAiMjUwMjUxNzA3MDEiLCAiMjUwMjUxNzA1MDEiLCAiMjUwMjUxNzA4MDAiLCAiMjUwMjUxNzAyMDAiLCAiMjUwMjUxNzA0MDAiLCAiMjUwMjUxNzAxMDAiLCAiMjUwMjUxNzAxMDAiLCAiMjUwMjUxNzA2MDEiLCAiMjUwMjUxNzAzMDAiLCAiMjUwMjUxNzA3MDIiLCIyNTAyNTE2MDYwMiIsICIyNTAyNTE2MDUwMSIsICIyNTAyNTE2MDEwMSIpCgpgYGAKCgpgYGB7ciBib3N0b25fMjAxMF9kYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93JywgcmVzdWx0cz0iaGlkZSJ9Cgpib3N0b24xMCA8LSAKICBnZXRfYWNzKGdlb2dyYXBoeSA9ICJ0cmFjdCIsIHZhcmlhYmxlcyA9IGFjc192YXIsIAogICAgICAgICAgeWVhcj0yMDEwLCBzdGF0ZT0nTUEnLCBjb3VudHk9MDI1LCBnZW9tZXRyeT1ULCBvdXRwdXQ9IndpZGUiKSAlPiUgCiAgc3RfdHJhbnNmb3JtKCdFUFNHOjI2OTg2JykgJT4lIAogIGZpbHRlcighKEdFT0lEICVpbiUgcmVtb3ZlKSkgJT4lIAogIHJlbmFtZShUb3RhbFBvcCA9IEIwMjAwMV8wMDFFLCAKICAgICAgICAgV2hpdGVzID0gQjAyMDAxXzAwMkUsCiAgICAgICAgIEFmcmljYW5fQW1lcmljYW5zID0gQjAyMDAxXzAwM0UsCiAgICAgICAgIEFzaWFucyA9IEIwMjAwMV8wMDVFLAogICAgICAgICBMYXRpbnggPSBCMDMwMDJfMDEyRSwKICAgICAgICAgTTcwXzc0ID0gQjAxMDAxXzAyMkUsCiAgICAgICAgIE03NV83OSA9IEIwMTAwMV8wMjNFLAogICAgICAgICBNODBfODUgPSBCMDEwMDFfMDI0RSwKICAgICAgICAgTTg1ID0gQjAxMDAxXzAyNUUsCiAgICAgICAgIEZNNzBfNzQgPSBCMDEwMDFfMDQ2RSwKICAgICAgICAgRk03NV83OSA9IEIwMTAwMV8wNDdFLAogICAgICAgICBGTTgwXzg1ID0gQjAxMDAxXzA0OEUsCiAgICAgICAgIEZNODUgPSBCMDEwMDFfMDQ5RSwKICAgICAgICAgTWVkSEhJbmMgPSBCMTkwMTNfMDAxRSwgCiAgICAgICAgIE1lZFJlbnQgPSBCMjUwNThfMDAxRSwKICAgICAgICAgVG90YWxQb3ZlcnR5ID0gQjA2MDEyXzAwMkUsCiAgICAgICAgIENvbGxlZ2UgPSBCMDYwMDlfMDA1RSwKICAgICAgICAgR3JhZHVhdGUgPSBCMDYwMDlfMDA2RSwKICAgICAgICAgTm9DYXIgPSBCMDgwMTRfMDAyRSwKICAgICAgICAgUmVudGVyID0gQjI1MDI2XzAwOUUsCiAgICAgICAgIEZvcmVpZ25lciA9IEIwNTAwMV8wMDZFCiAgICAgICAgICkgJT4lIAogIGRwbHlyOjpzZWxlY3QoLXN0YXJ0c193aXRoKCJCIikpJT4lCiAgbXV0YXRlKHBjdFdoaXRlID0gaWZlbHNlKFRvdGFsUG9wID4gMCwgV2hpdGVzIC8gVG90YWxQb3AsIDApLAogICAgICAgICBwY3RNaW5vcml0eSA9IGlmZWxzZShUb3RhbFBvcCA+IDAsIChBZnJpY2FuX0FtZXJpY2FucyArIEFzaWFucyArIExhdGlueCApIC8gVG90YWxQb3AsIDApLAogICAgICAgICBwY3RBZ2luZyA9IGlmZWxzZShUb3RhbFBvcCA+IDAsIChNNzBfNzQgKyBNNzVfNzkgKyBNODBfODUgKyBNODUgKyBGTTcwXzc0ICsgRk03NV83OSArIEZNODBfODUgKyBGTTg1ICkgLyBUb3RhbFBvcCwgMCksCiAgICAgICAgIHBjdEJhY2hlbG9ycyA9IGlmZWxzZShUb3RhbFBvcCA+IDAsICgoQ29sbGVnZSArIEdyYWR1YXRlKSAvIFRvdGFsUG9wKSwgMCksCiAgICAgICAgIHBjdFBvdmVydHkgPSBpZmVsc2UoVG90YWxQb3AgPiAwLCBUb3RhbFBvdmVydHkgLyBUb3RhbFBvcCwgMCksCiAgICAgICAgIHBjdE5vQ2FyID0gaWZlbHNlKFRvdGFsUG9wID4gMCwgTm9DYXIgLyBUb3RhbFBvcCwgMCksCiAgICAgICAgIHBjdFJlbnRlciA9IGlmZWxzZShUb3RhbFBvcCA+IDAsIFJlbnRlciAvIFRvdGFsUG9wLCAwKSwKICAgICAgICAgcGN0Rm9yZWlnbmVyID0gaWZlbHNlKFRvdGFsUG9wID4gMCwgRm9yZWlnbmVyIC8gVG90YWxQb3AsIDApLAogICAgICAgICB5ZWFyID0gIjIwMTAiKSAlPiUgCiAgZHBseXI6OnNlbGVjdCgtV2hpdGVzLC1BZnJpY2FuX0FtZXJpY2FucywgLUFzaWFucywgLUxhdGlueCwgLU03MF83NCwgLU03NV83OSwgLU04MF84NSwgLU04NSwgLUZNNzBfNzQsIC1GTTc1Xzc5LCAtRk04MF84NSwgLUZNODUsIC1Db2xsZWdlLCAtR3JhZHVhdGUsIC1Ub3RhbFBvdmVydHksIC1Ob0NhciwgLVJlbnRlciwgLUZvcmVpZ25lcikKCgpgYGAKCmBgYHtyIGdldCBzdWZmb2xrLCB3YXJuaW5nID0gRkFMU0UsIGNhY2hlPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIGluY2x1ZGU9RkFMU0V9ClN1ZmZvbGsgPC0gCiAgZ2V0X2FjcyhnZW9ncmFwaHkgPSAidHJhY3QiLCB2YXJpYWJsZXMgPSAiQjAyMDAxXzAwMUUiLCAKICAgICAgICAgIHllYXI9MjAxMCwgc3RhdGU9J01BJywgY291bnR5PTAyNSwgZ2VvbWV0cnk9VCwgb3V0cHV0PSJ3aWRlIikKYGBgCgoKTm90ZTogQm9zdG9uIGNpdHkgaXMgcGFydCBvZiB0aGUgbGFyZ2VyIFN1ZmZvbGsgY291bnR5IGluIE1hc3NhY2h1c2V0dHMsIHdoaWNoIGFsc28gaW5jbHVkZXMgdGhlIGNpdHkgb2YgQ2hlbHNlYSwgUmV2ZXJlLCBhbmQgV2ludGhyb3AuIFRvIGxpbWl0IG91ciBhbmFseXNpcyB3aXRoaW4gQm9zdG9uLCB3ZSByZW1vdmVkIGFsbCBhcmVhcyBvdXRzaWRlIEJvc3Rvbi4gVGhlIG1hcCBiZWxvdyBzaG93cyBCb3N0b24gcmVsYXRpdmUgdG8gb3RoZXIgY2l0aWVzIGluIFN1ZmZvbGsgY291bnR5LiAgCgoKYGBge3Igc3VmZm9sa19jb3VudHksIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGU9VFJVRX0KCmdncGxvdCgpICsgCiAgZ2VvbV9zZihkYXRhPXN0X3VuaW9uKFN1ZmZvbGspLCBmaWxsPSAiI0QzRDNEMyIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDIpICsKICBnZW9tX3NmKGRhdGE9c3RfdW5pb24oYm9zdG9uMTApLCBmaWxsPSAiI2JkN2ViZSIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIkJvc3RvbiBDaXR5IGluIFN1ZmZvbGsgQ291bnR5IiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDEwIGFuZCAyMDE5IiwKICAgICAgIGNvbG9yID0gIkJvc3RvbiIpICsKICB0aGVtZV9saWdodCgpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIikpICsKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLHggPSAtNzEuMTAseSA9IDQyLjMsIHNpemUgPSA0LCBsYWJlbCA9ICJCb3N0b24iLGNvbG9yID0gIndoaXRlIikgKwogIGFubm90YXRlKGdlb20gPSAidGV4dCIseCA9IC03MS4wNCx5ID0gNDIuNDAsIHNpemUgPSAzLCBsYWJlbCA9ICJDaGVsc2VhIixjb2xvciA9ICJibGFjayIpICsKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLHggPSAtNzEuMDEseSA9IDQyLjQyLCBzaXplID0gMywgbGFiZWwgPSAiUmV2ZXJlIixjb2xvciA9ICJibGFjayIpICsKICBhbm5vdGF0ZShnZW9tID0gInRleHQiLHggPSAtNzAuOTcseSA9IDQyLjM4LCBzaXplID0gMywgbGFiZWwgPSAiV2ludGhyb3AiLGNvbG9yID0gImJsYWNrIikgCgpgYGAKCk5vdywgd2UgcmVwZWF0IHRoZSBzYW1lIHByb2Nlc3MgdG8gb2J0YWluIHRoZSAyMDE5IEFDUyBkYXRhIGFuZCBjb21iaW5lIGl0IHdpdGggdGhlIDIwMTAgZGF0YS4gCgpgYGB7ciBib3N0b25fMjAxOV9kYXRhLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9ImhpZGUifQoKYm9zdG9uMTkgPC0gCiAgZ2V0X2FjcyhnZW9ncmFwaHkgPSAidHJhY3QiLCB2YXJpYWJsZXMgPSBhY3NfdmFyLCAKICAgICAgICAgIHllYXI9MjAxOSwgc3RhdGU9J01BJywgY291bnR5PTAyNSwgZ2VvbWV0cnk9VCwgb3V0cHV0PSJ3aWRlIikgJT4lIAogIHN0X3RyYW5zZm9ybSgnRVBTRzoyNjk4NicpICU+JSAKICBmaWx0ZXIoIShHRU9JRCAlaW4lIHJlbW92ZSkpICU+JSAKICByZW5hbWUoVG90YWxQb3AgPSBCMDIwMDFfMDAxRSwgCiAgICAgICAgIFdoaXRlcyA9IEIwMjAwMV8wMDJFLAogICAgICAgICBBZnJpY2FuX0FtZXJpY2FucyA9IEIwMjAwMV8wMDNFLAogICAgICAgICBBc2lhbnMgPSBCMDIwMDFfMDA1RSwKICAgICAgICAgTGF0aW54ID0gQjAzMDAyXzAxMkUsCiAgICAgICAgIE03MF83NCA9IEIwMTAwMV8wMjJFLAogICAgICAgICBNNzVfNzkgPSBCMDEwMDFfMDIzRSwKICAgICAgICAgTTgwXzg1ID0gQjAxMDAxXzAyNEUsCiAgICAgICAgIE04NSA9IEIwMTAwMV8wMjVFLAogICAgICAgICBGTTcwXzc0ID0gQjAxMDAxXzA0NkUsCiAgICAgICAgIEZNNzVfNzkgPSBCMDEwMDFfMDQ3RSwKICAgICAgICAgRk04MF84NSA9IEIwMTAwMV8wNDhFLAogICAgICAgICBGTTg1ID0gQjAxMDAxXzA0OUUsCiAgICAgICAgIE1lZEhISW5jID0gQjE5MDEzXzAwMUUsIAogICAgICAgICBNZWRSZW50ID0gQjI1MDU4XzAwMUUsCiAgICAgICAgIFRvdGFsUG92ZXJ0eSA9IEIwNjAxMl8wMDJFLAogICAgICAgICBDb2xsZWdlID0gQjA2MDA5XzAwNUUsCiAgICAgICAgIEdyYWR1YXRlID0gQjA2MDA5XzAwNkUsCiAgICAgICAgIE5vQ2FyID0gQjA4MDE0XzAwMkUsCiAgICAgICAgIFJlbnRlciA9IEIyNTAyNl8wMDlFLAogICAgICAgICBGb3JlaWduZXIgPSBCMDUwMDFfMDA2RQogICAgICAgICApICU+JSAKICBkcGx5cjo6c2VsZWN0KC1zdGFydHNfd2l0aCgiQiIpKSAlPiUgCiAgICBtdXRhdGUocGN0V2hpdGUgPSBpZmVsc2UoVG90YWxQb3AgPiAwLCBXaGl0ZXMgLyBUb3RhbFBvcCwgMCksCiAgICAgICAgIHBjdE1pbm9yaXR5ID0gaWZlbHNlKFRvdGFsUG9wID4gMCwgKEFmcmljYW5fQW1lcmljYW5zICsgQXNpYW5zICsgTGF0aW54ICkgLyBUb3RhbFBvcCwgMCksCiAgICAgICAgIHBjdEFnaW5nID0gaWZlbHNlKFRvdGFsUG9wID4gMCwgKE03MF83NCArIE03NV83OSArIE04MF84NSArIE04NSArIEZNNzBfNzQgKyBGTTc1Xzc5ICsgRk04MF84NSArIEZNODUgKSAvIFRvdGFsUG9wLCAwKSwKICAgICAgICAgcGN0QmFjaGVsb3JzID0gaWZlbHNlKFRvdGFsUG9wID4gMCwgKChDb2xsZWdlICsgR3JhZHVhdGUpIC8gVG90YWxQb3ApLCAwKSwKICAgICAgICAgcGN0UG92ZXJ0eSA9IGlmZWxzZShUb3RhbFBvcCA+IDAsIFRvdGFsUG92ZXJ0eSAvIFRvdGFsUG9wLCAwKSwKICAgICAgICAgcGN0Tm9DYXIgPSBpZmVsc2UoVG90YWxQb3AgPiAwLCBOb0NhciAvIFRvdGFsUG9wLCAwKSwKICAgICAgICAgcGN0UmVudGVyID0gaWZlbHNlKFRvdGFsUG9wID4gMCwgUmVudGVyIC8gVG90YWxQb3AsIDApLAogICAgICAgICBwY3RGb3JlaWduZXIgPSBpZmVsc2UoVG90YWxQb3AgPiAwLCBGb3JlaWduZXIgLyBUb3RhbFBvcCwgMCksCiAgICAgICAgIHllYXIgPSAiMjAxOSIpICU+JSAKICBkcGx5cjo6c2VsZWN0KC1XaGl0ZXMsLUFmcmljYW5fQW1lcmljYW5zLCAtQXNpYW5zLCAtTGF0aW54LCAtTTcwXzc0LCAtTTc1Xzc5LCAtTTgwXzg1LCAtTTg1LCAtRk03MF83NCwgLUZNNzVfNzksIC1GTTgwXzg1LCAtRk04NSwgLUNvbGxlZ2UsIC1HcmFkdWF0ZSwgLVRvdGFsUG92ZXJ0eSwgLU5vQ2FyLCAtUmVudGVyLCAtRm9yZWlnbmVyKQoKYWxsVHJhY3RzIDwtIHJiaW5kKGJvc3RvbjEwLGJvc3RvbjE5KQpgYGAKCgojIyBUcmFuc2l0IERhdGEKClRoZSBCb3N0b24gdHJhbnNpdCBkYXRhIGlzIHByb3ZpZGVkIGJ5IFtNYXNzR0lTXShodHRwczovL3d3dy5tYXNzLmdvdi9pbmZvLWRldGFpbHMvbWFzc2dpcy1kYXRhLW1idGEtcmFwaWQtdHJhbnNpdCNvdmVydmlldy0pLCB0aHJvdWdoIHdoaWNoIHdlIGRvd25sb2FkZWQgdGhlIHJhdyBmaWxlIGFuZCB1cGxvYWRlZCBpdCB0byBvdXIgR2l0SHViIHJlcG9zaXRvcnkuIFRvIGVuc3VyZSBkYXRhIGNvbnNpc3RlbmN5LCB3ZSBoYXZlIHJlcG9qZWN0ZWQgdGhpcyBsYXllciBmb3IgaXQgdG8gbWF0Y2ggd2l0aCBvdXIgY2Vuc3VzIGRhdGEsIGFuZCBoYXZlIHJlLWNhdGVnb3JpemVkIHRyYW5zaXQgbGluZXMuIAoKCmBgYHtyIHRyYW5zaXRfZGF0YSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93JywgcmVzdWx0cz0iaGlkZSJ9Cgpib3N0b25fc3RvcHMgPC0gc3RfcmVhZCgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2VtaWx5emhvdTExMi9NVVNBNTA4MC1Cb3N0b24tVE9EL21haW4vZGF0YS9ib3N0b25fc3Rwcy5nZW9qc29uIikgJT4lCiAgc3RfdHJhbnNmb3JtKHN0X2Nycyhib3N0b24xMCkpICU+JSAKICBtdXRhdGUoc3RvcHMgPSBpZmVsc2UoZ3JlcGwoIi8iLCBMSU5FKSwgIk9USEVSIiwgTElORSkpIAoKCmBgYAoKVGhlIE1CVEEgUmFwaWQgVHJhbnNpdCBsYXllcnMgcmVwcmVzZW50IHRoZSBjb3JlIHN1YndheSBzeXN0ZW0gbGluZXMgYW5kIHN0YXRpb25zIHdpdGhpbiB0aGUgR3JlYXRlciBCb3N0b24gYXJlYS4gVGhlcmUgYXJlIGZpdmUgc3Vid2F5cyBsaW5lcyBpbiBCb3N0b246IFJlZCwgR3JlZW4sIE9yYW5nZSwgQmx1ZSwgYW5kIFNpbHZlciwgd2hpY2ggc2VydmljZXMgbWFueSBCb3N0b24gbmVpZ2hib3Job29kcyBwbHVzIHBhcnRzIG9mIENhbWJyaWRnZSwgU29tZXJ2aWxsZSwgUmV2ZXJlLCBNYWxkZW4sIEJyb29rbGluZSwgTmV3dG9uLCBNaWx0b24sIGFuZCBRdWluY3kuIFRvIGxpbWl0IG91ciBzY29wZSBvZiBhbmFseXNpcyB3aXRoaW4gQm9zdG9uLCB3ZSBoYXZlIHJlbW92ZWQgc3Vid2F5IHN0YXRpb25zIG91dHNpZGUgb2YgQm9zdG9uLiBUaGUgbWFwIGJlbG93IHNob3dzIHRyYW5zaXQgc3RvcHMgdXNlZCBpbiBvdXIgc3R1ZHkgYXMgd2VsbCBhcyB0aG9zZSB0aGF0IHdlIGhhdmUgZXhjbHVkZWQuIAoKYGBge3IgdmlzdWFsaXplX3N0b3BzLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHM9ImhpZGUifQoKTUJUQSA8LSBzdF9yZWFkKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZW1pbHl6aG91MTEyL01VU0E1MDgwLUJvc3Rvbi1UT0QvbWFpbi9kYXRhL01CVEFfbm9kZS5nZW9qc29uIikgJT4lCiAgc3RfdHJhbnNmb3JtKHN0X2Nycyhib3N0b24xMCkpCgpnZ3Bsb3QoKSArIAogIGdlb21fc2YoZGF0YT1zdF91bmlvbihib3N0b24xMCksIGZpbGw9ICIjRDNEM0QzIiwgY29sb3IgPSAid2hpdGUiLCBzaXplID0gMikgKwogIGdlb21fc2YoZGF0YT1NQlRBLCBjb2xvciA9ICJibGFjayIsIHNpemU9IDEpICsgCiAgZ2VvbV9zZihkYXRhPWJvc3Rvbl9zdG9wcywgCiAgICAgICAgICBhZXMoY29sb3VyID0gc3RvcHMgJT4lIHN0cl90b190aXRsZSgpKSwKICAgICAgICAgIHNob3cubGVnZW5kID0gInBvaW50Iiwgc2l6ZT0gMS41KSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiIzdlYjBkNSIsIiNiMmUwNjEiLCAiI2ZmYjU1YSIsICIjZmZlZTY1IiwgIiNmZDdmNmYiLCAiI2JkN2ViZSIpKSArCiAgbGFicyh0aXRsZSA9ICJCb3N0b24gTUJUQSBSYXBpZCBUcmFuc2l0IFN0b3BzIiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogTWFzc0dJUyAyMDIyIiwKICAgICAgIGNvbG91ciA9ICJMaW5lcyIpICsKICB0aGVtZV9saWdodCgpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIikpCgpgYGAKClRvIGRlbGluZWF0ZSBjZW5zdXMgdHJhY3RzIHRoYXQgYXJlIGluIGNsb3NlIHByb3hpbWl0eSB0byB0cmFuc2l0IHN0YXRpb25zLCB3ZSBkZWxpbmVhdGVkIGEgaGFsZiBtaWxlIGFyZWEgZm9yIGVhY2ggdHJhbnNpdCBzdGF0aW9ucywgYW5kIGNvbXBhcmVkIHRoZW0gdG8gYWxsIHRoZSBjZW50cm9pZHMgKGNlbnRlciBwb25pdHMpIG9mIGNlbnN1cyB0cmFjdHMuIElmIHRoZSBjZW50cm9pZCBpcyBsb2NhdGVkIHdpdGhpbiB0aGUgaGFsZiBtaWxlIGFyZWEsIHdlIGNhdGVnb3JpemUgdGhhdCB0cmFjdCBhcyAiVE9EIjsgb3RoZXJ3aXNlLCB0aGlzIHRyYWN0IGlzIGNvbnNpZGVyZWQgIk5vbi1UT0QiLiBBbiBhZGRpdGlvbmFsIGRhdGEgbWFuaXB1bGF0aW9uIGhlcmUgaXMgdG8gYWRqdXN0IG1lZGlhbiByZW50IGFuZCBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBmb3IgaW5mbGF0aW9uLiAgCgpgYGB7ciBkZWxpbmVhdGVfVE9ELCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQoKc3RvcHNfYnVmZmVyIDwtIHN0X3VuaW9uKHN0X2J1ZmZlcihib3N0b25fc3RvcHMsIDgwNCkpICU+JSBzdF9zZigpIAoKYWxsVHJhY3RzLmdyb3VwIDwtIAogIHJiaW5kKAogICAgc3RfY2VudHJvaWQoYWxsVHJhY3RzKVtzdG9wc19idWZmZXIsXSAlPiUKICAgICAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogICAgICBsZWZ0X2pvaW4oYWxsVHJhY3RzKSAlPiUKICAgICAgc3Rfc2YoKSAlPiUKICAgICAgbXV0YXRlKFRPRCA9ICJUT0QiKSwKICAgIHN0X2NlbnRyb2lkKGFsbFRyYWN0cylbc3RvcHNfYnVmZmVyLCBvcCA9IHN0X2Rpc2pvaW50XSAlPiUKICAgICAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogICAgICBsZWZ0X2pvaW4oYWxsVHJhY3RzKSAlPiUKICAgICAgc3Rfc2YoKSAlPiUKICAgICAgbXV0YXRlKFRPRCA9ICJOb24tVE9EIikpICU+JQogIG11dGF0ZShNZWRSZW50LmluZiA9IGlmZWxzZSh5ZWFyID09ICIyMDEwIiwgTWVkUmVudCAqIDEuMTcsIE1lZFJlbnQpKSAlPiUgCiAgbXV0YXRlKE1lZEhISW5jLmluZiA9IGlmZWxzZSh5ZWFyID09ICIyMDEwIiwgTWVkSEhJbmMgKiAxLjE3LCBNZWRISEluYykpIAoKYGBgCgpUaGUgbWFwIGJlbG93IHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgVE9EIGFuZCBOb24tVE9EIHRyYWN0cyBpbiBCb3N0b24sIHVzaW5nIHRoZSBhYm92ZSBtZXRob2QuIAoKYGBge3IgdmlzdWFsaXplX3RvZCwgIHdhcm5pbmcgPSBGQUxTRX0KCmFsbFRyYWN0cy5ncm91cCAlPiUgCiAgZmlsdGVyKHllYXIgPT0gMjAxMCApICU+JSAKICBnZ3Bsb3QoKSArIAogIGdlb21fc2YoYWVzKGZpbGwgPSBUT0QpLCBjb2xvciA9ICJ0cmFuc3BhcmVudCIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjN2ViMGQ1IiwgIiNiMmUwNjEiKSkgKyAKICBnZW9tX3NmKGRhdGE9Ym9zdG9uX3N0b3BzLCAKICAgICAgICAgIGNvbG9yID0gIiNmZDdmNmYiLCBzaXplPSAwLjgpKwogIGxhYnModGl0bGUgPSAiVHJhbnNpZW50IE9yaWVudGVkIERldmVsb3BtZW50IFRyYWN0cyIsCiAgICAgICBzdWJ0aXRsZSA9ICJUcmFjdHMgd2l0aGluIDAuNSBtaWxlIG9mIHRyYW5zaXQgc3RvcHMiLAogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTAgYW5kIDIwMTkiLAogICAgICAgZmlsbCA9ICJUcmFjdHMgVHlwZXMiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSkKCgpgYGAKCiMgRGF0YSBBbmFseXNpcwoKIyMgRGVtb2dyYXBoaWMgQ2hhcmFjdGVyaXN0aWNzIAoKV2UgZmlyc3QgbG9va2VkIGF0IHRoZSB0ZW1wb3JhbCBjaGFuZ2VzIGluICoqYWdpbmcgcG9wdWxhdGlvbioqIGRpc3RyaWJ1dGlvbi4gVGhlIG1hcCBiZWxvdyByZXZlYWxzIHRoYXQgdGhlIG51bWJlciBvZiBwb3B1bGF0aW9ucyB0aGF0IGFyZSA3MCBhbmQgYWJvdmUgaW5jcmVhc2VzIGluIEJvc3RvbiBvdmVyYWxsLiBZZXQsIG1vc3QgYWdpbmcgcG9wdWxhdGlvbiBsaXZlIGluIE5vbi1UT0QgdHJhY3RzLiBUaGlzIHBhdHRlcm4gaXMgY29uc2lzdGVudCB0aHJvdWdoIHRoZSB5ZWFycyBhcyB3ZSBjYW4gc2VlIHRoYXQgVE9EIHRyYWN0cyBhcmUgcmVsYXRpdmVseSAieW91bmdlciIgdGhhbiBOb24tVE9EIHRyYWN0cy4gVGhpcyBsb29zZWx5IGltcGxpZXMgdGhhdCBpbiBCb3N0b24sIHRyYW5zaXQtcmljaCBuZWlnaGJvcmhvb2RzIGFyZSBmYXZvcmVkIGJ5IHRoZSB5b3VuZ2VyIGNvaG9ydCwgcHJvYmFibHkgYmVjYXVzZSB0aG9zZSBwZW9wbGUgaGF2ZSBhIGhpZ2hlciBkZW1hbmQgZm9yIHRyYW5zaXQgdG8gZ2V0IHRvIHNjaG9vbCBhbmQgd29yay4gCgpgYGB7ciBwZXJjZW50YWdlX2FnaW5nLCB3YXJuaW5nID0gRkFMU0V9CgphbGxUcmFjdHMuZ3JvdXAgJT4lIAogIGdncGxvdCgpKwogIGdlb21fc2YoYWVzKGZpbGw9cGN0QWdpbmcpLCBjb2xvcj0idHJhbnNwYXJlbnQiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICIjRkFGOUY2IiwgaGlnaCA9ICJibHVlNCIsIG5hbWU9ICJQZXJjZW50YWdlIEFnaW5nIiwgYnJlYWtzID0gYygwLCAwLjEsIDAuMiwgMC4zKSkrCiAgZmFjZXRfd3JhcCh+eWVhcikgKwogIGdlb21fc2YoZGF0YT1zdG9wc19idWZmZXIsIGNvbG9yID0gInJlZCIsIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBsaW5ld2lkdGggPSAwLjQpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5IiwgZmlsbD1OQSwgc2l6ZT0wLjgpCiAgICAgICAgKSArIAogIGxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBvZiBBZ2luZyBQb3B1bGF0aW9uIGluIEJvc3RvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJSZWQgY2lyY2xlcyBpbmRpY2F0ZSBhcmVhcyB3aXRoaW4gMC41IG1pbGUgb2YgYSB0cmFuc2l0IHN0b3BzIiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDEwIGFuZCAyMDE5IFxuIE1hc3NHSVMgMjAyMiIpIAogCgpgYGAKCldlIHRoZW4gbG9va2VkIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgKipOb24tVVMgY2l0aXplbnMqKiBpbiBCb3N0b24uIFdlIHNlbGVjdGVkIHRoaXMgZGVtb2dyYXBoaWMgdmFyaWFibGUgYmVjYXVzZSB3ZSBleHBlY3RlZCB0aGF0IG5vbi1VUyBjaXRpemVucyBhcmUgbW9yZSBsaWtlbHkgdG8gbGl2ZSBpbiB0cmFuc2l0LXJpY2ggbmVpZ2hib3Job29kcyBiZWNhdXNlIHRoZXNlIHBsYWNlcyBvZnRlbiBwcm92aWRlIGVhc3kgYWNjZXNzIHRvIG1ham9yIGpvYiBjZW50ZXJzLCBidXNpbmVzcyBkaXN0cmljdHMsIGFuZCBlbXBsb3ltZW50IG9wcG9ydHVuaXRpZXMsIHdoaWNoIGlzIGVzcGVjaWFsbHkgYXR0cmFjdGl2ZSB0byBmb3JlaWduZXJzIHNlZWtpbmcgZW1wbG95bWVudCBpbiB1cmJhbiBhcmVhcy4gWWV0LCB0aGUgbWFwIGJlbG93IHJldmVhbHMgb25seSBhIHNsaWdodCBkaWZmZXJlbmNlIGJldHdlZW4gbnVtYmVyIG9mIG5vbi1VUyBjaXRpemVucyBiZXR3ZWVuIFRPRCBhbmQgTm9uLVRPRCB0cmFjdHMsIHdoZXJlIFRPRCB0cmFjdHMgYXR0cmFjdCBzbGlnaHRseSBtb3JlIGZvcmVpZ25lcnMgdGhhbiBOb24tVE9EIHRyYWN0cywgYW5kIHRoaXMgcGF0dGVybiBpcyBjb25zaXN0ZW50IHRocm91Z2hvdXQgeWVhcnMuIAoKYGBge3IgcGVyY2VudF9mb3JlaWduZXIsIHdhcm5pbmcgPSBGQUxTRX0KCmFsbFRyYWN0cy5ncm91cCAlPiUgCiAgZ2dwbG90KCkrCiAgZ2VvbV9zZihhZXMoZmlsbD1wY3RGb3JlaWduZXIpLCBjb2xvcj0idHJhbnNwYXJlbnQiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICIjRkFGOUY2IiwgaGlnaCA9ICJibHVlNCIsIG5hbWU9ICJQZXJjZW50YWdlIEZvcmVpZ25lciIsIGJyZWFrcyA9IGMoMCwgMC4yLCAwLjQsIDAuNikpKwogIGZhY2V0X3dyYXAofnllYXIpICsKICBnZW9tX3NmKGRhdGE9c3RvcHNfYnVmZmVyLCBjb2xvciA9ICJyZWQiLCBmaWxsID0gInRyYW5zcGFyZW50IiwgbGluZXdpZHRoID0gMC40KSArCiB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5IiwgZmlsbD1OQSwgc2l6ZT0wLjgpCiAgICAgICAgKSArIAogIGxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBvZiBOb24tVVMgQ2l0aXplbnMgaW4gQm9zdG9uIiwKICAgICAgIHN1YnRpdGxlID0gIlJlZCBjaXJjbGVzIGluZGljYXRlIGFyZWFzIHdpdGhpbiAwLjUgbWlsZSBvZiBhIHRyYW5zaXQgc3RvcHMiLAogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTAgYW5kIDIwMTkgXG4gTWFzc0dJUyAyMDIyIikgCiAKYGBgCgpXZSBhbHNvIGxvb2tlZCBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mICoqcmFjaWFsIG1pbm9yaXR5IHBvcHVsYXRpb24qKiBpbiBCb3N0b24uIFRoZSBtYXAgYmVsb3cgc2hvd3MgdGhhdCBtaW5vcml0eSBwb3B1bGF0aW9uIGFyZSBjb25jZW50cmF0ZWQgaW4gc291dGhlcm4gQm9zdG9uLCBtYWlubHkgaW4gUm94YnVyeSBhbmQgRG9yY2hlc3Rlci4gTW9yZSBpbXBvcnRhbnRseSwgdGhlc2UgbmVpZ2hib3Job29kcyBhcmUgbW9zdGx5IG1hZGUgdXAgb2YgTm9uLVRPRCB0cmFjdHMuIFRoaXMgcGF0dGVybiBpcyBjb25zaXN0ZW50IG92ZXIgdGltZSBhbmQgaW4gMjAxOSwgd2UgYXJlIHNlZWluZyBhbiBpbmNyZWFzaW5nIG51bWJlciBvZiBtaW5vcml0eSBwb3B1bGF0aW9uIGxpdmluZyBpbiB0aGUgc2FtZSBuZWlnaGJvcmhvb2RzIGFzIGluIDIwMTAuIAoKYGBge3IgcGVyY2VudF9taW5vcml0aWVzLCB3YXJuaW5nID0gRkFMU0V9CmFsbFRyYWN0cy5ncm91cCAlPiUgCiAgZ2dwbG90KCkrCiAgZ2VvbV9zZihhZXMoZmlsbD1wY3RNaW5vcml0eSksIGNvbG9yPSJ0cmFuc3BhcmVudCIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gIiNGQUY5RjYiLCBoaWdoID0gImJsdWU0IiwgbmFtZT0gIlBlcmNlbnRhZ2UgTWlub3JpdHkiLCBicmVha3MgPSBjKDAsIDAuMywgMC42LCAwLjkpKSsKICBmYWNldF93cmFwKH55ZWFyKSArCiAgZ2VvbV9zZihkYXRhPXN0b3BzX2J1ZmZlciwgY29sb3IgPSAicmVkIiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGxpbmV3aWR0aCA9IDAuNCkgKwogdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGw9TkEsIHNpemU9MC44KQogICAgICAgICkgKyAKICBsYWJzKHRpdGxlID0gIlBlcmNlbnRhZ2Ugb2YgTWlub3JpdGllcyBpbiBCb3N0b24iLAogICAgICAgc3VidGl0bGUgPSAiUmVkIGNpcmNsZXMgaW5kaWNhdGUgYXJlYXMgd2l0aGluIDAuNSBtaWxlIG9mIGEgdHJhbnNpdCBzdG9wcyIsCiAgICAgICBjYXB0aW9uID0gIkRhdGE6IEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgMjAxMCBhbmQgMjAxOSBcbiBNYXNzR0lTIDIwMjIiKSAKYGBgCgoKIyMgRWNvbm9taWMgQ2hhcmFjdGVyaXN0aWNzCgpGb3IgZWNvbm9taWMgdmFyaWFibGVzLCB3ZSBmaXJzdCBsb29rZWQgYXQgKiptZWRpYW4gcmVudCoqIGluIEJvc3Rvbi4gVGhlIG1hcCBiZWxvdyByZXZlYWxzIHRoYXQgcmVudCBpcyBzaWduaWZpY2FudGx5IGhpZ2hlciBpbiBUT0QgdHJhY3RzIHRoYW4gTm9uLVRPRCB0cmFjdHMgaW4gYm90aCAyMDEwIGFuZCAyMDE5LiBUaGlzIGltcGxpZXMgdGhhdCB0cmFuc2l0LXJpY2ggbmVpZ2hib3Job29kcyBhcmUgYWxzbyBtb3JlIGV4cGVuc2l2ZS4gSW4gYWRkaXRpb24sIGFmdGVyIGFkanVzdGluZyBmb3IgaW5mbGF0aW9uLCB3ZSBhbHNvIHNlZSB0aGF0IG1lZGlhbiByZW50IGhhcyBpbmNyZWFzZWQgc2lnbmlmaWNhbnRseSBpbiBhbGwgY2Vuc3VzIHRyYWN0cyBpbiBCb3N0b24sIGFuZCB0aGlzIGluY3JlYXNlIGluIHJlbnQgaXMgbW9zdCBzYWxpZW50IGluIGNpdHkgY2VudGVyLCB3aGVyZSBtdWx0aXBsZSB0cmFuc2l0IGxpbmVzIG1lZXQuIAoKYGBge3IgbWVkaWFuX3JlbnQsIHdhcm5pbmcgPSBGQUxTRX0KCmFsbFRyYWN0cy5ncm91cCAlPiUgCiAgZ2dwbG90KCkrCiAgZ2VvbV9zZihhZXMoZmlsbD1NZWRSZW50LmluZiksIGNvbG9yPSJ0cmFuc3BhcmVudCIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gIiNGQUY5RjYiLCBoaWdoID0gInNlYWdyZWVuNCIsIG5hbWU9ICJSZW50IikrCiAgZmFjZXRfd3JhcCh+eWVhcikgKwogIGdlb21fc2YoZGF0YT1zdG9wc19idWZmZXIsIGNvbG9yID0gInJlZCIsIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBsaW5ld2lkdGggPSAwLjQpICsKICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGw9TkEsIHNpemU9MC44KQogICAgICAgICkgKyAKICBsYWJzKHRpdGxlID0gIk1lZGlhbiBSZW50IGluIEJvc3RvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJSZWQgY2lyY2xlcyBpbmRpY2F0ZSBhcmVhcyB3aXRoaW4gMC41IG1pbGUgb2YgYSB0cmFuc2l0IHN0b3BzIFxuMjAxOSBkYXRhIGFkanVzdGVkIGZvciBpbmZsYXRpb24iLAogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTAgYW5kIDIwMTkgXG4gTWFzc0dJUyAyMDIyIikgCgpgYGAKCkxvb2tpbmcgYXQgdGhlIHBlcmNlbnRhZ2Ugb2YgKipwZW9wbGUgdW5kZXIgcG92ZXJ0eSoqIGluIEJvc3Rvbiwgd2UgY2FuIHNlZSB0aGF0IGluIGJvdGggMjAxMCBhbmQgMjAxOSwgbmVpZ2hib3Job29kcyBpbiBzb3V0aGVybiBCb3N0b24gKFJveGJ1cnkgYW5kIERvcmNoZXN0ZXIpIGhhdmUgaGlnaGVyIHBvdmVydHkgcmF0ZXMgdGhhbiBvdGhlciBuZWlnaGJvcmhvb2RzLiBUaGVzZSBuZWlnaGJvcmhvb2RzIGFyZSBtb3N0bHkgbG9jYXRlZCBpbiBOb24tVE9EIHRyYWN0cy4gWWV0LCB3ZSBhcmUgYWxzbyBhYmxlIHRvIHNlZSBwb3ZlcnR5IHJhdGUgaXMgZGVjcmVhc2luZyBvdmVyIHRoZSB5ZWFycy4gSW4gMjAxMCwgYSBzaWduaWZpY2FudCBudW1iZXIgb2YgVE9EIHRyYWN0cyBpbiB3ZXN0ZXJuIEJvc3RvbiBoYXZlIGhpZ2hlciBwb3ZlcnR5IHJhdGUgdGhhbiBvdGhlcnMuIEluIDIwMTksIGhvd2V2ZXIsIHdlIHNlZSB0aGF0IHRoZSBjb25kaXRpb24gaW1wcm92ZWQsIHdpdGggbW9zdCBjZW5zdXMgdHJhY3Qgd2l0aCBoaWdoZXIgcG92ZXJ0eSByYXRlIGNvbmNlbnRyYXRlZCBpbiBzb3V0aCBCb3N0b24uICAKCmBgYHtyIHBvdmVydHksIHdhcm5pbmcgPSBGQUxTRX0KCmFsbFRyYWN0cy5ncm91cCAlPiUgCiAgZ2dwbG90KCkrCiAgZ2VvbV9zZihhZXMoZmlsbD1wY3RQb3ZlcnR5KSwgY29sb3I9InRyYW5zcGFyZW50IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiI0ZBRjlGNiIsIGhpZ2ggPSAic2VhZ3JlZW40IiwgbmFtZT0gIlBlcmNlbnRhZ2UgUG92ZXJ0eSIpKwogIGZhY2V0X3dyYXAofnllYXIpICsKICBnZW9tX3NmKGRhdGE9c3RvcHNfYnVmZmVyLCBjb2xvciA9ICJyZWQiLCBmaWxsID0gInRyYW5zcGFyZW50IiwgbGluZXdpZHRoID0gMC40KSArCiB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5IiwgZmlsbD1OQSwgc2l6ZT0wLjgpCiAgICAgICAgKSArIAogIGxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBQb3ZlcnR5IGluIEJvc3RvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJSZWQgY2lyY2xlcyBpbmRpY2F0ZSBhcmVhcyB3aXRoaW4gMC41IG1pbGUgb2YgYSB0cmFuc2l0IHN0b3BzIiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDEwIGFuZCAyMDE5IFxuIE1hc3NHSVMgMjAyMiIpCgpgYGAKClRoZSAqKm1lZGlhbiBob3VzZWhvbGQgaW5jb21lKiogZGF0YSBpcyBub3QgaWRlYWwgYXMgaXQgY29udGFpbnMgYSBsb3Qgb2YgbWlzc2luZyBkYXRhIGVudHJpZXMuIEhvd2V2ZXIsIGl0IHN0aWxsIGluZm9ybXMgdXMgdGhhdCBpbiBib3RoIDIwMTAgYW5kIDIwMTksIGhvdXNlaG9sZHMgbGl2aW5nIGluIFRPRCB0cmFjdHMgaGF2ZSBoaWdoZXIgbWVkaWFuIGhvdXNlaG9sZCBpbmNvbWUuIFRoaXMgaXMgY29uc2lzdGVudCB3aXRoIHByZXZpb3VzIG1hcHMsIHdoZXJlIFRPRCB0cmFjdHMgYWxzbyBoYXZlIGhpZ2hlciByZW50IGFuZCBsb3dlciBwb3ZlcnR5IHJhdGVzLiBJdCBpcyBhbHNvIHdvcnRoIHBvaW50aW5nIG91dCB0aGF0IG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGluIFRPRCB0cmFjdHMgaXMgdGhlIGhpZ2hlc3QgaW4gdGhlIGNpdHkgY2VudGVyLiBBcyB0aGUgZGlzdGFuY2UgZnJvbSBjaXR5IGNlbnRlciBpbmNyZWFzZXMsIHRoZSBkaWZmZXJlbmNlIGluIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGJldHdlZW4gVE9EIGFuZCBOb24tVE9EIHRyYWN0cyBiZWNvbWUgbGVzcyBwcm9taW5lbnQuIAoKYGBge3IgbWVkaWFuX2luY29tZSwgd2FybmluZyA9IEZBTFNFfQoKYWxsVHJhY3RzLmdyb3VwICU+JSAKICBtdXRhdGUoaW5jID0gTWVkSEhJbmMuaW5mLzEwMDApICU+JSAKICBnZ3Bsb3QoKSsKICBnZW9tX3NmKGFlcyhmaWxsPWluYyksIGNvbG9yPSJ0cmFuc3BhcmVudCIpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXMobG93ID0gIiNGQUY5RjYiLCBoaWdoID0gInNlYWdyZWVuNCIsIG5hbWU9ICJJbmNvbWUgKHRob3VzYW5kcykiKSsKICBmYWNldF93cmFwKH55ZWFyKSArCiAgZ2VvbV9zZihkYXRhPXN0b3BzX2J1ZmZlciwgY29sb3IgPSAicmVkIiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGxpbmV3aWR0aCA9IDAuNCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsPU5BLCBzaXplPTAuOCkKICAgICAgICApICsgCiAgbGFicyh0aXRsZSA9ICJNZWRpYW4gSG91c2Vob2xkIEluY29tZSBpbiBCb3N0b24iLAogICAgICAgc3VidGl0bGUgPSAiUmVkIGNpcmNsZXMgaW5kaWNhdGUgYXJlYXMgd2l0aGluIDAuNSBtaWxlIG9mIGEgdHJhbnNpdCBzdG9wc1xuMjAxOSBkYXRhIGFkanVzdGVkIGZvciBpbmZsYXRpb24iLAogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTAgYW5kIDIwMTkgXG4gTWFzc0dJUyAyMDIyIikKCmBgYAoKCiMjIFNvY2lhbCBDaGFyYWN0ZXJpc3RpY3MgCgpGcm9tIHRoZSBtYXAgYmVsb3csIHdlIGNhbiBzZWUgdGhhdCBpbiBib3RoIDIwMTAgYW5kIDIwMTksIHRoZSBtYWpvcml0eSBvZiBob3VzZXMgaW4gQm9zdG9uIGFyZSAqKnJlbnRlciBvY2N1cGllZCoqLCB3aXRoIGhvdXNlcyBpbiBUT0QgdHJhY3RzLCBlc3BlY2lhbGx5IHRob3NlIHRyYWN0cyBpbiBjaXR5IGNlbnRlciwgYXBwZWFyIHNsaWdodGx5IG1vcmUgcHJlZmVyYWJsZSB0byByZW50ZXJzLiBDb25zaWRlcmluZyB0aGF0IHRoZXJlIGFyZSBhIGxvdCBvZiB1bml2ZXJzaXRpZXMgaW4gQm9zdG9uIGFuZCB0aGF0IHNvbWUgb2YgdGhlc2UgdW5pdmVyc2l0aWVzIGhhdmUgdGhlaXIgb3duIHRyYW5zaXQgc3RhdGlvbiBvbiBjYW1wdXMsIHdlIHN1c3BlY3QgdGhhdCBhIGxhcmdlIG51bWJlciBvZiByZW50ZXJzIG9mIHN0dWRlbnRzLCB3aG8gY2hvc2UgdG8gbGl2ZSBhcm91bmQuICAKCmBgYHtyIHJlbnRlcnMsIHdhcm5pbmcgPSBGQUxTRX0KCmFsbFRyYWN0cy5ncm91cCAlPiUgCiAgZ2dwbG90KCkrCiAgZ2VvbV9zZihhZXMoZmlsbD1wY3RSZW50ZXIpLCBjb2xvcj0idHJhbnNwYXJlbnQiKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICIjRkFGOUY2IiwgaGlnaCA9ICIjMDA0N0FCIiwgbmFtZT0gIlBlcmNlbnRhZ2UgUmVudGVycyIpKwogIGZhY2V0X3dyYXAofnllYXIpICsKICBnZW9tX3NmKGRhdGE9c3RvcHNfYnVmZmVyLCBjb2xvciA9ICJyZWQiLCBmaWxsID0gInRyYW5zcGFyZW50IiwgbGluZXdpZHRoID0gMC40KSArCiAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsPU5BLCBzaXplPTAuOCkKICAgICAgICApICsgCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50YWdlIFJlbnRlcnMgaW4gQm9zdG9uIiwKICAgICAgIHN1YnRpdGxlID0gIlJlZCBjaXJjbGVzIGluZGljYXRlIGFyZWFzIHdpdGhpbiAwLjUgbWlsZSBvZiBhIHRyYW5zaXQgc3RvcHMiLAogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTAgYW5kIDIwMTkgXG4gTWFzc0dJUyAyMDIyIikgCgpgYGAKCldlIHNlZSBhIGNsZWFyIGRpZmZlcmVuY2UgaW4gc3BhdGlhbCBwYXR0ZXJuIGhlcmUgd2hlbiBjb25zaWRlcmluZyB3aGV0aGVyIHBlb3BsZSBsaXZpbmcgaW4gQm9zdG9uICoqb3duIGEgY2FyKiogb3Igbm90LiBDb21wYXJlZCB0byBOb24tVE9EIHRyYWN0cywgYSBzaWduaWZpY2FudGx5IGhpZ2hlciBudW1iZXIgb2YgcGVvcGxlIGluIFRPRCB0cmFjdHMgZG8gbm90IGhhdmUgYSBjYXIuIFRoaXMgY291bGQgaW1wbHkgdGhhdCBwZW9wbGUgY2hvc2UgdG8gbGl2ZSBpbiB0cmFuc2l0LXJpY2ggbmVpZ2hib3Job29kIGJlY2F1c2Ugb2YgdGhlICJ0cmFuc2l0IiBpdHNlbGYuICAKCmBgYHtyIG5vX2Nhciwgd2FybmluZyA9IEZBTFNFfQoKYWxsVHJhY3RzLmdyb3VwICU+JSAKICBnZ3Bsb3QoKSsKICBnZW9tX3NmKGFlcyhmaWxsPXBjdE5vQ2FyKSwgY29sb3I9InRyYW5zcGFyZW50IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiI0ZBRjlGNiIsIGhpZ2ggPSAiIzAwNDdBQiIsIG5hbWU9ICJQZXJjZW50YWdlIE5vIFZlaGljbGUiLCBicmVha3MgPSBjKDAsIDAuMiwgMC40LCAwLjYpKSsKICBmYWNldF93cmFwKH55ZWFyKSArCiAgZ2VvbV9zZihkYXRhPXN0b3BzX2J1ZmZlciwgY29sb3IgPSAicmVkIiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGxpbmV3aWR0aCA9IDAuNCkgKwogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5IiwgZmlsbD1OQSwgc2l6ZT0wLjgpCiAgICAgICAgKSArIAogIGxhYnModGl0bGUgPSAiUGVyY2VudGFnZSBvZiBQb3B1bGF0aW9uIHdpdGhvdXQgQ2FyIGluIEJvc3RvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJSZWQgY2lyY2xlcyBpbmRpY2F0ZSBhcmVhcyB3aXRoaW4gMC41IG1pbGUgb2YgYSB0cmFuc2l0IHN0b3BzIiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDEwIGFuZCAyMDE5IFxuIE1hc3NHSVMgMjAyMiIpIAoKCmBgYAoKTGFzdGx5LCB3ZSBsb29rZWQgYXQgKiplZHVjYXRpb24gYXR0YWlubWVudCoqIGZvciBCb3N0b25pYW5zLiBGcm9tIDIwMTAgdG8gMjAxOSwgdGhlIG51bWJlciBvZiBwZW9wbGUgd2l0aCBhIGxlYXN0IGEgYmFjaGVsb3LigJlzIGRlZ3JlZSBpbmNyZWFzZWQgaW4gQm9zdG9uLCBhbmQgdGhpcyBpbmNyZWFzZSBpcyB0aGUgbW9zdCBzYWxpZW50IGluIFRPRCB0cmFjdHMuIEFnYWluLCBjZW5zdXMgdHJhY3RzIHdpdGggbG93IGVkdWNhdGlvbiBhdHRhaW5tZW50IGFyZSBOb24tVE9EIHRyYWN0cywgYW5kIGFyZSBjb25jZW50cmF0ZWQgaW4gc291dGggQm9zdG9uLiAKCgpgYGB7ciBwZXJjZW50YWdlX2JhY2hlbG9yLCB3YXJuaW5nID0gRkFMU0V9CgphbGxUcmFjdHMuZ3JvdXAgJT4lIAogIGdncGxvdCgpKwogIGdlb21fc2YoYWVzKGZpbGw9cGN0QmFjaGVsb3JzKSwgY29sb3I9InRyYW5zcGFyZW50IikgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyhsb3cgPSAiI0ZBRjlGNiIsIGhpZ2ggPSAiIzAwNDdBQiIsIG5hbWU9ICJQZXJjZW50YWdlIEJhY2hlbG9ycyIsIGJyZWFrcyA9IGMoMCwgMC4zLCAwLjYsIDAuOSkpKwogIGZhY2V0X3dyYXAofnllYXIpICsKICBnZW9tX3NmKGRhdGE9c3RvcHNfYnVmZmVyLCBjb2xvciA9ICJyZWQiLCBmaWxsID0gInRyYW5zcGFyZW50IiwgbGluZXdpZHRoID0gMC40KSArCiAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsPU5BLCBzaXplPTAuOCkKICAgICAgICApICsgCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50YWdlIG9mIFBvcHVsYXRpb24gd2l0aCBhdCBMZWFzdCBhIEJhY2VobG9yJ3MgRGVncmVlIGluIEJvc3RvbiIsCiAgICAgICBzdWJ0aXRsZSA9ICJSZWQgY2lyY2xlcyBpbmRpY2F0ZSBhcmVhcyB3aXRoaW4gMC41IG1pbGUgb2YgYSB0cmFuc2l0IHN0b3BzIiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDEwIGFuZCAyMDE5IFxuIE1hc3NHSVMgMjAyMiIpIAoKYGBgCgojIyBRdWljayBTdW1tYXJ5IAoKVG8gc3VwcG9ydCBvdXIgb2JzZXJ2YXRpb25zIGFib3ZlLCB3ZSBmdXJ0aGVyIGNhbGN1bGF0ZWQgdGhlIG1lYW4gZm9yIGFsbCBvZiBvdXIgdmFyaWFibGVzLCB3aGljaCBhbGxvd3MgdXMgdG8gYmV0dGVyIGV4YW1pbmUgY2hhbmdlcyBpbiBwb3B1bGF0aW9uIGNoYXJhY3RlcmlzdGljcyBhY3Jvc3Mgc3BhY2UgYW5kIHRpbWUgYXMgYSB3aG9sZS4gCgpgYGB7ciBhbGxfdmFyaWFibGVzX3N1bW1hcml6ZSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93JywgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0V9CgphbGxUcmFjdHMuU3VtbWFyeSA8LSAKICBzdF9kcm9wX2dlb21ldHJ5KGFsbFRyYWN0cy5ncm91cCkgJT4lCiAgZ3JvdXBfYnkoeWVhciwgVE9EKSAlPiUKICBzdW1tYXJpemUoUmVudCA9IG1lYW4oTWVkUmVudC5pbmYsIG5hLnJtID0gVCksCiAgICAgICAgICAgIEluY29tZSA9IG1lYW4oTWVkSEhJbmMuaW5mLCBuYS5ybSA9IFQpLAogICAgICAgICAgICBQb3AgPSBtZWFuKFRvdGFsUG9wLCBuYS5ybSA9IFQpLAogICAgICAgICAgICBQY3RNaW5vcml0eSA9IG1lYW4ocGN0TWlub3JpdHksIG5hLnJtID0gVCksCiAgICAgICAgICAgIFBjdEFnaW5nID0gbWVhbihwY3RBZ2luZywgbmEucm0gPSBUKSwKICAgICAgICAgICAgUGN0QmFjaCA9IG1lYW4ocGN0QmFjaGVsb3JzLCBuYS5ybSA9IFQpLAogICAgICAgICAgICBQY3RQb3ZlcnR5ID0gbWVhbihwY3RQb3ZlcnR5LCBuYS5ybSA9IFQpLAogICAgICAgICAgICBQY3ROb0NhciA9IG1lYW4ocGN0Tm9DYXIsIG5hLnJtID0gVCksCiAgICAgICAgICAgIFBjdFJlbnRlciA9IG1lYW4ocGN0UmVudGVyLCBuYS5ybSA9IFQpLAogICAgICAgICAgICBQY3RGb3JlaWduID0gbWVhbihwY3RGb3JlaWduZXIsIG5hLnJtID0gVCkpCgpgYGAKClRoZSByZXN1bHQgaXMgc2hvd24gaW4gdGhlIHRhYmxlIGFzIHdlbGwgYXMgdGhlIGNoYXJ0IGJlbG93LiAKCmBgYHtyIGFsbF92YXJpYWJsZXNfdGFibGUsIHdhcm5pbmcgPSBGQUxTRX0KCmthYmxlKGFsbFRyYWN0cy5TdW1tYXJ5LCBmb3JtYXQgPSAiaHRtbCIpICU+JQoga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gVCwgCiAgICAgICAgICAgICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLAogICAgICAgICAgICAgICBmb250X3NpemUgPSAxMikgJT4lIAogIGZvb3Rub3RlKGdlbmVyYWxfdGl0bGUgPSAiXG4iLAogICAgICAgICAgIGdlbmVyYWwgPSAiVGFibGUgMTogQ29tcGFyYWluZyBQb3B1bGF0aW9uIENoYXJhY3RlcmlzdGljcyBBY3Jvc3MgU3BhY2UgYW5kIFRpbWUgIikgJT4lIAogIHJvd19zcGVjKDAsIGZvbnRfc2l6ZSA9IDE0KSAlPiUgCiAgcm93X3NwZWMoMSwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiM3ZWIwZDUiKSAlPiUgCiAgcm93X3NwZWMoMiwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiNiMmUwNjEiKSAlPiUgCiAgcm93X3NwZWMoMywgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiM3ZWIwZDUiKSAlPiUgCiAgcm93X3NwZWMoNCwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiNiMmUwNjEiKSAlPiUgCiAgY29sdW1uX3NwZWMoMToyLCBib2xkID0gVCkKCiMgCgpgYGAKCldobyBpcyBsaXZpbmcgYXJvdW5kIHRyYW5zaXQgc3RhdGlvbnMgaW4gQm9zdG9uLCB3aGF0IGFyZSB0aGVpciBzb2NpYWwsIGVjb25vbWljLCBhbmQgZGVtb2dyYXBoaWMgY2hhcmFjdGVyaXN0aWNzLCBhbmQgZG8gdGhleSB2YXJ5IGFjcm9zcyB0aW1lPyBPdXIgYW5hbHlzaXMgaGF2ZSBmb3VuZCB0aGUgZm9sbG93aW5nIHRvIGFuc3dlciBvdXIgZmlyc3QgYW5kIHNlY29uZCBxdWVzdGlvbnM6IDEpCVBvcHVsYXRpb25zIGxpdmluZyBpbiB0cmFuc2l0LXJpY2ggbmVpZ2hib3Job29kcyBpbiBCb3N0b24gYXJlIG9mIHJlbGF0aXZlbHkgeW91bmdlciBhZ2UsIGFyZSBtb3N0bHkgcmVudGVycywgaGF2ZSBoaWdoZXIgZWR1Y2F0aW9uIGF0dGFpbm1lbnQsIGhhdmUgaGlnaGVyIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lLCBhbmQgZG8gbm90IG93biBhbnkgdmVoaWNsZXMuIDIpIE9uIHRoZSBvdGhlciBoYW5kLCBOb24tVE9EIG5laWdoYm9yaG9vZHMgaW4gQm9zdG9uIHRlbmQgdG8gaGF2ZSBoaWdoZXIgY29uY2VudHJhdGlvbiBvZiBhZ2luZyBwb3B1bGF0aW9uIGFuZCBtaW5vcml0eSBwb3B1bGF0aW9uIGFzIHdlbGwgYXMgbG93ZXIgZWR1Y2F0aW9uIGF0dGFpbm1lbnQuIDMpIEdlbnRyaWZpY2F0aW9uIHJlbWFpbnMgcHJldmFsZW50IGluIHRoZSBjaXR5IGFzIHdlIHNlZSBjaXR5d2lkZSBpbmNyZWFzZSBpbiBtZWRpYW4gaG91c2Vob2xkIHJlbnQgYW5kIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lLiBJbiBhZGRpdGlvbiwgdGhlIGNpdHkgaXMgYmVjb21pbmcgbW9yZSBhbmQgbW9yZSBkaXZlcnNlOyBpdHMgcG92ZXJ0eSByYXRlIGhhcyBiZWVuIHJlZHVjaW5nIHdoaWxlIG92ZXJhbGwgYW5kIGluZGl2aWR1YWxz4oCZIGVkdWNhdGlvbiBhdHRhaW5tZW50IGhhcyBiZWVuIGluY3JlYXNpbmcuIAoKCmBgYHtyIGFsbF92YXJpYWJsZXNfcGxvdCwgd2FybmluZyA9IEZBTFNFfQoKYWxsVHJhY3RzLlN1bW1hcnkgJT4lCiAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSwgLXllYXIsIC1UT0QpICU+JQogIGdncGxvdChhZXMoeWVhciwgVmFsdWUsIGZpbGwgPSBUT0QpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGZhY2V0X3dyYXAoflZhcmlhYmxlLCBzY2FsZXMgPSAiZnJlZSIsIG5jb2w9NSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM3ZWIwZDUiLCAiI2IyZTA2MSIpKSArICAKICBsYWJzKHRpdGxlID0gIkluZGljYXRvciBEaWZmZXJlbmNlcyBBY3Jvc3MgVGltZSBhbmQgU3BhY2UiLAogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTAgYW5kIDIwMTkiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGw9TkEsIHNpemU9MC44KQogICAgICAgICkgCmBgYAoKIyMgRnVydGhlciBBbmFseXNpcyAKCldlIGRpZCBzb21lIGZ1cnRoZXIgYW5hbHlzaXMgdG8gcmVhcnJhbmdlIG91ciB0YWJsZXMgYW5kIGNhbGN1bGF0ZSBwZXJjZW50YWdlIHBvaW50IGNoYW5nZS4gVGhpcyBpbmNsdWRlcyBwaXZvdGluZyB0aGUgdGFibGUgdHdpY2UgdG8gbWFrZSB5ZWFyIDIwMTAgYW5kIDIwMTkgdHdvIHNlcGFyYXRlIGNvbHVtbnMgCgpgYGB7ciBwZXJjZW50YWdlX2NoYW5nZSwgd2FybmluZyA9IEZBTFNFLCBjbGFzcy5zb3VyY2UgPSAnZm9sZC1zaG93J30KCmFsbFRyYWN0cy5Mb25nIDwtIGFsbFRyYWN0cy5TdW1tYXJ5ICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhSZW50LCBJbmNvbWUsIFBvcCwgUGN0TWlub3JpdHksIFBjdEFnaW5nLCBQY3RCYWNoLCBQY3RQb3ZlcnR5LCBQY3ROb0NhciwgUGN0UmVudGVyLCBQY3RGb3JlaWduKSwgbmFtZXNfdG8gPSAiVmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0geWVhciwgdmFsdWVzX2Zyb20gPSBWYWx1ZSwgbmFtZXNfcHJlZml4ID0gIlllYXIiKSAlPiUgCiAgbXV0YXRlKHBjdF9jaGFuZ2UgPSAoWWVhcjIwMTktWWVhcjIwMTApIC8gWWVhcjIwMTApCgpgYGAKCkxvb2tpbmcgYXQgdGhlIHBlcmNlbnRhZ2UgY2hhbmdlIG9mIHZhcmlhYmxlcyBiZXR3ZWVuIE5vbi1UT0QgYW5kIFRPRCB0cmFjdHMsIHdlIG1heSBzZWUgdGhhdCBmcm9tIDIwMTAgdG8gMjAxOSwgMSkgbWVkaWFuIGhvdXNlIHJlbnQgYW5kIG1lZGlhbiBob3VzZWhvbGQgaW5jb21lIGluY3JlYXNlcyBzaWduaWZpY2FudGx5IGluIFRPRCB0cmFjdHMgY29tcGFyZWQgdG8gTm9uLVRPRCwgMikgcG92ZXJ0eSByYXRlIHdhcyBzaWduaWZpY2FudGx5IHJlZHVjZWQgaW4gVE9EIHRyYWN0cyBjb21wYXJlZCB0byBOb24tVE9ELCAzKSBwb3B1bGF0aW9uIGluY3JlYXNlIGlzIG1vcmUgc2FsaWVudCBpbiBOb24tVE9EIHRyYWN0cyB0aGFuIFRPRC4gCgpgYGB7ciBhbGxfdmFyaWFibGVzX2Jhciwgd2FybmluZyA9IEZBTFNFfQoKYWxsVHJhY3RzLkxvbmcgJT4lIAogIGdncGxvdCgpICsKICBnZW9tX2JhcihhZXMoeCA9IFZhcmlhYmxlLCB5ID0gcGN0X2NoYW5nZSwgZmlsbCA9IFRPRCksCiAgICAgICAgICAgc3RhdCA9ICJpZGVudGl0eSIpICsKICBmYWNldF93cmFwKH5UT0QpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM3ZWIwZDUiLCAiI2IyZTA2MSIpKSArICAKICBsYWJzKHRpdGxlID0gIlBlcmNlbnRhZ2UgQ2hhbmdlIDIwMTAtMjAxOSBmb3IgVE9EIGFuZCBOb24tVE9EIFRyYWN0cyIsCiAgICAgICBjYXB0aW9uID0gIkRhdGE6IEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgMjAxMCBhbmQgMjAxOSIpICsKICB5bGFiICgiUGVyY2VudGFnZSBDaGFuZ2UiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGw9TkEsIHNpemU9MC44KQogICAgICAgICkgCiAgCgoKYGBgCgpXZSBhbHNvIGxvb2tlZCBpbnRvIHNlZSBpZiB0aGVyZSdzIGludHJhLXJlZ2lvbmFsIHZhcmlhdGlvbnMgb2Ygb3VyIHZhcmlhYmxlcyBhbW9uZyBUT0QgdHJhY3RzLCB1c2luZyBwb3B1bGF0aW9uIGFuZCBtZWRpYW4gaG91c2UgcmVudCBhcyBhbiBleGFtcGxlLiBUbyBhY2hpZXZlIHRoYXQsIHdlIGpvaW5lZCB0aGUgY2VudHJvaWRzIG9mIGNlbnN1cyB0cmFjdHMgaW50byB0aGUgaGFsZiBtaWxlIGJ1ZmZlciBvZiB0cmFuc2l0IHN0YXRpb25zLCB3aGljaCB3ZSB0aGVuIHN1bW1hcml6ZWQgdGhlIHRvdGFsIHBvcHVsYXRpb24gYW5kIG1lZGlhbiByZW50IHdpdGhpbiBoYWxmIG1pbGUgb2YgZWFjaCB0cmFuc2l0IHN0YXRpb24uIAoKCmBgYHtyIGdyYWR1YXRlZF9wcmVwLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQoKYm9zdG9uX3N0b3BzJElEIDwtIHNlcV9hbG9uZyhib3N0b25fc3RvcHMkU1RBVElPTikgIyB1bmlxdWUgaWQgZm9yIGVhY2ggc3RhdGlvbgoKc3RvcF9hdHRyaWJ1dGVzIDwtIHN0X2J1ZmZlcihib3N0b25fc3RvcHMsIDgwNCkgJT4lIAogIHN0X3NmKCkgJT4lIAogIHN0X2ludGVyc2VjdGlvbihzdF9jZW50cm9pZChib3N0b24xMCkpICU+JSAKICBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lIAogIGdyb3VwX2J5KElEKSAlPiUgCiAgc3VtbWFyaXplKAogICAgdG90YWxfcG9wdWxhdGlvbiA9IHN1bShUb3RhbFBvcCksCiAgICBtZWRpYW5fcmVudCA9IG1lYW4oTWVkUmVudCwgbmEucm0gPSBUKSkKCnN0b3BzX3N1bW1hcnkgPC0gYm9zdG9uX3N0b3BzICU+JSAKICBsZWZ0X2pvaW4oc3RvcF9hdHRyaWJ1dGVzLCBieSA9ICJJRCIpCgpgYGAKCk5vdCBzdXJwcmlzaW5nbHksIHRoZSBtYXAgYmVsb3cgc2hvd3MgdGhhdCB0cmFuc2l0IHN0YXRpb24gaW4gY2l0eSBjZW50ZXIgYXR0cmFjdHMgbW9yZSBwZW9wbGUgdG8gbGl2ZSBuZWFyYnkgd2hpbGUgYXMgZGlzdGFuY2UgZnJvbSB0aGUgY2l0eSBjZW50ZXIgZ2V0cyBncmVhdGVyLCB0aGUgZG90IHNpemUgYmVjb21lcyBzbWFsbGVyLCBtZWFuaW5nIHRoZXJlJ3MgbGVzcyBwZW9wbGUgbGl2aW5nIG5lYXJieS4gCgpgYGB7ciBmb3JtYXRfZG90cywgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KYm9zdG9uMTBfNDMyNiA8LSBzdF90cmFuc2Zvcm0oYm9zdG9uMTAsIGNycyA9IDQzMjYpCnN0b3BzX3N1bW1hcnlfNDMyNiA8LSBzdF90cmFuc2Zvcm0oc3RvcHNfc3VtbWFyeSwgY3JzID0gNDMyNikKCnN0b3BzX3N1bW1hcnlfY29vcmRzIDwtIHN0X2Nvb3JkaW5hdGVzKHN0b3BzX3N1bW1hcnlfNDMyNikKc3RvcHNfc3VtbWFyeV9kZiA8LSBkYXRhLmZyYW1lKAogIFggPSBzdG9wc19zdW1tYXJ5X2Nvb3Jkc1ssIDFdLAogIFkgPSBzdG9wc19zdW1tYXJ5X2Nvb3Jkc1ssIDJdLAogIHRvdGFsX3BvcHVsYXRpb24gPSBzdG9wc19zdW1tYXJ5JHRvdGFsX3BvcHVsYXRpb24sICAjIEluY2x1ZGUgb3RoZXIgYXR0cmlidXRlcyBoZXJlCiAgcmVudCA9IHN0b3BzX3N1bW1hcnkkbWVkaWFuX3JlbnQsIAogIHN0b3BzID0gc3RvcHNfc3VtbWFyeSRzdG9wcyMgSW5jbHVkZSBhZGRpdGlvbmFsIGF0dHJpYnV0ZXMgYXMgbmVlZGVkCikKCmBgYAoKCgpgYGB7ciBncmFkdWF0ZWRfcG9wLCB3YXJuaW5nPUZBTFNFfQoKZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YT1zdF91bmlvbihib3N0b24xMF80MzI2KSwgZmlsbD0gIiNEM0QzRDMiLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAyKSArCiAgZ2VvbV9wb2ludChkYXRhID0gc3RvcHNfc3VtbWFyeV9kZiwgYWVzKHggPSBYLCB5ID0gWSwgc2l6ZSA9IHRvdGFsX3BvcHVsYXRpb24sIGNvbG9yID0gc3RyX3RvX3RpdGxlKHN0b3BzKSkpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygwLjUsIDQuNSksIG5hbWUgPSAiUG9wdWxhdGlvbiIpICsgICAgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjN2ViMGQ1IiwiI2IyZTA2MSIsICIjZmZiNTVhIiwgIiNmZmVlNjUiLCAiI2ZkN2Y2ZiIsICIjYmQ3ZWJlIiksIG5hbWUgPSAiU3RvcHMiKSArCiAgbGFicyh0aXRsZSA9ICJQb3B1bGF0aW9uIHdpdGhpbiAwLjUgTWlsZSBvZiBUYW5zaXQgU3RvcHMiLAogICAgICAgc3VidGl0bGUgPSAiRG90IHNpemUgcHJvcG9ydGlvbmFsIHRvIHBvcHVsYXRpb24iLAogICAgICAgY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTkiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSkKYGBgCgoKU2ltaWxhcmx5LCBtZWRpYW4gcmVudCBpcyB0aGUgaGlnaGVzdCBhcm91bmQgdHJhbnNpdCBzdGF0aW9ucyBpbiB0aGUgY2l0eSBjZW50ZXIuVGhpcyBzaG93cyB0aGF0IHRoZSBpbmZsdWVuY2Ugb2YgdHJhbnNpdCBzdGF0aW9uIG9uIG5lYXJieSBwb3B1bGF0aW9uIGFuZCBzZXR0bGVtZW50cyBjaGFyYWN0ZXJpc3RpY3MgYXJlIG5vdCB0aGUgc2FtZSB0aHJvdWdob3V0IHRoZSBjaXR5LiAgCgpgYGB7ciBncmFkdWF0ZWRfcmVudCwgd2FybmluZz1GQUxTRSwgd2FybmluZz1GQUxTRX0KCgpnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhPXN0X3VuaW9uKGJvc3RvbjEwXzQzMjYpLCBmaWxsPSAiI0QzRDNEMyIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDIpICsKICBnZW9tX3BvaW50KGRhdGEgPSBzdG9wc19zdW1tYXJ5X2RmLCBhZXMoeCA9IFgsIHkgPSBZLCBzaXplID0gcmVudCwgY29sb3IgPSBzdHJfdG9fdGl0bGUoc3RvcHMpKSkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDAuNSwgNCksIG5hbWUgPSAiUmVudCIpICsgICAgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjN2ViMGQ1IiwiI2IyZTA2MSIsICIjZmZiNTVhIiwgIiNmZmVlNjUiLCAiI2ZkN2Y2ZiIsICIjYmQ3ZWJlIiksIG5hbWUgPSAiU3RvcHMiKSArCiAgbGFicyh0aXRsZSA9ICJNZWRpYW4gUmVudCB3aXRoaW4gMC41IE1pbGUgb2YgVGFuc2l0IFN0b3BzIiwKICAgICAgIHN1YnRpdGxlID0gIkRvdCBzaXplIHByb3BvcnRpb25hbCB0byByZW50IiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDE5IikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIikpCmBgYAoKTW9yZW92ZXIsIHdlIHdlcmUgY3VyaW91cyBpZiB0aGVyZSBpcyBhIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBkaXN0YW5jZSBmcm9tIHRyYW5zaXQgc3RvcHMgYW5kIHJlbnQ/IFdlIHRoZXJlZm9yZSBjcmVhdGVkIGEgbXVsdGlwbGUgcmluZyBidWZmZXIsIHdoZXJlIGVhY2ggYnVmZmVyIGlzIG9mIGhhbGYgYSBtaWxlIGRpc3RhbmNlIHRvIHRoZSBwcmV2aW91cyBvbmUsIHRvIGFuc3dlciB0aGlzIHF1ZXN0aW9uLiAgCgpgYGB7ciBib3N0b25fTVJCLCB3YXJuaW5nID0gRkFMU0UsIHJlc3VsdHM9J2hpZGUnfQoKYm9zdG9uX01SQiA8LSBtdWx0aXBsZVJpbmdCdWZmZXIoc3RfdW5pb24oYm9zdG9uX3N0b3BzKSwgMTQ0ODQsIDgwNCkKZ2dwbG90KCkgKwogICAgZ2VvbV9zZihkYXRhPWJvc3Rvbl9NUkIsIGFlcyhmaWxsID0gZGlzdGFuY2UpLCBjb2xvciA9ICIjNzA4MDkwIikgKwogICAgc2NhbGVfZmlsbF9jb250aW51b3VzKGxvdyA9ICIjRkFGOUY2IiwgaGlnaCA9ICIjYmViOWRiIiwgbmFtZT0gIkRpc3RhbmNlIikrCiAgICBnZW9tX3NmKGRhdGE9c3RfdW5pb24oYm9zdG9uMTApLCBmaWxsPSAiI0QzRDNEMyIsIGNvbG9yID0gIndoaXRlIiwgc2l6ZSA9IDIpICsKICAgIGdlb21fc2YoZGF0YT1ib3N0b25fc3RvcHMsIAogICAgICAgICAgY29sb3IgPSAiI2ZkN2Y2ZiIsIHNpemU9IDAuOCkgKyAgICAKICAgIGxhYnModGl0bGU9IkhhbGYgTWlsZSBCdWZmZXJzIiwKICAgICAgICAgc3VidGl0bGUgPSAiRGlzdGFuY2UgaW4tYmV0d2VlbiBlYWNoIGJ1ZmZlciBpcyAwLjUgbWlsZSIsCiAgICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDEwIGFuZCAyMDE5IFxuTWFzc0dJUyAyMDIyIikgKwogICAgdGhlbWVfbGlnaHQoKSArICAgCiAgICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIikpCgpgYGAKClRoZSBmaWd1cmUgYmVsb3cgc2hvd3MgdGhhdCBvdmVyYWxsLCByZW50IGRlY3JlYXNlcyBhcyBkaXN0YW5jZSBmcm9tIHRyYW5zaXQgc3RvcHMgZ2V0cyBncmVhdGVyLiBIb3dldmVyLCB0aGUgcmVsYXRpb25zaGlwIGlzIG5vdCBsaW5lYXIgYXMgd2Ugc2VlIHRoYXQgcmVudCBpcyBpbmNyZWFzaW5nIGZyb20gMjUwMCB0byA0MDAwIG1ldGVycy4gVGhpcyBpbXBsaWVzIHRoYXQgdHJhbnNpdCBzdGF0aW9ucyBpcyBub3QgdGhlIG9ubHkgZmFjdG9yIGRlZmluaW5nIHJlbnQuIEluIG90aGVyIHdvcmRzLCBpdCBjb3VsZCBiZSBob3VzZWhvbGRzIGFyZSB3aWxsaW5nIHRvIHBheSBtb3JlIGZvciB0cmFuc2l0IGFtZW5pdGllcywgb3IgdGhhdCB0aGV5IHBheSBmb3Igb3RoZXIgdHlwZXMgb2YgYW1lbml0aWVzIGluIG5laWdoYm9yaG9vZHMgdGhhdCBoYXBwZW4gdG8gYWxzbyBiZSB0cmFuc2l0LXJpY2g6IHByb3hpbWl0eSB0byB0cmFuc2l0IHN0YXRpb24gb25seSBwYXJ0aWFsbHkgaW5mbHVlbmNlIHRoZWlyIGRlY2lzaW9ucyB0byBsaXZlIGluIG5lYXJieSBsb2NhdGlvbnMuIAoKYGBge3IgbGluZV9wbG90LCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgcmVzdWx0cz0naGlkZSd9CgphbGxUcmFjdHMucmluZ3MgPC0KICBzdF9qb2luKHN0X2NlbnRyb2lkKGRwbHlyOjpzZWxlY3QoYWxsVHJhY3RzLCBHRU9JRCwgeWVhcikpLAogICAgICAgICAgYm9zdG9uX01SQikgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogIGxlZnRfam9pbihkcGx5cjo6c2VsZWN0KGFsbFRyYWN0cywgR0VPSUQsIE1lZFJlbnQsIHllYXIpLCAKICAgICAgICAgICAgYnk9YygiR0VPSUQiPSJHRU9JRCIsICJ5ZWFyIj0ieWVhciIpKSAlPiUKICBzdF9zZigpIAoKCmFsbFRyYWN0cy5yaW5ncy5zdW1tYXJ5IDwtIHN0X2Ryb3BfZ2VvbWV0cnkoYWxsVHJhY3RzLnJpbmdzKSAlPiUKICBncm91cF9ieShkaXN0YW5jZSwgeWVhcikgJT4lCiAgc3VtbWFyaXplKE1lYW5fUmVudCA9IG1lYW4oTWVkUmVudCwgbmEucm09VCkpCgoKZ2dwbG90KGFsbFRyYWN0cy5yaW5ncy5zdW1tYXJ5LCBhZXMoeCA9IGRpc3RhbmNlLCB5ID0gTWVhbl9SZW50KSkgKyAKICBnZW9tX2xpbmUoYWVzKGNvbG9yID0geWVhciksIHNpemUgPSAyKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjN2ViMGQ1IiwgIiNiMmUwNjEiKSwgbmFtZSA9ICJZZWFyIikgKwogIGxhYnModGl0bGUgPSAiTWVhbiBSZW50IGFzIGEgRnVuY3Rpb24gb2YgRGlzdGFuY2UgdG8gU3Vid2F5IFN0YXRpb25zIiwKICAgICAgIGNhcHRpb24gPSAiRGF0YTogQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSAyMDEwIGFuZCAyMDE5IikgKwogIHhsYWIgKCJEaXN0YW5jZSBmcm9tIFRyYW5zaXQgU3RvcHMiKSArCiAgeWxhYigiTWVhbiBSZW50IikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsPU5BLCBzaXplPTAuOCkKICAgICAgICApIAoKYGBgCgojIEZ1dHVyZSBQbGFubmluZyAKClRvIHF1aWNrbHkgc3VtbWFyaXplLCBCb3N0b24gaXMgZ2VudHJpZnlpbmcgYmV0d2VlbiAyMDEwIGFuZCAyMDE5LCB3aXRoIGluY3JlYXNpbmcgcG9wdWxhdGlvbiwgZGl2ZXJzaXR5LCBtZWRpYW4gaG91c2Vob2xkIGluY29tZSwgbWVkaWFuIHJlbnQsIGFuZCBlZHVjYXRpb24gYXR0YWlubWVudCBhcyB3ZWxsIGFzIGRlY3JlYXNpbmcgcG92ZXJ0eSByYXRlIHRocm91Z2hvdXQgdGhlIGNpdHkuIFRoZXJlJ3MgZGlmZmVyZW5jZSBpbiB0ZXJtcyBvZiBwb3B1bGF0aW9uIGNoYXJhY3RlcmlzdGljcyBiZXR3ZWVuIFRPRCBhbmQgTm9uLVRPRCByZWdpb25zLCB3aGVyZSBUT0QgYXR0cmFjdHMgbW9zdGx5IHJlbnRlcnMgd2hvIGFyZSB5b3VuZ2VyLCB3ZWFsdGhpZXIsIGFuZCB3ZWxsLWVkdWNhdGVkLCB3aGVyZWFzIE5vbi1UT0QgdHJhY3RzJyBob3VzZWhvbGRzIGNvbnNpc3QgbGFyZ2VyIGNvbmNlbnRyYXRpb24gb2YgbWlub3JpdHkgYW5kIGFnaW5nIHBvcHVsYXRpb24gd2l0aCBsb3dlciBlZHVjYXRpb24gYXR0YWlubWVudC4gCgpJbiBhZGRpdGlvbiwgdGhlcmUncyBpbnRyYS1yZWdpb25hbCBkaWZmZXJlbmNlIHdpdGhpbiBUT0QgdHJhY3RzLCB3aGVyZSBtZWRpYW4gcmVudCBmb3IgaG91c2VzIG5leHQgdG8gdHJhbnNpdCBzdGF0aW9ucyB0aGF0IGFyZSBpbiBjaXR5IGNlbnRlciBiZWluZyB0aGUgbW9zdCBleHBlbnNpdmUuIEZ1cnRoZXIsIHJlbnQgZGlkIG5vdCBvbmx5IGRlY3JlYXNlIGFzIHdlIG1vdmUgYXdheSBmcm9tIHRyYW5zaXQgc3RhdGlvbnMuIFRoaXMgbGVhZHMgdXMgdG8gY29uY2x1ZGUgdGhhdCBub3QgYWxsIHRyYW5zaXQgc3RhdGlvbnMgYXJlIGFzIGFwcGVhbGluZyBhcyBlYWNoIG90aGVyLiBQcm94aW1pdHkgdG8gdHJhbnNpdCBzdGF0aW9uIG9ubHkgYWZmZWN0cyBwZW9wbGUncyBkZWNpc2lvbiB0byBsaXZlIGluIG5lYXJieSBsb2NhdGlvbnMgdG8gYSBjZXJ0YWluIGV4dGVudC4gKipUT0QgbmVpZ2hib3Job29kcyBpbiBCb3N0b24gaXMgYWJsZSB0byBhdHRyYWN0IHlvdW5nZXIgYW5kIHdlYWx0aGllciBpbmRpdmlkdWFsIG5vdCBvbmx5IGJlY2F1c2UgdGhleSBvZmZlciBjb252ZW5pZW5jZSBpbiBwdWJsaWMgdHJhbnNwb3J0YXRpb24sIGJ1dCBhbHNvIGNvdWxkIGJlY2F1c2UgQm9zdG9uaWFucyB2YWx1ZSB0aGUgY3VsdHVyYWwgYW1lbml0aWVzLCBlbnRlcnRhaW5tZW50ICYgbmlnaHRsaWZlLCBhcyB3ZWxsIGFzIGVtcGxveW1lbnQgYW5kIGFjYWRlbWljIG9wcG9ydHVuaXRpZXMgdGhhdCBhcmUgaGFwcGVuZWQgdG8gYmUgd2l0aGluIGhhbGYgYSBtaWxlIG9mIHRoZXNlIHRyYW5zaXQgc3RvcHMuKiogCgpXaGlsZSBCb3N0b24gaXMgYSBoaWdobHkgd2Fsa2FibGUgY2l0eSwgcGxhbm5pbmcgb2ZmaWNpYWwgc2hvdWxkIHN0aWxsIHdvcmsgdG93YXJkcyBtYWtpbmcgcHVibGljIHRyYW5zcG9ydGF0aW9uIG1vcmUgYWNjZXNzaWJsZSB0byBuZWlnaGJvcmhvb2RzIHRoYXQgYXJlIGN1cnJlbnRseS4gTm9uLVRPRCBhbmQgZGV2ZWxvcGluZyBwYXJjZWxzIG5lYXIgdHJhbnNpdCBzdGF0aW9ucywgd2hpY2ggY291bGQgYWxsZXZpYXRlIHRoZSBob3VzaW5nIGFuZCBhbWVuaXR5IHNob3J0YWdlcyBhdCBjaXR5IGNlbnRlciBhbmQgcmVkdWNlIGludHJhLXJlZ2lvbmFsIGRpc3Bhcml0aWVzLiBEZXNwaXRlIHRoYXQgTm9uLVRPRCBuZWlnaGJvcmhvb2QgaGF2ZSBoaWdoZXIgY2FyIG93bmVjcnNoaXAgcmF0ZSwgdGhpcyBkb2VzIG5vdCBtZWFuIHRoYXQgcHVibGljIHRyYW5zcG9ydGF0aW9uIHBsYW5uaW5nIGlzIG5vdCBpbXBvcnRhbnQgaW4gdGhlc2UgbmVpZ2hib3Job29kcy4gRm9yIHBsYWNlcyBsaWtlIHRoZSBjaXR5IGNlbnRlciB3aGVyZSBpdCBpcyBoYXJkIHRvIGdldCB0byB0aHJvdWdoIGRyaXZpbmcgYW5kIHdoZXJlIGJ1c2luZXNzIGFuZCBpbnRlbGxlY3R1YWwgb3Bwb3J0dW5pdGllcyBhY2N1bXVsYXRlLCBwdWJsaWMgdHJhbnNwb3J0YXRpb24gaXMgdGhlIGJlc3Qgd2F5IHRvIGNvbm5lY3QgZGlmZmVyZW50IG5laWdoYm9yaG9vZHMgdG9nZXRoZXIuICBJbmRlZWQsIHRoaXMgYWxpZ25zIHdpdGggdGhlIGNpdHkncyBnb2FsIHRvICJjb25uZWN0IGFsbCBuZWlnaGJvcmhvb2QgY2VudGVycyBpbnRvIGEgY29tcHJlaGVuc2l2ZSB0cmFuc2l0IG5ldHdvcmsiLiAKCldpdGggdGhlIGN1cnJlbnQgZGF0YSB3ZSBoYXZlLCBob3cgZG8gd2UgaW1wcm92ZSBwdWJsaWMgdHJhbnNpdCBhY2Nlc3NpYmlsaXR5IGluIE5vbi1UT0QgbmVpZ2hib3Job29kcyBpbiBCb3N0b24/IFdlIGF0dGVtcHRlZCB0byBhbnN3ZXIgdGhpcyBxdWVzdGlvbiB3aXRoIGEgYml2YXJpYXRlIG1hcCwgY29uc2lkZXJpbmcgdGhlIHBvc3NpYmlsaXR5IG9mIGV4dGVuZGluZyBleGlzdGluZyB0cmFuc2l0IGxpbmVzIGFuZCBhZGRpbmcgYSB0cmFuc2l0IHN0YXRpb24gaW4gTm9uLVRPRCBuZWlnaGJvcmhvb2RzIHdoZXJlIHRoZXJlJ3MgYm90aCBhIGhpZ2ggY29uY2VudHJhdGlvbiBvZiBhZ2luZyBhbmQgbWlub3JpdHkgcG9wdWxhdGlvbiAodHdvIHBvcHVsYXRpb24gc3ViZ3JvdXBzIHRoYXQgYXJlIG9mdGVuIGV4Y2x1ZGVkIGluIFRPRCkuVGhlIG1hcCBiZWxvdyBoaWdobGlnaHRzIGFuIGFyZWEgaW4gc291dGhlcm4gQm9zdG9uIHdpdGggaGlnaCBudW1iZXIgb2YgYm90aCBwb3B1bGF0aW9uIHN1Ymdyb3Vwcy4gV2UgZW5jb3VyYWdlZCB0cmFuc3BvcnRhdGlvbiBwbGFubmVycyB0byBmdXJ0aGVyIGludmVzdGlnYXRlIHRoZSBwb3NzaWJpbGl0eSBvZiBmdXR1cmUgdHJhbnNpdCBkZXZlbG9wbWVudHMgaW4gdGhlc2UgbG9jYXRpb25zLiAKCmBgYHtyIGJpdmFyaWF0ZV9tYXAsIHdhcm5pbmcgPSBGQUxTRX0KCgpiaV9kYXRhIDwtIGJpX2NsYXNzKGJvc3RvbjE5LCB4ID0gcGN0TWlub3JpdHksIHkgPSBwY3RBZ2luZywgc3R5bGUgPSAicXVhbnRpbGUiLCBkaW0gPSAzKSAjICBhIDMqMyBjb2xvci1zY2hlbWVkIGJpLXZhcmlhdGUgY2hvcm9wbGV0aCAKCgpiaV9tYXAgPC0gZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IGJpX2RhdGEsIG1hcHBpbmcgPSBhZXMoZmlsbCA9IGJpX2NsYXNzKSwgY29sb3IgPSAidHJhbnNwYXJlbnQiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgYmlfc2NhbGVfZmlsbChwYWwgPSAiRGtDeWFuIiwgZGltID0gMykgKyAKICBsYWJzKHRpdGxlID0gIkJpdmFyaWF0ZSBDaG9yb3BsZXRoIG9mIFBjdCBNaW5vcml0eSBvdmVyIFBjdCBBZ2luZyBQb3B1bGF0aW9uIikgKyAKICBnZW9tX3NmKGRhdGEgPSBib3N0b25fc3RvcHMsIGNvbG91ciA9ICJ5ZWxsb3ciLCBhbHBoYSA9IDAuOCwgc2l6ZSA9IDAuNSkgKwogIGxhYnMoY2FwdGlvbiA9ICJEYXRhOiBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IDIwMTkiKSArCiAgdGhlbWVfbGlnaHQoKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpKQoKbGVnZW5kIDwtIGJpX2xlZ2VuZChwYWwgPSAiRGtDeWFuIiwKICAgICAgICAgICAgICAgICAgICBkaW0gPSAzLAogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiUGN0TWlub3JpdHkgIiwKICAgICAgICAgICAgICAgICAgICB5bGFiID0gIlBjdEFnaW5nICIsCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDUuOCkKCmdnZHJhdygpICsKICBkcmF3X3Bsb3QoYmlfbWFwLCAwLCAwLCAxLCAxKSArCiAgZHJhd19wbG90KGxlZ2VuZCwgMC4xLCAwLjIsIDEuMiwgMC4yMykKYGBgCgpGaW5hbGx5LCB0aGVyZSBpcyBvbmUgaW1wb3J0YW50IGxpbWl0YXRpb24gb2YgdGhpcyBzdHVkeSB0aGF0IGhhcyB0byBiZSBhZGRyZXNzZWQuIFdlIG1lbnRpb25lZCBiZWZvcmUgdGhhdCB0aGUgTUJUQSB0cmFuc2l0IGxpbmVzIGdvIGJleW9uZCB0aGUgYm91bmRhcnkgb2YgQm9zdG9uIGNpdGllcy4gSW4gdGhpcyBjYXNlLCBpdCBpcyBsaWtlbHkgdGhhdCBzb21lIGNlbnN1cyB0cmFjdHMgYXQgdGhlIGVkZ2Ugb2YgQm9zdG9uIHRoYXQgYXJlIGNhdGVnb3JpemVkIGFzIE5vbi1UT0QgYXJlIGFjdHVhbGx5IFRPRC5GdXR1cmUgc3R1ZHkgYXQgYSByZWdpb25hbCBzY2FsZSBzaG91bGQgY29uc2lkZXIgZXhhbWluZSBUT0QgZGV2ZWxvcG1lbnQgaW4gQm9zdG9uIGNvbnNpZGVyaW5nIGFsbCB0cmFuc2l0IHN0b3BzIGluIHRoZSBHcmVhdGVyIEJvc3RvbiBBcmVhcyBhcyB3ZWxsIGFzIGFsbCB0eXBlcyBvZiB0cmFuc2l0IHN0b3BzLiAKCg==