Contexto

Una empresa de e-commerce quiere evaluar el impacto de una nueva campaña de marketing sobre sus ventas diarias. Tienen datos de ventas antes y después de la campaña y desean determinar si la campaña tuvo un efecto significativo en el aumento de las ventas.

Dado que los datos de ventas pueden tener alta variabilidad y dependencia temporal, se decide usar el doble bootstrap para mejorar la estimación del intervalo de confianza del efecto de la campaña.

Información de la Data

Datos:

Se dispone de un dataset con 90 días de ventas antes de la campaña y 90 días después de la campaña.

Variables del dataset:

  • Día: Es la etiqueta correspondiente al día de la venta.
  • Ventas: Es el monto de venta resultante.
  • Periodo: Indica si la venta es previa o posterior a la implementación de la campaña.

Herramientas para la simulación

Cargar librerías

library(boot)
library(utils)

Leer base de datos y Exploración

venta <- read.csv("C:\\Users\\aleja\\Documents\\00_Carrera_y_formación\\00_TEC_Por semestre_LIT\\SEMESTRE_8\\Bases_de_Datos\\dataset_ventas.csv")
head(venta)
##   dia    ventas periodo
## 1   1  83.71554   antes
## 2   2 114.96018   antes
## 3   3 104.24468   antes
## 4   4  77.40558   antes
## 5   5  91.32100   antes
## 6   6 124.77155   antes

Crear subconjuntos para determinar impacto de la campaña

venta_antes<-venta[venta$periodo == "antes",]
head(venta_antes)
##   dia    ventas periodo
## 1   1  83.71554   antes
## 2   2 114.96018   antes
## 3   3 104.24468   antes
## 4   4  77.40558   antes
## 5   5  91.32100   antes
## 6   6 124.77155   antes
venta_despues<-venta[venta$periodo == "despues",]
head(venta_despues)
##    dia    ventas periodo
## 91   1 127.25308 despues
## 92   2  90.98972 despues
## 93   3 112.71553 despues
## 94   4 127.66793 despues
## 95   5 104.97484 despues
## 96   6 125.46672 despues

Bootstrapping Sencillo

Calcular media y aplicar bootstrapping sencillo.

#Función para calcular la media
bootstrap_media <- function(data, indices) {
  return(mean(data[indices]))  
}

set.seed(386) 

#Aplicar Bootstrap con 100000 repeticiones
Rbootstrap_va <- boot(data = venta_antes$ventas, statistic = bootstrap_media, R = 100000)

#Mostrar resumen de resultados
print(Rbootstrap_va)
## 
## ORDINARY NONPARAMETRIC BOOTSTRAP
## 
## 
## Call:
## boot(data = venta_antes$ventas, statistic = bootstrap_media, 
##     R = 1e+05)
## 
## 
## Bootstrap Statistics :
##     original     bias    std. error
## t1* 100.5368 0.00116431    1.815028
#Calcular Intervalo de Confianza del 95%
intervalo_conf <- boot.ci(Rbootstrap_va, type = "perc")
print("Intervalo de confianza de ventas anteriores_________________")
## [1] "Intervalo de confianza de ventas anteriores_________________"
print(intervalo_conf)
## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
## Based on 100000 bootstrap replicates
## 
## CALL : 
## boot.ci(boot.out = Rbootstrap_va, type = "perc")
## 
## Intervals : 
## Level     Percentile     
## 95%   ( 97.0, 104.1 )  
## Calculations and Intervals on Original Scale
hist(Rbootstrap_va$t, main = "Distribución Bootstrap de la Media (Ventas Anteriores)",
     xlab = "Media Remuestreada", col = "powderblue", border = "black")

#Aplicar Bootstrap con 100000 repeticiones
Rbootstrap_vd <- boot(data = venta_despues$ventas, statistic = bootstrap_media, R = 100000)

#Mostrar resumen de resultados
print(Rbootstrap_vd)
## 
## ORDINARY NONPARAMETRIC BOOTSTRAP
## 
## 
## Call:
## boot(data = venta_despues$ventas, statistic = bootstrap_media, 
##     R = 1e+05)
## 
## 
## Bootstrap Statistics :
##     original     bias    std. error
## t1* 110.5493 0.01502967    1.484184
#Calcular Intervalo de Confianza del 95%
intervalo_conf2 <- boot.ci(Rbootstrap_vd, type = "perc")
print("Intervalo de confianza de ventas posteriores_________________")
## [1] "Intervalo de confianza de ventas posteriores_________________"
print(intervalo_conf2)
## BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
## Based on 100000 bootstrap replicates
## 
## CALL : 
## boot.ci(boot.out = Rbootstrap_vd, type = "perc")
## 
## Intervals : 
## Level     Percentile     
## 95%   (107.7, 113.5 )  
## Calculations and Intervals on Original Scale
hist(Rbootstrap_vd$t, main = "Distribución Bootstrap de la Media (Ventas Posteriores)",
     xlab = "Media Remuestreada", col = "powderblue", border = "black")

Aplicación de Doble Bootstrapping

set.seed(386)

#f(): Calcular promedio de ventas
ventas_av <- function(data,indices){
  muestraE <- data[indices, ]
  return(mean(muestraE$ventas))
}


#f(): Realizar simulación de Doble bootstrapping
doble_bootstrap <- function(data, n_outer, n_inner) {
  set.seed(386)
  outer_results <- replicate(n_outer, {
    outer_sample <- data[sample(nrow(data), 90, replace = TRUE), ]  # Muestra de 9 días de venta
    inner_boot <- boot(data = outer_sample, statistic = ventas_av, R = n_inner)
    return(mean(inner_boot$t))  #Promedio de ventas en el nivel interno
  })
  
  return(outer_results)
}

#Aplicamos el doble bootstrapping
n_outer <- 1000    #Muestras bootstrap externas
n_inner <- 750    #Muestras bootstrap internas

doble_resultados_A <- doble_bootstrap(venta_antes, n_outer, n_inner)
doble_resultados_D <- doble_bootstrap(venta_despues, n_outer, n_inner)


#Calcular intervalos de confianza al 95%
conf_intervals <- quantile(doble_resultados_A, probs = c(0.025, 0.975))

#Mostrar resultados
cat("Calificación promedio estimada:", mean(doble_resultados_A), "\n")
## Calificación promedio estimada: 100.5336
cat("Intervalo de confianza al 95%:", conf_intervals[1], "-", conf_intervals[2], "\n")
## Intervalo de confianza al 95%: 97.01549 - 104.136
#Calcular intervalos de confianza al 95%
conf_intervals <- quantile(doble_resultados_D, probs = c(0.025, 0.975))

#Mostrar resultados
cat("Calificación promedio estimada:", mean(doble_resultados_D), "\n")
## Calificación promedio estimada: 110.5021
cat("Intervalo de confianza al 95%:", conf_intervals[1], "-", conf_intervals[2], "\n")
## Intervalo de confianza al 95%: 107.5073 - 113.5529

Conclusión Comparativa

Resultados con 100,000 iteraciones de bootstrapp de primer nivel

Medias:

  • Antes: $100.53 por venta
  • Después: $110.54 por venta

Intervalos:

  • Antes: ( 97.0, 104.1 )
  • Después: (107.7, 113.5 )

Resultados con n_outer = 1000 & n_inner = 750 de iteraciones de bootstrapp de segundo nivel

Medias:

  • Antes: $100.53 por venta
  • Después: $110.50 por venta

Intervalos:

  • Antes: ( 97.01, 104.13 )
  • Después: (107.50, 113.55 )

En ambos métodos de simulaciones podemos observar un valor similar tanto en intervalos como en medias. Esto puede deberse a que ambos tienen una muestra bastante grande así como un número de iteraciones altas.

¿La campaña tuvo un impacto significativo?

Según las dos simulación realizadas puedo concluir que, efectivamente, la campaña tuvo un impacto significativo subiendo un 10% la media de ventas

LS0tDQp0aXRsZTogIkRvdWJsZV9Cb290c3RyYXBwaW5nX0VtcHJlc2FfRWNvbW1lcmNlX0E3NDkiDQphdXRob3I6ICJTYW1hbnRoYSAtIEEwMTQyMjc0OSINCmRhdGU6ICIyMDI1LTA4LTIwIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgICB0b2M6IFRSVUUNCiAgICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUNCiAgICAgdGhlbWU6IHlldGkNCi0tLQ0KPGNlbnRlcj4NCiFbXShodHRwczovL2Nkbi5kcmliYmJsZS5jb20vdXNlcnVwbG9hZC80MTkzMzI4Ni9maWxlL29yaWdpbmFsLTFmNzBlYmMyYjExOGQwNzEyMjdlOTVjMDRhZWJkYTUwLmdpZikNCjwvY2VudGVyPg0KDQojIDxiPiA8c3BhbiBzdHlsZT0iY29sb3I6ICNDRDEwNzY7Ij4gQ29udGV4dG8gPC9zcGFuPiA8L2I+DQoNClVuYSBlbXByZXNhIGRlIGUtY29tbWVyY2UgcXVpZXJlIGV2YWx1YXIgZWwgaW1wYWN0byBkZSB1bmEgbnVldmEgY2FtcGHDsWEgZGUgbWFya2V0aW5nIHNvYnJlIHN1cyAqKnZlbnRhcyBkaWFyaWFzKiouIFRpZW5lbiBkYXRvcyBkZSB2ZW50YXMgYW50ZXMgeSBkZXNwdcOpcyBkZSBsYSBjYW1wYcOxYSB5IGRlc2VhbiBkZXRlcm1pbmFyIHNpIGxhIGNhbXBhw7FhIHR1dm8gdW4gZWZlY3RvIHNpZ25pZmljYXRpdm8gZW4gZWwgYXVtZW50byBkZSBsYXMgdmVudGFzLg0KDQpEYWRvIHF1ZSBsb3MgZGF0b3MgZGUgdmVudGFzIHB1ZWRlbiB0ZW5lciBhbHRhIHZhcmlhYmlsaWRhZCB5IGRlcGVuZGVuY2lhIHRlbXBvcmFsLCBzZSBkZWNpZGUgdXNhciBlbCAqKmRvYmxlIGJvb3RzdHJhcCoqIHBhcmENCm1lam9yYXIgbGEgZXN0aW1hY2nDs24gZGVsIGludGVydmFsbyBkZSBjb25maWFuemEgZGVsIGVmZWN0byBkZSBsYSBjYW1wYcOxYS4NCg0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHBpbms7ICI+IEluZm9ybWFjacOzbiBkZSBsYSBEYXRhIDwvc3Bhbj4NCg0KRGF0b3M6DQoNClNlIGRpc3BvbmUgZGUgdW4gZGF0YXNldCBjb24gOTAgZMOtYXMgZGUgdmVudGFzIGFudGVzIGRlIGxhIGNhbXBhw7FhIHkgOTAgZMOtYXMgZGVzcHXDqXMgZGUgbGEgY2FtcGHDsWEuDQoNCioqVmFyaWFibGVzIGRlbCBkYXRhc2V0OioqDQoNCisgRMOtYTogRXMgbGEgZXRpcXVldGEgY29ycmVzcG9uZGllbnRlIGFsIGTDrWEgZGUgbGEgdmVudGEuDQorIFZlbnRhczogRXMgZWwgbW9udG8gZGUgdmVudGEgcmVzdWx0YW50ZS4gDQorIFBlcmlvZG86IEluZGljYSBzaSBsYSB2ZW50YSBlcyBwcmV2aWEgbyBwb3N0ZXJpb3IgYSBsYSBpbXBsZW1lbnRhY2nDs24gZGUgbGEgY2FtcGHDsWEuDQoNCiMgPGI+IDxzcGFuIHN0eWxlPSJjb2xvcjojQ0QxMDc2OyAiPiBIZXJyYW1pZW50YXMgcGFyYSBsYSBzaW11bGFjacOzbiAgPC9zcGFuPiA8L2I+DQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcmVkIDsiPiBDYXJnYXIgbGlicmVyw61hcyA8L3NwYW4+DQpgYGB7cn0NCmxpYnJhcnkoYm9vdCkNCmxpYnJhcnkodXRpbHMpDQoNCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHJlZCA7Ij4gTGVlciBiYXNlIGRlIGRhdG9zIHkgRXhwbG9yYWNpw7NuIDwvc3Bhbj4NCmBgYHtyfQ0KdmVudGEgPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcYWxlamFcXERvY3VtZW50c1xcMDBfQ2FycmVyYV95X2Zvcm1hY2nDs25cXDAwX1RFQ19Qb3Igc2VtZXN0cmVfTElUXFxTRU1FU1RSRV84XFxCYXNlc19kZV9EYXRvc1xcZGF0YXNldF92ZW50YXMuY3N2IikNCmhlYWQodmVudGEpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiByZWQgOyI+IENyZWFyIHN1YmNvbmp1bnRvcyBwYXJhIGRldGVybWluYXIgaW1wYWN0byBkZSBsYSBjYW1wYcOxYTwvc3Bhbj4NCmBgYHtyfQ0KdmVudGFfYW50ZXM8LXZlbnRhW3ZlbnRhJHBlcmlvZG8gPT0gImFudGVzIixdDQpoZWFkKHZlbnRhX2FudGVzKQ0KDQp2ZW50YV9kZXNwdWVzPC12ZW50YVt2ZW50YSRwZXJpb2RvID09ICJkZXNwdWVzIixdDQpoZWFkKHZlbnRhX2Rlc3B1ZXMpDQpgYGANCg0KIyA8Yj4gPHNwYW4gc3R5bGU9ImNvbG9yOiAjQ0QxMDc2IDsiPiBCb290c3RyYXBwaW5nIFNlbmNpbGxvIDwvc3Bhbj4gPC9iPg0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrICA7Ij4gQ2FsY3VsYXIgbWVkaWEgeSBhcGxpY2FyIGJvb3RzdHJhcHBpbmcgc2VuY2lsbG8uICA8L3NwYW4+DQoNCmBgYHtyfQ0KDQojRnVuY2nDs24gcGFyYSBjYWxjdWxhciBsYSBtZWRpYQ0KYm9vdHN0cmFwX21lZGlhIDwtIGZ1bmN0aW9uKGRhdGEsIGluZGljZXMpIHsNCiAgcmV0dXJuKG1lYW4oZGF0YVtpbmRpY2VzXSkpICANCn0NCg0Kc2V0LnNlZWQoMzg2KSANCg0KI0FwbGljYXIgQm9vdHN0cmFwIGNvbiAxMDAwMDAgcmVwZXRpY2lvbmVzDQpSYm9vdHN0cmFwX3ZhIDwtIGJvb3QoZGF0YSA9IHZlbnRhX2FudGVzJHZlbnRhcywgc3RhdGlzdGljID0gYm9vdHN0cmFwX21lZGlhLCBSID0gMTAwMDAwKQ0KDQojTW9zdHJhciByZXN1bWVuIGRlIHJlc3VsdGFkb3MNCnByaW50KFJib290c3RyYXBfdmEpDQoNCiNDYWxjdWxhciBJbnRlcnZhbG8gZGUgQ29uZmlhbnphIGRlbCA5NSUNCmludGVydmFsb19jb25mIDwtIGJvb3QuY2koUmJvb3RzdHJhcF92YSwgdHlwZSA9ICJwZXJjIikNCnByaW50KCJJbnRlcnZhbG8gZGUgY29uZmlhbnphIGRlIHZlbnRhcyBhbnRlcmlvcmVzX19fX19fX19fX19fX19fX18iKQ0KcHJpbnQoaW50ZXJ2YWxvX2NvbmYpDQoNCg0KaGlzdChSYm9vdHN0cmFwX3ZhJHQsIG1haW4gPSAiRGlzdHJpYnVjacOzbiBCb290c3RyYXAgZGUgbGEgTWVkaWEgKFZlbnRhcyBBbnRlcmlvcmVzKSIsDQogICAgIHhsYWIgPSAiTWVkaWEgUmVtdWVzdHJlYWRhIiwgY29sID0gInBvd2RlcmJsdWUiLCBib3JkZXIgPSAiYmxhY2siKQ0KDQojQXBsaWNhciBCb290c3RyYXAgY29uIDEwMDAwMCByZXBldGljaW9uZXMNClJib290c3RyYXBfdmQgPC0gYm9vdChkYXRhID0gdmVudGFfZGVzcHVlcyR2ZW50YXMsIHN0YXRpc3RpYyA9IGJvb3RzdHJhcF9tZWRpYSwgUiA9IDEwMDAwMCkNCg0KI01vc3RyYXIgcmVzdW1lbiBkZSByZXN1bHRhZG9zDQpwcmludChSYm9vdHN0cmFwX3ZkKQ0KDQojQ2FsY3VsYXIgSW50ZXJ2YWxvIGRlIENvbmZpYW56YSBkZWwgOTUlDQppbnRlcnZhbG9fY29uZjIgPC0gYm9vdC5jaShSYm9vdHN0cmFwX3ZkLCB0eXBlID0gInBlcmMiKQ0KcHJpbnQoIkludGVydmFsbyBkZSBjb25maWFuemEgZGUgdmVudGFzIHBvc3RlcmlvcmVzX19fX19fX19fX19fX19fX18iKQ0KcHJpbnQoaW50ZXJ2YWxvX2NvbmYyKQ0KDQoNCmhpc3QoUmJvb3RzdHJhcF92ZCR0LCBtYWluID0gIkRpc3RyaWJ1Y2nDs24gQm9vdHN0cmFwIGRlIGxhIE1lZGlhIChWZW50YXMgUG9zdGVyaW9yZXMpIiwNCiAgICAgeGxhYiA9ICJNZWRpYSBSZW11ZXN0cmVhZGEiLCBjb2wgPSAicG93ZGVyYmx1ZSIsIGJvcmRlciA9ICJibGFjayIpDQoNCg0KYGBgDQoNCiMgPGI+IDxzcGFuIHN0eWxlPSJjb2xvcjogI0NEMTA3NjsiPiBBcGxpY2FjacOzbiBkZSBEb2JsZSBCb290c3RyYXBwaW5nIDwvc3Bhbj4gPC9iPg0KYGBge3J9DQpzZXQuc2VlZCgzODYpDQoNCiNmKCk6IENhbGN1bGFyIHByb21lZGlvIGRlIHZlbnRhcw0KdmVudGFzX2F2IDwtIGZ1bmN0aW9uKGRhdGEsaW5kaWNlcyl7DQogIG11ZXN0cmFFIDwtIGRhdGFbaW5kaWNlcywgXQ0KICByZXR1cm4obWVhbihtdWVzdHJhRSR2ZW50YXMpKQ0KfQ0KDQoNCiNmKCk6IFJlYWxpemFyIHNpbXVsYWNpw7NuIGRlIERvYmxlIGJvb3RzdHJhcHBpbmcNCmRvYmxlX2Jvb3RzdHJhcCA8LSBmdW5jdGlvbihkYXRhLCBuX291dGVyLCBuX2lubmVyKSB7DQogIHNldC5zZWVkKDM4NikNCiAgb3V0ZXJfcmVzdWx0cyA8LSByZXBsaWNhdGUobl9vdXRlciwgew0KICAgIG91dGVyX3NhbXBsZSA8LSBkYXRhW3NhbXBsZShucm93KGRhdGEpLCA5MCwgcmVwbGFjZSA9IFRSVUUpLCBdICAjIE11ZXN0cmEgZGUgOSBkw61hcyBkZSB2ZW50YQ0KICAgIGlubmVyX2Jvb3QgPC0gYm9vdChkYXRhID0gb3V0ZXJfc2FtcGxlLCBzdGF0aXN0aWMgPSB2ZW50YXNfYXYsIFIgPSBuX2lubmVyKQ0KICAgIHJldHVybihtZWFuKGlubmVyX2Jvb3QkdCkpICAjUHJvbWVkaW8gZGUgdmVudGFzIGVuIGVsIG5pdmVsIGludGVybm8NCiAgfSkNCiAgDQogIHJldHVybihvdXRlcl9yZXN1bHRzKQ0KfQ0KDQojQXBsaWNhbW9zIGVsIGRvYmxlIGJvb3RzdHJhcHBpbmcNCm5fb3V0ZXIgPC0gMTAwMCAgICAjTXVlc3RyYXMgYm9vdHN0cmFwIGV4dGVybmFzDQpuX2lubmVyIDwtIDc1MCAgICAjTXVlc3RyYXMgYm9vdHN0cmFwIGludGVybmFzDQoNCmRvYmxlX3Jlc3VsdGFkb3NfQSA8LSBkb2JsZV9ib290c3RyYXAodmVudGFfYW50ZXMsIG5fb3V0ZXIsIG5faW5uZXIpDQpkb2JsZV9yZXN1bHRhZG9zX0QgPC0gZG9ibGVfYm9vdHN0cmFwKHZlbnRhX2Rlc3B1ZXMsIG5fb3V0ZXIsIG5faW5uZXIpDQoNCg0KI0NhbGN1bGFyIGludGVydmFsb3MgZGUgY29uZmlhbnphIGFsIDk1JQ0KY29uZl9pbnRlcnZhbHMgPC0gcXVhbnRpbGUoZG9ibGVfcmVzdWx0YWRvc19BLCBwcm9icyA9IGMoMC4wMjUsIDAuOTc1KSkNCg0KI01vc3RyYXIgcmVzdWx0YWRvcw0KY2F0KCJDYWxpZmljYWNpw7NuIHByb21lZGlvIGVzdGltYWRhOiIsIG1lYW4oZG9ibGVfcmVzdWx0YWRvc19BKSwgIlxuIikNCmNhdCgiSW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBhbCA5NSU6IiwgY29uZl9pbnRlcnZhbHNbMV0sICItIiwgY29uZl9pbnRlcnZhbHNbMl0sICJcbiIpDQoNCiNDYWxjdWxhciBpbnRlcnZhbG9zIGRlIGNvbmZpYW56YSBhbCA5NSUNCmNvbmZfaW50ZXJ2YWxzIDwtIHF1YW50aWxlKGRvYmxlX3Jlc3VsdGFkb3NfRCwgcHJvYnMgPSBjKDAuMDI1LCAwLjk3NSkpDQoNCiNNb3N0cmFyIHJlc3VsdGFkb3MNCmNhdCgiQ2FsaWZpY2FjacOzbiBwcm9tZWRpbyBlc3RpbWFkYToiLCBtZWFuKGRvYmxlX3Jlc3VsdGFkb3NfRCksICJcbiIpDQpjYXQoIkludGVydmFsbyBkZSBjb25maWFuemEgYWwgOTUlOiIsIGNvbmZfaW50ZXJ2YWxzWzFdLCAiLSIsIGNvbmZfaW50ZXJ2YWxzWzJdLCAiXG4iKQ0KYGBgDQoNCiMgPGI+IDxzcGFuIHN0eWxlPSJjb2xvcjogI0NEMTA3NjsiPiBDb25jbHVzacOzbiBDb21wYXJhdGl2YSAgPC9zcGFuPiA8L2I+IA0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrICA7Ij4gUmVzdWx0YWRvcyBjb24gKioxMDAsMDAwKiogaXRlcmFjaW9uZXMgZGUgYm9vdHN0cmFwcCBkZSBwcmltZXIgbml2ZWwgPC9zcGFuPg0KDQoqTWVkaWFzOioNCg0KKiBBbnRlczogJDEwMC41MyBwb3IgdmVudGENCiogRGVzcHXDqXM6ICQxMTAuNTQgcG9yIHZlbnRhDQoNCipJbnRlcnZhbG9zOioNCg0KKiBBbnRlczogKCA5Ny4wLCAxMDQuMSApDQoqIERlc3B1w6lzOiAoMTA3LjcsIDExMy41ICkNCg0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrICA7Ij4gUmVzdWx0YWRvcyBjb24gKipuX291dGVyID0gMTAwMCAmIG5faW5uZXIgPSA3NTAqKiBkZSBpdGVyYWNpb25lcyBkZSBib290c3RyYXBwIGRlIHNlZ3VuZG8gbml2ZWwgPC9zcGFuPg0KDQoqTWVkaWFzOioNCg0KKiBBbnRlczogJDEwMC41MyBwb3IgdmVudGENCiogRGVzcHXDqXM6ICQxMTAuNTAgcG9yIHZlbnRhDQoNCipJbnRlcnZhbG9zOioNCg0KKiBBbnRlczogKCA5Ny4wMSwgMTA0LjEzICkNCiogRGVzcHXDqXM6ICgxMDcuNTAsIDExMy41NSApIA0KDQpFbiBhbWJvcyBtw6l0b2RvcyBkZSBzaW11bGFjaW9uZXMgcG9kZW1vcyBvYnNlcnZhciB1biB2YWxvciBzaW1pbGFyIHRhbnRvIGVuIGludGVydmFsb3MgY29tbyBlbiBtZWRpYXMuIEVzdG8gcHVlZGUgZGViZXJzZSBhIHF1ZSBhbWJvcyB0aWVuZW4gdW5hIG11ZXN0cmEgYmFzdGFudGUgZ3JhbmRlIGFzw60gY29tbyB1biBuw7ptZXJvIGRlIGl0ZXJhY2lvbmVzIGFsdGFzLiANCg0KKirCv0xhIGNhbXBhw7FhIHR1dm8gdW4gaW1wYWN0byBzaWduaWZpY2F0aXZvPyoqDQoNClNlZ8O6biBsYXMgZG9zIHNpbXVsYWNpw7NuIHJlYWxpemFkYXMgcHVlZG8gY29uY2x1aXIgcXVlLCBlZmVjdGl2YW1lbnRlLCBsYSBjYW1wYcOxYSB0dXZvIHVuIGltcGFjdG8gc2lnbmlmaWNhdGl2byBzdWJpZW5kbyB1biAxMCUgbGEgbWVkaWEgZGUgdmVudGFzDQoNCg0KDQo=