Generamos datos para entrenamiento y pruebas
train_dataset<-dataset[1:(0.7*nrow(dataset)),] #subdataset de entrenamiento.
test_dataset<-dataset[(0.7*nrow(dataset)+1): nrow(dataset),] #subdataset de prueba.
head(test_dataset)
Arreglos a dataset de entrenamiento:
train_dataset$click<-as.numeric(train_dataset$click)
train_dataset$src<-as.numeric(train_dataset$src)
train_dataset$cpc<-as.vector(train_dataset$cpc)
train_dataset$ecpm<-as.vector(train_dataset$ecpm)
Creamos Varibles Categóricas para set de datos de entrenamiento
train_dataset$placement<-ifelse(train_dataset$placement == "A", 0, 1)
#Creamos de variables categóticas
#weekday
train_dataset<-train_dataset %>%
mutate(weekday.TUE = ifelse(weekday == "TUE", 1, 0)) %>%
mutate(weekday.THU = ifelse(weekday == "THU", 1, 0)) %>%
mutate(weekday.SUN = ifelse(weekday == "SUN", 1, 0)) %>%
mutate(weekday.FRI = ifelse(weekday == "FRI", 1, 0)) %>%
mutate(weekday.SAT = ifelse(weekday == "SAT", 1, 0)) %>%
mutate(weekday.WED = ifelse(weekday == "WED", 1, 0)) %>%
mutate(weekday.MON= ifelse(weekday == "MON", 1, 0))
train_dataset<-train_dataset %>%
mutate(state.77d6b684 = ifelse(state == "77d6b684", 1, 0)) %>%
mutate(state.97e4e7b7 = ifelse(state == "97e4e7b7", 1, 0)) %>%
mutate(state.4bdb89dd = ifelse(state == "4bdb89dd", 1, 0)) %>%
mutate(state.f38822b3 = ifelse(state == "f38822b3", 1, 0)) %>%
mutate(state.f04eaa4b = ifelse(state == "f04eaa4b", 1, 0)) %>%
mutate(state.92676321 = ifelse(state == "92676321", 1, 0)) %>%
mutate(state.26e1d51b = ifelse(state == "26e1d51b", 1, 0)) %>%
mutate(state.92600ee5 = ifelse(state == "92600ee5", 1, 0)) %>%
mutate(state.dd26f5e6 = ifelse(state == "dd26f5e6", 1, 0)) %>%
mutate(state.a8283dd2 = ifelse(state == "a8283dd2", 1, 0)) %>%
mutate(state.8ab3223a = ifelse(state == "8ab3223a", 1, 0)) %>%
mutate(state.63d0870f = ifelse(state == "63d0870f", 1, 0)) %>%
mutate(state.c43dc4a7 = ifelse(state == "c43dc4a7", 1, 0)) %>%
mutate(state.bf0f3c8c = ifelse(state == "bf0f3c8c", 1, 0)) %>%
mutate(state.d1f48576 = ifelse(state == "d1f48576", 1, 0))
#provider name
train_dataset<-train_dataset %>%
mutate(provider_name.b985a6c6 = ifelse(state == "b985a6c6", 1, 0)) %>%
mutate(provider_name.af8e115f = ifelse(state == "af8e115f", 1, 0)) %>%
mutate(provider_name.d886ded = ifelse(state == "d886ded", 1, 0))
Arreglos a dataset de prueba:
#Arreglos a dataset de prueba
test_dataset$click<-as.numeric(test_dataset$click)
test_dataset$src<-as.numeric(test_dataset$src)
test_dataset$cpc<-as.vector(test_dataset$cpc)
test_dataset$ecpm<-as.vector(test_dataset$ecpm)
test_dataset$placement<-ifelse(test_dataset$placement == "A", 0, 1)
Creamos Varibles Categóricas para set de datos de prueba
test_dataset$placement<-ifelse(test_dataset$placement == "A", 0, 1)
#Creamos de variables categóticas
#weekday
test_dataset<-test_dataset %>%
mutate(weekday.TUE = ifelse(weekday == "TUE", 1, 0)) %>%
mutate(weekday.THU = ifelse(weekday == "THU", 1, 0)) %>%
mutate(weekday.SUN = ifelse(weekday == "SUN", 1, 0)) %>%
mutate(weekday.FRI = ifelse(weekday == "FRI", 1, 0)) %>%
mutate(weekday.SAT = ifelse(weekday == "SAT", 1, 0)) %>%
mutate(weekday.WED = ifelse(weekday == "WED", 1, 0)) %>%
mutate(weekday.MON= ifelse(weekday == "MON", 1, 0))
test_dataset<-test_dataset %>%
mutate(state.77d6b684 = ifelse(state == "77d6b684", 1, 0)) %>%
mutate(state.97e4e7b7 = ifelse(state == "97e4e7b7", 1, 0)) %>%
mutate(state.4bdb89dd = ifelse(state == "4bdb89dd", 1, 0)) %>%
mutate(state.f38822b3 = ifelse(state == "f38822b3", 1, 0)) %>%
mutate(state.f04eaa4b = ifelse(state == "f04eaa4b", 1, 0)) %>%
mutate(state.92676321 = ifelse(state == "92676321", 1, 0)) %>%
mutate(state.26e1d51b = ifelse(state == "26e1d51b", 1, 0)) %>%
mutate(state.92600ee5 = ifelse(state == "92600ee5", 1, 0)) %>%
mutate(state.dd26f5e6 = ifelse(state == "dd26f5e6", 1, 0)) %>%
mutate(state.a8283dd2 = ifelse(state == "a8283dd2", 1, 0)) %>%
mutate(state.8ab3223a = ifelse(state == "8ab3223a", 1, 0)) %>%
mutate(state.63d0870f = ifelse(state == "63d0870f", 1, 0)) %>%
mutate(state.c43dc4a7 = ifelse(state == "c43dc4a7", 1, 0)) %>%
mutate(state.bf0f3c8c = ifelse(state == "bf0f3c8c", 1, 0)) %>%
mutate(state.d1f48576 = ifelse(state == "d1f48576", 1, 0))
#provider name
test_dataset<-test_dataset %>%
mutate(provider_name.b985a6c6 = ifelse(state == "b985a6c6", 1, 0)) %>%
mutate(provider_name.af8e115f = ifelse(state == "af8e115f", 1, 0)) %>%
mutate(provider_name.d886ded = ifelse(state == "d886ded", 1, 0))
Modelo de regresión logistica con todas las variavble, excepto ‘zip’ y ‘brand_name’ ya que son demaciadas variables categoricas:
#No usaremos la varaible zip ni brand_name por que son demaciados elementos diferentes.
Logit_model1<-
glm(formula=click ~ src + hour + placement + cpc
+ ctr + ecpm + position + weekday.MON + weekday.FRI + weekday.SUN + weekday.TUE +
weekday.THU + weekday.SAT + state.f38822b3 + state.4bdb89dd + state.92600ee5 +
state.bf0f3c8c + state.f04eaa4b + state.a8283dd2 + state.dd26f5e6 + state.c43dc4a7 + state.63d0870f + state.77d6b684 + state.8ab3223a + state.26e1d51b + state.92676321 + state.d1f48576
, data=train_dataset, family = binomial(link="logit"))
glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(Logit_model1)
Call:
glm(formula = click ~ src + hour + placement + cpc + ctr + ecpm +
position + weekday.MON + weekday.FRI + weekday.SUN + weekday.TUE +
weekday.THU + weekday.SAT + state.f38822b3 + state.4bdb89dd +
state.92600ee5 + state.bf0f3c8c + state.f04eaa4b + state.a8283dd2 +
state.dd26f5e6 + state.c43dc4a7 + state.63d0870f + state.77d6b684 +
state.8ab3223a + state.26e1d51b + state.92676321 + state.d1f48576,
family = binomial(link = "logit"), data = train_dataset)
Deviance Residuals:
Min 1Q Median 3Q Max
-8.4904 -0.2747 -0.1665 -0.0987 3.6796
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -3.6212231 0.0313934 -115.350 < 2e-16 ***
src -0.0007771 0.0001651 -4.706 2.53e-06 ***
hour -0.0245923 0.0007841 -31.362 < 2e-16 ***
placement 1.3919191 0.0127543 109.133 < 2e-16 ***
cpc 0.4066732 0.0071148 57.159 < 2e-16 ***
ctr 17.1704597 0.2394683 71.702 < 2e-16 ***
ecpm -0.4431471 0.0096228 -46.052 < 2e-16 ***
position -0.5974681 0.0056986 -104.844 < 2e-16 ***
weekday.MON 0.0428716 0.0182530 2.349 0.018837 *
weekday.FRI 0.0679309 0.0200902 3.381 0.000721 ***
weekday.SUN 0.6340413 0.0209855 30.213 < 2e-16 ***
weekday.TUE 0.0090771 0.0183994 0.493 0.621777
weekday.THU -0.0262560 0.0192433 -1.364 0.172436
weekday.SAT 0.5322960 0.0210327 25.308 < 2e-16 ***
state.f38822b3 -0.4944600 0.0278503 -17.754 < 2e-16 ***
state.4bdb89dd -0.4259786 0.0329094 -12.944 < 2e-16 ***
state.92600ee5 -0.6905151 0.0270756 -25.503 < 2e-16 ***
state.bf0f3c8c -0.3701961 0.0344010 -10.761 < 2e-16 ***
state.f04eaa4b -0.6774949 0.0268554 -25.228 < 2e-16 ***
state.a8283dd2 -0.0056743 0.0293590 -0.193 0.846746
state.dd26f5e6 0.2249447 0.0323901 6.945 3.79e-12 ***
state.c43dc4a7 -0.4785729 0.0309811 -15.447 < 2e-16 ***
state.63d0870f -0.1184034 0.0382737 -3.094 0.001977 **
state.77d6b684 -0.4972242 0.0306970 -16.198 < 2e-16 ***
state.8ab3223a 0.2078498 0.0367659 5.653 1.57e-08 ***
state.26e1d51b -0.6091662 0.0316434 -19.251 < 2e-16 ***
state.92676321 -0.0128167 0.0312440 -0.410 0.681649
state.d1f48576 0.5986194 0.0341215 17.544 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 383615 on 1225773 degrees of freedom
Residual deviance: 312629 on 1225746 degrees of freedom
AIC: 312685
Number of Fisher Scoring iterations: 8
Ahora con la infomracion proporcionada por el modelo general, eliminaremos las variables que son menos significativas:
Ahora eliminamos las observaciones ‘MON’, ‘TUE’ y ‘WED’ para la variable weekday ademas eliminamos las observaciones ‘a8283dd2’, ‘92676321’
Logit_model2<-
glm(formula=click ~ src + hour + placement + cpc
+ ctr + ecpm + position + weekday.FRI + weekday.SUN +
weekday.SAT + state.f38822b3 + state.4bdb89dd + state.92600ee5 +
state.bf0f3c8c + state.f04eaa4b + state.dd26f5e6 + state.c43dc4a7 + state.63d0870f + state.77d6b684 + state.8ab3223a + state.26e1d51b + state.d1f48576
, data=train_dataset, family = binomial(link="logit"))
glm.fit: fitted probabilities numerically 0 or 1 occurred
summary(Logit_model2)
Call:
glm(formula = click ~ src + hour + placement + cpc + ctr + ecpm +
position + weekday.FRI + weekday.SUN + weekday.SAT + state.f38822b3 +
state.4bdb89dd + state.92600ee5 + state.bf0f3c8c + state.f04eaa4b +
state.dd26f5e6 + state.c43dc4a7 + state.63d0870f + state.77d6b684 +
state.8ab3223a + state.26e1d51b + state.d1f48576, family = binomial(link = "logit"),
data = train_dataset)
Deviance Residuals:
Min 1Q Median 3Q Max
-8.4904 -0.2747 -0.1666 -0.0988 3.6889
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -3.6196518 0.0214054 -169.100 < 2e-16 ***
src -0.0007795 0.0001651 -4.722 2.33e-06 ***
hour -0.0245630 0.0007840 -31.329 < 2e-16 ***
placement 1.3917827 0.0127512 109.149 < 2e-16 ***
cpc 0.4064843 0.0071135 57.142 < 2e-16 ***
ctr 17.1695170 0.2393922 71.721 < 2e-16 ***
ecpm -0.4428990 0.0096174 -46.052 < 2e-16 ***
position -0.5975813 0.0056983 -104.871 < 2e-16 ***
weekday.FRI 0.0598121 0.0163981 3.647 0.000265 ***
weekday.SUN 0.6257532 0.0174566 35.846 < 2e-16 ***
weekday.SAT 0.5239950 0.0175186 29.911 < 2e-16 ***
state.f38822b3 -0.4874646 0.0198263 -24.587 < 2e-16 ***
state.4bdb89dd -0.4197283 0.0264956 -15.841 < 2e-16 ***
state.92600ee5 -0.6834597 0.0188096 -36.336 < 2e-16 ***
state.bf0f3c8c -0.3639665 0.0283250 -12.850 < 2e-16 ***
state.f04eaa4b -0.6709813 0.0184795 -36.309 < 2e-16 ***
state.dd26f5e6 0.2315773 0.0257916 8.979 < 2e-16 ***
state.c43dc4a7 -0.4723663 0.0240602 -19.633 < 2e-16 ***
state.63d0870f -0.1118275 0.0329002 -3.399 0.000676 ***
state.77d6b684 -0.4906320 0.0236883 -20.712 < 2e-16 ***
state.8ab3223a 0.2140548 0.0311225 6.878 6.08e-12 ***
state.26e1d51b -0.6029681 0.0249212 -24.195 < 2e-16 ***
state.d1f48576 0.6048629 0.0279122 21.670 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 383615 on 1225773 degrees of freedom
Residual deviance: 312643 on 1225751 degrees of freedom
AIC: 312689
Number of Fisher Scoring iterations: 8
Al parecer todas estas variables son significativas, por lo que haremos una predicción.
Logit_Predict_LM2<-predict(Logit_model2, newdata=test_dataset, type="response")
Logit_Predict_LM2<-data.frame(Logit_Predict_LM2)
nrow(test_dataset)
[1] 525331
nrow(Logit_Predict_LM2)
[1] 525331
Logit_Predict_LM2
Compare_LM2_dataset<-data.frame("observacion" = test_dataset$click,
"Probabilidad" = Logit_Predict_LM2$Logit_Predict_LM2,
"Prediccion" = ifelse(Logit_Predict_LM2$Logit_Predict_LM2 >=0.1,1,0))
Compare_LM2_dataset
Análisis de Rendimiento
countYes <- 0
countNo <- 0
TotalYes <- 0
TotalNo <- 0
countNoFail<-0
countYesFail<-0
for(i in 1:nrow(Compare_LM2_dataset)) {
if(Compare_LM2_dataset$observacion[i] == 0){
if(Compare_LM2_dataset$Prediccion[i] == 0){
countNo <- countNo + 1
} else {
countNoFail <- countNoFail + 1
}
}
if(Compare_LM2_dataset$observacion[i] == 1){
TotalYes<-TotalYes + 1
if(Compare_LM2_dataset$Prediccion[i] == 1){
countYes <- countYes + 1
}else {
countYesFail <- countYesFail + 1
}
}
}
TotalNo <- countNo + countNoFail
TotalYes <- countYes + countYesFail
countYes/TotalYes
[1] 0.5806418
countNo/TotalNo
[1] 0.849926
LS0tDQp0aXRsZTogJ1Byb3llY3RvICMxIC0gUHJlZGljY2nzbiBkZSBDbGlja3MnDQphdXRob3I6ICJQcmVuZyBCaWJhIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShtbGJlbmNoKQ0KbGlicmFyeShjYVRvb2xzKQ0KYGBgDQoNCmBgYHtyfQ0KI0NhcmdhbW9zIERhdGENCmxvYWQoImRhdGFfcHJveWVjdG8ucmRhIikNCm5hbWVzKHRyYWluKQ0KYGBgDQoNCiMjIFNodWZsZSBkZSBkYXRvcw0KYGBge3J9DQojTWV4Y2xhbW9zIGxvcyBkYXRvcyBwYXJhIGZvcm1hciBkb3MgZGF0YSBzZXRzOiBlbnRyZW5hbWllbnRvIHkgcHJ1ZWJhLg0KaW5kZXg8LTE6bnJvdyh0cmFpbikNCnNodWZmX2luZGV4PC1zYW1wbGUoaW5kZXgpDQpkYXRhc2V0PC10cmFpbltzaHVmZl9pbmRleCxdICNEYXRhIEZyYW1lIGRlc29yZGVuYWRvLg0KYGBgDQoNCiMjIEdlbmVyYW1vcyBkYXRvcyBwYXJhIGVudHJlbmFtaWVudG8geSBwcnVlYmFzDQpgYGB7cn0NCnRyYWluX2RhdGFzZXQ8LWRhdGFzZXRbMTooMC43Km5yb3coZGF0YXNldCkpLF0gI3N1YmRhdGFzZXQgZGUgZW50cmVuYW1pZW50by4NCnRlc3RfZGF0YXNldDwtZGF0YXNldFsoMC43Km5yb3coZGF0YXNldCkrMSk6IG5yb3coZGF0YXNldCksXSAjc3ViZGF0YXNldCBkZSBwcnVlYmEuDQpgYGANCg0KYGBge3J9DQpoZWFkKHRlc3RfZGF0YXNldCkNCmBgYA0KDQoNCiMjIyBBcnJlZ2xvcyBhIGRhdGFzZXQgZGUgZW50cmVuYW1pZW50bzoNCg0KYGBge3IsIH0NCnRyYWluX2RhdGFzZXQkY2xpY2s8LWFzLm51bWVyaWModHJhaW5fZGF0YXNldCRjbGljaykNCnRyYWluX2RhdGFzZXQkc3JjPC1hcy5udW1lcmljKHRyYWluX2RhdGFzZXQkc3JjKQ0KDQp0cmFpbl9kYXRhc2V0JGNwYzwtYXMudmVjdG9yKHRyYWluX2RhdGFzZXQkY3BjKQ0KdHJhaW5fZGF0YXNldCRlY3BtPC1hcy52ZWN0b3IodHJhaW5fZGF0YXNldCRlY3BtKQ0KYGBgDQoNCiMjIyBDcmVhbW9zIFZhcmlibGVzIENhdGVn83JpY2FzIHBhcmEgc2V0IGRlIGRhdG9zIGRlIGVudHJlbmFtaWVudG8NCmBgYHtyfQ0KdHJhaW5fZGF0YXNldCRwbGFjZW1lbnQ8LWlmZWxzZSh0cmFpbl9kYXRhc2V0JHBsYWNlbWVudCA9PSAiQSIsIDAsIDEpDQojQ3JlYW1vcyBkZSB2YXJpYWJsZXMgY2F0ZWfzdGljYXMNCg0KI3dlZWtkYXkNCnRyYWluX2RhdGFzZXQ8LXRyYWluX2RhdGFzZXQgJT4lIA0KICBtdXRhdGUod2Vla2RheS5UVUUgPSBpZmVsc2Uod2Vla2RheSA9PSAiVFVFIiwgMSwgMCkpICU+JQ0KICBtdXRhdGUod2Vla2RheS5USFUgPSBpZmVsc2Uod2Vla2RheSA9PSAiVEhVIiwgMSwgMCkpICU+JSANCiAgbXV0YXRlKHdlZWtkYXkuU1VOID0gaWZlbHNlKHdlZWtkYXkgPT0gIlNVTiIsIDEsIDApKSAlPiUNCiAgbXV0YXRlKHdlZWtkYXkuRlJJID0gaWZlbHNlKHdlZWtkYXkgPT0gIkZSSSIsIDEsIDApKSAlPiUNCiAgbXV0YXRlKHdlZWtkYXkuU0FUID0gaWZlbHNlKHdlZWtkYXkgPT0gIlNBVCIsIDEsIDApKSAlPiUNCiAgbXV0YXRlKHdlZWtkYXkuV0VEID0gaWZlbHNlKHdlZWtkYXkgPT0gIldFRCIsIDEsIDApKSAlPiUNCiAgbXV0YXRlKHdlZWtkYXkuTU9OPSBpZmVsc2Uod2Vla2RheSA9PSAiTU9OIiwgMSwgMCkpIA0KICANCnRyYWluX2RhdGFzZXQ8LXRyYWluX2RhdGFzZXQgJT4lIA0KICAgbXV0YXRlKHN0YXRlLjc3ZDZiNjg0ID0gaWZlbHNlKHN0YXRlID09ICI3N2Q2YjY4NCIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS45N2U0ZTdiNyA9IGlmZWxzZShzdGF0ZSA9PSAiOTdlNGU3YjciLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuNGJkYjg5ZGQgPSBpZmVsc2Uoc3RhdGUgPT0gIjRiZGI4OWRkIiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLmYzODgyMmIzID0gaWZlbHNlKHN0YXRlID09ICJmMzg4MjJiMyIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS5mMDRlYWE0YiA9IGlmZWxzZShzdGF0ZSA9PSAiZjA0ZWFhNGIiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuOTI2NzYzMjEgPSBpZmVsc2Uoc3RhdGUgPT0gIjkyNjc2MzIxIiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLjI2ZTFkNTFiID0gaWZlbHNlKHN0YXRlID09ICIyNmUxZDUxYiIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS45MjYwMGVlNSA9IGlmZWxzZShzdGF0ZSA9PSAiOTI2MDBlZTUiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuZGQyNmY1ZTYgPSBpZmVsc2Uoc3RhdGUgPT0gImRkMjZmNWU2IiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLmE4MjgzZGQyID0gaWZlbHNlKHN0YXRlID09ICJhODI4M2RkMiIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS44YWIzMjIzYSA9IGlmZWxzZShzdGF0ZSA9PSAiOGFiMzIyM2EiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuNjNkMDg3MGYgPSBpZmVsc2Uoc3RhdGUgPT0gIjYzZDA4NzBmIiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLmM0M2RjNGE3ID0gaWZlbHNlKHN0YXRlID09ICJjNDNkYzRhNyIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS5iZjBmM2M4YyA9IGlmZWxzZShzdGF0ZSA9PSAiYmYwZjNjOGMiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuZDFmNDg1NzYgPSBpZmVsc2Uoc3RhdGUgPT0gImQxZjQ4NTc2IiwgMSwgMCkpDQoNCiNwcm92aWRlciBuYW1lDQp0cmFpbl9kYXRhc2V0PC10cmFpbl9kYXRhc2V0ICU+JSANCiAgIG11dGF0ZShwcm92aWRlcl9uYW1lLmI5ODVhNmM2ID0gaWZlbHNlKHN0YXRlID09ICJiOTg1YTZjNiIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShwcm92aWRlcl9uYW1lLmFmOGUxMTVmID0gaWZlbHNlKHN0YXRlID09ICJhZjhlMTE1ZiIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShwcm92aWRlcl9uYW1lLmQ4ODZkZWQgPSBpZmVsc2Uoc3RhdGUgPT0gImQ4ODZkZWQiLCAxLCAwKSkNCg0KDQpgYGANCg0KIyMjIEFycmVnbG9zIGEgZGF0YXNldCBkZSBwcnVlYmE6DQpgYGB7cn0NCiNBcnJlZ2xvcyBhIGRhdGFzZXQgZGUgcHJ1ZWJhDQp0ZXN0X2RhdGFzZXQkY2xpY2s8LWFzLm51bWVyaWModGVzdF9kYXRhc2V0JGNsaWNrKQ0KdGVzdF9kYXRhc2V0JHNyYzwtYXMubnVtZXJpYyh0ZXN0X2RhdGFzZXQkc3JjKQ0KDQp0ZXN0X2RhdGFzZXQkY3BjPC1hcy52ZWN0b3IodGVzdF9kYXRhc2V0JGNwYykNCnRlc3RfZGF0YXNldCRlY3BtPC1hcy52ZWN0b3IodGVzdF9kYXRhc2V0JGVjcG0pDQoNCnRlc3RfZGF0YXNldCRwbGFjZW1lbnQ8LWlmZWxzZSh0ZXN0X2RhdGFzZXQkcGxhY2VtZW50ID09ICJBIiwgMCwgMSkNCg0KYGBgDQoNCiMjIyBDcmVhbW9zIFZhcmlibGVzIENhdGVn83JpY2FzIHBhcmEgc2V0IGRlIGRhdG9zIGRlIHBydWViYQ0KYGBge3J9DQp0ZXN0X2RhdGFzZXQkcGxhY2VtZW50PC1pZmVsc2UodGVzdF9kYXRhc2V0JHBsYWNlbWVudCA9PSAiQSIsIDAsIDEpDQojQ3JlYW1vcyBkZSB2YXJpYWJsZXMgY2F0ZWfzdGljYXMNCg0KI3dlZWtkYXkNCnRlc3RfZGF0YXNldDwtdGVzdF9kYXRhc2V0ICU+JSANCiAgbXV0YXRlKHdlZWtkYXkuVFVFID0gaWZlbHNlKHdlZWtkYXkgPT0gIlRVRSIsIDEsIDApKSAlPiUNCiAgbXV0YXRlKHdlZWtkYXkuVEhVID0gaWZlbHNlKHdlZWtkYXkgPT0gIlRIVSIsIDEsIDApKSAlPiUgDQogIG11dGF0ZSh3ZWVrZGF5LlNVTiA9IGlmZWxzZSh3ZWVrZGF5ID09ICJTVU4iLCAxLCAwKSkgJT4lDQogIG11dGF0ZSh3ZWVrZGF5LkZSSSA9IGlmZWxzZSh3ZWVrZGF5ID09ICJGUkkiLCAxLCAwKSkgJT4lDQogIG11dGF0ZSh3ZWVrZGF5LlNBVCA9IGlmZWxzZSh3ZWVrZGF5ID09ICJTQVQiLCAxLCAwKSkgJT4lDQogIG11dGF0ZSh3ZWVrZGF5LldFRCA9IGlmZWxzZSh3ZWVrZGF5ID09ICJXRUQiLCAxLCAwKSkgJT4lDQogIG11dGF0ZSh3ZWVrZGF5Lk1PTj0gaWZlbHNlKHdlZWtkYXkgPT0gIk1PTiIsIDEsIDApKSANCiAgDQp0ZXN0X2RhdGFzZXQ8LXRlc3RfZGF0YXNldCAlPiUgDQogICBtdXRhdGUoc3RhdGUuNzdkNmI2ODQgPSBpZmVsc2Uoc3RhdGUgPT0gIjc3ZDZiNjg0IiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLjk3ZTRlN2I3ID0gaWZlbHNlKHN0YXRlID09ICI5N2U0ZTdiNyIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS40YmRiODlkZCA9IGlmZWxzZShzdGF0ZSA9PSAiNGJkYjg5ZGQiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuZjM4ODIyYjMgPSBpZmVsc2Uoc3RhdGUgPT0gImYzODgyMmIzIiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLmYwNGVhYTRiID0gaWZlbHNlKHN0YXRlID09ICJmMDRlYWE0YiIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS45MjY3NjMyMSA9IGlmZWxzZShzdGF0ZSA9PSAiOTI2NzYzMjEiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuMjZlMWQ1MWIgPSBpZmVsc2Uoc3RhdGUgPT0gIjI2ZTFkNTFiIiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLjkyNjAwZWU1ID0gaWZlbHNlKHN0YXRlID09ICI5MjYwMGVlNSIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS5kZDI2ZjVlNiA9IGlmZWxzZShzdGF0ZSA9PSAiZGQyNmY1ZTYiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuYTgyODNkZDIgPSBpZmVsc2Uoc3RhdGUgPT0gImE4MjgzZGQyIiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLjhhYjMyMjNhID0gaWZlbHNlKHN0YXRlID09ICI4YWIzMjIzYSIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS42M2QwODcwZiA9IGlmZWxzZShzdGF0ZSA9PSAiNjNkMDg3MGYiLCAxLCAwKSkgJT4lDQogICBtdXRhdGUoc3RhdGUuYzQzZGM0YTcgPSBpZmVsc2Uoc3RhdGUgPT0gImM0M2RjNGE3IiwgMSwgMCkpICU+JQ0KICAgbXV0YXRlKHN0YXRlLmJmMGYzYzhjID0gaWZlbHNlKHN0YXRlID09ICJiZjBmM2M4YyIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShzdGF0ZS5kMWY0ODU3NiA9IGlmZWxzZShzdGF0ZSA9PSAiZDFmNDg1NzYiLCAxLCAwKSkNCg0KI3Byb3ZpZGVyIG5hbWUNCnRlc3RfZGF0YXNldDwtdGVzdF9kYXRhc2V0ICU+JSANCiAgIG11dGF0ZShwcm92aWRlcl9uYW1lLmI5ODVhNmM2ID0gaWZlbHNlKHN0YXRlID09ICJiOTg1YTZjNiIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShwcm92aWRlcl9uYW1lLmFmOGUxMTVmID0gaWZlbHNlKHN0YXRlID09ICJhZjhlMTE1ZiIsIDEsIDApKSAlPiUNCiAgIG11dGF0ZShwcm92aWRlcl9uYW1lLmQ4ODZkZWQgPSBpZmVsc2Uoc3RhdGUgPT0gImQ4ODZkZWQiLCAxLCAwKSkNCmBgYA0KDQoNCiMjIyBNb2RlbG8gZGUgcmVncmVzafNuIGxvZ2lzdGljYSBjb24gdG9kYXMgbGFzIHZhcmlhdmJsZSwgZXhjZXB0byAnemlwJyB5ICdicmFuZF9uYW1lJyB5YSBxdWUgc29uIGRlbWFjaWFkYXMgdmFyaWFibGVzIGNhdGVnb3JpY2FzOg0KYGBge3IsfQ0KI05vIHVzYXJlbW9zIGxhIHZhcmFpYmxlIHppcCBuaSBicmFuZF9uYW1lIHBvciBxdWUgc29uIGRlbWFjaWFkb3MgZWxlbWVudG9zIGRpZmVyZW50ZXMuDQoNCkxvZ2l0X21vZGVsMTwtDQogIGdsbShmb3JtdWxhPWNsaWNrIH4gc3JjICsgaG91ciArICBwbGFjZW1lbnQgKyBjcGMNCiAgICAgICsgY3RyICsgZWNwbSArIHBvc2l0aW9uICsgd2Vla2RheS5NT04gKyB3ZWVrZGF5LkZSSSArIHdlZWtkYXkuU1VOICsgd2Vla2RheS5UVUUgKyANCiAgICAgIHdlZWtkYXkuVEhVICsgd2Vla2RheS5TQVQgKyBzdGF0ZS5mMzg4MjJiMyArIHN0YXRlLjRiZGI4OWRkICsgc3RhdGUuOTI2MDBlZTUgKyANCiAgICAgICAgc3RhdGUuYmYwZjNjOGMgKyBzdGF0ZS5mMDRlYWE0YiArIHN0YXRlLmE4MjgzZGQyICsgc3RhdGUuZGQyNmY1ZTYgKyAgICBzdGF0ZS5jNDNkYzRhNyArIHN0YXRlLjYzZDA4NzBmICsgc3RhdGUuNzdkNmI2ODQgKyBzdGF0ZS44YWIzMjIzYSArIHN0YXRlLjI2ZTFkNTFiICsgc3RhdGUuOTI2NzYzMjEgKyBzdGF0ZS5kMWY0ODU3NiANCiAgICAgICAgLCBkYXRhPXRyYWluX2RhdGFzZXQsIGZhbWlseSA9IGJpbm9taWFsKGxpbms9ImxvZ2l0IikpDQoNCnN1bW1hcnkoTG9naXRfbW9kZWwxKQ0KYGBgDQojIyBBaG9yYSBjb24gbGEgaW5mb21yYWNpb24gcHJvcG9yY2lvbmFkYSBwb3IgZWwgbW9kZWxvIGdlbmVyYWwsIGVsaW1pbmFyZW1vcyBsYXMgdmFyaWFibGVzIHF1ZSBzb24gbWVub3Mgc2lnbmlmaWNhdGl2YXM6DQoNCiMjIyBBaG9yYSBlbGltaW5hbW9zIGxhcyBvYnNlcnZhY2lvbmVzICdNT04nLCAnVFVFJyB5ICdXRUQnIHBhcmEgbGEgdmFyaWFibGUgd2Vla2RheSBhZGVtYXMgZWxpbWluYW1vcyBsYXMgb2JzZXJ2YWNpb25lcyAnYTgyODNkZDInLCAnOTI2NzYzMjEnDQoNCmBgYHtyfQ0KTG9naXRfbW9kZWwyPC0NCiAgZ2xtKGZvcm11bGE9Y2xpY2sgfiBzcmMgKyBob3VyICsgIHBsYWNlbWVudCArIGNwYw0KICAgICAgKyBjdHIgKyBlY3BtICsgcG9zaXRpb24gKyB3ZWVrZGF5LkZSSSArIHdlZWtkYXkuU1VOICsgDQogICAgICB3ZWVrZGF5LlNBVCArIHN0YXRlLmYzODgyMmIzICsgc3RhdGUuNGJkYjg5ZGQgKyBzdGF0ZS45MjYwMGVlNSArIA0KICAgICAgICBzdGF0ZS5iZjBmM2M4YyArIHN0YXRlLmYwNGVhYTRiICArIHN0YXRlLmRkMjZmNWU2ICsgICAgc3RhdGUuYzQzZGM0YTcgKyBzdGF0ZS42M2QwODcwZiArIHN0YXRlLjc3ZDZiNjg0ICsgc3RhdGUuOGFiMzIyM2EgKyBzdGF0ZS4yNmUxZDUxYiArIHN0YXRlLmQxZjQ4NTc2IA0KICAgICAgICAsIGRhdGE9dHJhaW5fZGF0YXNldCwgZmFtaWx5ID0gYmlub21pYWwobGluaz0ibG9naXQiKSkNCg0Kc3VtbWFyeShMb2dpdF9tb2RlbDIpDQpgYGANCiMjIyBBbCBwYXJlY2VyIHRvZGFzIGVzdGFzIHZhcmlhYmxlcyBzb24gc2lnbmlmaWNhdGl2YXMsIHBvciBsbyBxdWUgaGFyZW1vcyB1bmEgcHJlZGljY2nzbi4NCg0KYGBge3J9DQpMb2dpdF9QcmVkaWN0X0xNMjwtcHJlZGljdChMb2dpdF9tb2RlbDIsIG5ld2RhdGE9dGVzdF9kYXRhc2V0LCB0eXBlPSJyZXNwb25zZSIpDQoNCkxvZ2l0X1ByZWRpY3RfTE0yPC1kYXRhLmZyYW1lKExvZ2l0X1ByZWRpY3RfTE0yKQ0KDQpucm93KHRlc3RfZGF0YXNldCkNCm5yb3coTG9naXRfUHJlZGljdF9MTTIpDQoNCkxvZ2l0X1ByZWRpY3RfTE0yDQoNCkNvbXBhcmVfTE0yX2RhdGFzZXQ8LWRhdGEuZnJhbWUoIm9ic2VydmFjaW9uIiA9IHRlc3RfZGF0YXNldCRjbGljaywgDQogICAgICAgICAgICAgICAgICAiUHJvYmFiaWxpZGFkIiA9IExvZ2l0X1ByZWRpY3RfTE0yJExvZ2l0X1ByZWRpY3RfTE0yLA0KICAgICAgICAgICAgICAgICAgIlByZWRpY2Npb24iID0gaWZlbHNlKExvZ2l0X1ByZWRpY3RfTE0yJExvZ2l0X1ByZWRpY3RfTE0yID49MC4xLDEsMCkpDQoNCkNvbXBhcmVfTE0yX2RhdGFzZXQNCmBgYA0KIyMjIEFu4Wxpc2lzIGRlIFJlbmRpbWllbnRvDQpgYGB7cn0NCmNvdW50WWVzIDwtIDANCmNvdW50Tm8gPC0gMA0KDQpUb3RhbFllcyA8LSAwDQpUb3RhbE5vIDwtIDANCiAgDQpjb3VudE5vRmFpbDwtMA0KY291bnRZZXNGYWlsPC0wDQoNCmZvcihpIGluIDE6bnJvdyhDb21wYXJlX0xNMl9kYXRhc2V0KSkgew0KICBpZihDb21wYXJlX0xNMl9kYXRhc2V0JG9ic2VydmFjaW9uW2ldID09IDApew0KICAgIGlmKENvbXBhcmVfTE0yX2RhdGFzZXQkUHJlZGljY2lvbltpXSA9PSAwKXsNCiAgICAgIGNvdW50Tm8gPC0gY291bnRObyArIDENCiAgICB9IGVsc2Ugew0KICAgICAgY291bnROb0ZhaWwgPC0gY291bnROb0ZhaWwgKyAxDQogICAgfQ0KICB9DQogIA0KICAgaWYoQ29tcGFyZV9MTTJfZGF0YXNldCRvYnNlcnZhY2lvbltpXSA9PSAxKXsNCiAgICAgVG90YWxZZXM8LVRvdGFsWWVzICsgMQ0KICAgIGlmKENvbXBhcmVfTE0yX2RhdGFzZXQkUHJlZGljY2lvbltpXSA9PSAxKXsNCiAgICAgIGNvdW50WWVzIDwtIGNvdW50WWVzICsgMQ0KICAgIH1lbHNlIHsNCiAgICAgIGNvdW50WWVzRmFpbCA8LSBjb3VudFllc0ZhaWwgKyAxDQogICAgfQ0KICAgfQ0KfQ0KVG90YWxObyA8LSBjb3VudE5vICsgY291bnROb0ZhaWwNClRvdGFsWWVzIDwtIGNvdW50WWVzICsgY291bnRZZXNGYWlsDQoNCg0KY291bnRZZXMvVG90YWxZZXMNCmNvdW50Tm8vVG90YWxObw0KYGBgDQoNCg0KDQoNCg==