Introduction
In this RMarkdown file, the extended methods and data-analysis for the manuscript “Multisystem inflammatory syndrome in children related to COVID-19: a systematic review” is described. The complete data-analysis can be reproduced from the data collection sheet (in .xls format), provided in the supplementary files of the manuscript or on Github . The study protocol was published on the PROSPERO systematic review register, prior to conducting the review: CRD42020189248
knitr:: opts_chunk$ set (cache = FALSE , warning = FALSE , message = FALSE )
options (digits = 3 )
options (width = 60 )
library (tidyverse)
require (readxl)
require (httr)
require (reshape2)
require (broom)
require (RColorBrewer)
require (scales)
require (ggrepel)
require (gridExtra)
require (ggExtra)
library (ggbeeswarm)
require (ggpubr)
library (cowplot)
library (naniar)
require (DT)
require (zoo)
require (psych)
library (skimr)
library (UpSetR)
library (see)
library (wesanderson)
library (padr)
options (scipen= 999 )
co_hb <- 12
co_neutrophilia <- 8000
co_CRP <- 10
co_lympho <- 1250
co_fibrino <- 400
co_Ddim <- 250
co_ferritin <- 300
co_albu <- 34
co_PCT <- 0.49
co_LDH <- 280
co_IL6 <- 16.4
co_ESR <- 22
co_BNP <- 100
co_NTproBNP <- 400
co_tropo <- 40
co_WBC <- 11000
co_platelet <- 150000
co_sodium <- 135
#input = df_cohort_controls
#find = "max"
#param = "CRP"
collapse_labvals_cohort <- function (input, find, param, verbose = FALSE ){
if (find == "max" ){
df <- input %>% select (contains (param) | contains ("cohort_id" ) | contains ("cohort_type" ) | contains ("tot_cases_n" ))
if (verbose == TRUE ){
print ("Column extracted from cohorts:" )
print (colnames (df))
}
df_med <- df %>% select (contains ("med" ))
df_med <- type_convert (df_med)
df_med <- df_med %>% mutate_all (funs (replace_na (., -999 )))
# colnames(df_med)[max.col(df_med,ties.method="first")]
df_med <- df_med %>% mutate (med = as.numeric (apply (df_med, 1 , max)))
df_min <- df %>% select (contains ("Q1" ))
df_min <- type_convert (df_min)
df_min <- df_min %>% mutate_all (funs (replace_na (., -999 )))
#colnames(df_min)[max.col(df_min,ties.method="first")]
df_min <- df_min %>% mutate (min = as.numeric (apply (df_min, 1 , max)))
df_max <- df %>% select (contains ("Q3" ))
df_max <- type_convert (df_max)
df_max <- df_max %>% mutate_all (funs (replace_na (., -999 )))
#colnames(df_max)[max.col(df_max,ties.method="first")]
df_max <- df_max %>% mutate (max = as.numeric (apply (df_max, 1 , max)))
df_full <- cbind (df %>% select (cohort_id, cohort_type, tot_cases_n), df_med %>% select (med), df_min %>% select (min), df_max %>% select (max))
df_full[df_full == -999 ] <- NA
names (df_full)[names (df_full) == 'max' ] <- paste0 (param, "_max" )
names (df_full)[names (df_full) == 'min' ] <- paste0 (param, "_min" )
names (df_full)[names (df_full) == 'med' ] <- paste0 (param, "_med" )
df_full$ data_descr <- "IQR"
df_full$ cohort_id <- paste0 (df_full$ cohort_id, " (n = " , as.character (df_full$ tot_cases_n),")" )
write.csv (df_full, paste0 ("./data/cohort_" , param, ".csv" ))
print (datatable (df_full, caption = paste0 ("overview of " , param)))
return (df_full)
}
else if (find == "min" ){
df <- input %>% select (contains (param) | contains ("cohort_id" ) | contains ("cohort_type" ) | contains ("tot_cases_n" ))
if (verbose == TRUE ){
print ("Column extracted from cohorts:" )
print (colnames (df))
}
df_med <- df %>% select (contains ("med" ))
df_med <- type_convert (df_med)
df_med <- df_med %>% mutate_all (funs (replace_na (., 1e6 )))
# colnames(df_med)[max.col(df_med,ties.method="first")]
df_med <- df_med %>% mutate (med = as.numeric (apply (df_med, 1 , min)))
df_min <- df %>% select (contains ("Q1" ))
df_min <- type_convert (df_min)
df_min <- df_min %>% mutate_all (funs (replace_na (., 1e6 )))
#colnames(df_min)[max.col(df_min,ties.method="first")]
df_min <- df_min %>% mutate (min = as.numeric (apply (df_min, 1 , min)))
df_max <- df %>% select (contains ("Q3" ))
df_max <- type_convert (df_max)
df_max <- df_max %>% mutate_all (funs (replace_na (., 1e6 )))
#colnames(df_max)[max.col(df_max,ties.method="first")]
df_max <- df_max %>% mutate (max = as.numeric (apply (df_max, 1 , min)))
df_full <- cbind (df %>% select (cohort_id, cohort_type, tot_cases_n), df_med %>% select (med), df_min %>% select (min), df_max %>% select (max))
df_full[df_full == 1e6 ] <- NA
names (df_full)[names (df_full) == 'max' ] <- paste0 (param, "_max" )
names (df_full)[names (df_full) == 'min' ] <- paste0 (param, "_min" )
names (df_full)[names (df_full) == 'med' ] <- paste0 (param, "_med" )
df_full$ data_descr <- "IQR"
df_full$ cohort_id <- paste0 (df_full$ cohort_id, " (n = " , as.character (df_full$ tot_cases_n),")" )
write.csv (df_full, paste0 ("./data/cohort_" , param, ".csv" ))
print (datatable (df_full, caption = paste0 ("overview of " , param)))
return (df_full)
}
}
#input = df_singlecases
#find = "max"
#param = "CRP"
collapse_labvals_single <- function (input, find, param, verbose = FALSE ){
if (find == "max" ){
df <- input %>% select (contains (param) | contains ("cohort_id" ))
if (verbose == TRUE ){
print ("Column extracted from single cases:" )
print (colnames (df))
}
df_coll <- df %>% mutate_all (funs (replace_na (., -999 )))
df_coll <- type_convert (df_coll)
# colnames(df_med)[max.col(df_med,ties.method="first")]
df_coll <- df_coll %>% mutate (max = as.numeric (apply (df_coll, 1 , max)))
df_coll[df_coll == -999 ] <- NA
names (df_coll)[names (df_coll) == 'max' ] <- paste0 (param, "_max" )
df_coll$ data_descr <- "IQR"
df_coll$ cohort_id <- paste0 ("single cases (n = " , as.character (n_single_cases),")" )
write.csv (skim (df_coll), paste0 ("./data/singlecases_" , param, ".csv" ))
return (df_coll)
}
else if (find == "min" ){
df <- input %>% select (contains (param) | contains ("cohort_id" ))
if (verbose == TRUE ){
print ("Column extracted from single cases:" )
print (colnames (df))
}
df_coll <- df %>% mutate_all (funs (replace_na (., 1e6 )))
# colnames(df_med)[max.col(df_med,ties.method="first")]
df_coll <- df_coll %>% mutate (min = as.numeric (apply (df_coll, 1 , min)))
df_coll[df_coll == 1e6 ] <- NA
names (df_coll)[names (df_coll) == 'min' ] <- paste0 (param, "_min" )
df_coll$ cohort_id <- paste0 ("single cases (n = " , as.character (n_single_cases),")" )
write.csv (skim (df_coll), paste0 ("./data/singlecases_" , param, ".csv" ))
return (df_coll)
}
}
moveme <- function (df, movecommand) {
invec <- names (df)
movecommand <- lapply (strsplit (strsplit (movecommand, ";" )[[1 ]],
",| \\ s+" ), function (x) x[x != "" ])
movelist <- lapply (movecommand, function (x) {
Where <- x[which (x %in% c ("before" , "after" , "first" ,
"last" )): length (x)]
ToMove <- setdiff (x, Where)
list (ToMove, Where)
})
myVec <- invec
for (i in seq_along (movelist)) {
temp <- setdiff (myVec, movelist[[i]][[1 ]])
A <- movelist[[i]][[2 ]][1 ]
if (A %in% c ("before" , "after" )) {
ba <- movelist[[i]][[2 ]][2 ]
if (A == "before" ) {
after <- match (ba, temp) - 1
}
else if (A == "after" ) {
after <- match (ba, temp)
}
}
else if (A == "first" ) {
after <- 0
}
else if (A == "last" ) {
after <- length (myVec)
}
myVec <- append (temp, values = movelist[[i]][[1 ]], after = after)
}
df[,match (myVec, names (df))]
}
makeBarplot <- function (var_id_cohort, var_id_single, var_id){
n_cohort <- df_cohort %>% select (tot_cases_n) %>% sum ()#, outcome_death_n)
var_cohort <- df_cohort[var_id_cohort] %>% sum (., na.rm = TRUE )#, outcome_death_n)
n_single <- df_singlecases %>% nrow ()
var_single <- df_singlecases %>% filter (get (var_id_single) == TRUE ) %>% nrow ()
n_all <- n_cohort + n_single
var_all <- var_cohort + var_single
bar_df_abs <- data.frame (x = c ("cohort" , "cohort" , "single cases" , "single cases" , "all" , "all" ), col = c ("total" , var_id, "total" , var_id, "total" , var_id), vals = c (n_cohort, var_cohort, n_single, var_single, n_all, var_all) )
bar_df_prct <- data.frame (x = c ("cohort" , "cohort" , "single cases" , "single cases" , "all" , "all" ), col = c (paste0 (var_id, " -" ), paste0 (var_id, " +" ), paste0 (var_id, " -" ), paste0 (var_id, " +" ), paste0 (var_id, " -" ), paste0 (var_id, " +" )), vals = c (100 - (var_cohort/ n_cohort* 100 ), var_cohort/ n_cohort* 100 , 100 - (var_single/ n_single* 100 ), var_single/ n_single* 100 , 100 - (var_all/ n_all* 100 ), var_all/ n_all* 100 ) )
p_abs <- ggplot (bar_df_abs, aes (x = x, y = vals, fill = col)) +
geom_bar (stat = "identity" , position = "dodge" ) +
theme_bw () +
labs (title = paste0 ("Total cases vs " , var_id), subtitle = "Absolute numbers" , x = "group" , y = "n" , col = "" ) +
scale_fill_manual (values = wes_palette ("Royal1" )) +
theme (legend.title = element_blank ())
p_prct <- ggplot (bar_df_prct, aes (x = x, y = vals, fill = col)) +
geom_bar (stat = "identity" , position = "fill" ) +
theme_bw () +
labs (title = paste0 (var_id), subtitle = "Percent" , x = "group" , y = "%" , col = "" ) +
scale_y_continuous (labels = scales:: percent)+
scale_fill_manual (values = wes_palette ("Royal1" )) +
theme (legend.title = element_blank ())
ggarrange (p_abs, p_prct, legend = "bottom" )
}
makeHeatmap_cohort <- function (param1, colname_single, exclude_single = NULL , plottitle, textsize = 3 ){
var_cohort <- df_cohort %>% select (("cohort_id" ) | "tot_cases_n" | ( contains (param1) & contains ("_n" )))
var_cohort$ cohort_id <- paste0 (var_cohort$ cohort_id, " (n = " , as.character (var_cohort$ tot_cases_n),")" )
var_cohort <- var_cohort %>%
gather (variable, value, 3 : ncol (var_cohort)) %>% group_by (cohort_id, variable) %>% summarize (prct = value/ tot_cases_n* 100 )
var_cohort$ variable <- sub ("_n" , "" , var_cohort$ variable)
if (! is.null (exclude_single)){
var_single <- df_singlecases %>% select (- contains (exclude_single))
var_single <- var_single %>% select (contains (colname_single))
} else
{
var_single <- df_singlecases %>% select (contains (colname_single))
}
#%>% select(-contains("any"))
cols <- sapply (var_single, is.logical)
var_single[,cols] <- lapply (var_single[,cols], as.numeric)
var_single <- colSums (var_single, na.rm = TRUE )
var_single <- var_single/ nrow (df_singlecases)* 100
var_single <- as.data.frame (var_single) %>% rownames_to_column ()
var_single$ cohort_id <- paste0 ("single cases (n = " , n_single_cases,")" )
colnames (var_single) <- c ("variable" , "prct" , "cohort_id" )
missing <- setdiff (var_single$ variable, var_cohort$ variable)
if (length (missing) != 0 ){
missing_df <- data.frame (variable = missing, prct = NA , cohort_id = unique (var_cohort$ cohort_id))
var_cohort <- bind_rows (var_cohort, as_tibble (missing_df))
} else if (length (missing) == 0 ) {
missing <- setdiff (var_cohort$ variable, var_single$ variable)
if (length (missing) != 0 ){
missing_df <- data.frame (variable = missing, prct = NA , cohort_id = unique (var_single$ cohort_id))
var_single <- bind_rows (var_single, as_tibble (missing_df))
}
}
hm_cohort <- ggplot (var_cohort, aes (x = variable, y = cohort_id, fill = prct)) +
geom_tile () + theme_classic () +
theme (axis.text.x= element_blank (), axis.ticks.x= element_blank (), axis.line= element_blank ())+
scale_fill_gradient (low = "yellow" , high= "red" , na.value = "lightgray" , limits = c (0 ,100 )) +
labs (x = "" , y = "cohort" , title = plottitle) +
geom_text (aes (label= round (prct, 2 )), size = textsize, color = "black" )
hm_single <- ggplot (var_single, aes (x = variable, y = cohort_id, fill = prct)) +
geom_tile () + theme_classic () +
theme (axis.text.x= element_text (angle= 90 , hjust= 1 ), axis.line= element_blank ())+
scale_fill_gradient (low = "yellow" , high = "red" , na.value = "lightgray" , limits = c (0 ,100 ))+ labs (y = "cohort" ) +
geom_text (aes (label= round (prct, 2 )), size = textsize, color = "black" )
plot_grid (hm_cohort, hm_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
}
Search strategy
Electronic bibliographical databases were searched, both indexed (PubMed, Embase) and preprint repositories (BioRxiv and MedRxiv). Additionally, COVID-19-specific research repositories were be searched (Cochrane COVID‐19 Study Register, the World Health Organization (WHO) COVID‐19 Global Research Database). Publications in English language between 31 December 2019 up to 30 June 2020, when the final search was carried out, were reviewed on eligibility. Both finished and ongoing studies were considered. The reference lists of the included studies were considered as an additional source.
Search strategy focused on keywords involving the hyperinflammatory presentation (PIMS-TS, MIS-C, hyperinflammation, HLH, toxic shock syndrome, vasculitis, Kawasaki disease), as well as the association with COVID-19 (SARS-CoV-2, COVID-19, novel coronavirus) and the pediatric population (children, adolescent, pediatric). Structured hierarchic keywords (MeSH, Emtree) and wildcards were used when applicable. Boolean operators were used to combine the various keywords of interest. Below, the full search terms are presented for the different databases).
PubMed
(“PIMS*” OR “MIS*” OR “multisystem inflammat*” OR “hyperinflammat*” OR “inflammatory disease” OR “systemic inflammat*” OR “cytokine release” OR “Kawasaki*” OR “vasculitis” OR “toxic shock” OR “shock” OR ("pediatric multisystem inflammatory disease, COVID-19 related" [Supplementary Concept]) OR "Mucocutaneous Lymph Node Syndrome"[Mesh] OR "Shock"[Mesh] OR "Vasculitis"[Mesh] OR “inflammation”[MeSH]) AND (“covid*” or “sars-cov-2” or “2019-nCov” or “novel coronavirus” or “coronavirus disease” or "COVID-19" [Supplementary Concept] OR "severe acute respiratory syndrome coronavirus 2" [Supplementary Concept]) AND (“child*” or “adolescen*” or “teen*” or “pediatric*” or “infant” or “newborn” or "Child"[Mesh] OR "Adolescent"[Mesh] OR "Pediatrics"[Mesh] or "Infant, Newborn"[Mesh] or "Infant"[Mesh]) AND ("2019/12/31"[Date - Publication] : "3000"[Date - Publication])
Embase
('pims*' OR 'mis' OR ‘mis-c’ OR 'multisystem inflammat*' OR 'hyperinflammat*' OR 'inflammatory disease' OR 'systemic inflammat*' OR 'cytokine release' OR 'kawasaki*' OR 'vasculitis' OR 'toxic shock' OR 'shock') AND ('covid*' OR 'sars-cov-2' OR '2019-ncov' OR 'novel coronavirus' OR 'coronavirus disease') AND ('child*' OR 'adolescen*' OR 'teen*' OR 'pediatric*' OR 'infant' OR 'newborn') AND [31-12-2019]/sd
BioRxiv and MedRxiv
Literature search in biorxiv and medrxiv was done with the R by downloading the data from the dedicated COVID-19 SARS-CoV-2 preprints page in json format, and can be found on Github .
Cochrane COVID-19 study register
(pims* OR mis OR "mis-c" OR "multisystem inflammat*" OR hyperinflammat* OR "inflammatory disease" OR "systemic inflammat*" OR "cytokine release" OR kawasaki* OR vasculitis OR "toxic shock" OR shock) AND (child* OR adolescen* OR teen* OR pediatric* OR infant OR newborn)
WHO COVID-19 Global literature on coronavirus disease
("pims*" OR "mis" OR "mis-c" OR "multisystem inflammat*" OR "hyperinflammat*" OR "inflammatory disease" OR "systemic inflammat*" OR "cytokine release" OR "kawasaki*" OR "vasculitis" OR "toxic shock" OR "shock") AND ("child*" OR "adolescen*" OR "teen*" OR "pediatric*" OR "infant" OR "newborn")
Study selection and risk of bias assessment
Original studies were included with following designs: RCT, observational studies, case-control studies, cross-sectional studies, case reports and case series.
Records eligible for inclusion should present clinical cases fulfilling the following 3 criteria:
Inclusion criteria
Study population: hyperinflammatory syndrome meeting the case definitions of PIMS-TS or MIS(-C) in children (0-19 years of age) with a temporal association with confirmed or probable COVID-19
Outcome: clinical, epidemiological and immunological descriptions, therapeutic management and clinical effect, and prognosis of individuals or cohorts of patients.
Types of study designs: RCT, observational studies, case-control studies, cross-sectional studies, case reports and case series
Exclusion criteria
Studies on adult patients with SARS-CoV-2 infection and/or SARS-CoV-2 associated hyperinflammatory syndromes
Studies on pediatric patients with other coronavirus infections (SARS-CoV-1 and Middle East Respiratory Syndrome Coronavirus (MERS-CoV) infection or other respiratory infections.
Studies with incomplete or lacking necessary data
Duplicate studies
Studies without accessible full text versions
Studies not in English language
Study selection was a two-stage process with, first, titles and abstracts of studies screened with retrieval using the search strategy and then, second, full text screening of potentially eligible studies assessed by two reviewers independently. Any disagreement over the eligibility of particular studies was resolved through discussion with a third reviewer.
The Preferred Reporting Items for Systematic Reviews and Meta-Analyses (PRISMA) checklist was used to guide the study selection and extraction process. Risk for bias on eligible observational studies were assessed by LH according to the NewCastle-Ottawa Scale (NOS), with full verification of all judgments by RVP. Level of evidence was rated according to Sackett.
PRISMA flow diagram
Update between 2020-06-30 and 2020-08-13
Initially, the literature search and data-extraction was performed up to June 30, 2020. Afterwards, an update of the literature search, data-extraction and manuscript was done with studies published between July 1st and August 13th. In this second phase, conflicts during study selection were resolved by discussion between LH and RVP until a consensus was reached, instead of by the third independent third reviewer. For n = 7 studies, RVP extracted the data, while the second reviewer LH cross checked all data for correctness and completeness. No other changes to the literature seach methodology, data-extraction or analysis was done.
Data import and cleaning
Single cases
After data collection, we import the single cases from the general excel sheet and transform the excel sheet so that variables are columns and rows are cases. Columns without any values are also removed.
The single cases from Pouletty (10.1136/annrheumdis-2020-217960) are excluded (as they are included in the cohorts, and they only report IL6 data for single cases, which are added to the IL6 figure).
df_singlecases <-
read_excel ("20200903_data_extraction.xlsx" ,
sheet = "Single cases" ,
skip = 1 ,
col_names = FALSE )[,- c (1 : 2 )]
df_singlecases <- df_singlecases %>% t ()
df_singlecases <- as.data.frame (df_singlecases, stringsAsFactors = FALSE )
nms <- as.vector (df_singlecases[1 ,])
nms[is.na (nms)] <- 'tmp'
colnames (df_singlecases) <- make.unique (as.character (nms))
df_singlecases <- df_singlecases[- 1 ,]
df_singlecases <- df_singlecases %>% select (- contains ("tmp" ))
df_singlecases <- df_singlecases %>% select (- variable_id)
df_singlecases <- df_singlecases %>%
mutate_all (funs (str_replace (., "Yes" , "yes" )))
df_singlecases <- df_singlecases %>%
mutate_all (funs (str_replace (., "No" , "no" )))
df_singlecases <- df_singlecases %>%
mutate_all (funs (str_replace (., "pos" , "yes" )))
df_singlecases <- df_singlecases %>%
mutate_all (funs (str_replace (., "neg" , "no" )))
df_singlecases <- df_singlecases %>%
replace_with_na_all (condition = ~ .x == "NA" )
df_singlecases <- type_convert (df_singlecases)
df_singlecases_inclPouletty <- df_singlecases
df_singlecases <- df_singlecases %>% filter (doi != "https://10.1136/annrheumdis-2020-217960" ) # these cases are excluded according to the data sheet
df_singlecases <- df_singlecases[colSums (! is.na (df_singlecases)) > 0 ]
df_singlecases$ date_of_publication <- as.Date (df_singlecases$ date_of_publication, origin = "1899-12-30" )
n_single_cases <- nrow (df_singlecases)
Making summary statistics
In this section, data is summarized. For example, if there are any comorbidities present, a column “comorb_any” is added and annotated as TRUE. The same is done for COVID serology and symptoms of major organ (respiratory, cardiovascular etc).
If IgG, IgA, IgM or COVID serology is reported as positive, the column covid_sero_any is annotated as TRUE.
If PCR+, stool PCR+, IgG, IgA, IgM or COVID serology is reported as positive, the column covid_pos_any is annotated as TRUE.
If any respiratory symptoms, symp_resp_any is annotated as TRUE.
If any GI symptoms, symp_GI_any is annotated as TRUE.
If any neurological symptoms, symp_neuro_any is annotated as TRUE.
If any renal symptoms, symp_renal_any is annotated as TRUE.
If any cardiovascular symptoms, symp_cardiovasc_any is annotated as TRUE.
df_singlecases <- df_singlecases %>% mutate (symp_cardiovasc_any = apply (df_singlecases %>% select (symp_cardiovasc_myocard,
symp_cardiovasc_pericard,
symp_cardiovasc_cordilat,
symp_cardiovasc_aneurysm,
symp_cardiovasc_shock,
symp_cardiovasc_tachycard,
symp_cardiovasc_arrhyt), 1 , any))
df_singlecases <- df_singlecases %>% moveme (., "symp_cardiovasc_any before symp_cardiovasc_myocard" )
write.csv (df_singlecases, paste0 ("./data/df_singlecases.csv" ))
#datatable(df_singlecases, caption = "Single cases dataframe")
Download single case data as .csv on Github
Cohorts
Afterwards, we do the same for the cohort sheet.
The papers by Grimaud et al. and Verdoni et al. are removed from the cohort dataframe, as most information is present in the single cases dataframe.
df_cohort <-
read_excel ("20200903_data_extraction.xlsx" ,
sheet = "Cohorts" ,
skip = 1 ,
col_names = FALSE )[,- c (1 : 3 )]
df_cohort <- df_cohort %>% t ()
df_cohort <- as.data.frame (df_cohort, stringsAsFactors = FALSE )
nms <- as.vector (df_cohort[1 ,])
nms[is.na (nms)] <- 'tmp'
colnames (df_cohort) <- make.unique (as.character (nms))
df_cohort <- df_cohort[- 1 ,]
df_cohort <- df_cohort %>% select (- contains ("tmp" ))
df_cohort <- df_cohort %>% select (- variable_id)
df_cohort <- df_cohort %>%
mutate_all (funs (str_replace (., "Yes" , "yes" )))
df_cohort <- df_cohort %>%
mutate_all (funs (str_replace (., "No" , "no" )))
df_cohort <- df_cohort %>%
mutate_all (funs (str_replace (., "pos" , "yes" )))
df_cohort <- df_cohort %>%
mutate_all (funs (str_replace (., "neg" , "no" )))
df_cohort <- df_cohort %>%
replace_with_na_all (condition = ~ .x == "NA" )
df_cohort <- type_convert (df_cohort)
df_cohort <- df_cohort[colSums (! is.na (df_cohort)) > 0 ]
df_cohort <- df_cohort %>% filter (doi != "https://doi.org/10.1186/s13613-020-00690-8" ) %>% filter (doi != "https://doi.org/10.1016/S0140-6736(20)31103-X" )
df_cohort_controls <- df_cohort
df_cohort <- df_cohort %>% filter (cohort_type == "MIS-C" )
df_cohort$ date_of_publication <- as.Date (df_cohort$ date_of_publication, origin = "1899-12-30" )
write.csv (df_cohort, paste0 ("./data/df_cohort.csv" ))
#datatable(df_cohort, caption = "Cohort dataframe")
Download cohort data as .csv on Github
Descriptive statistics
General
Click on the any of the tabs above to see descriptive statistics for every variable
Single cases
Download data as .csv on Github
Cohorts
The “Prct_total” column is the percentage of e.g. death divided by the total cases in the cohort group. Only makes sense where n is reported e.g. therapy (not for lab values).
Download data as .csv on Github
Historical controls
Download data as .csv on Github
Data exploration
Important
For the cohorts, percentages describe the total (e.g. positive) cases, divided by the sum of the total cases of studies reporting the variable .
Cases in function of COVID pandemic
To investigate the relationship of the published PIMS cases with the ongoing COVID-19 pandemic, the case data from Johns Hopkins was downloaded (and added to this repository).
The list was filtered on the UK, US, Italy and France, as these country contribute the most to our dataset.
Caveat: this is a distored image of the PIMS cases: as the cases are published together, their true date of diagnosis is unknown.
firstdiff <- function (x) {
shifted <- c (0 ,x[1 : (length (x)- 1 )])
x- shifted
}
USA_cases <- read_csv ("./data/time_series_covid19_confirmed_US.csv" )
USA_cases <- USA_cases %>% select (- c (UID, iso2, iso3, code3, FIPS, Admin2, Province_State, Lat, Long_, Combined_Key))
names (USA_cases)[names (USA_cases) == 'Country_Region' ] <- "Country/Region"
global_cases <- read_csv ("./data/time_series_covid19_confirmed_global.csv" )
global_cases <- global_cases %>% select (- c (` Province/State ` , Lat, Long))
global_cases <- rbind (USA_cases, global_cases)
global_cases <- global_cases %>% melt ()
global_cases$ variable <- as.Date (global_cases$ variable, format = "%m/%d/%y" )
colnames (global_cases) <- c ("country" , "date_of_publication" , "tot_cases_covid" )
global_cases <- global_cases %>% filter (country == "United Kingdom" | country == "Italy" | country == "France" | country == "US" )
all_glob_cases <- global_cases %>% group_by (date_of_publication) %>% summarise (total_cases = sum (tot_cases_covid))
all_glob_cases$ newcases <- firstdiff (all_glob_cases$ total_cases)
all_glob_cases$ newcase_roll7 <- zoo:: rollmean (all_glob_cases$ newcases, k = 7 , fill = NA )
evo_cases <- rbind (df_cohort %>% select (tot_cases_n, date_of_publication) %>% mutate (type = "cohort" ),
df_singlecases %>% select (date_of_publication) %>% mutate (tot_cases_n = 1 , type = "single" ))
evo_cases <- pad (evo_cases)
evo_cases$ tot_cases_n[is.na (evo_cases$ tot_cases_n)] <- 0
evo_cases$ cumplot <- cumsum (evo_cases$ tot_cases_n)
full_data <- merge (evo_cases, all_glob_cases, all = TRUE )
p1 <- ggplot (full_data , aes (x = date_of_publication, y = cumplot)) +
geom_col (position = "dodge" , col = wes_palette ("Royal1" )[2 ], fill = wes_palette ("Royal1" )[2 ]) +
theme_bw () + geom_line (aes (x = date_of_publication, y = newcase_roll7/ 175 )) +
labs (x = "Date" , y = "cumulative number of cases" , title = "Number of published cases" ) + scale_x_date (limits = as.Date (c ('2020-01-15' ,'2020-08-14' ))) + scale_y_continuous (
"cumulative number of published cases" ,
sec.axis = sec_axis (~ . * 175 , name = "new COVID-19 cases (7-day average)" )
)
p1
ggsave (p1, filename = "./plots/covid_evo_total.png" , dpi = 300 , height= 7 , width= 10 )
ggsave (p1, filename = "./plots/covid_evo_total.svg" , dpi = 300 , height= 7 , width= 10 )
ggsave (p1, filename = "./plots/covid_evo_total.pdf" , dpi = 300 , height= 7 , width= 10 )
all_glob_cases <- global_cases %>% group_by (date_of_publication, country) %>% summarise (total_cases = sum (tot_cases_covid)) %>% ungroup ()
all_glob_cases <- all_glob_cases %>% group_by (country) %>%
mutate (newcases = firstdiff (total_cases)) %>% ungroup ()
#all_glob_cases$newcases <- firstdiff(all_glob_cases$total_cases)
all_glob_cases <- all_glob_cases %>% group_by (country) %>% mutate (newcase_roll7 = zoo:: rollmean (newcases, k = 7 , fill = NA ))
evo_cases <- rbind (df_cohort %>% select (tot_cases_n, date_of_publication, country) %>% mutate (type = "cohort" ),
df_singlecases %>% select (date_of_publication, country) %>% mutate (tot_cases_n = 1 , type = "single" ))
country_barplot <- evo_cases
evo_cases <- pad (evo_cases)
#evo_cases$tot_cases_n[is.na(evo_cases$tot_cases_n)] <- 0
#evo_cases$tot_cases_n[is.na(evo_cases$tot_cases_n)] <- 0
evo_cases <- evo_cases %>% group_by (country) %>% mutate (cumplot = cumsum (tot_cases_n)) %>% ungroup ()
evo_cases <- evo_cases %>% fill (country)
full_data <- merge (evo_cases, all_glob_cases, all = TRUE )
full_data_filt <- full_data %>% filter (country == "United Kingdom" | country == "Italy" | country == "France" | country == "US" )
full_data_filt <- full_data_filt %>% mutate (continent = ifelse (country == "US" , "US" , "Europe" ))
p1 <- ggplot (full_data_filt , aes (x = date_of_publication, y = cumplot)) +
geom_col (position = "dodge" , aes (fill = country, col = country)) +
theme_bw () +
scale_color_manual (values = wes_palette ("Darjeeling2" )[c (1 ,3 ,4 ,2 )]) +
scale_fill_manual (values = wes_palette ("Darjeeling2" )[c (1 ,3 ,4 ,2 )]) +
geom_line (aes (x = date_of_publication, y = newcase_roll7/ 100 , col = country)) +
labs (x = "Date" , y = "cumulative number of cases (bars)" , title = "Number of published cases, per country" ) +
scale_x_date (limits = as.Date (c ('2020-03-01' ,'2020-08-14' ))) + scale_y_continuous ( "cumulative number of published cases (bars)" ,
sec.axis = sec_axis (~ . * 100 , name = "new COVID-19 cases (7-day average, lines)" )
) +
theme (legend.position= "bottom" ) +
facet_wrap (~ continent, scales = "free_y" )
p1
ggsave (p1, filename = "./plots/covid_evo_percountry.png" , dpi = 300 , height= 7 , width= 10 )
ggsave (p1, filename = "./plots/covid_evo_percountry.svg" , dpi = 300 , height= 7 , width= 10 )
ggsave (p1, filename = "./plots/covid_evo_percountry.pdf" , dpi = 300 , height= 7 , width= 10 )
PIMS cases by country
Total cases and deaths
Sex and age distribution
n_cohort <- df_cohort %>% select (tot_cases_n) %>% sum ()
var_cohort <- df_cohort %>% select (contains ("sex" ))
var_cohort <- colSums (var_cohort, na.rm = TRUE )
var_cohort <- var_cohort/ sum (df_cohort$ tot_cases_n)* 100
var_cohort["sex_na" ] <- (100 - var_cohort["sex_m" ] - var_cohort["sex_f" ])
var_control <- df_cohort_controls %>% filter (cohort_id == "Pouletty - histor. KD" ) %>% select (contains ("sex" ))
var_control <- colSums (var_control, na.rm = TRUE )
var_control <- var_control/ sum (df_cohort_controls %>% filter (cohort_id == "Pouletty - histor. KD" ) %>% select (tot_cases_n))* 100
var_control["sex_na" ] <- (100 - var_control["sex_m" ] - var_control["sex_f" ])
n_single <- df_singlecases %>% nrow ()
var_single <- df_singlecases %>% select (contains ("sex" ))
var_single$ sex_m <- ifelse (var_single$ sex == "M" , TRUE , FALSE )
var_single$ sex_f <- ifelse (var_single$ sex == "F" , TRUE , FALSE )
cols <- sapply (var_single, is.logical)
var_single[,cols] <- lapply (var_single[,cols], as.numeric)
var_single <- colSums (var_single %>% select (- sex), na.rm = TRUE )
var_single <- var_single/ nrow (df_singlecases)* 100
var_single["sex_na" ] <- (100 - var_single["sex_m" ] - var_single["sex_f" ])
bar_df_prct <- data.frame (
x = c ("males" , "females" , "missing" , "males" , "females" , "missing" , "males" , "females" , "missing" ),
vals = c (var_single, var_cohort, var_control),
col = c (rep ("single" , length (var_single)), rep ("cohorts" , length (var_cohort)), rep ("histor ctrl" , length (var_control))
))
p_prct <- ggplot (bar_df_prct, aes (x = col, y = vals, fill = x)) +
geom_bar (stat = "identity" , position = "stack" ) +
theme_bw () +
labs (title = "Male/female distribution in dataset" , subtitle = "Percent" , x = "sex" , y = "%" , col = " " ) + lims (y = c (0 ,100 )) + theme (axis.text.x= element_text (angle= 90 , hjust= 1 ), legend.title = element_blank ())+
scale_fill_manual (values = wes_palette ("Royal1" ))
p_prct
var_cohort <- df_cohort %>% select (contains ("sex" ) | ("cohort_id" ) | "tot_cases_n" )
sex_f <- var_cohort %>% group_by (cohort_id) %>% summarize (prct = sex_f/ tot_cases_n) %>% mutate (sex = "female" )
sex_m <- var_cohort %>% group_by (cohort_id) %>% summarize (prct = sex_m/ tot_cases_n) %>% mutate (sex = "male" )
sex_all <- rbind (sex_f, sex_m)
p_sex_cohort <- ggplot (sex_all, aes (y = cohort_id, x = prct, fill = sex)) +
geom_bar (stat = "identity" , position = "fill" ) +
theme_bw () + labs (x = "" ) +
scale_fill_manual (values = wes_palette ("Royal1" ))
var_controls <- df_cohort_controls %>% filter (cohort_id == "Pouletty - histor. KD" ) %>% select (contains ("sex" ) | ("cohort_id" ) | "tot_cases_n" )
sex_f <- var_controls %>% group_by (cohort_id) %>% summarize (prct = sex_f/ tot_cases_n) %>% mutate (sex = "female" )
sex_m <- var_controls %>% group_by (cohort_id) %>% summarize (prct = sex_m/ tot_cases_n) %>% mutate (sex = "male" )
sex_all <- rbind (sex_f, sex_m)
p_sex_controls <- ggplot (sex_all, aes (y = cohort_id, x = prct, fill = sex)) +
geom_bar (stat = "identity" , position = "fill" ) +
theme_bw () + labs (x = "" ) +
scale_fill_manual (values = wes_palette ("Royal1" ))
n_single <- df_singlecases %>% nrow ()
var_single <- df_singlecases %>% select (contains ("sex" ))
var_single$ sex_m <- ifelse (var_single$ sex == "M" , TRUE , FALSE )
var_single$ sex_f <- ifelse (var_single$ sex == "F" , TRUE , FALSE )
cols <- sapply (var_single, is.logical)
var_single[,cols] <- lapply (var_single[,cols], as.numeric)
var_single <- colSums (var_single %>% select (- sex), na.rm = TRUE )
var_single <- var_single/ nrow (df_singlecases)* 100
sex_single <- data.frame (cohort_id = "single_cases" , prct = c (var_single["sex_m" ], var_single["sex_f" ]), sex = c ("male" , "female" ))
p_sex_single <- ggplot (sex_single, aes (y = cohort_id, x = prct, fill = sex)) +
geom_bar (stat = "identity" , position = "fill" ) +
theme_bw () +
scale_fill_manual (values = wes_palette ("Royal1" ))
a <- plot_grid (p_sex_cohort, p_sex_controls, p_sex_single, align = "v" , nrow = 3 , rel_heights = c (5 / 7 , 1 / 7 , 1 / 7 ))
cohort_age <- df_cohort_controls %>% select (contains ("cohort_id" ) | contains ("age" ) | contains ("cohort_type" ) | contains ("tot_cases_n" ))
cohort_age$ cohort_id <- paste0 (cohort_age$ cohort_id, " (n = " , cohort_age$ tot_cases_n,")" )
cohort_age$ age_med_yrs <- as.numeric (cohort_age$ age_med_yrs )
cohort_age$ age_Q1_yrs <- as.numeric (cohort_age$ age_Q1_yrs)
cohort_age$ age_Q3_yrs <- as.numeric (cohort_age$ age_Q3_yrs)
cohort_age$ age_min_yrs <- as.numeric (cohort_age$ age_min_yrs)
cohort_age$ age_max_yrs <- as.numeric (cohort_age$ age_max_yrs)
cohort_age$ data_descr <- ifelse (! is.na (cohort_age$ age_Q1_yrs) & is.na (cohort_age$ age_min_yrs) , "IQR" ,
ifelse (is.na (cohort_age$ age_Q1_yrs) & ! is.na (cohort_age$ age_min_yrs), "range" ,
ifelse (! is.na (cohort_age$ age_Q1_yrs) & ! is.na (cohort_age$ age_min_yrs), "both" , "none" )))
p_age_cohort <- ggplot (cohort_age %>% filter (cohort_type == "MIS-C" ), aes (y = cohort_id, x = age_med_yrs, col = data_descr)) +
geom_point (size = 4 ) +
geom_errorbar (aes (xmin= age_Q1_yrs, xmax= age_Q3_yrs), width= .8 , position= position_dodge (.9 )) +
geom_errorbar (aes (xmin= age_min_yrs, xmax= age_max_yrs), width= .2 , position= position_dodge (.9 )) +
theme_bw () + lims (x = c (0 ,21 )) +
labs (y = "cohort" , x = "" , col = "bars" ) + theme (legend.position= "top" )+
scale_color_manual (values = c (wes_palette ("BottleRocket2" )[1 : 3 ], wes_palette ("BottleRocket1" )[2 ]))
p_age_controls <- ggplot (cohort_age %>% filter (cohort_type != "MIS-C" ), aes (y = cohort_id, x = age_med_yrs, col = data_descr)) +
geom_point (size = 4 ) +
geom_errorbar (aes (xmin= age_Q1_yrs, xmax= age_Q3_yrs), width= .2 , position= position_dodge (.9 )) +
geom_errorbar (aes (xmin= age_min_yrs, xmax= age_max_yrs), width= .2 , position= position_dodge (.9 )) +
theme_bw () + lims (x = c (0 ,21 )) +
labs (y = "cohort" , x = "" , col = "bars" ) + theme (legend.position= "none" )+
scale_color_manual (values = wes_palette ("BottleRocket2" )[2 ])
p_age_single <- ggplot (df_singlecases, aes (x = as.numeric (age), y = paste0 ("single cases (n = " , n_single,")" ))) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + lims (x = c (0 ,21 )) +
labs (y = "cohort" , x = "Age (years)" )
a <- plot_grid (p_age_cohort, p_age_controls, p_age_single, align = "v" , nrow = 3 , rel_heights = c (2 / 3 , 1 / 5 , 1 / 3 ))
Symptoms
Single cases
All symptoms
Where applicable, overlap of variable in the single case group was summarized with Upset plots (Lex & Gehlenborg, Nature Methods, 2014) .
makeUpsetR <- function (input_df){
var_single <- input_df
cols <- sapply (var_single, is.logical)
var_single[,cols] <- lapply (var_single[,cols], as.numeric)
var_single_upsetr <- var_single
var_single_upsetr[is.na (var_single_upsetr)] <- 0
var_single_upsetr <- as.data.frame (var_single_upsetr)
for (i in 1 : ncol (var_single_upsetr)){ var_single_upsetr[ , i] <- as.integer (var_single_upsetr[ , i]) }
upset (var_single_upsetr, sets = c (colnames (var_single_upsetr)), sets.bar.color = "#56B4E9" ,
order.by = "freq" , keep.order = TRUE )#, empty.intersections = "on", keep.order = FALSE)
}
makeUpsetR (df_singlecases %>% select (contains ( "symp" )) %>% select (contains ("any" )))
Respiratory
Cardiovascular
GI
Single cases + cohort
Respiratory
barSymp <- function (colname_chort, colname_single, exclude_single = NULL , plottitle){
var_cohort <- df_cohort %>%
select (contains ("cohort_id" ) | contains ("tot_cases_n" ) | (contains (colname_chort) & contains ("_n" )))
var_cohort <- var_cohort %>%
gather (variable, value, 3 : ncol (var_cohort)) %>%
drop_na (value) %>% group_by (variable) %>%
summarize (prct = sum (value)/ sum (tot_cases_n)* 100 )
var_cohort <- setNames (var_cohort$ prct, var_cohort$ variable)
names (var_cohort) <- sub ("_n" , "" , names (var_cohort))
n_single <- df_singlecases %>% nrow ()
if (! is.null (exclude_single)){
var_single <- df_singlecases %>% select (- contains (exclude_single))
var_single <- var_single %>% select (contains (colname_single))
} else
{
var_single <- df_singlecases %>% select (contains (colname_single))
}
#%>% select(-contains("any"))
cols <- sapply (var_single, is.logical)
var_single[,cols] <- lapply (var_single[,cols], as.numeric)
var_single <- colSums (var_single, na.rm = TRUE )
var_single <- var_single/ nrow (df_singlecases)* 100
bar_df_prct <- data.frame (
x = c (names (var_single), names (var_cohort)),
vals = c (var_single, var_cohort),
col = c (rep ("single" , length (var_single)), rep ("cohorts" , length (var_cohort)))
)
p_prct <- ggplot (bar_df_prct, aes (x = x, y = vals, fill = col)) +
geom_bar (stat = "identity" , position = "dodge" ) +
theme_bw () +
labs (title = plottitle,
subtitle = "Percent of group" , x = "treatment" , y = "%" , col = " " ) +
theme (axis.text.x= element_text (angle= 90 , hjust= 1 ), legend.title = element_blank ())+
scale_fill_manual (values = wes_palette ("Royal1" ))
p_prct
}
Cardiovascular
Gastro-intestinal
Kawasaki criteria
Shock
Lab values
For lab values, sometimes multiple values are reported (baseline, peak or not-specified). All lab values are collapsed based on the max (or the min for e.g. hemoglobin): so only the highest value of median, Q1 or Q3 is used. Dashed vertical line corresponds to the cutoff used in the study.
C-reactive protein
crp_collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "CRP" )
crp_collapse_single <- collapse_labvals_single (df_singlecases, "max" , "CRP" )
crp_missing <- sum (is.na (crp_collapse_single$ CRP_max))
p_crp_cohort <- ggplot (crp_collapse_cohort, aes (y = cohort_id, x = CRP_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= CRP_min, xmax= CRP_max), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,600 )) +
theme_bw () + labs (title = "CRP" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_CRP, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_crp_single <- ggplot (crp_collapse_single, aes (x = as.numeric (CRP_max), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + lims (x = c (0 ,600 )) + labs (y = "" , x = "CRP (mg/dL)" , subtitle = paste0 ("missing data for " , crp_missing, " cases" )) +
geom_hline (yintercept = co_CRP, linetype = "dashed" , color = "black" )
CRP_grid <- plot_grid (p_crp_cohort, p_crp_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
CRP_grid
The number of single cases with elevated CRP: 122 out of total cases (= total cases minus missing cases): 125
Lymphocytes
lympho_collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "min" , "lympho" )
lympho_collapse_single <- collapse_labvals_single (df_singlecases, "min" , "lympho" )
lympho_missing <- sum (is.na (lympho_collapse_single$ lympho_min))
p_lympho_cohort <- ggplot (lympho_collapse_cohort, aes (y = cohort_id, x = lympho_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= lympho_min, xmax= lympho_max), width= .2 , position= position_dodge (.9 )) +
theme_bw () + labs (title = "lymphocytes" , y = "" , x = "" ) + lims (x = c (0 ,7500 )) +
geom_vline (xintercept = co_lympho, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])#+
#rremove("y.text")
p_lympho_single <- ggplot (lympho_collapse_single, aes (x = as.numeric (lympho_min), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
lims (x = c (0 ,7500 ))+
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "Lymphocytes (/µL)" , subtitle = paste0 ("missing data for " , lympho_missing, " cases" )) +
geom_vline (xintercept = co_lympho, linetype = "dashed" , color = "black" ) #+
#rremove("y.text")
lympho_grid <- plot_grid (p_lympho_cohort, p_lympho_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
lympho_grid
The number of single cases with lymphopenia: 60 out of total cases (= total cases minus missing cases): 76
White blood cells
wbc_collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "WBC" )
wbc_collapse_single <- collapse_labvals_single (df_singlecases, "max" , "WBC" )
wbc_missing <- sum (is.na (wbc_collapse_single$ WBC_max))
p_wbc_cohort <- ggplot (wbc_collapse_cohort, aes (y = cohort_id, x = WBC_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= WBC_min, xmax= WBC_max), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,50000 )) +
theme_bw () + labs (title = "WBC" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_WBC, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_wbc_single <- ggplot (wbc_collapse_single, aes (x = as.numeric (WBC_max), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "WBC (/µL)" , subtitle = paste0 ("missing data for " , wbc_missing, " cases" )) + lims (x = c (0 ,50000 )) +
geom_vline (xintercept = co_WBC, linetype = "dashed" , color = "black" )
WBC_grid <- plot_grid (p_wbc_cohort, p_wbc_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
WBC_grid
The number of single cases with increased WBCs: 32 out of total cases (= total cases minus missing cases): 52
Ferritin
ferritin_collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "ferrit" )
ferritin_collapse_single <- collapse_labvals_single (df_singlecases, "max" , "ferrit" )
ferritin_missing <- sum (is.na (ferritin_collapse_single$ ferrit_max))
p_ferritin_cohort <- ggplot (ferritin_collapse_cohort, aes (y = cohort_id, x = ferrit_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= ferrit_min, xmax= ferrit_max), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,11000 )) +
theme_bw () + labs (title = "Ferritin" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_ferritin, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_ferritin_single <- ggplot (ferritin_collapse_single, aes (x = as.numeric (ferrit_max), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "Ferritin (µg/l)" , subtitle = paste0 ("missing data for " , ferritin_missing, " cases" )) + lims (x = c (0 ,11000 )) +
geom_vline (xintercept = co_ferritin, linetype = "dashed" , color = "black" )
ferritin_grid <- plot_grid (p_ferritin_cohort, p_ferritin_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
ferritin_grid
The number of single cases with increased ferritin: 78 out of total cases (= total cases minus missing cases): 92
Troponin
troponin_collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "troponin" )
troponin_collapse_single <- collapse_labvals_single (df_singlecases, "max" , "troponin" )
troponin_missing <- sum (is.na (troponin_collapse_single$ troponin_max))
p_troponin_cohort <- ggplot (troponin_collapse_cohort, aes (y = cohort_id, x = troponin_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= troponin_min, xmax= troponin_max), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,7000 )) +
theme_bw () + labs (title = "Troponin" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_tropo, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_troponin_single <- ggplot (troponin_collapse_single, aes (x = as.numeric (troponin_max), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "Troponin (ng/L)" , subtitle = paste0 ("missing data for " , troponin_missing, " cases" )) + lims (x = c (0 ,7000 )) +
geom_vline (xintercept = co_tropo, linetype = "dashed" , color = "black" )
troponin_grid <- plot_grid (p_troponin_cohort, p_troponin_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
troponin_grid
The number of single cases with increased troponin: 90 out of total cases (= total cases minus missing cases): 108
IL-6
Note: The cases from Pouletty et al are added to the single cases as they report on IL6 values.
IL6_collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "IL6" )
IL6_collapse_single <- collapse_labvals_single (df_singlecases_inclPouletty, "max" , "IL6" )
IL6_missing <- sum (is.na (IL6_collapse_single$ IL6_max))
p_IL6_cohort <- ggplot (IL6_collapse_cohort, aes (y = cohort_id, x = IL6_med)) +
geom_point () +
geom_errorbar (aes (xmin= IL6_min, xmax= IL6_max), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,2500 )) +
theme_bw () + labs (title = "IL6" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_IL6, linetype = "dashed" , color = "black" ) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_IL6_single <- ggplot (IL6_collapse_single, aes (x = as.numeric (IL6_max), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "IL6 (pg/ml)" , subtitle = paste0 ("missing data for " , IL6_missing, " cases" )) + lims (x = c (0 ,2500 )) +
geom_vline (xintercept = co_IL6, linetype = "dashed" , color = "black" )
IL6_grid <- plot_grid (p_IL6_cohort, p_IL6_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
IL6_grid
The number of single cases with increased IL6: 41 out of total cases (= total cases minus missing cases): 42
BNP
collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "_BNP" )
collapse_single <- collapse_labvals_single (df_singlecases, "max" , "_BNP" )
missing <- sum (is.na (collapse_single$ ` _BNP_max ` ))
p_BNP_cohort <- ggplot (collapse_cohort, aes (y = cohort_id, x = ` _BNP_med ` , col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= ` _BNP_min ` , xmax= ` _BNP_max ` ), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,20000 )) +
theme_bw () + labs (title = "BNP" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_BNP, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 )) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_BNP_single <- ggplot (collapse_single, aes (x = as.numeric (` _BNP_max ` ), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "BNP (pg/ml)" , subtitle = paste0 ("missing data for " , missing, " cases" )) + lims (x = c (0 ,20000 )) +
geom_vline (xintercept = co_BNP, linetype = "dashed" , color = "black" )
BNP_grid <- plot_grid (p_BNP_cohort, p_BNP_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
BNP_grid
The number of single cases with increased BNP: 49 out of total cases (= total cases minus missing cases): 56
NTproBNP
collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "NTproBNP" )
collapse_single <- collapse_labvals_single (df_singlecases, "max" , "NTproBNP" )
missing <- sum (is.na (collapse_single$ NTproBNP_max))
p_NTproBNP_cohort <- ggplot (collapse_cohort, aes (y = cohort_id, x = NTproBNP_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= NTproBNP_min, xmax= NTproBNP_max), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,70000 )) +
theme_bw () + labs (title = "NTproBNP" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_NTproBNP, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_NTproBNP_single <- ggplot (collapse_single, aes (x = as.numeric (NTproBNP_max), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "NTproBNP (pg/ml)" , subtitle = paste0 ("missing data for " , missing, " cases" )) + lims (x = c (0 ,70000 )) +
geom_vline (xintercept = co_NTproBNP, linetype = "dashed" , color = "black" )
NTproBNP_grid <- plot_grid (p_NTproBNP_cohort, p_NTproBNP_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
NTproBNP_grid
The number of single cases with increased NTproBNP: 30 out of total cases (= total cases minus missing cases): 37
Platelets
collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "min" , "platelet" )
collapse_single <- collapse_labvals_single (df_singlecases, "min" , "platelet" )
missing <- sum (is.na (collapse_single$ platelet_min))
p_platelet_cohort <- ggplot (collapse_cohort, aes (y = cohort_id, x = platelet_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= platelet_min, xmax= platelet_max, col= cohort_type), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,750000 )) +
theme_bw () + labs (title = "platelet" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_platelet, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_platelet_single <- ggplot (collapse_single, aes (x = as.numeric (platelet_min), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "Platelets (/µL)" , subtitle = paste0 ("missing data for " , missing, " cases" )) + lims (x = c (0 ,750000 )) +
geom_vline (xintercept = co_platelet, linetype = "dashed" , color = "black" )
platelet_grid <- plot_grid (p_platelet_cohort, p_platelet_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
platelet_grid
The number of single cases with thrombopenia (< 150 000): 45 out of total cases (= total cases minus missing cases): 104
D-dimers
collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "max" , "Ddim" )
collapse_single <- collapse_labvals_single (df_singlecases, "max" , "Ddim" )
missing <- sum (is.na (collapse_single$ Ddim_max))
p_Ddim_cohort <- ggplot (collapse_cohort, aes (y = cohort_id, x = Ddim_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= Ddim_min, xmax= Ddim_max, col= cohort_type), width= .2 , position= position_dodge (.9 )) + lims (x = c (0 ,11000 )) +
theme_bw () + labs (title = "D-dimers" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_Ddim, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_Ddim_single <- ggplot (collapse_single, aes (x = as.numeric (Ddim_max), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "D-dimers (ng/ml)" , subtitle = paste0 ("missing data for " , missing, " cases" )) + lims (x = c (0 ,11000 )) +
geom_vline (xintercept = co_Ddim, linetype = "dashed" , color = "black" )
Ddim_grid <- plot_grid (p_Ddim_cohort, p_Ddim_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
Ddim_grid
The number of single cases with increased D-dimers: 74 out of total cases (= total cases minus missing cases): 75
Sodium
collapse_cohort <- collapse_labvals_cohort (df_cohort_controls, "min" , "sodium" )
collapse_single <- collapse_labvals_single (df_singlecases, "min" , "sodium" )
missing <- sum (is.na (collapse_single$ sodium_min))
p_sodium_cohort <- ggplot (collapse_cohort, aes (y = cohort_id, x = sodium_med, col = cohort_type)) +
geom_point () +
geom_errorbar (aes (xmin= sodium_min, xmax= sodium_max, col= cohort_type), width= .2 , position= position_dodge (.9 )) + lims (x = c (100 ,200 )) +
theme_bw () + labs (title = "Sodium" , y = "cohort" , x = "" ) +
geom_vline (xintercept = co_sodium, linetype = "dashed" , color = "black" ) + theme (legend.justification = c (1 , 1 ), legend.position = c (0.98 , 0.98 ), legend.title= element_blank ()) +
scale_color_manual (values = wes_palette ("Royal1" )[c (4 ,2 ,1 )])
p_sodium_single <- ggplot (collapse_single, aes (x = as.numeric (sodium_min), y = cohort_id)) +
geom_violin (fill = wes_palette ("Darjeeling2" )[4 ]) +
geom_boxplot (width= .3 , fill = wes_palette ("Darjeeling2" )[1 ]) +
theme_bw () + geom_beeswarm (groupOnX= FALSE , alpha = 0.5 ) + labs (y = "" , x = "Sodium (mmol/L)" , subtitle = paste0 ("missing data for " , missing, " cases" )) + lims (x = c (100 ,200 )) +
geom_vline (xintercept = co_sodium, linetype = "dashed" , color = "black" )
sodium_grid <- plot_grid (p_sodium_cohort, p_sodium_single, align = "v" , nrow = 2 , rel_heights = c (2 / 3 , 1 / 3 ))
sodium_grid
The number of single cases with hyponatremia: 55 out of total cases (= total cases minus missing cases): 61
Critical care interventions
Treatments
IVIg
Overall therapy
Case definitions
Lab reference values
Cut-offs in this study:
Neutrophilia > 8000/µL
Elevated CRP > 10 mg/L
Lymphopenia < 1250/µL
WBC > 11000/µL
Fibrinogen > 400 mg/dL
D-dimers > 250 ng/mL
Ferritin > 300 ng/mL
Albumin < 34 g/L
Procalcitonin > 0.49 ng/mL
LDH > 280 U/L
IL6 > 16.4 pg/mL
ESR > 22 mm/
BNP > 100 pg/mL
NTproBNP > 400 pg/mL
Troponin > 0.04 ng/mL
RCPCH, CDC and WHO
PIMS-TS
Source RCPCH
A child presenting with persistent fever, inflammation (neutrophilia, elevated CRP and lymphopaenia) and evidence of single or multi-organ dysfunction (shock, cardiac, respiratory, renal, gastrointestinal or neurological disorder) with additional features (see listed in Appendix 1). This may include children fulfilling full or partial criteria for Kawasaki disease.
Exclusion of any other microbial cause, including bacterial sepsis, staphylococcal or streptococcal shock syndromes, infections associated with myocarditis such as enterovirus (waiting for results of these investigations should not delay seeking expert advice).
SARS-CoV-2 PCR testing may be positive or negative
We are unable to evaluate criteria 2.
PIMS_TS_fulfilled <- apply (df_singlecases, 1 , function (row) {
# persistent fever, inflammation (neutrophilia, elevated CRP and lymphopaenia)
pat_id <- row["patientID_int" ]
fever <- row["symp_fever" ] == TRUE
neutrophilia <- as.numeric (row["lab_neutrophils" ]) > co_neutrophilia
elevated_CRP <- (as.numeric (row["lab_CRP_admis" ]) > co_CRP | as.numeric (row["lab_CRP_NS" ]) > co_CRP | as.numeric (row["lab_CRP_peak" ]) > co_CRP )
lymphopenia <- as.numeric (row["lab_lymphocytes_lowest" ]) < co_lympho
inflamm <- any (fever, neutrophilia, elevated_CRP, lymphopenia)
# lab values
#fibrinogen <- row["lab_fibrino"] > co_fibrino
#Ddimers <- row["lab_Ddim_peak"] > co_Ddim | row["lab_Ddim_NS"] > co_Ddim
#ferritin <- (row["lab_ferritin_NS"] > co_ferritin | row["lab_ferritin_admis"] > co_ferritin | row["lab_ferritin_peak"] > co_ferritin)
#albumin <- row["lab_albumin_admis"] < co_albu | row["lab_albumin_lowest"] < co_albu | row["lab_albumin_NS"] < co_albu
#lab_vals <- any(fibrinogen, Ddimers, ferritin, albumin)
# single or multi-organ dysfunction (shock, cardiac, respiratory, renal, gastrointestinal or neurological disorder)
pneumonia <- row["symp_resp_pneumonia" ] == TRUE
resp_failure <- row["symp_resp_failure" ] == TRUE
resp <- any (pneumonia, resp_failure)
AKI <- row["symp_renal_AKI" ] == TRUE
RRT <- row["critcare_RRT" ] == TRUE
renal <- any (AKI, RRT)
myocarditis <- row["symp_cardiovasc_myocard" ] == TRUE
pericarditis <- row["symp_cardiovasc_pericard" ] == TRUE
LVEF_under30 <- row["symp_cardiovasc_LV_less30" ] == TRUE
LVEF_30to55 <- row["symp_cardiovasc_LV_30to55" ] == TRUE
BNP <- (as.numeric (row["lab_BNP_admis" ]) > co_BNP | as.numeric (row["lab_BNP_max" ]) > co_BNP )
NTproBNP <- as.numeric (row["lab_NTproBNP" ]) > co_NTproBNP
tropo <- as.numeric (row["lab_troponin_admis" ]) > co_tropo
shock <- row["symp_cardiovasc_shock" ] == TRUE
cardiovasc <- any (myocarditis, LVEF_under30, LVEF_30to55, NTproBNP, BNP, tropo, shock)
rash <- row["kawasaki_exanthema" ] == TRUE
dermato <- any (rash)
ddim <- as.numeric (row["lab_Ddim_NS" ]) >= co_Ddim
hemato <- any (ddim)
organ_dysfunc <- sum (hemato, resp, renal, cardiovasc, dermato, na.rm = TRUE ) >= 1
criteria_fulfilled <- (inflamm) & organ_dysfunc #&lab_vals
#return(c(pat_id, "criteria1_inflamm" = inflamm, "criteria2_labvals" = lab_vals, "criteria3_organdysfunc" = organ_dysfunc, "criteria_fulfilled" = criteria_fulfilled))
return (c (pat_id, "criteria1_inflamm" = inflamm, "criteria2_organdysfunc" = organ_dysfunc, "criteria_fulfilled" = criteria_fulfilled))
})
PIMS_TS_fulfilled <- PIMS_TS_fulfilled %>% t () %>% as_tibble ()
PIMS_TS_fulfilled <- type_convert (PIMS_TS_fulfilled)
PIMS_TS_fulfilled_heatmap <- PIMS_TS_fulfilled
cols <- sapply (PIMS_TS_fulfilled_heatmap, is.logical)
PIMS_TS_fulfilled_heatmap[,cols] <- lapply (PIMS_TS_fulfilled_heatmap[,cols], as.numeric)
PIMS_TS_fulfilled_heatmap_melt <- PIMS_TS_fulfilled_heatmap %>% melt ()
PIMS_TS_fulfilled_heatmap_melt[is.na (PIMS_TS_fulfilled_heatmap_melt)] <- 2
skim (PIMS_TS_fulfilled)
Data summary
Name
PIMS_TS_fulfilled
Number of rows
138
Number of columns
4
_______________________
Column type frequency:
character
1
logical
3
________________________
Group variables
None
Variable type: character
patientID_int
0
1
9
11
0
138
0
Variable type: logical
criteria1_inflamm
0
1
1
TRU: 138
criteria2_organdysfunc
0
1
1
TRU: 138
criteria_fulfilled
0
1
1
TRU: 138
#ggplot(PIMS_TS_fulfilled_heatmap_melt, aes(x = variable, y = as.character(patientID_int), fill = as.factor(value))) + geom_tile() + theme_classic() + theme(axis.line=element_blank()) + labs(y = "Patient ID", x = "criteria", fill = "criteria met", title = "Overview of which single cases fulfill PIMS-TS case definition") + scale_fill_manual(labels = c("No", "Yes", "Missing"), values = c("pink2", "royalblue3", "darkgrey")) + theme(axis.text.x=element_text(angle=90, hjust=1))
CDC MIS-C
Source CDC and UpToDate
The case definition for MIS-C is:
Age <21 years
Clinical presentation consistent with MIS-C, including all of the following:
Fever
Documented fever >38.0°C (100.4°F) for ≥24 hours or
Report of subjective fever lasting ≥24 hours
Laboratory evidence of inflammation
Severe illness requiring hospitalization
Multisystem involvement
2 or more organ systems involved
Cardiovascular (eg, shock, elevated troponin, elevated BNP, abnormal echocardiogram, arrhythmia)
Respiratory (eg, pneumonia, ARDS, pulmonary embolism)
Renal (eg, AKI, renal failure)
Neurologic (eg, seizure, stroke, aseptic meningitis)
Hematologic (eg, coagulopathy)
Gastrointestinal (eg, elevated liver enzymes, diarrhea, ileus, gastrointestinal bleeding)
Dermatologic (eg, erythroderma, mucositis, other rash)
No alternative plausible diagnoses
Recent or current SARS-CoV-2 infection or exposure
Any of the following:
Positive SARS-CoV-2 RT-PCR
Positive serology
Positive antigen test
COVID-19 exposure within the 4 weeks prior to the onset of symptoms
CDC_fulfilled <- apply (df_singlecases, 1 , function (row) {
# criteria 1
criteria1 = TRUE
# criteria 2
pat_id <- row["patientID_int" ]
# fever?
fever <- row["symp_fever" ] == TRUE | row["kawasaki_fever" ] == TRUE
inflamm <- any (fever)
# lab values evidence for inflammation
neutrophilia <- as.numeric (row["lab_neutrophils" ]) > co_neutrophilia
elevated_CRP <- (as.numeric (row["lab_CRP_admis" ]) > co_CRP | as.numeric (row["lab_CRP_NS" ]) > co_CRP | as.numeric (row["lab_CRP_peak" ]) > co_CRP )
lymphopenia <- as.numeric (row["lab_lymphocytes_lowest" ]) < co_lympho
fibrinogen <- as.numeric (row["lab_fibrino" ]) > co_fibrino
Ddimers <- as.numeric (row["lab_Ddim_peak" ]) > co_Ddim | as.numeric (row["lab_Ddim_NS" ]) > co_Ddim
ferritin <- (as.numeric (row["lab_ferritin_NS" ]) > co_ferritin | as.numeric (row["lab_ferritin_admis" ]) > co_ferritin | as.numeric (row["lab_ferritin_peak" ]) > co_ferritin)
albumin <- as.numeric (row["lab_albumin_admis" ]) < co_albu | as.numeric (row["lab_albumin_lowest" ]) < co_albu | as.numeric (row["lab_albumin_NS" ]) < co_albu
PCT <- as.numeric (row["lab_PCT_admis" ]) > co_PCT | as.numeric (row["lab_PCT_peak" ]) > co_PCT | as.numeric (row["lab_PCT_NS" ]) > co_PCT
LDH <- as.numeric (row["lab_LDH" ]) > co_LDH
IL6 <- as.numeric (row["lab_IL6" ]) > co_IL6
ESR <- as.numeric (row["lab_ESR" ]) > co_ESR
lab_vals <- any (neutrophilia, elevated_CRP, lymphopenia, fibrinogen, Ddimers, ferritin, albumin, PCT, LDH, IL6, ESR)
# Ilness requiring hospitalisation
## used surrogate parameters for hosp
hosp_ICU <- row["admis_hosp_days" ] > 1 | row["admis_ICU_days" ] > 1 | row["admis_PICU_admis" ] == TRUE
NIV <- row["critcare_NIV" ] == TRUE | row["critcare_NIV_days" ] > 1
MV <- row["critcare_MV" ] == TRUE | row["critcare_MV_days" ] > 1
inotrop <- row["critcare_inotrop" ] == TRUE | row["critcare_inotrop_days" ] > 1
ECMO <- row["critcare_ECMO" ] == TRUE
IVIg <- row["rx_IVIg_once" ] == TRUE | row["rx_IVIg_multip" ] == TRUE
biologicals <- row["rx_anakinra" ] == TRUE | row["rx_tocilizumab" ] == TRUE | row["rx_infliximab" ] == TRUE | row["rx_antibiotics" ] == TRUE | row["rx_plasma" ] == TRUE | row["rx_remdesivir" ] == TRUE
heparin <- row["rx_heparin" ] == TRUE
req_hosp <- any (hosp_ICU, NIV, MV, inotrop, ECMO, IVIg, biologicals, heparin)
## multisystem involvement >= 2
## respiratory
pneumonia <- row["symp_resp_pneumonia" ] == TRUE
resp_failure <- row["symp_resp_failure" ] == TRUE
resp <- any (pneumonia, resp_failure)
AKI <- row["symp_renal_AKI" ] == TRUE
RRT <- row["critcare_RRT" ] == TRUE
renal <- any (AKI, RRT)
myocarditis <- row["symp_cardiovasc_myocard" ] == TRUE
pericarditis <- row["symp_cardiovasc_pericard" ] == TRUE
LVEF_under30 <- row["symp_cardiovasc_LV_less30" ] == TRUE
LVEF_30to55 <- row["symp_cardiovasc_LV_30to55" ] == TRUE
BNP <- (as.numeric (row["lab_BNP_admis" ]) > co_BNP | as.numeric (row["lab_BNP_max" ]) > co_BNP )
NTproBNP <- as.numeric (row["lab_NTproBNP" ]) > co_NTproBNP
tropo <- as.numeric (row["lab_troponin_admis" ]) > co_tropo
shock <- row["symp_cardiovasc_shock" ] == TRUE
cardiovasc <- any (myocarditis, LVEF_under30, LVEF_30to55, NTproBNP, BNP, tropo, shock)
rash <- row["kawasaki_exanthema" ] == TRUE
dermato <- any (rash)
organ_dysfunc <- sum (resp, renal, cardiovasc, dermato, na.rm = TRUE ) >= 2
criteria2 <- sum (inflamm, lab_vals, req_hosp, organ_dysfunc, na.rm = TRUE ) == 4
# criteria 3
## not evaluable
criteria3 = TRUE
# criteria 4
# COVID pos?
PCR_pos <- row["covid_PCR_pos" ] == TRUE
stool_pos <- row["covid_PCR_stool_pos" ] == TRUE
closecontact <- row["covid_closecontact" ] == TRUE
IgA <- row["covid_IgA_pos" ] == TRUE
IgM <- row["covid_IgM_pos" ] == TRUE
IgG <- row["covid_IgG_pos" ] == TRUE
any_sero <- row["covid_sero_pos" ] == TRUE
criteria4 <- any (PCR_pos, stool_pos, closecontact, IgA, IgM, IgG, any_sero)
if (FALSE %in% c (criteria1, criteria2, criteria3, criteria4)){
criteria_fulfilled <- FALSE
} else if (NA %in% c (criteria1, criteria2, criteria3, criteria4)){
criteria_fulfilled <- NA
} else if (sum (criteria1, criteria2, criteria3, criteria4, na.rm = TRUE ) == 4 ){
criteria_fulfilled <- TRUE
}
#criteria_fulfilled <- sum(criteria1, criteria2, criteria3, criteria4, na.rm = TRUE) == 4
return (c (pat_id, "criteria1_age" = criteria1, "criteria2_clinical" = criteria2, "criteria3_noAlt" = criteria3, "criteria4_recentExposure" = criteria4, "criteria_fulfilled" = criteria_fulfilled))
})
CDC_fulfilled <- CDC_fulfilled %>% t () %>% as_tibble ()
CDC_fulfilled <- type_convert (CDC_fulfilled)
CDC_fulfilled_heatmap <- CDC_fulfilled
cols <- sapply (CDC_fulfilled_heatmap, is.logical)
CDC_fulfilled_heatmap[,cols] <- lapply (CDC_fulfilled_heatmap[,cols], as.numeric)
CDC_fulfilled_heatmap_melt <- CDC_fulfilled_heatmap %>% melt ()
CDC_fulfilled_heatmap_melt[is.na (CDC_fulfilled_heatmap_melt)] <- 2
skim (CDC_fulfilled)
Data summary
Name
CDC_fulfilled
Number of rows
138
Number of columns
6
_______________________
Column type frequency:
character
1
logical
5
________________________
Group variables
None
Variable type: character
patientID_int
0
1
9
11
0
138
0
Variable type: logical
criteria1_age
0
1.00
1.00
TRU: 138
criteria2_clinical
0
1.00
0.64
TRU: 89, FAL: 49
criteria3_noAlt
0
1.00
1.00
TRU: 138
criteria4_recentExposure
15
0.89
1.00
TRU: 123
criteria_fulfilled
8
0.94
0.62
TRU: 81, FAL: 49
#ggplot(CDC_fulfilled_heatmap_melt, aes(x = variable, y = as.character(patientID_int), fill = as.factor(value))) + geom_tile() + theme_classic() + theme(axis.line=element_blank()) + labs(y = "Patient ID", x = "criteria", fill = "criteria met", title = "Overview of which single cases fulfill CDC MIS-C case definition") + scale_fill_manual(labels = c("No", "Yes", "Missing"), values = c("pink2", "royalblue3", "darkgrey")) + theme(axis.text.x=element_text(angle=90, hjust=1))
CDC criterium 2 in more detail
CDC_fulfilled_crit2 <- apply (df_singlecases, 1 , function (row) {
pat_id <- row["patientID_int" ]
# fever?
fever <- row["symp_fever" ] == TRUE | row["kawasaki_fever" ] == TRUE
inflamm <- any (fever)
# lab values evidence for inflammation
neutrophilia <- as.numeric (row["lab_neutrophils" ]) > co_neutrophilia
elevated_CRP <- (as.numeric (row["lab_CRP_admis" ]) > co_CRP | as.numeric (row["lab_CRP_NS" ]) > co_CRP | as.numeric (row["lab_CRP_peak" ]) > co_CRP )
lymphopenia <- as.numeric (row["lab_lymphocytes_lowest" ]) < co_lympho
fibrinogen <- as.numeric (row["lab_fibrino" ]) > co_fibrino
Ddimers <- as.numeric (row["lab_Ddim_peak" ]) > co_Ddim | as.numeric (row["lab_Ddim_NS" ]) > co_Ddim
ferritin <- (as.numeric (row["lab_ferritin_NS" ]) > co_ferritin | as.numeric (row["lab_ferritin_admis" ]) > co_ferritin | as.numeric (row["lab_ferritin_peak" ]) > co_ferritin)
albumin <- as.numeric (row["lab_albumin_admis" ]) < co_albu | as.numeric (row["lab_albumin_lowest" ]) < co_albu | as.numeric (row["lab_albumin_NS" ]) < co_albu
PCT <- as.numeric (row["lab_PCT_admis" ]) > co_PCT | as.numeric (row["lab_PCT_peak" ]) > co_PCT | as.numeric (row["lab_PCT_NS" ]) > co_PCT
LDH <- as.numeric (row["lab_LDH" ]) > co_LDH
IL6 <- as.numeric (row["lab_IL6" ]) > co_IL6
ESR <- as.numeric (row["lab_ESR" ]) > co_ESR
lab_vals <- any (neutrophilia, elevated_CRP, lymphopenia, fibrinogen, Ddimers, ferritin, albumin, PCT, LDH, IL6, ESR)
# Ilness requiring hospitalisation
## used surrogate parameters for hosp
hosp_ICU <- row["admis_hosp_days" ] > 1 | row["admis_ICU_days" ] > 1 | row["admis_PICU_admis" ] == TRUE
NIV <- row["critcare_NIV" ] == TRUE | row["critcare_NIV_days" ] > 1
MV <- row["critcare_MV" ] == TRUE | row["critcare_MV_days" ] > 1
inotrop <- row["critcare_inotrop" ] == TRUE | row["critcare_inotrop_days" ] > 1
ECMO <- row["critcare_ECMO" ] == TRUE
IVIg <- row["rx_IVIg_once" ] == TRUE | row["rx_IVIg_multip" ] == TRUE
biologicals <- row["rx_anakinra" ] == TRUE | row["rx_tocilizumab" ] == TRUE | row["rx_infliximab" ] == TRUE | row["rx_antibiotics" ] == TRUE | row["rx_plasma" ] == TRUE | row["rx_remdesivir" ] == TRUE
heparin <- row["rx_heparin" ] == TRUE
req_hosp <- any (hosp_ICU, NIV, MV, inotrop, ECMO, IVIg, biologicals, heparin)
## multisystem involvement >= 2
## respiratory
pneumonia <- row["symp_resp_pneumonia" ] == TRUE
resp_failure <- row["symp_resp_failure" ] == TRUE
resp <- any (pneumonia, resp_failure)
AKI <- row["symp_renal_AKI" ] == TRUE
RRT <- row["critcare_RRT" ] == TRUE
renal <- any (AKI, RRT)
myocarditis <- row["symp_cardiovasc_myocard" ] == TRUE
pericarditis <- row["symp_cardiovasc_pericard" ] == TRUE
LVEF_under30 <- row["symp_cardiovasc_LV_less30" ] == TRUE
LVEF_30to55 <- row["symp_cardiovasc_LV_30to55" ] == TRUE
BNP <- (as.numeric (row["lab_BNP_admis" ]) > co_BNP | as.numeric (row["lab_BNP_max" ]) > co_BNP )
NTproBNP <- as.numeric (row["lab_NTproBNP" ]) > co_NTproBNP
tropo <- as.numeric (row["lab_troponin_admis" ]) > co_tropo
shock <- row["symp_cardiovasc_shock" ] == TRUE
cardiovasc <- any (myocarditis, LVEF_under30, LVEF_30to55, NTproBNP, BNP, tropo, shock)
rash <- row["kawasaki_exanthema" ] == TRUE
dermato <- any (rash)
organ_dysfunc <- sum (resp, renal, cardiovasc, dermato, na.rm = TRUE ) >= 2
#criteria_fulfilled <- sum(criteria1, criteria2, criteria3, criteria4, na.rm = TRUE) == 4
return (c (pat_id, "criteria2_inflamm" = inflamm, "criteria2_labvals" = lab_vals, "criteria2_req_hosp" = req_hosp, "criteria2_organ_dysfunc" = organ_dysfunc))
})
CDC_fulfilled_crit2 <- CDC_fulfilled_crit2
CDC_fulfilled_crit2 <- CDC_fulfilled_crit2 %>% t () %>% as_tibble ()
CDC_fulfilled_crit2 <- type_convert (CDC_fulfilled_crit2)
CDC_fulfilled_crit2_heatmap <- CDC_fulfilled_crit2
cols <- sapply (CDC_fulfilled_crit2_heatmap, is.logical)
CDC_fulfilled_crit2_heatmap[,cols] <- lapply (CDC_fulfilled_crit2_heatmap[,cols], as.numeric)
CDC_fulfilled_crit2_heatmap_melt <- CDC_fulfilled_crit2_heatmap %>% melt ()
CDC_fulfilled_crit2_heatmap_melt[is.na (CDC_fulfilled_crit2_heatmap_melt)] <- 2
CDC_fulfilled_crit2_heatmap_melt$ criteria <- "CDC criteria 2"
#skim(CDC_fulfilled_crit2)
ggplot (CDC_fulfilled_crit2_heatmap_melt, aes (x = variable, y = as.character (patientID_int), fill = as.factor (value))) + geom_tile () +
theme_classic () + theme (axis.line= element_blank ()) +
labs (y = "Patient ID" , x = "criteria" , fill = "criteria met" , title = "Overview of which single cases fulfill criterium 2 of the CDC case definition" ) +
scale_fill_manual (labels = c ("No" , "Yes" , "Missing" ), values = wes_palette ("Zissou1" )) +
theme (axis.text.x= element_text (angle= 90 , hjust= 1 )) + facet_wrap (~ criteria, scales = "free_x" )
WHO case definition
Source UpToDate :
All 6 criteria must be met:
Age 0 to 19 years
Fever for ≥3 days
Clinical signs of multisystem involvement (at least 2 of the following):
Rash, bilateral nonpurulent conjunctivitis, or mucocutaneous inflammation signs (oral, hands, or feet)
Hypotension or shock
Cardiac dysfunction, pericarditis, valvulitis, or coronary abnormalities (including echocardiographic findings or elevated troponin/BNP)
Evidence of coagulopathy (prolonged PT or PTT; elevated D-dimer)
Acute gastrointestinal symptoms (diarrhea, vomiting, or abdominal pain)
Elevated markers of inflammation (eg, ESR, CRP, or procalcitonin)
No other obvious microbial cause of inflammation, including bacterial sepsis and staphylococcal/streptococcal toxic shock syndromes
Evidence of SARS-CoV-2 infection
Any of the following:
Positive SARS-CoV-2 RT-PCR
Positive serology
Positive antigen test
Contact with an individual with COVID-19
#row <- df_singlecases[87, ]
WHO_fulfilled <- apply (df_singlecases, 1 , function (row) {
pat_id <- row["patientID_int" ]
# criteria 1
criteria1 = TRUE
# criteria 2: fever?
fever <- row["symp_fever" ] == TRUE | row["kawasaki_fever" ] == TRUE
criteria2 <- any (fever)
# criteria 3: clinical signs of multisystem involvement (at least 2)
## Rash, bilateral nonpurulent conjunctivitis, or mucocutaneous inflammation signs (oral, hands, or feet)
rash <- row["kawasaki_exanthema" ] == TRUE
conjunctivitis <- row["kawasaki_conjunctivitis" ] == TRUE
mucocutaneaous <- row["kawasaki_mouth" ] == TRUE | row["kawasaki_extremity" ] == TRUE
criteria3_a <- any (rash, conjunctivitis, mucocutaneaous)
## hypotension or shock
shock <- row["symp_cardiovasc_shock" ] == TRUE
criteria3_b <- any (shock)
## cardiac dysfunction
myocarditis <- row["symp_cardiovasc_myocard" ] == TRUE
pericarditis <- row["symp_cardiovasc_pericard" ] == TRUE
LVEF_under30 <- row["symp_cardiovasc_LV_less30" ] == TRUE
LVEF_30to55 <- row["symp_cardiovasc_LV_30to55" ] == TRUE
BNP <- (as.numeric (row["lab_BNP_admis" ]) > co_BNP | as.numeric (row["lab_BNP_max" ]) > co_BNP )
NTproBNP <- as.numeric (row["lab_NTproBNP" ]) > co_NTproBNP
tropo <- as.numeric (row["lab_troponin_admis" ]) > co_tropo
coronary <- row["symp_cardiovasc_cordilat" ] == TRUE | row["symp_cardiovasc_aneurysm" ] == TRUE
criteria3_c <- any (myocarditis, LVEF_under30, LVEF_30to55, NTproBNP, BNP, tropo, coronary)
## coagulopathy
fibrinogen <- as.numeric (row["lab_fibrino" ]) > co_fibrino
Ddimers <- as.numeric (row["lab_Ddim_peak" ]) > co_Ddim | as.numeric (row["lab_Ddim_NS" ]) > co_Ddim
criteria3_d <- any (fibrinogen, Ddimers)
## acute GI symptoms
GIsymp <- row["symp_GI_NS" ] == TRUE | row["symp_GI_abdopain" ] == TRUE | row["symp_GI_vomiting" ] == TRUE | row["symp_GI_diarrh" ] == TRUE | row["symp_GI_colitis" ] == TRUE
criteria3_e <- any (GIsymp)
criteria3 <- sum (criteria3_a, criteria3_b, criteria3_c, criteria3_d, criteria3_e, na.rm = TRUE ) >= 2
# criteria 4: Elevated markers of inflammation (eg, ESR, CRP, or procalcitonin)
neutrophilia <- as.numeric (row["lab_neutrophils" ]) > co_neutrophilia
elevated_CRP <- (as.numeric (row["lab_CRP_admis" ]) >= co_CRP) | (as.numeric (row["lab_CRP_NS" ]) >= co_CRP) | (as.numeric (row["lab_CRP_peak" ]) >= co_CRP )
# print(paste0(pat_id, elevated_CRP, row["lab_CRP_peak"]))
lymphopenia <- as.numeric (row["lab_lymphocytes_lowest" ]) < co_lympho
ferritin <- (as.numeric (row["lab_ferritin_NS" ]) > co_ferritin | as.numeric (row["lab_ferritin_admis" ]) > co_ferritin | as.numeric (row["lab_ferritin_peak" ]) > co_ferritin)
albumin <- as.numeric (row["lab_albumin_admis" ]) < co_albu | as.numeric (row["lab_albumin_lowest" ]) < co_albu | as.numeric (row["lab_albumin_NS" ]) < co_albu
PCT <- as.numeric (row["lab_PCT_admis" ]) > co_PCT | as.numeric (row["lab_PCT_peak" ]) > co_PCT | as.numeric (row["lab_PCT_NS" ]) > co_PCT
LDH <- as.numeric (row["lab_LDH" ]) > co_LDH
IL6 <- as.numeric (row["lab_IL6" ]) > co_IL6
ESR <- as.numeric (row["lab_ESR" ]) > co_ESR
criteria4 <- any (neutrophilia, elevated_CRP, lymphopenia, ferritin, albumin, PCT, LDH, IL6, ESR)
# criteria 5: No other obvious microbial cause of inflammation
criteria5 <- TRUE
# criteria 6: COVID pos?
PCR_pos <- row["covid_PCR_pos" ] == TRUE
stool_pos <- row["covid_PCR_stool_pos" ] == TRUE
closecontact <- row["covid_closecontact" ] == TRUE
IgA <- row["covid_IgA_pos" ] == TRUE
IgM <- row["covid_IgM_pos" ] == TRUE
IgG <- row["covid_IgG_pos" ] == TRUE
any_sero <- row["covid_sero_pos" ] == TRUE
criteria6 <- any (PCR_pos, stool_pos, closecontact, IgA, IgM, IgG, any_sero)
if (NA %in% c (criteria1, criteria2, criteria3, criteria4, criteria5, criteria6)){
criteria_fulfilled <- NA
} else if (FALSE %in% c (criteria1, criteria2, criteria3, criteria4, criteria5, criteria6)){
criteria_fulfilled <- FALSE
} else if (sum (criteria1, criteria2, criteria3, criteria4, criteria5, criteria6, na.rm = TRUE ) == 6 ){
criteria_fulfilled <- TRUE
} else {
criteria_fulfilled <- FALSE
}
return (c (pat_id, "criteria1_age" = criteria1, "criteria2_fever" = criteria2, "criteria3_clinical" = criteria3, "criteria4_inflamm" = criteria4, "criteria5_noAlt" = criteria5, "criteria6_recentExposure" = criteria6, "criteria_fulfilled" = criteria_fulfilled))
})
WHO_fulfilled <- WHO_fulfilled %>% t () %>% as_tibble ()
WHO_fulfilled <- type_convert (WHO_fulfilled)
WHO_fulfilled_heatmap <- WHO_fulfilled
cols <- sapply (WHO_fulfilled_heatmap, is.logical)
WHO_fulfilled_heatmap[,cols] <- lapply (WHO_fulfilled_heatmap[,cols], as.numeric)
WHO_fulfilled_heatmap_melt <- WHO_fulfilled_heatmap %>% melt ()
WHO_fulfilled_heatmap_melt[is.na (WHO_fulfilled_heatmap_melt)] <- 2
skim (WHO_fulfilled)
Data summary
Name
WHO_fulfilled
Number of rows
138
Number of columns
8
_______________________
Column type frequency:
character
1
logical
7
________________________
Group variables
None
Variable type: character
patientID_int
0
1
9
11
0
138
0
Variable type: logical
criteria1_age
0
1.00
1.00
TRU: 138
criteria2_fever
0
1.00
1.00
TRU: 138
criteria3_clinical
0
1.00
0.97
TRU: 134, FAL: 4
criteria4_inflamm
8
0.94
1.00
TRU: 130
criteria5_noAlt
0
1.00
1.00
TRU: 138
criteria6_recentExposure
15
0.89
1.00
TRU: 123
criteria_fulfilled
18
0.87
0.97
TRU: 116, FAL: 4
#ggplot(WHO_fulfilled_heatmap_melt, aes(x = variable, y = as.character(patientID_int), fill = as.factor(value))) + geom_tile() + theme_classic() + theme(axis.line=element_blank()) + labs(y = "Patient ID", x = "criteria", fill = "criteria met", title = "Overview of which single cases fulfill WHO MIS-C case definition") + scale_fill_manual(labels = c("No", "Yes", "Missing"), values = c("pink2", "royalblue3", "darkgrey")) + theme(axis.text.x=element_text(angle=90, hjust=1))
Per-case overview
PIMS_TS_fulfilled_heatmap_melt$ criteria <- "PIMS-TS"
WHO_fulfilled_heatmap_melt$ criteria <- "WHO"
CDC_fulfilled_heatmap_melt$ criteria <- "CDC"
full_heatmap <- rbind (PIMS_TS_fulfilled_heatmap_melt, WHO_fulfilled_heatmap_melt, CDC_fulfilled_heatmap_melt)
ggplot (full_heatmap, aes (x = variable, y = as.character (patientID_int), fill = as.factor (value))) + geom_tile () + theme_classic () + theme (axis.line= element_blank ()) + labs (y = "Patient ID" , x = "criteria" , fill = "criteria met" , title = "Overview of which single cases fulfill case definitions" ) + scale_fill_manual (labels = c ("No" , "Yes" , "Missing" ), values = wes_palette ("Zissou1" )) + theme (axis.text.x= element_text (angle= 90 , hjust= 1 )) + facet_wrap (~ criteria, scales = "free_x" )
Summary
criteria_summary <- data.frame (PIMS_TS_fulfilled %>% select (criteria_fulfilled), CDC_fulfilled %>% select (criteria_fulfilled), WHO_fulfilled %>% select (criteria_fulfilled))
colnames (criteria_summary) <- c ("PIMS-TS" , "CDC" , "WHO" )
cols <- sapply (criteria_summary, is.logical)
criteria_summary[,cols] <- lapply (criteria_summary[,cols], as.numeric)
criteria_summary <- criteria_summary %>% melt () %>%
group_by (variable) %>%
summarise (fulfilled = sum (value == 1 , na.rm = TRUE ), not_fulfilled = sum (value == 0 , na.rm = TRUE ), not_assessable = sum (is.na (value)))
criteria_summary$ sum <- rowSums (criteria_summary[,- 1 ])
criteria_summary_melt <- criteria_summary %>% melt ()
colnames (criteria_summary_melt) <- c ("case_definition" , "fulfilled" , "count" )
fill_bar <- ggplot (criteria_summary_melt %>% filter (fulfilled != 'sum' ), aes (x = case_definition, y = count, fill = fulfilled)) +
geom_bar (stat = "identity" , position = "fill" ) + theme_bw () +
labs (y = "fraction" , title = "Single cases meeting which criteria" , subtitle = paste0 ("fraction of total (n = " , max (criteria_summary_melt$ count) ,")" )) +
theme (legend.title = element_blank ()) +
scale_fill_manual (values = wes_palette ("Royal1" )[c (1 ,2 ,4 )])
dodge_bar <- ggplot (criteria_summary_melt %>% filter (fulfilled != 'sum' ), aes (x = case_definition, y = count, fill = fulfilled)) +
geom_bar (stat = "identity" , position = "dodge" ) + theme_bw () +
labs (y = "number of cases" , title = "Single cases meeting which criteria" , subtitle = "absolute values" ) +
theme (legend.title = element_blank ()) +
scale_fill_manual (values = wes_palette ("Royal1" )[c (1 ,2 ,4 )])
ggarrange (dodge_bar, fill_bar, legend = "bottom" , common.legend = TRUE )
Association of case definition with outcome
WHO_outcome <- WHO_fulfilled_heatmap %>% select (contains ("patientID_int" ) | contains ("criteria_fulfilled" ))
colnames (WHO_outcome) <- c ("patientID_int" , "casedef_WHO_fulfilled" )
CDC_outcome <- CDC_fulfilled_heatmap %>% select (contains ("patientID_int" ) | contains ("criteria_fulfilled" ))
colnames (CDC_outcome) <- c ("patientID_int" , "casedef_CDC_fulfilled" )
PIMS_TS_outcome <- PIMS_TS_fulfilled_heatmap %>% select (contains ("patientID_int" ) | contains ("criteria_fulfilled" ))
colnames (PIMS_TS_outcome) <- c ("patientID_int" , "casedef_PIMS_TS_fulfilled" )
assoc_outcome <- merge (WHO_outcome, CDC_outcome, by = "patientID_int" )
assoc_outcome <- merge (assoc_outcome, PIMS_TS_outcome)
#assoc_outcome <- assoc_outcome[complete.cases(assoc_outcome[ ,-1]),]
outcome_params <- df_singlecases %>% select (patientID_int | symp_cardiovasc_cordilat | symp_cardiovasc_aneurysm | symp_cardiovasc_shock | outcome_death | critcare_MV | critcare_ECMO)
assoc_outcome_full <- merge (outcome_params, assoc_outcome, by = "patientID_int" , all = TRUE )
cols <- sapply (assoc_outcome_full, is.logical)
assoc_outcome_full[,cols] <- lapply (assoc_outcome_full[,cols], as.numeric)
makeUpsetR (assoc_outcome_full %>% select (- contains ("patientID" )))
Severe course
A new variable ‘severe course’ made, which contains the following:
symp_cardiovasc_cordilat
symp_cardiovasc_aneurysm
symp_cardiovasc_shock
outcome_death
critcare_MV
critcare_ECMO
critcare_RRT
critcare_inotrop
admis_PICU_admis
Mild presentation means all of the above are either 0 or NA.
Cases with missing values in case defintions are removed.
assoc_outcome <- merge (WHO_outcome, CDC_outcome, by = "patientID_int" )
assoc_outcome <- merge (assoc_outcome, PIMS_TS_outcome)
assoc_outcome <- merge (assoc_outcome, PIMS_TS_outcome)
assoc_outcome <- assoc_outcome[complete.cases (assoc_outcome[ ,- 1 ]),]
outcome_params <- df_singlecases %>% select (patientID_int | contains ("critcare" ) | contains ("admis_PICU_admis" ) | contains ("outcome_death" ) | contains ("symp_cardiovasc_cordilat" ) | contains ("symp_cardiovasc_aneurysm" ) | contains ("symp_cardiovasc_shock" ))
assoc_outcome_full <- merge (outcome_params, assoc_outcome, by = "patientID_int" )
cols <- sapply (assoc_outcome_full, is.logical)
assoc_outcome_full[,cols] <- lapply (assoc_outcome_full[,cols], as.numeric)
assoc_outcome_full$ severe_course <- ifelse (assoc_outcome_full$ symp_cardiovasc_cordilat == 1 | assoc_outcome_full$ symp_cardiovasc_aneurysm == 1 | assoc_outcome_full$ symp_cardiovasc_shock == 1 | assoc_outcome_full$ outcome_death == 1 | assoc_outcome_full$ critcare_MV == 1 | assoc_outcome_full$ critcare_ECMO == 1 | assoc_outcome_full$ critcare_RRT == 1 | assoc_outcome_full$ admis_PICU_admis == 1 | assoc_outcome_full$ critcare_inotrop == 1 , 1 , 0 )
assoc_outcome_full$ mild_presentation <- ifelse ((assoc_outcome_full$ severe_course == 0 | is.na (assoc_outcome_full$ severe_course)), 1 , 0 )
makeUpsetR (assoc_outcome_full %>% select (contains ("casedef" ) | contains ("severe_course" ) ))
Characteristics of severe course
Download data as .csv on Github
# in this step, do not remove NAs
assoc_outcome <- merge (WHO_outcome, CDC_outcome, by = "patientID_int" )
assoc_outcome <- merge (assoc_outcome, PIMS_TS_outcome)
assoc_outcome <- merge (assoc_outcome, PIMS_TS_outcome)
#assoc_outcome <- assoc_outcome[complete.cases(assoc_outcome[ ,-1]),]
outcome_params <- df_singlecases %>% select (patientID_int | contains ("critcare" ) | contains ("admis_PICU_admis" ) | contains ("outcome_death" ) | contains ("symp_cardiovasc_cordilat" ) | contains ("symp_cardiovasc_aneurysm" ) | contains ("symp_cardiovasc_shock" ))
assoc_outcome_full <- merge (outcome_params, assoc_outcome, by = "patientID_int" )
cols <- sapply (assoc_outcome_full, is.logical)
assoc_outcome_full[,cols] <- lapply (assoc_outcome_full[,cols], as.numeric)
assoc_outcome_full$ severe_course <- ifelse (assoc_outcome_full$ symp_cardiovasc_cordilat == 1 | assoc_outcome_full$ symp_cardiovasc_aneurysm == 1 | assoc_outcome_full$ symp_cardiovasc_shock == 1 | assoc_outcome_full$ outcome_death == 1 | assoc_outcome_full$ critcare_MV == 1 | assoc_outcome_full$ critcare_ECMO == 1 | assoc_outcome_full$ critcare_RRT == 1 | assoc_outcome_full$ admis_PICU_admis == 1 | assoc_outcome_full$ critcare_inotrop == 1 , 1 , 0 )
tab1 <- assoc_outcome_full %>% select (patientID_int,severe_course)
tab1$ severe_course <- ifelse (is.na (tab1$ severe_course), 0 , 1 )
tab2 <- df_singlecases %>% select (patientID_int,
sex, age,
symp_resp_any,
symp_cardiovasc_any,
symp_cardiovasc_myocard,
symp_cardiovasc_pericard,
symp_cardiovasc_cordilat,
symp_cardiovasc_aneurysm,
symp_cardiovasc_LV_30to55,
symp_cardiovasc_LV_less30,
symp_cardiovasc_shock,
symp_cardiovasc_LVEF,
symp_cardiovasc_tachycard,
symp_GI_any,
symp_neuro_any,
kawasaki_complete,
kawasaki_incomplete,
kawasaki_fever,
kawasaki_exanthema,
kawasaki_extremity,
kawasaki_mouth,
kawasaki_cervical,
kawasaki_conjunctivitis,
covid_PCR_pos,
covid_sero_any,
admis_PICU_admis,
critcare_NIV,
critcare_MV,
critcare_inotrop,
critcare_ECMO,
critcare_RRT,
rx_cortic,
rx_heparin,
rx_IVIg_once,
rx_IVIg_multip,
rx_anakinra,
rx_tocilizumab,
rx_infliximab,
rx_antibiotics,
rx_plasma,
rx_remdesivir)
tab2$ sex <- as.factor (tab2$ sex)
labvals <-
data.frame (
collapse_labvals_single (df_singlecases, "max" , "CRP" ) %>% select (CRP_max),
collapse_labvals_single (df_singlecases, "max" , "ferritin" ) %>% select (ferritin_max),
collapse_labvals_single (df_singlecases, "max" , "IL" ) %>% select (IL_max),
collapse_labvals_single (df_singlecases, "max" , "WBC" ) %>% select (WBC_max),
collapse_labvals_single (df_singlecases, "min" , "lympho" ) %>% select (lympho_min),
collapse_labvals_single (df_singlecases, "min" , "platelet" ) %>% select (platelet_min),
collapse_labvals_single (df_singlecases, "min" , "sodium" ) %>% select (sodium_min),
collapse_labvals_single (df_singlecases, "max" , "Ddim" ) %>% select (Ddim_max),
collapse_labvals_single (df_singlecases, "max" , "trop" ) %>% select (trop_max)
)
tab2 <- cbind (tab2, labvals)
tab <- merge (tab1, tab2)
skim <- tab %>% group_by (severe_course) %>% skim ()
skim <- skim %>% select (skim_variable, severe_course, factor.top_counts, logical.count, numeric.p25, numeric.p50, numeric.p75, n_missing)
skim$ n_total <- rep (count (tab1, severe_course) %>% pull (n), nrow (skim)/ 2 )
skim$ n_valid <- skim$ n_total - skim$ n_missing
write.csv (skim, paste0 ("./data/unfavorable_course_descriptivestats.csv" ))
SessionInfo
## R version 4.0.3 (2020-10-10)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Big Sur 10.16
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets
## [6] methods base
##
## other attached packages:
## [1] gdtools_0.2.2 padr_0.5.3
## [3] wesanderson_0.3.6 see_0.6.1
## [5] UpSetR_1.4.0 skimr_2.1.2
## [7] psych_2.0.9 zoo_1.8-8
## [9] DT_0.16 naniar_0.6.0
## [11] cowplot_1.1.0 ggpubr_0.4.0
## [13] ggbeeswarm_0.6.0 ggExtra_0.9
## [15] gridExtra_2.3 ggrepel_0.8.2
## [17] scales_1.1.1 RColorBrewer_1.1-2
## [19] broom_0.7.2 reshape2_1.4.4
## [21] httr_1.4.2 readxl_1.3.1
## [23] forcats_0.5.0 stringr_1.4.0
## [25] dplyr_1.0.2 purrr_0.3.4
## [27] readr_1.4.0 tidyr_1.1.2
## [29] tibble_3.0.4 ggplot2_3.3.3
## [31] tidyverse_1.3.0
##
## loaded via a namespace (and not attached):
## [1] colorspace_1.4-1 ggsignif_0.6.0 ellipsis_0.3.1
## [4] rio_0.5.16 ggridges_0.5.2 visdat_0.5.3
## [7] parameters_0.9.0 base64enc_0.1-3 fs_1.5.0
## [10] rstudioapi_0.11 farver_2.0.3 fansi_0.4.1
## [13] lubridate_1.7.9 xml2_1.3.2 mnormt_2.0.2
## [16] knitr_1.30 jsonlite_1.7.1 dbplyr_1.4.4
## [19] effectsize_0.4.0 shiny_1.5.0 compiler_4.0.3
## [22] backports_1.1.10 assertthat_0.2.1 fastmap_1.0.1
## [25] cli_2.1.0 later_1.1.0.1 htmltools_0.5.0
## [28] tools_4.0.3 gtable_0.3.0 glue_1.4.2
## [31] Rcpp_1.0.5 carData_3.0-4 cellranger_1.1.0
## [34] vctrs_0.3.4 svglite_1.2.3.2 nlme_3.1-149
## [37] crosstalk_1.1.0.1 insight_0.10.0 xfun_0.19
## [40] openxlsx_4.2.3 rvest_0.3.6 mime_0.9
## [43] miniUI_0.1.1.1 lifecycle_0.2.0 rstatix_0.6.0
## [46] hms_0.5.3 promises_1.1.1 parallel_4.0.3
## [49] yaml_2.2.1 curl_4.3 stringi_1.5.3
## [52] highr_0.8 bayestestR_0.7.5 zip_2.1.1
## [55] repr_1.1.0 systemfonts_0.3.2 rlang_0.4.8
## [58] pkgconfig_2.0.3 evaluate_0.14 lattice_0.20-41
## [61] labeling_0.4.2 htmlwidgets_1.5.2 tidyselect_1.1.0
## [64] plyr_1.8.6 magrittr_1.5 R6_2.5.0
## [67] generics_0.1.0 DBI_1.1.0 pillar_1.4.6
## [70] haven_2.3.1 foreign_0.8-80 withr_2.3.0
## [73] abind_1.4-5 modelr_0.1.8 crayon_1.3.4
## [76] car_3.0-10 tmvnsim_1.0-2 rmarkdown_2.5
## [79] grid_4.0.3 data.table_1.13.2 blob_1.2.1
## [82] reprex_0.3.0 digest_0.6.27 xtable_1.8-4
## [85] httpuv_1.5.4 munsell_0.5.0 beeswarm_0.2.3
## [88] vipor_0.4.5
LS0tCnRpdGxlOiAnTXVsdGlzeXN0ZW0gaW5mbGFtbWF0b3J5IHN5bmRyb21lIGluIGNoaWxkcmVuIHJlbGF0ZWQgdG8gQ09WSUQtMTk6IGEgc3lzdGVtYXRpYwogIHJldmlldycKYXV0aG9yOiAiTGV2aSBIb3N0ZSwgUnViZW4gVmFuIFBhZW1lbCwgRmlsb21lZW4gSGFlcnluY2siCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWSwgJUg6JU06JVMnKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgZmlnX2NhcHRpb246IHllcwogICAgaGlnaGxpZ2h0OiBrYXRlCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgbGF0ZXhfZW5naW5lOiB4ZWxhdGV4CiAgICBwYW5kb2NfYXJnczogLS1saXN0aW5ncwogICAgaW5jbHVkZXM6CiAgICAgIGluX2hlYWRlcjogcHJlYW1ibGUudGV4CnN1YnRpdGxlOiBFeHRlbmRlZCBtZXRob2RzIGFuZCBkYXRhIGFuYWx5c2lzCi0tLQoKPHN0eWxlPgpib2R5IHsKdGV4dC1hbGlnbjoganVzdGlmeX0KPC9zdHlsZT4KCgojIEludHJvZHVjdGlvbgpJbiB0aGlzIFJNYXJrZG93biBmaWxlLCB0aGUgZXh0ZW5kZWQgbWV0aG9kcyBhbmQgZGF0YS1hbmFseXNpcyBmb3IgdGhlIG1hbnVzY3JpcHQgIk11bHRpc3lzdGVtIGluZmxhbW1hdG9yeSBzeW5kcm9tZSBpbiBjaGlsZHJlbiByZWxhdGVkIHRvIENPVklELTE5OiBhIHN5c3RlbWF0aWMgcmV2aWV3IiBpcyBkZXNjcmliZWQuIFRoZSBjb21wbGV0ZSBkYXRhLWFuYWx5c2lzIGNhbiBiZSByZXByb2R1Y2VkIGZyb20gdGhlIGRhdGEgY29sbGVjdGlvbiBzaGVldCAoaW4gLnhscyBmb3JtYXQpLCBwcm92aWRlZCBpbiB0aGUgc3VwcGxlbWVudGFyeSBmaWxlcyBvZiB0aGUgbWFudXNjcmlwdCBvciBvbiBbR2l0aHViXShodHRwczovL2dpdGh1Yi5jb20vcm12cGFlbWUvUElNU19NSVNDX1NSKS4gVGhlIHN0dWR5IHByb3RvY29sIHdhcyBwdWJsaXNoZWQgb24gdGhlIFBST1NQRVJPIHN5c3RlbWF0aWMgcmV2aWV3IHJlZ2lzdGVyLCBwcmlvciB0byBjb25kdWN0aW5nIHRoZSByZXZpZXc6IFtDUkQ0MjAyMDE4OTI0OF0oaHR0cHM6Ly93d3cuY3JkLnlvcmsuYWMudWsvcHJvc3Blcm8vZGlzcGxheV9yZWNvcmQucGhwP1JlY29yZElEPTE4OTI0OCkKCmBgYHtyIHNldHVwLCBpbmNsdWRlPVRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpCm9wdGlvbnMoZGlnaXRzID0gMykKb3B0aW9ucyh3aWR0aCA9IDYwKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKcmVxdWlyZShyZWFkeGwpCnJlcXVpcmUoaHR0cikKcmVxdWlyZShyZXNoYXBlMikKcmVxdWlyZShicm9vbSkKcmVxdWlyZShSQ29sb3JCcmV3ZXIpCnJlcXVpcmUoc2NhbGVzKQpyZXF1aXJlKGdncmVwZWwpCnJlcXVpcmUoZ3JpZEV4dHJhKQpyZXF1aXJlKGdnRXh0cmEpCmxpYnJhcnkoZ2diZWVzd2FybSkKcmVxdWlyZShnZ3B1YnIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShuYW5pYXIpCnJlcXVpcmUoRFQpCnJlcXVpcmUoem9vKQpyZXF1aXJlKHBzeWNoKQpsaWJyYXJ5KHNraW1yKQpsaWJyYXJ5KFVwU2V0UikKbGlicmFyeShzZWUpCmxpYnJhcnkod2VzYW5kZXJzb24pCmxpYnJhcnkocGFkcikKCm9wdGlvbnMoc2NpcGVuPTk5OSkKCmNvX2hiIDwtIDEyCmNvX25ldXRyb3BoaWxpYSA8LSA4MDAwCmNvX0NSUCA8LSAxMApjb19seW1waG8gPC0gMTI1MApjb19maWJyaW5vIDwtIDQwMApjb19EZGltIDwtIDI1MApjb19mZXJyaXRpbiA8LSAzMDAKY29fYWxidSA8LSAzNApjb19QQ1QgPC0gMC40OQpjb19MREggPC0gMjgwCmNvX0lMNiA8LSAxNi40CmNvX0VTUiA8LSAyMgpjb19CTlAgPC0gMTAwCmNvX05UcHJvQk5QIDwtIDQwMApjb190cm9wbyA8LSA0MApjb19XQkMgPC0gMTEwMDAKY29fcGxhdGVsZXQgPC0gMTUwMDAwCmNvX3NvZGl1bSA8LSAxMzUKI2lucHV0ID0gZGZfY29ob3J0X2NvbnRyb2xzCiNmaW5kID0gIm1heCIKI3BhcmFtID0gIkNSUCIKCmNvbGxhcHNlX2xhYnZhbHNfY29ob3J0IDwtIGZ1bmN0aW9uKGlucHV0LCBmaW5kLCBwYXJhbSwgdmVyYm9zZSA9IEZBTFNFKXsKICBpZiAoZmluZCA9PSAibWF4Iil7CiAgICBkZiA8LSBpbnB1dCAlPiUgc2VsZWN0KGNvbnRhaW5zKHBhcmFtKSB8IGNvbnRhaW5zKCJjb2hvcnRfaWQiKSB8IGNvbnRhaW5zKCJjb2hvcnRfdHlwZSIpIHwgY29udGFpbnMoInRvdF9jYXNlc19uIikpCiAgICBpZiAodmVyYm9zZSA9PSBUUlVFKXsKICAgICAgcHJpbnQoIkNvbHVtbiBleHRyYWN0ZWQgZnJvbSBjb2hvcnRzOiIpCiAgICAgIHByaW50KGNvbG5hbWVzKGRmKSkKICAgIH0KICAgIGRmX21lZCA8LSBkZiAlPiUgc2VsZWN0KGNvbnRhaW5zKCJtZWQiKSkKICAgIGRmX21lZCA8LSB0eXBlX2NvbnZlcnQoZGZfbWVkKQogICAgZGZfbWVkIDwtIGRmX21lZCAlPiUgbXV0YXRlX2FsbChmdW5zKHJlcGxhY2VfbmEoLiwgLTk5OSkpKQogICAgIyBjb2xuYW1lcyhkZl9tZWQpW21heC5jb2woZGZfbWVkLHRpZXMubWV0aG9kPSJmaXJzdCIpXQogICAgZGZfbWVkIDwtIGRmX21lZCAlPiUgbXV0YXRlKG1lZCA9IGFzLm51bWVyaWMoYXBwbHkoZGZfbWVkLCAxLCBtYXgpKSkKICAgIAogICAgZGZfbWluIDwtIGRmICU+JSBzZWxlY3QoY29udGFpbnMoIlExIikpCiAgICBkZl9taW4gPC0gdHlwZV9jb252ZXJ0KGRmX21pbikKICAgIGRmX21pbiA8LSBkZl9taW4gJT4lIG11dGF0ZV9hbGwoZnVucyhyZXBsYWNlX25hKC4sIC05OTkpKSkKICAgICNjb2xuYW1lcyhkZl9taW4pW21heC5jb2woZGZfbWluLHRpZXMubWV0aG9kPSJmaXJzdCIpXQogICAgZGZfbWluIDwtIGRmX21pbiAlPiUgbXV0YXRlKG1pbiA9IGFzLm51bWVyaWMoYXBwbHkoZGZfbWluLCAxLCBtYXgpKSkKICAgIAogICAgZGZfbWF4IDwtIGRmICU+JSBzZWxlY3QoY29udGFpbnMoIlEzIikpCiAgICBkZl9tYXggPC0gdHlwZV9jb252ZXJ0KGRmX21heCkKICAgIGRmX21heCA8LSBkZl9tYXggJT4lIG11dGF0ZV9hbGwoZnVucyhyZXBsYWNlX25hKC4sIC05OTkpKSkKICAgICNjb2xuYW1lcyhkZl9tYXgpW21heC5jb2woZGZfbWF4LHRpZXMubWV0aG9kPSJmaXJzdCIpXQogICAgZGZfbWF4IDwtIGRmX21heCAlPiUgbXV0YXRlKG1heCA9IGFzLm51bWVyaWMoYXBwbHkoZGZfbWF4LCAxLCBtYXgpKSkKICAgIAogICAgZGZfZnVsbCA8LSBjYmluZChkZiAlPiUgc2VsZWN0KGNvaG9ydF9pZCwgY29ob3J0X3R5cGUsIHRvdF9jYXNlc19uKSwgZGZfbWVkICU+JSBzZWxlY3QobWVkKSwgZGZfbWluICU+JSBzZWxlY3QobWluKSwgZGZfbWF4ICU+JSBzZWxlY3QobWF4KSkKICAgIGRmX2Z1bGxbZGZfZnVsbCA9PSAtOTk5XSA8LSBOQQogICAgbmFtZXMoZGZfZnVsbClbbmFtZXMoZGZfZnVsbCkgPT0gJ21heCddIDwtIHBhc3RlMChwYXJhbSwgIl9tYXgiKQogICAgbmFtZXMoZGZfZnVsbClbbmFtZXMoZGZfZnVsbCkgPT0gJ21pbiddIDwtIHBhc3RlMChwYXJhbSwgIl9taW4iKQogICAgbmFtZXMoZGZfZnVsbClbbmFtZXMoZGZfZnVsbCkgPT0gJ21lZCddIDwtIHBhc3RlMChwYXJhbSwgIl9tZWQiKQogICAgZGZfZnVsbCRkYXRhX2Rlc2NyIDwtICJJUVIiCiAgICBkZl9mdWxsJGNvaG9ydF9pZCA8LSBwYXN0ZTAoZGZfZnVsbCRjb2hvcnRfaWQsICIgKG4gPSAiLCBhcy5jaGFyYWN0ZXIoZGZfZnVsbCR0b3RfY2FzZXNfbiksIikiKQogICAgd3JpdGUuY3N2KGRmX2Z1bGwsIHBhc3RlMCgiLi9kYXRhL2NvaG9ydF8iLCBwYXJhbSwgIi5jc3YiKSkKICAgIHByaW50KGRhdGF0YWJsZShkZl9mdWxsLCBjYXB0aW9uID0gcGFzdGUwKCJvdmVydmlldyBvZiAiLCBwYXJhbSkpKQogICAgcmV0dXJuKGRmX2Z1bGwpCiAgfQogIGVsc2UgaWYgKGZpbmQgPT0gIm1pbiIpewogICAgZGYgPC0gaW5wdXQgJT4lIHNlbGVjdChjb250YWlucyhwYXJhbSkgfCBjb250YWlucygiY29ob3J0X2lkIikgfCBjb250YWlucygiY29ob3J0X3R5cGUiKSB8IGNvbnRhaW5zKCJ0b3RfY2FzZXNfbiIpKQogICAgaWYgKHZlcmJvc2UgPT0gVFJVRSl7CiAgICAgIHByaW50KCJDb2x1bW4gZXh0cmFjdGVkIGZyb20gY29ob3J0czoiKQogICAgICBwcmludChjb2xuYW1lcyhkZikpCiAgICB9CiAgICBkZl9tZWQgPC0gZGYgJT4lIHNlbGVjdChjb250YWlucygibWVkIikpCiAgICBkZl9tZWQgPC0gdHlwZV9jb252ZXJ0KGRmX21lZCkKICAgIGRmX21lZCA8LSBkZl9tZWQgJT4lIG11dGF0ZV9hbGwoZnVucyhyZXBsYWNlX25hKC4sIDFlNikpKQogICAgIyBjb2xuYW1lcyhkZl9tZWQpW21heC5jb2woZGZfbWVkLHRpZXMubWV0aG9kPSJmaXJzdCIpXQogICAgZGZfbWVkIDwtIGRmX21lZCAlPiUgbXV0YXRlKG1lZCA9IGFzLm51bWVyaWMoYXBwbHkoZGZfbWVkLCAxLCBtaW4pKSkKICAgIAogICAgZGZfbWluIDwtIGRmICU+JSBzZWxlY3QoY29udGFpbnMoIlExIikpCiAgICBkZl9taW4gPC0gdHlwZV9jb252ZXJ0KGRmX21pbikKICAgIGRmX21pbiA8LSBkZl9taW4gJT4lIG11dGF0ZV9hbGwoZnVucyhyZXBsYWNlX25hKC4sIDFlNikpKQogICAgI2NvbG5hbWVzKGRmX21pbilbbWF4LmNvbChkZl9taW4sdGllcy5tZXRob2Q9ImZpcnN0IildCiAgICBkZl9taW4gPC0gZGZfbWluICU+JSBtdXRhdGUobWluID0gYXMubnVtZXJpYyhhcHBseShkZl9taW4sIDEsIG1pbikpKQogICAgCiAgICBkZl9tYXggPC0gZGYgJT4lIHNlbGVjdChjb250YWlucygiUTMiKSkKICAgIGRmX21heCA8LSB0eXBlX2NvbnZlcnQoZGZfbWF4KQogICAgZGZfbWF4IDwtIGRmX21heCAlPiUgbXV0YXRlX2FsbChmdW5zKHJlcGxhY2VfbmEoLiwgMWU2KSkpCiAgICAjY29sbmFtZXMoZGZfbWF4KVttYXguY29sKGRmX21heCx0aWVzLm1ldGhvZD0iZmlyc3QiKV0KICAgIGRmX21heCA8LSBkZl9tYXggJT4lIG11dGF0ZShtYXggPSBhcy5udW1lcmljKGFwcGx5KGRmX21heCwgMSwgbWluKSkpCiAgICAKICAgIGRmX2Z1bGwgPC0gY2JpbmQoZGYgJT4lIHNlbGVjdChjb2hvcnRfaWQsIGNvaG9ydF90eXBlLCB0b3RfY2FzZXNfbiksIGRmX21lZCAlPiUgc2VsZWN0KG1lZCksIGRmX21pbiAlPiUgc2VsZWN0KG1pbiksIGRmX21heCAlPiUgc2VsZWN0KG1heCkpCiAgICBkZl9mdWxsW2RmX2Z1bGwgPT0gMWU2XSA8LSBOQQogICAgbmFtZXMoZGZfZnVsbClbbmFtZXMoZGZfZnVsbCkgPT0gJ21heCddIDwtIHBhc3RlMChwYXJhbSwgIl9tYXgiKQogICAgbmFtZXMoZGZfZnVsbClbbmFtZXMoZGZfZnVsbCkgPT0gJ21pbiddIDwtIHBhc3RlMChwYXJhbSwgIl9taW4iKQogICAgbmFtZXMoZGZfZnVsbClbbmFtZXMoZGZfZnVsbCkgPT0gJ21lZCddIDwtIHBhc3RlMChwYXJhbSwgIl9tZWQiKQogICAgZGZfZnVsbCRkYXRhX2Rlc2NyIDwtICJJUVIiCiAgICBkZl9mdWxsJGNvaG9ydF9pZCA8LSBwYXN0ZTAoZGZfZnVsbCRjb2hvcnRfaWQsICIgKG4gPSAiLCBhcy5jaGFyYWN0ZXIoZGZfZnVsbCR0b3RfY2FzZXNfbiksIikiKQogICAgd3JpdGUuY3N2KGRmX2Z1bGwsIHBhc3RlMCgiLi9kYXRhL2NvaG9ydF8iLCBwYXJhbSwgIi5jc3YiKSkKICAgIHByaW50KGRhdGF0YWJsZShkZl9mdWxsLCBjYXB0aW9uID0gcGFzdGUwKCJvdmVydmlldyBvZiAiLCBwYXJhbSkpKQogICAgcmV0dXJuKGRmX2Z1bGwpCiAgfQp9CgojaW5wdXQgPSBkZl9zaW5nbGVjYXNlcwojZmluZCA9ICJtYXgiCiNwYXJhbSA9ICJDUlAiCgpjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZSA8LSBmdW5jdGlvbihpbnB1dCwgZmluZCwgcGFyYW0sIHZlcmJvc2UgPSBGQUxTRSl7CiAgaWYgKGZpbmQgPT0gIm1heCIpewogICAgZGYgPC0gaW5wdXQgJT4lIHNlbGVjdChjb250YWlucyhwYXJhbSkgfCBjb250YWlucygiY29ob3J0X2lkIikpCiAgICBpZiAodmVyYm9zZSA9PSBUUlVFKXsKICAgICAgcHJpbnQoIkNvbHVtbiBleHRyYWN0ZWQgZnJvbSBzaW5nbGUgY2FzZXM6IikKICAgICAgcHJpbnQoY29sbmFtZXMoZGYpKQogICAgfQogICAgZGZfY29sbCA8LSBkZiAlPiUgbXV0YXRlX2FsbChmdW5zKHJlcGxhY2VfbmEoLiwgLTk5OSkpKQogICAgZGZfY29sbCA8LSB0eXBlX2NvbnZlcnQoZGZfY29sbCkKICAgICMgY29sbmFtZXMoZGZfbWVkKVttYXguY29sKGRmX21lZCx0aWVzLm1ldGhvZD0iZmlyc3QiKV0KICAgIGRmX2NvbGwgPC0gZGZfY29sbCAlPiUgbXV0YXRlKG1heCA9IGFzLm51bWVyaWMoYXBwbHkoZGZfY29sbCwgMSwgbWF4KSkpCiAgICAKICAgIGRmX2NvbGxbZGZfY29sbCA9PSAtOTk5XSA8LSBOQQogICAgbmFtZXMoZGZfY29sbClbbmFtZXMoZGZfY29sbCkgPT0gJ21heCddIDwtIHBhc3RlMChwYXJhbSwgIl9tYXgiKQogICAgZGZfY29sbCRkYXRhX2Rlc2NyIDwtICJJUVIiCiAgICBkZl9jb2xsJGNvaG9ydF9pZCA8LSBwYXN0ZTAoInNpbmdsZSBjYXNlcyAobiA9ICIsIGFzLmNoYXJhY3RlcihuX3NpbmdsZV9jYXNlcyksIikiKQogICAgd3JpdGUuY3N2KHNraW0oZGZfY29sbCksIHBhc3RlMCgiLi9kYXRhL3NpbmdsZWNhc2VzXyIsIHBhcmFtLCAiLmNzdiIpKQogICAgcmV0dXJuKGRmX2NvbGwpCiAgfQogIGVsc2UgaWYgKGZpbmQgPT0gIm1pbiIpewogICAgZGYgPC0gaW5wdXQgJT4lIHNlbGVjdChjb250YWlucyhwYXJhbSkgfCBjb250YWlucygiY29ob3J0X2lkIikpCiAgICBpZiAodmVyYm9zZSA9PSBUUlVFKXsKICAgICAgcHJpbnQoIkNvbHVtbiBleHRyYWN0ZWQgZnJvbSBzaW5nbGUgY2FzZXM6IikKICAgICAgcHJpbnQoY29sbmFtZXMoZGYpKQogICAgfQogICAgZGZfY29sbCA8LSBkZiAlPiUgbXV0YXRlX2FsbChmdW5zKHJlcGxhY2VfbmEoLiwgMWU2KSkpCiAgICAjIGNvbG5hbWVzKGRmX21lZClbbWF4LmNvbChkZl9tZWQsdGllcy5tZXRob2Q9ImZpcnN0IildCiAgICBkZl9jb2xsIDwtIGRmX2NvbGwgJT4lIG11dGF0ZShtaW4gPSBhcy5udW1lcmljKGFwcGx5KGRmX2NvbGwsIDEsIG1pbikpKQogICAgCiAgICBkZl9jb2xsW2RmX2NvbGwgPT0gMWU2XSA8LSBOQQogICAgbmFtZXMoZGZfY29sbClbbmFtZXMoZGZfY29sbCkgPT0gJ21pbiddIDwtIHBhc3RlMChwYXJhbSwgIl9taW4iKQogICAgZGZfY29sbCRjb2hvcnRfaWQgPC0gcGFzdGUwKCJzaW5nbGUgY2FzZXMgKG4gPSAiLCBhcy5jaGFyYWN0ZXIobl9zaW5nbGVfY2FzZXMpLCIpIikKICAgIHdyaXRlLmNzdihza2ltKGRmX2NvbGwpLCBwYXN0ZTAoIi4vZGF0YS9zaW5nbGVjYXNlc18iLCBwYXJhbSwgIi5jc3YiKSkKICAgIHJldHVybihkZl9jb2xsKQogIH0KfQoKCm1vdmVtZSA8LSBmdW5jdGlvbiAoZGYsIG1vdmVjb21tYW5kKSB7CiAgaW52ZWMgPC0gbmFtZXMoZGYpCiAgCiAgbW92ZWNvbW1hbmQgPC0gbGFwcGx5KHN0cnNwbGl0KHN0cnNwbGl0KG1vdmVjb21tYW5kLCAiOyIpW1sxXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiLHxcXHMrIiksIGZ1bmN0aW9uKHgpIHhbeCAhPSAiIl0pCiAgbW92ZWxpc3QgPC0gbGFwcGx5KG1vdmVjb21tYW5kLCBmdW5jdGlvbih4KSB7CiAgICBXaGVyZSA8LSB4W3doaWNoKHggJWluJSBjKCJiZWZvcmUiLCAiYWZ0ZXIiLCAiZmlyc3QiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxhc3QiKSk6bGVuZ3RoKHgpXQogICAgVG9Nb3ZlIDwtIHNldGRpZmYoeCwgV2hlcmUpCiAgICBsaXN0KFRvTW92ZSwgV2hlcmUpCiAgfSkKICBteVZlYyA8LSBpbnZlYwogIGZvciAoaSBpbiBzZXFfYWxvbmcobW92ZWxpc3QpKSB7CiAgICB0ZW1wIDwtIHNldGRpZmYobXlWZWMsIG1vdmVsaXN0W1tpXV1bWzFdXSkKICAgIEEgPC0gbW92ZWxpc3RbW2ldXVtbMl1dWzFdCiAgICBpZiAoQSAlaW4lIGMoImJlZm9yZSIsICJhZnRlciIpKSB7CiAgICAgIGJhIDwtIG1vdmVsaXN0W1tpXV1bWzJdXVsyXQogICAgICBpZiAoQSA9PSAiYmVmb3JlIikgewogICAgICAgIGFmdGVyIDwtIG1hdGNoKGJhLCB0ZW1wKSAtIDEKICAgICAgfQogICAgICBlbHNlIGlmIChBID09ICJhZnRlciIpIHsKICAgICAgICBhZnRlciA8LSBtYXRjaChiYSwgdGVtcCkKICAgICAgfQogICAgfQogICAgZWxzZSBpZiAoQSA9PSAiZmlyc3QiKSB7CiAgICAgIGFmdGVyIDwtIDAKICAgIH0KICAgIGVsc2UgaWYgKEEgPT0gImxhc3QiKSB7CiAgICAgIGFmdGVyIDwtIGxlbmd0aChteVZlYykKICAgIH0KICAgIG15VmVjIDwtIGFwcGVuZCh0ZW1wLCB2YWx1ZXMgPSBtb3ZlbGlzdFtbaV1dW1sxXV0sIGFmdGVyID0gYWZ0ZXIpCiAgfQogIAogIGRmWyxtYXRjaChteVZlYywgbmFtZXMoZGYpKV0KfQoKbWFrZUJhcnBsb3QgPC0gZnVuY3Rpb24odmFyX2lkX2NvaG9ydCwgdmFyX2lkX3NpbmdsZSwgdmFyX2lkKXsKICAKICBuX2NvaG9ydCA8LSBkZl9jb2hvcnQgJT4lIHNlbGVjdCh0b3RfY2FzZXNfbikgJT4lIHN1bSgpIywgb3V0Y29tZV9kZWF0aF9uKQogIHZhcl9jb2hvcnQgPC0gZGZfY29ob3J0W3Zhcl9pZF9jb2hvcnRdICU+JSBzdW0oLiwgbmEucm0gPSBUUlVFKSMsIG91dGNvbWVfZGVhdGhfbikKICAKICBuX3NpbmdsZSA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbnJvdygpCiAgCiAgdmFyX3NpbmdsZSA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgZmlsdGVyKGdldCh2YXJfaWRfc2luZ2xlKSA9PSBUUlVFKSAlPiUgbnJvdygpCiAgCiAgbl9hbGwgPC0gbl9jb2hvcnQgKyBuX3NpbmdsZQogIHZhcl9hbGwgPC0gdmFyX2NvaG9ydCArIHZhcl9zaW5nbGUKICAKICBiYXJfZGZfYWJzIDwtIGRhdGEuZnJhbWUoeCA9IGMoImNvaG9ydCIsICJjb2hvcnQiLCAic2luZ2xlIGNhc2VzIiwgInNpbmdsZSBjYXNlcyIsICJhbGwiLCAiYWxsIiksIGNvbCA9IGMoInRvdGFsIiwgdmFyX2lkLCAidG90YWwiLCB2YXJfaWQsICJ0b3RhbCIsIHZhcl9pZCksIHZhbHMgPSBjKG5fY29ob3J0LCB2YXJfY29ob3J0LCBuX3NpbmdsZSwgdmFyX3NpbmdsZSwgbl9hbGwsIHZhcl9hbGwpICkKICAKICBiYXJfZGZfcHJjdCA8LSBkYXRhLmZyYW1lKHggPSBjKCJjb2hvcnQiLCAiY29ob3J0IiwgInNpbmdsZSBjYXNlcyIsICJzaW5nbGUgY2FzZXMiLCAiYWxsIiwgImFsbCIpLCBjb2wgPSBjKHBhc3RlMCh2YXJfaWQsICIgLSIpLCBwYXN0ZTAodmFyX2lkLCAiICsiKSwgcGFzdGUwKHZhcl9pZCwgIiAtIiksIHBhc3RlMCh2YXJfaWQsICIgKyIpLCBwYXN0ZTAodmFyX2lkLCAiIC0iKSwgcGFzdGUwKHZhcl9pZCwgIiArIikpLCB2YWxzID0gYygxMDAtKHZhcl9jb2hvcnQvbl9jb2hvcnQqMTAwKSwgdmFyX2NvaG9ydC9uX2NvaG9ydCoxMDAsIDEwMC0odmFyX3NpbmdsZS9uX3NpbmdsZSoxMDApLCB2YXJfc2luZ2xlL25fc2luZ2xlKjEwMCwgMTAwLSh2YXJfYWxsL25fYWxsKjEwMCksIHZhcl9hbGwvbl9hbGwqMTAwKSApCiAgCiAgCiAgcF9hYnMgPC0gZ2dwbG90KGJhcl9kZl9hYnMsIGFlcyh4ID0geCwgeSA9ICB2YWxzLCBmaWxsID0gY29sKSkgKwogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogICAgdGhlbWVfYncoKSArIAogICAgbGFicyh0aXRsZSA9IHBhc3RlMCgiVG90YWwgY2FzZXMgdnMgIiwgdmFyX2lkKSwgc3VidGl0bGUgPSAiQWJzb2x1dGUgbnVtYmVycyIsIHggPSAiZ3JvdXAiLCB5ID0gIm4iLCBjb2wgPSAiIikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpKSArCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCiAgCiAgCiAgcF9wcmN0IDwtIGdncGxvdChiYXJfZGZfcHJjdCwgYWVzKHggPSB4LCB5ID0gIHZhbHMsIGZpbGwgPSBjb2wpKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZmlsbCIpICsKICAgIHRoZW1lX2J3KCkgKyAKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAodmFyX2lkKSwgc3VidGl0bGUgPSAiUGVyY2VudCIsIHggPSAiZ3JvdXAiLCB5ID0gIiUiLCBjb2wgPSAiIikgICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpKSArCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCiAgCiAgZ2dhcnJhbmdlKHBfYWJzLCBwX3ByY3QsIGxlZ2VuZCA9ICJib3R0b20iKQogIAp9CgptYWtlSGVhdG1hcF9jb2hvcnQgPC0gZnVuY3Rpb24ocGFyYW0xLCBjb2xuYW1lX3NpbmdsZSwgZXhjbHVkZV9zaW5nbGUgPSBOVUxMLCBwbG90dGl0bGUsIHRleHRzaXplID0gMyl7CiAgdmFyX2NvaG9ydCA8LSBkZl9jb2hvcnQgJT4lIHNlbGVjdCgoImNvaG9ydF9pZCIpIHwgInRvdF9jYXNlc19uIiB8ICggY29udGFpbnMocGFyYW0xKSAmIGNvbnRhaW5zKCJfbiIpKSkKICB2YXJfY29ob3J0JGNvaG9ydF9pZCA8LSBwYXN0ZTAodmFyX2NvaG9ydCRjb2hvcnRfaWQsICIgKG4gPSAiLCBhcy5jaGFyYWN0ZXIodmFyX2NvaG9ydCR0b3RfY2FzZXNfbiksIikiKQogIHZhcl9jb2hvcnQgPC0gdmFyX2NvaG9ydCAlPiUgCiAgICBnYXRoZXIodmFyaWFibGUsIHZhbHVlLCAzOm5jb2wodmFyX2NvaG9ydCkpICU+JSBncm91cF9ieShjb2hvcnRfaWQsIHZhcmlhYmxlKSAlPiUgc3VtbWFyaXplKHByY3QgPSB2YWx1ZS90b3RfY2FzZXNfbioxMDApCiAgdmFyX2NvaG9ydCR2YXJpYWJsZSA8LSBzdWIoIl9uIiwgIiIsIHZhcl9jb2hvcnQkdmFyaWFibGUpCiAgCiAgaWYgKCFpcy5udWxsKGV4Y2x1ZGVfc2luZ2xlKSl7CiAgICB2YXJfc2luZ2xlIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QoLWNvbnRhaW5zKGV4Y2x1ZGVfc2luZ2xlKSkKICAgIHZhcl9zaW5nbGUgPC0gdmFyX3NpbmdsZSAlPiUgc2VsZWN0KGNvbnRhaW5zKGNvbG5hbWVfc2luZ2xlKSkKICB9IGVsc2UKICB7CiAgICB2YXJfc2luZ2xlIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QoY29udGFpbnMoY29sbmFtZV9zaW5nbGUpKQogIH0KICAKICAjJT4lIHNlbGVjdCgtY29udGFpbnMoImFueSIpKQogIGNvbHMgPC0gc2FwcGx5KHZhcl9zaW5nbGUsIGlzLmxvZ2ljYWwpCiAgdmFyX3NpbmdsZVssY29sc10gPC0gbGFwcGx5KHZhcl9zaW5nbGVbLGNvbHNdLCBhcy5udW1lcmljKQogIHZhcl9zaW5nbGUgPC0gY29sU3Vtcyh2YXJfc2luZ2xlLCBuYS5ybSA9IFRSVUUpCiAgdmFyX3NpbmdsZSA8LSB2YXJfc2luZ2xlL25yb3coZGZfc2luZ2xlY2FzZXMpKjEwMAogIHZhcl9zaW5nbGUgPC0gYXMuZGF0YS5mcmFtZSh2YXJfc2luZ2xlKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkKICB2YXJfc2luZ2xlJGNvaG9ydF9pZCA8LSBwYXN0ZTAoInNpbmdsZSBjYXNlcyAobiA9ICIsIG5fc2luZ2xlX2Nhc2VzLCIpIikKICBjb2xuYW1lcyh2YXJfc2luZ2xlKSA8LSBjKCJ2YXJpYWJsZSIsICJwcmN0IiwgImNvaG9ydF9pZCIpCiAgCiAgCiAgbWlzc2luZyA8LSBzZXRkaWZmKHZhcl9zaW5nbGUkdmFyaWFibGUsIHZhcl9jb2hvcnQkdmFyaWFibGUpCiAgaWYgKGxlbmd0aChtaXNzaW5nKSAhPSAwICl7CiAgICBtaXNzaW5nX2RmIDwtIGRhdGEuZnJhbWUodmFyaWFibGUgPSBtaXNzaW5nLCBwcmN0ID0gTkEsIGNvaG9ydF9pZCA9IHVuaXF1ZSh2YXJfY29ob3J0JGNvaG9ydF9pZCkpCiAgICB2YXJfY29ob3J0IDwtIGJpbmRfcm93cyh2YXJfY29ob3J0LCBhc190aWJibGUobWlzc2luZ19kZikpCiAgfSBlbHNlIGlmIChsZW5ndGgobWlzc2luZykgPT0gMCkgewogICAgbWlzc2luZyA8LSBzZXRkaWZmKHZhcl9jb2hvcnQkdmFyaWFibGUsIHZhcl9zaW5nbGUkdmFyaWFibGUpCiAgICBpZiAobGVuZ3RoKG1pc3NpbmcpICE9IDApewogICAgICBtaXNzaW5nX2RmIDwtIGRhdGEuZnJhbWUodmFyaWFibGUgPSBtaXNzaW5nLCBwcmN0ID0gTkEsIGNvaG9ydF9pZCA9IHVuaXF1ZSh2YXJfc2luZ2xlJGNvaG9ydF9pZCkpCiAgICAgIHZhcl9zaW5nbGUgPC0gYmluZF9yb3dzKHZhcl9zaW5nbGUsIGFzX3RpYmJsZShtaXNzaW5nX2RmKSkKICAgIH0KICB9CiAgCiAgaG1fY29ob3J0IDwtIGdncGxvdCh2YXJfY29ob3J0LCBhZXMoeCA9IHZhcmlhYmxlLCB5ID0gY29ob3J0X2lkLCBmaWxsID0gcHJjdCkpICsgCiAgICBnZW9tX3RpbGUoKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAieWVsbG93IiwgaGlnaD0icmVkIiwgbmEudmFsdWUgPSAibGlnaHRncmF5IiwgbGltaXRzID0gYygwLDEwMCkpICsKICAgIGxhYnMoeCA9ICIiLCB5ID0gImNvaG9ydCIsIHRpdGxlID1wbG90dGl0bGUpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWw9cm91bmQocHJjdCwgMikpLCBzaXplID0gdGV4dHNpemUsIGNvbG9yID0gImJsYWNrIikKICAKICBobV9zaW5nbGUgPC0gZ2dwbG90KHZhcl9zaW5nbGUsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBjb2hvcnRfaWQsIGZpbGwgPSBwcmN0KSkgKyAKICAgIGdlb21fdGlsZSgpICsgIHRoZW1lX2NsYXNzaWMoKSArCiAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpLCBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInllbGxvdyIsIGhpZ2ggPSAicmVkIiwgbmEudmFsdWUgPSAibGlnaHRncmF5IiwgbGltaXRzID0gYygwLDEwMCkpKyBsYWJzKHkgPSAiY29ob3J0IikgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1yb3VuZChwcmN0LCAyKSksIHNpemUgPSB0ZXh0c2l6ZSwgY29sb3IgPSAiYmxhY2siKSAKICAKICBwbG90X2dyaWQoaG1fY29ob3J0LCBobV9zaW5nbGUsIGFsaWduID0gInYiLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDIvMywgMS8zKSkKfQpgYGAKCiMgU2VhcmNoIHN0cmF0ZWd5CgpFbGVjdHJvbmljIGJpYmxpb2dyYXBoaWNhbCBkYXRhYmFzZXMgd2VyZSBzZWFyY2hlZCwgYm90aCBpbmRleGVkIChQdWJNZWQsIEVtYmFzZSkgYW5kIHByZXByaW50IHJlcG9zaXRvcmllcyAoQmlvUnhpdiBhbmQgTWVkUnhpdikuIEFkZGl0aW9uYWxseSwgQ09WSUQtMTktc3BlY2lmaWMgcmVzZWFyY2ggcmVwb3NpdG9yaWVzIHdlcmUgYmUgc2VhcmNoZWQgKENvY2hyYW5lIENPVklE4oCQMTkgU3R1ZHkgUmVnaXN0ZXIsIHRoZSBXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uIChXSE8pIENPVklE4oCQMTkgR2xvYmFsIFJlc2VhcmNoIERhdGFiYXNlKS4gUHVibGljYXRpb25zIGluIEVuZ2xpc2ggbGFuZ3VhZ2UgYmV0d2VlbiAzMSBEZWNlbWJlciAyMDE5IHVwIHRvIDMwIEp1bmUgMjAyMCwgd2hlbiB0aGUgZmluYWwgc2VhcmNoIHdhcyBjYXJyaWVkIG91dCwgd2VyZSByZXZpZXdlZCBvbiBlbGlnaWJpbGl0eS4gQm90aCBmaW5pc2hlZCBhbmQgb25nb2luZyBzdHVkaWVzIHdlcmUgY29uc2lkZXJlZC4gVGhlIHJlZmVyZW5jZSBsaXN0cyBvZiB0aGUgaW5jbHVkZWQgc3R1ZGllcyB3ZXJlIGNvbnNpZGVyZWQgYXMgYW4gYWRkaXRpb25hbCBzb3VyY2UuIAoKU2VhcmNoIHN0cmF0ZWd5IGZvY3VzZWQgb24ga2V5d29yZHMgaW52b2x2aW5nIHRoZSBoeXBlcmluZmxhbW1hdG9yeSBwcmVzZW50YXRpb24gKFBJTVMtVFMsIE1JUy1DLCBoeXBlcmluZmxhbW1hdGlvbiwgSExILCB0b3hpYyBzaG9jayBzeW5kcm9tZSwgdmFzY3VsaXRpcywgS2F3YXNha2kgZGlzZWFzZSksIGFzIHdlbGwgYXMgdGhlIGFzc29jaWF0aW9uIHdpdGggQ09WSUQtMTkgKFNBUlMtQ29WLTIsIENPVklELTE5LCBub3ZlbCBjb3JvbmF2aXJ1cykgYW5kIHRoZSBwZWRpYXRyaWMgcG9wdWxhdGlvbiAoY2hpbGRyZW4sIGFkb2xlc2NlbnQsIHBlZGlhdHJpYykuIFN0cnVjdHVyZWQgaGllcmFyY2hpYyBrZXl3b3JkcyAoTWVTSCwgRW10cmVlKSBhbmQgd2lsZGNhcmRzIHdlcmUgdXNlZCB3aGVuIGFwcGxpY2FibGUuIEJvb2xlYW4gb3BlcmF0b3JzIHdlcmUgdXNlZCB0byBjb21iaW5lIHRoZSB2YXJpb3VzIGtleXdvcmRzIG9mIGludGVyZXN0LiBCZWxvdywgdGhlIGZ1bGwgc2VhcmNoIHRlcm1zIGFyZSBwcmVzZW50ZWQgZm9yIHRoZSBkaWZmZXJlbnQgZGF0YWJhc2VzKS4gCgojIyBQdWJNZWQgCgpgYGAKKOKAnFBJTVMq4oCdIE9SIOKAnE1JUyrigJ3igK9PUiDigJxtdWx0aXN5c3RlbeKAr2luZmxhbW1hdCrigJ3igK9PUiDigJxoeXBlcmluZmxhbW1hdCrigJ0gT1Ig4oCcaW5mbGFtbWF0b3J5IGRpc2Vhc2XigJ0gT1Ig4oCcc3lzdGVtaWPigK9pbmZsYW1tYXQq4oCd4oCvT1Ig4oCcY3l0b2tpbmUgcmVsZWFzZeKAnSBPUiDigJxLYXdhc2FraSrigJ0gT1Ig4oCcdmFzY3VsaXRpc+KAnSBPUiDigJx0b3hpYyBzaG9ja+KAneKAr09SIOKAnHNob2Nr4oCdIE9SICgicGVkaWF0cmlj4oCvbXVsdGlzeXN0ZW0gaW5mbGFtbWF0b3J5IGRpc2Vhc2UsIENPVklELTE5IHJlbGF0ZWQiIFtTdXBwbGVtZW50YXJ5IENvbmNlcHRdKSBPUiAiTXVjb2N1dGFuZW91c+KAr0x5bXBoIE5vZGUgU3luZHJvbWUiW01lc2hdIE9SICJTaG9jayJbTWVzaF0gT1IgIlZhc2N1bGl0aXMiW01lc2hdIE9SIOKAnGluZmxhbW1hdGlvbuKAnVtNZVNIXSnigK9BTkTigK8o4oCcY292aWQq4oCdIG9yIOKAnHNhcnMtY292LTLigJ0gb3Ig4oCcMjAxOS1uQ2924oCdIG9yIOKAnG5vdmVsIGNvcm9uYXZpcnVz4oCdIG9yIOKAnGNvcm9uYXZpcnVzIGRpc2Vhc2XigJ0gb3LigK8iQ09WSUQtMTkiIFtTdXBwbGVtZW50YXJ5IENvbmNlcHRdIE9S4oCvInNldmVyZSBhY3V0ZSByZXNwaXJhdG9yeSBzeW5kcm9tZSBjb3JvbmF2aXJ1cyAyIiBbU3VwcGxlbWVudGFyeSBDb25jZXB0XSkgQU5E4oCvKOKAnGNoaWxkKuKAnSBvciDigJxhZG9sZXNjZW4q4oCdIG9yIOKAnHRlZW4q4oCdIG9yIOKAnHBlZGlhdHJpYyrigJ0gb3Ig4oCcaW5mYW504oCdIG9yIOKAnG5ld2Jvcm7igJ0gb3LigK8iQ2hpbGQiW01lc2hd4oCvT1LigK8iQWRvbGVzY2VudCJbTWVzaF0gT1LigK8iUGVkaWF0cmljcyJbTWVzaF3igK9vciAiSW5mYW50LOKAr05ld2Jvcm4iW01lc2hd4oCvb3LigK8iSW5mYW50IltNZXNoXSkgQU5EICgiMjAxOS8xMi8zMSJbRGF0ZSAtIFB1YmxpY2F0aW9uXSA6ICIzMDAwIltEYXRlIC0gUHVibGljYXRpb25dKeKAryAKYGBgCgojIyBFbWJhc2UgIAoKYGBgCigncGltcyonIE9SICdtaXMn4oCvT1Ig4oCYbWlzLWPigJnigK9PUiAnbXVsdGlzeXN0ZW3igK9pbmZsYW1tYXQqJyBPUiAnaHlwZXJpbmZsYW1tYXQqJyBPUiAnaW5mbGFtbWF0b3J5IGRpc2Vhc2UnIE9SICdzeXN0ZW1pY+KAr2luZmxhbW1hdConIE9SICdjeXRva2luZSByZWxlYXNlJyBPUiAna2F3YXNha2kqJyBPUiAndmFzY3VsaXRpcycgT1IgJ3RveGljIHNob2NrJyBPUiAnc2hvY2snKSBBTkQgKCdjb3ZpZConIE9SICdzYXJzLWNvdi0yJyBPUiAnMjAxOS1uY292JyBPUiAnbm92ZWwgY29yb25hdmlydXMnIE9SICdjb3JvbmF2aXJ1cyBkaXNlYXNlJykgQU5EICgnY2hpbGQqJyBPUiAnYWRvbGVzY2VuKicgT1IgJ3RlZW4qJyBPUiAncGVkaWF0cmljKicgT1IgJ2luZmFudCcgT1IgJ25ld2Jvcm4nKSBBTkQgWzMxLTEyLTIwMTldL3Nk4oCvIApgYGAKCiMjIEJpb1J4aXYgYW5kIE1lZFJ4aXYgCkxpdGVyYXR1cmUgc2VhcmNoIGluIGJpb3J4aXYgYW5kIG1lZHJ4aXYgd2FzIGRvbmUgd2l0aCB0aGUgUiBieSBkb3dubG9hZGluZyB0aGUgZGF0YSBmcm9tIHRoZSBkZWRpY2F0ZWQgW0NPVklELTE5IFNBUlMtQ29WLTIgcHJlcHJpbnRzIHBhZ2VdKGh0dHBzOi8vY29ubmVjdC5iaW9yeGl2Lm9yZy9yZWxhdGUvY29udGVudC8xODEpIGluIGpzb24gZm9ybWF0LCBhbmQgY2FuIGJlIGZvdW5kIG9uIFtHaXRodWJdKGh0dHBzOi8vZ2l0aHViLmNvbS9ybXZwYWVtZS9QSU1TX01JU0NfU1IvYmxvYi9tYXN0ZXIvcHJlcHJpbnRfc2VhcmNoLlIpLgoKCiMjIENvY2hyYW5lIENPVklELTE5IHN0dWR5IHJlZ2lzdGVyIAoKYGBgCihwaW1zKiBPUiBtaXMgT1IgIm1pcy1jIiBPUiAibXVsdGlzeXN0ZW0gaW5mbGFtbWF0KiIgT1IgaHlwZXJpbmZsYW1tYXQqIE9SICJpbmZsYW1tYXRvcnkgZGlzZWFzZSIgT1IgInN5c3RlbWljIGluZmxhbW1hdCoiIE9SICJjeXRva2luZSByZWxlYXNlIiBPUiBrYXdhc2FraSogT1IgdmFzY3VsaXRpcyBPUiAidG94aWMgc2hvY2siIE9SIHNob2NrKSBBTkQgKGNoaWxkKiBPUiBhZG9sZXNjZW4qIE9SIHRlZW4qIE9SIHBlZGlhdHJpYyogT1IgaW5mYW50IE9SIG5ld2Jvcm4pIApgYGAKCiMjIFdITyBDT1ZJRC0xOSBHbG9iYWwgbGl0ZXJhdHVyZSBvbiBjb3JvbmF2aXJ1cyBkaXNlYXNlIAoKYGBgCigicGltcyoiIE9SICJtaXMiIE9SICJtaXMtYyIgT1IgIm11bHRpc3lzdGVt4oCvaW5mbGFtbWF0KiIgT1IgImh5cGVyaW5mbGFtbWF0KiIgT1IgImluZmxhbW1hdG9yeSBkaXNlYXNlIiBPUiAic3lzdGVtaWPigK9pbmZsYW1tYXQqIiBPUiAiY3l0b2tpbmUgcmVsZWFzZSIgT1IgImthd2FzYWtpKiIgT1IgInZhc2N1bGl0aXMiIE9SICJ0b3hpYyBzaG9jayIgT1IgInNob2NrIikgQU5EICgiY2hpbGQqIiBPUiAiYWRvbGVzY2VuKiIgT1IgInRlZW4qIiBPUiAicGVkaWF0cmljKiIgT1IgImluZmFudCIgT1IgIm5ld2Jvcm4iKSAKYGBgCgojIFN0dWR5IHNlbGVjdGlvbiBhbmQgcmlzayBvZiBiaWFzIGFzc2Vzc21lbnQKT3JpZ2luYWwgc3R1ZGllcyB3ZXJlIGluY2x1ZGVkIHdpdGggZm9sbG93aW5nIGRlc2lnbnM6IFJDVCwgb2JzZXJ2YXRpb25hbCBzdHVkaWVzLCBjYXNlLWNvbnRyb2wgc3R1ZGllcywgY3Jvc3Mtc2VjdGlvbmFsIHN0dWRpZXMsIGNhc2UgcmVwb3J0cyBhbmQgY2FzZSBzZXJpZXMuIAoKUmVjb3JkcyBlbGlnaWJsZSBmb3IgaW5jbHVzaW9uIHNob3VsZCBwcmVzZW50IGNsaW5pY2FsIGNhc2VzIGZ1bGZpbGxpbmcgdGhlIGZvbGxvd2luZyAzIGNyaXRlcmlhOiAKCkluY2x1c2lvbiBjcml0ZXJpYQoKMS4JU3R1ZHkgcG9wdWxhdGlvbjogaHlwZXJpbmZsYW1tYXRvcnkgc3luZHJvbWUgbWVldGluZyB0aGUgY2FzZSBkZWZpbml0aW9ucyBvZiBQSU1TLVRTIG9yIE1JUygtQykgaW4gY2hpbGRyZW4gKDAtMTkgeWVhcnMgb2YgYWdlKSB3aXRoIGEgdGVtcG9yYWwgYXNzb2NpYXRpb24gd2l0aCBjb25maXJtZWQgb3IgcHJvYmFibGUgQ09WSUQtMTkKMi4JT3V0Y29tZTogY2xpbmljYWwsIGVwaWRlbWlvbG9naWNhbCBhbmQgaW1tdW5vbG9naWNhbCBkZXNjcmlwdGlvbnMsIHRoZXJhcGV1dGljIG1hbmFnZW1lbnQgYW5kIGNsaW5pY2FsIGVmZmVjdCwgYW5kIHByb2dub3NpcyBvZiBpbmRpdmlkdWFscyBvciBjb2hvcnRzIG9mIHBhdGllbnRzLgozLglUeXBlcyBvZiBzdHVkeSBkZXNpZ25zOiBSQ1QsIG9ic2VydmF0aW9uYWwgc3R1ZGllcywgY2FzZS1jb250cm9sIHN0dWRpZXMsIGNyb3NzLXNlY3Rpb25hbCBzdHVkaWVzLCBjYXNlIHJlcG9ydHMgYW5kIGNhc2Ugc2VyaWVzCgpFeGNsdXNpb24gY3JpdGVyaWEKCjEuCVN0dWRpZXMgb24gYWR1bHQgcGF0aWVudHMgd2l0aCBTQVJTLUNvVi0yIGluZmVjdGlvbiBhbmQvb3IgU0FSUy1Db1YtMiBhc3NvY2lhdGVkIGh5cGVyaW5mbGFtbWF0b3J5IHN5bmRyb21lcwoyLglTdHVkaWVzIG9uIHBlZGlhdHJpYyBwYXRpZW50cyB3aXRoIG90aGVyIGNvcm9uYXZpcnVzIGluZmVjdGlvbnMgKFNBUlMtQ29WLTEgYW5kIE1pZGRsZSBFYXN0IFJlc3BpcmF0b3J5IFN5bmRyb21lIENvcm9uYXZpcnVzIChNRVJTLUNvVikgaW5mZWN0aW9uIG9yIG90aGVyIHJlc3BpcmF0b3J5IGluZmVjdGlvbnMuCjMuCVN0dWRpZXMgd2l0aCBpbmNvbXBsZXRlIG9yIGxhY2tpbmcgbmVjZXNzYXJ5IGRhdGEgCjQuCUR1cGxpY2F0ZSBzdHVkaWVzCjUuCVN0dWRpZXMgd2l0aG91dCBhY2Nlc3NpYmxlIGZ1bGwgdGV4dCB2ZXJzaW9ucwo2LglTdHVkaWVzIG5vdCBpbiBFbmdsaXNoIGxhbmd1YWdlCgpTdHVkeSBzZWxlY3Rpb24gd2FzIGEgdHdvLXN0YWdlIHByb2Nlc3Mgd2l0aCwgZmlyc3QsIHRpdGxlcyBhbmQgYWJzdHJhY3RzIG9mIHN0dWRpZXMgc2NyZWVuZWQgd2l0aCByZXRyaWV2YWwgdXNpbmcgdGhlIHNlYXJjaCBzdHJhdGVneSBhbmQgdGhlbiwgc2Vjb25kLCBmdWxsIHRleHQgc2NyZWVuaW5nIG9mIHBvdGVudGlhbGx5IGVsaWdpYmxlIHN0dWRpZXMgYXNzZXNzZWQgYnkgdHdvIHJldmlld2VycyBpbmRlcGVuZGVudGx5LiBBbnkgZGlzYWdyZWVtZW50IG92ZXIgdGhlIGVsaWdpYmlsaXR5IG9mIHBhcnRpY3VsYXIgc3R1ZGllcyB3YXMgcmVzb2x2ZWQgdGhyb3VnaCBkaXNjdXNzaW9uIHdpdGggYSB0aGlyZCByZXZpZXdlci4gCgpUaGUgUHJlZmVycmVkIFJlcG9ydGluZyBJdGVtcyBmb3IgU3lzdGVtYXRpYyBSZXZpZXdzIGFuZCBNZXRhLUFuYWx5c2VzIChQUklTTUEpIGNoZWNrbGlzdCB3YXMgdXNlZCB0byBndWlkZSB0aGUgc3R1ZHkgc2VsZWN0aW9uIGFuZCBleHRyYWN0aW9uIHByb2Nlc3MuIFJpc2sgZm9yIGJpYXMgb24gZWxpZ2libGUgb2JzZXJ2YXRpb25hbCBzdHVkaWVzIHdlcmUgYXNzZXNzZWQgYnkgTEggYWNjb3JkaW5nIHRvIHRoZSBOZXdDYXN0bGUtT3R0YXdhIFNjYWxlIChOT1MpLCB3aXRoIGZ1bGwgdmVyaWZpY2F0aW9uIG9mIGFsbCBqdWRnbWVudHMgYnkgUlZQLiBMZXZlbCBvZiBldmlkZW5jZSB3YXMgcmF0ZWQgYWNjb3JkaW5nIHRvIFNhY2tldHQuCgojIFBSSVNNQSBmbG93IGRpYWdyYW0KCiFbXSguL3Bsb3RzL1BSSVNNQSAyMDA5IGZsb3cgZGlhZ3JhbSAtIHVwZGF0ZSAwODIwMjAucG5nKQoKIyBEYXRhIGV4dHJhY3Rpb24KQWxsIG9yaWdpbmFsIHN0dWRpZXMgZGVzY3JpYmluZyBjbGluaWNhbOKAr2Nhc2Vz4oCvbWVldGluZyB0aGUgY2FzZSBkZWZpbml0aW9u4oCvb2YgUElNUy1UUyzigK9hcyBkZWZpbmVkIGJ5IFJDUENILOKAr3dlcmUgZWxpZ2libGUgZm9yIGluY2x1c2lvbi4gUHJpbWFyeSBvdXRjb21lIGFuYWx5c2lzIGZvY3VzZWQgb24gY2xpbmljYWwsIGVwaWRlbWlvbG9naWNhbCBhbmQgaW1tdW5vbG9naWNhbCBtYW5pZmVzdGF0aW9ucywgdGhlcmFwZXV0aWMgbWFuYWdlbWVudCBhbmTigK9wcm9nbm9zaXMu4oCvIAoKVGhlIGZvbGxvd2luZyBkYXRhIHBvaW50cyB3ZXJlIG91dGxpbmVkIHRvIGJlIGV4dHJhY3RlZCBvdXQgb2YgZWxpZ2libGUgcmVjb3JkczogcGF0aWVudCBjaGFyYWN0ZXJpc3RpY3MgKGUuZy4gc2V4LCBhZ2UsIGV0aG5pY2l0eSwgYW50aHJvcG9tZXRyeSzigKYpLCBjb21vcmJpZGl0aWVzIChlLmcuIGNhcmRpb3Zhc2N1bGFyIGRpc2Vhc2UsIHJlc3BpcmF0b3J5IGRpc2Vhc2UsIGRpYWJldGVzIG1lbGxpdHVzLCByZW5hbCBkaXNlYXNlLCBtYWxpZ25hbmN5L2NhbmNlciwgaW1tdW5vZGVmaWNpZW5jeSzigKYpLCBTQVJTLUNvVi0yIGluZmVjdGlvbiByZWxhdGVkIGRhdGEgKGUuZy4gY2xvc2UgY29udGFjdHMgd2l0aCBjb25maXJtZWQgb3Igc3VzcGVjdGVkIENPVklELTE5LCBQQ1IgYW5kIHNlcm9sb2d5IHJlc3VsdHMs4oCmKSwgY2xpbmljYWwgc3ltcHRvbXMgKGUuZy4gZmV2ZXIsIHJlc3BpcmF0b3J5LCBnYXN0cm8taW50ZXN0aW5hbCwgbmV1cm9sb2dpY2FsLCBkZXJtYXRvbG9naWNhbCwgcmVuYWwgb3IgY2FyZGlhYyBtYW5pZmVzdGF0aW9ucywgZGVzY3JpcHRpb24gb2YgS2F3YXNha2kgY3JpdGVyaWEs4oCmKSwgbGFib3JhdG9yeSB0ZXN0cyBhdCB2YXJpb3VzIHRpbWUgcG9pbnRzIChlLmcuIGhhZW1vZ2xvYmluLCBXQkMsIGx5bXBob2N5dGUsIG5ldXRyb3BoaWwgYW5kIHBsYXRlbGV0IGNvdW50cywgc29kaXVtLCBmZXJyaXRpbiwgRC1kaW1lciwgZmlicmlub2dlbiwgYWxidW1pbiwgY3JlYXRpbmluZSwgbGl2ZXIgdHJhbnNhbWluYXNlcywgQ0ssIExESCwgdHJvcG9uaW4sIE5ULXByb0JOUCwgQ1JQLCBFU1IsIHNlcnVtIGN5dG9raW5lcywgY29tcGxlbWVudCwgaW1tdW5vZ2xvYnVsaW5zLOKApiksIHJhZGlvbG9naWNhbCByZXN1bHRzLCBob3NwaXRhbCBhZG1pc3Npb24gZGF0YSAoZGF5cyBvZiBob3NwaXRhbGlzYXRpb24sIGRheXMgb2YgSUNVIGNhcmUs4oCmKSwgY3JpdGljYWwgY2FyZSBpbnRlcnZlbnRpb25zIChpbnZhc2l2ZSBhbmQgbm9uLWludmFzaXZlIHZlbnRpbGF0aW9uLCBpbm90cm9wZXMvdmFzb3ByZXNzb3JzIHVzZSwgRUNNTyzigKYpIGFuZCB0aGVyYXBldXRpY3MgYW5kIHRoZWlyIGVmZmVjdCAoY29ydGljb3N0ZXJvaWRzLCBhc3BpcmluLCBJVklHLCBiaW90aGVyYXBldXRpY3MsIGFudGliaW90aWNzLOKApikuIEZpZWxkcyB3aXRoIGluc3VmZmljaWVudCBkYXRhIHdpbGwgYmUgZXhjbHVkZWQgZnJvbSBmaW5hbCBhbmFseXNpcy4gQWRkaXRpb25hbCBwYXJhbWV0ZXJzIHdlcmUgaW5jbHVkZWQgaWYgcmVsZXZhbnQuIAoKCkNhc2VzIHdlcmUgZXhjbHVkZWQgaWYgaW5zdWZmaWNpZW50IGRhdGEgc3VnZ2VzdGluZyBhIHRlbXBvcmFsIGFzc29jaWF0aW9uIHdpdGggU0FSUy1Db1YtMiB3YXMgcHJlc2VudGVkLiBBIHJlY2VudCBvciBjdXJyZW50IHBvc2l0aXZlIFNBUlMtQ29WLTIgUENSIChuYXNvcGhhcnluZ2VhbCwgZmVjYWwsIG90aGVyKSBvciBzZXJvbG9neSAoSWdBLCBJZ00sIElnRykgcmVzdWx0cyBuZWVkZWQgdG8gYmUgcHJlc2VudGVkLCBvciBoaXN0b3J5IG9mIGNsb3NlIGNvbnRhY3QgKGUuZy4gaG91c2Vob2xkKSB3aXRoIGEgY29uZmlybWVkIG9yIGhpZ2hseSBzdXNwZWN0IGNhc2Ugb2YgQ09WSUQtMTkgd2FzIHJlcXVpcmVkLiBTdHVkaWVzIHdlcmUgZXhjbHVkZWQgaWYgZGF0YSB3YXMgaW5jb25zaXN0ZW50bHkgcHJlc2VudGVkLiAKCgpBcyBhIHNlY29uZGFyeSBvdXRjb21lLCBpdCB3YXMgb3V0bGluZWQgdG8gbWFrZSBhIHF1YWxpdGF0aXZlIGFzc2Vzc21lbnQgYW5kIHByb3Bvc2UgYW4gaW1tdW5vbG9naWNhbCBtZWNoYW5pc20gdW5kZXJwaW5uaW5nIHRoaXMgaW5mbGFtbWF0b3J5IHN5bmRyb21lIGJhc2VkIG9uIHRoZSBjYXNlcyByZXBvcnRlZCBpbiBsaXRlcmF0dXJlIGFuZC9vciBpbW11bm9sb2dpY2FsIGludmVzdGlnYXRpb25zIHBlcmZvcm1lZCBpbiB0aGVzZSBhZmZlY3RlZCBjaGlsZHJlbi4gTmV2ZXJ0aGVsZXNzLCB1cCB0byB0aGUgZmluYWwgc2VhcmNoLCBpbnN1ZmZpY2llbnQgZGF0YSB3YXMgYXZhaWxhYmxlIHRvIGNvbmR1Y3Qgc3VjaCBhc3Nlc3NtZW50cy4gIAoKQSBzaW5nbGUgcmV2aWV3ZXIgKExIKSBleHRyYWN0ZWQgZGF0YSB1c2luZyBhIHN0YW5kYXJkaXplZCBmb3JtLCB3aGlsZSBhIHNlY29uZCByZXZpZXdlciAoUlZQKSBjcm9zcyBjaGVja2VkIGFsbCBkYXRhIGZvciBjb3JyZWN0bmVzcyBhbmQgY29tcGxldGVuZXNzLiBBbnkgZGlzYWdyZWVtZW50IG92ZXIgc3R1ZHkgZWxpZ2liaWxpdHkgYW5kIGNvbmZsaWN0IG9uIGRhdGEgZXh0cmFjdGlvbiB3ZXJlIHJlc29sdmVkIGJ5IGEgdGhpcmQgcmV2aWV3ZXIgKEZIKS4gCgpDb2hvcnQgc3R1ZGllcyBhbmQgc3R1ZGllcyByZXBvcnRpbmcgb24gc2luZ2xlIGNhc2VzIHdlcmUgYW5hbHlzZWQgc2VwYXJhdGVseSwgYXMgd2UgZGlkIG5vdCBoYXZlIGFjY2VzcyB0byB0aGUgaW5kaXZpZHVhbCBjYXNlIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgY29ob3J0IHN0dWRpZXMuICBGb3IgdGhlIGNvaG9ydCBzdHVkaWVzLCBwcm9wb3J0aW9ucyB3ZXJlIGNhbGN1bGF0ZWQgYnkgc3VtbWluZyBvbmx5IHRoZSBzdHVkaWVzIHdoaWNoIHJlcG9ydCBvbiB0aGUgdmFyaWFibGUsIGV4Y2VwdCBmb3IgcmFyZSBjb25kaXRpb25zIHN1Y2ggYXMgZGVhdGgsIGNvbW9yYmlkaXRpZXMsIHVzZSBvZiBFQ01PIG9yIGJpb3BoYXJtYWNldXRpY2Fscy4KCldlIGhhdmUgZGVsaWJlcmF0ZWx5IHVzZWQg4oCcTUlT4oCdIGNvbmNlcm5pbmcgdGhlIFdITyBkZWZpbml0aW9uIChhbHNvIHNlZSBTdXBwbDEpIHNpbmNlIHRoZSBXSE8gY2FzZSBkZWZpbml0aW9uIGhhcyBhbHdheXMgdXNlZCDigJxNSVPigJ0gaW5zdGVhZCBvZiDigJxNSVMtQ+KAnSBpbiBpdHMgY29tbXVuaWNhdGlvbi4gSW4gdGhlaXIg4oCcU2NpZW50aWZpYyBicmllZuKAnSBubyBhYmJyZXZpYXRpb25zIGFyZSB1c2VkIChodHRwczovL3d3dy53aG8uaW50L3B1YmxpY2F0aW9ucy9pL2l0ZW0vbXVsdGlzeXN0ZW0taW5mbGFtbWF0b3J5LXN5bmRyb21lLWluLWNoaWxkcmVuLWFuZC1hZG9sZXNjZW50cy13aXRoLWNvdmlkLTE5KS4gV2hpbGUgb24gdGhlIFdITyB3ZWJzaXRlIOKAnE1JU+KAnSBpcyBtZW50aW9uZWQgKGh0dHBzOi8vd3d3Lndoby5pbnQvbmV3cy1yb29tL2NvbW1lbnRhcmllcy9kZXRhaWwvbXVsdGlzeXN0ZW0taW5mbGFtbWF0b3J5LXN5bmRyb21lLWluLWNoaWxkcmVuLWFuZC1hZG9sZXNjZW50cy13aXRoLWNvdmlkLTE5KSwgYXMgd2VsbCBhcyBpbiB0aGUgV0hPIGNhc2UgcmVwb3J0IGZvcm1zIChodHRwczovL3d3dy53aG8uaW50L2RvY3MvZGVmYXVsdC1zb3VyY2UvY29yb25hdmlydXNlL2ZpbmFsLS1taXNjLWNyZi0xOC1tYXktMjAyMC13aG8ucGRmP3NmdnJzbj04ODM5MTgxYV80KSAKCiMgVXBkYXRlIGJldHdlZW4gMjAyMC0wNi0zMCBhbmQgMjAyMC0wOC0xMwoKSW5pdGlhbGx5LCB0aGUgbGl0ZXJhdHVyZSBzZWFyY2ggYW5kIGRhdGEtZXh0cmFjdGlvbiB3YXMgcGVyZm9ybWVkIHVwIHRvIEp1bmUgMzAsIDIwMjAuIEFmdGVyd2FyZHMsIGFuIHVwZGF0ZSBvZiB0aGUgbGl0ZXJhdHVyZSBzZWFyY2gsIGRhdGEtZXh0cmFjdGlvbiBhbmQgbWFudXNjcmlwdCB3YXMgZG9uZSB3aXRoIHN0dWRpZXMgcHVibGlzaGVkIGJldHdlZW4gSnVseSAxc3QgYW5kIEF1Z3VzdCAxM3RoLiBJbiB0aGlzIHNlY29uZCBwaGFzZSwgY29uZmxpY3RzIGR1cmluZyBzdHVkeSBzZWxlY3Rpb24gd2VyZSByZXNvbHZlZCBieSBkaXNjdXNzaW9uIGJldHdlZW4gTEggYW5kIFJWUCB1bnRpbCBhIGNvbnNlbnN1cyB3YXMgcmVhY2hlZCwgaW5zdGVhZCBvZiBieSB0aGUgdGhpcmQgaW5kZXBlbmRlbnQgdGhpcmQgcmV2aWV3ZXIuIEZvciBuID0gNyBzdHVkaWVzLCBSVlAgZXh0cmFjdGVkIHRoZSBkYXRhLCB3aGlsZSB0aGUgc2Vjb25kIHJldmlld2VyIExIIGNyb3NzIGNoZWNrZWQgYWxsIGRhdGEgZm9yIGNvcnJlY3RuZXNzIGFuZCBjb21wbGV0ZW5lc3MuIE5vIG90aGVyIGNoYW5nZXMgdG8gdGhlIGxpdGVyYXR1cmUgc2VhY2ggbWV0aG9kb2xvZ3ksIGRhdGEtZXh0cmFjdGlvbiBvciBhbmFseXNpcyB3YXMgZG9uZS4gCgoKIyBEYXRhIGltcG9ydCBhbmQgY2xlYW5pbmcKIyMgU2luZ2xlIGNhc2VzCkFmdGVyIGRhdGEgY29sbGVjdGlvbiwgd2UgaW1wb3J0IHRoZSBzaW5nbGUgY2FzZXMgZnJvbSB0aGUgW2dlbmVyYWwgZXhjZWwgc2hlZXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9ybXZwYWVtZS9QSU1TX01JU0NfU1IpIGFuZCB0cmFuc2Zvcm0gdGhlIGV4Y2VsIHNoZWV0IHNvIHRoYXQgdmFyaWFibGVzIGFyZSBjb2x1bW5zIGFuZCByb3dzIGFyZSBjYXNlcy4gQ29sdW1ucyB3aXRob3V0IGFueSB2YWx1ZXMgYXJlIGFsc28gcmVtb3ZlZC4gCgpUaGUgc2luZ2xlIGNhc2VzIGZyb20gUG91bGV0dHkgKDEwLjExMzYvYW5ucmhldW1kaXMtMjAyMC0yMTc5NjApIGFyZSBleGNsdWRlZCAoYXMgdGhleSBhcmUgaW5jbHVkZWQgaW4gdGhlIGNvaG9ydHMsIGFuZCB0aGV5IG9ubHkgcmVwb3J0IElMNiBkYXRhIGZvciBzaW5nbGUgY2FzZXMsIHdoaWNoIGFyZSBhZGRlZCB0byB0aGUgSUw2IGZpZ3VyZSkuCgoKYGBge3J9CmRmX3NpbmdsZWNhc2VzIDwtCiAgcmVhZF9leGNlbCgiMjAyMDA5MDNfZGF0YV9leHRyYWN0aW9uLnhsc3giLAogICAgICAgICAgICAgc2hlZXQgPSAiU2luZ2xlIGNhc2VzIiwKICAgICAgICAgICAgIHNraXAgPSAxLAogICAgICAgICAgICAgY29sX25hbWVzID0gRkFMU0UpWywtYygxOjIpXQpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgdCgpCmRmX3NpbmdsZWNhc2VzIDwtIGFzLmRhdGEuZnJhbWUoZGZfc2luZ2xlY2FzZXMsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKbm1zIDwtIGFzLnZlY3RvcihkZl9zaW5nbGVjYXNlc1sxLF0pCm5tc1tpcy5uYShubXMpXSA8LSAndG1wJwpjb2xuYW1lcyhkZl9zaW5nbGVjYXNlcykgPC0gbWFrZS51bmlxdWUoYXMuY2hhcmFjdGVyKG5tcykpCmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzWy0xLF0KZGZfc2luZ2xlY2FzZXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdCgtY29udGFpbnMoInRtcCIpKQpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgc2VsZWN0KC12YXJpYWJsZV9pZCkKCmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzICU+JSAKICBtdXRhdGVfYWxsKGZ1bnMoc3RyX3JlcGxhY2UoLiwgIlllcyIsICJ5ZXMiKSkpCmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzICU+JSAKICBtdXRhdGVfYWxsKGZ1bnMoc3RyX3JlcGxhY2UoLiwgIk5vIiwgIm5vIikpKQpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgCiAgbXV0YXRlX2FsbChmdW5zKHN0cl9yZXBsYWNlKC4sICJwb3MiLCAieWVzIikpKQpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgCiAgbXV0YXRlX2FsbChmdW5zKHN0cl9yZXBsYWNlKC4sICJuZWciLCAibm8iKSkpCgpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUKICByZXBsYWNlX3dpdGhfbmFfYWxsKGNvbmRpdGlvbiA9IH4ueCA9PSAiTkEiKQoKZGZfc2luZ2xlY2FzZXMgPC0gdHlwZV9jb252ZXJ0KGRmX3NpbmdsZWNhc2VzKQpkZl9zaW5nbGVjYXNlc19pbmNsUG91bGV0dHkgPC0gZGZfc2luZ2xlY2FzZXMKZGZfc2luZ2xlY2FzZXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIGZpbHRlcihkb2kgIT0gImh0dHBzOi8vMTAuMTEzNi9hbm5yaGV1bWRpcy0yMDIwLTIxNzk2MCIpICAjIHRoZXNlIGNhc2VzIGFyZSBleGNsdWRlZCBhY2NvcmRpbmcgdG8gdGhlIGRhdGEgc2hlZXQKCmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzW2NvbFN1bXMoIWlzLm5hKGRmX3NpbmdsZWNhc2VzKSkgPiAwXQoKZGZfc2luZ2xlY2FzZXMkZGF0ZV9vZl9wdWJsaWNhdGlvbiA8LSBhcy5EYXRlKGRmX3NpbmdsZWNhc2VzJGRhdGVfb2ZfcHVibGljYXRpb24sIG9yaWdpbiA9ICIxODk5LTEyLTMwIikKCm5fc2luZ2xlX2Nhc2VzIDwtIG5yb3coZGZfc2luZ2xlY2FzZXMpCgoKYGBgCgoKIyMjIE1ha2luZyBzdW1tYXJ5IHN0YXRpc3RpY3MKCkluIHRoaXMgc2VjdGlvbiwgZGF0YSBpcyBzdW1tYXJpemVkLiBGb3IgZXhhbXBsZSwgaWYgdGhlcmUgYXJlIGFueSBjb21vcmJpZGl0aWVzIHByZXNlbnQsIGEgY29sdW1uICJjb21vcmJfYW55IiBpcyBhZGRlZCBhbmQgYW5ub3RhdGVkIGFzIFRSVUUuIFRoZSBzYW1lIGlzIGRvbmUgZm9yIENPVklEIHNlcm9sb2d5IGFuZCBzeW1wdG9tcyBvZiBtYWpvciBvcmdhbiAocmVzcGlyYXRvcnksIGNhcmRpb3Zhc2N1bGFyIGV0YykuCgpgYGB7cn0KZGZfc2luZ2xlY2FzZXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIG11dGF0ZShjb21vcmJfYW55ID0gYXBwbHkoZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb250YWlucygiY29tb3JiIikpLCAxLCBhbnkpKQpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbW92ZW1lKC4sICJjb21vcmJfYW55IGJlZm9yZSBjb21vcmJfY2FyZGlvdmFzYyIpCmBgYAoKSWYgSWdHLCBJZ0EsIElnTSBvciBDT1ZJRCBzZXJvbG9neSBpcyByZXBvcnRlZCBhcyBwb3NpdGl2ZSwgdGhlIGNvbHVtbiBjb3ZpZF9zZXJvX2FueSBpcyBhbm5vdGF0ZWQgYXMgVFJVRS4KCmBgYHtyfQpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbXV0YXRlKGNvdmlkX3Nlcm9fYW55ID0gYXBwbHkoZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb3ZpZF9zZXJvX3BvcywgY292aWRfSWdBX3BvcywgY292aWRfSWdNX3BvcywgY292aWRfSWdHX3BvcyksIDEsIGFueSkpCgpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbW92ZW1lKC4sICJjb3ZpZF9zZXJvX2FueSBiZWZvcmUgY292aWRfc2Vyb19wb3MiKQpgYGAKCklmIFBDUissIHN0b29sIFBDUissIElnRywgSWdBLCBJZ00gb3IgQ09WSUQgc2Vyb2xvZ3kgaXMgcmVwb3J0ZWQgYXMgcG9zaXRpdmUsIHRoZSBjb2x1bW4gY292aWRfcG9zX2FueSBpcyBhbm5vdGF0ZWQgYXMgVFJVRS4KCmBgYHtyfQpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbXV0YXRlKGNvdmlkX3Bvc19hbnkgPSBhcHBseShkZl9zaW5nbGVjYXNlcyAlPiUgc2VsZWN0KGNvdmlkX1BDUl9wb3MsIGNvdmlkX1BDUl9zdG9vbF9wb3MsIGNvdmlkX3Nlcm9fcG9zLCBjb3ZpZF9JZ0FfcG9zLCBjb3ZpZF9JZ01fcG9zLCBjb3ZpZF9JZ0dfcG9zKSwgMSwgYW55KSkKCmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBtb3ZlbWUoLiwgImNvdmlkX3Bvc19hbnkgYmVmb3JlIGNvdmlkX3Nlcm9fYW55IikKYGBgCgpJZiBhbnkgcmVzcGlyYXRvcnkgc3ltcHRvbXMsIHN5bXBfcmVzcF9hbnkgaXMgYW5ub3RhdGVkIGFzIFRSVUUuCgpgYGB7cn0KZGZfc2luZ2xlY2FzZXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIG11dGF0ZShzeW1wX3Jlc3BfYW55ID0gYXBwbHkoZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChzeW1wX3Jlc3BfTlMsIHN5bXBfcmVzcF9VUlQsIHN5bXBfcmVzcF9keXNwbmVhLCBzeW1wX3Jlc3BfcG5ldW1vbmlhLCBzeW1wX3Jlc3BfZmFpbHVyZSwgc3ltcF9yZXNwX2NoZXN0cGFpbiksIDEsIGFueSkpCgpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbW92ZW1lKC4sICJzeW1wX3Jlc3BfYW55IGJlZm9yZSBzeW1wX3Jlc3BfTlMiKQpgYGAKCklmIGFueSBHSSBzeW1wdG9tcywgc3ltcF9HSV9hbnkgaXMgYW5ub3RhdGVkIGFzIFRSVUUuCgpgYGB7cn0KZGZfc2luZ2xlY2FzZXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIG11dGF0ZShzeW1wX0dJX2FueSA9IGFwcGx5KGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QoY29udGFpbnMoInN5bXBfR0kiKSksIDEsIGFueSkpCgpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbW92ZW1lKC4sICJzeW1wX0dJX2FueSBiZWZvcmUgc3ltcF9HSV9OUyIpCmBgYAoKSWYgYW55IG5ldXJvbG9naWNhbCBzeW1wdG9tcywgc3ltcF9uZXVyb19hbnkgaXMgYW5ub3RhdGVkIGFzIFRSVUUuCgpgYGB7cn0KZGZfc2luZ2xlY2FzZXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIG11dGF0ZShzeW1wX25ldXJvX2FueSA9IGFwcGx5KGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3Qoc3ltcF9uZXVyb19oZWFkYWNoZSxzeW1wX25ldXJvX21lbmluZ2l0aXMsc3ltcF9uZXVyb19tZW5pbmdpc20sc3ltcF9uZXVyb19hc3RoZW5pYSxzeW1wX25ldXJvX2lycml0YWIpLCAxLCBhbnkpKQoKZGZfc2luZ2xlY2FzZXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIG1vdmVtZSguLCAic3ltcF9uZXVyb19hbnkgYmVmb3JlIHN5bXBfbmV1cm9fR0NTIikKYGBgCgpJZiBhbnkgcmVuYWwgc3ltcHRvbXMsIHN5bXBfcmVuYWxfYW55IGlzIGFubm90YXRlZCBhcyBUUlVFLgoKYGBge3J9CmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBtdXRhdGUoc3ltcF9yZW5hbF9hbnkgPSBhcHBseShkZl9zaW5nbGVjYXNlcyAlPiUgc2VsZWN0KHN5bXBfcmVuYWxfQUtJKSwgMSwgYW55KSkKCmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBtb3ZlbWUoLiwgInN5bXBfcmVuYWxfYW55IGJlZm9yZSBzeW1wX3JlbmFsX0FLSSIpCmBgYAoKSWYgYW55IGNhcmRpb3Zhc2N1bGFyIHN5bXB0b21zLCBzeW1wX2NhcmRpb3Zhc2NfYW55IGlzIGFubm90YXRlZCBhcyBUUlVFLgoKYGBge3J9CmRmX3NpbmdsZWNhc2VzIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBtdXRhdGUoc3ltcF9jYXJkaW92YXNjX2FueSA9IGFwcGx5KGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3Qoc3ltcF9jYXJkaW92YXNjX215b2NhcmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltcF9jYXJkaW92YXNjX3BlcmljYXJkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXBfY2FyZGlvdmFzY19jb3JkaWxhdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1wX2NhcmRpb3Zhc2NfYW5ldXJ5c20sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltcF9jYXJkaW92YXNjX3Nob2NrLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXBfY2FyZGlvdmFzY190YWNoeWNhcmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltcF9jYXJkaW92YXNjX2Fycmh5dCksIDEsIGFueSkpCgpkZl9zaW5nbGVjYXNlcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbW92ZW1lKC4sICJzeW1wX2NhcmRpb3Zhc2NfYW55IGJlZm9yZSBzeW1wX2NhcmRpb3Zhc2NfbXlvY2FyZCIpCgp3cml0ZS5jc3YoZGZfc2luZ2xlY2FzZXMsIHBhc3RlMCgiLi9kYXRhL2RmX3NpbmdsZWNhc2VzLmNzdiIpKQoKI2RhdGF0YWJsZShkZl9zaW5nbGVjYXNlcywgY2FwdGlvbiA9ICJTaW5nbGUgY2FzZXMgZGF0YWZyYW1lIikKYGBgCgoKPGJ1dHRvbiBvbmNsaWNrPSJsb2NhdGlvbi5ocmVmPSdodHRwczovL2dpdGh1Yi5jb20vcm12cGFlbWUvUElNU19UUy9ibG9iL21hc3Rlci9kYXRhL2RmX3NpbmdsZWNhc2VzLmNzdiciIHR5cGU9ImJ1dHRvbiI+CkRvd25sb2FkIHNpbmdsZSBjYXNlIGRhdGEgYXMgLmNzdiBvbiBHaXRodWI8L2J1dHRvbj4KCiMjIENvaG9ydHMKQWZ0ZXJ3YXJkcywgd2UgZG8gdGhlIHNhbWUgZm9yIHRoZSBjb2hvcnQgc2hlZXQuCgpUaGUgcGFwZXJzIGJ5IEdyaW1hdWQgZXQgYWwuIGFuZCBWZXJkb25pIGV0IGFsLiBhcmUgcmVtb3ZlZCBmcm9tIHRoZSBjb2hvcnQgZGF0YWZyYW1lLCBhcyBtb3N0IGluZm9ybWF0aW9uIGlzIHByZXNlbnQgaW4gdGhlIHNpbmdsZSBjYXNlcyBkYXRhZnJhbWUuIApgYGB7cn0KZGZfY29ob3J0IDwtCiAgcmVhZF9leGNlbCgiMjAyMDA5MDNfZGF0YV9leHRyYWN0aW9uLnhsc3giLAogICAgICAgICAgICAgc2hlZXQgPSAiQ29ob3J0cyIsCiAgICAgICAgICAgICBza2lwID0gMSwKICAgICAgICAgICAgIGNvbF9uYW1lcyA9IEZBTFNFKVssLWMoMTozKV0KCgpkZl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSB0KCkKZGZfY29ob3J0IDwtIGFzLmRhdGEuZnJhbWUoZGZfY29ob3J0LCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCm5tcyA8LSBhcy52ZWN0b3IoZGZfY29ob3J0WzEsXSkKbm1zW2lzLm5hKG5tcyldIDwtICd0bXAnCmNvbG5hbWVzKGRmX2NvaG9ydCkgPC0gbWFrZS51bmlxdWUoYXMuY2hhcmFjdGVyKG5tcykpCmRmX2NvaG9ydCA8LSBkZl9jb2hvcnRbLTEsXQpkZl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSBzZWxlY3QoLWNvbnRhaW5zKCJ0bXAiKSkKZGZfY29ob3J0IDwtIGRmX2NvaG9ydCAlPiUgc2VsZWN0KC12YXJpYWJsZV9pZCkKCmRmX2NvaG9ydCA8LSBkZl9jb2hvcnQgJT4lIAogIG11dGF0ZV9hbGwoZnVucyhzdHJfcmVwbGFjZSguLCAiWWVzIiwgInllcyIpKSkKZGZfY29ob3J0IDwtIGRmX2NvaG9ydCAlPiUgCiAgbXV0YXRlX2FsbChmdW5zKHN0cl9yZXBsYWNlKC4sICJObyIsICJubyIpKSkKZGZfY29ob3J0IDwtIGRmX2NvaG9ydCAlPiUgCiAgbXV0YXRlX2FsbChmdW5zKHN0cl9yZXBsYWNlKC4sICJwb3MiLCAieWVzIikpKQpkZl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSAKICBtdXRhdGVfYWxsKGZ1bnMoc3RyX3JlcGxhY2UoLiwgIm5lZyIsICJubyIpKSkKCmRmX2NvaG9ydCA8LSBkZl9jb2hvcnQgJT4lCiAgcmVwbGFjZV93aXRoX25hX2FsbChjb25kaXRpb24gPSB+LnggPT0gIk5BIikKCmRmX2NvaG9ydCA8LSB0eXBlX2NvbnZlcnQoZGZfY29ob3J0KQoKZGZfY29ob3J0IDwtIGRmX2NvaG9ydFtjb2xTdW1zKCFpcy5uYShkZl9jb2hvcnQpKSA+IDBdCgpkZl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSBmaWx0ZXIoZG9pICE9ICJodHRwczovL2RvaS5vcmcvMTAuMTE4Ni9zMTM2MTMtMDIwLTAwNjkwLTgiKSAlPiUgZmlsdGVyKGRvaSAhPSAiaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvUzAxNDAtNjczNigyMCkzMTEwMy1YIikKCmRmX2NvaG9ydF9jb250cm9scyA8LSBkZl9jb2hvcnQKCmRmX2NvaG9ydCA8LSBkZl9jb2hvcnQgJT4lIGZpbHRlcihjb2hvcnRfdHlwZSA9PSAiTUlTLUMiKQoKZGZfY29ob3J0JGRhdGVfb2ZfcHVibGljYXRpb24gPC0gYXMuRGF0ZShkZl9jb2hvcnQkZGF0ZV9vZl9wdWJsaWNhdGlvbiwgb3JpZ2luID0gIjE4OTktMTItMzAiKQoKd3JpdGUuY3N2KGRmX2NvaG9ydCwgcGFzdGUwKCIuL2RhdGEvZGZfY29ob3J0LmNzdiIpKQoKI2RhdGF0YWJsZShkZl9jb2hvcnQsIGNhcHRpb24gPSAiQ29ob3J0IGRhdGFmcmFtZSIpCmBgYAoKPGJ1dHRvbiBvbmNsaWNrPSJsb2NhdGlvbi5ocmVmPSdodHRwczovL2dpdGh1Yi5jb20vcm12cGFlbWUvUElNU19UUy9ibG9iL21hc3Rlci9kYXRhL2RmX2NvaG9ydC5jc3YnIiB0eXBlPSJidXR0b24iPgpEb3dubG9hZCBjb2hvcnQgZGF0YSBhcyAuY3N2IG9uIEdpdGh1YjwvYnV0dG9uPgoKIyBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHsudGFic2V0fQojIyBHZW5lcmFsCgoqKkNsaWNrIG9uIHRoZSBhbnkgb2YgdGhlIHRhYnMgYWJvdmUgdG8gc2VlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgZm9yIGV2ZXJ5IHZhcmlhYmxlKiogICAgICAKCiMjIFNpbmdsZSBjYXNlcwoKPGJ1dHRvbiBvbmNsaWNrPSJsb2NhdGlvbi5ocmVmPSdodHRwczovL2dpdGh1Yi5jb20vcm12cGFlbWUvUElNU19UUy9ibG9iL21hc3Rlci9kYXRhL3NpbmdsZWNhc2VzX2Rlc2NyaXB0aXZlc3RhdHMuY3N2JyIgdHlwZT0iYnV0dG9uIj4KRG93bmxvYWQgZGF0YSBhcyAuY3N2IG9uIEdpdGh1YjwvYnV0dG9uPgoKCmBgYHtyfQojc2tpbShkZl9zaW5nbGVjYXNlcykKd3JpdGUuY3N2KHNraW0oZGZfc2luZ2xlY2FzZXMpLCBwYXN0ZTAoIi4vZGF0YS9zaW5nbGVjYXNlc19kZXNjcmlwdGl2ZXN0YXRzLmNzdiIpKQpgYGAKCiMjIENvaG9ydHMKVGhlICJQcmN0X3RvdGFsIiBjb2x1bW4gaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgZS5nLiBkZWF0aCBkaXZpZGVkIGJ5IHRoZSB0b3RhbCBjYXNlcyBpbiB0aGUgY29ob3J0IGdyb3VwLiBPbmx5IG1ha2VzIHNlbnNlIHdoZXJlIG4gaXMgcmVwb3J0ZWQgZS5nLiB0aGVyYXB5IChub3QgZm9yIGxhYiB2YWx1ZXMpLgoKPGJ1dHRvbiBvbmNsaWNrPSJsb2NhdGlvbi5ocmVmPSdodHRwczovL2dpdGh1Yi5jb20vcm12cGFlbWUvUElNU19UUy9ibG9iL21hc3Rlci9kYXRhL2NvaG9ydF9kZXNjcmlwdGl2ZXN0YXRzLmNzdiciIHR5cGU9ImJ1dHRvbiI+CkRvd25sb2FkIGRhdGEgYXMgLmNzdiBvbiBHaXRodWI8L2J1dHRvbj4KCmBgYHtyfQpza2ltc3VtIDwtIHNraW1fd2l0aChudW1lcmljID0gc2ZsKHN1bSA9IH4gc3VtKC4sIG5hLnJtID0gVFJVRSksIFByY3RfdG90YWwgPSB+IHN1bSguLCBuYS5ybSA9IFRSVUUpL3N1bShkZl9jb2hvcnQkdG90X2Nhc2VzX24pKjEwMCksIGFwcGVuZCA9IFRSVUUpCiNza2ltc3VtKGRmX2NvaG9ydCkKd3JpdGUuY3N2KHNraW1zdW0oZGZfY29ob3J0KSwgcGFzdGUwKCIuL2RhdGEvY29ob3J0X2Rlc2NyaXB0aXZlc3RhdHMuY3N2IikpCmBgYAoKIyMgSGlzdG9yaWNhbCBjb250cm9scwoKPGJ1dHRvbiBvbmNsaWNrPSJsb2NhdGlvbi5ocmVmPSdodHRwczovL2dpdGh1Yi5jb20vcm12cGFlbWUvUElNU19UUy9ibG9iL21hc3Rlci9kYXRhL2hpc3RvcmljYWxjb250cm9sc19kZXNjcmlwdGl2ZXN0YXRzLmNzdiciIHR5cGU9ImJ1dHRvbiI+CkRvd25sb2FkIGRhdGEgYXMgLmNzdiBvbiBHaXRodWI8L2J1dHRvbj4KCmBgYHtyfQpkZl9jb2hvcnRfY29udHJvbHNfc3RhdHMgPC0gZGZfY29ob3J0X2NvbnRyb2xzICU+JSBmaWx0ZXIoY29ob3J0X3R5cGUgIT0gIk1JUy1DIikKZGZfY29ob3J0X2NvbnRyb2xzX3N0YXRzIDwtIGRmX2NvaG9ydF9jb250cm9sc19zdGF0c1tjb2xTdW1zKCFpcy5uYShkZl9jb2hvcnRfY29udHJvbHNfc3RhdHMpKSA+IDBdCnNraW1zdW0gPC0gc2tpbV93aXRoKG51bWVyaWMgPSBzZmwoc3VtID0gfiBzdW0oLiwgbmEucm0gPSBUUlVFKSwgUHJjdF90b3RhbCA9IH4gc3VtKC4sIG5hLnJtID0gVFJVRSkvc3VtKGRmX2NvaG9ydF9jb250cm9sc19zdGF0cyR0b3RfY2FzZXNfbikqMTAwKSwgYXBwZW5kID0gVFJVRSkKI3NraW1zdW0oZGZfY29ob3J0X2NvbnRyb2xzX3N0YXRzKQoKd3JpdGUuY3N2KHNraW1zdW0oZGZfY29ob3J0X2NvbnRyb2xzX3N0YXRzKSwgcGFzdGUwKCIuL2RhdGEvaGlzdG9yaWNhbGNvbnRyb2xzX2Rlc2NyaXB0aXZlc3RhdHMuY3N2IikpCgp3cml0ZS5jc3YoZGZfY29ob3J0X2NvbnRyb2xzX3N0YXRzLCBwYXN0ZTAoIi4vZGF0YS9kZl9jb2hvcnRfY29udHJvbHNfc3RhdHMuY3N2IikpCmBgYAoKCiMgRGF0YSBleHBsb3JhdGlvbgoKKipJbXBvcnRhbnQqKiAKCkZvciB0aGUgY29ob3J0cywgcGVyY2VudGFnZXMgZGVzY3JpYmUgdGhlIHRvdGFsIChlLmcuIHBvc2l0aXZlKSBjYXNlcywgZGl2aWRlZCBieSB0aGUgc3VtIG9mIHRoZSB0b3RhbCBjYXNlcyAqKm9mIHN0dWRpZXMgcmVwb3J0aW5nIHRoZSB2YXJpYWJsZSoqLgoKIyMgQ2FzZXMgaW4gZnVuY3Rpb24gb2YgQ09WSUQgcGFuZGVtaWMKClRvIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgb2YgdGhlIHB1Ymxpc2hlZCBQSU1TIGNhc2VzIHdpdGggdGhlIG9uZ29pbmcgQ09WSUQtMTkgcGFuZGVtaWMsIHRoZSBjYXNlIGRhdGEgZnJvbSBbSm9obnMgSG9wa2luc10oaHR0cHM6Ly9naXRodWIuY29tL0NTU0VHSVNhbmREYXRhL0NPVklELTE5KSB3YXMgZG93bmxvYWRlZCAoYW5kIGFkZGVkIHRvIHRoaXMgcmVwb3NpdG9yeSkuCgpUaGUgbGlzdCB3YXMgZmlsdGVyZWQgb24gdGhlIFVLLCBVUywgSXRhbHkgYW5kIEZyYW5jZSwgYXMgdGhlc2UgY291bnRyeSBjb250cmlidXRlIHRoZSBtb3N0IHRvIG91ciBkYXRhc2V0LiAKCkNhdmVhdDogdGhpcyBpcyBhIGRpc3RvcmVkIGltYWdlIG9mIHRoZSBQSU1TIGNhc2VzOiBhcyB0aGUgY2FzZXMgYXJlIHB1Ymxpc2hlZCB0b2dldGhlciwgdGhlaXIgdHJ1ZSBkYXRlIG9mIGRpYWdub3NpcyBpcyB1bmtub3duLiAKCmBgYHtyfQoKZmlyc3RkaWZmIDwtIGZ1bmN0aW9uKHgpIHsKICBzaGlmdGVkIDwtIGMoMCx4WzE6KGxlbmd0aCh4KS0xKV0pCiAgeC1zaGlmdGVkCn0KClVTQV9jYXNlcyA8LSByZWFkX2NzdigiLi9kYXRhL3RpbWVfc2VyaWVzX2NvdmlkMTlfY29uZmlybWVkX1VTLmNzdiIpClVTQV9jYXNlcyA8LSBVU0FfY2FzZXMgJT4lIHNlbGVjdCgtYyhVSUQsIGlzbzIsIGlzbzMsIGNvZGUzLCBGSVBTLCBBZG1pbjIsIFByb3ZpbmNlX1N0YXRlLCBMYXQsIExvbmdfLCBDb21iaW5lZF9LZXkpKQoKbmFtZXMoVVNBX2Nhc2VzKVtuYW1lcyhVU0FfY2FzZXMpID09ICdDb3VudHJ5X1JlZ2lvbiddIDwtICJDb3VudHJ5L1JlZ2lvbiIKCmdsb2JhbF9jYXNlcyA8LSByZWFkX2NzdigiLi9kYXRhL3RpbWVfc2VyaWVzX2NvdmlkMTlfY29uZmlybWVkX2dsb2JhbC5jc3YiKQpnbG9iYWxfY2FzZXMgPC0gZ2xvYmFsX2Nhc2VzICU+JSBzZWxlY3QoLWMoYFByb3ZpbmNlL1N0YXRlYCwgTGF0LCBMb25nKSkKCmdsb2JhbF9jYXNlcyA8LSByYmluZChVU0FfY2FzZXMsIGdsb2JhbF9jYXNlcykKCmdsb2JhbF9jYXNlcyA8LSBnbG9iYWxfY2FzZXMgJT4lIG1lbHQoKQpnbG9iYWxfY2FzZXMkdmFyaWFibGUgPC0gYXMuRGF0ZShnbG9iYWxfY2FzZXMkdmFyaWFibGUsIGZvcm1hdCA9ICIlbS8lZC8leSIpCmNvbG5hbWVzKGdsb2JhbF9jYXNlcykgPC0gYygiY291bnRyeSIsICJkYXRlX29mX3B1YmxpY2F0aW9uIiwgInRvdF9jYXNlc19jb3ZpZCIpCmdsb2JhbF9jYXNlcyA8LSBnbG9iYWxfY2FzZXMgJT4lIGZpbHRlcihjb3VudHJ5ID09ICJVbml0ZWQgS2luZ2RvbSIgIHwgY291bnRyeSA9PSAiSXRhbHkiIHwgY291bnRyeSA9PSAiRnJhbmNlIiB8IGNvdW50cnkgPT0gIlVTIikKYWxsX2dsb2JfY2FzZXMgPC0gZ2xvYmFsX2Nhc2VzICU+JSBncm91cF9ieShkYXRlX29mX3B1YmxpY2F0aW9uKSAlPiUgc3VtbWFyaXNlKHRvdGFsX2Nhc2VzID0gc3VtKHRvdF9jYXNlc19jb3ZpZCkpCmFsbF9nbG9iX2Nhc2VzJG5ld2Nhc2VzIDwtIGZpcnN0ZGlmZihhbGxfZ2xvYl9jYXNlcyR0b3RhbF9jYXNlcykKYWxsX2dsb2JfY2FzZXMkbmV3Y2FzZV9yb2xsNyA8LSB6b286OnJvbGxtZWFuKGFsbF9nbG9iX2Nhc2VzJG5ld2Nhc2VzLCBrID0gNywgZmlsbCA9IE5BKQoKZXZvX2Nhc2VzIDwtIHJiaW5kKGRmX2NvaG9ydCAlPiUgc2VsZWN0KHRvdF9jYXNlc19uLCBkYXRlX29mX3B1YmxpY2F0aW9uKSAlPiUgbXV0YXRlKHR5cGUgPSAiY29ob3J0IiksIAogICAgICAgICAgICAgICAgICAgZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChkYXRlX29mX3B1YmxpY2F0aW9uKSAlPiUgbXV0YXRlKHRvdF9jYXNlc19uID0gMSwgdHlwZSA9ICJzaW5nbGUiKSkKCmV2b19jYXNlcyA8LSBwYWQoZXZvX2Nhc2VzKQpldm9fY2FzZXMkdG90X2Nhc2VzX25baXMubmEoZXZvX2Nhc2VzJHRvdF9jYXNlc19uKV0gPC0gMApldm9fY2FzZXMkY3VtcGxvdCA8LSBjdW1zdW0oZXZvX2Nhc2VzJHRvdF9jYXNlc19uKQoKZnVsbF9kYXRhIDwtIG1lcmdlKGV2b19jYXNlcywgYWxsX2dsb2JfY2FzZXMsIGFsbCA9IFRSVUUpCgpwMSA8LSBnZ3Bsb3QoZnVsbF9kYXRhICwgYWVzKHggPSBkYXRlX29mX3B1YmxpY2F0aW9uLCB5ID0gY3VtcGxvdCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIsIGNvbCA9IHdlc19wYWxldHRlKCJSb3lhbDEiKVsyXSwgZmlsbCA9IHdlc19wYWxldHRlKCJSb3lhbDEiKVsyXSkgKyAKICB0aGVtZV9idygpICsgZ2VvbV9saW5lKGFlcyh4ID0gZGF0ZV9vZl9wdWJsaWNhdGlvbiwgeSA9IG5ld2Nhc2Vfcm9sbDcvMTc1KSkgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJjdW11bGF0aXZlIG51bWJlciBvZiBjYXNlcyIsIHRpdGxlID0gIk51bWJlciBvZiBwdWJsaXNoZWQgY2FzZXMiKSArICBzY2FsZV94X2RhdGUobGltaXRzID0gYXMuRGF0ZShjKCcyMDIwLTAxLTE1JywnMjAyMC0wOC0xNCcpKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAiY3VtdWxhdGl2ZSBudW1iZXIgb2YgcHVibGlzaGVkIGNhc2VzIiwgCiAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4gLiAqIDE3NSwgbmFtZSA9ICJuZXcgQ09WSUQtMTkgY2FzZXMgKDctZGF5IGF2ZXJhZ2UpIikKICApCgpwMSAKCmdnc2F2ZShwMSwgZmlsZW5hbWUgPSAiLi9wbG90cy9jb3ZpZF9ldm9fdG90YWwucG5nIiwgZHBpID0gMzAwLCBoZWlnaHQ9Nywgd2lkdGg9MTApCmdnc2F2ZShwMSwgZmlsZW5hbWUgPSAiLi9wbG90cy9jb3ZpZF9ldm9fdG90YWwuc3ZnIiwgZHBpID0gMzAwLCBoZWlnaHQ9Nywgd2lkdGg9MTApCmdnc2F2ZShwMSwgZmlsZW5hbWUgPSAiLi9wbG90cy9jb3ZpZF9ldm9fdG90YWwucGRmIiwgZHBpID0gMzAwLCBoZWlnaHQ9Nywgd2lkdGg9MTApCgoKCmFsbF9nbG9iX2Nhc2VzIDwtIGdsb2JhbF9jYXNlcyAlPiUgZ3JvdXBfYnkoZGF0ZV9vZl9wdWJsaWNhdGlvbiwgY291bnRyeSkgJT4lIHN1bW1hcmlzZSh0b3RhbF9jYXNlcyA9IHN1bSh0b3RfY2FzZXNfY292aWQpKSAlPiUgdW5ncm91cCgpCgoKYWxsX2dsb2JfY2FzZXMgPC0gYWxsX2dsb2JfY2FzZXMgJT4lIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIG11dGF0ZShuZXdjYXNlcyA9IGZpcnN0ZGlmZih0b3RhbF9jYXNlcykpICU+JSB1bmdyb3VwKCkKCiNhbGxfZ2xvYl9jYXNlcyRuZXdjYXNlcyA8LSBmaXJzdGRpZmYoYWxsX2dsb2JfY2FzZXMkdG90YWxfY2FzZXMpCmFsbF9nbG9iX2Nhc2VzIDwtIGFsbF9nbG9iX2Nhc2VzICU+JSBncm91cF9ieShjb3VudHJ5KSAgJT4lIG11dGF0ZShuZXdjYXNlX3JvbGw3ID0gem9vOjpyb2xsbWVhbihuZXdjYXNlcywgayA9IDcsIGZpbGwgPSBOQSkpIAoKZXZvX2Nhc2VzIDwtIHJiaW5kKGRmX2NvaG9ydCAlPiUgc2VsZWN0KHRvdF9jYXNlc19uLCBkYXRlX29mX3B1YmxpY2F0aW9uLCBjb3VudHJ5KSAlPiUgbXV0YXRlKHR5cGUgPSAiY29ob3J0IiksIAogICAgICAgICAgICAgICAgICAgZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChkYXRlX29mX3B1YmxpY2F0aW9uLCBjb3VudHJ5KSAlPiUgbXV0YXRlKHRvdF9jYXNlc19uID0gMSwgdHlwZSA9ICJzaW5nbGUiKSkKCmNvdW50cnlfYmFycGxvdCA8LSBldm9fY2FzZXMKCmV2b19jYXNlcyA8LSBwYWQoZXZvX2Nhc2VzKQojZXZvX2Nhc2VzJHRvdF9jYXNlc19uW2lzLm5hKGV2b19jYXNlcyR0b3RfY2FzZXNfbildIDwtIDAKI2V2b19jYXNlcyR0b3RfY2FzZXNfbltpcy5uYShldm9fY2FzZXMkdG90X2Nhc2VzX24pXSA8LSAwCmV2b19jYXNlcyA8LSBldm9fY2FzZXMgJT4lIGdyb3VwX2J5KGNvdW50cnkpICU+JSBtdXRhdGUoY3VtcGxvdCA9IGN1bXN1bSh0b3RfY2FzZXNfbikpICU+JSB1bmdyb3VwKCkKZXZvX2Nhc2VzIDwtIGV2b19jYXNlcyAlPiUgZmlsbChjb3VudHJ5KQoKCmZ1bGxfZGF0YSA8LSBtZXJnZShldm9fY2FzZXMsIGFsbF9nbG9iX2Nhc2VzLCBhbGwgPSBUUlVFKQpmdWxsX2RhdGFfZmlsdCA8LSBmdWxsX2RhdGEgJT4lIGZpbHRlcihjb3VudHJ5ID09ICJVbml0ZWQgS2luZ2RvbSIgIHwgY291bnRyeSA9PSAiSXRhbHkiIHwgY291bnRyeSA9PSAiRnJhbmNlIiB8IGNvdW50cnkgPT0gIlVTIikKCmZ1bGxfZGF0YV9maWx0IDwtIGZ1bGxfZGF0YV9maWx0ICU+JSBtdXRhdGUoY29udGluZW50ID0gaWZlbHNlKGNvdW50cnkgPT0gIlVTIiwgIlVTIiwgIkV1cm9wZSIpKQoKcDEgPC0gZ2dwbG90KGZ1bGxfZGF0YV9maWx0ICwgYWVzKHggPSBkYXRlX29mX3B1YmxpY2F0aW9uLCB5ID0gY3VtcGxvdCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIsIGFlcyhmaWxsID0gY291bnRyeSwgY29sID0gY291bnRyeSkpICsgCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVtjKDEsMyw0LDIpXSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpW2MoMSwzLDQsMildKSArCiAgZ2VvbV9saW5lKGFlcyh4ID0gZGF0ZV9vZl9wdWJsaWNhdGlvbiwgeSA9IG5ld2Nhc2Vfcm9sbDcvMTAwLCBjb2wgPSBjb3VudHJ5KSkgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJjdW11bGF0aXZlIG51bWJlciBvZiBjYXNlcyAoYmFycykiLCB0aXRsZSA9ICJOdW1iZXIgb2YgcHVibGlzaGVkIGNhc2VzLCBwZXIgY291bnRyeSIpICsKICBzY2FsZV94X2RhdGUobGltaXRzID0gYXMuRGF0ZShjKCcyMDIwLTAzLTAxJywnMjAyMC0wOC0xNCcpKSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoICAgICJjdW11bGF0aXZlIG51bWJlciBvZiBwdWJsaXNoZWQgY2FzZXMgKGJhcnMpIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4gLiAqIDEwMCwgbmFtZSA9ICJuZXcgQ09WSUQtMTkgY2FzZXMgKDctZGF5IGF2ZXJhZ2UsIGxpbmVzKSIpIAogICkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsgCiAgZmFjZXRfd3JhcCh+Y29udGluZW50LCBzY2FsZXMgPSAiZnJlZV95IikKCnAxCgpnZ3NhdmUocDEsIGZpbGVuYW1lID0gIi4vcGxvdHMvY292aWRfZXZvX3BlcmNvdW50cnkucG5nIiwgZHBpID0gMzAwLCBoZWlnaHQ9Nywgd2lkdGg9MTApCmdnc2F2ZShwMSwgZmlsZW5hbWUgPSAiLi9wbG90cy9jb3ZpZF9ldm9fcGVyY291bnRyeS5zdmciLCBkcGkgPSAzMDAsIGhlaWdodD03LCB3aWR0aD0xMCkKZ2dzYXZlKHAxLCBmaWxlbmFtZSA9ICIuL3Bsb3RzL2NvdmlkX2V2b19wZXJjb3VudHJ5LnBkZiIsIGRwaSA9IDMwMCwgaGVpZ2h0PTcsIHdpZHRoPTEwKQoKYGBgCgojIyBQSU1TIGNhc2VzIGJ5IGNvdW50cnkgCgpgYGB7cn0KCmdncGxvdChjb3VudHJ5X2JhcnBsb3QsIGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCAtdG90X2Nhc2VzX24pLCB5ID0gdG90X2Nhc2VzX24sIGZpbGwgPSB0eXBlKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKwogIHRoZW1lX2J3KCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJSb3lhbDEiKSkgKyAKICBsYWJzKHggPSAiQ291bnRyeSIsIHkgPSAiVG90YWwgY2FzZXMiLCB0aXRsZSA9ICJDYXNlcyBwZXIgY291bnRyaWVzIGluIGRhdGFzZXQiKSArIAogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3Q9MSkpCgpgYGAKCgojIyBUb3RhbCBjYXNlcyBhbmQgZGVhdGhzCmBgYHtyfQojdmFyX2lkX2NvaG9ydCA9ICJvdXRjb21lX2RlYXRoX24iCiN2YXJfaWRfc2luZ2xlID0gIm91dGNvbWVfZGVhdGgiCiN2YXJfaWQgPSAiZGVhdGhzIgptYWtlQmFycGxvdCgib3V0Y29tZV9kZWF0aF9uIiwgIm91dGNvbWVfZGVhdGgiLCAiZGVhdGhzIikKYGBgCgojIyBTZXggYW5kIGFnZSBkaXN0cmlidXRpb24KYGBge3J9Cm5fY29ob3J0IDwtIGRmX2NvaG9ydCAlPiUgc2VsZWN0KHRvdF9jYXNlc19uKSAlPiUgc3VtKCkKdmFyX2NvaG9ydCA8LSBkZl9jb2hvcnQgJT4lIHNlbGVjdChjb250YWlucygic2V4IikpCnZhcl9jb2hvcnQgPC0gY29sU3Vtcyh2YXJfY29ob3J0LCBuYS5ybSA9IFRSVUUpCnZhcl9jb2hvcnQgPC0gdmFyX2NvaG9ydC9zdW0oZGZfY29ob3J0JHRvdF9jYXNlc19uKSoxMDAKdmFyX2NvaG9ydFsic2V4X25hIl0gPC0gKDEwMCAtIHZhcl9jb2hvcnRbInNleF9tIl0gLSB2YXJfY29ob3J0WyJzZXhfZiJdKQoKdmFyX2NvbnRyb2wgPC0gZGZfY29ob3J0X2NvbnRyb2xzICU+JSBmaWx0ZXIoY29ob3J0X2lkID09ICJQb3VsZXR0eSAtIGhpc3Rvci4gS0QiKSAlPiUgc2VsZWN0KGNvbnRhaW5zKCJzZXgiKSkKdmFyX2NvbnRyb2wgPC0gY29sU3Vtcyh2YXJfY29udHJvbCwgbmEucm0gPSBUUlVFKQp2YXJfY29udHJvbCA8LSB2YXJfY29udHJvbC9zdW0oZGZfY29ob3J0X2NvbnRyb2xzICU+JSBmaWx0ZXIoY29ob3J0X2lkID09ICJQb3VsZXR0eSAtIGhpc3Rvci4gS0QiKSAlPiUgc2VsZWN0KHRvdF9jYXNlc19uKSkqMTAwCnZhcl9jb250cm9sWyJzZXhfbmEiXSA8LSAoMTAwIC0gdmFyX2NvbnRyb2xbInNleF9tIl0gLSB2YXJfY29udHJvbFsic2V4X2YiXSkKCm5fc2luZ2xlIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBucm93KCkKdmFyX3NpbmdsZSA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgc2VsZWN0KGNvbnRhaW5zKCJzZXgiKSkKdmFyX3NpbmdsZSRzZXhfbSA8LSBpZmVsc2UodmFyX3NpbmdsZSRzZXggPT0gIk0iLCBUUlVFLCBGQUxTRSkKdmFyX3NpbmdsZSRzZXhfZiA8LSBpZmVsc2UodmFyX3NpbmdsZSRzZXggPT0gIkYiLCBUUlVFLCBGQUxTRSkKY29scyA8LSBzYXBwbHkodmFyX3NpbmdsZSwgaXMubG9naWNhbCkKdmFyX3NpbmdsZVssY29sc10gPC0gbGFwcGx5KHZhcl9zaW5nbGVbLGNvbHNdLCBhcy5udW1lcmljKQp2YXJfc2luZ2xlIDwtIGNvbFN1bXModmFyX3NpbmdsZSAlPiUgc2VsZWN0KC1zZXgpLCBuYS5ybSA9IFRSVUUpCnZhcl9zaW5nbGUgPC0gdmFyX3NpbmdsZS9ucm93KGRmX3NpbmdsZWNhc2VzKSoxMDAKdmFyX3NpbmdsZVsic2V4X25hIl0gPC0gKDEwMCAtIHZhcl9zaW5nbGVbInNleF9tIl0gLSB2YXJfc2luZ2xlWyJzZXhfZiJdKQoKYmFyX2RmX3ByY3QgPC0gZGF0YS5mcmFtZSgKICB4ID0gYygibWFsZXMiLCAiZmVtYWxlcyIsICJtaXNzaW5nIiwgIm1hbGVzIiwgImZlbWFsZXMiLCAibWlzc2luZyIsICJtYWxlcyIsICJmZW1hbGVzIiwgIm1pc3NpbmciKSwKICB2YWxzID0gYyh2YXJfc2luZ2xlLCB2YXJfY29ob3J0LCB2YXJfY29udHJvbCksCiAgY29sID0gYyhyZXAoInNpbmdsZSIsIGxlbmd0aCh2YXJfc2luZ2xlKSksIHJlcCgiY29ob3J0cyIsIGxlbmd0aCh2YXJfY29ob3J0KSksIHJlcCgiaGlzdG9yIGN0cmwiLCBsZW5ndGgodmFyX2NvbnRyb2wpKQogICkpCgpwX3ByY3QgPC0gZ2dwbG90KGJhcl9kZl9wcmN0LCBhZXMoeCA9IGNvbCwgeSA9ICB2YWxzLCBmaWxsID0geCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArCiAgdGhlbWVfYncoKSArIAogIGxhYnModGl0bGUgPSAiTWFsZS9mZW1hbGUgZGlzdHJpYnV0aW9uIGluIGRhdGFzZXQiLCBzdWJ0aXRsZSA9ICJQZXJjZW50IiwgeCA9ICJzZXgiLCB5ID0gIiUiLCBjb2wgPSAiICIpICArIGxpbXMoeSA9IGMoMCwxMDApKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3Q9MSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpKQpwX3ByY3QKYGBgCgoKYGBge3J9CnZhcl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSBzZWxlY3QoY29udGFpbnMoInNleCIpIHwgKCJjb2hvcnRfaWQiKSB8ICJ0b3RfY2FzZXNfbiIpCnNleF9mIDwtIHZhcl9jb2hvcnQgJT4lIGdyb3VwX2J5KGNvaG9ydF9pZCkgJT4lIHN1bW1hcml6ZShwcmN0ID0gc2V4X2YvdG90X2Nhc2VzX24pICU+JSAgbXV0YXRlKHNleCA9ICJmZW1hbGUiKQpzZXhfbSA8LSB2YXJfY29ob3J0ICU+JSBncm91cF9ieShjb2hvcnRfaWQpICU+JSBzdW1tYXJpemUocHJjdCA9IHNleF9tL3RvdF9jYXNlc19uKSAlPiUgbXV0YXRlKHNleCA9ICJtYWxlIikKc2V4X2FsbCA8LSByYmluZChzZXhfZiwgc2V4X20pCgpwX3NleF9jb2hvcnQgPC0gZ2dwbG90KHNleF9hbGwsIGFlcyh5ID0gY29ob3J0X2lkLCB4ID0gcHJjdCwgZmlsbCA9IHNleCkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArIAogIHRoZW1lX2J3KCkgKyBsYWJzKHggPSAiIikgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIikpCgp2YXJfY29udHJvbHMgPC0gZGZfY29ob3J0X2NvbnRyb2xzICU+JSBmaWx0ZXIoY29ob3J0X2lkID09ICJQb3VsZXR0eSAtIGhpc3Rvci4gS0QiKSAlPiUgc2VsZWN0KGNvbnRhaW5zKCJzZXgiKSB8ICgiY29ob3J0X2lkIikgfCAidG90X2Nhc2VzX24iKQpzZXhfZiA8LSB2YXJfY29udHJvbHMgJT4lIGdyb3VwX2J5KGNvaG9ydF9pZCkgJT4lIHN1bW1hcml6ZShwcmN0ID0gc2V4X2YvdG90X2Nhc2VzX24pICU+JSBtdXRhdGUoc2V4ID0gImZlbWFsZSIpCnNleF9tIDwtIHZhcl9jb250cm9scyAlPiUgZ3JvdXBfYnkoY29ob3J0X2lkKSAlPiUgc3VtbWFyaXplKHByY3QgPSBzZXhfbS90b3RfY2FzZXNfbikgJT4lIG11dGF0ZShzZXggPSAibWFsZSIpCnNleF9hbGwgPC0gcmJpbmQoc2V4X2YsIHNleF9tKQoKcF9zZXhfY29udHJvbHMgPC0gZ2dwbG90KHNleF9hbGwsIGFlcyh5ID0gY29ob3J0X2lkLCB4ID0gcHJjdCwgZmlsbCA9IHNleCkpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImZpbGwiKSArIAogIHRoZW1lX2J3KCkgKyBsYWJzKHggPSAiIikgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIikpCgpuX3NpbmdsZSA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbnJvdygpCnZhcl9zaW5nbGUgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb250YWlucygic2V4IikpCnZhcl9zaW5nbGUkc2V4X20gPC0gaWZlbHNlKHZhcl9zaW5nbGUkc2V4ID09ICJNIiwgVFJVRSwgRkFMU0UpCnZhcl9zaW5nbGUkc2V4X2YgPC0gaWZlbHNlKHZhcl9zaW5nbGUkc2V4ID09ICJGIiwgVFJVRSwgRkFMU0UpCmNvbHMgPC0gc2FwcGx5KHZhcl9zaW5nbGUsIGlzLmxvZ2ljYWwpCnZhcl9zaW5nbGVbLGNvbHNdIDwtIGxhcHBseSh2YXJfc2luZ2xlWyxjb2xzXSwgYXMubnVtZXJpYykKdmFyX3NpbmdsZSA8LSBjb2xTdW1zKHZhcl9zaW5nbGUgJT4lIHNlbGVjdCgtc2V4KSwgbmEucm0gPSBUUlVFKQp2YXJfc2luZ2xlIDwtIHZhcl9zaW5nbGUvbnJvdyhkZl9zaW5nbGVjYXNlcykqMTAwCgpzZXhfc2luZ2xlIDwtIGRhdGEuZnJhbWUoY29ob3J0X2lkID0gInNpbmdsZV9jYXNlcyIsIHByY3QgPSBjKHZhcl9zaW5nbGVbInNleF9tIl0sIHZhcl9zaW5nbGVbInNleF9mIl0pLCBzZXggPSBjKCJtYWxlIiwgImZlbWFsZSIpKQoKcF9zZXhfc2luZ2xlIDwtIGdncGxvdChzZXhfc2luZ2xlLCBhZXMoeSA9IGNvaG9ydF9pZCwgeCA9IHByY3QsIGZpbGwgPSBzZXgpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJmaWxsIikgKyAKICB0aGVtZV9idygpICsgCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpKQoKYSA8LSBwbG90X2dyaWQocF9zZXhfY29ob3J0LCBwX3NleF9jb250cm9scywgcF9zZXhfc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDMsIHJlbF9oZWlnaHRzID0gYyg1LzcsIDEvNywgMS83KSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0gOCwgZmlnLndpZHRoPSA2fQpjb2hvcnRfYWdlIDwtIGRmX2NvaG9ydF9jb250cm9scyAlPiUgc2VsZWN0KGNvbnRhaW5zKCJjb2hvcnRfaWQiKSB8IGNvbnRhaW5zKCJhZ2UiKSB8IGNvbnRhaW5zKCJjb2hvcnRfdHlwZSIpICB8IGNvbnRhaW5zKCJ0b3RfY2FzZXNfbiIpKQpjb2hvcnRfYWdlJGNvaG9ydF9pZCA8LSBwYXN0ZTAoY29ob3J0X2FnZSRjb2hvcnRfaWQsICIgKG4gPSAiLCBjb2hvcnRfYWdlJHRvdF9jYXNlc19uLCIpIikKY29ob3J0X2FnZSRhZ2VfbWVkX3lycyA8LSBhcy5udW1lcmljKGNvaG9ydF9hZ2UkYWdlX21lZF95cnMgKQpjb2hvcnRfYWdlJGFnZV9RMV95cnMgPC0gYXMubnVtZXJpYyhjb2hvcnRfYWdlJGFnZV9RMV95cnMpCmNvaG9ydF9hZ2UkYWdlX1EzX3lycyA8LSBhcy5udW1lcmljKGNvaG9ydF9hZ2UkYWdlX1EzX3lycykKY29ob3J0X2FnZSRhZ2VfbWluX3lycyA8LSBhcy5udW1lcmljKGNvaG9ydF9hZ2UkYWdlX21pbl95cnMpCmNvaG9ydF9hZ2UkYWdlX21heF95cnMgPC0gYXMubnVtZXJpYyhjb2hvcnRfYWdlJGFnZV9tYXhfeXJzKQoKY29ob3J0X2FnZSRkYXRhX2Rlc2NyIDwtIGlmZWxzZSghaXMubmEoY29ob3J0X2FnZSRhZ2VfUTFfeXJzKSAmIGlzLm5hKGNvaG9ydF9hZ2UkYWdlX21pbl95cnMpICwgIklRUiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShpcy5uYShjb2hvcnRfYWdlJGFnZV9RMV95cnMpICYgIWlzLm5hKGNvaG9ydF9hZ2UkYWdlX21pbl95cnMpLCAicmFuZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKCFpcy5uYShjb2hvcnRfYWdlJGFnZV9RMV95cnMpICYgIWlzLm5hKGNvaG9ydF9hZ2UkYWdlX21pbl95cnMpLCAiYm90aCIsICJub25lIikpKQoKcF9hZ2VfY29ob3J0IDwtIGdncGxvdChjb2hvcnRfYWdlICU+JSBmaWx0ZXIoY29ob3J0X3R5cGUgPT0gIk1JUy1DIiksIGFlcyh5ID0gY29ob3J0X2lkLCB4ID0gYWdlX21lZF95cnMsIGNvbCA9IGRhdGFfZGVzY3IpKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDQpICsgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1hZ2VfUTFfeXJzLCB4bWF4PWFnZV9RM195cnMpLCB3aWR0aD0uOCwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoLjkpKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1hZ2VfbWluX3lycywgIHhtYXg9YWdlX21heF95cnMpLCB3aWR0aD0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoLjkpKSArCiAgdGhlbWVfYncoKSArIGxpbXMoeCA9IGMoMCwyMSkpICsgCiAgbGFicyh5ID0gImNvaG9ydCIsIHggPSAiIiwgY29sID0gImJhcnMiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIikrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMod2VzX3BhbGV0dGUoIkJvdHRsZVJvY2tldDIiKVsxOjNdLCB3ZXNfcGFsZXR0ZSgiQm90dGxlUm9ja2V0MSIpWzJdKSkKCnBfYWdlX2NvbnRyb2xzIDwtIGdncGxvdChjb2hvcnRfYWdlICU+JSBmaWx0ZXIoY29ob3J0X3R5cGUgIT0gIk1JUy1DIiksIGFlcyh5ID0gY29ob3J0X2lkLCB4ID0gYWdlX21lZF95cnMsIGNvbCA9IGRhdGFfZGVzY3IpKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDQpICsgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1hZ2VfUTFfeXJzLCB4bWF4PWFnZV9RM195cnMpLCB3aWR0aD0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoLjkpKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1hZ2VfbWluX3lycywgIHhtYXg9YWdlX21heF95cnMpLCB3aWR0aD0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoLjkpKSArCiAgdGhlbWVfYncoKSArIGxpbXMoeCA9IGMoMCwyMSkpICsKICBsYWJzKHkgPSAiY29ob3J0IiwgeCA9ICIiLCBjb2wgPSAiYmFycyIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikrCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJCb3R0bGVSb2NrZXQyIilbMl0pCgpwX2FnZV9zaW5nbGUgPC0gZ2dwbG90KGRmX3NpbmdsZWNhc2VzLCBhZXMoeCA9IGFzLm51bWVyaWMoYWdlKSwgeSA9IHBhc3RlMCgic2luZ2xlIGNhc2VzIChuID0gIiwgbl9zaW5nbGUsIikiKSkpICsKICBnZW9tX3Zpb2xpbihmaWxsID0gd2VzX3BhbGV0dGUoIkRhcmplZWxpbmcyIilbNF0pICsgCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4zLCBmaWxsID0gd2VzX3BhbGV0dGUoIkRhcmplZWxpbmcyIilbMV0pICsgCiAgdGhlbWVfYncoKSArIGdlb21fYmVlc3dhcm0oZ3JvdXBPblg9RkFMU0UsIGFscGhhID0gMC41KSArIGxpbXMoeCA9IGMoMCwyMSkpICsgCiAgbGFicyh5ID0gImNvaG9ydCIsIHggPSAiQWdlICh5ZWFycykiKQoKYSA8LSBwbG90X2dyaWQocF9hZ2VfY29ob3J0LCBwX2FnZV9jb250cm9scywgcF9hZ2Vfc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDMsIHJlbF9oZWlnaHRzID0gYygyLzMsIDEvNSwgMS8zKSkKYGBgCgohW10oLi9wbG90cy9kZW1vX2dyaWRfcGxvdHMucG5nKQoKIyMgU3ltcHRvbXMgCiMjIyBTaW5nbGUgY2FzZXMgey50YWJzZXR9CiMjIyMgQWxsIHN5bXB0b21zCldoZXJlIGFwcGxpY2FibGUsIG92ZXJsYXAgb2YgdmFyaWFibGUgaW4gdGhlIHNpbmdsZSBjYXNlIGdyb3VwIHdhcyBzdW1tYXJpemVkIHdpdGggW1Vwc2V0IHBsb3RzIChMZXggJiBHZWhsZW5ib3JnLCBOYXR1cmUgTWV0aG9kcywgMjAxNCldKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvbm1ldGguMzAzMykuCgpgYGB7cn0KbWFrZVVwc2V0UiA8LSBmdW5jdGlvbihpbnB1dF9kZil7CiAgdmFyX3NpbmdsZSA8LSBpbnB1dF9kZiAKICBjb2xzIDwtIHNhcHBseSh2YXJfc2luZ2xlLCBpcy5sb2dpY2FsKQogIHZhcl9zaW5nbGVbLGNvbHNdIDwtIGxhcHBseSh2YXJfc2luZ2xlWyxjb2xzXSwgYXMubnVtZXJpYykKICAKICB2YXJfc2luZ2xlX3Vwc2V0ciA8LSB2YXJfc2luZ2xlIAogIHZhcl9zaW5nbGVfdXBzZXRyW2lzLm5hKHZhcl9zaW5nbGVfdXBzZXRyKV0gPC0gMAogIHZhcl9zaW5nbGVfdXBzZXRyIDwtIGFzLmRhdGEuZnJhbWUodmFyX3NpbmdsZV91cHNldHIpCiAgZm9yKGkgaW4gMTpuY29sKHZhcl9zaW5nbGVfdXBzZXRyKSl7IHZhcl9zaW5nbGVfdXBzZXRyWyAsIGldIDwtIGFzLmludGVnZXIodmFyX3NpbmdsZV91cHNldHJbICwgaV0pIH0KICB1cHNldCh2YXJfc2luZ2xlX3Vwc2V0ciwgc2V0cyA9IGMoY29sbmFtZXModmFyX3NpbmdsZV91cHNldHIpKSwgc2V0cy5iYXIuY29sb3IgPSAiIzU2QjRFOSIsCiAgICAgICAgb3JkZXIuYnkgPSAiZnJlcSIsIGtlZXAub3JkZXIgPSBUUlVFKSMsIGVtcHR5LmludGVyc2VjdGlvbnMgPSAib24iLCBrZWVwLm9yZGVyID0gRkFMU0UpCn0KCm1ha2VVcHNldFIoZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb250YWlucyggInN5bXAiKSkgJT4lIHNlbGVjdChjb250YWlucygiYW55IikpKQpgYGAKCiMjIyMgUmVzcGlyYXRvcnkKYGBge3J9Cm1ha2VVcHNldFIoZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb250YWlucygic3ltcCIpKSAlPiUgc2VsZWN0KGNvbnRhaW5zKCJyZXNwIikpICU+JSBzZWxlY3QoLWNvbnRhaW5zKCJhbnkiKSkpCmBgYAoKIyMjIyBDYXJkaW92YXNjdWxhcgpgYGB7cn0KbWFrZVVwc2V0UihkZl9zaW5nbGVjYXNlcyAlPiUgc2VsZWN0KGNvbnRhaW5zKCJzeW1wIikpICU+JSBzZWxlY3QoY29udGFpbnMoImNhcmRpb3Zhc2MiKSkgJT4lIHNlbGVjdCgtY29udGFpbnMoIkxWRUYiKSkgJT4lIHNlbGVjdCgtY29udGFpbnMoImFueSIpKSkKYGBgCgojIyMjIEdJCmBgYHtyfQptYWtlVXBzZXRSKGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QoY29udGFpbnMoInN5bXAiKSkgJT4lIHNlbGVjdChjb250YWlucygiR0kiKSkgJT4lIHNlbGVjdCgtY29udGFpbnMoIm5ldXJvIikpICU+JSBzZWxlY3QoLWNvbnRhaW5zKCJhbnkiKSkpCmBgYAoKIyMjIFNpbmdsZSBjYXNlcyArIGNvaG9ydCB7LnRhYnNldH0KIyMjIyBSZXNwaXJhdG9yeQpgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aD0gNn0KYmFyU3ltcCA8LSBmdW5jdGlvbihjb2xuYW1lX2Nob3J0LCBjb2xuYW1lX3NpbmdsZSwgZXhjbHVkZV9zaW5nbGUgPSBOVUxMLCBwbG90dGl0bGUpewogIAogIHZhcl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSAKICAgIHNlbGVjdChjb250YWlucygiY29ob3J0X2lkIikgfCBjb250YWlucygidG90X2Nhc2VzX24iKSB8IChjb250YWlucyhjb2xuYW1lX2Nob3J0KSAmIGNvbnRhaW5zKCJfbiIpKSkKICAKICB2YXJfY29ob3J0IDwtIHZhcl9jb2hvcnQgJT4lIAogICAgZ2F0aGVyKHZhcmlhYmxlLCB2YWx1ZSwgMzpuY29sKHZhcl9jb2hvcnQpKSAlPiUgCiAgICBkcm9wX25hKHZhbHVlKSAgJT4lIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUgCiAgICBzdW1tYXJpemUocHJjdCA9IHN1bSh2YWx1ZSkvc3VtKHRvdF9jYXNlc19uKSoxMDApCiAgCiAgdmFyX2NvaG9ydCA8LSBzZXROYW1lcyh2YXJfY29ob3J0JHByY3QsIHZhcl9jb2hvcnQkdmFyaWFibGUpCiAgbmFtZXModmFyX2NvaG9ydCkgPC0gc3ViKCJfbiIsICIiLCBuYW1lcyh2YXJfY29ob3J0KSkKICAKICBuX3NpbmdsZSA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbnJvdygpCiAgCiAgaWYgKCFpcy5udWxsKGV4Y2x1ZGVfc2luZ2xlKSl7CiAgICB2YXJfc2luZ2xlIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QoLWNvbnRhaW5zKGV4Y2x1ZGVfc2luZ2xlKSkKICAgIHZhcl9zaW5nbGUgPC0gdmFyX3NpbmdsZSAlPiUgc2VsZWN0KGNvbnRhaW5zKGNvbG5hbWVfc2luZ2xlKSkKICB9IGVsc2UKICB7CiAgICB2YXJfc2luZ2xlIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QoY29udGFpbnMoY29sbmFtZV9zaW5nbGUpKQogIH0KICAKICAjJT4lIHNlbGVjdCgtY29udGFpbnMoImFueSIpKQogIGNvbHMgPC0gc2FwcGx5KHZhcl9zaW5nbGUsIGlzLmxvZ2ljYWwpCiAgdmFyX3NpbmdsZVssY29sc10gPC0gbGFwcGx5KHZhcl9zaW5nbGVbLGNvbHNdLCBhcy5udW1lcmljKQogIHZhcl9zaW5nbGUgPC0gY29sU3Vtcyh2YXJfc2luZ2xlLCBuYS5ybSA9IFRSVUUpCiAgdmFyX3NpbmdsZSA8LSB2YXJfc2luZ2xlL25yb3coZGZfc2luZ2xlY2FzZXMpKjEwMAogIAogIGJhcl9kZl9wcmN0IDwtIGRhdGEuZnJhbWUoCiAgICB4ID0gYyhuYW1lcyh2YXJfc2luZ2xlKSwgbmFtZXModmFyX2NvaG9ydCkpLAogICAgdmFscyA9IGModmFyX3NpbmdsZSwgdmFyX2NvaG9ydCksCiAgICBjb2wgPSBjKHJlcCgic2luZ2xlIiwgbGVuZ3RoKHZhcl9zaW5nbGUpKSwgcmVwKCJjb2hvcnRzIiwgbGVuZ3RoKHZhcl9jb2hvcnQpKSkKICApCiAgCiAgcF9wcmN0IDwtIGdncGxvdChiYXJfZGZfcHJjdCwgYWVzKHggPSB4LCB5ID0gIHZhbHMsIGZpbGwgPSBjb2wpKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgICB0aGVtZV9idygpICsgCiAgICBsYWJzKHRpdGxlID0gcGxvdHRpdGxlLCAKICAgICAgICAgc3VidGl0bGUgPSAiUGVyY2VudCBvZiBncm91cCIsIHggPSAidHJlYXRtZW50IiwgeSA9ICIlIiwgY29sID0gIiAiKSAgKyAKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3Q9MSksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIikpCiAgcF9wcmN0Cn0KYGBgCgpgYGB7ciBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoPSA2fQptYWtlSGVhdG1hcF9jb2hvcnQoInN5bXBfcmVzcCIsICJzeW1wX3Jlc3AiLCBwbG90dGl0bGUgPSAiQ2FzZXMgd2l0aCByZXNwaXJhdG9yeSBzeW1wdG9tcywgcGVyIGNvaG9ydCIpCmBgYAoKYGBge3J9CmJhclN5bXAoInN5bXBfcmVzcCIsICJzeW1wX3Jlc3AiLCBwbG90dGl0bGUgPSAiQ2FzZXMgd2l0aCByZXNwaXJhdG9yeSBzeW1wdG9tcyIpCmBgYAoKCmBgYHtyfQojIHZhcl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSBzZWxlY3QoKCJjb2hvcnRfaWQiKSB8ICJ0b3RfY2FzZXNfbiIgfCggY29udGFpbnMoInN5bXBfcmVzcCIpICYgY29udGFpbnMoIm4iKSkpCiMgCiMgcmVzcF9zeW1wX2NvaG9ydCA8LSB2YXJfY29ob3J0ICU+JSAKIyAgIGdhdGhlcih2YXJpYWJsZSwgdmFsdWUsIDM6bmNvbCh2YXJfY29ob3J0KSkgJT4lIGdyb3VwX2J5KGNvaG9ydF9pZCwgdmFyaWFibGUpICU+JSBzdW1tYXJpemUocHJjdCA9IHZhbHVlL3RvdF9jYXNlc19uKQojIAojIGdncGxvdChyZXNwX3N5bXBfY29ob3J0LCBhZXMoeCA9IHByY3QsIHkgPSBjb2hvcnRfaWQsIGNvbCA9IHZhcmlhYmxlKSkgKyBnZW9tX3BvaW50KCkKYGBgCgojIyMjIENhcmRpb3Zhc2N1bGFyCmBgYHtyIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGg9IDh9Cm1ha2VIZWF0bWFwX2NvaG9ydCgic3ltcF9jYXJkaW92YXNjIiwgInN5bXBfY2FyZGlvdmFzYyIsIGV4Y2x1ZGVfc2luZ2xlID0gInN5bXBfY2FyZGlvdmFzY19MVkVGIiwgcGxvdHRpdGxlID0gIkNhc2VzIHdpdGggY2FyZGlvdmFzY3VsYXIgc3ltcHRvbXMsIHBlciBjb2hvcnQiKQpgYGAKCmBgYHtyfQpiYXJTeW1wKCJzeW1wX2NhcmRpb3Zhc2MiLCAic3ltcF9jYXJkaW92YXNjIiwgZXhjbHVkZV9zaW5nbGUgPSAic3ltcF9jYXJkaW92YXNjX0xWRUYiLCBwbG90dGl0bGUgPSAiQ2FzZXMgd2l0aCBjYXJkaW92YXNjdWxhciBzeW1wdG9tcyIpCmBgYAoKIyMjIyBHYXN0cm8taW50ZXN0aW5hbApgYGB7ciBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoPSA2fQptYWtlSGVhdG1hcF9jb2hvcnQoInN5bXBfR0kiLCAic3ltcF9HSSIsIHBsb3R0aXRsZSA9ICJDYXNlcyB3aXRoIEdJIHN5bXB0b21zLCBwZXIgY29ob3J0IikKYGBgCgpgYGB7cn0KYmFyU3ltcCgic3ltcF9HSSIsICJzeW1wX0dJIiwgcGxvdHRpdGxlID0gIkNhc2VzIHdpdGggR0kgc3ltcHRvbXMiKQpgYGAKCiMjIENPVklEIGNvbnRhY3QKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGg9IDh9CnZhcl9jb2hvcnQgPC0gZGZfY29ob3J0ICU+JSBzZWxlY3QoKCJjb2hvcnRfaWQiIHwgInRvdF9jYXNlc19uIikgfCAoIGNvbnRhaW5zKCJjb3ZpZCIpICYgY29udGFpbnMoIl9uIikgJiAoY29udGFpbnMoInBvcyIpIHwgY29udGFpbnMoImNsb3NlY29udCIpICB8IGNvbnRhaW5zKCJhbnkiKSkpKQp2YXJfY29ob3J0JGNvaG9ydF9pZCA8LSBwYXN0ZTAodmFyX2NvaG9ydCRjb2hvcnRfaWQsICIgKG4gPSAiLCBhcy5jaGFyYWN0ZXIodmFyX2NvaG9ydCR0b3RfY2FzZXNfbiksIikiKQoKdmFyX2NvaG9ydCA8LSB2YXJfY29ob3J0ICU+JSAKICBnYXRoZXIodmFyaWFibGUsIHZhbHVlLCAzOm5jb2wodmFyX2NvaG9ydCkpICU+JSBncm91cF9ieShjb2hvcnRfaWQsIHZhcmlhYmxlKSAlPiUgc3VtbWFyaXplKHByY3QgPSB2YWx1ZS90b3RfY2FzZXNfbioxMDApCgp2YXJfY29ob3J0JHZhcmlhYmxlIDwtIHN1Yigibl8iLCAiIiwgdmFyX2NvaG9ydCR2YXJpYWJsZSkKCnZhcl9zaW5nbGUgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb250YWlucygiY292aWQiKSkKY29scyA8LSBzYXBwbHkodmFyX3NpbmdsZSwgaXMubG9naWNhbCkKdmFyX3NpbmdsZVssY29sc10gPC0gbGFwcGx5KHZhcl9zaW5nbGVbLGNvbHNdLCBhcy5udW1lcmljKQp2YXJfc2luZ2xlIDwtIGNvbFN1bXModmFyX3NpbmdsZSwgbmEucm0gPSBUUlVFKQp2YXJfc2luZ2xlIDwtIHZhcl9zaW5nbGUvbnJvdyhkZl9zaW5nbGVjYXNlcykqMTAwCnZhcl9zaW5nbGUgPC0gYXMuZGF0YS5mcmFtZSh2YXJfc2luZ2xlKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkKdmFyX3NpbmdsZSRjb2hvcnRfaWQgPC0gcGFzdGUwKCJzaW5nbGUgY2FzZXMgKG4gPSAiLCBuX3NpbmdsZV9jYXNlcywiKSIpCmNvbG5hbWVzKHZhcl9zaW5nbGUpIDwtIGMoInZhcmlhYmxlIiwgInByY3QiLCAiY29ob3J0X2lkIikKCgptaXNzaW5nIDwtIHNldGRpZmYodmFyX3NpbmdsZSR2YXJpYWJsZSwgdmFyX2NvaG9ydCR2YXJpYWJsZSkKaWYgKGxlbmd0aChtaXNzaW5nKSAhPSAwICl7CiAgbWlzc2luZ19kZiA8LSBkYXRhLmZyYW1lKHZhcmlhYmxlID0gbWlzc2luZywgcHJjdCA9IHJlcChOQSwgbGVuZ3RoKG1pc3NpbmcpKSwgY29ob3J0X2lkID0gcmVwKHVuaXF1ZSh2YXJfY29ob3J0JGNvaG9ydF9pZCksIGxlbmd0aChtaXNzaW5nKSkpCiAgdmFyX2NvaG9ydCA8LSBiaW5kX3Jvd3ModmFyX2NvaG9ydCwgYXNfdGliYmxlKG1pc3NpbmdfZGYpKQp9IAoKbWlzc2luZyA8LSBzZXRkaWZmKHZhcl9jb2hvcnQkdmFyaWFibGUsIHZhcl9zaW5nbGUkdmFyaWFibGUpCgppZiAobGVuZ3RoKG1pc3NpbmcpICE9IDApIHsKICBpZiAobGVuZ3RoKG1pc3NpbmcpICE9IDApewogICAgZGF0YS5mcmFtZSh2YXJpYWJsZSA9IG1pc3NpbmcsIHByY3QgPSByZXAoTkEsIGxlbmd0aChtaXNzaW5nKSksIGNvaG9ydF9pZCA9IHJlcCh1bmlxdWUodmFyX3NpbmdsZSRjb2hvcnRfaWQpLCBsZW5ndGgobWlzc2luZykpKQogICAgdmFyX3NpbmdsZSA8LSBiaW5kX3Jvd3ModmFyX3NpbmdsZSwgYXNfdGliYmxlKG1pc3NpbmdfZGYpKQogIH0KfQoKCmhtX2NvaG9ydCA8LSBnZ3Bsb3QodmFyX2NvaG9ydCwgYWVzKHggPSB2YXJpYWJsZSwgeSA9IGNvaG9ydF9pZCwgZmlsbCA9IHByY3QpKSArIAogIGdlb21fdGlsZSgpICsgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInllbGxvdyIsIGhpZ2g9InJlZCIsIG5hLnZhbHVlID0gImxpZ2h0Z3JheSIsIGxpbWl0cyA9IGMoMCwxMDApKSArCiAgbGFicyh4ID0gIiIsIHkgPSAiY29ob3J0IiwgdGl0bGUgPSAiQ09WSUQgc3ltcHRvbXMsIHBlciBjb2hvcnQiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1yb3VuZChwcmN0LCAyKSksIHNpemUgPSAzLCBjb2xvciA9ICJibGFjayIpCgpobV9zaW5nbGUgPC0gZ2dwbG90KHZhcl9zaW5nbGUsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBjb2hvcnRfaWQsIGZpbGwgPSBwcmN0KSkgKyAKICBnZW9tX3RpbGUoKSArICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3Q9MSksIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInllbGxvdyIsIGhpZ2ggPSAicmVkIiwgbmEudmFsdWUgPSAibGlnaHRncmF5IiwgbGltaXRzID0gYygwLDEwMCkpKyBsYWJzKHkgPSAiY29ob3J0IikgKwogIGdlb21fdGV4dChhZXMobGFiZWw9cm91bmQocHJjdCwgMikpLCBzaXplID0gMywgY29sb3IgPSAiYmxhY2siKSAKCnBsb3RfZ3JpZChobV9jb2hvcnQsIGhtX3NpbmdsZSwgYWxpZ24gPSAidiIsIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMi8zLCAxLzMpKQoKYGBgCgpgYGB7cn0KdmFyX2NvaG9ydCA8LSBkZl9jb2hvcnQgJT4lIAogIHNlbGVjdChjb250YWlucygiY29ob3J0X2lkIikgfCBjb250YWlucygidG90X2Nhc2VzX24iKSB8IGNvbnRhaW5zKCJjb3ZpZCIpICYgY29udGFpbnMoIl9uIikgJiAoY29udGFpbnMoIl9wb3MiKSB8IGNvbnRhaW5zKCJjbG9zZSIpKSkKCmNvdmlkX2NvaG9ydCA8LSB2YXJfY29ob3J0ICU+JSAKICBnYXRoZXIodmFyaWFibGUsIHZhbHVlLCAzOm5jb2wodmFyX2NvaG9ydCkpICU+JSAKICBkcm9wX25hKHZhbHVlKSAgJT4lIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUgCiAgc3VtbWFyaXplKHByY3QgPSBzdW0odmFsdWUpL3N1bSh0b3RfY2FzZXNfbikqMTAwKQoKY292aWRfY29ob3J0IDwtIHNldE5hbWVzKGNvdmlkX2NvaG9ydCRwcmN0LCBjb3ZpZF9jb2hvcnQkdmFyaWFibGUpCgpuX3NpbmdsZSA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgbnJvdygpCnZhcl9zaW5nbGUgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb250YWlucygiY292aWQiKSkgCmNvbHMgPC0gc2FwcGx5KHZhcl9zaW5nbGUsIGlzLmxvZ2ljYWwpCnZhcl9zaW5nbGVbLGNvbHNdIDwtIGxhcHBseSh2YXJfc2luZ2xlWyxjb2xzXSwgYXMubnVtZXJpYykKCm1ha2VVcHNldFIoZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChjb250YWlucygiY292aWQiKSkgJT4lIHNlbGVjdCgtY29udGFpbnMoImNvdmlkX0lnTV9wb3MiKSkgJT4lIHNlbGVjdCgtY29udGFpbnMoImNvdmlkX0lnQV9wb3MiKSkgICU+JSBzZWxlY3QoLWNvbnRhaW5zKCJjb3ZpZF9JZ0dfcG9zIikpICAlPiUgc2VsZWN0KC1jb250YWlucygiY292aWRfc2Vyb19wb3MiKSkgKQoKdmFyX3NpbmdsZSA8LSBjb2xTdW1zKHZhcl9zaW5nbGUsIG5hLnJtID0gVFJVRSkKdmFyX3NpbmdsZSA8LSB2YXJfc2luZ2xlL25yb3coZGZfc2luZ2xlY2FzZXMpKjEwMAoKYmFyX2RmX3ByY3QgPC0gZGF0YS5mcmFtZSgKICB4ID0gYygiY2xvc2UgY29udGFjdCByZXBvcnRlZCIsICJQQ1IgKyIsICJzdG9vbCArIiwiUENSIG9yIHN0b29sIG9yIHNlcm8gKyIsICJhbnkgc2Vyb2xvZ3kgKyIsICJzZXJvICsgZnVydGhlciBOUyIsICJJZ0EgKyIsICJJZ00gKyIsICJJZ0cgKyIsICJjbG9zZSBjb250YWN0IHJlcG9ydGVkIiwgIklnQSArIiwgIklnRyArIiwgIklnTSArIiwgIlBDUiArIiwgInNlcm8gKyBmdXJ0aGVyIE5TIiwgInN0b29sICsiKSwKICB2YWxzID0gYyh2YXJfc2luZ2xlLCBjb3ZpZF9jb2hvcnQpLAogIGNvbCA9IGMocmVwKCJzaW5nbGUiLCBsZW5ndGgodmFyX3NpbmdsZSkpLCByZXAoImNvaG9ydHMiLCBsZW5ndGgoY292aWRfY29ob3J0KSkpCikKCnBfcHJjdCA8LSBnZ3Bsb3QoYmFyX2RmX3ByY3QsIGFlcyh4ID0geCwgeSA9ICB2YWxzLCBmaWxsID0gY29sKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICB0aGVtZV9idygpICsgCiAgbGFicyh0aXRsZSA9ICJTQVJTLUNvVjIgdGVzdGluZyIsIAogICAgICAgc3VidGl0bGUgPSAiUHJjdCIsIHggPSAidmFyaWFibGUiLCB5ID0gIiUiLCBjb2wgPSAiICIpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpKQojcF9wcmN0CgpuZWl0aGVyX1BDUl9JZyA8LSBucm93KGRmX3NpbmdsZWNhc2VzICU+JSBmaWx0ZXIoKGNvdmlkX3Nlcm9fYW55ID09IEZBTFNFIHwgaXMubmEoY292aWRfc2Vyb19hbnkpKSAmIChjb3ZpZF9QQ1JfcG9zID09IEZBTFNFIHwgaXMubmEoY292aWRfUENSX3BvcykpICYgKGNvdmlkX1BDUl9zdG9vbF9wb3MgPT0gRkFMU0UgfCBpcy5uYShjb3ZpZF9QQ1Jfc3Rvb2xfcG9zKSkpKQoKbmVpdGhlcl9QQ1JfSWdfY2xvc2Vjb250YWN0IDwtCiAgbnJvdyhkZl9zaW5nbGVjYXNlcyAlPiUgZmlsdGVyKChjb3ZpZF9zZXJvX2FueSA9PSBGQUxTRSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzLm5hKGNvdmlkX3Nlcm9fYW55KSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjb3ZpZF9QQ1JfcG9zID09IEZBTFNFIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShjb3ZpZF9QQ1JfcG9zKSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjb3ZpZF9QQ1Jfc3Rvb2xfcG9zID09IEZBTFNFIHwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpcy5uYShjb3ZpZF9QQ1Jfc3Rvb2xfcG9zKSkgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjb3ZpZF9jbG9zZWNvbnRhY3QgPT0gRkFMU0UgfCBpcy5uYShjb3ZpZF9jbG9zZWNvbnRhY3QpKQogICkpCgpwcmludChwYXN0ZTAoIkNhc2VzIHdpdGggbmVpdGhlciBQQ1Igbm9yIHNlcm9sb2d5OiAiLCBuZWl0aGVyX1BDUl9JZykpCgpwcmludChwYXN0ZTAoIkNhc2VzIHdpdGggbmVpdGhlciBQQ1Igbm9yIHNlcm9sb2d5IG5vciBjbG9zZWNvbnRhY3Q6ICIsIG5laXRoZXJfUENSX0lnX2Nsb3NlY29udGFjdCkpCmBgYAoKIyMgS2F3YXNha2kgY3JpdGVyaWEKCmBgYHtyIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGg9IDh9Cm1ha2VIZWF0bWFwX2NvaG9ydCgia2F3YXNha2kiLCAia2F3YXNha2kiLGV4Y2x1ZGVfc2luZ2xlID0gImtveW9iYXMiLCBwbG90dGl0bGUgPSAiQ2FzZXMgd2l0aCBrYXdhc2FraSBzeW1wdG9tcywgcGVyIGNvaG9ydCIpCmBgYAoKYGBge3IgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aD0gNn0KYmFyU3ltcCgia2F3YXNha2kiLCAia2F3YXNha2kiLCBleGNsdWRlX3NpbmdsZSA9ICJrb3lvYmFzIiwgcGxvdHRpdGxlID0gIkthd2FzYWtpIHN5bXB0b21zIikKYGBgCgojIyBTaG9jawpgYGB7cn0KbWFrZUJhcnBsb3QoInN5bXBfY2FyZGlvdmFzY19zaG9ja19uIiwgInN5bXBfY2FyZGlvdmFzY19zaG9jayIsICJTaG9jayIpCmBgYAoKIyMgTGFiIHZhbHVlcyB7LnRhYnNldH0KRm9yIGxhYiB2YWx1ZXMsIHNvbWV0aW1lcyBtdWx0aXBsZSB2YWx1ZXMgYXJlIHJlcG9ydGVkIChiYXNlbGluZSwgcGVhayBvciBub3Qtc3BlY2lmaWVkKS4gQWxsIGxhYiB2YWx1ZXMgYXJlIGNvbGxhcHNlZCBiYXNlZCBvbiB0aGUgbWF4IChvciB0aGUgbWluIGZvciBlLmcuIGhlbW9nbG9iaW4pOiBzbyBvbmx5IHRoZSBoaWdoZXN0IHZhbHVlIG9mIG1lZGlhbiwgUTEgb3IgUTMgaXMgdXNlZC4gRGFzaGVkIHZlcnRpY2FsIGxpbmUgY29ycmVzcG9uZHMgdG8gdGhlIGN1dG9mZiB1c2VkIGluIHRoZSBzdHVkeS4gCgojIyMgQy1yZWFjdGl2ZSBwcm90ZWluCgpgYGB7cn0KY3JwX2NvbGxhcHNlX2NvaG9ydCA8LSBjb2xsYXBzZV9sYWJ2YWxzX2NvaG9ydChkZl9jb2hvcnRfY29udHJvbHMsICJtYXgiLCAiQ1JQIikKY3JwX2NvbGxhcHNlX3NpbmdsZSA8LSBjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZShkZl9zaW5nbGVjYXNlcywgIm1heCIsICJDUlAiKQpjcnBfbWlzc2luZyA8LSBzdW0oaXMubmEoY3JwX2NvbGxhcHNlX3NpbmdsZSRDUlBfbWF4KSkKCnBfY3JwX2NvaG9ydCA8LSBnZ3Bsb3QoY3JwX2NvbGxhcHNlX2NvaG9ydCwgYWVzKHkgPSBjb2hvcnRfaWQsIHggPSBDUlBfbWVkLCBjb2wgPSBjb2hvcnRfdHlwZSkpICsgCiAgZ2VvbV9wb2ludCgpICsgIAogIGdlb21fZXJyb3JiYXIoYWVzKHhtaW49Q1JQX21pbiwgeG1heD1DUlBfbWF4KSwgd2lkdGg9LjIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSkgKyBsaW1zKHggPSBjKDAsNjAwKSkgKyAKICB0aGVtZV9idygpICsgbGFicyh0aXRsZSA9ICJDUlAiLCB5ID0gImNvaG9ydCIsIHggPSAiIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX0NSUCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk4LCAwLjk4KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbYyg0LDIsMSldKQoKcF9jcnBfc2luZ2xlIDwtIGdncGxvdChjcnBfY29sbGFwc2Vfc2luZ2xlLCBhZXMoeCA9IGFzLm51bWVyaWMoQ1JQX21heCksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9ICB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVsxXSkgKyAKICB0aGVtZV9idygpICsgZ2VvbV9iZWVzd2FybShncm91cE9uWD1GQUxTRSwgYWxwaGEgPSAwLjUpICsgbGltcyh4ID0gYygwLDYwMCkpICsgbGFicyh5ID0gIiIsIHggPSAiQ1JQIChtZy9kTCkiLCBzdWJ0aXRsZSA9IHBhc3RlMCgibWlzc2luZyBkYXRhIGZvciAiLCBjcnBfbWlzc2luZywgIiBjYXNlcyIpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gY29fQ1JQLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpCgpDUlBfZ3JpZCA8LSBwbG90X2dyaWQocF9jcnBfY29ob3J0LCBwX2NycF9zaW5nbGUsIGFsaWduID0gInYiLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDIvMywgMS8zKSkKQ1JQX2dyaWQKYGBgCgpUaGUgbnVtYmVyIG9mIHNpbmdsZSBjYXNlcyB3aXRoIGVsZXZhdGVkIENSUDogYHIgY3JwX2NvbGxhcHNlX3NpbmdsZSAlPiUgZmlsdGVyKCFpcy5uYShDUlBfbWF4KSAmIENSUF9tYXggPj0gY29fQ1JQKSAlPiUgbnJvdygpYCBvdXQgb2YgdG90YWwgY2FzZXMgKD0gdG90YWwgY2FzZXMgbWludXMgbWlzc2luZyBjYXNlcyk6IGByIGNycF9jb2xsYXBzZV9zaW5nbGUgJT4lIG5yb3coKSAtIGNycF9taXNzaW5nYAoKIyMjIEx5bXBob2N5dGVzCmBgYHtyfQpseW1waG9fY29sbGFwc2VfY29ob3J0IDwtIGNvbGxhcHNlX2xhYnZhbHNfY29ob3J0KGRmX2NvaG9ydF9jb250cm9scywgIm1pbiIsICJseW1waG8iKQpseW1waG9fY29sbGFwc2Vfc2luZ2xlIDwtIGNvbGxhcHNlX2xhYnZhbHNfc2luZ2xlKGRmX3NpbmdsZWNhc2VzLCAibWluIiwgImx5bXBobyIpCmx5bXBob19taXNzaW5nIDwtIHN1bShpcy5uYShseW1waG9fY29sbGFwc2Vfc2luZ2xlJGx5bXBob19taW4pKQoKcF9seW1waG9fY29ob3J0IDwtIGdncGxvdChseW1waG9fY29sbGFwc2VfY29ob3J0LCBhZXMoeSA9IGNvaG9ydF9pZCwgeCA9IGx5bXBob19tZWQsIGNvbCA9IGNvaG9ydF90eXBlKSkgKyAKICBnZW9tX3BvaW50KCkgKyAgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1seW1waG9fbWluLCB4bWF4PWx5bXBob19tYXgpLCB3aWR0aD0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoLjkpKSArIAogIHRoZW1lX2J3KCkgKyBsYWJzKHRpdGxlID0gImx5bXBob2N5dGVzIiwgeSA9ICIiLCB4ID0gIiIpICsgbGltcyh4ID0gYygwLDc1MDApKSAgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX2x5bXBobywgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk4LCAwLjk4KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbYyg0LDIsMSldKSMrCiNycmVtb3ZlKCJ5LnRleHQiKSAKCnBfbHltcGhvX3NpbmdsZSA8LSBnZ3Bsb3QobHltcGhvX2NvbGxhcHNlX3NpbmdsZSwgYWVzKHggPSBhcy5udW1lcmljKGx5bXBob19taW4pLCB5ID0gY29ob3J0X2lkKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVs0XSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGg9LjMsIGZpbGwgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVsxXSkgKyAKICBsaW1zKHggPSBjKDAsNzUwMCkpKwogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgICsgbGFicyh5ID0gIiIsIHggPSAiTHltcGhvY3l0ZXMgKC/CtUwpIiwgc3VidGl0bGUgPSBwYXN0ZTAoIm1pc3NpbmcgZGF0YSBmb3IgIiwgbHltcGhvX21pc3NpbmcsICIgY2FzZXMiKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX2x5bXBobywgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSAjKyAKI3JyZW1vdmUoInkudGV4dCIpIAoKbHltcGhvX2dyaWQgPC0gcGxvdF9ncmlkKHBfbHltcGhvX2NvaG9ydCwgcF9seW1waG9fc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygyLzMsIDEvMykpCmx5bXBob19ncmlkCmBgYAoKVGhlIG51bWJlciBvZiBzaW5nbGUgY2FzZXMgd2l0aCBseW1waG9wZW5pYTogYHIgbHltcGhvX2NvbGxhcHNlX3NpbmdsZSAlPiUgZmlsdGVyKCFpcy5uYShseW1waG9fbWluKSAmIGx5bXBob19taW4gPD0gY29fbHltcGhvKSAlPiUgbnJvdygpYCBvdXQgb2YgdG90YWwgY2FzZXMgKD0gdG90YWwgY2FzZXMgbWludXMgbWlzc2luZyBjYXNlcyk6IGByIGx5bXBob19jb2xsYXBzZV9zaW5nbGUgJT4lIG5yb3coKSAtIGx5bXBob19taXNzaW5nYAoKIyMjIFdoaXRlIGJsb29kIGNlbGxzCmBgYHtyfQp3YmNfY29sbGFwc2VfY29ob3J0IDwtIGNvbGxhcHNlX2xhYnZhbHNfY29ob3J0KGRmX2NvaG9ydF9jb250cm9scywgIm1heCIsICJXQkMiKQp3YmNfY29sbGFwc2Vfc2luZ2xlIDwtIGNvbGxhcHNlX2xhYnZhbHNfc2luZ2xlKGRmX3NpbmdsZWNhc2VzLCAibWF4IiwgIldCQyIpCndiY19taXNzaW5nIDwtIHN1bShpcy5uYSh3YmNfY29sbGFwc2Vfc2luZ2xlJFdCQ19tYXgpKQoKcF93YmNfY29ob3J0IDwtIGdncGxvdCh3YmNfY29sbGFwc2VfY29ob3J0LCBhZXMoeSA9IGNvaG9ydF9pZCwgeCA9IFdCQ19tZWQsIGNvbCA9IGNvaG9ydF90eXBlKSkgKyAKICBnZW9tX3BvaW50KCkgKyAgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj1XQkNfbWluLCB4bWF4PVdCQ19tYXgpLCB3aWR0aD0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoLjkpKSArIGxpbXMoeCA9IGMoMCw1MDAwMCkpICsgCiAgdGhlbWVfYncoKSArIGxhYnModGl0bGUgPSAiV0JDIiwgeSA9ICJjb2hvcnQiLCB4ID0gIiIpICArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY29fV0JDLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpICArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk4LCAwLjk4KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbYyg0LDIsMSldKQoKcF93YmNfc2luZ2xlIDwtIGdncGxvdCh3YmNfY29sbGFwc2Vfc2luZ2xlLCBhZXMoeCA9IGFzLm51bWVyaWMoV0JDX21heCksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzFdKSArIAogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHkgPSAiIiwgeCA9ICJXQkMgKC/CtUwpIiwgc3VidGl0bGUgPSBwYXN0ZTAoIm1pc3NpbmcgZGF0YSBmb3IgIiwgd2JjX21pc3NpbmcsICIgY2FzZXMiKSkgKyBsaW1zKHggPSBjKDAsNTAwMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY29fV0JDLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpIAoKV0JDX2dyaWQgPC0gcGxvdF9ncmlkKHBfd2JjX2NvaG9ydCwgcF93YmNfc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygyLzMsIDEvMykpCldCQ19ncmlkCmBgYAoKVGhlIG51bWJlciBvZiBzaW5nbGUgY2FzZXMgd2l0aCBpbmNyZWFzZWQgV0JDczogYHIgd2JjX2NvbGxhcHNlX3NpbmdsZSAlPiUgZmlsdGVyKCFpcy5uYShXQkNfbWF4KSAmIFdCQ19tYXggPj0gY29fV0JDKSAlPiUgbnJvdygpYCBvdXQgb2YgdG90YWwgY2FzZXMgKD0gdG90YWwgY2FzZXMgbWludXMgbWlzc2luZyBjYXNlcyk6IGByIHdiY19jb2xsYXBzZV9zaW5nbGUgJT4lIG5yb3coKSAtIHdiY19taXNzaW5nYAoKCiMjIyBGZXJyaXRpbgpgYGB7cn0KZmVycml0aW5fY29sbGFwc2VfY29ob3J0IDwtIGNvbGxhcHNlX2xhYnZhbHNfY29ob3J0KGRmX2NvaG9ydF9jb250cm9scywgIm1heCIsICJmZXJyaXQiKQpmZXJyaXRpbl9jb2xsYXBzZV9zaW5nbGUgPC0gY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXMsICJtYXgiLCAiZmVycml0IikKZmVycml0aW5fbWlzc2luZyA8LSBzdW0oaXMubmEoZmVycml0aW5fY29sbGFwc2Vfc2luZ2xlJGZlcnJpdF9tYXgpKQoKcF9mZXJyaXRpbl9jb2hvcnQgPC0gZ2dwbG90KGZlcnJpdGluX2NvbGxhcHNlX2NvaG9ydCwgYWVzKHkgPSBjb2hvcnRfaWQsIHggPSBmZXJyaXRfbWVkLCBjb2wgPSBjb2hvcnRfdHlwZSkpICsgCiAgZ2VvbV9wb2ludCgpICsgIAogIGdlb21fZXJyb3JiYXIoYWVzKHhtaW49ZmVycml0X21pbiwgeG1heD1mZXJyaXRfbWF4KSwgd2lkdGg9LjIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSkgKyBsaW1zKHggPSBjKDAsMTEwMDApKSArIAogIHRoZW1lX2J3KCkgKyBsYWJzKHRpdGxlID0gIkZlcnJpdGluIiwgeSA9ICJjb2hvcnQiLCB4ID0gIiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjb19mZXJyaXRpbiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk4LCAwLjk4KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbYyg0LDIsMSldKQoKcF9mZXJyaXRpbl9zaW5nbGUgPC0gZ2dwbG90KGZlcnJpdGluX2NvbGxhcHNlX3NpbmdsZSwgYWVzKHggPSBhcy5udW1lcmljKGZlcnJpdF9tYXgpLCB5ID0gY29ob3J0X2lkKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVs0XSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGg9LjMsIGZpbGwgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVsxXSkgKyAKICB0aGVtZV9idygpICsgZ2VvbV9iZWVzd2FybShncm91cE9uWD1GQUxTRSwgYWxwaGEgPSAwLjUpICsgbGFicyh5ID0gIiIsIHggPSAiRmVycml0aW4gKMK1Zy9sKSIsIHN1YnRpdGxlID0gcGFzdGUwKCJtaXNzaW5nIGRhdGEgZm9yICIsIGZlcnJpdGluX21pc3NpbmcsICIgY2FzZXMiKSkgKyBsaW1zKHggPSBjKDAsMTEwMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY29fZmVycml0aW4sIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgCgpmZXJyaXRpbl9ncmlkIDwtIHBsb3RfZ3JpZChwX2ZlcnJpdGluX2NvaG9ydCwgcF9mZXJyaXRpbl9zaW5nbGUsIGFsaWduID0gInYiLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDIvMywgMS8zKSkKZmVycml0aW5fZ3JpZApgYGAKClRoZSBudW1iZXIgb2Ygc2luZ2xlIGNhc2VzIHdpdGggaW5jcmVhc2VkIGZlcnJpdGluOiBgciBmZXJyaXRpbl9jb2xsYXBzZV9zaW5nbGUgJT4lIGZpbHRlcighaXMubmEoZmVycml0X21heCkgJiBmZXJyaXRfbWF4ID49IGNvX2ZlcnJpdGluKSAlPiUgbnJvdygpYCBvdXQgb2YgdG90YWwgY2FzZXMgKD0gdG90YWwgY2FzZXMgbWludXMgbWlzc2luZyBjYXNlcyk6IGByIGZlcnJpdGluX2NvbGxhcHNlX3NpbmdsZSAlPiUgbnJvdygpIC0gZmVycml0aW5fbWlzc2luZ2AKCiMjIyBUcm9wb25pbgpgYGB7cn0KdHJvcG9uaW5fY29sbGFwc2VfY29ob3J0IDwtIGNvbGxhcHNlX2xhYnZhbHNfY29ob3J0KGRmX2NvaG9ydF9jb250cm9scywgIm1heCIsICJ0cm9wb25pbiIpCnRyb3BvbmluX2NvbGxhcHNlX3NpbmdsZSA8LSBjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZShkZl9zaW5nbGVjYXNlcywgIm1heCIsICJ0cm9wb25pbiIpCnRyb3BvbmluX21pc3NpbmcgPC0gc3VtKGlzLm5hKHRyb3BvbmluX2NvbGxhcHNlX3NpbmdsZSR0cm9wb25pbl9tYXgpKQoKcF90cm9wb25pbl9jb2hvcnQgPC0gZ2dwbG90KHRyb3BvbmluX2NvbGxhcHNlX2NvaG9ydCwgYWVzKHkgPSBjb2hvcnRfaWQsIHggPSB0cm9wb25pbl9tZWQsIGNvbCA9IGNvaG9ydF90eXBlKSkgKyAKICBnZW9tX3BvaW50KCkgKyAgCiAgZ2VvbV9lcnJvcmJhcihhZXMoeG1pbj10cm9wb25pbl9taW4sIHhtYXg9dHJvcG9uaW5fbWF4KSwgd2lkdGg9LjIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSkgKyBsaW1zKHggPSBjKDAsNzAwMCkpICsgCiAgdGhlbWVfYncoKSArIGxhYnModGl0bGUgPSAiVHJvcG9uaW4iLCB5ID0gImNvaG9ydCIsIHggPSAiIikgICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjb190cm9wbywgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSAgKyB0aGVtZShsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMSksIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45OCwgMC45OCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpW2MoNCwyLDEpXSkKCnBfdHJvcG9uaW5fc2luZ2xlIDwtIGdncGxvdCh0cm9wb25pbl9jb2xsYXBzZV9zaW5nbGUsIGFlcyh4ID0gYXMubnVtZXJpYyh0cm9wb25pbl9tYXgpLCB5ID0gY29ob3J0X2lkKSkgKwogIGdlb21fdmlvbGluKGZpbGwgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVs0XSkgKyAKICBnZW9tX2JveHBsb3Qod2lkdGg9LjMsIGZpbGwgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzIiKVsxXSkgKyAKICB0aGVtZV9idygpICsgZ2VvbV9iZWVzd2FybShncm91cE9uWD1GQUxTRSwgYWxwaGEgPSAwLjUpICsgbGFicyh5ID0gIiIsIHggPSAiVHJvcG9uaW4gKG5nL0wpIiwgc3VidGl0bGUgPSBwYXN0ZTAoIm1pc3NpbmcgZGF0YSBmb3IgIiwgdHJvcG9uaW5fbWlzc2luZywgIiBjYXNlcyIpKSArIGxpbXMoeCA9IGMoMCw3MDAwKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX3Ryb3BvLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpIAoKdHJvcG9uaW5fZ3JpZCA8LSBwbG90X2dyaWQocF90cm9wb25pbl9jb2hvcnQsIHBfdHJvcG9uaW5fc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygyLzMsIDEvMykpCnRyb3BvbmluX2dyaWQKYGBgCgpUaGUgbnVtYmVyIG9mIHNpbmdsZSBjYXNlcyB3aXRoIGluY3JlYXNlZCB0cm9wb25pbjogYHIgdHJvcG9uaW5fY29sbGFwc2Vfc2luZ2xlICU+JSBmaWx0ZXIoIWlzLm5hKHRyb3BvbmluX21heCkgJiB0cm9wb25pbl9tYXggPj0gY29fdHJvcG8pICU+JSBucm93KClgIG91dCBvZiB0b3RhbCBjYXNlcyAoPSB0b3RhbCBjYXNlcyBtaW51cyBtaXNzaW5nIGNhc2VzKTogYHIgdHJvcG9uaW5fY29sbGFwc2Vfc2luZ2xlICU+JSBucm93KCkgLSB0cm9wb25pbl9taXNzaW5nYAoKCiMjIyBJTC02Ck5vdGU6IFRoZSBjYXNlcyBmcm9tIFBvdWxldHR5IGV0IGFsIGFyZSBhZGRlZCB0byB0aGUgc2luZ2xlIGNhc2VzIGFzIHRoZXkgcmVwb3J0IG9uIElMNiB2YWx1ZXMuIAoKYGBge3J9CklMNl9jb2xsYXBzZV9jb2hvcnQgPC0gY29sbGFwc2VfbGFidmFsc19jb2hvcnQoZGZfY29ob3J0X2NvbnRyb2xzLCAibWF4IiwgIklMNiIpCklMNl9jb2xsYXBzZV9zaW5nbGUgPC0gY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXNfaW5jbFBvdWxldHR5LCAibWF4IiwgIklMNiIpCklMNl9taXNzaW5nIDwtIHN1bShpcy5uYShJTDZfY29sbGFwc2Vfc2luZ2xlJElMNl9tYXgpKQoKcF9JTDZfY29ob3J0IDwtIGdncGxvdChJTDZfY29sbGFwc2VfY29ob3J0LCBhZXMoeSA9IGNvaG9ydF9pZCwgeCA9IElMNl9tZWQpKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX2Vycm9yYmFyKGFlcyh4bWluPUlMNl9taW4sIHhtYXg9SUw2X21heCksIHdpZHRoPS4yLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSguOSkpICsgbGltcyh4ID0gYygwLDI1MDApKSArIAogIHRoZW1lX2J3KCkgKyBsYWJzKHRpdGxlID0gIklMNiIsIHkgPSAiY29ob3J0IiwgeCA9ICIiKSAgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX0lMNiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSAgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbYyg0LDIsMSldKQoKcF9JTDZfc2luZ2xlIDwtIGdncGxvdChJTDZfY29sbGFwc2Vfc2luZ2xlLCBhZXMoeCA9IGFzLm51bWVyaWMoSUw2X21heCksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzFdKSArIAogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHkgPSAiIiwgeCA9ICJJTDYgKHBnL21sKSIsIHN1YnRpdGxlID0gcGFzdGUwKCJtaXNzaW5nIGRhdGEgZm9yICIsIElMNl9taXNzaW5nLCAiIGNhc2VzIikpICsgbGltcyh4ID0gYygwLDI1MDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY29fSUw2LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpIAoKSUw2X2dyaWQgPC0gcGxvdF9ncmlkKHBfSUw2X2NvaG9ydCwgcF9JTDZfc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygyLzMsIDEvMykpCklMNl9ncmlkCmBgYAoKVGhlIG51bWJlciBvZiBzaW5nbGUgY2FzZXMgd2l0aCBpbmNyZWFzZWQgSUw2OiBgciBJTDZfY29sbGFwc2Vfc2luZ2xlICU+JSBmaWx0ZXIoIWlzLm5hKElMNl9tYXgpICYgSUw2X21heCA+PSBjb19JTDYpICU+JSBucm93KClgIG91dCBvZiB0b3RhbCBjYXNlcyAoPSB0b3RhbCBjYXNlcyBtaW51cyBtaXNzaW5nIGNhc2VzKTogYHIgSUw2X2NvbGxhcHNlX3NpbmdsZSAlPiUgbnJvdygpIC0gSUw2X21pc3NpbmdgCgoKIyMjIEJOUAoKYGBge3J9CmNvbGxhcHNlX2NvaG9ydCA8LSBjb2xsYXBzZV9sYWJ2YWxzX2NvaG9ydChkZl9jb2hvcnRfY29udHJvbHMsICJtYXgiLCAiX0JOUCIpCmNvbGxhcHNlX3NpbmdsZSA8LSBjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZShkZl9zaW5nbGVjYXNlcywgIm1heCIsICJfQk5QIikKbWlzc2luZyA8LSBzdW0oaXMubmEoY29sbGFwc2Vfc2luZ2xlJGBfQk5QX21heGApKQoKcF9CTlBfY29ob3J0IDwtIGdncGxvdChjb2xsYXBzZV9jb2hvcnQsIGFlcyh5ID0gY29ob3J0X2lkLCB4ID0gYF9CTlBfbWVkYCwgY29sID0gY29ob3J0X3R5cGUpKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX2Vycm9yYmFyKGFlcyh4bWluPWBfQk5QX21pbmAsIHhtYXg9YF9CTlBfbWF4YCksIHdpZHRoPS4yLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSguOSkpICsgbGltcyh4ID0gYygwLDIwMDAwKSkgKyAKICB0aGVtZV9idygpICsgbGFicyh0aXRsZSA9ICJCTlAiLCB5ID0gImNvaG9ydCIsIHggPSAiIikgICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjb19CTlAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgICt0aGVtZShsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMSksIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45OCwgMC45OCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpW2MoNCwyLDEpXSkKCnBfQk5QX3NpbmdsZSA8LSBnZ3Bsb3QoY29sbGFwc2Vfc2luZ2xlLCBhZXMoeCA9IGFzLm51bWVyaWMoYF9CTlBfbWF4YCksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzFdKSArIAogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHkgPSAiIiwgeCA9ICJCTlAgKHBnL21sKSIsIHN1YnRpdGxlID0gcGFzdGUwKCJtaXNzaW5nIGRhdGEgZm9yICIsIG1pc3NpbmcsICIgY2FzZXMiKSkgKyBsaW1zKHggPSBjKDAsMjAwMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY29fQk5QLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpIAoKQk5QX2dyaWQgPC0gcGxvdF9ncmlkKHBfQk5QX2NvaG9ydCwgcF9CTlBfc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygyLzMsIDEvMykpCkJOUF9ncmlkCgpuX2luY3IgPC0gY29sbGFwc2Vfc2luZ2xlICU+JSBmaWx0ZXIoIWlzLm5hKGBfQk5QX21heGApICYgYF9CTlBfbWF4YCA+PSBjb19CTlApICU+JSBucm93KCkKYGBgCgpUaGUgbnVtYmVyIG9mIHNpbmdsZSBjYXNlcyB3aXRoIGluY3JlYXNlZCBCTlA6IGByIG5faW5jcmAgb3V0IG9mIHRvdGFsIGNhc2VzICg9IHRvdGFsIGNhc2VzIG1pbnVzIG1pc3NpbmcgY2FzZXMpOiBgciBjb2xsYXBzZV9zaW5nbGUgJT4lIG5yb3coKSAtIG1pc3NpbmdgCgoKIyMjIE5UcHJvQk5QCmBgYHtyfQpjb2xsYXBzZV9jb2hvcnQgPC0gY29sbGFwc2VfbGFidmFsc19jb2hvcnQoZGZfY29ob3J0X2NvbnRyb2xzLCAibWF4IiwgIk5UcHJvQk5QIikKY29sbGFwc2Vfc2luZ2xlIDwtIGNvbGxhcHNlX2xhYnZhbHNfc2luZ2xlKGRmX3NpbmdsZWNhc2VzLCAibWF4IiwgIk5UcHJvQk5QIikKbWlzc2luZyA8LSBzdW0oaXMubmEoY29sbGFwc2Vfc2luZ2xlJE5UcHJvQk5QX21heCkpCgpwX05UcHJvQk5QX2NvaG9ydCA8LSBnZ3Bsb3QoY29sbGFwc2VfY29ob3J0LCBhZXMoeSA9IGNvaG9ydF9pZCwgeCA9IE5UcHJvQk5QX21lZCwgY29sID0gY29ob3J0X3R5cGUpKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX2Vycm9yYmFyKGFlcyh4bWluPU5UcHJvQk5QX21pbiwgeG1heD1OVHByb0JOUF9tYXgpLCB3aWR0aD0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoLjkpKSArIGxpbXMoeCA9IGMoMCw3MDAwMCkpICsgCiAgdGhlbWVfYncoKSArIGxhYnModGl0bGUgPSAiTlRwcm9CTlAiLCB5ID0gImNvaG9ydCIsIHggPSAiIikgICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjb19OVHByb0JOUCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk4LCAwLjk4KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbYyg0LDIsMSldKQoKcF9OVHByb0JOUF9zaW5nbGUgPC0gZ2dwbG90KGNvbGxhcHNlX3NpbmdsZSwgYWVzKHggPSBhcy5udW1lcmljKE5UcHJvQk5QX21heCksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzFdKSArIAogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHkgPSAiIiwgeCA9ICJOVHByb0JOUCAocGcvbWwpIiwgc3VidGl0bGUgPSBwYXN0ZTAoIm1pc3NpbmcgZGF0YSBmb3IgIiwgbWlzc2luZywgIiBjYXNlcyIpKSArIGxpbXMoeCA9IGMoMCw3MDAwMCkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjb19OVHByb0JOUCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSAKCk5UcHJvQk5QX2dyaWQgPC0gcGxvdF9ncmlkKHBfTlRwcm9CTlBfY29ob3J0LCBwX05UcHJvQk5QX3NpbmdsZSwgYWxpZ24gPSAidiIsIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMi8zLCAxLzMpKQpOVHByb0JOUF9ncmlkCgpuX2luY3IgPC0gY29sbGFwc2Vfc2luZ2xlICU+JSBmaWx0ZXIoIWlzLm5hKGBOVHByb0JOUF9tYXhgKSAmIGBOVHByb0JOUF9tYXhgID49IGNvX05UcHJvQk5QKSAlPiUgbnJvdygpCmBgYAoKVGhlIG51bWJlciBvZiBzaW5nbGUgY2FzZXMgd2l0aCBpbmNyZWFzZWQgTlRwcm9CTlA6IGByIG5faW5jcmAgb3V0IG9mIHRvdGFsIGNhc2VzICg9IHRvdGFsIGNhc2VzIG1pbnVzIG1pc3NpbmcgY2FzZXMpOiBgciBjb2xsYXBzZV9zaW5nbGUgJT4lIG5yb3coKSAtIG1pc3NpbmdgCgoKIyMjIFBsYXRlbGV0cwoKYGBge3J9CmNvbGxhcHNlX2NvaG9ydCA8LSBjb2xsYXBzZV9sYWJ2YWxzX2NvaG9ydChkZl9jb2hvcnRfY29udHJvbHMsICJtaW4iLCAicGxhdGVsZXQiKQpjb2xsYXBzZV9zaW5nbGUgPC0gY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXMsICJtaW4iLCAicGxhdGVsZXQiKQptaXNzaW5nIDwtIHN1bShpcy5uYShjb2xsYXBzZV9zaW5nbGUkcGxhdGVsZXRfbWluKSkKCnBfcGxhdGVsZXRfY29ob3J0IDwtIGdncGxvdChjb2xsYXBzZV9jb2hvcnQsIGFlcyh5ID0gY29ob3J0X2lkLCB4ID0gcGxhdGVsZXRfbWVkLCBjb2wgPSBjb2hvcnRfdHlwZSkpICsgCiAgZ2VvbV9wb2ludCgpICsgIAogIGdlb21fZXJyb3JiYXIoYWVzKHhtaW49cGxhdGVsZXRfbWluLCB4bWF4PXBsYXRlbGV0X21heCwgY29sPWNvaG9ydF90eXBlKSwgd2lkdGg9LjIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSkgKyBsaW1zKHggPSBjKDAsNzUwMDAwKSkgKyAKICB0aGVtZV9idygpICsgbGFicyh0aXRsZSA9ICJwbGF0ZWxldCIsIHkgPSAiY29ob3J0IiwgeCA9ICIiKSAgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX3BsYXRlbGV0LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpICArIHRoZW1lKGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygxLCAxKSwgbGVnZW5kLnBvc2l0aW9uID0gYygwLjk4LCAwLjk4KSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiUm95YWwxIilbYyg0LDIsMSldKQoKcF9wbGF0ZWxldF9zaW5nbGUgPC0gZ2dwbG90KGNvbGxhcHNlX3NpbmdsZSwgYWVzKHggPSBhcy5udW1lcmljKHBsYXRlbGV0X21pbiksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzFdKSArIAogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHkgPSAiIiwgeCA9ICJQbGF0ZWxldHMgKC/CtUwpIiwgc3VidGl0bGUgPSBwYXN0ZTAoIm1pc3NpbmcgZGF0YSBmb3IgIiwgbWlzc2luZywgIiBjYXNlcyIpKSArIGxpbXMoeCA9IGMoMCw3NTAwMDApKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gY29fcGxhdGVsZXQsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgCgpwbGF0ZWxldF9ncmlkIDwtIHBsb3RfZ3JpZChwX3BsYXRlbGV0X2NvaG9ydCwgcF9wbGF0ZWxldF9zaW5nbGUsIGFsaWduID0gInYiLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDIvMywgMS8zKSkKcGxhdGVsZXRfZ3JpZAoKbl9kZWNyIDwtIGNvbGxhcHNlX3NpbmdsZSAlPiUgZmlsdGVyKCFpcy5uYShgcGxhdGVsZXRfbWluYCkgJiBgcGxhdGVsZXRfbWluYCA8PSBjb19wbGF0ZWxldCkgJT4lIG5yb3coKQpgYGAKClRoZSBudW1iZXIgb2Ygc2luZ2xlIGNhc2VzIHdpdGggdGhyb21ib3BlbmlhICg8IDE1MCAwMDApOiBgciBuX2RlY3JgIG91dCBvZiB0b3RhbCBjYXNlcyAoPSB0b3RhbCBjYXNlcyBtaW51cyBtaXNzaW5nIGNhc2VzKTogYHIgY29sbGFwc2Vfc2luZ2xlICU+JSBucm93KCkgLSBtaXNzaW5nYAoKIyMjIEQtZGltZXJzCgpgYGB7cn0KY29sbGFwc2VfY29ob3J0IDwtIGNvbGxhcHNlX2xhYnZhbHNfY29ob3J0KGRmX2NvaG9ydF9jb250cm9scywgIm1heCIsICJEZGltIikKY29sbGFwc2Vfc2luZ2xlIDwtIGNvbGxhcHNlX2xhYnZhbHNfc2luZ2xlKGRmX3NpbmdsZWNhc2VzLCAibWF4IiwgIkRkaW0iKQptaXNzaW5nIDwtIHN1bShpcy5uYShjb2xsYXBzZV9zaW5nbGUkRGRpbV9tYXgpKQoKcF9EZGltX2NvaG9ydCA8LSBnZ3Bsb3QoY29sbGFwc2VfY29ob3J0LCBhZXMoeSA9IGNvaG9ydF9pZCwgeCA9IERkaW1fbWVkLCBjb2wgPSBjb2hvcnRfdHlwZSkpICsgCiAgZ2VvbV9wb2ludCgpICsgIAogIGdlb21fZXJyb3JiYXIoYWVzKHhtaW49RGRpbV9taW4sIHhtYXg9RGRpbV9tYXgsIGNvbD1jb2hvcnRfdHlwZSksIHdpZHRoPS4yLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSguOSkpICsgbGltcyh4ID0gYygwLDExMDAwKSkgKyAKICB0aGVtZV9idygpICsgbGFicyh0aXRsZSA9ICJELWRpbWVycyIsIHkgPSAiY29ob3J0IiwgeCA9ICIiKSAgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX0RkaW0sIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIikgICsgdGhlbWUobGVnZW5kLmp1c3RpZmljYXRpb24gPSBjKDEsIDEpLCBsZWdlbmQucG9zaXRpb24gPSBjKDAuOTgsIDAuOTgpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJSb3lhbDEiKVtjKDQsMiwxKV0pCgpwX0RkaW1fc2luZ2xlIDwtIGdncGxvdChjb2xsYXBzZV9zaW5nbGUsIGFlcyh4ID0gYXMubnVtZXJpYyhEZGltX21heCksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzFdKSArIAogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHkgPSAiIiwgeCA9ICJELWRpbWVycyAobmcvbWwpIiwgc3VidGl0bGUgPSBwYXN0ZTAoIm1pc3NpbmcgZGF0YSBmb3IgIiwgbWlzc2luZywgIiBjYXNlcyIpKSArIGxpbXMoeCA9IGMoMCwxMTAwMCkpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjb19EZGltLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJibGFjayIpIAoKRGRpbV9ncmlkIDwtIHBsb3RfZ3JpZChwX0RkaW1fY29ob3J0LCBwX0RkaW1fc2luZ2xlLCBhbGlnbiA9ICJ2IiwgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygyLzMsIDEvMykpCkRkaW1fZ3JpZAoKbl9pbmNyIDwtIGNvbGxhcHNlX3NpbmdsZSAlPiUgZmlsdGVyKCFpcy5uYShgRGRpbV9tYXhgKSAmIGBEZGltX21heGAgPj0gY29fRGRpbSkgJT4lIG5yb3coKQpgYGAKClRoZSBudW1iZXIgb2Ygc2luZ2xlIGNhc2VzIHdpdGggaW5jcmVhc2VkIEQtZGltZXJzOiBgciBuX2luY3JgIG91dCBvZiB0b3RhbCBjYXNlcyAoPSB0b3RhbCBjYXNlcyBtaW51cyBtaXNzaW5nIGNhc2VzKTogYHIgY29sbGFwc2Vfc2luZ2xlICU+JSBucm93KCkgLSBtaXNzaW5nYAoKCgojIyMgU29kaXVtCgpgYGB7cn0KY29sbGFwc2VfY29ob3J0IDwtIGNvbGxhcHNlX2xhYnZhbHNfY29ob3J0KGRmX2NvaG9ydF9jb250cm9scywgIm1pbiIsICJzb2RpdW0iKQpjb2xsYXBzZV9zaW5nbGUgPC0gY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXMsICJtaW4iLCAic29kaXVtIikKbWlzc2luZyA8LSBzdW0oaXMubmEoY29sbGFwc2Vfc2luZ2xlJHNvZGl1bV9taW4pKQoKcF9zb2RpdW1fY29ob3J0IDwtIGdncGxvdChjb2xsYXBzZV9jb2hvcnQsIGFlcyh5ID0gY29ob3J0X2lkLCB4ID0gc29kaXVtX21lZCwgY29sID0gY29ob3J0X3R5cGUpKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX2Vycm9yYmFyKGFlcyh4bWluPXNvZGl1bV9taW4sIHhtYXg9c29kaXVtX21heCwgY29sPWNvaG9ydF90eXBlKSwgd2lkdGg9LjIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKC45KSkgKyBsaW1zKHggPSBjKDEwMCwyMDApKSArIAogIHRoZW1lX2J3KCkgKyBsYWJzKHRpdGxlID0gIlNvZGl1bSIsIHkgPSAiY29ob3J0IiwgeCA9ICIiKSAgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX3NvZGl1bSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSAgKyB0aGVtZShsZWdlbmQuanVzdGlmaWNhdGlvbiA9IGMoMSwgMSksIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC45OCwgMC45OCksIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpW2MoNCwyLDEpXSkKCnBfc29kaXVtX3NpbmdsZSA8LSBnZ3Bsb3QoY29sbGFwc2Vfc2luZ2xlLCBhZXMoeCA9IGFzLm51bWVyaWMoc29kaXVtX21pbiksIHkgPSBjb2hvcnRfaWQpKSArCiAgZ2VvbV92aW9saW4oZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzRdKSArIAogIGdlb21fYm94cGxvdCh3aWR0aD0uMywgZmlsbCA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMiIpWzFdKSArIAogIHRoZW1lX2J3KCkgKyBnZW9tX2JlZXN3YXJtKGdyb3VwT25YPUZBTFNFLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHkgPSAiIiwgeCA9ICJTb2RpdW0gKG1tb2wvTCkiLCBzdWJ0aXRsZSA9IHBhc3RlMCgibWlzc2luZyBkYXRhIGZvciAiLCBtaXNzaW5nLCAiIGNhc2VzIikpICsgbGltcyh4ID0gYygxMDAsMjAwKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGNvX3NvZGl1bSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAiYmxhY2siKSAKCnNvZGl1bV9ncmlkIDwtIHBsb3RfZ3JpZChwX3NvZGl1bV9jb2hvcnQsIHBfc29kaXVtX3NpbmdsZSwgYWxpZ24gPSAidiIsIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMi8zLCAxLzMpKQpzb2RpdW1fZ3JpZAoKbl9kZWNyIDwtIGNvbGxhcHNlX3NpbmdsZSAlPiUgZmlsdGVyKCFpcy5uYShgc29kaXVtX21pbmApICYgYHNvZGl1bV9taW5gIDw9IGNvX3NvZGl1bSkgJT4lIG5yb3coKQpgYGAKClRoZSBudW1iZXIgb2Ygc2luZ2xlIGNhc2VzIHdpdGggaHlwb25hdHJlbWlhOiBgciBuX2RlY3JgIG91dCBvZiB0b3RhbCBjYXNlcyAoPSB0b3RhbCBjYXNlcyBtaW51cyBtaXNzaW5nIGNhc2VzKTogYHIgY29sbGFwc2Vfc2luZ2xlICU+JSBucm93KCkgLSBtaXNzaW5nYAoKIyMgQ3JpdGljYWwgY2FyZSBpbnRlcnZlbnRpb25zCgojIyMgSW5vdHJvcGVzCmBgYHtyfQptYWtlQmFycGxvdCh2YXJfaWRfY29ob3J0ID0gImNyaXRjYXJlX2lub3Ryb3BfbiIsIHZhcl9pZF9zaW5nbGUgPSAiY3JpdGNhcmVfaW5vdHJvcCIsIHZhcl9pZCA9ICJpbm90cm9wZXMiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGg9IDh9Cm1ha2VIZWF0bWFwX2NvaG9ydCgiY3JpdGNhcmUiLCAiY3JpdGNhcmUiLGV4Y2x1ZGVfc2luZ2xlID0gImRheXMiLCBwbG90dGl0bGUgPSAiQ2FzZXMgcmVjZWl2aW5nIGNyaXRpY2FsIGNhcmUgaW50ZXJ2ZW50aW9ucywgcGVyIGNvaG9ydCIpCmBgYAoKYGBge3J9CmJhclN5bXAoImNyaXRjYXJlIiwgImNyaXRjYXJlIiwgZXhjbHVkZV9zaW5nbGUgPSAiZGF5cyIsIHBsb3R0aXRsZSA9ICJDYXNlcyByZWNlaXZpbmcgY3JpdGljYWwgY2FyZSBpbnRlcnZlbnRpb25zIikKYGBgCgojIyBUcmVhdG1lbnRzCiMjIyBJVklnCmBgYHtyfQptYWtlQmFycGxvdCh2YXJfaWRfY29ob3J0ID0gInJ4X0lWSWdfb25jZV9uIiwgdmFyX2lkX3NpbmdsZSA9ICJyeF9JVklnX29uY2UiLCB2YXJfaWQgPSAiSVZJZyIpCmBgYAoKIyMjIE92ZXJhbGwgdGhlcmFweQpgYGB7ciBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoPSA4fQptYWtlSGVhdG1hcF9jb2hvcnQoInJ4IiwgInJ4IixleGNsdWRlX3NpbmdsZSA9ICJkYXlzIiwgcGxvdHRpdGxlID0gIkNhc2VzIHJlY2VpdmluZyB0cmVhdG1lbnQsIHBlciBjb2hvcnQiKQpgYGAKCmBgYHtyfQpiYXJTeW1wKCJyeCIsICJyeCIsIGV4Y2x1ZGVfc2luZ2xlID0gImRheXMiLCBwbG90dGl0bGUgPSAiQ2FzZXMgcmVjZWl2aW5nIHRyZWF0bWVudCIpCmBgYAoKCiMgQ2FzZSBkZWZpbml0aW9ucyAKIyMgTGFiIHJlZmVyZW5jZSB2YWx1ZXMKQ3V0LW9mZnMgaW4gdGhpcyBzdHVkeToKCi0gTmV1dHJvcGhpbGlhID4gODAwMC/CtUwKLSBFbGV2YXRlZCBDUlAgPiAxMCBtZy9MCi0gTHltcGhvcGVuaWEgPCAxMjUwL8K1TAotIFdCQyA+IDExMDAwL8K1TAotIEZpYnJpbm9nZW4gPiA0MDAgbWcvZEwKLSBELWRpbWVycyA+IDI1MCBuZy9tTAotIEZlcnJpdGluID4gMzAwIG5nL21MCi0gQWxidW1pbiA8IDM0IGcvTAotIFByb2NhbGNpdG9uaW4gPiAwLjQ5IG5nL21MCi0gTERIID4gMjgwIFUvTAotIElMNiA+IDE2LjQgcGcvbUwKLSBFU1IgPiAyMiBtbS8KLSBCTlAgPiAxMDAgcGcvbUwKLSBOVHByb0JOUCA+IDQwMCBwZy9tTAotIFRyb3BvbmluID4gMC4wNCBuZy9tTAoKIyMgUkNQQ0gsIENEQyBhbmQgV0hPIHsudGFic2V0fQoKIyMjIFBJTVMtVFMKW1NvdXJjZSBSQ1BDSF0oaHR0cHM6Ly93d3cucmNwY2guYWMudWsvc2l0ZXMvZGVmYXVsdC9maWxlcy8yMDIwLTA1L0NPVklELTE5LVBhZWRpYXRyaWMtbXVsdGlzeXN0ZW0tJTIwaW5mbGFtbWF0b3J5JTIwc3luZHJvbWUtMjAyMDA1MDEucGRmKSAgCgoxLiBBIGNoaWxkIHByZXNlbnRpbmcgd2l0aCBwZXJzaXN0ZW50IGZldmVyLCBpbmZsYW1tYXRpb24gKG5ldXRyb3BoaWxpYSwgZWxldmF0ZWQgQ1JQIGFuZCBseW1waG9wYWVuaWEpIGFuZCBldmlkZW5jZSBvZiBzaW5nbGUgb3IgbXVsdGktb3JnYW4gZHlzZnVuY3Rpb24gKHNob2NrLCBjYXJkaWFjLCByZXNwaXJhdG9yeSwgcmVuYWwsIGdhc3Ryb2ludGVzdGluYWwgb3IgbmV1cm9sb2dpY2FsIGRpc29yZGVyKSB3aXRoIGFkZGl0aW9uYWwgZmVhdHVyZXMgKHNlZSBsaXN0ZWQgaW4gQXBwZW5kaXggMSkuIFRoaXMgbWF5IGluY2x1ZGUgY2hpbGRyZW4gZnVsZmlsbGluZyBmdWxsIG9yIHBhcnRpYWwgY3JpdGVyaWEgZm9yIEthd2FzYWtpIGRpc2Vhc2UuCjIuIEV4Y2x1c2lvbiBvZiBhbnkgb3RoZXIgbWljcm9iaWFsIGNhdXNlLCBpbmNsdWRpbmcgYmFjdGVyaWFsIHNlcHNpcywgc3RhcGh5bG9jb2NjYWwgb3Igc3RyZXB0b2NvY2NhbCBzaG9jayBzeW5kcm9tZXMsIGluZmVjdGlvbnMgYXNzb2NpYXRlZCB3aXRoIG15b2NhcmRpdGlzIHN1Y2ggYXMgZW50ZXJvdmlydXMgKHdhaXRpbmcgZm9yIHJlc3VsdHMgb2YgdGhlc2UgaW52ZXN0aWdhdGlvbnMgc2hvdWxkIG5vdCBkZWxheSBzZWVraW5nIGV4cGVydCBhZHZpY2UpLgozLiBTQVJTLUNvVi0yIFBDUiB0ZXN0aW5nIG1heSBiZSBwb3NpdGl2ZSBvciBuZWdhdGl2ZSAKCldlIGFyZSB1bmFibGUgdG8gZXZhbHVhdGUgY3JpdGVyaWEgMi4KCmBgYHtyLCBmaWcuaGVpZ2h0PSAxMCwgZmlnLndpZHRoPSA4fQpQSU1TX1RTX2Z1bGZpbGxlZCA8LSBhcHBseShkZl9zaW5nbGVjYXNlcywgMSwgZnVuY3Rpb24ocm93KSB7CiAgIyBwZXJzaXN0ZW50IGZldmVyLCBpbmZsYW1tYXRpb24gKG5ldXRyb3BoaWxpYSwgZWxldmF0ZWQgQ1JQIGFuZCBseW1waG9wYWVuaWEpIAogIHBhdF9pZCA8LSByb3dbInBhdGllbnRJRF9pbnQiXQogIGZldmVyIDwtIHJvd1sic3ltcF9mZXZlciJdID09IFRSVUUKICBuZXV0cm9waGlsaWEgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9uZXV0cm9waGlscyJdKSA+IGNvX25ldXRyb3BoaWxpYQogIGVsZXZhdGVkX0NSUCA8LSAoYXMubnVtZXJpYyhyb3dbImxhYl9DUlBfYWRtaXMiXSkgPiBjb19DUlAgfCBhcy5udW1lcmljKHJvd1sibGFiX0NSUF9OUyJdKSA+IGNvX0NSUCB8IGFzLm51bWVyaWMocm93WyJsYWJfQ1JQX3BlYWsiXSkgPiBjb19DUlAgKQogIGx5bXBob3BlbmlhIDwtIGFzLm51bWVyaWMocm93WyJsYWJfbHltcGhvY3l0ZXNfbG93ZXN0Il0pIDwgY29fbHltcGhvCiAgaW5mbGFtbSA8LSBhbnkoZmV2ZXIsIG5ldXRyb3BoaWxpYSwgZWxldmF0ZWRfQ1JQLCBseW1waG9wZW5pYSkKICAKICAjIGxhYiB2YWx1ZXMKICAjZmlicmlub2dlbiA8LSByb3dbImxhYl9maWJyaW5vIl0gPiBjb19maWJyaW5vCiAgI0RkaW1lcnMgPC0gcm93WyJsYWJfRGRpbV9wZWFrIl0gPiBjb19EZGltIHwgIHJvd1sibGFiX0RkaW1fTlMiXSA+IGNvX0RkaW0KICAjZmVycml0aW4gPC0gKHJvd1sibGFiX2ZlcnJpdGluX05TIl0gPiBjb19mZXJyaXRpbiB8IHJvd1sibGFiX2ZlcnJpdGluX2FkbWlzIl0gPiBjb19mZXJyaXRpbiB8IHJvd1sibGFiX2ZlcnJpdGluX3BlYWsiXSA+IGNvX2ZlcnJpdGluKQogICNhbGJ1bWluIDwtIHJvd1sibGFiX2FsYnVtaW5fYWRtaXMiXSA8IGNvX2FsYnUgfCByb3dbImxhYl9hbGJ1bWluX2xvd2VzdCJdIDwgY29fYWxidSB8IHJvd1sibGFiX2FsYnVtaW5fTlMiXSA8IGNvX2FsYnUKICAjbGFiX3ZhbHMgPC0gYW55KGZpYnJpbm9nZW4sIERkaW1lcnMsIGZlcnJpdGluLCBhbGJ1bWluKQogIAogICMgc2luZ2xlIG9yIG11bHRpLW9yZ2FuIGR5c2Z1bmN0aW9uIChzaG9jaywgY2FyZGlhYywgcmVzcGlyYXRvcnksIHJlbmFsLCBnYXN0cm9pbnRlc3RpbmFsIG9yIG5ldXJvbG9naWNhbCBkaXNvcmRlcikKICBwbmV1bW9uaWEgPC0gcm93WyJzeW1wX3Jlc3BfcG5ldW1vbmlhIl0gPT0gVFJVRQogIHJlc3BfZmFpbHVyZSA8LSByb3dbInN5bXBfcmVzcF9mYWlsdXJlIl0gPT0gVFJVRQogIHJlc3AgPC0gYW55KHBuZXVtb25pYSwgcmVzcF9mYWlsdXJlKQogIAogIEFLSSA8LSByb3dbInN5bXBfcmVuYWxfQUtJIl0gPT0gVFJVRQogIFJSVCA8LSByb3dbImNyaXRjYXJlX1JSVCJdID09IFRSVUUKICByZW5hbCA8LSBhbnkoQUtJLCBSUlQpCiAgCiAgbXlvY2FyZGl0aXMgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2NfbXlvY2FyZCJdID09IFRSVUUKICBwZXJpY2FyZGl0aXMgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2NfcGVyaWNhcmQiXSA9PSBUUlVFCiAgTFZFRl91bmRlcjMwIDwtIHJvd1sic3ltcF9jYXJkaW92YXNjX0xWX2xlc3MzMCJdID09IFRSVUUKICBMVkVGXzMwdG81NSA8LSByb3dbInN5bXBfY2FyZGlvdmFzY19MVl8zMHRvNTUiXSA9PSBUUlVFCiAgQk5QIDwtIChhcy5udW1lcmljKHJvd1sibGFiX0JOUF9hZG1pcyJdKSA+IGNvX0JOUCB8IGFzLm51bWVyaWMocm93WyJsYWJfQk5QX21heCJdKSA+IGNvX0JOUCApIAogIE5UcHJvQk5QIDwtIGFzLm51bWVyaWMocm93WyJsYWJfTlRwcm9CTlAiXSkgPiBjb19OVHByb0JOUAogIHRyb3BvIDwtIGFzLm51bWVyaWMocm93WyJsYWJfdHJvcG9uaW5fYWRtaXMiXSkgPiBjb190cm9wbwogIHNob2NrIDwtIHJvd1sic3ltcF9jYXJkaW92YXNjX3Nob2NrIl0gPT0gVFJVRQogIAogIAogIGNhcmRpb3Zhc2MgPC0gYW55KG15b2NhcmRpdGlzLCBMVkVGX3VuZGVyMzAsIExWRUZfMzB0bzU1LCBOVHByb0JOUCwgQk5QLCB0cm9wbywgc2hvY2spCiAgCiAgcmFzaCA8LSByb3dbImthd2FzYWtpX2V4YW50aGVtYSJdID09IFRSVUUKICBkZXJtYXRvIDwtIGFueShyYXNoKQogIAogIGRkaW0gPC0gYXMubnVtZXJpYyhyb3dbImxhYl9EZGltX05TIl0pID49IGNvX0RkaW0KICBoZW1hdG8gPC0gYW55KGRkaW0pCiAgCiAgb3JnYW5fZHlzZnVuYyA8LSBzdW0oaGVtYXRvLCByZXNwLCByZW5hbCwgY2FyZGlvdmFzYywgZGVybWF0bywgbmEucm0gPSBUUlVFKSA+PSAxCiAgCiAgY3JpdGVyaWFfZnVsZmlsbGVkIDwtIChpbmZsYW1tKSAmIG9yZ2FuX2R5c2Z1bmMgIyZsYWJfdmFscwogICNyZXR1cm4oYyhwYXRfaWQsICJjcml0ZXJpYTFfaW5mbGFtbSIgPSBpbmZsYW1tLCAiY3JpdGVyaWEyX2xhYnZhbHMiID0gbGFiX3ZhbHMsICJjcml0ZXJpYTNfb3JnYW5keXNmdW5jIiA9IG9yZ2FuX2R5c2Z1bmMsICJjcml0ZXJpYV9mdWxmaWxsZWQiID0gY3JpdGVyaWFfZnVsZmlsbGVkKSkKICByZXR1cm4oYyhwYXRfaWQsICJjcml0ZXJpYTFfaW5mbGFtbSIgPSBpbmZsYW1tLCAiY3JpdGVyaWEyX29yZ2FuZHlzZnVuYyIgPSBvcmdhbl9keXNmdW5jLCAiY3JpdGVyaWFfZnVsZmlsbGVkIiA9IGNyaXRlcmlhX2Z1bGZpbGxlZCkpCn0pCgpQSU1TX1RTX2Z1bGZpbGxlZCA8LSBQSU1TX1RTX2Z1bGZpbGxlZCAlPiUgdCgpICU+JSBhc190aWJibGUoKQpQSU1TX1RTX2Z1bGZpbGxlZCA8LSB0eXBlX2NvbnZlcnQoUElNU19UU19mdWxmaWxsZWQpClBJTVNfVFNfZnVsZmlsbGVkX2hlYXRtYXAgPC0gUElNU19UU19mdWxmaWxsZWQKY29scyA8LSBzYXBwbHkoUElNU19UU19mdWxmaWxsZWRfaGVhdG1hcCwgaXMubG9naWNhbCkKUElNU19UU19mdWxmaWxsZWRfaGVhdG1hcFssY29sc10gPC0gbGFwcGx5KFBJTVNfVFNfZnVsZmlsbGVkX2hlYXRtYXBbLGNvbHNdLCBhcy5udW1lcmljKQpQSU1TX1RTX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQgPC0gUElNU19UU19mdWxmaWxsZWRfaGVhdG1hcCAlPiUgbWVsdCgpClBJTVNfVFNfZnVsZmlsbGVkX2hlYXRtYXBfbWVsdFtpcy5uYShQSU1TX1RTX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQpXSA8LSAyCgpza2ltKFBJTVNfVFNfZnVsZmlsbGVkKQoKI2dncGxvdChQSU1TX1RTX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBhcy5jaGFyYWN0ZXIocGF0aWVudElEX2ludCksIGZpbGwgPSBhcy5mYWN0b3IodmFsdWUpKSkgKyBnZW9tX3RpbGUoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpICsgbGFicyh5ID0gIlBhdGllbnQgSUQiLCB4ID0gImNyaXRlcmlhIiwgZmlsbCA9ICJjcml0ZXJpYSBtZXQiLCB0aXRsZSA9ICJPdmVydmlldyBvZiB3aGljaCBzaW5nbGUgY2FzZXMgZnVsZmlsbCBQSU1TLVRTIGNhc2UgZGVmaW5pdGlvbiIpICsgIHNjYWxlX2ZpbGxfbWFudWFsKGxhYmVscyA9IGMoIk5vIiwgIlllcyIsICJNaXNzaW5nIiksIHZhbHVlcyA9IGMoInBpbmsyIiwgInJveWFsYmx1ZTMiLCAiZGFya2dyZXkiKSkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpKQpgYGAKCiMjIyBDREMgTUlTLUMKW1NvdXJjZSBDRENdKGh0dHBzOi8vd3d3LmNkYy5nb3YvbWlzLWMvaGNwLykgYW5kIFtVcFRvRGF0ZV0oaHR0cHM6Ly93d3cudXB0b2RhdGUuY29tL2NvbnRlbnRzL2ltYWdlP2ltYWdlS2V5PVBFRFMlMkYxMjgyMDEmdG9waWNLZXk9UEVEUyUyRjEyNzQ4OCkKClRoZSBjYXNlIGRlZmluaXRpb24gZm9yIE1JUy1DIGlzOgoKMS4gQWdlIDwyMSB5ZWFycwoyLiBDbGluaWNhbCBwcmVzZW50YXRpb24gY29uc2lzdGVudCB3aXRoIE1JUy1DLCBpbmNsdWRpbmcgYWxsIG9mIHRoZSBmb2xsb3dpbmc6Ci0gRmV2ZXIKLSBEb2N1bWVudGVkIGZldmVyID4zOC4wwrBDICgxMDAuNMKwRikgZm9yIOKJpTI0IGhvdXJzIG9yCi0gUmVwb3J0IG9mIHN1YmplY3RpdmUgZmV2ZXIgbGFzdGluZyDiiaUyNCBob3VycwotIExhYm9yYXRvcnkgZXZpZGVuY2Ugb2YgaW5mbGFtbWF0aW9uCi0gU2V2ZXJlIGlsbG5lc3MgcmVxdWlyaW5nIGhvc3BpdGFsaXphdGlvbgotIE11bHRpc3lzdGVtIGludm9sdmVtZW50Ci0gMiBvciBtb3JlIG9yZ2FuIHN5c3RlbXMgaW52b2x2ZWQKLSBDYXJkaW92YXNjdWxhciAoZWcsIHNob2NrLCBlbGV2YXRlZCB0cm9wb25pbiwgZWxldmF0ZWQgQk5QLCBhYm5vcm1hbCBlY2hvY2FyZGlvZ3JhbSwgYXJyaHl0aG1pYSkKLSBSZXNwaXJhdG9yeSAoZWcsIHBuZXVtb25pYSwgQVJEUywgcHVsbW9uYXJ5IGVtYm9saXNtKQotIFJlbmFsIChlZywgQUtJLCByZW5hbCBmYWlsdXJlKQotIE5ldXJvbG9naWMgKGVnLCBzZWl6dXJlLCBzdHJva2UsIGFzZXB0aWMgbWVuaW5naXRpcykKLSBIZW1hdG9sb2dpYyAoZWcsIGNvYWd1bG9wYXRoeSkKLSBHYXN0cm9pbnRlc3RpbmFsIChlZywgZWxldmF0ZWQgbGl2ZXIgZW56eW1lcywgZGlhcnJoZWEsIGlsZXVzLCBnYXN0cm9pbnRlc3RpbmFsIGJsZWVkaW5nKQotIERlcm1hdG9sb2dpYyAoZWcsIGVyeXRocm9kZXJtYSwgbXVjb3NpdGlzLCBvdGhlciByYXNoKQozLiBObyBhbHRlcm5hdGl2ZSBwbGF1c2libGUgZGlhZ25vc2VzCjQuIFJlY2VudCBvciBjdXJyZW50IFNBUlMtQ29WLTIgaW5mZWN0aW9uIG9yIGV4cG9zdXJlCi0gQW55IG9mIHRoZSBmb2xsb3dpbmc6Ci0gUG9zaXRpdmUgU0FSUy1Db1YtMiBSVC1QQ1IKLSBQb3NpdGl2ZSBzZXJvbG9neQotIFBvc2l0aXZlIGFudGlnZW4gdGVzdAotIENPVklELTE5IGV4cG9zdXJlIHdpdGhpbiB0aGUgNCB3ZWVrcyBwcmlvciB0byB0aGUgb25zZXQgb2Ygc3ltcHRvbXMKCgoKYGBge3IsIGZpZy5oZWlnaHQ9IDEwLCBmaWcud2lkdGg9IDh9CgpDRENfZnVsZmlsbGVkIDwtIGFwcGx5KGRmX3NpbmdsZWNhc2VzLCAxLCBmdW5jdGlvbihyb3cpIHsKICAjIGNyaXRlcmlhIDEKICBjcml0ZXJpYTEgPSBUUlVFCiAgCiAgIyBjcml0ZXJpYSAyCiAgcGF0X2lkIDwtIHJvd1sicGF0aWVudElEX2ludCJdCiAgCiAgIyBmZXZlcj8KICBmZXZlciA8LSByb3dbInN5bXBfZmV2ZXIiXSA9PSBUUlVFIHwgcm93WyJrYXdhc2FraV9mZXZlciJdID09IFRSVUUKICAKICBpbmZsYW1tIDwtIGFueShmZXZlcikKICAKICAjIGxhYiB2YWx1ZXMgZXZpZGVuY2UgZm9yIGluZmxhbW1hdGlvbgogIG5ldXRyb3BoaWxpYSA8LSBhcy5udW1lcmljKHJvd1sibGFiX25ldXRyb3BoaWxzIl0pID4gY29fbmV1dHJvcGhpbGlhCiAgZWxldmF0ZWRfQ1JQIDwtIChhcy5udW1lcmljKHJvd1sibGFiX0NSUF9hZG1pcyJdKSA+IGNvX0NSUCB8IGFzLm51bWVyaWMocm93WyJsYWJfQ1JQX05TIl0pID4gY29fQ1JQIHwgYXMubnVtZXJpYyhyb3dbImxhYl9DUlBfcGVhayJdKSA+IGNvX0NSUCApCiAgbHltcGhvcGVuaWEgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9seW1waG9jeXRlc19sb3dlc3QiXSkgPCBjb19seW1waG8KICBmaWJyaW5vZ2VuIDwtIGFzLm51bWVyaWMocm93WyJsYWJfZmlicmlubyJdKSA+IGNvX2ZpYnJpbm8KICBEZGltZXJzIDwtIGFzLm51bWVyaWMocm93WyJsYWJfRGRpbV9wZWFrIl0pID4gY29fRGRpbSB8ICBhcy5udW1lcmljKHJvd1sibGFiX0RkaW1fTlMiXSkgPiBjb19EZGltCiAgZmVycml0aW4gPC0gKGFzLm51bWVyaWMocm93WyJsYWJfZmVycml0aW5fTlMiXSkgPiBjb19mZXJyaXRpbiB8IGFzLm51bWVyaWMocm93WyJsYWJfZmVycml0aW5fYWRtaXMiXSkgPiBjb19mZXJyaXRpbiB8IGFzLm51bWVyaWMocm93WyJsYWJfZmVycml0aW5fcGVhayJdKSA+IGNvX2ZlcnJpdGluKQogIGFsYnVtaW4gPC0gYXMubnVtZXJpYyhyb3dbImxhYl9hbGJ1bWluX2FkbWlzIl0pIDwgY29fYWxidSB8IGFzLm51bWVyaWMocm93WyJsYWJfYWxidW1pbl9sb3dlc3QiXSkgPCBjb19hbGJ1IHwgYXMubnVtZXJpYyhyb3dbImxhYl9hbGJ1bWluX05TIl0pIDwgY29fYWxidQogIFBDVCA8LSBhcy5udW1lcmljKHJvd1sibGFiX1BDVF9hZG1pcyJdKSA+IGNvX1BDVCB8IGFzLm51bWVyaWMocm93WyJsYWJfUENUX3BlYWsiXSkgPiBjb19QQ1QgfCBhcy5udW1lcmljKHJvd1sibGFiX1BDVF9OUyJdKSA+IGNvX1BDVCAKICBMREggPC0gYXMubnVtZXJpYyhyb3dbImxhYl9MREgiXSkgPiBjb19MREgKICBJTDYgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9JTDYiXSkgPiBjb19JTDYKICBFU1IgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9FU1IiXSkgPiBjb19FU1IKICAKICBsYWJfdmFscyA8LSBhbnkobmV1dHJvcGhpbGlhLCBlbGV2YXRlZF9DUlAsIGx5bXBob3BlbmlhLCBmaWJyaW5vZ2VuLCBEZGltZXJzLCBmZXJyaXRpbiwgYWxidW1pbiwgUENULCBMREgsIElMNiwgRVNSKQogIAogICMgSWxuZXNzIHJlcXVpcmluZyBob3NwaXRhbGlzYXRpb24KICAjIyB1c2VkIHN1cnJvZ2F0ZSBwYXJhbWV0ZXJzIGZvciBob3NwCiAgaG9zcF9JQ1UgPC0gcm93WyJhZG1pc19ob3NwX2RheXMiXSA+IDEgfCByb3dbImFkbWlzX0lDVV9kYXlzIl0gPiAxIHwgcm93WyJhZG1pc19QSUNVX2FkbWlzIl0gPT0gVFJVRQogIE5JViA8LSByb3dbImNyaXRjYXJlX05JViJdID09IFRSVUUgfCByb3dbImNyaXRjYXJlX05JVl9kYXlzIl0gPiAxCiAgTVYgPC0gcm93WyJjcml0Y2FyZV9NViJdID09IFRSVUUgfCByb3dbImNyaXRjYXJlX01WX2RheXMiXSA+IDEKICBpbm90cm9wIDwtIHJvd1siY3JpdGNhcmVfaW5vdHJvcCJdID09IFRSVUUgfCByb3dbImNyaXRjYXJlX2lub3Ryb3BfZGF5cyJdID4gMQogIEVDTU8gPC0gcm93WyJjcml0Y2FyZV9FQ01PIl0gPT0gVFJVRSAKICBJVklnIDwtIHJvd1sicnhfSVZJZ19vbmNlIl0gPT0gVFJVRSAgfCAgcm93WyJyeF9JVklnX211bHRpcCJdID09IFRSVUUgCiAgYmlvbG9naWNhbHMgPC0gcm93WyJyeF9hbmFraW5yYSJdID09IFRSVUUgfCByb3dbInJ4X3RvY2lsaXp1bWFiIl0gPT0gVFJVRSB8IHJvd1sicnhfaW5mbGl4aW1hYiJdID09IFRSVUUgfCByb3dbInJ4X2FudGliaW90aWNzIl0gPT0gVFJVRSB8IHJvd1sicnhfcGxhc21hIl0gPT0gVFJVRSB8IHJvd1sicnhfcmVtZGVzaXZpciJdID09IFRSVUUgCiAgaGVwYXJpbiA8LSByb3dbInJ4X2hlcGFyaW4iXSA9PSBUUlVFCiAgCiAgCiAgcmVxX2hvc3AgPC0gYW55KGhvc3BfSUNVLCBOSVYsIE1WLCBpbm90cm9wLCBFQ01PLCBJVklnLCBiaW9sb2dpY2FscywgaGVwYXJpbikKICAKICAjIyBtdWx0aXN5c3RlbSBpbnZvbHZlbWVudCA+PSAyCiAgIyMgcmVzcGlyYXRvcnkKICBwbmV1bW9uaWEgPC0gcm93WyJzeW1wX3Jlc3BfcG5ldW1vbmlhIl0gPT0gVFJVRQogIHJlc3BfZmFpbHVyZSA8LSByb3dbInN5bXBfcmVzcF9mYWlsdXJlIl0gPT0gVFJVRQogIHJlc3AgPC0gYW55KHBuZXVtb25pYSwgcmVzcF9mYWlsdXJlKQogIAogIEFLSSA8LSByb3dbInN5bXBfcmVuYWxfQUtJIl0gPT0gVFJVRQogIFJSVCA8LSByb3dbImNyaXRjYXJlX1JSVCJdID09IFRSVUUKICByZW5hbCA8LSBhbnkoQUtJLCBSUlQpCiAgCiAgbXlvY2FyZGl0aXMgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2NfbXlvY2FyZCJdID09IFRSVUUKICBwZXJpY2FyZGl0aXMgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2NfcGVyaWNhcmQiXSA9PSBUUlVFCiAgTFZFRl91bmRlcjMwIDwtIHJvd1sic3ltcF9jYXJkaW92YXNjX0xWX2xlc3MzMCJdID09IFRSVUUKICBMVkVGXzMwdG81NSA8LSByb3dbInN5bXBfY2FyZGlvdmFzY19MVl8zMHRvNTUiXSA9PSBUUlVFCiAgQk5QIDwtIChhcy5udW1lcmljKHJvd1sibGFiX0JOUF9hZG1pcyJdKSA+IGNvX0JOUCB8IGFzLm51bWVyaWMocm93WyJsYWJfQk5QX21heCJdKSA+IGNvX0JOUCApIAogIE5UcHJvQk5QIDwtIGFzLm51bWVyaWMocm93WyJsYWJfTlRwcm9CTlAiXSkgPiBjb19OVHByb0JOUAogIHRyb3BvIDwtIGFzLm51bWVyaWMocm93WyJsYWJfdHJvcG9uaW5fYWRtaXMiXSkgPiBjb190cm9wbwogIHNob2NrIDwtIHJvd1sic3ltcF9jYXJkaW92YXNjX3Nob2NrIl0gPT0gVFJVRQogIAogIGNhcmRpb3Zhc2MgPC0gYW55KG15b2NhcmRpdGlzLCBMVkVGX3VuZGVyMzAsIExWRUZfMzB0bzU1LCBOVHByb0JOUCwgQk5QLCB0cm9wbywgc2hvY2spCiAgCiAgcmFzaCA8LSByb3dbImthd2FzYWtpX2V4YW50aGVtYSJdID09IFRSVUUKICBkZXJtYXRvIDwtIGFueShyYXNoKQogIAogIG9yZ2FuX2R5c2Z1bmMgPC0gc3VtKHJlc3AsIHJlbmFsLCBjYXJkaW92YXNjLCBkZXJtYXRvLCBuYS5ybSA9IFRSVUUpID49IDIKICAKICBjcml0ZXJpYTIgPC0gc3VtKGluZmxhbW0sIGxhYl92YWxzLCByZXFfaG9zcCwgb3JnYW5fZHlzZnVuYywgbmEucm0gPSBUUlVFKSA9PSA0CiAgIyBjcml0ZXJpYSAzCiAgIyMgbm90IGV2YWx1YWJsZQogIGNyaXRlcmlhMyA9IFRSVUUKICAjIGNyaXRlcmlhIDQKICAjIENPVklEIHBvcz8KICBQQ1JfcG9zIDwtIHJvd1siY292aWRfUENSX3BvcyJdID09IFRSVUUKICBzdG9vbF9wb3MgPC0gcm93WyJjb3ZpZF9QQ1Jfc3Rvb2xfcG9zIl0gPT0gVFJVRQogIGNsb3NlY29udGFjdCA8LSByb3dbImNvdmlkX2Nsb3NlY29udGFjdCJdID09IFRSVUUKICBJZ0EgPC0gcm93WyJjb3ZpZF9JZ0FfcG9zIl0gPT0gVFJVRQogIElnTSA8LSByb3dbImNvdmlkX0lnTV9wb3MiXSA9PSBUUlVFICAgIAogIElnRyA8LSByb3dbImNvdmlkX0lnR19wb3MiXSA9PSBUUlVFICAgIAogIGFueV9zZXJvIDwtIHJvd1siY292aWRfc2Vyb19wb3MiXSA9PSBUUlVFCiAgCiAgY3JpdGVyaWE0IDwtIGFueShQQ1JfcG9zLCBzdG9vbF9wb3MsIGNsb3NlY29udGFjdCwgSWdBLCBJZ00sIElnRywgYW55X3Nlcm8pCiAgCiAgaWYgKEZBTFNFICVpbiUgYyhjcml0ZXJpYTEsIGNyaXRlcmlhMiwgY3JpdGVyaWEzLCBjcml0ZXJpYTQpKXsKICAgIGNyaXRlcmlhX2Z1bGZpbGxlZCA8LSBGQUxTRQogIH0gZWxzZSBpZiAoTkEgJWluJSBjKGNyaXRlcmlhMSwgY3JpdGVyaWEyLCBjcml0ZXJpYTMsIGNyaXRlcmlhNCkpewogICAgY3JpdGVyaWFfZnVsZmlsbGVkIDwtIE5BCiAgfSBlbHNlIGlmIChzdW0oY3JpdGVyaWExLCBjcml0ZXJpYTIsIGNyaXRlcmlhMywgY3JpdGVyaWE0LCBuYS5ybSA9IFRSVUUpID09IDQpewogICAgY3JpdGVyaWFfZnVsZmlsbGVkIDwtIFRSVUUKICB9CiAgCiAgI2NyaXRlcmlhX2Z1bGZpbGxlZCA8LSBzdW0oY3JpdGVyaWExLCBjcml0ZXJpYTIsIGNyaXRlcmlhMywgY3JpdGVyaWE0LCBuYS5ybSA9IFRSVUUpID09IDQKICByZXR1cm4oYyhwYXRfaWQsICJjcml0ZXJpYTFfYWdlIiA9IGNyaXRlcmlhMSwgImNyaXRlcmlhMl9jbGluaWNhbCIgPSBjcml0ZXJpYTIsICJjcml0ZXJpYTNfbm9BbHQiID0gY3JpdGVyaWEzLCAiY3JpdGVyaWE0X3JlY2VudEV4cG9zdXJlIiA9IGNyaXRlcmlhNCwgImNyaXRlcmlhX2Z1bGZpbGxlZCIgPSBjcml0ZXJpYV9mdWxmaWxsZWQpKQp9KQoKQ0RDX2Z1bGZpbGxlZCA8LSBDRENfZnVsZmlsbGVkICU+JSB0KCkgJT4lIGFzX3RpYmJsZSgpCkNEQ19mdWxmaWxsZWQgPC0gdHlwZV9jb252ZXJ0KENEQ19mdWxmaWxsZWQpCkNEQ19mdWxmaWxsZWRfaGVhdG1hcCA8LSBDRENfZnVsZmlsbGVkCmNvbHMgPC0gc2FwcGx5KENEQ19mdWxmaWxsZWRfaGVhdG1hcCwgaXMubG9naWNhbCkKQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwWyxjb2xzXSA8LSBsYXBwbHkoQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwWyxjb2xzXSwgYXMubnVtZXJpYykKQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQgPC0gQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwICU+JSBtZWx0KCkKQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHRbaXMubmEoQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQpXSA8LSAyCgpza2ltKENEQ19mdWxmaWxsZWQpCiNnZ3Bsb3QoQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBhcy5jaGFyYWN0ZXIocGF0aWVudElEX2ludCksIGZpbGwgPSBhcy5mYWN0b3IodmFsdWUpKSkgKyBnZW9tX3RpbGUoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpICsgbGFicyh5ID0gIlBhdGllbnQgSUQiLCB4ID0gImNyaXRlcmlhIiwgZmlsbCA9ICJjcml0ZXJpYSBtZXQiLCB0aXRsZSA9ICJPdmVydmlldyBvZiB3aGljaCBzaW5nbGUgY2FzZXMgZnVsZmlsbCBDREMgTUlTLUMgY2FzZSBkZWZpbml0aW9uIikgKyAgc2NhbGVfZmlsbF9tYW51YWwobGFiZWxzID0gYygiTm8iLCAiWWVzIiwgIk1pc3NpbmciKSwgdmFsdWVzID0gYygicGluazIiLCAicm95YWxibHVlMyIsICJkYXJrZ3JleSIpKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3Q9MSkpCmBgYAoKIyMjIyBDREMgY3JpdGVyaXVtIDIgaW4gbW9yZSBkZXRhaWwKYGBge3IsIGZpZy5oZWlnaHQgPSAxNiwgZmlnLndpZHRoPTd9CkNEQ19mdWxmaWxsZWRfY3JpdDIgPC0gYXBwbHkoZGZfc2luZ2xlY2FzZXMsIDEsIGZ1bmN0aW9uKHJvdykgewogIHBhdF9pZCA8LSByb3dbInBhdGllbnRJRF9pbnQiXQogIAogICMgZmV2ZXI/CiAgZmV2ZXIgPC0gcm93WyJzeW1wX2ZldmVyIl0gPT0gVFJVRSB8IHJvd1sia2F3YXNha2lfZmV2ZXIiXSA9PSBUUlVFCiAgCiAgaW5mbGFtbSA8LSBhbnkoZmV2ZXIpCiAgCiAgIyBsYWIgdmFsdWVzIGV2aWRlbmNlIGZvciBpbmZsYW1tYXRpb24KICBuZXV0cm9waGlsaWEgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9uZXV0cm9waGlscyJdKSA+IGNvX25ldXRyb3BoaWxpYQogIGVsZXZhdGVkX0NSUCA8LSAoYXMubnVtZXJpYyhyb3dbImxhYl9DUlBfYWRtaXMiXSkgPiBjb19DUlAgfCBhcy5udW1lcmljKHJvd1sibGFiX0NSUF9OUyJdKSA+IGNvX0NSUCB8IGFzLm51bWVyaWMocm93WyJsYWJfQ1JQX3BlYWsiXSkgPiBjb19DUlAgKQogIGx5bXBob3BlbmlhIDwtIGFzLm51bWVyaWMocm93WyJsYWJfbHltcGhvY3l0ZXNfbG93ZXN0Il0pIDwgY29fbHltcGhvCiAgZmlicmlub2dlbiA8LSBhcy5udW1lcmljKHJvd1sibGFiX2ZpYnJpbm8iXSkgPiBjb19maWJyaW5vCiAgRGRpbWVycyA8LSBhcy5udW1lcmljKHJvd1sibGFiX0RkaW1fcGVhayJdKSA+IGNvX0RkaW0gfCAgYXMubnVtZXJpYyhyb3dbImxhYl9EZGltX05TIl0pID4gY29fRGRpbQogIGZlcnJpdGluIDwtIChhcy5udW1lcmljKHJvd1sibGFiX2ZlcnJpdGluX05TIl0pID4gY29fZmVycml0aW4gfCBhcy5udW1lcmljKHJvd1sibGFiX2ZlcnJpdGluX2FkbWlzIl0pID4gY29fZmVycml0aW4gfCBhcy5udW1lcmljKHJvd1sibGFiX2ZlcnJpdGluX3BlYWsiXSkgPiBjb19mZXJyaXRpbikKICBhbGJ1bWluIDwtIGFzLm51bWVyaWMocm93WyJsYWJfYWxidW1pbl9hZG1pcyJdKSA8IGNvX2FsYnUgfCBhcy5udW1lcmljKHJvd1sibGFiX2FsYnVtaW5fbG93ZXN0Il0pIDwgY29fYWxidSB8IGFzLm51bWVyaWMocm93WyJsYWJfYWxidW1pbl9OUyJdKSA8IGNvX2FsYnUKICBQQ1QgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9QQ1RfYWRtaXMiXSkgPiBjb19QQ1QgfCBhcy5udW1lcmljKHJvd1sibGFiX1BDVF9wZWFrIl0pID4gY29fUENUIHwgYXMubnVtZXJpYyhyb3dbImxhYl9QQ1RfTlMiXSkgPiBjb19QQ1QgCiAgTERIIDwtIGFzLm51bWVyaWMocm93WyJsYWJfTERIIl0pID4gY29fTERICiAgSUw2IDwtIGFzLm51bWVyaWMocm93WyJsYWJfSUw2Il0pID4gY29fSUw2CiAgRVNSIDwtIGFzLm51bWVyaWMocm93WyJsYWJfRVNSIl0pID4gY29fRVNSCiAgCiAgbGFiX3ZhbHMgPC0gYW55KG5ldXRyb3BoaWxpYSwgZWxldmF0ZWRfQ1JQLCBseW1waG9wZW5pYSwgZmlicmlub2dlbiwgRGRpbWVycywgZmVycml0aW4sIGFsYnVtaW4sIFBDVCwgTERILCBJTDYsIEVTUikKICAKICAjIElsbmVzcyByZXF1aXJpbmcgaG9zcGl0YWxpc2F0aW9uCiAgIyMgdXNlZCBzdXJyb2dhdGUgcGFyYW1ldGVycyBmb3IgaG9zcAogIGhvc3BfSUNVIDwtIHJvd1siYWRtaXNfaG9zcF9kYXlzIl0gPiAxIHwgcm93WyJhZG1pc19JQ1VfZGF5cyJdID4gMSB8IHJvd1siYWRtaXNfUElDVV9hZG1pcyJdID09IFRSVUUKICBOSVYgPC0gcm93WyJjcml0Y2FyZV9OSVYiXSA9PSBUUlVFIHwgcm93WyJjcml0Y2FyZV9OSVZfZGF5cyJdID4gMQogIE1WIDwtIHJvd1siY3JpdGNhcmVfTVYiXSA9PSBUUlVFIHwgcm93WyJjcml0Y2FyZV9NVl9kYXlzIl0gPiAxCiAgaW5vdHJvcCA8LSByb3dbImNyaXRjYXJlX2lub3Ryb3AiXSA9PSBUUlVFIHwgcm93WyJjcml0Y2FyZV9pbm90cm9wX2RheXMiXSA+IDEKICBFQ01PIDwtIHJvd1siY3JpdGNhcmVfRUNNTyJdID09IFRSVUUgCiAgSVZJZyA8LSByb3dbInJ4X0lWSWdfb25jZSJdID09IFRSVUUgIHwgIHJvd1sicnhfSVZJZ19tdWx0aXAiXSA9PSBUUlVFIAogIGJpb2xvZ2ljYWxzIDwtIHJvd1sicnhfYW5ha2lucmEiXSA9PSBUUlVFIHwgcm93WyJyeF90b2NpbGl6dW1hYiJdID09IFRSVUUgfCByb3dbInJ4X2luZmxpeGltYWIiXSA9PSBUUlVFIHwgcm93WyJyeF9hbnRpYmlvdGljcyJdID09IFRSVUUgfCByb3dbInJ4X3BsYXNtYSJdID09IFRSVUUgfCByb3dbInJ4X3JlbWRlc2l2aXIiXSA9PSBUUlVFIAogIGhlcGFyaW4gPC0gcm93WyJyeF9oZXBhcmluIl0gPT0gVFJVRQogIAogIAogIHJlcV9ob3NwIDwtIGFueShob3NwX0lDVSwgTklWLCBNViwgaW5vdHJvcCwgRUNNTywgSVZJZywgYmlvbG9naWNhbHMsIGhlcGFyaW4pCiAgCiAgIyMgbXVsdGlzeXN0ZW0gaW52b2x2ZW1lbnQgPj0gMgogICMjIHJlc3BpcmF0b3J5CiAgcG5ldW1vbmlhIDwtIHJvd1sic3ltcF9yZXNwX3BuZXVtb25pYSJdID09IFRSVUUKICByZXNwX2ZhaWx1cmUgPC0gcm93WyJzeW1wX3Jlc3BfZmFpbHVyZSJdID09IFRSVUUKICByZXNwIDwtIGFueShwbmV1bW9uaWEsIHJlc3BfZmFpbHVyZSkKICAKICBBS0kgPC0gcm93WyJzeW1wX3JlbmFsX0FLSSJdID09IFRSVUUKICBSUlQgPC0gcm93WyJjcml0Y2FyZV9SUlQiXSA9PSBUUlVFCiAgcmVuYWwgPC0gYW55KEFLSSwgUlJUKQogIAogIG15b2NhcmRpdGlzIDwtIHJvd1sic3ltcF9jYXJkaW92YXNjX215b2NhcmQiXSA9PSBUUlVFCiAgcGVyaWNhcmRpdGlzIDwtIHJvd1sic3ltcF9jYXJkaW92YXNjX3BlcmljYXJkIl0gPT0gVFJVRQogIExWRUZfdW5kZXIzMCA8LSByb3dbInN5bXBfY2FyZGlvdmFzY19MVl9sZXNzMzAiXSA9PSBUUlVFCiAgTFZFRl8zMHRvNTUgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2NfTFZfMzB0bzU1Il0gPT0gVFJVRQogIEJOUCA8LSAoYXMubnVtZXJpYyhyb3dbImxhYl9CTlBfYWRtaXMiXSkgPiBjb19CTlAgfCBhcy5udW1lcmljKHJvd1sibGFiX0JOUF9tYXgiXSkgPiBjb19CTlAgKSAKICBOVHByb0JOUCA8LSBhcy5udW1lcmljKHJvd1sibGFiX05UcHJvQk5QIl0pID4gY29fTlRwcm9CTlAKICB0cm9wbyA8LSBhcy5udW1lcmljKHJvd1sibGFiX3Ryb3BvbmluX2FkbWlzIl0pID4gY29fdHJvcG8KICBzaG9jayA8LSByb3dbInN5bXBfY2FyZGlvdmFzY19zaG9jayJdID09IFRSVUUKICAKICBjYXJkaW92YXNjIDwtIGFueShteW9jYXJkaXRpcywgTFZFRl91bmRlcjMwLCBMVkVGXzMwdG81NSwgTlRwcm9CTlAsIEJOUCwgdHJvcG8sIHNob2NrKQogIAogIHJhc2ggPC0gcm93WyJrYXdhc2FraV9leGFudGhlbWEiXSA9PSBUUlVFCiAgZGVybWF0byA8LSBhbnkocmFzaCkKICAKICBvcmdhbl9keXNmdW5jIDwtIHN1bShyZXNwLCByZW5hbCwgY2FyZGlvdmFzYywgZGVybWF0bywgbmEucm0gPSBUUlVFKSA+PSAyCiAgCgogICNjcml0ZXJpYV9mdWxmaWxsZWQgPC0gc3VtKGNyaXRlcmlhMSwgY3JpdGVyaWEyLCBjcml0ZXJpYTMsIGNyaXRlcmlhNCwgbmEucm0gPSBUUlVFKSA9PSA0CiAgcmV0dXJuKGMocGF0X2lkLCAiY3JpdGVyaWEyX2luZmxhbW0iID0gaW5mbGFtbSwgImNyaXRlcmlhMl9sYWJ2YWxzIiA9IGxhYl92YWxzLCAiY3JpdGVyaWEyX3JlcV9ob3NwIiA9IHJlcV9ob3NwLCAiY3JpdGVyaWEyX29yZ2FuX2R5c2Z1bmMiID0gb3JnYW5fZHlzZnVuYykpCn0pCkNEQ19mdWxmaWxsZWRfY3JpdDIgPC0gQ0RDX2Z1bGZpbGxlZF9jcml0MgpDRENfZnVsZmlsbGVkX2NyaXQyIDwtIENEQ19mdWxmaWxsZWRfY3JpdDIgJT4lIHQoKSAlPiUgYXNfdGliYmxlKCkKQ0RDX2Z1bGZpbGxlZF9jcml0MiA8LSB0eXBlX2NvbnZlcnQoQ0RDX2Z1bGZpbGxlZF9jcml0MikKQ0RDX2Z1bGZpbGxlZF9jcml0Ml9oZWF0bWFwIDwtIENEQ19mdWxmaWxsZWRfY3JpdDIKY29scyA8LSBzYXBwbHkoQ0RDX2Z1bGZpbGxlZF9jcml0Ml9oZWF0bWFwLCBpcy5sb2dpY2FsKQpDRENfZnVsZmlsbGVkX2NyaXQyX2hlYXRtYXBbLGNvbHNdIDwtIGxhcHBseShDRENfZnVsZmlsbGVkX2NyaXQyX2hlYXRtYXBbLGNvbHNdLCBhcy5udW1lcmljKQpDRENfZnVsZmlsbGVkX2NyaXQyX2hlYXRtYXBfbWVsdCA8LSBDRENfZnVsZmlsbGVkX2NyaXQyX2hlYXRtYXAgJT4lIG1lbHQoKQpDRENfZnVsZmlsbGVkX2NyaXQyX2hlYXRtYXBfbWVsdFtpcy5uYShDRENfZnVsZmlsbGVkX2NyaXQyX2hlYXRtYXBfbWVsdCldIDwtIDIKQ0RDX2Z1bGZpbGxlZF9jcml0Ml9oZWF0bWFwX21lbHQkY3JpdGVyaWEgPC0gIkNEQyBjcml0ZXJpYSAyIgojc2tpbShDRENfZnVsZmlsbGVkX2NyaXQyKQoKCmdncGxvdChDRENfZnVsZmlsbGVkX2NyaXQyX2hlYXRtYXBfbWVsdCwgYWVzKHggPSB2YXJpYWJsZSwgeSA9IGFzLmNoYXJhY3RlcihwYXRpZW50SURfaW50KSwgZmlsbCA9IGFzLmZhY3Rvcih2YWx1ZSkpKSArIGdlb21fdGlsZSgpICsgCiAgdGhlbWVfY2xhc3NpYygpICsgdGhlbWUoYXhpcy5saW5lPWVsZW1lbnRfYmxhbmsoKSkgKyAKICBsYWJzKHkgPSAiUGF0aWVudCBJRCIsIHggPSAiY3JpdGVyaWEiLCBmaWxsID0gImNyaXRlcmlhIG1ldCIsIHRpdGxlID0gIk92ZXJ2aWV3IG9mIHdoaWNoIHNpbmdsZSBjYXNlcyBmdWxmaWxsIGNyaXRlcml1bSAyIG9mIHRoZSBDREMgY2FzZSBkZWZpbml0aW9uIikgKyAgCiAgc2NhbGVfZmlsbF9tYW51YWwobGFiZWxzID0gYygiTm8iLCAiWWVzIiwgIk1pc3NpbmciKSwgdmFsdWVzID0gd2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyAKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpKSArIGZhY2V0X3dyYXAofiBjcml0ZXJpYSwgc2NhbGVzID0gImZyZWVfeCIpCmBgYAoKIyMjIFdITyBjYXNlIGRlZmluaXRpb24KW1NvdXJjZSBVcFRvRGF0ZV0oaHR0cHM6Ly93d3cudXB0b2RhdGUuY29tL2NvbnRlbnRzL2ltYWdlP2ltYWdlS2V5PVBFRFMlMkYxMjgyMDEmdG9waWNLZXk9UEVEUyUyRjEyNzQ4OCk6CgpBbGwgNiBjcml0ZXJpYSBtdXN0IGJlIG1ldDoKCjEuIEFnZSAwIHRvIDE5IHllYXJzCjIuIEZldmVyIGZvciDiiaUzIGRheXMKMy4gQ2xpbmljYWwgc2lnbnMgb2YgbXVsdGlzeXN0ZW0gaW52b2x2ZW1lbnQgKGF0IGxlYXN0IDIgb2YgdGhlIGZvbGxvd2luZyk6Ci0gUmFzaCwgYmlsYXRlcmFsIG5vbnB1cnVsZW50IGNvbmp1bmN0aXZpdGlzLCBvciBtdWNvY3V0YW5lb3VzIGluZmxhbW1hdGlvbiBzaWducyAob3JhbCwgaGFuZHMsIG9yIGZlZXQpCi0gSHlwb3RlbnNpb24gb3Igc2hvY2sKLSBDYXJkaWFjIGR5c2Z1bmN0aW9uLCBwZXJpY2FyZGl0aXMsIHZhbHZ1bGl0aXMsIG9yIGNvcm9uYXJ5IGFibm9ybWFsaXRpZXMgKGluY2x1ZGluZyBlY2hvY2FyZGlvZ3JhcGhpYyBmaW5kaW5ncyBvciBlbGV2YXRlZCB0cm9wb25pbi9CTlApCi0gRXZpZGVuY2Ugb2YgY29hZ3Vsb3BhdGh5IChwcm9sb25nZWQgUFQgb3IgUFRUOyBlbGV2YXRlZCBELWRpbWVyKQotIEFjdXRlIGdhc3Ryb2ludGVzdGluYWwgc3ltcHRvbXMgKGRpYXJyaGVhLCB2b21pdGluZywgb3IgYWJkb21pbmFsIHBhaW4pCjQuIEVsZXZhdGVkIG1hcmtlcnMgb2YgaW5mbGFtbWF0aW9uIChlZywgRVNSLCBDUlAsIG9yIHByb2NhbGNpdG9uaW4pCjUuIE5vIG90aGVyIG9idmlvdXMgbWljcm9iaWFsIGNhdXNlIG9mIGluZmxhbW1hdGlvbiwgaW5jbHVkaW5nIGJhY3RlcmlhbCBzZXBzaXMgYW5kIHN0YXBoeWxvY29jY2FsL3N0cmVwdG9jb2NjYWwgdG94aWMgc2hvY2sgc3luZHJvbWVzCjYuIEV2aWRlbmNlIG9mIFNBUlMtQ29WLTIgaW5mZWN0aW9uCi0gQW55IG9mIHRoZSBmb2xsb3dpbmc6Ci0gUG9zaXRpdmUgU0FSUy1Db1YtMiBSVC1QQ1IKLSBQb3NpdGl2ZSBzZXJvbG9neQotIFBvc2l0aXZlIGFudGlnZW4gdGVzdAotIENvbnRhY3Qgd2l0aCBhbiBpbmRpdmlkdWFsIHdpdGggQ09WSUQtMTkKCmBgYHtyLCBmaWcuaGVpZ2h0PSAxMCwgZmlnLndpZHRoPSA4fQojcm93IDwtIGRmX3NpbmdsZWNhc2VzWzg3LCBdCldIT19mdWxmaWxsZWQgPC0gYXBwbHkoZGZfc2luZ2xlY2FzZXMsIDEsIGZ1bmN0aW9uKHJvdykgewogIHBhdF9pZCA8LSByb3dbInBhdGllbnRJRF9pbnQiXQogIAogICMgY3JpdGVyaWEgMQogIGNyaXRlcmlhMSA9IFRSVUUKICAKICAjIGNyaXRlcmlhIDI6IGZldmVyPwogIGZldmVyIDwtIHJvd1sic3ltcF9mZXZlciJdID09IFRSVUUgfCByb3dbImthd2FzYWtpX2ZldmVyIl0gPT0gVFJVRQogIAogIGNyaXRlcmlhMiA8LSBhbnkoZmV2ZXIpCiAgCiAgIyBjcml0ZXJpYSAzOiBjbGluaWNhbCBzaWducyBvZiBtdWx0aXN5c3RlbSBpbnZvbHZlbWVudCAoYXQgbGVhc3QgMikKICAjIyBSYXNoLCBiaWxhdGVyYWwgbm9ucHVydWxlbnQgY29uanVuY3Rpdml0aXMsIG9yIG11Y29jdXRhbmVvdXMgaW5mbGFtbWF0aW9uIHNpZ25zIChvcmFsLCBoYW5kcywgb3IgZmVldCkKICByYXNoIDwtIHJvd1sia2F3YXNha2lfZXhhbnRoZW1hIl0gPT0gVFJVRQogIGNvbmp1bmN0aXZpdGlzIDwtIHJvd1sia2F3YXNha2lfY29uanVuY3Rpdml0aXMiXSA9PSBUUlVFCiAgbXVjb2N1dGFuZWFvdXMgPC0gcm93WyJrYXdhc2FraV9tb3V0aCJdID09IFRSVUUgfCByb3dbImthd2FzYWtpX2V4dHJlbWl0eSJdID09IFRSVUUKICAKICBjcml0ZXJpYTNfYSA8LSBhbnkocmFzaCwgY29uanVuY3Rpdml0aXMsIG11Y29jdXRhbmVhb3VzKQogIAogICMjIGh5cG90ZW5zaW9uIG9yIHNob2NrCiAgc2hvY2sgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2Nfc2hvY2siXSA9PSBUUlVFCiAgY3JpdGVyaWEzX2IgPC0gYW55KHNob2NrKQogIAogICMjIGNhcmRpYWMgZHlzZnVuY3Rpb24KICBteW9jYXJkaXRpcyA8LSByb3dbInN5bXBfY2FyZGlvdmFzY19teW9jYXJkIl0gPT0gVFJVRQogIHBlcmljYXJkaXRpcyA8LSByb3dbInN5bXBfY2FyZGlvdmFzY19wZXJpY2FyZCJdID09IFRSVUUKICBMVkVGX3VuZGVyMzAgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2NfTFZfbGVzczMwIl0gPT0gVFJVRQogIExWRUZfMzB0bzU1IDwtIHJvd1sic3ltcF9jYXJkaW92YXNjX0xWXzMwdG81NSJdID09IFRSVUUKICBCTlAgPC0gKGFzLm51bWVyaWMocm93WyJsYWJfQk5QX2FkbWlzIl0pID4gY29fQk5QIHwgYXMubnVtZXJpYyhyb3dbImxhYl9CTlBfbWF4Il0pID4gY29fQk5QICkgCiAgTlRwcm9CTlAgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9OVHByb0JOUCJdKSA+IGNvX05UcHJvQk5QCiAgdHJvcG8gPC0gYXMubnVtZXJpYyhyb3dbImxhYl90cm9wb25pbl9hZG1pcyJdKSA+IGNvX3Ryb3BvCiAgY29yb25hcnkgPC0gcm93WyJzeW1wX2NhcmRpb3Zhc2NfY29yZGlsYXQiXSA9PSBUUlVFIHwgcm93WyJzeW1wX2NhcmRpb3Zhc2NfYW5ldXJ5c20iXSA9PSBUUlVFCiAgCiAgY3JpdGVyaWEzX2MgPC0gYW55KG15b2NhcmRpdGlzLCBMVkVGX3VuZGVyMzAsIExWRUZfMzB0bzU1LCBOVHByb0JOUCwgQk5QLCB0cm9wbywgY29yb25hcnkpCiAgCiAgIyMgY29hZ3Vsb3BhdGh5CiAgZmlicmlub2dlbiA8LSBhcy5udW1lcmljKHJvd1sibGFiX2ZpYnJpbm8iXSkgPiBjb19maWJyaW5vCiAgRGRpbWVycyA8LSBhcy5udW1lcmljKHJvd1sibGFiX0RkaW1fcGVhayJdKSA+IGNvX0RkaW0gfCAgYXMubnVtZXJpYyhyb3dbImxhYl9EZGltX05TIl0pID4gY29fRGRpbQogIAogIGNyaXRlcmlhM19kIDwtIGFueShmaWJyaW5vZ2VuLCBEZGltZXJzKQogIAogICMjIGFjdXRlIEdJIHN5bXB0b21zCiAgR0lzeW1wIDwtIHJvd1sic3ltcF9HSV9OUyJdID09IFRSVUUgfCByb3dbInN5bXBfR0lfYWJkb3BhaW4iXSA9PSBUUlVFIHwgcm93WyJzeW1wX0dJX3ZvbWl0aW5nIl0gPT0gVFJVRSB8IHJvd1sic3ltcF9HSV9kaWFycmgiXSA9PSBUUlVFIHwgcm93WyJzeW1wX0dJX2NvbGl0aXMiXSA9PSBUUlVFIAogIAogIGNyaXRlcmlhM19lIDwtIGFueShHSXN5bXApCiAgCiAgY3JpdGVyaWEzIDwtIHN1bShjcml0ZXJpYTNfYSwgY3JpdGVyaWEzX2IsIGNyaXRlcmlhM19jLCBjcml0ZXJpYTNfZCwgY3JpdGVyaWEzX2UsIG5hLnJtID0gVFJVRSkgPj0gMgogIAogICMgY3JpdGVyaWEgNDogRWxldmF0ZWQgbWFya2VycyBvZiBpbmZsYW1tYXRpb24gKGVnLCBFU1IsIENSUCwgb3IgcHJvY2FsY2l0b25pbikKICBuZXV0cm9waGlsaWEgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9uZXV0cm9waGlscyJdKSA+IGNvX25ldXRyb3BoaWxpYQogIGVsZXZhdGVkX0NSUCA8LSAoYXMubnVtZXJpYyhyb3dbImxhYl9DUlBfYWRtaXMiXSkgPj0gY29fQ1JQKSB8IChhcy5udW1lcmljKHJvd1sibGFiX0NSUF9OUyJdKSA+PSBjb19DUlApIHwgKGFzLm51bWVyaWMocm93WyJsYWJfQ1JQX3BlYWsiXSkgPj0gY29fQ1JQICkKICAjICBwcmludChwYXN0ZTAocGF0X2lkLCBlbGV2YXRlZF9DUlAsIHJvd1sibGFiX0NSUF9wZWFrIl0pKQogIGx5bXBob3BlbmlhIDwtIGFzLm51bWVyaWMocm93WyJsYWJfbHltcGhvY3l0ZXNfbG93ZXN0Il0pIDwgY29fbHltcGhvCiAgCiAgZmVycml0aW4gPC0gKGFzLm51bWVyaWMocm93WyJsYWJfZmVycml0aW5fTlMiXSkgPiBjb19mZXJyaXRpbiB8IGFzLm51bWVyaWMocm93WyJsYWJfZmVycml0aW5fYWRtaXMiXSkgPiBjb19mZXJyaXRpbiB8IGFzLm51bWVyaWMocm93WyJsYWJfZmVycml0aW5fcGVhayJdKSA+IGNvX2ZlcnJpdGluKQogIGFsYnVtaW4gPC0gYXMubnVtZXJpYyhyb3dbImxhYl9hbGJ1bWluX2FkbWlzIl0pIDwgY29fYWxidSB8IGFzLm51bWVyaWMocm93WyJsYWJfYWxidW1pbl9sb3dlc3QiXSkgPCBjb19hbGJ1IHwgYXMubnVtZXJpYyhyb3dbImxhYl9hbGJ1bWluX05TIl0pIDwgY29fYWxidQogIFBDVCA8LSBhcy5udW1lcmljKHJvd1sibGFiX1BDVF9hZG1pcyJdKSA+IGNvX1BDVCB8IGFzLm51bWVyaWMocm93WyJsYWJfUENUX3BlYWsiXSkgPiBjb19QQ1QgfCBhcy5udW1lcmljKHJvd1sibGFiX1BDVF9OUyJdKSA+IGNvX1BDVCAKICBMREggPC0gYXMubnVtZXJpYyhyb3dbImxhYl9MREgiXSkgPiBjb19MREgKICBJTDYgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9JTDYiXSkgPiBjb19JTDYKICBFU1IgPC0gYXMubnVtZXJpYyhyb3dbImxhYl9FU1IiXSkgPiBjb19FU1IKICAKICBjcml0ZXJpYTQgPC0gYW55KG5ldXRyb3BoaWxpYSwgZWxldmF0ZWRfQ1JQLCBseW1waG9wZW5pYSwgZmVycml0aW4sIGFsYnVtaW4sIFBDVCwgTERILCBJTDYsIEVTUikKICAKICAjIGNyaXRlcmlhIDU6IE5vIG90aGVyIG9idmlvdXMgbWljcm9iaWFsIGNhdXNlIG9mIGluZmxhbW1hdGlvbgogIGNyaXRlcmlhNSA8LSBUUlVFCiAgCiAgIyBjcml0ZXJpYSA2OiBDT1ZJRCBwb3M/CiAgUENSX3BvcyA8LSByb3dbImNvdmlkX1BDUl9wb3MiXSA9PSBUUlVFCiAgc3Rvb2xfcG9zIDwtIHJvd1siY292aWRfUENSX3N0b29sX3BvcyJdID09IFRSVUUKICBjbG9zZWNvbnRhY3QgPC0gcm93WyJjb3ZpZF9jbG9zZWNvbnRhY3QiXSA9PSBUUlVFCiAgSWdBIDwtIHJvd1siY292aWRfSWdBX3BvcyJdID09IFRSVUUKICBJZ00gPC0gcm93WyJjb3ZpZF9JZ01fcG9zIl0gPT0gVFJVRSAgICAKICBJZ0cgPC0gcm93WyJjb3ZpZF9JZ0dfcG9zIl0gPT0gVFJVRSAgICAKICBhbnlfc2VybyA8LSByb3dbImNvdmlkX3Nlcm9fcG9zIl0gPT0gVFJVRQogIAogIGNyaXRlcmlhNiA8LSBhbnkoUENSX3Bvcywgc3Rvb2xfcG9zLCBjbG9zZWNvbnRhY3QsIElnQSwgSWdNLCBJZ0csIGFueV9zZXJvKQogIAogIGlmIChOQSAlaW4lIGMoY3JpdGVyaWExLCBjcml0ZXJpYTIsIGNyaXRlcmlhMywgY3JpdGVyaWE0LCBjcml0ZXJpYTUsIGNyaXRlcmlhNikpewogICAgY3JpdGVyaWFfZnVsZmlsbGVkIDwtIE5BCiAgfSBlbHNlIGlmIChGQUxTRSAlaW4lIGMoY3JpdGVyaWExLCBjcml0ZXJpYTIsIGNyaXRlcmlhMywgY3JpdGVyaWE0LCBjcml0ZXJpYTUsIGNyaXRlcmlhNikpewogICAgY3JpdGVyaWFfZnVsZmlsbGVkIDwtIEZBTFNFCiAgfSBlbHNlIGlmIChzdW0oY3JpdGVyaWExLCBjcml0ZXJpYTIsIGNyaXRlcmlhMywgY3JpdGVyaWE0LCBjcml0ZXJpYTUsIGNyaXRlcmlhNiwgbmEucm0gPSBUUlVFKSA9PSA2KXsKICAgIGNyaXRlcmlhX2Z1bGZpbGxlZCA8LSBUUlVFCiAgfSBlbHNlIHsKICAgIGNyaXRlcmlhX2Z1bGZpbGxlZCA8LSBGQUxTRQogIH0KICAKICByZXR1cm4oYyhwYXRfaWQsICJjcml0ZXJpYTFfYWdlIiA9IGNyaXRlcmlhMSwgImNyaXRlcmlhMl9mZXZlciIgPSBjcml0ZXJpYTIsICJjcml0ZXJpYTNfY2xpbmljYWwiID0gY3JpdGVyaWEzLCAiY3JpdGVyaWE0X2luZmxhbW0iID0gY3JpdGVyaWE0LCAiY3JpdGVyaWE1X25vQWx0IiA9IGNyaXRlcmlhNSwgImNyaXRlcmlhNl9yZWNlbnRFeHBvc3VyZSIgPSBjcml0ZXJpYTYsICJjcml0ZXJpYV9mdWxmaWxsZWQiID0gY3JpdGVyaWFfZnVsZmlsbGVkKSkKfSkKCgpXSE9fZnVsZmlsbGVkIDwtIFdIT19mdWxmaWxsZWQgJT4lIHQoKSAlPiUgYXNfdGliYmxlKCkKV0hPX2Z1bGZpbGxlZCA8LSB0eXBlX2NvbnZlcnQoV0hPX2Z1bGZpbGxlZCkKV0hPX2Z1bGZpbGxlZF9oZWF0bWFwIDwtIFdIT19mdWxmaWxsZWQKY29scyA8LSBzYXBwbHkoV0hPX2Z1bGZpbGxlZF9oZWF0bWFwLCBpcy5sb2dpY2FsKQpXSE9fZnVsZmlsbGVkX2hlYXRtYXBbLGNvbHNdIDwtIGxhcHBseShXSE9fZnVsZmlsbGVkX2hlYXRtYXBbLGNvbHNdLCBhcy5udW1lcmljKQpXSE9fZnVsZmlsbGVkX2hlYXRtYXBfbWVsdCA8LSBXSE9fZnVsZmlsbGVkX2hlYXRtYXAgJT4lIG1lbHQoKQpXSE9fZnVsZmlsbGVkX2hlYXRtYXBfbWVsdFtpcy5uYShXSE9fZnVsZmlsbGVkX2hlYXRtYXBfbWVsdCldIDwtIDIKCnNraW0oV0hPX2Z1bGZpbGxlZCkKCiNnZ3Bsb3QoV0hPX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBhcy5jaGFyYWN0ZXIocGF0aWVudElEX2ludCksIGZpbGwgPSBhcy5mYWN0b3IodmFsdWUpKSkgKyBnZW9tX3RpbGUoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpICsgbGFicyh5ID0gIlBhdGllbnQgSUQiLCB4ID0gImNyaXRlcmlhIiwgZmlsbCA9ICJjcml0ZXJpYSBtZXQiLCB0aXRsZSA9ICJPdmVydmlldyBvZiB3aGljaCBzaW5nbGUgY2FzZXMgZnVsZmlsbCBXSE8gTUlTLUMgY2FzZSBkZWZpbml0aW9uIikgKyAgc2NhbGVfZmlsbF9tYW51YWwobGFiZWxzID0gYygiTm8iLCAiWWVzIiwgIk1pc3NpbmciKSwgdmFsdWVzID0gYygicGluazIiLCAicm95YWxibHVlMyIsICJkYXJrZ3JleSIpKSArIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3Q9MSkpCmBgYAoKIyMgUGVyLWNhc2Ugb3ZlcnZpZXcKYGBge3IsIGZpZy5oZWlnaHQgPSAxNiwgZmlnLndpZHRoPTd9ClBJTVNfVFNfZnVsZmlsbGVkX2hlYXRtYXBfbWVsdCRjcml0ZXJpYSA8LSAiUElNUy1UUyIKV0hPX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQkY3JpdGVyaWEgPC0gIldITyIKQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQkY3JpdGVyaWEgPC0gIkNEQyIKCmZ1bGxfaGVhdG1hcCA8LSByYmluZChQSU1TX1RTX2Z1bGZpbGxlZF9oZWF0bWFwX21lbHQsIFdIT19mdWxmaWxsZWRfaGVhdG1hcF9tZWx0LCBDRENfZnVsZmlsbGVkX2hlYXRtYXBfbWVsdCkKCmdncGxvdChmdWxsX2hlYXRtYXAsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBhcy5jaGFyYWN0ZXIocGF0aWVudElEX2ludCksIGZpbGwgPSBhcy5mYWN0b3IodmFsdWUpKSkgKyBnZW9tX3RpbGUoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCkpICsgbGFicyh5ID0gIlBhdGllbnQgSUQiLCB4ID0gImNyaXRlcmlhIiwgZmlsbCA9ICJjcml0ZXJpYSBtZXQiLCB0aXRsZSA9ICJPdmVydmlldyBvZiB3aGljaCBzaW5nbGUgY2FzZXMgZnVsZmlsbCBjYXNlIGRlZmluaXRpb25zIikgKyAgc2NhbGVfZmlsbF9tYW51YWwobGFiZWxzID0gYygiTm8iLCAiWWVzIiwgIk1pc3NpbmciKSwgdmFsdWVzID0gd2VzX3BhbGV0dGUoIlppc3NvdTEiKSkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpKSArIGZhY2V0X3dyYXAofiBjcml0ZXJpYSwgc2NhbGVzID0gImZyZWVfeCIpCgoKYGBgCgoKIyMgU3VtbWFyeQpgYGB7ciwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9N30KY3JpdGVyaWFfc3VtbWFyeSA8LSBkYXRhLmZyYW1lKFBJTVNfVFNfZnVsZmlsbGVkICU+JSBzZWxlY3QoY3JpdGVyaWFfZnVsZmlsbGVkKSwgQ0RDX2Z1bGZpbGxlZCAlPiUgc2VsZWN0KGNyaXRlcmlhX2Z1bGZpbGxlZCksIFdIT19mdWxmaWxsZWQgJT4lIHNlbGVjdChjcml0ZXJpYV9mdWxmaWxsZWQpKQpjb2xuYW1lcyhjcml0ZXJpYV9zdW1tYXJ5KSA8LSBjKCJQSU1TLVRTIiwgIkNEQyIsICJXSE8iKQoKY29scyA8LSBzYXBwbHkoY3JpdGVyaWFfc3VtbWFyeSwgaXMubG9naWNhbCkKY3JpdGVyaWFfc3VtbWFyeVssY29sc10gPC0gbGFwcGx5KGNyaXRlcmlhX3N1bW1hcnlbLGNvbHNdLCBhcy5udW1lcmljKQoKY3JpdGVyaWFfc3VtbWFyeSA8LSBjcml0ZXJpYV9zdW1tYXJ5ICU+JSBtZWx0KCkgJT4lIAogIGdyb3VwX2J5KHZhcmlhYmxlKSAlPiUgCiAgc3VtbWFyaXNlKGZ1bGZpbGxlZCA9IHN1bSh2YWx1ZSA9PSAxLCBuYS5ybSA9IFRSVUUpLCBub3RfZnVsZmlsbGVkID0gc3VtKHZhbHVlID09IDAsIG5hLnJtID0gVFJVRSksIG5vdF9hc3Nlc3NhYmxlID0gc3VtKGlzLm5hKHZhbHVlKSkpCmNyaXRlcmlhX3N1bW1hcnkkc3VtIDwtIHJvd1N1bXMoY3JpdGVyaWFfc3VtbWFyeVssLTFdKQoKY3JpdGVyaWFfc3VtbWFyeV9tZWx0IDwtIGNyaXRlcmlhX3N1bW1hcnkgJT4lIG1lbHQoKQpjb2xuYW1lcyhjcml0ZXJpYV9zdW1tYXJ5X21lbHQpIDwtIGMoImNhc2VfZGVmaW5pdGlvbiIsICJmdWxmaWxsZWQiLCAiY291bnQiKQoKZmlsbF9iYXIgPC0gZ2dwbG90KGNyaXRlcmlhX3N1bW1hcnlfbWVsdCAlPiUgZmlsdGVyKGZ1bGZpbGxlZCAhPSAnc3VtJyksIGFlcyh4ID0gY2FzZV9kZWZpbml0aW9uLCB5ID0gY291bnQsIGZpbGwgPSBmdWxmaWxsZWQpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJmaWxsIikgKyB0aGVtZV9idygpICsgCiAgbGFicyh5ID0gImZyYWN0aW9uIiwgdGl0bGUgPSAiU2luZ2xlIGNhc2VzIG1lZXRpbmcgd2hpY2ggY3JpdGVyaWEiLCBzdWJ0aXRsZSA9IHBhc3RlMCgiZnJhY3Rpb24gb2YgdG90YWwgKG4gPSAiLCBtYXgoY3JpdGVyaWFfc3VtbWFyeV9tZWx0JGNvdW50KSAsIikiKSkgKwogICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJSb3lhbDEiKVtjKDEsMiw0KV0pCgpkb2RnZV9iYXIgPC0gZ2dwbG90KGNyaXRlcmlhX3N1bW1hcnlfbWVsdCAlPiUgZmlsdGVyKGZ1bGZpbGxlZCAhPSAnc3VtJyksIGFlcyh4ID0gY2FzZV9kZWZpbml0aW9uLCB5ID0gY291bnQsIGZpbGwgPSBmdWxmaWxsZWQpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsgdGhlbWVfYncoKSArIAogIGxhYnMoeSA9ICJudW1iZXIgb2YgY2FzZXMiLCB0aXRsZSA9ICJTaW5nbGUgY2FzZXMgbWVldGluZyB3aGljaCBjcml0ZXJpYSIsIHN1YnRpdGxlID0gImFic29sdXRlIHZhbHVlcyIpICsKICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIlJveWFsMSIpW2MoMSwyLDQpXSkKCmdnYXJyYW5nZShkb2RnZV9iYXIsIGZpbGxfYmFyLCBsZWdlbmQgPSAiYm90dG9tIiwgY29tbW9uLmxlZ2VuZCA9IFRSVUUpCmBgYAoKIyBBc3NvY2lhdGlvbiBvZiBjYXNlIGRlZmluaXRpb24gd2l0aCBvdXRjb21lCmBgYHtyfQpXSE9fb3V0Y29tZSA8LSBXSE9fZnVsZmlsbGVkX2hlYXRtYXAgJT4lIHNlbGVjdChjb250YWlucygicGF0aWVudElEX2ludCIpIHwgY29udGFpbnMoImNyaXRlcmlhX2Z1bGZpbGxlZCIpKQpjb2xuYW1lcyhXSE9fb3V0Y29tZSkgPC0gYygicGF0aWVudElEX2ludCIsICJjYXNlZGVmX1dIT19mdWxmaWxsZWQiKQoKQ0RDX291dGNvbWUgPC0gQ0RDX2Z1bGZpbGxlZF9oZWF0bWFwICU+JSBzZWxlY3QoY29udGFpbnMoInBhdGllbnRJRF9pbnQiKSB8IGNvbnRhaW5zKCJjcml0ZXJpYV9mdWxmaWxsZWQiKSkKY29sbmFtZXMoQ0RDX291dGNvbWUpIDwtIGMoInBhdGllbnRJRF9pbnQiLCAiY2FzZWRlZl9DRENfZnVsZmlsbGVkIikKClBJTVNfVFNfb3V0Y29tZSA8LSBQSU1TX1RTX2Z1bGZpbGxlZF9oZWF0bWFwICU+JSBzZWxlY3QoY29udGFpbnMoInBhdGllbnRJRF9pbnQiKSB8IGNvbnRhaW5zKCJjcml0ZXJpYV9mdWxmaWxsZWQiKSkKY29sbmFtZXMoUElNU19UU19vdXRjb21lKSA8LSBjKCJwYXRpZW50SURfaW50IiwgImNhc2VkZWZfUElNU19UU19mdWxmaWxsZWQiKQoKYXNzb2Nfb3V0Y29tZSA8LSBtZXJnZShXSE9fb3V0Y29tZSwgQ0RDX291dGNvbWUsIGJ5ID0gInBhdGllbnRJRF9pbnQiKQphc3NvY19vdXRjb21lIDwtIG1lcmdlKGFzc29jX291dGNvbWUsIFBJTVNfVFNfb3V0Y29tZSkKCiNhc3NvY19vdXRjb21lIDwtIGFzc29jX291dGNvbWVbY29tcGxldGUuY2FzZXMoYXNzb2Nfb3V0Y29tZVsgLC0xXSksXQoKb3V0Y29tZV9wYXJhbXMgPC0gZGZfc2luZ2xlY2FzZXMgJT4lIHNlbGVjdChwYXRpZW50SURfaW50IHwgc3ltcF9jYXJkaW92YXNjX2NvcmRpbGF0IHwgc3ltcF9jYXJkaW92YXNjX2FuZXVyeXNtIHwgc3ltcF9jYXJkaW92YXNjX3Nob2NrIHwgb3V0Y29tZV9kZWF0aCB8IGNyaXRjYXJlX01WIHwgY3JpdGNhcmVfRUNNTykKCmFzc29jX291dGNvbWVfZnVsbCA8LSBtZXJnZShvdXRjb21lX3BhcmFtcywgYXNzb2Nfb3V0Y29tZSwgYnkgPSAicGF0aWVudElEX2ludCIsIGFsbCA9IFRSVUUpCgoKY29scyA8LSBzYXBwbHkoYXNzb2Nfb3V0Y29tZV9mdWxsLCBpcy5sb2dpY2FsKQphc3NvY19vdXRjb21lX2Z1bGxbLGNvbHNdIDwtIGxhcHBseShhc3NvY19vdXRjb21lX2Z1bGxbLGNvbHNdLCBhcy5udW1lcmljKQoKCm1ha2VVcHNldFIoYXNzb2Nfb3V0Y29tZV9mdWxsICU+JSBzZWxlY3QoLWNvbnRhaW5zKCJwYXRpZW50SUQiKSkpCmBgYAoKIyMgU2V2ZXJlIGNvdXJzZQpBIG5ldyB2YXJpYWJsZSAnc2V2ZXJlIGNvdXJzZScgbWFkZSwgd2hpY2ggY29udGFpbnMgdGhlIGZvbGxvd2luZzoKCi0gc3ltcF9jYXJkaW92YXNjX2NvcmRpbGF0IAotIHN5bXBfY2FyZGlvdmFzY19hbmV1cnlzbQotIHN5bXBfY2FyZGlvdmFzY19zaG9jayAKLSBvdXRjb21lX2RlYXRoCi0gY3JpdGNhcmVfTVYgCi0gY3JpdGNhcmVfRUNNTwotIGNyaXRjYXJlX1JSVAotIGNyaXRjYXJlX2lub3Ryb3AKLSBhZG1pc19QSUNVX2FkbWlzCgpNaWxkIHByZXNlbnRhdGlvbiBtZWFucyBhbGwgb2YgdGhlIGFib3ZlIGFyZSBlaXRoZXIgMCBvciBOQS4gCgpDYXNlcyB3aXRoIG1pc3NpbmcgdmFsdWVzIGluIGNhc2UgZGVmaW50aW9ucyBhcmUgcmVtb3ZlZC4KCmBgYHtyfQphc3NvY19vdXRjb21lIDwtIG1lcmdlKFdIT19vdXRjb21lLCBDRENfb3V0Y29tZSwgYnkgPSAicGF0aWVudElEX2ludCIpCmFzc29jX291dGNvbWUgPC0gbWVyZ2UoYXNzb2Nfb3V0Y29tZSwgUElNU19UU19vdXRjb21lKQphc3NvY19vdXRjb21lIDwtIG1lcmdlKGFzc29jX291dGNvbWUsIFBJTVNfVFNfb3V0Y29tZSkKYXNzb2Nfb3V0Y29tZSA8LSBhc3NvY19vdXRjb21lW2NvbXBsZXRlLmNhc2VzKGFzc29jX291dGNvbWVbICwtMV0pLF0KCm91dGNvbWVfcGFyYW1zIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QocGF0aWVudElEX2ludCB8IGNvbnRhaW5zKCJjcml0Y2FyZSIpICB8IGNvbnRhaW5zKCJhZG1pc19QSUNVX2FkbWlzIikgfCBjb250YWlucygib3V0Y29tZV9kZWF0aCIpICB8Y29udGFpbnMgKCJzeW1wX2NhcmRpb3Zhc2NfY29yZGlsYXQiKSB8IGNvbnRhaW5zICgic3ltcF9jYXJkaW92YXNjX2FuZXVyeXNtIikgIHxjb250YWlucygic3ltcF9jYXJkaW92YXNjX3Nob2NrIikpCgphc3NvY19vdXRjb21lX2Z1bGwgPC0gbWVyZ2Uob3V0Y29tZV9wYXJhbXMsIGFzc29jX291dGNvbWUsIGJ5ID0gInBhdGllbnRJRF9pbnQiKQoKY29scyA8LSBzYXBwbHkoYXNzb2Nfb3V0Y29tZV9mdWxsLCBpcy5sb2dpY2FsKQphc3NvY19vdXRjb21lX2Z1bGxbLGNvbHNdIDwtIGxhcHBseShhc3NvY19vdXRjb21lX2Z1bGxbLGNvbHNdLCBhcy5udW1lcmljKQoKYXNzb2Nfb3V0Y29tZV9mdWxsJHNldmVyZV9jb3Vyc2UgPC0gaWZlbHNlKGFzc29jX291dGNvbWVfZnVsbCRzeW1wX2NhcmRpb3Zhc2NfY29yZGlsYXQgPT0gMSB8IGFzc29jX291dGNvbWVfZnVsbCRzeW1wX2NhcmRpb3Zhc2NfYW5ldXJ5c20gPT0gMSB8IGFzc29jX291dGNvbWVfZnVsbCRzeW1wX2NhcmRpb3Zhc2Nfc2hvY2sgPT0gMSB8IGFzc29jX291dGNvbWVfZnVsbCRvdXRjb21lX2RlYXRoID09IDEgfCBhc3NvY19vdXRjb21lX2Z1bGwkY3JpdGNhcmVfTVYgPT0gMSB8IGFzc29jX291dGNvbWVfZnVsbCRjcml0Y2FyZV9FQ01PID09IDEgfCBhc3NvY19vdXRjb21lX2Z1bGwkY3JpdGNhcmVfUlJUID09IDEgfCBhc3NvY19vdXRjb21lX2Z1bGwkYWRtaXNfUElDVV9hZG1pcyA9PSAxIHwgYXNzb2Nfb3V0Y29tZV9mdWxsJGNyaXRjYXJlX2lub3Ryb3AgPT0gMSAsIDEsIDApCgphc3NvY19vdXRjb21lX2Z1bGwkbWlsZF9wcmVzZW50YXRpb24gPC0gaWZlbHNlKChhc3NvY19vdXRjb21lX2Z1bGwkc2V2ZXJlX2NvdXJzZSA9PSAwIHwgaXMubmEoYXNzb2Nfb3V0Y29tZV9mdWxsJHNldmVyZV9jb3Vyc2UpKSwgMSwgMCkKCm1ha2VVcHNldFIoYXNzb2Nfb3V0Y29tZV9mdWxsICU+JSBzZWxlY3QoY29udGFpbnMoImNhc2VkZWYiKSB8IGNvbnRhaW5zKCJzZXZlcmVfY291cnNlIikgKSkKCgptYWtlVXBzZXRSKGFzc29jX291dGNvbWVfZnVsbCAlPiUgc2VsZWN0KGNvbnRhaW5zKCJjYXNlZGVmIikgfCBjb250YWlucygic2V2ZXJlX2NvdXJzZSIpICB8IGNvbnRhaW5zKCJtaWxkX3ByZXMiKSApKQoKCmBgYAoKIyMgQ2hhcmFjdGVyaXN0aWNzIG9mIHNldmVyZSBjb3Vyc2UKCgo8YnV0dG9uIG9uY2xpY2s9ImxvY2F0aW9uLmhyZWY9J2h0dHBzOi8vZ2l0aHViLmNvbS9ybXZwYWVtZS9QSU1TX1RTL2Jsb2IvbWFzdGVyL2RhdGEvdW5mYXZvcmFibGVfY291cnNlX2Rlc2NyaXB0aXZlc3RhdHMuY3N2JyIgdHlwZT0iYnV0dG9uIj4KRG93bmxvYWQgZGF0YSBhcyAuY3N2IG9uIEdpdGh1YjwvYnV0dG9uPgoKYGBge3J9CiMgaW4gdGhpcyBzdGVwLCBkbyBub3QgcmVtb3ZlIE5Bcwphc3NvY19vdXRjb21lIDwtIG1lcmdlKFdIT19vdXRjb21lLCBDRENfb3V0Y29tZSwgYnkgPSAicGF0aWVudElEX2ludCIpCmFzc29jX291dGNvbWUgPC0gbWVyZ2UoYXNzb2Nfb3V0Y29tZSwgUElNU19UU19vdXRjb21lKQphc3NvY19vdXRjb21lIDwtIG1lcmdlKGFzc29jX291dGNvbWUsIFBJTVNfVFNfb3V0Y29tZSkKI2Fzc29jX291dGNvbWUgPC0gYXNzb2Nfb3V0Y29tZVtjb21wbGV0ZS5jYXNlcyhhc3NvY19vdXRjb21lWyAsLTFdKSxdCgpvdXRjb21lX3BhcmFtcyA8LSBkZl9zaW5nbGVjYXNlcyAlPiUgc2VsZWN0KHBhdGllbnRJRF9pbnQgfCBjb250YWlucygiY3JpdGNhcmUiKSAgfCBjb250YWlucygiYWRtaXNfUElDVV9hZG1pcyIpIHwgY29udGFpbnMoIm91dGNvbWVfZGVhdGgiKSAgfGNvbnRhaW5zICgic3ltcF9jYXJkaW92YXNjX2NvcmRpbGF0IikgfCBjb250YWlucyAoInN5bXBfY2FyZGlvdmFzY19hbmV1cnlzbSIpICB8Y29udGFpbnMoInN5bXBfY2FyZGlvdmFzY19zaG9jayIpKQoKYXNzb2Nfb3V0Y29tZV9mdWxsIDwtIG1lcmdlKG91dGNvbWVfcGFyYW1zLCBhc3NvY19vdXRjb21lLCBieSA9ICJwYXRpZW50SURfaW50IikKCmNvbHMgPC0gc2FwcGx5KGFzc29jX291dGNvbWVfZnVsbCwgaXMubG9naWNhbCkKYXNzb2Nfb3V0Y29tZV9mdWxsWyxjb2xzXSA8LSBsYXBwbHkoYXNzb2Nfb3V0Y29tZV9mdWxsWyxjb2xzXSwgYXMubnVtZXJpYykKCmFzc29jX291dGNvbWVfZnVsbCRzZXZlcmVfY291cnNlIDwtIGlmZWxzZShhc3NvY19vdXRjb21lX2Z1bGwkc3ltcF9jYXJkaW92YXNjX2NvcmRpbGF0ID09IDEgfCBhc3NvY19vdXRjb21lX2Z1bGwkc3ltcF9jYXJkaW92YXNjX2FuZXVyeXNtID09IDEgfCBhc3NvY19vdXRjb21lX2Z1bGwkc3ltcF9jYXJkaW92YXNjX3Nob2NrID09IDEgfCBhc3NvY19vdXRjb21lX2Z1bGwkb3V0Y29tZV9kZWF0aCA9PSAxIHwgYXNzb2Nfb3V0Y29tZV9mdWxsJGNyaXRjYXJlX01WID09IDEgfCBhc3NvY19vdXRjb21lX2Z1bGwkY3JpdGNhcmVfRUNNTyA9PSAxIHwgYXNzb2Nfb3V0Y29tZV9mdWxsJGNyaXRjYXJlX1JSVCA9PSAxIHwgYXNzb2Nfb3V0Y29tZV9mdWxsJGFkbWlzX1BJQ1VfYWRtaXMgPT0gMSB8IGFzc29jX291dGNvbWVfZnVsbCRjcml0Y2FyZV9pbm90cm9wID09IDEgLCAxLCAwKQoKCnRhYjEgPC0gYXNzb2Nfb3V0Y29tZV9mdWxsICU+JSBzZWxlY3QocGF0aWVudElEX2ludCxzZXZlcmVfY291cnNlKQp0YWIxJHNldmVyZV9jb3Vyc2UgPC0gaWZlbHNlKGlzLm5hKHRhYjEkc2V2ZXJlX2NvdXJzZSksIDAsIDEpCgp0YWIyIDwtIGRmX3NpbmdsZWNhc2VzICU+JSBzZWxlY3QocGF0aWVudElEX2ludCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXgsIGFnZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXBfcmVzcF9hbnksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1wX2NhcmRpb3Zhc2NfYW55LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltcF9jYXJkaW92YXNjX215b2NhcmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1wX2NhcmRpb3Zhc2NfcGVyaWNhcmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1wX2NhcmRpb3Zhc2NfY29yZGlsYXQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1wX2NhcmRpb3Zhc2NfYW5ldXJ5c20sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1wX2NhcmRpb3Zhc2NfTFZfMzB0bzU1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltcF9jYXJkaW92YXNjX0xWX2xlc3MzMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXBfY2FyZGlvdmFzY19zaG9jaywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXBfY2FyZGlvdmFzY19MVkVGLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltcF9jYXJkaW92YXNjX3RhY2h5Y2FyZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bXBfR0lfYW55LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltcF9uZXVyb19hbnksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXdhc2FraV9jb21wbGV0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthd2FzYWtpX2luY29tcGxldGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXdhc2FraV9mZXZlciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthd2FzYWtpX2V4YW50aGVtYSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthd2FzYWtpX2V4dHJlbWl0eSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGthd2FzYWtpX21vdXRoLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2F3YXNha2lfY2VydmljYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrYXdhc2FraV9jb25qdW5jdGl2aXRpcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdmlkX1BDUl9wb3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3ZpZF9zZXJvX2FueSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZG1pc19QSUNVX2FkbWlzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JpdGNhcmVfTklWLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JpdGNhcmVfTVYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcml0Y2FyZV9pbm90cm9wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3JpdGNhcmVfRUNNTywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyaXRjYXJlX1JSVCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ4X2NvcnRpYywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ4X2hlcGFyaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByeF9JVklnX29uY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByeF9JVklnX211bHRpcCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJ4X2FuYWtpbnJhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnhfdG9jaWxpenVtYWIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByeF9pbmZsaXhpbWFiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnhfYW50aWJpb3RpY3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByeF9wbGFzbWEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByeF9yZW1kZXNpdmlyKQoKdGFiMiRzZXggPC0gYXMuZmFjdG9yKHRhYjIkc2V4KQoKbGFidmFscyA8LQogIGRhdGEuZnJhbWUoCiAgICBjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZShkZl9zaW5nbGVjYXNlcywgIm1heCIsICJDUlAiKSAlPiUgc2VsZWN0KENSUF9tYXgpLAogICAgY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXMsICJtYXgiLCAiZmVycml0aW4iKSAlPiUgc2VsZWN0KGZlcnJpdGluX21heCksCiAgICBjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZShkZl9zaW5nbGVjYXNlcywgIm1heCIsICJJTCIpICU+JSBzZWxlY3QoSUxfbWF4KSwKICAgIGNvbGxhcHNlX2xhYnZhbHNfc2luZ2xlKGRmX3NpbmdsZWNhc2VzLCAibWF4IiwgIldCQyIpICU+JSBzZWxlY3QoV0JDX21heCksCiAgICBjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZShkZl9zaW5nbGVjYXNlcywgIm1pbiIsICJseW1waG8iKSAlPiUgc2VsZWN0KGx5bXBob19taW4pLAogICAgY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXMsICJtaW4iLCAicGxhdGVsZXQiKSAlPiUgc2VsZWN0KHBsYXRlbGV0X21pbiksCiAgICBjb2xsYXBzZV9sYWJ2YWxzX3NpbmdsZShkZl9zaW5nbGVjYXNlcywgIm1pbiIsICJzb2RpdW0iKSAlPiUgc2VsZWN0KHNvZGl1bV9taW4pLAogICAgY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXMsICJtYXgiLCAiRGRpbSIpICU+JSBzZWxlY3QoRGRpbV9tYXgpLAogICAgY29sbGFwc2VfbGFidmFsc19zaW5nbGUoZGZfc2luZ2xlY2FzZXMsICJtYXgiLCAidHJvcCIpICU+JSBzZWxlY3QodHJvcF9tYXgpCiAgKQp0YWIyIDwtIGNiaW5kKHRhYjIsIGxhYnZhbHMpCgp0YWIgPC0gbWVyZ2UodGFiMSwgdGFiMikKCnNraW0gPC0gdGFiICU+JSBncm91cF9ieShzZXZlcmVfY291cnNlKSAlPiUgc2tpbSgpCgpza2ltIDwtIHNraW0gJT4lIHNlbGVjdChza2ltX3ZhcmlhYmxlLCBzZXZlcmVfY291cnNlLCBmYWN0b3IudG9wX2NvdW50cywgbG9naWNhbC5jb3VudCwgIG51bWVyaWMucDI1LCAgbnVtZXJpYy5wNTAsICBudW1lcmljLnA3NSwgbl9taXNzaW5nKQoKc2tpbSRuX3RvdGFsIDwtIHJlcChjb3VudCh0YWIxLCBzZXZlcmVfY291cnNlKSAlPiUgcHVsbChuKSwgbnJvdyhza2ltKS8yKQpza2ltJG5fdmFsaWQgPC0gc2tpbSRuX3RvdGFsIC0gc2tpbSRuX21pc3NpbmcKCndyaXRlLmNzdihza2ltLCBwYXN0ZTAoIi4vZGF0YS91bmZhdm9yYWJsZV9jb3Vyc2VfZGVzY3JpcHRpdmVzdGF0cy5jc3YiKSkKYGBgCgoKIyBTZXNzaW9uSW5mbwpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGA=