1. Defining malnutrition
1.1. Prerequisites
library(tidyverse)
library(zscorer)
library(readr)
library(dplyr)
library (lubridate)
library (ggplot2)
library (rmarkdown)
library(openxlsx)
PSFI_df_malnutrition <- read_csv("Ben_cut_4_27.csv")
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(
date_present = as.POSIXct(date_present, format = "%d%b%Y:%H:%M:%S", tz = "UTC"),
dob = mdy(dob),
age_days_exact = as.numeric(difftime(date_present, dob, units = "days"))
)
summary(PSFI_df_malnutrition$age_days_exact)
Min. 1st Qu. Median Mean 3rd Qu. Max.
32.03 289.19 604.61 1124.44 1461.64 5452.40
View(PSFI_df_malnutrition)
1.2. Anthroprometric analysis
PSFI_df_malnutrition %>%
filter(case_control == 1) %>%
select(ht, wt, age_years, muac) %>%
summary()
Error in `select()`:
! Can't select columns that don't exist.
✖ Column `age_years` doesn't exist.
Run `]8;;x-r-run:rlang::last_trace()rlang::last_trace()]8;;` to see where the error occurred.
# Layout to split the screen
layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))
# Draw the boxplot and the histogram
par(mar=c(0, 3.1, 1.1, 2.1))
boxplot(PSFI_df_malnutrition$ht[PSFI_df_malnutrition$case_control == 1] , horizontal=TRUE , ylim=c(0,200), xaxt="n" , col=rgb(0.8,0.8,0,0.5) , frame=F)
par(mar=c(4, 3.1, 1.1, 2.1))
hist(PSFI_df_malnutrition$ht[PSFI_df_malnutrition$case_control == 1]
, breaks=40 , col=rgb(1,0.8,0.8,1) , border=F , main="" , xlab="Height (cm)", xlim=c(0,200))

layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))
par(mar=c(0, 3.1, 1.1, 2.1))
boxplot(PSFI_df_malnutrition$wt[PSFI_df_malnutrition$case_control == 1] , horizontal=TRUE , ylim=c(0,80), xaxt="n" , col=rgb(0.8,0.8,0,0.5) , frame=F)
par(mar=c(4, 3.1, 1.1, 2.1))
hist(PSFI_df_malnutrition$wt[PSFI_df_malnutrition$case_control == 1]
, breaks=40 , col=rgb(1,0.8,0.8,1) , border=F , main="" , xlab="Weight (kg)", xlim=c(0,80))

layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))
par(mar=c(0, 3.1, 1.1, 2.1))
boxplot(PSFI_df_malnutrition$muac[PSFI_df_malnutrition$case_control == 1] , horizontal=TRUE , ylim=c(5,30), xaxt="n" , col=rgb(0.8,0.8,0,0.5) , frame=F)
par(mar=c(4, 3.1, 1.1, 2.1))
hist(PSFI_df_malnutrition$muac[PSFI_df_malnutrition$case_control == 1]
, breaks=20 , col=rgb(1,0.8,0.8,1) , border=F , main="" , xlab="Mid-upper arm circumference (cm)", xlim=c(5,30))
abline(v = 11.5, col = "red", lwd = 2, lty = 2) # severe
abline(v = 12.5, col = "blue", lwd = 2, lty = 2) # moderate

PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(age_years = age_days_exact / 365.25)
summary(PSFI_df_malnutrition$age_years)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.08768 0.79176 1.65535 3.07854 4.00176 14.92786
layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))
par(mar=c(0, 3.1, 1.1, 2.1))
boxplot(PSFI_df_malnutrition$age_years[PSFI_df_malnutrition$case_control == 1] , horizontal=TRUE , ylim=c(0,15), xaxt="n" , col=rgb(0.8,0.8,0,0.5) , frame=F)
par(mar=c(4, 3.1, 1.1, 2.1))
hist(PSFI_df_malnutrition$age_years[PSFI_df_malnutrition$case_control == 1]
, breaks=40 , col=rgb(1,0.8,0.8,1) , border=F , main="" , xlab="Age (years)", xlim=c(0,15))

1.3. Z-scorer
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(sex_who = if_else(sex == 1, 1, 2))
summary(PSFI_df_malnutrition$sex_who)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 1.000 1.000 1.427 2.000 2.000
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(
age_group = case_when(
age_days_exact < 5 * 365.25 ~ 0L,
age_days_exact >= 5 * 365.25 ~ 1L,
TRUE ~ NA_integer_
)
)
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(
wflz = addWGSR(
data = .,
sex = "sex_who",
firstPart = "wt",
secondPart = "ht",
index = "wfl"
)$wflz,
wfhz = addWGSR(
data = .,
sex = "sex_who",
firstPart = "wt",
secondPart = "ht",
index = "wfh"
)$wfhz,
baz = addWGSR(
data = .,
sex = "sex_who",
firstPart = "wt",
secondPart = "ht",
thirdPart = "age_days_exact",
index = "bfa"
)$bfaz,
)
==============================================================================================
==============================================================================================
==============================================================================================
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(
muacz = case_when(
muac >= 12.5 ~ 0,
muac >= 11.5 & muac < 12.5 ~ -2.5,
muac < 11.5 ~ -4,
TRUE ~ NA_real_
)
)
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(
zscore_unified = case_when(
age_group == 0 & ht >= 45 & ht < 65 ~ wflz,
age_group == 0 & ht >= 65 & ht < 120 ~ wfhz,
age_group == 0 & (ht < 45 | ht >= 120 | is.na(ht)) ~ muacz,
age_group == 1 ~ baz,
TRUE ~ NA_real_
)
)
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(
malnutrition = case_when(
is.na(zscore_unified) ~ NA_integer_,
zscore_unified < -3 ~ 2L,
zscore_unified >= -3 & zscore_unified < -2 ~ 1L,
TRUE ~ 0L
)
)
PSFI_df_malnutrition <- PSFI_df_malnutrition %>%
mutate(
malnutrition_source = case_when(
age_group == 0 & ht >= 45 & ht < 65 ~ "WFL",
age_group == 0 & ht >= 65 & ht < 120 ~ "WFH",
age_group == 0 & (ht < 45 | ht >= 120 | is.na(ht)) ~ "MUAC",
age_group == 1 ~ "BFA",
TRUE ~ NA_character_
)
)
1.4 Z score check
PSFI_df_malnutrition %>%
filter(age_group == 1 & case_control == 1) %>%
pull(baz) %>%
summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
-11.0000 -2.1325 -0.4700 -0.2723 1.1300 32.6700
PSFI_df_malnutrition %>%
filter(age_group == 0 & ht >= 45 & ht < 65 & case_control == 1) %>%
pull(wflz) %>%
summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
-4.9000 -1.0075 0.8800 0.9719 2.4400 13.7700
PSFI_df_malnutrition %>%
filter(age_group == 0 & ht >= 65 & ht < 120 & case_control == 1) %>%
pull(wfhz) %>%
summary()
Min. 1st Qu. Median Mean 3rd Qu. Max.
-10.5900 -2.4175 -0.8900 -0.9841 0.7500 12.8800
layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))
par(mar=c(0, 3.1, 1.1, 2.1))
boxplot(PSFI_df_malnutrition$baz[PSFI_df_malnutrition$age_group == 1 & PSFI_df_malnutrition$case_control == 1] , horizontal=TRUE , ylim=c(-10,10), xaxt="n" , col=rgb(0.8,0.8,0,0.5) , frame=F)
par(mar=c(4, 3.1, 1.1, 2.1))
hist(PSFI_df_malnutrition$baz[PSFI_df_malnutrition$age_group == 1 & PSFI_df_malnutrition$case_control == 1]
, breaks=50 , col=rgb(1,0.8,0.8,1) , border=F , main="" , xlab="BMI for age (z-score)", xlim=c(-10,10))

layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))
par(mar=c(0, 3.1, 1.1, 2.1))
boxplot(PSFI_df_malnutrition$wfhz[PSFI_df_malnutrition$age_group == 0 & PSFI_df_malnutrition$ht >= 65 & PSFI_df_malnutrition$ht < 120 & PSFI_df_malnutrition$case_control == 1] , horizontal=TRUE , ylim=c(-10,10), xaxt="n" , col=rgb(0.8,0.8,0,0.5) , frame=F)
par(mar=c(4, 3.1, 1.1, 2.1))
hist(PSFI_df_malnutrition$wfhz[PSFI_df_malnutrition$age_group == 0 & PSFI_df_malnutrition$ht >= 65 & PSFI_df_malnutrition$ht < 120 & PSFI_df_malnutrition$case_control == 1]
, breaks=50 , col=rgb(1,0.8,0.8,1) , border=F , main="" , xlab="Weight-for-height (z-score)", xlim=c(-10,10))

layout(mat = matrix(c(1,2),2,1, byrow=TRUE), height = c(1,8))
par(mar=c(0, 3.1, 1.1, 2.1))
boxplot(PSFI_df_malnutrition$wflz[PSFI_df_malnutrition$age_group == 0 & PSFI_df_malnutrition$ht >= 45 & PSFI_df_malnutrition$ht < 65 & PSFI_df_malnutrition$case_control == 1] , horizontal=TRUE , ylim=c(-10,10), xaxt="n" , col=rgb(0.8,0.8,0,0.5) , frame=F)
par(mar=c(4, 3.1, 1.1, 2.1))
hist(PSFI_df_malnutrition$wflz[PSFI_df_malnutrition$age_group == 0 & PSFI_df_malnutrition$ht >= 45 & PSFI_df_malnutrition$ht < 65 & PSFI_df_malnutrition$case_control == 1]
, breaks=50 , col=rgb(1,0.8,0.8,1) , border=F , main="" , xlab="Weight for length (z-score)", xlim=c(-10,10))

## muac is not based on z-score, but rather if it is <115mm, between 115-125 or >125mm
PSFI_df_malnutrition %>%
filter(case_control == 1) %>%
drop_na(muacz) %>%
mutate(
malnutrition_status = case_when(
muacz < -3 ~ "Severe malnutrition",
muacz >= -3 & muacz < -2 ~ "Moderate malnutrition",
muacz >= -2 ~ "No malnutrition",
TRUE ~ NA_character_
)
) %>%
ggplot(aes(x = malnutrition_status)) +
geom_bar() +
labs(
x = "Malnutrition status based on MUAC",
y = "N"
)

1.5 Data check
PSFI_df_malnutrition%>%
group_by(malnutrition) %>%
summarize(
malnutrition_missing = sum(is.na(malnutrition)),
mort_inhosp_missing = sum(is.na(mort_inhosp)), #103 mort_inhosp_miissing = controls
)
PSFI_df_malnutrition %>%
filter (case_control == 1) %>%
group_by(malnutrition_source) %>%
summarize(
count_malnut = n()
)
# NA due to child with height of 20 cm (under WHO curve for wfh/wfl) and 38 days old (too young for MUAC)
PSFI_df_malnutrition %>%
filter (case_control == 1) %>%
group_by(malnutrition) %>%
summarize(
count_malnut = n()
)
PSFI_df_malnutrition %>%
drop_na(malnutrition, mort_inhosp) %>%
ggplot(aes(x = factor(malnutrition))) +
geom_bar() +
labs(
x = "Malnutrition",
y = "N"
)

PSFI_df_malnutrition%>%
filter (case_control == 1) %>%
count(malnutrition, mort_inhosp) %>%
group_by(malnutrition) %>%
mutate(prop = n / sum(n))
PSFI_df_malnutrition %>%
drop_na(mort_inhosp, malnutrition) %>% #only cases & minus the one previously mentioned NA
ggplot +
(aes(x = factor(malnutrition), fill = factor(mort_inhosp))) +
geom_bar(stat = "count", position = "fill") +
labs(
x = "Malnutrition",
y = "Proportion",
fill = "Mortality"
)

PSFI_df_malnutrition %>%
drop_na(malnutrition) %>%
ggplot +
(aes(x = factor(malnutrition), fill = factor(case_control))) +
geom_bar(stat = "count", position = "fill") +
labs(
x = "Malnutrition",
y = "Proportion",
fill = "Case/Control"
)

write.xlsx(PSFI_df_malnutrition, file = "PSFI_final_malnutrition.xlsx")
LS0tCnRpdGxlOiAiVGhlIERvdWJsZSBCdXJkZW4gb2YgTWFsbnV0cml0aW9uIGFuZCBQZWRpYXRyaWMgU2Vwc2lzIGluIFRhbnphbmlhIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyAxLiBEZWZpbmluZyBtYWxudXRyaXRpb24KCiMjIDEuMS4gUHJlcmVxdWlzaXRlcwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHpzY29yZXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkgKGx1YnJpZGF0ZSkKbGlicmFyeSAoZ2dwbG90MikKbGlicmFyeSAocm1hcmtkb3duKQpsaWJyYXJ5KG9wZW54bHN4KQpgYGAKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiA8LSByZWFkX2NzdigiQmVuX2N1dF80XzI3LmNzdiIpCmBgYAoKYGBge3J9CiAgUFNGSV9kZl9tYWxudXRyaXRpb24gPC0gUFNGSV9kZl9tYWxudXRyaXRpb24gJT4lCiAgbXV0YXRlKAogICAgZGF0ZV9wcmVzZW50ID0gYXMuUE9TSVhjdChkYXRlX3ByZXNlbnQsIGZvcm1hdCA9ICIlZCViJVk6JUg6JU06JVMiLCB0eiA9ICJVVEMiKSwKICAgIGRvYiA9IG1keShkb2IpLAogICAgYWdlX2RheXNfZXhhY3QgPSBhcy5udW1lcmljKGRpZmZ0aW1lKGRhdGVfcHJlc2VudCwgZG9iLCB1bml0cyA9ICJkYXlzIikpCiAgKQogIAogIApzdW1tYXJ5KFBTRklfZGZfbWFsbnV0cml0aW9uJGFnZV9kYXlzX2V4YWN0KQpgYGAKCmBgYHtyfQpWaWV3KFBTRklfZGZfbWFsbnV0cml0aW9uKQoKYGBgCgojIyAxLjIuIEFudGhyb3Byb21ldHJpYyBhbmFseXNpcwoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIGZpbHRlcihjYXNlX2NvbnRyb2wgPT0gMSkgJT4lCiAgc2VsZWN0KGh0LCB3dCwgYWdlX3llYXJzLCBtdWFjKSAlPiUKICBzdW1tYXJ5KCkKYGBgCgpgYGB7cn0KIyBMYXlvdXQgdG8gc3BsaXQgdGhlIHNjcmVlbgpsYXlvdXQobWF0ID0gbWF0cml4KGMoMSwyKSwyLDEsIGJ5cm93PVRSVUUpLCAgaGVpZ2h0ID0gYygxLDgpKQogCiMgRHJhdyB0aGUgYm94cGxvdCBhbmQgdGhlIGhpc3RvZ3JhbSAKcGFyKG1hcj1jKDAsIDMuMSwgMS4xLCAyLjEpKQpib3hwbG90KFBTRklfZGZfbWFsbnV0cml0aW9uJGh0W1BTRklfZGZfbWFsbnV0cml0aW9uJGNhc2VfY29udHJvbCA9PSAxXSAsIGhvcml6b250YWw9VFJVRSAsIHlsaW09YygwLDIwMCksIHhheHQ9Im4iICwgY29sPXJnYigwLjgsMC44LDAsMC41KSAsIGZyYW1lPUYpCnBhcihtYXI9Yyg0LCAzLjEsIDEuMSwgMi4xKSkKaGlzdChQU0ZJX2RmX21hbG51dHJpdGlvbiRodFtQU0ZJX2RmX21hbG51dHJpdGlvbiRjYXNlX2NvbnRyb2wgPT0gMV0KICAgICAsIGJyZWFrcz00MCAsIGNvbD1yZ2IoMSwwLjgsMC44LDEpICwgYm9yZGVyPUYgLCBtYWluPSIiICwgeGxhYj0iSGVpZ2h0IChjbSkiLCB4bGltPWMoMCwyMDApKQpgYGAKCmBgYHtyfQpsYXlvdXQobWF0ID0gbWF0cml4KGMoMSwyKSwyLDEsIGJ5cm93PVRSVUUpLCAgaGVpZ2h0ID0gYygxLDgpKQogcGFyKG1hcj1jKDAsIDMuMSwgMS4xLCAyLjEpKQpib3hwbG90KFBTRklfZGZfbWFsbnV0cml0aW9uJHd0W1BTRklfZGZfbWFsbnV0cml0aW9uJGNhc2VfY29udHJvbCA9PSAxXSAsIGhvcml6b250YWw9VFJVRSAsIHlsaW09YygwLDgwKSwgeGF4dD0ibiIgLCBjb2w9cmdiKDAuOCwwLjgsMCwwLjUpICwgZnJhbWU9RikKcGFyKG1hcj1jKDQsIDMuMSwgMS4xLCAyLjEpKQpoaXN0KFBTRklfZGZfbWFsbnV0cml0aW9uJHd0W1BTRklfZGZfbWFsbnV0cml0aW9uJGNhc2VfY29udHJvbCA9PSAxXQogICAgICwgYnJlYWtzPTQwICwgY29sPXJnYigxLDAuOCwwLjgsMSkgLCBib3JkZXI9RiAsIG1haW49IiIgLCB4bGFiPSJXZWlnaHQgKGtnKSIsIHhsaW09YygwLDgwKSkKYGBgCgpgYGB7cn0KbGF5b3V0KG1hdCA9IG1hdHJpeChjKDEsMiksMiwxLCBieXJvdz1UUlVFKSwgIGhlaWdodCA9IGMoMSw4KSkKcGFyKG1hcj1jKDAsIDMuMSwgMS4xLCAyLjEpKQpib3hwbG90KFBTRklfZGZfbWFsbnV0cml0aW9uJG11YWNbUFNGSV9kZl9tYWxudXRyaXRpb24kY2FzZV9jb250cm9sID09IDFdICwgaG9yaXpvbnRhbD1UUlVFICwgeWxpbT1jKDUsMzApLCB4YXh0PSJuIiAsIGNvbD1yZ2IoMC44LDAuOCwwLDAuNSkgLCBmcmFtZT1GKQpwYXIobWFyPWMoNCwgMy4xLCAxLjEsIDIuMSkpCmhpc3QoUFNGSV9kZl9tYWxudXRyaXRpb24kbXVhY1tQU0ZJX2RmX21hbG51dHJpdGlvbiRjYXNlX2NvbnRyb2wgPT0gMV0KICAgICAsIGJyZWFrcz0yMCAsIGNvbD1yZ2IoMSwwLjgsMC44LDEpICwgYm9yZGVyPUYgLCBtYWluPSIiICwgeGxhYj0iTWlkLXVwcGVyIGFybSBjaXJjdW1mZXJlbmNlIChjbSkiLCB4bGltPWMoNSwzMCkpCmFibGluZSh2ID0gMTEuNSwgY29sID0gInJlZCIsIGx3ZCA9IDIsIGx0eSA9IDIpICAgIyBzZXZlcmUKYWJsaW5lKHYgPSAxMi41LCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIsIGx0eSA9IDIpICAjIG1vZGVyYXRlCmBgYAoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uIDwtIFBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIG11dGF0ZShhZ2VfeWVhcnMgPSBhZ2VfZGF5c19leGFjdCAvIDM2NS4yNSkKCnN1bW1hcnkoUFNGSV9kZl9tYWxudXRyaXRpb24kYWdlX3llYXJzKQpgYGAKCmBgYHtyfQpsYXlvdXQobWF0ID0gbWF0cml4KGMoMSwyKSwyLDEsIGJ5cm93PVRSVUUpLCAgaGVpZ2h0ID0gYygxLDgpKQogcGFyKG1hcj1jKDAsIDMuMSwgMS4xLCAyLjEpKQpib3hwbG90KFBTRklfZGZfbWFsbnV0cml0aW9uJGFnZV95ZWFyc1tQU0ZJX2RmX21hbG51dHJpdGlvbiRjYXNlX2NvbnRyb2wgPT0gMV0gLCBob3Jpem9udGFsPVRSVUUgLCB5bGltPWMoMCwxNSksIHhheHQ9Im4iICwgY29sPXJnYigwLjgsMC44LDAsMC41KSAsIGZyYW1lPUYpCnBhcihtYXI9Yyg0LCAzLjEsIDEuMSwgMi4xKSkKaGlzdChQU0ZJX2RmX21hbG51dHJpdGlvbiRhZ2VfeWVhcnNbUFNGSV9kZl9tYWxudXRyaXRpb24kY2FzZV9jb250cm9sID09IDFdCiAgICAgLCBicmVha3M9NDAgLCBjb2w9cmdiKDEsMC44LDAuOCwxKSAsIGJvcmRlcj1GICwgbWFpbj0iIiAsIHhsYWI9IkFnZSAoeWVhcnMpIiwgeGxpbT1jKDAsMTUpKQpgYGAKCiMjIDEuMy4gWi1zY29yZXIKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiA8LSBQU0ZJX2RmX21hbG51dHJpdGlvbiAlPiUKICBtdXRhdGUoc2V4X3dobyA9IGlmX2Vsc2Uoc2V4ID09IDEsIDEsIDIpKQoKc3VtbWFyeShQU0ZJX2RmX21hbG51dHJpdGlvbiRzZXhfd2hvKQpgYGAKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiA8LSBQU0ZJX2RmX21hbG51dHJpdGlvbiAlPiUKICBtdXRhdGUoCiAgICBhZ2VfZ3JvdXAgPSBjYXNlX3doZW4oCiAgICAgIGFnZV9kYXlzX2V4YWN0IDwgNSAqIDM2NS4yNSB+IDBMLAogICAgICBhZ2VfZGF5c19leGFjdCA+PSA1ICogMzY1LjI1IH4gMUwsCiAgICAgIFRSVUUgfiBOQV9pbnRlZ2VyXwogICAgKQogICkKCmBgYAoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uIDwtIFBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIG11dGF0ZSgKICAgIHdmbHogPSBhZGRXR1NSKAogICAgICBkYXRhID0gLiwKICAgICAgc2V4ID0gInNleF93aG8iLAogICAgICBmaXJzdFBhcnQgPSAid3QiLAogICAgICBzZWNvbmRQYXJ0ID0gImh0IiwKICAgICAgaW5kZXggPSAid2ZsIgogICAgKSR3Zmx6LAogICAgCiAgICB3Zmh6ID0gYWRkV0dTUigKICAgICAgZGF0YSA9IC4sCiAgICAgIHNleCA9ICJzZXhfd2hvIiwKICAgICAgZmlyc3RQYXJ0ID0gInd0IiwKICAgICAgc2Vjb25kUGFydCA9ICJodCIsCiAgICAgIGluZGV4ID0gIndmaCIKICAgICkkd2ZoeiwKICAgIAogICAgYmF6ID0gYWRkV0dTUigKICAgICAgZGF0YSA9IC4sCiAgICAgIHNleCA9ICJzZXhfd2hvIiwKICAgICAgZmlyc3RQYXJ0ID0gInd0IiwKICAgICAgc2Vjb25kUGFydCA9ICJodCIsCiAgICAgIHRoaXJkUGFydCA9ICJhZ2VfZGF5c19leGFjdCIsCiAgICAgIGluZGV4ID0gImJmYSIKICAgICkkYmZheiwKICApCgpgYGAKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiA8LSBQU0ZJX2RmX21hbG51dHJpdGlvbiAlPiUKICBtdXRhdGUoCiAgICBtdWFjeiA9IGNhc2Vfd2hlbigKICAgICAgbXVhYyA+PSAxMi41IH4gMCwKICAgICAgbXVhYyA+PSAxMS41ICYgbXVhYyA8IDEyLjUgfiAtMi41LAogICAgICBtdWFjIDwgMTEuNSB+IC00LAogICAgICBUUlVFIH4gTkFfcmVhbF8KICAgICkKICApCmBgYAoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uIDwtIFBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIG11dGF0ZSgKICAgIHpzY29yZV91bmlmaWVkID0gY2FzZV93aGVuKAogICAgICBhZ2VfZ3JvdXAgPT0gMCAmIGh0ID49IDQ1ICYgaHQgPCA2NSB+IHdmbHosCiAgICAgIGFnZV9ncm91cCA9PSAwICYgaHQgPj0gNjUgJiBodCA8IDEyMCB+IHdmaHosCiAgICAgIGFnZV9ncm91cCA9PSAwICYgKGh0IDwgNDUgfCBodCA+PSAxMjAgfCBpcy5uYShodCkpIH4gbXVhY3osCiAgICAgIGFnZV9ncm91cCA9PSAxIH4gYmF6LAogICAgICBUUlVFIH4gTkFfcmVhbF8KICAgICkKICApCmBgYAoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uIDwtIFBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIG11dGF0ZSgKICAgIG1hbG51dHJpdGlvbiA9IGNhc2Vfd2hlbigKICBpcy5uYSh6c2NvcmVfdW5pZmllZCkgfiBOQV9pbnRlZ2VyXywKICB6c2NvcmVfdW5pZmllZCA8IC0zIH4gMkwsCiAgenNjb3JlX3VuaWZpZWQgPj0gLTMgJiB6c2NvcmVfdW5pZmllZCA8IC0yIH4gMUwsCiAgVFJVRSB+IDBMCiAgICApCiAgKQpgYGAKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiA8LSBQU0ZJX2RmX21hbG51dHJpdGlvbiAlPiUKICBtdXRhdGUoCiAgICBtYWxudXRyaXRpb25fc291cmNlID0gY2FzZV93aGVuKAogICAgICBhZ2VfZ3JvdXAgPT0gMCAmIGh0ID49IDQ1ICYgaHQgPCA2NSAgfiAiV0ZMIiwKICAgICAgYWdlX2dyb3VwID09IDAgJiBodCA+PSA2NSAmIGh0IDwgMTIwIH4gIldGSCIsCiAgICAgIGFnZV9ncm91cCA9PSAwICYgKGh0IDwgNDUgfCBodCA+PSAxMjAgfCBpcy5uYShodCkpIH4gIk1VQUMiLAogICAgICBhZ2VfZ3JvdXAgPT0gMSB+ICJCRkEiLAogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICAgKQogICkKYGBgCgojIyAxLjQgWiBzY29yZSBjaGVjawoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIGZpbHRlcihhZ2VfZ3JvdXAgPT0gMSAmIGNhc2VfY29udHJvbCA9PSAxKSAlPiUKICBwdWxsKGJheikgJT4lCiAgc3VtbWFyeSgpCgpgYGAKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiAlPiUKICBmaWx0ZXIoYWdlX2dyb3VwID09IDAgJiBodCA+PSA0NSAmIGh0IDwgNjUgJiBjYXNlX2NvbnRyb2wgPT0gMSkgJT4lCiAgcHVsbCh3Zmx6KSAlPiUKICBzdW1tYXJ5KCkKYGBgCgpgYGB7cn0KUFNGSV9kZl9tYWxudXRyaXRpb24gJT4lCiAgZmlsdGVyKGFnZV9ncm91cCA9PSAwICYgaHQgPj0gNjUgJiBodCA8IDEyMCAmIGNhc2VfY29udHJvbCA9PSAxKSAlPiUKICBwdWxsKHdmaHopICU+JQogIHN1bW1hcnkoKQpgYGAKCgpgYGB7cn0KbGF5b3V0KG1hdCA9IG1hdHJpeChjKDEsMiksMiwxLCBieXJvdz1UUlVFKSwgIGhlaWdodCA9IGMoMSw4KSkKIHBhcihtYXI9YygwLCAzLjEsIDEuMSwgMi4xKSkKYm94cGxvdChQU0ZJX2RmX21hbG51dHJpdGlvbiRiYXpbUFNGSV9kZl9tYWxudXRyaXRpb24kYWdlX2dyb3VwID09IDEgJiBQU0ZJX2RmX21hbG51dHJpdGlvbiRjYXNlX2NvbnRyb2wgPT0gMV0gLCBob3Jpem9udGFsPVRSVUUgLCB5bGltPWMoLTEwLDEwKSwgeGF4dD0ibiIgLCBjb2w9cmdiKDAuOCwwLjgsMCwwLjUpICwgZnJhbWU9RikKcGFyKG1hcj1jKDQsIDMuMSwgMS4xLCAyLjEpKQpoaXN0KFBTRklfZGZfbWFsbnV0cml0aW9uJGJheltQU0ZJX2RmX21hbG51dHJpdGlvbiRhZ2VfZ3JvdXAgPT0gMSAmIFBTRklfZGZfbWFsbnV0cml0aW9uJGNhc2VfY29udHJvbCA9PSAxXQogICAgICwgYnJlYWtzPTUwICwgY29sPXJnYigxLDAuOCwwLjgsMSkgLCBib3JkZXI9RiAsIG1haW49IiIgLCB4bGFiPSJCTUkgZm9yIGFnZSAoei1zY29yZSkiLCB4bGltPWMoLTEwLDEwKSkKYGBgCgpgYGB7cn0KbGF5b3V0KG1hdCA9IG1hdHJpeChjKDEsMiksMiwxLCBieXJvdz1UUlVFKSwgIGhlaWdodCA9IGMoMSw4KSkKIHBhcihtYXI9YygwLCAzLjEsIDEuMSwgMi4xKSkKYm94cGxvdChQU0ZJX2RmX21hbG51dHJpdGlvbiR3Zmh6W1BTRklfZGZfbWFsbnV0cml0aW9uJGFnZV9ncm91cCA9PSAwICYgUFNGSV9kZl9tYWxudXRyaXRpb24kaHQgPj0gNjUgJiBQU0ZJX2RmX21hbG51dHJpdGlvbiRodCA8IDEyMCAmIFBTRklfZGZfbWFsbnV0cml0aW9uJGNhc2VfY29udHJvbCA9PSAxXSAsIGhvcml6b250YWw9VFJVRSAsIHlsaW09YygtMTAsMTApLCB4YXh0PSJuIiAsIGNvbD1yZ2IoMC44LDAuOCwwLDAuNSkgLCBmcmFtZT1GKQpwYXIobWFyPWMoNCwgMy4xLCAxLjEsIDIuMSkpCmhpc3QoUFNGSV9kZl9tYWxudXRyaXRpb24kd2ZoeltQU0ZJX2RmX21hbG51dHJpdGlvbiRhZ2VfZ3JvdXAgPT0gMCAmIFBTRklfZGZfbWFsbnV0cml0aW9uJGh0ID49IDY1ICYgUFNGSV9kZl9tYWxudXRyaXRpb24kaHQgPCAxMjAgJiBQU0ZJX2RmX21hbG51dHJpdGlvbiRjYXNlX2NvbnRyb2wgPT0gMV0KICAgICAsIGJyZWFrcz01MCAsIGNvbD1yZ2IoMSwwLjgsMC44LDEpICwgYm9yZGVyPUYgLCBtYWluPSIiICwgeGxhYj0iV2VpZ2h0LWZvci1oZWlnaHQgKHotc2NvcmUpIiwgeGxpbT1jKC0xMCwxMCkpCmBgYAoKYGBge3J9CmxheW91dChtYXQgPSBtYXRyaXgoYygxLDIpLDIsMSwgYnlyb3c9VFJVRSksICBoZWlnaHQgPSBjKDEsOCkpCiBwYXIobWFyPWMoMCwgMy4xLCAxLjEsIDIuMSkpCmJveHBsb3QoUFNGSV9kZl9tYWxudXRyaXRpb24kd2ZseltQU0ZJX2RmX21hbG51dHJpdGlvbiRhZ2VfZ3JvdXAgPT0gMCAmIFBTRklfZGZfbWFsbnV0cml0aW9uJGh0ID49IDQ1ICYgUFNGSV9kZl9tYWxudXRyaXRpb24kaHQgPCA2NSAmIFBTRklfZGZfbWFsbnV0cml0aW9uJGNhc2VfY29udHJvbCA9PSAxXSAsIGhvcml6b250YWw9VFJVRSAsIHlsaW09YygtMTAsMTApLCB4YXh0PSJuIiAsIGNvbD1yZ2IoMC44LDAuOCwwLDAuNSkgLCBmcmFtZT1GKQpwYXIobWFyPWMoNCwgMy4xLCAxLjEsIDIuMSkpCmhpc3QoUFNGSV9kZl9tYWxudXRyaXRpb24kd2ZseltQU0ZJX2RmX21hbG51dHJpdGlvbiRhZ2VfZ3JvdXAgPT0gMCAmIFBTRklfZGZfbWFsbnV0cml0aW9uJGh0ID49IDQ1ICYgUFNGSV9kZl9tYWxudXRyaXRpb24kaHQgPCA2NSAmIFBTRklfZGZfbWFsbnV0cml0aW9uJGNhc2VfY29udHJvbCA9PSAxXQogICAgICwgYnJlYWtzPTUwICwgY29sPXJnYigxLDAuOCwwLjgsMSkgLCBib3JkZXI9RiAsIG1haW49IiIgLCB4bGFiPSJXZWlnaHQgZm9yIGxlbmd0aCAoei1zY29yZSkiLCB4bGltPWMoLTEwLDEwKSkKYGBgCmBgYHtyfQojIyBtdWFjIGlzIG5vdCBiYXNlZCBvbiB6LXNjb3JlLCBidXQgcmF0aGVyIGlmIGl0IGlzIDwxMTVtbSwgYmV0d2VlbiAxMTUtMTI1IG9yID4xMjVtbQpQU0ZJX2RmX21hbG51dHJpdGlvbiAlPiUKICBmaWx0ZXIoY2FzZV9jb250cm9sID09IDEpICU+JQogIGRyb3BfbmEobXVhY3opICU+JQogIG11dGF0ZSgKICAgIG1hbG51dHJpdGlvbl9zdGF0dXMgPSBjYXNlX3doZW4oCiAgICAgIG11YWN6IDwgLTMgfiAiU2V2ZXJlIG1hbG51dHJpdGlvbiIsCiAgICAgIG11YWN6ID49IC0zICYgbXVhY3ogPCAtMiB+ICJNb2RlcmF0ZSBtYWxudXRyaXRpb24iLAogICAgICBtdWFjeiA+PSAtMiB+ICJObyBtYWxudXRyaXRpb24iLAogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICAgKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbWFsbnV0cml0aW9uX3N0YXR1cykpICsKICBnZW9tX2JhcigpICsKICBsYWJzKAogICAgeCA9ICJNYWxudXRyaXRpb24gc3RhdHVzIGJhc2VkIG9uIE1VQUMiLAogICAgeSA9ICJOIgogICkKYGBgCgoKIyMgMS41IERhdGEgY2hlY2sKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiU+JQogIGdyb3VwX2J5KG1hbG51dHJpdGlvbikgJT4lCiAgc3VtbWFyaXplKAogICAgbWFsbnV0cml0aW9uX21pc3NpbmcgPSBzdW0oaXMubmEobWFsbnV0cml0aW9uKSksCiAgICBtb3J0X2luaG9zcF9taXNzaW5nID0gc3VtKGlzLm5hKG1vcnRfaW5ob3NwKSksICMxMDMgbW9ydF9pbmhvc3BfbWlpc3NpbmcgID0gY29udHJvbHMKICApCmBgYAoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIGZpbHRlciAoY2FzZV9jb250cm9sID09IDEpICU+JQogIGdyb3VwX2J5KG1hbG51dHJpdGlvbl9zb3VyY2UpICU+JQogIHN1bW1hcml6ZSgKICAgIGNvdW50X21hbG51dCA9IG4oKQogICkKCiMgTkEgZHVlIHRvIGNoaWxkIHdpdGggaGVpZ2h0IG9mIDIwIGNtICh1bmRlciBXSE8gY3VydmUgZm9yIHdmaC93ZmwpIGFuZCAzOCBkYXlzIG9sZCAodG9vIHlvdW5nIGZvciBNVUFDKQpgYGAKCmBgYHtyfQpQU0ZJX2RmX21hbG51dHJpdGlvbiAlPiUKICBmaWx0ZXIgKGNhc2VfY29udHJvbCA9PSAxKSAlPiUKICBncm91cF9ieShtYWxudXRyaXRpb24pICU+JQogIHN1bW1hcml6ZSgKICAgIGNvdW50X21hbG51dCA9IG4oKQogICkKYGBgCgpgYGB7cn0KUFNGSV9kZl9tYWxudXRyaXRpb24gJT4lCiAgZHJvcF9uYShtYWxudXRyaXRpb24sIG1vcnRfaW5ob3NwKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBmYWN0b3IobWFsbnV0cml0aW9uKSkpICsKICBnZW9tX2JhcigpICsKICBsYWJzKAogICAgeCA9ICJNYWxudXRyaXRpb24iLAogICAgeSA9ICJOIgogICkKYGBgCgpgYGB7cn0KUFNGSV9kZl9tYWxudXRyaXRpb24lPiUKICBmaWx0ZXIgKGNhc2VfY29udHJvbCA9PSAxKSAlPiUKICBjb3VudChtYWxudXRyaXRpb24sIG1vcnRfaW5ob3NwKSAlPiUKICBncm91cF9ieShtYWxudXRyaXRpb24pICU+JQogIG11dGF0ZShwcm9wID0gbiAvIHN1bShuKSkKYGBgCgpgYGB7cn0KUFNGSV9kZl9tYWxudXRyaXRpb24gJT4lCiAgZHJvcF9uYShtb3J0X2luaG9zcCwgbWFsbnV0cml0aW9uKSAlPiUgI29ubHkgY2FzZXMgJiBtaW51cyB0aGUgb25lIHByZXZpb3VzbHkgbWVudGlvbmVkIE5BCiAgZ2dwbG90ICsKICAoYWVzKHggPSBmYWN0b3IobWFsbnV0cml0aW9uKSwgZmlsbCA9IGZhY3Rvcihtb3J0X2luaG9zcCkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJjb3VudCIsIHBvc2l0aW9uID0gImZpbGwiKSArCiAgbGFicygKICAgIHggPSAiTWFsbnV0cml0aW9uIiwKICAgIHkgPSAiUHJvcG9ydGlvbiIsCiAgICBmaWxsID0gIk1vcnRhbGl0eSIKICApCmBgYAoKYGBge3J9ClBTRklfZGZfbWFsbnV0cml0aW9uICU+JQogIGNvdW50KG1hbG51dHJpdGlvbiwgY2FzZV9jb250cm9sKSAlPiUKICBncm91cF9ieShtYWxudXRyaXRpb24pICU+JQogIG11dGF0ZShwcm9wID0gbiAvIHN1bShuKSkKYGBgCgpgYGB7cn0KUFNGSV9kZl9tYWxudXRyaXRpb24gJT4lCiAgZHJvcF9uYShtYWxudXRyaXRpb24pICU+JQogIGdncGxvdCArCiAgKGFlcyh4ID0gZmFjdG9yKG1hbG51dHJpdGlvbiksIGZpbGwgPSBmYWN0b3IoY2FzZV9jb250cm9sKSkpICsKICBnZW9tX2JhcihzdGF0ID0gImNvdW50IiwgcG9zaXRpb24gPSAiZmlsbCIpICsKICBsYWJzKAogICAgeCA9ICJNYWxudXRyaXRpb24iLAogICAgeSA9ICJQcm9wb3J0aW9uIiwKICAgIGZpbGwgPSAiQ2FzZS9Db250cm9sIgogICkKYGBgCgpgYGB7cn0Kd3JpdGUueGxzeChQU0ZJX2RmX21hbG51dHJpdGlvbiwgZmlsZSA9ICJQU0ZJX2ZpbmFsX21hbG51dHJpdGlvbi54bHN4IikKYGBgCg==