Instalar paquetes y llamar librerías

# install.packages("forecast")
library(forecast)
# install.packages("readxl")
library(readxl)

Ejemplo Producción

Contexto

Una Serie de tiempo es una colección de observaciones sobre un determinado fenómeno efectuadas en momentos de tiempo sucesivos, usualmente equiespaciados.

Ejemplo de series de tiempo: 1. Precio de acciones 2. Niveles de inventario 3. Rotación personal 4. Ventas 5. PIB(GDP)

Crear la serie de tiempo

Ejemplo: Los siguentes datos de producción trimestral inician en el primer trimestre de 2020. Se busca pronosticar la producción de los sigueintes 5 trimestres.

produccion <- c(50,53,55,57,55,60)
# En "start" el primer argumento es el perido, y el segundo la cantidad de periodos en 1 año.
st_produccion <- ts(data=produccion, start = c(2020,1),
                    frequency = 4) # En este caso, la serie de tiempo inicia en 2020 en el 1° mes.

# st_produccion <- ts(data=produccion, start = c(2020,1),
                   # frequency = 12) # En este caso, la serie de tiempo inicia en 2020 en el 1° mes.

# st_produccion <- ts(data=produccion, start = c(2020,8),
                   # frequency = 12) # En este caso, la serie de tiempo inicia en 2020 en el 8° mes.

Crear modelo ARIMA

ARIMA significa modelo autoregresivo integrado de promedio movil, en ingles

modelo_produccion <- auto.arima(st_produccion, D = 1) # D: Diferenciación Estacional
modelo_produccion
## Series: st_produccion 
## ARIMA(0,0,0)(0,1,0)[4] with drift 
## 
## Coefficients:
##        drift
##       1.5000
## s.e.  0.1768
## 
## sigma^2 = 2.01:  log likelihood = -2.84
## AIC=9.68   AICc=-2.32   BIC=7.06
summary(modelo_produccion)
## Series: st_produccion 
## ARIMA(0,0,0)(0,1,0)[4] with drift 
## 
## Coefficients:
##        drift
##       1.5000
## s.e.  0.1768
## 
## sigma^2 = 2.01:  log likelihood = -2.84
## AIC=9.68   AICc=-2.32   BIC=7.06
## 
## Training set error measures:
##                      ME      RMSE       MAE        MPE      MAPE       MASE
## Training set 0.03333332 0.5787923 0.3666667 0.03685269 0.6429133 0.06111111
##                    ACF1
## Training set -0.5073047
# Al comparar modelos, seleccionamos el que tenga el menor MAPE (Porcentaje de Error Promedio Absoluto)

Generar el pronostico

pronostico_producción <- forecast(modelo_produccion, level = c(95), h=5)
# Si no nos dicen otra cosa, el nivel de confiabilidad es 95%. Los periodo a pronosticar es h.
pronostico_producción
##         Point Forecast    Lo 95    Hi 95
## 2021 Q3             61 58.22127 63.77873
## 2021 Q4             63 60.22127 65.77873
## 2022 Q1             61 58.22127 63.77873
## 2022 Q2             66 63.22127 68.77873
## 2022 Q3             67 63.07028 70.92972
plot(pronostico_producción)

Ejercicio 1. México rumbo al 2025

En equipos de 2 o 3, seleccionar un estado de México, obtener los datos historicos de su población, generar un pronostico hasta 2050

Comparar contra los datos de la CONAPO y escribir conlusiones(¿por qué la diferencia del pronóstico?)

App Shiny Aguascalientes

App Shiny Aguascalientea

Ejemplo Población Aguascalientes

Crear la serie de tiempo

# Datos de población del municipio de Aguascalientes: años 2000, 2005, 2010, 2015, 2020, 2024
poblacion <- c(944285, 1065416, 1184996, 1312544, 1425607, 1530185)
st_poblacion <- ts(data = poblacion, start = c(2000), frequency = 1) # Serie anual

## <span style="color:blue;"> Generar el pronóstico </span>
pronostico_poblacion <- forecast(st_poblacion, level = c(95), h = 5) # Hasta 2050 (2024 + 26 años)
pronostico_poblacion
##      Point Forecast   Lo 95   Hi 95
## 2006        1647224 1549317 1745130
## 2007        1763815 1625174 1902456
## 2008        1880406 1708351 2052461
## 2009        1996997 1795110 2198885
## 2010        2113588 1883989 2343187
plot(pronostico_poblacion, main = "Pronóstico población Aguascalientes hasta 2050")

## Crear modelo ARIMA

modelo_poblacion <- auto.arima(st_poblacion, D = 1)
modelo_poblacion
## Series: st_poblacion 
## ARIMA(0,1,0) with drift 
## 
## Coefficients:
##            drift
##       117180.000
## s.e.    3490.753
## 
## sigma^2 = 76327505:  log likelihood = -51.91
## AIC=107.82   AICc=113.82   BIC=107.03
summary(modelo_poblacion)
## Series: st_poblacion 
## ARIMA(0,1,0) with drift 
## 
## Coefficients:
##            drift
##       117180.000
## s.e.    3490.753
## 
## sigma^2 = 76327505:  log likelihood = -51.91
## AIC=107.82   AICc=113.82   BIC=107.03
## 
## Training set error measures:
##                    ME     RMSE      MAE        MPE     MAPE       MASE
## Training set 137.8508 7133.373 5710.851 0.05642175 0.427205 0.04873571
##                   ACF1
## Training set 0.1476909

Generar el pronóstico

pronostico_poblacion <- forecast(st_poblacion, level = c(95), h = 5) # Hasta 2050 (2024 + 26 años)
pronostico_poblacion
##      Point Forecast   Lo 95   Hi 95
## 2006        1647224 1549317 1745130
## 2007        1763815 1625174 1902456
## 2008        1880406 1708351 2052461
## 2009        1996997 1795110 2198885
## 2010        2113588 1883989 2343187
plot(pronostico_poblacion, main = "Pronóstico población Aguascalientes hasta 2050")

Ejercicio 2. Aplicación de Shiny

Agregar una pestaña en la aplicacción de Shiny con el ejercicio México rumbo al 2050. En el menú se debe seleccionar la cantidad de años a pronosticar.

Ejercicio 3. Aprendizaje mas importante

  1. Creación de FODA
  2. Balance General y Estados de resultados
  3. El uso las formulas de estadistica
  4. Como dirigirse a la gente en una presentación
  5. Creación de tableros
  6. No recuerdo la materia
  7. Utilizar R y los principios de análisis de datos
  8. Modelos ANOVA y redes neuronales
  9. Ikigai: Construye tus sueños
  10. Concentración de Análitica de datos y herramientas de inteligencia artificial

Activivad 2. Hershey´s Producción

ventas <- read_excel("C:\\Users\\macha\\Downloads\\Ventas_Históricas_Lechitas.xlsx")
str(ventas)
## tibble [36 × 1] (S3: tbl_df/tbl/data.frame)
##  $ Ventas: num [1:36] 25521 23740 26254 25868 27073 ...
st_ventas <- ts(data=ventas, start=c(2017, 1), frequency = 12)

Crear el modelo ARIMA

modelo_ventas <- auto.arima(st_ventas)
modelo_ventas
## Series: st_ventas 
## ARIMA(1,0,0)(1,1,0)[12] with drift 
## 
## Coefficients:
##          ar1     sar1     drift
##       0.6383  -0.5517  288.8979
## s.e.  0.1551   0.2047   14.5026
## 
## sigma^2 = 202701:  log likelihood = -181.5
## AIC=371   AICc=373.11   BIC=375.72
summary(modelo_ventas)
## Series: st_ventas 
## ARIMA(1,0,0)(1,1,0)[12] with drift 
## 
## Coefficients:
##          ar1     sar1     drift
##       0.6383  -0.5517  288.8979
## s.e.  0.1551   0.2047   14.5026
## 
## sigma^2 = 202701:  log likelihood = -181.5
## AIC=371   AICc=373.11   BIC=375.72
## 
## Training set error measures:
##                    ME    RMSE    MAE        MPE      MAPE       MASE      ACF1
## Training set 25.22158 343.864 227.17 0.08059932 0.7069542 0.06491044 0.2081026

Generar el pronóstico

pronostico_ventas <- forecast(modelo_ventas, level= c(95), h=12)
pronostico_ventas
##          Point Forecast    Lo 95    Hi 95
## Jan 2020       35498.90 34616.48 36381.32
## Feb 2020       34202.17 33155.28 35249.05
## Mar 2020       36703.01 35596.10 37809.92
## Apr 2020       36271.90 35141.44 37402.36
## May 2020       37121.98 35982.07 38261.90
## Jun 2020       37102.65 35958.90 38246.40
## Jul 2020       37151.04 36005.73 38296.34
## Aug 2020       38564.64 37418.70 39710.58
## Sep 2020       38755.22 37609.03 39901.42
## Oct 2020       39779.02 38632.72 40925.32
## Nov 2020       38741.63 37595.28 39887.97
## Dec 2020       38645.86 37499.50 39792.22
plot(pronostico_ventas)

LS0tDQp0aXRsZTogIkFjdGl2aWRhZCAyIg0KYXV0aG9yOiAiTWFyY2VsbyBBZ3VpcnJlIEEwMTE3NzkyNCINCmRhdGU6ICIyMDI1LTA4LTE0Ig0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGNlcnVsZWFuDQotLS0NCg0KIVtdKGh0dHBzOi8vYXByZW5kZWNvbmVsaS5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMjAvMDUvQWRvYmVTdG9ja18zMDAxNjcxNjItc2NhbGVkLmpwZWcpDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hcyA8L3NwYW4+DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGluc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikNCmxpYnJhcnkoZm9yZWNhc3QpDQojIGluc3RhbGwucGFja2FnZXMoInJlYWR4bCIpDQpsaWJyYXJ5KHJlYWR4bCkNCmBgYA0KDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gRWplbXBsbyBQcm9kdWNjacOzbiA8L3NwYW4+DQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENvbnRleHRvIDwvc3Bhbj4NClVuYSAqKlNlcmllIGRlIHRpZW1wbyoqIGVzIHVuYSBjb2xlY2Npw7NuIGRlIG9ic2VydmFjaW9uZXMgc29icmUgdW4gZGV0ZXJtaW5hZG8gZmVuw7NtZW5vIGVmZWN0dWFkYXMgZW4gbW9tZW50b3MgZGUgdGllbXBvIHN1Y2VzaXZvcywgdXN1YWxtZW50ZSBlcXVpZXNwYWNpYWRvcy4NCg0KRWplbXBsbyBkZSBzZXJpZXMgZGUgdGllbXBvOg0KMS4gUHJlY2lvIGRlIGFjY2lvbmVzDQoyLiBOaXZlbGVzIGRlIGludmVudGFyaW8NCjMuIFJvdGFjacOzbiBwZXJzb25hbA0KNC4gVmVudGFzDQo1LiBQSUIoR0RQKQ0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBDcmVhciBsYSBzZXJpZSBkZSB0aWVtcG8gPC9zcGFuPg0KRWplbXBsbzogTG9zIHNpZ3VlbnRlcyBkYXRvcyBkZSBwcm9kdWNjacOzbiB0cmltZXN0cmFsIGluaWNpYW4gZW4gZWwgcHJpbWVyIHRyaW1lc3RyZSBkZSAyMDIwLiBTZSBidXNjYSBwcm9ub3N0aWNhciBsYSBwcm9kdWNjacOzbiBkZSBsb3Mgc2lndWVpbnRlcyA1IHRyaW1lc3RyZXMuDQpgYGB7cn0NCnByb2R1Y2Npb24gPC0gYyg1MCw1Myw1NSw1Nyw1NSw2MCkNCiMgRW4gInN0YXJ0IiBlbCBwcmltZXIgYXJndW1lbnRvIGVzIGVsIHBlcmlkbywgeSBlbCBzZWd1bmRvIGxhIGNhbnRpZGFkIGRlIHBlcmlvZG9zIGVuIDEgYcOxby4NCnN0X3Byb2R1Y2Npb24gPC0gdHMoZGF0YT1wcm9kdWNjaW9uLCBzdGFydCA9IGMoMjAyMCwxKSwNCiAgICAgICAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gNCkgIyBFbiBlc3RlIGNhc28sIGxhIHNlcmllIGRlIHRpZW1wbyBpbmljaWEgZW4gMjAyMCBlbiBlbCAxwrAgbWVzLg0KDQojIHN0X3Byb2R1Y2Npb24gPC0gdHMoZGF0YT1wcm9kdWNjaW9uLCBzdGFydCA9IGMoMjAyMCwxKSwNCiAgICAgICAgICAgICAgICAgICAjIGZyZXF1ZW5jeSA9IDEyKSAjIEVuIGVzdGUgY2FzbywgbGEgc2VyaWUgZGUgdGllbXBvIGluaWNpYSBlbiAyMDIwIGVuIGVsIDHCsCBtZXMuDQoNCiMgc3RfcHJvZHVjY2lvbiA8LSB0cyhkYXRhPXByb2R1Y2Npb24sIHN0YXJ0ID0gYygyMDIwLDgpLA0KICAgICAgICAgICAgICAgICAgICMgZnJlcXVlbmN5ID0gMTIpICMgRW4gZXN0ZSBjYXNvLCBsYSBzZXJpZSBkZSB0aWVtcG8gaW5pY2lhIGVuIDIwMjAgZW4gZWwgOMKwIG1lcy4NCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBDcmVhciBtb2RlbG8gQVJJTUEgPC9zcGFuPg0KKipBUklNQSoqIHNpZ25pZmljYSBtb2RlbG8gYXV0b3JlZ3Jlc2l2byBpbnRlZ3JhZG8gZGUgcHJvbWVkaW8gbW92aWwsIGVuIGluZ2xlcw0KYGBge3J9DQptb2RlbG9fcHJvZHVjY2lvbiA8LSBhdXRvLmFyaW1hKHN0X3Byb2R1Y2Npb24sIEQgPSAxKSAjIEQ6IERpZmVyZW5jaWFjacOzbiBFc3RhY2lvbmFsDQptb2RlbG9fcHJvZHVjY2lvbg0Kc3VtbWFyeShtb2RlbG9fcHJvZHVjY2lvbikNCiMgQWwgY29tcGFyYXIgbW9kZWxvcywgc2VsZWNjaW9uYW1vcyBlbCBxdWUgdGVuZ2EgZWwgbWVub3IgTUFQRSAoUG9yY2VudGFqZSBkZSBFcnJvciBQcm9tZWRpbyBBYnNvbHV0bykNCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBHZW5lcmFyIGVsIHByb25vc3RpY28gPC9zcGFuPg0KYGBge3J9DQpwcm9ub3N0aWNvX3Byb2R1Y2Npw7NuIDwtIGZvcmVjYXN0KG1vZGVsb19wcm9kdWNjaW9uLCBsZXZlbCA9IGMoOTUpLCBoPTUpDQojIFNpIG5vIG5vcyBkaWNlbiBvdHJhIGNvc2EsIGVsIG5pdmVsIGRlIGNvbmZpYWJpbGlkYWQgZXMgOTUlLiBMb3MgcGVyaW9kbyBhIHByb25vc3RpY2FyIGVzIGguDQpwcm9ub3N0aWNvX3Byb2R1Y2Npw7NuDQpwbG90KHByb25vc3RpY29fcHJvZHVjY2nDs24pDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBFamVyY2ljaW8gMS4gTcOpeGljbyBydW1ibyBhbCAyMDI1IDwvc3Bhbj4NCkVuIGVxdWlwb3MgZGUgMiBvIDMsIHNlbGVjY2lvbmFyIHVuIGVzdGFkbyBkZSBNw6l4aWNvLCBvYnRlbmVyIGxvcyBkYXRvcyBoaXN0b3JpY29zIGRlIHN1IHBvYmxhY2nDs24sIGdlbmVyYXIgdW4gcHJvbm9zdGljbyBoYXN0YSAyMDUwDQoNCkNvbXBhcmFyIGNvbnRyYSBsb3MgZGF0b3MgZGUgbGEgQ09OQVBPIHkgZXNjcmliaXIgY29ubHVzaW9uZXMowr9wb3IgcXXDqSBsYSBkaWZlcmVuY2lhIGRlbCBwcm9uw7NzdGljbz8pDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gQXBwIFNoaW55IEFndWFzY2FsaWVudGVzIDwvc3Bhbj4NCltBcHAgU2hpbnkgQWd1YXNjYWxpZW50ZWFdKGh0dHBzOi8vbWFyY2Vsb2FndWlycmUuc2hpbnlhcHBzLmlvL0FwcF9Qb2JsYWNpb25fQWd1YXMvKQ0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IEVqZW1wbG8gUG9ibGFjacOzbiBBZ3Vhc2NhbGllbnRlcyA8L3NwYW4+DQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENyZWFyIGxhIHNlcmllIGRlIHRpZW1wbyA8L3NwYW4+DQoNCmBgYHtyfQ0KIyBEYXRvcyBkZSBwb2JsYWNpw7NuIGRlbCBtdW5pY2lwaW8gZGUgQWd1YXNjYWxpZW50ZXM6IGHDsW9zIDIwMDAsIDIwMDUsIDIwMTAsIDIwMTUsIDIwMjAsIDIwMjQNCnBvYmxhY2lvbiA8LSBjKDk0NDI4NSwgMTA2NTQxNiwgMTE4NDk5NiwgMTMxMjU0NCwgMTQyNTYwNywgMTUzMDE4NSkNCnN0X3BvYmxhY2lvbiA8LSB0cyhkYXRhID0gcG9ibGFjaW9uLCBzdGFydCA9IGMoMjAwMCksIGZyZXF1ZW5jeSA9IDEpICMgU2VyaWUgYW51YWwNCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gR2VuZXJhciBlbCBwcm9uw7NzdGljbyA8L3NwYW4+DQpwcm9ub3N0aWNvX3BvYmxhY2lvbiA8LSBmb3JlY2FzdChzdF9wb2JsYWNpb24sIGxldmVsID0gYyg5NSksIGggPSA1KSAjIEhhc3RhIDIwNTAgKDIwMjQgKyAyNiBhw7FvcykNCnByb25vc3RpY29fcG9ibGFjaW9uDQpwbG90KHByb25vc3RpY29fcG9ibGFjaW9uLCBtYWluID0gIlByb27Ds3N0aWNvIHBvYmxhY2nDs24gQWd1YXNjYWxpZW50ZXMgaGFzdGEgMjA1MCIpDQpgYGANCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENyZWFyIG1vZGVsbyBBUklNQSA8L3NwYW4+DQoNCmBgYHtyfQ0KbW9kZWxvX3BvYmxhY2lvbiA8LSBhdXRvLmFyaW1hKHN0X3BvYmxhY2lvbiwgRCA9IDEpDQptb2RlbG9fcG9ibGFjaW9uDQpzdW1tYXJ5KG1vZGVsb19wb2JsYWNpb24pDQpgYGANCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IEdlbmVyYXIgZWwgcHJvbsOzc3RpY28gPC9zcGFuPg0KYGBge3J9DQpwcm9ub3N0aWNvX3BvYmxhY2lvbiA8LSBmb3JlY2FzdChzdF9wb2JsYWNpb24sIGxldmVsID0gYyg5NSksIGggPSA1KSAjIEhhc3RhIDIwNTAgKDIwMjQgKyAyNiBhw7FvcykNCnByb25vc3RpY29fcG9ibGFjaW9uDQpwbG90KHByb25vc3RpY29fcG9ibGFjaW9uLCBtYWluID0gIlByb27Ds3N0aWNvIHBvYmxhY2nDs24gQWd1YXNjYWxpZW50ZXMgaGFzdGEgMjA1MCIpDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBFamVyY2ljaW8gMi4gQXBsaWNhY2nDs24gZGUgU2hpbnkgPC9zcGFuPg0KQWdyZWdhciB1bmEgcGVzdGHDsWEgZW4gbGEgYXBsaWNhY2Npw7NuIGRlIFNoaW55IGNvbiBlbCBlamVyY2ljaW8gTcOpeGljbyBydW1ibyBhbCAyMDUwLiBFbiBlbCBtZW7DuiBzZSBkZWJlIHNlbGVjY2lvbmFyIGxhIGNhbnRpZGFkIGRlIGHDsW9zIGEgcHJvbm9zdGljYXIuDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gRWplcmNpY2lvIDMuIEFwcmVuZGl6YWplIG1hcyBpbXBvcnRhbnRlIDwvc3Bhbj4NCjEuIENyZWFjacOzbiBkZSBGT0RBIA0KMi4gQmFsYW5jZSBHZW5lcmFsIHkgRXN0YWRvcyBkZSByZXN1bHRhZG9zDQozLiBFbCB1c28gbGFzIGZvcm11bGFzIGRlIGVzdGFkaXN0aWNhIA0KNC4gQ29tbyBkaXJpZ2lyc2UgYSBsYSBnZW50ZSBlbiB1bmEgcHJlc2VudGFjacOzbg0KNS4gQ3JlYWNpw7NuIGRlIHRhYmxlcm9zDQo2LiBObyByZWN1ZXJkbyBsYSBtYXRlcmlhDQo3LiBVdGlsaXphciBSIHkgbG9zIHByaW5jaXBpb3MgZGUgYW7DoWxpc2lzIGRlIGRhdG9zDQo4LiBNb2RlbG9zIEFOT1ZBIHkgcmVkZXMgbmV1cm9uYWxlcw0KOS4gSWtpZ2FpOiBDb25zdHJ1eWUgdHVzIHN1ZcOxb3MNCjEwLiBDb25jZW50cmFjacOzbiBkZSBBbsOhbGl0aWNhIGRlIGRhdG9zIHkgaGVycmFtaWVudGFzIGRlIGludGVsaWdlbmNpYSBhcnRpZmljaWFsDQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBBY3Rpdml2YWQgMi4gSGVyc2hlecK0cyBQcm9kdWNjacOzbiA8L3NwYW4+DQohW10oaHR0cHM6Ly93d3cudmlzaXR0aGV1c2EubXgvc2l0ZXMvZGVmYXVsdC9maWxlcy9zdHlsZXMvaGVyb19sL3B1YmxpYy9pbWFnZXMvaGVyb19tZWRpYV9pbWFnZS8yMDE3LTAyL0hFUk9fQ2hvY29sYXRlV29ybGRfSGVyc2hleV9QZW5uc3lsdmFuaWFfMDAxX1dlYjcyRFAuanBnP2l0b2s9clFidEJzdU8pDQoNCmBgYHtyfQ0KdmVudGFzIDwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcbWFjaGFcXERvd25sb2Fkc1xcVmVudGFzX0hpc3TDs3JpY2FzX0xlY2hpdGFzLnhsc3giKQ0Kc3RyKHZlbnRhcykNCnN0X3ZlbnRhcyA8LSB0cyhkYXRhPXZlbnRhcywgc3RhcnQ9YygyMDE3LCAxKSwgZnJlcXVlbmN5ID0gMTIpDQpgYGANCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENyZWFyIGVsIG1vZGVsbyBBUklNQSA8L3NwYW4+DQpgYGB7cn0NCm1vZGVsb192ZW50YXMgPC0gYXV0by5hcmltYShzdF92ZW50YXMpDQptb2RlbG9fdmVudGFzDQpzdW1tYXJ5KG1vZGVsb192ZW50YXMpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gR2VuZXJhciBlbCBwcm9uw7NzdGljbyA8L3NwYW4+DQpgYGB7cn0NCnByb25vc3RpY29fdmVudGFzIDwtIGZvcmVjYXN0KG1vZGVsb192ZW50YXMsIGxldmVsPSBjKDk1KSwgaD0xMikNCnByb25vc3RpY29fdmVudGFzDQpwbG90KHByb25vc3RpY29fdmVudGFzKQ0KYGBgDQoNCg0K