Actividad 4.2

Enrique Monsivais
2023-10-04

Shiny App ß Análisis de Sentimientos (Himno y El Triste)

Redes Neuronales

Introducción a las Redes Neuronales

Una Red Neural Artificial (ANN) modela la relación entre un conjunto de entradas y una salida, resolviendo un problema de aprendizaje.

Un ejemplo de aplicación de Redes Neuronales es 1. La recomendación de contenido de Netflix. 2. El feed de Tiktok, o instagram.

1. Instalar paquetes y llamar librerías

library(neuralnet)

2. Alimentar con ejemplos

examen <- c(20,10,30,20,80,30)
proyecto <- c(90,20,40,50,50,80)
estatus <- c(1,0,0,0,1,1)
df <- data.frame(examen, proyecto, estatus)

3. Generar Red Neuronal

red_neuronal <- neuralnet(estatus ~ examen + proyecto, data=df)
plot(red_neuronal, rep = 'best')

4. Predecir con la red neuronal

prueba_examen <- c(30,40,85)
prueba_proyecto <- c(85,50,40)
prueba <- data.frame(prueba_examen, prueba_proyecto)

prediccion <- compute(red_neuronal, prueba)
prediccion$net.result 
##           [,1]
## [1,] 0.4999788
## [2,] 0.4999789
## [3,] 0.4999789
probabilidad <- prediccion$net.result
resultado <- ifelse(probabilidad>0.5,1,0)
resultado
##      [,1]
## [1,]    0
## [2,]    0
## [3,]    0

Ejercicio Red Neuronal

1. Instalar paquetes y llamar librerías

library(neuralnet)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:neuralnet':
## 
##     compute
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

2. Alimentar con base de datos

data <-  read.csv("C:\\Users\\enriq\\OneDrive\\Documentos\\Datos a Desiciones\\Modulo4\\cancer_de_mama.csv")
data <- na.omit(data)

3. Asignar valores númericos a la variable dependiente

data <- data %>%
  mutate(diagnosis = ifelse(diagnosis == "M", 1, ifelse(diagnosis == "V", 0, diagnosis)))

4. Dividimos los datos en entrenamiento y prueba

inp <- sample(2, nrow(data), replace = TRUE, prob = c(0.7, 0.3))
training_data <- data[inp==1, ]
test_data <- data[inp==2, ]

5. Generar Red Neuronal

set.seed(222)
attach(data)
n <- neuralnet(diagnosis~.,
               data = training_data,
               hidden = 5,
               err.fct = "sse",
               linear.output = FALSE,
               lifesign = 'full',
               rep = 1,
               algorithm = "rprop+",
               stepmax = 500000)
## hidden: 5    thresh: 0.01    rep: 1/1    steps:    1000  min thresh: 0.224288958813999
##                                                    2000  min thresh: 0.224288958813999
##                                                    3000  min thresh: 0.224288958813999
##                                                    4000  min thresh: 0.224288958813999
##                                                    5000  min thresh: 0.224288958813999
##                                                    6000  min thresh: 0.224288958813999
##                                                    7000  min thresh: 0.224288958813999
##                                                    8000  min thresh: 0.101646496234301
##                                                    9000  min thresh: 0.0965388464781778
##                                                   10000  min thresh: 0.0965388464781778
##                                                   11000  min thresh: 0.0965388464781778
##                                                   12000  min thresh: 0.0965388464781778
##                                                   13000  min thresh: 0.0965388464781778
##                                                   14000  min thresh: 0.0965388464781778
##                                                   15000  min thresh: 0.0965388464781778
##                                                   16000  min thresh: 0.0965388464781778
##                                                   17000  min thresh: 0.0965388464781778
##                                                   18000  min thresh: 0.0965388464781778
##                                                   19000  min thresh: 0.0965388464781778
##                                                   20000  min thresh: 0.0880770494011347
##                                                   21000  min thresh: 0.0630496046396311
##                                                   22000  min thresh: 0.0117993088136834
##                                                   23000  min thresh: 0.0117993088136834
##                                                   24000  min thresh: 0.0117993088136834
##                                                   25000  min thresh: 0.0117993088136834
##                                                   25836  error: 2.33795  time: 7.3 secs
plot(n, rep = 'best')

6. Cambiar las predicciones de 0 y 1 a M, V

# Obtener las predicciones como 0 o 1
output <- neuralnet::compute(n, rep = 1, test_data[, -1])
p <- output$net.result
pred <- ifelse(p >= 0.5, "M", "V")

7. Matriz de Confusión

# Asegurarse de que ambos vectores tengan la misma longitud
n <- min(length(pred), length(test_data$diagnosis))
pred <- pred[1:n]
actual <- test_data$diagnosis[1:n]

# Crear la matriz de confusión
tab <- table(pred, actual)
tab
##     actual
## pred   1   B
##    M  74   4
##    V   2 100

8. Porcentaje de error total

#Con esta operación obtenemos el porcentaje de error total (usando datos de la matrix de confusión)
1 - sum(diag(tab)) / sum(tab)
## [1] 0.03333333

Series de Tiempo

Introducción

Una Serie de Tiempo es una colecció de observaciones sobre un feterminado 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 persona.
4. Ventas.

1. Instalar paquetes y llamar librerías

library(forecast)
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo

2. Crear la Serie de Tiempo

# Paso 1. Obtener los valores dependeintes
produccion <- c(50,53,55,57,55,60)

#Paso 2. Agregar a los valores anteriores su tiempo correspondiente
serie_de_tiempo <-  ts(data = produccion, start = 2020, frequency = 4) #aquí lo hizo por trimestre 
serie_de_tiempo
##      Qtr1 Qtr2 Qtr3 Qtr4
## 2020   50   53   55   57
## 2021   55   60

3. Crear modelo ARIMA

# ARIMA: AutoRegressive Integrated Moving Average o Modelo Autorregresivo Integrado de Media Móvil. 
#ARIMA (p, d, q)
# p = orden de auto-regresión
# d = orden de integración (o diferenciación)
# q = orden del promedio móvil

# ¿Cuándo se usa? Cuando las estimaciones futuras se explican por los datos del pasado y no por variables independientes.

#Ejemplo: Tipo de cambio
modelo <- auto.arima(serie_de_tiempo, D=1) #agg D porque la gráfica iba para arriba y el pronóstico no 
modelo
## Series: serie_de_tiempo 
## 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)
## Series: serie_de_tiempo 
## 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

4. Realizar pronóstico

pronostico <- forecast(modelo, 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)

Banco mundial

El Banco mundial (WB) es un organismo multinacional especializado en finanzas. En R se puede acceder a sus indicadores a través de la librería WDI.

1. Instalar paquetes y llamar librerías

library(WDI)
library(wbstats)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ forcats   1.0.0     ✔ readr     2.1.4
## ✔ ggplot2   3.4.2     ✔ stringr   1.5.0
## ✔ lubridate 1.9.2     ✔ tibble    3.2.1
## ✔ purrr     1.0.1     ✔ tidyr     1.3.0
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::compute() masks neuralnet::compute()
## ✖ dplyr::filter()  masks stats::filter()
## ✖ dplyr::lag()     masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

2. Crear la serie de tiempo

# Paso 1. Obtener los valores dependientes
gdp_data <- wb_data(country = "MX", indicator = "NY.GDP.MKTP.CD",start_date = 1973, end_date = 2022)

# Paso 2. Agregar a los valores anteriores su tiempo correspondiente
serie_de_tiempo1 <- ts(data=gdp_data$NY.GDP.MKTP.CD, start = c(1973,1), frequency=1, end=c(2022,1))
serie_de_tiempo1
## Time Series:
## Start = 1973 
## End = 2022 
## Frequency = 1 
##  [1] 5.528021e+10 7.200018e+10 8.800000e+10 8.887679e+10 8.191250e+10
##  [6] 1.026473e+11 1.345296e+11 2.055770e+11 2.638021e+11 1.846036e+11
## [11] 1.561675e+11 1.842312e+11 1.952414e+11 1.345561e+11 1.475426e+11
## [16] 1.816112e+11 2.214031e+11 2.612537e+11 3.131397e+11 3.631578e+11
## [21] 5.007334e+11 5.278106e+11 3.600725e+11 4.109730e+11 5.004160e+11
## [26] 5.264997e+11 6.002330e+11 7.079099e+11 7.567029e+11 7.721097e+11
## [31] 7.293350e+11 7.822429e+11 8.774769e+11 9.753834e+11 1.052697e+12
## [36] 1.109987e+12 9.000470e+11 1.057801e+12 1.180487e+12 1.201094e+12
## [41] 1.274444e+12 1.315356e+12 1.171870e+12 1.078493e+12 1.158912e+12
## [46] 1.222406e+12 1.269010e+12 1.090515e+12 1.272839e+12 1.414187e+12
## attr(,"label")
## [1] GDP (current US$)

3. Crear modelo ARIMA

modelo1 <- auto.arima(serie_de_tiempo1)
modelo1
## Series: serie_de_tiempo1 
## ARIMA(0,1,0) 
## 
## sigma^2 = 7.381e+21:  log likelihood = -1303.18
## AIC=2608.36   AICc=2608.44   BIC=2610.25
summary(modelo1)
## Series: serie_de_tiempo1 
## ARIMA(0,1,0) 
## 
## sigma^2 = 7.381e+21:  log likelihood = -1303.18
## AIC=2608.36   AICc=2608.44   BIC=2610.25
## 
## Training set error measures:
##                       ME        RMSE         MAE      MPE     MAPE     MASE
## Training set 27179245230 85046847387 67623045592 4.943879 14.05421 0.980016
##                     ACF1
## Training set -0.01519178

4. Realizar pronóstico

pronostico1 <- forecast(modelo1, level = c(95), h=5)
pronostico1
##      Point Forecast        Lo 95        Hi 95
## 2023   1.414187e+12 1.245806e+12 1.582568e+12
## 2024   1.414187e+12 1.176060e+12 1.652314e+12
## 2025   1.414187e+12 1.122543e+12 1.705832e+12
## 2026   1.414187e+12 1.077425e+12 1.750949e+12
## 2027   1.414187e+12 1.037676e+12 1.790699e+12
plot(pronostico1)

LS0tDQojdGl0bGU6ICJBY3RpdmlkYWQgNC4yIg0KI2F1dGhvcjogIkVucmlxdWUgTW9uc2l2YWlzIg0KZGF0ZTogIjIwMjMtMTAtMDQiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogcGFwZXINCiAgICBoaWdobGlnaHQ6ICJ6ZW5idXJuIg0KICAgIHNtb290aF9zY3JvbGw6IHRydWUNCi0tLQ0KIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6IHJlZDsiPiBBY3RpdmlkYWQgNC4yPC9zcGFuPioqKg0KDQo8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxOHB4OyBjb2xvcjogYmxhY2s7Ij5FbnJpcXVlIE1vbnNpdmFpczwvc3Bhbj48YnI+DQo8c3BhbiBzdHlsZT0iZm9udC1zaXplOiAxOHB4OyBjb2xvcjogYmxhY2s7Ij4yMDIzLTEwLTA0PC9zcGFuPg0KDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPiBTaGlueSBBcHAgw58gQW7DoWxpc2lzIGRlIFNlbnRpbWllbnRvcyAoSGltbm8geSBFbCBUcmlzdGUpPC9zcGFuPg0KIVtdKEM6XFxVc2Vyc1xcZW5yaXFcXE9uZURyaXZlXFxEb2N1bWVudG9zXFxEYXRvcyBhIERlc2ljaW9uZXNcXE1vZHVsbzRcXGVtb2Npb25lcy5naWYpDQoNCg0KIyMjIDxlbSBzdHlsZT0iY29sb3I6IGdyZWVuOyI+IExpbmsgZGUgbGEgU2hpbm55IEFwcDo8L2VtPiA8YSBocmVmPSJodHRwczovL2h1ejRlbS1lbnJpcXVlLW0uc2hpbnlhcHBzLmlvL0ZlZWxpbmdzLyI+U2hpbnlBcHA8L2E+DQoNCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+IFJlZGVzIE5ldXJvbmFsZXM8L3NwYW4+DQoNCg0KIyMjICo8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+IEludHJvZHVjY2nDs24gYSBsYXMgUmVkZXMgTmV1cm9uYWxlczwvc3Bhbj4qDQohW10oQzpcXFVzZXJzXFxlbnJpcVxcT25lRHJpdmVcXERvY3VtZW50b3NcXERhdG9zIGEgRGVzaWNpb25lc1xcTW9kdWxvNFxccm4uZ2lmKQ0KDQpVbmEgUmVkIE5ldXJhbCBBcnRpZmljaWFsIChBTk4pIG1vZGVsYSBsYSByZWxhY2nDs24gZW50cmUgdW4gY29uanVudG8gZGUgZW50cmFkYXMgeSB1bmEgc2FsaWRhLCByZXNvbHZpZW5kbyB1biBwcm9ibGVtYSBkZSBhcHJlbmRpemFqZS4gDQoNClVuIGVqZW1wbG8gZGUgYXBsaWNhY2nDs24gZGUgUmVkZXMgTmV1cm9uYWxlcyBlcyANCjEuIExhIHJlY29tZW5kYWNpw7NuIGRlIGNvbnRlbmlkbyBkZSBOZXRmbGl4Lg0KMi4gRWwgZmVlZCBkZSBUaWt0b2ssIG8gaW5zdGFncmFtLg0KDQojIyMjICoqKjxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij4xLiBJbnN0YWxhciBwYXF1ZXRlcyB5IGxsYW1hciBsaWJyZXLDrWFzPC9zcGFuPioqKg0KYGBge3J9DQpsaWJyYXJ5KG5ldXJhbG5ldCkNCmBgYA0KDQojIyMjICoqKjxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij4yLiBBbGltZW50YXIgY29uIGVqZW1wbG9zPC9zcGFuPioqKg0KYGBge3J9DQpleGFtZW4gPC0gYygyMCwxMCwzMCwyMCw4MCwzMCkNCnByb3llY3RvIDwtIGMoOTAsMjAsNDAsNTAsNTAsODApDQplc3RhdHVzIDwtIGMoMSwwLDAsMCwxLDEpDQpkZiA8LSBkYXRhLmZyYW1lKGV4YW1lbiwgcHJveWVjdG8sIGVzdGF0dXMpDQoNCmBgYA0KDQojIyMjICoqKjxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij4zLiBHZW5lcmFyIFJlZCBOZXVyb25hbDwvc3Bhbj4qKioNCmBgYHtyfQ0KcmVkX25ldXJvbmFsIDwtIG5ldXJhbG5ldChlc3RhdHVzIH4gZXhhbWVuICsgcHJveWVjdG8sIGRhdGE9ZGYpDQpwbG90KHJlZF9uZXVyb25hbCwgcmVwID0gJ2Jlc3QnKQ0KYGBgDQoNCiMjIyMgKioqPHNwYW4gc3R5bGU9ImNvbG9yOiBibGFjazsiPjQuIFByZWRlY2lyIGNvbiBsYSByZWQgbmV1cm9uYWw8L3NwYW4+KioqDQpgYGB7cn0NCnBydWViYV9leGFtZW4gPC0gYygzMCw0MCw4NSkNCnBydWViYV9wcm95ZWN0byA8LSBjKDg1LDUwLDQwKQ0KcHJ1ZWJhIDwtIGRhdGEuZnJhbWUocHJ1ZWJhX2V4YW1lbiwgcHJ1ZWJhX3Byb3llY3RvKQ0KDQpwcmVkaWNjaW9uIDwtIGNvbXB1dGUocmVkX25ldXJvbmFsLCBwcnVlYmEpDQpwcmVkaWNjaW9uJG5ldC5yZXN1bHQgDQpwcm9iYWJpbGlkYWQgPC0gcHJlZGljY2lvbiRuZXQucmVzdWx0DQpyZXN1bHRhZG8gPC0gaWZlbHNlKHByb2JhYmlsaWRhZD4wLjUsMSwwKQ0KcmVzdWx0YWRvDQpgYGANCg0KDQojIyMgKjxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5FamVyY2ljaW8gUmVkIE5ldXJvbmFsPC9zcGFuPioNCg0KIyMjIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrOyI+MS4gSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hczwvc3Bhbj4qKioNCmBgYHtyfQ0KbGlicmFyeShuZXVyYWxuZXQpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCiMjIyMgKioqPHNwYW4gc3R5bGU9ImNvbG9yOiBibGFjazsiPjIuIEFsaW1lbnRhciBjb24gYmFzZSBkZSBkYXRvczwvc3Bhbj4qKioNCmBgYHtyfQ0KZGF0YSA8LSAgcmVhZC5jc3YoIkM6XFxVc2Vyc1xcZW5yaXFcXE9uZURyaXZlXFxEb2N1bWVudG9zXFxEYXRvcyBhIERlc2ljaW9uZXNcXE1vZHVsbzRcXGNhbmNlcl9kZV9tYW1hLmNzdiIpDQpkYXRhIDwtIG5hLm9taXQoZGF0YSkNCmBgYA0KDQojIyMjICoqKjxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij4zLiBBc2lnbmFyIHZhbG9yZXMgbsO6bWVyaWNvcyBhIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlPC9zcGFuPioqKg0KYGBge3J9DQpkYXRhIDwtIGRhdGEgJT4lDQogIG11dGF0ZShkaWFnbm9zaXMgPSBpZmVsc2UoZGlhZ25vc2lzID09ICJNIiwgMSwgaWZlbHNlKGRpYWdub3NpcyA9PSAiViIsIDAsIGRpYWdub3NpcykpKQ0KYGBgDQoNCiMjIyMgKioqPHNwYW4gc3R5bGU9ImNvbG9yOiBibGFjazsiPjQuIERpdmlkaW1vcyBsb3MgZGF0b3MgZW4gZW50cmVuYW1pZW50byB5IHBydWViYTwvc3Bhbj4qKioNCmBgYHtyfQ0KaW5wIDwtIHNhbXBsZSgyLCBucm93KGRhdGEpLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKQ0KdHJhaW5pbmdfZGF0YSA8LSBkYXRhW2lucD09MSwgXQ0KdGVzdF9kYXRhIDwtIGRhdGFbaW5wPT0yLCBdDQpgYGANCg0KIyMjIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6IGJsYWNrOyI+NS4gR2VuZXJhciBSZWQgTmV1cm9uYWw8L3NwYW4+KioqDQpgYGB7cn0NCnNldC5zZWVkKDIyMikNCmF0dGFjaChkYXRhKQ0KbiA8LSBuZXVyYWxuZXQoZGlhZ25vc2lzfi4sDQogICAgICAgICAgICAgICBkYXRhID0gdHJhaW5pbmdfZGF0YSwNCiAgICAgICAgICAgICAgIGhpZGRlbiA9IDUsDQogICAgICAgICAgICAgICBlcnIuZmN0ID0gInNzZSIsDQogICAgICAgICAgICAgICBsaW5lYXIub3V0cHV0ID0gRkFMU0UsDQogICAgICAgICAgICAgICBsaWZlc2lnbiA9ICdmdWxsJywNCiAgICAgICAgICAgICAgIHJlcCA9IDEsDQogICAgICAgICAgICAgICBhbGdvcml0aG0gPSAicnByb3ArIiwNCiAgICAgICAgICAgICAgIHN0ZXBtYXggPSA1MDAwMDApDQpwbG90KG4sIHJlcCA9ICdiZXN0JykNCmBgYA0KDQojIyMjICoqKjxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij42LiBDYW1iaWFyIGxhcyBwcmVkaWNjaW9uZXMgZGUgMCB5IDEgYSBNLCBWPC9zcGFuPioqKg0KYGBge3J9DQojIE9idGVuZXIgbGFzIHByZWRpY2Npb25lcyBjb21vIDAgbyAxDQpvdXRwdXQgPC0gbmV1cmFsbmV0Ojpjb21wdXRlKG4sIHJlcCA9IDEsIHRlc3RfZGF0YVssIC0xXSkNCnAgPC0gb3V0cHV0JG5ldC5yZXN1bHQNCnByZWQgPC0gaWZlbHNlKHAgPj0gMC41LCAiTSIsICJWIikNCmBgYA0KDQoNCiMjIyMgKioqPHNwYW4gc3R5bGU9ImNvbG9yOiBibGFjazsiPjcuIE1hdHJpeiBkZSBDb25mdXNpw7NuPC9zcGFuPioqKg0KYGBge3J9DQojIEFzZWd1cmFyc2UgZGUgcXVlIGFtYm9zIHZlY3RvcmVzIHRlbmdhbiBsYSBtaXNtYSBsb25naXR1ZA0KbiA8LSBtaW4obGVuZ3RoKHByZWQpLCBsZW5ndGgodGVzdF9kYXRhJGRpYWdub3NpcykpDQpwcmVkIDwtIHByZWRbMTpuXQ0KYWN0dWFsIDwtIHRlc3RfZGF0YSRkaWFnbm9zaXNbMTpuXQ0KDQojIENyZWFyIGxhIG1hdHJpeiBkZSBjb25mdXNpw7NuDQp0YWIgPC0gdGFibGUocHJlZCwgYWN0dWFsKQ0KdGFiDQpgYGANCg0KDQojIyMjICoqKjxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij44LiBQb3JjZW50YWplIGRlIGVycm9yIHRvdGFsPC9zcGFuPioqKg0KYGBge3J9DQojQ29uIGVzdGEgb3BlcmFjacOzbiBvYnRlbmVtb3MgZWwgcG9yY2VudGFqZSBkZSBlcnJvciB0b3RhbCAodXNhbmRvIGRhdG9zIGRlIGxhIG1hdHJpeCBkZSBjb25mdXNpw7NuKQ0KMSAtIHN1bShkaWFnKHRhYikpIC8gc3VtKHRhYikNCmBgYA0KDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPiBTZXJpZXMgZGUgVGllbXBvPC9zcGFuPg0KDQohW10oQzpcXFVzZXJzXFxlbnJpcVxcT25lRHJpdmVcXERvY3VtZW50b3NcXERhdG9zIGEgRGVzaWNpb25lc1xcTW9kdWxvNFxcdGltZXNlcmllcy5naWYpDQoNCiMjIyAqPHNwYW4gc3R5bGU9ImNvbG9yOmdyZWVuOyI+SW50cm9kdWNjacOzbjwvc3Bhbj4qDQoNClVuYSAqU2VyaWUgZGUgVGllbXBvKiBlcyB1bmEgY29sZWNjacOzIGRlIG9ic2VydmFjaW9uZXMgc29icmUgdW4gZmV0ZXJtaW5hZG8gZmVuw7NtZW5vIGVmZWN0dWFkYXMgZW4gbW9tZW50b3MgZGUgdGllbXBvIHN1Y2VzaXZvcywgdXN1YWxtZW50ZSBlcXVpZXNwYWNpYWRvcy4gIA0KDQpFamVtcGxvcyBkZSBTZXJpZXMgZGUgVGllbXBvIHNvbjogIA0KMS4gUHJlY2lvIGRlIGFjY2lvbmVzLiAgDQoyLiBOaXZlbGVzIGRlIGludmVudGFyaW8uICANCjMuIFJvdGFjacOzbiBkZSBwZXJzb25hLiAgDQo0LiBWZW50YXMuICANCg0KIyMjIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6YmxhY2s7Ij4xLiBJbnN0YWxhciBwYXF1ZXRlcyB5IGxsYW1hciBsaWJyZXLDrWFzPC9zcGFuPioqKg0KYGBge3J9DQpsaWJyYXJ5KGZvcmVjYXN0KQ0KYGBgDQoNCiMjIyMgKioqPHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrOyI+Mi4gQ3JlYXIgbGEgU2VyaWUgZGUgVGllbXBvPC9zcGFuPioqKg0KYGBge3J9DQojIFBhc28gMS4gT2J0ZW5lciBsb3MgdmFsb3JlcyBkZXBlbmRlaW50ZXMNCnByb2R1Y2Npb24gPC0gYyg1MCw1Myw1NSw1Nyw1NSw2MCkNCg0KI1Bhc28gMi4gQWdyZWdhciBhIGxvcyB2YWxvcmVzIGFudGVyaW9yZXMgc3UgdGllbXBvIGNvcnJlc3BvbmRpZW50ZQ0Kc2VyaWVfZGVfdGllbXBvIDwtICB0cyhkYXRhID0gcHJvZHVjY2lvbiwgc3RhcnQgPSAyMDIwLCBmcmVxdWVuY3kgPSA0KSAjYXF1w60gbG8gaGl6byBwb3IgdHJpbWVzdHJlIA0Kc2VyaWVfZGVfdGllbXBvDQpgYGANCg0KIyMjIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6YmxhY2s7Ij4zLiBDcmVhciBtb2RlbG8gQVJJTUE8L3NwYW4+KioqDQpgYGB7cn0NCiMgQVJJTUE6IEF1dG9SZWdyZXNzaXZlIEludGVncmF0ZWQgTW92aW5nIEF2ZXJhZ2UgbyBNb2RlbG8gQXV0b3JyZWdyZXNpdm8gSW50ZWdyYWRvIGRlIE1lZGlhIE3Ds3ZpbC4gDQojQVJJTUEgKHAsIGQsIHEpDQojIHAgPSBvcmRlbiBkZSBhdXRvLXJlZ3Jlc2nDs24NCiMgZCA9IG9yZGVuIGRlIGludGVncmFjacOzbiAobyBkaWZlcmVuY2lhY2nDs24pDQojIHEgPSBvcmRlbiBkZWwgcHJvbWVkaW8gbcOzdmlsDQoNCiMgwr9DdcOhbmRvIHNlIHVzYT8gQ3VhbmRvIGxhcyBlc3RpbWFjaW9uZXMgZnV0dXJhcyBzZSBleHBsaWNhbiBwb3IgbG9zIGRhdG9zIGRlbCBwYXNhZG8geSBubyBwb3IgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzLg0KDQojRWplbXBsbzogVGlwbyBkZSBjYW1iaW8NCm1vZGVsbyA8LSBhdXRvLmFyaW1hKHNlcmllX2RlX3RpZW1wbywgRD0xKSAjYWdnIEQgcG9ycXVlIGxhIGdyw6FmaWNhIGliYSBwYXJhIGFycmliYSB5IGVsIHByb27Ds3N0aWNvIG5vIA0KbW9kZWxvDQpgYGANCmBgYHtyfQ0Kc3VtbWFyeShtb2RlbG8pDQpgYGANCg0KIyMjIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6YmxhY2s7Ij40LiBSZWFsaXphciBwcm9uw7NzdGljbzwvc3Bhbj4qKioNCmBgYHtyfQ0KcHJvbm9zdGljbyA8LSBmb3JlY2FzdChtb2RlbG8sIGxldmVsID0gYyg5NSksIGg9NSkNCnByb25vc3RpY28NCnBsb3QocHJvbm9zdGljbykNCmBgYA0KDQoNCiMjIyAqPHNwYW4gc3R5bGU9ImNvbG9yOmdyZWVuOyI+QmFuY28gbXVuZGlhbDwvc3Bhbj4qDQoNCkVsICpCYW5jbyBtdW5kaWFsIChXQikqIGVzIHVuIG9yZ2FuaXNtbyBtdWx0aW5hY2lvbmFsIGVzcGVjaWFsaXphZG8gZW4gZmluYW56YXMuDQpFbiBSIHNlIHB1ZWRlIGFjY2VkZXIgYSBzdXMgaW5kaWNhZG9yZXMgYSB0cmF2w6lzIGRlIGxhIGxpYnJlcsOtYSBXREkuDQoNCiMjIyMgKioqPHNwYW4gc3R5bGU9ImNvbG9yOmJsYWNrOyI+MS4gSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hczwvc3Bhbj4qKioNCmBgYHtyfQ0KbGlicmFyeShXREkpDQpsaWJyYXJ5KHdic3RhdHMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQojIyMjICoqKjxzcGFuIHN0eWxlPSJjb2xvcjogYmxhY2s7Ij4yLiBDcmVhciBsYSBzZXJpZSBkZSB0aWVtcG88L3NwYW4+KioqDQpgYGB7cn0NCiMgUGFzbyAxLiBPYnRlbmVyIGxvcyB2YWxvcmVzIGRlcGVuZGllbnRlcw0KZ2RwX2RhdGEgPC0gd2JfZGF0YShjb3VudHJ5ID0gIk1YIiwgaW5kaWNhdG9yID0gIk5ZLkdEUC5NS1RQLkNEIixzdGFydF9kYXRlID0gMTk3MywgZW5kX2RhdGUgPSAyMDIyKQ0KDQojIFBhc28gMi4gQWdyZWdhciBhIGxvcyB2YWxvcmVzIGFudGVyaW9yZXMgc3UgdGllbXBvIGNvcnJlc3BvbmRpZW50ZQ0Kc2VyaWVfZGVfdGllbXBvMSA8LSB0cyhkYXRhPWdkcF9kYXRhJE5ZLkdEUC5NS1RQLkNELCBzdGFydCA9IGMoMTk3MywxKSwgZnJlcXVlbmN5PTEsIGVuZD1jKDIwMjIsMSkpDQpzZXJpZV9kZV90aWVtcG8xDQpgYGANCg0KIyMjIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6YmxhY2s7Ij4zLiBDcmVhciBtb2RlbG8gQVJJTUE8L3NwYW4+KioqDQpgYGB7cn0NCm1vZGVsbzEgPC0gYXV0by5hcmltYShzZXJpZV9kZV90aWVtcG8xKQ0KbW9kZWxvMQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShtb2RlbG8xKQ0KYGBgDQoNCg0KIyMjIyAqKio8c3BhbiBzdHlsZT0iY29sb3I6YmxhY2s7Ij40LiBSZWFsaXphciBwcm9uw7NzdGljbzwvc3Bhbj4qKioNCmBgYHtyfQ0KcHJvbm9zdGljbzEgPC0gZm9yZWNhc3QobW9kZWxvMSwgbGV2ZWwgPSBjKDk1KSwgaD01KQ0KcHJvbm9zdGljbzENCnBsb3QocHJvbm9zdGljbzEpDQpgYGANCg0K