Explicación en clase: Teoría y Ejemplo de Producción Trimestral.

Concepto

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

Ejemplos de series de tiempo:

  1. Precios de acciones

  2. Niveles de inventario

  3. Rotación de personal

  4. Ventas

  5. PIB(GDP)

Mas información: Libro de R

Instalar paquetes

library(readr)
library(readxl)
library(forecast)
library(finreportr)
library(dplyr)
library(tidyverse)
library(tidyr)

Crear la serie de tiempo

Ejemplo: Los siguientes datos de produccion trimestral inician en el primer trimestre del 2020.

Se busca pronosticar la producción de los siguientes 5 trimestres.

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

Crear un modelo ARIMA

ARIMA significa Autoregressive Integraded moving average o Modelo Autorregresivo integrado de promedio movil.

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

Generar el pronóstico

pronostico <- forecast(arima,level=c(95), h=5)
pronostico
##         Point Forecast    Lo 95    Hi 95
## 2022 Q1             61 58.22127 63.77873
## 2022 Q2             63 60.22127 65.77873
## 2022 Q3             61 58.22127 63.77873
## 2022 Q4             66 63.22127 68.77873
## 2023 Q1             67 63.07028 70.92972
plot(pronostico)

En este ejercicio se puede ver un crecimiento para los siguientes periodos de la línea de tiempo. Se mentiene la tendencia de altibajos en los semestres contiguos y aún en los escenarios pesimistas existe un avance en la producción estimada.

Actividad Hershey’s: Importar base de datos y crear serie de tiempo, modelo ARIMA y pronóstico.

Importar base de datos

lechitas <- read_excel("Lechitas.xlsx")
ts1 <- ts(data = lechitas$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

Crear un modelo ARIMA

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

pronostico2 <- forecast(arimax, h=12)
pronostico2
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2020       35498.90 34921.91 36075.88 34616.48 36381.32
## Feb 2020       34202.17 33517.65 34886.69 33155.28 35249.05
## Mar 2020       36703.01 35979.24 37426.78 35596.10 37809.92
## Apr 2020       36271.90 35532.73 37011.07 35141.44 37402.36
## May 2020       37121.98 36376.63 37867.33 35982.07 38261.90
## Jun 2020       37102.65 36354.79 37850.51 35958.90 38246.40
## Jul 2020       37151.04 36402.16 37899.91 36005.73 38296.34
## Aug 2020       38564.64 37815.35 39313.93 37418.70 39710.58
## Sep 2020       38755.22 38005.77 39504.68 37609.03 39901.42
## Oct 2020       39779.02 39029.50 40528.55 38632.72 40925.32
## Nov 2020       38741.63 37992.07 39491.18 37595.28 39887.97
## Dec 2020       38645.86 37896.29 39395.42 37499.50 39792.22
plot(pronostico2)

En esta gráfica se puede observar un crecimiento con tendencia positiva en los próximos periódos. Se cuenta con un nivel de confianza del 95% establecido de forma predeterminada por la función.

Actividad Finanzas Corporativas: Información disponible: CompanyInfo, AnnualReports, GetIncome, etc.

options(HTTPUserAgent = "a a@gmail.com")
CompanyInfo("JPM")
##               company        CIK  SIC state state.inc FY.end     street.address
## 1 JPMORGAN CHASE & CO 0000019617 6021    NY        DE   1231 383 MADISON AVENUE
##          city.state
## 1 NEW YORK NY 10017
AnnualReports("BABA", foreign = TRUE)
##    filing.name filing.date         accession.no
## 1       20-F/A  2024-02-23 0001193125-24-044480
## 2         20-F  2023-07-21 0000950170-23-033752
## 3         20-F  2022-07-26 0001104659-22-082622
## 4         20-F  2021-07-27 0001104659-21-096092
## 5         20-F  2020-07-09 0001104659-20-082409
## 6         20-F  2019-06-05 0001047469-19-003492
## 7         20-F  2018-07-27 0001047469-18-005257
## 8         20-F  2017-06-15 0001047469-17-004019
## 9         20-F  2016-05-24 0001047469-16-013400
## 10        20-F  2015-06-25 0001047469-15-005768
google_income <- GetIncome('GOOG',2016)
amazon_balance <- GetBalanceSheet("AMZN",2015)
apple_cashflow <- GetCashFlow("AAPL",2014)

Análisis Financiero de Empresa: Crear base de datos y serie de tiempo, modelo ARIMA y pronóstico.

Actividad en equipo - Integrantes:

  • Regina Enríquez Chapa (A01721435)

  • Maximiliano Carvajal Huesca (A01552179)

  • Guillermo Cázares Cruz (A01283709)

Cargar información

options(HTTPUserAgent = "a a@gmail.com")
CompanyInfo("AAPL")
##      company        CIK  SIC state state.inc FY.end     street.address
## 1 Apple Inc. 0000320193 3571    CA        CA   0928 ONE APPLE PARK WAY
##           city.state
## 1 CUPERTINO CA 95014
options(HTTPUserAgent = "a a@gmail.com")
Apple17_income <- GetIncome("AAPL",2017)
Apple17_balance <- GetBalanceSheet("AAPL",2017)
Apple17_cash<- GetCashFlow("AAPL",2017) 
options(HTTPUserAgent = "a a@gmail.com")
Apple14_income <- GetIncome("AAPL",2014)
Apple14_balance <- GetBalanceSheet("AAPL",2014)
Apple14_cash <- GetCashFlow("AAPL",2014) 
A13_income <- GetIncome("AAPL",2013)
A15_income <- GetIncome("AAPL",2015)
options(HTTPUserAgent = "a a@gmail.com")
A16_income <- GetIncome("AAPL",2016)
options(HTTPUserAgent = "a a@gmail.com")
Apple11_income <- GetIncome("AAPL",2011)
Apple11_balance <- GetBalanceSheet("AAPL",2011)
Apple11_cash <- GetCashFlow("AAPL",2011) 

Se selecciona una variable, se toma de cada tabla para juntarlas con todas las fechas, y se lleva a cabo una unión de tablas para la predicción

Operating expenses

Apple_OpExp_11 <- select(Apple11_income,Metric,Amount,endDate)
Apple_OpExp_11 <- subset(Apple_OpExp_11, Metric == "Total operating expenses")

Apple_OpExp_14 <- select(Apple14_income,Metric,Amount,endDate)
Apple_OpExp_14 <- subset(Apple_OpExp_14, Metric == "Operating Expenses")

Apple_OpExp_17 <- select(Apple17_income,Metric,Amount,endDate)
Apple_OpExp_17 <- subset(Apple_OpExp_17, Metric == "Operating Expenses")
Apple_OpExp_complete <- rbind(Apple_OpExp_11,Apple_OpExp_14,Apple_OpExp_17)
Apple_OpExp_complete <- Apple_OpExp_complete[order(Apple_OpExp_complete$endDate),]
Apple_OpExp_complete$Amount <- as.numeric(Apple_OpExp_complete$Amount)

Creación de series de tiempo

ts_OpExp <- ts(data=Apple_OpExp_complete$Amount, start = c(2009,1), frequency = 1)
ts_OpExp
## Time Series:
## Start = 2009 
## End = 2017 
## Frequency = 1 
## [1] 5.4820e+09 7.2990e+09 1.0028e+10 1.3421e+10 1.5305e+10 1.8034e+10 2.2396e+10
## [8] 2.4239e+10 2.6842e+10
arima_OpExp <- auto.arima(ts_OpExp)
arima_OpExp
## Series: ts_OpExp 
## ARIMA(0,1,0) with drift 
## 
## Coefficients:
##            drift
##       2670000000
## s.e.   296005922
## 
## sigma^2 = 7.752e+17:  log likelihood = -175.58
## AIC=355.17   AICc=357.57   BIC=355.33
summary(arima_OpExp)
## Series: ts_OpExp 
## ARIMA(0,1,0) with drift 
## 
## Coefficients:
##            drift
##       2670000000
## s.e.   296005922
## 
## sigma^2 = 7.752e+17:  log likelihood = -175.58
## AIC=355.17   AICc=357.57   BIC=355.33
## 
## Training set error measures:
##                    ME      RMSE       MAE        MPE     MAPE      MASE
## Training set 312444.3 776486811 563201333 -0.7305296 3.821376 0.2109368
##                    ACF1
## Training set -0.3443892
pronostico_2 <- forecast(arima_OpExp, level=c(95), h=6)
pronostico_2
##      Point Forecast       Lo 95       Hi 95
## 2018     2.9512e+10 27786343272 31237656728
## 2019     3.2182e+10 29741552851 34622447149
## 2020     3.4852e+10 31863074870 37840925130
## 2021     3.7522e+10 34070686543 40973313457
## 2022     4.0192e+10 36333314250 44050685750
## 2023     4.2862e+10 38635021544 47088978456
plot(pronostico_2)

Considerando los pronósticos del modelo ARIMA se puede ver que hay un seguimiento a la tendencia positiva que tenían los datos históricos. Se puede ver que en los próximos años el gasto operativo seguirá aumentando, posiblemente representando un crecimiento de la empresa teniendo por consecuencia un aumento las operaciones de la empresa constante.

Prueba completa con “Revenue, Net”

RevNet_17 <- subset(Apple17_income, Metric == "Revenue, Net")
RevNet_17 <- RevNet_17[order(RevNet_17$endDate,RevNet_17$startDate),]
RevNet_17 <- RevNet_17[-c(1,5,10),]
options(HTTPUserAgent = "a a@gmail.com")
A16_income <- GetIncome("AAPL",2016)
A15_income <- GetIncome("AAPL",2015)
A13_income <- GetIncome("AAPL",2013)
RevNet_16 <- subset(A16_income, Metric == "Revenue, Net")
RevNet_16 <- RevNet_16[order(RevNet_16$endDate,RevNet_16$startDate),]
RevNet_16 <- RevNet_16[c(2:4,6),]
RevNet_15 <- subset(A15_income, Metric == "Revenue, Net")
RevNet_15 <- RevNet_15[order(RevNet_15$endDate,RevNet_15$startDate),]
RevNet_15 <- RevNet_15[c(2:4,6),]
RevNet_14 <- subset(Apple14_income, Metric == "Revenue, Net")
RevNet_14 <- RevNet_14[order(RevNet_14$endDate,RevNet_14$startDate),]
RevNet_14 <- RevNet_14[c(2:4,6),]
RevNet_13 <- subset(A13_income, Metric == "Sales Revenue Net")
RevNet_13 <- RevNet_13[order(RevNet_13$endDate,RevNet_13$startDate),]
RevNet_13 <- RevNet_13[c(3,4,6),]
RevNet_complete <- rbind(RevNet_13,RevNet_14,RevNet_15,RevNet_16,RevNet_17)
RevNet_complete <- RevNet_complete[order(RevNet_complete$endDate),]
str(RevNet_complete)
## 'data.frame':    23 obs. of  5 variables:
##  $ Metric   : chr  "Sales Revenue Net" "Sales Revenue Net" "Sales Revenue Net" "Revenue, Net" ...
##  $ Units    : chr  "iso4217_USD" "iso4217_USD" "iso4217_USD" "iso4217_USD" ...
##  $ Amount   : chr  "39186000000" "35023000000" "35966000000" "54512000000" ...
##  $ startDate: chr  "2012-01-01" "2012-04-01" "2012-07-01" "2012-09-30" ...
##  $ endDate  : chr  "2012-03-31" "2012-06-30" "2012-09-29" "2012-12-29" ...
RevNet_complete$Amount <- as.numeric(RevNet_complete$Amount)
str(RevNet_complete)
## 'data.frame':    23 obs. of  5 variables:
##  $ Metric   : chr  "Sales Revenue Net" "Sales Revenue Net" "Sales Revenue Net" "Revenue, Net" ...
##  $ Units    : chr  "iso4217_USD" "iso4217_USD" "iso4217_USD" "iso4217_USD" ...
##  $ Amount   : num  3.92e+10 3.50e+10 3.60e+10 5.45e+10 4.36e+10 ...
##  $ startDate: chr  "2012-01-01" "2012-04-01" "2012-07-01" "2012-09-30" ...
##  $ endDate  : chr  "2012-03-31" "2012-06-30" "2012-09-29" "2012-12-29" ...
library(forecast)
ts_RevNet <- ts(data=RevNet_complete$Amount, start = c(2012,1), frequency = 4)
ts_RevNet
##            Qtr1       Qtr2       Qtr3       Qtr4
## 2012 3.9186e+10 3.5023e+10 3.5966e+10 5.4512e+10
## 2013 4.3603e+10 3.5323e+10 3.7472e+10 5.7594e+10
## 2014 4.5646e+10 3.7432e+10 4.2123e+10 7.4599e+10
## 2015 5.8010e+10 4.9605e+10 5.1501e+10 7.5872e+10
## 2016 5.0557e+10 4.2358e+10 4.6852e+10 7.8351e+10
## 2017 5.2896e+10 4.5408e+10 5.2579e+10
arima_RevNet <- auto.arima(ts_RevNet)
arima_RevNet
## Series: ts_RevNet 
## ARIMA(0,0,0)(0,1,0)[4] with drift 
## 
## Coefficients:
##           drift
##       849302632
## s.e.  461280066
## 
## sigma^2 = 3.92e+19:  log likelihood = -455.04
## AIC=914.08   AICc=914.83   BIC=915.97
summary(arima_RevNet)
## Series: ts_RevNet 
## ARIMA(0,0,0)(0,1,0)[4] with drift 
## 
## Coefficients:
##           drift
##       849302632
## s.e.  461280066
## 
## sigma^2 = 3.92e+19:  log likelihood = -455.04
## AIC=914.08   AICc=914.83   BIC=915.97
## 
## Training set error measures:
##                   ME       RMSE        MAE        MPE     MAPE      MASE
## Training set 6791039 5538526781 3653271588 -0.7888238 7.147855 0.6723053
##                   ACF1
## Training set 0.6995847
pronostico_1 <- forecast(arima_RevNet, level=c(95), h=8)
pronostico_1
##         Point Forecast       Lo 95        Hi 95
## 2017 Q4    81748210526 69477491366  94018929687
## 2018 Q1    56293210526 44022491366  68563929687
## 2018 Q2    48805210526 36534491366  61075929687
## 2018 Q3    55976210526 43705491366  68246929687
## 2018 Q4    85145421053 67792003596 102498838509
## 2019 Q1    59690421053 42337003596  77043838509
## 2019 Q2    52202421053 34849003596  69555838509
## 2019 Q3    59373421053 42020003596  76726838509
plot(pronostico_1)

En el pronóstico se puede ver un ligero crecimiento por etapas, con más información se podría determinar estacionalidad dentro de la serie de tiempo. Se denota una constancia en el comportamiento de la información en el pronóstico en comparación con los datos históricos, esto quiere decir, en base al análisis, el Net Revenue seguirá teniendo un comportamiento similar para Apple en los próximos años.

LS0tDQp0aXRsZTogQWN0aXZpZGFkIDJfIEdlbmVyYWNpw7NuIGRlIGVzY2VuYXJpb3MgZnV0dXJvcyBjb24gbW9kZWxvcyBkZSBwcm9uw7NzdGljb3MgZW4NCiAgc2VyaWVzIGRlIHRpZW1wby4NCmF1dGhvcjogIk1heGltaWxpYW5vIENhcnZhamFsIEh1ZXNjYSINCmRhdGU6ICIyMDI0LTAyLTI4Ig0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IHVuaXRlZA0KLS0tDQpgYGB7PWh0bWx9DQo8c3R5bGU+DQpib2R5IHsNCnRleHQtYWxpZ246IGp1c3RpZnl9DQo8L3N0eWxlPg0KYGBgDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIEV4cGxpY2FjacOzbiBlbiBjbGFzZTogVGVvcsOtYSB5IEVqZW1wbG8gZGUgUHJvZHVjY2nDs24gVHJpbWVzdHJhbC4NCg0KIVtdKGh0dHBzOi8vbWlyby5tZWRpdW0uY29tL3YyL3Jlc2l6ZTpmaXQ6MTQwMC8xKk5wRU9nMEoyQnAwUVp0cW9xbmY0N0EuZ2lmKQ0KDQojIyBDb25jZXB0bw0KDQpVbmEgKipzZXJpZSBkZSB0aWVtcG8qKiBlcyB1bmEgY29sZWNjacOzbiBkZSBvYnNlcnZhY2lvbmVzIHNvYnJlIHVuIGRldGVybWluYWRvIGZlbsOzbWVubywgZWZlY3R1YWRhcyBlbiBtb21lbnRvcyBzdWNlc2l2b3MsIHVzdWFsbWVudGUgZXF1aWVzcGFjaWFkb3MuDQoNCkVqZW1wbG9zIGRlIHNlcmllcyBkZSB0aWVtcG86DQoNCjEuICBQcmVjaW9zIGRlIGFjY2lvbmVzDQoNCjIuICBOaXZlbGVzIGRlIGludmVudGFyaW8NCg0KMy4gIFJvdGFjacOzbiBkZSBwZXJzb25hbA0KDQo0LiAgVmVudGFzDQoNCjUuICBQSUIoKkdEUCopDQoNCk1hcyBpbmZvcm1hY2nDs246IFsqKkxpYnJvIGRlIFIqKl0oaHR0cHM6Ly9yNGRzLmhhZGxleS5uei8pDQoNCiMjIEluc3RhbGFyIHBhcXVldGVzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KbGlicmFyeShmaW5yZXBvcnRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5cikNCmBgYA0KDQojIyBDcmVhciBsYSBzZXJpZSBkZSB0aWVtcG8NCg0KKipFamVtcGxvKio6IExvcyBzaWd1aWVudGVzIGRhdG9zIGRlIHByb2R1Y2Npb24gdHJpbWVzdHJhbCBpbmljaWFuIGVuIGVsIHByaW1lciB0cmltZXN0cmUgZGVsIDIwMjAuDQoNClNlIGJ1c2NhIHByb25vc3RpY2FyIGxhIHByb2R1Y2Npw7NuIGRlIGxvcyBzaWd1aWVudGVzIDUgdHJpbWVzdHJlcy4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnByb2R1Y2Npb24gPC0gYyg1MCw1Myw1NSw1Nyw1NSw2MCkNCnRzIDwtIHRzKGRhdGE9IHByb2R1Y2Npb24sIHN0YXJ0PSBjKDIwMjAsMyksZnJlcXVlbmN5ID0gNCkNCnRzIA0KYGBgDQoNCiMjIENyZWFyIHVuIG1vZGVsbyBBUklNQQ0KDQoqKkFSSU1BKiogc2lnbmlmaWNhICoqQXV0b3JlZ3Jlc3NpdmUgSW50ZWdyYWRlZCBtb3ZpbmcgYXZlcmFnZSoqIG8gTW9kZWxvIEF1dG9ycmVncmVzaXZvIGludGVncmFkbyBkZSBwcm9tZWRpbyBtb3ZpbC4NCg0KYGBge3J9DQphcmltYSA8LSBhdXRvLmFyaW1hKHRzLCBEPTEpDQpzdW1tYXJ5KGFyaW1hKQ0KYGBgDQoNCiMjIEdlbmVyYXIgZWwgcHJvbsOzc3RpY28NCg0KYGBge3J9DQpwcm9ub3N0aWNvIDwtIGZvcmVjYXN0KGFyaW1hLGxldmVsPWMoOTUpLCBoPTUpDQpwcm9ub3N0aWNvDQpwbG90KHByb25vc3RpY28pDQpgYGANCg0KRW4gZXN0ZSBlamVyY2ljaW8gc2UgcHVlZGUgdmVyIHVuIGNyZWNpbWllbnRvIHBhcmEgbG9zIHNpZ3VpZW50ZXMgcGVyaW9kb3MgZGUgbGEgbMOtbmVhIGRlIHRpZW1wby4gU2UgbWVudGllbmUgbGEgdGVuZGVuY2lhIGRlIGFsdGliYWpvcyBlbiBsb3Mgc2VtZXN0cmVzIGNvbnRpZ3VvcyB5IGHDum4gZW4gbG9zIGVzY2VuYXJpb3MgcGVzaW1pc3RhcyBleGlzdGUgdW4gYXZhbmNlIGVuIGxhIHByb2R1Y2Npw7NuIGVzdGltYWRhLg0KDQojIEFjdGl2aWRhZCBIZXJzaGV5J3M6IEltcG9ydGFyIGJhc2UgZGUgZGF0b3MgeSBjcmVhciBzZXJpZSBkZSB0aWVtcG8sIG1vZGVsbyBBUklNQSB5IHByb27Ds3N0aWNvLg0KDQohW10oaHR0cHM6Ly9tZWRpYTIuZ2lwaHkuY29tL21lZGlhL3NiS3k1WGFybVRuNkQzc3RBUy9naXBoeS5naWY/Y2lkPTZjMDliOTUyenk2cW50ZzZ0d2RmcnVodzA2YWEyNnU1M21raGw1OGgwZmpvdG15NSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmcmlkPWdpcGh5LmdpZiZjdD1nKQ0KDQojIyBJbXBvcnRhciBiYXNlIGRlIGRhdG9zDQoNCmBgYHtyfQ0KbGVjaGl0YXMgPC0gcmVhZF9leGNlbCgiTGVjaGl0YXMueGxzeCIpDQp0czEgPC0gdHMoZGF0YSA9IGxlY2hpdGFzJFZlbnRhcywgc3RhcnQ9YygyMDE3LDEpLGZyZXF1ZW5jeSA9IDEyKQ0KdHMxDQpgYGANCg0KIyMgQ3JlYXIgdW4gbW9kZWxvIEFSSU1BDQoNCmBgYHtyfQ0KYXJpbWF4IDwtIGF1dG8uYXJpbWEodHMxLCBEPTEpDQpzdW1tYXJ5KGFyaW1heCkNCg0KYGBgDQoNCiMjIEdlbmVyYXIgZWwgcHJvbsOzc3RpY28NCg0KYGBge3J9DQpwcm9ub3N0aWNvMiA8LSBmb3JlY2FzdChhcmltYXgsIGg9MTIpDQpwcm9ub3N0aWNvMg0KcGxvdChwcm9ub3N0aWNvMikNCmBgYA0KDQpFbiBlc3RhIGdyw6FmaWNhIHNlIHB1ZWRlIG9ic2VydmFyIHVuIGNyZWNpbWllbnRvIGNvbiB0ZW5kZW5jaWEgcG9zaXRpdmEgZW4gbG9zIHByw7N4aW1vcyBwZXJpw7Nkb3MuIFNlIGN1ZW50YSBjb24gdW4gbml2ZWwgZGUgY29uZmlhbnphIGRlbCA5NSUgZXN0YWJsZWNpZG8gZGUgZm9ybWEgcHJlZGV0ZXJtaW5hZGEgcG9yIGxhIGZ1bmNpw7NuLg0KDQojIEFjdGl2aWRhZCBGaW5hbnphcyBDb3Jwb3JhdGl2YXM6IEluZm9ybWFjacOzbiBkaXNwb25pYmxlOiBDb21wYW55SW5mbywgQW5udWFsUmVwb3J0cywgR2V0SW5jb21lLCBldGMuDQoNCmBgYHtyfQ0Kb3B0aW9ucyhIVFRQVXNlckFnZW50ID0gImEgYUBnbWFpbC5jb20iKQ0KQ29tcGFueUluZm8oIkpQTSIpDQpBbm51YWxSZXBvcnRzKCJCQUJBIiwgZm9yZWlnbiA9IFRSVUUpDQpnb29nbGVfaW5jb21lIDwtIEdldEluY29tZSgnR09PRycsMjAxNikNCmFtYXpvbl9iYWxhbmNlIDwtIEdldEJhbGFuY2VTaGVldCgiQU1aTiIsMjAxNSkNCmFwcGxlX2Nhc2hmbG93IDwtIEdldENhc2hGbG93KCJBQVBMIiwyMDE0KQ0KYGBgDQoNCiMgQW7DoWxpc2lzIEZpbmFuY2llcm8gZGUgRW1wcmVzYTogQ3JlYXIgYmFzZSBkZSBkYXRvcyB5IHNlcmllIGRlIHRpZW1wbywgbW9kZWxvIEFSSU1BIHkgcHJvbsOzc3RpY28uDQoNCkFjdGl2aWRhZCBlbiBlcXVpcG8gLSBJbnRlZ3JhbnRlczoNCg0KLSAgIFJlZ2luYSBFbnLDrXF1ZXogQ2hhcGEgKEEwMTcyMTQzNSkNCg0KLSAgIE1heGltaWxpYW5vIENhcnZhamFsIEh1ZXNjYSAoQTAxNTUyMTc5KQ0KDQotICAgR3VpbGxlcm1vIEPDoXphcmVzIENydXogKEEwMTI4MzcwOSkNCg0KIVtdKGh0dHBzOi8vY2RuLmRyaWJiYmxlLmNvbS91c2Vycy81MzQyNjc5L3NjcmVlbnNob3RzLzExODI1NDgwL2FwcGxlLmdpZikNCg0KIyMgQ2FyZ2FyIGluZm9ybWFjacOzbg0KDQpgYGB7cn0NCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJhIGFAZ21haWwuY29tIikNCkNvbXBhbnlJbmZvKCJBQVBMIikNCmBgYA0KDQpgYGB7cn0NCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJhIGFAZ21haWwuY29tIikNCkFwcGxlMTdfaW5jb21lIDwtIEdldEluY29tZSgiQUFQTCIsMjAxNykNCkFwcGxlMTdfYmFsYW5jZSA8LSBHZXRCYWxhbmNlU2hlZXQoIkFBUEwiLDIwMTcpDQpBcHBsZTE3X2Nhc2g8LSBHZXRDYXNoRmxvdygiQUFQTCIsMjAxNykgDQpgYGANCg0KYGBge3J9DQpvcHRpb25zKEhUVFBVc2VyQWdlbnQgPSAiYSBhQGdtYWlsLmNvbSIpDQpBcHBsZTE0X2luY29tZSA8LSBHZXRJbmNvbWUoIkFBUEwiLDIwMTQpDQpBcHBsZTE0X2JhbGFuY2UgPC0gR2V0QmFsYW5jZVNoZWV0KCJBQVBMIiwyMDE0KQ0KQXBwbGUxNF9jYXNoIDwtIEdldENhc2hGbG93KCJBQVBMIiwyMDE0KSANCkExM19pbmNvbWUgPC0gR2V0SW5jb21lKCJBQVBMIiwyMDEzKQ0KQTE1X2luY29tZSA8LSBHZXRJbmNvbWUoIkFBUEwiLDIwMTUpDQpgYGANCg0KYGBge3J9DQpvcHRpb25zKEhUVFBVc2VyQWdlbnQgPSAiYSBhQGdtYWlsLmNvbSIpDQpBMTZfaW5jb21lIDwtIEdldEluY29tZSgiQUFQTCIsMjAxNikNCmBgYA0KDQpgYGB7cn0NCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJhIGFAZ21haWwuY29tIikNCkFwcGxlMTFfaW5jb21lIDwtIEdldEluY29tZSgiQUFQTCIsMjAxMSkNCkFwcGxlMTFfYmFsYW5jZSA8LSBHZXRCYWxhbmNlU2hlZXQoIkFBUEwiLDIwMTEpDQpBcHBsZTExX2Nhc2ggPC0gR2V0Q2FzaEZsb3coIkFBUEwiLDIwMTEpIA0KYGBgDQoNClNlIHNlbGVjY2lvbmEgdW5hIHZhcmlhYmxlLCBzZSB0b21hIGRlIGNhZGEgdGFibGEgcGFyYSBqdW50YXJsYXMgY29uIHRvZGFzIGxhcyBmZWNoYXMsIHkgc2UgbGxldmEgYSBjYWJvIHVuYSB1bmnDs24gZGUgdGFibGFzIHBhcmEgbGEgcHJlZGljY2nDs24NCg0KIyMgT3BlcmF0aW5nIGV4cGVuc2VzDQoNCmBgYHtyfQ0KQXBwbGVfT3BFeHBfMTEgPC0gc2VsZWN0KEFwcGxlMTFfaW5jb21lLE1ldHJpYyxBbW91bnQsZW5kRGF0ZSkNCkFwcGxlX09wRXhwXzExIDwtIHN1YnNldChBcHBsZV9PcEV4cF8xMSwgTWV0cmljID09ICJUb3RhbCBvcGVyYXRpbmcgZXhwZW5zZXMiKQ0KDQpBcHBsZV9PcEV4cF8xNCA8LSBzZWxlY3QoQXBwbGUxNF9pbmNvbWUsTWV0cmljLEFtb3VudCxlbmREYXRlKQ0KQXBwbGVfT3BFeHBfMTQgPC0gc3Vic2V0KEFwcGxlX09wRXhwXzE0LCBNZXRyaWMgPT0gIk9wZXJhdGluZyBFeHBlbnNlcyIpDQoNCkFwcGxlX09wRXhwXzE3IDwtIHNlbGVjdChBcHBsZTE3X2luY29tZSxNZXRyaWMsQW1vdW50LGVuZERhdGUpDQpBcHBsZV9PcEV4cF8xNyA8LSBzdWJzZXQoQXBwbGVfT3BFeHBfMTcsIE1ldHJpYyA9PSAiT3BlcmF0aW5nIEV4cGVuc2VzIikNCmBgYA0KDQpgYGB7cn0NCkFwcGxlX09wRXhwX2NvbXBsZXRlIDwtIHJiaW5kKEFwcGxlX09wRXhwXzExLEFwcGxlX09wRXhwXzE0LEFwcGxlX09wRXhwXzE3KQ0KQXBwbGVfT3BFeHBfY29tcGxldGUgPC0gQXBwbGVfT3BFeHBfY29tcGxldGVbb3JkZXIoQXBwbGVfT3BFeHBfY29tcGxldGUkZW5kRGF0ZSksXQ0KYGBgDQoNCmBgYHtyfQ0KQXBwbGVfT3BFeHBfY29tcGxldGUkQW1vdW50IDwtIGFzLm51bWVyaWMoQXBwbGVfT3BFeHBfY29tcGxldGUkQW1vdW50KQ0KYGBgDQoNCiMjIyBDcmVhY2nDs24gZGUgc2VyaWVzIGRlIHRpZW1wbw0KDQpgYGB7cn0NCnRzX09wRXhwIDwtIHRzKGRhdGE9QXBwbGVfT3BFeHBfY29tcGxldGUkQW1vdW50LCBzdGFydCA9IGMoMjAwOSwxKSwgZnJlcXVlbmN5ID0gMSkNCnRzX09wRXhwDQpgYGANCg0KYGBge3J9DQphcmltYV9PcEV4cCA8LSBhdXRvLmFyaW1hKHRzX09wRXhwKQ0KYXJpbWFfT3BFeHANCnN1bW1hcnkoYXJpbWFfT3BFeHApDQpgYGANCg0KYGBge3J9DQpwcm9ub3N0aWNvXzIgPC0gZm9yZWNhc3QoYXJpbWFfT3BFeHAsIGxldmVsPWMoOTUpLCBoPTYpDQpwcm9ub3N0aWNvXzINCnBsb3QocHJvbm9zdGljb18yKQ0KYGBgDQoNCkNvbnNpZGVyYW5kbyBsb3MgcHJvbsOzc3RpY29zIGRlbCBtb2RlbG8gQVJJTUEgc2UgcHVlZGUgdmVyIHF1ZSBoYXkgdW4gc2VndWltaWVudG8gYSBsYSB0ZW5kZW5jaWEgcG9zaXRpdmEgcXVlIHRlbsOtYW4gbG9zIGRhdG9zIGhpc3TDs3JpY29zLiBTZSBwdWVkZSB2ZXIgcXVlIGVuIGxvcyBwcsOzeGltb3MgYcOxb3MgZWwgZ2FzdG8gb3BlcmF0aXZvIHNlZ3VpcsOhIGF1bWVudGFuZG8sIHBvc2libGVtZW50ZSByZXByZXNlbnRhbmRvIHVuIGNyZWNpbWllbnRvIGRlIGxhIGVtcHJlc2EgdGVuaWVuZG8gcG9yIGNvbnNlY3VlbmNpYSB1biBhdW1lbnRvIGxhcyBvcGVyYWNpb25lcyBkZSBsYSBlbXByZXNhIGNvbnN0YW50ZS4NCg0KIyBQcnVlYmEgY29tcGxldGEgY29uICJSZXZlbnVlLCBOZXQiDQoNCmBgYHtyfQ0KUmV2TmV0XzE3IDwtIHN1YnNldChBcHBsZTE3X2luY29tZSwgTWV0cmljID09ICJSZXZlbnVlLCBOZXQiKQ0KUmV2TmV0XzE3IDwtIFJldk5ldF8xN1tvcmRlcihSZXZOZXRfMTckZW5kRGF0ZSxSZXZOZXRfMTckc3RhcnREYXRlKSxdDQpSZXZOZXRfMTcgPC0gUmV2TmV0XzE3Wy1jKDEsNSwxMCksXQ0KYGBgDQoNCmBgYHtyfQ0Kb3B0aW9ucyhIVFRQVXNlckFnZW50ID0gImEgYUBnbWFpbC5jb20iKQ0KQTE2X2luY29tZSA8LSBHZXRJbmNvbWUoIkFBUEwiLDIwMTYpDQpBMTVfaW5jb21lIDwtIEdldEluY29tZSgiQUFQTCIsMjAxNSkNCkExM19pbmNvbWUgPC0gR2V0SW5jb21lKCJBQVBMIiwyMDEzKQ0KYGBgDQoNCmBgYHtyfQ0KUmV2TmV0XzE2IDwtIHN1YnNldChBMTZfaW5jb21lLCBNZXRyaWMgPT0gIlJldmVudWUsIE5ldCIpDQpSZXZOZXRfMTYgPC0gUmV2TmV0XzE2W29yZGVyKFJldk5ldF8xNiRlbmREYXRlLFJldk5ldF8xNiRzdGFydERhdGUpLF0NCmBgYA0KDQpgYGB7cn0NClJldk5ldF8xNiA8LSBSZXZOZXRfMTZbYygyOjQsNiksXQ0KYGBgDQoNCmBgYHtyfQ0KUmV2TmV0XzE1IDwtIHN1YnNldChBMTVfaW5jb21lLCBNZXRyaWMgPT0gIlJldmVudWUsIE5ldCIpDQpSZXZOZXRfMTUgPC0gUmV2TmV0XzE1W29yZGVyKFJldk5ldF8xNSRlbmREYXRlLFJldk5ldF8xNSRzdGFydERhdGUpLF0NClJldk5ldF8xNSA8LSBSZXZOZXRfMTVbYygyOjQsNiksXQ0KYGBgDQoNCmBgYHtyfQ0KUmV2TmV0XzE0IDwtIHN1YnNldChBcHBsZTE0X2luY29tZSwgTWV0cmljID09ICJSZXZlbnVlLCBOZXQiKQ0KUmV2TmV0XzE0IDwtIFJldk5ldF8xNFtvcmRlcihSZXZOZXRfMTQkZW5kRGF0ZSxSZXZOZXRfMTQkc3RhcnREYXRlKSxdDQpSZXZOZXRfMTQgPC0gUmV2TmV0XzE0W2MoMjo0LDYpLF0NCmBgYA0KDQpgYGB7cn0NClJldk5ldF8xMyA8LSBzdWJzZXQoQTEzX2luY29tZSwgTWV0cmljID09ICJTYWxlcyBSZXZlbnVlIE5ldCIpDQpSZXZOZXRfMTMgPC0gUmV2TmV0XzEzW29yZGVyKFJldk5ldF8xMyRlbmREYXRlLFJldk5ldF8xMyRzdGFydERhdGUpLF0NClJldk5ldF8xMyA8LSBSZXZOZXRfMTNbYygzLDQsNiksXQ0KYGBgDQoNCmBgYHtyfQ0KUmV2TmV0X2NvbXBsZXRlIDwtIHJiaW5kKFJldk5ldF8xMyxSZXZOZXRfMTQsUmV2TmV0XzE1LFJldk5ldF8xNixSZXZOZXRfMTcpDQpSZXZOZXRfY29tcGxldGUgPC0gUmV2TmV0X2NvbXBsZXRlW29yZGVyKFJldk5ldF9jb21wbGV0ZSRlbmREYXRlKSxdDQpgYGANCg0KYGBge3J9DQpzdHIoUmV2TmV0X2NvbXBsZXRlKQ0KYGBgDQoNCmBgYHtyfQ0KUmV2TmV0X2NvbXBsZXRlJEFtb3VudCA8LSBhcy5udW1lcmljKFJldk5ldF9jb21wbGV0ZSRBbW91bnQpDQpgYGANCg0KYGBge3J9DQpzdHIoUmV2TmV0X2NvbXBsZXRlKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShmb3JlY2FzdCkNCmBgYA0KDQpgYGB7cn0NCnRzX1Jldk5ldCA8LSB0cyhkYXRhPVJldk5ldF9jb21wbGV0ZSRBbW91bnQsIHN0YXJ0ID0gYygyMDEyLDEpLCBmcmVxdWVuY3kgPSA0KQ0KdHNfUmV2TmV0DQpgYGANCg0KYGBge3J9DQphcmltYV9SZXZOZXQgPC0gYXV0by5hcmltYSh0c19SZXZOZXQpDQphcmltYV9SZXZOZXQNCnN1bW1hcnkoYXJpbWFfUmV2TmV0KQ0KYGBgDQoNCmBgYHtyfQ0KcHJvbm9zdGljb18xIDwtIGZvcmVjYXN0KGFyaW1hX1Jldk5ldCwgbGV2ZWw9Yyg5NSksIGg9OCkNCnByb25vc3RpY29fMQ0KcGxvdChwcm9ub3N0aWNvXzEpDQpgYGANCg0KRW4gZWwgcHJvbsOzc3RpY28gc2UgcHVlZGUgdmVyIHVuIGxpZ2VybyBjcmVjaW1pZW50byBwb3IgZXRhcGFzLCBjb24gbcOhcyBpbmZvcm1hY2nDs24gc2UgcG9kcsOtYSBkZXRlcm1pbmFyIGVzdGFjaW9uYWxpZGFkIGRlbnRybyBkZSBsYSBzZXJpZSBkZSB0aWVtcG8uIFNlIGRlbm90YSB1bmEgY29uc3RhbmNpYSBlbiBlbCBjb21wb3J0YW1pZW50byBkZSBsYSBpbmZvcm1hY2nDs24gZW4gZWwgcHJvbsOzc3RpY28gZW4gY29tcGFyYWNpw7NuIGNvbiBsb3MgZGF0b3MgaGlzdMOzcmljb3MsIGVzdG8gcXVpZXJlIGRlY2lyLCBlbiBiYXNlIGFsIGFuw6FsaXNpcywgZWwgKk5ldCBSZXZlbnVlKiBzZWd1aXLDoSB0ZW5pZW5kbyB1biBjb21wb3J0YW1pZW50byBzaW1pbGFyIHBhcmEgQXBwbGUgZW4gbG9zIHByw7N4aW1vcyBhw7Fvcy4NCg==