Contexto

Telco es una empresa internacionalque vende una variedad de servicios de telecomunicaciones es un indicador de la deserción de cliente , fenomeno en el ciual los cliente cancelan sus serviicos con la emmpresa. El objetivo de este trabaho es predecir si un cliente abandanorá o se quedera en la empresa.

Paquetes y librerias

library("tidyverse")
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library("caret")
## Cargando paquete requerido: lattice
## 
## Adjuntando el paquete: 'caret'
## 
## The following object is masked from 'package:purrr':
## 
##     lift
library("e1071")#Matriz de confusión
library("dplyr")

Importar la base de datos

tel<- read.csv("TELCO.csv")

Revisión de la base de datos (BD)

summary(tel)
##   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(tel)
##   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(tel)
## '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" ...

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, por ejemplo, el precio de una casa), la regresión logística predice resultados binarios o categóricos, como sí/no, 1/0, verdadero/falso.

Si la probabilidad es mayor que 0.5, el modelo predice que el evento ocurrirá (por ejemplo, que el cliente se dará de baja).

Si la probabilidad es menor que 0.5, predice que el evento no ocurrirá.

Preparar la BD

#Eliminar la columna customerID
tel1<- tel %>% select(-customerID)
tel1 <- tel1 %>% mutate_if(is.character, as.factor)
tel1<- na.omit(tel1)

Entrenar modelo

set.seed(123)
r_train <- createDataPartition(tel1$Churn, p=0.7, list=FALSE)
train <- tel1[r_train, ]
test <-tel1[-r_train, ]

# Asegurar que en ambos conjuntos la variable 'Churn' esté ordenada: "No" primero y "Yes" segundo
train$Churn <- factor(train$Churn, levels = c("Yes","No"))
test$Churn <- factor(test$Churn, levels = c("Yes", "No"))
# Entrenar el modelo de red neuronal
modelo1 <- glm( Churn ~ .,   data = train, family = binomial)

summary(modelo1)
## 
## Call:
## glm(formula = Churn ~ ., family = binomial, data = train)
## 
## 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

Entrenar modelo

# Realizar predicciones en los conjuntos de entrenamiento y prueba
resultado_train <- predict(modelo1, train, type="response")
resultado_train<- ifelse(resultado_train>= 0.5, "Yes","No")
resultado_test <- predict(modelo1, test, type="response")
resultado_test <- ifelse(resultado_test>= 0.5, "Yes","No")

Matriz de confusion Entreno y Prueba

# Evaluar desempeño del modelo
mcf <- confusionMatrix(factor(resultado_train,
       levels=c("Yes", "No")),train$Churn)
mcf
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  Yes   No
##        Yes  598 3237
##        No   711  378
##                                           
##                Accuracy : 0.1982          
##                  95% CI : (0.1872, 0.2096)
##     No Information Rate : 0.7342          
##     P-Value [Acc > NIR] : 1               
##                                           
##                   Kappa : -0.2715         
##                                           
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.4568          
##             Specificity : 0.1046          
##          Pos Pred Value : 0.1559          
##          Neg Pred Value : 0.3471          
##              Prevalence : 0.2658          
##          Detection Rate : 0.1214          
##    Detection Prevalence : 0.7788          
##       Balanced Accuracy : 0.2807          
##                                           
##        'Positive' Class : Yes             
## 
# Evaluar desempeño del modelo
mcf1<- confusionMatrix(factor(resultado_test,
       levels=c("Yes","No")),test$Churn)
mcf1
## Confusion Matrix and Statistics
## 
##           Reference
## Prediction  Yes   No
##        Yes  229 1385
##        No   331  163
##                                           
##                Accuracy : 0.186           
##                  95% CI : (0.1696, 0.2032)
##     No Information Rate : 0.7343          
##     P-Value [Acc > NIR] : 1               
##                                           
##                   Kappa : -0.3035         
##                                           
##  Mcnemar's Test P-Value : <2e-16          
##                                           
##             Sensitivity : 0.4089          
##             Specificity : 0.1053          
##          Pos Pred Value : 0.1419          
##          Neg Pred Value : 0.3300          
##              Prevalence : 0.2657          
##          Detection Rate : 0.1086          
##    Detection Prevalence : 0.7657          
##       Balanced Accuracy : 0.2571          
##                                           
##        'Positive' Class : Yes             
## 

Predicción

info_cliente <- tel1 %>% 
  select(-Churn) %>%  # Elimina la columna "Churn"
  slice(4)            # Selecciona la primera fila
prob <- predict(modelo1, info_cliente, type = "response")
prob
##         1 
## 0.9731558
prob<-ifelse(prob>= 0.5,"Yes","No")
prob
##     1 
## "Yes"
# Guardar el modelo pre-entrenado en un archivo RDS
saveRDS(modelo1, file = "modelo.rds1")
saveRDS(train, file = "train.rds")

Cargar los modelos pre-entrenados

modelo_ml <- readRDS(“modelo.rds”) # Modelo para la pestaña ML (por ejemplo, red neuronal) modelo_rl <- readRDS(“modelo.rds1”) # Modelo de regresión logística train <- readRDS(“train.rds”)

LS0tDQp0aXRsZTogIlJlZ3Jlc2nDs24gTG9naXNpdGNhIg0KYXV0aG9yOiAiQW5kcmV1IFNhcnJldGEiDQpkYXRlOiAiMjAyNS0wMi0yNSINCm91dHB1dDoNCiAgIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRoZW1lOiAiam91cm5hbCINCiAgICBoaWdobGlnaHQ6ICJrYXRlIg0KLS0tDQoNCiFbXShEOlxUZWNcU2V4dG8gU2VtZXN0cmVcSUEgY29uY2VudHJhY2lvblxSc3R1ZGlvXE1vZHVsbyAyXGNodXJuLmpwZykNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPioqQ29udGV4dG8qKjwvc3Bhbj4NCg0KKipUZWxjbyoqIGVzIHVuYSBlbXByZXNhIGludGVybmFjaW9uYWxxdWUgdmVuZGUNCnVuYSB2YXJpZWRhZCBkZSBzZXJ2aWNpb3MgZGUgdGVsZWNvbXVuaWNhY2lvbmVzIGVzIHVuIGluZGljYWRvciBkZSBsYSANCmRlc2VyY2nDs24gZGUgY2xpZW50ZSAsIGZlbm9tZW5vIGVuIGVsIGNpdWFsIGxvcyBjbGllbnRlIGNhbmNlbGFuIHN1cyANCnNlcnZpaWNvcyBjb24gbGEgZW1tcHJlc2EuIEVsIG9iamV0aXZvIGRlIGVzdGUgdHJhYmFobyBlcyBwcmVkZWNpciBzaSB1biANCmNsaWVudGUgYWJhbmRhbm9yw6EgbyBzZSBxdWVkZXJhIGVuIGxhIGVtcHJlc2EuDQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPioqUGFxdWV0ZXMgeSBsaWJyZXJpYXMqKjwvc3Bhbj4NCg0KYGBge3J9DQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSgiY2FyZXQiKQ0KbGlicmFyeSgiZTEwNzEiKSNNYXRyaXogZGUgY29uZnVzacOzbg0KbGlicmFyeSgiZHBseXIiKQ0KDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4qKkltcG9ydGFyIGxhIGJhc2UgZGUgZGF0b3MqKjwvc3Bhbj4NCg0KYGBge3J9DQp0ZWw8LSByZWFkLmNzdigiVEVMQ08uY3N2IikNCg0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+KipSZXZpc2nDs24gZGUgbGEgYmFzZSBkZSBkYXRvcyAoQkQpKio8L3NwYW4+DQpgYGB7cn0NCnN1bW1hcnkodGVsKQ0KaGVhZCh0ZWwpDQpzdHIodGVsKQ0KYGBgDQoNCkxBICoqcmVncmVzacOzbiBsb2fDrXN0aWNhKiogZXMgdW4gbW9kZWxvIHF1ZSBzZSB1dGlsaXphIHBhcmEgcHJlZGVjaXIgbGEgcHJvYmFiaWxpZGFkIGRlIHF1ZSBvY3VycmEgdW4gZXZlbnRvLCBiYXNhZG8gZW4gdW5hIG8gbcOhcyB2YXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMuIEEgZGlmZXJlbmNpYSBkZSBsYSByZWdyZXNpw7NuIGxpbmVhbCwgcXVlIHByZWRpY2UgdmFsb3JlcyBjb250aW51b3MgKGNvbW8sIHBvciBlamVtcGxvLCBlbCBwcmVjaW8gZGUgdW5hIGNhc2EpLCBsYSByZWdyZXNpw7NuIGxvZ8Otc3RpY2EgcHJlZGljZSByZXN1bHRhZG9zICoqYmluYXJpb3MgbyBjYXRlZ8Ozcmljb3MqKiwgY29tbyBzw60vbm8sIDEvMCwgdmVyZGFkZXJvL2ZhbHNvLg0KDQpTaSBsYSBwcm9iYWJpbGlkYWQgZXMgbWF5b3IgcXVlIDAuNSwgZWwgbW9kZWxvIHByZWRpY2UgcXVlIGVsIGV2ZW50byBvY3Vycmlyw6EgKHBvciBlamVtcGxvLCBxdWUgZWwgY2xpZW50ZSBzZSBkYXLDoSBkZSBiYWphKS4NCg0KU2kgbGEgcHJvYmFiaWxpZGFkIGVzIG1lbm9yIHF1ZSAwLjUsIHByZWRpY2UgcXVlIGVsIGV2ZW50byBubyBvY3Vycmlyw6EuDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+KipQcmVwYXJhciBsYSBCRCoqPC9zcGFuPg0KYGBge3J9DQojRWxpbWluYXIgbGEgY29sdW1uYSBjdXN0b21lcklEDQp0ZWwxPC0gdGVsICU+JSBzZWxlY3QoLWN1c3RvbWVySUQpDQp0ZWwxIDwtIHRlbDEgJT4lIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsIGFzLmZhY3RvcikNCnRlbDE8LSBuYS5vbWl0KHRlbDEpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4qKkVudHJlbmFyIG1vZGVsbyoqPC9zcGFuPg0KYGBge3J9DQpzZXQuc2VlZCgxMjMpDQpyX3RyYWluIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24odGVsMSRDaHVybiwgcD0wLjcsIGxpc3Q9RkFMU0UpDQp0cmFpbiA8LSB0ZWwxW3JfdHJhaW4sIF0NCnRlc3QgPC10ZWwxWy1yX3RyYWluLCBdDQoNCiMgQXNlZ3VyYXIgcXVlIGVuIGFtYm9zIGNvbmp1bnRvcyBsYSB2YXJpYWJsZSAnQ2h1cm4nIGVzdMOpIG9yZGVuYWRhOiAiTm8iIHByaW1lcm8geSAiWWVzIiBzZWd1bmRvDQp0cmFpbiRDaHVybiA8LSBmYWN0b3IodHJhaW4kQ2h1cm4sIGxldmVscyA9IGMoIlllcyIsIk5vIikpDQp0ZXN0JENodXJuIDwtIGZhY3Rvcih0ZXN0JENodXJuLCBsZXZlbHMgPSBjKCJZZXMiLCAiTm8iKSkNCmBgYA0KDQpgYGB7cn0NCiMgRW50cmVuYXIgZWwgbW9kZWxvIGRlIHJlZCBuZXVyb25hbA0KbW9kZWxvMSA8LSBnbG0oIENodXJuIH4gLiwgICBkYXRhID0gdHJhaW4sIGZhbWlseSA9IGJpbm9taWFsKQ0KDQpzdW1tYXJ5KG1vZGVsbzEpDQogIA0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+KipFbnRyZW5hciBtb2RlbG8qKjwvc3Bhbj4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFJlYWxpemFyIHByZWRpY2Npb25lcyBlbiBsb3MgY29uanVudG9zIGRlIGVudHJlbmFtaWVudG8geSBwcnVlYmENCnJlc3VsdGFkb190cmFpbiA8LSBwcmVkaWN0KG1vZGVsbzEsIHRyYWluLCB0eXBlPSJyZXNwb25zZSIpDQpyZXN1bHRhZG9fdHJhaW48LSBpZmVsc2UocmVzdWx0YWRvX3RyYWluPj0gMC41LCAiWWVzIiwiTm8iKQ0KcmVzdWx0YWRvX3Rlc3QgPC0gcHJlZGljdChtb2RlbG8xLCB0ZXN0LCB0eXBlPSJyZXNwb25zZSIpDQpyZXN1bHRhZG9fdGVzdCA8LSBpZmVsc2UocmVzdWx0YWRvX3Rlc3Q+PSAwLjUsICJZZXMiLCJObyIpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4qKk1hdHJpeiBkZSBjb25mdXNpb24gRW50cmVubyB5IFBydWViYSoqPC9zcGFuPg0KYGBge3J9DQojIEV2YWx1YXIgZGVzZW1wZcOxbyBkZWwgbW9kZWxvDQptY2YgPC0gY29uZnVzaW9uTWF0cml4KGZhY3RvcihyZXN1bHRhZG9fdHJhaW4sDQogICAgICAgbGV2ZWxzPWMoIlllcyIsICJObyIpKSx0cmFpbiRDaHVybikNCm1jZg0KDQojIEV2YWx1YXIgZGVzZW1wZcOxbyBkZWwgbW9kZWxvDQptY2YxPC0gY29uZnVzaW9uTWF0cml4KGZhY3RvcihyZXN1bHRhZG9fdGVzdCwNCiAgICAgICBsZXZlbHM9YygiWWVzIiwiTm8iKSksdGVzdCRDaHVybikNCm1jZjENCg0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4qKlByZWRpY2Npw7NuKio8L3NwYW4+DQpgYGB7cn0NCmluZm9fY2xpZW50ZSA8LSB0ZWwxICU+JSANCiAgc2VsZWN0KC1DaHVybikgJT4lICAjIEVsaW1pbmEgbGEgY29sdW1uYSAiQ2h1cm4iDQogIHNsaWNlKDQpICAgICAgICAgICAgIyBTZWxlY2Npb25hIGxhIHByaW1lcmEgZmlsYQ0KYGBgDQoNCmBgYHtyfQ0KcHJvYiA8LSBwcmVkaWN0KG1vZGVsbzEsIGluZm9fY2xpZW50ZSwgdHlwZSA9ICJyZXNwb25zZSIpDQpwcm9iDQpwcm9iPC1pZmVsc2UocHJvYj49IDAuNSwiWWVzIiwiTm8iKQ0KcHJvYg0KYGBgDQoNCg0KYGBge3J9DQojIEd1YXJkYXIgZWwgbW9kZWxvIHByZS1lbnRyZW5hZG8gZW4gdW4gYXJjaGl2byBSRFMNCnNhdmVSRFMobW9kZWxvMSwgZmlsZSA9ICJtb2RlbG8ucmRzMSIpDQpgYGANCg0KYGBge3J9DQpzYXZlUkRTKHRyYWluLCBmaWxlID0gInRyYWluLnJkcyIpDQpgYGANCg0KIyBDYXJnYXIgbG9zIG1vZGVsb3MgcHJlLWVudHJlbmFkb3MNCm1vZGVsb19tbCA8LSByZWFkUkRTKCJtb2RlbG8ucmRzIikgICAgIyBNb2RlbG8gcGFyYSBsYSBwZXN0YcOxYSBNTCAocG9yIGVqZW1wbG8sIHJlZCBuZXVyb25hbCkNCm1vZGVsb19ybCA8LSByZWFkUkRTKCJtb2RlbG8ucmRzMSIpICAgICAjIE1vZGVsbyBkZSByZWdyZXNpw7NuIGxvZ8Otc3RpY2ENCnRyYWluIDwtIHJlYWRSRFMoInRyYWluLnJkcyIpDQoNCg==