Dataset
#install.packages("PerformanceAnalytics")
library(readr)
library(dplyr)
data <- read.csv("C:/Users/ander/Desktop/Kpis_SLA_meli.csv", header =TRUE, sep=",")
#Elimino la variable del SLA, para quedarme con dataset para analizar Backlog
data2 <- data[,c(2:15)]
head(data2)
Matriz de Correlación
#escala todas las variables para que tengan media = 0 y desviación estÔndar = 1
data <- data%>% mutate_all (~ ( scale (.)%>% as.vector ))
data2 <- data2%>% mutate_all (~ ( scale (.)%>% as.vector ))
library(PerformanceAnalytics)
x <- data[,c( "SLA","VOLUMEN.RECIBIDO","BACKLOG", "Ausentismo","Ausentismo.NP", "Horas.trabajadas", "Hora.espera.promedio", "DESVIO.CAPACIDAD.vs.RECIBIDO", "BACKLOG_t1")]
chart.Correlation(x, histogram = TRUE, method = "pearson")

#install.packages("leaps")
require(leaps)
# Prueba todos los posibles modelos y se queda con los mejores
#NO puede haber datos faltantes para aplicar lo que sigue:
mejores_modelos_back <- regsubsets(BACKLOG ~ ., data = data2, nvmax = 5)
mejores_modelos_sla <- regsubsets(SLA ~ ., data = data, nvmax = 5)
Selección de variables
#install.packages("leaps")
require(leaps)
# Prueba todos los posibles modelos y se queda con los mejores
#NO puede haber datos faltantes para aplicar lo que sigue:
mejores_modelos_back <- regsubsets(BACKLOG ~ ., data = data2, nvmax = 7)
mejores_modelos_sla <- regsubsets(SLA ~ ., data = data, nvmax = 7)
library(ggplot2)
p <- ggplot(data = data.frame(n_predictores = 1:7, R_ajustado = summary(mejores_modelos_back)$adjr2), aes(x = n_predictores, y = R_ajustado)) +
geom_line() +
geom_point()
# Se identifica en rojo el mƔximo
p <- p + geom_point(aes(x=n_predictores[which.max(summary(mejores_modelos_back)$adjr2)], y=R_ajustado[which.max(summary(mejores_modelos_back)$adjr2)]), colour = "red", size = 3)
p <- p + scale_x_continuous(breaks = c(0:6)) + theme_bw() +
labs(title = "R2_ajustado vs nĆŗmero de predictores", x = "nĆŗmero predictores")
p

################################################################
p1 <- ggplot(data = data.frame(n_predictores = 1:7, R_ajustado = summary(mejores_modelos_sla)$adjr2), aes(x = n_predictores, y = R_ajustado)) +
geom_line() +
geom_point()
# Se identifica en rojo el mƔximo
p1 <- p1 + geom_point(aes(x=n_predictores[which.max(summary(mejores_modelos_sla)$adjr2)], y=R_ajustado[which.max(summary(mejores_modelos_sla)$adjr2)]), colour = "red", size = 3)
p1 <- p1 + scale_x_continuous(breaks = c(0:5)) + theme_bw() +
labs(title = "R2_ajustado vs nĆŗmero de predictores", x = "nĆŗmero predictores")
p1
Mejor modelo para Backlog
coef(object = mejores_modelos_back, id = 5)
## (Intercept) CAPACIDAD VOLUMEN.RECIBIDO BACKLOG_t1
## -4.510281e-17 -2.855217e-01 8.143013e-01 5.490245e-01
## Ausentismo.NP Reencaminado
## 2.465519e-01 -3.021792e-01
Mejor modelo para SLA
coef(object = mejores_modelos_sla, id = 3)
## (Intercept) VOLUMEN.RECIBIDO BACKLOG Citados_confirmados
## -3.452100e-16 1.266789e-01 -9.456872e-01 8.757600e-02
Todas las combinaciones
Selecciona el subconjunto de predictores que alcanzan mayor R2 o
menor MSE, Mallowās Cp o AIC, etc.
library(olsrr)
lm.fit1 <- lm(BACKLOG ~ ., data = data2)
k_best <- ols_step_best_subset(lm.fit1)
k_best
plot(k_best)# el eje horizontal representa la cantidad de variables utilizadas en cada modelo.


lm.fit2 <- lm(SLA ~ ., data = data)
k_best <- ols_step_best_subset(lm.fit2)
k_best
plot(k_best)# el eje horizontal representa la cantidad de variables utilizadas en cada modelo.


Modelos Finales
Modelo Backlog
model_Backlog <- lm(BACKLOG ~ CAPACIDAD + VOLUMEN.RECIBIDO + BACKLOG_t1 +Ausentismo.NP + Reencaminado , data = data2)
summary(model_Backlog)
##
## Call:
## lm(formula = BACKLOG ~ CAPACIDAD + VOLUMEN.RECIBIDO + BACKLOG_t1 +
## Ausentismo.NP + Reencaminado, data = data2)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.42503 -0.40659 -0.02751 0.39744 1.40309
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 7.264e-17 7.028e-02 0.000 1.00000
## CAPACIDAD -2.855e-01 9.035e-02 -3.160 0.00247 **
## VOLUMEN.RECIBIDO 8.143e-01 1.109e-01 7.345 6.46e-10 ***
## BACKLOG_t1 5.490e-01 7.516e-02 7.305 7.54e-10 ***
## Ausentismo.NP 2.466e-01 7.609e-02 3.240 0.00195 **
## Reencaminado -3.022e-01 1.032e-01 -2.929 0.00480 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.5709 on 60 degrees of freedom
## Multiple R-squared: 0.6991, Adjusted R-squared: 0.674
## F-statistic: 27.88 on 5 and 60 DF, p-value: 1.764e-14
Modelo SLA
model_sla <- lm(SLA ~ VOLUMEN.RECIBIDO + BACKLOG + Citados_confirmados , data=data)
summary(model_sla)
##
## Call:
## lm(formula = SLA ~ VOLUMEN.RECIBIDO + BACKLOG + Citados_confirmados,
## data = data)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.81131 -0.22906 0.04872 0.31298 1.02202
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -4.435e-16 5.658e-02 0.000 1.0000
## VOLUMEN.RECIBIDO 1.267e-01 6.842e-02 1.851 0.0689 .
## BACKLOG -9.457e-01 6.860e-02 -13.786 <2e-16 ***
## Citados_confirmados 8.758e-02 5.728e-02 1.529 0.1314
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.4597 on 62 degrees of freedom
## Multiple R-squared: 0.7985, Adjusted R-squared: 0.7887
## F-statistic: 81.87 on 3 and 62 DF, p-value: < 2.2e-16
Se usa el criterio del vif para verificar la multicolinealidad un vif
bajo o menor a 5 es criterio suficiente para descartar
multicolinealidad
library(car)
car::vif(model_Backlog)
## CAPACIDAD VOLUMEN.RECIBIDO BACKLOG_t1 Ausentismo.NP
## 1.627691 2.451276 1.126340 1.154621
## Reencaminado
## 2.121876
AnÔlisis de normalidad, homocedasticidad y autocorrelación de los
residuos.
#install.packages("lmtest")
library(lmtest)
shapiro.test(model_sla$residuals)
##
## Shapiro-Wilk normality test
##
## data: model_sla$residuals
## W = 0.93513, p-value = 0.001882
bptest(model_sla)
##
## studentized Breusch-Pagan test
##
## data: model_sla
## BP = 6.3412, df = 3, p-value = 0.09614
dwtest(model_sla)
##
## Durbin-Watson test
##
## data: model_sla
## DW = 1.5639, p-value = 0.02968
## alternative hypothesis: true autocorrelation is greater than 0
par(mfrow=c(2,2))
plot(model_Backlog)
### Distancia Cook
dcook<-cooks.distance(model_sla)
influenceIndexPlot(model_sla, vars='Cook', las=1,col='blue')

dcook<-cooks.distance(model_Backlog)
influenceIndexPlot(model_Backlog, vars='Cook', las=1,col='blue')

qqPlot(model_Backlog$residuals, pch=19,
main="QQplot para los residuos del Modelo Lineal",
xlab="Cuantiles te“oricos",
ylab="Cuantiles muestrales")

## [1] 59 11
LS0tDQp0aXRsZTogIk1vZGVsbyBMaW5lYWwgTXVsdGl2YXJpYWRvIFNMQSINCmF1dGhvcjogIkN1c3RvbWVyIEludGVsbGlnZW5jZSINCmRhdGU6ICIyMy8xMS8yMDIyIg0Kb3V0cHV0Og0KICAgaHRtbF9kb2N1bWVudDoNCiAgICAgdG9jOiB5ZXMNCiAgICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgIHRvY19mbG9hdDogeWVzDQogICAgIGRmX3ByaW50OiBwYWdlZA0KICAgICB0aGVtZTogdW5pdGVkDQogICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCnNldHdkKCJDOi9Vc2Vycy9hbmRlci9EZXNrdG9wIikNCmBgYA0KDQoNCiMjIERhdGFzZXQNCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KI2luc3RhbGwucGFja2FnZXMoIlBlcmZvcm1hbmNlQW5hbHl0aWNzIikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQpkYXRhIDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9hbmRlci9EZXNrdG9wL0twaXNfU0xBX21lbGkuY3N2IiwgaGVhZGVyID1UUlVFLCBzZXA9IiwiKQ0KDQojRWxpbWlubyBsYSB2YXJpYWJsZSBkZWwgU0xBLCBwYXJhIHF1ZWRhcm1lIGNvbiBkYXRhc2V0IHBhcmEgYW5hbGl6YXIgQmFja2xvZw0KZGF0YTIgPC0gZGF0YVssYygyOjE1KV0NCmhlYWQoZGF0YTIpDQoNCmBgYA0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjpkYXJrcmVkIj5NYXRyaXogZGUgQ29ycmVsYWNpw7NuPC9zcGFuPg0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQoNCg0KI2VzY2FsYSB0b2RhcyBsYXMgdmFyaWFibGVzIHBhcmEgcXVlIHRlbmdhbiBtZWRpYSA9IDAgeSBkZXN2aWFjacOzbiBlc3TDoW5kYXIgPSAxIA0KZGF0YSA8LSBkYXRhJT4lIG11dGF0ZV9hbGwgKH4gKCBzY2FsZSAoLiklPiUgYXMudmVjdG9yICkpDQpkYXRhMiA8LSBkYXRhMiU+JSBtdXRhdGVfYWxsICh+ICggc2NhbGUgKC4pJT4lIGFzLnZlY3RvciApKQ0KDQoNCmBgYA0KDQo8YnI+DQoNCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0NCg0KDQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KeCA8LSBkYXRhWyxjKCAiU0xBIiwiVk9MVU1FTi5SRUNJQklETyIsIkJBQ0tMT0ciLCAiQXVzZW50aXNtbyIsIkF1c2VudGlzbW8uTlAiLCAiSG9yYXMudHJhYmFqYWRhcyIsICJIb3JhLmVzcGVyYS5wcm9tZWRpbyIsICJERVNWSU8uQ0FQQUNJREFELnZzLlJFQ0lCSURPIiwgIkJBQ0tMT0dfdDEiKV0NCmNoYXJ0LkNvcnJlbGF0aW9uKHgsIGhpc3RvZ3JhbSA9IFRSVUUsIG1ldGhvZCA9ICJwZWFyc29uIikNCmBgYA0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQoNCg0KI2luc3RhbGwucGFja2FnZXMoImxlYXBzIikNCg0KcmVxdWlyZShsZWFwcykgDQoNCiMgUHJ1ZWJhIHRvZG9zIGxvcyBwb3NpYmxlcyBtb2RlbG9zIHkgc2UgcXVlZGEgY29uIGxvcyBtZWpvcmVzDQojTk8gcHVlZGUgaGFiZXIgZGF0b3MgZmFsdGFudGVzIHBhcmEgYXBsaWNhciBsbyBxdWUgc2lndWU6DQptZWpvcmVzX21vZGVsb3NfYmFjayA8LSByZWdzdWJzZXRzKEJBQ0tMT0cgfiAuLCBkYXRhID0gZGF0YTIsIG52bWF4ID0gNSkgDQptZWpvcmVzX21vZGVsb3Nfc2xhIDwtIHJlZ3N1YnNldHMoU0xBIH4gLiwgZGF0YSA9IGRhdGEsIG52bWF4ID0gNSkgDQoNCg0KYGBgDQoNCjxicj4NCg0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmRhcmtyZWQiPlNlbGVjY2nDs24gZGUgdmFyaWFibGVzPC9zcGFuPg0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQoNCg0KI2luc3RhbGwucGFja2FnZXMoImxlYXBzIikNCg0KcmVxdWlyZShsZWFwcykgDQoNCiMgUHJ1ZWJhIHRvZG9zIGxvcyBwb3NpYmxlcyBtb2RlbG9zIHkgc2UgcXVlZGEgY29uIGxvcyBtZWpvcmVzDQojTk8gcHVlZGUgaGFiZXIgZGF0b3MgZmFsdGFudGVzIHBhcmEgYXBsaWNhciBsbyBxdWUgc2lndWU6DQptZWpvcmVzX21vZGVsb3NfYmFjayA8LSByZWdzdWJzZXRzKEJBQ0tMT0cgfiAuLCBkYXRhID0gZGF0YTIsIG52bWF4ID0gNykgDQptZWpvcmVzX21vZGVsb3Nfc2xhIDwtIHJlZ3N1YnNldHMoU0xBIH4gLiwgZGF0YSA9IGRhdGEsIG52bWF4ID0gNykgDQoNCg0KYGBgDQoNCjxicj4NCg0KDQpgYGB7cn0NCg0KbGlicmFyeShnZ3Bsb3QyKSANCnAgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKG5fcHJlZGljdG9yZXMgPSAxOjcsIFJfYWp1c3RhZG8gPSBzdW1tYXJ5KG1lam9yZXNfbW9kZWxvc19iYWNrKSRhZGpyMiksIGFlcyh4ID0gbl9wcmVkaWN0b3JlcywgeSA9IFJfYWp1c3RhZG8pKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3BvaW50KCkgDQojIFNlIGlkZW50aWZpY2EgZW4gcm9qbyBlbCBtw6F4aW1vIA0KcCA8LSBwICsgZ2VvbV9wb2ludChhZXMoeD1uX3ByZWRpY3RvcmVzW3doaWNoLm1heChzdW1tYXJ5KG1lam9yZXNfbW9kZWxvc19iYWNrKSRhZGpyMildLCB5PVJfYWp1c3RhZG9bd2hpY2gubWF4KHN1bW1hcnkobWVqb3Jlc19tb2RlbG9zX2JhY2spJGFkanIyKV0pLCBjb2xvdXIgPSAicmVkIiwgc2l6ZSA9IDMpIA0KcCA8LSBwICsgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMDo2KSkgKyB0aGVtZV9idygpICsgDQogIGxhYnModGl0bGUgPSAiUjJfYWp1c3RhZG8gdnMgbsO6bWVybyBkZSBwcmVkaWN0b3JlcyIsIHggPSAibsO6bWVybyBwcmVkaWN0b3JlcyIpIA0KcA0KDQoNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCnAxIDwtIGdncGxvdChkYXRhID0gZGF0YS5mcmFtZShuX3ByZWRpY3RvcmVzID0gMTo3LCBSX2FqdXN0YWRvID0gc3VtbWFyeShtZWpvcmVzX21vZGVsb3Nfc2xhKSRhZGpyMiksIGFlcyh4ID0gbl9wcmVkaWN0b3JlcywgeSA9IFJfYWp1c3RhZG8pKSArIA0KICBnZW9tX2xpbmUoKSArIA0KICBnZW9tX3BvaW50KCkgDQojIFNlIGlkZW50aWZpY2EgZW4gcm9qbyBlbCBtw6F4aW1vIA0KcDEgPC0gcDEgKyBnZW9tX3BvaW50KGFlcyh4PW5fcHJlZGljdG9yZXNbd2hpY2gubWF4KHN1bW1hcnkobWVqb3Jlc19tb2RlbG9zX3NsYSkkYWRqcjIpXSwgeT1SX2FqdXN0YWRvW3doaWNoLm1heChzdW1tYXJ5KG1lam9yZXNfbW9kZWxvc19zbGEpJGFkanIyKV0pLCBjb2xvdXIgPSAicmVkIiwgc2l6ZSA9IDMpIA0KcDEgPC0gcDEgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwOjUpKSArIHRoZW1lX2J3KCkgKyANCiAgbGFicyh0aXRsZSA9ICJSMl9hanVzdGFkbyB2cyBuw7ptZXJvIGRlIHByZWRpY3RvcmVzIiwgeCA9ICJuw7ptZXJvIHByZWRpY3RvcmVzIikgDQpwMQ0KDQoNCg0KYGBgDQo8YnI+DQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6ZGFya3JlZCI+TWVqb3IgbW9kZWxvIHBhcmEgQmFja2xvZzwvc3Bhbj4NCg0KPGJyPg0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQoNCmNvZWYob2JqZWN0ID0gbWVqb3Jlc19tb2RlbG9zX2JhY2ssIGlkID0gNSkNCmBgYA0KPGJyPg0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmRhcmtyZWQiPk1lam9yIG1vZGVsbyBwYXJhIFNMQTwvc3Bhbj4NCg0KPGJyPg0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQoNCmNvZWYob2JqZWN0ID0gbWVqb3Jlc19tb2RlbG9zX3NsYSwgaWQgPSAzKQ0KYGBgDQoNCg0KPGJyPg0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmRhcmtyZWQiPlRvZGFzIGxhcyBjb21iaW5hY2lvbmVzPC9zcGFuPg0KDQo8YnI+DQoNClNlbGVjY2lvbmEgZWwgc3ViY29uanVudG8gZGUgcHJlZGljdG9yZXMgcXVlIGFsY2FuemFuIG1heW9yIFIyIG8gbWVub3IgTVNFLCBNYWxsb3figJlzIENwIG8gQUlDLCBldGMuDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkob2xzcnIpDQpsbS5maXQxIDwtIGxtKEJBQ0tMT0cgfiAuLCBkYXRhID0gZGF0YTIpDQprX2Jlc3QgPC0gb2xzX3N0ZXBfYmVzdF9zdWJzZXQobG0uZml0MSkNCmtfYmVzdA0KDQpwbG90KGtfYmVzdCkjIGVsIGVqZSBob3Jpem9udGFsIHJlcHJlc2VudGEgbGEgY2FudGlkYWQgZGUgdmFyaWFibGVzIHV0aWxpemFkYXMgZW4gY2FkYSBtb2RlbG8uDQoNCg0KYGBgDQoNCg0KPGJyPg0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQoNCg0KbG0uZml0MiA8LSBsbShTTEEgfiAuLCBkYXRhID0gZGF0YSkNCmtfYmVzdCA8LSBvbHNfc3RlcF9iZXN0X3N1YnNldChsbS5maXQyKQ0Ka19iZXN0DQoNCnBsb3Qoa19iZXN0KSMgZWwgZWplIGhvcml6b250YWwgcmVwcmVzZW50YSBsYSBjYW50aWRhZCBkZSB2YXJpYWJsZXMgdXRpbGl6YWRhcyBlbiBjYWRhIG1vZGVsby4NCg0KDQpgYGANCg0KPGJyPg0KDQojIyBNb2RlbG9zIEZpbmFsZXMNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6ZGFya3JlZCI+TW9kZWxvIEJhY2tsb2c8L3NwYW4+DQoNCjxicj4NCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRX0NCm1vZGVsX0JhY2tsb2cgPC0gbG0oQkFDS0xPRyB+IENBUEFDSURBRCAgKyBWT0xVTUVOLlJFQ0lCSURPICArIEJBQ0tMT0dfdDEgK0F1c2VudGlzbW8uTlAgICsgUmVlbmNhbWluYWRvICwgZGF0YSA9IGRhdGEyKQ0Kc3VtbWFyeShtb2RlbF9CYWNrbG9nKQ0KYGBgDQoNCjxicj4NCg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjpkYXJrcmVkIj5Nb2RlbG8gU0xBPC9zcGFuPg0KDQo8YnI+DQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0V9DQptb2RlbF9zbGEgPC0gbG0oU0xBIH4gVk9MVU1FTi5SRUNJQklETyAgICAgKyAgIEJBQ0tMT0cgKyBDaXRhZG9zX2NvbmZpcm1hZG9zICAsIGRhdGE9ZGF0YSkNCnN1bW1hcnkobW9kZWxfc2xhKQ0KDQpgYGANCg0KPGJyPg0KDQpTZSB1c2EgZWwgY3JpdGVyaW8gZGVsIHZpZiBwYXJhIHZlcmlmaWNhciBsYSBtdWx0aWNvbGluZWFsaWRhZCB1biB2aWYgYmFqbyBvIG1lbm9yIGEgNSBlcyBjcml0ZXJpbyBzdWZpY2llbnRlIHBhcmEgZGVzY2FydGFyIG11bHRpY29saW5lYWxpZGFkDQoNCjxicj4NCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRSxtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeShjYXIpDQpjYXI6OnZpZihtb2RlbF9CYWNrbG9nKQ0KYGBgDQoNCg0KIyMgQW7DoWxpc2lzIGRlIG5vcm1hbGlkYWQsIGhvbW9jZWRhc3RpY2lkYWQgeSBhdXRvY29ycmVsYWNpw7NuIGRlIGxvcyByZXNpZHVvcy4NCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImxtdGVzdCIpDQpsaWJyYXJ5KGxtdGVzdCkNCg0KDQpzaGFwaXJvLnRlc3QobW9kZWxfc2xhJHJlc2lkdWFscykNCg0KYnB0ZXN0KG1vZGVsX3NsYSkNCg0KZHd0ZXN0KG1vZGVsX3NsYSkNCmBgYA0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QobW9kZWxfQmFja2xvZykNCg0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmRhcmtyZWQiPkRpc3RhbmNpYSBDb29rPC9zcGFuPg0KDQoNCmBgYHtyLCBlY2hvPVRSVUV9DQpkY29vazwtY29va3MuZGlzdGFuY2UobW9kZWxfc2xhKQ0KaW5mbHVlbmNlSW5kZXhQbG90KG1vZGVsX3NsYSwgdmFycz0nQ29vaycsIGxhcz0xLGNvbD0nYmx1ZScpDQpgYGANCg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KZGNvb2s8LWNvb2tzLmRpc3RhbmNlKG1vZGVsX0JhY2tsb2cpDQppbmZsdWVuY2VJbmRleFBsb3QobW9kZWxfQmFja2xvZywgdmFycz0nQ29vaycsIGxhcz0xLGNvbD0nYmx1ZScpDQpgYGANCg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KDQpxcVBsb3QobW9kZWxfQmFja2xvZyRyZXNpZHVhbHMsIHBjaD0xOSwNCm1haW49IlFRcGxvdCBwYXJhIGxvcyByZXNpZHVvcyBkZWwgTW9kZWxvIExpbmVhbCIsDQp4bGFiPSJDdWFudGlsZXMgdGXCtG9yaWNvcyIsDQp5bGFiPSJDdWFudGlsZXMgbXVlc3RyYWxlcyIpDQpgYGANCg==