Elaborado por: Eliana Poveda
1. Predicción de los precios de las acciones. Analizar el
comportamiento de los precios de las Acciones de Ecopetrol según la
variación del precio del barril de petróleo WTI producido en Colombia.
Se tienen los siguientes precios.
library(readxl)
datos=ecopetrol <- read_excel("C:/Users/asus/Desktop/ecopetrol.xlsx")
View(ecopetrol)
cor(datos$Precio_accion,datos$Precio_barril)
[1] 0.7074373
Resultado: El coeficiente de correlación sugiere que hay una relacion
líneal fuerte y positiva entre las variables.Se observa que a mayor
precio_acciones el precio_barril aumenta y su relación es positiva de
acuerdo con el coeficiente de correlación de Pearson (0,7074).
ggplot(datos,aes(x=Precio_accion, y=Precio_barril))+geom_point()+theme_bw()+
geom_smooth(method = "lm")
`geom_smooth()` using formula 'y ~ x'

En la grafica se observa que hay una relación entre esta dos
variables, que inicialmente pareciera no ser necesariamente lineal
Ajuste del modelo
**B. Pruebe la significancia del modelo propuesto en “a)” plantee
las hipótesis respectivas y use el concepto de Valor _p para tomar la
decisión sobre las hipótesis. Use α = 0.05**
Resultado: El modelo de regresión propuesto para predecir el valor de
las acciones de ecopetrol es precioacción=177.77+(26.19∗preciobarril) en
donde β0=177 y β1=26.19 Ho = El modelo no es significativo Ha = El
modelo si es significativo
resumen$coefficients[2, ]
Estimate Std. Error t value Pr(>|t|)
26.192134618 6.541913749 4.003741966 0.001023938
Teniendo en cuenta que el valor_p es igual a 0.001023938 < 0.05 =
α, se debe rechazar Ho y aceptar Ha, con lo cual se concluye que el
valor de la pendiente es un predictor significativo para la ecuación del
precio de la acción de Ecopetrol.
Punto C. Interprete los coeficientes del modelo propuesto en
“a)
mod$coefficients
(Intercept) Precio_barril
177.76779 26.19213
Resultado: Según el modelo propuesto, por cada dolar adicional que
cueste un barril de petroleo el precio de la acción de Ecopetrol aumenta
en el 26,19 pesos colombianos. También, consierando B0 si el precio del
barril de petroleo fuera 0 entonces el precio de las acciones de
Ecopetrol serían de 177 pesos.
Punto D. Haga un análisis de los residuos. ¿Qué supuesto no
se cumple?
e=mod$residuals
par(mfrow=c(2,2))
plot(mod)

shapiro.test(mod$residuals)
Shapiro-Wilk normality test
data: mod$residuals
W = 0.89259, p-value = 0.04276
Resultado: Tanto lo que muestra la grafica Normal QQ como la prueba
shapiro se concluye que los residuos no siguen una distribución normal.
No se cumple la normalidad. También la graficas de residuales vs
ajustados muestran que los residuos no se comportan de forma aleatoria
como se esperaría. En conclusión no se cumplen los supuestos
relacionados con la normalidad y la aleatoriedad de los residuos.
Considerando los resultados obtenidos en el modelo propuesto, el uso de
este modelo no es recomendable para predecir el precio de la acción en
Ecopetrol, esto debido a que el modelo propuesto no cumple con los
supuestos y además el porcentaje de R2 toma un valor muy bajo.Por tanto,
se podría explorar una transformación de la variables con la finalidad
de poder ver si este supuesto se puede corregise.
2 PUNTO.SLLMV VS INFLACIÓN. Se busca realizar la predicción
del Salario Minimo (SMMLV) a partir de la variación de la inflación en
colombia. Para esto se plantea realizar una regresión lineal. Se van a
considerar los siguientes datos para su construcción
library(readxl)
datos2 <- read_excel("C:/Users/asus/Downloads/SMMLV.xlsx")
View(datos2)
Con la finalidad de observar la relación de estas dos variables, se
realiza un diagrama de dispesión con el fin de ver si es posible
explicar la variabilidad del salario minimo en funcion de la inflación
anual.
ggplot(datos2,aes(x=datos2$INFLACION, y=datos2$SMLM))+geom_point()+theme_bw()+
geom_smooth(method = "lm")
Warning: Use of `datos2$INFLACION` is discouraged. Use `INFLACION` instead.
Warning: Use of `datos2$SMLM` is discouraged. Use `SMLM` instead.
Warning: Use of `datos2$INFLACION` is discouraged. Use `INFLACION` instead.
Warning: Use of `datos2$SMLM` is discouraged. Use `SMLM` instead.
`geom_smooth()` using formula 'y ~ x'

Punto a. Escriba la ecuación del modelo de regresión lineal
simple
SMMLM=β0+β1Inflación+ϵ
mod2 = lm(datos2$SMLM ~datos2$INFLACION)
resumen2 = summary(mod2)
resumen2
Call:
lm(formula = datos2$SMLM ~ datos2$INFLACION)
Residuals:
Min 1Q Median 3Q Max
-75463 -63456 -42854 17623 263207
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 648486 58947 11.00 1.4e-08 ***
datos2$INFLACION -39489 10151 -3.89 0.00145 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 94130 on 15 degrees of freedom
Multiple R-squared: 0.5022, Adjusted R-squared: 0.469
F-statistic: 15.13 on 1 and 15 DF, p-value: 0.00145
PuntoB. Plantee y valide las hipótesis correspondientes a la
linealidad general del modelo propuesto en a)
mean(mod2$residuals)
[1] -1.491304e-12
shapiro.test(mod2$residuals)
Shapiro-Wilk normality test
data: mod2$residuals
W = 0.78826, p-value = 0.001407
library(lmtest)
bptest(mod2)
studentized Breusch-Pagan test
data: mod2
BP = 0.61478, df = 1, p-value = 0.433
Resultado: Por un lado, la prueba de Shapiro - Wilk arroja que el
p_value es 0.001407 < 0.05, por lo tanto, se rechaza la hipotesis
nula y se concluye que los residuos no vienen de una distribución
normal.Frente a la media de los errores estos estan muy cercanos a cero
. Asimismo, se detecta, según la prueba Breusch-Pagan, donde Ho =
Homocedasticidad (los residuos se distibuyen con la misma varianza) y Ha
= Heterocedasticidad (los residuos no se distribuyen con la misma
varianza), que el un p-value de 0.433 > 0.05, por lo tanto, no se
rechaza Ho, por lo que se evidencia que la varianza de los residuos es
homocedastica. En conclusión, los residuales no cumplen con el supuesto
de normalidad, por lo que los datos no se ajustan adecuadamente a un
modelo lineal.
Punto C. Indique e interprete el coeficiente de correlación
del modelo propuesto en a)
Resultado: coeficiente de correlación del modelo propuesto es de
R2=0.5022, por lo que explica en un 50.22% la variabilidad del salario
de acuerdo a la inflación
Punto D. Interprete cada uno de los coeficientes del modelo
propuesto en a)
Resultado: Los que nos indica el modelo es que el B0 nos dice que si
la inflacion es cero, entonces el salario minimo legal sera de $648.486
aproximadamente. Por otro lado, Lo que indica la pendiente b1, es cual
es la disminucion del salario minimo legal por cada incremento en una
unidad de inflacion, es decir, que si la inflacion aumenta en un 1%
entonces, el salario minimo legal disminuira $39.489 aproximadamente.
Por otro lado, los valores del valor P nos dice que el coeficiente b1 si
es significativo porque este es igual a cero entonces se rechaza H0.
Además, el R2 nos dice que la inflacion explica en un 46.9% el salario
minimo
Punto E.Construya una gráfica de residuales y haga un
análisis cualitativo de los supuestos del modelo propuesto en
a
e=mod2$residuals
par(mfrow=c(2,2))
plot(mod2)

Resultado: Para el valor de la Media cero: Se cumple, no se presenta
novedad.Frente a la Varianza Constante: Se puede observar que el modelo
propuesto no cumple con este supuesto. Es posible identificar que los
errores no son aleatorios y que el modelo no es lineal. Para la
Normalidad: En el grafico se puede observar que los datos no se ajustan
del todo a la línea de normalidad. Respecto la Independencia: Teniendo
en cuenta que los registros corresponden a datos en el tiempo, se indica
que son de orden temporal. En conclusión se debe transformar el modelo
de regresion lineal, ya que en el grafico de ajuste no se cumple la
aleatoridad de los errores.
Punto F.Comente sobre la conveniencia de usar el modelo
propuesto en a) para predecir el SMLM para Colombia
Resultado: Considerando los resultados obtenidos en el modelo
propuesto, se puede indicar que no es recomendable el uso de este modelo
para predecir el SLML en Colombia, esto debido a que el modelo propuesto
no cumple con los supuestos y además el porcentaje de R2 toma un valor
muy bajo.
Punto a. Realice un filtro a la base de datos e incluya solo
las ofertas de apartamentos, de la zona norte de la ciudad con precios
inferiores a los 500 millones de pesos y áreas menores a 300 mt2.
Presente los primeros 3 registros de la base y algunas tablas que
comprueben la consulta. (¿Adicional un mapa con los puntos de la base,
discutir si todos los puntos se ubican en la zona norte o se presentan
valores en otras zonas, por qué?).
head(datos_vivienda)
pos=which (datos_vivienda$Tipo== "Apartamento" & datos_vivienda$Zona == "Zona Norte" & datos_vivienda$precio_millon < 500 & datos_vivienda$Area_contruida < 300)
viviendas = datos_vivienda[pos,]
viviendas <- transform(viviendas, parqueaderos = as.numeric(parqueaderos))
Warning in eval(substitute(list(...)), `_data`, parent.frame()) :
NAs introduced by coercion
viviendas[is.na(viviendas)] <- 0
head(viviendas, 15)
NA
require(leaflet)
Loading required package: leaflet
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
leaflet() %>% addCircleMarkers(lng = datos_vivienda$cordenada_longitud,lat = datos_vivienda$Cordenada_latitud,radius = 0.3,color = "black",label = datos_vivienda$ID) %>% addTiles()
Warning in validateCoords(lng, lat, funcName) :
Data contains 3 rows with either missing or invalid lat/lon values and will be ignored
Warning: Unknown or uninitialised column: `ID`.
Punto b. Realice un análisis exploratorio de datos enfocado
en la correlación entre la variable respuesta (precio del apartamento)
en función del área construida, estrato y si tiene parqueadero. Use
gráficos interactivos con plotly e interprete los
resultados
Grafico area construida vs precio
graf1 <- plot_ly(data = datos_vivienda, x =~datos_vivienda$Area_contruida , y = ~datos_vivienda$precio_millon ,
marker = list(size = 10,
color = 'lightblue',
line = list(color = 'blue',
width = 2)))
graf1 <- graf1 %>% layout(title = 'Precio Vivienda vs Area Construida',
yaxis = list(zeroline = FALSE),
xaxis = list(zeroline = FALSE))
graf1
No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plotly.com/r/reference/#scatter
No scatter mode specifed:
Setting the mode to markers
Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
Warning: Ignoring 3 observations
No trace type specified:
Based on info supplied, a 'scatter' trace seems appropriate.
Read more about this trace type -> https://plotly.com/r/reference/#scatter
No scatter mode specifed:
Setting the mode to markers
Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode
Warning: Ignoring 3 observations
Resultado: la correlacion nos dice que existen una relacion positiva
entre el precio y el area construida, es decir que, mientras el area
construida sea mayor el precio sera mas alto.
Precio_millon vs Estrato
require(ggplot2)
require(plotly)
graf2= ggplot(datos_vivienda = datos_vivienda, mapping = aes(x= datos_vivienda$Estrato, y=datos_vivienda$precio_millon))+ geom_point()+geom_smooth()
ggplotly(graf2)
`geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
Warning: Removed 3 rows containing non-finite values (stat_smooth).
Warning: Computation failed in `stat_smooth()`:
x has insufficient unique values to support 10 knots: reduce k.
Resultado:Es posible advertir, de acuerdo con el grafico, una
relación directa entre las dos variables, es decir, entre mayor sea el
estrato, mayor es el precio de la vivienda.
Grafica precios por millon vs # Parquederos
require(ggplot2)
require(plotly)
graf3= ggplot(datos_vivienda = datos_vivienda, mapping = aes(x=datos_vivienda$parqueaderos, y= datos_vivienda$precio_millon))+ geom_point()+geom_smooth()
ggplotly(graf3)
`geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'
Warning: Removed 2 rows containing non-finite values (stat_smooth).
Resultado: El grafico no da cuenta de una relación existente entre el
numero de parqueaderos vs el precio de la vivienda.
C. Estime un modelo de regresión lineal múltiple con las
variables del punto anterior e interprete los coeficientes si son
estadísticamente significativos. Las interpretaciones deber están
contextualizadas y discutir si los resultados son lógicos.
Adicionalmente interprete el coeficiente R2 y discuta el ajuste del
modelo e implicaciones (que podrían hacer para mejorarlo).
modelo_viviendas = lm(formula= precio_millon ~ Area_contruida + Estrato + parqueaderos, data = viviendas )
summary(modelo_viviendas)
Call:
lm(formula = precio_millon ~ Area_contruida + Estrato + parqueaderos,
data = viviendas)
Residuals:
Min 1Q Median 3Q Max
-216.571 -31.564 -1.213 27.889 224.053
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -157.38220 7.71190 -20.408 < 2e-16 ***
Area_contruida 0.94938 0.06054 15.682 < 2e-16 ***
Estrato 68.99436 2.26623 30.445 < 2e-16 ***
parqueaderos 22.64906 2.73064 8.294 3.24e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 53.75 on 1073 degrees of freedom
Multiple R-squared: 0.7629, Adjusted R-squared: 0.7623
F-statistic: 1151 on 3 and 1073 DF, p-value: < 2.2e-16
Resultado: Con los resultados anteriores se puede expresar el modelo
ajustado como se muestra a continuación:
Preciomillon=−157.38220+0.94938x1i+68.99436x3i+22.64906x2i R2=0.7623
a)El valor del R cuadrado = 0.7623 significa que la variables: area
construida, estrato y parquaderos explican el 76% del precio del
apartamento. b)Se pueden interpretar los efectos B de la siguiente
forma: -Si el área construida de la vivienda aumenta 1mts2, se espera
que el precio por millon de la vivienda aumente en -.94 millones. -Si el
estrato de la vivienda aumenta en 1, el precio por millon de la vivienda
aumente en 22.64 millones. -Por cada parqueadero adicional, se espera
que el precio por millon de la vivienda aumente en 15.55661 millones.
-En este contexto el intercepto de -157.38, lo que no es lógico porque
no hay un costo de valor negativo para una vivienda -El coeficiente R2
ajustado de 0.76 lo que indica que el precio de la vivienda es explicado
por el modelo en un 76%
Punto d. Realice la validación de supuestos del modelo e
interprete los resultados (no es necesario corregir en caso de presentar
problemas solo realizar sugerencias de que se podría
hacer).
par(mfrow = c(2, 2))
plot(modelo_viviendas)

library(lmtest)
bptest(modelo_viviendas)
studentized Breusch-Pagan test
data: modelo_viviendas
BP = 156.86, df = 3, p-value < 2.2e-16
Resultado:Según las gráficas se puede concluir lo siguiente:
1)Gràfica NormalQQ: d es posible evidenciar que los errores no siguen el
supuesto de normalidad. 2)Asimismo, los residuales no son homocedasticos
de acuerdo con la gráfica Scale Location y la prueba de Breush-Pagan, la
cual dio un p_valor muy próximo a 0 por lo que se rechaza la hipotesis
nula de homocedasticidad. Se concluye que los residuales no cumplen con
el supuesto de normalidad ni homocedasticidad, por lo que los datos no
se ajustan adecuadamente a un modelo lineal.
Punto e. Con el modelo identificado predecir el precio de un
apartamento con 100 mt2, de estrato 4 y con parqueadero. ¿Si este
apartamento lo están ofreciendo en 450 millones cual seria su opinión
con base en el resultado del modelo considera que es una buena
oferta?
-473.29+(0.9787*100)+(87.11*1)+(125.24*4)
[1] 212.65
Resultado: Considerando los valores obtenidos del modelo, no es buena
opción comprar el apartamento que estan ofreciendo por 450 millones,
dado que el modelo registra un valor de compra aproximado de 212
millones.
Punto f.Con las predicciones del modelo sugiera potenciales
ofertas para una persona interesada en un apartamento en la zona norte
con mas de 100 mt2 de área, de estrato 4, que tenga parqueadero y tenga
encuenta que la persona tiene un crédito preaprobado de máximo 400
millones de pesos. Realice un análisis y presente en un mapa al menos 5
ofertas potenciales que debe discutir
oferta = which(datos_vivienda$Tipo=="Apartamento"& datos_vivienda$Zona=="Zona Norte"& datos_vivienda$precio_millon<=400 & datos_vivienda$Area_contruida>100 & datos_vivienda$Estrato == 4 & datos_vivienda$parqueaderos >= 1)
oferta_2=datos_vivienda[oferta,]
oferta_final = head(oferta_2,5)
oferta_final
oferta1 = predict(modelo_viviendas,list(Area_contruida=123,Estrato=4,parqueaderos=1))
oferta2 = predict(modelo_viviendas,list(Area_contruida=130,Estrato=4,parqueaderos=1))
oferta3 = predict(modelo_viviendas,list(Area_contruida=108,Estrato=4,parqueaderos=1))
oferta4 = predict(modelo_viviendas,list(Area_contruida=104,Estrato=4,parqueaderos=1))
oferta5 = predict(modelo_viviendas,list(Area_contruida=125,Estrato=4,parqueaderos=2))
data.frame(oferta1,oferta2,oferta3,oferta4,oferta5)
NA
Resultado: Considerando que la persona tiene un crédito preaprobado
por un valor de 400 millones se sugiere al comprador ofertas de
apartamento en zona norte, estrato 4 y con posibilidad de 1 o 2
parqueaderos y área construida mayor a 100mt2. Cualquiera de las ofertas
alcanza al comprador, según el preaprobado con el que cuenta.
library(leaflet)
leaflet() %>% addCircleMarkers(lng = oferta_final$cordenada_longitud,lat = oferta_final$Cordenada_latitud,radius = 5,color = "red",label = oferta_def$ID) %>% addTiles()
Warning: Unknown or uninitialised column: `ID`.
Punto 4 Con base en los datos de arboles proponga un modelo
de regresión lineal múltiple que permita predecir el peso del árbol en
función de las covariables que considere importantes y seleccionándolas
de acuerdo con un proceso adecuado. Tenga en cuenta realizar una
evaluación de la significancia de los parámetros, interpretación y
proponga un método de evaluación por medio de validación cruzada.
Presente métricas apropiadas como el RMSE y MAE.
library(readxl)
dataarboles <- read_excel("C:/Users/asus/Desktop/dataarboles.xlsx",
col_types = c("text", "text", "numeric",
"numeric", "numeric"))
View(dataarboles)
dataarboles=dataarboles[, 3:5]
attach(dataarboles)
The following objects are masked from dataarboles (pos = 3):
altura, diametro, peso
The following objects are masked from dataarboles (pos = 4):
altura, diametro, peso
The following objects are masked from arboles:
altura, diametro, peso
The following objects are masked from dataarboles (pos = 16):
altura, diametro, peso
The following objects are masked from dataarboles (pos = 17):
altura, diametro, peso
The following objects are masked from dataarboles (pos = 18):
altura, diametro, peso
The following objects are masked from dataarboles (pos = 19):
altura, diametro, peso
names(dataarboles)
[1] "peso" "diametro" "altura"
ggpairs(dataarboles, lower = list(continuous = "smooth"),
diag = list(continuous = "barDiag"), axisLabels = "none")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Resultado: de las gráficas se puede concluir que las variables que
tienen una mayor relación lineal con la peso son el diametro (0.908),
altura ( 0.858). Tambien, e diametro y altura están correlacionados (
0.936).
Modelo de regresión multiple
set.seed(1)
train <- sample(x = 1:90, 72)
modelo_arboles <- lm(peso~diametro + altura, data = arboles, subset = train)
summary(modelo_arboles)
Call:
lm(formula = peso ~ diametro + altura, data = arboles, subset = train)
Residuals:
Min 1Q Median 3Q Max
-6.6550 -2.4204 0.4327 1.8321 10.6024
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -9.2952 1.6058 -5.788 1.91e-07 ***
diametro 4.0257 0.8240 4.886 6.43e-06 ***
altura 0.9855 0.6525 1.510 0.136
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 3.455 on 69 degrees of freedom
Multiple R-squared: 0.8375, Adjusted R-squared: 0.8328
F-statistic: 177.8 on 2 and 69 DF, p-value: < 2.2e-16
Con los resultados anteriores se puede expresar el modelo ajustado
como se muestra a continuación:
Y()=−9.29+4.02∗X1(Diametro)+0.98∗X2(Altura) Se pueden interpretar los
efectos β de la siguiente forma: _ De acuerdo a los cálculos observados
si el diámetro del árbol aumenta en una unidad, se espera que el peso
del árbol aumente en 4.02 unidades. _ De igual manera se puede indicar
que por cada metro adicional en la altura del árbol, se esperaría que el
peso del árbol aumente en 0.98 unidades. _ De esta manera el intercepto
de -9.1205, no es un valor , dado que no debería existir un árbol con un
peso negativo. _ De igual forma el coeficiente R2 ajustado toma un valor
de 0.83, lo cual indica que el peso del árbol es explicado por el modelo
con un 83%.
par(mfrow=c(2,2))
plot(modelo_arboles)

Validación del modelo
Resultado: 1. Media cero: Se cumple por defecto. 2. Varianza
Constante: Se observa en la grafica 1 de residuales vs ajustados que el
comportamiento es aleatorio mostrando una leve curva hacia abajo. 3.
Normalidad: Se observa en la grafica 2 que los datos se ajustan bien a
la linea de normalidad en el qqplot 4. Independencia: Dado que estos
registros no corresponden a datos en el tiempo no se tiene un orden
temporal para realizar la validación de este supuesto.
Hipótesis nula H0: Para este caso el coeficiente B1 no aporta al
modelo propuesto, dado que el p-value es menor al 0.05 con valor
correspondiente a.(6.43e-06 ), rechazamos la hipótesis nula, y se puede
concluir que el coeficiente B1 si aporta al modelo de regresión
propuesto.
_ Hipótesis nula H0: Para este caso el coeficiente B2 no aporta al
modelo propuesto, como el p-value es mayor al 0.05 (0.136), NO
rechazamos la hipótesis nula, y concluimos que el coeficiente B2 NO
aporta al modelo de regresión propuesto.
Métricas RMSE y MAE
prediccion_arboles <- predict(object = modelo_arboles, newdata = dataarboles[-train, ])
error_arboles <- mean((dataarboles$peso[-train] - prediccion_arboles)^2)
error_arboles
[1] 13.47297
library(Metrics)
mae(arboles$peso[-train], prediccion_arboles)
[1] 3.01947
Resultado: Teniendo en cuenta las validaciones se puede indicar que
el modelo se equivoca en un 13% del peso promedio de acuerdo al MAE y la
desviación estándar de la varianza inexplicada es de 3.0 de acuerdo al
RMSE.
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCg0KLS0tDQpFbGFib3JhZG8gcG9yOiBFbGlhbmEgUG92ZWRhDQoNCg0KIyMgKioxLiBQcmVkaWNjacOzbiBkZSBsb3MgcHJlY2lvcyBkZSBsYXMgYWNjaW9uZXMuIEFuYWxpemFyIGVsIGNvbXBvcnRhbWllbnRvIGRlIGxvcyBwcmVjaW9zIGRlIGxhcyBBY2Npb25lcyBkZSBFY29wZXRyb2wgc2Vnw7puIGxhIHZhcmlhY2nDs24gZGVsIHByZWNpbyBkZWwgYmFycmlsIGRlIHBldHLDs2xlbyBXVEkgcHJvZHVjaWRvIGVuIENvbG9tYmlhLiBTZSB0aWVuZW4gbG9zIHNpZ3VpZW50ZXMgcHJlY2lvcyoqLg0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHhsKQ0KZGF0b3M9ZWNvcGV0cm9sIDwtIHJlYWRfZXhjZWwoIkM6L1VzZXJzL2FzdXMvRGVza3RvcC9lY29wZXRyb2wueGxzeCIpDQpWaWV3KGVjb3BldHJvbCkNCmBgYA0KDQpgYGB7cn0NCmNvcihkYXRvcyRQcmVjaW9fYWNjaW9uLGRhdG9zJFByZWNpb19iYXJyaWwpDQpgYGANClJlc3VsdGFkbzogRWwgY29lZmljaWVudGUgZGUgY29ycmVsYWNpw7NuIHN1Z2llcmUgcXVlIGhheSB1bmEgcmVsYWNpb24gbMOtbmVhbCBmdWVydGUgeSBwb3NpdGl2YSBlbnRyZSBsYXMgdmFyaWFibGVzLlNlIG9ic2VydmEgcXVlIGEgbWF5b3IgcHJlY2lvX2FjY2lvbmVzIGVsIHByZWNpb19iYXJyaWwgYXVtZW50YSB5IHN1IHJlbGFjacOzbiBlcyBwb3NpdGl2YSBkZSBhY3VlcmRvIGNvbiBlbCBjb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs24gZGUgUGVhcnNvbiAoMCw3MDc0KS4NCg0KYGBge3J9DQpnZ3Bsb3QoZGF0b3MsYWVzKHg9UHJlY2lvX2FjY2lvbiwgeT1QcmVjaW9fYmFycmlsKSkrZ2VvbV9wb2ludCgpK3RoZW1lX2J3KCkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpDQpgYGANCkVuIGxhIGdyYWZpY2Egc2Ugb2JzZXJ2YSBxdWUgaGF5IHVuYSByZWxhY2nDs24gZW50cmUgZXN0YSBkb3MgdmFyaWFibGVzLCBxdWUgaW5pY2lhbG1lbnRlIHBhcmVjaWVyYSBubyBzZXIgbmVjZXNhcmlhbWVudGUgbGluZWFsDQoNCg0KIyMgKipBanVzdGUgZGVsIG1vZGVsbyoqDQojIyAqKlB1bnRvIGEuUHJvcG9uZ2EgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIHNpbXBsZSBxdWUgcGVybWl0YSBwcmVkZWNpciBlbCB2YWxvciBkZSBsYXMgQWNjaW9uZXMgZGUgRWNvcGV0cm9sIGNvbiBiYXNlIGVuIGVsIFByZWNpbyBkZWwgYmFycmlsIGRlIHBldHLDs2xlbyBlbiBDb2xvbWJpYS4gSW5kaXF1ZSBsYSBlY3VhY2nDs24gZGUgcmVncmVzacOzbiB5IGVsIHZhbG9yIGRlbFIyLkxhIHJlZ3Jlc2nDs24gc2UgZXN0cnVjdHVyYXLDrWEgZGUgbGEgc2lndWllbnRlIGZvcm1hKio6IA0KIA0KUHJlY2lvX2FjY2lvbj3OsjArzrIxUHJlY2lvX2JhcnJpbCvPtQ0KIA0KYGBge3J9DQptb2Q9bG0oUHJlY2lvX2FjY2lvbn5QcmVjaW9fYmFycmlsLGRhdGEgPSBkYXRvcykNCnJlc3VtZW49c3VtbWFyeShtb2QpDQpyZXN1bWVuDQpgYGANCnJlc3VsdGFkbzogRWwgdmFsb3IgZGVsIFIgY3VhZHJhZG8gPSAwLjUwIHNpZ25pZmljYSBxdWUgbGEgdmFyaWFibGUgcHJlY2lvX2JhcnJpbCBleHBsaWNhIGVsIDUwJSBkZWwgcHJlY2lvIGRlIGxhcyBhY2Npb25lcy4NCg0KDQojIyAqKkIuIFBydWViZSBsYSBzaWduaWZpY2FuY2lhIGRlbCBtb2RlbG8gcHJvcHVlc3RvIGVuICJhKSIgcGxhbnRlZSBsYXMgaGlww7N0ZXNpcyByZXNwZWN0aXZhcyB5IHVzZSBlbCBjb25jZXB0byBkZSBWYWxvciBfcCBwYXJhIHRvbWFyIGxhIGRlY2lzacOzbiBzb2JyZSBsYXMgaGlww7N0ZXNpcy4gVXNlIM6xID0gMC4wNSoqDQoNClJlc3VsdGFkbzogRWwgbW9kZWxvIGRlIHJlZ3Jlc2nDs24gcHJvcHVlc3RvIHBhcmEgcHJlZGVjaXIgZWwgdmFsb3IgZGUgbGFzIGFjY2lvbmVzIGRlIGVjb3BldHJvbCBlcyANCnByZWNpb2FjY2nDs249MTc3Ljc3KygyNi4xOeKIl3ByZWNpb2JhcnJpbCkgIGVuIGRvbmRlIM6yMD0xNzcgeSDOsjE9MjYuMTkNCkhvID0gRWwgbW9kZWxvIG5vIGVzIHNpZ25pZmljYXRpdm8gSGEgPSBFbCBtb2RlbG8gc2kgZXMgc2lnbmlmaWNhdGl2bw0KDQpgYGB7cn0NCnJlc3VtZW4kY29lZmZpY2llbnRzWzIsIF0NCmBgYA0KVGVuaWVuZG8gZW4gY3VlbnRhIHF1ZSBlbCB2YWxvcl9wIGVzIGlndWFsIGEgMC4wMDEwMjM5MzggPCAwLjA1ID0gzrEsICBzZSBkZWJlIHJlY2hhemFyIEhvIHkgYWNlcHRhciBIYSwgY29uIGxvIGN1YWwgc2UgY29uY2x1eWUgcXVlIGVsIHZhbG9yIGRlIGxhIHBlbmRpZW50ZSBlcyB1biBwcmVkaWN0b3Igc2lnbmlmaWNhdGl2byBwYXJhIGxhIGVjdWFjacOzbiBkZWwgcHJlY2lvIGRlIGxhIGFjY2nDs24gZGUgRWNvcGV0cm9sLg0KDQoNCiMjICoqUHVudG8gQy4gSW50ZXJwcmV0ZSBsb3MgY29lZmljaWVudGVzIGRlbCBtb2RlbG8gcHJvcHVlc3RvIGVuICJhKSoqDQoNCmBgYHtyfQ0KbW9kJGNvZWZmaWNpZW50cw0KDQpgYGANCg0KUmVzdWx0YWRvOiAgU2Vnw7puIGVsIG1vZGVsbyBwcm9wdWVzdG8sIHBvciBjYWRhIGRvbGFyIGFkaWNpb25hbCBxdWUgY3Vlc3RlIHVuIGJhcnJpbCBkZSBwZXRyb2xlbyBlbCBwcmVjaW8gZGUgbGEgYWNjacOzbiBkZSBFY29wZXRyb2wgYXVtZW50YSBlbiBlbCAyNiwxOSBwZXNvcyBjb2xvbWJpYW5vcy4gVGFtYmnDqW4sIGNvbnNpZXJhbmRvIEIwIHNpIGVsIHByZWNpbyBkZWwgYmFycmlsIGRlIHBldHJvbGVvIGZ1ZXJhIDAgZW50b25jZXMgZWwgcHJlY2lvIGRlIGxhcyBhY2Npb25lcyBkZSBFY29wZXRyb2wgc2Vyw61hbiBkZSAxNzcgcGVzb3MuIA0KDQojIyAqKlB1bnRvIEQuIEhhZ2EgdW4gYW7DoWxpc2lzIGRlIGxvcyByZXNpZHVvcy4gIMK/UXXDqSBzdXB1ZXN0byBubyBzZSBjdW1wbGU/KioNCmBgYHtyfQ0KZT1tb2QkcmVzaWR1YWxzDQpwYXIobWZyb3c9YygyLDIpKQ0KcGxvdChtb2QpDQpgYGANCmBgYHtyfQ0Kc2hhcGlyby50ZXN0KG1vZCRyZXNpZHVhbHMpDQpgYGANCg0KUmVzdWx0YWRvOiBUYW50byBsbyBxdWUgbXVlc3RyYSBsYSBncmFmaWNhIE5vcm1hbCBRUSBjb21vIGxhIHBydWViYSBzaGFwaXJvIHNlIGNvbmNsdXllIHF1ZSBsb3MgcmVzaWR1b3Mgbm8gc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4gTm8gc2UgY3VtcGxlIGxhIG5vcm1hbGlkYWQuIFRhbWJpw6luIGxhIGdyYWZpY2FzIGRlIHJlc2lkdWFsZXMgdnMgYWp1c3RhZG9zICBtdWVzdHJhbiBxdWUgbG9zIHJlc2lkdW9zIG5vIHNlIGNvbXBvcnRhbiBkZSBmb3JtYSBhbGVhdG9yaWEgY29tbyBzZSBlc3BlcmFyw61hLiBFbiBjb25jbHVzacOzbiBubyBzZSBjdW1wbGVuIGxvcyBzdXB1ZXN0b3MgcmVsYWNpb25hZG9zIGNvbiBsYSBub3JtYWxpZGFkIHkgbGEgYWxlYXRvcmllZGFkIGRlIGxvcyByZXNpZHVvcy4gIENvbnNpZGVyYW5kbyBsb3MgcmVzdWx0YWRvcyBvYnRlbmlkb3MgZW4gZWwgbW9kZWxvIHByb3B1ZXN0bywgIGVsIHVzbyBkZSBlc3RlIG1vZGVsbyBubyBlcyByZWNvbWVuZGFibGUgcGFyYSBwcmVkZWNpciBlbCBwcmVjaW8gZGUgbGEgYWNjacOzbiBlbiBFY29wZXRyb2wsIGVzdG8gZGViaWRvIGEgcXVlIGVsIG1vZGVsbyBwcm9wdWVzdG8gbm8gY3VtcGxlIGNvbiBsb3Mgc3VwdWVzdG9zIHkgYWRlbcOhcyBlbCBwb3JjZW50YWplIGRlIFIyIHRvbWEgdW4gdmFsb3IgbXV5IGJham8uUG9yIHRhbnRvLCBzZSBwb2Ryw61hIGV4cGxvcmFyIHVuYSB0cmFuc2Zvcm1hY2nDs24gZGUgbGEgdmFyaWFibGVzIGNvbiBsYSBmaW5hbGlkYWQgZGUgcG9kZXIgdmVyIHNpIGVzdGUgc3VwdWVzdG8gc2UgcHVlZGUgY29ycmVnaXNlLiANCg0KDQojIyAqKjIgUFVOVE8uU0xMTVYgVlMgSU5GTEFDScOTTi4gU2UgYnVzY2EgcmVhbGl6YXIgbGEgcHJlZGljY2nDs24gZGVsIFNhbGFyaW8gTWluaW1vIChTTU1MVikgYSBwYXJ0aXIgZGUgbGEgdmFyaWFjacOzbiBkZSBsYSBpbmZsYWNpw7NuIGVuIGNvbG9tYmlhLiBQYXJhIGVzdG8gc2UgcGxhbnRlYSByZWFsaXphciB1bmEgcmVncmVzacOzbiBsaW5lYWwuIFNlIHZhbiBhIGNvbnNpZGVyYXIgbG9zIHNpZ3VpZW50ZXMgZGF0b3MgcGFyYSBzdSBjb25zdHJ1Y2Npw7NuKioNCg0KYGBge3J9DQpsaWJyYXJ5KHJlYWR4bCkNCmRhdG9zMiA8LSByZWFkX2V4Y2VsKCJDOi9Vc2Vycy9hc3VzL0Rvd25sb2Fkcy9TTU1MVi54bHN4IikNClZpZXcoZGF0b3MyKQ0KDQpgYGANCg0KQ29uIGxhIGZpbmFsaWRhZCBkZSBvYnNlcnZhciBsYSByZWxhY2nDs24gZGUgZXN0YXMgZG9zIHZhcmlhYmxlcywgc2UgcmVhbGl6YSB1biBkaWFncmFtYSBkZSBkaXNwZXNpw7NuIGNvbiBlbCBmaW4gZGUgdmVyIHNpIGVzIHBvc2libGUgZXhwbGljYXIgbGEgdmFyaWFiaWxpZGFkIGRlbCBzYWxhcmlvIG1pbmltbyBlbiBmdW5jaW9uIGRlIGxhIGluZmxhY2nDs24gYW51YWwuIA0KDQpgYGB7cn0NCmdncGxvdChkYXRvczIsYWVzKHg9ZGF0b3MyJElORkxBQ0lPTiwgeT1kYXRvczIkU01MTSkpK2dlb21fcG9pbnQoKSt0aGVtZV9idygpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KYGBgDQojIyAqKlB1bnRvIGEuIEVzY3JpYmEgbGEgZWN1YWNpw7NuIGRlbCBtb2RlbG8gZGUgcmVncmVzacOzbiBsaW5lYWwgc2ltcGxlKioNCg0KIFNNTUxNPc6yMCvOsjFJbmZsYWNpw7NuK8+1DQogDQpgYGB7cn0NCm1vZDIgPSBsbShkYXRvczIkU01MTSB+ZGF0b3MyJElORkxBQ0lPTikNCnJlc3VtZW4yID0gc3VtbWFyeShtb2QyKQ0KcmVzdW1lbjINCmBgYA0KDQojIyAqKlB1bnRvQi4gUGxhbnRlZSB5IHZhbGlkZSBsYXMgaGlww7N0ZXNpcyBjb3JyZXNwb25kaWVudGVzIGEgbGEgbGluZWFsaWRhZCBnZW5lcmFsIGRlbCBtb2RlbG8gcHJvcHVlc3RvIGVuIGEpKioNCmBgYHtyfQ0KbWVhbihtb2QyJHJlc2lkdWFscykNCmBgYA0KYGBge3J9DQpzaGFwaXJvLnRlc3QobW9kMiRyZXNpZHVhbHMpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGxtdGVzdCkNCmJwdGVzdChtb2QyKQ0KYGBgDQoNClJlc3VsdGFkbzogUG9yIHVuIGxhZG8sICBsYSBwcnVlYmEgZGUgU2hhcGlybyAtIFdpbGsgYXJyb2phIHF1ZSAgZWwgcF92YWx1ZSBlcyAwLjAwMTQwNyA8IDAuMDUsIHBvciBsbyB0YW50bywgIHNlIHJlY2hhemEgbGEgaGlwb3Rlc2lzIG51bGEgeSBzZSBjb25jbHV5ZSBxdWUgbG9zIHJlc2lkdW9zIG5vIHZpZW5lbiBkZSB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwuRnJlbnRlIGEgbGEgbWVkaWEgZGUgbG9zIGVycm9yZXMgZXN0b3MgZXN0YW4gbXV5IGNlcmNhbm9zIGEgY2VybyAuIEFzaW1pc21vLCBzZSBkZXRlY3RhLCBzZWfDum4gbGEgcHJ1ZWJhIEJyZXVzY2gtUGFnYW4sICBkb25kZSAgSG8gPSBIb21vY2VkYXN0aWNpZGFkIChsb3MgcmVzaWR1b3Mgc2UgZGlzdGlidXllbiBjb24gbGEgbWlzbWEgdmFyaWFuemEpIHkgSGEgPSBIZXRlcm9jZWRhc3RpY2lkYWQgKGxvcyByZXNpZHVvcyBubyBzZSBkaXN0cmlidXllbiBjb24gbGEgbWlzbWEgdmFyaWFuemEpLCBxdWUgZWwgIHVuIHAtdmFsdWUgZGUgMC40MzMgPiAwLjA1LCBwb3IgbG8gdGFudG8sICBubyBzZSByZWNoYXphIEhvLCBwb3IgbG8gcXVlIHNlIGV2aWRlbmNpYSBxdWUgbGEgdmFyaWFuemEgZGUgbG9zIHJlc2lkdW9zIGVzIGhvbW9jZWRhc3RpY2EuIEVuIGNvbmNsdXNpw7NuLCBsb3MgcmVzaWR1YWxlcyBubyBjdW1wbGVuIGNvbiBlbCBzdXB1ZXN0byBkZSBub3JtYWxpZGFkLCBwb3IgbG8gcXVlIGxvcyBkYXRvcyBubyBzZSBhanVzdGFuIGFkZWN1YWRhbWVudGUgYSB1biBtb2RlbG8gbGluZWFsLg0KDQojIyAqKlB1bnRvIEMuIEluZGlxdWUgZSBpbnRlcnByZXRlIGVsIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiBkZWwgbW9kZWxvIHByb3B1ZXN0byBlbiBhKSoqDQoNClJlc3VsdGFkbzogIGNvZWZpY2llbnRlIGRlIGNvcnJlbGFjacOzbiBkZWwgbW9kZWxvIHByb3B1ZXN0byBlcyBkZSBSMj0wLjUwMjIsIHBvciBsbyBxdWUgZXhwbGljYSBlbiB1biA1MC4yMiUgbGEgdmFyaWFiaWxpZGFkIGRlbCBzYWxhcmlvIGRlIGFjdWVyZG8gYSBsYSBpbmZsYWNpw7NuDQoNCiMjICoqUHVudG8gRC4gSW50ZXJwcmV0ZSBjYWRhIHVubyBkZSBsb3MgY29lZmljaWVudGVzIGRlbCBtb2RlbG8gcHJvcHVlc3RvIGVuIGEpKioNCg0KUmVzdWx0YWRvOiBMb3MgcXVlIG5vcyBpbmRpY2EgZWwgbW9kZWxvIGVzIHF1ZSAgZWwgQjAgbm9zIGRpY2UgcXVlIHNpIGxhIGluZmxhY2lvbiBlcyBjZXJvLCBlbnRvbmNlcyBlbCBzYWxhcmlvIG1pbmltbyBsZWdhbCBzZXJhIGRlICQ2NDguNDg2IGFwcm94aW1hZGFtZW50ZS4gUG9yIG90cm8gbGFkbywgTG8gcXVlIGluZGljYSBsYSBwZW5kaWVudGUgYjEsIGVzIGN1YWwgZXMgbGEgZGlzbWludWNpb24gZGVsIHNhbGFyaW8gbWluaW1vIGxlZ2FsIHBvciBjYWRhIGluY3JlbWVudG8gZW4gdW5hIHVuaWRhZCBkZSBpbmZsYWNpb24sIGVzIGRlY2lyLCBxdWUgc2kgbGEgaW5mbGFjaW9uIGF1bWVudGEgZW4gdW4gMSUgZW50b25jZXMsIGVsIHNhbGFyaW8gbWluaW1vIGxlZ2FsIGRpc21pbnVpcmEgJDM5LjQ4OSBhcHJveGltYWRhbWVudGUuIFBvciBvdHJvIGxhZG8sIGxvcyB2YWxvcmVzIGRlbCB2YWxvciBQIG5vcyBkaWNlIHF1ZSBlbCBjb2VmaWNpZW50ZSBiMSBzaSBlcyBzaWduaWZpY2F0aXZvIHBvcnF1ZSBlc3RlIGVzIGlndWFsIGEgY2VybyBlbnRvbmNlcyBzZSByZWNoYXphIEgwLiBBZGVtw6FzLCBlbCBSMiBub3MgZGljZSBxdWUgbGEgaW5mbGFjaW9uIGV4cGxpY2EgZW4gdW4gNDYuOSUgZWwgc2FsYXJpbyBtaW5pbW8NCg0KIyMgKipQdW50byBFLkNvbnN0cnV5YSB1bmEgZ3LDoWZpY2EgZGUgcmVzaWR1YWxlcyB5IGhhZ2EgdW4gYW7DoWxpc2lzIGN1YWxpdGF0aXZvIGRlIGxvcyBzdXB1ZXN0b3MgZGVsIG1vZGVsbyBwcm9wdWVzdG8gZW4gYSoqDQpgYGB7cn0NCmU9bW9kMiRyZXNpZHVhbHMNCnBhcihtZnJvdz1jKDIsMikpDQpwbG90KG1vZDIpDQpgYGANClJlc3VsdGFkbzogUGFyYSBlbCB2YWxvciBkZSBsYSBNZWRpYSBjZXJvOiBTZSBjdW1wbGUsIG5vIHNlIHByZXNlbnRhIG5vdmVkYWQuRnJlbnRlIGEgbGEgVmFyaWFuemEgQ29uc3RhbnRlOiBTZSBwdWVkZSBvYnNlcnZhciBxdWUgZWwgbW9kZWxvIHByb3B1ZXN0byBubyBjdW1wbGUgY29uIGVzdGUgc3VwdWVzdG8uIEVzIHBvc2libGUgaWRlbnRpZmljYXIgcXVlICBsb3MgZXJyb3JlcyBubyBzb24gYWxlYXRvcmlvcyB5IHF1ZSAgZWwgbW9kZWxvIG5vIGVzIGxpbmVhbC4gUGFyYSBsYSAgTm9ybWFsaWRhZDogRW4gZWwgZ3JhZmljbyBzZSBwdWVkZSBvYnNlcnZhciBxdWUgbG9zIGRhdG9zIG5vIHNlIGFqdXN0YW4gZGVsIHRvZG8gYSBsYSBsw61uZWEgZGUgbm9ybWFsaWRhZC4gUmVzcGVjdG8gIGxhICBJbmRlcGVuZGVuY2lhOiBUZW5pZW5kbyBlbiBjdWVudGEgcXVlIGxvcyByZWdpc3Ryb3MgY29ycmVzcG9uZGVuIGEgZGF0b3MgZW4gZWwgdGllbXBvLCBzZSBpbmRpY2EgcXVlIHNvbiBkZSBvcmRlbiB0ZW1wb3JhbC4gRW4gY29uY2x1c2nDs24gc2UgZGViZSB0cmFuc2Zvcm1hciBlbCBtb2RlbG8gZGUgcmVncmVzaW9uIGxpbmVhbCwgeWEgcXVlICBlbiBlbCAgZ3JhZmljbyBkZSBhanVzdGUgbm8gc2UgY3VtcGxlIGxhIGFsZWF0b3JpZGFkIGRlIGxvcyBlcnJvcmVzLiANCg0KIyMgKipQdW50byBGLkNvbWVudGUgc29icmUgbGEgY29udmVuaWVuY2lhIGRlIHVzYXIgZWwgbW9kZWxvIHByb3B1ZXN0byBlbiBhKSBwYXJhIHByZWRlY2lyIGVsIFNNTE0gcGFyYSBDb2xvbWJpYSoqDQoNClJlc3VsdGFkbzogQ29uc2lkZXJhbmRvIGxvcyByZXN1bHRhZG9zIG9idGVuaWRvcyBlbiBlbCBtb2RlbG8gcHJvcHVlc3RvLCBzZSBwdWVkZSBpbmRpY2FyIHF1ZSBubyBlcyByZWNvbWVuZGFibGUgZWwgdXNvIGRlIGVzdGUgbW9kZWxvIHBhcmEgcHJlZGVjaXIgZWwgU0xNTCBlbiBDb2xvbWJpYSwgZXN0byBkZWJpZG8gYSBxdWUgZWwgbW9kZWxvIHByb3B1ZXN0byBubyBjdW1wbGUgY29uIGxvcyBzdXB1ZXN0b3MgeSBhZGVtw6FzIGVsIHBvcmNlbnRhamUgZGUgUjIgdG9tYSB1biB2YWxvciBtdXkgYmFqby4NCg0KIyMgKipQdW50byAzLiAgQ29uIGJhc2UgZW4gbG9zIGRhdG9zIGRlIHByZWNpb3MgZGUgdml2aWVuZGEgZGUgbGEgYWN0aXZpZGFkIGVuIGNsYXNlIHJlYWxpemFyIHVuIGluZm9ybWUgcXVlIGNvbnRlbmdhIGxvcyBzaWd1aWVudGVzIHB1bnRvcyB1dGlsaXphbmRvIFIgeSBSTWFya2Rvd24gKHB1YmxpY2FyIGVsIGluZm9ybWUgZmluYWwgZW4gUnB1YnMgcHJlc2VudGFuZG8gY8OzZGlnbywgcmVzdWx0YWRvcyBlIGludGVycHJldGFjaW9uZXMpKioNCg0KYGBge3J9DQpsaWJyYXJ5KHJlYWR4bCkNCmRhdG9zX3ZpdmllbmRhIDwtIHJlYWRfZXhjZWwoIkRhdG9zX1ZpdmllbmRhLnhsc3giKQ0KVmlldyhkYXRvc192aXZpZW5kYSkNCg0KYGBgDQoNCiMjICoqUHVudG8gYS4gUmVhbGljZSB1biBmaWx0cm8gYSBsYSBiYXNlIGRlIGRhdG9zIGUgaW5jbHV5YSBzb2xvIGxhcyBvZmVydGFzIGRlIGFwYXJ0YW1lbnRvcywgZGUgbGEgem9uYSBub3J0ZSBkZSBsYSBjaXVkYWQgY29uIHByZWNpb3MgaW5mZXJpb3JlcyBhIGxvcyA1MDAgbWlsbG9uZXMgZGUgcGVzb3MgeSDDoXJlYXMgbWVub3JlcyBhIDMwMCBtdDIuIFByZXNlbnRlIGxvcyBwcmltZXJvcyAzIHJlZ2lzdHJvcyBkZSBsYSBiYXNlIHkgYWxndW5hcyB0YWJsYXMgcXVlIGNvbXBydWViZW4gbGEgY29uc3VsdGEuICjCv0FkaWNpb25hbCB1biBtYXBhIGNvbiBsb3MgcHVudG9zIGRlIGxhIGJhc2UsIGRpc2N1dGlyIHNpIHRvZG9zIGxvcyBwdW50b3Mgc2UgdWJpY2FuIGVuIGxhIHpvbmEgbm9ydGUgbyBzZSBwcmVzZW50YW4gdmFsb3JlcyBlbiBvdHJhcyB6b25hcywgcG9yIHF1w6k/KSoqLg0KDQpgYGB7cn0NCmhlYWQoZGF0b3Nfdml2aWVuZGEpDQpgYGANCmBgYHtyfQ0KIHBvcz13aGljaCAoZGF0b3Nfdml2aWVuZGEkVGlwbz09ICJBcGFydGFtZW50byIgJiBkYXRvc192aXZpZW5kYSRab25hID09ICJab25hIE5vcnRlIiAmIGRhdG9zX3ZpdmllbmRhJHByZWNpb19taWxsb24gPCA1MDAgJiBkYXRvc192aXZpZW5kYSRBcmVhX2NvbnRydWlkYSA8IDMwMCkNCnZpdmllbmRhcyA9IGRhdG9zX3ZpdmllbmRhW3BvcyxdDQp2aXZpZW5kYXMgPC0gdHJhbnNmb3JtKHZpdmllbmRhcywgcGFycXVlYWRlcm9zID0gYXMubnVtZXJpYyhwYXJxdWVhZGVyb3MpKQ0Kdml2aWVuZGFzW2lzLm5hKHZpdmllbmRhcyldIDwtIDANCmhlYWQodml2aWVuZGFzLCAxNSkNCg0KYGBgDQpgYGB7cn0NCnJlcXVpcmUobGVhZmxldCkNCg0KbGVhZmxldCgpICU+JSBhZGRDaXJjbGVNYXJrZXJzKGxuZyA9IGRhdG9zX3ZpdmllbmRhJGNvcmRlbmFkYV9sb25naXR1ZCxsYXQgPSBkYXRvc192aXZpZW5kYSRDb3JkZW5hZGFfbGF0aXR1ZCxyYWRpdXMgPSAwLjMsY29sb3IgPSAiYmxhY2siLGxhYmVsID0gZGF0b3Nfdml2aWVuZGEkSUQpICU+JSBhZGRUaWxlcygpDQpgYGANCg0KIyMgKipQdW50byBiLiBSZWFsaWNlIHVuIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgZGF0b3MgZW5mb2NhZG8gZW4gbGEgY29ycmVsYWNpw7NuIGVudHJlIGxhIHZhcmlhYmxlIHJlc3B1ZXN0YSAocHJlY2lvIGRlbCBhcGFydGFtZW50bykgZW4gZnVuY2nDs24gZGVsIMOhcmVhIGNvbnN0cnVpZGEsIGVzdHJhdG8geSBzaSB0aWVuZSBwYXJxdWVhZGVyby4gVXNlIGdyw6FmaWNvcyBpbnRlcmFjdGl2b3MgY29uIHBsb3RseSBlIGludGVycHJldGUgbG9zIHJlc3VsdGFkb3MqKg0KDQojICpHcmFmaWNvIGFyZWEgY29uc3RydWlkYSB2cyBwcmVjaW8qIA0KDQpgYGB7cn0NCmdyYWYxIDwtIHBsb3RfbHkoZGF0YSA9IGRhdG9zX3ZpdmllbmRhLCB4ID1+ZGF0b3Nfdml2aWVuZGEkQXJlYV9jb250cnVpZGEgLCB5ID0gfmRhdG9zX3ZpdmllbmRhJHByZWNpb19taWxsb24gLA0KICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChzaXplID0gMTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ2xpZ2h0Ymx1ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gJ2JsdWUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDIpKSkNCmdyYWYxIDwtIGdyYWYxICU+JSBsYXlvdXQodGl0bGUgPSAnUHJlY2lvIFZpdmllbmRhIHZzIEFyZWEgQ29uc3RydWlkYScsDQogICAgICAgICB5YXhpcyA9IGxpc3QoemVyb2xpbmUgPSBGQUxTRSksDQogICAgICAgICB4YXhpcyA9IGxpc3QoemVyb2xpbmUgPSBGQUxTRSkpDQoNCmdyYWYxDQpgYGANCg0KUmVzdWx0YWRvOiBsYSBjb3JyZWxhY2lvbiBub3MgZGljZSBxdWUgZXhpc3RlbiB1bmEgcmVsYWNpb24gcG9zaXRpdmEgZW50cmUgZWwgcHJlY2lvICB5IGVsIGFyZWEgY29uc3RydWlkYSwgZXMgZGVjaXIgcXVlLCBtaWVudHJhcyBlbCBhcmVhIGNvbnN0cnVpZGEgc2VhIG1heW9yIGVsIHByZWNpbyBzZXJhIG1hcyBhbHRvLg0KDQojICpQcmVjaW9fbWlsbG9uIHZzIEVzdHJhdG8qDQoNCmBgYHtyfQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShwbG90bHkpDQoNCmdyYWYyPSBnZ3Bsb3QoZGF0b3Nfdml2aWVuZGEgPSBkYXRvc192aXZpZW5kYSwgbWFwcGluZyA9IGFlcyh4PSBkYXRvc192aXZpZW5kYSRFc3RyYXRvLCB5PWRhdG9zX3ZpdmllbmRhJHByZWNpb19taWxsb24pKSsgZ2VvbV9wb2ludCgpK2dlb21fc21vb3RoKCkNCmdncGxvdGx5KGdyYWYyKQ0KDQoNCmBgYA0KDQpSZXN1bHRhZG86RXMgcG9zaWJsZSBhZHZlcnRpciwgZGUgYWN1ZXJkbyBjb24gZWwgZ3JhZmljbywgIHVuYSByZWxhY2nDs24gZGlyZWN0YSBlbnRyZSBsYXMgZG9zIHZhcmlhYmxlcywgZXMgZGVjaXIsICBlbnRyZSBtYXlvciBzZWEgZWwgZXN0cmF0bywgbWF5b3IgZXMgZWwgcHJlY2lvIGRlIGxhIHZpdmllbmRhLg0KDQojICpHcmFmaWNhIHByZWNpb3MgcG9yIG1pbGxvbiB2cyAjIFBhcnF1ZWRlcm9zKg0KYGBge3J9DQpyZXF1aXJlKGdncGxvdDIpDQpyZXF1aXJlKHBsb3RseSkNCg0KZ3JhZjM9IGdncGxvdChkYXRvc192aXZpZW5kYSA9IGRhdG9zX3ZpdmllbmRhLCBtYXBwaW5nID0gYWVzKHg9ZGF0b3Nfdml2aWVuZGEkcGFycXVlYWRlcm9zLCB5PSBkYXRvc192aXZpZW5kYSRwcmVjaW9fbWlsbG9uKSkrIGdlb21fcG9pbnQoKStnZW9tX3Ntb290aCgpDQpnZ3Bsb3RseShncmFmMykNCmBgYA0KDQpSZXN1bHRhZG86IEVsIGdyYWZpY28gbm8gZGEgY3VlbnRhIGRlICB1bmEgcmVsYWNpw7NuIGV4aXN0ZW50ZSBlbnRyZSBlbCBudW1lcm8gZGUgcGFycXVlYWRlcm9zIHZzIGVsIHByZWNpbyBkZSBsYSB2aXZpZW5kYS4NCg0KIyMgKipDLiBFc3RpbWUgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIG3Dumx0aXBsZSBjb24gbGFzIHZhcmlhYmxlcyBkZWwgcHVudG8gYW50ZXJpb3IgZSBpbnRlcnByZXRlIGxvcyBjb2VmaWNpZW50ZXMgc2kgc29uIGVzdGFkw61zdGljYW1lbnRlIHNpZ25pZmljYXRpdm9zLiBMYXMgaW50ZXJwcmV0YWNpb25lcyBkZWJlciBlc3TDoW4gY29udGV4dHVhbGl6YWRhcyB5IGRpc2N1dGlyIHNpIGxvcyByZXN1bHRhZG9zIHNvbiBsw7NnaWNvcy4gQWRpY2lvbmFsbWVudGUgaW50ZXJwcmV0ZSBlbCBjb2VmaWNpZW50ZSBSMiB5IGRpc2N1dGEgZWwgYWp1c3RlIGRlbCBtb2RlbG8gZSBpbXBsaWNhY2lvbmVzIChxdWUgcG9kcsOtYW4gaGFjZXIgcGFyYSBtZWpvcmFybG8pKiouDQoNCmBgYHtyfQ0KDQptb2RlbG9fdml2aWVuZGFzID0gbG0oZm9ybXVsYT0gcHJlY2lvX21pbGxvbiB+IEFyZWFfY29udHJ1aWRhICsgRXN0cmF0byArICBwYXJxdWVhZGVyb3MsIGRhdGEgPSB2aXZpZW5kYXMgKQ0Kc3VtbWFyeShtb2RlbG9fdml2aWVuZGFzKQ0KDQpgYGANClJlc3VsdGFkbzogIENvbiBsb3MgcmVzdWx0YWRvcyBhbnRlcmlvcmVzIHNlIHB1ZWRlIGV4cHJlc2FyIGVsIG1vZGVsbyBhanVzdGFkbyBjb21vIHNlIG11ZXN0cmEgYSBjb250aW51YWNpw7NuOg0KUHJlY2lvbWlsbG9uPeKIkjE1Ny4zODIyMCswLjk0OTM4eDFpKzY4Ljk5NDM2eDNpKzIyLjY0OTA2eDJpIFIyPTAuNzYyMw0KDQphKUVsIHZhbG9yIGRlbCBSIGN1YWRyYWRvID0gMC43NjIzIHNpZ25pZmljYSBxdWUgbGEgdmFyaWFibGVzOiBhcmVhIGNvbnN0cnVpZGEsIGVzdHJhdG8geSBwYXJxdWFkZXJvcyBleHBsaWNhbiBlbCA3NiUgZGVsIHByZWNpbyBkZWwgYXBhcnRhbWVudG8uDQpiKVNlIHB1ZWRlbiBpbnRlcnByZXRhciBsb3MgZWZlY3RvcyBCIGRlIGxhIHNpZ3VpZW50ZSBmb3JtYToNCi1TaSBlbCDDoXJlYSBjb25zdHJ1aWRhIGRlIGxhIHZpdmllbmRhIGF1bWVudGEgMW10czIsIHNlIGVzcGVyYSBxdWUgZWwgcHJlY2lvIHBvciBtaWxsb24gZGUgbGEgdml2aWVuZGEgYXVtZW50ZSBlbiAtLjk0IG1pbGxvbmVzLg0KLVNpIGVsIGVzdHJhdG8gZGUgbGEgdml2aWVuZGEgYXVtZW50YSBlbiAxLCBlbCBwcmVjaW8gcG9yIG1pbGxvbiBkZSBsYSB2aXZpZW5kYSBhdW1lbnRlIGVuIDIyLjY0IG1pbGxvbmVzLg0KLVBvciBjYWRhIHBhcnF1ZWFkZXJvIGFkaWNpb25hbCwgc2UgZXNwZXJhIHF1ZSBlbCBwcmVjaW8gcG9yIG1pbGxvbiBkZSBsYSB2aXZpZW5kYSBhdW1lbnRlIGVuIDE1LjU1NjYxIG1pbGxvbmVzLg0KLUVuIGVzdGUgY29udGV4dG8gZWwgaW50ZXJjZXB0byBkZSAtMTU3LjM4LCBsbyBxdWUgbm8gZXMgbMOzZ2ljbyBwb3JxdWUgbm8gaGF5IHVuIGNvc3RvIGRlIHZhbG9yIG5lZ2F0aXZvIHBhcmEgdW5hIHZpdmllbmRhDQotRWwgY29lZmljaWVudGUgUjIgYWp1c3RhZG8gZGUgMC43NiBsbyBxdWUgaW5kaWNhIHF1ZSBlbCBwcmVjaW8gZGUgbGEgdml2aWVuZGEgZXMgZXhwbGljYWRvIHBvciBlbCBtb2RlbG8gZW4gdW4gNzYlDQoNCg0KIyMgKipQdW50byBkLiBSZWFsaWNlIGxhIHZhbGlkYWNpw7NuIGRlIHN1cHVlc3RvcyBkZWwgbW9kZWxvIGUgaW50ZXJwcmV0ZSBsb3MgcmVzdWx0YWRvcyAobm8gZXMgbmVjZXNhcmlvIGNvcnJlZ2lyIGVuIGNhc28gZGUgcHJlc2VudGFyIHByb2JsZW1hcyBzb2xvIHJlYWxpemFyIHN1Z2VyZW5jaWFzIGRlIHF1ZSBzZSBwb2Ryw61hIGhhY2VyKS4qKg0KYGBge3J9DQpwYXIobWZyb3cgPSBjKDIsIDIpKQ0KcGxvdChtb2RlbG9fdml2aWVuZGFzKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkobG10ZXN0KQ0KYnB0ZXN0KG1vZGVsb192aXZpZW5kYXMpDQpgYGANCg0KUmVzdWx0YWRvOlNlZ8O6biBsYXMgZ3LDoWZpY2FzIHNlIHB1ZWRlIGNvbmNsdWlyIGxvIHNpZ3VpZW50ZTogDQoxKUdyw6BmaWNhIE5vcm1hbFFROiBkIGVzIHBvc2libGUgZXZpZGVuY2lhciBxdWUgbG9zIGVycm9yZXMgbm8gc2lndWVuIGVsIHN1cHVlc3RvIGRlIG5vcm1hbGlkYWQuDQoyKUFzaW1pc21vLCBsb3MgcmVzaWR1YWxlcyAgbm8gc29uIGhvbW9jZWRhc3RpY29zIGRlIGFjdWVyZG8gY29uIGxhIGdyw6FmaWNhIFNjYWxlIExvY2F0aW9uIHkgbGEgcHJ1ZWJhIGRlIEJyZXVzaC1QYWdhbiwgbGEgY3VhbCBkaW8gdW4gcF92YWxvciBtdXkgcHLDs3hpbW8gYSAwIHBvciBsbyBxdWUgc2UgcmVjaGF6YSBsYSBoaXBvdGVzaXMgbnVsYSBkZSBob21vY2VkYXN0aWNpZGFkLiBTZSBjb25jbHV5ZSBxdWUgIGxvcyByZXNpZHVhbGVzIG5vIGN1bXBsZW4gY29uIGVsIHN1cHVlc3RvIGRlIG5vcm1hbGlkYWQgbmkgaG9tb2NlZGFzdGljaWRhZCwgcG9yIGxvIHF1ZSBsb3MgZGF0b3Mgbm8gc2UgYWp1c3RhbiBhZGVjdWFkYW1lbnRlIGEgdW4gbW9kZWxvIGxpbmVhbC4NCg0KDQojIyAqKlB1bnRvIGUuIENvbiBlbCBtb2RlbG8gaWRlbnRpZmljYWRvIHByZWRlY2lyIGVsIHByZWNpbyBkZSB1biBhcGFydGFtZW50byBjb24gMTAwIG10MiwgZGUgZXN0cmF0byA0IHkgY29uIHBhcnF1ZWFkZXJvLiDCv1NpIGVzdGUgYXBhcnRhbWVudG8gbG8gZXN0w6FuIG9mcmVjaWVuZG8gZW4gNDUwIG1pbGxvbmVzIGN1YWwgc2VyaWEgc3Ugb3BpbmnDs24gY29uIGJhc2UgZW4gZWwgcmVzdWx0YWRvIGRlbCBtb2RlbG8gY29uc2lkZXJhIHF1ZSBlcyB1bmEgYnVlbmEgb2ZlcnRhPyoqDQpgYGB7cn0NCi00NzMuMjkrKDAuOTc4NyoxMDApKyg4Ny4xMSoxKSsoMTI1LjI0KjQpDQpgYGANClJlc3VsdGFkbzogQ29uc2lkZXJhbmRvIGxvcyB2YWxvcmVzIG9idGVuaWRvcyBkZWwgbW9kZWxvLCBubyBlcyBidWVuYSBvcGNpw7NuIGNvbXByYXIgZWwgYXBhcnRhbWVudG8gcXVlIGVzdGFuIG9mcmVjaWVuZG8gcG9yIDQ1MCBtaWxsb25lcywgZGFkbyBxdWUgZWwgbW9kZWxvIHJlZ2lzdHJhIHVuIHZhbG9yIGRlIGNvbXByYSBhcHJveGltYWRvIGRlIDIxMiBtaWxsb25lcy4NCg0KIyMgKipQdW50byBmLkNvbiBsYXMgcHJlZGljY2lvbmVzIGRlbCBtb2RlbG8gc3VnaWVyYSBwb3RlbmNpYWxlcyBvZmVydGFzIHBhcmEgdW5hIHBlcnNvbmEgaW50ZXJlc2FkYSBlbiB1biBhcGFydGFtZW50byBlbiBsYSB6b25hIG5vcnRlIGNvbiBtYXMgZGUgMTAwIG10MiBkZSDDoXJlYSwgZGUgZXN0cmF0byA0LCBxdWUgdGVuZ2EgcGFycXVlYWRlcm8geSB0ZW5nYSBlbmN1ZW50YSBxdWUgbGEgcGVyc29uYSB0aWVuZSB1biBjcsOpZGl0byBwcmVhcHJvYmFkbyBkZSBtw6F4aW1vIDQwMCBtaWxsb25lcyBkZSBwZXNvcy4gUmVhbGljZSB1biBhbsOhbGlzaXMgeSBwcmVzZW50ZSBlbiB1biBtYXBhIGFsIG1lbm9zIDUgb2ZlcnRhcyBwb3RlbmNpYWxlcyBxdWUgZGViZSBkaXNjdXRpcioqDQoNCmBgYHtyfQ0Kb2ZlcnRhID0gd2hpY2goZGF0b3Nfdml2aWVuZGEkVGlwbz09IkFwYXJ0YW1lbnRvIiYgZGF0b3Nfdml2aWVuZGEkWm9uYT09IlpvbmEgTm9ydGUiJiBkYXRvc192aXZpZW5kYSRwcmVjaW9fbWlsbG9uPD00MDAgJiBkYXRvc192aXZpZW5kYSRBcmVhX2NvbnRydWlkYT4xMDAgJiBkYXRvc192aXZpZW5kYSRFc3RyYXRvID09IDQgJiBkYXRvc192aXZpZW5kYSRwYXJxdWVhZGVyb3MgPj0gMSkNCm9mZXJ0YV8yPWRhdG9zX3ZpdmllbmRhW29mZXJ0YSxdDQpvZmVydGFfZmluYWwgPSBoZWFkKG9mZXJ0YV8yLDUpDQpvZmVydGFfZmluYWwNCmBgYA0KDQpgYGB7cn0NCm9mZXJ0YTEgPSBwcmVkaWN0KG1vZGVsb192aXZpZW5kYXMsbGlzdChBcmVhX2NvbnRydWlkYT0xMjMsRXN0cmF0bz00LHBhcnF1ZWFkZXJvcz0xKSkNCm9mZXJ0YTIgPSBwcmVkaWN0KG1vZGVsb192aXZpZW5kYXMsbGlzdChBcmVhX2NvbnRydWlkYT0xMzAsRXN0cmF0bz00LHBhcnF1ZWFkZXJvcz0xKSkNCm9mZXJ0YTMgPSBwcmVkaWN0KG1vZGVsb192aXZpZW5kYXMsbGlzdChBcmVhX2NvbnRydWlkYT0xMDgsRXN0cmF0bz00LHBhcnF1ZWFkZXJvcz0xKSkNCm9mZXJ0YTQgPSBwcmVkaWN0KG1vZGVsb192aXZpZW5kYXMsbGlzdChBcmVhX2NvbnRydWlkYT0xMDQsRXN0cmF0bz00LHBhcnF1ZWFkZXJvcz0xKSkNCm9mZXJ0YTUgPSBwcmVkaWN0KG1vZGVsb192aXZpZW5kYXMsbGlzdChBcmVhX2NvbnRydWlkYT0xMjUsRXN0cmF0bz00LHBhcnF1ZWFkZXJvcz0yKSkNCmRhdGEuZnJhbWUob2ZlcnRhMSxvZmVydGEyLG9mZXJ0YTMsb2ZlcnRhNCxvZmVydGE1KQ0KDQpgYGANCg0KUmVzdWx0YWRvOiBDb25zaWRlcmFuZG8gcXVlIGxhIHBlcnNvbmEgdGllbmUgdW4gY3LDqWRpdG8gcHJlYXByb2JhZG8gcG9yIHVuIHZhbG9yIGRlIDQwMCBtaWxsb25lcyAgc2Ugc3VnaWVyZSBhbCBjb21wcmFkb3Igb2ZlcnRhcyBkZSBhcGFydGFtZW50byBlbiB6b25hIG5vcnRlLCBlc3RyYXRvIDQgeSBjb24gcG9zaWJpbGlkYWQgZGUgMSBvIDIgcGFycXVlYWRlcm9zIHkgw6FyZWEgY29uc3RydWlkYSBtYXlvciBhIDEwMG10Mi4gQ3VhbHF1aWVyYSBkZSBsYXMgb2ZlcnRhcyBhbGNhbnphIGFsIGNvbXByYWRvciwgc2Vnw7puIGVsIHByZWFwcm9iYWRvIGNvbiBlbCBxdWUgY3VlbnRhLiANCg0KYGBge3J9DQpsaWJyYXJ5KGxlYWZsZXQpDQpsZWFmbGV0KCkgJT4lIGFkZENpcmNsZU1hcmtlcnMobG5nID0gb2ZlcnRhX2ZpbmFsJGNvcmRlbmFkYV9sb25naXR1ZCxsYXQgPSBvZmVydGFfZmluYWwkQ29yZGVuYWRhX2xhdGl0dWQscmFkaXVzID0gNSxjb2xvciA9ICJyZWQiLGxhYmVsID0gb2ZlcnRhX2RlZiRJRCkgJT4lIGFkZFRpbGVzKCkNCmBgYA0KDQojIyAqKlB1bnRvIDQgQ29uIGJhc2UgZW4gbG9zIGRhdG9zIGRlIGFyYm9sZXMgcHJvcG9uZ2EgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIG3Dumx0aXBsZSBxdWUgcGVybWl0YSBwcmVkZWNpciBlbCBwZXNvIGRlbCDDoXJib2wgZW4gZnVuY2nDs24gZGUgbGFzIGNvdmFyaWFibGVzIHF1ZSBjb25zaWRlcmUgaW1wb3J0YW50ZXMgeSBzZWxlY2Npb27DoW5kb2xhcyBkZSBhY3VlcmRvIGNvbiB1biBwcm9jZXNvIGFkZWN1YWRvLiBUZW5nYSBlbiBjdWVudGEgcmVhbGl6YXIgdW5hIGV2YWx1YWNpw7NuIGRlIGxhIHNpZ25pZmljYW5jaWEgZGUgbG9zIHBhcsOhbWV0cm9zLCBpbnRlcnByZXRhY2nDs24geSBwcm9wb25nYSB1biBtw6l0b2RvIGRlIGV2YWx1YWNpw7NuIHBvciBtZWRpbyBkZSB2YWxpZGFjacOzbiBjcnV6YWRhLiBQcmVzZW50ZSBtw6l0cmljYXMgYXByb3BpYWRhcyBjb21vIGVsIFJNU0UgeSBNQUUuKioNCg0KYGBge3J9DQoNCmxpYnJhcnkocmVhZHhsKQ0KZGF0YWFyYm9sZXMgPC0gcmVhZF9leGNlbCgiQzovVXNlcnMvYXN1cy9EZXNrdG9wL2RhdGFhcmJvbGVzLnhsc3giLCANCiAgICBjb2xfdHlwZXMgPSBjKCJ0ZXh0IiwgInRleHQiLCAibnVtZXJpYyIsIA0KICAgICAgICAibnVtZXJpYyIsICJudW1lcmljIikpDQpWaWV3KGRhdGFhcmJvbGVzKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YWFyYm9sZXM9ZGF0YWFyYm9sZXNbLCAzOjVdDQphdHRhY2goZGF0YWFyYm9sZXMpDQpuYW1lcyhkYXRhYXJib2xlcykNCmBgYA0KYGBge3J9DQpnZ3BhaXJzKGRhdGFhcmJvbGVzLCBsb3dlciA9IGxpc3QoY29udGludW91cyA9ICJzbW9vdGgiKSwNCiAgICAgICAgZGlhZyA9IGxpc3QoY29udGludW91cyA9ICJiYXJEaWFnIiksIGF4aXNMYWJlbHMgPSAibm9uZSIpDQpgYGANClJlc3VsdGFkbzogZGUgbGFzIGdyw6FmaWNhcyBzZSBwdWVkZSBjb25jbHVpciBxdWUgbGFzIHZhcmlhYmxlcyBxdWUgdGllbmVuIHVuYSBtYXlvciByZWxhY2nDs24gbGluZWFsIGNvbiBsYSBwZXNvIHNvbiBlbCBkaWFtZXRybyAoMC45MDgpLCBhbHR1cmEgKCAwLjg1OCkuIFRhbWJpZW4sIGUgZGlhbWV0cm8geSBhbHR1cmEgZXN0w6FuICBjb3JyZWxhY2lvbmFkb3MgKCAwLjkzNikuIA0KDQojIyAqKk1vZGVsbyBkZSByZWdyZXNpw7NuIG11bHRpcGxlKioNCg0KYGBge3J9DQpzZXQuc2VlZCgxKQ0KdHJhaW4gPC0gc2FtcGxlKHggPSAxOjkwLCA3MikNCm1vZGVsb19hcmJvbGVzIDwtIGxtKHBlc29+ZGlhbWV0cm8gKyBhbHR1cmEsIGRhdGEgPSBhcmJvbGVzLCBzdWJzZXQgPSB0cmFpbikNCnN1bW1hcnkobW9kZWxvX2FyYm9sZXMpDQpgYGANCkNvbiBsb3MgcmVzdWx0YWRvcyBhbnRlcmlvcmVzIHNlIHB1ZWRlIGV4cHJlc2FyIGVsIG1vZGVsbyBhanVzdGFkbyBjb21vIHNlIG11ZXN0cmEgYSBjb250aW51YWNpw7NuOg0KWSgpPeKIkjkuMjkrNC4wMuKIl1gxKERpYW1ldHJvKSswLjk44oiXWDIoQWx0dXJhKQ0KU2UgcHVlZGVuIGludGVycHJldGFyIGxvcyBlZmVjdG9zIM6yIGRlIGxhIHNpZ3VpZW50ZSBmb3JtYToNCl8gRGUgYWN1ZXJkbyBhIGxvcyBjw6FsY3Vsb3Mgb2JzZXJ2YWRvcyBzaSBlbCBkacOhbWV0cm8gZGVsIMOhcmJvbCBhdW1lbnRhIGVuIHVuYSB1bmlkYWQsIHNlIGVzcGVyYSBxdWUgZWwgcGVzbyBkZWwgw6FyYm9sIGF1bWVudGUgZW4gNC4wMiB1bmlkYWRlcy4NCl8gRGUgaWd1YWwgbWFuZXJhIHNlIHB1ZWRlIGluZGljYXIgcXVlIHBvciBjYWRhIG1ldHJvIGFkaWNpb25hbCBlbiBsYSBhbHR1cmEgZGVsIMOhcmJvbCwgc2UgZXNwZXJhcsOtYSBxdWUgZWwgcGVzbyBkZWwgw6FyYm9sIGF1bWVudGUgZW4gMC45OCB1bmlkYWRlcy4NCl8gRGUgZXN0YSBtYW5lcmEgZWwgaW50ZXJjZXB0byBkZSAtOS4xMjA1LCBubyBlcyB1biB2YWxvciAsIGRhZG8gcXVlIG5vIGRlYmVyw61hIGV4aXN0aXIgdW4gw6FyYm9sIGNvbiB1biBwZXNvIG5lZ2F0aXZvLg0KXyBEZSBpZ3VhbCBmb3JtYSBlbCBjb2VmaWNpZW50ZSBSMiBhanVzdGFkbyB0b21hIHVuIHZhbG9yIGRlIDAuODMsIGxvIGN1YWwgaW5kaWNhIHF1ZSBlbCBwZXNvIGRlbCDDoXJib2wgZXMgZXhwbGljYWRvIHBvciBlbCBtb2RlbG8gY29uIHVuIDgzJS4NCg0KDQpgYGB7cn0NCnBhcihtZnJvdz1jKDIsMikpDQpwbG90KG1vZGVsb19hcmJvbGVzKQ0KDQpgYGANCiMjICoqVmFsaWRhY2nDs24gZGVsIG1vZGVsbyoqDQpSZXN1bHRhZG86IDEuIE1lZGlhIGNlcm86IFNlIGN1bXBsZSBwb3IgZGVmZWN0by4gMi4gVmFyaWFuemEgQ29uc3RhbnRlOiBTZSBvYnNlcnZhIGVuIGxhIGdyYWZpY2EgMSBkZSByZXNpZHVhbGVzIHZzIGFqdXN0YWRvcyBxdWUgZWwgY29tcG9ydGFtaWVudG8gZXMgYWxlYXRvcmlvIG1vc3RyYW5kbyB1bmEgbGV2ZSBjdXJ2YSBoYWNpYSBhYmFqby4gMy4gTm9ybWFsaWRhZDogU2Ugb2JzZXJ2YSBlbiBsYSBncmFmaWNhIDIgcXVlIGxvcyBkYXRvcyBzZSBhanVzdGFuIGJpZW4gYSBsYSBsaW5lYSBkZSBub3JtYWxpZGFkIGVuIGVsIHFxcGxvdCA0LiBJbmRlcGVuZGVuY2lhOiBEYWRvIHF1ZSBlc3RvcyByZWdpc3Ryb3Mgbm8gY29ycmVzcG9uZGVuIGEgZGF0b3MgZW4gZWwgdGllbXBvIG5vIHNlIHRpZW5lIHVuIG9yZGVuIHRlbXBvcmFsIHBhcmEgcmVhbGl6YXIgbGEgdmFsaWRhY2nDs24gZGUgZXN0ZSBzdXB1ZXN0by4NCg0KIEhpcMOzdGVzaXMgbnVsYSBIMDogUGFyYSBlc3RlIGNhc28gZWwgY29lZmljaWVudGUgQjEgbm8gYXBvcnRhIGFsIG1vZGVsbyBwcm9wdWVzdG8sIGRhZG8gcXVlIGVsIHAtdmFsdWUgZXMgbWVub3IgYWwgMC4wNSBjb24gdmFsb3IgY29ycmVzcG9uZGllbnRlIGEuKDYuNDNlLTA2ICksIHJlY2hhemFtb3MgbGEgaGlww7N0ZXNpcyBudWxhLCB5IHNlIHB1ZWRlIGNvbmNsdWlyIHF1ZSBlbCBjb2VmaWNpZW50ZSBCMSBzaSBhcG9ydGEgYWwgbW9kZWxvIGRlIHJlZ3Jlc2nDs24gcHJvcHVlc3RvLg0KDQpfIEhpcMOzdGVzaXMgbnVsYSBIMDogUGFyYSBlc3RlIGNhc28gZWwgY29lZmljaWVudGUgQjIgbm8gYXBvcnRhIGFsIG1vZGVsbyBwcm9wdWVzdG8sIGNvbW8gZWwgcC12YWx1ZSBlcyBtYXlvciBhbCAwLjA1ICgwLjEzNiksIE5PIHJlY2hhemFtb3MgbGEgaGlww7N0ZXNpcyBudWxhLCB5IGNvbmNsdWltb3MgcXVlIGVsIGNvZWZpY2llbnRlIEIyIE5PIGFwb3J0YSBhbCBtb2RlbG8gZGUgcmVncmVzacOzbiBwcm9wdWVzdG8uDQoNCiMjICoqTcOpdHJpY2FzIFJNU0UgeSBNQUUqKg0KYGBge3J9DQpwcmVkaWNjaW9uX2FyYm9sZXMgPC0gcHJlZGljdChvYmplY3QgPSBtb2RlbG9fYXJib2xlcywgbmV3ZGF0YSA9IGRhdGFhcmJvbGVzWy10cmFpbiwgXSkNCmVycm9yX2FyYm9sZXMgPC0gbWVhbigoZGF0YWFyYm9sZXMkcGVzb1stdHJhaW5dIC0gcHJlZGljY2lvbl9hcmJvbGVzKV4yKQ0KZXJyb3JfYXJib2xlcw0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoTWV0cmljcykNCm1hZShhcmJvbGVzJHBlc29bLXRyYWluXSwgcHJlZGljY2lvbl9hcmJvbGVzKQ0KYGBgDQpSZXN1bHRhZG86IFRlbmllbmRvIGVuIGN1ZW50YSBsYXMgdmFsaWRhY2lvbmVzIHNlIHB1ZWRlIGluZGljYXIgcXVlIGVsIG1vZGVsbyBzZSBlcXVpdm9jYSAgZW4gdW4gMTMlIGRlbCBwZXNvIHByb21lZGlvIGRlIGFjdWVyZG8gYWwgTUFFIHkgbGEgZGVzdmlhY2nDs24gZXN0w6FuZGFyIGRlIGxhIHZhcmlhbnphIGluZXhwbGljYWRhIGVzIGRlIDMuMCBkZSBhY3VlcmRvIGFsIFJNU0UuDQoNCg==