Welcome!

Structure of workshop

  1. About me
  2. Types of census data
  3. The Census API
  4. Using tidycensus and censusapi to get data on places
  5. Using the ipumsr package to get data on people

About me

I am an associate professor in the UTSA Department of Demography and have been at UTSA since 2006.

Research interests include data science, Bayesian methods, education demography and health disparities.

Types of Census Data

Decennial Census

American Community Survey

County Business Patterns

Population Estimates Program - SAIPE and SAHIE

Decennial Census Summary File 1

The Census Summary File 1(SF 1) contains the data compiled from the questions asked of all people and about every housing unit.

Population items include sex, age, race, Hispanic or Latino origin, household relationship, household type, household size, family type, family size, and group quarters. Housing items include occupancy status, vacancy status, and tenure (whether a housing unit is owner-occupied or renter-occupied).

SF 1 includes population and housing characteristics for the total population, population totals for an extensive list of race (American Indian and Alaska Native tribes, Asian, and Native Hawaiian and Other Pacific Islander) and Hispanic or Latino groups, and population and housing characteristics for a limited list of race and Hispanic or Latino groups.

The decennial Census summary file 1 does not contain information on education, socioeconomic conditions or other detailed characteristics of the population.

Up until 2010, the Census bureau surveyed 1 out of every 6 households to measure these characteristics, which was referred to as the Census “long form”, which was tabulated into a product called the Summary File 3. The year 2000 was the last year this survey was conducted, and beginning in 2005, the American Community Survey replaced the “long form” as the tool to measure socioeconomic characteristics of the population. (US Census Bureau, 2010)

American Community Survey Summary File

The American Community Survey (ACS) is part of the U.S. Census Bureau’s Survey Program and is designed to provide current demographic, social, economic, and housing estimates throughout the decade.

The ACS provides information on more than 40 topics, including educational attainment, language spoken at home, ability to speak English, the foreign born, marital status, migration, and many more. Each year the survey randomly samples around 3.5 million addresses and produces statistics that cover 1-year and 5-year periods for geographic areas in the United States and Puerto Rico, ranging from neighborhoods to congressional districts to the entire nation.

The ACS 1-year estimates are published for areas that have populations of 65,000 or more.

The ACS 5-year estimates are published for all geographic areas, including Census tracts, block groups, American Indian areas, core-based statistical areas, combined statistical areas, Congressional districts, and state legislative districts.

The American Community Survey Summary File (ACSSF) is a unique data product that includes all the estimates and margins of error from the detailed tables and geographies that are published for the ACS. Data contained in the ACS Summary File cover demographic, social, economic, and housing subject areas.

These data represent totals of population counts, along with the measurement errors in those counts for places, not for individuals, which is the subject of the ACS Public Use Microdata.

American Community Survey Public Use Microdata

The Public Use Microdata Sample (PUMS) contains a sample of actual responses to the American Community Survey (ACS). The PUMS dataset includes variables for nearly every question on the survey, as well as many new variables that were derived after the fact from multiple survey responses (such as poverty status).

Each record in the file represents a single person, or–in the household-level dataset–a single housing unit. In the person-level file, individuals are organized into households, making possible the study of people within the contexts of their families and other household members.

PUMS files for an individual year, such as 2015, contain data on approximately one percent of the United States population. PUMS files covering a five-year period, such as 2011-2015, contain data on approximately five percent of the United States population.

The PUMS files are much more flexible than the aggregate data produced in the ACS summary files, though the PUMS also tend to be more complicated to use. Working with PUMS data generally involves downloading large datasets onto a local computer and analyzing the data using statistical software such as R, SPSS, Stata, or SAS.

Since all ACS responses are strictly confidential, many variables in the PUMS files have been modified in order to protect the confidentiality of survey respondents. For instance, particularly high incomes are “top-coded,” uncommon birthplace or ancestry responses are grouped into broader categories, and the PUMS files provide a very limited set of geographic variables, including state, metropolitan area and public use microdata area, or PUMA.

While PUMS files contain cases from nearly every town and county in the country, towns and counties (and other low-level geography) are not identified by any variables in the PUMS datasets. The most detailed unit of geography contained in the PUMS files is the Public Use Microdata Area (PUMA). PUMAs are special non-overlapping areas that partition each state into contiguous geographic units containing no fewer than 100,000 people each. The 2011-2015 5-year ACS PUMS files rely on PUMA boundaries that were drawn by state governments after the 2000 and 2010 Census.

The PUMS data are most easily accessed from the University of Minnesota’s Integrated Public Use Microdata Series (IPUMS) data archive. This data source processes the data produced by the Census Bureau into more easily comparable and readable data files that are available for all years of the decennial Census and the ACS. (Ruggles et al., 2015)

Using the tidycensus package

They tidycensus is part of the tidyverse, and was written and maintained by Dr. Kyle Walker at TCU.

It allows you to dynamically download and map data from the decennial Census and ACS for any level of Census geography, except blocks!

If you want data on places, this is the easiest way to get it.

Census table names

The Census publishes data for places in summary tables. These follow a pattern for their names, you can find a description of this here. The biggest problem with finding data from the Census is knowing the table name you want.

You can find table names for the ACS here

What kind of table do you want?

There are several types of tables the Census publishes.

The Detailed tables are very detailed summaries of the data for places, in the 2015 data there were more than 64,000 tables published. These can be a little overwhelming to use, but we’ll see an example below

Subject tables take some of the detailed tables and compute summaries of them around certain demographic, social or economic subjects. Basically this is one way to get more data related to a subject without having to know all of the individual detail tables you need.

Data Profile tables contain broad social, economic, housing, and demographic information. The data are presented as both counts and percentages. There are over 2,400 variables in this dataset. These are very useful summaries and what I personally rely on for most of my data extracts.

Get a Census developer API Key

Obtain one at http://api.census.gov/data/key_signup.html

Save your API key to your working directory

I recommend you install your API key in your Rprofile, just so you don’t have to keep pasting it into your code. To do this, type tidycensus::census_api_key(key = "yourkeyhere", install = T) one time to install your key for use in tidycensus.

Let’s do some stuff!

Look at available ACS variables

As I mentioned above, finding the right table can be a challenge, especially for new data users. tidycensus has the load_variables() function that will load all of the available tables for a specific table type.

For example, if we are interested in variables from the ACS data profile tables, we can load all available variables then use R to search for what we need.

One of the best ways to search is to use grep(), which is a tool for searching for patterns within text, and is SUPER USEFUL!

library(tidycensus)
library(dplyr)
library(sf)
library(ggplot2)
library(censusapi)
?load_variables
## starting httpd help server ... done
v15_Profile <- load_variables(year = 2015 , dataset = "acs5/profile",
                              cache = TRUE) #demographic profile tables

#Open the data for examination
knitr::kable(head(v15_Profile))
name label concept
DP02_0001 Estimate!!HOUSEHOLDS BY TYPE!!Total households SELECTED SOCIAL CHARACTERISTICS IN THE UNITED STATES
DP02_0001P Percent!!HOUSEHOLDS BY TYPE!!Total households SELECTED SOCIAL CHARACTERISTICS IN THE UNITED STATES
DP02_0002 Estimate!!HOUSEHOLDS BY TYPE!!Total households!!Family households (families) SELECTED SOCIAL CHARACTERISTICS IN THE UNITED STATES
DP02_0002P Percent!!HOUSEHOLDS BY TYPE!!Total households!!Family households (families) SELECTED SOCIAL CHARACTERISTICS IN THE UNITED STATES
DP02_0003 Estimate!!HOUSEHOLDS BY TYPE!!Total households!!Family households (families)!!With own children of the householder under 18 years SELECTED SOCIAL CHARACTERISTICS IN THE UNITED STATES
DP02_0003P Percent!!HOUSEHOLDS BY TYPE!!Total households!!Family households (families)!!With own children of the householder under 18 years SELECTED SOCIAL CHARACTERISTICS IN THE UNITED STATES
#Search for variables by keywords in the label
v15_Profile[grep(x = v15_Profile$label, "Median household"), c("name", "label")]
## # A tibble: 2 x 2
##   name       label                                                              
##   <chr>      <chr>                                                              
## 1 DP03_0062  Estimate!!INCOME AND BENEFITS (IN 2015 INFLATION-ADJUSTED DOLLARS)~
## 2 DP03_0062P Percent!!INCOME AND BENEFITS (IN 2015 INFLATION-ADJUSTED DOLLARS)!~

Also, if you want the names and info for the subject tables, change the dataset = argument to acs5/subject

v15_subject <- load_variables(year = 2015 ,dataset= "acs5/subject",
                              cache = TRUE) #demographic subject tables

Finally, to view variables in the detailed tables, change the dataset = argument to acs5

v15_detailed <- load_variables(year = 2015 , dataset = "acs5",
                               cache = TRUE) #demographic detail tables

If you are interested in variables from the decennial census, change the dataset = argument to sf1 or sf3 depending on which decennial summary file you want.

Extract from ACS summary file data profile variables from 2015 for Bexar County, TX Census Tracts

Here is a real example

The data profile tables are very useful because they contain lots of pre-calculated variables.

Here is a query where we extract the median household income in census tracts from the 2015 ACS for Bexar County, Texas. We can also get the spatial data by requesting geometry=TRUE. Using output="wide" will put each variable in a column of the data set, with each row being a census tract.

sa_acs<-get_acs(geography = "tract", state="TX", county = c("Bexar"),
                year = 2015,
                variables=c( "DP03_0062E") ,
                geometry = T, output = "wide")
## Getting data from the 2011-2015 5-year ACS
## Downloading feature geometry from the Census website.  To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
## Using the ACS Data Profile
#create a county FIPS code - 5 digit
sa_acs$county<-substr(sa_acs$GEOID, 1, 5)

#rename variables and filter missing cases
sa_acs2<-sa_acs%>%
  mutate( medhhinc=DP03_0062E) %>%
  na.omit()

#take a peek at the first few lines of data
head(sa_acs2)

We can immediately map these data as well, because tidycensus can get you the geography corresponding to your data.

Here, I use the dplyr pipe “%>%” to feed the data into ggplot and map the median household income for each census tract in Bexar County in 2015, using a quantile break system.

sa_acs2 %>%
  mutate(med_income=cut(medhhinc,breaks = quantile(medhhinc, na.rm=T, p=seq(0,1,length.out = 9)),include.lowest = T))%>%
  ggplot( aes(fill = med_income, color = med_income)) + 
  geom_sf() + 
  ggtitle("Median Household Income", 
          subtitle = "Bexar County Texas, 2015 - Quantile Breaks")+
  scale_fill_brewer(palette = "Blues") + 
  scale_color_brewer(palette = "Blues")

ACS margins of error

The ACS is a survey and in areas where the sample size is small, the errors in estimates can be quite large. As a way to let users know how uncertain the estimates are for any given area, the Census publishes Margins of Error for each estimate published. In states, counties and cities, these margins of error are usually small since the overall sample size in those larger areas is large enough to provide more certainty about the population estimates.

In areas that are smaller, tracts and especially block groups, the margins of error can be be very large relative to the estimates. One way to visualize this is to map the coefficient of variation in the estimates, which is: \(CV= \frac{\sigma}{\theta}\), where \(\theta\) is the estimate of interest.

mapping of errors in variables

Here I generate a quantile break for the coefficient of variation in census tract income estimates

sa_acs2 %>%
  mutate(cv =(DP03_0062M/1.645)/DP03_0062E)%>%
  mutate(cv_map=cut(cv,breaks = quantile(cv, na.rm=T, p=seq(0,1,length.out = 9)),include.lowest = T))%>%
  ggplot( aes(fill =cv_map, color = cv_map)) + 
  geom_sf() + 
  ggtitle("Coefficient of Variation in Median Household Income", 
          subtitle = "Bexar County Texas, 2015 - Quantile Breaks")+
  scale_fill_viridis_d(option="B")+ 
  scale_color_viridis_d(option="B")

Metro area incomes

Here is another example where we get data for metro/micropolitan areas in the US. I use a detailed table request this time.

v15_acs<- load_variables(year = 2015 , dataset = "acs5",
                         cache = TRUE) #regular ACS profile tables

knitr::kable(head(v15_acs))

#Search for variables by keywords in the label 
v15_acs[grep(x = v15_Profile$label, "Median household"), c("name", "label")]

metro<-get_acs(geography = "metropolitan statistical area/micropolitan statistical area",
               year = 2015,
                variables=c( "B19013_001E") ,
                geometry = F, output = "wide")
## Getting data from the 2011-2015 5-year ACS

For this geography, tidycensus won’t download the geometrys automatically (maybe in a later release), so we use Kyle Walker’s other library tigris for downloading Census geographic data.

library(tigris)
## To enable 
## caching of data, set `options(tigris_use_cache = TRUE)` in your R script or .Rprofile.
options(tigris_class = "sf") #for use with ggplot2

met_geo<-core_based_statistical_areas(cb=T, year = 2015)

#Filter out territories
sts<-states(cb = T, year = 2015)%>%
  filter(!STATEFP%in%c( "60", "66", "69", "72", "78"))

#merge geographic data to table data
met_join<-geo_join(met_geo, metro, by="GEOID")
## Warning: `group_by_()` was deprecated in dplyr 0.7.0.
## Please use `group_by()` instead.
## See vignette('programming') for more help
#rename variables and filter missing cases
met_join<-met_join%>%
  mutate( medhhinc=B19013_001E) %>%
  mutate(med_income=cut(medhhinc,breaks = quantile(medhhinc, na.rm=T, p=seq(0,1,length.out = 9)),include.lowest = T))

##Create our map

map1<-met_join%>%
  st_transform(crs = 2278)%>%
  ggplot( aes(fill = med_income, color = med_income)) + 
  geom_sf() + 
  ggtitle("Median Household Income", 
          subtitle = "MSAs, 2015 - Quantile Breaks")+
  scale_fill_brewer(palette = "Blues") + 
  scale_color_brewer(palette = "Blues")+
  geom_sf(data=sts, fill=NA, color="black")
    
map1

If you would like to zoom in, we can use the mapview library. This is very useful for teaching and for presentations.

library(mapview)

pal <- colorRampPalette(viridisLite::viridis(n=6)) #set colors

mapview(met_join, zcol="med_income", col.regions=pal, legend=T,map.types="OpenStreetMap", layer.name="Median Income")

Using the censusapi package

The Census has lots of APIs that are available. tidycensus is great for accessing the ACS and decennial census, but if you want data from another API, the more general censusapi package gives you access to all of the Census APIs

First, since this is a different package, you’ll need to add your API key to your .Renviron data. You can do this by following the example below:

Sys.setenv(CENSUS_KEY="f67be5a86e696eebf0c84a5a20d85f2c04f7e9ef")
# Reload .Renviron
readRenviron("~/.Renviron")
# Check to see that the expected key is output in your R console
Sys.getenv("CENSUS_KEY")

Now we load all of the available APIs into an R object so we can look what’s available.

apis <- listCensusApis()
knitr::kable(head(apis))
title name vintage url isTimeseries temporal description modified
449 Annual Economic Surveys: Annual Business Survey abscb 2017 https://api.census.gov/data/2017/abscb NA unidentified The Annual Business Survey (ABS) provides information on selected economic and demographic characteristics for businesses and business owners by sex, ethnicity, race, and veteran status. Further, the survey measures research and development (for microbusinesses), new business topics such as innovation and technology, as well as other business characteristics. The U.S. Census Bureau and the National Center conduct the ABS jointly for Science and Engineering Statistics within the National Science Foundation. The ABS replaces the five-year Survey of Business Owners (SBO) for employer businesses, the Annual Survey of Entrepreneurs (ASE), the Business R&D and Innovation for Microbusinesses survey (BRDI-M), and the innovation section of the Business R&D and Innovation Survey (BRDI-S). https://www.census.gov/programs-surveys/abs.html 2020-04-30 00:00:00.0
543 Annual Economic Surveys: Annual Business Survey abscb 2018 https://api.census.gov/data/2018/abscb NA unidentified The Annual Business Survey (ABS) provides information on selected economic and demographic characteristics for businesses and business owners by sex, ethnicity, race, and veteran status. Further, the survey measures research and development (for microbusinesses), new business topics such as innovation and technology, as well as other business characteristics. The U.S. Census Bureau and the National Center conduct the ABS jointly for Science and Engineering Statistics within the National Science Foundation. The ABS replaces the five-year Survey of Business Owners (SBO) for employer businesses, the Annual Survey of Entrepreneurs (ASE), the Business R&D and Innovation for Microbusinesses survey (BRDI-M), and the innovation section of the Business R&D and Innovation Survey (BRDI-S). https://www.census.gov/programs-surveys/abs.html 2020-10-26 00:00:00.0
453 Annual Economic Surveys: Annual Business Survey abscbo 2017 https://api.census.gov/data/2017/abscbo NA unidentified The Annual Business Survey (ABS) provides information on selected economic and demographic characteristics for businesses and business owners by sex, ethnicity, race, and veteran status. Further, the survey measures research and development (for microbusinesses), new business topics such as innovation and technology, as well as other business characteristics. The U.S. Census Bureau and the National Center conduct the ABS jointly for Science and Engineering Statistics within the National Science Foundation. The ABS replaces the five-year Survey of Business Owners (SBO) for employer businesses, the Annual Survey of Entrepreneurs (ASE), the Business R&D and Innovation for Microbusinesses survey (BRDI-M), and the innovation section of the Business R&D and Innovation Survey (BRDI-S). https://www.census.gov/programs-surveys/abs.html 2020-04-30 00:00:00.0
544 Annual Economic Surveys: Annual Business Survey abscbo 2018 https://api.census.gov/data/2018/abscbo NA unidentified The Annual Business Survey (ABS) provides information on selected economic and demographic characteristics for businesses and business owners by sex, ethnicity, race, and veteran status. Further, the survey measures research and development (for microbusinesses), new business topics such as innovation and technology, as well as other business characteristics. The U.S. Census Bureau and the National Center conduct the ABS jointly for Science and Engineering Statistics within the National Science Foundation. The ABS replaces the five-year Survey of Business Owners (SBO) for employer businesses, the Annual Survey of Entrepreneurs (ASE), the Business R&D and Innovation for Microbusinesses survey (BRDI-M), and the innovation section of the Business R&D and Innovation Survey (BRDI-S). https://www.census.gov/programs-surveys/abs.html 2020-10-26 00:00:00.0
455 Annual Economic Surveys: Annual Business Survey abscs 2017 https://api.census.gov/data/2017/abscs NA unidentified The Annual Business Survey (ABS) provides information on selected economic and demographic characteristics for businesses and business owners by sex, ethnicity, race, and veteran status. Further, the survey measures research and development (for microbusinesses), new business topics such as innovation and technology, as well as other business characteristics. The U.S. Census Bureau and the National Center conduct the ABS jointly for Science and Engineering Statistics within the National Science Foundation. The ABS replaces the five-year Survey of Business Owners (SBO) for employer businesses, the Annual Survey of Entrepreneurs (ASE), the Business R&D and Innovation for Microbusinesses survey (BRDI-M), and the innovation section of the Business R&D and Innovation Survey (BRDI-S). https://www.census.gov/programs-surveys/abs.html 2020-04-30 00:00:00.0
545 Annual Economic Surveys: Annual Business Survey abscs 2018 https://api.census.gov/data/2018/abscs NA unidentified The Annual Business Survey (ABS) provides information on selected economic and demographic characteristics for businesses and business owners by sex, ethnicity, race, and veteran status. Further, the survey measures research and development (for microbusinesses), new business topics such as innovation and technology, as well as other business characteristics. The U.S. Census Bureau and the National Center conduct the ABS jointly for Science and Engineering Statistics within the National Science Foundation. The ABS replaces the five-year Survey of Business Owners (SBO) for employer businesses, the Annual Survey of Entrepreneurs (ASE), the Business R&D and Innovation for Microbusinesses survey (BRDI-M), and the innovation section of the Business R&D and Innovation Survey (BRDI-S). https://www.census.gov/programs-surveys/abs.html 2020-10-26 00:00:00.0

So, we can see there are a lot. For a concrete example, let’s examine the effect of the Patient Protection and Affordable Care Act on uninsurance rates in US states.

For this, we will use the Small Area Health Insurance Estimates program. This program combines data from the ACS and data from individual states on other health insurance programs to produce model-based estimates of the overall rates of insurance and uninsurance for states and counties.

Census maintains a nice website for browsing the data and downloading images of data visualizations, but anything custom can be a process. In R this is no problem.

Below, we first look up the variables available in the SAHIE data, then we do an extract and create a dataset for Texas and California for unsinsurance rates by race/ethnicity. Next, we create a line plot of the uninsurance time series for each state and demographic group.

#timeseries/poverty/saipe
sahevars<-listCensusMetadata(name = "timeseries/healthins/sahie", type = "v")
head(sahevars)
## # A tibble: 6 x 7
##   name   label                   concept    predicateType group limit required  
##   <chr>  <chr>                   <chr>      <chr>         <chr> <chr> <chr>     
## 1 NIPR_~ Number in Demographic ~ Uncertain~ int           N/A   0     <NA>      
## 2 NIPR_~ Number in Demographic ~ Estimate   int           N/A   0     <NA>      
## 3 AGECAT Age Category            Demograph~ int           N/A   6     default d~
## 4 NIC_PT Number Insured, Estima~ Estimate   int           N/A   0     <NA>      
## 5 GEOID  State+County FIPS Code  Uncertain~ int           N/A   0     <NA>      
## 6 STATE  State FIPS Code         Geographi~ int           N/A   0     <NA>
#SAEPOVRTALL_PT

Get the data for states

ui_rates<-getCensus(name = "timeseries/healthins/sahie",
          vars = c("STATE", "YEAR","RACECAT", "PCTUI_PT"), 
          region = "state:*")



head(ui_rates)
## # A tibble: 6 x 5
##   state STATE YEAR  RACECAT PCTUI_PT
##   <chr> <chr> <chr> <chr>      <dbl>
## 1 01    01    2006  0           15.7
## 2 01    01    2006  1           12.8
## 3 01    01    2006  2           20.5
## 4 01    01    2006  3           34.1
## 5 02    02    2006  0           19.4
## 6 02    02    2006  1           15.7

Clean up the data and make a line plot:

ui_rates%>%
  mutate(yr=as.numeric(YEAR), uninsure_rate=as.numeric(PCTUI_PT))%>%
  filter(STATE%in%c("06", "48"), RACECAT!="0")%>%
  select(STATE,  yr,RACECAT, uninsure_rate)%>%
  mutate(new_race=case_when( .$RACECAT=='1' ~ "NH White", 
                    .$RACECAT=='2' ~ "NH Black",
                    .$RACECAT=='3' ~ "Hispanic"))%>%
  ggplot(aes(x=yr, y=uninsure_rate))+geom_line(aes(color= new_race, linetype=STATE, group=interaction(STATE, new_race)))+ylim(low=0,high=50)+ylab("% Uninsured")+xlab("Year")+ggtitle("% Uninsured in Texas and California by Race/Ethnicty", subtitle = "SAHIE Estimates")

Another big Census estimate program focus on poverty and income, and is called the Small Area Income and Poverty Estimate, or SAIPE program. Like the SAHIE, the SAIPE creates model based estimates of income and poverty for states, counties and school districts on an annual basis.

Below, we do an extract from the SAIPE for Texas and California and create a line plot for the under-4 and total poverty rates for each state over time.

saipvars<-listCensusMetadata(name = "timeseries/poverty/saipe", type = "v")
head(saipvars)
## # A tibble: 6 x 7
##   name      label                     predicateType group limit concept required
##   <chr>     <chr>                     <chr>         <chr> <chr> <chr>   <chr>   
## 1 SAEPOVRT~ Ages 5-17 in Families in~ float         N/A   0     <NA>    <NA>    
## 2 SAEMHI_U~ Median Household Income ~ int           N/A   0     <NA>    <NA>    
## 3 SAEPOVRT~ Ages 0-4 in Poverty, Rat~ float         N/A   0     <NA>    <NA>    
## 4 SAEPOVRT~ Ages 0-4 in Poverty, Rat~ float         N/A   0     <NA>    <NA>    
## 5 SAEPOVRT~ All ages in Poverty, Rat~ float         N/A   0     <NA>    <NA>    
## 6 SAEPOVAL~ All ages in Poverty, Cou~ int           N/A   0     <NA>    <NA>
#SAEPOVRTALL_PT
 
p_rates<-getCensus(name = "timeseries/poverty/saipe",
          vars = c("STATE", "YEAR", "SAEPOVRTALL_PT", "SAEPOVRT0_4_PT"), 
          region = "state:*")

p_rates%>%
  mutate(yr=as.numeric(YEAR), tot_pov_rate=as.numeric(SAEPOVRTALL_PT), child04_poverty=as.numeric(SAEPOVRT0_4_PT))%>%
  filter(STATE%in%c("06", "48"))%>%
  select(STATE,  yr, tot_pov_rate, child04_poverty)%>%
  ggplot(aes(x=yr, y=child04_poverty))+geom_line(aes(color= STATE, group=STATE))+ylim(low=0,high=40)+ylab("% In Poverty")+xlab("Year")+ggtitle("% Children under age 4 Below the Poverty Line in Texas and California ", subtitle = "SAIPE Estimates")

p_rates%>%
  mutate(yr=as.numeric(YEAR), tot_pov_rate=as.numeric(SAEPOVRTALL_PT), child04_poverty=as.numeric(SAEPOVRT0_4_PT))%>%
  filter(STATE%in%c("06", "48"))%>%
  select(STATE,  yr, tot_pov_rate, child04_poverty)%>%
  ggplot(aes(x=yr, y=tot_pov_rate))+
  geom_line(aes(color= STATE, group=STATE))+
  ylim(low=0,high=40)+
  ylab("% In Poverty")+
  xlab("Year")+
  ggtitle("% Below the Poverty Line in Texas and California ", subtitle = "SAIPE Estimates")

Using the ipumsr package

The previous examples focused on getting data for places from several Census program. This section focuses on getting data on individuals.

Each year, when the ACS is done, or on a decennial year when the Census is carried out, each individual survey is published in a Public Use Microdata file. For example, in the 2011 - 2016 ACS 5 year data release, there were 15,681,972 persons in the data, while the 1 year file contained 3,156,487 persons.

So, you can get a lot of data!

To get access to the microdata, you can get the files directly from Census, or use the data that has been cleaned and homogenized by the IPUMS project at the University of Minnesota Population Center.

In addition to the ACS, you can get decennial Census data going back to the 1790 Census, international census data for nearly 100 countries, Current Population Survey data, Demographic and Health Survey data, the National Historic GIS, and more.

Basically, you can spend your entire career working with the data at the IPUMS project.

The benefit to using IPUMS is that you can download multiple years of data at a single time, with as many or as few variables as you want, for places you want. Moreover, you can get the data in multiple formats (SAS, Stata, SPSS, and R), with a fully formatted codebook for everything.

The staff at IPUMS have created a R package to read in IPUMS data (and they’re working on an API too!!) called ipumsr. It will read data from any IPUMS project.

Here is a link to an introduction to the package written by IPUMS staff.

Here is a CPS example done by IPUMS staff and a NHGIS example.

Getting your own IPUMS data

First create an account with the IPUMS project, let them know who you are and what you will be using their data for, and most importantly that you will not be using it for EVIL!

Browse the IPUMS data source of your choice

Submit your data extract request

Wait….

Download the data file and the XML file, and save them somewhere you will remember. To use the ipumsr package, download the DDI codebook and the .DAT unformatted data file. Otherwise, we could download the stata or SPSS format files and read them in using the haven library, easy peasy.

IPUMS - Waiting

IPUMS - Data

Then use ipumsr!

if (!require("ipumsr")) stop("Reading IPUMS data into R requires the ipumsr package. It can be installed using the following command: install.packages('ipumsr')")
## Loading required package: ipumsr
ddi <- read_ipums_ddi("~/OneDrive - University of Texas at San Antonio//usa_00071.xml")
data <- read_ipums_micro(ddi)


names(data)

So, now we have the 2016 ACS 1 year data read into memory in R, and we could do anything we want now.

I use these data for lots of reasons, but I’ll show a few general things that you need to do in order to use them.

Recoding IPUMS variables

Survey data are a mess! They have missing data codes, top codes, numerical values when you want categorical values, and vice versa. Generally, you have to recode variables in order to have them be useful.

Here, I recode several things into standards used in social demographic research.

names(data)<-tolower(names(data))
data<-haven::zap_labels(data)
library(car)
## Loading required package: carData
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
#survey weights
data$pwt <- data$perwt/100
data$hwt <- data$hhwt/100

#race/ethnicity 
data$hisp <- Recode(data$hispan, recodes = "9=NA; 1:4='Hispanic'; 0='NonHispanic'")
data$race_rec <- Recode(data$race, recodes = "1='White'; 2='Black'; 3='Other'; 4:6='Asian'; 7:9='Other'")
data$race_eth <- interaction(data$hisp, data$race_rec, sep = "_")
data$race_eth  <- as.factor(ifelse(substr(as.character(data$race_eth),1,8) == "Hispanic", "Hispanic", as.character(data$race_eth)))
data$race_eth <- relevel(data$race_eth, ref = "NonHispanic_White")

#Gender
data$male <- ifelse(data$sex == 1,1,0)

#foreign born status
data$usborn <- Recode(data$bpl, recodes = "1:120=1; 121:900=0; else=NA")

#educational attainment
data$educ_level<- Recode(data$educd, recodes = "2:61='0LT_HS';62:64='1_HSD/GED';65:80='2_somecoll';90:100='2_somecoll'; 81:83='3_AssocDegree';101='4_bachelordegree'; 110:116='4_BAplus_GradDegree'; else=NA")


#Employment status
data$employed <- Recode(data$empstatd, recodes = "10:12=1; 20:22=0; else=NA")

data$inc_wage<- Recode(data$incwage, recodes = "0=NA")

So now we have lots of things recoded, we can do some descriptive analysis. For example, let’s look at income by gender in Texas cities

data<-data%>%
  filter(labforce==2,statefip=="48", age>18) %>%
  mutate(newwage= ifelse(incwage%in%c(999998,999999), NA, incwage),
         sexrecode=ifelse(sex==1, "male", "female"),
         cityrec = case_when(.$met2013==11100~"Amarillo", 
                            .$met2013 == 12420~"Austin",
                            .$met2013==15180 ~"Brownsville", 
                            .$met2013== 17780 ~ "College Station",
                            .$met2013== 18580 ~ "Corpus Christi",
                            .$met2013== 21340 ~ "El Paso",
                            .$met2013== 26420 ~ "Houston",
                            .$met2013== 29700~ "Laredo",
                            .$met2013== 32580~ "McAllen",
                            .$met2013== 47380~ "Waco", 
                            .$met2013== 41700 ~ "San Antonio",
                            .$met2013== 19100 ~ "Dallas"))

data%>%
  group_by(sexrecode, cityrec)%>%
  summarise(med_income=median(newwage, na.rm=T), n=n())%>%
  ggplot(aes(cityrec, med_income))+geom_bar(aes(fill=sexrecode),position="dodge", stat="identity")+ylab("Median Income")+xlab("Metro Area")+theme(axis.text.x = element_text(angle = 45, hjust = 1))
## `summarise()` has grouped output by 'sexrecode'. You can override using the `.groups` argument.

We can do a regression analysis of income differences by various factors.

Before we do this, since the ACS is a complex survey, we cannot simply use regular methods for regression analysis, we must cluster standard errors by sampling cluster and strata and factor in person-weights in the analysis.

This means we must define a formal survey design object.

I restrict the analysis to only Texas and control for various demographic and socioeconomic factors, then compare across cities.

data<-data%>%
  filter(employed==1)%>%
  na.omit()

library(survey)
## Loading required package: grid
## Loading required package: Matrix
## Loading required package: survival
## 
## Attaching package: 'survey'
## The following object is masked from 'package:graphics':
## 
##     dotchart
library(splines)
design<-svydesign(ids=~cluster, strata=~strata, weights=~pwt, data=data)

#Base city difference model
inc_mod_1<- svyglm(log(inc_wage)~cityrec,
                 design = design)

#city difference after controlling for demographic factors
inc_mod<- svyglm(log(inc_wage)~male+usborn+educ_level+bs(age)+cityrec,
                 design = design)

summary(inc_mod_1)
## 
## Call:
## svyglm(formula = log(inc_wage) ~ cityrec, design = design)
## 
## Survey design:
## svydesign(ids = ~cluster, strata = ~strata, weights = ~pwt, data = data)
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)    
## (Intercept)            10.290456   0.037672 273.157  < 2e-16 ***
## cityrecAustin           0.213217   0.040130   5.313 1.08e-07 ***
## cityrecBrownsville     -0.272902   0.051877  -5.261 1.44e-07 ***
## cityrecCollege Station -0.158502   0.061568  -2.574   0.0100 *  
## cityrecCorpus Christi   0.003041   0.047182   0.064   0.9486    
## cityrecDallas           0.167271   0.038339   4.363 1.29e-05 ***
## cityrecEl Paso         -0.250072   0.045551  -5.490 4.04e-08 ***
## cityrecHouston          0.172000   0.038785   4.435 9.24e-06 ***
## cityrecLaredo          -0.238425   0.056807  -4.197 2.71e-05 ***
## cityrecMcAllen         -0.260690   0.047899  -5.442 5.28e-08 ***
## cityrecSan Antonio     -0.038517   0.040055  -0.962   0.3363    
## cityrecWaco            -0.119537   0.054446  -2.196   0.0281 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 1.084504)
## 
## Number of Fisher Scoring iterations: 2
summary(inc_mod)
## 
## Call:
## svyglm(formula = log(inc_wage) ~ male + usborn + educ_level + 
##     bs(age) + cityrec, design = design)
## 
## Survey design:
## svydesign(ids = ~cluster, strata = ~strata, weights = ~pwt, data = data)
## 
## Coefficients:
##                                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                    8.412593   0.038627 217.793  < 2e-16 ***
## male                           0.427110   0.007469  57.183  < 2e-16 ***
## usborn                         0.189738   0.009944  19.080  < 2e-16 ***
## educ_level1_HSD/GED            0.236177   0.014200  16.632  < 2e-16 ***
## educ_level2_somecoll           0.395092   0.014812  26.674  < 2e-16 ***
## educ_level3_AssocDegree        0.572162   0.017539  32.621  < 2e-16 ***
## educ_level4_bachelordegree     0.876107   0.014677  59.692  < 2e-16 ***
## educ_level4_BAplus_GradDegree  1.129654   0.016038  70.436  < 2e-16 ***
## bs(age)1                       2.661177   0.062358  42.676  < 2e-16 ***
## bs(age)2                       0.714695   0.077986   9.164  < 2e-16 ***
## bs(age)3                       0.422052   0.132645   3.182  0.00146 ** 
## cityrecAustin                  0.064425   0.033828   1.904  0.05685 .  
## cityrecBrownsville            -0.194302   0.044226  -4.393 1.12e-05 ***
## cityrecCollege Station        -0.125369   0.050279  -2.493  0.01265 *  
## cityrecCorpus Christi         -0.020340   0.040996  -0.496  0.61978    
## cityrecDallas                  0.075777   0.032368   2.341  0.01923 *  
## cityrecEl Paso                -0.230730   0.037979  -6.075 1.25e-09 ***
## cityrecHouston                 0.093941   0.032716   2.871  0.00409 ** 
## cityrecLaredo                 -0.153910   0.047836  -3.217  0.00129 ** 
## cityrecMcAllen                -0.182294   0.039815  -4.579 4.69e-06 ***
## cityrecSan Antonio            -0.085836   0.033841  -2.536  0.01120 *  
## cityrecWaco                   -0.102159   0.044747  -2.283  0.02243 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 0.758806)
## 
## Number of Fisher Scoring iterations: 2

Other Resources

Miktek

To build pdf’s you’ll need a version of Latex installed, Miktek is a good option

R-markdown cheat sheets

Rstudio keeps a variety of cheat sheets for various topics, they can be helpful in a pinch

UCLA Statistical computing help

This page has lots of examples of using R for various types of analysis.

Other examples

On my Rpubs page I have lots of examples of various types of analysis using R and you can get the data for these on my Github data page

Thanks!

Let me know how I can help!

[@Coreysparks1](https://twitter.com/CoreySparks1)

Github

Rpubs

UTSA Demography

LS0tDQp0aXRsZTogIkFuYWx5emluZyBDZW5zdXMgRGF0YSBVc2luZyBSIg0KYXV0aG9yOiAiQ29yZXkgUy4gU3BhcmtzLCBQaC5ELiAtIFVuaXZlcnNpdHkgb2YgVGV4YXMgYXQgU2FuIEFudG9uaW8iDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlQiwgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHRpYmJsZQ0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCg0KIyMgV2VsY29tZSENCg0KIyMgU3RydWN0dXJlIG9mIHdvcmtzaG9wDQoxKSBBYm91dCBtZQ0KMikgVHlwZXMgb2YgY2Vuc3VzIGRhdGENCjMpIFRoZSBDZW5zdXMgQVBJDQo0KSBVc2luZyBgdGlkeWNlbnN1c2AgYW5kIGBjZW5zdXNhcGlgIHRvIGdldCBkYXRhIG9uIHBsYWNlcw0KNSkgVXNpbmcgdGhlIGBpcHVtc3JgIHBhY2thZ2UgdG8gZ2V0IGRhdGEgb24gcGVvcGxlDQoNCiMjIEFib3V0IG1lDQpJIGFtIGFuIGFzc29jaWF0ZSBwcm9mZXNzb3IgaW4gdGhlIFtVVFNBIERlcGFydG1lbnQgb2YgRGVtb2dyYXBoeV0oaHR0cHM6Ly9oY2FwLnV0c2EuZWR1L2RlbW9ncmFwaHkvKSBhbmQgaGF2ZSBiZWVuIGF0IFVUU0Egc2luY2UgMjAwNi4gDQoNClJlc2VhcmNoIGludGVyZXN0cyBpbmNsdWRlIGRhdGEgc2NpZW5jZSwgQmF5ZXNpYW4gbWV0aG9kcywgZWR1Y2F0aW9uIGRlbW9ncmFwaHkgYW5kIGhlYWx0aCBkaXNwYXJpdGllcy4NCiBcbmV3cGFnZQ0KDQoNCiMjIFR5cGVzIG9mIENlbnN1cyBEYXRhIA0KDQpEZWNlbm5pYWwgQ2Vuc3VzDQoNCkFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkNCg0KQ291bnR5IEJ1c2luZXNzIFBhdHRlcm5zDQoNClBvcHVsYXRpb24gRXN0aW1hdGVzIFByb2dyYW0gLSBTQUlQRSBhbmQgU0FISUUNClxuZXdwYWdlDQoNCiMjIyBEZWNlbm5pYWwgQ2Vuc3VzIFN1bW1hcnkgRmlsZSAxIA0KVGhlIENlbnN1cyBTdW1tYXJ5IEZpbGUgMShTRiAxKSBjb250YWlucyB0aGUgZGF0YSBjb21waWxlZCBmcm9tIHRoZSBxdWVzdGlvbnMgYXNrZWQgb2YgYWxsIHBlb3BsZSBhbmQgYWJvdXQgZXZlcnkgaG91c2luZyB1bml0LiANCg0KUG9wdWxhdGlvbiBpdGVtcyBpbmNsdWRlIHNleCwgYWdlLCByYWNlLCBIaXNwYW5pYyBvciBMYXRpbm8gb3JpZ2luLCBob3VzZWhvbGQgcmVsYXRpb25zaGlwLCBob3VzZWhvbGQgdHlwZSwgaG91c2Vob2xkIHNpemUsIGZhbWlseSB0eXBlLCBmYW1pbHkgc2l6ZSwgYW5kIGdyb3VwIHF1YXJ0ZXJzLiBIb3VzaW5nIGl0ZW1zIGluY2x1ZGUgb2NjdXBhbmN5IHN0YXR1cywgdmFjYW5jeSBzdGF0dXMsIGFuZCB0ZW51cmUgKHdoZXRoZXIgYSBob3VzaW5nIHVuaXQgaXMgb3duZXItb2NjdXBpZWQgb3IgcmVudGVyLW9jY3VwaWVkKS4gDQoNClNGIDEgaW5jbHVkZXMgcG9wdWxhdGlvbiBhbmQgaG91c2luZyBjaGFyYWN0ZXJpc3RpY3MgZm9yIHRoZSB0b3RhbCBwb3B1bGF0aW9uLCBwb3B1bGF0aW9uIHRvdGFscyBmb3IgYW4gZXh0ZW5zaXZlIGxpc3Qgb2YgcmFjZSAoQW1lcmljYW4gSW5kaWFuIGFuZCBBbGFza2EgTmF0aXZlIHRyaWJlcywgQXNpYW4sIGFuZCBOYXRpdmUgSGF3YWlpYW4gYW5kIE90aGVyIFBhY2lmaWMgSXNsYW5kZXIpIGFuZCBIaXNwYW5pYyBvciBMYXRpbm8gZ3JvdXBzLCBhbmQgcG9wdWxhdGlvbiBhbmQgaG91c2luZyBjaGFyYWN0ZXJpc3RpY3MgZm9yIGEgbGltaXRlZCBsaXN0IG9mIHJhY2UgYW5kIEhpc3BhbmljIG9yIExhdGlubyBncm91cHMuICANCg0KVGhlIGRlY2VubmlhbCBDZW5zdXMgc3VtbWFyeSBmaWxlIDEgKipfZG9lcyBub3RfKiogY29udGFpbiBpbmZvcm1hdGlvbiBvbiBlZHVjYXRpb24sIHNvY2lvZWNvbm9taWMgY29uZGl0aW9ucyBvciBvdGhlciBkZXRhaWxlZCBjaGFyYWN0ZXJpc3RpY3Mgb2YgdGhlIHBvcHVsYXRpb24uIA0KDQpVcCB1bnRpbCAyMDEwLCB0aGUgQ2Vuc3VzIGJ1cmVhdSBzdXJ2ZXllZCAxIG91dCBvZiBldmVyeSA2IGhvdXNlaG9sZHMgdG8gbWVhc3VyZSB0aGVzZSBjaGFyYWN0ZXJpc3RpY3MsIHdoaWNoIHdhcyByZWZlcnJlZCB0byBhcyB0aGUgQ2Vuc3VzICJsb25nIGZvcm0iLCB3aGljaCB3YXMgdGFidWxhdGVkIGludG8gYSBwcm9kdWN0IGNhbGxlZCB0aGUgU3VtbWFyeSBGaWxlIDMuIFRoZSB5ZWFyIDIwMDAgd2FzIHRoZSBsYXN0IHllYXIgdGhpcyBzdXJ2ZXkgd2FzIGNvbmR1Y3RlZCwgYW5kIGJlZ2lubmluZyBpbiAyMDA1LCB0aGUgQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSByZXBsYWNlZCB0aGUgImxvbmcgZm9ybSIgYXMgdGhlIHRvb2wgdG8gbWVhc3VyZSBzb2Npb2Vjb25vbWljIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgcG9wdWxhdGlvbi4gKFVTIENlbnN1cyBCdXJlYXUsIDIwMTApDQoNCiMjIyBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IFN1bW1hcnkgRmlsZQ0KVGhlIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgKEFDUykgaXMgcGFydCBvZiB0aGUgVS5TLiBDZW5zdXMgQnVyZWF1J3MgU3VydmV5DQpQcm9ncmFtIGFuZCBpcyBkZXNpZ25lZCB0byBwcm92aWRlIGN1cnJlbnQgZGVtb2dyYXBoaWMsIHNvY2lhbCwgZWNvbm9taWMsIGFuZCBob3VzaW5nDQplc3RpbWF0ZXMgdGhyb3VnaG91dCB0aGUgZGVjYWRlLiANCg0KVGhlIEFDUyBwcm92aWRlcyBpbmZvcm1hdGlvbiBvbiBtb3JlIHRoYW4gNDAgdG9waWNzLCBpbmNsdWRpbmcgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCwgbGFuZ3VhZ2Ugc3Bva2VuIGF0IGhvbWUsIGFiaWxpdHkgdG8gc3BlYWsgRW5nbGlzaCwgdGhlIGZvcmVpZ24gYm9ybiwgbWFyaXRhbCBzdGF0dXMsIG1pZ3JhdGlvbiwgYW5kIG1hbnkgbW9yZS4gRWFjaCB5ZWFyIHRoZSBzdXJ2ZXkgcmFuZG9tbHkgc2FtcGxlcyBhcm91bmQgMy41IG1pbGxpb24gYWRkcmVzc2VzIGFuZCBwcm9kdWNlcyBzdGF0aXN0aWNzIHRoYXQgY292ZXIgMS15ZWFyIGFuZCA1LXllYXIgcGVyaW9kcyBmb3IgZ2VvZ3JhcGhpYyBhcmVhcyBpbiB0aGUgVW5pdGVkIFN0YXRlcyBhbmQgUHVlcnRvIFJpY28sIHJhbmdpbmcgZnJvbSBuZWlnaGJvcmhvb2RzIHRvIGNvbmdyZXNzaW9uYWwgZGlzdHJpY3RzIHRvIHRoZSBlbnRpcmUgbmF0aW9uLiANCg0KVGhlICoqQUNTIDEteWVhcioqIGVzdGltYXRlcyBhcmUgcHVibGlzaGVkIGZvciBhcmVhcyB0aGF0IGhhdmUgcG9wdWxhdGlvbnMgb2YgNjUsMDAwIG9yIG1vcmUuIA0KDQpUaGUgKipBQ1MgNS15ZWFyKiogZXN0aW1hdGVzIGFyZSBwdWJsaXNoZWQgZm9yIGFsbCBnZW9ncmFwaGljIGFyZWFzLCBpbmNsdWRpbmcgQ2Vuc3VzIHRyYWN0cywgYmxvY2sgZ3JvdXBzLCBBbWVyaWNhbiBJbmRpYW4gYXJlYXMsIGNvcmUtYmFzZWQgc3RhdGlzdGljYWwgYXJlYXMsIGNvbWJpbmVkIHN0YXRpc3RpY2FsIGFyZWFzLCBDb25ncmVzc2lvbmFsIGRpc3RyaWN0cywgYW5kIHN0YXRlIGxlZ2lzbGF0aXZlIGRpc3RyaWN0cy4gDQoNClRoZSBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IFN1bW1hcnkgRmlsZSAoQUNTU0YpIGlzIGEgdW5pcXVlIGRhdGEgcHJvZHVjdCB0aGF0IGluY2x1ZGVzIGFsbCB0aGUgZXN0aW1hdGVzIGFuZCBtYXJnaW5zIG9mIGVycm9yIGZyb20gdGhlIGRldGFpbGVkIHRhYmxlcyBhbmQgZ2VvZ3JhcGhpZXMgdGhhdCBhcmUgcHVibGlzaGVkIGZvciB0aGUgQUNTLiBEYXRhIGNvbnRhaW5lZCBpbiB0aGUgQUNTIFN1bW1hcnkgRmlsZSBjb3ZlciBkZW1vZ3JhcGhpYywgc29jaWFsLCBlY29ub21pYywgYW5kIGhvdXNpbmcgc3ViamVjdCBhcmVhcy4gDQoNClRoZXNlIGRhdGEgcmVwcmVzZW50IHRvdGFscyBvZiBwb3B1bGF0aW9uIGNvdW50cywgYWxvbmcgd2l0aCB0aGUgbWVhc3VyZW1lbnQgZXJyb3JzIGluIHRob3NlIGNvdW50cyBmb3IgcGxhY2VzLCBub3QgZm9yIGluZGl2aWR1YWxzLCB3aGljaCBpcyB0aGUgc3ViamVjdCBvZiB0aGUgQUNTIFB1YmxpYyBVc2UgTWljcm9kYXRhLg0KIA0KIyMjIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgUHVibGljIFVzZSBNaWNyb2RhdGENClRoZSBQdWJsaWMgVXNlIE1pY3JvZGF0YSBTYW1wbGUgKipfKFBVTVMpXyoqIGNvbnRhaW5zIGEgc2FtcGxlIG9mIGFjdHVhbCByZXNwb25zZXMgdG8gdGhlIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkgKEFDUykuIFRoZSBQVU1TIGRhdGFzZXQgaW5jbHVkZXMgdmFyaWFibGVzIGZvciBuZWFybHkgZXZlcnkgcXVlc3Rpb24gb24gdGhlIHN1cnZleSwgYXMgd2VsbCBhcyBtYW55IG5ldyB2YXJpYWJsZXMgdGhhdCB3ZXJlIGRlcml2ZWQgYWZ0ZXIgdGhlIGZhY3QgZnJvbSBtdWx0aXBsZSBzdXJ2ZXkgcmVzcG9uc2VzIChzdWNoIGFzIHBvdmVydHkgc3RhdHVzKS4gDQoNCkVhY2ggcmVjb3JkIGluIHRoZSBmaWxlIHJlcHJlc2VudHMgYSAqKl9zaW5nbGUgcGVyc29uLCBvci0taW4gdGhlIGhvdXNlaG9sZC1sZXZlbCBkYXRhc2V0LS1hIHNpbmdsZSBob3VzaW5nIHVuaXRfKiouIEluIHRoZSBwZXJzb24tbGV2ZWwgZmlsZSwgaW5kaXZpZHVhbHMgYXJlIG9yZ2FuaXplZCBpbnRvIGhvdXNlaG9sZHMsIG1ha2luZyBwb3NzaWJsZSB0aGUgc3R1ZHkgb2YgcGVvcGxlIHdpdGhpbiB0aGUgY29udGV4dHMgb2YgdGhlaXIgZmFtaWxpZXMgYW5kIG90aGVyIGhvdXNlaG9sZCBtZW1iZXJzLiANCg0KUFVNUyBmaWxlcyBmb3IgYW4gaW5kaXZpZHVhbCB5ZWFyLCBzdWNoIGFzIDIwMTUsIGNvbnRhaW4gZGF0YSBvbiBhcHByb3hpbWF0ZWx5IG9uZSBwZXJjZW50IG9mIHRoZSBVbml0ZWQgU3RhdGVzIHBvcHVsYXRpb24uIFBVTVMgZmlsZXMgY292ZXJpbmcgYSBmaXZlLXllYXIgcGVyaW9kLCBzdWNoIGFzIDIwMTEtMjAxNSwgY29udGFpbiBkYXRhIG9uIGFwcHJveGltYXRlbHkgZml2ZSBwZXJjZW50IG9mIHRoZSBVbml0ZWQgU3RhdGVzIHBvcHVsYXRpb24uIA0KDQpUaGUgUFVNUyBmaWxlcyBhcmUgbXVjaCBtb3JlIGZsZXhpYmxlIHRoYW4gdGhlIGFnZ3JlZ2F0ZSBkYXRhIHByb2R1Y2VkIGluIHRoZSBBQ1Mgc3VtbWFyeSBmaWxlcywgdGhvdWdoIHRoZSBQVU1TIGFsc28gdGVuZCB0byBiZSBtb3JlIGNvbXBsaWNhdGVkIHRvIHVzZS4gV29ya2luZyB3aXRoIFBVTVMgZGF0YSBnZW5lcmFsbHkgaW52b2x2ZXMgZG93bmxvYWRpbmcgbGFyZ2UgZGF0YXNldHMgb250byBhIGxvY2FsIGNvbXB1dGVyIGFuZCBhbmFseXppbmcgdGhlIGRhdGEgdXNpbmcgc3RhdGlzdGljYWwgc29mdHdhcmUgc3VjaCBhcyBSLCBTUFNTLCBTdGF0YSwgb3IgU0FTLiANCg0KU2luY2UgYWxsIEFDUyByZXNwb25zZXMgYXJlIHN0cmljdGx5IGNvbmZpZGVudGlhbCwgbWFueSB2YXJpYWJsZXMgaW4gdGhlIFBVTVMgZmlsZXMgaGF2ZSBiZWVuIG1vZGlmaWVkIGluIG9yZGVyIHRvIHByb3RlY3QgdGhlIGNvbmZpZGVudGlhbGl0eSBvZiBzdXJ2ZXkgcmVzcG9uZGVudHMuIEZvciBpbnN0YW5jZSwgcGFydGljdWxhcmx5IGhpZ2ggaW5jb21lcyBhcmUgInRvcC1jb2RlZCwiIHVuY29tbW9uIGJpcnRocGxhY2Ugb3IgYW5jZXN0cnkgcmVzcG9uc2VzIGFyZSBncm91cGVkIGludG8gYnJvYWRlciBjYXRlZ29yaWVzLCBhbmQgdGhlIFBVTVMgZmlsZXMgcHJvdmlkZSBhIHZlcnkgbGltaXRlZCBzZXQgb2YgZ2VvZ3JhcGhpYyB2YXJpYWJsZXMsIGluY2x1ZGluZyBzdGF0ZSwgbWV0cm9wb2xpdGFuIGFyZWEgYW5kIHB1YmxpYyB1c2UgbWljcm9kYXRhIGFyZWEsIG9yIFBVTUEuIA0KDQpXaGlsZSBQVU1TIGZpbGVzIGNvbnRhaW4gY2FzZXMgZnJvbSBuZWFybHkgZXZlcnkgdG93biBhbmQgY291bnR5IGluIHRoZSBjb3VudHJ5LCB0b3ducyBhbmQgY291bnRpZXMgKGFuZCBvdGhlciBsb3ctbGV2ZWwgZ2VvZ3JhcGh5KSBhcmUgbm90IGlkZW50aWZpZWQgYnkgYW55IHZhcmlhYmxlcyBpbiB0aGUgUFVNUyBkYXRhc2V0cy4gVGhlIG1vc3QgZGV0YWlsZWQgdW5pdCBvZiBnZW9ncmFwaHkgY29udGFpbmVkIGluIHRoZSBQVU1TIGZpbGVzIGlzIHRoZSAqKl9QdWJsaWMgVXNlIE1pY3JvZGF0YSBBcmVhIChQVU1BKV8qKi4gUFVNQXMgYXJlIHNwZWNpYWwgbm9uLW92ZXJsYXBwaW5nIGFyZWFzIHRoYXQgcGFydGl0aW9uIGVhY2ggc3RhdGUgaW50byBjb250aWd1b3VzIGdlb2dyYXBoaWMgdW5pdHMgY29udGFpbmluZyBubyBmZXdlciB0aGFuIDEwMCwwMDAgcGVvcGxlIGVhY2guIFRoZSAyMDExLTIwMTUgNS15ZWFyIEFDUyBQVU1TIGZpbGVzIHJlbHkgb24gUFVNQSBib3VuZGFyaWVzIHRoYXQgd2VyZSBkcmF3biBieSBzdGF0ZSBnb3Zlcm5tZW50cyBhZnRlciB0aGUgMjAwMCBhbmQgMjAxMCBDZW5zdXMuIA0KDQpUaGUgUFVNUyBkYXRhIGFyZSBtb3N0IGVhc2lseSBhY2Nlc3NlZCBmcm9tIHRoZSBVbml2ZXJzaXR5IG9mIE1pbm5lc290YSdzICoqX0ludGVncmF0ZWQgUHVibGljIFVzZSBNaWNyb2RhdGEgU2VyaWVzIChJUFVNUylfKiogZGF0YSBhcmNoaXZlLiBUaGlzIGRhdGEgc291cmNlIHByb2Nlc3NlcyB0aGUgZGF0YSBwcm9kdWNlZCBieSB0aGUgQ2Vuc3VzIEJ1cmVhdSBpbnRvIG1vcmUgZWFzaWx5IGNvbXBhcmFibGUgYW5kIHJlYWRhYmxlIGRhdGEgZmlsZXMgdGhhdCBhcmUgYXZhaWxhYmxlIGZvciBhbGwgeWVhcnMgb2YgdGhlIGRlY2VubmlhbCBDZW5zdXMgYW5kIHRoZSBBQ1MuIChSdWdnbGVzIGV0IGFsLiwgMjAxNSkNCg0KXG5ld3BhZ2UNCg0KIyBVc2luZyB0aGUgdGlkeWNlbnN1cyBwYWNrYWdlDQpUaGV5IFt0aWR5Y2Vuc3VzXShodHRwczovL2dpdGh1Yi5jb20vd2Fsa2Vya2UvdGlkeWNlbnN1cykgaXMgcGFydCBvZiB0aGUgYHRpZHl2ZXJzZWAsIGFuZCB3YXMgd3JpdHRlbiBhbmQgbWFpbnRhaW5lZCBieSBbRHIuIEt5bGUgV2Fsa2VyXShodHRwOi8vcGVyc29uYWwudGN1LmVkdS9reWxld2Fsa2VyLykgYXQgVENVLg0KDQpJdCBhbGxvd3MgeW91IHRvIGR5bmFtaWNhbGx5IGRvd25sb2FkIGFuZCBtYXAgZGF0YSBmcm9tIHRoZSBkZWNlbm5pYWwgQ2Vuc3VzIGFuZCBBQ1MgZm9yIGFueSBsZXZlbCBvZiBbQ2Vuc3VzIGdlb2dyYXBoeV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9nZW8vcmVmZXJlbmNlL3dlYmF0bGFzLyksIGV4Y2VwdCBibG9ja3MhDQoNCklmIHlvdSB3YW50IGRhdGEgb24gcGxhY2VzLCB0aGlzIGlzIHRoZSBlYXNpZXN0IHdheSB0byBnZXQgaXQuDQoNCiMjIyBDZW5zdXMgdGFibGUgbmFtZXMNClRoZSBDZW5zdXMgcHVibGlzaGVzIGRhdGEgZm9yIHBsYWNlcyBpbiAqKl9zdW1tYXJ5IHRhYmxlc18qKi4gVGhlc2UgZm9sbG93IGEgcGF0dGVybiBmb3IgdGhlaXIgbmFtZXMsIHlvdSBjYW4gZmluZCBhIGRlc2NyaXB0aW9uIG9mIHRoaXMgW2hlcmVdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvcHJvZ3JhbXMtc3VydmV5cy9hY3MvZ3VpZGFuY2Uvd2hpY2gtZGF0YS10b29sL3RhYmxlLWlkcy1leHBsYWluZWQuaHRtbCkuIFRoZSBiaWdnZXN0IHByb2JsZW0gd2l0aCBmaW5kaW5nIGRhdGEgZnJvbSB0aGUgQ2Vuc3VzIGlzIGtub3dpbmcgdGhlIHRhYmxlIG5hbWUgeW91IHdhbnQuIA0KDQpZb3UgY2FuIGZpbmQgdGFibGUgbmFtZXMgZm9yIHRoZSBBQ1MgW2hlcmVdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvZGF0YS9kZXZlbG9wZXJzL2RhdGEtc2V0cy9hY3MtNXllYXIuaHRtbCkNCg0KDQojIyMgV2hhdCBraW5kIG9mIHRhYmxlIGRvIHlvdSB3YW50Pw0KVGhlcmUgYXJlIHNldmVyYWwgdHlwZXMgb2YgdGFibGVzIHRoZSBDZW5zdXMgcHVibGlzaGVzLiANCg0KVGhlIFtEZXRhaWxlZCB0YWJsZXNdKGh0dHBzOi8vYXBpLmNlbnN1cy5nb3YvZGF0YS8yMDE2L2Fjcy9hY3M1L3ZhcmlhYmxlcy5odG1sKSBhcmUgdmVyeSBkZXRhaWxlZCBzdW1tYXJpZXMgb2YgdGhlIGRhdGEgZm9yIHBsYWNlcywgaW4gdGhlIDIwMTUgZGF0YSB0aGVyZSB3ZXJlIG1vcmUgdGhhbiA2NCwwMDAgdGFibGVzIHB1Ymxpc2hlZC4gVGhlc2UgY2FuIGJlIGEgbGl0dGxlIG92ZXJ3aGVsbWluZyB0byB1c2UsIGJ1dCB3ZSdsbCBzZWUgYW4gZXhhbXBsZSBiZWxvdw0KDQpbU3ViamVjdCB0YWJsZXNdKGh0dHBzOi8vYXBpLmNlbnN1cy5nb3YvZGF0YS8yMDE2L2Fjcy9hY3M1L3N1YmplY3QuaHRtbCkgdGFrZSBzb21lIG9mIHRoZSBkZXRhaWxlZCB0YWJsZXMgYW5kIGNvbXB1dGUgc3VtbWFyaWVzIG9mIHRoZW0gYXJvdW5kIGNlcnRhaW4gZGVtb2dyYXBoaWMsIHNvY2lhbCBvciBlY29ub21pYyBzdWJqZWN0cy4gQmFzaWNhbGx5IHRoaXMgaXMgb25lIHdheSB0byBnZXQgbW9yZSBkYXRhIHJlbGF0ZWQgdG8gYSBzdWJqZWN0IHdpdGhvdXQgaGF2aW5nIHRvIGtub3cgYWxsIG9mIHRoZSBpbmRpdmlkdWFsIGRldGFpbCB0YWJsZXMgeW91IG5lZWQuIA0KIA0KW0RhdGEgUHJvZmlsZSB0YWJsZXNdKGh0dHBzOi8vYXBpLmNlbnN1cy5nb3YvZGF0YS8yMDE2L2Fjcy9hY3M1L3Byb2ZpbGUuaHRtbCkgY29udGFpbiBicm9hZCBzb2NpYWwsIGVjb25vbWljLCBob3VzaW5nLCBhbmQgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24uIFRoZSBkYXRhIGFyZSBwcmVzZW50ZWQgYXMgYm90aCBjb3VudHMgYW5kIHBlcmNlbnRhZ2VzLiBUaGVyZSBhcmUgb3ZlciAyLDQwMCB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhc2V0LiBUaGVzZSBhcmUgdmVyeSB1c2VmdWwgc3VtbWFyaWVzIGFuZCB3aGF0IEkgcGVyc29uYWxseSByZWx5IG9uIGZvciBtb3N0IG9mIG15IGRhdGEgZXh0cmFjdHMuIA0KDQojIyMgR2V0IGEgQ2Vuc3VzIGRldmVsb3BlciBBUEkgS2V5DQpPYnRhaW4gb25lIGF0IGh0dHA6Ly9hcGkuY2Vuc3VzLmdvdi9kYXRhL2tleV9zaWdudXAuaHRtbA0KDQojIyMgU2F2ZSB5b3VyIEFQSSBrZXkgdG8geW91ciB3b3JraW5nIGRpcmVjdG9yeQ0KSSByZWNvbW1lbmQgeW91IGluc3RhbGwgeW91ciBBUEkga2V5IGluIHlvdXIgUnByb2ZpbGUsIGp1c3Qgc28geW91IGRvbid0IGhhdmUgdG8ga2VlcCBwYXN0aW5nIGl0IGludG8geW91ciBjb2RlLiBUbyBkbyB0aGlzLCB0eXBlIGB0aWR5Y2Vuc3VzOjpjZW5zdXNfYXBpX2tleShrZXkgPSAgInlvdXJrZXloZXJlIiwgaW5zdGFsbCA9IFQpYCBvbmUgdGltZSB0byBpbnN0YWxsIHlvdXIga2V5IGZvciB1c2UgaW4gYHRpZHljZW5zdXNgLg0KDQojIyMgTGV0J3MgZG8gc29tZSBzdHVmZiENCg0KYGBge3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcygiY2Vuc3VzYXBpIikNCiNkb24ndCB1c2UgbXkga2V5LCBwdXQgeW91cnMgaW4gaGVyZQ0KI3VzZSBpbnN0YWxsPVQgb25lIHRpbWUgb25seQ0KI2xpYnJhcnkoY2Vuc3VzYXBpKQ0KY2Vuc3VzX2FwaV9rZXkoa2V5ID0gICJmNjdiZTVhODZlNjk2ZWViZjBjODRhNWEyMGQ4NWYyYzA0ZjdlOWVmIikNCmBgYA0KDQpcbmV3cGFnZQ0KDQoNCiMjIyBMb29rIGF0IGF2YWlsYWJsZSBBQ1MgdmFyaWFibGVzDQpBcyBJIG1lbnRpb25lZCBhYm92ZSwgZmluZGluZyB0aGUgcmlnaHQgdGFibGUgY2FuIGJlIGEgY2hhbGxlbmdlLCBlc3BlY2lhbGx5IGZvciBuZXcgZGF0YSB1c2Vycy4gYHRpZHljZW5zdXNgIGhhcyB0aGUgYGxvYWRfdmFyaWFibGVzKClgIGZ1bmN0aW9uIHRoYXQgd2lsbCBsb2FkIGFsbCBvZiB0aGUgYXZhaWxhYmxlIHRhYmxlcyBmb3IgYSBzcGVjaWZpYyB0YWJsZSB0eXBlLiANCg0KIEZvciBleGFtcGxlLCBpZiB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB2YXJpYWJsZXMgZnJvbSB0aGUgQUNTIFtkYXRhIHByb2ZpbGVdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvYWNzL3d3dy9kYXRhL2RhdGEtdGFibGVzLWFuZC10b29scy9kYXRhLXByb2ZpbGVzLzIwMTYvKSB0YWJsZXMsIHdlIGNhbiBsb2FkIGFsbCBhdmFpbGFibGUgdmFyaWFibGVzIHRoZW4gdXNlIFIgdG8gc2VhcmNoIGZvciB3aGF0IHdlIG5lZWQuDQogDQpPbmUgb2YgdGhlIGJlc3Qgd2F5cyB0byBzZWFyY2ggaXMgdG8gdXNlIFtgZ3JlcCgpYF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvR3JlcCksIHdoaWNoIGlzIGEgdG9vbCBmb3Igc2VhcmNoaW5nIGZvciBwYXR0ZXJucyB3aXRoaW4gdGV4dCwgYW5kIGlzICoqX1NVUEVSIFVTRUZVTCFfKioNCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkodGlkeWNlbnN1cykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShjZW5zdXNhcGkpDQpgYGANCg0KYGBge3J9DQo/bG9hZF92YXJpYWJsZXMNCnYxNV9Qcm9maWxlIDwtIGxvYWRfdmFyaWFibGVzKHllYXIgPSAyMDE1ICwgZGF0YXNldCA9ICJhY3M1L3Byb2ZpbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBUUlVFKSAjZGVtb2dyYXBoaWMgcHJvZmlsZSB0YWJsZXMNCg0KI09wZW4gdGhlIGRhdGEgZm9yIGV4YW1pbmF0aW9uDQprbml0cjo6a2FibGUoaGVhZCh2MTVfUHJvZmlsZSkpDQoNCiNTZWFyY2ggZm9yIHZhcmlhYmxlcyBieSBrZXl3b3JkcyBpbiB0aGUgbGFiZWwNCnYxNV9Qcm9maWxlW2dyZXAoeCA9IHYxNV9Qcm9maWxlJGxhYmVsLCAiTWVkaWFuIGhvdXNlaG9sZCIpLCBjKCJuYW1lIiwgImxhYmVsIildDQpgYGANCg0KQWxzbywgaWYgeW91IHdhbnQgdGhlIG5hbWVzIGFuZCBpbmZvIGZvciB0aGUgc3ViamVjdCB0YWJsZXMsIGNoYW5nZSB0aGUgYGRhdGFzZXQgPSBgIGFyZ3VtZW50IHRvIGBhY3M1L3N1YmplY3RgDQoNCmBgYHtyfQ0KdjE1X3N1YmplY3QgPC0gbG9hZF92YXJpYWJsZXMoeWVhciA9IDIwMTUgLGRhdGFzZXQ9ICJhY3M1L3N1YmplY3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBUUlVFKSAjZGVtb2dyYXBoaWMgc3ViamVjdCB0YWJsZXMNCg0KYGBgDQoNCkZpbmFsbHksIHRvIHZpZXcgdmFyaWFibGVzIGluIHRoZSBkZXRhaWxlZCB0YWJsZXMsIGNoYW5nZSB0aGUgYGRhdGFzZXQgPSBgIGFyZ3VtZW50IHRvIGBhY3M1YA0KDQpgYGB7cn0NCnYxNV9kZXRhaWxlZCA8LSBsb2FkX3ZhcmlhYmxlcyh5ZWFyID0gMjAxNSAsIGRhdGFzZXQgPSAiYWNzNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBUUlVFKSAjZGVtb2dyYXBoaWMgZGV0YWlsIHRhYmxlcw0KYGBgDQoNCklmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiB2YXJpYWJsZXMgZnJvbSB0aGUgZGVjZW5uaWFsIGNlbnN1cywgY2hhbmdlIHRoZSBgZGF0YXNldCA9IGAgYXJndW1lbnQgdG8gYHNmMWAgb3IgIGBzZjNgIGRlcGVuZGluZyBvbiB3aGljaCBkZWNlbm5pYWwgc3VtbWFyeSBmaWxlIHlvdSB3YW50LiANCg0KDQpcbmV3cGFnZQ0KIyMgRXh0cmFjdCBmcm9tIEFDUyBzdW1tYXJ5IGZpbGUgZGF0YSBwcm9maWxlIHZhcmlhYmxlcyBmcm9tIDIwMTUgZm9yIEJleGFyIENvdW50eSwgVFggQ2Vuc3VzIFRyYWN0cw0KSGVyZSBpcyBhIHJlYWwgZXhhbXBsZQ0KDQpUaGUgZGF0YSBwcm9maWxlIHRhYmxlcyBhcmUgdmVyeSB1c2VmdWwgYmVjYXVzZSB0aGV5IGNvbnRhaW4gbG90cyBvZiBwcmUtY2FsY3VsYXRlZCB2YXJpYWJsZXMuDQoNCkhlcmUgaXMgYSBxdWVyeSB3aGVyZSB3ZSBleHRyYWN0IHRoZSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBpbiBjZW5zdXMgdHJhY3RzIGZyb20gdGhlIDIwMTUgQUNTIGZvciBCZXhhciBDb3VudHksIFRleGFzLiBXZSBjYW4gYWxzbyBnZXQgdGhlIHNwYXRpYWwgZGF0YSBieSByZXF1ZXN0aW5nIGBnZW9tZXRyeT1UUlVFYC4gIFVzaW5nIGBvdXRwdXQ9IndpZGUiYCB3aWxsIHB1dCBlYWNoIHZhcmlhYmxlIGluIGEgY29sdW1uIG9mIHRoZSBkYXRhIHNldCwgd2l0aCBlYWNoIHJvdyBiZWluZyBhIGNlbnN1cyB0cmFjdC4gDQoNCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCnNhX2FjczwtZ2V0X2FjcyhnZW9ncmFwaHkgPSAidHJhY3QiLCBzdGF0ZT0iVFgiLCBjb3VudHkgPSBjKCJCZXhhciIpLA0KICAgICAgICAgICAgICAgIHllYXIgPSAyMDE1LA0KICAgICAgICAgICAgICAgIHZhcmlhYmxlcz1jKCAiRFAwM18wMDYyRSIpICwNCiAgICAgICAgICAgICAgICBnZW9tZXRyeSA9IFQsIG91dHB1dCA9ICJ3aWRlIikNCg0KI2NyZWF0ZSBhIGNvdW50eSBGSVBTIGNvZGUgLSA1IGRpZ2l0DQpzYV9hY3MkY291bnR5PC1zdWJzdHIoc2FfYWNzJEdFT0lELCAxLCA1KQ0KDQojcmVuYW1lIHZhcmlhYmxlcyBhbmQgZmlsdGVyIG1pc3NpbmcgY2FzZXMNCnNhX2FjczI8LXNhX2FjcyU+JQ0KICBtdXRhdGUoIG1lZGhoaW5jPURQMDNfMDA2MkUpICU+JQ0KICBuYS5vbWl0KCkNCg0KI3Rha2UgYSBwZWVrIGF0IHRoZSBmaXJzdCBmZXcgbGluZXMgb2YgZGF0YQ0KaGVhZChzYV9hY3MyKQ0KYGBgDQoNCldlIGNhbiBpbW1lZGlhdGVseSBtYXAgdGhlc2UgZGF0YSBhcyB3ZWxsLCBiZWNhdXNlIGB0aWR5Y2Vuc3VzYCBjYW4gZ2V0IHlvdSB0aGUgZ2VvZ3JhcGh5IGNvcnJlc3BvbmRpbmcgdG8geW91ciBkYXRhLiANCg0KSGVyZSwgSSB1c2UgdGhlIGBkcGx5cmAgcGlwZSAiYCU+JWAiIHRvIGZlZWQgdGhlIGRhdGEgaW50byBgZ2dwbG90YCBhbmQgbWFwIHRoZSBtZWRpYW4gaG91c2Vob2xkIGluY29tZSBmb3IgZWFjaCBjZW5zdXMgdHJhY3QgaW4gQmV4YXIgQ291bnR5IGluIDIwMTUsIHVzaW5nIGEgcXVhbnRpbGUgYnJlYWsgc3lzdGVtLiANCg0KYGBge3J9DQoNCnNhX2FjczIgJT4lDQogIG11dGF0ZShtZWRfaW5jb21lPWN1dChtZWRoaGluYyxicmVha3MgPSBxdWFudGlsZShtZWRoaGluYywgbmEucm09VCwgcD1zZXEoMCwxLGxlbmd0aC5vdXQgPSA5KSksaW5jbHVkZS5sb3dlc3QgPSBUKSklPiUNCiAgZ2dwbG90KCBhZXMoZmlsbCA9IG1lZF9pbmNvbWUsIGNvbG9yID0gbWVkX2luY29tZSkpICsgDQogIGdlb21fc2YoKSArIA0KICBnZ3RpdGxlKCJNZWRpYW4gSG91c2Vob2xkIEluY29tZSIsIA0KICAgICAgICAgIHN1YnRpdGxlID0gIkJleGFyIENvdW50eSBUZXhhcywgMjAxNSAtIFF1YW50aWxlIEJyZWFrcyIpKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikgKyANCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiQmx1ZXMiKQ0KDQoNCmBgYA0KDQoNCiMjIyBBQ1MgbWFyZ2lucyBvZiBlcnJvcg0KVGhlIEFDUyBpcyBhIHN1cnZleSBhbmQgaW4gYXJlYXMgd2hlcmUgdGhlIHNhbXBsZSBzaXplIGlzIHNtYWxsLCB0aGUgZXJyb3JzIGluIGVzdGltYXRlcyBjYW4gYmUgcXVpdGUgbGFyZ2UuIEFzIGEgd2F5IHRvIGxldCB1c2VycyBrbm93IGhvdyB1bmNlcnRhaW4gdGhlIGVzdGltYXRlcyBhcmUgZm9yIGFueSBnaXZlbiBhcmVhLCB0aGUgQ2Vuc3VzIHB1Ymxpc2hlcyAqKl9NYXJnaW5zIG9mIEVycm9yXyoqIGZvciBlYWNoIGVzdGltYXRlIHB1Ymxpc2hlZC4gSW4gc3RhdGVzLCBjb3VudGllcyBhbmQgY2l0aWVzLCB0aGVzZSBtYXJnaW5zIG9mIGVycm9yIGFyZSB1c3VhbGx5IHNtYWxsIHNpbmNlIHRoZSBvdmVyYWxsIHNhbXBsZSBzaXplIGluIHRob3NlIGxhcmdlciBhcmVhcyBpcyBsYXJnZSBlbm91Z2ggdG8gcHJvdmlkZSBtb3JlIGNlcnRhaW50eSBhYm91dCB0aGUgcG9wdWxhdGlvbiBlc3RpbWF0ZXMuIA0KDQpJbiBhcmVhcyB0aGF0IGFyZSBzbWFsbGVyLCB0cmFjdHMgYW5kIGVzcGVjaWFsbHkgYmxvY2sgZ3JvdXBzLCB0aGUgbWFyZ2lucyBvZiBlcnJvciBjYW4gYmUgYmUgdmVyeSBsYXJnZSByZWxhdGl2ZSB0byB0aGUgZXN0aW1hdGVzLiBPbmUgd2F5IHRvIHZpc3VhbGl6ZSB0aGlzIGlzIHRvIG1hcCB0aGUgKipfY29lZmZpY2llbnQgb2YgdmFyaWF0aW9uXyoqIGluIHRoZSBlc3RpbWF0ZXMsIHdoaWNoIGlzOiAkQ1Y9IFxmcmFje1xzaWdtYX17XHRoZXRhfSQsIHdoZXJlICRcdGhldGEkIGlzIHRoZSBlc3RpbWF0ZSBvZiBpbnRlcmVzdC4gDQoNCiMjIyMgbWFwcGluZyBvZiBlcnJvcnMgaW4gdmFyaWFibGVzDQpIZXJlIEkgZ2VuZXJhdGUgYSBxdWFudGlsZSBicmVhayBmb3IgdGhlIGNvZWZmaWNpZW50IG9mIHZhcmlhdGlvbiBpbiBjZW5zdXMgdHJhY3QgaW5jb21lIGVzdGltYXRlcyANCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQ0KDQpzYV9hY3MyICU+JQ0KICBtdXRhdGUoY3YgPShEUDAzXzAwNjJNLzEuNjQ1KS9EUDAzXzAwNjJFKSU+JQ0KICBtdXRhdGUoY3ZfbWFwPWN1dChjdixicmVha3MgPSBxdWFudGlsZShjdiwgbmEucm09VCwgcD1zZXEoMCwxLGxlbmd0aC5vdXQgPSA5KSksaW5jbHVkZS5sb3dlc3QgPSBUKSklPiUNCiAgZ2dwbG90KCBhZXMoZmlsbCA9Y3ZfbWFwLCBjb2xvciA9IGN2X21hcCkpICsgDQogIGdlb21fc2YoKSArIA0KICBnZ3RpdGxlKCJDb2VmZmljaWVudCBvZiBWYXJpYXRpb24gaW4gTWVkaWFuIEhvdXNlaG9sZCBJbmNvbWUiLCANCiAgICAgICAgICBzdWJ0aXRsZSA9ICJCZXhhciBDb3VudHkgVGV4YXMsIDIwMTUgLSBRdWFudGlsZSBCcmVha3MiKSsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uPSJCIikrIA0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2Qob3B0aW9uPSJCIikNCmBgYA0KDQoNCg0KIyMjIE1ldHJvIGFyZWEgaW5jb21lcw0KSGVyZSBpcyBhbm90aGVyIGV4YW1wbGUgd2hlcmUgd2UgZ2V0IGRhdGEgZm9yIG1ldHJvL21pY3JvcG9saXRhbiBhcmVhcyBpbiB0aGUgVVMuIEkgdXNlIGEgZGV0YWlsZWQgdGFibGUgcmVxdWVzdCB0aGlzIHRpbWUuIA0KDQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQoNCnYxNV9hY3M8LSBsb2FkX3ZhcmlhYmxlcyh5ZWFyID0gMjAxNSAsIGRhdGFzZXQgPSAiYWNzNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgY2FjaGUgPSBUUlVFKSAjcmVndWxhciBBQ1MgcHJvZmlsZSB0YWJsZXMNCg0Ka25pdHI6OmthYmxlKGhlYWQodjE1X2FjcykpDQoNCiNTZWFyY2ggZm9yIHZhcmlhYmxlcyBieSBrZXl3b3JkcyBpbiB0aGUgbGFiZWwgDQp2MTVfYWNzW2dyZXAoeCA9IHYxNV9Qcm9maWxlJGxhYmVsLCAiTWVkaWFuIGhvdXNlaG9sZCIpLCBjKCJuYW1lIiwgImxhYmVsIildDQoNCm1ldHJvPC1nZXRfYWNzKGdlb2dyYXBoeSA9ICJtZXRyb3BvbGl0YW4gc3RhdGlzdGljYWwgYXJlYS9taWNyb3BvbGl0YW4gc3RhdGlzdGljYWwgYXJlYSIsDQogICAgICAgICAgICAgICB5ZWFyID0gMjAxNSwNCiAgICAgICAgICAgICAgICB2YXJpYWJsZXM9YyggIkIxOTAxM18wMDFFIikgLA0KICAgICAgICAgICAgICAgIGdlb21ldHJ5ID0gRiwgb3V0cHV0ID0gIndpZGUiKQ0KDQpgYGANCg0KRm9yIHRoaXMgZ2VvZ3JhcGh5LCBgdGlkeWNlbnN1c2Agd29uJ3QgZG93bmxvYWQgdGhlIGdlb21ldHJ5cyBhdXRvbWF0aWNhbGx5IChtYXliZSBpbiBhIGxhdGVyIHJlbGVhc2UpLCBzbyB3ZSB1c2UgS3lsZSBXYWxrZXIncyBvdGhlciBsaWJyYXJ5IGB0aWdyaXNgIGZvciBkb3dubG9hZGluZyBDZW5zdXMgZ2VvZ3JhcGhpYyBkYXRhLiANCg0KYGBge3IsIHJlc3VsdHM9J2hpZGUnfQ0KbGlicmFyeSh0aWdyaXMpDQpvcHRpb25zKHRpZ3Jpc19jbGFzcyA9ICJzZiIpICNmb3IgdXNlIHdpdGggZ2dwbG90Mg0KDQptZXRfZ2VvPC1jb3JlX2Jhc2VkX3N0YXRpc3RpY2FsX2FyZWFzKGNiPVQsIHllYXIgPSAyMDE1KQ0KDQojRmlsdGVyIG91dCB0ZXJyaXRvcmllcw0Kc3RzPC1zdGF0ZXMoY2IgPSBULCB5ZWFyID0gMjAxNSklPiUNCiAgZmlsdGVyKCFTVEFURUZQJWluJWMoICI2MCIsICI2NiIsICI2OSIsICI3MiIsICI3OCIpKQ0KDQojbWVyZ2UgZ2VvZ3JhcGhpYyBkYXRhIHRvIHRhYmxlIGRhdGENCm1ldF9qb2luPC1nZW9fam9pbihtZXRfZ2VvLCBtZXRybywgYnk9IkdFT0lEIikNCg0KI3JlbmFtZSB2YXJpYWJsZXMgYW5kIGZpbHRlciBtaXNzaW5nIGNhc2VzDQptZXRfam9pbjwtbWV0X2pvaW4lPiUNCiAgbXV0YXRlKCBtZWRoaGluYz1CMTkwMTNfMDAxRSkgJT4lDQogIG11dGF0ZShtZWRfaW5jb21lPWN1dChtZWRoaGluYyxicmVha3MgPSBxdWFudGlsZShtZWRoaGluYywgbmEucm09VCwgcD1zZXEoMCwxLGxlbmd0aC5vdXQgPSA5KSksaW5jbHVkZS5sb3dlc3QgPSBUKSkNCg0KIyNDcmVhdGUgb3VyIG1hcA0KDQptYXAxPC1tZXRfam9pbiU+JQ0KICBzdF90cmFuc2Zvcm0oY3JzID0gMjI3OCklPiUNCiAgZ2dwbG90KCBhZXMoZmlsbCA9IG1lZF9pbmNvbWUsIGNvbG9yID0gbWVkX2luY29tZSkpICsgDQogIGdlb21fc2YoKSArIA0KICBnZ3RpdGxlKCJNZWRpYW4gSG91c2Vob2xkIEluY29tZSIsIA0KICAgICAgICAgIHN1YnRpdGxlID0gIk1TQXMsIDIwMTUgLSBRdWFudGlsZSBCcmVha3MiKSsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJCbHVlcyIpICsgDQogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikrDQogIGdlb21fc2YoZGF0YT1zdHMsIGZpbGw9TkEsIGNvbG9yPSJibGFjayIpDQogICAgDQptYXAxDQoNCmBgYA0KDQpJZiB5b3Ugd291bGQgbGlrZSB0byB6b29tIGluLCB3ZSBjYW4gdXNlIHRoZSBgbWFwdmlld2AgbGlicmFyeS4gVGhpcyBpcyB2ZXJ5IHVzZWZ1bCBmb3IgdGVhY2hpbmcgYW5kIGZvciBwcmVzZW50YXRpb25zLg0KDQpgYGB7cn0NCmxpYnJhcnkobWFwdmlldykNCg0KcGFsIDwtIGNvbG9yUmFtcFBhbGV0dGUodmlyaWRpc0xpdGU6OnZpcmlkaXMobj02KSkgI3NldCBjb2xvcnMNCg0KbWFwdmlldyhtZXRfam9pbiwgemNvbD0ibWVkX2luY29tZSIsIGNvbC5yZWdpb25zPXBhbCwgbGVnZW5kPVQsbWFwLnR5cGVzPSJPcGVuU3RyZWV0TWFwIiwgbGF5ZXIubmFtZT0iTWVkaWFuIEluY29tZSIpDQoNCmBgYA0KDQoNCiMgVXNpbmcgdGhlIGNlbnN1c2FwaSBwYWNrYWdlDQpUaGUgQ2Vuc3VzIGhhcyBsb3RzIG9mIEFQSXMgdGhhdCBhcmUgYXZhaWxhYmxlLiBgdGlkeWNlbnN1c2AgaXMgZ3JlYXQgZm9yIGFjY2Vzc2luZyB0aGUgQUNTIGFuZCBkZWNlbm5pYWwgY2Vuc3VzLCBidXQgaWYgeW91IHdhbnQgZGF0YSBmcm9tIGFub3RoZXIgQVBJLCB0aGUgbW9yZSBnZW5lcmFsIGBjZW5zdXNhcGlgIHBhY2thZ2UgZ2l2ZXMgeW91IGFjY2VzcyB0byBhbGwgb2YgdGhlIENlbnN1cyBBUElzDQoNCkZpcnN0LCBzaW5jZSB0aGlzIGlzIGEgZGlmZmVyZW50IHBhY2thZ2UsIHlvdSdsbCBuZWVkIHRvIGFkZCB5b3VyIEFQSSBrZXkgdG8geW91ciBgLlJlbnZpcm9uYCBkYXRhLiBZb3UgY2FuIGRvIHRoaXMgYnkgZm9sbG93aW5nIHRoZSBleGFtcGxlIGJlbG93Og0KDQpgYGB7ciwgZXZhbD1GfQ0KDQpTeXMuc2V0ZW52KENFTlNVU19LRVk9ImY2N2JlNWE4NmU2OTZlZWJmMGM4NGE1YTIwZDg1ZjJjMDRmN2U5ZWYiKQ0KIyBSZWxvYWQgLlJlbnZpcm9uDQpyZWFkUmVudmlyb24oIn4vLlJlbnZpcm9uIikNCiMgQ2hlY2sgdG8gc2VlIHRoYXQgdGhlIGV4cGVjdGVkIGtleSBpcyBvdXRwdXQgaW4geW91ciBSIGNvbnNvbGUNClN5cy5nZXRlbnYoIkNFTlNVU19LRVkiKQ0KYGBgDQoNCk5vdyB3ZSBsb2FkIGFsbCBvZiB0aGUgYXZhaWxhYmxlIEFQSXMgaW50byBhbiBSIG9iamVjdCBzbyB3ZSBjYW4gbG9vayB3aGF0J3MgYXZhaWxhYmxlLg0KDQpgYGB7cn0NCmFwaXMgPC0gbGlzdENlbnN1c0FwaXMoKQ0Ka25pdHI6OmthYmxlKGhlYWQoYXBpcykpDQoNCmBgYA0KDQpTbywgd2UgY2FuIHNlZSB0aGVyZSBhcmUgYSBsb3QuIEZvciBhIGNvbmNyZXRlIGV4YW1wbGUsIGxldCdzIGV4YW1pbmUgdGhlIGVmZmVjdCBvZiB0aGUgW1BhdGllbnQgUHJvdGVjdGlvbiBhbmQgQWZmb3JkYWJsZSBDYXJlIEFjdF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUGF0aWVudF9Qcm90ZWN0aW9uX2FuZF9BZmZvcmRhYmxlX0NhcmVfQWN0KSBvbiB1bmluc3VyYW5jZSByYXRlcyBpbiBVUyBzdGF0ZXMuIA0KDQpGb3IgdGhpcywgd2Ugd2lsbCB1c2UgdGhlIFtTbWFsbCBBcmVhIEhlYWx0aCBJbnN1cmFuY2UgRXN0aW1hdGVzXShodHRwczovL3d3dy5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvc2FoaWUuaHRtbCkgcHJvZ3JhbS4gVGhpcyBwcm9ncmFtIGNvbWJpbmVzIGRhdGEgZnJvbSB0aGUgQUNTIGFuZCBkYXRhIGZyb20gaW5kaXZpZHVhbCBzdGF0ZXMgb24gb3RoZXIgaGVhbHRoIGluc3VyYW5jZSBwcm9ncmFtcyB0byBwcm9kdWNlIG1vZGVsLWJhc2VkIGVzdGltYXRlcyBvZiB0aGUgb3ZlcmFsbCByYXRlcyBvZiBpbnN1cmFuY2UgYW5kIHVuaW5zdXJhbmNlIGZvciBzdGF0ZXMgYW5kIGNvdW50aWVzLiANCg0KQ2Vuc3VzIG1haW50YWlucyBhIG5pY2UgW3dlYnNpdGVdKGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvZGF0YS10b29scy9kZW1vL3NhaGllLyMvKSBmb3IgYnJvd3NpbmcgdGhlIGRhdGEgYW5kIGRvd25sb2FkaW5nIGltYWdlcyBvZiBkYXRhIHZpc3VhbGl6YXRpb25zLCBidXQgYW55dGhpbmcgY3VzdG9tIGNhbiBiZSBhIHByb2Nlc3MuIEluIFIgdGhpcyBpcyBubyBwcm9ibGVtLiANCg0KQmVsb3csIHdlIGZpcnN0IGxvb2sgdXAgdGhlIHZhcmlhYmxlcyBhdmFpbGFibGUgaW4gdGhlIFNBSElFIGRhdGEsIHRoZW4gd2UgZG8gYW4gZXh0cmFjdCBhbmQgY3JlYXRlIGEgZGF0YXNldCBmb3IgVGV4YXMgYW5kIENhbGlmb3JuaWEgZm9yIHVuc2luc3VyYW5jZSByYXRlcyBieSByYWNlL2V0aG5pY2l0eS4gTmV4dCwgd2UgY3JlYXRlIGEgbGluZSBwbG90IG9mIHRoZSB1bmluc3VyYW5jZSB0aW1lIHNlcmllcyBmb3IgZWFjaCBzdGF0ZSBhbmQgZGVtb2dyYXBoaWMgZ3JvdXAuIA0KDQpgYGB7cn0NCiN0aW1lc2VyaWVzL3BvdmVydHkvc2FpcGUNCnNhaGV2YXJzPC1saXN0Q2Vuc3VzTWV0YWRhdGEobmFtZSA9ICJ0aW1lc2VyaWVzL2hlYWx0aGlucy9zYWhpZSIsIHR5cGUgPSAidiIpDQpoZWFkKHNhaGV2YXJzKQ0KI1NBRVBPVlJUQUxMX1BUDQoNCmBgYA0KDQojIyMgR2V0IHRoZSBkYXRhIGZvciBzdGF0ZXMNCmBgYHtyfQ0KdWlfcmF0ZXM8LWdldENlbnN1cyhuYW1lID0gInRpbWVzZXJpZXMvaGVhbHRoaW5zL3NhaGllIiwNCiAgICAgICAgICB2YXJzID0gYygiU1RBVEUiLCAiWUVBUiIsIlJBQ0VDQVQiLCAiUENUVUlfUFQiKSwgDQogICAgICAgICAgcmVnaW9uID0gInN0YXRlOioiKQ0KDQoNCg0KaGVhZCh1aV9yYXRlcykNCmBgYA0KDQoNCiMjIyBDbGVhbiB1cCB0aGUgZGF0YSBhbmQgbWFrZSBhIGxpbmUgcGxvdDoNCg0KYGBge3J9DQp1aV9yYXRlcyU+JQ0KICBtdXRhdGUoeXI9YXMubnVtZXJpYyhZRUFSKSwgdW5pbnN1cmVfcmF0ZT1hcy5udW1lcmljKFBDVFVJX1BUKSklPiUNCiAgZmlsdGVyKFNUQVRFJWluJWMoIjA2IiwgIjQ4IiksIFJBQ0VDQVQhPSIwIiklPiUNCiAgc2VsZWN0KFNUQVRFLCAgeXIsUkFDRUNBVCwgdW5pbnN1cmVfcmF0ZSklPiUNCiAgbXV0YXRlKG5ld19yYWNlPWNhc2Vfd2hlbiggLiRSQUNFQ0FUPT0nMScgfiAiTkggV2hpdGUiLCANCiAgICAgICAgICAgICAgICAgICAgLiRSQUNFQ0FUPT0nMicgfiAiTkggQmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAuJFJBQ0VDQVQ9PSczJyB+ICJIaXNwYW5pYyIpKSU+JQ0KICBnZ3Bsb3QoYWVzKHg9eXIsIHk9dW5pbnN1cmVfcmF0ZSkpK2dlb21fbGluZShhZXMoY29sb3I9IG5ld19yYWNlLCBsaW5ldHlwZT1TVEFURSwgZ3JvdXA9aW50ZXJhY3Rpb24oU1RBVEUsIG5ld19yYWNlKSkpK3lsaW0obG93PTAsaGlnaD01MCkreWxhYigiJSBVbmluc3VyZWQiKSt4bGFiKCJZZWFyIikrZ2d0aXRsZSgiJSBVbmluc3VyZWQgaW4gVGV4YXMgYW5kIENhbGlmb3JuaWEgYnkgUmFjZS9FdGhuaWN0eSIsIHN1YnRpdGxlID0gIlNBSElFIEVzdGltYXRlcyIpDQoNCmBgYA0KDQoNCkFub3RoZXIgYmlnIENlbnN1cyBlc3RpbWF0ZSBwcm9ncmFtIGZvY3VzIG9uIHBvdmVydHkgYW5kIGluY29tZSwgYW5kIGlzIGNhbGxlZCB0aGUgW1NtYWxsIEFyZWEgSW5jb21lIGFuZCBQb3ZlcnR5IEVzdGltYXRlXShodHRwczovL3d3dy5jZW5zdXMuZ292L3Byb2dyYW1zLXN1cnZleXMvc2FpcGUuaHRtbCksIG9yIFNBSVBFIHByb2dyYW0uIExpa2UgdGhlIFNBSElFLCB0aGUgU0FJUEUgY3JlYXRlcyBtb2RlbCBiYXNlZCBlc3RpbWF0ZXMgb2YgaW5jb21lIGFuZCBwb3ZlcnR5IGZvciBzdGF0ZXMsIGNvdW50aWVzIGFuZCBzY2hvb2wgZGlzdHJpY3RzIG9uIGFuIGFubnVhbCBiYXNpcy4gDQoNCkJlbG93LCB3ZSBkbyBhbiBleHRyYWN0IGZyb20gdGhlIFNBSVBFIGZvciBUZXhhcyBhbmQgQ2FsaWZvcm5pYSBhbmQgY3JlYXRlIGEgbGluZSBwbG90IGZvciB0aGUgdW5kZXItNCBhbmQgdG90YWwgcG92ZXJ0eSByYXRlcyBmb3IgZWFjaCBzdGF0ZSBvdmVyIHRpbWUuIA0KIA0KYGBge3J9DQpzYWlwdmFyczwtbGlzdENlbnN1c01ldGFkYXRhKG5hbWUgPSAidGltZXNlcmllcy9wb3ZlcnR5L3NhaXBlIiwgdHlwZSA9ICJ2IikNCmhlYWQoc2FpcHZhcnMpDQojU0FFUE9WUlRBTExfUFQNCiANCnBfcmF0ZXM8LWdldENlbnN1cyhuYW1lID0gInRpbWVzZXJpZXMvcG92ZXJ0eS9zYWlwZSIsDQogICAgICAgICAgdmFycyA9IGMoIlNUQVRFIiwgIllFQVIiLCAiU0FFUE9WUlRBTExfUFQiLCAiU0FFUE9WUlQwXzRfUFQiKSwgDQogICAgICAgICAgcmVnaW9uID0gInN0YXRlOioiKQ0KDQpwX3JhdGVzJT4lDQogIG11dGF0ZSh5cj1hcy5udW1lcmljKFlFQVIpLCB0b3RfcG92X3JhdGU9YXMubnVtZXJpYyhTQUVQT1ZSVEFMTF9QVCksIGNoaWxkMDRfcG92ZXJ0eT1hcy5udW1lcmljKFNBRVBPVlJUMF80X1BUKSklPiUNCiAgZmlsdGVyKFNUQVRFJWluJWMoIjA2IiwgIjQ4IikpJT4lDQogIHNlbGVjdChTVEFURSwgIHlyLCB0b3RfcG92X3JhdGUsIGNoaWxkMDRfcG92ZXJ0eSklPiUNCiAgZ2dwbG90KGFlcyh4PXlyLCB5PWNoaWxkMDRfcG92ZXJ0eSkpK2dlb21fbGluZShhZXMoY29sb3I9IFNUQVRFLCBncm91cD1TVEFURSkpK3lsaW0obG93PTAsaGlnaD00MCkreWxhYigiJSBJbiBQb3ZlcnR5IikreGxhYigiWWVhciIpK2dndGl0bGUoIiUgQ2hpbGRyZW4gdW5kZXIgYWdlIDQgQmVsb3cgdGhlIFBvdmVydHkgTGluZSBpbiBUZXhhcyBhbmQgQ2FsaWZvcm5pYSAiLCBzdWJ0aXRsZSA9ICJTQUlQRSBFc3RpbWF0ZXMiKQ0KDQoNCnBfcmF0ZXMlPiUNCiAgbXV0YXRlKHlyPWFzLm51bWVyaWMoWUVBUiksIHRvdF9wb3ZfcmF0ZT1hcy5udW1lcmljKFNBRVBPVlJUQUxMX1BUKSwgY2hpbGQwNF9wb3ZlcnR5PWFzLm51bWVyaWMoU0FFUE9WUlQwXzRfUFQpKSU+JQ0KICBmaWx0ZXIoU1RBVEUlaW4lYygiMDYiLCAiNDgiKSklPiUNCiAgc2VsZWN0KFNUQVRFLCAgeXIsIHRvdF9wb3ZfcmF0ZSwgY2hpbGQwNF9wb3ZlcnR5KSU+JQ0KICBnZ3Bsb3QoYWVzKHg9eXIsIHk9dG90X3Bvdl9yYXRlKSkrDQogIGdlb21fbGluZShhZXMoY29sb3I9IFNUQVRFLCBncm91cD1TVEFURSkpKw0KICB5bGltKGxvdz0wLGhpZ2g9NDApKw0KICB5bGFiKCIlIEluIFBvdmVydHkiKSsNCiAgeGxhYigiWWVhciIpKw0KICBnZ3RpdGxlKCIlIEJlbG93IHRoZSBQb3ZlcnR5IExpbmUgaW4gVGV4YXMgYW5kIENhbGlmb3JuaWEgIiwgc3VidGl0bGUgPSAiU0FJUEUgRXN0aW1hdGVzIikNCg0KYGBgDQoNCg0KIyBVc2luZyB0aGUgaXB1bXNyIHBhY2thZ2UNClRoZSBwcmV2aW91cyBleGFtcGxlcyBmb2N1c2VkIG9uIGdldHRpbmcgZGF0YSBmb3IgcGxhY2VzIGZyb20gc2V2ZXJhbCBDZW5zdXMgcHJvZ3JhbS4gVGhpcyBzZWN0aW9uIGZvY3VzZXMgb24gZ2V0dGluZyBkYXRhIG9uICppbmRpdmlkdWFscyouIA0KDQpFYWNoIHllYXIsIHdoZW4gdGhlIEFDUyBpcyBkb25lLCBvciBvbiBhIGRlY2VubmlhbCB5ZWFyIHdoZW4gdGhlIENlbnN1cyBpcyBjYXJyaWVkIG91dCwgZWFjaCBpbmRpdmlkdWFsIHN1cnZleSBpcyBwdWJsaXNoZWQgaW4gYSAqKl9QdWJsaWMgVXNlIE1pY3JvZGF0YV8qKiBmaWxlLiBGb3IgZXhhbXBsZSwgaW4gdGhlIDIwMTEgLSAyMDE2IEFDUyA1IHllYXIgZGF0YSByZWxlYXNlLCB0aGVyZSB3ZXJlIDE1LDY4MSw5NzIgcGVyc29ucyBpbiB0aGUgZGF0YSwgd2hpbGUgdGhlIDEgeWVhciBmaWxlIGNvbnRhaW5lZCAzLDE1Niw0ODcgcGVyc29ucy4gDQoNCipTbywgeW91IGNhbiBnZXQgYSBsb3Qgb2YgZGF0YSEqDQoNClRvIGdldCBhY2Nlc3MgdG8gdGhlIG1pY3JvZGF0YSwgeW91IGNhbiBnZXQgdGhlIGZpbGVzIFtkaXJlY3RseSBmcm9tIENlbnN1c10oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2Fjcy9kYXRhL3B1bXMuaHRtbCksIG9yIHVzZSB0aGUgZGF0YSB0aGF0IGhhcyBiZWVuIGNsZWFuZWQgYW5kIGhvbW9nZW5pemVkIGJ5IHRoZSBbSVBVTVMgcHJvamVjdF0oaHR0cHM6Ly93d3cuaXB1bXMub3JnLykgYXQgdGhlIFtVbml2ZXJzaXR5IG9mIE1pbm5lc290YSBQb3B1bGF0aW9uIENlbnRlcl0oaHR0cHM6Ly9wb3AudW1uLmVkdS8pLiANCg0KDQpJbiBhZGRpdGlvbiB0byB0aGUgQUNTLCB5b3UgY2FuIGdldCBkZWNlbm5pYWwgQ2Vuc3VzIGRhdGEgZ29pbmcgYmFjayB0byB0aGUgMTc5MCBDZW5zdXMsIGludGVybmF0aW9uYWwgY2Vuc3VzIGRhdGEgZm9yIG5lYXJseSAxMDAgY291bnRyaWVzLCBbQ3VycmVudCBQb3B1bGF0aW9uIFN1cnZleV0oaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL2Nwcy5odG1sKSBkYXRhLCBbRGVtb2dyYXBoaWMgYW5kIEhlYWx0aCBTdXJ2ZXldKGh0dHBzOi8vZGhzcHJvZ3JhbS5jb20vKSBkYXRhLCB0aGUgW05hdGlvbmFsIEhpc3RvcmljIEdJU10oaHR0cHM6Ly93d3cubmhnaXMub3JnLyksIGFuZCBtb3JlLiANCg0KQmFzaWNhbGx5LCB5b3UgY2FuIHNwZW5kIHlvdXIgZW50aXJlIGNhcmVlciB3b3JraW5nIHdpdGggdGhlIGRhdGEgYXQgdGhlIElQVU1TIHByb2plY3QuIA0KDQpUaGUgYmVuZWZpdCB0byB1c2luZyBJUFVNUyBpcyB0aGF0IHlvdSBjYW4gZG93bmxvYWQgbXVsdGlwbGUgeWVhcnMgb2YgZGF0YSBhdCBhIHNpbmdsZSB0aW1lLCB3aXRoIGFzIG1hbnkgb3IgYXMgZmV3IHZhcmlhYmxlcyBhcyB5b3Ugd2FudCwgZm9yIHBsYWNlcyB5b3Ugd2FudC4gTW9yZW92ZXIsIHlvdSBjYW4gZ2V0IHRoZSBkYXRhIGluIG11bHRpcGxlIGZvcm1hdHMgKFNBUywgU3RhdGEsIFNQU1MsIGFuZCBSKSwgd2l0aCBhIGZ1bGx5IGZvcm1hdHRlZCBjb2RlYm9vayBmb3IgZXZlcnl0aGluZy4gDQoNClRoZSBzdGFmZiBhdCBJUFVNUyBoYXZlIGNyZWF0ZWQgYSBSIHBhY2thZ2UgdG8gcmVhZCBpbiBJUFVNUyBkYXRhIChhbmQgdGhleSdyZSB3b3JraW5nIG9uIGFuIEFQSSB0b28hISkgY2FsbGVkIGBpcHVtc3JgLiBJdCB3aWxsIHJlYWQgZGF0YSBmcm9tIGFueSBJUFVNUyBwcm9qZWN0LiANCg0KSGVyZSBpcyBhIGxpbmsgdG8gYW4gW2ludHJvZHVjdGlvbiB0byB0aGUgcGFja2FnZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2lwdW1zci92aWduZXR0ZXMvaXB1bXMuaHRtbCkgd3JpdHRlbiBieSBJUFVNUyBzdGFmZi4gDQoNCkhlcmUgaXMgYSBbQ1BTIGV4YW1wbGVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9pcHVtc3IvdmlnbmV0dGVzL2lwdW1zLWNwcy5odG1sKSBkb25lIGJ5IElQVU1TIHN0YWZmIGFuZCBhIFtOSEdJUyBleGFtcGxlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvaXB1bXNyL3ZpZ25ldHRlcy9pcHVtcy1uaGdpcy5odG1sKS4NCg0KDQojIyMgR2V0dGluZyB5b3VyIG93biBJUFVNUyBkYXRhDQpGaXJzdCBjcmVhdGUgYW4gYWNjb3VudCB3aXRoIHRoZSBJUFVNUyBwcm9qZWN0LCBsZXQgdGhlbSBrbm93IHdobyB5b3UgYXJlIGFuZCB3aGF0IHlvdSB3aWxsIGJlIHVzaW5nIHRoZWlyIGRhdGEgZm9yLCBhbmQgbW9zdCBpbXBvcnRhbnRseSB0aGF0IHlvdSB3aWxsIG5vdCBiZSB1c2luZyBpdCBmb3IgRVZJTCENCg0KQnJvd3NlIHRoZSBJUFVNUyBkYXRhIHNvdXJjZSBvZiB5b3VyIGNob2ljZSA8c2VlIG9uIHNjcmVlbiBleGFtcGxlPg0KDQpTdWJtaXQgeW91ciBkYXRhIGV4dHJhY3QgcmVxdWVzdA0KDQpXYWl0Li4uLg0KDQpEb3dubG9hZCB0aGUgZGF0YSBmaWxlIGFuZCB0aGUgWE1MIGZpbGUsIGFuZCBzYXZlIHRoZW0gc29tZXdoZXJlICB5b3Ugd2lsbCByZW1lbWJlci4gVG8gdXNlIHRoZSBgaXB1bXNyYCBwYWNrYWdlLCBkb3dubG9hZCB0aGUgRERJIGNvZGVib29rIGFuZCB0aGUgLkRBVCB1bmZvcm1hdHRlZCBkYXRhIGZpbGUuIE90aGVyd2lzZSwgd2UgY291bGQgZG93bmxvYWQgdGhlIHN0YXRhIG9yIFNQU1MgZm9ybWF0IGZpbGVzIGFuZCByZWFkIHRoZW0gaW4gdXNpbmcgdGhlIGBoYXZlbmAgbGlicmFyeSwgZWFzeSBwZWFzeS4gDQoNCiFbSVBVTVMgLSBXYWl0aW5nXShDOi9Vc2Vycy9vemQ1MDQvT25lRHJpdmUgLSBVbml2ZXJzaXR5IG9mIFRleGFzIGF0IFNhbiBBbnRvbmlvL2lwdW1zMS5QTkcpDQoNCg0KIVtJUFVNUyAtIERhdGFdKEM6L1VzZXJzL296ZDUwNC9PbmVEcml2ZSAtIFVuaXZlcnNpdHkgb2YgVGV4YXMgYXQgU2FuIEFudG9uaW8vaXB1bXMyLlBORykNCg0KVGhlbiB1c2UgYGlwdW1zcmAhDQoNCg0KYGBge3IsIHJlc3VsdHM9J2hpZGUnfQ0KaWYgKCFyZXF1aXJlKCJpcHVtc3IiKSkgc3RvcCgiUmVhZGluZyBJUFVNUyBkYXRhIGludG8gUiByZXF1aXJlcyB0aGUgaXB1bXNyIHBhY2thZ2UuIEl0IGNhbiBiZSBpbnN0YWxsZWQgdXNpbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kOiBpbnN0YWxsLnBhY2thZ2VzKCdpcHVtc3InKSIpDQoNCmRkaSA8LSByZWFkX2lwdW1zX2RkaSgifi9PbmVEcml2ZSAtIFVuaXZlcnNpdHkgb2YgVGV4YXMgYXQgU2FuIEFudG9uaW8vL3VzYV8wMDA3MS54bWwiKQ0KZGF0YSA8LSByZWFkX2lwdW1zX21pY3JvKGRkaSkNCg0KDQpuYW1lcyhkYXRhKQ0KYGBgDQoNClNvLCBub3cgd2UgaGF2ZSB0aGUgMjAxNiBBQ1MgMSB5ZWFyIGRhdGEgcmVhZCBpbnRvIG1lbW9yeSBpbiBSLCBhbmQgd2UgY291bGQgZG8gYW55dGhpbmcgd2Ugd2FudCBub3cuIA0KDQpJIHVzZSB0aGVzZSBkYXRhIGZvciBsb3RzIG9mIHJlYXNvbnMsIGJ1dCBJJ2xsIHNob3cgYSBmZXcgZ2VuZXJhbCB0aGluZ3MgdGhhdCB5b3UgbmVlZCB0byBkbyBpbiBvcmRlciB0byB1c2UgdGhlbS4gDQoNCiMjIyBSZWNvZGluZyBJUFVNUyB2YXJpYWJsZXMNCioqX1N1cnZleSBkYXRhIGFyZSBhIG1lc3MhXyoqIFRoZXkgaGF2ZSBtaXNzaW5nIGRhdGEgY29kZXMsIHRvcCBjb2RlcywgbnVtZXJpY2FsIHZhbHVlcyB3aGVuIHlvdSB3YW50IGNhdGVnb3JpY2FsIHZhbHVlcywgYW5kIHZpY2UgdmVyc2EuIEdlbmVyYWxseSwgeW91IGhhdmUgdG8gcmVjb2RlIHZhcmlhYmxlcyBpbiBvcmRlciB0byBoYXZlIHRoZW0gYmUgdXNlZnVsLiANCg0KSGVyZSwgSSByZWNvZGUgc2V2ZXJhbCB0aGluZ3MgaW50byBzdGFuZGFyZHMgdXNlZCBpbiBzb2NpYWwgZGVtb2dyYXBoaWMgcmVzZWFyY2guIA0KDQpgYGB7cn0NCm5hbWVzKGRhdGEpPC10b2xvd2VyKG5hbWVzKGRhdGEpKQ0KZGF0YTwtaGF2ZW46OnphcF9sYWJlbHMoZGF0YSkNCmxpYnJhcnkoY2FyKQ0KI3N1cnZleSB3ZWlnaHRzDQpkYXRhJHB3dCA8LSBkYXRhJHBlcnd0LzEwMA0KZGF0YSRod3QgPC0gZGF0YSRoaHd0LzEwMA0KDQojcmFjZS9ldGhuaWNpdHkgDQpkYXRhJGhpc3AgPC0gUmVjb2RlKGRhdGEkaGlzcGFuLCByZWNvZGVzID0gIjk9TkE7IDE6ND0nSGlzcGFuaWMnOyAwPSdOb25IaXNwYW5pYyciKQ0KZGF0YSRyYWNlX3JlYyA8LSBSZWNvZGUoZGF0YSRyYWNlLCByZWNvZGVzID0gIjE9J1doaXRlJzsgMj0nQmxhY2snOyAzPSdPdGhlcic7IDQ6Nj0nQXNpYW4nOyA3Ojk9J090aGVyJyIpDQpkYXRhJHJhY2VfZXRoIDwtIGludGVyYWN0aW9uKGRhdGEkaGlzcCwgZGF0YSRyYWNlX3JlYywgc2VwID0gIl8iKQ0KZGF0YSRyYWNlX2V0aCAgPC0gYXMuZmFjdG9yKGlmZWxzZShzdWJzdHIoYXMuY2hhcmFjdGVyKGRhdGEkcmFjZV9ldGgpLDEsOCkgPT0gIkhpc3BhbmljIiwgIkhpc3BhbmljIiwgYXMuY2hhcmFjdGVyKGRhdGEkcmFjZV9ldGgpKSkNCmRhdGEkcmFjZV9ldGggPC0gcmVsZXZlbChkYXRhJHJhY2VfZXRoLCByZWYgPSAiTm9uSGlzcGFuaWNfV2hpdGUiKQ0KDQojR2VuZGVyDQpkYXRhJG1hbGUgPC0gaWZlbHNlKGRhdGEkc2V4ID09IDEsMSwwKQ0KDQojZm9yZWlnbiBib3JuIHN0YXR1cw0KZGF0YSR1c2Jvcm4gPC0gUmVjb2RlKGRhdGEkYnBsLCByZWNvZGVzID0gIjE6MTIwPTE7IDEyMTo5MDA9MDsgZWxzZT1OQSIpDQoNCiNlZHVjYXRpb25hbCBhdHRhaW5tZW50DQpkYXRhJGVkdWNfbGV2ZWw8LSBSZWNvZGUoZGF0YSRlZHVjZCwgcmVjb2RlcyA9ICIyOjYxPScwTFRfSFMnOzYyOjY0PScxX0hTRC9HRUQnOzY1OjgwPScyX3NvbWVjb2xsJzs5MDoxMDA9JzJfc29tZWNvbGwnOyA4MTo4Mz0nM19Bc3NvY0RlZ3JlZSc7MTAxPSc0X2JhY2hlbG9yZGVncmVlJzsgMTEwOjExNj0nNF9CQXBsdXNfR3JhZERlZ3JlZSc7IGVsc2U9TkEiKQ0KDQoNCiNFbXBsb3ltZW50IHN0YXR1cw0KZGF0YSRlbXBsb3llZCA8LSBSZWNvZGUoZGF0YSRlbXBzdGF0ZCwgcmVjb2RlcyA9ICIxMDoxMj0xOyAyMDoyMj0wOyBlbHNlPU5BIikNCg0KZGF0YSRpbmNfd2FnZTwtIFJlY29kZShkYXRhJGluY3dhZ2UsIHJlY29kZXMgPSAiMD1OQSIpDQoNCg0KYGBgDQoNCg0KU28gbm93IHdlIGhhdmUgbG90cyBvZiB0aGluZ3MgcmVjb2RlZCwgd2UgY2FuIGRvIHNvbWUgZGVzY3JpcHRpdmUgYW5hbHlzaXMuIEZvciBleGFtcGxlLCBsZXQncyBsb29rIGF0IGluY29tZSBieSBnZW5kZXIgaW4gVGV4YXMgY2l0aWVzDQpgYGB7cn0NCmRhdGE8LWRhdGElPiUNCiAgZmlsdGVyKGxhYmZvcmNlPT0yLHN0YXRlZmlwPT0iNDgiLCBhZ2U+MTgpICU+JQ0KICBtdXRhdGUobmV3d2FnZT0gaWZlbHNlKGluY3dhZ2UlaW4lYyg5OTk5OTgsOTk5OTk5KSwgTkEsIGluY3dhZ2UpLA0KICAgICAgICAgc2V4cmVjb2RlPWlmZWxzZShzZXg9PTEsICJtYWxlIiwgImZlbWFsZSIpLA0KICAgICAgICAgY2l0eXJlYyA9IGNhc2Vfd2hlbiguJG1ldDIwMTM9PTExMTAwfiJBbWFyaWxsbyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kbWV0MjAxMyA9PSAxMjQyMH4iQXVzdGluIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJG1ldDIwMTM9PTE1MTgwIH4iQnJvd25zdmlsbGUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJG1ldDIwMTM9PSAxNzc4MCB+ICJDb2xsZWdlIFN0YXRpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kbWV0MjAxMz09IDE4NTgwIH4gIkNvcnB1cyBDaHJpc3RpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJG1ldDIwMTM9PSAyMTM0MCB+ICJFbCBQYXNvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJG1ldDIwMTM9PSAyNjQyMCB+ICJIb3VzdG9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJG1ldDIwMTM9PSAyOTcwMH4gIkxhcmVkbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRtZXQyMDEzPT0gMzI1ODB+ICJNY0FsbGVuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJG1ldDIwMTM9PSA0NzM4MH4gIldhY28iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJG1ldDIwMTM9PSA0MTcwMCB+ICJTYW4gQW50b25pbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRtZXQyMDEzPT0gMTkxMDAgfiAiRGFsbGFzIikpDQoNCmRhdGElPiUNCiAgZ3JvdXBfYnkoc2V4cmVjb2RlLCBjaXR5cmVjKSU+JQ0KICBzdW1tYXJpc2UobWVkX2luY29tZT1tZWRpYW4obmV3d2FnZSwgbmEucm09VCksIG49bigpKSU+JQ0KICBnZ3Bsb3QoYWVzKGNpdHlyZWMsIG1lZF9pbmNvbWUpKStnZW9tX2JhcihhZXMoZmlsbD1zZXhyZWNvZGUpLHBvc2l0aW9uPSJkb2RnZSIsIHN0YXQ9ImlkZW50aXR5IikreWxhYigiTWVkaWFuIEluY29tZSIpK3hsYWIoIk1ldHJvIEFyZWEiKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQoNCmBgYA0KDQpXZSBjYW4gZG8gYSByZWdyZXNzaW9uIGFuYWx5c2lzIG9mIGluY29tZSBkaWZmZXJlbmNlcyBieSB2YXJpb3VzIGZhY3RvcnMuIA0KDQpCZWZvcmUgd2UgZG8gdGhpcywgc2luY2UgdGhlIEFDUyBpcyBhIGNvbXBsZXggc3VydmV5LCB3ZSBjYW5ub3Qgc2ltcGx5IHVzZSByZWd1bGFyIG1ldGhvZHMgZm9yIHJlZ3Jlc3Npb24gYW5hbHlzaXMsIHdlIG11c3QgY2x1c3RlciBzdGFuZGFyZCBlcnJvcnMgYnkgc2FtcGxpbmcgY2x1c3RlciBhbmQgc3RyYXRhIGFuZCBmYWN0b3IgaW4gcGVyc29uLXdlaWdodHMgaW4gdGhlIGFuYWx5c2lzLiANCg0KVGhpcyBtZWFucyB3ZSBtdXN0IGRlZmluZSBhIGZvcm1hbCBzdXJ2ZXkgZGVzaWduIG9iamVjdC4gDQoNCkkgcmVzdHJpY3QgdGhlIGFuYWx5c2lzIHRvIG9ubHkgVGV4YXMgYW5kIGNvbnRyb2wgZm9yIHZhcmlvdXMgZGVtb2dyYXBoaWMgYW5kIHNvY2lvZWNvbm9taWMgZmFjdG9ycywgdGhlbiBjb21wYXJlIGFjcm9zcyBjaXRpZXMuIA0KDQoNCg0KYGBge3J9DQpkYXRhPC1kYXRhJT4lDQogIGZpbHRlcihlbXBsb3llZD09MSklPiUNCiAgbmEub21pdCgpDQoNCmxpYnJhcnkoc3VydmV5KQ0KbGlicmFyeShzcGxpbmVzKQ0KZGVzaWduPC1zdnlkZXNpZ24oaWRzPX5jbHVzdGVyLCBzdHJhdGE9fnN0cmF0YSwgd2VpZ2h0cz1+cHd0LCBkYXRhPWRhdGEpDQoNCiNCYXNlIGNpdHkgZGlmZmVyZW5jZSBtb2RlbA0KaW5jX21vZF8xPC0gc3Z5Z2xtKGxvZyhpbmNfd2FnZSl+Y2l0eXJlYywNCiAgICAgICAgICAgICAgICAgZGVzaWduID0gZGVzaWduKQ0KDQojY2l0eSBkaWZmZXJlbmNlIGFmdGVyIGNvbnRyb2xsaW5nIGZvciBkZW1vZ3JhcGhpYyBmYWN0b3JzDQppbmNfbW9kPC0gc3Z5Z2xtKGxvZyhpbmNfd2FnZSl+bWFsZSt1c2Jvcm4rZWR1Y19sZXZlbCticyhhZ2UpK2NpdHlyZWMsDQogICAgICAgICAgICAgICAgIGRlc2lnbiA9IGRlc2lnbikNCg0Kc3VtbWFyeShpbmNfbW9kXzEpDQpzdW1tYXJ5KGluY19tb2QpDQpgYGAgIA0KDQoNClxuZXdwYWdlDQoNCiMgT3RoZXIgUmVzb3VyY2VzDQojIyMgTWlrdGVrDQpUbyBidWlsZCBwZGYncyB5b3UnbGwgbmVlZCBhIHZlcnNpb24gb2YgTGF0ZXggaW5zdGFsbGVkLCBbTWlrdGVrXShodHRwczovL21pa3RleC5vcmcvZG93bmxvYWQpIGlzIGEgZ29vZCBvcHRpb24NCg0KIyMjIFItbWFya2Rvd24gY2hlYXQgc2hlZXRzDQpSc3R1ZGlvIGtlZXBzIGEgdmFyaWV0eSBvZiBbY2hlYXQgc2hlZXRzXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvKSBmb3IgdmFyaW91cyB0b3BpY3MsIHRoZXkgY2FuIGJlIGhlbHBmdWwgaW4gYSBwaW5jaA0KDQoNCiMjIyBVQ0xBIFN0YXRpc3RpY2FsIGNvbXB1dGluZyBoZWxwDQpbVGhpcyBwYWdlXShodHRwOi8vd3d3LmF0cy51Y2xhLmVkdS9zdGF0LykgaGFzIGxvdHMgb2YgZXhhbXBsZXMgb2YgdXNpbmcgUiBmb3IgdmFyaW91cyB0eXBlcyBvZiBhbmFseXNpcy4NCg0KIyMjIE90aGVyIGV4YW1wbGVzDQpPbiBbbXkgUnB1YnMgcGFnZV0oaHR0cDovL3JwdWJzLmNvbS9jb3JleV9zcGFya3MpIEkgaGF2ZSBsb3RzIG9mIGV4YW1wbGVzIG9mIHZhcmlvdXMgdHlwZXMgb2YgYW5hbHlzaXMgdXNpbmcgUiBhbmQgeW91IGNhbiBnZXQgdGhlIGRhdGEgZm9yIHRoZXNlIG9uIFtteSBHaXRodWIgZGF0YSAgcGFnZV0oaHR0cHM6Ly9naXRodWIuY29tL2NvcmV5c3BhcmtzL2RhdGEpDQoNCiMjIFRoYW5rcyENCkxldCBtZSBrbm93IGhvdyBJIGNhbiBoZWxwIQ0KDQpbQENvcmV5c3BhcmtzMV0oaHR0cHM6Ly90d2l0dGVyLmNvbS9Db3JleVNwYXJrczEpDQoNCltHaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9jb3JleXNwYXJrcykNCg0KW1JwdWJzXShodHRwOi8vcnB1YnMuY29tL2NvcmV5X3NwYXJrcykNCg0KW1VUU0EgRGVtb2dyYXBoeV0oaHR0cDovL2NvcHAudXRzYS5lZHUvZGVtb2dyYXBoeS8pDQoNCg==