LIBRARY

# Basic Packages
library(sp) # Classes and Methods for Spatial Data.
library(rgdal)  # for vector work; sp package should always load with rgdal. ]
library(sf) # Simple Features for R, st_as_sf
library (raster)   # for metadata/attributes- vectors or rasters
library(dplyr)    # mutate, left_join
library(tidyverse) # tidy data 
library(data.table) # setnames
library(plyr)
library(igraph) # network analysis
library(tmap)
library(spatstat) # analysis of spatial point patterns,  ‘ppp’ (point pattern) object
library(maptools) # coerce SpatialPolygons into an ‘owin: observ window’ object
library(spdep) # local moran's I, nb2listw, 
library(rgeos)
library(magrittr)  # %>%
library(reshape2)  # dcast, cast category variables to 1/0
# STATISTIC
library(limSolve) # https://search.r-project.org/CRAN/refmans/limSolve/html/lsei.html 
library(GGally)       #correlation diagram  
# PLT
library(ggplot2)
library(corrplot)
library(htmlwidgets)
library(shinyjs)
library(contoureR)
library(geometry)
library(tmaptools)
library(RColorBrewer) # for color selection
library(hrbrthemes) # theme
library(ggbreak)     # break x/y axis     
library(ggpubr)
library(viridis)

# NETWORK 
library(igraph)

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

SET UP

# Random Seed
rm_seed <- 315
set.seed(rm_seed)
# prepare index 
lt_geoid_bg <- idx_cbgroup$GEOID
lt_geoid_bg <- lt_geoid_bg[lt_geoid_bg!="360139900000"]

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

SAVE & EXPORT

# Individual 
a <- export_imp_dfs(finl_dfs_ind)
# Household 
b <- export_imp_dfs(finl_dfs_hh)

write.csv(a,"data/01_synthetic_population_dataset/process_saved_dataset/XX_final_synthesized_individual.csv", row.names = F)
write.csv(b,"data/01_synthetic_population_dataset/process_saved_dataset/XX_final_synthesized_household.csv", row.names = F)

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