In this tutorial, we will first introduce the United States Census data and give an overview of how to access and use Census data. The later part covers how to access and extract Census data in R, using package tidycensus. We will also briefly covers downloading shapefiles using R package tigris.

Census data overview and hierarchies

Part of this section was derived from the online book Analyzing US Census Data: Methods, Maps, and Models in R section 1 and 2.

Introduction to US Census data

The decennial US Census is intended to be a complete enumeration of the US population to assist with apportionment, which refers to the balanced arrangement of Congressional districts to ensure appropriate representation in the United States House of Representatives. It asks a limited set of questions on race, ethnicity, age, sex, and housing tenure.

American Community Survey (ACS) is now the premier source of detailed demographic information about the US population. The ACS is mailed to approximately 3.5 million households per year (representing around 3 percent of the US population), allowing for annual data updates. The Census Bureau releases two ACS datasets to the public: the 1-year ACS, which covers areas of population 65,000 and greater, and the 5-year ACS, which is a moving average of data over a 5-year period that covers geographies down to the Census block group. ACS data are distinct from decennial Census data in that data represent estimates rather than precise counts, and in turn are characterized by margins of error around those estimates.

Aggregate data from the decennial US Census, American Community Survey, and other Census surveys are made available to the public at different enumeration units. Enumeration units are geographies at which Census data are tabulated. They include both legal entities such as states and counties, and statistical entities that are not official jurisdictions but used to standardize data tabulation. The smallest unit at which data are made available from the decennial US Census is the block, and the smallest unit available in the ACS is the block group, which represents a collection of blocks. Other surveys are generally available at higher levels of aggregation.

Enumeration units represent different levels of the Census hierarchy. This hierarchy is summarized in the graphic below (from https://www.census.gov/programs-surveys/geography/guidance/hierarchy.html).

The central axis of the diagram represents the central Census hierarchy of enumeration units, as each geography from Census blocks all the way up to the nation nests within its parent unit. This means that block groups are fully composed of Census blocks, Census tracts are fully composed of block groups, and so forth. An example of nesting is shown in the graphic below for 2020 Census tracts in Harris County, Texas.

The plot illustrates how Census tracts in Harris County neatly nest within its parent geography, the county. This means that the sum of Census data for Census tracts in Harris County will also equal Harris County’s published total at the county level.

Reviewing the diagram shows that some Census geographies, like congressional districts, only nest within states, and that some other geographies do not nest within any parent geography at all. A good example of this is the Zip Code Tabulation Area (ZCTA), which is used by the Census Bureau to represent postal code geographies in the US. A brief illustration is represented by the graphic below.

How to access Census data

Data Downloads from the Census Bureau

There is a data download interface available, where users can interactively search several Census Bureau datasets (the decennial Census & ACS, along with the Economic Census, Population Estimates Program, and others), generate custom queries by geography, and download data extracts.

The Census API

Census APIs are characterized by an API endpoint, which is a base web address for a given Census dataset, and a query, which customizes the data returned from the API. In most cases, users will interact with the Census API through software libraries that offer simplified programmatic access to the API’s data resources. The example covered in this tutorial is the R package tidycensus (K. Walker and Herman 2021). Users of the Census API through these software libraries will require a Census API key, which is free and fast to acquire.

An introduction to tidycensus

The tidycensus package (K. Walker and Herman 2021), first released in 2017, is an R package designed to facilitate the process of acquiring and working with US Census Bureau population data in the R environment. The package has two distinct goals. First, tidycensus aims to make Census data available to R users in a tidyverse-friendly format, helping kick-start the process of generating insights from US Census data. Second, the package is designed to streamline the data wrangling process for spatial Census data analysts. With tidycensus, R users can request geometry along with attributes for their Census data, helping facilitate mapping and spatial analysis.

T US Census Bureau makes a wide range of datasets available to the user community through their APIs and other data download resources. tidycensus is not a comprehensive portal to these data resources; instead, it focuses on a select number of datasets implemented in a series of core functions. These core functions in tidycensus include:

  • get_decennial(), which requests data from the US Decennial Census APIs for 2000, 2010, and 2020.

  • get_acs(), which requests data from the 1-year and 5-year American Community Survey samples. Data are available from the 1-year ACS back to 2005 and the 5-year ACS back to 2005-2009.

  • get_estimates(), an interface to the Population Estimates APIs. These datasets include yearly estimates of population characteristics by state, county, and metropolitan area, along with components of change demographic estimates like births, deaths, and migration rates.

  • get_pums(), which accesses data from the ACS Public Use Microdata Sample APIs. These samples include anonymized individual-level records from the ACS organized by household and are highly useful for many different social science analyses. get_pums() is covered in more depth in Chapters 9 and 10.

  • get_flows(), an interface to the ACS Migration Flows APIs. Includes information on in- and out-flows from various geographies for the 5-year ACS samples, enabling origin-destination analyses.

Getting started with tidycensus

To get started with tidycensus, users should install the package with install.packages("tidycensus") if not yet installed; load the package with library("tidycensus"); and set their Census API key with the census_api_key() function. API keys can be obtained at https://api.census.gov/data/key_signup.html. After you’ve signed up for an API key, be sure to activate the key from the email you receive from the Census Bureau so it works correctly. Declaring install = TRUE when calling census_api_key() will install the key for use in future R sessions, which may be convenient for many users.

#remotes::install_github("walkerke/tidycensus", force=T)
library(tidycensus)
# census_api_key("YOUR KEY GOES HERE", install = TRUE)

Decennial Census

Let’s start with get_decennial(), which is used to access decennial Census data from the 2000, 2010, and 2020 decennial US Censuses. To get data from the decennial US Census, users must specify a string representing the requested geography; a vector of Census variable IDs, represented by variable; or optionally a Census table ID, passed to table. The code below gets data on total population by state from the 2010 decennial Census.

total_population_10 <- get_decennial(
  geography = "state", 
  variables = "P001001",
  year = 2010
)
Getting data from the 2010 decennial Census
Using Census Summary File 1
total_population_10

The function returns a tibble of data from the 2010 US Census (the function default year) with information on total population by state, and assigns it to the object total_population_10. Data for 2000 or 2020 can also be obtained by supplying the appropriate year to the year parameter.

By default, get_decennial() uses the argument sumfile = "sf1", which fetches data from the decennial Census Summary File 1. This summary file exists for the 2000 and 2010 decennial US Censuses, and includes core demographic characteristics for Census geographies. The 2000 and 2010 decennial Census data also include Summary File 2, which contains information on a range of population and housing unit characteristics and is specified as "sf2". Detailed demographic information in the 2000 decennial Census such as income and occupation can be found in Summary Files 3 ("sf3") and 4 ("sf4"). Data from the 2000 and 2010 Decennial Censuses for island territories other than Puerto Rico must be accessed at their corresponding summary files: "as" for American Samoa, "mp" for the Northern Mariana Islands, "gu" for Guam, and "vi" for the US Virgin Islands.

2020 Decennial Census data are available from the PL 94-171 Redistricting summary file, which is specified with sumfile = "pl" and is also available for 2010. The Redistricting summary files include a limited subset of variables from the decennial US Census to be used for legislative redistricting. These variables include total population and housing units; race and ethnicity; voting-age population; and group quarters population. For example, the code below retrieves information on the American Indian & Alaska Native population by state from the 2020 decennial Census.

aian_2020 <- get_decennial(
  geography = "state",
  variables = "P1_005N",
  year = 2020,
  sumfile = "pl"
)
Getting data from the 2020 decennial Census
Using the PL 94-171 Redistricting Data summary file
aian_2020

The argument sumfile = "pl" is assumed (and in turn not required) when users request data for 2020 and will remain so until the main Demographic and Housing Characteristics File is released in mid-to-late 2022.

For many geographies, tidycensus supports more granular requests that are subsetted by state or even by county, if supported by the API. For example, we can use the state parameter to subset county level population for Texas:

total_population_10_TX <- get_decennial(
  geography = "county", 
  variables = "P001001",
  state="Texas",
  year = 2010
)
Getting data from the 2010 decennial Census
Using FIPS code '48' for state 'Texas'
Using Census Summary File 1
total_population_10_TX

American Community Survey (ACS)

Similarly, get_acs() retrieves data from the American Community Survey. As discussed in the previous section, the ACS includes a wide variety of variables detailing characteristics of the US population not found in the decennial Census. The example below fetches data on the number of residents born in Mexico by state.

born_in_mexico <- get_acs(
  geography = "state", 
  variables = "B05006_150",
  year = 2020
)
Getting data from the 2016-2020 5-year ACS
born_in_mexico

If the year is not specified, get_acs() defaults to the most recent five-year ACS sample, which at the time of this writing is 2016-2020. The data returned is similar in structure to that returned by get_decennial(), but includes an estimate column (for the ACS estimate) and moe column (for the margin of error around that estimate) instead of a value column. Different years and different surveys are available by adjusting the year and survey parameters. survey defaults to the 5-year ACS; however this can be changed to the 1-year ACS by using the argument survey = "acs1". For example, the following code will fetch data from the 1-year ACS for 2019:

born_in_mexico_1yr <- get_acs(
  geography = "state", 
  variables = "B05006_150", 
  survey = "acs1",
  year = 2019
)
Getting data from the 2019 1-year ACS
The 1-year ACS provides data for geographies with populations of 65,000 and greater.

Note the differences between the 5-year ACS estimates and the 1-year ACS estimates shown. For states with larger Mexican-born populations like Arizona, California, and Colorado, the 1-year ACS data will represent the most up-to-date estimates, albeit characterized by larger margins of error relative to their estimates. For states with smaller Mexican-born populations like Alabama, Alaska, and Arkansas, however, the estimate returns NA, R’s notation representing missing data. If you encounter this in your data’s estimate column, it will generally mean that the estimate is too small for a given geography to be deemed reliable by the Census Bureau. In this case, only the states with the largest Mexican-born populations have data available for that variable in the 1-year ACS, meaning that the 5-year ACS should be used to make full state-wise comparisons if desired.

Variables from the ACS detailed tables, data profiles, summary tables, comparison profile, and supplemental estimates are available through tidycensus’s get_acs() function; the function will auto-detect from which dataset to look for variables based on their names. Alternatively, users can supply a table name to the table parameter in get_acs(); this will return data for every variable in that table. For example, to get all variables associated with table B01001, which covers sex broken down by age, from the 2016-2020 5-year ACS:

age_table <- get_acs(
  geography = "state", 
  table = "B01001",
  year = 2020
)
Getting data from the 2016-2020 5-year ACS
age_table

To find all of the variables associated with a given ACS table, tidycensus downloads a dataset of variables from the Census Bureau website and looks up the variable codes for download. If the cache_table parameter is set to TRUE, the function instructs tidycensus to cache this dataset on the user’s computer for faster future access. This only needs to be done once per ACS or Census dataset if the user would like to specify this option.

Geography and variables in tidycensus

The geography parameter in get_acs() and get_decennial() allows users to request data aggregated to common Census enumeration units. At the time of this writing, tidycensus accepts enumeration units nested within states and/or counties, when applicable. Census blocks are available in get_decennial() but not in get_acs() as block-level data are not available from the American Community Survey. To request data within states and/or counties, state and county names can be supplied to the state and county parameters, respectively. Arguments should be formatted in the way that they are accepted by the US Census Bureau API, specified in the table below. If an “Available by” geography is in bold, that argument is required for that geography.

The only geographies available in 2000 are "state", "county", "county subdivision", "tract", "block group", and "place". Some geographies available from the Census API are not available in tidycensus at the moment as they require more complex hierarchy specification than the package supports, and not all variables are available at every geography.

Geography Definition Available by Available in
"us" United States get_acs(), get_decennial(), get_estimates()
"region" Census region get_acs(), get_decennial(), get_estimates()
"division" Census division get_acs(), get_decennial(), get_estimates()
"state" State or equivalent state get_acs(), get_decennial(), get_estimates(), get_flows()
"county" County or equivalent state, county get_acs(), get_decennial(), get_estimates(), get_flows()
"county subdivision" County subdivision state, county get_acs(), get_decennial(), get_estimates(), get_flows()
"tract" Census tract state, county get_acs(), get_decennial()
"block group" Census block group state, county get_acs() (2013-), get_decennial()
"block" Census block state, county get_decennial()
"place" Census-designated place state get_acs(), get_decennial(), get_estimates()
"alaska native regional corporation" Alaska native regional corporation state get_acs(), get_decennial()
"american indian area/alaska native area/hawaiian home land" Federal and state-recognized American Indian reservations and Hawaiian home lands state get_acs(), get_decennial()
"american indian area/alaska native area (reservation or statistical entity only)" Only reservations and statistical entities state get_acs(), get_decennial()
"american indian area (off-reservation trust land only)/hawaiian home land" Only off-reservation trust lands and Hawaiian home lands state get_acs(),
"metropolitan statistical area/micropolitan statistical area" OR "cbsa" Core-based statistical area state get_acs(), get_decennial(), get_estimates(), get_flows()
"combined statistical area" Combined statistical area state get_acs(), get_decennial(), get_estimates()
"new england city and town area" New England city/town area state get_acs(), get_decennial()
"combined new england city and town area" Combined New England area state get_acs(), get_decennial()
"urban area" Census-defined urbanized areas get_acs(), get_decennial()
"congressional district" Congressional district for the year-appropriate Congress state get_acs(), get_decennial()
"school district (elementary)" Elementary school district state get_acs(), get_decennial()
"school district (secondary)" Secondary school district state get_acs(), get_decennial()
"school district (unified)" Unified school district state get_acs(), get_decennial()
"public use microdata area" PUMA (geography associated with Census microdata samples) state get_acs()
"zip code tabulation area" OR "zcta" Zip code tabulation area state get_acs(), get_decennial()
"state legislative district (upper chamber)" State senate districts state get_acs(), get_decennial()
"state legislative district (lower chamber)" State house districts state get_acs(), get_decennial()
"voting district" Voting districts (2020 only) state get_decennial()

The geography parameter must be typed exactly as specified in the table above to request data correctly from the Census API; use the guide above as a reference and copy-paste for longer strings. For core-based statistical areas and zip code tabulation areas, two heavily-requested geographies, the aliases "cbsa" and "zcta" can be used, respectively, to fetch data for those geographies.

cbsa_population <- get_acs(
  geography = "cbsa",
  variables = "B01003_001",
  year = 2020
)
Getting data from the 2016-2020 5-year ACS

Searching for variables in tidycensus

One additional challenge when searching for Census variables is understanding variable IDs, which are required to fetch data from the Census and ACS APIs. There are thousands of variables available across the different datasets and summary files. To make searching easier for R users, tidycensus offers the load_variables() function. This function obtains a dataset of variables from the Census Bureau website and formats it for fast searching, ideally in RStudio.

The function takes two required arguments: year, which takes the year or endyear of the Census dataset or ACS sample, and dataset, which references the dataset name. For the 2000 or 2010 Decennial Census, use "sf1" or "sf2" as the dataset name to access variables from Summary Files 1 and 2, respectively. The 2000 Decennial Census also accepts "sf3" and "sf4" for Summary Files 3 and 4. For 2020, the only dataset supported at the time of this writing is "pl" for the PL-94171 Redistricting dataset; more datasets will be supported as the 2020 Census data are released. An example request would look like load_variables(year = 2020, dataset = "pl") for variables from the 2020 Decennial Census Redistricting data.

For variables from the American Community Survey, users should specify the dataset as "acs1" for the 1-year ACS or "acs5" for the 5-year ACS. If no suffix to these dataset names is specified, users will retrieve data from the ACS Detailed Tables. Variables from the ACS Data Profile, Summary Tables, and Comparison Profile are also available by appending the suffixes /profile, /summary, or /cprofile, respectively. For example, a user requesting variables from the 2020 5-year ACS Detailed Tables would specify load_variables(year = 2020, dataset = "acs5"); a request for variables from the Data Profile then would be load_variables(year = 2020, dataset = "acs5/profile"). In addition to these datasets, the ACS Supplemental Estimates variables can be accessed with the dataset name "acsse".

As this function requires processing thousands of variables from the Census Bureau which may take a few moments depending on the user’s internet connection, the user can specify cache = TRUE in the function call to store the data in the user’s cache directory for future access. On subsequent calls of the load_variables() function, cache = TRUE will direct the function to look in the cache directory for the variables rather than the Census website.

An example of how load_variables() works is as follows:

v16 <- load_variables(2016, "acs5", cache = TRUE)

The returned data frame always has three columns: name, which refers to the Census variable ID; label, which is a descriptive data label for the variable; and concept, which refers to the topic of the data and often corresponds to a table of Census data. For the 5-year ACS detailed tables, the returned data frame also includes a fourth column, geography, which specifies the smallest geography at which a given variable is available from the Census API. As illustrated above, the data frame can be filtered using tidyverse tools for variable exploration. However, the RStudio integrated development environment includes an interactive data viewer which is ideal for browsing this dataset, and allows for interactive sorting and filtering. The data viewer can be accessed with the View() function:

View(v16)

By browsing the table in this way, users can identify the appropriate variable IDs (found in the name column) that can be passed to the variables parameter in get_acs() or get_decennial(). Users may note that the raw variable IDs in the ACS, as consumed by the API, require a suffix of E or M. tidycensus does not require this suffix, as it will automatically return both the estimate and margin of error for a given requested variable. Additionally, if users desire an entire table of related variables from the ACS, the user should supply the characters prior to the underscore from a variable ID to the table parameter.

In the next section, we will demonstrate how to access and clean Census Data using county level sociodemographic data from Texas as an example.

Exploring Census data with visualization in R

Part of this section was derived from the online book Analyzing US Census Data: Methods, Maps, and Models in R section 3 and 4.

This chapter covers wrangling Census data with R package tidyverse and exploring Census data with visualization. We will demonstrate the process using county level sociodemographic data from Harris County as an example.

Extracting American Community Survey data

To extract sociodemofraphic data of interest from 2016-2020 American Community Survey 5-year estimates, we first load the codebook which allows us to search and locate the variables of interest:

#Census API token: replace "Your KEY" with your requested API token here: https://api.census.gov/data/key_signup.html
#census_api_key("Your KEY", install="TRUE", overwrite = TRUE)

#View all the possible variables we can use in the dataset
acs20 <- load_variables(year= 2020, dataset="acs5/profile", cache=TRUE)

# Search in the codebook page
#View(acs20)

If we are interested in county level sociodemographic variables (% unemployed, % living under poverty, Per capita income and etc.), we need first list the variables of interest by searching the keywords in the codebook page viewed above:

#View tha loaded variables and filter to choose the variables of interest at county level
varlist <- c("DP05_0001", "DP03_0088", "DP03_0005P", "DP03_0128P",
             "DP03_0099P","DP04_0077P", "DP02_0060P", "DP02_0061P", 
             "DP05_0077P", "DP04_0058P","DP02_0072P", "DP02_0114P",
             "DP04_0047P")

subset(acs20, acs20$name %in% varlist)

# Get 2020 ACS data for all Texas counties 
TX_county <- get_acs(geography = "county", state="TX", 
                        variables=varlist, 
                        year=2020) ##geometry=T will also give you the shapefiles
Getting data from the 2016-2020 5-year ACS
Using the ACS Data Profile
Using FIPS code '48' for state 'TX'
TX_county

If you are interested in getting county level data for all US states, you can set the state parameter to NULL.

Process Census data and create summary statistics

With the data retrieved using tidycensus, we need process and manipulate it to the data format wanted for further analysis and visualizations.

library(tidyverse)
#Clean the datsaet
TX_county_dt <- TX_county[,c(1,3,4)] %>%  
  spread(key="variable", value="estimate") %>% # from long to wide format
  mutate(Crowded_housing= 100- DP04_0077P, #Define variable crowded housing
         No_high_school= DP02_0060P+DP02_0061P,#Define variable No high school diploma
         Racial_minority = 100 - DP05_0077P,  #Define variable Racial minority
         ) %>%                       
  #mutate_each(funs(replace(., .<0, NA))) %>%   #Replace missing values with NA
  rename(No_vehicle=DP04_0058P, Unemployed=DP03_0005P,  Renters=DP04_0047P, 
         Per_capita_income=DP03_0088, Living_poverty=DP03_0128P,
         Uninsured=DP03_0099P,Population=DP05_0001, Disability=DP02_0072P,
         Limited_English=DP02_0114P)  #Rename the variables 

# Retain the variables of interest 
TX_county_dt <-  dplyr::select(TX_county_dt, GEOID, Population, Crowded_housing,
                               No_high_school, Renters, Racial_minority, No_vehicle,
                               Unemployed,Per_capita_income, Living_poverty,Uninsured,
                               Disability, Limited_English)
#options(digits=3)

TX_county_dt

The data contains 254 observations and 13 columns, with each raw containing data for one county in Texas and each column representing a variable. GEOID is the county FIPS. Each measure is in percentage, except per capita income in US dollars.

Summary Table

table1 package is useful to create summary statistics table: https://cran.r-project.org/web/packages/table1/vignettes/table1-examples.html

library(table1)

table1(~ Population+ Per_capita_income + Unemployed+ Crowded_housing+No_high_school+
         Renters+Racial_minority+No_vehicle+Living_poverty+Uninsured+Disability+
         Limited_English, data=TX_county_dt)
Overall
(N=254)
Population
Mean (SD) 113000 (405000)
Median [Min, Max] 18500 [117, 4680000]
Per_capita_income
Mean (SD) 27100 (5850)
Median [Min, Max] 26700 [13300, 47700]
Unemployed
Mean (SD) 2.92 (1.39)
Median [Min, Max] 2.80 [0, 9.20]
Crowded_housing
Mean (SD) 4.02 (2.40)
Median [Min, Max] 3.60 [0, 12.8]
No_high_school
Mean (SD) 18.2 (8.51)
Median [Min, Max] 16.9 [3.40, 78.1]
Renters
Mean (SD) 28.0 (9.46)
Median [Min, Max] 26.8 [3.60, 82.3]
Racial_minority
Mean (SD) 44.5 (21.4)
Median [Min, Max] 41.8 [0, 99.0]
No_vehicle
Mean (SD) 5.06 (2.42)
Median [Min, Max] 5.00 [0, 12.4]
Living_poverty
Mean (SD) 15.3 (6.39)
Median [Min, Max] 14.5 [0, 42.6]
Uninsured
Mean (SD) 17.4 (5.11)
Median [Min, Max] 17.1 [4.00, 35.2]
Disability
Mean (SD) 15.9 (4.75)
Median [Min, Max] 16.0 [4.60, 47.9]
Limited_English
Mean (SD) 26.6 (18.9)
Median [Min, Max] 20.2 [2.60, 94.1]

Correlation Matrix

cor <- cor(TX_county_dt[,2:13], method = "pearson", use = "complete.obs")
cor <- as.data.frame(round(cor,2))
# rename variables
names <- c("Population", "Crowded housing","No high school diploma", "Renters", 
           "Racial minority","No vehicle","Unemployment","Per capita income",
           "Living in poverty", "Uninsured", "Disability", "Limited English")
names(cor) <- names
row.names(cor) <-  names
#add correlation coefficients & reorder matrix using hierarchical clustering
library(ggcorrplot)
ggcorrplot(cor,  type = "lower",lab = TRUE, lab_size = 1.5)

Data visualization with ggplot2

Alternatively, we can request data in wide format using tidycensus, which will spread the estimate (variable name ending in “E”) and margin of error (variable name ending in “M”) information across the columns.

tx_wide <- get_acs(
  geography = "county",
  state = "Texas",
  variables = c(living_poverty = "DP03_0128P", # rename the variables 
                unemployed = "DP03_0005P",
                Per_capita_income="DP03_0088"),
  output = "wide", # wide format 
  year = 2020
)
Getting data from the 2016-2020 5-year ACS
Using the ACS Data Profile
Using FIPS code '48' for state 'Texas'
tx_wide

We can create some visualization using ggplot2 package, such as histogram of % living under poverty at county level in Texas.

ggplot(tx_wide, aes(x = living_povertyE)) + 
  geom_histogram()+
  labs(x="% people living in poverty", y="count")

Explore the relationship between % poverty and % unemployed using scatter plot:

ggplot(tx_wide, aes(x = living_povertyE, y = unemployedE)) + 
  geom_point()+
  geom_smooth(method="lm")+
  labs(x="% people living in poverty", y="% people unemployed")

The geom_smooth() function draws a fitted line representing the relationship between the two columns on the plot. The argument method = "lm" draws a straight line based on a linear model fit; smoothed relationships can be visualized as well with method = "loess".

We can also create a bar chart identifying the top 20 counties in Texas with the highest per capita income.

tx_wide %>%
  mutate(County = str_split_fixed(NAME, ",", 2)[,1]) %>% # retain only county name
  arrange(desc(Per_capita_incomeE)) %>% # order by variable 
  slice(1:20)%>% # top 20
  ggplot(aes(y = reorder(County, Per_capita_incomeE), x = Per_capita_incomeE)) + 
  #order from highest to lowest 
  geom_col()+
  labs(x="Per capita income, $", y="")+
  ggtitle("The top 20 counties in Texas with the highest per capita income")

While tidycensus has tools available for working with margins of error in a data wrangling workflow, it is also often useful to visualize those margins of error to illustrate the degree of uncertainty around estimates, especially when making comparisons between those estimates. Below is an example presenting uncertainty around each estimates using error bars:

tx_wide %>%
  mutate(County = str_split_fixed(NAME, ",", 2)[,1]) %>% # retain only county name
  arrange(desc(Per_capita_incomeE)) %>% # order by variable 
  slice(1:20)%>% # top 20
  ggplot(aes(x = Per_capita_incomeE, y = reorder(County, Per_capita_incomeE))) + 
  geom_errorbarh(aes(xmin = Per_capita_incomeE - Per_capita_incomeM, 
                     xmax = Per_capita_incomeE + Per_capita_incomeM)) + 
  geom_point(size = 3, color = "darkgreen") + 
  theme_minimal(base_size = 12.5) + 
  labs(title = "Per capita income", 
       subtitle = "Top 20 counties in Texas", 
       x = "2016-2020 ACS estimate", 
       y = "") 

Visualizing ACS estimates over time

Sometimes we want to obtain a time series of ACS estimates to explore temporal demographic shifts. For an illustrative example, we’ll obtain 5-year ACS data from 2010 through 2019 on median house value for Harris County and Travis County, Texas. map_dfr() is used to iterate over a named vector of years, creating a time-series dataset of median home value in Harris and Travis County since 2010, and we use the formula specification for anonymous functions so that ~ .x translates to function(x) x.

my_vars <- c(
  "B25077_001"
) # list the vairables of interest (median house value)

years <- 2010:2019 # year
names(years) <- years

county_mhv_tx <- map_dfr(
  years,
  ~ get_acs(
    geography = "county",
    state="Texas",
    variables = my_vars,
    year = .x,
    survey = "acs5",
    geometry = FALSE
  ),
  .id = "year"  # when combining results, add id var (name of list item)
) %>%
  arrange(variable, NAME) %>%
  rename(value=estimate) %>%
  select(-variable) %>%
  mutate(year=as.numeric(year))

county_mhv_tx

Arguably the most common chart type chosen for time-series visualization is the line chart, which ggplot2 handles capably with the geom_line() function. Here we compare the temporal trend of median house value in Harris and Travis County over time (2010-2019):

compare <- subset(county_mhv_tx, county_mhv_tx$NAME %in% 
                    c("Harris County, Texas", "Travis County, Texas"))

ggplot(compare, aes(x = year, y = value, color=NAME)) + 
  geom_line() + 
  geom_point()+
  labs(title = "Median home value in Harris and Travis County, TX",
       x = "Year",
       y = "ACS estimate",
       caption = "2016-2020 ACS 5-year estimate",
       color="County")+
  theme_minimal(base_size = 12) + 
  scale_x_continuous(breaks = c(2010:2019))+
  scale_y_continuous(labels = scales::label_dollar(scale = .001, suffix = "k")) 

NA
NA

Introduction to tigris

Download TIGER/Line Shapfiles Manually

If you prefer to download the shapefiles using the web interface, you can navigate and download shapefiles by specifying the year and geographic level on the website. By saving the shapefile in your local folder under the working directory, package rgdal or sf can be used used to read and open the shapefiles in R. In this example, the 2020 Texas county level shapefile was downloaded:

# using rgdal
library(rgdal)
# indicate dsn (data source, folder name) and layer name
TX_County <- readOGR(dsn = "TX_county",layer =  "TX_county", verbose=F)
Warning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among others
class(TX_County)
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"

Note that the returned object is a “SpatialPolygonsDataFrame”, which consists of data columns on characteristics of the counties, and spatial polygons, which contains a set of spatially explicit shapes/polygons that represent the geographic locations of the counties.

head(TX_County@data,10)

Or you can use read_sf from the sf package, which will return a sf object.

library(sf)
TX_County1 <- read_sf('TX_county/TX_county.shp')
class(TX_County1)
[1] "sf"         "tbl_df"     "tbl"        "data.frame"
head(TX_County1)
Simple feature collection with 6 features and 17 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -102.0904 ymin: 28.02283 xmax: -93.6882 ymax: 35.18324
Geodetic CRS:  GRS 1980(IUGG, 1980)

The sf object includes a data frame with a series of columns representing characteristics of those states, like a name, postal code, and Census ID (the GEOID column). It also contains a special list-column, geometry, which is made up of a sequence of coordinate of longitude/latitude coordinate pairs that collectively represent the boundary of each state.

You can easily convert sf object to SpatialPolygonDataFrame as following:

# TX_County <- as(TX_County1, "Spatial")

Download Shapefiles using R Package tigris

The tigris R package simplifies the process for R users of obtaining and using Census geographic datasets. Functions in tigris download a requested Census geographic dataset from the US Census Bureau website, then load the dataset into R as a spatial object.

You can download shapefiles at different geographical levels. For example, use states() function to retrieve state-level shapefile, counties() for county-level, and tracts() for census-tract level.

When you call a tigris function, it does the following:

  • Downloads your data from the US Census Bureau website

  • Stores your data in a user cache directory or in a temporary directory

  • Loads your data into R session with rgdal::readOGR() or sf::st_read()

see reference here.

Example 1: Get Texas County-level shapefile

‘state’ argument can be a two-digit FIPS code of a specific state or state name abbreviation, for example, 48 stands for Texas.

library(tigris)
options(tigris_use_cache=TRUE) #cache Census shapefile downloads
txcounty <- counties(state=48, cb=TRUE, year=2020)

Notice the argument cb=TRUE. It helps to return Cartographic Boundary Files, which has less details than TIGER/Line Shapefiles. (Detail descriptions can be found here.)

Let’s see a comparison for Texas, where Black lines are TIGER/Line file and Red lines are Cartographic Boundary.

Example 2: Census tract shapefile for one county

With tracts() function, you can retrieve census tract shapefile for a specific county, here’s an example of Harris county in Texas, (Note: you may actually want to use FIPS code instead of county name to accurately find the data you need. For instance, “Harris” will match both “Harris County” and “Harrison County”, which causes confusion that end up returning empty data.)

harristracts <- tracts(state=48, county = "Harris County", cb=T, year=2020)
Using FIPS code '201' for 'Harris County'
# View the polygons using package tmap
tm_shape(harristracts) + tm_polygons()

Example 3: Shapefiles for multiple states

To retrieve county-level shapefiles, you can specify a vector of FIPS code in state argument. For example, 17=Illinois, 26=Michigan, 55=Wisconsin.

multi_st_county <- counties(state=c(17,26,55), cb=TRUE, year=2020)
tm_shape(multi_st_county) + tm_polygons()

However, since census tracts shapefiles are only available at state-level, it is not applicable with a vector of FIPS code directly put into the function. Instead, you can apply rind_tigris() function to combine multiple tracts files.

sts <- c(17,26,55)
combined <- rbind_tigris(
  lapply(sts, function(x){
    tracts(x, cb=TRUE)
  })
)
Retrieving data for the year 2021
Retrieving data for the year 2021
Retrieving data for the year 2021
tm_shape(combined) + tm_polygons()

Example 4: Census tracts for the entire US

It is straightforward to get tracts file for the entire US, you can simply specify NULL in state and county arguments,

ustract <- tracts(state = NULL, county = NULL, cb = TRUE, year = 2019)
Retrieving Census tracts for the entire United States
tm_shape(ustract) + tm_polygons()

Example 5: Shifting and rescaling geometry for national US mapping

A common problem for national display of the United States is the fragmented nature of US states and territories geographically. The continental United States can be displayed on a map in a relatively straightforward way, and there are a number of projected coordinate reference systems designed for correct display of the continental US. Often, analysts and cartographers then have to make decisions about how to handle Alaska, Hawaii, and Puerto Rico, which cannot be reasonably plotted using default US projections.

tigris offers a solution to this problem with the shift_geometry() function. shift_geometry() takes an opinionated approach to the shifting and rescaling of Alaska, Hawaii, and Puerto Rico geometries to offer four options for an alternative view of the US. The function works by projecting geometries in Alaska, Hawaii, and Puerto Rico to appropriate coordinate reference systems for those areas, then re-sizing the geometries (if requested) and moving them to an alternative layout in relationship to the rest of the US using the Albers Equal Area CRS.

us_states <- states(cb = TRUE, resolution = "20m")
Retrieving data for the year 2021
us_states_shifted <- shift_geometry(us_states)

tm_shape(us_states_shifted)+tm_polygons()

This view uses two default arguments: preserve_area = FALSE, which shrinks Alaska and inflates Hawaii and Puerto Rico, and position = "below", which places these areas below the continental United States. Alternatively, we can set preserve_area = TRUE and position = "outside" (used together below, but they can be mixed and matched) for a different view:

us_states_outside <- shift_geometry(us_states, 
                                    preserve_area = TRUE,
                                    position = "outside")

tm_shape(us_states_outside)+tm_polygons()

Mapping Census data in R

Get data ready for mapping

Merging data with shapefiles

Before creating maps in R, we need to merge the data of interest (in this case, not census data) with shapefiles. The following example used the Texas county level COVID-19 cases data from the Department of Health and Human Services website.

# read in data
library(readxl)
cases <- read_excel("Texas COVID-19 Cumulative Confirmed Cases by County.xlsx",
                    sheet="Cases by County 2023",
                    skip=2)[1:254,1:2] # cumulative cases by 1/1/2023
colnames(cases) <- c("County", "Freq")
head(cases)
NA
library(dplyr)
# Merge with SpatialPolygonDataFrame
#merge by county name
TX_County@data <- left_join(TX_County@data, cases, by=c("NAME"="County"))

# Merge with sf object
TX_County1 <- left_join(TX_County1, cases,by=c("NAME"="County"))

If you have individual level address data, and would like to obtain census information from address, you need to first geocode the address: https://geocoding.geo.census.gov/geocoder/

Basic Mapping in R

# Map the number of cases at county level
library(RColorBrewer)
library(classInt)
library(maptools)
### select variable to plot
plotvar <- TX_County@data$Freq ### variable to plot
# specify breaks
nclr <- 5 
brks <- round(quantile(plotvar, probs=seq(0,1,1/(nclr))), digits=1)
colornum <- findInterval(plotvar,brks,all.inside=T)
plotclr <- brewer.pal(nclr,"BuPu") # you can choose different colors schemes 
colcode <- plotclr[colornum]

### make the map
plot(TX_County, col=colcode, axe=T)
legend("bottomleft",legend=leglabs(round(brks,digits=1)),fill=plotclr,cex=0.8,bty="n")
title("Number of cumulative COVID-19 cases at county level \nin Texas, as of Jan 1, 2023")

Using geometry in tidycensus

As covered in the previous section, Census geographies are available from the tigris R package as simple features objects, using the data model from the sf R package. tidycensus wraps several common geographic data functions in the tigris package to allow R users to return simple feature geometry pre-linked to downloaded demographic data with a single function call. The key argument to accomplish this is geometry = TRUE, which is available in the core data download functions in tidycensus, get_acs(), get_decennial(), and get_estimates().

Traditionally, getting “spatial” Census data requires a tedious multi-step process that can involve several software platforms. These steps include:

  • Fetching shapefiles from the Census website;

  • Downloading a CSV of data, then cleaning and formatting it;

  • Loading geometries and data into your desktop GIS of choice;

  • Aligning key fields in your desktop GIS and joining your data.

geometry = TRUE combines the automated data download functionality of tidycensus and tigris to allow R users to bypass this process entirely. The following example illustrates the use of the geometry = TRUE argument, fetching information on population, per capita income and unemployment rate for all Texas counties. We will use this data for mapping in the next few sections.

library(tidycensus)
# 2019 ACS data for all Texas counties - total population, 
# Per capita income and % unemployed
TX_county_dt <- get_acs(geography = "county", state="TX", 
                        variables=c("B01001_001", "B19301_001", "DP03_0005P"), 
                        year=2019, geometry=T)
Getting data from the 2015-2019 5-year ACS
Fetching data by table type ("B/C", "S", "DP") and combining the result.
# format the data 
TX_county_dt <- TX_county_dt[,-5] %>%  
   tidyr::spread(key="variable", value="estimate") %>% 
   rename(Population=B01001_001, Per_capita_income=B19301_001, 
          Unemployment=DP03_0005P)


TX_county_dt
Simple feature collection with 254 features and 5 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -106.6456 ymin: 25.83738 xmax: -93.50829 ymax: 36.5007
Geodetic CRS:  NAD83

Mapping with ggplot2 and ggmap

One of the most common ways to visualize statistical information on a map is with choropleth mapping. Choropleth maps use shading to represent how underlying data values vary by feature in a spatial dataset. The COVID-19 cases plot at Texas county level earlier in this chapter is an example of a choropleth map.

We can use ggplot2 to create a Choropleth map:

############################
### Using ggplot2 Method 1
############################
library(ggplot2) 
# more about mapping in ggplot: http://mazamascience.com/WorkingWithData/?p=1494
# map
library(scales)
map1 <- ggplot(TX_county_dt)+
  geom_sf(aes(fill=Population), color="grey60", alpha=0.8)+ # specify variable to map
  scale_fill_distiller(palette = "YlOrRd",na.value = "grey50", 
                       breaks = pretty_breaks(n = 6), 
                       label=comma,values = c(1,0), 
                       guide=guide_colorbar(reverse = TRUE))+
  #geom_point(data=text, lat=lat, long=long)+ #can add point data here!
  labs(fill="")+xlab("Longitude")+ylab("Latitude")+
  ggtitle("Map of Texas County level Population")

map1 #display

The county polygons can be styled using ggplot2 conventions and the geom_sf() function. The geom_sf() function in the above example interprets the geometry of the sf object (in this case, polygon) and visualizes the result as a filled choropleth map. In this case, the ACS estimate of total population is mapped to the yellow-orange-red color ramp in ggplot2, highlighting the most populated counties (such as Harris County) with darker reds.

If you would like to add the Google map as background, there is an alternative way for mapping using ggplot2, with package ggmap. You will need to request for your own Google API key (instructions can be found here). More details about visualization with ggmap can be found here.

############################
### Using ggplot2 Method 2
############################
#install.packages('rgeos', type='source')
library(gpclib)
# first convert the SpatialPolygonDataFrame to ggplot object 
ggSHP <- fortify(TX_County, region="GEOID")
# Merge data with shapefiles
ggSHP2 <- left_join(ggSHP, TX_county_dt, by=c("id"="GEOID"))

# Optional: if you would like to add Google map as the background
#library(ggmap)
#register_google(key="key"YOUR GOOGLE API KEY, write=TRUE) 
# you will need to insert your own Google API key 

geocode("Texas") #get center coordinates of Texas
# Get Google map - road map
GoogleMap <- ggmap(get_googlemap(center=c(-99.9, 32.0), scale=2 ,zoom=6,
                                 maptype = "roadmap"), extent="panel")

# mapping county level population
map2 <- GoogleMap + #optional 
  geom_polygon(data=ggSHP2, aes(x=long, y=lat, group=group, fill=Unemployment), 
               color="grey60", alpha=0.8)+ # specify variable to map
  scale_fill_distiller(palette = "YlOrRd",na.value = "grey50", 
                       breaks = pretty_breaks(n = 3), label=comma,
                       values = c(1,0), guide=guide_colorbar(reverse = TRUE))+
  labs(fill="% Unemployed")+xlab("Longitude")+ylab("Latitude")+
  ggtitle("Map of Texas County level Unemployment Rate")
map2  #check


# Put several maps together
library(ggpubr)
figure1 <- ggarrange(map1, map2, nrow = 1)
figure1


#save the maps
#ggsave("county_tmap_ggplot.png", figure1)

Mapping with tmap

For ggplot2 users, geom_sf() offers a familiar interface for mapping data obtained from the US Census Bureau. However, ggplot2 is far from the only option for cartographic visualization in R. The tmap package (Tennekes 2018) is an excellent alternative for mapping in R that includes a wide range of functionality for custom cartography. The section that follows is an overview of several cartographic techniques implemented with tmap for visualizing US Census data. A full treatment of best practices in cartographic design is beyond the scope of this section; recommended resources for learning more include Peterson (2020) and Brewer (2016).

########################
### Using tmap
#######################
library(tmap)
# more tmap styles info here: https://geocompr.github.io/post/2019/tmap-color-scales/
library(ggmap)
#register_google(key="YOUR GOOGLE API KEY", write=TRUE) 
# geocode to get some city 
coordinates <- geocode(c("Houston, TX", "Austin, TX", "Dallas, TX")) %>% 
  mutate(city=c("Houston", "Austin", "Dallas"))
ℹ <]8;;https://maps.googleapis.com/maps/api/geocode/json?address=Houston,+TX&key=xxx-W7Ie8An3EnYx3a_LadnKrVUUKLDfshttps://maps.googleapis.com/maps/api/geocode/json?address=Houston,+TX&key=xxx-W7Ie8An3EnYx3a_LadnKrVUUKLDfs]8;;>
ℹ <]8;;https://maps.googleapis.com/maps/api/geocode/json?address=Austin,+TX&key=xxx-W7Ie8An3EnYx3a_LadnKrVUUKLDfshttps://maps.googleapis.com/maps/api/geocode/json?address=Austin,+TX&key=xxx-W7Ie8An3EnYx3a_LadnKrVUUKLDfs]8;;>
ℹ <]8;;https://maps.googleapis.com/maps/api/geocode/json?address=Dallas,+TX&key=xxx-W7Ie8An3EnYx3a_LadnKrVUUKLDfshttps://maps.googleapis.com/maps/api/geocode/json?address=Dallas,+TX&key=xxx-W7Ie8An3EnYx3a_LadnKrVUUKLDfs]8;;>
coor_sf = st_as_sf(coordinates, coords = c('lon', 'lat'), crs = st_crs(TX_county_dt)$proj4string)

coordinates

# map
map1 <- tm_shape(TX_county_dt)+
  tm_polygons(col=c("Unemployment","Per_capita_income"), style="quantile",n=4, 
              # specify variables and styles of mapping 
              title=c("Percentage","Dollars"), palette="seq", lwd=0.5,  
              border.alpha = 0.8, midpoint=NA)+
  tm_facets(ncol=2)+ # number of columns
  tm_layout(aes.palette = list(seq = "YlOrRd"))+ # color scheme
  tm_layout(inner.margin=c(0,0.01,0,0), # layout of the map
            legend.text.size = 1,
            legend.title.size = 1,
            legend.position=c("left", "bottom"), 
            panel.labels=c("Unemployment","Per capita income"),
            panel.label.bg.color = "White")+
  tm_shape(coor_sf)+ # you can also add point data - mark locations of the big cities 
  tm_symbols(size=0.5, col="black", border.col="black")+tm_text("city", size=1.2, just="left", ymod=0.6)

map1 


# save the map
#tmap_save(map3, filename="county_map_tmap", dpi=500)  
  

An alternative commonly used to visualize count data is the graduated symbol map. Graduated symbol maps use shapes referenced to geographic units that are sized relative to a data attribute. The example below uses tmap’s tm_bubbles() function to create a graduated symbol map of the total population in Texas counties:

tm_shape(TX_county_dt) + 
  tm_polygons() + 
  tm_bubbles(size = "Population", 
             alpha = 0.5, 
             col = "navy",
             title.size = "County population size in Texas, 2020")

There are other functions in tmap that can be used to customize your maps. tm_scale_bar() adds a scale bar; tm_compass() adds a north arrow; and tm_credits() helps cartographers give credit for the basemap, which is required when using Mapbox and OpenStreetMap tiles. The legend.hist argument in tm_polygons() can be set to TRUE, adding a histogram to the map with bars colored by the values used on the map.

tm_shape(TX_county_dt)+
  tm_polygons(col=c("Unemployment"), style="quantile",n=4, 
              title=c("Percentage"), palette="seq", lwd=0.5,  
              border.alpha = 0.3, midpoint=NA,
              legend.hist=T,legend.hist.z=4)+
  tm_layout(aes.palette = list(seq = "YlOrRd"))+ # color scheme
  tm_layout(inner.margin=c(0,0.2,0,0), # layout of the map
            legend.text.size = 1,
            legend.title.size = 1,
            legend.position=c("left", "bottom"), 
            panel.labels=c("Unemployment"),
            panel.label.bg.color = "White")+
  tm_compass(position = c("left", "top"))+
  tm_scale_bar(position = c("right", "top"))

NA
NA

Interactive Mapping

Mapview

We can quickly visualize geographic data obtained with tigris on an interactive map by using the mapview() function in the mapview package. The mapview() function also includes a parameter zcol that takes a column in the dataset as an argument, and visualizes that column with an interactive choropleth map.

library(mapview)
mapview(TX_county_dt, zcol = "Per_capita_income")

Interactive Mapping with leaflet

With over 31,000 GitHub stars as of July 2021, the Leaflet JavaScript library (Agafonkin 2020) is one of the most popular frameworks worldwide for interactive mapping. The RStudio team brought the Leaflet to R with the leaflet R package (Cheng, Karambelkar, and Xie 2021), which now powers several approaches to interactive mapping in R. The following examples cover how to visualize Census data on an interactive Leaflet map using approaches from mapview, tmap, and the core leaflet package. Details on leaflet mapping in R can be found here.

Below is an example of interactive map created using leaflet - visualization county level population data in Texas:

######################
## Interactive maps
####################
library(leaflet)
TX_county_dt2 <- as(TX_county_dt, "Spatial")
l <- leaflet(TX_county_dt2) %>% addTiles()
# color scheme
pal <- colorNumeric(palette = "YlOrRd", domain=TX_county_dt2$Population)
# add popup labels
labels <- sprintf("<strong> County: %s </strong> <br/> 
                  Population: %s <br/> Unemployment rate: %s <br/> 
                  Per capita income, $: %s",
                  TX_county_dt2$NAME, TX_county_dt2$Population,
                  TX_county_dt2$Unemployment, TX_county_dt2$Per_capita_income) %>% 
  lapply(htmltools::HTML)
# add to the map
interactive_map <- l %>%
  addPolygons(
    color = "grey", weight = 1,
    fillColor = ~ pal(TX_county_dt2$Population), fillOpacity = 0.5,
    highlightOptions = highlightOptions(weight = 4),
    label = labels,
    labelOptions = labelOptions(
      style = list(
        "font-weight" = "normal",
        padding = "3px 8px"
      ),
      textsize = "15px", direction = "auto"
    )
  ) %>%
  addLegend(
    pal = pal, values = ~TX_county_dt2$Population, opacity = 0.5,
    title = "Population", position = "bottomright"
  )

interactive_map

Alternative ways for interactive mapping

There are many other ways for interactive mapping in R:

LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIHRpZHljZW5zdXMgYW5kIHRpZ3JpcyIKc3VidGl0bGU6ICJFeHBsb3JpbmcgVVMgQ2Vuc3VzIGRhdGEgaW4gUiIKYXV0aG9yOiAiQ2ljaSBCYXVlciwgS2VoZSBaaGFuZyIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMwogICAgdG9jX2Zsb2F0OiB5ZXMKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHtyIHNldHVwICwgaW5jbHVkZT1GLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBULG1lc3NhZ2U9Riwgd2FybmluZz1GKQoKYGBgCgpJbiB0aGlzIHR1dG9yaWFsLCB3ZSB3aWxsIGZpcnN0IGludHJvZHVjZSB0aGUgVW5pdGVkIFN0YXRlcyBDZW5zdXMgZGF0YSBhbmQgZ2l2ZSBhbiBvdmVydmlldyBvZiBob3cgdG8gYWNjZXNzIGFuZCB1c2UgQ2Vuc3VzIGRhdGEuIFRoZSBsYXRlciBwYXJ0IGNvdmVycyBob3cgdG8gYWNjZXNzIGFuZCBleHRyYWN0IENlbnN1cyBkYXRhIGluIFIsIHVzaW5nIHBhY2thZ2UgdGlkeWNlbnN1cy4gV2Ugd2lsbCBhbHNvIGJyaWVmbHkgY292ZXJzIGRvd25sb2FkaW5nIHNoYXBlZmlsZXMgdXNpbmcgUiBwYWNrYWdlIHRpZ3Jpcy4KCiMgQ2Vuc3VzIGRhdGEgb3ZlcnZpZXcgYW5kIGhpZXJhcmNoaWVzCgpQYXJ0IG9mIHRoaXMgc2VjdGlvbiB3YXMgZGVyaXZlZCBmcm9tIHRoZSBvbmxpbmUgYm9vayBbQW5hbHl6aW5nIFVTIENlbnN1cyBEYXRhOiBNZXRob2RzLCBNYXBzLCBhbmQgTW9kZWxzIGluIFJdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL2NlbnN1cy1yL2luZGV4Lmh0bWwpIHNlY3Rpb24gMSBhbmQgMi4KCiMjIEludHJvZHVjdGlvbiB0byBVUyBDZW5zdXMgZGF0YQoKVGhlIGRlY2VubmlhbCBVUyBDZW5zdXMgaXMgaW50ZW5kZWQgdG8gYmUgYSBjb21wbGV0ZSBlbnVtZXJhdGlvbiBvZiB0aGUgVVMgcG9wdWxhdGlvbiB0byBhc3Npc3Qgd2l0aCAqYXBwb3J0aW9ubWVudCosIHdoaWNoIHJlZmVycyB0byB0aGUgYmFsYW5jZWQgYXJyYW5nZW1lbnQgb2YgQ29uZ3Jlc3Npb25hbCBkaXN0cmljdHMgdG8gZW5zdXJlIGFwcHJvcHJpYXRlIHJlcHJlc2VudGF0aW9uIGluIHRoZSBVbml0ZWQgU3RhdGVzIEhvdXNlIG9mIFJlcHJlc2VudGF0aXZlcy4gSXQgYXNrcyBhIGxpbWl0ZWQgc2V0IG9mIHF1ZXN0aW9ucyBvbiByYWNlLCBldGhuaWNpdHksIGFnZSwgc2V4LCBhbmQgaG91c2luZyB0ZW51cmUuCgoqKkFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkqKiAoQUNTKSBpcyBub3cgdGhlIHByZW1pZXIgc291cmNlIG9mIGRldGFpbGVkIGRlbW9ncmFwaGljIGluZm9ybWF0aW9uIGFib3V0IHRoZSBVUyBwb3B1bGF0aW9uLiBUaGUgQUNTIGlzIG1haWxlZCB0byBhcHByb3hpbWF0ZWx5IDMuNSBtaWxsaW9uIGhvdXNlaG9sZHMgcGVyIHllYXIgKHJlcHJlc2VudGluZyBhcm91bmQgMyBwZXJjZW50IG9mIHRoZSBVUyBwb3B1bGF0aW9uKSwgYWxsb3dpbmcgZm9yIGFubnVhbCBkYXRhIHVwZGF0ZXMuIFRoZSBDZW5zdXMgQnVyZWF1IHJlbGVhc2VzIHR3byBBQ1MgZGF0YXNldHMgdG8gdGhlIHB1YmxpYzogdGhlICoqMS15ZWFyIEFDUyoqLCB3aGljaCBjb3ZlcnMgYXJlYXMgb2YgcG9wdWxhdGlvbiA2NSwwMDAgYW5kIGdyZWF0ZXIsIGFuZCB0aGUgKio1LXllYXIgQUNTKiosIHdoaWNoIGlzIGEgbW92aW5nIGF2ZXJhZ2Ugb2YgZGF0YSBvdmVyIGEgNS15ZWFyIHBlcmlvZCB0aGF0IGNvdmVycyBnZW9ncmFwaGllcyBkb3duIHRvIHRoZSBDZW5zdXMgYmxvY2sgZ3JvdXAuIEFDUyBkYXRhIGFyZSBkaXN0aW5jdCBmcm9tIGRlY2VubmlhbCBDZW5zdXMgZGF0YSBpbiB0aGF0IGRhdGEgcmVwcmVzZW50ICplc3RpbWF0ZXMqIHJhdGhlciB0aGFuIHByZWNpc2UgY291bnRzLCBhbmQgaW4gdHVybiBhcmUgY2hhcmFjdGVyaXplZCBieSAqbWFyZ2lucyBvZiBlcnJvciogYXJvdW5kIHRob3NlIGVzdGltYXRlcy4KCiFbXShpbWFnZXMvQUNTX2NvbXBhcmUucG5nKXt3aWR0aD0iNTIxIn0KCkFnZ3JlZ2F0ZSBkYXRhIGZyb20gdGhlIGRlY2VubmlhbCBVUyBDZW5zdXMsIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXksIGFuZCBvdGhlciBDZW5zdXMgc3VydmV5cyBhcmUgbWFkZSBhdmFpbGFibGUgdG8gdGhlIHB1YmxpYyBhdCBkaWZmZXJlbnQgKmVudW1lcmF0aW9uIHVuaXRzKi4gRW51bWVyYXRpb24gdW5pdHMgYXJlIGdlb2dyYXBoaWVzIGF0IHdoaWNoIENlbnN1cyBkYXRhIGFyZSB0YWJ1bGF0ZWQuIFRoZXkgaW5jbHVkZSBib3RoICpsZWdhbCBlbnRpdGllcyogc3VjaCBhcyBzdGF0ZXMgYW5kIGNvdW50aWVzLCBhbmQgKnN0YXRpc3RpY2FsIGVudGl0aWVzKiB0aGF0IGFyZSBub3Qgb2ZmaWNpYWwganVyaXNkaWN0aW9ucyBidXQgdXNlZCB0byBzdGFuZGFyZGl6ZSBkYXRhIHRhYnVsYXRpb24uIFRoZSBzbWFsbGVzdCB1bml0IGF0IHdoaWNoIGRhdGEgYXJlIG1hZGUgYXZhaWxhYmxlIGZyb20gdGhlIGRlY2VubmlhbCBVUyBDZW5zdXMgaXMgdGhlICpibG9jaywqIGFuZCB0aGUgc21hbGxlc3QgdW5pdCBhdmFpbGFibGUgaW4gdGhlIEFDUyBpcyB0aGUgKmJsb2NrIGdyb3VwKiwgd2hpY2ggcmVwcmVzZW50cyBhIGNvbGxlY3Rpb24gb2YgYmxvY2tzLiBPdGhlciBzdXJ2ZXlzIGFyZSBnZW5lcmFsbHkgYXZhaWxhYmxlIGF0IGhpZ2hlciBsZXZlbHMgb2YgYWdncmVnYXRpb24uCgpFbnVtZXJhdGlvbiB1bml0cyByZXByZXNlbnQgZGlmZmVyZW50IGxldmVscyBvZiB0aGUgKkNlbnN1cyBoaWVyYXJjaHkuKiBUaGlzIGhpZXJhcmNoeSBpcyBzdW1tYXJpemVkIGluIHRoZSBncmFwaGljIGJlbG93IChmcm9tIDxodHRwczovL3d3dy5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvZ2VvZ3JhcGh5L2d1aWRhbmNlL2hpZXJhcmNoeS5odG1sPikuCgohW10oaW1hZ2VzL2NlbnN1cy1oaWVyYXJjaGllcy5wbmcpe3dpZHRoPSI1ODcifQoKVGhlIGNlbnRyYWwgYXhpcyBvZiB0aGUgZGlhZ3JhbSByZXByZXNlbnRzIHRoZSBjZW50cmFsIENlbnN1cyBoaWVyYXJjaHkgb2YgZW51bWVyYXRpb24gdW5pdHMsIGFzIGVhY2ggZ2VvZ3JhcGh5IGZyb20gQ2Vuc3VzIGJsb2NrcyBhbGwgdGhlIHdheSB1cCB0byB0aGUgbmF0aW9uICpuZXN0cyogd2l0aGluIGl0cyBwYXJlbnQgdW5pdC4gVGhpcyBtZWFucyB0aGF0IGJsb2NrIGdyb3VwcyBhcmUgZnVsbHkgY29tcG9zZWQgb2YgQ2Vuc3VzIGJsb2NrcywgQ2Vuc3VzIHRyYWN0cyBhcmUgZnVsbHkgY29tcG9zZWQgb2YgYmxvY2sgZ3JvdXBzLCBhbmQgc28gZm9ydGguIEFuIGV4YW1wbGUgb2YgbmVzdGluZyBpcyBzaG93biBpbiB0aGUgZ3JhcGhpYyBiZWxvdyBmb3IgMjAyMCBDZW5zdXMgdHJhY3RzIGluIEhhcnJpcyBDb3VudHksIFRleGFzLgoKIVtdKGltYWdlcy9IYXJyaXNDb3VudHlfVHJhY3RzLnBuZyl7d2lkdGg9IjU5MiJ9CgpUaGUgcGxvdCBpbGx1c3RyYXRlcyBob3cgQ2Vuc3VzIHRyYWN0cyBpbiBIYXJyaXMgQ291bnR5IG5lYXRseSBuZXN0IHdpdGhpbiBpdHMgcGFyZW50IGdlb2dyYXBoeSwgdGhlIGNvdW50eS4gVGhpcyBtZWFucyB0aGF0IHRoZSBzdW0gb2YgQ2Vuc3VzIGRhdGEgZm9yIENlbnN1cyB0cmFjdHMgaW4gSGFycmlzIENvdW50eSB3aWxsIGFsc28gZXF1YWwgSGFycmlzIENvdW50eSdzIHB1Ymxpc2hlZCB0b3RhbCBhdCB0aGUgY291bnR5IGxldmVsLgoKUmV2aWV3aW5nIHRoZSBkaWFncmFtIHNob3dzIHRoYXQgc29tZSBDZW5zdXMgZ2VvZ3JhcGhpZXMsIGxpa2UgY29uZ3Jlc3Npb25hbCBkaXN0cmljdHMsIG9ubHkgbmVzdCB3aXRoaW4gc3RhdGVzLCBhbmQgdGhhdCBzb21lIG90aGVyIGdlb2dyYXBoaWVzIGRvIG5vdCBuZXN0IHdpdGhpbiBhbnkgcGFyZW50IGdlb2dyYXBoeSBhdCBhbGwuIEEgZ29vZCBleGFtcGxlIG9mIHRoaXMgaXMgdGhlIFppcCBDb2RlIFRhYnVsYXRpb24gQXJlYSAoWkNUQSksIHdoaWNoIGlzIHVzZWQgYnkgdGhlIENlbnN1cyBCdXJlYXUgdG8gcmVwcmVzZW50IHBvc3RhbCBjb2RlIGdlb2dyYXBoaWVzIGluIHRoZSBVUy4gQSBicmllZiBpbGx1c3RyYXRpb24gaXMgcmVwcmVzZW50ZWQgYnkgdGhlIGdyYXBoaWMgYmVsb3cuCgohW10oaW1hZ2VzL1pDVEFfSGFycmlzQ291bnR5LnBuZyl7d2lkdGg9IjU3MSJ9CgojIyBIb3cgdG8gYWNjZXNzIENlbnN1cyBkYXRhCgojIyMgRGF0YSBEb3dubG9hZHMgZnJvbSB0aGUgQ2Vuc3VzIEJ1cmVhdQoKVGhlcmUgaXMgYSBbZGF0YSBkb3dubG9hZCBpbnRlcmZhY2VdKGh0dHBzOi8vZGF0YS5jZW5zdXMuZ292L2FkdmFuY2VkKSBhdmFpbGFibGUsIHdoZXJlIHVzZXJzIGNhbiBpbnRlcmFjdGl2ZWx5IHNlYXJjaCBzZXZlcmFsIENlbnN1cyBCdXJlYXUgZGF0YXNldHMgKHRoZSBkZWNlbm5pYWwgQ2Vuc3VzICYgQUNTLCBhbG9uZyB3aXRoIHRoZSBFY29ub21pYyBDZW5zdXMsIFBvcHVsYXRpb24gRXN0aW1hdGVzIFByb2dyYW0sIGFuZCBvdGhlcnMpLCBnZW5lcmF0ZSBjdXN0b20gcXVlcmllcyBieSBnZW9ncmFwaHksIGFuZCBkb3dubG9hZCBkYXRhIGV4dHJhY3RzLgoKIyMjIFRoZSBDZW5zdXMgQVBJCgpDZW5zdXMgQVBJcyBhcmUgY2hhcmFjdGVyaXplZCBieSBhbiAqQVBJIGVuZHBvaW50Kiwgd2hpY2ggaXMgYSBiYXNlIHdlYiBhZGRyZXNzIGZvciBhIGdpdmVuIENlbnN1cyBkYXRhc2V0LCBhbmQgYSAqcXVlcnkqLCB3aGljaCBjdXN0b21pemVzIHRoZSBkYXRhIHJldHVybmVkIGZyb20gdGhlIEFQSS4gSW4gbW9zdCBjYXNlcywgdXNlcnMgd2lsbCBpbnRlcmFjdCB3aXRoIHRoZSBDZW5zdXMgQVBJIHRocm91Z2ggKnNvZnR3YXJlIGxpYnJhcmllcyogdGhhdCBvZmZlciBzaW1wbGlmaWVkIHByb2dyYW1tYXRpYyBhY2Nlc3MgdG8gdGhlIEFQSSdzIGRhdGEgcmVzb3VyY2VzLiBUaGUgZXhhbXBsZSBjb3ZlcmVkIGluIHRoaXMgdHV0b3JpYWwgaXMgdGhlIFIgcGFja2FnZSAqKnRpZHljZW5zdXMqKiAoW0suIFdhbGtlciBhbmQgSGVybWFuIDIwMjFdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL2NlbnN1cy1yL3JlZmVyZW5jZXMuaHRtbCNyZWYtd2Fsa2VyX2FuZF9oZXJtYW4yMDIxKSkuIFVzZXJzIG9mIHRoZSBDZW5zdXMgQVBJIHRocm91Z2ggdGhlc2Ugc29mdHdhcmUgbGlicmFyaWVzIHdpbGwgcmVxdWlyZSBhIFtDZW5zdXMgQVBJIGtleV0oaHR0cHM6Ly9hcGkuY2Vuc3VzLmdvdi9kYXRhL2tleV9zaWdudXAuaHRtbCksIHdoaWNoIGlzIGZyZWUgYW5kIGZhc3QgdG8gYWNxdWlyZS4KCiMgQW4gaW50cm9kdWN0aW9uIHRvIHRpZHljZW5zdXMKClRoZSAqKnRpZHljZW5zdXMqKiBwYWNrYWdlIChbSy4gV2Fsa2VyIGFuZCBIZXJtYW4gMjAyMV0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vY2Vuc3VzLXIvcmVmZXJlbmNlcy5odG1sI3JlZi13YWxrZXJfYW5kX2hlcm1hbjIwMjEpKSwgZmlyc3QgcmVsZWFzZWQgaW4gMjAxNywgaXMgYW4gUiBwYWNrYWdlIGRlc2lnbmVkIHRvIGZhY2lsaXRhdGUgdGhlIHByb2Nlc3Mgb2YgYWNxdWlyaW5nIGFuZCB3b3JraW5nIHdpdGggVVMgQ2Vuc3VzIEJ1cmVhdSBwb3B1bGF0aW9uIGRhdGEgaW4gdGhlIFIgZW52aXJvbm1lbnQuIFRoZSBwYWNrYWdlIGhhcyB0d28gZGlzdGluY3QgZ29hbHMuIEZpcnN0LCAqKnRpZHljZW5zdXMqKiBhaW1zIHRvIG1ha2UgQ2Vuc3VzIGRhdGEgYXZhaWxhYmxlIHRvIFIgdXNlcnMgaW4gYSAqKnRpZHl2ZXJzZSoqLWZyaWVuZGx5IGZvcm1hdCwgaGVscGluZyBraWNrLXN0YXJ0IHRoZSBwcm9jZXNzIG9mIGdlbmVyYXRpbmcgaW5zaWdodHMgZnJvbSBVUyBDZW5zdXMgZGF0YS4gU2Vjb25kLCB0aGUgcGFja2FnZSBpcyBkZXNpZ25lZCB0byBzdHJlYW1saW5lIHRoZSBkYXRhIHdyYW5nbGluZyBwcm9jZXNzIGZvciBzcGF0aWFsIENlbnN1cyBkYXRhIGFuYWx5c3RzLiBXaXRoICoqdGlkeWNlbnN1cyoqLCBSIHVzZXJzIGNhbiByZXF1ZXN0ICpnZW9tZXRyeSogYWxvbmcgd2l0aCBhdHRyaWJ1dGVzIGZvciB0aGVpciBDZW5zdXMgZGF0YSwgaGVscGluZyBmYWNpbGl0YXRlIG1hcHBpbmcgYW5kIHNwYXRpYWwgYW5hbHlzaXMuCgpUIFVTIENlbnN1cyBCdXJlYXUgbWFrZXMgYSB3aWRlIHJhbmdlIG9mIGRhdGFzZXRzIGF2YWlsYWJsZSB0byB0aGUgdXNlciBjb21tdW5pdHkgdGhyb3VnaCB0aGVpciBBUElzIGFuZCBvdGhlciBkYXRhIGRvd25sb2FkIHJlc291cmNlcy4gKip0aWR5Y2Vuc3VzKiogaXMgbm90IGEgY29tcHJlaGVuc2l2ZSBwb3J0YWwgdG8gdGhlc2UgZGF0YSByZXNvdXJjZXM7IGluc3RlYWQsIGl0IGZvY3VzZXMgb24gYSBzZWxlY3QgbnVtYmVyIG9mIGRhdGFzZXRzIGltcGxlbWVudGVkIGluIGEgc2VyaWVzIG9mIGNvcmUgZnVuY3Rpb25zLiBUaGVzZSBjb3JlIGZ1bmN0aW9ucyBpbiAqKnRpZHljZW5zdXMqKiBpbmNsdWRlOgoKLSAgIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgd2hpY2ggcmVxdWVzdHMgZGF0YSBmcm9tIHRoZSBVUyBEZWNlbm5pYWwgQ2Vuc3VzIEFQSXMgZm9yIDIwMDAsIDIwMTAsIGFuZCAyMDIwLgoKLSAgIFtgZ2V0X2FjcygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Fjcy5odG1sKSwgd2hpY2ggcmVxdWVzdHMgZGF0YSBmcm9tIHRoZSAxLXllYXIgYW5kIDUteWVhciBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IHNhbXBsZXMuIERhdGEgYXJlIGF2YWlsYWJsZSBmcm9tIHRoZSAxLXllYXIgQUNTIGJhY2sgdG8gMjAwNSBhbmQgdGhlIDUteWVhciBBQ1MgYmFjayB0byAyMDA1LTIwMDkuCgotICAgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpLCBhbiBpbnRlcmZhY2UgdG8gdGhlIFBvcHVsYXRpb24gRXN0aW1hdGVzIEFQSXMuIFRoZXNlIGRhdGFzZXRzIGluY2x1ZGUgeWVhcmx5IGVzdGltYXRlcyBvZiBwb3B1bGF0aW9uIGNoYXJhY3RlcmlzdGljcyBieSBzdGF0ZSwgY291bnR5LCBhbmQgbWV0cm9wb2xpdGFuIGFyZWEsIGFsb25nIHdpdGggY29tcG9uZW50cyBvZiBjaGFuZ2UgZGVtb2dyYXBoaWMgZXN0aW1hdGVzIGxpa2UgYmlydGhzLCBkZWF0aHMsIGFuZCBtaWdyYXRpb24gcmF0ZXMuCgotICAgW2BnZXRfcHVtcygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X3B1bXMuaHRtbCksIHdoaWNoIGFjY2Vzc2VzIGRhdGEgZnJvbSB0aGUgQUNTIFB1YmxpYyBVc2UgTWljcm9kYXRhIFNhbXBsZSBBUElzLiBUaGVzZSBzYW1wbGVzIGluY2x1ZGUgYW5vbnltaXplZCBpbmRpdmlkdWFsLWxldmVsIHJlY29yZHMgZnJvbSB0aGUgQUNTIG9yZ2FuaXplZCBieSBob3VzZWhvbGQgYW5kIGFyZSBoaWdobHkgdXNlZnVsIGZvciBtYW55IGRpZmZlcmVudCBzb2NpYWwgc2NpZW5jZSBhbmFseXNlcy4gW2BnZXRfcHVtcygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X3B1bXMuaHRtbCkgaXMgY292ZXJlZCBpbiBtb3JlIGRlcHRoIGluIENoYXB0ZXJzIFs5XShodHRwczovL3dhbGtlci1kYXRhLmNvbS9jZW5zdXMtci9pbnRyb2R1Y3Rpb24tdG8tY2Vuc3VzLW1pY3JvZGF0YS5odG1sI2ludHJvZHVjdGlvbi10by1jZW5zdXMtbWljcm9kYXRhKSBhbmQgWzEwXShodHRwczovL3dhbGtlci1kYXRhLmNvbS9jZW5zdXMtci9hbmFseXppbmctY2Vuc3VzLW1pY3JvZGF0YS5odG1sI2FuYWx5emluZy1jZW5zdXMtbWljcm9kYXRhKS4KCi0gICBbYGdldF9mbG93cygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Zsb3dzLmh0bWwpLCBhbiBpbnRlcmZhY2UgdG8gdGhlIEFDUyBNaWdyYXRpb24gRmxvd3MgQVBJcy4gSW5jbHVkZXMgaW5mb3JtYXRpb24gb24gaW4tIGFuZCBvdXQtZmxvd3MgZnJvbSB2YXJpb3VzIGdlb2dyYXBoaWVzIGZvciB0aGUgNS15ZWFyIEFDUyBzYW1wbGVzLCBlbmFibGluZyBvcmlnaW4tZGVzdGluYXRpb24gYW5hbHlzZXMuCgojIyBHZXR0aW5nIHN0YXJ0ZWQgd2l0aCB0aWR5Y2Vuc3VzCgpUbyBnZXQgc3RhcnRlZCB3aXRoICoqdGlkeWNlbnN1cyoqLCB1c2VycyBzaG91bGQgaW5zdGFsbCB0aGUgcGFja2FnZSB3aXRoIGBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5Y2Vuc3VzIilgIGlmIG5vdCB5ZXQgaW5zdGFsbGVkOyBsb2FkIHRoZSBwYWNrYWdlIHdpdGggW2BsaWJyYXJ5KCJ0aWR5Y2Vuc3VzIilgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzLyk7IGFuZCBzZXQgdGhlaXIgQ2Vuc3VzIEFQSSBrZXkgd2l0aCB0aGUgW2BjZW5zdXNfYXBpX2tleSgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvY2Vuc3VzX2FwaV9rZXkuaHRtbCkgZnVuY3Rpb24uIEFQSSBrZXlzIGNhbiBiZSBvYnRhaW5lZCBhdCA8aHR0cHM6Ly9hcGkuY2Vuc3VzLmdvdi9kYXRhL2tleV9zaWdudXAuaHRtbD4uIEFmdGVyIHlvdSd2ZSBzaWduZWQgdXAgZm9yIGFuIEFQSSBrZXksIGJlIHN1cmUgdG8gYWN0aXZhdGUgdGhlIGtleSBmcm9tIHRoZSBlbWFpbCB5b3UgcmVjZWl2ZSBmcm9tIHRoZSBDZW5zdXMgQnVyZWF1IHNvIGl0IHdvcmtzIGNvcnJlY3RseS4gRGVjbGFyaW5nIGBpbnN0YWxsID0gVFJVRWAgd2hlbiBjYWxsaW5nIFtgY2Vuc3VzX2FwaV9rZXkoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2NlbnN1c19hcGlfa2V5Lmh0bWwpIHdpbGwgaW5zdGFsbCB0aGUga2V5IGZvciB1c2UgaW4gZnV0dXJlIFIgc2Vzc2lvbnMsIHdoaWNoIG1heSBiZSBjb252ZW5pZW50IGZvciBtYW55IHVzZXJzLgoKYGBge3J9CiNyZW1vdGVzOjppbnN0YWxsX2dpdGh1Yigid2Fsa2Vya2UvdGlkeWNlbnN1cyIsIGZvcmNlPVQpCmxpYnJhcnkodGlkeWNlbnN1cykKIyBjZW5zdXNfYXBpX2tleSgiWU9VUiBLRVkgR09FUyBIRVJFIiwgaW5zdGFsbCA9IFRSVUUpCmBgYAoKIyMjIERlY2VubmlhbCBDZW5zdXMKCkxldCdzIHN0YXJ0IHdpdGggW2BnZXRfZGVjZW5uaWFsKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZGVjZW5uaWFsLmh0bWwpLCB3aGljaCBpcyB1c2VkIHRvIGFjY2VzcyBkZWNlbm5pYWwgQ2Vuc3VzIGRhdGEgZnJvbSB0aGUgMjAwMCwgMjAxMCwgYW5kIDIwMjAgZGVjZW5uaWFsIFVTIENlbnN1c2VzLiBUbyBnZXQgZGF0YSBmcm9tIHRoZSBkZWNlbm5pYWwgVVMgQ2Vuc3VzLCB1c2VycyBtdXN0IHNwZWNpZnkgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSByZXF1ZXN0ZWQgYGdlb2dyYXBoeWA7IGEgdmVjdG9yIG9mIENlbnN1cyB2YXJpYWJsZSBJRHMsIHJlcHJlc2VudGVkIGJ5IGB2YXJpYWJsZWA7IG9yIG9wdGlvbmFsbHkgYSBDZW5zdXMgdGFibGUgSUQsIHBhc3NlZCB0byBgdGFibGVgLiBUaGUgY29kZSBiZWxvdyBnZXRzIGRhdGEgb24gdG90YWwgcG9wdWxhdGlvbiBieSBzdGF0ZSBmcm9tIHRoZSAyMDEwIGRlY2VubmlhbCBDZW5zdXMuCgpgYGB7cn0KdG90YWxfcG9wdWxhdGlvbl8xMCA8LSBnZXRfZGVjZW5uaWFsKAogIGdlb2dyYXBoeSA9ICJzdGF0ZSIsIAogIHZhcmlhYmxlcyA9ICJQMDAxMDAxIiwKICB5ZWFyID0gMjAxMAopCgp0b3RhbF9wb3B1bGF0aW9uXzEwCmBgYAoKVGhlIGZ1bmN0aW9uIHJldHVybnMgYSB0aWJibGUgb2YgZGF0YSBmcm9tIHRoZSAyMDEwIFVTIENlbnN1cyAodGhlIGZ1bmN0aW9uIGRlZmF1bHQgeWVhcikgd2l0aCBpbmZvcm1hdGlvbiBvbiB0b3RhbCBwb3B1bGF0aW9uIGJ5IHN0YXRlLCBhbmQgYXNzaWducyBpdCB0byB0aGUgb2JqZWN0IGB0b3RhbF9wb3B1bGF0aW9uXzEwYC4gRGF0YSBmb3IgMjAwMCBvciAyMDIwIGNhbiBhbHNvIGJlIG9idGFpbmVkIGJ5IHN1cHBseWluZyB0aGUgYXBwcm9wcmlhdGUgeWVhciB0byB0aGUgYHllYXJgIHBhcmFtZXRlci4KCkJ5IGRlZmF1bHQsIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSB1c2VzIHRoZSBhcmd1bWVudCBgc3VtZmlsZSA9ICJzZjEiYCwgd2hpY2ggZmV0Y2hlcyBkYXRhIGZyb20gdGhlIGRlY2VubmlhbCBDZW5zdXMgU3VtbWFyeSBGaWxlIDEuIFRoaXMgc3VtbWFyeSBmaWxlIGV4aXN0cyBmb3IgdGhlIDIwMDAgYW5kIDIwMTAgZGVjZW5uaWFsIFVTIENlbnN1c2VzLCBhbmQgaW5jbHVkZXMgY29yZSBkZW1vZ3JhcGhpYyBjaGFyYWN0ZXJpc3RpY3MgZm9yIENlbnN1cyBnZW9ncmFwaGllcy4gVGhlIDIwMDAgYW5kIDIwMTAgZGVjZW5uaWFsIENlbnN1cyBkYXRhIGFsc28gaW5jbHVkZSBTdW1tYXJ5IEZpbGUgMiwgd2hpY2ggY29udGFpbnMgaW5mb3JtYXRpb24gb24gYSByYW5nZSBvZiBwb3B1bGF0aW9uIGFuZCBob3VzaW5nIHVuaXQgY2hhcmFjdGVyaXN0aWNzIGFuZCBpcyBzcGVjaWZpZWQgYXMgYCJzZjIiYC4gRGV0YWlsZWQgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24gaW4gdGhlIDIwMDAgZGVjZW5uaWFsIENlbnN1cyBzdWNoIGFzIGluY29tZSBhbmQgb2NjdXBhdGlvbiBjYW4gYmUgZm91bmQgaW4gU3VtbWFyeSBGaWxlcyAzIChgInNmMyJgKSBhbmQgNCAoYCJzZjQiYCkuIERhdGEgZnJvbSB0aGUgMjAwMCBhbmQgMjAxMCBEZWNlbm5pYWwgQ2Vuc3VzZXMgZm9yIGlzbGFuZCB0ZXJyaXRvcmllcyBvdGhlciB0aGFuIFB1ZXJ0byBSaWNvIG11c3QgYmUgYWNjZXNzZWQgYXQgdGhlaXIgY29ycmVzcG9uZGluZyBzdW1tYXJ5IGZpbGVzOiBgImFzImAgZm9yIEFtZXJpY2FuIFNhbW9hLCBgIm1wImAgZm9yIHRoZSBOb3J0aGVybiBNYXJpYW5hIElzbGFuZHMsIGAiZ3UiYCBmb3IgR3VhbSwgYW5kIGAidmkiYCBmb3IgdGhlIFVTIFZpcmdpbiBJc2xhbmRzLgoKMjAyMCBEZWNlbm5pYWwgQ2Vuc3VzIGRhdGEgYXJlIGF2YWlsYWJsZSBmcm9tIHRoZSBQTCA5NC0xNzEgUmVkaXN0cmljdGluZyBzdW1tYXJ5IGZpbGUsIHdoaWNoIGlzIHNwZWNpZmllZCB3aXRoIGBzdW1maWxlID0gInBsImAgYW5kIGlzIGFsc28gYXZhaWxhYmxlIGZvciAyMDEwLiBUaGUgUmVkaXN0cmljdGluZyBzdW1tYXJ5IGZpbGVzIGluY2x1ZGUgYSBsaW1pdGVkIHN1YnNldCBvZiB2YXJpYWJsZXMgZnJvbSB0aGUgZGVjZW5uaWFsIFVTIENlbnN1cyB0byBiZSB1c2VkIGZvciBsZWdpc2xhdGl2ZSByZWRpc3RyaWN0aW5nLiBUaGVzZSB2YXJpYWJsZXMgaW5jbHVkZSB0b3RhbCBwb3B1bGF0aW9uIGFuZCBob3VzaW5nIHVuaXRzOyByYWNlIGFuZCBldGhuaWNpdHk7IHZvdGluZy1hZ2UgcG9wdWxhdGlvbjsgYW5kIGdyb3VwIHF1YXJ0ZXJzIHBvcHVsYXRpb24uIEZvciBleGFtcGxlLCB0aGUgY29kZSBiZWxvdyByZXRyaWV2ZXMgaW5mb3JtYXRpb24gb24gdGhlIEFtZXJpY2FuIEluZGlhbiAmIEFsYXNrYSBOYXRpdmUgcG9wdWxhdGlvbiBieSBzdGF0ZSBmcm9tIHRoZSAyMDIwIGRlY2VubmlhbCBDZW5zdXMuCgpgYGB7cn0KYWlhbl8yMDIwIDwtIGdldF9kZWNlbm5pYWwoCiAgZ2VvZ3JhcGh5ID0gInN0YXRlIiwKICB2YXJpYWJsZXMgPSAiUDFfMDA1TiIsCiAgeWVhciA9IDIwMjAsCiAgc3VtZmlsZSA9ICJwbCIKKQoKYWlhbl8yMDIwCmBgYAoKVGhlIGFyZ3VtZW50IGBzdW1maWxlID0gInBsImAgaXMgYXNzdW1lZCAoYW5kIGluIHR1cm4gbm90IHJlcXVpcmVkKSB3aGVuIHVzZXJzIHJlcXVlc3QgZGF0YSBmb3IgMjAyMCBhbmQgd2lsbCByZW1haW4gc28gdW50aWwgdGhlIG1haW4gRGVtb2dyYXBoaWMgYW5kIEhvdXNpbmcgQ2hhcmFjdGVyaXN0aWNzIEZpbGUgaXMgcmVsZWFzZWQgaW4gbWlkLXRvLWxhdGUgMjAyMi4KCkZvciBtYW55IGdlb2dyYXBoaWVzLCAqKnRpZHljZW5zdXMqKiBzdXBwb3J0cyBtb3JlIGdyYW51bGFyIHJlcXVlc3RzIHRoYXQgYXJlIHN1YnNldHRlZCBieSBzdGF0ZSBvciBldmVuIGJ5IGNvdW50eSwgaWYgc3VwcG9ydGVkIGJ5IHRoZSBBUEkuIEZvciBleGFtcGxlLCB3ZSBjYW4gdXNlIHRoZSBgc3RhdGVgIHBhcmFtZXRlciB0byBzdWJzZXQgY291bnR5IGxldmVsIHBvcHVsYXRpb24gZm9yIFRleGFzOgoKYGBge3J9CnRvdGFsX3BvcHVsYXRpb25fMTBfVFggPC0gZ2V0X2RlY2VubmlhbCgKICBnZW9ncmFwaHkgPSAiY291bnR5IiwgCiAgdmFyaWFibGVzID0gIlAwMDEwMDEiLAogIHN0YXRlPSJUZXhhcyIsCiAgeWVhciA9IDIwMTAKKQoKdG90YWxfcG9wdWxhdGlvbl8xMF9UWApgYGAKCiMjIyBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IChBQ1MpCgpTaW1pbGFybHksIFtgZ2V0X2FjcygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Fjcy5odG1sKSByZXRyaWV2ZXMgZGF0YSBmcm9tIHRoZSBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5LiBBcyBkaXNjdXNzZWQgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24sIHRoZSBBQ1MgaW5jbHVkZXMgYSB3aWRlIHZhcmlldHkgb2YgdmFyaWFibGVzIGRldGFpbGluZyBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIFVTIHBvcHVsYXRpb24gbm90IGZvdW5kIGluIHRoZSBkZWNlbm5pYWwgQ2Vuc3VzLiBUaGUgZXhhbXBsZSBiZWxvdyBmZXRjaGVzIGRhdGEgb24gdGhlIG51bWJlciBvZiByZXNpZGVudHMgYm9ybiBpbiBNZXhpY28gYnkgc3RhdGUuCgpgYGB7cn0KYm9ybl9pbl9tZXhpY28gPC0gZ2V0X2FjcygKICBnZW9ncmFwaHkgPSAic3RhdGUiLCAKICB2YXJpYWJsZXMgPSAiQjA1MDA2XzE1MCIsCiAgeWVhciA9IDIwMjAKKQoKYm9ybl9pbl9tZXhpY28KYGBgCgpJZiB0aGUgeWVhciBpcyBub3Qgc3BlY2lmaWVkLCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCkgZGVmYXVsdHMgdG8gdGhlIG1vc3QgcmVjZW50IGZpdmUteWVhciBBQ1Mgc2FtcGxlLCB3aGljaCBhdCB0aGUgdGltZSBvZiB0aGlzIHdyaXRpbmcgaXMgMjAxNi0yMDIwLiBUaGUgZGF0YSByZXR1cm5lZCBpcyBzaW1pbGFyIGluIHN0cnVjdHVyZSB0byB0aGF0IHJldHVybmVkIGJ5IFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgYnV0IGluY2x1ZGVzIGFuIGBlc3RpbWF0ZWAgY29sdW1uIChmb3IgdGhlIEFDUyBlc3RpbWF0ZSkgYW5kIGBtb2VgIGNvbHVtbiAoZm9yIHRoZSBtYXJnaW4gb2YgZXJyb3IgYXJvdW5kIHRoYXQgZXN0aW1hdGUpIGluc3RlYWQgb2YgYSBgdmFsdWVgIGNvbHVtbi4gRGlmZmVyZW50IHllYXJzIGFuZCBkaWZmZXJlbnQgc3VydmV5cyBhcmUgYXZhaWxhYmxlIGJ5IGFkanVzdGluZyB0aGUgYHllYXJgIGFuZCBgc3VydmV5YCBwYXJhbWV0ZXJzLiBgc3VydmV5YCBkZWZhdWx0cyB0byB0aGUgNS15ZWFyIEFDUzsgaG93ZXZlciB0aGlzIGNhbiBiZSBjaGFuZ2VkIHRvIHRoZSAxLXllYXIgQUNTIGJ5IHVzaW5nIHRoZSBhcmd1bWVudCBgc3VydmV5ID0gImFjczEiYC4gRm9yIGV4YW1wbGUsIHRoZSBmb2xsb3dpbmcgY29kZSB3aWxsIGZldGNoIGRhdGEgZnJvbSB0aGUgMS15ZWFyIEFDUyBmb3IgMjAxOToKCmBgYHtyfQpib3JuX2luX21leGljb18xeXIgPC0gZ2V0X2FjcygKICBnZW9ncmFwaHkgPSAic3RhdGUiLCAKICB2YXJpYWJsZXMgPSAiQjA1MDA2XzE1MCIsIAogIHN1cnZleSA9ICJhY3MxIiwKICB5ZWFyID0gMjAxOQopCmBgYAoKTm90ZSB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgNS15ZWFyIEFDUyBlc3RpbWF0ZXMgYW5kIHRoZSAxLXllYXIgQUNTIGVzdGltYXRlcyBzaG93bi4gRm9yIHN0YXRlcyB3aXRoIGxhcmdlciBNZXhpY2FuLWJvcm4gcG9wdWxhdGlvbnMgbGlrZSBBcml6b25hLCBDYWxpZm9ybmlhLCBhbmQgQ29sb3JhZG8sIHRoZSAxLXllYXIgQUNTIGRhdGEgd2lsbCByZXByZXNlbnQgdGhlIG1vc3QgdXAtdG8tZGF0ZSBlc3RpbWF0ZXMsIGFsYmVpdCBjaGFyYWN0ZXJpemVkIGJ5IGxhcmdlciBtYXJnaW5zIG9mIGVycm9yIHJlbGF0aXZlIHRvIHRoZWlyIGVzdGltYXRlcy4gRm9yIHN0YXRlcyB3aXRoIHNtYWxsZXIgTWV4aWNhbi1ib3JuIHBvcHVsYXRpb25zIGxpa2UgQWxhYmFtYSwgQWxhc2thLCBhbmQgQXJrYW5zYXMsIGhvd2V2ZXIsIHRoZSBlc3RpbWF0ZSByZXR1cm5zIGBOQWAsIFIncyBub3RhdGlvbiByZXByZXNlbnRpbmcgbWlzc2luZyBkYXRhLiBJZiB5b3UgZW5jb3VudGVyIHRoaXMgaW4geW91ciBkYXRhJ3MgYGVzdGltYXRlYCBjb2x1bW4sIGl0IHdpbGwgZ2VuZXJhbGx5IG1lYW4gdGhhdCB0aGUgZXN0aW1hdGUgaXMgdG9vIHNtYWxsIGZvciBhIGdpdmVuIGdlb2dyYXBoeSB0byBiZSBkZWVtZWQgcmVsaWFibGUgYnkgdGhlIENlbnN1cyBCdXJlYXUuIEluIHRoaXMgY2FzZSwgb25seSB0aGUgc3RhdGVzIHdpdGggdGhlIGxhcmdlc3QgTWV4aWNhbi1ib3JuIHBvcHVsYXRpb25zIGhhdmUgZGF0YSBhdmFpbGFibGUgZm9yIHRoYXQgdmFyaWFibGUgaW4gdGhlIDEteWVhciBBQ1MsIG1lYW5pbmcgdGhhdCB0aGUgNS15ZWFyIEFDUyBzaG91bGQgYmUgdXNlZCB0byBtYWtlIGZ1bGwgc3RhdGUtd2lzZSBjb21wYXJpc29ucyBpZiBkZXNpcmVkLgoKVmFyaWFibGVzIGZyb20gdGhlIEFDUyBkZXRhaWxlZCB0YWJsZXMsIGRhdGEgcHJvZmlsZXMsIHN1bW1hcnkgdGFibGVzLCBjb21wYXJpc29uIHByb2ZpbGUsIGFuZCBzdXBwbGVtZW50YWwgZXN0aW1hdGVzIGFyZSBhdmFpbGFibGUgdGhyb3VnaCAqKnRpZHljZW5zdXMqKidzIFtgZ2V0X2FjcygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Fjcy5odG1sKSBmdW5jdGlvbjsgdGhlIGZ1bmN0aW9uIHdpbGwgYXV0by1kZXRlY3QgZnJvbSB3aGljaCBkYXRhc2V0IHRvIGxvb2sgZm9yIHZhcmlhYmxlcyBiYXNlZCBvbiB0aGVpciBuYW1lcy4gQWx0ZXJuYXRpdmVseSwgdXNlcnMgY2FuIHN1cHBseSBhIHRhYmxlIG5hbWUgdG8gdGhlIHRhYmxlIHBhcmFtZXRlciBpbiBnZXRfYWNzKCk7IHRoaXMgd2lsbCByZXR1cm4gZGF0YSBmb3IgZXZlcnkgdmFyaWFibGUgaW4gdGhhdCB0YWJsZS4gRm9yIGV4YW1wbGUsIHRvIGdldCBhbGwgdmFyaWFibGVzIGFzc29jaWF0ZWQgd2l0aCB0YWJsZSBCMDEwMDEsIHdoaWNoIGNvdmVycyBzZXggYnJva2VuIGRvd24gYnkgYWdlLCBmcm9tIHRoZSAyMDE2LTIwMjAgNS15ZWFyIEFDUzoKCmBgYHtyfQphZ2VfdGFibGUgPC0gZ2V0X2FjcygKICBnZW9ncmFwaHkgPSAic3RhdGUiLCAKICB0YWJsZSA9ICJCMDEwMDEiLAogIHllYXIgPSAyMDIwCikKCmFnZV90YWJsZQpgYGAKClRvIGZpbmQgYWxsIG9mIHRoZSB2YXJpYWJsZXMgYXNzb2NpYXRlZCB3aXRoIGEgZ2l2ZW4gQUNTIHRhYmxlLCAqKnRpZHljZW5zdXMqKiBkb3dubG9hZHMgYSBkYXRhc2V0IG9mIHZhcmlhYmxlcyBmcm9tIHRoZSBDZW5zdXMgQnVyZWF1IHdlYnNpdGUgYW5kIGxvb2tzIHVwIHRoZSB2YXJpYWJsZSBjb2RlcyBmb3IgZG93bmxvYWQuIElmIHRoZSBgY2FjaGVfdGFibGVgIHBhcmFtZXRlciBpcyBzZXQgdG8gYFRSVUVgLCB0aGUgZnVuY3Rpb24gaW5zdHJ1Y3RzICoqdGlkeWNlbnN1cyoqIHRvIGNhY2hlIHRoaXMgZGF0YXNldCBvbiB0aGUgdXNlcidzIGNvbXB1dGVyIGZvciBmYXN0ZXIgZnV0dXJlIGFjY2Vzcy4gVGhpcyBvbmx5IG5lZWRzIHRvIGJlIGRvbmUgb25jZSBwZXIgQUNTIG9yIENlbnN1cyBkYXRhc2V0IGlmIHRoZSB1c2VyIHdvdWxkIGxpa2UgdG8gc3BlY2lmeSB0aGlzIG9wdGlvbi4KCiMjIyBHZW9ncmFwaHkgYW5kIHZhcmlhYmxlcyBpbiB0aWR5Y2Vuc3VzCgpUaGUgYGdlb2dyYXBoeWAgcGFyYW1ldGVyIGluIFtgZ2V0X2FjcygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Fjcy5odG1sKSBhbmQgW2BnZXRfZGVjZW5uaWFsKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZGVjZW5uaWFsLmh0bWwpIGFsbG93cyB1c2VycyB0byByZXF1ZXN0IGRhdGEgYWdncmVnYXRlZCB0byBjb21tb24gQ2Vuc3VzIGVudW1lcmF0aW9uIHVuaXRzLiBBdCB0aGUgdGltZSBvZiB0aGlzIHdyaXRpbmcsICoqdGlkeWNlbnN1cyoqIGFjY2VwdHMgZW51bWVyYXRpb24gdW5pdHMgbmVzdGVkIHdpdGhpbiBzdGF0ZXMgYW5kL29yIGNvdW50aWVzLCB3aGVuIGFwcGxpY2FibGUuIENlbnN1cyBibG9ja3MgYXJlIGF2YWlsYWJsZSBpbiBbYGdldF9kZWNlbm5pYWwoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9kZWNlbm5pYWwuaHRtbCkgYnV0IG5vdCBpbiBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCkgYXMgYmxvY2stbGV2ZWwgZGF0YSBhcmUgbm90IGF2YWlsYWJsZSBmcm9tIHRoZSBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5LiBUbyByZXF1ZXN0IGRhdGEgd2l0aGluIHN0YXRlcyBhbmQvb3IgY291bnRpZXMsIHN0YXRlIGFuZCBjb3VudHkgbmFtZXMgY2FuIGJlIHN1cHBsaWVkIHRvIHRoZSBgc3RhdGVgIGFuZCBgY291bnR5YCBwYXJhbWV0ZXJzLCByZXNwZWN0aXZlbHkuIEFyZ3VtZW50cyBzaG91bGQgYmUgZm9ybWF0dGVkIGluIHRoZSB3YXkgdGhhdCB0aGV5IGFyZSBhY2NlcHRlZCBieSB0aGUgVVMgQ2Vuc3VzIEJ1cmVhdSBBUEksIHNwZWNpZmllZCBpbiB0aGUgdGFibGUgYmVsb3cuIElmIGFuICJBdmFpbGFibGUgYnkiIGdlb2dyYXBoeSBpcyBpbiBib2xkLCB0aGF0IGFyZ3VtZW50IGlzIHJlcXVpcmVkIGZvciB0aGF0IGdlb2dyYXBoeS4KClRoZSBvbmx5IGdlb2dyYXBoaWVzIGF2YWlsYWJsZSBpbiAyMDAwIGFyZSBgInN0YXRlImAsIGAiY291bnR5ImAsIGAiY291bnR5IHN1YmRpdmlzaW9uImAsIGAidHJhY3QiYCwgYCJibG9jayBncm91cCJgLCBhbmQgYCJwbGFjZSJgLiBTb21lIGdlb2dyYXBoaWVzIGF2YWlsYWJsZSBmcm9tIHRoZSBDZW5zdXMgQVBJIGFyZSBub3QgYXZhaWxhYmxlIGluIHRpZHljZW5zdXMgYXQgdGhlIG1vbWVudCBhcyB0aGV5IHJlcXVpcmUgbW9yZSBjb21wbGV4IGhpZXJhcmNoeSBzcGVjaWZpY2F0aW9uIHRoYW4gdGhlIHBhY2thZ2Ugc3VwcG9ydHMsIGFuZCBub3QgYWxsIHZhcmlhYmxlcyBhcmUgYXZhaWxhYmxlIGF0IGV2ZXJ5IGdlb2dyYXBoeS4KCnwgR2VvZ3JhcGh5ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgRGVmaW5pdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgQXZhaWxhYmxlIGJ5ICAgICAgICAgIHwgQXZhaWxhYmxlIGluICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCBgInVzImAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBVbml0ZWQgU3RhdGVzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInJlZ2lvbiJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDZW5zdXMgcmVnaW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImRpdmlzaW9uImAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDZW5zdXMgZGl2aXNpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInN0YXRlImAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBTdGF0ZSBvciBlcXVpdmFsZW50ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpLCBbYGdldF9mbG93cygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Zsb3dzLmh0bWwpIHwKfCBgImNvdW50eSJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDb3VudHkgb3IgZXF1aXZhbGVudCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSwgY291bnR5ICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpLCBbYGdldF9mbG93cygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Zsb3dzLmh0bWwpIHwKfCBgImNvdW50eSBzdWJkaXZpc2lvbiJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDb3VudHkgc3ViZGl2aXNpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiosIGNvdW50eSAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpLCBbYGdldF9mbG93cygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Zsb3dzLmh0bWwpIHwKfCBgInRyYWN0ImAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDZW5zdXMgdHJhY3QgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiosIGNvdW50eSAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImJsb2NrIGdyb3VwImAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDZW5zdXMgYmxvY2sgZ3JvdXAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiosIGNvdW50eSAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCkgKDIwMTMtKSwgW2BnZXRfZGVjZW5uaWFsKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZGVjZW5uaWFsLmh0bWwpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImJsb2NrImAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDZW5zdXMgYmxvY2sgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiosICoqY291bnR5KiogfCBbYGdldF9kZWNlbm5pYWwoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9kZWNlbm5pYWwuaHRtbCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInBsYWNlImAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDZW5zdXMtZGVzaWduYXRlZCBwbGFjZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImFsYXNrYSBuYXRpdmUgcmVnaW9uYWwgY29ycG9yYXRpb24iYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBBbGFza2EgbmF0aXZlIHJlZ2lvbmFsIGNvcnBvcmF0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImFtZXJpY2FuIGluZGlhbiBhcmVhL2FsYXNrYSBuYXRpdmUgYXJlYS9oYXdhaWlhbiBob21lIGxhbmQiYCAgICAgICAgICAgICAgICAgICAgICAgfCBGZWRlcmFsIGFuZCBzdGF0ZS1yZWNvZ25pemVkIEFtZXJpY2FuIEluZGlhbiByZXNlcnZhdGlvbnMgYW5kIEhhd2FpaWFuIGhvbWUgbGFuZHMgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImFtZXJpY2FuIGluZGlhbiBhcmVhL2FsYXNrYSBuYXRpdmUgYXJlYSAocmVzZXJ2YXRpb24gb3Igc3RhdGlzdGljYWwgZW50aXR5IG9ubHkpImAgfCBPbmx5IHJlc2VydmF0aW9ucyBhbmQgc3RhdGlzdGljYWwgZW50aXRpZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImFtZXJpY2FuIGluZGlhbiBhcmVhIChvZmYtcmVzZXJ2YXRpb24gdHJ1c3QgbGFuZCBvbmx5KS9oYXdhaWlhbiBob21lIGxhbmQiYCAgICAgICAgfCBPbmx5IG9mZi1yZXNlcnZhdGlvbiB0cnVzdCBsYW5kcyBhbmQgSGF3YWlpYW4gaG9tZSBsYW5kcyAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgIm1ldHJvcG9saXRhbiBzdGF0aXN0aWNhbCBhcmVhL21pY3JvcG9saXRhbiBzdGF0aXN0aWNhbCBhcmVhImAgT1IgYCJjYnNhImAgICAgICAgICAgfCBDb3JlLWJhc2VkIHN0YXRpc3RpY2FsIGFyZWEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpLCBbYGdldF9mbG93cygpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2Zsb3dzLmh0bWwpIHwKfCBgImNvbWJpbmVkIHN0YXRpc3RpY2FsIGFyZWEiYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDb21iaW5lZCBzdGF0aXN0aWNhbCBhcmVhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSwgW2BnZXRfZXN0aW1hdGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZXN0aW1hdGVzLmh0bWwpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgIm5ldyBlbmdsYW5kIGNpdHkgYW5kIHRvd24gYXJlYSJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBOZXcgRW5nbGFuZCBjaXR5L3Rvd24gYXJlYSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImNvbWJpbmVkIG5ldyBlbmdsYW5kIGNpdHkgYW5kIHRvd24gYXJlYSJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDb21iaW5lZCBOZXcgRW5nbGFuZCBhcmVhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInVyYmFuIGFyZWEiYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDZW5zdXMtZGVmaW5lZCB1cmJhbml6ZWQgYXJlYXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgImNvbmdyZXNzaW9uYWwgZGlzdHJpY3QiYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBDb25ncmVzc2lvbmFsIGRpc3RyaWN0IGZvciB0aGUgeWVhci1hcHByb3ByaWF0ZSBDb25ncmVzcyAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInNjaG9vbCBkaXN0cmljdCAoZWxlbWVudGFyeSkiYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBFbGVtZW50YXJ5IHNjaG9vbCBkaXN0cmljdCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiogICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInNjaG9vbCBkaXN0cmljdCAoc2Vjb25kYXJ5KSJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBTZWNvbmRhcnkgc2Nob29sIGRpc3RyaWN0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiogICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInNjaG9vbCBkaXN0cmljdCAodW5pZmllZCkiYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBVbmlmaWVkIHNjaG9vbCBkaXN0cmljdCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiogICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInB1YmxpYyB1c2UgbWljcm9kYXRhIGFyZWEiYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBQVU1BIChnZW9ncmFwaHkgYXNzb2NpYXRlZCB3aXRoIENlbnN1cyBtaWNyb2RhdGEgc2FtcGxlcykgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInppcCBjb2RlIHRhYnVsYXRpb24gYXJlYSJgIE9SIGAiemN0YSJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBaaXAgY29kZSB0YWJ1bGF0aW9uIGFyZWEgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBzdGF0ZSAgICAgICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInN0YXRlIGxlZ2lzbGF0aXZlIGRpc3RyaWN0ICh1cHBlciBjaGFtYmVyKSJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBTdGF0ZSBzZW5hdGUgZGlzdHJpY3RzICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiogICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInN0YXRlIGxlZ2lzbGF0aXZlIGRpc3RyaWN0IChsb3dlciBjaGFtYmVyKSJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBTdGF0ZSBob3VzZSBkaXN0cmljdHMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiogICAgICAgICAgICAgfCBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCksIFtgZ2V0X2RlY2VubmlhbCgpYF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vdGlkeWNlbnN1cy9yZWZlcmVuY2UvZ2V0X2RlY2VubmlhbC5odG1sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfCBgInZvdGluZyBkaXN0cmljdCJgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBWb3RpbmcgZGlzdHJpY3RzICgyMDIwIG9ubHkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAqKnN0YXRlKiogICAgICAgICAgICAgfCBbYGdldF9kZWNlbm5pYWwoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9kZWNlbm5pYWwuaHRtbCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKClRoZSBnZW9ncmFwaHkgcGFyYW1ldGVyIG11c3QgYmUgdHlwZWQgZXhhY3RseSBhcyBzcGVjaWZpZWQgaW4gdGhlIHRhYmxlIGFib3ZlIHRvIHJlcXVlc3QgZGF0YSBjb3JyZWN0bHkgZnJvbSB0aGUgQ2Vuc3VzIEFQSTsgdXNlIHRoZSBndWlkZSBhYm92ZSBhcyBhIHJlZmVyZW5jZSBhbmQgY29weS1wYXN0ZSBmb3IgbG9uZ2VyIHN0cmluZ3MuIEZvciBjb3JlLWJhc2VkIHN0YXRpc3RpY2FsIGFyZWFzIGFuZCB6aXAgY29kZSB0YWJ1bGF0aW9uIGFyZWFzLCB0d28gaGVhdmlseS1yZXF1ZXN0ZWQgZ2VvZ3JhcGhpZXMsIHRoZSBhbGlhc2VzIGAiY2JzYSJgIGFuZCBgInpjdGEiYCBjYW4gYmUgdXNlZCwgcmVzcGVjdGl2ZWx5LCB0byBmZXRjaCBkYXRhIGZvciB0aG9zZSBnZW9ncmFwaGllcy4KCmBgYHtyfQpjYnNhX3BvcHVsYXRpb24gPC0gZ2V0X2FjcygKICBnZW9ncmFwaHkgPSAiY2JzYSIsCiAgdmFyaWFibGVzID0gIkIwMTAwM18wMDEiLAogIHllYXIgPSAyMDIwCikKYGBgCgojIyMgU2VhcmNoaW5nIGZvciB2YXJpYWJsZXMgaW4gdGlkeWNlbnN1cwoKT25lIGFkZGl0aW9uYWwgY2hhbGxlbmdlIHdoZW4gc2VhcmNoaW5nIGZvciBDZW5zdXMgdmFyaWFibGVzIGlzIHVuZGVyc3RhbmRpbmcgdmFyaWFibGUgSURzLCB3aGljaCBhcmUgcmVxdWlyZWQgdG8gZmV0Y2ggZGF0YSBmcm9tIHRoZSBDZW5zdXMgYW5kIEFDUyBBUElzLiBUaGVyZSBhcmUgdGhvdXNhbmRzIG9mIHZhcmlhYmxlcyBhdmFpbGFibGUgYWNyb3NzIHRoZSBkaWZmZXJlbnQgZGF0YXNldHMgYW5kIHN1bW1hcnkgZmlsZXMuIFRvIG1ha2Ugc2VhcmNoaW5nIGVhc2llciBmb3IgUiB1c2VycywgKip0aWR5Y2Vuc3VzKiogb2ZmZXJzIHRoZSBbYGxvYWRfdmFyaWFibGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9sb2FkX3ZhcmlhYmxlcy5odG1sKSBmdW5jdGlvbi4gVGhpcyBmdW5jdGlvbiBvYnRhaW5zIGEgZGF0YXNldCBvZiB2YXJpYWJsZXMgZnJvbSB0aGUgQ2Vuc3VzIEJ1cmVhdSB3ZWJzaXRlIGFuZCBmb3JtYXRzIGl0IGZvciBmYXN0IHNlYXJjaGluZywgaWRlYWxseSBpbiBSU3R1ZGlvLgoKVGhlIGZ1bmN0aW9uIHRha2VzIHR3byByZXF1aXJlZCBhcmd1bWVudHM6IGB5ZWFyYCwgd2hpY2ggdGFrZXMgdGhlIHllYXIgb3IgZW5keWVhciBvZiB0aGUgQ2Vuc3VzIGRhdGFzZXQgb3IgQUNTIHNhbXBsZSwgYW5kIGBkYXRhc2V0YCwgd2hpY2ggcmVmZXJlbmNlcyB0aGUgZGF0YXNldCBuYW1lLiBGb3IgdGhlIDIwMDAgb3IgMjAxMCBEZWNlbm5pYWwgQ2Vuc3VzLCB1c2UgYCJzZjEiYCBvciBgInNmMiJgIGFzIHRoZSBkYXRhc2V0IG5hbWUgdG8gYWNjZXNzIHZhcmlhYmxlcyBmcm9tIFN1bW1hcnkgRmlsZXMgMSBhbmQgMiwgcmVzcGVjdGl2ZWx5LiBUaGUgMjAwMCBEZWNlbm5pYWwgQ2Vuc3VzIGFsc28gYWNjZXB0cyBgInNmMyJgIGFuZCBgInNmNCJgIGZvciBTdW1tYXJ5IEZpbGVzIDMgYW5kIDQuIEZvciAyMDIwLCB0aGUgb25seSBkYXRhc2V0IHN1cHBvcnRlZCBhdCB0aGUgdGltZSBvZiB0aGlzIHdyaXRpbmcgaXMgYCJwbCJgIGZvciB0aGUgUEwtOTQxNzEgUmVkaXN0cmljdGluZyBkYXRhc2V0OyBtb3JlIGRhdGFzZXRzIHdpbGwgYmUgc3VwcG9ydGVkIGFzIHRoZSAyMDIwIENlbnN1cyBkYXRhIGFyZSByZWxlYXNlZC4gQW4gZXhhbXBsZSByZXF1ZXN0IHdvdWxkIGxvb2sgbGlrZSBgbG9hZF92YXJpYWJsZXMoeWVhciA9IDIwMjAsIGRhdGFzZXQgPSAicGwiKWAgZm9yIHZhcmlhYmxlcyBmcm9tIHRoZSAyMDIwIERlY2VubmlhbCBDZW5zdXMgUmVkaXN0cmljdGluZyBkYXRhLgoKRm9yIHZhcmlhYmxlcyBmcm9tIHRoZSBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5LCB1c2VycyBzaG91bGQgc3BlY2lmeSB0aGUgZGF0YXNldCBhcyBgImFjczEiYCBmb3IgdGhlIDEteWVhciBBQ1Mgb3IgYCJhY3M1ImAgZm9yIHRoZSA1LXllYXIgQUNTLiBJZiBubyBzdWZmaXggdG8gdGhlc2UgZGF0YXNldCBuYW1lcyBpcyBzcGVjaWZpZWQsIHVzZXJzIHdpbGwgcmV0cmlldmUgZGF0YSBmcm9tIHRoZSBBQ1MgRGV0YWlsZWQgVGFibGVzLiBWYXJpYWJsZXMgZnJvbSB0aGUgQUNTIERhdGEgUHJvZmlsZSwgU3VtbWFyeSBUYWJsZXMsIGFuZCBDb21wYXJpc29uIFByb2ZpbGUgYXJlIGFsc28gYXZhaWxhYmxlIGJ5IGFwcGVuZGluZyB0aGUgc3VmZml4ZXMgYC9wcm9maWxlYCwgYC9zdW1tYXJ5YCwgb3IgYC9jcHJvZmlsZWAsIHJlc3BlY3RpdmVseS4gRm9yIGV4YW1wbGUsIGEgdXNlciByZXF1ZXN0aW5nIHZhcmlhYmxlcyBmcm9tIHRoZSAyMDIwIDUteWVhciBBQ1MgRGV0YWlsZWQgVGFibGVzIHdvdWxkIHNwZWNpZnkgYGxvYWRfdmFyaWFibGVzKHllYXIgPSAyMDIwLCBkYXRhc2V0ID0gImFjczUiKWA7IGEgcmVxdWVzdCBmb3IgdmFyaWFibGVzIGZyb20gdGhlIERhdGEgUHJvZmlsZSB0aGVuIHdvdWxkIGJlIGBsb2FkX3ZhcmlhYmxlcyh5ZWFyID0gMjAyMCwgZGF0YXNldCA9ICJhY3M1L3Byb2ZpbGUiKWAuIEluIGFkZGl0aW9uIHRvIHRoZXNlIGRhdGFzZXRzLCB0aGUgQUNTIFN1cHBsZW1lbnRhbCBFc3RpbWF0ZXMgdmFyaWFibGVzIGNhbiBiZSBhY2Nlc3NlZCB3aXRoIHRoZSBkYXRhc2V0IG5hbWUgYCJhY3NzZSJgLgoKQXMgdGhpcyBmdW5jdGlvbiByZXF1aXJlcyBwcm9jZXNzaW5nIHRob3VzYW5kcyBvZiB2YXJpYWJsZXMgZnJvbSB0aGUgQ2Vuc3VzIEJ1cmVhdSB3aGljaCBtYXkgdGFrZSBhIGZldyBtb21lbnRzIGRlcGVuZGluZyBvbiB0aGUgdXNlcidzIGludGVybmV0IGNvbm5lY3Rpb24sIHRoZSB1c2VyIGNhbiBzcGVjaWZ5IGBjYWNoZSA9IFRSVUVgIGluIHRoZSBmdW5jdGlvbiBjYWxsIHRvIHN0b3JlIHRoZSBkYXRhIGluIHRoZSB1c2VyJ3MgY2FjaGUgZGlyZWN0b3J5IGZvciBmdXR1cmUgYWNjZXNzLiBPbiBzdWJzZXF1ZW50IGNhbGxzIG9mIHRoZSBbYGxvYWRfdmFyaWFibGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9sb2FkX3ZhcmlhYmxlcy5odG1sKSBmdW5jdGlvbiwgYGNhY2hlID0gVFJVRWAgd2lsbCBkaXJlY3QgdGhlIGZ1bmN0aW9uIHRvIGxvb2sgaW4gdGhlIGNhY2hlIGRpcmVjdG9yeSBmb3IgdGhlIHZhcmlhYmxlcyByYXRoZXIgdGhhbiB0aGUgQ2Vuc3VzIHdlYnNpdGUuCgpBbiBleGFtcGxlIG9mIGhvdyBbYGxvYWRfdmFyaWFibGVzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9sb2FkX3ZhcmlhYmxlcy5odG1sKSB3b3JrcyBpcyBhcyBmb2xsb3dzOgoKYGBge3J9CnYxNiA8LSBsb2FkX3ZhcmlhYmxlcygyMDE2LCAiYWNzNSIsIGNhY2hlID0gVFJVRSkKYGBgCgpUaGUgcmV0dXJuZWQgZGF0YSBmcmFtZSBhbHdheXMgaGFzIHRocmVlIGNvbHVtbnM6IGBuYW1lYCwgd2hpY2ggcmVmZXJzIHRvIHRoZSBDZW5zdXMgdmFyaWFibGUgSUQ7IGBsYWJlbGAsIHdoaWNoIGlzIGEgZGVzY3JpcHRpdmUgZGF0YSBsYWJlbCBmb3IgdGhlIHZhcmlhYmxlOyBhbmQgYGNvbmNlcHRgLCB3aGljaCByZWZlcnMgdG8gdGhlIHRvcGljIG9mIHRoZSBkYXRhIGFuZCBvZnRlbiBjb3JyZXNwb25kcyB0byBhIHRhYmxlIG9mIENlbnN1cyBkYXRhLiBGb3IgdGhlIDUteWVhciBBQ1MgZGV0YWlsZWQgdGFibGVzLCB0aGUgcmV0dXJuZWQgZGF0YSBmcmFtZSBhbHNvIGluY2x1ZGVzIGEgZm91cnRoIGNvbHVtbiwgYGdlb2dyYXBoeWAsIHdoaWNoIHNwZWNpZmllcyB0aGUgc21hbGxlc3QgZ2VvZ3JhcGh5IGF0IHdoaWNoIGEgZ2l2ZW4gdmFyaWFibGUgaXMgYXZhaWxhYmxlIGZyb20gdGhlIENlbnN1cyBBUEkuIEFzIGlsbHVzdHJhdGVkIGFib3ZlLCB0aGUgZGF0YSBmcmFtZSBjYW4gYmUgZmlsdGVyZWQgdXNpbmcgdGlkeXZlcnNlIHRvb2xzIGZvciB2YXJpYWJsZSBleHBsb3JhdGlvbi4gSG93ZXZlciwgdGhlIFJTdHVkaW8gaW50ZWdyYXRlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCBpbmNsdWRlcyBhbiBpbnRlcmFjdGl2ZSBkYXRhIHZpZXdlciB3aGljaCBpcyBpZGVhbCBmb3IgYnJvd3NpbmcgdGhpcyBkYXRhc2V0LCBhbmQgYWxsb3dzIGZvciBpbnRlcmFjdGl2ZSBzb3J0aW5nIGFuZCBmaWx0ZXJpbmcuIFRoZSBkYXRhIHZpZXdlciBjYW4gYmUgYWNjZXNzZWQgd2l0aCB0aGUgW2BWaWV3KClgXShodHRwczovL3JkcnIuaW8vci91dGlscy9WaWV3Lmh0bWwpIGZ1bmN0aW9uOgoKYGBge3J9ClZpZXcodjE2KQpgYGAKCkJ5IGJyb3dzaW5nIHRoZSB0YWJsZSBpbiB0aGlzIHdheSwgdXNlcnMgY2FuIGlkZW50aWZ5IHRoZSBhcHByb3ByaWF0ZSB2YXJpYWJsZSBJRHMgKGZvdW5kIGluIHRoZSBgbmFtZWAgY29sdW1uKSB0aGF0IGNhbiBiZSBwYXNzZWQgdG8gdGhlIGB2YXJpYWJsZXNgIHBhcmFtZXRlciBpbiBbYGdldF9hY3MoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9hY3MuaHRtbCkgb3IgW2BnZXRfZGVjZW5uaWFsKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfZGVjZW5uaWFsLmh0bWwpLiBVc2VycyBtYXkgbm90ZSB0aGF0IHRoZSByYXcgdmFyaWFibGUgSURzIGluIHRoZSBBQ1MsIGFzIGNvbnN1bWVkIGJ5IHRoZSBBUEksIHJlcXVpcmUgYSBzdWZmaXggb2YgYEVgIG9yIGBNYC4gKip0aWR5Y2Vuc3VzKiogZG9lcyBub3QgcmVxdWlyZSB0aGlzIHN1ZmZpeCwgYXMgaXQgd2lsbCBhdXRvbWF0aWNhbGx5IHJldHVybiBib3RoIHRoZSBlc3RpbWF0ZSBhbmQgbWFyZ2luIG9mIGVycm9yIGZvciBhIGdpdmVuIHJlcXVlc3RlZCB2YXJpYWJsZS4gQWRkaXRpb25hbGx5LCBpZiB1c2VycyBkZXNpcmUgYW4gZW50aXJlIHRhYmxlIG9mIHJlbGF0ZWQgdmFyaWFibGVzIGZyb20gdGhlIEFDUywgdGhlIHVzZXIgc2hvdWxkIHN1cHBseSB0aGUgY2hhcmFjdGVycyBwcmlvciB0byB0aGUgdW5kZXJzY29yZSBmcm9tIGEgdmFyaWFibGUgSUQgdG8gdGhlIGB0YWJsZWAgcGFyYW1ldGVyLgoKSW4gdGhlIG5leHQgc2VjdGlvbiwgd2Ugd2lsbCBkZW1vbnN0cmF0ZSBob3cgdG8gYWNjZXNzIGFuZCBjbGVhbiBDZW5zdXMgRGF0YSB1c2luZyBjb3VudHkgbGV2ZWwgc29jaW9kZW1vZ3JhcGhpYyBkYXRhIGZyb20gVGV4YXMgYXMgYW4gZXhhbXBsZS4KCiMgRXhwbG9yaW5nIENlbnN1cyBkYXRhIHdpdGggdmlzdWFsaXphdGlvbiBpbiBSCgpQYXJ0IG9mIHRoaXMgc2VjdGlvbiB3YXMgZGVyaXZlZCBmcm9tIHRoZSBvbmxpbmUgYm9vayBbQW5hbHl6aW5nIFVTIENlbnN1cyBEYXRhOiBNZXRob2RzLCBNYXBzLCBhbmQgTW9kZWxzIGluIFJdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL2NlbnN1cy1yL2luZGV4Lmh0bWwpIHNlY3Rpb24gMyBhbmQgNC4KClRoaXMgY2hhcHRlciBjb3ZlcnMgd3JhbmdsaW5nIENlbnN1cyBkYXRhIHdpdGggUiBwYWNrYWdlIHRpZHl2ZXJzZSBhbmQgZXhwbG9yaW5nIENlbnN1cyBkYXRhIHdpdGggdmlzdWFsaXphdGlvbi4gV2Ugd2lsbCBkZW1vbnN0cmF0ZSB0aGUgcHJvY2VzcyB1c2luZyBjb3VudHkgbGV2ZWwgc29jaW9kZW1vZ3JhcGhpYyBkYXRhIGZyb20gSGFycmlzIENvdW50eSBhcyBhbiBleGFtcGxlLgoKIyMgRXh0cmFjdGluZyBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IGRhdGEKClRvIGV4dHJhY3Qgc29jaW9kZW1vZnJhcGhpYyBkYXRhIG9mIGludGVyZXN0IGZyb20gMjAxNi0yMDIwIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgNS15ZWFyIGVzdGltYXRlcywgd2UgZmlyc3QgbG9hZCB0aGUgY29kZWJvb2sgd2hpY2ggYWxsb3dzIHVzIHRvIHNlYXJjaCBhbmQgbG9jYXRlIHRoZSB2YXJpYWJsZXMgb2YgaW50ZXJlc3Q6CgpgYGB7cn0KI0NlbnN1cyBBUEkgdG9rZW46IHJlcGxhY2UgIllvdXIgS0VZIiB3aXRoIHlvdXIgcmVxdWVzdGVkIEFQSSB0b2tlbiBoZXJlOiBodHRwczovL2FwaS5jZW5zdXMuZ292L2RhdGEva2V5X3NpZ251cC5odG1sCiNjZW5zdXNfYXBpX2tleSgiWW91ciBLRVkiLCBpbnN0YWxsPSJUUlVFIiwgb3ZlcndyaXRlID0gVFJVRSkKCiNWaWV3IGFsbCB0aGUgcG9zc2libGUgdmFyaWFibGVzIHdlIGNhbiB1c2UgaW4gdGhlIGRhdGFzZXQKYWNzMjAgPC0gbG9hZF92YXJpYWJsZXMoeWVhcj0gMjAyMCwgZGF0YXNldD0iYWNzNS9wcm9maWxlIiwgY2FjaGU9VFJVRSkKCiMgU2VhcmNoIGluIHRoZSBjb2RlYm9vayBwYWdlCiNWaWV3KGFjczIwKQoKYGBgCgpJZiB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBjb3VudHkgbGV2ZWwgc29jaW9kZW1vZ3JhcGhpYyB2YXJpYWJsZXMgKCUgdW5lbXBsb3llZCwgJSBsaXZpbmcgdW5kZXIgcG92ZXJ0eSwgUGVyIGNhcGl0YSBpbmNvbWUgYW5kIGV0Yy4pLCB3ZSBuZWVkIGZpcnN0IGxpc3QgdGhlIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCBieSBzZWFyY2hpbmcgdGhlIGtleXdvcmRzIGluIHRoZSBjb2RlYm9vayBwYWdlIHZpZXdlZCBhYm92ZToKCmBgYHtyfQojVmlldyB0aGEgbG9hZGVkIHZhcmlhYmxlcyBhbmQgZmlsdGVyIHRvIGNob29zZSB0aGUgdmFyaWFibGVzIG9mIGludGVyZXN0IGF0IGNvdW50eSBsZXZlbAp2YXJsaXN0IDwtIGMoIkRQMDVfMDAwMSIsICJEUDAzXzAwODgiLCAiRFAwM18wMDA1UCIsICJEUDAzXzAxMjhQIiwKICAgICAgICAgICAgICJEUDAzXzAwOTlQIiwiRFAwNF8wMDc3UCIsICJEUDAyXzAwNjBQIiwgIkRQMDJfMDA2MVAiLCAKICAgICAgICAgICAgICJEUDA1XzAwNzdQIiwgIkRQMDRfMDA1OFAiLCJEUDAyXzAwNzJQIiwgIkRQMDJfMDExNFAiLAogICAgICAgICAgICAgIkRQMDRfMDA0N1AiKQoKc3Vic2V0KGFjczIwLCBhY3MyMCRuYW1lICVpbiUgdmFybGlzdCkKYGBgCgpgYGB7cn0KCiMgR2V0IDIwMjAgQUNTIGRhdGEgZm9yIGFsbCBUZXhhcyBjb3VudGllcyAKVFhfY291bnR5IDwtIGdldF9hY3MoZ2VvZ3JhcGh5ID0gImNvdW50eSIsIHN0YXRlPSJUWCIsIAogICAgICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZXM9dmFybGlzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgIHllYXI9MjAyMCkgIyNnZW9tZXRyeT1UIHdpbGwgYWxzbyBnaXZlIHlvdSB0aGUgc2hhcGVmaWxlcwpUWF9jb3VudHkKYGBgCgpJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gZ2V0dGluZyBjb3VudHkgbGV2ZWwgZGF0YSBmb3IgYWxsIFVTIHN0YXRlcywgeW91IGNhbiBzZXQgdGhlIGBzdGF0ZWAgcGFyYW1ldGVyIHRvIGBOVUxMYC4KCiMjIFByb2Nlc3MgQ2Vuc3VzIGRhdGEgYW5kIGNyZWF0ZSBzdW1tYXJ5IHN0YXRpc3RpY3MKCldpdGggdGhlIGRhdGEgcmV0cmlldmVkIHVzaW5nIHRpZHljZW5zdXMsIHdlIG5lZWQgcHJvY2VzcyBhbmQgbWFuaXB1bGF0ZSBpdCB0byB0aGUgZGF0YSBmb3JtYXQgd2FudGVkIGZvciBmdXJ0aGVyIGFuYWx5c2lzIGFuZCB2aXN1YWxpemF0aW9ucy4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKI0NsZWFuIHRoZSBkYXRzYWV0ClRYX2NvdW50eV9kdCA8LSBUWF9jb3VudHlbLGMoMSwzLDQpXSAlPiUgIAogIHNwcmVhZChrZXk9InZhcmlhYmxlIiwgdmFsdWU9ImVzdGltYXRlIikgJT4lICMgZnJvbSBsb25nIHRvIHdpZGUgZm9ybWF0CiAgbXV0YXRlKENyb3dkZWRfaG91c2luZz0gMTAwLSBEUDA0XzAwNzdQLCAjRGVmaW5lIHZhcmlhYmxlIGNyb3dkZWQgaG91c2luZwogICAgICAgICBOb19oaWdoX3NjaG9vbD0gRFAwMl8wMDYwUCtEUDAyXzAwNjFQLCNEZWZpbmUgdmFyaWFibGUgTm8gaGlnaCBzY2hvb2wgZGlwbG9tYQogICAgICAgICBSYWNpYWxfbWlub3JpdHkgPSAxMDAgLSBEUDA1XzAwNzdQLCAgI0RlZmluZSB2YXJpYWJsZSBSYWNpYWwgbWlub3JpdHkKICAgICAgICAgKSAlPiUgICAgICAgICAgICAgICAgICAgICAgIAogICNtdXRhdGVfZWFjaChmdW5zKHJlcGxhY2UoLiwgLjwwLCBOQSkpKSAlPiUgICAjUmVwbGFjZSBtaXNzaW5nIHZhbHVlcyB3aXRoIE5BCiAgcmVuYW1lKE5vX3ZlaGljbGU9RFAwNF8wMDU4UCwgVW5lbXBsb3llZD1EUDAzXzAwMDVQLCAgUmVudGVycz1EUDA0XzAwNDdQLCAKICAgICAgICAgUGVyX2NhcGl0YV9pbmNvbWU9RFAwM18wMDg4LCBMaXZpbmdfcG92ZXJ0eT1EUDAzXzAxMjhQLAogICAgICAgICBVbmluc3VyZWQ9RFAwM18wMDk5UCxQb3B1bGF0aW9uPURQMDVfMDAwMSwgRGlzYWJpbGl0eT1EUDAyXzAwNzJQLAogICAgICAgICBMaW1pdGVkX0VuZ2xpc2g9RFAwMl8wMTE0UCkgICNSZW5hbWUgdGhlIHZhcmlhYmxlcyAKCiMgUmV0YWluIHRoZSB2YXJpYWJsZXMgb2YgaW50ZXJlc3QgClRYX2NvdW50eV9kdCA8LSAgZHBseXI6OnNlbGVjdChUWF9jb3VudHlfZHQsIEdFT0lELCBQb3B1bGF0aW9uLCBDcm93ZGVkX2hvdXNpbmcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOb19oaWdoX3NjaG9vbCwgUmVudGVycywgUmFjaWFsX21pbm9yaXR5LCBOb192ZWhpY2xlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVW5lbXBsb3llZCxQZXJfY2FwaXRhX2luY29tZSwgTGl2aW5nX3BvdmVydHksVW5pbnN1cmVkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGlzYWJpbGl0eSwgTGltaXRlZF9FbmdsaXNoKQojb3B0aW9ucyhkaWdpdHM9MykKClRYX2NvdW50eV9kdApgYGAKClRoZSBkYXRhIGNvbnRhaW5zIDI1NCBvYnNlcnZhdGlvbnMgYW5kIDEzIGNvbHVtbnMsIHdpdGggZWFjaCByYXcgY29udGFpbmluZyBkYXRhIGZvciBvbmUgY291bnR5IGluIFRleGFzIGFuZCBlYWNoIGNvbHVtbiByZXByZXNlbnRpbmcgYSB2YXJpYWJsZS4gR0VPSUQgaXMgdGhlIGNvdW50eSBGSVBTLiBFYWNoIG1lYXN1cmUgaXMgaW4gcGVyY2VudGFnZSwgZXhjZXB0IHBlciBjYXBpdGEgaW5jb21lIGluIFVTIGRvbGxhcnMuCgojIyMgU3VtbWFyeSBUYWJsZQoKYHRhYmxlMWAgcGFja2FnZSBpcyB1c2VmdWwgdG8gY3JlYXRlIHN1bW1hcnkgc3RhdGlzdGljcyB0YWJsZTogPGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy90YWJsZTEvdmlnbmV0dGVzL3RhYmxlMS1leGFtcGxlcy5odG1sPgoKYGBge3J9CmxpYnJhcnkodGFibGUxKQoKdGFibGUxKH4gUG9wdWxhdGlvbisgUGVyX2NhcGl0YV9pbmNvbWUgKyBVbmVtcGxveWVkKyBDcm93ZGVkX2hvdXNpbmcrTm9faGlnaF9zY2hvb2wrCiAgICAgICAgIFJlbnRlcnMrUmFjaWFsX21pbm9yaXR5K05vX3ZlaGljbGUrTGl2aW5nX3BvdmVydHkrVW5pbnN1cmVkK0Rpc2FiaWxpdHkrCiAgICAgICAgIExpbWl0ZWRfRW5nbGlzaCwgZGF0YT1UWF9jb3VudHlfZHQpCmBgYAoKIyMjIENvcnJlbGF0aW9uIE1hdHJpeAoKYGBge3J9CmNvciA8LSBjb3IoVFhfY291bnR5X2R0WywyOjEzXSwgbWV0aG9kID0gInBlYXJzb24iLCB1c2UgPSAiY29tcGxldGUub2JzIikKY29yIDwtIGFzLmRhdGEuZnJhbWUocm91bmQoY29yLDIpKQojIHJlbmFtZSB2YXJpYWJsZXMKbmFtZXMgPC0gYygiUG9wdWxhdGlvbiIsICJDcm93ZGVkIGhvdXNpbmciLCJObyBoaWdoIHNjaG9vbCBkaXBsb21hIiwgIlJlbnRlcnMiLCAKICAgICAgICAgICAiUmFjaWFsIG1pbm9yaXR5IiwiTm8gdmVoaWNsZSIsIlVuZW1wbG95bWVudCIsIlBlciBjYXBpdGEgaW5jb21lIiwKICAgICAgICAgICAiTGl2aW5nIGluIHBvdmVydHkiLCAiVW5pbnN1cmVkIiwgIkRpc2FiaWxpdHkiLCAiTGltaXRlZCBFbmdsaXNoIikKbmFtZXMoY29yKSA8LSBuYW1lcwpyb3cubmFtZXMoY29yKSA8LSAgbmFtZXMKI2FkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudHMgJiByZW9yZGVyIG1hdHJpeCB1c2luZyBoaWVyYXJjaGljYWwgY2x1c3RlcmluZwpsaWJyYXJ5KGdnY29ycnBsb3QpCmdnY29ycnBsb3QoY29yLCAgdHlwZSA9ICJsb3dlciIsbGFiID0gVFJVRSwgbGFiX3NpemUgPSAxLjUpCgpgYGAKCiMjIERhdGEgdmlzdWFsaXphdGlvbiB3aXRoIGdncGxvdDIKCkFsdGVybmF0aXZlbHksIHdlIGNhbiByZXF1ZXN0IGRhdGEgaW4gd2lkZSBmb3JtYXQgdXNpbmcgdGlkeWNlbnN1cywgd2hpY2ggd2lsbCBzcHJlYWQgdGhlIGVzdGltYXRlICh2YXJpYWJsZSBuYW1lIGVuZGluZyBpbiAiRSIpIGFuZCBtYXJnaW4gb2YgZXJyb3IgKHZhcmlhYmxlIG5hbWUgZW5kaW5nIGluICJNIikgaW5mb3JtYXRpb24gYWNyb3NzIHRoZSBjb2x1bW5zLgoKYGBge3J9CnR4X3dpZGUgPC0gZ2V0X2FjcygKICBnZW9ncmFwaHkgPSAiY291bnR5IiwKICBzdGF0ZSA9ICJUZXhhcyIsCiAgdmFyaWFibGVzID0gYyhsaXZpbmdfcG92ZXJ0eSA9ICJEUDAzXzAxMjhQIiwgIyByZW5hbWUgdGhlIHZhcmlhYmxlcyAKICAgICAgICAgICAgICAgIHVuZW1wbG95ZWQgPSAiRFAwM18wMDA1UCIsCiAgICAgICAgICAgICAgICBQZXJfY2FwaXRhX2luY29tZT0iRFAwM18wMDg4IiksCiAgb3V0cHV0ID0gIndpZGUiLCAjIHdpZGUgZm9ybWF0IAogIHllYXIgPSAyMDIwCikKdHhfd2lkZQpgYGAKCldlIGNhbiBjcmVhdGUgc29tZSB2aXN1YWxpemF0aW9uIHVzaW5nIGdncGxvdDIgcGFja2FnZSwgc3VjaCBhcyBoaXN0b2dyYW0gb2YgJSBsaXZpbmcgdW5kZXIgcG92ZXJ0eSBhdCBjb3VudHkgbGV2ZWwgaW4gVGV4YXMuCgpgYGB7cn0KZ2dwbG90KHR4X3dpZGUsIGFlcyh4ID0gbGl2aW5nX3BvdmVydHlFKSkgKyAKICBnZW9tX2hpc3RvZ3JhbSgpKwogIGxhYnMoeD0iJSBwZW9wbGUgbGl2aW5nIGluIHBvdmVydHkiLCB5PSJjb3VudCIpCmBgYAoKRXhwbG9yZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gJSBwb3ZlcnR5IGFuZCAlIHVuZW1wbG95ZWQgdXNpbmcgc2NhdHRlciBwbG90OgoKYGBge3J9CmdncGxvdCh0eF93aWRlLCBhZXMoeCA9IGxpdmluZ19wb3ZlcnR5RSwgeSA9IHVuZW1wbG95ZWRFKSkgKyAKICBnZW9tX3BvaW50KCkrCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpKwogIGxhYnMoeD0iJSBwZW9wbGUgbGl2aW5nIGluIHBvdmVydHkiLCB5PSIlIHBlb3BsZSB1bmVtcGxveWVkIikKYGBgCgpUaGUgW2BnZW9tX3Ntb290aCgpYF0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL2dlb21fc21vb3RoLmh0bWwpIGZ1bmN0aW9uIGRyYXdzIGEgZml0dGVkIGxpbmUgcmVwcmVzZW50aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIGNvbHVtbnMgb24gdGhlIHBsb3QuIFRoZSBhcmd1bWVudCBgbWV0aG9kID0gImxtImAgZHJhd3MgYSBzdHJhaWdodCBsaW5lIGJhc2VkIG9uIGEgbGluZWFyIG1vZGVsIGZpdDsgc21vb3RoZWQgcmVsYXRpb25zaGlwcyBjYW4gYmUgdmlzdWFsaXplZCBhcyB3ZWxsIHdpdGggYG1ldGhvZCA9ICJsb2VzcyJgLgoKV2UgY2FuIGFsc28gY3JlYXRlIGEgYmFyIGNoYXJ0IGlkZW50aWZ5aW5nIHRoZSB0b3AgMjAgY291bnRpZXMgaW4gVGV4YXMgd2l0aCB0aGUgaGlnaGVzdCBwZXIgY2FwaXRhIGluY29tZS4KCmBgYHtyfQp0eF93aWRlICU+JQogIG11dGF0ZShDb3VudHkgPSBzdHJfc3BsaXRfZml4ZWQoTkFNRSwgIiwiLCAyKVssMV0pICU+JSAjIHJldGFpbiBvbmx5IGNvdW50eSBuYW1lCiAgYXJyYW5nZShkZXNjKFBlcl9jYXBpdGFfaW5jb21lRSkpICU+JSAjIG9yZGVyIGJ5IHZhcmlhYmxlIAogIHNsaWNlKDE6MjApJT4lICMgdG9wIDIwCiAgZ2dwbG90KGFlcyh5ID0gcmVvcmRlcihDb3VudHksIFBlcl9jYXBpdGFfaW5jb21lRSksIHggPSBQZXJfY2FwaXRhX2luY29tZUUpKSArIAogICNvcmRlciBmcm9tIGhpZ2hlc3QgdG8gbG93ZXN0IAogIGdlb21fY29sKCkrCiAgbGFicyh4PSJQZXIgY2FwaXRhIGluY29tZSwgJCIsIHk9IiIpKwogIGdndGl0bGUoIlRoZSB0b3AgMjAgY291bnRpZXMgaW4gVGV4YXMgd2l0aCB0aGUgaGlnaGVzdCBwZXIgY2FwaXRhIGluY29tZSIpCgpgYGAKCldoaWxlICoqdGlkeWNlbnN1cyoqIGhhcyB0b29scyBhdmFpbGFibGUgZm9yIHdvcmtpbmcgd2l0aCBtYXJnaW5zIG9mIGVycm9yIGluIGEgZGF0YSB3cmFuZ2xpbmcgd29ya2Zsb3csIGl0IGlzIGFsc28gb2Z0ZW4gdXNlZnVsIHRvIHZpc3VhbGl6ZSB0aG9zZSBtYXJnaW5zIG9mIGVycm9yIHRvIGlsbHVzdHJhdGUgdGhlIGRlZ3JlZSBvZiB1bmNlcnRhaW50eSBhcm91bmQgZXN0aW1hdGVzLCBlc3BlY2lhbGx5IHdoZW4gbWFraW5nIGNvbXBhcmlzb25zIGJldHdlZW4gdGhvc2UgZXN0aW1hdGVzLiBCZWxvdyBpcyBhbiBleGFtcGxlIHByZXNlbnRpbmcgdW5jZXJ0YWludHkgYXJvdW5kIGVhY2ggZXN0aW1hdGVzIHVzaW5nIGVycm9yIGJhcnM6CgpgYGB7cn0KdHhfd2lkZSAlPiUKICBtdXRhdGUoQ291bnR5ID0gc3RyX3NwbGl0X2ZpeGVkKE5BTUUsICIsIiwgMilbLDFdKSAlPiUgIyByZXRhaW4gb25seSBjb3VudHkgbmFtZQogIGFycmFuZ2UoZGVzYyhQZXJfY2FwaXRhX2luY29tZUUpKSAlPiUgIyBvcmRlciBieSB2YXJpYWJsZSAKICBzbGljZSgxOjIwKSU+JSAjIHRvcCAyMAogIGdncGxvdChhZXMoeCA9IFBlcl9jYXBpdGFfaW5jb21lRSwgeSA9IHJlb3JkZXIoQ291bnR5LCBQZXJfY2FwaXRhX2luY29tZUUpKSkgKyAKICBnZW9tX2Vycm9yYmFyaChhZXMoeG1pbiA9IFBlcl9jYXBpdGFfaW5jb21lRSAtIFBlcl9jYXBpdGFfaW5jb21lTSwgCiAgICAgICAgICAgICAgICAgICAgIHhtYXggPSBQZXJfY2FwaXRhX2luY29tZUUgKyBQZXJfY2FwaXRhX2luY29tZU0pKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG9yID0gImRhcmtncmVlbiIpICsgCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMi41KSArIAogIGxhYnModGl0bGUgPSAiUGVyIGNhcGl0YSBpbmNvbWUiLCAKICAgICAgIHN1YnRpdGxlID0gIlRvcCAyMCBjb3VudGllcyBpbiBUZXhhcyIsIAogICAgICAgeCA9ICIyMDE2LTIwMjAgQUNTIGVzdGltYXRlIiwgCiAgICAgICB5ID0gIiIpIApgYGAKCiMjIFZpc3VhbGl6aW5nIEFDUyBlc3RpbWF0ZXMgb3ZlciB0aW1lCgpTb21ldGltZXMgd2Ugd2FudCB0byBvYnRhaW4gYSB0aW1lIHNlcmllcyBvZiBBQ1MgZXN0aW1hdGVzIHRvIGV4cGxvcmUgdGVtcG9yYWwgZGVtb2dyYXBoaWMgc2hpZnRzLiBGb3IgYW4gaWxsdXN0cmF0aXZlIGV4YW1wbGUsIHdlJ2xsIG9idGFpbiA1LXllYXIgQUNTIGRhdGEgZnJvbSAyMDEwIHRocm91Z2ggMjAxOSBvbiBtZWRpYW4gaG91c2UgdmFsdWUgZm9yIEhhcnJpcyBDb3VudHkgYW5kIFRyYXZpcyBDb3VudHksIFRleGFzLiBbYG1hcF9kZnIoKWBdKGh0dHBzOi8vcHVycnIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvbWFwLmh0bWwpIGlzIHVzZWQgdG8gaXRlcmF0ZSBvdmVyIGEgbmFtZWQgdmVjdG9yIG9mIHllYXJzLCBjcmVhdGluZyBhIHRpbWUtc2VyaWVzIGRhdGFzZXQgb2YgbWVkaWFuIGhvbWUgdmFsdWUgaW4gSGFycmlzIGFuZCBUcmF2aXMgQ291bnR5IHNpbmNlIDIwMTAsIGFuZCB3ZSB1c2UgdGhlIGZvcm11bGEgc3BlY2lmaWNhdGlvbiBmb3IgYW5vbnltb3VzIGZ1bmN0aW9ucyBzbyB0aGF0IGB+IC54YCB0cmFuc2xhdGVzIHRvIGBmdW5jdGlvbih4KSB4YC4KCmBgYHtyIG1lc3NhZ2U9Rn0KbXlfdmFycyA8LSBjKAogICJCMjUwNzdfMDAxIgopICMgbGlzdCB0aGUgdmFpcmFibGVzIG9mIGludGVyZXN0IChtZWRpYW4gaG91c2UgdmFsdWUpCgp5ZWFycyA8LSAyMDEwOjIwMTkgIyB5ZWFyCm5hbWVzKHllYXJzKSA8LSB5ZWFycwoKY291bnR5X21odl90eCA8LSBtYXBfZGZyKAogIHllYXJzLAogIH4gZ2V0X2FjcygKICAgIGdlb2dyYXBoeSA9ICJjb3VudHkiLAogICAgc3RhdGU9IlRleGFzIiwKICAgIHZhcmlhYmxlcyA9IG15X3ZhcnMsCiAgICB5ZWFyID0gLngsCiAgICBzdXJ2ZXkgPSAiYWNzNSIsCiAgICBnZW9tZXRyeSA9IEZBTFNFCiAgKSwKICAuaWQgPSAieWVhciIgICMgd2hlbiBjb21iaW5pbmcgcmVzdWx0cywgYWRkIGlkIHZhciAobmFtZSBvZiBsaXN0IGl0ZW0pCikgJT4lCiAgYXJyYW5nZSh2YXJpYWJsZSwgTkFNRSkgJT4lCiAgcmVuYW1lKHZhbHVlPWVzdGltYXRlKSAlPiUKICBzZWxlY3QoLXZhcmlhYmxlKSAlPiUKICBtdXRhdGUoeWVhcj1hcy5udW1lcmljKHllYXIpKQoKY291bnR5X21odl90eApgYGAKCkFyZ3VhYmx5IHRoZSBtb3N0IGNvbW1vbiBjaGFydCB0eXBlIGNob3NlbiBmb3IgdGltZS1zZXJpZXMgdmlzdWFsaXphdGlvbiBpcyB0aGUgbGluZSBjaGFydCwgd2hpY2ggKipnZ3Bsb3QyKiogaGFuZGxlcyBjYXBhYmx5IHdpdGggdGhlIFtgZ2VvbV9saW5lKClgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9wYXRoLmh0bWwpIGZ1bmN0aW9uLiBIZXJlIHdlIGNvbXBhcmUgdGhlIHRlbXBvcmFsIHRyZW5kIG9mIG1lZGlhbiBob3VzZSB2YWx1ZSBpbiBIYXJyaXMgYW5kIFRyYXZpcyBDb3VudHkgb3ZlciB0aW1lICgyMDEwLTIwMTkpOgoKYGBge3J9CmNvbXBhcmUgPC0gc3Vic2V0KGNvdW50eV9taHZfdHgsIGNvdW50eV9taHZfdHgkTkFNRSAlaW4lIAogICAgICAgICAgICAgICAgICAgIGMoIkhhcnJpcyBDb3VudHksIFRleGFzIiwgIlRyYXZpcyBDb3VudHksIFRleGFzIikpCgpnZ3Bsb3QoY29tcGFyZSwgYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGNvbG9yPU5BTUUpKSArIAogIGdlb21fbGluZSgpICsgCiAgZ2VvbV9wb2ludCgpKwogIGxhYnModGl0bGUgPSAiTWVkaWFuIGhvbWUgdmFsdWUgaW4gSGFycmlzIGFuZCBUcmF2aXMgQ291bnR5LCBUWCIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJBQ1MgZXN0aW1hdGUiLAogICAgICAgY2FwdGlvbiA9ICIyMDE2LTIwMjAgQUNTIDUteWVhciBlc3RpbWF0ZSIsCiAgICAgICBjb2xvcj0iQ291bnR5IikrCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMikgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygyMDEwOjIwMTkpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpsYWJlbF9kb2xsYXIoc2NhbGUgPSAuMDAxLCBzdWZmaXggPSAiayIpKSAKICAKICAKYGBgCgojIEludHJvZHVjdGlvbiB0byB0aWdyaXMKCiMjIERvd25sb2FkIFRJR0VSL0xpbmUgU2hhcGZpbGVzIE1hbnVhbGx5CgpJZiB5b3UgcHJlZmVyIHRvIGRvd25sb2FkIHRoZSBzaGFwZWZpbGVzIHVzaW5nIHRoZSBbd2ViIGludGVyZmFjZV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9nZW9ncmFwaGllcy9tYXBwaW5nLWZpbGVzL3RpbWUtc2VyaWVzL2dlby90aWdlci1saW5lLWZpbGUuaHRtbCksIHlvdSBjYW4gbmF2aWdhdGUgYW5kIGRvd25sb2FkIHNoYXBlZmlsZXMgYnkgc3BlY2lmeWluZyB0aGUgeWVhciBhbmQgZ2VvZ3JhcGhpYyBsZXZlbCBvbiB0aGUgd2Vic2l0ZS4gQnkgc2F2aW5nIHRoZSBzaGFwZWZpbGUgaW4geW91ciBsb2NhbCBmb2xkZXIgdW5kZXIgdGhlIHdvcmtpbmcgZGlyZWN0b3J5LCBwYWNrYWdlIGByZ2RhbGAgb3IgYHNmYCBjYW4gYmUgdXNlZCB1c2VkIHRvIHJlYWQgYW5kIG9wZW4gdGhlIHNoYXBlZmlsZXMgaW4gUi4gSW4gdGhpcyBleGFtcGxlLCB0aGUgMjAyMCBUZXhhcyBjb3VudHkgbGV2ZWwgc2hhcGVmaWxlIHdhcyBkb3dubG9hZGVkOgoKYGBge3IgbWVzc2FnZT1GfQojIHVzaW5nIHJnZGFsCmxpYnJhcnkocmdkYWwpCiMgaW5kaWNhdGUgZHNuIChkYXRhIHNvdXJjZSwgZm9sZGVyIG5hbWUpIGFuZCBsYXllciBuYW1lClRYX0NvdW50eSA8LSByZWFkT0dSKGRzbiA9ICJUWF9jb3VudHkiLGxheWVyID0gICJUWF9jb3VudHkiLCB2ZXJib3NlPUYpCmNsYXNzKFRYX0NvdW50eSkKYGBgCgpOb3RlIHRoYXQgdGhlIHJldHVybmVkIG9iamVjdCBpcyBhICJTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWUiLCB3aGljaCBjb25zaXN0cyBvZiBkYXRhIGNvbHVtbnMgb24gY2hhcmFjdGVyaXN0aWNzIG9mIHRoZSBjb3VudGllcywgYW5kIHNwYXRpYWwgcG9seWdvbnMsIHdoaWNoIGNvbnRhaW5zIGEgc2V0IG9mIHNwYXRpYWxseSBleHBsaWNpdCBzaGFwZXMvcG9seWdvbnMgdGhhdCByZXByZXNlbnQgdGhlIGdlb2dyYXBoaWMgbG9jYXRpb25zIG9mIHRoZSBjb3VudGllcy4KCmBgYHtyIG1lc3NhZ2U9Rn0KaGVhZChUWF9Db3VudHlAZGF0YSwxMCkKYGBgCgpPciB5b3UgY2FuIHVzZSBgcmVhZF9zZmAgZnJvbSB0aGUgYHNmYCBwYWNrYWdlLCB3aGljaCB3aWxsIHJldHVybiBhIHNmIG9iamVjdC4KCmBgYHtyfQpsaWJyYXJ5KHNmKQpUWF9Db3VudHkxIDwtIHJlYWRfc2YoJ1RYX2NvdW50eS9UWF9jb3VudHkuc2hwJykKY2xhc3MoVFhfQ291bnR5MSkKaGVhZChUWF9Db3VudHkxKQpgYGAKClRoZSBgc2ZgIG9iamVjdCBpbmNsdWRlcyBhIGRhdGEgZnJhbWUgd2l0aCBhIHNlcmllcyBvZiBjb2x1bW5zIHJlcHJlc2VudGluZyBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhvc2Ugc3RhdGVzLCBsaWtlIGEgbmFtZSwgcG9zdGFsIGNvZGUsIGFuZCBDZW5zdXMgSUQgKHRoZSBgR0VPSURgIGNvbHVtbikuIEl0IGFsc28gY29udGFpbnMgYSBzcGVjaWFsIGxpc3QtY29sdW1uLCBgZ2VvbWV0cnlgLCB3aGljaCBpcyBtYWRlIHVwIG9mIGEgc2VxdWVuY2Ugb2YgY29vcmRpbmF0ZSBvZiBsb25naXR1ZGUvbGF0aXR1ZGUgY29vcmRpbmF0ZSBwYWlycyB0aGF0IGNvbGxlY3RpdmVseSByZXByZXNlbnQgdGhlIGJvdW5kYXJ5IG9mIGVhY2ggc3RhdGUuCgpZb3UgY2FuIGVhc2lseSBjb252ZXJ0IGBzZmAgb2JqZWN0IHRvIGBTcGF0aWFsUG9seWdvbkRhdGFGcmFtZWAgYXMgZm9sbG93aW5nOgoKYGBge3J9CiMgVFhfQ291bnR5IDwtIGFzKFRYX0NvdW50eTEsICJTcGF0aWFsIikKYGBgCgojIyBEb3dubG9hZCBTaGFwZWZpbGVzIHVzaW5nIFIgUGFja2FnZSB0aWdyaXMKClRoZSAqKnRpZ3JpcyoqIFIgcGFja2FnZSBzaW1wbGlmaWVzIHRoZSBwcm9jZXNzIGZvciBSIHVzZXJzIG9mIG9idGFpbmluZyBhbmQgdXNpbmcgQ2Vuc3VzIGdlb2dyYXBoaWMgZGF0YXNldHMuIEZ1bmN0aW9ucyBpbiAqKnRpZ3JpcyoqICpkb3dubG9hZCogYSByZXF1ZXN0ZWQgQ2Vuc3VzIGdlb2dyYXBoaWMgZGF0YXNldCBmcm9tIHRoZSBVUyBDZW5zdXMgQnVyZWF1IHdlYnNpdGUsIHRoZW4gKmxvYWQqIHRoZSBkYXRhc2V0IGludG8gUiBhcyBhIHNwYXRpYWwgb2JqZWN0LgoKWW91IGNhbiBkb3dubG9hZCBzaGFwZWZpbGVzIGF0IGRpZmZlcmVudCBnZW9ncmFwaGljYWwgbGV2ZWxzLiBGb3IgZXhhbXBsZSwgdXNlICoqc3RhdGVzKCkqKiBmdW5jdGlvbiB0byByZXRyaWV2ZSBzdGF0ZS1sZXZlbCBzaGFwZWZpbGUsICoqY291bnRpZXMoKSoqIGZvciBjb3VudHktbGV2ZWwsIGFuZCAqKnRyYWN0cygpKiogZm9yIGNlbnN1cy10cmFjdCBsZXZlbC4KCldoZW4geW91IGNhbGwgYSB0aWdyaXMgZnVuY3Rpb24sIGl0IGRvZXMgdGhlIGZvbGxvd2luZzoKCi0gICBEb3dubG9hZHMgeW91ciBkYXRhIGZyb20gdGhlIFVTIENlbnN1cyBCdXJlYXUgd2Vic2l0ZQoKLSAgIFN0b3JlcyB5b3VyIGRhdGEgaW4gYSB1c2VyIGNhY2hlIGRpcmVjdG9yeSBvciBpbiBhIHRlbXBvcmFyeSBkaXJlY3RvcnkKCi0gICBMb2FkcyB5b3VyIGRhdGEgaW50byBSIHNlc3Npb24gd2l0aCByZ2RhbDo6cmVhZE9HUigpIG9yIHNmOjpzdF9yZWFkKCkKCnNlZSBbcmVmZXJlbmNlXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWdyaXMtd2ViaW5hci8jMzApIGhlcmUuCgojIyMgRXhhbXBsZSAxOiBHZXQgVGV4YXMgQ291bnR5LWxldmVsIHNoYXBlZmlsZQoKJ3N0YXRlJyBhcmd1bWVudCBjYW4gYmUgYSB0d28tZGlnaXQgRklQUyBjb2RlIG9mIGEgc3BlY2lmaWMgc3RhdGUgb3Igc3RhdGUgbmFtZSBhYmJyZXZpYXRpb24sIGZvciBleGFtcGxlLCA0OCBzdGFuZHMgZm9yIFRleGFzLgoKYGBge3J9CmxpYnJhcnkodGlncmlzKQpvcHRpb25zKHRpZ3Jpc191c2VfY2FjaGU9VFJVRSkgI2NhY2hlIENlbnN1cyBzaGFwZWZpbGUgZG93bmxvYWRzCnR4Y291bnR5IDwtIGNvdW50aWVzKHN0YXRlPTQ4LCBjYj1UUlVFLCB5ZWFyPTIwMjApCgpgYGAKCmBgYHtyIGVjaG89Rn0KbGlicmFyeSh0bWFwKQp0bV9zaGFwZSh0eGNvdW50eSkgKyB0bV9wb2x5Z29ucygpCmBgYAoKTm90aWNlIHRoZSBhcmd1bWVudCAqKmNiPVRSVUUqKi4gSXQgaGVscHMgdG8gcmV0dXJuIFtDYXJ0b2dyYXBoaWMgQm91bmRhcnkgRmlsZXNdKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L2dlby90aWdlci9HRU5aMjAxOS9zaHAvKSwgd2hpY2ggaGFzIGxlc3MgZGV0YWlscyB0aGFuIFtUSUdFUi9MaW5lIFNoYXBlZmlsZXNdKGh0dHBzOi8vd3d3Mi5jZW5zdXMuZ292L2dlby90aWdlci9USUdFUjIwMTkvVFJBQ1QvKS4gKERldGFpbCBkZXNjcmlwdGlvbnMgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3d3dzIuY2Vuc3VzLmdvdi9nZW8vdGlnZXIvRGlyZWN0b3J5X0NvbnRlbnRzX1JlYWRNZS5wZGYpLikKCkxldCdzIHNlZSBhIGNvbXBhcmlzb24gZm9yIFRleGFzLCB3aGVyZSBCbGFjayBsaW5lcyBhcmUgVElHRVIvTGluZSBmaWxlIGFuZCBSZWQgbGluZXMgYXJlIENhcnRvZ3JhcGhpYyBCb3VuZGFyeS4KCmBgYHtyIGVjaG89Rn0KdHhjb3VudHkwIDwtIGNvdW50aWVzKHN0YXRlPTQ4LCBjYj1GQUxTRSwgeWVhcj0yMDIwKQpsaWJyYXJ5KGdncGxvdDIpCmdnIDwtIGdncGxvdCgpICsgCiAgZ2VvbV9zZihkYXRhID0gdHhjb3VudHkwLCBhZXMoY29sb3I9ImJsYWNrIikpICsgIyBUSUdFUi9MaW5lCiAgZ2VvbV9zZihkYXRhID0gdHhjb3VudHksIGFlcyhjb2xvcj0icmVkIikpICsgIyBDYXJ0b2dyYXBoaWMgQm91bmRhcnkKICBzY2FsZV9jb2xvdXJfbWFudWFsKG5hbWUgPSAiRmlsZSIsIHZhbHVlcyA9YygiYmxhY2siPSJibGFjayIsInJlZCI9InJlZCIpLCBsYWJlbHMgPSBjKCJUSUdFUi9MaW5lIiwiQ0IiKSkKZ2cKYGBgCgojIyMgRXhhbXBsZSAyOiBDZW5zdXMgdHJhY3Qgc2hhcGVmaWxlIGZvciBvbmUgY291bnR5CgpXaXRoICoqdHJhY3RzKCkqKiBmdW5jdGlvbiwgeW91IGNhbiByZXRyaWV2ZSBjZW5zdXMgdHJhY3Qgc2hhcGVmaWxlIGZvciBhIHNwZWNpZmljIGNvdW50eSwgaGVyZSdzIGFuIGV4YW1wbGUgb2YgSGFycmlzIGNvdW50eSBpbiBUZXhhcywgKE5vdGU6IHlvdSBtYXkgYWN0dWFsbHkgd2FudCB0byB1c2UgRklQUyBjb2RlIGluc3RlYWQgb2YgY291bnR5IG5hbWUgdG8gYWNjdXJhdGVseSBmaW5kIHRoZSBkYXRhIHlvdSBuZWVkLiBGb3IgaW5zdGFuY2UsICJIYXJyaXMiIHdpbGwgbWF0Y2ggYm90aCAiSGFycmlzIENvdW50eSIgYW5kICJIYXJyaXNvbiBDb3VudHkiLCB3aGljaCBjYXVzZXMgY29uZnVzaW9uIHRoYXQgZW5kIHVwIHJldHVybmluZyBlbXB0eSBkYXRhLikKCmBgYHtyfQpoYXJyaXN0cmFjdHMgPC0gdHJhY3RzKHN0YXRlPTQ4LCBjb3VudHkgPSAiSGFycmlzIENvdW50eSIsIGNiPVQsIHllYXI9MjAyMCkKIyBWaWV3IHRoZSBwb2x5Z29ucyB1c2luZyBwYWNrYWdlIHRtYXAKdG1fc2hhcGUoaGFycmlzdHJhY3RzKSArIHRtX3BvbHlnb25zKCkKYGBgCgojIyMgRXhhbXBsZSAzOiBTaGFwZWZpbGVzIGZvciBtdWx0aXBsZSBzdGF0ZXMKClRvIHJldHJpZXZlIGNvdW50eS1sZXZlbCBzaGFwZWZpbGVzLCB5b3UgY2FuIHNwZWNpZnkgYSB2ZWN0b3Igb2YgRklQUyBjb2RlIGluICoqc3RhdGUqKiBhcmd1bWVudC4gRm9yIGV4YW1wbGUsIDE3PUlsbGlub2lzLCAyNj1NaWNoaWdhbiwgNTU9V2lzY29uc2luLgoKYGBge3J9Cm11bHRpX3N0X2NvdW50eSA8LSBjb3VudGllcyhzdGF0ZT1jKDE3LDI2LDU1KSwgY2I9VFJVRSwgeWVhcj0yMDIwKQp0bV9zaGFwZShtdWx0aV9zdF9jb3VudHkpICsgdG1fcG9seWdvbnMoKQpgYGAKCkhvd2V2ZXIsIHNpbmNlIGNlbnN1cyB0cmFjdHMgc2hhcGVmaWxlcyBhcmUgb25seSBhdmFpbGFibGUgYXQgc3RhdGUtbGV2ZWwsIGl0IGlzIG5vdCBhcHBsaWNhYmxlIHdpdGggYSB2ZWN0b3Igb2YgRklQUyBjb2RlIGRpcmVjdGx5IHB1dCBpbnRvIHRoZSBmdW5jdGlvbi4gSW5zdGVhZCwgeW91IGNhbiBhcHBseSBgcmluZF90aWdyaXMoKWAgZnVuY3Rpb24gdG8gY29tYmluZSBtdWx0aXBsZSB0cmFjdHMgZmlsZXMuCgpgYGB7cn0Kc3RzIDwtIGMoMTcsMjYsNTUpCmNvbWJpbmVkIDwtIHJiaW5kX3RpZ3JpcygKICBsYXBwbHkoc3RzLCBmdW5jdGlvbih4KXsKICAgIHRyYWN0cyh4LCBjYj1UUlVFKQogIH0pCikKdG1fc2hhcGUoY29tYmluZWQpICsgdG1fcG9seWdvbnMoKQpgYGAKCiMjIyBFeGFtcGxlIDQ6IENlbnN1cyB0cmFjdHMgZm9yIHRoZSBlbnRpcmUgVVMKCkl0IGlzIHN0cmFpZ2h0Zm9yd2FyZCB0byBnZXQgdHJhY3RzIGZpbGUgZm9yIHRoZSBlbnRpcmUgVVMsIHlvdSBjYW4gc2ltcGx5IHNwZWNpZnkgTlVMTCBpbiAqKnN0YXRlKiogYW5kICoqY291bnR5KiogYXJndW1lbnRzLAoKYGBge3J9CnVzdHJhY3QgPC0gdHJhY3RzKHN0YXRlID0gTlVMTCwgY291bnR5ID0gTlVMTCwgY2IgPSBUUlVFLCB5ZWFyID0gMjAxOSkKdG1fc2hhcGUodXN0cmFjdCkgKyB0bV9wb2x5Z29ucygpCmBgYAoKIyMjIEV4YW1wbGUgNTogU2hpZnRpbmcgYW5kIHJlc2NhbGluZyBnZW9tZXRyeSBmb3IgbmF0aW9uYWwgVVMgbWFwcGluZwoKQSBjb21tb24gcHJvYmxlbSBmb3IgbmF0aW9uYWwgZGlzcGxheSBvZiB0aGUgVW5pdGVkIFN0YXRlcyBpcyB0aGUgZnJhZ21lbnRlZCBuYXR1cmUgb2YgVVMgc3RhdGVzIGFuZCB0ZXJyaXRvcmllcyBnZW9ncmFwaGljYWxseS4gVGhlIGNvbnRpbmVudGFsIFVuaXRlZCBTdGF0ZXMgY2FuIGJlIGRpc3BsYXllZCBvbiBhIG1hcCBpbiBhIHJlbGF0aXZlbHkgc3RyYWlnaHRmb3J3YXJkIHdheSwgYW5kIHRoZXJlIGFyZSBhIG51bWJlciBvZiBwcm9qZWN0ZWQgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtcyBkZXNpZ25lZCBmb3IgY29ycmVjdCBkaXNwbGF5IG9mIHRoZSBjb250aW5lbnRhbCBVUy4gT2Z0ZW4sIGFuYWx5c3RzIGFuZCBjYXJ0b2dyYXBoZXJzIHRoZW4gaGF2ZSB0byBtYWtlIGRlY2lzaW9ucyBhYm91dCBob3cgdG8gaGFuZGxlIEFsYXNrYSwgSGF3YWlpLCBhbmQgUHVlcnRvIFJpY28sIHdoaWNoIGNhbm5vdCBiZSByZWFzb25hYmx5IHBsb3R0ZWQgdXNpbmcgZGVmYXVsdCBVUyBwcm9qZWN0aW9ucy4KCioqdGlncmlzKiogb2ZmZXJzIGEgc29sdXRpb24gdG8gdGhpcyBwcm9ibGVtIHdpdGggdGhlIFtgc2hpZnRfZ2VvbWV0cnkoKWBdKGh0dHBzOi8vcmRyci5pby9wa2cvdGlncmlzL21hbi9zaGlmdF9nZW9tZXRyeS5odG1sKSBmdW5jdGlvbi4gW2BzaGlmdF9nZW9tZXRyeSgpYF0oaHR0cHM6Ly9yZHJyLmlvL3BrZy90aWdyaXMvbWFuL3NoaWZ0X2dlb21ldHJ5Lmh0bWwpIHRha2VzIGFuIG9waW5pb25hdGVkIGFwcHJvYWNoIHRvIHRoZSBzaGlmdGluZyBhbmQgcmVzY2FsaW5nIG9mIEFsYXNrYSwgSGF3YWlpLCBhbmQgUHVlcnRvIFJpY28gZ2VvbWV0cmllcyB0byBvZmZlciBmb3VyIG9wdGlvbnMgZm9yIGFuIGFsdGVybmF0aXZlIHZpZXcgb2YgdGhlIFVTLiBUaGUgZnVuY3Rpb24gd29ya3MgYnkgcHJvamVjdGluZyBnZW9tZXRyaWVzIGluIEFsYXNrYSwgSGF3YWlpLCBhbmQgUHVlcnRvIFJpY28gdG8gYXBwcm9wcmlhdGUgY29vcmRpbmF0ZSByZWZlcmVuY2Ugc3lzdGVtcyBmb3IgdGhvc2UgYXJlYXMsIHRoZW4gcmUtc2l6aW5nIHRoZSBnZW9tZXRyaWVzIChpZiByZXF1ZXN0ZWQpIGFuZCBtb3ZpbmcgdGhlbSB0byBhbiBhbHRlcm5hdGl2ZSBsYXlvdXQgaW4gcmVsYXRpb25zaGlwIHRvIHRoZSByZXN0IG9mIHRoZSBVUyB1c2luZyB0aGUgQWxiZXJzIEVxdWFsIEFyZWEgQ1JTLgoKYGBge3J9CnVzX3N0YXRlcyA8LSBzdGF0ZXMoY2IgPSBUUlVFLCByZXNvbHV0aW9uID0gIjIwbSIpCnVzX3N0YXRlc19zaGlmdGVkIDwtIHNoaWZ0X2dlb21ldHJ5KHVzX3N0YXRlcykKCnRtX3NoYXBlKHVzX3N0YXRlc19zaGlmdGVkKSt0bV9wb2x5Z29ucygpCgpgYGAKClRoaXMgdmlldyB1c2VzIHR3byBkZWZhdWx0IGFyZ3VtZW50czogYHByZXNlcnZlX2FyZWEgPSBGQUxTRWAsIHdoaWNoIHNocmlua3MgQWxhc2thIGFuZCBpbmZsYXRlcyBIYXdhaWkgYW5kIFB1ZXJ0byBSaWNvLCBhbmQgYHBvc2l0aW9uID0gImJlbG93ImAsIHdoaWNoIHBsYWNlcyB0aGVzZSBhcmVhcyBiZWxvdyB0aGUgY29udGluZW50YWwgVW5pdGVkIFN0YXRlcy4gQWx0ZXJuYXRpdmVseSwgd2UgY2FuIHNldCBgcHJlc2VydmVfYXJlYSA9IFRSVUVgIGFuZCBgcG9zaXRpb24gPSAib3V0c2lkZSJgICh1c2VkIHRvZ2V0aGVyIGJlbG93LCBidXQgdGhleSBjYW4gYmUgbWl4ZWQgYW5kIG1hdGNoZWQpIGZvciBhIGRpZmZlcmVudCB2aWV3OgoKYGBge3J9CnVzX3N0YXRlc19vdXRzaWRlIDwtIHNoaWZ0X2dlb21ldHJ5KHVzX3N0YXRlcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZXNlcnZlX2FyZWEgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJvdXRzaWRlIikKCnRtX3NoYXBlKHVzX3N0YXRlc19vdXRzaWRlKSt0bV9wb2x5Z29ucygpCgpgYGAKCiMgTWFwcGluZyBDZW5zdXMgZGF0YSBpbiBSCgojIyBHZXQgZGF0YSByZWFkeSBmb3IgbWFwcGluZwoKIyMjIE1lcmdpbmcgZGF0YSB3aXRoIHNoYXBlZmlsZXMKCkJlZm9yZSBjcmVhdGluZyBtYXBzIGluIFIsIHdlIG5lZWQgdG8gbWVyZ2UgdGhlIGRhdGEgb2YgaW50ZXJlc3QgKGluIHRoaXMgY2FzZSwgbm90IGNlbnN1cyBkYXRhKSB3aXRoIHNoYXBlZmlsZXMuIFRoZSBmb2xsb3dpbmcgZXhhbXBsZSB1c2VkIHRoZSBUZXhhcyBjb3VudHkgbGV2ZWwgQ09WSUQtMTkgY2FzZXMgZGF0YSBmcm9tIHRoZSBbRGVwYXJ0bWVudCBvZiBIZWFsdGggYW5kIEh1bWFuIFNlcnZpY2VzIHdlYnNpdGUuXShodHRwczovL3d3dy5kc2hzLnRleGFzLmdvdi9jb3ZpZC0xOS1jb3JvbmF2aXJ1cy1kaXNlYXNlLTIwMTkvdGV4YXMtY292aWQtMTktZGF0YSkKCmBgYHtyfQojIHJlYWQgaW4gZGF0YQpsaWJyYXJ5KHJlYWR4bCkKY2FzZXMgPC0gcmVhZF9leGNlbCgiVGV4YXMgQ09WSUQtMTkgQ3VtdWxhdGl2ZSBDb25maXJtZWQgQ2FzZXMgYnkgQ291bnR5Lnhsc3giLAogICAgICAgICAgICAgICAgICAgIHNoZWV0PSJDYXNlcyBieSBDb3VudHkgMjAyMyIsCiAgICAgICAgICAgICAgICAgICAgc2tpcD0yKVsxOjI1NCwxOjJdICMgY3VtdWxhdGl2ZSBjYXNlcyBieSAxLzEvMjAyMwpjb2xuYW1lcyhjYXNlcykgPC0gYygiQ291bnR5IiwgIkZyZXEiKQpoZWFkKGNhc2VzKQoKYGBgCgpgYGB7cn0KbGlicmFyeShkcGx5cikKIyBNZXJnZSB3aXRoIFNwYXRpYWxQb2x5Z29uRGF0YUZyYW1lCiNtZXJnZSBieSBjb3VudHkgbmFtZQpUWF9Db3VudHlAZGF0YSA8LSBsZWZ0X2pvaW4oVFhfQ291bnR5QGRhdGEsIGNhc2VzLCBieT1jKCJOQU1FIj0iQ291bnR5IikpCgojIE1lcmdlIHdpdGggc2Ygb2JqZWN0ClRYX0NvdW50eTEgPC0gbGVmdF9qb2luKFRYX0NvdW50eTEsIGNhc2VzLGJ5PWMoIk5BTUUiPSJDb3VudHkiKSkKYGBgCgpJZiB5b3UgaGF2ZSBpbmRpdmlkdWFsIGxldmVsIGFkZHJlc3MgZGF0YSwgYW5kIHdvdWxkIGxpa2UgdG8gb2J0YWluIGNlbnN1cyBpbmZvcm1hdGlvbiBmcm9tIGFkZHJlc3MsIHlvdSBuZWVkIHRvIGZpcnN0IGdlb2NvZGUgdGhlIGFkZHJlc3M6IDxodHRwczovL2dlb2NvZGluZy5nZW8uY2Vuc3VzLmdvdi9nZW9jb2Rlci8+CgojIyMgQmFzaWMgTWFwcGluZyBpbiBSCgpgYGB7cn0KIyBNYXAgdGhlIG51bWJlciBvZiBjYXNlcyBhdCBjb3VudHkgbGV2ZWwKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoY2xhc3NJbnQpCmxpYnJhcnkobWFwdG9vbHMpCiMjIyBzZWxlY3QgdmFyaWFibGUgdG8gcGxvdApwbG90dmFyIDwtIFRYX0NvdW50eUBkYXRhJEZyZXEgIyMjIHZhcmlhYmxlIHRvIHBsb3QKIyBzcGVjaWZ5IGJyZWFrcwpuY2xyIDwtIDUgCmJya3MgPC0gcm91bmQocXVhbnRpbGUocGxvdHZhciwgcHJvYnM9c2VxKDAsMSwxLyhuY2xyKSkpLCBkaWdpdHM9MSkKY29sb3JudW0gPC0gZmluZEludGVydmFsKHBsb3R2YXIsYnJrcyxhbGwuaW5zaWRlPVQpCnBsb3RjbHIgPC0gYnJld2VyLnBhbChuY2xyLCJCdVB1IikgIyB5b3UgY2FuIGNob29zZSBkaWZmZXJlbnQgY29sb3JzIHNjaGVtZXMgCmNvbGNvZGUgPC0gcGxvdGNscltjb2xvcm51bV0KCiMjIyBtYWtlIHRoZSBtYXAKcGxvdChUWF9Db3VudHksIGNvbD1jb2xjb2RlLCBheGU9VCkKbGVnZW5kKCJib3R0b21sZWZ0IixsZWdlbmQ9bGVnbGFicyhyb3VuZChicmtzLGRpZ2l0cz0xKSksZmlsbD1wbG90Y2xyLGNleD0wLjgsYnR5PSJuIikKdGl0bGUoIk51bWJlciBvZiBjdW11bGF0aXZlIENPVklELTE5IGNhc2VzIGF0IGNvdW50eSBsZXZlbCBcbmluIFRleGFzLCBhcyBvZiBKYW4gMSwgMjAyMyIpCmBgYAoKIyMjIFVzaW5nIGdlb21ldHJ5IGluIHRpZHljZW5zdXMKCkFzIGNvdmVyZWQgaW4gdGhlIHByZXZpb3VzIHNlY3Rpb24sIENlbnN1cyBnZW9ncmFwaGllcyBhcmUgYXZhaWxhYmxlIGZyb20gdGhlICoqdGlncmlzKiogUiBwYWNrYWdlIGFzIHNpbXBsZSBmZWF0dXJlcyBvYmplY3RzLCB1c2luZyB0aGUgZGF0YSBtb2RlbCBmcm9tIHRoZSAqKnNmKiogUiBwYWNrYWdlLiB0aWR5Y2Vuc3VzIHdyYXBzIHNldmVyYWwgY29tbW9uIGdlb2dyYXBoaWMgZGF0YSBmdW5jdGlvbnMgaW4gdGhlICoqdGlncmlzKiogcGFja2FnZSB0byBhbGxvdyBSIHVzZXJzIHRvIHJldHVybiBzaW1wbGUgZmVhdHVyZSBnZW9tZXRyeSBwcmUtbGlua2VkIHRvIGRvd25sb2FkZWQgZGVtb2dyYXBoaWMgZGF0YSB3aXRoIGEgc2luZ2xlIGZ1bmN0aW9uIGNhbGwuIFRoZSBrZXkgYXJndW1lbnQgdG8gYWNjb21wbGlzaCB0aGlzIGlzIGBnZW9tZXRyeSA9IFRSVUVgLCB3aGljaCBpcyBhdmFpbGFibGUgaW4gdGhlIGNvcmUgZGF0YSBkb3dubG9hZCBmdW5jdGlvbnMgaW4gdGlkeWNlbnN1cywgW2BnZXRfYWNzKClgXShodHRwczovL3dhbGtlci1kYXRhLmNvbS90aWR5Y2Vuc3VzL3JlZmVyZW5jZS9nZXRfYWNzLmh0bWwpLCBbYGdldF9kZWNlbm5pYWwoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9kZWNlbm5pYWwuaHRtbCksIGFuZCBbYGdldF9lc3RpbWF0ZXMoKWBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL3RpZHljZW5zdXMvcmVmZXJlbmNlL2dldF9lc3RpbWF0ZXMuaHRtbCkuCgpUcmFkaXRpb25hbGx5LCBnZXR0aW5nICJzcGF0aWFsIiBDZW5zdXMgZGF0YSByZXF1aXJlcyBhIHRlZGlvdXMgbXVsdGktc3RlcCBwcm9jZXNzIHRoYXQgY2FuIGludm9sdmUgc2V2ZXJhbCBzb2Z0d2FyZSBwbGF0Zm9ybXMuIFRoZXNlIHN0ZXBzIGluY2x1ZGU6CgotICAgRmV0Y2hpbmcgc2hhcGVmaWxlcyBmcm9tIHRoZSBDZW5zdXMgd2Vic2l0ZTsKCi0gICBEb3dubG9hZGluZyBhIENTViBvZiBkYXRhLCB0aGVuIGNsZWFuaW5nIGFuZCBmb3JtYXR0aW5nIGl0OwoKLSAgIExvYWRpbmcgZ2VvbWV0cmllcyBhbmQgZGF0YSBpbnRvIHlvdXIgZGVza3RvcCBHSVMgb2YgY2hvaWNlOwoKLSAgIEFsaWduaW5nIGtleSBmaWVsZHMgaW4geW91ciBkZXNrdG9wIEdJUyBhbmQgam9pbmluZyB5b3VyIGRhdGEuCgpgZ2VvbWV0cnkgPSBUUlVFYCBjb21iaW5lcyB0aGUgYXV0b21hdGVkIGRhdGEgZG93bmxvYWQgZnVuY3Rpb25hbGl0eSBvZiB0aWR5Y2Vuc3VzIGFuZCB0aWdyaXMgdG8gYWxsb3cgUiB1c2VycyB0byBieXBhc3MgdGhpcyBwcm9jZXNzIGVudGlyZWx5LiBUaGUgZm9sbG93aW5nIGV4YW1wbGUgaWxsdXN0cmF0ZXMgdGhlIHVzZSBvZiB0aGUgYGdlb21ldHJ5ID0gVFJVRWAgYXJndW1lbnQsIGZldGNoaW5nIGluZm9ybWF0aW9uIG9uIHBvcHVsYXRpb24sIHBlciBjYXBpdGEgaW5jb21lIGFuZCB1bmVtcGxveW1lbnQgcmF0ZSBmb3IgYWxsIFRleGFzIGNvdW50aWVzLiBXZSB3aWxsIHVzZSB0aGlzIGRhdGEgZm9yIG1hcHBpbmcgaW4gdGhlIG5leHQgZmV3IHNlY3Rpb25zLgoKYGBge3J9CmxpYnJhcnkodGlkeWNlbnN1cykKIyAyMDE5IEFDUyBkYXRhIGZvciBhbGwgVGV4YXMgY291bnRpZXMgLSB0b3RhbCBwb3B1bGF0aW9uLCAKIyBQZXIgY2FwaXRhIGluY29tZSBhbmQgJSB1bmVtcGxveWVkClRYX2NvdW50eV9kdCA8LSBnZXRfYWNzKGdlb2dyYXBoeSA9ICJjb3VudHkiLCBzdGF0ZT0iVFgiLCAKICAgICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGVzPWMoIkIwMTAwMV8wMDEiLCAiQjE5MzAxXzAwMSIsICJEUDAzXzAwMDVQIiksIAogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyPTIwMTksIGdlb21ldHJ5PVQpCiMgZm9ybWF0IHRoZSBkYXRhIApUWF9jb3VudHlfZHQgPC0gVFhfY291bnR5X2R0WywtNV0gJT4lICAKICAgdGlkeXI6OnNwcmVhZChrZXk9InZhcmlhYmxlIiwgdmFsdWU9ImVzdGltYXRlIikgJT4lIAogICByZW5hbWUoUG9wdWxhdGlvbj1CMDEwMDFfMDAxLCBQZXJfY2FwaXRhX2luY29tZT1CMTkzMDFfMDAxLCAKICAgICAgICAgIFVuZW1wbG95bWVudD1EUDAzXzAwMDVQKQoKClRYX2NvdW50eV9kdApgYGAKCiMjIE1hcHBpbmcgd2l0aCBnZ3Bsb3QyIGFuZCBnZ21hcAoKT25lIG9mIHRoZSBtb3N0IGNvbW1vbiB3YXlzIHRvIHZpc3VhbGl6ZSBzdGF0aXN0aWNhbCBpbmZvcm1hdGlvbiBvbiBhIG1hcCBpcyB3aXRoICpjaG9yb3BsZXRoIG1hcHBpbmcqLiBDaG9yb3BsZXRoIG1hcHMgdXNlIHNoYWRpbmcgdG8gcmVwcmVzZW50IGhvdyB1bmRlcmx5aW5nIGRhdGEgdmFsdWVzIHZhcnkgYnkgZmVhdHVyZSBpbiBhIHNwYXRpYWwgZGF0YXNldC4gVGhlIENPVklELTE5IGNhc2VzIHBsb3QgYXQgVGV4YXMgY291bnR5IGxldmVsIGVhcmxpZXIgaW4gdGhpcyBjaGFwdGVyIGlzIGFuIGV4YW1wbGUgb2YgYSBjaG9yb3BsZXRoIG1hcC4KCldlIGNhbiB1c2UgZ2dwbG90MiB0byBjcmVhdGUgYSBDaG9yb3BsZXRoIG1hcDoKCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyBVc2luZyBnZ3Bsb3QyIE1ldGhvZCAxCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbGlicmFyeShnZ3Bsb3QyKSAKIyBtb3JlIGFib3V0IG1hcHBpbmcgaW4gZ2dwbG90OiBodHRwOi8vbWF6YW1hc2NpZW5jZS5jb20vV29ya2luZ1dpdGhEYXRhLz9wPTE0OTQKIyBtYXAKbGlicmFyeShzY2FsZXMpCm1hcDEgPC0gZ2dwbG90KFRYX2NvdW50eV9kdCkrCiAgZ2VvbV9zZihhZXMoZmlsbD1Qb3B1bGF0aW9uKSwgY29sb3I9ImdyZXk2MCIsIGFscGhhPTAuOCkrICMgc3BlY2lmeSB2YXJpYWJsZSB0byBtYXAKICBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIllsT3JSZCIsbmEudmFsdWUgPSAiZ3JleTUwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNiksIAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPWNvbW1hLHZhbHVlcyA9IGMoMSwwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGU9Z3VpZGVfY29sb3JiYXIocmV2ZXJzZSA9IFRSVUUpKSsKICAjZ2VvbV9wb2ludChkYXRhPXRleHQsIGxhdD1sYXQsIGxvbmc9bG9uZykrICNjYW4gYWRkIHBvaW50IGRhdGEgaGVyZSEKICBsYWJzKGZpbGw9IiIpK3hsYWIoIkxvbmdpdHVkZSIpK3lsYWIoIkxhdGl0dWRlIikrCiAgZ2d0aXRsZSgiTWFwIG9mIFRleGFzIENvdW50eSBsZXZlbCBQb3B1bGF0aW9uIikKCm1hcDEgI2Rpc3BsYXkKYGBgCgpUaGUgY291bnR5IHBvbHlnb25zIGNhbiBiZSBzdHlsZWQgdXNpbmcgKipnZ3Bsb3QyKiogY29udmVudGlvbnMgYW5kIHRoZSBbYGdlb21fc2YoKWBdKGh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9nZ3NmLmh0bWwpIGZ1bmN0aW9uLiBUaGUgW2BnZW9tX3NmKClgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2dzZi5odG1sKSBmdW5jdGlvbiBpbiB0aGUgYWJvdmUgZXhhbXBsZSBpbnRlcnByZXRzIHRoZSBnZW9tZXRyeSBvZiB0aGUgc2Ygb2JqZWN0IChpbiB0aGlzIGNhc2UsIHBvbHlnb24pIGFuZCB2aXN1YWxpemVzIHRoZSByZXN1bHQgYXMgYSBmaWxsZWQgY2hvcm9wbGV0aCBtYXAuIEluIHRoaXMgY2FzZSwgdGhlIEFDUyBlc3RpbWF0ZSBvZiB0b3RhbCBwb3B1bGF0aW9uIGlzIG1hcHBlZCB0byB0aGUgeWVsbG93LW9yYW5nZS1yZWQgY29sb3IgcmFtcCBpbiAqKmdncGxvdDIqKiwgaGlnaGxpZ2h0aW5nIHRoZSBtb3N0IHBvcHVsYXRlZCBjb3VudGllcyAoc3VjaCBhcyBIYXJyaXMgQ291bnR5KSB3aXRoIGRhcmtlciByZWRzLgoKSWYgeW91IHdvdWxkIGxpa2UgdG8gYWRkIHRoZSBHb29nbGUgbWFwIGFzIGJhY2tncm91bmQsIHRoZXJlIGlzIGFuIGFsdGVybmF0aXZlIHdheSBmb3IgbWFwcGluZyB1c2luZyBgZ2dwbG90MmAsIHdpdGggcGFja2FnZSBgZ2dtYXBgLiBZb3Ugd2lsbCBuZWVkIHRvIHJlcXVlc3QgZm9yIHlvdXIgb3duIEdvb2dsZSBBUEkga2V5IChpbnN0cnVjdGlvbnMgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3NlYXJjaC5yLXByb2plY3Qub3JnL0NSQU4vcmVmbWFucy9nZ21hcC9odG1sL3JlZ2lzdGVyX2dvb2dsZS5odG1sKSkuIE1vcmUgZGV0YWlscyBhYm91dCB2aXN1YWxpemF0aW9uIHdpdGggZ2dtYXAgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2pvdXJuYWwuci1wcm9qZWN0Lm9yZy9hcmNoaXZlLzIwMTMtMS9rYWhsZS13aWNraGFtLnBkZikuCgpgYGB7ciB3YXJuaW5nPUYsIG1lc3NhZ2U9RiwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMgVXNpbmcgZ2dwbG90MiBNZXRob2QgMgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiNpbnN0YWxsLnBhY2thZ2VzKCdyZ2VvcycsIHR5cGU9J3NvdXJjZScpCmxpYnJhcnkoZ3BjbGliKQojIGZpcnN0IGNvbnZlcnQgdGhlIFNwYXRpYWxQb2x5Z29uRGF0YUZyYW1lIHRvIGdncGxvdCBvYmplY3QgCmdnU0hQIDwtIGZvcnRpZnkoVFhfQ291bnR5LCByZWdpb249IkdFT0lEIikKIyBNZXJnZSBkYXRhIHdpdGggc2hhcGVmaWxlcwpnZ1NIUDIgPC0gbGVmdF9qb2luKGdnU0hQLCBUWF9jb3VudHlfZHQsIGJ5PWMoImlkIj0iR0VPSUQiKSkKCiMgT3B0aW9uYWw6IGlmIHlvdSB3b3VsZCBsaWtlIHRvIGFkZCBHb29nbGUgbWFwIGFzIHRoZSBiYWNrZ3JvdW5kCiNsaWJyYXJ5KGdnbWFwKQojcmVnaXN0ZXJfZ29vZ2xlKGtleT0ia2V5IllPVVIgR09PR0xFIEFQSSBLRVksIHdyaXRlPVRSVUUpIAojIHlvdSB3aWxsIG5lZWQgdG8gaW5zZXJ0IHlvdXIgb3duIEdvb2dsZSBBUEkga2V5IAoKZ2VvY29kZSgiVGV4YXMiKSAjZ2V0IGNlbnRlciBjb29yZGluYXRlcyBvZiBUZXhhcwojIEdldCBHb29nbGUgbWFwIC0gcm9hZCBtYXAKR29vZ2xlTWFwIDwtIGdnbWFwKGdldF9nb29nbGVtYXAoY2VudGVyPWMoLTk5LjksIDMyLjApLCBzY2FsZT0yICx6b29tPTYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHR5cGUgPSAicm9hZG1hcCIpLCBleHRlbnQ9InBhbmVsIikKCiMgbWFwcGluZyBjb3VudHkgbGV2ZWwgcG9wdWxhdGlvbgptYXAyIDwtIEdvb2dsZU1hcCArICNvcHRpb25hbCAKICBnZW9tX3BvbHlnb24oZGF0YT1nZ1NIUDIsIGFlcyh4PWxvbmcsIHk9bGF0LCBncm91cD1ncm91cCwgZmlsbD1VbmVtcGxveW1lbnQpLCAKICAgICAgICAgICAgICAgY29sb3I9ImdyZXk2MCIsIGFscGhhPTAuOCkrICMgc3BlY2lmeSB2YXJpYWJsZSB0byBtYXAKICBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIllsT3JSZCIsbmEudmFsdWUgPSAiZ3JleTUwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gMyksIGxhYmVsPWNvbW1hLAogICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoMSwwKSwgZ3VpZGU9Z3VpZGVfY29sb3JiYXIocmV2ZXJzZSA9IFRSVUUpKSsKICBsYWJzKGZpbGw9IiUgVW5lbXBsb3llZCIpK3hsYWIoIkxvbmdpdHVkZSIpK3lsYWIoIkxhdGl0dWRlIikrCiAgZ2d0aXRsZSgiTWFwIG9mIFRleGFzIENvdW50eSBsZXZlbCBVbmVtcGxveW1lbnQgUmF0ZSIpCm1hcDIgICNjaGVjawoKIyBQdXQgc2V2ZXJhbCBtYXBzIHRvZ2V0aGVyCmxpYnJhcnkoZ2dwdWJyKQpmaWd1cmUxIDwtIGdnYXJyYW5nZShtYXAxLCBtYXAyLCBucm93ID0gMSkKZmlndXJlMQoKI3NhdmUgdGhlIG1hcHMKI2dnc2F2ZSgiY291bnR5X3RtYXBfZ2dwbG90LnBuZyIsIGZpZ3VyZTEpCmBgYAoKIyMgTWFwcGluZyB3aXRoIHRtYXAKCkZvciAqKmdncGxvdDIqKiB1c2VycywgW2BnZW9tX3NmKClgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2dzZi5odG1sKSBvZmZlcnMgYSBmYW1pbGlhciBpbnRlcmZhY2UgZm9yIG1hcHBpbmcgZGF0YSBvYnRhaW5lZCBmcm9tIHRoZSBVUyBDZW5zdXMgQnVyZWF1LiBIb3dldmVyLCAqKmdncGxvdDIqKiBpcyBmYXIgZnJvbSB0aGUgb25seSBvcHRpb24gZm9yIGNhcnRvZ3JhcGhpYyB2aXN1YWxpemF0aW9uIGluIFIuIFRoZSAqKnRtYXAqKiBwYWNrYWdlIChbVGVubmVrZXMgMjAxOF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vY2Vuc3VzLXIvcmVmZXJlbmNlcy5odG1sI3JlZi10ZW5uZWtlczIwMTgpKSBpcyBhbiBleGNlbGxlbnQgYWx0ZXJuYXRpdmUgZm9yIG1hcHBpbmcgaW4gUiB0aGF0IGluY2x1ZGVzIGEgd2lkZSByYW5nZSBvZiBmdW5jdGlvbmFsaXR5IGZvciBjdXN0b20gY2FydG9ncmFwaHkuIFRoZSBzZWN0aW9uIHRoYXQgZm9sbG93cyBpcyBhbiBvdmVydmlldyBvZiBzZXZlcmFsIGNhcnRvZ3JhcGhpYyB0ZWNobmlxdWVzIGltcGxlbWVudGVkIHdpdGggKip0bWFwKiogZm9yIHZpc3VhbGl6aW5nIFVTIENlbnN1cyBkYXRhLiBBIGZ1bGwgdHJlYXRtZW50IG9mIGJlc3QgcHJhY3RpY2VzIGluIGNhcnRvZ3JhcGhpYyBkZXNpZ24gaXMgYmV5b25kIHRoZSBzY29wZSBvZiB0aGlzIHNlY3Rpb247IHJlY29tbWVuZGVkIHJlc291cmNlcyBmb3IgbGVhcm5pbmcgbW9yZSBpbmNsdWRlIFBldGVyc29uIChbMjAyMF0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vY2Vuc3VzLXIvcmVmZXJlbmNlcy5odG1sI3JlZi1wZXRlcnNvbjIwMjApKSBhbmQgQnJld2VyIChbMjAxNl0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vY2Vuc3VzLXIvcmVmZXJlbmNlcy5odG1sI3JlZi1icmV3ZXIyMDE2KSkuCgpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIFVzaW5nIHRtYXAKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKbGlicmFyeSh0bWFwKQojIG1vcmUgdG1hcCBzdHlsZXMgaW5mbyBoZXJlOiBodHRwczovL2dlb2NvbXByLmdpdGh1Yi5pby9wb3N0LzIwMTkvdG1hcC1jb2xvci1zY2FsZXMvCmxpYnJhcnkoZ2dtYXApCiNyZWdpc3Rlcl9nb29nbGUoa2V5PSJZT1VSIEdPT0dMRSBBUEkgS0VZIiwgd3JpdGU9VFJVRSkgCiMgZ2VvY29kZSB0byBnZXQgc29tZSBjaXR5IApjb29yZGluYXRlcyA8LSBnZW9jb2RlKGMoIkhvdXN0b24sIFRYIiwgIkF1c3RpbiwgVFgiLCAiRGFsbGFzLCBUWCIpKSAlPiUgCiAgbXV0YXRlKGNpdHk9YygiSG91c3RvbiIsICJBdXN0aW4iLCAiRGFsbGFzIikpCmNvb3Jfc2YgPSBzdF9hc19zZihjb29yZGluYXRlcywgY29vcmRzID0gYygnbG9uJywgJ2xhdCcpLCBjcnMgPSBzdF9jcnMoVFhfY291bnR5X2R0KSRwcm9qNHN0cmluZykKCmNvb3JkaW5hdGVzCgojIG1hcAptYXAxIDwtIHRtX3NoYXBlKFRYX2NvdW50eV9kdCkrCiAgdG1fcG9seWdvbnMoY29sPWMoIlVuZW1wbG95bWVudCIsIlBlcl9jYXBpdGFfaW5jb21lIiksIHN0eWxlPSJxdWFudGlsZSIsbj00LCAKICAgICAgICAgICAgICAjIHNwZWNpZnkgdmFyaWFibGVzIGFuZCBzdHlsZXMgb2YgbWFwcGluZyAKICAgICAgICAgICAgICB0aXRsZT1jKCJQZXJjZW50YWdlIiwiRG9sbGFycyIpLCBwYWxldHRlPSJzZXEiLCBsd2Q9MC41LCAgCiAgICAgICAgICAgICAgYm9yZGVyLmFscGhhID0gMC44LCBtaWRwb2ludD1OQSkrCiAgdG1fZmFjZXRzKG5jb2w9MikrICMgbnVtYmVyIG9mIGNvbHVtbnMKICB0bV9sYXlvdXQoYWVzLnBhbGV0dGUgPSBsaXN0KHNlcSA9ICJZbE9yUmQiKSkrICMgY29sb3Igc2NoZW1lCiAgdG1fbGF5b3V0KGlubmVyLm1hcmdpbj1jKDAsMC4wMSwwLDApLCAjIGxheW91dCBvZiB0aGUgbWFwCiAgICAgICAgICAgIGxlZ2VuZC50ZXh0LnNpemUgPSAxLAogICAgICAgICAgICBsZWdlbmQudGl0bGUuc2l6ZSA9IDEsCiAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbj1jKCJsZWZ0IiwgImJvdHRvbSIpLCAKICAgICAgICAgICAgcGFuZWwubGFiZWxzPWMoIlVuZW1wbG95bWVudCIsIlBlciBjYXBpdGEgaW5jb21lIiksCiAgICAgICAgICAgIHBhbmVsLmxhYmVsLmJnLmNvbG9yID0gIldoaXRlIikrCiAgdG1fc2hhcGUoY29vcl9zZikrICMgeW91IGNhbiBhbHNvIGFkZCBwb2ludCBkYXRhIC0gbWFyayBsb2NhdGlvbnMgb2YgdGhlIGJpZyBjaXRpZXMgCiAgdG1fc3ltYm9scyhzaXplPTAuNSwgY29sPSJibGFjayIsIGJvcmRlci5jb2w9ImJsYWNrIikrdG1fdGV4dCgiY2l0eSIsIHNpemU9MS4yLCBqdXN0PSJsZWZ0IiwgeW1vZD0wLjYpCgptYXAxIAoKIyBzYXZlIHRoZSBtYXAKI3RtYXBfc2F2ZShtYXAzLCBmaWxlbmFtZT0iY291bnR5X21hcF90bWFwIiwgZHBpPTUwMCkgIAogIApgYGAKCkFuIGFsdGVybmF0aXZlIGNvbW1vbmx5IHVzZWQgdG8gdmlzdWFsaXplIGNvdW50IGRhdGEgaXMgdGhlICoqZ3JhZHVhdGVkIHN5bWJvbCBtYXAqKi4gR3JhZHVhdGVkIHN5bWJvbCBtYXBzIHVzZSBzaGFwZXMgcmVmZXJlbmNlZCB0byBnZW9ncmFwaGljIHVuaXRzIHRoYXQgYXJlIHNpemVkIHJlbGF0aXZlIHRvIGEgZGF0YSBhdHRyaWJ1dGUuIFRoZSBleGFtcGxlIGJlbG93IHVzZXMgKip0bWFwKioncyBbYHRtX2J1YmJsZXMoKWBdKGh0dHBzOi8vcmRyci5pby9wa2cvdG1hcC9tYW4vdG1fc3ltYm9scy5odG1sKSBmdW5jdGlvbiB0byBjcmVhdGUgYSBncmFkdWF0ZWQgc3ltYm9sIG1hcCBvZiB0aGUgdG90YWwgcG9wdWxhdGlvbiBpbiBUZXhhcyBjb3VudGllczoKCmBgYHtyfQp0bV9zaGFwZShUWF9jb3VudHlfZHQpICsgCiAgdG1fcG9seWdvbnMoKSArIAogIHRtX2J1YmJsZXMoc2l6ZSA9ICJQb3B1bGF0aW9uIiwgCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSwgCiAgICAgICAgICAgICBjb2wgPSAibmF2eSIsCiAgICAgICAgICAgICB0aXRsZS5zaXplID0gIkNvdW50eSBwb3B1bGF0aW9uIHNpemUgaW4gVGV4YXMsIDIwMjAiKQoKYGBgCgpUaGVyZSBhcmUgb3RoZXIgZnVuY3Rpb25zIGluIHRtYXAgdGhhdCBjYW4gYmUgdXNlZCB0byBjdXN0b21pemUgeW91ciBtYXBzLiBbYHRtX3NjYWxlX2JhcigpYF0oaHR0cHM6Ly9yZHJyLmlvL3BrZy90bWFwL21hbi90bV9zY2FsZV9iYXIuaHRtbCkgYWRkcyBhIHNjYWxlIGJhcjsgW2B0bV9jb21wYXNzKClgXShodHRwczovL3JkcnIuaW8vcGtnL3RtYXAvbWFuL3RtX2NvbXBhc3MuaHRtbCkgYWRkcyBhIG5vcnRoIGFycm93OyBhbmQgW2B0bV9jcmVkaXRzKClgXShodHRwczovL3JkcnIuaW8vcGtnL3RtYXAvbWFuL3RtX2NyZWRpdHMuaHRtbCkgaGVscHMgY2FydG9ncmFwaGVycyBnaXZlIGNyZWRpdCBmb3IgdGhlIGJhc2VtYXAsIHdoaWNoIGlzIHJlcXVpcmVkIHdoZW4gdXNpbmcgTWFwYm94IGFuZCBPcGVuU3RyZWV0TWFwIHRpbGVzLiBUaGUgYGxlZ2VuZC5oaXN0YCBhcmd1bWVudCBpbiBbYHRtX3BvbHlnb25zKClgXShodHRwczovL3JkcnIuaW8vcGtnL3RtYXAvbWFuL3RtX3BvbHlnb25zLmh0bWwpIGNhbiBiZSBzZXQgdG8gVFJVRSwgYWRkaW5nIGEgaGlzdG9ncmFtIHRvIHRoZSBtYXAgd2l0aCBiYXJzIGNvbG9yZWQgYnkgdGhlIHZhbHVlcyB1c2VkIG9uIHRoZSBtYXAuCgpgYGB7cn0KdG1fc2hhcGUoVFhfY291bnR5X2R0KSsKICB0bV9wb2x5Z29ucyhjb2w9YygiVW5lbXBsb3ltZW50IiksIHN0eWxlPSJxdWFudGlsZSIsbj00LCAKICAgICAgICAgICAgICB0aXRsZT1jKCJQZXJjZW50YWdlIiksIHBhbGV0dGU9InNlcSIsIGx3ZD0wLjUsICAKICAgICAgICAgICAgICBib3JkZXIuYWxwaGEgPSAwLjMsIG1pZHBvaW50PU5BLAogICAgICAgICAgICAgIGxlZ2VuZC5oaXN0PVQsbGVnZW5kLmhpc3Quej00KSsKICB0bV9sYXlvdXQoYWVzLnBhbGV0dGUgPSBsaXN0KHNlcSA9ICJZbE9yUmQiKSkrICMgY29sb3Igc2NoZW1lCiAgdG1fbGF5b3V0KGlubmVyLm1hcmdpbj1jKDAsMC4yLDAsMCksICMgbGF5b3V0IG9mIHRoZSBtYXAKICAgICAgICAgICAgbGVnZW5kLnRleHQuc2l6ZSA9IDEsCiAgICAgICAgICAgIGxlZ2VuZC50aXRsZS5zaXplID0gMSwKICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uPWMoImxlZnQiLCAiYm90dG9tIiksIAogICAgICAgICAgICBwYW5lbC5sYWJlbHM9YygiVW5lbXBsb3ltZW50IiksCiAgICAgICAgICAgIHBhbmVsLmxhYmVsLmJnLmNvbG9yID0gIldoaXRlIikrCiAgdG1fY29tcGFzcyhwb3NpdGlvbiA9IGMoImxlZnQiLCAidG9wIikpKwogIHRtX3NjYWxlX2Jhcihwb3NpdGlvbiA9IGMoInJpZ2h0IiwgInRvcCIpKQogIAoKYGBgCgojIyBJbnRlcmFjdGl2ZSBNYXBwaW5nCgojIyMgTWFwdmlldwoKV2UgY2FuIHF1aWNrbHkgdmlzdWFsaXplIGdlb2dyYXBoaWMgZGF0YSBvYnRhaW5lZCB3aXRoIHRpZ3JpcyBvbiBhbiBpbnRlcmFjdGl2ZSBtYXAgYnkgdXNpbmcgdGhlIFtgbWFwdmlldygpYF0oaHR0cHM6Ly9yZHJyLmlvL3BrZy9tYXB2aWV3L21hbi9tYXBWaWV3Lmh0bWwpIGZ1bmN0aW9uIGluIHRoZSAqKm1hcHZpZXcqKiBwYWNrYWdlLiBUaGUgW2BtYXB2aWV3KClgXShodHRwczovL3JkcnIuaW8vcGtnL21hcHZpZXcvbWFuL21hcFZpZXcuaHRtbCkgZnVuY3Rpb24gYWxzbyBpbmNsdWRlcyBhIHBhcmFtZXRlciBgemNvbGAgdGhhdCB0YWtlcyBhIGNvbHVtbiBpbiB0aGUgZGF0YXNldCBhcyBhbiBhcmd1bWVudCwgYW5kIHZpc3VhbGl6ZXMgdGhhdCBjb2x1bW4gd2l0aCBhbiBpbnRlcmFjdGl2ZSBjaG9yb3BsZXRoIG1hcC4KCmBgYHtyfQpsaWJyYXJ5KG1hcHZpZXcpCm1hcHZpZXcoVFhfY291bnR5X2R0LCB6Y29sID0gIlBlcl9jYXBpdGFfaW5jb21lIikKYGBgCgojIyMgSW50ZXJhY3RpdmUgTWFwcGluZyB3aXRoIGxlYWZsZXQKCldpdGggb3ZlciAzMSwwMDAgR2l0SHViIHN0YXJzIGFzIG9mIEp1bHkgMjAyMSwgdGhlIExlYWZsZXQgSmF2YVNjcmlwdCBsaWJyYXJ5IChbQWdhZm9ua2luIDIwMjBdKGh0dHBzOi8vd2Fsa2VyLWRhdGEuY29tL2NlbnN1cy1yL3JlZmVyZW5jZXMuaHRtbCNyZWYtbGVhZmxldCkpIGlzIG9uZSBvZiB0aGUgbW9zdCBwb3B1bGFyIGZyYW1ld29ya3Mgd29ybGR3aWRlIGZvciBpbnRlcmFjdGl2ZSBtYXBwaW5nLiBUaGUgUlN0dWRpbyB0ZWFtIGJyb3VnaHQgdGhlIExlYWZsZXQgdG8gUiB3aXRoIHRoZSAqKmxlYWZsZXQqKiBSIHBhY2thZ2UgKFtDaGVuZywgS2FyYW1iZWxrYXIsIGFuZCBYaWUgMjAyMV0oaHR0cHM6Ly93YWxrZXItZGF0YS5jb20vY2Vuc3VzLXIvcmVmZXJlbmNlcy5odG1sI3JlZi1jaGVuZzIwMjEpKSwgd2hpY2ggbm93IHBvd2VycyBzZXZlcmFsIGFwcHJvYWNoZXMgdG8gaW50ZXJhY3RpdmUgbWFwcGluZyBpbiBSLiBUaGUgZm9sbG93aW5nIGV4YW1wbGVzIGNvdmVyIGhvdyB0byB2aXN1YWxpemUgQ2Vuc3VzIGRhdGEgb24gYW4gaW50ZXJhY3RpdmUgTGVhZmxldCBtYXAgdXNpbmcgYXBwcm9hY2hlcyBmcm9tICoqbWFwdmlldyoqLCAqKnRtYXAqKiwgYW5kIHRoZSBjb3JlICoqbGVhZmxldCoqIHBhY2thZ2UuIERldGFpbHMgb24gbGVhZmxldCBtYXBwaW5nIGluIFIgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2RhdGEubGlicmFyeS52aXJnaW5pYS5lZHUvZGF0YS1zY2llbnRpc3QtYXMtY2FydG9ncmFwaGVyLWFuLWludHJvZHVjdGlvbi10by1tYWtpbmctaW50ZXJhY3RpdmUtbWFwcy1pbi1yLXdpdGgtbGVhZmxldC8pLgoKQmVsb3cgaXMgYW4gZXhhbXBsZSBvZiBpbnRlcmFjdGl2ZSBtYXAgY3JlYXRlZCB1c2luZyBsZWFmbGV0IC0gdmlzdWFsaXphdGlvbiBjb3VudHkgbGV2ZWwgcG9wdWxhdGlvbiBkYXRhIGluIFRleGFzOgoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMgSW50ZXJhY3RpdmUgbWFwcwojIyMjIyMjIyMjIyMjIyMjIyMjIwpsaWJyYXJ5KGxlYWZsZXQpClRYX2NvdW50eV9kdDIgPC0gYXMoVFhfY291bnR5X2R0LCAiU3BhdGlhbCIpCmwgPC0gbGVhZmxldChUWF9jb3VudHlfZHQyKSAlPiUgYWRkVGlsZXMoKQojIGNvbG9yIHNjaGVtZQpwYWwgPC0gY29sb3JOdW1lcmljKHBhbGV0dGUgPSAiWWxPclJkIiwgZG9tYWluPVRYX2NvdW50eV9kdDIkUG9wdWxhdGlvbikKIyBhZGQgcG9wdXAgbGFiZWxzCmxhYmVscyA8LSBzcHJpbnRmKCI8c3Ryb25nPiBDb3VudHk6ICVzIDwvc3Ryb25nPiA8YnIvPiAKICAgICAgICAgICAgICAgICAgUG9wdWxhdGlvbjogJXMgPGJyLz4gVW5lbXBsb3ltZW50IHJhdGU6ICVzIDxici8+IAogICAgICAgICAgICAgICAgICBQZXIgY2FwaXRhIGluY29tZSwgJDogJXMiLAogICAgICAgICAgICAgICAgICBUWF9jb3VudHlfZHQyJE5BTUUsIFRYX2NvdW50eV9kdDIkUG9wdWxhdGlvbiwKICAgICAgICAgICAgICAgICAgVFhfY291bnR5X2R0MiRVbmVtcGxveW1lbnQsIFRYX2NvdW50eV9kdDIkUGVyX2NhcGl0YV9pbmNvbWUpICU+JSAKICBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQojIGFkZCB0byB0aGUgbWFwCmludGVyYWN0aXZlX21hcCA8LSBsICU+JQogIGFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiZ3JleSIsIHdlaWdodCA9IDEsCiAgICBmaWxsQ29sb3IgPSB+IHBhbChUWF9jb3VudHlfZHQyJFBvcHVsYXRpb24pLCBmaWxsT3BhY2l0eSA9IDAuNSwKICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKHdlaWdodCA9IDQpLAogICAgbGFiZWwgPSBsYWJlbHMsCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoCiAgICAgIHN0eWxlID0gbGlzdCgKICAgICAgICAiZm9udC13ZWlnaHQiID0gIm5vcm1hbCIsCiAgICAgICAgcGFkZGluZyA9ICIzcHggOHB4IgogICAgICApLAogICAgICB0ZXh0c2l6ZSA9ICIxNXB4IiwgZGlyZWN0aW9uID0gImF1dG8iCiAgICApCiAgKSAlPiUKICBhZGRMZWdlbmQoCiAgICBwYWwgPSBwYWwsIHZhbHVlcyA9IH5UWF9jb3VudHlfZHQyJFBvcHVsYXRpb24sIG9wYWNpdHkgPSAwLjUsCiAgICB0aXRsZSA9ICJQb3B1bGF0aW9uIiwgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiCiAgKQoKaW50ZXJhY3RpdmVfbWFwCmBgYAoKIyMjIEFsdGVybmF0aXZlIHdheXMgZm9yIGludGVyYWN0aXZlIG1hcHBpbmcKClRoZXJlIGFyZSBtYW55IG90aGVyIHdheXMgZm9yIGludGVyYWN0aXZlIG1hcHBpbmcgaW4gUjoKCi0gICBSIHBhY2thZ2UgYGdnaXJhcGhgOiBbbGlua2VkIG1hcHMgYW5kIGNoYXJ0c10oaHR0cHM6Ly93d3cuaW5mb3dvcmxkLmNvbS9hcnRpY2xlLzM2MjY5MTEvZWFzeS1pbnRlcmFjdGl2ZS1nZ3Bsb3QtZ3JhcGhzLWluLXItd2l0aC1nZ2lyYXBoLmh0bWwpCgotICAgUiBwYWNrYWdlIGBnZ2FuaW1hdGVgOiBbY3JlYXRlIGFuZCBzYXZlIG1hcHMgaW4gZ2lmIG9yIG1wNF0oaHR0cHM6Ly93d3cuNWhhdy5jb20vcG9zdHMvd2Vlay0zLW1ha2luZy1hbi1hbmltYXRlZC1tYXAtdXNpbmctbWFwcy1nZ3Bsb3QyLWFuZC1nZ2FuaW1hdGUvKQoKLSAgIFIgcGFja2FnZSBgcGxvdGx5OmAgW2ludGVyYWN0aXZlIG1hcHBpbmddKGh0dHBzOi8vcGxvdGx5LmNvbS9yL21hcHMvKQoKLSAgIFIgc2hpbnk6IFtyZWFjdGl2ZSBtYXBwaW5nXShodHRwczovL3d3dy5wYXVsYW1vcmFnYS5jb20vYm9vay1nZW9zcGF0aWFsL3NlYy1kYXNoYm9hcmRzd2l0aHNoaW55Lmh0bWwpCg==