This initial chunk sets the working directory, loads necessary libraries, and imports all the raw data files (.csv and .xlsx) that will be used for the subsequent National IQ (NIQ) data harmonization and analysis.

##################################################################s-factor
#setwd('~')
library('readxl')
#setwd('rfolder/bestNIQs/data')

agri <- read.csv("data/agri.csv")
basicskills <- read.csv("data/basicskills.csv")
becker <- read.csv("data/becker.csv")
becker$alpha3[becker$alpha3=='KNA.'] <- 'KNA'
calories <- read.csv("data/calories.csv")
ce2 <- read.csv("data/ce2.csv")
CIAGDP <- read.csv("data/CIAGDP.csv")
circ2 <- read.csv("data/circ2.csv")
doi_total <- read.csv("data/doi_total.csv")
GNInPPPIMF <- read.csv("data/GNInPPPIMF.csv")
GNIPPPIMF <- read.csv("data/GNIPPPIMF.csv")
HDI <- read.csv("data/HDI.csv")

health <- read.csv("data/health.csv")
ict <- read.csv("data/ict.csv")
isp <- read.csv("data/internet-speeds-by-country-2024.csv")
meanages <- read.csv("data/meanages.csv")
medianincome <- read.csv("data/medianincome.csv")
medianwealth <- read.csv("data/medianwealth.csv")
mega <- read.csv("data/mega.csv")
newdata <- read.csv("data/newdata.csv")
PIRLS2021 <- read.csv("data/PIRLS2021.csv")
pisa <- read.csv("data/pisa.csv")
oil <- read.csv('data/worldoil.csv')
SPI <- read.csv("data/SPI.csv")
techexp <- read.csv("data/techexp.csv")
testscores <- read.csv("data/testscores.csv")
timss4m <- read.csv("data/timss4thmath.csv")
timss8m <- read.csv("data/timssmath8th.csv")
timss4s <- read.csv("data/timsssci4th.csv")
timss8s <- read.csv("data/timss8thsci.csv")
WBGDP <- read.csv("data/WBGDP.csv")
allniq <- read_excel("data/allniq.xlsx")
New names:
IMFGDP <- read_excel("data/IMFGDP.xls")
hssiqs <- read.csv('data/hssiq.csv')

This section performs the crucial step of cleaning and harmonizing various international test score and estimated IQ datasets (e.g., Harmonized Test Scores, PISA, TIMSS, Rinder’s estimates) into a standardized IQ scale.

#############################
#IQ data cleaning
hts <- testscores %>% filter(Indicator == 'Harmonized Test Scores')

hts$mean = rowMeans(subset(hts, select=c(X2010, X2017, X2018, X2020)), na.rm = TRUE)
hts$wbtestscore = (hts$mean - 529.5)/100*15+100
hts$t2020 <- hts$X2020

hts <- hts %>% select(wbtestscore, Country.ISO3)
nit <- allniq %>% select(CA_totc, SAS_IQc, countrycode)
nit$RinderIQ <- as.numeric(nit$CA_totc)
Warning: NAs introduced by coercion
nit$RinderSAS <- as.numeric(nit$SAS_IQc)
Warning: NAs introduced by coercion
basicskills$bs <- (basicskills$Mean - 514.8)/100*15+100
basicskills$alpha3 <- countrycode(basicskills$Country, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously: Kosovo
basicskills$alpha3[basicskills$Country=='Kosovo'] <- 'KSV'

bs <- basicskills %>% filter(!Data.layer=='5') %>% select(bs, alpha3)

pisa$alpha3 <- countrycode(pisa$cmtry, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously: Kosovo
pisa$alpha3[pisa$cmtry=='Kosovo'] <- 'KSV'
becker$alpha3[becker$alpha3=='FRA '] <- 'FRA'
pisa$pisa2 <- (pisa$pisa-505.8)/100*15+100

timss4m$alpha3 <- countrycode(timss4m$country, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously:  Kosovo
timss4m$alpha3[48] <- 'KSV'
timss4m$alpha3[timss4m$country=='England'] <- 'GBR'
timss4m$T4mIQ <- (timss4m$score-535)/100*15 + 97.3

timss4s$alpha3 <- countrycode(timss4s$country, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously:  England,  Kosovo
timss4s$alpha3[51] <- 'KSV'
timss4s$alpha3[12] <- 'GBR'
timss4s$T4sIQ <- (timss4s$sci4thtimss-542.333)/100*15 + 100

timss8m$alpha3 <- countrycode(timss8m$country, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously:  England
timss8m$alpha3[13] <- 'GBR'
timss8m$T8mIQ <- (timss8m$math8th-520.33333)/100*15 + 100

timss8s$alpha3 <- countrycode(timss8s$country, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously:  England
timss8s$alpha3[14] <- 'GBR'
timss8s$T8sIQ <- (timss8s$timss8thsci-522.33333)/100*15 + 100

PIRLS2021$alpha3 <- countrycode(PIRLS2021$country, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously:  Kosovo
PIRLS2021$alpha3[50] <- 'KSV'
PIRLS2021$PRLIQ <- (PIRLS2021$score-562.33333)/100*15 + 100

t4m <- timss4m %>% select(alpha3, T4mIQ)
t4s <- timss4s %>% select(alpha3, T4sIQ)
t8m <- timss8m %>% select(alpha3, T8mIQ)
t8s <- timss8s %>% select(alpha3, T8sIQ)
p21 <- PIRLS2021 %>% select(alpha3, PRLIQ)

niqs1 <- full_join(becker, hts, by = join_by(alpha3 == Country.ISO3))
niqs2 <- full_join(niqs1, pisa, by = join_by(alpha3 == alpha3))
niqs3 <- full_join(niqs2, bs, by = join_by(alpha3 == alpha3))
niqs4 <- full_join(niqs3, nit, by = join_by(alpha3 == countrycode))
niqs5 <- full_join(niqs4, t4m, by = join_by(alpha3 == alpha3))
niqs6 <- full_join(niqs5, t4s, by = join_by(alpha3 == alpha3))
niqs7 <- full_join(niqs6, t8m, by = join_by(alpha3 == alpha3))
niqs8 <- full_join(niqs7, t8s, by = join_by(alpha3 == alpha3))
niqs9 <- full_join(niqs8, p21, by = join_by(alpha3 == alpha3))

This chunk performs final adjustments, aggregations, and regional grouping on the merged dataset.

niqs9$R[is.na(niqs9$UW) & is.na(niqs9$NW) & is.na(niqs9$QNW) & is.na(niqs9$SAS)] <- NA
onlyscores <- data.frame(niqs9 %>% select(UW, T4mIQ, T4sIQ, T8sIQ, T8mIQ, PRLIQ, QNW, NW, SAS, L.V12, R, wbtestscore, RinderIQ, RinderSAS, pisa2, bs, L.V02, alpha3))
onlyscores$SAS <- onlyscores$SAS - 1.74 + 1
onlyscores$NW <- onlyscores$NW - 1 + 1
onlyscores$UW <- onlyscores$UW + 1
onlyscores$bs <- onlyscores$bs + 1
onlyscores$pisa2 <- onlyscores$pisa2 + 1
onlyscores$wbtestscore <- onlyscores$wbtestscore + 1
onlyscores$QNW <- onlyscores$QNW - 1 + 1
onlyscores$L.V12 <- onlyscores$L.V12 - 0.84 + 1
onlyscores$L.V02 <- onlyscores$L.V02 - 0.84
onlyscores$RinderIQ <- onlyscores$RinderIQ - 0.74
onlyscores$RinderSAS <- onlyscores$RinderSAS - 0.74
onlyscores$OM = rowMeans(subset(onlyscores, select=c(RinderSAS, RinderIQ, L.V02, L.V12, QNW, wbtestscore, pisa2, bs, UW, NW, SAS, QNW)), na.rm = TRUE)
onlyscores$R <- onlyscores$R - 1.74 + 1

onlyscores$region <- countrycode(onlyscores$alpha3, origin='iso3c', destination='un.regionsub.name')
Warning: Some values were not matched unambiguously: ANT, KSV, TWN
onlyscores$region[onlyscores$alpha3=='KSV'] <- 'Southern Europe'
onlyscores$region[onlyscores$alpha3=='TWN'] <- 'Eastern Asia'
onlyscores <- onlyscores %>% filter(!is.na(region))
onlyscores$region[onlyscores$alpha3=='KNA'] <- NA
###################################
################################
byreg <- onlyscores %>%
  group_by(region) %>%
  summarise(RIQ = mean(RinderIQ, na.rm=T), BSD = mean(bs, na.rm=T), WBTS = mean(wbtestscore, na.rm=T), PISA = mean(pisa2, na.rm=T), RSAS = mean(RinderSAS, na.rm=T), BQNW = mean(QNW, na.rm=T), BSAS = mean(SAS, na.rm=T), LV12 = mean(L.V12, na.rm=T), LV02 = mean(L.V02, na.rm=T), BOR = mean(R, na.rm=T))

print(byreg, n=20)

Charting the relationship between mean and standard error (simple method)

##################################
longer <- onlyscores %>% select(T4mIQ, T4sIQ, T8sIQ, T8mIQ, PRLIQ, QNW, RinderSAS, pisa2, alpha3)

long_format <- longer %>%
  gather(key = "Measure", value = "Value", -alpha3)

long_format$se <- 1/sqrt(350)

uniques <- unique(onlyscores$alpha3)

rs <- rep(0, length(uniques))
with_se <- data.frame(uniques, rs)

for(i in 1:length(uniques)) {
  f <- long_format %>% filter(alpha3==uniques[i] & !is.na(Value))
  if (nrow(f) > 1) {
    metaobjn <- metafor::rma(yi=Value, sei=se, data = f)
    with_se$mean[i] <- metaobjn$b
    with_se$se[i] <- metaobjn$se
  } 
  else if (nrow(f) == 1) {
    with_se$mean[i] <- mean(f$Value)
    with_se$se[i] <- NA
  } 
  else {
    with_se$mean[i] <- NA
    with_se$se[i] <- NA
  }
}

p <- GG_scatter(with_se, 'mean', 'se', case_names='uniques')  +
  xlab('Mean') +
  ylab('Standard Error') +
  theme_bw() +
  theme(
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.position = "right",
    plot.background = element_rect(fill = "white")
  )
p
file_name = 'output/ropz.jpg'
ggsave(plot = p, filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

Charting the relationship between psychometric and scholastic ability

p <- GG_scatter(onlyscores, 'UW', 'bs', case_names='alpha3')  +
  xlab('IQ Based on Pychometric Data (From Becker)') +
  ylab('Scholastic Ability Based on Basic Skills Dataset') +
  theme_bw() +
  theme(
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.position = "right",
    plot.background = element_rect(fill = "white")
  )
p

file_name = 'output/ropzicle.jpg'
ggsave(plot = p, filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

Calculation of meta-analytic means.

########################################
onlyscores2 <- data.frame(onlyscores %>% select(UW, QNW, NW, SAS, L.V12, R, T4mIQ, T4sIQ, T8sIQ, T8mIQ, PRLIQ, wbtestscore, RinderIQ, RinderSAS, pisa2, bs, L.V02, alpha3))
#onlyscores2 <- onlyscores2 %>% filter(!(alpha3 %in% (unique(newdata$alpha3))))

onlyscores2$nest2 = rowMeans(subset(onlyscores2, select=c(T4mIQ, T8mIQ, QNW, UW, NW, SAS, L.V02, L.V12, R)), na.rm = TRUE)
onlyscores2$nest3 = rowMeans(subset(onlyscores2, select=c(nest2, T4sIQ, T8sIQ)), na.rm = TRUE)
onlyscores2$nest4 = rowMeans(subset(onlyscores2, select=c(nest3, pisa2, RinderSAS, wbtestscore, PRLIQ)), na.rm = TRUE)
onlyscores2$NIQtemp1 = rowMeans(subset(onlyscores2, select=c(nest4, bs, RinderIQ)), na.rm = TRUE)
onlyscores2$revised <- 0

###########################
#Meta-analytic means
longer <- onlyscores %>% select(UW, QNW, NW, SAS, L.V12, R, T4mIQ, T4sIQ, T8sIQ, T8mIQ, PRLIQ, wbtestscore, RinderIQ, RinderSAS, pisa2, bs, L.V02, alpha3)
long_format <- longer %>%
  gather(key = "Measure", value = "Value", -alpha3)

long_format$se <- NA
long_format$se[long_format$Measure=='UW'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='NW'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='QNW'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='T4mIQ'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='T8mIQ'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='R'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='SAS'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='T4sIQ'] <- 15/sqrt(125)
long_format$se[long_format$Measure=='T8sIQ'] <- 15/sqrt(125)
long_format$se[long_format$Measure=='L.V02'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='L.V12'] <- 15/sqrt(50)
long_format$se[long_format$Measure=='PRLIQ'] <- 15/sqrt(250)
long_format$se[long_format$Measure=='pisa2'] <- 15/sqrt(250)
long_format$se[long_format$Measure=='wbtestscore'] <- 15/sqrt(500)
long_format$se[long_format$Measure=='RinderSAS'] <- 15/sqrt(250)
long_format$se[long_format$Measure=='bs'] <- 15/sqrt(750)
long_format$se[long_format$Measure=='RinderIQ'] <- 15/sqrt(750)

uniques <- unique(onlyscores$alpha3)

mean <- rep(0, length(uniques))
with_se <- data.frame(uniques, mean)

for(i in 1:length(uniques)) {
  f <- long_format %>% filter(alpha3==uniques[i] & !is.na(Value))
  if (nrow(f) > 1) {
    metaobjn <- metafor::rma(yi=Value, sei=se, data = f)
    with_se$mean[i] <- metaobjn$b
    with_se$se[i] <- metaobjn$se
  } 
  else if (nrow(f) == 1) {
    with_se$mean[i] <- mean(f$Value)
    with_se$se[i] <- NA
  } 
  else {
    with_se$mean[i] <- NA
    with_se$se[i] <- NA
  }
}

Regression models predicting standard errors based on means and sample sizes.


long_format <- longer %>%
  gather(key = "Measure", value = "Value", -alpha3)

with_se <- long_format %>% group_by(alpha3) %>% summarise(mean = mean(Value, na.rm=T), se = sd(Value, na.rm=T)/sqrt(sum(!is.na(Value))), n = sum(!is.na(Value)))

lr <- lm(data=with_se, se ~ mean)
summary(lr)

Call:
lm(formula = se ~ mean, data = with_se)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.5236 -0.6971 -0.2905  0.3537  9.3262 

Coefficients:
             Estimate Std. Error t value             Pr(>|t|)    
(Intercept)  7.429649   0.732361   10.14 < 0.0000000000000002 ***
mean        -0.068579   0.008725   -7.86    0.000000000000331 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.309 on 181 degrees of freedom
  (28 observations deleted due to missingness)
Multiple R-squared:  0.2545,    Adjusted R-squared:  0.2504 
F-statistic: 61.79 on 1 and 181 DF,  p-value: 0.0000000000003313
lr <- lm(data=with_se, se ~ n)
summary(lr)

Call:
lm(formula = se ~ n, data = with_se)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.9796 -0.6665 -0.0802  0.5470  8.1964 

Coefficients:
            Estimate Std. Error t value            Pr(>|t|)    
(Intercept)   3.5552     0.2014   17.65 <0.0000000000000002 ***
n            -0.1939     0.0191  -10.15 <0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.21 on 181 degrees of freedom
  (28 observations deleted due to missingness)
Multiple R-squared:  0.3628,    Adjusted R-squared:  0.3593 
F-statistic: 103.1 on 1 and 181 DF,  p-value: < 0.00000000000000022
lr <- lm(data=with_se, se ~ mean + n)
summary(lr)

Call:
lm(formula = se ~ mean + n, data = with_se)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.9508 -0.6304 -0.1386  0.5679  8.3803 

Coefficients:
            Estimate Std. Error t value         Pr(>|t|)    
(Intercept)  5.48373    0.73417   7.469 0.00000000000336 ***
mean        -0.02793    0.01024  -2.728          0.00701 ** 
n           -0.15200    0.02425  -6.269 0.00000000261139 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.189 on 180 degrees of freedom
  (28 observations deleted due to missingness)
Multiple R-squared:  0.3881,    Adjusted R-squared:  0.3813 
F-statistic: 57.08 on 2 and 180 DF,  p-value: < 0.00000000000000022

Calculation of meta-analytic means (again).

onlyscores2 <- data.frame(onlyscores %>% select(UW, QNW, NW, SAS, L.V12, R, T4mIQ, T4sIQ, T8sIQ, T8mIQ, PRLIQ, wbtestscore, RinderIQ, RinderSAS, pisa2, bs, L.V02, alpha3))
#onlyscores2 <- onlyscores2 %>% filter(!(alpha3 %in% (unique(newdata$alpha3))))

onlyscores2$nest1 = rowMeans(subset(onlyscores2, select=c(QNW, NW, UW, T4mIQ, T8mIQ, L.V02, L.V12, SAS, R)), na.rm = TRUE)
onlyscores2$nest2 = rowMeans(subset(onlyscores2, select=c(nest1, T4sIQ, T8sIQ)), na.rm = TRUE)
onlyscores2$nest3 = rowMeans(subset(onlyscores2, select=c(nest2, pisa2, wbtestscore, RinderSAS, PRLIQ)), na.rm = TRUE)
onlyscores2$NIQtemp1 = rowMeans(subset(onlyscores2, select=c(nest3, RinderIQ, bs)), na.rm = TRUE)
onlyscores2$revised <- 0
###########################
#Meta-analytic means
longer <- onlyscores %>% select(UW, QNW, NW, SAS, L.V12, R, T4mIQ, T4sIQ, T8sIQ, T8mIQ, PRLIQ, wbtestscore, RinderIQ, RinderSAS, pisa2, bs, L.V02, alpha3)
long_format <- longer %>%
  gather(key = "Measure", value = "Value", -alpha3)

long_format$se <- NA
long_format$se[long_format$Measure=='UW'] <- 15/sqrt(10)
long_format$se[long_format$Measure=='NW'] <- 15/sqrt(10)
long_format$se[long_format$Measure=='QNW'] <- 15/sqrt(10)
long_format$se[long_format$Measure=='T4mIQ'] <- 15/sqrt(10)
long_format$se[long_format$Measure=='T8mIQ'] <- 15/sqrt(10)
long_format$se[long_format$Measure=='R'] <- 15/sqrt(20)
long_format$se[long_format$Measure=='SAS'] <- 15/sqrt(20)
long_format$se[long_format$Measure=='T4sIQ'] <- 15/sqrt(20)
long_format$se[long_format$Measure=='T8sIQ'] <- 15/sqrt(20)
long_format$se[long_format$Measure=='L.V02'] <- 15/sqrt(20)
long_format$se[long_format$Measure=='L.V12'] <- 15/sqrt(20)
long_format$se[long_format$Measure=='PRLIQ'] <- 15/sqrt(40)
long_format$se[long_format$Measure=='pisa2'] <- 15/sqrt(40)
long_format$se[long_format$Measure=='wbtestscore'] <- 15/sqrt(40)
long_format$se[long_format$Measure=='RinderSAS'] <- 15/sqrt(40)
long_format$se[long_format$Measure=='bs'] <- 15/sqrt(80)
long_format$se[long_format$Measure=='RinderIQ'] <- 15/sqrt(80)

long_format$se2 <- 15/sqrt(350)

uniques <- unique(onlyscores$alpha3)

mean <- rep(0, length(uniques))
with_se <- data.frame(uniques, mean)

for(i in 1:length(uniques)) {
  f <- long_format %>% filter(alpha3==uniques[i] & !is.na(Value))
  if (nrow(f) > 1) {
    metaobjn <- metafor::rma(yi=Value, sei=se, data = f)
    metaobjn2 <- metafor::rma(yi=Value, sei=se2, data = f)
    with_se$mean[i] <- metaobjn$b
    with_se$se[i] <- sd(f$Value)/sqrt(nrow(f %>% filter(!is.na(Value))))
  } 
  else if (nrow(f) == 1) {
    with_se$mean[i] <- mean(f$Value)
    with_se$se[i] <- NA
  } 
  else {
    with_se$mean[i] <- NA
    with_se$se[i] <- NA
  }
}

Calculation of final means.

########################################PSY##SCH########################################PSY##############################
nd <- newdata %>% select(alpha3, NIQr)
nd <- na.omit(nd)
rop2 <- with_se %>% select(uniques, se, mean)
onlyscores4 <- full_join(onlyscores2, rop2, by = join_by(alpha3 == uniques))
onlyscores4 <- full_join(onlyscores4, nd, by = join_by(alpha3 == alpha3))
onlyscores4 <- onlyscores4 %>% select(UW, QNW, NW, SAS, L.V12, R, NIQr, NIQtemp1, wbtestscore, RinderIQ, RinderSAS, mean, se, pisa2, bs, L.V02, alpha3)
onlyscores4$seadj <- onlyscores4$se*2.32/mean(with_se$se, na.rm=T)

onlyscores4$region <- countrycode(onlyscores4$alpha3, origin='iso3c', destination='un.regionsub.name')
Warning: Some values were not matched unambiguously: KSV, TWN
onlyscores4$region[onlyscores4$alpha3=='KSV'] <- 'Southern Europe'
onlyscores4$region[onlyscores4$alpha3=='TWN'] <- 'Eastern Asia'
onlyscores4$alpha3[onlyscores4$alpha3=='KNA.'] <- NA
onlyscores4$region[onlyscores4$alpha3=='KNA'] <- 'Latin America and the Caribbean'

onlyscores4$NIQt <- (onlyscores4$NIQtemp1 + onlyscores4$mean)/2
onlyscores4$NIQ <- (onlyscores4$NIQtemp1 + onlyscores4$mean)/2
onlyscores4$revised <- 0
onlyscores4$revised[onlyscores4$alpha3 %in% unique(nd$alpha3)] <- 1

onlyscores4$NIQ[onlyscores4$revised==1] <- onlyscores4$NIQr[onlyscores4$revised==1]

tviqs <- onlyscores4 %>% select(NIQ, mean, NIQtemp1, alpha3, NIQt, NIQr)
tviqs$name <- countrycode(tviqs$alpha3, origin='iso3c', destination='country.name')
Warning: Some values were not matched unambiguously: KSV
revisedlist <- tviqs %>% select(name, NIQt, NIQr) %>% filter(!is.na(NIQr))

Europe IQ map.

library(ggplot2)
library(dplyr)
library(maps)
library(countrycode)

world_map <- map_data("world")
world_map$alpha3 <- countrycode(world_map$region, origin = "country.name", destination = "iso3c")
Warning: Some values were not matched unambiguously: Ascension Island, Azores, Barbuda, Bonaire, Canary Islands, Chagos Archipelago, Grenadines, Heard Island, Kosovo, Madeira Islands, Micronesia, Saba, Saint Martin, Siachen Glacier, Sint Eustatius, Virgin Islands
onlyb <- onlyscores4 %>% filter(!is.na(alpha3))

world_map$alpha3[world_map$region == "Kosovo"] <- "KSV"
world_map_data <- left_join(world_map, onlyb, by = c('alpha3'))

# Define IQ bins and colors
world_map_data$color_category <- cut(world_map_data$NIQ, 
                                     breaks = c(-Inf, 85, 88, 91, 94, 97, 100, Inf),
                                     labels = c('=< 85', '85 to 88', '88 to 91', '91 to 94', '94 to 97', '97 to 100', '> 100'),
                                     right = TRUE)

europe_bounds <- c(-25, 50, 35, 70)

# Subset data for Europe
europe_map_data <- world_map_data %>%
  filter(long >= europe_bounds[1], long <= europe_bounds[2],
         lat >= europe_bounds[3], lat <= europe_bounds[4])

# Plotting
p_europe <- ggplot(data = europe_map_data, aes(x = long, y = lat, group = group, fill = color_category)) +
  geom_polygon(color = "black") +
  scale_fill_manual(name = "IQ",
                    values = c("=< 85" = "orange2",
                               "85 to 88" = "#FFDD55",
                               "88 to 91" = "#FFEECC",
                               "91 to 94" = "#CCEEFF",
                               "94 to 97" = "#66CCFF",
                               "97 to 100" = "#4477EE",
                               "> 100" = "#4422AA")) +
  theme_minimal() +
  theme(plot.background = element_rect(fill = "white"),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_blank()) +
  labs(title = "")

p_europe
file_name <- paste0('output/eumap.png')
ggsave(filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

Chart of Lynn 2002 and current estimates

p <- GG_scatter(onlyscores4, 'NIQ', 'L.V02', case_names='alpha3') + 
  geom_point() + 
  geom_smooth(method = 'lm', se = FALSE, color = 'blue') + 
  labs(x = 'National IQ (Jensen & Kirkegaard, 2024)', y = "National IQ (Lynn and Vanhannen, 2002)") +
  theme_minimal() +
  theme_bw() +
  theme(
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.position = "right",
    plot.background = element_rect(fill = "white")
  )

p
file_name <- paste0('output/lv.jpg')
ggsave(filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

Charting relationship between standard errors and means (final data)

fit2 <- lm(data=onlyscores4, seadj ~ NIQ)
summary(fit2)

Call:
lm(formula = seadj ~ NIQ, data = onlyscores4)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.4387 -0.9795 -0.3994  0.5010 12.5201 

Coefficients:
            Estimate Std. Error t value             Pr(>|t|)    
(Intercept) 10.09143    0.99776  10.114 < 0.0000000000000002 ***
NIQ         -0.09306    0.01185  -7.856     0.00000000000034 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.762 on 181 degrees of freedom
  (28 observations deleted due to missingness)
Multiple R-squared:  0.2543,    Adjusted R-squared:  0.2502 
F-statistic: 61.72 on 1 and 181 DF,  p-value: 0.0000000000003399
fit4 <- lm(data=onlyscores4, seadj ~ ns(NIQ, df=4))
summary(fit4)

Call:
lm(formula = seadj ~ ns(NIQ, df = 4), data = onlyscores4)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.6244 -0.8290 -0.2513  0.4813 12.2187 

Coefficients:
                 Estimate Std. Error t value   Pr(>|t|)    
(Intercept)        3.1397     0.6741   4.658 0.00000623 ***
ns(NIQ, df = 4)1  -1.1289     0.6716  -1.681    0.09455 .  
ns(NIQ, df = 4)2  -2.9789     0.7151  -4.166 0.00004831 ***
ns(NIQ, df = 4)3  -0.8624     1.6543  -0.521    0.60280    
ns(NIQ, df = 4)4  -2.5542     0.9013  -2.834    0.00513 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.729 on 178 degrees of freedom
  (28 observations deleted due to missingness)
Multiple R-squared:  0.2938,    Adjusted R-squared:  0.2779 
F-statistic: 18.51 on 4 and 178 DF,  p-value: 0.0000000000009732
# passes
anova(fit4, fit2)
Analysis of Variance Table

Model 1: seadj ~ ns(NIQ, df = 4)
Model 2: seadj ~ NIQ
  Res.Df    RSS Df Sum of Sq      F Pr(>F)  
1    178 532.08                             
2    181 561.85 -3   -29.778 3.3207 0.0211 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
uzi3 <- seq(from=62, to=109, by=0.01)
uzi4 <- data.frame(NIQ=uzi3)
uzi4$fit = predict(fit4, uzi4, interval = "confidence")

p <- ggplot(uzi4) +
  geom_point(mapping = aes(x=NIQ, y=seadj), data=onlyscores4) +
  geom_line(data = uzi4, aes(x = NIQ, y = fit[, 1]), color = "green", size = 1) +
  geom_ribbon(data = uzi4, aes(x = NIQ, ymin = fit[, 2], ymax = fit[, 3]), alpha = 0.35) + # Confidence interval shading
  geom_text(data = onlyscores4, aes(x = NIQ, y = seadj, label = alpha3), vjust = -.66, size = 3) + # Add country labels
  labs(title = "spearman's rho = -.63, n = 201") +
  xlab('National IQ') +
  ylab('Standard Error') +
  theme_bw() +
  theme(
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 16),
    axis.title.y = element_text(size = 16),
    legend.position = "right",
    plot.background = element_rect(fill = "white")
  )
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.
plot(p)

file_name <- paste0('output/sechart.jpg')
ggsave(plot = p, filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

Charting the relationship between WB test scores and Lynn 2002 estimates.

p <- GG_scatter(onlyscores4, 'wbtestscore', 'L.V02', case_names='alpha3') + 
  geom_point() + 
  geom_smooth(method = 'lm', se = FALSE, color = 'blue') + 
  labs(x = 'World Bank Test Scores', y = "National IQ (Lynn and Vanhannen, 2002)") +
  theme_minimal() +
  theme_bw() +
  theme(
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.position = "right",
    plot.background = element_rect(fill = "white")
  )
p
file_name <- paste0('output/lv2.jpg')
ggsave(filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

Grouping the GDP data together.

HDIGDP <- HDI %>% select(iso3, gnipc_2021, gnipc_2020, gnipc_2019, gnipc_2018)
IMFGDP$alpha3 <- countrycode(IMFGDP[, 1] %>% unlist(), origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously: Australia and New Zealand, Kosovo, Timor
Warning: Some strings were matched more than once, and therefore set to <NA> in the result: Australia and New Zealand,AUS,NZL
IMFGDP$alpha3[IMFGDP[, 1]=='Kosovo'] <- 'KSV'
IMFGDP$alpha3[IMFGDP[, 1]=='Timor'] <- 'TLS'
IMFGDP$alpha3[IMFGDP[, 1]=='Timor'] <- 'TLS'
IMFGDP$alpha3[IMFGDP[, 1]=='Australia and New Zealand'] <- 'NZL'

IMFGDP$gdp2022 <- as.numeric(IMFGDP[, 44] %>% unlist())
Warning: NAs introduced by coercion
IMFGDP$gdp2021 <- as.numeric(IMFGDP[, 43] %>% unlist())
Warning: NAs introduced by coercion
IMFGDP$gdp2020 <- as.numeric(IMFGDP[, 42] %>% unlist())
Warning: NAs introduced by coercion
IMFGDP$gdp2019 <- as.numeric(IMFGDP[, 41] %>% unlist())
Warning: NAs introduced by coercion
IMFGDP$gdp2018 <- as.numeric(IMFGDP[, 40] %>% unlist())
Warning: NAs introduced by coercion
CIAGDP$alpha3 <- countrycode(CIAGDP$name, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously: Kosovo, Saint Martin, Virgin Islands
CIAGDP$alpha3[CIAGDP$name=='Kosovo'] <- 'KSV'
SPI <- SPI %>% filter(spiyear > 2017 & spiyear < 2023)

average_scores <- SPI %>%
  filter(spiyear %in% 2018:2022) %>%  # Filter for the specific years
  group_by(spicountrycode) %>%  # Group by country
  summarise(across(where(is.numeric), ~mean(.x, na.rm = TRUE), .names = "avg_{.col}"))  # Average for each numeric column

#GDP calculations
IMFGDP$gdpimf = rowMeans(subset(IMFGDP, select=c(gdp2018, gdp2019, gdp2020, gdp2021, gdp2022)), na.rm = TRUE)
WBGDP$gdpwb = rowMeans(subset(WBGDP, select=c(X2018, X2019, X2020, X2021, X2022)), na.rm = TRUE)
HDIGDP$gdphdi = rowMeans(subset(HDIGDP, select=c(gnipc_2018, gnipc_2019, gnipc_2020, gnipc_2021)), na.rm = TRUE)
CIAGDP$gdpcia <- as.numeric(gsub("[\\$,]", "", CIAGDP$value))

imf2 <- IMFGDP %>% select(alpha3, gdpimf)
imf2 <- imf2[-135, ]
wb2 <- WBGDP %>% select(Country.Code, gdpwb)
hdi2 <- HDIGDP %>% select(iso3, gdphdi)
cia2 <- CIAGDP %>% select(alpha3, gdpcia)
spi2 <- average_scores %>% select(spicountrycode, avg_GDPpc)

GNIPPPIMF$gnipppimf = rowMeans(subset(GNIPPPIMF, select=c(X2018, X2019, X2020, X2021, X2022)), na.rm = TRUE)
GNIPPPIMF2 <- GNIPPPIMF %>% select(Country.Code, gnipppimf)

medianwealth$wealth <- as.numeric(medianwealth$Median)
Warning: NAs introduced by coercion
medianwealth$alpha3 <- countrycode(medianwealth$Location, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously:  European Union,  Guyana
medianwealth$alpha3[medianwealth$Location=='Guyana'] <- 'GUY'
medianincome$income <- as.numeric(medianincome$medianIncomeByCountry_medianIncome)
medianincome$alpha3 <- countrycode(medianincome$country, origin = 'country.name', destination='iso3c')
Warning: Some values were not matched unambiguously: Micronesia
medianincome$alpha3[medianincome$country=='Micronesia'] <- 'FSM'
mi2 <- medianincome %>% select(alpha3, income)
mw2 <- medianwealth %>% select(alpha3, wealth)

gdpcum <- full_join(imf2, wb2, by = join_by(alpha3 == Country.Code))
gdpcum2 <- full_join(gdpcum, hdi2, by = join_by(alpha3 == iso3))
gdpcum3 <- full_join(gdpcum2, cia2, by = join_by(alpha3 == alpha3))
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
gdpcum4 <- full_join(gdpcum3, spi2, by = join_by(alpha3 == spicountrycode))
gdpcum5 <- full_join(gdpcum4, mi2, by = join_by(alpha3 == alpha3))
gdpcum6 <- full_join(gdpcum5, mw2, by = join_by(alpha3 == alpha3))
Warning: Detected an unexpected many-to-many relationship between `x` and `y`.
gdpcum7 <- full_join(gdpcum6, GNIPPPIMF2, by = join_by(alpha3 == Country.Code))

gdpcum7 <- gdpcum7[-193, ]

gdpcum7 <- gdpcum7 %>% filter(!is.na(alpha3))
gdpcum7 <- gdpcum7[1:269, ]
gdpcum7$gdpspi <- gdpcum7$avg_GDPpc
gdpcum7$gnihdi <- gdpcum7$gdphdi

gdpcum7$GDP = rowMeans(subset(gdpcum7, select=c(gdpwb, gdpcia, gdpimf, gdpspi)), na.rm = TRUE)

esca <- gdpcum7 %>% select(GDP, income, wealth, gnihdi, gnipppimf, alpha3)

Regressing GDP onto NIQ.

forchart <- full_join(tviqs, esca, by = join_by(alpha3 == alpha3))

#VCT and FSM not in original
forchart <- forchart %>% filter(!alpha3=='VCT')
forchart <- forchart %>% filter(!alpha3=='FSM')

p <- GG_scatter(forchart, 'NIQ', 'GDP', case_names='alpha3') + 
  geom_point() + 
  geom_smooth(method = 'lm', se = T, color = 'orange') + 
  geom_smooth(se = T, color = 'blue') + 
  theme_bw() +
  theme(
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.position = "right",
    plot.background = element_rect(fill = "white")
  )
p
file_name <- paste0('output/niqngdp.jpg')
ggsave(filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

onlyscores4$sf <- pnorm((onlyscores4$NIQ-125)/15)

fusedtrans <- left_join(onlyscores4, esca, by='alpha3')

fusedtrans <- fusedtrans %>% filter(!alpha3=='VCT')
fusedtrans <- fusedtrans %>% filter(!alpha3=='FSM')
p2 <- GG_scatter(fusedtrans, 'sf', 'GDP', case_names='alpha3') + labs(x = "Predicted % who score above 125", y = "GDP per capita", title = "") + theme(
  axis.text.x = element_text(size = 12),
  axis.text.y = element_text(size = 12),
  axis.title.x = element_text(size = 15),
  axis.title.y = element_text(size = 15),
  legend.position = "right",
  plot.background = element_rect(fill = "white")
) + geom_smooth()
p2
file_name <- paste0('output/dlift2.jpg')
ggsave(plot = p, filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

World IQ map.

world_map <- map_data("world")
world_map$alpha3 <- countrycode(world_map$region, origin = "country.name", destination = "iso3c")
Warning: Some values were not matched unambiguously: Ascension Island, Azores, Barbuda, Bonaire, Canary Islands, Chagos Archipelago, Grenadines, Heard Island, Kosovo, Madeira Islands, Micronesia, Saba, Saint Martin, Siachen Glacier, Sint Eustatius, Virgin Islands
onlyb <- onlyscores4 %>% filter(!is.na(alpha3))

world_map_data <- left_join(world_map, onlyb, by = c('alpha3'))

world_map_data$color_category <- cut(world_map_data$NIQ, 
                                     breaks = c(-Inf, 71, 76, 81, 86, 91, 96, 101, Inf),
                                     labels = c('=< 71', '71 to 76', '76 to 81', '81 to 86', '86 to 91', '91 to 96', '96 to 101', '> 101'),
                                     right = TRUE)


p <- ggplot(data = world_map_data, aes(x = long, y = lat, group = group, fill = color_category)) +
  geom_polygon(color = "black") +
  scale_fill_manual(name = "IQ",
                    values = c("=< 71" = "darkred",
                               "71 to 76" = "red1",
                               "76 to 81" = "orange",
                               "81 to 86" = "#FFDD55",
                               "86 to 91" = "#FFEECC",
                               "91 to 96" = "#66CCFF",
                               "96 to 101" = "#4477EE",
                               "> 101" = "#4422AA")) +
  theme_minimal() +
  theme(plot.background = element_rect(fill = "white"),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        axis.line = element_blank()) +
  labs(title = "")

p

file_name <- paste0('output/natedysssss.png')
ggsave(filename = file_name, dpi = 420)
Saving 7.29 x 4.5 in image

Regressing logGNI onto NIQ.

#################3
#S-factor data cleaning
years <- 2018:2022
variable_pattern <- paste0(".*_(", paste(years, collapse = "|"), ")")
variable_pattern
[1] ".*_(2018|2019|2020|2021|2022)"
long_hdi <- pivot_longer(HDI, 
                         cols = matches(variable_pattern),
                         names_to = c("variable", "year"),
                         names_sep = "_",
                         values_drop_na = TRUE)
Warning: Expected 2 pieces. Additional pieces discarded in 92 rows [1, 22, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, ...].
terst <- long_hdi %>%
  mutate(year = as.numeric(year)) %>% filter(year %in% years)
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `year = as.numeric(year)`.
Caused by warning:
! NAs introduced by coercion
long_hdi <- pivot_longer(HDI, 
                         cols = matches(variable_pattern),
                         names_to = c("variable", "year"),
                         names_sep = "_",
                         values_drop_na = TRUE) %>%
  mutate(year = as.numeric(year)) %>% # Convert year to numeric
  filter(year %in% years)  # Keep only the years 2018-2022
Warning: Expected 2 pieces. Additional pieces discarded in 92 rows [1, 22, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, ...].Warning: There was 1 warning in `mutate()`.
ℹ In argument: `year = as.numeric(year)`.
Caused by warning:
! NAs introduced by coercion
average_values2 <- long_hdi %>%
  group_by(iso3, variable) %>%
  summarise(average = mean(value, na.rm = TRUE), .groups = 'drop')


wide_hdi <- pivot_wider(average_values2, names_from = variable, values_from = average)

wide_hdi <- data.frame(wide_hdi)
SFACTOR <- full_join(SPI, wide_hdi, by = join_by(spicountrycode == iso3))
SFACTOR <- SFACTOR %>% filter(!is.na(spicountrycode))
SFACTOR <- SFACTOR %>% filter(spiyear==2022)
SFACTOR <- full_join(SFACTOR, esca, by = join_by(spicountrycode == alpha3))
SFACTOR$GNI = rowMeans(subset(SFACTOR, select=c(gnipc, gnihdi, gnipppimf)), na.rm = TRUE)
SFACTOR$GNI[SFACTOR$spicountrycode=='MAC'] <- 92487.5
SFACTOR$alpha3 <- SFACTOR$spicountrycode
gnis <- SFACTOR %>% select(GNI, alpha3)

forchart2 <- full_join(gnis, onlyscores4, by='alpha3')

forchart2$logGNI <- log(forchart2$GNI)
p <- GG_scatter(forchart2, 'NIQ', 'logGNI', case_names='alpha3') + labs(
  x = 'National IQ (Jensen & Kirkegaard, 2024)', 
  y = "log(GNI)"
) +
  theme_minimal() +  # Use a minimal theme
  theme_bw() +  # Base theme with white background
  theme(
    axis.text.x = element_text(size = 12),
    axis.text.y = element_text(size = 12),
    axis.title.x = element_text(size = 12),
    axis.title.y = element_text(size = 12),
    legend.position = "right",
    plot.background = element_rect(fill = "white")
  )

# Print the plot
print(p)
ggsave(plot = p, filename = 'output/oeyeopen243.jpg', dpi = 420)
Saving 7.29 x 4.5 in image

lr <- lm(data=forchart2, logGNI ~ NIQ)
summary(lr)

Call:
lm(formula = logGNI ~ NIQ, data = forchart2)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.20404 -0.39976  0.00287  0.31940  1.91091 

Coefficients:
            Estimate Std. Error t value             Pr(>|t|)    
(Intercept) 2.085779   0.371933   5.608         0.0000000702 ***
NIQ         0.087582   0.004451  19.678 < 0.0000000000000002 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6786 on 193 degrees of freedom
  (80 observations deleted due to missingness)
Multiple R-squared:  0.6674,    Adjusted R-squared:  0.6656 
F-statistic: 387.2 on 1 and 193 DF,  p-value: < 0.00000000000000022
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNClRoaXMgaW5pdGlhbCBjaHVuayBzZXRzIHRoZSB3b3JraW5nIGRpcmVjdG9yeSwgbG9hZHMgbmVjZXNzYXJ5IGxpYnJhcmllcywgYW5kIGltcG9ydHMgYWxsIHRoZSByYXcgZGF0YSBmaWxlcyAoLmNzdiBhbmQgLnhsc3gpIHRoYXQgd2lsbCBiZSB1c2VkIGZvciB0aGUgc3Vic2VxdWVudCBOYXRpb25hbCBJUSAoTklRKSBkYXRhIGhhcm1vbml6YXRpb24gYW5kIGFuYWx5c2lzLg0KDQpgYGB7cn0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI3MtZmFjdG9yDQojc2V0d2QoJ34nKQ0KbGlicmFyeSgncmVhZHhsJykNCiNzZXR3ZCgncmZvbGRlci9iZXN0TklRcy9kYXRhJykNCg0KYWdyaSA8LSByZWFkLmNzdigiZGF0YS9hZ3JpLmNzdiIpDQpiYXNpY3NraWxscyA8LSByZWFkLmNzdigiZGF0YS9iYXNpY3NraWxscy5jc3YiKQ0KYmVja2VyIDwtIHJlYWQuY3N2KCJkYXRhL2JlY2tlci5jc3YiKQ0KYmVja2VyJGFscGhhM1tiZWNrZXIkYWxwaGEzPT0nS05BLiddIDwtICdLTkEnDQpjYWxvcmllcyA8LSByZWFkLmNzdigiZGF0YS9jYWxvcmllcy5jc3YiKQ0KY2UyIDwtIHJlYWQuY3N2KCJkYXRhL2NlMi5jc3YiKQ0KQ0lBR0RQIDwtIHJlYWQuY3N2KCJkYXRhL0NJQUdEUC5jc3YiKQ0KY2lyYzIgPC0gcmVhZC5jc3YoImRhdGEvY2lyYzIuY3N2IikNCmRvaV90b3RhbCA8LSByZWFkLmNzdigiZGF0YS9kb2lfdG90YWwuY3N2IikNCkdOSW5QUFBJTUYgPC0gcmVhZC5jc3YoImRhdGEvR05JblBQUElNRi5jc3YiKQ0KR05JUFBQSU1GIDwtIHJlYWQuY3N2KCJkYXRhL0dOSVBQUElNRi5jc3YiKQ0KSERJIDwtIHJlYWQuY3N2KCJkYXRhL0hESS5jc3YiKQ0KDQpoZWFsdGggPC0gcmVhZC5jc3YoImRhdGEvaGVhbHRoLmNzdiIpDQppY3QgPC0gcmVhZC5jc3YoImRhdGEvaWN0LmNzdiIpDQppc3AgPC0gcmVhZC5jc3YoImRhdGEvaW50ZXJuZXQtc3BlZWRzLWJ5LWNvdW50cnktMjAyNC5jc3YiKQ0KbWVhbmFnZXMgPC0gcmVhZC5jc3YoImRhdGEvbWVhbmFnZXMuY3N2IikNCm1lZGlhbmluY29tZSA8LSByZWFkLmNzdigiZGF0YS9tZWRpYW5pbmNvbWUuY3N2IikNCm1lZGlhbndlYWx0aCA8LSByZWFkLmNzdigiZGF0YS9tZWRpYW53ZWFsdGguY3N2IikNCm1lZ2EgPC0gcmVhZC5jc3YoImRhdGEvbWVnYS5jc3YiKQ0KbmV3ZGF0YSA8LSByZWFkLmNzdigiZGF0YS9uZXdkYXRhLmNzdiIpDQpQSVJMUzIwMjEgPC0gcmVhZC5jc3YoImRhdGEvUElSTFMyMDIxLmNzdiIpDQpwaXNhIDwtIHJlYWQuY3N2KCJkYXRhL3Bpc2EuY3N2IikNCm9pbCA8LSByZWFkLmNzdignZGF0YS93b3JsZG9pbC5jc3YnKQ0KU1BJIDwtIHJlYWQuY3N2KCJkYXRhL1NQSS5jc3YiKQ0KdGVjaGV4cCA8LSByZWFkLmNzdigiZGF0YS90ZWNoZXhwLmNzdiIpDQp0ZXN0c2NvcmVzIDwtIHJlYWQuY3N2KCJkYXRhL3Rlc3RzY29yZXMuY3N2IikNCnRpbXNzNG0gPC0gcmVhZC5jc3YoImRhdGEvdGltc3M0dGhtYXRoLmNzdiIpDQp0aW1zczhtIDwtIHJlYWQuY3N2KCJkYXRhL3RpbXNzbWF0aDh0aC5jc3YiKQ0KdGltc3M0cyA8LSByZWFkLmNzdigiZGF0YS90aW1zc3NjaTR0aC5jc3YiKQ0KdGltc3M4cyA8LSByZWFkLmNzdigiZGF0YS90aW1zczh0aHNjaS5jc3YiKQ0KV0JHRFAgPC0gcmVhZC5jc3YoImRhdGEvV0JHRFAuY3N2IikNCmFsbG5pcSA8LSByZWFkX2V4Y2VsKCJkYXRhL2FsbG5pcS54bHN4IikNCklNRkdEUCA8LSByZWFkX2V4Y2VsKCJkYXRhL0lNRkdEUC54bHMiKQ0KaHNzaXFzIDwtIHJlYWQuY3N2KCdkYXRhL2hzc2lxLmNzdicpDQpgYGANCg0KVGhpcyBzZWN0aW9uIHBlcmZvcm1zIHRoZSBjcnVjaWFsIHN0ZXAgb2YgY2xlYW5pbmcgYW5kIGhhcm1vbml6aW5nIHZhcmlvdXMgaW50ZXJuYXRpb25hbCB0ZXN0IHNjb3JlIGFuZCBlc3RpbWF0ZWQgSVEgZGF0YXNldHMgKGUuZy4sIEhhcm1vbml6ZWQgVGVzdCBTY29yZXMsIFBJU0EsIFRJTVNTLCBSaW5kZXIncyBlc3RpbWF0ZXMpIGludG8gYSBzdGFuZGFyZGl6ZWQgSVEgc2NhbGUuDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiNJUSBkYXRhIGNsZWFuaW5nDQpodHMgPC0gdGVzdHNjb3JlcyAlPiUgZmlsdGVyKEluZGljYXRvciA9PSAnSGFybW9uaXplZCBUZXN0IFNjb3JlcycpDQoNCmh0cyRtZWFuID0gcm93TWVhbnMoc3Vic2V0KGh0cywgc2VsZWN0PWMoWDIwMTAsIFgyMDE3LCBYMjAxOCwgWDIwMjApKSwgbmEucm0gPSBUUlVFKQ0KaHRzJHdidGVzdHNjb3JlID0gKGh0cyRtZWFuIC0gNTI5LjUpLzEwMCoxNSsxMDANCmh0cyR0MjAyMCA8LSBodHMkWDIwMjANCg0KaHRzIDwtIGh0cyAlPiUgc2VsZWN0KHdidGVzdHNjb3JlLCBDb3VudHJ5LklTTzMpDQpuaXQgPC0gYWxsbmlxICU+JSBzZWxlY3QoQ0FfdG90YywgU0FTX0lRYywgY291bnRyeWNvZGUpDQpuaXQkUmluZGVySVEgPC0gYXMubnVtZXJpYyhuaXQkQ0FfdG90YykNCm5pdCRSaW5kZXJTQVMgPC0gYXMubnVtZXJpYyhuaXQkU0FTX0lRYykNCmJhc2ljc2tpbGxzJGJzIDwtIChiYXNpY3NraWxscyRNZWFuIC0gNTE0LjgpLzEwMCoxNSsxMDANCmJhc2ljc2tpbGxzJGFscGhhMyA8LSBjb3VudHJ5Y29kZShiYXNpY3NraWxscyRDb3VudHJ5LCBvcmlnaW4gPSAnY291bnRyeS5uYW1lJywgZGVzdGluYXRpb249J2lzbzNjJykNCmJhc2ljc2tpbGxzJGFscGhhM1tiYXNpY3NraWxscyRDb3VudHJ5PT0nS29zb3ZvJ10gPC0gJ0tTVicNCg0KYnMgPC0gYmFzaWNza2lsbHMgJT4lIGZpbHRlcighRGF0YS5sYXllcj09JzUnKSAlPiUgc2VsZWN0KGJzLCBhbHBoYTMpDQoNCnBpc2EkYWxwaGEzIDwtIGNvdW50cnljb2RlKHBpc2EkY210cnksIG9yaWdpbiA9ICdjb3VudHJ5Lm5hbWUnLCBkZXN0aW5hdGlvbj0naXNvM2MnKQ0KcGlzYSRhbHBoYTNbcGlzYSRjbXRyeT09J0tvc292byddIDwtICdLU1YnDQpiZWNrZXIkYWxwaGEzW2JlY2tlciRhbHBoYTM9PSdGUkEgJ10gPC0gJ0ZSQScNCnBpc2EkcGlzYTIgPC0gKHBpc2EkcGlzYS01MDUuOCkvMTAwKjE1KzEwMA0KDQp0aW1zczRtJGFscGhhMyA8LSBjb3VudHJ5Y29kZSh0aW1zczRtJGNvdW50cnksIG9yaWdpbiA9ICdjb3VudHJ5Lm5hbWUnLCBkZXN0aW5hdGlvbj0naXNvM2MnKQ0KdGltc3M0bSRhbHBoYTNbNDhdIDwtICdLU1YnDQp0aW1zczRtJGFscGhhM1t0aW1zczRtJGNvdW50cnk9PSdFbmdsYW5kJ10gPC0gJ0dCUicNCnRpbXNzNG0kVDRtSVEgPC0gKHRpbXNzNG0kc2NvcmUtNTM1KS8xMDAqMTUgKyA5Ny4zDQoNCnRpbXNzNHMkYWxwaGEzIDwtIGNvdW50cnljb2RlKHRpbXNzNHMkY291bnRyeSwgb3JpZ2luID0gJ2NvdW50cnkubmFtZScsIGRlc3RpbmF0aW9uPSdpc28zYycpDQp0aW1zczRzJGFscGhhM1s1MV0gPC0gJ0tTVicNCnRpbXNzNHMkYWxwaGEzWzEyXSA8LSAnR0JSJw0KdGltc3M0cyRUNHNJUSA8LSAodGltc3M0cyRzY2k0dGh0aW1zcy01NDIuMzMzKS8xMDAqMTUgKyAxMDANCg0KdGltc3M4bSRhbHBoYTMgPC0gY291bnRyeWNvZGUodGltc3M4bSRjb3VudHJ5LCBvcmlnaW4gPSAnY291bnRyeS5uYW1lJywgZGVzdGluYXRpb249J2lzbzNjJykNCnRpbXNzOG0kYWxwaGEzWzEzXSA8LSAnR0JSJw0KdGltc3M4bSRUOG1JUSA8LSAodGltc3M4bSRtYXRoOHRoLTUyMC4zMzMzMykvMTAwKjE1ICsgMTAwDQoNCnRpbXNzOHMkYWxwaGEzIDwtIGNvdW50cnljb2RlKHRpbXNzOHMkY291bnRyeSwgb3JpZ2luID0gJ2NvdW50cnkubmFtZScsIGRlc3RpbmF0aW9uPSdpc28zYycpDQp0aW1zczhzJGFscGhhM1sxNF0gPC0gJ0dCUicNCnRpbXNzOHMkVDhzSVEgPC0gKHRpbXNzOHMkdGltc3M4dGhzY2ktNTIyLjMzMzMzKS8xMDAqMTUgKyAxMDANCg0KUElSTFMyMDIxJGFscGhhMyA8LSBjb3VudHJ5Y29kZShQSVJMUzIwMjEkY291bnRyeSwgb3JpZ2luID0gJ2NvdW50cnkubmFtZScsIGRlc3RpbmF0aW9uPSdpc28zYycpDQpQSVJMUzIwMjEkYWxwaGEzWzUwXSA8LSAnS1NWJw0KUElSTFMyMDIxJFBSTElRIDwtIChQSVJMUzIwMjEkc2NvcmUtNTYyLjMzMzMzKS8xMDAqMTUgKyAxMDANCg0KdDRtIDwtIHRpbXNzNG0gJT4lIHNlbGVjdChhbHBoYTMsIFQ0bUlRKQ0KdDRzIDwtIHRpbXNzNHMgJT4lIHNlbGVjdChhbHBoYTMsIFQ0c0lRKQ0KdDhtIDwtIHRpbXNzOG0gJT4lIHNlbGVjdChhbHBoYTMsIFQ4bUlRKQ0KdDhzIDwtIHRpbXNzOHMgJT4lIHNlbGVjdChhbHBoYTMsIFQ4c0lRKQ0KcDIxIDwtIFBJUkxTMjAyMSAlPiUgc2VsZWN0KGFscGhhMywgUFJMSVEpDQoNCm5pcXMxIDwtIGZ1bGxfam9pbihiZWNrZXIsIGh0cywgYnkgPSBqb2luX2J5KGFscGhhMyA9PSBDb3VudHJ5LklTTzMpKQ0KbmlxczIgPC0gZnVsbF9qb2luKG5pcXMxLCBwaXNhLCBieSA9IGpvaW5fYnkoYWxwaGEzID09IGFscGhhMykpDQpuaXFzMyA8LSBmdWxsX2pvaW4obmlxczIsIGJzLCBieSA9IGpvaW5fYnkoYWxwaGEzID09IGFscGhhMykpDQpuaXFzNCA8LSBmdWxsX2pvaW4obmlxczMsIG5pdCwgYnkgPSBqb2luX2J5KGFscGhhMyA9PSBjb3VudHJ5Y29kZSkpDQpuaXFzNSA8LSBmdWxsX2pvaW4obmlxczQsIHQ0bSwgYnkgPSBqb2luX2J5KGFscGhhMyA9PSBhbHBoYTMpKQ0KbmlxczYgPC0gZnVsbF9qb2luKG5pcXM1LCB0NHMsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gYWxwaGEzKSkNCm5pcXM3IDwtIGZ1bGxfam9pbihuaXFzNiwgdDhtLCBieSA9IGpvaW5fYnkoYWxwaGEzID09IGFscGhhMykpDQpuaXFzOCA8LSBmdWxsX2pvaW4obmlxczcsIHQ4cywgYnkgPSBqb2luX2J5KGFscGhhMyA9PSBhbHBoYTMpKQ0KbmlxczkgPC0gZnVsbF9qb2luKG5pcXM4LCBwMjEsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gYWxwaGEzKSkNCg0KDQpgYGANCg0KVGhpcyBjaHVuayBwZXJmb3JtcyBmaW5hbCBhZGp1c3RtZW50cywgYWdncmVnYXRpb25zLCBhbmQgcmVnaW9uYWwgZ3JvdXBpbmcgb24gdGhlIG1lcmdlZCBkYXRhc2V0Lg0KDQpgYGB7cn0NCm5pcXM5JFJbaXMubmEobmlxczkkVVcpICYgaXMubmEobmlxczkkTlcpICYgaXMubmEobmlxczkkUU5XKSAmIGlzLm5hKG5pcXM5JFNBUyldIDwtIE5BDQpvbmx5c2NvcmVzIDwtIGRhdGEuZnJhbWUobmlxczkgJT4lIHNlbGVjdChVVywgVDRtSVEsIFQ0c0lRLCBUOHNJUSwgVDhtSVEsIFBSTElRLCBRTlcsIE5XLCBTQVMsIEwuVjEyLCBSLCB3YnRlc3RzY29yZSwgUmluZGVySVEsIFJpbmRlclNBUywgcGlzYTIsIGJzLCBMLlYwMiwgYWxwaGEzKSkNCm9ubHlzY29yZXMkU0FTIDwtIG9ubHlzY29yZXMkU0FTIC0gMS43NCArIDENCm9ubHlzY29yZXMkTlcgPC0gb25seXNjb3JlcyROVyAtIDEgKyAxDQpvbmx5c2NvcmVzJFVXIDwtIG9ubHlzY29yZXMkVVcgKyAxDQpvbmx5c2NvcmVzJGJzIDwtIG9ubHlzY29yZXMkYnMgKyAxDQpvbmx5c2NvcmVzJHBpc2EyIDwtIG9ubHlzY29yZXMkcGlzYTIgKyAxDQpvbmx5c2NvcmVzJHdidGVzdHNjb3JlIDwtIG9ubHlzY29yZXMkd2J0ZXN0c2NvcmUgKyAxDQpvbmx5c2NvcmVzJFFOVyA8LSBvbmx5c2NvcmVzJFFOVyAtIDEgKyAxDQpvbmx5c2NvcmVzJEwuVjEyIDwtIG9ubHlzY29yZXMkTC5WMTIgLSAwLjg0ICsgMQ0Kb25seXNjb3JlcyRMLlYwMiA8LSBvbmx5c2NvcmVzJEwuVjAyIC0gMC44NA0Kb25seXNjb3JlcyRSaW5kZXJJUSA8LSBvbmx5c2NvcmVzJFJpbmRlcklRIC0gMC43NA0Kb25seXNjb3JlcyRSaW5kZXJTQVMgPC0gb25seXNjb3JlcyRSaW5kZXJTQVMgLSAwLjc0DQpvbmx5c2NvcmVzJE9NID0gcm93TWVhbnMoc3Vic2V0KG9ubHlzY29yZXMsIHNlbGVjdD1jKFJpbmRlclNBUywgUmluZGVySVEsIEwuVjAyLCBMLlYxMiwgUU5XLCB3YnRlc3RzY29yZSwgcGlzYTIsIGJzLCBVVywgTlcsIFNBUywgUU5XKSksIG5hLnJtID0gVFJVRSkNCm9ubHlzY29yZXMkUiA8LSBvbmx5c2NvcmVzJFIgLSAxLjc0ICsgMQ0KDQpvbmx5c2NvcmVzJHJlZ2lvbiA8LSBjb3VudHJ5Y29kZShvbmx5c2NvcmVzJGFscGhhMywgb3JpZ2luPSdpc28zYycsIGRlc3RpbmF0aW9uPSd1bi5yZWdpb25zdWIubmFtZScpDQpvbmx5c2NvcmVzJHJlZ2lvbltvbmx5c2NvcmVzJGFscGhhMz09J0tTViddIDwtICdTb3V0aGVybiBFdXJvcGUnDQpvbmx5c2NvcmVzJHJlZ2lvbltvbmx5c2NvcmVzJGFscGhhMz09J1RXTiddIDwtICdFYXN0ZXJuIEFzaWEnDQpvbmx5c2NvcmVzIDwtIG9ubHlzY29yZXMgJT4lIGZpbHRlcighaXMubmEocmVnaW9uKSkNCm9ubHlzY29yZXMkcmVnaW9uW29ubHlzY29yZXMkYWxwaGEzPT0nS05BJ10gPC0gTkENCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KYnlyZWcgPC0gb25seXNjb3JlcyAlPiUNCiAgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiAgc3VtbWFyaXNlKFJJUSA9IG1lYW4oUmluZGVySVEsIG5hLnJtPVQpLCBCU0QgPSBtZWFuKGJzLCBuYS5ybT1UKSwgV0JUUyA9IG1lYW4od2J0ZXN0c2NvcmUsIG5hLnJtPVQpLCBQSVNBID0gbWVhbihwaXNhMiwgbmEucm09VCksIFJTQVMgPSBtZWFuKFJpbmRlclNBUywgbmEucm09VCksIEJRTlcgPSBtZWFuKFFOVywgbmEucm09VCksIEJTQVMgPSBtZWFuKFNBUywgbmEucm09VCksIExWMTIgPSBtZWFuKEwuVjEyLCBuYS5ybT1UKSwgTFYwMiA9IG1lYW4oTC5WMDIsIG5hLnJtPVQpLCBCT1IgPSBtZWFuKFIsIG5hLnJtPVQpKQ0KDQpwcmludChieXJlZywgbj0yMCkNCmBgYA0KDQpDaGFydGluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbWVhbiBhbmQgc3RhbmRhcmQgZXJyb3IgKHNpbXBsZSBtZXRob2QpDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KbG9uZ2VyIDwtIG9ubHlzY29yZXMgJT4lIHNlbGVjdChUNG1JUSwgVDRzSVEsIFQ4c0lRLCBUOG1JUSwgUFJMSVEsIFFOVywgUmluZGVyU0FTLCBwaXNhMiwgYWxwaGEzKQ0KDQpsb25nX2Zvcm1hdCA8LSBsb25nZXIgJT4lDQogIGdhdGhlcihrZXkgPSAiTWVhc3VyZSIsIHZhbHVlID0gIlZhbHVlIiwgLWFscGhhMykNCg0KbG9uZ19mb3JtYXQkc2UgPC0gMS9zcXJ0KDM1MCkNCg0KdW5pcXVlcyA8LSB1bmlxdWUob25seXNjb3JlcyRhbHBoYTMpDQoNCnJzIDwtIHJlcCgwLCBsZW5ndGgodW5pcXVlcykpDQp3aXRoX3NlIDwtIGRhdGEuZnJhbWUodW5pcXVlcywgcnMpDQoNCmZvcihpIGluIDE6bGVuZ3RoKHVuaXF1ZXMpKSB7DQogIGYgPC0gbG9uZ19mb3JtYXQgJT4lIGZpbHRlcihhbHBoYTM9PXVuaXF1ZXNbaV0gJiAhaXMubmEoVmFsdWUpKQ0KICBpZiAobnJvdyhmKSA+IDEpIHsNCiAgICBtZXRhb2JqbiA8LSBtZXRhZm9yOjpybWEoeWk9VmFsdWUsIHNlaT1zZSwgZGF0YSA9IGYpDQogICAgd2l0aF9zZSRtZWFuW2ldIDwtIG1ldGFvYmpuJGINCiAgICB3aXRoX3NlJHNlW2ldIDwtIG1ldGFvYmpuJHNlDQogIH0gDQogIGVsc2UgaWYgKG5yb3coZikgPT0gMSkgew0KICAgIHdpdGhfc2UkbWVhbltpXSA8LSBtZWFuKGYkVmFsdWUpDQogICAgd2l0aF9zZSRzZVtpXSA8LSBOQQ0KICB9IA0KICBlbHNlIHsNCiAgICB3aXRoX3NlJG1lYW5baV0gPC0gTkENCiAgICB3aXRoX3NlJHNlW2ldIDwtIE5BDQogIH0NCn0NCg0KcCA8LSBHR19zY2F0dGVyKHdpdGhfc2UsICdtZWFuJywgJ3NlJywgY2FzZV9uYW1lcz0ndW5pcXVlcycpICArDQogIHhsYWIoJ01lYW4nKSArDQogIHlsYWIoJ1N0YW5kYXJkIEVycm9yJykgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKQ0KICApDQpwDQpmaWxlX25hbWUgPSAnb3V0cHV0L3JvcHouanBnJw0KZ2dzYXZlKHBsb3QgPSBwLCBmaWxlbmFtZSA9IGZpbGVfbmFtZSwgZHBpID0gNDIwKQ0KYGBgDQoNCkNoYXJ0aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBwc3ljaG9tZXRyaWMgYW5kIHNjaG9sYXN0aWMgYWJpbGl0eQ0KYGBge3J9DQpwIDwtIEdHX3NjYXR0ZXIob25seXNjb3JlcywgJ1VXJywgJ2JzJywgY2FzZV9uYW1lcz0nYWxwaGEzJykgICsNCiAgeGxhYignSVEgQmFzZWQgb24gUHljaG9tZXRyaWMgRGF0YSAoRnJvbSBCZWNrZXIpJykgKw0KICB5bGFiKCdTY2hvbGFzdGljIEFiaWxpdHkgQmFzZWQgb24gQmFzaWMgU2tpbGxzIERhdGFzZXQnKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpDQogICkNCnANCg0KZmlsZV9uYW1lID0gJ291dHB1dC9yb3B6aWNsZS5qcGcnDQpnZ3NhdmUocGxvdCA9IHAsIGZpbGVuYW1lID0gZmlsZV9uYW1lLCBkcGkgPSA0MjApDQoNCmBgYA0KDQpDYWxjdWxhdGlvbiBvZiBtZXRhLWFuYWx5dGljIG1lYW5zLg0KDQpgYGB7cn0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCm9ubHlzY29yZXMyIDwtIGRhdGEuZnJhbWUob25seXNjb3JlcyAlPiUgc2VsZWN0KFVXLCBRTlcsIE5XLCBTQVMsIEwuVjEyLCBSLCBUNG1JUSwgVDRzSVEsIFQ4c0lRLCBUOG1JUSwgUFJMSVEsIHdidGVzdHNjb3JlLCBSaW5kZXJJUSwgUmluZGVyU0FTLCBwaXNhMiwgYnMsIEwuVjAyLCBhbHBoYTMpKQ0KI29ubHlzY29yZXMyIDwtIG9ubHlzY29yZXMyICU+JSBmaWx0ZXIoIShhbHBoYTMgJWluJSAodW5pcXVlKG5ld2RhdGEkYWxwaGEzKSkpKQ0KDQpvbmx5c2NvcmVzMiRuZXN0MiA9IHJvd01lYW5zKHN1YnNldChvbmx5c2NvcmVzMiwgc2VsZWN0PWMoVDRtSVEsIFQ4bUlRLCBRTlcsIFVXLCBOVywgU0FTLCBMLlYwMiwgTC5WMTIsIFIpKSwgbmEucm0gPSBUUlVFKQ0Kb25seXNjb3JlczIkbmVzdDMgPSByb3dNZWFucyhzdWJzZXQob25seXNjb3JlczIsIHNlbGVjdD1jKG5lc3QyLCBUNHNJUSwgVDhzSVEpKSwgbmEucm0gPSBUUlVFKQ0Kb25seXNjb3JlczIkbmVzdDQgPSByb3dNZWFucyhzdWJzZXQob25seXNjb3JlczIsIHNlbGVjdD1jKG5lc3QzLCBwaXNhMiwgUmluZGVyU0FTLCB3YnRlc3RzY29yZSwgUFJMSVEpKSwgbmEucm0gPSBUUlVFKQ0Kb25seXNjb3JlczIkTklRdGVtcDEgPSByb3dNZWFucyhzdWJzZXQob25seXNjb3JlczIsIHNlbGVjdD1jKG5lc3Q0LCBicywgUmluZGVySVEpKSwgbmEucm0gPSBUUlVFKQ0Kb25seXNjb3JlczIkcmV2aXNlZCA8LSAwDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KI01ldGEtYW5hbHl0aWMgbWVhbnMNCmxvbmdlciA8LSBvbmx5c2NvcmVzICU+JSBzZWxlY3QoVVcsIFFOVywgTlcsIFNBUywgTC5WMTIsIFIsIFQ0bUlRLCBUNHNJUSwgVDhzSVEsIFQ4bUlRLCBQUkxJUSwgd2J0ZXN0c2NvcmUsIFJpbmRlcklRLCBSaW5kZXJTQVMsIHBpc2EyLCBicywgTC5WMDIsIGFscGhhMykNCmxvbmdfZm9ybWF0IDwtIGxvbmdlciAlPiUNCiAgZ2F0aGVyKGtleSA9ICJNZWFzdXJlIiwgdmFsdWUgPSAiVmFsdWUiLCAtYWxwaGEzKQ0KDQpsb25nX2Zvcm1hdCRzZSA8LSBOQQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J1VXJ10gPC0gMTUvc3FydCg1MCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdOVyddIDwtIDE1L3NxcnQoNTApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nUU5XJ10gPC0gMTUvc3FydCg1MCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdUNG1JUSddIDwtIDE1L3NxcnQoNTApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nVDhtSVEnXSA8LSAxNS9zcXJ0KDUwKQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J1InXSA8LSAxNS9zcXJ0KDUwKQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J1NBUyddIDwtIDE1L3NxcnQoNTApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nVDRzSVEnXSA8LSAxNS9zcXJ0KDEyNSkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdUOHNJUSddIDwtIDE1L3NxcnQoMTI1KQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J0wuVjAyJ10gPC0gMTUvc3FydCg1MCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdMLlYxMiddIDwtIDE1L3NxcnQoNTApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nUFJMSVEnXSA8LSAxNS9zcXJ0KDI1MCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdwaXNhMiddIDwtIDE1L3NxcnQoMjUwKQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J3didGVzdHNjb3JlJ10gPC0gMTUvc3FydCg1MDApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nUmluZGVyU0FTJ10gPC0gMTUvc3FydCgyNTApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nYnMnXSA8LSAxNS9zcXJ0KDc1MCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdSaW5kZXJJUSddIDwtIDE1L3NxcnQoNzUwKQ0KDQp1bmlxdWVzIDwtIHVuaXF1ZShvbmx5c2NvcmVzJGFscGhhMykNCg0KbWVhbiA8LSByZXAoMCwgbGVuZ3RoKHVuaXF1ZXMpKQ0Kd2l0aF9zZSA8LSBkYXRhLmZyYW1lKHVuaXF1ZXMsIG1lYW4pDQoNCmZvcihpIGluIDE6bGVuZ3RoKHVuaXF1ZXMpKSB7DQogIGYgPC0gbG9uZ19mb3JtYXQgJT4lIGZpbHRlcihhbHBoYTM9PXVuaXF1ZXNbaV0gJiAhaXMubmEoVmFsdWUpKQ0KICBpZiAobnJvdyhmKSA+IDEpIHsNCiAgICBtZXRhb2JqbiA8LSBtZXRhZm9yOjpybWEoeWk9VmFsdWUsIHNlaT1zZSwgZGF0YSA9IGYpDQogICAgd2l0aF9zZSRtZWFuW2ldIDwtIG1ldGFvYmpuJGINCiAgICB3aXRoX3NlJHNlW2ldIDwtIG1ldGFvYmpuJHNlDQogIH0gDQogIGVsc2UgaWYgKG5yb3coZikgPT0gMSkgew0KICAgIHdpdGhfc2UkbWVhbltpXSA8LSBtZWFuKGYkVmFsdWUpDQogICAgd2l0aF9zZSRzZVtpXSA8LSBOQQ0KICB9IA0KICBlbHNlIHsNCiAgICB3aXRoX3NlJG1lYW5baV0gPC0gTkENCiAgICB3aXRoX3NlJHNlW2ldIDwtIE5BDQogIH0NCn0NCg0KYGBgDQoNCg0KUmVncmVzc2lvbiBtb2RlbHMgcHJlZGljdGluZyBzdGFuZGFyZCBlcnJvcnMgYmFzZWQgb24gbWVhbnMgYW5kIHNhbXBsZSBzaXplcy4NCg0KYGBge3J9DQoNCmxvbmdfZm9ybWF0IDwtIGxvbmdlciAlPiUNCiAgZ2F0aGVyKGtleSA9ICJNZWFzdXJlIiwgdmFsdWUgPSAiVmFsdWUiLCAtYWxwaGEzKQ0KDQp3aXRoX3NlIDwtIGxvbmdfZm9ybWF0ICU+JSBncm91cF9ieShhbHBoYTMpICU+JSBzdW1tYXJpc2UobWVhbiA9IG1lYW4oVmFsdWUsIG5hLnJtPVQpLCBzZSA9IHNkKFZhbHVlLCBuYS5ybT1UKS9zcXJ0KHN1bSghaXMubmEoVmFsdWUpKSksIG4gPSBzdW0oIWlzLm5hKFZhbHVlKSkpDQoNCmxyIDwtIGxtKGRhdGE9d2l0aF9zZSwgc2UgfiBtZWFuKQ0Kc3VtbWFyeShscikNCg0KbHIgPC0gbG0oZGF0YT13aXRoX3NlLCBzZSB+IG4pDQpzdW1tYXJ5KGxyKQ0KDQpsciA8LSBsbShkYXRhPXdpdGhfc2UsIHNlIH4gbWVhbiArIG4pDQpzdW1tYXJ5KGxyKQ0KDQpgYGANCkNhbGN1bGF0aW9uIG9mIG1ldGEtYW5hbHl0aWMgbWVhbnMgKGFnYWluKS4NCg0KYGBge3J9DQpvbmx5c2NvcmVzMiA8LSBkYXRhLmZyYW1lKG9ubHlzY29yZXMgJT4lIHNlbGVjdChVVywgUU5XLCBOVywgU0FTLCBMLlYxMiwgUiwgVDRtSVEsIFQ0c0lRLCBUOHNJUSwgVDhtSVEsIFBSTElRLCB3YnRlc3RzY29yZSwgUmluZGVySVEsIFJpbmRlclNBUywgcGlzYTIsIGJzLCBMLlYwMiwgYWxwaGEzKSkNCiNvbmx5c2NvcmVzMiA8LSBvbmx5c2NvcmVzMiAlPiUgZmlsdGVyKCEoYWxwaGEzICVpbiUgKHVuaXF1ZShuZXdkYXRhJGFscGhhMykpKSkNCg0Kb25seXNjb3JlczIkbmVzdDEgPSByb3dNZWFucyhzdWJzZXQob25seXNjb3JlczIsIHNlbGVjdD1jKFFOVywgTlcsIFVXLCBUNG1JUSwgVDhtSVEsIEwuVjAyLCBMLlYxMiwgU0FTLCBSKSksIG5hLnJtID0gVFJVRSkNCm9ubHlzY29yZXMyJG5lc3QyID0gcm93TWVhbnMoc3Vic2V0KG9ubHlzY29yZXMyLCBzZWxlY3Q9YyhuZXN0MSwgVDRzSVEsIFQ4c0lRKSksIG5hLnJtID0gVFJVRSkNCm9ubHlzY29yZXMyJG5lc3QzID0gcm93TWVhbnMoc3Vic2V0KG9ubHlzY29yZXMyLCBzZWxlY3Q9YyhuZXN0MiwgcGlzYTIsIHdidGVzdHNjb3JlLCBSaW5kZXJTQVMsIFBSTElRKSksIG5hLnJtID0gVFJVRSkNCm9ubHlzY29yZXMyJE5JUXRlbXAxID0gcm93TWVhbnMoc3Vic2V0KG9ubHlzY29yZXMyLCBzZWxlY3Q9YyhuZXN0MywgUmluZGVySVEsIGJzKSksIG5hLnJtID0gVFJVRSkNCm9ubHlzY29yZXMyJHJldmlzZWQgPC0gMA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojTWV0YS1hbmFseXRpYyBtZWFucw0KbG9uZ2VyIDwtIG9ubHlzY29yZXMgJT4lIHNlbGVjdChVVywgUU5XLCBOVywgU0FTLCBMLlYxMiwgUiwgVDRtSVEsIFQ0c0lRLCBUOHNJUSwgVDhtSVEsIFBSTElRLCB3YnRlc3RzY29yZSwgUmluZGVySVEsIFJpbmRlclNBUywgcGlzYTIsIGJzLCBMLlYwMiwgYWxwaGEzKQ0KbG9uZ19mb3JtYXQgPC0gbG9uZ2VyICU+JQ0KICBnYXRoZXIoa2V5ID0gIk1lYXN1cmUiLCB2YWx1ZSA9ICJWYWx1ZSIsIC1hbHBoYTMpDQoNCmxvbmdfZm9ybWF0JHNlIDwtIE5BDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nVVcnXSA8LSAxNS9zcXJ0KDEwKQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J05XJ10gPC0gMTUvc3FydCgxMCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdRTlcnXSA8LSAxNS9zcXJ0KDEwKQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J1Q0bUlRJ10gPC0gMTUvc3FydCgxMCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdUOG1JUSddIDwtIDE1L3NxcnQoMTApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nUiddIDwtIDE1L3NxcnQoMjApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nU0FTJ10gPC0gMTUvc3FydCgyMCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdUNHNJUSddIDwtIDE1L3NxcnQoMjApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nVDhzSVEnXSA8LSAxNS9zcXJ0KDIwKQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J0wuVjAyJ10gPC0gMTUvc3FydCgyMCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdMLlYxMiddIDwtIDE1L3NxcnQoMjApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nUFJMSVEnXSA8LSAxNS9zcXJ0KDQwKQ0KbG9uZ19mb3JtYXQkc2VbbG9uZ19mb3JtYXQkTWVhc3VyZT09J3Bpc2EyJ10gPC0gMTUvc3FydCg0MCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSd3YnRlc3RzY29yZSddIDwtIDE1L3NxcnQoNDApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nUmluZGVyU0FTJ10gPC0gMTUvc3FydCg0MCkNCmxvbmdfZm9ybWF0JHNlW2xvbmdfZm9ybWF0JE1lYXN1cmU9PSdicyddIDwtIDE1L3NxcnQoODApDQpsb25nX2Zvcm1hdCRzZVtsb25nX2Zvcm1hdCRNZWFzdXJlPT0nUmluZGVySVEnXSA8LSAxNS9zcXJ0KDgwKQ0KDQpsb25nX2Zvcm1hdCRzZTIgPC0gMTUvc3FydCgzNTApDQoNCnVuaXF1ZXMgPC0gdW5pcXVlKG9ubHlzY29yZXMkYWxwaGEzKQ0KDQptZWFuIDwtIHJlcCgwLCBsZW5ndGgodW5pcXVlcykpDQp3aXRoX3NlIDwtIGRhdGEuZnJhbWUodW5pcXVlcywgbWVhbikNCg0KZm9yKGkgaW4gMTpsZW5ndGgodW5pcXVlcykpIHsNCiAgZiA8LSBsb25nX2Zvcm1hdCAlPiUgZmlsdGVyKGFscGhhMz09dW5pcXVlc1tpXSAmICFpcy5uYShWYWx1ZSkpDQogIGlmIChucm93KGYpID4gMSkgew0KICAgIG1ldGFvYmpuIDwtIG1ldGFmb3I6OnJtYSh5aT1WYWx1ZSwgc2VpPXNlLCBkYXRhID0gZikNCiAgICBtZXRhb2JqbjIgPC0gbWV0YWZvcjo6cm1hKHlpPVZhbHVlLCBzZWk9c2UyLCBkYXRhID0gZikNCiAgICB3aXRoX3NlJG1lYW5baV0gPC0gbWV0YW9iam4kYg0KICAgIHdpdGhfc2Ukc2VbaV0gPC0gc2QoZiRWYWx1ZSkvc3FydChucm93KGYgJT4lIGZpbHRlcighaXMubmEoVmFsdWUpKSkpDQogIH0gDQogIGVsc2UgaWYgKG5yb3coZikgPT0gMSkgew0KICAgIHdpdGhfc2UkbWVhbltpXSA8LSBtZWFuKGYkVmFsdWUpDQogICAgd2l0aF9zZSRzZVtpXSA8LSBOQQ0KICB9IA0KICBlbHNlIHsNCiAgICB3aXRoX3NlJG1lYW5baV0gPC0gTkENCiAgICB3aXRoX3NlJHNlW2ldIDwtIE5BDQogIH0NCn0NCg0KDQpgYGANCg0KQ2FsY3VsYXRpb24gb2YgZmluYWwgbWVhbnMuDQpgYGB7cn0NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyNQU1kjI1NDSCMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyNQU1kjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCm5kIDwtIG5ld2RhdGEgJT4lIHNlbGVjdChhbHBoYTMsIE5JUXIpDQpuZCA8LSBuYS5vbWl0KG5kKQ0Kcm9wMiA8LSB3aXRoX3NlICU+JSBzZWxlY3QodW5pcXVlcywgc2UsIG1lYW4pDQpvbmx5c2NvcmVzNCA8LSBmdWxsX2pvaW4ob25seXNjb3JlczIsIHJvcDIsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gdW5pcXVlcykpDQpvbmx5c2NvcmVzNCA8LSBmdWxsX2pvaW4ob25seXNjb3JlczQsIG5kLCBieSA9IGpvaW5fYnkoYWxwaGEzID09IGFscGhhMykpDQpvbmx5c2NvcmVzNCA8LSBvbmx5c2NvcmVzNCAlPiUgc2VsZWN0KFVXLCBRTlcsIE5XLCBTQVMsIEwuVjEyLCBSLCBOSVFyLCBOSVF0ZW1wMSwgd2J0ZXN0c2NvcmUsIFJpbmRlcklRLCBSaW5kZXJTQVMsIG1lYW4sIHNlLCBwaXNhMiwgYnMsIEwuVjAyLCBhbHBoYTMpDQpvbmx5c2NvcmVzNCRzZWFkaiA8LSBvbmx5c2NvcmVzNCRzZSoyLjMyL21lYW4od2l0aF9zZSRzZSwgbmEucm09VCkNCg0Kb25seXNjb3JlczQkcmVnaW9uIDwtIGNvdW50cnljb2RlKG9ubHlzY29yZXM0JGFscGhhMywgb3JpZ2luPSdpc28zYycsIGRlc3RpbmF0aW9uPSd1bi5yZWdpb25zdWIubmFtZScpDQpvbmx5c2NvcmVzNCRyZWdpb25bb25seXNjb3JlczQkYWxwaGEzPT0nS1NWJ10gPC0gJ1NvdXRoZXJuIEV1cm9wZScNCm9ubHlzY29yZXM0JHJlZ2lvbltvbmx5c2NvcmVzNCRhbHBoYTM9PSdUV04nXSA8LSAnRWFzdGVybiBBc2lhJw0Kb25seXNjb3JlczQkYWxwaGEzW29ubHlzY29yZXM0JGFscGhhMz09J0tOQS4nXSA8LSBOQQ0Kb25seXNjb3JlczQkcmVnaW9uW29ubHlzY29yZXM0JGFscGhhMz09J0tOQSddIDwtICdMYXRpbiBBbWVyaWNhIGFuZCB0aGUgQ2FyaWJiZWFuJw0KDQpvbmx5c2NvcmVzNCROSVF0IDwtIChvbmx5c2NvcmVzNCROSVF0ZW1wMSArIG9ubHlzY29yZXM0JG1lYW4pLzINCm9ubHlzY29yZXM0JE5JUSA8LSAob25seXNjb3JlczQkTklRdGVtcDEgKyBvbmx5c2NvcmVzNCRtZWFuKS8yDQpvbmx5c2NvcmVzNCRyZXZpc2VkIDwtIDANCm9ubHlzY29yZXM0JHJldmlzZWRbb25seXNjb3JlczQkYWxwaGEzICVpbiUgdW5pcXVlKG5kJGFscGhhMyldIDwtIDENCg0Kb25seXNjb3JlczQkTklRW29ubHlzY29yZXM0JHJldmlzZWQ9PTFdIDwtIG9ubHlzY29yZXM0JE5JUXJbb25seXNjb3JlczQkcmV2aXNlZD09MV0NCg0KdHZpcXMgPC0gb25seXNjb3JlczQgJT4lIHNlbGVjdChOSVEsIG1lYW4sIE5JUXRlbXAxLCBhbHBoYTMsIE5JUXQsIE5JUXIpDQp0dmlxcyRuYW1lIDwtIGNvdW50cnljb2RlKHR2aXFzJGFscGhhMywgb3JpZ2luPSdpc28zYycsIGRlc3RpbmF0aW9uPSdjb3VudHJ5Lm5hbWUnKQ0KDQpyZXZpc2VkbGlzdCA8LSB0dmlxcyAlPiUgc2VsZWN0KG5hbWUsIE5JUXQsIE5JUXIpICU+JSBmaWx0ZXIoIWlzLm5hKE5JUXIpKQ0KDQpgYGANCg0KDQpFdXJvcGUgSVEgbWFwLg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShtYXBzKQ0KbGlicmFyeShjb3VudHJ5Y29kZSkNCg0Kd29ybGRfbWFwIDwtIG1hcF9kYXRhKCJ3b3JsZCIpDQp3b3JsZF9tYXAkYWxwaGEzIDwtIGNvdW50cnljb2RlKHdvcmxkX21hcCRyZWdpb24sIG9yaWdpbiA9ICJjb3VudHJ5Lm5hbWUiLCBkZXN0aW5hdGlvbiA9ICJpc28zYyIpDQoNCm9ubHliIDwtIG9ubHlzY29yZXM0ICU+JSBmaWx0ZXIoIWlzLm5hKGFscGhhMykpDQoNCndvcmxkX21hcCRhbHBoYTNbd29ybGRfbWFwJHJlZ2lvbiA9PSAiS29zb3ZvIl0gPC0gIktTViINCndvcmxkX21hcF9kYXRhIDwtIGxlZnRfam9pbih3b3JsZF9tYXAsIG9ubHliLCBieSA9IGMoJ2FscGhhMycpKQ0KDQojIERlZmluZSBJUSBiaW5zIGFuZCBjb2xvcnMNCndvcmxkX21hcF9kYXRhJGNvbG9yX2NhdGVnb3J5IDwtIGN1dCh3b3JsZF9tYXBfZGF0YSROSVEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgODUsIDg4LCA5MSwgOTQsIDk3LCAxMDAsIEluZiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygnPTwgODUnLCAnODUgdG8gODgnLCAnODggdG8gOTEnLCAnOTEgdG8gOTQnLCAnOTQgdG8gOTcnLCAnOTcgdG8gMTAwJywgJz4gMTAwJyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHQgPSBUUlVFKQ0KDQpldXJvcGVfYm91bmRzIDwtIGMoLTI1LCA1MCwgMzUsIDcwKQ0KDQojIFN1YnNldCBkYXRhIGZvciBFdXJvcGUNCmV1cm9wZV9tYXBfZGF0YSA8LSB3b3JsZF9tYXBfZGF0YSAlPiUNCiAgZmlsdGVyKGxvbmcgPj0gZXVyb3BlX2JvdW5kc1sxXSwgbG9uZyA8PSBldXJvcGVfYm91bmRzWzJdLA0KICAgICAgICAgbGF0ID49IGV1cm9wZV9ib3VuZHNbM10sIGxhdCA8PSBldXJvcGVfYm91bmRzWzRdKQ0KDQojIFBsb3R0aW5nDQpwX2V1cm9wZSA8LSBnZ3Bsb3QoZGF0YSA9IGV1cm9wZV9tYXBfZGF0YSwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gY29sb3JfY2F0ZWdvcnkpKSArDQogIGdlb21fcG9seWdvbihjb2xvciA9ICJibGFjayIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJJUSIsDQogICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoIj08IDg1IiA9ICJvcmFuZ2UyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODUgdG8gODgiID0gIiNGRkRENTUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4OCB0byA5MSIgPSAiI0ZGRUVDQyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjkxIHRvIDk0IiA9ICIjQ0NFRUZGIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiOTQgdG8gOTciID0gIiM2NkNDRkYiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI5NyB0byAxMDAiID0gIiM0NDc3RUUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI+IDEwMCIgPSAiIzQ0MjJBQSIpKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnModGl0bGUgPSAiIikNCg0KcF9ldXJvcGUNCmZpbGVfbmFtZSA8LSBwYXN0ZTAoJ291dHB1dC9ldW1hcC5wbmcnKQ0KZ2dzYXZlKGZpbGVuYW1lID0gZmlsZV9uYW1lLCBkcGkgPSA0MjApDQoNCmBgYA0KDQoNCkNoYXJ0IG9mIEx5bm4gMjAwMiBhbmQgY3VycmVudCBlc3RpbWF0ZXMNCmBgYHtyfQ0KcCA8LSBHR19zY2F0dGVyKG9ubHlzY29yZXM0LCAnTklRJywgJ0wuVjAyJywgY2FzZV9uYW1lcz0nYWxwaGEzJykgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIHNlID0gRkFMU0UsIGNvbG9yID0gJ2JsdWUnKSArIA0KICBsYWJzKHggPSAnTmF0aW9uYWwgSVEgKEplbnNlbiAmIEtpcmtlZ2FhcmQsIDIwMjQpJywgeSA9ICJOYXRpb25hbCBJUSAoTHlubiBhbmQgVmFuaGFubmVuLCAyMDAyKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikNCiAgKQ0KDQpwDQpmaWxlX25hbWUgPC0gcGFzdGUwKCdvdXRwdXQvbHYuanBnJykNCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGVfbmFtZSwgZHBpID0gNDIwKQ0KYGBgDQoNCg0KQ2hhcnRpbmcgcmVsYXRpb25zaGlwIGJldHdlZW4gc3RhbmRhcmQgZXJyb3JzIGFuZCBtZWFucyAoZmluYWwgZGF0YSkNCmBgYHtyfQ0KZml0MiA8LSBsbShkYXRhPW9ubHlzY29yZXM0LCBzZWFkaiB+IE5JUSkNCnN1bW1hcnkoZml0MikNCg0KZml0NCA8LSBsbShkYXRhPW9ubHlzY29yZXM0LCBzZWFkaiB+IG5zKE5JUSwgZGY9NCkpDQpzdW1tYXJ5KGZpdDQpDQoNCiMgcGFzc2VzDQphbm92YShmaXQ0LCBmaXQyKQ0KDQp1emkzIDwtIHNlcShmcm9tPTYyLCB0bz0xMDksIGJ5PTAuMDEpDQp1emk0IDwtIGRhdGEuZnJhbWUoTklRPXV6aTMpDQp1emk0JGZpdCA9IHByZWRpY3QoZml0NCwgdXppNCwgaW50ZXJ2YWwgPSAiY29uZmlkZW5jZSIpDQoNCnAgPC0gZ2dwbG90KHV6aTQpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9TklRLCB5PXNlYWRqKSwgZGF0YT1vbmx5c2NvcmVzNCkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IHV6aTQsIGFlcyh4ID0gTklRLCB5ID0gZml0WywgMV0pLCBjb2xvciA9ICJncmVlbiIsIHNpemUgPSAxKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSB1emk0LCBhZXMoeCA9IE5JUSwgeW1pbiA9IGZpdFssIDJdLCB5bWF4ID0gZml0WywgM10pLCBhbHBoYSA9IDAuMzUpICsgIyBDb25maWRlbmNlIGludGVydmFsIHNoYWRpbmcNCiAgZ2VvbV90ZXh0KGRhdGEgPSBvbmx5c2NvcmVzNCwgYWVzKHggPSBOSVEsIHkgPSBzZWFkaiwgbGFiZWwgPSBhbHBoYTMpLCB2anVzdCA9IC0uNjYsIHNpemUgPSAzKSArICMgQWRkIGNvdW50cnkgbGFiZWxzDQogIGxhYnModGl0bGUgPSAic3BlYXJtYW4ncyByaG8gPSAtLjYzLCBuID0gMjAxIikgKw0KICB4bGFiKCdOYXRpb25hbCBJUScpICsNCiAgeWxhYignU3RhbmRhcmQgRXJyb3InKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpDQogICkNCg0KcGxvdChwKQ0KDQpmaWxlX25hbWUgPC0gcGFzdGUwKCdvdXRwdXQvc2VjaGFydC5qcGcnKQ0KZ2dzYXZlKHBsb3QgPSBwLCBmaWxlbmFtZSA9IGZpbGVfbmFtZSwgZHBpID0gNDIwKQ0KDQpgYGANCg0KQ2hhcnRpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFdCIHRlc3Qgc2NvcmVzIGFuZCBMeW5uIDIwMDIgZXN0aW1hdGVzLg0KDQpgYGB7cn0NCnAgPC0gR0dfc2NhdHRlcihvbmx5c2NvcmVzNCwgJ3didGVzdHNjb3JlJywgJ0wuVjAyJywgY2FzZV9uYW1lcz0nYWxwaGEzJykgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIHNlID0gRkFMU0UsIGNvbG9yID0gJ2JsdWUnKSArIA0KICBsYWJzKHggPSAnV29ybGQgQmFuayBUZXN0IFNjb3JlcycsIHkgPSAiTmF0aW9uYWwgSVEgKEx5bm4gYW5kIFZhbmhhbm5lbiwgMjAwMikiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwNCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpDQogICkNCnANCmZpbGVfbmFtZSA8LSBwYXN0ZTAoJ291dHB1dC9sdjIuanBnJykNCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGVfbmFtZSwgZHBpID0gNDIwKQ0KDQpgYGANCg0KR3JvdXBpbmcgdGhlIEdEUCBkYXRhIHRvZ2V0aGVyLg0KYGBge3J9DQpIRElHRFAgPC0gSERJICU+JSBzZWxlY3QoaXNvMywgZ25pcGNfMjAyMSwgZ25pcGNfMjAyMCwgZ25pcGNfMjAxOSwgZ25pcGNfMjAxOCkNCklNRkdEUCRhbHBoYTMgPC0gY291bnRyeWNvZGUoSU1GR0RQWywgMV0gJT4lIHVubGlzdCgpLCBvcmlnaW4gPSAnY291bnRyeS5uYW1lJywgZGVzdGluYXRpb249J2lzbzNjJykNCg0KSU1GR0RQJGFscGhhM1tJTUZHRFBbLCAxXT09J0tvc292byddIDwtICdLU1YnDQpJTUZHRFAkYWxwaGEzW0lNRkdEUFssIDFdPT0nVGltb3InXSA8LSAnVExTJw0KSU1GR0RQJGFscGhhM1tJTUZHRFBbLCAxXT09J1RpbW9yJ10gPC0gJ1RMUycNCklNRkdEUCRhbHBoYTNbSU1GR0RQWywgMV09PSdBdXN0cmFsaWEgYW5kIE5ldyBaZWFsYW5kJ10gPC0gJ05aTCcNCg0KSU1GR0RQJGdkcDIwMjIgPC0gYXMubnVtZXJpYyhJTUZHRFBbLCA0NF0gJT4lIHVubGlzdCgpKQ0KSU1GR0RQJGdkcDIwMjEgPC0gYXMubnVtZXJpYyhJTUZHRFBbLCA0M10gJT4lIHVubGlzdCgpKQ0KSU1GR0RQJGdkcDIwMjAgPC0gYXMubnVtZXJpYyhJTUZHRFBbLCA0Ml0gJT4lIHVubGlzdCgpKQ0KSU1GR0RQJGdkcDIwMTkgPC0gYXMubnVtZXJpYyhJTUZHRFBbLCA0MV0gJT4lIHVubGlzdCgpKQ0KSU1GR0RQJGdkcDIwMTggPC0gYXMubnVtZXJpYyhJTUZHRFBbLCA0MF0gJT4lIHVubGlzdCgpKQ0KQ0lBR0RQJGFscGhhMyA8LSBjb3VudHJ5Y29kZShDSUFHRFAkbmFtZSwgb3JpZ2luID0gJ2NvdW50cnkubmFtZScsIGRlc3RpbmF0aW9uPSdpc28zYycpDQpDSUFHRFAkYWxwaGEzW0NJQUdEUCRuYW1lPT0nS29zb3ZvJ10gPC0gJ0tTVicNClNQSSA8LSBTUEkgJT4lIGZpbHRlcihzcGl5ZWFyID4gMjAxNyAmIHNwaXllYXIgPCAyMDIzKQ0KDQphdmVyYWdlX3Njb3JlcyA8LSBTUEkgJT4lDQogIGZpbHRlcihzcGl5ZWFyICVpbiUgMjAxODoyMDIyKSAlPiUgICMgRmlsdGVyIGZvciB0aGUgc3BlY2lmaWMgeWVhcnMNCiAgZ3JvdXBfYnkoc3BpY291bnRyeWNvZGUpICU+JSAgIyBHcm91cCBieSBjb3VudHJ5DQogIHN1bW1hcmlzZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIH5tZWFuKC54LCBuYS5ybSA9IFRSVUUpLCAubmFtZXMgPSAiYXZnX3suY29sfSIpKSAgIyBBdmVyYWdlIGZvciBlYWNoIG51bWVyaWMgY29sdW1uDQoNCiNHRFAgY2FsY3VsYXRpb25zDQpJTUZHRFAkZ2RwaW1mID0gcm93TWVhbnMoc3Vic2V0KElNRkdEUCwgc2VsZWN0PWMoZ2RwMjAxOCwgZ2RwMjAxOSwgZ2RwMjAyMCwgZ2RwMjAyMSwgZ2RwMjAyMikpLCBuYS5ybSA9IFRSVUUpDQpXQkdEUCRnZHB3YiA9IHJvd01lYW5zKHN1YnNldChXQkdEUCwgc2VsZWN0PWMoWDIwMTgsIFgyMDE5LCBYMjAyMCwgWDIwMjEsIFgyMDIyKSksIG5hLnJtID0gVFJVRSkNCkhESUdEUCRnZHBoZGkgPSByb3dNZWFucyhzdWJzZXQoSERJR0RQLCBzZWxlY3Q9YyhnbmlwY18yMDE4LCBnbmlwY18yMDE5LCBnbmlwY18yMDIwLCBnbmlwY18yMDIxKSksIG5hLnJtID0gVFJVRSkNCkNJQUdEUCRnZHBjaWEgPC0gYXMubnVtZXJpYyhnc3ViKCJbXFwkLF0iLCAiIiwgQ0lBR0RQJHZhbHVlKSkNCg0KaW1mMiA8LSBJTUZHRFAgJT4lIHNlbGVjdChhbHBoYTMsIGdkcGltZikNCmltZjIgPC0gaW1mMlstMTM1LCBdDQp3YjIgPC0gV0JHRFAgJT4lIHNlbGVjdChDb3VudHJ5LkNvZGUsIGdkcHdiKQ0KaGRpMiA8LSBIRElHRFAgJT4lIHNlbGVjdChpc28zLCBnZHBoZGkpDQpjaWEyIDwtIENJQUdEUCAlPiUgc2VsZWN0KGFscGhhMywgZ2RwY2lhKQ0Kc3BpMiA8LSBhdmVyYWdlX3Njb3JlcyAlPiUgc2VsZWN0KHNwaWNvdW50cnljb2RlLCBhdmdfR0RQcGMpDQoNCkdOSVBQUElNRiRnbmlwcHBpbWYgPSByb3dNZWFucyhzdWJzZXQoR05JUFBQSU1GLCBzZWxlY3Q9YyhYMjAxOCwgWDIwMTksIFgyMDIwLCBYMjAyMSwgWDIwMjIpKSwgbmEucm0gPSBUUlVFKQ0KR05JUFBQSU1GMiA8LSBHTklQUFBJTUYgJT4lIHNlbGVjdChDb3VudHJ5LkNvZGUsIGduaXBwcGltZikNCg0KbWVkaWFud2VhbHRoJHdlYWx0aCA8LSBhcy5udW1lcmljKG1lZGlhbndlYWx0aCRNZWRpYW4pDQptZWRpYW53ZWFsdGgkYWxwaGEzIDwtIGNvdW50cnljb2RlKG1lZGlhbndlYWx0aCRMb2NhdGlvbiwgb3JpZ2luID0gJ2NvdW50cnkubmFtZScsIGRlc3RpbmF0aW9uPSdpc28zYycpDQptZWRpYW53ZWFsdGgkYWxwaGEzW21lZGlhbndlYWx0aCRMb2NhdGlvbj09J0d1eWFuYSddIDwtICdHVVknDQptZWRpYW5pbmNvbWUkaW5jb21lIDwtIGFzLm51bWVyaWMobWVkaWFuaW5jb21lJG1lZGlhbkluY29tZUJ5Q291bnRyeV9tZWRpYW5JbmNvbWUpDQptZWRpYW5pbmNvbWUkYWxwaGEzIDwtIGNvdW50cnljb2RlKG1lZGlhbmluY29tZSRjb3VudHJ5LCBvcmlnaW4gPSAnY291bnRyeS5uYW1lJywgZGVzdGluYXRpb249J2lzbzNjJykNCm1lZGlhbmluY29tZSRhbHBoYTNbbWVkaWFuaW5jb21lJGNvdW50cnk9PSdNaWNyb25lc2lhJ10gPC0gJ0ZTTScNCm1pMiA8LSBtZWRpYW5pbmNvbWUgJT4lIHNlbGVjdChhbHBoYTMsIGluY29tZSkNCm13MiA8LSBtZWRpYW53ZWFsdGggJT4lIHNlbGVjdChhbHBoYTMsIHdlYWx0aCkNCg0KZ2RwY3VtIDwtIGZ1bGxfam9pbihpbWYyLCB3YjIsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gQ291bnRyeS5Db2RlKSkNCmdkcGN1bTIgPC0gZnVsbF9qb2luKGdkcGN1bSwgaGRpMiwgYnkgPSBqb2luX2J5KGFscGhhMyA9PSBpc28zKSkNCmdkcGN1bTMgPC0gZnVsbF9qb2luKGdkcGN1bTIsIGNpYTIsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gYWxwaGEzKSkNCmdkcGN1bTQgPC0gZnVsbF9qb2luKGdkcGN1bTMsIHNwaTIsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gc3BpY291bnRyeWNvZGUpKQ0KZ2RwY3VtNSA8LSBmdWxsX2pvaW4oZ2RwY3VtNCwgbWkyLCBieSA9IGpvaW5fYnkoYWxwaGEzID09IGFscGhhMykpDQpnZHBjdW02IDwtIGZ1bGxfam9pbihnZHBjdW01LCBtdzIsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gYWxwaGEzKSkNCmdkcGN1bTcgPC0gZnVsbF9qb2luKGdkcGN1bTYsIEdOSVBQUElNRjIsIGJ5ID0gam9pbl9ieShhbHBoYTMgPT0gQ291bnRyeS5Db2RlKSkNCg0KZ2RwY3VtNyA8LSBnZHBjdW03Wy0xOTMsIF0NCg0KZ2RwY3VtNyA8LSBnZHBjdW03ICU+JSBmaWx0ZXIoIWlzLm5hKGFscGhhMykpDQpnZHBjdW03IDwtIGdkcGN1bTdbMToyNjksIF0NCmdkcGN1bTckZ2Rwc3BpIDwtIGdkcGN1bTckYXZnX0dEUHBjDQpnZHBjdW03JGduaWhkaSA8LSBnZHBjdW03JGdkcGhkaQ0KDQpnZHBjdW03JEdEUCA9IHJvd01lYW5zKHN1YnNldChnZHBjdW03LCBzZWxlY3Q9YyhnZHB3YiwgZ2RwY2lhLCBnZHBpbWYsIGdkcHNwaSkpLCBuYS5ybSA9IFRSVUUpDQoNCmVzY2EgPC0gZ2RwY3VtNyAlPiUgc2VsZWN0KEdEUCwgaW5jb21lLCB3ZWFsdGgsIGduaWhkaSwgZ25pcHBwaW1mLCBhbHBoYTMpDQoNCmBgYA0KDQpSZWdyZXNzaW5nIEdEUCBvbnRvIE5JUS4NCmBgYHtyfQ0KZm9yY2hhcnQgPC0gZnVsbF9qb2luKHR2aXFzLCBlc2NhLCBieSA9IGpvaW5fYnkoYWxwaGEzID09IGFscGhhMykpDQoNCiNWQ1QgYW5kIEZTTSBub3QgaW4gb3JpZ2luYWwNCmZvcmNoYXJ0IDwtIGZvcmNoYXJ0ICU+JSBmaWx0ZXIoIWFscGhhMz09J1ZDVCcpDQpmb3JjaGFydCA8LSBmb3JjaGFydCAlPiUgZmlsdGVyKCFhbHBoYTM9PSdGU00nKQ0KDQpwIDwtIEdHX3NjYXR0ZXIoZm9yY2hhcnQsICdOSVEnLCAnR0RQJywgY2FzZV9uYW1lcz0nYWxwaGEzJykgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsbScsIHNlID0gVCwgY29sb3IgPSAnb3JhbmdlJykgKyANCiAgZ2VvbV9zbW9vdGgoc2UgPSBULCBjb2xvciA9ICdibHVlJykgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikNCiAgKQ0KcA0KZmlsZV9uYW1lIDwtIHBhc3RlMCgnb3V0cHV0L25pcW5nZHAuanBnJykNCmdnc2F2ZShmaWxlbmFtZSA9IGZpbGVfbmFtZSwgZHBpID0gNDIwKQ0KYGBgDQpgYGB7cn0NCm9ubHlzY29yZXM0JHNmIDwtIHBub3JtKChvbmx5c2NvcmVzNCROSVEtMTI1KS8xNSkNCg0KZnVzZWR0cmFucyA8LSBsZWZ0X2pvaW4ob25seXNjb3JlczQsIGVzY2EsIGJ5PSdhbHBoYTMnKQ0KDQpmdXNlZHRyYW5zIDwtIGZ1c2VkdHJhbnMgJT4lIGZpbHRlcighYWxwaGEzPT0nVkNUJykNCmZ1c2VkdHJhbnMgPC0gZnVzZWR0cmFucyAlPiUgZmlsdGVyKCFhbHBoYTM9PSdGU00nKQ0KcDIgPC0gR0dfc2NhdHRlcihmdXNlZHRyYW5zLCAnc2YnLCAnR0RQJywgY2FzZV9uYW1lcz0nYWxwaGEzJykgKyBsYWJzKHggPSAiUHJlZGljdGVkICUgd2hvIHNjb3JlIGFib3ZlIDEyNSIsIHkgPSAiR0RQIHBlciBjYXBpdGEiLCB0aXRsZSA9ICIiKSArIHRoZW1lKA0KICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikNCikgKyBnZW9tX3Ntb290aCgpDQpwMg0KZmlsZV9uYW1lIDwtIHBhc3RlMCgnb3V0cHV0L2RsaWZ0Mi5qcGcnKQ0KZ2dzYXZlKHBsb3QgPSBwLCBmaWxlbmFtZSA9IGZpbGVfbmFtZSwgZHBpID0gNDIwKQ0KDQpgYGANCg0KV29ybGQgSVEgbWFwLg0KYGBge3J9DQp3b3JsZF9tYXAgPC0gbWFwX2RhdGEoIndvcmxkIikNCndvcmxkX21hcCRhbHBoYTMgPC0gY291bnRyeWNvZGUod29ybGRfbWFwJHJlZ2lvbiwgb3JpZ2luID0gImNvdW50cnkubmFtZSIsIGRlc3RpbmF0aW9uID0gImlzbzNjIikNCg0Kb25seWIgPC0gb25seXNjb3JlczQgJT4lIGZpbHRlcighaXMubmEoYWxwaGEzKSkNCg0Kd29ybGRfbWFwX2RhdGEgPC0gbGVmdF9qb2luKHdvcmxkX21hcCwgb25seWIsIGJ5ID0gYygnYWxwaGEzJykpDQoNCndvcmxkX21hcF9kYXRhJGNvbG9yX2NhdGVnb3J5IDwtIGN1dCh3b3JsZF9tYXBfZGF0YSROSVEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgNzEsIDc2LCA4MSwgODYsIDkxLCA5NiwgMTAxLCBJbmYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoJz08IDcxJywgJzcxIHRvIDc2JywgJzc2IHRvIDgxJywgJzgxIHRvIDg2JywgJzg2IHRvIDkxJywgJzkxIHRvIDk2JywgJzk2IHRvIDEwMScsICc+IDEwMScpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2h0ID0gVFJVRSkNCg0KDQpwIDwtIGdncGxvdChkYXRhID0gd29ybGRfbWFwX2RhdGEsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGNvbG9yX2NhdGVnb3J5KSkgKw0KICBnZW9tX3BvbHlnb24oY29sb3IgPSAiYmxhY2siKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKG5hbWUgPSAiSVEiLA0KICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCI9PCA3MSIgPSAiZGFya3JlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjcxIHRvIDc2IiA9ICJyZWQxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNzYgdG8gODEiID0gIm9yYW5nZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjgxIHRvIDg2IiA9ICIjRkZERDU1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODYgdG8gOTEiID0gIiNGRkVFQ0MiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI5MSB0byA5NiIgPSAiIzY2Q0NGRiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjk2IHRvIDEwMSIgPSAiIzQ0NzdFRSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIj4gMTAxIiA9ICIjNDQyMkFBIikpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUocGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgbGFicyh0aXRsZSA9ICIiKQ0KDQpwDQoNCmZpbGVfbmFtZSA8LSBwYXN0ZTAoJ291dHB1dC9uYXRlZHlzc3Nzcy5wbmcnKQ0KZ2dzYXZlKGZpbGVuYW1lID0gZmlsZV9uYW1lLCBkcGkgPSA0MjApDQoNCmBgYA0KDQpSZWdyZXNzaW5nIGxvZ0dOSSBvbnRvIE5JUS4NCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjIyMzDQojUy1mYWN0b3IgZGF0YSBjbGVhbmluZw0KeWVhcnMgPC0gMjAxODoyMDIyDQp2YXJpYWJsZV9wYXR0ZXJuIDwtIHBhc3RlMCgiLipfKCIsIHBhc3RlKHllYXJzLCBjb2xsYXBzZSA9ICJ8IiksICIpIikNCnZhcmlhYmxlX3BhdHRlcm4NCg0KbG9uZ19oZGkgPC0gcGl2b3RfbG9uZ2VyKEhESSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgY29scyA9IG1hdGNoZXModmFyaWFibGVfcGF0dGVybiksDQogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSBjKCJ2YXJpYWJsZSIsICJ5ZWFyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfc2VwID0gIl8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc19kcm9wX25hID0gVFJVRSkNCg0KdGVyc3QgPC0gbG9uZ19oZGkgJT4lDQogIG11dGF0ZSh5ZWFyID0gYXMubnVtZXJpYyh5ZWFyKSkgJT4lIGZpbHRlcih5ZWFyICVpbiUgeWVhcnMpDQoNCmxvbmdfaGRpIDwtIHBpdm90X2xvbmdlcihIREksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBtYXRjaGVzKHZhcmlhYmxlX3BhdHRlcm4pLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gYygidmFyaWFibGUiLCAieWVhciIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3NlcCA9ICJfIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfZHJvcF9uYSA9IFRSVUUpICU+JQ0KICBtdXRhdGUoeWVhciA9IGFzLm51bWVyaWMoeWVhcikpICU+JSAjIENvbnZlcnQgeWVhciB0byBudW1lcmljDQogIGZpbHRlcih5ZWFyICVpbiUgeWVhcnMpICAjIEtlZXAgb25seSB0aGUgeWVhcnMgMjAxOC0yMDIyDQoNCg0KYXZlcmFnZV92YWx1ZXMyIDwtIGxvbmdfaGRpICU+JQ0KICBncm91cF9ieShpc28zLCB2YXJpYWJsZSkgJT4lDQogIHN1bW1hcmlzZShhdmVyYWdlID0gbWVhbih2YWx1ZSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICdkcm9wJykNCg0KDQp3aWRlX2hkaSA8LSBwaXZvdF93aWRlcihhdmVyYWdlX3ZhbHVlczIsIG5hbWVzX2Zyb20gPSB2YXJpYWJsZSwgdmFsdWVzX2Zyb20gPSBhdmVyYWdlKQ0KDQp3aWRlX2hkaSA8LSBkYXRhLmZyYW1lKHdpZGVfaGRpKQ0KU0ZBQ1RPUiA8LSBmdWxsX2pvaW4oU1BJLCB3aWRlX2hkaSwgYnkgPSBqb2luX2J5KHNwaWNvdW50cnljb2RlID09IGlzbzMpKQ0KU0ZBQ1RPUiA8LSBTRkFDVE9SICU+JSBmaWx0ZXIoIWlzLm5hKHNwaWNvdW50cnljb2RlKSkNClNGQUNUT1IgPC0gU0ZBQ1RPUiAlPiUgZmlsdGVyKHNwaXllYXI9PTIwMjIpDQpTRkFDVE9SIDwtIGZ1bGxfam9pbihTRkFDVE9SLCBlc2NhLCBieSA9IGpvaW5fYnkoc3BpY291bnRyeWNvZGUgPT0gYWxwaGEzKSkNClNGQUNUT1IkR05JID0gcm93TWVhbnMoc3Vic2V0KFNGQUNUT1IsIHNlbGVjdD1jKGduaXBjLCBnbmloZGksIGduaXBwcGltZikpLCBuYS5ybSA9IFRSVUUpDQpTRkFDVE9SJEdOSVtTRkFDVE9SJHNwaWNvdW50cnljb2RlPT0nTUFDJ10gPC0gOTI0ODcuNQ0KU0ZBQ1RPUiRhbHBoYTMgPC0gU0ZBQ1RPUiRzcGljb3VudHJ5Y29kZQ0KZ25pcyA8LSBTRkFDVE9SICU+JSBzZWxlY3QoR05JLCBhbHBoYTMpDQoNCmZvcmNoYXJ0MiA8LSBmdWxsX2pvaW4oZ25pcywgb25seXNjb3JlczQsIGJ5PSdhbHBoYTMnKQ0KDQpmb3JjaGFydDIkbG9nR05JIDwtIGxvZyhmb3JjaGFydDIkR05JKQ0KcCA8LSBHR19zY2F0dGVyKGZvcmNoYXJ0MiwgJ05JUScsICdsb2dHTkknLCBjYXNlX25hbWVzPSdhbHBoYTMnKSArIGxhYnMoDQogIHggPSAnTmF0aW9uYWwgSVEgKEplbnNlbiAmIEtpcmtlZ2FhcmQsIDIwMjQpJywgDQogIHkgPSAibG9nKEdOSSkiDQopICsNCiAgdGhlbWVfbWluaW1hbCgpICsgICMgVXNlIGEgbWluaW1hbCB0aGVtZQ0KICB0aGVtZV9idygpICsgICMgQmFzZSB0aGVtZSB3aXRoIHdoaXRlIGJhY2tncm91bmQNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsDQogICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKQ0KICApDQoNCiMgUHJpbnQgdGhlIHBsb3QNCnByaW50KHApDQpnZ3NhdmUocGxvdCA9IHAsIGZpbGVuYW1lID0gJ291dHB1dC9vZXllb3BlbjI0My5qcGcnLCBkcGkgPSA0MjApDQoNCg0KbHIgPC0gbG0oZGF0YT1mb3JjaGFydDIsIGxvZ0dOSSB+IE5JUSkNCnN1bW1hcnkobHIpDQoNCmBgYA==