VINTAGE RESTAURANT - CASO DE
ESTUDIO
Explicación
Este documento resuelve el caso “The Vintage
Restaurant” (Tabla 18.26): ventas mensuales de alimentos y
bebidas (en miles de $) durante los primeros 3 años de operación del
restaurante en Captiva Island, Florida.
**Para resolver el problema se usaron:
- Descomposición clásica de series de tiempo
(Tendencia × Estacionalidad), y
- Regresión con variables ficticias (dummy variables)
para el componente estacional.
Ambos métodos siguen perteneciendo al tema de Series de
Tiempo, pero corresponden a un enfoque distinto: en vez de suavizar
la serie o dejar que un algoritmo decida la estructura (como
auto.arima), aquí se descompone
explícitamente la serie en Tendencia (T), Estacionalidad (S) e
Irregular (I), y se pronostica combinando esos componentes. Es el
enfoque clásico para series fuertemente estacionales con pocos
años de historia (aquí solo 3 años = 36 meses), donde un ARIMA
estacional no se podría estimar de forma confiable.
INSTALACIÓN DE LIBRERÍAS
#install.packages("forecast")
#install.packages("knitr")
library(forecast)
library(knitr)
CARGA DE DATOS (Tabla
18.26)
meses <- c("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto",
"Septiembre","Octubre","Noviembre","Diciembre")
año1 <- c(242,235,232,178,184,140,145,152,110,130,152,206)
año2 <- c(263,238,247,193,193,149,157,161,122,130,167,230)
año3 <- c(282,255,265,205,210,160,166,174,126,148,173,235)
ventas <- c(año1, año2, año3)
n <- length(ventas)
t <- 1:n
dataframe3 <- data.frame(
t = t,
mes = factor(rep(meses, 3), levels = meses),
año = rep(1:3, each = 12),
ventas = ventas
)
kable(dataframe3, caption = "Ventas mensuales - Vintage Restaurant (miles de $)")
Ventas mensuales - Vintage Restaurant (miles de $)
| 1 |
Enero |
1 |
242 |
| 2 |
Febrero |
1 |
235 |
| 3 |
Marzo |
1 |
232 |
| 4 |
Abril |
1 |
178 |
| 5 |
Mayo |
1 |
184 |
| 6 |
Junio |
1 |
140 |
| 7 |
Julio |
1 |
145 |
| 8 |
Agosto |
1 |
152 |
| 9 |
Septiembre |
1 |
110 |
| 10 |
Octubre |
1 |
130 |
| 11 |
Noviembre |
1 |
152 |
| 12 |
Diciembre |
1 |
206 |
| 13 |
Enero |
2 |
263 |
| 14 |
Febrero |
2 |
238 |
| 15 |
Marzo |
2 |
247 |
| 16 |
Abril |
2 |
193 |
| 17 |
Mayo |
2 |
193 |
| 18 |
Junio |
2 |
149 |
| 19 |
Julio |
2 |
157 |
| 20 |
Agosto |
2 |
161 |
| 21 |
Septiembre |
2 |
122 |
| 22 |
Octubre |
2 |
130 |
| 23 |
Noviembre |
2 |
167 |
| 24 |
Diciembre |
2 |
230 |
| 25 |
Enero |
3 |
282 |
| 26 |
Febrero |
3 |
255 |
| 27 |
Marzo |
3 |
265 |
| 28 |
Abril |
3 |
205 |
| 29 |
Mayo |
3 |
210 |
| 30 |
Junio |
3 |
160 |
| 31 |
Julio |
3 |
166 |
| 32 |
Agosto |
3 |
174 |
| 33 |
Septiembre |
3 |
126 |
| 34 |
Octubre |
3 |
148 |
| 35 |
Noviembre |
3 |
173 |
| 36 |
Diciembre |
3 |
235 |
# Serie de tiempo mensual, iniciando en Enero del Año 1
tsVINTAGE <- ts(ventas, start = c(1,1), frequency = 12)
tsVINTAGE
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 1 242 235 232 178 184 140 145 152 110 130 152 206
## 2 263 238 247 193 193 149 157 161 122 130 167 230
## 3 282 255 265 205 210 160 166 174 126 148 173 235
1. GRÁFICA DE LA SERIE DE
TIEMPO
plot(tsVINTAGE, main = "Ventas mensuales de alimentos y bebidas - Vintage Restaurant",
ylab = "Ventas ($ miles)", xlab = "Año", type = "o", col = "steelblue", pch = 16)

Comentario sobre el patrón principal:
La serie muestra dos componentes claros:
- Tendencia creciente: las ventas de cada mes
aumentan de un año a otro (por ejemplo, enero pasa de 242 a 263 y a 282
en los 3 años), reflejando el crecimiento del restaurante.
- Estacionalidad marcada y repetitiva de periodo 12:
cada año se repite el mismo patrón — ventas altas en enero,
febrero, marzo y diciembre (temporada alta turística en
Florida) y ventas bajas en junio, julio, agosto y especialmente
septiembre (temporada baja).
No se aprecia un patrón cíclico de largo plazo ni irregularidades
severas; el comportamiento es consistente año con año.
2. ANÁLISIS DE ESTACIONALIDAD - ÍNDICES
ESTACIONALES
Se usa el método clásico de razón al promedio móvil centrado
(CMA) de orden 12 (método de descomposición multiplicativa,
disponible en R con decompose()):
descomposicion <- decompose(tsVINTAGE, type = "multiplicative")
plot(descomposicion)

# Índices estacionales (uno por mes, promediados y normalizados a promedio = 1)
indice_estacional <- descomposicion$figure
names(indice_estacional) <- meses
tabla_estacional <- data.frame(
Mes = meses,
Indice_Estacional = round(indice_estacional, 4)
)
kable(tabla_estacional, caption = "Índices estacionales por mes")
Índices estacionales por mes
| Enero |
Enero |
1.4436 |
| Febrero |
Febrero |
1.2997 |
| Marzo |
Marzo |
1.3441 |
| Abril |
Abril |
1.0412 |
| Mayo |
Mayo |
1.0494 |
| Junio |
Junio |
0.8004 |
| Julio |
Julio |
0.8283 |
| Agosto |
Agosto |
0.8530 |
| Septiembre |
Septiembre |
0.6280 |
| Octubre |
Octubre |
0.7003 |
| Noviembre |
Noviembre |
0.8528 |
| Diciembre |
Diciembre |
1.1593 |
barplot(indice_estacional, names.arg = meses, las = 2, col = "salmon",
main = "Índice estacional por mes - Vintage Restaurant",
ylab = "Índice estacional")
abline(h = 1, lty = 2)

Comentario sobre los índices estacionales:
- Temporada alta: enero (≈1.44), marzo (≈1.34) y
febrero (≈1.30) están muy por encima de 1 — las ventas de esos meses son
entre 30% y 44% superiores al promedio anual. Diciembre también está por
arriba del promedio (≈1.16).
- Temporada baja: septiembre es el mes más débil
(≈0.63, es decir, 37% por debajo del promedio), seguido de octubre
(≈0.70) y junio (≈0.80).
¿Tienen sentido intuitivo? Sí. Captiva Island, cerca
de Fort Myers, es un destino turístico de invierno en Florida (“snowbird
season”): los turistas del norte de EE. UU. y Canadá llegan de diciembre
a marzo escapando del frío, lo que explica los índices altos en esos
meses. En cambio, el verano (junio-septiembre) coincide con el clima
húmedo y caluroso de Florida y la temporada de huracanes, por lo que
baja el turismo — de ahí los índices bajos, con su mínimo en
septiembre.
3. DESESTACIONALIZACIÓN DE LA
SERIE
serie_desestacionalizada <- tsVINTAGE / rep(indice_estacional, 3)
plot(t, as.numeric(serie_desestacionalizada), type = "o", col = "darkgreen",
main = "Serie desestacionalizada - Vintage Restaurant",
xlab = "Mes (t)", ylab = "Ventas ($ miles), sin efecto estacional")
# Tendencia lineal sobre la serie desestacionalizada
modelo_tendencia <- lm(as.numeric(serie_desestacionalizada) ~ t)
summary(modelo_tendencia)
##
## Call:
## lm(formula = as.numeric(serie_desestacionalizada) ~ t)
##
## Residuals:
## Min 1Q Median 3Q Max
## -6.1892 -2.2527 -0.4848 0.8131 9.4189
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 169.3494 1.0926 155.00 <2e-16 ***
## t 1.0213 0.0515 19.83 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.21 on 34 degrees of freedom
## Multiple R-squared: 0.9204, Adjusted R-squared: 0.9181
## F-statistic: 393.3 on 1 and 34 DF, p-value: < 2.2e-16
lines(t, fitted(modelo_tendencia), col = "black", lty = 2, lwd = 2)
legend("topleft", legend = c("Serie desestacionalizada", "Tendencia lineal"),
col = c("darkgreen","black"), lty = c(1,2), pch = c(1,NA))

¿Existe tendencia en la serie
desestacionalizada?
Sí, una vez removido el efecto estacional, la serie
desestacionalizada muestra una tendencia lineal creciente
clara (pendiente ≈ +1.02 miles de $ por mes, con R² ≈ 0.92),
consistente con el crecimiento del restaurante mes a mes a lo largo de
los 3 años, sin el “ruido” que generaba la estacionalidad.
4. PRONÓSTICO - MÉTODO DE
DESCOMPOSICIÓN
El pronóstico para cada mes del Año 4 se obtiene
multiplicando el valor proyectado de la tendencia por el índice
estacional correspondiente a ese mes:
\[ \hat{Y}_t = (b_0 + b_1 \cdot t) \times
SI_{mes} \]
t_futuro <- (n+1):(n+12) # meses 37 a 48 = Año 4
b0 <- coef(modelo_tendencia)[1]
b1 <- coef(modelo_tendencia)[2]
tendencia_futura <- b0 + b1 * t_futuro
pronostico_descomposicion <- tendencia_futura * as.numeric(indice_estacional)
tabla_descomposicion <- data.frame(
Mes = meses,
t = t_futuro,
Tendencia_Proyectada = round(tendencia_futura, 2),
Indice_Estacional = round(as.numeric(indice_estacional), 4),
Pronostico_Descomposicion = round(pronostico_descomposicion, 2)
)
kable(tabla_descomposicion, caption = "Pronóstico Año 4 - Método de Descomposición")
Pronóstico Año 4 - Método de Descomposición
| Enero |
37 |
207.14 |
1.4436 |
299.02 |
| Febrero |
38 |
208.16 |
1.2997 |
270.54 |
| Marzo |
39 |
209.18 |
1.3441 |
281.16 |
| Abril |
40 |
210.20 |
1.0412 |
218.86 |
| Mayo |
41 |
211.22 |
1.0494 |
221.65 |
| Junio |
42 |
212.24 |
0.8004 |
169.88 |
| Julio |
43 |
213.27 |
0.8283 |
176.65 |
| Agosto |
44 |
214.29 |
0.8530 |
182.78 |
| Septiembre |
45 |
215.31 |
0.6280 |
135.21 |
| Octubre |
46 |
216.33 |
0.7003 |
151.50 |
| Noviembre |
47 |
217.35 |
0.8528 |
185.35 |
| Diciembre |
48 |
218.37 |
1.1593 |
253.15 |
plot(t, ventas, type = "o", col = "steelblue",
xlim = c(1, max(t_futuro)), ylim = range(c(ventas, pronostico_descomposicion)),
main = "Pronóstico Año 4 - Método de Descomposición",
xlab = "Mes (t)", ylab = "Ventas ($ miles)")
lines(t_futuro, pronostico_descomposicion, type = "o", col = "red", pch = 15)
legend("topleft", legend = c("Ventas históricas (Años 1-3)", "Pronóstico Año 4"),
col = c("steelblue","red"), pch = c(1,15))

cat("Ventas totales pronosticadas Año 4 (Descomposición):", round(sum(pronostico_descomposicion),2), "\n")
## Ventas totales pronosticadas Año 4 (Descomposición): 2545.76
5. PRONÓSTICO - REGRESIÓN CON VARIABLES
FICTICIAS (DUMMY)
Se plantea un modelo de regresión múltiple:
\[ Ventas_t = b_0 + b_1 \cdot t + b_2
M_{ene} + b_3 M_{feb} + \dots + b_{12} M_{nov} + \varepsilon_t
\]
Se usan 11 variables dummy (enero a noviembre);
diciembre queda como categoría base (su efecto está incluido en el
intercepto).
# "mes" ya es un factor con Diciembre al final -> Diciembre queda como nivel de referencia
modelo_dummy <- lm(ventas ~ t + mes, data = dataframe3)
summary(modelo_dummy)
##
## Call:
## lm(formula = ventas ~ t + mes, data = dataframe3)
##
## Residuals:
## Min 1Q Median 3Q Max
## -8.1250 -1.9583 0.1667 2.2292 7.4583
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 249.10764 2.74567 90.727 < 2e-16 ***
## t 1.01736 0.07554 13.467 2.14e-12 ***
## mesFebrero -20.68403 3.62688 -5.703 8.30e-06 ***
## mesMarzo -16.36806 3.62924 -4.510 0.000158 ***
## mesAbril -73.38542 3.63317 -20.199 3.90e-16 ***
## mesMayo -70.73611 3.63866 -19.440 8.97e-16 ***
## mesJunio -117.75347 3.64571 -32.299 < 2e-16 ***
## mesJulio -112.43750 3.65431 -30.768 < 2e-16 ***
## mesAgosto -107.12153 3.66445 -29.233 < 2e-16 ***
## mesSeptiembre -151.13889 3.67611 -41.114 < 2e-16 ***
## mesOctubre -135.48958 3.68928 -36.725 < 2e-16 ***
## mesNoviembre -108.50694 3.70395 -29.295 < 2e-16 ***
## mesDiciembre -49.85764 3.72009 -13.402 2.36e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.441 on 23 degrees of freedom
## Multiple R-squared: 0.9942, Adjusted R-squared: 0.9911
## F-statistic: 327 on 12 and 23 DF, p-value: < 2.2e-16
# Pronóstico Año 4 con el modelo de dummies
nuevos_datos <- data.frame(
t = t_futuro,
mes = factor(meses, levels = meses)
)
pronostico_dummy <- predict(modelo_dummy, newdata = nuevos_datos)
tabla_dummy <- data.frame(
Mes = meses,
t = t_futuro,
Pronostico_Regresion_Dummy = round(as.numeric(pronostico_dummy), 2)
)
kable(tabla_dummy, caption = "Pronóstico Año 4 - Regresión con Variables Dummy")
Pronóstico Año 4 - Regresión con Variables Dummy
| Enero |
37 |
286.75 |
| Febrero |
38 |
267.08 |
| Marzo |
39 |
272.42 |
| Abril |
40 |
216.42 |
| Mayo |
41 |
220.08 |
| Junio |
42 |
174.08 |
| Julio |
43 |
180.42 |
| Agosto |
44 |
186.75 |
| Septiembre |
45 |
143.75 |
| Octubre |
46 |
160.42 |
| Noviembre |
47 |
188.42 |
| Diciembre |
48 |
248.08 |
plot(t, ventas, type = "o", col = "steelblue",
xlim = c(1, max(t_futuro)), ylim = range(c(ventas, pronostico_dummy)),
main = "Pronóstico Año 4 - Regresión con Variables Dummy",
xlab = "Mes (t)", ylab = "Ventas ($ miles)")
lines(t_futuro, pronostico_dummy, type = "o", col = "darkorange", pch = 17)
legend("topleft", legend = c("Ventas históricas (Años 1-3)", "Pronóstico Año 4"),
col = c("steelblue","darkorange"), pch = c(1,17))

cat("Ventas totales pronosticadas Año 4 (Regresión Dummy):", round(sum(pronostico_dummy),2), "\n")
## Ventas totales pronosticadas Año 4 (Regresión Dummy): 2544.67
6. TABLAS Y GRÁFICAS RESUMEN
tabla_resumen <- data.frame(
Mes = meses,
Indice_Estacional = round(as.numeric(indice_estacional), 4),
Pronostico_Descomposicion = round(pronostico_descomposicion, 2),
Pronostico_Regresion_Dummy = round(as.numeric(pronostico_dummy), 2),
Diferencia = round(pronostico_descomposicion - as.numeric(pronostico_dummy), 2)
)
kable(tabla_resumen, caption = "Resumen comparativo de pronósticos - Año 4")
Resumen comparativo de pronósticos - Año 4
| Enero |
1.4436 |
299.02 |
286.75 |
12.27 |
| Febrero |
1.2997 |
270.54 |
267.08 |
3.46 |
| Marzo |
1.3441 |
281.16 |
272.42 |
8.75 |
| Abril |
1.0412 |
218.86 |
216.42 |
2.45 |
| Mayo |
1.0494 |
221.65 |
220.08 |
1.57 |
| Junio |
0.8004 |
169.88 |
174.08 |
-4.21 |
| Julio |
0.8283 |
176.65 |
180.42 |
-3.77 |
| Agosto |
0.8530 |
182.78 |
186.75 |
-3.97 |
| Septiembre |
0.6280 |
135.21 |
143.75 |
-8.54 |
| Octubre |
0.7003 |
151.50 |
160.42 |
-8.92 |
| Noviembre |
0.8528 |
185.35 |
188.42 |
-3.07 |
| Diciembre |
1.1593 |
253.15 |
248.08 |
5.07 |
plot(1:12, pronostico_descomposicion, type = "o", col = "red", pch = 15,
xaxt = "n", ylim = range(c(pronostico_descomposicion, pronostico_dummy)),
main = "Comparación de pronósticos - Año 4",
xlab = "Mes", ylab = "Ventas pronosticadas ($ miles)")
lines(1:12, pronostico_dummy, type = "o", col = "darkorange", pch = 17)
axis(1, at = 1:12, labels = meses, las = 2)
legend("topright", legend = c("Descomposición", "Regresión Dummy"),
col = c("red","darkorange"), pch = c(15,17))

7. ERROR DE PRONÓSTICO - ENERO AÑO 4
(VENTAS REALES = $295,000)
ventas_reales_enero4 <- 295
pronostico_enero4_descomp <- pronostico_descomposicion[1]
pronostico_enero4_dummy <- as.numeric(pronostico_dummy)[1]
error_descomp <- ventas_reales_enero4 - pronostico_enero4_descomp
error_dummy <- ventas_reales_enero4 - pronostico_enero4_dummy
cat("Pronóstico Enero Año 4 (Descomposición):", round(pronostico_enero4_descomp,2),
" -> Error:", round(error_descomp,2), "\n")
## Pronóstico Enero Año 4 (Descomposición): 299.02 -> Error: -4.02
cat("Pronóstico Enero Año 4 (Regresión Dummy):", round(pronostico_enero4_dummy,2),
" -> Error:", round(error_dummy,2), "\n\n")
## Pronóstico Enero Año 4 (Regresión Dummy): 286.75 -> Error: 8.25
cat("Error porcentual (Descomposición):", round(100*error_descomp/ventas_reales_enero4,2), "%\n")
## Error porcentual (Descomposición): -1.36 %
cat("Error porcentual (Regresión Dummy):", round(100*error_dummy/ventas_reales_enero4,2), "%\n")
## Error porcentual (Regresión Dummy): 2.8 %
Interpretación del error de pronóstico:
Ambos modelos pronostican enero del Año 4 muy cerca de las ventas
reales de $295,000 (el error es de apenas unos cuantos miles de dólares,
es decir, menos del 3% en ambos casos). Este es un
error pequeño y esperable: ningún modelo de pronóstico es perfecto, ya
que existen factores que no captura la tendencia ni la estacionalidad
histórica (clima de ese mes en particular, eventos locales, cambios en
la competencia, publicidad, etc.).
¿Qué se puede hacer para reducir la incertidumbre de Karen
sobre el proceso de pronóstico?
- Presentar el pronóstico como un rango, no como un número
exacto — por ejemplo, un intervalo de confianza (± cierto
margen basado en el error histórico de los modelos) en vez de una sola
cifra, para que Karen entienda que el pronóstico es una
estimación, no una promesa.
- Actualizar el modelo cada vez que hay un nuevo mes de datos
reales (pronóstico “rodante”): conforme pasan los meses del Año
4, se reincorporan las ventas reales y se reajustan tendencia e índices
estacionales, lo cual reduce el error en los meses siguientes.
- Monitorear el error de pronóstico mes a mes (MAD,
MAPE, RMSE) para detectar si el modelo se está desviando de forma
sistemática (por ejemplo, si septiembre real siempre resulta más alto
que el pronóstico, hay que revisar el índice estacional de ese
mes).
- Incorporar información adicional cuando esté
disponible (reservaciones ya confirmadas, ocupación hotelera de la isla,
tendencias turísticas de Florida) para ajustar el pronóstico puramente
estadístico con juicio de negocio.
- Usar varios métodos en paralelo (como se hizo aquí
con descomposición y regresión dummy) y promediarlos o mostrar el rango
entre ellos, en vez de depender de un solo modelo — esto ya por sí mismo
comunica a Karen el grado de incertidumbre inherente al ejercicio.
CONCLUSIONES
Patrón de la serie: las ventas de Vintage
Restaurant combinan una tendencia de crecimiento
sostenido (aprox. +$1,000 al mes en términos
desestacionalizados) con una estacionalidad fuerte y
repetitiva ligada a la temporada turística de invierno en
Florida.
Estacionalidad: enero, febrero, marzo y
diciembre son los meses de temporada alta (índices entre 1.16 y 1.44);
junio, julio, agosto, septiembre y octubre son de temporada baja
(índices entre 0.63 y 0.85), con septiembre como el mes más flojo del
año. Estos patrones tienen pleno sentido dado que Captiva Island es un
destino de “snowbirds” en temporada de invierno.
Serie desestacionalizada: una vez removido el
efecto estacional, se confirma una tendencia lineal creciente clara (R²
≈ 0.92), señal de que el crecimiento del negocio es real y consistente,
no un artefacto de la estacionalidad.
Pronósticos Año 4: tanto el método de
descomposición clásica como la regresión con variables dummy arrojan
pronósticos consistentes entre sí (diferencias menores al 5% mes a mes),
con enero y marzo del Año 4 como los meses de mayor venta
esperada (~$280,000-$300,000) y septiembre como el mes
más bajo (~$135,000-$145,000).
Validación con datos reales: al comparar contra
la venta real de enero del Año 4 ($295,000), ambos modelos tuvieron un
error menor al 3%, lo que valida la metodología, aunque se recomienda a
Karen tratar cualquier pronóstico como una estimación con
incertidumbre, no como una cifra exacta, y actualizar el modelo
conforme lleguen nuevos datos reales.
Recomendación general para Karen: usar estos
pronósticos principalmente para planeación de personal, compras
de inventario (mariscos frescos) y flujo de caja, reforzando la
operación en los meses de temporada alta (dic-mar) y ajustando
costos/personal en los meses de temporada baja (jun-oct), sin perder de
vista que la tendencia general del negocio sigue siendo de
crecimiento.
LS0tDQp0aXRsZTogIlRFTUEyX1RpbWVzZXJpZXMrR0VGQSAoRGVzY29tcG9zaWNpw7NuIHkgUmVncmVzacOzbiBEdW1teSkiDQphdXRob3I6ICJMdWNlcm9fU2FsYXphcl9BMDA4MzQ4OTMiDQpkYXRlOiAiMjAyNi0wOC0yNiINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRoZW1lOiB1bml0ZWQNCi0tLQ0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlZJTlRBR0UgUkVTVEFVUkFOVCAtIENBU08gREUgRVNUVURJTzwvc3Bhbj4NCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiB5ZWxsb3c7Ij5FeHBsaWNhY2nDs248L3NwYW4+DQoNCkVzdGUgZG9jdW1lbnRvIHJlc3VlbHZlIGVsIGNhc28gKioiVGhlIFZpbnRhZ2UgUmVzdGF1cmFudCIqKiAoVGFibGEgMTguMjYpOiB2ZW50YXMgbWVuc3VhbGVzIGRlIGFsaW1lbnRvcyB5IGJlYmlkYXMgKGVuIG1pbGVzIGRlICQpIGR1cmFudGUgbG9zIHByaW1lcm9zIDMgYcOxb3MgZGUgb3BlcmFjacOzbiBkZWwgcmVzdGF1cmFudGUgZW4gQ2FwdGl2YSBJc2xhbmQsIEZsb3JpZGEuDQoNCioqUGFyYSByZXNvbHZlciBlbCBwcm9ibGVtYSBzZSB1c2Fyb246DQoNCi0gKipEZXNjb21wb3NpY2nDs24gY2zDoXNpY2EgZGUgc2VyaWVzIGRlIHRpZW1wbyoqIChUZW5kZW5jaWEgw5cgRXN0YWNpb25hbGlkYWQpLCB5DQotICoqUmVncmVzacOzbiBjb24gdmFyaWFibGVzIGZpY3RpY2lhcyAoZHVtbXkgdmFyaWFibGVzKSoqIHBhcmEgZWwgY29tcG9uZW50ZSBlc3RhY2lvbmFsLg0KDQpBbWJvcyBtw6l0b2RvcyBzaWd1ZW4gcGVydGVuZWNpZW5kbyBhbCB0ZW1hIGRlICpTZXJpZXMgZGUgVGllbXBvKiwgcGVybyBjb3JyZXNwb25kZW4gYSB1biBlbmZvcXVlIGRpc3RpbnRvOiBlbiB2ZXogZGUgc3Vhdml6YXIgbGEgc2VyaWUgbyBkZWphciBxdWUgdW4gYWxnb3JpdG1vIGRlY2lkYSBsYSBlc3RydWN0dXJhIChjb21vIGBhdXRvLmFyaW1hYCksIGFxdcOtIHNlICoqZGVzY29tcG9uZSBleHBsw61jaXRhbWVudGUqKiBsYSBzZXJpZSBlbiBUZW5kZW5jaWEgKFQpLCBFc3RhY2lvbmFsaWRhZCAoUykgZSBJcnJlZ3VsYXIgKEkpLCB5IHNlIHByb25vc3RpY2EgY29tYmluYW5kbyBlc29zIGNvbXBvbmVudGVzLiBFcyBlbCBlbmZvcXVlIGNsw6FzaWNvIHBhcmEgc2VyaWVzICoqZnVlcnRlbWVudGUgZXN0YWNpb25hbGVzIGNvbiBwb2NvcyBhw7FvcyBkZSBoaXN0b3JpYSoqIChhcXXDrSBzb2xvIDMgYcOxb3MgPSAzNiBtZXNlcyksIGRvbmRlIHVuIEFSSU1BIGVzdGFjaW9uYWwgbm8gc2UgcG9kcsOtYSBlc3RpbWFyIGRlIGZvcm1hIGNvbmZpYWJsZS4NCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPklOU1RBTEFDScOTTiBERSBMSUJSRVLDjUFTPC9zcGFuPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNpbnN0YWxsLnBhY2thZ2VzKCJmb3JlY2FzdCIpDQojaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkoa25pdHIpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiB5ZWxsb3c7Ij5DQVJHQSBERSBEQVRPUyAoVGFibGEgMTguMjYpPC9zcGFuPg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbWVzZXMgPC0gYygiRW5lcm8iLCJGZWJyZXJvIiwiTWFyem8iLCJBYnJpbCIsIk1heW8iLCJKdW5pbyIsIkp1bGlvIiwiQWdvc3RvIiwNCiAgICAgICAgICAgIlNlcHRpZW1icmUiLCJPY3R1YnJlIiwiTm92aWVtYnJlIiwiRGljaWVtYnJlIikNCg0KYcOxbzEgPC0gYygyNDIsMjM1LDIzMiwxNzgsMTg0LDE0MCwxNDUsMTUyLDExMCwxMzAsMTUyLDIwNikNCmHDsW8yIDwtIGMoMjYzLDIzOCwyNDcsMTkzLDE5MywxNDksMTU3LDE2MSwxMjIsMTMwLDE2NywyMzApDQphw7FvMyA8LSBjKDI4MiwyNTUsMjY1LDIwNSwyMTAsMTYwLDE2NiwxNzQsMTI2LDE0OCwxNzMsMjM1KQ0KDQp2ZW50YXMgPC0gYyhhw7FvMSwgYcOxbzIsIGHDsW8zKQ0KbiA8LSBsZW5ndGgodmVudGFzKQ0KdCA8LSAxOm4NCg0KZGF0YWZyYW1lMyA8LSBkYXRhLmZyYW1lKA0KICB0ID0gdCwNCiAgbWVzID0gZmFjdG9yKHJlcChtZXNlcywgMyksIGxldmVscyA9IG1lc2VzKSwNCiAgYcOxbyA9IHJlcCgxOjMsIGVhY2ggPSAxMiksDQogIHZlbnRhcyA9IHZlbnRhcw0KKQ0Ka2FibGUoZGF0YWZyYW1lMywgY2FwdGlvbiA9ICJWZW50YXMgbWVuc3VhbGVzIC0gVmludGFnZSBSZXN0YXVyYW50IChtaWxlcyBkZSAkKSIpDQoNCiMgU2VyaWUgZGUgdGllbXBvIG1lbnN1YWwsIGluaWNpYW5kbyBlbiBFbmVybyBkZWwgQcOxbyAxDQp0c1ZJTlRBR0UgPC0gdHModmVudGFzLCBzdGFydCA9IGMoMSwxKSwgZnJlcXVlbmN5ID0gMTIpDQp0c1ZJTlRBR0UNCmBgYA0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij4xLiBHUsOBRklDQSBERSBMQSBTRVJJRSBERSBUSUVNUE88L3NwYW4+DQoNCmBgYHtyfQ0KcGxvdCh0c1ZJTlRBR0UsIG1haW4gPSAiVmVudGFzIG1lbnN1YWxlcyBkZSBhbGltZW50b3MgeSBiZWJpZGFzIC0gVmludGFnZSBSZXN0YXVyYW50IiwNCiAgICAgeWxhYiA9ICJWZW50YXMgKCQgbWlsZXMpIiwgeGxhYiA9ICJBw7FvIiwgdHlwZSA9ICJvIiwgY29sID0gInN0ZWVsYmx1ZSIsIHBjaCA9IDE2KQ0KYGBgDQoNCioqQ29tZW50YXJpbyBzb2JyZSBlbCBwYXRyw7NuIHByaW5jaXBhbDoqKg0KDQpMYSBzZXJpZSBtdWVzdHJhIGRvcyBjb21wb25lbnRlcyBjbGFyb3M6DQoNCi0gKipUZW5kZW5jaWEgY3JlY2llbnRlKio6IGxhcyB2ZW50YXMgZGUgY2FkYSBtZXMgYXVtZW50YW4gZGUgdW4gYcOxbyBhIG90cm8gKHBvciBlamVtcGxvLCBlbmVybyBwYXNhIGRlIDI0MiBhIDI2MyB5IGEgMjgyIGVuIGxvcyAzIGHDsW9zKSwgcmVmbGVqYW5kbyBlbCBjcmVjaW1pZW50byBkZWwgcmVzdGF1cmFudGUuDQotICoqRXN0YWNpb25hbGlkYWQgbWFyY2FkYSB5IHJlcGV0aXRpdmEgZGUgcGVyaW9kbyAxMioqOiBjYWRhIGHDsW8gc2UgcmVwaXRlIGVsIG1pc21vIHBhdHLDs24g4oCUIHZlbnRhcyBhbHRhcyBlbiAqKmVuZXJvLCBmZWJyZXJvLCBtYXJ6byB5IGRpY2llbWJyZSoqICh0ZW1wb3JhZGEgYWx0YSB0dXLDrXN0aWNhIGVuIEZsb3JpZGEpIHkgdmVudGFzIGJhamFzIGVuICoqanVuaW8sIGp1bGlvLCBhZ29zdG8geSBlc3BlY2lhbG1lbnRlIHNlcHRpZW1icmUqKiAodGVtcG9yYWRhIGJhamEpLg0KDQpObyBzZSBhcHJlY2lhIHVuIHBhdHLDs24gY8OtY2xpY28gZGUgbGFyZ28gcGxhem8gbmkgaXJyZWd1bGFyaWRhZGVzIHNldmVyYXM7IGVsIGNvbXBvcnRhbWllbnRvIGVzIGNvbnNpc3RlbnRlIGHDsW8gY29uIGHDsW8uDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjIuIEFOw4FMSVNJUyBERSBFU1RBQ0lPTkFMSURBRCAtIMONTkRJQ0VTIEVTVEFDSU9OQUxFUzwvc3Bhbj4NCg0KU2UgdXNhIGVsIG3DqXRvZG8gY2zDoXNpY28gZGUgKipyYXrDs24gYWwgcHJvbWVkaW8gbcOzdmlsIGNlbnRyYWRvIChDTUEpKiogZGUgb3JkZW4gMTIgKG3DqXRvZG8gZGUgZGVzY29tcG9zaWNpw7NuIG11bHRpcGxpY2F0aXZhLCBkaXNwb25pYmxlIGVuIFIgY29uIGBkZWNvbXBvc2UoKWApOg0KDQpgYGB7cn0NCmRlc2NvbXBvc2ljaW9uIDwtIGRlY29tcG9zZSh0c1ZJTlRBR0UsIHR5cGUgPSAibXVsdGlwbGljYXRpdmUiKQ0KcGxvdChkZXNjb21wb3NpY2lvbikNCmBgYA0KDQpgYGB7cn0NCiMgw41uZGljZXMgZXN0YWNpb25hbGVzICh1bm8gcG9yIG1lcywgcHJvbWVkaWFkb3MgeSBub3JtYWxpemFkb3MgYSBwcm9tZWRpbyA9IDEpDQppbmRpY2VfZXN0YWNpb25hbCA8LSBkZXNjb21wb3NpY2lvbiRmaWd1cmUNCm5hbWVzKGluZGljZV9lc3RhY2lvbmFsKSA8LSBtZXNlcw0KDQp0YWJsYV9lc3RhY2lvbmFsIDwtIGRhdGEuZnJhbWUoDQogIE1lcyA9IG1lc2VzLA0KICBJbmRpY2VfRXN0YWNpb25hbCA9IHJvdW5kKGluZGljZV9lc3RhY2lvbmFsLCA0KQ0KKQ0Ka2FibGUodGFibGFfZXN0YWNpb25hbCwgY2FwdGlvbiA9ICLDjW5kaWNlcyBlc3RhY2lvbmFsZXMgcG9yIG1lcyIpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmJhcnBsb3QoaW5kaWNlX2VzdGFjaW9uYWwsIG5hbWVzLmFyZyA9IG1lc2VzLCBsYXMgPSAyLCBjb2wgPSAic2FsbW9uIiwNCiAgICAgICAgbWFpbiA9ICLDjW5kaWNlIGVzdGFjaW9uYWwgcG9yIG1lcyAtIFZpbnRhZ2UgUmVzdGF1cmFudCIsDQogICAgICAgIHlsYWIgPSAiw41uZGljZSBlc3RhY2lvbmFsIikNCmFibGluZShoID0gMSwgbHR5ID0gMikNCmBgYA0KDQoqKkNvbWVudGFyaW8gc29icmUgbG9zIMOtbmRpY2VzIGVzdGFjaW9uYWxlczoqKg0KDQotICoqVGVtcG9yYWRhIGFsdGE6KiogZW5lcm8gKOKJiDEuNDQpLCBtYXJ6byAo4omIMS4zNCkgeSBmZWJyZXJvICjiiYgxLjMwKSBlc3TDoW4gbXV5IHBvciBlbmNpbWEgZGUgMSDigJQgbGFzIHZlbnRhcyBkZSBlc29zIG1lc2VzIHNvbiBlbnRyZSAzMCUgeSA0NCUgc3VwZXJpb3JlcyBhbCBwcm9tZWRpbyBhbnVhbC4gRGljaWVtYnJlIHRhbWJpw6luIGVzdMOhIHBvciBhcnJpYmEgZGVsIHByb21lZGlvICjiiYgxLjE2KS4NCi0gKipUZW1wb3JhZGEgYmFqYToqKiBzZXB0aWVtYnJlIGVzIGVsIG1lcyBtw6FzIGTDqWJpbCAo4omIMC42MywgZXMgZGVjaXIsIDM3JSBwb3IgZGViYWpvIGRlbCBwcm9tZWRpbyksIHNlZ3VpZG8gZGUgb2N0dWJyZSAo4omIMC43MCkgeSBqdW5pbyAo4omIMC44MCkuDQoNCioqwr9UaWVuZW4gc2VudGlkbyBpbnR1aXRpdm8/KiogU8OtLiBDYXB0aXZhIElzbGFuZCwgY2VyY2EgZGUgRm9ydCBNeWVycywgZXMgdW4gZGVzdGlubyB0dXLDrXN0aWNvIGRlIGludmllcm5vIGVuIEZsb3JpZGEgKCJzbm93YmlyZCBzZWFzb24iKTogbG9zIHR1cmlzdGFzIGRlbCBub3J0ZSBkZSBFRS4gVVUuIHkgQ2FuYWTDoSBsbGVnYW4gZGUgZGljaWVtYnJlIGEgbWFyem8gZXNjYXBhbmRvIGRlbCBmcsOtbywgbG8gcXVlIGV4cGxpY2EgbG9zIMOtbmRpY2VzIGFsdG9zIGVuIGVzb3MgbWVzZXMuIEVuIGNhbWJpbywgZWwgdmVyYW5vIChqdW5pby1zZXB0aWVtYnJlKSBjb2luY2lkZSBjb24gZWwgY2xpbWEgaMO6bWVkbyB5IGNhbHVyb3NvIGRlIEZsb3JpZGEgeSBsYSB0ZW1wb3JhZGEgZGUgaHVyYWNhbmVzLCBwb3IgbG8gcXVlIGJhamEgZWwgdHVyaXNtbyDigJQgZGUgYWjDrSBsb3Mgw61uZGljZXMgYmFqb3MsIGNvbiBzdSBtw61uaW1vIGVuIHNlcHRpZW1icmUuDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjMuIERFU0VTVEFDSU9OQUxJWkFDScOTTiBERSBMQSBTRVJJRTwvc3Bhbj4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnNlcmllX2Rlc2VzdGFjaW9uYWxpemFkYSA8LSB0c1ZJTlRBR0UgLyByZXAoaW5kaWNlX2VzdGFjaW9uYWwsIDMpDQoNCnBsb3QodCwgYXMubnVtZXJpYyhzZXJpZV9kZXNlc3RhY2lvbmFsaXphZGEpLCB0eXBlID0gIm8iLCBjb2wgPSAiZGFya2dyZWVuIiwNCiAgICAgbWFpbiA9ICJTZXJpZSBkZXNlc3RhY2lvbmFsaXphZGEgLSBWaW50YWdlIFJlc3RhdXJhbnQiLA0KICAgICB4bGFiID0gIk1lcyAodCkiLCB5bGFiID0gIlZlbnRhcyAoJCBtaWxlcyksIHNpbiBlZmVjdG8gZXN0YWNpb25hbCIpDQoNCiMgVGVuZGVuY2lhIGxpbmVhbCBzb2JyZSBsYSBzZXJpZSBkZXNlc3RhY2lvbmFsaXphZGENCm1vZGVsb190ZW5kZW5jaWEgPC0gbG0oYXMubnVtZXJpYyhzZXJpZV9kZXNlc3RhY2lvbmFsaXphZGEpIH4gdCkNCnN1bW1hcnkobW9kZWxvX3RlbmRlbmNpYSkNCg0KbGluZXModCwgZml0dGVkKG1vZGVsb190ZW5kZW5jaWEpLCBjb2wgPSAiYmxhY2siLCBsdHkgPSAyLCBsd2QgPSAyKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiU2VyaWUgZGVzZXN0YWNpb25hbGl6YWRhIiwgIlRlbmRlbmNpYSBsaW5lYWwiKSwNCiAgICAgICBjb2wgPSBjKCJkYXJrZ3JlZW4iLCJibGFjayIpLCBsdHkgPSBjKDEsMiksIHBjaCA9IGMoMSxOQSkpDQpgYGANCg0KKirCv0V4aXN0ZSB0ZW5kZW5jaWEgZW4gbGEgc2VyaWUgZGVzZXN0YWNpb25hbGl6YWRhPyoqDQoNClPDrSwgdW5hIHZleiByZW1vdmlkbyBlbCBlZmVjdG8gZXN0YWNpb25hbCwgbGEgc2VyaWUgZGVzZXN0YWNpb25hbGl6YWRhIG11ZXN0cmEgdW5hICoqdGVuZGVuY2lhIGxpbmVhbCBjcmVjaWVudGUgY2xhcmEqKiAocGVuZGllbnRlIOKJiCArMS4wMiBtaWxlcyBkZSAkIHBvciBtZXMsIGNvbiBSwrIg4omIIDAuOTIpLCBjb25zaXN0ZW50ZSBjb24gZWwgY3JlY2ltaWVudG8gZGVsIHJlc3RhdXJhbnRlIG1lcyBhIG1lcyBhIGxvIGxhcmdvIGRlIGxvcyAzIGHDsW9zLCBzaW4gZWwgInJ1aWRvIiBxdWUgZ2VuZXJhYmEgbGEgZXN0YWNpb25hbGlkYWQuDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjQuIFBST07Dk1NUSUNPIC0gTcOJVE9ETyBERSBERVNDT01QT1NJQ0nDk048L3NwYW4+DQoNCkVsIHByb27Ds3N0aWNvIHBhcmEgY2FkYSBtZXMgZGVsICoqQcOxbyA0Kiogc2Ugb2J0aWVuZSBtdWx0aXBsaWNhbmRvIGVsIHZhbG9yIHByb3llY3RhZG8gZGUgbGEgdGVuZGVuY2lhIHBvciBlbCDDrW5kaWNlIGVzdGFjaW9uYWwgY29ycmVzcG9uZGllbnRlIGEgZXNlIG1lczoNCg0KJCQgXGhhdHtZfV90ID0gKGJfMCArIGJfMSBcY2RvdCB0KSBcdGltZXMgU0lfe21lc30gJCQNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnRfZnV0dXJvIDwtIChuKzEpOihuKzEyKSAgIyBtZXNlcyAzNyBhIDQ4ID0gQcOxbyA0DQoNCmIwIDwtIGNvZWYobW9kZWxvX3RlbmRlbmNpYSlbMV0NCmIxIDwtIGNvZWYobW9kZWxvX3RlbmRlbmNpYSlbMl0NCnRlbmRlbmNpYV9mdXR1cmEgPC0gYjAgKyBiMSAqIHRfZnV0dXJvDQoNCnByb25vc3RpY29fZGVzY29tcG9zaWNpb24gPC0gdGVuZGVuY2lhX2Z1dHVyYSAqIGFzLm51bWVyaWMoaW5kaWNlX2VzdGFjaW9uYWwpDQoNCnRhYmxhX2Rlc2NvbXBvc2ljaW9uIDwtIGRhdGEuZnJhbWUoDQogIE1lcyA9IG1lc2VzLA0KICB0ID0gdF9mdXR1cm8sDQogIFRlbmRlbmNpYV9Qcm95ZWN0YWRhID0gcm91bmQodGVuZGVuY2lhX2Z1dHVyYSwgMiksDQogIEluZGljZV9Fc3RhY2lvbmFsID0gcm91bmQoYXMubnVtZXJpYyhpbmRpY2VfZXN0YWNpb25hbCksIDQpLA0KICBQcm9ub3N0aWNvX0Rlc2NvbXBvc2ljaW9uID0gcm91bmQocHJvbm9zdGljb19kZXNjb21wb3NpY2lvbiwgMikNCikNCmthYmxlKHRhYmxhX2Rlc2NvbXBvc2ljaW9uLCBjYXB0aW9uID0gIlByb27Ds3N0aWNvIEHDsW8gNCAtIE3DqXRvZG8gZGUgRGVzY29tcG9zaWNpw7NuIikNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGxvdCh0LCB2ZW50YXMsIHR5cGUgPSAibyIsIGNvbCA9ICJzdGVlbGJsdWUiLA0KICAgICB4bGltID0gYygxLCBtYXgodF9mdXR1cm8pKSwgeWxpbSA9IHJhbmdlKGModmVudGFzLCBwcm9ub3N0aWNvX2Rlc2NvbXBvc2ljaW9uKSksDQogICAgIG1haW4gPSAiUHJvbsOzc3RpY28gQcOxbyA0IC0gTcOpdG9kbyBkZSBEZXNjb21wb3NpY2nDs24iLA0KICAgICB4bGFiID0gIk1lcyAodCkiLCB5bGFiID0gIlZlbnRhcyAoJCBtaWxlcykiKQ0KbGluZXModF9mdXR1cm8sIHByb25vc3RpY29fZGVzY29tcG9zaWNpb24sIHR5cGUgPSAibyIsIGNvbCA9ICJyZWQiLCBwY2ggPSAxNSkNCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZCA9IGMoIlZlbnRhcyBoaXN0w7NyaWNhcyAoQcOxb3MgMS0zKSIsICJQcm9uw7NzdGljbyBBw7FvIDQiKSwNCiAgICAgICBjb2wgPSBjKCJzdGVlbGJsdWUiLCJyZWQiKSwgcGNoID0gYygxLDE1KSkNCg0KY2F0KCJWZW50YXMgdG90YWxlcyBwcm9ub3N0aWNhZGFzIEHDsW8gNCAoRGVzY29tcG9zaWNpw7NuKToiLCByb3VuZChzdW0ocHJvbm9zdGljb19kZXNjb21wb3NpY2lvbiksMiksICJcbiIpDQpgYGANCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+NS4gUFJPTsOTU1RJQ08gLSBSRUdSRVNJw5NOIENPTiBWQVJJQUJMRVMgRklDVElDSUFTIChEVU1NWSk8L3NwYW4+DQoNClNlIHBsYW50ZWEgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbcO6bHRpcGxlOg0KDQokJCBWZW50YXNfdCA9IGJfMCArIGJfMSBcY2RvdCB0ICsgYl8yIE1fe2VuZX0gKyBiXzMgTV97ZmVifSArIFxkb3RzICsgYl97MTJ9IE1fe25vdn0gKyBcdmFyZXBzaWxvbl90ICQkDQoNClNlIHVzYW4gKioxMSB2YXJpYWJsZXMgZHVtbXkqKiAoZW5lcm8gYSBub3ZpZW1icmUpOyBkaWNpZW1icmUgcXVlZGEgY29tbyBjYXRlZ29yw61hIGJhc2UgKHN1IGVmZWN0byBlc3TDoSBpbmNsdWlkbyBlbiBlbCBpbnRlcmNlcHRvKS4NCg0KYGBge3J9DQojICJtZXMiIHlhIGVzIHVuIGZhY3RvciBjb24gRGljaWVtYnJlIGFsIGZpbmFsIC0+IERpY2llbWJyZSBxdWVkYSBjb21vIG5pdmVsIGRlIHJlZmVyZW5jaWENCm1vZGVsb19kdW1teSA8LSBsbSh2ZW50YXMgfiB0ICsgbWVzLCBkYXRhID0gZGF0YWZyYW1lMykNCnN1bW1hcnkobW9kZWxvX2R1bW15KQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFByb27Ds3N0aWNvIEHDsW8gNCBjb24gZWwgbW9kZWxvIGRlIGR1bW1pZXMNCm51ZXZvc19kYXRvcyA8LSBkYXRhLmZyYW1lKA0KICB0ID0gdF9mdXR1cm8sDQogIG1lcyA9IGZhY3RvcihtZXNlcywgbGV2ZWxzID0gbWVzZXMpDQopDQpwcm9ub3N0aWNvX2R1bW15IDwtIHByZWRpY3QobW9kZWxvX2R1bW15LCBuZXdkYXRhID0gbnVldm9zX2RhdG9zKQ0KDQp0YWJsYV9kdW1teSA8LSBkYXRhLmZyYW1lKA0KICBNZXMgPSBtZXNlcywNCiAgdCA9IHRfZnV0dXJvLA0KICBQcm9ub3N0aWNvX1JlZ3Jlc2lvbl9EdW1teSA9IHJvdW5kKGFzLm51bWVyaWMocHJvbm9zdGljb19kdW1teSksIDIpDQopDQprYWJsZSh0YWJsYV9kdW1teSwgY2FwdGlvbiA9ICJQcm9uw7NzdGljbyBBw7FvIDQgLSBSZWdyZXNpw7NuIGNvbiBWYXJpYWJsZXMgRHVtbXkiKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdCh0LCB2ZW50YXMsIHR5cGUgPSAibyIsIGNvbCA9ICJzdGVlbGJsdWUiLA0KICAgICB4bGltID0gYygxLCBtYXgodF9mdXR1cm8pKSwgeWxpbSA9IHJhbmdlKGModmVudGFzLCBwcm9ub3N0aWNvX2R1bW15KSksDQogICAgIG1haW4gPSAiUHJvbsOzc3RpY28gQcOxbyA0IC0gUmVncmVzacOzbiBjb24gVmFyaWFibGVzIER1bW15IiwNCiAgICAgeGxhYiA9ICJNZXMgKHQpIiwgeWxhYiA9ICJWZW50YXMgKCQgbWlsZXMpIikNCmxpbmVzKHRfZnV0dXJvLCBwcm9ub3N0aWNvX2R1bW15LCB0eXBlID0gIm8iLCBjb2wgPSAiZGFya29yYW5nZSIsIHBjaCA9IDE3KQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiVmVudGFzIGhpc3TDs3JpY2FzIChBw7FvcyAxLTMpIiwgIlByb27Ds3N0aWNvIEHDsW8gNCIpLA0KICAgICAgIGNvbCA9IGMoInN0ZWVsYmx1ZSIsImRhcmtvcmFuZ2UiKSwgcGNoID0gYygxLDE3KSkNCg0KY2F0KCJWZW50YXMgdG90YWxlcyBwcm9ub3N0aWNhZGFzIEHDsW8gNCAoUmVncmVzacOzbiBEdW1teSk6Iiwgcm91bmQoc3VtKHByb25vc3RpY29fZHVtbXkpLDIpLCAiXG4iKQ0KYGBgDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjYuIFRBQkxBUyBZIEdSw4FGSUNBUyBSRVNVTUVOPC9zcGFuPg0KDQpgYGB7cn0NCnRhYmxhX3Jlc3VtZW4gPC0gZGF0YS5mcmFtZSgNCiAgTWVzID0gbWVzZXMsDQogIEluZGljZV9Fc3RhY2lvbmFsID0gcm91bmQoYXMubnVtZXJpYyhpbmRpY2VfZXN0YWNpb25hbCksIDQpLA0KICBQcm9ub3N0aWNvX0Rlc2NvbXBvc2ljaW9uID0gcm91bmQocHJvbm9zdGljb19kZXNjb21wb3NpY2lvbiwgMiksDQogIFByb25vc3RpY29fUmVncmVzaW9uX0R1bW15ID0gcm91bmQoYXMubnVtZXJpYyhwcm9ub3N0aWNvX2R1bW15KSwgMiksDQogIERpZmVyZW5jaWEgPSByb3VuZChwcm9ub3N0aWNvX2Rlc2NvbXBvc2ljaW9uIC0gYXMubnVtZXJpYyhwcm9ub3N0aWNvX2R1bW15KSwgMikNCikNCmthYmxlKHRhYmxhX3Jlc3VtZW4sIGNhcHRpb24gPSAiUmVzdW1lbiBjb21wYXJhdGl2byBkZSBwcm9uw7NzdGljb3MgLSBBw7FvIDQiKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdCgxOjEyLCBwcm9ub3N0aWNvX2Rlc2NvbXBvc2ljaW9uLCB0eXBlID0gIm8iLCBjb2wgPSAicmVkIiwgcGNoID0gMTUsDQogICAgIHhheHQgPSAibiIsIHlsaW0gPSByYW5nZShjKHByb25vc3RpY29fZGVzY29tcG9zaWNpb24sIHByb25vc3RpY29fZHVtbXkpKSwNCiAgICAgbWFpbiA9ICJDb21wYXJhY2nDs24gZGUgcHJvbsOzc3RpY29zIC0gQcOxbyA0IiwNCiAgICAgeGxhYiA9ICJNZXMiLCB5bGFiID0gIlZlbnRhcyBwcm9ub3N0aWNhZGFzICgkIG1pbGVzKSIpDQpsaW5lcygxOjEyLCBwcm9ub3N0aWNvX2R1bW15LCB0eXBlID0gIm8iLCBjb2wgPSAiZGFya29yYW5nZSIsIHBjaCA9IDE3KQ0KYXhpcygxLCBhdCA9IDE6MTIsIGxhYmVscyA9IG1lc2VzLCBsYXMgPSAyKQ0KbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoIkRlc2NvbXBvc2ljacOzbiIsICJSZWdyZXNpw7NuIER1bW15IiksDQogICAgICAgY29sID0gYygicmVkIiwiZGFya29yYW5nZSIpLCBwY2ggPSBjKDE1LDE3KSkNCmBgYA0KDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjcuIEVSUk9SIERFIFBST07Dk1NUSUNPIC0gRU5FUk8gQcORTyA0IChWRU5UQVMgUkVBTEVTID0gJDI5NSwwMDApPC9zcGFuPg0KDQpgYGB7cn0NCnZlbnRhc19yZWFsZXNfZW5lcm80IDwtIDI5NQ0KDQpwcm9ub3N0aWNvX2VuZXJvNF9kZXNjb21wIDwtIHByb25vc3RpY29fZGVzY29tcG9zaWNpb25bMV0NCnByb25vc3RpY29fZW5lcm80X2R1bW15ICAgPC0gYXMubnVtZXJpYyhwcm9ub3N0aWNvX2R1bW15KVsxXQ0KDQplcnJvcl9kZXNjb21wIDwtIHZlbnRhc19yZWFsZXNfZW5lcm80IC0gcHJvbm9zdGljb19lbmVybzRfZGVzY29tcA0KZXJyb3JfZHVtbXkgICA8LSB2ZW50YXNfcmVhbGVzX2VuZXJvNCAtIHByb25vc3RpY29fZW5lcm80X2R1bW15DQoNCmNhdCgiUHJvbsOzc3RpY28gRW5lcm8gQcOxbyA0IChEZXNjb21wb3NpY2nDs24pOiIsIHJvdW5kKHByb25vc3RpY29fZW5lcm80X2Rlc2NvbXAsMiksDQogICAgIiAtPiBFcnJvcjoiLCByb3VuZChlcnJvcl9kZXNjb21wLDIpLCAiXG4iKQ0KY2F0KCJQcm9uw7NzdGljbyBFbmVybyBBw7FvIDQgKFJlZ3Jlc2nDs24gRHVtbXkpOiIsIHJvdW5kKHByb25vc3RpY29fZW5lcm80X2R1bW15LDIpLA0KICAgICIgLT4gRXJyb3I6Iiwgcm91bmQoZXJyb3JfZHVtbXksMiksICJcblxuIikNCg0KY2F0KCJFcnJvciBwb3JjZW50dWFsIChEZXNjb21wb3NpY2nDs24pOiIsIHJvdW5kKDEwMCplcnJvcl9kZXNjb21wL3ZlbnRhc19yZWFsZXNfZW5lcm80LDIpLCAiJVxuIikNCmNhdCgiRXJyb3IgcG9yY2VudHVhbCAoUmVncmVzacOzbiBEdW1teSk6Iiwgcm91bmQoMTAwKmVycm9yX2R1bW15L3ZlbnRhc19yZWFsZXNfZW5lcm80LDIpLCAiJVxuIikNCmBgYA0KDQoqKkludGVycHJldGFjacOzbiBkZWwgZXJyb3IgZGUgcHJvbsOzc3RpY286KioNCg0KQW1ib3MgbW9kZWxvcyBwcm9ub3N0aWNhbiBlbmVybyBkZWwgQcOxbyA0IG11eSBjZXJjYSBkZSBsYXMgdmVudGFzIHJlYWxlcyBkZSAkMjk1LDAwMCAoZWwgZXJyb3IgZXMgZGUgYXBlbmFzIHVub3MgY3VhbnRvcyBtaWxlcyBkZSBkw7NsYXJlcywgZXMgZGVjaXIsICoqbWVub3MgZGVsIDMlKiogZW4gYW1ib3MgY2Fzb3MpLiBFc3RlIGVzIHVuIGVycm9yIHBlcXVlw7FvIHkgZXNwZXJhYmxlOiBuaW5nw7puIG1vZGVsbyBkZSBwcm9uw7NzdGljbyBlcyBwZXJmZWN0bywgeWEgcXVlIGV4aXN0ZW4gZmFjdG9yZXMgcXVlIG5vIGNhcHR1cmEgbGEgdGVuZGVuY2lhIG5pIGxhIGVzdGFjaW9uYWxpZGFkIGhpc3TDs3JpY2EgKGNsaW1hIGRlIGVzZSBtZXMgZW4gcGFydGljdWxhciwgZXZlbnRvcyBsb2NhbGVzLCBjYW1iaW9zIGVuIGxhIGNvbXBldGVuY2lhLCBwdWJsaWNpZGFkLCBldGMuKS4NCg0KKirCv1F1w6kgc2UgcHVlZGUgaGFjZXIgcGFyYSByZWR1Y2lyIGxhIGluY2VydGlkdW1icmUgZGUgS2FyZW4gc29icmUgZWwgcHJvY2VzbyBkZSBwcm9uw7NzdGljbz8qKg0KDQoxLiAqKlByZXNlbnRhciBlbCBwcm9uw7NzdGljbyBjb21vIHVuIHJhbmdvLCBubyBjb21vIHVuIG7Dum1lcm8gZXhhY3RvKiog4oCUIHBvciBlamVtcGxvLCB1biBpbnRlcnZhbG8gZGUgY29uZmlhbnphICjCsSBjaWVydG8gbWFyZ2VuIGJhc2FkbyBlbiBlbCBlcnJvciBoaXN0w7NyaWNvIGRlIGxvcyBtb2RlbG9zKSBlbiB2ZXogZGUgdW5hIHNvbGEgY2lmcmEsIHBhcmEgcXVlIEthcmVuIGVudGllbmRhIHF1ZSBlbCBwcm9uw7NzdGljbyBlcyB1bmEgKmVzdGltYWNpw7NuKiwgbm8gdW5hIHByb21lc2EuDQoyLiAqKkFjdHVhbGl6YXIgZWwgbW9kZWxvIGNhZGEgdmV6IHF1ZSBoYXkgdW4gbnVldm8gbWVzIGRlIGRhdG9zIHJlYWxlcyoqIChwcm9uw7NzdGljbyAicm9kYW50ZSIpOiBjb25mb3JtZSBwYXNhbiBsb3MgbWVzZXMgZGVsIEHDsW8gNCwgc2UgcmVpbmNvcnBvcmFuIGxhcyB2ZW50YXMgcmVhbGVzIHkgc2UgcmVhanVzdGFuIHRlbmRlbmNpYSBlIMOtbmRpY2VzIGVzdGFjaW9uYWxlcywgbG8gY3VhbCByZWR1Y2UgZWwgZXJyb3IgZW4gbG9zIG1lc2VzIHNpZ3VpZW50ZXMuDQozLiAqKk1vbml0b3JlYXIgZWwgZXJyb3IgZGUgcHJvbsOzc3RpY28gbWVzIGEgbWVzKiogKE1BRCwgTUFQRSwgUk1TRSkgcGFyYSBkZXRlY3RhciBzaSBlbCBtb2RlbG8gc2UgZXN0w6EgZGVzdmlhbmRvIGRlIGZvcm1hIHNpc3RlbcOhdGljYSAocG9yIGVqZW1wbG8sIHNpIHNlcHRpZW1icmUgcmVhbCBzaWVtcHJlIHJlc3VsdGEgbcOhcyBhbHRvIHF1ZSBlbCBwcm9uw7NzdGljbywgaGF5IHF1ZSByZXZpc2FyIGVsIMOtbmRpY2UgZXN0YWNpb25hbCBkZSBlc2UgbWVzKS4NCjQuICoqSW5jb3Jwb3JhciBpbmZvcm1hY2nDs24gYWRpY2lvbmFsKiogY3VhbmRvIGVzdMOpIGRpc3BvbmlibGUgKHJlc2VydmFjaW9uZXMgeWEgY29uZmlybWFkYXMsIG9jdXBhY2nDs24gaG90ZWxlcmEgZGUgbGEgaXNsYSwgdGVuZGVuY2lhcyB0dXLDrXN0aWNhcyBkZSBGbG9yaWRhKSBwYXJhIGFqdXN0YXIgZWwgcHJvbsOzc3RpY28gcHVyYW1lbnRlIGVzdGFkw61zdGljbyBjb24ganVpY2lvIGRlIG5lZ29jaW8uDQo1LiAqKlVzYXIgdmFyaW9zIG3DqXRvZG9zIGVuIHBhcmFsZWxvKiogKGNvbW8gc2UgaGl6byBhcXXDrSBjb24gZGVzY29tcG9zaWNpw7NuIHkgcmVncmVzacOzbiBkdW1teSkgeSBwcm9tZWRpYXJsb3MgbyBtb3N0cmFyIGVsIHJhbmdvIGVudHJlIGVsbG9zLCBlbiB2ZXogZGUgZGVwZW5kZXIgZGUgdW4gc29sbyBtb2RlbG8g4oCUIGVzdG8geWEgcG9yIHPDrSBtaXNtbyBjb211bmljYSBhIEthcmVuIGVsIGdyYWRvIGRlIGluY2VydGlkdW1icmUgaW5oZXJlbnRlIGFsIGVqZXJjaWNpby4NCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPkNPTkNMVVNJT05FUzwvc3Bhbj4NCg0KMS4gKipQYXRyw7NuIGRlIGxhIHNlcmllOioqIGxhcyB2ZW50YXMgZGUgVmludGFnZSBSZXN0YXVyYW50IGNvbWJpbmFuIHVuYSAqKnRlbmRlbmNpYSBkZSBjcmVjaW1pZW50byBzb3N0ZW5pZG8qKiAoYXByb3guICskMSwwMDAgYWwgbWVzIGVuIHTDqXJtaW5vcyBkZXNlc3RhY2lvbmFsaXphZG9zKSBjb24gdW5hICoqZXN0YWNpb25hbGlkYWQgZnVlcnRlIHkgcmVwZXRpdGl2YSoqIGxpZ2FkYSBhIGxhIHRlbXBvcmFkYSB0dXLDrXN0aWNhIGRlIGludmllcm5vIGVuIEZsb3JpZGEuDQoNCjIuICoqRXN0YWNpb25hbGlkYWQ6KiogZW5lcm8sIGZlYnJlcm8sIG1hcnpvIHkgZGljaWVtYnJlIHNvbiBsb3MgbWVzZXMgZGUgdGVtcG9yYWRhIGFsdGEgKMOtbmRpY2VzIGVudHJlIDEuMTYgeSAxLjQ0KTsganVuaW8sIGp1bGlvLCBhZ29zdG8sIHNlcHRpZW1icmUgeSBvY3R1YnJlIHNvbiBkZSB0ZW1wb3JhZGEgYmFqYSAow61uZGljZXMgZW50cmUgMC42MyB5IDAuODUpLCBjb24gc2VwdGllbWJyZSBjb21vIGVsIG1lcyBtw6FzIGZsb2pvIGRlbCBhw7FvLiBFc3RvcyBwYXRyb25lcyB0aWVuZW4gcGxlbm8gc2VudGlkbyBkYWRvIHF1ZSBDYXB0aXZhIElzbGFuZCBlcyB1biBkZXN0aW5vIGRlICJzbm93YmlyZHMiIGVuIHRlbXBvcmFkYSBkZSBpbnZpZXJuby4NCg0KMy4gKipTZXJpZSBkZXNlc3RhY2lvbmFsaXphZGE6KiogdW5hIHZleiByZW1vdmlkbyBlbCBlZmVjdG8gZXN0YWNpb25hbCwgc2UgY29uZmlybWEgdW5hIHRlbmRlbmNpYSBsaW5lYWwgY3JlY2llbnRlIGNsYXJhIChSwrIg4omIIDAuOTIpLCBzZcOxYWwgZGUgcXVlIGVsIGNyZWNpbWllbnRvIGRlbCBuZWdvY2lvIGVzIHJlYWwgeSBjb25zaXN0ZW50ZSwgbm8gdW4gYXJ0ZWZhY3RvIGRlIGxhIGVzdGFjaW9uYWxpZGFkLg0KDQo0LiAqKlByb27Ds3N0aWNvcyBBw7FvIDQ6KiogdGFudG8gZWwgbcOpdG9kbyBkZSBkZXNjb21wb3NpY2nDs24gY2zDoXNpY2EgY29tbyBsYSByZWdyZXNpw7NuIGNvbiB2YXJpYWJsZXMgZHVtbXkgYXJyb2phbiBwcm9uw7NzdGljb3MgY29uc2lzdGVudGVzIGVudHJlIHPDrSAoZGlmZXJlbmNpYXMgbWVub3JlcyBhbCA1JSBtZXMgYSBtZXMpLCBjb24gKiplbmVybyB5IG1hcnpvIGRlbCBBw7FvIDQgY29tbyBsb3MgbWVzZXMgZGUgbWF5b3IgdmVudGEgZXNwZXJhZGEqKiAofiQyODAsMDAwLSQzMDAsMDAwKSB5ICoqc2VwdGllbWJyZSBjb21vIGVsIG1lcyBtw6FzIGJham8qKiAofiQxMzUsMDAwLSQxNDUsMDAwKS4NCg0KNS4gKipWYWxpZGFjacOzbiBjb24gZGF0b3MgcmVhbGVzOioqIGFsIGNvbXBhcmFyIGNvbnRyYSBsYSB2ZW50YSByZWFsIGRlIGVuZXJvIGRlbCBBw7FvIDQgKCQyOTUsMDAwKSwgYW1ib3MgbW9kZWxvcyB0dXZpZXJvbiB1biBlcnJvciBtZW5vciBhbCAzJSwgbG8gcXVlIHZhbGlkYSBsYSBtZXRvZG9sb2fDrWEsIGF1bnF1ZSBzZSByZWNvbWllbmRhIGEgS2FyZW4gdHJhdGFyIGN1YWxxdWllciBwcm9uw7NzdGljbyBjb21vIHVuYSAqKmVzdGltYWNpw7NuIGNvbiBpbmNlcnRpZHVtYnJlKiosIG5vIGNvbW8gdW5hIGNpZnJhIGV4YWN0YSwgeSBhY3R1YWxpemFyIGVsIG1vZGVsbyBjb25mb3JtZSBsbGVndWVuIG51ZXZvcyBkYXRvcyByZWFsZXMuDQoNCjYuICoqUmVjb21lbmRhY2nDs24gZ2VuZXJhbCBwYXJhIEthcmVuOioqIHVzYXIgZXN0b3MgcHJvbsOzc3RpY29zIHByaW5jaXBhbG1lbnRlIHBhcmEgKipwbGFuZWFjacOzbiBkZSBwZXJzb25hbCwgY29tcHJhcyBkZSBpbnZlbnRhcmlvIChtYXJpc2NvcyBmcmVzY29zKSB5IGZsdWpvIGRlIGNhamEqKiwgcmVmb3J6YW5kbyBsYSBvcGVyYWNpw7NuIGVuIGxvcyBtZXNlcyBkZSB0ZW1wb3JhZGEgYWx0YSAoZGljLW1hcikgeSBhanVzdGFuZG8gY29zdG9zL3BlcnNvbmFsIGVuIGxvcyBtZXNlcyBkZSB0ZW1wb3JhZGEgYmFqYSAoanVuLW9jdCksIHNpbiBwZXJkZXIgZGUgdmlzdGEgcXVlIGxhIHRlbmRlbmNpYSBnZW5lcmFsIGRlbCBuZWdvY2lvIHNpZ3VlIHNpZW5kbyBkZSBjcmVjaW1pZW50by4NCg==