Instalar paquetes y llamar librerías
#install.packages("forecast")
library(forecast)
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
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.
Ejemplos de series de tiempo son:
1. Precio de acciones 2. Niveles de inventario 3. Rotación de personal
4. Ventas 5. PIB (GDP).
Crear la serie de tiempo
Ejemplo: Los siguientes datos de producción trimestral inician el
primer trimestre de 2020. Se busca pronosticar la producción de los
siguientes 5 trimestres.
produccion <- c(50,53,55,57,55,60)
st_produccion <- ts(data=produccion, start= c(2020, 1), frequency=4) # En este caso, la serie de tiempo inicia en 2020, en el 1º trimestre
# Mensual primer 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
# Mensual otro mes : : st_produccion <- ts(data=produccion, start= c(2020, 8), frequency=12) # En este caso, la serie de tiempo inicia en 2020, en el 8vo mes
# Anual : st_produccion <- ts(data=produccion, start= c(2020), frequency=1) # En este caso, la serie de tiempo inicia en 2020
Crear el modelo ARIMA
ARIMA significa Modelo Autorregresivo Integrado de
Promedio Móvil, en inglés.
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) #MAPE : Median Absolute Porcentage Error / Porcentaje de Error Promedio Absoluto
## 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.
Generar el pronóstico
pronostico_produccion <- forecast(modelo_produccion, level = c(95), h=5)
# Si no nos dicen otra cosa, el nivel de confiabilidad es 95%. Los periodos a pronosticar es h
pronostico_produccion
## 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_produccion)

Ejercicio 1. Mexico rumbo al 2050
En equipos de 2 o 3, seleccionar un estado de México, obtener los
datos históricos de su poblacón, generar un pronóstico hasta 2050
Cargar archivo
pob_sonora <- read_excel("/Users/hugoenrique/Desktop/Universidad/8vo\ Semestre/Generación\ de\ Escenarios/M1/Act2/pob_sonora_1990_2020.xlsx")
pob_sonora
## # A tibble: 7 × 3
## Entidad Año Población
## <chr> <dbl> <dbl>
## 1 Sonora 1990 1823606
## 2 Sonora 1995 2085536
## 3 Sonora 2000 2216969
## 4 Sonora 2005 2394861
## 5 Sonora 2010 2662480
## 6 Sonora 2015 2850330
## 7 Sonora 2020 2944840
Crear la serie de tiempo
st_pob_sonora <- ts(data=pob_sonora$Población, start= c(1990), frequency=.2)
#En este caso, la serie de tiempo inicia en 2020, en el 1er trimestre.
Crear el modeo ARIMA
ARIMA significa Modelo Autorregresivo Integrado de Promedio
Móvil, en inglés.
modelo_pbsonora <- auto.arima(st_pob_sonora) # Diferenciación Estacional
modelo_pbsonora
## Series: st_pob_sonora
## ARIMA(0,1,0) with drift
##
## Coefficients:
## drift
## 186872.33
## s.e. 25733.79
##
## sigma^2 = 4.768e+09: log likelihood = -74.82
## AIC=153.64 AICc=157.64 BIC=153.23
summary(modelo_pbsonora)
## Series: st_pob_sonora
## ARIMA(0,1,0) with drift
##
## Coefficients:
## drift
## 186872.33
## s.e. 25733.79
##
## sigma^2 = 4.768e+09: log likelihood = -74.82
## AIC=153.64 AICc=157.64 BIC=153.23
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 233.819 58361.29 45028.68 0.1062428 1.823979 0.01856457 -0.1802949
# Al comparar modelos, seleccionamos el que tenga el menor MAPE (Porcentaje de Error Promedio Absoluto)
Generar el pronóstico
pronostico_pbsonora <- forecast(modelo_pbsonora, level=c(95), h=7)
#Si no nos dicen otra cosa, el nivel de confiabilidad es 95%. Los periodos a pronosticar es h.
pronostico_pbsonora
## Point Forecast Lo 95 Hi 95
## 2025 3131712 2996369 3267056
## 2030 3318585 3127180 3509989
## 2035 3505457 3271035 3739879
## 2040 3692329 3421643 3963016
## 2045 3879202 3576565 4181839
## 2050 4066074 3734552 4397596
## 2055 4252946 3894861 4611031
plot(pronostico_pbsonora)

Conclusión
En nuestro pronóstico se refleja un constante crecimiento en la
población de Sonora. El último censo realizado por INEGI en 2020
registró una población de 2,944,840 en Sonora, mientras que nuestro
pronóstico refleja una población ligeramente mayor a los 4 millones de
habitantes.
Actividad 2. Hershey’s

Crear la serie de tiempo
ventas <- read_excel("/Users/hugoenrique/Desktop/Universidad/8vo\ Semestre/Generación\ de\ Escenarios/M1/Act2/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 modeo 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.8980
## s.e. 0.1551 0.2047 14.5026
##
## sigma^2 = 202700: 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.8980
## s.e. 0.1551 0.2047 14.5026
##
## sigma^2 = 202700: log likelihood = -181.5
## AIC=371 AICc=373.11 BIC=375.72
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 25.22163 343.863 227.1699 0.08059942 0.7069541 0.06491041
## ACF1
## Training set 0.2081043
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.29 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.91 38246.40
## Jul 2020 37151.04 36005.74 38296.35
## Aug 2020 38564.65 37418.71 39710.59
## Sep 2020 38755.23 37609.03 39901.42
## Oct 2020 39779.03 38632.73 40925.33
## Nov 2020 38741.63 37595.29 39887.97
## Dec 2020 38645.86 37499.50 39792.22
plot(pronostico_ventas)

LS0tCnRpdGxlOiAiQWN0aXZpZGFkIDIiCmF1dGhvcjogIkh1Z28gRW5yaXF1ZSBFc3Byb25jZWRhIEFuYXlhIC8gQTAxMjg0ODI3IgpkYXRlOiAiMjAyNS0wOC0xMiIKb3V0cHV0OiAKIGh0bWxfZG9jdW1lbnQ6CiAgIHRvYzogVFJVRQogICB0b2NfZmxvYXQ6IFRydWUKICAgY29kZV9kb3dubG9hZDogVHJ1ZQogICB0aGVtZTogY2VydWxlYW4KLS0tCgohW10oaHR0cHM6Ly93d3c1LnV2YS5lcy9lc3RhZG1lZC9kYXRvcy9zZXJpZXMvZ3JhZjE1LmdpZikKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hcyA8L3NwYW4+CmBgYHtyfQojaW5zdGFsbC5wYWNrYWdlcygiZm9yZWNhc3QiKQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KHJlYWR4bCkKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IEVqZW1wbG8uIFByb2R1Y2Npw7NuIDwvc3Bhbj4KCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENvbnRleHRvIDwvc3Bhbj4KVW5hICoqc2VyaWUgZGUgdGllbXBvKiogZXMgdW5hIGNvbGVjY2nDs24gZGUgb2JzZXJ2YWNpb25lcyBzb2JyZSB1biBkZXRlcm1pbmFkbyBmZW7Ds21lbm8gZWZlY3R1YWRhcyBlbiBtb21lbnRvcyBkZSB0aWVtcG8gc3VjZXNpdm9zLCB1c3VhbG1lbnRlIGVxdWllc3BhY2lhZG9zLiAgCgpFamVtcGxvcyBkZSBzZXJpZXMgZGUgdGllbXBvIHNvbjogIAoxLiBQcmVjaW8gZGUgYWNjaW9uZXMKMi4gTml2ZWxlcyBkZSBpbnZlbnRhcmlvCjMuIFJvdGFjacOzbiBkZSBwZXJzb25hbAo0LiBWZW50YXMKNS4gUElCIChHRFApLiAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENyZWFyIGxhIHNlcmllIGRlIHRpZW1wbyA8L3NwYW4+CkVqZW1wbG86IExvcyBzaWd1aWVudGVzIGRhdG9zIGRlIHByb2R1Y2Npw7NuIHRyaW1lc3RyYWwgaW5pY2lhbiBlbCBwcmltZXIgdHJpbWVzdHJlIGRlIDIwMjAuIFNlIGJ1c2NhIHByb25vc3RpY2FyIGxhIHByb2R1Y2Npw7NuIGRlIGxvcyBzaWd1aWVudGVzIDUgdHJpbWVzdHJlcy4KYGBge3J9CnByb2R1Y2Npb24gPC0gYyg1MCw1Myw1NSw1Nyw1NSw2MCkKc3RfcHJvZHVjY2lvbiA8LSB0cyhkYXRhPXByb2R1Y2Npb24sIHN0YXJ0PSBjKDIwMjAsIDEpLCBmcmVxdWVuY3k9NCkgIyBFbiBlc3RlIGNhc28sIGxhIHNlcmllIGRlIHRpZW1wbyBpbmljaWEgZW4gMjAyMCwgZW4gZWwgMcK6IHRyaW1lc3RyZQoKIyBNZW5zdWFsIHByaW1lciBtZXMgOiBzdF9wcm9kdWNjaW9uIDwtIHRzKGRhdGE9cHJvZHVjY2lvbiwgc3RhcnQ9IGMoMjAyMCwgMSksIGZyZXF1ZW5jeT0xMikgIyBFbiBlc3RlIGNhc28sIGxhIHNlcmllIGRlIHRpZW1wbyBpbmljaWEgZW4gMjAyMCwgZW4gZWwgMcK6IG1lcwoKIyBNZW5zdWFsIG90cm8gbWVzIDogIDogc3RfcHJvZHVjY2lvbiA8LSB0cyhkYXRhPXByb2R1Y2Npb24sIHN0YXJ0PSBjKDIwMjAsIDgpLCBmcmVxdWVuY3k9MTIpICMgRW4gZXN0ZSBjYXNvLCBsYSBzZXJpZSBkZSB0aWVtcG8gaW5pY2lhIGVuIDIwMjAsIGVuIGVsIDh2byBtZXMKCiMgQW51YWwgOiBzdF9wcm9kdWNjaW9uIDwtIHRzKGRhdGE9cHJvZHVjY2lvbiwgc3RhcnQ9IGMoMjAyMCksIGZyZXF1ZW5jeT0xKSAjIEVuIGVzdGUgY2FzbywgbGEgc2VyaWUgZGUgdGllbXBvIGluaWNpYSBlbiAyMDIwCmBgYAoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij4gQ3JlYXIgZWwgbW9kZWxvIEFSSU1BIDwvc3Bhbj4KKipBUklNQSoqIHNpZ25pZmljYSBNb2RlbG8gQXV0b3JyZWdyZXNpdm8gSW50ZWdyYWRvIGRlIFByb21lZGlvIE3Ds3ZpbCwgZW4gaW5nbMOpcy4KYGBge3J9Cm1vZGVsb19wcm9kdWNjaW9uIDwtIGF1dG8uYXJpbWEoc3RfcHJvZHVjY2lvbiwgRD0xKSAjIEQ6IERpZmVyZW5jaWFjacOzbiBlc3RhY2lvbmFsCm1vZGVsb19wcm9kdWNjaW9uCnN1bW1hcnkobW9kZWxvX3Byb2R1Y2Npb24pICNNQVBFIDogTWVkaWFuIEFic29sdXRlIFBvcmNlbnRhZ2UgRXJyb3IgLyBQb3JjZW50YWplIGRlIEVycm9yIFByb21lZGlvIEFic29sdXRvCiMgQWwgY29tcGFyYXIgbW9kZWxvcywgc2VsZWNjaW9uYW1vcyBlbCBxdWUgdGVuZ2EgZWwgbWVub3IgTUFQRS4KYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBHZW5lcmFyIGVsIHByb27Ds3N0aWNvIDwvc3Bhbj4KYGBge3J9CnByb25vc3RpY29fcHJvZHVjY2lvbiA8LSBmb3JlY2FzdChtb2RlbG9fcHJvZHVjY2lvbiwgbGV2ZWwgPSBjKDk1KSwgaD01KQojIFNpIG5vIG5vcyBkaWNlbiBvdHJhIGNvc2EsIGVsIG5pdmVsIGRlIGNvbmZpYWJpbGlkYWQgZXMgOTUlLiBMb3MgcGVyaW9kb3MgYSBwcm9ub3N0aWNhciBlcyBoCnByb25vc3RpY29fcHJvZHVjY2lvbgpwbG90KHByb25vc3RpY29fcHJvZHVjY2lvbikKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IEVqZXJjaWNpbyAxLiBNZXhpY28gcnVtYm8gYWwgMjA1MCA8L3NwYW4+CkVuIGVxdWlwb3MgZGUgMiBvIDMsIHNlbGVjY2lvbmFyIHVuIGVzdGFkbyBkZSBNw6l4aWNvLCBvYnRlbmVyIGxvcyBkYXRvcyBoaXN0w7NyaWNvcyBkZSBzdSBwb2JsYWPDs24sIGdlbmVyYXIgdW4gcHJvbsOzc3RpY28gaGFzdGEgMjA1MCAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENhcmdhciBhcmNoaXZvIDwvc3Bhbj4KYGBge3J9CnBvYl9zb25vcmEgPC0gcmVhZF9leGNlbCgiL1VzZXJzL2h1Z29lbnJpcXVlL0Rlc2t0b3AvVW5pdmVyc2lkYWQvOHZvXCBTZW1lc3RyZS9HZW5lcmFjaW/MgW5cIGRlXCBFc2NlbmFyaW9zL00xL0FjdDIvcG9iX3Nvbm9yYV8xOTkwXzIwMjAueGxzeCIpCnBvYl9zb25vcmEKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBDcmVhciBsYSBzZXJpZSBkZSB0aWVtcG8gPC9zcGFuPgpgYGB7cn0Kc3RfcG9iX3Nvbm9yYSA8LSB0cyhkYXRhPXBvYl9zb25vcmEkUG9ibGFjacOzbiwgc3RhcnQ9IGMoMTk5MCksIGZyZXF1ZW5jeT0uMikKI0VuIGVzdGUgY2FzbywgbGEgc2VyaWUgZGUgdGllbXBvIGluaWNpYSBlbiAyMDIwLCBlbiBlbCAxZXIgdHJpbWVzdHJlLgpgYGAKCiMjIDxzcGFuIHN0eWxlPSAiY29sb3I6Ymx1ZTsiPiBDcmVhciBlbCBtb2RlbyBBUklNQSA8L3NwYW4+CipBUklNQSogc2lnbmlmaWNhIE1vZGVsbyBBdXRvcnJlZ3Jlc2l2byBJbnRlZ3JhZG8gZGUgUHJvbWVkaW8gTcOzdmlsLCBlbiBpbmdsw6lzLgpgYGB7cn0KbW9kZWxvX3Bic29ub3JhIDwtIGF1dG8uYXJpbWEoc3RfcG9iX3Nvbm9yYSkgIyBEaWZlcmVuY2lhY2nDs24gRXN0YWNpb25hbAptb2RlbG9fcGJzb25vcmEKc3VtbWFyeShtb2RlbG9fcGJzb25vcmEpCiMgQWwgY29tcGFyYXIgbW9kZWxvcywgc2VsZWNjaW9uYW1vcyBlbCBxdWUgdGVuZ2EgZWwgbWVub3IgTUFQRSAoUG9yY2VudGFqZSBkZSBFcnJvciBQcm9tZWRpbyBBYnNvbHV0bykKYGBgCgojIyA8c3BhbiBzdHlsZT0gImNvbG9yOmJsdWU7Ij4gR2VuZXJhciBlbCBwcm9uw7NzdGljbyA8L3NwYW4+CmBgYHtyfQpwcm9ub3N0aWNvX3Bic29ub3JhIDwtIGZvcmVjYXN0KG1vZGVsb19wYnNvbm9yYSwgbGV2ZWw9Yyg5NSksIGg9NykKI1NpIG5vIG5vcyBkaWNlbiBvdHJhIGNvc2EsIGVsIG5pdmVsIGRlIGNvbmZpYWJpbGlkYWQgZXMgOTUlLiBMb3MgcGVyaW9kb3MgYSBwcm9ub3N0aWNhciBlcyBoLgpwcm9ub3N0aWNvX3Bic29ub3JhCnBsb3QocHJvbm9zdGljb19wYnNvbm9yYSkKYGBgCgojIyA8c3BhbiBzdHlsZT0gImNvbG9yOmJsdWU7Ij4gQ29uY2x1c2nDs24gPC9zcGFuPgpFbiBudWVzdHJvIHByb27Ds3N0aWNvIHNlIHJlZmxlamEgdW4gY29uc3RhbnRlIGNyZWNpbWllbnRvIGVuIGxhIHBvYmxhY2nDs24gZGUgU29ub3JhLiBFbCDDumx0aW1vIGNlbnNvIHJlYWxpemFkbyBwb3IgSU5FR0kgZW4gMjAyMCByZWdpc3Ryw7MgdW5hIHBvYmxhY2nDs24gZGUgMiw5NDQsODQwIGVuIFNvbm9yYSwgbWllbnRyYXMgcXVlIG51ZXN0cm8gcHJvbsOzc3RpY28gcmVmbGVqYSB1bmEgcG9ibGFjacOzbiBsaWdlcmFtZW50ZSBtYXlvciBhIGxvcyA0IG1pbGxvbmVzIGRlIGhhYml0YW50ZXMuCgojIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IEVqZXJjaWNpbyAyLiBBcGxpY2FjacOzbiBkZSBTaGlueTwvc3Bhbj4KQWdyZWdhciB1bmEgcGVzdGHDsWEgZW4gbGEgYXBsaWNhY2nDs24gZGUgU2hpbnkgY29uIGVsIGVqZXJjaWNpbyBNw6l4aWNvIHJ1bWJvIGFsIDIwNTAuIEVuIGVsIG1lbsO6IHNlIGRlYmUgc2VsZWNjaW9uYXIgbGEgY2FudGlkYWQgZGUgYcOxb3MgYSBwcm9ub3N0aWNhciB5IGVsIG5pdmVsIGRlIGNvbmZpYWJpbGlkYWQuCgpbQXBsaWNhY2nDs24gZGUgU2hpbnldKGh0dHBzOi8vYTAxMjg0ODI3LnNoaW55YXBwcy5pby9NMV9HRUZBX0ExLykKCgojIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IEVqZXJjaWNpbyAzLiBSZWZsZXhpw7NuIGRlIG1pcyBtYXRlcmlhcyBlbiBMSVQ8L3NwYW4+CjEuICoqRWwgcm9sIGRlIGxvcyBOZWdvY2lvcyBlbiBsYSBTb2NpZWRhZDoqKiBBcHJlbmTDrSBhIHJlYWxpemFyIGVsIGFuw6FsaXNpcyBQRVNURUwsIEZPREEgeSBjcmVhY2nDs24gZGUgS1BJJ3MgYWwgbWlzbW8gdGllbXBvIGFwcmVuZGltb3MgYSByZWFsaXphciBwcm9wdWVzdGFzIGRlIHZhbG9yIHBhcmEgdW5hIGVtcHJlc2EKMi4gKipEZWNpc2lvbmVzIEZpbmFuY2llcmFzOioqIEFwcmVuZGltb3MgYSBoYWNlciBsb3MgRXN0YWRvcyBkZSByZXN1bHRhZG9zLCBCYWxhbmNlIGdlbmVyYWwsIGVudHJlIG90cm9zIGRvY3VtZW50b3MgY29udGFibGVzLgozLiAqKlBlbnNhbWllbnRvIEVzdGFkw61zdGljbzoqKiBObyByZWN1ZXJkbyBxdWUgdmkgZW4gZXN0YSBtYXRlcmlhLiAKNC4gKipDb211bmljYWNpw7NuIHF1ZSBpbnNwaXJhOioqIFZpbW9zIGVsIElLSUdBSSBwYXJhIGVuY29udHJhciBudWVzdHJvIHByb3Bvc2l0bywgbGEgaW50ZW5jacOzbiBlcmEgYXByZW5kZXIgYSBkZXNlbnZvbHZlcnRlIHBhcmEgZ2VuZXJhciB1biBuZWdvY2lvIHF1ZSBsbGVuYXJhIHR1IHBhc2nDs24uCjUuICoqRXN0cmF0ZWdpYXMgZGUgTWVyY2FkbyB5IERpZmVyZW5jaWFjacOzbjoqKiBBcHJlbmRpbW9zIGEgaGFjZXIgY29zdGVvIGRlIHVuIHBsYW4gZGUgbWFya2V0aW5nIHBhcmEgZWwgc29jaW8gZm9ybWFkb3IgeSBwcmVzZW50YW1vcyB1biB0YWJsZXJvIGludGVyYWN0aXZvIGVuIGV4Y2VsLgo2LiAqKkV2YWx1YWNpw7NuIGRlIFByb3llY3RvcyBkZSBpbnZlcnNpw7NuOioqIEFwcmVuZGltb3MgYSBzYWNhciBlbCBXQUNDLCBDb3N0byBkZSBDYXBpdGFsLCBjb3NhcyBhc8OtIHBhcmEgcG9kZXIgZXZhbHVhciBlbXByZXNhcyB5IHNhYmVyIHNpIHNlcsOtYW4gcmVudGFibGVzLiAKNy4gKipNYW5pcHVsYWNpw7NuIGRlIERhdG9zOioqIEFwcmVuZGltb3MgYSBoYWNlciBsaW1waWV6YSwgeSB1dGlsaXphY2nDs24gZGUgZGF0b3MgZW4gUiBwYXJhIHBvZGVyIGdlbmVyYXIgaW5zaWdodHMgeSBlbnRlbmRlciBlbCBmdW5jaW9uYW1pZW50byBkZSB0YWJsYXMuCjguICoqTWluZXLDrWEgZGUgZGF0b3M6KiogQXByZW5kaW1vcyBtdWNob3MgbW9kZWxvcyBkZSBNYWNoaW5lIExlYXJuaW5nLCBsYSByZWxhY2nDs24gZW50cmUgZXhwbGFuaWJpbGlkYWQgeSBkaWZpY3VsdGFkIGRlIHVuIG1vZGVsbyB5IGNvbW8gZW50cmUgbcOhcyBzZW5jaWxsbyBlbCBtb2RlbG8gbcOhcyBmw6FjaWwgZGUgbGVlcmxvLgo5LiAqKkJvb3RjYW1wIGRlIHByb2dyYW1hY2nDs246KiogQXByZW5kaW1vcyBhIGhhY2VyIFNoaW55QXBwcywgcHJvZ3JhbWFjacOzbiBlbiBSIHkgdXRpbGl6YW1vcyBtdWNobyBlc3RvIHBhcmEgdHJhYmFqYXIgY29uIGRhdG9zIGRlIEFyY2EgQ29udGluZW50YWwKMTAuICoqU2VtZXN0cmUgVGVjOioqIFJlZm9yY8OpIGVuIEVzcGHDsWEgZGl2ZXJzb3MgdGVtYXMgZGUgUmVjdXJzb3MgaHVtYW5vcywgRmluYW56YXMgeSBhcHJlbmRpIGEgaGFjZXIgaW1wdWVzdG9zIGVuIEVzcGHDsWEgZGViaWRvIGEgdW5hIG1hdGVyaWEgZGUgRmlzY2FiaWxpZGFkLgoKIyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPiBBY3RpdmlkYWQgMi4gSGVyc2hleSdzIDwvc3Bhbj4KCiFbXShodHRwczovL2kwLndwLmNvbS9nZWVrYW5kbGlmZS5jb20ubXgvd3AtY29udGVudC91cGxvYWRzLzIwMjMvMDkvSGVyc2hleS1NZXhpY28tcHJlc2VudGEtbGEtbnVldmEtYmFycmEtSGVyc2hleXMtQ29jb2EtQ3JlYXRpb25zLWhlY2hhLWNvbi1jYWNhby0xMDAtZGUtb3JpZ2VuLW1leGljYW5vLmpwZz9maXQ9MTIwMCUyQzYxMSZzc2w9MSkKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+IENyZWFyIGxhIHNlcmllIGRlIHRpZW1wbyA8L3NwYW4+CmBgYHtyfQp2ZW50YXMgPC0gcmVhZF9leGNlbCgiL1VzZXJzL2h1Z29lbnJpcXVlL0Rlc2t0b3AvVW5pdmVyc2lkYWQvOHZvXCBTZW1lc3RyZS9HZW5lcmFjaW/MgW5cIGRlXCBFc2NlbmFyaW9zL00xL0FjdDIvVmVudGFzX0hpc3TDs3JpY2FzX0xlY2hpdGFzLnhsc3giKQpzdHIodmVudGFzKQpzdF92ZW50YXMgPC0gdHMoZGF0YT12ZW50YXMsIHN0YXJ0PWMoMjAxNywgMSksIGZyZXF1ZW5jeSA9IDEyKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSAiY29sb3I6Ymx1ZTsiPiBDcmVhciBlbCBtb2RlbyBBUklNQSA8L3NwYW4+CmBgYHtyfQptb2RlbG9fdmVudGFzIDwtIGF1dG8uYXJpbWEoc3RfdmVudGFzKQptb2RlbG9fdmVudGFzCnN1bW1hcnkobW9kZWxvX3ZlbnRhcykKYGBgCgojIyA8c3BhbiBzdHlsZT0gImNvbG9yOmJsdWU7Ij4gR2VuZXJhciBlbCBwcm9uw7NzdGljbyA8L3NwYW4+CmBgYHtyfQpwcm9ub3N0aWNvX3ZlbnRhcyA8LSBmb3JlY2FzdChtb2RlbG9fdmVudGFzLCBsZXZlbCA9IGMoOTUpLCBoID0gMTIpCnByb25vc3RpY29fdmVudGFzCnBsb3QocHJvbm9zdGljb192ZW50YXMpCmBgYAoKCgo=