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
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

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
## 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
## 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

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
## 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

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