I. POLICE SHOOTING DATA ———————————

A. Load Libraries

#library(Hmisc)
library(dplyr)
library(ggmap)
library(readr)

B. Functions

1. getStateName

This function is just a way to convert state names back and forth using base R functions, but includes washington dc and puerto rico.

getState <- function(x){
  ##remove punctuation and twim white space, convert to lower case
  x <- tolower(trimws(gsub("[[:punct:]]", "", x)))
  x[which(x == "washington dc")] <- "district of columbia"
  
  states.abb <- c(state.abb, "DC", "DC", "PR")
  states.name <- c(state.name, "District of Columbia", "District of Columbia", "Puerto Rico")
  
  m.abb <- tolower(states.abb)
  m.name <- tolower(gsub("[[:punct:]]", "", states.name))
  
  ##automatically decide to convert from names to states or vice versa based on majority match
  if(sum(x %in% m.abb) > sum(x %in% m.name)){
    #convert abbreviations to names
    y <- states.name[match(x,m.abb)]
  } else {
    y <- states.abb[match(x,m.name)]
  }
   return(y)
}
##returns abbreviations only
getState.abb <- function(x){
  ##remove punctuation and twim white space, convert to lower case
  x <- tolower(trimws(gsub("[[:punct:]]", "", x)))
  x[which(x == "washington dc")] <- "district of columbia"
  
  states.abb <- c(state.abb, "DC", "DC", "PR")
  states.name <- c(state.name, "District of Columbia", "District of Columbia", "Puerto Rico")
  
  m.abb <- tolower(states.abb)
  m.name <- tolower(gsub("[[:punct:]]", "", states.name))
  
    x[which(x %in% m.abb)] <- states.abb[match(x[which(x %in% m.abb)] ,m.abb)]
    x[which(x %in% m.name)] <- states.abb[match(x[which(x %in% m.name)],m.name)]
  return(x)
}
##returns Names only
getState.names <- function(x){
  ##remove punctuation and twim white space, convert to lower case
  x <- tolower(trimws(gsub("[[:punct:]]", "", x)))
  x[which(x == "washington dc")] <- "district of columbia"
  
  states.abb <- c(state.abb, "DC", "DC", "PR")
  states.name <- c(state.name, "District of Columbia", "District of Columbia", "Puerto Rico")
  
  m.abb <- tolower(states.abb)
  m.name <- tolower(gsub("[[:punct:]]", "", states.name))
  
  x[which(x %in% m.abb)] <- states.name[match(x[which(x %in% m.abb)] ,m.abb)]
  x[which(x %in% m.name)] <- states.name[match(x[which(x %in% m.name)],m.name)]
  
  return(x)
}

2. Get FIPS

getFIPS <- function(df, cityVar="city", stateVar="State", countyVar="county", addressVar = "address"){
  require(tibble)
  require(readr)
  require(dplyr)
  require(ggmap)
  require(noncensus)
  setwd("createData")
#PART I - LOAD 3 DATA SETS    
  data(counties)
  counties <- sapply(counties, as.character) %>% tibble::as_data_frame()
  counties$FIPS <- paste0("`", as.character(counties$state_fips), as.character(counties$county_fips))
  counties$county_lower <- counties$county_name
  counties$county_lower  = tolower(trimws(gsub("[[:punct:]]", "", counties$county_lower)))
  counties$county_lower= gsub(" county| parish| borough", "", counties$county_lower, fixed = TRUE)
geoCode <- readr::read_tsv("35158-0001-Data.tsv") %>% 
  dplyr::mutate(
    State =  getState.abb(STATENAME),
    city_lower = ADDRESS_CITY,
    city_lower = gsub("st. ", "saint ", trimws(tolower(city_lower)), fixed = TRUE),
    city_lower = gsub("mt. ", "mount ", trimws(tolower(city_lower)), fixed = TRUE),
    city_lower = tolower(as.character(trimws(gsub("[[:punct:]]", "", city_lower)))),
    county_lower = tolower(as.character(trimws(gsub("[[:punct:]]", "", COUNTYNAME)))),
    FIPS = paste("`", FIPS, sep="")
  )
charNums <- c("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
geo_city <- readr::read_delim(file="POP_PLACES_20170601.txt", delim="|") %>% 
  dplyr::mutate(
    FIPS = paste0("`", STATE_NUMERIC, COUNTY_NUMERIC),
    city_lower1 = tolower(as.character(trimws(gsub("[[:punct:]]", "", FEATURE_NAME)))),
    city_lower2 = tolower(as.character(trimws(gsub("[[:punct:]]", "", MAP_NAME  )))),
    ##trim last 3 characters, consisting of a letter-number, e.g. D-3
    city_lower2 = ifelse(substring(city_lower2, nchar(city_lower2), nchar(city_lower2)) %in% charNums,
                         trimws(substr(city_lower2, 1, nchar(city_lower2)-3)),
                         city_lower2),
    county_lower = tolower(as.character(trimws(gsub("[[:punct:]]", "", COUNTY_NAME)))),
    county_lower =  ifelse(substring(county_lower, nchar(county_lower)-2, nchar(county_lower)) == " ca",
                           trimws(substr(county_lower, 1, nchar(county_lower)-3)),
                           county_lower)
  )
#PART II.  Load Data
if(cityVar %in% names(df) == FALSE){df[,cityVar] <- NA}
if(stateVar %in% names(df) == FALSE){df[,stateVar] <- NA}
if(addressVar %in% names(df) == FALSE){df[,addressVar] <- NA}
if(countyVar %in% names(df) == FALSE){df[,countyVar] <- NA}
if("FIPS" %in% names(df) == FALSE){df$FIPS <- NA}
#PART III.  Search Using Existing Datasets
scan4fips <- function(df_a, cityVar_a=cityVar, stateVar_a=stateVar, countyVar_a=countyVar){
#step 1 - identify counties if they are already labelled using noncensus counties file
city_vector <- df_a[,cityVar_a] %>% unlist() %>% as.character() %>% trimws() 
county_vector <- df_a[,countyVar_a] %>% unlist() %>% as.character() %>% trimws() 
  
county_index <- which(grepl(" county| parish| borough", city_vector, 
                            ignore.case = TRUE, fixed = FALSE) & is.na(county_vector))
##If "city" has "county" etc., in its title, move it to county column  
df_a[county_index,countyVar_a] <- df_a[county_index,cityVar_a]
for(i in which(is.na(df_a$FIPS) & !is.na(df_a[,countyVar_a]))){
  st <- df_a[[i,stateVar_a]]
  cnty <- df_a[[i,countyVar_a]]
  fips <- unique(counties$FIPS[which(counties$state == st & counties$county_name == cnty)])
  if(length(fips) == 1 & !is.null(fips)){
  if(!is.na(fips) & fips != "NULL") {
    df_a$FIPS[[i]] <- fips
  }} else {
  county_lower = cnty
  county_lower = tolower(trimws(gsub("[[:punct:]]", "", cnty)))
  county_lower = gsub(" county| parish| borough", "", county_lower, fixed = TRUE)
  
  if(length(fips) == 1 & !is.null(fips)){
  if(!is.na(fips) & fips != "NULL") {df_a$FIPS[[i]] <- fips}} else {
      fips1 <- (geo_city$FIPS[which(geo_city$county_lower == county_lower & geo_city$STATE_ALPHA == st)])
      fips2 <- (geoCode$FIPS[which(geoCode$State ==st & geoCode$county_lower== county_lower)])
    new_fips <- names(sort(table(c(fips, fips1, fips2)), decreasing=TRUE)[1])
    if(length(new_fips) == 1 & !is.null(new_fips)){
    if(!is.na(new_fips) & new_fips != "NULL"){df_a$FIPS[[i]] <- new_fips}}
  }
  } 
}
  
#step 2 - Use city/location
for(i in which(is.na(df_a$FIPS) & !is.na(df_a[,cityVar_a]))){
  st <- df_a[[i,stateVar_a]]
  i_city <- df_a[[i,cityVar_a]]
  city_lower = tolower(trimws(gsub("[[:punct:]]", "", i_city)))
  new_fips <- unique(geo_city$FIPS[which(geo_city$city_lower1 == city_lower & geo_city$STATE_ALPHA == st)])
    df_a$FIPS[[i]] <- new_fips}} else {
      
  new_fips <-  unique(geoCode$FIPS[which(geoCode$State == st & geoCode$city_lower==city_lower)])
      df_a$FIPS[[i]] <- new_fips}} else {
        
    new_fips <-  unique(geo_city$FIPS[which(geo_city$city_lower2 == city_lower & geo_city$STATE_ALPHA == st)])
        if(!is.na(new_fips) & new_fips != "NULL"){
            df_a$FIPS[[i]] <- new_fips}} else {
  
  city_lower = gsub("Mt |mt. ", "mount ", trimws(i_city), fixed = TRUE)
  city_lower = gsub(" county| parish| charter township| township", "", city_lower, fixed = TRUE)
  city_lower = ifelse(city_lower %in% c("coney island", "brooklyn", "manhattan", 
  city_lower = ifelse(st == "DC", "washington", city_lower)
  fips1 <- unique(geo_city$FIPS[which(geo_city$city_lower1 == city_lower & geo_city$STATE_ALPHA == st)])
  fips3 <- unique(geo_city$FIPS[which(geo_city$county_lower == city_lower & geo_city$STATE_ALPHA == st)])
  new_fips <- names(sort(table(c(fips1, fips2, fips3, fips4, fips5)), decreasing=TRUE)[1])
  
  if(length(new_fips) == 1 & !is.null(new_fips)){
  return(df_a)
#PART IV. SEARCH USING GOOGLE MAPS
#After running scan, search for remaining missing cases using google
search4FIPS <- function(df_b, addressVar_b=addressVar, countyVar_b=countyVar){
  df_names <- names(df_b)
  fips.na <- df_b[index,]
  address_vector <- fips.na[,addressVar_b] %>% unlist() 
  #names(fips_geo)[a_n] <- "address_google"  #deleting duplicate variable name, causing errors
  df_b[index,countyVar_b] <- as.character(fips_geo$administrative_area_level_2)
missing_fips <- length(df$FIPS[which(is.na(df$FIPS))])
message(paste0("Initial Missing FIPS:  ", missing_fips))
missing_fips <- length(dfa$FIPS[which(is.na(dfa$FIPS))])
message(paste0("Missing FIPS after Step 1:  ", missing_fips))
dfc <- scan4fips(dfb)
missing_fips <- length(dfc$FIPS[which(is.na(dfc$FIPS))])
return(dfc)
}

C. Load Washington Post Data

wapo <- read_csv("https://cdn.rawgit.com/washingtonpost/data-police-shootings/master/fatal-police-shootings-data.csv") %>% 
  mutate(address = paste(city, state, "USA", sep=", ")) %>% 
  dplyr::rename(Weapon=armed, Race=race, mental_illness=signs_of_mental_illness) %>% 
  dplyr::mutate(
    year=as.numeric(format(date,"%Y")),
    age_f= cut(age, breaks=c(0, 14, 19, 39, 200), 
                    right= FALSE, labels=c("AgeUnder15", "Age15_19", "Age20_39", "Age40Above")), 
         
    Race=replace(Race, which(Race=="W"), "White"),
         Race=replace(Race, which(Race=="B"), "Black"),
         Race=replace(Race, which(Race=="H"), "Hispanic"),
         Race=replace(Race, which(Race=="A"), "Asian"),
         Race=replace(Race, which(Race=="N"), "Native American"),
          Race=replace(Race, which(Race=="O"), "Other"),
         gender=replace(gender, which(gender=="M"), "Male"),
         gender=replace(gender, which(gender=="F"), "Female"),
         State =  getState.abb(state),     
         mental_illness=replace(mental_illness, 
                                which(mental_illness=="True"), 
                                "Mentally Ill"),
         mental_illness=replace(mental_illness, 
                                which(mental_illness=="False"), 
                                "Not Mentally Ill/Unknown"),
         body_camera=replace(body_camera, 
                             which(body_camera=="False"), "No BodyCam"),
         body_camera=replace(body_camera, 
                             which(body_camera=="True"), "BodyCam"),
    dataSource="Wapo") %>% 
  dplyr::mutate(
    date=as.character(date)
  )
  

D. Load Lott & Moody (2016)

#setwd("createData")
lott <- haven::read_stata("createData/police.shoot.dta") %>%  
  mutate_all( funs(replace(., is.nan(.), NA))) %>% 
  dplyr::mutate(
    OfficerRace = NA,
    OfficerRace = replace(OfficerRace, which(pw==1), "White"),
    OfficerRace = replace(OfficerRace, which(ph==1), "Hispanic"),
    OfficerRace = replace(OfficerRace, which(pb==1), "Black"),
    OfficerRace = replace(OfficerRace, which(pu==1), "Unknown"),
    OfficerRace = replace(OfficerRace, which(po==1), "Other"),
    Officer2Race = NA,
    Officer2Race = replace(Officer2Race, which(officer2race==1), "White"),
    Officer2Race = replace(Officer2Race, which(officer2race==3), "Hispanic"),
    Officer2Race = replace(Officer2Race, which(officer2race==2), "Black"),
    Officer2Race = replace(Officer2Race, which(officer2race==4), "Asian/Pacific Islander"),
    OfficerSex = NA,
    OfficerSex = replace(OfficerSex, which(officer1gender==1), "Male"),
    OfficerSex = replace(OfficerSex, which(officer1gender==0), "Female"),
    Officer2Sex = NA,
    Officer2Sex = replace(Officer2Sex, which(officer2gender==1), "Male"),
    Officer2Sex = replace(Officer2Sex, which(officer2gender==0), "Female"),
    Race = NA,
    Race = replace(Race, which(offender1race == 1), "White"),
    Race = replace(Race, which(offender1race == 2), "Black"),
    Race = replace(Race, which(offender1race == 3), "Hispanic"),
    Race = replace(Race, which(offender1race == 4), "Asian/Pacific Islander"),
    Race = replace(Race, which(offender1race == 5), "Native American"),
    Race = replace(Race, which(offender1race == 6), "Other")
  ) %>% 
                -pf, -pw, -ph, -pb, -pu, -po, -offender1race, 
                -officer1gender, -officer2gender, -officer2race) %>% 
dplyr::mutate(
  suicidal = replace(suicidal, which(suicidal == 0), "False"),
  suicidal = replace(suicidal, which(suicidal == 1), "True"),
  drugrelated = replace(drugrelated, which(drugrelated == 0), "False"),
  drugrelated = replace(drugrelated, which(drugrelated == 1), "True"),
  offender2 = replace(offender2, which(offender2 == 0), "False"),
  offender2 = replace(offender2, which(offender2 == 1), "True"),
  # polkilled = replace(polkilled, which(polkilled==0), "False"),
  # polkilled = replace(polkilled, which(polkilled==1), "True"),
  firearm = replace(firearm, which(firearm==0), "False"),
  firearm = replace(firearm, which(firearm==1), "True"),
  knife = replace(knife, which(knife==0), "False"),
  knife=replace(knife, which(knife==1), "True"),
  vehicle = replace(vehicle, which(vehicle==0), "False"),
  vehicle=replace(vehicle, which(vehicle==1), "True"),
  otherweapon=replace(otherweapon, which(otherweapon==0), "False"),
  otherweapon=replace(otherweapon, which(otherweapon==1), "True"),
  armed = replace(armed, which(armed==0), "False"),
  armed=replace(armed, which(armed==1), "True"),
  ipcr = replace(ipcr, which(ipcr==0), "False"),
  ipcr = replace(ipcr, which(ipcr==1), "True"),
    ivcr = replace(ivcr, which(ivcr==0), "False"),
    ivcr = replace(ivcr, which(ivcr==1), "True"),
    bodycam = replace(bodycam, which(bodycam==0), "False"),
  bodycam = replace(bodycam, which(bodycam==1), "True"),
    guncam = replace(guncam, which(guncam==0), "False"),
  guncam = replace(guncam, which(guncam==1), "True"),
    gunshots = replace(gunshots, which(gunshots==0), "False"),
  gunshots = replace(gunshots, which(gunshots==1), "True"),
    sameofficers = replace(sameofficers, which(sameofficers==0), "False"),
  sameofficers = replace(sameofficers, which(sameofficers==1), "True"),
    helicopters = replace(helicopters, which(helicopters==0), "False"),
  helicopters = replace(helicopters, which(helicopters==1), "True"),
    union = replace(union, which(union==0), "False"),
  union = replace(union, which(union==1), "True"),
    college = replace(college, which(college==0), "False"),
  college = replace(college, which(college==1), "True"),
    community = replace(community, which(community==0), "False"),
  community = replace(community, which(community==1), "True"),
  age_f= cut(sa, breaks=c(0, 14, 19, 39, 200), 
                    right= FALSE, labels=c("AgeUnder15", "Age15_19", "Age20_39", "Age40Above")),
  State =  getState.abb(stnm), 
  #state_lower = stateFromLower(stnm),
  dataSource="lott",
  address=paste(city, stnm, "USA", sep=", ")
) %>% 
  dplyr::rename(Age = sa, date=Date)
for(i in 1:ncol(lott)) {
  if(Hmisc::label(lott)[i]!=""){
    if(lab == "Date"){lab <- "date"} #keep consistent with other df's
    if(lab == "suspect arm**ed, percent"){lab <- "Armed"}
    lab <- gsub(", ", "", lab)
    lab <- gsub("percent ", "", lab)
    lab <- gsub("percent", "", lab)
    if(lab == "whether offender2 exists"){lab <- "Offender 2"}
    lab <- gsub("suspect ", "", lab)
    names(lott)[i] <- lab
  }
}

E. Combine Data

lott_nested <- 
 lott %>%
  tidyr::nest(-dataSource, -address, -State, -city, -year)
wapo_nested <- 
  wapo %>%
  tidyr::nest(-dataSource, -address, -State, -city, -year) 
killData <- dplyr::bind_rows(lott_nested, wapo_nested) %>% 
   dplyr::filter(State %in% c(state.abb, "DC"), year < 2017)
#excluding a case in Virgin Islands (lott), and onec case in puerto rico (lott)

F. Load Geo-Coordinates (FIPS) data

Two files are used to identify the counties in which police shootings occurred:
1. Law Enforcement Agency Indentifiers Crosswalk, 2012 (ICPSR 35158)
https://www.icpsr.umich.edu/icpsrweb/ICPSR/studies/35158 2. “Populated Places” file “POP_PLACES_20170601.txt”, a subset of the larger file “NationalFile_20170601.txt” from USGS - Domestic and Antarctic Names - State and Topical Gazetteer Download Files Source: https://geonames.usgs.gov/domestic/download_data.htm

The remaining cases without a FIPS code are identified using the geocode() function from the ggmaps package.

kd <- getFIPS(df=killData)
Parsed with column specification:
cols(
  .default = col_integer(),
  FIPS_ST = col_character(),
  FIPS_COUNTY = col_character(),
  FIPS = col_character(),
  ORI9 = col_character(),
  ORI7 = col_character(),
  NAME = col_character(),
  STATENAME = col_character(),
  COUNTYNAME = col_character(),
  UANAME = col_character(),
  LG_NAME = col_character(),
  ADDRESS_NAME = col_character(),
  ADDRESS_STR1 = col_character(),
  ADDRESS_STR2 = col_character(),
  ADDRESS_CITY = col_character(),
  ADDRESS_STATE = col_character(),
  LEMAS_ID = col_character(),
  U_POPGRP = col_character(),
  COMMENT = col_character(),
  INTPTLAT = col_double(),
  INTPTLONG = col_double()
  # ... with 3 more columns
)
See spec(...) for full column specifications.
Parsed with column specification:
cols(
  .default = col_character(),
  `<U+FEFF>FEATURE_ID` = col_integer(),
  PRIM_LAT_DEC = col_double(),
  PRIM_LONG_DEC = col_double(),
  ELEV_IN_M = col_integer(),
  ELEV_IN_FT = col_integer()
)
See spec(...) for full column specifications.
Mangling the following names: <U+FEFF>FEATURE_ID -> <U+FEFF>FEATURE_ID. Use enc2native() to avoid the warning.Mangling the following names: <U+FEFF>FEATURE_ID -> <U+FEFF>FEATURE_ID. Use enc2native() to avoid the warning.Mangling the following names: <U+FEFF>FEATURE_ID -> <U+FEFF>FEATURE_ID. Use enc2native() to avoid the warning.Mangling the following names: <U+FEFF>FEATURE_ID -> <U+FEFF>FEATURE_ID. Use enc2native() to avoid the warning.Mangling the following names: <U+FEFF>FEATURE_ID -> <U+FEFF>FEATURE_ID. Use enc2native() to avoid the warning.Mangling the following names: <U+FEFF>FEATURE_ID -> <U+FEFF>FEATURE_ID. Use enc2native() to avoid the warning.Initial Missing FIPS:  3271
Step 1.  Scanning for FIPS using existing data sets
Missing FIPS after Step 1:  82
Step 2.  Scanning for FIPS using Google Maps
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Florence%2C%20AK%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=National%20Park%2C%20AZ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Prairie%20Grove%2C%20AZ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Boise%20National%20Forest%2C%20ID%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Hollis%2C%20ME%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Norfolk-Quincy%2C%20MA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Hamilton%20Township%2C%20NJ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Henderson%2C%20NM%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Clintonville%2C%20OH%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Franklin-Westerville%2C%20OH%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Waverl%2C%20OH%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Lakes%2C%20AK%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Clint%20Wells%2C%20AZ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=St.%20Johns%2C%20FL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=West%20Woodlawn%2C%20IL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Suitland-Silver%20Hill%2C%20MD%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Dartmouth%2C%20MA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Redford%20Charter%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Flint%20charter%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Northland%2C%20MO%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Boiling%20Springs%20Lakes%2C%20NC%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Huntingdon%2C%20WV%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Pinon%20Hills%2C%20CA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Overtown%2C%20FL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Opp%2C%20FL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Alabama%2C%20GA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Chavies%20community%2C%20KY%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Fort%20Meade%2C%20MD%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Spauldings%2C%20MD%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Bloomfield%20Twp%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Hamilton%20Township%2C%20NJ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Little%20Egg%20Harbor%20Township%2C%20NJ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Cockeysville%2C%20TX%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Troutdale%2C%20VA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Mt%20Hope%2C%20WV%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Chapeno%2C%20TX%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Smyrna%2C%20ME%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Eaton%20Rapids%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Roxand%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Carollwood%2C%20FL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Fort%20Meade%2C%20MD%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Straban%20Township%2C%20PA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Ideal%20Beach%2C%20NJ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Watsonsville%2C%20CA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Wood%20Lake%2C%20ND%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Mt.%20Auburn%2C%20OH%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Bloomfield%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Brick%20Township%2C%20NJ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=West%20Knox%2C%20TN%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Pinion%20Hills%2C%20CA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Cato%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Lakes%20Charles%2C%20LA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=West%20Goshen%2C%20CA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Norwood%2C%20OK%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=North%20Laredo%2C%20TX%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Canaan%20Township%2C%20PA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Geneva%2C%20WI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Penn%20Township%2C%20PA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Hollywood%20Hills%2C%20CA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Perry%20Township%2C%20OH%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=East%20Berstadt%2C%20KY%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Pueblo%20of%20Laguna%2C%20NM%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Milcreek%2C%20UT%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Jacksonsville%2C%20FL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Shawnee%20National%20Forest%2C%20IL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Ishpeming%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Columbia%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Laguna%20Pueblo%2C%20NM%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Lake%20Asbury%2C%20FL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Little%20Egg%20Harbor%20Township%2C%20NJ%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=McKinneyville%2C%20CA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=East%20Hollywood%2C%20CA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Sylvania%20Township%2C%20OH%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Weeki%20Wachi%2C%20FL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Big%20Bear%2C%20MO%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Logan%20Canyon%2C%20UT%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Killeen%2C%20AL%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Muckleshoot%20Indian%20Reservation%2C%20WA%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Holland%20Township%2C%20MI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Simpsonsville%2C%20KY%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Keaau%2C%20HI%2C%20USA
Source : https://maps.googleapis.com/maps/api/geocode/json?address=Forks%20Township%2C%20PA%2C%20USA
Missing FIPS after Step 2:  7

There are four remaining cases without a FIPS code. After examining these four cases, I made the following manual changes:

  1. “Florence, AK, USA” - Lott - 2013 - is identified as Florence, Alabama, Lauderdale County, FIPS `01077

  2. “Opp, FL, USA” - Lott - 2015 - is identified as Opp, Alabama, Covington County, FIPS `01039

  3. “Boise National Forest, ID, USA” - Lott - 2013 - is in/near Lowman, ID, Boise County, FIPS `16015

  4. “Cockeysville, TX, USA” could not be verified and is dropped.

In addition, the following changes are made:

  1. “Prairie Grove, AZ, USA” - Lott - 2013 - is Prairie Grove, Arkansas, Washington County, FIPS `05143

  2. “Alabama, GA, USA” - Lott - 2015 - DROPPED

  3. “National Park, AZ, USA” - Lott - 2013 - DROPPED

drop_addresses <- c("Alabama, GA, USA", "National Park, AZ, USA", "Cockeysville, TX, USA")
nrow(kd)
[1] 3271
kd <- subset(kd, !(address %in% drop_addresses))
nrow(kd)
[1] 3268
kd$FIPS[which(kd$address == "Prairie Grove, AZ, USA")] <- "`05143"
kd$State[which(kd$address == "Prairie Grove, AZ, USA")] <- "AR"
kd$FIPS[which(kd$address == "Florence, AK, USA")] <- "`01077"
kd$State[which(kd$address == "Florence, AK, USA")] <- "AL"
kd$State[which(kd$address == "Opp, FL, USA")] <- "AL"
kd$FIPS[which(kd$address == "Boise National Forest, ID, USA")] <- "`16015"

NYC Corrrection

(see section below in UCR crime data - using Manhattan FIPS for all NYC FIPS)

nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
kd <- kd %>% 
  dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  ) %>% 
  dplyr::select(-county)

G. Save Data.

wapo <- kd %>% dplyr::filter(dataSource=="Wapo") %>% 
  tidyr::unnest()
fst::write.fst(wapo, path="df_wapo_fst.csv")
write.csv(wapo, file="df_wapo.csv")
lott <- kd %>% dplyr::filter(dataSource=="lott") %>% 
  tidyr::unnest()
fst::write.fst(lott, path="df_lott_fst.csv")
write.csv(lott, file="df_lott.csv")

II. POPULATION CENSUS DATA ———————————

1. COUNTY-LEVEL Population Data

CC-EST2015-ALLDATA-[ST-FIPS]: Annual County Resident Population Estimates by Age, Sex, Race, and Hispanic Origin: April 1, 2010 to July 1, 2015 File: 7/1/2015 County Characteristics Resident Population Estimates Source: U.S. Census Bureau, Population Division Release Date: June 2016

Load Data from Census Website

library(tidyr)
library(readr)
library(dplyr)
# I.  COUNTY-LEVEL POPULATION CENSUS DATA ---------------------------------
##Using dplyr/tidy-verse code
county_census <- read_csv(file="https://www2.census.gov/programs-surveys/popest/datasets/2010-2015/counties/asrh/cc-est2015-alldata.csv")
Parsed with column specification:
cols(
  .default = col_integer(),
  SUMLEV = col_character(),
  STATE = col_character(),
  COUNTY = col_character(),
  STNAME = col_character(),
  CTYNAME = col_character()
)
See spec(...) for full column specifications.
                          
##https://www.census.gov/popest/data/counties/asrh/2015/files/CC-EST2015-ALLDATA.csv
##Race-Total, gender-Both, age-All
countyPop <- county_census %>% 
  dplyr::filter(YEAR %in% c(4,5,6,7,8)) %>% 
  dplyr::mutate(YEAR=replace(YEAR, which(YEAR==4), 2011),
         YEAR=replace(YEAR, which(YEAR==5), 2012),
         YEAR=replace(YEAR, which(YEAR==6), 2013),
         YEAR=replace(YEAR, which(YEAR==7), 2014),
         YEAR=replace(YEAR, which(YEAR==8), 2015),
         FIPS=paste("`", STATE, COUNTY, sep=""),
         
         
         age=NA,
         age=replace(age, which(AGEGRP==0), "All"),
         age=replace(age, which(AGEGRP %in% c(1,2,3)), "Under15"),
         age=replace(age, which(AGEGRP == 4), "15_19"),
         age=replace(age, which(AGEGRP == 5), "20_24"),
         age=replace(age, which(AGEGRP == 6), "25_29"),
         age=replace(age, which(AGEGRP == 7), "30_34"),
         age=replace(age, which(AGEGRP == 8), "35_39"),
         age=replace(age, which(AGEGRP == 9), "40_44"),
         age=replace(age, which(AGEGRP == 10), "45_49"),
         age=replace(age, which(AGEGRP == 11), "50_54"),
         age=replace(age, which(AGEGRP == 12), "55_59"),
         age=replace(age, which(AGEGRP > 12), "60Above")
  ) %>% 
  transmute(year=YEAR, 
            state=STNAME,
            county=CTYNAME,
            FIPS=FIPS, age=age,
          Total_Male=TOT_MALE, 
          Total_Female=TOT_FEMALE, 
          Total_Both = Total_Male+Total_Female,
          
          Black_Male=BA_MALE, Black_Female=BA_FEMALE,
          Black_Both=Black_Male+Black_Female,
          
          Amerindian_Male=IA_MALE, Amerindian_Female=IA_FEMALE,
          Amerindian_Both=Amerindian_Male+Amerindian_Female,
          
          Asian_Male=AA_MALE, Asian_Female=AA_FEMALE,
          Asian_Both=Asian_Male+Asian_Female,
          
          PacificIslander_Male=NA_MALE, PacificIslander_Female=NA_FEMALE,
          PacificIslander_Both=PacificIslander_Male+PacificIslander_Female,
          
          Hispanic_Male=HWA_MALE, #Hispanic, White alone male population 
          Hispanic_Female=HWA_FEMALE, #Hispanic, White alone female population 
          Hispanic_Both=Hispanic_Male+Hispanic_Female,
          
          White_Male=NHWA_MALE,  #Not Hispanic, White alone male population
          White_Female=NHWA_FEMALE, #Not Hispanic, White alone female population
          White_Both=White_Male+White_Female
    ) 
##Separate, then re-unite in long format
white_df <- countyPop %>% 
  dplyr::select(year, state, county, FIPS, age, White_Male, White_Female, White_Both) %>% 
  mutate(Race="White") %>% 
  group_by(year, state, county, FIPS, Race, gender, age) %>% 
  dplyr::summarise(population=(sum(as.numeric(population), na.rm = TRUE)))
Total_df <- countyPop %>% 
  dplyr::select(year, state, county, FIPS, age, Total_Male, Total_Female, Total_Both) %>% 
  dplyr::rename(Male=Total_Male, Female=Total_Female, Both=Total_Both) %>% 
  tidyr::gather(gender, population, 6:8) %>% 
  dplyr::mutate(Race="Total") %>% 
  group_by(year, state, county, FIPS, Race, gender, age) %>% 
  dplyr::summarise(population=(sum(as.numeric(population), na.rm = TRUE)))
Black_df <- countyPop %>% 
  dplyr::select(year, state, county, FIPS, age, Black_Male, Black_Female, Black_Both) %>% 
  dplyr::rename(Male=Black_Male, Female=Black_Female, Both=Black_Both) %>% 
  tidyr::gather(gender, population, 6:8) %>% 
  dplyr::mutate(Race="Black") %>% 
  dplyr::group_by(year, state, county, FIPS, Race, gender, age) %>% 
Asian_df <- countyPop %>% 
  dplyr::select(year, state, county, FIPS, age, Asian_Male, Asian_Female, Asian_Both) %>% 
  dplyr::rename(Male=Asian_Male, Female=Asian_Female, Both=Asian_Both) %>% 
  dplyr::group_by(year, state, county, FIPS, Race, gender, age) %>% 
  dplyr::summarise(population=(sum(as.numeric(population), na.rm = TRUE)))
Amerindian_df <- countyPop %>% 
  dplyr::select(year, state, county, FIPS, age, Amerindian_Male, Amerindian_Female, Amerindian_Both) %>% 
  dplyr::rename(Male=Amerindian_Male, Female=Amerindian_Female, Both=Amerindian_Both) %>% 
  tidyr::gather(gender, population, 6:8) %>% 
  dplyr::mutate(Race="Native American") %>% 
  dplyr::group_by(year, state, county, FIPS, Race, gender, age) %>% 
Hispanic_df <- countyPop %>% 
  dplyr::select(year, state, county, FIPS, age, Hispanic_Male, Hispanic_Female, Hispanic_Both) %>% 
  dplyr::rename(Male=Hispanic_Male, Female=Hispanic_Female, Both=Hispanic_Both) %>% 
  dplyr::summarise(population=(sum(as.numeric(population), na.rm = TRUE)))
PacificIslander_df <- countyPop %>% 
  dplyr::select(year, state, county, FIPS, age, PacificIslander_Male, PacificIslander_Female, PacificIslander_Both) %>% 
  dplyr::rename(Male=PacificIslander_Male, Female=PacificIslander_Female, Both=PacificIslander_Both) %>% 
  tidyr::gather(gender, population, 6:8) %>% 
  dplyr::summarise(population=(sum(as.numeric(population), na.rm = TRUE)))
##Recombine - can delete total,both, and all values
countyPop2 <- bind_rows(Total_df , white_df, Black_df, Hispanic_df,
                        Asian_df, Amerindian_df, PacificIslander_df
                        )
census_county <- countyPop2
rm(countyPop2)
rm(countyPop)

NYC Correction

nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
census_county <- census_county %>% ungroup() %>% 
  dplyr::mutate(FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")) %>% 
  dplyr::group_by(year, FIPS, Race, gender, age) %>% 
  dplyr::summarise(population=sum(population, na.rm=T),
                   state=first(state),
                   county=first(county))

County Populations

All population variables are for year 2015, except variables appended with “5yr”, which are averaged across 2011 to 2015. Variables appended with “change” are the percent change from 2011 to 2015.

census_vars <- census_county %>% 
  dplyr::group_by(year, FIPS) %>% 
  dplyr::mutate(
    pop.c.total = population[which(Race=="Total"  & gender=="Both" & age=="All")],
    pop.c.white_nh = population[which(Race=="White"  & gender=="Both" & age=="All")],
    pop.c.black = population[which(Race == "Black" & gender=="Both" & age=="All")],
    pop.c.asian = population[which(Race=="Asian" & gender=="Both" & age=="All")],
    #Create Asian/PAcific Islander Category for some datasets that conflate the two
    pop.c.AP = mean(population[which(gender=="Both" & age=="All" & (Race == "Asian" | Race == "Pacific Islander"))], na.rm=T),
    ##Create White/Hispanic category to match UCR
    pop.c.WH = mean(population[which(gender=="Both" & age=="All" & (Race == "White" | Race == "Hispanic"))], na.rm=T),
    pop.c.amerindian = population[which(Race=="Native American"  & gender=="Both" & age=="All")],
    pop.c.hispanic = population[which(Race=="Hispanic"  & gender=="Both" & age=="All")],
    pop.male.15_29 = sum(population[which(Race=="Total" & gender=="Male" & age %in% c("15_19","20_24","25_29"))], na.rm=T),
  dplyr::group_by(FIPS) %>% 
  dplyr::mutate(
    ##Averaged aross 2011-2015    
    pop.c.total_5yr = mean(pop.c.total, na.rm=T),
         pop.c.white_nh_5yr = mean(pop.c.white_nh, na.rm=T),
          pop.c.WH_5yr = mean(pop.c.WH, na.rm=T),
         pop.c.black_5yr = mean(pop.c.black, na.rm=T),
         pop.c.asian_5yr = mean(pop.c.asian, na.rm=T),
         pop.c.hispanic_5yr = mean(pop.c.hispanic, na.rm=T),
         pop.c.amerindian_5yr = mean(pop.c.amerindian, na.rm=T),
         pop.male.15_29_5yr = mean(pop.male.15_29, na.rm=T),
  
    ##Change from 2011 - 2015 
  pop.c.total_change = mean((pop.c.total[which(year==2015)]-pop.c.total[which(year==2011)])/pop.c.total[which(year==2011)], 
                            na.rm=T),
  pop.c.white_nh_change = mean((pop.c.white_nh[which(year==2015)]-pop.c.white_nh[which(year==2011)])/pop.c.white_nh[which(year==2011)], 
                               na.rm=T),
  
  
  pop.c.black_change = mean((pop.c.black[which(year==2015)]-pop.c.black[which(year==2011)])/pop.c.black[which(year==2011)], na.rm=T),
  
  ##A few counties had zero blacks, which resulted in infinite values (division by zero), therefore adding + 1
  pop.c.black_change = ifelse(is.infinite(pop.c.black_change),  
        #If infinite, change                    
        mean(((pop.c.black[which(year==2015)]+1)-(pop.c.black[which(year==2011)]+1))/(pop.c.black[which(year==2011)]+1), na.rm=T),  
        ##If not infinite, keep the same
        pop.c.black_change)
  
  ) %>% 
  dplyr::filter(year==2015, Race=="Total", age=="All", gender=="Both") %>% 
  dplyr::select(-Race, -gender, -age, -year)
  

2. STATE-LEVEL Population Data

State Characteristics Datasets: Annual State Resident Population Estimates for 5 Race Groups (5 Race Alone or in Combination Groups) by Age, Sex, and Hispanic Origin: April 1, 2010 to July 1, 2015 https://www2.census.gov/programs-surveys/popest/datasets/2010-2015/state/asrh/sc-est2015-alldata5.csv

Load Data from Census website

census_state <- read_csv("https://www2.census.gov/programs-surveys/popest/datasets/2010-2015/state/asrh/sc-est2015-alldata5.csv")
  
##formerly, read_csv("https://www.census.gov/popest/data/state/asrh/2015/files/SC-EST2015-ALLDATA5.csv")

census_state2 <- census_state %>% 
  transmute(State=NAME, gender=SEX, Hisp=ORIGIN, Race=RACE, AGE=AGE,
            y2011=POPESTIMATE2011, y2012=POPESTIMATE2012,
            y2013=POPESTIMATE2013, y2014=POPESTIMATE2014,
            y2015=POPESTIMATE2015) %>% 
  dplyr::mutate(
    gender=replace(gender, which(gender==0), "Both"),
    gender=replace(gender, which(gender==1), "Male"),
    gender=replace(gender, which(gender==2), "Female"),
        age=NA,
         age=replace(age, which(AGE < 15), "Under15"),
         age=replace(age, which(AGE>=15 & AGE<=19), "15_19"),
         age=replace(age, which(AGE>=20 & AGE<=24), "20_24"),
         age=replace(age, which(AGE>=25 & AGE<=29), "25_29"),
         age=replace(age, which(AGE>=30 & AGE<=34), "30_34"),
         age=replace(age, which(AGE>=35 & AGE<=39), "35_39"),
         age=replace(age, which(AGE>=40 & AGE<=44), "40_44"),
         age=replace(age, which(AGE>=45 & AGE<=49), "45_49"),
         age=replace(age, which(AGE>=50 & AGE<=54), "50_54"),
         age=replace(age, which(AGE>=55 & AGE<=59), "55_59"),
         age=replace(age, which(AGE>=60), "60Above"),
    ##Need to add a row for all ages, or not
        #age=replace(age, which(age==0), "All"),
    
    Race=replace(Race, which(Race==1 & Hisp==1), "White"),
    Race=replace(Race, which(Race==1 & Hisp==2), "Hispanic"),
    Race=replace(Race, which(Race==2 & Hisp==0), "Black"),
    Race=replace(Race, which(Race==3 & Hisp==0), "Native American"),
    Race=replace(Race, which(Race==4 & Hisp==0), "Asian"),
    Race=replace(Race, which(Race==5 & Hisp==0), "Pacific Islander")
  ) %>% 
  dplyr::select(-c(Hisp, AGE)) %>% 
  dplyr::filter(Race %in% c("White", "Hispanic", "Black","Asian",
                     "Native American", "Pacific Islander")) %>% 
  dplyr::group_by(State, Race, gender, age) %>% 
  dplyr::summarise(y2011=sum(y2011, na.rm=T),
            y2012=sum(y2012, na.rm=T),
            y2013=sum(y2013, na.rm=T),
            y2014=sum(y2014, na.rm=T),
            y2015=sum(y2015, na.rm=T)
            
            ) %>% 
  ###File size prior to tidying:  631 KB
  ###File size after gathering years into one column:  2544 KB.   
  tidyr::gather(year, population, 5:9) %>% 
  dplyr::mutate(
    year=replace(year, which(year=="y2011"), 2011),
    year=replace(year, which(year=="y2012"), 2012),
    year=replace(year, which(year=="y2013"), 2013),
    year=replace(year, which(year=="y2014"), 2014),
    year=replace(year, which(year=="y2015"), 2015)
  )

##Adding a summary categories:
##State = United States
##gender = 'Both' (already created)
##age = 'All'
##Race = 'Total'

##age -'All'
age_df <- census_state2 %>% 
  dplyr::group_by(year, State, Race, gender) %>% 
  dplyr::summarise(population=sum(population, na.rm=T)) %>% 
  dplyr::mutate(age="All")

census_state2 <- dplyr::bind_rows(census_state2, age_df)

##Race - Total
race_df <- census_state2 %>% 
  dplyr::group_by(year, State, gender, age) %>% 
  dplyr::summarise(population=sum(population, na.rm=T)) %>% 
  dplyr::mutate(Race="Total")

census_state2 <- dplyr::bind_rows(census_state2, race_df)

##State=US

us_df <- census_state2 %>% 
  dplyr::group_by(year, gender, Race, age) %>% 
  dplyr::summarise(population=sum(population, na.rm=T)) %>% 
  dplyr::mutate(State="United States")

census_state <- dplyr::bind_rows(census_state2, us_df)
##file size after adding rows:  3366 KB
##write.csv(census_state, file="census_state.csv")

State Populations

All population variables are for year 2015, except variables appended with “5yr”, which are averaged across 2011 to 2015. Variables appended with “change” are the percent change from 2011 to 2015.

census_state <- census_state %>% 
   dplyr::group_by(year, State) %>% 
  dplyr::mutate(
    pop.total = population[which(Race=="Total"  & gender=="Both" & age=="All")],
    pop.white_nh = population[which(Race=="White"  & gender=="Both" & age=="All")],
    pop.black = population[which(Race == "Black" & gender=="Both" & age=="All")],
    pop.asian = population[which(Race=="Asian" & gender=="Both" & age=="All")],
    #Create Asian/PAcific Islander Category for some datasets that conflate the two
    pop.AP = mean(population[which(gender=="Both" & age=="All" & (Race == "Asian" | Race == "Pacific Islander"))], na.rm=T),
    ##Create White/Hispanic category to match UCR
    pop.WH = mean(population[which(gender=="Both" & age=="All" & (Race == "White" | Race == "Hispanic"))], na.rm=T),
    pop.amerindian = population[which(Race=="Native American"  & gender=="Both" & age=="All")],
    pop.hispanic = population[which(Race=="Hispanic"  & gender=="Both" & age=="All")],
    pop.male.15_29 = sum(population[which(Race=="Total" & gender=="Male" & age %in% c("15_19","20_24","25_29"))], na.rm=T),
    pop.black.male15_29 = sum(population[which(Race=="Black"  & gender=="Male" & age %in% c("15_19","20_24","25_29"))])
  ) %>% 
  dplyr::group_by(State) %>% 
  dplyr::mutate(
    ##Averaged aross 2011-2015    
    pop.total_5yr = mean(pop.total, na.rm=T),
         pop.white_nh_5yr = mean(pop.white_nh, na.rm=T),
          pop.WH_5yr = mean(pop.WH, na.rm=T),
         pop.black_5yr = mean(pop.black, na.rm=T),
         pop.asian_5yr = mean(pop.asian, na.rm=T),
         pop.hispanic_5yr = mean(pop.hispanic, na.rm=T),
         pop.amerindian_5yr = mean(pop.amerindian, na.rm=T),
         pop.male.15_29_5yr = mean(pop.male.15_29, na.rm=T),
  
    ##Change from 2011 - 2015 
  pop.total_change = mean((pop.total[which(year==2015)]-pop.total[which(year==2011)])/pop.total[which(year==2011)], 
                            na.rm=T),
  pop.white_nh_change = mean((pop.white_nh[which(year==2015)]-pop.white_nh[which(year==2011)])/pop.white_nh[which(year==2011)], 
                               na.rm=T),
  
  
  pop.black_change = mean((pop.black[which(year==2015)]-pop.black[which(year==2011)])/pop.black[which(year==2011)], na.rm=T),
  
  ##A few counties had zero blacks, which resulted in infinite values (division by zero), therefore adding + 1
  pop.black_change = ifelse(is.infinite(pop.black_change),  
        #If infinite, change                    
        mean(((pop.black[which(year==2015)]+1)-(pop.black[which(year==2011)]+1))/(pop.black[which(year==2011)]+1), na.rm=T),  
        ##If not infinite, keep the same
        pop.black_change)
  
  ) %>% 
  dplyr::filter(year==2015, Race=="Total", age=="All", gender=="Both") %>% 
  dplyr::select(-Race, -gender, -age, -year)

III. ARREST DATA (Panel 3) ———————————

1. Load Data

2015 Data

Uniform Crime Reporting Program Data: Arrests by Age, Sex, and Race, 2015 (ICPSR 36794) https://www.icpsr.umich.edu/icpsrweb/NACJD/studies/36794 ICPSR_36794

Note that the offense codes changed in the 2015 edition. For example, Murder is now “01A” instead of “011”.
File 36794-0001-Data.tsv I’ve converted this to ‘fst’ format for faster loading.

# ucr_15 <- readr::read_tsv("createData/36794-0001-Data.tsv", na = c("", "NA", 999998, 99998, 99999, 998))
# fst::write.fst(ucr_15, path="createData/ucr_15.csv")
ucr_15 <- fst::read.fst(path="createData/ucr_15.csv")
  

2014 Data

Uniform Crime Reporting Program Data: Arrests by Age, Sex, and Race, Summarized Yearly, 2014 (ICPSR 36400). http://www.icpsr.umich.edu/icpsrweb/NACJD/studies/36400

File 36400-0001-Data.tsv

##File = 36400-0001-Data.tsv
# ucr_14 <- read_tsv("createData/36400-0001-Data.tsv", na = c("", "NA", 999998, 99998, 99999, 998))
# fst::write.fst(ucr_14, path="createData/ucr_14.csv")
ucr_14 <- fst::read.fst(path="createData/ucr_14.csv")

2013 Data

Uniform Crime Reporting Program Data: Arrests by Age, Sex, and Race, Summarized Yearly, 2013 (ICPSR 36116) http://www.icpsr.umich.edu/icpsrweb/NACJD/studies/36116 File 36116-0001-Data.tsv

##File = 36116-0001-Data.tsv
# ucr_13 <- read_tsv("createData/36116-0001-Data.tsv", na = c("", "NA", 999998, 99998, 99999, 998))
# fst::write.fst(ucr_13, path="createData/ucr_13.csv")
ucr_13 <- fst::read.fst(path="createData/ucr_13.csv")

2012 Data

Uniform Crime Reporting Program Data: Arrests by Age, Sex, and Race, Summarized Yearly, 2012 (ICPSR 35018) http://www.icpsr.umich.edu/icpsrweb/NACJD/studies/35018

File 35018-0001-Data.tsv

##File = 35018-0001-Data.tsv
# ucr_12 <- read_tsv("createData/35018-0001-Data.tsv", na = c("", "NA", 999998, 99998, 99999, 998))
# fst::write.fst(ucr_12, path="createData/ucr_12.csv")
ucr_12 <- fst::read.fst(path="createData/ucr_12.csv")

2011 Data

Uniform Crime Reporting Program Data: Arrests by Age, Sex, and Race, Summarized Yearly, 2011 (ICPSR 34581) http://www.icpsr.umich.edu/icpsrweb/NACJD/studies/34581 File 34581-0001-Data.tsv

## File = 34581-0001-Data.tsv
# ucr_11 <- read_tsv("createData/34581-0001-Data.tsv", na = c("", "NA", 999998, 99998, 99999, 998))
# fst::write.fst(ucr_11, path="createData/ucr_11.csv")
ucr_11 <- fst::read.fst(path="createData/ucr_11.csv")

2. Combine and Filter

Note that violent crime is composed of four offenses: murder and nonnegligent manslaughter, forcible rape, robbery, and aggravated assault.

offenses_2011_2014 <- c("011", "020", "030", "040", "050", 
              "060", "070", "130", "140", "180", 
              "185", "210")
keepVars <- c("YEAR","STATE","STNAME","COUNTY", "ORI", "AGENCY","OFFENSE","M0_9", "M10_12", "M13_14","M15", "M16","M17","M18","M19",
              "M20","M21","M22","M23","M24","M25_29", "M30_34", "M35_39", "M40_44", "M45_49", "M50_54","M55_59","M60_64","M65","F0_9",
              "F10_12","F13_14","F15","F16","F17","F18","F19","F20","F21","F22","F23","F24","F25_29","F30_34","F35_39","F40_44",
              "F45_49",  "F50_54",  "F55_59","F60_64","F65","JW", "JB","JI","JA","AW","AB", "AI","AA")
ucr_15 <- ucr_15[,keepVars] 
 ucr_15 <- ucr_15 %>%  dplyr::mutate(crime=NA,
                crime=replace(crime, which(OFFENSE == "01A"), "murder"),
                ##Murder and non-negligent manslaughter
                crime=replace(crime, which(OFFENSE == "02"), "rape"),
                ##Forcible rape
                crime=replace(crime, which(OFFENSE == "03"), "robbery"),
                ##robbery
                crime=replace(crime, which(OFFENSE == "04"), "assault" ),
                ##Aggravated assault
                crime=replace(crime, which(OFFENSE == "05"), "burglary" ),
                ##Burglary-breaking or entering
                crime=replace(crime, 
                              which(OFFENSE %in% c("06", "07", "13")), 
                              "theft" ),
                ## 060 = Larceny-theft (not motor vehicle)
                ## 070 = Motor vehicle theft
                ## 130 = Stolen property-buy, receive, poss.
                crime=replace(crime, which(OFFENSE == "140"), "vandalism" ),
                ##Vandalism
                crime=replace(crime, which(OFFENSE =="180"), "drug_sale"),
                ##Sale/manufacture (subtotal) - drugs
                crime=replace(crime, which(OFFENSE =="185"), "drug_poss"),
                ##Possession (subtotal)
                crime=replace(crime, which(OFFENSE =="21"), "dui")
                ##Driving under the influence
  ) %>% ##eliminating data for other crimes
  dplyr::filter(!is.na(crime))
ucr <- dplyr::bind_rows(ucr_11, ucr_12, ucr_13, ucr_14) 
ucr <- ucr[,keepVars] 
  ##dplyr::filter(OFFENSE %in% offenses_2011_2014) %>% 
  ##dplyr::select(c(7, 3, 18, 13, 4, 17, 22:70, 73:76)) %>% 
ucr <- ucr %>% dplyr::mutate(crime=NA,
         crime=replace(crime, which(OFFENSE == "011"), "murder"),
         ##Murder and non-negligent manslaughter
         crime=replace(crime, which(OFFENSE == "020"), "rape"),
         ##Forcible rape
         crime=replace(crime, which(OFFENSE == "030"), "robbery"),
         ##robbery
         crime=replace(crime, which(OFFENSE == "040"), "assault" ),
         ##Aggravated assault
         crime=replace(crime, which(OFFENSE == "050"), "burglary" ),
         ##Burglary-breaking or entering
         crime=replace(crime, 
                       which(OFFENSE %in% c("060", "070", "130")), 
                       "theft" ),
         ## 060 = Larceny-theft (not motor vehicle)
         ## 070 = Motor vehicle theft
         crime=replace(crime, which(OFFENSE == "140"), "vandalism" ),
         ##Vandalism
         crime=replace(crime, which(OFFENSE =="180"), "drug_sale"),
         ##Sale/manufacture (subtotal) - drugs
         crime=replace(crime, which(OFFENSE =="185"), "drug_poss"),
         ##Possession (subtotal)
         crime=replace(crime, which(OFFENSE =="210"), "dui")
         ##Driving under the influence
         ) %>% ##eliminating data for other crimes
  dplyr::filter(!is.na(crime)) %>% 
  dplyr::bind_rows(ucr_15)

Finding data entry errors

Delphi, Indiana in 2013 mistakenly reported crimes with values of 10000 appear in multiple columns and for multiple rows (i.e. offenses) for the same agency and which also exceed population size. In addition, 2 police stations report negative values for arrests: * FLOYD COUNTY POLICE DEPT, GA 2013 rape * LEE, GA 2015 assault

ucr$totals <- NA
ucr$totals <- apply(ucr[,8:59], 1, sum, na.rm=T)
error_rows <- as.numeric()
  #otherc <- setdiff(8:59, i) ##other variables/columns
  #ucr$totals <- apply(ucr[,otherc], 1, sum, na.rm=T)
  ##if one arrest column exceeds the sum of all the others - impossible, therefore flag.
  er = which(ucr[,i] == 10000 | ucr[,i] == 10001 | ucr[,i] == 20000)
  
  if(length(er)>0){
    message(paste0("variable = ", names(ucr)[i]))
    message(paste(ucr$AGENCY[er], sep=" \n"))
    error_rows <- unique(c(error_rows, er))
  }
}
variable = M13_14
DELPHI
variable = M17
DELPHI
variable = M18
DELPHI
variable = M20
DELPHI
variable = M24
DELPHIDELPHI
variable = M30_34
DELPHIDELPHI
variable = M40_44
DELPHI
variable = M45_49
DELPHIDELPHIDELPHI
variable = F13_14
DELPHI
variable = F17
DELPHI
variable = AW
DELPHIDELPHI
total_Zero <- which(ucr$totals < 0)
error_rows <- unique(c(error_rows, total_Zero))
ucr_error <- ucr[error_rows,]

Deleting data entry errors

Deleting these cases.

ucr <- ucr[-which(ucr$AGENCY=="DELPHI" & ucr$STATE==13 & ucr$YEAR==2013 ),] ## removed 6 cases
ucr <- ucr[-which(ucr$AGENCY=="FLOYD COUNTY POLICE DEPT" & ucr$STATE==10 & ucr$YEAR==2013 & ucr$crime == "rape"),] # one case
ucr <- ucr[-which(ucr$AGENCY=="LEE" & ucr$STATE==10 & ucr$YEAR==2015 & ucr$crime == "assault"),] # one case

3. Attach FIPS codes to UCR Data, aggregate by county

1.– Some identical FIPS codes have separate county names - e.g. California, FIPS code 06065 = both ‘Riverside’ & ‘Riverside County’. Therefore grouping by FIPS rather than by county. 2.– There is also an FIPS coding error for Philadelphia. The ORI code PAPEP00 is read as Indiana County, PA, FIPS = 42063, which should instead be 42101.

Load Geographic Codes - County FIPS

Law Enforcement Agency Indentifiers Crosswalk, 2012 (ICPSR 35158) https://www.icpsr.umich.edu/icpsrweb/ICPSR/studies/35158

#setwd("createData")
ucr_geo <- read_tsv("createData/35158-0001-Data.tsv") %>% 
  dplyr::select(ORI7, FIPS, COUNTYNAME, STATENAME ) %>% 
  dplyr::rename(ORI=ORI7, county=COUNTYNAME, State=STATENAME)
Parsed with column specification:
cols(
  .default = col_integer(),
  FIPS_ST = col_character(),
  FIPS_COUNTY = col_character(),
  FIPS = col_character(),
  ORI9 = col_character(),
  ORI7 = col_character(),
  NAME = col_character(),
  STATENAME = col_character(),
  COUNTYNAME = col_character(),
  UANAME = col_character(),
  LG_NAME = col_character(),
  ADDRESS_NAME = col_character(),
  ADDRESS_STR1 = col_character(),
  ADDRESS_STR2 = col_character(),
  ADDRESS_CITY = col_character(),
  ADDRESS_STATE = col_character(),
  LEMAS_ID = col_character(),
  U_POPGRP = col_character(),
  COMMENT = col_character(),
  INTPTLAT = col_double(),
  INTPTLONG = col_double()
  # ... with 3 more columns
)
See spec(...) for full column specifications.

|==========                                                                     |  12%    1                                                                     |  13%    1 MB
|===========                                                                    |  13%    1 MB
|===========                                                                    |  14%    1 MB
|============                                                                   |  15%    1 MB
|============                                                                   |  15%    1 MB
|=============                                                                  |  16%    1 MB
|=============                                                                  |  16%    1 MB
|==============                                                                 |  17%    1 MB
|==============                                                                 |  18%    1 MB
|==============                                                                 |  18%    2 MB
|===============                                                                |  19%    2 MB
|===============                                                                |  19%    2 MB
|================                                                               |  20%    2 MB
|================                                                               |  21%    2 MB
|=================                                                              |  21%    2 MB
|=================                                                              |  22%    2 MB
|==================                                                             |  22%    2 MB
|==================                                                             |  23%    2 MB
|===================                                                            |  24%    2 MB
|===================                                                            |  24%    2 MB
|====================                                                           |  25%    2 MB
|====================                                                           |  25%    2 MB
|=====================                                                          |  26%    2 MB
|=====================                                                          |  26%    2 MB
|=====================                                                          |  27%    3 MB
|======================                                                         |  28%    3 MB
|======================                                                         |  28%    3 MB
|=======================                                                        |  29%    3 MB
|=======================                                                        |  29%    3 MB
|========================                                                       |  30%    3 MB
|========================                                                       |  30%    3 MB
|=========================                                                      |  31%    3 MB
|=========================                                                      |  32%    3 MB
|==========================                                                     |  32%    3 MB
|==========================                                                     |  33%    3 MB
|===========================                                                    |  33%    3 MB
|===========================                                                    |  34%    3 MB
|============================                                                   |  35%    3 MB
|============================                                                   |  35%    3 MB
|=============================                                                  |  36%    4 MB
|=============================                                                  |  36%    4 MB
|==============================                                                 |  37%    4 MB
|==============================                                                 |  38%    4 MB
|===============================                                                |  38%    4 MB
|===============================                                                |  39%    4 MB
|===============================                                                |  39%    4 MB
|================================                                               |  40%    4 MB
|================================                                               |  41%    4 MB
|=================================                                              |  41%    4 MB
|=================================                                              |  42%    4 MB
|==================================                                             |  42%    4 MB
|==================================                                             |  43%    4 MB
|===================================                                            |  44%    4 MB
|===================================                                            |  44%    4 MB
|====================================                                           |  45%    4 MB
|====================================                                           |  45%    5 MB
|=====================================                                          |  46%    5 MB
|=====================================                                          |  46%    5 MB
|======================================                                         |  47%    5 MB
|======================================                                         |  48%    5 MB
|======================================                                         |  48%    5 MB
|=======================================                                        |  49%    5 MB
|=======================================                                        |  49%    5 MB
|========================================                                       |  50%    5 MB
|========================================                                       |  51%    5 MB
|=========================================                                      |  51%    5 MB
|=========================================                                      |  52%    5 MB
|==========================================                                     |  52%    5 MB
|==========================================                                     |  53%    5 MB
|===========================================                                    |  54%    5 MB
|===========================================                                    |  54%    6 MB
|============================================                                   |  55%    6 MB
|============================================                                   |  55%    6 MB
|=============================================                                  |  56%    6 MB
|=============================================                                  |  57%    6 MB
|==============================================                                 |  57%    6 MB
|==============================================                                 |  58%    6 MB
|===============================================                                |  58%    6 MB
|===============================================                                |  59%    6 MB
|================================================                               |  60%    6 MB
|================================================                               |  60%    6 MB
|=================================================                              |  61%    6 MB
|=================================================                              |  61%    6 MB
|==================================================                             |  62%    6 MB
|==================================================                             |  63%    6 MB
|==================================================                             |  63%    7 MB
|===================================================                            |  64%    7 MB
|===================================================                            |  64%    7 MB
|====================================================                           |  65%    7 MB
|====================================================                           |  66%    7 MB
|=====================================================                          |  66%    7 MB
|=====================================================                          |  67%    7 MB
|======================================================                         |  67%    7 MB
|======================================================                         |  68%    7 MB
|======================================================                         |  68%    7 MB
|=======================================================                        |  69%    7 MB
|=======================================================                        |  69%    7 MB
|========================================================                       |  70%    7 MB
|========================================================                           7 MB
|=========================================================                      |  71%    7 MB
|=========================================================                      |  72%    7 MB
|==========================================================                     |  73%    8 MB
|==========================================================                     |  73%    8 MB
|===========================================================                    |  74%    8 MB
|===========================================================                    |  74%    8 MB
|============================================================                   |  75%    8 MB
|============================================================                   |  76%    8 MB
|=============================================================                  |  76%    8 MB
|=============================================================                  |  77%    8 MB
|==============================================================                 |  78%    8 MB
|==============================================================                 |  78%    8 MB
|===============================================================                |  79%    8 MB
|===============================================================                |  79%    8 MB
|================================================================               |  80%    8 MB
|================================================================               |  80%    8 MB
|=================================================================              |  81%    9 MB
|=================================================================              |  82%    9 MB
|==================================================================             |  82%    9 MB
|==================================================================             |  83%    9 MB
|===================================================================            |  83%    9 MB
|===================================================================            |  84%    9 MB
|====================================================================           |  85%    9 MB
|====================================================================           |  85%    9 MB
|=====================================================================          |  86%    9 MB
|=====================================================================          |  86%    9 MB
|=====================================================================          |  87%    9 MB
|======================================================================         |  88%    9 MB
|======================================================================         |  88%    9 MB
|=======================================================================        |  89%    9 MB
|=======================================================================        |  89%    9 MB
|========================================================================       |  90%    9 MB
|========================================================================       |  91%   10 MB
|=========================================================================      |  91%   10 MB
|=========================================================================      |  92%   10 MB
|==========================================================================     |  92%   10 MB
|==========================================================================     |  93%   10 MB
|===========================================================================    |  94%   10 MB
|===========================================================================    |  94%   10 MB
|============================================================================   |  95%   10 MB
|============================================================================   |  95%   10 MB
|=============================================================================  |  96%   10 MB
|=============================================================================  |  97%   10 MB
|============================================================================== |  97%   10 MB
|============================================================================== |  98%   10 MB
|===============================================================================|  98%   10 MB
|===============================================================================|  99%   10 MB
|================================================================================| 100%   11 MB

Aggregate by County

ucr2 <- left_join(ucr, ucr_geo)
Joining, by = "ORI"
ucr2 <- ucr2 %>% arrange(YEAR, State, county, FIPS, OFFENSE) 
##Fix Philly.
ucr2 <- ucr2 %>% 
  dplyr::mutate(
  FIPS=replace(FIPS, which(ORI == "PAPEP00"), 42101)
) %>% 
  dplyr::rename(year=YEAR) %>% ungroup() %>% 
  dplyr::select(-c(STATE, STNAME, COUNTY, county, AGENCY, ORI, OFFENSE)) %>% 
  dplyr::filter(!is.na(FIPS))
ucr2 <- ucr2 %>% 
  dplyr::group_by(year, State, FIPS, crime) %>%
  dplyr::summarise_each_(funs(sum(., na.rm = TRUE)),
                  names(ucr2)[c(2:53)])
`summarise_each()` is deprecated.
Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
To map `funs` over a selection of variables, use `summarise_at()`

4. Arrests by Sex & Age by County

{Note: I’ve decided to keep these two files separate. When writing to .csv files, combined they are approx. 37KB. When combining these data frames using dplyr::full_join, for instance, the total file size exceeds 1GB.}

ucr_age_sex <- ucr2 %>% 
  dplyr::select(-c(AW, JW, AB, JB, AA, JA, AI, JI)) %>% 
  dplyr::group_by(year, State, FIPS, crime) %>% 
  ## Convention:  first letter = gender (M,F,B), 
  ##then age group, matching census age groups
  ## B = Both Genders
  ## All = all ages
  dplyr::mutate_all(as.numeric) %>% 
  dplyr::summarise(
    MAll=sum( c(M0_9, M10_12, M13_14, M15, M16, M17, M18, M19,     
                M20, M21,M22,M23,M24,M25_29,M30_34,M35_39,M40_44,
                M45_49,M50_54,M55_59,M60_64,M65), na.rm=T), 
    ##Census: AGEGRP=0
    FAll=sum( c( F0_9,  F10_12,  F13_14,  F15,  F16,  F17,  F18,  F19,     
                   F20,  F21, F22, F23, F24, F25_29, F30_34, F35_39, F40_44,
                   F45_49, F50_54, F55_59, F60_64, F65), na.rm=T), 
    ##Census: AGEGRP=0
    
    BAll=MAll+FAll,
    
    ##Males
    MUnder15=sum(c(M0_9, M10_12, M13_14), na.rm=T), ##Census: AGEGRP=1,2,3
    M15_19=sum(c( M15, M16, M17, M18, M19), na.rm=T), ##Census: AGEGRP=4
    M20_24=sum(c(M20, M21,M22,M23,M24), na.rm=T), ##Census: AGEGRP=5
    M25_29=M25_29, ##Census: AGEGRP=6
    M30_34=M30_34, ##Census: AGEGRP=7
    M35_39=M35_39, ##Census: AGEGRP=8
    M40_44=M40_44, ##Census: AGEGRP=9
    M45_49=M45_49, ##Census: AGEGRP=10
    M50_54=M50_54, ##Census: AGEGRP=11
    M55_59=M55_59, ##Census: AGEGRP=12
    M60Above=sum(c(M60_64,M65), na.rm=T), ##Census: AGEGRP=13-18
    
    FUnder15=sum(c(F0_9, F10_12, F13_14), na.rm=T), ##Census: AGEGRP=1,2,3
    F15_19=sum(c( F15, F16, F17, F18, F19), na.rm=T), ##Census: AGEGRP=4
    F20_24=sum(c(F20, F21,F22,F23,F24), na.rm=T), ##Census: AGEGRP=5
    F25_29=F25_29, ##Census: AGEGRP=6
    F30_34=F30_34, ##Census: AGEGRP=7
    F35_39=F35_39, ##Census: AGEGRP=8
    F40_44=F40_44, ##Census: AGEGRP=9
    F45_49=F45_49, ##Census: AGEGRP=10
    F50_54=F50_54, ##Census: AGEGRP=11
    F55_59=F55_59, ##Census: AGEGRP=12
    F60Above=sum(c(F60_64,F65), na.rm=T), ##Census: AGEGRP=13-18
    
    BUnder15=FUnder15+MUnder15,  ##Census: AGEGRP=1,2,3
    B15_19=F15_19+M15_19, ##Census: AGEGRP=4
    B20_24=F20_24+M20_24, ##Census: AGEGRP=5
    B25_29=F25_29+M25_29, ##Census: AGEGRP=6
    B30_34=F30_34+M30_34, ##Census: AGEGRP=7
    B35_39=F35_39+M35_39, ##Census: AGEGRP=8
    B40_44=F40_44+M40_44, ##Census: AGEGRP=9
    B45_49=F45_49+M45_49, ##Census: AGEGRP=10
    B50_54=F50_54+M50_54, ##Census: AGEGRP=11
    B55_59=F55_59+F55_59, ##Census: AGEGRP=12
    B60Above=M60Above+F60Above ##Census: AGEGRP=13-18
    ) %>% 
  tidyr::gather("sex_age", "freq", 5:40) %>% 
  tidyr::separate(sex_age, into=c("gender", "age"), sep=1) %>% 
  dplyr::mutate(gender=replace(gender, which(gender=="M"), "Male"),
         gender=replace(gender, which(gender=="F"), "Female"),
         gender=replace(gender, which(gender=="B"), "Both")
         ) %>% 
 tidyr::spread(crime, freq) %>%
 dplyr::mutate(
 #for Counties that reported to UCR but not specific crimes such as murder,
 #treating these as zeros for aggregating Violent Crime Rates
 murder=replace(murder, which(is.na(murder)), 0),
 rape=replace(rape, which(is.na(rape)), 0),
 robbery=replace(robbery, which(is.na(robbery)), 0),
 assault=replace(assault, which(is.na(assault)), 0),
 ViolentCrime = murder+rape+robbery+assault) %>%
  arrange(year, State, FIPS, gender, age)

5. Arrests by Race by County

##UCR Race
ucr_race <- ucr2 %>% 
  dplyr::group_by(year, State, FIPS, crime) %>% 
  dplyr::select(year, State, FIPS, 
        crime, JW, JB, JI, JA, AW, AB, AI, AA) %>% 
  dplyr::mutate(
    White= AW + JW,
    Black=AB + JB,
    Asian=AA + JA,
    Amerindian= AI + JI) %>% 
dplyr::select(-c(AW, JW, AB, JB, AA, JA, AI, JI)) %>% 
tidyr::gather("Race", "freq", 5:8) %>% 
tidyr::spread(crime, freq) %>%
dplyr::mutate(
   Race=replace(Race, which(Race=="Amerindian"), "Native American"),
   murder=replace(murder, which(is.na(murder)), 0),
   rape=replace(rape, which(is.na(rape)), 0),
   robbery=replace(robbery, which(is.na(robbery)), 0),
   assault=replace(assault, which(is.na(assault)), 0),
   ViolentCrime = murder+rape+robbery+assault) %>%
dplyr::group_by(year, State, FIPS, Race) %>% 
dplyr::mutate(
    drugs = sum(c(drug_poss, drug_sale), na.rm=T)
  ) %>% 
dplyr::select(-drug_sale, -drug_poss) %>% 
  dplyr::arrange(year, State, FIPS, Race)

6. FLORIDA

Florida arrest data are not included in the UCR. Here I include Florida arrest data, taken from the excel file “Arrests by County, Age, Sex and Offense for Florida, 2004 - 2015” available on the Florida Department of Law Enforcement website: http://www.fdle.state.fl.us/cms/FSAC/Data-Statistics/UCR-Arrest-Data.aspx

Note that the Florida offense codes don’t exactly match the UCR. The UCR murder code is for “Murder and non-negligent manslaughter”, whereas the Florida records are separate for murder and for manslaughter. The UCR also distinguishes between “Manslaughter by negligence” and “Murder and non-negligent manslaughter”, whereas Florida records only indicate one category for manslaughter.

Florida also does not report separate categories for drug sales and drug possession arrests. I therefore conflate the categories in the rest of the UCR.

##Adding FIPS codes to Florida
#setwd("createData")
require(noncensus)
  data(counties)
  counties <- sapply(counties, as.character) %>% tibble::as_data_frame()
  cnty_df <- counties[which(counties$state=="FL"),c("county_name", "state", "FIPS")]
  names(cnty_df) <- c("county", "state", "FIPS")
  cnty_df$county  <- tolower(trimws(gsub("[[:punct:]]", "", cnty_df$county)))
  cnty_df$county <- gsub(" county| parish| borough", "", cnty_df$county, fixed = FALSE)
florida <- readr::read_csv("createData/floridaArrest_2011_2015.csv") %>% 
  tidyr::gather(Race, freq, 6:9) %>% 
  tidyr::spread(crime, freq) %>% 
  dplyr::mutate(
    murder = murder_a + manslaughter,
    theft = buy_receive_possess_stolen_property + larceny + motor_vehicle_theft,
    ViolentCrime = murder+rape+robbery+assault,
    county = tolower(trimws(gsub("[[:punct:]]", "", county)))
  ) %>% 
  dplyr::select(-murder_a, -manslaughter, -buy_receive_possess_stolen_property, -larceny, -motor_vehicle_theft) %>% 
  dplyr::left_join(cnty_df)
Parsed with column specification:
cols(
  State = col_character(),
  state = col_character(),
  year = col_integer(),
  county = col_character(),
  crime = col_character(),
  White = col_double(),
  Black = col_double(),
  `Native American` = col_double(),
  Asian = col_double()
)
Joining, by = c("state", "county")
unique(florida$county[which(is.na(florida$FIPS))])
[1] "osecola"

Fixing missing counties

Osecola county was not recognized. Entering it manually.

florida <- florida %>% 
  dplyr::mutate(
    FIPS=replace(FIPS, which(county=="osecola"), "`12097")
  )
unique(florida$county[which(is.na(florida$FIPS))])
character(0)

Adding Florida to the UCR_Race dataset.

uVars <- names(ucr_race)
florida <- florida[,which(names(florida) %in% uVars)]
ucr_race <- ucr_race %>% 
  dplyr::bind_rows(florida)

7. NYC Arrest Data

The UCR Data only contains information for Manhattan, NY - FIPS code 36061. Manhattan is also called ‘New York County.’ It does not include data from: Kings County (Brooklyn, 36047), Queens (36081), The Bronx (36005), Staten Island (36085)

The ORI codes for which arrest data are reported in the UCR for FIPS 36061 includes: - NY03083 (NYC METRO TRNSPRTN AUTH) - NY330SS (SP: NEW YORK COUNTY) - NY03031 (ST PRK: NEW YORK CITY RE)

Further, the only ORI7 code listed in the UCR files as Group “1A”, indicating a city larger than 1 Million, is NY03030, (in the CrossWalk identified as “NEW YORK CITY POLICE DEPARTMENT”), which contains only missing values, i.e. no arrests are reported. Right now, ZERO murders are reported for NYC for example, from 2013-2015. The Law Enforcement Management and Administrative Statistics (LEMAS) data also reports police officers for ORI7 district NY03030.

To resolve these problems I aggregate NYC into one county across all datasets using county code 36061 (Manhattan or New York County). Because arrest data are incomplete from the UCR, I use the New York City Police Department’s “Crime and Enforcement Activity in New York City” report, available from: http://www.nyc.gov/html/nypd/html/analysis_and_planning/crime_and_enforcement_activity.shtml

Specifically, I use the file “Enforcement Report Data Tables 2008-2015”, http://www.nyc.gov/html/nypd/downloads/zip/analysis_and_planning/crime_and_enforcement_report_data_tables_2008-2015_2016-02.zip

Unlike the UCR Data, the NYC arrest data distinguishes Hispanics and Non-Hispanic Whites. To make this data consistent with the UCR data, I collapse Hispanic and White into a single ‘White’ racial category.

#setwd("createData")
nyc <- read_csv("createData/nycArrests.csv") %>% 
  dplyr::filter(year<2015) %>% 
  dplyr::mutate(
    Race=replace(Race, which(Race=="Hispanic"), "White"),
    FIPS="36061",
    State="NEW YORK"
  ) %>% 
  dplyr::group_by(year, State, FIPS, Race) %>% 
  dplyr::summarise_all(sum, na.rm=T)
Parsed with column specification:
cols(
  year = col_integer(),
  Race = col_character(),
  murder = col_integer(),
  rape = col_integer(),
  robbery = col_integer(),
  assault = col_integer(),
  ViolentCrime = col_integer(),
  theft = col_integer()
)
nyFips <- c("36061", "36047", "36081", "36005", "36085")
ucr_race <- ucr_race %>% 
  dplyr::filter(!(FIPS %in% nyFips)) %>% 
  dplyr::bind_rows(nyc)

8. Create Race Crime Rate Variables

Attach county-level Census Population Data

# if(exists("census_county")==FALSE){
#   census_county <- fst::read.fst("createData/census_county.csv")
# }
census_race <- census_county %>% 
  dplyr::ungroup() %>% 
  dplyr::filter(gender == "Both", age == "All") %>% 
  dplyr::select(-gender, -age, -state, -county)
ucr_race2 <- ucr_race 
##Fixing fips that begin with 0
for(i in 1:nrow(ucr_race2)){
  if(nchar(ucr_race2$FIPS[i])==4){
    ucr_race2$FIPS[i] <- paste0("`0", as.character(ucr_race2$FIPS[i]))
  } else {
  if(nchar(ucr_race2$FIPS[i])==5){
      ucr_race2$FIPS[i] <- paste0("`", as.character(ucr_race2$FIPS[i]))
    } 
  }
}
  
ucr_race2 <- ucr_race2 %>% dplyr::left_join(census_race)
Joining, by = c("year", "FIPS", "Race")

Creating Crime Rate Variables by Race

crimeVars <- c("murder", "vc", "dui", "vandal", "theft", "drugs")
#florida_fips <- unique(ucr_race2$FIPS[which(ucr_race2$State=="FLORIDA")])
UCRData <-  ucr_race2 %>% 
  dplyr::group_by(year, FIPS) %>% 
    #mutate(State=stateFromLower(tolower(State), rev=T)) %>% 
    ##selecting, changing names, dropping all other vars
    dplyr::transmute(
      Race=Race, 
      murder=murder, 
      vc=ViolentCrime, 
      dui=dui, 
      vandal=vandalism, 
      theft=theft, 
      drugs=drugs,
      #drug_poss=drug_poss, 
      #drug_sale=drug_sale, 
      popUCR.c=population) %>% 
  dplyr::group_by(year, FIPS) %>% 
  mutate_at(crimeVars, funs(replace(., is.na(.), 0))) %>% ##Converting missing to zeros for counties reporting to UCR
  ##Frequencies
  mutate_at(crimeVars, funs("white" = .[which(Race=="White")])) %>% 
  mutate_at(crimeVars, funs("black" = .[which(Race=="Black")])) %>% 
  mutate_at(crimeVars, funs("asian" = .[which(Race=="Asian")])) %>% 
  mutate_at(crimeVars, funs("amerindian" = .[which(Race=="Native American")])) %>% 
  ##Rates 
  mutate_at(crimeVars, funs("white_r" = .[which(Race=="White")] / popUCR.c[which(Race=="White")])) %>% 
  mutate_at(crimeVars, funs("black_r" = .[which(Race=="Black")] / popUCR.c[which(Race=="Black")])) %>% 
  mutate_at(crimeVars, funs("asian_r" = .[which(Race=="Asian")] / popUCR.c[which(Race=="Asian")])) %>% 
  mutate_at(crimeVars, funs("amerindian_r" = .[which(Race=="Native American")] / popUCR.c[which(Race=="Native American")])) %>% 
  
  ##Now convert original crime vars to "Total" - all races. Will not be labelled
  mutate_at(crimeVars, funs(sum(as.numeric(.), na.rm=T))) %>% 
  mutate_at(crimeVars, funs("r" = sum(as.numeric(.), na.rm=T) / sum(as.numeric(popUCR.c), na.rm=T))) %>% ##Total 
 ##create average over years
dplyr::group_by(FIPS) %>% 
  ##Averaged aross 2011-2015  
  mutate_if(is.numeric, funs("5yr" = mean(., na.rm=T))) %>%
  mutate_if(is.numeric, funs(replace(., is.nan(.), NA))) %>% 
  mutate_if(is.numeric, funs(replace(., is.infinite(.), NA))) 
Adding missing grouping variables: `year`, `FIPS`
##Save File, so this code in above chunks can be skipped.
##readr::write_csv(UCRData, path="createData/UCRData.csv")
fst::write.fst(UCRData, path="createData/UCRData.csv")   
  

IV. SEDA Variables - ELA, Math, Segregation, Gini, SES composite

Sean F. Reardon, Demetra Kalogrides, Andrew Ho, Ben Shear, Kenneth Shores, Erin Fahle. (2016). Stanford Education Data Archive (Version 1.1 File Title). http://purl.stanford.edu/db586ns4974.

File - district covariates by year and grade (long file).csv

1. Load SES and Frequency of Students Variables - Averaging across years

Converted files to fst format for faster loading.

totenrl = Number of Students in Grade

nsch = Number of Schools in the District

NYC schools are already aggregated, but no county FIPS codes are provided. This has to be done manually to avoid losing all NYC cases. .* leaid = “3620580” .* leaname = “NEW YORK CITY PUBLIC SCHOOLS”

Notes on variables: .* ses_all: “computed as the first principal component factor score of the following measures: median income, percent with a bachelor’s degree or higher, poverty rate, SNAP rate, single mother headed household rate, and unemployment rate”; does not vary by grade or year; original data source is ACS.

.* “theil_whiteBlack” is labelled “hswhtblk” in the SEDA dataset: Information index between schools: White/Black. “the information theory index is computed as the average deviation of each student’s school racial diversity from the district-wide racial diversity. Values of 0 indicate no segregation while values of 1 indicate complete segregation. See Theil (1972) for more informaiton”

.* gini_all “computed using counts of people in each of 16 income categories; using the rpme – Robust Pareto midpoint estimator– implemented in Stata by von Hippel and Powers”

##  "district covariates by year and grade (long file).csv"
#seda_ses <- readr::read_csv(choose.files())
seda_ses <- fst::read.fst("createData/seda_ses_fst.csv") 
seda_ses_covars <- seda_ses %>%
dplyr::mutate(countyid = replace(countyid, which(leaname == "NEW YORK CITY PUBLIC SCHOOLS" | leaid == "3620580"), "36061")) %>% 
dplyr::group_by(leaid)  %>% 
dplyr::summarise(
  FIPS = first(countyid),
  ##all students, across all grades - used for weighted averaging ses vars
  totalStudents_white = sum(wht, na.rm=T),
  totalStudents_black = sum(blk, na.rm=T),
  totalStudents_asian = sum(asn, na.rm=T),
  totalStudents_hisp = sum(hsp, na.rm=T),
  totalStudents_amer = sum(ind, na.rm=T),
  totalStudents_all = sum(totenrl, na.rm=T),
  seda_6thGraders_total = sum(totenrl[which(grade == 6)], na.rm=T),
  seda_7thGraders_total = sum(totenrl[which(grade == 7)], na.rm=T),
  seda_8thGraders_total = sum(totenrl[which(grade == 8)], na.rm=T),
  
  ses_all = weighted.mean(sesall[which(!is.na(totalStudents_all))], 
                          w=totalStudents_all[which(!is.na(totalStudents_all))], na.rm=T),
  theil_whiteBlack = weighted.mean(hswhtblk[which(!is.na(totalStudents_all))], 
                                   w=totalStudents_all[which(!is.na(totalStudents_all))], na.rm=T),
  gini_all = weighted.mean(giniall[which(!is.na(totalStudents_all))], 
                           w=totalStudents_all[which(!is.na(totalStudents_all))], na.rm=T)
  ) %>% 
  dplyr::mutate_all(funs(replace(., is.nan(.), NA))) 

2. 6th & 8th grade ELA and Math scores

SEDA File: “district means national-referenced by year grade subject (long file)_v1_1.csv" File description: “This file contains district level means in NAEP-referenced units. Estimates are comparable between states. There are multiple observations per district; one for each year, grade and subject.” File: MeanG_V1.1

ELA scores for 6th and 8th graders, averaged across district and then county across years 2009-2013.

Weighted mean function returns missing values if values for weights (grade-specific populations) are missing, so filtering to cases where number of students in respective grade is reported.

#setwd("createData")
seda_scores <- read_csv("createData/district means national-referenced by year grade subject (long file)_v1_1.csv") %>% 
  dplyr::filter(grade %in% c("08", "06")) %>% 
  dplyr::mutate(
    leaid = ifelse(nchar(leaid) == 6, paste0("0", as.character(leaid)), as.character(leaid))
  ) %>% 
  dplyr::group_by(leaid) %>% 
  dplyr::summarise(
    ELA_8thgrade = mean(mean_link_ela[which(grade=="08")], na.rm=T),
    MATH_8thgrade = mean(mean_link_math[which(grade=="08")], na.rm=T),
    ##6th grade has a lot fewer missing values - e.g. Los Angeles districts didn't report 8th grade data
    ELA_6thgrade = mean(mean_link_ela[which(grade=="06")], na.rm=T),
    MATH_6thgrade = mean(mean_link_math[which(grade=="06")], na.rm=T)
    ) %>% 
  dplyr::mutate_all(funs(replace(., is.nan(.), NA))) 

3. 6th and 7th grade, race gaps in ELA and math

Variables:

.* gapblk_ela = white-black gap in ela .* gapblk_math = white-black gap in math

Number of non-missing cases for ELA gap: .* 8th grade - 10099 .* 7th grade - 10359 .* 6th grade - 10172

Number of non-missing caes for math gap: .* 8th grade - 9280 .* 7th grade - 9350 .* 6th grade - 10309

Using 7th grade ELA and 6th grade math gap estimates.

seda_gaps <- read_csv("createData/district gaps by year grade subject (long file)_v1_1.csv") %>% 
  dplyr::filter(grade %in% c("07","06")) %>% 
  dplyr::mutate(
    leaid = ifelse(nchar(leaid) == 6, paste0("0", as.character(leaid)), as.character(leaid))
  ) %>% 
  dplyr::group_by(leaid) %>% 
  dplyr::summarise(
    ELA_7thgrade_gapblk = mean(gapblk_ela[which(grade=="07")], na.rm=T),
    MATH_6thgrade_gapblk = mean(gapblk_math[which(grade=="06")], na.rm=T)
    ELA_7thgrade_gapblk = replace(ELA_7thgrade_gapblk, is.nan(ELA_7thgrade_gapblk), NA),
    MATH_6thgrade_gapblk = replace(MATH_6thgrade_gapblk, is.nan(MATH_6thgrade_gapblk), NA)
  ) %>% 
  dplyr::mutate_all(funs(replace(., is.nan(.), NA))) 
Parsed with column specification:
cols(
  leaid = col_integer(),
  leaname = col_character(),
  fips = col_integer(),
  stateabb = col_character(),
  year = col_integer(),
  grade = col_character(),
  gapblk_ela = col_double(),
  gapseblk_ela = col_double(),
  gaphsp_ela = col_double(),
  gapsehsp_ela = col_double(),
  gapblk_math = col_double(),
  gapseblk_math = col_double(),
  gaphsp_math = col_double(),
  gapsehsp_math = col_double(),
  racepercent_ela = col_double(),
  racepercent_math = col_double(),
  fipst = col_integer()
)

4. Combine and Aggregate by County

Below the school districts are aggregated by taking their weighted means, weighting by the number of students in each district for each respective grade.

seda <- dplyr::left_join(seda_ses_covars, seda_scores, by=c("leaid")) %>% 
  dplyr::left_join(seda_gaps, by=c("leaid")) %>% 
  dplyr::group_by(leaid) %>% 
  ##Correction for NYC - aggregating
  dplyr::mutate(
    FIPS = paste0("`", FIPS)
  ) %>% 
  dplyr::group_by(FIPS) %>% 
  dplyr::summarise(
    MATH_6thgrade_gap = weighted.mean(MATH_6thgrade_gapblk[which(!is.na(seda_6thGraders_total))], 
                                         w=seda_6thGraders_total[which(!is.na(seda_6thGraders_total))], na.rm=T),
    
    ELA_7thgrade_gap = weighted.mean(ELA_7thgrade_gapblk[which(!is.na(seda_7thGraders_total))], 
                                        w=seda_7thGraders_total[which(!is.na(seda_7thGraders_total))], na.rm=T),
    
    ELA_8thgrade = weighted.mean(ELA_8thgrade[which(!is.na(seda_8thGraders_total))], 
                                 w=seda_8thGraders_total[which(!is.na(seda_8thGraders_total))], na.rm=T),
    
    ELA_6thgrade = weighted.mean(ELA_6thgrade[which(!is.na(seda_6thGraders_total))], 
                                 w=seda_6thGraders_total[which(!is.na(seda_6thGraders_total))], na.rm=T),
    
    MATH_8thgrade = weighted.mean(MATH_8thgrade[which(!is.na(seda_8thGraders_total))], 
                                 w=seda_8thGraders_total[which(!is.na(seda_8thGraders_total))], na.rm=T),
    
    MATH_6thgrade = weighted.mean(MATH_6thgrade[which(!is.na(seda_6thGraders_total))], 
                                 w=seda_6thGraders_total[which(!is.na(seda_6thGraders_total))], na.rm=T),
    
    
  ses_all = weighted.mean(ses_all[which(!is.na(totalStudents_all))], 
                          w=totalStudents_all[which(!is.na(totalStudents_all))], na.rm=T),
  theil_whiteBlack = weighted.mean(theil_whiteBlack[which(!is.na(totalStudents_all))], 
                                   w=totalStudents_all[which(!is.na(totalStudents_all))], na.rm=T),
  gini_all = weighted.mean(gini_all[which(!is.na(totalStudents_all))], 
                           w=totalStudents_all[which(!is.na(totalStudents_all))], na.rm=T)
  

V. ACS (American Community Survey)

1. Median Income by Race ACS (American Community Survey)

Further income data, disaggregated by race, are taken from the American Community Survey, “2011-2015 American Community Survey 5-Year Estimates”, available online at https://factfinder.census.gov/faces/affhelp/jsf/pages/metadata.xhtml?lang=en&type=dataset&id=dataset.en.ACS_15_5YR

Options:

  • Median Earnings, or
  • Median Household Income, or
  • Median Family Income, or
  • per capita income

Race-specific median family incomes by county were retrieved from the following files:

  1. [White] B19113A - MEDIAN FAMILY INCOME IN THE PAST 12 MONTHS (IN 2015 INFLATION-ADJUSTED DOLLARS) (WHITE ALONE HOUSEHOLDER).

  2. [Black] B19113B - MEDIAN FAMILY INCOME IN THE PAST 12 MONTHS (IN 2015 INFLATION-ADJUSTED DOLLARS) (BLACK OR AFRICAN AMERICAN ALONE HOUSEHOLDER)

  3. [White Non-Hispanic] B19113H - MEDIAN FAMILY INCOME IN THE PAST 12 MONTHS (IN 2015 INFLATION-ADJUSTED DOLLARS) (WHITE ALONE, NOT HISPANIC OR LATINO HOUSEHOLDER)

  4. [Hispanic] B19113I - MEDIAN FAMILY INCOME IN THE PAST 12 MONTHS (IN 2015 INFLATION-ADJUSTED DOLLARS) (HISPANIC OR LATINO HOUSEHOLDER)

  5. [All] B19113 - MEDIAN FAMILY INCOME IN THE PAST 12 MONTHS (IN 2015 INFLATION-ADJUSTED DOLLARS)

Aggregating the NYC burroughs using the median incomes of median incomes for each burrough.

#setwd("createData")
nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
inc_all <- read_csv("createData/ACS_medianIncome.csv") %>% 
  dplyr::mutate(
    Race = "Total"
  ) %>% 
  tidyr::separate(county, into=c("county", "stateName"), sep=",")
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  medianIncome = col_double()
)
inc_white <- read_csv("createData/ACS_medianIncome_white.csv") %>% 
  dplyr::mutate(
    Race = "White"
  ) %>% 
  tidyr::separate(county, into=c("county", "stateName"), sep=",") 
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  medianIncome = col_integer()
)
inc_black <- read_csv("createData/ACS_medianIncome_black.csv") %>% 
    dplyr::mutate(
    Race = "Black"
  ) %>% 
  tidyr::separate(county, into=c("county", "stateName"), sep=",")
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  medianIncome = col_number()
)
inc_white_nh <- read_csv("createData/ACS_medianIncome_white_NH.csv") %>% 
    dplyr::mutate(
    Race = "White_NH"
  ) %>% 
  tidyr::separate(county, into=c("county", "stateName"), sep=",")
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  medianIncome = col_integer()
)
inc_hisp <- read_csv("createData/ACS_medianIncome_hispanic.csv") %>% 
    dplyr::mutate(
    Race = "Hispanic"
  ) %>% 
  tidyr::separate(county, into=c("county", "stateName"), sep=",") 
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  medianIncome = col_number()
)
inc_df <- dplyr::bind_rows(inc_all, inc_white, inc_white_nh, inc_black, inc_hisp) %>% 
  tidyr::spread(Race, medianIncome) %>% 
    dplyr::rename(
    medianIncome = Total,
    medianIncome_white = White,
    medianIncome_black = Black,
    medianIncome_white_nh = White_NH,
    medianIncome_hisp = Hispanic
  ) %>% 
dplyr::select(-county, -stateName)
##Fixing fips that begin with 0
for(i in 1:nrow(inc_df)){
  if(nchar(inc_df$fips[i])==4){
    inc_df$fips[i] <- paste0("`0", as.character(inc_df$fips[i]))
  } 
  if(nchar(inc_df$fips[i])==5){
    inc_df$fips[i] <- paste0("`", as.character(inc_df$fips[i]))
  } 
  
}
inc_df <- inc_df %>% 
   dplyr::rename(FIPS=fips) %>% 
  dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  ) %>% 
    dplyr::group_by(FIPS) %>% 
  dplyr::summarise_all(median, na.rm=T)

2. Poverty. ACS (American Community Survey)

Poverty [Total and by Race] S1702 - POVERTY STATUS IN THE PAST 12 MONTHS OF FAMILIES

– HC02_EST_VC01 - All families - Percent below poverty level; Estimate; Families

– HC02_EST_VC09 - All families - Percent below poverty level; Estimate; RACE AND HISPANIC OR LATINO ORIGIN - Families with a householder who is White alone"

– HC02_EST_VC10 - All families - Percent below poverty level; Estimate; RACE AND HISPANIC OR LATINO ORIGIN - Families with a householder who is Black or African American alone

– HC02_EST_VC11 - All families - Percent below poverty level; Estimate; RACE AND HISPANIC OR LATINO ORIGIN - Families with a householder who is American Indian and Alaska Native alone

–HC02_EST_VC12 - All families - Percent below poverty level; Estimate; RACE AND HISPANIC OR LATINO ORIGIN - Families with a householder who is Asian alone

– HC02_EST_VC13 - All families - Percent below poverty level; Estimate; RACE AND HISPANIC OR LATINO ORIGIN - Families with a householder who is Native Hawaiian and Other Pacific Islander alone

– HC02_EST_VC17 - All families - Percent below poverty level; Estimate; Hispanic or Latino origin (of any race)

– HC02_EST_VC18 - All families - Percent below poverty level; Estimate; White alone, not Hispanic or Latino

#setwd("createData")
nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
pov <- read_csv("createData/ACS_poverty.csv") %>% 
  dplyr::select(-county)
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  poverty = col_double(),
  poverty_white = col_double(),
  poverty_black = col_double(),
  poverty_amerindian = col_double(),
  poverty_asian = col_double(),
  poverty_hawaiian = col_double(),
  poverty_hispanic = col_double(),
  poverty_white_nh = col_double()
)
##Fixing fips that begin with 0
for(i in 1:nrow(pov)){
  if(nchar(pov$fips[i])==4){
    pov$fips[i] <- paste0("`0", as.character(pov$fips[i]))
  } 
  if(nchar(pov$fips[i])==5){
    pov$fips[i] <- paste0("`", as.character(pov$fips[i]))
  } 
  
}
pov <- pov %>% 
   dplyr::rename(FIPS=fips) %>% 
    dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  ) %>% 
    group_by(FIPS) %>% 
  dplyr::summarise_all(median, na.rm=T)

3. Gini Index ACS (American Community Survey)

#setwd("createData")
nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
gini <- read_csv("createData/ACS_gini_5yr.csv") %>% 
  dplyr::select(-county)
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  gini = col_double()
)
##Fixing fips that begin with 0
for(i in 1:nrow(gini)){
  } 
  if(nchar(gini$fips[i])==5){
    gini$fips[i] <- paste0("`", as.character(gini$fips[i]))
  } 
}
gini <- gini %>% 
  dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  ) %>% 
    group_by(FIPS) %>% 
  dplyr::summarise_all(median, na.rm=T)

4. Single-Parent-Headed Households % ACS (American Community Survey)

– B11001 - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE)”

– B11001A - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE) (WHITE ALONE)”

– B11001B - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE) (BLACK OR AFRICAN AMERICAN ALONE)”

– B11001C - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE) (AMERICAN INDIAN AND ALASKA NATIVE ALONE)”

– B11001D - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE) (ASIAN ALONE)”

– B11001E - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE) (NATIVE HAWAIIAN AND OTHER PACIFIC ISLANDER ALONE)”

– B11001H - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE) (WHITE ALONE, NOT HISPANIC OR LATINO)”

– B11001I - “HOUSEHOLD TYPE (INCLUDING LIVING ALONE) (HISPANIC OR LATINO)”

From each dataset two variables are extracted:

  1. “Estimate; Family households” [HD01_VD02]

  2. “Estimate; Family households: - Other family: - Female householder, no husband present” [HD01_VD06]

#setwd("createData")
nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
sp_total <- read_csv("createData/ACS_singleParent_total.csv") %>% 
  dplyr::mutate(singleParent_prcnt = singleParent/totalFamilies)
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  totalFamilies = col_integer(),
  singleParent = col_integer()
)
sp_white <- read_csv("createData/ACS_singleParent_white.csv") %>% 
    dplyr::mutate(
      singleParent_prcnt_white = ifelse(families_white>0,
                                        singleParent_white/families_white,0)
    )
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  families_white = col_integer(),
  singleParent_white = col_integer()
)
sp_white_nh <- read_csv("createData/ACS_singleParent_white_nh.csv") %>% ##nonhispanic white
      dplyr::mutate(
        singleParent_prcnt_white_nh = ifelse(families_white_nh > 0,
                                             singleParent_white_nh/families_white_nh, 0)
      )
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  families_white_nh = col_integer(),
  singleParent_white_nh = col_integer()
)
sp_black <- read_csv("createData/ACS_singleParent_black.csv") %>% 
      dplyr::mutate(
        singleParent_prcnt_black = ifelse(families_black > 0,
                                          singleParent_black/families_black,  0)
)
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  families_black = col_integer(),
  singleParent_black = col_integer()
)
      dplyr::mutate(
        singleParent_prcnt_amerindian = ifelse(families_amerindian>0,
                                               singleParent_amerindian/families_amerindian, 0)
      )
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  families_amerindian = col_integer(),
  singleParent_amerindian = col_integer()
)
sp_asian <- read_csv("createData/ACS_singleParent_asian.csv") %>% 
      dplyr::mutate(
        singleParent_prcnt_asian = ifelse(families_asian>0,
                                          singleParent_asian/families_asian, 0)
      )
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  families_asian = col_integer(),
  singleParent_asian = col_integer()
)
sp_hawaiian <- read_csv("createData/ACS_singleParent_hawaiian.csv") %>% 
      dplyr::mutate(
        singleParent_prcnt_hawaiian = ifelse(families_hawaiian>0,
                                             singleParent_hawaiian/families_hawaiian,  0)
      )
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  families_hawaiian = col_integer(),
  singleParent_hawaiian = col_integer()
)
        singleParent_prcnt_hispanic = ifelse(families_hispanic>0,
                                             singleParent_hispanic/families_hispanic, 0)
      )
Parsed with column specification:
cols(
  fips = col_integer(),
  county = col_character(),
  families_hispanic = col_integer(),
  singleParent_hispanic = col_integer()
)
singleParent <- dplyr::left_join(sp_total, sp_white) %>% 
  dplyr::left_join(sp_white_nh) %>% 
  dplyr::left_join(sp_black) %>% 
  dplyr::left_join(sp_amerindian) %>% 
  dplyr::left_join(sp_asian) %>% 
  dplyr::left_join(sp_hawaiian) %>% 
  dplyr::left_join(sp_hispanic) %>% 
  dplyr::select(-county)
Joining, by = c("fips", "county")
Joining, by = c("fips", "county")
Joining, by = c("fips", "county")
Joining, by = c("fips", "county")
Joining, by = c("fips", "county")
Joining, by = c("fips", "county")
Joining, by = c("fips", "county")
  
##Fixing fips that begin with 0
for(i in 1:nrow(singleParent)){
  if(nchar(singleParent$fips[i])==4){
    singleParent$fips[i] <- paste0("`0", as.character(singleParent$fips[i]))
  } 
  } 
}
singleParent <- singleParent %>% 
   dplyr::rename(FIPS=fips) %>% 
  dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
    group_by(FIPS) %>% 
  dplyr::summarise_all(median, na.rm=T)

5. Educational Attainment (less than high school %) ACS (American Community Survey)

EDUCATIONAL ATTAINMENT [Total and by Race] S1501 - EDUCATIONAL ATTAINMENT

HC02_EST_VC03 - “Percent; Estimate; Population 18 to 24 years - Less than high school graduate”

#setwd("createData")
nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
hs <- read_csv("createData/ACS_highschool.csv")
Parsed with column specification:
cols(
  fips = col_integer(),
  highschoolDropOut = col_double()
)
  if(nchar(hs$fips[i])==4){
    hs$fips[i] <- paste0("`0", as.character(hs$fips[i]))
  } 
  if(nchar(hs$fips[i])==5){
    hs$fips[i] <- paste0("`", as.character(hs$fips[i]))
  } 
}
hs <- hs %>% 
dplyr::rename(FIPS=fips) %>% 
dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  ) %>% 
    group_by(FIPS) %>% 
  dplyr::summarise_all(median, na.rm=T)

6. Crowing (ACS) (Occupants per room) (ACS)

[All Races, by Owner or Renter] B25014 - TENURE BY OCCUPANTS PER ROOM To calculate “crowding” we esimate the percentage of households with 1.01 or more occupants per room. We include owners and renters. We use the following variables:

  • HD01_VD01 - “Estimate; Total:”

  • HD01_VD05 - “Estimate; Owner occupied: - 1.01 to 1.50 occupants per room”

  • HD01_VD06 - “Estimate; Owner occupied: - 1.51 to 2.00 occupants per room”

  • HD01_VD07 - “Estimate; Owner occupied: - 2.01 or more occupants per room”

  • HD01_VD11 - “Estimate; Renter occupied: - 1.01 to 1.50 occupants per room”

  • HD01_VD12 - “Estimate; Renter occupied: - 1.51 to 2.00 occupants per room”

  • HD01_VD13 - “Estimate; Renter occupied: - 2.01 or more occupants per room”

#setwd("createData")
crowd <- read_csv("createData/ACS_crowding.csv")
Parsed with column specification:
cols(
  fips = col_integer(),
  crowding_prcnt = col_double()
)
for(i in 1:nrow(crowd)){
  if(nchar(crowd$fips[i])==4){
    crowd$fips[i] <- paste0("`0", as.character(crowd$fips[i]))
  } 
  if(nchar(crowd$fips[i])==5){
    crowd$fips[i] <- paste0("`", as.character(crowd$fips[i]))
  } 
  
crowd <- crowd %>% 
   dplyr::rename(FIPS=fips) %>% 
  dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  dplyr::summarise_all(median, na.rm=T)

7. Residential Segregation - CountyHealthRankings.org from ACS 2016-2017

Averaged across 2016 and 2017 countyhealthrankings.org, “Residential segregation—black/white, 2011-2015, source=ACS”

Description: http://www.countyhealthrankings.org/measure/residential-segregation-blackwhite

“Racial/ethnic residential segregation refers to the degree to which two or more groups live separately from one another in a geographic area. The index of dissimilarity is a demographic measure of the evenness with which two groups (black and white residents, in this case) are distributed across the component geographic areas (census tracts, in this case) that make up a larger area (counties, in this case). The index score can be interpreted as the percentage of either black or white residents that would have to move to different geographic areas in order to produce a distribution that matches that of the larger area.”

#setwd("createData")
seg <- readr::read_csv("createData/segregation_countyhealth.csv") %>% 
  group_by(fips) %>% 
  dplyr::select(-State, -County, -year, -X1) %>% 
  dplyr::summarise_all(mean, na.rm=T) %>% 
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  ) %>% 
    group_by(FIPS) %>% 
  dplyr::summarise_all(median, na.rm=T)
Missing column names filled in: 'X1' [1]Parsed with column specification:
cols(
  X1 = col_integer(),
  fips = col_character(),
  State = col_character(),
  County = col_character(),
  residential_segregation_black_white = col_integer(),
  residential_segregation_nonwhite_white = col_integer(),
  year = col_integer()
)

VI. BLS Data - Employment (2011-2015 average)

Employment data are derived from the Bureau of Labor Statistics, “Labor Force Data by County, 2015 Annual Averages”. The Local Area Unemployment Statistics (LAUS) are provided at: averages https://www.bls.gov/lau/#tables Specifically, I downloaded the aggregated the following excel files:

  1. Labor force data by county, 2015 annual averages https://www.bls.gov/lau/laucnty15.xlsx

  2. Labor force data by county, 2014 annual averages https://www.bls.gov/lau/laucnty14.xlsx

  3. Labor force data by county, 2013 annual averages https://www.bls.gov/lau/laucnty13.xlsx

  4. Labor force data by county, 2012 annual averages https://www.bls.gov/lau/laucnty12.xlsx

  5. Labor force data by county, 2011 annual averages https://www.bls.gov/lau/laucnty11.xlsx

#setwd("createData")
nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
blsVars <- c("laborForce", "employed", "unemployed", "unemploymentRate")
bls <- read_csv("createData/blsData_2011_2015.csv") %>% 
  dplyr::mutate(
    stateCode = paste0("`", stateCode),
    fips = paste0(stateCode, countyCode),
    fips = replace(fips, which(fips %in% nyFips), "`36061")
  ) %>% 
  dplyr::group_by(fips, year) %>% 
dplyr::group_by(year, fips) %>% 
  mutate_all(sum, na.rm=T) %>%  ##aggregating NYC
  mutate(unemploymentRate = unemployed/laborForce) %>% 
  mutate_at(blsVars, funs("5yr" = mean(., na.rm=T))) %>% 
  mutate_at(blsVars,funs("change" = mean((.[which(year==2015)] - .[which(year==2011)]) / .[which(year==2011)], na.rm=T))) %>% 
  dplyr::filter(year==2015) %>% 
  dplyr::select(-year) %>% 
Parsed with column specification:
cols(
  stateCode = col_character(),
  countyCode = col_character(),
  countyName = col_character(),
  year = col_integer(),
  laborForce = col_integer(),
  employed = col_integer(),
  unemployed = col_integer()
)

VII. POLICE DATA (LEMAS)

Law Enforcement Management and Administrative Statistics (LEMAS) Series from ICPSR (2013). https://www.icpsr.umich.edu/icpsrweb/ICPSR/studies/36164

# Law Enforcement Agency Indentifiers Crosswalk, 2012 (ICPSR 35158)
# https://www.icpsr.umich.edu/icpsrweb/ICPSR/studies/35158
nyFips <- c("36061", "36047", "36081", "36005", "36085")
#setwd("createData")
ucr_geo <-  read_tsv("createData/35158-0001-Data.tsv") %>% 
dplyr::select(ORI7, FIPS )
Parsed with column specification:
cols(
  .default = col_integer(),
  FIPS_ST = col_character(),
  FIPS_COUNTY = col_character(),
  FIPS = col_character(),
  ORI9 = col_character(),
  ORI7 = col_character(),
  NAME = col_character(),
  STATENAME = col_character(),
  COUNTYNAME = col_character(),
  UANAME = col_character(),
  LG_NAME = col_character(),
  ADDRESS_NAME = col_character(),
  ADDRESS_STR1 = col_character(),
  ADDRESS_STR2 = col_character(),
  ADDRESS_CITY = col_character(),
  ADDRESS_STATE = col_character(),
  LEMAS_ID = col_character(),
  U_POPGRP = col_character(),
  COMMENT = col_character(),
  INTPTLAT = col_double(),
  INTPTLONG = col_double()
  # ... with 3 more columns
)
See spec(...) for full column specifications.
police <- haven::read_stata("createData/36164-0001-Data.dta") %>% 
  dplyr::select(
                ORI7, 
                PERS_RESP_PATRL, #primary duty - patrol
                PERS_RESP_INVST, #primary duty - investigative
                FTSWORN,  #TOTAL NUMBER OF SWORN PERSONNEL - fulltime
                PERS_FTS_BLK, #TOTAL NUMBER OF SWORN PERSONNEL - fulltime - Black
                COM_MIS, #COMMUNITY POLICING COMPONENT IN MISSION STATEMENT
                ## 1 = No written mission statement
                ## 2 = Written statement, no community policing component
                #FINALWT #FINAL WEIGHT FOR EACH STRATUM
                ) %>% 
    policeFullTime = FTSWORN,
    policeFemale = PERS_PDSW_FFT,
    policeBlack = PERS_FTS_BLK,
    policePatrol=PERS_RESP_PATRL, 
    gunShotDetection=TECH_TYP_GUN) %>% 
  dplyr::left_join(ucr_geo) %>% 
  mutate_all(funs(replace(., is.nan(.), NA))) %>% 
    communityPolice=replace(communityPolice, which(communityPolice==3), TRUE),
    communityPolice=replace(communityPolice, which(communityPolice != 3), FALSE),
    gunShotDetection=replace(gunShotDetection, which(gunShotDetection == 1), TRUE),
  group_by(State, FIPS) %>% 
  dplyr::summarise(
    communityPolice=mean(communityPolice, na.rm=T),
    gunShotDetection=mean(gunShotDetection, na.rm=T),
    policeFullTime=sum(policeFullTime, na.rm=T),
  ) %>% 
  dplyr::mutate(
    policeFullTime_log=log(policeFullTime),
    policePrcntBlack = 100*policeBlack/policeFullTime,
    policePatrol_log = log(1+policePatrol),
    policeInvestigate_log = log(1+policeInvestigate)
  ) %>% 
  ungroup() %>% 
  dplyr::filter(!is.na(FIPS)) %>% 
  dplyr::mutate(FIPS=paste("`", as.character(FIPS), sep="")) %>% 
  dplyr::select(-State)
Joining, by = "ORI7"
Column `ORI7` has different attributes on LHS and RHS of join
  
#fst::write.fst(police, path="police.csv")

VIII. Land Area (Census)

Land Area estimates from: https://www.census.gov/support/USACdataDownloads.html

‘Land Area’ file “LND01.xls”.
Variable: LND110210D, “Land area in square miles 2010”

nyFips <- c("`36061", "`36047", "`36081", "`36005", "`36085")
library(dplyr)
area <- readr::read_csv("createData/LND01.csv") %>% 
  dplyr::select(Areaname, STCOU, LND110210D) %>% 
  dplyr::mutate(
    stateCode = substr(STCOU, start=3, stop=5)
  ) %>% 
  dplyr::filter(stateCode != "000") %>%   ##getting rid of state totals
  dplyr::transmute(
    FIPS = paste0("`", STCOU),
    landArea = LND110210D
  ) %>% 
  dplyr::filter(landArea > 0) %>% 
  dplyr::mutate(
    FIPS = replace(FIPS, which(FIPS %in% nyFips), "`36061")
  ) %>% 
  dplyr::group_by(FIPS) %>% 
  dplyr::summarise(
    landArea = sum(landArea, na.rm=TRUE)
  )
##eliminating 3 cases that aren't in the other data files with size 0
#Clifton Forge, VA, `51560 %>% 
#South Boston, VA, `51780

IX. Combine all Variables

if(exists("UCRData")==FALSE){
  UCRData <- fst::read.fst("createData/UCRData.csv")
}
countyVars <- census_vars %>% 
  dplyr::left_join(seda) %>%
  dplyr::left_join(police) %>% 
  dplyr::left_join(area) %>% 
  dplyr::left_join(bls) %>% 
  dplyr::left_join(inc_df) %>% 
  dplyr::left_join(pov) %>% 
  dplyr::left_join(gini) %>% 
  dplyr::left_join(singleParent) %>% 
  dplyr::left_join(hs) %>% 
  dplyr::left_join(crowd) %>% 
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
Joining, by = "FIPS"
  
fst::write.fst(countyVars, path="countyVars_f.csv")
write.csv(countyVars, file="countyVars.csv")
  

X. Principle Components

1. CRIME

if(exists("countyVars")==TRUE){
  countyVars <- countyVars
} else {
  countyVars <- fst::read.fst("Data/countyVars_f.csv")
} 
##vars <- fst::read.fst("countyVars.csv")
totalCrime <- countyVars[,c("FIPS", "murder_r_5yr", "dui_r_5yr", "vc_r_5yr", "theft_r_5yr", "vandal_r_5yr", "drugs_r_5yr")]
totalCrime <- totalCrime[complete.cases(totalCrime),] 
pc_crime <-  prcomp(~ murder_r_5yr + vc_r_5yr + dui_r_5yr  + vandal_r_5yr + theft_r_5yr + drugs_r_5yr, 
                            data=totalCrime,
                            scale. = T, center=TRUE,
                            na.action=na.omit)
totalCrime$pc1Crime <- pc_crime$x[,1]
totalCrime$pc2Crime <- pc_crime$x[,2]
totalCrime <- totalCrime[,c("FIPS", "pc1Crime", "pc2Crime")]
countyVars <- dplyr::left_join(countyVars, totalCrime)
Joining, by = "FIPS"
##print PCA analysis from FactoMineR
pcFit <- FactoMineR::PCA(countyVars[,c("murder_r_5yr",  "dui_r_5yr", "vc_r_5yr", "theft_r_5yr", "vandal_r_5yr", "drugs_r_5yr")])
Missing values are imputed by the mean of the variable: you should use the imputePCA function of the missMDA package

summary(pcFit)

Call:
FactoMineR::PCA(X = countyVars[, c("murder_r_5yr", "dui_r_5yr",  
     "vc_r_5yr", "theft_r_5yr", "vandal_r_5yr", "drugs_r_5yr")]) 


Eigenvalues
                       Dim.1   Dim.2   Dim.3   Dim.4   Dim.5   Dim.6
Variance               3.178   0.921   0.714   0.496   0.390   0.302
% of var.             52.963  15.346  11.895   8.264   6.497   5.035
Cumulative % of var.  52.963  68.310  80.204  88.468  94.965 100.000

Individuals (the 10 first)
                 Dist    Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr   cos2  
1            |  1.224 | -0.232  0.001  0.036 | -0.387  0.005  0.100 |  0.526  0.012  0.185 |
2            |  1.088 | -0.634  0.004  0.340 | -0.280  0.003  0.066 |  0.576  0.015  0.280 |
3            |  1.396 | -0.211  0.000  0.023 | -0.545  0.010  0.152 |  1.050  0.049  0.565 |
4            |  2.017 |  0.035  0.000  0.000 | -0.468  0.008  0.054 |  1.899  0.161  0.886 |
5            |  2.898 | -0.247  0.001  0.007 | -0.851  0.025  0.086 |  2.592  0.300  0.800 |
6            |  1.807 | -0.819  0.007  0.205 | -0.447  0.007  0.061 |  1.498  0.100  0.687 |
7            |  4.847 |  1.910  0.037  0.155 | -1.611  0.090  0.110 |  3.889  0.675  0.644 |
8            |  1.183 | -0.511  0.003  0.187 | -0.456  0.007  0.148 |  0.669  0.020  0.319 |
9            |  3.767 |  0.965  0.009  0.066 | -1.275  0.056  0.115 |  3.304  0.487  0.769 |
10           |  1.422 |  0.245  0.001  0.030 | -0.097  0.000  0.005 |  0.871  0.034  0.375 |

Variables
                Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr   cos2  
murder_r_5yr |  0.647 13.173  0.419 | -0.230  0.053 |  0.682 65.266  0.466 |
dui_r_5yr    |  0.684 14.718  0.468 |  0.499 26.997  0.249 | -0.061  0.522  0.004 |
vc_r_5yr     |  0.816 20.972  0.666 | -0.201  4.377  0.040 |  0.122  2.079  0.015 |
theft_r_5yr  |  0.805 20.410  0.649 | -0.280  8.509  0.078 | -0.295 12.169  0.087 |
vandal_r_5yr |  0.782 19.233  0.611 | -0.257  7.184  0.066 | -0.374 19.607  0.140 |
drugs_r_5yr  |  0.604 11.494  0.365 |  0.659 47.180  0.434 |  0.050  0.357  0.003 |

2. Crime - Violent Crime, Theft, Vandalism only

if(exists("countyVars")==TRUE){
  countyVars <- countyVars
} else {
  countyVars <- fst::read.fst("Data/countyVars_f.csv")
} 
vCrime <- countyVars[,c("FIPS", "vc_r_5yr", "theft_r_5yr", "vandal_r_5yr")]
vCrime <- vCrime[complete.cases(vCrime),] 
pc_crime <-  prcomp(~  vc_r_5yr +  vandal_r_5yr + theft_r_5yr , 
                            data=vCrime,
                            scale. = T, center=TRUE,
                            na.action=na.omit)
vCrime$pc2Crime_3 <- pc_crime$x[,2]
vCrime <- vCrime[,c("FIPS", "pc1Crime_3", "pc2Crime_3")]
countyVars <- dplyr::left_join(countyVars, vCrime)
Joining, by = "FIPS"
##print PCA analysis from FactoMineR

summary(pcFit)

Call:
FactoMineR::PCA(X = countyVars[, c("vc_r_5yr", "theft_r_5yr",  
     "vandal_r_5yr")]) 


Eigenvalues
                       Dim.1   Dim.2   Dim.3
Variance               2.232   0.457   0.311
% of var.             74.413  15.233  10.354
Cumulative % of var.  74.413  89.646 100.000

Individuals (the 10 first)
                 Dist    Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr   cos2  
1            |  1.031 | -0.180  0.000  0.031 |  0.331  0.008  0.103 | -0.959  0.094  0.866 |
2            |  0.862 | -0.547  0.004  0.403 |  0.388  0.011  0.203 | -0.541 |  0.914 | -0.245  0.001  0.072 |  0.697  0.034  0.582 | -0.538  0.030  0.347 |
4            |  0.883 | -0.566  0.005  0.412 |  0.598  0.025  0.459 | -0.317  0.010  0.129 |
5            |  1.023 | -0.951  0.013  0.864 |  0.307  0.007  0.090 | -0.221  0.005  0.047 |
6            |  1.111 | -1.061  0.016  0.912 |  0.312  0.007  0.079 | -0.106  0.001  0.009 |
7            |  1.512 |  0.525  0.004  0.121 |  0.963  0.065  0.405 | -1.041  0.111  0.474 |
8            |  0.825 | -0.380  0.002  0.212 |  0.483  0.016  0.343 | -0.551  0.031  0.446 |
9            |  1.076 | -0.032  0.000  0.001 |  0.952  0.063  0.783 | -0.500  0.026  0.216 |
10           |  1.064 | -0.057  0.000  0.003 |  0.455  0.014  0.183 | -0.960  0.095  0.814 |

Variables
                Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr   cos2  
vc_r_5yr     |  0.832 31.013  0.692 |  0.540 63.798  0.292 |  0.127  5.189  0.016 |
theft_r_5yr  |  0.891 35.586  0.794 | -0.131  3.756  0.017 | -0.434 60.658  0.188 |
vandal_r_5yr |  0.864 33.401  0.746 | -0.385 32.446  0.148 |  0.326 34.153  0.106 |

3. SES

if(exists("countyVars")==TRUE){
  countyVars <- countyVars
} else {
  countyVars <- fst::read.fst("Data/countyVars_f.csv")
} 
totalSES <- countyVars[,c("FIPS", "poverty", "singleParent", "medianIncome", "unemploymentRate_5yr")]
totalSES <- totalSES[complete.cases(totalSES),] 
pc_ses <-  prcomp(~ poverty + singleParent + medianIncome + unemploymentRate_5yr, 
                            data=totalSES,
                            scale. = T, center=TRUE,
                            na.action=na.omit)
totalSES$pc1SES <- pc_ses$x[,1]
totalSES$pc2SES <- pc_ses$x[,2]
countyVars <- dplyr::left_join(countyVars, totalSES)
Joining, by = "FIPS"
##print PCA analysis from FactoMineR
pcFit <- FactoMineR::PCA(countyVars[,c("poverty", "singleParent", "medianIncome", "unemploymentRate_5yr")])
Missing values are imputed by the mean of the variable: you should use the imputePCA function of the missMDA package

summary(pcFit)

Call:
FactoMineR::PCA(X = countyVars[, c("poverty", "singleParent",  
     "medianIncome", "unemploymentRate_5yr")]) 


Eigenvalues
                       Dim.1   Dim.2   Dim.3   Dim.4
Variance               2.234   1.033   0.504   0.229
% of var.             55.853  25.835  12.593   5.719
Cumulative % of var.  55.853  81.688  94.281 100.000

Individuals (the 10 first)
                         Dist    Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr   cos2  
1                    |  0.787 | -0.739  0.008  0.881 | -0.163  0.001  0.043 |  0.215  0.003  0.074 |
2                    |  0.581 | -0.508  0.004  0.765 |  0.173  0.001  0.088 |  0.166  0.002  0.082 |
3                    |  2.186 |  2.167  0.067  0.982 |  0.040  0.000  0.000 |  0.285  0.005  0.017 |
4                    |  1.032 |  0.650 | -0.264  0.002  0.065 | -0.069  0.000  0.004 |
5                    |  0.302 |  0.025  0.000  0.007 | -0.218  0.001  0.520 | -0.201  0.003  0.443 |
6                    |  2.369 |  2.309  0.076  0.950 | -0.044  0.000  0.000 | -0.183  0.002  0.006 |
7                    |  2.263 |  2.261  0.073  0.998 | -0.024  0.000  0.000 |  0.014  0.000  0.000 |
8                    |  1.040 |  0.983  0.014  0.894 |  0.285  0.002  0.075 |  0.037  0.000  0.001 |
9                    |  1.350 |  1.337  0.025  0.981 | -0.087  0.000  0.004 | -0.166  0.002  0.015 |
10                   |  1.042 |  0.838  0.010  0.647 | -0.294  0.003  0.079 | -0.515  0.017  0.244 |

Variables
                        Dim.1    ctr   cos2    Dim.2    ctr   cos2    Dim.3    ctr   cos2  
poverty              |  0.910 37.059  0.828 |  0.084  0.685  0.007 | -0.203  8.203  0.041 |
singleParent         | -0.105  0.489  0.011 |  0.981 93.038  0.961 | -0.153  4.657  0.023 |
medianIncome         | -0.880 34.681  0.775 |  0.153  2.260  0.023 |  0.325 20.943  0.105 |
unemploymentRate_5yr |  0.788 27.771  0.620 |  0.204  4.016  0.042 |  0.577 66.197  0.333 |
fst::write.fst(countyVars, path="countyVars_f.csv")
write.csv(countyVars, file="countyVars.csv")

XI. Add to Police Killing Variables

1. Reload Police Killing Data (saved above)

2. Washington Post

3. Lott & Moody (2016)

4. Combining Lott & Moody (2013-2015) with 2016 data from Washington Post

5. Save Data

XII. AGGREGATION

Below I aggregate counties into geographical units of having a minimum specified population size. For example, if the threshold is 10,000, then I aggregate counties with less than 10,000 residents into a larger unit having at least 10,000 residents. The aggregation problem has many possible solutions. The algorithm I employ aggregates adjacent counties with smallest population sizes first, i.e. counties with the smallest populations in the US are selected first, then aggregated with their smallest size neighbors.

https://www.census.gov/geo/reference/county-adjacency.html

A. FUNCTIONS

1. Aggregate Counties

This is to create the index that identifies which larger regions counties belong to. There are 5 counties (or census areas) that are not included in the Census adjacency file. They in Alaska, Hawaii, and South Dakota. Their FIPS codes are: 02158, 15001, 15003, 15007, and 46102. I merge these with the smallest group within the state.

2. Aggregate.County.Data

This is to summarise all variables in the datasets used below. Because drug possession and drug sales arrest data are not provided by Florida, I’m not including these two variable sets in the aggregated data sets.

I use the adjacency table ‘countyAdjacent.csv’ I generated from the file ‘createCountyAdjacent.R’.

https://www.census.gov/geo/reference/county-adjacency.html

B. 10k Regions

C. 100k Regions

D. 1 MILLION Region

E. STATES

LS0tDQp0aXRsZTogIkdyYWIgRGF0YSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCg0KIyBJLiBQT0xJQ0UgU0hPT1RJTkcgREFUQSAgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojI0EuICBMb2FkIExpYnJhcmllcw0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQojbGlicmFyeShIbWlzYykNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdnbWFwKQ0KbGlicmFyeShyZWFkcikNCg0KDQpgYGANCg0KIyNCLiBGdW5jdGlvbnMgDQoNCiMjIzEuICBnZXRTdGF0ZU5hbWUNClRoaXMgZnVuY3Rpb24gaXMganVzdCBhIHdheSB0byBjb252ZXJ0IHN0YXRlIG5hbWVzIGJhY2sgYW5kIGZvcnRoIHVzaW5nIGJhc2UgUiBmdW5jdGlvbnMsIGJ1dCBpbmNsdWRlcyB3YXNoaW5ndG9uIGRjIGFuZCBwdWVydG8gcmljby4NCg0KYGBge3J9DQoNCg0KZ2V0U3RhdGUgPC0gZnVuY3Rpb24oeCl7DQogICMjcmVtb3ZlIHB1bmN0dWF0aW9uIGFuZCB0d2ltIHdoaXRlIHNwYWNlLCBjb252ZXJ0IHRvIGxvd2VyIGNhc2UNCiAgeCA8LSB0b2xvd2VyKHRyaW13cyhnc3ViKCJbWzpwdW5jdDpdXSIsICIiLCB4KSkpDQogIHhbd2hpY2goeCA9PSAid2FzaGluZ3RvbiBkYyIpXSA8LSAiZGlzdHJpY3Qgb2YgY29sdW1iaWEiDQogIA0KICBzdGF0ZXMuYWJiIDwtIGMoc3RhdGUuYWJiLCAiREMiLCAiREMiLCAiUFIiKQ0KICBzdGF0ZXMubmFtZSA8LSBjKHN0YXRlLm5hbWUsICJEaXN0cmljdCBvZiBDb2x1bWJpYSIsICJEaXN0cmljdCBvZiBDb2x1bWJpYSIsICJQdWVydG8gUmljbyIpDQogIA0KICBtLmFiYiA8LSB0b2xvd2VyKHN0YXRlcy5hYmIpDQogIG0ubmFtZSA8LSB0b2xvd2VyKGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIHN0YXRlcy5uYW1lKSkNCiAgDQogICMjYXV0b21hdGljYWxseSBkZWNpZGUgdG8gY29udmVydCBmcm9tIG5hbWVzIHRvIHN0YXRlcyBvciB2aWNlIHZlcnNhIGJhc2VkIG9uIG1ham9yaXR5IG1hdGNoDQogIGlmKHN1bSh4ICVpbiUgbS5hYmIpID4gc3VtKHggJWluJSBtLm5hbWUpKXsNCiAgICAjY29udmVydCBhYmJyZXZpYXRpb25zIHRvIG5hbWVzDQogICAgeSA8LSBzdGF0ZXMubmFtZVttYXRjaCh4LG0uYWJiKV0NCiAgfSBlbHNlIHsNCiAgICB5IDwtIHN0YXRlcy5hYmJbbWF0Y2goeCxtLm5hbWUpXQ0KICB9DQogICByZXR1cm4oeSkNCn0NCg0KIyNyZXR1cm5zIGFiYnJldmlhdGlvbnMgb25seQ0KZ2V0U3RhdGUuYWJiIDwtIGZ1bmN0aW9uKHgpew0KICAjI3JlbW92ZSBwdW5jdHVhdGlvbiBhbmQgdHdpbSB3aGl0ZSBzcGFjZSwgY29udmVydCB0byBsb3dlciBjYXNlDQogIHggPC0gdG9sb3dlcih0cmltd3MoZ3N1YigiW1s6cHVuY3Q6XV0iLCAiIiwgeCkpKQ0KICB4W3doaWNoKHggPT0gIndhc2hpbmd0b24gZGMiKV0gPC0gImRpc3RyaWN0IG9mIGNvbHVtYmlhIg0KICANCiAgc3RhdGVzLmFiYiA8LSBjKHN0YXRlLmFiYiwgIkRDIiwgIkRDIiwgIlBSIikNCiAgc3RhdGVzLm5hbWUgPC0gYyhzdGF0ZS5uYW1lLCAiRGlzdHJpY3Qgb2YgQ29sdW1iaWEiLCAiRGlzdHJpY3Qgb2YgQ29sdW1iaWEiLCAiUHVlcnRvIFJpY28iKQ0KICANCiAgbS5hYmIgPC0gdG9sb3dlcihzdGF0ZXMuYWJiKQ0KICBtLm5hbWUgPC0gdG9sb3dlcihnc3ViKCJbWzpwdW5jdDpdXSIsICIiLCBzdGF0ZXMubmFtZSkpDQogIA0KICAgIHhbd2hpY2goeCAlaW4lIG0uYWJiKV0gPC0gc3RhdGVzLmFiYlttYXRjaCh4W3doaWNoKHggJWluJSBtLmFiYildICxtLmFiYildDQogICAgeFt3aGljaCh4ICVpbiUgbS5uYW1lKV0gPC0gc3RhdGVzLmFiYlttYXRjaCh4W3doaWNoKHggJWluJSBtLm5hbWUpXSxtLm5hbWUpXQ0KDQogIHJldHVybih4KQ0KfQ0KDQoNCiMjcmV0dXJucyBOYW1lcyBvbmx5DQpnZXRTdGF0ZS5uYW1lcyA8LSBmdW5jdGlvbih4KXsNCiAgIyNyZW1vdmUgcHVuY3R1YXRpb24gYW5kIHR3aW0gd2hpdGUgc3BhY2UsIGNvbnZlcnQgdG8gbG93ZXIgY2FzZQ0KICB4IDwtIHRvbG93ZXIodHJpbXdzKGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIHgpKSkNCiAgeFt3aGljaCh4ID09ICJ3YXNoaW5ndG9uIGRjIildIDwtICJkaXN0cmljdCBvZiBjb2x1bWJpYSINCiAgDQogIHN0YXRlcy5hYmIgPC0gYyhzdGF0ZS5hYmIsICJEQyIsICJEQyIsICJQUiIpDQogIHN0YXRlcy5uYW1lIDwtIGMoc3RhdGUubmFtZSwgIkRpc3RyaWN0IG9mIENvbHVtYmlhIiwgIkRpc3RyaWN0IG9mIENvbHVtYmlhIiwgIlB1ZXJ0byBSaWNvIikNCiAgDQogIG0uYWJiIDwtIHRvbG93ZXIoc3RhdGVzLmFiYikNCiAgbS5uYW1lIDwtIHRvbG93ZXIoZ3N1YigiW1s6cHVuY3Q6XV0iLCAiIiwgc3RhdGVzLm5hbWUpKQ0KICANCiAgeFt3aGljaCh4ICVpbiUgbS5hYmIpXSA8LSBzdGF0ZXMubmFtZVttYXRjaCh4W3doaWNoKHggJWluJSBtLmFiYildICxtLmFiYildDQogIHhbd2hpY2goeCAlaW4lIG0ubmFtZSldIDwtIHN0YXRlcy5uYW1lW21hdGNoKHhbd2hpY2goeCAlaW4lIG0ubmFtZSldLG0ubmFtZSldDQogIA0KICByZXR1cm4oeCkNCn0NCmBgYA0KDQojIyMyLiBHZXQgRklQUw0KYGBge3J9DQpnZXRGSVBTIDwtIGZ1bmN0aW9uKGRmLCBjaXR5VmFyPSJjaXR5Iiwgc3RhdGVWYXI9IlN0YXRlIiwgY291bnR5VmFyPSJjb3VudHkiLCBhZGRyZXNzVmFyID0gImFkZHJlc3MiKXsNCiAgcmVxdWlyZSh0aWJibGUpDQogIHJlcXVpcmUocmVhZHIpDQogIHJlcXVpcmUoZHBseXIpDQogIHJlcXVpcmUoZ2dtYXApDQogIHJlcXVpcmUobm9uY2Vuc3VzKQ0KICBzZXR3ZCgiY3JlYXRlRGF0YSIpDQojUEFSVCBJIC0gTE9BRCAzIERBVEEgU0VUUyAgICANCiAgZGF0YShjb3VudGllcykNCiAgY291bnRpZXMgPC0gc2FwcGx5KGNvdW50aWVzLCBhcy5jaGFyYWN0ZXIpICU+JSB0aWJibGU6OmFzX2RhdGFfZnJhbWUoKQ0KICBjb3VudGllcyRGSVBTIDwtIHBhc3RlMCgiYCIsIGFzLmNoYXJhY3Rlcihjb3VudGllcyRzdGF0ZV9maXBzKSwgYXMuY2hhcmFjdGVyKGNvdW50aWVzJGNvdW50eV9maXBzKSkNCiAgY291bnRpZXMkY291bnR5X2xvd2VyIDwtIGNvdW50aWVzJGNvdW50eV9uYW1lDQogIGNvdW50aWVzJGNvdW50eV9sb3dlciAgPSB0b2xvd2VyKHRyaW13cyhnc3ViKCJbWzpwdW5jdDpdXSIsICIiLCBjb3VudGllcyRjb3VudHlfbG93ZXIpKSkNCiAgY291bnRpZXMkY291bnR5X2xvd2VyPSBnc3ViKCIgY291bnR5fCBwYXJpc2h8IGJvcm91Z2giLCAiIiwgY291bnRpZXMkY291bnR5X2xvd2VyLCBmaXhlZCA9IFRSVUUpDQoNCmdlb0NvZGUgPC0gcmVhZHI6OnJlYWRfdHN2KCIzNTE1OC0wMDAxLURhdGEudHN2IikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIFN0YXRlID0gIGdldFN0YXRlLmFiYihTVEFURU5BTUUpLA0KICAgIGNpdHlfbG93ZXIgPSBBRERSRVNTX0NJVFksDQogICAgY2l0eV9sb3dlciA9IGdzdWIoInN0LiAiLCAic2FpbnQgIiwgdHJpbXdzKHRvbG93ZXIoY2l0eV9sb3dlcikpLCBmaXhlZCA9IFRSVUUpLA0KICAgIGNpdHlfbG93ZXIgPSBnc3ViKCJtdC4gIiwgIm1vdW50ICIsIHRyaW13cyh0b2xvd2VyKGNpdHlfbG93ZXIpKSwgZml4ZWQgPSBUUlVFKSwNCiAgICBjaXR5X2xvd2VyID0gdG9sb3dlcihhcy5jaGFyYWN0ZXIodHJpbXdzKGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIGNpdHlfbG93ZXIpKSkpLA0KICAgIGNvdW50eV9sb3dlciA9IHRvbG93ZXIoYXMuY2hhcmFjdGVyKHRyaW13cyhnc3ViKCJbWzpwdW5jdDpdXSIsICIiLCBDT1VOVFlOQU1FKSkpKSwNCiAgICBGSVBTID0gcGFzdGUoImAiLCBGSVBTLCBzZXA9IiIpDQogICkNCg0KY2hhck51bXMgPC0gYygiMCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiLCAiNiIsICI3IiwgIjgiLCAiOSIpDQoNCmdlb19jaXR5IDwtIHJlYWRyOjpyZWFkX2RlbGltKGZpbGU9IlBPUF9QTEFDRVNfMjAxNzA2MDEudHh0IiwgZGVsaW09InwiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgRklQUyA9IHBhc3RlMCgiYCIsIFNUQVRFX05VTUVSSUMsIENPVU5UWV9OVU1FUklDKSwNCiAgICBjaXR5X2xvd2VyMSA9IHRvbG93ZXIoYXMuY2hhcmFjdGVyKHRyaW13cyhnc3ViKCJbWzpwdW5jdDpdXSIsICIiLCBGRUFUVVJFX05BTUUpKSkpLA0KICAgIGNpdHlfbG93ZXIyID0gdG9sb3dlcihhcy5jaGFyYWN0ZXIodHJpbXdzKGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIE1BUF9OQU1FICApKSkpLA0KICAgICMjdHJpbSBsYXN0IDMgY2hhcmFjdGVycywgY29uc2lzdGluZyBvZiBhIGxldHRlci1udW1iZXIsIGUuZy4gRC0zDQogICAgY2l0eV9sb3dlcjIgPSBpZmVsc2Uoc3Vic3RyaW5nKGNpdHlfbG93ZXIyLCBuY2hhcihjaXR5X2xvd2VyMiksIG5jaGFyKGNpdHlfbG93ZXIyKSkgJWluJSBjaGFyTnVtcywNCiAgICAgICAgICAgICAgICAgICAgICAgICB0cmltd3Moc3Vic3RyKGNpdHlfbG93ZXIyLCAxLCBuY2hhcihjaXR5X2xvd2VyMiktMykpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNpdHlfbG93ZXIyKSwNCiAgICBjb3VudHlfbG93ZXIgPSB0b2xvd2VyKGFzLmNoYXJhY3Rlcih0cmltd3MoZ3N1YigiW1s6cHVuY3Q6XV0iLCAiIiwgQ09VTlRZX05BTUUpKSkpLA0KICAgIGNvdW50eV9sb3dlciA9ICBpZmVsc2Uoc3Vic3RyaW5nKGNvdW50eV9sb3dlciwgbmNoYXIoY291bnR5X2xvd2VyKS0yLCBuY2hhcihjb3VudHlfbG93ZXIpKSA9PSAiIGNhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyaW13cyhzdWJzdHIoY291bnR5X2xvd2VyLCAxLCBuY2hhcihjb3VudHlfbG93ZXIpLTMpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdW50eV9sb3dlcikNCiAgKQ0KDQojUEFSVCBJSS4gIExvYWQgRGF0YQ0KaWYoY2l0eVZhciAlaW4lIG5hbWVzKGRmKSA9PSBGQUxTRSl7ZGZbLGNpdHlWYXJdIDwtIE5BfQ0KaWYoc3RhdGVWYXIgJWluJSBuYW1lcyhkZikgPT0gRkFMU0Upe2RmWyxzdGF0ZVZhcl0gPC0gTkF9DQppZihhZGRyZXNzVmFyICVpbiUgbmFtZXMoZGYpID09IEZBTFNFKXtkZlssYWRkcmVzc1Zhcl0gPC0gTkF9DQppZihjb3VudHlWYXIgJWluJSBuYW1lcyhkZikgPT0gRkFMU0Upe2RmWyxjb3VudHlWYXJdIDwtIE5BfQ0KaWYoIkZJUFMiICVpbiUgbmFtZXMoZGYpID09IEZBTFNFKXtkZiRGSVBTIDwtIE5BfQ0KDQojUEFSVCBJSUkuICBTZWFyY2ggVXNpbmcgRXhpc3RpbmcgRGF0YXNldHMNCnNjYW40ZmlwcyA8LSBmdW5jdGlvbihkZl9hLCBjaXR5VmFyX2E9Y2l0eVZhciwgc3RhdGVWYXJfYT1zdGF0ZVZhciwgY291bnR5VmFyX2E9Y291bnR5VmFyKXsNCg0KI3N0ZXAgMSAtIGlkZW50aWZ5IGNvdW50aWVzIGlmIHRoZXkgYXJlIGFscmVhZHkgbGFiZWxsZWQgdXNpbmcgbm9uY2Vuc3VzIGNvdW50aWVzIGZpbGUNCmNpdHlfdmVjdG9yIDwtIGRmX2FbLGNpdHlWYXJfYV0gJT4lIHVubGlzdCgpICU+JSBhcy5jaGFyYWN0ZXIoKSAlPiUgdHJpbXdzKCkgDQpjb3VudHlfdmVjdG9yIDwtIGRmX2FbLGNvdW50eVZhcl9hXSAlPiUgdW5saXN0KCkgJT4lIGFzLmNoYXJhY3RlcigpICU+JSB0cmltd3MoKSANCiAgDQpjb3VudHlfaW5kZXggPC0gd2hpY2goZ3JlcGwoIiBjb3VudHl8IHBhcmlzaHwgYm9yb3VnaCIsIGNpdHlfdmVjdG9yLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmUuY2FzZSA9IFRSVUUsIGZpeGVkID0gRkFMU0UpICYgaXMubmEoY291bnR5X3ZlY3RvcikpDQojI0lmICJjaXR5IiBoYXMgImNvdW50eSIgZXRjLiwgaW4gaXRzIHRpdGxlLCBtb3ZlIGl0IHRvIGNvdW50eSBjb2x1bW4gIA0KZGZfYVtjb3VudHlfaW5kZXgsY291bnR5VmFyX2FdIDwtIGRmX2FbY291bnR5X2luZGV4LGNpdHlWYXJfYV0NCg0KZm9yKGkgaW4gd2hpY2goaXMubmEoZGZfYSRGSVBTKSAmICFpcy5uYShkZl9hWyxjb3VudHlWYXJfYV0pKSl7DQogIHN0IDwtIGRmX2FbW2ksc3RhdGVWYXJfYV1dDQogIGNudHkgPC0gZGZfYVtbaSxjb3VudHlWYXJfYV1dDQogIGZpcHMgPC0gdW5pcXVlKGNvdW50aWVzJEZJUFNbd2hpY2goY291bnRpZXMkc3RhdGUgPT0gc3QgJiBjb3VudGllcyRjb3VudHlfbmFtZSA9PSBjbnR5KV0pDQogIGlmKGxlbmd0aChmaXBzKSA9PSAxICYgIWlzLm51bGwoZmlwcykpew0KICBpZighaXMubmEoZmlwcykgJiBmaXBzICE9ICJOVUxMIikgew0KICAgIGRmX2EkRklQU1tbaV1dIDwtIGZpcHMNCiAgfX0gZWxzZSB7DQogIGNvdW50eV9sb3dlciA9IGNudHkNCiAgY291bnR5X2xvd2VyID0gdG9sb3dlcih0cmltd3MoZ3N1YigiW1s6cHVuY3Q6XV0iLCAiIiwgY250eSkpKQ0KICBjb3VudHlfbG93ZXIgPSBnc3ViKCIgY291bnR5fCBwYXJpc2h8IGJvcm91Z2giLCAiIiwgY291bnR5X2xvd2VyLCBmaXhlZCA9IFRSVUUpDQogIGZpcHMgPC0gdW5pcXVlKGNvdW50aWVzJEZJUFNbd2hpY2goY291bnRpZXMkc3RhdGUgPT0gc3QgJiBjb3VudGllcyRjb3VudHlfbG93ZXIgPT0gY291bnR5X2xvd2VyKV0pDQogIA0KICBpZihsZW5ndGgoZmlwcykgPT0gMSAmICFpcy5udWxsKGZpcHMpKXsNCiAgaWYoIWlzLm5hKGZpcHMpICYgZmlwcyAhPSAiTlVMTCIpIHtkZl9hJEZJUFNbW2ldXSA8LSBmaXBzfX0gZWxzZSB7DQogICAgICBmaXBzMSA8LSAoZ2VvX2NpdHkkRklQU1t3aGljaChnZW9fY2l0eSRjb3VudHlfbG93ZXIgPT0gY291bnR5X2xvd2VyICYgZ2VvX2NpdHkkU1RBVEVfQUxQSEEgPT0gc3QpXSkNCiAgICAgIGZpcHMyIDwtIChnZW9Db2RlJEZJUFNbd2hpY2goZ2VvQ29kZSRTdGF0ZSA9PXN0ICYgZ2VvQ29kZSRjb3VudHlfbG93ZXI9PSBjb3VudHlfbG93ZXIpXSkNCiAgICBuZXdfZmlwcyA8LSBuYW1lcyhzb3J0KHRhYmxlKGMoZmlwcywgZmlwczEsIGZpcHMyKSksIGRlY3JlYXNpbmc9VFJVRSlbMV0pDQogICAgaWYobGVuZ3RoKG5ld19maXBzKSA9PSAxICYgIWlzLm51bGwobmV3X2ZpcHMpKXsNCiAgICBpZighaXMubmEobmV3X2ZpcHMpICYgbmV3X2ZpcHMgIT0gIk5VTEwiKXtkZl9hJEZJUFNbW2ldXSA8LSBuZXdfZmlwc319DQogIH0NCiAgfSANCn0NCiAgDQojc3RlcCAyIC0gVXNlIGNpdHkvbG9jYXRpb24NCmZvcihpIGluIHdoaWNoKGlzLm5hKGRmX2EkRklQUykgJiAhaXMubmEoZGZfYVssY2l0eVZhcl9hXSkpKXsNCiAgc3QgPC0gZGZfYVtbaSxzdGF0ZVZhcl9hXV0NCiAgaV9jaXR5IDwtIGRmX2FbW2ksY2l0eVZhcl9hXV0NCiAgY2l0eV9sb3dlciA9IHRvbG93ZXIodHJpbXdzKGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIGlfY2l0eSkpKQ0KICBuZXdfZmlwcyA8LSB1bmlxdWUoZ2VvX2NpdHkkRklQU1t3aGljaChnZW9fY2l0eSRjaXR5X2xvd2VyMSA9PSBjaXR5X2xvd2VyICYgZ2VvX2NpdHkkU1RBVEVfQUxQSEEgPT0gc3QpXSkNCg0KICBpZihsZW5ndGgobmV3X2ZpcHMpID09IDEgJiAhaXMubnVsbChuZXdfZmlwcykpew0KICBpZighaXMubmEobmV3X2ZpcHMpICYgbmV3X2ZpcHMgIT0gIk5VTEwiKXsNCiAgICBkZl9hJEZJUFNbW2ldXSA8LSBuZXdfZmlwc319IGVsc2Ugew0KICAgICAgDQogIG5ld19maXBzIDwtICB1bmlxdWUoZ2VvQ29kZSRGSVBTW3doaWNoKGdlb0NvZGUkU3RhdGUgPT0gc3QgJiBnZW9Db2RlJGNpdHlfbG93ZXI9PWNpdHlfbG93ZXIpXSkNCiAgDQogICAgaWYobGVuZ3RoKG5ld19maXBzKSA9PSAxICYgIWlzLm51bGwobmV3X2ZpcHMpKXsNCiAgICBpZighaXMubmEobmV3X2ZpcHMpICYgbmV3X2ZpcHMgIT0gIk5VTEwiKXsNCiAgICAgIGRmX2EkRklQU1tbaV1dIDwtIG5ld19maXBzfX0gZWxzZSB7DQogICAgICAgIA0KICAgIG5ld19maXBzIDwtICB1bmlxdWUoZ2VvX2NpdHkkRklQU1t3aGljaChnZW9fY2l0eSRjaXR5X2xvd2VyMiA9PSBjaXR5X2xvd2VyICYgZ2VvX2NpdHkkU1RBVEVfQUxQSEEgPT0gc3QpXSkNCiAgDQogICAgICAgIGlmKGxlbmd0aChuZXdfZmlwcykgPT0gMSAmICFpcy5udWxsKG5ld19maXBzKSl7DQogICAgICAgIGlmKCFpcy5uYShuZXdfZmlwcykgJiBuZXdfZmlwcyAhPSAiTlVMTCIpew0KICAgICAgICAgICAgZGZfYSRGSVBTW1tpXV0gPC0gbmV3X2ZpcHN9fSBlbHNlIHsNCiAgDQogIGNpdHlfbG93ZXIgPSBnc3ViKCJNdCB8bXQuICIsICJtb3VudCAiLCB0cmltd3MoaV9jaXR5KSwgZml4ZWQgPSBUUlVFKQ0KICBjaXR5X2xvd2VyID0gZ3N1Yigic3QuICIsICJzYWludCAiLCB0cmltd3ModG9sb3dlcihjaXR5X2xvd2VyKSksIGZpeGVkID0gVFJVRSkNCiAgY2l0eV9sb3dlciA9IHRvbG93ZXIodHJpbXdzKGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIGNpdHlfbG93ZXIpKSkNCiAgY2l0eV9sb3dlciA9IGdzdWIoIiBjb3VudHl8IHBhcmlzaHwgY2hhcnRlciB0b3duc2hpcHwgdG93bnNoaXAiLCAiIiwgY2l0eV9sb3dlciwgZml4ZWQgPSBUUlVFKQ0KICBjaXR5X2xvd2VyID0gaWZlbHNlKGNpdHlfbG93ZXIgJWluJSBjKCJjb25leSBpc2xhbmQiLCAiYnJvb2tseW4iLCAibWFuaGF0dGFuIiwgDQogICAgICAgICJicm9ueCIsICJ0aGUgYnJvbngiLCAicXVlZW5zIiwgInN0YXRlbiBpc2xhbmQiLCAibmV3IHlvcmsgY2l0eSIpICYgDQogICAgICAgICAgc3QgPT0gIk5ZIiwgIm5ldyB5b3JrIiwgY2l0eV9sb3dlcikNCiAgY2l0eV9sb3dlciA9IGlmZWxzZShzdCA9PSAiREMiLCAid2FzaGluZ3RvbiIsIGNpdHlfbG93ZXIpDQogIGZpcHMxIDwtIHVuaXF1ZShnZW9fY2l0eSRGSVBTW3doaWNoKGdlb19jaXR5JGNpdHlfbG93ZXIxID09IGNpdHlfbG93ZXIgJiBnZW9fY2l0eSRTVEFURV9BTFBIQSA9PSBzdCldKQ0KICBmaXBzMiA8LSB1bmlxdWUoZ2VvX2NpdHkkRklQU1t3aGljaChnZW9fY2l0eSRjaXR5X2xvd2VyMiA9PSBjaXR5X2xvd2VyICYgZ2VvX2NpdHkkU1RBVEVfQUxQSEEgPT0gc3QpXSkNCiAgZmlwczMgPC0gdW5pcXVlKGdlb19jaXR5JEZJUFNbd2hpY2goZ2VvX2NpdHkkY291bnR5X2xvd2VyID09IGNpdHlfbG93ZXIgJiBnZW9fY2l0eSRTVEFURV9BTFBIQSA9PSBzdCldKQ0KICBmaXBzNCA8LSB1bmlxdWUoZ2VvQ29kZSRGSVBTW3doaWNoKGdlb0NvZGUkU3RhdGUgPT0gc3QgJiBnZW9Db2RlJGNpdHlfbG93ZXI9PWNpdHlfbG93ZXIpXSkNCiAgZmlwczUgPC0gdW5pcXVlKGdlb0NvZGUkRklQU1t3aGljaChnZW9Db2RlJFN0YXRlID09IHN0ICYgZ2VvQ29kZSRjb3VudHlfbG93ZXI9PWNpdHlfbG93ZXIpXSkNCiAgbmV3X2ZpcHMgPC0gbmFtZXMoc29ydCh0YWJsZShjKGZpcHMxLCBmaXBzMiwgZmlwczMsIGZpcHM0LCBmaXBzNSkpLCBkZWNyZWFzaW5nPVRSVUUpWzFdKQ0KICANCiAgaWYobGVuZ3RoKG5ld19maXBzKSA9PSAxICYgIWlzLm51bGwobmV3X2ZpcHMpKXsNCiAgaWYoIWlzLm5hKG5ld19maXBzKSAmIG5ld19maXBzICE9ICJOVUxMIil7ZGZfYSRGSVBTW1tpXV0gPC0gbmV3X2ZpcHN9fQ0KICB9fX19DQogIHJldHVybihkZl9hKQ0KfQ0KDQojUEFSVCBJVi4gU0VBUkNIIFVTSU5HIEdPT0dMRSBNQVBTDQojQWZ0ZXIgcnVubmluZyBzY2FuLCBzZWFyY2ggZm9yIHJlbWFpbmluZyBtaXNzaW5nIGNhc2VzIHVzaW5nIGdvb2dsZQ0Kc2VhcmNoNEZJUFMgPC0gZnVuY3Rpb24oZGZfYiwgYWRkcmVzc1Zhcl9iPWFkZHJlc3NWYXIsIGNvdW50eVZhcl9iPWNvdW50eVZhcil7DQogIGRmX25hbWVzIDwtIG5hbWVzKGRmX2IpDQogIGRmX2JbLGFkZHJlc3NWYXJfYl0gPC0gYXBwbHkoZGZfYlssYWRkcmVzc1Zhcl9iXSwgMSwgZnVuY3Rpb24oeCkgdHJpbXdzKGFzLmNoYXJhY3Rlcih4KSkpICU+JSB0aWJibGU6OmFzX2RhdGFfZnJhbWUoKQ0KICANCiAgaW5kZXggPC0gd2hpY2goKGRmX2IkRklQUyA9PSAiTlVMTCIgfCBpcy5uYShkZl9iJEZJUFMpKSAmICFpcy5uYShkZl9iWyxhZGRyZXNzVmFyX2JdKSAmIGRmX2JbLGFkZHJlc3NWYXJfYl0gIT0gIiIpDQogIGZpcHMubmEgPC0gZGZfYltpbmRleCxdDQogIGFkZHJlc3NfdmVjdG9yIDwtIGZpcHMubmFbLGFkZHJlc3NWYXJfYl0gJT4lIHVubGlzdCgpIA0KDQogIGZpcHNfZ2VvIDwtIGRwbHlyOjpiaW5kX2NvbHMoZ2dtYXA6Omdlb2NvZGUoYWRkcmVzc192ZWN0b3IsIHNvdXJjZT0iZ29vZ2xlIiwgb3V0cHV0PSJtb3JlIiksZmlwcy5uYSkNCiAgI2FfbiA8LSB3aGljaChuYW1lcyhmaXBzX2dlbyk9PSJhZGRyZXNzIilbMV0NCiAgI25hbWVzKGZpcHNfZ2VvKVthX25dIDwtICJhZGRyZXNzX2dvb2dsZSIgICNkZWxldGluZyBkdXBsaWNhdGUgdmFyaWFibGUgbmFtZSwgY2F1c2luZyBlcnJvcnMNCiAgZGZfYltpbmRleCxjb3VudHlWYXJfYl0gPC0gYXMuY2hhcmFjdGVyKGZpcHNfZ2VvJGFkbWluaXN0cmF0aXZlX2FyZWFfbGV2ZWxfMikNCiAgcmV0dXJuKGRmX2IpDQp9DQoNCm1pc3NpbmdfZmlwcyA8LSBsZW5ndGgoZGYkRklQU1t3aGljaChpcy5uYShkZiRGSVBTKSldKQ0KbWVzc2FnZShwYXN0ZTAoIkluaXRpYWwgTWlzc2luZyBGSVBTOiAgIiwgbWlzc2luZ19maXBzKSkNCm1lc3NhZ2UoIlN0ZXAgMS4gIFNjYW5uaW5nIGZvciBGSVBTIHVzaW5nIGV4aXN0aW5nIGRhdGEgc2V0cyIpDQpkZmEgPC0gc2NhbjRmaXBzKGRmKQ0KbWlzc2luZ19maXBzIDwtIGxlbmd0aChkZmEkRklQU1t3aGljaChpcy5uYShkZmEkRklQUykpXSkNCm1lc3NhZ2UocGFzdGUwKCJNaXNzaW5nIEZJUFMgYWZ0ZXIgU3RlcCAxOiAgIiwgbWlzc2luZ19maXBzKSkNCm1lc3NhZ2UoIlN0ZXAgMi4gIFNjYW5uaW5nIGZvciBGSVBTIHVzaW5nIEdvb2dsZSBNYXBzIikNCmRmYiA8LSBzZWFyY2g0RklQUyhkZmEpDQpkZmMgPC0gc2NhbjRmaXBzKGRmYikNCm1pc3NpbmdfZmlwcyA8LSBsZW5ndGgoZGZjJEZJUFNbd2hpY2goaXMubmEoZGZjJEZJUFMpKV0pDQptZXNzYWdlKHBhc3RlMCgiTWlzc2luZyBGSVBTIGFmdGVyIFN0ZXAgMjogICIsIG1pc3NpbmdfZmlwcykpDQoNCg0KcmV0dXJuKGRmYykNCg0KfQ0KDQoNCmBgYA0KDQoNCiMjIEMuICBMb2FkIFdhc2hpbmd0b24gUG9zdCBEYXRhIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCg0Kd2FwbyA8LSByZWFkX2NzdigiaHR0cHM6Ly9jZG4ucmF3Z2l0LmNvbS93YXNoaW5ndG9ucG9zdC9kYXRhLXBvbGljZS1zaG9vdGluZ3MvbWFzdGVyL2ZhdGFsLXBvbGljZS1zaG9vdGluZ3MtZGF0YS5jc3YiKSAlPiUgDQogIG11dGF0ZShhZGRyZXNzID0gcGFzdGUoY2l0eSwgc3RhdGUsICJVU0EiLCBzZXA9IiwgIikpICU+JSANCiAgZHBseXI6OnJlbmFtZShXZWFwb249YXJtZWQsIFJhY2U9cmFjZSwgbWVudGFsX2lsbG5lc3M9c2lnbnNfb2ZfbWVudGFsX2lsbG5lc3MpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICB5ZWFyPWFzLm51bWVyaWMoZm9ybWF0KGRhdGUsIiVZIikpLA0KICAgIGFnZV9mPSBjdXQoYWdlLCBicmVha3M9YygwLCAxNCwgMTksIDM5LCAyMDApLCANCiAgICAgICAgICAgICAgICAgICAgcmlnaHQ9IEZBTFNFLCBsYWJlbHM9YygiQWdlVW5kZXIxNSIsICJBZ2UxNV8xOSIsICJBZ2UyMF8zOSIsICJBZ2U0MEFib3ZlIikpLCANCiAgICAgICAgIA0KICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0iVyIpLCAiV2hpdGUiKSwNCiAgICAgICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0iQiIpLCAiQmxhY2siKSwNCiAgICAgICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0iSCIpLCAiSGlzcGFuaWMiKSwNCiAgICAgICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0iQSIpLCAiQXNpYW4iKSwNCiAgICAgICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0iTiIpLCAiTmF0aXZlIEFtZXJpY2FuIiksDQogICAgICAgICAgUmFjZT1yZXBsYWNlKFJhY2UsIHdoaWNoKFJhY2U9PSJPIiksICJPdGhlciIpLA0KICAgICAgICAgZ2VuZGVyPXJlcGxhY2UoZ2VuZGVyLCB3aGljaChnZW5kZXI9PSJNIiksICJNYWxlIiksDQogICAgICAgICBnZW5kZXI9cmVwbGFjZShnZW5kZXIsIHdoaWNoKGdlbmRlcj09IkYiKSwgIkZlbWFsZSIpLA0KICAgICAgICAgU3RhdGUgPSAgZ2V0U3RhdGUuYWJiKHN0YXRlKSwgICAgIA0KICAgICAgICAgbWVudGFsX2lsbG5lc3M9cmVwbGFjZShtZW50YWxfaWxsbmVzcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKG1lbnRhbF9pbGxuZXNzPT0iVHJ1ZSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lbnRhbGx5IElsbCIpLA0KICAgICAgICAgbWVudGFsX2lsbG5lc3M9cmVwbGFjZShtZW50YWxfaWxsbmVzcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWNoKG1lbnRhbF9pbGxuZXNzPT0iRmFsc2UiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3QgTWVudGFsbHkgSWxsL1Vua25vd24iKSwNCiAgICAgICAgIGJvZHlfY2FtZXJhPXJlcGxhY2UoYm9keV9jYW1lcmEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaChib2R5X2NhbWVyYT09IkZhbHNlIiksICJObyBCb2R5Q2FtIiksDQogICAgICAgICBib2R5X2NhbWVyYT1yZXBsYWNlKGJvZHlfY2FtZXJhLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpY2goYm9keV9jYW1lcmE9PSJUcnVlIiksICJCb2R5Q2FtIiksDQogICAgZGF0YVNvdXJjZT0iV2FwbyIpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBkYXRlPWFzLmNoYXJhY3RlcihkYXRlKQ0KICApDQogIA0KDQpgYGANCg0KDQojIyBELiAgTG9hZCBMb3R0ICYgTW9vZHkgKDIwMTYpIA0KYGBge3J9DQojc2V0d2QoImNyZWF0ZURhdGEiKQ0KbG90dCA8LSBoYXZlbjo6cmVhZF9zdGF0YSgiY3JlYXRlRGF0YS9wb2xpY2Uuc2hvb3QuZHRhIikgJT4lICANCiAgbXV0YXRlX2FsbCggZnVucyhyZXBsYWNlKC4sIGlzLm5hbiguKSwgTkEpKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIE9mZmljZXJSYWNlID0gTkEsDQogICAgT2ZmaWNlclJhY2UgPSByZXBsYWNlKE9mZmljZXJSYWNlLCB3aGljaChwdz09MSksICJXaGl0ZSIpLA0KICAgIE9mZmljZXJSYWNlID0gcmVwbGFjZShPZmZpY2VyUmFjZSwgd2hpY2gocGg9PTEpLCAiSGlzcGFuaWMiKSwNCiAgICBPZmZpY2VyUmFjZSA9IHJlcGxhY2UoT2ZmaWNlclJhY2UsIHdoaWNoKHBiPT0xKSwgIkJsYWNrIiksDQogICAgT2ZmaWNlclJhY2UgPSByZXBsYWNlKE9mZmljZXJSYWNlLCB3aGljaChwdT09MSksICJVbmtub3duIiksDQogICAgT2ZmaWNlclJhY2UgPSByZXBsYWNlKE9mZmljZXJSYWNlLCB3aGljaChwbz09MSksICJPdGhlciIpLA0KICAgIE9mZmljZXIyUmFjZSA9IE5BLA0KICAgIE9mZmljZXIyUmFjZSA9IHJlcGxhY2UoT2ZmaWNlcjJSYWNlLCB3aGljaChvZmZpY2VyMnJhY2U9PTEpLCAiV2hpdGUiKSwNCiAgICBPZmZpY2VyMlJhY2UgPSByZXBsYWNlKE9mZmljZXIyUmFjZSwgd2hpY2gob2ZmaWNlcjJyYWNlPT0zKSwgIkhpc3BhbmljIiksDQogICAgT2ZmaWNlcjJSYWNlID0gcmVwbGFjZShPZmZpY2VyMlJhY2UsIHdoaWNoKG9mZmljZXIycmFjZT09MiksICJCbGFjayIpLA0KICAgIE9mZmljZXIyUmFjZSA9IHJlcGxhY2UoT2ZmaWNlcjJSYWNlLCB3aGljaChvZmZpY2VyMnJhY2U9PTQpLCAiQXNpYW4vUGFjaWZpYyBJc2xhbmRlciIpLA0KICAgIE9mZmljZXIyUmFjZSA9IHJlcGxhY2UoT2ZmaWNlcjJSYWNlLCB3aGljaChvZmZpY2VyMnJhY2U9PTUpLCAiTmF0aXZlIEFtZXJpY2FuIiksDQogICAgT2ZmaWNlcjJSYWNlID0gcmVwbGFjZShPZmZpY2VyMlJhY2UsIHdoaWNoKG9mZmljZXIycmFjZT09NiksICJPdGhlciIpLA0KICAgIE9mZmljZXJTZXggPSBOQSwNCiAgICBPZmZpY2VyU2V4ID0gcmVwbGFjZShPZmZpY2VyU2V4LCB3aGljaChvZmZpY2VyMWdlbmRlcj09MSksICJNYWxlIiksDQogICAgT2ZmaWNlclNleCA9IHJlcGxhY2UoT2ZmaWNlclNleCwgd2hpY2gob2ZmaWNlcjFnZW5kZXI9PTApLCAiRmVtYWxlIiksDQogICAgT2ZmaWNlcjJTZXggPSBOQSwNCiAgICBPZmZpY2VyMlNleCA9IHJlcGxhY2UoT2ZmaWNlcjJTZXgsIHdoaWNoKG9mZmljZXIyZ2VuZGVyPT0xKSwgIk1hbGUiKSwNCiAgICBPZmZpY2VyMlNleCA9IHJlcGxhY2UoT2ZmaWNlcjJTZXgsIHdoaWNoKG9mZmljZXIyZ2VuZGVyPT0wKSwgIkZlbWFsZSIpLA0KICAgIFJhY2UgPSBOQSwNCiAgICBSYWNlID0gcmVwbGFjZShSYWNlLCB3aGljaChvZmZlbmRlcjFyYWNlID09IDEpLCAiV2hpdGUiKSwNCiAgICBSYWNlID0gcmVwbGFjZShSYWNlLCB3aGljaChvZmZlbmRlcjFyYWNlID09IDIpLCAiQmxhY2siKSwNCiAgICBSYWNlID0gcmVwbGFjZShSYWNlLCB3aGljaChvZmZlbmRlcjFyYWNlID09IDMpLCAiSGlzcGFuaWMiKSwNCiAgICBSYWNlID0gcmVwbGFjZShSYWNlLCB3aGljaChvZmZlbmRlcjFyYWNlID09IDQpLCAiQXNpYW4vUGFjaWZpYyBJc2xhbmRlciIpLA0KICAgIFJhY2UgPSByZXBsYWNlKFJhY2UsIHdoaWNoKG9mZmVuZGVyMXJhY2UgPT0gNSksICJOYXRpdmUgQW1lcmljYW4iKSwNCiAgICBSYWNlID0gcmVwbGFjZShSYWNlLCB3aGljaChvZmZlbmRlcjFyYWNlID09IDYpLCAiT3RoZXIiKQ0KICApICU+JSANCiAgZHBseXI6OnNlbGVjdCgtY29udGFpbnMoImR1bSIpKSAlPiUgICMjZGVsZXRpbmcgZHVtbXkgdmFyaWFibGVzDQogIGRwbHlyOjpzZWxlY3QoLXN0YXRlLCAtc3RudW1iZXIsIC1jaXR5aWQsIC1jaXR5c3RhdGUsIC1zdywgLXNiLCAtc2gsIA0KICAgICAgICAgICAgICAgIC1wZiwgLXB3LCAtcGgsIC1wYiwgLXB1LCAtcG8sIC1vZmZlbmRlcjFyYWNlLCANCiAgICAgICAgICAgICAgICAtb2ZmaWNlcjFnZW5kZXIsIC1vZmZpY2VyMmdlbmRlciwgLW9mZmljZXIycmFjZSkgJT4lIA0KZHBseXI6Om11dGF0ZSgNCiAgc3VpY2lkYWwgPSByZXBsYWNlKHN1aWNpZGFsLCB3aGljaChzdWljaWRhbCA9PSAwKSwgIkZhbHNlIiksDQogIHN1aWNpZGFsID0gcmVwbGFjZShzdWljaWRhbCwgd2hpY2goc3VpY2lkYWwgPT0gMSksICJUcnVlIiksDQogIGRydWdyZWxhdGVkID0gcmVwbGFjZShkcnVncmVsYXRlZCwgd2hpY2goZHJ1Z3JlbGF0ZWQgPT0gMCksICJGYWxzZSIpLA0KICBkcnVncmVsYXRlZCA9IHJlcGxhY2UoZHJ1Z3JlbGF0ZWQsIHdoaWNoKGRydWdyZWxhdGVkID09IDEpLCAiVHJ1ZSIpLA0KICBvZmZlbmRlcjIgPSByZXBsYWNlKG9mZmVuZGVyMiwgd2hpY2gob2ZmZW5kZXIyID09IDApLCAiRmFsc2UiKSwNCiAgb2ZmZW5kZXIyID0gcmVwbGFjZShvZmZlbmRlcjIsIHdoaWNoKG9mZmVuZGVyMiA9PSAxKSwgIlRydWUiKSwNCiAgIyBwb2xraWxsZWQgPSByZXBsYWNlKHBvbGtpbGxlZCwgd2hpY2gocG9sa2lsbGVkPT0wKSwgIkZhbHNlIiksDQogICMgcG9sa2lsbGVkID0gcmVwbGFjZShwb2xraWxsZWQsIHdoaWNoKHBvbGtpbGxlZD09MSksICJUcnVlIiksDQogIGZpcmVhcm0gPSByZXBsYWNlKGZpcmVhcm0sIHdoaWNoKGZpcmVhcm09PTApLCAiRmFsc2UiKSwNCiAgZmlyZWFybSA9IHJlcGxhY2UoZmlyZWFybSwgd2hpY2goZmlyZWFybT09MSksICJUcnVlIiksDQogIGtuaWZlID0gcmVwbGFjZShrbmlmZSwgd2hpY2goa25pZmU9PTApLCAiRmFsc2UiKSwNCiAga25pZmU9cmVwbGFjZShrbmlmZSwgd2hpY2goa25pZmU9PTEpLCAiVHJ1ZSIpLA0KICB2ZWhpY2xlID0gcmVwbGFjZSh2ZWhpY2xlLCB3aGljaCh2ZWhpY2xlPT0wKSwgIkZhbHNlIiksDQogIHZlaGljbGU9cmVwbGFjZSh2ZWhpY2xlLCB3aGljaCh2ZWhpY2xlPT0xKSwgIlRydWUiKSwNCiAgb3RoZXJ3ZWFwb249cmVwbGFjZShvdGhlcndlYXBvbiwgd2hpY2gob3RoZXJ3ZWFwb249PTApLCAiRmFsc2UiKSwNCiAgb3RoZXJ3ZWFwb249cmVwbGFjZShvdGhlcndlYXBvbiwgd2hpY2gob3RoZXJ3ZWFwb249PTEpLCAiVHJ1ZSIpLA0KICBhcm1lZCA9IHJlcGxhY2UoYXJtZWQsIHdoaWNoKGFybWVkPT0wKSwgIkZhbHNlIiksDQogIGFybWVkPXJlcGxhY2UoYXJtZWQsIHdoaWNoKGFybWVkPT0xKSwgIlRydWUiKSwNCiAgaXBjciA9IHJlcGxhY2UoaXBjciwgd2hpY2goaXBjcj09MCksICJGYWxzZSIpLA0KICBpcGNyID0gcmVwbGFjZShpcGNyLCB3aGljaChpcGNyPT0xKSwgIlRydWUiKSwNCiAgICBpdmNyID0gcmVwbGFjZShpdmNyLCB3aGljaChpdmNyPT0wKSwgIkZhbHNlIiksDQogICAgaXZjciA9IHJlcGxhY2UoaXZjciwgd2hpY2goaXZjcj09MSksICJUcnVlIiksDQogICAgYm9keWNhbSA9IHJlcGxhY2UoYm9keWNhbSwgd2hpY2goYm9keWNhbT09MCksICJGYWxzZSIpLA0KICBib2R5Y2FtID0gcmVwbGFjZShib2R5Y2FtLCB3aGljaChib2R5Y2FtPT0xKSwgIlRydWUiKSwNCiAgICBndW5jYW0gPSByZXBsYWNlKGd1bmNhbSwgd2hpY2goZ3VuY2FtPT0wKSwgIkZhbHNlIiksDQogIGd1bmNhbSA9IHJlcGxhY2UoZ3VuY2FtLCB3aGljaChndW5jYW09PTEpLCAiVHJ1ZSIpLA0KICAgIGd1bnNob3RzID0gcmVwbGFjZShndW5zaG90cywgd2hpY2goZ3Vuc2hvdHM9PTApLCAiRmFsc2UiKSwNCiAgZ3Vuc2hvdHMgPSByZXBsYWNlKGd1bnNob3RzLCB3aGljaChndW5zaG90cz09MSksICJUcnVlIiksDQogICAgc2FtZW9mZmljZXJzID0gcmVwbGFjZShzYW1lb2ZmaWNlcnMsIHdoaWNoKHNhbWVvZmZpY2Vycz09MCksICJGYWxzZSIpLA0KICBzYW1lb2ZmaWNlcnMgPSByZXBsYWNlKHNhbWVvZmZpY2Vycywgd2hpY2goc2FtZW9mZmljZXJzPT0xKSwgIlRydWUiKSwNCiAgICBoZWxpY29wdGVycyA9IHJlcGxhY2UoaGVsaWNvcHRlcnMsIHdoaWNoKGhlbGljb3B0ZXJzPT0wKSwgIkZhbHNlIiksDQogIGhlbGljb3B0ZXJzID0gcmVwbGFjZShoZWxpY29wdGVycywgd2hpY2goaGVsaWNvcHRlcnM9PTEpLCAiVHJ1ZSIpLA0KICAgIHVuaW9uID0gcmVwbGFjZSh1bmlvbiwgd2hpY2godW5pb249PTApLCAiRmFsc2UiKSwNCiAgdW5pb24gPSByZXBsYWNlKHVuaW9uLCB3aGljaCh1bmlvbj09MSksICJUcnVlIiksDQogICAgY29sbGVnZSA9IHJlcGxhY2UoY29sbGVnZSwgd2hpY2goY29sbGVnZT09MCksICJGYWxzZSIpLA0KICBjb2xsZWdlID0gcmVwbGFjZShjb2xsZWdlLCB3aGljaChjb2xsZWdlPT0xKSwgIlRydWUiKSwNCiAgICBjb21tdW5pdHkgPSByZXBsYWNlKGNvbW11bml0eSwgd2hpY2goY29tbXVuaXR5PT0wKSwgIkZhbHNlIiksDQogIGNvbW11bml0eSA9IHJlcGxhY2UoY29tbXVuaXR5LCB3aGljaChjb21tdW5pdHk9PTEpLCAiVHJ1ZSIpLA0KICBhZ2VfZj0gY3V0KHNhLCBicmVha3M9YygwLCAxNCwgMTksIDM5LCAyMDApLCANCiAgICAgICAgICAgICAgICAgICAgcmlnaHQ9IEZBTFNFLCBsYWJlbHM9YygiQWdlVW5kZXIxNSIsICJBZ2UxNV8xOSIsICJBZ2UyMF8zOSIsICJBZ2U0MEFib3ZlIikpLA0KICBTdGF0ZSA9ICBnZXRTdGF0ZS5hYmIoc3RubSksIA0KICAjc3RhdGVfbG93ZXIgPSBzdGF0ZUZyb21Mb3dlcihzdG5tKSwNCiAgZGF0YVNvdXJjZT0ibG90dCIsDQogIGFkZHJlc3M9cGFzdGUoY2l0eSwgc3RubSwgIlVTQSIsIHNlcD0iLCAiKQ0KKSAlPiUgDQogIGRwbHlyOjpyZW5hbWUoQWdlID0gc2EsIGRhdGU9RGF0ZSkNCg0KZm9yKGkgaW4gMTpuY29sKGxvdHQpKSB7DQogIGlmKEhtaXNjOjpsYWJlbChsb3R0KVtpXSE9IiIpew0KICAgIA0KICAgIGxhYiA8LSBIbWlzYzo6bGFiZWwobG90dClbaV0NCiAgICBpZihsYWIgPT0gInN1c3BlY3QncyBhZ2UiKXtsYWIgPC0gIkFnZSJ9DQogICAgaWYobGFiID09ICJEYXRlIil7bGFiIDwtICJkYXRlIn0gI2tlZXAgY29uc2lzdGVudCB3aXRoIG90aGVyIGRmJ3MNCiAgICBpZihsYWIgPT0gInN1c3BlY3QgYXJtKiplZCwgcGVyY2VudCIpe2xhYiA8LSAiQXJtZWQifQ0KICAgIGxhYiA8LSBnc3ViKCIsICIsICIiLCBsYWIpDQogICAgbGFiIDwtIGdzdWIoInBlcmNlbnQgIiwgIiIsIGxhYikNCiAgICBsYWIgPC0gZ3N1YigicGVyY2VudCIsICIiLCBsYWIpDQogICAgaWYobGFiID09ICJ3aGV0aGVyIG9mZmVuZGVyMiBleGlzdHMiKXtsYWIgPC0gIk9mZmVuZGVyIDIifQ0KICAgIGxhYiA8LSBnc3ViKCJzdXNwZWN0ICIsICIiLCBsYWIpDQogICAgbmFtZXMobG90dClbaV0gPC0gbGFiDQogIH0NCn0NCmBgYCAgDQoNCg0KIyNFLiAgQ29tYmluZSBEYXRhDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCg0KbG90dF9uZXN0ZWQgPC0gDQogbG90dCAlPiUNCiAgdGlkeXI6Om5lc3QoLWRhdGFTb3VyY2UsIC1hZGRyZXNzLCAtU3RhdGUsIC1jaXR5LCAteWVhcikNCg0Kd2Fwb19uZXN0ZWQgPC0gDQogIHdhcG8gJT4lDQogIHRpZHlyOjpuZXN0KC1kYXRhU291cmNlLCAtYWRkcmVzcywgLVN0YXRlLCAtY2l0eSwgLXllYXIpIA0KDQpraWxsRGF0YSA8LSBkcGx5cjo6YmluZF9yb3dzKGxvdHRfbmVzdGVkLCB3YXBvX25lc3RlZCkgJT4lIA0KICAgZHBseXI6OmZpbHRlcihTdGF0ZSAlaW4lIGMoc3RhdGUuYWJiLCAiREMiKSwgeWVhciA8IDIwMTcpDQojZXhjbHVkaW5nIGEgY2FzZSBpbiBWaXJnaW4gSXNsYW5kcyAobG90dCksIGFuZCBvbmVjIGNhc2UgaW4gcHVlcnRvIHJpY28gKGxvdHQpDQoNCmBgYA0KDQoNCg0KIyNGLiAgTG9hZCBHZW8tQ29vcmRpbmF0ZXMgKEZJUFMpIGRhdGEgDQoNClR3byBmaWxlcyBhcmUgdXNlZCB0byBpZGVudGlmeSB0aGUgY291bnRpZXMgaW4gd2hpY2ggcG9saWNlIHNob290aW5ncyBvY2N1cnJlZDogIA0KMS4gIExhdyBFbmZvcmNlbWVudCBBZ2VuY3kgSW5kZW50aWZpZXJzIENyb3Nzd2FsaywgMjAxMiAoSUNQU1IgMzUxNTgpICANCmh0dHBzOi8vd3d3LmljcHNyLnVtaWNoLmVkdS9pY3BzcndlYi9JQ1BTUi9zdHVkaWVzLzM1MTU4DQoyLiAgIlBvcHVsYXRlZCBQbGFjZXMiIGZpbGUgIlBPUF9QTEFDRVNfMjAxNzA2MDEudHh0IiwgYSBzdWJzZXQgb2YgdGhlIGxhcmdlciBmaWxlICJOYXRpb25hbEZpbGVfMjAxNzA2MDEudHh0IiBmcm9tIFVTR1MgLSBEb21lc3RpYyBhbmQgQW50YXJjdGljIE5hbWVzIC0gU3RhdGUgYW5kIFRvcGljYWwgR2F6ZXR0ZWVyIERvd25sb2FkIEZpbGVzDQpTb3VyY2U6ICBodHRwczovL2dlb25hbWVzLnVzZ3MuZ292L2RvbWVzdGljL2Rvd25sb2FkX2RhdGEuaHRtDQoNClRoZSByZW1haW5pbmcgY2FzZXMgd2l0aG91dCBhIEZJUFMgY29kZSBhcmUgaWRlbnRpZmllZCB1c2luZyB0aGUgKmdlb2NvZGUoKSogZnVuY3Rpb24gZnJvbSB0aGUgZ2dtYXBzIHBhY2thZ2UuDQoNCg0KYGBge3J9DQprZCA8LSBnZXRGSVBTKGRmPWtpbGxEYXRhKQ0Ka2QgJT4lIGRwbHlyOjpmaWx0ZXIoaXMubmEoRklQUykpICU+JSB0aWJibGU6OmFzX3RpYmJsZSgpDQoNCmBgYA0KDQpUaGVyZSBhcmUgZm91ciByZW1haW5pbmcgY2FzZXMgd2l0aG91dCBhIEZJUFMgY29kZS4gIEFmdGVyIGV4YW1pbmluZyB0aGVzZSBmb3VyIGNhc2VzLCBJIG1hZGUgdGhlIGZvbGxvd2luZyBtYW51YWwgY2hhbmdlczoNCg0KMS4gIkZsb3JlbmNlLCBBSywgVVNBIiAtIExvdHQgLSAyMDEzIC0gaXMgaWRlbnRpZmllZCBhcyBGbG9yZW5jZSwgQWxhYmFtYSwgTGF1ZGVyZGFsZSBDb3VudHksIEZJUFMgYDAxMDc3DQoNCjIuICJPcHAsIEZMLCBVU0EiIC0gTG90dCAtIDIwMTUgLSBpcyBpZGVudGlmaWVkIGFzIE9wcCwgQWxhYmFtYSwgQ292aW5ndG9uIENvdW50eSwgRklQUyAgYDAxMDM5DQoNCjMuICJCb2lzZSBOYXRpb25hbCBGb3Jlc3QsIElELCBVU0EiIC0gTG90dCAtIDIwMTMgLSBpcyBpbi9uZWFyIExvd21hbiwgSUQsIEJvaXNlIENvdW50eSwgRklQUyBgMTYwMTUNCg0KNC4gICJDb2NrZXlzdmlsbGUsIFRYLCBVU0EiIGNvdWxkIG5vdCBiZSB2ZXJpZmllZCBhbmQgaXMgZHJvcHBlZC4NCg0KSW4gYWRkaXRpb24sIHRoZSBmb2xsb3dpbmcgY2hhbmdlcyBhcmUgbWFkZToNCg0KMS4gIlByYWlyaWUgR3JvdmUsIEFaLCBVU0EiIC0gTG90dCAtIDIwMTMgLSBpcyBQcmFpcmllIEdyb3ZlLCBBcmthbnNhcywgV2FzaGluZ3RvbiBDb3VudHksIEZJUFMgYDA1MTQzDQoNCjIuICJBbGFiYW1hLCBHQSwgVVNBIiAtIExvdHQgLSAyMDE1IC0gRFJPUFBFRA0KDQozLiAiTmF0aW9uYWwgUGFyaywgQVosIFVTQSIgLSBMb3R0IC0gMjAxMyAtIERST1BQRUQNCiANCg0KDQpgYGB7cn0NCmRyb3BfYWRkcmVzc2VzIDwtIGMoIkFsYWJhbWEsIEdBLCBVU0EiLCAiTmF0aW9uYWwgUGFyaywgQVosIFVTQSIsICJDb2NrZXlzdmlsbGUsIFRYLCBVU0EiKQ0KbnJvdyhrZCkNCmtkIDwtIHN1YnNldChrZCwgIShhZGRyZXNzICVpbiUgZHJvcF9hZGRyZXNzZXMpKQ0KbnJvdyhrZCkNCmtkJEZJUFNbd2hpY2goa2QkYWRkcmVzcyA9PSAiUHJhaXJpZSBHcm92ZSwgQVosIFVTQSIpXSA8LSAiYDA1MTQzIg0Ka2QkU3RhdGVbd2hpY2goa2QkYWRkcmVzcyA9PSAiUHJhaXJpZSBHcm92ZSwgQVosIFVTQSIpXSA8LSAiQVIiDQprZCRGSVBTW3doaWNoKGtkJGFkZHJlc3MgPT0gIkZsb3JlbmNlLCBBSywgVVNBIildIDwtICJgMDEwNzciDQprZCRTdGF0ZVt3aGljaChrZCRhZGRyZXNzID09ICJGbG9yZW5jZSwgQUssIFVTQSIpXSA8LSAiQUwiDQprZCRGSVBTW3doaWNoKGtkJGFkZHJlc3MgPT0gIk9wcCwgRkwsIFVTQSIpXSA8LSAiYDAxMDM5Ig0Ka2QkU3RhdGVbd2hpY2goa2QkYWRkcmVzcyA9PSAiT3BwLCBGTCwgVVNBIildIDwtICJBTCINCmtkJEZJUFNbd2hpY2goa2QkYWRkcmVzcyA9PSAiQm9pc2UgTmF0aW9uYWwgRm9yZXN0LCBJRCwgVVNBIildIDwtICJgMTYwMTUiDQoNCmBgYA0KDQojIyNOWUMgQ29ycnJlY3Rpb24NCihzZWUgc2VjdGlvbiBiZWxvdyBpbiBVQ1IgY3JpbWUgZGF0YSAtIHVzaW5nIE1hbmhhdHRhbiBGSVBTIGZvciBhbGwgTllDIEZJUFMpDQpgYGB7cn0NCm55RmlwcyA8LSBjKCJgMzYwNjEiLCAiYDM2MDQ3IiwgImAzNjA4MSIsICJgMzYwMDUiLCAiYDM2MDg1IikNCg0Ka2QgPC0ga2QgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIEZJUFMgPSByZXBsYWNlKEZJUFMsIHdoaWNoKEZJUFMgJWluJSBueUZpcHMpLCAiYDM2MDYxIikNCiAgKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLWNvdW50eSkNCg0KYGBgDQoNCg0KDQojIyBHLiAgIFNhdmUgRGF0YS4NCmBgYHtyfQ0KDQp3YXBvIDwtIGtkICU+JSBkcGx5cjo6ZmlsdGVyKGRhdGFTb3VyY2U9PSJXYXBvIikgJT4lIA0KICB0aWR5cjo6dW5uZXN0KCkNCmZzdDo6d3JpdGUuZnN0KHdhcG8sIHBhdGg9ImRmX3dhcG9fZnN0LmNzdiIpDQp3cml0ZS5jc3Yod2FwbywgZmlsZT0iZGZfd2Fwby5jc3YiKQ0KDQpsb3R0IDwtIGtkICU+JSBkcGx5cjo6ZmlsdGVyKGRhdGFTb3VyY2U9PSJsb3R0IikgJT4lIA0KICB0aWR5cjo6dW5uZXN0KCkNCmZzdDo6d3JpdGUuZnN0KGxvdHQsIHBhdGg9ImRmX2xvdHRfZnN0LmNzdiIpDQp3cml0ZS5jc3YobG90dCwgZmlsZT0iZGZfbG90dC5jc3YiKQ0KDQoNCg0KYGBgDQoNCg0KDQojIElJLiBQT1BVTEFUSU9OIENFTlNVUyBEQVRBIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoNCiMjMS4gIENPVU5UWS1MRVZFTCBQb3B1bGF0aW9uIERhdGENCkNDLUVTVDIwMTUtQUxMREFUQS1bU1QtRklQU106IEFubnVhbCBDb3VudHkgUmVzaWRlbnQgUG9wdWxhdGlvbiBFc3RpbWF0ZXMgYnkgQWdlLCBTZXgsIFJhY2UsIGFuZCBIaXNwYW5pYyBPcmlnaW46DQpBcHJpbCAxLCAyMDEwIHRvIEp1bHkgMSwgMjAxNSBGaWxlOiA3LzEvMjAxNSBDb3VudHkgQ2hhcmFjdGVyaXN0aWNzIFJlc2lkZW50IFBvcHVsYXRpb24gRXN0aW1hdGVzDQpTb3VyY2U6IFUuUy4gQ2Vuc3VzIEJ1cmVhdSwgUG9wdWxhdGlvbiBEaXZpc2lvbiBSZWxlYXNlIERhdGU6IEp1bmUgMjAxNg0KDQojIyNMb2FkIERhdGEgZnJvbSBDZW5zdXMgV2Vic2l0ZQ0KYGBge3J9DQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZHBseXIpDQoNCiMgSS4gIENPVU5UWS1MRVZFTCBQT1BVTEFUSU9OIENFTlNVUyBEQVRBIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyNVc2luZyBkcGx5ci90aWR5LXZlcnNlIGNvZGUNCmNvdW50eV9jZW5zdXMgPC0gcmVhZF9jc3YoZmlsZT0iaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvcHJvZ3JhbXMtc3VydmV5cy9wb3Blc3QvZGF0YXNldHMvMjAxMC0yMDE1L2NvdW50aWVzL2FzcmgvY2MtZXN0MjAxNS1hbGxkYXRhLmNzdiIpDQogICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyNodHRwczovL3d3dy5jZW5zdXMuZ292L3BvcGVzdC9kYXRhL2NvdW50aWVzL2FzcmgvMjAxNS9maWxlcy9DQy1FU1QyMDE1LUFMTERBVEEuY3N2DQoNCiMjUmFjZS1Ub3RhbCwgZ2VuZGVyLUJvdGgsIGFnZS1BbGwNCg0KY291bnR5UG9wIDwtIGNvdW50eV9jZW5zdXMgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKFlFQVIgJWluJSBjKDQsNSw2LDcsOCkpICU+JSANCiAgZHBseXI6Om11dGF0ZShZRUFSPXJlcGxhY2UoWUVBUiwgd2hpY2goWUVBUj09NCksIDIwMTEpLA0KICAgICAgICAgWUVBUj1yZXBsYWNlKFlFQVIsIHdoaWNoKFlFQVI9PTUpLCAyMDEyKSwNCiAgICAgICAgIFlFQVI9cmVwbGFjZShZRUFSLCB3aGljaChZRUFSPT02KSwgMjAxMyksDQogICAgICAgICBZRUFSPXJlcGxhY2UoWUVBUiwgd2hpY2goWUVBUj09NyksIDIwMTQpLA0KICAgICAgICAgWUVBUj1yZXBsYWNlKFlFQVIsIHdoaWNoKFlFQVI9PTgpLCAyMDE1KSwNCiAgICAgICAgIEZJUFM9cGFzdGUoImAiLCBTVEFURSwgQ09VTlRZLCBzZXA9IiIpLA0KICAgICAgICAgDQogICAgICAgICANCiAgICAgICAgIGFnZT1OQSwNCiAgICAgICAgIGFnZT1yZXBsYWNlKGFnZSwgd2hpY2goQUdFR1JQPT0wKSwgIkFsbCIpLA0KICAgICAgICAgYWdlPXJlcGxhY2UoYWdlLCB3aGljaChBR0VHUlAgJWluJSBjKDEsMiwzKSksICJVbmRlcjE1IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA9PSA0KSwgIjE1XzE5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA9PSA1KSwgIjIwXzI0IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA9PSA2KSwgIjI1XzI5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA9PSA3KSwgIjMwXzM0IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA9PSA4KSwgIjM1XzM5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA9PSA5KSwgIjQwXzQ0IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA9PSAxMCksICI0NV80OSIpLA0KICAgICAgICAgYWdlPXJlcGxhY2UoYWdlLCB3aGljaChBR0VHUlAgPT0gMTEpLCAiNTBfNTQiKSwNCiAgICAgICAgIGFnZT1yZXBsYWNlKGFnZSwgd2hpY2goQUdFR1JQID09IDEyKSwgIjU1XzU5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRUdSUCA+IDEyKSwgIjYwQWJvdmUiKQ0KICApICU+JSANCg0KICB0cmFuc211dGUoeWVhcj1ZRUFSLCANCiAgICAgICAgICAgIHN0YXRlPVNUTkFNRSwNCiAgICAgICAgICAgIGNvdW50eT1DVFlOQU1FLA0KICAgICAgICAgICAgRklQUz1GSVBTLCBhZ2U9YWdlLA0KDQogICAgICAgICAgVG90YWxfTWFsZT1UT1RfTUFMRSwgDQogICAgICAgICAgVG90YWxfRmVtYWxlPVRPVF9GRU1BTEUsIA0KICAgICAgICAgIFRvdGFsX0JvdGggPSBUb3RhbF9NYWxlK1RvdGFsX0ZlbWFsZSwNCiAgICAgICAgICANCiAgICAgICAgICBCbGFja19NYWxlPUJBX01BTEUsIEJsYWNrX0ZlbWFsZT1CQV9GRU1BTEUsDQogICAgICAgICAgQmxhY2tfQm90aD1CbGFja19NYWxlK0JsYWNrX0ZlbWFsZSwNCiAgICAgICAgICANCiAgICAgICAgICBBbWVyaW5kaWFuX01hbGU9SUFfTUFMRSwgQW1lcmluZGlhbl9GZW1hbGU9SUFfRkVNQUxFLA0KICAgICAgICAgIEFtZXJpbmRpYW5fQm90aD1BbWVyaW5kaWFuX01hbGUrQW1lcmluZGlhbl9GZW1hbGUsDQogICAgICAgICAgDQogICAgICAgICAgQXNpYW5fTWFsZT1BQV9NQUxFLCBBc2lhbl9GZW1hbGU9QUFfRkVNQUxFLA0KICAgICAgICAgIEFzaWFuX0JvdGg9QXNpYW5fTWFsZStBc2lhbl9GZW1hbGUsDQogICAgICAgICAgDQogICAgICAgICAgUGFjaWZpY0lzbGFuZGVyX01hbGU9TkFfTUFMRSwgUGFjaWZpY0lzbGFuZGVyX0ZlbWFsZT1OQV9GRU1BTEUsDQogICAgICAgICAgUGFjaWZpY0lzbGFuZGVyX0JvdGg9UGFjaWZpY0lzbGFuZGVyX01hbGUrUGFjaWZpY0lzbGFuZGVyX0ZlbWFsZSwNCiAgICAgICAgICANCiAgICAgICAgICBIaXNwYW5pY19NYWxlPUhXQV9NQUxFLCAjSGlzcGFuaWMsIFdoaXRlIGFsb25lIG1hbGUgcG9wdWxhdGlvbiANCiAgICAgICAgICBIaXNwYW5pY19GZW1hbGU9SFdBX0ZFTUFMRSwgI0hpc3BhbmljLCBXaGl0ZSBhbG9uZSBmZW1hbGUgcG9wdWxhdGlvbiANCiAgICAgICAgICBIaXNwYW5pY19Cb3RoPUhpc3BhbmljX01hbGUrSGlzcGFuaWNfRmVtYWxlLA0KICAgICAgICAgIA0KICAgICAgICAgIFdoaXRlX01hbGU9TkhXQV9NQUxFLCAgI05vdCBIaXNwYW5pYywgV2hpdGUgYWxvbmUgbWFsZSBwb3B1bGF0aW9uDQogICAgICAgICAgV2hpdGVfRmVtYWxlPU5IV0FfRkVNQUxFLCAjTm90IEhpc3BhbmljLCBXaGl0ZSBhbG9uZSBmZW1hbGUgcG9wdWxhdGlvbg0KICAgICAgICAgIFdoaXRlX0JvdGg9V2hpdGVfTWFsZStXaGl0ZV9GZW1hbGUNCiAgICApIA0KDQojI1NlcGFyYXRlLCB0aGVuIHJlLXVuaXRlIGluIGxvbmcgZm9ybWF0DQp3aGl0ZV9kZiA8LSBjb3VudHlQb3AgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHllYXIsIHN0YXRlLCBjb3VudHksIEZJUFMsIGFnZSwgV2hpdGVfTWFsZSwgV2hpdGVfRmVtYWxlLCBXaGl0ZV9Cb3RoKSAlPiUgDQogIGRwbHlyOjpyZW5hbWUoTWFsZT1XaGl0ZV9NYWxlLCBGZW1hbGU9V2hpdGVfRmVtYWxlLCBCb3RoPVdoaXRlX0JvdGgpICU+JSANCiAgdGlkeXI6OmdhdGhlcihnZW5kZXIsIHBvcHVsYXRpb24sIDY6OCkgJT4lIA0KICBtdXRhdGUoUmFjZT0iV2hpdGUiKSAlPiUgDQogIGdyb3VwX2J5KHllYXIsIHN0YXRlLCBjb3VudHksIEZJUFMsIFJhY2UsIGdlbmRlciwgYWdlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UocG9wdWxhdGlvbj0oc3VtKGFzLm51bWVyaWMocG9wdWxhdGlvbiksIG5hLnJtID0gVFJVRSkpKQ0KDQpUb3RhbF9kZiA8LSBjb3VudHlQb3AgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHllYXIsIHN0YXRlLCBjb3VudHksIEZJUFMsIGFnZSwgVG90YWxfTWFsZSwgVG90YWxfRmVtYWxlLCBUb3RhbF9Cb3RoKSAlPiUgDQogIGRwbHlyOjpyZW5hbWUoTWFsZT1Ub3RhbF9NYWxlLCBGZW1hbGU9VG90YWxfRmVtYWxlLCBCb3RoPVRvdGFsX0JvdGgpICU+JSANCiAgdGlkeXI6OmdhdGhlcihnZW5kZXIsIHBvcHVsYXRpb24sIDY6OCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKFJhY2U9IlRvdGFsIikgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBzdGF0ZSwgY291bnR5LCBGSVBTLCBSYWNlLCBnZW5kZXIsIGFnZSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKHBvcHVsYXRpb249KHN1bShhcy5udW1lcmljKHBvcHVsYXRpb24pLCBuYS5ybSA9IFRSVUUpKSkNCg0KQmxhY2tfZGYgPC0gY291bnR5UG9wICU+JSANCiAgZHBseXI6OnNlbGVjdCh5ZWFyLCBzdGF0ZSwgY291bnR5LCBGSVBTLCBhZ2UsIEJsYWNrX01hbGUsIEJsYWNrX0ZlbWFsZSwgQmxhY2tfQm90aCkgJT4lIA0KICBkcGx5cjo6cmVuYW1lKE1hbGU9QmxhY2tfTWFsZSwgRmVtYWxlPUJsYWNrX0ZlbWFsZSwgQm90aD1CbGFja19Cb3RoKSAlPiUgDQogIHRpZHlyOjpnYXRoZXIoZ2VuZGVyLCBwb3B1bGF0aW9uLCA2OjgpICU+JSANCiAgZHBseXI6Om11dGF0ZShSYWNlPSJCbGFjayIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHllYXIsIHN0YXRlLCBjb3VudHksIEZJUFMsIFJhY2UsIGdlbmRlciwgYWdlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UocG9wdWxhdGlvbj0oc3VtKGFzLm51bWVyaWMocG9wdWxhdGlvbiksIG5hLnJtID0gVFJVRSkpKQ0KDQpBc2lhbl9kZiA8LSBjb3VudHlQb3AgJT4lIA0KICBkcGx5cjo6c2VsZWN0KHllYXIsIHN0YXRlLCBjb3VudHksIEZJUFMsIGFnZSwgQXNpYW5fTWFsZSwgQXNpYW5fRmVtYWxlLCBBc2lhbl9Cb3RoKSAlPiUgDQogIGRwbHlyOjpyZW5hbWUoTWFsZT1Bc2lhbl9NYWxlLCBGZW1hbGU9QXNpYW5fRmVtYWxlLCBCb3RoPUFzaWFuX0JvdGgpICU+JSANCiAgdGlkeXI6OmdhdGhlcihnZW5kZXIsIHBvcHVsYXRpb24sIDY6OCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKFJhY2U9IkFzaWFuIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoeWVhciwgc3RhdGUsIGNvdW50eSwgRklQUywgUmFjZSwgZ2VuZGVyLCBhZ2UpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShwb3B1bGF0aW9uPShzdW0oYXMubnVtZXJpYyhwb3B1bGF0aW9uKSwgbmEucm0gPSBUUlVFKSkpDQoNCkFtZXJpbmRpYW5fZGYgPC0gY291bnR5UG9wICU+JSANCiAgZHBseXI6OnNlbGVjdCh5ZWFyLCBzdGF0ZSwgY291bnR5LCBGSVBTLCBhZ2UsIEFtZXJpbmRpYW5fTWFsZSwgQW1lcmluZGlhbl9GZW1hbGUsIEFtZXJpbmRpYW5fQm90aCkgJT4lIA0KICBkcGx5cjo6cmVuYW1lKE1hbGU9QW1lcmluZGlhbl9NYWxlLCBGZW1hbGU9QW1lcmluZGlhbl9GZW1hbGUsIEJvdGg9QW1lcmluZGlhbl9Cb3RoKSAlPiUgDQogIHRpZHlyOjpnYXRoZXIoZ2VuZGVyLCBwb3B1bGF0aW9uLCA2OjgpICU+JSANCiAgZHBseXI6Om11dGF0ZShSYWNlPSJOYXRpdmUgQW1lcmljYW4iKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh5ZWFyLCBzdGF0ZSwgY291bnR5LCBGSVBTLCBSYWNlLCBnZW5kZXIsIGFnZSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKHBvcHVsYXRpb249KHN1bShhcy5udW1lcmljKHBvcHVsYXRpb24pLCBuYS5ybSA9IFRSVUUpKSkNCg0KSGlzcGFuaWNfZGYgPC0gY291bnR5UG9wICU+JSANCiAgZHBseXI6OnNlbGVjdCh5ZWFyLCBzdGF0ZSwgY291bnR5LCBGSVBTLCBhZ2UsIEhpc3BhbmljX01hbGUsIEhpc3BhbmljX0ZlbWFsZSwgSGlzcGFuaWNfQm90aCkgJT4lIA0KICBkcGx5cjo6cmVuYW1lKE1hbGU9SGlzcGFuaWNfTWFsZSwgRmVtYWxlPUhpc3BhbmljX0ZlbWFsZSwgQm90aD1IaXNwYW5pY19Cb3RoKSAlPiUgDQogIHRpZHlyOjpnYXRoZXIoZ2VuZGVyLCBwb3B1bGF0aW9uLCA2OjgpICU+JSANCiAgZHBseXI6Om11dGF0ZShSYWNlPSJIaXNwYW5pYyIpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHllYXIsIHN0YXRlLCBjb3VudHksIEZJUFMsIFJhY2UsIGdlbmRlciwgYWdlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UocG9wdWxhdGlvbj0oc3VtKGFzLm51bWVyaWMocG9wdWxhdGlvbiksIG5hLnJtID0gVFJVRSkpKQ0KDQpQYWNpZmljSXNsYW5kZXJfZGYgPC0gY291bnR5UG9wICU+JSANCiAgZHBseXI6OnNlbGVjdCh5ZWFyLCBzdGF0ZSwgY291bnR5LCBGSVBTLCBhZ2UsIFBhY2lmaWNJc2xhbmRlcl9NYWxlLCBQYWNpZmljSXNsYW5kZXJfRmVtYWxlLCBQYWNpZmljSXNsYW5kZXJfQm90aCkgJT4lIA0KICBkcGx5cjo6cmVuYW1lKE1hbGU9UGFjaWZpY0lzbGFuZGVyX01hbGUsIEZlbWFsZT1QYWNpZmljSXNsYW5kZXJfRmVtYWxlLCBCb3RoPVBhY2lmaWNJc2xhbmRlcl9Cb3RoKSAlPiUgDQogIHRpZHlyOjpnYXRoZXIoZ2VuZGVyLCBwb3B1bGF0aW9uLCA2OjgpICU+JSANCiAgZHBseXI6Om11dGF0ZShSYWNlPSJQYWNpZmljIElzbGFuZGVyIikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoeWVhciwgc3RhdGUsIGNvdW50eSwgRklQUywgUmFjZSwgZ2VuZGVyLCBhZ2UpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShwb3B1bGF0aW9uPShzdW0oYXMubnVtZXJpYyhwb3B1bGF0aW9uKSwgbmEucm0gPSBUUlVFKSkpDQoNCiMjUmVjb21iaW5lIC0gY2FuIGRlbGV0ZSB0b3RhbCxib3RoLCBhbmQgYWxsIHZhbHVlcw0KY291bnR5UG9wMiA8LSBiaW5kX3Jvd3MoVG90YWxfZGYgLCB3aGl0ZV9kZiwgQmxhY2tfZGYsIEhpc3BhbmljX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgQXNpYW5fZGYsIEFtZXJpbmRpYW5fZGYsIFBhY2lmaWNJc2xhbmRlcl9kZg0KICAgICAgICAgICAgICAgICAgICAgICAgKQ0KDQpjZW5zdXNfY291bnR5IDwtIGNvdW50eVBvcDINCnJtKGNvdW50eVBvcDIpDQpybShjb3VudHlQb3ApDQojZnN0Ojp3cml0ZS5mc3QoY291bnR5UG9wMiwgcGF0aD0iY2Vuc3VzX2NvdW50eS5jc3YiKQ0KI3dyaXRlLmNzdihjb3VudHlQb3AyLCBmaWxlPSJjZW5zdXNfY291bnR5LmNzdiIpDQoNCmBgYA0KDQoNCiMjI05ZQyBDb3JyZWN0aW9uDQpgYGB7cn0NCm55RmlwcyA8LSBjKCJgMzYwNjEiLCAiYDM2MDQ3IiwgImAzNjA4MSIsICJgMzYwMDUiLCAiYDM2MDg1IikNCg0KY2Vuc3VzX2NvdW50eSA8LSBjZW5zdXNfY291bnR5ICU+JSB1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKEZJUFMgPSByZXBsYWNlKEZJUFMsIHdoaWNoKEZJUFMgJWluJSBueUZpcHMpLCAiYDM2MDYxIikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHllYXIsIEZJUFMsIFJhY2UsIGdlbmRlciwgYWdlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UocG9wdWxhdGlvbj1zdW0ocG9wdWxhdGlvbiwgbmEucm09VCksDQogICAgICAgICAgICAgICAgICAgc3RhdGU9Zmlyc3Qoc3RhdGUpLA0KICAgICAgICAgICAgICAgICAgIGNvdW50eT1maXJzdChjb3VudHkpKQ0KYGBgDQoNCg0KIyMjIENvdW50eSBQb3B1bGF0aW9ucw0KQWxsIHBvcHVsYXRpb24gdmFyaWFibGVzIGFyZSBmb3IgeWVhciAyMDE1LCBleGNlcHQgdmFyaWFibGVzIGFwcGVuZGVkIHdpdGggIjV5ciIsIHdoaWNoIGFyZSBhdmVyYWdlZCBhY3Jvc3MgMjAxMSB0byAyMDE1LiAgVmFyaWFibGVzIGFwcGVuZGVkIHdpdGggImNoYW5nZSIgYXJlIHRoZSBwZXJjZW50IGNoYW5nZSBmcm9tIDIwMTEgdG8gMjAxNS4NCg0KYGBge3J9DQoNCg0KY2Vuc3VzX3ZhcnMgPC0gY2Vuc3VzX2NvdW50eSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh5ZWFyLCBGSVBTKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgcG9wLmMudG90YWwgPSBwb3B1bGF0aW9uW3doaWNoKFJhY2U9PSJUb3RhbCIgICYgZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiKV0sDQogICAgcG9wLmMud2hpdGVfbmggPSBwb3B1bGF0aW9uW3doaWNoKFJhY2U9PSJXaGl0ZSIgICYgZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiKV0sDQogICAgcG9wLmMuYmxhY2sgPSBwb3B1bGF0aW9uW3doaWNoKFJhY2UgPT0gIkJsYWNrIiAmIGdlbmRlcj09IkJvdGgiICYgYWdlPT0iQWxsIildLA0KICAgIHBvcC5jLmFzaWFuID0gcG9wdWxhdGlvblt3aGljaChSYWNlPT0iQXNpYW4iICYgZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiKV0sDQogICAgI0NyZWF0ZSBBc2lhbi9QQWNpZmljIElzbGFuZGVyIENhdGVnb3J5IGZvciBzb21lIGRhdGFzZXRzIHRoYXQgY29uZmxhdGUgdGhlIHR3bw0KICAgIHBvcC5jLkFQID0gbWVhbihwb3B1bGF0aW9uW3doaWNoKGdlbmRlcj09IkJvdGgiICYgYWdlPT0iQWxsIiAmIChSYWNlID09ICJBc2lhbiIgfCBSYWNlID09ICJQYWNpZmljIElzbGFuZGVyIikpXSwgbmEucm09VCksDQogICAgIyNDcmVhdGUgV2hpdGUvSGlzcGFuaWMgY2F0ZWdvcnkgdG8gbWF0Y2ggVUNSDQogICAgcG9wLmMuV0ggPSBtZWFuKHBvcHVsYXRpb25bd2hpY2goZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiICYgKFJhY2UgPT0gIldoaXRlIiB8IFJhY2UgPT0gIkhpc3BhbmljIikpXSwgbmEucm09VCksDQogICAgcG9wLmMuYW1lcmluZGlhbiA9IHBvcHVsYXRpb25bd2hpY2goUmFjZT09Ik5hdGl2ZSBBbWVyaWNhbiIgICYgZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiKV0sDQogICAgcG9wLmMuaGlzcGFuaWMgPSBwb3B1bGF0aW9uW3doaWNoKFJhY2U9PSJIaXNwYW5pYyIgICYgZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiKV0sDQogICAgcG9wLm1hbGUuMTVfMjkgPSBzdW0ocG9wdWxhdGlvblt3aGljaChSYWNlPT0iVG90YWwiICYgZ2VuZGVyPT0iTWFsZSIgJiBhZ2UgJWluJSBjKCIxNV8xOSIsIjIwXzI0IiwiMjVfMjkiKSldLCBuYS5ybT1UKSwNCiAgICBwb3AuYmxhY2subWFsZTE1XzI5ID0gc3VtKHBvcHVsYXRpb25bd2hpY2goUmFjZT09IkJsYWNrIiAgJiBnZW5kZXI9PSJNYWxlIiAmIGFnZSAlaW4lIGMoIjE1XzE5IiwiMjBfMjQiLCIyNV8yOSIpKV0pDQogICkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoRklQUykgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgICMjQXZlcmFnZWQgYXJvc3MgMjAxMS0yMDE1ICAgIA0KICAgIHBvcC5jLnRvdGFsXzV5ciA9IG1lYW4ocG9wLmMudG90YWwsIG5hLnJtPVQpLA0KICAgICAgICAgcG9wLmMud2hpdGVfbmhfNXlyID0gbWVhbihwb3AuYy53aGl0ZV9uaCwgbmEucm09VCksDQogICAgICAgICAgcG9wLmMuV0hfNXlyID0gbWVhbihwb3AuYy5XSCwgbmEucm09VCksDQogICAgICAgICBwb3AuYy5ibGFja181eXIgPSBtZWFuKHBvcC5jLmJsYWNrLCBuYS5ybT1UKSwNCiAgICAgICAgIHBvcC5jLmFzaWFuXzV5ciA9IG1lYW4ocG9wLmMuYXNpYW4sIG5hLnJtPVQpLA0KICAgICAgICAgcG9wLmMuaGlzcGFuaWNfNXlyID0gbWVhbihwb3AuYy5oaXNwYW5pYywgbmEucm09VCksDQogICAgICAgICBwb3AuYy5hbWVyaW5kaWFuXzV5ciA9IG1lYW4ocG9wLmMuYW1lcmluZGlhbiwgbmEucm09VCksDQogICAgICAgICBwb3AubWFsZS4xNV8yOV81eXIgPSBtZWFuKHBvcC5tYWxlLjE1XzI5LCBuYS5ybT1UKSwNCiAgDQogICAgIyNDaGFuZ2UgZnJvbSAyMDExIC0gMjAxNSANCiAgcG9wLmMudG90YWxfY2hhbmdlID0gbWVhbigocG9wLmMudG90YWxbd2hpY2goeWVhcj09MjAxNSldLXBvcC5jLnRvdGFsW3doaWNoKHllYXI9PTIwMTEpXSkvcG9wLmMudG90YWxbd2hpY2goeWVhcj09MjAxMSldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSwNCiAgcG9wLmMud2hpdGVfbmhfY2hhbmdlID0gbWVhbigocG9wLmMud2hpdGVfbmhbd2hpY2goeWVhcj09MjAxNSldLXBvcC5jLndoaXRlX25oW3doaWNoKHllYXI9PTIwMTEpXSkvcG9wLmMud2hpdGVfbmhbd2hpY2goeWVhcj09MjAxMSldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5ybT1UKSwNCiAgDQogIA0KICBwb3AuYy5ibGFja19jaGFuZ2UgPSBtZWFuKChwb3AuYy5ibGFja1t3aGljaCh5ZWFyPT0yMDE1KV0tcG9wLmMuYmxhY2tbd2hpY2goeWVhcj09MjAxMSldKS9wb3AuYy5ibGFja1t3aGljaCh5ZWFyPT0yMDExKV0sIG5hLnJtPVQpLA0KICANCiAgIyNBIGZldyBjb3VudGllcyBoYWQgemVybyBibGFja3MsIHdoaWNoIHJlc3VsdGVkIGluIGluZmluaXRlIHZhbHVlcyAoZGl2aXNpb24gYnkgemVybyksIHRoZXJlZm9yZSBhZGRpbmcgKyAxDQogIHBvcC5jLmJsYWNrX2NoYW5nZSA9IGlmZWxzZShpcy5pbmZpbml0ZShwb3AuYy5ibGFja19jaGFuZ2UpLCAgDQogICAgICAgICNJZiBpbmZpbml0ZSwgY2hhbmdlICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgbWVhbigoKHBvcC5jLmJsYWNrW3doaWNoKHllYXI9PTIwMTUpXSsxKS0ocG9wLmMuYmxhY2tbd2hpY2goeWVhcj09MjAxMSldKzEpKS8ocG9wLmMuYmxhY2tbd2hpY2goeWVhcj09MjAxMSldKzEpLCBuYS5ybT1UKSwgIA0KICAgICAgICAjI0lmIG5vdCBpbmZpbml0ZSwga2VlcCB0aGUgc2FtZQ0KICAgICAgICBwb3AuYy5ibGFja19jaGFuZ2UpDQogIA0KICApICU+JSANCiAgZHBseXI6OmZpbHRlcih5ZWFyPT0yMDE1LCBSYWNlPT0iVG90YWwiLCBhZ2U9PSJBbGwiLCBnZW5kZXI9PSJCb3RoIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1SYWNlLCAtZ2VuZGVyLCAtYWdlLCAteWVhcikNCiAgDQoNCg0KDQoNCmBgYA0KDQoNCiMjMi4gU1RBVEUtTEVWRUwgUG9wdWxhdGlvbiBEYXRhDQpTdGF0ZSBDaGFyYWN0ZXJpc3RpY3MgRGF0YXNldHM6IEFubnVhbCBTdGF0ZSBSZXNpZGVudCBQb3B1bGF0aW9uIEVzdGltYXRlcyBmb3IgNSBSYWNlIEdyb3VwcyAoNSBSYWNlIEFsb25lIG9yIGluIENvbWJpbmF0aW9uIEdyb3VwcykgYnkgQWdlLCBTZXgsIGFuZCBIaXNwYW5pYyBPcmlnaW46IEFwcmlsIDEsIDIwMTAgdG8gSnVseSAxLCAyMDE1DQpodHRwczovL3d3dzIuY2Vuc3VzLmdvdi9wcm9ncmFtcy1zdXJ2ZXlzL3BvcGVzdC9kYXRhc2V0cy8yMDEwLTIwMTUvc3RhdGUvYXNyaC9zYy1lc3QyMDE1LWFsbGRhdGE1LmNzdg0KDQojIyNMb2FkIERhdGEgZnJvbSBDZW5zdXMgd2Vic2l0ZQ0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmNlbnN1c19zdGF0ZSA8LSByZWFkX2NzdigiaHR0cHM6Ly93d3cyLmNlbnN1cy5nb3YvcHJvZ3JhbXMtc3VydmV5cy9wb3Blc3QvZGF0YXNldHMvMjAxMC0yMDE1L3N0YXRlL2Fzcmgvc2MtZXN0MjAxNS1hbGxkYXRhNS5jc3YiKQ0KICANCiMjZm9ybWVybHksIHJlYWRfY3N2KCJodHRwczovL3d3dy5jZW5zdXMuZ292L3BvcGVzdC9kYXRhL3N0YXRlL2FzcmgvMjAxNS9maWxlcy9TQy1FU1QyMDE1LUFMTERBVEE1LmNzdiIpDQoNCmNlbnN1c19zdGF0ZTIgPC0gY2Vuc3VzX3N0YXRlICU+JSANCiAgdHJhbnNtdXRlKFN0YXRlPU5BTUUsIGdlbmRlcj1TRVgsIEhpc3A9T1JJR0lOLCBSYWNlPVJBQ0UsIEFHRT1BR0UsDQogICAgICAgICAgICB5MjAxMT1QT1BFU1RJTUFURTIwMTEsIHkyMDEyPVBPUEVTVElNQVRFMjAxMiwNCiAgICAgICAgICAgIHkyMDEzPVBPUEVTVElNQVRFMjAxMywgeTIwMTQ9UE9QRVNUSU1BVEUyMDE0LA0KICAgICAgICAgICAgeTIwMTU9UE9QRVNUSU1BVEUyMDE1KSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgZ2VuZGVyPXJlcGxhY2UoZ2VuZGVyLCB3aGljaChnZW5kZXI9PTApLCAiQm90aCIpLA0KICAgIGdlbmRlcj1yZXBsYWNlKGdlbmRlciwgd2hpY2goZ2VuZGVyPT0xKSwgIk1hbGUiKSwNCiAgICBnZW5kZXI9cmVwbGFjZShnZW5kZXIsIHdoaWNoKGdlbmRlcj09MiksICJGZW1hbGUiKSwNCiAgICAgICAgYWdlPU5BLA0KICAgICAgICAgYWdlPXJlcGxhY2UoYWdlLCB3aGljaChBR0UgPCAxNSksICJVbmRlcjE1IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49MTUgJiBBR0U8PTE5KSwgIjE1XzE5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49MjAgJiBBR0U8PTI0KSwgIjIwXzI0IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49MjUgJiBBR0U8PTI5KSwgIjI1XzI5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49MzAgJiBBR0U8PTM0KSwgIjMwXzM0IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49MzUgJiBBR0U8PTM5KSwgIjM1XzM5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49NDAgJiBBR0U8PTQ0KSwgIjQwXzQ0IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49NDUgJiBBR0U8PTQ5KSwgIjQ1XzQ5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49NTAgJiBBR0U8PTU0KSwgIjUwXzU0IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49NTUgJiBBR0U8PTU5KSwgIjU1XzU5IiksDQogICAgICAgICBhZ2U9cmVwbGFjZShhZ2UsIHdoaWNoKEFHRT49NjApLCAiNjBBYm92ZSIpLA0KICAgICMjTmVlZCB0byBhZGQgYSByb3cgZm9yIGFsbCBhZ2VzLCBvciBub3QNCiAgICAgICAgI2FnZT1yZXBsYWNlKGFnZSwgd2hpY2goYWdlPT0wKSwgIkFsbCIpLA0KICAgIA0KICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0xICYgSGlzcD09MSksICJXaGl0ZSIpLA0KICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0xICYgSGlzcD09MiksICJIaXNwYW5pYyIpLA0KICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0yICYgSGlzcD09MCksICJCbGFjayIpLA0KICAgIFJhY2U9cmVwbGFjZShSYWNlLCB3aGljaChSYWNlPT0zICYgSGlzcD09MCksICJOYXRpdmUgQW1lcmljYW4iKSwNCiAgICBSYWNlPXJlcGxhY2UoUmFjZSwgd2hpY2goUmFjZT09NCAmIEhpc3A9PTApLCAiQXNpYW4iKSwNCiAgICBSYWNlPXJlcGxhY2UoUmFjZSwgd2hpY2goUmFjZT09NSAmIEhpc3A9PTApLCAiUGFjaWZpYyBJc2xhbmRlciIpDQogICkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1jKEhpc3AsIEFHRSkpICU+JSANCiAgZHBseXI6OmZpbHRlcihSYWNlICVpbiUgYygiV2hpdGUiLCAiSGlzcGFuaWMiLCAiQmxhY2siLCJBc2lhbiIsDQogICAgICAgICAgICAgICAgICAgICAiTmF0aXZlIEFtZXJpY2FuIiwgIlBhY2lmaWMgSXNsYW5kZXIiKSkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoU3RhdGUsIFJhY2UsIGdlbmRlciwgYWdlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoeTIwMTE9c3VtKHkyMDExLCBuYS5ybT1UKSwNCiAgICAgICAgICAgIHkyMDEyPXN1bSh5MjAxMiwgbmEucm09VCksDQogICAgICAgICAgICB5MjAxMz1zdW0oeTIwMTMsIG5hLnJtPVQpLA0KICAgICAgICAgICAgeTIwMTQ9c3VtKHkyMDE0LCBuYS5ybT1UKSwNCiAgICAgICAgICAgIHkyMDE1PXN1bSh5MjAxNSwgbmEucm09VCkNCiAgICAgICAgICAgIA0KICAgICAgICAgICAgKSAlPiUgDQogICMjI0ZpbGUgc2l6ZSBwcmlvciB0byB0aWR5aW5nOiAgNjMxIEtCDQogICMjI0ZpbGUgc2l6ZSBhZnRlciBnYXRoZXJpbmcgeWVhcnMgaW50byBvbmUgY29sdW1uOiAgMjU0NCBLQi4gICANCiAgdGlkeXI6OmdhdGhlcih5ZWFyLCBwb3B1bGF0aW9uLCA1OjkpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICB5ZWFyPXJlcGxhY2UoeWVhciwgd2hpY2goeWVhcj09InkyMDExIiksIDIwMTEpLA0KICAgIHllYXI9cmVwbGFjZSh5ZWFyLCB3aGljaCh5ZWFyPT0ieTIwMTIiKSwgMjAxMiksDQogICAgeWVhcj1yZXBsYWNlKHllYXIsIHdoaWNoKHllYXI9PSJ5MjAxMyIpLCAyMDEzKSwNCiAgICB5ZWFyPXJlcGxhY2UoeWVhciwgd2hpY2goeWVhcj09InkyMDE0IiksIDIwMTQpLA0KICAgIHllYXI9cmVwbGFjZSh5ZWFyLCB3aGljaCh5ZWFyPT0ieTIwMTUiKSwgMjAxNSkNCiAgKQ0KDQojI0FkZGluZyBhIHN1bW1hcnkgY2F0ZWdvcmllczoNCiMjU3RhdGUgPSBVbml0ZWQgU3RhdGVzDQojI2dlbmRlciA9ICdCb3RoJyAoYWxyZWFkeSBjcmVhdGVkKQ0KIyNhZ2UgPSAnQWxsJw0KIyNSYWNlID0gJ1RvdGFsJw0KDQojI2FnZSAtJ0FsbCcNCmFnZV9kZiA8LSBjZW5zdXNfc3RhdGUyICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHllYXIsIFN0YXRlLCBSYWNlLCBnZW5kZXIpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShwb3B1bGF0aW9uPXN1bShwb3B1bGF0aW9uLCBuYS5ybT1UKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGFnZT0iQWxsIikNCg0KY2Vuc3VzX3N0YXRlMiA8LSBkcGx5cjo6YmluZF9yb3dzKGNlbnN1c19zdGF0ZTIsIGFnZV9kZikNCg0KIyNSYWNlIC0gVG90YWwNCnJhY2VfZGYgPC0gY2Vuc3VzX3N0YXRlMiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh5ZWFyLCBTdGF0ZSwgZ2VuZGVyLCBhZ2UpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShwb3B1bGF0aW9uPXN1bShwb3B1bGF0aW9uLCBuYS5ybT1UKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKFJhY2U9IlRvdGFsIikNCg0KY2Vuc3VzX3N0YXRlMiA8LSBkcGx5cjo6YmluZF9yb3dzKGNlbnN1c19zdGF0ZTIsIHJhY2VfZGYpDQoNCiMjU3RhdGU9VVMNCg0KdXNfZGYgPC0gY2Vuc3VzX3N0YXRlMiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh5ZWFyLCBnZW5kZXIsIFJhY2UsIGFnZSkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKHBvcHVsYXRpb249c3VtKHBvcHVsYXRpb24sIG5hLnJtPVQpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoU3RhdGU9IlVuaXRlZCBTdGF0ZXMiKQ0KDQpjZW5zdXNfc3RhdGUgPC0gZHBseXI6OmJpbmRfcm93cyhjZW5zdXNfc3RhdGUyLCB1c19kZikNCiMjZmlsZSBzaXplIGFmdGVyIGFkZGluZyByb3dzOiAgMzM2NiBLQg0KIyN3cml0ZS5jc3YoY2Vuc3VzX3N0YXRlLCBmaWxlPSJjZW5zdXNfc3RhdGUuY3N2IikNCmBgYA0KDQojIyMgU3RhdGUgUG9wdWxhdGlvbnMNCkFsbCBwb3B1bGF0aW9uIHZhcmlhYmxlcyBhcmUgZm9yIHllYXIgMjAxNSwgZXhjZXB0IHZhcmlhYmxlcyBhcHBlbmRlZCB3aXRoICI1eXIiLCB3aGljaCBhcmUgYXZlcmFnZWQgYWNyb3NzIDIwMTEgdG8gMjAxNS4gIFZhcmlhYmxlcyBhcHBlbmRlZCB3aXRoICJjaGFuZ2UiIGFyZSB0aGUgcGVyY2VudCBjaGFuZ2UgZnJvbSAyMDExIHRvIDIwMTUuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KDQpjZW5zdXNfc3RhdGUgPC0gY2Vuc3VzX3N0YXRlICU+JSANCiAgIGRwbHlyOjpncm91cF9ieSh5ZWFyLCBTdGF0ZSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIHBvcC50b3RhbCA9IHBvcHVsYXRpb25bd2hpY2goUmFjZT09IlRvdGFsIiAgJiBnZW5kZXI9PSJCb3RoIiAmIGFnZT09IkFsbCIpXSwNCiAgICBwb3Aud2hpdGVfbmggPSBwb3B1bGF0aW9uW3doaWNoKFJhY2U9PSJXaGl0ZSIgICYgZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiKV0sDQogICAgcG9wLmJsYWNrID0gcG9wdWxhdGlvblt3aGljaChSYWNlID09ICJCbGFjayIgJiBnZW5kZXI9PSJCb3RoIiAmIGFnZT09IkFsbCIpXSwNCiAgICBwb3AuYXNpYW4gPSBwb3B1bGF0aW9uW3doaWNoKFJhY2U9PSJBc2lhbiIgJiBnZW5kZXI9PSJCb3RoIiAmIGFnZT09IkFsbCIpXSwNCiAgICAjQ3JlYXRlIEFzaWFuL1BBY2lmaWMgSXNsYW5kZXIgQ2F0ZWdvcnkgZm9yIHNvbWUgZGF0YXNldHMgdGhhdCBjb25mbGF0ZSB0aGUgdHdvDQogICAgcG9wLkFQID0gbWVhbihwb3B1bGF0aW9uW3doaWNoKGdlbmRlcj09IkJvdGgiICYgYWdlPT0iQWxsIiAmIChSYWNlID09ICJBc2lhbiIgfCBSYWNlID09ICJQYWNpZmljIElzbGFuZGVyIikpXSwgbmEucm09VCksDQogICAgIyNDcmVhdGUgV2hpdGUvSGlzcGFuaWMgY2F0ZWdvcnkgdG8gbWF0Y2ggVUNSDQogICAgcG9wLldIID0gbWVhbihwb3B1bGF0aW9uW3doaWNoKGdlbmRlcj09IkJvdGgiICYgYWdlPT0iQWxsIiAmIChSYWNlID09ICJXaGl0ZSIgfCBSYWNlID09ICJIaXNwYW5pYyIpKV0sIG5hLnJtPVQpLA0KICAgIHBvcC5hbWVyaW5kaWFuID0gcG9wdWxhdGlvblt3aGljaChSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIiAgJiBnZW5kZXI9PSJCb3RoIiAmIGFnZT09IkFsbCIpXSwNCiAgICBwb3AuaGlzcGFuaWMgPSBwb3B1bGF0aW9uW3doaWNoKFJhY2U9PSJIaXNwYW5pYyIgICYgZ2VuZGVyPT0iQm90aCIgJiBhZ2U9PSJBbGwiKV0sDQogICAgcG9wLm1hbGUuMTVfMjkgPSBzdW0ocG9wdWxhdGlvblt3aGljaChSYWNlPT0iVG90YWwiICYgZ2VuZGVyPT0iTWFsZSIgJiBhZ2UgJWluJSBjKCIxNV8xOSIsIjIwXzI0IiwiMjVfMjkiKSldLCBuYS5ybT1UKSwNCiAgICBwb3AuYmxhY2subWFsZTE1XzI5ID0gc3VtKHBvcHVsYXRpb25bd2hpY2goUmFjZT09IkJsYWNrIiAgJiBnZW5kZXI9PSJNYWxlIiAmIGFnZSAlaW4lIGMoIjE1XzE5IiwiMjBfMjQiLCIyNV8yOSIpKV0pDQogICkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoU3RhdGUpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICAjI0F2ZXJhZ2VkIGFyb3NzIDIwMTEtMjAxNSAgICANCiAgICBwb3AudG90YWxfNXlyID0gbWVhbihwb3AudG90YWwsIG5hLnJtPVQpLA0KICAgICAgICAgcG9wLndoaXRlX25oXzV5ciA9IG1lYW4ocG9wLndoaXRlX25oLCBuYS5ybT1UKSwNCiAgICAgICAgICBwb3AuV0hfNXlyID0gbWVhbihwb3AuV0gsIG5hLnJtPVQpLA0KICAgICAgICAgcG9wLmJsYWNrXzV5ciA9IG1lYW4ocG9wLmJsYWNrLCBuYS5ybT1UKSwNCiAgICAgICAgIHBvcC5hc2lhbl81eXIgPSBtZWFuKHBvcC5hc2lhbiwgbmEucm09VCksDQogICAgICAgICBwb3AuaGlzcGFuaWNfNXlyID0gbWVhbihwb3AuaGlzcGFuaWMsIG5hLnJtPVQpLA0KICAgICAgICAgcG9wLmFtZXJpbmRpYW5fNXlyID0gbWVhbihwb3AuYW1lcmluZGlhbiwgbmEucm09VCksDQogICAgICAgICBwb3AubWFsZS4xNV8yOV81eXIgPSBtZWFuKHBvcC5tYWxlLjE1XzI5LCBuYS5ybT1UKSwNCiAgDQogICAgIyNDaGFuZ2UgZnJvbSAyMDExIC0gMjAxNSANCiAgcG9wLnRvdGFsX2NoYW5nZSA9IG1lYW4oKHBvcC50b3RhbFt3aGljaCh5ZWFyPT0yMDE1KV0tcG9wLnRvdGFsW3doaWNoKHllYXI9PTIwMTEpXSkvcG9wLnRvdGFsW3doaWNoKHllYXI9PTIwMTEpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm09VCksDQogIHBvcC53aGl0ZV9uaF9jaGFuZ2UgPSBtZWFuKChwb3Aud2hpdGVfbmhbd2hpY2goeWVhcj09MjAxNSldLXBvcC53aGl0ZV9uaFt3aGljaCh5ZWFyPT0yMDExKV0pL3BvcC53aGl0ZV9uaFt3aGljaCh5ZWFyPT0yMDExKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtPVQpLA0KICANCiAgDQogIHBvcC5ibGFja19jaGFuZ2UgPSBtZWFuKChwb3AuYmxhY2tbd2hpY2goeWVhcj09MjAxNSldLXBvcC5ibGFja1t3aGljaCh5ZWFyPT0yMDExKV0pL3BvcC5ibGFja1t3aGljaCh5ZWFyPT0yMDExKV0sIG5hLnJtPVQpLA0KICANCiAgIyNBIGZldyBjb3VudGllcyBoYWQgemVybyBibGFja3MsIHdoaWNoIHJlc3VsdGVkIGluIGluZmluaXRlIHZhbHVlcyAoZGl2aXNpb24gYnkgemVybyksIHRoZXJlZm9yZSBhZGRpbmcgKyAxDQogIHBvcC5ibGFja19jaGFuZ2UgPSBpZmVsc2UoaXMuaW5maW5pdGUocG9wLmJsYWNrX2NoYW5nZSksICANCiAgICAgICAgI0lmIGluZmluaXRlLCBjaGFuZ2UgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICBtZWFuKCgocG9wLmJsYWNrW3doaWNoKHllYXI9PTIwMTUpXSsxKS0ocG9wLmJsYWNrW3doaWNoKHllYXI9PTIwMTEpXSsxKSkvKHBvcC5ibGFja1t3aGljaCh5ZWFyPT0yMDExKV0rMSksIG5hLnJtPVQpLCAgDQogICAgICAgICMjSWYgbm90IGluZmluaXRlLCBrZWVwIHRoZSBzYW1lDQogICAgICAgIHBvcC5ibGFja19jaGFuZ2UpDQogIA0KICApICU+JSANCiAgZHBseXI6OmZpbHRlcih5ZWFyPT0yMDE1LCBSYWNlPT0iVG90YWwiLCBhZ2U9PSJBbGwiLCBnZW5kZXI9PSJCb3RoIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1SYWNlLCAtZ2VuZGVyLCAtYWdlLCAteWVhcikNCiAgDQoNCg0KYGBgDQoNCg0KDQoNCg0KIyBJSUkuIEFSUkVTVCBEQVRBIChQYW5lbCAzKSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMxLiAgTG9hZCBEYXRhDQojIyMyMDE1IERhdGENCg0KVW5pZm9ybSBDcmltZSBSZXBvcnRpbmcgUHJvZ3JhbSBEYXRhOiBBcnJlc3RzIGJ5IEFnZSwgU2V4LCBhbmQgUmFjZSwgMjAxNSAoSUNQU1IgMzY3OTQpDQpodHRwczovL3d3dy5pY3Bzci51bWljaC5lZHUvaWNwc3J3ZWIvTkFDSkQvc3R1ZGllcy8zNjc5NA0KSUNQU1JfMzY3OTQNCg0KTm90ZSB0aGF0IHRoZSBvZmZlbnNlIGNvZGVzIGNoYW5nZWQgaW4gdGhlIDIwMTUgZWRpdGlvbi4gIEZvciBleGFtcGxlLCBNdXJkZXIgaXMgbm93ICIwMUEiIGluc3RlYWQgb2YgIjAxMSIuICANCkZpbGUgYDM2Nzk0LTAwMDEtRGF0YS50c3ZgDQpJJ3ZlIGNvbnZlcnRlZCB0aGlzIHRvICdmc3QnIGZvcm1hdCBmb3IgZmFzdGVyIGxvYWRpbmcuICANCg0KYGBge3J9DQojIHVjcl8xNSA8LSByZWFkcjo6cmVhZF90c3YoImNyZWF0ZURhdGEvMzY3OTQtMDAwMS1EYXRhLnRzdiIsIG5hID0gYygiIiwgIk5BIiwgOTk5OTk4LCA5OTk5OCwgOTk5OTksIDk5OCkpDQojIGZzdDo6d3JpdGUuZnN0KHVjcl8xNSwgcGF0aD0iY3JlYXRlRGF0YS91Y3JfMTUuY3N2IikNCg0KdWNyXzE1IDwtIGZzdDo6cmVhZC5mc3QocGF0aD0iY3JlYXRlRGF0YS91Y3JfMTUuY3N2IikNCiAgDQpgYGANCg0KDQogIA0KDQoNCiMjIzIwMTQgRGF0YQ0KVW5pZm9ybSBDcmltZSBSZXBvcnRpbmcgUHJvZ3JhbSBEYXRhOiBBcnJlc3RzIGJ5IEFnZSwgU2V4LCBhbmQgUmFjZSwgU3VtbWFyaXplZCBZZWFybHksIDIwMTQgKElDUFNSIDM2NDAwKS4NCmh0dHA6Ly93d3cuaWNwc3IudW1pY2guZWR1L2ljcHNyd2ViL05BQ0pEL3N0dWRpZXMvMzY0MDANCg0KRmlsZSBgMzY0MDAtMDAwMS1EYXRhLnRzdmANCg0KYGBge3J9DQojI0ZpbGUgPSAzNjQwMC0wMDAxLURhdGEudHN2DQojIHVjcl8xNCA8LSByZWFkX3RzdigiY3JlYXRlRGF0YS8zNjQwMC0wMDAxLURhdGEudHN2IiwgbmEgPSBjKCIiLCAiTkEiLCA5OTk5OTgsIDk5OTk4LCA5OTk5OSwgOTk4KSkNCiMgZnN0Ojp3cml0ZS5mc3QodWNyXzE0LCBwYXRoPSJjcmVhdGVEYXRhL3Vjcl8xNC5jc3YiKQ0KDQp1Y3JfMTQgPC0gZnN0OjpyZWFkLmZzdChwYXRoPSJjcmVhdGVEYXRhL3Vjcl8xNC5jc3YiKQ0KDQpgYGANCg0KIyMjMjAxMyBEYXRhDQpVbmlmb3JtIENyaW1lIFJlcG9ydGluZyBQcm9ncmFtIERhdGE6IEFycmVzdHMgYnkgQWdlLCBTZXgsIGFuZCBSYWNlLCBTdW1tYXJpemVkIFllYXJseSwgMjAxMyAoSUNQU1IgMzYxMTYpDQpodHRwOi8vd3d3LmljcHNyLnVtaWNoLmVkdS9pY3BzcndlYi9OQUNKRC9zdHVkaWVzLzM2MTE2DQpGaWxlIGAzNjExNi0wMDAxLURhdGEudHN2YA0KDQpgYGB7cn0NCiMjRmlsZSA9IDM2MTE2LTAwMDEtRGF0YS50c3YNCiMgdWNyXzEzIDwtIHJlYWRfdHN2KCJjcmVhdGVEYXRhLzM2MTE2LTAwMDEtRGF0YS50c3YiLCBuYSA9IGMoIiIsICJOQSIsIDk5OTk5OCwgOTk5OTgsIDk5OTk5LCA5OTgpKQ0KIyBmc3Q6OndyaXRlLmZzdCh1Y3JfMTMsIHBhdGg9ImNyZWF0ZURhdGEvdWNyXzEzLmNzdiIpDQoNCnVjcl8xMyA8LSBmc3Q6OnJlYWQuZnN0KHBhdGg9ImNyZWF0ZURhdGEvdWNyXzEzLmNzdiIpDQoNCmBgYA0KDQoNCiMjIzIwMTIgRGF0YQ0KVW5pZm9ybSBDcmltZSBSZXBvcnRpbmcgUHJvZ3JhbSBEYXRhOiBBcnJlc3RzIGJ5IEFnZSwgU2V4LCBhbmQgUmFjZSwgU3VtbWFyaXplZCBZZWFybHksIDIwMTIgKElDUFNSIDM1MDE4KQ0KaHR0cDovL3d3dy5pY3Bzci51bWljaC5lZHUvaWNwc3J3ZWIvTkFDSkQvc3R1ZGllcy8zNTAxOA0KDQpGaWxlIGAzNTAxOC0wMDAxLURhdGEudHN2YA0KDQpgYGB7cn0NCiMjRmlsZSA9IDM1MDE4LTAwMDEtRGF0YS50c3YNCiMgdWNyXzEyIDwtIHJlYWRfdHN2KCJjcmVhdGVEYXRhLzM1MDE4LTAwMDEtRGF0YS50c3YiLCBuYSA9IGMoIiIsICJOQSIsIDk5OTk5OCwgOTk5OTgsIDk5OTk5LCA5OTgpKQ0KIyBmc3Q6OndyaXRlLmZzdCh1Y3JfMTIsIHBhdGg9ImNyZWF0ZURhdGEvdWNyXzEyLmNzdiIpDQoNCnVjcl8xMiA8LSBmc3Q6OnJlYWQuZnN0KHBhdGg9ImNyZWF0ZURhdGEvdWNyXzEyLmNzdiIpDQoNCmBgYA0KDQojIyMyMDExIERhdGENClVuaWZvcm0gQ3JpbWUgUmVwb3J0aW5nIFByb2dyYW0gRGF0YTogQXJyZXN0cyBieSBBZ2UsIFNleCwgYW5kIFJhY2UsIFN1bW1hcml6ZWQgWWVhcmx5LCAyMDExIChJQ1BTUiAzNDU4MSkNCmh0dHA6Ly93d3cuaWNwc3IudW1pY2guZWR1L2ljcHNyd2ViL05BQ0pEL3N0dWRpZXMvMzQ1ODENCkZpbGUgYDM0NTgxLTAwMDEtRGF0YS50c3ZgDQoNCmBgYHtyfQ0KIyMgRmlsZSA9IDM0NTgxLTAwMDEtRGF0YS50c3YNCiMgdWNyXzExIDwtIHJlYWRfdHN2KCJjcmVhdGVEYXRhLzM0NTgxLTAwMDEtRGF0YS50c3YiLCBuYSA9IGMoIiIsICJOQSIsIDk5OTk5OCwgOTk5OTgsIDk5OTk5LCA5OTgpKQ0KIyBmc3Q6OndyaXRlLmZzdCh1Y3JfMTEsIHBhdGg9ImNyZWF0ZURhdGEvdWNyXzExLmNzdiIpDQoNCnVjcl8xMSA8LSBmc3Q6OnJlYWQuZnN0KHBhdGg9ImNyZWF0ZURhdGEvdWNyXzExLmNzdiIpDQoNCmBgYA0KDQojIzIuIENvbWJpbmUgYW5kIEZpbHRlcg0KTm90ZSB0aGF0IHZpb2xlbnQgY3JpbWUgaXMgY29tcG9zZWQgb2YgZm91ciBvZmZlbnNlczogbXVyZGVyIGFuZCBub25uZWdsaWdlbnQgbWFuc2xhdWdodGVyLCBmb3JjaWJsZSByYXBlLCByb2JiZXJ5LCBhbmQgYWdncmF2YXRlZCBhc3NhdWx0Lg0KDQoNCmBgYHtyfQ0Kb2ZmZW5zZXNfMjAxMV8yMDE0IDwtIGMoIjAxMSIsICIwMjAiLCAiMDMwIiwgIjA0MCIsICIwNTAiLCANCiAgICAgICAgICAgICAgIjA2MCIsICIwNzAiLCAiMTMwIiwgIjE0MCIsICIxODAiLCANCiAgICAgICAgICAgICAgIjE4NSIsICIyMTAiKQ0KDQprZWVwVmFycyA8LSBjKCJZRUFSIiwiU1RBVEUiLCJTVE5BTUUiLCJDT1VOVFkiLCAiT1JJIiwgIkFHRU5DWSIsIk9GRkVOU0UiLCJNMF85IiwgIk0xMF8xMiIsICJNMTNfMTQiLCJNMTUiLCAiTTE2IiwiTTE3IiwiTTE4IiwiTTE5IiwNCiAgICAgICAgICAgICAgIk0yMCIsIk0yMSIsIk0yMiIsIk0yMyIsIk0yNCIsIk0yNV8yOSIsICJNMzBfMzQiLCAiTTM1XzM5IiwgIk00MF80NCIsICJNNDVfNDkiLCAiTTUwXzU0IiwiTTU1XzU5IiwiTTYwXzY0IiwiTTY1IiwiRjBfOSIsDQogICAgICAgICAgICAgICJGMTBfMTIiLCJGMTNfMTQiLCJGMTUiLCJGMTYiLCJGMTciLCJGMTgiLCJGMTkiLCJGMjAiLCJGMjEiLCJGMjIiLCJGMjMiLCJGMjQiLCJGMjVfMjkiLCJGMzBfMzQiLCJGMzVfMzkiLCJGNDBfNDQiLA0KICAgICAgICAgICAgICAiRjQ1XzQ5IiwgICJGNTBfNTQiLCAgIkY1NV81OSIsIkY2MF82NCIsIkY2NSIsIkpXIiwgIkpCIiwiSkkiLCJKQSIsIkFXIiwiQUIiLCAiQUkiLCJBQSIpDQoNCnVjcl8xNSA8LSB1Y3JfMTVbLGtlZXBWYXJzXSANCiB1Y3JfMTUgPC0gdWNyXzE1ICU+JSAgZHBseXI6Om11dGF0ZShjcmltZT1OQSwNCiAgICAgICAgICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09ICIwMUEiKSwgIm11cmRlciIpLA0KICAgICAgICAgICAgICAgICMjTXVyZGVyIGFuZCBub24tbmVnbGlnZW50IG1hbnNsYXVnaHRlcg0KICAgICAgICAgICAgICAgIGNyaW1lPXJlcGxhY2UoY3JpbWUsIHdoaWNoKE9GRkVOU0UgPT0gIjAyIiksICJyYXBlIiksDQogICAgICAgICAgICAgICAgIyNGb3JjaWJsZSByYXBlDQogICAgICAgICAgICAgICAgY3JpbWU9cmVwbGFjZShjcmltZSwgd2hpY2goT0ZGRU5TRSA9PSAiMDMiKSwgInJvYmJlcnkiKSwNCiAgICAgICAgICAgICAgICAjI3JvYmJlcnkNCiAgICAgICAgICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09ICIwNCIpLCAiYXNzYXVsdCIgKSwNCiAgICAgICAgICAgICAgICAjI0FnZ3JhdmF0ZWQgYXNzYXVsdA0KICAgICAgICAgICAgICAgIGNyaW1lPXJlcGxhY2UoY3JpbWUsIHdoaWNoKE9GRkVOU0UgPT0gIjA1IiksICJidXJnbGFyeSIgKSwNCiAgICAgICAgICAgICAgICAjI0J1cmdsYXJ5LWJyZWFraW5nIG9yIGVudGVyaW5nDQogICAgICAgICAgICAgICAgY3JpbWU9cmVwbGFjZShjcmltZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaChPRkZFTlNFICVpbiUgYygiMDYiLCAiMDciLCAiMTMiKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRoZWZ0IiApLA0KICAgICAgICAgICAgICAgICMjIDA2MCA9IExhcmNlbnktdGhlZnQgKG5vdCBtb3RvciB2ZWhpY2xlKQ0KICAgICAgICAgICAgICAgICMjIDA3MCA9IE1vdG9yIHZlaGljbGUgdGhlZnQNCiAgICAgICAgICAgICAgICAjIyAxMzAgPSBTdG9sZW4gcHJvcGVydHktYnV5LCByZWNlaXZlLCBwb3NzLg0KICAgICAgICAgICAgICAgIGNyaW1lPXJlcGxhY2UoY3JpbWUsIHdoaWNoKE9GRkVOU0UgPT0gIjE0MCIpLCAidmFuZGFsaXNtIiApLA0KICAgICAgICAgICAgICAgICMjVmFuZGFsaXNtDQogICAgICAgICAgICAgICAgY3JpbWU9cmVwbGFjZShjcmltZSwgd2hpY2goT0ZGRU5TRSA9PSIxODAiKSwgImRydWdfc2FsZSIpLA0KICAgICAgICAgICAgICAgICMjU2FsZS9tYW51ZmFjdHVyZSAoc3VidG90YWwpIC0gZHJ1Z3MNCiAgICAgICAgICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09IjE4NSIpLCAiZHJ1Z19wb3NzIiksDQogICAgICAgICAgICAgICAgIyNQb3NzZXNzaW9uIChzdWJ0b3RhbCkNCiAgICAgICAgICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09IjIxIiksICJkdWkiKQ0KICAgICAgICAgICAgICAgICMjRHJpdmluZyB1bmRlciB0aGUgaW5mbHVlbmNlDQogICkgJT4lICMjZWxpbWluYXRpbmcgZGF0YSBmb3Igb3RoZXIgY3JpbWVzDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKGNyaW1lKSkNCg0KdWNyIDwtIGRwbHlyOjpiaW5kX3Jvd3ModWNyXzExLCB1Y3JfMTIsIHVjcl8xMywgdWNyXzE0KSANCnVjciA8LSB1Y3JbLGtlZXBWYXJzXSANCg0KICAjI2RwbHlyOjpmaWx0ZXIoT0ZGRU5TRSAlaW4lIG9mZmVuc2VzXzIwMTFfMjAxNCkgJT4lIA0KICAjI2RwbHlyOjpzZWxlY3QoYyg3LCAzLCAxOCwgMTMsIDQsIDE3LCAyMjo3MCwgNzM6NzYpKSAlPiUgDQp1Y3IgPC0gdWNyICU+JSBkcGx5cjo6bXV0YXRlKGNyaW1lPU5BLA0KICAgICAgICAgY3JpbWU9cmVwbGFjZShjcmltZSwgd2hpY2goT0ZGRU5TRSA9PSAiMDExIiksICJtdXJkZXIiKSwNCiAgICAgICAgICMjTXVyZGVyIGFuZCBub24tbmVnbGlnZW50IG1hbnNsYXVnaHRlcg0KICAgICAgICAgY3JpbWU9cmVwbGFjZShjcmltZSwgd2hpY2goT0ZGRU5TRSA9PSAiMDIwIiksICJyYXBlIiksDQogICAgICAgICAjI0ZvcmNpYmxlIHJhcGUNCiAgICAgICAgIGNyaW1lPXJlcGxhY2UoY3JpbWUsIHdoaWNoKE9GRkVOU0UgPT0gIjAzMCIpLCAicm9iYmVyeSIpLA0KICAgICAgICAgIyNyb2JiZXJ5DQogICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09ICIwNDAiKSwgImFzc2F1bHQiICksDQogICAgICAgICAjI0FnZ3JhdmF0ZWQgYXNzYXVsdA0KICAgICAgICAgY3JpbWU9cmVwbGFjZShjcmltZSwgd2hpY2goT0ZGRU5TRSA9PSAiMDUwIiksICJidXJnbGFyeSIgKSwNCiAgICAgICAgICMjQnVyZ2xhcnktYnJlYWtpbmcgb3IgZW50ZXJpbmcNCiAgICAgICAgIGNyaW1lPXJlcGxhY2UoY3JpbWUsIA0KICAgICAgICAgICAgICAgICAgICAgICB3aGljaChPRkZFTlNFICVpbiUgYygiMDYwIiwgIjA3MCIsICIxMzAiKSksIA0KICAgICAgICAgICAgICAgICAgICAgICAidGhlZnQiICksDQogICAgICAgICAjIyAwNjAgPSBMYXJjZW55LXRoZWZ0IChub3QgbW90b3IgdmVoaWNsZSkNCiAgICAgICAgICMjIDA3MCA9IE1vdG9yIHZlaGljbGUgdGhlZnQNCiAgICAgICAgICMjIDEzMCA9IFN0b2xlbiBwcm9wZXJ0eS1idXksIHJlY2VpdmUsIHBvc3MuDQogICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09ICIxNDAiKSwgInZhbmRhbGlzbSIgKSwNCiAgICAgICAgICMjVmFuZGFsaXNtDQogICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09IjE4MCIpLCAiZHJ1Z19zYWxlIiksDQogICAgICAgICAjI1NhbGUvbWFudWZhY3R1cmUgKHN1YnRvdGFsKSAtIGRydWdzDQogICAgICAgICBjcmltZT1yZXBsYWNlKGNyaW1lLCB3aGljaChPRkZFTlNFID09IjE4NSIpLCAiZHJ1Z19wb3NzIiksDQogICAgICAgICAjI1Bvc3Nlc3Npb24gKHN1YnRvdGFsKQ0KICAgICAgICAgY3JpbWU9cmVwbGFjZShjcmltZSwgd2hpY2goT0ZGRU5TRSA9PSIyMTAiKSwgImR1aSIpDQogICAgICAgICAjI0RyaXZpbmcgdW5kZXIgdGhlIGluZmx1ZW5jZQ0KICAgICAgICAgKSAlPiUgIyNlbGltaW5hdGluZyBkYXRhIGZvciBvdGhlciBjcmltZXMNCiAgZHBseXI6OmZpbHRlcighaXMubmEoY3JpbWUpKSAlPiUgDQogIGRwbHlyOjpiaW5kX3Jvd3ModWNyXzE1KQ0KYGBgDQoNCiMjI0ZpbmRpbmcgZGF0YSBlbnRyeSBlcnJvcnMgDQpEZWxwaGksIEluZGlhbmEgaW4gMjAxMyBtaXN0YWtlbmx5IHJlcG9ydGVkIGNyaW1lcyB3aXRoIHZhbHVlcyBvZiAxMDAwMCBhcHBlYXIgaW4gbXVsdGlwbGUgY29sdW1ucyBhbmQgZm9yIG11bHRpcGxlIHJvd3MgKGkuZS4gb2ZmZW5zZXMpIGZvciB0aGUgc2FtZSBhZ2VuY3kgYW5kIHdoaWNoIGFsc28gZXhjZWVkIHBvcHVsYXRpb24gc2l6ZS4gSW4gYWRkaXRpb24sIDIgcG9saWNlIHN0YXRpb25zIHJlcG9ydCBuZWdhdGl2ZSB2YWx1ZXMgZm9yIGFycmVzdHM6DQogICogRkxPWUQgQ09VTlRZIFBPTElDRSBERVBULCBHQSAyMDEzIHJhcGUNCiAgKiBMRUUsIEdBIDIwMTUgYXNzYXVsdA0KDQpgYGB7cn0NCnVjciR0b3RhbHMgPC0gTkENCnVjciR0b3RhbHMgPC0gYXBwbHkodWNyWyw4OjU5XSwgMSwgc3VtLCBuYS5ybT1UKQ0KDQplcnJvcl9yb3dzIDwtIGFzLm51bWVyaWMoKQ0KDQpmb3IoaSBpbiBjKDg6NTkpKXsNCiAgI290aGVyYyA8LSBzZXRkaWZmKDg6NTksIGkpICMjb3RoZXIgdmFyaWFibGVzL2NvbHVtbnMNCiAgI3VjciR0b3RhbHMgPC0gYXBwbHkodWNyWyxvdGhlcmNdLCAxLCBzdW0sIG5hLnJtPVQpDQogICMjaWYgb25lIGFycmVzdCBjb2x1bW4gZXhjZWVkcyB0aGUgc3VtIG9mIGFsbCB0aGUgb3RoZXJzIC0gaW1wb3NzaWJsZSwgdGhlcmVmb3JlIGZsYWcuDQogIGVyID0gd2hpY2godWNyWyxpXSA9PSAxMDAwMCB8IHVjclssaV0gPT0gMTAwMDEgfCB1Y3JbLGldID09IDIwMDAwKQ0KICANCiAgaWYobGVuZ3RoKGVyKT4wKXsNCiAgICBtZXNzYWdlKHBhc3RlMCgidmFyaWFibGUgPSAiLCBuYW1lcyh1Y3IpW2ldKSkNCiAgICBtZXNzYWdlKHBhc3RlKHVjciRBR0VOQ1lbZXJdLCBzZXA9IiBcbiIpKQ0KICAgIGVycm9yX3Jvd3MgPC0gdW5pcXVlKGMoZXJyb3Jfcm93cywgZXIpKQ0KICB9DQp9DQp0b3RhbF9aZXJvIDwtIHdoaWNoKHVjciR0b3RhbHMgPCAwKQ0KZXJyb3Jfcm93cyA8LSB1bmlxdWUoYyhlcnJvcl9yb3dzLCB0b3RhbF9aZXJvKSkNCnVjcl9lcnJvciA8LSB1Y3JbZXJyb3Jfcm93cyxdDQoNCmBgYA0KDQojIyNEZWxldGluZyBkYXRhIGVudHJ5IGVycm9ycw0KIERlbGV0aW5nIHRoZXNlIGNhc2VzLg0KDQpgYGB7cn0NCnVjciA8LSB1Y3JbLXdoaWNoKHVjciRBR0VOQ1k9PSJERUxQSEkiICYgdWNyJFNUQVRFPT0xMyAmIHVjciRZRUFSPT0yMDEzICksXSAjIyByZW1vdmVkIDYgY2FzZXMNCnVjciA8LSB1Y3JbLXdoaWNoKHVjciRBR0VOQ1k9PSJGTE9ZRCBDT1VOVFkgUE9MSUNFIERFUFQiICYgdWNyJFNUQVRFPT0xMCAmIHVjciRZRUFSPT0yMDEzICYgdWNyJGNyaW1lID09ICJyYXBlIiksXSAjIG9uZSBjYXNlDQp1Y3IgPC0gdWNyWy13aGljaCh1Y3IkQUdFTkNZPT0iTEVFIiAmIHVjciRTVEFURT09MTAgJiB1Y3IkWUVBUj09MjAxNSAmIHVjciRjcmltZSA9PSAiYXNzYXVsdCIpLF0gIyBvbmUgY2FzZQ0KYGBgDQoNCg0KIyMzLiBBdHRhY2ggRklQUyBjb2RlcyB0byBVQ1IgRGF0YSwgYWdncmVnYXRlIGJ5IGNvdW50eQ0KDQoxLi0tIFNvbWUgaWRlbnRpY2FsIEZJUFMgY29kZXMgaGF2ZSBzZXBhcmF0ZSBjb3VudHkgbmFtZXMgLSBlLmcuIENhbGlmb3JuaWEsIEZJUFMgY29kZSAwNjA2NSA9IGJvdGggJ1JpdmVyc2lkZScgJiAnUml2ZXJzaWRlIENvdW50eScuICBUaGVyZWZvcmUgZ3JvdXBpbmcgYnkgRklQUyByYXRoZXIgdGhhbiBieSBjb3VudHkuDQoyLi0tIFRoZXJlIGlzIGFsc28gYW4gRklQUyBjb2RpbmcgZXJyb3IgZm9yIFBoaWxhZGVscGhpYS4gIFRoZSBPUkkgY29kZSBgUEFQRVAwMGAgaXMgcmVhZCBhcyBJbmRpYW5hIENvdW50eSwgUEEsIEZJUFMgPSA0MjA2Mywgd2hpY2ggc2hvdWxkIGluc3RlYWQgYmUgNDIxMDEuIA0KDQojIyNMb2FkIEdlb2dyYXBoaWMgQ29kZXMgLSBDb3VudHkgRklQUyANCkxhdyBFbmZvcmNlbWVudCBBZ2VuY3kgSW5kZW50aWZpZXJzIENyb3Nzd2FsaywgMjAxMiAoSUNQU1IgMzUxNTgpDQpodHRwczovL3d3dy5pY3Bzci51bWljaC5lZHUvaWNwc3J3ZWIvSUNQU1Ivc3R1ZGllcy8zNTE1OA0KDQpgYGB7cn0NCiNzZXR3ZCgiY3JlYXRlRGF0YSIpDQp1Y3JfZ2VvIDwtIHJlYWRfdHN2KCJjcmVhdGVEYXRhLzM1MTU4LTAwMDEtRGF0YS50c3YiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoT1JJNywgRklQUywgQ09VTlRZTkFNRSwgU1RBVEVOQU1FICkgJT4lIA0KICBkcGx5cjo6cmVuYW1lKE9SST1PUkk3LCBjb3VudHk9Q09VTlRZTkFNRSwgU3RhdGU9U1RBVEVOQU1FKQ0KDQpgYGANCg0KIyMjQWdncmVnYXRlIGJ5IENvdW50eQ0KIA0KYGBge3J9DQp1Y3IyIDwtIGxlZnRfam9pbih1Y3IsIHVjcl9nZW8pDQp1Y3IyIDwtIHVjcjIgJT4lIGFycmFuZ2UoWUVBUiwgU3RhdGUsIGNvdW50eSwgRklQUywgT0ZGRU5TRSkgDQoNCiMjRml4IFBoaWxseS4NCnVjcjIgPC0gdWNyMiAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogIEZJUFM9cmVwbGFjZShGSVBTLCB3aGljaChPUkkgPT0gIlBBUEVQMDAiKSwgNDIxMDEpDQopICU+JSANCiAgZHBseXI6OnJlbmFtZSh5ZWFyPVlFQVIpICU+JSB1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1jKFNUQVRFLCBTVE5BTUUsIENPVU5UWSwgY291bnR5LCBBR0VOQ1ksIE9SSSwgT0ZGRU5TRSkpICU+JSANCiAgZHBseXI6OmZpbHRlcighaXMubmEoRklQUykpDQoNCnVjcjIgPC0gdWNyMiAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh5ZWFyLCBTdGF0ZSwgRklQUywgY3JpbWUpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlX2VhY2hfKGZ1bnMoc3VtKC4sIG5hLnJtID0gVFJVRSkpLA0KICAgICAgICAgICAgICAgICAgbmFtZXModWNyMilbYygyOjUzKV0pDQoNCmBgYA0KDQoNCiMjNC4gQXJyZXN0cyBieSBTZXggJiBBZ2UgYnkgQ291bnR5DQp7Tm90ZTogIEkndmUgZGVjaWRlZCB0byBrZWVwIHRoZXNlIHR3byBmaWxlcyBzZXBhcmF0ZS4gIFdoZW4gd3JpdGluZyB0byAuY3N2IGZpbGVzLCBjb21iaW5lZCB0aGV5IGFyZSBhcHByb3guIDM3S0IuICBXaGVuIGNvbWJpbmluZyB0aGVzZSBkYXRhIGZyYW1lcyB1c2luZyBkcGx5cjo6ZnVsbF9qb2luLCBmb3IgaW5zdGFuY2UsIHRoZSB0b3RhbCBmaWxlIHNpemUgZXhjZWVkcyAxR0IufQ0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCnVjcl9hZ2Vfc2V4IDwtIHVjcjIgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1jKEFXLCBKVywgQUIsIEpCLCBBQSwgSkEsIEFJLCBKSSkpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHllYXIsIFN0YXRlLCBGSVBTLCBjcmltZSkgJT4lIA0KICAjIyBDb252ZW50aW9uOiAgZmlyc3QgbGV0dGVyID0gZ2VuZGVyIChNLEYsQiksIA0KICAjI3RoZW4gYWdlIGdyb3VwLCBtYXRjaGluZyBjZW5zdXMgYWdlIGdyb3Vwcw0KICAjIyBCID0gQm90aCBHZW5kZXJzDQogICMjIEFsbCA9IGFsbCBhZ2VzDQogIGRwbHlyOjptdXRhdGVfYWxsKGFzLm51bWVyaWMpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBNQWxsPXN1bSggYyhNMF85LCBNMTBfMTIsIE0xM18xNCwgTTE1LCBNMTYsIE0xNywgTTE4LCBNMTksICAgICANCiAgICAgICAgICAgICAgICBNMjAsIE0yMSxNMjIsTTIzLE0yNCxNMjVfMjksTTMwXzM0LE0zNV8zOSxNNDBfNDQsDQogICAgICAgICAgICAgICAgTTQ1XzQ5LE01MF81NCxNNTVfNTksTTYwXzY0LE02NSksIG5hLnJtPVQpLCANCiAgICAjI0NlbnN1czogQUdFR1JQPTANCiAgICBGQWxsPXN1bSggYyggRjBfOSwgIEYxMF8xMiwgIEYxM18xNCwgIEYxNSwgIEYxNiwgIEYxNywgIEYxOCwgIEYxOSwgICAgIA0KICAgICAgICAgICAgICAgICAgIEYyMCwgIEYyMSwgRjIyLCBGMjMsIEYyNCwgRjI1XzI5LCBGMzBfMzQsIEYzNV8zOSwgRjQwXzQ0LA0KICAgICAgICAgICAgICAgICAgIEY0NV80OSwgRjUwXzU0LCBGNTVfNTksIEY2MF82NCwgRjY1KSwgbmEucm09VCksIA0KICAgICMjQ2Vuc3VzOiBBR0VHUlA9MA0KICAgIA0KICAgIEJBbGw9TUFsbCtGQWxsLA0KICAgIA0KICAgICMjTWFsZXMNCiAgICBNVW5kZXIxNT1zdW0oYyhNMF85LCBNMTBfMTIsIE0xM18xNCksIG5hLnJtPVQpLCAjI0NlbnN1czogQUdFR1JQPTEsMiwzDQogICAgTTE1XzE5PXN1bShjKCBNMTUsIE0xNiwgTTE3LCBNMTgsIE0xOSksIG5hLnJtPVQpLCAjI0NlbnN1czogQUdFR1JQPTQNCiAgICBNMjBfMjQ9c3VtKGMoTTIwLCBNMjEsTTIyLE0yMyxNMjQpLCBuYS5ybT1UKSwgIyNDZW5zdXM6IEFHRUdSUD01DQogICAgTTI1XzI5PU0yNV8yOSwgIyNDZW5zdXM6IEFHRUdSUD02DQogICAgTTMwXzM0PU0zMF8zNCwgIyNDZW5zdXM6IEFHRUdSUD03DQogICAgTTM1XzM5PU0zNV8zOSwgIyNDZW5zdXM6IEFHRUdSUD04DQogICAgTTQwXzQ0PU00MF80NCwgIyNDZW5zdXM6IEFHRUdSUD05DQogICAgTTQ1XzQ5PU00NV80OSwgIyNDZW5zdXM6IEFHRUdSUD0xMA0KICAgIE01MF81ND1NNTBfNTQsICMjQ2Vuc3VzOiBBR0VHUlA9MTENCiAgICBNNTVfNTk9TTU1XzU5LCAjI0NlbnN1czogQUdFR1JQPTEyDQogICAgTTYwQWJvdmU9c3VtKGMoTTYwXzY0LE02NSksIG5hLnJtPVQpLCAjI0NlbnN1czogQUdFR1JQPTEzLTE4DQogICAgDQogICAgRlVuZGVyMTU9c3VtKGMoRjBfOSwgRjEwXzEyLCBGMTNfMTQpLCBuYS5ybT1UKSwgIyNDZW5zdXM6IEFHRUdSUD0xLDIsMw0KICAgIEYxNV8xOT1zdW0oYyggRjE1LCBGMTYsIEYxNywgRjE4LCBGMTkpLCBuYS5ybT1UKSwgIyNDZW5zdXM6IEFHRUdSUD00DQogICAgRjIwXzI0PXN1bShjKEYyMCwgRjIxLEYyMixGMjMsRjI0KSwgbmEucm09VCksICMjQ2Vuc3VzOiBBR0VHUlA9NQ0KICAgIEYyNV8yOT1GMjVfMjksICMjQ2Vuc3VzOiBBR0VHUlA9Ng0KICAgIEYzMF8zND1GMzBfMzQsICMjQ2Vuc3VzOiBBR0VHUlA9Nw0KICAgIEYzNV8zOT1GMzVfMzksICMjQ2Vuc3VzOiBBR0VHUlA9OA0KICAgIEY0MF80ND1GNDBfNDQsICMjQ2Vuc3VzOiBBR0VHUlA9OQ0KICAgIEY0NV80OT1GNDVfNDksICMjQ2Vuc3VzOiBBR0VHUlA9MTANCiAgICBGNTBfNTQ9RjUwXzU0LCAjI0NlbnN1czogQUdFR1JQPTExDQogICAgRjU1XzU5PUY1NV81OSwgIyNDZW5zdXM6IEFHRUdSUD0xMg0KICAgIEY2MEFib3ZlPXN1bShjKEY2MF82NCxGNjUpLCBuYS5ybT1UKSwgIyNDZW5zdXM6IEFHRUdSUD0xMy0xOA0KICAgIA0KICAgIEJVbmRlcjE1PUZVbmRlcjE1K01VbmRlcjE1LCAgIyNDZW5zdXM6IEFHRUdSUD0xLDIsMw0KICAgIEIxNV8xOT1GMTVfMTkrTTE1XzE5LCAjI0NlbnN1czogQUdFR1JQPTQNCiAgICBCMjBfMjQ9RjIwXzI0K00yMF8yNCwgIyNDZW5zdXM6IEFHRUdSUD01DQogICAgQjI1XzI5PUYyNV8yOStNMjVfMjksICMjQ2Vuc3VzOiBBR0VHUlA9Ng0KICAgIEIzMF8zND1GMzBfMzQrTTMwXzM0LCAjI0NlbnN1czogQUdFR1JQPTcNCiAgICBCMzVfMzk9RjM1XzM5K00zNV8zOSwgIyNDZW5zdXM6IEFHRUdSUD04DQogICAgQjQwXzQ0PUY0MF80NCtNNDBfNDQsICMjQ2Vuc3VzOiBBR0VHUlA9OQ0KICAgIEI0NV80OT1GNDVfNDkrTTQ1XzQ5LCAjI0NlbnN1czogQUdFR1JQPTEwDQogICAgQjUwXzU0PUY1MF81NCtNNTBfNTQsICMjQ2Vuc3VzOiBBR0VHUlA9MTENCiAgICBCNTVfNTk9RjU1XzU5K0Y1NV81OSwgIyNDZW5zdXM6IEFHRUdSUD0xMg0KICAgIEI2MEFib3ZlPU02MEFib3ZlK0Y2MEFib3ZlICMjQ2Vuc3VzOiBBR0VHUlA9MTMtMTgNCiAgICApICU+JSANCiAgdGlkeXI6OmdhdGhlcigic2V4X2FnZSIsICJmcmVxIiwgNTo0MCkgJT4lIA0KICB0aWR5cjo6c2VwYXJhdGUoc2V4X2FnZSwgaW50bz1jKCJnZW5kZXIiLCAiYWdlIiksIHNlcD0xKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoZ2VuZGVyPXJlcGxhY2UoZ2VuZGVyLCB3aGljaChnZW5kZXI9PSJNIiksICJNYWxlIiksDQogICAgICAgICBnZW5kZXI9cmVwbGFjZShnZW5kZXIsIHdoaWNoKGdlbmRlcj09IkYiKSwgIkZlbWFsZSIpLA0KICAgICAgICAgZ2VuZGVyPXJlcGxhY2UoZ2VuZGVyLCB3aGljaChnZW5kZXI9PSJCIiksICJCb3RoIikNCiAgICAgICAgICkgJT4lIA0KIHRpZHlyOjpzcHJlYWQoY3JpbWUsIGZyZXEpICU+JQ0KIGRwbHlyOjptdXRhdGUoDQogI2ZvciBDb3VudGllcyB0aGF0IHJlcG9ydGVkIHRvIFVDUiBidXQgbm90IHNwZWNpZmljIGNyaW1lcyBzdWNoIGFzIG11cmRlciwNCiAjdHJlYXRpbmcgdGhlc2UgYXMgemVyb3MgZm9yIGFnZ3JlZ2F0aW5nIFZpb2xlbnQgQ3JpbWUgUmF0ZXMNCiBtdXJkZXI9cmVwbGFjZShtdXJkZXIsIHdoaWNoKGlzLm5hKG11cmRlcikpLCAwKSwNCiByYXBlPXJlcGxhY2UocmFwZSwgd2hpY2goaXMubmEocmFwZSkpLCAwKSwNCiByb2JiZXJ5PXJlcGxhY2Uocm9iYmVyeSwgd2hpY2goaXMubmEocm9iYmVyeSkpLCAwKSwNCiBhc3NhdWx0PXJlcGxhY2UoYXNzYXVsdCwgd2hpY2goaXMubmEoYXNzYXVsdCkpLCAwKSwNCiBWaW9sZW50Q3JpbWUgPSBtdXJkZXIrcmFwZStyb2JiZXJ5K2Fzc2F1bHQpICU+JQ0KICBhcnJhbmdlKHllYXIsIFN0YXRlLCBGSVBTLCBnZW5kZXIsIGFnZSkNCg0KYGBgDQoNCg0KIyM1LiBBcnJlc3RzIGJ5IFJhY2UgYnkgQ291bnR5DQpgYGB7cn0NCiMjVUNSIFJhY2UNCnVjcl9yYWNlIDwtIHVjcjIgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoeWVhciwgU3RhdGUsIEZJUFMsIGNyaW1lKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoeWVhciwgU3RhdGUsIEZJUFMsIA0KICAgICAgICBjcmltZSwgSlcsIEpCLCBKSSwgSkEsIEFXLCBBQiwgQUksIEFBKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgV2hpdGU9IEFXICsgSlcsDQogICAgQmxhY2s9QUIgKyBKQiwNCiAgICBBc2lhbj1BQSArIEpBLA0KICAgIEFtZXJpbmRpYW49IEFJICsgSkkpICU+JSANCmRwbHlyOjpzZWxlY3QoLWMoQVcsIEpXLCBBQiwgSkIsIEFBLCBKQSwgQUksIEpJKSkgJT4lIA0KdGlkeXI6OmdhdGhlcigiUmFjZSIsICJmcmVxIiwgNTo4KSAlPiUgDQp0aWR5cjo6c3ByZWFkKGNyaW1lLCBmcmVxKSAlPiUNCmRwbHlyOjptdXRhdGUoDQogICBSYWNlPXJlcGxhY2UoUmFjZSwgd2hpY2goUmFjZT09IkFtZXJpbmRpYW4iKSwgIk5hdGl2ZSBBbWVyaWNhbiIpLA0KICAgbXVyZGVyPXJlcGxhY2UobXVyZGVyLCB3aGljaChpcy5uYShtdXJkZXIpKSwgMCksDQogICByYXBlPXJlcGxhY2UocmFwZSwgd2hpY2goaXMubmEocmFwZSkpLCAwKSwNCiAgIHJvYmJlcnk9cmVwbGFjZShyb2JiZXJ5LCB3aGljaChpcy5uYShyb2JiZXJ5KSksIDApLA0KICAgYXNzYXVsdD1yZXBsYWNlKGFzc2F1bHQsIHdoaWNoKGlzLm5hKGFzc2F1bHQpKSwgMCksDQogICBWaW9sZW50Q3JpbWUgPSBtdXJkZXIrcmFwZStyb2JiZXJ5K2Fzc2F1bHQpICU+JQ0KZHBseXI6Omdyb3VwX2J5KHllYXIsIFN0YXRlLCBGSVBTLCBSYWNlKSAlPiUgDQpkcGx5cjo6bXV0YXRlKA0KICAgIGRydWdzID0gc3VtKGMoZHJ1Z19wb3NzLCBkcnVnX3NhbGUpLCBuYS5ybT1UKQ0KICApICU+JSANCmRwbHlyOjpzZWxlY3QoLWRydWdfc2FsZSwgLWRydWdfcG9zcykgJT4lIA0KICBkcGx5cjo6YXJyYW5nZSh5ZWFyLCBTdGF0ZSwgRklQUywgUmFjZSkNCmBgYA0KDQoNCiMjNi4gRkxPUklEQSANCkZsb3JpZGEgYXJyZXN0IGRhdGEgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgVUNSLiAgSGVyZSBJIGluY2x1ZGUgRmxvcmlkYSBhcnJlc3QgZGF0YSwgdGFrZW4gZnJvbSB0aGUgZXhjZWwgZmlsZSAiQXJyZXN0cyBieSBDb3VudHksIEFnZSwgU2V4IGFuZCBPZmZlbnNlIGZvciBGbG9yaWRhLCAyMDA0IC0gMjAxNSIgYXZhaWxhYmxlIG9uIHRoZSBGbG9yaWRhIERlcGFydG1lbnQgb2YgTGF3IEVuZm9yY2VtZW50IHdlYnNpdGU6IA0KaHR0cDovL3d3dy5mZGxlLnN0YXRlLmZsLnVzL2Ntcy9GU0FDL0RhdGEtU3RhdGlzdGljcy9VQ1ItQXJyZXN0LURhdGEuYXNweA0KDQpOb3RlIHRoYXQgdGhlIEZsb3JpZGEgb2ZmZW5zZSBjb2RlcyBkb24ndCBleGFjdGx5IG1hdGNoIHRoZSBVQ1IuICBUaGUgVUNSIG11cmRlciBjb2RlIGlzIGZvciAiTXVyZGVyIGFuZCBub24tbmVnbGlnZW50IG1hbnNsYXVnaHRlciIsIHdoZXJlYXMgdGhlIEZsb3JpZGEgcmVjb3JkcyBhcmUgc2VwYXJhdGUgZm9yIG11cmRlciBhbmQgZm9yIG1hbnNsYXVnaHRlci4gIFRoZSBVQ1IgYWxzbyBkaXN0aW5ndWlzaGVzIGJldHdlZW4gIk1hbnNsYXVnaHRlciBieSBuZWdsaWdlbmNlIiBhbmQgIk11cmRlciBhbmQgbm9uLW5lZ2xpZ2VudCBtYW5zbGF1Z2h0ZXIiLCB3aGVyZWFzIEZsb3JpZGEgcmVjb3JkcyBvbmx5IGluZGljYXRlIG9uZSBjYXRlZ29yeSBmb3IgbWFuc2xhdWdodGVyLiAgDQoNCkZsb3JpZGEgYWxzbyBkb2VzIG5vdCByZXBvcnQgc2VwYXJhdGUgY2F0ZWdvcmllcyBmb3IgZHJ1ZyBzYWxlcyBhbmQgZHJ1ZyBwb3NzZXNzaW9uIGFycmVzdHMuICBJIHRoZXJlZm9yZSBjb25mbGF0ZSB0aGUgY2F0ZWdvcmllcyBpbiB0aGUgcmVzdCBvZiB0aGUgVUNSLg0KDQpgYGB7cn0NCiMjQWRkaW5nIEZJUFMgY29kZXMgdG8gRmxvcmlkYQ0KI3NldHdkKCJjcmVhdGVEYXRhIikNCnJlcXVpcmUobm9uY2Vuc3VzKQ0KICBkYXRhKGNvdW50aWVzKQ0KICBjb3VudGllcyA8LSBzYXBwbHkoY291bnRpZXMsIGFzLmNoYXJhY3RlcikgJT4lIHRpYmJsZTo6YXNfZGF0YV9mcmFtZSgpDQogIGNvdW50aWVzJEZJUFMgPC0gcGFzdGUwKCJgIiwgYXMuY2hhcmFjdGVyKGNvdW50aWVzJHN0YXRlX2ZpcHMpLCBhcy5jaGFyYWN0ZXIoY291bnRpZXMkY291bnR5X2ZpcHMpKQ0KICBjbnR5X2RmIDwtIGNvdW50aWVzW3doaWNoKGNvdW50aWVzJHN0YXRlPT0iRkwiKSxjKCJjb3VudHlfbmFtZSIsICJzdGF0ZSIsICJGSVBTIildDQogIG5hbWVzKGNudHlfZGYpIDwtIGMoImNvdW50eSIsICJzdGF0ZSIsICJGSVBTIikNCiAgY250eV9kZiRjb3VudHkgIDwtIHRvbG93ZXIodHJpbXdzKGdzdWIoIltbOnB1bmN0Ol1dIiwgIiIsIGNudHlfZGYkY291bnR5KSkpDQogIGNudHlfZGYkY291bnR5IDwtIGdzdWIoIiBjb3VudHl8IHBhcmlzaHwgYm9yb3VnaCIsICIiLCBjbnR5X2RmJGNvdW50eSwgZml4ZWQgPSBGQUxTRSkNCg0KZmxvcmlkYSA8LSByZWFkcjo6cmVhZF9jc3YoImNyZWF0ZURhdGEvZmxvcmlkYUFycmVzdF8yMDExXzIwMTUuY3N2IikgJT4lIA0KICB0aWR5cjo6Z2F0aGVyKFJhY2UsIGZyZXEsIDY6OSkgJT4lIA0KICB0aWR5cjo6c3ByZWFkKGNyaW1lLCBmcmVxKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgbXVyZGVyID0gbXVyZGVyX2EgKyBtYW5zbGF1Z2h0ZXIsDQogICAgdGhlZnQgPSBidXlfcmVjZWl2ZV9wb3NzZXNzX3N0b2xlbl9wcm9wZXJ0eSArIGxhcmNlbnkgKyBtb3Rvcl92ZWhpY2xlX3RoZWZ0LA0KICAgIFZpb2xlbnRDcmltZSA9IG11cmRlcityYXBlK3JvYmJlcnkrYXNzYXVsdCwNCiAgICBjb3VudHkgPSB0b2xvd2VyKHRyaW13cyhnc3ViKCJbWzpwdW5jdDpdXSIsICIiLCBjb3VudHkpKSkNCiAgKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLW11cmRlcl9hLCAtbWFuc2xhdWdodGVyLCAtYnV5X3JlY2VpdmVfcG9zc2Vzc19zdG9sZW5fcHJvcGVydHksIC1sYXJjZW55LCAtbW90b3JfdmVoaWNsZV90aGVmdCkgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKGNudHlfZGYpDQoNCg0KdW5pcXVlKGZsb3JpZGEkY291bnR5W3doaWNoKGlzLm5hKGZsb3JpZGEkRklQUykpXSkNCg0KYGBgDQoNCiMjI0ZpeGluZyBtaXNzaW5nIGNvdW50aWVzDQpPc2Vjb2xhIGNvdW50eSB3YXMgbm90IHJlY29nbml6ZWQuIEVudGVyaW5nIGl0IG1hbnVhbGx5Lg0KDQpgYGB7cn0NCg0KZmxvcmlkYSA8LSBmbG9yaWRhICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBGSVBTPXJlcGxhY2UoRklQUywgd2hpY2goY291bnR5PT0ib3NlY29sYSIpLCAiYDEyMDk3IikNCiAgKQ0KDQp1bmlxdWUoZmxvcmlkYSRjb3VudHlbd2hpY2goaXMubmEoZmxvcmlkYSRGSVBTKSldKQ0KDQpgYGANCg0KIyMjQWRkaW5nIEZsb3JpZGEgdG8gdGhlIFVDUl9SYWNlIGRhdGFzZXQuDQpgYGB7cn0NCg0KdVZhcnMgPC0gbmFtZXModWNyX3JhY2UpDQpmbG9yaWRhIDwtIGZsb3JpZGFbLHdoaWNoKG5hbWVzKGZsb3JpZGEpICVpbiUgdVZhcnMpXQ0KDQp1Y3JfcmFjZSA8LSB1Y3JfcmFjZSAlPiUgDQogIGRwbHlyOjpiaW5kX3Jvd3MoZmxvcmlkYSkNCg0KYGBgDQoNCg0KIyM3LiBOWUMgQXJyZXN0IERhdGENClRoZSBVQ1IgRGF0YSBvbmx5IGNvbnRhaW5zIGluZm9ybWF0aW9uIGZvciBNYW5oYXR0YW4sIE5ZIC0gRklQUyBjb2RlIDM2MDYxLiAgTWFuaGF0dGFuIGlzIGFsc28gY2FsbGVkICdOZXcgWW9yayBDb3VudHkuJyAgSXQgZG9lcyBub3QgaW5jbHVkZSBkYXRhIGZyb206ICBLaW5ncyBDb3VudHkgKEJyb29rbHluLCAzNjA0NyksIFF1ZWVucyAoMzYwODEpLCBUaGUgQnJvbnggKDM2MDA1KSwgU3RhdGVuIElzbGFuZCAoMzYwODUpDQoNClRoZSBPUkkgY29kZXMgZm9yIHdoaWNoIGFycmVzdCBkYXRhIGFyZSByZXBvcnRlZCBpbiB0aGUgVUNSIGZvciBGSVBTIDM2MDYxIGluY2x1ZGVzOg0KLSBOWTAzMDgzIChOWUMgTUVUUk8gVFJOU1BSVE4gQVVUSCkNCi0gTlkzMzBTUyAoU1A6IE5FVyBZT1JLIENPVU5UWSkNCi0gTlkwMzAzMSAoU1QgUFJLOiBORVcgWU9SSyBDSVRZIFJFKQ0KDQpGdXJ0aGVyLCB0aGUgb25seSBPUkk3IGNvZGUgbGlzdGVkIGluIHRoZSBVQ1IgZmlsZXMgYXMgR3JvdXAgIjFBIiwgaW5kaWNhdGluZyBhIGNpdHkgbGFyZ2VyIHRoYW4gMSBNaWxsaW9uLCBpcyBOWTAzMDMwLCAoaW4gdGhlIENyb3NzV2FsayBpZGVudGlmaWVkIGFzICJORVcgWU9SSyBDSVRZIFBPTElDRSBERVBBUlRNRU5UIiksIHdoaWNoIGNvbnRhaW5zIG9ubHkgbWlzc2luZyB2YWx1ZXMsIGkuZS4gbm8gYXJyZXN0cyBhcmUgcmVwb3J0ZWQuICBSaWdodCBub3csIFpFUk8gbXVyZGVycyBhcmUgcmVwb3J0ZWQgZm9yIE5ZQyBmb3IgZXhhbXBsZSwgZnJvbSAyMDEzLTIwMTUuICBUaGUgTGF3IEVuZm9yY2VtZW50IE1hbmFnZW1lbnQgYW5kIEFkbWluaXN0cmF0aXZlIFN0YXRpc3RpY3MgKExFTUFTKSBkYXRhIGFsc28gcmVwb3J0cyBwb2xpY2Ugb2ZmaWNlcnMgZm9yIE9SSTcgZGlzdHJpY3QgTlkwMzAzMC4gIA0KDQpUbyByZXNvbHZlIHRoZXNlIHByb2JsZW1zIEkgYWdncmVnYXRlIE5ZQyBpbnRvIG9uZSBjb3VudHkgYWNyb3NzIGFsbCBkYXRhc2V0cyB1c2luZyBjb3VudHkgY29kZSAzNjA2MSAoTWFuaGF0dGFuIG9yIE5ldyBZb3JrIENvdW50eSkuICBCZWNhdXNlIGFycmVzdCBkYXRhIGFyZSBpbmNvbXBsZXRlIGZyb20gdGhlIFVDUiwgSSB1c2UgdGhlIE5ldyBZb3JrIENpdHkgUG9saWNlIERlcGFydG1lbnQncyAiQ3JpbWUgYW5kIEVuZm9yY2VtZW50IEFjdGl2aXR5IGluIE5ldyBZb3JrIENpdHkiIHJlcG9ydCwgYXZhaWxhYmxlIGZyb206DQpodHRwOi8vd3d3Lm55Yy5nb3YvaHRtbC9ueXBkL2h0bWwvYW5hbHlzaXNfYW5kX3BsYW5uaW5nL2NyaW1lX2FuZF9lbmZvcmNlbWVudF9hY3Rpdml0eS5zaHRtbA0KDQpTcGVjaWZpY2FsbHksIEkgdXNlIHRoZSBmaWxlICJFbmZvcmNlbWVudCBSZXBvcnQgRGF0YSBUYWJsZXMgMjAwOC0yMDE1IiwgDQpodHRwOi8vd3d3Lm55Yy5nb3YvaHRtbC9ueXBkL2Rvd25sb2Fkcy96aXAvYW5hbHlzaXNfYW5kX3BsYW5uaW5nL2NyaW1lX2FuZF9lbmZvcmNlbWVudF9yZXBvcnRfZGF0YV90YWJsZXNfMjAwOC0yMDE1XzIwMTYtMDIuemlwDQoNClVubGlrZSB0aGUgVUNSIERhdGEsIHRoZSBOWUMgYXJyZXN0IGRhdGEgZGlzdGluZ3Vpc2hlcyBIaXNwYW5pY3MgYW5kIE5vbi1IaXNwYW5pYyBXaGl0ZXMuICBUbyBtYWtlIHRoaXMgZGF0YSBjb25zaXN0ZW50IHdpdGggdGhlIFVDUiBkYXRhLCBJIGNvbGxhcHNlIEhpc3BhbmljIGFuZCBXaGl0ZSBpbnRvIGEgc2luZ2xlICdXaGl0ZScgcmFjaWFsIGNhdGVnb3J5Lg0KDQpgYGB7cn0NCiNzZXR3ZCgiY3JlYXRlRGF0YSIpDQpueWMgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvbnljQXJyZXN0cy5jc3YiKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoeWVhcjwyMDE1KSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgUmFjZT1yZXBsYWNlKFJhY2UsIHdoaWNoKFJhY2U9PSJIaXNwYW5pYyIpLCAiV2hpdGUiKSwNCiAgICBGSVBTPSIzNjA2MSIsDQogICAgU3RhdGU9Ik5FVyBZT1JLIg0KICApICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHllYXIsIFN0YXRlLCBGSVBTLCBSYWNlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYWxsKHN1bSwgbmEucm09VCkNCg0KDQpueUZpcHMgPC0gYygiMzYwNjEiLCAiMzYwNDciLCAiMzYwODEiLCAiMzYwMDUiLCAiMzYwODUiKQ0KDQp1Y3JfcmFjZSA8LSB1Y3JfcmFjZSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoIShGSVBTICVpbiUgbnlGaXBzKSkgJT4lIA0KICBkcGx5cjo6YmluZF9yb3dzKG55YykNCg0KDQpgYGANCg0KDQojIzguICBDcmVhdGUgUmFjZSBDcmltZSBSYXRlIFZhcmlhYmxlcw0KIyMjQXR0YWNoIGNvdW50eS1sZXZlbCBDZW5zdXMgUG9wdWxhdGlvbiBEYXRhDQpgYGB7cn0NCiMgaWYoZXhpc3RzKCJjZW5zdXNfY291bnR5Iik9PUZBTFNFKXsNCiMgICBjZW5zdXNfY291bnR5IDwtIGZzdDo6cmVhZC5mc3QoImNyZWF0ZURhdGEvY2Vuc3VzX2NvdW50eS5jc3YiKQ0KIyB9DQoNCmNlbnN1c19yYWNlIDwtIGNlbnN1c19jb3VudHkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JSANCiAgZHBseXI6OmZpbHRlcihnZW5kZXIgPT0gIkJvdGgiLCBhZ2UgPT0gIkFsbCIpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtZ2VuZGVyLCAtYWdlLCAtc3RhdGUsIC1jb3VudHkpDQoNCnVjcl9yYWNlMiA8LSB1Y3JfcmFjZSANCg0KIyNGaXhpbmcgZmlwcyB0aGF0IGJlZ2luIHdpdGggMA0KZm9yKGkgaW4gMTpucm93KHVjcl9yYWNlMikpew0KICBpZihuY2hhcih1Y3JfcmFjZTIkRklQU1tpXSk9PTQpew0KICAgIHVjcl9yYWNlMiRGSVBTW2ldIDwtIHBhc3RlMCgiYDAiLCBhcy5jaGFyYWN0ZXIodWNyX3JhY2UyJEZJUFNbaV0pKQ0KICB9IGVsc2Ugew0KICBpZihuY2hhcih1Y3JfcmFjZTIkRklQU1tpXSk9PTUpew0KICAgICAgdWNyX3JhY2UyJEZJUFNbaV0gPC0gcGFzdGUwKCJgIiwgYXMuY2hhcmFjdGVyKHVjcl9yYWNlMiRGSVBTW2ldKSkNCiAgICB9IA0KICB9DQp9DQogIA0KdWNyX3JhY2UyIDwtIHVjcl9yYWNlMiAlPiUgZHBseXI6OmxlZnRfam9pbihjZW5zdXNfcmFjZSkNCmBgYA0KDQojIyNDcmVhdGluZyBDcmltZSBSYXRlIFZhcmlhYmxlcyBieSBSYWNlDQoNCmBgYHtyfQ0KDQpjcmltZVZhcnMgPC0gYygibXVyZGVyIiwgInZjIiwgImR1aSIsICJ2YW5kYWwiLCAidGhlZnQiLCAiZHJ1Z3MiKQ0KI2Zsb3JpZGFfZmlwcyA8LSB1bmlxdWUodWNyX3JhY2UyJEZJUFNbd2hpY2godWNyX3JhY2UyJFN0YXRlPT0iRkxPUklEQSIpXSkNCg0KVUNSRGF0YSA8LSAgdWNyX3JhY2UyICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KHllYXIsIEZJUFMpICU+JSANCiAgICAjbXV0YXRlKFN0YXRlPXN0YXRlRnJvbUxvd2VyKHRvbG93ZXIoU3RhdGUpLCByZXY9VCkpICU+JSANCiAgICAjI3NlbGVjdGluZywgY2hhbmdpbmcgbmFtZXMsIGRyb3BwaW5nIGFsbCBvdGhlciB2YXJzDQogICAgZHBseXI6OnRyYW5zbXV0ZSgNCiAgICAgIFJhY2U9UmFjZSwgDQogICAgICBtdXJkZXI9bXVyZGVyLCANCiAgICAgIHZjPVZpb2xlbnRDcmltZSwgDQogICAgICBkdWk9ZHVpLCANCiAgICAgIHZhbmRhbD12YW5kYWxpc20sIA0KICAgICAgdGhlZnQ9dGhlZnQsIA0KICAgICAgZHJ1Z3M9ZHJ1Z3MsDQogICAgICAjZHJ1Z19wb3NzPWRydWdfcG9zcywgDQogICAgICAjZHJ1Z19zYWxlPWRydWdfc2FsZSwgDQogICAgICBwb3BVQ1IuYz1wb3B1bGF0aW9uKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieSh5ZWFyLCBGSVBTKSAlPiUgDQogIG11dGF0ZV9hdChjcmltZVZhcnMsIGZ1bnMocmVwbGFjZSguLCBpcy5uYSguKSwgMCkpKSAlPiUgIyNDb252ZXJ0aW5nIG1pc3NpbmcgdG8gemVyb3MgZm9yIGNvdW50aWVzIHJlcG9ydGluZyB0byBVQ1INCiAgIyNGcmVxdWVuY2llcw0KICBtdXRhdGVfYXQoY3JpbWVWYXJzLCBmdW5zKCJ3aGl0ZSIgPSAuW3doaWNoKFJhY2U9PSJXaGl0ZSIpXSkpICU+JSANCiAgbXV0YXRlX2F0KGNyaW1lVmFycywgZnVucygiYmxhY2siID0gLlt3aGljaChSYWNlPT0iQmxhY2siKV0pKSAlPiUgDQogIG11dGF0ZV9hdChjcmltZVZhcnMsIGZ1bnMoImFzaWFuIiA9IC5bd2hpY2goUmFjZT09IkFzaWFuIildKSkgJT4lIA0KICBtdXRhdGVfYXQoY3JpbWVWYXJzLCBmdW5zKCJhbWVyaW5kaWFuIiA9IC5bd2hpY2goUmFjZT09Ik5hdGl2ZSBBbWVyaWNhbiIpXSkpICU+JSANCiAgIyNSYXRlcyANCiAgbXV0YXRlX2F0KGNyaW1lVmFycywgZnVucygid2hpdGVfciIgPSAuW3doaWNoKFJhY2U9PSJXaGl0ZSIpXSAvIHBvcFVDUi5jW3doaWNoKFJhY2U9PSJXaGl0ZSIpXSkpICU+JSANCiAgbXV0YXRlX2F0KGNyaW1lVmFycywgZnVucygiYmxhY2tfciIgPSAuW3doaWNoKFJhY2U9PSJCbGFjayIpXSAvIHBvcFVDUi5jW3doaWNoKFJhY2U9PSJCbGFjayIpXSkpICU+JSANCiAgbXV0YXRlX2F0KGNyaW1lVmFycywgZnVucygiYXNpYW5fciIgPSAuW3doaWNoKFJhY2U9PSJBc2lhbiIpXSAvIHBvcFVDUi5jW3doaWNoKFJhY2U9PSJBc2lhbiIpXSkpICU+JSANCiAgbXV0YXRlX2F0KGNyaW1lVmFycywgZnVucygiYW1lcmluZGlhbl9yIiA9IC5bd2hpY2goUmFjZT09Ik5hdGl2ZSBBbWVyaWNhbiIpXSAvIHBvcFVDUi5jW3doaWNoKFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKV0pKSAlPiUgDQogIA0KICAjI05vdyBjb252ZXJ0IG9yaWdpbmFsIGNyaW1lIHZhcnMgdG8gIlRvdGFsIiAtIGFsbCByYWNlcy4gV2lsbCBub3QgYmUgbGFiZWxsZWQNCiAgbXV0YXRlX2F0KGNyaW1lVmFycywgZnVucyhzdW0oYXMubnVtZXJpYyguKSwgbmEucm09VCkpKSAlPiUgDQogIG11dGF0ZV9hdChjcmltZVZhcnMsIGZ1bnMoInIiID0gc3VtKGFzLm51bWVyaWMoLiksIG5hLnJtPVQpIC8gc3VtKGFzLm51bWVyaWMocG9wVUNSLmMpLCBuYS5ybT1UKSkpICU+JSAjI1RvdGFsIA0KICMjY3JlYXRlIGF2ZXJhZ2Ugb3ZlciB5ZWFycw0KZHBseXI6Omdyb3VwX2J5KEZJUFMpICU+JSANCiAgIyNBdmVyYWdlZCBhcm9zcyAyMDExLTIwMTUgIA0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVucygiNXlyIiA9IG1lYW4oLiwgbmEucm09VCkpKSAlPiUNCiAgZHBseXI6OmZpbHRlcih5ZWFyPT0yMDE1LCBSYWNlPT0iV2hpdGUiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLXllYXIsIC1SYWNlKSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5zKHJlcGxhY2UoLiwgaXMubmFuKC4pLCBOQSkpKSAlPiUgDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5zKHJlcGxhY2UoLiwgaXMuaW5maW5pdGUoLiksIE5BKSkpIA0KDQoNCiMjU2F2ZSBGaWxlLCBzbyB0aGlzIGNvZGUgaW4gYWJvdmUgY2h1bmtzIGNhbiBiZSBza2lwcGVkLg0KIyNyZWFkcjo6d3JpdGVfY3N2KFVDUkRhdGEsIHBhdGg9ImNyZWF0ZURhdGEvVUNSRGF0YS5jc3YiKQ0KZnN0Ojp3cml0ZS5mc3QoVUNSRGF0YSwgcGF0aD0iY3JlYXRlRGF0YS9VQ1JEYXRhLmNzdiIpICAgDQogIA0KYGBgDQoNCg0KDQoNCiNJVi4gIFNFREEgVmFyaWFibGVzIC0gRUxBLCBNYXRoLCBTZWdyZWdhdGlvbiwgR2luaSwgU0VTIGNvbXBvc2l0ZQ0KDQpgU2VhbiBGLiBSZWFyZG9uLCBEZW1ldHJhIEthbG9ncmlkZXMsIEFuZHJldyBIbywgQmVuIFNoZWFyLCBLZW5uZXRoIFNob3JlcywgRXJpbiBGYWhsZS4gKDIwMTYpLmAgDQpgICBTdGFuZm9yZCBFZHVjYXRpb24gRGF0YSBBcmNoaXZlIChWZXJzaW9uIDEuMSBGaWxlIFRpdGxlKS5gDQpodHRwOi8vcHVybC5zdGFuZm9yZC5lZHUvZGI1ODZuczQ5NzQuDQoNCkZpbGUgLSBgZGlzdHJpY3QgY292YXJpYXRlcyBieSB5ZWFyIGFuZCBncmFkZSAobG9uZyBmaWxlKS5jc3ZgDQoNCg0KIyMxLiBMb2FkIFNFUyBhbmQgRnJlcXVlbmN5IG9mIFN0dWRlbnRzIFZhcmlhYmxlcyAtIEF2ZXJhZ2luZyBhY3Jvc3MgeWVhcnMgDQoNCkNvbnZlcnRlZCBmaWxlcyB0byBmc3QgZm9ybWF0IGZvciBmYXN0ZXIgbG9hZGluZy4NCg0KYHRvdGVucmxgID0gTnVtYmVyIG9mIFN0dWRlbnRzIGluIEdyYWRlDQoNCmBuc2NoYCA9CU51bWJlciBvZiBTY2hvb2xzIGluIHRoZSBEaXN0cmljdA0KDQoNCk5ZQyBzY2hvb2xzIGFyZSBhbHJlYWR5IGFnZ3JlZ2F0ZWQsIGJ1dCBubyBjb3VudHkgRklQUyBjb2RlcyBhcmUgcHJvdmlkZWQuICBUaGlzIGhhcyB0byBiZSBkb25lIG1hbnVhbGx5IHRvIGF2b2lkIGxvc2luZyBhbGwgTllDIGNhc2VzLg0KIC4qIGxlYWlkID0gIjM2MjA1ODAiDQogLiogbGVhbmFtZSA9ICJORVcgWU9SSyBDSVRZIFBVQkxJQyBTQ0hPT0xTIg0KDQpOb3RlcyBvbiB2YXJpYWJsZXM6DQouKiAgc2VzX2FsbDogICJjb21wdXRlZCBhcyB0aGUgZmlyc3QgcHJpbmNpcGFsIGNvbXBvbmVudCBmYWN0b3Igc2NvcmUgb2YgdGhlIGZvbGxvd2luZyBtZWFzdXJlczogbWVkaWFuIGluY29tZSwgcGVyY2VudCB3aXRoIGEgYmFjaGVsb3IncyBkZWdyZWUgb3IgaGlnaGVyLCBwb3ZlcnR5IHJhdGUsIFNOQVAgcmF0ZSwgc2luZ2xlIG1vdGhlciBoZWFkZWQgaG91c2Vob2xkIHJhdGUsIGFuZCB1bmVtcGxveW1lbnQgcmF0ZSI7IGRvZXMgbm90IHZhcnkgYnkgZ3JhZGUgb3IgeWVhcjsgb3JpZ2luYWwgZGF0YSBzb3VyY2UgaXMgQUNTLg0KDQouKiAgInRoZWlsX3doaXRlQmxhY2siIGlzIGxhYmVsbGVkICJoc3dodGJsayIgaW4gdGhlIFNFREEgZGF0YXNldDogICBJbmZvcm1hdGlvbiBpbmRleCBiZXR3ZWVuIHNjaG9vbHM6IFdoaXRlL0JsYWNrLiAgICJ0aGUgaW5mb3JtYXRpb24gdGhlb3J5IGluZGV4IGlzIGNvbXB1dGVkIGFzIHRoZSBhdmVyYWdlIGRldmlhdGlvbiBvZiBlYWNoIHN0dWRlbnQncyBzY2hvb2wgcmFjaWFsIGRpdmVyc2l0eSBmcm9tIHRoZSBkaXN0cmljdC13aWRlIHJhY2lhbCBkaXZlcnNpdHkuIFZhbHVlcyBvZiAwIGluZGljYXRlIG5vIHNlZ3JlZ2F0aW9uIHdoaWxlIHZhbHVlcyBvZiAxIGluZGljYXRlIGNvbXBsZXRlIHNlZ3JlZ2F0aW9uLiBTZWUgVGhlaWwgKDE5NzIpIGZvciBtb3JlIGluZm9ybWFpdG9uIg0KDQouKiAgZ2luaV9hbGwgImNvbXB1dGVkIHVzaW5nIGNvdW50cyBvZiBwZW9wbGUgaW4gZWFjaCBvZiAxNiBpbmNvbWUgY2F0ZWdvcmllczsgdXNpbmcgdGhlIHJwbWUgLS0gUm9idXN0IFBhcmV0byBtaWRwb2ludCBlc3RpbWF0b3ItLSBpbXBsZW1lbnRlZCBpbiBTdGF0YSBieSB2b24gSGlwcGVsIGFuZCBQb3dlcnMiDQoNCmBgYHtyfQ0KDQojIyAgImRpc3RyaWN0IGNvdmFyaWF0ZXMgYnkgeWVhciBhbmQgZ3JhZGUgKGxvbmcgZmlsZSkuY3N2Ig0KI3NlZGFfc2VzIDwtIHJlYWRyOjpyZWFkX2NzdihjaG9vc2UuZmlsZXMoKSkNCnNlZGFfc2VzIDwtIGZzdDo6cmVhZC5mc3QoImNyZWF0ZURhdGEvc2VkYV9zZXNfZnN0LmNzdiIpIA0KDQpzZWRhX3Nlc19jb3ZhcnMgPC0gc2VkYV9zZXMgJT4lDQpkcGx5cjo6bXV0YXRlKGNvdW50eWlkID0gcmVwbGFjZShjb3VudHlpZCwgd2hpY2gobGVhbmFtZSA9PSAiTkVXIFlPUksgQ0lUWSBQVUJMSUMgU0NIT09MUyIgfCBsZWFpZCA9PSAiMzYyMDU4MCIpLCAiMzYwNjEiKSkgJT4lIA0KZHBseXI6Omdyb3VwX2J5KGxlYWlkKSAgJT4lIA0KZHBseXI6OnN1bW1hcmlzZSgNCiAgRklQUyA9IGZpcnN0KGNvdW50eWlkKSwNCg0KICAjI2FsbCBzdHVkZW50cywgYWNyb3NzIGFsbCBncmFkZXMgLSB1c2VkIGZvciB3ZWlnaHRlZCBhdmVyYWdpbmcgc2VzIHZhcnMNCiAgdG90YWxTdHVkZW50c193aGl0ZSA9IHN1bSh3aHQsIG5hLnJtPVQpLA0KICB0b3RhbFN0dWRlbnRzX2JsYWNrID0gc3VtKGJsaywgbmEucm09VCksDQogIHRvdGFsU3R1ZGVudHNfYXNpYW4gPSBzdW0oYXNuLCBuYS5ybT1UKSwNCiAgdG90YWxTdHVkZW50c19oaXNwID0gc3VtKGhzcCwgbmEucm09VCksDQogIHRvdGFsU3R1ZGVudHNfYW1lciA9IHN1bShpbmQsIG5hLnJtPVQpLA0KICB0b3RhbFN0dWRlbnRzX2FsbCA9IHN1bSh0b3RlbnJsLCBuYS5ybT1UKSwNCiAgc2VkYV82dGhHcmFkZXJzX3RvdGFsID0gc3VtKHRvdGVucmxbd2hpY2goZ3JhZGUgPT0gNildLCBuYS5ybT1UKSwNCiAgc2VkYV83dGhHcmFkZXJzX3RvdGFsID0gc3VtKHRvdGVucmxbd2hpY2goZ3JhZGUgPT0gNyldLCBuYS5ybT1UKSwNCiAgc2VkYV84dGhHcmFkZXJzX3RvdGFsID0gc3VtKHRvdGVucmxbd2hpY2goZ3JhZGUgPT0gOCldLCBuYS5ybT1UKSwNCiAgDQogIHNlc19hbGwgPSB3ZWlnaHRlZC5tZWFuKHNlc2FsbFt3aGljaCghaXMubmEodG90YWxTdHVkZW50c19hbGwpKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB3PXRvdGFsU3R1ZGVudHNfYWxsW3doaWNoKCFpcy5uYSh0b3RhbFN0dWRlbnRzX2FsbCkpXSwgbmEucm09VCksDQogIHRoZWlsX3doaXRlQmxhY2sgPSB3ZWlnaHRlZC5tZWFuKGhzd2h0YmxrW3doaWNoKCFpcy5uYSh0b3RhbFN0dWRlbnRzX2FsbCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHc9dG90YWxTdHVkZW50c19hbGxbd2hpY2goIWlzLm5hKHRvdGFsU3R1ZGVudHNfYWxsKSldLCBuYS5ybT1UKSwNCiAgZ2luaV9hbGwgPSB3ZWlnaHRlZC5tZWFuKGdpbmlhbGxbd2hpY2goIWlzLm5hKHRvdGFsU3R1ZGVudHNfYWxsKSldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHc9dG90YWxTdHVkZW50c19hbGxbd2hpY2goIWlzLm5hKHRvdGFsU3R1ZGVudHNfYWxsKSldLCBuYS5ybT1UKQ0KICApICU+JSANCiAgZHBseXI6Om11dGF0ZV9hbGwoZnVucyhyZXBsYWNlKC4sIGlzLm5hbiguKSwgTkEpKSkgDQoNCmBgYA0KDQoNCiMjMi4gIDZ0aCAmIDh0aCBncmFkZSBFTEEgYW5kIE1hdGggc2NvcmVzDQoNClNFREEgRmlsZTogImRpc3RyaWN0IG1lYW5zIG5hdGlvbmFsLXJlZmVyZW5jZWQgYnkgeWVhciBncmFkZSBzdWJqZWN0IChsb25nIGZpbGUpX3YxXzEuY3N2Ig0KRmlsZSBkZXNjcmlwdGlvbjogIlRoaXMgZmlsZSBjb250YWlucyBkaXN0cmljdCBsZXZlbCBtZWFucyBpbiBOQUVQLXJlZmVyZW5jZWQgdW5pdHMuIEVzdGltYXRlcyBhcmUgY29tcGFyYWJsZSBiZXR3ZWVuIHN0YXRlcy4gVGhlcmUgYXJlIG11bHRpcGxlIG9ic2VydmF0aW9ucyBwZXIgZGlzdHJpY3Q7IG9uZSBmb3IgZWFjaCB5ZWFyLCBncmFkZSBhbmQgc3ViamVjdC4iDQpGaWxlOiAgTWVhbkdfVjEuMQ0KDQpFTEEgc2NvcmVzIGZvciA2dGggYW5kIDh0aCBncmFkZXJzLCBhdmVyYWdlZCBhY3Jvc3MgZGlzdHJpY3QgYW5kIHRoZW4gY291bnR5IGFjcm9zcyB5ZWFycyAyMDA5LTIwMTMuDQoNCldlaWdodGVkIG1lYW4gZnVuY3Rpb24gcmV0dXJucyBtaXNzaW5nIHZhbHVlcyBpZiB2YWx1ZXMgZm9yIHdlaWdodHMgKGdyYWRlLXNwZWNpZmljIHBvcHVsYXRpb25zKSBhcmUgbWlzc2luZywgc28gZmlsdGVyaW5nIHRvIGNhc2VzIHdoZXJlIG51bWJlciBvZiBzdHVkZW50cyBpbiByZXNwZWN0aXZlIGdyYWRlIGlzIHJlcG9ydGVkLg0KDQpgYGB7cn0NCiNzZXR3ZCgiY3JlYXRlRGF0YSIpDQoNCg0Kc2VkYV9zY29yZXMgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvZGlzdHJpY3QgbWVhbnMgbmF0aW9uYWwtcmVmZXJlbmNlZCBieSB5ZWFyIGdyYWRlIHN1YmplY3QgKGxvbmcgZmlsZSlfdjFfMS5jc3YiKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoZ3JhZGUgJWluJSBjKCIwOCIsICIwNiIpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgbGVhaWQgPSBpZmVsc2UobmNoYXIobGVhaWQpID09IDYsIHBhc3RlMCgiMCIsIGFzLmNoYXJhY3RlcihsZWFpZCkpLCBhcy5jaGFyYWN0ZXIobGVhaWQpKQ0KICApICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGxlYWlkKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgRUxBXzh0aGdyYWRlID0gbWVhbihtZWFuX2xpbmtfZWxhW3doaWNoKGdyYWRlPT0iMDgiKV0sIG5hLnJtPVQpLA0KICAgIE1BVEhfOHRoZ3JhZGUgPSBtZWFuKG1lYW5fbGlua19tYXRoW3doaWNoKGdyYWRlPT0iMDgiKV0sIG5hLnJtPVQpLA0KICAgICMjNnRoIGdyYWRlIGhhcyBhIGxvdCBmZXdlciBtaXNzaW5nIHZhbHVlcyAtIGUuZy4gTG9zIEFuZ2VsZXMgZGlzdHJpY3RzIGRpZG4ndCByZXBvcnQgOHRoIGdyYWRlIGRhdGENCiAgICBFTEFfNnRoZ3JhZGUgPSBtZWFuKG1lYW5fbGlua19lbGFbd2hpY2goZ3JhZGU9PSIwNiIpXSwgbmEucm09VCksDQogICAgTUFUSF82dGhncmFkZSA9IG1lYW4obWVhbl9saW5rX21hdGhbd2hpY2goZ3JhZGU9PSIwNiIpXSwgbmEucm09VCkNCiAgICApICU+JSANCiAgZHBseXI6Om11dGF0ZV9hbGwoZnVucyhyZXBsYWNlKC4sIGlzLm5hbiguKSwgTkEpKSkgDQoNCg0KYGBgDQoNCg0KIyMzLiAgNnRoIGFuZCA3dGggZ3JhZGUsIHJhY2UgZ2FwcyBpbiBFTEEgYW5kIG1hdGgNClZhcmlhYmxlczoNCg0KLiogZ2FwYmxrX2VsYSA9IHdoaXRlLWJsYWNrIGdhcCBpbiBlbGENCi4qIGdhcGJsa19tYXRoID0gd2hpdGUtYmxhY2sgZ2FwIGluIG1hdGgNCg0KTnVtYmVyIG9mIG5vbi1taXNzaW5nIGNhc2VzIGZvciBFTEEgZ2FwOg0KLiogOHRoIGdyYWRlIC0gMTAwOTkNCi4qIDd0aCBncmFkZSAtIDEwMzU5DQouKiA2dGggZ3JhZGUgLSAxMDE3Mg0KDQpOdW1iZXIgb2Ygbm9uLW1pc3NpbmcgY2FlcyBmb3IgbWF0aCBnYXA6DQouKiA4dGggZ3JhZGUgLSA5MjgwDQouKiA3dGggZ3JhZGUgLSA5MzUwDQouKiA2dGggZ3JhZGUgLSAxMDMwOQ0KDQpVc2luZyA3dGggZ3JhZGUgRUxBIGFuZCA2dGggZ3JhZGUgbWF0aCBnYXAgZXN0aW1hdGVzLg0KDQpgYGB7cn0NCg0KDQpzZWRhX2dhcHMgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvZGlzdHJpY3QgZ2FwcyBieSB5ZWFyIGdyYWRlIHN1YmplY3QgKGxvbmcgZmlsZSlfdjFfMS5jc3YiKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoZ3JhZGUgJWluJSBjKCIwNyIsIjA2IikpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBsZWFpZCA9IGlmZWxzZShuY2hhcihsZWFpZCkgPT0gNiwgcGFzdGUwKCIwIiwgYXMuY2hhcmFjdGVyKGxlYWlkKSksIGFzLmNoYXJhY3RlcihsZWFpZCkpDQogICkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkobGVhaWQpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBFTEFfN3RoZ3JhZGVfZ2FwYmxrID0gbWVhbihnYXBibGtfZWxhW3doaWNoKGdyYWRlPT0iMDciKV0sIG5hLnJtPVQpLA0KICAgIE1BVEhfNnRoZ3JhZGVfZ2FwYmxrID0gbWVhbihnYXBibGtfbWF0aFt3aGljaChncmFkZT09IjA2IildLCBuYS5ybT1UKQ0KICAgICkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIEVMQV83dGhncmFkZV9nYXBibGsgPSByZXBsYWNlKEVMQV83dGhncmFkZV9nYXBibGssIGlzLm5hbihFTEFfN3RoZ3JhZGVfZ2FwYmxrKSwgTkEpLA0KICAgIE1BVEhfNnRoZ3JhZGVfZ2FwYmxrID0gcmVwbGFjZShNQVRIXzZ0aGdyYWRlX2dhcGJsaywgaXMubmFuKE1BVEhfNnRoZ3JhZGVfZ2FwYmxrKSwgTkEpDQogICkgJT4lIA0KICBkcGx5cjo6bXV0YXRlX2FsbChmdW5zKHJlcGxhY2UoLiwgaXMubmFuKC4pLCBOQSkpKSANCg0KDQpgYGANCg0KDQoNCiMjNC4gIENvbWJpbmUgYW5kIEFnZ3JlZ2F0ZSBieSBDb3VudHkgDQoNCkJlbG93IHRoZSBzY2hvb2wgZGlzdHJpY3RzIGFyZSBhZ2dyZWdhdGVkIGJ5IHRha2luZyB0aGVpciB3ZWlnaHRlZCBtZWFucywgd2VpZ2h0aW5nIGJ5IHRoZSBudW1iZXIgb2Ygc3R1ZGVudHMgaW4gZWFjaCBkaXN0cmljdCBmb3IgZWFjaCByZXNwZWN0aXZlIGdyYWRlLg0KDQpgYGB7cn0NCg0Kc2VkYSA8LSBkcGx5cjo6bGVmdF9qb2luKHNlZGFfc2VzX2NvdmFycywgc2VkYV9zY29yZXMsIGJ5PWMoImxlYWlkIikpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihzZWRhX2dhcHMsIGJ5PWMoImxlYWlkIikpICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGxlYWlkKSAlPiUgDQogICMjQ29ycmVjdGlvbiBmb3IgTllDIC0gYWdncmVnYXRpbmcNCiAgZHBseXI6Om11dGF0ZSgNCiAgICBGSVBTID0gYXMuY2hhcmFjdGVyKEZJUFMpLA0KICAgIEZJUFMgPSByZXBsYWNlKEZJUFMsIHdoaWNoKG5jaGFyKEZJUFMpPT00KSwgcGFzdGUwKCIwIiwgRklQUykpLA0KICAgIEZJUFMgPSBwYXN0ZTAoImAiLCBGSVBTKQ0KICApICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KEZJUFMpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBNQVRIXzZ0aGdyYWRlX2dhcCA9IHdlaWdodGVkLm1lYW4oTUFUSF82dGhncmFkZV9nYXBibGtbd2hpY2goIWlzLm5hKHNlZGFfNnRoR3JhZGVyc190b3RhbCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHc9c2VkYV82dGhHcmFkZXJzX3RvdGFsW3doaWNoKCFpcy5uYShzZWRhXzZ0aEdyYWRlcnNfdG90YWwpKV0sIG5hLnJtPVQpLA0KICAgIA0KICAgIEVMQV83dGhncmFkZV9nYXAgPSB3ZWlnaHRlZC5tZWFuKEVMQV83dGhncmFkZV9nYXBibGtbd2hpY2goIWlzLm5hKHNlZGFfN3RoR3JhZGVyc190b3RhbCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdz1zZWRhXzd0aEdyYWRlcnNfdG90YWxbd2hpY2goIWlzLm5hKHNlZGFfN3RoR3JhZGVyc190b3RhbCkpXSwgbmEucm09VCksDQogICAgDQogICAgRUxBXzh0aGdyYWRlID0gd2VpZ2h0ZWQubWVhbihFTEFfOHRoZ3JhZGVbd2hpY2goIWlzLm5hKHNlZGFfOHRoR3JhZGVyc190b3RhbCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3PXNlZGFfOHRoR3JhZGVyc190b3RhbFt3aGljaCghaXMubmEoc2VkYV84dGhHcmFkZXJzX3RvdGFsKSldLCBuYS5ybT1UKSwNCiAgICANCiAgICBFTEFfNnRoZ3JhZGUgPSB3ZWlnaHRlZC5tZWFuKEVMQV82dGhncmFkZVt3aGljaCghaXMubmEoc2VkYV82dGhHcmFkZXJzX3RvdGFsKSldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHc9c2VkYV82dGhHcmFkZXJzX3RvdGFsW3doaWNoKCFpcy5uYShzZWRhXzZ0aEdyYWRlcnNfdG90YWwpKV0sIG5hLnJtPVQpLA0KICAgIA0KICAgIE1BVEhfOHRoZ3JhZGUgPSB3ZWlnaHRlZC5tZWFuKE1BVEhfOHRoZ3JhZGVbd2hpY2goIWlzLm5hKHNlZGFfOHRoR3JhZGVyc190b3RhbCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3PXNlZGFfOHRoR3JhZGVyc190b3RhbFt3aGljaCghaXMubmEoc2VkYV84dGhHcmFkZXJzX3RvdGFsKSldLCBuYS5ybT1UKSwNCiAgICANCiAgICBNQVRIXzZ0aGdyYWRlID0gd2VpZ2h0ZWQubWVhbihNQVRIXzZ0aGdyYWRlW3doaWNoKCFpcy5uYShzZWRhXzZ0aEdyYWRlcnNfdG90YWwpKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdz1zZWRhXzZ0aEdyYWRlcnNfdG90YWxbd2hpY2goIWlzLm5hKHNlZGFfNnRoR3JhZGVyc190b3RhbCkpXSwgbmEucm09VCksDQogICAgDQogICAgDQogIHNlc19hbGwgPSB3ZWlnaHRlZC5tZWFuKHNlc19hbGxbd2hpY2goIWlzLm5hKHRvdGFsU3R1ZGVudHNfYWxsKSldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgdz10b3RhbFN0dWRlbnRzX2FsbFt3aGljaCghaXMubmEodG90YWxTdHVkZW50c19hbGwpKV0sIG5hLnJtPVQpLA0KICB0aGVpbF93aGl0ZUJsYWNrID0gd2VpZ2h0ZWQubWVhbih0aGVpbF93aGl0ZUJsYWNrW3doaWNoKCFpcy5uYSh0b3RhbFN0dWRlbnRzX2FsbCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHc9dG90YWxTdHVkZW50c19hbGxbd2hpY2goIWlzLm5hKHRvdGFsU3R1ZGVudHNfYWxsKSldLCBuYS5ybT1UKSwNCiAgZ2luaV9hbGwgPSB3ZWlnaHRlZC5tZWFuKGdpbmlfYWxsW3doaWNoKCFpcy5uYSh0b3RhbFN0dWRlbnRzX2FsbCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB3PXRvdGFsU3R1ZGVudHNfYWxsW3doaWNoKCFpcy5uYSh0b3RhbFN0dWRlbnRzX2FsbCkpXSwgbmEucm09VCkNCiAgKSAlPiUgDQogIGRwbHlyOjptdXRhdGVfYWxsKGZ1bnMocmVwbGFjZSguLCBpcy5uYW4oLiksIE5BKSkpIA0KICANCmBgYA0KDQoNCg0KDQoNCg0KI1YuICBBQ1MgKEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkpDQoNCiMjMS4gTWVkaWFuIEluY29tZSBieSBSYWNlIEFDUyAoQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSkNCkZ1cnRoZXIgaW5jb21lIGRhdGEsIGRpc2FnZ3JlZ2F0ZWQgYnkgcmFjZSwgYXJlIHRha2VuIGZyb20gdGhlIEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXksICIyMDExLTIwMTUgQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSA1LVllYXIgRXN0aW1hdGVzIiwgYXZhaWxhYmxlIG9ubGluZSBhdA0KaHR0cHM6Ly9mYWN0ZmluZGVyLmNlbnN1cy5nb3YvZmFjZXMvYWZmaGVscC9qc2YvcGFnZXMvbWV0YWRhdGEueGh0bWw/bGFuZz1lbiZ0eXBlPWRhdGFzZXQmaWQ9ZGF0YXNldC5lbi5BQ1NfMTVfNVlSDQoNCipPcHRpb25zKjogIA0KDQotIE1lZGlhbiBFYXJuaW5ncywgb3IgDQotIE1lZGlhbiBIb3VzZWhvbGQgSW5jb21lLCBvciANCi0gTWVkaWFuIEZhbWlseSBJbmNvbWUsIG9yDQotIHBlciBjYXBpdGEgaW5jb21lDQoNCioqUmFjZS1zcGVjaWZpYyBtZWRpYW4gZmFtaWx5IGluY29tZXMgYnkgY291bnR5IHdlcmUgcmV0cmlldmVkIGZyb20gdGhlIGZvbGxvd2luZyBmaWxlczoqKg0KDQoxLiBbV2hpdGVdIEIxOTExM0EgLSBNRURJQU4gRkFNSUxZIElOQ09NRSBJTiBUSEUgUEFTVCAxMiBNT05USFMgKElOIDIwMTUgSU5GTEFUSU9OLUFESlVTVEVEIERPTExBUlMpIChXSElURSBBTE9ORSBIT1VTRUhPTERFUikuDQoNCjIuIFtCbGFja10gQjE5MTEzQiAtIE1FRElBTiBGQU1JTFkgSU5DT01FIElOIFRIRSBQQVNUIDEyIE1PTlRIUyAoSU4gMjAxNSBJTkZMQVRJT04tQURKVVNURUQgRE9MTEFSUykgKEJMQUNLIE9SIEFGUklDQU4gQU1FUklDQU4gQUxPTkUgSE9VU0VIT0xERVIpDQoNCjMuICBbV2hpdGUgTm9uLUhpc3BhbmljXSBCMTkxMTNIIC0gTUVESUFOIEZBTUlMWSBJTkNPTUUgSU4gVEhFIFBBU1QgMTIgTU9OVEhTIChJTiAyMDE1IElORkxBVElPTi1BREpVU1RFRCBET0xMQVJTKSAoV0hJVEUgQUxPTkUsIE5PVCBISVNQQU5JQyBPUiBMQVRJTk8gSE9VU0VIT0xERVIpDQoNCjQuIFtIaXNwYW5pY10gQjE5MTEzSSAtIE1FRElBTiBGQU1JTFkgSU5DT01FIElOIFRIRSBQQVNUIDEyIE1PTlRIUyAoSU4gMjAxNSBJTkZMQVRJT04tQURKVVNURUQgRE9MTEFSUykgKEhJU1BBTklDIE9SIExBVElOTyBIT1VTRUhPTERFUikNCg0KNS4gW0FsbF0gQjE5MTEzIC0gTUVESUFOIEZBTUlMWSBJTkNPTUUgSU4gVEhFIFBBU1QgMTIgTU9OVEhTIChJTiAyMDE1IElORkxBVElPTi1BREpVU1RFRCBET0xMQVJTKQ0KDQpBZ2dyZWdhdGluZyB0aGUgTllDIGJ1cnJvdWdocyB1c2luZyB0aGUgbWVkaWFuIGluY29tZXMgb2YgbWVkaWFuIGluY29tZXMgZm9yIGVhY2ggYnVycm91Z2guDQpgYGB7cn0NCiNzZXR3ZCgiY3JlYXRlRGF0YSIpDQpueUZpcHMgPC0gYygiYDM2MDYxIiwgImAzNjA0NyIsICJgMzYwODEiLCAiYDM2MDA1IiwgImAzNjA4NSIpDQoNCmluY19hbGwgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX21lZGlhbkluY29tZS5jc3YiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgUmFjZSA9ICJUb3RhbCINCiAgKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZShjb3VudHksIGludG89YygiY291bnR5IiwgInN0YXRlTmFtZSIpLCBzZXA9IiwiKQ0KDQppbmNfd2hpdGUgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX21lZGlhbkluY29tZV93aGl0ZS5jc3YiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgUmFjZSA9ICJXaGl0ZSINCiAgKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZShjb3VudHksIGludG89YygiY291bnR5IiwgInN0YXRlTmFtZSIpLCBzZXA9IiwiKSANCg0KaW5jX2JsYWNrIDwtIHJlYWRfY3N2KCJjcmVhdGVEYXRhL0FDU19tZWRpYW5JbmNvbWVfYmxhY2suY3N2IikgJT4lIA0KICAgIGRwbHlyOjptdXRhdGUoDQogICAgUmFjZSA9ICJCbGFjayINCiAgKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZShjb3VudHksIGludG89YygiY291bnR5IiwgInN0YXRlTmFtZSIpLCBzZXA9IiwiKQ0KDQppbmNfd2hpdGVfbmggPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX21lZGlhbkluY29tZV93aGl0ZV9OSC5jc3YiKSAlPiUgDQogICAgZHBseXI6Om11dGF0ZSgNCiAgICBSYWNlID0gIldoaXRlX05IIg0KICApICU+JSANCiAgdGlkeXI6OnNlcGFyYXRlKGNvdW50eSwgaW50bz1jKCJjb3VudHkiLCAic3RhdGVOYW1lIiksIHNlcD0iLCIpDQoNCmluY19oaXNwIDwtIHJlYWRfY3N2KCJjcmVhdGVEYXRhL0FDU19tZWRpYW5JbmNvbWVfaGlzcGFuaWMuY3N2IikgJT4lIA0KICAgIGRwbHlyOjptdXRhdGUoDQogICAgUmFjZSA9ICJIaXNwYW5pYyINCiAgKSAlPiUgDQogIHRpZHlyOjpzZXBhcmF0ZShjb3VudHksIGludG89YygiY291bnR5IiwgInN0YXRlTmFtZSIpLCBzZXA9IiwiKSANCg0KDQoNCmluY19kZiA8LSBkcGx5cjo6YmluZF9yb3dzKGluY19hbGwsIGluY193aGl0ZSwgaW5jX3doaXRlX25oLCBpbmNfYmxhY2ssIGluY19oaXNwKSAlPiUgDQogIHRpZHlyOjpzcHJlYWQoUmFjZSwgbWVkaWFuSW5jb21lKSAlPiUgDQogICAgZHBseXI6OnJlbmFtZSgNCiAgICBtZWRpYW5JbmNvbWUgPSBUb3RhbCwNCiAgICBtZWRpYW5JbmNvbWVfd2hpdGUgPSBXaGl0ZSwNCiAgICBtZWRpYW5JbmNvbWVfYmxhY2sgPSBCbGFjaywNCiAgICBtZWRpYW5JbmNvbWVfd2hpdGVfbmggPSBXaGl0ZV9OSCwNCiAgICBtZWRpYW5JbmNvbWVfaGlzcCA9IEhpc3BhbmljDQogICkgJT4lIA0KZHBseXI6OnNlbGVjdCgtY291bnR5LCAtc3RhdGVOYW1lKQ0KDQoNCiMjRml4aW5nIGZpcHMgdGhhdCBiZWdpbiB3aXRoIDANCmZvcihpIGluIDE6bnJvdyhpbmNfZGYpKXsNCiAgaWYobmNoYXIoaW5jX2RmJGZpcHNbaV0pPT00KXsNCiAgICBpbmNfZGYkZmlwc1tpXSA8LSBwYXN0ZTAoImAwIiwgYXMuY2hhcmFjdGVyKGluY19kZiRmaXBzW2ldKSkNCiAgfSANCiAgaWYobmNoYXIoaW5jX2RmJGZpcHNbaV0pPT01KXsNCiAgICBpbmNfZGYkZmlwc1tpXSA8LSBwYXN0ZTAoImAiLCBhcy5jaGFyYWN0ZXIoaW5jX2RmJGZpcHNbaV0pKQ0KICB9IA0KICANCn0NCg0KDQppbmNfZGYgPC0gaW5jX2RmICU+JSANCiAgIGRwbHlyOjpyZW5hbWUoRklQUz1maXBzKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgRklQUyA9IHJlcGxhY2UoRklQUywgd2hpY2goRklQUyAlaW4lIG55RmlwcyksICJgMzYwNjEiKQ0KICApICU+JSANCiAgICBkcGx5cjo6Z3JvdXBfYnkoRklQUykgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlX2FsbChtZWRpYW4sIG5hLnJtPVQpDQoNCg0KYGBgDQoNCg0KIyMyLiAgUG92ZXJ0eS4gQUNTIChBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5KQ0KKipQb3ZlcnR5KioNCltUb3RhbCBhbmQgYnkgUmFjZV0gUzE3MDIgLSBQT1ZFUlRZIFNUQVRVUyBJTiBUSEUgUEFTVCAxMiBNT05USFMgT0YgRkFNSUxJRVMNCg0KLS0gSEMwMl9FU1RfVkMwMSAtIEFsbCBmYW1pbGllcyAgLSBQZXJjZW50IGJlbG93IHBvdmVydHkgbGV2ZWw7IEVzdGltYXRlOyBGYW1pbGllcw0KDQotLSBIQzAyX0VTVF9WQzA5IC0gQWxsIGZhbWlsaWVzICAtIFBlcmNlbnQgYmVsb3cgcG92ZXJ0eSBsZXZlbDsgRXN0aW1hdGU7IFJBQ0UgQU5EIEhJU1BBTklDIE9SIExBVElOTyBPUklHSU4gLSBGYW1pbGllcyB3aXRoIGEgaG91c2Vob2xkZXIgd2hvIGlzICpXaGl0ZSBhbG9uZSoiDQoNCi0tIEhDMDJfRVNUX1ZDMTAgLSBBbGwgZmFtaWxpZXMgIC0gUGVyY2VudCBiZWxvdyBwb3ZlcnR5IGxldmVsOyBFc3RpbWF0ZTsgUkFDRSBBTkQgSElTUEFOSUMgT1IgTEFUSU5PIE9SSUdJTiAtIEZhbWlsaWVzIHdpdGggYSBob3VzZWhvbGRlciB3aG8gaXMgKkJsYWNrIG9yIEFmcmljYW4gQW1lcmljYW4gYWxvbmUqDQoNCi0tIEhDMDJfRVNUX1ZDMTEgLSBBbGwgZmFtaWxpZXMgIC0gUGVyY2VudCBiZWxvdyBwb3ZlcnR5IGxldmVsOyBFc3RpbWF0ZTsgUkFDRSBBTkQgSElTUEFOSUMgT1IgTEFUSU5PIE9SSUdJTiAtIEZhbWlsaWVzIHdpdGggYSBob3VzZWhvbGRlciB3aG8gaXMgKkFtZXJpY2FuIEluZGlhbiBhbmQgQWxhc2thIE5hdGl2ZSBhbG9uZSoNCg0KLS1IQzAyX0VTVF9WQzEyIC0gQWxsIGZhbWlsaWVzICAtIFBlcmNlbnQgYmVsb3cgcG92ZXJ0eSBsZXZlbDsgRXN0aW1hdGU7IFJBQ0UgQU5EIEhJU1BBTklDIE9SIExBVElOTyBPUklHSU4gLSBGYW1pbGllcyB3aXRoIGEgaG91c2Vob2xkZXIgd2hvIGlzICpBc2lhbiBhbG9uZSoNCg0KLS0gSEMwMl9FU1RfVkMxMyAtIEFsbCBmYW1pbGllcyAgLSBQZXJjZW50IGJlbG93IHBvdmVydHkgbGV2ZWw7IEVzdGltYXRlOyBSQUNFIEFORCBISVNQQU5JQyBPUiBMQVRJTk8gT1JJR0lOIC0gRmFtaWxpZXMgd2l0aCBhIGhvdXNlaG9sZGVyIHdobyBpcyAqTmF0aXZlIEhhd2FpaWFuIGFuZCBPdGhlciBQYWNpZmljIElzbGFuZGVyIGFsb25lKg0KDQotLSBIQzAyX0VTVF9WQzE3IC0gQWxsIGZhbWlsaWVzICAtIFBlcmNlbnQgYmVsb3cgcG92ZXJ0eSBsZXZlbDsgRXN0aW1hdGU7IEhpc3BhbmljIG9yIExhdGlubyBvcmlnaW4gKG9mIGFueSByYWNlKQ0KDQotLSBIQzAyX0VTVF9WQzE4IC0gQWxsIGZhbWlsaWVzICAtIFBlcmNlbnQgYmVsb3cgcG92ZXJ0eSBsZXZlbDsgRXN0aW1hdGU7IFdoaXRlIGFsb25lLCBub3QgSGlzcGFuaWMgb3IgTGF0aW5vDQoNCmBgYHtyfQ0KI3NldHdkKCJjcmVhdGVEYXRhIikNCm55RmlwcyA8LSBjKCJgMzYwNjEiLCAiYDM2MDQ3IiwgImAzNjA4MSIsICJgMzYwMDUiLCAiYDM2MDg1IikNCg0KcG92IDwtIHJlYWRfY3N2KCJjcmVhdGVEYXRhL0FDU19wb3ZlcnR5LmNzdiIpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtY291bnR5KQ0KDQojI0ZpeGluZyBmaXBzIHRoYXQgYmVnaW4gd2l0aCAwDQpmb3IoaSBpbiAxOm5yb3cocG92KSl7DQogIGlmKG5jaGFyKHBvdiRmaXBzW2ldKT09NCl7DQogICAgcG92JGZpcHNbaV0gPC0gcGFzdGUwKCJgMCIsIGFzLmNoYXJhY3Rlcihwb3YkZmlwc1tpXSkpDQogIH0gDQogIGlmKG5jaGFyKHBvdiRmaXBzW2ldKT09NSl7DQogICAgcG92JGZpcHNbaV0gPC0gcGFzdGUwKCJgIiwgYXMuY2hhcmFjdGVyKHBvdiRmaXBzW2ldKSkNCiAgfSANCiAgDQp9DQoNCg0KcG92IDwtIHBvdiAlPiUgDQogICBkcGx5cjo6cmVuYW1lKEZJUFM9ZmlwcykgJT4lIA0KICAgIGRwbHlyOjptdXRhdGUoDQogICAgRklQUyA9IHJlcGxhY2UoRklQUywgd2hpY2goRklQUyAlaW4lIG55RmlwcyksICJgMzYwNjEiKQ0KICApICU+JSANCiAgICBncm91cF9ieShGSVBTKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYWxsKG1lZGlhbiwgbmEucm09VCkNCg0KYGBgDQoNCiMjMy4gR2luaSBJbmRleCBBQ1MgKEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkpDQoNCi0gQjE5MDgzIC0gCUdJTkkgSU5ERVggT0YgSU5DT01FIElORVFVQUxJVFkgKDUgeWVhciBhdmVyYWdlcykNCmh0dHBzOi8vZmFjdGZpbmRlci5jZW5zdXMuZ292L2ZhY2VzL2FmZmhlbHAvanNmL3BhZ2VzL21ldGFkYXRhLnhodG1sP2xhbmc9ZW4mdHlwZT10YWJsZSZpZD10YWJsZS5lbi5BQ1NfMTVfNVlSX0IxOTA4Mw0KDQpgYGB7cn0NCiNzZXR3ZCgiY3JlYXRlRGF0YSIpDQpueUZpcHMgPC0gYygiYDM2MDYxIiwgImAzNjA0NyIsICJgMzYwODEiLCAiYDM2MDA1IiwgImAzNjA4NSIpDQoNCmdpbmkgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX2dpbmlfNXlyLmNzdiIpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtY291bnR5KQ0KDQoNCiMjRml4aW5nIGZpcHMgdGhhdCBiZWdpbiB3aXRoIDANCmZvcihpIGluIDE6bnJvdyhnaW5pKSl7DQogIGlmKG5jaGFyKGdpbmkkZmlwc1tpXSk9PTQpew0KICAgIGdpbmkkZmlwc1tpXSA8LSBwYXN0ZTAoImAwIiwgYXMuY2hhcmFjdGVyKGdpbmkkZmlwc1tpXSkpDQogIH0gDQogIGlmKG5jaGFyKGdpbmkkZmlwc1tpXSk9PTUpew0KICAgIGdpbmkkZmlwc1tpXSA8LSBwYXN0ZTAoImAiLCBhcy5jaGFyYWN0ZXIoZ2luaSRmaXBzW2ldKSkNCiAgfSANCn0NCg0KZ2luaSA8LSBnaW5pICU+JSANCiAgIGRwbHlyOjpyZW5hbWUoRklQUz1maXBzKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgRklQUyA9IHJlcGxhY2UoRklQUywgd2hpY2goRklQUyAlaW4lIG55RmlwcyksICJgMzYwNjEiKQ0KICApICU+JSANCiAgICBncm91cF9ieShGSVBTKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYWxsKG1lZGlhbiwgbmEucm09VCkNCg0KYGBgDQoNCg0KIyM0LiBTaW5nbGUtUGFyZW50LUhlYWRlZCBIb3VzZWhvbGRzICUgIEFDUyAoQW1lcmljYW4gQ29tbXVuaXR5IFN1cnZleSkNCg0KLS0gQjExMDAxIC0gIkhPVVNFSE9MRCBUWVBFIChJTkNMVURJTkcgTElWSU5HIEFMT05FKSINCg0KLS0gQjExMDAxQSAtICJIT1VTRUhPTEQgVFlQRSAoSU5DTFVESU5HIExJVklORyBBTE9ORSkgKFdISVRFIEFMT05FKSINCg0KLS0gQjExMDAxQiAtICJIT1VTRUhPTEQgVFlQRSAoSU5DTFVESU5HIExJVklORyBBTE9ORSkgKEJMQUNLIE9SIEFGUklDQU4gQU1FUklDQU4gQUxPTkUpIg0KDQotLSBCMTEwMDFDIC0gIkhPVVNFSE9MRCBUWVBFIChJTkNMVURJTkcgTElWSU5HIEFMT05FKSAoQU1FUklDQU4gSU5ESUFOIEFORCBBTEFTS0EgTkFUSVZFIEFMT05FKSINCg0KLS0gQjExMDAxRCAtICJIT1VTRUhPTEQgVFlQRSAoSU5DTFVESU5HIExJVklORyBBTE9ORSkgKEFTSUFOIEFMT05FKSINCg0KLS0gQjExMDAxRSAtICJIT1VTRUhPTEQgVFlQRSAoSU5DTFVESU5HIExJVklORyBBTE9ORSkgKE5BVElWRSBIQVdBSUlBTiBBTkQgT1RIRVIgUEFDSUZJQyBJU0xBTkRFUiBBTE9ORSkiDQoNCi0tIEIxMTAwMUggLSAiSE9VU0VIT0xEIFRZUEUgKElOQ0xVRElORyBMSVZJTkcgQUxPTkUpIChXSElURSBBTE9ORSwgTk9UIEhJU1BBTklDIE9SIExBVElOTykiDQoNCi0tIEIxMTAwMUkgLSAiSE9VU0VIT0xEIFRZUEUgKElOQ0xVRElORyBMSVZJTkcgQUxPTkUpIChISVNQQU5JQyBPUiBMQVRJTk8pIg0KDQpGcm9tIGVhY2ggZGF0YXNldCB0d28gdmFyaWFibGVzIGFyZSBleHRyYWN0ZWQ6ICANCg0KMS4gICJFc3RpbWF0ZTsgRmFtaWx5IGhvdXNlaG9sZHMiIFtIRDAxX1ZEMDJdICANCg0KMi4gIkVzdGltYXRlOyBGYW1pbHkgaG91c2Vob2xkczogLSBPdGhlciBmYW1pbHk6IC0gRmVtYWxlIGhvdXNlaG9sZGVyLCBubyBodXNiYW5kIHByZXNlbnQiIFtIRDAxX1ZEMDZdDQoNCmBgYHtyfQ0KI3NldHdkKCJjcmVhdGVEYXRhIikNCm55RmlwcyA8LSBjKCJgMzYwNjEiLCAiYDM2MDQ3IiwgImAzNjA4MSIsICJgMzYwMDUiLCAiYDM2MDg1IikNCg0Kc3BfdG90YWwgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX3NpbmdsZVBhcmVudF90b3RhbC5jc3YiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoc2luZ2xlUGFyZW50X3ByY250ID0gc2luZ2xlUGFyZW50L3RvdGFsRmFtaWxpZXMpDQoNCg0Kc3Bfd2hpdGUgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX3NpbmdsZVBhcmVudF93aGl0ZS5jc3YiKSAlPiUgDQogICAgZHBseXI6Om11dGF0ZSgNCiAgICAgIHNpbmdsZVBhcmVudF9wcmNudF93aGl0ZSA9IGlmZWxzZShmYW1pbGllc193aGl0ZT4wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbmdsZVBhcmVudF93aGl0ZS9mYW1pbGllc193aGl0ZSwwKQ0KICAgICkNCg0Kc3Bfd2hpdGVfbmggPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX3NpbmdsZVBhcmVudF93aGl0ZV9uaC5jc3YiKSAlPiUgIyNub25oaXNwYW5pYyB3aGl0ZQ0KICAgICAgZHBseXI6Om11dGF0ZSgNCiAgICAgICAgc2luZ2xlUGFyZW50X3ByY250X3doaXRlX25oID0gaWZlbHNlKGZhbWlsaWVzX3doaXRlX25oID4gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbmdsZVBhcmVudF93aGl0ZV9uaC9mYW1pbGllc193aGl0ZV9uaCwgMCkNCiAgICAgICkNCg0Kc3BfYmxhY2sgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX3NpbmdsZVBhcmVudF9ibGFjay5jc3YiKSAlPiUgDQogICAgICBkcGx5cjo6bXV0YXRlKA0KICAgICAgICBzaW5nbGVQYXJlbnRfcHJjbnRfYmxhY2sgPSBpZmVsc2UoZmFtaWxpZXNfYmxhY2sgPiAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2luZ2xlUGFyZW50X2JsYWNrL2ZhbWlsaWVzX2JsYWNrLCAgMCkNCikNCg0Kc3BfYW1lcmluZGlhbiA8LSByZWFkX2NzdigiY3JlYXRlRGF0YS9BQ1Nfc2luZ2xlUGFyZW50X2FtZXJpbmRpYW4uY3N2IikgJT4lIA0KICAgICAgZHBseXI6Om11dGF0ZSgNCiAgICAgICAgc2luZ2xlUGFyZW50X3ByY250X2FtZXJpbmRpYW4gPSBpZmVsc2UoZmFtaWxpZXNfYW1lcmluZGlhbj4wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaW5nbGVQYXJlbnRfYW1lcmluZGlhbi9mYW1pbGllc19hbWVyaW5kaWFuLCAwKQ0KICAgICAgKQ0KDQpzcF9hc2lhbiA8LSByZWFkX2NzdigiY3JlYXRlRGF0YS9BQ1Nfc2luZ2xlUGFyZW50X2FzaWFuLmNzdiIpICU+JSANCiAgICAgIGRwbHlyOjptdXRhdGUoDQogICAgICAgIHNpbmdsZVBhcmVudF9wcmNudF9hc2lhbiA9IGlmZWxzZShmYW1pbGllc19hc2lhbj4wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2luZ2xlUGFyZW50X2FzaWFuL2ZhbWlsaWVzX2FzaWFuLCAwKQ0KICAgICAgKQ0KDQpzcF9oYXdhaWlhbiA8LSByZWFkX2NzdigiY3JlYXRlRGF0YS9BQ1Nfc2luZ2xlUGFyZW50X2hhd2FpaWFuLmNzdiIpICU+JSANCiAgICAgIGRwbHlyOjptdXRhdGUoDQogICAgICAgIHNpbmdsZVBhcmVudF9wcmNudF9oYXdhaWlhbiA9IGlmZWxzZShmYW1pbGllc19oYXdhaWlhbj4wLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2luZ2xlUGFyZW50X2hhd2FpaWFuL2ZhbWlsaWVzX2hhd2FpaWFuLCAgMCkNCiAgICAgICkNCg0Kc3BfaGlzcGFuaWMgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvQUNTX3NpbmdsZVBhcmVudF9oaXNwYW5pYy5jc3YiKSAlPiUgDQogICAgICBkcGx5cjo6bXV0YXRlKA0KICAgICAgICBzaW5nbGVQYXJlbnRfcHJjbnRfaGlzcGFuaWMgPSBpZmVsc2UoZmFtaWxpZXNfaGlzcGFuaWM+MCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbmdsZVBhcmVudF9oaXNwYW5pYy9mYW1pbGllc19oaXNwYW5pYywgMCkNCiAgICAgICkNCg0Kc2luZ2xlUGFyZW50IDwtIGRwbHlyOjpsZWZ0X2pvaW4oc3BfdG90YWwsIHNwX3doaXRlKSAlPiUgDQogIGRwbHlyOjpsZWZ0X2pvaW4oc3Bfd2hpdGVfbmgpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihzcF9ibGFjaykgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKHNwX2FtZXJpbmRpYW4pICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihzcF9hc2lhbikgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKHNwX2hhd2FpaWFuKSAlPiUgDQogIGRwbHlyOjpsZWZ0X2pvaW4oc3BfaGlzcGFuaWMpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtY291bnR5KQ0KICANCg0KIyNGaXhpbmcgZmlwcyB0aGF0IGJlZ2luIHdpdGggMA0KZm9yKGkgaW4gMTpucm93KHNpbmdsZVBhcmVudCkpew0KICBpZihuY2hhcihzaW5nbGVQYXJlbnQkZmlwc1tpXSk9PTQpew0KICAgIHNpbmdsZVBhcmVudCRmaXBzW2ldIDwtIHBhc3RlMCgiYDAiLCBhcy5jaGFyYWN0ZXIoc2luZ2xlUGFyZW50JGZpcHNbaV0pKQ0KICB9IA0KICBpZihuY2hhcihzaW5nbGVQYXJlbnQkZmlwc1tpXSk9PTUpew0KICAgIHNpbmdsZVBhcmVudCRmaXBzW2ldIDwtIHBhc3RlMCgiYCIsIGFzLmNoYXJhY3RlcihzaW5nbGVQYXJlbnQkZmlwc1tpXSkpDQogIH0gDQp9DQoNCnNpbmdsZVBhcmVudCA8LSBzaW5nbGVQYXJlbnQgJT4lIA0KICAgZHBseXI6OnJlbmFtZShGSVBTPWZpcHMpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBGSVBTID0gcmVwbGFjZShGSVBTLCB3aGljaChGSVBTICVpbiUgbnlGaXBzKSwgImAzNjA2MSIpDQogICkgJT4lIA0KICAgIGdyb3VwX2J5KEZJUFMpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZV9hbGwobWVkaWFuLCBuYS5ybT1UKQ0KDQpgYGANCg0KIyM1LiAgRWR1Y2F0aW9uYWwgQXR0YWlubWVudCAobGVzcyB0aGFuIGhpZ2ggc2Nob29sICUpICBBQ1MgKEFtZXJpY2FuIENvbW11bml0eSBTdXJ2ZXkpDQoqKkVEVUNBVElPTkFMIEFUVEFJTk1FTlQqKg0KW1RvdGFsIGFuZCBieSBSYWNlXSBTMTUwMSAtIEVEVUNBVElPTkFMIEFUVEFJTk1FTlQNCg0KSEMwMl9FU1RfVkMwMyAtICJQZXJjZW50OyBFc3RpbWF0ZTsgUG9wdWxhdGlvbiAxOCB0byAyNCB5ZWFycyAtIExlc3MgdGhhbiBoaWdoIHNjaG9vbCBncmFkdWF0ZSINCg0KYGBge3J9DQojc2V0d2QoImNyZWF0ZURhdGEiKQ0KbnlGaXBzIDwtIGMoImAzNjA2MSIsICJgMzYwNDciLCAiYDM2MDgxIiwgImAzNjAwNSIsICJgMzYwODUiKQ0KDQpocyA8LSByZWFkX2NzdigiY3JlYXRlRGF0YS9BQ1NfaGlnaHNjaG9vbC5jc3YiKQ0KDQojI0ZpeGluZyBmaXBzIHRoYXQgYmVnaW4gd2l0aCAwDQpmb3IoaSBpbiAxOm5yb3coaHMpKXsNCiAgaWYobmNoYXIoaHMkZmlwc1tpXSk9PTQpew0KICAgIGhzJGZpcHNbaV0gPC0gcGFzdGUwKCJgMCIsIGFzLmNoYXJhY3RlcihocyRmaXBzW2ldKSkNCiAgfSANCiAgaWYobmNoYXIoaHMkZmlwc1tpXSk9PTUpew0KICAgIGhzJGZpcHNbaV0gPC0gcGFzdGUwKCJgIiwgYXMuY2hhcmFjdGVyKGhzJGZpcHNbaV0pKQ0KICB9IA0KfQ0KDQpocyA8LSBocyAlPiUgDQpkcGx5cjo6cmVuYW1lKEZJUFM9ZmlwcykgJT4lIA0KZHBseXI6Om11dGF0ZSgNCiAgICBGSVBTID0gcmVwbGFjZShGSVBTLCB3aGljaChGSVBTICVpbiUgbnlGaXBzKSwgImAzNjA2MSIpDQogICkgJT4lIA0KICAgIGdyb3VwX2J5KEZJUFMpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZV9hbGwobWVkaWFuLCBuYS5ybT1UKQ0KDQpgYGANCg0KDQoNCg0KDQojIzYuICBDcm93aW5nIChBQ1MpICAoT2NjdXBhbnRzIHBlciByb29tKSAgKEFDUykNCltBbGwgUmFjZXMsIGJ5IE93bmVyIG9yIFJlbnRlcl0gQjI1MDE0IC0gVEVOVVJFIEJZIE9DQ1VQQU5UUyBQRVIgUk9PTQ0KVG8gY2FsY3VsYXRlICJjcm93ZGluZyIgd2UgZXNpbWF0ZSB0aGUgcGVyY2VudGFnZSBvZiBob3VzZWhvbGRzIHdpdGggMS4wMSBvciBtb3JlIG9jY3VwYW50cyBwZXIgcm9vbS4gIFdlIGluY2x1ZGUgb3duZXJzIGFuZCByZW50ZXJzLiAgV2UgdXNlIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOg0KDQotIEhEMDFfVkQwMSAtICJFc3RpbWF0ZTsgVG90YWw6Ig0KDQotIEhEMDFfVkQwNSAtICJFc3RpbWF0ZTsgT3duZXIgb2NjdXBpZWQ6IC0gMS4wMSB0byAxLjUwIG9jY3VwYW50cyBwZXIgcm9vbSINCg0KLSBIRDAxX1ZEMDYgLSAiRXN0aW1hdGU7IE93bmVyIG9jY3VwaWVkOiAtIDEuNTEgdG8gMi4wMCBvY2N1cGFudHMgcGVyIHJvb20iDQoNCi0gSEQwMV9WRDA3IC0gIkVzdGltYXRlOyBPd25lciBvY2N1cGllZDogLSAyLjAxIG9yIG1vcmUgb2NjdXBhbnRzIHBlciByb29tIg0KDQotIEhEMDFfVkQxMSAtICJFc3RpbWF0ZTsgUmVudGVyIG9jY3VwaWVkOiAtIDEuMDEgdG8gMS41MCBvY2N1cGFudHMgcGVyIHJvb20iDQoNCi0gSEQwMV9WRDEyIC0gIkVzdGltYXRlOyBSZW50ZXIgb2NjdXBpZWQ6IC0gMS41MSB0byAyLjAwIG9jY3VwYW50cyBwZXIgcm9vbSINCg0KLSBIRDAxX1ZEMTMgLSAiRXN0aW1hdGU7IFJlbnRlciBvY2N1cGllZDogLSAyLjAxIG9yIG1vcmUgb2NjdXBhbnRzIHBlciByb29tIg0KDQpgYGB7cn0NCiNzZXR3ZCgiY3JlYXRlRGF0YSIpDQpjcm93ZCA8LSByZWFkX2NzdigiY3JlYXRlRGF0YS9BQ1NfY3Jvd2RpbmcuY3N2IikNCg0KIyNGaXhpbmcgZmlwcyB0aGF0IGJlZ2luIHdpdGggMA0KZm9yKGkgaW4gMTpucm93KGNyb3dkKSl7DQogIGlmKG5jaGFyKGNyb3dkJGZpcHNbaV0pPT00KXsNCiAgICBjcm93ZCRmaXBzW2ldIDwtIHBhc3RlMCgiYDAiLCBhcy5jaGFyYWN0ZXIoY3Jvd2QkZmlwc1tpXSkpDQogIH0gDQogIGlmKG5jaGFyKGNyb3dkJGZpcHNbaV0pPT01KXsNCiAgICBjcm93ZCRmaXBzW2ldIDwtIHBhc3RlMCgiYCIsIGFzLmNoYXJhY3Rlcihjcm93ZCRmaXBzW2ldKSkNCiAgfSANCiAgDQp9DQoNCmNyb3dkIDwtIGNyb3dkICU+JSANCiAgIGRwbHlyOjpyZW5hbWUoRklQUz1maXBzKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgRklQUyA9IHJlcGxhY2UoRklQUywgd2hpY2goRklQUyAlaW4lIG55RmlwcyksICJgMzYwNjEiKQ0KICApICU+JSANCiAgICBncm91cF9ieShGSVBTKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYWxsKG1lZGlhbiwgbmEucm09VCkNCg0KYGBgDQoNCg0KDQoNCiMjNy4gIFJlc2lkZW50aWFsIFNlZ3JlZ2F0aW9uIC0gQ291bnR5SGVhbHRoUmFua2luZ3Mub3JnIGZyb20gQUNTIDIwMTYtMjAxNw0KQXZlcmFnZWQgYWNyb3NzIDIwMTYgYW5kIDIwMTcNCmNvdW50eWhlYWx0aHJhbmtpbmdzLm9yZywgIlJlc2lkZW50aWFsIHNlZ3JlZ2F0aW9u4oCUYmxhY2svd2hpdGUsIDIwMTEtMjAxNSwgc291cmNlPUFDUyINCg0KRGVzY3JpcHRpb246IGh0dHA6Ly93d3cuY291bnR5aGVhbHRocmFua2luZ3Mub3JnL21lYXN1cmUvcmVzaWRlbnRpYWwtc2VncmVnYXRpb24tYmxhY2t3aGl0ZQ0KDQoiUmFjaWFsL2V0aG5pYyByZXNpZGVudGlhbCBzZWdyZWdhdGlvbiByZWZlcnMgdG8gdGhlIGRlZ3JlZSB0byB3aGljaCB0d28gb3IgbW9yZSBncm91cHMgbGl2ZSBzZXBhcmF0ZWx5IGZyb20gb25lIGFub3RoZXIgaW4gYSBnZW9ncmFwaGljIGFyZWEuIFRoZSBpbmRleCBvZiBkaXNzaW1pbGFyaXR5IGlzIGEgZGVtb2dyYXBoaWMgbWVhc3VyZSBvZiB0aGUgZXZlbm5lc3Mgd2l0aCB3aGljaCB0d28gZ3JvdXBzIChibGFjayBhbmQgd2hpdGUgcmVzaWRlbnRzLCBpbiB0aGlzIGNhc2UpIGFyZSBkaXN0cmlidXRlZCBhY3Jvc3MgdGhlIGNvbXBvbmVudCBnZW9ncmFwaGljIGFyZWFzIChjZW5zdXMgdHJhY3RzLCBpbiB0aGlzIGNhc2UpIHRoYXQgbWFrZSB1cCBhIGxhcmdlciBhcmVhIChjb3VudGllcywgaW4gdGhpcyBjYXNlKS4gVGhlIGluZGV4IHNjb3JlIGNhbiBiZSBpbnRlcnByZXRlZCBhcyB0aGUgcGVyY2VudGFnZSBvZiBlaXRoZXIgYmxhY2sgb3Igd2hpdGUgcmVzaWRlbnRzIHRoYXQgd291bGQgaGF2ZSB0byBtb3ZlIHRvIGRpZmZlcmVudCBnZW9ncmFwaGljIGFyZWFzIGluIG9yZGVyIHRvIHByb2R1Y2UgYSBkaXN0cmlidXRpb24gdGhhdCBtYXRjaGVzIHRoYXQgb2YgdGhlIGxhcmdlciBhcmVhLiINCg0KYGBge3J9DQojc2V0d2QoImNyZWF0ZURhdGEiKQ0Kc2VnIDwtIHJlYWRyOjpyZWFkX2NzdigiY3JlYXRlRGF0YS9zZWdyZWdhdGlvbl9jb3VudHloZWFsdGguY3N2IikgJT4lIA0KICBncm91cF9ieShmaXBzKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoLVN0YXRlLCAtQ291bnR5LCAteWVhciwgLVgxKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYWxsKG1lYW4sIG5hLnJtPVQpICU+JSANCiAgIGRwbHlyOjpyZW5hbWUoRklQUz1maXBzKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgRklQUyA9IHJlcGxhY2UoRklQUywgd2hpY2goRklQUyAlaW4lIG55RmlwcyksICJgMzYwNjEiKQ0KICApICU+JSANCiAgICBncm91cF9ieShGSVBTKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYWxsKG1lZGlhbiwgbmEucm09VCkNCg0KYGBgDQoNCg0KDQoNCiNWSS4gQkxTIERhdGEgLSBFbXBsb3ltZW50ICgyMDExLTIwMTUgYXZlcmFnZSkNCg0KRW1wbG95bWVudCBkYXRhIGFyZSBkZXJpdmVkIGZyb20gdGhlIEJ1cmVhdSBvZiBMYWJvciBTdGF0aXN0aWNzLCAiTGFib3IgRm9yY2UgRGF0YSBieSBDb3VudHksIDIwMTUgQW5udWFsIEF2ZXJhZ2VzIi4gIFRoZSBMb2NhbCBBcmVhIFVuZW1wbG95bWVudCBTdGF0aXN0aWNzIChMQVVTKSBhcmUgcHJvdmlkZWQgYXQ6ICAgYXZlcmFnZXMNCmh0dHBzOi8vd3d3LmJscy5nb3YvbGF1LyN0YWJsZXMNClNwZWNpZmljYWxseSwgSSBkb3dubG9hZGVkIHRoZSBhZ2dyZWdhdGVkIHRoZSBmb2xsb3dpbmcgZXhjZWwgZmlsZXM6DQogIA0KICAxLiBMYWJvciBmb3JjZSBkYXRhIGJ5IGNvdW50eSwgMjAxNSBhbm51YWwgYXZlcmFnZXMgIGh0dHBzOi8vd3d3LmJscy5nb3YvbGF1L2xhdWNudHkxNS54bHN4DQogIA0KICAyLiBMYWJvciBmb3JjZSBkYXRhIGJ5IGNvdW50eSwgMjAxNCBhbm51YWwgYXZlcmFnZXMgIGh0dHBzOi8vd3d3LmJscy5nb3YvbGF1L2xhdWNudHkxNC54bHN4DQogIA0KICAzLiBMYWJvciBmb3JjZSBkYXRhIGJ5IGNvdW50eSwgMjAxMyBhbm51YWwgYXZlcmFnZXMgIGh0dHBzOi8vd3d3LmJscy5nb3YvbGF1L2xhdWNudHkxMy54bHN4DQogIA0KICA0LiBMYWJvciBmb3JjZSBkYXRhIGJ5IGNvdW50eSwgMjAxMiBhbm51YWwgYXZlcmFnZXMgIGh0dHBzOi8vd3d3LmJscy5nb3YvbGF1L2xhdWNudHkxMi54bHN4DQogIA0KICA1LiBMYWJvciBmb3JjZSBkYXRhIGJ5IGNvdW50eSwgMjAxMSBhbm51YWwgYXZlcmFnZXMgIGh0dHBzOi8vd3d3LmJscy5nb3YvbGF1L2xhdWNudHkxMS54bHN4DQogDQoNCmBgYHtyfQ0KI3NldHdkKCJjcmVhdGVEYXRhIikNCm55RmlwcyA8LSBjKCJgMzYwNjEiLCAiYDM2MDQ3IiwgImAzNjA4MSIsICJgMzYwMDUiLCAiYDM2MDg1IikNCmJsc1ZhcnMgPC0gYygibGFib3JGb3JjZSIsICJlbXBsb3llZCIsICJ1bmVtcGxveWVkIiwgInVuZW1wbG95bWVudFJhdGUiKQ0KDQpibHMgPC0gcmVhZF9jc3YoImNyZWF0ZURhdGEvYmxzRGF0YV8yMDExXzIwMTUuY3N2IikgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIHN0YXRlQ29kZSA9IHBhc3RlMCgiYCIsIHN0YXRlQ29kZSksDQogICAgZmlwcyA9IHBhc3RlMChzdGF0ZUNvZGUsIGNvdW50eUNvZGUpLA0KICAgIGZpcHMgPSByZXBsYWNlKGZpcHMsIHdoaWNoKGZpcHMgJWluJSBueUZpcHMpLCAiYDM2MDYxIikNCiAgKSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShmaXBzLCB5ZWFyKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYWxsKG1lZGlhbiwgbmEucm09VCkgJT4lICMjbmVjZXNzYXJ5IHRvIHJlbW92ZSBleHRyYSBOWUMgDQogIGRwbHlyOjpzZWxlY3QoLWNvdW50eU5hbWUsIC1zdGF0ZUNvZGUsIC1jb3VudHlDb2RlKSAlPiUgDQpkcGx5cjo6Z3JvdXBfYnkoeWVhciwgZmlwcykgJT4lIA0KICBtdXRhdGVfYWxsKHN1bSwgbmEucm09VCkgJT4lICAjI2FnZ3JlZ2F0aW5nIE5ZQw0KICBtdXRhdGUodW5lbXBsb3ltZW50UmF0ZSA9IHVuZW1wbG95ZWQvbGFib3JGb3JjZSkgJT4lIA0KZHBseXI6Omdyb3VwX2J5KGZpcHMpICU+JSANCiAgbXV0YXRlX2F0KGJsc1ZhcnMsIGZ1bnMoIjV5ciIgPSBtZWFuKC4sIG5hLnJtPVQpKSkgJT4lIA0KICBtdXRhdGVfYXQoYmxzVmFycyxmdW5zKCJjaGFuZ2UiID0gbWVhbigoLlt3aGljaCh5ZWFyPT0yMDE1KV0gLSAuW3doaWNoKHllYXI9PTIwMTEpXSkgLyAuW3doaWNoKHllYXI9PTIwMTEpXSwgbmEucm09VCkpKSAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoeWVhcj09MjAxNSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC15ZWFyKSAlPiUgDQogIGRwbHlyOjpyZW5hbWUoRklQUz1maXBzKQ0KDQoNCg0KYGBgDQoNCg0KI1ZJSS4gIFBPTElDRSBEQVRBIChMRU1BUykNCg0KTGF3IEVuZm9yY2VtZW50IE1hbmFnZW1lbnQgYW5kIEFkbWluaXN0cmF0aXZlIFN0YXRpc3RpY3MgKExFTUFTKSBTZXJpZXMgZnJvbSBJQ1BTUiAoMjAxMykuDQpodHRwczovL3d3dy5pY3Bzci51bWljaC5lZHUvaWNwc3J3ZWIvSUNQU1Ivc3R1ZGllcy8zNjE2NA0KDQpgYGB7cn0NCiMgTGF3IEVuZm9yY2VtZW50IEFnZW5jeSBJbmRlbnRpZmllcnMgQ3Jvc3N3YWxrLCAyMDEyIChJQ1BTUiAzNTE1OCkNCiMgaHR0cHM6Ly93d3cuaWNwc3IudW1pY2guZWR1L2ljcHNyd2ViL0lDUFNSL3N0dWRpZXMvMzUxNTgNCg0KbnlGaXBzIDwtIGMoIjM2MDYxIiwgIjM2MDQ3IiwgIjM2MDgxIiwgIjM2MDA1IiwgIjM2MDg1IikNCg0KI3NldHdkKCJjcmVhdGVEYXRhIikNCnVjcl9nZW8gPC0gIHJlYWRfdHN2KCJjcmVhdGVEYXRhLzM1MTU4LTAwMDEtRGF0YS50c3YiKSAlPiUgDQpkcGx5cjo6c2VsZWN0KE9SSTcsIEZJUFMgKQ0KDQoNCnBvbGljZSA8LSBoYXZlbjo6cmVhZF9zdGF0YSgiY3JlYXRlRGF0YS8zNjE2NC0wMDAxLURhdGEuZHRhIikgJT4lIA0KICBkcGx5cjo6c2VsZWN0KA0KICAgICAgICAgICAgICAgIE9SSTcsIA0KICAgICAgICAgICAgICAgIFNUQVRFQ09ERSwgDQogICAgICAgICAgICAgICAgUEVSU19SRVNQX1BBVFJMLCAjcHJpbWFyeSBkdXR5IC0gcGF0cm9sDQogICAgICAgICAgICAgICAgUEVSU19SRVNQX0lOVlNULCAjcHJpbWFyeSBkdXR5IC0gaW52ZXN0aWdhdGl2ZQ0KICAgICAgICAgICAgICAgIFBFUlNfUERTV19GRlQsICNOVU1CRVIgT0YgRkVNQUxFIFNXT1JOIFBFUlNPTk5FTCAtIGZ1bGx0aW1lDQogICAgICAgICAgICAgICAgRlRTV09STiwgICNUT1RBTCBOVU1CRVIgT0YgU1dPUk4gUEVSU09OTkVMIC0gZnVsbHRpbWUNCiAgICAgICAgICAgICAgICBQRVJTX0ZUU19CTEssICNUT1RBTCBOVU1CRVIgT0YgU1dPUk4gUEVSU09OTkVMIC0gZnVsbHRpbWUgLSBCbGFjaw0KICAgICAgICAgICAgICAgIENPTV9NSVMsICNDT01NVU5JVFkgUE9MSUNJTkcgQ09NUE9ORU5UIElOIE1JU1NJT04gU1RBVEVNRU5UDQogICAgICAgICAgICAgICAgIyMgMSA9IE5vIHdyaXR0ZW4gbWlzc2lvbiBzdGF0ZW1lbnQNCiAgICAgICAgICAgICAgICAjIyAyID0gV3JpdHRlbiBzdGF0ZW1lbnQsIG5vIGNvbW11bml0eSBwb2xpY2luZyBjb21wb25lbnQNCiAgICAgICAgICAgICAgICAjIyAzID0gV3JpdHRlbiBzdGF0ZW1lbnQsIHllcyBjb21tdW5pdHkgcG9saWNpbmcgY29tcG9uZW50DQogICAgICAgICAgICAgICAgVEVDSF9UWVBfR1VOICNHdW5zaG90IGRldGVjdGlvbiBzeXN0ZW0sIDEgPSBZZXMgKDglKSwgMiA9IE5PLg0KICAgICAgICAgICAgICAgICNGSU5BTFdUICNGSU5BTCBXRUlHSFQgRk9SIEVBQ0ggU1RSQVRVTQ0KICAgICAgICAgICAgICAgICkgJT4lIA0KICBkcGx5cjo6cmVuYW1lKA0KICAgIFN0YXRlPVNUQVRFQ09ERSwNCiAgICBwb2xpY2VGdWxsVGltZSA9IEZUU1dPUk4sDQogICAgcG9saWNlRmVtYWxlID0gUEVSU19QRFNXX0ZGVCwNCiAgICBwb2xpY2VCbGFjayA9IFBFUlNfRlRTX0JMSywNCiAgICBwb2xpY2VQYXRyb2w9UEVSU19SRVNQX1BBVFJMLCANCiAgICBwb2xpY2VJbnZlc3RpZ2F0ZT1QRVJTX1JFU1BfSU5WU1QsDQogICAgY29tbXVuaXR5UG9saWNlPUNPTV9NSVMsDQogICAgZ3VuU2hvdERldGVjdGlvbj1URUNIX1RZUF9HVU4pICU+JSANCiAgZHBseXI6OmxlZnRfam9pbih1Y3JfZ2VvKSAlPiUgDQogIG11dGF0ZV9hbGwoZnVucyhyZXBsYWNlKC4sIGlzLm5hbiguKSwgTkEpKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKA0KICAgIEZJUFMgPSByZXBsYWNlKEZJUFMsIHdoaWNoKEZJUFMgJWluJSBueUZpcHMpLCAiMzYwNjEiKSwgIyMjTllDIGFnZ3JlZ2F0aW9uDQogICAgY29tbXVuaXR5UG9saWNlPXJlcGxhY2UoY29tbXVuaXR5UG9saWNlLCB3aGljaChjb21tdW5pdHlQb2xpY2U9PTMpLCBUUlVFKSwNCiAgICBjb21tdW5pdHlQb2xpY2U9cmVwbGFjZShjb21tdW5pdHlQb2xpY2UsIHdoaWNoKGNvbW11bml0eVBvbGljZSAhPSAzKSwgRkFMU0UpLA0KICAgIGd1blNob3REZXRlY3Rpb249cmVwbGFjZShndW5TaG90RGV0ZWN0aW9uLCB3aGljaChndW5TaG90RGV0ZWN0aW9uID09IDEpLCBUUlVFKSwNCiAgICBndW5TaG90RGV0ZWN0aW9uPXJlcGxhY2UoZ3VuU2hvdERldGVjdGlvbiwgd2hpY2goZ3VuU2hvdERldGVjdGlvbiA9PSAyKSwgRkFMU0UpDQogICkgJT4lIA0KICBncm91cF9ieShTdGF0ZSwgRklQUykgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIHBvbGljZVBhdHJvbD1zdW0ocG9saWNlUGF0cm9sLCBuYS5ybT1UKSwNCiAgICBwb2xpY2VJbnZlc3RpZ2F0ZT1zdW0ocG9saWNlSW52ZXN0aWdhdGUsIG5hLnJtPVQpLA0KICAgIGNvbW11bml0eVBvbGljZT1tZWFuKGNvbW11bml0eVBvbGljZSwgbmEucm09VCksDQogICAgZ3VuU2hvdERldGVjdGlvbj1tZWFuKGd1blNob3REZXRlY3Rpb24sIG5hLnJtPVQpLA0KICAgIHBvbGljZUZ1bGxUaW1lPXN1bShwb2xpY2VGdWxsVGltZSwgbmEucm09VCksDQogICAgcG9saWNlRmVtYWxlPXN1bShwb2xpY2VGZW1hbGUsIG5hLnJtPVQpLA0KICAgIHBvbGljZUJsYWNrPXN1bShwb2xpY2VCbGFjaywgbmEucm09VCkNCiAgKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgcG9saWNlRnVsbFRpbWVfbG9nPWxvZyhwb2xpY2VGdWxsVGltZSksDQogICAgcG9saWNlUHJjbnRCbGFjayA9IDEwMCpwb2xpY2VCbGFjay9wb2xpY2VGdWxsVGltZSwNCiAgICBwb2xpY2VQcmNudEZlbWFsZSA9IDEwMCpwb2xpY2VGZW1hbGUvcG9saWNlRnVsbFRpbWUsDQogICAgcG9saWNlUGF0cm9sX2xvZyA9IGxvZygxK3BvbGljZVBhdHJvbCksDQogICAgcG9saWNlSW52ZXN0aWdhdGVfbG9nID0gbG9nKDErcG9saWNlSW52ZXN0aWdhdGUpDQogICkgJT4lIA0KICBtdXRhdGVfYWxsKCBmdW5zKHJlcGxhY2UoLiwgaXMubmFuKC4pLCBOQSkpKSAlPiUgDQogIG11dGF0ZV9hbGwoIGZ1bnMocmVwbGFjZSguLCBpcy5pbmZpbml0ZSguKSwgTkEpKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShGSVBTKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKEZJUFM9cGFzdGUoImAiLCBhcy5jaGFyYWN0ZXIoRklQUyksIHNlcD0iIikpICU+JSANCiAgZHBseXI6OnNlbGVjdCgtU3RhdGUpDQogIA0KDQojZnN0Ojp3cml0ZS5mc3QocG9saWNlLCBwYXRoPSJwb2xpY2UuY3N2IikNCg0KDQpgYGANCg0KI1ZJSUkuIExhbmQgQXJlYSAoQ2Vuc3VzKQ0KTGFuZCBBcmVhIGVzdGltYXRlcyBmcm9tOg0KaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9zdXBwb3J0L1VTQUNkYXRhRG93bmxvYWRzLmh0bWwNCg0KJ0xhbmQgQXJlYScgZmlsZSAiTE5EMDEueGxzIi4gIA0KVmFyaWFibGU6ICBMTkQxMTAyMTBELCAiTGFuZCBhcmVhIGluIHNxdWFyZSBtaWxlcyAyMDEwIiANCg0KDQpgYGB7cn0NCg0KbnlGaXBzIDwtIGMoImAzNjA2MSIsICJgMzYwNDciLCAiYDM2MDgxIiwgImAzNjAwNSIsICJgMzYwODUiKQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KDQphcmVhIDwtIHJlYWRyOjpyZWFkX2NzdigiY3JlYXRlRGF0YS9MTkQwMS5jc3YiKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoQXJlYW5hbWUsIFNUQ09VLCBMTkQxMTAyMTBEKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgc3RhdGVDb2RlID0gc3Vic3RyKFNUQ09VLCBzdGFydD0zLCBzdG9wPTUpDQogICkgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKHN0YXRlQ29kZSAhPSAiMDAwIikgJT4lICAgIyNnZXR0aW5nIHJpZCBvZiBzdGF0ZSB0b3RhbHMNCiAgZHBseXI6OnRyYW5zbXV0ZSgNCiAgICBGSVBTID0gcGFzdGUwKCJgIiwgU1RDT1UpLA0KICAgIGxhbmRBcmVhID0gTE5EMTEwMjEwRA0KICApICU+JSANCiAgZHBseXI6OmZpbHRlcihsYW5kQXJlYSA+IDApICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBGSVBTID0gcmVwbGFjZShGSVBTLCB3aGljaChGSVBTICVpbiUgbnlGaXBzKSwgImAzNjA2MSIpDQogICkgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoRklQUykgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIGxhbmRBcmVhID0gc3VtKGxhbmRBcmVhLCBuYS5ybT1UUlVFKQ0KICApDQojI2VsaW1pbmF0aW5nIDMgY2FzZXMgdGhhdCBhcmVuJ3QgaW4gdGhlIG90aGVyIGRhdGEgZmlsZXMgd2l0aCBzaXplIDANCiNZZWxsb3dzdG9uZSBOYXRpb25hbCBQYXJrLCBNVCwgYDMwMTEzDQojQ2xpZnRvbiBGb3JnZSwgVkEsIGA1MTU2MCAlPiUgDQojU291dGggQm9zdG9uLCBWQSwgYDUxNzgwDQoNCg0KYGBgDQoNCg0KDQojSVguICBDb21iaW5lIGFsbCBWYXJpYWJsZXMNCg0KDQpgYGB7cn0NCmlmKGV4aXN0cygiVUNSRGF0YSIpPT1GQUxTRSl7DQogIFVDUkRhdGEgPC0gZnN0OjpyZWFkLmZzdCgiY3JlYXRlRGF0YS9VQ1JEYXRhLmNzdiIpDQp9DQoNCmNvdW50eVZhcnMgPC0gY2Vuc3VzX3ZhcnMgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKHNlZGEpICU+JQ0KICBkcGx5cjo6bGVmdF9qb2luKHBvbGljZSkgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKGFyZWEpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihibHMpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihpbmNfZGYpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihwb3YpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihnaW5pKSAlPiUgDQogIGRwbHlyOjpsZWZ0X2pvaW4oc2luZ2xlUGFyZW50KSAlPiUgDQogIGRwbHlyOjpsZWZ0X2pvaW4oaHMpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihjcm93ZCkgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKHNlZykgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKFVDUkRhdGEpDQogIA0KZnN0Ojp3cml0ZS5mc3QoY291bnR5VmFycywgcGF0aD0iY291bnR5VmFyc19mLmNzdiIpDQp3cml0ZS5jc3YoY291bnR5VmFycywgZmlsZT0iY291bnR5VmFycy5jc3YiKQ0KICANCmBgYA0KDQoNCg0KI1guICBQcmluY2lwbGUgQ29tcG9uZW50cyANCiMjMS4gIENSSU1FDQpgYGB7cn0NCmlmKGV4aXN0cygiY291bnR5VmFycyIpPT1UUlVFKXsNCiAgY291bnR5VmFycyA8LSBjb3VudHlWYXJzDQp9IGVsc2Ugew0KICBjb3VudHlWYXJzIDwtIGZzdDo6cmVhZC5mc3QoIkRhdGEvY291bnR5VmFyc19mLmNzdiIpDQp9IA0KIyN2YXJzIDwtIGZzdDo6cmVhZC5mc3QoImNvdW50eVZhcnMuY3N2IikNCg0KdG90YWxDcmltZSA8LSBjb3VudHlWYXJzWyxjKCJGSVBTIiwgIm11cmRlcl9yXzV5ciIsICJkdWlfcl81eXIiLCAidmNfcl81eXIiLCAidGhlZnRfcl81eXIiLCAidmFuZGFsX3JfNXlyIiwgImRydWdzX3JfNXlyIildDQp0b3RhbENyaW1lIDwtIHRvdGFsQ3JpbWVbY29tcGxldGUuY2FzZXModG90YWxDcmltZSksXSANCg0KcGNfY3JpbWUgPC0gIHByY29tcCh+IG11cmRlcl9yXzV5ciArIHZjX3JfNXlyICsgZHVpX3JfNXlyICArIHZhbmRhbF9yXzV5ciArIHRoZWZ0X3JfNXlyICsgZHJ1Z3Nfcl81eXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE9dG90YWxDcmltZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS4gPSBULCBjZW50ZXI9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5hY3Rpb249bmEub21pdCkNCg0KdG90YWxDcmltZSRwYzFDcmltZSA8LSBwY19jcmltZSR4WywxXQ0KdG90YWxDcmltZSRwYzJDcmltZSA8LSBwY19jcmltZSR4WywyXQ0KdG90YWxDcmltZSA8LSB0b3RhbENyaW1lWyxjKCJGSVBTIiwgInBjMUNyaW1lIiwgInBjMkNyaW1lIildDQoNCmNvdW50eVZhcnMgPC0gZHBseXI6OmxlZnRfam9pbihjb3VudHlWYXJzLCB0b3RhbENyaW1lKQ0KDQoNCg0KIyNwcmludCBQQ0EgYW5hbHlzaXMgZnJvbSBGYWN0b01pbmVSDQoNCnBjRml0IDwtIEZhY3RvTWluZVI6OlBDQShjb3VudHlWYXJzWyxjKCJtdXJkZXJfcl81eXIiLCAgImR1aV9yXzV5ciIsICJ2Y19yXzV5ciIsICJ0aGVmdF9yXzV5ciIsICJ2YW5kYWxfcl81eXIiLCAiZHJ1Z3Nfcl81eXIiKV0pDQpzdW1tYXJ5KHBjRml0KQ0KDQpgYGANCg0KDQojIzIuICBDcmltZSAtIFZpb2xlbnQgQ3JpbWUsIFRoZWZ0LCBWYW5kYWxpc20gb25seQ0KYGBge3J9DQoNCmlmKGV4aXN0cygiY291bnR5VmFycyIpPT1UUlVFKXsNCiAgY291bnR5VmFycyA8LSBjb3VudHlWYXJzDQp9IGVsc2Ugew0KICBjb3VudHlWYXJzIDwtIGZzdDo6cmVhZC5mc3QoIkRhdGEvY291bnR5VmFyc19mLmNzdiIpDQp9IA0KDQp2Q3JpbWUgPC0gY291bnR5VmFyc1ssYygiRklQUyIsICJ2Y19yXzV5ciIsICJ0aGVmdF9yXzV5ciIsICJ2YW5kYWxfcl81eXIiKV0NCnZDcmltZSA8LSB2Q3JpbWVbY29tcGxldGUuY2FzZXModkNyaW1lKSxdIA0KDQpwY19jcmltZSA8LSAgcHJjb21wKH4gIHZjX3JfNXlyICsgIHZhbmRhbF9yXzV5ciArIHRoZWZ0X3JfNXlyICwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT12Q3JpbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGUuID0gVCwgY2VudGVyPVRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEuYWN0aW9uPW5hLm9taXQpDQoNCnZDcmltZSRwYzFDcmltZV8zIDwtIHBjX2NyaW1lJHhbLDFdDQp2Q3JpbWUkcGMyQ3JpbWVfMyA8LSBwY19jcmltZSR4WywyXQ0KdkNyaW1lIDwtIHZDcmltZVssYygiRklQUyIsICJwYzFDcmltZV8zIiwgInBjMkNyaW1lXzMiKV0NCg0KY291bnR5VmFycyA8LSBkcGx5cjo6bGVmdF9qb2luKGNvdW50eVZhcnMsIHZDcmltZSkNCg0KDQoNCiMjcHJpbnQgUENBIGFuYWx5c2lzIGZyb20gRmFjdG9NaW5lUg0KDQpwY0ZpdCA8LSBGYWN0b01pbmVSOjpQQ0EoY291bnR5VmFyc1ssYygidmNfcl81eXIiLCAidGhlZnRfcl81eXIiLCAidmFuZGFsX3JfNXlyIildKQ0Kc3VtbWFyeShwY0ZpdCkNCg0KDQpgYGANCg0KIyMzLiAgU0VTDQpgYGB7cn0NCg0KaWYoZXhpc3RzKCJjb3VudHlWYXJzIik9PVRSVUUpew0KICBjb3VudHlWYXJzIDwtIGNvdW50eVZhcnMNCn0gZWxzZSB7DQogIGNvdW50eVZhcnMgPC0gZnN0OjpyZWFkLmZzdCgiRGF0YS9jb3VudHlWYXJzX2YuY3N2IikNCn0gDQoNCg0KdG90YWxTRVMgPC0gY291bnR5VmFyc1ssYygiRklQUyIsICJwb3ZlcnR5IiwgInNpbmdsZVBhcmVudCIsICJtZWRpYW5JbmNvbWUiLCAidW5lbXBsb3ltZW50UmF0ZV81eXIiKV0NCnRvdGFsU0VTIDwtIHRvdGFsU0VTW2NvbXBsZXRlLmNhc2VzKHRvdGFsU0VTKSxdIA0KDQpwY19zZXMgPC0gIHByY29tcCh+IHBvdmVydHkgKyBzaW5nbGVQYXJlbnQgKyBtZWRpYW5JbmNvbWUgKyB1bmVtcGxveW1lbnRSYXRlXzV5ciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT10b3RhbFNFUywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS4gPSBULCBjZW50ZXI9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5hY3Rpb249bmEub21pdCkNCg0KdG90YWxTRVMkcGMxU0VTIDwtIHBjX3NlcyR4WywxXQ0KdG90YWxTRVMkcGMyU0VTIDwtIHBjX3NlcyR4WywyXQ0KdG90YWxTRVMgPC0gdG90YWxTRVNbLGMoIkZJUFMiLCAicGMxU0VTIiwgInBjMlNFUyIpXQ0KDQpjb3VudHlWYXJzIDwtIGRwbHlyOjpsZWZ0X2pvaW4oY291bnR5VmFycywgdG90YWxTRVMpDQoNCg0KDQojI3ByaW50IFBDQSBhbmFseXNpcyBmcm9tIEZhY3RvTWluZVINCg0KcGNGaXQgPC0gRmFjdG9NaW5lUjo6UENBKGNvdW50eVZhcnNbLGMoInBvdmVydHkiLCAic2luZ2xlUGFyZW50IiwgIm1lZGlhbkluY29tZSIsICJ1bmVtcGxveW1lbnRSYXRlXzV5ciIpXSkNCnN1bW1hcnkocGNGaXQpDQoNCmZzdDo6d3JpdGUuZnN0KGNvdW50eVZhcnMsIHBhdGg9ImNvdW50eVZhcnNfZi5jc3YiKQ0Kd3JpdGUuY3N2KGNvdW50eVZhcnMsIGZpbGU9ImNvdW50eVZhcnMuY3N2IikNCmBgYA0KDQoNCg0KDQojWEkuICBBZGQgdG8gUG9saWNlIEtpbGxpbmcgVmFyaWFibGVzDQojIzEuIFJlbG9hZCBQb2xpY2UgS2lsbGluZyBEYXRhIChzYXZlZCBhYm92ZSkNCmBgYHtyfQ0Kd2FwbyA8LSBmc3Q6OnJlYWQuZnN0KCJkZl93YXBvX2ZzdC5jc3YiKSAlPiUgDQogICAgZHBseXI6Om11dGF0ZSgNCiAgICBTdGF0ZT1zdGF0ZSwNCiAgICBkYXRlID0gYXMuRGF0ZShkYXRlLCBmb3JtYXQ9ICIlWS0lbS0lZCIpLA0KICAgIGFnZSA9IGFzLm51bWVyaWMoYWdlKSwNCiAgICBnZW5kZXI9IGZhY3RvcihnZW5kZXIsIGxldmVscz1jKCJNYWxlIiwgIkZlbWFsZSIpKQ0KICApDQoNCmxvdHQgPC0gZnN0OjpyZWFkLmZzdCgiZGZfbG90dF9mc3QuY3N2IikgDQoNCmBgYA0KDQojIzIuIFdhc2hpbmd0b24gUG9zdA0KYGBge3J9DQp3YXBvX2MgPC0gd2FwbyAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKEZJUFMpLCB5ZWFyIDwgMjAxNykgJT4lIA0KICBncm91cF9ieShkYXRhU291cmNlLCBGSVBTKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgU3RhdGU9Zmlyc3QoU3RhdGUpLCANCiAgICBraWxsZWQgPSBuKCksIA0KICAgIGtpbGxlZC51bmFybWVkID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiKSksDQogICAga2lsbGVkLm5vYXR0YWNrID0gbGVuZ3RoKHdoaWNoKHRocmVhdF9sZXZlbD09Im90aGVyIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUgPSBsZW5ndGgod2hpY2goZmxlZT09Ik5vdCBmbGVlaW5nIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrID0ga2lsbGVkLnVuYXJtZWQgKyBraWxsZWQubm9hdHRhY2ssDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlID0ga2lsbGVkLnVuYXJtZWQgKyBraWxsZWQubm9hdHRhY2sgKyBraWxsZWQubm9mbGVlLA0KICAgIA0KICAgICMjTWFsZXMNCiAgICBraWxsZWQubWFsZSA9IGxlbmd0aCh3aGljaChnZW5kZXI9PSJNYWxlIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5tYWxlID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgZ2VuZGVyPT0iTWFsZSIpKSwNCiAgICBraWxsZWQubm9hdHRhY2subWFsZSA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBnZW5kZXI9PSJNYWxlIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUubWFsZSA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgZ2VuZGVyPT0iTWFsZSIpKSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFjay5tYWxlID0ga2lsbGVkLnVuYXJtZWQubWFsZSArIGtpbGxlZC5ub2F0dGFjay5tYWxlLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrX25vZmxlZS5tYWxlID0ga2lsbGVkLnVuYXJtZWQubWFsZSArIGtpbGxlZC5ub2F0dGFjay5tYWxlICsga2lsbGVkLm5vZmxlZS5tYWxlLA0KICAgIA0KICAgICMjRmVtYWxlcw0KICAgIGtpbGxlZC5mZW1hbGUgPSBsZW5ndGgod2hpY2goZ2VuZGVyPT0iRmVtYWxlIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5mZW1hbGUgPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBnZW5kZXI9PSJGZW1hbGUiKSksDQogICAga2lsbGVkLm5vYXR0YWNrLmZlbWFsZSA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBnZW5kZXI9PSJGZW1hbGUiKSksDQogICAga2lsbGVkLm5vZmxlZS5mZW1hbGUgPSBsZW5ndGgod2hpY2goZmxlZT09Ik5vdCBmbGVlaW5nIiAmIGdlbmRlcj09IkZlbWFsZSIpKSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFjay5mZW1hbGUgPSBraWxsZWQudW5hcm1lZC5mZW1hbGUgKyBraWxsZWQubm9hdHRhY2suZmVtYWxlLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrX25vZmxlZS5mZW1hbGUgPSBraWxsZWQudW5hcm1lZC5mZW1hbGUgKyBraWxsZWQubm9hdHRhY2suZmVtYWxlICsga2lsbGVkLm5vZmxlZS5mZW1hbGUsDQogICAgDQogICAgIyNXaGl0ZSBOb25IaXNwYW5pYw0KICAgIGtpbGxlZC53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaChSYWNlPT0iV2hpdGUiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLndoaXRlX25oID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgUmFjZT09IldoaXRlIikpLA0KICAgIGtpbGxlZC5ub2F0dGFjay53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBSYWNlPT0iV2hpdGUiKSksDQogICAga2lsbGVkLm5vZmxlZS53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgUmFjZT09IldoaXRlIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLndoaXRlX25oID0ga2lsbGVkLnVuYXJtZWQud2hpdGVfbmggKyBraWxsZWQubm9hdHRhY2sud2hpdGVfbmgsDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlLndoaXRlX25oID0ga2lsbGVkLnVuYXJtZWQud2hpdGVfbmggKyBraWxsZWQubm9hdHRhY2sud2hpdGVfbmggKyBraWxsZWQubm9mbGVlLndoaXRlX25oLA0KICAgIA0KICAgICMjQmxhY2sNCiAgICBraWxsZWQuYmxhY2sgPSBsZW5ndGgod2hpY2goUmFjZT09IkJsYWNrIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5ibGFjayA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIFJhY2U9PSJCbGFjayIpKSwNCiAgICBraWxsZWQubm9hdHRhY2suYmxhY2sgPSBsZW5ndGgod2hpY2godGhyZWF0X2xldmVsPT0ib3RoZXIiICYgUmFjZT09IkJsYWNrIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUuYmxhY2sgPSBsZW5ndGgod2hpY2goZmxlZT09Ik5vdCBmbGVlaW5nIiAmIFJhY2U9PSJCbGFjayIpKSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFjay5ibGFjayA9IGtpbGxlZC51bmFybWVkLmJsYWNrICsga2lsbGVkLm5vYXR0YWNrLmJsYWNrLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrX25vZmxlZS5ibGFjayA9IGtpbGxlZC51bmFybWVkLmJsYWNrICsga2lsbGVkLm5vYXR0YWNrLmJsYWNrICsga2lsbGVkLm5vZmxlZS5ibGFjaywNCiAgICANCiAgICAjSGlzcGFuaWMNCiAgICBraWxsZWQuaGlzcCA9IGxlbmd0aCh3aGljaChSYWNlPT0iSGlzcGFuaWMiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmhpc3AgPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iSGlzcGFuaWMiKSksDQogICAga2lsbGVkLm5vYXR0YWNrLmhpc3AgPSBsZW5ndGgod2hpY2godGhyZWF0X2xldmVsPT0ib3RoZXIiICYgUmFjZT09Ikhpc3BhbmljIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUuaGlzcCA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgUmFjZT09Ikhpc3BhbmljIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLmhpc3AgPSBraWxsZWQudW5hcm1lZC5oaXNwICsga2lsbGVkLm5vYXR0YWNrLmhpc3AsDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlLmhpc3AgPSBraWxsZWQudW5hcm1lZC5oaXNwICsga2lsbGVkLm5vYXR0YWNrLmhpc3AgKyBraWxsZWQubm9mbGVlLmhpc3AsDQogICAgDQogICAgDQogICAgIyNXaGl0ZSArIEhpc3BhbmljIGNhdGVnb3J5IC0gbWF0Y2hlcyBVQ1INCiAgICBraWxsZWQud2hpdGUgPSBsZW5ndGgod2hpY2goUmFjZT09IldoaXRlIiB8IFJhY2UgPT0gIkhpc3BhbmljIikpLCANCiAgICBraWxsZWQudW5hcm1lZC53aGl0ZSA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIChSYWNlPT0iV2hpdGUiIHwgUmFjZSA9PSAiSGlzcGFuaWMiKSkpLA0KICAgIGtpbGxlZC5ub2F0dGFjay53aGl0ZSA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiAoUmFjZT09IldoaXRlIiB8IFJhY2UgPT0gIkhpc3BhbmljIikgKSksDQogICAga2lsbGVkLm5vZmxlZS53aGl0ZSA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgKFJhY2U9PSJXaGl0ZSIgfCBSYWNlID09ICJIaXNwYW5pYyIpICAgKSksDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2sud2hpdGUgPSBraWxsZWQudW5hcm1lZC53aGl0ZSArIGtpbGxlZC5ub2F0dGFjay53aGl0ZSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFja19ub2ZsZWUud2hpdGUgPSBraWxsZWQudW5hcm1lZC53aGl0ZSArIGtpbGxlZC5ub2F0dGFjay53aGl0ZSArIGtpbGxlZC5ub2ZsZWUud2hpdGUsDQogICAgDQogICAgDQogICAgI0FzaWFuDQogICAga2lsbGVkLmFzaWFuID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJBc2lhbiIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQuYXNpYW4gPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iQXNpYW4iKSksDQogICAga2lsbGVkLm5vYXR0YWNrLmFzaWFuID0gbGVuZ3RoKHdoaWNoKHRocmVhdF9sZXZlbD09Im90aGVyIiAmIFJhY2U9PSJBc2lhbiIpKSwNCiAgICBraWxsZWQubm9mbGVlLmFzaWFuID0gbGVuZ3RoKHdoaWNoKGZsZWU9PSJOb3QgZmxlZWluZyIgJiBSYWNlPT0iQXNpYW4iKSksDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2suYXNpYW4gPSBraWxsZWQudW5hcm1lZC5hc2lhbiArIGtpbGxlZC5ub2F0dGFjay5hc2lhbiwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFja19ub2ZsZWUuYXNpYW4gPSBraWxsZWQudW5hcm1lZC5hc2lhbiArIGtpbGxlZC5ub2F0dGFjay5hc2lhbiArIGtpbGxlZC5ub2ZsZWUuYXNpYW4sDQogICAgDQogICAgI05hdGl2ZSBBbWVyaWNhbg0KICAgIGtpbGxlZC5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmFtZXJpbmRpYW4gPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLA0KICAgIGtpbGxlZC5ub2F0dGFjay5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKHRocmVhdF9sZXZlbD09Im90aGVyIiAmIFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKSksDQogICAga2lsbGVkLm5vZmxlZS5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKGZsZWU9PSJOb3QgZmxlZWluZyIgJiBSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLmFtZXJpbmRpYW4gPSBraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuICsga2lsbGVkLm5vYXR0YWNrLmFtZXJpbmRpYW4sDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlLmFtZXJpbmRpYW4gPSBraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuICsga2lsbGVkLm5vYXR0YWNrLmFtZXJpbmRpYW4gKyBraWxsZWQubm9mbGVlLmFtZXJpbmRpYW4NCiAgICAgICAgICAgICkgDQoNCiMjUmVwZWF0IGZvciBTdGF0ZXMNCndhcG9fc3RhdGUgPC0gd2FwbyAlPiUgDQogIGRwbHlyOjpmaWx0ZXIoIWlzLm5hKFN0YXRlKSwgeWVhciA8IDIwMTcpICU+JSANCiAgZ3JvdXBfYnkoZGF0YVNvdXJjZSwgU3RhdGUpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBraWxsZWQgPSBuKCksIA0KICAgIGtpbGxlZC51bmFybWVkID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiKSksDQogICAga2lsbGVkLm5vYXR0YWNrID0gbGVuZ3RoKHdoaWNoKHRocmVhdF9sZXZlbD09Im90aGVyIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUgPSBsZW5ndGgod2hpY2goZmxlZT09Ik5vdCBmbGVlaW5nIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrID0ga2lsbGVkLnVuYXJtZWQgKyBraWxsZWQubm9hdHRhY2ssDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlID0ga2lsbGVkLnVuYXJtZWQgKyBraWxsZWQubm9hdHRhY2sgKyBraWxsZWQubm9mbGVlLA0KICAgIA0KICAgICMjTWFsZXMNCiAgICBraWxsZWQubWFsZSA9IGxlbmd0aCh3aGljaChnZW5kZXI9PSJNYWxlIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5tYWxlID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgZ2VuZGVyPT0iTWFsZSIpKSwNCiAgICBraWxsZWQubm9hdHRhY2subWFsZSA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBnZW5kZXI9PSJNYWxlIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUubWFsZSA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgZ2VuZGVyPT0iTWFsZSIpKSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFjay5tYWxlID0ga2lsbGVkLnVuYXJtZWQubWFsZSArIGtpbGxlZC5ub2F0dGFjay5tYWxlLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrX25vZmxlZS5tYWxlID0ga2lsbGVkLnVuYXJtZWQubWFsZSArIGtpbGxlZC5ub2F0dGFjay5tYWxlICsga2lsbGVkLm5vZmxlZS5tYWxlLA0KICAgIA0KICAgICMjRmVtYWxlcw0KICAgIGtpbGxlZC5mZW1hbGUgPSBsZW5ndGgod2hpY2goZ2VuZGVyPT0iRmVtYWxlIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5mZW1hbGUgPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBnZW5kZXI9PSJGZW1hbGUiKSksDQogICAga2lsbGVkLm5vYXR0YWNrLmZlbWFsZSA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBnZW5kZXI9PSJGZW1hbGUiKSksDQogICAga2lsbGVkLm5vZmxlZS5mZW1hbGUgPSBsZW5ndGgod2hpY2goZmxlZT09Ik5vdCBmbGVlaW5nIiAmIGdlbmRlcj09IkZlbWFsZSIpKSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFjay5mZW1hbGUgPSBraWxsZWQudW5hcm1lZC5mZW1hbGUgKyBraWxsZWQubm9hdHRhY2suZmVtYWxlLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrX25vZmxlZS5mZW1hbGUgPSBraWxsZWQudW5hcm1lZC5mZW1hbGUgKyBraWxsZWQubm9hdHRhY2suZmVtYWxlICsga2lsbGVkLm5vZmxlZS5mZW1hbGUsDQogICAgDQogICAgIyNXaGl0ZSBOb25IaXNwYW5pYw0KICAgIGtpbGxlZC53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaChSYWNlPT0iV2hpdGUiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLndoaXRlX25oID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgUmFjZT09IldoaXRlIikpLA0KICAgIGtpbGxlZC5ub2F0dGFjay53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBSYWNlPT0iV2hpdGUiKSksDQogICAga2lsbGVkLm5vZmxlZS53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgUmFjZT09IldoaXRlIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLndoaXRlX25oID0ga2lsbGVkLnVuYXJtZWQud2hpdGVfbmggKyBraWxsZWQubm9hdHRhY2sud2hpdGVfbmgsDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlLndoaXRlX25oID0ga2lsbGVkLnVuYXJtZWQud2hpdGVfbmggKyBraWxsZWQubm9hdHRhY2sud2hpdGVfbmggKyBraWxsZWQubm9mbGVlLndoaXRlX25oLA0KICAgIA0KICAgICMjQmxhY2sNCiAgICBraWxsZWQuYmxhY2sgPSBsZW5ndGgod2hpY2goUmFjZT09IkJsYWNrIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5ibGFjayA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIFJhY2U9PSJCbGFjayIpKSwNCiAgICBraWxsZWQubm9hdHRhY2suYmxhY2sgPSBsZW5ndGgod2hpY2godGhyZWF0X2xldmVsPT0ib3RoZXIiICYgUmFjZT09IkJsYWNrIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUuYmxhY2sgPSBsZW5ndGgod2hpY2goZmxlZT09Ik5vdCBmbGVlaW5nIiAmIFJhY2U9PSJCbGFjayIpKSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFjay5ibGFjayA9IGtpbGxlZC51bmFybWVkLmJsYWNrICsga2lsbGVkLm5vYXR0YWNrLmJsYWNrLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrX25vZmxlZS5ibGFjayA9IGtpbGxlZC51bmFybWVkLmJsYWNrICsga2lsbGVkLm5vYXR0YWNrLmJsYWNrICsga2lsbGVkLm5vZmxlZS5ibGFjaywNCiAgICANCiAgICAjSGlzcGFuaWMNCiAgICBraWxsZWQuaGlzcCA9IGxlbmd0aCh3aGljaChSYWNlPT0iSGlzcGFuaWMiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmhpc3AgPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iSGlzcGFuaWMiKSksDQogICAga2lsbGVkLm5vYXR0YWNrLmhpc3AgPSBsZW5ndGgod2hpY2godGhyZWF0X2xldmVsPT0ib3RoZXIiICYgUmFjZT09Ikhpc3BhbmljIikpLA0KICAgIGtpbGxlZC5ub2ZsZWUuaGlzcCA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgUmFjZT09Ikhpc3BhbmljIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLmhpc3AgPSBraWxsZWQudW5hcm1lZC5oaXNwICsga2lsbGVkLm5vYXR0YWNrLmhpc3AsDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlLmhpc3AgPSBraWxsZWQudW5hcm1lZC5oaXNwICsga2lsbGVkLm5vYXR0YWNrLmhpc3AgKyBraWxsZWQubm9mbGVlLmhpc3AsDQogICAgDQogICAgDQogICAgIyNXaGl0ZSArIEhpc3BhbmljIGNhdGVnb3J5IC0gbWF0Y2hlcyBVQ1INCiAgICBraWxsZWQud2hpdGUgPSBsZW5ndGgod2hpY2goUmFjZT09IldoaXRlIiB8IFJhY2UgPT0gIkhpc3BhbmljIikpLCANCiAgICBraWxsZWQudW5hcm1lZC53aGl0ZSA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIChSYWNlPT0iV2hpdGUiIHwgUmFjZSA9PSAiSGlzcGFuaWMiKSkpLA0KICAgIGtpbGxlZC5ub2F0dGFjay53aGl0ZSA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiAoUmFjZT09IldoaXRlIiB8IFJhY2UgPT0gIkhpc3BhbmljIikgKSksDQogICAga2lsbGVkLm5vZmxlZS53aGl0ZSA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgKFJhY2U9PSJXaGl0ZSIgfCBSYWNlID09ICJIaXNwYW5pYyIpICAgKSksDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2sud2hpdGUgPSBraWxsZWQudW5hcm1lZC53aGl0ZSArIGtpbGxlZC5ub2F0dGFjay53aGl0ZSwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFja19ub2ZsZWUud2hpdGUgPSBraWxsZWQudW5hcm1lZC53aGl0ZSArIGtpbGxlZC5ub2F0dGFjay53aGl0ZSArIGtpbGxlZC5ub2ZsZWUud2hpdGUsDQogICAgDQogICAgDQogICAgI0FzaWFuDQogICAga2lsbGVkLmFzaWFuID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJBc2lhbiIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQuYXNpYW4gPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iQXNpYW4iKSksDQogICAga2lsbGVkLm5vYXR0YWNrLmFzaWFuID0gbGVuZ3RoKHdoaWNoKHRocmVhdF9sZXZlbD09Im90aGVyIiAmIFJhY2U9PSJBc2lhbiIpKSwNCiAgICBraWxsZWQubm9mbGVlLmFzaWFuID0gbGVuZ3RoKHdoaWNoKGZsZWU9PSJOb3QgZmxlZWluZyIgJiBSYWNlPT0iQXNpYW4iKSksDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2suYXNpYW4gPSBraWxsZWQudW5hcm1lZC5hc2lhbiArIGtpbGxlZC5ub2F0dGFjay5hc2lhbiwNCiAgICBraWxsZWQudW5hcm1lZF9ub2F0dGFja19ub2ZsZWUuYXNpYW4gPSBraWxsZWQudW5hcm1lZC5hc2lhbiArIGtpbGxlZC5ub2F0dGFjay5hc2lhbiArIGtpbGxlZC5ub2ZsZWUuYXNpYW4sDQogICAgDQogICAgI05hdGl2ZSBBbWVyaWNhbg0KICAgIGtpbGxlZC5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmFtZXJpbmRpYW4gPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLA0KICAgIGtpbGxlZC5ub2F0dGFjay5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKHRocmVhdF9sZXZlbD09Im90aGVyIiAmIFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKSksDQogICAga2lsbGVkLm5vZmxlZS5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKGZsZWU9PSJOb3QgZmxlZWluZyIgJiBSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLA0KICAgIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLmFtZXJpbmRpYW4gPSBraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuICsga2lsbGVkLm5vYXR0YWNrLmFtZXJpbmRpYW4sDQogICAga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlLmFtZXJpbmRpYW4gPSBraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuICsga2lsbGVkLm5vYXR0YWNrLmFtZXJpbmRpYW4gKyBraWxsZWQubm9mbGVlLmFtZXJpbmRpYW4NCiAgICANCiAgICANCiAgICAgICAgICAgICkgDQoNCg0KYGBgDQoNCg0KIyMzLiBMb3R0ICYgTW9vZHkgKDIwMTYpDQpgYGB7cn0NCg0KDQpsb3R0X3BraWxsIDwtIGxvdHQgJT4lIA0KICBncm91cF9ieShkYXRhU291cmNlLCBGSVBTLCB5ZWFyKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgcG9saWNlS2lsbGVkID0gZmlyc3QoYHBvbGljZSBraWxsZWRgKQ0KICApICU+JSANCiAgZ3JvdXBfYnkoZGF0YVNvdXJjZSwgRklQUykgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIHBvbGljZUtpbGxlZCA9IHN1bShwb2xpY2VLaWxsZWQpDQogICkNCg0KbG90dF9jIDwtIGxvdHQgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKEZJUFMpLCB5ZWFyIDwgMjAxNykgJT4lIA0KICBncm91cF9ieShkYXRhU291cmNlLCBGSVBTKSAlPiUgIyNhdmVyYWdlIGFjcm9zcyB5ZWFycyAyMDEyLTIwMTUNCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBTdGF0ZT1maXJzdChTdGF0ZSksIA0KICAgIGtpbGxlZCA9IG4oKSwgDQogICAga2lsbGVkLnVuYXJtZWQgPSBsZW5ndGgod2hpY2goQXJtZWQ9PUZBTFNFKSksDQogICAgDQogICAjI1doaXRlIE5vbkhpc3BhbmljDQogICAga2lsbGVkLndoaXRlX25oID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJXaGl0ZSIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQud2hpdGVfbmggPSBsZW5ndGgod2hpY2goQXJtZWQ9PUZBTFNFICYgUmFjZT09IldoaXRlIikpLCAgDQogICANCiAgICAjI0JsYWNrDQogICAga2lsbGVkLmJsYWNrID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJCbGFjayIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQuYmxhY2sgPSBsZW5ndGgod2hpY2goQXJtZWQ9PUZBTFNFICYgUmFjZT09IkJsYWNrIikpLA0KICAgDQogICAgIyNIaXNwYW5pYw0KICAgIGtpbGxlZC5oaXNwID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJIaXNwYW5pYyIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQuaGlzcCA9IGxlbmd0aCh3aGljaChBcm1lZD09RkFMU0UgJiBSYWNlPT0iSGlzcGFuaWMiKSksDQogICANCiAgICAjI1doaXRlICsgSGlzcGFuaWMNCiAgICBraWxsZWQud2hpdGUgPSBsZW5ndGgod2hpY2goUmFjZT09Ikhpc3BhbmljIiB8IFJhY2UgPT0gIldoaXRlIikpLCANCiAgICBraWxsZWQudW5hcm1lZC53aGl0ZSA9IGxlbmd0aCh3aGljaChBcm1lZD09RkFMU0UgJiAoUmFjZT09Ikhpc3BhbmljIiB8IFJhY2UgPT0gIldoaXRlIikpKSwNCiAgIA0KICAgICMjQXNpYW4NCiAgICBraWxsZWQuYXNpYW4gPSBsZW5ndGgod2hpY2goUmFjZT09IkFzaWFuL1BhY2lmaWMgSXNsYW5kZXIiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmFzaWFuID0gbGVuZ3RoKHdoaWNoKEFybWVkPT1GQUxTRSAmIFJhY2U9PSJBc2lhbi9QYWNpZmljIElzbGFuZGVyIikpLA0KICAgICAgDQogICAgIyNOYXRpdmUgQW1lcmljYW4NCiAgICBraWxsZWQuYW1lcmluZGlhbiA9IGxlbmd0aCh3aGljaChSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKEFybWVkPT1GQUxTRSAmIFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKSksDQogICANCiAgIGF2X1BvbGljZV9vbl9TY2VuZSA9IG1lYW4oYG51bWJlciBwb2xpY2Ugb24gc2NlbmVgKSwNCiAgIG9mZmljZXJfd2hpdGUgPSBsZW5ndGgod2hpY2goT2ZmaWNlclJhY2U9PSJXaGl0ZSIpKSAvIGtpbGxlZCwgIA0KICAgI1BlcmNlbnRhZ2Ugb2YgZmlyc3Qgb2ZmaWNlcnMgd2hpdGUgb3V0IG9mIHRvdGFsIGluY2ljZW50cw0KICAgb2ZmaWNlcl91bmtub3duID0gbGVuZ3RoKHdoaWNoKE9mZmljZXJSYWNlPT0iVW5rbm93biIpKSAvIGtpbGxlZCwNCiAgIG9mZmljZXJfYmxhY2sgPSBsZW5ndGgod2hpY2goT2ZmaWNlclJhY2U9PSJCbGFjayIpKSAvIGtpbGxlZCwNCiAgIG9mZmljZXJfaGlzcGFuaWMgPSBsZW5ndGgod2hpY2goT2ZmaWNlclJhY2U9PSJIaXNwYW5pYyIpKSAvIGtpbGxlZA0KICApICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihsb3R0X3BraWxsKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KDQoNCiMjUmVwZWF0IGZvciBTdGF0ZXMNCg0KbG90dF9wa2lsbF9zdGF0ZSA8LSBsb3R0ICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGRhdGFTb3VyY2UsIFN0YXRlLCB5ZWFyKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgcG9saWNlS2lsbGVkID0gZmlyc3QoYHBvbGljZSBraWxsZWRgKQ0KICApICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KGRhdGFTb3VyY2UsIFN0YXRlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAgcG9saWNlS2lsbGVkID0gc3VtKHBvbGljZUtpbGxlZCkNCiAgKQ0KDQpsb3R0X3N0YXRlIDwtIGxvdHQgJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShTdGF0ZSksIHllYXIgPCAyMDE3KSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShkYXRhU291cmNlLCBTdGF0ZSkgJT4lICMjYXZlcmFnZSBhY3Jvc3MgeWVhcnMgMjAxMi0yMDE1DQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAga2lsbGVkID0gbigpLCANCiAgICBraWxsZWQudW5hcm1lZCA9IGxlbmd0aCh3aGljaChBcm1lZD09RkFMU0UpKSwNCiAgICANCiAgICMjV2hpdGUgTm9uSGlzcGFuaWMNCiAgICBraWxsZWQud2hpdGVfbmggPSBsZW5ndGgod2hpY2goUmFjZT09IldoaXRlIikpLCANCiAgICBraWxsZWQudW5hcm1lZC53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaChBcm1lZD09RkFMU0UgJiBSYWNlPT0iV2hpdGUiKSksICANCiAgIA0KICAgICMjQmxhY2sNCiAgICBraWxsZWQuYmxhY2sgPSBsZW5ndGgod2hpY2goUmFjZT09IkJsYWNrIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5ibGFjayA9IGxlbmd0aCh3aGljaChBcm1lZD09RkFMU0UgJiBSYWNlPT0iQmxhY2siKSksDQogICANCiAgICAjI0hpc3BhbmljDQogICAga2lsbGVkLmhpc3AgPSBsZW5ndGgod2hpY2goUmFjZT09Ikhpc3BhbmljIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5oaXNwID0gbGVuZ3RoKHdoaWNoKEFybWVkPT1GQUxTRSAmIFJhY2U9PSJIaXNwYW5pYyIpKSwNCiAgIA0KICAgICMjV2hpdGUgKyBIaXNwYW5pYw0KICAgIGtpbGxlZC53aGl0ZSA9IGxlbmd0aCh3aGljaChSYWNlPT0iSGlzcGFuaWMiIHwgUmFjZSA9PSAiV2hpdGUiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLndoaXRlID0gbGVuZ3RoKHdoaWNoKEFybWVkPT1GQUxTRSAmIChSYWNlPT0iSGlzcGFuaWMiIHwgUmFjZSA9PSAiV2hpdGUiKSkpLA0KICAgDQogICAgICAgIyNBc2lhbg0KICAgIGtpbGxlZC5hc2lhbiA9IGxlbmd0aCh3aGljaChSYWNlPT0iQXNpYW4vUGFjaWZpYyBJc2xhbmRlciIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQuYXNpYW4gPSBsZW5ndGgod2hpY2goQXJtZWQ9PUZBTFNFICYgUmFjZT09IkFzaWFuL1BhY2lmaWMgSXNsYW5kZXIiKSksDQogICAgICANCiAgICAjI05hdGl2ZSBBbWVyaWNhbg0KICAgIGtpbGxlZC5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmFtZXJpbmRpYW4gPSBsZW5ndGgod2hpY2goQXJtZWQ9PUZBTFNFICYgUmFjZT09Ik5hdGl2ZSBBbWVyaWNhbiIpKSwNCiAgIA0KICAgYXZfUG9saWNlX29uX1NjZW5lID0gbWVhbihgbnVtYmVyIHBvbGljZSBvbiBzY2VuZWApLA0KICAgb2ZmaWNlcl93aGl0ZSA9IGxlbmd0aCh3aGljaChPZmZpY2VyUmFjZT09IldoaXRlIikpIC8ga2lsbGVkLCAgDQogICAjUGVyY2VudGFnZSBvZiBmaXJzdCBvZmZpY2VycyB3aGl0ZSBvdXQgb2YgdG90YWwgaW5jaWNlbnRzDQogICBvZmZpY2VyX3Vua25vd24gPSBsZW5ndGgod2hpY2goT2ZmaWNlclJhY2U9PSJVbmtub3duIikpIC8ga2lsbGVkLA0KICAgb2ZmaWNlcl9ibGFjayA9IGxlbmd0aCh3aGljaChPZmZpY2VyUmFjZT09IkJsYWNrIikpIC8ga2lsbGVkLA0KICAgb2ZmaWNlcl9oaXNwYW5pYyA9IGxlbmd0aCh3aGljaChPZmZpY2VyUmFjZT09Ikhpc3BhbmljIikpIC8ga2lsbGVkDQogICkgJT4lIA0KICBkcGx5cjo6bGVmdF9qb2luKGxvdHRfcGtpbGxfc3RhdGUpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpgYGANCg0KIyM0LiBDb21iaW5pbmcgTG90dCAmIE1vb2R5ICgyMDEzLTIwMTUpIHdpdGggMjAxNiBkYXRhIGZyb20gV2FzaGluZ3RvbiBQb3N0DQpgYGB7cn0NCmxvdHRfd2FwbyA8LSB3YXBvICU+JSANCiAgZHBseXI6OmZpbHRlcighaXMubmEoRklQUyksIHllYXIgPT0gMjAxNikgJT4lIA0KICBncm91cF9ieShkYXRhU291cmNlLEZJUFMpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZSgNCiAgICBraWxsZWQgPSBuKCksIA0KICAgIGtpbGxlZC51bmFybWVkID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiKSksDQogICAgIyNXaGl0ZSBOb25IaXNwYW5pYw0KICAgIGtpbGxlZC53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaChSYWNlPT0iV2hpdGUiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLndoaXRlX25oID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgUmFjZT09IldoaXRlIikpLA0KICAgIA0KICAgICMjQmxhY2sNCiAgICBraWxsZWQuYmxhY2sgPSBsZW5ndGgod2hpY2goUmFjZT09IkJsYWNrIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5ibGFjayA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIFJhY2U9PSJCbGFjayIpKSwNCg0KICAgICNIaXNwYW5pYw0KICAgIGtpbGxlZC5oaXNwID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJIaXNwYW5pYyIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQuaGlzcCA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIFJhY2U9PSJIaXNwYW5pYyIpKSwNCiAgICANCiAgICAjI1doaXRlICsgSGlzcGFuaWMgY2F0ZWdvcnkgLSBtYXRjaGVzIFVDUg0KICAgIGtpbGxlZC53aGl0ZSA9IGxlbmd0aCh3aGljaChSYWNlPT0iV2hpdGUiIHwgUmFjZSA9PSAiSGlzcGFuaWMiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLndoaXRlID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgKFJhY2U9PSJXaGl0ZSIgfCBSYWNlID09ICJIaXNwYW5pYyIpKSksDQogICAgDQogICAgICNBc2lhbg0KICAgIGtpbGxlZC5hc2lhbiA9IGxlbmd0aCh3aGljaChSYWNlPT0iQXNpYW4iKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmFzaWFuID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgUmFjZT09IkFzaWFuIikpLA0KICAgICMga2lsbGVkLm5vYXR0YWNrLmFzaWFuID0gbGVuZ3RoKHdoaWNoKHRocmVhdF9sZXZlbD09Im90aGVyIiAmIFJhY2U9PSJBc2lhbiIpKSwNCiAgICAjIGtpbGxlZC5ub2ZsZWUuYXNpYW4gPSBsZW5ndGgod2hpY2goZmxlZT09Ik5vdCBmbGVlaW5nIiAmIFJhY2U9PSJBc2lhbiIpKSwNCiAgICAjIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLmFzaWFuID0ga2lsbGVkLnVuYXJtZWQuYXNpYW4gKyBraWxsZWQubm9hdHRhY2suYXNpYW4sDQogICAgIyBraWxsZWQudW5hcm1lZF9ub2F0dGFja19ub2ZsZWUuYXNpYW4gPSBraWxsZWQudW5hcm1lZC5hc2lhbiArIGtpbGxlZC5ub2F0dGFjay5hc2lhbiArIGtpbGxlZC5ub2ZsZWUuYXNpYW4sDQogICAgDQogICAgI05hdGl2ZSBBbWVyaWNhbg0KICAgIGtpbGxlZC5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJOYXRpdmUgQW1lcmljYW4iKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmFtZXJpbmRpYW4gPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpDQogICAgIyBraWxsZWQubm9hdHRhY2suYW1lcmluZGlhbiA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLA0KICAgICMga2lsbGVkLm5vZmxlZS5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKGZsZWU9PSJOb3QgZmxlZWluZyIgJiBSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLA0KICAgICMga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2suYW1lcmluZGlhbiA9IGtpbGxlZC51bmFybWVkLmFtZXJpbmRpYW4gKyBraWxsZWQubm9hdHRhY2suYW1lcmluZGlhbiwNCiAgICAjIGtpbGxlZC51bmFybWVkX25vYXR0YWNrX25vZmxlZS5hbWVyaW5kaWFuID0ga2lsbGVkLnVuYXJtZWQuYW1lcmluZGlhbiArIGtpbGxlZC5ub2F0dGFjay5hbWVyaW5kaWFuICsga2lsbGVkLm5vZmxlZS5hbWVyaW5kaWFuDQogICkNCg0KDQpsb3R0X2MyIDwtIGxvdHRfYyAlPiUgDQogIGdyb3VwX2J5KGRhdGFTb3VyY2UsRklQUykgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGNvbnRhaW5zKCJraWxsZWQiKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1wb2xpY2VLaWxsZWQpDQoNCg0KbG90dF93YXBvIDwtIGRwbHlyOjpiaW5kX3Jvd3MobG90dF93YXBvLCBsb3R0X2MyKSAlPiUgDQogIGdyb3VwX2J5KEZJUFMpICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBzdW0sIG5hLnJtPVQpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBkYXRhU291cmNlID0gIldhUG8gJiBMb3R0Ig0KICApDQoNCg0KIyNSZXBlYXQgZm9yIFN0YXRlcw0KbG90dF93YXBvX3N0YXRlIDwtIHdhcG8gJT4lIA0KICBkcGx5cjo6ZmlsdGVyKCFpcy5uYShTdGF0ZSksIHllYXIgPT0gMjAxNikgJT4lIA0KICBncm91cF9ieShkYXRhU291cmNlLFN0YXRlKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2UoDQogICAga2lsbGVkID0gbigpLCANCiAgICBraWxsZWQudW5hcm1lZCA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIikpLA0KICAgICMjV2hpdGUgTm9uSGlzcGFuaWMNCiAgICBraWxsZWQud2hpdGVfbmggPSBsZW5ndGgod2hpY2goUmFjZT09IldoaXRlIikpLCANCiAgICBraWxsZWQudW5hcm1lZC53aGl0ZV9uaCA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIFJhY2U9PSJXaGl0ZSIpKSwNCiAgICANCiAgICAjI0JsYWNrDQogICAga2lsbGVkLmJsYWNrID0gbGVuZ3RoKHdoaWNoKFJhY2U9PSJCbGFjayIpKSwgDQogICAga2lsbGVkLnVuYXJtZWQuYmxhY2sgPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iQmxhY2siKSksDQoNCiAgICAjSGlzcGFuaWMNCiAgICBraWxsZWQuaGlzcCA9IGxlbmd0aCh3aGljaChSYWNlPT0iSGlzcGFuaWMiKSksIA0KICAgIGtpbGxlZC51bmFybWVkLmhpc3AgPSBsZW5ndGgod2hpY2goV2VhcG9uPT0idW5hcm1lZCIgJiBSYWNlPT0iSGlzcGFuaWMiKSksDQogICAgDQogICAgIyNXaGl0ZSArIEhpc3BhbmljIGNhdGVnb3J5IC0gbWF0Y2hlcyBVQ1INCiAgICBraWxsZWQud2hpdGUgPSBsZW5ndGgod2hpY2goUmFjZT09IldoaXRlIiB8IFJhY2UgPT0gIkhpc3BhbmljIikpLCANCiAgICBraWxsZWQudW5hcm1lZC53aGl0ZSA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIChSYWNlPT0iV2hpdGUiIHwgUmFjZSA9PSAiSGlzcGFuaWMiKSkpLA0KICAgIA0KICAgICAjQXNpYW4NCiAgICBraWxsZWQuYXNpYW4gPSBsZW5ndGgod2hpY2goUmFjZT09IkFzaWFuIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5hc2lhbiA9IGxlbmd0aCh3aGljaChXZWFwb249PSJ1bmFybWVkIiAmIFJhY2U9PSJBc2lhbiIpKSwNCiAgICAjIGtpbGxlZC5ub2F0dGFjay5hc2lhbiA9IGxlbmd0aCh3aGljaCh0aHJlYXRfbGV2ZWw9PSJvdGhlciIgJiBSYWNlPT0iQXNpYW4iKSksDQogICAgIyBraWxsZWQubm9mbGVlLmFzaWFuID0gbGVuZ3RoKHdoaWNoKGZsZWU9PSJOb3QgZmxlZWluZyIgJiBSYWNlPT0iQXNpYW4iKSksDQogICAgIyBraWxsZWQudW5hcm1lZF9ub2F0dGFjay5hc2lhbiA9IGtpbGxlZC51bmFybWVkLmFzaWFuICsga2lsbGVkLm5vYXR0YWNrLmFzaWFuLA0KICAgICMga2lsbGVkLnVuYXJtZWRfbm9hdHRhY2tfbm9mbGVlLmFzaWFuID0ga2lsbGVkLnVuYXJtZWQuYXNpYW4gKyBraWxsZWQubm9hdHRhY2suYXNpYW4gKyBraWxsZWQubm9mbGVlLmFzaWFuLA0KICAgIA0KICAgICNOYXRpdmUgQW1lcmljYW4NCiAgICBraWxsZWQuYW1lcmluZGlhbiA9IGxlbmd0aCh3aGljaChSYWNlPT0iTmF0aXZlIEFtZXJpY2FuIikpLCANCiAgICBraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuID0gbGVuZ3RoKHdoaWNoKFdlYXBvbj09InVuYXJtZWQiICYgUmFjZT09Ik5hdGl2ZSBBbWVyaWNhbiIpKQ0KICAgICMga2lsbGVkLm5vYXR0YWNrLmFtZXJpbmRpYW4gPSBsZW5ndGgod2hpY2godGhyZWF0X2xldmVsPT0ib3RoZXIiICYgUmFjZT09Ik5hdGl2ZSBBbWVyaWNhbiIpKSwNCiAgICAjIGtpbGxlZC5ub2ZsZWUuYW1lcmluZGlhbiA9IGxlbmd0aCh3aGljaChmbGVlPT0iTm90IGZsZWVpbmciICYgUmFjZT09Ik5hdGl2ZSBBbWVyaWNhbiIpKSwNCiAgICAjIGtpbGxlZC51bmFybWVkX25vYXR0YWNrLmFtZXJpbmRpYW4gPSBraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuICsga2lsbGVkLm5vYXR0YWNrLmFtZXJpbmRpYW4sDQogICAgIyBraWxsZWQudW5hcm1lZF9ub2F0dGFja19ub2ZsZWUuYW1lcmluZGlhbiA9IGtpbGxlZC51bmFybWVkLmFtZXJpbmRpYW4gKyBraWxsZWQubm9hdHRhY2suYW1lcmluZGlhbiArIGtpbGxlZC5ub2ZsZWUuYW1lcmluZGlhbg0KICApDQoNCg0KbG90dF9jMl9zdGF0ZSA8LSBsb3R0X3N0YXRlICU+JSANCiAgZ3JvdXBfYnkoZGF0YVNvdXJjZSxTdGF0ZSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGNvbnRhaW5zKCJraWxsZWQiKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KC1wb2xpY2VLaWxsZWQpDQoNCg0KbG90dF93YXBvX3N0YXRlIDwtIGRwbHlyOjpiaW5kX3Jvd3MobG90dF93YXBvX3N0YXRlLCBsb3R0X2MyX3N0YXRlKSAlPiUgDQogIGdyb3VwX2J5KFN0YXRlKSAlPiUgDQogIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBzdW0sIG5hLnJtPVQpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICBkYXRhU291cmNlID0gIldhUG8gJiBMb3R0Ig0KICApDQoNCg0KYGBgDQoNCg0KIyM1LiAgU2F2ZSBEYXRhDQpgYGB7cn0NCg0KcmVhZHI6OndyaXRlX2Nzdihsb3R0X3dhcG8sIHBhdGg9ImtpbGxlZF9sb3R0X3dhcG8uY3N2IikNCnJlYWRyOjp3cml0ZV9jc3YobG90dF9jLCBwYXRoPSJraWxsZWRfbG90dC5jc3YiKQ0KcmVhZHI6OndyaXRlX2Nzdih3YXBvX2MsIHBhdGg9ImtpbGxlZF93YXBvLmNzdiIpDQoNCnJlYWRyOjp3cml0ZV9jc3YobG90dF93YXBvX3N0YXRlLCBwYXRoPSJraWxsZWRfbG90dF93YXBvX3N0YXRlLmNzdiIpDQpyZWFkcjo6d3JpdGVfY3N2KGxvdHRfc3RhdGUsIHBhdGg9ImtpbGxlZF9sb3R0X3N0YXRlLmNzdiIpDQpyZWFkcjo6d3JpdGVfY3N2KHdhcG9fc3RhdGUsIHBhdGg9ImtpbGxlZF93YXBvX3N0YXRlLmNzdiIpDQoNCmBgYA0KDQoNCg0KDQojWElJLiAgQUdHUkVHQVRJT04NCkJlbG93IEkgYWdncmVnYXRlIGNvdW50aWVzIGludG8gZ2VvZ3JhcGhpY2FsIHVuaXRzIG9mIGhhdmluZyBhIG1pbmltdW0gc3BlY2lmaWVkIHBvcHVsYXRpb24gc2l6ZS4gICBGb3IgZXhhbXBsZSwgaWYgdGhlIHRocmVzaG9sZCBpcyAxMCwwMDAsIHRoZW4gSSBhZ2dyZWdhdGUgY291bnRpZXMgd2l0aCBsZXNzIHRoYW4gMTAsMDAwIHJlc2lkZW50cyAgaW50byBhIGxhcmdlciB1bml0IGhhdmluZyBhdCBsZWFzdCAxMCwwMDAgcmVzaWRlbnRzLiAgVGhlIGFnZ3JlZ2F0aW9uIHByb2JsZW0gaGFzIG1hbnkgcG9zc2libGUgc29sdXRpb25zLiAgVGhlIGFsZ29yaXRobSBJIGVtcGxveSBhZ2dyZWdhdGVzIGFkamFjZW50IGNvdW50aWVzIHdpdGggc21hbGxlc3QgcG9wdWxhdGlvbiBzaXplcyBmaXJzdCwgaS5lLiBjb3VudGllcyB3aXRoIHRoZSBzbWFsbGVzdCBwb3B1bGF0aW9ucyBpbiB0aGUgVVMgYXJlIHNlbGVjdGVkIGZpcnN0LCB0aGVuIGFnZ3JlZ2F0ZWQgd2l0aCB0aGVpciBzbWFsbGVzdCBzaXplIG5laWdoYm9ycy4gIA0KDQpodHRwczovL3d3dy5jZW5zdXMuZ292L2dlby9yZWZlcmVuY2UvY291bnR5LWFkamFjZW5jeS5odG1sDQoNCiMjQS4gIEZVTkNUSU9OUw0KIyMjMS4gQWdncmVnYXRlIENvdW50aWVzDQpUaGlzIGlzIHRvIGNyZWF0ZSB0aGUgaW5kZXggdGhhdCBpZGVudGlmaWVzIHdoaWNoIGxhcmdlciByZWdpb25zIGNvdW50aWVzIGJlbG9uZyB0by4gIFRoZXJlIGFyZSA1IGNvdW50aWVzIChvciBjZW5zdXMgYXJlYXMpIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBpbiB0aGUgQ2Vuc3VzIGFkamFjZW5jeSBmaWxlLiAgVGhleSBpbiBBbGFza2EsIEhhd2FpaSwgYW5kIFNvdXRoIERha290YS4gIFRoZWlyIEZJUFMgY29kZXMgYXJlOiAwMjE1OCwgMTUwMDEsIDE1MDAzLCAxNTAwNywgYW5kIDQ2MTAyLiAgSSBtZXJnZSB0aGVzZSB3aXRoIHRoZSBzbWFsbGVzdCBncm91cCB3aXRoaW4gdGhlIHN0YXRlLg0KDQoNCg0KYGBge3J9DQpBZ2dyZWdhdGUuQ291bnRpZXMgPC0gZnVuY3Rpb24ocG9wLnRoLCAgYWRqYWNlbnRGaWxlID0gImNyZWF0ZURhdGEvY291bnR5QWRqYWNlbnQuY3N2IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXJGaWxlID0gImNvdW50eVZhcnNfZi5jc3YiKXsNCg0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQogIGFkamFjZW50IDwtIGZzdDo6cmVhZC5mc3QoYWRqYWNlbnRGaWxlKQ0KICBjb3VudHlWYXJzIDwtIGZzdDo6cmVhZC5mc3QocGF0aD12YXJGaWxlKQ0KICBkZl9hZ2cgPC0gY291bnR5VmFyc1ssYygiRklQUyIsICJzdGF0ZSIsICJwb3AuYy50b3RhbF81eXIiKV0gDQogIGRmIDwtIGRmX2FnZw0KICBuYW1lcyhkZikgPC0gYygiRklQUyIsInN0YXRlIiwgICJwb3AiKQ0KDQojI2dyYWJiaW5nIGV4dHJhIEZJUFMgbm90IGFzc2lnbmVkIGluIGFkamFjZW5jeSBmaWxlIC0gYXR0YWNoaW5nIHRvIHNtYWxsZXN0IGNvdW50aWVzIHdpdGhpbiB0aGUgc3RhdGUNCmV4dHJhRklQUyA8LSBzZXRkaWZmKCBkZl9hZ2ckRklQUywgYWRqYWNlbnQkRklQUykNCmV4dHJhX2RmIDwtIGRmX2FnZ1t3aGljaChkZl9hZ2ckRklQUyAlaW4lIGV4dHJhRklQUyksXQ0KZGZfYWdnIDwtIGRmX2FnZ1shKGRmX2FnZyRGSVBTICVpbiUgZXh0cmFGSVBTKSxdDQpleHRyYV9kZiRuX0ZJUFMgPC0gTkENCiBmb3IoaSBpbiBzZXFfYWxvbmcoZXh0cmFfZGYkRklQUykpew0KICAgaV9zdGF0ZSA8LSBleHRyYV9kZiRzdGF0ZVtpXQ0KICAgZGZfYWdnX3N1YnNldCA8LSBzdWJzZXQoZGZfYWdnLCBzdGF0ZSA9PSBpX3N0YXRlKQ0KICAgZXh0cmFfZGYkbl9GSVBTW2ldIDwtIGRmX2FnZ19zdWJzZXQkRklQU1t3aGljaC5taW4oZGZfYWdnX3N1YnNldCRwb3AuYy50b3RhbF81eXIpXQ0KIH0NCg0KZXh0cmFfZGYgPC0gZXh0cmFfZGZbLGMoIkZJUFMiLCAibl9GSVBTIildDQojI0FkZCB0aGVzZSBhcmUgcm93cyB0byBhZGogZmlsZSBiZWxvdw0KYWRqIDwtIGFkamFjZW50WyxjKCJGSVBTIiwgIm5fRklQUyIpXSAlPiUgDQogIGRwbHlyOjpiaW5kX3Jvd3MoZXh0cmFfZGYpDQoNCmFkaiA8LSBkcGx5cjo6bGVmdF9qb2luKGFkaiwgZGYsIGJ5PWMoIkZJUFMiKSkNCmRmIDwtIGRmWyxjKCJGSVBTIiwgInBvcCIpXQ0KbmFtZXMoZGYpIDwtIGMoICJuX0ZJUFMiLCAgInBvcF9uIikNCmRmIDwtIGRwbHlyOjpsZWZ0X2pvaW4oYWRqLCBkZiwgYnk9Yygibl9GSVBTIikpICU+JSANCiAgZHBseXI6OmFycmFuZ2UoRklQUywgcG9wX24pICU+JSAgICMjYXJyYW5nZSBzbyB0aGF0IG5laWdoYm9ycyB3aXRoIHNtYWxsZXN0IHBvcHVsYXRpb25zIGNvbWUgZmlyc3QNCiAgZ3JvdXBfYnkoRklQUykgJT4lIA0KICBkcGx5cjo6bXV0YXRlKEdyb3VwUG9wID0gcG9wKSANCg0KZGZHIDwtIGRmICU+JSBncm91cF9ieShGSVBTKSAlPiUgZHBseXI6OnN1bW1hcmlzZSgpDQpkZkckR3JvdXAgPC0gYXMubnVtZXJpYyhyb3cubmFtZXMoZGZHKSkNCmRmIDwtIGRmICU+JSBkcGx5cjo6bGVmdF9qb2luKGRmRykNCg0KI2xpc3R3aXNlIGRlbGV0aW9uIG9mIGNhc2VzDQpkZiA8LSBkZltjb21wbGV0ZS5jYXNlcyhkZiksXQ0KDQptZXNzYWdlKHBhc3RlMCgiSU5JVElBTCBNRVRSSUNTOiBUSEVSRSBBUkUgIiwgbGVuZ3RoKHVuaXF1ZShkZiRHcm91cCkpLCAiIFVOSVFVRSBHUk9VUFMiKSkNCm1lc3NhZ2UocGFzdGUwKCJUSEVSRSBBUkUgIiwgbGVuZ3RoKHVuaXF1ZShkZiRHcm91cFt3aGljaChkZiRHcm91cFBvcCA8IHBvcC50aCldKSksICIgR1JPVVBTIFdJVEggUE9QVUxBVElPTlMgU01BTExFUiBUSEFOIFRIUkVTSE9MRCIpKQ0KDQojI0NvbmRpdGlvbiAxIC0gQ29tYmluZSBpZiBuZWlnaGJvciBhbHNvIGhhcyBzbWFsbCBwb3B1bGF0aW9uDQpmb3IoaSBpbiAxOm5yb3coZGYpKXsNCiAgZiA8LSBkZiRGSVBTW2ldDQogIGYyIDwtIGRmJG5fRklQU1tpXQ0KICBpMiA8LSB3aGljaChkZiRGSVBTPT1mMikNCiAgDQogIHBvcF9pMiA8LSB1bmlxdWUoZGYkcG9wW2kyXSkNCiAgR3BvcF9pMiA8LSB1bmlxdWUoZGYkR3JvdXBQb3BbaTJdKQ0KICBnX2kxIDwtIGRmJEdyb3VwW2ldDQogIGdfaTIgPC0gdW5pcXVlKGRmJEdyb3VwW2kyXSkNCiAgDQogIGlmKGRmJHBvcFtpXSA8IHBvcC50aCAmIGRmJEdyb3VwUG9wW2ldIDwgcG9wLnRoKXsgIyMxKSBJZiBjb3VudHkgaSBoYXMgcG9wdWxhdGlvbiBzbWFsbGVyIHRoYW4gdGhyZXNob2xkIA0KICAgIGlmKHBvcF9pMiA8IHBvcC50aCAmIEdwb3BfaTIgPCBwb3AudGgpeyAgICAgICAgICMjMikgSWYgbmVpZ2hib3IgYWxzbyBoYXMgcG9wLiBzbWFsbGVyIHRoYW4gdGhyZXNob2xkIA0KICAgICAgaWYoZ19pMSAhPSBnX2kyKXsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjMykgSWYgdGhleSBkb24ndCBhbHJlYWR5IGJlbG9uZyB0byB0aGUgc2FtZSBncm91cCwgdGhlbi4uLg0KICAgICAgICBkZiRHcm91cFt3aGljaChkZiRHcm91cCA9PSBnX2kyKV0gPC0gZ19pMQ0KICAgICAgICANCiAgICAgICAgI2NoZWNrIHRvIGVuc3VyZSB0aGV5IGRvbid0IGhhdmUgdGhlIGV4YWN0IHNhbWUgcG9wdWxhdGlvbiB2YWx1ZSwgdGhlbiBhZGQgdW5pcXVlIHZhbHVlcw0KICAgICAgICBpZihkZiRHcm91cFBvcFtpXSA9PSBHcG9wX2kyKXttZXNzYWdlKCJXYXJuaW5nIC0gdHdvIGNvdW50aWVzIGhhdmUgZXhhY3Qgc2FtZSBncm91cCBwb3B1bGF0aW9uIHZhbHVlcyIpfSBlbHNlIHsNCiAgICAgICAgICBkZiRHcm91cFBvcFt3aGljaChkZiRHcm91cCA9PSBnX2kxKV0gPC0gc3VtKHVuaXF1ZShkZiRwb3Bbd2hpY2goZGYkR3JvdXAgPT0gZ19pMSldKSkNCiAgICAgICAgfQ0KICAgICAgfX19IA0KfQ0KDQptZXNzYWdlKHBhc3RlMCgiRU5EIE9GIFJPVU5EIDEsIFRIRVJFIEFSRSAiLCBsZW5ndGgodW5pcXVlKGRmJEdyb3VwKSksICIgVU5JUVVFIEdST1VQUyIpKQ0KbWVzc2FnZShwYXN0ZTAoIlRIRVJFIEFSRSAiLCBsZW5ndGgodW5pcXVlKGRmJEdyb3VwW3doaWNoKGRmJEdyb3VwUG9wIDwgcG9wLnRoKV0pKSwgIiBHUk9VUFMgV0lUSCBQT1BVTEFUSU9OUyBTTUFMTEVSIFRIQU4gVEhSRVNIT0xEIikpDQoNCiMjQ29uZGl0aW9uIDIgLSBNZXJnZSB3aXRoIExhcmdlciBOZWlnaGJvcnMgYWxzbw0KZm9yKGkgaW4gMTpucm93KGRmKSl7DQogIGYgPC0gZGYkRklQU1tpXQ0KICBmMiA8LSBkZiRuX0ZJUFNbaV0NCiAgaTIgPC0gd2hpY2goZGYkRklQUz09ZjIpDQogIA0KICBwb3BfaTIgPC0gdW5pcXVlKGRmJHBvcFtpMl0pDQogIEdwb3BfaTIgPC0gdW5pcXVlKGRmJEdyb3VwUG9wW2kyXSkNCiAgZ19pMSA8LSBkZiRHcm91cFtpXQ0KICBnX2kyIDwtIHVuaXF1ZShkZiRHcm91cFtpMl0pDQogIA0KICBpZihkZiRwb3BbaV0gPCBwb3AudGggJiBkZiRHcm91cFBvcFtpXSA8IHBvcC50aCl7ICMjMSkgSWYgY291bnR5IGkgaGFzIHBvcHVsYXRpb24gc21hbGxlciB0aGFuIHRocmVzaG9sZCANCiAgICBpZihnX2kxICE9IGdfaTIpeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyMzKSBJZiB0aGV5IGRvbid0IGFscmVhZHkgYmVsb25nIHRvIHRoZSBzYW1lIGdyb3VwLCB0aGVuLi4uDQogICAgICBkZiRHcm91cFt3aGljaChkZiRHcm91cCA9PSBnX2kyKV0gPC0gZ19pMQ0KICAgICAgDQogICAgICAjY2hlY2sgdG8gZW5zdXJlIHRoZXkgZG9uJ3QgaGF2ZSB0aGUgZXhhY3Qgc2FtZSBwb3B1bGF0aW9uIHZhbHVlLCB0aGVuIGFkZCB1bmlxdWUgdmFsdWVzDQogICAgICBpZihkZiRHcm91cFBvcFtpXSA9PSBHcG9wX2kyKXttZXNzYWdlKCJXYXJuaW5nIC0gdHdvIGNvdW50aWVzIGhhdmUgZXhhY3Qgc2FtZSBncm91cCBwb3B1bGF0aW9uIHZhbHVlcyIpfSBlbHNlIHsNCiAgICAgICAgZGYkR3JvdXBQb3Bbd2hpY2goZGYkR3JvdXAgPT0gZ19pMSldIDwtIHN1bSh1bmlxdWUoZGYkcG9wW3doaWNoKGRmJEdyb3VwID09IGdfaTEpXSkpDQogICAgICB9DQogICAgfX0NCn0NCg0KbWVzc2FnZShwYXN0ZTAoIkVORCBPRiBST1VORCAyLCBUSEVSRSBBUkUgIiwgbGVuZ3RoKHVuaXF1ZShkZiRHcm91cCkpLCAiIFVOSVFVRSBHUk9VUFMiKSkNCm1lc3NhZ2UocGFzdGUwKCJUSEVSRSBBUkUgIiwgbGVuZ3RoKHVuaXF1ZShkZiRHcm91cFt3aGljaChkZiRHcm91cFBvcCA8IHBvcC50aCldKSksICIgR1JPVVBTIFdJVEggUE9QVUxBVElPTlMgU01BTExFUiBUSEFOIFRIUkVTSE9MRCIpKQ0KDQpkZiRuR3JvdXAgPC0gTkENCm15R3JvdXBzIDwtIHVuaXF1ZShkZiRHcm91cCkNCmZvcihpIGluIHNlcV9hbG9uZyh1bmlxdWUoZGYkR3JvdXApKSl7DQogIGRmJG5Hcm91cFt3aGljaChkZiRHcm91cCA9PSBteUdyb3Vwc1tpXSldIDwtIGkNCn0NCg0KZGZfaWQgPC0gZGZbLGMoIkZJUFMiLCAibkdyb3VwIildICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KEZJUFMsIG5Hcm91cCkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKCkNCg0KbmFtZXMoZGZfaWQpIDwtIGMoIkZJUFMiLCAiR3JvdXAiKQ0KcmV0dXJuKGRmX2lkKQ0KfQ0KDQpgYGANCg0KDQoNCiMjIzIuICBBZ2dyZWdhdGUuQ291bnR5LkRhdGENClRoaXMgaXMgdG8gc3VtbWFyaXNlIGFsbCB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXRzIHVzZWQgYmVsb3cuDQpCZWNhdXNlIGRydWcgcG9zc2Vzc2lvbiBhbmQgZHJ1ZyBzYWxlcyBhcnJlc3QgZGF0YSBhcmUgbm90IHByb3ZpZGVkIGJ5IEZsb3JpZGEsIEknbSBub3QgaW5jbHVkaW5nIHRoZXNlIHR3byB2YXJpYWJsZSBzZXRzIGluIHRoZSBhZ2dyZWdhdGVkIGRhdGEgc2V0cy4NCg0KYGBge3J9DQpBZ2dyZWdhdGUuQ291bnR5LkRhdGEgPC0gZnVuY3Rpb24oa2lsbEZpbGUsIGluZGV4RmlsZSwgdmFyRmlsZSA9ICJjb3VudHlWYXJzX2YuY3N2Iil7DQoNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShkcGx5cikNCmRmX25ldyA8LSBmc3Q6OnJlYWQuZnN0KHBhdGg9dmFyRmlsZSkNCmRmIDwtIGRwbHlyOjpsZWZ0X2pvaW4oZGZfbmV3LCByZWFkcjo6cmVhZF9jc3Yoa2lsbEZpbGUpKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoDQogICAgcG9saWNlUmF0aW8gPSBwb2xpY2VGdWxsVGltZS9wb3AuYy50b3RhbF81eXIsDQogICAgYndfaW5jb21lX2dhcCA9IG1lZGlhbkluY29tZV9ibGFjay9tZWRpYW5JbmNvbWVfd2hpdGVfbmgNCiAgKQ0KDQpjcmltZVZhcnMgPC0gYygibXVyZGVyIiwgICJkdWkiLCAiZHJ1Z3MiLCAidmMiLCAidGhlZnQiLCAidmFuZGFsIiwNCiAgICAgICAgICAgICAgICJtdXJkZXJfNXlyIiwgICJkdWlfNXlyIiwgImRydWdzXzV5ciIsICJ2Y181eXIiLCAidGhlZnRfNXlyIiwgInZhbmRhbF81eXIiICwNCiAgICAgICAgICAgICAgICJtdXJkZXJfd2hpdGUiLCAgIm11cmRlcl9ibGFjayIsICAiZHVpIiwgImR1aV93aGl0ZSIsICJkdWlfYmxhY2siLA0KICAgICAgICAgICAgICAgImRydWdzIiwgImRydWdzX3doaXRlIiwgImRydWdzX2JsYWNrIiwNCiAgICAgICAgICAgICAgICJ2Y193aGl0ZSIsICJ2Y19ibGFjayIsICAidGhlZnRfd2hpdGUiLCAidGhlZnRfYmxhY2siLA0KICAgICAgICAgICAgICAgInZhbmRhbF93aGl0ZSIsICJ2YW5kYWxfYmxhY2siLA0KICAgICAgICAgICAgICAgIm11cmRlcl93aGl0ZV81eXIiLCAibXVyZGVyX2JsYWNrXzV5ciIsDQogICAgICAgICAgICAgICAiZHVpX3doaXRlXzV5ciIsICJkdWlfYmxhY2tfNXlyIiwNCiAgICAgICAgICAgICAgICJkcnVnc193aGl0ZV81eXIiLCAiZHJ1Z3NfYmxhY2tfNXlyIiwNCiAgICAgICAgICAgICAgICJ2Y193aGl0ZV81eXIiLCAidmNfYmxhY2tfNXlyIiwNCiAgICAgICAgICAgICAgICJ0aGVmdF93aGl0ZV81eXIiLCAidGhlZnRfYmxhY2tfNXlyIiwNCiAgICAgICAgICAgICAgICJ2YW5kYWxfd2hpdGVfNXlyIiAsICJ2YW5kYWxfYmxhY2tfNXlyIikNCg0KcG9wVmFycyA8LSBjKCJwb3B1bGF0aW9uIiwgInBvcC5jLnRvdGFsIiwicG9wLmMuYmxhY2siLCAgInBvcC5jLndoaXRlX25oIiwgInBvcC5jLldIIiwgInBvcC5jLmFzaWFuIiwgDQogICAgICAgICAgICAgInBvcC5jLkFQIiwgInBvcC5jLmFtZXJpbmRpYW4iLCAicG9wLmMuaGlzcGFuaWMiLCAicG9wLm1hbGUuMTVfMjkiLCAicG9wLmJsYWNrLm1hbGUxNV8yOSIsDQogICAgICAgICAgICAgInBvcC5jLnRvdGFsXzV5ciIsInBvcC5jLmJsYWNrXzV5ciIsICAicG9wLmMud2hpdGVfbmhfNXlyIiwgInBvcC5jLldIXzV5ciIsICJwb3AuYy5hc2lhbl81eXIiLCANCiAgICAgICAgICAgICAicG9wLmMuYW1lcmluZGlhbl81eXIiLCAicG9wLmMuaGlzcGFuaWNfNXlyIiwgInBvcC5tYWxlLjE1XzI5XzV5ciIsIA0KICAgICAgICAgICAgICJsYW5kQXJlYSIpDQoNCmtpbGxWYXJzIDwtIGMoImtpbGxlZCIsICAia2lsbGVkLnVuYXJtZWQiLCAia2lsbGVkLndoaXRlX25oIiwgImtpbGxlZC51bmFybWVkLndoaXRlX25oIiwgDQogICAgICAgICAgICAgICJraWxsZWQuYmxhY2siICwia2lsbGVkLnVuYXJtZWQuYmxhY2siLCJraWxsZWQuaGlzcCIsICJraWxsZWQudW5hcm1lZC5oaXNwIiwgImtpbGxlZC53aGl0ZSIsDQogICAgICAgICAgICAgICJraWxsZWQudW5hcm1lZC53aGl0ZSIgLCAia2lsbGVkLmFzaWFuIiwgImtpbGxlZC51bmFybWVkLmFzaWFuIiAsImtpbGxlZC5hbWVyaW5kaWFuIiwgDQogICAgICAgICAgICAgICJraWxsZWQudW5hcm1lZC5hbWVyaW5kaWFuIiApDQoNCg0Kc2VzQ291bnRWYXJzIDwtIGMoInVuZW1wbG95ZWQiLCAibGFib3JGb3JjZSIsICJlbXBsb3llZCIsICJsYWJvckZvcmNlXzV5ciIsICJlbXBsb3llZF81eXIiLCAidW5lbXBsb3llZF81eXIiLA0KICAgICAgICAgICAgICAgICAgInBvbGljZUZ1bGxUaW1lIiwgICJwb2xpY2VCbGFjayIgLCAicG9saWNlUGF0cm9sIiwgICJwb2xpY2VJbnZlc3RpZ2F0ZSIgLCANCiAgICAgICAgICAgICAgICAgICJwb2xpY2VGZW1hbGUiICwgInRvdGFsRmFtaWxpZXMiLCAic2luZ2xlUGFyZW50IiwNCiAgICAgICAgICAgICAgICAgICJmYW1pbGllc193aGl0ZSIsICJzaW5nbGVQYXJlbnRfd2hpdGUiLCAiZmFtaWxpZXNfd2hpdGVfbmgiLCAic2luZ2xlUGFyZW50X3doaXRlX25oIiwNCiAgICAgICAgICAgICAgICAgICJmYW1pbGllc19ibGFjayIsICJzaW5nbGVQYXJlbnRfYmxhY2siLCAiZmFtaWxpZXNfYW1lcmluZGlhbiIsICJzaW5nbGVQYXJlbnRfYW1lcmluZGlhbiIsDQogICAgICAgICAgICAgICAgICAiZmFtaWxpZXNfYXNpYW4iLCAgInNpbmdsZVBhcmVudF9hc2lhbiIsICJmYW1pbGllc19oYXdhaWlhbiIsICJzaW5nbGVQYXJlbnRfaGF3YWlpYW4iICwNCiAgICAgICAgICAgICAgICAgICJmYW1pbGllc19oaXNwYW5pYyIgICwgInNpbmdsZVBhcmVudF9oaXNwYW5pYyIgICwgInNpbmdsZVBhcmVudF9wcmNudF9oaXNwYW5pYyIgKQ0KDQojI1dFSUdIVEVEIEFWRVJBR0VTIC0gVE9UQUwgLSA1WVIgKHdlaWdodGVkIGJ5IHRvdGFsIHBvcHVsYXRpb24sIGF2ZXJhZ2VkIG92ZXIgc2V2ZXJhbCB5ZWFycykNCndNZWFuVmFycy50b3RhbF81eXIgPC0gYygibWVkaWFuSW5jb21lIiwgInBvdmVydHkiLCAiZ2luaSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJyZXNpZGVudGlhbF9zZWdyZWdhdGlvbl9ibGFja193aGl0ZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICJyZXNpZGVudGlhbF9zZWdyZWdhdGlvbl9ub253aGl0ZV93aGl0ZSIsICJoaWdoc2Nob29sRHJvcE91dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIm11cmRlcl9yXzV5ciIsICJ2Y19yXzV5ciIsICJkdWlfcl81eXIiLCJkcnVnc19yXzV5ciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgInRoZWZ0X3JfNXlyIiAgLCAidmFuZGFsX3JfNXlyIiwgImNyb3dkaW5nX3ByY250IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAicG9saWNlUHJjbnRCbGFjayIsICJwb2xpY2VSYXRpbyIsICJid19pbmNvbWVfZ2FwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiRUxBXzh0aGdyYWRlIiwgIk1BVEhfOHRoZ3JhZGUiICwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiRUxBXzZ0aGdyYWRlIiAsICJNQVRIXzZ0aGdyYWRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk1BVEhfNnRoZ3JhZGVfZ2FwIiwgIkVMQV83dGhncmFkZV9nYXAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAidGhlaWxfd2hpdGVCbGFjayIpDQoNCiMjI1dFSUdIVEVEIEFWRVJBR0VTIC0gV2hpdGUgJiBIaXNwYW5pYyAtIDVZUiAtIE5vdGUgIldoaXRlIiBpbmNsdWRlcyBzaXNwYW5pY3MNCndNZWFuVmFycy5XSF81eXIgPC0gYygibXVyZGVyX3doaXRlX3JfNXlyIiAsICJ2Y193aGl0ZV9yXzV5ciIgLCAiZHVpX3doaXRlX3JfNXlyIiAsInZhbmRhbF93aGl0ZV9yXzV5ciIsDQogICAgICAgICAgICAgICAgICAgICAgInRoZWZ0X3doaXRlX3JfNXlyIiAsImRydWdzX3doaXRlX3JfNXlyIiAgLCANCiAgICAgICAgICAgICAgICAgICAgICAibWVkaWFuSW5jb21lX3doaXRlIiAsICAicG92ZXJ0eV93aGl0ZSIgICApDQoNCiMjI1dFSUdIVEVEIEFWRVJBR0VTIC0gQmxhY2sgLSA1WVIgDQp3TWVhblZhcnMuQmxhY2tfNXlyIDwtIGMoIm11cmRlcl9ibGFja19yXzV5ciIgLCAidmNfYmxhY2tfcl81eXIiICwgImR1aV9ibGFja19yXzV5ciIsICJ2YW5kYWxfYmxhY2tfcl81eXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJ0aGVmdF9ibGFja19yXzV5ciIgLCJkcnVnc19ibGFja19yXzV5ciIgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAibWVkaWFuSW5jb21lX2JsYWNrIiwgInBvdmVydHlfYmxhY2siICkgDQojUmF0ZXMgZm9yIDIwMTUNCmNyaW1lUmF0ZS50b3RhbF8yMDE1IDwtIGMoIm11cmRlcl9yIiwgInZjX3IiLCAiZHVpX3IiICwgInZhbmRhbF9yIiAsICJ0aGVmdF9yIiAgLCAiZHJ1Z3NfciIgKQ0KDQojUmFjZS1zcGVjaWZpYyBSYXRlcyBmb3IgeWVhciAyMDE1IC0NCmNyaW1lUmF0ZS5XSF8yMDE1IDwtIGMoIm11cmRlcl93aGl0ZV9yIiAsInZjX3doaXRlX3IiICwgImR1aV93aGl0ZV9yIiwgInZhbmRhbF93aGl0ZV9yIiwgInRoZWZ0X3doaXRlX3IiLCANCiAgICAgICAgICAgICAgICAgICAgICAgImRydWdzX3doaXRlX3IiKQ0KDQojMjAxNSAtICoqQWxzbyBpbmNsdWRlcyBDaGFuZ2UgaW4gQmxhY2sgUG9wIA0KY3JpbWVSYXRlLkJsYWNrXzIwMTUgPC0gYygibXVyZGVyX2JsYWNrX3IiICwgInZjX2JsYWNrX3IiLCAiZHVpX2JsYWNrX3IiLCAidmFuZGFsX2JsYWNrX3IiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgInRoZWZ0X2JsYWNrX3IiICwiZHJ1Z3NfYmxhY2tfciIgLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAicG9wLmMuYmxhY2tfY2hhbmdlIikNCg0KIyNBR0dSRUdBVEUNCmRmX2luZGV4IDwtIHJlYWRyOjpyZWFkX2NzdihpbmRleEZpbGUpIA0KZGYgPC0gZGYgJT4lIGRwbHlyOjpsZWZ0X2pvaW4oZGZfaW5kZXgpDQoNCmRmX2lkIDwtIGRmICU+JSBkcGx5cjo6Z3JvdXBfYnkoR3JvdXApICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZShGSVBTID0gcGFzdGUodW5pcXVlKEZJUFMpLCBjb2xsYXBzZT0iLCAiKSwNCiAgICAgICAgICAgICAgICAgICBTdGF0ZSA9IHBhc3RlKHVuaXF1ZShzdGF0ZSksIGNvbGxhcHNlID0gIiwgIikNCiAgICAgICAgICAgICAgICAgICApDQoNCmRmX3N1bXMgPC0gZGZbLGMoIkdyb3VwIiwga2lsbFZhcnMsIHBvcFZhcnMsIGNyaW1lVmFycywgc2VzQ291bnRWYXJzKV0gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoR3JvdXApICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZV9hbGwoc3VtLCBuYS5ybT1UKQ0KDQpkZl93TWVhbi50b3RhbF81eXIgPC0gZGZbLGMoIkdyb3VwIiwgd01lYW5WYXJzLnRvdGFsXzV5ciwgInBvcC5jLnRvdGFsXzV5ciIpXSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShHcm91cCkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlX2F0KHdNZWFuVmFycy50b3RhbF81eXIsIGZ1bnMod2VpZ2h0ZWQubWVhbiguW3doaWNoKCFpcy5uYShwb3AuYy50b3RhbF81eXIpKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ID0gcG9wLmMudG90YWxfNXlyW3doaWNoKCFpcy5uYShwb3AuYy50b3RhbF81eXIpKV0sIG5hLnJtPVQpKSkNCg0KZGZfd01lYW4uV0hfNXlyIDwtIGRmWyxjKCJHcm91cCIsIHdNZWFuVmFycy5XSF81eXIsICJwb3AuYy5XSF81eXIiICldICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KEdyb3VwKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYXQod01lYW5WYXJzLldIXzV5ciwgZnVucyh3ZWlnaHRlZC5tZWFuKC5bd2hpY2goIWlzLm5hKHBvcC5jLldIXzV5cikpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBwb3AuYy5XSF81eXJbd2hpY2goIWlzLm5hKHBvcC5jLldIXzV5cikpXSwgbmEucm09VCkpKQ0KDQpkZl93TWVhbi5CbGFja181eXIgPC0gZGZbLGMoIkdyb3VwIiwgd01lYW5WYXJzLkJsYWNrXzV5ciwgInBvcC5jLmJsYWNrXzV5ciIgKV0gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoR3JvdXApICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZV9hdCh3TWVhblZhcnMuQmxhY2tfNXlyLCBmdW5zKHdlaWdodGVkLm1lYW4oLlt3aGljaCghaXMubmEocG9wLmMuYmxhY2tfNXlyKSldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdyA9IHBvcC5jLmJsYWNrXzV5clt3aGljaCghaXMubmEocG9wLmMuYmxhY2tfNXlyKSldLCBuYS5ybT1UKSkpDQoNCmRmX2NyaW1lLnRvdGFsXzIwMTUgPC0gZGZbLGMoIkdyb3VwIiwgY3JpbWVSYXRlLnRvdGFsXzIwMTUsICJwb3AuYy50b3RhbCIpXSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShHcm91cCkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlX2F0KGNyaW1lUmF0ZS50b3RhbF8yMDE1LCBmdW5zKHdlaWdodGVkLm1lYW4oLlt3aGljaCghaXMubmEocG9wLmMudG90YWwpKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdyA9IHBvcC5jLnRvdGFsW3doaWNoKCFpcy5uYShwb3AuYy50b3RhbCkpXSwgbmEucm09VCkpKQ0KDQpkZl9jcmltZS5XSF8yMDE1IDwtIGRmWyxjKCJHcm91cCIsIGNyaW1lUmF0ZS5XSF8yMDE1LCAicG9wLmMuV0giICldICU+JSANCiAgZHBseXI6Omdyb3VwX2J5KEdyb3VwKSAlPiUgDQogIGRwbHlyOjpzdW1tYXJpc2VfYXQoY3JpbWVSYXRlLldIXzIwMTUsIGZ1bnMod2VpZ2h0ZWQubWVhbiguW3doaWNoKCFpcy5uYShwb3AuYy5XSCkpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ID0gcG9wLmMuV0hbd2hpY2goIWlzLm5hKHBvcC5jLldIKSldLCBuYS5ybT1UKSkpDQoNCmRmX2NyaW1lLkJsYWNrXzIwMTUgPC0gZGZbLGMoIkdyb3VwIiwgY3JpbWVSYXRlLkJsYWNrXzIwMTUsICJwb3AuYy5ibGFjayIgKV0gJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoR3JvdXApICU+JSANCiAgZHBseXI6OnN1bW1hcmlzZV9hdChjcmltZVJhdGUuQmxhY2tfMjAxNSwgZnVucyh3ZWlnaHRlZC5tZWFuKC5bd2hpY2goIWlzLm5hKHBvcC5jLmJsYWNrKSldLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBwb3AuYy5ibGFja1t3aGljaCghaXMubmEocG9wLmMuYmxhY2spKV0sIG5hLnJtPVQpKSkNCg0KIyNGaW5hbGx5LCBjYWxjdWxhdGUgcmFjZS1zcGVjaWZpYyByYXRlcyBvZiBtZWRpYW4gaW5jb21lIGFuZCBwb3ZlcnR5IG92ZXIgNXlyIHBlcmlvZA0KZGZfc2VzX3doaXRlX2hpc3BhbmljIDwtIGRmWyxjKCJHcm91cCIsICJtZWRpYW5JbmNvbWVfd2hpdGVfbmgiICwgInBvdmVydHlfd2hpdGVfbmgiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWVkaWFuSW5jb21lX2hpc3AiICwgICJwb3ZlcnR5X2hpc3BhbmljIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicG9wLmMud2hpdGVfbmhfNXlyIiwgInBvcC5jLmhpc3BhbmljXzV5ciIpXSAlPiUgDQogIGRwbHlyOjpncm91cF9ieShHcm91cCkgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKA0KICAgIG1lZGlhbkluY29tZV93aGl0ZV9uaCA9IHdlaWdodGVkLm1lYW4obWVkaWFuSW5jb21lX3doaXRlX25oW3doaWNoKCFpcy5uYShwb3AuYy53aGl0ZV9uaF81eXIpKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdyA9IHBvcC5jLndoaXRlX25oXzV5clt3aGljaCghaXMubmEocG9wLmMud2hpdGVfbmhfNXlyKSldLCBuYS5ybT1UKSwNCiAgICAgICAgICAgICAgICAgICANCiAgICBwb3ZlcnR5X3doaXRlX25oID0gd2VpZ2h0ZWQubWVhbihwb3ZlcnR5X3doaXRlX25oW3doaWNoKCFpcy5uYShwb3AuYy53aGl0ZV9uaF81eXIpKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBwb3AuYy53aGl0ZV9uaF81eXJbd2hpY2goIWlzLm5hKHBvcC5jLndoaXRlX25oXzV5cikpXSwgbmEucm09VCksDQogICAgICAgICAgICANCiAgICBtZWRpYW5JbmNvbWVfaGlzcCA9IHdlaWdodGVkLm1lYW4obWVkaWFuSW5jb21lX2hpc3Bbd2hpY2goIWlzLm5hKHBvcC5jLmhpc3BhbmljXzV5cikpXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBwb3AuYy5oaXNwYW5pY181eXJbd2hpY2goIWlzLm5hKHBvcC5jLmhpc3BhbmljXzV5cikpXSwgbmEucm09VCksDQogICAgICAgICAgICANCiAgICBwb3ZlcnR5X2hpc3BhbmljID0gd2VpZ2h0ZWQubWVhbihwb3ZlcnR5X2hpc3BhbmljW3doaWNoKCFpcy5uYShwb3AuYy5oaXNwYW5pY181eXIpKV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHcgPSBwb3AuYy5oaXNwYW5pY181eXJbd2hpY2goIWlzLm5hKHBvcC5jLmhpc3BhbmljXzV5cikpXSwgbmEucm09VCkgICkNCg0KIyNDT01CSU5FIEFMTCBEQVRBU0VUUw0KZGZfbmV3IDwtIGRwbHlyOjpsZWZ0X2pvaW4oZGZfaWQsIGRmX3N1bXMpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihkZl93TWVhbi50b3RhbF81eXIpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihkZl93TWVhbi5XSF81eXIpICU+JSANCiAgZHBseXI6OmxlZnRfam9pbihkZl93TWVhbi5CbGFja181eXIpICU+JQ0KICBkcGx5cjo6bGVmdF9qb2luKGRmX2NyaW1lLnRvdGFsXzIwMTUpICU+JQ0KICBkcGx5cjo6bGVmdF9qb2luKGRmX2NyaW1lLldIXzIwMTUgKSAlPiUNCiAgZHBseXI6OmxlZnRfam9pbihkZl9jcmltZS5CbGFja18yMDE1KSAlPiUNCiAgZHBseXI6OmxlZnRfam9pbihkZl9zZXNfd2hpdGVfaGlzcGFuaWMpICU+JSANCiAgZHBseXI6Om11dGF0ZSgNCiAgICB1bmVtcGxveW1lbnRSYXRlXzV5ciA9IHVuZW1wbG95ZWRfNXlyL2xhYm9yRm9yY2VfNXlyLA0KICAgIHNpbmdsZVBhcmVudF9wcmNudCA9IHNpbmdsZVBhcmVudC90b3RhbEZhbWlsaWVzDQogICkNCg0KDQojI0NBbGN1bGF0ZSBwcmluY2lwbGUgY29tcG9uZW50cyAtIENyaW1lIGFuZCBTRVMNCiMjMS4gIENyaW1lDQp0b3RhbENyaW1lIDwtIGRmX25ld1ssYygiR3JvdXAiLCAibXVyZGVyX3JfNXlyIiwgICJkdWlfcl81eXIiLCAidmNfcl81eXIiLCAidGhlZnRfcl81eXIiLCAidmFuZGFsX3JfNXlyIiwgImRydWdzX3JfNXlyIiApXQ0KdG90YWxDcmltZSA8LSB0b3RhbENyaW1lW2NvbXBsZXRlLmNhc2VzKHRvdGFsQ3JpbWUpLF0gDQpwY19jcmltZSA8LSAgcHJjb21wKH4gbXVyZGVyX3JfNXlyICsgdmNfcl81eXIgKyBkdWlfcl81eXIgICsgdmFuZGFsX3JfNXlyICsgdGhlZnRfcl81eXIgKyBkcnVnc19yXzV5ciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT10b3RhbENyaW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlLiA9IFQsIGNlbnRlcj1UUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLmFjdGlvbj1uYS5vbWl0KQ0KdG90YWxDcmltZSRwYzFDcmltZSA8LSBwY19jcmltZSR4WywxXQ0KdG90YWxDcmltZSRwYzJDcmltZSA8LSBwY19jcmltZSR4WywyXQ0KdG90YWxDcmltZSA8LSB0b3RhbENyaW1lWyxjKCJHcm91cCIsICJwYzFDcmltZSIsICJwYzJDcmltZSIpXQ0KZGZfbmV3IDwtIGRwbHlyOjpsZWZ0X2pvaW4oZGZfbmV3LCB0b3RhbENyaW1lKQ0KDQojIzIuIFNFUw0KdG90YWxTRVMgPC0gZGZfbmV3WyxjKCJHcm91cCIsICJwb3ZlcnR5IiwgInNpbmdsZVBhcmVudCIsICJtZWRpYW5JbmNvbWUiLCAidW5lbXBsb3ltZW50UmF0ZV81eXIiKV0NCnRvdGFsU0VTIDwtIHRvdGFsU0VTW2NvbXBsZXRlLmNhc2VzKHRvdGFsU0VTKSxdIA0KDQpwY19zZXMgPC0gIHByY29tcCh+IHBvdmVydHkgKyBzaW5nbGVQYXJlbnQgKyBtZWRpYW5JbmNvbWUgKyB1bmVtcGxveW1lbnRSYXRlXzV5ciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YT10b3RhbFNFUywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZS4gPSBULCBjZW50ZXI9VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYS5hY3Rpb249bmEub21pdCkNCg0KdG90YWxTRVMkcGMxU0VTIDwtIHBjX3NlcyR4WywxXQ0KdG90YWxTRVMkcGMyU0VTIDwtIHBjX3NlcyR4WywyXQ0KdG90YWxTRVMgPC0gdG90YWxTRVNbLGMoIkdyb3VwIiwgInBjMVNFUyIsICJwYzJTRVMiKV0NCg0KZGZfbmV3IDwtIGRwbHlyOjpsZWZ0X2pvaW4oZGZfbmV3LCB0b3RhbFNFUykNCg0KcmV0dXJuKGRmX25ldykNCn0NCg0KYGBgDQoNCg0KDQpJIHVzZSB0aGUgYWRqYWNlbmN5IHRhYmxlICdjb3VudHlBZGphY2VudC5jc3YnIEkgZ2VuZXJhdGVkIGZyb20gdGhlIGZpbGUgJ2NyZWF0ZUNvdW50eUFkamFjZW50LlInLiAgDQoNCmh0dHBzOi8vd3d3LmNlbnN1cy5nb3YvZ2VvL3JlZmVyZW5jZS9jb3VudHktYWRqYWNlbmN5Lmh0bWwNCg0KIyNCLiAxMGsgUmVnaW9ucw0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQpkZl8xMGtfaWQgPC0gQWdncmVnYXRlLkNvdW50aWVzKHBvcC50aCA9IDEwMDAwICApDQpyZWFkcjo6d3JpdGVfY3N2KGRmXzEwa19pZCwgImluZGV4X3Rlbl9rLmNzdiIpDQoNCiNXYXBvICYgTG90dC9Nb29keQ0KZGZfV0wgPC0gQWdncmVnYXRlLkNvdW50eS5EYXRhKGtpbGxGaWxlID0gImtpbGxlZF9sb3R0X3dhcG8uY3N2IiwgaW5kZXhGaWxlID0gImluZGV4X3Rlbl9rLmNzdiIpIA0KcmVhZHI6OndyaXRlX2NzdihkZl9XTCwgcGF0aD0ia2lsbGVkX2xvdHRfd2Fwb190ZW5rLmNzdiIpDQoNCmRmX1cgPC0gQWdncmVnYXRlLkNvdW50eS5EYXRhKGtpbGxGaWxlID0gICJraWxsZWRfd2Fwby5jc3YiLCBpbmRleEZpbGUgPSAiaW5kZXhfdGVuX2suY3N2IikgDQpyZWFkcjo6d3JpdGVfY3N2KGRmX1csIHBhdGg9ImtpbGxlZF93YXBvX3RlbmsuY3N2IikNCmBgYA0KDQoNCiMjQy4gIDEwMGsgUmVnaW9ucw0KYGBge3J9DQoNCmRmXzEwMGtfaWQgPC0gQWdncmVnYXRlLkNvdW50aWVzKHBvcC50aCA9IDEwMDAwMCAgKQ0KcmVhZHI6OndyaXRlX2NzdihkZl8xMDBrX2lkLCAiaW5kZXgxMDBrLmNzdiIpDQoNCiNXYXBvICYgTG90dC9Nb29keQ0KZGZfV0wgPC0gQWdncmVnYXRlLkNvdW50eS5EYXRhKGtpbGxGaWxlID0gImtpbGxlZF9sb3R0X3dhcG8uY3N2IiwgaW5kZXhGaWxlID0gImluZGV4MTAway5jc3YiKSANCnJlYWRyOjp3cml0ZV9jc3YoZGZfV0wsIHBhdGg9ImtpbGxlZF9sb3R0X3dhcG9fMTAway5jc3YiKQ0KDQpkZl9XIDwtIEFnZ3JlZ2F0ZS5Db3VudHkuRGF0YShraWxsRmlsZSA9ICAia2lsbGVkX3dhcG8uY3N2IiwgaW5kZXhGaWxlID0gImluZGV4MTAway5jc3YiKSANCnJlYWRyOjp3cml0ZV9jc3YoZGZfVywgcGF0aD0ia2lsbGVkX3dhcG9fMTAway5jc3YiKQ0KYGBgDQoNCiMjRC4gIDEgTUlMTElPTiBSZWdpb24NCmBgYHtyfQ0KDQpkZl8xTV9pZCA8LSBBZ2dyZWdhdGUuQ291bnRpZXMocG9wLnRoID0gMWUwNiApDQpyZWFkcjo6d3JpdGVfY3N2KGRmXzFNX2lkLCAiaW5kZXhfMU1pbGxpb24uY3N2IikNCg0KI1dhcG8gJiBMb3R0L01vb2R5DQpkZl9XTCA8LSBBZ2dyZWdhdGUuQ291bnR5LkRhdGEoa2lsbEZpbGUgPSAia2lsbGVkX2xvdHRfd2Fwby5jc3YiLCBpbmRleEZpbGUgPSAiaW5kZXhfMU1pbGxpb24uY3N2IikgDQpyZWFkcjo6d3JpdGVfY3N2KGRmX1dMLCBwYXRoPSJraWxsZWRfbG90dF93YXBvXzFNLmNzdiIpDQoNCmRmX1cgPC0gQWdncmVnYXRlLkNvdW50eS5EYXRhKGtpbGxGaWxlID0gICJraWxsZWRfd2Fwby5jc3YiLCBpbmRleEZpbGUgPSAiaW5kZXhfMU1pbGxpb24uY3N2IikgDQpyZWFkcjo6d3JpdGVfY3N2KGRmX1csIHBhdGg9ImtpbGxlZF93YXBvXzFNLmNzdiIpDQoNCg0KDQpgYGANCg0KIyNFLiBTVEFURVMNCmBgYHtyfQ0KZGZfaWRfc3RhdGUgPC0gZnN0OjpyZWFkLmZzdChwYXRoPSJjb3VudHlWYXJzX2YuY3N2IikgJT4lIA0KICBkcGx5cjo6Z3JvdXBfYnkoRklQUykgJT4lIA0KICBkcGx5cjo6c3VtbWFyaXNlKEdyb3VwID0gZmlyc3Qoc3RhdGUpKQ0KDQpyZWFkcjo6d3JpdGVfY3N2KGRmX2lkX3N0YXRlLCAiaW5kZXhfc3RhdGUuY3N2IikNCg0KI1dhcG8gJiBMb3R0L01vb2R5DQpkZl9XTCA8LSBBZ2dyZWdhdGUuQ291bnR5LkRhdGEoa2lsbEZpbGUgPSAia2lsbGVkX2xvdHRfd2Fwby5jc3YiLCBpbmRleEZpbGUgPSAiaW5kZXhfc3RhdGUuY3N2IikgDQpyZWFkcjo6d3JpdGVfY3N2KGRmX1dMLCBwYXRoPSJraWxsZWRfbG90dF93YXBvX1N0YXRlLmNzdiIpDQoNCmRmX1cgPC0gQWdncmVnYXRlLkNvdW50eS5EYXRhKGtpbGxGaWxlID0gICJraWxsZWRfd2Fwby5jc3YiLCBpbmRleEZpbGUgPSAiaW5kZXhfc3RhdGUuY3N2IikgDQpyZWFkcjo6d3JpdGVfY3N2KGRmX1csIHBhdGg9ImtpbGxlZF93YXBvX1N0YXRlLmNzdiIpDQoNCmBgYA0KDQo=