Paula Cazali

En este proyecto se analizará un dataset sobre partidos de futbol, en especifico de la UEFA Champeons League.

Cargando librerias y dataset

library(dplyr)
library(ggplot2)
library(readr)
partidos <- read_csv("spi_matches.csv")

Como todo el dataset es sobre distintos equipos de futbol primero necesitamos obtener solo donde están los partidos de la UEFA Champions League:

uefa <-
partidos %>% 
  filter(league == "UEFA Champions League")

Por lo que el dataset quedaría de la siguiente forma:

head(uefa)

En el datasest hay algunas columnas que no se necesitan para hacer la predicción, por lo que podemos eliminar esas columnas que en este caso serían: la fecha en la cual se realizó el partido, la liga a la que pertenecen, ya que sabemos que todos los partidos son de la UEFA Champeons League, el id de liga, y otras variables que no tienen información relevante en el dataset. También eliminaremos las filas que no tengan dato en alguna de las columnas.

uefa <-
uefa %>% 
  select(-date, -league_id, -league, -importance1, -importance2) %>% 
  filter(xg1 != "NA") %>% 
  filter(xg2 != "NA")

Por lo que el dataset se vería asi:

head(uefa)

Cambiaremos los nombres de las columnas del dataset para poder tener mejor visión de los equipos locales y los visitantes y sus respectivas observaciones.

colnames(uefa) <- c("local", "visit", "spi_local", "spi_visit", "prob_local", "prob_visit", "probtie", "proj_score1", "proj_score2", "score_local", "score_visit", "xg_local", "xg_visit", "nsxg_local", "nsxg_visit", "adj_score1", "adj_score2")
head(uefa)

A continuación se obtendrán los partidos totales definidos a favor de los locales, los definidos a favor de los visitantes y los empates y se graficarán

Total de partidos jugados como locales:

partidos_local <-
uefa %>% 
  mutate(cnt = 1) %>% 
  group_by(local) %>% 
  summarise(partidos_local = sum(cnt))
partidos_local

Total de partidos jugados como visitantes:

partidos_visit <-
uefa %>%
  mutate(cnt = 1) %>% 
  group_by(visit) %>% 
  summarise(partidos_visit = sum(cnt))
partidos_visit

Partidos definidos a favor de los locales, a favor de los visitantes y partidos en empate:

Graficando:

Total_Win %>% 
  ggplot(aes(x=Partidos,y=total_wins))+
  geom_bar(stat = "identity", fill = c("blue", "green", "red")) +
  ggtitle("Partidos definidos como locales, visitantes y empates") + 
  labs(x = "Partidos") + 
  labs(y = "Total")

En esa gráfica se puede apreciar que hay más partidos ganados si se juega de local que si se juega de visitante, para cualquier equipo en la UEFA Champeons League.

Modelo

Se dividirá el dataset en 70% para el modelo de predicción y el 30% para las pruebas del modelo.

uefa.train <- uefa[1:(0.7*(nrow(uefa))), ]
uefa.test <- uefa[(0.7*(nrow(uefa))):nrow(uefa), ]

Introducimos la variable Win1 para los partidos ganados locales y la variable Win2 para los ganados por los visitantes. Un “1” significa que lo ganó y un “0” puede significar que lo perdió o que lo empató.

uefa.train$Win1 <- ifelse((uefa.train$score_local > uefa.train$score_visit), 1, 0)
uefa.train$Win2 <- ifelse((uefa.train$score_visit > uefa.train$score_local), 1, 0)
uefa.test$Win1 <- ifelse((uefa.test$score_local > uefa.test$score_visit), 1, 0)
uefa.test$Win2 <- ifelse((uefa.test$score_visit > uefa.test$score_local), 1, 0)

Para los locales

Regresión binomial tipo logística para predecir la variable Win1 (Si gana o no el partido), en base a los goles esperados de los locales.

logit_reg <- glm(formula = Win1 ~ xg_local, 
                 family = binomial(link = "logit"),
                 data = uefa.train)
summary(logit_reg)

Call:
glm(formula = Win1 ~ xg_local, family = binomial(link = "logit"), 
    data = uefa.train)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-2.3520  -0.8320  -0.5038   0.9089   1.9864  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)  -2.4363     0.3452  -7.057 1.70e-12 ***
xg_local      1.3627     0.1969   6.921 4.48e-12 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 331.07  on 240  degrees of freedom
Residual deviance: 256.91  on 239  degrees of freedom
AIC: 260.91

Number of Fisher Scoring iterations: 4
exp_goals1 <- seq(min(uefa.train$xg_local), max(uefa.train$xg_local), 0.05)
prediccion <- predict(object = logit_reg, 
                newdata = list(xg_local = exp_goals1),
                type = "response")
graph_predict <- data.frame(exp_goals1, prediccion)
colnames(graph_predict) <- c("Expected_Goals", "Probabilidad")

Gráfica del Modelo para locales

ggplot(data = graph_predict, aes(x = Expected_Goals, y = Probabilidad)) + 
  geom_line(color = "blue", size = 1) + 
  ggtitle("Modelo para Locales - Regresión Logística") +
  labs(x = "Expected Goals") + 
  labs(y = "Probabilidad") +
  theme_minimal()

Modelo con datos del dataset de pruebas

prediccion_test <- predict(object = logit_reg,
                         newdata = uefa.test,
                         type="response")
aux <- data.frame(Win = uefa.test$Win1, Probabilidad = prediccion_test)
uefa.results1 <- data.frame(Local = uefa.test$local, as.data.frame(aux))
  
uefa.results1

Para los visitantes

Regresión binomial tipo logística para predecir la variable Win2 (Si gana o no el partido), en base a los goles esperados de los visitantes.

logit_reg2 <- glm(formula = Win2 ~ xg_visit, 
                 family = binomial(link = "logit"),
                 data = uefa.train)
summary(logit_reg2)

Call:
glm(formula = Win2 ~ xg_visit, family = binomial(link = "logit"), 
    data = uefa.train)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.7648  -0.8087  -0.5242   0.9814   2.0532  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)  -2.5427     0.3385  -7.512 5.84e-14 ***
xg_visit      1.2543     0.2060   6.090 1.13e-09 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 301.97  on 240  degrees of freedom
Residual deviance: 249.64  on 239  degrees of freedom
AIC: 253.64

Number of Fisher Scoring iterations: 4
exp_goals2 <- seq(min(uefa.train$xg_visit), max(uefa.train$xg_visit), 0.05)
prediccion2 <- predict(object = logit_reg2, 
                newdata = list(xg_visit = exp_goals2),
                type = "response")
graph_predict2 <- data.frame(exp_goals2, prediccion2)
colnames(graph_predict2) <- c("Expected_Goals", "Probabilidad")

Gráfica del Modelo para visitantes

ggplot(data = graph_predict2, aes(x = Expected_Goals, y = Probabilidad)) + 
  geom_line(color = "blue", size = 1) + 
  ggtitle("Modelo para Visitantes - Regresión Logística") +
  labs(x = "Expected Goals") + 
  labs(y = "Probabilidad") +
  theme_minimal()

Modelo con datos del dataset de pruebas

prediccion2_test <- predict(object = logit_reg2,
                         newdata = uefa.test,
                         type="response")
aux2 <- data.frame(Win = uefa.test$Win2, Probabilidad = prediccion2_test)
uefa.results2 <- data.frame(Visitante = uefa.test$visit, as.data.frame(aux2))
  
uefa.results2

Conclusiones

En el análisis de estos datos usando la variable de goles esperados podemos ver que los equipos que juegan de locales tienen más posibilidades de ganar y echar más goles (debido a los goles esperados) que los equipos que juegan de visitantes.

LS0tDQp0aXRsZTogIlByb3llY3RvIEVjb25vbWV0cmlhIDEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMgUGF1bGEgQ2F6YWxpIA0KDQohW10oZ2FsaWxlby5wbmcpDQoNCkVuIGVzdGUgcHJveWVjdG8gc2UgYW5hbGl6YXLDoSB1biBkYXRhc2V0IHNvYnJlIHBhcnRpZG9zIGRlIGZ1dGJvbCwgZW4gZXNwZWNpZmljbyBkZSBsYSBVRUZBIENoYW1wZW9ucyBMZWFndWUuDQoNCkNhcmdhbmRvIGxpYnJlcmlhcyB5IGRhdGFzZXQNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmVhZHIpDQpwYXJ0aWRvcyA8LSByZWFkX2Nzdigic3BpX21hdGNoZXMuY3N2IikNCmBgYA0KDQoNCkNvbW8gdG9kbyBlbCBkYXRhc2V0IGVzIHNvYnJlIGRpc3RpbnRvcyBlcXVpcG9zIGRlIGZ1dGJvbCBwcmltZXJvIG5lY2VzaXRhbW9zIG9idGVuZXIgc29sbyBkb25kZSBlc3TDoW4gbG9zIHBhcnRpZG9zIGRlIGxhIFVFRkEgQ2hhbXBpb25zIExlYWd1ZToNCmBgYHtyfQ0KdWVmYSA8LQ0KcGFydGlkb3MgJT4lIA0KICBmaWx0ZXIobGVhZ3VlID09ICJVRUZBIENoYW1waW9ucyBMZWFndWUiKQ0KYGBgDQoNCg0KUG9yIGxvIHF1ZSBlbCBkYXRhc2V0IHF1ZWRhcsOtYSBkZSBsYSBzaWd1aWVudGUgZm9ybWE6DQpgYGB7cn0NCmhlYWQodWVmYSkNCmBgYA0KDQoNCkVuIGVsIGRhdGFzZXN0IGhheSBhbGd1bmFzIGNvbHVtbmFzIHF1ZSBubyBzZSBuZWNlc2l0YW4gcGFyYSBoYWNlciBsYSBwcmVkaWNjacOzbiwgcG9yIGxvIHF1ZSBwb2RlbW9zIGVsaW1pbmFyIGVzYXMgY29sdW1uYXMgcXVlIGVuIGVzdGUgY2FzbyBzZXLDrWFuOiBsYSBmZWNoYSBlbiBsYSBjdWFsIHNlIHJlYWxpesOzIGVsIHBhcnRpZG8sIGxhIGxpZ2EgYSBsYSBxdWUgcGVydGVuZWNlbiwgeWEgcXVlIHNhYmVtb3MgcXVlIHRvZG9zIGxvcyBwYXJ0aWRvcyBzb24gZGUgbGEgVUVGQSBDaGFtcGVvbnMgTGVhZ3VlLCBlbCBpZCBkZSBsaWdhLCB5IG90cmFzIHZhcmlhYmxlcyBxdWUgbm8gdGllbmVuIGluZm9ybWFjacOzbiByZWxldmFudGUgZW4gZWwgZGF0YXNldC4NClRhbWJpw6luIGVsaW1pbmFyZW1vcyBsYXMgZmlsYXMgcXVlIG5vIHRlbmdhbiBkYXRvIGVuIGFsZ3VuYSBkZSBsYXMgY29sdW1uYXMuDQpgYGB7cn0NCnVlZmEgPC0NCnVlZmEgJT4lIA0KICBzZWxlY3QoLWRhdGUsIC1sZWFndWVfaWQsIC1sZWFndWUsIC1pbXBvcnRhbmNlMSwgLWltcG9ydGFuY2UyKSAlPiUgDQogIGZpbHRlcih4ZzEgIT0gIk5BIikgJT4lIA0KICBmaWx0ZXIoeGcyICE9ICJOQSIpDQpgYGANCg0KDQpQb3IgbG8gcXVlIGVsIGRhdGFzZXQgc2UgdmVyw61hIGFzaToNCmBgYHtyfQ0KaGVhZCh1ZWZhKQ0KYGBgDQoNCkNhbWJpYXJlbW9zIGxvcyBub21icmVzIGRlIGxhcyBjb2x1bW5hcyBkZWwgZGF0YXNldCBwYXJhIHBvZGVyIHRlbmVyIG1lam9yIHZpc2nDs24gZGUgbG9zIGVxdWlwb3MgbG9jYWxlcyB5IGxvcyB2aXNpdGFudGVzIHkgc3VzIHJlc3BlY3RpdmFzIG9ic2VydmFjaW9uZXMuDQpgYGB7cn0NCmNvbG5hbWVzKHVlZmEpIDwtIGMoImxvY2FsIiwgInZpc2l0IiwgInNwaV9sb2NhbCIsICJzcGlfdmlzaXQiLCAicHJvYl9sb2NhbCIsICJwcm9iX3Zpc2l0IiwgInByb2J0aWUiLCAicHJval9zY29yZTEiLCAicHJval9zY29yZTIiLCAic2NvcmVfbG9jYWwiLCAic2NvcmVfdmlzaXQiLCAieGdfbG9jYWwiLCAieGdfdmlzaXQiLCAibnN4Z19sb2NhbCIsICJuc3hnX3Zpc2l0IiwgImFkal9zY29yZTEiLCAiYWRqX3Njb3JlMiIpDQpoZWFkKHVlZmEpDQpgYGANCg0KKiBMYSB2YXJpYWJsZSAic3BpIiBzaWduaWZpY2Egc29jY2VyIHBvd2VyIGluZGV4IGVzIHVuIHJhbmtpbmcgbXVuZGlhbCBkZSBsb3MgZXF1aXBvcyBkZSBmdXRib2wuDQoqIExhIHZhcmliYWxlICJ4ZyIgc2lnbmlmaWNhIGV4cGVjdGVkIGdvYWxzLCBzb24gbG9zIGdvbGVzIGVzcGVyYWRvcyBwb3IgcGFydGUgZGUgY2FkYSBlcXVpcG8uDQoqIExhIHZhcmlhYmxlICJuc3hnIiBzaWduaWZpY2Egbm9uLXNob3QgZXhwZWN0ZWQgZ29hbHMgeSBzb24gbG9zIGdvbGVzIGVzcGVyYWRvcyBubyBsYW56YWRvcy4NCiogWSBsYSB2YXJpYWJsZSAic2NvcmUiIG5vcyBkaWNlIGVsIHJlc3VsdGFkbyBmaW5hbCBkZWwgcGFydGlkby4NCg0KDQojIyMjIEEgY29udGludWFjacOzbiBzZSBvYnRlbmRyw6FuIGxvcyBwYXJ0aWRvcyB0b3RhbGVzIGRlZmluaWRvcyBhIGZhdm9yIGRlIGxvcyBsb2NhbGVzLCBsb3MgZGVmaW5pZG9zIGEgZmF2b3IgZGUgbG9zIHZpc2l0YW50ZXMgeSBsb3MgZW1wYXRlcyB5IHNlIGdyYWZpY2Fyw6FuDQoNClRvdGFsIGRlIHBhcnRpZG9zIGp1Z2Fkb3MgY29tbyBsb2NhbGVzOg0KYGBge3J9DQpwYXJ0aWRvc19sb2NhbCA8LQ0KdWVmYSAlPiUgDQogIG11dGF0ZShjbnQgPSAxKSAlPiUgDQogIGdyb3VwX2J5KGxvY2FsKSAlPiUgDQogIHN1bW1hcmlzZShwYXJ0aWRvc19sb2NhbCA9IHN1bShjbnQpKQ0KcGFydGlkb3NfbG9jYWwNCmBgYA0KDQoNClRvdGFsIGRlIHBhcnRpZG9zIGp1Z2Fkb3MgY29tbyB2aXNpdGFudGVzOg0KYGBge3J9DQpwYXJ0aWRvc192aXNpdCA8LQ0KdWVmYSAlPiUNCiAgbXV0YXRlKGNudCA9IDEpICU+JSANCiAgZ3JvdXBfYnkodmlzaXQpICU+JSANCiAgc3VtbWFyaXNlKHBhcnRpZG9zX3Zpc2l0ID0gc3VtKGNudCkpDQpwYXJ0aWRvc192aXNpdA0KYGBgDQoNCg0KUGFydGlkb3MgZGVmaW5pZG9zIGEgZmF2b3IgZGUgbG9zIGxvY2FsZXMsIGEgZmF2b3IgZGUgbG9zIHZpc2l0YW50ZXMgeSBwYXJ0aWRvcyBlbiBlbXBhdGU6DQpgYGB7cn0NClRvdGFsX1dpbiA8LQ0KdWVmYSAlPiUgDQogIG11dGF0ZShXaW4gPSBpZmVsc2UoKHVlZmEkc2NvcmVfbG9jYWwgPiB1ZWZhJHNjb3JlX3Zpc2l0KSwgYXMuaW50ZWdlcigxKSwgaWZlbHNlKCh1ZWZhJHNjb3JlX3Zpc2l0ID4gdWVmYSRzY29yZV9sb2NhbCksIGFzLmludGVnZXIoMiksIGFzLmludGVnZXIoMykpKSkgJT4lIA0KICBzZWxlY3QoV2luKSAlPiUgDQogIGdyb3VwX2J5KFdpbikgJT4lIA0KICBzdW1tYXJpc2UodG90YWxfY291bnQgPSBzdW0oV2luKSkgJT4lIA0KICBtdXRhdGUoUGFydGlkb3MgPSBjKCJEZWYuIGxvY2FsIiwgIkRlZi52aXNpdCIsICJFbXBhdGUiKSkgJT4lIA0KICBtdXRhdGUodG90YWxfd2lucyA9IHRvdGFsX2NvdW50IC8gV2luKSAlPiUgDQogIHNlbGVjdCgtV2luLCAtdG90YWxfY291bnQpDQoNCmBgYA0KDQpHcmFmaWNhbmRvOg0KYGBge3J9DQpUb3RhbF9XaW4gJT4lIA0KICBnZ3Bsb3QoYWVzKHg9UGFydGlkb3MseT10b3RhbF93aW5zKSkrDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gYygiYmx1ZSIsICJncmVlbiIsICJyZWQiKSkgKw0KICBnZ3RpdGxlKCJQYXJ0aWRvcyBkZWZpbmlkb3MgY29tbyBsb2NhbGVzLCB2aXNpdGFudGVzIHkgZW1wYXRlcyIpICsgDQogIGxhYnMoeCA9ICJQYXJ0aWRvcyIpICsgDQogIGxhYnMoeSA9ICJUb3RhbCIpDQpgYGANCg0KRW4gZXNhIGdyw6FmaWNhIHNlIHB1ZWRlIGFwcmVjaWFyIHF1ZSBoYXkgbcOhcyBwYXJ0aWRvcyBnYW5hZG9zIHNpIHNlIGp1ZWdhIGRlIGxvY2FsIHF1ZSBzaSBzZSBqdWVnYSBkZSB2aXNpdGFudGUsIHBhcmEgY3VhbHF1aWVyIGVxdWlwbyBlbiBsYSBVRUZBIENoYW1wZW9ucyBMZWFndWUuDQoNCg0KIyBNb2RlbG8NCg0KU2UgZGl2aWRpcsOhIGVsIGRhdGFzZXQgZW4gNzAlIHBhcmEgZWwgbW9kZWxvIGRlIHByZWRpY2Npw7NuIHkgZWwgMzAlIHBhcmEgbGFzIHBydWViYXMgZGVsIG1vZGVsby4NCmBgYHtyfQ0KdWVmYS50cmFpbiA8LSB1ZWZhWzE6KDAuNyoobnJvdyh1ZWZhKSkpLCBdDQp1ZWZhLnRlc3QgPC0gdWVmYVsoMC43Kihucm93KHVlZmEpKSk6bnJvdyh1ZWZhKSwgXQ0KYGBgDQoNCg0KSW50cm9kdWNpbW9zIGxhIHZhcmlhYmxlIFdpbjEgcGFyYSBsb3MgcGFydGlkb3MgZ2FuYWRvcyBsb2NhbGVzIHkgbGEgdmFyaWFibGUgV2luMiBwYXJhIGxvcyBnYW5hZG9zIHBvciBsb3MgdmlzaXRhbnRlcy4gVW4gIjEiIHNpZ25pZmljYSBxdWUgbG8gZ2Fuw7MgeSB1biAiMCIgcHVlZGUgc2lnbmlmaWNhciBxdWUgbG8gcGVyZGnDsyBvIHF1ZSBsbyBlbXBhdMOzLg0KYGBge3J9DQp1ZWZhLnRyYWluJFdpbjEgPC0gaWZlbHNlKCh1ZWZhLnRyYWluJHNjb3JlX2xvY2FsID4gdWVmYS50cmFpbiRzY29yZV92aXNpdCksIDEsIDApDQp1ZWZhLnRyYWluJFdpbjIgPC0gaWZlbHNlKCh1ZWZhLnRyYWluJHNjb3JlX3Zpc2l0ID4gdWVmYS50cmFpbiRzY29yZV9sb2NhbCksIDEsIDApDQpgYGANCg0KDQpgYGB7cn0NCnVlZmEudGVzdCRXaW4xIDwtIGlmZWxzZSgodWVmYS50ZXN0JHNjb3JlX2xvY2FsID4gdWVmYS50ZXN0JHNjb3JlX3Zpc2l0KSwgMSwgMCkNCnVlZmEudGVzdCRXaW4yIDwtIGlmZWxzZSgodWVmYS50ZXN0JHNjb3JlX3Zpc2l0ID4gdWVmYS50ZXN0JHNjb3JlX2xvY2FsKSwgMSwgMCkNCmBgYA0KDQoNCiMjIFBhcmEgbG9zIGxvY2FsZXMNClJlZ3Jlc2nDs24gYmlub21pYWwgdGlwbyBsb2fDrXN0aWNhIHBhcmEgcHJlZGVjaXIgbGEgdmFyaWFibGUgV2luMSAoU2kgZ2FuYSBvIG5vIGVsIHBhcnRpZG8pLCBlbiBiYXNlIGEgbG9zIGdvbGVzIGVzcGVyYWRvcyBkZSBsb3MgbG9jYWxlcy4NCmBgYHtyfQ0KbG9naXRfcmVnIDwtIGdsbShmb3JtdWxhID0gV2luMSB+IHhnX2xvY2FsLCANCiAgICAgICAgICAgICAgICAgZmFtaWx5ID0gYmlub21pYWwobGluayA9ICJsb2dpdCIpLA0KICAgICAgICAgICAgICAgICBkYXRhID0gdWVmYS50cmFpbikNCnN1bW1hcnkobG9naXRfcmVnKQ0KYGBgDQoNCmBgYHtyfQ0KZXhwX2dvYWxzMSA8LSBzZXEobWluKHVlZmEudHJhaW4keGdfbG9jYWwpLCBtYXgodWVmYS50cmFpbiR4Z19sb2NhbCksIDAuMDUpDQoNCnByZWRpY2Npb24gPC0gcHJlZGljdChvYmplY3QgPSBsb2dpdF9yZWcsIA0KICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBsaXN0KHhnX2xvY2FsID0gZXhwX2dvYWxzMSksDQogICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpDQoNCmdyYXBoX3ByZWRpY3QgPC0gZGF0YS5mcmFtZShleHBfZ29hbHMxLCBwcmVkaWNjaW9uKQ0KY29sbmFtZXMoZ3JhcGhfcHJlZGljdCkgPC0gYygiRXhwZWN0ZWRfR29hbHMiLCAiUHJvYmFiaWxpZGFkIikNCmBgYA0KDQojIyBHcsOhZmljYSBkZWwgTW9kZWxvIHBhcmEgbG9jYWxlcw0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IGdyYXBoX3ByZWRpY3QsIGFlcyh4ID0gRXhwZWN0ZWRfR29hbHMsIHkgPSBQcm9iYWJpbGlkYWQpKSArIA0KICBnZW9tX2xpbmUoY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAxKSArIA0KICBnZ3RpdGxlKCJNb2RlbG8gcGFyYSBMb2NhbGVzIC0gUmVncmVzacOzbiBMb2fDrXN0aWNhIikgKw0KICBsYWJzKHggPSAiRXhwZWN0ZWQgR29hbHMiKSArIA0KICBsYWJzKHkgPSAiUHJvYmFiaWxpZGFkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyMgTW9kZWxvIGNvbiBkYXRvcyBkZWwgZGF0YXNldCBkZSBwcnVlYmFzDQoNCmBgYHtyfQ0KcHJlZGljY2lvbl90ZXN0IDwtIHByZWRpY3Qob2JqZWN0ID0gbG9naXRfcmVnLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB1ZWZhLnRlc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgdHlwZT0icmVzcG9uc2UiKQ0KYXV4IDwtIGRhdGEuZnJhbWUoV2luID0gdWVmYS50ZXN0JFdpbjEsIFByb2JhYmlsaWRhZCA9IHByZWRpY2Npb25fdGVzdCkNCnVlZmEucmVzdWx0czEgPC0gZGF0YS5mcmFtZShMb2NhbCA9IHVlZmEudGVzdCRsb2NhbCwgYXMuZGF0YS5mcmFtZShhdXgpKQ0KICANCnVlZmEucmVzdWx0czENCmBgYA0KDQoNCiMjIFBhcmEgbG9zIHZpc2l0YW50ZXMNClJlZ3Jlc2nDs24gYmlub21pYWwgdGlwbyBsb2fDrXN0aWNhIHBhcmEgcHJlZGVjaXIgbGEgdmFyaWFibGUgV2luMiAoU2kgZ2FuYSBvIG5vIGVsIHBhcnRpZG8pLCBlbiBiYXNlIGEgbG9zIGdvbGVzIGVzcGVyYWRvcyBkZSBsb3MgdmlzaXRhbnRlcy4NCmBgYHtyfQ0KbG9naXRfcmVnMiA8LSBnbG0oZm9ybXVsYSA9IFdpbjIgfiB4Z192aXNpdCwgDQogICAgICAgICAgICAgICAgIGZhbWlseSA9IGJpbm9taWFsKGxpbmsgPSAibG9naXQiKSwNCiAgICAgICAgICAgICAgICAgZGF0YSA9IHVlZmEudHJhaW4pDQpzdW1tYXJ5KGxvZ2l0X3JlZzIpDQpgYGANCg0KYGBge3J9DQpleHBfZ29hbHMyIDwtIHNlcShtaW4odWVmYS50cmFpbiR4Z192aXNpdCksIG1heCh1ZWZhLnRyYWluJHhnX3Zpc2l0KSwgMC4wNSkNCg0KcHJlZGljY2lvbjIgPC0gcHJlZGljdChvYmplY3QgPSBsb2dpdF9yZWcyLCANCiAgICAgICAgICAgICAgICBuZXdkYXRhID0gbGlzdCh4Z192aXNpdCA9IGV4cF9nb2FsczIpLA0KICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKQ0KDQpncmFwaF9wcmVkaWN0MiA8LSBkYXRhLmZyYW1lKGV4cF9nb2FsczIsIHByZWRpY2Npb24yKQ0KY29sbmFtZXMoZ3JhcGhfcHJlZGljdDIpIDwtIGMoIkV4cGVjdGVkX0dvYWxzIiwgIlByb2JhYmlsaWRhZCIpDQpgYGANCg0KIyMgR3LDoWZpY2EgZGVsIE1vZGVsbyBwYXJhIHZpc2l0YW50ZXMNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBncmFwaF9wcmVkaWN0MiwgYWVzKHggPSBFeHBlY3RlZF9Hb2FscywgeSA9IFByb2JhYmlsaWRhZCkpICsgDQogIGdlb21fbGluZShjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsgDQogIGdndGl0bGUoIk1vZGVsbyBwYXJhIFZpc2l0YW50ZXMgLSBSZWdyZXNpw7NuIExvZ8Otc3RpY2EiKSArDQogIGxhYnMoeCA9ICJFeHBlY3RlZCBHb2FscyIpICsgDQogIGxhYnMoeSA9ICJQcm9iYWJpbGlkYWQiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiMjIyBNb2RlbG8gY29uIGRhdG9zIGRlbCBkYXRhc2V0IGRlIHBydWViYXMNCg0KYGBge3J9DQpwcmVkaWNjaW9uMl90ZXN0IDwtIHByZWRpY3Qob2JqZWN0ID0gbG9naXRfcmVnMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gdWVmYS50ZXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU9InJlc3BvbnNlIikNCmF1eDIgPC0gZGF0YS5mcmFtZShXaW4gPSB1ZWZhLnRlc3QkV2luMiwgUHJvYmFiaWxpZGFkID0gcHJlZGljY2lvbjJfdGVzdCkNCnVlZmEucmVzdWx0czIgPC0gZGF0YS5mcmFtZShWaXNpdGFudGUgPSB1ZWZhLnRlc3QkdmlzaXQsIGFzLmRhdGEuZnJhbWUoYXV4MikpDQogIA0KdWVmYS5yZXN1bHRzMg0KYGBgDQoNCiMgQ29uY2x1c2lvbmVzDQojIyMjIEVuIGVsIGFuw6FsaXNpcyBkZSBlc3RvcyBkYXRvcyB1c2FuZG8gbGEgdmFyaWFibGUgZGUgZ29sZXMgZXNwZXJhZG9zIHBvZGVtb3MgdmVyIHF1ZSBsb3MgZXF1aXBvcyBxdWUganVlZ2FuIGRlIGxvY2FsZXMgdGllbmVuIG3DoXMgcG9zaWJpbGlkYWRlcyBkZSBnYW5hciB5IGVjaGFyIG3DoXMgZ29sZXMgKGRlYmlkbyBhIGxvcyBnb2xlcyBlc3BlcmFkb3MpIHF1ZSBsb3MgZXF1aXBvcyBxdWUganVlZ2FuIGRlIHZpc2l0YW50ZXMuDQo=