A finales de 2019 se identificó en Wuhan, China una gran cantidad de personas enfermas con neumonía, estudios de investigadores permitieron determinar que se trataba de un virus totalmente desconocido, un nuevo coronavirus. Coronavirus es una gran familia de virus conocidos por causar enfermedades respiratorias y gastrointestinales que van desde un resfriado común hasta manifestaciones clínicas más severas como las causadas por el síndrome respiratorio de Oriente Medio (MERS) y el síndrome respiratorio agudo grave (SARS). Este coronavirus llamado 2019 novel coronavirus (COVID-19) es de fácil transmisión y la gravedad de sus síntomas ha causado gran incertidumbre y temor debido a que el virus actualmente se ha propagado por más de 180 países.
Por ello, se propone estudiar una base de datos sobre el COVID-19 actualizada día a día en Kaggle nombrada como \(covid\_19\_data.csv\).
Descripción de la base de datos
Esta es una base de datos con 11341 observaciones y 8 variables que son:
- Sno: número de observación.
- ObservationDate: Fecha de observación MM/DD/AAAA.
- Province/State: Provincia o estado de la observación (Podría estar vacía cuando falta).
- Country/Region: País de la observación.
- Last Update: Hora en UTC en la que se actualiza la fila para la provincia o país dado sin estandarizar.
- Confirmed: Número acumulado de casos confirmados hasta esa fecha.
- Deaths: Número acumulado de muertes hasta esa fecha.
- Recovered: Número acumulado de casos recuperados hasta esa fecha.
Objetivo
 |
Modelar la cantidad de infectados por el virus COVID-19 que se pueden detectar en una fecha teniendo en cuenta la cantidad de casos confirmados y su diferencia entre los muertos y recuperados para cada uno de los países de Sur América con el fin de determinar el incremento de infección |
Análisis descriptivo
A continuación se presenta un resumen de la base de datos original:
## SNo Observation_Date Province_State Country_Region
## Min. : 1 Min. :2020-01-22 :3595 US :4796
## 1st Qu.: 2836 1st Qu.:2020-03-01 Texas : 267 Mainland China:1920
## Median : 5671 Median :2020-03-15 Georgia : 173 Australia : 331
## Mean : 5671 Mean :2020-03-08 Virginia: 146 Canada : 266
## 3rd Qu.: 8506 3rd Qu.:2020-03-23 Kentucky: 134 France : 136
## Max. :11341 Max. :2020-03-23 Missouri: 130 UK : 102
## (Other) :6896 (Other) :3790
## Last_Update Confirmed Deaths Recovered
## 2020-03-23 23:19:34:3179 Min. : 0.0 Min. : 0.00 Min. : 0
## 2020-03-11T20:00:00: 197 1st Qu.: 1.0 1st Qu.: 0.00 1st Qu.: 0
## 2020-03-23 23:19:21: 182 Median : 5.0 Median : 0.00 Median : 0
## 2020-03-16T14:38:45: 118 Mean : 491.6 Mean : 17.52 Mean : 175
## 2020-03-15T18:20:18: 91 3rd Qu.: 71.0 3rd Qu.: 0.00 3rd Qu.: 2
## 2020-03-15T18:20:19: 71 Max. :67800.0 Max. :6077.00 Max. :59882
## (Other) :7503
Donde se puede ver la cantidad de observaciones que tiene la base de datos original, junto a la fecha de inicio de los registros con la última registrada. Además, la variable que contiene la provincia o estado son la única variabla con Na’s. Hay un país donde han detectado más de 67000 casos de COVID-19 y otro donde han muerto un poco más de 6000 personas. Lo cual es bastante desconsolador teniendo en cuenta el corto periodo de tiempo entre el 22 de enero hasta el 23 de marzo de 2020.
Con el fin de poder realizar el análisis jerárquico se realizaron algunos arreglos en la base de datos. Se filtró la base para los países de América del Sur únicamente. Además, se eliminaron variables innecesarias como \(SNo\) y \(Last\_Update\) pero se incluyeron dos nuevas que son: \(Infected\) (número de personas infectadas a la fecha) que se estima de la siguiente manera: \(Infected=Confirmed-Deaths-Recovered\) y \(ID\_Country\) que es el identificador del país asignado por orden alfabético. Por último, se hizo que el origen de detección del virus o fecha 0 coincidiera con la fecha 26 de febrero de 2020 puesto que en esta parte del continente se detecto el primer caso ese día. Por ello, para conocer su estructura se presentan las primeras observaciones de la nueva base de datos:
## Observation_Date ID_Country Country_Region Confirmed Deaths Recovered
## 1 0 1 Argentina 0 0 0
## 2 1 1 Argentina 0 0 0
## 3 2 1 Argentina 0 0 0
## 4 3 1 Argentina 0 0 0
## 5 4 1 Argentina 0 0 0
## 6 5 1 Argentina 0 0 0
## Infected
## 1 0
## 2 0
## 3 0
## 4 0
## 5 0
## 6 0
De la base de datos anterior, se puede ver también:

El número de muertes por COVID-19 incrementa a medida que el número de casos confirmados aumenta, en otras palabras, el número de contagiados y la cantidad de personas que mueren son cantidades que aumentan proporcionalmente.

En trece de los dieciséis países de América del Sur, por lo menos, una persona posee el virus actualmente. En seis de ellos hay más de mil casos confirmados a la fecha.

En orden decreciente Brazil, Ecuador y Argentina, tienen un número de muertes que ya supero los veinticinco pero países como Chile, Perú y Colombia mantienen tasas de mortalidad bajas aunque la cantidad de infectados sea alta. Comparando Argentina y Colombia que tienen una cantidad de casos confirmados similares se puede notar una gran diferencia entre la mortalidad en cada país.

Así, como ha tenido más muertes, Argentina, ha podido recuperar más pacientes con COVID-19 que ningun otro país y Venezuela que no tiene tantos casos confirmados ha podido recuperar a más personas con la enfermedad.
Veamos ahora, lo que se desea modelar, en la escala normal:

Por las formas exponenciales visibles en los gráficos se proponen dos procedimientos: el primero, tomar la variable \(Infected\) como el logaritmo y el segundo, la variable \(Infected\) como una respuesta \(Poisson\). Siguiendo el primer procedimiento, la gráfica quedaría:

Realizando un test de Shapiro-Wilk, se determinó que la variable \(Infected\) no se distribuye Normal, por lo tanto, se realiza la segunda propuesta de procedimiento.
Modelos a considerar
Modelo 1
\[Infected_{ij} \sim Poisson(\lambda_{ij})\] \[log(\lambda_{ij}) = \beta_0+\beta_1 Observation\_Date_{ij}+ b_{oi}\] \[b_0 \sim N(0, \sigma_{b_0}^2)\] con un vector de parámetros \(\Theta=(\beta_0, \beta_1, \sigma_{b_0})^T\)
Modelo 2
\[Infected_{ij} \sim Poisson(\lambda_{ij})\] \[log(\lambda_{ij}) = \beta_0+\beta_1 Observation\_Date_{ij}+ b_{oi}+b_{1i} Observation\_Date_{ij}\] \[\begin{pmatrix}
b_0 \\
b_1
\end{pmatrix} \sim N \left[ \begin{pmatrix}
0 \\
0
\end{pmatrix}, \begin{pmatrix}
\sigma_{b_0}^2 & \sigma_{b_{01}}^2 \\
\sigma_{b_{01}}^2 & \sigma_{b_1}^2
\end{pmatrix} \right]\] con un vector de parámetros \(\Theta=(\beta_0, \beta_1, \sigma_{b_0}, \sigma_{b_1}, \sigma_{b_{01}})^T\)
Modelo 3
\[Infected_{ij} \sim Poisson(\lambda_{ij})\] \[log(\lambda_{ij}) = \beta_0+\beta_1 Observation\_Date_{ij} + \beta_2Deaths_{ij} + \beta_3Recovered_{ij} + b_{oi}+b_{1i} Observation\_Date_{ij}\] \[\begin{pmatrix}
b_0 \\
b_1
\end{pmatrix} \sim N \left[ \begin{pmatrix}
0 \\
0
\end{pmatrix}, \begin{pmatrix}
\sigma_{b_0}^2 & \sigma_{b_{01}}^2 \\
\sigma_{b_{01}}^2 & \sigma_{b_1}^2
\end{pmatrix} \right]\] con un vector de parámetros \(\Theta=(\beta_0, \beta_1, \beta_2, \beta_3, \sigma_{b_0}, \sigma_{b_1}, \sigma_{b_{01}})^T\)
Construcción de los modelos
Modelo 1
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: poisson ( log )
## Formula: Infected ~ Observation_Date + (1 | ID_Country)
## Data: covid
##
## AIC BIC logLik deviance df.resid
## 2493.7 2505.3 -1243.9 2487.7 348
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -6.9732 -0.8589 -0.3160 0.5786 9.1132
##
## Random effects:
## Groups Name Variance Std.Dev.
## ID_Country (Intercept) 2.808 1.676
## Number of obs: 351, groups: ID_Country, 13
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.842229 0.467902 -6.074 1.24e-09 ***
## Observation_Date 0.298312 0.002138 139.523 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## Observtn_Dt -0.106
Modelo 2
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: poisson ( log )
## Formula: Infected ~ Observation_Date + (Observation_Date | ID_Country)
## Data: covid
##
## AIC BIC logLik deviance df.resid
## 2228.4 2247.7 -1109.2 2218.4 346
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -5.5692 -0.9436 -0.3969 0.4434 8.5034
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID_Country (Intercept) 2.492418 1.57874
## Observation_Date 0.003678 0.06065 -0.36
## Number of obs: 351, groups: ID_Country, 13
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.25797 0.45646 -4.947 7.55e-07 ***
## Observation_Date 0.27171 0.01773 15.323 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr)
## Observtn_Dt -0.413
Modelo 3
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: poisson ( log )
## Formula:
## Infected ~ Observation_Date + Deaths + Recovered + (Observation_Date |
## ID_Country)
## Data: covid
##
## AIC BIC logLik deviance df.resid
## 2208.8 2235.8 -1097.4 2194.8 344
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -5.6087 -0.9337 -0.3963 0.4000 8.6509
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID_Country (Intercept) 2.449785 1.56518
## Observation_Date 0.003699 0.06082 -0.34
## Number of obs: 351, groups: ID_Country, 13
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.336606 0.453561 -5.152 2.58e-07 ***
## Observation_Date 0.276224 0.017833 15.490 < 2e-16 ***
## Deaths 0.001654 0.001591 1.040 0.299
## Recovered -0.013902 0.002971 -4.679 2.89e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) Obsr_D Deaths
## Observtn_Dt -0.404
## Deaths 0.028 -0.041
## Recovered 0.044 -0.063 0.002
Análisis de residuales
Modelo 1

Modelo 2

Modelo 3

Comparación de los modelos
Se puede notar en los residuales de los ajustes anteriores que la varianza aún tiene algunos problemas de homogeneidad. Por ello, se propone un último modelo y corregir dicho problema. El resultado del modelo es el siguiente:
## Generalized linear mixed model fit by maximum likelihood (Laplace
## Approximation) [glmerMod]
## Family: poisson ( log )
## Formula: Infected ~ poly(Observation_Date, 4) + (Observation_Date | ID_Country)
## Data: covid
##
## AIC BIC logLik deviance df.resid
## 2154.5 2185.4 -1069.2 2138.5 343
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -5.6401 -0.8734 -0.2990 0.3598 12.2654
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## ID_Country (Intercept) 2.716115 1.64806
## Observation_Date 0.004479 0.06693 -0.44
## Number of obs: 351, groups: ID_Country, 13
##
## Fixed effects:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 1.0121 0.4230 2.393 0.016723 *
## poly(Observation_Date, 4)1 46.4221 3.3563 13.831 < 2e-16 ***
## poly(Observation_Date, 4)2 -5.4227 1.6450 -3.297 0.000979 ***
## poly(Observation_Date, 4)3 3.2578 1.0861 3.000 0.002704 **
## poly(Observation_Date, 4)4 -1.9724 0.4286 -4.602 4.19e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) p(O_D,4)1 p(O_D,4)2 p(O_D,4)3
## ply(O_D,4)1 -0.035
## ply(O_D,4)2 0.143 -0.516
## ply(O_D,4)3 -0.117 0.444 -0.939
## ply(O_D,4)4 0.088 -0.342 0.771 -0.921
Al comparar los modelos por una prueba de verosimilitud sencilla, se puede determinar que:
## Data: covid
## Models:
## mod1: Infected ~ Observation_Date + (1 | ID_Country)
## mod2: Infected ~ Observation_Date + (Observation_Date | ID_Country)
## mod3: Infected ~ Observation_Date + Deaths + Recovered + (Observation_Date |
## mod3: ID_Country)
## mod4: Infected ~ poly(Observation_Date, 4) + (Observation_Date | ID_Country)
## Df AIC BIC logLik deviance Chisq Chi Df Pr(>Chisq)
## mod1 3 2493.7 2505.3 -1243.9 2487.7
## mod2 5 2228.4 2247.7 -1109.2 2218.4 269.340 2 < 2.2e-16 ***
## mod3 7 2208.8 2235.8 -1097.4 2194.8 23.629 2 7.397e-06 ***
## mod4 8 2154.5 2185.4 -1069.2 2138.5 56.265 1 6.333e-14 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Añadir cada una de las variables a cada modelo consecutivamente a llevado a mejorar el modelo, esto se refleja en el análisis de la correlación de Pearson que se muestra a continuación:
## [1] 0.9919989
## [1] 0.9948642
## [1] 0.9949198
## [1] 0.9955308
Siendo el último resultado, el correspondiente al modelo 4, eso quiere decir que es un mejor modelo que los otros. Sus residuales también muestran gran mejoría mostrando una dispersión más homogénea:

Presentación del mejor modelo
Para terminar se desea visualizar como quedó el modelo. Se presenta aquí:

Viendo las gráficas parecen satisfactorias puesto que el comportamiento de las curvas por grupo sigue la tendencia de los puntos como se debe. Esto podría ser útil para predecir cantidad de infectados con solo darle al modelo la fecha que queremos predecir. Por ejemplo, el último valor observado en la base de datos para la variable \(Observation\_Date\) es \(26\) el registro corresponde al día 23 de marzo de 2020 que realmente pertenece a la información recolectada durante el día 22 de marzo, tomando como \(Country\_Region\) a Colombia por la base se sabe que ese día habían 269 casos de personas infectadas, el modelo predice para el día 23 de marzo 291 infectados aproximadamente. Haciendo lo mismo para el día 25 de marzo, se predicen 384 infectados, según el Ministerio de Salud en Colombia fueron 458 personas con la enfermedad. Esta diferencia se presenta puesto que solo se tienen 27 observaciones por grupo pero sirve para conocer la propagación del virus en distintas poblaciones, también como motivador para continuar con el periodo de cuarentena y seguir las recomendaciones, tanto como buscar nuevas estrategias para lograr que el virus no se siga propagando a la velocidad que lo hace actualmente. Para que el modelo siga trabajando y mejore en sus predicciones, es recomendable actualizar la base de datos diariamente, o en lo posible, cuando se vaya a usar el modelo.
LS0tDQp0aXRsZTogTW9kZWxvcyBqZXLDoXJxdWljb3MgcGFyYSBwcmVkZWNpciBlbCBuw7ptZXJvIGRlIGluZmVjdGFkb3MgcG9yIENPVklELTE5IGVuIEFtw6lyaWNhIGRlbCBTdXINCmF1dGhvcjogIkx1aXMgRmVsaXBlIEJlZG95YSBNYXJ0w61uZXoiDQpkYXRlOiAiTWFyem8gMjUsIDIwMjAiDQoNCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCi0tLQ0KDQo8c3R5bGU+DQpib2R5IHsNCnRleHQtYWxpZ246IGp1c3RpZnl9DQo8L3N0eWxlPg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQpBIGZpbmFsZXMgZGUgMjAxOSBzZSBpZGVudGlmaWPDsyBlbiBXdWhhbiwgQ2hpbmEgdW5hIGdyYW4gY2FudGlkYWQgZGUgcGVyc29uYXMgZW5mZXJtYXMgY29uIG5ldW1vbsOtYSwgZXN0dWRpb3MgZGUgaW52ZXN0aWdhZG9yZXMgcGVybWl0aWVyb24gZGV0ZXJtaW5hciBxdWUgc2UgdHJhdGFiYSBkZSB1biB2aXJ1cyB0b3RhbG1lbnRlIGRlc2Nvbm9jaWRvLCB1biBudWV2byBjb3JvbmF2aXJ1cy4gQ29yb25hdmlydXMgZXMgdW5hIGdyYW4gZmFtaWxpYSBkZSB2aXJ1cyBjb25vY2lkb3MgcG9yIGNhdXNhciBlbmZlcm1lZGFkZXMgcmVzcGlyYXRvcmlhcyB5IGdhc3Ryb2ludGVzdGluYWxlcyBxdWUgdmFuIGRlc2RlIHVuIHJlc2ZyaWFkbyBjb23Dum4gaGFzdGEgbWFuaWZlc3RhY2lvbmVzIGNsw61uaWNhcyBtw6FzIHNldmVyYXMgY29tbyBsYXMgY2F1c2FkYXMgcG9yIGVsIHPDrW5kcm9tZSByZXNwaXJhdG9yaW8gZGUgT3JpZW50ZSBNZWRpbyAoTUVSUykgeSBlbCBzw61uZHJvbWUgcmVzcGlyYXRvcmlvIGFndWRvIGdyYXZlIChTQVJTKS4gRXN0ZSBjb3JvbmF2aXJ1cyBsbGFtYWRvIDIwMTkgbm92ZWwgY29yb25hdmlydXMgKENPVklELTE5KSBlcyBkZSBmw6FjaWwgdHJhbnNtaXNpw7NuIHkgbGEgZ3JhdmVkYWQgZGUgc3VzIHPDrW50b21hcyBoYSBjYXVzYWRvIGdyYW4gaW5jZXJ0aWR1bWJyZSB5IHRlbW9yIGRlYmlkbyBhIHF1ZSBlbCB2aXJ1cyBhY3R1YWxtZW50ZSBzZSBoYSBwcm9wYWdhZG8gcG9yIG3DoXMgZGUgMTgwIHBhw61zZXMuDQoNCjxjZW50ZXI+IVtdKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvYi9iMy9DT1ZJRC0xOS1vdXRicmVhay10aW1lbGluZS5naWYpe3dpZHRoPTUwMHB4fTwvY2VudGVyPg0KDQpQb3IgZWxsbywgc2UgcHJvcG9uZSBlc3R1ZGlhciB1bmEgW2Jhc2VdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vc3VkYWxhaXJhamt1bWFyL25vdmVsLWNvcm9uYS12aXJ1cy0yMDE5LWRhdGFzZXQvZG93bmxvYWQpIGRlIGRhdG9zIHNvYnJlIGVsIENPVklELTE5IGFjdHVhbGl6YWRhIGTDrWEgYSBkw61hIGVuIFtLYWdnbGVdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vc3VkYWxhaXJhamt1bWFyL25vdmVsLWNvcm9uYS12aXJ1cy0yMDE5LWRhdGFzZXQpIG5vbWJyYWRhIGNvbW8gJGNvdmlkXF8xOVxfZGF0YS5jc3YkLiAgDQoNCiMgRGVzY3JpcGNpw7NuIGRlIGxhIGJhc2UgZGUgZGF0b3MNCg0KRXN0YSBlcyB1bmEgYmFzZSBkZSBkYXRvcyBjb24gMTEzNDEgb2JzZXJ2YWNpb25lcyB5IDggdmFyaWFibGVzIHF1ZSBzb246DQoNCi0gKipTbm86KiogbsO6bWVybyBkZSBvYnNlcnZhY2nDs24uDQotICoqT2JzZXJ2YXRpb25EYXRlOioqIEZlY2hhIGRlIG9ic2VydmFjacOzbiBNTS9ERC9BQUFBLg0KLSAqKlByb3ZpbmNlL1N0YXRlOioqIFByb3ZpbmNpYSBvIGVzdGFkbyBkZSBsYSBvYnNlcnZhY2nDs24gKFBvZHLDrWEgZXN0YXIgdmFjw61hIGN1YW5kbyBmYWx0YSkuDQotICoqQ291bnRyeS9SZWdpb246KiogUGHDrXMgZGUgbGEgb2JzZXJ2YWNpw7NuLg0KLSAqKkxhc3QgVXBkYXRlOioqIEhvcmEgZW4gVVRDIGVuIGxhIHF1ZSBzZSBhY3R1YWxpemEgbGEgZmlsYSBwYXJhIGxhIHByb3ZpbmNpYSBvIHBhw61zIGRhZG8gc2luIGVzdGFuZGFyaXphci4NCi0gKipDb25maXJtZWQ6KiogTsO6bWVybyBhY3VtdWxhZG8gZGUgY2Fzb3MgY29uZmlybWFkb3MgaGFzdGEgZXNhIGZlY2hhLg0KLSAqKkRlYXRoczoqKiBOw7ptZXJvIGFjdW11bGFkbyBkZSBtdWVydGVzIGhhc3RhIGVzYSBmZWNoYS4NCi0gKipSZWNvdmVyZWQ6KiogTsO6bWVybyBhY3VtdWxhZG8gZGUgY2Fzb3MgcmVjdXBlcmFkb3MgaGFzdGEgZXNhIGZlY2hhLg0KDQojIE9iamV0aXZvDQoNCnwgIHwgIHwNCnwtLS18LS0tfA0KfCAhW10oY292aWQtMTkuanBnKXt3aWR0aD0yNTBweH0gfCBNb2RlbGFyIGxhIGNhbnRpZGFkIGRlIGluZmVjdGFkb3MgcG9yIGVsIHZpcnVzIENPVklELTE5IHF1ZSBzZSBwdWVkZW4gZGV0ZWN0YXIgZW4gdW5hIGZlY2hhIHRlbmllbmRvIGVuIGN1ZW50YSBsYSBjYW50aWRhZCBkZSBjYXNvcyBjb25maXJtYWRvcyB5IHN1IGRpZmVyZW5jaWEgZW50cmUgbG9zIG11ZXJ0b3MgeSByZWN1cGVyYWRvcyBwYXJhIGNhZGEgdW5vIGRlIGxvcyBwYcOtc2VzIGRlIFN1ciBBbcOpcmljYSBjb24gZWwgZmluIGRlIGRldGVybWluYXIgZWwgaW5jcmVtZW50byBkZSBpbmZlY2Npw7NuIHwNCg0KIyBBbsOhbGlzaXMgZGVzY3JpcHRpdm8NCg0KYGBge3IgZWNobz1GQUxTRX0NCiMgTGVjdHVyYSBkZSBsYSBiYXNlIGRlIGRhdG9zDQpDb3ZpZCA8LSByZWFkLmNzdigiY292aWRfMTlfZGF0YS5jc3YiLCANCiAgICAgICAgICAgICAgICAgIGNvbC5uYW1lcyA9IGMoIlNObyIsICJPYnNlcnZhdGlvbl9EYXRlIiwgIlByb3ZpbmNlX1N0YXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvdW50cnlfUmVnaW9uIiwgIkxhc3RfVXBkYXRlIiwgIkNvbmZpcm1lZCIsICJEZWF0aHMiLCAiUmVjb3ZlcmVkIikpDQoNCiMgT2JzZXJ2YXRpb25fRGF0ZSBlbiBmb3JtYXRvIGZlY2hhDQpDb3ZpZCRPYnNlcnZhdGlvbl9EYXRlIDwtIGFzLkRhdGUoQ292aWQkT2JzZXJ2YXRpb25fRGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyV5IikNCmBgYA0KDQpBIGNvbnRpbnVhY2nDs24gc2UgcHJlc2VudGEgdW4gcmVzdW1lbiBkZSBsYSBiYXNlIGRlIGRhdG9zIG9yaWdpbmFsOg0KDQpgYGB7cn0NCnN1bW1hcnkoQ292aWQpDQpgYGANCg0KRG9uZGUgc2UgcHVlZGUgdmVyIGxhIGNhbnRpZGFkIGRlIG9ic2VydmFjaW9uZXMgcXVlIHRpZW5lIGxhIGJhc2UgZGUgZGF0b3Mgb3JpZ2luYWwsIGp1bnRvIGEgbGEgZmVjaGEgZGUgaW5pY2lvIGRlIGxvcyByZWdpc3Ryb3MgY29uIGxhIMO6bHRpbWEgcmVnaXN0cmFkYS4gQWRlbcOhcywgbGEgdmFyaWFibGUgcXVlIGNvbnRpZW5lIGxhIHByb3ZpbmNpYSBvIGVzdGFkbyBzb24gbGEgw7puaWNhIHZhcmlhYmxhIGNvbiBOYSdzLiBIYXkgdW4gcGHDrXMgZG9uZGUgaGFuIGRldGVjdGFkbyBtw6FzIGRlIDY3MDAwIGNhc29zIGRlIENPVklELTE5IHkgb3RybyBkb25kZSBoYW4gbXVlcnRvIHVuIHBvY28gbcOhcyBkZSA2MDAwIHBlcnNvbmFzLiBMbyBjdWFsIGVzIGJhc3RhbnRlIGRlc2NvbnNvbGFkb3IgdGVuaWVuZG8gZW4gY3VlbnRhIGVsIGNvcnRvIHBlcmlvZG8gZGUgdGllbXBvIGVudHJlIGVsIDIyIGRlIGVuZXJvIGhhc3RhIGVsIDIzIGRlIG1hcnpvIGRlIDIwMjAuDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEJhc2UgZGUgZGF0b3MgcGHDrXNlcyBTdXIgQW3DqXJpY2ENCnVybCA8LSB1cmwoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9hanR1cm5lci9hY2V0YXRlL21hc3Rlci9wbGFjZXMvQ291bnRyaWVzLVNvdXRoLUFtZXJpY2EuY3N2IikNCnNvdXRoIDwtIHJlYWQuY3N2KHVybCkNCg0Kbm9tYnJlcyA8LSBhcy5jaGFyYWN0ZXIoc291dGgkbmFtZSkNCm5vbWJyZXMgPC0gbm9tYnJlc1tvcmRlcihub21icmVzKV0NCg0Kc3VyYW1lcmljYSA8LSBDb3ZpZFtDb3ZpZCRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzFdIHwgQ292aWQkQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1syXSB8IA0KICAgICAgICAgICAgICAgICAgICBDb3ZpZCRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzNdIHwgQ292aWQkQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1s0XSB8IA0KICAgICAgICAgICAgICAgICAgICBDb3ZpZCRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzVdIHwgQ292aWQkQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1s2XSB8IA0KICAgICAgICAgICAgICAgICAgICBDb3ZpZCRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzddIHwgQ292aWQkQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1s4XSB8IA0KICAgICAgICAgICAgICAgICAgICBDb3ZpZCRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzldIHwgQ292aWQkQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1sxMF0gfCANCiAgICAgICAgICAgICAgICAgICAgQ292aWQkQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1sxMV0gfCBDb3ZpZCRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzEyXSB8IA0KICAgICAgICAgICAgICAgICAgICBDb3ZpZCRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzEzXSB8IENvdmlkJENvdW50cnlfUmVnaW9uID09IG5vbWJyZXNbMTRdIHwgDQogICAgICAgICAgICAgICAgICAgIENvdmlkJENvdW50cnlfUmVnaW9uID09IG5vbWJyZXNbMTVdIHwgQ292aWQkQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1sxNl0sIF0NCg0KbGlicmFyeShkcGx5cikNCmNvbnRlbyA8LSBzdXJhbWVyaWNhICU+JSBncm91cF9ieShPYnNlcnZhdGlvbl9EYXRlLCBDb3VudHJ5X1JlZ2lvbikNCg0KY29udGVvJElEX0NvdW50cnkgPC0gaWZlbHNlKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzFdLCAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzJdLCAyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb250ZW8kQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1szXSwgMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzRdLCA0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzVdLCA1LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb250ZW8kQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1s2XSwgNiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzddLCA3LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzhdLCA4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb250ZW8kQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1s5XSwgOSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA9PSBub21icmVzWzEwXSwgMTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb250ZW8kQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1sxMV0sIDExLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb250ZW8kQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1sxMl0sIDEyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29udGVvJENvdW50cnlfUmVnaW9uID09IG5vbWJyZXNbMTNdLCAxMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb250ZW8kQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1sxNF0sIDE0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb250ZW8kQ291bnRyeV9SZWdpb24gPT0gbm9tYnJlc1sxNV0sIDE1LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxNikpKSkpKSkpKSkpKSkpKQ0KDQpjb250ZW8gPC0gY29udGVvWy0yOi0xLCBdDQoNCmNvbnRlbyRDb3VudHJ5X1JlZ2lvbiA8LSBhcy5mYWN0b3IoYXMuY2hhcmFjdGVyKGNvbnRlbyRDb3VudHJ5X1JlZ2lvbikpDQpjb250ZW8kT2JzZXJ2YXRpb25fRGF0ZSA8LSBhcy5udW1lcmljKGNvbnRlbyRPYnNlcnZhdGlvbl9EYXRlKSAtIGFzLm51bWVyaWMoYXMuRGF0ZSgiMjAyMC0wMi0yNiIpKQ0KY29udGVvJEluZmVjdGVkIDwtIHdpdGgoY29udGVvLCBDb25maXJtZWQgLSBEZWF0aHMgLSBSZWNvdmVyZWQpDQoNCnBydWViYSA8LSBkYXRhLmZyYW1lKE9ic2VydmF0aW9uX0RhdGUgPSByZXAoMDoyNiwgdGltZXMgPSAxMyksIElEX0NvdW50cnkgPSByZXAoYygxOjYsIDg6OSwgMTE6MTIsIDE0OjE2KSwgZWFjaCA9IDI3KSwgQ291bnRyeV9SZWdpb24gPSByZXAobm9tYnJlc1tjKC03LCAtMTAsIC0xMyldLCBlYWNoID0gMjcpKQ0KDQpjb3ZpZCA8LSBsZWZ0X2pvaW4ocHJ1ZWJhLCBjb250ZW8pDQpjb3ZpZCA8LSBhcy5kYXRhLmZyYW1lKGFwcGx5KGNvdmlkLCAyLCBmdW5jdGlvbih4KSBpZmVsc2UoaXMubmEoeCksIDAsIGFzLm51bWVyaWMoeCkpKSkNCmNvdmlkIDwtIGNvdmlkWywgLTY6LTRdDQpjb3ZpZCRDb3VudHJ5X1JlZ2lvbiA8LSByZXAobm9tYnJlc1tjKC03LCAtMTAsIC0xMyldLCBlYWNoID0gMjcpDQpjb3ZpZCRDb3VudHJ5X1JlZ2lvbiA8LSBhcy5mYWN0b3IoY292aWQkQ291bnRyeV9SZWdpb24pDQpjb3ZpZCRJRF9Db3VudHJ5IDwtIGFzLmZhY3Rvcihjb3ZpZCRJRF9Db3VudHJ5KQ0KYGBgDQoNCkNvbiBlbCBmaW4gZGUgcG9kZXIgcmVhbGl6YXIgZWwgYW7DoWxpc2lzIGplcsOhcnF1aWNvIHNlIHJlYWxpemFyb24gYWxndW5vcyBhcnJlZ2xvcyBlbiBsYSBiYXNlIGRlIGRhdG9zLiBTZSBmaWx0csOzIGxhIGJhc2UgcGFyYSBsb3MgcGHDrXNlcyBkZSBBbcOpcmljYSBkZWwgU3VyIMO6bmljYW1lbnRlLiBBZGVtw6FzLCBzZSBlbGltaW5hcm9uIHZhcmlhYmxlcyBpbm5lY2VzYXJpYXMgY29tbyAkU05vJCB5ICRMYXN0XF9VcGRhdGUkIHBlcm8gc2UgaW5jbHV5ZXJvbiBkb3MgbnVldmFzIHF1ZSBzb246ICRJbmZlY3RlZCQgKG7Dum1lcm8gZGUgcGVyc29uYXMgaW5mZWN0YWRhcyBhIGxhIGZlY2hhKSBxdWUgc2UgZXN0aW1hIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6ICRJbmZlY3RlZD1Db25maXJtZWQtRGVhdGhzLVJlY292ZXJlZCQgeSAkSURcX0NvdW50cnkkIHF1ZSBlcyBlbCBpZGVudGlmaWNhZG9yIGRlbCBwYcOtcyBhc2lnbmFkbyBwb3Igb3JkZW4gYWxmYWLDqXRpY28uIFBvciDDumx0aW1vLCBzZSBoaXpvIHF1ZSBlbCBvcmlnZW4gZGUgZGV0ZWNjacOzbiBkZWwgdmlydXMgbyBmZWNoYSAwIGNvaW5jaWRpZXJhIGNvbiBsYSBmZWNoYSAyNiBkZSBmZWJyZXJvIGRlIDIwMjAgcHVlc3RvIHF1ZSBlbiBlc3RhIHBhcnRlIGRlbCBjb250aW5lbnRlIHNlIGRldGVjdG8gZWwgcHJpbWVyIGNhc28gZXNlIGTDrWEuIFBvciBlbGxvLCBwYXJhIGNvbm9jZXIgc3UgZXN0cnVjdHVyYSBzZSBwcmVzZW50YW4gbGFzIHByaW1lcmFzIG9ic2VydmFjaW9uZXMgZGUgbGEgbnVldmEgYmFzZSBkZSBkYXRvczoNCg0KYGBge3J9DQpoZWFkKGNvdmlkKQ0KYGBgDQoNCkRlIGxhIGJhc2UgZGUgZGF0b3MgYW50ZXJpb3IsIHNlIHB1ZWRlIHZlciB0YW1iacOpbjoNCg0KYGBge3IgZWNobz1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChjb3ZpZCwgYWVzKERlYXRocywgQ29uZmlybWVkKSkgKyBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpDQpgYGANCg0KRWwgbsO6bWVybyBkZSBtdWVydGVzIHBvciBDT1ZJRC0xOSBpbmNyZW1lbnRhIGEgbWVkaWRhIHF1ZSBlbCBuw7ptZXJvIGRlIGNhc29zIGNvbmZpcm1hZG9zIGF1bWVudGEsIGVuIG90cmFzIHBhbGFicmFzLCBlbCBuw7ptZXJvIGRlIGNvbnRhZ2lhZG9zIHkgbGEgY2FudGlkYWQgZGUgcGVyc29uYXMgcXVlIG11ZXJlbiBzb24gY2FudGlkYWRlcyBxdWUgYXVtZW50YW4gcHJvcG9yY2lvbmFsbWVudGUuDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpiYXIxIDwtIGNvdmlkICU+JSBncm91cF9ieShDb3VudHJ5X1JlZ2lvbikgJT4lIHN1bW1hcmlzZShDb25maXJtZWQ9c3VtKENvbmZpcm1lZCkpDQpnZ3Bsb3QoYmFyMSwgYWVzKENvdW50cnlfUmVnaW9uLCBDb25maXJtZWQsIGNvbG9yID0gQ291bnRyeV9SZWdpb24sIGZpbGw9Q291bnRyeV9SZWdpb24pKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKyB0aGVtZV9idygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKQ0KYGBgDQoNCkVuIHRyZWNlIGRlIGxvcyBkaWVjaXPDqWlzIHBhw61zZXMgZGUgQW3DqXJpY2EgZGVsIFN1ciwgcG9yIGxvIG1lbm9zLCB1bmEgcGVyc29uYSBwb3NlZSBlbCB2aXJ1cyBhY3R1YWxtZW50ZS4gRW4gc2VpcyBkZSBlbGxvcyBoYXkgbcOhcyBkZSBtaWwgY2Fzb3MgY29uZmlybWFkb3MgYSBsYSBmZWNoYS4NCg0KYGBge3IgZWNobz1GQUxTRX0NCmJhcjIgPC0gY292aWQgJT4lIGdyb3VwX2J5KENvdW50cnlfUmVnaW9uKSAlPiUgc3VtbWFyaXNlKERlYXRocz1zdW0oRGVhdGhzKSkNCmdncGxvdChiYXIyLCBhZXMoQ291bnRyeV9SZWdpb24sIERlYXRocywgY29sb3IgPSBDb3VudHJ5X1JlZ2lvbiwgZmlsbD1Db3VudHJ5X1JlZ2lvbikpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArIHRoZW1lX2J3KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgaGp1c3QgPSAxKSkNCmBgYA0KDQpFbiBvcmRlbiBkZWNyZWNpZW50ZSBCcmF6aWwsIEVjdWFkb3IgeSBBcmdlbnRpbmEsIHRpZW5lbiB1biBuw7ptZXJvIGRlIG11ZXJ0ZXMgcXVlIHlhIHN1cGVybyBsb3MgdmVpbnRpY2luY28gcGVybyBwYcOtc2VzIGNvbW8gQ2hpbGUsIFBlcsO6IHkgQ29sb21iaWEgbWFudGllbmVuIHRhc2FzIGRlIG1vcnRhbGlkYWQgYmFqYXMgYXVucXVlIGxhIGNhbnRpZGFkIGRlIGluZmVjdGFkb3Mgc2VhIGFsdGEuIENvbXBhcmFuZG8gQXJnZW50aW5hIHkgQ29sb21iaWEgcXVlIHRpZW5lbiB1bmEgY2FudGlkYWQgZGUgY2Fzb3MgY29uZmlybWFkb3Mgc2ltaWxhcmVzIHNlIHB1ZWRlIG5vdGFyIHVuYSBncmFuIGRpZmVyZW5jaWEgZW50cmUgbGEgbW9ydGFsaWRhZCBlbiBjYWRhIHBhw61zLg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KYmFyMyA8LSBjb3ZpZCAlPiUgZ3JvdXBfYnkoQ291bnRyeV9SZWdpb24pICU+JSBzdW1tYXJpc2UoUmVjb3ZlcmVkPXN1bShSZWNvdmVyZWQpKQ0KZ2dwbG90KGJhcjMsIGFlcyhDb3VudHJ5X1JlZ2lvbiwgUmVjb3ZlcmVkLCBjb2xvciA9IENvdW50cnlfUmVnaW9uLCBmaWxsPUNvdW50cnlfUmVnaW9uKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCBoanVzdCA9IDEpKQ0KYGBgDQoNCkFzw60sIGNvbW8gaGEgdGVuaWRvIG3DoXMgbXVlcnRlcywgQXJnZW50aW5hLCBoYSBwb2RpZG8gcmVjdXBlcmFyIG3DoXMgcGFjaWVudGVzIGNvbiBDT1ZJRC0xOSBxdWUgbmluZ3VuIG90cm8gcGHDrXMgeSBWZW5lenVlbGEgcXVlIG5vIHRpZW5lIHRhbnRvcyBjYXNvcyBjb25maXJtYWRvcyBoYSBwb2RpZG8gcmVjdXBlcmFyIGEgbcOhcyBwZXJzb25hcyBjb24gbGEgZW5mZXJtZWRhZC4NCg0KVmVhbW9zIGFob3JhLCBsbyBxdWUgc2UgZGVzZWEgbW9kZWxhciwgZW4gbGEgZXNjYWxhIG5vcm1hbDoNCg0KYGBge3IgZWNobz1GQUxTRX0NCnAgPC0gZ2dwbG90KGNvdmlkLCBhZXMoT2JzZXJ2YXRpb25fRGF0ZSwgSW5mZWN0ZWQsIGNvbG9yID0gQ291bnRyeV9SZWdpb24pKQ0KcCArIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KCkNCmBgYA0KDQpQb3IgbGFzIGZvcm1hcyBleHBvbmVuY2lhbGVzIHZpc2libGVzIGVuIGxvcyBncsOhZmljb3Mgc2UgcHJvcG9uZW4gZG9zIHByb2NlZGltaWVudG9zOiBlbCBwcmltZXJvLCB0b21hciBsYSB2YXJpYWJsZSAkSW5mZWN0ZWQkIGNvbW8gZWwgbG9nYXJpdG1vIHkgZWwgc2VndW5kbywgbGEgdmFyaWFibGUgJEluZmVjdGVkJCBjb21vIHVuYSByZXNwdWVzdGEgJFBvaXNzb24kLiBTaWd1aWVuZG8gZWwgcHJpbWVyIHByb2NlZGltaWVudG8sIGxhIGdyw6FmaWNhIHF1ZWRhcsOtYToNCg0KYGBge3IgZWNobz1GQUxTRX0NCmNvdmlkJGxvZ0luZmVjdGVkIDwtIGlmZWxzZShjb3ZpZCRJbmZlY3RlZCA+IDAsIGxvZyhjb3ZpZCRJbmZlY3RlZCksIDApDQpwIDwtIGdncGxvdChjb3ZpZCwgYWVzKE9ic2VydmF0aW9uX0RhdGUsIGxvZ0luZmVjdGVkLCBjb2xvciA9IENvdW50cnlfUmVnaW9uKSkNCnAgKyBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgeWxhYigibG9nKEluZmVjdGVkKSIpDQpgYGANCg0KUmVhbGl6YW5kbyB1biB0ZXN0IGRlIFNoYXBpcm8tV2lsaywgc2UgZGV0ZXJtaW7DsyBxdWUgbGEgdmFyaWFibGUgJEluZmVjdGVkJCBubyBzZSBkaXN0cmlidXllIE5vcm1hbCwgcG9yIGxvIHRhbnRvLCBzZSByZWFsaXphIGxhIHNlZ3VuZGEgcHJvcHVlc3RhIGRlIHByb2NlZGltaWVudG8uDQoNCiMgTW9kZWxvcyBhIGNvbnNpZGVyYXIgey50YWJzZXR9DQojIyBNb2RlbG8gMQ0KDQokJEluZmVjdGVkX3tpan0gXHNpbSBQb2lzc29uKFxsYW1iZGFfe2lqfSkkJA0KJCRsb2coXGxhbWJkYV97aWp9KSA9IFxiZXRhXzArXGJldGFfMSBPYnNlcnZhdGlvblxfRGF0ZV97aWp9KyBiX3tvaX0kJA0KJCRiXzAgXHNpbSBOKDAsIFxzaWdtYV97Yl8wfV4yKSQkDQpjb24gdW4gdmVjdG9yIGRlIHBhcsOhbWV0cm9zICRcVGhldGE9KFxiZXRhXzAsIFxiZXRhXzEsIFxzaWdtYV97Yl8wfSleVCQNCg0KIyMgTW9kZWxvIDINCg0KJCRJbmZlY3RlZF97aWp9IFxzaW0gUG9pc3NvbihcbGFtYmRhX3tpan0pJCQNCiQkbG9nKFxsYW1iZGFfe2lqfSkgPSBcYmV0YV8wK1xiZXRhXzEgT2JzZXJ2YXRpb25cX0RhdGVfe2lqfSsgYl97b2l9K2JfezFpfSBPYnNlcnZhdGlvblxfRGF0ZV97aWp9JCQNCiQkXGJlZ2lue3BtYXRyaXh9DQpiXzAgXFwNCmJfMQ0KXGVuZHtwbWF0cml4fSBcc2ltIE4gXGxlZnRbIFxiZWdpbntwbWF0cml4fQ0KMCBcXA0KMA0KXGVuZHtwbWF0cml4fSwgXGJlZ2lue3BtYXRyaXh9DQpcc2lnbWFfe2JfMH1eMiAmIFxzaWdtYV97Yl97MDF9fV4yIFxcDQpcc2lnbWFfe2JfezAxfX1eMiAmIFxzaWdtYV97Yl8xfV4yIA0KXGVuZHtwbWF0cml4fSBccmlnaHRdJCQNCmNvbiB1biB2ZWN0b3IgZGUgcGFyw6FtZXRyb3MgJFxUaGV0YT0oXGJldGFfMCwgXGJldGFfMSwgXHNpZ21hX3tiXzB9LCBcc2lnbWFfe2JfMX0sIFxzaWdtYV97Yl97MDF9fSleVCQNCg0KIyMgTW9kZWxvIDMNCg0KJCRJbmZlY3RlZF97aWp9IFxzaW0gUG9pc3NvbihcbGFtYmRhX3tpan0pJCQNCiQkbG9nKFxsYW1iZGFfe2lqfSkgPSBcYmV0YV8wK1xiZXRhXzEgT2JzZXJ2YXRpb25cX0RhdGVfe2lqfSArIFxiZXRhXzJEZWF0aHNfe2lqfSArIFxiZXRhXzNSZWNvdmVyZWRfe2lqfSArIGJfe29pfStiX3sxaX0gT2JzZXJ2YXRpb25cX0RhdGVfe2lqfSQkDQokJFxiZWdpbntwbWF0cml4fQ0KYl8wIFxcDQpiXzENClxlbmR7cG1hdHJpeH0gXHNpbSBOIFxsZWZ0WyBcYmVnaW57cG1hdHJpeH0NCjAgXFwNCjANClxlbmR7cG1hdHJpeH0sIFxiZWdpbntwbWF0cml4fQ0KXHNpZ21hX3tiXzB9XjIgJiBcc2lnbWFfe2JfezAxfX1eMiBcXA0KXHNpZ21hX3tiX3swMX19XjIgJiBcc2lnbWFfe2JfMX1eMiANClxlbmR7cG1hdHJpeH0gXHJpZ2h0XSQkDQpjb24gdW4gdmVjdG9yIGRlIHBhcsOhbWV0cm9zICRcVGhldGE9KFxiZXRhXzAsIFxiZXRhXzEsIFxiZXRhXzIsIFxiZXRhXzMsIFxzaWdtYV97Yl8wfSwgXHNpZ21hX3tiXzF9LCBcc2lnbWFfe2JfezAxfX0pXlQkDQoNCiMgQ29uc3RydWNjacOzbiBkZSBsb3MgbW9kZWxvcyB7LnRhYnNldH0NCiMjIE1vZGVsbyAxDQoNCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KGxtZTQpDQpgYGANCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCm1vZDEgPC0gZ2xtZXIoSW5mZWN0ZWQgfiBPYnNlcnZhdGlvbl9EYXRlICsgKDEgfCBJRF9Db3VudHJ5KSwgDQogICAgICAgICAgICAgIGRhdGE9Y292aWQsIA0KICAgICAgICAgICAgICBmYW1pbHkgPSBwb2lzc29uKGxpbmsgPSAibG9nIiksDQogICAgICAgICAgICAgIG5BR1EgPSAxKQ0Kc3VtbWFyeShtb2QxKQ0KYGBgDQoNCiMjIE1vZGVsbyAyDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQptb2QyIDwtIGdsbWVyKEluZmVjdGVkIH4gT2JzZXJ2YXRpb25fRGF0ZSArIChPYnNlcnZhdGlvbl9EYXRlIHwgSURfQ291bnRyeSksIA0KICAgICAgICAgICAgICBkYXRhPWNvdmlkLCANCiAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpLA0KICAgICAgICAgICAgICBuQUdRID0gMSkNCnN1bW1hcnkobW9kMikNCmBgYA0KDQojIyBNb2RlbG8gMw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KbW9kMyA8LSBnbG1lcihJbmZlY3RlZCB+IE9ic2VydmF0aW9uX0RhdGUgKyBEZWF0aHMgKyBSZWNvdmVyZWQgKyAoT2JzZXJ2YXRpb25fRGF0ZSB8IElEX0NvdW50cnkpLCANCiAgICAgICAgICAgICAgZGF0YT1jb3ZpZCwgDQogICAgICAgICAgICAgIGZhbWlseSA9IHBvaXNzb24obGluayA9ICJsb2ciKSwNCiAgICAgICAgICAgICAgbkFHUSA9IDEpDQpzdW1tYXJ5KG1vZDMpDQpgYGANCg0KIyBBbsOhbGlzaXMgZGUgcmVzaWR1YWxlc3sudGFic2V0fQ0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KZGlhZ1Bsb3Q8LWZ1bmN0aW9uKG1vZGVsKXsNCiAgZGYgPC0gZGF0YS5mcmFtZShmaXR0ZWQ9Zml0dGVkKG1vZGVsKSwgcmVzaWQ9cmVzaWR1YWxzKG1vZGVsKSwgc3RkcmVzaWQ9cmVzaWR1YWxzKG1vZGVsLCBzY2FsZWQ9VFJVRSkpDQogIHAxPC1nZ3Bsb3QoZGYsIGFlcyhmaXR0ZWQsIHJlc2lkKSkrZ2VvbV9wb2ludCgpDQogIHAxPC1wMStzdGF0X3Ntb290aChtZXRob2Q9ImxvZXNzIikrZ2VvbV9obGluZSh5aW50ZXJjZXB0PTAsIGNvbD0icmVkIiwgbGluZXR5cGU9ImRhc2hlZCIpDQogIHAxPC1wMSt4bGFiKCJGaXR0ZWQgdmFsdWVzIikreWxhYigiUmVzaWR1YWxzIikNCiAgcDE8LXAxK2dndGl0bGUoIlJlc2lkdWFsIHZzIEZpdHRlZCBQbG90IikrdGhlbWVfYncoKQ0KICANCiAgcDI8LWdncGxvdChkZiwgYWVzKHNhbXBsZT1zdGRyZXNpZCkpICsgc3RhdF9xcSgpICsgc3RhdF9xcV9saW5lKGNvbCA9ICJyZWQiKSt4bGFiKCJUaGVvcmV0aWNhbCBRdWFudGlsZXMiKSt5bGFiKCJTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIikNCiAgcDI8LXAyK2dndGl0bGUoIk5vcm1hbCBRLVEgUGxvdCIpK3RoZW1lX2J3KCkNCiAgDQogIHJldHVybihsaXN0KHJ2ZlBsb3Q9cDEsIHFxUGxvdD1wMikpDQp9DQpgYGANCg0KIyMgTW9kZWxvIDENCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCnAxIDwtIGRpYWdQbG90KG1vZDEpDQpsaWJyYXJ5KGNvd3Bsb3QpDQpwbG90X2dyaWQocDFbWzFdXSkNCmBgYA0KDQojIyBNb2RlbG8gMg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDIgPC0gZGlhZ1Bsb3QobW9kMikNCnBsb3RfZ3JpZChwMltbMV1dKQ0KYGBgDQoNCiMjIE1vZGVsbyAzDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpwMyA8LSBkaWFnUGxvdChtb2QzKQ0KcGxvdF9ncmlkKHAzW1sxXV0pDQpgYGANCg0KIyBDb21wYXJhY2nDs24gZGUgbG9zIG1vZGVsb3MNCg0KU2UgcHVlZGUgbm90YXIgZW4gbG9zIHJlc2lkdWFsZXMgZGUgbG9zIGFqdXN0ZXMgYW50ZXJpb3JlcyBxdWUgbGEgdmFyaWFuemEgYcO6biB0aWVuZSBhbGd1bm9zIHByb2JsZW1hcyBkZSBob21vZ2VuZWlkYWQuIFBvciBlbGxvLCBzZSBwcm9wb25lIHVuIMO6bHRpbW8gbW9kZWxvIHkgY29ycmVnaXIgZGljaG8gcHJvYmxlbWEuIEVsIHJlc3VsdGFkbyBkZWwgbW9kZWxvIGVzIGVsIHNpZ3VpZW50ZToNCg0KYGBge3J9DQptb2Q0IDwtIGdsbWVyKEluZmVjdGVkIH4gcG9seShPYnNlcnZhdGlvbl9EYXRlLCA0KSArIChPYnNlcnZhdGlvbl9EYXRlIHwgSURfQ291bnRyeSksIA0KICAgICAgICAgICAgICBkYXRhPWNvdmlkLCANCiAgICAgICAgICAgICAgZmFtaWx5ID0gcG9pc3NvbihsaW5rID0gImxvZyIpLA0KICAgICAgICAgICAgICBuQUdRID0gMSkNCnN1bW1hcnkobW9kNCkNCmBgYA0KDQpBbCBjb21wYXJhciBsb3MgbW9kZWxvcyBwb3IgdW5hIHBydWViYSBkZSB2ZXJvc2ltaWxpdHVkIHNlbmNpbGxhLCBzZSBwdWVkZSBkZXRlcm1pbmFyIHF1ZToNCg0KYGBge3J9DQphbm92YShtb2QxLCBtb2QyLCBtb2QzLCBtb2Q0KQ0KYGBgDQoNCkHDsWFkaXIgY2FkYSB1bmEgZGUgbGFzIHZhcmlhYmxlcyBhIGNhZGEgbW9kZWxvIGNvbnNlY3V0aXZhbWVudGUgYSBsbGV2YWRvIGEgbWVqb3JhciBlbCBtb2RlbG8sIGVzdG8gc2UgcmVmbGVqYSBlbiBlbCBhbsOhbGlzaXMgZGUgbGEgY29ycmVsYWNpw7NuIGRlIFBlYXJzb24gcXVlIHNlIG11ZXN0cmEgYSBjb250aW51YWNpw7NuOg0KDQpgYGB7cn0NCiMgQ29ycmVsYWNpw7NuIGRlIFBlYXJzb24NCiMgTW9kZWxvIDENCmNvcihjb3ZpZCRJbmZlY3RlZCwgcHJlZGljdChtb2QxLCB0eXBlID0gInJlc3BvbnNlIikpDQojIE1vZGVsbyAyDQpjb3IoY292aWQkSW5mZWN0ZWQsIHByZWRpY3QobW9kMiwgdHlwZSA9ICJyZXNwb25zZSIpKQ0KIyBNb2RlbG8gMw0KY29yKGNvdmlkJEluZmVjdGVkLCBwcmVkaWN0KG1vZDMsIHR5cGUgPSAicmVzcG9uc2UiKSkNCiMgTW9kZWxvIDQNCmNvcihjb3ZpZCRJbmZlY3RlZCwgcHJlZGljdChtb2Q0LCB0eXBlID0gInJlc3BvbnNlIikpDQpgYGANCg0KU2llbmRvIGVsIMO6bHRpbW8gcmVzdWx0YWRvLCBlbCBjb3JyZXNwb25kaWVudGUgYWwgbW9kZWxvIDQsIGVzbyBxdWllcmUgZGVjaXIgcXVlIGVzIHVuIG1lam9yIG1vZGVsbyBxdWUgbG9zIG90cm9zLiBTdXMgcmVzaWR1YWxlcyB0YW1iacOpbiBtdWVzdHJhbiBncmFuIG1lam9yw61hIG1vc3RyYW5kbyB1bmEgZGlzcGVyc2nDs24gbcOhcyBob21vZ8OpbmVhOg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KcDQgPC0gZGlhZ1Bsb3QobW9kNCkNCnBsb3RfZ3JpZChwNFtbMV1dKQ0KYGBgDQoNCiMgUHJlc2VudGFjacOzbiBkZWwgbWVqb3IgbW9kZWxvDQoNClBhcmEgdGVybWluYXIgc2UgZGVzZWEgdmlzdWFsaXphciBjb21vIHF1ZWTDsyBlbCBtb2RlbG8uIFNlIHByZXNlbnRhIGFxdcOtOg0KDQpgYGB7ciBlY2hvPUZBTFNFfQ0KY292aWQkbGluZWEgPC0gcHJlZGljdChtb2Q0LCB0eXBlID0gInJlc3BvbnNlIikNCnAgPC0gZ2dwbG90KGNvdmlkLCBhZXMoT2JzZXJ2YXRpb25fRGF0ZSwgSW5mZWN0ZWQsIGNvbG9yID0gQ291bnRyeV9SZWdpb24pKSANCnAgKyBnZW9tX3BvaW50KCkgKyB0aGVtZV9idygpICsgZ2VvbV9saW5lKHkgPSBjb3ZpZCRsaW5lYSkNCmBgYA0KDQpWaWVuZG8gbGFzIGdyw6FmaWNhcyBwYXJlY2VuIHNhdGlzZmFjdG9yaWFzIHB1ZXN0byBxdWUgZWwgY29tcG9ydGFtaWVudG8gZGUgbGFzIGN1cnZhcyBwb3IgZ3J1cG8gc2lndWUgbGEgdGVuZGVuY2lhIGRlIGxvcyBwdW50b3MgY29tbyBzZSBkZWJlLiBFc3RvIHBvZHLDrWEgc2VyIMO6dGlsIHBhcmEgcHJlZGVjaXIgY2FudGlkYWQgZGUgaW5mZWN0YWRvcyBjb24gc29sbyBkYXJsZSBhbCBtb2RlbG8gbGEgZmVjaGEgcXVlIHF1ZXJlbW9zIHByZWRlY2lyLiBQb3IgZWplbXBsbywgZWwgw7psdGltbyB2YWxvciBvYnNlcnZhZG8gZW4gbGEgYmFzZSBkZSBkYXRvcyBwYXJhIGxhIHZhcmlhYmxlICRPYnNlcnZhdGlvblxfRGF0ZSQgZXMgJDI2JCBlbCByZWdpc3RybyBjb3JyZXNwb25kZSBhbCBkw61hIDIzIGRlIG1hcnpvIGRlIDIwMjAgcXVlIHJlYWxtZW50ZSBwZXJ0ZW5lY2UgYSBsYSBpbmZvcm1hY2nDs24gcmVjb2xlY3RhZGEgZHVyYW50ZSBlbCBkw61hIDIyIGRlIG1hcnpvLCB0b21hbmRvIGNvbW8gJENvdW50cnlcX1JlZ2lvbiQgYSBDb2xvbWJpYSBwb3IgbGEgYmFzZSBzZSBzYWJlIHF1ZSBlc2UgZMOtYSBoYWLDrWFuIDI2OSBjYXNvcyBkZSBwZXJzb25hcyBpbmZlY3RhZGFzLCBlbCBtb2RlbG8gcHJlZGljZSBwYXJhIGVsIGTDrWEgMjMgZGUgbWFyem8gMjkxIGluZmVjdGFkb3MgYXByb3hpbWFkYW1lbnRlLiBIYWNpZW5kbyBsbyBtaXNtbyBwYXJhIGVsIGTDrWEgMjUgZGUgbWFyem8sIHNlIHByZWRpY2VuIDM4NCBpbmZlY3RhZG9zLCBzZWfDum4gZWwgTWluaXN0ZXJpbyBkZSBTYWx1ZCBlbiBDb2xvbWJpYSBmdWVyb24gNDU4IHBlcnNvbmFzIGNvbiBsYSBlbmZlcm1lZGFkLiBFc3RhIGRpZmVyZW5jaWEgc2UgcHJlc2VudGEgcHVlc3RvIHF1ZSBzb2xvIHNlIHRpZW5lbiAyNyBvYnNlcnZhY2lvbmVzIHBvciBncnVwbyBwZXJvIHNpcnZlIHBhcmEgY29ub2NlciBsYSBwcm9wYWdhY2nDs24gZGVsIHZpcnVzIGVuIGRpc3RpbnRhcyBwb2JsYWNpb25lcywgdGFtYmnDqW4gY29tbyBtb3RpdmFkb3IgcGFyYSBjb250aW51YXIgY29uIGVsIHBlcmlvZG8gZGUgY3VhcmVudGVuYSB5IHNlZ3VpciBsYXMgcmVjb21lbmRhY2lvbmVzLCB0YW50byBjb21vIGJ1c2NhciBudWV2YXMgZXN0cmF0ZWdpYXMgcGFyYSBsb2dyYXIgcXVlIGVsIHZpcnVzIG5vIHNlIHNpZ2EgcHJvcGFnYW5kbyBhIGxhIHZlbG9jaWRhZCBxdWUgbG8gaGFjZSBhY3R1YWxtZW50ZS4gUGFyYSBxdWUgZWwgbW9kZWxvIHNpZ2EgdHJhYmFqYW5kbyB5IG1lam9yZSBlbiBzdXMgcHJlZGljY2lvbmVzLCBlcyByZWNvbWVuZGFibGUgYWN0dWFsaXphciBsYSBiYXNlIGRlIGRhdG9zIGRpYXJpYW1lbnRlLCBvIGVuIGxvIHBvc2libGUsIGN1YW5kbyBzZSB2YXlhIGEgdXNhciBlbCBtb2RlbG8uDQo=