Tarea 2: Integración de Tema 2

Astrid Paola González Díaz - A00830114

2024-02-28

Tareas en equipo realizadas por:

  • Ana López

  • Astrid González

  • Santiago González


Tema 2: Time Series

Introducción

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

Algunos ejemplos de series de tiempo son:
1. Precios de acciones
2. Niveles de inventarios
3. Rotación de personal
4. Ventas
5. PIB o GDP

Mas información:

Libro R for Data Science (2e)

Ejercicio en Clase

Librerías Necesarias

library(forecast)
library(kableExtra)

Datos TS

Ejemplo:
Los siguientes datos de producción inicial inician en el primer trimestre del 2020. Se busca pronosticar la producción de los siguientes 5 trimestres.

producción <- c(50,53,55,57,55,60)

ts<- ts(data= producción, start = c(2020,1), frequency = 4)
ts
##      Qtr1 Qtr2 Qtr3 Qtr4
## 2020   50   53   55   57
## 2021   55   60

Se crearon datos dummy para realizar el primer modelado de ejemplo de Time Series, por esta razón es que se delimitanron bajo una creación manual de vector. Después se delimitó un comienzo de la fecha en 2020 en el primer trimestre.

Modelado

ARIMA

El modelado ARIMA significa AutoRegressive Integrated Moving Average o Modelo Autor-regresivo Integrado de Promedio Móvil.

arima<- auto.arima(ts, D=1)
arima
## Series: ts 
## 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(arima)
## Series: ts 
## 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

En este primer modelo se puede observar como es que el que presenta un mejor desempeño en la iteración interna. De esta manera es que se obtiene un modelo ARIMA (0,0,0)(0,1,0)[4] donde se dice que no hay términos de autor-regresión así como no hay términos de promedio móvil en el modelo – no utiliza los valores anteriores de la serie ni los errores previos para hacer predicciones. Además indica que hay un solo término de diferencia de primer orden – que la serie temporal original fue diferenciada una vez para hacerla estacionaria. Muestra con el [4] que hay una estacionalidad en 4 unidades de tiempo y que se incluyó un término de deriva en el modelo para contar con una tendencia lineal.

Generación de pronóstico

pronostico<- forecast(arima, level = c(95), h=5)
pronostico
##         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)

En este caso se presenta un pronóstico con un nivel de confianza de 95% para los siguientes 5 trimestres, se observa una tendencia lineal que sigue en cierta manera los valores y patrones que se mostraban en los valores reales.

| Actividad 2: Hershey´s

Datos TS

Ejemplo:
Los siguientes datos son de ventas de “leches” Hersehy´s donde comienza en 2017 durante Enero para después almacenar información mensual.

lechita<- read.csv("C:/Users/Astrid Gonzalez/Documents/UNIVERSIDAD/OCTAVO/Generación de escenarios futuros con analítica/Módulo 1/Ventas_Históricas_Lechitas.csv")
kable(head(lechita)) %>% kable_paper(full_width= T, "hover")
Mes Ventas
ene-17 25520.51
feb-17 23740.11
mar-17 26253.58
abr-17 25868.43
may-17 27072.87
jun-17 27150.50
ts1<- ts(data=lechita$Ventas, start=c(2017,1), frequency=12)
(ts1)
##           Jan      Feb      Mar      Apr      May      Jun      Jul      Aug
## 2017 25520.51 23740.11 26253.58 25868.43 27072.87 27150.50 27067.10 28145.25
## 2018 28463.69 26996.11 29768.20 29292.51 29950.68 30099.17 30851.26 32271.76
## 2019 32496.44 31287.28 33376.02 32949.77 34004.11 33757.89 32927.30 34324.12
##           Sep      Oct      Nov      Dec
## 2017 27546.29 28400.37 27441.98 27852.47
## 2018 31940.74 32995.93 32197.12 31984.82
## 2019 35151.28 36133.07 34799.91 34846.17

Modelado

ARIMA

arima1<- auto.arima(ts1, D=1)
arima1
## Series: ts1 
## 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(arima1)
## Series: ts1 
## 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

Este modelo presenta un Root Mean Squared Error de 343.86 de ventas, tomando en cuenta la dimensión de los números originales se podría decir que es un buen modelo con error bajo. Además este modelo está tomando en cuenta un valor previo de la serie temporal para predecir el siguiente valor así como un término de diferencia de primer orden en las serie temporal y un término auto-regresivo de primer orden en la serie de las diferencias, además presenta una estacionalidad cada 12 periodos – es decir un patrón de comportamiento – y se incluye un término de deriva que permite una tendencia lineal en el tiempo.

Generación de pronóstico

pronostico1<- forecast(arima1, level = c(95), h=5)
pronostico1
##          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
plot(pronostico1)

En este modelo se presenta un nivel de confianza de 95% y una ventana de predicción de los siguientes 5 periodos, en este caso al ser datos mensuales, se pronostican los siguientes 5 meses.

| Actividad 3: Finanzas Corporativas

Librerías Necesarias

library(finreportr)

Información disponible

Con la función finreportr podemos obtener la siguiente información:

  • CompanyInfo()= brinda información general como nombre, ubicación, ZIP, etc.

  • AnnualReports() = brinda el nombre, fecha y número de acceso.

  • GetIncome()= brinda el estado de resultados.

  • GetBalanceSheet() = Brinda el balance general.

  • GetCashFlow()= Brinda el flujo de efectivo.

Extracción de información

Información de la compañía

options(HTTPUserAgent = "a a@gmail.com")

kable(CompanyInfo("JPM")) %>% kable_paper( "hover")
company CIK SIC state state.inc FY.end street.address city.state
JPMORGAN CHASE & CO 0000019617 6021 NY DE 1231 383 MADISON AVENUE NEW YORK NY 10017

Reportes Anual

kable(head(AnnualReports("BABA", foreign = TRUE))) %>% kable_paper(full_width=T, "hover")
filing.name filing.date accession.no
20-F/A 2024-02-23 0001193125-24-044480
20-F 2023-07-21 0000950170-23-033752
20-F 2022-07-26 0001104659-22-082622
20-F 2021-07-27 0001104659-21-096092
20-F 2020-07-09 0001104659-20-082409
20-F 2019-06-05 0001047469-19-003492

Estado de resultados

options(HTTPUserAgent = "a a@gmail.com")
kable(head(GetIncome("GOOG", 2018)))%>% kable_paper(full_width=T, "hover")
Metric Units Amount startDate endDate
Revenues usd 74989000000 2015-01-01 2015-12-31
Revenues usd 90272000000 2016-01-01 2016-12-31
Revenues usd 110855000000 2017-01-01 2017-12-31
Cost of Revenue usd 28164000000 2015-01-01 2015-12-31
Cost of Revenue usd 35138000000 2016-01-01 2016-12-31
Cost of Revenue usd 45583000000 2017-01-01 2017-12-31

Balance General

options(HTTPUserAgent = "a a@gmail.com")
kable(head(GetBalanceSheet("AMZN", 2015)))%>% kable_paper(full_width=T, "hover")
Metric Units Amount startDate endDate
Cash and Cash Equivalents, at Carrying Value usd 5269000000 NA 2011-12-31
Cash and Cash Equivalents, at Carrying Value usd 8084000000 NA 2012-12-31
Cash and Cash Equivalents, at Carrying Value usd 8658000000 NA 2013-12-31
Cash and Cash Equivalents, at Carrying Value usd 14557000000 NA 2014-12-31
Marketable Securities, Current usd 3789000000 NA 2013-12-31
Marketable Securities, Current usd 2859000000 NA 2014-12-31

Flujo de Efectivo

options(HTTPUserAgent = "a a@gmail.com")
kable(head(GetCashFlow("AAPL", 2014)))%>% kable_paper(full_width=T, "hover")
Metric Units Amount startDate endDate
Depreciation, Amortization and Accretion, Net iso4217_USD 6757000000 2012-09-30 2013-09-28
Depreciation, Amortization and Accretion, Net iso4217_USD 7946000000 2013-09-29 2014-09-27
Depreciation, Amortization and Accretion, Net iso4217_USD 3277000000 2011-09-25 2012-09-29
Share-based Compensation iso4217_USD 2253000000 2012-09-30 2013-09-28
Share-based Compensation iso4217_USD 2863000000 2013-09-29 2014-09-27
Share-based Compensation iso4217_USD 1740000000 2011-09-25 2012-09-29

| Actividad de Equipo: Series de tiempo Empresas

Se seleccionó a Netflix para realizar el análisis financiero. Se extraerá información de los años 2015 a 2018 para obtener 6 años de datos, de esta manera es que se podrá tener la mayor información posible para realizar los pronósticos.

Análisis financiero

Extracción de datos

options(HTTPUserAgent = "a a@gmail.com")
netflix18<- GetIncome("NFLX", 2018)
netflix15<- GetIncome("NFLX", 2015)

Transformación de datos

## Cambio de datos 
netflix15$Metric<- as.factor(netflix15$Metric)
netflix18$Metric<- as.factor(netflix18$Metric)

kable(head(netflix15))%>% kable_paper(full_width=T, "hover")
Metric Units Amount startDate endDate
Revenues usd 3609282000 2012-01-01 2012-12-31
Revenues usd 1023961000 2013-01-01 2013-03-31
Revenues usd 1069372000 2013-04-01 2013-06-30
Revenues usd 1105999000 2013-07-01 2013-09-30
Revenues usd 1175230000 2013-10-01 2013-12-31
Revenues usd 4374562000 2013-01-01 2013-12-31
kable(head(netflix18))%>% kable_paper(full_width=T, "hover")
Metric Units Amount startDate endDate
Revenues usd 6779511000 2015-01-01 2015-12-31
Revenues usd 1957736000 2016-01-01 2016-03-31
Revenues usd 2105204000 2016-04-01 2016-06-30
Revenues usd 2290188000 2016-07-01 2016-09-30
Revenues usd 2477541000 2016-10-01 2016-12-31
Revenues usd 8830669000 2016-01-01 2016-12-31

En este punto ya se cuenta con dos bases de datos diferentes, una del 2015 que incluye datos del 2012 al 2014 y una del 2018 que incluye datos del 2015 a 2017

Marketing Expense

Selección de Métrica a Analizar

marketing_netflix1 <- netflix15[netflix15$Metric == "Marketing Expense",]
marketing_netflix2<- netflix18[netflix18$Metric== "Marketing Expense",]

marketing<- rbind(marketing_netflix1, marketing_netflix2)

marketing$Amount<- as.numeric(marketing$Amount)

kable(head(marketing))%>% kable_paper(full_width=T, "hover")
Metric Units Amount startDate endDate
15 Marketing Expense usd 439208000 2012-01-01 2012-12-31
16 Marketing Expense usd 469942000 2013-01-01 2013-12-31
17 Marketing Expense usd 607186000 2014-01-01 2014-12-31
151 Marketing Expense usd 824092000 2015-01-01 2015-12-31
161 Marketing Expense usd 991078000 2016-01-01 2016-12-31
171 Marketing Expense usd 1278022000 2017-01-01 2017-12-31

Se seleccionó solo la métrica a analizar que corresponde a “Marketing Expenses” para después unir datos a través de las filas, de esta manera se contaron con los datos ordenados.

Datos TS

tsNetflix<- ts(data=marketing$Amount, start=c(2012,1), frequency=1)
tsNetflix
## Time Series:
## Start = 2012 
## End = 2017 
## Frequency = 1 
## [1]  439208000  469942000  607186000  824092000  991078000 1278022000

Modelado

ARIMA

netflix_arima<- auto.arima(tsNetflix)
summary(netflix_arima)
## Series: tsNetflix 
## ARIMA(0,1,0) with drift 
## 
## Coefficients:
##           drift
##       167762800
## s.e.   38132573
## 
## sigma^2 = 9.082e+15:  log likelihood = -98.4
## AIC=200.8   AICc=206.8   BIC=200.02
## 
## Training set error measures:
##                    ME     RMSE      MAE       MPE     MAPE      MASE       ACF1
## Training set 45240.85 77811930 56153374 -3.152125 8.268978 0.3347189 0.06935673

Este modelo tiene un solo factor diferenciado para realizarlo estacionario, de esta manera es que consigue su modelo óptimo aunque el RMSE presenta valores muy altos.

netflix_for<- forecast(netflix_arima, level= c(95), h=5)
kable(netflix_for) %>% kable_paper("hover")
Point Forecast Lo 95 Hi 95
2018 1445784800 1259000698 1632568902
2019 1613547600 1349394990 1877700210
2020 1781310400 1457790845 2104829955
2021 1949073200 1575504996 2322641404
2022 2116836000 1699174051 2534497949
plot(netflix_for)

Para el pronóstico del gasto de Marketing de Netflix se puede observar que para los próximos 5 años se tendrá un crecimiento en tendencia de los gastos.

Revenue

En este punto ya se cuenta con dos bases de datos diferentes, una del 2015 que incluye datos del 2012 al 2014 y una del 2018 que incluye datos del 2015 a 2017

Selección de Métrica a Analizar

rev_netflix1 <- netflix15[netflix15$Metric == "Revenues",]
rev_netflix2<- netflix18[netflix18$Metric== "Revenues",]

revenue<- rbind(rev_netflix1, rev_netflix2)

revenue$Amount<- as.numeric(revenue$Amount)

revenue<- revenue[-c(2:5, 7:10,13:16, 18:21),]


kable(head(revenue))%>% kable_paper(full_width=T, "hover")
Metric Units Amount startDate endDate
1 Revenues usd 3609282000 2012-01-01 2012-12-31
6 Revenues usd 4374562000 2013-01-01 2013-12-31
11 Revenues usd 5504656000 2014-01-01 2014-12-31
12 Revenues usd 6779511000 2015-01-01 2015-12-31
17 Revenues usd 8830669000 2016-01-01 2016-12-31
22 Revenues usd 11692713000 2017-01-01 2017-12-31

Se seleccionó solo la métrica a analizar que corresponde a “Revenues” para después unir datos a través de las filas, de esta manera se contaron con los datos ordenados.

Datos TS

tsNetflix_rev<- ts(data=revenue$Amount, start=c(2012,1), frequency=1)
tsNetflix_rev
## Time Series:
## Start = 2012 
## End = 2017 
## Frequency = 1 
## [1]  3609282000  4374562000  5504656000  6779511000  8830669000 11692713000

Modelado

ARIMA

netflix_arima2<- auto.arima(tsNetflix_rev)
summary(netflix_arima2)
## Series: tsNetflix_rev 
## ARIMA(0,2,0) 
## 
## sigma^2 = 3.536e+17:  log likelihood = -86.49
## AIC=174.98   AICc=176.98   BIC=174.37
## 
## Training set error measures:
##                     ME      RMSE       MAE      MPE     MAPE      MASE
## Training set 349207831 485496286 350251542 4.076958 4.100816 0.2166478
##                   ACF1
## Training set 0.3276528

Este modelo tiene un solo factor diferenciado para realizarlo estacionario, de esta manera es que consigue su modelo óptimo aunque el RMSE presenta valores muy altos.

netflix_for2<- forecast(netflix_arima2, level= c(95), h=5)
kable(netflix_for2) %>% kable_paper("hover")
Point Forecast Lo 95 Hi 95
2018 14554757000 13389344605 15720169395
2019 17416801000 14810859663 20022742337
2020 20278845000 15918271104 24639418896
2021 23140889000 16757662426 29524115574
2022 26002933000 17360003361 34645862639
plot(netflix_for2)

Como se puede observar, el modelo de pronósticos presenta una tendencia positiva de utilidades (revenue) para los próximos 5 años. Aunque no se puede hablar de una causalidad directa entre el gasto de mercadotecnia y las utilidades, si se puede observar como es que ambas variables presentan un comportamiento similar para los próximos años.

LS0tDQp0aXRsZTogIlRhcmVhIDI6IEludGVncmFjacOzbiBkZSBUZW1hIDIiDQphdXRob3I6ICJBc3RyaWQgUGFvbGEgR29uesOhbGV6IETDrWF6IC0gQTAwODMwMTE0Ig0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBybWRmb3JtYXRzOjpkb3duY3V0ZToNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIGRlZmF1bHRfc3R5bGU6ICJsaWdodCINCiAgICBkb3duY3V0ZV90aGVtZTogImRlZmF1bHQiDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyMgR2xvYmFsIG9wdGlvbnMNCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCB0aWR5ID0gVFJVRSkNCmBgYA0KDQoqKlRhcmVhcyBlbiBlcXVpcG8gcmVhbGl6YWRhcyBwb3I6KioNCg0KLSAgIEFuYSBMw7NwZXoNCg0KLSAgIEFzdHJpZCBHb256w6FsZXoNCg0KLSAgIFNhbnRpYWdvIEdvbnrDoWxleg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBUZW1hIDI6ICoqVGltZSBTZXJpZXMqKg0KDQojIyBJbnRyb2R1Y2Npw7NuDQoNClVuYSAqKnNlcmllIGRlIHRpZW1wbyoqIGVzIHVuYSBjb2xlY2Npw7NuIGRlIG9ic2VydmFjaW9uZXMgc29icmUgdW4gZGV0ZXJtaW5hZG8gZmVuw7NtZW5vLCBlZmVjdHVhZGFzIGVuIG1vbWVudG9zIHN1Y2VzaXZvcywgdXN1YWxtZW50ZSAqZXF1aWVzcGFjZWFkb3MqLg0KDQoqQWxndW5vcyBlamVtcGxvcyBkZSBzZXJpZXMgZGUgdGllbXBvIHNvbjoqXA0KMS4gUHJlY2lvcyBkZSBhY2Npb25lc1wNCjIuIE5pdmVsZXMgZGUgaW52ZW50YXJpb3NcDQozLiBSb3RhY2nDs24gZGUgcGVyc29uYWxcDQo0LiBWZW50YXNcDQo1LiBQSUIgbyBHRFANCg0KKk1hcyBpbmZvcm1hY2nDs246Kg0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0zODg4Njc0MzkxLnBuZyl7d2lkdGg9IjE2MiJ9W0xpYnJvICpSIGZvciBEYXRhIFNjaWVuY2UgKDJlKSpdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnopDQoNCiMjIEVqZXJjaWNpbyBlbiBDbGFzZQ0KDQojIyMjIExpYnJlcsOtYXMgTmVjZXNhcmlhcw0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmBgYA0KDQojIyBEYXRvcyBUUw0KDQoqKkVqZW1wbG86KipcDQpMb3Mgc2lndWllbnRlcyBkYXRvcyBkZSBwcm9kdWNjacOzbiBpbmljaWFsIGluaWNpYW4gZW4gZWwgcHJpbWVyIHRyaW1lc3RyZSBkZWwgMjAyMC4gU2UgYnVzY2EgcHJvbm9zdGljYXIgbGEgcHJvZHVjY2nDs24gZGUgbG9zIHNpZ3VpZW50ZXMgNSB0cmltZXN0cmVzLg0KDQpgYGB7cn0NCnByb2R1Y2Npw7NuIDwtIGMoNTAsNTMsNTUsNTcsNTUsNjApDQoNCnRzPC0gdHMoZGF0YT0gcHJvZHVjY2nDs24sIHN0YXJ0ID0gYygyMDIwLDEpLCBmcmVxdWVuY3kgPSA0KQ0KdHMNCmBgYA0KDQpTZSBjcmVhcm9uIGRhdG9zICpkdW1teSogcGFyYSByZWFsaXphciBlbCBwcmltZXIgbW9kZWxhZG8gZGUgZWplbXBsbyBkZSBUaW1lIFNlcmllcywgcG9yIGVzdGEgcmF6w7NuIGVzIHF1ZSBzZSBkZWxpbWl0YW5yb24gYmFqbyB1bmEgY3JlYWNpw7NuIG1hbnVhbCBkZSB2ZWN0b3IuIERlc3B1w6lzIHNlIGRlbGltaXTDsyB1biBjb21pZW56byBkZSBsYSBmZWNoYSBlbiAyMDIwIGVuIGVsIHByaW1lciB0cmltZXN0cmUuDQoNCiMjIE1vZGVsYWRvDQoNCiMjIyBBUklNQQ0KDQpFbCBtb2RlbGFkbyAqKkFSSU1BKiogc2lnbmlmaWNhICpBdXRvUmVncmVzc2l2ZSBJbnRlZ3JhdGVkIE1vdmluZyBBdmVyYWdlKiBvIE1vZGVsbyBBdXRvci1yZWdyZXNpdm8gSW50ZWdyYWRvIGRlIFByb21lZGlvIE3Ds3ZpbC4NCg0KYGBge3J9DQphcmltYTwtIGF1dG8uYXJpbWEodHMsIEQ9MSkNCmFyaW1hDQpzdW1tYXJ5KGFyaW1hKQ0KYGBgDQoNCkVuIGVzdGUgcHJpbWVyIG1vZGVsbyBzZSBwdWVkZSBvYnNlcnZhciBjb21vIGVzIHF1ZSBlbCBxdWUgcHJlc2VudGEgdW4gbWVqb3IgZGVzZW1wZcOxbyBlbiBsYSBpdGVyYWNpw7NuIGludGVybmEuIERlIGVzdGEgbWFuZXJhIGVzIHF1ZSBzZSBvYnRpZW5lIHVuIG1vZGVsbyBBUklNQSAoMCwwLDApKDAsMSwwKVs0XSBkb25kZSBzZSBkaWNlIHF1ZSBubyBoYXkgdMOpcm1pbm9zIGRlIGF1dG9yLXJlZ3Jlc2nDs24gYXPDrSBjb21vIG5vIGhheSB0w6lybWlub3MgZGUgcHJvbWVkaW8gbcOzdmlsIGVuIGVsIG1vZGVsbyDigJMgbm8gdXRpbGl6YSBsb3MgdmFsb3JlcyBhbnRlcmlvcmVzIGRlIGxhIHNlcmllIG5pIGxvcyBlcnJvcmVzIHByZXZpb3MgcGFyYSBoYWNlciBwcmVkaWNjaW9uZXMuIEFkZW3DoXMgaW5kaWNhIHF1ZSBoYXkgdW4gc29sbyB0w6lybWlubyBkZSBkaWZlcmVuY2lhIGRlIHByaW1lciBvcmRlbiDigJMgcXVlIGxhIHNlcmllIHRlbXBvcmFsIG9yaWdpbmFsIGZ1ZSBkaWZlcmVuY2lhZGEgdW5hIHZleiBwYXJhIGhhY2VybGEgZXN0YWNpb25hcmlhLiBNdWVzdHJhIGNvbiBlbCBbNF0gcXVlIGhheSB1bmEgZXN0YWNpb25hbGlkYWQgZW4gNCB1bmlkYWRlcyBkZSB0aWVtcG8geSBxdWUgc2UgaW5jbHV5w7MgdW4gdMOpcm1pbm8gZGUgZGVyaXZhIGVuIGVsIG1vZGVsbyBwYXJhIGNvbnRhciBjb24gdW5hIHRlbmRlbmNpYSBsaW5lYWwuDQoNCiMjIEdlbmVyYWNpw7NuIGRlIHByb27Ds3N0aWNvDQoNCmBgYHtyfQ0KcHJvbm9zdGljbzwtIGZvcmVjYXN0KGFyaW1hLCBsZXZlbCA9IGMoOTUpLCBoPTUpDQpwcm9ub3N0aWNvDQoNCnBsb3QocHJvbm9zdGljbykNCmBgYA0KDQpFbiBlc3RlIGNhc28gc2UgcHJlc2VudGEgdW4gcHJvbsOzc3RpY28gY29uIHVuIG5pdmVsIGRlIGNvbmZpYW56YSBkZSA5NSUgcGFyYSBsb3Mgc2lndWllbnRlcyA1IHRyaW1lc3RyZXMsIHNlIG9ic2VydmEgdW5hIHRlbmRlbmNpYSBsaW5lYWwgcXVlIHNpZ3VlIGVuIGNpZXJ0YSBtYW5lcmEgbG9zIHZhbG9yZXMgeSBwYXRyb25lcyBxdWUgc2UgbW9zdHJhYmFuIGVuIGxvcyB2YWxvcmVzIHJlYWxlcy4NCg0KIyAhW10oZnRJTWRvelBJTGRsLmdpZil7d2lkdGg9IjY4In1cfCBBY3RpdmlkYWQgMjogKipIZXJzaGV5wrRzKioNCg0KIyMgRGF0b3MgVFMNCg0KKipFamVtcGxvOioqXA0KTG9zIHNpZ3VpZW50ZXMgZGF0b3Mgc29uIGRlIHZlbnRhcyBkZSAibGVjaGVzIiBIZXJzZWh5wrRzIGRvbmRlIGNvbWllbnphIGVuIDIwMTcgZHVyYW50ZSBFbmVybyBwYXJhIGRlc3B1w6lzIGFsbWFjZW5hciBpbmZvcm1hY2nDs24gbWVuc3VhbC5cDQoNCmBgYHtyfQ0KbGVjaGl0YTwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9Bc3RyaWQgR29uemFsZXovRG9jdW1lbnRzL1VOSVZFUlNJREFEL09DVEFWTy9HZW5lcmFjacOzbiBkZSBlc2NlbmFyaW9zIGZ1dHVyb3MgY29uIGFuYWzDrXRpY2EvTcOzZHVsbyAxL1ZlbnRhc19IaXN0w7NyaWNhc19MZWNoaXRhcy5jc3YiKQ0Ka2FibGUoaGVhZChsZWNoaXRhKSkgJT4lIGthYmxlX3BhcGVyKGZ1bGxfd2lkdGg9IFQsICJob3ZlciIpDQpgYGANCg0KYGBge3J9DQp0czE8LSB0cyhkYXRhPWxlY2hpdGEkVmVudGFzLCBzdGFydD1jKDIwMTcsMSksIGZyZXF1ZW5jeT0xMikNCih0czEpDQpgYGANCg0KIyMgTW9kZWxhZG8NCg0KIyMjIEFSSU1BDQoNCmBgYHtyfQ0KYXJpbWExPC0gYXV0by5hcmltYSh0czEsIEQ9MSkNCmFyaW1hMQ0Kc3VtbWFyeShhcmltYTEpDQpgYGANCg0KRXN0ZSBtb2RlbG8gcHJlc2VudGEgdW4gKlJvb3QgTWVhbiBTcXVhcmVkIEVycm9yKiBkZSAzNDMuODYgZGUgdmVudGFzLCB0b21hbmRvIGVuIGN1ZW50YSBsYSBkaW1lbnNpw7NuIGRlIGxvcyBuw7ptZXJvcyBvcmlnaW5hbGVzIHNlIHBvZHLDrWEgZGVjaXIgcXVlIGVzIHVuIGJ1ZW4gbW9kZWxvIGNvbiBlcnJvciBiYWpvLiBBZGVtw6FzIGVzdGUgbW9kZWxvIGVzdMOhIHRvbWFuZG8gZW4gY3VlbnRhIHVuIHZhbG9yIHByZXZpbyBkZSBsYSBzZXJpZSB0ZW1wb3JhbCBwYXJhIHByZWRlY2lyIGVsIHNpZ3VpZW50ZSB2YWxvciBhc8OtIGNvbW8gdW4gdMOpcm1pbm8gZGUgZGlmZXJlbmNpYSBkZSBwcmltZXIgb3JkZW4gZW4gbGFzIHNlcmllIHRlbXBvcmFsIHkgdW4gdMOpcm1pbm8gYXV0by1yZWdyZXNpdm8gZGUgcHJpbWVyIG9yZGVuIGVuIGxhIHNlcmllIGRlIGxhcyBkaWZlcmVuY2lhcywgYWRlbcOhcyBwcmVzZW50YSB1bmEgZXN0YWNpb25hbGlkYWQgY2FkYSAxMiBwZXJpb2RvcyDigJMgZXMgZGVjaXIgdW4gcGF0csOzbiBkZSBjb21wb3J0YW1pZW50byDigJMgeSBzZSBpbmNsdXllIHVuIHTDqXJtaW5vIGRlIGRlcml2YSBxdWUgcGVybWl0ZSB1bmEgdGVuZGVuY2lhIGxpbmVhbCBlbiBlbCB0aWVtcG8uDQoNCiMjIEdlbmVyYWNpw7NuIGRlIHByb27Ds3N0aWNvDQoNCmBgYHtyfQ0KcHJvbm9zdGljbzE8LSBmb3JlY2FzdChhcmltYTEsIGxldmVsID0gYyg5NSksIGg9NSkNCnByb25vc3RpY28xDQoNCnBsb3QocHJvbm9zdGljbzEpDQpgYGANCg0KRW4gZXN0ZSBtb2RlbG8gc2UgcHJlc2VudGEgdW4gbml2ZWwgZGUgY29uZmlhbnphIGRlIDk1JSB5IHVuYSB2ZW50YW5hIGRlIHByZWRpY2Npw7NuIGRlIGxvcyBzaWd1aWVudGVzIDUgcGVyaW9kb3MsIGVuIGVzdGUgY2FzbyBhbCBzZXIgZGF0b3MgbWVuc3VhbGVzLCBzZSBwcm9ub3N0aWNhbiBsb3Mgc2lndWllbnRlcyA1IG1lc2VzLg0KDQojICFbXShnaXBoeSUyMCgyKS5naWYpe3dpZHRoPSI2MCJ9XHwgQWN0aXZpZGFkIDM6ICoqRmluYW56YXMgQ29ycG9yYXRpdmFzKioNCg0KIyMjIExpYnJlcsOtYXMgTmVjZXNhcmlhcw0KDQpgYGB7cn0NCmxpYnJhcnkoZmlucmVwb3J0cikNCmBgYA0KDQojIyMgSW5mb3JtYWNpw7NuIGRpc3BvbmlibGUNCg0KQ29uIGxhIGZ1bmNpw7NuICpmaW5yZXBvcnRyKiBwb2RlbW9zIG9idGVuZXIgbGEgc2lndWllbnRlIGluZm9ybWFjacOzbjpcDQoNCi0gICBDb21wYW55SW5mbygpPSBicmluZGEgaW5mb3JtYWNpw7NuIGdlbmVyYWwgY29tbyBub21icmUsIHViaWNhY2nDs24sIFpJUCwgZXRjLg0KDQotICAgQW5udWFsUmVwb3J0cygpID0gYnJpbmRhIGVsIG5vbWJyZSwgZmVjaGEgeSBuw7ptZXJvIGRlIGFjY2Vzby4NCg0KLSAgIEdldEluY29tZSgpPSBicmluZGEgZWwgZXN0YWRvIGRlIHJlc3VsdGFkb3MuDQoNCi0gICBHZXRCYWxhbmNlU2hlZXQoKSA9IEJyaW5kYSBlbCBiYWxhbmNlIGdlbmVyYWwuDQoNCi0gICBHZXRDYXNoRmxvdygpPSBCcmluZGEgZWwgZmx1am8gZGUgZWZlY3Rpdm8uDQoNCiMjIEV4dHJhY2Npw7NuIGRlIGluZm9ybWFjacOzbg0KDQojIyBJbmZvcm1hY2nDs24gZGUgbGEgY29tcGHDscOtYQ0KDQpgYGB7cn0NCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJhIGFAZ21haWwuY29tIikNCg0Ka2FibGUoQ29tcGFueUluZm8oIkpQTSIpKSAlPiUga2FibGVfcGFwZXIoICJob3ZlciIpDQoNCmBgYA0KDQojIyBSZXBvcnRlcyBBbnVhbA0KDQpgYGB7cn0NCg0Ka2FibGUoaGVhZChBbm51YWxSZXBvcnRzKCJCQUJBIiwgZm9yZWlnbiA9IFRSVUUpKSkgJT4lIGthYmxlX3BhcGVyKGZ1bGxfd2lkdGg9VCwgImhvdmVyIikNCmBgYA0KDQojIyBFc3RhZG8gZGUgcmVzdWx0YWRvcw0KDQpgYGB7cn0NCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJhIGFAZ21haWwuY29tIikNCmthYmxlKGhlYWQoR2V0SW5jb21lKCJHT09HIiwgMjAxOCkpKSU+JSBrYWJsZV9wYXBlcihmdWxsX3dpZHRoPVQsICJob3ZlciIpDQpgYGANCg0KIyMgQmFsYW5jZSBHZW5lcmFsDQoNCmBgYHtyfQ0Kb3B0aW9ucyhIVFRQVXNlckFnZW50ID0gImEgYUBnbWFpbC5jb20iKQ0Ka2FibGUoaGVhZChHZXRCYWxhbmNlU2hlZXQoIkFNWk4iLCAyMDE1KSkpJT4lIGthYmxlX3BhcGVyKGZ1bGxfd2lkdGg9VCwgImhvdmVyIikNCmBgYA0KDQojIyBGbHVqbyBkZSBFZmVjdGl2bw0KDQpgYGB7cn0NCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJhIGFAZ21haWwuY29tIikNCmthYmxlKGhlYWQoR2V0Q2FzaEZsb3coIkFBUEwiLCAyMDE0KSkpJT4lIGthYmxlX3BhcGVyKGZ1bGxfd2lkdGg9VCwgImhvdmVyIikNCmBgYA0KDQojICFbXShuZXRmbGl4LmdpZil7d2lkdGg9IjcwIn1cfCBBY3RpdmlkYWQgZGUgRXF1aXBvOiAqKlNlcmllcyBkZSB0aWVtcG8gRW1wcmVzYXMqKg0KDQpTZSBzZWxlY2Npb27DsyBhIE5ldGZsaXggcGFyYSByZWFsaXphciBlbCBhbsOhbGlzaXMgZmluYW5jaWVyby4gU2UgZXh0cmFlcsOhIGluZm9ybWFjacOzbiBkZSBsb3MgYcOxb3MgMjAxNSBhIDIwMTggcGFyYSBvYnRlbmVyIDYgYcOxb3MgZGUgZGF0b3MsIGRlIGVzdGEgbWFuZXJhIGVzIHF1ZSBzZSBwb2Ryw6EgdGVuZXIgbGEgbWF5b3IgaW5mb3JtYWNpw7NuIHBvc2libGUgcGFyYSByZWFsaXphciBsb3MgcHJvbsOzc3RpY29zLg0KDQojIyBBbsOhbGlzaXMgZmluYW5jaWVybw0KDQoNCiMjIyBFeHRyYWNjacOzbiBkZSBkYXRvcw0KDQpgYGB7cn0NCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJhIGFAZ21haWwuY29tIikNCm5ldGZsaXgxODwtIEdldEluY29tZSgiTkZMWCIsIDIwMTgpDQpuZXRmbGl4MTU8LSBHZXRJbmNvbWUoIk5GTFgiLCAyMDE1KQ0KYGBgDQoNCiMjIyBUcmFuc2Zvcm1hY2nDs24gZGUgZGF0b3MNCg0KYGBge3J9DQojIyBDYW1iaW8gZGUgZGF0b3MgDQpuZXRmbGl4MTUkTWV0cmljPC0gYXMuZmFjdG9yKG5ldGZsaXgxNSRNZXRyaWMpDQpuZXRmbGl4MTgkTWV0cmljPC0gYXMuZmFjdG9yKG5ldGZsaXgxOCRNZXRyaWMpDQoNCmthYmxlKGhlYWQobmV0ZmxpeDE1KSklPiUga2FibGVfcGFwZXIoZnVsbF93aWR0aD1ULCAiaG92ZXIiKQ0Ka2FibGUoaGVhZChuZXRmbGl4MTgpKSU+JSBrYWJsZV9wYXBlcihmdWxsX3dpZHRoPVQsICJob3ZlciIpDQpgYGANCg0KRW4gZXN0ZSBwdW50byB5YSBzZSBjdWVudGEgY29uIGRvcyBiYXNlcyBkZSBkYXRvcyBkaWZlcmVudGVzLCB1bmEgZGVsIDIwMTUgcXVlIGluY2x1eWUgZGF0b3MgZGVsIDIwMTIgYWwgMjAxNCB5IHVuYSBkZWwgMjAxOCBxdWUgaW5jbHV5ZSBkYXRvcyBkZWwgMjAxNSBhIDIwMTcNCg0KIyMgTWFya2V0aW5nIEV4cGVuc2UNCiMjIyBTZWxlY2Npw7NuIGRlIE3DqXRyaWNhIGEgQW5hbGl6YXINCg0KYGBge3J9DQoNCm1hcmtldGluZ19uZXRmbGl4MSA8LSBuZXRmbGl4MTVbbmV0ZmxpeDE1JE1ldHJpYyA9PSAiTWFya2V0aW5nIEV4cGVuc2UiLF0NCm1hcmtldGluZ19uZXRmbGl4MjwtIG5ldGZsaXgxOFtuZXRmbGl4MTgkTWV0cmljPT0gIk1hcmtldGluZyBFeHBlbnNlIixdDQoNCm1hcmtldGluZzwtIHJiaW5kKG1hcmtldGluZ19uZXRmbGl4MSwgbWFya2V0aW5nX25ldGZsaXgyKQ0KDQptYXJrZXRpbmckQW1vdW50PC0gYXMubnVtZXJpYyhtYXJrZXRpbmckQW1vdW50KQ0KDQprYWJsZShoZWFkKG1hcmtldGluZykpJT4lIGthYmxlX3BhcGVyKGZ1bGxfd2lkdGg9VCwgImhvdmVyIikNCg0KYGBgDQoNClNlIHNlbGVjY2lvbsOzIHNvbG8gbGEgbcOpdHJpY2EgYSBhbmFsaXphciBxdWUgY29ycmVzcG9uZGUgYSAqIk1hcmtldGluZyBFeHBlbnNlcyIqIHBhcmEgZGVzcHXDqXMgdW5pciBkYXRvcyBhIHRyYXbDqXMgZGUgbGFzIGZpbGFzLCBkZSBlc3RhIG1hbmVyYSBzZSBjb250YXJvbiBjb24gbG9zIGRhdG9zIG9yZGVuYWRvcy4NCg0KIyMgRGF0b3MgVFMNCg0KYGBge3J9DQp0c05ldGZsaXg8LSB0cyhkYXRhPW1hcmtldGluZyRBbW91bnQsIHN0YXJ0PWMoMjAxMiwxKSwgZnJlcXVlbmN5PTEpDQp0c05ldGZsaXgNCmBgYA0KDQojIyBNb2RlbGFkbw0KDQojIyMgQVJJTUENCg0KYGBge3J9DQoNCm5ldGZsaXhfYXJpbWE8LSBhdXRvLmFyaW1hKHRzTmV0ZmxpeCkNCnN1bW1hcnkobmV0ZmxpeF9hcmltYSkNCmBgYA0KDQpFc3RlIG1vZGVsbyB0aWVuZSB1biBzb2xvIGZhY3RvciBkaWZlcmVuY2lhZG8gcGFyYSByZWFsaXphcmxvIGVzdGFjaW9uYXJpbywgZGUgZXN0YSBtYW5lcmEgZXMgcXVlIGNvbnNpZ3VlIHN1IG1vZGVsbyDDs3B0aW1vIGF1bnF1ZSBlbCBSTVNFIHByZXNlbnRhIHZhbG9yZXMgbXV5IGFsdG9zLg0KDQpgYGB7cn0NCm5ldGZsaXhfZm9yPC0gZm9yZWNhc3QobmV0ZmxpeF9hcmltYSwgbGV2ZWw9IGMoOTUpLCBoPTUpDQprYWJsZShuZXRmbGl4X2ZvcikgJT4lIGthYmxlX3BhcGVyKCJob3ZlciIpDQpgYGANCg0KYGBge3J9DQpwbG90KG5ldGZsaXhfZm9yKQ0KYGBgDQoNClBhcmEgZWwgcHJvbsOzc3RpY28gZGVsIGdhc3RvIGRlIE1hcmtldGluZyBkZSBOZXRmbGl4IHNlIHB1ZWRlIG9ic2VydmFyIHF1ZSBwYXJhIGxvcyBwcsOzeGltb3MgNSBhw7FvcyBzZSB0ZW5kcsOhIHVuIGNyZWNpbWllbnRvIGVuIHRlbmRlbmNpYSBkZSBsb3MgZ2FzdG9zLg0KDQojIyBSZXZlbnVlDQoNCkVuIGVzdGUgcHVudG8geWEgc2UgY3VlbnRhIGNvbiBkb3MgYmFzZXMgZGUgZGF0b3MgZGlmZXJlbnRlcywgdW5hIGRlbCAyMDE1IHF1ZSBpbmNsdXllIGRhdG9zIGRlbCAyMDEyIGFsIDIwMTQgeSB1bmEgZGVsIDIwMTggcXVlIGluY2x1eWUgZGF0b3MgZGVsIDIwMTUgYSAyMDE3DQoNCiMjIyBTZWxlY2Npw7NuIGRlIE3DqXRyaWNhIGEgQW5hbGl6YXINCg0KYGBge3J9DQoNCnJldl9uZXRmbGl4MSA8LSBuZXRmbGl4MTVbbmV0ZmxpeDE1JE1ldHJpYyA9PSAiUmV2ZW51ZXMiLF0NCnJldl9uZXRmbGl4MjwtIG5ldGZsaXgxOFtuZXRmbGl4MTgkTWV0cmljPT0gIlJldmVudWVzIixdDQoNCnJldmVudWU8LSByYmluZChyZXZfbmV0ZmxpeDEsIHJldl9uZXRmbGl4MikNCg0KcmV2ZW51ZSRBbW91bnQ8LSBhcy5udW1lcmljKHJldmVudWUkQW1vdW50KQ0KDQpyZXZlbnVlPC0gcmV2ZW51ZVstYygyOjUsIDc6MTAsMTM6MTYsIDE4OjIxKSxdDQoNCg0Ka2FibGUoaGVhZChyZXZlbnVlKSklPiUga2FibGVfcGFwZXIoZnVsbF93aWR0aD1ULCAiaG92ZXIiKQ0KDQpgYGANCg0KU2Ugc2VsZWNjaW9uw7Mgc29sbyBsYSBtw6l0cmljYSBhIGFuYWxpemFyIHF1ZSBjb3JyZXNwb25kZSBhICoiUmV2ZW51ZXMiKiBwYXJhIGRlc3B1w6lzIHVuaXIgZGF0b3MgYSB0cmF2w6lzIGRlIGxhcyBmaWxhcywgZGUgZXN0YSBtYW5lcmEgc2UgY29udGFyb24gY29uIGxvcyBkYXRvcyBvcmRlbmFkb3MuDQoNCiMjIERhdG9zIFRTDQoNCmBgYHtyfQ0KdHNOZXRmbGl4X3JldjwtIHRzKGRhdGE9cmV2ZW51ZSRBbW91bnQsIHN0YXJ0PWMoMjAxMiwxKSwgZnJlcXVlbmN5PTEpDQp0c05ldGZsaXhfcmV2DQpgYGANCg0KIyMgTW9kZWxhZG8NCg0KIyMjIEFSSU1BDQoNCmBgYHtyfQ0KDQpuZXRmbGl4X2FyaW1hMjwtIGF1dG8uYXJpbWEodHNOZXRmbGl4X3JldikNCnN1bW1hcnkobmV0ZmxpeF9hcmltYTIpDQpgYGANCg0KRXN0ZSBtb2RlbG8gdGllbmUgdW4gc29sbyBmYWN0b3IgZGlmZXJlbmNpYWRvIHBhcmEgcmVhbGl6YXJsbyBlc3RhY2lvbmFyaW8sIGRlIGVzdGEgbWFuZXJhIGVzIHF1ZSBjb25zaWd1ZSBzdSBtb2RlbG8gw7NwdGltbyBhdW5xdWUgZWwgUk1TRSBwcmVzZW50YSB2YWxvcmVzIG11eSBhbHRvcy4NCg0KYGBge3J9DQpuZXRmbGl4X2ZvcjI8LSBmb3JlY2FzdChuZXRmbGl4X2FyaW1hMiwgbGV2ZWw9IGMoOTUpLCBoPTUpDQprYWJsZShuZXRmbGl4X2ZvcjIpICU+JSBrYWJsZV9wYXBlcigiaG92ZXIiKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChuZXRmbGl4X2ZvcjIpDQpgYGANCg0KQ29tbyBzZSBwdWVkZSBvYnNlcnZhciwgZWwgbW9kZWxvIGRlIHByb27Ds3N0aWNvcyBwcmVzZW50YSB1bmEgdGVuZGVuY2lhIHBvc2l0aXZhIGRlIHV0aWxpZGFkZXMgKHJldmVudWUpIHBhcmEgbG9zIHByw7N4aW1vcyA1IGHDsW9zLiBBdW5xdWUgbm8gc2UgcHVlZGUgaGFibGFyIGRlIHVuYSBjYXVzYWxpZGFkIGRpcmVjdGEgZW50cmUgZWwgZ2FzdG8gZGUgbWVyY2Fkb3RlY25pYSB5IGxhcyB1dGlsaWRhZGVzLCBzaSBzZSBwdWVkZSBvYnNlcnZhciBjb21vIGVzIHF1ZSBhbWJhcyB2YXJpYWJsZXMgcHJlc2VudGFuIHVuIGNvbXBvcnRhbWllbnRvIHNpbWlsYXIgcGFyYSBsb3MgcHLDs3hpbW9zIGHDsW9zLiA=