1. Preparación de los datos

1.a. lectura de los datos

'data.frame':   418 obs. of  12 variables:
 $ PassengerId: int  892 893 894 895 896 897 898 899 900 901 ...
 $ Pclass     : int  3 3 2 3 3 3 3 2 3 3 ...
 $ Name       : Factor w/ 418 levels "Abbott, Master. Eugene Joseph",..: 210 409 273 414 182 370 85 58 5 104 ...
 $ Sex        : Factor w/ 2 levels "female","male": 2 1 2 2 1 2 1 2 1 2 ...
 $ Age        : num  34.5 47 62 27 22 14 30 26 18 21 ...
 $ SibSp      : int  0 1 0 0 1 0 0 1 0 2 ...
Error in gregexpr(calltext, singleline, fixed = TRUE) : 
  regular expression is invalid UTF-8

 $ Parch      : int  0 0 0 0 1 0 0 1 0 0 ...
 $ Ticket     : Factor w/ 363 levels "110469","110489",..: 153 222 74 148 139 262 159 85 101 270 ...
 $ Fare       : num  7.83 7 9.69 8.66 12.29 ...
 $ Cabin      : Factor w/ 76 levels "A11","A18","A21",..: NA NA NA NA NA NA NA NA NA NA ...
 $ Embarked   : Factor w/ 3 levels "C","Q","S": 2 3 2 3 3 3 2 3 1 3 ...
 $ Survived   : int  0 1 0 0 1 1 0 1 1 0 ...

El dataset Titanictiene 418 observaciones y 12 variables. Resulta conveniente tratas como factor a la variables Survived y Pclass.

1.b y c. Selección y transformación de las variables

Se seleccionan las variables PassengerId, Survived, Pclass, Sex, Age, SibSp, Parch, Fare y Embarked, y se transforman a factor las variables Survived, Pclass y Embarked.

1.d. Correlograma

En el siguiente gráfico vemos la correlación y las distribuciones de las variables Survived, Pclass, Sex, Age y Fare. En color rojo se destacan los que no sobrevivieron al hundimiento y en color celeste a aquellos que sí. Algunos puntos a destacar:

  • Baja tasa de supervivencia en las terceras y segundas clases (gráficos [2,1] y [1,2])
  • Edad promedio de 25 años [4,4] y correlación positiva entre tarifa y edad [4,5]
  • Mayor tarifa media entre aquellos que sobrevivieron [1,5]
  • Mayor tasa de supervivencia en mujeres que en hombres [1,3]
  • Baja tasa de supervivencia general (en torno a 35% de los pasajeros) [1,1]

e. Distribución de clase

Calculamos la distribución de clase para el dataset completo.

[1] "sobrevive el 37.6 %"

e. División del dataset en entrenamiento y validación

Dividimos el dataset en entrenamiento (70%) y validación (30%)

<293/125/418>

Verificamos la distribución de clase nuevamente.

[1] "sobrevive el 38.9 %" "en train"           
[1] "sobrevive el 34.4 %" "en validación"      

El dataset de validacion tiene 39.1% de supervivientes y validacion 34.4%. Para el tamaño del dataset (418 obs.) es un balanceo adecuado.

2.Predicciones (en entrenamiento)

2.a. Modelo

\[Survived_i = \beta_0 + \beta1 Pclass_i + \beta_2 Sex_i + \beta_3 Age_i \]


Call:
glm(formula = Survived ~ Pclass + Sex + Age, family = "binomial", 
    data = training(titanic_split))

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-2.0901  -0.6147  -0.5156   0.7591   2.2017  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)  3.30916    0.65893   5.022 5.11e-07 ***
Pclass2     -1.67309    0.46407  -3.605 0.000312 ***
Pclass3     -2.00682    0.41455  -4.841 1.29e-06 ***
Sexmale     -2.28525    0.29939  -7.633 2.29e-14 ***
Age         -0.03457    0.01370  -2.523 0.011625 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 391.64  on 292  degrees of freedom
Residual deviance: 288.00  on 288  degrees of freedom
AIC: 298

Number of Fisher Scoring iterations: 4

2.b. Resultados

  • Pclass2, Pclass3: coeficientes negativos y significativos al 1%. Es decir que pertenecer a las clases 2 y 3 reduce la probabilidad de sobrevivir.

  • Sexomale es negativo y significativo a 1%: ser hombre reduce la probabilidad de sobrevivir.

  • Age es negativo y significativo al 5%: mayor edad reduce la probabilidad de sobrevivir.

2.c. ¿Quién tiene una mayor probabilidad de supervivencia? Rose que es una mujer de 17 años que viaja en primera clase o Jack que es un hombre de 20 años viajando en tercera clase

        1         2 
0.9382844 0.1578577 

Rose tiene más probabilidades de sobrevivir (93.8%), mientras que Jack tiene 15.7% de probabilidades de sobrevivir.

3. Generación de modelos

Se generaron tres modelos:

Modelo 1

\[Survived_i = \beta_0 + \beta1 Pclass_i + \beta_2 Sex_i + \beta_3 Age_i + \beta_4 Embarked_i\]

Modelo 2

\[Survived_i = \beta_0 + \beta1 Pclass_i + \beta_2 Sex_i + \beta_3 Age_i + \beta_4 Embarked_i+ \beta_5 Parche_i\]

Modelo 3

\[Survived_i = \beta_0 + \beta_1 Sex_i + \beta_2 Fare_i + \beta_3 Embarked_i\] ## 3.b. Selección del mejor modelo por deviance explicada

Como era esperable el modelo con mayor cantidad de regresores es que presenta la menor deviance. mientras que el modelo del punto 2a al ser el más parsimonioso logra captar una menor proporción de la deviance explicada

4. Evaluación del modelo

Curva ROC y AUC

La curva ROC mide la relación entre la tasa de verdaderos positivos y la tasa de falsos positivos en distintos umbrales de probabilidad. Asimismo, el área bajo la curva ROC (AUC) nos permite comparar la capacidad de clasificación de distintos modelos. En el caso del dataset Titanic, la curva AUB registra un valor e 0.82, por lo que podemos decir que el modelo 2 es un buen modelo para predecir la supervivencia de los pasajeros.

Setting levels: control = 0, case = 1
Setting direction: controls < cases

[1] "AUC: Modelo 2 0.822919729491326"

Violin Plot

El violin plot presentado abajo, es un tipo de gráfico que permite observar la distribución de probabilidad predicha para la dos clases del dataset: supervivientes y no supervivientes. Como se puede observar la mayor parte de los que no sobreviven registran probabilidades predichas por debajo de 0.25, mientras que en el grupo de lo supervivientes la mayor parte presenta una probabilidad predicha superior al 50%.

Este gráfico esta estrechamente vinculado al gráfico de la curva ROC presentado arriba, ya que de definirse un umbral de probabilidad predicha más alto se obtendrá un menor recall y un mayor sensitivity (o TPR) a costa de mayor specificity (o FPR).

5. Elección del punto corte

Sobre el dataset de validación se calcularon las curvas de acuracy, Specificity, Recall y Precision en función del punto de corte. En el punto de corte igual a 0.35 encontramos la intersección entre las curvas acuracy, recall, sensitivity y specificity. Es decir que en 0.35 tendremos un balance entre las distintas métricas y por ello elegimos ese punto como el punto de corte.

 [1] 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50 0.55 0.60 0.65 0.70 0.75 0.80 0.85 0.90 0.95

Matríz de confusión

A continuación se presenta la matríz de confusión para el dataset de validación. De los 43 casos postitivos se logra clasificar de forma correcta a 33; mientras que del total de casos no positivos (82) se clasifica correctamente a 61. De esta forma el accuracy es de 75.2% con un intervalo de confianza del 95% entre 0.66 y 0.82, y que el mismo es significativamente (p-valor pequeño) superior que el NIR (No Information Rate). Podemos decir también que predecimos levemente mejor los casos de supervivencia que los de no supervivencia (0.76 vs 0.74).

Confusion Matrix and Statistics

   
     0  1
  0 61 10
  1 21 33
                                          
               Accuracy : 0.752           
                 95% CI : (0.6668, 0.8249)
    No Information Rate : 0.656           
    P-Value [Acc > NIR] : 0.01355         
                                          
                  Kappa : 0.482           
                                          
 Mcnemar's Test P-Value : 0.07249         
                                          
            Sensitivity : 0.7674          
            Specificity : 0.7439          
         Pos Pred Value : 0.6111          
         Neg Pred Value : 0.8592          
             Prevalence : 0.3440          
         Detection Rate : 0.2640          
   Detection Prevalence : 0.4320          
      Balanced Accuracy : 0.7557          
                                          
       'Positive' Class : 1               
                                          

6. Dataset de testeo

a. Leer archivo de test y realizar mismas transformaciones que en entrenamiento

A continuación se presenta la matríz de confusión obtenida con las predicciones del modelo elegido sobre el dataset de testing.

'data.frame':   418 obs. of  8 variables:
 $ Survived: Factor w/ 2 levels "0","1": 1 2 1 1 2 2 1 2 2 1 ...
 $ Pclass  : Factor w/ 3 levels "1","2","3": 3 3 2 3 3 3 3 2 3 3 ...
 $ Sex     : Factor w/ 2 levels "female","male": 2 1 2 2 1 2 1 2 1 2 ...
 $ Age     : num  34.5 47 62 27 22 14 30 26 18 21 ...
 $ SibSp   : int  0 1 0 0 1 0 0 1 0 2 ...
 $ Parch   : int  0 0 0 0 1 0 0 1 0 0 ...
 $ Fare    : num  7.83 7 9.69 8.66 12.29 ...
 $ Embarked: Factor w/ 3 levels "C","Q","S": 2 3 2 3 3 3 2 3 1 3 ...

b. Clasificar en testing con el modelo y el punto de corte elegidos

Para el caso de los supervivientes, se logra clasificar correctamentea 119 de 157 asos; mientras que de los no spervivientes se clasifica correctamente a 195 de 261 casos. En suma, se obtuvo un accuracy de 75.12% levemente por debajo del 75.2% obtenido en validación.

Confusion Matrix and Statistics

   
      0   1
  0 195  38
  1  66 119
                                          
               Accuracy : 0.7512          
                 95% CI : (0.7069, 0.7919)
    No Information Rate : 0.6244          
    P-Value [Acc > NIR] : 2.419e-08       
                                          
                  Kappa : 0.4878          
                                          
 Mcnemar's Test P-Value : 0.008107        
                                          
            Sensitivity : 0.7580          
            Specificity : 0.7471          
         Pos Pred Value : 0.6432          
         Neg Pred Value : 0.8369          
             Prevalence : 0.3756          
         Detection Rate : 0.2847          
   Detection Prevalence : 0.4426          
      Balanced Accuracy : 0.7525          
                                          
       'Positive' Class : 1               
                                          
LS0tDQp0aXRsZTogIlRQIDMgUmVncmVzacOzbiBsb2fDrXN0aWNhIg0KYXV0aG9yOiAiU2FudGlhZ28gUm9zc2kiDQpkYXRlOiAiMjIgZGUgbm92aWVtYnJlIGRlIDIwMTkiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNQ0KICAgIHRoZW1lOiB1bml0ZWQNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShHR2FsbHkpDQpsaWJyYXJ5KHRpZHltb2RlbHMpDQpsaWJyYXJ5KGdsbW5ldCkNCmxpYnJhcnkobW9kZWxyKQ0KbGlicmFyeShwUk9DKQ0Kc2V0LnNlZWQoMjA0OCkNCmBgYA0KDQojIDEuIFByZXBhcmFjacOzbiBkZSBsb3MgZGF0b3MgDQoNCiMjIDEuYS4gbGVjdHVyYSBkZSBsb3MgZGF0b3MNCmBgYHtyIHNldHVwfQ0KI0NhcmdvIGVsIGRhdGFzZXQNCnRyYWluIDwtIHJlYWQuY3N2KCJ0aXRhbmljX2NvbXBsZXRlX3Rlc3QuY3N2IikNCnRyYWluICU+JSBzdHIoKQ0KYGBgDQoNCkVsIGRhdGFzZXQgYFRpdGFuaWNgdGllbmUgNDE4IG9ic2VydmFjaW9uZXMgeSAxMiB2YXJpYWJsZXMuIFJlc3VsdGEgY29udmVuaWVudGUgdHJhdGFzIGNvbW8gZmFjdG9yIGEgbGEgdmFyaWFibGVzICoqU3Vydml2ZWQgeSBQY2xhc3MqKi4NCg0KIyMgMS5iIHkgYy4gU2VsZWNjacOzbiB5IHRyYW5zZm9ybWFjacOzbiBkZSBsYXMgdmFyaWFibGVzDQoNClNlIHNlbGVjY2lvbmFuIGxhcyB2YXJpYWJsZXMgUGFzc2VuZ2VySWQsIFN1cnZpdmVkLCBQY2xhc3MsIFNleCwgQWdlLCBTaWJTcCwgUGFyY2gsIEZhcmUgeSBFbWJhcmtlZCwgeSBzZSB0cmFuc2Zvcm1hbiBhIGZhY3RvciBsYXMgdmFyaWFibGVzIFN1cnZpdmVkLCBQY2xhc3MgeSBFbWJhcmtlZC4gDQoNCmBgYHtyfQ0KI1RyYW5zZm9ybW8gbGFzIHZhcmlhYmxlcyBTdXJ2aXZlZCwgUGNsYXNzIHkgRW1iYXJrZWQgYSBmYWN0b3INCnRyYWluIDwtIHRyYWluICU+JSANCiAgZHBseXI6OnNlbGVjdChQYXNzZW5nZXJJZCwgU3Vydml2ZWQsIFBjbGFzcywgU2V4LCBBZ2UsIFNpYlNwLFBhcmNoLCBGYXJlLEVtYmFya2VkKSAlPiUgDQogIG11dGF0ZSggIFN1cnZpdmVkID0gYXMuZmFjdG9yKFN1cnZpdmVkKSwgDQogICAgICAgICAgIFBjbGFzcyA9IGFzLmZhY3RvcihQY2xhc3MpLA0KICAgICAgICAgICBFbWJhcmtlZCA9IGFzLmZhY3RvcihFbWJhcmtlZCkgKQ0KYGBgDQoNCiMjIDEuZC4gQ29ycmVsb2dyYW1hDQoNCkVuIGVsIHNpZ3VpZW50ZSBncsOhZmljbyB2ZW1vcyBsYSBjb3JyZWxhY2nDs24geSBsYXMgZGlzdHJpYnVjaW9uZXMgZGUgbGFzIHZhcmlhYmxlcyBTdXJ2aXZlZCwgUGNsYXNzLCBTZXgsIEFnZSAgeSBGYXJlLiBFbiBjb2xvciByb2pvIHNlIGRlc3RhY2FuIGxvcyBxdWUgbm8gc29icmV2aXZpZXJvbiBhbCBodW5kaW1pZW50byB5IGVuIGNvbG9yIGNlbGVzdGUgYSBhcXVlbGxvcyBxdWUgc8OtLiBBbGd1bm9zIHB1bnRvcyBhIGRlc3RhY2FyOg0KDQoqIEJhamEgdGFzYSBkZSBzdXBlcnZpdmVuY2lhIGVuIGxhcyB0ZXJjZXJhcyB5IHNlZ3VuZGFzIGNsYXNlcyAoZ3LDoWZpY29zIFsyLDFdIHkgWzEsMl0pDQoqIEVkYWQgcHJvbWVkaW8gZGUgMjUgYcOxb3MgWzQsNF0geSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZW50cmUgdGFyaWZhIHkgZWRhZCBbNCw1XQ0KKiBNYXlvciB0YXJpZmEgbWVkaWEgZW50cmUgYXF1ZWxsb3MgcXVlIHNvYnJldml2aWVyb24gWzEsNV0NCiogTWF5b3IgdGFzYSBkZSBzdXBlcnZpdmVuY2lhIGVuIG11amVyZXMgcXVlIGVuIGhvbWJyZXMgWzEsM10NCiogQmFqYSB0YXNhIGRlIHN1cGVydml2ZW5jaWEgZ2VuZXJhbCAoZW4gdG9ybm8gYSAzNSUgZGUgbG9zIHBhc2FqZXJvcykgWzEsMV0NCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gMTJ9DQojQ29ycmVsYWNpb25lcyBncmFmaWNvcw0KdHJhaW4gJT4lICBkcGx5cjo6c2VsZWN0KFN1cnZpdmVkLCBQY2xhc3MsIFNleCwgQWdlICxGYXJlKSAlPiUgDQogIGdncGFpcnMoLiwgDQogICAgICAgICAgdGl0bGUgPSAiTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMiLA0KICAgICAgICAgIG1hcHBpbmcgPSBhZXMoY29sb3VyPSBTdXJ2aXZlZCxhbHBoYT0wLjUpKQ0KDQpgYGANCg0KIyMgZS4gRGlzdHJpYnVjacOzbiBkZSBjbGFzZQ0KDQpDYWxjdWxhbW9zIGxhIGRpc3RyaWJ1Y2nDs24gZGUgY2xhc2UgcGFyYSBlbCBkYXRhc2V0IGNvbXBsZXRvLg0KDQpgYGB7cn0NCg0KdHJhaW4gJT4lDQogIGdyb3VwX2J5KFN1cnZpdmVkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIG51bWVyb19jYXNvcyA9IG4oKSwNCiAgICBwb3JjZW50YWplID0gbnVtZXJvX2Nhc29zIC8gbnJvdyh0cmFpbikNCiAgICApDQoNCg0KcmF0aW9fc3VwZXJ2aXZlbmNpYSA8LSBmdW5jdGlvbihkYXRhKSB7DQogICAgICB0bXAgPC0gZGF0YSAlPiUgZmlsdGVyKFN1cnZpdmVkPT0xKSAlPiUgZHBseXI6OnNlbGVjdCgxKSAlPiUgbnJvdygpDQogICAgICB0bXAyIDwtIGRhdGEgJT4lIGRwbHlyOjpzZWxlY3QoMSkgJT4lIG5yb3coKQ0KICANCiAgICAgIHBhc3RlKCJzb2JyZXZpdmUgZWwiLCByb3VuZCh0bXAvdG1wMiwzKSoxMDAsIiUiKQ0KICAgICAgfQ0KDQoNCnRyYWluIDwtIHRyYWluICU+JSBtdXRhdGUodGFnID0gY2FzZV93aGVuKFN1cnZpdmVkID09IDEgfiAiU29icmV2aXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN1cnZpdmVkID09IDAgfiAiTm8gc29icmV2aXZlIikpDQoNCmdncGxvdCh0cmFpbikrIGdlb21fYmFyKCBhZXMoeCA9IFN1cnZpdmVkLCBmaWxsPXRhZykpKw0KICBsYWJzKHRpdGxlID0gIlRpdGFuaWMuIFNvYnJldml2aWVudGVzIHkgbm8gc29icmV2aXZpZW50ZXMiLA0KICAgIHN1YnRpdGxlID0gIkZ1ZW5ldDogS2FnZ2xlIikgKw0KICAgIGxhYnMoeCA9ICJTb2JyZXZpdmllbnRlIiwgeSA9ICIjIHBlcnNvbmFzIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFQpKQ0KDQpyYXRpb19zdXBlcnZpdmVuY2lhKHRyYWluKQ0KYGBgDQoNCg0KIyMgZS4gRGl2aXNpw7NuIGRlbCBkYXRhc2V0IGVuIGVudHJlbmFtaWVudG8geSB2YWxpZGFjacOzbg0KDQpEaXZpZGltb3MgZWwgZGF0YXNldCBlbiBlbnRyZW5hbWllbnRvICg3MCUpIHkgdmFsaWRhY2nDs24gKDMwJSkNCg0KYGBge3J9DQojU2VwYXJvIGVuIHRyYWluIHkgdGVzdA0Kc2V0LnNlZWQoMjA0OCkNCnRpdGFuaWNfc3BsaXQgPC0gaW5pdGlhbF9zcGxpdCh0cmFpbiwgcHJvcCA9IDAuNykNCnRpdGFuaWNfc3BsaXQNCmBgYA0KDQpWZXJpZmljYW1vcyBsYSBkaXN0cmlidWNpw7NuIGRlIGNsYXNlIG51ZXZhbWVudGUuDQoNCmBgYHtyfQ0KDQojVFJBSU5JTkcNCnRpdGFuaWNfc3BsaXQgJT4lIA0KICB0cmFpbmluZygpICU+JQ0KICBncm91cF9ieShTdXJ2aXZlZCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBudW1lcm9fY2Fzb3MgPSBuKCksDQogICAgcG9yY2VudGFqZSA9IG51bWVyb19jYXNvcyAvIG5yb3codHJhaW5pbmcodGl0YW5pY19zcGxpdCkpDQogICAgKQ0KDQp0aXRhbmljX3NwbGl0ICU+JSB0cmFpbmluZygpICU+JSByYXRpb19zdXBlcnZpdmVuY2lhKCkgJT4lIGMoImVuIHRyYWluIikNCg0KI1ZBTElEQUNJT04NCg0KI1RSQUlOSU5HDQp0aXRhbmljX3NwbGl0ICU+JSANCiAgdGVzdGluZygpICU+JQ0KICBncm91cF9ieShTdXJ2aXZlZCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBudW1lcm9fY2Fzb3MgPSBuKCksDQogICAgcG9yY2VudGFqZSA9IG51bWVyb19jYXNvcyAvIG5yb3codHJhaW5pbmcodGl0YW5pY19zcGxpdCkpDQogICAgKQ0KDQp0aXRhbmljX3NwbGl0ICU+JSB0ZXN0aW5nKCkgJT4lIHJhdGlvX3N1cGVydml2ZW5jaWEoKSAlPiUgYygiZW4gdmFsaWRhY2nDs24iKQ0KYGBgDQoNCkVsIGRhdGFzZXQgZGUgdmFsaWRhY2lvbiB0aWVuZSAzOS4xJSBkZSBzdXBlcnZpdmllbnRlcyB5IHZhbGlkYWNpb24gMzQuNCUuIFBhcmEgZWwgdGFtYcOxbyBkZWwgZGF0YXNldCAoNDE4IG9icy4pIGVzIHVuIGJhbGFuY2VvIGFkZWN1YWRvLiAgDQoNCg0KIyAyLlByZWRpY2Npb25lcyAoZW4gZW50cmVuYW1pZW50bykNCg0KDQojIyAyLmEuIE1vZGVsbw0KDQokJFN1cnZpdmVkX2kgPSBcYmV0YV8wICsgXGJldGExIFBjbGFzc19pICsgXGJldGFfMiBTZXhfaSArIFxiZXRhXzMgQWdlX2kgJCQNCg0KYGBge3J9DQptb2RfMCA8LSBnbG0oU3Vydml2ZWQgfiBQY2xhc3MgKyBTZXggKyBBZ2UsIGRhdGEgPSB0cmFpbmluZyh0aXRhbmljX3NwbGl0KSwgZmFtaWx5ID0gImJpbm9taWFsIikNCnN1bW1hcnkobW9kXzApDQoNCmBgYA0KDQojIyAyLmIuIFJlc3VsdGFkb3MNCg0KKiBQY2xhc3MyLCBQY2xhc3MzOiBjb2VmaWNpZW50ZXMgbmVnYXRpdm9zIHkgc2lnbmlmaWNhdGl2b3MgYWwgMSUuIEVzIGRlY2lyIHF1ZSBwZXJ0ZW5lY2VyIGEgbGFzIGNsYXNlcyAyIHkgMyByZWR1Y2UgbGEgcHJvYmFiaWxpZGFkIGRlIHNvYnJldml2aXIuDQoNCiogU2V4b21hbGUgZXMgbmVnYXRpdm8geSBzaWduaWZpY2F0aXZvIGEgMSU6IHNlciBob21icmUgcmVkdWNlIGxhIHByb2JhYmlsaWRhZCBkZSBzb2JyZXZpdmlyLg0KDQoqIEFnZSBlcyBuZWdhdGl2byB5IHNpZ25pZmljYXRpdm8gYWwgNSU6IG1heW9yIGVkYWQgcmVkdWNlIGxhIHByb2JhYmlsaWRhZCBkZSBzb2JyZXZpdmlyLg0KDQojIyAyLmMuIMK/UXVpw6luIHRpZW5lIHVuYSBtYXlvciBwcm9iYWJpbGlkYWQgZGUgc3VwZXJ2aXZlbmNpYT8gUm9zZSBxdWUgZXMgdW5hIG11amVyIGRlIDE3IGHDsW9zIHF1ZSB2aWFqYSBlbiBwcmltZXJhIGNsYXNlIG8gSmFjayBxdWUgZXMgdW4gaG9tYnJlIGRlIDIwIGHDsW9zIHZpYWphbmRvIGVuIHRlcmNlcmEgY2xhc2UNCg0KYGBge3J9DQpuZXdkYXRhID0gZGF0YS5mcmFtZSgiUGNsYXNzIj1jKCIxIiwiMyIpLCJTZXgiPWMoImZlbWFsZSIsIm1hbGUiKSwiQWdlIj1jKDE3LDIwKSkNCg0KcHJlZGljdC5nbG0ob2JqZWN0ID0gbW9kXzAsIG5ld2RhdGEsdHlwZSA9ICJyZXNwb25zZSIpDQpgYGANCg0KDQoqKlJvc2UgdGllbmUgbcOhcyBwcm9iYWJpbGlkYWRlcyBkZSBzb2JyZXZpdmlyICg5My44JSkqKiwgbWllbnRyYXMgcXVlIEphY2sgdGllbmUgMTUuNyUgZGUgcHJvYmFiaWxpZGFkZXMgZGUgc29icmV2aXZpci4NCg0KDQojIDMuIEdlbmVyYWNpw7NuIGRlIG1vZGVsb3MNCg0KU2UgZ2VuZXJhcm9uIHRyZXMgbW9kZWxvczoNCg0KIyMjIyBNb2RlbG8gMQ0KJCRTdXJ2aXZlZF9pID0gXGJldGFfMCArIFxiZXRhMSBQY2xhc3NfaSArIFxiZXRhXzIgU2V4X2kgKyBcYmV0YV8zIEFnZV9pICArIFxiZXRhXzQgRW1iYXJrZWRfaSQkDQoNCiMjIyMgTW9kZWxvIDINCiQkU3Vydml2ZWRfaSA9IFxiZXRhXzAgKyBcYmV0YTEgUGNsYXNzX2kgKyBcYmV0YV8yIFNleF9pICsgXGJldGFfMyBBZ2VfaSAgKyBcYmV0YV80IEVtYmFya2VkX2krIFxiZXRhXzUgUGFyY2hlX2kkJA0KDQojIyMjIE1vZGVsbyAzDQokJFN1cnZpdmVkX2kgPSBcYmV0YV8wICsgXGJldGFfMSBTZXhfaSArIFxiZXRhXzIgRmFyZV9pICArIFxiZXRhXzMgRW1iYXJrZWRfaSQkDQojIyAzLmIuIFNlbGVjY2nDs24gZGVsIG1lam9yIG1vZGVsbyBwb3IgZGV2aWFuY2UgZXhwbGljYWRhDQpgYGB7cn0NCiNHZW5lcm8gZm9ybXVsYXMgZGUgbW9kZWxvIDJfYSB5IHRyZXMgbnVldm9zIG1vZGVsb3MNCmxvZ2l0X2Zvcm11bGFzIDwtIGZvcm11bGFzKC5yZXNwb25zZSA9IH5TdXJ2aXZlZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgbW9kXzJhPSB+IFBjbGFzcyArIFNleCArIEFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBtb2RfMT0gfiBQY2xhc3MgKyBTZXggKyBBZ2UgKyBFbWJhcmtlZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgbW9kXzI9IH5QY2xhc3MgKyBTZXggKyBBZ2UgKyBQYXJjaCArIEVtYmFya2VkLCAgDQogICAgICAgICAgICAgICAgICAgICAgICAgbW9kXzM9IH4gU2V4ICsgIEZhcmUgKyBFbWJhcmtlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICkNCg0KI2NvcnJvIGxvIG1vZGVsb3MgbG9naXQNCm1vZGVscyA8LSB0aWJibGUobG9naXRfZm9ybXVsYXMpICU+JSAjIGRhdGFmcmFtZSBhIHBhcnRpciBkZWwgb2JqZXRvIGZvcm11bGFzDQogIG11dGF0ZShtb2RlbHMgPSBuYW1lcyhsb2dpdF9mb3JtdWxhcyksICMgY29sdW1uYSBjb24gbG9zIG5vbWJyZXMgZGUgbGFzIGZvcm11bGFzDQogICAgICAgICBleHByZXNzaW9uID0gcGFzdGUobG9naXRfZm9ybXVsYXMpLCAjIGNvbHVtbmEgY29uIGxhcyBleHByZXNpb25lcyBkZSBsYXMgZm9ybXVsYXMNCiAgICAgICAgIG1vZCA9IG1hcChsb2dpdF9mb3JtdWxhcywgfmdsbSguLGZhbWlseSA9ICdiaW5vbWlhbCcsIGRhdGEgPSB0cmFpbmluZyh0aXRhbmljX3NwbGl0KSkpKSANCg0KI2FncmVnbyBlc3RhZGlzdGljYXMgcmVzdW1lbiBkZSBsb3MgbW9kZWxvcw0KbW9kZWxzIDwtIG1vZGVscyAlPiUgDQogIG11dGF0ZShnbGFuY2UgPSBtYXAobW9kLGdsYW5jZSkpIA0KDQojdGFibGEgc2FsaWRhIG9yZGVuYWRhIHBvciBkZXZpYW5jZQ0KbW9kZWxzICU+JSANCiAgdW5uZXN0KGdsYW5jZSkgJT4lIGFycmFuZ2UoZGV2aWFuY2UpDQpgYGANCg0KQ29tbyBlcmEgZXNwZXJhYmxlIGVsIG1vZGVsbyBjb24gbWF5b3IgY2FudGlkYWQgZGUgcmVncmVzb3JlcyBlcyBxdWUgcHJlc2VudGEgbGEgbWVub3IgZGV2aWFuY2UuIG1pZW50cmFzIHF1ZSBlbCBtb2RlbG8gZGVsIHB1bnRvIDJhIGFsIHNlciBlbCBtw6FzIHBhcnNpbW9uaW9zbyBsb2dyYSBjYXB0YXIgdW5hIG1lbm9yIHByb3BvcmNpw7NuIGRlIGxhIGRldmlhbmNlIGV4cGxpY2FkYQ0KDQoNCiMgNC4gRXZhbHVhY2nDs24gZGVsIG1vZGVsbyANCg0KDQojIyBDdXJ2YSBST0MgeSBBVUMNCg0KTGEgY3VydmEgUk9DIG1pZGUgbGEgcmVsYWNpw7NuIGVudHJlIGxhIHRhc2EgZGUgdmVyZGFkZXJvcyBwb3NpdGl2b3MgeSBsYSB0YXNhIGRlIGZhbHNvcyBwb3NpdGl2b3MgZW4gZGlzdGludG9zIHVtYnJhbGVzIGRlIHByb2JhYmlsaWRhZC4gQXNpbWlzbW8sIGVsIMOhcmVhIGJham8gbGEgY3VydmEgUk9DIChBVUMpIG5vcyBwZXJtaXRlIGNvbXBhcmFyIGxhIGNhcGFjaWRhZCBkZSBjbGFzaWZpY2FjacOzbiBkZSBkaXN0aW50b3MgbW9kZWxvcy4gRW4gZWwgY2FzbyBkZWwgZGF0YXNldCBUaXRhbmljLCBsYSBjdXJ2YSBBVUIgcmVnaXN0cmEgdW4gdmFsb3IgZSAwLjgyLCBwb3IgbG8gcXVlIHBvZGVtb3MgZGVjaXIgcXVlIGVsIG1vZGVsbyAyIGVzIHVuIGJ1ZW4gbW9kZWxvIHBhcmEgcHJlZGVjaXIgbGEgc3VwZXJ2aXZlbmNpYSBkZSBsb3MgcGFzYWplcm9zLg0KDQpgYGB7cn0NCg0KIyBQcmVkaWNjaW9uIE1vZGVsbyBlbGVnaWRvIGVuIFRSQUlODQpwcmVkaWN0aW9uX21vZF8yIDwtIG1vZGVscyAlPiUgDQogIG11dGF0ZShwcmVkPSBtYXAobW9kLGF1Z21lbnQsbmV3ZGF0YT10cmFpbmluZyh0aXRhbmljX3NwbGl0KSwgdHlwZS5wcmVkaWN0ID0gInJlc3BvbnNlIikpICU+JSANCiAgZmlsdGVyKG1vZGVscz09Im1vZF8yIikgJT4lIA0KICB1bm5lc3QocHJlZCkNCg0KIyBDYWxjdWxhbW9zIGN1cnZhcyBST0MNCnJvY19tb2RfMiA8LSByb2MocmVzcG9uc2U9cHJlZGljdGlvbl9tb2RfMiRTdXJ2aXZlZCwgcHJlZGljdG9yPXByZWRpY3Rpb25fbW9kXzIkLmZpdHRlZCkNCg0KZ2dyb2MobGlzdChgTW9kZWxvIDJgPXJvY19tb2RfMiksIHNpemU9MSkgKyBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDEsIGxpbmV0eXBlPSdkYXNoZWQnKSArIHRoZW1lX2J3KCkgKyBsYWJzKHRpdGxlPSdDdXJ2YXMgUk9DJywgY29sb3I9J01vZGVsbycpDQoNCnByaW50KHBhc3RlKCdBVUM6IE1vZGVsbyAyJywgcm9jX21vZF8yJGF1YykpDQpgYGANCg0KIyMgVmlvbGluIFBsb3QNCkVsIHZpb2xpbiBwbG90IHByZXNlbnRhZG8gYWJham8sIGVzIHVuIHRpcG8gZGUgZ3LDoWZpY28gcXVlIHBlcm1pdGUgb2JzZXJ2YXIgbGEgZGlzdHJpYnVjacOzbiBkZSBwcm9iYWJpbGlkYWQgcHJlZGljaGEgcGFyYSBsYSBkb3MgY2xhc2VzIGRlbCBkYXRhc2V0OiBzdXBlcnZpdmllbnRlcyB5IG5vIHN1cGVydml2aWVudGVzLiBDb21vIHNlIHB1ZWRlIG9ic2VydmFyIGxhIG1heW9yIHBhcnRlIGRlIGxvcyBxdWUgbm8gc29icmV2aXZlbiByZWdpc3RyYW4gcHJvYmFiaWxpZGFkZXMgcHJlZGljaGFzIHBvciBkZWJham8gZGUgMC4yNSwgbWllbnRyYXMgcXVlIGVuIGVsIGdydXBvIGRlIGxvIHN1cGVydml2aWVudGVzIGxhIG1heW9yIHBhcnRlIHByZXNlbnRhIHVuYSBwcm9iYWJpbGlkYWQgcHJlZGljaGEgc3VwZXJpb3IgYWwgNTAlLg0KDQpFc3RlIGdyw6FmaWNvIGVzdGEgZXN0cmVjaGFtZW50ZSB2aW5jdWxhZG8gYWwgZ3LDoWZpY28gZGUgbGEgY3VydmEgUk9DIHByZXNlbnRhZG8gYXJyaWJhLCB5YSBxdWUgZGUgZGVmaW5pcnNlIHVuIHVtYnJhbCBkZSBwcm9iYWJpbGlkYWQgcHJlZGljaGEgbcOhcyBhbHRvIHNlIG9idGVuZHLDoSB1biBtZW5vciByZWNhbGwgeSB1biBtYXlvciBzZW5zaXRpdml0eSAobyBUUFIpIGEgY29zdGEgZGUgbWF5b3Igc3BlY2lmaWNpdHkgKG8gRlBSKS4gIA0KDQpgYGB7cn0NCnZpb2xpbl9tb2RfMiA9IGdncGxvdChwcmVkaWN0aW9uX21vZF8yICwgYWVzKHg9U3Vydml2ZWQsIHk9LmZpdHRlZCwgZ3JvdXA9U3Vydml2ZWQsZmlsbD1mYWN0b3IoU3Vydml2ZWQpKSkgKyANCiAgZ2VvbV92aW9saW4oKSArDQogIHRoZW1lX2J3KCkgKw0KICBndWlkZXMoZmlsbD1GQUxTRSkgKw0KICBsYWJzKHRpdGxlPSdWaW9saW4gcGxvdCcsIHN1YnRpdGxlPSdNb2RlbG8gY29tcGxldG8nLCB5PSdQcmVkaWN0ZWQgcHJvYmFiaWxpdHknKQ0KDQp2aW9saW5fbW9kXzINCmBgYA0KDQoNCiMgNS4gRWxlY2Npw7NuIGRlbCBwdW50byBjb3J0ZQ0KDQpTb2JyZSBlbCBkYXRhc2V0IGRlIHZhbGlkYWNpw7NuIHNlIGNhbGN1bGFyb24gbGFzIGN1cnZhcyBkZSBhY3VyYWN5LCBTcGVjaWZpY2l0eSwgUmVjYWxsIHkgUHJlY2lzaW9uIGVuIGZ1bmNpw7NuIGRlbCBwdW50byBkZSBjb3J0ZS4gRW4gZWwgcHVudG8gZGUgY29ydGUgaWd1YWwgYSAwLjM1IGVuY29udHJhbW9zIGxhIGludGVyc2VjY2nDs24gZW50cmUgbGFzIGN1cnZhcyBhY3VyYWN5LCByZWNhbGwsIHNlbnNpdGl2aXR5IHkgc3BlY2lmaWNpdHkuIEVzIGRlY2lyIHF1ZSBlbiAwLjM1IHRlbmRyZW1vcyB1biBiYWxhbmNlIGVudHJlIGxhcyBkaXN0aW50YXMgbcOpdHJpY2FzIHkgcG9yIGVsbG8gZWxlZ2ltb3MgZXNlIHB1bnRvIGNvbW8gZWwgcHVudG8gZGUgY29ydGUuDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkoZTEwNzEpDQoNCiMgUHJlZGljY2lvbiBNb2RlbG8gZWxlZ2lkbyBlbiBWQUxJREFDSU9ODQpwcmVkaWN0aW9uX21vZF8yX3ZhbGlkYWNpb24gPC0gbW9kZWxzICU+JSANCiAgbXV0YXRlKHByZWQ9IG1hcChtb2QsYXVnbWVudCxuZXdkYXRhPXRlc3RpbmcodGl0YW5pY19zcGxpdCksIHR5cGUucHJlZGljdCA9ICJyZXNwb25zZSIpKSAlPiUgDQogIGZpbHRlcihtb2RlbHM9PSJtb2RfMiIpICU+JSANCiAgdW5uZXN0KHByZWQpDQoNCnByZWRpY3Rpb25fbWV0cmljcyA8LSBmdW5jdGlvbihjdXRvZmYsIHByZWRpY3Rpb25zPXByZWRpY3Rpb25fbW9kXzJfdmFsaWRhY2lvbil7DQogIHRhYmxlIDwtIHByZWRpY3Rpb25zICU+JSANCiAgICBtdXRhdGUocHJlZGljdGVkX2NsYXNzPWlmX2Vsc2UoLmZpdHRlZD5jdXRvZmYsIjEiLCAiMCIpICU+JSBhcy5mYWN0b3IoKSwNCiAgICAgICAgICAgU3Vydml2ZWQ9IGZhY3RvcihTdXJ2aXZlZCkpICU+JSBzZWxlY3QocHJlZGljdGVkX2NsYXNzLFN1cnZpdmVkKQ0KICANCiBjb25mdXNpb25NYXRyaXgodGFibGUodGFibGUkcHJlZGljdGVkX2NsYXNzLCB0YWJsZSRTdXJ2aXZlZCksIHBvc2l0aXZlID0gIjEiKSAlPiUNCiAgICB0aWR5KCkgJT4lDQogICAgc2VsZWN0KHRlcm0sIGVzdGltYXRlKSAlPiUNCiAgICBmaWx0ZXIodGVybSAlaW4lIGMoJ2FjY3VyYWN5JywgJ3NlbnNpdGl2aXR5JywgJ3NwZWNpZmljaXR5JywgJ3ByZWNpc2lvbicsJ3JlY2FsbCcpKSAlPiUNCiAgICBtdXRhdGUoY3V0b2ZmPWN1dG9mZikNCiAgDQp9DQoNCnNlcSgwLjEwLDAuOTUsMC4wNSkNCmN1dG9mZnMgPSBzZXEoMC4xMCwwLjk1LDAuMSkgI0RhIGVycm9yIHNpIGhhZ28gY29uIG1lbm9yIHNlcGFyYWNpb24gZGUgY3V0b2ZmDQogIA0KbG9naXRfcHJlZD0gbWFwX2RmcihjdXRvZmZzLCBwcmVkaWN0aW9uX21ldHJpY3MpICU+JSBtdXRhdGUodGVybT1hcy5mYWN0b3IodGVybSkpDQoNCg0KbG9naXRfcHJlZD0gbWFwX2RmcihjdXRvZmZzLCBwcmVkaWN0aW9uX21ldHJpY3MpJT4lIG11dGF0ZSh0ZXJtPWFzLmZhY3Rvcih0ZXJtKSkNCg0KZ2dwbG90KGxvZ2l0X3ByZWQsIGFlcyhjdXRvZmYsZXN0aW1hdGUsIGdyb3VwPXRlcm0sIGNvbG9yPXRlcm0pKSArIGdlb21fbGluZShzaXplPTEsIGFscGhhPTAuNSkgKw0KICB0aGVtZV9idygpICsNCiAgbGFicyh0aXRsZT0gJ0FjY3VyYWN5LCBTZW5zaXRpdml0eSwgU3BlY2lmaWNpdHksIFJlY2FsbCB5IFByZWNpc2lvbicsIHN1YnRpdGxlPSAnTW9kZWxvIGNvbXBsZXRvJywgY29sb3I9IiIpDQoNCmBgYA0KDQojIyBNYXRyw616IGRlIGNvbmZ1c2nDs24NCg0KQSBjb250aW51YWNpw7NuIHNlIHByZXNlbnRhIGxhIG1hdHLDrXogZGUgY29uZnVzacOzbiBwYXJhIGVsIGRhdGFzZXQgZGUgdmFsaWRhY2nDs24uIERlIGxvcyA0MyBjYXNvcyBwb3N0aXRpdm9zIHNlIGxvZ3JhIGNsYXNpZmljYXIgZGUgZm9ybWEgY29ycmVjdGEgYSAzMzsgbWllbnRyYXMgcXVlIGRlbCB0b3RhbCBkZSBjYXNvcyBubyBwb3NpdGl2b3MgKDgyKSBzZSBjbGFzaWZpY2EgY29ycmVjdGFtZW50ZSBhIDYxLiBEZSBlc3RhIGZvcm1hIGVsIGFjY3VyYWN5IGVzIGRlIDc1LjIlIGNvbiB1biBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlbCA5NSUgZW50cmUgMC42NiB5IDAuODIsIHkgcXVlIGVsIG1pc21vIGVzIHNpZ25pZmljYXRpdmFtZW50ZSAocC12YWxvciBwZXF1ZcOxbykgc3VwZXJpb3IgcXVlIGVsIE5JUiAoTm8gSW5mb3JtYXRpb24gUmF0ZSkuIFBvZGVtb3MgZGVjaXIgdGFtYmnDqW4gcXVlIHByZWRlY2ltb3MgbGV2ZW1lbnRlIG1lam9yIGxvcyBjYXNvcyBkZSBzdXBlcnZpdmVuY2lhIHF1ZSBsb3MgZGUgbm8gc3VwZXJ2aXZlbmNpYSAoMC43NiB2cyAwLjc0KS4NCg0KYGBge3J9DQp0YWJsYSA8LSBwcmVkaWN0aW9uX21vZF8yX3ZhbGlkYWNpb24gJT4lIA0KICAgIG11dGF0ZShwcmVkaWN0ZWRfY2xhc3M9aWZfZWxzZSguZml0dGVkPjAuMzUsIjEiLCAiMCIpICU+JSBhcy5mYWN0b3IoKSwNCiAgICAgICAgICAgU3Vydml2ZWQ9IGZhY3RvcihTdXJ2aXZlZCkpICU+JSBzZWxlY3QocHJlZGljdGVkX2NsYXNzLFN1cnZpdmVkKQ0KDQpjb25mdXNpb25NYXRyaXgodGFibGUodGFibGEkcHJlZGljdGVkX2NsYXNzLCB0YWJsYSRTdXJ2aXZlZCksIHBvc2l0aXZlID0gIjEiKSANCmBgYA0KDQoNCiMgNi4gRGF0YXNldCBkZSB0ZXN0ZW8NCg0KIyMgYS4gTGVlciBhcmNoaXZvIGRlIHRlc3QgeSByZWFsaXphciBtaXNtYXMgdHJhbnNmb3JtYWNpb25lcyBxdWUgZW4gZW50cmVuYW1pZW50bw0KQSBjb250aW51YWNpw7NuIHNlIHByZXNlbnRhIGxhIG1hdHLDrXogZGUgY29uZnVzacOzbiBvYnRlbmlkYSBjb24gbGFzIHByZWRpY2Npb25lcyBkZWwgbW9kZWxvIGVsZWdpZG8gc29icmUgZWwgZGF0YXNldCBkZSB0ZXN0aW5nLg0KDQpgYGB7cn0NCnRlc3Q8LXJlYWQuY3N2KCJ0aXRhbmljX2NvbXBsZXRlX3Rlc3QuY3N2IikNCg0KDQojVHJhbnNmb3JtbyBsYXMgdmFyaWFibGVzIFN1cnZpdmVkLCBQY2xhc3MgeSBFbWJhcmtlZCBhIGZhY3Rvcg0KdGVzdCA8LSB0ZXN0ICU+JSANCiAgZHBseXI6OnNlbGVjdChTdXJ2aXZlZCwgUGNsYXNzLCBTZXgsIEFnZSwgU2liU3AsUGFyY2gsIEZhcmUsRW1iYXJrZWQpICU+JSANCiAgbXV0YXRlKCAgU3Vydml2ZWQgPSBhcy5mYWN0b3IoU3Vydml2ZWQpLCANCiAgICAgICAgICAgUGNsYXNzID0gYXMuZmFjdG9yKFBjbGFzcyksDQogICAgICAgICAgIEVtYmFya2VkID0gYXMuZmFjdG9yKEVtYmFya2VkKSApDQoNCnN0cih0ZXN0KQ0KYGBgDQoNCiMjIGIuIENsYXNpZmljYXIgZW4gdGVzdGluZyBjb24gZWwgbW9kZWxvIHkgZWwgcHVudG8gZGUgY29ydGUgZWxlZ2lkb3MNCg0KUGFyYSBlbCBjYXNvIGRlIGxvcyBzdXBlcnZpdmllbnRlcywgc2UgbG9ncmEgY2xhc2lmaWNhciBjb3JyZWN0YW1lbnRlYSAxMTkgZGUgMTU3IGFzb3M7IG1pZW50cmFzIHF1ZSBkZSBsb3Mgbm8gc3BlcnZpdmllbnRlcyBzZSBjbGFzaWZpY2EgY29ycmVjdGFtZW50ZSBhIDE5NSBkZSAyNjEgY2Fzb3MuIEVuIHN1bWEsIHNlIG9idHV2byB1biBhY2N1cmFjeSBkZSA3NS4xMiUgbGV2ZW1lbnRlIHBvciBkZWJham8gZGVsIDc1LjIlIG9idGVuaWRvIGVuIHZhbGlkYWNpw7NuLg0KDQpgYGB7cn0NCiMgUHJlZGljY2lvbiBNb2RlbG8gZWxlZ2lkbyBlbiBURVNUDQpwcmVkaWN0aW9uX21vZF8yX1RFU1QgPC0gbW9kZWxzICU+JSANCiAgbXV0YXRlKHByZWQ9IG1hcChtb2QsYXVnbWVudCxuZXdkYXRhPXRlc3QsIHR5cGUucHJlZGljdCA9ICJyZXNwb25zZSIpKSAlPiUgDQogIGZpbHRlcihtb2RlbHM9PSJtb2RfMiIpICU+JSANCiAgdW5uZXN0KHByZWQpDQoNCnRhYmxhIDwtIHByZWRpY3Rpb25fbW9kXzJfVEVTVCAlPiUgDQogICAgbXV0YXRlKHByZWRpY3RlZF9jbGFzcz1pZl9lbHNlKC5maXR0ZWQ+MC4zNSwiMSIsICIwIikgJT4lIGFzLmZhY3RvcigpLA0KICAgICAgICAgICBTdXJ2aXZlZD0gZmFjdG9yKFN1cnZpdmVkKSkgJT4lIHNlbGVjdChwcmVkaWN0ZWRfY2xhc3MsU3Vydml2ZWQpDQoNCmNvbmZ1c2lvbk1hdHJpeCh0YWJsZSh0YWJsYSRwcmVkaWN0ZWRfY2xhc3MsIHRhYmxhJFN1cnZpdmVkKSwgcG9zaXRpdmUgPSAiMSIpIA0KYGBgDQoNCg==