La primera parte del presente tutorial construye gráficas para la interpretación de los resultados de la publicación del capítulo limma del curso Bioconductor for Genomic Data Science de Kasper Daniel Hansen.
En la segunda parte se presenta la (i) limpieza de datos reportados, (ii) creación de un ExpressionSet y (iii) reproducción de resultados del artículo publicado por Torres et al. 2015, en el cual aplican la tecnología del microarreglo de proteínas.
Objetivo
- Complementar el flujo de trabajo de
Bioconductor
para el análisis de microarreglos.
Nota: Todos los outputs deben verse como líneas corridas. Disminuir el zoom de ser necesario.
Dependencies
library(tidyverse)
library(ggrepel)
library(Biobase)
library(limma)
library(NMF)
DNA microarray: Leukemia
Contexto:
- This is data on different types of leukemia. The code
NoL
means not leukemia, ie. normal controls.
Problema
- Which genes are differentially expressed between the
ALL
type and normal controls?
ExpressionSet
El presente ejemplo nos brinda un ExpressionSet()
, el cual es un contenedor de datos que integra:
- Data de expresión, accesible con la función
exprs()
, y
- Data de las muestras o covariables, accesible con la función
pData()
.
leukemiasEset <- leukeset
leukemiasEset
ExpressionSet (storageMode: lockedEnvironment)
assayData: 20172 features, 60 samples
element names: exprs, se.exprs
protocolData
sampleNames: GSM330151.CEL GSM330153.CEL ... GSM331677.CEL (60 total)
varLabels: ScanDate
varMetadata: labelDescription
phenoData
sampleNames: GSM330151.CEL GSM330153.CEL ... GSM331677.CEL (60 total)
varLabels: Project Tissue ... Subtype (5 total)
varMetadata: labelDescription
featureData: none
experimentData: use 'experimentData(object)'
Annotation: genemapperhgu133plus2
Differential expression
Define the control group
- First we subset the data and clean it up.
- Then, define the control group
eset <- leukemiasEset[, leukemiasEset$LeukemiaType %in% c("ALL", "NoL")]
eset$LeukemiaType <- factor(eset$LeukemiaType)
table(eset$LeukemiaType) # debe ser: control (fct referencia) vs caso
ALL NoL
12 12
eset$LeukemiaType <- relevel(eset$LeukemiaType, ref = "NoL")
table(eset$LeukemiaType) # debe ser: control (fct referencia) vs caso
NoL ALL
12 12
Matrix + Linear model + eBayes
limma
ayuda a resolver dos principales problemas:
- presencia de varianzas artificialmente altas o bajas producto del bajo número de réplicas entre arreglos o muestras (Baldi and Long 2001); y un
- presencia de falsos positivos producto al amplio número de hipótesis puestas a prueba en forma simultánea (Kayala and Baldi 2012).
- Un test-t empírico de Bayes permite reducir (o moderar) las varianzas de todas las lecturas.
cyber-t
actualiza la varianza observada de cada gen asumiendo como la probabilidad previa (prior) que la varianza de genes vecinos con medias de expresión similar (Baldi and Long 2001).
limma
optimizó y generalizó esta estrategia a distintos diseños experimentales. Asume una varianza general como prior para la actualización de todas las varianzas observadas (Smyth and others 2004).
Nota: A diferencia de un enfoque bayesiano puro, donde se asume una probabilidad previa para la actualización de un evento (condicionado) dado un evento condicionante, en un enfoque empírico esta información es obtenida de un pool de elementos observados en el mismo experimento.
- Los métodos de corrección o ajuste de valores p permiten que el controlar la razón de falsos positivos con respecto a todos los descubrimientos o razón de falsos descubrimientos (FDR) (Brazma et al. 2001).
- El método Benjamini-Hochberg determina un valor crítico de valores p dependiente del total de hipótesis puestas a prueba y el valor de FDR deseado (Benjamini and Hochberg 1995).
Ambas propiedades son revisadas aquí.
design <- model.matrix(~ eset$LeukemiaType)
fit <- lmFit(eset, design)
eb <- eBayes(fit)
topTable(eb) %>% rownames_to_column()
Removing intercept from test coefficients
The output from topTable()
includes
logFC
: the log fold-change between cases and controls.
t
: the t-statistic used to assess differential expression.
P.Value
: the p-value for differential expression; this value is not adjusted for multiple testing.
adj.P.Val
: the p-value adjusted for multiple testing. Different adjustment methods are available, the default is Benjamini-Horchberg.
# tidy toptable
td <- topTable(eb, coef = 2, # default: slope
sort.by =NULL, resort.by =NULL,
#genelist = NULL, # no fit$gene
number = Inf, # show all the hipothesis
confint=0.95) %>% rownames_to_column() %>% as.tbl() %>%
dplyr::rename(Gene.ID=rowname)
Plots
p-value histogram
test <- topTable(eb, coef = 2,
sort.by ="P",
#sort.by ="AveExpr",
genelist = fit$genes$Gene.ID, number = Inf)
library(ggplot2)
ax <- qplot(test$P.Value, binwidth=.05)
bx <- qplot(test$adj.P.Val, binwidth=.05)
Rmisc::multiplot(ax,bx,cols = 2)
volcano plot
# (2) Volcano plot: Log Fold Change x -log10(p.value)
td %>%
mutate(significance=if_else(P.Value<1e-13,
"p.adj < 1e-13","diff rve")) %>%
ggplot(aes(logFC,-log10(P.Value))) +
geom_point(aes(colour=significance)) +
scale_color_manual(values=c("black","red")) +
ggrepel::geom_text_repel(data = filter(td,
P.Value<1e-14 | P.Value<1e-13 & logFC>0),
aes(label=Gene.ID)) +
labs(title="Leukemia DNA microarray",
subtitle="Caso vs Control")
heatmap + hierachical clustering
La inferencia estadística es comúnmente complementada con técnicas de clasificación.
La clasificación supervisada o predicción de clase, define a priori el número de categorías, el conjunto de entrenamiento y el de prueba. Ejemplos: support vector machines (SVM), k-nearest neighbors (k-NN) y validación por leave-one-out cross-validation (LOOCV).
La clasificación no-supervisada o descubrimiento de clase, agrupa objetos en base a métricas de similaridad de los objetos a lo largo de las muestras. Requiere definir 2 tipos de algoritmos:
de distancia: e.g., Euclidiana, en la que se prioriza la magnitud sobre la dispersión de las señales, y la correlación de Pearson, en la que se prioriza la dispersión sobre la magnitud.
de agrupamiento: e.g., agrupamiento jerárquico o hierarchical clustering, en la que los racimos o clusters se forman iterativamente al calcular la distancia entre elementos y racimos en formación. Más detalles, aquí. Otros son el k-mean clustering, self-organizing maps (SOM) y principal component analysis (PCA).
Las principales desventajas de la técnica están en el requerimiento de decisiones entre varios algoritmos sin consenso y su escasa reproducibilidad entre experimentos. (Allison et al. 2006)
#eset <- eset#leukemiasEset
#exprs(eset) %>% dim()
x <- td %>%
arrange(desc(t)) %>%
filter(B>0 & adj.P.Val<1e-10) %>%
select(Gene.ID) %>% as.matrix()
#x %>% dim()
#%>% dim()
aheatmap(exprs(eset)[x,],
Rowv = TRUE, Colv = TRUE,
annCol = pData(eset),
layout = "_")
Protein microarray: Malaria
Contexto:
- Pacientes con parasitemia circulante de P. falciparum y auscencia de síntomas son considerados como individuos con inmunidad clínica ante la malaria.
- Hipótesis: La respuesta de anticuerpos ante la infección en el grupo de pacientes asintomáticos reconoce un subgrupo de proteínas de P. falciparum, posiblemente asociadas al desarrollo de la inmunidad clínica.
Revisar más información sobre el experimento aquí.
Problema
- ¿Cómo limpiar la data dsponible y generar un
ExpressionSet()
desde cero?
- ¿Qué proteínas están diferencialmente reconocidas en el grupo de asintomáticos con respecto a los sintomáticos?
Tidy up data
raw<-protmicro
raw %>% View()
phenotype data
- Objetivo:
- Extraer la data fenotípica,
- Transponer su estructura,
- Asignar el nombre de muestra por columna,
- Crear un nuevo objeto capaz de ser leído por el
ExpressionSet
.
#samples <- raw[1:2,] %>% colnames()
#samples %>% as.matrix() %>% t() %>% class()
#https://stackoverflow.com/questions/34004008/transposing-in-dplyr
pheno_data <- raw[1:2,] %>%
slice(1) %>%
select(-1,-2) %>%
mutate(group=1) %>%
gather(sample_name,phenotype) %>%
filter(phenotype!="1")
pheno_data %>% arrange(sample_name)
pheno_data %>% count(phenotype)
#https://www.rdocumentation.org/packages/tibble/versions/1.3.3/topics/rownames
pheno_data_row <- pheno_data %>%
arrange(sample_name) %>%
as.data.frame() %>%
column_to_rownames(var="sample_name")
pheno_d <- new("AnnotatedDataFrame", data=pheno_data_row)
expression data
- Objetivo:
- Transformar el
data.frame
a una matriz,
- Separar la data de expresión de la data de normalización.
# limpieza inicial
exprs_data <- raw[77:nrow(raw),] %>%
rename(gene_name="X__1",
gene_ID="X__2") %>%
select(-gene_name) %>%
mutate(group=seq(n())) %>%
unite(gene_ID.n,gene_ID,group,sep = ".") %>%
mutate(gene_ID.n=stringr::str_replace(gene_ID.n,"\\s",""))
#exprs_data %>% dim() #33668
exprs_ctrl <- exprs_data %>% slice(1:31) #%>% dim() # 31 "no DNA" per sample
exprs_prot <- exprs_data %>% slice(32:n()) #%>% dim() # 33637 "no DNA" per sample
# PROTEINS
exprs_prot_m <- exprs_prot %>%
gather(sample_name, expression, -gene_ID.n) %>%
mutate(expression=as.numeric(expression)) %>%
reshape2::acast(gene_ID.n ~ sample_name,
value.var = "expression") #%>% class()
# dimensión
dim(exprs_prot_m)
[1] 855 38
# seis lecturas por proteína de las 8 primeras muestras
head(exprs_prot_m[,1:8])
PA06 PA07 PA11 PA12 PA13 PA14 PA15 PA16
MAL13P1.103.289 17058 9181 9841 20898 19586 13419 10469 29562
MAL13P1.107-s1.554 7393 4539 3886 18981 5236 9570 10345 7392
MAL13P1.107-s2.464 6822 3942 3336 32468 5201 10846 13803 9165
MAL13P1.114e3s1.339 14834 7712 9367 18653 18574 27646 26424 30289
MAL13P1.121_1o4.423 11942 4889 7618 16364 12059 9713 29187 8391
MAL13P1.124.557 8064 4424 10852 13348 4781 12231 11681 10184
# CONTROL
exprs_ctrl_m <- exprs_ctrl %>%
summarise_all(median) %>% # MEDIAN to NORMALIZE against noDNA controls
gather(sample_name, expression, -gene_ID.n) %>%
mutate(expression=as.numeric(expression)) %>%
reshape2::acast(gene_ID.n ~ sample_name,
value.var = "expression") #%>% dim() #%>% class()
# dimensión
dim(exprs_ctrl_m)
[1] 1 38
# controles noDNA de las 8 primeras muestras
exprs_ctrl_m[,1:8]
PA06 PA07 PA11 PA12 PA13 PA14 PA15 PA16
8888 5030 4080 7784 4581 7538 7850 5827
mat <- NULL # crear objeto vacío
# loop para generar una matriz de las dimensiones de `exprs_prot_m`
for(i in 1:nrow(exprs_prot_m)){
mat <- rbind(mat,exprs_ctrl_m)
}
# dimensiones de la matriz con la mediana de ctrls `noDNA` creada
dim(mat)
[1] 855 38
# matriz con la mediana de ctrls `noDNA` para las 8 primeras muestras
head(mat[,1:8]) #%>% class()
PA06 PA07 PA11 PA12 PA13 PA14 PA15 PA16
noDNA.23 8888 5030 4080 7784 4581 7538 7850 5827
noDNA.23 8888 5030 4080 7784 4581 7538 7850 5827
noDNA.23 8888 5030 4080 7784 4581 7538 7850 5827
noDNA.23 8888 5030 4080 7784 4581 7538 7850 5827
noDNA.23 8888 5030 4080 7784 4581 7538 7850 5827
noDNA.23 8888 5030 4080 7784 4581 7538 7850 5827
gene names
# generate a list (df) of gene names and gene ID's
ln <- raw[108:nrow(raw),1:2] %>%
rename(gene_name="X__1",
gene_ID="X__2") %>%
mutate(num=seq(from=32, to=31+n())) %>%
unite(gene_ID.n,gene_ID,num,sep=".") %>%
full_join(exprs_prot,by="gene_ID.n") %>%
select(1:2) %>%
rename(Gene.ID=gene_ID.n)
Create an ExpressionSet
eset <- ExpressionSet(assayData = exprs_norm,
phenoData = pheno_d)
eset
ExpressionSet (storageMode: lockedEnvironment)
assayData: 855 features, 38 samples
element names: exprs
protocolData: none
phenoData
sampleNames: PA06 PA07 ... TFS03 (38 total)
varLabels: phenotype
varMetadata: labelDescription
featureData: none
experimentData: use 'experimentData(object)'
Annotation:
Differential expression
Define the control group
- El problem defin al grupo de sintomáticos como el grupo control.
eset$phenotype <- factor(eset$phenotype)
table(eset$phenotype) # debe ser: control (fct referencia) vs caso
Asymptomatic Symptomatic
14 24
eset$phenotype <- relevel(eset$phenotype, ref = "Symptomatic")
table(eset$phenotype) # debe ser: control (fct referencia) vs caso
Symptomatic Asymptomatic
24 14
Matrix + Linear model + eBayes
design <- model.matrix(~ eset$phenotype)
fit <- lmFit(eset, design)
eb <- eBayes(fit)
topTable(eb) %>% rownames_to_column()
Removing intercept from test coefficients
# tidy toptable
td <- topTable(eb, coef = 2, # default: slope
sort.by =NULL, resort.by =NULL,
#genelist = NULL, # no fit$gene
number = Inf, # show all the hipothesis
confint=0.95) %>% rownames_to_column() %>% as.tbl() %>%
dplyr::rename(Gene.ID=rowname)
Problemas específicos
- Decisión estadística cambia:
- microarreglos de DNA -> variación w.r.t. housekeeping gene
- microarreglo de proteínas -> veces sobre control (blanco) -> intensidad final es relevante
Plots
p-value histogram
volcano plot
- OBJETIVO:
- Priorizar el Tamaño del Efecto por la significancia estadístistica.
# (2) Volcano plot: Log Fold Change x -log10(p.value)
tv <- td %>%
inner_join(biobroom::tidy.ExpressionSet(eset,addPheno = TRUE) %>% #count(gene)
group_by(gene,phenotype) %>% summarise(mean_group=mean(value)) %>%
ungroup() %>%
spread(phenotype,mean_group) %>%
#arrange(desc(Asymptomatic)) %>%
rename(Gene.ID=gene),
by="Gene.ID")
tv %>%
mutate(significance=if_else(adj.P.Val<0.05,
"adj.P.Val<0.05","diff rve")) %>%
ggplot(aes(logFC,-log10(P.Value))) +
#geom_point(aes(colour=significance)) + scale_color_manual(values=c("red","black")) +
geom_point(aes(colour=Asymptomatic)) + viridis::scale_color_viridis() +
ggrepel::geom_text_repel(data = tv %>%
filter(adj.P.Val<0.05 & logFC>1.5 & Asymptomatic>1)# %>%
#arrange(desc(Asymptomatic)) %>%
#top_n(10,Asymptomatic)
,
aes(label=Gene.ID)) +
labs(title="Malaria Protein microarray",
subtitle="Caso vs Control")+
geom_hline(aes(yintercept=-log10(0.01)), lty=3)+
geom_vline(aes(xintercept=1), lty=3)
diff reactive
boxplot
list
tv %>%
filter(adj.P.Val<0.05 & logFC>1 & Asymptomatic>1) %>%
arrange(desc(Asymptomatic)) %>%
select(Gene.ID) %>%
inner_join(ln, by="Gene.ID") %>%
inner_join(biobroom::tidy.ExpressionSet(eset,addPheno = TRUE) %>%
group_by(gene,phenotype) %>% summarise(mean_group=mean(value)) %>%
ungroup() %>%
spread(phenotype,mean_group) %>%
rename(Gene.ID=gene),
by="Gene.ID") %>%
inner_join(td %>%
arrange(desc(t)) %>%
mutate(t.order=seq(n())) %>%
select(Gene.ID,AveExpr,P.Value,adj.P.Val,t.order),
by="Gene.ID") #%>% slice(1:10)
top reactive
- El grupo de antígenos con mayor reactividad permitirá darle una contexto biológico a los valores con significancia estadística.
boxplots
- show the intensity distributions of selected features in both groups.
both
heatmap
eset <- ExpressionSet(assayData = exprs_norm,
phenoData = pheno_d)
s <- tv %>%
filter(adj.P.Val<0.05 & logFC>1 & Asymptomatic>1) %>%
arrange(desc(Asymptomatic)) %>%
select(Gene.ID) %>% as.matrix()
x <- tv %>%
#arrange(desc(t)) %>%
arrange(desc(AveExpr)) %>%
#filter(B>0 #& adj.P.Val<1e-4
# ) %>%
top_n(10,AveExpr) %>%
arrange(desc(Asymptomatic)) %>% # If diff order at boxplot is achieved, the deactivate this line.
select(Gene.ID) %>% as.matrix()
pData(eset) <- biobroom::tidy.ExpressionSet(eset,addPheno = TRUE) %>%
group_by(sample) %>% summarise(sample_median=median(value)) %>%
full_join(pData(eset) %>%
rownames_to_column() %>%
rename(sample=rowname),
by="sample") %>%
arrange(phenotype,sample_median) %>%
as.data.frame() %>%
column_to_rownames(var="sample")
y <- pData(eset) %>% rownames_to_column() %>%
select(rowname) %>% as.matrix() %>% as.character()
eset <- eset[c(x,s),y]
aheatmap(exprs(eset),
Rowv = NA, Colv = NA,
annCol = pData(eset),
layout = "_")
boxplot
#repro
biobroom::tidy.ExpressionSet(eset,addPheno = TRUE) %>% #count(gene)
full_join(biobroom::tidy.ExpressionSet(eset,addPheno = TRUE) %>% #count(gene)
group_by(gene,phenotype) %>% summarise(mean_group=mean(value)) %>%
ungroup() %>%
spread(phenotype,mean_group) %>%
arrange(desc(Asymptomatic)) %>%
select(-Symptomatic),
by="gene") %>%
full_join(x %>% as.data.frame() %>%
mutate(group="Top 10") %>%
rename(gene="Gene.ID") %>%
mutate(gene=as.character(gene)),
by="gene") %>%
full_join(s %>% as.data.frame() %>%
mutate(group="Differentially*") %>%
rename(gene="Gene.ID") %>%
mutate(gene=as.character(gene)),
by="gene") %>%
unite(group, group.x, group.y) %>%
mutate(group=stringr::str_replace(group,"NA_(.)", "\\1")) %>%
mutate(group=stringr::str_replace(group,"(.)_NA", "\\1")) %>%
mutate(group=forcats::fct_relevel(group,"Top 10")) %>%
ggplot(aes(reorder(gene,Asymptomatic),value,fill=phenotype))+
geom_boxplot()+
#geom_point() +
facet_grid(group~.,scales = "free", space = "free") +#
ylab("log2-transformed normalized MFI")+
xlab("antigens")+
labs(title="Highly and differentially reactive antigens",
subtitle="All sorted w.r.t. Asymptomatic mean Ab reactivity",
caption="*filtered by adj.P.Val<0.05 and logFC>1")+
coord_flip() # ORDENAR eje de proteínas!!!!
diff reactive (paper)
- Los autores reportan todos los antígenos con valor p ajustado menor a 0.05
- Dada la variabilidad entre las muestras por grupo, un algoritmo de clasificación no es la estrategia más adecuada.
heatmap
aheatmap(exprs(eset)[x,],
Rowv = NA, Colv = NA,
annCol = pData(eset),
layout = "_")
boxplots
- Una mejor estrategia de visualización son los diagramas de cajas, los cuales grafican la distribución total de las observaciones.
#repro
biobroom::tidy.ExpressionSet(eset,addPheno = TRUE) %>% #str()
mutate(order=seq(from=n(),to=1)) %>%
ggplot(aes(reorder(gene,order,order=TRUE),value,fill=phenotype))+
geom_boxplot()+
#geom_point() +
ylab("log2-transformed normalized MFI")+
xlab("antigens")+
labs(title="Differentially reactive antigens",
subtitle="filtered by adj.P.Value<0.05 and sorted w.r.t. Asymptomatic median Ab reactivity")+
coord_flip() # ORDENAR eje de proteínas!!!!
list
x %>% as.data.frame() %>%
mutate(Gene.ID=as.character(Gene.ID)) %>%
inner_join(ln, by="Gene.ID") %>%
inner_join(biobroom::tidy.ExpressionSet(eset,addPheno = TRUE) %>%
group_by(gene,phenotype) %>% summarise(mean_group=mean(value)) %>%
ungroup() %>%
spread(phenotype,mean_group) %>%
rename(Gene.ID=gene),
by="Gene.ID") %>%
inner_join(td %>%
arrange(desc(t)) %>%
mutate(t.order=seq(n())) %>%
select(Gene.ID,P.Value,adj.P.Val,t.order),
by="Gene.ID") #%>% slice(1:8)
B-stat >0
- Here, all features are filtered by positive log-odds that the gene is differentially expressed (B=0 ~ 50% probability a gene is differentially expressed).
- B-statistic is adjusted for multiple testing by assuming that 1% of the genes (modifiable parameter) are expected to be differentially expressed.
- Depends on normality (same as p-values), and independence between genes (same as BH control of FDR), but require in addition a prior guess for the proportion of differentially expressed probes.
- p-values may be preferred to the B-statistics because they do not require this prior knowledge.
sorted by significance
boxplots
- show the intensity distributions of selected features in both groups.
list
sorted by average
boxplots
- show the intensity distributions of selected features in both groups.
list
Conclusión: aplica el tidyverse
antes y después de Bioconductor
Al igual que en los casos presentados en los tutoriales anteriores, el dialecto del tidyverse
facilitó tanto el ingreso de data para la ejecución de modelos en Bioconductor
, como para “limpiar” sus resultados y generar en forma intuitiva visualizaciones que ayuden a su interpretación.
El análisis presentado sigue el flujo de trabajo propuesto por David Robinson:
Computer environment
devtools::session_info()
Session info ----------------------------------------------------------------------------
setting value
version R version 3.4.3 (2017-11-30)
system x86_64, linux-gnu
ui X11
language en_US
collate en_US.UTF-8
tz America/Lima
date 2018-01-07
Packages --------------------------------------------------------------------------------
package * version date source
assertthat 0.2.0 2017-04-11 CRAN (R 3.4.0)
backports 1.1.0 2017-05-22 CRAN (R 3.4.1)
base * 3.4.3 2017-12-01 local
base64enc 0.1-3 2015-07-28 CRAN (R 3.4.0)
bindr 0.1 2016-11-13 cran (@0.1)
bindrcpp * 0.2 2017-06-17 CRAN (R 3.4.1)
Biobase * 2.32.0 2017-08-02 Bioconductor
biobroom 1.4.2 2017-08-02 Bioconductor
BiocGenerics * 0.18.0 2016-06-23 Bioconductor
broom 0.4.2 2017-02-13 CRAN (R 3.4.0)
cellranger 1.1.0 2016-07-27 CRAN (R 3.4.0)
class 7.3-14 2015-08-30 CRAN (R 3.4.0)
cluster * 2.0.6 2017-03-16 CRAN (R 3.4.0)
codetools 0.2-15 2016-10-05 CRAN (R 3.3.1)
colorspace 1.3-2 2016-12-14 CRAN (R 3.4.0)
compiler 3.4.3 2017-12-01 local
datasets * 3.4.3 2017-12-01 local
dendextend 1.5.2 2017-03-28 CRAN (R 3.4.0)
DEoptimR 1.0-8 2016-11-19 CRAN (R 3.4.0)
devtools 1.13.2 2017-06-02 CRAN (R 3.4.1)
digest 0.6.12 2017-01-27 CRAN (R 3.4.0)
diptest 0.75-7 2016-12-05 CRAN (R 3.4.0)
doParallel 1.0.10 2015-10-14 CRAN (R 3.4.0)
dplyr * 0.7.2 2017-07-20 CRAN (R 3.4.1)
evaluate 0.10.1 2017-06-24 CRAN (R 3.4.1)
flexmix 2.3-14 2017-04-28 CRAN (R 3.4.0)
forcats 0.2.0 2017-01-23 CRAN (R 3.4.0)
foreach 1.4.3 2015-10-13 CRAN (R 3.4.0)
foreign 0.8-69 2017-06-21 CRAN (R 3.4.1)
fpc 2.1-10 2015-08-14 CRAN (R 3.4.0)
ggplot2 * 2.2.1.9000 2017-10-24 Github (tidyverse/ggplot2@ffb40f3)
ggrepel * 0.6.9 2017-05-05 Github (slowkow/ggrepel@d21b468)
glue 1.1.1 2017-06-21 CRAN (R 3.4.1)
graphics * 3.4.3 2017-12-01 local
grDevices * 3.4.3 2017-12-01 local
grid 3.4.3 2017-12-01 local
gridBase 0.4-7 2014-02-24 CRAN (R 3.4.0)
gridExtra 2.2.1 2016-02-29 CRAN (R 3.4.0)
gtable 0.2.0 2016-02-26 CRAN (R 3.4.0)
haven 1.1.0 2017-07-09 CRAN (R 3.4.1)
hms 0.3 2016-11-22 CRAN (R 3.4.0)
htmltools 0.3.6 2017-04-28 CRAN (R 3.4.0)
httr 1.2.1 2016-07-03 CRAN (R 3.4.0)
iterators 1.0.8 2015-10-13 CRAN (R 3.4.0)
jsonlite 1.5 2017-06-01 cran (@1.5)
kernlab 0.9-25 2016-10-03 CRAN (R 3.4.0)
knitr 1.16 2017-05-18 cran (@1.16)
labeling 0.3 2014-08-23 CRAN (R 3.4.0)
lattice 0.20-35 2017-03-25 CRAN (R 3.3.3)
lazyeval 0.2.0 2016-06-12 CRAN (R 3.4.0)
limma * 3.28.21 2017-08-02 Bioconductor
lubridate 1.6.0 2016-09-13 CRAN (R 3.4.0)
magrittr 1.5 2014-11-22 CRAN (R 3.4.0)
MASS 7.3-47 2017-04-21 CRAN (R 3.4.0)
mclust 5.3 2017-05-21 CRAN (R 3.4.1)
memoise 1.1.0 2017-04-21 CRAN (R 3.4.0)
methods * 3.4.3 2017-12-01 local
mnormt 1.5-5 2016-10-15 CRAN (R 3.4.0)
modelr 0.1.1 2017-07-24 CRAN (R 3.4.1)
modeltools 0.2-21 2013-09-02 CRAN (R 3.4.0)
munsell 0.4.3 2016-02-13 CRAN (R 3.4.0)
mvtnorm 1.0-6 2017-03-02 CRAN (R 3.4.0)
nlme 3.1-131 2017-02-06 CRAN (R 3.4.0)
NMF * 0.23.4 2017-05-05 Github (renozao/NMF@ff913c0)
nnet 7.3-12 2016-02-02 CRAN (R 3.4.0)
parallel * 3.4.3 2017-12-01 local
pkgconfig 2.0.1 2017-03-21 cran (@2.0.1)
pkgmaker * 0.26.7 2017-05-05 Github (renozao/pkgmaker@845deb6)
plyr 1.8.4 2016-06-08 CRAN (R 3.4.0)
prabclus 2.2-6 2015-01-14 CRAN (R 3.4.0)
psych 1.7.5 2017-05-03 CRAN (R 3.4.0)
purrr * 0.2.3 2017-08-02 cran (@0.2.3)
R6 2.2.2 2017-06-17 CRAN (R 3.4.1)
RColorBrewer * 1.1-2 2014-12-07 CRAN (R 3.4.0)
Rcpp 0.12.13 2017-09-28 cran (@0.12.13)
readr * 1.1.1 2017-05-16 CRAN (R 3.4.1)
readxl 1.0.0 2017-04-18 CRAN (R 3.4.0)
registry * 0.3 2015-07-08 CRAN (R 3.4.0)
reshape2 1.4.2 2016-10-22 CRAN (R 3.4.0)
rlang 0.1.2 2017-08-09 cran (@0.1.2)
rmarkdown 1.6 2017-06-15 CRAN (R 3.4.1)
Rmisc 1.5 2013-10-22 CRAN (R 3.4.0)
rngtools * 1.2.4 2014-03-06 CRAN (R 3.4.0)
robustbase 0.92-7 2016-12-09 CRAN (R 3.4.0)
rprojroot 1.2 2017-01-16 CRAN (R 3.4.0)
rvest 0.3.2 2016-06-17 CRAN (R 3.4.0)
scales 0.5.0.9000 2017-10-06 Github (hadley/scales@d767915)
stats * 3.4.3 2017-12-01 local
stats4 3.4.3 2017-12-01 local
stringi 1.1.5 2017-04-07 CRAN (R 3.4.0)
stringr 1.2.0 2017-02-18 CRAN (R 3.4.0)
tibble * 1.3.4 2017-08-22 cran (@1.3.4)
tidyr * 0.6.3 2017-05-15 CRAN (R 3.4.1)
tidyverse * 1.1.1 2017-01-27 CRAN (R 3.4.0)
tools 3.4.3 2017-12-01 local
trimcluster 0.1-2 2012-10-29 CRAN (R 3.4.0)
utils * 3.4.3 2017-12-01 local
viridis 0.4.0 2017-03-27 CRAN (R 3.4.0)
viridisLite 0.2.0 2017-03-24 CRAN (R 3.4.0)
whisker 0.3-2 2013-04-28 CRAN (R 3.4.0)
withr 2.0.0 2017-10-24 Github (jimhester/withr@a43df66)
xml2 1.1.1 2017-01-24 CRAN (R 3.4.0)
xtable 1.8-2 2016-02-05 CRAN (R 3.4.0)
yaml 2.1.14 2016-11-12 CRAN (R 3.4.0)
References
Allison, David B, Xiangqin Cui, Grier P Page, and Mahyar Sabripour. 2006. “Microarray Data Analysis: From Disarray to Consolidation and Consensus.” Nature Reviews Genetics 7 (1). Nature Publishing Group: 55–65. doi:10.1038/nrg1749.
Baldi, Pierre, and Anthony D Long. 2001. “A Bayesian Framework for the Analysis of Microarray Expression Data: Regularized T-Test and Statistical Inferences of Gene Changes.” Bioinformatics 17 (6). Oxford Univ Press: 509–19. doi:10.1093/bioinformatics/17.6.509.
Benjamini, Yoav, and Yosef Hochberg. 1995. “Controlling the False Discovery Rate: A Practical and Powerful Approach to Multiple Testing.” Journal of the Royal Statistical Society. Series B (Methodological). JSTOR, 289–300. doi:10.2307/2346101.
Brazma, Alvis, Pascal Hingamp, John Quackenbush, Gavin Sherlock, Paul Spellman, Chris Stoeckert, John Aach, et al. 2001. “Minimum Information About a Microarray Experiment (MIAME)—toward Standards for Microarray Data.” Nature Genetics 29 (4). Nature Publishing Group: 365–71. doi:10.1038/ng1201-365.
Huber, Wolfgang, Anja Von Heydebreck, Holger Sültmann, Annemarie Poustka, and Martin Vingron. 2002. “Variance Stabilization Applied to Microarray Data Calibration and to the Quantification of Differential Expression.” Bioinformatics 18 (suppl 1). Oxford Univ Press: S96–S104. doi:10.1093/bioinformatics/18.suppl_1.S96.
Kayala, Matthew A, and Pierre Baldi. 2012. “Cyber-T Web Server: Differential Analysis of High-Throughput Data.” Nucleic Acids Research 40 (W1). Oxford Univ Press: W553–W559. doi:10.1093/nar/gks420.
King, C. L., D. H. Davies, P. Felgner, E. Baum, A. Jain, A. Randall, K. Tetteh, C. J. Drakeley, and B. Greenhouse. 2015. “Biosignatures of Exposure/Transmission and Immunity.” American Journal of Tropical Medicine and Hygiene 93 (3 Suppl). American Society of Tropical Medicine; Hygiene: 16–27. doi:10.4269/ajtmh.15-0037.
Kreil, David P, and Roslin R Russell. 2005. “Tutorial Section: There Is No Silver Bullet—a Guide to Low-Level Data Transforms and Normalisation Methods for Microarray Data.” Briefings in Bioinformatics 6 (1). Oxford Univ Press: 86–97. doi:10.1093/bib/6.1.86.
Smyth, Gordon K, and others. 2004. “Linear Models and Empirical Bayes Methods for Assessing Differential Expression in Microarray Experiments.” Statistical Applications in Genetics and Molecular Biology 3 (1): 3. doi:10.2202/1544-6115.1027.
LS0tCnRpdGxlOiAiTWljcm9hcnJlZ2xvczogQ29tcGxlbWVudG9zIGFsIEZsdWpvIGRlIHRyYWJham8gZGUgYEJpb2NvbmR1Y3RvcmAiCmF1dGhvcjogImF2YWxsZWNhbUBnbWFpbC5jb20iCmRhdGU6ICIyMDE3LTA4LTA0IgpvdXRwdXQ6CiAgI2h0bWxfZG9jdW1lbnQ6CiAgI3BkZl9kb2N1bWVudDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwogICAgI3RoZW1lOiB1bml0ZWQKICAgICNjb2RlX2ZvbGRpbmc6ICJoaWRlIgogICAgI2ZpZ19jYXB0aW9uOiBUUlVFCiAgICAjbnVtYmVyX3NlY3Rpb25zOiBUUlVFCmJpYmxpb2dyYXBoeTogbWFsYXJpYS5iaWIKbGluay1jaXRhdGlvbnM6IHllcwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCm9wdGlvbnMod2lkdGggPSA5MCkgIyBleHBhbmQgbGltaXRzIG9mIENPTlNPTEUgb3V0cHV0CmBgYAoKTGEgcHJpbWVyYSBwYXJ0ZSBkZWwgcHJlc2VudGUgdHV0b3JpYWwgY29uc3RydXllIGdyw6FmaWNhcyBwYXJhIGxhIGludGVycHJldGFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcyBkZSBsYSBwdWJsaWNhY2nDs24gZGVsIApjYXDDrXR1bG8gW2xpbW1hXShodHRwczovL2thc3BlcmRhbmllbGhhbnNlbi5naXRodWIuaW8vZ2VuYmlvY29uZHVjdG9yL2h0bWwvbGltbWEuaHRtbCkgCmRlbCBjdXJzbwpbQmlvY29uZHVjdG9yIGZvciBHZW5vbWljIERhdGEgU2NpZW5jZV0oaHR0cHM6Ly9rYXNwZXJkYW5pZWxoYW5zZW4uZ2l0aHViLmlvL2dlbmJpb2NvbmR1Y3Rvci8pIApkZSBbS2FzcGVyIERhbmllbCBIYW5zZW5dKGh0dHA6Ly93d3cuaGFuc2VubGFiLm9yZy8pLgoKRW4gbGEgc2VndW5kYSBwYXJ0ZSBzZSBwcmVzZW50YSBsYSAoaSkgbGltcGllemEgZGUgZGF0b3MgcmVwb3J0YWRvcywgKGlpKSBjcmVhY2nDs24gZGUgdW4gRXhwcmVzc2lvblNldCB5IChpaWkpIHJlcHJvZHVjY2nDs24gZGUgcmVzdWx0YWRvcyBkZWwgCmFydMOtY3VsbyBwdWJsaWNhZG8gcG9yIFtUb3JyZXMgZXQgYWwuIDIwMTVdKGh0dHBzOi8vYWNhZGVtaWMub3VwLmNvbS9qaWQvYXJ0aWNsZS1sb29rdXAvZG9pLzEwLjEwOTMvaW5mZGlzL2ppdTYxNCksIGVuIGVsIGN1YWwgYXBsaWNhbiBsYSB0ZWNub2xvZ8OtYSBkZWwgbWljcm9hcnJlZ2xvIGRlIHByb3Rlw61uYXMuCgojIyBPYmpldGl2bwoKLSBDb21wbGVtZW50YXIgZWwgZmx1am8gZGUgdHJhYmFqbyBkZSBgQmlvY29uZHVjdG9yYCBwYXJhIGVsIGFuw6FsaXNpcyBkZSBtaWNyb2FycmVnbG9zLgoKX19Ob3RhOl9fIFRvZG9zIGxvcyBvdXRwdXRzIGRlYmVuIHZlcnNlIGNvbW8gbMOtbmVhcyBjb3JyaWRhcy4gX0Rpc21pbnVpciBlbCB6b29tIGRlIHNlciBuZWNlc2FyaW8uXwoKIyMgRGVwZW5kZW5jaWVzCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KEJpb2Jhc2UpCmxpYnJhcnkobGltbWEpCmxpYnJhcnkoTk1GKQpgYGAKCiMjIERhdGEgaW5wdXQKCkxhIGRhdGEgaGEgc2lkbyBhZHF1aXJpZGEgcG9yIGRvcyB2aWFzIGRpc3RpbnRhczoKCi0gRGF0YSBkaXNwb25pYmxlIGRlbCBwYXF1ZXRlIGBsZXVrZW1pYUVzZXRgIGUKLSBJbXBvcnRhY2nDs24gZGVsIGFyY2hpdm8gX19leGNlbF9fIGRpc3BvbmlibGUgZW4gZWwgbWF0ZXJpYWwgc3VwbGVtZW50YXJpbyBkZWwgYXJ0w61jdWxvIHJlZmVyaWRvLgoKYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89VFJVRX0KbGlicmFyeShsZXVrZW1pYXNFc2V0KQpkYXRhKGxldWtlbWlhc0VzZXQpCmxldWtlc2V0IDwtIGxldWtlbWlhc0VzZXQKCiNodHRwczovL2FjYWRlbWljLm91cC5jb20vamlkL2FydGljbGUtbG9va3VwL2RvaS8xMC4xMDkzL2luZmRpcy9qaXU2MTQjc3VwcGxlbWVudGFyeS1kYXRhCnByb3RtaWNybyA8LSByZWFkeGw6OnJlYWRfZXhjZWwoImRhdGEtcmF3L2ppdTYxNF9TdXBwbGVtZW50YXJ5X0RhdGEvaml1NjE0c3VwcF90YWJsZTEueGxzeCIpCmBgYAoKQW1iYXMgYmFzZXMgaGFuIHNpZG8gZ3JhYmFkYXMgZW4gdW4gZm9ybWF0byBgLnJkc2AgY29uIGxhIGZ1bmNpw7NuIGBzYXZlUkRTKClgIHBhcmEgZmFjaWxpdGFyIHN1IGRpc3RyaWJ1Y2nDs24geSBhY2Nlc28uCmBgYHtyLGV2YWw9RkFMU0UsIGVjaG89VFJVRX0Kc2F2ZVJEUyhsZXVrZXNldCwgImRhdGEtcmF3L2xldWtlc2V0LnJkcyIpCnNhdmVSRFMocHJvdG1pY3JvLCAiZGF0YS1yYXcvcHJvdG1pY3JvLnJkcyIpCmBgYAoKUG9yIGVsbG8sIGxhIGltcG9ydGFjacOzbiBkZSBhbWJhcyBiYXNlcyBzZXLDoSBlamVjdXRhZGEgcG9yIGxhIGZ1bmNpw7NuIGByZWFkUkRTKClgLgpgYGB7cn0KbGV1a2VzZXQgPC0gcmVhZFJEUygiZGF0YS1yYXcvbGV1a2VzZXQucmRzIikKcHJvdG1pY3JvIDwtIHJlYWRSRFMoImRhdGEtcmF3L3Byb3RtaWNyby5yZHMiKQpgYGAKCiMjIEROQSBtaWNyb2FycmF5OiBMZXVrZW1pYQoKX19Db250ZXh0bzpfXwoKLSBUaGlzIGlzIGRhdGEgb24gZGlmZmVyZW50IHR5cGVzIG9mIGxldWtlbWlhLiAgVGhlIGNvZGUgYE5vTGAgbWVhbnMgbm90IGxldWtlbWlhLCBpZS4gbm9ybWFsIGNvbnRyb2xzLgoKIyMjIFByb2JsZW1hCgotIFdoaWNoIGdlbmVzIGFyZSBkaWZmZXJlbnRpYWxseSBleHByZXNzZWQgYmV0d2VlbiB0aGUgYEFMTGAgdHlwZSBhbmQgbm9ybWFsIGNvbnRyb2xzPwoKIyMjIEV4cHJlc3Npb25TZXQKCkVsIHByZXNlbnRlIGVqZW1wbG8gbm9zIGJyaW5kYSB1biBgRXhwcmVzc2lvblNldCgpYCwgZWwgY3VhbCBlcyB1biBjb250ZW5lZG9yIGRlIGRhdG9zIHF1ZSBpbnRlZ3JhOgoKLSBEYXRhIGRlIF9fZXhwcmVzacOzbl9fLCBhY2Nlc2libGUgY29uIGxhIGZ1bmNpw7NuIGBleHBycygpYCwgeQotIERhdGEgZGUgbGFzIF9fbXVlc3RyYXNfXyBvIGNvdmFyaWFibGVzLCBhY2Nlc2libGUgY29uIGxhIGZ1bmNpw7NuIGBwRGF0YSgpYC4KCmBgYHtyfQpsZXVrZW1pYXNFc2V0IDwtIGxldWtlc2V0CmxldWtlbWlhc0VzZXQKYGBgCgojIyMgRGlmZmVyZW50aWFsIGV4cHJlc3Npb24KCiMjIyMgRGVmaW5lIHRoZSBjb250cm9sIGdyb3VwCgotIEZpcnN0IHdlIHN1YnNldCB0aGUgZGF0YSBhbmQgY2xlYW4gaXQgdXAuCi0gVGhlbiwgZGVmaW5lIHRoZSBjb250cm9sIGdyb3VwCgpgYGB7cn0KZXNldCA8LSBsZXVrZW1pYXNFc2V0WywgbGV1a2VtaWFzRXNldCRMZXVrZW1pYVR5cGUgJWluJSBjKCJBTEwiLCAiTm9MIildCmVzZXQkTGV1a2VtaWFUeXBlIDwtIGZhY3Rvcihlc2V0JExldWtlbWlhVHlwZSkKCnRhYmxlKGVzZXQkTGV1a2VtaWFUeXBlKSAjIGRlYmUgc2VyOiBjb250cm9sIChmY3QgcmVmZXJlbmNpYSkgdnMgY2Fzbwplc2V0JExldWtlbWlhVHlwZSA8LSByZWxldmVsKGVzZXQkTGV1a2VtaWFUeXBlLCByZWYgPSAiTm9MIikKdGFibGUoZXNldCRMZXVrZW1pYVR5cGUpICMgZGViZSBzZXI6IGNvbnRyb2wgKGZjdCByZWZlcmVuY2lhKSB2cyBjYXNvCmBgYAoKIyMjIyBNYXRyaXggKyBMaW5lYXIgbW9kZWwgKyBlQmF5ZXMKCmBsaW1tYWAgYXl1ZGEgYSByZXNvbHZlciBkb3MgcHJpbmNpcGFsZXMgcHJvYmxlbWFzOgoKLSBwcmVzZW5jaWEgZGUgdmFyaWFuemFzIGFydGlmaWNpYWxtZW50ZSBhbHRhcyBvIGJhamFzIHByb2R1Y3RvIGRlbCAKYmFqbyBuw7ptZXJvIGRlIHLDqXBsaWNhcyBlbnRyZSBhcnJlZ2xvcyBvIG11ZXN0cmFzIFtAYmFsZGkyMDAxY3liZXJ0XTsgeSB1bgotIHByZXNlbmNpYSBkZSBmYWxzb3MgcG9zaXRpdm9zIHByb2R1Y3RvIGFsIGFtcGxpbyBuw7ptZXJvIGRlIGhpcMOzdGVzaXMgCnB1ZXN0YXMgYSBwcnVlYmEgZW4gZm9ybWEgc2ltdWx0w6FuZWEgW0BrYXlhbGEyMDEyY3liZXJdLgoKMS4gVW4gX190ZXN0LXQgZW1ww61yaWNvIGRlIEJheWVzX18gcGVybWl0ZSByZWR1Y2lyIChvIG1vZGVyYXIpIGxhcyB2YXJpYW56YXMgZGUgCnRvZGFzIGxhcyBsZWN0dXJhcy4KICAgIC0gYGN5YmVyLXRgIGFjdHVhbGl6YSBsYSB2YXJpYW56YSBvYnNlcnZhZGEgZGUgY2FkYSBnZW4gYXN1bWllbmRvIGNvbW8gbGEgcHJvYmFiaWxpZGFkIHByZXZpYSAoX3ByaW9yXykgCiAgICBxdWUgbGEgdmFyaWFuemEgZGUgZ2VuZXMgdmVjaW5vcyBjb24gbWVkaWFzIGRlIGV4cHJlc2nDs24gc2ltaWxhciBbQGJhbGRpMjAwMWN5YmVydF0uCiAgICAtIGBsaW1tYWAgb3B0aW1pesOzIHkgZ2VuZXJhbGl6w7MgZXN0YSBlc3RyYXRlZ2lhIGEgZGlzdGludG9zIGRpc2XDsW9zIGV4cGVyaW1lbnRhbGVzLiAKICAgIEFzdW1lIHVuYSB2YXJpYW56YSBnZW5lcmFsIGNvbW8gX3ByaW9yXyBwYXJhIGxhIGFjdHVhbGl6YWNpw7NuIGRlIHRvZGFzIGxhcyB2YXJpYW56YXMgCiAgICBvYnNlcnZhZGFzIFtAc215dGgyMDA0ZWJheWVzXS4KICAgIAogICAgX19Ob3RhOl9fIEEgZGlmZXJlbmNpYSBkZSB1biBlbmZvcXVlIGJheWVzaWFubyBwdXJvLCBkb25kZSBzZSBhc3VtZSB1bmEgCiAgICBwcm9iYWJpbGlkYWQgcHJldmlhIHBhcmEgbGEgYWN0dWFsaXphY2nDs24gZGUgdW4gZXZlbnRvIChjb25kaWNpb25hZG8pIGRhZG8gdW4gZXZlbnRvIGNvbmRpY2lvbmFudGUsCiAgICBlbiB1biBlbmZvcXVlIGVtcMOtcmljbyBlc3RhIGluZm9ybWFjacOzbiBlcyBvYnRlbmlkYSBkZSB1biBfcG9vbF8gZGUKICAgIGVsZW1lbnRvcyBvYnNlcnZhZG9zIGVuIGVsIG1pc21vIGV4cGVyaW1lbnRvLgogICAgCjIuIExvcyBtw6l0b2RvcyBkZSBfX2NvcnJlY2Npw7NuIG8gYWp1c3RlIGRlIHZhbG9yZXMgcF9fIHBlcm1pdGVuIHF1ZSBlbCAKY29udHJvbGFyIGxhIHJhesOzbiBkZSBmYWxzb3MgcG9zaXRpdm9zIGNvbiAKcmVzcGVjdG8gYSB0b2RvcyBsb3MgZGVzY3VicmltaWVudG9zIG8gcmF6w7NuIGRlIGZhbHNvcyBkZXNjdWJyaW1pZW50b3MgCihGRFIpIFtAYnJhem1hMjAwMV0uCiAgICAtIEVsIG3DqXRvZG8gQmVuamFtaW5pLUhvY2hiZXJnIGRldGVybWluYSB1biB2YWxvciBjcsOtdGljbyBkZSB2YWxvcmVzIHAgZGVwZW5kaWVudGUgZGVsIHRvdGFsIApkZSBoaXDDs3Rlc2lzIHB1ZXN0YXMgYSBwcnVlYmEgeSBlbCB2YWxvciBkZSBGRFIgZGVzZWFkbyBbQGJlbmphbWluaTE5OTVmZHJdLgoKQW1iYXMgcHJvcGllZGFkZXMgc29uIHJldmlzYWRhcyBbYXF1w61dKGh0dHA6Ly9nZW5vbWljc2NsYXNzLmdpdGh1Yi5pby9ib29rL3BhZ2VzL3VzaW5nX2xpbW1hLmh0bWwpLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9CmRlc2lnbiA8LSBtb2RlbC5tYXRyaXgofiBlc2V0JExldWtlbWlhVHlwZSkKCmViIDwtIGVzZXQgJT4lIAogIGxtRml0KGRlc2lnbikgJT4lIAogIGVCYXllcygpCgplYiAlPiUgdG9wVGFibGUoKQpgYGAKCmBgYHtyfQpkZXNpZ24gPC0gbW9kZWwubWF0cml4KH4gZXNldCRMZXVrZW1pYVR5cGUpCmZpdCA8LSBsbUZpdChlc2V0LCBkZXNpZ24pCmViIDwtIGVCYXllcyhmaXQpCnRvcFRhYmxlKGViKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkKYGBgCgpUaGUgb3V0cHV0IGZyb20gYHRvcFRhYmxlKClgIGluY2x1ZGVzCgotIGBsb2dGQ2A6IHRoZSBsb2cgZm9sZC1jaGFuZ2UgYmV0d2VlbiBjYXNlcyBhbmQgY29udHJvbHMuCi0gYHRgOiB0aGUgdC1zdGF0aXN0aWMgdXNlZCB0byBhc3Nlc3MgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24uCi0gYFAuVmFsdWVgOiB0aGUgcC12YWx1ZSBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb247IHRoaXMgdmFsdWUgaXMgbm90IGFkanVzdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nLgotIGBhZGouUC5WYWxgOiB0aGUgcC12YWx1ZSBhZGp1c3RlZCBmb3IgbXVsdGlwbGUgdGVzdGluZy4gICBEaWZmZXJlbnQgYWRqdXN0bWVudCBtZXRob2RzIGFyZSBhdmFpbGFibGUsIHRoZSBkZWZhdWx0IGlzIEJlbmphbWluaS1Ib3JjaGJlcmcuCgpgYGB7cn0KIyB0aWR5IHRvcHRhYmxlCnRkIDwtIHRvcFRhYmxlKGViLCBjb2VmID0gMiwgICAgICAgICAgICAgICAjIGRlZmF1bHQ6IHNsb3BlCiAgICAgICAgIHNvcnQuYnkgPU5VTEwsIHJlc29ydC5ieSA9TlVMTCwgCiAgICAgICAgICNnZW5lbGlzdCA9IE5VTEwsICAgICAgICAgICAgICAgICAjIG5vIGZpdCRnZW5lCiAgICAgICAgIG51bWJlciA9IEluZiwgICAgICAgICAgICAgICAgICAgICAjIHNob3cgYWxsIHRoZSBoaXBvdGhlc2lzCiAgICAgICAgIGNvbmZpbnQ9MC45NSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSBhcy50YmwoKSAlPiUgCiAgZHBseXI6OnJlbmFtZShHZW5lLklEPXJvd25hbWUpCmBgYAoKYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9CiMgZXhwbG9yZSB0aGUgdG9wdGFibGUKCnRvcFRhYmxlKGViLCBjb2VmID0gMiwgCiAgICAgICAgICMgaW50ZXJlc3Rpbmcgc29ydGluZzogMXN0OiBzaWduaWZpY2FuY2UsIHRoZW46IGVmZmVjdAogICAgICAgICBzb3J0LmJ5ID0iUCIsIHJlc29ydC5ieSA9ImxvZ0ZDIiwKICAgICAgICAgbnVtYmVyID0gSW5mLCAKICAgICAgICAgY29uZmludD0wLjk1KQoKI3RvcFRhYmxlKGViLCBjb2VmID0gYygxLDIpLCBudW1iZXIgPSBJbmYpICU+JSAKIyAgYXMuZGF0YS5mcmFtZSgpICU+JSByb3duYW1lc190b19jb2x1bW4oKSAlPiUgYXMudGliYmxlKCkgJT4lIAojICBhcnJhbmdlKHJvd25hbWUpCiNjb2VmKGViKSAlPiUgCiMgIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIGFzLnRpYmJsZSgpICU+JSAKIyAgYXJyYW5nZShyb3duYW1lKQoKYGBgCgojIyMgUGxvdHMKCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQoKIyMjIyB2YXJpYW5jZSBzaHJpbmthZ2UKCnBhcihtZnJvdz1jKDEsMikpCnBsb3QoZWIkQW1lYW4sIGViJHNpZ21hKQpwbG90KGViJEFtZWFuLCBlYiRzMi5wb3N0KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQp4IDwtIGViICU+JSBiaW9icm9vbTo6YXVnbWVudC5NQXJyYXlMTSgpICU+JSAjIyBFUlJPUiBpbiBmdW5jdGlvbiEhIHMyLnByaW9yISEKICBpbm5lcl9qb2luKAogICAgaW5uZXJfam9pbihlYiRBbWVhbiAlPiUgCiAgICAgICAgICAgICAgIGFzLnRpYmJsZSgpICU+JSAKICAgICAgICAgICAgICAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oKSAlPiUgCiAgICAgICAgICAgICAgIGRwbHlyOjpyZW5hbWUoLkFNZWFuPXZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5nZW5lPXJvd25hbWUpLAogICAgICAgICAgICAgICBlYiRzMi5wb3N0ICU+JSAKICAgICAgICAgICAgICAgYXMudGliYmxlKCkgJT4lIAogICAgICAgICAgICAgICB0aWJibGU6OnJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICAgICAgICAgICAgICAgZHBseXI6OnJlbmFtZShzMi5wb3N0PXZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5nZW5lPXJvd25hbWUpLAogICAgICAgICAgICAgICBieT0iLmdlbmUiKSwKICAgICAgICAgICAgIGJ5PSIuZ2VuZSIpIAoKbSA8LSB4ICU+JSAKICBnZ3Bsb3QoYWVzKC5BTWVhbiwuc2lnbWEpKSsKICBnZW9tX2hleCgpK3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjIsOSkpCiAgI2dlb21fZGVuc2l0eTJkKCkKCm4gPC0geCAlPiUgCiAgZ2dwbG90KGFlcyguQU1lYW4sczIucG9zdCkpKwogIGdlb21faGV4KCkrc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMiw5KSkKICAjZ2VvbV9kZW5zaXR5MmQoKSMKCm8gPC0geCAlPiUgCiAgZ2dwbG90KGFlcyguQU1lYW4sLnNpZ21hKSkrCiAgI2dlb21faGV4KCkrc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMiw5KSkKICBnZW9tX2RlbnNpdHkyZCgpIysKICAjc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMDUsMC43KSkrCiAgI3NjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjA1LDE1KSkKCnAgPC0geCAlPiUgCiAgZ2dwbG90KGFlcyguQU1lYW4sczIucG9zdCkpKwogICNnZW9tX2hleCgpCiAgZ2VvbV9kZW5zaXR5MmQoKSMrCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjA1LDAuNykpKwogICNzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4wNSwxNSkpCgpSbWlzYzo6bXVsdGlwbG90KG0sbixvLHAsY29scyA9IDIpCmBgYAoKIyMjIyBwLXZhbHVlIGhpc3RvZ3JhbQoKLSB1c2VmdWwgdG8gY2hlY2sgcHJpb3IgdG8gZXhlY3V0aW9uIG9mIGEgbXVsdGlwbGUgY29tcGFyaXNvbiBjb3JyZWN0aW9uLgoKLSBFbCBjb21wb3J0YW1pZW50byBkZSBlc3RhIGNvcnJlY2Npw7NuIHB1ZWRlIGluZmVyaXJzZSBwcmVsaW1pbmFybWVudGUgYWwgb2JzZXJ2YXIgbGEgZGl0cmlidWNpw7NuIGRlIHZhbG9yZXMgcCBlbiB1biBoaXN0b2dyYW1hLiAKLSBDb3Jyb2JvcmFyIHF1ZSBsYSBwcm9wb3JjacOzbiBkZSB2YWxvcmVzIHAgYWp1c3RhZG9zIG1lbm9yZXMgYWwgbml2ZWwgZGUgRkRSIGRlc2VhZG8gc2Vyw6EgaWd1YWwgYSBsYSBwcm9wb3JjacOzbiBkZSB2YWxvcmVzIHAgbWVub3JlcyBhbCBuaXZlbCBkZSBzaWduaWZpY2FuY2lhIHF1ZSBlc3TDqW4gc29icmUgbGEgZGlzdHJpYnVjacOzbiBkZSBsYXMgaGlww7N0ZXNpcyBudWxhcyBubyByZWNoYXphZGFzLgotIF9fQ29tcGFyYXIgY29uIGVsIHNpZ3VpZW50ZSBjYXNvX18KCmBgYHtyfQp0ZXN0IDwtIHRvcFRhYmxlKGViLCBjb2VmID0gMiwKICAgICAgICAgICAgICAgICBzb3J0LmJ5ID0iUCIsIAogICAgICAgICAgICAgICAgICNzb3J0LmJ5ID0iQXZlRXhwciIsIAogICAgICAgICAgICAgICAgIGdlbmVsaXN0ID0gZml0JGdlbmVzJEdlbmUuSUQsIG51bWJlciA9IEluZikKbGlicmFyeShnZ3Bsb3QyKQpheCA8LSBxcGxvdCh0ZXN0JFAuVmFsdWUsIGJpbndpZHRoPS4wNSkKYnggPC0gcXBsb3QodGVzdCRhZGouUC5WYWwsIGJpbndpZHRoPS4wNSkKUm1pc2M6Om11bHRpcGxvdChheCxieCxjb2xzID0gMikKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgZWNobz1GQUxTRX0KCiMjIyMgYmFzZSBSIHZvbGNhbm8gcGxvdAoKIyAoMikgVm9sY2FubyBwbG90OiBMb2cgRm9sZCBDaGFuZ2UgeCAtbG9nMTAocC52YWx1ZSkKI3NvdXJjZTogaHR0cDovL2dlbm9taWNzY2xhc3MuZ2l0aHViLmlvL2Jvb2svcGFnZXMvdXNpbmdfbGltbWEuaHRtbAoKIwpwYXIobWZyb3c9YygxLDIpKQp3aXRoKHRkLCBwbG90KGxvZ0ZDLCAtbG9nMTAoUC5WYWx1ZSksY2V4PS43LCBwY2g9MjAsCiAgICAgICAgICAgICAgICAgICAgbWFpbiA9ICJjYXNvIHZzIGNvbnRyb2wiLAogICAgICAgICAgICAgICAgICAgICNjb2w9Y29scywKICAgICAgICAgICAgICAgICAgICAjeGxpbT1jKC0yLDIpLCB5bGltPWMoMCwxNSksCiAgICAgICAgICAgICAgICAgICAgeGxhYj0ibG9nIEZvbGQgQ2hhbmdlIikpCmFibGluZShoPWMoLWxvZzEwKDAuMDUpLC1sb2cxMCgxZS0xMykpLAogICAgICAgdj1jKC0xLDEpLAogICAgICAgbHR5PTIsIGNvbD0gImdyZXk1NSIpCmBgYAoKPCEtLQpoPC10b3BUYWJsZShlYiwgY29lZiA9IDIsIAogICAgICAgICAgICBzb3J0LmJ5ID1OVUxMLCByZXNvcnQuYnkgPU5VTEwsIAogICAgICAgICAgICBnZW5lbGlzdCA9IE5VTEwsIAogICAgICAgICAgICBudW1iZXIgPSBJbmYsIAogICAgICAgICAgICBjb25maW50PTAuOTUpCmg8LWhbcm93bmFtZXMoY29lZihlYikpLF0KdGQgPC0gZGF0YS5mcmFtZShHZW5lLklEPWRpbW5hbWVzKGViJGNvZWZmaWNpZW50cylbWzFdXSxsb2dGQz1jb2VmKGViKVssMl0sQXZlRXhwcj1oJEF2ZUV4cHIsIHAudmFsdWU9ZWIkcC52YWx1ZVssMl0sIHBhZGo9aCRhZGouUC5WYWwsIEI9aCRCKQotLT4KCiMjIyMgdm9sY2FubyBwbG90CgotIFZpc3VhbGl6YWNpw7PFhCBkZWwgZWZlY3RvIGRlbCBjYXNvIHNvYnJlIGVsIGNvbnRyb2wgKGxvZ0ZDKSBwb3Igc3Ugc2lnbmlmaWNhbmNpYSBlc3RhZMOtc3RpY2EuCgotIHR1dG9yaWFsIFthcXXDrV0oaHR0cDovL3d3dy5nZXR0aW5nZ2VuZXRpY3Nkb25lLmNvbS8yMDE2LzAxL3JlcGVsLW92ZXJsYXBwaW5nLXRleHQtbGFiZWxzLWluLWdncGxvdDIuaHRtbCkKCmBgYHtyLCBlY2hvPVRSVUV9CiMgKDIpIFZvbGNhbm8gcGxvdDogTG9nIEZvbGQgQ2hhbmdlIHggLWxvZzEwKHAudmFsdWUpCgp0ZCAlPiUgCiAgbXV0YXRlKHNpZ25pZmljYW5jZT1pZl9lbHNlKFAuVmFsdWU8MWUtMTMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwLmFkaiA8IDFlLTEzIiwiZGlmZiBydmUiKSkgJT4lIAogIGdncGxvdChhZXMobG9nRkMsLWxvZzEwKFAuVmFsdWUpKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91cj1zaWduaWZpY2FuY2UpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJibGFjayIsInJlZCIpKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBmaWx0ZXIodGQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFAuVmFsdWU8MWUtMTQgfCBQLlZhbHVlPDFlLTEzICYgbG9nRkM+MCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhsYWJlbD1HZW5lLklEKSkgKwogIGxhYnModGl0bGU9IkxldWtlbWlhIEROQSBtaWNyb2FycmF5IiwKICAgICAgIHN1YnRpdGxlPSJDYXNvIHZzIENvbnRyb2wiKQpgYGAKCiMjIyMgaGVhdG1hcCArIGhpZXJhY2hpY2FsIGNsdXN0ZXJpbmcKCkxhIGluZmVyZW5jaWEgZXN0YWTDrXN0aWNhIGVzIGNvbcO6bm1lbnRlIGNvbXBsZW1lbnRhZGEgY29uIHTDqWNuaWNhcyBkZSBjbGFzaWZpY2FjacOzbi4KCjEuIExhIGNsYXNpZmljYWNpw7NuIF9fc3VwZXJ2aXNhZGFfXyBvIHByZWRpY2Npw7NuIGRlIGNsYXNlLCBkZWZpbmUgX2EgcHJpb3JpXyAKZWwgbsO6bWVybyBkZSBjYXRlZ29yw61hcywgZWwgY29uanVudG8gZGUgZW50cmVuYW1pZW50byB5IGVsIGRlIHBydWViYS4gRWplbXBsb3M6Cl9zdXBwb3J0IHZlY3RvciBtYWNoaW5lc18gKFNWTSksIF9rLW5lYXJlc3QgbmVpZ2hib3JzXyAoay1OTikgeSB2YWxpZGFjacOzbgpwb3IgX2xlYXZlLW9uZS1vdXQgY3Jvc3MtdmFsaWRhdGlvbl8gKExPT0NWKS4KCjIuIExhIGNsYXNpZmljYWNpw7NuIF9fbm8tc3VwZXJ2aXNhZGFfXyBvIGRlc2N1YnJpbWllbnRvIGRlIGNsYXNlLCBhZ3J1cGEgb2JqZXRvcyAKZW4gYmFzZSBhIG3DqXRyaWNhcyBkZSBzaW1pbGFyaWRhZCBkZSBsb3Mgb2JqZXRvcyBhIGxvIGxhcmdvIGRlIGxhcyBtdWVzdHJhcy4KUmVxdWllcmUgZGVmaW5pciAyIHRpcG9zIGRlIGFsZ29yaXRtb3M6IAogICAgCiAgICAtIGRlIGRpc3RhbmNpYTogZS5nLiwgRXVjbGlkaWFuYSwgZW4gbGEgcXVlIHNlIHByaW9yaXphIGxhIAogICAgbWFnbml0dWQgc29icmUgbGEgZGlzcGVyc2nDs24gZGUgbGFzIHNlw7FhbGVzLCB5IGxhIGNvcnJlbGFjacOzbiBkZSAKICAgIFBlYXJzb24sIGVuIGxhIHF1ZSBzZSBwcmlvcml6YSBsYSBkaXNwZXJzacOzbiBzb2JyZSBsYSBtYWduaXR1ZC4KICAgIAogICAgLSBkZSBhZ3J1cGFtaWVudG86IGUuZy4sIGFncnVwYW1pZW50byBqZXLDoXJxdWljbyBvIF9oaWVyYXJjaGljYWwgY2x1c3RlcmluZ18sCiAgICBlbiBsYSBxdWUgbG9zIHJhY2ltb3MgbyBfY2x1c3RlcnNfIHNlIGZvcm1hbiBpdGVyYXRpdmFtZW50ZSBhbCBjYWxjdWxhciAKICAgIGxhIGRpc3RhbmNpYSBlbnRyZSBlbGVtZW50b3MgeSByYWNpbW9zIGVuIGZvcm1hY2nDs24uIAogICAgTcOhcyBkZXRhbGxlcywgW2FxdcOtXShib25zYWkuaGdjLmpwL35tZGVob29uL3NvZnR3YXJlL2NsdXN0ZXIvY2x1c3RlcjMucGRmKS4gCiAgICBPdHJvcyBzb24gZWwgCiAgICBfay1tZWFuIGNsdXN0ZXJpbmdfLCBfc2VsZi1vcmdhbml6aW5nIG1hcHNfIChTT00pIHkgCiAgICBfcHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpc18gKFBDQSkuCiAgICAKICAgID4gTGFzIHByaW5jaXBhbGVzIGRlc3ZlbnRhamFzIGRlIGxhIHTDqWNuaWNhIGVzdMOhbiBlbiBlbCByZXF1ZXJpbWllbnRvIAogICAgZGUgZGVjaXNpb25lcyBlbnRyZSB2YXJpb3MgYWxnb3JpdG1vcyBzaW4gY29uc2Vuc28geSBzdSBlc2Nhc2EgcmVwcm9kdWNpYmlsaWRhZAogICAgZW50cmUgZXhwZXJpbWVudG9zLiBbQGFsbGlzb24yMDA2XQoKYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCBmaWcuYWxpZ249ImNlbnRlciJ9CiNlc2V0IDwtIGVzZXQjbGV1a2VtaWFzRXNldAojZXhwcnMoZXNldCkgJT4lIGRpbSgpCnggPC0gdGQgJT4lIAogIGFycmFuZ2UoZGVzYyh0KSkgJT4lIAogIGZpbHRlcihCPjAgJiBhZGouUC5WYWw8MWUtMTApICU+JSAKICBzZWxlY3QoR2VuZS5JRCkgJT4lIGFzLm1hdHJpeCgpIAojeCAlPiUgZGltKCkKIyU+JSBkaW0oKQphaGVhdG1hcChleHBycyhlc2V0KVt4LF0sIAogICAgICAgICBSb3d2ID0gVFJVRSwgQ29sdiA9IFRSVUUsIAogICAgICAgICBhbm5Db2wgPSBwRGF0YShlc2V0KSwgCiAgICAgICAgIGxheW91dCA9ICJfIikKYGBgCgpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KIyMjIyBib3hwbG90cwpiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKSAlPiUgCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGdlbmUsdmFsdWUsb3JkZXIgPSBUUlVFKSx2YWx1ZSxmaWxsPUxldWtlbWlhVHlwZSkpKwogIGdlb21fYm94cGxvdCgpKwogICNnZW9tX3BvaW50KCkgKwogIHlsYWIoImxvZzItdHJhbnNmb3JtZWQgbm9ybWFsaXplZCBNRkkiKSsKICB4bGFiKCJhbnRpZ2VucyIpKwogIGxhYnModGl0bGU9IkRpZmZlcmVudGlhbiByZWFjdGl2aXR5IG9mIGFudGlib2RpZXMiLAogICAgICAgc3VidGl0bGU9ImZpbHRlcmVkIGJ5IEI+MCAofmFkai5QLlZhbDwwLjAxKSBhbmQgc29ydGVkIHcuci50LiBtZWRpYW4gQWIgcmVhY3Rpdml0eSBwZXIgZ2VuZSIpKwogIGNvb3JkX2ZsaXAoKSAjIE9SREVOQVIgZWplIGRlIHByb3Rlw61uYXMhISEhCmBgYAoKCiMjIFByb3RlaW4gbWljcm9hcnJheTogTWFsYXJpYQoKX19Db250ZXh0bzpfXwoKLSBQYWNpZW50ZXMgX19jb25fXyBwYXJhc2l0ZW1pYSBjaXJjdWxhbnRlIGRlIF9QLiBmYWxjaXBhcnVtXyB5IF9fYXVzY2VuY2lhX18gZGUgc8OtbnRvbWFzIHNvbiBjb25zaWRlcmFkb3MgY29tbyBpbmRpdmlkdW9zIGNvbiBpbm11bmlkYWQgY2zDrW5pY2EgYW50ZSBsYSBtYWxhcmlhLgotIF9fSGlww7N0ZXNpczpfXyBMYSByZXNwdWVzdGEgZGUgYW50aWN1ZXJwb3MgYW50ZSBsYSBpbmZlY2Npw7NuIGVuIGVsIGdydXBvIGRlIF9fcGFjaWVudGVzIGFzaW50b23DoXRpY29zX18gcmVjb25vY2UgdW4gc3ViZ3J1cG8gZGUgcHJvdGXDrW5hcyBkZSBfUC4gZmFsY2lwYXJ1bV8sIHBvc2libGVtZW50ZSBhc29jaWFkYXMgYWwgZGVzYXJyb2xsbyBkZSBsYSBpbm11bmlkYWQgY2zDrW5pY2EuCgpSZXZpc2FyIG3DoXMgaW5mb3JtYWNpw7NuIHNvYnJlIGVsIGV4cGVyaW1lbnRvIFthcXXDrV0oaHR0cHM6Ly9hY2FkZW1pYy5vdXAuY29tL2ppZC9hcnRpY2xlLWxvb2t1cC9kb2kvMTAuMTA5My9pbmZkaXMvaml1NjE0KS4KCiMjIyBQcm9ibGVtYQoKLSDCv0PDs21vIGxpbXBpYXIgbGEgZGF0YSBkc3BvbmlibGUgeSBnZW5lcmFyIHVuIGBFeHByZXNzaW9uU2V0KClgIGRlc2RlIGNlcm8/Ci0gwr9RdcOpIHByb3Rlw61uYXMgZXN0w6FuIGRpZmVyZW5jaWFsbWVudGUgcmVjb25vY2lkYXMgZW4gZWwgZ3J1cG8gZGUgYXNpbnRvbcOhdGljb3MgY29uIHJlc3BlY3RvIGEgbG9zIHNpbnRvbcOhdGljb3M/CgojIyMgVGlkeSB1cCBkYXRhCgpgYGB7cn0KcmF3PC1wcm90bWljcm8KYGBgCgpgYGB7ciwgZXZhbD1GQUxTRX0KcmF3ICU+JSBWaWV3KCkKYGBgCgojIyMjIHBoZW5vdHlwZSBkYXRhCgotIE9iamV0aXZvOgogICAgKyBFeHRyYWVyIGxhIGRhdGEgZmVub3TDrXBpY2EsCiAgICArIFRyYW5zcG9uZXIgc3UgZXN0cnVjdHVyYSwKICAgICsgQXNpZ25hciBlbCBub21icmUgZGUgbXVlc3RyYSBwb3IgY29sdW1uYSwKICAgICsgQ3JlYXIgdW4gbnVldm8gb2JqZXRvIGNhcGF6IGRlIHNlciBsZcOtZG8gcG9yIGVsIGBFeHByZXNzaW9uU2V0YC4KCmBgYHtyfQojc2FtcGxlcyA8LSByYXdbMToyLF0gJT4lIGNvbG5hbWVzKCkKI3NhbXBsZXMgJT4lIGFzLm1hdHJpeCgpICU+JSB0KCkgJT4lIGNsYXNzKCkKI2h0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzM0MDA0MDA4L3RyYW5zcG9zaW5nLWluLWRwbHlyCgpwaGVub19kYXRhIDwtIHJhd1sxOjIsXSAlPiUgCiAgc2xpY2UoMSkgJT4lIAogIHNlbGVjdCgtMSwtMikgJT4lIAogIG11dGF0ZShncm91cD0xKSAlPiUgCiAgZ2F0aGVyKHNhbXBsZV9uYW1lLHBoZW5vdHlwZSkgJT4lIAogIGZpbHRlcihwaGVub3R5cGUhPSIxIikgCgpwaGVub19kYXRhICU+JSBhcnJhbmdlKHNhbXBsZV9uYW1lKQpwaGVub19kYXRhICU+JSBjb3VudChwaGVub3R5cGUpCmBgYAoKYGBge3J9CiNodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvdGliYmxlL3ZlcnNpb25zLzEuMy4zL3RvcGljcy9yb3duYW1lcwpwaGVub19kYXRhX3JvdyA8LSBwaGVub19kYXRhICU+JSAKICBhcnJhbmdlKHNhbXBsZV9uYW1lKSAlPiUgCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXModmFyPSJzYW1wbGVfbmFtZSIpCgpwaGVub19kIDwtIG5ldygiQW5ub3RhdGVkRGF0YUZyYW1lIiwgZGF0YT1waGVub19kYXRhX3JvdykKYGBgCgojIyMjIGV4cHJlc3Npb24gZGF0YQoKLSBPYmpldGl2bzoKICAgICsgVHJhbnNmb3JtYXIgZWwgYGRhdGEuZnJhbWVgIGEgdW5hIG1hdHJpeiwKICAgICsgU2VwYXJhciBsYSBkYXRhIGRlIGV4cHJlc2nDs24gZGUgbGEgZGF0YSBkZSBub3JtYWxpemFjacOzbi4KCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQpyYXdbNzc6bnJvdyhyYXcpLF0gJT4lIAogIHJlbmFtZShnZW5lX25hbWU9IlhfXzEiLAogICAgICAgICBnZW5lX0lEPSJYX18yIikgJT4lIAogIHNlbGVjdCgxOjEwLC1nZW5lX25hbWUpICU+JSAjc29sbyBwcmltZXJhcyA4IG11ZXN0cmFzIGNvbiBmaW4gZGVtb3N0cmF0aXZvCiAgbXV0YXRlKGdyb3VwPXNlcShuKCkpKSAlPiUgCiAgdW5pdGUoZ2VuZV9JRC5uLGdlbmVfSUQsZ3JvdXAsc2VwID0gIi4iKSAlPiUgCiAgZ2F0aGVyKHNhbXBsZV9uYW1lLCBleHByZXNzaW9uLCAtZ2VuZV9JRC5uKSAlPiUgCiAgbXV0YXRlKGV4cHJlc3Npb249YXMubnVtZXJpYyhleHByZXNzaW9uKSkgJT4lIAogIHJlc2hhcGUyOjphY2FzdChnZW5lX0lELm4gfiBzYW1wbGVfbmFtZSwKICAgICAgICAgICAgICAgICAgdmFsdWUudmFyID0gImV4cHJlc3Npb24iKSAlPiUgaGVhZCgpICMlPiUgY2xhc3MoKQpgYGAKCmBgYHtyfQojIGxpbXBpZXphIGluaWNpYWwKZXhwcnNfZGF0YSA8LSByYXdbNzc6bnJvdyhyYXcpLF0gJT4lIAogIHJlbmFtZShnZW5lX25hbWU9IlhfXzEiLAogICAgICAgICBnZW5lX0lEPSJYX18yIikgJT4lIAogIHNlbGVjdCgtZ2VuZV9uYW1lKSAlPiUgCiAgbXV0YXRlKGdyb3VwPXNlcShuKCkpKSAlPiUgCiAgdW5pdGUoZ2VuZV9JRC5uLGdlbmVfSUQsZ3JvdXAsc2VwID0gIi4iKSAlPiUgCiAgbXV0YXRlKGdlbmVfSUQubj1zdHJpbmdyOjpzdHJfcmVwbGFjZShnZW5lX0lELm4sIlxccyIsIiIpKQoKI2V4cHJzX2RhdGEgJT4lIGRpbSgpICMzMzY2OApleHByc19jdHJsIDwtIGV4cHJzX2RhdGEgJT4lIHNsaWNlKDE6MzEpICMlPiUgZGltKCkgIyAzMSAibm8gRE5BIiBwZXIgc2FtcGxlCmV4cHJzX3Byb3QgPC0gZXhwcnNfZGF0YSAlPiUgc2xpY2UoMzI6bigpKSAjJT4lIGRpbSgpICMgMzM2MzcgIm5vIEROQSIgcGVyIHNhbXBsZQoKIyBQUk9URUlOUwpleHByc19wcm90X20gPC0gZXhwcnNfcHJvdCAlPiUgCiAgZ2F0aGVyKHNhbXBsZV9uYW1lLCBleHByZXNzaW9uLCAtZ2VuZV9JRC5uKSAlPiUgCiAgbXV0YXRlKGV4cHJlc3Npb249YXMubnVtZXJpYyhleHByZXNzaW9uKSkgJT4lIAogIHJlc2hhcGUyOjphY2FzdChnZW5lX0lELm4gfiBzYW1wbGVfbmFtZSwKICAgICAgICAgICAgICAgICAgdmFsdWUudmFyID0gImV4cHJlc3Npb24iKSAjJT4lIGNsYXNzKCkKIyBkaW1lbnNpw7NuCmRpbShleHByc19wcm90X20pCiMgc2VpcyBsZWN0dXJhcyBwb3IgcHJvdGXDrW5hIGRlIGxhcyA4IHByaW1lcmFzIG11ZXN0cmFzCmhlYWQoZXhwcnNfcHJvdF9tWywxOjhdKQoKIyBDT05UUk9MCmV4cHJzX2N0cmxfbSA8LSBleHByc19jdHJsICU+JQogIHN1bW1hcmlzZV9hbGwobWVkaWFuKSAlPiUgIyBNRURJQU4gdG8gTk9STUFMSVpFIGFnYWluc3Qgbm9ETkEgY29udHJvbHMKICBnYXRoZXIoc2FtcGxlX25hbWUsIGV4cHJlc3Npb24sIC1nZW5lX0lELm4pICU+JSAKICBtdXRhdGUoZXhwcmVzc2lvbj1hcy5udW1lcmljKGV4cHJlc3Npb24pKSAlPiUgCiAgcmVzaGFwZTI6OmFjYXN0KGdlbmVfSUQubiB+IHNhbXBsZV9uYW1lLAogICAgICAgICAgICAgICAgICB2YWx1ZS52YXIgPSAiZXhwcmVzc2lvbiIpICMlPiUgZGltKCkgIyU+JSBjbGFzcygpCiMgZGltZW5zacOzbgpkaW0oZXhwcnNfY3RybF9tKQojIGNvbnRyb2xlcyBub0ROQSBkZSBsYXMgOCBwcmltZXJhcyBtdWVzdHJhcwpleHByc19jdHJsX21bLDE6OF0KYGBgCgpgYGB7cn0KbWF0IDwtIE5VTEwgIyBjcmVhciBvYmpldG8gdmFjw61vCiMgbG9vcCBwYXJhIGdlbmVyYXIgdW5hIG1hdHJpeiBkZSBsYXMgZGltZW5zaW9uZXMgZGUgYGV4cHJzX3Byb3RfbWAKZm9yKGkgaW4gMTpucm93KGV4cHJzX3Byb3RfbSkpewogIG1hdCA8LSByYmluZChtYXQsZXhwcnNfY3RybF9tKQp9CiMgZGltZW5zaW9uZXMgZGUgbGEgbWF0cml6IGNvbiBsYSBtZWRpYW5hIGRlIGN0cmxzIGBub0ROQWAgY3JlYWRhCmRpbShtYXQpCiMgbWF0cml6IGNvbiBsYSBtZWRpYW5hIGRlIGN0cmxzIGBub0ROQWAgcGFyYSBsYXMgOCBwcmltZXJhcyBtdWVzdHJhcwpoZWFkKG1hdFssMTo4XSkgIyU+JSBjbGFzcygpCmBgYAoKIyMjIyBnZW5lIG5hbWVzCgpgYGB7cn0KIyBnZW5lcmF0ZSBhIGxpc3QgKGRmKSBvZiBnZW5lIG5hbWVzIGFuZCBnZW5lIElEJ3MKbG4gPC0gcmF3WzEwODpucm93KHJhdyksMToyXSAlPiUgCiAgcmVuYW1lKGdlbmVfbmFtZT0iWF9fMSIsCiAgICAgICAgIGdlbmVfSUQ9IlhfXzIiKSAlPiUgCiAgbXV0YXRlKG51bT1zZXEoZnJvbT0zMiwgdG89MzErbigpKSkgJT4lIAogIHVuaXRlKGdlbmVfSUQubixnZW5lX0lELG51bSxzZXA9Ii4iKSAlPiUKICBmdWxsX2pvaW4oZXhwcnNfcHJvdCxieT0iZ2VuZV9JRC5uIikgJT4lIAogIHNlbGVjdCgxOjIpICU+JSAKICByZW5hbWUoR2VuZS5JRD1nZW5lX0lELm4pCmBgYAoKIyMjIE5vcm1hbGl6YXRpb24gKyBUcmFuc2Zvcm1hdGlvbgoKT2JqZXRpdm8gZGUgbGEgX19ub3JtYWxpemFjacOzbl9fOiBob21vZ2VuZWl6YXIgbGEgdmFyaWFiaWxpZGFkIGVudHJlIGFycmVnbG9zCmVuIGJhc2UgYSBjb250cm9sZXMsIGxvcyBjdWFsZXMgc2UgYXN1bWUgcXVlIHNvbiBpbnZhcmlhbnRlcyBlbnRyZSBtdWVzdHJhcy4gCkVsIG3DqXRvZG8gZGVwZW5kZSBkZWwgZGlzZcOxbyBkZSBhcnJlZ2xvczoKCi0gc3VzdHJhY2Npw7NuIGRlIGNvbnRyb2xlcyBvIF9mb2xkIG92ZXIgY29udHJvbF8gKF9fRk9DX18pLAphcGxpY2FkbyBlbiBtaWNyb2FycmVnbG9zIGRlIHByb3Rlw61uYXMgY29uIHJlc3BlY3RvIGEgbGEgbWVkaWFuYSBkZWwgY29udHJvbCBibGFuY28KcG9yIG11ZXN0cmEgW0BLaW5nMjAxNUZPQ107Ci0gZXN0YWJpbGl6YWNpw7NuIGRlIHZhcmlhbnphcyBvIF9fVlNOX18sIAphcGxpY2FkbyBlbiBtaWNyb2FycmVnbG9zIGRlIEROQSBjb24gcmVzcGVjdG8gYSBjb250cm9sZXMgZGUgCmludGVuc2lkYWQgaW52YXJpYW50ZSBlbnRyZSBtdWVzdHJhcywgZS5nLiBnZW5lcyBfaG91c2VrZWVwaW5nXyBbQGh1YmVyMjAwMnZzbl0KCk9iamV0aXZvIGRlIGxhIF9fdHJhbnNmb3JtYWNpw7NuX186IHJlZHVjaXIgbGEKaGV0ZXJvY2VkYXN0aWNpZGFkIG8gaGV0ZXJvZ2VuZWlkYWQgZGUgdmFyaWFuemFzIGVudHJlIGxhcyBvYnNlcnZhY2lvbmVzIApwb3IgZXJyb3JlcyBhbGVhdG9yaW9zIGVuIGVsIHByb2Nlc28gZGUgaGlicmlkYWNpw7NuIFtAa3JlaWwyMDA1YnVsbGV0XS4KRG9zIHByaW5jaXBhbGVzIG3DqXRvZG9zOgoKLSBfX2xvZ2Fyw610bWljYV9fLApsYSBjdWFsIGFzdW1lIHVuIGVycm9yIG11bHRpcGxpY2F0aXZvIHF1ZSBjb3JyaWdlIGxhcyB2YXJpYW56YXMgZGUgCmFsdGEgaW50ZW5zaWRhZCBwZXJvIGNhcGF6IGRpc3BlcnNhciBhIGxhcyBkZSBiYWphIGludGVuc2lkYWQ7IHkKLSBfX2FzaW5oX18sCmxhIGN1YWwgYXN1bWUgdW4gZXJyb3IgbXVsdGlwbGljYXRpdm8geSBhZGl0aXZvIHF1ZSBjb3JyaWdlIGVzdGEgZGlzcGVyc2nDs24sIApwZXJvIHNvbG8gcmVsZXZhbnRlIGVuIGNvbnRleHRvcyBkb25kZSBsb3MgdmFsb3JlcyBub3JtYWxpemFkb3MgbWVub3JlcyBhIGxhIHVuaWRhZCAKdGllbmVuIHNpZ25pZmljYWRvIGJpb2zDs2dpY28uCgpFbiBlbCBjb250ZXh0byBkZSBtaWNyb2FycmVnbG9zIGRlIEROQSwgYW1iYXMgdHJhbnNmb3JtYWNpb25lcyBwZXJtaXRlbiBob21vZ2VuaXphciBsYSBzb2JyZWV4cHJlc2nDs24gbyByZXByZXNpw7NuIGfDqW5pY2EgY29uIHJlc3BlY3RvIGEgZWwgY29udHJvbCBlbGVnaWRvLiBQb3IgZWplbXBsbywgdW5hIHNvYnJlZXhwcmVzacOzbiBkZSA0IHNvYnJlIGVsIGNvbnRyb2wgc2UgaG9tb2dlbml6YSBjb24gdW5hIHJlcHJlc2nDs24gZGUgbGEgbWlzbWEgbWFnbml0dWQ6CgokJGxvZ18yXGxlZnQoXGZyYWN7Z2VuX3h9e2N0cmx9XHJpZ2h0KSBccXF1YWQgXFJpZ2h0YXJyb3cgXHFxdWFkIGxvZ18yXGxlZnQoXGZyYWN7NGF9e2F9XHJpZ2h0KT0rMiBccXF1YWQgb3IgXHFxdWFkIGxvZ18yXGxlZnQoXGZyYWN7Yn17NGJ9XHJpZ2h0KT0tMiQkCgo+ICoqTk9UQSoqOiBMb3MgYXV0b3JlcyBkZWwgcGFwZXIgcmVwb3J0YW4gZWwgbcOpdG9kbyBgdnNuYC4gQSBkaWZlcmVuY2lhIGRlIGxhIHRyYW5zZm9ybWFjacOzbiBsb2dhcsOtdGltaWNhLCBlc3RlIGxvZ3JhIGNvcnJlZ2lyIGVycm9yZXMgZW4gbGVjdHVyYXMgZGUgaW50ZW5zaWRhZCBiYWphIChlLmcuLCBjZXJjYW5hcyB5IG1lbm9yZXMgYSBsYSB1bmlkYWQgcG9zdGVyaW9yIGEgc3Ugbm9ybWFsaXphY2nDs24pLiBFcyBpZMOzbmVvIGVuIGV4cGVyaW1lbnRvcyBkb25kZSBsYSBpbnRlbnNpZGFkZXMgcG9zaXRpdmFzIHkgbmVnYXRpdmFzIGNvbiByZXNwZWN0byBhbCBjb250cm9sIChnZW5lcmFsbWVudGUsIGdlbmVzIF9ob3VzZWtlZXBpbmdfKSBzb24gYmlvbMOzZ2ljYW1lbnRlIHJlbGV2YW50ZXMuIFNpbiBlbWJhcmdvLCBlbCBjb250ZXh0byBkZSBtaWNyb2FycmVnbG8gZGUgcHJvdGXDrW5hcyBlcyBwYXJ0aWN1bGFybWVudGUgYXNpbcOpdHJpY28sIGVzIGRlY2lyLCBsYXMgbGVjdHVyYXMgY29uIHJlbGV2YW5jaWEgYmlvbMOzZ2ljYSBzZXLDoW4gdG9kYXMgbGFzIHF1ZSBwb3NlZWFuIGludGVuc2lkYWRlcyBtYXlvcmVzIGFsIGNvbnRyb2wgbmVnYXRpdm8gKG5vRE5BKSB1c2FkbyBlbiBsYSBub3JtYWxpemFjacOzbi4gCk3DoXMgZGV0YWxsZXMsIFthcXXDrV0oaHR0cHM6Ly9hY2FkZW1pYy5vdXAuY29tL2JpYi9hcnRpY2xlLzYvMS84Ni8yODg5MjMvVHV0b3JpYWwtc2VjdGlvbi1UaGVyZS1pcy1uby1zaWx2ZXItYnVsbGV0LWEtZ3VpZGUpCgpgYGB7cn0KIyBjdXN0b20gZnVuY3Rpb24KIyBkZWZpbmlyIHJlc3VsdGFkbyBwYXJhIGxvcyB2YWxvcmVzIG1lbm9yZXMgYSBjZXJvLCAKIyBkb25kZSBlbCBsb2cgbm8gZXN0w6EgZGVmaW5pZG8KbG9nMi5OQSA9IGZ1bmN0aW9uKHgpIHtsb2cyKGlmZWxzZSh4PjAsIHgsIE5BKSl9CgojIG5vcm1hbGl6YWNpw7NuIGNvbiByZXNwZWN0byBhIGxvcyBjb250cm9sZXMgYG5vRE5BYCBjLyB0cmFuc2Zvcm1hY2nDs24gbG9nMgpleHByc19ub3JtIDwtIGxvZzIuTkEoZXhwcnNfcHJvdF9tL21hdCkKaGVhZChleHByc19ub3JtWywxOjZdKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0xMCwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KIyBjb21wYXJlIGJldHdlZW4gbm9ybWFsaXphdGlvbiBtZXRob2RzCnogPC0gZXhwcnNfcHJvdF9tICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIGFzLnRibCgpICU+JSAKICBnYXRoZXIoc2FtcGxlLGV4cHJlc3Npb24pICU+JSAKICBhcnJhbmdlKGV4cHJlc3Npb24pICMlPiUgc3VtbWFyeSgpCmEgPC0gZXhwcnNfcHJvdF9tL21hdAojYSAlPiUgZGltKCkKYiA8LSBhICU+JSAKICBhcy5kYXRhLmZyYW1lKCkgJT4lIGFzLnRibCgpICU+JSAKICBnYXRoZXIoc2FtcGxlLGV4cHJlc3Npb24pICU+JSAKICBhcnJhbmdlKGV4cHJlc3Npb24pICMlPiUgc3VtbWFyeSgpCmMgPC0gYiAlPiUgCiAgZ2dwbG90KGFlcyhleHByZXNzaW9uLGxvZzIoZXhwcmVzc2lvbikpKSArCiAgZ2VvbV9oZXgoKSArCiAgI2dlb21fZGVuc2l0eTJkKCkrCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD0xKSwgbHR5PTMpCmQgPC0gYiAlPiUgCiAgZ2dwbG90KGFlcyhleHByZXNzaW9uLGxvZzIoZXhwcmVzc2lvbikpKSArCiAgI2dlb21faGV4KCkgKwogIGdlb21fZGVuc2l0eTJkKCkrCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD0xKSwgbHR5PTMpClJtaXNjOjptdWx0aXBsb3QoYyxkLGNvbHMgPSAyKQoKZSA8LSBiICU+JSBncm91cF9ieShzYW1wbGUpICU+JSAKICBzdW1tYXJpc2UobWVhbj1tZWFuKGV4cHJlc3Npb24pLHNkPXNkKGV4cHJlc3Npb24pKSAlPiUgCiAgZ2dwbG90KGFlcyhtZWFuLHNkKSkrCiAgZ2VvbV9wb2ludCgpK2dlb21fc21vb3RoKCkKZiA8LSBiICU+JSAKICBtdXRhdGVfYXQodmFycyhleHByZXNzaW9uKSwgZnVucyhsb2cyKSkgJT4lICNhcnJhbmdlKHNhbXBsZSkKICBncm91cF9ieShzYW1wbGUpICU+JQogIHN1bW1hcmlzZShtZWFuPW1lYW4oZXhwcmVzc2lvbiksc2Q9c2QoZXhwcmVzc2lvbikpICU+JSAKICBnZ3Bsb3QoYWVzKG1lYW4sc2QpKSsKICBnZW9tX3BvaW50KCkrZ2VvbV9zbW9vdGgoKQpSbWlzYzo6bXVsdGlwbG90KGUsZixjb2xzID0gMikKYGBgCgoKPCEtLQoKX19FbiBlbCBwYXNhZG8uLi5fXwoKYGBgcgphbGwucmF3X3JuYW1lcyA8LSByYXdbLDJdCmFsbC5yYXdfZGF0YSA8LSBkYXRhLm1hdHJpeChyYXdbLDM6bmNvbChyYXcpXSkKcm93bmFtZXMoYWxsLnJhd19kYXRhKSA8LSBhbGwucmF3X3JuYW1lcwpjdHJsLnJhd19ybmFtZXMgPC0gcmF3WzE6MzEsMl0KY3RybC5yYXdfZGF0YSA8LSBkYXRhLm1hdHJpeChyYXdbMTozMSwzOm5jb2wocmF3KV0pCnJvd25hbWVzKGN0cmwucmF3X2RhdGEpIDwtIGN0cmwucmF3X3JuYW1lcyAgICAgICAgICAgICAgICAKbWVkaWFuLmN0cmwucmF3X2RhdGE8LXQoYXMubWF0cml4KGFwcGx5KGN0cmwucmF3X2RhdGEsIDIsIG1lZGlhbikpKQpyb3duYW1lcyhtZWRpYW4uY3RybC5yYXdfZGF0YSkgPC0gYygibWVkaWFuLmN0cmwiKSAgICAgICAgICAgICAgICAKYW50aS5yYXdfcm5hbWVzIDwtIHJhd1szMjpucm93KHJhdyksMl0gICAgICAgICAgICAgICAgICAgICAgICAgICAKYW50aS5yYXdfZGF0YSA8LSBkYXRhLm1hdHJpeChyYXdbMzI6bnJvdyhyYXcpLDM6bmNvbChyYXcpXSkgICAgIApyb3duYW1lcyhhbnRpLnJhd19kYXRhKSA8LSBhbnRpLnJhd19ybmFtZXMgICAgICAgICAgICAgICAgCm1lZGlhbi5jdHJsLnJhd19kYXRhLjE8LXJlcChtZWRpYW4uY3RybC5yYXdfZGF0YVsxXSxucm93KGFudGkucmF3X2RhdGEpKQptZWRpYW4uY3RybC5yYXdfZGF0YS5tYXQ8LW1hdHJpeChtZWRpYW4uY3RybC5yYXdfZGF0YS4xLGxlbmd0aChtZWRpYW4uY3RybC5yYXdfZGF0YS4xKSwxKQpmb3IgKGkgaW4gMjpuY29sKG1lZGlhbi5jdHJsLnJhd19kYXRhKSkgewogIG1lZGlhbi5jdHJsLnJhd19kYXRhLm1hdDwtY2JpbmQobWVkaWFuLmN0cmwucmF3X2RhdGEubWF0LHJlcChtZWRpYW4uY3RybC5yYXdfZGF0YVtpXSxucm93KGFudGkucmF3X2RhdGEpKSkKfQpsb2cyLnplcm8gPSBmdW5jdGlvbih4KSB7bG9nMihpZmVsc2UoeD4wLCB4LCAxKSl9CmxvZzIuTkEgPSBmdW5jdGlvbih4KSB7bG9nMihpZmVsc2UoeD4wLCB4LCBOQSkpfSAgIGRzaXRyaWJ1dGlvbgpsb2cyLk5BLm5vcm0uQU5USUdFTlM8LWxvZzIuTkEoYW50aS5yYXdfZGF0YS9tZWRpYW4uY3RybC5yYXdfZGF0YS5tYXQpCmBgYAotLT4KCgojIyMgQ3JlYXRlIGFuIEV4cHJlc3Npb25TZXQKCmBgYHtyfQplc2V0IDwtIEV4cHJlc3Npb25TZXQoYXNzYXlEYXRhID0gZXhwcnNfbm9ybSwgCiAgICAgICAgICAgICAgICAgICAgICBwaGVub0RhdGEgPSBwaGVub19kKQplc2V0CmBgYAoKYGBge3IgcXVhbGl0eVgsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9CiMjIyBQcmUtcGxvdHMKCiMjIyMgSGVhdG1hcAoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIFNBTVBMRSBPUkRFUiBwZXIgZ3JvdXAKCiMgW1NUQVJUIEZST00gVEhFIEJFR0lOTk5JTkddCiNlc2V0CiNlc2V0JEdyb3VwIDwtIGZhY3Rvcihlc2V0JEdyb3VwKQojZXNldCRHcm91cAoKI3BEYXRhKGVzZXQpIDwtIGNiaW5kKHBEYXRhKGVzZXQpLGNhdF8yLHQoY29sLm1lYW4ubV9kYXRhWCkpI25jb2wocERhdGEoZXNldCkpCiNyb3duYW1lcyhzYW1wbGVTRVZjb3ZhcmlhdGVzKQojY2F0XzIgPC0gZGF0YS5mcmFtZShhcy5mYWN0b3IobWF0cml4KHNhbXBsZVNFVmNvdmFyaWF0ZXMkZWRhZF9DQVQpKSkKI3Jvd25hbWVzKGNhdF8yKSA8LSByb3duYW1lcyhzYW1wbGVTRVZjb3ZhcmlhdGVzKQojY29sbmFtZXMoY2F0XzIpIDwtICJlZGFkX0NBVF8yIgojcERhdGEoZXNldClbMjNdIDwtIHNhbXBsZVNFVmNvdmFyaWF0ZXMkZWRhZF9DQVQKI3BEYXRhKGVzZXQpIDwtIGNiaW5kKHBEYXRhKGVzZXQpLGNhdF8yKSNuY29sKHBEYXRhKGVzZXQpKQoKIyBzdGFydHMKI2NsYXNzKGV4cHJzKGVzZXQpKSAjbWF0cml4Cm1fZGF0YSA8LSBleHBycyhlc2V0KQptX2RhdGE8LWFzLmRhdGEuZnJhbWUobV9kYXRhKQoKIyBbTU9ESUZJQ0FUSU9OIDI4anVsMjAxNl0KY29sLm1lYW4ubV9kYXRhWDwtdChhcy5tYXRyaXgoYXBwbHkobV9kYXRhLCAyLCBtZWFuLCBuYS5ybT1UUlVFKSkpCnJvd25hbWVzKGNvbC5tZWFuLm1fZGF0YVgpIDwtIGMoImNvbC5tZWFuLm0iKSAgICAgICAgICAgICAgICAgIyBhc3NpZ24gcm93IG5hbWVzIAojY29sLm1lYW4ubV9kYXRhWAoKcm93Lm1lYW4ubV9kYXRhPC1hcy5tYXRyaXgoYXBwbHkobV9kYXRhLCAxLCBtZWFuLCBuYS5ybT1UUlVFKSkKY29sbmFtZXMocm93Lm1lYW4ubV9kYXRhKSA8LSBjKCJyb3cubWVhbi5tIikgICAgICAgICAgICAgICAgICMgYXNzaWduIHJvdyBuYW1lcyAKI3Jvdy5tZWFuLm1fZGF0YQoKCm1fZGF0YV9yb3cubWVhbjwtY2JpbmQobV9kYXRhLHJvdy5tZWFuLm1fZGF0YSkKbV9kYXRhX3Jvdy5tZWFuPC1hcy5tYXRyaXgobV9kYXRhX3Jvdy5tZWFuKQoKbV9kYXRhX3Jvdy5tZWFuPC1hcy5kYXRhLmZyYW1lKG1fZGF0YV9yb3cubWVhbikKbV9kYXRhX3Jvdy5tZWFuPC1tX2RhdGFfcm93Lm1lYW5bb3JkZXIoLW1fZGF0YV9yb3cubWVhbiRyb3cubWVhbi5tKSxdCm1fZGF0YV9yb3cubWVhbjwtYXMubWF0cml4KG1fZGF0YV9yb3cubWVhbikKCm1fZGF0YV9yb3cubWVhbjwtYXMuZGF0YS5mcmFtZShtX2RhdGFfcm93Lm1lYW4pCm1fZGF0YV9yb3cubWVhbiRyb3cubWVhbi5tPC1OVUxMCiNkaW0obV9kYXRhX3Jvdy5tZWFuKQojbV9kYXRhX3Jvdy5tZWFuCm1fZGF0YV9yb3cubWVhbjwtYXMubWF0cml4KG1fZGF0YV9yb3cubWVhbikKIwoKbV9kYXRhX2NvbC5yb3cubWVhbjwtcmJpbmQobV9kYXRhX3Jvdy5tZWFuLGNvbC5tZWFuLm1fZGF0YVgpCgptX2RhdGFfY29sLnJvdy5tZWFuPC10KG1fZGF0YV9jb2wucm93Lm1lYW4pCm1fZGF0YV9jb2wucm93Lm1lYW48LWFzLmRhdGEuZnJhbWUobV9kYXRhX2NvbC5yb3cubWVhbikKCm1fZGF0YV9jb2wucm93Lm1lYW48LW1fZGF0YV9jb2wucm93Lm1lYW5bb3JkZXIobV9kYXRhX2NvbC5yb3cubWVhbiRjb2wubWVhbi5tKSxdCm1fZGF0YV9jb2wucm93Lm1lYW4kY29sLm1lYW4ubTwtTlVMTAptX2RhdGFfY29sLnJvdy5tZWFuPC10KG1fZGF0YV9jb2wucm93Lm1lYW4pCgptX2RhdGFfY29sLnJvdy5tZWFuPC1hcy5kYXRhLmZyYW1lKG1fZGF0YV9jb2wucm93Lm1lYW4pCiNkaW0obV9kYXRhX2NvbC5yb3cubWVhbikKI21fZGF0YV9jb2wucm93Lm1lYW4KbV9kYXRhX2NvbC5yb3cubWVhbjwtYXMubWF0cml4KG1fZGF0YV9jb2wucm93Lm1lYW4pCiMgZW5kcwoKCiMjIyMjIFRPUDEwIE9GIEhJR0hFUiBSRUFDVElWSVRZIGluIEJPVEggR1JPVVBTIC0+IHRoZSBzYW1lIGFzIHNvcnQuYnkgQXZlRXhwCiNoZWFkKHJvd25hbWVzKG1fZGF0YV9jb2wucm93Lm1lYW4pLCAxMCkKCiMgW0FEREVEIDI4anVsMjAxNl0KZmVhdHVyZV9zb3J0X21lYW48LXJvd25hbWVzKG1fZGF0YV9jb2wucm93Lm1lYW4pCnNhbXBsZV9zb3J0X21lYW5fRklSU1Q8LWNvbG5hbWVzKG1fZGF0YV9jb2wucm93Lm1lYW4pCiMKcERhdGEoZXNldCkgPC0gY2JpbmQocERhdGEoZXNldCksdChjb2wubWVhbi5tX2RhdGFYKSkjbmNvbChwRGF0YShlc2V0KSkKIwplc2V0IDwtIGVzZXRbZmVhdHVyZV9zb3J0X21lYW4sc2FtcGxlX3NvcnRfbWVhbl9GSVJTVF0gIyMgUkVPUkRFUiBzYW1wbGVzIGFuZCBmZWF0dXJlcyBpbnNpZGUgdGhlIEV4cHJlc3Npb25TZXQKCiNlc2V0JEdyb3VwCmBgYAoKYGBge3IgaGVhdG1hcDExLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQojaGVhZChhbnRpLnJhd19kYXRhKVssMTo1XQojaGVhZChsb2cyLk5BLm5vcm0uQU5USUdFTlMpWywxOjVdCiNoZWFkKGV4cHJzKG5vcm1hbC5sb2cyLnJhdy5lU2V0LlZJVkFYLlNFVi5GSUxURVIpKVssMTo1XQojYW50aS5yYXdfZGF0YQpyYXdobSA8LSBleHByc19wcm90X21bZmVhdHVyZV9zb3J0X21lYW4sc2FtcGxlX3NvcnRfbWVhbl9GSVJTVF0gIyMgUkVPUkRFUiBzYW1wbGVzIGFuZCBmZWF0dXJlcyBpbnNpZGUgdGhlIEV4cHJlc3Npb25TZXQKI2hlYWQocmF3aG0pWywxOjVdCgojbG9nMmhwIDwtIGV4cHJzKG5vcm1hbC5sb2cyLnJhdy5lU2V0LlZJVkFYLlNFVi5GSUxURVIpW2ZlYXR1cmVfc29ydF9tZWFuLHNhbXBsZV9zb3J0X21lYW5fRklSU1RdICMjIFJFT1JERVIgc2FtcGxlcyBhbmQgZmVhdHVyZXMgaW5zaWRlIHRoZSBFeHByZXNzaW9uU2V0CiNzdW0obG9nMmhwPT1leHBycyhlc2V0KSkKI2hlYWQobG9nMmhwKVssMTo1XQojaGVhZChleHBycyhlc2V0KSlbLDE6NV0KI2N0cmwucmF3X2RhdGEKY3RybGhtIDwtIGV4cHJzX2N0cmxfbVssc2FtcGxlX3NvcnRfbWVhbl9GSVJTVF0gIyMgUkVPUkRFUiBzYW1wbGVzIGFuZCBmZWF0dXJlcyBpbnNpZGUgdGhlIEV4cHJlc3Npb25TZXQKI2hlYWQoY3RybGhtKVssMTo1XQoKI2hlYWQobWVkaWFuLmN0cmwucmF3X2RhdGEpWywxOjVdCiNtZWRpYW4uY3RybC5yYXdfZGF0YQpgYGAKCmBgYHtyIGhlYXRtYXAwLCBldmFsPUZBTFNFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89RkFMU0V9CgojX19Tb3J0IGFsbCBieSBNZWFuIFNhbXBsZSBJbnRlbnNpdHlfXwoKI2VzZXQ8LW5vcm1hbC5sb2cyLnJhdy5lU2V0LlZJVkFYLlNFVi5GSUxURVIKI3BEYXRhKGVzZXQpIDwtIHBEYXRhKGVzZXQpWyw5Om5jb2wocERhdGEoZXNldCkpXQojbGlicmFyeShOTUYpCmFoZWF0bWFwKGV4cHJzKGVzZXQpLCBSb3d2ID0gTkEsIENvbHYgPSBOQSwgYW5uQ29sID0gcERhdGEoZXNldCkpCmBgYAoKYGBge3IgYmNrZ3JkMSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgZmlnLmFsaWduPSdjZW50ZXInLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQojIyMjIEJhY2tncm91ZCBlZmZlY3QKI3Jvd25hbWVzKHJvdy5tZWFuLm1fZGF0YSkKUkFXX2RhdGEgPC0gZXhwcnNfcHJvdF9tW3Jvd25hbWVzKHJvdy5tZWFuLm1fZGF0YSksXQpyb3cubWVhbi5SQVdfZGF0YTwtYXMubWF0cml4KGFwcGx5KFJBV19kYXRhLCAxLCBtZWRpYW4sIG5hLnJtPVRSVUUpKQpjb2xuYW1lcyhyb3cubWVhbi5SQVdfZGF0YSkgPC0gYygicm93Lm1lYW4uUkFXIikgICAgICAgICAgICAgICAgICMgYXNzaWduIHJvdyBuYW1lcyAKIwpjb2wubWVhbi5SQVdfZGF0YTwtYXMubWF0cml4KGFwcGx5KFJBV19kYXRhWyxjb2xuYW1lcyhjb2wubWVhbi5tX2RhdGFYKV0sIDIsIG1lZGlhbiwgbmEucm09VFJVRSkpICMjIyBPTkxZIEZPUiA2MCBzYW1wbGVzCmNvbG5hbWVzKGNvbC5tZWFuLlJBV19kYXRhKSA8LSBjKCJjb2wubWVhbi5SQVciKSAgICAgICAgICAgICAgICAgIyBhc3NpZ24gcm93IG5hbWVzIAojCiNoZWFkKHJvdy5tZWFuLlJBV19kYXRhKQojaGVhZChyb3cubWVhbi5tX2RhdGEpCnRvdGludCA8LSBjYmluZChyb3cubWVhbi5tX2RhdGEscm93Lm1lYW4uUkFXX2RhdGEpCnRvdGludCA8LSBhcy5kYXRhLmZyYW1lKHRvdGludCkKY29sbmFtZXModG90aW50KSA8LSBjKCJMT0cyLmZlYXR1cmUubWVhbi5pbnQiLCAiUkFXLmZlYXR1cmUubWVkaWFuLmludCIpCnQxIDwtIGdncGxvdCh0b3RpbnQsIGFlcyh4PUxPRzIuZmVhdHVyZS5tZWFuLmludCx5PVJBVy5mZWF0dXJlLm1lZGlhbi5pbnQpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkKIwpzYW1wbGVpbnQgPC0gY2JpbmQodChjb2wubWVhbi5tX2RhdGFYKSxjb2wubWVhbi5SQVdfZGF0YSkKc2FtcGxlaW50IDwtIGFzLmRhdGEuZnJhbWUoc2FtcGxlaW50KQpjb2xuYW1lcyhzYW1wbGVpbnQpIDwtIGMoIkxPRzIuc2FtcGxlLm1lYW4uaW50IiwgIlJBVy5zYW1wbGUubWVkaWFuLmludCIpCnQyIDwtIGdncGxvdChzYW1wbGVpbnQsIGFlcyh4PUxPRzIuc2FtcGxlLm1lYW4uaW50LHk9UkFXLnNhbXBsZS5tZWRpYW4uaW50KSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpCiMKI2NsYXNzKGNvbC5tZWFuLm1fZGF0YVgpCiNjbGFzcyhtZWRpYW4uY3RybC5yYXdfZGF0YSkgI2V4cHJzX2N0cmxfbQpOby5ETkEuaW50IDwtIHN1YnNldChleHByc19jdHJsX20sIHNlbGVjdD0gY29sbmFtZXMoY29sLm1lYW4ubV9kYXRhWCkpCiNOby5ETkEuaW50CiNjb2wubWVhbi5tX2RhdGFYCmJhY2sgPC0gcmJpbmQoY29sLm1lYW4ubV9kYXRhWCxOby5ETkEuaW50KQpiYWNrIDwtIGFzLmRhdGEuZnJhbWUodChiYWNrKSkKY29sbmFtZXMoYmFjaykgPC0gYygiTE9HMi5zYW1wbGUubWVhbi5pbnQiLCAiUkFXLk5vLkROQS5tZWRpYW4uaW50IikKYjEgPC0gZ2dwbG90KGJhY2ssIGFlcyh4PUxPRzIuc2FtcGxlLm1lYW4uaW50LHk9UkFXLk5vLkROQS5tZWRpYW4uaW50KSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpCiMKcmF3ayA8LSBjYmluZChjb2wubWVhbi5SQVdfZGF0YSx0KE5vLkROQS5pbnQpKQpyYXdrIDwtIGFzLmRhdGEuZnJhbWUocmF3aykKY29sbmFtZXMocmF3aykgPC0gYygiUkFXLnNhbXBsZS5tZWRpYW4uaW50IiwgIlJBVy5Oby5ETkEubWVkaWFuLmludCIpCmIyIDwtIGdncGxvdChyYXdrLCBhZXMoeD1SQVcuc2FtcGxlLm1lZGlhbi5pbnQseT1SQVcuTm8uRE5BLm1lZGlhbi5pbnQpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkKIwojUm1pc2M6Om11bHRpcGxvdCh0MSxiMix0MixiMSwgY29scz0yKQojCmBgYAoKYGBge3IgYmNrZ3JuZDIsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD03LCBmaWcuYWxpZ249J2NlbnRlcicsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9CgojIFJBVyB2cyBMT0cyIEhFQVRNQVAKCnBhcihtZnJvdz1jKDEsMikpCgojIFtTVEFSVCBGUk9NIFRIRSBCRUdJTk5OSU5HXQojZXNldCM8LW5vcm1hbC5sb2cyLnJhdy5lU2V0CiMKZXNldCA8LSBlc2V0W2ZlYXR1cmVfc29ydF9tZWFuLHNhbXBsZV9zb3J0X21lYW5fRklSU1RdICMjIFJFT1JERVIgc2FtcGxlcyBhbmQgZmVhdHVyZXMgaW5zaWRlIHRoZSBFeHByZXNzaW9uU2V0CgphaGVhdG1hcChleHBycyhlc2V0KSwgUm93diA9IE5BLCBDb2x2ID0gTkEsIG1haW4gPSAiTE9HMiIpCmFoZWF0bWFwKHJiaW5kKHJhd2htLGN0cmxobSksIFJvd3YgPSBOQSwgQ29sdiA9IE5BLCBtYWluID0gIlJBVyIpCmBgYAoKYGBge3IgaG9tb3NrMSwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9OCwgZmlnLmFsaWduPSdjZW50ZXInLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQoKIyMjIyBIZXRlcm9za2VkYXN0aWNpdHkgCiMqcHJlLSAmIHBvc3QtIHRyYW5zZm9ybWF0aW9uL25vcm1hbGl6YXRpb24qCgojClJBV19kYXRhIDwtIGV4cHJzX3Byb3RfbVtyb3duYW1lcyhyb3cubWVhbi5tX2RhdGEpLF0Kcm93LnNkLlJBV19kYXRhPC1hcy5tYXRyaXgoYXBwbHkoUkFXX2RhdGEsIDEsIHNkLCBuYS5ybT1UUlVFKSkKY29sbmFtZXMocm93LnNkLlJBV19kYXRhKSA8LSBjKCJyb3cubWVhbi5SQVciKSAgICAgICAgICAgICAgICAgIyBhc3NpZ24gcm93IG5hbWVzIAojCmhvbW9za1JBVyA8LSBjYmluZChyb3cubWVhbi5SQVdfZGF0YSxyb3cuc2QuUkFXX2RhdGEpCmhvbW9za1JBVyA8LSBhcy5kYXRhLmZyYW1lKGhvbW9za1JBVykKY29sbmFtZXMoaG9tb3NrUkFXKSA8LSBjKCJSQVcuZmVhdHVyZS5tZWRpYW4uaW50IiwiUkFXLmZlYXR1cmUuc2QuaW50IikKaDIgPC0gZ2dwbG90KGhvbW9za1JBVywgYWVzKHg9UkFXLmZlYXR1cmUubWVkaWFuLmludCx5PVJBVy5mZWF0dXJlLnNkLmludCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKQojCnJvdy5zZC5tX2RhdGE8LWFzLm1hdHJpeChhcHBseShtX2RhdGEsIDEsIHNkLCBuYS5ybT1UUlVFKSkKY29sbmFtZXMocm93LnNkLm1fZGF0YSkgPC0gYygicm93LnNkLm0iKSAgICAgICAgICAgICAgICAgIyBhc3NpZ24gcm93IG5hbWVzIAojCmhvbW9zayA8LSBjYmluZChyb3cubWVhbi5tX2RhdGEscm93LnNkLm1fZGF0YSkKaG9tb3NrIDwtIGFzLmRhdGEuZnJhbWUoaG9tb3NrKQpjb2xuYW1lcyhob21vc2spIDwtIGMoIkxPRzIuZmVhdHVyZS5tZWFuLmludCIsICJMT0cyLmZlYXR1cmUuc2QuaW50IikKaDEgPC0gZ2dwbG90KGhvbW9zaywgYWVzKHg9TE9HMi5mZWF0dXJlLm1lYW4uaW50LHk9TE9HMi5mZWF0dXJlLnNkLmludCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSNtZXRob2Q9ImxtIixzZT1GQUxTRQojClJtaXNjOjptdWx0aXBsb3QoaDIsaDEsY29scz0yKQpgYGAKCiMjIyBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbgoKIyMjIyBEZWZpbmUgdGhlIGNvbnRyb2wgZ3JvdXAKCi0gRWwgcHJvYmxlbSBkZWZpbiBhbCBncnVwbyBkZSBzaW50b23DoXRpY29zIGNvbW8gZWwgZ3J1cG8gY29udHJvbC4KCmBgYHtyfQplc2V0JHBoZW5vdHlwZSA8LSBmYWN0b3IoZXNldCRwaGVub3R5cGUpCgp0YWJsZShlc2V0JHBoZW5vdHlwZSkgIyBkZWJlIHNlcjogY29udHJvbCAoZmN0IHJlZmVyZW5jaWEpIHZzIGNhc28KZXNldCRwaGVub3R5cGUgPC0gcmVsZXZlbChlc2V0JHBoZW5vdHlwZSwgcmVmID0gIlN5bXB0b21hdGljIikKdGFibGUoZXNldCRwaGVub3R5cGUpICMgZGViZSBzZXI6IGNvbnRyb2wgKGZjdCByZWZlcmVuY2lhKSB2cyBjYXNvCmBgYAoKIyMjIyBNYXRyaXggKyBMaW5lYXIgbW9kZWwgKyBlQmF5ZXMKCmBgYHtyfQpkZXNpZ24gPC0gbW9kZWwubWF0cml4KH4gZXNldCRwaGVub3R5cGUpCmZpdCA8LSBsbUZpdChlc2V0LCBkZXNpZ24pCmViIDwtIGVCYXllcyhmaXQpCnRvcFRhYmxlKGViKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkKYGBgCgpgYGB7cn0KIyB0aWR5IHRvcHRhYmxlCnRkIDwtIHRvcFRhYmxlKGViLCBjb2VmID0gMiwgICAgICAgICAgICAgICAjIGRlZmF1bHQ6IHNsb3BlCiAgICAgICAgIHNvcnQuYnkgPU5VTEwsIHJlc29ydC5ieSA9TlVMTCwgCiAgICAgICAgICNnZW5lbGlzdCA9IE5VTEwsICAgICAgICAgICAgICAgICAjIG5vIGZpdCRnZW5lCiAgICAgICAgIG51bWJlciA9IEluZiwgICAgICAgICAgICAgICAgICAgICAjIHNob3cgYWxsIHRoZSBoaXBvdGhlc2lzCiAgICAgICAgIGNvbmZpbnQ9MC45NSkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSBhcy50YmwoKSAlPiUgCiAgZHBseXI6OnJlbmFtZShHZW5lLklEPXJvd25hbWUpCmBgYAoKIyMjIFByb2JsZW1hcyBlc3BlY8OtZmljb3MKCi0gRGVjaXNpw7NuIGVzdGFkw61zdGljYSBjYW1iaWE6CiAgICArIG1pY3JvYXJyZWdsb3MgZGUgRE5BIC0+IHZhcmlhY2nDs24gdy5yLnQuIF9ob3VzZWtlZXBpbmdfIGdlbmUKICAgICsgbWljcm9hcnJlZ2xvIGRlIHByb3Rlw61uYXMgLT4gdmVjZXMgc29icmUgY29udHJvbCAoYmxhbmNvKSAtPiBpbnRlbnNpZGFkIGZpbmFsIGVzIHJlbGV2YW50ZQoKIyMjIFBsb3RzCgpgYGB7ciwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KCiMjIyMgdmFyaWFuY2Ugc2hyaW5rYWdlCgpwYXIobWZyb3c9YygxLDIpKQpwbG90KGViJEFtZWFuLCBlYiRzaWdtYSkKcGxvdChlYiRBbWVhbiwgZWIkczIucG9zdCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KeCA8LSBlYiAlPiUgYmlvYnJvb206OmF1Z21lbnQuTUFycmF5TE0oKSAlPiUgIyMgRVJST1IgaW4gZnVuY3Rpb24hISBzMi5wcmlvciEhCiAgaW5uZXJfam9pbigKICAgIGlubmVyX2pvaW4oZWIkQW1lYW4gJT4lIAogICAgICAgICAgICAgICBhcy50aWJibGUoKSAlPiUgCiAgICAgICAgICAgICAgIHRpYmJsZTo6cm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogICAgICAgICAgICAgICBkcGx5cjo6cmVuYW1lKC5BTWVhbj12YWx1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZ2VuZT1yb3duYW1lKSwKICAgICAgICAgICAgICAgZWIkczIucG9zdCAlPiUgCiAgICAgICAgICAgICAgIGFzLnRpYmJsZSgpICU+JSAKICAgICAgICAgICAgICAgdGliYmxlOjpyb3duYW1lc190b19jb2x1bW4oKSAlPiUgCiAgICAgICAgICAgICAgIGRwbHlyOjpyZW5hbWUoczIucG9zdD12YWx1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZ2VuZT1yb3duYW1lKSwKICAgICAgICAgICAgICAgYnk9Ii5nZW5lIiksCiAgICAgICAgICAgICBieT0iLmdlbmUiKSAKCm0gPC0geCAlPiUgCiAgZ2dwbG90KGFlcyguQU1lYW4sLnNpZ21hKSkrCiAgZ2VvbV9oZXgoKStzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4yLDMpKQogICNnZW9tX2RlbnNpdHkyZCgpCgpuIDwtIHggJT4lIAogIGdncGxvdChhZXMoLkFNZWFuLHMyLnBvc3QpKSsKICBnZW9tX2hleCgpK3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjIsMykpCiAgI2dlb21fZGVuc2l0eTJkKCkjCgpvIDwtIHggJT4lIAogIGdncGxvdChhZXMoLkFNZWFuLC5zaWdtYSkpKwogICNnZW9tX2hleCgpK3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjIsOSkpCiAgZ2VvbV9kZW5zaXR5MmQoKSMrCiAgI3NjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0wLjA1LDAuNykpKwogICNzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4wNSwxNSkpCgpwIDwtIHggJT4lIAogIGdncGxvdChhZXMoLkFNZWFuLHMyLnBvc3QpKSsKICAjZ2VvbV9oZXgoKQogIGdlb21fZGVuc2l0eTJkKCkjKwogICNzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4wNSwwLjcpKSsKICAjc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoLTAuMDUsMTUpKQoKUm1pc2M6Om11bHRpcGxvdChtLG4sbyxwLGNvbHMgPSAyKQpgYGAKCgoKIyMjIyBwLXZhbHVlIGhpc3RvZ3JhbQoKYGBge3IsIGVjaG89RkFMU0V9CnRlc3QgPC0gdG9wVGFibGUoZWIsIGNvZWYgPSAyLAogICAgICAgICAgICAgICAgIHNvcnQuYnkgPSJQIiwgCiAgICAgICAgICAgICAgICAgI3NvcnQuYnkgPSJBdmVFeHByIiwgCiAgICAgICAgICAgICAgICAgZ2VuZWxpc3QgPSBmaXQkZ2VuZXMkR2VuZS5JRCwgbnVtYmVyID0gSW5mKQpsaWJyYXJ5KGdncGxvdDIpCmF4IDwtIHFwbG90KHRlc3QkUC5WYWx1ZSwgYmlud2lkdGg9LjA1KQpieCA8LSBxcGxvdCh0ZXN0JGFkai5QLlZhbCwgYmlud2lkdGg9LjA1KQpSbWlzYzo6bXVsdGlwbG90KGF4LGJ4LGNvbHMgPSAyKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89RkFMU0V9CgojIyMjIGJhc2UgUiB2b2xjYW5vIHBsb3QKCiMgKDIpIFZvbGNhbm8gcGxvdDogTG9nIEZvbGQgQ2hhbmdlIHggLWxvZzEwKHAudmFsdWUpCiNzb3VyY2U6IGh0dHA6Ly9nZW5vbWljc2NsYXNzLmdpdGh1Yi5pby9ib29rL3BhZ2VzL3VzaW5nX2xpbW1hLmh0bWwKCiMKcGFyKG1mcm93PWMoMSwyKSkKd2l0aCh0ZCwgcGxvdChsb2dGQywgLWxvZzEwKFAuVmFsdWUpLGNleD0uNywgcGNoPTIwLAogICAgICAgICAgICAgICAgICAgIG1haW4gPSAiY2FzbyB2cyBjb250cm9sIiwKICAgICAgICAgICAgICAgICAgICAjY29sPWNvbHMsCiAgICAgICAgICAgICAgICAgICAgI3hsaW09YygtMiwyKSwgeWxpbT1jKDAsMTUpLAogICAgICAgICAgICAgICAgICAgIHhsYWI9ImxvZyBGb2xkIENoYW5nZSIpKQphYmxpbmUoaD1jKC1sb2cxMCgwLjA1KSwtbG9nMTAoMWUtMTMpKSwKICAgICAgIHY9YygtMSwxKSwKICAgICAgIGx0eT0yLCBjb2w9ICJncmV5NTUiKQpgYGAKCgojIyMjIHZvbGNhbm8gcGxvdAoKLSBPQkpFVElWTzoKICAgICsgUHJpb3JpemFyIGVsIF9fVGFtYcOxbyBkZWwgRWZlY3RvX18gcG9yIGxhIF9fc2lnbmlmaWNhbmNpYSBlc3RhZMOtc3Rpc3RpY2FfXy4KCmBgYHtyLCBldmFsPVRSVUUsIGVjaG89RkFMU0V9CiMjIyMgaGVhdG1hcCArIGhpZXJhY2hpY2FsIGNsdXN0ZXJpbmcKZXNldCA8LSBFeHByZXNzaW9uU2V0KGFzc2F5RGF0YSA9IGV4cHJzX25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgcGhlbm9EYXRhID0gcGhlbm9fZCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9Ni41LCBlY2hvPVRSVUV9CiMgKDIpIFZvbGNhbm8gcGxvdDogTG9nIEZvbGQgQ2hhbmdlIHggLWxvZzEwKHAudmFsdWUpCgp0diA8LSB0ZCAlPiUgCiAgaW5uZXJfam9pbihiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKSAlPiUgI2NvdW50KGdlbmUpCiAgICAgICAgICAgICAgIGdyb3VwX2J5KGdlbmUscGhlbm90eXBlKSAlPiUgc3VtbWFyaXNlKG1lYW5fZ3JvdXA9bWVhbih2YWx1ZSkpICU+JSAKICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JSAKICAgICAgICAgICAgICAgc3ByZWFkKHBoZW5vdHlwZSxtZWFuX2dyb3VwKSAlPiUgCiAgICAgICAgICAgICAgICNhcnJhbmdlKGRlc2MoQXN5bXB0b21hdGljKSkgJT4lIAogICAgICAgICAgICAgICByZW5hbWUoR2VuZS5JRD1nZW5lKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgCgp0diAlPiUgCiAgbXV0YXRlKHNpZ25pZmljYW5jZT1pZl9lbHNlKGFkai5QLlZhbDwwLjA1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYWRqLlAuVmFsPDAuMDUiLCJkaWZmIHJ2ZSIpKSAlPiUgCiAgZ2dwbG90KGFlcyhsb2dGQywtbG9nMTAoUC5WYWx1ZSkpKSArCiAgI2dlb21fcG9pbnQoYWVzKGNvbG91cj1zaWduaWZpY2FuY2UpKSArIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygicmVkIiwiYmxhY2siKSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91cj1Bc3ltcHRvbWF0aWMpKSArIHZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMoKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGEgPSB0diAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGFkai5QLlZhbDwwLjA1ICYgbG9nRkM+MS41ICYgQXN5bXB0b21hdGljPjEpIyAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI2FycmFuZ2UoZGVzYyhBc3ltcHRvbWF0aWMpKSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI3RvcF9uKDEwLEFzeW1wdG9tYXRpYykKICAgICAgICAgICAgICAgICAgICAgICAgICAgLAogICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMobGFiZWw9R2VuZS5JRCkpICsKICBsYWJzKHRpdGxlPSJNYWxhcmlhIFByb3RlaW4gbWljcm9hcnJheSIsCiAgICAgICBzdWJ0aXRsZT0iQ2FzbyB2cyBDb250cm9sIikrCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0tbG9nMTAoMC4wMSkpLCBsdHk9MykrCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD0xKSwgbHR5PTMpCmBgYAoKIyMjIGRpZmYgcmVhY3RpdmUKCiMjIyMgYm94cGxvdAoKYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9NiwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KI3JlcHJvCiMgI3N0cigpCiMgIG11dGF0ZShvcmRlcj1zZXEoZnJvbT1uKCksdG89MSkpIAoKYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lCiAgaW5uZXJfam9pbih0diAlPiUgCiAgICAgICAgICAgICAgIGZpbHRlcihhZGouUC5WYWw8MC4wNSAmIGxvZ0ZDPjEgJiBBc3ltcHRvbWF0aWM+MSkgJT4lIAogICAgICAgICAgICAgICByZW5hbWUoZ2VuZT0iR2VuZS5JRCIpCiAgICAsYnk9ImdlbmUiKSAlPiUgCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGdlbmUsbG9nRkMpLHZhbHVlLGZpbGw9cGhlbm90eXBlKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgI2dlb21fcG9pbnQoKSArCiAgeWxhYigibG9nMi10cmFuc2Zvcm1lZCBub3JtYWxpemVkIE1GSSIpKwogIHhsYWIoImFudGlnZW5zIikrCiAgbGFicyh0aXRsZT0iRGlmZmVyZW50aWFsbHkgcmVhY3RpdmUgYW50aWdlbnMiLAogICAgICAgc3VidGl0bGU9ImZpbHRlcmVkIGJ5IGFkai5QLlZhbHVlPDAuMDUgYW5kIGxvZ0ZDPjEgc29ydGVkIHcuci50LiBGb2xkIENoYW5nZSIpKwogIGNvb3JkX2ZsaXAoKSAjIE9SREVOQVIgZWplIGRlIHByb3Rlw61uYXMhISEhCmBgYAoKYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9NiwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KI3JlcHJvCiMgI3N0cigpCiMgIG11dGF0ZShvcmRlcj1zZXEoZnJvbT1uKCksdG89MSkpIAoKYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lCiAgaW5uZXJfam9pbih0diAlPiUgCiAgICAgICAgICAgICAgIGZpbHRlcihhZGouUC5WYWw8MC4wNSAmIGxvZ0ZDPjEgJiBBc3ltcHRvbWF0aWM+MSkgJT4lIAogICAgICAgICAgICAgICByZW5hbWUoZ2VuZT0iR2VuZS5JRCIpCiAgICAsYnk9ImdlbmUiKSAlPiUgCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGdlbmUsQXN5bXB0b21hdGljKSx2YWx1ZSxmaWxsPXBoZW5vdHlwZSkpKwogIGdlb21fYm94cGxvdCgpKwogICNnZW9tX3BvaW50KCkgKwogIHlsYWIoImxvZzItdHJhbnNmb3JtZWQgbm9ybWFsaXplZCBNRkkiKSsKICB4bGFiKCJhbnRpZ2VucyIpKwogIGxhYnModGl0bGU9IkRpZmZlcmVudGlhbGx5IHJlYWN0aXZlIGFudGlnZW5zIiwKICAgICAgIHN1YnRpdGxlPSJmaWx0ZXJlZCBieSBhZGouUC5WYWx1ZTwwLjA1IGFuZCBsb2dGQz4xIHNvcnRlZCB3LnIudC4gQXN5bXB0b21hdGljIG1lZGlhbiBBYiByZWFjdGl2aXR5IikrCiAgY29vcmRfZmxpcCgpICMgT1JERU5BUiBlamUgZGUgcHJvdGXDrW5hcyEhISEKYGBgCgojIyMjIGxpc3QKCmBgYHtyfQp0diAlPiUgCiAgZmlsdGVyKGFkai5QLlZhbDwwLjA1ICYgbG9nRkM+MSAmIEFzeW1wdG9tYXRpYz4xKSAlPiUgCiAgYXJyYW5nZShkZXNjKEFzeW1wdG9tYXRpYykpICU+JSAKICBzZWxlY3QoR2VuZS5JRCkgJT4lIAogIGlubmVyX2pvaW4obG4sIGJ5PSJHZW5lLklEIikgJT4lIAogIGlubmVyX2pvaW4oYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogICAgICAgICAgICAgICBncm91cF9ieShnZW5lLHBoZW5vdHlwZSkgJT4lIHN1bW1hcmlzZShtZWFuX2dyb3VwPW1lYW4odmFsdWUpKSAlPiUgCiAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAgICAgICAgICAgIHNwcmVhZChwaGVub3R5cGUsbWVhbl9ncm91cCkgJT4lIAogICAgICAgICAgICAgICByZW5hbWUoR2VuZS5JRD1nZW5lKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgJT4lIAogIGlubmVyX2pvaW4odGQgJT4lIAogICAgICAgICAgICAgICBhcnJhbmdlKGRlc2ModCkpICU+JSAKICAgICAgICAgICAgICAgbXV0YXRlKHQub3JkZXI9c2VxKG4oKSkpICU+JSAKICAgICAgICAgICAgICAgc2VsZWN0KEdlbmUuSUQsQXZlRXhwcixQLlZhbHVlLGFkai5QLlZhbCx0Lm9yZGVyKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgIyU+JSBzbGljZSgxOjEwKQpgYGAKCgoKIyMjIHRvcCByZWFjdGl2ZQoKLSBFbCBncnVwbyBkZSBhbnTDrWdlbm9zIGNvbiBtYXlvciByZWFjdGl2aWRhZCBwZXJtaXRpcsOhIGRhcmxlIHVuYSBjb250ZXh0byBiaW9sw7NnaWNvIGEgbG9zIHZhbG9yZXMgY29uIHNpZ25pZmljYW5jaWEgZXN0YWTDrXN0aWNhLgoKYGBge3IsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0KIyMjIyBoZWF0bWFwCmVzZXQgPC0gRXhwcmVzc2lvblNldChhc3NheURhdGEgPSBleHByc19ub3JtLCAKICAgICAgICAgICAgICAgICAgICAgIHBoZW5vRGF0YSA9IHBoZW5vX2QpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89RkFMU0V9CiNlc2V0IDwtIGVzZXQjbGV1a2VtaWFzRXNldAojZXhwcnMoZXNldCkgJT4lIGRpbSgpCnggPC0gdGQgJT4lIAogICNhcnJhbmdlKGRlc2ModCkpICU+JSAKICBhcnJhbmdlKGRlc2MoQXZlRXhwcikpICU+JSAKICAjZmlsdGVyKEI+MCAjJiBhZGouUC5WYWw8MWUtNAogICMgICAgICAgKSAlPiUgCiAgdG9wX24oMTAsQXZlRXhwcikgJT4lIAogIHNlbGVjdChHZW5lLklEKSAlPiUgYXMubWF0cml4KCkgCiN4ICU+JSBkaW0oKQoKcERhdGEoZXNldCkgPC0gYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSkgJT4lIHN1bW1hcmlzZShzYW1wbGVfbWVkaWFuPW1lZGlhbih2YWx1ZSkpICU+JSAKICBmdWxsX2pvaW4ocERhdGEoZXNldCkgJT4lIAogICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICAgICAgICAgICAgICByZW5hbWUoc2FtcGxlPXJvd25hbWUpLAogICAgICAgICAgICBieT0ic2FtcGxlIikgJT4lIAogIGFycmFuZ2UocGhlbm90eXBlLHNhbXBsZV9tZWRpYW4pICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0ic2FtcGxlIikKCnkgPC0gcERhdGEoZXNldCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICBzZWxlY3Qocm93bmFtZSkgJT4lIGFzLm1hdHJpeCgpICU+JSBhcy5jaGFyYWN0ZXIoKQoKZXNldCA8LSBlc2V0W3gseV0KCiNhaGVhdG1hcChleHBycyhlc2V0KVt4LF0sIAojICAgICAgICAgUm93diA9IE5BLCBDb2x2ID0gTkEsIAojICAgICAgICAgYW5uQ29sID0gcERhdGEoZXNldCksIAojICAgICAgICAgbGF5b3V0ID0gIl8iKQpgYGAKCiMjIyMgYm94cGxvdHMKCi0gc2hvdyB0aGUgaW50ZW5zaXR5IGRpc3RyaWJ1dGlvbnMgb2Ygc2VsZWN0ZWQgZmVhdHVyZXMgaW4gYm90aCBncm91cHMuCgpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0yLjUsIGVjaG89RkFMU0UsIGV2YWw9RkFMU0V9CiNyZXBybwpiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKSAlPiUgI3N0cigpCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGdlbmUsdmFsdWUsb3JkZXIgPSBUUlVFKSx2YWx1ZSxmaWxsPXBoZW5vdHlwZSkpKwogIGdlb21fYm94cGxvdCgpKwogICNnZW9tX3BvaW50KCkgKwogIHlsYWIoImxvZzItdHJhbnNmb3JtZWQgbm9ybWFsaXplZCBNRkkiKSsKICB4bGFiKCJhbnRpZ2VucyIpKwogIGxhYnModGl0bGU9IkhpZ2hseSByZWFjdGl2ZSBhbnRpZ2VucyIsCiAgICAgICBzdWJ0aXRsZT0idG9wIDEwIHNvcnRlZCB3LnIudC4gbWVkaWFuIEFiIHJlYWN0aXZpdHkiKSsKICBjb29yZF9mbGlwKCkgIyBPUkRFTkFSIGVqZSBkZSBwcm90ZcOtbmFzISEhIQpgYGAKCiMjIyMgbGlzdAoKYGBge3IsIGVjaG89RkFMU0V9CnggJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKEdlbmUuSUQ9YXMuY2hhcmFjdGVyKEdlbmUuSUQpKSAlPiUgCiAgaW5uZXJfam9pbihsbiwgYnk9IkdlbmUuSUQiKSAlPiUgCiAgaW5uZXJfam9pbihiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKSAlPiUgCiAgICAgICAgICAgICAgIGdyb3VwX2J5KGdlbmUscGhlbm90eXBlKSAlPiUgc3VtbWFyaXNlKG1lYW5fZ3JvdXA9bWVhbih2YWx1ZSkpICU+JSAKICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JSAKICAgICAgICAgICAgICAgc3ByZWFkKHBoZW5vdHlwZSxtZWFuX2dyb3VwKSAlPiUgCiAgICAgICAgICAgICAgIHJlbmFtZShHZW5lLklEPWdlbmUpLAogICAgICAgICAgICAgYnk9IkdlbmUuSUQiKSAlPiUgCiAgaW5uZXJfam9pbih0ZCAlPiUgCiAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyh0KSkgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodC5vcmRlcj1zZXEobigpKSkgJT4lIAogICAgICAgICAgICAgICBzZWxlY3QoR2VuZS5JRCxBdmVFeHByLFAuVmFsdWUsYWRqLlAuVmFsLHQub3JkZXIpLAogICAgICAgICAgICAgYnk9IkdlbmUuSUQiKSAjJT4lIHNsaWNlKDE6MTApCmBgYAoKIyMjIGJvdGgKCiMjIyMgaGVhdG1hcAoKYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTYsIGZpZy5hbGlnbj0iY2VudGVyIn0KZXNldCA8LSBFeHByZXNzaW9uU2V0KGFzc2F5RGF0YSA9IGV4cHJzX25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgcGhlbm9EYXRhID0gcGhlbm9fZCkKCnMgPC0gdHYgJT4lIAogIGZpbHRlcihhZGouUC5WYWw8MC4wNSAmIGxvZ0ZDPjEgJiBBc3ltcHRvbWF0aWM+MSkgJT4lIAogIGFycmFuZ2UoZGVzYyhBc3ltcHRvbWF0aWMpKSAlPiUgCiAgc2VsZWN0KEdlbmUuSUQpICU+JSBhcy5tYXRyaXgoKSAKCnggPC0gdHYgJT4lIAogICNhcnJhbmdlKGRlc2ModCkpICU+JSAKICBhcnJhbmdlKGRlc2MoQXZlRXhwcikpICU+JSAKICAjZmlsdGVyKEI+MCAjJiBhZGouUC5WYWw8MWUtNAogICMgICAgICAgKSAlPiUgCiAgdG9wX24oMTAsQXZlRXhwcikgJT4lIAogIGFycmFuZ2UoZGVzYyhBc3ltcHRvbWF0aWMpKSAlPiUgIyBJZiBkaWZmIG9yZGVyIGF0IGJveHBsb3QgaXMgYWNoaWV2ZWQsIHRoZSBkZWFjdGl2YXRlIHRoaXMgbGluZS4KICBzZWxlY3QoR2VuZS5JRCkgJT4lIGFzLm1hdHJpeCgpIAoKcERhdGEoZXNldCkgPC0gYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSkgJT4lIHN1bW1hcmlzZShzYW1wbGVfbWVkaWFuPW1lZGlhbih2YWx1ZSkpICU+JSAKICBmdWxsX2pvaW4ocERhdGEoZXNldCkgJT4lIAogICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICAgICAgICAgICAgICByZW5hbWUoc2FtcGxlPXJvd25hbWUpLAogICAgICAgICAgICBieT0ic2FtcGxlIikgJT4lIAogIGFycmFuZ2UocGhlbm90eXBlLHNhbXBsZV9tZWRpYW4pICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0ic2FtcGxlIikKCnkgPC0gcERhdGEoZXNldCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICBzZWxlY3Qocm93bmFtZSkgJT4lIGFzLm1hdHJpeCgpICU+JSBhcy5jaGFyYWN0ZXIoKQoKZXNldCA8LSBlc2V0W2MoeCxzKSx5XQoKYWhlYXRtYXAoZXhwcnMoZXNldCksIAogICAgICAgICBSb3d2ID0gTkEsIENvbHYgPSBOQSwgCiAgICAgICAgIGFubkNvbCA9IHBEYXRhKGVzZXQpLCAKICAgICAgICAgbGF5b3V0ID0gIl8iKQpgYGAKCiMjIyMgYm94cGxvdAoKYGBge3IsIGZpZy53aWR0aD02LGZpZy5oZWlnaHQ9Ny41LCBlY2hvPVRSVUV9CiNyZXBybwpiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKSAlPiUgI2NvdW50KGdlbmUpCiAgZnVsbF9qb2luKGJpb2Jyb29tOjp0aWR5LkV4cHJlc3Npb25TZXQoZXNldCxhZGRQaGVubyA9IFRSVUUpICU+JSAjY291bnQoZ2VuZSkKICAgICAgICAgICAgICBncm91cF9ieShnZW5lLHBoZW5vdHlwZSkgJT4lIHN1bW1hcmlzZShtZWFuX2dyb3VwPW1lYW4odmFsdWUpKSAlPiUgCiAgICAgICAgICAgICAgdW5ncm91cCgpICU+JSAKICAgICAgICAgICAgICBzcHJlYWQocGhlbm90eXBlLG1lYW5fZ3JvdXApICU+JSAKICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoQXN5bXB0b21hdGljKSkgJT4lIAogICAgICAgICAgICAgIHNlbGVjdCgtU3ltcHRvbWF0aWMpLAogICAgICAgICAgICBieT0iZ2VuZSIpICU+JSAKICBmdWxsX2pvaW4oeCAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICAgICAgICAgICAgICBtdXRhdGUoZ3JvdXA9IlRvcCAxMCIpICU+JSAKICAgICAgICAgICAgICByZW5hbWUoZ2VuZT0iR2VuZS5JRCIpICU+JSAKICAgICAgICAgICAgICBtdXRhdGUoZ2VuZT1hcy5jaGFyYWN0ZXIoZ2VuZSkpLAogICAgICAgICAgICBieT0iZ2VuZSIpICU+JSAKICBmdWxsX2pvaW4ocyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSAKICAgICAgICAgICAgICBtdXRhdGUoZ3JvdXA9IkRpZmZlcmVudGlhbGx5KiIpICU+JSAKICAgICAgICAgICAgICByZW5hbWUoZ2VuZT0iR2VuZS5JRCIpICU+JSAKICAgICAgICAgICAgICBtdXRhdGUoZ2VuZT1hcy5jaGFyYWN0ZXIoZ2VuZSkpLAogICAgICAgICAgICBieT0iZ2VuZSIpICU+JSAKICB1bml0ZShncm91cCwgZ3JvdXAueCwgZ3JvdXAueSkgJT4lIAogIG11dGF0ZShncm91cD1zdHJpbmdyOjpzdHJfcmVwbGFjZShncm91cCwiTkFfKC4pIiwgIlxcMSIpKSAlPiUgCiAgbXV0YXRlKGdyb3VwPXN0cmluZ3I6OnN0cl9yZXBsYWNlKGdyb3VwLCIoLilfTkEiLCAiXFwxIikpICU+JSAKICBtdXRhdGUoZ3JvdXA9Zm9yY2F0czo6ZmN0X3JlbGV2ZWwoZ3JvdXAsIlRvcCAxMCIpKSAlPiUgCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGdlbmUsQXN5bXB0b21hdGljKSx2YWx1ZSxmaWxsPXBoZW5vdHlwZSkpKwogIGdlb21fYm94cGxvdCgpKwogICNnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQoZ3JvdXB+LixzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiKSArIwogIHlsYWIoImxvZzItdHJhbnNmb3JtZWQgbm9ybWFsaXplZCBNRkkiKSsKICB4bGFiKCJhbnRpZ2VucyIpKwogIGxhYnModGl0bGU9IkhpZ2hseSBhbmQgZGlmZmVyZW50aWFsbHkgcmVhY3RpdmUgYW50aWdlbnMiLAogICAgICAgc3VidGl0bGU9IkFsbCBzb3J0ZWQgdy5yLnQuIEFzeW1wdG9tYXRpYyBtZWFuIEFiIHJlYWN0aXZpdHkiLAogICAgICAgY2FwdGlvbj0iKmZpbHRlcmVkIGJ5IGFkai5QLlZhbDwwLjA1IGFuZCBsb2dGQz4xIikrCiAgY29vcmRfZmxpcCgpICMgT1JERU5BUiBlamUgZGUgcHJvdGXDrW5hcyEhISEKYGBgCgojIyMgZGlmZiByZWFjdGl2ZSAocGFwZXIpCgotIExvcyBhdXRvcmVzIHJlcG9ydGFuIHRvZG9zIGxvcyBhbnTDrWdlbm9zIGNvbiBfX3ZhbG9yIHAgYWp1c3RhZG8gbWVub3IgYSAwLjA1X18KLSBEYWRhIGxhIHZhcmlhYmlsaWRhZCBlbnRyZSBsYXMgbXVlc3RyYXMgcG9yIGdydXBvLCB1biBhbGdvcml0bW8gZGUgY2xhc2lmaWNhY2nDs24gbm8gZXMgbGEgZXN0cmF0ZWdpYSBtw6FzIGFkZWN1YWRhLgoKIyMjIyBoZWF0bWFwCgpgYGB7ciwgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQojIyMjIGhlYXRtYXAgKyBoaWVyYWNoaWNhbCBjbHVzdGVyaW5nCmVzZXQgPC0gRXhwcmVzc2lvblNldChhc3NheURhdGEgPSBleHByc19ub3JtLCAKICAgICAgICAgICAgICAgICAgICAgIHBoZW5vRGF0YSA9IHBoZW5vX2QpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCBmaWcuYWxpZ249ImNlbnRlciIsIGV2YWw9VFJVRSwgZWNobz1GQUxTRX0KeCA8LSB0ZCAlPiUgCiAgI2FycmFuZ2UoZGVzYyh0KSkgJT4lIAogICNhcnJhbmdlKGRlc2MoQXZlRXhwcikpICU+JSAKICBmaWx0ZXIoYWRqLlAuVmFsPDAuMDUjQj4wICMmIGFkai5QLlZhbDwxZS00CiAgICAgICAgICkgJT4lIAogIGlubmVyX2pvaW4oYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogICAgICAgICAgICAgICBncm91cF9ieShnZW5lLHBoZW5vdHlwZSkgJT4lIHN1bW1hcmlzZShtZWFuX2dyb3VwPW1lYW4odmFsdWUpKSAlPiUgCiAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAgICAgICAgICAgIHNwcmVhZChwaGVub3R5cGUsbWVhbl9ncm91cCkgJT4lIAogICAgICAgICAgICAgICBhcnJhbmdlKGRlc2MoQXN5bXB0b21hdGljKSkgJT4lIAogICAgICAgICAgICAgICByZW5hbWUoR2VuZS5JRD1nZW5lKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgJT4lIAogIGFycmFuZ2UoZGVzYyhBc3ltcHRvbWF0aWMpKSAlPiUgCiAgZmlsdGVyKFN5bXB0b21hdGljPjApICU+JSAjdG9wX24oMzAsQXN5bXB0b21hdGljKQogIHNlbGVjdChHZW5lLklEKSAlPiUgYXMubWF0cml4KCkgCiN4ICU+JSBkaW0oKQoKcERhdGEoZXNldCkgPC0gYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSkgJT4lIHN1bW1hcmlzZShzYW1wbGVfbWVkaWFuPW1lZGlhbih2YWx1ZSkpICU+JSAKICBmdWxsX2pvaW4ocERhdGEoZXNldCkgJT4lIAogICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICAgICAgICAgICAgICByZW5hbWUoc2FtcGxlPXJvd25hbWUpLAogICAgICAgICAgICBieT0ic2FtcGxlIikgJT4lIAogIGFycmFuZ2UocGhlbm90eXBlLHNhbXBsZV9tZWRpYW4pICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0ic2FtcGxlIikKCnkgPC0gcERhdGEoZXNldCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICBzZWxlY3Qocm93bmFtZSkgJT4lIGFzLm1hdHJpeCgpICU+JSBhcy5jaGFyYWN0ZXIoKQoKZXNldCA8LSBlc2V0W3gseV0KCiNhaGVhdG1hcChleHBycyhlc2V0KVt4LF0sIAojICAgICAgICAgUm93diA9IFRSVUUsIENvbHYgPSBOQSwgCiMgICAgICAgICBhbm5Db2wgPSBwRGF0YShlc2V0KSwgCiMgICAgICAgICBsYXlvdXQgPSAiXyIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9NSwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0KIyMjIyBib3hwbG90cwojLSBzaG93IHRoZSBpbnRlbnNpdHkgZGlzdHJpYnV0aW9ucyBvZiBzZWxlY3RlZCBmZWF0dXJlcyBpbiBib3RoIGdyb3Vwcy4KCiMgwr9IT1cgVE8gRVhUUkFDVCBIRSBDTFVTVEVSSU5HIE9SREVSPwoKI3JlcHJvCmJpb2Jyb29tOjp0aWR5LkV4cHJlc3Npb25TZXQoZXNldCxhZGRQaGVubyA9IFRSVUUpICU+JSAjc3RyKCkKICBnZ3Bsb3QoYWVzKHJlb3JkZXIoZ2VuZSx2YWx1ZSxvcmRlciA9IFRSVUUpLHZhbHVlLGZpbGw9cGhlbm90eXBlKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgI2dlb21fcG9pbnQoKSArCiAgeWxhYigibG9nMi10cmFuc2Zvcm1lZCBub3JtYWxpemVkIE1GSSIpKwogIHhsYWIoImFudGlnZW5zIikrCiAgbGFicyh0aXRsZT0iRGlmZmVyZW50aWFsbHkgcmVhY3RpdmUgYW50aWdlbnMiLAogICAgICAgc3VidGl0bGU9ImZpbHRlcmVkIGJ5IEI+MCAofmFkai5QLlZhbDwwLjAxKSwgYW5kIHNvcnRlZCB3LnIudC4gbWVkaWFuIEFiIHJlYWN0aXZpdHkiKSsKICBjb29yZF9mbGlwKCkgIyBPUkRFTkFSIGVqZSBkZSBwcm90ZcOtbmFzISEhIQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTgsIGZpZy5hbGlnbj0iY2VudGVyIn0KYWhlYXRtYXAoZXhwcnMoZXNldClbeCxdLCAKICAgICAgICAgUm93diA9IE5BLCBDb2x2ID0gTkEsIAogICAgICAgICBhbm5Db2wgPSBwRGF0YShlc2V0KSwgCiAgICAgICAgIGxheW91dCA9ICJfIikKYGBgCgojIyMjIGJveHBsb3RzCgotIFVuYSBtZWpvciBlc3RyYXRlZ2lhIGRlIHZpc3VhbGl6YWNpw7NuIHNvbiBsb3MgZGlhZ3JhbWFzIGRlIGNhamFzLCBsb3MgY3VhbGVzIGdyYWZpY2FuIGxhIGRpc3RyaWJ1Y2nDs24gdG90YWwgZGUgbGFzIG9ic2VydmFjaW9uZXMuCgpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0xMX0KI3JlcHJvCmJpb2Jyb29tOjp0aWR5LkV4cHJlc3Npb25TZXQoZXNldCxhZGRQaGVubyA9IFRSVUUpICU+JSAjc3RyKCkKICBtdXRhdGUob3JkZXI9c2VxKGZyb209bigpLHRvPTEpKSAlPiUgCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGdlbmUsb3JkZXIsb3JkZXI9VFJVRSksdmFsdWUsZmlsbD1waGVub3R5cGUpKSsKICBnZW9tX2JveHBsb3QoKSsKICAjZ2VvbV9wb2ludCgpICsKICB5bGFiKCJsb2cyLXRyYW5zZm9ybWVkIG5vcm1hbGl6ZWQgTUZJIikrCiAgeGxhYigiYW50aWdlbnMiKSsKICBsYWJzKHRpdGxlPSJEaWZmZXJlbnRpYWxseSByZWFjdGl2ZSBhbnRpZ2VucyIsCiAgICAgICBzdWJ0aXRsZT0iZmlsdGVyZWQgYnkgYWRqLlAuVmFsdWU8MC4wNSBhbmQgc29ydGVkIHcuci50LiBBc3ltcHRvbWF0aWMgbWVkaWFuIEFiIHJlYWN0aXZpdHkiKSsKICBjb29yZF9mbGlwKCkgIyBPUkRFTkFSIGVqZSBkZSBwcm90ZcOtbmFzISEhIQpgYGAKCiMjIyMgbGlzdAoKYGBge3J9CnggJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgbXV0YXRlKEdlbmUuSUQ9YXMuY2hhcmFjdGVyKEdlbmUuSUQpKSAlPiUgCiAgaW5uZXJfam9pbihsbiwgYnk9IkdlbmUuSUQiKSAlPiUgCiAgaW5uZXJfam9pbihiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKSAlPiUgCiAgICAgICAgICAgICAgIGdyb3VwX2J5KGdlbmUscGhlbm90eXBlKSAlPiUgc3VtbWFyaXNlKG1lYW5fZ3JvdXA9bWVhbih2YWx1ZSkpICU+JSAKICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JSAKICAgICAgICAgICAgICAgc3ByZWFkKHBoZW5vdHlwZSxtZWFuX2dyb3VwKSAlPiUgCiAgICAgICAgICAgICAgIHJlbmFtZShHZW5lLklEPWdlbmUpLAogICAgICAgICAgICAgYnk9IkdlbmUuSUQiKSAlPiUgCiAgICBpbm5lcl9qb2luKHRkICU+JSAKICAgICAgICAgICAgICAgYXJyYW5nZShkZXNjKHQpKSAlPiUgCiAgICAgICAgICAgICAgIG11dGF0ZSh0Lm9yZGVyPXNlcShuKCkpKSAlPiUgCiAgICAgICAgICAgICAgIHNlbGVjdChHZW5lLklELFAuVmFsdWUsYWRqLlAuVmFsLHQub3JkZXIpLAogICAgICAgICAgICAgYnk9IkdlbmUuSUQiKSAjJT4lIHNsaWNlKDE6OCkKYGBgCgojIyMgQi1zdGF0ID4wCgotIEhlcmUsIGFsbCBmZWF0dXJlcyBhcmUgZmlsdGVyZWQgYnkgX19wb3NpdGl2ZSBsb2ctb2Rkc19fIHRoYXQgdGhlIGdlbmUgaXMgZGlmZmVyZW50aWFsbHkgZXhwcmVzc2VkIChCPTAgfiA1MCUgcHJvYmFiaWxpdHkgYSBnZW5lIGlzIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCkuCi0gX19CLXN0YXRpc3RpY19fIGlzIGFkanVzdGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nIGJ5IGFzc3VtaW5nIHRoYXQgMSUgb2YgdGhlIGdlbmVzIChtb2RpZmlhYmxlIHBhcmFtZXRlcikgYXJlIGV4cGVjdGVkIHRvIGJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZC4KLSBEZXBlbmRzIG9uIG5vcm1hbGl0eSAoc2FtZSBhcyBwLXZhbHVlcyksIGFuZCBpbmRlcGVuZGVuY2UgYmV0d2VlbiBnZW5lcyAoc2FtZSBhcyBCSCBjb250cm9sIG9mIEZEUiksIGJ1dCByZXF1aXJlIGluIGFkZGl0aW9uIGEgcHJpb3IgZ3Vlc3MgZm9yIHRoZSBwcm9wb3J0aW9uIG9mIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBwcm9iZXMuCi0gX19wLXZhbHVlc19fIG1heSBiZSBwcmVmZXJyZWQgdG8gdGhlIEItc3RhdGlzdGljcyBiZWNhdXNlIHRoZXkgZG8gbm90IHJlcXVpcmUgdGhpcyBwcmlvciBrbm93bGVkZ2UuCgojIyMjIHNvcnRlZCBieSBzaWduaWZpY2FuY2UKCmBgYHtyLCBldmFsPVRSVUUsIGVjaG89RkFMU0V9CiMjIyMjIGhlYXRtYXAKZXNldCA8LSBFeHByZXNzaW9uU2V0KGFzc2F5RGF0YSA9IGV4cHJzX25vcm0sIAogICAgICAgICAgICAgICAgICAgICAgcGhlbm9EYXRhID0gcGhlbm9fZCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD03LCBmaWcud2lkdGg9MTAsIGZpZy5hbGlnbj0iY2VudGVyIiwgZWNobz1GQUxTRX0KI2VzZXQgPC0gZXNldCNsZXVrZW1pYXNFc2V0CiNleHBycyhlc2V0KSAlPiUgZGltKCkKeCA8LSB0ZCAlPiUgCiAgYXJyYW5nZShkZXNjKHQpKSAlPiUgCiAgI2FycmFuZ2UoZGVzYyhBdmVFeHByKSkgJT4lIAogIGZpbHRlcihCPjAgIyYgYWRqLlAuVmFsPDFlLTQKICAgICAgICAgKSAlPiUgCiAgc2VsZWN0KEdlbmUuSUQpICU+JSBhcy5tYXRyaXgoKSAKI3ggJT4lIGRpbSgpCgpwRGF0YShlc2V0KSA8LSBiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKSAlPiUgCiAgZ3JvdXBfYnkoc2FtcGxlKSAlPiUgc3VtbWFyaXNlKHNhbXBsZV9tZWRpYW49bWVkaWFuKHZhbHVlKSkgJT4lIAogIGZ1bGxfam9pbihwRGF0YShlc2V0KSAlPiUgCiAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogICAgICAgICAgICAgIHJlbmFtZShzYW1wbGU9cm93bmFtZSksCiAgICAgICAgICAgIGJ5PSJzYW1wbGUiKSAlPiUgCiAgYXJyYW5nZShwaGVub3R5cGUsc2FtcGxlX21lZGlhbikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAKICBjb2x1bW5fdG9fcm93bmFtZXModmFyPSJzYW1wbGUiKQoKeSA8LSBwRGF0YShlc2V0KSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIAogIHNlbGVjdChyb3duYW1lKSAlPiUgYXMubWF0cml4KCkgJT4lIGFzLmNoYXJhY3RlcigpCgplc2V0IDwtIGVzZXRbeCx5XQoKI2FoZWF0bWFwKGV4cHJzKGVzZXQpW3gsXSwgCiMgICAgICAgICBSb3d2ID0gTkEsIENvbHYgPSBOQSwgCiMgICAgICAgICBhbm5Db2wgPSBwRGF0YShlc2V0KSwgCiMgICAgICAgICBsYXlvdXQgPSAiXyIpCmBgYAoKIyMjIyMgYm94cGxvdHMKCi0gc2hvdyB0aGUgaW50ZW5zaXR5IGRpc3RyaWJ1dGlvbnMgb2Ygc2VsZWN0ZWQgZmVhdHVyZXMgaW4gYm90aCBncm91cHMuCgpgYGB7ciwgZmlnLndpZHRoPTgsZmlnLmhlaWdodD01LCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQojcmVwcm8KYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lICNzdHIoKQogIG11dGF0ZShvcmRlcj1zZXEoZnJvbT1uKCksdG89MSkpICU+JSAKICBnZ3Bsb3QoYWVzKHJlb3JkZXIoZ2VuZSxvcmRlcixvcmRlcj1UUlVFKSx2YWx1ZSxmaWxsPXBoZW5vdHlwZSkpKwogIGdlb21fYm94cGxvdCgpKwogICNnZW9tX3BvaW50KCkgKwogIHlsYWIoImxvZzItdHJhbnNmb3JtZWQgbm9ybWFsaXplZCBNRkkiKSsKICB4bGFiKCJhbnRpZ2VucyIpKwogIGxhYnModGl0bGU9IkRpZmZlcmVudGlhbGx5IHJlYWN0aXZlIGFudGlnZW5zIiwKICAgICAgIHN1YnRpdGxlPSJmaWx0ZXJlZCBieSBCPjAgKH5hZGouUC5WYWw8MC4wMSksIGFuZCBzb3J0ZWQgdy5yLnQuIFAuVmFsdWUiKSsKICBjb29yZF9mbGlwKCkgIyBPUkRFTkFSIGVqZSBkZSBwcm90ZcOtbmFzISEhIQpgYGAKCiMjIyMjIGxpc3QKCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQp4ICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIG11dGF0ZShHZW5lLklEPWFzLmNoYXJhY3RlcihHZW5lLklEKSkgJT4lIAogIGlubmVyX2pvaW4obG4sIGJ5PSJHZW5lLklEIikgJT4lIAogIGlubmVyX2pvaW4oYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogICAgICAgICAgICAgICBncm91cF9ieShnZW5lLHBoZW5vdHlwZSkgJT4lIHN1bW1hcmlzZShtZWFuX2dyb3VwPW1lYW4odmFsdWUpKSAlPiUgCiAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAgICAgICAgICAgIHNwcmVhZChwaGVub3R5cGUsbWVhbl9ncm91cCkgJT4lIAogICAgICAgICAgICAgICByZW5hbWUoR2VuZS5JRD1nZW5lKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgJT4lIAogICAgaW5uZXJfam9pbih0ZCAlPiUgCiAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyh0KSkgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodC5vcmRlcj1zZXEobigpKSkgJT4lIAogICAgICAgICAgICAgICBzZWxlY3QoR2VuZS5JRCxQLlZhbHVlLGFkai5QLlZhbCx0Lm9yZGVyKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgIyU+JSBzbGljZSgxOjEwKQpgYGAKCgojIyMjIHNvcnRlZCBieSBhdmVyYWdlCgpgYGB7ciwgZXZhbD1UUlVFLCBlY2hvPUZBTFNFfQojIyMjIyBoZWF0bWFwCmVzZXQgPC0gRXhwcmVzc2lvblNldChhc3NheURhdGEgPSBleHByc19ub3JtLCAKICAgICAgICAgICAgICAgICAgICAgIHBoZW5vRGF0YSA9IHBoZW5vX2QpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NywgZmlnLndpZHRoPTEwLCBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG89RkFMU0V9CiNlc2V0IDwtIGVzZXQjbGV1a2VtaWFzRXNldAojZXhwcnMoZXNldCkgJT4lIGRpbSgpCnggPC0gdGQgJT4lIAogICNhcnJhbmdlKGRlc2ModCkpICU+JSAKICBhcnJhbmdlKGRlc2MoQXZlRXhwcikpICU+JSAKICBmaWx0ZXIoQj4wICMmIGFkai5QLlZhbDwxZS00CiAgICAgICAgICkgJT4lIAogIHNlbGVjdChHZW5lLklEKSAlPiUgYXMubWF0cml4KCkgCiN4ICU+JSBkaW0oKQoKcERhdGEoZXNldCkgPC0gYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSkgJT4lIHN1bW1hcmlzZShzYW1wbGVfbWVkaWFuPW1lZGlhbih2YWx1ZSkpICU+JSAKICBmdWxsX2pvaW4ocERhdGEoZXNldCkgJT4lIAogICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICAgICAgICAgICAgICByZW5hbWUoc2FtcGxlPXJvd25hbWUpLAogICAgICAgICAgICBieT0ic2FtcGxlIikgJT4lIAogIGFycmFuZ2UocGhlbm90eXBlLHNhbXBsZV9tZWRpYW4pICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgY29sdW1uX3RvX3Jvd25hbWVzKHZhcj0ic2FtcGxlIikKCnkgPC0gcERhdGEoZXNldCkgJT4lIHJvd25hbWVzX3RvX2NvbHVtbigpICU+JSAKICBzZWxlY3Qocm93bmFtZSkgJT4lIGFzLm1hdHJpeCgpICU+JSBhcy5jaGFyYWN0ZXIoKQoKZXNldCA8LSBlc2V0W3gseV0KCiNhaGVhdG1hcChleHBycyhlc2V0KVt4LF0sIAojICAgICAgICAgUm93diA9IE5BLCBDb2x2ID0gTkEsIAojICAgICAgICAgYW5uQ29sID0gcERhdGEoZXNldCksIAojICAgICAgICAgbGF5b3V0ID0gIl8iKQpgYGAKCiMjIyMjIGJveHBsb3RzCgotIHNob3cgdGhlIGludGVuc2l0eSBkaXN0cmlidXRpb25zIG9mIHNlbGVjdGVkIGZlYXR1cmVzIGluIGJvdGggZ3JvdXBzLgoKYGBge3IsIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9NSwgZWNobz1GQUxTRSwgZXZhbD1GQUxTRX0KI3JlcHJvCmJpb2Jyb29tOjp0aWR5LkV4cHJlc3Npb25TZXQoZXNldCxhZGRQaGVubyA9IFRSVUUpICU+JSAjc3RyKCkKICBnZ3Bsb3QoYWVzKHJlb3JkZXIoZ2VuZSx2YWx1ZSxvcmRlciA9IFRSVUUpLHZhbHVlLGZpbGw9cGhlbm90eXBlKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgI2dlb21fcG9pbnQoKSArCiAgeWxhYigibG9nMi10cmFuc2Zvcm1lZCBub3JtYWxpemVkIE1GSSIpKwogIHhsYWIoImFudGlnZW5zIikrCiAgbGFicyh0aXRsZT0iRGlmZmVyZW50aWFsbHkgcmVhY3RpdmUgYW50aWdlbnMiLAogICAgICAgc3VidGl0bGU9ImZpbHRlcmVkIGJ5IEI+MCAofmFkai5QLlZhbDwwLjAxKSwgYW5kIHNvcnRlZCB3LnIudC4gbWVkaWFuIEFiIHJlYWN0aXZpdHkiKSsKICBjb29yZF9mbGlwKCkgIyBPUkRFTkFSIGVqZSBkZSBwcm90ZcOtbmFzISEhIQpgYGAKCiMjIyMjIGxpc3QKCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPUZBTFNFfQp4ICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIAogIG11dGF0ZShHZW5lLklEPWFzLmNoYXJhY3RlcihHZW5lLklEKSkgJT4lIAogIGlubmVyX2pvaW4obG4sIGJ5PSJHZW5lLklEIikgJT4lIAogIGlubmVyX2pvaW4oYmlvYnJvb206OnRpZHkuRXhwcmVzc2lvblNldChlc2V0LGFkZFBoZW5vID0gVFJVRSkgJT4lIAogICAgICAgICAgICAgICBncm91cF9ieShnZW5lLHBoZW5vdHlwZSkgJT4lIHN1bW1hcmlzZShtZWFuX2dyb3VwPW1lYW4odmFsdWUpKSAlPiUgCiAgICAgICAgICAgICAgIHVuZ3JvdXAoKSAlPiUgCiAgICAgICAgICAgICAgIHNwcmVhZChwaGVub3R5cGUsbWVhbl9ncm91cCkgJT4lIAogICAgICAgICAgICAgICByZW5hbWUoR2VuZS5JRD1nZW5lKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgJT4lIAogICAgaW5uZXJfam9pbih0ZCAlPiUgCiAgICAgICAgICAgICAgIGFycmFuZ2UoZGVzYyh0KSkgJT4lIAogICAgICAgICAgICAgICBtdXRhdGUodC5vcmRlcj1zZXEobigpKSkgJT4lIAogICAgICAgICAgICAgICBzZWxlY3QoR2VuZS5JRCxQLlZhbHVlLGFkai5QLlZhbCx0Lm9yZGVyKSwKICAgICAgICAgICAgIGJ5PSJHZW5lLklEIikgIyU+JSBzbGljZSgxOjEwKQpgYGAKCiMjIENvbmNsdXNpw7NuOiBhcGxpY2EgZWwgYHRpZHl2ZXJzZWAgYW50ZXMgeSBkZXNwdcOpcyBkZSBgQmlvY29uZHVjdG9yYAoKLSBBbCBpZ3VhbCBxdWUgZW4gbG9zIGNhc29zIHByZXNlbnRhZG9zIGVuIGxvcyB0dXRvcmlhbGVzIGFudGVyaW9yZXMsIGVsIGRpYWxlY3RvIGRlbCBgdGlkeXZlcnNlYCBmYWNpbGl0w7MgdGFudG8gZWwgaW5ncmVzbyBkZSBkYXRhIHBhcmEgbGEgZWplY3VjacOzbiBkZSBtb2RlbG9zIGVuIGBCaW9jb25kdWN0b3JgLCBjb21vIHBhcmEgImxpbXBpYXIiIHN1cyByZXN1bHRhZG9zIHkgZ2VuZXJhciBlbiBmb3JtYSBpbnR1aXRpdmEgdmlzdWFsaXphY2lvbmVzIHF1ZSBheXVkZW4gYSBzdSBpbnRlcnByZXRhY2nDs24uCgotIEVsIGFuw6FsaXNpcyBwcmVzZW50YWRvIHNpZ3VlIGVsIGZsdWpvIGRlIHRyYWJham8gcHJvcHVlc3RvIHBvciBEYXZpZCBSb2JpbnNvbjoKCiFbd29ya2Zsb3ddKGZpZ3VyZS90aWR5XzAxLmpwZykKCiMjIEVYVFJBIFRPT0w6IGBiaW9icm9vbWAgeSBgRXhwcmVzc2lvblNldF90aWRpZXJzYAoKLSBgYmlvYnJvb21gIGluY2x1eWUgInRpZGllcnMiIHBhcmEgdmFyaWFzIGVzdHJ1Y3R1cmFzIGRlIGRhdG9zIGRlIEJpb2NvbmR1Y3Rvci4gUmV2w61zYWxvIFthcXXDrV0oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9iaW9jL3ZpZ25ldHRlcy9iaW9icm9vbS9pbnN0L2RvYy9iaW9icm9vbV92aWduZXR0ZS5odG1sKS4KCi0gwr9UYXJlYT8gUG9uZXJsbyBlbiBwcsOhY3RpY2EgY29uIHN1cyBlamVtcGxvcyBkZSBSTkEtc2VxIDopCgpgYGB7cn0KI2V4cHJzKGVzZXQpCiNwRGF0YShlc2V0KSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIGFycmFuZ2UocGhlbm90eXBlKQpiaW9icm9vbTo6dGlkeS5FeHByZXNzaW9uU2V0KGVzZXQsYWRkUGhlbm8gPSBUUlVFKQpgYGAKCiMjIENvbXB1dGVyIGVudmlyb25tZW50CmBgYHtyfQpkZXZ0b29sczo6c2Vzc2lvbl9pbmZvKCkKYGBgCgojIyBSZWZlcmVuY2Vz