Data Import and Cleaning
Libraries
library(rio)
library(dplyr)
library(bit64)
library(sf)
library(tmap)
library(tigris)
library(lwgeom)
library(tidycensus)
City of Atlanta Census Tracts
City of Atlanta census tracts (prior to annexation of Emory) and associated attribute data were manually downloaded from the 500 cities project page on the CDC website. Next the geographies and attributes were imported and joined with the following code.
five_city <-import('C:/Users/dvern/Desktop/MARTA Project/500_cities.csv')
all_tracts <-st_read('C:/Users/dvern/Desktop/MARTA Project/tracts/500Cities_Tracts_Clip.shp')
atl_tracts <- all_tracts %>% filter(PlaceName == 'Atlanta')
atl_data <- five_city %>% filter(PlaceName == 'Atlanta')
atl_tracts$plctract10 <- as.character(atl_tracts$plctract10)
atl <- left_join(atl_tracts, atl_data, by= c('plctract10'='Place_TractID'))
#st_write(atl, 'C:/Users/dvern/Desktop/MARTA Project/atl_tracts.shp')
#ESRI shapefile of atl census tracts saved to assist with georeferencing of project lines
Projection
The UTM Zone 16N projection was chosen for this project as it maintains distance relationships in small areas on the scale of cities and/or counties.
x <- 32616 #makes a variable to hold the EPSG code for UTM 16N
atl <-st_transform(atl, crs = x) %>% select(Population2010, TractFIPS) #trim attributes I'm not concerned with for now
atl$TractFIPS <- as.character(atl$TractFIPS)
atl <- atl %>% rename(GEOID = TractFIPS) #change variable name to facilitate future join operation
Add in Emory/CDC
Emory and the CDC were not incorporated into the City of Atlanta at the time of the 500 cities project. This code will use the tidy census package to download the Dekalb county census tracts, filter down to Emory’s tract, then join it with the rest of Atlanta.
options(tigris_use_cache=TRUE) #prevent redownloading files
dek_tracts <- tracts('GA', county = 'Dekalb') %>% st_as_sf() #download census tracts to Dekalb county
emory <- dek_tracts %>% filter(NAME == '224.02') %>% st_transform(x) %>% select(GEOID) %>%
mutate(Population2010 = 1) # need to add placeholder population variable to enable rowbind with rest of ATL
atl_plus <- rbind(atl, emory)
Project Lines File
Digitization of the planned MARTA expansion project segments was conducted in ArcGIS. First the following project map was georeferenced to the atlanta census tracts file from earlier using directions found at this Brown university pdf.
Next the digitized segments were brought into the R environment.
dig_segs <-st_read('C:/Users/dvern/Desktop/MARTA Project/New segs/new_segs1.shp')
dig_segs.proj <-st_transform(dig_segs, crs=x)
dig_segs.proj$Name <- as.character(dig_segs.proj$Name) #assist future join
Finally the projected budget for each project was collated from this Atlanta Journal-Constitution article and imported as a table. This was the joined with the projects line file.
proj_vals <- import('C:/Users/dvern/Desktop/MARTA Project/proj_values.csv')
seg_vals <- left_join(dig_segs.proj, proj_vals) #associates each segment with the project budget for that segment
Geoprocessing Steps
Segment Length and budget ratio
The following steps calculate the individual segment lengths and the total length of each project (some comprise many segments, such as the addition of more frequent bus service along some routes). Then a cost per mile ratio was generated from total budget/total length. This ratio calculation took place in a separate data frame due to the use of groupby and the final step joins the ratio back to the original segments file.
#get individual segment length
seg_vals$length <- st_length(seg_vals)
seg_vals$length <- as.numeric(seg_vals$length) #st_length outputs in the units class which is incompatible with calculations
seg_vals <- seg_vals %>% mutate(km = length / 1000) %>% mutate(miles = km*0.621371) #add lengths in km and miles
#forming the ratio variable for each project
ratio <- seg_vals %>% group_by(Name) %>% summarise(tot_len = sum(miles)) #sum lengths of segments that fall under the same project
rat1 <- left_join(ratio, proj_vals) #join in the proj values so that a $/mile ratio variable can be made
rat2 <- rat1 %>% mutate(ratio = Budg_mil / tot_len)
rat3 <- rat2 %>% st_drop_geometry() %>% select(ratio, Name) #select variables for joining back to main, ungrouped, segments file
#join ratio to original segments file
seg_vals1 <- left_join(seg_vals, rat3)
Joining segments to tracts, calculating total budgeted spending per tract
This step will join segments to tracts using st_intersection which will chop the lines into smaller sections based on what tract they intersect with. This will enable the calculation of the spending per section. Then, once the sections are joined with polygons, aggregation to the polygon will give us the total spending per polygon using the summarize step.
# intersection
int = st_intersection(seg_vals1, atl_plus)
# find out about the length of each line segment
int$len = st_length(int)
int1 <- int %>% mutate(km = len / 1000) %>% mutate(miles = km*0.621371) #add lengths in km and miles
int2 <- int1 %>% mutate(spending = miles * ratio)
# spatial overlay
join_new = st_join(atl_plus, int2)
# use the ID of the polygon for the aggregation
out = group_by(join_new, GEOID.x) %>%
summarize(tot_spend = sum(spending))
out[is.na(out)] <- 0 #replace NAs with zeros to assist future calculations
Next the major projects will be separated out by type to assist with future visulaization.
##separate out project types for mapping
LRT <- seg_vals %>% filter(Type == 'LRT')
FLBS <- seg_vals %>% filter(Type == 'FLBS')
BRT <- seg_vals %>% filter(Type == 'BRT')
ART <- seg_vals %>% filter(Type == 'ART' | Name == 'Cleveland AVE')
First Thematic Maps
The following code makes the first thematic maps of the spatial variation in budgeted MARTA spending. Major Project lines are shown for context. A version where the tracts with zero spending were shown as grey was experimented with.
tm_shape(out) +
tm_fill('tot_spend',
title = 'Budgeted Spending\n(Millions USD)',
style = 'quantile',
palette = 'BuPu') +
tm_borders() +
#tm_shape(out_none) + tm_fill('spend', col = 'grey', alpha = 1) + tm_borders() +
tm_shape(LRT) + tm_lines(lwd = 2) +
tm_shape(BRT) + tm_lines(lwd = 2, col = 'red') +
tm_shape(ART) + tm_lines(lwd = 2, col = 'blue') +
#tm_shape(FLBS) + tm_lines(lwd = 1, col = 'navy') +
#tm_add_legend(type = 'fill', col = 'grey', labels = '0.00') +
tm_add_legend(type = 'line', col = 'black', lwd = 3, labels = 'LRT') +
tm_add_legend(type = 'line', col = 'blue', lwd = 3, labels = 'ART') +
tm_add_legend(type = 'line', col = 'red', lwd = 3, labels = 'BRT') +
tm_credits('Source: Atlanta Journal-Constitution', fontface = 'bold', position = c('LEFT','BOTTOM')) +
tm_layout(legend.title.fontface = 'bold')

*Note that this appears uncrowded in the normal viewer and upon export as a picture.
#make a dataset with just zero spending tracts
out$spend <- as.numeric(out$tot_spend)
out_none <- out %>% filter(spend == 0)
#map with greyed out zeros
tm_shape(out) +
tm_fill('tot_spend',
title = 'Budgeted Spending\n(Millions USD)',
style = 'quantile',
palette = 'BuPu') +
tm_borders() +
tm_shape(out_none) + tm_fill('spend', col = 'grey', alpha = 1) + tm_borders() +
tm_shape(LRT) + tm_lines(lwd = 1) +
tm_shape(BRT) + tm_lines(lwd = 1, col = 'red') +
tm_shape(ART) + tm_lines(lwd = 1, col = 'blue') +
tm_shape(FLBS) + tm_lines(lwd = 1, col = 'navy') +
tm_add_legend(type = 'fill', col = 'grey', labels = '0.00') +
tm_add_legend(type = 'line', col = 'black', lwd = 3, labels = 'LRT') +
tm_add_legend(type = 'line', col = 'blue', lwd = 3, labels = 'ART') +
tm_add_legend(type = 'line', col = 'red', lwd = 3, labels = 'BRT') +
tm_credits('Source: Atlanta Journal-Constitution', fontface = 'bold', position = c('LEFT','BOTTOM')) +
tm_layout(legend.title.fontface = 'bold')

A close examination of this second map reveals that there are a few central tracts which probably shouldn’t be identified as zero spending. However, due to small inaccuracies in the georeferencing and digitization process, some segments and tracts don’t overlap when they probably should. I say probably because in most cases, the tract boundaries appear to follow major transportation routes.
Unfortunately, at this stage I’ve already spent a LOT of time geoprocessing and I need to get to the analysis. To improve this in the future, I would need to compare the tract boundaries in question and see if they indeed fall along major roads/ transit routes that are in the MARTA project list. From there, I’d need to redigitize segments that match up better.
On to analysis.
Downloading, cleaning, and joining other attribute data
Just kidding about being ready to do analysis. Now I need to download some covariate data (population and median income) from the ACS for my tracts. This took a fair amount of processing as Atlanta spreads across both Fulton and Dekalb counties.
#### attributes to tracts join
library(tidycensus)
all_vars <- load_variables(year = 2017, dataset = 'acs5', cache = T)
# From my search, I found that I want the following variables: 'B25026_001','B21004_001'
## this part grabs the variables for the atl tracts in fulton county
fult_pop <- get_acs(geography = 'tract',
variables = 'B25026_001',
county = 'Fulton',
state = 'Georgia',
year = 2017,
survey = 'acs5') %>% rename(population_2017= estimate)
fult_inc <- get_acs(geography = 'tract',
variables = 'B21004_001',
county = 'Fulton',
state = 'Georgia',
year = 2017,
survey = 'acs5') %>% rename(med_income_17= estimate) %>% select(med_income_17, GEOID)
atl_pop <-left_join(atl_plus, fult_pop)
atl_pop_inc <- left_join(atl_pop, fult_inc)
atl_atts_fult <- atl_pop_inc %>% select(GEOID, population_2017, Population2010, med_income_17)
### This part grabs the variables for the atl tracts in dekalb county
dek_pop <- get_acs(geography = 'tract',
variables = 'B25026_001',
county = 'Dekalb',
state = 'Georgia',
year = 2017,
survey = 'acs5') %>% rename(population_2017= estimate)
dek_inc <- get_acs(geography = 'tract',
variables = 'B21004_001',
county = 'Dekalb',
state = 'Georgia',
year = 2017,
survey = 'acs5') %>% rename(med_income_17= estimate) %>% select(med_income_17, GEOID)
dek_pop <-left_join(atl_plus, dek_pop)
dek_pop_inc <- left_join(dek_pop, dek_inc)
atl_atts_dek <- dek_pop_inc %>% select(GEOID, population_2017, Population2010, med_income_17) %>% filter(is.na(population_2017) == F) %>% st_drop_geometry()
## now join fulton and dekalb polys into one atlanta attributes dataframe
atl_atts <- left_join(atl_atts_fult, atl_atts_dek, by= 'GEOID')
atl_atts1 <- atl_atts %>%
mutate(pop_17 = ifelse(is.na(population_2017.x),population_2017.y, population_2017.x)) %>%
mutate(inc_17 = ifelse(is.na(med_income_17.x),med_income_17.y, med_income_17.x)) %>% select(GEOID, pop_17, inc_17) %>% st_drop_geometry()
#above mutate code is necessary to consolidate the fulton / dekalb attributes into single columns
# join with spending polygons
atl_spend_atts <- left_join(out, atl_atts1, by = c('GEOID.x' = 'GEOID'))
atl_spend_atts <- atl_spend_atts %>% filter(is.na(pop_17) == F) #remove some weird tracts that don't map and have no data
Analysis
Clusters
Looking at the map of budgeted spending by census tract it seems obvious that the constant risk assumption is violated. However, we’d like to know in what areas the spending is higher than expected based on the population of a tract. Thus, we will produce a map of poissson probabilities to test for and locate the local extremes.
library(spdep) #package for performing cluster analysis
atl_spend_atts$tot_spend <- as.numeric(atl_spend_atts$tot_spend) #conmvert from units class to numeric
atl_spend_atts <- atl_spend_atts %>% mutate(spend_ratio = ifelse( pop_17 > 0,(tot_spend * 1000000 / pop_17), NA)) %>%filter(is.na(spend_ratio) == F)
spend_probs <- probmap(n =atl_spend_atts$tot_spend,
x = atl_spend_atts$pop_17,
row.names = atl_spend_atts$GEOID.x)
atl_spend_atts$pmap <- spend_probs$pmap
#generate poisson probs
# This just summarizes (merges polygons) of all counties with significant HIGH risk
spend_hi <- atl_spend_atts %>% #form contiguous areas of sig high or low spending into polygons
filter(pmap > 0.95) %>% summarise()
spend_lo <- atl_spend_atts %>%
filter(pmap < 0.05) %>% summarise()
# make map of sig high or low spending areas
m1 <-tm_shape(atl_spend_atts) +
tm_fill('spend_ratio',
palette = 'BuPu',
style = 'quantile',
title = 'Spending per\nPerson (USD)') +
tm_borders() +
tm_layout(legend.position = c('RIGHT','TOP'),
main.title = 'Clusters of MARTA\nExpansion Spending by Population') +
# Now plot only borders of high or low rate counties
tm_shape(spend_lo) +
tm_borders(col = 'blue', lwd = 2) +
tm_shape(spend_hi) +
tm_borders(col = 'red', lwd = 2) +
# general layout stuff...
tm_layout(legend.outside = F, legend.text.size = 0.55,
legend.title.size = 0.65, legend.title.fontface = 'bold',
legend.position = c('LEFT', 'TOP'), inner.margins = c(0.02, .03, .02, 0),
main.title.position = 'center', main.title.size = 1, main.title.fontface = 'bold') +
tm_add_legend(type = 'line',
col = 'red',
lwd = 2,
labels = 'Significantly high') +
tm_add_legend(type = 'line',
col = 'blue',
lwd = 2,
labels = 'Significantly low')
Looking at the above map, almost all of the Atlanta census tracts fall into the category of significant high or low spending. Now, this was done with population count as the denominator, but what if using population density would give us a more clear picture?
The following code brings in the land area (km2) variable for each tract and calculates population density in persons per km2.
dek_tracts$ALAND <- as.numeric(dek_tracts$ALAND) #convert to numeric for calculations
dek_tracts_a <- dek_tracts %>%
select(GEOID, ALAND) %>% mutate(km2 = ALAND/1000000) %>% st_drop_geometry()
#fulton tracts
ful_tracts <- dek_tracts <- tracts('GA', county = 'Fulton') %>% st_as_sf() %>% st_drop_geometry()
ful_tracts$ALAND <- as.numeric(ful_tracts$ALAND)
ful_tracts_a <- ful_tracts %>%
select(GEOID, ALAND) %>% mutate(km2 = ALAND/1000000)
#joins and cleaning
fult_a <-left_join(atl_plus, ful_tracts_a)
dek_a <-left_join(atl_plus, dek_tracts_a)
all_a <- rbind(fult_a, dek_a) %>% filter(is.na(ALAND) == F) %>% select(GEOID, km2) %>% st_drop_geometry() #drop geometry to make a table that can be joined to main attributes file
area_atts <- left_join(atl_spend_atts, all_a, by=c('GEOID.x'='GEOID'))
area_atts <-area_atts %>% mutate(pop_dens = pop_17 / km2) #create pop density variable in persons per km2
Now we’ll run the test of local extremes again but with population density as the denominator. Finally, we’ll map the significant results to see how different it is than using pop counts.
Analysis:
spend_probs_dens <- probmap(n =area_atts$tot_spend,
x = area_atts$pop_dens,
row.names = area_atts$GEOID.x)
area_atts$pmap <- spend_probs_dens$pmap
#generate poisson probs
area_atts <- area_atts %>% mutate(spend_ratio_d = tot_spend *1000000/ pop_dens)
Map:
# This just summarizes (merges polygons) of all counties with significant HIGH risk
spend_hi_d <- area_atts %>% #form contiguous areas of sig high or low spending into polygons
filter(pmap > 0.95) %>% summarise()
spend_lo_d <- area_atts %>%
filter(pmap < 0.05) %>% summarise()
# make map of sig high or low spending areas
m2 <-tm_shape(area_atts) +
tm_fill('spend_ratio_d',
palette = 'BuPu',
style = 'quantile',
title = 'Spending per\nPerson Per Km2 (USD)') +
tm_borders() +
tm_layout(legend.position = c('RIGHT','TOP'),
main.title = 'Clusters of MARTA\nExpansion Spending by Pop. Density') +
# Now plot only borders of 'high-rate' counties
tm_shape(spend_lo_d) +
tm_borders(col = 'blue', lwd = 2) +
tm_shape(spend_hi_d) +
tm_borders(col = 'red', lwd = 2) +
#general layout
tm_layout(legend.outside = F, legend.text.size = 0.55,
legend.title.size = 0.65, legend.title.fontface = 'bold',
legend.position = c('LEFT', 'TOP'), inner.margins = c(0.02, .03, .02, 0),
main.title.position = 'center', main.title.size = 1, main.title.fontface = 'bold') +
tm_add_legend(type = 'line',
col = 'red',
lwd = 2,
labels = 'Significantly high') +
tm_add_legend(type = 'line',
col = 'blue',
lwd = 2,
labels = 'Significantly low')
tmap_arrange(m1, m2)

The use of population density does change the distribution of significantly extreme tracts such that there are fewer significant tracts overall and some tracts switch from sig hi to low and vice versa. Either way you slice it, there are clear significant extreme clusters of spending. However, using pop density as the denominator seems to remove some of the noise caused by having similar populations in drastically differently sized tracts.
Regression
Now that I’ve established significant clustering of high and low spending exists,I’d like to see if this phenomenon can be explained by other underlying factors. In particular, I am interested to examine the correlation of median tract income with budgeted spending.
First I will fit my linear regression models.
#empty model
#before my tot_spend variable was in millions of dollars, I will convert it back to dollars for running my models
area_atts$tot_spend <- area_atts$tot_spend / 1000000
m0 <- lm(tot_spend ~ 1, data = area_atts)
#conditional model
m1 <- lm(tot_spend ~ pop_dens + inc_17, data = area_atts)
summary(m1)
The results of my conditional model show that, holding population density constant, 2017 median tract income was a significant negative predictor of budgeted MARTA spending. Based on the model, each dollar increase in median income is associated with a 796.8 dollar decrease in planned spending. However, it is important to note that since I have zero dollar values for 26 of 130 tracts, the residuals and residual standard error for this model are huge.
summary(area_atts$spend)
Now I’ll test the residuals from my model to see whether our factors explain any of the variation in spatial autocorrelation between tracts.
This will involve first choosing a neighbors definiton and then running the lm.morantest function. I have decided to use k-nearest neighbors of 3 due to the fact that emory is not touching any other atl tracts and several border tracts have only one contiguous neighbor.
##Creating nb object
#since we're using proximity based nb object, we need the tract centroid points
area_atts_sp <- as(area_atts, 'Spatial')
area_points <- coordinates(area_atts_sp)
area_k3 <- knearneigh(area_points, k =3) #creates set of 3 nearest neighbors
area_k3_nb <- knn2nb(area_k3, row.names = area_atts_sp$GEOID.x, sym = T) #creates a symmetrical nb object
area_listw <- area_k3_nb %>% nb2listw() #creates listw object for Moran's I test
##performing lm.morantest()
#empty model residuals
lm.morantest(m0, listw = area_listw)
Global Moran I for regression residuals
data:
model: lm(formula = tot_spend ~ 1, data = area_atts)
weights: area_listw
Moran I statistic standard deviate = 4.5259, p-value = 3.007e-06
alternative hypothesis: greater
sample estimates:
Observed Moran I Expectation Variance
0.281758061 -0.007751938 0.004091894
#conditional model residuals
#m1_1 <- lm(tot_spend ~ inc_17, data = area_atts) #I thought of to just test the effect of income since pop_dens wasn't significant but decided to include pop_dens after all
lm.morantest(m1, listw = area_listw)
Global Moran I for regression residuals
data:
model: lm(formula = tot_spend ~ pop_dens + inc_17, data = area_atts)
weights: area_listw
Moran I statistic standard deviate = 3.9708, p-value = 3.581e-05
alternative hypothesis: greater
sample estimates:
Observed Moran I Expectation Variance
0.233938193 -0.016975080 0.003992891
From these tests we see there is relatively low spatial autocorrelation in model residuals for budgeted spending. Of that, only about 17% is explained by tract median income and population density. My conjecture is that much of the remaining autocorrelation is explained by the fact that many of the high-value projects are comprised of beltline rail. By definition, all these projects are contiguous and since the beltline follows old rail throughways in the city, their locations may be less entagled with other demographic factors.
For the final figures in this project, I’ll map the model residuals.

The maps illustrate that our factors slightly reduce spatial autocorrelation but there is still a fair amount of spatial structure present due to the periphery tracts with zero spending. Interestingly, some of the largest residuals are in the central portion of the city. This is where, as I mentioned previously, innacuracies in digitization may have missed assigning spending to some tracts.
LS0tDQp0aXRsZTogJ0VwaSA1OTAgRmluYWwgUHJvamVjdCcNCmF1dGhvcjogIkRlbm5pcyBOaWNob2xzIg0KZGF0ZTogIjEyLzEwLzE5Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQpzdWJ0aXRsZTogQXNzZXNzaW5nIHRoZSBlcXVpdHkgb2YgdGhlIHBsYW5uZWQgTUFSVEEgZXhwYW5zaW9uIGluIHRoZSBDaXR5IG9mIEF0bGFudGENCi0tLQ0KDQojSW50cm9kdWN0aW9uDQoNCkFjY2VzcyB0byB0cmFuc3BvcnRhdGlvbiBpcyBhbiBpbXBvcnRhbnQgc29jaWFsIGRldGVybWluYW50IG9mIGhlYWx0aCAoU0RPSCkuICBQZW9wbGUncyB0cmFuc2l0IGVudmlyb25tZW50IGFmZmVjdHMgdGhlaXIgYWJpbGl0eSB0byByZWFjaCBmcmVzaCBmb29kIGFuZCBoZWFsdGhjYXJlIGluc3RpdHV0aW9ucyB3aGljaCBjYW4gZGV0ZXJtaW5lIGhlYWx0aCBvbiBhIGRhaWx5IGJhc2lzLiAgVHJhbnNpdCBhY2Nlc3MgYWxzbyBkZXRlcm1pbmVzIHdoYXQgam9icyBwZW9wbGUgY2FuIHJlYWNoIHdoaWNoIGhhcyBpbXBvcnRhbnQgbG9uZy10ZXJtIHNvY2lvZWNvbm9taWMgY29uc2VxdWVuY2VzLiANCg0KVGhlICoqcHVycG9zZSoqIG9mIG15IGFuYWx5c2lzIHdpbGwgYmUgdG8gZXhhbWluZSBlcXVpdHkgaW4gdGhlIGFwcG9ydGlvbm1lbnQgb2YgZnVuZHMgZnJvbSB0aGUgJDIuNSBiaWxsaW9uIE1BUlRBIGV4cGFuc2lvbiB0YXggYXBwcm92ZWQgaW4gMjAxNiBpbiB0aGUgQ2l0eSBvZiBBdGxhbnRhLiBEaXNlYXNlIG1hcHBpbmcgd2lsbCBiZSB1c2VkIHRvIGlsbHVzdHJhdGUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBmdW5kcyBhdCB0aGUgY2Vuc3VzIHRyYWN0IGxldmVsIGFuZCBzcGF0aWFsIHJlZ3Jlc3Npb24gd2lsbCBiZSB1c2VkIHRvIGRldGVybWluZSBpZiBkb2xsYXJzIHJlY2VpdmVkIGJ5IGEgdHJhY3Qgc2lnbmlmaWNhbnRseSBjb3Zhcnkgd2l0aCBmYWN0b3JzIGxpa2UgbWVkaWFuIGluY29tZSwgcG9wdWxhdGlvbiwgcmFjaWFsIGNvbXBvc2l0aW9uLCBldGMuIE5lY2Vzc2FyeSBkYXRhIG9uIHByb2plY3QgYnVkZ2V0cyB3aWxsIGJlIGRyYXduIGZyb20gbmV3c3BhcGVyIGFydGljbGVzIGFuZCB0aGUgc3BhdGlhbCBsb2NhdGlvbiBvZiBuZXcgcHJvamVjdHMgd2lsbCBiZSBkaWdpdGl6ZWQgaW50byBsaW5lIGZpbGVzIGZyb20gcHJvamVjdCBtYXBzIGF2YWlsYWJsZSBvbiB0aGUgTUFSVEEgd2Vic2l0ZS4NCg0KDQojRGF0YSBJbXBvcnQgYW5kIENsZWFuaW5nDQoNCioqTGlicmFyaWVzKioNCg0KYGBge3J9DQpsaWJyYXJ5KHJpbykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGJpdDY0KQ0KbGlicmFyeShzZikNCmxpYnJhcnkodG1hcCkNCmxpYnJhcnkodGlncmlzKQ0KbGlicmFyeShsd2dlb20pDQpsaWJyYXJ5KHRpZHljZW5zdXMpDQpgYGANCg0KDQoNCioqQ2l0eSBvZiBBdGxhbnRhIENlbnN1cyBUcmFjdHMqKg0KDQpDaXR5IG9mIEF0bGFudGEgY2Vuc3VzIHRyYWN0cyAocHJpb3IgdG8gYW5uZXhhdGlvbiBvZiBFbW9yeSkgYW5kIGFzc29jaWF0ZWQgYXR0cmlidXRlIGRhdGEgd2VyZSBtYW51YWxseSBkb3dubG9hZGVkIGZyb20gdGhlIDUwMCBjaXRpZXMgcHJvamVjdCBwYWdlIG9uIHRoZSBDREMgd2Vic2l0ZS4gTmV4dCB0aGUgZ2VvZ3JhcGhpZXMgYW5kIGF0dHJpYnV0ZXMgd2VyZSBpbXBvcnRlZCBhbmQgam9pbmVkIHdpdGggdGhlIGZvbGxvd2luZyBjb2RlLg0KDQpgYGB7cn0NCmZpdmVfY2l0eSA8LWltcG9ydCgnQzovVXNlcnMvZHZlcm4vRGVza3RvcC9NQVJUQSBQcm9qZWN0LzUwMF9jaXRpZXMuY3N2JykNCmFsbF90cmFjdHMgPC1zdF9yZWFkKCdDOi9Vc2Vycy9kdmVybi9EZXNrdG9wL01BUlRBIFByb2plY3QvdHJhY3RzLzUwMENpdGllc19UcmFjdHNfQ2xpcC5zaHAnKQ0KDQphdGxfdHJhY3RzIDwtIGFsbF90cmFjdHMgJT4lIGZpbHRlcihQbGFjZU5hbWUgPT0gJ0F0bGFudGEnKQ0KDQphdGxfZGF0YSA8LSBmaXZlX2NpdHkgJT4lIGZpbHRlcihQbGFjZU5hbWUgPT0gJ0F0bGFudGEnKQ0KDQphdGxfdHJhY3RzJHBsY3RyYWN0MTAgPC0gYXMuY2hhcmFjdGVyKGF0bF90cmFjdHMkcGxjdHJhY3QxMCkNCg0KYXRsIDwtIGxlZnRfam9pbihhdGxfdHJhY3RzLCBhdGxfZGF0YSwgYnk9IGMoJ3BsY3RyYWN0MTAnPSdQbGFjZV9UcmFjdElEJykpDQoNCiNzdF93cml0ZShhdGwsICdDOi9Vc2Vycy9kdmVybi9EZXNrdG9wL01BUlRBIFByb2plY3QvYXRsX3RyYWN0cy5zaHAnKSANCg0KI0VTUkkgc2hhcGVmaWxlIG9mIGF0bCBjZW5zdXMgdHJhY3RzIHNhdmVkIHRvIGFzc2lzdCB3aXRoIGdlb3JlZmVyZW5jaW5nIG9mIHByb2plY3QgbGluZXMNCg0KYGBgDQoNCipQcm9qZWN0aW9uKg0KDQpUaGUgVVRNIFpvbmUgMTZOIHByb2plY3Rpb24gd2FzIGNob3NlbiBmb3IgdGhpcyBwcm9qZWN0IGFzIGl0IG1haW50YWlucyBkaXN0YW5jZSByZWxhdGlvbnNoaXBzIGluIHNtYWxsIGFyZWFzIG9uIHRoZSBzY2FsZSBvZiBjaXRpZXMgYW5kL29yIGNvdW50aWVzLg0KDQpgYGB7cn0NCnggPC0gMzI2MTYgICNtYWtlcyBhIHZhcmlhYmxlIHRvIGhvbGQgdGhlIEVQU0cgY29kZSBmb3IgVVRNIDE2Tg0KYXRsIDwtc3RfdHJhbnNmb3JtKGF0bCwgY3JzID0geCkgJT4lIHNlbGVjdChQb3B1bGF0aW9uMjAxMCwgVHJhY3RGSVBTKSAgI3RyaW0gYXR0cmlidXRlcyBJJ20gbm90IGNvbmNlcm5lZCB3aXRoIGZvciBub3cNCg0KYXRsJFRyYWN0RklQUyA8LSBhcy5jaGFyYWN0ZXIoYXRsJFRyYWN0RklQUykNCg0KYXRsIDwtIGF0bCAlPiUgcmVuYW1lKEdFT0lEID0gVHJhY3RGSVBTKSAjY2hhbmdlIHZhcmlhYmxlIG5hbWUgdG8gZmFjaWxpdGF0ZSBmdXR1cmUgam9pbiBvcGVyYXRpb24NCmBgYA0KDQoqQWRkIGluIEVtb3J5L0NEQyoNCg0KRW1vcnkgYW5kIHRoZSBDREMgd2VyZSBub3QgaW5jb3Jwb3JhdGVkIGludG8gdGhlIENpdHkgb2YgQXRsYW50YSBhdCB0aGUgdGltZSBvZiB0aGUgNTAwIGNpdGllcyBwcm9qZWN0LiBUaGlzIGNvZGUgd2lsbCB1c2UgdGhlIHRpZHkgY2Vuc3VzIHBhY2thZ2UgdG8gZG93bmxvYWQgdGhlIERla2FsYiBjb3VudHkgY2Vuc3VzIHRyYWN0cywgZmlsdGVyIGRvd24gdG8gRW1vcnkncyB0cmFjdCwgdGhlbiBqb2luIGl0IHdpdGggdGhlIHJlc3Qgb2YgQXRsYW50YS4NCg0KYGBge3J9DQpvcHRpb25zKHRpZ3Jpc191c2VfY2FjaGU9VFJVRSkgI3ByZXZlbnQgcmVkb3dubG9hZGluZyBmaWxlcw0KZGVrX3RyYWN0cyA8LSB0cmFjdHMoJ0dBJywgY291bnR5ID0gJ0Rla2FsYicpICU+JSBzdF9hc19zZigpICNkb3dubG9hZCBjZW5zdXMgdHJhY3RzIHRvIERla2FsYiBjb3VudHkNCg0KZW1vcnkgPC0gZGVrX3RyYWN0cyAlPiUgZmlsdGVyKE5BTUUgPT0gJzIyNC4wMicpICU+JSBzdF90cmFuc2Zvcm0oeCkgJT4lIHNlbGVjdChHRU9JRCkgJT4lIA0KICBtdXRhdGUoUG9wdWxhdGlvbjIwMTAgPSAxKSAjIG5lZWQgdG8gYWRkIHBsYWNlaG9sZGVyIHBvcHVsYXRpb24gdmFyaWFibGUgdG8gZW5hYmxlIHJvd2JpbmQgd2l0aCByZXN0IG9mIEFUTA0KDQphdGxfcGx1cyA8LSByYmluZChhdGwsIGVtb3J5KQ0KDQoNCmBgYA0KDQoNCioqUHJvamVjdCBMaW5lcyBGaWxlKioNCg0KRGlnaXRpemF0aW9uIG9mIHRoZSBwbGFubmVkIE1BUlRBIGV4cGFuc2lvbiBwcm9qZWN0IHNlZ21lbnRzIHdhcyBjb25kdWN0ZWQgaW4gQXJjR0lTLiBGaXJzdCB0aGUgZm9sbG93aW5nIHByb2plY3QgbWFwIHdhcyBnZW9yZWZlcmVuY2VkIHRvIHRoZSBhdGxhbnRhIGNlbnN1cyB0cmFjdHMgZmlsZSBmcm9tIGVhcmxpZXIgdXNpbmcgZGlyZWN0aW9ucyBmb3VuZCBhdCBbdGhpcyBCcm93biB1bml2ZXJzaXR5IHBkZl0oaHR0cHM6Ly9zNC5hZC5icm93bi5lZHUvUmVzb3VyY2VzL1R1dG9yaWFsL01vZHVsMi9HZW9yZWZlcmVuY2luZyUyMGFuZCUyMERpZ2l0aXppbmclMjAlMjBpbiUyMEFyY0dJUy5wZGYpLg0KDQohW10obWFydGFfbWFwLmpwZykNCg0KTmV4dCB0aGUgZGlnaXRpemVkIHNlZ21lbnRzIHdlcmUgYnJvdWdodCBpbnRvIHRoZSBSIGVudmlyb25tZW50Lg0KDQpgYGB7cn0NCg0KZGlnX3NlZ3MgPC1zdF9yZWFkKCdDOi9Vc2Vycy9kdmVybi9EZXNrdG9wL01BUlRBIFByb2plY3QvTmV3IHNlZ3MvbmV3X3NlZ3MxLnNocCcpDQpkaWdfc2Vncy5wcm9qIDwtc3RfdHJhbnNmb3JtKGRpZ19zZWdzLCBjcnM9eCkNCg0KZGlnX3NlZ3MucHJvaiROYW1lIDwtIGFzLmNoYXJhY3RlcihkaWdfc2Vncy5wcm9qJE5hbWUpICNhc3Npc3QgZnV0dXJlIGpvaW4NCmBgYA0KDQpGaW5hbGx5IHRoZSBwcm9qZWN0ZWQgYnVkZ2V0IGZvciBlYWNoIHByb2plY3Qgd2FzIGNvbGxhdGVkIGZyb20gdGhpcyBBdGxhbnRhIEpvdXJuYWwtQ29uc3RpdHV0aW9uIFthcnRpY2xlXShodHRwczovL3d3dy5hamMuY29tL2Jsb2cvY29tbXV0aW5nL21hcnRhLWZpbmFsLWF0bGFudGEtZXhwYW5zaW9uLXBsYW4tZGV0YWlsZWQtbG9vay91SUtHbDUySE9ZWjFGQUtmYmFWVGlKLykgYW5kIGltcG9ydGVkIGFzIGEgdGFibGUuIFRoaXMgd2FzIHRoZSBqb2luZWQgd2l0aCB0aGUgcHJvamVjdHMgbGluZSBmaWxlLg0KDQpgYGB7cn0NCnByb2pfdmFscyA8LSBpbXBvcnQoJ0M6L1VzZXJzL2R2ZXJuL0Rlc2t0b3AvTUFSVEEgUHJvamVjdC9wcm9qX3ZhbHVlcy5jc3YnKQ0KDQpzZWdfdmFscyA8LSBsZWZ0X2pvaW4oZGlnX3NlZ3MucHJvaiwgcHJval92YWxzKSAjYXNzb2NpYXRlcyBlYWNoIHNlZ21lbnQgd2l0aCB0aGUgcHJvamVjdCBidWRnZXQgZm9yIHRoYXQgc2VnbWVudA0KDQpgYGANCg0KI0dlb3Byb2Nlc3NpbmcgU3RlcHMNCg0KKipTZWdtZW50IExlbmd0aCBhbmQgYnVkZ2V0IHJhdGlvKioNCg0KVGhlIGZvbGxvd2luZyBzdGVwcyBjYWxjdWxhdGUgdGhlIGluZGl2aWR1YWwgc2VnbWVudCBsZW5ndGhzIGFuZCB0aGUgdG90YWwgbGVuZ3RoIG9mIGVhY2ggcHJvamVjdCAoc29tZSBjb21wcmlzZSBtYW55IHNlZ21lbnRzLCBzdWNoIGFzIHRoZSBhZGRpdGlvbiBvZiBtb3JlIGZyZXF1ZW50IGJ1cyBzZXJ2aWNlIGFsb25nIHNvbWUgcm91dGVzKS4gVGhlbiBhIGNvc3QgcGVyIG1pbGUgcmF0aW8gd2FzIGdlbmVyYXRlZCBmcm9tICp0b3RhbCBidWRnZXQvdG90YWwgbGVuZ3RoKi4gVGhpcyByYXRpbyBjYWxjdWxhdGlvbiB0b29rIHBsYWNlIGluIGEgc2VwYXJhdGUgZGF0YSBmcmFtZSBkdWUgdG8gdGhlIHVzZSBvZiBgZ3JvdXBieWAgYW5kIHRoZSBmaW5hbCBzdGVwIGpvaW5zIHRoZSByYXRpbyBiYWNrIHRvIHRoZSBvcmlnaW5hbCBzZWdtZW50cyBmaWxlLg0KDQpgYGB7cn0NCiNnZXQgaW5kaXZpZHVhbCBzZWdtZW50IGxlbmd0aA0KDQpzZWdfdmFscyRsZW5ndGggPC0gc3RfbGVuZ3RoKHNlZ192YWxzKQ0Kc2VnX3ZhbHMkbGVuZ3RoIDwtIGFzLm51bWVyaWMoc2VnX3ZhbHMkbGVuZ3RoKSAjc3RfbGVuZ3RoIG91dHB1dHMgaW4gdGhlIHVuaXRzIGNsYXNzIHdoaWNoIGlzIGluY29tcGF0aWJsZSB3aXRoIGNhbGN1bGF0aW9ucw0Kc2VnX3ZhbHMgPC0gc2VnX3ZhbHMgJT4lIG11dGF0ZShrbSA9IGxlbmd0aCAvIDEwMDApICU+JSBtdXRhdGUobWlsZXMgPSBrbSowLjYyMTM3MSkgICNhZGQgbGVuZ3RocyBpbiBrbSBhbmQgbWlsZXMNCg0KDQojZm9ybWluZyB0aGUgcmF0aW8gdmFyaWFibGUgZm9yIGVhY2ggcHJvamVjdA0KDQpyYXRpbyA8LSBzZWdfdmFscyAlPiUgZ3JvdXBfYnkoTmFtZSkgJT4lIHN1bW1hcmlzZSh0b3RfbGVuID0gc3VtKG1pbGVzKSkgI3N1bSBsZW5ndGhzIG9mIHNlZ21lbnRzIHRoYXQgZmFsbCB1bmRlciB0aGUgc2FtZSBwcm9qZWN0DQoNCnJhdDEgPC0gbGVmdF9qb2luKHJhdGlvLCBwcm9qX3ZhbHMpICNqb2luIGluIHRoZSBwcm9qIHZhbHVlcyBzbyB0aGF0IGEgJC9taWxlIHJhdGlvIHZhcmlhYmxlIGNhbiBiZSBtYWRlDQpyYXQyIDwtIHJhdDEgJT4lIG11dGF0ZShyYXRpbyA9IEJ1ZGdfbWlsIC8gdG90X2xlbikNCg0KcmF0MyA8LSByYXQyICU+JSBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lIHNlbGVjdChyYXRpbywgTmFtZSkgI3NlbGVjdCB2YXJpYWJsZXMgZm9yIGpvaW5pbmcgYmFjayB0byBtYWluLCB1bmdyb3VwZWQsIHNlZ21lbnRzIGZpbGUNCg0KI2pvaW4gcmF0aW8gdG8gb3JpZ2luYWwgc2VnbWVudHMgZmlsZQ0KDQpzZWdfdmFsczEgPC0gbGVmdF9qb2luKHNlZ192YWxzLCByYXQzKQ0KYGBgDQoNCg0KKipKb2luaW5nIHNlZ21lbnRzIHRvIHRyYWN0cywgY2FsY3VsYXRpbmcgdG90YWwgYnVkZ2V0ZWQgc3BlbmRpbmcgcGVyIHRyYWN0KioNCg0KVGhpcyBzdGVwIHdpbGwgam9pbiBzZWdtZW50cyB0byB0cmFjdHMgdXNpbmcgYHN0X2ludGVyc2VjdGlvbmAgd2hpY2ggd2lsbCBjaG9wIHRoZSBsaW5lcyBpbnRvIHNtYWxsZXIgc2VjdGlvbnMgYmFzZWQgb24gd2hhdCB0cmFjdCB0aGV5IGludGVyc2VjdCB3aXRoLiBUaGlzIHdpbGwgZW5hYmxlIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgc3BlbmRpbmcgcGVyIHNlY3Rpb24uIFRoZW4sIG9uY2UgdGhlIHNlY3Rpb25zIGFyZSBqb2luZWQgd2l0aCBwb2x5Z29ucywgYWdncmVnYXRpb24gdG8gdGhlIHBvbHlnb24gd2lsbCBnaXZlIHVzIHRoZSB0b3RhbCBzcGVuZGluZyBwZXIgcG9seWdvbiB1c2luZyB0aGUgYHN1bW1hcml6ZWAgc3RlcC4NCg0KDQpgYGB7cn0NCiMgaW50ZXJzZWN0aW9uDQppbnQgPSBzdF9pbnRlcnNlY3Rpb24oc2VnX3ZhbHMxLCBhdGxfcGx1cykNCiMgZmluZCBvdXQgYWJvdXQgdGhlIGxlbmd0aCBvZiBlYWNoIGxpbmUgc2VnbWVudA0KaW50JGxlbiA9IHN0X2xlbmd0aChpbnQpDQppbnQxIDwtIGludCAlPiUgbXV0YXRlKGttID0gbGVuIC8gMTAwMCkgJT4lIG11dGF0ZShtaWxlcyA9IGttKjAuNjIxMzcxKSAgI2FkZCBsZW5ndGhzIGluIGttIGFuZCBtaWxlcw0KaW50MiA8LSBpbnQxICU+JSBtdXRhdGUoc3BlbmRpbmcgPSBtaWxlcyAqIHJhdGlvKQ0KDQojIHNwYXRpYWwgb3ZlcmxheQ0Kam9pbl9uZXcgPSBzdF9qb2luKGF0bF9wbHVzLCBpbnQyKQ0KIyB1c2UgdGhlIElEIG9mIHRoZSBwb2x5Z29uIGZvciB0aGUgYWdncmVnYXRpb24NCm91dCA9IGdyb3VwX2J5KGpvaW5fbmV3LCBHRU9JRC54KSAlPiUNCiAgc3VtbWFyaXplKHRvdF9zcGVuZCA9IHN1bShzcGVuZGluZykpDQoNCm91dFtpcy5uYShvdXQpXSA8LSAwICNyZXBsYWNlIE5BcyB3aXRoIHplcm9zIHRvIGFzc2lzdCBmdXR1cmUgY2FsY3VsYXRpb25zDQoNCmBgYA0KDQpOZXh0IHRoZSBtYWpvciBwcm9qZWN0cyB3aWxsIGJlIHNlcGFyYXRlZCBvdXQgYnkgdHlwZSB0byBhc3Npc3Qgd2l0aCBmdXR1cmUgdmlzdWxhaXphdGlvbi4NCg0KYGBge3J9DQojI3NlcGFyYXRlIG91dCBwcm9qZWN0IHR5cGVzIGZvciBtYXBwaW5nDQoNCkxSVCA8LSBzZWdfdmFscyAlPiUgZmlsdGVyKFR5cGUgPT0gJ0xSVCcpDQoNCkZMQlMgPC0gc2VnX3ZhbHMgJT4lIGZpbHRlcihUeXBlID09ICdGTEJTJykNCg0KQlJUIDwtIHNlZ192YWxzICU+JSBmaWx0ZXIoVHlwZSA9PSAnQlJUJykNCg0KQVJUIDwtIHNlZ192YWxzICU+JSBmaWx0ZXIoVHlwZSA9PSAnQVJUJyB8IE5hbWUgPT0gJ0NsZXZlbGFuZCBBVkUnKQ0KDQpgYGANCg0KDQoqKkZpcnN0IFRoZW1hdGljIE1hcHMqKg0KDQpUaGUgZm9sbG93aW5nIGNvZGUgbWFrZXMgdGhlIGZpcnN0IHRoZW1hdGljIG1hcHMgb2YgdGhlIHNwYXRpYWwgdmFyaWF0aW9uIGluIGJ1ZGdldGVkIE1BUlRBIHNwZW5kaW5nLiBNYWpvciBQcm9qZWN0IGxpbmVzIGFyZSBzaG93biBmb3IgY29udGV4dC4gQSB2ZXJzaW9uIHdoZXJlIHRoZSB0cmFjdHMgd2l0aCB6ZXJvIHNwZW5kaW5nIHdlcmUgc2hvd24gYXMgZ3JleSB3YXMgZXhwZXJpbWVudGVkIHdpdGguDQoNCmBgYHtyfQ0KICB0bV9zaGFwZShvdXQpICsNCiAgdG1fZmlsbCgndG90X3NwZW5kJywgDQogICAgICAgICAgdGl0bGUgPSAnQnVkZ2V0ZWQgU3BlbmRpbmdcbihNaWxsaW9ucyBVU0QpJywNCiAgICAgICAgICBzdHlsZSA9ICdxdWFudGlsZScsDQogICAgICAgICAgcGFsZXR0ZSA9ICdCdVB1JykgKyANCiAgdG1fYm9yZGVycygpICsNCiN0bV9zaGFwZShvdXRfbm9uZSkgKyB0bV9maWxsKCdzcGVuZCcsIGNvbCA9ICdncmV5JywgYWxwaGEgPSAxKSArIHRtX2JvcmRlcnMoKSArDQogIHRtX3NoYXBlKExSVCkgKyB0bV9saW5lcyhsd2QgPSAyKSArDQogIHRtX3NoYXBlKEJSVCkgKyB0bV9saW5lcyhsd2QgPSAyLCBjb2wgPSAncmVkJykgKw0KICB0bV9zaGFwZShBUlQpICsgdG1fbGluZXMobHdkID0gMiwgY29sID0gJ2JsdWUnKSArIA0KICAgICN0bV9zaGFwZShGTEJTKSArIHRtX2xpbmVzKGx3ZCA9IDEsIGNvbCA9ICduYXZ5JykgKyANCiAgI3RtX2FkZF9sZWdlbmQodHlwZSA9ICdmaWxsJywgY29sID0gJ2dyZXknLCBsYWJlbHMgPSAnMC4wMCcpICsNCiAgdG1fYWRkX2xlZ2VuZCh0eXBlID0gJ2xpbmUnLCBjb2wgPSAnYmxhY2snLCBsd2QgPSAzLCBsYWJlbHMgPSAnTFJUJykgKw0KICB0bV9hZGRfbGVnZW5kKHR5cGUgPSAnbGluZScsIGNvbCA9ICdibHVlJywgbHdkID0gMywgbGFiZWxzID0gJ0FSVCcpICsNCiAgdG1fYWRkX2xlZ2VuZCh0eXBlID0gJ2xpbmUnLCBjb2wgPSAncmVkJywgbHdkID0gMywgbGFiZWxzID0gJ0JSVCcpICsgDQogIA0KICB0bV9jcmVkaXRzKCdTb3VyY2U6IEF0bGFudGEgSm91cm5hbC1Db25zdGl0dXRpb24nLCBmb250ZmFjZSA9ICdib2xkJywgcG9zaXRpb24gPSBjKCdMRUZUJywnQk9UVE9NJykpICsNCiAgDQogIHRtX2xheW91dChsZWdlbmQudGl0bGUuZm9udGZhY2UgPSAnYm9sZCcpDQpgYGANCipOb3RlIHRoYXQgdGhpcyBhcHBlYXJzIHVuY3Jvd2RlZCBpbiB0aGUgbm9ybWFsIHZpZXdlciBhbmQgdXBvbiBleHBvcnQgYXMgYSBwaWN0dXJlLg0KDQoNCmBgYHtyfQ0KDQojbWFrZSBhIGRhdGFzZXQgd2l0aCBqdXN0IHplcm8gc3BlbmRpbmcgdHJhY3RzDQpvdXQkc3BlbmQgPC0gYXMubnVtZXJpYyhvdXQkdG90X3NwZW5kKQ0KDQpvdXRfbm9uZSA8LSBvdXQgJT4lIGZpbHRlcihzcGVuZCA9PSAwKQ0KDQojbWFwIHdpdGggZ3JleWVkIG91dCB6ZXJvcw0KDQogIHRtX3NoYXBlKG91dCkgKw0KICB0bV9maWxsKCd0b3Rfc3BlbmQnLCANCiAgICAgICAgICB0aXRsZSA9ICdCdWRnZXRlZCBTcGVuZGluZ1xuKE1pbGxpb25zIFVTRCknLA0KICAgICAgICAgIHN0eWxlID0gJ3F1YW50aWxlJywNCiAgICAgICAgICBwYWxldHRlID0gJ0J1UHUnKSArIA0KICB0bV9ib3JkZXJzKCkgKw0KdG1fc2hhcGUob3V0X25vbmUpICsgdG1fZmlsbCgnc3BlbmQnLCBjb2wgPSAnZ3JleScsIGFscGhhID0gMSkgKyB0bV9ib3JkZXJzKCkgKw0KICB0bV9zaGFwZShMUlQpICsgdG1fbGluZXMobHdkID0gMSkgKw0KICB0bV9zaGFwZShCUlQpICsgdG1fbGluZXMobHdkID0gMSwgY29sID0gJ3JlZCcpICsNCiAgdG1fc2hhcGUoQVJUKSArIHRtX2xpbmVzKGx3ZCA9IDEsIGNvbCA9ICdibHVlJykgKyANCiAgICB0bV9zaGFwZShGTEJTKSArIHRtX2xpbmVzKGx3ZCA9IDEsIGNvbCA9ICduYXZ5JykgKyANCiAgdG1fYWRkX2xlZ2VuZCh0eXBlID0gJ2ZpbGwnLCBjb2wgPSAnZ3JleScsIGxhYmVscyA9ICcwLjAwJykgKw0KICB0bV9hZGRfbGVnZW5kKHR5cGUgPSAnbGluZScsIGNvbCA9ICdibGFjaycsIGx3ZCA9IDMsIGxhYmVscyA9ICdMUlQnKSArDQogIHRtX2FkZF9sZWdlbmQodHlwZSA9ICdsaW5lJywgY29sID0gJ2JsdWUnLCBsd2QgPSAzLCBsYWJlbHMgPSAnQVJUJykgKw0KICB0bV9hZGRfbGVnZW5kKHR5cGUgPSAnbGluZScsIGNvbCA9ICdyZWQnLCBsd2QgPSAzLCBsYWJlbHMgPSAnQlJUJykgKyANCiAgDQogIHRtX2NyZWRpdHMoJ1NvdXJjZTogQXRsYW50YSBKb3VybmFsLUNvbnN0aXR1dGlvbicsIGZvbnRmYWNlID0gJ2JvbGQnLCBwb3NpdGlvbiA9IGMoJ0xFRlQnLCdCT1RUT00nKSkgKw0KICANCiAgdG1fbGF5b3V0KGxlZ2VuZC50aXRsZS5mb250ZmFjZSA9ICdib2xkJykNCmBgYA0KDQpBIGNsb3NlIGV4YW1pbmF0aW9uIG9mIHRoaXMgc2Vjb25kIG1hcCByZXZlYWxzIHRoYXQgdGhlcmUgYXJlIGEgZmV3IGNlbnRyYWwgdHJhY3RzIHdoaWNoIHByb2JhYmx5IHNob3VsZG4ndCBiZSBpZGVudGlmaWVkIGFzIHplcm8gc3BlbmRpbmcuIEhvd2V2ZXIsIGR1ZSB0byBzbWFsbCBpbmFjY3VyYWNpZXMgaW4gdGhlIGdlb3JlZmVyZW5jaW5nIGFuZCBkaWdpdGl6YXRpb24gcHJvY2Vzcywgc29tZSBzZWdtZW50cyBhbmQgdHJhY3RzIGRvbid0IG92ZXJsYXAgd2hlbiB0aGV5IHByb2JhYmx5IHNob3VsZC4gSSBzYXkgKnByb2JhYmx5KiBiZWNhdXNlIGluIG1vc3QgY2FzZXMsIHRoZSB0cmFjdCBib3VuZGFyaWVzIGFwcGVhciB0byBmb2xsb3cgbWFqb3IgdHJhbnNwb3J0YXRpb24gcm91dGVzLg0KDQpVbmZvcnR1bmF0ZWx5LCBhdCB0aGlzIHN0YWdlIEkndmUgYWxyZWFkeSBzcGVudCBhIExPVCBvZiB0aW1lIGdlb3Byb2Nlc3NpbmcgYW5kIEkgbmVlZCB0byBnZXQgdG8gdGhlIGFuYWx5c2lzLg0KVG8gaW1wcm92ZSB0aGlzIGluIHRoZSBmdXR1cmUsIEkgd291bGQgbmVlZCB0byBjb21wYXJlIHRoZSB0cmFjdCBib3VuZGFyaWVzIGluIHF1ZXN0aW9uIGFuZCBzZWUgaWYgdGhleSBpbmRlZWQgZmFsbCBhbG9uZyBtYWpvciByb2Fkcy8gdHJhbnNpdCByb3V0ZXMgdGhhdCBhcmUgaW4gdGhlIE1BUlRBIHByb2plY3QgbGlzdC4gRnJvbSB0aGVyZSwgSSdkIG5lZWQgdG8gcmVkaWdpdGl6ZSBzZWdtZW50cyB0aGF0IG1hdGNoIHVwIGJldHRlci4NCg0KT24gdG8gYW5hbHlzaXMuDQoNCg0KKipEb3dubG9hZGluZywgY2xlYW5pbmcsIGFuZCBqb2luaW5nIG90aGVyIGF0dHJpYnV0ZSBkYXRhKioNCg0KSnVzdCBraWRkaW5nIGFib3V0IGJlaW5nIHJlYWR5IHRvIGRvIGFuYWx5c2lzLiBOb3cgSSBuZWVkIHRvIGRvd25sb2FkIHNvbWUgY292YXJpYXRlIGRhdGEgKHBvcHVsYXRpb24gYW5kIG1lZGlhbiBpbmNvbWUpIGZyb20gdGhlIEFDUyBmb3IgbXkgdHJhY3RzLg0KVGhpcyB0b29rIGEgZmFpciBhbW91bnQgb2YgcHJvY2Vzc2luZyBhcyBBdGxhbnRhIHNwcmVhZHMgYWNyb3NzIGJvdGggRnVsdG9uIGFuZCBEZWthbGIgY291bnRpZXMuDQoNCmBgYHtyfQ0KIyMjIyBhdHRyaWJ1dGVzIHRvIHRyYWN0cyBqb2luDQogIA0KICBsaWJyYXJ5KHRpZHljZW5zdXMpDQogIA0KICBhbGxfdmFycyA8LSBsb2FkX3ZhcmlhYmxlcyh5ZWFyID0gMjAxNywgZGF0YXNldCA9ICdhY3M1JywgY2FjaGUgPSBUKQ0KICANCiAgIyBGcm9tIG15IHNlYXJjaCwgSSBmb3VuZCB0aGF0IEkgd2FudCB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczogJ0IyNTAyNl8wMDEnLCdCMjEwMDRfMDAxJw0KICANCiAgIyMgdGhpcyBwYXJ0IGdyYWJzIHRoZSB2YXJpYWJsZXMgZm9yIHRoZSBhdGwgdHJhY3RzIGluIGZ1bHRvbiBjb3VudHkNCiAgDQogIGZ1bHRfcG9wIDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gJ3RyYWN0JywNCiAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGVzID0gJ0IyNTAyNl8wMDEnLA0KICAgICAgICAgICAgICAgICAgICAgICBjb3VudHkgPSAnRnVsdG9uJywNCiAgICAgICAgICAgICAgICAgICAgICAgc3RhdGUgPSAnR2VvcmdpYScsDQogICAgICAgICAgICAgICAgICAgICAgeWVhciA9IDIwMTcsDQogICAgICAgICAgICAgICAgICAgICAgIHN1cnZleSA9ICdhY3M1JykgJT4lIHJlbmFtZShwb3B1bGF0aW9uXzIwMTc9IGVzdGltYXRlKQ0KICANCiAgZnVsdF9pbmMgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAndHJhY3QnLA0KICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcyA9ICdCMjEwMDRfMDAxJywNCiAgICAgICAgICAgICAgICAgICAgICBjb3VudHkgPSAnRnVsdG9uJywNCiAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9ICdHZW9yZ2lhJywNCiAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gMjAxNywNCiAgICAgICAgICAgICAgICAgICAgICBzdXJ2ZXkgPSAnYWNzNScpICU+JSByZW5hbWUobWVkX2luY29tZV8xNz0gZXN0aW1hdGUpICU+JSBzZWxlY3QobWVkX2luY29tZV8xNywgR0VPSUQpDQogIA0KICANCiAgYXRsX3BvcCA8LWxlZnRfam9pbihhdGxfcGx1cywgZnVsdF9wb3ApDQogIA0KICBhdGxfcG9wX2luYyA8LSBsZWZ0X2pvaW4oYXRsX3BvcCwgZnVsdF9pbmMpDQoNCiAgYXRsX2F0dHNfZnVsdCA8LSBhdGxfcG9wX2luYyAlPiUgc2VsZWN0KEdFT0lELCBwb3B1bGF0aW9uXzIwMTcsIFBvcHVsYXRpb24yMDEwLCBtZWRfaW5jb21lXzE3KQ0KICANCiAgDQogIA0KICAjIyMgVGhpcyBwYXJ0IGdyYWJzIHRoZSB2YXJpYWJsZXMgZm9yIHRoZSBhdGwgdHJhY3RzIGluIGRla2FsYiBjb3VudHkNCiAgDQogIGRla19wb3AgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAndHJhY3QnLA0KICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcyA9ICdCMjUwMjZfMDAxJywNCiAgICAgICAgICAgICAgICAgICAgICBjb3VudHkgPSAnRGVrYWxiJywNCiAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9ICdHZW9yZ2lhJywNCiAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gMjAxNywNCiAgICAgICAgICAgICAgICAgICAgICBzdXJ2ZXkgPSAnYWNzNScpICU+JSByZW5hbWUocG9wdWxhdGlvbl8yMDE3PSBlc3RpbWF0ZSkNCiAgDQogIGRla19pbmMgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAndHJhY3QnLA0KICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcyA9ICdCMjEwMDRfMDAxJywNCiAgICAgICAgICAgICAgICAgICAgICBjb3VudHkgPSAnRGVrYWxiJywNCiAgICAgICAgICAgICAgICAgICAgICBzdGF0ZSA9ICdHZW9yZ2lhJywNCiAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gMjAxNywNCiAgICAgICAgICAgICAgICAgICAgICBzdXJ2ZXkgPSAnYWNzNScpICU+JSByZW5hbWUobWVkX2luY29tZV8xNz0gZXN0aW1hdGUpICU+JSBzZWxlY3QobWVkX2luY29tZV8xNywgR0VPSUQpDQogIA0KICANCiAgZGVrX3BvcCA8LWxlZnRfam9pbihhdGxfcGx1cywgZGVrX3BvcCkNCiAgDQogIGRla19wb3BfaW5jIDwtIGxlZnRfam9pbihkZWtfcG9wLCBkZWtfaW5jKQ0KICANCiAgYXRsX2F0dHNfZGVrIDwtIGRla19wb3BfaW5jICU+JSBzZWxlY3QoR0VPSUQsIHBvcHVsYXRpb25fMjAxNywgUG9wdWxhdGlvbjIwMTAsIG1lZF9pbmNvbWVfMTcpICU+JSBmaWx0ZXIoaXMubmEocG9wdWxhdGlvbl8yMDE3KSA9PSBGKSAlPiUgc3RfZHJvcF9nZW9tZXRyeSgpDQogIA0KIA0KICANCiAgIyMgbm93IGpvaW4gZnVsdG9uIGFuZCBkZWthbGIgcG9seXMgaW50byBvbmUgYXRsYW50YSBhdHRyaWJ1dGVzIGRhdGFmcmFtZQ0KICANCiAgYXRsX2F0dHMgPC0gbGVmdF9qb2luKGF0bF9hdHRzX2Z1bHQsIGF0bF9hdHRzX2RlaywgYnk9ICdHRU9JRCcpDQogIGF0bF9hdHRzMSA8LSBhdGxfYXR0cyAlPiUgDQogICAgbXV0YXRlKHBvcF8xNyA9IGlmZWxzZShpcy5uYShwb3B1bGF0aW9uXzIwMTcueCkscG9wdWxhdGlvbl8yMDE3LnksIHBvcHVsYXRpb25fMjAxNy54KSkgJT4lDQogICAgbXV0YXRlKGluY18xNyA9IGlmZWxzZShpcy5uYShtZWRfaW5jb21lXzE3LngpLG1lZF9pbmNvbWVfMTcueSwgbWVkX2luY29tZV8xNy54KSkgJT4lIHNlbGVjdChHRU9JRCwgcG9wXzE3LCBpbmNfMTcpICU+JSBzdF9kcm9wX2dlb21ldHJ5KCkNCiAgICANCiAgI2Fib3ZlIG11dGF0ZSBjb2RlIGlzIG5lY2Vzc2FyeSB0byBjb25zb2xpZGF0ZSB0aGUgZnVsdG9uIC8gZGVrYWxiIGF0dHJpYnV0ZXMgaW50byBzaW5nbGUgY29sdW1ucw0KICANCiAgDQogICMgam9pbiB3aXRoIHNwZW5kaW5nIHBvbHlnb25zDQogIA0KICANCiAgYXRsX3NwZW5kX2F0dHMgPC0gbGVmdF9qb2luKG91dCwgYXRsX2F0dHMxLCBieSA9IGMoJ0dFT0lELngnID0gJ0dFT0lEJykpDQogIA0KICBhdGxfc3BlbmRfYXR0cyA8LSBhdGxfc3BlbmRfYXR0cyAlPiUgZmlsdGVyKGlzLm5hKHBvcF8xNykgPT0gRikgI3JlbW92ZSBzb21lIHdlaXJkIHRyYWN0cyB0aGF0IGRvbid0IG1hcCBhbmQgaGF2ZSBubyBkYXRhDQoNCiAgDQpgYGANCg0KDQojQW5hbHlzaXMNCg0KIyNDbHVzdGVycw0KTG9va2luZyBhdCB0aGUgbWFwIG9mIGJ1ZGdldGVkIHNwZW5kaW5nIGJ5IGNlbnN1cyB0cmFjdCBpdCBzZWVtcyBvYnZpb3VzIHRoYXQgdGhlIGNvbnN0YW50IHJpc2sgYXNzdW1wdGlvbiBpcyB2aW9sYXRlZC4gSG93ZXZlciwgd2UnZCBsaWtlIHRvIGtub3cgaW4gd2hhdCBhcmVhcyB0aGUgc3BlbmRpbmcgaXMgaGlnaGVyIHRoYW4gZXhwZWN0ZWQgYmFzZWQgb24gdGhlIHBvcHVsYXRpb24gb2YgYSB0cmFjdC4gVGh1cywgd2Ugd2lsbCBwcm9kdWNlIGEgbWFwIG9mIHBvaXNzc29uIHByb2JhYmlsaXRpZXMgdG8gdGVzdCBmb3IgYW5kIGxvY2F0ZSB0aGUgbG9jYWwgZXh0cmVtZXMuDQoNCmBgYHtyfQ0KbGlicmFyeShzcGRlcCkgI3BhY2thZ2UgZm9yIHBlcmZvcm1pbmcgY2x1c3RlciBhbmFseXNpcw0KDQphdGxfc3BlbmRfYXR0cyR0b3Rfc3BlbmQgPC0gYXMubnVtZXJpYyhhdGxfc3BlbmRfYXR0cyR0b3Rfc3BlbmQpICNjb25tdmVydCBmcm9tIHVuaXRzIGNsYXNzIHRvIG51bWVyaWMNCg0KYXRsX3NwZW5kX2F0dHMgPC0gYXRsX3NwZW5kX2F0dHMgJT4lIG11dGF0ZShzcGVuZF9yYXRpbyA9IGlmZWxzZSggcG9wXzE3ID4gMCwodG90X3NwZW5kICogMTAwMDAwMCAvIHBvcF8xNyksIE5BKSkgJT4lZmlsdGVyKGlzLm5hKHNwZW5kX3JhdGlvKSA9PSBGKQ0KDQpzcGVuZF9wcm9icyA8LSBwcm9ibWFwKG4gPWF0bF9zcGVuZF9hdHRzJHRvdF9zcGVuZCwNCiAgICAgICAgICAgICAgICAgICAgICAgeCA9IGF0bF9zcGVuZF9hdHRzJHBvcF8xNywNCiAgICAgICAgICAgICAgICAgICAgICAgcm93Lm5hbWVzID0gYXRsX3NwZW5kX2F0dHMkR0VPSUQueCkNCg0KYXRsX3NwZW5kX2F0dHMkcG1hcCA8LSBzcGVuZF9wcm9icyRwbWFwDQojZ2VuZXJhdGUgcG9pc3NvbiBwcm9icw0KDQpgYGANCg0KDQoNCg0KDQpgYGB7cn0NCiMgVGhpcyBqdXN0IHN1bW1hcml6ZXMgKG1lcmdlcyBwb2x5Z29ucykgb2YgYWxsIGNvdW50aWVzIHdpdGggc2lnbmlmaWNhbnQgSElHSCByaXNrDQoNCnNwZW5kX2hpIDwtIGF0bF9zcGVuZF9hdHRzICU+JSAjZm9ybSBjb250aWd1b3VzIGFyZWFzIG9mIHNpZyBoaWdoIG9yIGxvdyBzcGVuZGluZyBpbnRvIHBvbHlnb25zDQogIGZpbHRlcihwbWFwID4gMC45NSkgJT4lIHN1bW1hcmlzZSgpDQoNCnNwZW5kX2xvIDwtIGF0bF9zcGVuZF9hdHRzICU+JQ0KICBmaWx0ZXIocG1hcCA8IDAuMDUpICU+JSBzdW1tYXJpc2UoKQ0KDQoNCiMgbWFrZSBtYXAgb2Ygc2lnIGhpZ2ggb3IgbG93IHNwZW5kaW5nIGFyZWFzDQptMSA8LXRtX3NoYXBlKGF0bF9zcGVuZF9hdHRzKSArIA0KICB0bV9maWxsKCdzcGVuZF9yYXRpbycsDQogICAgICAgICAgcGFsZXR0ZSA9ICdCdVB1JywNCiAgICAgICAgICAgc3R5bGUgPSAncXVhbnRpbGUnLA0KICAgICAgICAgIHRpdGxlID0gJ1NwZW5kaW5nIHBlclxuUGVyc29uIChVU0QpJykgKw0KICB0bV9ib3JkZXJzKCkgKyANCiAgdG1fbGF5b3V0KGxlZ2VuZC5wb3NpdGlvbiA9IGMoJ1JJR0hUJywnVE9QJyksDQogICAgICAgICAgICBtYWluLnRpdGxlID0gJ0NsdXN0ZXJzIG9mIE1BUlRBXG5FeHBhbnNpb24gU3BlbmRpbmcgYnkgUG9wdWxhdGlvbicpICsNCiAgDQojIE5vdyBwbG90IG9ubHkgYm9yZGVycyBvZiBoaWdoIG9yIGxvdyByYXRlIGNvdW50aWVzDQoNCg0KICB0bV9zaGFwZShzcGVuZF9sbykgKyANCiAgdG1fYm9yZGVycyhjb2wgPSAnYmx1ZScsIGx3ZCA9IDIpICsgDQogIHRtX3NoYXBlKHNwZW5kX2hpKSArIA0KICB0bV9ib3JkZXJzKGNvbCA9ICdyZWQnLCBsd2QgPSAyKSArDQoNCiMgZ2VuZXJhbCBsYXlvdXQgc3R1ZmYuLi4gIA0KdG1fbGF5b3V0KGxlZ2VuZC5vdXRzaWRlID0gRiwgbGVnZW5kLnRleHQuc2l6ZSA9IDAuNTUsIA0KICAgICAgICAgIGxlZ2VuZC50aXRsZS5zaXplID0gMC42NSwgbGVnZW5kLnRpdGxlLmZvbnRmYWNlID0gJ2JvbGQnLA0KICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoJ0xFRlQnLCAnVE9QJyksIGlubmVyLm1hcmdpbnMgPSBjKDAuMDIsIC4wMywgLjAyLCAwKSwNCiAgICAgICAgIG1haW4udGl0bGUucG9zaXRpb24gPSAnY2VudGVyJywgbWFpbi50aXRsZS5zaXplID0gMSwgbWFpbi50aXRsZS5mb250ZmFjZSA9ICdib2xkJykgKyANCiAgIHRtX2FkZF9sZWdlbmQodHlwZSA9ICdsaW5lJywNCiAgICAgICAgICAgICAgY29sID0gJ3JlZCcsDQogICAgICAgICAgICAgIGx3ZCA9IDIsDQogICAgICAgICAgICAgIGxhYmVscyA9ICdTaWduaWZpY2FudGx5IGhpZ2gnKSArDQogICB0bV9hZGRfbGVnZW5kKHR5cGUgPSAnbGluZScsDQogICAgICAgICAgICAgIGNvbCA9ICdibHVlJywNCiAgICAgICAgICAgICAgbHdkID0gMiwNCiAgICAgICAgICAgICAgbGFiZWxzID0gJ1NpZ25pZmljYW50bHkgbG93JykNCmBgYCANCg0KTG9va2luZyBhdCB0aGUgYWJvdmUgbWFwLCBhbG1vc3QgYWxsIG9mIHRoZSBBdGxhbnRhIGNlbnN1cyB0cmFjdHMgZmFsbCBpbnRvIHRoZSBjYXRlZ29yeSBvZiBzaWduaWZpY2FudCBoaWdoIG9yIGxvdyBzcGVuZGluZy4NCk5vdywgdGhpcyB3YXMgZG9uZSB3aXRoIHBvcHVsYXRpb24gY291bnQgYXMgdGhlIGRlbm9taW5hdG9yLCBidXQgd2hhdCBpZiB1c2luZyBwb3B1bGF0aW9uIGRlbnNpdHkgd291bGQgZ2l2ZSB1cyBhIG1vcmUgY2xlYXIgcGljdHVyZT8NCg0KVGhlIGZvbGxvd2luZyBjb2RlIGJyaW5ncyBpbiB0aGUgbGFuZCBhcmVhIChrbTIpIHZhcmlhYmxlIGZvciBlYWNoIHRyYWN0IGFuZCBjYWxjdWxhdGVzIHBvcHVsYXRpb24gZGVuc2l0eSBpbiBwZXJzb25zIHBlciBrbTIuDQoNCg0KYGBge3J9DQpkZWtfdHJhY3RzJEFMQU5EIDwtIGFzLm51bWVyaWMoZGVrX3RyYWN0cyRBTEFORCkgI2NvbnZlcnQgdG8gbnVtZXJpYyBmb3IgY2FsY3VsYXRpb25zDQoNCmRla190cmFjdHNfYSA8LSBkZWtfdHJhY3RzICU+JSANCiAgc2VsZWN0KEdFT0lELCBBTEFORCkgJT4lIG11dGF0ZShrbTIgPSBBTEFORC8xMDAwMDAwKSAlPiUgc3RfZHJvcF9nZW9tZXRyeSgpIA0KDQojZnVsdG9uIHRyYWN0cw0KDQpmdWxfdHJhY3RzIDwtIGRla190cmFjdHMgPC0gdHJhY3RzKCdHQScsIGNvdW50eSA9ICdGdWx0b24nKSAlPiUgc3RfYXNfc2YoKSAlPiUgc3RfZHJvcF9nZW9tZXRyeSgpDQoNCmZ1bF90cmFjdHMkQUxBTkQgPC0gYXMubnVtZXJpYyhmdWxfdHJhY3RzJEFMQU5EKQ0KDQpmdWxfdHJhY3RzX2EgPC0gZnVsX3RyYWN0cyAlPiUgDQogIHNlbGVjdChHRU9JRCwgQUxBTkQpICU+JSBtdXRhdGUoa20yID0gQUxBTkQvMTAwMDAwMCkNCg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQojam9pbnMgYW5kIGNsZWFuaW5nDQoNCmZ1bHRfYSA8LWxlZnRfam9pbihhdGxfcGx1cywgZnVsX3RyYWN0c19hKQ0KDQpkZWtfYSA8LWxlZnRfam9pbihhdGxfcGx1cywgZGVrX3RyYWN0c19hKQ0KDQphbGxfYSA8LSByYmluZChmdWx0X2EsIGRla19hKSAlPiUgZmlsdGVyKGlzLm5hKEFMQU5EKSA9PSBGKSAlPiUgc2VsZWN0KEdFT0lELCBrbTIpICU+JSBzdF9kcm9wX2dlb21ldHJ5KCkgI2Ryb3AgZ2VvbWV0cnkgdG8gbWFrZSBhIHRhYmxlIHRoYXQgY2FuIGJlIGpvaW5lZCB0byBtYWluIGF0dHJpYnV0ZXMgZmlsZQ0KDQphcmVhX2F0dHMgPC0gbGVmdF9qb2luKGF0bF9zcGVuZF9hdHRzLCBhbGxfYSwgYnk9YygnR0VPSUQueCc9J0dFT0lEJykpIA0KYXJlYV9hdHRzIDwtYXJlYV9hdHRzICU+JSBtdXRhdGUocG9wX2RlbnMgPSBwb3BfMTcgLyBrbTIpICNjcmVhdGUgcG9wIGRlbnNpdHkgdmFyaWFibGUgaW4gcGVyc29ucyBwZXIga20yDQoNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmBgYA0KDQoNCk5vdyB3ZSdsbCBydW4gdGhlIHRlc3Qgb2YgbG9jYWwgZXh0cmVtZXMgYWdhaW4gYnV0IHdpdGggcG9wdWxhdGlvbiBkZW5zaXR5IGFzIHRoZSBkZW5vbWluYXRvci4gRmluYWxseSwgd2UnbGwgbWFwIHRoZSBzaWduaWZpY2FudCByZXN1bHRzIHRvIHNlZSBob3cgZGlmZmVyZW50IGl0IGlzIHRoYW4gdXNpbmcgcG9wIGNvdW50cy4NCg0KQW5hbHlzaXM6DQpgYGB7cn0NCnNwZW5kX3Byb2JzX2RlbnMgPC0gcHJvYm1hcChuID1hcmVhX2F0dHMkdG90X3NwZW5kLA0KICAgICAgICAgICAgICAgICAgICAgICB4ID0gYXJlYV9hdHRzJHBvcF9kZW5zLA0KICAgICAgICAgICAgICAgICAgICAgICByb3cubmFtZXMgPSBhcmVhX2F0dHMkR0VPSUQueCkNCg0KYXJlYV9hdHRzJHBtYXAgPC0gc3BlbmRfcHJvYnNfZGVucyRwbWFwDQojZ2VuZXJhdGUgcG9pc3NvbiBwcm9icw0KDQphcmVhX2F0dHMgPC0gYXJlYV9hdHRzICU+JSBtdXRhdGUoc3BlbmRfcmF0aW9fZCA9IHRvdF9zcGVuZCAqMTAwMDAwMC8gcG9wX2RlbnMpDQpgYGANCg0KTWFwOg0KDQpgYGB7cn0NCiMgVGhpcyBqdXN0IHN1bW1hcml6ZXMgKG1lcmdlcyBwb2x5Z29ucykgb2YgYWxsIGNvdW50aWVzIHdpdGggc2lnbmlmaWNhbnQgSElHSCByaXNrDQoNCnNwZW5kX2hpX2QgPC0gYXJlYV9hdHRzICU+JSAjZm9ybSBjb250aWd1b3VzIGFyZWFzIG9mIHNpZyBoaWdoIG9yIGxvdyBzcGVuZGluZyBpbnRvIHBvbHlnb25zDQogIGZpbHRlcihwbWFwID4gMC45NSkgJT4lIHN1bW1hcmlzZSgpDQoNCnNwZW5kX2xvX2QgPC0gYXJlYV9hdHRzICU+JQ0KICBmaWx0ZXIocG1hcCA8IDAuMDUpICU+JSBzdW1tYXJpc2UoKQ0KDQoNCiMgbWFrZSBtYXAgb2Ygc2lnIGhpZ2ggb3IgbG93IHNwZW5kaW5nIGFyZWFzDQogbTIgPC10bV9zaGFwZShhcmVhX2F0dHMpICsgDQogIHRtX2ZpbGwoJ3NwZW5kX3JhdGlvX2QnLA0KICAgICAgICAgIHBhbGV0dGUgPSAnQnVQdScsDQogICAgICAgICAgIHN0eWxlID0gJ3F1YW50aWxlJywNCiAgICAgICAgICB0aXRsZSA9ICdTcGVuZGluZyBwZXJcblBlcnNvbiBQZXIgS20yIChVU0QpJykgKw0KICB0bV9ib3JkZXJzKCkgKyANCiAgdG1fbGF5b3V0KGxlZ2VuZC5wb3NpdGlvbiA9IGMoJ1JJR0hUJywnVE9QJyksDQogICAgICAgICAgICBtYWluLnRpdGxlID0gJ0NsdXN0ZXJzIG9mIE1BUlRBXG5FeHBhbnNpb24gU3BlbmRpbmcgYnkgUG9wLiBEZW5zaXR5JykgKw0KICANCiMgTm93IHBsb3Qgb25seSBib3JkZXJzIG9mICdoaWdoLXJhdGUnIGNvdW50aWVzDQoNCiAgdG1fc2hhcGUoc3BlbmRfbG9fZCkgKyANCiAgdG1fYm9yZGVycyhjb2wgPSAnYmx1ZScsIGx3ZCA9IDIpICsgDQogIHRtX3NoYXBlKHNwZW5kX2hpX2QpICsgDQogIHRtX2JvcmRlcnMoY29sID0gJ3JlZCcsIGx3ZCA9IDIpICsNCg0KI2dlbmVyYWwgbGF5b3V0IA0KdG1fbGF5b3V0KGxlZ2VuZC5vdXRzaWRlID0gRiwgbGVnZW5kLnRleHQuc2l6ZSA9IDAuNTUsIA0KICAgICAgICAgIGxlZ2VuZC50aXRsZS5zaXplID0gMC42NSwgbGVnZW5kLnRpdGxlLmZvbnRmYWNlID0gJ2JvbGQnLA0KICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoJ0xFRlQnLCAnVE9QJyksIGlubmVyLm1hcmdpbnMgPSBjKDAuMDIsIC4wMywgLjAyLCAwKSwNCiAgICAgICAgIG1haW4udGl0bGUucG9zaXRpb24gPSAnY2VudGVyJywgbWFpbi50aXRsZS5zaXplID0gMSwgbWFpbi50aXRsZS5mb250ZmFjZSA9ICdib2xkJykgKyANCiAgIHRtX2FkZF9sZWdlbmQodHlwZSA9ICdsaW5lJywNCiAgICAgICAgICAgICAgY29sID0gJ3JlZCcsDQogICAgICAgICAgICAgIGx3ZCA9IDIsDQogICAgICAgICAgICAgIGxhYmVscyA9ICdTaWduaWZpY2FudGx5IGhpZ2gnKSArDQogICB0bV9hZGRfbGVnZW5kKHR5cGUgPSAnbGluZScsDQogICAgICAgICAgICAgIGNvbCA9ICdibHVlJywNCiAgICAgICAgICAgICAgbHdkID0gMiwNCiAgICAgICAgICAgICAgbGFiZWxzID0gJ1NpZ25pZmljYW50bHkgbG93JykNCmBgYA0KDQoNCmBgYHtyfQ0KdG1hcF9hcnJhbmdlKG0xLCBtMikNCmBgYA0KDQpUaGUgdXNlIG9mIHBvcHVsYXRpb24gZGVuc2l0eSBkb2VzIGNoYW5nZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHNpZ25pZmljYW50bHkgZXh0cmVtZSB0cmFjdHMgc3VjaCB0aGF0IHRoZXJlIGFyZSBmZXdlciBzaWduaWZpY2FudCB0cmFjdHMgb3ZlcmFsbCBhbmQgc29tZSB0cmFjdHMgc3dpdGNoIGZyb20gc2lnIGhpIHRvIGxvdyBhbmQgdmljZSB2ZXJzYS4gRWl0aGVyIHdheSB5b3Ugc2xpY2UgaXQsIHRoZXJlIGFyZSBjbGVhciBzaWduaWZpY2FudCBleHRyZW1lIGNsdXN0ZXJzIG9mIHNwZW5kaW5nLiBIb3dldmVyLCB1c2luZyBwb3AgZGVuc2l0eSBhcyB0aGUgZGVub21pbmF0b3Igc2VlbXMgdG8gcmVtb3ZlIHNvbWUgb2YgdGhlIG5vaXNlIGNhdXNlZCBieSBoYXZpbmcgc2ltaWxhciBwb3B1bGF0aW9ucyBpbiBkcmFzdGljYWxseSBkaWZmZXJlbnRseSBzaXplZCB0cmFjdHMuDQoNCg0KIyNSZWdyZXNzaW9uDQoNCk5vdyB0aGF0IEkndmUgZXN0YWJsaXNoZWQgc2lnbmlmaWNhbnQgY2x1c3RlcmluZyBvZiBoaWdoIGFuZCBsb3cgc3BlbmRpbmcgZXhpc3RzLEknZCBsaWtlIHRvIHNlZSBpZiB0aGlzIHBoZW5vbWVub24gY2FuIGJlIGV4cGxhaW5lZCBieSBvdGhlciB1bmRlcmx5aW5nIGZhY3RvcnMuIEluIHBhcnRpY3VsYXIsIEkgYW0gaW50ZXJlc3RlZCB0byBleGFtaW5lIHRoZSBjb3JyZWxhdGlvbiBvZiBtZWRpYW4gdHJhY3QgaW5jb21lIHdpdGggYnVkZ2V0ZWQgc3BlbmRpbmcuDQoNCkZpcnN0IEkgd2lsbCBmaXQgbXkgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzLg0KDQpgYGB7cn0NCiNlbXB0eSBtb2RlbA0KDQojYmVmb3JlIG15IHRvdF9zcGVuZCB2YXJpYWJsZSB3YXMgaW4gbWlsbGlvbnMgb2YgZG9sbGFycywgSSB3aWxsIGNvbnZlcnQgaXQgYmFjayB0byBkb2xsYXJzIGZvciBydW5uaW5nIG15IG1vZGVscw0KDQphcmVhX2F0dHMkdG90X3NwZW5kIDwtIGFyZWFfYXR0cyR0b3Rfc3BlbmQgLyAxMDAwMDAwDQoNCm0wIDwtIGxtKHRvdF9zcGVuZCB+IDEsIGRhdGEgPSBhcmVhX2F0dHMpDQoNCiNjb25kaXRpb25hbCBtb2RlbA0KDQptMSA8LSBsbSh0b3Rfc3BlbmQgfiBwb3BfZGVucyArIGluY18xNywgZGF0YSA9IGFyZWFfYXR0cykNCg0Kc3VtbWFyeShtMSkNCmBgYA0KDQpUaGUgcmVzdWx0cyBvZiBteSBjb25kaXRpb25hbCBtb2RlbCBzaG93IHRoYXQsIGhvbGRpbmcgcG9wdWxhdGlvbiBkZW5zaXR5IGNvbnN0YW50LCAyMDE3IG1lZGlhbiB0cmFjdCBpbmNvbWUgd2FzIGEgc2lnbmlmaWNhbnQgbmVnYXRpdmUgcHJlZGljdG9yIG9mIGJ1ZGdldGVkIE1BUlRBIHNwZW5kaW5nLiBCYXNlZCBvbiB0aGUgbW9kZWwsIGVhY2ggZG9sbGFyIGluY3JlYXNlIGluIG1lZGlhbiBpbmNvbWUgaXMgYXNzb2NpYXRlZCB3aXRoIGEgNzk2LjggZG9sbGFyIGRlY3JlYXNlIGluIHBsYW5uZWQgc3BlbmRpbmcuIEhvd2V2ZXIsIGl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgc2luY2UgSSBoYXZlIHplcm8gZG9sbGFyIHZhbHVlcyBmb3IgMjYgb2YgMTMwIHRyYWN0cywgdGhlIHJlc2lkdWFscyBhbmQgcmVzaWR1YWwgc3RhbmRhcmQgZXJyb3IgZm9yIHRoaXMgbW9kZWwgYXJlIGh1Z2UuDQoNCmBgYHtyfQ0Kc3VtbWFyeShhcmVhX2F0dHMkc3BlbmQpDQpgYGANCg0KDQpOb3cgSSdsbCB0ZXN0IHRoZSByZXNpZHVhbHMgZnJvbSBteSBtb2RlbCB0byBzZWUgd2hldGhlciBvdXIgZmFjdG9ycyBleHBsYWluIGFueSBvZiB0aGUgdmFyaWF0aW9uIGluIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGJldHdlZW4gdHJhY3RzLg0KDQpUaGlzIHdpbGwgaW52b2x2ZSBmaXJzdCBjaG9vc2luZyBhIG5laWdoYm9ycyBkZWZpbml0b24gYW5kIHRoZW4gcnVubmluZyB0aGUgYGxtLm1vcmFudGVzdGAgZnVuY3Rpb24uIEkgaGF2ZSBkZWNpZGVkIHRvIHVzZSBrLW5lYXJlc3QgbmVpZ2hib3JzIG9mIDMgZHVlIHRvIHRoZSBmYWN0IHRoYXQgZW1vcnkgaXMgbm90IHRvdWNoaW5nIGFueSBvdGhlciBhdGwgdHJhY3RzIGFuZCBzZXZlcmFsIGJvcmRlciB0cmFjdHMgaGF2ZSBvbmx5IG9uZSBjb250aWd1b3VzIG5laWdoYm9yLg0KDQpgYGB7cn0NCiMjQ3JlYXRpbmcgbmIgb2JqZWN0DQoNCiNzaW5jZSB3ZSdyZSB1c2luZyBwcm94aW1pdHkgYmFzZWQgbmIgb2JqZWN0LCB3ZSBuZWVkIHRoZSB0cmFjdCBjZW50cm9pZCBwb2ludHMNCg0KYXJlYV9hdHRzX3NwIDwtIGFzKGFyZWFfYXR0cywgJ1NwYXRpYWwnKQ0KYXJlYV9wb2ludHMgIDwtIGNvb3JkaW5hdGVzKGFyZWFfYXR0c19zcCkNCg0KYXJlYV9rMyA8LSBrbmVhcm5laWdoKGFyZWFfcG9pbnRzLCBrID0zKSAjY3JlYXRlcyBzZXQgb2YgMyBuZWFyZXN0IG5laWdoYm9ycw0KDQphcmVhX2szX25iIDwtIGtubjJuYihhcmVhX2szLCByb3cubmFtZXMgPSBhcmVhX2F0dHNfc3AkR0VPSUQueCwgc3ltID0gVCkgI2NyZWF0ZXMgYSBzeW1tZXRyaWNhbCBuYiBvYmplY3QNCg0KYXJlYV9saXN0dyA8LSBhcmVhX2szX25iICU+JSBuYjJsaXN0dygpICNjcmVhdGVzIGxpc3R3IG9iamVjdCBmb3IgTW9yYW4ncyBJIHRlc3QNCg0KIyNwZXJmb3JtaW5nIGxtLm1vcmFudGVzdCgpDQoNCiNlbXB0eSBtb2RlbCByZXNpZHVhbHMNCmxtLm1vcmFudGVzdChtMCwgbGlzdHcgPSBhcmVhX2xpc3R3KQ0KDQpgYGANCg0KDQoNCg0KYGBge3J9DQojY29uZGl0aW9uYWwgbW9kZWwgcmVzaWR1YWxzDQoNCiNtMV8xIDwtIGxtKHRvdF9zcGVuZCB+IGluY18xNywgZGF0YSA9IGFyZWFfYXR0cykgI0kgdGhvdWdodCBvZiB0byBqdXN0IHRlc3QgdGhlIGVmZmVjdCBvZiBpbmNvbWUgc2luY2UgcG9wX2RlbnMgd2Fzbid0IHNpZ25pZmljYW50IGJ1dCBkZWNpZGVkIHRvIGluY2x1ZGUgcG9wX2RlbnMgYWZ0ZXIgYWxsDQoNCmxtLm1vcmFudGVzdChtMSwgbGlzdHcgPSBhcmVhX2xpc3R3KQ0KYGBgDQoNCkZyb20gdGhlc2UgdGVzdHMgd2Ugc2VlIHRoZXJlIGlzIHJlbGF0aXZlbHkgbG93IHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGluIG1vZGVsIHJlc2lkdWFscyBmb3IgYnVkZ2V0ZWQgc3BlbmRpbmcuIE9mIHRoYXQsIG9ubHkgYWJvdXQgMTclIGlzIGV4cGxhaW5lZCBieSB0cmFjdCBtZWRpYW4gaW5jb21lIGFuZCBwb3B1bGF0aW9uIGRlbnNpdHkuIE15IGNvbmplY3R1cmUgaXMgdGhhdCBtdWNoIG9mIHRoZSByZW1haW5pbmcgYXV0b2NvcnJlbGF0aW9uIGlzIGV4cGxhaW5lZCBieSB0aGUgZmFjdCB0aGF0IG1hbnkgb2YgdGhlIGhpZ2gtdmFsdWUgcHJvamVjdHMgYXJlIGNvbXByaXNlZCBvZiBiZWx0bGluZSByYWlsLiBCeSBkZWZpbml0aW9uLCBhbGwgdGhlc2UgcHJvamVjdHMgYXJlIGNvbnRpZ3VvdXMgYW5kIHNpbmNlIHRoZSBiZWx0bGluZSBmb2xsb3dzIG9sZCByYWlsIHRocm91Z2h3YXlzIGluIHRoZSBjaXR5LCB0aGVpciBsb2NhdGlvbnMgbWF5IGJlIGxlc3MgZW50YWdsZWQgd2l0aCBvdGhlciBkZW1vZ3JhcGhpYyBmYWN0b3JzLg0KDQpGb3IgdGhlIGZpbmFsIGZpZ3VyZXMgaW4gdGhpcyBwcm9qZWN0LCBJJ2xsIG1hcCB0aGUgbW9kZWwgcmVzaWR1YWxzLg0KDQpgYGB7cn0NCmFyZWFfYXR0cyRtMF9yZXNpZCA8LSByZXNpZChtMCkgI2NyZWF0ZSByZXNpZHVhbCB2YXJpYWJsZXMNCmFyZWFfYXR0cyRtMV9yZXNpZCA8LSByZXNpZChtMSkNCg0KdG1fc2hhcGUoYXJlYV9hdHRzKSArDQogIHRtX2ZpbGwoYygnbTBfcmVzaWQnLCAnbTFfcmVzaWQnKSwgdGl0bGUgPSBjKCdtMCByZXNpZHNcbihtaWxsLiBVU0QpJywnIG0xIHJlc2lkc1xuKG1pbGwuIFVTRCknKSwNCiAgICAgICAgICBzdHlsZSA9ICdzZCcsDQogICAgICAgICAgcGFsZXR0ZSA9ICctUmRZbEJ1JykgKyB0bV9ib3JkZXJzKCkgKw0KICB0bV9sYXlvdXQobGVnZW5kLnBvc2l0aW9uID0gYygnbGVmdCcsJ3RvcCcpLCBsZWdlbmQuZm9ybWF0ID0gbGlzdChkaWdpdHMgPTEpLCBsZWdlbmQudGV4dC5zaXplID0gMC42LCBsZWdlbmQudGl0bGUuc2l6ZSA9IDAuOTAsIGlubmVyLm1hcmdpbnMgPSBjKDAuMDIsMC4yLCAwLjAyLCAwLjAyKSkNCg0KYGBgDQoNClRoZSBtYXBzIGlsbHVzdHJhdGUgdGhhdCBvdXIgZmFjdG9ycyAqKnNsaWdodGx5KiogcmVkdWNlIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGJ1dCB0aGVyZSBpcyBzdGlsbCBhIGZhaXIgYW1vdW50IG9mIHNwYXRpYWwgc3RydWN0dXJlIHByZXNlbnQgZHVlIHRvIHRoZSBwZXJpcGhlcnkgdHJhY3RzIHdpdGggemVybyBzcGVuZGluZy4gSW50ZXJlc3RpbmdseSwgc29tZSBvZiB0aGUgbGFyZ2VzdCByZXNpZHVhbHMgYXJlIGluIHRoZSBjZW50cmFsIHBvcnRpb24gb2YgdGhlIGNpdHkuIFRoaXMgaXMgd2hlcmUsIGFzIEkgbWVudGlvbmVkIHByZXZpb3VzbHksIGlubmFjdXJhY2llcyBpbiBkaWdpdGl6YXRpb24gbWF5IGhhdmUgbWlzc2VkIGFzc2lnbmluZyBzcGVuZGluZyB0byBzb21lIHRyYWN0cy4NCg0K