Data Collection
Study area: Chautauqua County Data: 2021 Tax Parcel data; road
network; schools; 2021 census data B01001 SEX BY AGE (2020 5yr) https://data.census.gov/cedsci/table?q=population&g=0500000US36013%241500000&tid=ACSDT5Y2020.B01001
B14002 Sex by school enrollment by level of school by type of school for
the population 3 years and over https://data.census.gov/cedsci/table?q=education&g=0500000US36013%241500000&tid=ACSDT5Y2020.B14002
B08007 Sex of workers by place of work–state and county level https://data.census.gov/cedsci/table?q=employment,%20age&g=0500000US36013%241500000&tid=ACSDT5Y2020.B08007
B01002 MEDIAN AGE BY SEX (2020 5yr) https://data.census.gov/cedsci/table?q=population&g=0500000US36013%241500000&tid=ACSDT5Y2020.B01002
B09019 HOUSEHOLD TYPE (INCLUDING LIVING ALONE) BY RELATIONSHIP (2020
5yr) https://data.census.gov/table?q=B09019&g=0500000US36013$1500000
B09021 LIVING ARRANGEMENTS OF ADULTS 18 YEARS AND OVER BY AGE https://data.census.gov/cedsci/table?q=B09021&g=0500000US36013%241500000&tid=ACSDT5Y2020.B09021
B11005 HOUSEHOLDS BY PRESENCE OF PEOPLE UNDER 18 YEARS BY HOUSEHOLD TYPE
(2020 5yr) https://data.census.gov/cedsci/table?q=children&g=0500000US36013%241500000&tid=ACSDT5Y2020.B11005
B09021 LIVING ARRANGEMENTS OF ADULTS 18 YEARS AND OVER BY AGE https://data.census.gov/cedsci/table?q=B09021&g=0500000US36013%241500000
B11004 FAMILY TYPE BY PRESENCE AND AGE OF RELATED CHILDREN UNDER 18
YEARS (2020 5yr) https://data.census.gov/cedsci/table?q=children&g=0500000US36013%241500000&tid=ACSDT5Y2020.B11004
B09020 RELATIONSHIP BY HOUSEHOLD TYPE (INCLUDING LIVING ALONE) FOR THE
POPULATION 65 YEARS AND OVER https://data.census.gov/cedsci/table?q=Household%20type%20child&g=0500000US36013%241500000&tid=ACSDT5Y2020.B09020
B11001 HOUSEHOLD TYPE (INCLUDING LIVING ALONE) https://data.census.gov/cedsci/table?q=Household%20type&g=0500000US36013%241500000&tid=ACSDT5Y2020.B11001
B11012 HOUSEHOLDS BY TYPE https://data.census.gov/cedsci/table?q=Household%20type&g=0500000US36013%241500000&tid=ACSDT5Y2020.B11012
P5 Group Quarters Population By Major Group Quarters Type (2020 Decennial)
https://data.census.gov/cedsci/table?q=Group%20Quarters%20Population&g=0500000US36013%241500000
2020 Urban Area Clusters
https://www.census.gov/cgi-bin/geo/shapefiles/index.php?year=2020&layergroup=Urban+Areas
# UNUSED
B11012 HOUSEHOLDS BY TYPE
https://data.census.gov/cedsci/table?q=Household%20type&g=0500000US36013%241500000&tid=ACSDT5Y2020.B11012
B11016 HOUSEHOLD TYPE BY HOUSEHOLD SIZE
https://data.census.gov/cedsci/table?q=Household%20type&g=0500000US36013%241500000&tid=ACSDT5Y2020.B11016
P5 Group Quarters Population By Major Group Quarters Type (2020 Decennial)
https://data.census.gov/cedsci/table?q=Group%20Quarters%20Population&g=0500000US36013%241500000
U.S. Census Bureau’s Longitudinal Employer-Household Dynamics (LEHD) Origin-Destination Employment Statistics (LODES)
0-18 School locations
18-22 University
Chautauqua: COUNTYFP: “013” COUNTYNS: “00974105” GEOID: “36013”
Spatial Data
Projected CRS: NAD83 / UTM zone 18N
# County
tt <- st_read("data/tl_2021_us_county/tl_2021_us_county.shp")
c_county <- tt[tt$COUNTYNS=="00974105",]
# Tract
tt <- st_read("data/tl_2021_36_tract/tl_2021_36_tract.shp")
c_tract <- tt[tt$COUNTYFP=="013",]
# Block Groups
tt <- st_read("data/tl_2021_36_bg/tl_2021_36_bg.shp")
c_bgroup <- tt[tt$COUNTYFP=="013",]
# Parcel & Residential Parcel
c_parcel <- st_read("data/Chautauqua_2021_Tax_Parcels_SHP_2203/Chautauqua_2021_Tax_Parcels_SHP_2203.shp")
c_parcel_r <- c_parcel[(c_parcel$PROP_CLASS > "199" & c_parcel$PROP_CLASS < "300"),]
c_parcel_r <- c_parcel_r[!is.na(c_parcel_r$COUNTY),]
# Group Quarter Parcel: NAD83 / UTM zone 18N
c_parcel_gq <- c_parcel[c_parcel$PROP_CLASS %in% c("613","615","633","641","642","660","670"),]
# Urban Areas 2020
c_urban <- st_read(paste(dirname(dirname(getwd())), "/zz_NYS_GIS_Data/tl_2020_us_uac10/tl_2020_us_uac10.shp", sep="")) %>% filter(NAME10 %like% ", NY")
# Project spatial data (e.g., county, tract, block groups) to "NAD83 / UTM zone 18N"
c_county <- st_transform(c_county, st_crs(c_parcel_r))
c_tract <- st_transform(c_tract, st_crs(c_parcel_r))
c_bgroup <- st_transform(c_bgroup, st_crs(c_parcel_r))
c_urban <- st_transform(c_urban, st_crs(c_parcel_r))
# Urban Areas only in Chautauqua County
c_urban <- c_urban[lengths(st_intersects(c_urban,c_county))>0,]
Census (css) Data
Individual Level
# B01001 SEX BY AGE (2020 5yr)
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B01001-2022-05-19T145839.csv", colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
css_age_gender <- ttt
# B08007 Sex of workers by place of work--state and county level
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B08007-2022-05-23T034722.csv", colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
css_work_place <- ttt[c("GEOID","NAMELSAD","TRACT_NAMELSAD","m_ttl","m_Worked_in_county_of_residence",
"m_Worked_outside_county_of_residence","m_Worked_outside_state_of_residence",
"f_ttl","f_Worked_in_county_of_residence",
"f_Worked_outside_county_of_residence","f_Worked_outside_state_of_residence")]
# B09021 Living arrangements of adults 18 years and over by age
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B09021-2022-05-24T015931.csv", colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
css_over18_in_hh <- ttt
css_over18_in_hh$hhder_spouse_partner_ttl_over17 <- css_over18_in_hh$married_hhder_spouse_ttl_over17 + css_over18_in_hh$unmarried_hhder_partner_ttl_over17
css_over18_in_hh$hhder_spouse_partner_18_34 <- css_over18_in_hh$married_hhder_spouse_18_34 + css_over18_in_hh$unmarried_hhder_partner_18_34
css_over18_in_hh$hhder_spouse_partner_35_64 <- css_over18_in_hh$married_hhder_spouse_35_64 + css_over18_in_hh$unmarried_hhder_partner_35_64
css_over18_in_hh$hhder_spouse_partner_over64 <- css_over18_in_hh$married_hhder_spouse_over64 + css_over18_in_hh$unmarried_hhder_partner_over64
css_over18_in_hh <- css_over18_in_hh[,!colnames(css_over18_in_hh) %in% c("married_hhder_spouse_ttl_over17","unmarried_hhder_partner_ttl_over17","married_hhder_spouse_18_34","unmarried_hhder_partner_18_34","married_hhder_spouse_35_64", "unmarried_hhder_partner_35_64","married_hhder_spouse_over64","unmarried_hhder_partner_over64")]
# P5 Group Quarters Population By Major Group Quarters Type (2020 Decennial)
lt <- c("Institutionalized.population","Other.institutional.facilities",
"Noninstitutionalized.population","Military.quarters",
"in_groupquarter","temp")
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_DECENNIALPL2020.P5-2022-06-06T011200.csv", colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
ttt <- ttt[, !names(ttt)%in% lt]
ttt[,6:length(ttt)] <- round(ttt[,6:length(ttt)]/ttt$Total,4)
ttt[ttt == "NaN"] <- 0
ttt$temp <- apply(ttt[,6:length(ttt)], 1, sum)
ttt[ttt$temp ==0,]$Other.noninstitutional.facilities <- 1
ttt <- left_join(ttt, css_hh_type[c("GEOID","in_groupquarter")])
ttt$Total <- ttt$in_groupquarter
ttt[,6:length(ttt)] <- round(ttt[,6:length(ttt)] * ttt$Total,0)
ttt <- ttt[, !names(ttt)%in% lt]
css_group_quarter_pop <- ttt
# B09020 RELATIONSHIP BY HOUSEHOLD TYPE (INCLUDING LIVING ALONE) FOR THE POPULATION 65 YEARS AND OVER
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B09020-2022-06-13T143729.csv",
colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
# combine parent & parent-in-law
ttt$over64_parent_or_inlaw <- ttt$over64_parent + ttt$over64_parent.in.law
# combine (family/non-family) non-relatives with relatives
ttt$over64_relatives_nonrelatives <- ttt$over64_other_relatives + ttt$over64_nonrelatives + ttt$over64_nonfamily_nonrelatives
# combine family householder with non-family not-alone householder
ttt$over64_m_hhder_not_alone <- ttt$over64_m_hhder + ttt$over64_nonfamily_m_hhder_not_alone
ttt$over64_f_hhder_not_alone <- ttt$over64_f_hhder + ttt$over64_nonfamily_f_hhder_not_alone
lt <- c("over64_in_hh","over64_in_hh_family","over64_in_hh_nonfamily",
"over64_parent","over64_parent.in.law",
"over64_other_relatives","over64_nonrelatives","over64_nonfamily_nonrelatives",
"over64_m_hhder","over64_nonfamily_m_hhder_not_alone",
"over64_f_hhder","over64_nonfamily_f_hhder_not_alone")
ttt <- ttt[,!colnames(ttt) %in% lt]
css_over64_in_hh <- ttt
# ------------ Backup -----------
# # B14002 Sex by school enrollment by level of school by type of school for the population 3 years and over
# ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B14002-2022-05-23T033555.csv", colClasses = "character")
# ttt <- cln_census_geoid(ttt, idx_cbgroup)
# ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
# css_school_enroll <- ttt
Household level
# B09019 household type (including living alone) by relationship
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B09019-2022-05-19T155332.csv", colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
css_hh_type <- ttt
css_hh_type$hhmber_Opposite_sex <- css_hh_type$hhmber_Opposite_sex_spouse + css_hh_type$hhmber_Opposite_sex_unmarried_partner
css_hh_type$hhmber_Same_sex <- css_hh_type$hhmber_Same_sex_spouse + css_hh_type$hhmber_Same_sex_unmarried_partner
css_hh_type$hhmber_Child <- css_hh_type$hhmber_Child + css_hh_type$hhmber_Foster_child
css_hh_type$hhmber_Other <- css_hh_type$hhmber_Other_nonrelatives + css_hh_type$hhmber_Other_relatives
css_hh_type <- css_hh_type[, !colnames(css_hh_type) %in% c("hhmber_Opposite_sex_spouse","hhmber_Opposite_sex_unmarried_partner",
"hhmber_Same_sex_spouse", "hhmber_Same_sex_unmarried_partner","hhmber_Foster_child",
"hhmber_Other_nonrelatives", "hhmber_Other_relatives")]
# B11012 HOUSEHOLDS BY TYPE - married + cohabiting. This df helps to identify married & cohabiting hh. Ignore the udr18 information.
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B11012-2022-06-20T211726.csv", colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
css_hh_type_2 <- ttt
# B11005 households by presence of people under 18 years by household type
ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B11005-2022-05-19T162036.csv", colClasses = "character")
ttt <- cln_census_geoid(ttt, idx_cbgroup)
ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
css_hh_with_udr18 <- ttt
# ------------ Backup -----------
# # B11004 family type by presence and age of related children under 18 years
# ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B11004-2022-05-19T162839.csv", colClasses = "character")
# ttt <- cln_census_geoid(ttt, idx_cbgroup)
# ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
# css_hh_with_udr18_brkdown <- ttt
# # B11001 HOUSEHOLD TYPE (INCLUDING LIVING ALONE)
# ttt <- read.csv("data/ACSDT5Y2020_chau_block_group_cleaned/Chautanqua_bg_ACSDT5Y2020.B11001-2022-06-20T172331.csv", colClasses = "character")
# ttt <- cln_census_geoid(ttt, idx_cbgroup)
# ttt[,5:length(ttt)] <- cln_census_numeric(ttt[,5:length(ttt)])
# css_hh_type_2 <- ttt
Reorganize household type
# 1: married family and cohabiting couple household (married_cohabiting)
data <- css_hh_type_2[,c(1,5:21)]
## new columns
data$hh_married_cohabiting <- data$hh_family_married + data$hh_cohabiting_couple
data$hh_married_cohabiting_udr18 <- data$hh_family_married_with_udr18 + data$hh_cohabiting_couple_with_udr18
data$hh_married_cohabiting_NO18 <- data$hh_family_married_NO_udr18 + data$hh_cohabiting_couple_NO_udr18
# join two household level data
data <- left_join(data, css_hh_type[c("GEOID","hhder_ttl","hhder_m_ttl","hhder_f_ttl")])
# new columns
data$hh_f_hhder_married_cohabiting <- data$hhder_f_ttl - data$hh_f_hhder_nospouse
data$hh_m_hhder_married_cohabiting <- data$hhder_m_ttl - data$hh_m_hhder_nospouse
# Validate
data$hh_family_married + data$hh_cohabiting_couple -
data$hh_f_hhder_married_cohabiting - data$hh_m_hhder_married_cohabiting
# Final household level dataset
data <- data[c("GEOID","hh_ttl","hhder_m_ttl","hhder_f_ttl",
"hh_m_hhder_married_cohabiting","hh_f_hhder_married_cohabiting",
"hh_m_hhder_nospouse","hh_f_hhder_nospouse",
"hh_married_cohabiting","hh_married_cohabiting_udr18","hh_married_cohabiting_NO18",
"hh_m_hhder_nospouse_alone","hh_m_hhder_nospouse_with_udr18",
"hh_m_hhder_nospouse_with_relatives","hh_m_hhder_nospouse_non_relatives",
"hh_f_hhder_nospouse_alone","hh_f_hhder_nospouse_with_udr18",
"hh_f_hhder_nospouse_with_relatives","hh_f_hhder_nospouse_non_relatives")]
# 2: Householder Alone >= 65
tt <- css_over64_in_hh[c("GEOID","over64_nonfamily_m_hhder_alone","over64_nonfamily_f_hhder_alone")]
setnames(tt, old=c("over64_nonfamily_m_hhder_alone","over64_nonfamily_f_hhder_alone"),
new = c("hh_m_hhder_nospouse_alone_over64","hh_f_hhder_nospouse_alone_over64"))
data <- left_join(data, tt)
# 3: Classify household into 12 types
## -------- Married or Cohabiting Couple ------
data$h1_mc_udr18 <- data$hh_married_cohabiting_udr18
data$h2_mc_NO18 <- data$hh_married_cohabiting_NO18
## -------- Male householder no spouse ------
data$h3_mns_alone_less65 <- data$hh_m_hhder_nospouse_alone - data$hh_m_hhder_nospouse_alone_over64
data$h4_mns_alone_over64 <- data$hh_m_hhder_nospouse_alone_over64
data$h5_mns_udr18 <- data$hh_m_hhder_nospouse_with_udr18
data$h6_mns_NO18_others <- data$hh_m_hhder_nospouse_with_relatives
data$h7_mns_nonfamily <- data$hh_m_hhder_nospouse_non_relatives
## -------- Female householder no spouse ------
data$h8_fns_alone_less65 <- data$hh_f_hhder_nospouse_alone - data$hh_f_hhder_nospouse_alone_over64
data$h9_fns_alone_over64 <- data$hh_f_hhder_nospouse_alone_over64
data$h10_fns_udr18 <- data$hh_f_hhder_nospouse_with_udr18
data$h11_fns_NO18_others <- data$hh_f_hhder_nospouse_with_relatives
data$h12_fns_nonfamily <- data$hh_f_hhder_nospouse_non_relatives
css_hh_type_fnl <- data
# 4: Group Quarters, pop >= 65
data <- css_over64_in_hh[c("GEOID","over64_in_gqquarter")]
data <- left_join(css_group_quarter_pop, data)
data$age_13_18_juvenilefacilities <- data$Juvenile.facilities
data$age_15_24_college <- data$College.University.student.housing
data$age_18_64_other <- data$Total - data$over64_in_gqquarter - data$age_13_18_juvenilefacilities - data$age_15_24_college
css_group_quarter_pop_2 <- data
Generate Individual Population
# set random seed
set.seed(rm_seed)
dfs_ind <- list()
for (i in 1:length(lt_geoid_bg)) {
# create an empty dataframe for individuals in census bg i
tt <- css_age_gender[css_age_gender$GEOID == lt_geoid_bg[[i]],]$ttl
df <- setnames(data.frame(matrix(nrow = tt, ncol = 5)), new = c("ind_id","gender","age","hh_id","hh_role"))
# unique identifier & gender & age
df$ind_id <- paste(lt_geoid_bg[[i]], "_ind_",rownames(df), sep = "")
df$gender <- rep(c("Male","Female"), times = c(css_age_gender[css_age_gender$GEOID == lt_geoid_bg[[i]],]$m_ttl,
css_age_gender[css_age_gender$GEOID == lt_geoid_bg[[i]],]$f_ttl))
df$age <- ind_age_generator(lt_geoid_bg[[i]])
# append dataframe to the list
dfs_ind[[length(dfs_ind) + 1]] <- df
}
names(dfs_ind) <- lt_geoid_bg
Assign: Group Quarter
# set random seed
set.seed(rm_seed)
# Prepare data frame
foo <- dfs_ind # individual
dfs_gquarter <- list()
for (i in 1:length(lt_geoid_bg)) {
# Start Here
idx <- lt_geoid_bg[[i]]
m <- css_group_quarter_pop_2 %>% filter(GEOID == idx) %>%
select(c("Total","age_13_18_juvenilefacilities","age_15_24_college","age_18_64_other","over64_in_gqquarter")) %>%
unlist() %>% as.matrix()
m <- m + 0.01
# Create an empty dataframe to store group quarter populations
df <- data.frame(matrix(nrow = 0, ncol = 2)) %>% setnames(new = c("ind_id","type"))
if(m[1] > 0){
data <- foo[[idx]]
# College Student
a <- data %>% filter(is.na(hh_role) & age %in% 15:24) %>% slice_sample( n = m[3]) %>% pull(ind_id)
data[data$ind_id %in% a,"hh_role"] <- "in_gq"
data[data$ind_id %in% a,"hh_id"] <- "gq_college_housing"
# Juvenile_facility
b <- data %>% filter(is.na(hh_role) & age %in% 13:18) %>% slice_sample( n = m[2]) %>% pull(ind_id)
data[data$ind_id %in% b,"hh_role"] <- "in_gq"
data[data$ind_id %in% b,"hh_id"] <- "gq_Juvenile_facility"
# Other adult
c <- data %>% filter(is.na(hh_role) & age %in% 18:64) %>% slice_sample( n = m[4]) %>% pull(ind_id)
data[data$ind_id %in% c,"hh_role"] <- "in_gq"
data[data$ind_id %in% c,"hh_id"] <- "gq_others_adult"
# Other for over 64
d <- data %>% filter(is.na(hh_role) & age > 64) %>% slice_sample( n = m[5]) %>% pull(ind_id)
data[data$ind_id %in% d,"hh_role"] <- "in_gq"
data[data$ind_id %in% d,"hh_id"] <- "gq_others_adult_over64"
}
# Collect all individuals in gq
df <- data %>% filter(hh_role == "in_gq")
dfs_gquarter[[length(dfs_gquarter) + 1]] <- df
foo[[idx]] <- data
print(i)
}
names(dfs_gquarter) <- lt_geoid_bg
dfs_ind <- foo
HOUSEHOLD
Create empty HH container for 12 types
# set random seed
set.seed(rm_seed)
# Table: css_hh_type_fnl
foo <- dfs_ind # individual
dfs_hh <- list()
lt <- names(css_hh_type_fnl[,22:33])
# Start Loop to create household df containers
for (i in 1:length(lt_geoid_bg)) {
# start here, get census block group index
idx <- lt_geoid_bg[[i]]
m <- css_hh_type_fnl %>% filter(GEOID == idx) %>% select(c(22:33)) %>% unlist()
df <- data.frame(hh_id = NA,type = rep(lt, m), if_pop = 0)
df$hh_id <- paste(idx, "_hh_",rownames(df), sep = "")
dfs_hh[[1+length(dfs_hh)]] <- df
}
names(dfs_hh) <- lt_geoid_bg
Fill Type 1: h1_mc_udr18
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# Initialize
child_mom_brks <- c(0,17,41,100)
mom_dad_brks <- c(-100,-5,9,100)
labls <- c(0,1,0)
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# household to fill
lt_temp <- df %>% filter(type == "h1_mc_udr18") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age < 18) %>% nrow()
n <- min(length(lt_temp), n)
if(n > 0){
for (j in 1:n) {
hh_idx <- lt_temp[[j]]
# While loop start
oo = 0
while (oo == 0) {
# Randomly select one child < 18
a <- data %>% filter(is.na(hh_id) & age < 18) %>% slice_sample(n=1)
b <- data %>% filter(is.na(hh_id) & gender == "Female" & age >=18) %>% slice_sample(n=1)
c <- data %>% filter(is.na(hh_id) & gender == "Male" & age >=18) %>% slice_sample(n=1)
o1 <- as.numeric(as.character(cut(b$age - a$age, breaks = child_mom_brks, labels = labls)))
o2 <- as.numeric(as.character(cut(c$age - b$age, breaks = mom_dad_brks, labels = labls)))
oo <- o1 * o2
}
# Save Result
data[data$ind_id == a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"child_udr18")
data[data$ind_id == b$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"mom")
data[data$ind_id == c$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"dad")
print(j)
}
}
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
dfs_ind <- foo
# # save the result
# # imp_dfs_ind <- dfs_ind
# data <- export_imp_dfs(imp_dfs_ind)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step1_populate_type1_h1_mc_udr18.csv", row.names = F)
Fill Type 5&10: single parent
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# Initialize
child_mom_brks <- c(0,17,41,100)
child_dad_brks <- c(0,17,49,100)
labls <- c(0,1,0)
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# type 5: h5_mns_udr18 household to fill
lt_temp <- df %>% filter(type == "h5_mns_udr18") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age < 18) %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
for (j in 1:n) {
hh_idx <- lt_temp[[j]]
oo=0 # while loop stop condition oo=1
n_loop = 1000
while (oo==0 & n_loop > 0) {
a <- data %>% filter(age < 18 & is.na(hh_id)) %>% slice_sample(n=1)
b <- data %>% filter(gender=="Male" & age >=18 & is.na(hh_id)) %>% slice_sample(n=1)
oo <- as.numeric(as.character(cut(b$age - a$age, breaks = child_dad_brks, label = labls)))
n_loop = n_loop-1 }
if(n_loop <=0){break}
# Save Result
data[data$ind_id == a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"child_udr18")
data[data$ind_id == b$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"single_dad")
print(paste("single_dad ",j, sep = " "))
} }
# type 10: h10_fns_udr18
lt_temp <- df %>% filter(type == "h10_fns_udr18") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age < 18) %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
for (j in 1:n) {
hh_idx <- lt_temp[[j]] # household id
oo=0
n_loop = 1000
while (oo==0 & n_loop > 0) {
a <- data %>% filter(is.na(hh_role) & age < 18) %>% slice_sample(n=1)
c <- data %>% filter(is.na(hh_role) & age >= 18 & gender=="Female") %>% slice_sample(n=1)
oo <- as.numeric(as.character(cut(c$age - a$age, breaks = child_mom_brks, label = labls)))
n_loop = n_loop-1
}
if(n_loop <=0){break}
# Save Result
data[data$ind_id == a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"child_udr18")
data[data$ind_id == c$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"single_mom")
print(paste("single_mom ",j, sep = " "))
}
}
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
# # save result
# data <- export_imp_dfs(dfs_ind)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step2_populate_type5_10_single_parent.csv", row.names = F)
# dfs_ind <- foo
Fill Type 4&9: alone >64
h4_mns_alone_over64 h9_fns_alone_over64
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# Populate
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# ------------- MALE ALONE > 64
# number of hh with older MALE singleton
lt_temp <- df %>% filter(type=="h4_mns_alone_over64") %>% pull(hh_id)
# count of individuals satisfying constraints
n <- data %>% filter(is.na(hh_role) & gender =="Male" & age > 64) %>% nrow()
n <- min(length(lt_temp), n)
if(n>0)(
for (j in 1:n) {
hh_idx <- lt_temp[[j]] # household id
a <- data %>% filter(is.na(hh_role) & gender =="Male" & age > 64) %>% slice_sample(n=1)
# Save Result
data[data$ind_id == a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"male_oldersingleton")
})
# ------------- FEMALE ALONE > 64
# number of hh with older FEMALE singleton
lt_temp <- df %>% filter(type=="h9_fns_alone_over64") %>% pull(hh_id)
# count of individuals satisfying constraints
n <- data %>% filter(is.na(hh_role) & gender =="Female" & age > 64) %>% nrow()
n <- min(length(lt_temp), n)
if(n>0)(
for (j in 1:n) {
hh_idx <- lt_temp[[j]] # household id
a <- data %>% filter(is.na(hh_role) & gender =="Female" & age > 64) %>% slice_sample(n=1)
# Save Result
data[data$ind_id == a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"female_oldersingleton")
})
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
# # # save result
# data <- export_imp_dfs(foo)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step3_populate_type4_9_older_singleton.csv", row.names = F)
# dfs_ind <- foo
Fill Type 2: h2_mc_NO18
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# Initialize
mom_dad_brks <- c(-100,-5,9,100)
labls <- c(0,1,0)
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# ------------- fill type 2: h2_mc_NO18
# decide the minimum number of hh to fill
lt_temp <- df %>% filter(type == "h2_mc_NO18") %>% pull(hh_id)
n <- min(data %>% filter(is.na(hh_role) & age >= 18 & gender=="Male") %>% nrow(),
data %>% filter(is.na(hh_role) & age >= 18 & gender=="Female") %>% nrow())
n <- min(length(lt_temp), n)
if(n>0)(
for (j in 1:n) {
hh_idx <- lt_temp[[j]]
# Define stop condition
oo=0
n_loop = 1000 # maximum runs
while (oo ==0 & n_loop >0) {
a <- data %>% filter(is.na(hh_role) & age >=18 & gender=="Male") %>% slice_sample(n=1)
b <- data %>% filter(is.na(hh_role) & age >=18 & gender=="Female") %>% slice_sample(n=1)
oo <- as.numeric(as.character(cut(a$age - b$age, breaks = mom_dad_brks, label = labls)))
n_loop = n_loop -1
}
if(n_loop <=0){break}
# Save Result
data[data$ind_id == a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"husband_NO_udr18")
data[data$ind_id == b$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"wife_NO_udr18")
print(paste("mc_NO_18",j, sep = " "))
}
)
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
# # # save result
# data <- export_imp_dfs(foo)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step4_populate_type2_h2_mc_NO18.csv", row.names = F)
# dfs_ind <- foo
data <- read.csv("data/00_saved_dataset/01_step4_populate_type2_h2_mc_NO18.csv")
Fill Type 3&8: Adult alone < 65
h3_mns_alone_less65 h8_fns_alone_less65
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# type 3: h3_mns_alone_less65
lt_temp <- df %>% filter(type == "h3_mns_alone_less65") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age >=18 & age <65 & gender =="Male") %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
a <- data %>% filter(is.na(hh_role) & age >=18 & age <65 & gender =="Male") %>% slice_sample(n=n) %>% pull("ind_id")
data[data$ind_id %in% a,]$hh_id <- lt_temp[1:n]
data[data$ind_id %in% a,]$hh_role <- "mns_alone_less65"
}
# type 8: h8_fns_alone_less65
lt_temp <- df %>% filter(type == "h8_fns_alone_less65") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age >=18 & age <65 & gender =="Female") %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
b <- data %>% filter(is.na(hh_role) & age >=18 & age <65 & gender =="Female") %>% slice_sample(n=n) %>% pull("ind_id")
data[data$ind_id %in% b,]$hh_id <- lt_temp[1:n]
data[data$ind_id %in% b,]$hh_role <- "fns_alone_less65"
}
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
# save result
# data <- export_imp_dfs(foo)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step5_populate_type3_8_alone_less65.csv")
#
# dfs_ind <- foo
Fill Type 6&11: Adult not alone with other relatives
h6_mns_NO18_others h11_fns_NO18_others
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# populate adult
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# Type 6: h6_mns_NO18_others
lt_temp <- df %>% filter(type == "h6_mns_NO18_others") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age >= 18 & gender=="Male") %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
a <- data %>% filter(is.na(hh_role) & age >= 18 & gender=="Male") %>% slice_sample(n=n) %>% pull(ind_id)
data[data$ind_id %in% a,]$hh_id <- lt_temp[1:n]
data[data$ind_id %in% a,]$hh_role <- "mns_no18_other_relative"
}
# Type 11: h11_fns_NO18_others
lt_temp <- df %>% filter(type == "h11_fns_NO18_others") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age >= 18 & gender=="Female") %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
b <- data %>% filter(is.na(hh_role) & age >= 18 & gender=="Female") %>% slice_sample(n=n) %>% pull(ind_id)
data[data$ind_id %in% b,]$hh_id <- lt_temp[1:n]
data[data$ind_id %in% b,]$hh_role <- "fns_no18_other_relative"
}
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
# save result
# data <- export_imp_dfs(foo)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step6_populate_type6_11_adult_hhder_NOsp_NO18_otherrelatives.csv")
# dfs_ind <- foo
# imp_dfs_ind <- dfs_ind
# imp_dfs_hh <- dfs_hh
Fill Child >= 18
Get child age limit
# set random seed
set.seed(rm_seed)
# Table
foo <- imp_dfs_ind # individual
tt <- imp_dfs_hh # household
# Find the the lower and higher bound of child age
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# -------------
# MALE householder - potential father
a <- data %>% filter(hh_role %in% c("dad","husband_NO_udr18","single_dad","mns_no18_other_relative"))
# FEMALE householder - potential mother
b <- data %>% filter(hh_role %in% c("mom","wife_NO_udr18","single_mom","fns_no18_other_relative"))
df <- left_join(df,a[c("hh_id","age")], by=c("hh_id"="hh_id"))
df <- setnames(df, old="age",new="male_hhder_age")
df <- left_join(df,b[c("hh_id","age")], by=c("hh_id"="hh_id"))
df <- setnames(df, old="age",new="female_hhder_age")
# Child age limit
df$child_lo_b <- 999
df$child_hi_b <- -1
df[!is.na(df$female_hhder_age),]$child_lo_b <- df[!is.na(df$female_hhder_age),]$female_hhder_age - 40
df[!is.na(df$female_hhder_age),]$child_hi_b <- df[!is.na(df$female_hhder_age),]$female_hhder_age - 18
df[(!is.na(df$male_hhder_age) & !is.na(df$female_hhder_age)),]$child_lo_b <- mapply(max,
df[(!is.na(df$male_hhder_age) & !is.na(df$female_hhder_age)),]$male_hhder_age - 49,
df[(!is.na(df$male_hhder_age) & !is.na(df$female_hhder_age)),]$child_lo_b)
df[(!is.na(df$male_hhder_age) & !is.na(df$female_hhder_age)),]$child_hi_b <- mapply(min,
df[(!is.na(df$male_hhder_age) & !is.na(df$female_hhder_age)),]$male_hhder_age - 18,
df[(!is.na(df$male_hhder_age) & !is.na(df$female_hhder_age)),]$child_hi_b)
df[(!is.na(df$male_hhder_age) & is.na(df$female_hhder_age)),]$child_lo_b <- df[(!is.na(df$male_hhder_age) & is.na(df$female_hhder_age)),]$male_hhder_age - 49
df[(!is.na(df$male_hhder_age) & is.na(df$female_hhder_age)),]$child_hi_b <- df[(!is.na(df$male_hhder_age) & is.na(df$female_hhder_age)),]$male_hhder_age - 18
tt[[idx]] <- df
# print(paste(i,"done",sep = "----------------"))
}
Assign child >= 18
# set random seed
set.seed(rm_seed)
# Use previous tables: foo (individual) & tt (household)
# Populate by census block group
lt_hhtype_temp <- c("h1_mc_udr18","h2_mc_NO18","h5_mns_udr18","h6_mns_NO18_others","h10_fns_udr18","h11_fns_NO18_others")
lt_age_range <- list(18:34,
35:64,
65:100)
labls <- c(0,1,0)
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# Census data
m1 <- css_over18_in_hh %>% filter(GEOID == idx) %>% select("child_hhmber_18_34","child_hhmber_35_64","child_hhmber_over64")
for (zz in 1:3) {
lt_age <- lt_age_range[[zz]]
# in age range
m2 <- data %>% filter(is.na(hh_role) & age %in% lt_age) %>% nrow()
n <- min(m1[1,zz], m2)
if( n>0 ){
for (j in 1:n) {
oo = 0
n_loop = 1000
while (oo==0 & n_loop > 0) {
# Household info (row)
a <- df %>% filter(type %in% lt_hhtype_temp) %>% slice_sample(n=1)
# Child info (row)
b <- data %>% filter(is.na(hh_role) & age %in% lt_age) %>% slice_sample(n=1)
# Check if in range
oo <- as.numeric(as.character(cut(b$age, breaks = c(-999, a$child_lo_b -1, a$child_hi_b, 999), label = labls)))
n_loop = n_loop-1
}
if(n_loop <=0){break}
# SAVE result to dataframe
data[data$ind_id== b$ind_id,c("hh_id","hh_role")] <- c(a$hh_id, "child_over17")
# print(paste(names(m1)[[zz]],"child_over17",j, sep = " "))
}
}
}
foo[[idx]] <- data
# print(paste(i,"done",sep = "----------------"))
}
# save result
# data <- export_imp_dfs(foo)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step7_populate_ind_child_over17.csv")
dfs_ind <- foo # individual
dfs_hh <- tt
Assign child <18
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# Populate by census block group
lt_hhtype_temp <- c("h1_mc_udr18","h5_mns_udr18","h10_fns_udr18")
labls <- c(0,1,0)
# Join individual info to household
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# Household size
a <- table(data$hh_id) %>% as.data.frame() %>% setnames(old="Freq", new="hh_size")
df <- left_join(df, a, by=c("hh_id" ="Var1"))
# Household with child over 17
a <- data %>% filter(hh_role == "child_over17")
b <- table(a$hh_id) %>% as.data.frame() %>% setnames(old="Freq", new="child_over17_count")
if(nrow(a) > 0){
df <- left_join(df, b, by=c("hh_id" ="Var1"))
a <- a[order(a$age, decreasing = T),]
a <- a[!duplicated(a$hh_id),]
a$grand_child_lo_b <- 999
a$grand_child_hi_b <- -1
a[a$gender =="Female",]$grand_child_lo_b <- a[a$gender =="Female",]$age - 40
a[a$gender =="Female",]$grand_child_hi_b <- a[a$gender =="Female",]$age - 18
a[a$gender =="Male",]$grand_child_lo_b <- a[a$gender =="Male",]$age - 49
a[a$gender =="Male",]$grand_child_hi_b <- a[a$gender =="Male",]$age - 18
a <- setnames(a, old="age", new="child_over17_age")
df <- left_join(df, a[c("hh_id","child_over17_age","grand_child_lo_b","grand_child_hi_b")], by=c("hh_id" = "hh_id"))
df[is.na(df)] <- 0
} else{
df$child_over17_count <- 0
}
tt[[idx]] <- df
# print(paste(i,"done",sep = "----------------"))
}
# Assign child udr 18
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# -------------
hh_max_size = 6
lt_temp <- df %>% filter( type %in% lt_hhtype_temp & hh_size <= hh_max_size) %>% nrow()
n <- data %>% filter(is.na(hh_role) & age < 18) %>% nrow()
if(n>0 & lt_temp>0){
for (j in 1:n) {
oo=0 # while loop stop condition oo=1
o1=0
o2=0
n_loop = 1000
while(oo==0 & n_loop > 0){
# Child
a <- data %>% filter(is.na(hh_role) & age < 18) %>% slice_sample(n=1)
# Household
b <- df %>% filter( type %in% lt_hhtype_temp & hh_size <= hh_max_size) %>% slice_sample(n=1)
o1 <- as.numeric(as.character(cut(a$age, breaks = c(-999, b$child_lo_b -1, b$child_hi_b, 999), label = labls)))
if(b$child_over17_count > 0){
o2 <- as.numeric(as.character(cut(a$age, breaks = c(-999, b$grand_child_lo_b -1, b$grand_child_hi_b, 999), label = labls)))
}
oo=o1+o2
n_loop = n_loop-1
}
if(n_loop <=0){break}
# Save Result
hh_idx <- b$hh_id
df[df$hh_id == hh_idx,]$hh_size <- df[df$hh_id == hh_idx,]$hh_size + 1
data[data$ind_id == a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"child_or_grand_udr18")
print(paste("child_udr18 ",j, sep = " "))
}
}
foo[[idx]] <- data
tt[[idx]] <- df
print(paste(i,"done",sep = "----------------"))
}
# # # save result
# data <- export_imp_dfs(foo)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step8_populate_ind_udr18_rest.csv")
dfs_ind <- foo
dfs_hh <- tt # household
Fill Type 6&11 Other relatives
# set random seed
set.seed(rm_seed)
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# Add other relatives to hh type 6&11: h6_mns_NO18_others, h11_fns_NO18_others
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# ----ONLY for check---------
# a <- table(data$hh_id) %>% as.data.frame()
# df <- left_join(df, a, by=c("hh_id"="Var1"))
# df$z <- df$Freq - df$hh_size
# print(sum(df$hh_size, na.rm = T) - nrow(data[!is.na(data$hh_id) & data$hh_role!="in_gq",]))
# ---- Houshold with other relatives but only have one member ---------
lt_temp <- df %>% filter(type %in% c("h11_fns_NO18_others", "h6_mns_NO18_others") & hh_size ==1) %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age >= 18) %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
for (j in 1:n) {
hh_idx <- lt_temp[[j]]
# randomly select an individual
a <- data %>% filter(is.na(hh_role) & age >= 18) %>% slice_sample(n=1)
data[data$ind_id==a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"other_relatives")
}
}
# ----- Non family household: Male -------
lt_temp <- df %>% filter(type == "h7_mns_nonfamily") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age >= 18 & gender == "Male") %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
for (j in 1:n) {
hh_idx <- lt_temp[[j]]
a <- data %>% filter(is.na(hh_role) & age >= 18 & gender == "Male") %>% slice_sample(n=1)
data[data$ind_id==a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"mns_non_family")
}
}
# ----- Non family household: Female -------
lt_temp <- df %>% filter(type == "h12_fns_nonfamily") %>% pull(hh_id)
n <- data %>% filter(is.na(hh_role) & age >= 18 & gender == "Female") %>% nrow()
n <- min(n, length(lt_temp))
if(n>0){
for (j in 1:n) {
hh_idx <- lt_temp[[j]]
a <- data %>% filter(is.na(hh_role) & age >= 18 & gender == "Female") %>% slice_sample(n=1)
data[data$ind_id==a$ind_id, c("hh_id","hh_role")] <- c(hh_idx,"fns_non_family")
}
}
# Randomly assign 1 non-family members
m <- data %>% filter(hh_role %in% c("fns_non_family","mns_non_family")) %>% nrow()
n <- data %>% filter(is.na(hh_role)) %>% nrow()
n <- min(m, n)
if(n >0){
lt_temp <- data %>% filter(hh_role %in% c("fns_non_family","mns_non_family")) %>% slice_sample(n=n) %>% pull(hh_id)
a <- data %>% filter(is.na(hh_role)) %>% slice_sample(n=n) %>% pull(ind_id)
data[data$ind_id %in% a,]$hh_id <- lt_temp
data[data$ind_id %in% a,]$hh_role <- "non_family_member"
}
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
# Randomly assign the rest individuals
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# ----- rest members --------
a <- table(data$hh_id) %>% as.data.frame()
df <- left_join(df, a, by=c("hh_id"="Var1"))
df$hh_size <- df$Freq
df[is.na(df)] <- 0
df <- df[df$hh_size > 0,]
# unassigned individuals
n <- data %>% filter(is.na(hh_role)) %>% nrow()
if(n > 0){
for (j in 1:n) {
a <- data %>% filter(is.na(hh_role)) %>% slice_sample(n=1) %>% pull(ind_id)
lt_temp <- df %>% filter(!type %in% c("h3_mns_alone_less65","h4_mns_alone_over64",
"h8_fns_alone_less65","h9_fns_alone_over64") &
hh_size < 7) %>% slice_sample(n=1) %>% pull(hh_id)
data[data$ind_id == a,c("hh_id","hh_role")] <- c(lt_temp, "other_members")
df[df$hh_id == lt_temp,]$hh_size <- df[df$hh_id == lt_temp,]$hh_size + 1
}
}
foo[[idx]] <- data
print(paste(i,"done",sep = "----------------"))
}
# # # save result
# data <- export_imp_dfs(foo)
# write.csv(data,"data/01_synthetic_population_dataset/process_saved_dataset/XX_step9_populate_ind_type6_7_11_12_other_relatives_non_family.csv")
dfs_ind <- foo
dfs_hh <- tt # household
Update household size
# Table
foo <- dfs_ind # individual
tt <- dfs_hh # household
# 1 -- For LOOP
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# ------------- update household size + add geoid
a <- table(data$hh_id) %>% as.data.frame()
df <- left_join(df, a, by=c("hh_id"="Var1"))
df$hh_size <- df$Freq
df$GEOID <- idx
df <- df[c("GEOID","hh_id","type","hh_size")]
df[is.na(df)] <- 0
df <- df[df$hh_size > 0,]
# ------------- individual df + add geoid
data$GEOID <- idx
foo[[idx]] <- data
tt[[idx]] <- df
print(paste(i,"done",sep = "----------------"))
}
finl_dfs_ind <- foo
finl_dfs_hh <- tt
Validation
V - Household
df_chisq <- data.frame(matrix(ncol = 2)) %>% setnames(new = c("GEOID","chisq_hh"))
foo <- finl_dfs_ind
tt <- finl_dfs_hh
# 1 -- For LOOP
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
# Individual Data
data <- foo[[idx]]
# Household Data
df <- tt[[idx]]
# -------------
# census data
a <- css_hh_type_fnl %>% filter(GEOID == idx) %>% select(c(22:33)) %>%
gather(key="type", value="count")
b <- table(df$type) %>% as.data.frame() %>% setnames(old="Freq", new="simu_count")
a <- left_join(a, b, by=c("type"="Var1"))
a[is.na(a)] <- 0
c <- sum((a$simu_count - a$count)**2 / a$simu_count, na.rm = T)
df_chisq[1+nrow(df_chisq),c("GEOID","chisq_hh")] <- c(idx, c)
print(paste(i,"done",sep = "----------------"))
}
data <- df_chisq[(df_chisq$chisq_hh!="Inf" & !is.na(df_chisq$chisq_hh)),]
data$chisq_hh <- as.numeric(data$chisq_hh)
ggplot(data, aes(x=chisq_hh)) + geom_density()
df <- data.frame(matrix(ncol = 10)) %>% setnames(new = c("GEOID","s_h10_fns_udr18","s_h5_mns_udr18",
"s_h9_fns_alone_over64","s_h4_mns_alone_over64","s_h2_mc_NO18",
"s_h3_mns_alone_less65","s_h8_fns_alone_less65",
"s_h6_mns_NO18_others","s_h11_fns_NO18_others"))
data <- foo
for (i in 1:length(lt_geoid_bg)) {
idx <- lt_geoid_bg[[i]]
df[i,] <- c(
idx,
data[[idx]] %>% filter(hh_role=="single_mom") %>% nrow(),
data[[idx]] %>% filter(hh_role=="single_dad") %>% nrow(),
data[[idx]] %>% filter(hh_role=="female_oldersingleton") %>% nrow(),
data[[idx]] %>% filter(hh_role=="male_oldersingleton") %>% nrow(),
data[[idx]] %>% filter(hh_role=="husband_NO_udr18") %>% nrow(),
data[[idx]] %>% filter(hh_role=="mns_alone_less65") %>% nrow(),
data[[idx]] %>% filter(hh_role=="fns_alone_less65") %>% nrow(),
data[[idx]] %>% filter(hh_role=="mns_no18_other_relative") %>% nrow(),
data[[idx]] %>% filter(hh_role=="fns_no18_other_relative") %>% nrow()
)
}
df[,2:ncol(df)] <- sapply(df[,2:ncol(df)], as.numeric) %>% as.data.frame()
df <- left_join(df, css_hh_type_fnl[,c(1,22:33)], by=c("GEOID"="GEOID"))
# CHEKC
df$s_h10_fns_udr18 - df$h10_fns_udr18
df$s_h5_mns_udr18 - df$h5_mns_udr18
df$s_h9_fns_alone_over64 - df$h9_fns_alone_over64
df$s_h4_mns_alone_over64 - df$h4_mns_alone_over64
df$s_h2_mc_NO18 - df$h2_mc_NO18
df$s_h3_mns_alone_less65 - df$h3_mns_alone_less65
df$s_h8_fns_alone_less65 - df$h8_fns_alone_less65
df$s_h6_mns_NO18_others - df$h6_mns_NO18_others
df$s_h11_fns_NO18_others - df$h11_fns_NO18_others
LS0tDQp0aXRsZTogIlIgKDEvMykgQUJNIElucHV0IERhdGEgLSBTeW50aGV0aWMgcG9wdWxhdGlvbiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIExJQlJBUlkNCmBgYHtyfQ0KIyBCYXNpYyBQYWNrYWdlcw0KbGlicmFyeShzcCkgIyBDbGFzc2VzIGFuZCBNZXRob2RzIGZvciBTcGF0aWFsIERhdGEuDQpsaWJyYXJ5KHJnZGFsKSAgIyBmb3IgdmVjdG9yIHdvcms7IHNwIHBhY2thZ2Ugc2hvdWxkIGFsd2F5cyBsb2FkIHdpdGggcmdkYWwuIF0NCmxpYnJhcnkoc2YpICMgU2ltcGxlIEZlYXR1cmVzIGZvciBSLCBzdF9hc19zZg0KbGlicmFyeSAocmFzdGVyKSAgICMgZm9yIG1ldGFkYXRhL2F0dHJpYnV0ZXMtIHZlY3RvcnMgb3IgcmFzdGVycw0KbGlicmFyeShkcGx5cikgICAgIyBtdXRhdGUsIGxlZnRfam9pbg0KbGlicmFyeSh0aWR5dmVyc2UpICMgdGlkeSBkYXRhIA0KbGlicmFyeShkYXRhLnRhYmxlKSAjIHNldG5hbWVzDQpsaWJyYXJ5KHBseXIpDQpsaWJyYXJ5KGlncmFwaCkgIyBuZXR3b3JrIGFuYWx5c2lzDQpsaWJyYXJ5KHRtYXApDQpsaWJyYXJ5KHNwYXRzdGF0KSAjIGFuYWx5c2lzIG9mIHNwYXRpYWwgcG9pbnQgcGF0dGVybnMsICDigJhwcHDigJkgKHBvaW50IHBhdHRlcm4pIG9iamVjdA0KbGlicmFyeShtYXB0b29scykgIyBjb2VyY2UgU3BhdGlhbFBvbHlnb25zIGludG8gYW4g4oCYb3dpbjogb2JzZXJ2IHdpbmRvd+KAmSBvYmplY3QNCmxpYnJhcnkoc3BkZXApICMgbG9jYWwgbW9yYW4ncyBJLCBuYjJsaXN0dywgDQpsaWJyYXJ5KHJnZW9zKQ0KbGlicmFyeShtYWdyaXR0cikgICMgJT4lDQpsaWJyYXJ5KHJlc2hhcGUyKSAgIyBkY2FzdCwgY2FzdCBjYXRlZ29yeSB2YXJpYWJsZXMgdG8gMS8wDQojIFNUQVRJU1RJQw0KbGlicmFyeShsaW1Tb2x2ZSkgIyBodHRwczovL3NlYXJjaC5yLXByb2plY3Qub3JnL0NSQU4vcmVmbWFucy9saW1Tb2x2ZS9odG1sL2xzZWkuaHRtbCANCmxpYnJhcnkoR0dhbGx5KSAgICAgICAjY29ycmVsYXRpb24gZGlhZ3JhbSAgDQojIFBMVA0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShjb3JycGxvdCkNCmxpYnJhcnkoaHRtbHdpZGdldHMpDQpsaWJyYXJ5KHNoaW55anMpDQpsaWJyYXJ5KGNvbnRvdXJlUikNCmxpYnJhcnkoZ2VvbWV0cnkpDQpsaWJyYXJ5KHRtYXB0b29scykNCmxpYnJhcnkoUkNvbG9yQnJld2VyKSAjIGZvciBjb2xvciBzZWxlY3Rpb24NCmxpYnJhcnkoaHJicnRoZW1lcykgIyB0aGVtZQ0KbGlicmFyeShnZ2JyZWFrKSAgICAgIyBicmVhayB4L3kgYXhpcyAgICAgDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkodmlyaWRpcykNCg0KIyBORVRXT1JLIA0KbGlicmFyeShpZ3JhcGgpDQpgYGANCg0KIyBEYXRhIENvbGxlY3Rpb24gDQpTdHVkeSBhcmVhOiBDaGF1dGF1cXVhIENvdW50eSANCkRhdGE6IDIwMjEgDQogICAgVGF4IFBhcmNlbCBkYXRhOyANCiAgICByb2FkIG5ldHdvcms7IHNjaG9vbHM7IA0KICAgIDIwMjEgY2Vuc3VzIGRhdGENCiAgICAgICAgICBCMDEwMDEgU0VYIEJZIEFHRSAoMjAyMCA1eXIpDQogICAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1wb3B1bGF0aW9uJmc9MDUwMDAwMFVTMzYwMTMlMjQxNTAwMDAwJnRpZD1BQ1NEVDVZMjAyMC5CMDEwMDEgDQogICAgICAgICAgQjE0MDAyICBTZXggYnkgc2Nob29sIGVucm9sbG1lbnQgYnkgbGV2ZWwgb2Ygc2Nob29sIGJ5IHR5cGUgb2Ygc2Nob29sIGZvciB0aGUgcG9wdWxhdGlvbiAzIHllYXJzIGFuZCBvdmVyDQogICAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1lZHVjYXRpb24mZz0wNTAwMDAwVVMzNjAxMyUyNDE1MDAwMDAmdGlkPUFDU0RUNVkyMDIwLkIxNDAwMg0KICAgICAgICAgIEIwODAwNyAgU2V4IG9mIHdvcmtlcnMgYnkgcGxhY2Ugb2Ygd29yay0tc3RhdGUgYW5kIGNvdW50eSBsZXZlbA0KICAgICAgICAgICAgaHR0cHM6Ly9kYXRhLmNlbnN1cy5nb3YvY2Vkc2NpL3RhYmxlP3E9ZW1wbG95bWVudCwlMjBhZ2UmZz0wNTAwMDAwVVMzNjAxMyUyNDE1MDAwMDAmdGlkPUFDU0RUNVkyMDIwLkIwODAwNw0KICAgICAgICAgIEIwMTAwMiBNRURJQU4gQUdFIEJZIFNFWCAoMjAyMCA1eXIpDQogICAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1wb3B1bGF0aW9uJmc9MDUwMDAwMFVTMzYwMTMlMjQxNTAwMDAwJnRpZD1BQ1NEVDVZMjAyMC5CMDEwMDINCiAgICAgICAgICBCMDkwMTkgSE9VU0VIT0xEIFRZUEUgKElOQ0xVRElORyBMSVZJTkcgQUxPTkUpIEJZIFJFTEFUSU9OU0hJUCAoMjAyMCA1eXIpDQogICAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi90YWJsZT9xPUIwOTAxOSZnPTA1MDAwMDBVUzM2MDEzJDE1MDAwMDANCiAgICAgICAgICBCMDkwMjEgIExJVklORyBBUlJBTkdFTUVOVFMgT0YgQURVTFRTIDE4IFlFQVJTIEFORCBPVkVSIEJZIEFHRQ0KICAgICAgICAgICAgaHR0cHM6Ly9kYXRhLmNlbnN1cy5nb3YvY2Vkc2NpL3RhYmxlP3E9QjA5MDIxJmc9MDUwMDAwMFVTMzYwMTMlMjQxNTAwMDAwJnRpZD1BQ1NEVDVZMjAyMC5CMDkwMjENCiAgICAgICAgICBCMTEwMDUgSE9VU0VIT0xEUyBCWSBQUkVTRU5DRSBPRiBQRU9QTEUgVU5ERVIgMTggWUVBUlMgQlkgSE9VU0VIT0xEIFRZUEUgKDIwMjAgNXlyKQ0KICAgICAgICAgICAgaHR0cHM6Ly9kYXRhLmNlbnN1cy5nb3YvY2Vkc2NpL3RhYmxlP3E9Y2hpbGRyZW4mZz0wNTAwMDAwVVMzNjAxMyUyNDE1MDAwMDAmdGlkPUFDU0RUNVkyMDIwLkIxMTAwNQ0KICAgICAgICAgIEIwOTAyMSAgTElWSU5HIEFSUkFOR0VNRU5UUyBPRiBBRFVMVFMgMTggWUVBUlMgQU5EIE9WRVIgQlkgQUdFDQogICAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1CMDkwMjEmZz0wNTAwMDAwVVMzNjAxMyUyNDE1MDAwMDAgDQogICAgICAgICAgQjExMDA0IEZBTUlMWSBUWVBFIEJZIFBSRVNFTkNFIEFORCBBR0UgT0YgUkVMQVRFRCBDSElMRFJFTiBVTkRFUiAxOCBZRUFSUyAoMjAyMCA1eXIpDQogICAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1jaGlsZHJlbiZnPTA1MDAwMDBVUzM2MDEzJTI0MTUwMDAwMCZ0aWQ9QUNTRFQ1WTIwMjAuQjExMDA0DQogICAgICAgICAgQjA5MDIwICBSRUxBVElPTlNISVAgQlkgSE9VU0VIT0xEIFRZUEUgKElOQ0xVRElORyBMSVZJTkcgQUxPTkUpIEZPUiBUSEUgUE9QVUxBVElPTiA2NSBZRUFSUyBBTkQgT1ZFUg0KICAgICAgICAgIGh0dHBzOi8vZGF0YS5jZW5zdXMuZ292L2NlZHNjaS90YWJsZT9xPUhvdXNlaG9sZCUyMHR5cGUlMjBjaGlsZCZnPTA1MDAwMDBVUzM2MDEzJTI0MTUwMDAwMCZ0aWQ9QUNTRFQ1WTIwMjAuQjA5MDIwDQogICAgICAgICAgQjExMDAxICBIT1VTRUhPTEQgVFlQRSAoSU5DTFVESU5HIExJVklORyBBTE9ORSkNCiAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1Ib3VzZWhvbGQlMjB0eXBlJmc9MDUwMDAwMFVTMzYwMTMlMjQxNTAwMDAwJnRpZD1BQ1NEVDVZMjAyMC5CMTEwMDENCiAgICAgICAgICBCMTEwMTIgIEhPVVNFSE9MRFMgQlkgVFlQRQ0KICAgICAgICAgIGh0dHBzOi8vZGF0YS5jZW5zdXMuZ292L2NlZHNjaS90YWJsZT9xPUhvdXNlaG9sZCUyMHR5cGUmZz0wNTAwMDAwVVMzNjAxMyUyNDE1MDAwMDAmdGlkPUFDU0RUNVkyMDIwLkIxMTAxMg0KICAgICAgICAgIA0KICAgICAgICAgIFA1ICBHcm91cCBRdWFydGVycyBQb3B1bGF0aW9uIEJ5IE1ham9yIEdyb3VwIFF1YXJ0ZXJzIFR5cGUgKDIwMjAgRGVjZW5uaWFsKQ0KICAgICAgICAgIGh0dHBzOi8vZGF0YS5jZW5zdXMuZ292L2NlZHNjaS90YWJsZT9xPUdyb3VwJTIwUXVhcnRlcnMlMjBQb3B1bGF0aW9uJmc9MDUwMDAwMFVTMzYwMTMlMjQxNTAwMDAwDQogICAgICAgICAgDQogICAgICAgICAgMjAyMCBVcmJhbiBBcmVhIENsdXN0ZXJzIA0KICAgICAgICAgIGh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvY2dpLWJpbi9nZW8vc2hhcGVmaWxlcy9pbmRleC5waHA/eWVhcj0yMDIwJmxheWVyZ3JvdXA9VXJiYW4rQXJlYXMNCiAgICAgICAgICANCiAgICAgICAgICANCiAgICAgICAgICAjIFVOVVNFRCANCiAgICAgICAgICBCMTEwMTIgIEhPVVNFSE9MRFMgQlkgVFlQRQ0KICAgICAgICAgIGh0dHBzOi8vZGF0YS5jZW5zdXMuZ292L2NlZHNjaS90YWJsZT9xPUhvdXNlaG9sZCUyMHR5cGUmZz0wNTAwMDAwVVMzNjAxMyUyNDE1MDAwMDAmdGlkPUFDU0RUNVkyMDIwLkIxMTAxMg0KICAgICAgICAgIEIxMTAxNiAgSE9VU0VIT0xEIFRZUEUgQlkgSE9VU0VIT0xEIFNJWkUNCiAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1Ib3VzZWhvbGQlMjB0eXBlJmc9MDUwMDAwMFVTMzYwMTMlMjQxNTAwMDAwJnRpZD1BQ1NEVDVZMjAyMC5CMTEwMTYNCiAgICAgICAgICANCiAgICAgICAgICBQNSAgR3JvdXAgUXVhcnRlcnMgUG9wdWxhdGlvbiBCeSBNYWpvciBHcm91cCBRdWFydGVycyBUeXBlICgyMDIwIERlY2VubmlhbCkNCiAgICAgICAgICBodHRwczovL2RhdGEuY2Vuc3VzLmdvdi9jZWRzY2kvdGFibGU/cT1Hcm91cCUyMFF1YXJ0ZXJzJTIwUG9wdWxhdGlvbiZnPTA1MDAwMDBVUzM2MDEzJTI0MTUwMDAwMA0KDQogICAgICAgICAgDQogICAgVS5TLiBDZW5zdXMgQnVyZWF14oCZcyBMb25naXR1ZGluYWwgRW1wbG95ZXItSG91c2Vob2xkIER5bmFtaWNzIChMRUhEKSBPcmlnaW4tRGVzdGluYXRpb24gRW1wbG95bWVudCBTdGF0aXN0aWNzIChMT0RFUykNCiAgICAwLTE4IFNjaG9vbCBsb2NhdGlvbnMNCiAgICAxOC0yMiBVbml2ZXJzaXR5DQoNCkNoYXV0YXVxdWE6IA0KICAgIENPVU5UWUZQOiAiMDEzIg0KICAgIENPVU5UWU5TOiAiMDA5NzQxMDUiDQogICAgR0VPSUQ6ICIzNjAxMyINCg0KIyMgU3BhdGlhbCBEYXRhDQpQcm9qZWN0ZWQgQ1JTOiBOQUQ4MyAvIFVUTSB6b25lIDE4Tg0KYGBge3J9DQojIENvdW50eQ0KdHQgPC0gc3RfcmVhZCgiZGF0YS90bF8yMDIxX3VzX2NvdW50eS90bF8yMDIxX3VzX2NvdW50eS5zaHAiKQ0KY19jb3VudHkgPC0gdHRbdHQkQ09VTlRZTlM9PSIwMDk3NDEwNSIsXQ0KDQojIFRyYWN0DQp0dCA8LSBzdF9yZWFkKCJkYXRhL3RsXzIwMjFfMzZfdHJhY3QvdGxfMjAyMV8zNl90cmFjdC5zaHAiKQ0KY190cmFjdCA8LSB0dFt0dCRDT1VOVFlGUD09IjAxMyIsXQ0KDQojIEJsb2NrIEdyb3VwcyANCnR0IDwtIHN0X3JlYWQoImRhdGEvdGxfMjAyMV8zNl9iZy90bF8yMDIxXzM2X2JnLnNocCIpDQpjX2Jncm91cCA8LSB0dFt0dCRDT1VOVFlGUD09IjAxMyIsXQ0KDQojIFBhcmNlbCAmIFJlc2lkZW50aWFsIFBhcmNlbCANCmNfcGFyY2VsIDwtIHN0X3JlYWQoImRhdGEvQ2hhdXRhdXF1YV8yMDIxX1RheF9QYXJjZWxzX1NIUF8yMjAzL0NoYXV0YXVxdWFfMjAyMV9UYXhfUGFyY2Vsc19TSFBfMjIwMy5zaHAiKQ0KY19wYXJjZWxfciA8LSBjX3BhcmNlbFsoY19wYXJjZWwkUFJPUF9DTEFTUyA+ICIxOTkiICYgY19wYXJjZWwkUFJPUF9DTEFTUyA8ICIzMDAiKSxdIA0KY19wYXJjZWxfciA8LSBjX3BhcmNlbF9yWyFpcy5uYShjX3BhcmNlbF9yJENPVU5UWSksXQ0KDQojIEdyb3VwIFF1YXJ0ZXIgUGFyY2VsOiBOQUQ4MyAvIFVUTSB6b25lIDE4Tg0KY19wYXJjZWxfZ3EgPC0gY19wYXJjZWxbY19wYXJjZWwkUFJPUF9DTEFTUyAlaW4lIGMoIjYxMyIsIjYxNSIsIjYzMyIsIjY0MSIsIjY0MiIsIjY2MCIsIjY3MCIpLF0gDQoNCiMgVXJiYW4gQXJlYXMgMjAyMA0KY191cmJhbiA8LSBzdF9yZWFkKHBhc3RlKGRpcm5hbWUoZGlybmFtZShnZXR3ZCgpKSksICIvenpfTllTX0dJU19EYXRhL3RsXzIwMjBfdXNfdWFjMTAvdGxfMjAyMF91c191YWMxMC5zaHAiLCBzZXA9IiIpKSAlPiUgZmlsdGVyKE5BTUUxMCAlbGlrZSUgIiwgTlkiKQ0KDQojIFByb2plY3Qgc3BhdGlhbCBkYXRhIChlLmcuLCBjb3VudHksIHRyYWN0LCBibG9jayBncm91cHMpIHRvICJOQUQ4MyAvIFVUTSB6b25lIDE4TiINCmNfY291bnR5IDwtIHN0X3RyYW5zZm9ybShjX2NvdW50eSwgc3RfY3JzKGNfcGFyY2VsX3IpKQ0KY190cmFjdCA8LSBzdF90cmFuc2Zvcm0oY190cmFjdCwgc3RfY3JzKGNfcGFyY2VsX3IpKQ0KY19iZ3JvdXAgPC0gc3RfdHJhbnNmb3JtKGNfYmdyb3VwLCBzdF9jcnMoY19wYXJjZWxfcikpDQpjX3VyYmFuIDwtIHN0X3RyYW5zZm9ybShjX3VyYmFuLCBzdF9jcnMoY19wYXJjZWxfcikpDQoNCiMgVXJiYW4gQXJlYXMgb25seSBpbiBDaGF1dGF1cXVhIENvdW50eQ0KY191cmJhbiA8LSBjX3VyYmFuW2xlbmd0aHMoc3RfaW50ZXJzZWN0cyhjX3VyYmFuLGNfY291bnR5KSk+MCxdDQpgYGANCg0KIyMgQ2Vuc3VzIChjc3MpIERhdGEgIA0KIyMjIEluZGl2aWR1YWwgTGV2ZWwgDQpgYGB7cn0NCiMgQjAxMDAxIFNFWCBCWSBBR0UgKDIwMjAgNXlyKQ0KdHR0IDwtIHJlYWQuY3N2KCJkYXRhL0FDU0RUNVkyMDIwX2NoYXVfYmxvY2tfZ3JvdXBfY2xlYW5lZC9DaGF1dGFucXVhX2JnX0FDU0RUNVkyMDIwLkIwMTAwMS0yMDIyLTA1LTE5VDE0NTgzOS5jc3YiLCBjb2xDbGFzc2VzID0gImNoYXJhY3RlciIpDQp0dHQgPC0gY2xuX2NlbnN1c19nZW9pZCh0dHQsIGlkeF9jYmdyb3VwKQ0KdHR0Wyw1Omxlbmd0aCh0dHQpXSA8LSBjbG5fY2Vuc3VzX251bWVyaWModHR0Wyw1Omxlbmd0aCh0dHQpXSkNCmNzc19hZ2VfZ2VuZGVyIDwtIHR0dA0KDQojIEIwODAwNyAgU2V4IG9mIHdvcmtlcnMgYnkgcGxhY2Ugb2Ygd29yay0tc3RhdGUgYW5kIGNvdW50eSBsZXZlbA0KdHR0IDwtIHJlYWQuY3N2KCJkYXRhL0FDU0RUNVkyMDIwX2NoYXVfYmxvY2tfZ3JvdXBfY2xlYW5lZC9DaGF1dGFucXVhX2JnX0FDU0RUNVkyMDIwLkIwODAwNy0yMDIyLTA1LTIzVDAzNDcyMi5jc3YiLCBjb2xDbGFzc2VzID0gImNoYXJhY3RlciIpDQp0dHQgPC0gY2xuX2NlbnN1c19nZW9pZCh0dHQsIGlkeF9jYmdyb3VwKQ0KdHR0Wyw1Omxlbmd0aCh0dHQpXSA8LSBjbG5fY2Vuc3VzX251bWVyaWModHR0Wyw1Omxlbmd0aCh0dHQpXSkNCmNzc193b3JrX3BsYWNlIDwtIHR0dFtjKCJHRU9JRCIsIk5BTUVMU0FEIiwiVFJBQ1RfTkFNRUxTQUQiLCJtX3R0bCIsIm1fV29ya2VkX2luX2NvdW50eV9vZl9yZXNpZGVuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIm1fV29ya2VkX291dHNpZGVfY291bnR5X29mX3Jlc2lkZW5jZSIsIm1fV29ya2VkX291dHNpZGVfc3RhdGVfb2ZfcmVzaWRlbmNlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJmX3R0bCIsImZfV29ya2VkX2luX2NvdW50eV9vZl9yZXNpZGVuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgImZfV29ya2VkX291dHNpZGVfY291bnR5X29mX3Jlc2lkZW5jZSIsImZfV29ya2VkX291dHNpZGVfc3RhdGVfb2ZfcmVzaWRlbmNlIildDQoNCiMgQjA5MDIxICBMaXZpbmcgYXJyYW5nZW1lbnRzIG9mIGFkdWx0cyAxOCB5ZWFycyBhbmQgb3ZlciBieSBhZ2UNCnR0dCA8LSByZWFkLmNzdigiZGF0YS9BQ1NEVDVZMjAyMF9jaGF1X2Jsb2NrX2dyb3VwX2NsZWFuZWQvQ2hhdXRhbnF1YV9iZ19BQ1NEVDVZMjAyMC5CMDkwMjEtMjAyMi0wNS0yNFQwMTU5MzEuY3N2IiwgY29sQ2xhc3NlcyA9ICJjaGFyYWN0ZXIiKQ0KdHR0IDwtIGNsbl9jZW5zdXNfZ2VvaWQodHR0LCBpZHhfY2Jncm91cCkNCnR0dFssNTpsZW5ndGgodHR0KV0gPC0gY2xuX2NlbnN1c19udW1lcmljKHR0dFssNTpsZW5ndGgodHR0KV0pDQpjc3Nfb3ZlcjE4X2luX2hoIDwtIHR0dA0KY3NzX292ZXIxOF9pbl9oaCRoaGRlcl9zcG91c2VfcGFydG5lcl90dGxfb3ZlcjE3IDwtIGNzc19vdmVyMThfaW5faGgkbWFycmllZF9oaGRlcl9zcG91c2VfdHRsX292ZXIxNyArICBjc3Nfb3ZlcjE4X2luX2hoJHVubWFycmllZF9oaGRlcl9wYXJ0bmVyX3R0bF9vdmVyMTcNCmNzc19vdmVyMThfaW5faGgkaGhkZXJfc3BvdXNlX3BhcnRuZXJfMThfMzQgPC0gY3NzX292ZXIxOF9pbl9oaCRtYXJyaWVkX2hoZGVyX3Nwb3VzZV8xOF8zNCArIGNzc19vdmVyMThfaW5faGgkdW5tYXJyaWVkX2hoZGVyX3BhcnRuZXJfMThfMzQNCmNzc19vdmVyMThfaW5faGgkaGhkZXJfc3BvdXNlX3BhcnRuZXJfMzVfNjQgPC0gY3NzX292ZXIxOF9pbl9oaCRtYXJyaWVkX2hoZGVyX3Nwb3VzZV8zNV82NCArIGNzc19vdmVyMThfaW5faGgkdW5tYXJyaWVkX2hoZGVyX3BhcnRuZXJfMzVfNjQNCmNzc19vdmVyMThfaW5faGgkaGhkZXJfc3BvdXNlX3BhcnRuZXJfb3ZlcjY0IDwtIGNzc19vdmVyMThfaW5faGgkbWFycmllZF9oaGRlcl9zcG91c2Vfb3ZlcjY0ICsgY3NzX292ZXIxOF9pbl9oaCR1bm1hcnJpZWRfaGhkZXJfcGFydG5lcl9vdmVyNjQNCmNzc19vdmVyMThfaW5faGggPC0gY3NzX292ZXIxOF9pbl9oaFssIWNvbG5hbWVzKGNzc19vdmVyMThfaW5faGgpICVpbiUgYygibWFycmllZF9oaGRlcl9zcG91c2VfdHRsX292ZXIxNyIsInVubWFycmllZF9oaGRlcl9wYXJ0bmVyX3R0bF9vdmVyMTciLCJtYXJyaWVkX2hoZGVyX3Nwb3VzZV8xOF8zNCIsInVubWFycmllZF9oaGRlcl9wYXJ0bmVyXzE4XzM0IiwibWFycmllZF9oaGRlcl9zcG91c2VfMzVfNjQiLCAidW5tYXJyaWVkX2hoZGVyX3BhcnRuZXJfMzVfNjQiLCJtYXJyaWVkX2hoZGVyX3Nwb3VzZV9vdmVyNjQiLCJ1bm1hcnJpZWRfaGhkZXJfcGFydG5lcl9vdmVyNjQiKV0NCg0KIyBQNSAgR3JvdXAgUXVhcnRlcnMgUG9wdWxhdGlvbiBCeSBNYWpvciBHcm91cCBRdWFydGVycyBUeXBlICgyMDIwIERlY2VubmlhbCkNCmx0IDwtIGMoIkluc3RpdHV0aW9uYWxpemVkLnBvcHVsYXRpb24iLCJPdGhlci5pbnN0aXR1dGlvbmFsLmZhY2lsaXRpZXMiLA0KICAgICAgICAiTm9uaW5zdGl0dXRpb25hbGl6ZWQucG9wdWxhdGlvbiIsIk1pbGl0YXJ5LnF1YXJ0ZXJzIiwNCiAgICAgICAgImluX2dyb3VwcXVhcnRlciIsInRlbXAiKQ0KdHR0IDwtIHJlYWQuY3N2KCJkYXRhL0FDU0RUNVkyMDIwX2NoYXVfYmxvY2tfZ3JvdXBfY2xlYW5lZC9DaGF1dGFucXVhX2JnX0RFQ0VOTklBTFBMMjAyMC5QNS0yMDIyLTA2LTA2VDAxMTIwMC5jc3YiLCBjb2xDbGFzc2VzID0gImNoYXJhY3RlciIpDQp0dHQgPC0gY2xuX2NlbnN1c19nZW9pZCh0dHQsIGlkeF9jYmdyb3VwKQ0KdHR0Wyw1Omxlbmd0aCh0dHQpXSA8LSBjbG5fY2Vuc3VzX251bWVyaWModHR0Wyw1Omxlbmd0aCh0dHQpXSkNCnR0dCA8LSB0dHRbLCAhbmFtZXModHR0KSVpbiUgbHRdDQp0dHRbLDY6bGVuZ3RoKHR0dCldIDwtIHJvdW5kKHR0dFssNjpsZW5ndGgodHR0KV0vdHR0JFRvdGFsLDQpDQp0dHRbdHR0ID09ICJOYU4iXSA8LSAwDQp0dHQkdGVtcCA8LSBhcHBseSh0dHRbLDY6bGVuZ3RoKHR0dCldLCAxLCBzdW0pDQp0dHRbdHR0JHRlbXAgPT0wLF0kT3RoZXIubm9uaW5zdGl0dXRpb25hbC5mYWNpbGl0aWVzIDwtIDENCg0KdHR0IDwtIGxlZnRfam9pbih0dHQsIGNzc19oaF90eXBlW2MoIkdFT0lEIiwiaW5fZ3JvdXBxdWFydGVyIildKQ0KdHR0JFRvdGFsIDwtIHR0dCRpbl9ncm91cHF1YXJ0ZXINCnR0dFssNjpsZW5ndGgodHR0KV0gPC0gcm91bmQodHR0Wyw2Omxlbmd0aCh0dHQpXSAqIHR0dCRUb3RhbCwwKQ0KdHR0IDwtIHR0dFssICFuYW1lcyh0dHQpJWluJSBsdF0NCmNzc19ncm91cF9xdWFydGVyX3BvcCA8LSB0dHQNCg0KIyBCMDkwMjAgIFJFTEFUSU9OU0hJUCBCWSBIT1VTRUhPTEQgVFlQRSAoSU5DTFVESU5HIExJVklORyBBTE9ORSkgRk9SIFRIRSBQT1BVTEFUSU9OIDY1IFlFQVJTIEFORCBPVkVSDQp0dHQgPC0gcmVhZC5jc3YoImRhdGEvQUNTRFQ1WTIwMjBfY2hhdV9ibG9ja19ncm91cF9jbGVhbmVkL0NoYXV0YW5xdWFfYmdfQUNTRFQ1WTIwMjAuQjA5MDIwLTIwMjItMDYtMTNUMTQzNzI5LmNzdiIsIA0KICAgICAgICAgICAgICAgIGNvbENsYXNzZXMgPSAiY2hhcmFjdGVyIikNCnR0dCA8LSBjbG5fY2Vuc3VzX2dlb2lkKHR0dCwgaWR4X2NiZ3JvdXApDQp0dHRbLDU6bGVuZ3RoKHR0dCldIDwtIGNsbl9jZW5zdXNfbnVtZXJpYyh0dHRbLDU6bGVuZ3RoKHR0dCldKQ0KIyBjb21iaW5lIHBhcmVudCAmIHBhcmVudC1pbi1sYXcNCnR0dCRvdmVyNjRfcGFyZW50X29yX2lubGF3IDwtIHR0dCRvdmVyNjRfcGFyZW50ICsgdHR0JG92ZXI2NF9wYXJlbnQuaW4ubGF3DQojIGNvbWJpbmUgKGZhbWlseS9ub24tZmFtaWx5KSBub24tcmVsYXRpdmVzIHdpdGggcmVsYXRpdmVzDQp0dHQkb3ZlcjY0X3JlbGF0aXZlc19ub25yZWxhdGl2ZXMgPC0gdHR0JG92ZXI2NF9vdGhlcl9yZWxhdGl2ZXMgKyB0dHQkb3ZlcjY0X25vbnJlbGF0aXZlcyArIHR0dCRvdmVyNjRfbm9uZmFtaWx5X25vbnJlbGF0aXZlcw0KIyBjb21iaW5lIGZhbWlseSBob3VzZWhvbGRlciB3aXRoIG5vbi1mYW1pbHkgbm90LWFsb25lIGhvdXNlaG9sZGVyIA0KdHR0JG92ZXI2NF9tX2hoZGVyX25vdF9hbG9uZSA8LSB0dHQkb3ZlcjY0X21faGhkZXIgKyB0dHQkb3ZlcjY0X25vbmZhbWlseV9tX2hoZGVyX25vdF9hbG9uZQ0KdHR0JG92ZXI2NF9mX2hoZGVyX25vdF9hbG9uZSA8LSB0dHQkb3ZlcjY0X2ZfaGhkZXIgKyB0dHQkb3ZlcjY0X25vbmZhbWlseV9mX2hoZGVyX25vdF9hbG9uZQ0KDQpsdCA8LSBjKCJvdmVyNjRfaW5faGgiLCJvdmVyNjRfaW5faGhfZmFtaWx5Iiwib3ZlcjY0X2luX2hoX25vbmZhbWlseSIsDQogICJvdmVyNjRfcGFyZW50Iiwib3ZlcjY0X3BhcmVudC5pbi5sYXciLA0KICAib3ZlcjY0X290aGVyX3JlbGF0aXZlcyIsIm92ZXI2NF9ub25yZWxhdGl2ZXMiLCJvdmVyNjRfbm9uZmFtaWx5X25vbnJlbGF0aXZlcyIsDQogICJvdmVyNjRfbV9oaGRlciIsIm92ZXI2NF9ub25mYW1pbHlfbV9oaGRlcl9ub3RfYWxvbmUiLA0KICAib3ZlcjY0X2ZfaGhkZXIiLCJvdmVyNjRfbm9uZmFtaWx5X2ZfaGhkZXJfbm90X2Fsb25lIikNCnR0dCA8LSB0dHRbLCFjb2xuYW1lcyh0dHQpICVpbiUgbHRdDQpjc3Nfb3ZlcjY0X2luX2hoIDwtIHR0dA0KDQojIC0tLS0tLS0tLS0tLSBCYWNrdXAgLS0tLS0tLS0tLS0NCiMgIyBCMTQwMDIgIFNleCBieSBzY2hvb2wgZW5yb2xsbWVudCBieSBsZXZlbCBvZiBzY2hvb2wgYnkgdHlwZSBvZiBzY2hvb2wgZm9yIHRoZSBwb3B1bGF0aW9uIDMgeWVhcnMgYW5kIG92ZXINCiMgdHR0IDwtIHJlYWQuY3N2KCJkYXRhL0FDU0RUNVkyMDIwX2NoYXVfYmxvY2tfZ3JvdXBfY2xlYW5lZC9DaGF1dGFucXVhX2JnX0FDU0RUNVkyMDIwLkIxNDAwMi0yMDIyLTA1LTIzVDAzMzU1NS5jc3YiLCBjb2xDbGFzc2VzID0gImNoYXJhY3RlciIpDQojIHR0dCA8LSBjbG5fY2Vuc3VzX2dlb2lkKHR0dCwgaWR4X2NiZ3JvdXApDQojIHR0dFssNTpsZW5ndGgodHR0KV0gPC0gY2xuX2NlbnN1c19udW1lcmljKHR0dFssNTpsZW5ndGgodHR0KV0pDQojIGNzc19zY2hvb2xfZW5yb2xsIDwtIHR0dA0KYGBgDQoNCg0KDQojIyMgSG91c2Vob2xkIGxldmVsDQpgYGB7cn0NCiMgQjA5MDE5IGhvdXNlaG9sZCB0eXBlIChpbmNsdWRpbmcgbGl2aW5nIGFsb25lKSBieSByZWxhdGlvbnNoaXAgDQp0dHQgPC0gcmVhZC5jc3YoImRhdGEvQUNTRFQ1WTIwMjBfY2hhdV9ibG9ja19ncm91cF9jbGVhbmVkL0NoYXV0YW5xdWFfYmdfQUNTRFQ1WTIwMjAuQjA5MDE5LTIwMjItMDUtMTlUMTU1MzMyLmNzdiIsIGNvbENsYXNzZXMgPSAiY2hhcmFjdGVyIikNCnR0dCA8LSBjbG5fY2Vuc3VzX2dlb2lkKHR0dCwgaWR4X2NiZ3JvdXApDQp0dHRbLDU6bGVuZ3RoKHR0dCldIDwtIGNsbl9jZW5zdXNfbnVtZXJpYyh0dHRbLDU6bGVuZ3RoKHR0dCldKQ0KY3NzX2hoX3R5cGUgPC0gdHR0DQpjc3NfaGhfdHlwZSRoaG1iZXJfT3Bwb3NpdGVfc2V4IDwtIGNzc19oaF90eXBlJGhobWJlcl9PcHBvc2l0ZV9zZXhfc3BvdXNlICsgY3NzX2hoX3R5cGUkaGhtYmVyX09wcG9zaXRlX3NleF91bm1hcnJpZWRfcGFydG5lcg0KY3NzX2hoX3R5cGUkaGhtYmVyX1NhbWVfc2V4IDwtIGNzc19oaF90eXBlJGhobWJlcl9TYW1lX3NleF9zcG91c2UgKyBjc3NfaGhfdHlwZSRoaG1iZXJfU2FtZV9zZXhfdW5tYXJyaWVkX3BhcnRuZXINCmNzc19oaF90eXBlJGhobWJlcl9DaGlsZCA8LSBjc3NfaGhfdHlwZSRoaG1iZXJfQ2hpbGQgKyBjc3NfaGhfdHlwZSRoaG1iZXJfRm9zdGVyX2NoaWxkDQpjc3NfaGhfdHlwZSRoaG1iZXJfT3RoZXIgPC0gY3NzX2hoX3R5cGUkaGhtYmVyX090aGVyX25vbnJlbGF0aXZlcyArIGNzc19oaF90eXBlJGhobWJlcl9PdGhlcl9yZWxhdGl2ZXMNCmNzc19oaF90eXBlIDwtIGNzc19oaF90eXBlWywgIWNvbG5hbWVzKGNzc19oaF90eXBlKSAlaW4lIGMoImhobWJlcl9PcHBvc2l0ZV9zZXhfc3BvdXNlIiwiaGhtYmVyX09wcG9zaXRlX3NleF91bm1hcnJpZWRfcGFydG5lciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoaG1iZXJfU2FtZV9zZXhfc3BvdXNlIiwgImhobWJlcl9TYW1lX3NleF91bm1hcnJpZWRfcGFydG5lciIsImhobWJlcl9Gb3N0ZXJfY2hpbGQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImhobWJlcl9PdGhlcl9ub25yZWxhdGl2ZXMiLCAiaGhtYmVyX090aGVyX3JlbGF0aXZlcyIpXQ0KDQojIEIxMTAxMiAgSE9VU0VIT0xEUyBCWSBUWVBFIC0gbWFycmllZCArIGNvaGFiaXRpbmcuIFRoaXMgZGYgaGVscHMgdG8gaWRlbnRpZnkgbWFycmllZCAmIGNvaGFiaXRpbmcgaGguIElnbm9yZSB0aGUgdWRyMTggaW5mb3JtYXRpb24uICANCnR0dCA8LSByZWFkLmNzdigiZGF0YS9BQ1NEVDVZMjAyMF9jaGF1X2Jsb2NrX2dyb3VwX2NsZWFuZWQvQ2hhdXRhbnF1YV9iZ19BQ1NEVDVZMjAyMC5CMTEwMTItMjAyMi0wNi0yMFQyMTE3MjYuY3N2IiwgY29sQ2xhc3NlcyA9ICJjaGFyYWN0ZXIiKQ0KdHR0IDwtIGNsbl9jZW5zdXNfZ2VvaWQodHR0LCBpZHhfY2Jncm91cCkNCnR0dFssNTpsZW5ndGgodHR0KV0gPC0gY2xuX2NlbnN1c19udW1lcmljKHR0dFssNTpsZW5ndGgodHR0KV0pDQpjc3NfaGhfdHlwZV8yIDwtIHR0dA0KDQojIEIxMTAwNSBob3VzZWhvbGRzIGJ5IHByZXNlbmNlIG9mIHBlb3BsZSB1bmRlciAxOCB5ZWFycyBieSBob3VzZWhvbGQgdHlwZQ0KdHR0IDwtIHJlYWQuY3N2KCJkYXRhL0FDU0RUNVkyMDIwX2NoYXVfYmxvY2tfZ3JvdXBfY2xlYW5lZC9DaGF1dGFucXVhX2JnX0FDU0RUNVkyMDIwLkIxMTAwNS0yMDIyLTA1LTE5VDE2MjAzNi5jc3YiLCBjb2xDbGFzc2VzID0gImNoYXJhY3RlciIpDQp0dHQgPC0gY2xuX2NlbnN1c19nZW9pZCh0dHQsIGlkeF9jYmdyb3VwKQ0KdHR0Wyw1Omxlbmd0aCh0dHQpXSA8LSBjbG5fY2Vuc3VzX251bWVyaWModHR0Wyw1Omxlbmd0aCh0dHQpXSkNCmNzc19oaF93aXRoX3VkcjE4IDwtIHR0dA0KDQoNCiMgLS0tLS0tLS0tLS0tIEJhY2t1cCAtLS0tLS0tLS0tLQ0KIyAjIEIxMTAwNCBmYW1pbHkgdHlwZSBieSBwcmVzZW5jZSBhbmQgYWdlIG9mIHJlbGF0ZWQgY2hpbGRyZW4gdW5kZXIgMTggeWVhcnMgIA0KIyB0dHQgPC0gcmVhZC5jc3YoImRhdGEvQUNTRFQ1WTIwMjBfY2hhdV9ibG9ja19ncm91cF9jbGVhbmVkL0NoYXV0YW5xdWFfYmdfQUNTRFQ1WTIwMjAuQjExMDA0LTIwMjItMDUtMTlUMTYyODM5LmNzdiIsIGNvbENsYXNzZXMgPSAiY2hhcmFjdGVyIikNCiMgdHR0IDwtIGNsbl9jZW5zdXNfZ2VvaWQodHR0LCBpZHhfY2Jncm91cCkNCiMgdHR0Wyw1Omxlbmd0aCh0dHQpXSA8LSBjbG5fY2Vuc3VzX251bWVyaWModHR0Wyw1Omxlbmd0aCh0dHQpXSkNCiMgY3NzX2hoX3dpdGhfdWRyMThfYnJrZG93biA8LSB0dHQNCg0KIyAjIEIxMTAwMSAgSE9VU0VIT0xEIFRZUEUgKElOQ0xVRElORyBMSVZJTkcgQUxPTkUpDQojIHR0dCA8LSByZWFkLmNzdigiZGF0YS9BQ1NEVDVZMjAyMF9jaGF1X2Jsb2NrX2dyb3VwX2NsZWFuZWQvQ2hhdXRhbnF1YV9iZ19BQ1NEVDVZMjAyMC5CMTEwMDEtMjAyMi0wNi0yMFQxNzIzMzEuY3N2IiwgY29sQ2xhc3NlcyA9ICJjaGFyYWN0ZXIiKQ0KIyB0dHQgPC0gY2xuX2NlbnN1c19nZW9pZCh0dHQsIGlkeF9jYmdyb3VwKQ0KIyB0dHRbLDU6bGVuZ3RoKHR0dCldIDwtIGNsbl9jZW5zdXNfbnVtZXJpYyh0dHRbLDU6bGVuZ3RoKHR0dCldKQ0KIyBjc3NfaGhfdHlwZV8yIDwtIHR0dA0KYGBgDQoNCg0KIyMgUmVvcmdhbml6ZSBob3VzZWhvbGQgdHlwZSANCmBgYHtyfQ0KIyAxOiBtYXJyaWVkIGZhbWlseSBhbmQgY29oYWJpdGluZyBjb3VwbGUgaG91c2Vob2xkIChtYXJyaWVkX2NvaGFiaXRpbmcpIA0KZGF0YSA8LSBjc3NfaGhfdHlwZV8yWyxjKDEsNToyMSldDQojIyBuZXcgY29sdW1ucyANCmRhdGEkaGhfbWFycmllZF9jb2hhYml0aW5nIDwtIGRhdGEkaGhfZmFtaWx5X21hcnJpZWQgKyBkYXRhJGhoX2NvaGFiaXRpbmdfY291cGxlDQpkYXRhJGhoX21hcnJpZWRfY29oYWJpdGluZ191ZHIxOCA8LSBkYXRhJGhoX2ZhbWlseV9tYXJyaWVkX3dpdGhfdWRyMTggKyBkYXRhJGhoX2NvaGFiaXRpbmdfY291cGxlX3dpdGhfdWRyMTgNCmRhdGEkaGhfbWFycmllZF9jb2hhYml0aW5nX05PMTggPC0gZGF0YSRoaF9mYW1pbHlfbWFycmllZF9OT191ZHIxOCArIGRhdGEkaGhfY29oYWJpdGluZ19jb3VwbGVfTk9fdWRyMTgNCg0KIyBqb2luIHR3byBob3VzZWhvbGQgbGV2ZWwgZGF0YSANCmRhdGEgPC0gbGVmdF9qb2luKGRhdGEsIGNzc19oaF90eXBlW2MoIkdFT0lEIiwiaGhkZXJfdHRsIiwiaGhkZXJfbV90dGwiLCJoaGRlcl9mX3R0bCIpXSkNCg0KIyBuZXcgY29sdW1ucyANCmRhdGEkaGhfZl9oaGRlcl9tYXJyaWVkX2NvaGFiaXRpbmcgPC0gZGF0YSRoaGRlcl9mX3R0bCAtIGRhdGEkaGhfZl9oaGRlcl9ub3Nwb3VzZQ0KZGF0YSRoaF9tX2hoZGVyX21hcnJpZWRfY29oYWJpdGluZyA8LSBkYXRhJGhoZGVyX21fdHRsIC0gZGF0YSRoaF9tX2hoZGVyX25vc3BvdXNlDQoNCiMgVmFsaWRhdGUNCmRhdGEkaGhfZmFtaWx5X21hcnJpZWQgKyBkYXRhJGhoX2NvaGFiaXRpbmdfY291cGxlIC0gDQogIGRhdGEkaGhfZl9oaGRlcl9tYXJyaWVkX2NvaGFiaXRpbmcgLSBkYXRhJGhoX21faGhkZXJfbWFycmllZF9jb2hhYml0aW5nDQoNCiMgRmluYWwgaG91c2Vob2xkIGxldmVsIGRhdGFzZXQgDQpkYXRhIDwtIGRhdGFbYygiR0VPSUQiLCJoaF90dGwiLCJoaGRlcl9tX3R0bCIsImhoZGVyX2ZfdHRsIiwNCiAgICAgICAgICAgICAgICJoaF9tX2hoZGVyX21hcnJpZWRfY29oYWJpdGluZyIsImhoX2ZfaGhkZXJfbWFycmllZF9jb2hhYml0aW5nIiwNCiAgICAgICAgICAgICAgICJoaF9tX2hoZGVyX25vc3BvdXNlIiwiaGhfZl9oaGRlcl9ub3Nwb3VzZSIsDQogICAgICAgICAgICAgICAiaGhfbWFycmllZF9jb2hhYml0aW5nIiwiaGhfbWFycmllZF9jb2hhYml0aW5nX3VkcjE4IiwiaGhfbWFycmllZF9jb2hhYml0aW5nX05PMTgiLA0KICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAiaGhfbV9oaGRlcl9ub3Nwb3VzZV9hbG9uZSIsImhoX21faGhkZXJfbm9zcG91c2Vfd2l0aF91ZHIxOCIsDQogICAgICAgICAgICAgICAiaGhfbV9oaGRlcl9ub3Nwb3VzZV93aXRoX3JlbGF0aXZlcyIsImhoX21faGhkZXJfbm9zcG91c2Vfbm9uX3JlbGF0aXZlcyIsDQogICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICJoaF9mX2hoZGVyX25vc3BvdXNlX2Fsb25lIiwiaGhfZl9oaGRlcl9ub3Nwb3VzZV93aXRoX3VkcjE4IiwNCiAgICAgICAgICAgICAgICJoaF9mX2hoZGVyX25vc3BvdXNlX3dpdGhfcmVsYXRpdmVzIiwiaGhfZl9oaGRlcl9ub3Nwb3VzZV9ub25fcmVsYXRpdmVzIildDQoNCg0KIyAyOiBIb3VzZWhvbGRlciBBbG9uZSA+PSA2NQ0KdHQgPC0gY3NzX292ZXI2NF9pbl9oaFtjKCJHRU9JRCIsIm92ZXI2NF9ub25mYW1pbHlfbV9oaGRlcl9hbG9uZSIsIm92ZXI2NF9ub25mYW1pbHlfZl9oaGRlcl9hbG9uZSIpXQ0Kc2V0bmFtZXModHQsIG9sZD1jKCJvdmVyNjRfbm9uZmFtaWx5X21faGhkZXJfYWxvbmUiLCJvdmVyNjRfbm9uZmFtaWx5X2ZfaGhkZXJfYWxvbmUiKSwNCiAgICAgICAgIG5ldyA9IGMoImhoX21faGhkZXJfbm9zcG91c2VfYWxvbmVfb3ZlcjY0IiwiaGhfZl9oaGRlcl9ub3Nwb3VzZV9hbG9uZV9vdmVyNjQiKSkNCmRhdGEgPC0gbGVmdF9qb2luKGRhdGEsIHR0KQ0KDQojIDM6IENsYXNzaWZ5IGhvdXNlaG9sZCBpbnRvIDEyIHR5cGVzIA0KIyMgLS0tLS0tLS0gTWFycmllZCBvciBDb2hhYml0aW5nIENvdXBsZSAtLS0tLS0NCmRhdGEkaDFfbWNfdWRyMTggPC0gZGF0YSRoaF9tYXJyaWVkX2NvaGFiaXRpbmdfdWRyMTgNCmRhdGEkaDJfbWNfTk8xOCA8LSBkYXRhJGhoX21hcnJpZWRfY29oYWJpdGluZ19OTzE4DQoNCiMjIC0tLS0tLS0tIE1hbGUgaG91c2Vob2xkZXIgbm8gc3BvdXNlIC0tLS0tLQ0KZGF0YSRoM19tbnNfYWxvbmVfbGVzczY1IDwtIGRhdGEkaGhfbV9oaGRlcl9ub3Nwb3VzZV9hbG9uZSAtIGRhdGEkaGhfbV9oaGRlcl9ub3Nwb3VzZV9hbG9uZV9vdmVyNjQNCmRhdGEkaDRfbW5zX2Fsb25lX292ZXI2NCA8LSBkYXRhJGhoX21faGhkZXJfbm9zcG91c2VfYWxvbmVfb3ZlcjY0DQpkYXRhJGg1X21uc191ZHIxOCA8LSBkYXRhJGhoX21faGhkZXJfbm9zcG91c2Vfd2l0aF91ZHIxOA0KZGF0YSRoNl9tbnNfTk8xOF9vdGhlcnMgPC0gZGF0YSRoaF9tX2hoZGVyX25vc3BvdXNlX3dpdGhfcmVsYXRpdmVzIA0KZGF0YSRoN19tbnNfbm9uZmFtaWx5IDwtIGRhdGEkaGhfbV9oaGRlcl9ub3Nwb3VzZV9ub25fcmVsYXRpdmVzDQoNCiMjIC0tLS0tLS0tIEZlbWFsZSBob3VzZWhvbGRlciBubyBzcG91c2UgLS0tLS0tDQpkYXRhJGg4X2Zuc19hbG9uZV9sZXNzNjUgPC0gZGF0YSRoaF9mX2hoZGVyX25vc3BvdXNlX2Fsb25lIC0gZGF0YSRoaF9mX2hoZGVyX25vc3BvdXNlX2Fsb25lX292ZXI2NA0KZGF0YSRoOV9mbnNfYWxvbmVfb3ZlcjY0IDwtIGRhdGEkaGhfZl9oaGRlcl9ub3Nwb3VzZV9hbG9uZV9vdmVyNjQNCmRhdGEkaDEwX2Zuc191ZHIxOCA8LSBkYXRhJGhoX2ZfaGhkZXJfbm9zcG91c2Vfd2l0aF91ZHIxOA0KZGF0YSRoMTFfZm5zX05PMThfb3RoZXJzIDwtIGRhdGEkaGhfZl9oaGRlcl9ub3Nwb3VzZV93aXRoX3JlbGF0aXZlcyANCmRhdGEkaDEyX2Zuc19ub25mYW1pbHkgPC0gZGF0YSRoaF9mX2hoZGVyX25vc3BvdXNlX25vbl9yZWxhdGl2ZXMNCg0KY3NzX2hoX3R5cGVfZm5sIDwtIGRhdGENCg0KIyA077yaIEdyb3VwIFF1YXJ0ZXJzLCBwb3AgPj0gNjUNCmRhdGEgPC0gY3NzX292ZXI2NF9pbl9oaFtjKCJHRU9JRCIsIm92ZXI2NF9pbl9ncXF1YXJ0ZXIiKV0NCmRhdGEgPC0gbGVmdF9qb2luKGNzc19ncm91cF9xdWFydGVyX3BvcCwgZGF0YSkNCmRhdGEkYWdlXzEzXzE4X2p1dmVuaWxlZmFjaWxpdGllcyA8LSBkYXRhJEp1dmVuaWxlLmZhY2lsaXRpZXMNCmRhdGEkYWdlXzE1XzI0X2NvbGxlZ2UgPC0gZGF0YSRDb2xsZWdlLlVuaXZlcnNpdHkuc3R1ZGVudC5ob3VzaW5nDQpkYXRhJGFnZV8xOF82NF9vdGhlciA8LSBkYXRhJFRvdGFsIC0gZGF0YSRvdmVyNjRfaW5fZ3FxdWFydGVyIC0gZGF0YSRhZ2VfMTNfMThfanV2ZW5pbGVmYWNpbGl0aWVzIC0gZGF0YSRhZ2VfMTVfMjRfY29sbGVnZQ0KY3NzX2dyb3VwX3F1YXJ0ZXJfcG9wXzIgPC0gZGF0YQ0KYGBgDQojIFNFVCBVUA0KYGBge3J9DQojIFJhbmRvbSBTZWVkDQpybV9zZWVkIDwtIDMxNQ0Kc2V0LnNlZWQocm1fc2VlZCkNCiMgcHJlcGFyZSBpbmRleCANCmx0X2dlb2lkX2JnIDwtIGlkeF9jYmdyb3VwJEdFT0lEDQpsdF9nZW9pZF9iZyA8LSBsdF9nZW9pZF9iZ1tsdF9nZW9pZF9iZyE9IjM2MDEzOTkwMDAwMCJdDQpgYGANCg0KIyBHZW5lcmF0ZSBJbmRpdmlkdWFsIFBvcHVsYXRpb24NCmBgYHtyfQ0KIyBzZXQgcmFuZG9tIHNlZWQgDQpzZXQuc2VlZChybV9zZWVkKQ0KDQpkZnNfaW5kIDwtIGxpc3QoKQ0KZm9yIChpIGluIDE6bGVuZ3RoKGx0X2dlb2lkX2JnKSkgew0KICAjIGNyZWF0ZSBhbiBlbXB0eSBkYXRhZnJhbWUgZm9yIGluZGl2aWR1YWxzIGluIGNlbnN1cyBiZyBpICANCiAgdHQgPC0gY3NzX2FnZV9nZW5kZXJbY3NzX2FnZV9nZW5kZXIkR0VPSUQgPT0gbHRfZ2VvaWRfYmdbW2ldXSxdJHR0bCANCiAgZGYgPC0gc2V0bmFtZXMoZGF0YS5mcmFtZShtYXRyaXgobnJvdyA9IHR0LCBuY29sID0gNSkpLCBuZXcgPSBjKCJpbmRfaWQiLCJnZW5kZXIiLCJhZ2UiLCJoaF9pZCIsImhoX3JvbGUiKSkNCiAgDQogICMgdW5pcXVlIGlkZW50aWZpZXIgJiBnZW5kZXIgJiBhZ2UNCiAgZGYkaW5kX2lkIDwtIHBhc3RlKGx0X2dlb2lkX2JnW1tpXV0sICJfaW5kXyIscm93bmFtZXMoZGYpLCBzZXAgPSAiIikNCiAgZGYkZ2VuZGVyIDwtIHJlcChjKCJNYWxlIiwiRmVtYWxlIiksIHRpbWVzID0gYyhjc3NfYWdlX2dlbmRlcltjc3NfYWdlX2dlbmRlciRHRU9JRCA9PSBsdF9nZW9pZF9iZ1tbaV1dLF0kbV90dGwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3NzX2FnZV9nZW5kZXJbY3NzX2FnZV9nZW5kZXIkR0VPSUQgPT0gbHRfZ2VvaWRfYmdbW2ldXSxdJGZfdHRsKSkNCiAgZGYkYWdlIDwtIGluZF9hZ2VfZ2VuZXJhdG9yKGx0X2dlb2lkX2JnW1tpXV0pDQogIA0KICAjIGFwcGVuZCBkYXRhZnJhbWUgdG8gdGhlIGxpc3QgDQogIGRmc19pbmRbW2xlbmd0aChkZnNfaW5kKSArIDFdXSA8LSBkZg0KfQ0KDQpuYW1lcyhkZnNfaW5kKSA8LSBsdF9nZW9pZF9iZw0KYGBgDQoNCiMgQXNzaWduOiBHcm91cCBRdWFydGVyDQpgYGB7cn0NCiMgc2V0IHJhbmRvbSBzZWVkIA0Kc2V0LnNlZWQocm1fc2VlZCkNCg0KIyBQcmVwYXJlIGRhdGEgZnJhbWUgDQpmb28gPC0gZGZzX2luZCAgICMgaW5kaXZpZHVhbCANCmRmc19ncXVhcnRlciA8LSBsaXN0KCkNCg0KZm9yIChpIGluIDE6bGVuZ3RoKGx0X2dlb2lkX2JnKSkgew0KICAjIFN0YXJ0IEhlcmUNCiAgaWR4IDwtIGx0X2dlb2lkX2JnW1tpXV0NCiAgbSA8LSBjc3NfZ3JvdXBfcXVhcnRlcl9wb3BfMiAlPiUgZmlsdGVyKEdFT0lEID09IGlkeCkgJT4lDQogICAgc2VsZWN0KGMoIlRvdGFsIiwiYWdlXzEzXzE4X2p1dmVuaWxlZmFjaWxpdGllcyIsImFnZV8xNV8yNF9jb2xsZWdlIiwiYWdlXzE4XzY0X290aGVyIiwib3ZlcjY0X2luX2dxcXVhcnRlciIpKSAlPiUgDQogICAgdW5saXN0KCkgJT4lIGFzLm1hdHJpeCgpDQogIG0gPC0gbSArIDAuMDENCiAgDQogICMgQ3JlYXRlIGFuIGVtcHR5IGRhdGFmcmFtZSB0byBzdG9yZSBncm91cCBxdWFydGVyIHBvcHVsYXRpb25zDQogIGRmIDwtIGRhdGEuZnJhbWUobWF0cml4KG5yb3cgPSAwLCBuY29sID0gMikpICU+JSBzZXRuYW1lcyhuZXcgPSBjKCJpbmRfaWQiLCJ0eXBlIikpDQogIA0KICBpZihtWzFdID4gMCl7DQogICAgZGF0YSA8LSBmb29bW2lkeF1dDQogICAgDQogICAgIyBDb2xsZWdlIFN0dWRlbnQgDQogICAgYSA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBhZ2UgJWluJSAxNToyNCkgJT4lIHNsaWNlX3NhbXBsZSggbiA9IG1bM10pICU+JSBwdWxsKGluZF9pZCkNCiAgICBkYXRhW2RhdGEkaW5kX2lkICVpbiUgYSwiaGhfcm9sZSJdIDwtICJpbl9ncSINCiAgICBkYXRhW2RhdGEkaW5kX2lkICVpbiUgYSwiaGhfaWQiXSA8LSAiZ3FfY29sbGVnZV9ob3VzaW5nIg0KICAgIA0KICAgICMgSnV2ZW5pbGVfZmFjaWxpdHkNCiAgICBiIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSAlaW4lIDEzOjE4KSAlPiUgc2xpY2Vfc2FtcGxlKCBuID0gbVsyXSkgJT4lIHB1bGwoaW5kX2lkKQ0KICAgIGRhdGFbZGF0YSRpbmRfaWQgJWluJSBiLCJoaF9yb2xlIl0gPC0gImluX2dxIg0KICAgIGRhdGFbZGF0YSRpbmRfaWQgJWluJSBiLCJoaF9pZCJdIDwtICJncV9KdXZlbmlsZV9mYWNpbGl0eSINCiAgICANCiAgICAjIE90aGVyIGFkdWx0IA0KICAgIGMgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlICVpbiUgMTg6NjQpICU+JSBzbGljZV9zYW1wbGUoIG4gPSBtWzRdKSAlPiUgcHVsbChpbmRfaWQpDQogICAgZGF0YVtkYXRhJGluZF9pZCAlaW4lIGMsImhoX3JvbGUiXSA8LSAiaW5fZ3EiDQogICAgZGF0YVtkYXRhJGluZF9pZCAlaW4lIGMsImhoX2lkIl0gPC0gImdxX290aGVyc19hZHVsdCINCiAgICANCiAgICAjIE90aGVyIGZvciBvdmVyIDY0DQogICAgZCA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBhZ2UgPiA2NCkgJT4lIHNsaWNlX3NhbXBsZSggbiA9IG1bNV0pICU+JSBwdWxsKGluZF9pZCkNCiAgICBkYXRhW2RhdGEkaW5kX2lkICVpbiUgZCwiaGhfcm9sZSJdIDwtICJpbl9ncSINCiAgICBkYXRhW2RhdGEkaW5kX2lkICVpbiUgZCwiaGhfaWQiXSA8LSAiZ3Ffb3RoZXJzX2FkdWx0X292ZXI2NCINCiAgfQ0KICANCiAgIyBDb2xsZWN0IGFsbCBpbmRpdmlkdWFscyBpbiBncSANCiAgZGYgPC0gZGF0YSAlPiUgZmlsdGVyKGhoX3JvbGUgPT0gImluX2dxIikNCiAgZGZzX2dxdWFydGVyW1tsZW5ndGgoZGZzX2dxdWFydGVyKSAgKyAxXV0gPC0gZGYNCiAgDQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICBwcmludChpKQ0KfQ0KDQpuYW1lcyhkZnNfZ3F1YXJ0ZXIpIDwtIGx0X2dlb2lkX2JnDQpkZnNfaW5kIDwtIGZvbw0KYGBgDQoNCiMgSE9VU0VIT0xEIA0KIyMgQ3JlYXRlIGVtcHR5IEhIIGNvbnRhaW5lciBmb3IgMTIgdHlwZXMgDQpgYGB7cn0NCiMgc2V0IHJhbmRvbSBzZWVkIA0Kc2V0LnNlZWQocm1fc2VlZCkNCg0KIyBUYWJsZTogY3NzX2hoX3R5cGVfZm5sDQpmb28gPC0gZGZzX2luZCAgICMgaW5kaXZpZHVhbCANCmRmc19oaCA8LSBsaXN0KCkNCg0KbHQgPC0gbmFtZXMoY3NzX2hoX3R5cGVfZm5sWywyMjozM10pDQoNCiMgU3RhcnQgTG9vcCB0byBjcmVhdGUgaG91c2Vob2xkIGRmIGNvbnRhaW5lcnMNCmZvciAoaSBpbiAxOmxlbmd0aChsdF9nZW9pZF9iZykpIHsNCiAgIyBzdGFydCBoZXJlLCBnZXQgY2Vuc3VzIGJsb2NrIGdyb3VwIGluZGV4DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogIG0gPC0gY3NzX2hoX3R5cGVfZm5sICU+JSBmaWx0ZXIoR0VPSUQgPT0gaWR4KSAlPiUgc2VsZWN0KGMoMjI6MzMpKSAlPiUgdW5saXN0KCkNCiAgDQogIGRmIDwtIGRhdGEuZnJhbWUoaGhfaWQgPSBOQSx0eXBlID0gcmVwKGx0LCBtKSwgaWZfcG9wID0gMCkNCiAgZGYkaGhfaWQgPC0gcGFzdGUoaWR4LCAiX2hoXyIscm93bmFtZXMoZGYpLCBzZXAgPSAiIikNCiAgZGZzX2hoW1sxK2xlbmd0aChkZnNfaGgpXV0gPC0gZGYNCn0NCg0KbmFtZXMoZGZzX2hoKSA8LSBsdF9nZW9pZF9iZw0KYGBgDQoNCiMjIEZpbGwgVHlwZSAxOiBoMV9tY191ZHIxOA0KYGBge3J9DQojIHNldCByYW5kb20gc2VlZCANCnNldC5zZWVkKHJtX3NlZWQpDQoNCiMgVGFibGUNCmZvbyA8LSBkZnNfaW5kICAgIyBpbmRpdmlkdWFsIA0KdHQgPC0gZGZzX2hoICAjIGhvdXNlaG9sZCANCg0KIyBJbml0aWFsaXplIA0KY2hpbGRfbW9tX2Jya3MgPC0gYygwLDE3LDQxLDEwMCkNCm1vbV9kYWRfYnJrcyA8LSBjKC0xMDAsLTUsOSwxMDApDQpsYWJscyA8LSBjKDAsMSwwKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgobHRfZ2VvaWRfYmcpKSB7DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogICMgSW5kaXZpZHVhbCBEYXRhDQogIGRhdGEgPC0gZm9vW1tpZHhdXQ0KICAjIEhvdXNlaG9sZCBEYXRhIA0KICBkZiA8LSB0dFtbaWR4XV0NCiAgIyBob3VzZWhvbGQgdG8gZmlsbCANCiAgbHRfdGVtcCA8LSBkZiAlPiUgZmlsdGVyKHR5cGUgPT0gImgxX21jX3VkcjE4IikgJT4lIHB1bGwoaGhfaWQpDQogIG4gPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlIDwgMTgpICU+JSBucm93KCkNCiAgbiA8LSBtaW4obGVuZ3RoKGx0X3RlbXApLCBuKQ0KICANCiAgaWYobiA+IDApew0KICAgIGZvciAoaiBpbiAxOm4pIHsNCiAgICAgIGhoX2lkeCA8LSBsdF90ZW1wW1tqXV0NCiAgICAgIA0KICAgICAgIyBXaGlsZSBsb29wIHN0YXJ0IA0KICAgICAgb28gPSAwDQogICAgICB3aGlsZSAob28gPT0gMCkgew0KICAgICAgICAjIFJhbmRvbWx5IHNlbGVjdCBvbmUgY2hpbGQgPCAxOA0KICAgICAgICBhIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9pZCkgJiBhZ2UgPCAxOCkgJT4lIHNsaWNlX3NhbXBsZShuPTEpDQogICAgICAgIGIgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX2lkKSAmIGdlbmRlciA9PSAiRmVtYWxlIiAmIGFnZSA+PTE4KSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICAgYyA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfaWQpICYgZ2VuZGVyID09ICJNYWxlIiAmIGFnZSA+PTE4KSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICAgDQogICAgICAgIG8xIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGN1dChiJGFnZSAtIGEkYWdlLCBicmVha3MgPSBjaGlsZF9tb21fYnJrcywgbGFiZWxzID0gbGFibHMpKSkNCiAgICAgICAgbzIgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY3V0KGMkYWdlIC0gYiRhZ2UsIGJyZWFrcyA9IG1vbV9kYWRfYnJrcywgbGFiZWxzID0gbGFibHMpKSkNCiAgICAgICAgb28gPC0gbzEgKiBvMg0KICAgICAgfQ0KICAgICAgDQogICAgICAjIFNhdmUgUmVzdWx0DQogICAgICBkYXRhW2RhdGEkaW5kX2lkID09IGEkaW5kX2lkLCBjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhoaF9pZHgsImNoaWxkX3VkcjE4IikNCiAgICAgIGRhdGFbZGF0YSRpbmRfaWQgPT0gYiRpbmRfaWQsIGMoImhoX2lkIiwiaGhfcm9sZSIpXSA8LSBjKGhoX2lkeCwibW9tIikNCiAgICAgIGRhdGFbZGF0YSRpbmRfaWQgPT0gYyRpbmRfaWQsIGMoImhoX2lkIiwiaGhfcm9sZSIpXSA8LSBjKGhoX2lkeCwiZGFkIikNCiAgICAgIA0KICAgICAgcHJpbnQoaikNCiAgfQ0KICAgIA0KICB9DQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICBwcmludChwYXN0ZShpLCJkb25lIixzZXAgPSAiLS0tLS0tLS0tLS0tLS0tLSIpKQ0KfQ0KDQpkZnNfaW5kIDwtIGZvbyAgICANCg0KDQojICMgc2F2ZSB0aGUgcmVzdWx0IA0KIyAjIGltcF9kZnNfaW5kIDwtIGRmc19pbmQNCiMgZGF0YSA8LSBleHBvcnRfaW1wX2RmcyhpbXBfZGZzX2luZCkNCiMgd3JpdGUuY3N2KGRhdGEsImRhdGEvMDFfc3ludGhldGljX3BvcHVsYXRpb25fZGF0YXNldC9wcm9jZXNzX3NhdmVkX2RhdGFzZXQvWFhfc3RlcDFfcG9wdWxhdGVfdHlwZTFfaDFfbWNfdWRyMTguY3N2Iiwgcm93Lm5hbWVzID0gRikNCmBgYA0KDQojIyBGaWxsIFR5cGUgNSYxMDogc2luZ2xlIHBhcmVudA0KYGBge3J9DQojIHNldCByYW5kb20gc2VlZCANCnNldC5zZWVkKHJtX3NlZWQpDQoNCiMgVGFibGUNCmZvbyA8LSBkZnNfaW5kICAgIyBpbmRpdmlkdWFsIA0KdHQgPC0gZGZzX2hoICAjIGhvdXNlaG9sZCANCg0KIyBJbml0aWFsaXplIA0KY2hpbGRfbW9tX2Jya3MgPC0gYygwLDE3LDQxLDEwMCkNCmNoaWxkX2RhZF9icmtzIDwtIGMoMCwxNyw0OSwxMDApDQpsYWJscyA8LSBjKDAsMSwwKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgobHRfZ2VvaWRfYmcpKSB7DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogICMgSW5kaXZpZHVhbCBEYXRhDQogIGRhdGEgPC0gZm9vW1tpZHhdXQ0KICAjIEhvdXNlaG9sZCBEYXRhIA0KICBkZiA8LSB0dFtbaWR4XV0NCiAgDQogICMgdHlwZSA1OiBoNV9tbnNfdWRyMTggICBob3VzZWhvbGQgdG8gZmlsbCANCiAgbHRfdGVtcCA8LSBkZiAlPiUgZmlsdGVyKHR5cGUgPT0gImg1X21uc191ZHIxOCIpICU+JSBwdWxsKGhoX2lkKQ0KICBuIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA8IDE4KSAlPiUgbnJvdygpDQogIG4gPC0gbWluKG4sIGxlbmd0aChsdF90ZW1wKSkNCiAgDQogIGlmKG4+MCl7DQogICAgZm9yIChqIGluIDE6bikgew0KICAgICAgaGhfaWR4IDwtIGx0X3RlbXBbW2pdXQ0KICAgICAgb289MCAgICMgd2hpbGUgbG9vcCBzdG9wIGNvbmRpdGlvbiBvbz0xDQogICAgICBuX2xvb3AgPSAxMDAwDQogICAgICB3aGlsZSAob289PTAgJiBuX2xvb3AgPiAwKSB7DQogICAgICAgIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGFnZSA8IDE4ICYgaXMubmEoaGhfaWQpKSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICAgYiA8LSBkYXRhICU+JSBmaWx0ZXIoZ2VuZGVyPT0iTWFsZSIgJiBhZ2UgPj0xOCAmIGlzLm5hKGhoX2lkKSkgJT4lIHNsaWNlX3NhbXBsZShuPTEpDQogICAgICAgIG9vIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGN1dChiJGFnZSAtIGEkYWdlLCBicmVha3MgPSBjaGlsZF9kYWRfYnJrcywgbGFiZWwgPSBsYWJscykpKQ0KICAgICAgICBuX2xvb3AgPSBuX2xvb3AtMSB9DQogICAgICANCiAgICAgIGlmKG5fbG9vcCA8PTApe2JyZWFrfQ0KICAgICAgIyBTYXZlIFJlc3VsdA0KICAgICAgZGF0YVtkYXRhJGluZF9pZCA9PSBhJGluZF9pZCwgYygiaGhfaWQiLCJoaF9yb2xlIildIDwtIGMoaGhfaWR4LCJjaGlsZF91ZHIxOCIpDQogICAgICBkYXRhW2RhdGEkaW5kX2lkID09IGIkaW5kX2lkLCBjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhoaF9pZHgsInNpbmdsZV9kYWQiKQ0KICAgICAgcHJpbnQocGFzdGUoInNpbmdsZV9kYWQgICAiLGosIHNlcCA9ICIgICIpKQ0KICAgICAgDQogICAgfSAgfQ0KICANCiAgIyB0eXBlIDEwOiBoMTBfZm5zX3VkcjE4IA0KICBsdF90ZW1wIDwtIGRmICU+JSBmaWx0ZXIodHlwZSA9PSAiaDEwX2Zuc191ZHIxOCIpICU+JSBwdWxsKGhoX2lkKQ0KICBuIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA8IDE4KSAlPiUgbnJvdygpDQogIG4gPC0gbWluKG4sIGxlbmd0aChsdF90ZW1wKSkNCiAgaWYobj4wKXsNCiAgICBmb3IgKGogaW4gMTpuKSB7DQogICAgICBoaF9pZHggPC0gbHRfdGVtcFtbal1dICAgICAgICAgICAgIyBob3VzZWhvbGQgaWQNCiAgICAgIG9vPTANCiAgICAgIG5fbG9vcCA9IDEwMDANCiAgICAgIHdoaWxlIChvbz09MCAmIG5fbG9vcCA+IDApIHsNCiAgICAgICAgYSA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBhZ2UgPCAxOCkgJT4lIHNsaWNlX3NhbXBsZShuPTEpDQogICAgICAgIGMgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49IDE4ICYgZ2VuZGVyPT0iRmVtYWxlIikgJT4lIHNsaWNlX3NhbXBsZShuPTEpDQogICAgICAgIG9vIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGN1dChjJGFnZSAtIGEkYWdlLCBicmVha3MgPSBjaGlsZF9tb21fYnJrcywgbGFiZWwgPSBsYWJscykpKQ0KICAgICAgICBuX2xvb3AgPSBuX2xvb3AtMQ0KICAgICAgfQ0KICAgICAgDQogICAgICBpZihuX2xvb3AgPD0wKXticmVha30NCiAgICAgIA0KICAgICAgIyBTYXZlIFJlc3VsdA0KICAgICAgZGF0YVtkYXRhJGluZF9pZCA9PSBhJGluZF9pZCwgYygiaGhfaWQiLCJoaF9yb2xlIildIDwtIGMoaGhfaWR4LCJjaGlsZF91ZHIxOCIpDQogICAgICBkYXRhW2RhdGEkaW5kX2lkID09IGMkaW5kX2lkLCBjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhoaF9pZHgsInNpbmdsZV9tb20iKQ0KICAgICAgcHJpbnQocGFzdGUoInNpbmdsZV9tb20gICAiLGosIHNlcCA9ICIgICIpKQ0KICAgIH0NCiAgfQ0KDQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICBwcmludChwYXN0ZShpLCJkb25lIixzZXAgPSAiLS0tLS0tLS0tLS0tLS0tLSIpKQ0KICANCn0NCg0KIyAjIHNhdmUgcmVzdWx0IA0KIyBkYXRhIDwtIGV4cG9ydF9pbXBfZGZzKGRmc19pbmQpDQojIHdyaXRlLmNzdihkYXRhLCJkYXRhLzAxX3N5bnRoZXRpY19wb3B1bGF0aW9uX2RhdGFzZXQvcHJvY2Vzc19zYXZlZF9kYXRhc2V0L1hYX3N0ZXAyX3BvcHVsYXRlX3R5cGU1XzEwX3NpbmdsZV9wYXJlbnQuY3N2Iiwgcm93Lm5hbWVzID0gRikNCg0KIyBkZnNfaW5kIDwtIGZvbw0KYGBgDQoNCiMjIEZpbGwgVHlwZSA0Jjk6IGFsb25lID42NA0KaDRfbW5zX2Fsb25lX292ZXI2NA0KaDlfZm5zX2Fsb25lX292ZXI2NA0KYGBge3J9DQojIHNldCByYW5kb20gc2VlZCANCnNldC5zZWVkKHJtX3NlZWQpDQoNCiMgVGFibGUNCmZvbyA8LSBkZnNfaW5kICAgIyBpbmRpdmlkdWFsIA0KdHQgPC0gZGZzX2hoICAjIGhvdXNlaG9sZCANCg0KIyBQb3B1bGF0ZSANCmZvciAoaSBpbiAxOmxlbmd0aChsdF9nZW9pZF9iZykpIHsNCiAgaWR4IDwtIGx0X2dlb2lkX2JnW1tpXV0NCiAgIyBJbmRpdmlkdWFsIERhdGENCiAgZGF0YSA8LSBmb29bW2lkeF1dDQogICMgSG91c2Vob2xkIERhdGEgDQogIGRmIDwtIHR0W1tpZHhdXQ0KICAjIC0tLS0tLS0tLS0tLS0gTUFMRSBBTE9ORSA+IDY0DQogICMgbnVtYmVyIG9mIGhoIHdpdGggb2xkZXIgTUFMRSBzaW5nbGV0b24NCiAgbHRfdGVtcCA8LSBkZiAlPiUgZmlsdGVyKHR5cGU9PSJoNF9tbnNfYWxvbmVfb3ZlcjY0IikgJT4lIHB1bGwoaGhfaWQpDQogICMgY291bnQgb2YgaW5kaXZpZHVhbHMgc2F0aXNmeWluZyBjb25zdHJhaW50cyANCiAgbiA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBnZW5kZXIgPT0iTWFsZSIgJiBhZ2UgPiA2NCkgJT4lIG5yb3coKQ0KICBuIDwtIG1pbihsZW5ndGgobHRfdGVtcCksIG4pDQogIA0KICBpZihuPjApKA0KICAgIGZvciAoaiBpbiAxOm4pIHsNCiAgICAgIGhoX2lkeCA8LSBsdF90ZW1wW1tqXV0gICAgICAgICAgICAjIGhvdXNlaG9sZCBpZA0KICAgICAgYSA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBnZW5kZXIgPT0iTWFsZSIgJiBhZ2UgPiA2NCkgJT4lIHNsaWNlX3NhbXBsZShuPTEpDQogICAgICAjIFNhdmUgUmVzdWx0DQogICAgICBkYXRhW2RhdGEkaW5kX2lkID09IGEkaW5kX2lkLCBjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhoaF9pZHgsIm1hbGVfb2xkZXJzaW5nbGV0b24iKQ0KICAgIH0pDQogIA0KICAjIC0tLS0tLS0tLS0tLS0gRkVNQUxFIEFMT05FID4gNjQNCiAgIyBudW1iZXIgb2YgaGggd2l0aCBvbGRlciBGRU1BTEUgc2luZ2xldG9uDQogIGx0X3RlbXAgPC0gZGYgJT4lIGZpbHRlcih0eXBlPT0iaDlfZm5zX2Fsb25lX292ZXI2NCIpICU+JSBwdWxsKGhoX2lkKQ0KICAjIGNvdW50IG9mIGluZGl2aWR1YWxzIHNhdGlzZnlpbmcgY29uc3RyYWludHMgDQogIG4gPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgZ2VuZGVyID09IkZlbWFsZSIgJiBhZ2UgPiA2NCkgJT4lIG5yb3coKQ0KICBuIDwtIG1pbihsZW5ndGgobHRfdGVtcCksIG4pDQogIA0KICBpZihuPjApKA0KICAgIGZvciAoaiBpbiAxOm4pIHsNCiAgICAgIGhoX2lkeCA8LSBsdF90ZW1wW1tqXV0gICAgICAgICAgICAjIGhvdXNlaG9sZCBpZA0KICAgICAgYSA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBnZW5kZXIgPT0iRmVtYWxlIiAmIGFnZSA+IDY0KSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICMgU2F2ZSBSZXN1bHQNCiAgICAgIGRhdGFbZGF0YSRpbmRfaWQgPT0gYSRpbmRfaWQsIGMoImhoX2lkIiwiaGhfcm9sZSIpXSA8LSBjKGhoX2lkeCwiZmVtYWxlX29sZGVyc2luZ2xldG9uIikNCiAgICB9KQ0KDQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICBwcmludChwYXN0ZShpLCJkb25lIixzZXAgPSAiLS0tLS0tLS0tLS0tLS0tLSIpKQ0KfQ0KDQoNCiMgIyAjIHNhdmUgcmVzdWx0IA0KIyBkYXRhIDwtIGV4cG9ydF9pbXBfZGZzKGZvbykNCiMgd3JpdGUuY3N2KGRhdGEsImRhdGEvMDFfc3ludGhldGljX3BvcHVsYXRpb25fZGF0YXNldC9wcm9jZXNzX3NhdmVkX2RhdGFzZXQvWFhfc3RlcDNfcG9wdWxhdGVfdHlwZTRfOV9vbGRlcl9zaW5nbGV0b24uY3N2Iiwgcm93Lm5hbWVzID0gRikNCg0KIyBkZnNfaW5kIDwtIGZvbw0KDQpgYGANCg0KIyMgRmlsbCBUeXBlIDI6IGgyX21jX05PMTgNCmBgYHtyfQ0KIyBzZXQgcmFuZG9tIHNlZWQgDQpzZXQuc2VlZChybV9zZWVkKQ0KDQojIFRhYmxlDQpmb28gPC0gZGZzX2luZCAgICMgaW5kaXZpZHVhbCANCnR0IDwtIGRmc19oaCAgIyBob3VzZWhvbGQgDQoNCiMgSW5pdGlhbGl6ZQ0KbW9tX2RhZF9icmtzIDwtIGMoLTEwMCwtNSw5LDEwMCkNCmxhYmxzIDwtIGMoMCwxLDApDQoNCmZvciAoaSBpbiAxOmxlbmd0aChsdF9nZW9pZF9iZykpIHsNCiAgaWR4IDwtIGx0X2dlb2lkX2JnW1tpXV0NCiAgIyBJbmRpdmlkdWFsIERhdGENCiAgZGF0YSA8LSBmb29bW2lkeF1dDQogICMgSG91c2Vob2xkIERhdGEgDQogIGRmIDwtIHR0W1tpZHhdXQ0KICAjIC0tLS0tLS0tLS0tLS0gZmlsbCB0eXBlIDI6IGgyX21jX05PMTgNCiAgIyBkZWNpZGUgdGhlIG1pbmltdW0gbnVtYmVyIG9mIGhoIHRvIGZpbGwNCiAgbHRfdGVtcCA8LSBkZiAlPiUgZmlsdGVyKHR5cGUgPT0gImgyX21jX05PMTgiKSAlPiUgcHVsbChoaF9pZCkNCiAgbiA8LSBtaW4oZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49IDE4ICYgZ2VuZGVyPT0iTWFsZSIpICU+JSBucm93KCksDQogICAgICAgIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA+PSAxOCAmIGdlbmRlcj09IkZlbWFsZSIpICU+JSBucm93KCkpDQogIG4gPC0gbWluKGxlbmd0aChsdF90ZW1wKSwgbikNCiAgDQogIGlmKG4+MCkoDQogICAgZm9yIChqIGluIDE6bikgew0KICAgICAgaGhfaWR4IDwtIGx0X3RlbXBbW2pdXQ0KICAgICAgIyBEZWZpbmUgc3RvcCBjb25kaXRpb24gDQogICAgICBvbz0wDQogICAgICBuX2xvb3AgPSAxMDAwICAjIG1heGltdW0gcnVucw0KICAgICAgDQogICAgICB3aGlsZSAob28gPT0wICYgbl9sb29wID4wKSB7DQogICAgICAgIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49MTggJiBnZW5kZXI9PSJNYWxlIikgJT4lIHNsaWNlX3NhbXBsZShuPTEpDQogICAgICAgIGIgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49MTggJiBnZW5kZXI9PSJGZW1hbGUiKSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICAgb28gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY3V0KGEkYWdlIC0gYiRhZ2UsIGJyZWFrcyA9IG1vbV9kYWRfYnJrcywgbGFiZWwgPSBsYWJscykpKQ0KICAgICAgICBuX2xvb3AgPSBuX2xvb3AgLTENCiAgICAgIH0NCiAgICAgIGlmKG5fbG9vcCA8PTApe2JyZWFrfQ0KICAgICAgIyBTYXZlIFJlc3VsdA0KICAgICAgZGF0YVtkYXRhJGluZF9pZCA9PSBhJGluZF9pZCwgYygiaGhfaWQiLCJoaF9yb2xlIildIDwtIGMoaGhfaWR4LCJodXNiYW5kX05PX3VkcjE4IikNCiAgICAgIGRhdGFbZGF0YSRpbmRfaWQgPT0gYiRpbmRfaWQsIGMoImhoX2lkIiwiaGhfcm9sZSIpXSA8LSBjKGhoX2lkeCwid2lmZV9OT191ZHIxOCIpDQogICAgICBwcmludChwYXN0ZSgibWNfTk9fMTgiLGosIHNlcCA9ICIgICIpKQ0KICAgIH0NCiAgKQ0KDQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICBwcmludChwYXN0ZShpLCJkb25lIixzZXAgPSAiLS0tLS0tLS0tLS0tLS0tLSIpKQ0KfQ0KDQojICMgIyBzYXZlIHJlc3VsdCANCiMgZGF0YSA8LSBleHBvcnRfaW1wX2Rmcyhmb28pDQojIHdyaXRlLmNzdihkYXRhLCJkYXRhLzAxX3N5bnRoZXRpY19wb3B1bGF0aW9uX2RhdGFzZXQvcHJvY2Vzc19zYXZlZF9kYXRhc2V0L1hYX3N0ZXA0X3BvcHVsYXRlX3R5cGUyX2gyX21jX05PMTguY3N2Iiwgcm93Lm5hbWVzID0gRikNCg0KIyBkZnNfaW5kIDwtIGZvbw0KYGBgDQpgYGB7cn0NCmRhdGEgPC0gcmVhZC5jc3YoImRhdGEvMDBfc2F2ZWRfZGF0YXNldC8wMV9zdGVwNF9wb3B1bGF0ZV90eXBlMl9oMl9tY19OTzE4LmNzdiIpDQpgYGANCg0KIyMgRmlsbCBUeXBlIDMmODogQWR1bHQgYWxvbmUgPCA2NQ0KaDNfbW5zX2Fsb25lX2xlc3M2NQ0KaDhfZm5zX2Fsb25lX2xlc3M2NQ0KYGBge3J9DQojIHNldCByYW5kb20gc2VlZCANCnNldC5zZWVkKHJtX3NlZWQpDQoNCiMgVGFibGUNCmZvbyA8LSBkZnNfaW5kICAgIyBpbmRpdmlkdWFsIA0KdHQgPC0gZGZzX2hoICAjIGhvdXNlaG9sZCANCg0KZm9yIChpIGluIDE6bGVuZ3RoKGx0X2dlb2lkX2JnKSkgew0KICBpZHggPC0gbHRfZ2VvaWRfYmdbW2ldXQ0KICAjIEluZGl2aWR1YWwgRGF0YQ0KICBkYXRhIDwtIGZvb1tbaWR4XV0NCiAgIyBIb3VzZWhvbGQgRGF0YSANCiAgZGYgPC0gdHRbW2lkeF1dDQogICMgdHlwZSAzOiBoM19tbnNfYWxvbmVfbGVzczY1DQogIGx0X3RlbXAgPC0gZGYgJT4lIGZpbHRlcih0eXBlID09ICJoM19tbnNfYWxvbmVfbGVzczY1IikgJT4lIHB1bGwoaGhfaWQpDQogIG4gPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49MTggJiBhZ2UgPDY1ICYgZ2VuZGVyID09Ik1hbGUiKSAlPiUgbnJvdygpDQogIG4gPC0gbWluKG4sIGxlbmd0aChsdF90ZW1wKSkNCiAgaWYobj4wKXsNCiAgICBhIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA+PTE4ICYgYWdlIDw2NSAmIGdlbmRlciA9PSJNYWxlIikgJT4lIHNsaWNlX3NhbXBsZShuPW4pICU+JSBwdWxsKCJpbmRfaWQiKQ0KICAgIGRhdGFbZGF0YSRpbmRfaWQgJWluJSBhLF0kaGhfaWQgPC0gbHRfdGVtcFsxOm5dDQogICAgZGF0YVtkYXRhJGluZF9pZCAlaW4lIGEsXSRoaF9yb2xlIDwtICJtbnNfYWxvbmVfbGVzczY1Ig0KICB9DQogIA0KICAjIHR5cGUgODogaDhfZm5zX2Fsb25lX2xlc3M2NQ0KICBsdF90ZW1wIDwtIGRmICU+JSBmaWx0ZXIodHlwZSA9PSAiaDhfZm5zX2Fsb25lX2xlc3M2NSIpICU+JSBwdWxsKGhoX2lkKQ0KICBuIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA+PTE4ICYgYWdlIDw2NSAmIGdlbmRlciA9PSJGZW1hbGUiKSAlPiUgbnJvdygpDQogIG4gPC0gbWluKG4sIGxlbmd0aChsdF90ZW1wKSkNCiAgaWYobj4wKXsNCiAgICBiIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA+PTE4ICYgYWdlIDw2NSAmIGdlbmRlciA9PSJGZW1hbGUiKSAlPiUgc2xpY2Vfc2FtcGxlKG49bikgJT4lIHB1bGwoImluZF9pZCIpDQogICAgZGF0YVtkYXRhJGluZF9pZCAlaW4lIGIsXSRoaF9pZCA8LSBsdF90ZW1wWzE6bl0NCiAgICBkYXRhW2RhdGEkaW5kX2lkICVpbiUgYixdJGhoX3JvbGUgPC0gImZuc19hbG9uZV9sZXNzNjUiDQogIH0NCg0KICBmb29bW2lkeF1dIDwtIGRhdGENCiAgcHJpbnQocGFzdGUoaSwiZG9uZSIsc2VwID0gIi0tLS0tLS0tLS0tLS0tLS0iKSkNCn0NCg0KIyBzYXZlIHJlc3VsdA0KIyBkYXRhIDwtIGV4cG9ydF9pbXBfZGZzKGZvbykNCiMgd3JpdGUuY3N2KGRhdGEsImRhdGEvMDFfc3ludGhldGljX3BvcHVsYXRpb25fZGF0YXNldC9wcm9jZXNzX3NhdmVkX2RhdGFzZXQvWFhfc3RlcDVfcG9wdWxhdGVfdHlwZTNfOF9hbG9uZV9sZXNzNjUuY3N2IikNCiMgDQojIGRmc19pbmQgPC0gZm9vDQoNCmBgYA0KDQoNCiMjIEZpbGwgVHlwZSA2JjExOiBBZHVsdCBub3QgYWxvbmUgd2l0aCBvdGhlciByZWxhdGl2ZXMNCmg2X21uc19OTzE4X290aGVycw0KaDExX2Zuc19OTzE4X290aGVycw0KYGBge3J9DQojIHNldCByYW5kb20gc2VlZCANCnNldC5zZWVkKHJtX3NlZWQpDQoNCiMgVGFibGUNCmZvbyA8LSBkZnNfaW5kICAgIyBpbmRpdmlkdWFsIA0KdHQgPC0gZGZzX2hoICAjIGhvdXNlaG9sZCANCg0KIyBwb3B1bGF0ZSBhZHVsdCANCmZvciAoaSBpbiAxOmxlbmd0aChsdF9nZW9pZF9iZykpIHsNCiAgaWR4IDwtIGx0X2dlb2lkX2JnW1tpXV0NCiAgIyBJbmRpdmlkdWFsIERhdGENCiAgZGF0YSA8LSBmb29bW2lkeF1dDQogICMgSG91c2Vob2xkIERhdGEgDQogIGRmIDwtIHR0W1tpZHhdXQ0KICANCiAgIyBUeXBlIDY6IGg2X21uc19OTzE4X290aGVycw0KICBsdF90ZW1wIDwtIGRmICU+JSBmaWx0ZXIodHlwZSA9PSAiaDZfbW5zX05PMThfb3RoZXJzIikgJT4lIHB1bGwoaGhfaWQpDQogIG4gPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49IDE4ICYgZ2VuZGVyPT0iTWFsZSIpICU+JSBucm93KCkNCiAgbiA8LSBtaW4obiwgbGVuZ3RoKGx0X3RlbXApKQ0KICBpZihuPjApew0KICAgIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49IDE4ICYgZ2VuZGVyPT0iTWFsZSIpICU+JSBzbGljZV9zYW1wbGUobj1uKSAlPiUgcHVsbChpbmRfaWQpDQogICAgZGF0YVtkYXRhJGluZF9pZCAlaW4lIGEsXSRoaF9pZCA8LSBsdF90ZW1wWzE6bl0NCiAgICBkYXRhW2RhdGEkaW5kX2lkICVpbiUgYSxdJGhoX3JvbGUgPC0gIm1uc19ubzE4X290aGVyX3JlbGF0aXZlIg0KICB9DQoNCiAgIyBUeXBlIDExOiBoMTFfZm5zX05PMThfb3RoZXJzDQogIGx0X3RlbXAgPC0gZGYgJT4lIGZpbHRlcih0eXBlID09ICJoMTFfZm5zX05PMThfb3RoZXJzIikgJT4lIHB1bGwoaGhfaWQpDQogIG4gPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49IDE4ICYgZ2VuZGVyPT0iRmVtYWxlIikgJT4lIG5yb3coKQ0KICBuIDwtIG1pbihuLCBsZW5ndGgobHRfdGVtcCkpDQogIGlmKG4+MCl7DQogICAgYiA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBhZ2UgPj0gMTggJiBnZW5kZXI9PSJGZW1hbGUiKSAlPiUgc2xpY2Vfc2FtcGxlKG49bikgJT4lIHB1bGwoaW5kX2lkKQ0KICAgIGRhdGFbZGF0YSRpbmRfaWQgJWluJSBiLF0kaGhfaWQgPC0gbHRfdGVtcFsxOm5dDQogICAgZGF0YVtkYXRhJGluZF9pZCAlaW4lIGIsXSRoaF9yb2xlIDwtICJmbnNfbm8xOF9vdGhlcl9yZWxhdGl2ZSINCiAgfQ0KDQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICBwcmludChwYXN0ZShpLCJkb25lIixzZXAgPSAiLS0tLS0tLS0tLS0tLS0tLSIpKQ0KfQ0KDQojIHNhdmUgcmVzdWx0DQojIGRhdGEgPC0gZXhwb3J0X2ltcF9kZnMoZm9vKQ0KIyB3cml0ZS5jc3YoZGF0YSwiZGF0YS8wMV9zeW50aGV0aWNfcG9wdWxhdGlvbl9kYXRhc2V0L3Byb2Nlc3Nfc2F2ZWRfZGF0YXNldC9YWF9zdGVwNl9wb3B1bGF0ZV90eXBlNl8xMV9hZHVsdF9oaGRlcl9OT3NwX05PMThfb3RoZXJyZWxhdGl2ZXMuY3N2IikNCiMgZGZzX2luZCA8LSBmb28NCg0KIyBpbXBfZGZzX2luZCA8LSBkZnNfaW5kDQojIGltcF9kZnNfaGggPC0gZGZzX2hoDQpgYGANCg0KIyMgRmlsbCBDaGlsZCA+PSAxOCANCiMjIyBHZXQgY2hpbGQgYWdlIGxpbWl0IA0KYGBge3J9DQojIHNldCByYW5kb20gc2VlZCANCnNldC5zZWVkKHJtX3NlZWQpDQoNCiMgVGFibGUNCmZvbyA8LSBpbXBfZGZzX2luZCAgICMgaW5kaXZpZHVhbCANCnR0IDwtIGltcF9kZnNfaGggICMgaG91c2Vob2xkIA0KDQojIEZpbmQgdGhlIHRoZSBsb3dlciBhbmQgaGlnaGVyIGJvdW5kIG9mIGNoaWxkIGFnZQ0KZm9yIChpIGluIDE6bGVuZ3RoKGx0X2dlb2lkX2JnKSkgew0KICBpZHggPC0gbHRfZ2VvaWRfYmdbW2ldXQ0KICAjIEluZGl2aWR1YWwgRGF0YQ0KICBkYXRhIDwtIGZvb1tbaWR4XV0NCiAgIyBIb3VzZWhvbGQgRGF0YSANCiAgZGYgPC0gdHRbW2lkeF1dDQogICMgLS0tLS0tLS0tLS0tLQ0KDQogICMgTUFMRSBob3VzZWhvbGRlciAtICAgIHBvdGVudGlhbCBmYXRoZXIgIA0KICBhIDwtIGRhdGEgJT4lIGZpbHRlcihoaF9yb2xlICVpbiUgYygiZGFkIiwiaHVzYmFuZF9OT191ZHIxOCIsInNpbmdsZV9kYWQiLCJtbnNfbm8xOF9vdGhlcl9yZWxhdGl2ZSIpKQ0KICAjIEZFTUFMRSBob3VzZWhvbGRlciAtICBwb3RlbnRpYWwgbW90aGVyICANCiAgYiA8LSBkYXRhICU+JSBmaWx0ZXIoaGhfcm9sZSAlaW4lIGMoIm1vbSIsIndpZmVfTk9fdWRyMTgiLCJzaW5nbGVfbW9tIiwiZm5zX25vMThfb3RoZXJfcmVsYXRpdmUiKSkNCiAgDQogIGRmIDwtIGxlZnRfam9pbihkZixhW2MoImhoX2lkIiwiYWdlIildLCBieT1jKCJoaF9pZCI9ImhoX2lkIikpDQogIGRmIDwtIHNldG5hbWVzKGRmLCBvbGQ9ImFnZSIsbmV3PSJtYWxlX2hoZGVyX2FnZSIpDQogIGRmIDwtIGxlZnRfam9pbihkZixiW2MoImhoX2lkIiwiYWdlIildLCBieT1jKCJoaF9pZCI9ImhoX2lkIikpDQogIGRmIDwtIHNldG5hbWVzKGRmLCBvbGQ9ImFnZSIsbmV3PSJmZW1hbGVfaGhkZXJfYWdlIikNCiAgDQogICMgQ2hpbGQgYWdlIGxpbWl0IA0KICBkZiRjaGlsZF9sb19iIDwtIDk5OQ0KICBkZiRjaGlsZF9oaV9iIDwtIC0xDQogIGRmWyFpcy5uYShkZiRmZW1hbGVfaGhkZXJfYWdlKSxdJGNoaWxkX2xvX2IgPC0gZGZbIWlzLm5hKGRmJGZlbWFsZV9oaGRlcl9hZ2UpLF0kZmVtYWxlX2hoZGVyX2FnZSAtIDQwDQogIGRmWyFpcy5uYShkZiRmZW1hbGVfaGhkZXJfYWdlKSxdJGNoaWxkX2hpX2IgPC0gZGZbIWlzLm5hKGRmJGZlbWFsZV9oaGRlcl9hZ2UpLF0kZmVtYWxlX2hoZGVyX2FnZSAtIDE4DQogIA0KICANCiAgZGZbKCFpcy5uYShkZiRtYWxlX2hoZGVyX2FnZSkgJiAhaXMubmEoZGYkZmVtYWxlX2hoZGVyX2FnZSkpLF0kY2hpbGRfbG9fYiA8LSBtYXBwbHkobWF4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZbKCFpcy5uYShkZiRtYWxlX2hoZGVyX2FnZSkgJiAhaXMubmEoZGYkZmVtYWxlX2hoZGVyX2FnZSkpLF0kbWFsZV9oaGRlcl9hZ2UgLSA0OSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmWyghaXMubmEoZGYkbWFsZV9oaGRlcl9hZ2UpICYgIWlzLm5hKGRmJGZlbWFsZV9oaGRlcl9hZ2UpKSxdJGNoaWxkX2xvX2IpDQogIGRmWyghaXMubmEoZGYkbWFsZV9oaGRlcl9hZ2UpICYgIWlzLm5hKGRmJGZlbWFsZV9oaGRlcl9hZ2UpKSxdJGNoaWxkX2hpX2IgPC0gbWFwcGx5KG1pbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmWyghaXMubmEoZGYkbWFsZV9oaGRlcl9hZ2UpICYgIWlzLm5hKGRmJGZlbWFsZV9oaGRlcl9hZ2UpKSxdJG1hbGVfaGhkZXJfYWdlIC0gMTgsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZlsoIWlzLm5hKGRmJG1hbGVfaGhkZXJfYWdlKSAmICFpcy5uYShkZiRmZW1hbGVfaGhkZXJfYWdlKSksXSRjaGlsZF9oaV9iKQ0KICANCiAgZGZbKCFpcy5uYShkZiRtYWxlX2hoZGVyX2FnZSkgJiBpcy5uYShkZiRmZW1hbGVfaGhkZXJfYWdlKSksXSRjaGlsZF9sb19iIDwtIGRmWyghaXMubmEoZGYkbWFsZV9oaGRlcl9hZ2UpICYgaXMubmEoZGYkZmVtYWxlX2hoZGVyX2FnZSkpLF0kbWFsZV9oaGRlcl9hZ2UgLSA0OQ0KICBkZlsoIWlzLm5hKGRmJG1hbGVfaGhkZXJfYWdlKSAmIGlzLm5hKGRmJGZlbWFsZV9oaGRlcl9hZ2UpKSxdJGNoaWxkX2hpX2IgPC0gZGZbKCFpcy5uYShkZiRtYWxlX2hoZGVyX2FnZSkgJiBpcy5uYShkZiRmZW1hbGVfaGhkZXJfYWdlKSksXSRtYWxlX2hoZGVyX2FnZSAtIDE4DQoNCiAgdHRbW2lkeF1dIDwtIGRmDQogICMgcHJpbnQocGFzdGUoaSwiZG9uZSIsc2VwID0gIi0tLS0tLS0tLS0tLS0tLS0iKSkNCn0NCmBgYA0KDQojIyMgQXNzaWduIGNoaWxkID49IDE4DQpgYGB7cn0NCiMgc2V0IHJhbmRvbSBzZWVkIA0Kc2V0LnNlZWQocm1fc2VlZCkNCg0KIyBVc2UgcHJldmlvdXMgdGFibGVzOiBmb28gKGluZGl2aWR1YWwpICYgdHQgKGhvdXNlaG9sZCkNCiMgUG9wdWxhdGUgYnkgY2Vuc3VzIGJsb2NrIGdyb3VwDQoNCmx0X2hodHlwZV90ZW1wIDwtIGMoImgxX21jX3VkcjE4IiwiaDJfbWNfTk8xOCIsImg1X21uc191ZHIxOCIsImg2X21uc19OTzE4X290aGVycyIsImgxMF9mbnNfdWRyMTgiLCJoMTFfZm5zX05PMThfb3RoZXJzIikNCmx0X2FnZV9yYW5nZSA8LSBsaXN0KDE4OjM0LA0KICAgICAgICAgICAgICAgICAgICAgMzU6NjQsDQogICAgICAgICAgICAgICAgICAgICA2NToxMDApDQpsYWJscyA8LSBjKDAsMSwwKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgobHRfZ2VvaWRfYmcpKSB7DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogICMgSW5kaXZpZHVhbCBEYXRhDQogIGRhdGEgPC0gZm9vW1tpZHhdXQ0KICAjIEhvdXNlaG9sZCBEYXRhIA0KICBkZiA8LSB0dFtbaWR4XV0NCiAgIyBDZW5zdXMgZGF0YSANCiAgbTEgPC0gY3NzX292ZXIxOF9pbl9oaCAlPiUgZmlsdGVyKEdFT0lEID09IGlkeCkgJT4lIHNlbGVjdCgiY2hpbGRfaGhtYmVyXzE4XzM0IiwiY2hpbGRfaGhtYmVyXzM1XzY0IiwiY2hpbGRfaGhtYmVyX292ZXI2NCIpDQogIA0KICBmb3IgKHp6IGluIDE6Mykgew0KICAgIGx0X2FnZSA8LSBsdF9hZ2VfcmFuZ2VbW3p6XV0NCiAgICAjIGluIGFnZSByYW5nZSANCiAgICBtMiA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBhZ2UgJWluJSBsdF9hZ2UpICU+JSBucm93KCkNCiAgICBuIDwtIG1pbihtMVsxLHp6XSwgbTIpDQogICAgDQogICAgaWYoIG4+MCApew0KICAgICAgZm9yIChqIGluIDE6bikgew0KICAgICAgICBvbyA9IDANCiAgICAgICAgbl9sb29wID0gMTAwMA0KICAgICAgICB3aGlsZSAob289PTAgJiBuX2xvb3AgPiAwKSB7DQogICAgICAgICAgIyBIb3VzZWhvbGQgaW5mbyAocm93KQ0KICAgICAgICAgIGEgPC0gZGYgJT4lIGZpbHRlcih0eXBlICVpbiUgbHRfaGh0eXBlX3RlbXApICU+JSBzbGljZV9zYW1wbGUobj0xKQ0KICAgICAgICAgICMgQ2hpbGQgaW5mbyAocm93KQ0KICAgICAgICAgIGIgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlICVpbiUgbHRfYWdlKSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICAgICAjIENoZWNrIGlmIGluIHJhbmdlIA0KICAgICAgICAgIG9vIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGN1dChiJGFnZSwgYnJlYWtzID0gYygtOTk5LCBhJGNoaWxkX2xvX2IgLTEsIGEkY2hpbGRfaGlfYiwgOTk5KSwgbGFiZWwgPSBsYWJscykpKQ0KICAgICAgICAgIG5fbG9vcCA9IG5fbG9vcC0xDQogICAgICAgIH0NCiAgICAgICAgDQogICAgICAgIGlmKG5fbG9vcCA8PTApe2JyZWFrfQ0KICAgICAgICAjIFNBVkUgcmVzdWx0IHRvIGRhdGFmcmFtZSANCiAgICAgICAgZGF0YVtkYXRhJGluZF9pZD09IGIkaW5kX2lkLGMoImhoX2lkIiwiaGhfcm9sZSIpXSA8LSBjKGEkaGhfaWQsICJjaGlsZF9vdmVyMTciKQ0KICAgICAgICAjIHByaW50KHBhc3RlKG5hbWVzKG0xKVtbenpdXSwiY2hpbGRfb3ZlcjE3IixqLCBzZXAgPSAiICAiKSkNCiAgICAgIH0NCiAgICB9DQogIH0NCiAgDQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICAjIHByaW50KHBhc3RlKGksImRvbmUiLHNlcCA9ICItLS0tLS0tLS0tLS0tLS0tIikpDQp9DQoNCiMgc2F2ZSByZXN1bHQNCiMgZGF0YSA8LSBleHBvcnRfaW1wX2Rmcyhmb28pDQojIHdyaXRlLmNzdihkYXRhLCJkYXRhLzAxX3N5bnRoZXRpY19wb3B1bGF0aW9uX2RhdGFzZXQvcHJvY2Vzc19zYXZlZF9kYXRhc2V0L1hYX3N0ZXA3X3BvcHVsYXRlX2luZF9jaGlsZF9vdmVyMTcuY3N2IikNCmRmc19pbmQgPC0gZm9vICAgIyBpbmRpdmlkdWFsIA0KZGZzX2hoIDwtIHR0DQpgYGANCg0KIyMjIEFzc2lnbiBjaGlsZCA8MTgNCmBgYHtyfQ0KIyBzZXQgcmFuZG9tIHNlZWQgDQpzZXQuc2VlZChybV9zZWVkKQ0KDQojIFRhYmxlDQpmb28gPC0gZGZzX2luZCAgICMgaW5kaXZpZHVhbCANCnR0IDwtIGRmc19oaCAgIyBob3VzZWhvbGQgDQoNCiMgUG9wdWxhdGUgYnkgY2Vuc3VzIGJsb2NrIGdyb3VwDQpsdF9oaHR5cGVfdGVtcCA8LSBjKCJoMV9tY191ZHIxOCIsImg1X21uc191ZHIxOCIsImgxMF9mbnNfdWRyMTgiKQ0KbGFibHMgPC0gYygwLDEsMCkNCg0KIyBKb2luIGluZGl2aWR1YWwgaW5mbyB0byBob3VzZWhvbGQgDQpmb3IgKGkgaW4gMTpsZW5ndGgobHRfZ2VvaWRfYmcpKSB7DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogICMgSW5kaXZpZHVhbCBEYXRhDQogIGRhdGEgPC0gZm9vW1tpZHhdXQ0KICAjIEhvdXNlaG9sZCBEYXRhIA0KICBkZiA8LSB0dFtbaWR4XV0NCiAgIyBIb3VzZWhvbGQgc2l6ZSANCiAgYSA8LSB0YWJsZShkYXRhJGhoX2lkKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSBzZXRuYW1lcyhvbGQ9IkZyZXEiLCBuZXc9ImhoX3NpemUiKQ0KICBkZiA8LSBsZWZ0X2pvaW4oZGYsIGEsIGJ5PWMoImhoX2lkIiA9IlZhcjEiKSkNCiAgIyBIb3VzZWhvbGQgd2l0aCBjaGlsZCBvdmVyIDE3DQogIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGhoX3JvbGUgPT0gImNoaWxkX292ZXIxNyIpDQogIGIgPC0gdGFibGUoYSRoaF9pZCkgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgc2V0bmFtZXMob2xkPSJGcmVxIiwgbmV3PSJjaGlsZF9vdmVyMTdfY291bnQiKQ0KICANCiAgaWYobnJvdyhhKSA+IDApew0KICAgIGRmIDwtIGxlZnRfam9pbihkZiwgYiwgYnk9YygiaGhfaWQiID0iVmFyMSIpKQ0KICAgIGEgPC0gYVtvcmRlcihhJGFnZSwgZGVjcmVhc2luZyA9IFQpLF0NCiAgICBhIDwtIGFbIWR1cGxpY2F0ZWQoYSRoaF9pZCksXQ0KICAgIA0KICAgIGEkZ3JhbmRfY2hpbGRfbG9fYiA8LSA5OTkNCiAgICBhJGdyYW5kX2NoaWxkX2hpX2IgPC0gLTENCiAgICANCiAgICBhW2EkZ2VuZGVyID09IkZlbWFsZSIsXSRncmFuZF9jaGlsZF9sb19iIDwtIGFbYSRnZW5kZXIgPT0iRmVtYWxlIixdJGFnZSAtIDQwDQogICAgYVthJGdlbmRlciA9PSJGZW1hbGUiLF0kZ3JhbmRfY2hpbGRfaGlfYiA8LSBhW2EkZ2VuZGVyID09IkZlbWFsZSIsXSRhZ2UgLSAxOA0KICAgIGFbYSRnZW5kZXIgPT0iTWFsZSIsXSRncmFuZF9jaGlsZF9sb19iIDwtIGFbYSRnZW5kZXIgPT0iTWFsZSIsXSRhZ2UgLSA0OQ0KICAgIGFbYSRnZW5kZXIgPT0iTWFsZSIsXSRncmFuZF9jaGlsZF9oaV9iIDwtIGFbYSRnZW5kZXIgPT0iTWFsZSIsXSRhZ2UgLSAxOA0KICAgIA0KICAgIGEgPC0gc2V0bmFtZXMoYSwgb2xkPSJhZ2UiLCBuZXc9ImNoaWxkX292ZXIxN19hZ2UiKQ0KICAgIGRmIDwtIGxlZnRfam9pbihkZiwgYVtjKCJoaF9pZCIsImNoaWxkX292ZXIxN19hZ2UiLCJncmFuZF9jaGlsZF9sb19iIiwiZ3JhbmRfY2hpbGRfaGlfYiIpXSwgYnk9YygiaGhfaWQiID0gImhoX2lkIikpDQogICAgDQogICAgZGZbaXMubmEoZGYpXSA8LSAwDQogIH0gZWxzZXsNCiAgICBkZiRjaGlsZF9vdmVyMTdfY291bnQgPC0gMA0KICB9DQoNCiAgdHRbW2lkeF1dIDwtIGRmDQogICMgcHJpbnQocGFzdGUoaSwiZG9uZSIsc2VwID0gIi0tLS0tLS0tLS0tLS0tLS0iKSkNCn0NCg0KIyBBc3NpZ24gY2hpbGQgdWRyIDE4DQoNCmZvciAoaSBpbiAxOmxlbmd0aChsdF9nZW9pZF9iZykpIHsNCiAgaWR4IDwtIGx0X2dlb2lkX2JnW1tpXV0NCiAgIyBJbmRpdmlkdWFsIERhdGENCiAgZGF0YSA8LSBmb29bW2lkeF1dDQogICMgSG91c2Vob2xkIERhdGEgDQogIGRmIDwtIHR0W1tpZHhdXQ0KICAjIC0tLS0tLS0tLS0tLS0NCiAgaGhfbWF4X3NpemUgPSA2DQogIGx0X3RlbXAgPC0gZGYgJT4lIGZpbHRlciggdHlwZSAlaW4lIGx0X2hodHlwZV90ZW1wICYgaGhfc2l6ZSA8PSBoaF9tYXhfc2l6ZSkgJT4lIG5yb3coKQ0KICBuIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA8IDE4KSAlPiUgbnJvdygpDQogIGlmKG4+MCAmIGx0X3RlbXA+MCl7DQogICAgZm9yIChqIGluIDE6bikgew0KICAgICAgb289MCAgICMgd2hpbGUgbG9vcCBzdG9wIGNvbmRpdGlvbiBvbz0xDQogICAgICBvMT0wDQogICAgICBvMj0wDQogICAgICBuX2xvb3AgPSAxMDAwDQogICAgICB3aGlsZShvbz09MCAmIG5fbG9vcCA+IDApew0KICAgICAgICAjIENoaWxkIA0KICAgICAgICBhIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA8IDE4KSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICAgIyBIb3VzZWhvbGQNCiAgICAgICAgYiA8LSBkZiAlPiUgZmlsdGVyKCB0eXBlICVpbiUgbHRfaGh0eXBlX3RlbXAgJiBoaF9zaXplIDw9IGhoX21heF9zaXplKSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgICAgbzEgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoY3V0KGEkYWdlLCBicmVha3MgPSBjKC05OTksIGIkY2hpbGRfbG9fYiAtMSwgYiRjaGlsZF9oaV9iLCA5OTkpLCBsYWJlbCA9IGxhYmxzKSkpDQogICAgICAgIA0KICAgICAgICBpZihiJGNoaWxkX292ZXIxN19jb3VudCA+IDApew0KICAgICAgICAgIG8yIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGN1dChhJGFnZSwgYnJlYWtzID0gYygtOTk5LCBiJGdyYW5kX2NoaWxkX2xvX2IgLTEsIGIkZ3JhbmRfY2hpbGRfaGlfYiwgOTk5KSwgbGFiZWwgPSBsYWJscykpKQ0KICAgICAgICB9DQogICAgICAgIA0KICAgICAgICBvbz1vMStvMg0KICAgICAgICBuX2xvb3AgPSBuX2xvb3AtMQ0KICAgICAgfQ0KICAgICAgDQogICAgICBpZihuX2xvb3AgPD0wKXticmVha30NCiAgICAgICMgU2F2ZSBSZXN1bHQNCiAgICAgIGhoX2lkeCA8LSBiJGhoX2lkDQogICAgICBkZltkZiRoaF9pZCA9PSBoaF9pZHgsXSRoaF9zaXplIDwtIGRmW2RmJGhoX2lkID09IGhoX2lkeCxdJGhoX3NpemUgKyAxDQogICAgICBkYXRhW2RhdGEkaW5kX2lkID09IGEkaW5kX2lkLCBjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhoaF9pZHgsImNoaWxkX29yX2dyYW5kX3VkcjE4IikNCiAgICAgIHByaW50KHBhc3RlKCJjaGlsZF91ZHIxOCAgICIsaiwgc2VwID0gIiAgIikpDQogICAgfQ0KICB9DQoNCiAgZm9vW1tpZHhdXSA8LSBkYXRhDQogIHR0W1tpZHhdXSA8LSBkZg0KICBwcmludChwYXN0ZShpLCJkb25lIixzZXAgPSAiLS0tLS0tLS0tLS0tLS0tLSIpKQ0KfQ0KDQojICMgIyBzYXZlIHJlc3VsdA0KIyBkYXRhIDwtIGV4cG9ydF9pbXBfZGZzKGZvbykNCiMgd3JpdGUuY3N2KGRhdGEsImRhdGEvMDFfc3ludGhldGljX3BvcHVsYXRpb25fZGF0YXNldC9wcm9jZXNzX3NhdmVkX2RhdGFzZXQvWFhfc3RlcDhfcG9wdWxhdGVfaW5kX3VkcjE4X3Jlc3QuY3N2IikNCmRmc19pbmQgPC0gZm9vDQpkZnNfaGggPC0gdHQgICMgaG91c2Vob2xkDQpgYGANCg0KIyMgRmlsbCBUeXBlIDYmMTEgT3RoZXIgcmVsYXRpdmVzDQpgYGB7cn0NCiMgc2V0IHJhbmRvbSBzZWVkIA0Kc2V0LnNlZWQocm1fc2VlZCkNCg0KIyBUYWJsZQ0KZm9vIDwtIGRmc19pbmQgICAjIGluZGl2aWR1YWwgDQp0dCA8LSBkZnNfaGggICMgaG91c2Vob2xkIA0KDQojIEFkZCBvdGhlciByZWxhdGl2ZXMgdG8gaGggdHlwZSA2JjExOiBoNl9tbnNfTk8xOF9vdGhlcnMsIGgxMV9mbnNfTk8xOF9vdGhlcnMgICANCmZvciAoaSBpbiAxOmxlbmd0aChsdF9nZW9pZF9iZykpIHsNCiAgaWR4IDwtIGx0X2dlb2lkX2JnW1tpXV0NCiAgIyBJbmRpdmlkdWFsIERhdGENCiAgZGF0YSA8LSBmb29bW2lkeF1dDQogICMgSG91c2Vob2xkIERhdGEgDQogIGRmIDwtIHR0W1tpZHhdXQ0KICANCiAgIyAtLS0tT05MWSBmb3IgY2hlY2stLS0tLS0tLS0NCiAgIyBhIDwtIHRhYmxlKGRhdGEkaGhfaWQpICU+JSBhcy5kYXRhLmZyYW1lKCkNCiAgIyBkZiA8LSBsZWZ0X2pvaW4oZGYsIGEsIGJ5PWMoImhoX2lkIj0iVmFyMSIpKQ0KICAjIGRmJHogPC0gZGYkRnJlcSAtIGRmJGhoX3NpemUNCiAgIyBwcmludChzdW0oZGYkaGhfc2l6ZSwgbmEucm0gPSBUKSAtIG5yb3coZGF0YVshaXMubmEoZGF0YSRoaF9pZCkgJiBkYXRhJGhoX3JvbGUhPSJpbl9ncSIsXSkpDQogIA0KICAjIC0tLS0gSG91c2hvbGQgd2l0aCBvdGhlciByZWxhdGl2ZXMgYnV0IG9ubHkgaGF2ZSBvbmUgbWVtYmVyIC0tLS0tLS0tLSANCiAgbHRfdGVtcCA8LSBkZiAlPiUgZmlsdGVyKHR5cGUgJWluJSBjKCJoMTFfZm5zX05PMThfb3RoZXJzIiwgImg2X21uc19OTzE4X290aGVycyIpICYgaGhfc2l6ZSA9PTEpICU+JSBwdWxsKGhoX2lkKQ0KICBuIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA+PSAxOCkgJT4lIG5yb3coKQ0KICBuIDwtIG1pbihuLCBsZW5ndGgobHRfdGVtcCkpDQogIGlmKG4+MCl7DQogICAgZm9yIChqIGluIDE6bikgew0KICAgICAgaGhfaWR4IDwtIGx0X3RlbXBbW2pdXQ0KICAgICAgIyByYW5kb21seSBzZWxlY3QgYW4gaW5kaXZpZHVhbCANCiAgICAgIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49IDE4KSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgIGRhdGFbZGF0YSRpbmRfaWQ9PWEkaW5kX2lkLCBjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhoaF9pZHgsIm90aGVyX3JlbGF0aXZlcyIpDQogICAgfQ0KICAgIA0KICAgIA0KICB9DQogIA0KICAjIC0tLS0tIE5vbiBmYW1pbHkgaG91c2Vob2xkOiBNYWxlIC0tLS0tLS0NCiAgbHRfdGVtcCA8LSBkZiAlPiUgZmlsdGVyKHR5cGUgPT0gImg3X21uc19ub25mYW1pbHkiKSAlPiUgcHVsbChoaF9pZCkNCiAgbiA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBhZ2UgPj0gMTggJiBnZW5kZXIgPT0gIk1hbGUiKSAlPiUgbnJvdygpDQogIG4gPC0gbWluKG4sIGxlbmd0aChsdF90ZW1wKSkNCiAgaWYobj4wKXsNCiAgICBmb3IgKGogaW4gMTpuKSB7DQogICAgICBoaF9pZHggPC0gbHRfdGVtcFtbal1dDQogICAgICBhIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSAmIGFnZSA+PSAxOCAmIGdlbmRlciA9PSAiTWFsZSIpICU+JSBzbGljZV9zYW1wbGUobj0xKQ0KICAgICAgZGF0YVtkYXRhJGluZF9pZD09YSRpbmRfaWQsIGMoImhoX2lkIiwiaGhfcm9sZSIpXSA8LSBjKGhoX2lkeCwibW5zX25vbl9mYW1pbHkiKQ0KICAgICAgDQogICAgfQ0KICB9DQogIA0KICAjIC0tLS0tIE5vbiBmYW1pbHkgaG91c2Vob2xkOiBGZW1hbGUgLS0tLS0tLQ0KICBsdF90ZW1wIDwtIGRmICU+JSBmaWx0ZXIodHlwZSA9PSAiaDEyX2Zuc19ub25mYW1pbHkiKSAlPiUgcHVsbChoaF9pZCkNCiAgbiA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkgJiBhZ2UgPj0gMTggJiBnZW5kZXIgPT0gIkZlbWFsZSIpICU+JSBucm93KCkNCiAgbiA8LSBtaW4obiwgbGVuZ3RoKGx0X3RlbXApKQ0KICBpZihuPjApew0KICAgIGZvciAoaiBpbiAxOm4pIHsNCiAgICAgIGhoX2lkeCA8LSBsdF90ZW1wW1tqXV0NCiAgICAgIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpICYgYWdlID49IDE4ICYgZ2VuZGVyID09ICJGZW1hbGUiKSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkNCiAgICAgIGRhdGFbZGF0YSRpbmRfaWQ9PWEkaW5kX2lkLCBjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhoaF9pZHgsImZuc19ub25fZmFtaWx5IikNCiAgICAgIA0KICAgIH0NCiAgfQ0KICANCiAgIyBSYW5kb21seSBhc3NpZ24gMSBub24tZmFtaWx5IG1lbWJlcnMNCiAgbSA8LSBkYXRhICU+JSBmaWx0ZXIoaGhfcm9sZSAlaW4lIGMoImZuc19ub25fZmFtaWx5IiwibW5zX25vbl9mYW1pbHkiKSkgJT4lIG5yb3coKQ0KICBuIDwtIGRhdGEgJT4lIGZpbHRlcihpcy5uYShoaF9yb2xlKSkgJT4lIG5yb3coKQ0KICBuIDwtIG1pbihtLCBuKQ0KICANCiAgaWYobiA+MCl7DQogICAgbHRfdGVtcCA8LSBkYXRhICU+JSBmaWx0ZXIoaGhfcm9sZSAlaW4lIGMoImZuc19ub25fZmFtaWx5IiwibW5zX25vbl9mYW1pbHkiKSkgJT4lIHNsaWNlX3NhbXBsZShuPW4pICU+JSBwdWxsKGhoX2lkKQ0KICAgIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpKSAlPiUgc2xpY2Vfc2FtcGxlKG49bikgJT4lIHB1bGwoaW5kX2lkKQ0KICAgIGRhdGFbZGF0YSRpbmRfaWQgJWluJSBhLF0kaGhfaWQgPC0gbHRfdGVtcA0KICAgIGRhdGFbZGF0YSRpbmRfaWQgJWluJSBhLF0kaGhfcm9sZSA8LSAibm9uX2ZhbWlseV9tZW1iZXIiDQogICAgDQogIH0NCiAgZm9vW1tpZHhdXSA8LSBkYXRhDQogIHByaW50KHBhc3RlKGksImRvbmUiLHNlcCA9ICItLS0tLS0tLS0tLS0tLS0tIikpDQp9DQoNCiMgUmFuZG9tbHkgYXNzaWduIHRoZSByZXN0IGluZGl2aWR1YWxzIA0KDQpmb3IgKGkgaW4gMTpsZW5ndGgobHRfZ2VvaWRfYmcpKSB7DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogICMgSW5kaXZpZHVhbCBEYXRhDQogIGRhdGEgPC0gZm9vW1tpZHhdXQ0KICAjIEhvdXNlaG9sZCBEYXRhIA0KICBkZiA8LSB0dFtbaWR4XV0NCiAgIyAtLS0tLSByZXN0IG1lbWJlcnMgLS0tLS0tLS0NCiAgYSA8LSB0YWJsZShkYXRhJGhoX2lkKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQogIGRmIDwtIGxlZnRfam9pbihkZiwgYSwgYnk9YygiaGhfaWQiPSJWYXIxIikpDQogIGRmJGhoX3NpemUgPC0gZGYkRnJlcQ0KICANCiAgZGZbaXMubmEoZGYpXSA8LSAwDQogIGRmIDwtIGRmW2RmJGhoX3NpemUgPiAwLF0NCiAgDQogICMgdW5hc3NpZ25lZCBpbmRpdmlkdWFscyANCiAgbiA8LSBkYXRhICU+JSBmaWx0ZXIoaXMubmEoaGhfcm9sZSkpICU+JSBucm93KCkNCiAgaWYobiA+IDApew0KICAgIGZvciAoaiBpbiAxOm4pIHsNCiAgICAgIGEgPC0gZGF0YSAlPiUgZmlsdGVyKGlzLm5hKGhoX3JvbGUpKSAlPiUgc2xpY2Vfc2FtcGxlKG49MSkgJT4lIHB1bGwoaW5kX2lkKQ0KICAgICAgbHRfdGVtcCA8LSBkZiAlPiUgZmlsdGVyKCF0eXBlICVpbiUgYygiaDNfbW5zX2Fsb25lX2xlc3M2NSIsImg0X21uc19hbG9uZV9vdmVyNjQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaDhfZm5zX2Fsb25lX2xlc3M2NSIsImg5X2Zuc19hbG9uZV9vdmVyNjQiKSAmIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGhfc2l6ZSA8IDcpICU+JSBzbGljZV9zYW1wbGUobj0xKSAlPiUgcHVsbChoaF9pZCkNCiAgICAgIGRhdGFbZGF0YSRpbmRfaWQgPT0gYSxjKCJoaF9pZCIsImhoX3JvbGUiKV0gPC0gYyhsdF90ZW1wLCAib3RoZXJfbWVtYmVycyIpDQogICAgICBkZltkZiRoaF9pZCA9PSBsdF90ZW1wLF0kaGhfc2l6ZSA8LSBkZltkZiRoaF9pZCA9PSBsdF90ZW1wLF0kaGhfc2l6ZSArIDENCiAgICB9DQogIH0NCiAgDQogIGZvb1tbaWR4XV0gPC0gZGF0YQ0KICBwcmludChwYXN0ZShpLCJkb25lIixzZXAgPSAiLS0tLS0tLS0tLS0tLS0tLSIpKQ0KfQ0KDQoNCg0KDQojICMgIyBzYXZlIHJlc3VsdA0KIyBkYXRhIDwtIGV4cG9ydF9pbXBfZGZzKGZvbykNCiMgd3JpdGUuY3N2KGRhdGEsImRhdGEvMDFfc3ludGhldGljX3BvcHVsYXRpb25fZGF0YXNldC9wcm9jZXNzX3NhdmVkX2RhdGFzZXQvWFhfc3RlcDlfcG9wdWxhdGVfaW5kX3R5cGU2XzdfMTFfMTJfb3RoZXJfcmVsYXRpdmVzX25vbl9mYW1pbHkuY3N2IikNCg0KZGZzX2luZCA8LSBmb28NCmRmc19oaCA8LSB0dCAgIyBob3VzZWhvbGQNCmBgYA0KDQojIyBVcGRhdGUgaG91c2Vob2xkIHNpemUgDQpgYGB7cn0NCiMgVGFibGUNCmZvbyA8LSBkZnNfaW5kICAgIyBpbmRpdmlkdWFsIA0KdHQgPC0gZGZzX2hoICAjIGhvdXNlaG9sZCANCg0KIyAxIC0tIEZvciBMT09QDQpmb3IgKGkgaW4gMTpsZW5ndGgobHRfZ2VvaWRfYmcpKSB7DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogICMgSW5kaXZpZHVhbCBEYXRhDQogIGRhdGEgPC0gZm9vW1tpZHhdXQ0KICAjIEhvdXNlaG9sZCBEYXRhIA0KICBkZiA8LSB0dFtbaWR4XV0NCiAgIyAtLS0tLS0tLS0tLS0tIHVwZGF0ZSBob3VzZWhvbGQgc2l6ZSArIGFkZCBnZW9pZA0KICBhIDwtIHRhYmxlKGRhdGEkaGhfaWQpICU+JSBhcy5kYXRhLmZyYW1lKCkNCiAgZGYgPC0gbGVmdF9qb2luKGRmLCBhLCBieT1jKCJoaF9pZCI9IlZhcjEiKSkNCiAgZGYkaGhfc2l6ZSA8LSBkZiRGcmVxDQogIGRmJEdFT0lEIDwtIGlkeA0KICBkZiA8LSBkZltjKCJHRU9JRCIsImhoX2lkIiwidHlwZSIsImhoX3NpemUiKV0NCiAgZGZbaXMubmEoZGYpXSA8LSAwDQogIGRmIDwtIGRmW2RmJGhoX3NpemUgPiAwLF0NCiAgDQogICMgLS0tLS0tLS0tLS0tLSBpbmRpdmlkdWFsIGRmICsgYWRkIGdlb2lkDQogIGRhdGEkR0VPSUQgPC0gaWR4DQogIA0KICBmb29bW2lkeF1dIDwtIGRhdGENCiAgdHRbW2lkeF1dIDwtIGRmDQogIHByaW50KHBhc3RlKGksImRvbmUiLHNlcCA9ICItLS0tLS0tLS0tLS0tLS0tIikpDQp9DQoNCmZpbmxfZGZzX2luZCA8LSBmb28NCmZpbmxfZGZzX2hoIDwtIHR0DQpgYGANCg0KIyBTQVZFICYgRVhQT1JUIA0KYGBge3J9DQojIEluZGl2aWR1YWwgDQphIDwtIGV4cG9ydF9pbXBfZGZzKGZpbmxfZGZzX2luZCkNCiMgSG91c2Vob2xkIA0KYiA8LSBleHBvcnRfaW1wX2RmcyhmaW5sX2Rmc19oaCkNCg0Kd3JpdGUuY3N2KGEsImRhdGEvMDFfc3ludGhldGljX3BvcHVsYXRpb25fZGF0YXNldC9wcm9jZXNzX3NhdmVkX2RhdGFzZXQvWFhfZmluYWxfc3ludGhlc2l6ZWRfaW5kaXZpZHVhbC5jc3YiLCByb3cubmFtZXMgPSBGKQ0Kd3JpdGUuY3N2KGIsImRhdGEvMDFfc3ludGhldGljX3BvcHVsYXRpb25fZGF0YXNldC9wcm9jZXNzX3NhdmVkX2RhdGFzZXQvWFhfZmluYWxfc3ludGhlc2l6ZWRfaG91c2Vob2xkLmNzdiIsIHJvdy5uYW1lcyA9IEYpDQpgYGANCg0KDQoNCg0KDQojIFZhbGlkYXRpb24NCiMjIFYgLSBIb3VzZWhvbGQNCmBgYHtyfQ0KZGZfY2hpc3EgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IDIpKSAlPiUgc2V0bmFtZXMobmV3ID0gYygiR0VPSUQiLCJjaGlzcV9oaCIpKQ0KZm9vIDwtIGZpbmxfZGZzX2luZA0KdHQgPC0gZmlubF9kZnNfaGgNCg0KIyAxIC0tIEZvciBMT09QDQpmb3IgKGkgaW4gMTpsZW5ndGgobHRfZ2VvaWRfYmcpKSB7DQogIGlkeCA8LSBsdF9nZW9pZF9iZ1tbaV1dDQogICMgSW5kaXZpZHVhbCBEYXRhDQogIGRhdGEgPC0gZm9vW1tpZHhdXQ0KICAjIEhvdXNlaG9sZCBEYXRhIA0KICBkZiA8LSB0dFtbaWR4XV0NCiAgIyAtLS0tLS0tLS0tLS0tDQogICMgY2Vuc3VzIGRhdGEgDQogIGEgPC0gY3NzX2hoX3R5cGVfZm5sICU+JSBmaWx0ZXIoR0VPSUQgPT0gaWR4KSAlPiUgc2VsZWN0KGMoMjI6MzMpKSAlPiUgDQogICAgZ2F0aGVyKGtleT0idHlwZSIsIHZhbHVlPSJjb3VudCIpDQogIGIgPC0gdGFibGUoZGYkdHlwZSkgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgc2V0bmFtZXMob2xkPSJGcmVxIiwgbmV3PSJzaW11X2NvdW50IikNCiAgYSA8LSBsZWZ0X2pvaW4oYSwgYiwgYnk9YygidHlwZSI9IlZhcjEiKSkNCiAgYVtpcy5uYShhKV0gPC0gMA0KICANCiAgYyA8LSBzdW0oKGEkc2ltdV9jb3VudCAtIGEkY291bnQpKioyIC8gYSRzaW11X2NvdW50LCBuYS5ybSA9IFQpDQogIGRmX2NoaXNxWzErbnJvdyhkZl9jaGlzcSksYygiR0VPSUQiLCJjaGlzcV9oaCIpXSA8LSBjKGlkeCwgYykNCiAgDQogIHByaW50KHBhc3RlKGksImRvbmUiLHNlcCA9ICItLS0tLS0tLS0tLS0tLS0tIikpDQp9DQoNCg0KZGF0YSA8LSBkZl9jaGlzcVsoZGZfY2hpc3EkY2hpc3FfaGghPSJJbmYiICYgIWlzLm5hKGRmX2NoaXNxJGNoaXNxX2hoKSksXQ0KZGF0YSRjaGlzcV9oaCA8LSBhcy5udW1lcmljKGRhdGEkY2hpc3FfaGgpDQpnZ3Bsb3QoZGF0YSwgYWVzKHg9Y2hpc3FfaGgpKSArIGdlb21fZGVuc2l0eSgpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KZGYgPC0gZGF0YS5mcmFtZShtYXRyaXgobmNvbCA9IDEwKSkgJT4lIHNldG5hbWVzKG5ldyA9IGMoIkdFT0lEIiwic19oMTBfZm5zX3VkcjE4Iiwic19oNV9tbnNfdWRyMTgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic19oOV9mbnNfYWxvbmVfb3ZlcjY0Iiwic19oNF9tbnNfYWxvbmVfb3ZlcjY0Iiwic19oMl9tY19OTzE4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNfaDNfbW5zX2Fsb25lX2xlc3M2NSIsInNfaDhfZm5zX2Fsb25lX2xlc3M2NSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzX2g2X21uc19OTzE4X290aGVycyIsInNfaDExX2Zuc19OTzE4X290aGVycyIpKSANCg0KZGF0YSA8LSBmb28NCmZvciAoaSBpbiAxOmxlbmd0aChsdF9nZW9pZF9iZykpIHsNCiAgaWR4IDwtIGx0X2dlb2lkX2JnW1tpXV0NCiAgZGZbaSxdIDwtIGMoDQogICAgaWR4LA0KICAgIGRhdGFbW2lkeF1dICU+JSBmaWx0ZXIoaGhfcm9sZT09InNpbmdsZV9tb20iKSAlPiUgbnJvdygpLA0KICAgIGRhdGFbW2lkeF1dICU+JSBmaWx0ZXIoaGhfcm9sZT09InNpbmdsZV9kYWQiKSAlPiUgbnJvdygpLA0KICAgIGRhdGFbW2lkeF1dICU+JSBmaWx0ZXIoaGhfcm9sZT09ImZlbWFsZV9vbGRlcnNpbmdsZXRvbiIpICU+JSBucm93KCksDQogICAgZGF0YVtbaWR4XV0gJT4lIGZpbHRlcihoaF9yb2xlPT0ibWFsZV9vbGRlcnNpbmdsZXRvbiIpICU+JSBucm93KCksDQogICAgZGF0YVtbaWR4XV0gJT4lIGZpbHRlcihoaF9yb2xlPT0iaHVzYmFuZF9OT191ZHIxOCIpICU+JSBucm93KCksDQogICAgZGF0YVtbaWR4XV0gJT4lIGZpbHRlcihoaF9yb2xlPT0ibW5zX2Fsb25lX2xlc3M2NSIpICU+JSBucm93KCksDQogICAgZGF0YVtbaWR4XV0gJT4lIGZpbHRlcihoaF9yb2xlPT0iZm5zX2Fsb25lX2xlc3M2NSIpICU+JSBucm93KCksDQogICAgZGF0YVtbaWR4XV0gJT4lIGZpbHRlcihoaF9yb2xlPT0ibW5zX25vMThfb3RoZXJfcmVsYXRpdmUiKSAlPiUgbnJvdygpLA0KICAgIGRhdGFbW2lkeF1dICU+JSBmaWx0ZXIoaGhfcm9sZT09ImZuc19ubzE4X290aGVyX3JlbGF0aXZlIikgJT4lIG5yb3coKQ0KICApDQp9DQoNCmRmWywyOm5jb2woZGYpXSA8LSBzYXBwbHkoZGZbLDI6bmNvbChkZildLCBhcy5udW1lcmljKSAlPiUgYXMuZGF0YS5mcmFtZSgpDQpkZiA8LSBsZWZ0X2pvaW4oZGYsIGNzc19oaF90eXBlX2ZubFssYygxLDIyOjMzKV0sIGJ5PWMoIkdFT0lEIj0iR0VPSUQiKSkNCg0KIyBDSEVLQyANCmRmJHNfaDEwX2Zuc191ZHIxOCAtIGRmJGgxMF9mbnNfdWRyMTgNCmRmJHNfaDVfbW5zX3VkcjE4IC0gZGYkaDVfbW5zX3VkcjE4DQpkZiRzX2g5X2Zuc19hbG9uZV9vdmVyNjQgLSBkZiRoOV9mbnNfYWxvbmVfb3ZlcjY0DQpkZiRzX2g0X21uc19hbG9uZV9vdmVyNjQgLSBkZiRoNF9tbnNfYWxvbmVfb3ZlcjY0DQpkZiRzX2gyX21jX05PMTggLSBkZiRoMl9tY19OTzE4DQpkZiRzX2gzX21uc19hbG9uZV9sZXNzNjUgLSBkZiRoM19tbnNfYWxvbmVfbGVzczY1DQpkZiRzX2g4X2Zuc19hbG9uZV9sZXNzNjUgLSBkZiRoOF9mbnNfYWxvbmVfbGVzczY1DQpkZiRzX2g2X21uc19OTzE4X290aGVycyAtIGRmJGg2X21uc19OTzE4X290aGVycw0KZGYkc19oMTFfZm5zX05PMThfb3RoZXJzIC0gZGYkaDExX2Zuc19OTzE4X290aGVycw0KDQpgYGANCg0K