1. Preprocesamiento de los datos
Para llevar a cabo el análisis, primero se deben cargar, filtrar y
preprocesar los datos tomados en el matadero, los cuales fueron
descargados del European
Nucleotide Archive.
1.1 Setup del ambiente de trabajo
Se hará uso de paquetes de R, y librerías opensource de Bioconductor
para el procesamiento de datos.
library(ampvis2)
library(mia)
library(miaViz)
library(ggplot2)
library(Biostrings)
library(phyloseq)
library(ANCOMBC)
library(tidyr)
library(patchwork)
library(ggsignif)
library(scater)
library(ggpubr)
library(reshape2)
library(RColorBrewer)
library(dada2)
library(vegan)
Además, se debe setear el directorio que contenga los archivos
(.fastq) con los datos descargados:
# Reemplazar por directorio utilizado
setwd("~/UCU/alimentos1/")
path <- getwd()
1.3 Chequeo y filtrado de calidad
Para filtrar lecturas de mala calidad, se grafica la calidad de las
mismas para definir donde truncarlas.


Es característico de una lectura Illumina que al final de la
secuencia, el score de calidad decaiga, y que la lectura reverse tenga
menor calidad que la forward. Entonces se trunca las regiones de mala
calidad.
En este caso, se utilizarán las regiones donde el score sea mayor a
30 aproximadamente. Por lo tanto se truncaran las bases posteriores a
290 en lecturas forward, y 200 para reverse.
Para realizar el filtrado y truncado es útil la función
filterAndTrim, la cual permite:
Utilizando los parámetros:
truncLen=c(290, 200) ⟶ Lecturas con tamaño menor a 290 (forward)
o 200 (reverse) son descartadas
maxEE=(2,2) ⟶ Lecturas con mas de 2 errores esperados son
descartadas
maxN=0 ⟶ Lecturas con datos nulos son descartadas
Se debe tener cuidado de no truncar en exceso, debido a que dada2
solo tiene en cuenta la secuencia solapada entre forward y reverse,
entonces al truncar de más habrá poco solapamiento, y menos datos serán
procesados por dada2.
# Archivos donde se almacenarán las muestras filtradas y truncadas
filtFs <- file.path(path, "filtered", paste0(sample.names, "_F_filt.fastq.gz"))
filtRs <- file.path(path, "filtered", paste0(sample.names, "_R_filt.fastq.gz"))
# Filtrado y truncado de datos
filterAndTrim_out <- filterAndTrim(fnFs, filtFs, fnRs, filtRs, truncLen=c(290,200), maxN=0, maxEE=c(2,2), truncQ=2, rm.phix=TRUE, compress=TRUE, multithread=TRUE)
# Almacenar resultado
save(filterAndTrim_out, file="filterAndTrim_out")
Al ser una operación costosa, se almacena el resultado en un archivo
para evitar recalcular:
load("filterAndTrim_out")
El resultado de esta función es una matriz que contiene para cada
muestra, la cantidad de secuencias que existían originalmente, y cuántas
resultaron luego del filtrado.
Permite identificar cuantas lecturas fueron descartadas. Además,
almacena en los archivos especificados (filtFs y filtRs) los resultados
filtrados.
col_sum <- colSums(filterAndTrim_out)
filtered_reads <- col_sum[1] - col_sum[2]
message(sprintf("Fueron filtradas %s lecturas, un %%%.2f de las lecturas originales.", filtered_reads, filtered_reads * 100 / col_sum[1]))
Fueron filtradas 456939 lecturas, un %20.61 de las lecturas originales.
1.4 Aprendizaje de errores
Dada2 necesita conocer las probabilidades de errores para poder
decidir si dos secuencias que se diferencian en 1 o 2 bases son la misma
y haya ocurrido un error, o sean realmente dos secuencias
diferentes.
Por lo tanto, se debe estimar los errores, y modelar las
probabilidades de que hayan ocurrido transiciones (A ⟶ T, A ⟶ C, C ⟶ A,
etc):
# forward
errF <- learnErrors(filtFs, multithread=TRUE)
save(errF, file="errF")
# reverse
errR <- learnErrors(filtRs, multithread=TRUE)
save(errR, file="errR")
Al ser una operación costosa, se almacena el resultado en un archivo
para evitar recalcular:
load("errF")
load("errR")
Se puede observar que los errores son acordes a sus estimados, ya que
presentan gráficos similares:


1.5 Derreplicacion
La derreplicacion consiste en contar las apariciones de cada
secuencia en las muestras, lo cual es necesario para luego agrupar los
ASVs encontrados:
# forward
derepFs <- derepFastq(filtFs, verbose=TRUE)
names(derepFs) <- sample.names
save(derepFs, file= "derepFs")
# reverse
derepRs <- derepFastq(filtRs, verbose=TRUE)
names(derepRs) <- sample.names
save(derepRs, file= "derepRs")
Para evitar el costoso cálculo:
load("derepFs")
load("derepRs")
Obteniéndose por muestra, una matriz con el conteo de cada secuencia,
y sus scores promedio de calidad.
1.6 Identificar ASVs con DADA2
Ahora que se tienen los datos prontos para agrupar, se identifican
los ASVs para las secuencias forward y reverse utilizando la función
dada:
dadaFs <- dada(derepFs, err=errF, pool = TRUE , multithread=TRUE)
save(dadaFs, file="dadaFs")
#Reverse reads
dadaRs <- dada(derepRs, err=errR, pool = TRUE , multithread=TRUE)
save(dadaRs, file="dadaRs")
Para evitar el costoso cálculo:
1.7 Identificar cuantas veces aparece un ASV en cada muestra
Para esto, se debe unir los ASVs forward y reverse en una única
secuencia:
mergers <- mergePairs(dadaFs, derepFs, dadaRs, derepRs, verbose=TRUE)
save(mergers, file="mergers")
Para evitar el costoso cálculo:
El resultado de esta función es una lista de dataframes con
información sobre la unión de las secuencias forward y reverse, por
ejemplo: solapamiento, missmatch, etc.
Esta información es utilizada para contar las apariciones de cada ASV
en cada muestra:
1.8 Filtrado de ASVs resultantes y quimeras
Las secuencias se esperan que tengan un largo dentro de un intervalo.
Este intervalo se calcula a partir de los primers, largo de forward y
reverse, porque se espera que las secuencias tengan un largo similar al
solapamiento del forward y reverse.
En este caso el intervalo es entre 440 y 466, por lo tanto se filtran
todos los ASV que no lo cumplan:
Además, es posible que existan quimeras en los datos. Las quimeras
son secuencias malformadas y no existentes que pueden aparecer luego de
la secuenciación, y deben ser filtradas:
seqtab.nochim <- removeBimeraDenovo(seqtab, method="consensus", multithread=TRUE, verbose=TRUE)
save(seqtab.nochim,file="seqtab.nochim")
Para evitar el costoso cálculo:
1.10 Unificar datos con Phyloseq
Phyloseq es un framework que ofrece funcionalidades para analizar los
datos, por ejemplo diversidad alfa, beta, abundancias diferenciales,
etc, en base a toda la información de las muestras que se hayan
recolectado.
Se debe cargar la base de datos que contiene la taxonomía
(informacion biologica) de los ASVs:
taxa_gtdb <- assignTaxonomy(seqtab.nochim, "", multithread=TRUE)
Para evitar el costoso cálculo:
load("taxa_gtdb")
Luego, importar las muestras que se vayan a utilizar:
sample_data <- as.data.frame(read.table("sampleData_alimentos.csv", header=TRUE, sep=","))
rownames(sample_data) <- sample_data[,1]
Finalmente, cargar los datos a Phyloseq:
physeq <- phyloseq(otu_table(seqtab.nochim, taxa_are_rows=FALSE),sample_data(sample_data),tax_table(taxa_gtdb))
save(physeq, file="physeq")
2. Interpretación de resultados
2.1 Análisis de muestras
Para el objetivo del estudio no es necesario analizar todas las
muestras tomadas, es posible tomar un subset útil para la investigación.
En este caso, son las muestras tomadas inicialmente de la piel de los
cerdos, y en el recto anal.
ps <- subset_samples(physeq, Sampling.position %in% c("Sticking", "Anal swab"))
ps.prop <- transform_sample_counts(ps, function(OTU) OTU/sum(OTU))
message("Cantidad de muestras: ", nsamples(ps), "\n",
"Cantidad de ASVs: ", ntaxa(ps), "\n",
"Cantidad de ASVs no presentes en las muestras: ", ntaxa(prune_taxa(taxa_sums(ps) == 0, ps)))
Cantidad de muestras: 8
Cantidad de ASVs: 15413
Cantidad de ASVs no presentes en las muestras: 7606
Se filtran los ASV que no estan presentes en ninguna muestra, porque
no son utiles:
ps <- prune_taxa(taxa_sums(ps) > 0, ps)
La distribución de ASV resultantes por muestra se puede apreciar en
el siguiente gráfico:
reads_per_ASV <- data.frame(nreads=sort(taxa_sums(ps)), TRUE, SVs= 1:ntaxa(ps))
ggplot(data=reads_per_ASV,aes(x = SVs, y = nreads)) +
geom_area (stat="identity", fill = "#69BE28") +
scale_x_log10()

Como del granjero A se muestrearon dos cerdos, existen cerca del
doble de lecturas que los demás granjeros.
# Filter reads
filtered_reads <- data.frame(
nreads=sort(sample_sums(ps)),
Farmer=sample_data(ps)$Farmer,
Position=sample_data(ps)$Sampling.position,
TRUE,
samples=sample_data(ps)$Farmer,
type = "Samples"
)
# Plot
ggplot(filtered_reads, aes(x=samples, y=nreads)) +
geom_bar(aes(color=Position, fill=Position), stat="identity") +
facet_wrap(~Farmer, scales="free_x")

2.2 Abundancias relativas
# Graficar abundancias relativas por filo
plot_bar(ps.prop, x="Sample", fill="Phylum") +
facet_wrap(~Farmer, scales="free_x") +
geom_bar(aes(color=Phylum, fill=Phylum), stat="identity", position="stack")

En el gráfico anterior se puede ver en todas las muestras una gran
presencia de bacteroidetes, las mismas son comunes en el intestino de
muchos animales. Estas bacterias pueden desempeñar un papel importante
en la digestión y la absorción de nutrientes en los animales, así como
en la salud general de su sistema digestivo.
Además, se puede ver presencia de fusobacteriotas en las muestras.
Son conocidas por su capacidad para causar infecciones en los animales,
incluyendo infecciones orales, abscesos y enfermedades respiratorias.
Por ejemplo, en los cerdos se ha informado que las Fusobacterium pueden
estar implicadas en casos de necrosis hepática y abscesos. La infección
con Fusobacterium puede ser el resultado de una lesión en la piel o una
infección previa, lo que permite que las bacterias entren en el cuerpo y
causen una infección.
Otras bacterias presentes en todas las muestras son del filo
Spirochaetota, las mismas son conocidas por ser patógenas pero es común
en el tracto gastrointestinal de los cerdos, aunque no se consideran
patógenas en este caso para ellos.
# Abundancias relativas por género
tse <- makeTreeSummarizedExperimentFromPhyloseq(ps)
tse <- transformSamples(tse, method = "relabundance")
tse <- addTaxonomyTree(tse)
tse_gen <- agglomerateByRank(tse, rank = "Genus")
rownames(tse_gen)<-sub("Genus:","", rownames(tse_gen))
plotAbundanceDensity(tse_gen, layout = "jitter", abund_values="relabundance", n = 20, point_size=1, point_shape=19, point_alpha=0.5, colour_by="Farmer") +
scale_x_log10(label=scales::percent)

En este otro gráfico, se puede ver los porcentajes de abundancia
relativa entre cada género.
Como por ejemplo, campylobacter está presente en un más de 10% de
abundancia relativa en una muestra del cerdo perteneciente al granjero
B. Campylobacter puede ser un patógeno que causa enfermedades
gastrointestinales en humanos, por lo que la presencia de Campylobacter
en cerdos puede plantear preocupaciones en términos de seguridad
alimentaria. La bacteria puede transmitirse a los humanos a través del
consumo de alimentos contaminados con Campylobacter, como carne cruda o
insuficientemente cocida, así como a través del contacto directo con
animales infectados.
# Abundancia relativa por familia
tse_family <- agglomerateByRank(tse, rank = "Family")
rownames(tse_family)<-sub("Family:","", rownames(tse_family))
plotAbundanceDensity(tse_family, layout = "jitter", abund_values="relabundance", n = 20, point_size=1, point_shape=19, point_alpha=0.5, colour_by="Farmer") + scale_x_log10(label=scales::percent)

Las bacterias pertenecientes a la familia Moraxellaceae se encuentran
presente en todas las muestras pero mayormente en los chanchos del
granjero A y C. Moraxellaceae pueden causar problemas en la calidad de
la carne de cerdo, como el olor rancio, lo que puede ser un problema
importante para la industria cárnica.
Las bacterias enterobacteriaceae son patógenas y pueden causar
enfermedades como la salmonella. La misma está más presente en las
muestras del chancho del granjero B.
2.3 Diversidad alfa
La diversidad alfa en metabarcoding se refiere a la diversidad de
especies o tipos de organismos presentes en una muestra de ADN biológico
y se puede medir utilizando varios índices, como el índice de
Simpson.
rarefied<-rarefy_even_depth(ps,min(sample_sums(ps)),rngseed=1)
tse_rarefied <- makeTreeSummarizedExperimentFromPhyloseq(rarefied)
# Uniformidad
tse_rarefied <- estimateEvenness(tse_rarefied,
abund_values = "counts",
index="simpson")
plots <- lapply(c("simpson"),
plotColData,
object = tse_rarefied,
x = "Farmer",
colour_by = "Farmer")
plots <- lapply(plots, "+",
theme(axis.text.x = element_blank(),
axis.title.x = element_blank(),
axis.ticks.x = element_blank()))
plots[[1]] + plot_layout(guides = "collect")

La gráfica de diversidad alfa de Simpson muestra la riqueza de
especies y la equitabilidad en una comunidad. En esta gráfica, la
diversidad alfa se representa en el eje de las ordenadas, mientras que
el tamaño de la muestra se representa en el eje de abscisas.
La diversidad de Simpson se expresa como un índice de dominancia y se
calcula restando la suma de los cuadrados de las proporciones de cada
especie en la comunidad de uno. Cuanto más cercano sea el índice de
Simpson a 1, menor será la diversidad alfa, lo que indica una mayor
dominancia de una o unas pocas especies en la comunidad. Por otro lado,
cuanto más cercano sea el índice de Simpson a 0, mayor será la
diversidad alfa, lo que indica que las especies están distribuidas de
manera uniforme en la comunidad.
message("Indice simpson promedio del granjero B: ", mean(subset(x, Farmer == "B")$simpson))
Indice simpson promedio del granjero B: 0.200961048738534
message("Indice simpson promedio del granjero A: ", mean(subset(x, Farmer == "A")$simpson))
Indice simpson promedio del granjero A: 0.402348623504202
En este caso, las muestras del granjero B presentan un menor índice
simpson promedio, por lo tanto cuenta con una mayor diversidad alfa.
Por otro lado, las muestras del granjero A presentan un mayor índice
simpson que las demás muestras, por lo tanto cuentan con una diversidad
alfa menor. Esto puede significar que existe menor cantidad de bacterias
diferentes, o una gran proporción de las bacterias presentes son
similares.
2.4 Diversidad beta
En metabarcoding, la diversidad beta se refiere a la variación en la
composición de especies entre diferentes muestras.
# Aglomeracion por gènero manteniendo los NA
tse_genus <- agglomerateByRank(tse, rank = "Genus")
tse_genus_notNA <- tse_genus[!is.na(rowData(tse_genus)$Genus), ]
tse_genus_notNA <- runMDS(tse_genus_notNA, FUN = vegan::vegdist, method = "bray", name = "PCoA_BC", exprs_values = "counts")
# Create ggplot object
p <- plotReducedDim(tse_genus_notNA, "PCoA_BC", colour_by = "Farmer")
# Add explained variance for each axis
e <- attr(reducedDim(tse_genus_notNA, "PCoA_BC"), "eig");
rel_eig <- e/sum(e[e>0])
p + labs(x = paste("PCoA 1 (", round(100 * rel_eig[[1]],1), "%", ")", sep = ""),
y = paste("PCoA 2 (", round(100 * rel_eig[[2]],1), "%", ")", sep = ""))

Los puntos en la gráfica representan las muestras y su posición se
basa en su similitud biológica. Las muestras que están más cerca en la
gráfica se consideran más similares en términos de su composición
biológica.
Analizando la gráfica se puede concluir que las muestras coinciden
con lo esperado ya que entre ellas hay cierta distancia lo que refiere a
que las muestras no tienen composición biológica similar.
LS0tCnRpdGxlOiAiRW50cmVnYSBGaW5hbCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCiMgSW50cm9kdWNjacOzbgoKRW4gZXN0ZSBub3RlYm9vayBwcmVzZW50YSBlbCBwcm9jZWRpbWllbnRvIGxsZXZhZG8gYSBjYWJvIHBhcmEgZWwgYW7DoWxpc2lzIGRlIGRhdG9zIGRlIG1ldGFiYXJjb2RpbmcsIGEgcGFydGlyIGVsIGFydMOtY3VsbyAqIltUaGUgc291cmNlcyBhbmQgdHJhbnNtaXNzaW9uIHJvdXRlcyBvZiBtaWNyb2JpYWwgcG9wdWxhdGlvbnMgdGhyb3VnaG91dCBhIG1lYXQgcHJvY2Vzc2luZyBmYWNpbGl0eV0oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9zNDE1MjItMDIwLTAxMzYteikiKi4gRXN0ZSBhcnTDrWN1bG8gYnVzY2EgYW5hbGl6YXIgZSBpZGVudGlmaWNhciBmdWVudGVzIHBvdGVuY2lhbGVzIGRlIGNvbnRhbWluYWNpw7NuIG1pY3JvYmlhbmEgZW4gbGEgY2FybmUgZGUgY2VyZG9zLCBkdXJhbnRlIGVsIHByb2Nlc28gZGUgZmFlbmEgZW4gZWwgbWF0YWRlcm8uCgojIyBPYmpldGl2bwoKRWwgb2JqZXRpdm8gZGUgbnVlc3RybyBlc3R1ZGlvIHNlIHJlZHVjZSBhIGFuYWxpemFyIGPDs21vIGNhbWJpYSBsYSBjb21wb3NpY2nDs24gbWljcm9iaWFuYSBlbiBsYSBjYXJuZSBkZSBsb3MgY2VyZG9zIGRlIGxvcyBkaXN0aW50b3MgZ3Jhbmplcm9zLCBlIGlkZW50aWZpY2FyIHNpIGFsZ3VuYSBjb21wb3NpY2nDs24gcHJlc2VudGEgdW4gcGVsaWdybyBtYXlvciBwYXJhIGVsIG1hdGFkZXJvLgoKIyAxLiBQcmVwcm9jZXNhbWllbnRvIGRlIGxvcyBkYXRvcwoKUGFyYSBsbGV2YXIgYSBjYWJvIGVsIGFuw6FsaXNpcywgcHJpbWVybyBzZSBkZWJlbiBjYXJnYXIsIGZpbHRyYXIgeSBwcmVwcm9jZXNhciBsb3MgZGF0b3MgdG9tYWRvcyBlbiBlbCBtYXRhZGVybywgbG9zIGN1YWxlcyBmdWVyb24gZGVzY2FyZ2Fkb3MgZGVsIFtFdXJvcGVhbiBOdWNsZW90aWRlIEFyY2hpdmVdKGh0dHBzOi8vd3d3LmViaS5hYy51ay9lbmEvYnJvd3Nlci92aWV3L1BSSkVCMzc0MzQpLgoKIyMgMS4xIFNldHVwIGRlbCBhbWJpZW50ZSBkZSB0cmFiYWpvCgpTZSBoYXLDoSB1c28gZGUgcGFxdWV0ZXMgZGUgUiwgeSBsaWJyZXLDrWFzIG9wZW5zb3VyY2UgZGUgQmlvY29uZHVjdG9yIHBhcmEgZWwgcHJvY2VzYW1pZW50byBkZSBkYXRvcy4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoYW1wdmlzMikKbGlicmFyeShtaWEpCmxpYnJhcnkobWlhVml6KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoQmlvc3RyaW5ncykKbGlicmFyeShwaHlsb3NlcSkKbGlicmFyeShBTkNPTUJDKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShnZ3NpZ25pZikKbGlicmFyeShzY2F0ZXIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShkYWRhMikKbGlicmFyeSh2ZWdhbikKYGBgCgpBZGVtw6FzLCBzZSBkZWJlIHNldGVhciBlbCBkaXJlY3RvcmlvIHF1ZSBjb250ZW5nYSBsb3MgYXJjaGl2b3MgKC5mYXN0cSkgY29uIGxvcyBkYXRvcyBkZXNjYXJnYWRvczoKCmBgYHtyfQojIFJlZW1wbGF6YXIgcG9yIGRpcmVjdG9yaW8gdXRpbGl6YWRvCnNldHdkKCJ+L1VDVS9hbGltZW50b3MxLyIpCnBhdGggPC0gZ2V0d2QoKQpgYGAKCiMjIDEuMiBSZWdpc3RyYXIgbWV0YWluZm9ybWFjacOzbiBkZSBsYXMgbXVlc3RyYXMKCkRpZmVyZW50ZXMgbXVlc3RyYXMgZnVlcm9uIHRvbWFkYXMgZHVyYW50ZSBlbCBwcm9jZXNvIGRlIGZhZW5hLCBlbiBkaWZlcmVudGVzIGNlcmRvcywgbHVnYXJlcyB5IGhlcnJhbWllbnRhcy4gTGFzIGxlY3R1cmFzIHJlYWxpemFkYXMgZW4gY2FkYSBtdWVzdHJhIGZ1ZXJvbiBhbG1hY2VuYWRhcyBlbiBhcmNoaXZvcyAuZmFzdHEsIGxvcyBjdWFsZXMgY29udGllbmVuIGxhcyBzZWN1ZW5jaWFzIGRlIEFETiB5IGNhbGlkYWQgZGUgc3VzIHJlc3BlY3RpdmFzIGxlY3R1cmFzLgoKRGViaWRvIGEgcXVlIGxvcyBhcmNoaXZvcyBjb250aWVuZW4gZGVtYXNpYWRhIGluZm9ybWFjacOzbiwgbnVuY2Egc2UgY2FyZ2FuIGVuIG1lbW9yaWEuIFNpbm8gcXVlIGxhcyBmdW5jaW9uZXMgdXRpbGl6YWRhcyBzZSBlbmNhcmdhbiBkZSBidXNjYXIgbG9zIGRhdG9zIGVuIGNhZGEgYXJjaGl2byBjdWFuZG8gc2VhIG5lY2VzYXJpbywgYSBwYXJ0aXIgZGUgc3UgcnV0YS4gRW50b25jZXMsIHNlIGd1YXJkYSBlbCBsaXN0YWRvIGRlIHJ1dGFzIGhhY2lhIGxvcyBhcmNoaXZvcyBkZSB0b2RhcyBsYXMgbGVjdHVyYXMgZm9yd2FyZCAoZikgeSByZXZlcnNlIChyKS4KCmBgYHtyfQojIEFyY2hpdm9zIHF1ZSBjb250ZW5nYW4gJ18xLmZhc3RxJyByZXByZXNlbnRhbiBsZWN0dXJhcyBmCmZuRnMgPC0gc29ydChsaXN0LmZpbGVzKHBhdGgsIHBhdHRlcm49Il8xLmZhc3RxIiwgZnVsbC5uYW1lcyA9IFRSVUUpKSAKIyBBcmNoaXZvcyBxdWUgY29udGVuZ2FuICdfMi5mYXN0cScgcmVwcmVzZW50YW4gbGVjdHVyYXMgcgpmblJzIDwtIHNvcnQobGlzdC5maWxlcyhwYXRoLCBwYXR0ZXJuPSJfMi5mYXN0cSIsIGZ1bGwubmFtZXMgPSBUUlVFKSkKYGBgCgpMdWVnbywgc2UgZXh0cmFlbiBsb3Mgbm9tYnJlcyBkZSBjYWRhIG11ZXN0cmEgYSBwYXJ0aXIgZGVsIG5vbWJyZSBkZSBsb3MgYXJjaGl2b3M6CgpgYGB7cn0KIyBGb3JtYXRvOiBTQU1QTEVOQU1FX1hYWC5mYXN0cQpzYW1wbGUubmFtZXMgPC0gc2FwcGx5KHN0cnNwbGl0KGJhc2VuYW1lKGZuRnMpLCAiXyIpLCBgW2AsIDEpCmBgYAoKRmluYWxtZW50ZSBzZSBpbXBvcnRhIGxhIG1ldGFkYXRhIGRlIGNhZGEgbXVlc3RyYToKCmBgYHtyfQpzYW1wbGUubWV0YWRhdGEgPC0gcmVhZC5jc3YoInNhbXBsZURhdGFfYWxpbWVudG9zLmNzdiIpCmBgYAoKIyMgMS4zIENoZXF1ZW8geSBmaWx0cmFkbyBkZSBjYWxpZGFkCgpQYXJhIGZpbHRyYXIgbGVjdHVyYXMgZGUgbWFsYSBjYWxpZGFkLCBzZSBncmFmaWNhIGxhIGNhbGlkYWQgZGUgbGFzIG1pc21hcyBwYXJhIGRlZmluaXIgZG9uZGUgdHJ1bmNhcmxhcy4KCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgRm9yd2FyZCByZWFkcwpwbG90UXVhbGl0eVByb2ZpbGUoZm5Gc1sxOjJdKSAKIyBSZXZlcnNlIHJlYWRzCnBsb3RRdWFsaXR5UHJvZmlsZShmblJzWzE6Ml0pCmBgYAoKRXMgY2FyYWN0ZXLDrXN0aWNvIGRlIHVuYSBsZWN0dXJhIElsbHVtaW5hIHF1ZSBhbCBmaW5hbCBkZSBsYSBzZWN1ZW5jaWEsIGVsIHNjb3JlIGRlIGNhbGlkYWQgZGVjYWlnYSwgeSBxdWUgbGEgbGVjdHVyYSByZXZlcnNlIHRlbmdhIG1lbm9yIGNhbGlkYWQgcXVlIGxhIGZvcndhcmQuIEVudG9uY2VzIHNlIHRydW5jYSBsYXMgcmVnaW9uZXMgZGUgbWFsYSBjYWxpZGFkLgoKRW4gZXN0ZSBjYXNvLCBzZSB1dGlsaXphcsOhbiBsYXMgcmVnaW9uZXMgZG9uZGUgZWwgc2NvcmUgc2VhIG1heW9yIGEgMzAgYXByb3hpbWFkYW1lbnRlLiBQb3IgbG8gdGFudG8gc2UgdHJ1bmNhcmFuIGxhcyBiYXNlcyBwb3N0ZXJpb3JlcyBhIDI5MCBlbiBsZWN0dXJhcyBmb3J3YXJkLCB5IDIwMCBwYXJhIHJldmVyc2UuCgpQYXJhIHJlYWxpemFyIGVsIGZpbHRyYWRvIHkgdHJ1bmNhZG8gZXMgw7p0aWwgbGEgZnVuY2nDs24gZmlsdGVyQW5kVHJpbSwgbGEgY3VhbCBwZXJtaXRlOgoKLSAgIENvcnRhciByZWdpc3Ryb3MgZGUgbWFsYSBjYWxpZGFkCgotICAgRmlsdHJhciBsZWN0dXJhcyBjb24gZGF0b3MgbnVsb3MKCi0gICBDb3J0YXIgcHJpbWVycwoKVXRpbGl6YW5kbyBsb3MgcGFyw6FtZXRyb3M6CgotICAgdHJ1bmNMZW49YygyOTAsIDIwMCkg4p+2IExlY3R1cmFzIGNvbiB0YW1hw7FvIG1lbm9yIGEgMjkwIChmb3J3YXJkKSBvIDIwMCAocmV2ZXJzZSkgc29uIGRlc2NhcnRhZGFzCgotICAgbWF4RUU9KDIsMikg4p+2IExlY3R1cmFzIGNvbiBtYXMgZGUgMiBlcnJvcmVzIGVzcGVyYWRvcyBzb24gZGVzY2FydGFkYXMKCi0gICBtYXhOPTAg4p+2IExlY3R1cmFzIGNvbiBkYXRvcyBudWxvcyBzb24gZGVzY2FydGFkYXMKClNlIGRlYmUgdGVuZXIgY3VpZGFkbyBkZSBubyB0cnVuY2FyIGVuIGV4Y2VzbywgZGViaWRvIGEgcXVlIGRhZGEyIHNvbG8gdGllbmUgZW4gY3VlbnRhIGxhIHNlY3VlbmNpYSBzb2xhcGFkYSBlbnRyZSBmb3J3YXJkIHkgcmV2ZXJzZSwgZW50b25jZXMgYWwgdHJ1bmNhciBkZSBtw6FzIGhhYnLDoSBwb2NvIHNvbGFwYW1pZW50bywgeSBtZW5vcyBkYXRvcyBzZXLDoW4gcHJvY2VzYWRvcyBwb3IgZGFkYTIuCgpgYGB7ciBldmFsPUZBTFNFfQojIEFyY2hpdm9zIGRvbmRlIHNlIGFsbWFjZW5hcsOhbiBsYXMgbXVlc3RyYXMgZmlsdHJhZGFzIHkgdHJ1bmNhZGFzCmZpbHRGcyA8LSBmaWxlLnBhdGgocGF0aCwgImZpbHRlcmVkIiwgcGFzdGUwKHNhbXBsZS5uYW1lcywgIl9GX2ZpbHQuZmFzdHEuZ3oiKSkgCmZpbHRScyA8LSBmaWxlLnBhdGgocGF0aCwgImZpbHRlcmVkIiwgcGFzdGUwKHNhbXBsZS5uYW1lcywgIl9SX2ZpbHQuZmFzdHEuZ3oiKSkKCiMgRmlsdHJhZG8geSB0cnVuY2FkbyBkZSBkYXRvcwpmaWx0ZXJBbmRUcmltX291dCA8LSBmaWx0ZXJBbmRUcmltKGZuRnMsIGZpbHRGcywgZm5ScywgZmlsdFJzLCB0cnVuY0xlbj1jKDI5MCwyMDApLCBtYXhOPTAsIG1heEVFPWMoMiwyKSwgdHJ1bmNRPTIsIHJtLnBoaXg9VFJVRSwgY29tcHJlc3M9VFJVRSwgbXVsdGl0aHJlYWQ9VFJVRSkKCiMgQWxtYWNlbmFyIHJlc3VsdGFkbwpzYXZlKGZpbHRlckFuZFRyaW1fb3V0LCBmaWxlPSJmaWx0ZXJBbmRUcmltX291dCIpCmBgYAoKQWwgc2VyIHVuYSBvcGVyYWNpw7NuIGNvc3Rvc2EsIHNlIGFsbWFjZW5hIGVsIHJlc3VsdGFkbyBlbiB1biBhcmNoaXZvIHBhcmEgZXZpdGFyIHJlY2FsY3VsYXI6CgpgYGB7cn0KbG9hZCgiZmlsdGVyQW5kVHJpbV9vdXQiKQpgYGAKCkVsIHJlc3VsdGFkbyBkZSBlc3RhIGZ1bmNpw7NuIGVzIHVuYSBtYXRyaXogcXVlIGNvbnRpZW5lIHBhcmEgY2FkYSBtdWVzdHJhLCBsYSBjYW50aWRhZCBkZSBzZWN1ZW5jaWFzIHF1ZSBleGlzdMOtYW4gb3JpZ2luYWxtZW50ZSwgeSBjdcOhbnRhcyByZXN1bHRhcm9uIGx1ZWdvIGRlbCBmaWx0cmFkby4KClBlcm1pdGUgaWRlbnRpZmljYXIgY3VhbnRhcyBsZWN0dXJhcyBmdWVyb24gZGVzY2FydGFkYXMuIEFkZW3DoXMsIGFsbWFjZW5hIGVuIGxvcyBhcmNoaXZvcyBlc3BlY2lmaWNhZG9zIChmaWx0RnMgeSBmaWx0UnMpIGxvcyByZXN1bHRhZG9zIGZpbHRyYWRvcy4KCmBgYHtyfQpjb2xfc3VtIDwtIGNvbFN1bXMoZmlsdGVyQW5kVHJpbV9vdXQpCmZpbHRlcmVkX3JlYWRzIDwtIGNvbF9zdW1bMV0gLSBjb2xfc3VtWzJdCgptZXNzYWdlKHNwcmludGYoIkZ1ZXJvbiBmaWx0cmFkYXMgJXMgbGVjdHVyYXMsIHVuICUlJS4yZiBkZSBsYXMgbGVjdHVyYXMgb3JpZ2luYWxlcy4iLCBmaWx0ZXJlZF9yZWFkcywgZmlsdGVyZWRfcmVhZHMgKiAxMDAgLyBjb2xfc3VtWzFdKSkKYGBgCgojIyAxLjQgQXByZW5kaXphamUgZGUgZXJyb3JlcwoKRGFkYTIgbmVjZXNpdGEgY29ub2NlciBsYXMgcHJvYmFiaWxpZGFkZXMgZGUgZXJyb3JlcyBwYXJhIHBvZGVyIGRlY2lkaXIgc2kgZG9zIHNlY3VlbmNpYXMgcXVlIHNlIGRpZmVyZW5jaWFuIGVuIDEgbyAyIGJhc2VzIHNvbiBsYSBtaXNtYSB5IGhheWEgb2N1cnJpZG8gdW4gZXJyb3IsIG8gc2VhbiByZWFsbWVudGUgZG9zIHNlY3VlbmNpYXMgZGlmZXJlbnRlcy4KClBvciBsbyB0YW50bywgc2UgZGViZSBlc3RpbWFyIGxvcyBlcnJvcmVzLCB5IG1vZGVsYXIgbGFzIHByb2JhYmlsaWRhZGVzIGRlIHF1ZSBoYXlhbiBvY3VycmlkbyB0cmFuc2ljaW9uZXMgKEEg4p+2IFQsIEEg4p+2IEMsIEMg4p+2IEEsIGV0Yyk6CgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIGZvcndhcmQKZXJyRiA8LSBsZWFybkVycm9ycyhmaWx0RnMsIG11bHRpdGhyZWFkPVRSVUUpCnNhdmUoZXJyRiwgZmlsZT0iZXJyRiIpCgojIHJldmVyc2UKZXJyUiA8LSBsZWFybkVycm9ycyhmaWx0UnMsIG11bHRpdGhyZWFkPVRSVUUpCnNhdmUoZXJyUiwgZmlsZT0iZXJyUiIpCmBgYAoKQWwgc2VyIHVuYSBvcGVyYWNpw7NuIGNvc3Rvc2EsIHNlIGFsbWFjZW5hIGVsIHJlc3VsdGFkbyBlbiB1biBhcmNoaXZvIHBhcmEgZXZpdGFyIHJlY2FsY3VsYXI6CgpgYGB7cn0KbG9hZCgiZXJyRiIpCmxvYWQoImVyclIiKQpgYGAKClNlIHB1ZWRlIG9ic2VydmFyIHF1ZSBsb3MgZXJyb3JlcyBzb24gYWNvcmRlcyBhIHN1cyBlc3RpbWFkb3MsIHlhIHF1ZSBwcmVzZW50YW4gZ3LDoWZpY29zIHNpbWlsYXJlczoKCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3RFcnJvcnMoZXJyRiwgbm9taW5hbFE9VFJVRSkKcGxvdEVycm9ycyhlcnJSLCBub21pbmFsUT1UUlVFKQpgYGAKCiMjIDEuNSBEZXJyZXBsaWNhY2lvbgoKTGEgZGVycmVwbGljYWNpb24gY29uc2lzdGUgZW4gY29udGFyIGxhcyBhcGFyaWNpb25lcyBkZSBjYWRhIHNlY3VlbmNpYSBlbiBsYXMgbXVlc3RyYXMsIGxvIGN1YWwgZXMgbmVjZXNhcmlvIHBhcmEgbHVlZ28gYWdydXBhciBsb3MgQVNWcyBlbmNvbnRyYWRvczoKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgZm9yd2FyZApkZXJlcEZzIDwtIGRlcmVwRmFzdHEoZmlsdEZzLCB2ZXJib3NlPVRSVUUpCm5hbWVzKGRlcmVwRnMpIDwtIHNhbXBsZS5uYW1lcwpzYXZlKGRlcmVwRnMsIGZpbGU9ICJkZXJlcEZzIikKCiMgcmV2ZXJzZQpkZXJlcFJzIDwtIGRlcmVwRmFzdHEoZmlsdFJzLCB2ZXJib3NlPVRSVUUpCm5hbWVzKGRlcmVwUnMpIDwtIHNhbXBsZS5uYW1lcwpzYXZlKGRlcmVwUnMsIGZpbGU9ICJkZXJlcFJzIikKYGBgCgpQYXJhIGV2aXRhciBlbCBjb3N0b3NvIGPDoWxjdWxvOgoKYGBge3J9CmxvYWQoImRlcmVwRnMiKQpsb2FkKCJkZXJlcFJzIikKYGBgCgpPYnRlbmnDqW5kb3NlIHBvciBtdWVzdHJhLCB1bmEgbWF0cml6IGNvbiBlbCBjb250ZW8gZGUgY2FkYSBzZWN1ZW5jaWEsIHkgc3VzIHNjb3JlcyBwcm9tZWRpbyBkZSBjYWxpZGFkLgoKIyMgMS42IElkZW50aWZpY2FyIEFTVnMgY29uIERBREEyCgpBaG9yYSBxdWUgc2UgdGllbmVuIGxvcyBkYXRvcyBwcm9udG9zIHBhcmEgYWdydXBhciwgc2UgaWRlbnRpZmljYW4gbG9zIEFTVnMgcGFyYSBsYXMgc2VjdWVuY2lhcyBmb3J3YXJkIHkgcmV2ZXJzZSB1dGlsaXphbmRvIGxhIGZ1bmNpw7NuIGRhZGE6CgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpkYWRhRnMgPC0gZGFkYShkZXJlcEZzLCBlcnI9ZXJyRiwgcG9vbCA9IFRSVUUgLCBtdWx0aXRocmVhZD1UUlVFKQpzYXZlKGRhZGFGcywgZmlsZT0iZGFkYUZzIikKCiNSZXZlcnNlIHJlYWRzCmRhZGFScyA8LSBkYWRhKGRlcmVwUnMsIGVycj1lcnJSLCBwb29sID0gVFJVRSAsIG11bHRpdGhyZWFkPVRSVUUpCnNhdmUoZGFkYVJzLCBmaWxlPSJkYWRhUnMiKQpgYGAKClBhcmEgZXZpdGFyIGVsIGNvc3Rvc28gY8OhbGN1bG86CgpgYGB7cn0KbG9hZCgiZGFkYUZzIikKbG9hZCgiZGFkYVJzIikKYGBgCgojIyAxLjcgSWRlbnRpZmljYXIgY3VhbnRhcyB2ZWNlcyBhcGFyZWNlIHVuIEFTViBlbiBjYWRhIG11ZXN0cmEKClBhcmEgZXN0bywgc2UgZGViZSB1bmlyIGxvcyBBU1ZzIGZvcndhcmQgeSByZXZlcnNlIGVuIHVuYSDDum5pY2Egc2VjdWVuY2lhOgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbWVyZ2VycyA8LSBtZXJnZVBhaXJzKGRhZGFGcywgZGVyZXBGcywgZGFkYVJzLCBkZXJlcFJzLCB2ZXJib3NlPVRSVUUpIApzYXZlKG1lcmdlcnMsIGZpbGU9Im1lcmdlcnMiKQpgYGAKClBhcmEgZXZpdGFyIGVsIGNvc3Rvc28gY8OhbGN1bG86CgpgYGB7cn0KbG9hZCgibWVyZ2VycyIpCmBgYAoKRWwgcmVzdWx0YWRvIGRlIGVzdGEgZnVuY2nDs24gZXMgdW5hIGxpc3RhIGRlIGRhdGFmcmFtZXMgY29uIGluZm9ybWFjacOzbiBzb2JyZSBsYSB1bmnDs24gZGUgbGFzIHNlY3VlbmNpYXMgZm9yd2FyZCB5IHJldmVyc2UsIHBvciBlamVtcGxvOiBzb2xhcGFtaWVudG8sIG1pc3NtYXRjaCwgZXRjLgoKRXN0YSBpbmZvcm1hY2nDs24gZXMgdXRpbGl6YWRhIHBhcmEgY29udGFyIGxhcyBhcGFyaWNpb25lcyBkZSBjYWRhIEFTViBlbiBjYWRhIG11ZXN0cmE6CgpgYGB7cn0Kc2VxdGFiIDwtIG1ha2VTZXF1ZW5jZVRhYmxlKG1lcmdlcnMpCmBgYAoKIyMgMS44IEZpbHRyYWRvIGRlIEFTVnMgcmVzdWx0YW50ZXMgeSBxdWltZXJhcwoKTGFzIHNlY3VlbmNpYXMgc2UgZXNwZXJhbiBxdWUgdGVuZ2FuIHVuIGxhcmdvIGRlbnRybyBkZSB1biBpbnRlcnZhbG8uIEVzdGUgaW50ZXJ2YWxvIHNlIGNhbGN1bGEgYSBwYXJ0aXIgZGUgbG9zIHByaW1lcnMsIGxhcmdvIGRlIGZvcndhcmQgeSByZXZlcnNlLCBwb3JxdWUgc2UgZXNwZXJhIHF1ZSBsYXMgc2VjdWVuY2lhcyB0ZW5nYW4gdW4gbGFyZ28gc2ltaWxhciBhbCBzb2xhcGFtaWVudG8gZGVsIGZvcndhcmQgeSByZXZlcnNlLgoKRW4gZXN0ZSBjYXNvIGVsIGludGVydmFsbyBlcyBlbnRyZSA0NDAgeSA0NjYsIHBvciBsbyB0YW50byBzZSBmaWx0cmFuIHRvZG9zIGxvcyBBU1YgcXVlIG5vIGxvIGN1bXBsYW46CgpgYGB7cn0Kc2VxdGFiIDwtIHNlcXRhYlssbmNoYXIoY29sbmFtZXMoc2VxdGFiKSkgJWluJSBzZXEoNDQwLDQ2NildCmBgYAoKQWRlbcOhcywgZXMgcG9zaWJsZSBxdWUgZXhpc3RhbiBxdWltZXJhcyBlbiBsb3MgZGF0b3MuIExhcyBxdWltZXJhcyBzb24gc2VjdWVuY2lhcyBtYWxmb3JtYWRhcyB5IG5vIGV4aXN0ZW50ZXMgcXVlIHB1ZWRlbiBhcGFyZWNlciBsdWVnbyBkZSBsYSBzZWN1ZW5jaWFjacOzbiwgeSBkZWJlbiBzZXIgZmlsdHJhZGFzOgoKYGBge3IgZXZhbD1GQUxTRX0Kc2VxdGFiLm5vY2hpbSA8LSByZW1vdmVCaW1lcmFEZW5vdm8oc2VxdGFiLCBtZXRob2Q9ImNvbnNlbnN1cyIsIG11bHRpdGhyZWFkPVRSVUUsIHZlcmJvc2U9VFJVRSkKc2F2ZShzZXF0YWIubm9jaGltLGZpbGU9InNlcXRhYi5ub2NoaW0iKQpgYGAKClBhcmEgZXZpdGFyIGVsIGNvc3Rvc28gY8OhbGN1bG86CgpgYGB7cn0KbG9hZCgic2VxdGFiLm5vY2hpbSIpCmBgYAoKIyMgMS45IFJlc3VtZW4gZGUgaW5mb3JtYWNpw7NuIHBlcmRpZGEgZHVyYW50ZSBlbCBwcm9jZXNvCgpFcyBwb3NpYmxlIG9idGVuZXIgbGEgY2FudGlkYWQgZGUgQVNWcyBmb3J3YXJkIHkgcmV2ZXJzZSAoZGVub2lzZWQpLCBjYW50aWRhZCBkZSBzZWN1ZW5jaWFzIHJlc3VsdGFudGVzIGRlbCBtZXJnZSwgeSBjYW50aWRhZCBkZSBBU1ZzIHJlc3VsdGFudGVzIGx1ZWdvIGRlIGVsaW1pbmFyIGxhcmdvcyBubyBlc3BlcmFkb3MgeSBxdWUgY29udGVuZ2FuIHF1aW1lcmFzLgoKRXN0b3MgY8OhbGN1bG9zIHBlcm1pdGVuIGlkZW50aWZpY2FyIGxhIGluZm9ybWFjacOzbiByZWNvcnRhZGEgZHVyYW50ZSBlbCBwcmVwcm9jZXNhbWllbnRvIGRlIGxvcyBkYXRvczoKCmBgYHtyfQojIEZ1bmNpb24gYXV4aWxpYXIgcGFyYSBjb250YXIgbG9zIHZhbG9yZXMgdW5pY29zIGRlIHVuYSBjb2xlY2Npw7NuCmdldE4gPC0gZnVuY3Rpb24oeCkgc3VtKGdldFVuaXF1ZXMoeCkpCgp0cmFjayA8LSBjYmluZChmaWx0ZXJBbmRUcmltX291dCwgc2FwcGx5KGRhZGFGcywgZ2V0TiksIHNhcHBseShkYWRhUnMsIGdldE4pLCBzYXBwbHkobWVyZ2VycywgZ2V0TiksIHJvd1N1bXMoc2VxdGFiLm5vY2hpbSkpCmNvbG5hbWVzKHRyYWNrKSA8LSBjKCJpbnB1dCIsICJmaWx0ZXJlZCIsICJkZW5vaXNlZEYiLCAiZGVub2lzZWRSIiwgIm1lcmdlZCIsICJub25jaGltIikgCnJvd25hbWVzKHRyYWNrKSA8LSBzYW1wbGUubmFtZXMKCiMgTW9zdHJhciByZXN1bHRhZG9zCmhlYWQodHJhY2spCnRvdGFsX25vbmNoaW0gPC0gc3VtKHRyYWNrWywgJ25vbmNoaW0nXSkKdG90YWxfaW5wdXQgPC1zdW0odHJhY2tbLCAnaW5wdXQnXSkKbWVzc2FnZShzcHJpbnRmKCJTZSBwZXJkaWVyb24gdW4gdG90YWwgZGUgJXMgbXVlc3RyYXMsIHVuICUlJS4yZiIsICB0b3RhbF9pbnB1dCAtIHRvdGFsX25vbmNoaW0sIHN1bSh0b3RhbF9ub25jaGltICogMTAwIC8gdG90YWxfaW5wdXQpKSkKYGBgCgojIyAxLjEwIFVuaWZpY2FyIGRhdG9zIGNvbiBQaHlsb3NlcQoKUGh5bG9zZXEgZXMgdW4gZnJhbWV3b3JrIHF1ZSBvZnJlY2UgZnVuY2lvbmFsaWRhZGVzIHBhcmEgYW5hbGl6YXIgbG9zIGRhdG9zLCBwb3IgZWplbXBsbyBkaXZlcnNpZGFkIGFsZmEsIGJldGEsIGFidW5kYW5jaWFzIGRpZmVyZW5jaWFsZXMsIGV0YywgZW4gYmFzZSBhIHRvZGEgbGEgaW5mb3JtYWNpw7NuIGRlIGxhcyBtdWVzdHJhcyBxdWUgc2UgaGF5YW4gcmVjb2xlY3RhZG8uCgpTZSBkZWJlIGNhcmdhciBsYSBiYXNlIGRlIGRhdG9zIHF1ZSBjb250aWVuZSBsYSB0YXhvbm9tw61hIChpbmZvcm1hY2lvbiBiaW9sb2dpY2EpIGRlIGxvcyBBU1ZzOgoKYGBge3IgZXZhbD1GQUxTRX0KdGF4YV9ndGRiIDwtIGFzc2lnblRheG9ub215KHNlcXRhYi5ub2NoaW0sICIiLCBtdWx0aXRocmVhZD1UUlVFKQpgYGAKClBhcmEgZXZpdGFyIGVsIGNvc3Rvc28gY8OhbGN1bG86CgpgYGB7cn0KbG9hZCgidGF4YV9ndGRiIikKYGBgCgpMdWVnbywgaW1wb3J0YXIgbGFzIG11ZXN0cmFzIHF1ZSBzZSB2YXlhbiBhIHV0aWxpemFyOgoKYGBge3J9CnNhbXBsZV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUocmVhZC50YWJsZSgic2FtcGxlRGF0YV9hbGltZW50b3MuY3N2IiwgaGVhZGVyPVRSVUUsIHNlcD0iLCIpKQpyb3duYW1lcyhzYW1wbGVfZGF0YSkgPC0gc2FtcGxlX2RhdGFbLDFdCmBgYAoKRmluYWxtZW50ZSwgY2FyZ2FyIGxvcyBkYXRvcyBhIFBoeWxvc2VxOgoKYGBge3J9CnBoeXNlcSA8LSBwaHlsb3NlcShvdHVfdGFibGUoc2VxdGFiLm5vY2hpbSwgdGF4YV9hcmVfcm93cz1GQUxTRSksc2FtcGxlX2RhdGEoc2FtcGxlX2RhdGEpLHRheF90YWJsZSh0YXhhX2d0ZGIpKSAKc2F2ZShwaHlzZXEsIGZpbGU9InBoeXNlcSIpCmBgYAoKIyAyLiBJbnRlcnByZXRhY2nDs24gZGUgcmVzdWx0YWRvcwoKIyMgMi4xIEFuw6FsaXNpcyBkZSBtdWVzdHJhcwoKUGFyYSBlbCBvYmpldGl2byBkZWwgZXN0dWRpbyBubyBlcyBuZWNlc2FyaW8gYW5hbGl6YXIgdG9kYXMgbGFzIG11ZXN0cmFzIHRvbWFkYXMsIGVzIHBvc2libGUgdG9tYXIgdW4gc3Vic2V0IMO6dGlsIHBhcmEgbGEgaW52ZXN0aWdhY2nDs24uIEVuIGVzdGUgY2Fzbywgc29uIGxhcyBtdWVzdHJhcyB0b21hZGFzIGluaWNpYWxtZW50ZSBkZSBsYSBwaWVsIGRlIGxvcyBjZXJkb3MsIHkgZW4gZWwgcmVjdG8gYW5hbC4KCmBgYHtyIHNwbGl0PUZBTFNFfQpwcyA8LSBzdWJzZXRfc2FtcGxlcyhwaHlzZXEsIFNhbXBsaW5nLnBvc2l0aW9uICVpbiUgYygiU3RpY2tpbmciLCAiQW5hbCBzd2FiIikpCnBzLnByb3AgPC0gdHJhbnNmb3JtX3NhbXBsZV9jb3VudHMocHMsIGZ1bmN0aW9uKE9UVSkgT1RVL3N1bShPVFUpKQoKbWVzc2FnZSgiQ2FudGlkYWQgZGUgbXVlc3RyYXM6ICIsIG5zYW1wbGVzKHBzKSwgIlxuIiwKICAgICAgICAiQ2FudGlkYWQgZGUgQVNWczogIiwgbnRheGEocHMpLCAiXG4iLAogICAgICAgICJDYW50aWRhZCBkZSBBU1ZzIG5vIHByZXNlbnRlcyBlbiBsYXMgbXVlc3RyYXM6ICIsIG50YXhhKHBydW5lX3RheGEodGF4YV9zdW1zKHBzKSA9PSAwLCBwcykpKQpgYGAKClNlIGZpbHRyYW4gbG9zIEFTViBxdWUgbm8gZXN0YW4gcHJlc2VudGVzIGVuIG5pbmd1bmEgbXVlc3RyYSwgcG9ycXVlIG5vIHNvbiB1dGlsZXM6CgpgYGB7cn0KcHMgPC0gcHJ1bmVfdGF4YSh0YXhhX3N1bXMocHMpID4gMCwgcHMpCmBgYAoKTGEgZGlzdHJpYnVjacOzbiBkZSBBU1YgcmVzdWx0YW50ZXMgcG9yIG11ZXN0cmEgc2UgcHVlZGUgYXByZWNpYXIgZW4gZWwgc2lndWllbnRlIGdyw6FmaWNvOgoKYGBge3J9CnJlYWRzX3Blcl9BU1YgPC0gZGF0YS5mcmFtZShucmVhZHM9c29ydCh0YXhhX3N1bXMocHMpKSwgVFJVRSwgU1ZzPSAxOm50YXhhKHBzKSkKCmdncGxvdChkYXRhPXJlYWRzX3Blcl9BU1YsYWVzKHggPSBTVnMsIHkgPSBucmVhZHMpKSArCiAgZ2VvbV9hcmVhIChzdGF0PSJpZGVudGl0eSIsIGZpbGwgPSAiIzY5QkUyOCIpICsKICBzY2FsZV94X2xvZzEwKCkKYGBgCgpDb21vIGRlbCBncmFuamVybyBBIHNlIG11ZXN0cmVhcm9uIGRvcyBjZXJkb3MsIGV4aXN0ZW4gY2VyY2EgZGVsIGRvYmxlIGRlIGxlY3R1cmFzIHF1ZSBsb3MgZGVtw6FzIGdyYW5qZXJvcy4KCmBgYHtyfQojIEZpbHRlciByZWFkcwpmaWx0ZXJlZF9yZWFkcyA8LSBkYXRhLmZyYW1lKAogICAgbnJlYWRzPXNvcnQoc2FtcGxlX3N1bXMocHMpKSwgCiAgICBGYXJtZXI9c2FtcGxlX2RhdGEocHMpJEZhcm1lciwKICAgIFBvc2l0aW9uPXNhbXBsZV9kYXRhKHBzKSRTYW1wbGluZy5wb3NpdGlvbiwgCiAgICBUUlVFLCAKICAgIHNhbXBsZXM9c2FtcGxlX2RhdGEocHMpJEZhcm1lciwgCiAgICB0eXBlID0gIlNhbXBsZXMiCikKCiMgUGxvdApnZ3Bsb3QoZmlsdGVyZWRfcmVhZHMsIGFlcyh4PXNhbXBsZXMsIHk9bnJlYWRzKSkgKwogIGdlb21fYmFyKGFlcyhjb2xvcj1Qb3NpdGlvbiwgZmlsbD1Qb3NpdGlvbiksIHN0YXQ9ImlkZW50aXR5IikgKyAKICBmYWNldF93cmFwKH5GYXJtZXIsIHNjYWxlcz0iZnJlZV94IikKYGBgCgojIyAyLjIgQWJ1bmRhbmNpYXMgcmVsYXRpdmFzCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIEdyYWZpY2FyIGFidW5kYW5jaWFzIHJlbGF0aXZhcyBwb3IgZmlsbwpwbG90X2Jhcihwcy5wcm9wLCB4PSJTYW1wbGUiLCBmaWxsPSJQaHlsdW0iKSArCiAgZmFjZXRfd3JhcCh+RmFybWVyLCBzY2FsZXM9ImZyZWVfeCIpICsKICBnZW9tX2JhcihhZXMoY29sb3I9UGh5bHVtLCBmaWxsPVBoeWx1bSksIHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249InN0YWNrIikKYGBgCgpFbiBlbCBncsOhZmljbyBhbnRlcmlvciBzZSBwdWVkZSB2ZXIgZW4gdG9kYXMgbGFzIG11ZXN0cmFzIHVuYSBncmFuIHByZXNlbmNpYSBkZSBiYWN0ZXJvaWRldGVzLCBsYXMgbWlzbWFzIHNvbiBjb211bmVzIGVuIGVsIGludGVzdGlubyBkZSBtdWNob3MgYW5pbWFsZXMuIEVzdGFzIGJhY3RlcmlhcyBwdWVkZW4gZGVzZW1wZcOxYXIgdW4gcGFwZWwgaW1wb3J0YW50ZSBlbiBsYSBkaWdlc3Rpw7NuIHkgbGEgYWJzb3JjacOzbiBkZSBudXRyaWVudGVzIGVuIGxvcyBhbmltYWxlcywgYXPDrSBjb21vIGVuIGxhIHNhbHVkIGdlbmVyYWwgZGUgc3Ugc2lzdGVtYSBkaWdlc3Rpdm8uCgpBZGVtw6FzLCBzZSBwdWVkZSB2ZXIgcHJlc2VuY2lhIGRlIGZ1c29iYWN0ZXJpb3RhcyBlbiBsYXMgbXVlc3RyYXMuIFNvbiBjb25vY2lkYXMgcG9yIHN1IGNhcGFjaWRhZCBwYXJhIGNhdXNhciBpbmZlY2Npb25lcyBlbiBsb3MgYW5pbWFsZXMsIGluY2x1eWVuZG8gaW5mZWNjaW9uZXMgb3JhbGVzLCBhYnNjZXNvcyB5IGVuZmVybWVkYWRlcyByZXNwaXJhdG9yaWFzLiBQb3IgZWplbXBsbywgZW4gbG9zIGNlcmRvcyBzZSBoYSBpbmZvcm1hZG8gcXVlIGxhcyBGdXNvYmFjdGVyaXVtIHB1ZWRlbiBlc3RhciBpbXBsaWNhZGFzIGVuIGNhc29zIGRlIG5lY3Jvc2lzIGhlcMOhdGljYSB5IGFic2Nlc29zLiBMYSBpbmZlY2Npw7NuIGNvbiBGdXNvYmFjdGVyaXVtIHB1ZWRlIHNlciBlbCByZXN1bHRhZG8gZGUgdW5hIGxlc2nDs24gZW4gbGEgcGllbCBvIHVuYSBpbmZlY2Npw7NuIHByZXZpYSwgbG8gcXVlIHBlcm1pdGUgcXVlIGxhcyBiYWN0ZXJpYXMgZW50cmVuIGVuIGVsIGN1ZXJwbyB5IGNhdXNlbiB1bmEgaW5mZWNjacOzbi4KCk90cmFzIGJhY3RlcmlhcyBwcmVzZW50ZXMgZW4gdG9kYXMgbGFzIG11ZXN0cmFzIHNvbiBkZWwgZmlsbyBTcGlyb2NoYWV0b3RhLCBsYXMgbWlzbWFzIHNvbiBjb25vY2lkYXMgcG9yIHNlciBwYXTDs2dlbmFzIHBlcm8gZXMgY29tw7puIGVuIGVsIHRyYWN0byBnYXN0cm9pbnRlc3RpbmFsIGRlIGxvcyBjZXJkb3MsIGF1bnF1ZSBubyBzZSBjb25zaWRlcmFuIHBhdMOzZ2VuYXMgZW4gZXN0ZSBjYXNvIHBhcmEgZWxsb3MuCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIEFidW5kYW5jaWFzIHJlbGF0aXZhcyBwb3IgZ8OpbmVybwp0c2UgPC0gbWFrZVRyZWVTdW1tYXJpemVkRXhwZXJpbWVudEZyb21QaHlsb3NlcShwcykgCnRzZSA8LSB0cmFuc2Zvcm1TYW1wbGVzKHRzZSwgbWV0aG9kID0gInJlbGFidW5kYW5jZSIpCnRzZSA8LSBhZGRUYXhvbm9teVRyZWUodHNlKQp0c2VfZ2VuIDwtIGFnZ2xvbWVyYXRlQnlSYW5rKHRzZSwgcmFuayA9ICJHZW51cyIpCnJvd25hbWVzKHRzZV9nZW4pPC1zdWIoIkdlbnVzOiIsIiIsIHJvd25hbWVzKHRzZV9nZW4pKQoKcGxvdEFidW5kYW5jZURlbnNpdHkodHNlX2dlbiwgbGF5b3V0ID0gImppdHRlciIsIGFidW5kX3ZhbHVlcz0icmVsYWJ1bmRhbmNlIiwgbiA9IDIwLCBwb2ludF9zaXplPTEsIHBvaW50X3NoYXBlPTE5LCBwb2ludF9hbHBoYT0wLjUsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXJfYnk9IkZhcm1lciIpICsgCiAgc2NhbGVfeF9sb2cxMChsYWJlbD1zY2FsZXM6OnBlcmNlbnQpCmBgYAoKRW4gZXN0ZSBvdHJvIGdyw6FmaWNvLCBzZSBwdWVkZSB2ZXIgbG9zIHBvcmNlbnRhamVzIGRlIGFidW5kYW5jaWEgcmVsYXRpdmEgZW50cmUgY2FkYSBnw6luZXJvLgoKQ29tbyBwb3IgZWplbXBsbywgY2FtcHlsb2JhY3RlciBlc3TDoSBwcmVzZW50ZSBlbiB1biBtw6FzIGRlIDEwJSBkZSBhYnVuZGFuY2lhIHJlbGF0aXZhIGVuIHVuYSBtdWVzdHJhIGRlbCBjZXJkbyBwZXJ0ZW5lY2llbnRlIGFsIGdyYW5qZXJvIEIuIENhbXB5bG9iYWN0ZXIgcHVlZGUgc2VyIHVuIHBhdMOzZ2VubyBxdWUgY2F1c2EgZW5mZXJtZWRhZGVzIGdhc3Ryb2ludGVzdGluYWxlcyBlbiBodW1hbm9zLCBwb3IgbG8gcXVlIGxhIHByZXNlbmNpYSBkZSBDYW1weWxvYmFjdGVyIGVuIGNlcmRvcyBwdWVkZSBwbGFudGVhciBwcmVvY3VwYWNpb25lcyBlbiB0w6lybWlub3MgZGUgc2VndXJpZGFkIGFsaW1lbnRhcmlhLiBMYSBiYWN0ZXJpYSBwdWVkZSB0cmFuc21pdGlyc2UgYSBsb3MgaHVtYW5vcyBhIHRyYXbDqXMgZGVsIGNvbnN1bW8gZGUgYWxpbWVudG9zIGNvbnRhbWluYWRvcyBjb24gQ2FtcHlsb2JhY3RlciwgY29tbyBjYXJuZSBjcnVkYSBvIGluc3VmaWNpZW50ZW1lbnRlIGNvY2lkYSwgYXPDrSBjb21vIGEgdHJhdsOpcyBkZWwgY29udGFjdG8gZGlyZWN0byBjb24gYW5pbWFsZXMgaW5mZWN0YWRvcy4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgQWJ1bmRhbmNpYSByZWxhdGl2YSBwb3IgZmFtaWxpYQp0c2VfZmFtaWx5IDwtIGFnZ2xvbWVyYXRlQnlSYW5rKHRzZSwgcmFuayA9ICJGYW1pbHkiKQpyb3duYW1lcyh0c2VfZmFtaWx5KTwtc3ViKCJGYW1pbHk6IiwiIiwgcm93bmFtZXModHNlX2ZhbWlseSkpCgpwbG90QWJ1bmRhbmNlRGVuc2l0eSh0c2VfZmFtaWx5LCBsYXlvdXQgPSAiaml0dGVyIiwgYWJ1bmRfdmFsdWVzPSJyZWxhYnVuZGFuY2UiLCBuID0gMjAsIHBvaW50X3NpemU9MSwgcG9pbnRfc2hhcGU9MTksIHBvaW50X2FscGhhPTAuNSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91cl9ieT0iRmFybWVyIikgKyBzY2FsZV94X2xvZzEwKGxhYmVsPXNjYWxlczo6cGVyY2VudCkKYGBgCgpMYXMgYmFjdGVyaWFzIHBlcnRlbmVjaWVudGVzIGEgbGEgZmFtaWxpYSBNb3JheGVsbGFjZWFlIHNlIGVuY3VlbnRyYW4gcHJlc2VudGUgZW4gdG9kYXMgbGFzIG11ZXN0cmFzIHBlcm8gbWF5b3JtZW50ZSBlbiBsb3MgY2hhbmNob3MgZGVsIGdyYW5qZXJvIEEgeSBDLiBNb3JheGVsbGFjZWFlIHB1ZWRlbiBjYXVzYXIgcHJvYmxlbWFzIGVuIGxhIGNhbGlkYWQgZGUgbGEgY2FybmUgZGUgY2VyZG8sIGNvbW8gZWwgb2xvciByYW5jaW8sIGxvIHF1ZSBwdWVkZSBzZXIgdW4gcHJvYmxlbWEgaW1wb3J0YW50ZSBwYXJhIGxhIGluZHVzdHJpYSBjw6FybmljYS4KCkxhcyBiYWN0ZXJpYXMgZW50ZXJvYmFjdGVyaWFjZWFlIHNvbiBwYXTDs2dlbmFzIHkgcHVlZGVuIGNhdXNhciBlbmZlcm1lZGFkZXMgY29tbyBsYSBzYWxtb25lbGxhLiBMYSBtaXNtYSBlc3TDoSBtw6FzIHByZXNlbnRlIGVuIGxhcyBtdWVzdHJhcyBkZWwgY2hhbmNobyBkZWwgZ3Jhbmplcm8gQi4KCiMjIDIuMyBEaXZlcnNpZGFkIGFsZmEKCkxhIGRpdmVyc2lkYWQgYWxmYSBlbiBtZXRhYmFyY29kaW5nIHNlIHJlZmllcmUgYSBsYSBkaXZlcnNpZGFkIGRlIGVzcGVjaWVzIG8gdGlwb3MgZGUgb3JnYW5pc21vcyBwcmVzZW50ZXMgZW4gdW5hIG11ZXN0cmEgZGUgQUROIGJpb2zDs2dpY28geSBzZSBwdWVkZSBtZWRpciB1dGlsaXphbmRvIHZhcmlvcyDDrW5kaWNlcywgY29tbyBlbCDDrW5kaWNlIGRlIFNpbXBzb24uCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcmFyZWZpZWQ8LXJhcmVmeV9ldmVuX2RlcHRoKHBzLG1pbihzYW1wbGVfc3VtcyhwcykpLHJuZ3NlZWQ9MSkKdHNlX3JhcmVmaWVkIDwtIG1ha2VUcmVlU3VtbWFyaXplZEV4cGVyaW1lbnRGcm9tUGh5bG9zZXEocmFyZWZpZWQpCiMgVW5pZm9ybWlkYWQKdHNlX3JhcmVmaWVkIDwtIGVzdGltYXRlRXZlbm5lc3ModHNlX3JhcmVmaWVkLCAKICAgICAgICAgICAgICAgICAgICAgICAgYWJ1bmRfdmFsdWVzID0gImNvdW50cyIsCiAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4PSJzaW1wc29uIikKCnBsb3RzIDwtIGxhcHBseShjKCJzaW1wc29uIiksCiAgICAgICAgICAgICAgICBwbG90Q29sRGF0YSwKICAgICAgICAgICAgICAgIG9iamVjdCA9IHRzZV9yYXJlZmllZCwKICAgICAgICAgICAgICAgIHggPSAiRmFybWVyIiwKICAgICAgICAgICAgICAgIGNvbG91cl9ieSA9ICJGYXJtZXIiKQoKcGxvdHMgPC0gbGFwcGx5KHBsb3RzLCAiKyIsIAogICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCkpKQoKcGxvdHNbWzFdXSArIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICJjb2xsZWN0IikKYGBgCgpMYSBncsOhZmljYSBkZSBkaXZlcnNpZGFkIGFsZmEgZGUgU2ltcHNvbiBtdWVzdHJhIGxhIHJpcXVlemEgZGUgZXNwZWNpZXMgeSBsYSBlcXVpdGFiaWxpZGFkIGVuIHVuYSBjb211bmlkYWQuIEVuIGVzdGEgZ3LDoWZpY2EsIGxhIGRpdmVyc2lkYWQgYWxmYSBzZSByZXByZXNlbnRhIGVuIGVsIGVqZSBkZSBsYXMgb3JkZW5hZGFzLCBtaWVudHJhcyBxdWUgZWwgdGFtYcOxbyBkZSBsYSBtdWVzdHJhIHNlIHJlcHJlc2VudGEgZW4gZWwgZWplIGRlIGFic2Npc2FzLgoKTGEgZGl2ZXJzaWRhZCBkZSBTaW1wc29uIHNlIGV4cHJlc2EgY29tbyB1biDDrW5kaWNlIGRlIGRvbWluYW5jaWEgeSBzZSBjYWxjdWxhIHJlc3RhbmRvIGxhIHN1bWEgZGUgbG9zIGN1YWRyYWRvcyBkZSBsYXMgcHJvcG9yY2lvbmVzIGRlIGNhZGEgZXNwZWNpZSBlbiBsYSBjb211bmlkYWQgZGUgdW5vLiBDdWFudG8gbcOhcyBjZXJjYW5vIHNlYSBlbCDDrW5kaWNlIGRlIFNpbXBzb24gYSAxLCBtZW5vciBzZXLDoSBsYSBkaXZlcnNpZGFkIGFsZmEsIGxvIHF1ZSBpbmRpY2EgdW5hIG1heW9yIGRvbWluYW5jaWEgZGUgdW5hIG8gdW5hcyBwb2NhcyBlc3BlY2llcyBlbiBsYSBjb211bmlkYWQuIFBvciBvdHJvIGxhZG8sIGN1YW50byBtw6FzIGNlcmNhbm8gc2VhIGVsIMOtbmRpY2UgZGUgU2ltcHNvbiBhIDAsIG1heW9yIHNlcsOhIGxhIGRpdmVyc2lkYWQgYWxmYSwgbG8gcXVlIGluZGljYSBxdWUgbGFzIGVzcGVjaWVzIGVzdMOhbiBkaXN0cmlidWlkYXMgZGUgbWFuZXJhIHVuaWZvcm1lIGVuIGxhIGNvbXVuaWRhZC4KCmBgYHtyfQptZXNzYWdlKCJJbmRpY2Ugc2ltcHNvbiBwcm9tZWRpbyBkZWwgZ3Jhbmplcm8gQjogIiwgbWVhbihzdWJzZXQoeCwgRmFybWVyID09ICJCIikkc2ltcHNvbikpCm1lc3NhZ2UoIkluZGljZSBzaW1wc29uIHByb21lZGlvIGRlbCBncmFuamVybyBBOiAiLCBtZWFuKHN1YnNldCh4LCBGYXJtZXIgPT0gIkEiKSRzaW1wc29uKSkKYGBgCgpFbiBlc3RlIGNhc28sIGxhcyBtdWVzdHJhcyBkZWwgZ3Jhbmplcm8gQiBwcmVzZW50YW4gdW4gbWVub3Igw61uZGljZSBzaW1wc29uIHByb21lZGlvLCBwb3IgbG8gdGFudG8gY3VlbnRhIGNvbiB1bmEgbWF5b3IgZGl2ZXJzaWRhZCBhbGZhLgoKUG9yIG90cm8gbGFkbywgbGFzIG11ZXN0cmFzIGRlbCBncmFuamVybyBBIHByZXNlbnRhbiB1biBtYXlvciDDrW5kaWNlIHNpbXBzb24gcXVlIGxhcyBkZW3DoXMgbXVlc3RyYXMsIHBvciBsbyB0YW50byBjdWVudGFuIGNvbiB1bmEgZGl2ZXJzaWRhZCBhbGZhIG1lbm9yLiBFc3RvIHB1ZWRlIHNpZ25pZmljYXIgcXVlIGV4aXN0ZSBtZW5vciBjYW50aWRhZCBkZSBiYWN0ZXJpYXMgZGlmZXJlbnRlcywgbyB1bmEgZ3JhbiBwcm9wb3JjacOzbiBkZSBsYXMgYmFjdGVyaWFzIHByZXNlbnRlcyBzb24gc2ltaWxhcmVzLgoKIyMgMi40IERpdmVyc2lkYWQgYmV0YQoKRW4gbWV0YWJhcmNvZGluZywgbGEgZGl2ZXJzaWRhZCBiZXRhIHNlIHJlZmllcmUgYSBsYSB2YXJpYWNpw7NuIGVuIGxhIGNvbXBvc2ljacOzbiBkZSBlc3BlY2llcyBlbnRyZSBkaWZlcmVudGVzIG11ZXN0cmFzLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBBZ2xvbWVyYWNpb24gcG9yIGfDqG5lcm8gbWFudGVuaWVuZG8gbG9zIE5BCnRzZV9nZW51cyA8LSBhZ2dsb21lcmF0ZUJ5UmFuayh0c2UsIHJhbmsgPSAiR2VudXMiKQp0c2VfZ2VudXNfbm90TkEgPC0gdHNlX2dlbnVzWyFpcy5uYShyb3dEYXRhKHRzZV9nZW51cykkR2VudXMpLCBdCnRzZV9nZW51c19ub3ROQSA8LSBydW5NRFModHNlX2dlbnVzX25vdE5BLCBGVU4gPSB2ZWdhbjo6dmVnZGlzdCwgbWV0aG9kID0gImJyYXkiLCBuYW1lID0gIlBDb0FfQkMiLCBleHByc192YWx1ZXMgPSAiY291bnRzIikKCiMgQ3JlYXRlIGdncGxvdCBvYmplY3QKcCA8LSBwbG90UmVkdWNlZERpbSh0c2VfZ2VudXNfbm90TkEsICJQQ29BX0JDIiwgY29sb3VyX2J5ID0gIkZhcm1lciIpCgojIEFkZCBleHBsYWluZWQgdmFyaWFuY2UgZm9yIGVhY2ggYXhpcwplIDwtIGF0dHIocmVkdWNlZERpbSh0c2VfZ2VudXNfbm90TkEsICJQQ29BX0JDIiksICJlaWciKTsKcmVsX2VpZyA8LSBlL3N1bShlW2U+MF0pICAgICAgICAgIApwICsgbGFicyh4ID0gcGFzdGUoIlBDb0EgMSAoIiwgcm91bmQoMTAwICogcmVsX2VpZ1tbMV1dLDEpLCAiJSIsICIpIiwgc2VwID0gIiIpLAogICAgICAgICAgICAgIHkgPSBwYXN0ZSgiUENvQSAyICgiLCByb3VuZCgxMDAgKiByZWxfZWlnW1syXV0sMSksICIlIiwgIikiLCBzZXAgPSAiIikpCmBgYAoKTG9zIHB1bnRvcyBlbiBsYSBncsOhZmljYSByZXByZXNlbnRhbiBsYXMgbXVlc3RyYXMgeSBzdSBwb3NpY2nDs24gc2UgYmFzYSBlbiBzdSBzaW1pbGl0dWQgYmlvbMOzZ2ljYS4gTGFzIG11ZXN0cmFzIHF1ZSBlc3TDoW4gbcOhcyBjZXJjYSBlbiBsYSBncsOhZmljYSBzZSBjb25zaWRlcmFuIG3DoXMgc2ltaWxhcmVzIGVuIHTDqXJtaW5vcyBkZSBzdSBjb21wb3NpY2nDs24gYmlvbMOzZ2ljYS4KCkFuYWxpemFuZG8gbGEgZ3LDoWZpY2Egc2UgcHVlZGUgY29uY2x1aXIgcXVlIGxhcyBtdWVzdHJhcyBjb2luY2lkZW4gY29uIGxvIGVzcGVyYWRvIHlhIHF1ZSBlbnRyZSBlbGxhcyBoYXkgY2llcnRhIGRpc3RhbmNpYSBsbyBxdWUgcmVmaWVyZSBhIHF1ZSBsYXMgbXVlc3RyYXMgbm8gdGllbmVuIGNvbXBvc2ljacOzbiBiaW9sw7NnaWNhIHNpbWlsYXIuCgojIDMuIENvbmNsdXNpw7NuCgpMdWVnbyBkZSBhbmFsaXphciBsYXMgbXVlc3RyYXMgYmFjdGVyaWFuYXMgZGUgbG9zIGNlcmRvcyBkZSBsb3MgdHJlcyBncmFuamVyb3MsIHNlIGVuY29udHLDsyBxdWUgZWwgY2VyZG8gZGVsIGdyYW5qZXJvIEIgdGVuw61hIGxhIG1heW9yIGNhbnRpZGFkIGRlIENhbXB5bG9iYWN0ZXIgeSBDaGxvcm9mbGV4aSBlbiBzdSB0cmFjdG8gZ2FzdHJvaW50ZXN0aW5hbC4gRXN0byBwdWVkZSBzZXIgcHJlb2N1cGFudGUgeWEgcXVlIGFtYmFzIGJhY3RlcmlhcyBzZSBzYWJlIHF1ZSBwdWVkZW4gY2F1c2FyIGVuZmVybWVkYWRlcyBlbiBsb3Mgc2VyZXMgaHVtYW5vcy4KCkxhIHByZXNlbmNpYSBkZSBDYW1weWxvYmFjdGVyIGVuIGxvcyBjZXJkb3MgZXMgcGFydGljdWxhcm1lbnRlIHByZW9jdXBhbnRlIHlhIHF1ZSBzZSBoYSBkZW1vc3RyYWRvIHF1ZSBlc3RhIGJhY3RlcmlhIHB1ZWRlIHNlciB1biBpbXBvcnRhbnRlIGZhY3RvciBkZSByaWVzZ28gcGFyYSBsYSB0cmFuc21pc2nDs24gZGUgZW5mZXJtZWRhZGVzIGFsaW1lbnRhcmlhcy4gQWRlbcOhcywgbGEgcmVzaXN0ZW5jaWEgYSBsb3MgYW50aW1pY3JvYmlhbm9zLgoKTGEgcHJlc2VuY2lhIGRlIENobG9yb2ZsZXhpIGVuIGxvcyBjZXJkb3MgdGFtYmnDqW4gcHVlZGUgc2VyIHByZW9jdXBhbnRlIHlhIHF1ZSBzZSBzYWJlIHF1ZSBhbGd1bmFzIGVzcGVjaWVzIHB1ZWRlbiBjYXVzYXIgZW5mZXJtZWRhZGVzIHJlc3BpcmF0b3JpYXMgZW4gbG9zIHNlcmVzIGh1bWFub3MuIEFkZW3DoXMsIHNlIHNhYmUgcXVlIGFsZ3VuYXMgYmFjdGVyaWFzIENobG9yb2ZsZXhpIHNvbiByZXNpc3RlbnRlcyBhIGxvcyBhbnRpbWljcm9iaWFub3MsIGxvIHF1ZSBwdWVkZSBjb21wbGljYXIgZWwgdHJhdGFtaWVudG8gZGUgbGFzIGVuZmVybWVkYWRlcyBjYXVzYWRhcyBwb3IgZXN0YXMgYmFjdGVyaWFzLgoKUG9yIG90cm8gbGFkbywgc2UgcHVlZGUgdmVyIHF1ZSBsYSBjYXJuZSBkZSBsb3MgZ3Jhbmplcm9zIEEgeSBDIHRpZW5lbiB1bmEgbWF5b3IgY2FudGlkYWQgZGUgTW9yYXhlbGxhY2VhZSBxdWUgbGEgY2FybmUgZGVsIGdyYW5qZXJvIEIuIExhIG1pc21hIHByZXNlbnRhIHVuIHJpZXNnbyBlbiB0w6lybWlub3MgZGUgZGVzcGVyZGljaW8gYWxpbWVudGljaW8gcGVybyBubyBkZSByaWVzZ28gaHVtYW5vLgoKQ29udGVzdGFuZG8gbGEgcHJlZ3VudGEgZGlzcGFyYWRvcmEgZGUgbGEgaW52ZXN0aWdhY2nDs24gc2UgcG9kcsOtYSBkZWNpciBxdWUgbGEgY2FybmUgZGVsIGdyYW5qZXJvIEIgZXMgbGEgcXVlIG1heW9yIHBlbGlncm9zaWRhZCB0aWVuZS4K