Teoría

El paquete caret(classification And Regression Training) es una herramienta poderosa para la implementación de modelos de Machine Learning.

Instalación y llamado de librerías

#install.packages(caret) #Algoritmos de aprendizaje automático
library(caret) 
#install.packages("dataset") #Para usar la base de datos "Iris"
library(datasets)
#install.packages("ggplot2") #Graficar
library(ggplot2)
#install.packages("lattice") #Crear gráficos
library(lattice)
#install.packages("DataExplorer") #Análisis Descriptivo
library(DataExplorer)
#install.packages("kernlab")
library(kernlab)
#install.packages("rpart")
library(rpart)
#install.packages("randomForest")
library(randomForest)

Importar la base de datos

df <- data.frame(iris)

Análisis Descriptivo

#create_report(df)
plot_missing(df)

plot_histogram(df)

plot_correlation(df)

NOTA: La variable que queremos predecir debe si o si tener formato de FACTOR.

Entrenamiento del modelo

set.seed(123)
renglones_entrenamiento <- createDataPartition(df$Species, p=0.8, list=FALSE)
entrenamiento <-iris[renglones_entrenamiento, ]
prueba <- iris[-renglones_entrenamiento, ]

Distintos tipos de Métodos para Modelar

Los métodos más utilizados para modelar aprendizaje automático son:

  • SVM: Support Vector Machine o Máquina de Vectores de Soporte, Hay varios subtipos: Lineal(svmLinear), Radial(svmRadial), Polinómico(svmPoly), etc.

  • Árbol de Decisión: rpart

  • Redes Neuronales: nnet

  • Random Forest o Bosque Aleatorios: Rf

La validación Cruzada o CV es una técnica para evaluar el rendimiento de un modelo dividiendo los datos en múltiples subconjuntos, permitiendo medir su capacidad de generalización y evitar sobreajuste(overfitting)

La Matriz de confusión (Confusion Matrix) permite analizar qué tan bien funciona un modelo y qué tipos de errores comete. Lo que hace es comparar las predicciones del modelo con los valores reales de la variable objetivo.

Si la precisión es muy alta en entrenamiento(95-100%), pero bajo en prueba(60-70%)

Modelo 1. SVM Lineal

modelo1 <- train(Species ~ ., data = entrenamiento,
                 method = "svmLinear", #Cambiar por modelo
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method = "cv", number=10),
                 tuneGrid = data.frame(C=1) #cambiar hiperparámetros
                
                 )
resultado_entrenamiento1 <- predict(modelo1, entrenamiento)
resultado_prueba1 <- predict(modelo1, prueba)

#Matriz de confusión del resultado del Entrenamiento 1
print("Matriz de confusión del Entrenamiento")
## [1] "Matriz de confusión del Entrenamiento"
mcre1 <- confusionMatrix(resultado_entrenamiento1, entrenamiento$Species)
mcre1
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         40          0         0
##   versicolor      0         39         0
##   virginica       0          1        40
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9917          
##                  95% CI : (0.9544, 0.9998)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9875          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9750           1.0000
## Specificity                 1.0000            1.0000           0.9875
## Pos Pred Value              1.0000            1.0000           0.9756
## Neg Pred Value              1.0000            0.9877           1.0000
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3250           0.3333
## Detection Prevalence        0.3333            0.3250           0.3417
## Balanced Accuracy           1.0000            0.9875           0.9938
#Matriz de Confusión del Resultado de la prueba
print("Matriz de confusión de la Prueba")
## [1] "Matriz de confusión de la Prueba"
mcrp1 <- confusionMatrix(resultado_prueba1, prueba$Species)
mcrp1
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0         10         1
##   virginica       0          0         9
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9667          
##                  95% CI : (0.8278, 0.9992)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 2.963e-13       
##                                           
##                   Kappa : 0.95            
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            1.0000           0.9000
## Specificity                 1.0000            0.9500           1.0000
## Pos Pred Value              1.0000            0.9091           1.0000
## Neg Pred Value              1.0000            1.0000           0.9524
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3333           0.3000
## Detection Prevalence        0.3333            0.3667           0.3000
## Balanced Accuracy           1.0000            0.9750           0.9500

Modelo 2. SVM Radial

modelo2 <- train(Species ~ ., data = entrenamiento,
                 method = "svmRadial", #Cambiar por modelo
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method = "cv", number=10),
                 tuneGrid = data.frame(sigma=1, C=1) #cambiar hiperparámetros
                 )

resultado_entrenamiento2 <- predict(modelo2, entrenamiento)
resultado_prueba2 <- predict(modelo2, prueba)

#Matriz de confusión del resultado del Entrenamiento 2
print("Matriz de confusión del Entrenamiento 2")
## [1] "Matriz de confusión del Entrenamiento 2"
mcre2 <- confusionMatrix(resultado_entrenamiento2, entrenamiento$Species)
mcre2
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         40          0         0
##   versicolor      0         39         0
##   virginica       0          1        40
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9917          
##                  95% CI : (0.9544, 0.9998)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9875          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9750           1.0000
## Specificity                 1.0000            1.0000           0.9875
## Pos Pred Value              1.0000            1.0000           0.9756
## Neg Pred Value              1.0000            0.9877           1.0000
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3250           0.3333
## Detection Prevalence        0.3333            0.3250           0.3417
## Balanced Accuracy           1.0000            0.9875           0.9938
#Matriz de Confusión del Resultado de la prueba 2
print("Matriz de confusión de la Prueba 2")
## [1] "Matriz de confusión de la Prueba 2"
mcrp2 <- confusionMatrix(resultado_prueba2, prueba$Species)
mcrp2
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0         10         2
##   virginica       0          0         8
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9333          
##                  95% CI : (0.7793, 0.9918)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 8.747e-12       
##                                           
##                   Kappa : 0.9             
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            1.0000           0.8000
## Specificity                 1.0000            0.9000           1.0000
## Pos Pred Value              1.0000            0.8333           1.0000
## Neg Pred Value              1.0000            1.0000           0.9091
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3333           0.2667
## Detection Prevalence        0.3333            0.4000           0.2667
## Balanced Accuracy           1.0000            0.9500           0.9000

Modelo 3. SVM Polinómico

modelo3 <- train(Species ~ ., data = entrenamiento,
                 method = "svmPoly", #Cambiar por modelo
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method = "cv", number=10),
                 tuneGrid = data.frame(degree=1, scale=1, C=1) #cambiar hiperparámetros
                 )

resultado_entrenamiento3 <- predict(modelo3, entrenamiento)
resultado_prueba3 <- predict(modelo3, prueba)

#Matriz de confusión del resultado del Entrenamiento 3
print("Matriz de confusión del Entrenamiento 3")
## [1] "Matriz de confusión del Entrenamiento 3"
mcre3 <- confusionMatrix(resultado_entrenamiento3, entrenamiento$Species)
mcre3
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         40          0         0
##   versicolor      0         39         0
##   virginica       0          1        40
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9917          
##                  95% CI : (0.9544, 0.9998)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.9875          
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9750           1.0000
## Specificity                 1.0000            1.0000           0.9875
## Pos Pred Value              1.0000            1.0000           0.9756
## Neg Pred Value              1.0000            0.9877           1.0000
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3250           0.3333
## Detection Prevalence        0.3333            0.3250           0.3417
## Balanced Accuracy           1.0000            0.9875           0.9938
#Matriz de Confusión del Resultado de la prueba 3
print("Matriz de confusión de la Prueba 3")
## [1] "Matriz de confusión de la Prueba 3"
mcrp3 <- confusionMatrix(resultado_prueba3, prueba$Species)
mcrp3
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0         10         1
##   virginica       0          0         9
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9667          
##                  95% CI : (0.8278, 0.9992)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 2.963e-13       
##                                           
##                   Kappa : 0.95            
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            1.0000           0.9000
## Specificity                 1.0000            0.9500           1.0000
## Pos Pred Value              1.0000            0.9091           1.0000
## Neg Pred Value              1.0000            1.0000           0.9524
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3333           0.3000
## Detection Prevalence        0.3333            0.3667           0.3000
## Balanced Accuracy           1.0000            0.9750           0.9500

Modelo 4. Árbol de decisión

modelo4 <- train(Species ~ ., data = entrenamiento,
                 method = "rpart", #Cambiar por modelo
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method = "cv", number=10),
                 tuneLength = 10 #cambiar hiperparámetros
                 )

resultado_entrenamiento4 <- predict(modelo4, entrenamiento)
resultado_prueba4 <- predict(modelo4, prueba)

#Matriz de confusión del resultado del Entrenamiento 4
print("Matriz de confusión del Entrenamiento 4")
## [1] "Matriz de confusión del Entrenamiento 4"
mcre4 <- confusionMatrix(resultado_entrenamiento4, entrenamiento$Species)
mcre4
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         40          0         0
##   versicolor      0         39         3
##   virginica       0          1        37
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9667          
##                  95% CI : (0.9169, 0.9908)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.95            
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9750           0.9250
## Specificity                 1.0000            0.9625           0.9875
## Pos Pred Value              1.0000            0.9286           0.9737
## Neg Pred Value              1.0000            0.9872           0.9634
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3250           0.3083
## Detection Prevalence        0.3333            0.3500           0.3167
## Balanced Accuracy           1.0000            0.9688           0.9563
#Matriz de Confusión del Resultado de la prueba 4
print("Matriz de confusión de la Prueba 4")
## [1] "Matriz de confusión de la Prueba 4"
mcrp4 <- confusionMatrix(resultado_prueba4, prueba$Species)
mcrp4
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0         10         2
##   virginica       0          0         8
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9333          
##                  95% CI : (0.7793, 0.9918)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 8.747e-12       
##                                           
##                   Kappa : 0.9             
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            1.0000           0.8000
## Specificity                 1.0000            0.9000           1.0000
## Pos Pred Value              1.0000            0.8333           1.0000
## Neg Pred Value              1.0000            1.0000           0.9091
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3333           0.2667
## Detection Prevalence        0.3333            0.4000           0.2667
## Balanced Accuracy           1.0000            0.9500           0.9000

Modelo 5. Redes Neuronales

modelo5 <- train(Species ~ ., data = entrenamiento,
                 method = "nnet", #Cambiar por modelo
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method = "cv", number=10),
                 trace = FALSE
                 )

resultado_entrenamiento5 <- predict(modelo5, entrenamiento)
resultado_prueba5 <- predict(modelo5, prueba)

#Matriz de confusión del resultado del Entrenamiento 5
print("Matriz de confusión del Entrenamiento 5")
## [1] "Matriz de confusión del Entrenamiento 5"
mcre5 <- confusionMatrix(resultado_entrenamiento5, entrenamiento$Species)
mcre5
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         40          0         0
##   versicolor      0         36         0
##   virginica       0          4        40
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9667          
##                  95% CI : (0.9169, 0.9908)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.95            
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9000           1.0000
## Specificity                 1.0000            1.0000           0.9500
## Pos Pred Value              1.0000            1.0000           0.9091
## Neg Pred Value              1.0000            0.9524           1.0000
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3000           0.3333
## Detection Prevalence        0.3333            0.3000           0.3667
## Balanced Accuracy           1.0000            0.9500           0.9750
#Matriz de Confusión del Resultado de la prueba 5
print("Matriz de confusión de la Prueba 5")
## [1] "Matriz de confusión de la Prueba 5"
mcrp5 <- confusionMatrix(resultado_prueba5, prueba$Species)
mcrp5
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0          9         0
##   virginica       0          1        10
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9667          
##                  95% CI : (0.8278, 0.9992)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 2.963e-13       
##                                           
##                   Kappa : 0.95            
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            0.9000           1.0000
## Specificity                 1.0000            1.0000           0.9500
## Pos Pred Value              1.0000            1.0000           0.9091
## Neg Pred Value              1.0000            0.9524           1.0000
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3000           0.3333
## Detection Prevalence        0.3333            0.3000           0.3667
## Balanced Accuracy           1.0000            0.9500           0.9750

Modelo 6. RF

modelo6 <- train(Species ~ ., data = entrenamiento,
                 method = "rf", #Cambiar por modelo
                 preProcess = c("scale", "center"),
                 trControl = trainControl(method = "cv", number=10),
                 tuneGrid = expand.grid(mtry = c(2,4,6)) #cambiar hiperparámetros
                 )
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
## Warning in randomForest.default(x, y, mtry = param$mtry, ...): invalid mtry:
## reset to within valid range
resultado_entrenamiento6 <- predict(modelo6, entrenamiento)
resultado_prueba6 <- predict(modelo6, prueba)

#Matriz de confusión del resultado del Entrenamiento 6
print("Matriz de confusión del Entrenamiento 6")
## [1] "Matriz de confusión del Entrenamiento 6"
mcre6 <- confusionMatrix(resultado_entrenamiento6, entrenamiento$Species)
mcre6
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         40          0         0
##   versicolor      0         40         0
##   virginica       0          0        40
## 
## Overall Statistics
##                                      
##                Accuracy : 1          
##                  95% CI : (0.9697, 1)
##     No Information Rate : 0.3333     
##     P-Value [Acc > NIR] : < 2.2e-16  
##                                      
##                   Kappa : 1          
##                                      
##  Mcnemar's Test P-Value : NA         
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            1.0000           1.0000
## Specificity                 1.0000            1.0000           1.0000
## Pos Pred Value              1.0000            1.0000           1.0000
## Neg Pred Value              1.0000            1.0000           1.0000
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3333           0.3333
## Detection Prevalence        0.3333            0.3333           0.3333
## Balanced Accuracy           1.0000            1.0000           1.0000
#Matriz de Confusión del Resultado de la prueba 6
print("Matriz de confusión de la Prueba 6")
## [1] "Matriz de confusión de la Prueba 6"
mcrp6 <- confusionMatrix(resultado_prueba6, prueba$Species)
mcrp6
## Confusion Matrix and Statistics
## 
##             Reference
## Prediction   setosa versicolor virginica
##   setosa         10          0         0
##   versicolor      0         10         2
##   virginica       0          0         8
## 
## Overall Statistics
##                                           
##                Accuracy : 0.9333          
##                  95% CI : (0.7793, 0.9918)
##     No Information Rate : 0.3333          
##     P-Value [Acc > NIR] : 8.747e-12       
##                                           
##                   Kappa : 0.9             
##                                           
##  Mcnemar's Test P-Value : NA              
## 
## Statistics by Class:
## 
##                      Class: setosa Class: versicolor Class: virginica
## Sensitivity                 1.0000            1.0000           0.8000
## Specificity                 1.0000            0.9000           1.0000
## Pos Pred Value              1.0000            0.8333           1.0000
## Neg Pred Value              1.0000            1.0000           0.9091
## Prevalence                  0.3333            0.3333           0.3333
## Detection Rate              0.3333            0.3333           0.2667
## Detection Prevalence        0.3333            0.4000           0.2667
## Balanced Accuracy           1.0000            0.9500           0.9000

Resumen de Resultados

resultados <- data.frame(
  "SVM Lineal" = c(mcre1$overall["Accuracy"], mcrp1$overall["Accuracy"]),
  "SVM Radial" = c(mcre2$overall["Accuracy"], mcrp2$overall["Accuracy"]),
  "SVM Polinómico" = c(mcre3$overall["Accuracy"], mcrp3$overall["Accuracy"]),
  "Arbol de Decisión" = c(mcre4$overall["Accuracy"], mcrp4$overall["Accuracy"]),
  "Redes Neuronales" = c(mcre5$overall["Accuracy"], mcrp5$overall["Accuracy"]),
  "Bosques Aleatorios" = c(mcre6$overall["Accuracy"], mcrp6$overall["Accuracy"])
)
rownames(resultados) <- c("Precisión de Entrenamiento", "Precisión de Prueba")
resultados
##                            SVM.Lineal SVM.Radial SVM.Polinómico
## Precisión de Entrenamiento  0.9916667  0.9916667      0.9916667
## Precisión de Prueba         0.9666667  0.9333333      0.9666667
##                            Arbol.de.Decisión Redes.Neuronales
## Precisión de Entrenamiento         0.9666667        0.9666667
## Precisión de Prueba                0.9333333        0.9666667
##                            Bosques.Aleatorios
## Precisión de Entrenamiento          1.0000000
## Precisión de Prueba                 0.9333333

R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.

LS0tDQp0aXRsZTogIkNBUkVUIg0KYXV0aG9yOiAiU2FtYW50aGFfQTAxNDIyNzQ5Ig0KZGF0ZTogIjIwMjUtMDItMjAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUNCiAgICB0aGVtZTogInVuaXRlZCINCiAgICBoaWdobGlnaHQ6ICJlc3ByZXNzbyINCi0tLQ0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+VGVvcsOtYTwvc3Bhbj4NCkVsIHBhcXVldGUgY2FyZXQoKmNsYXNzaWZpY2F0aW9uIEFuZCBSZWdyZXNzaW9uIFRyYWluaW5nKikgZXMgdW5hIGhlcnJhbWllbnRhIHBvZGVyb3NhIHBhcmEgbGEgaW1wbGVtZW50YWNpw7NuIGRlIG1vZGVsb3MgZGUgKipNYWNoaW5lIExlYXJuaW5nKiouDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkluc3RhbGFjacOzbiB5IGxsYW1hZG8gZGUgbGlicmVyw61hczwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcyhjYXJldCkgI0FsZ29yaXRtb3MgZGUgYXByZW5kaXphamUgYXV0b23DoXRpY28NCmxpYnJhcnkoY2FyZXQpIA0KI2luc3RhbGwucGFja2FnZXMoImRhdGFzZXQiKSAjUGFyYSB1c2FyIGxhIGJhc2UgZGUgZGF0b3MgIklyaXMiDQpsaWJyYXJ5KGRhdGFzZXRzKQ0KI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKSAjR3JhZmljYXINCmxpYnJhcnkoZ2dwbG90MikNCiNpbnN0YWxsLnBhY2thZ2VzKCJsYXR0aWNlIikgI0NyZWFyIGdyw6FmaWNvcw0KbGlicmFyeShsYXR0aWNlKQ0KI2luc3RhbGwucGFja2FnZXMoIkRhdGFFeHBsb3JlciIpICNBbsOhbGlzaXMgRGVzY3JpcHRpdm8NCmxpYnJhcnkoRGF0YUV4cGxvcmVyKQ0KI2luc3RhbGwucGFja2FnZXMoImtlcm5sYWIiKQ0KbGlicmFyeShrZXJubGFiKQ0KI2luc3RhbGwucGFja2FnZXMoInJwYXJ0IikNCmxpYnJhcnkocnBhcnQpDQojaW5zdGFsbC5wYWNrYWdlcygicmFuZG9tRm9yZXN0IikNCmxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5JbXBvcnRhciBsYSBiYXNlIGRlIGRhdG9zPC9zcGFuPg0KYGBge3J9DQpkZiA8LSBkYXRhLmZyYW1lKGlyaXMpDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPkFuw6FsaXNpcyBEZXNjcmlwdGl2bzwvc3Bhbj4NCmBgYHtyfQ0KI2NyZWF0ZV9yZXBvcnQoZGYpDQpwbG90X21pc3NpbmcoZGYpDQpwbG90X2hpc3RvZ3JhbShkZikNCnBsb3RfY29ycmVsYXRpb24oZGYpDQpgYGANCioqTk9UQTogTGEgdmFyaWFibGUgcXVlIHF1ZXJlbW9zIHByZWRlY2lyIGRlYmUgc2kgbyBzaSB0ZW5lciBmb3JtYXRvIGRlIEZBQ1RPUi4qKg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+RW50cmVuYW1pZW50byBkZWwgbW9kZWxvPC9zcGFuPg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpyZW5nbG9uZXNfZW50cmVuYW1pZW50byA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGRmJFNwZWNpZXMsIHA9MC44LCBsaXN0PUZBTFNFKQ0KZW50cmVuYW1pZW50byA8LWlyaXNbcmVuZ2xvbmVzX2VudHJlbmFtaWVudG8sIF0NCnBydWViYSA8LSBpcmlzWy1yZW5nbG9uZXNfZW50cmVuYW1pZW50bywgXQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5EaXN0aW50b3MgdGlwb3MgZGUgTcOpdG9kb3MgcGFyYSBNb2RlbGFyPC9zcGFuPg0KTG9zIG3DqXRvZG9zIG3DoXMgdXRpbGl6YWRvcyBwYXJhIG1vZGVsYXIgYXByZW5kaXphamUgYXV0b23DoXRpY28gc29uOg0KDQoqICoqU1ZNKio6ICpTdXBwb3J0IFZlY3RvciBNYWNoaW5lKiBvIE3DoXF1aW5hIGRlIFZlY3RvcmVzIGRlIFNvcG9ydGUsIEhheSB2YXJpb3Mgc3VidGlwb3M6IA0KTGluZWFsKHN2bUxpbmVhciksIFJhZGlhbChzdm1SYWRpYWwpLCBQb2xpbsOzbWljbyhzdm1Qb2x5KSwgZXRjLg0KDQoqICoqw4FyYm9sIGRlIERlY2lzacOzbioqOiBycGFydA0KKiAqKlJlZGVzIE5ldXJvbmFsZXMqKjogbm5ldA0KKiAqKlJhbmRvbSBGb3Jlc3QgbyBCb3NxdWUgQWxlYXRvcmlvcyoqOiBSZg0KDQpMYSAqKnZhbGlkYWNpw7NuIENydXphZGEqKiBvIENWIGVzIHVuYSB0w6ljbmljYSBwYXJhIGV2YWx1YXIgZWwgcmVuZGltaWVudG8gZGUgdW4gbW9kZWxvIGRpdmlkaWVuZG8gbG9zIGRhdG9zIGVuIG3Dumx0aXBsZXMgc3ViY29uanVudG9zLCBwZXJtaXRpZW5kbyBtZWRpciBzdSBjYXBhY2lkYWQgZGUgZ2VuZXJhbGl6YWNpw7NuIHkgZXZpdGFyIHNvYnJlYWp1c3RlKCpvdmVyZml0dGluZyopDQoNCkxhICoqTWF0cml6IGRlIGNvbmZ1c2nDs24qKiAoKkNvbmZ1c2lvbiBNYXRyaXgqKSBwZXJtaXRlIGFuYWxpemFyIHF1w6kgdGFuIGJpZW4gZnVuY2lvbmEgdW4gbW9kZWxvIHkgcXXDqSB0aXBvcyBkZSBlcnJvcmVzIGNvbWV0ZS4gTG8gcXVlIGhhY2UgZXMgY29tcGFyYXIgbGFzIHByZWRpY2Npb25lcyBkZWwgbW9kZWxvIGNvbiBsb3MgdmFsb3JlcyByZWFsZXMgZGUgbGEgdmFyaWFibGUgb2JqZXRpdm8uDQoNClNpIGxhIHByZWNpc2nDs24gZXMgbXV5IGFsdGEgZW4gZW50cmVuYW1pZW50byg5NS0xMDAlKSwgcGVybyBiYWpvIGVuIHBydWViYSg2MC03MCUpDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5Nb2RlbG8gMS4gU1ZNIExpbmVhbDwvc3Bhbj4NCmBgYHtyfQ0KbW9kZWxvMSA8LSB0cmFpbihTcGVjaWVzIH4gLiwgZGF0YSA9IGVudHJlbmFtaWVudG8sDQogICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJzdm1MaW5lYXIiLCAjQ2FtYmlhciBwb3IgbW9kZWxvDQogICAgICAgICAgICAgICAgIHByZVByb2Nlc3MgPSBjKCJzY2FsZSIsICJjZW50ZXIiKSwNCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlcj0xMCksDQogICAgICAgICAgICAgICAgIHR1bmVHcmlkID0gZGF0YS5mcmFtZShDPTEpICNjYW1iaWFyIGhpcGVycGFyw6FtZXRyb3MNCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgKQ0KcmVzdWx0YWRvX2VudHJlbmFtaWVudG8xIDwtIHByZWRpY3QobW9kZWxvMSwgZW50cmVuYW1pZW50bykNCnJlc3VsdGFkb19wcnVlYmExIDwtIHByZWRpY3QobW9kZWxvMSwgcHJ1ZWJhKQ0KDQojTWF0cml6IGRlIGNvbmZ1c2nDs24gZGVsIHJlc3VsdGFkbyBkZWwgRW50cmVuYW1pZW50byAxDQpwcmludCgiTWF0cml6IGRlIGNvbmZ1c2nDs24gZGVsIEVudHJlbmFtaWVudG8iKQ0KbWNyZTEgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdGFkb19lbnRyZW5hbWllbnRvMSwgZW50cmVuYW1pZW50byRTcGVjaWVzKQ0KbWNyZTENCg0KI01hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgcHJ1ZWJhDQpwcmludCgiTWF0cml6IGRlIGNvbmZ1c2nDs24gZGUgbGEgUHJ1ZWJhIikNCm1jcnAxIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRhZG9fcHJ1ZWJhMSwgcHJ1ZWJhJFNwZWNpZXMpDQptY3JwMQ0KDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPk1vZGVsbyAyLiBTVk0gUmFkaWFsPC9zcGFuPg0KYGBge3J9DQptb2RlbG8yIDwtIHRyYWluKFNwZWNpZXMgfiAuLCBkYXRhID0gZW50cmVuYW1pZW50bywNCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInN2bVJhZGlhbCIsICNDYW1iaWFyIHBvciBtb2RlbG8NCiAgICAgICAgICAgICAgICAgcHJlUHJvY2VzcyA9IGMoInNjYWxlIiwgImNlbnRlciIpLA0KICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyPTEwKSwNCiAgICAgICAgICAgICAgICAgdHVuZUdyaWQgPSBkYXRhLmZyYW1lKHNpZ21hPTEsIEM9MSkgI2NhbWJpYXIgaGlwZXJwYXLDoW1ldHJvcw0KICAgICAgICAgICAgICAgICApDQoNCnJlc3VsdGFkb19lbnRyZW5hbWllbnRvMiA8LSBwcmVkaWN0KG1vZGVsbzIsIGVudHJlbmFtaWVudG8pDQpyZXN1bHRhZG9fcHJ1ZWJhMiA8LSBwcmVkaWN0KG1vZGVsbzIsIHBydWViYSkNCg0KI01hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCByZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8gMg0KcHJpbnQoIk1hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCBFbnRyZW5hbWllbnRvIDIiKQ0KbWNyZTIgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdGFkb19lbnRyZW5hbWllbnRvMiwgZW50cmVuYW1pZW50byRTcGVjaWVzKQ0KbWNyZTINCg0KI01hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgcHJ1ZWJhIDINCnByaW50KCJNYXRyaXogZGUgY29uZnVzacOzbiBkZSBsYSBQcnVlYmEgMiIpDQptY3JwMiA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTIsIHBydWViYSRTcGVjaWVzKQ0KbWNycDINCg0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5Nb2RlbG8gMy4gU1ZNIFBvbGluw7NtaWNvPC9zcGFuPg0KYGBge3J9DQptb2RlbG8zIDwtIHRyYWluKFNwZWNpZXMgfiAuLCBkYXRhID0gZW50cmVuYW1pZW50bywNCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInN2bVBvbHkiLCAjQ2FtYmlhciBwb3IgbW9kZWxvDQogICAgICAgICAgICAgICAgIHByZVByb2Nlc3MgPSBjKCJzY2FsZSIsICJjZW50ZXIiKSwNCiAgICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlcj0xMCksDQogICAgICAgICAgICAgICAgIHR1bmVHcmlkID0gZGF0YS5mcmFtZShkZWdyZWU9MSwgc2NhbGU9MSwgQz0xKSAjY2FtYmlhciBoaXBlcnBhcsOhbWV0cm9zDQogICAgICAgICAgICAgICAgICkNCg0KcmVzdWx0YWRvX2VudHJlbmFtaWVudG8zIDwtIHByZWRpY3QobW9kZWxvMywgZW50cmVuYW1pZW50bykNCnJlc3VsdGFkb19wcnVlYmEzIDwtIHByZWRpY3QobW9kZWxvMywgcHJ1ZWJhKQ0KDQojTWF0cml6IGRlIGNvbmZ1c2nDs24gZGVsIHJlc3VsdGFkbyBkZWwgRW50cmVuYW1pZW50byAzDQpwcmludCgiTWF0cml6IGRlIGNvbmZ1c2nDs24gZGVsIEVudHJlbmFtaWVudG8gMyIpDQptY3JlMyA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX2VudHJlbmFtaWVudG8zLCBlbnRyZW5hbWllbnRvJFNwZWNpZXMpDQptY3JlMw0KDQojTWF0cml6IGRlIENvbmZ1c2nDs24gZGVsIFJlc3VsdGFkbyBkZSBsYSBwcnVlYmEgMw0KcHJpbnQoIk1hdHJpeiBkZSBjb25mdXNpw7NuIGRlIGxhIFBydWViYSAzIikNCm1jcnAzIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRhZG9fcHJ1ZWJhMywgcHJ1ZWJhJFNwZWNpZXMpDQptY3JwMw0KDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPk1vZGVsbyA0LiDDgXJib2wgZGUgZGVjaXNpw7NuPC9zcGFuPg0KYGBge3J9DQptb2RlbG80IDwtIHRyYWluKFNwZWNpZXMgfiAuLCBkYXRhID0gZW50cmVuYW1pZW50bywNCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJwYXJ0IiwgI0NhbWJpYXIgcG9yIG1vZGVsbw0KICAgICAgICAgICAgICAgICBwcmVQcm9jZXNzID0gYygic2NhbGUiLCAiY2VudGVyIiksDQogICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXI9MTApLA0KICAgICAgICAgICAgICAgICB0dW5lTGVuZ3RoID0gMTAgI2NhbWJpYXIgaGlwZXJwYXLDoW1ldHJvcw0KICAgICAgICAgICAgICAgICApDQoNCnJlc3VsdGFkb19lbnRyZW5hbWllbnRvNCA8LSBwcmVkaWN0KG1vZGVsbzQsIGVudHJlbmFtaWVudG8pDQpyZXN1bHRhZG9fcHJ1ZWJhNCA8LSBwcmVkaWN0KG1vZGVsbzQsIHBydWViYSkNCg0KI01hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCByZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8gNA0KcHJpbnQoIk1hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCBFbnRyZW5hbWllbnRvIDQiKQ0KbWNyZTQgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdGFkb19lbnRyZW5hbWllbnRvNCwgZW50cmVuYW1pZW50byRTcGVjaWVzKQ0KbWNyZTQNCg0KI01hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgcHJ1ZWJhIDQNCnByaW50KCJNYXRyaXogZGUgY29uZnVzacOzbiBkZSBsYSBQcnVlYmEgNCIpDQptY3JwNCA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTQsIHBydWViYSRTcGVjaWVzKQ0KbWNycDQNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+TW9kZWxvIDUuIFJlZGVzIE5ldXJvbmFsZXM8L3NwYW4+DQpgYGB7cn0NCm1vZGVsbzUgPC0gdHJhaW4oU3BlY2llcyB+IC4sIGRhdGEgPSBlbnRyZW5hbWllbnRvLA0KICAgICAgICAgICAgICAgICBtZXRob2QgPSAibm5ldCIsICNDYW1iaWFyIHBvciBtb2RlbG8NCiAgICAgICAgICAgICAgICAgcHJlUHJvY2VzcyA9IGMoInNjYWxlIiwgImNlbnRlciIpLA0KICAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2wobWV0aG9kID0gImN2IiwgbnVtYmVyPTEwKSwNCiAgICAgICAgICAgICAgICAgdHJhY2UgPSBGQUxTRQ0KICAgICAgICAgICAgICAgICApDQoNCnJlc3VsdGFkb19lbnRyZW5hbWllbnRvNSA8LSBwcmVkaWN0KG1vZGVsbzUsIGVudHJlbmFtaWVudG8pDQpyZXN1bHRhZG9fcHJ1ZWJhNSA8LSBwcmVkaWN0KG1vZGVsbzUsIHBydWViYSkNCg0KI01hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCByZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8gNQ0KcHJpbnQoIk1hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCBFbnRyZW5hbWllbnRvIDUiKQ0KbWNyZTUgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdGFkb19lbnRyZW5hbWllbnRvNSwgZW50cmVuYW1pZW50byRTcGVjaWVzKQ0KbWNyZTUNCg0KI01hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgcHJ1ZWJhIDUNCnByaW50KCJNYXRyaXogZGUgY29uZnVzacOzbiBkZSBsYSBQcnVlYmEgNSIpDQptY3JwNSA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTUsIHBydWViYSRTcGVjaWVzKQ0KbWNycDUNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+TW9kZWxvIDYuIFJGPC9zcGFuPg0KYGBge3J9DQptb2RlbG82IDwtIHRyYWluKFNwZWNpZXMgfiAuLCBkYXRhID0gZW50cmVuYW1pZW50bywNCiAgICAgICAgICAgICAgICAgbWV0aG9kID0gInJmIiwgI0NhbWJpYXIgcG9yIG1vZGVsbw0KICAgICAgICAgICAgICAgICBwcmVQcm9jZXNzID0gYygic2NhbGUiLCAiY2VudGVyIiksDQogICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbChtZXRob2QgPSAiY3YiLCBudW1iZXI9MTApLA0KICAgICAgICAgICAgICAgICB0dW5lR3JpZCA9IGV4cGFuZC5ncmlkKG10cnkgPSBjKDIsNCw2KSkgI2NhbWJpYXIgaGlwZXJwYXLDoW1ldHJvcw0KICAgICAgICAgICAgICAgICApDQoNCnJlc3VsdGFkb19lbnRyZW5hbWllbnRvNiA8LSBwcmVkaWN0KG1vZGVsbzYsIGVudHJlbmFtaWVudG8pDQpyZXN1bHRhZG9fcHJ1ZWJhNiA8LSBwcmVkaWN0KG1vZGVsbzYsIHBydWViYSkNCg0KI01hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCByZXN1bHRhZG8gZGVsIEVudHJlbmFtaWVudG8gNg0KcHJpbnQoIk1hdHJpeiBkZSBjb25mdXNpw7NuIGRlbCBFbnRyZW5hbWllbnRvIDYiKQ0KbWNyZTYgPC0gY29uZnVzaW9uTWF0cml4KHJlc3VsdGFkb19lbnRyZW5hbWllbnRvNiwgZW50cmVuYW1pZW50byRTcGVjaWVzKQ0KbWNyZTYNCg0KI01hdHJpeiBkZSBDb25mdXNpw7NuIGRlbCBSZXN1bHRhZG8gZGUgbGEgcHJ1ZWJhIDYNCnByaW50KCJNYXRyaXogZGUgY29uZnVzacOzbiBkZSBsYSBQcnVlYmEgNiIpDQptY3JwNiA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0YWRvX3BydWViYTYsIHBydWViYSRTcGVjaWVzKQ0KbWNycDYNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+UmVzdW1lbiBkZSBSZXN1bHRhZG9zPC9zcGFuPg0KYGBge3J9DQpyZXN1bHRhZG9zIDwtIGRhdGEuZnJhbWUoDQogICJTVk0gTGluZWFsIiA9IGMobWNyZTEkb3ZlcmFsbFsiQWNjdXJhY3kiXSwgbWNycDEkb3ZlcmFsbFsiQWNjdXJhY3kiXSksDQogICJTVk0gUmFkaWFsIiA9IGMobWNyZTIkb3ZlcmFsbFsiQWNjdXJhY3kiXSwgbWNycDIkb3ZlcmFsbFsiQWNjdXJhY3kiXSksDQogICJTVk0gUG9saW7Ds21pY28iID0gYyhtY3JlMyRvdmVyYWxsWyJBY2N1cmFjeSJdLCBtY3JwMyRvdmVyYWxsWyJBY2N1cmFjeSJdKSwNCiAgIkFyYm9sIGRlIERlY2lzacOzbiIgPSBjKG1jcmU0JG92ZXJhbGxbIkFjY3VyYWN5Il0sIG1jcnA0JG92ZXJhbGxbIkFjY3VyYWN5Il0pLA0KICAiUmVkZXMgTmV1cm9uYWxlcyIgPSBjKG1jcmU1JG92ZXJhbGxbIkFjY3VyYWN5Il0sIG1jcnA1JG92ZXJhbGxbIkFjY3VyYWN5Il0pLA0KICAiQm9zcXVlcyBBbGVhdG9yaW9zIiA9IGMobWNyZTYkb3ZlcmFsbFsiQWNjdXJhY3kiXSwgbWNycDYkb3ZlcmFsbFsiQWNjdXJhY3kiXSkNCikNCnJvd25hbWVzKHJlc3VsdGFkb3MpIDwtIGMoIlByZWNpc2nDs24gZGUgRW50cmVuYW1pZW50byIsICJQcmVjaXNpw7NuIGRlIFBydWViYSIpDQpyZXN1bHRhZG9zDQoNCmBgYA0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMjIFIgTWFya2Rvd24NCg0KVGhpcyBpcyBhbiBSIE1hcmtkb3duIGRvY3VtZW50LiBNYXJrZG93biBpcyBhIHNpbXBsZSBmb3JtYXR0aW5nIHN5bnRheCBmb3IgYXV0aG9yaW5nIEhUTUwsIFBERiwgYW5kIE1TIFdvcmQgZG9jdW1lbnRzLiBGb3IgbW9yZSBkZXRhaWxzIG9uIHVzaW5nIFIgTWFya2Rvd24gc2VlIDxodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tPi4NCg==