![]()
Stock Price Simulation using Geometric
Brownian Motion (GBM) & Error Analysis
El GBM (Geometric Brownian Motion) es un modelo
matemático utilizado en finanzas para describir la evolución de los
precios de activos como acciones. Se basa en un movimiento browniano con
un crecimiento exponencial, considerando una tasa de retorno constante y
una volatilidad aleatoria. Es ampliamente usado en la valoración de
opciones y en simulaciones de precios de activos.
Collect real stock price data from Yahoo
Finance
Recolectamos datos de apple de la base de datos de yahoo finance con
la ayuda de la librería quantmod de R
Instalar paquetes y llamar
librerias
#install.packages("quantmod")
#install.packages("ggplot2")
#install.packages("dplyr")
#install.packages("tidyr")
library(quantmod)
library(ggplot2)
library(dplyr)
library(tidyr)
Paso 1: Recolectar datos reales de Yahoo
Finance
symbol <- "AAPL"
start_date <- "2010-01-01"
end_date <- Sys.Date()
Descargar los datos
getSymbols(symbol, src = "yahoo", from = start_date, to = end_date)
## [1] "AAPL"
Simulate stock prices using Geometric
Brownian Motion (GBM)
Este fragmento de código en R simula precios utilizando el modelo
Geométrico de Movimiento Browniano (GBM), que es útil para la
modelización financiera y la predicción de precios futuros de activos
basados en datos históricos.
Con μ=0.0009113= 0.0009113: Los precios tienen una
ligera tendencia al alza. Con σ=0.01757= 0.01757: Los
precios pueden mostrar variaciones diarias considerables alrededor de
esa tendencia, reflejando la volatilidad del mercado. En conjunto, estos
valores indican un activo financiero con un crecimiento esperado
positivo a largo plazo, pero con fluctuaciones diarias moderadas. Esto
es típico de muchos instrumentos financieros donde se espera un retorno
a largo plazo pero con movimientos de precios diarios impredecibles.
Parámetros del modelo GBM
log_returns <- diff(log(real_prices))
mu <- mean(log_returns, na.rm = TRUE)
sigma <- sd(log_returns, na.rm = TRUE)
S0 <- as.numeric(head(real_prices, 1)) # precio inicial (primer precio real)
Verificar los parámetros
calculados
cat("Mu: ", mu, "\n")
## Mu: 0.0009109554
cat("Sigma: ", sigma, "\n")
## Sigma: 0.01757749
Número de simulaciones y pasos
n_simulations <- 10 # Reducido para visualización
n_steps <- length(real_prices)
dt <- 1 / 252 # Asumimos 252 días de trading por año
Ajustar la tendencia con un modelo de
regresión lineal
time_index <- 1:n_steps
lm_model <- lm(log(real_prices) ~ time_index)
trend <- lm_model$coefficients[1] + lm_model$coefficients[2] * time_index
Simular los precios usando el modelo
GBM
set.seed(123)
simulated_prices <- matrix(0, nrow = n_steps, ncol = n_simulations)
for (i in 1:n_simulations) {
W <- c(0, cumsum(rnorm(n_steps - 1, 0, sqrt(dt)))) # Caminata aleatoria de Wiener
S <- exp(trend + (mu - 0.5 * sigma^2) * (0:(n_steps - 1)) * dt + sigma * W) # Modelo GBM ajustado con tendencia
simulated_prices[, i] <- S
}
Verificar si hay NAs en los precios
simulados
print(any(is.na(simulated_prices)))
## [1] FALSE
Compare the real and simulated prices
using error metrics and interpret the results
Dado el rango amplio de precios y la naturaleza volátil de los datos
bursátiles, estos errores no son excesivamente altos. son relativamente
buenos
MSE: 208.1941: Este valor puede parecer alto, pero en el contexto
de precios que han oscilado desde 7.64 hasta 241.53, es menos
preocupante.
MAE: 10.01358: Este valor sugiere que, en promedio, los precios
simulados difieren en aproximadamente 10 unidades de los precios
reales.
En el contexto de precios que van desde 7.64 hasta 241.53, un MAE de
10 unidades no es extremadamente alto e indica que hay una discrepancia
promedio notable que podría necesitar ajustes si se requiere una
precisión más alta.
En esta tabla podemos observar los valores de las simulaciones
comparadas con el precio real

How well did GBM simulate the real stock prices? compare with
results from part 01 Las simulaciones en el GBM fueron más
acertadas que las de la parte 1
What do the error metrics indicate about the model’s
accuracy? Ambos errores tanto el MSE como el MAE fueron más
bajos en el modelo de GBM lo que significa que tiene una precisión mayor
ya que un MSE más bajo indica que las simulaciones están muy cerca de
los precios reales en promedio. Es una medida de precisión global y un
MAE más bajo indica que las diferencias absolutas entre los precios
simulados y reales son pequeñas, lo que sugiere una buena precisión del
modelo.

Error métricas
real_prices_vector <- as.numeric(real_prices)
Error cuadrático medio (MSE) y Error
absoluto medio (MAE)
MSE <- mean((real_prices_vector - simulated_prices[,1])^2, na.rm = TRUE)
MAE <- mean(abs(real_prices_vector - simulated_prices[,1]), na.rm = TRUE)
cat("MSE: ", MSE, "\n")
## MSE: 208.1369
cat("MAE: ", MAE, "\n")
## MAE: 10.01158
# Calcular R-squared
SST <- sum((real_prices_vector - mean(real_prices_vector))^2) # Suma total de los cuadrados
SSE <- sum((real_prices_vector - simulated_prices[,1])^2) # Suma de los cuadrados de los errores
R_squared <- 1 - (SSE / SST)
cat("R-squared: ", R_squared, "\n")
## R-squared: 0.9532094
# Calcular MAPE (Mean Absolute Percentage Error)
MAPE <- mean(abs((real_prices_vector - simulated_prices[,1]) / real_prices_vector) * 100, na.rm = TRUE)
cat("MAPE: ", MAPE, "%\n")
## MAPE: 17.53245 %
Visualize and interpret the
results
Interpretación La línea azul muestra una tendencia
ascendente en los precios de las acciones de Apple Inc. desde 2010,
reflejando un crecimiento constante en su valor. Los picos indican
momentos de máximos históricos, posiblemente ligados a lanzamientos de
productos o anuncios financieros positivos, mientras que los valles
reflejan caídas por factores como crisis de mercado o informes
negativos. Además, las líneas de diferentes colores representan precios
simulados, y su similitud con la línea azul sugiere que las simulaciones
capturan correctamente las tendencias generales del mercado.
Crear un dataframe para los
gráficos
simulated_df <- data.frame(Date = index(real_prices), Real = real_prices_vector)
Convertir simulated_prices en un dataframe
con nombres explícitos para las simulaciones
simulated_df <- cbind(simulated_df, simulated_prices)
colnames(simulated_df)[-(1:2)] <- paste0("Sim_", 1:n_simulations)
Graficar precios reales vs
simulados
ggplot(simulated_df_long) +
geom_line(aes(x = Date, y = Price, color = Simulation)) + # Mostrar todas las simulaciones
geom_line(data = simulated_df, aes(x = Date, y = Real), color = "blue", size = 1) + # Mostrar precios reales
labs(title = "Comparación de precios reales y simulados",
x = "Fecha", y = "Precio") +
theme_minimal() +
theme(legend.title = element_blank())
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

LS0tDQp0aXRsZTogIlRhcmVhIDQgcGFydGUgMiINCmF1dGhvcjogIkVxdWlwbyAxIg0KZGF0ZTogIjIwMjUtMDItMTkiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQogICAgdGhlbWU6IGpvdXJuYWwNCi0tLQ0KIVtdKCkNCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+U3RvY2sgUHJpY2UgU2ltdWxhdGlvbiB1c2luZyBHZW9tZXRyaWMgQnJvd25pYW4gTW90aW9uIChHQk0pICYgRXJyb3IgQW5hbHlzaXM8L3NwYW4+DQpFbCAqKkdCTSAoR2VvbWV0cmljIEJyb3duaWFuIE1vdGlvbikqKiBlcyB1biBtb2RlbG8gbWF0ZW3DoXRpY28gdXRpbGl6YWRvIGVuIGZpbmFuemFzIHBhcmEgZGVzY3JpYmlyIGxhIGV2b2x1Y2nDs24gZGUgbG9zIHByZWNpb3MgZGUgYWN0aXZvcyBjb21vIGFjY2lvbmVzLiBTZSBiYXNhIGVuIHVuIG1vdmltaWVudG8gYnJvd25pYW5vIGNvbiB1biBjcmVjaW1pZW50byBleHBvbmVuY2lhbCwgY29uc2lkZXJhbmRvIHVuYSB0YXNhIGRlIHJldG9ybm8gY29uc3RhbnRlIHkgdW5hIHZvbGF0aWxpZGFkIGFsZWF0b3JpYS4gRXMgYW1wbGlhbWVudGUgdXNhZG8gZW4gbGEgdmFsb3JhY2nDs24gZGUgb3BjaW9uZXMgeSBlbiBzaW11bGFjaW9uZXMgZGUgcHJlY2lvcyBkZSBhY3Rpdm9zLg0KDQojIDxzcGFuIHN0eWxlID0gImNvbG9yOmJsdWU7Ij5Db2xsZWN0IHJlYWwgc3RvY2sgcHJpY2UgZGF0YSBmcm9tIFlhaG9vIEZpbmFuY2U8L3NwYW4+DQpSZWNvbGVjdGFtb3MgZGF0b3MgZGUgYXBwbGUgZGUgbGEgYmFzZSBkZSBkYXRvcyBkZSB5YWhvbyBmaW5hbmNlIGNvbiBsYSBheXVkYSBkZSBsYSBsaWJyZXLDrWEgcXVhbnRtb2QgZGUgUg0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+SW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyaWFzPC9zcGFuPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNpbnN0YWxsLnBhY2thZ2VzKCJxdWFudG1vZCIpDQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQojaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQ0KI2luc3RhbGwucGFja2FnZXMoInRpZHlyIikNCg0KbGlicmFyeShxdWFudG1vZCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOmJsdWU7Ij5QYXNvIDE6IFJlY29sZWN0YXIgZGF0b3MgcmVhbGVzIGRlIFlhaG9vIEZpbmFuY2U8L3NwYW4+DQpgYGB7cn0NCnN5bWJvbCA8LSAiQUFQTCINCnN0YXJ0X2RhdGUgPC0gIjIwMTAtMDEtMDEiDQplbmRfZGF0ZSA8LSBTeXMuRGF0ZSgpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6Ymx1ZTsiPkRlc2NhcmdhciBsb3MgZGF0b3M8L3NwYW4+DQpgYGB7cn0NCmdldFN5bWJvbHMoc3ltYm9sLCBzcmMgPSAieWFob28iLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSkNCmBgYA0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+RXh0cmFlciBsb3MgcHJlY2lvcyBkZSBjaWVycmU8L3NwYW4+DQpgYGB7cn0NCnJlYWxfcHJpY2VzIDwtIENsKGdldChzeW1ib2wpKQ0Kc3VtbWFyeShyZWFsX3ByaWNlcykNCmhlYWQocmVhbF9wcmljZXMpDQpgYGANCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+IFNpbXVsYXRlIHN0b2NrIHByaWNlcyB1c2luZyBHZW9tZXRyaWMgQnJvd25pYW4gTW90aW9uIChHQk0pPC9zcGFuPg0KRXN0ZSBmcmFnbWVudG8gZGUgY8OzZGlnbyBlbiBSIHNpbXVsYSBwcmVjaW9zIHV0aWxpemFuZG8gZWwgbW9kZWxvIEdlb23DqXRyaWNvIGRlIE1vdmltaWVudG8gQnJvd25pYW5vIChHQk0pLCBxdWUgZXMgw7p0aWwgcGFyYSBsYSBtb2RlbGl6YWNpw7NuIGZpbmFuY2llcmEgeSBsYSBwcmVkaWNjacOzbiBkZSBwcmVjaW9zIGZ1dHVyb3MgZGUgYWN0aXZvcyBiYXNhZG9zIGVuIGRhdG9zIGhpc3TDs3JpY29zLiANCg0KQ29uICoqzrw9MC4wMDA5MTEzXG11ID0gMC4wMDA5MTEzOioqIExvcyBwcmVjaW9zIHRpZW5lbiB1bmEgbGlnZXJhIHRlbmRlbmNpYSBhbCBhbHphLg0KQ29uICoqz4M9MC4wMTc1N1xzaWdtYSA9IDAuMDE3NTc6KiogTG9zIHByZWNpb3MgcHVlZGVuIG1vc3RyYXIgdmFyaWFjaW9uZXMgZGlhcmlhcyBjb25zaWRlcmFibGVzIGFscmVkZWRvciBkZSBlc2EgdGVuZGVuY2lhLCByZWZsZWphbmRvIGxhIHZvbGF0aWxpZGFkIGRlbCBtZXJjYWRvLg0KRW4gY29uanVudG8sIGVzdG9zIHZhbG9yZXMgaW5kaWNhbiB1biBhY3Rpdm8gZmluYW5jaWVybyBjb24gdW4gY3JlY2ltaWVudG8gZXNwZXJhZG8gcG9zaXRpdm8gYSBsYXJnbyBwbGF6bywgcGVybyBjb24gZmx1Y3R1YWNpb25lcyBkaWFyaWFzIG1vZGVyYWRhcy4gRXN0byBlcyB0w61waWNvIGRlIG11Y2hvcyBpbnN0cnVtZW50b3MgZmluYW5jaWVyb3MgZG9uZGUgc2UgZXNwZXJhIHVuIHJldG9ybm8gYSBsYXJnbyBwbGF6byBwZXJvIGNvbiBtb3ZpbWllbnRvcyBkZSBwcmVjaW9zIGRpYXJpb3MgaW1wcmVkZWNpYmxlcy4NCg0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+UGFyw6FtZXRyb3MgZGVsIG1vZGVsbyBHQk08L3NwYW4+DQpgYGB7cn0NCmxvZ19yZXR1cm5zIDwtIGRpZmYobG9nKHJlYWxfcHJpY2VzKSkNCm11IDwtIG1lYW4obG9nX3JldHVybnMsIG5hLnJtID0gVFJVRSkNCnNpZ21hIDwtIHNkKGxvZ19yZXR1cm5zLCBuYS5ybSA9IFRSVUUpDQpTMCA8LSBhcy5udW1lcmljKGhlYWQocmVhbF9wcmljZXMsIDEpKSAjIHByZWNpbyBpbmljaWFsIChwcmltZXIgcHJlY2lvIHJlYWwpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6Ymx1ZTsiPlZlcmlmaWNhciBsb3MgcGFyw6FtZXRyb3MgY2FsY3VsYWRvczwvc3Bhbj4NCmBgYHtyfQ0KY2F0KCJNdTogIiwgbXUsICJcbiIpDQpjYXQoIlNpZ21hOiAiLCBzaWdtYSwgIlxuIikNCmBgYA0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+TsO6bWVybyBkZSBzaW11bGFjaW9uZXMgeSBwYXNvczwvc3Bhbj4NCmBgYHtyfQ0Kbl9zaW11bGF0aW9ucyA8LSAxMCAgIyBSZWR1Y2lkbyBwYXJhIHZpc3VhbGl6YWNpw7NuDQpuX3N0ZXBzIDwtIGxlbmd0aChyZWFsX3ByaWNlcykNCmR0IDwtIDEgLyAyNTIgIyBBc3VtaW1vcyAyNTIgZMOtYXMgZGUgdHJhZGluZyBwb3IgYcOxbw0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOmJsdWU7Ij5BanVzdGFyIGxhIHRlbmRlbmNpYSBjb24gdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsPC9zcGFuPg0KYGBge3J9DQp0aW1lX2luZGV4IDwtIDE6bl9zdGVwcw0KbG1fbW9kZWwgPC0gbG0obG9nKHJlYWxfcHJpY2VzKSB+IHRpbWVfaW5kZXgpDQp0cmVuZCA8LSBsbV9tb2RlbCRjb2VmZmljaWVudHNbMV0gKyBsbV9tb2RlbCRjb2VmZmljaWVudHNbMl0gKiB0aW1lX2luZGV4DQpgYGANCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6Ymx1ZTsiPlNpbXVsYXIgbG9zIHByZWNpb3MgdXNhbmRvIGVsIG1vZGVsbyBHQk08L3NwYW4+DQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCnNpbXVsYXRlZF9wcmljZXMgPC0gbWF0cml4KDAsIG5yb3cgPSBuX3N0ZXBzLCBuY29sID0gbl9zaW11bGF0aW9ucykNCg0KZm9yIChpIGluIDE6bl9zaW11bGF0aW9ucykgew0KICBXIDwtIGMoMCwgY3Vtc3VtKHJub3JtKG5fc3RlcHMgLSAxLCAwLCBzcXJ0KGR0KSkpKSAjIENhbWluYXRhIGFsZWF0b3JpYSBkZSBXaWVuZXINCiAgUyA8LSBleHAodHJlbmQgKyAobXUgLSAwLjUgKiBzaWdtYV4yKSAqICgwOihuX3N0ZXBzIC0gMSkpICogZHQgKyBzaWdtYSAqIFcpICMgTW9kZWxvIEdCTSBhanVzdGFkbyBjb24gdGVuZGVuY2lhDQogIHNpbXVsYXRlZF9wcmljZXNbLCBpXSA8LSBTDQp9DQoNCmBgYA0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+VmVyaWZpY2FyIHNpIGhheSBOQXMgZW4gbG9zIHByZWNpb3Mgc2ltdWxhZG9zPC9zcGFuPg0KYGBge3J9DQpwcmludChhbnkoaXMubmEoc2ltdWxhdGVkX3ByaWNlcykpKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6Ymx1ZTsiPkNvbXBhcmUgdGhlIHJlYWwgYW5kIHNpbXVsYXRlZCBwcmljZXMgdXNpbmcgZXJyb3IgbWV0cmljcyBhbmQgaW50ZXJwcmV0IHRoZSByZXN1bHRzPC9zcGFuPg0KRGFkbyBlbCByYW5nbyBhbXBsaW8gZGUgcHJlY2lvcyB5IGxhIG5hdHVyYWxlemEgdm9sw6F0aWwgZGUgbG9zIGRhdG9zIGJ1cnPDoXRpbGVzLCBlc3RvcyBlcnJvcmVzIG5vIHNvbiBleGNlc2l2YW1lbnRlIGFsdG9zLiAgc29uIHJlbGF0aXZhbWVudGUgYnVlbm9zDQoNCiogTVNFOiAyMDguMTk0MTogRXN0ZSB2YWxvciBwdWVkZSBwYXJlY2VyIGFsdG8sIHBlcm8gZW4gZWwgY29udGV4dG8gZGUgcHJlY2lvcyBxdWUgaGFuIG9zY2lsYWRvIGRlc2RlIDcuNjQgaGFzdGEgMjQxLjUzLCBlcyBtZW5vcyBwcmVvY3VwYW50ZS4NCg0KKiBNQUU6IDEwLjAxMzU4OiBFc3RlIHZhbG9yIHN1Z2llcmUgcXVlLCBlbiBwcm9tZWRpbywgbG9zIHByZWNpb3Mgc2ltdWxhZG9zIGRpZmllcmVuIGVuIGFwcm94aW1hZGFtZW50ZSAxMCB1bmlkYWRlcyBkZSBsb3MgcHJlY2lvcyByZWFsZXMuDQoNCkVuIGVsIGNvbnRleHRvIGRlIHByZWNpb3MgcXVlIHZhbiBkZXNkZSA3LjY0IGhhc3RhIDI0MS41MywgdW4gTUFFIGRlIDEwIHVuaWRhZGVzIG5vIGVzIGV4dHJlbWFkYW1lbnRlIGFsdG8gZSBpbmRpY2EgcXVlIGhheSB1bmEgZGlzY3JlcGFuY2lhIHByb21lZGlvIG5vdGFibGUgcXVlIHBvZHLDrWEgbmVjZXNpdGFyIGFqdXN0ZXMgc2kgc2UgcmVxdWllcmUgdW5hIHByZWNpc2nDs24gbcOhcyBhbHRhLg0KDQpFbiBlc3RhIHRhYmxhIHBvZGVtb3Mgb2JzZXJ2YXIgbG9zIHZhbG9yZXMgZGUgbGFzIHNpbXVsYWNpb25lcyBjb21wYXJhZGFzIGNvbiBlbCBwcmVjaW8gcmVhbA0KDQohW10oQzpcXFVzZXJzXFxMdWlzIE1lbmRvemFcXERvd25sb2Fkc1xcU2ltdWxhY2lvbmVzLnBuZykNCg0KKipIb3cgd2VsbCBkaWQgR0JNIHNpbXVsYXRlIHRoZSByZWFsIHN0b2NrIHByaWNlcz8gY29tcGFyZSB3aXRoIHJlc3VsdHMgZnJvbSBwYXJ0IDAxKioNCkxhcyBzaW11bGFjaW9uZXMgZW4gZWwgR0JNIGZ1ZXJvbiBtw6FzIGFjZXJ0YWRhcyBxdWUgbGFzIGRlIGxhIHBhcnRlIDENCiANCioqV2hhdCBkbyB0aGUgZXJyb3IgbWV0cmljcyBpbmRpY2F0ZSBhYm91dCB0aGUgbW9kZWzigJlzIGFjY3VyYWN5PyoqDQpBbWJvcyBlcnJvcmVzIHRhbnRvIGVsIE1TRSBjb21vIGVsIE1BRSBmdWVyb24gbcOhcyBiYWpvcyBlbiBlbCBtb2RlbG8gZGUgR0JNIGxvIHF1ZSBzaWduaWZpY2EgcXVlIHRpZW5lIHVuYSBwcmVjaXNpw7NuIG1heW9yIHlhIHF1ZSB1biBNU0UgbcOhcyBiYWpvIGluZGljYSBxdWUgbGFzIHNpbXVsYWNpb25lcyBlc3TDoW4gbXV5IGNlcmNhIGRlIGxvcyBwcmVjaW9zIHJlYWxlcyBlbiBwcm9tZWRpby4gRXMgdW5hIG1lZGlkYSBkZSBwcmVjaXNpw7NuIGdsb2JhbCB5IHVuIE1BRSBtw6FzIGJham8gaW5kaWNhIHF1ZSBsYXMgZGlmZXJlbmNpYXMgYWJzb2x1dGFzIGVudHJlIGxvcyBwcmVjaW9zIHNpbXVsYWRvcyB5IHJlYWxlcyBzb24gcGVxdWXDsWFzLCBsbyBxdWUgc3VnaWVyZSB1bmEgYnVlbmEgcHJlY2lzacOzbiBkZWwgbW9kZWxvLg0KDQoNCiFbXShDOlxcVXNlcnNcXEx1aXMgTWVuZG96YVxcRG93bmxvYWRzXFxNQUUgTVNFLnBuZykNCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6Ymx1ZTsiPkVycm9yIG3DqXRyaWNhczwvc3Bhbj4NCmBgYHtyfQ0KcmVhbF9wcmljZXNfdmVjdG9yIDwtIGFzLm51bWVyaWMocmVhbF9wcmljZXMpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6Ymx1ZTsiPkVycm9yIGN1YWRyw6F0aWNvIG1lZGlvIChNU0UpIHkgRXJyb3IgYWJzb2x1dG8gbWVkaW8gKE1BRSk8L3NwYW4+DQpgYGB7cn0NCk1TRSA8LSBtZWFuKChyZWFsX3ByaWNlc192ZWN0b3IgLSBzaW11bGF0ZWRfcHJpY2VzWywxXSleMiwgbmEucm0gPSBUUlVFKSAgDQpNQUUgPC0gbWVhbihhYnMocmVhbF9wcmljZXNfdmVjdG9yIC0gc2ltdWxhdGVkX3ByaWNlc1ssMV0pLCBuYS5ybSA9IFRSVUUpICANCg0KY2F0KCJNU0U6ICIsIE1TRSwgIlxuIikNCmNhdCgiTUFFOiAiLCBNQUUsICJcbiIpDQoNCiMgQ2FsY3VsYXIgUi1zcXVhcmVkDQpTU1QgPC0gc3VtKChyZWFsX3ByaWNlc192ZWN0b3IgLSBtZWFuKHJlYWxfcHJpY2VzX3ZlY3RvcikpXjIpICAjIFN1bWEgdG90YWwgZGUgbG9zIGN1YWRyYWRvcw0KU1NFIDwtIHN1bSgocmVhbF9wcmljZXNfdmVjdG9yIC0gc2ltdWxhdGVkX3ByaWNlc1ssMV0pXjIpICAjIFN1bWEgZGUgbG9zIGN1YWRyYWRvcyBkZSBsb3MgZXJyb3Jlcw0KUl9zcXVhcmVkIDwtIDEgLSAoU1NFIC8gU1NUKQ0KDQpjYXQoIlItc3F1YXJlZDogIiwgUl9zcXVhcmVkLCAiXG4iKQ0KDQojIENhbGN1bGFyIE1BUEUgKE1lYW4gQWJzb2x1dGUgUGVyY2VudGFnZSBFcnJvcikNCk1BUEUgPC0gbWVhbihhYnMoKHJlYWxfcHJpY2VzX3ZlY3RvciAtIHNpbXVsYXRlZF9wcmljZXNbLDFdKSAvIHJlYWxfcHJpY2VzX3ZlY3RvcikgKiAxMDAsIG5hLnJtID0gVFJVRSkNCg0KY2F0KCJNQVBFOiAiLCBNQVBFLCAiJVxuIikNCmBgYA0KDQojIDxzcGFuIHN0eWxlID0gImNvbG9yOmJsdWU7Ij5WaXN1YWxpemUgYW5kIGludGVycHJldCB0aGUgcmVzdWx0czwvc3Bhbj4NCioqSW50ZXJwcmV0YWNpw7NuKioNCkxhIGzDrW5lYSBhenVsIG11ZXN0cmEgdW5hIHRlbmRlbmNpYSBhc2NlbmRlbnRlIGVuIGxvcyBwcmVjaW9zIGRlIGxhcyBhY2Npb25lcyBkZSBBcHBsZSBJbmMuIGRlc2RlIDIwMTAsIHJlZmxlamFuZG8gdW4gY3JlY2ltaWVudG8gY29uc3RhbnRlIGVuIHN1IHZhbG9yLiBMb3MgcGljb3MgaW5kaWNhbiBtb21lbnRvcyBkZSBtw6F4aW1vcyBoaXN0w7NyaWNvcywgcG9zaWJsZW1lbnRlIGxpZ2Fkb3MgYSBsYW56YW1pZW50b3MgZGUgcHJvZHVjdG9zIG8gYW51bmNpb3MgZmluYW5jaWVyb3MgcG9zaXRpdm9zLCBtaWVudHJhcyBxdWUgbG9zIHZhbGxlcyByZWZsZWphbiBjYcOtZGFzIHBvciBmYWN0b3JlcyBjb21vIGNyaXNpcyBkZSBtZXJjYWRvIG8gaW5mb3JtZXMgbmVnYXRpdm9zLiBBZGVtw6FzLCBsYXMgbMOtbmVhcyBkZSBkaWZlcmVudGVzIGNvbG9yZXMgcmVwcmVzZW50YW4gcHJlY2lvcyBzaW11bGFkb3MsIHkgc3Ugc2ltaWxpdHVkIGNvbiBsYSBsw61uZWEgYXp1bCBzdWdpZXJlIHF1ZSBsYXMgc2ltdWxhY2lvbmVzIGNhcHR1cmFuIGNvcnJlY3RhbWVudGUgbGFzIHRlbmRlbmNpYXMgZ2VuZXJhbGVzIGRlbCBtZXJjYWRvLg0KDQoNCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOmJsdWU7Ij5DcmVhciB1biBkYXRhZnJhbWUgcGFyYSBsb3MgZ3LDoWZpY29zPC9zcGFuPg0KYGBge3J9DQpzaW11bGF0ZWRfZGYgPC0gZGF0YS5mcmFtZShEYXRlID0gaW5kZXgocmVhbF9wcmljZXMpLCBSZWFsID0gcmVhbF9wcmljZXNfdmVjdG9yKQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOmJsdWU7Ij5Db252ZXJ0aXIgc2ltdWxhdGVkX3ByaWNlcyBlbiB1biBkYXRhZnJhbWUgY29uIG5vbWJyZXMgZXhwbMOtY2l0b3MgcGFyYSBsYXMgc2ltdWxhY2lvbmVzPC9zcGFuPg0KYGBge3J9DQpzaW11bGF0ZWRfZGYgPC0gY2JpbmQoc2ltdWxhdGVkX2RmLCBzaW11bGF0ZWRfcHJpY2VzKQ0KY29sbmFtZXMoc2ltdWxhdGVkX2RmKVstKDE6MildIDwtIHBhc3RlMCgiU2ltXyIsIDE6bl9zaW11bGF0aW9ucykNCmBgYA0KDQojIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjpibHVlOyI+Q29udmVydGlyIGVsIGRhdGFmcmFtZSBhIGZvcm1hdG8gbGFyZ28gcGFyYSBnZ3Bsb3Q8L3NwYW4+DQpgYGB7cn0NCnNpbXVsYXRlZF9kZl9sb25nIDwtIHNpbXVsYXRlZF9kZiAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiU2ltXyIpLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlNpbXVsYXRpb24iLCANCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJQcmljZSIpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6Ymx1ZTsiPkdyYWZpY2FyIHByZWNpb3MgcmVhbGVzIHZzIHNpbXVsYWRvczwvc3Bhbj4NCmBgYHtyfQ0KZ2dwbG90KHNpbXVsYXRlZF9kZl9sb25nKSArDQogIGdlb21fbGluZShhZXMoeCA9IERhdGUsIHkgPSBQcmljZSwgY29sb3IgPSBTaW11bGF0aW9uKSkgKyAgIyBNb3N0cmFyIHRvZGFzIGxhcyBzaW11bGFjaW9uZXMNCiAgZ2VvbV9saW5lKGRhdGEgPSBzaW11bGF0ZWRfZGYsIGFlcyh4ID0gRGF0ZSwgeSA9IFJlYWwpLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsgICMgTW9zdHJhciBwcmVjaW9zIHJlYWxlcw0KICBsYWJzKHRpdGxlID0gIkNvbXBhcmFjacOzbiBkZSBwcmVjaW9zIHJlYWxlcyB5IHNpbXVsYWRvcyIsDQogICAgICAgeCA9ICJGZWNoYSIsIHkgPSAiUHJlY2lvIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpDQpgYGANCg0KDQoNCg==