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)

Data input

La data ha sido adquirida por dos vias distintas:

  • Data disponible del paquete leukemiaEset e
  • Importación del archivo excel disponible en el material suplementario del artículo referido.
library(leukemiasEset)
data(leukemiasEset)
leukeset <- leukemiasEset

#https://academic.oup.com/jid/article-lookup/doi/10.1093/infdis/jiu614#supplementary-data
protmicro <- readxl::read_excel("data-raw/jiu614_Supplementary_Data/jiu614supp_table1.xlsx")

Ambas bases han sido grabadas en un formato .rds con la función saveRDS() para facilitar su distribución y acceso.

saveRDS(leukeset, "data-raw/leukeset.rds")
saveRDS(protmicro, "data-raw/protmicro.rds")

Por ello, la importación de ambas bases será ejecutada por la función readRDS().

leukeset <- readRDS("data-raw/leukeset.rds")
protmicro <- readRDS("data-raw/protmicro.rds")

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).
  1. 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.

  2. 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

  • useful to check prior to execution of a multiple comparison correction.

  • El comportamiento de esta corrección puede inferirse preliminarmente al observar la ditribución de valores p en un histograma.
  • Corroborar que la proporción de valores p ajustados menores al nivel de FDR deseado será igual a la proporción de valores p menores al nivel de significancia que estén sobre la distribución de las hipótesis nulas no rechazadas.
  • Comparar con el siguiente caso

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

  • Visualizacióń del efecto del caso sobre el control (logFC) por su significancia estadística.

  • tutorial aquí

# (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.

  1. 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).

  2. 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)

Normalization + Transformation

Objetivo de la normalización: homogeneizar la variabilidad entre arreglos en base a controles, los cuales se asume que son invariantes entre muestras. El método depende del diseño de arreglos:

  • sustracción de controles o fold over control (FOC), aplicado en microarreglos de proteínas con respecto a la mediana del control blanco por muestra (King et al. 2015);
  • estabilización de varianzas o VSN, aplicado en microarreglos de DNA con respecto a controles de intensidad invariante entre muestras, e.g. genes housekeeping (Huber et al. 2002)

Objetivo de la transformación: reducir la heterocedasticidad o heterogeneidad de varianzas entre las observaciones por errores aleatorios en el proceso de hibridación (Kreil and Russell 2005). Dos principales métodos:

  • logarítmica, la cual asume un error multiplicativo que corrige las varianzas de alta intensidad pero capaz dispersar a las de baja intensidad; y
  • asinh, la cual asume un error multiplicativo y aditivo que corrige esta dispersión, pero solo relevante en contextos donde los valores normalizados menores a la unidad tienen significado biológico.

En el contexto de microarreglos de DNA, ambas transformaciones permiten homogenizar la sobreexpresión o represión génica con respecto a el control elegido. Por ejemplo, una sobreexpresión de 4 sobre el control se homogeniza con una represión de la misma magnitud:

\[log_2\left(\frac{gen_x}{ctrl}\right) \qquad \Rightarrow \qquad log_2\left(\frac{4a}{a}\right)=+2 \qquad or \qquad log_2\left(\frac{b}{4b}\right)=-2\]

NOTA: Los autores del paper reportan el método vsn. A diferencia de la transformación logarítimica, este logra corregir errores en lecturas de intensidad baja (e.g., cercanas y menores a la unidad posterior a su normalización). Es idóneo en experimentos donde la intensidades positivas y negativas con respecto al control (generalmente, genes housekeeping) son biológicamente relevantes. Sin embargo, el contexto de microarreglo de proteínas es particularmente asimétrico, es decir, las lecturas con relevancia biológica serán todas las que poseean intensidades mayores al control negativo (noDNA) usado en la normalización. Más detalles, aquí

# custom function
# definir resultado para los valores menores a cero, 
# donde el log no está definido
log2.NA = function(x) {log2(ifelse(x>0, x, NA))}

# normalización con respecto a los controles `noDNA` c/ transformación log2
exprs_norm <- log2.NA(exprs_prot_m/mat)
head(exprs_norm[,1:6])
                          PA06        PA07        PA11     PA12       PA13      PA14
MAL13P1.103.289      0.9405178  0.86809290  1.27023577 1.424781 2.09608832 0.8320235
MAL13P1.107-s1.554  -0.2656989 -0.14818391 -0.07028325 1.285972 0.19280253 0.3443371
MAL13P1.107-s2.464  -0.3816641 -0.35163062 -0.29044986 2.060435 0.18312648 0.5249094
MAL13P1.114e3s1.339  0.7389770  0.61654665  1.19901791 1.260824 2.01955007 1.8748171
MAL13P1.121_1o4.423  0.4261138 -0.04101899  0.90084314 1.071942 1.39637581 0.3657352
MAL13P1.124.557     -0.1403632 -0.18520701  1.41131990 0.778040 0.06164984 0.6982887

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.

list

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:

workflow

workflow

EXTRA TOOL: biobroom y ExpressionSet_tidiers

  • biobroom incluye “tidiers” para varias estructuras de datos de Bioconductor. Revísalo aquí.

  • ¿Tarea? Ponerlo en práctica con sus ejemplos de RNA-seq :)

#exprs(eset)
#pData(eset) %>% rownames_to_column() %>% arrange(phenotype)
biobroom::tidy.ExpressionSet(eset,addPheno = TRUE)

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