Contexto

Telco es una empresa internacional que vende una variedad de servicios de telecomunicaciones. Churn es un indicador de la deserción de clientes, fenómeno en el cual los clientes cancelan sus servicios con la empresa. El objetivo de este trabajo es predecir si un cliente abandonará o se quedará en la empresa.

Importar librerías

library(tidyverse)
library(caret)
library(readr)

#install.packages("e1071") #Matriz de confusión 
library(e1071)

Importar base de datos

telco <- read.csv("C:/Users/aleja/Documents/R/R_Practicas_IA/Telco Customer Churn.csv")
#telco <- read_csv("Telco Customer Churn.csv")
#View(telco)

Entender la base de datos

summary(telco)
##   customerID           gender          SeniorCitizen      Partner         
##  Length:7043        Length:7043        Min.   :0.0000   Length:7043       
##  Class :character   Class :character   1st Qu.:0.0000   Class :character  
##  Mode  :character   Mode  :character   Median :0.0000   Mode  :character  
##                                        Mean   :0.1621                     
##                                        3rd Qu.:0.0000                     
##                                        Max.   :1.0000                     
##                                                                           
##   Dependents            tenure      PhoneService       MultipleLines     
##  Length:7043        Min.   : 0.00   Length:7043        Length:7043       
##  Class :character   1st Qu.: 9.00   Class :character   Class :character  
##  Mode  :character   Median :29.00   Mode  :character   Mode  :character  
##                     Mean   :32.37                                        
##                     3rd Qu.:55.00                                        
##                     Max.   :72.00                                        
##                                                                          
##  InternetService    OnlineSecurity     OnlineBackup       DeviceProtection  
##  Length:7043        Length:7043        Length:7043        Length:7043       
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  TechSupport        StreamingTV        StreamingMovies      Contract        
##  Length:7043        Length:7043        Length:7043        Length:7043       
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##                                                                             
##  PaperlessBilling   PaymentMethod      MonthlyCharges    TotalCharges   
##  Length:7043        Length:7043        Min.   : 18.25   Min.   :  18.8  
##  Class :character   Class :character   1st Qu.: 35.50   1st Qu.: 401.4  
##  Mode  :character   Mode  :character   Median : 70.35   Median :1397.5  
##                                        Mean   : 64.76   Mean   :2283.3  
##                                        3rd Qu.: 89.85   3rd Qu.:3794.7  
##                                        Max.   :118.75   Max.   :8684.8  
##                                                         NA's   :11      
##     Churn          
##  Length:7043       
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
## 
head(telco)
##   customerID gender SeniorCitizen Partner Dependents tenure PhoneService
## 1 7590-VHVEG Female             0     Yes         No      1           No
## 2 5575-GNVDE   Male             0      No         No     34          Yes
## 3 3668-QPYBK   Male             0      No         No      2          Yes
## 4 7795-CFOCW   Male             0      No         No     45           No
## 5 9237-HQITU Female             0      No         No      2          Yes
## 6 9305-CDSKC Female             0      No         No      8          Yes
##      MultipleLines InternetService OnlineSecurity OnlineBackup DeviceProtection
## 1 No phone service             DSL             No          Yes               No
## 2               No             DSL            Yes           No              Yes
## 3               No             DSL            Yes          Yes               No
## 4 No phone service             DSL            Yes           No              Yes
## 5               No     Fiber optic             No           No               No
## 6              Yes     Fiber optic             No           No              Yes
##   TechSupport StreamingTV StreamingMovies       Contract PaperlessBilling
## 1          No          No              No Month-to-month              Yes
## 2          No          No              No       One year               No
## 3          No          No              No Month-to-month              Yes
## 4         Yes          No              No       One year               No
## 5          No          No              No Month-to-month              Yes
## 6          No         Yes             Yes Month-to-month              Yes
##               PaymentMethod MonthlyCharges TotalCharges Churn
## 1          Electronic check          29.85        29.85    No
## 2              Mailed check          56.95      1889.50    No
## 3              Mailed check          53.85       108.15   Yes
## 4 Bank transfer (automatic)          42.30      1840.75    No
## 5          Electronic check          70.70       151.65   Yes
## 6          Electronic check          99.65       820.50   Yes
str(telco)
## 'data.frame':    7043 obs. of  21 variables:
##  $ customerID      : chr  "7590-VHVEG" "5575-GNVDE" "3668-QPYBK" "7795-CFOCW" ...
##  $ gender          : chr  "Female" "Male" "Male" "Male" ...
##  $ SeniorCitizen   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Partner         : chr  "Yes" "No" "No" "No" ...
##  $ Dependents      : chr  "No" "No" "No" "No" ...
##  $ tenure          : int  1 34 2 45 2 8 22 10 28 62 ...
##  $ PhoneService    : chr  "No" "Yes" "Yes" "No" ...
##  $ MultipleLines   : chr  "No phone service" "No" "No" "No phone service" ...
##  $ InternetService : chr  "DSL" "DSL" "DSL" "DSL" ...
##  $ OnlineSecurity  : chr  "No" "Yes" "Yes" "Yes" ...
##  $ OnlineBackup    : chr  "Yes" "No" "Yes" "No" ...
##  $ DeviceProtection: chr  "No" "Yes" "No" "Yes" ...
##  $ TechSupport     : chr  "No" "No" "No" "Yes" ...
##  $ StreamingTV     : chr  "No" "No" "No" "No" ...
##  $ StreamingMovies : chr  "No" "No" "No" "No" ...
##  $ Contract        : chr  "Month-to-month" "One year" "Month-to-month" "One year" ...
##  $ PaperlessBilling: chr  "Yes" "No" "Yes" "No" ...
##  $ PaymentMethod   : chr  "Electronic check" "Mailed check" "Mailed check" "Bank transfer (automatic)" ...
##  $ MonthlyCharges  : num  29.9 57 53.9 42.3 70.7 ...
##  $ TotalCharges    : num  29.9 1889.5 108.2 1840.8 151.7 ...
##  $ Churn           : chr  "No" "No" "Yes" "No" ...

Teoría sobre Regresión Logística

La Regresión Logística es un modelo que se utiliza para predecir la probabilidad de que ocurra un evento, basado en una o más variables independientes.A diferencia de la regresión lineal, que predice valores continuos(como el precio de una casa), la R Logística predice resultados binarios o categóricos, como un sí/no, 1/0, TRUE/FALSE.

  • Si la probabilidad es mayor que 0.5, el modelo predice que el evento ocurrirá (Ej: el cliente se dará de baja).
  • Si la probabilidad es menor, predice que el evento no ocurrirá.

Preparar la base de datos

#Eliminar columna de ""CustomerID
telco_limpia <- telco %>% select(-customerID)

#Convertir las variables caractér a factores
telco_limpia <- telco_limpia %>% mutate(across(where(is.character),as.factor))
str(telco_limpia)
## 'data.frame':    7043 obs. of  20 variables:
##  $ gender          : Factor w/ 2 levels "Female","Male": 1 2 2 2 1 1 2 1 1 2 ...
##  $ SeniorCitizen   : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Partner         : Factor w/ 2 levels "No","Yes": 2 1 1 1 1 1 1 1 2 1 ...
##  $ Dependents      : Factor w/ 2 levels "No","Yes": 1 1 1 1 1 1 2 1 1 2 ...
##  $ tenure          : int  1 34 2 45 2 8 22 10 28 62 ...
##  $ PhoneService    : Factor w/ 2 levels "No","Yes": 1 2 2 1 2 2 2 1 2 2 ...
##  $ MultipleLines   : Factor w/ 3 levels "No","No phone service",..: 2 1 1 2 1 3 3 2 3 1 ...
##  $ InternetService : Factor w/ 3 levels "DSL","Fiber optic",..: 1 1 1 1 2 2 2 1 2 1 ...
##  $ OnlineSecurity  : Factor w/ 3 levels "No","No internet service",..: 1 3 3 3 1 1 1 3 1 3 ...
##  $ OnlineBackup    : Factor w/ 3 levels "No","No internet service",..: 3 1 3 1 1 1 3 1 1 3 ...
##  $ DeviceProtection: Factor w/ 3 levels "No","No internet service",..: 1 3 1 3 1 3 1 1 3 1 ...
##  $ TechSupport     : Factor w/ 3 levels "No","No internet service",..: 1 1 1 3 1 1 1 1 3 1 ...
##  $ StreamingTV     : Factor w/ 3 levels "No","No internet service",..: 1 1 1 1 1 3 3 1 3 1 ...
##  $ StreamingMovies : Factor w/ 3 levels "No","No internet service",..: 1 1 1 1 1 3 1 1 3 1 ...
##  $ Contract        : Factor w/ 3 levels "Month-to-month",..: 1 2 1 2 1 1 1 1 1 2 ...
##  $ PaperlessBilling: Factor w/ 2 levels "No","Yes": 2 1 2 1 2 2 2 1 2 1 ...
##  $ PaymentMethod   : Factor w/ 4 levels "Bank transfer (automatic)",..: 3 4 4 1 3 3 2 4 3 1 ...
##  $ MonthlyCharges  : num  29.9 57 53.9 42.3 70.7 ...
##  $ TotalCharges    : num  29.9 1889.5 108.2 1840.8 151.7 ...
##  $ Churn           : Factor w/ 2 levels "No","Yes": 1 1 2 1 2 2 1 1 2 1 ...
#######look how we can stack actions

#Eliminar NA's
telco_limpia <- na.omit(telco_limpia)
view(telco_limpia)

Entrenar el modelo

set.seed(123)
renglones_entrenamiento_telco <- createDataPartition(telco_limpia$Churn, p=0.7, list=FALSE)
entrenamiento_telco <- telco_limpia[renglones_entrenamiento_telco, ]
prueba_telco <- telco_limpia[-renglones_entrenamiento_telco, ]

Generar el Modelo

modelo_telco <- glm(Churn ~., data= entrenamiento_telco, family = binomial)
summary(modelo_telco)
## 
## Call:
## glm(formula = Churn ~ ., family = binomial, data = entrenamiento_telco)
## 
## Coefficients: (7 not defined because of singularities)
##                                        Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                           1.0746695  0.9571525   1.123 0.261532    
## genderMale                           -0.0482269  0.0771304  -0.625 0.531797    
## SeniorCitizen                         0.1200467  0.1014491   1.183 0.236683    
## PartnerYes                           -0.0910761  0.0918164  -0.992 0.321228    
## DependentsYes                        -0.0843260  0.1068161  -0.789 0.429849    
## tenure                               -0.0621135  0.0074487  -8.339  < 2e-16 ***
## PhoneServiceYes                       0.0233358  0.7635434   0.031 0.975618    
## MultipleLinesNo phone service                NA         NA      NA       NA    
## MultipleLinesYes                      0.3794100  0.2078464   1.825 0.067935 .  
## InternetServiceFiber optic            1.5613737  0.9372764   1.666 0.095741 .  
## InternetServiceNo                    -1.5047493  0.9480893  -1.587 0.112481    
## OnlineSecurityNo internet service            NA         NA      NA       NA    
## OnlineSecurityYes                    -0.2149292  0.2098780  -1.024 0.305804    
## OnlineBackupNo internet service              NA         NA      NA       NA    
## OnlineBackupYes                       0.0008494  0.2053088   0.004 0.996699    
## DeviceProtectionNo internet service          NA         NA      NA       NA    
## DeviceProtectionYes                   0.1177891  0.2084585   0.565 0.572041    
## TechSupportNo internet service               NA         NA      NA       NA    
## TechSupportYes                       -0.1280168  0.2128673  -0.601 0.547579    
## StreamingTVNo internet service               NA         NA      NA       NA    
## StreamingTVYes                        0.5187839  0.3819512   1.358 0.174386    
## StreamingMoviesNo internet service           NA         NA      NA       NA    
## StreamingMoviesYes                    0.5783808  0.3840289   1.506 0.132045    
## ContractOne year                     -0.8451411  0.1304035  -6.481 9.11e-11 ***
## ContractTwo year                     -1.4644194  0.2039949  -7.179 7.04e-13 ***
## PaperlessBillingYes                   0.3020753  0.0884590   3.415 0.000638 ***
## PaymentMethodCredit card (automatic) -0.0093796  0.1357499  -0.069 0.944914    
## PaymentMethodElectronic check         0.2897469  0.1124649   2.576 0.009985 ** 
## PaymentMethodMailed check            -0.1002695  0.1367827  -0.733 0.463524    
## MonthlyCharges                       -0.0336622  0.0372618  -0.903 0.366314    
## TotalCharges                          0.0003653  0.0000844   4.328 1.50e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 5702.8  on 4923  degrees of freedom
## Residual deviance: 4117.1  on 4900  degrees of freedom
## AIC: 4165.1
## 
## Number of Fisher Scoring iterations: 6

Evaluar el Modelo

#Predicción en el Entrenamiento
prediccion_entrenamiento_telco <- predict(modelo_telco, entrenamiento_telco, type = "response")
resultado_prediccion_entrenamiento_telco <- 
  ifelse(prediccion_entrenamiento_telco >= 0.5, "Yes", "No")

#Matriz de confusión en Entrenamiento
mcet <- confusionMatrix(factor(resultado_prediccion_entrenamiento_telco, levels=c("Yes", "No")), entrenamiento_telco$Churn)
## Warning in
## confusionMatrix.default(factor(resultado_prediccion_entrenamiento_telco, :
## Levels are not in the same order for reference and data. Refactoring data to
## match.
mcet
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   No  Yes
##        No  3237  598
##        Yes  378  711
##                                           
##                Accuracy : 0.8018          
##                  95% CI : (0.7904, 0.8128)
##     No Information Rate : 0.7342          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.4634          
##                                           
##  Mcnemar's Test P-Value : 2.383e-12       
##                                           
##             Sensitivity : 0.8954          
##             Specificity : 0.5432          
##          Pos Pred Value : 0.8441          
##          Neg Pred Value : 0.6529          
##              Prevalence : 0.7342          
##          Detection Rate : 0.6574          
##    Detection Prevalence : 0.7788          
##       Balanced Accuracy : 0.7193          
##                                           
##        'Positive' Class : No              
## 
#Predicción en Prueba
prediccion_prueba_telco <-
  predict(modelo_telco,prueba_telco, type = "response")
resultado_prediccion_prueba_telco <-
  ifelse(prediccion_prueba_telco >= 0.5, "Yes", "No")

#Matriz de confusión en Prueba
mcep <- confusionMatrix(factor(resultado_prediccion_prueba_telco, levels=c("Yes", "No")), prueba_telco$Churn)
## Warning in confusionMatrix.default(factor(resultado_prediccion_prueba_telco, :
## Levels are not in the same order for reference and data. Refactoring data to
## match.
mcep
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction   No  Yes
##        No  1385  229
##        Yes  163  331
##                                           
##                Accuracy : 0.814           
##                  95% CI : (0.7968, 0.8304)
##     No Information Rate : 0.7343          
##     P-Value [Acc > NIR] : < 2.2e-16       
##                                           
##                   Kappa : 0.5048          
##                                           
##  Mcnemar's Test P-Value : 0.001027        
##                                           
##             Sensitivity : 0.8947          
##             Specificity : 0.5911          
##          Pos Pred Value : 0.8581          
##          Neg Pred Value : 0.6700          
##              Prevalence : 0.7343          
##          Detection Rate : 0.6570          
##    Detection Prevalence : 0.7657          
##       Balanced Accuracy : 0.7429          
##                                           
##        'Positive' Class : No              
## 

Ejemplo de Predicción

info_cliente <- telco_limpia[1, ]
info_cliente <- info_cliente %>% select(-Churn)
probabilidad_cliente <- predict(modelo_telco, info_cliente, type = "response")
probabilidad_cliente
##         1 
## 0.6272032
prediccion_cliente <-
  ifelse(probabilidad_cliente >=0.5, "Yes", "No")
prediccion_cliente
##     1 
## "Yes"
LS0tDQp0aXRsZTogIlJlZ3Jlc2lvbiBMb2dpc3RpY2EiDQphdXRob3I6ICJTYW1hbnRoYSAtIEEwMTQyMjc0OSINCmRhdGU6ICIyMDI1LTAyLTI1Ig0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IHNpbXBsZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCi0tLQ0KDQohW10oQzovVXNlcnMvYWxlamEvUGljdHVyZXMvSW1hZ2VuZXNfdHJhYmFqb3MvQ3VzdG9tZXJDaHVybi5naWYpDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+Q29udGV4dG88L3NwYW4+DQoNCioqVGVsY28qKiBlcyB1bmEgZW1wcmVzYSBpbnRlcm5hY2lvbmFsIHF1ZSB2ZW5kZSB1bmEgdmFyaWVkYWQgZGUgc2VydmljaW9zIGRlIHRlbGVjb211bmljYWNpb25lcy4gKipDaHVybioqIGVzIHVuIGluZGljYWRvciBkZSBsYSBkZXNlcmNpw7NuIGRlIGNsaWVudGVzLCBmZW7Ds21lbm8gZW4gZWwgY3VhbCBsb3MgY2xpZW50ZXMgY2FuY2VsYW4gc3VzIHNlcnZpY2lvcyBjb24gbGEgZW1wcmVzYS4gRWwgb2JqZXRpdm8gZGUgZXN0ZSB0cmFiYWpvIGVzIHByZWRlY2lyIHNpIHVuIGNsaWVudGUgYWJhbmRvbmFyw6EgbyBzZSBxdWVkYXLDoSBlbiBsYSBlbXByZXNhLg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkltcG9ydGFyIGxpYnJlcsOtYXM8L3NwYW4+DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShyZWFkcikNCg0KI2luc3RhbGwucGFja2FnZXMoImUxMDcxIikgI01hdHJpeiBkZSBjb25mdXNpw7NuIA0KbGlicmFyeShlMTA3MSkNCg0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+SW1wb3J0YXIgYmFzZSBkZSBkYXRvczwvc3Bhbj4NCmBgYHtyfQ0KdGVsY28gPC0gcmVhZC5jc3YoIkM6L1VzZXJzL2FsZWphL0RvY3VtZW50cy9SL1JfUHJhY3RpY2FzX0lBL1RlbGNvIEN1c3RvbWVyIENodXJuLmNzdiIpDQojdGVsY28gPC0gcmVhZF9jc3YoIlRlbGNvIEN1c3RvbWVyIENodXJuLmNzdiIpDQojVmlldyh0ZWxjbykNCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkVudGVuZGVyIGxhIGJhc2UgZGUgZGF0b3M8L3NwYW4+DQpgYGB7cn0NCnN1bW1hcnkodGVsY28pDQpoZWFkKHRlbGNvKQ0Kc3RyKHRlbGNvKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+VGVvcsOtYSBzb2JyZSBSZWdyZXNpw7NuIExvZ8Otc3RpY2E8L3NwYW4+DQpMYSAqKlJlZ3Jlc2nDs24gTG9nw61zdGljYSoqIGVzIHVuIG1vZGVsbyBxdWUgc2UgdXRpbGl6YSBwYXJhIHByZWRlY2lyIGxhIHByb2JhYmlsaWRhZCBkZSBxdWUgb2N1cnJhIHVuIGV2ZW50bywgYmFzYWRvIGVuIHVuYSBvIG3DoXMgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzLkEgZGlmZXJlbmNpYSBkZSBsYSByZWdyZXNpw7NuIGxpbmVhbCwgcXVlIHByZWRpY2UgdmFsb3JlcyBjb250aW51b3MoY29tbyBlbCBwcmVjaW8gZGUgdW5hIGNhc2EpLCBsYSBSIExvZ8Otc3RpY2EgcHJlZGljZSByZXN1bHRhZG9zICoqYmluYXJpb3MqKiBvICoqY2F0ZWfDs3JpY29zKiosIGNvbW8gdW4gc8OtL25vLCAxLzAsIFRSVUUvRkFMU0UuIA0KDQorIFNpIGxhIHByb2JhYmlsaWRhZCBlcyBtYXlvciBxdWUgMC41LCBlbCBtb2RlbG8gcHJlZGljZSBxdWUgZWwgZXZlbnRvIG9jdXJyaXLDoSAoRWo6IGVsIGNsaWVudGUgc2UgZGFyw6EgZGUgYmFqYSkuIA0KKyBTaSBsYSBwcm9iYWJpbGlkYWQgZXMgbWVub3IsIHByZWRpY2UgcXVlIGVsIGV2ZW50byBubyBvY3Vycmlyw6EuDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+UHJlcGFyYXIgbGEgYmFzZSBkZSBkYXRvczwvc3Bhbj4NCmBgYHtyfQ0KI0VsaW1pbmFyIGNvbHVtbmEgZGUgIiJDdXN0b21lcklEDQp0ZWxjb19saW1waWEgPC0gdGVsY28gJT4lIHNlbGVjdCgtY3VzdG9tZXJJRCkNCg0KI0NvbnZlcnRpciBsYXMgdmFyaWFibGVzIGNhcmFjdMOpciBhIGZhY3RvcmVzDQp0ZWxjb19saW1waWEgPC0gdGVsY29fbGltcGlhICU+JSBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmNoYXJhY3RlciksYXMuZmFjdG9yKSkNCnN0cih0ZWxjb19saW1waWEpDQojIyMjIyMjbG9vayBob3cgd2UgY2FuIHN0YWNrIGFjdGlvbnMNCg0KI0VsaW1pbmFyIE5BJ3MNCnRlbGNvX2xpbXBpYSA8LSBuYS5vbWl0KHRlbGNvX2xpbXBpYSkNCnZpZXcodGVsY29fbGltcGlhKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+RW50cmVuYXIgZWwgbW9kZWxvPC9zcGFuPg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpyZW5nbG9uZXNfZW50cmVuYW1pZW50b190ZWxjbyA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKHRlbGNvX2xpbXBpYSRDaHVybiwgcD0wLjcsIGxpc3Q9RkFMU0UpDQplbnRyZW5hbWllbnRvX3RlbGNvIDwtIHRlbGNvX2xpbXBpYVtyZW5nbG9uZXNfZW50cmVuYW1pZW50b190ZWxjbywgXQ0KcHJ1ZWJhX3RlbGNvIDwtIHRlbGNvX2xpbXBpYVstcmVuZ2xvbmVzX2VudHJlbmFtaWVudG9fdGVsY28sIF0NCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkdlbmVyYXIgZWwgTW9kZWxvPC9zcGFuPg0KYGBge3J9DQptb2RlbG9fdGVsY28gPC0gZ2xtKENodXJuIH4uLCBkYXRhPSBlbnRyZW5hbWllbnRvX3RlbGNvLCBmYW1pbHkgPSBiaW5vbWlhbCkNCnN1bW1hcnkobW9kZWxvX3RlbGNvKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+RXZhbHVhciBlbCBNb2RlbG88L3NwYW4+DQpgYGB7cn0NCiNQcmVkaWNjacOzbiBlbiBlbCBFbnRyZW5hbWllbnRvDQpwcmVkaWNjaW9uX2VudHJlbmFtaWVudG9fdGVsY28gPC0gcHJlZGljdChtb2RlbG9fdGVsY28sIGVudHJlbmFtaWVudG9fdGVsY28sIHR5cGUgPSAicmVzcG9uc2UiKQ0KcmVzdWx0YWRvX3ByZWRpY2Npb25fZW50cmVuYW1pZW50b190ZWxjbyA8LSANCiAgaWZlbHNlKHByZWRpY2Npb25fZW50cmVuYW1pZW50b190ZWxjbyA+PSAwLjUsICJZZXMiLCAiTm8iKQ0KDQojTWF0cml6IGRlIGNvbmZ1c2nDs24gZW4gRW50cmVuYW1pZW50bw0KbWNldCA8LSBjb25mdXNpb25NYXRyaXgoZmFjdG9yKHJlc3VsdGFkb19wcmVkaWNjaW9uX2VudHJlbmFtaWVudG9fdGVsY28sIGxldmVscz1jKCJZZXMiLCAiTm8iKSksIGVudHJlbmFtaWVudG9fdGVsY28kQ2h1cm4pDQptY2V0DQoNCiNQcmVkaWNjacOzbiBlbiBQcnVlYmENCnByZWRpY2Npb25fcHJ1ZWJhX3RlbGNvIDwtDQogIHByZWRpY3QobW9kZWxvX3RlbGNvLHBydWViYV90ZWxjbywgdHlwZSA9ICJyZXNwb25zZSIpDQpyZXN1bHRhZG9fcHJlZGljY2lvbl9wcnVlYmFfdGVsY28gPC0NCiAgaWZlbHNlKHByZWRpY2Npb25fcHJ1ZWJhX3RlbGNvID49IDAuNSwgIlllcyIsICJObyIpDQoNCiNNYXRyaXogZGUgY29uZnVzacOzbiBlbiBQcnVlYmENCm1jZXAgPC0gY29uZnVzaW9uTWF0cml4KGZhY3RvcihyZXN1bHRhZG9fcHJlZGljY2lvbl9wcnVlYmFfdGVsY28sIGxldmVscz1jKCJZZXMiLCAiTm8iKSksIHBydWViYV90ZWxjbyRDaHVybikNCm1jZXANCmBgYA0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkVqZW1wbG8gZGUgUHJlZGljY2nDs248L3NwYW4+DQpgYGB7cn0NCmluZm9fY2xpZW50ZSA8LSB0ZWxjb19saW1waWFbMSwgXQ0KaW5mb19jbGllbnRlIDwtIGluZm9fY2xpZW50ZSAlPiUgc2VsZWN0KC1DaHVybikNCnByb2JhYmlsaWRhZF9jbGllbnRlIDwtIHByZWRpY3QobW9kZWxvX3RlbGNvLCBpbmZvX2NsaWVudGUsIHR5cGUgPSAicmVzcG9uc2UiKQ0KcHJvYmFiaWxpZGFkX2NsaWVudGUNCnByZWRpY2Npb25fY2xpZW50ZSA8LQ0KICBpZmVsc2UocHJvYmFiaWxpZGFkX2NsaWVudGUgPj0wLjUsICJZZXMiLCAiTm8iKQ0KcHJlZGljY2lvbl9jbGllbnRlDQpgYGA=