1 Introducción

Los accidentes viales son una problemática que ha afectado de gran manera a la ciudad de Medellín. El crecimiento económico de la ciudad y la rápida urbanización causan un gran aumento en el parque automotor, la densidad vehícular y las dificultades de transitar en las vías que conforman la ciudad. En este trabajo se plantea crear un sistema que pueda ayudar a mitigar los accidentes en las vías, además de servir como guía para tomar medidas frente a la situación actual.

Durante el periodo entre 2014 y 2018 se logró tomar una cantidad significativa de datos sobre la accidentalidad en Medellín y algunas de sus zonas aledañas, para evidenciar así, el problema de movilidad que presenta el área. Estos datos se encuentran en el portal GeoMedellín, donde cada uno de estos incidentes se encuentra georreferenciado, dividido por barrio y comuna. Cuenta, además, con la información sobre la vía donde el accidente ocurrió y también sobre el tipo de accidente que se dio, la fecha de éste e incluso los daños perjudiciales causados a los ciudadanos -muertos, heridos o solo daños materiales-.

Ahora bien, al tener más de 200.000 datos durante este intervalo, el equipo se planteó el objetivo de darle un buen uso a estos, no sólo para analizar lo que sucedió en este lapso, sino también para ayudar a predecir accidentes a futuro y así poder esgrimir un modelo prevencionista. En ese orden de ideas, para acceder a la información recolectada y al presente análisis se habilitará un enlace a aplicación TransitApp, donde la información a la que se accede estará presentada de una forma interactiva e intuitiva, para obtener un mejor entendimiento del usuario.

En el presente reporte se encuentra información detallada respecto a la depuración, imputación, análisis descriptivo, creación de clusters y modelos predictivos realizados para crear la aplicación TransitApp. Se verá que los modelos mixtos (modelos jerárquicos) presentan una buena estimación de la accidentalidad (número de accidentes) en la ciudad de Medellín.

Enlace aplicativo TransitApp: https://valentina-garcia-velasquez.shinyapps.io/TransitAPP_2020/

Enlace repositorio GitHub: https://github.com/vagarciave/TransitApp_1.0/

2 Justificación

La ciudad de Medellín presenta un índice de accidentalidad vial bastante alto comparada con otras ciudades de la región e incluso con la capital del país, Bogotá. Según el “Ránking (sic) Latinoamericano de Ciudades Fatales” de 2018, informe realizado por el centro de pensamiento LA Network, Medellín estaba ranqueada en el puesto 29 de las ciudades con más muertes en las vías de Latinoamérica, con 10.9 muertos por cada 100 mil habitantes. Además, durante el año 2017 hubo un total 41.667 accidentes viales en Medellín, los cuales ocasionaron 258 muertes.

También es necesario tener en cuenta al sistema de salud en los accidentes viales, debido a que estos afectan gravemente la capacidad de cobertura para otro tipo de emergencias. Solo en 2017, 14000 de los 30000 heridos en los accidentes viales requirieron asistencia médica, y de este grupo, 3800 presentaron heridas graves. Aunque, durante los años 2019 y 2020 se ha notado una disminución de estas estadísticas sobre la accidentalidad vial, se puede evidenciar que existe la necesidad de tener un mayor entendimiento de los datos, especialmente para los conductores, motociclistas y hasta ciclistas y peatones. Con la implementación del sistema planteado en este trabajo, se pretende crear una política de prevención de accidentalidad y además una conciencia ciudadana para manejar con mayor precaución en ciertos lugares y poder planear mejor sus viajes.

3 Objetivos

El análisis y los modelos que se pretenden construir sólo abarca el área urbana de Medellín correspondiente a sus 16 comunas y sus respectivos barrios.

3.1 Objetivo general

Construir un sistema que le permita a la Secretaría de Movilidad de Medellín tomar decisiones en la creación de estrategias que ayuden a reducir la accidentalidad en zona específicas de Medellín, observando cuales son los tipos de accidentes más frecuentes en las diferentes comunas y sus barrios.

También se busca que el sistema les permita a todos los ciudadanos que se movilizan en un vehículo tomar precauciones respecto a los accidentes más frecuentes que suceden en lugares específicos.

Lo anterior creando una interfaz amigable para los usuarios y fácil de utilizar.

3.2 Objetivos específicos

  • Construir modelos que predigan el número de accidentes de cada tipo, tomando como entradas una ventana y una resolución temporal específicas, además de una zona espacial que puede ser un barrio o comuna de Medellín.

  • Elaborar un sistema que agrupe barrios con características similares por los tipos de accidentes (clase) y la gravedad que tienen lugar en estos.

  • Crear una interfaz gráfica que le permita al usuario visualizar con mayor comodidad la accidentalidad que hay en Medellín y las predicciones de esta a futuro.

4 Descripción y Limpieza de los datos

Los datos utilizados se encuentran en las bases de datos de Geomedellín (Portal Geográfico del Municipio de Medellín) y contienen información referente a múltiples accidentes de tránsito, en los que se detalla el tipo de accidente, dónde y cuándo ocurrió. La base de datos utilizada en este trabajo es una unión de las bases de incidentes en 2014, 2015, 2016, 2017 y 2018, se usará este último año para validar los modelos planteados.

La base de datos original cuenta con las siguientes variables:

  • X: Componente de coordenada.
  • Y: Componente de coordenada.
  • OBJECTID: Id de cada incidente.
  • RADICADO: Código emitido por la secretaría de movilidad de Medellín.
  • FECHA: Fecha del incidente.
  • HORA: Hora del incidente.
  • DIA: Día del mes en el que ocurre el incidente
  • PERIODO: Año del incidente.
  • CLASE: Tipo de accidente
  • DIRECCION.
  • DIRECCION_ENC.
  • CBML: Código de ubicación del predio en la ciudad.
  • TIPO_GEOCOD: Tipo de
  • GRAVEDAD: repercusiones del accidente
  • BARRIO.
  • COMUNA.
  • DISENO: clasificación del lugar del accidente.
  • DIA_NOMBRE: Día de la semana en el que ocurre el incidente
  • MES: Mes del incidente en número (del 1 al 12)
  • MES_NOMBRE: Mes del incidente
  • X_MAGNAMED: Componente de coordenada
  • Y_MAGNAMED: Componente de coordenada
  • LONGITUD: Componente de coordenada
  • LATITUD: Componente de coordenada

Se deciden eliminar las variables “X”, “Y”, “X_MAGNAMED” y “Y_MAGNAMED” ya que cumplen la misma función que las variables “LONGITUD” y “LATITUD”. También se elimina la variable “RADICADO” ya que sirve para identificar a un respectivo incidente, al igual que la variable “OBJECTID”. Se elimina la variable “MES_NOMBRE” ya que es redundante el la base de datos, debido a que se encuentra la misma información en la variable “MES”. Además ponerle los nombres a partir de la variable “MES” traería un aumento al coste computacional innecesario. También se decide eliminar las variables “DIRECCION”, “DIRECCION_ENC”, “CBML”, “TIPO_GEOCOD” y “HORA” ya no serán de utilidad en el modelo.

Además se crea otra variable llamada “DIA_FESTIVO”. Para poder analizar el número de accidentes en los días festivos y demás fechas especiales. Por lo tanto, las variables de interés que se usan en este proyecto son las siguientes:

  • OBJECTID: Id de cada incidente.
  • CLASE: Tipo de accidente
  • GRAVEDAD: repercusiones del accidente
  • COMUNA.
  • BARRIO.
  • DISENO: clasificación del lugar del accidente.
  • LATITUD: Componente de coordenada
  • LONGITUD: Componente de coordenada
  • FECHA: Fecha del incidente.
  • DIA: Día del mes en el que ocurre el incidente
  • MES: Mes del incidente en número (del 1 al 12)
  • PERIODO: Año del incidente.
  • DIA_NOMBRE: Día de la semana en el que ocurre el incidente
  • DIA_FESTIVO.

Definido lo anterior, se realiza una limpieza en la base de datos, ya que hay registros u observaciones que están mal escritos o simplemente no deberían estar. A continuación se explican los cambios realizados.

4.1 Depuración

Se decide quitar los acentos a cada una de las variables categóricas debido a que hay valores repetidos los cuales representan el mismo nivel o categoria, pero con acento y sin acento. Un ejemplo de esto es el barrio Berlpín de la comuna Aranjuez, el cual aparece 647 veces con el nombre de “Berlín” y 15 veces con el nombre de “Berlín”. Por lo tanto se decide arreglar este problema.

4.1.1 Para COMUNA

La variable COMUNA debe tener las comunas urbanas de Medellín y sus corregimientos.

Se sabe que en Medellín hay 16 comunas urbanas y 5 corregimientos, ambos están compuestos por barrios, por lo que la variable debería tener 16 + 5 = 21 niveles. Pero al observar los niveles de la variable “COMUNA” en el conjunto de entrenamiento, se evidencian 84 comunas, por lo cual se decide buscar las razones de esto y tratar de corregirlo.

Comunas: Popular, Santa Cruz, Manrique, Aranjuez, Castilla, Doce de Octubre, Robledo, Villa Hermosa, Buenos Aires, La Candelaria, Laureles-Estadio, La América, San Javier, El Poblado, Guayabal, Belén.

Corregimientos: Corregimiento de San Cristóbal, Corregimiento de San Antonio de Prado, Corregimiento de Santa Elena, Corregimiento de Altavista, Corregimiento de San Sebastián de Palmitas.

Uno de los problemas que se encuentra es que la persona encargada de digitar los datos se confundió entre las variables “COMUNA” y “BARRIO”. Un ejemplo de esto es el barrio Boston que aparece como comuna en 2 observaciones, con su respectiva comuna (La candelaria) en barrio. Así como el ejemplo anterior, hay varios casos. Por lo cual, estas comunas y barrios se ponen en su posición correcta.

Luego de resolver el problema anterior, se encuentra que aún hay comuna que no pertenecen a las 21 mencionadas anteriormente, estas son: “In”, “AU”, “SN”, “0”. Al no encontrar información de estos valores en la página oficial o en internet, se decide reemplazar estos valores con sus respectivos barrios como datos faltantes o NA.

4.1.2 Para BARRIO

Se detecta que los barrios contienen algunos problemas de espacios, algunos ejemplos son:

  • “Asomadera No. 1” y “Asomadera No.1”
  • “Aures No. 2” y “Aures No.2”
  • “Bombona No. 1” y “Bombona No.1”
  • “B. Cerro El Volador” y “B. Cerro El Volador”

Por lo tanto se arregla este problema quitando el espacio que hay entre “No.” y su número correspondiente en los barrios que tienen esta característica. También se eliminan los espacios que hay antes de la primera letra y después de la última letra.

También se reemplaza “Barrios de Jesús” por “Barrio de Jesús”, “Nueva Villa de La Iguana” por “Nueva Villa de la Iguana”, “Santa María de Los Ángeles” por “Santa María de los Ángeles”, “Villa Lilliam” por “Villa Liliam”.

4.1.3 Para CLASE

“Caida de Ocupante” se reemplaza por “Caida Ocupante” ya que se consideran equivalentes. También se elimina la observación con CLASE = “Choque y Atropello” ya que solo hay una.

4.1.4 Para DIA_NOMBRE

Se eliminan los espacios que hay antes de la primera letra y después de la última letra en todas las observaciones.

4.2 Imputación

En los datos faltantes de la variable DISENO, se decide usar el nombre de “No Registrado” para reemplazarlos.

En la base de datos se tiene la siguiente cantidad de datos faltantes por variable: la variable BARRIO tiene 19957 de datos faltantes, COMUNA tiene 19957 y CLASE tiene 7. Las demás variables no contienen datos faltantes.

Como la variable CLASE solo tiene 7 datos faltantes, se decide eliminar estas observaciones. Por el contrario, como BARRIO y COMUNA presentan una cantidad importante de los datos, se decide realizar una imputación de los mismos.

4.2.1 Para COMUNA

Primero se decide realizar la imputación en la variable COMUNA, se utiliza un modelo knn (k-Nearest Neighbour) con variable respuesta COMUNA y como predictoras las variables LATITUD y LONGITUD escaladas. Dado que este es un modelo que usa la distancia euclidiana para clasificar observaciones, se piensa que funcionaría bien para clasificar a las comunas teniendo su ubicación en latitud y longitud.

Para ajustar el modelo se usó la función train del paquete caret, usando K-Fold CV con K=10 y el número de vecinos igual a 1, 4, 7, 10, 13, 16 y 19. Se entrenó el modelo usando los años de 2014 a 2017 y se validó con el año 2018. Se usó la precisión de prueba del modelo como función de optimización. Los resultados obtenidos son los siguientes:

Accuracy Kappa AccuracyLower AccuracyUpper AccuracyNull AccuracyPValue
0.9985 0.9984 0.9981 0.9989 0.2062 0

Los resultados se consideran buenos y se decide realizar el reemplazo de los valores faltantes de COMUNA por medio de este modelo.

4.2.2 Para BARRIO

Se decide usar un modelo knn (k-Nearest Neighbour) con variable respuesta BARRIO y como predictoras las variables LATITUD y LONGITUD escaladas y COMUNA.

Dado que habían valores de barrios que están en el año 2018 pero no en los demás, no se pudo hacer uso del paquete caret ya que presentaba un error al entrenar el modelo, por lo que se decide usar la función knn.cv del paquete class, para medir el comportamiento del modelo knn con k = 1 mediante LOOCV, entrenando el modelo con los años de 2014 hasta 2017 y validando el resultado con el año 2018. Se obtiene una precisión de prueba de 0.9975, por lo que se decide usar este modelo para imputar los datos faltantes en BARRIO.

4.3 Base final

Finalmente se decide usar solo las comunas del área urbana de Medellín y dejar a un lado los corregimientos, es decir, solo se tendrán las 16 comunas mencionadas anteriormente en este reporte.

Tras las modificaciones mencionadas, de las 228693 observaciones originales entre las bases de datos del 2014 al 2018, se utilizarán 204002 observaciones en el análisis y construcción de los modelos. La base de datos luce de esta manera:

A continuación se encuentra el acceso al código utilizado en todo este proceso

Enlace: https://github.com/vagarciave/TransitApp_1.0/blob/master/limpieza/Depuracion.Rmd

5 Análisis descriptivo

5.1 Sobre la base de datos

Luego de la depuración e imputación de los datos, se cuenta con un total de 204002 incidentes de tránsito, los cuales tienen 14 características que se pueden llamar “variables”. De las 14 variables 7 son categorícas (OBJECTID, CLASE , GRAVEDAD, COMUNA, BARRIO, DISENO, DIA_NOMBRE). Hay un total de 16 comunas, 268 barrios, 6 clases de accidente, 3 niveles de gravedad, 13 tipos de diseño de vía.

Para este análisis no se considerarán las variables FECHA, LATITUD y LONGITUD.

5.2 Periodo

La cantidad total de accidentes por periodo es bastante simular, se nota una leve reducción para el 2018.

5.3 Clase

## List of 1
##  $ legend.position: chr "bottom"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi FALSE
##  - attr(*, "validate")= logi TRUE

Para clase, es claro que en cada periodo lo que más se presentan son choques, de manera análoga es poco común que hayan incendios, de igual forma los volcamientos también son poco comunes. Para las clases atropello, caída de ocupante y otro parece haber cantidades muy similares, estos comportamientos son parecidos en cada periodo pero hay diferencias que podrían ser significativas en los modelos.

5.4 Gravedad

## List of 1
##  $ legend.position: chr "bottom"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi FALSE
##  - attr(*, "validate")= logi TRUE

En los accidentes de tránsito lo más común es que se presenten heridos, seguido por solo daños, por otra parte el número de muertos para cada periodo es muy bajo, comparado con los otros tipos de gravedad. Para el año 2018 se nota una leve disminución en la cantidad de heridos.

5.5 Comuna

En los accidentes por comuna se evidencia que la comuna “La Candelaria” es la que mas accidentes ha registrado durante los periodos analizados, la de menor cantidad de accidentes es la comuna “Santa Cruz”, esto es con el número de accidentes observado, del 2014 al 2018.

5.6 Comunas por periodo

Ahora discriminando el número de accidentes en las comunas por periodo, se observa que se presenta una tendencia similar para cada periodo, por lo que se piensa que cada año van a existir tendencias similares de la accidentalidad por comuna.

5.7 Barrios por periodo

Para los barrios se tiene el cuenta el top 10 con más accidentes por cada periodo, el barrio que presentó mayor número de accidentes de 2014 a 2017 fue la Candelaria, para 2018 este barrio fue superado por una cantidad no muy grande por el barrio campo amor, se evidencia como a través del tiempo algunos barrios ingresan o salen del top 10, por ejemplo el Carlos E. Restrepo empezó a tener una accidentalidad más alta a partir del 2016, por su parte Guayaquil redujo su accidentalidad para 2018, el barrio Naranjal solo estuvo en el top 10 en el año 2015.

Los primeros 5 barrios con mas cantidad de accidentes por gravedad

Estos son los 5 barrios con mas cantidad de accidentes, los cuales se clasifican por la gravedad, que son:“solo daños”,“Herido” y “Muerto”, se identificaron los primeros barrios con mas accidentalidad por año, notar que la gravedad menos concurrente es “Muerto”, aunque la Candelaria es el barrio con mas accidentes por año, tamibien note que Castilla tiene mas accidentes con gravedad de muertes mas alta que la de los demas barrios.

5.8 Diseño

## List of 1
##  $ legend.position: chr "bottom"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi FALSE
##  - attr(*, "validate")= logi TRUE

El diseño que más accidentalidad presenta es el tramo de vía, esto para todos los periodos. De 2014 a 2018 hubo una disminución en este tipo de accidentes, por su lado los accidentes para intersección y Lote o predio aumentaron levemente de 2014 a 2018.

5.9 Accidentalidad por mes

Se puede apreciar que la accidentalidad para 2018 es menor comparada con otros años, esto para casi todos los meses, se observa como hay diferencias para cada periodo y cada año, por lo cual una variable temporal en los modelos predictivos podría sr significativa. Para los meses de Enero a Marzo la accidentalidad parece ser más baja, para el mes de Junio los accidentes disminuyen. De Agosto a Octubre la accidentalidad en más alta.

5.10 Día de la semana

Es claro que los días festivos son un factor realmente influyente en el número de accidentes, pues para estos se presentan menor cantidad de accidentes, para el día domingo el total de accidentes es menor, para los demás días no se observa una diferencia significativa.

5.11 Conclusión del análisis

Del análisis descriptivo se concluye que las variables temporales no son influyentes en la accidentalidad, para el mes hay variaciones significativas en el número total de accidentes, por su parte para la clase de accidente, gravedad y diseño también varía el total de accidentes. Principalmente la variabilidad a nivel de accidentalidad depende en mayor medida de barrio y comuna

6 Modelos Predictivos

Se define la accidentalidad como el número de accidentes que hay a nivel diario, semanal y mensual, discriminando por tipo de accidente (CLASE) y barrio o comuna donde éste ocurre. Lo anterior debido a que existe una variabilidad notable a nivel de accidentalidad para cada columna y para cada barrio como se observó en el análisis descriptivo.

Dado que el objetivo es predecir la accidentalidad a nivel diario, mensual o semanal, se busca construir modelos que predigan el número de accidentes en cada uno de los rangos temporales es decir se crearán modelos específicos para cada comuna/barrio según la unidad temporal.

Se piensa que los modelos mixtos o modelos jerárquicos pueden representar bien esta definición de accidentalidad, debido a la agrupación que existe al momento de definir la accidentalidad, es decir, existe una agrupación entre comuna y clase; y otra agrupación entre barrio y clase. Por lo que se decide crear estos modelos con la ayuda del paquete lme4 y medir su ajuste. En cada uno de estos casos se crea un modelo que prediga el número de accidentes, por lo que se considera que la accidentalidad puede seguir una distribución Poisson.

Para evaluar los modelos se crean conjuntos de entrenamiento y conjuntos de validación. Los conjuntos de entrenamiento constan de todas las combinaciones posibles de tipos de accidentes según si es comuna o barrio y su unidad de tiempo con los años (periodos) del 2014 al 2017, el conjunto de validación será con el año 2018.

La medida para evaluar el ajuste de los modelos será el error cuadrático medio en las predicciones tanto para los conjuntos de entrenamiento como para los de validación.

\[MSE = \frac{\sum_{i=1}^N (accidentalidad_i - \widehat{accidentalidad_i)^2}}{N}\]

Con la ayuda de R se crea la siguiente función para obtenerlo:

MSE <- function(y, y_est) mean((y-y_est)**2)

Se usarán los siguientes paquetes para ajustar los modelos

library(lme4)      # Paquete para la creación de modelos mixtos poisson
library(tidyverse) # Paquete para la creación de los conjuntos de datos

6.1 Ajuste de la base de datos

Se debe modificar la base de datos depurada para poder realizar los modelos. Se crean variables de tiempo a nivel diario, semanal y mensual, además de la variable accidentalidad y días festivos.

#  Vector con fechas de dias festivos
  # Definir dias festivos
  festivos <- ymd(c(
    #2014
    '2014-01-01','2014-01-06','2014-03-24','2014-04-17','2014-04-18', '2014-05-01',
    '2014-06-02','2014-06-23','2014-06-30','2014-07-20','2014-08-07', '2014-08-18',
    '2014-10-13','2014-11-03','2014-11-17','2014-12-08','2014-12-25',
    #2015
    '2015-01-01','2015-01-12','2015-03-23','2015-03-29','2015-04-02','2015-04-03',
    '2015-04-05','2015-05-01','2015-05-18','2015-06-08','2015-06-15','2015-06-29',
    '2015-07-20','2015-08-07', '2015-08-17','2015-10-12','2015-11-02','2015-11-16',
    '2015-12-08','2015-12-25',
    #2016
    '2016-01-01','2016-01-11','2016-03-20','2016-03-21','2016-03-24','2016-03-25',
    '2016-03-27','2016-05-01','2016-05-09','2016-05-30','2016-06-06','2016-07-04',
    '2016-07-20','2016-08-07', '2016-08-15','2016-10-17','2016-11-07','2016-11-14',
    '2016-12-08','2016-12-25',
    #2017
    '2017-01-01','2017-01-09','2017-03-20','2017-04-09','2017-04-13','2017-04-14',
    '2017-04-16','2017-05-01','2017-05-29','2017-06-19','2017-06-26','2017-07-03',
    '2017-07-20','2017-08-07', '2017-08-21','2017-10-16','2017-11-06','2017-11-13',
    '2017-12-08','2017-12-25',
    #2018
    '2018-01-01','2018-01-08','2018-03-19','2018-03-25','2018-03-29','2018-03-30',
    '2018-04-01','2018-05-01','2018-05-14','2018-06-04','2018-06-11','2018-07-02',
    '2018-07-20','2018-08-07', '2018-08-20','2018-10-15','2018-11-05','2018-11-11',
    '2018-12-08','2018-12-25',
    #2019
    '2019-01-01','2019-01-07','2019-03-25','2019-04-18','2019-04-19','2019-05-1',
    '2019-06-03','2019-06-24','2019-07-01','2019-07-20','2019-08-07','2019-08-19',
    '2019-10-14','2019-11-04','2019-11-11','2019-12-08','2019-12-25'
    ))

df <- df %>% select(COMUNA, CLASE, FECHA, PERIODO, MES, DIA_NOMBRE)

df$FECHA <- as.Date(df$FECHA)

# Se agrega la variable TIEMPO y MES_NOMBRE
df$MES_NOMBRE <- paste(df$PERIODO, df$MES, sep="-") %>% as.yearmon("%Y-%m")

# Para obtener la inversa se usaría: zoo::as.Date(df$FECHA, origin="2014-01-01")
df$TIEMPO_DIA <- as.numeric(as.Date(df$FECHA)) - as.numeric(as.Date("2014-01-01")) + 1

# Se crea la variable SEMANA
df <- df %>% mutate(SEMANA = strftime(FECHA, format = "%Y-%V"),
                          TIEMPO_SEMANA = match(SEMANA, sort(unique(SEMANA))))

# Se crea la variable MES
df <- df %>% mutate(MES = strftime(FECHA, format = "%Y-%m"),
                          TIEMPO_MES = match(MES, sort(unique(MES))))

# días festivos
df <- df %>% mutate(DIA_FESTIVO = ifelse(ymd(FECHA) %in% festivos,1,0))

# accidentalidad
df <- df %>% mutate(ACCIDENTALIDAD = 1)

6.2 Modelos predictivos para las Comunas

Para obtener la base datos en la cual se encuentre el número de accidentes para cada evento considerado, se crea una base de datos con todos los eventos posibles con ayuda de la función expand.grid, en la cual se tiene en cuenta todas la combinaciones de comuna, clase (tipo de accidente) y fecha.

fecha_vector <- as.Date(as.Date("2014-01-01"):as.Date("2018-12-31"))
base <- expand.grid(COMUNA = levels(df$COMUNA), CLASE = levels(df$CLASE),
                             FECHA = fecha_vector)
base <- base %>% mutate(TIEMPO_DIA = as.numeric(FECHA) -
                                            as.numeric(as.Date("2014-01-01")) + 1)

# PERIODO
base <- base %>% mutate(PERIODO = as.numeric(format(FECHA,'%Y')))

# Se crea la variable SEMANA
base <- base %>% mutate(SEMANA = strftime(FECHA, format = "%Y-%V"),
                          TIEMPO_SEMANA = match(SEMANA, sort(unique(SEMANA))))

# Se crea la variable MES
base <- base %>% mutate(MES = strftime(FECHA, format = "%Y-%m"),
                          TIEMPO_MES = match(MES, sort(unique(MES))))

# días festivos
base <- base %>% mutate(DIA_FESTIVO = ifelse(ymd(FECHA) %in% festivos,1,0))

Luefo se realiza un left join con la base que contiene todos los posibles eventos y la base de datos que contiene la información de los accidentes (base depurada).

base <- left_join(base, subset(df, select = -DIA_NOMBRE),
                  by = c("COMUNA", "CLASE", "FECHA", "TIEMPO_DIA",
                                       "PERIODO", "SEMANA", "TIEMPO_SEMANA",
                                       "TIEMPO_MES", "DIA_FESTIVO"))
base[is.na(base)] <- 0

accidentes_dia_comuna <- left_join(base, distinct(df[, c("FECHA", "DIA_NOMBRE")]), by = "FECHA")

6.2.1 Modelos - unidad de tiempo Día

La base de datos con el número de accidentes por comuna, clase y día se obtuvo anteriormente, ésta contiene 175296 observaciones.

dim(accidentes_dia_comuna)
## [1] 175296     12

La base luce de la siguiente manera:

Se realiza la partición de los datos para seleccionar el conjunto de entrenamiento y el conjunto de prueba.

test_dia_comuna <- accidentes_dia_comuna[accidentes_dia_comuna$PERIODO == 2018, ]
train_dia_comuna <- accidentes_dia_comuna[accidentes_dia_comuna$PERIODO %in%
                                            c(2014, 2015, 2016, 2017), ]

Se procede a la creación de modelos:

Se consideran distintos modelos partiendo de un modelo jerárquico con 2 niveles (CLASE y COMUNA) con solo un intercepto, ambos niveles o variables con efectos aleatorios se consideran correlacionados y se pondrá la variable CLASE (tipo de accidente) dentro de la variable comuna.

mod_dia_comuna0 <- glmer(ACCIDENTALIDAD ~ 1 + (1 | COMUNA/CLASE),
                         data = train_dia_comuna, family= poisson())
mod_dia_comuna1 <- glmer(ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | COMUNA/CLASE),
                         data = train_dia_comuna, family= poisson())
mod_dia_comuna2 <- glmer(ACCIDENTALIDAD ~ DIA_FESTIVO + TIEMPO_DIA + (1 | COMUNA/CLASE),
                         data = train_dia_comuna, family= poisson())
mod_dia_comuna3 <- glmer(ACCIDENTALIDAD ~ DIA_FESTIVO + DIA_NOMBRE + (1 | COMUNA/CLASE),
                         data = train_dia_comuna, family= poisson())
mod_dia_comuna4 <- glmer(ACCIDENTALIDAD ~ DIA_FESTIVO + DIA_NOMBRE +
                           (1 + DIA_FESTIVO| COMUNA/CLASE),
                         data = train_dia_comuna, family= poisson())

Se comparan los modelos por un analísis de varianza ANOVA:

anova(mod_dia_comuna0, mod_dia_comuna1, mod_dia_comuna2, mod_dia_comuna3, mod_dia_comuna4)

Al parecer cada modelo explica mejor la accidentalidad que el anterior, pero se debe recordar que el Valor-P es sensible al número de datos. En la base de entrenamiento hay 140256 observaciones, esto se considera grande, por lo que no hay que fijarse mucho en el Valor-P dado que es más fácil que rechace las hipótesis nulas.

Se procede a calcular el MSE de entrenamiento y de prueba en cada uno de los modelos, cabe resaltar que los valores predichos se redondearán al entero más cercano debido a que son datos de conteo y la función predict devuelve valores en la escala original pero con décimales.

# Modelo 0
y_est_train_dia_comuna0 <- round(predict(mod_dia_comuna0, newdata = train_dia_comuna,
                                         type = "response"),0)
y_est_test_dia_comuna0 <- round(predict(mod_dia_comuna0, newdata = test_dia_comuna,
                                        type = "response"),0)
mse_train_dia_comuna0 <- round(MSE(train_dia_comuna$ACCIDENTALIDAD,
                                   y_est_train_dia_comuna0),4)
mse_test_dia_comuna0 <- round(MSE(test_dia_comuna$ACCIDENTALIDAD,
                                 y_est_test_dia_comuna0),4)

# Modelo 1
y_est_train_dia_comuna1 <- round(predict(mod_dia_comuna1, newdata = train_dia_comuna,
                                         type = "response"),0)
y_est_test_dia_comuna1 <- round(predict(mod_dia_comuna1, newdata = test_dia_comuna,
                                        type = "response"),0)
mse_train_dia_comuna1 <- round(MSE(train_dia_comuna$ACCIDENTALIDAD,
                                   y_est_train_dia_comuna1),4)
mse_test_dia_comuna1 <- round(MSE(test_dia_comuna$ACCIDENTALIDAD,
                                  y_est_test_dia_comuna1),4)

# Modelo 2
y_est_train_dia_comuna2 <- round(predict(mod_dia_comuna2, newdata = train_dia_comuna,
                                         type = "response"),0)
y_est_test_dia_comuna2 <- round(predict(mod_dia_comuna2, newdata = test_dia_comuna,
                                        type = "response"),0)
mse_train_dia_comuna2 <- round(MSE(train_dia_comuna$ACCIDENTALIDAD,
                                   y_est_train_dia_comuna2),4)
mse_test_dia_comuna2 <- round(MSE(test_dia_comuna$ACCIDENTALIDAD,
                                  y_est_test_dia_comuna2),4)

# Modelo 3
y_est_train_dia_comuna3 <- round(predict(mod_dia_comuna3, newdata = train_dia_comuna,
                                         type = "response"),0)
y_est_test_dia_comuna3 <- round(predict(mod_dia_comuna3, newdata = test_dia_comuna,
                                        type = "response"),0)
mse_train_dia_comuna3 <- round(MSE(train_dia_comuna$ACCIDENTALIDAD,
                                   y_est_train_dia_comuna3),4)
mse_test_dia_comuna3 <- round(MSE(test_dia_comuna$ACCIDENTALIDAD,
                                  y_est_test_dia_comuna3),4)

# Modelo 4
y_est_train_dia_comuna4 <- round(predict(mod_dia_comuna4, newdata = train_dia_comuna,
                                         type = "response"),0)
y_est_test_dia_comuna4 <- round(predict(mod_dia_comuna4, newdata = test_dia_comuna,
                                        type = "response"),0)
mse_train_dia_comuna4 <- round(MSE(train_dia_comuna$ACCIDENTALIDAD,
                                   y_est_train_dia_comuna4),4)
mse_test_dia_comuna4 <- round(MSE(test_dia_comuna$ACCIDENTALIDAD,
                                  y_est_test_dia_comuna4),4)

Modelo_Mixto_Poisson Train_MSE Test_MSE Porcentaje_Variacion
ACCIDENTALIDAD ~ 1 + (1 | COMUNA/CLASE) 2.0222 1.9352 2.20
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | COMUNA/CLASE) 1.9038 1.8241 2.14
ACCIDENTALIDAD ~ DIA_FESTIVO + TIEMPO_DIA + (1 | COMUNA/CLASE) 1.9010 1.8598 1.10
ACCIDENTALIDAD ~ DIA_FESTIVO + DIA_NOMBRE + (1 | COMUNA/CLASE) 1.5791 1.5311 1.54
ACCIDENTALIDAD ~ DIA_FESTIVO + DIA_NOMBRE + (1 + DIA_FESTIVO | COMUNA/CLASE) 1.5400 1.5118 0.92

En los modelos mod_dia_comuna3 y mod_dia_comuna4 se descarta usar la variable TIEMPO_DIA debido a que en lugar en disminuir el Test_MSE, lo aumentó, y tampoco mejoró el Train_MSE significativamente, por lo que se considera que no es significativa para explicar la accidentalidad en las comunas de Medellín por tipo de accidente.

Finalmente se observa que el modelo con intercepto y pendiente aleatoria mod_dia_comuna4:

\[\widehat{\text{ACCIDENTALIDAD}} = \text{DIA_FESTIVO} + \text{DIA_NOMBRE} + (1 + \text{DIA_FESTIVO} | \text{COMUNA/CLASE})\]

Es el que obtiene el menor Train_MSE y Test_MSE, por lo que se escoge este modelo para la explicación de la accidentalidad en comuna por día.

A continuación se muestran algunos de los valores observados de la accidentalidad diaria por clase y por comuna, con su respectivo valor predicho última columna) en el conjunto de prueba.

6.2.2 Modelos - unidad de tiempo Semana

Para este modelo se agrupa la unidad de tiempo por semanas, en las cuales se suma la cantidad de accidentes que suceden el la misma, también se suma el número de días festivos. La base luce como sigue:

accidentes_semana_comuna <- accidentes_dia_comuna %>%
  group_by(COMUNA, CLASE, PERIODO, SEMANA, TIEMPO_SEMANA) %>%
  summarise(DIA_FESTIVO = sum(DIA_FESTIVO), ACCIDENTALIDAD = sum(ACCIDENTALIDAD))

accidentes_semana_comuna

Se procede a realizar la partición del conjunto de entrenamiento y el conjunto de prueba:

test_semana_comuna <- accidentes_semana_comuna[accidentes_semana_comuna$PERIODO == 2018, ]
train_semana_comuna <- accidentes_semana_comuna[accidentes_semana_comuna$PERIODO %in%
                                                  c(2014, 2015, 2016, 2017), ]

Ahora se ajustan los modelos mixtos con efectos aleatorios en COMUNA y CLASE al igual que se hizo a nivel diario, es decir, CLASE dentro de COMUNA.

mod_semana_comuna0 <- glmer(ACCIDENTALIDAD ~  1 + (1 | COMUNA/CLASE),
               data = train_semana_comuna, family= poisson())
mod_semana_comuna1 <- glmer(ACCIDENTALIDAD ~  DIA_FESTIVO + (1 | COMUNA/CLASE),
               data = train_semana_comuna, family= poisson())
mod_semana_comuna2 <- glmer(ACCIDENTALIDAD ~  DIA_FESTIVO + TIEMPO_SEMANA +
                              (1 | COMUNA/CLASE),
               data = train_semana_comuna, family= poisson())
mod_semana_comuna3 <- glmer(ACCIDENTALIDAD ~  DIA_FESTIVO +
                              (1 + DIA_FESTIVO | COMUNA/CLASE),
               data = train_semana_comuna, family= poisson())

Se comparan los modelos por un analísis de varianza ANOVA:

anova(mod_semana_comuna0, mod_semana_comuna1, mod_semana_comuna2, mod_semana_comuna3)

Se tiene el mismo problema del tamaño de muestra que en el modelo diario. Ahora, se procede a calcular el MSE de entrenamiento y de prueba en cada uno de los modelos, cabe resaltar que los valores predichos se redondearán al entero más cercano debido a que son datos de conteo y la función predict devuelve valores en la escala original pero con décimales.

# Modelo 0
y_est_train_semana_comuna0 <- round(predict(mod_semana_comuna0, newdata = train_semana_comuna,
                                         type = "response"),0)
y_est_test_semana_comuna0 <- round(predict(mod_semana_comuna0, newdata = test_semana_comuna,
                                        type = "response"),0)
mse_train_semana_comuna0 <- round(MSE(train_semana_comuna$ACCIDENTALIDAD,
                                   y_est_train_semana_comuna0),4)
mse_test_semana_comuna0 <- round(MSE(test_semana_comuna$ACCIDENTALIDAD,
                                 y_est_test_semana_comuna0),4)

# Modelo 1
y_est_train_semana_comuna1 <- round(predict(mod_semana_comuna1, newdata = train_semana_comuna,
                                         type = "response"),0)
y_est_test_semana_comuna1 <- round(predict(mod_semana_comuna1, newdata = test_semana_comuna,
                                        type = "response"),0)
mse_train_semana_comuna1 <- round(MSE(train_semana_comuna$ACCIDENTALIDAD,
                                   y_est_train_semana_comuna1),4)
mse_test_semana_comuna1 <- round(MSE(test_semana_comuna$ACCIDENTALIDAD,
                                  y_est_test_semana_comuna1),4)

# Modelo 2
y_est_train_semana_comuna2 <- round(predict(mod_semana_comuna2, newdata = train_semana_comuna,
                                         type = "response"),0)
y_est_test_semana_comuna2 <- round(predict(mod_semana_comuna2, newdata = test_semana_comuna,
                                        type = "response"),0)
mse_train_semana_comuna2 <- round(MSE(train_semana_comuna$ACCIDENTALIDAD,
                                   y_est_train_semana_comuna2),4)
mse_test_semana_comuna2 <- round(MSE(test_semana_comuna$ACCIDENTALIDAD,
                                  y_est_test_semana_comuna2),4)

# Modelo 3
y_est_train_semana_comuna3 <- round(predict(mod_semana_comuna3, newdata = train_semana_comuna,
                                         type = "response"),0)
y_est_test_semana_comuna3 <- round(predict(mod_semana_comuna3, newdata = test_semana_comuna,
                                        type = "response"),0)
mse_train_semana_comuna3 <- round(MSE(train_semana_comuna$ACCIDENTALIDAD,
                                   y_est_train_semana_comuna3),4)
mse_test_semana_comuna3 <- round(MSE(test_semana_comuna$ACCIDENTALIDAD,
                                  y_est_test_semana_comuna3),4)

Modelo_Mixto_Poisson Train_MSE Test_MSE Porcentaje_Variacion
ACCIDENTALIDAD ~ 1 + (1 | COMUNA/CLASE) 16.7066 15.1418 4.91
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | COMUNA/CLASE) 15.0649 13.2131 6.55
ACCIDENTALIDAD ~ DIA_FESTIVO + TIEMPO_SEMANA + (1 | COMUNA/CLASE) 14.9353 13.7151 4.26
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 + DIA_FESTIVO | COMUNA/CLASE) 14.9111 13.1024 6.46

En el modelo mod_semana_comuna3 se descarta usar la variable TIEMPO_SEMANA debido a que en lugar en disminuir el Test_MSE, lo aumentó, y tampoco mejoró el Train_MSE significativamente, por lo que se considera que no es significativa para explicar la accidentalidad en las comunas de Medellín por tipo de accidente.

Finalmente se observa que el modelo con intercepto y pendiente aleatoria mod_semana_comuna3:

\[\widehat{\text{ACCIDENTALIDAD}} = \text{DIA_FESTIVO} + (1 + \text{DIA_FESTIVO} | \text{COMUNA/CLASE})\]

Es el que obtiene el menor Train_MSE y Test_MSE, por lo que se escoge este modelo para la explicación de la accidentalidad en comuna por semana.

A continuación se muestran algunos de los valores observados de la accidentalidad semanal por clase y por comuna, con su respectivo valor predicho (última columna) en el conjunto de prueba.

6.2.3 Modelos - unidad de tiempo Mes

Para este modelo se agrupa la unidad de tiempo por meses, en los cuales se suma la cantidad de accidentes que suceden el el mismo, también se suma el número de días festivos que hay en dicho mes. La base luce como sigue:

accidentes_mes_comuna <- accidentes_dia_comuna %>% group_by(COMUNA, CLASE, PERIODO, MES, TIEMPO_MES) %>%
  summarise(DIA_FESTIVO = sum(DIA_FESTIVO), ACCIDENTALIDAD = sum(ACCIDENTALIDAD))

accidentes_mes_comuna

Se realiza la partición de la base de entrenamiento y de prueba

test_mes_comuna <- accidentes_mes_comuna[accidentes_mes_comuna$PERIODO == 2018, ]
train_mes_comuna <- accidentes_mes_comuna[accidentes_mes_comuna$PERIODO %in%
                                            c(2014, 2015, 2016, 2017), ]

Ahora se ajustan los modelos mixtos con efectos aleatorios en COMUNA y CLASE al igual que se hizo a nivel diario y semanal, es decir, CLASE dentro de COMUNA.

mod_mes_comuna0 <- glmer(ACCIDENTALIDAD ~  1 + (1 | COMUNA/CLASE),
               data = train_mes_comuna, family= poisson())
mod_mes_comuna1 <- glmer(ACCIDENTALIDAD ~  DIA_FESTIVO + (1 | COMUNA/CLASE),
               data = train_mes_comuna, family= poisson())
mod_mes_comuna2 <- glmer(ACCIDENTALIDAD ~  DIA_FESTIVO + (1 + DIA_FESTIVO | COMUNA/CLASE),
               data = train_mes_comuna, family= poisson())

Análisis de varianza ANOVA

anova(mod_mes_comuna0, mod_mes_comuna1, mod_mes_comuna2)

Se observa que el modelo mod_mes_comuna2, el cual tiene intercepto y pendiente aleatoria con la característica DIA_FESTIVO no aporta significativamente a la explicación de la accidentalidad según el análisis de varianza ANOVA. Sin embargo, se procede a calcular los MSE de entrenamiento y de prueba.

# Modelo 0
y_est_train_mes_comuna0 <- round(predict(mod_mes_comuna0, newdata = train_mes_comuna,
                                         type = "response"),0)
y_est_test_mes_comuna0 <- round(predict(mod_mes_comuna0, newdata = test_mes_comuna,
                                        type = "response"),0)
mse_train_mes_comuna0 <- round(MSE(train_mes_comuna$ACCIDENTALIDAD,
                                   y_est_train_mes_comuna0),4)
mse_test_mes_comuna0 <- round(MSE(test_mes_comuna$ACCIDENTALIDAD,
                                 y_est_test_mes_comuna0),4)

# Modelo 1
y_est_train_mes_comuna1 <- round(predict(mod_mes_comuna1, newdata = train_mes_comuna,
                                         type = "response"),0)
y_est_test_mes_comuna1 <- round(predict(mod_mes_comuna1, newdata = test_mes_comuna,
                                        type = "response"),0)
mse_train_mes_comuna1 <- round(MSE(train_mes_comuna$ACCIDENTALIDAD,
                                   y_est_train_mes_comuna1),4)
mse_test_mes_comuna1 <- round(MSE(test_mes_comuna$ACCIDENTALIDAD,
                                  y_est_test_mes_comuna1),4)

# Modelo 2
y_est_train_mes_comuna2 <- round(predict(mod_mes_comuna2, newdata = train_mes_comuna,
                                         type = "response"),0)
y_est_test_mes_comuna2 <- round(predict(mod_mes_comuna2, newdata = test_mes_comuna,
                                        type = "response"),0)
mse_train_mes_comuna2 <- round(MSE(train_mes_comuna$ACCIDENTALIDAD,
                                   y_est_train_mes_comuna2),4)
mse_test_mes_comuna2 <- round(MSE(test_mes_comuna$ACCIDENTALIDAD,
                                  y_est_test_mes_comuna2),4)

Modelo_Mixto_Poisson Train_MSE Test_MSE Porcentaje_Variacion
ACCIDENTALIDAD ~ 1 + (1 | COMUNA/CLASE) 88.9306 94.6510 3.12
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | COMUNA/CLASE) 87.6868 91.3359 2.04
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 + DIA_FESTIVO | COMUNA/CLASE) 87.6793 91.0191 1.87

Aunque el modelo mod_mes_comuna2 no tiene una mejora muy significativa respecto al modelo mod_mes_comuna1, sigue siendo mejor con el críterio del Test_MSE, por lo que el modelo elegido es el modelo mod_mes_comuna2

\[\widehat{\text{ACCIDENTALIDAD}} = \text{DIA_FESTIVO} + (1 + \text{DIA_FESTIVO} | \text{COMUNA/CLASE})\] A continuación se enseña la comparación entre la accidentalidad observada y la accidentalidad predicha mensualmente para la base de prueba (columna final).

data.frame(test_mes_comuna, A.PREDICHA = y_est_test_mes_comuna2)

6.3 Modelos predictivos para los Barrios

La base de datos para realizar el ajuste de los barrios se obtuvo igual a como se realizó para las comunas, es decir, con un expand.grid pero esta vez agrupando la base de datos por barrios.

Realizando el mismo método visto anteriormente para la selección de modelos en las comunas, se encuentran los siguiente modelos para los barrios.

6.3.1 Modelo - unidad de tiempo Día

Base de datos agrupada para la accidentalidad (número de accidentes) diaria.

accidentes_dia_barrio # Base de datos diaria

Conjunto de prueba y conjunto de validación:

test_dia_barrio <- accidentes_dia_barrio[accidentes_dia_barrio$PERIODO == 2018, ]
train_dia_barrio <- accidentes_dia_barrio[accidentes_dia_barrio$PERIODO %in%
                                            c(2014, 2015, 2016, 2017), ]

Se encontró que el modelo que mejor explica esta accidentalidad es:

mod_dia_barrio <- glmer(ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | BARRIO/CLASE),
               data = train_dia_barrio, family= poisson())

Con los siguientes Train_MSE y Test_MSE

y_est_train_dia_barrio <- round(predict(mod_dia_barrio, newdata = train_dia_barrio,
                                         type = "response"),0)
y_est_test_dia_barrio <- round(predict(mod_dia_barrio, newdata = test_dia_barrio,
                                        type = "response"),0)
mse_train_dia_barrio <- round(MSE(train_dia_barrio$ACCIDENTALIDAD,
                                   y_est_train_dia_barrio),4)
mse_test_dia_barrio <- round(MSE(test_dia_barrio$ACCIDENTALIDAD,
                                 y_est_test_dia_barrio),4)

Modelo_Mixto_Poisson Train_MSE Test_MSE Porcentaje_Variacion
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | BARRIO/CLASE) 0.0855 0.0825 1.79

Modelo:

\[\widehat{\text{ACCIDENTALIDAD}} = \text{DIA_FESTIVO} + (1 ~|~ \text{COMUNA/CLASE})\]

6.3.2 Modelo - unidad de tiempo Semana

Base para el modelo semanal

accidentes_semana_barrio <- accidentes_dia_barrio %>% group_by(BARRIO, CLASE, PERIODO, SEMANA, TIEMPO_SEMANA) %>%
  summarise(DIA_FESTIVO = sum(DIA_FESTIVO), ACCIDENTALIDAD = sum(ACCIDENTALIDAD))

accidentes_semana_barrio # Base de datos semanaria

Conjunto de prueba y conjunto de validación:

test_semana_barrio <- accidentes_semana_barrio[accidentes_semana_barrio$PERIODO == 2018, ]
train_semana_barrio <- accidentes_semana_barrio[accidentes_semana_barrio$PERIODO %in% c(2014, 2015, 2016, 2017), ]

Se encontró que el modelo que mejor explica esta accidentalidad es:

mod_semana_barrio <- glmer(ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | BARRIO/CLASE),
               data = train_semana_barrio, family= poisson())

y_est_train_semana_barrio <- round(predict(mod_semana_barrio, newdata = train_semana_barrio,
                                         type = "response"),0)
y_est_test_semana_barrio <- round(predict(mod_semana_barrio, newdata = test_semana_barrio,
                                        type = "response"),0)
mse_train_semana_barrio <- round(MSE(train_semana_barrio$ACCIDENTALIDAD,
                                   y_est_train_semana_barrio),4)
mse_test_semana_barrio <- round(MSE(test_semana_barrio$ACCIDENTALIDAD,
                                 y_est_test_semana_barrio),4)

Modelo_Mixto_Poisson Train_MSE Test_MSE Porcentaje_Variacion
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | BARRIO/CLASE) 0.5967 0.6149 1.5

Modelo:

\[\widehat{\text{ACCIDENTALIDAD}} = \text{DIA_FESTIVO} + (1 ~|~ \text{COMUNA/CLASE})\]

6.3.3 Modelo - unidad de tiempo Mes

Base para el modelo mensual

accidentes_mes_barrio <- accidentes_dia_barrio %>% group_by(BARRIO, CLASE, PERIODO, MES, TIEMPO_MES) %>%
  summarise(DIA_FESTIVO = sum(DIA_FESTIVO), ACCIDENTALIDAD = sum(ACCIDENTALIDAD))

accidentes_mes_barrio # Base de datos mes

Conjunto de prueba y conjunto de validación:

test_mes_barrio <- accidentes_mes_barrio[accidentes_mes_barrio$PERIODO == 2018, ]
train_mes_barrio <- accidentes_mes_barrio[accidentes_mes_barrio$PERIODO %in% c(2014, 2015, 2016, 2017), ]

Se encontró que el modelo que mejor explica esta accidentalidad es:

mod_mes_barrio <- glmer(ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | BARRIO/CLASE),
               data = train_mes_barrio, family= poisson())

y_est_train_mes_barrio <- round(predict(mod_mes_barrio, newdata = train_mes_barrio,
                                         type = "response"),0)
y_est_test_mes_barrio <- round(predict(mod_mes_barrio, newdata = test_mes_barrio,
                                        type = "response"),0)
mse_train_mes_barrio <- round(MSE(train_mes_barrio$ACCIDENTALIDAD,
                                   y_est_train_mes_barrio),4)
mse_test_mes_barrio <- round(MSE(test_mes_barrio$ACCIDENTALIDAD,
                                 y_est_test_mes_barrio),4)

Modelo_Mixto_Poisson Train_MSE Test_MSE Porcentaje_Variacion
ACCIDENTALIDAD ~ DIA_FESTIVO + (1 | BARRIO/CLASE) 2.8034 3.6059 12.52

Modelo:

\[\widehat{\text{ACCIDENTALIDAD}} = \text{DIA_FESTIVO} + (1 ~|~ \text{COMUNA/CLASE})\]

A continuación se enseña la comparación entre la accidentalidad observada y la accidentalidad predicha mensualmente para la base de prueba (columna final).

data.frame(test_mes_barrio, A.PREDICHA = y_est_test_mes_barrio)

remove(mod_dia_barrio)

7 Clustering

Según lo descrito en la introducción, es necesario centrarse en los métodos preventivos más que en las sanciones, debido a que, si la población conoce sus cifras y logra entender qué es lo que esta pasando dentro de la ciudad, se logrará no sólo reducir los incidentes de tránsito, sino también crear conciencia en las generaciones futuras.

Asimismo, para reducir los accidentes de transito en la ciudad es necesario comprender qué esta sucediendo a profundidad dentro de ella, y, gracias al acceso a las bases de datos anuales de Geomedellin, es posible clasificar las zonas donde más ocurren, para que estas sean intervenidas de una forma más rigurosa. En esta sección del proyecto fue necesario plantearnos la siguiente pregunta: ¿Cómo podríamos clasificar los barrios de Medellín de acuerdo a su accidentalidad?.

Considerando las caracteristicas de Medellín y del valle de Aburrá en general, pueden existir muchos factores que catalogan un barrio, en cuanto a seguridad vial, como peligroso o seguro. Día a día en la ciudad transitan todo tipo de vehículos, que dadas las condiciones de la zona, las calles angostas en algunos sectores, las vías en estado de deterioro y la imprudencia de la gente, hacen que sea muy complicado ir de un lugar a otro sin tener algún tipo de altercado en algún momento de la vida de una persona. Por este motivo, el criterio escogido para clasificar un barrio en vista de su accidentalidad, con los datos brindados de geomedellin, fue la gravedad del accidente. Adicionalmente, al ser solo 3 tipos de gravedad es facil de representar el análisis de forma más gráfica.

En primer lugar, la gravedad del accidente habla mucho de las condiciones en las que se dio el mismo, ya que muchas veces un mayor daño es causado por un mayor grado de irresponsabilidad. En consecuencia, es posible inferir que los barrios en los que se muestran los peores accidentes tengan la mayor cantidad de estos en general (aplica para el caso contrario). De manera anólaga, en el caso de que lo anterior no se cumpla, con este dato por lo menos se podrá identificar los barrios con los accidentes más graves, que del mismo modo, servirá para prevenir a la ciudadanía y tratar de identificar de manera profunda lo que está pasando en el lugar. Al fin y al cabo reducir los daños materiales es importante, pero reducir la cantidad de muertos en Medellín debe ser la prioridad.

En cuanto al clustering desarrollado para la clasificación de los barrios, se utilizó el método de K-Means. Aquí, se tomó la decisión de basarnos en la columna de la gravedad, ya que, no solo mostraría los barrios con más accidentalidad, sino el peligro que estos representan en cuanto a seguridad vial.

Primero, fue necesario extraer las columnas BARRIO y GRAVEDAD de la base de datos, para así solo centrarnos en lo importante durante el proceso.

Posteriormente, fue necesario hacer 2 pasos: primero se crearon 3 columnas correspondientes a los tipos de gravedad, asignando un valor de uno en la fila correspondiente al mismo tipo y un valor de cero para las demás; despues, fue necesario agrupar las columnas por barrio, para obtener la suma total de accidentes por barrio, dando como resultado la tabla que se enseña a continuación

Más adelante y ahora con sólo los datos necesarios, se realizó el método del codo para encontrar el número de clusters, al mismo tiempos que se escogía la mejor división utilizando el método k-means++ que posee python. Todo esto arrojó que lo mejor sería dividir los datos en 4 clusters.

Al realizar la respectiva clasificación se arrojó la siguiente gráfica, donde se puede observar la distribución de los barrios y permite aceptar la siguiente premisa: los 3 tipos de gravedad se relacionan entre sí, evidenciandose que a mayor numero de heridos, también hay mayor número de solo daños y muertos en promedio. En ese orden de ideas, se muestra otra información importante: Unos cúantos barrios son los que presentan la mayor concentración de accidentes, con una frecuencia mayor con respecto a los más seguros.

Teniendo en cuenta lo anterior, se analizó la media de accidentes por cluster, lo que arrojó una diferencia significativa entre ellos a la hora de analizar los heridos, muertos y daños ocasionados. El heatmap que se encuentra a continuación describe lo visto en las gráficas anteriores de una manera mas precisa. Por lo tanto, los números muestran una diferencia mucho mayor cuando se comparan los 2 grupos más seguros con los 2 más peligrosos, donde visualmente se puede notar al igual que en los gráficos anteriores. De ahí que, es importnte resaltar que en las 3 componentes, el promedio del cluster con más accidentes es mayor a la suma de los otros 3

Estos datos se muestran en la aplicación de shiny, en la parte de abajo de la sección de agrupamiento.

Al contar el número de barrios, encontramos otro dato muy interesante: Además de que el número de barrios cambia mucho de un cluster a otro, el cluster que tiene una mayor accidentalidad, que en promedio equivale a casi la mitad de todos los accidentes, solo se compone de 9 barrios.

Al tener esta información y con el fin de reducir considerablemente estos incidentes viales en Medellín, es necesario prevenir a los cuidadanos de los siguientes barrios, a su vez la alcaldía plantea posibles soluciones en la movilidad de estos:

Teniendo en cuenta la información anterior y teniendolos de manera gráfica en el mapa, la mayoría de los problemas de movilidad de la ciudad, como era de esperarse, ocurren en zonas centrales, especificamente en barrios como Caribe y La Candelaria.

Al igual que la información del heatmap, estos datos se muestran en la aplicación de shiny, debajo de la sección de agrupamiento.

Para finalizar esta sección, se agregó la tabla que clasifica el riesgo del barrio en la base de datos pricipal, para proximamente mostrar esta distribución en el mapa de Medellín asignando colores a los clusters. La columna quedó con el nombre SEGURIDAD_BARRIO.

8 Conclusiones

El modelo mixto o modelo jerárquico demuestra ser una buena alternativa para predecir la accidentalidad en las comuna y barrios de Medellín en las diferentes unidades de tiempo planteadas en este trabajo (día, semana, mes), ya que presenta un Train_MSE y un Test_MSE relativamente pequeño.

Al incluir todos los casos posibles en la construcción de los modelos, es decir, incluso los eventos donde no ocurren accidentes, los modelos mixtos se hacen muy pesados computacionalmente, y las bases de datos consideras crecen en observaciones significativamente, por lo que se recomienda crear una alternativa de optimización para el uso de los mismos.

El clustering realizado para el agrupamiento de mapas y el criterio elegido para agruparlos (número de accidentes) demuestran ser bien elegidos debido a que la forma en que se agrupan los datos tiene sentido con la realidad de la ciudad (La Candelaria y Laureles son barrios con mucho flujo vehícular y se encuentran en zonas donde hay mucha afluencia de personas de todo el Valle de Aburrá)

En los meses de agosto se puede observar que la accidentalidad es mucho mas alta que en los demás meses, algo a destacar es que el mes de agosto en los años analizados se festejaba la feria de flores, esto lleva a que la cantidad de personas en la ciudad de Medellín sea mas alta y por ende mas probabilidad de accidentes abra, ya que la ciudad estará mas congestionada, en cambio que en los meses de diciembre y enero la ciudad esta un poco mas descongestionada esto causa una posible disminución en la accidentalidad de Medellín.

9 Recomendaciones

Crear un plan de acción inmediato en los 9 barrios que se encuentran con la categoría de “Accidentalidad alta” ya que presentan índices muy altos que pueden tener como consecuencia un incremento en la accidentalidad y muertes en las vías.

Invertir en una campaña de conciencia y responsabilidad automovilista en el centro ya que en este lugar es donde mas se presentan accidentes en Medellín.

Cuando hay eventos como la feria de flores tener planes de movilidad mas estrictas esto con el fin de disminuir la alta accidentalidad en esa festividad.

10 Referencias

Andrew Gelman, Jennifer Hill (2007). Data Analysis Using Regression and Multilevel/Hierarchical Models.

Douglas Bates, Martin Maechler, Ben Bolker, Steve Walker (2015). Fitting Linear Mixed-Effects Models Using lme4. Journal of Statistical Software, 67(1), 1-48. doi:10.18637/jss.v067.i01.

Wickham et al., (2019). Welcome to the tidyverse. Journal of Open Source Software, 4(43), 1686, https://doi.org/10.21105/joss.01686

Achim Zeileis and Gabor Grothendieck (2005). zoo: S3 Infrastructure for Regular and Irregular Time Series. Journal of Statistical Software, 14(6), 1-27. doi:10.18637/jss.v014.i06

C. Sievert. Interactive Web-Based Data Visualization with R, plotly, and shiny. Chapman and Hall/CRC Florida, 2020.

Rstudio.github.io. 2020. Leaflet For R - Introduction. [online] Available at: https://rstudio.github.io/leaflet/ [Accessed 20 November 2020].

Tiempo, C., 2020. Estos Son Los 5 Puntos Con Más Accidentes De Tránsito En Medellín. [online] El Tiempo. Available at: https://www.eltiempo.com/colombia/medellin/estos-son-los-5-untos-con-mas-accidentes-de-transito-en-medellin-229534 [Accessed 20 November 2020].

Ctumedellin.com. 2020. Medellín, Una De Las Ciudades Más Letales Para Manejar – CTU COLOMBIA. [online] Available at: http://ctumedellin.com/sitio/2018/01/16/medellin-una-de-las-ciudades-mas-letales-para-manejar/ [Accessed 20 November 2020].

LA.Network. 2020. Estas Son Las 10 Ciudades Latinoamericanas Con Más Muertes En Las Vías. [online] Available at: https://la.network/ciudades-latinoamericanas-muertes-vias/ [Accessed 20 November 2020].

LS0tDQp0aXRsZTogIlRBRSAtIEFjY2lkZW50YWxpZGFkIGVuIE1lZGVsbMOtbiAtIFJlcG9ydGUgVMOpY25pY28iDQphdXRob3I6ICJKYWltZSBBbmRyZXMgTW9saW5hIENvcnJlYSA8YnI+IFZhbGVudGluYSBHYXJjw61hIFZlbGFzcXVleiA8YnI+IEZlbGlwZSBWaWxsYXJyZWFsIFBpZWRyYWhpdGEgPGJyPiBSaWNhcmRvIFBlbmFsb3phIFZlbGFzcXVleiA8YnI+IERhbmllbCBDaGFuY2kgUmVzdHJlcG8iDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGNvc21vDQogICAgaGlnaGxpZ2h0OiBrYXRlDQogICAgY3NzOiBmb3JtYXQuY3NzDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdG9jOiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogVFJVRQ0KLS0tDQoNCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQ0KZGVmLmNodW5rLmhvb2sgIDwtIGtuaXRyOjprbml0X2hvb2tzJGdldCgiY2h1bmsiKQ0Ka25pdHI6OmtuaXRfaG9va3Mkc2V0KGNodW5rID0gZnVuY3Rpb24oeCwgb3B0aW9ucykgew0KICB4IDwtIGRlZi5jaHVuay5ob29rKHgsIG9wdGlvbnMpDQogIGlmZWxzZShvcHRpb25zJHNpemUgIT0gIm5vcm1hbHNpemUiLCBwYXN0ZTAoIlxuIFxcIiwgb3B0aW9ucyRzaXplLCJcblxuIiwgeCwgIlxuXG4gXFxub3JtYWxzaXplIiksIHgpDQp9KQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcuYWxpZ24gPSAnY2VudGVyJywgc2l6ZT0iZm9vdG5vdGVzaXplIiwNCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRiwgd2FybmluZyA9IEYpDQpgYGANCg0KDQojIEludHJvZHVjY2nDs24NCg0KTG9zIGFjY2lkZW50ZXMgdmlhbGVzIHNvbiB1bmEgcHJvYmxlbcOhdGljYSBxdWUgaGEgYWZlY3RhZG8gZGUgZ3JhbiBtYW5lcmEgYSAgbGEgY2l1ZGFkIGRlIE1lZGVsbMOtbi4gRWwgY3JlY2ltaWVudG8gZWNvbsOzbWljbyBkZSBsYSBjaXVkYWQgeSBsYSByw6FwaWRhIHVyYmFuaXphY2nDs24gY2F1c2FuIHVuIGdyYW4gYXVtZW50byBlbiBlbCBwYXJxdWUgYXV0b21vdG9yLCBsYSBkZW5zaWRhZCB2ZWjDrWN1bGFyIHkgbGFzIGRpZmljdWx0YWRlcyBkZSB0cmFuc2l0YXIgZW4gbGFzIHbDrWFzIHF1ZSBjb25mb3JtYW4gbGEgY2l1ZGFkLiBFbiBlc3RlIHRyYWJham8gc2UgcGxhbnRlYSBjcmVhciB1biBzaXN0ZW1hIHF1ZSBwdWVkYSBheXVkYXIgYSBtaXRpZ2FyIGxvcyBhY2NpZGVudGVzIGVuIGxhcyB2w61hcywgYWRlbcOhcyBkZSBzZXJ2aXIgY29tbyBndcOtYSBwYXJhIHRvbWFyIG1lZGlkYXMgZnJlbnRlIGEgbGEgc2l0dWFjacOzbiBhY3R1YWwuDQoNCkR1cmFudGUgZWwgcGVyaW9kbyBlbnRyZSAyMDE0IHkgMjAxOCBzZSBsb2dyw7MgdG9tYXIgdW5hIGNhbnRpZGFkIHNpZ25pZmljYXRpdmEgZGUgZGF0b3Mgc29icmUgbGEgYWNjaWRlbnRhbGlkYWQgZW4gTWVkZWxsw61uIHkgYWxndW5hcyBkZSBzdXMgem9uYXMgYWxlZGHDsWFzLCBwYXJhIGV2aWRlbmNpYXIgYXPDrSwgZWwgcHJvYmxlbWEgZGUgbW92aWxpZGFkIHF1ZSBwcmVzZW50YSBlbCDDoXJlYS4gRXN0b3MgZGF0b3Mgc2UgZW5jdWVudHJhbiBlbiBlbCBwb3J0YWwgW0dlb01lZGVsbMOtbl0oaHR0cHM6Ly93d3cubWVkZWxsaW4uZ292LmNvL2dlb21lZGVsbGluLyksIGRvbmRlIGNhZGEgdW5vIGRlIGVzdG9zIGluY2lkZW50ZXMgc2UgZW5jdWVudHJhIGdlb3JyZWZlcmVuY2lhZG8sIGRpdmlkaWRvIHBvciBiYXJyaW8geSBjb211bmEuIEN1ZW50YSwgYWRlbcOhcywgY29uIGxhIGluZm9ybWFjacOzbiBzb2JyZSBsYSB2w61hIGRvbmRlIGVsIGFjY2lkZW50ZSBvY3VycmnDsyB5IHRhbWJpw6luIHNvYnJlIGVsIHRpcG8gZGUgYWNjaWRlbnRlIHF1ZSBzZSBkaW8sIGxhIGZlY2hhIGRlIMOpc3RlIGUgaW5jbHVzbyBsb3MgZGHDsW9zIHBlcmp1ZGljaWFsZXMgY2F1c2Fkb3MgYSBsb3MgY2l1ZGFkYW5vcyAtbXVlcnRvcywgaGVyaWRvcyBvIHNvbG8gZGHDsW9zIG1hdGVyaWFsZXMtLg0KDQpBaG9yYSBiaWVuLCBhbCB0ZW5lciBtw6FzIGRlIDIwMC4wMDAgZGF0b3MgZHVyYW50ZSBlc3RlIGludGVydmFsbywgZWwgZXF1aXBvIHNlIHBsYW50ZcOzIGVsIG9iamV0aXZvIGRlIGRhcmxlIHVuIGJ1ZW4gdXNvIGEgZXN0b3MsIG5vIHPDs2xvIHBhcmEgYW5hbGl6YXIgbG8gcXVlIHN1Y2VkacOzIGVuIGVzdGUgbGFwc28sIHNpbm8gdGFtYmnDqW4gcGFyYSBheXVkYXIgYSBwcmVkZWNpciBhY2NpZGVudGVzIGEgZnV0dXJvIHkgYXPDrSBwb2RlciBlc2dyaW1pciB1biBtb2RlbG8gcHJldmVuY2lvbmlzdGEuIEVuIGVzZSBvcmRlbiBkZSBpZGVhcywgcGFyYSBhY2NlZGVyIGEgbGEgaW5mb3JtYWNpw7NuIHJlY29sZWN0YWRhIHkgYWwgcHJlc2VudGUgYW7DoWxpc2lzIHNlIGhhYmlsaXRhcsOhIHVuIGVubGFjZSBhIGFwbGljYWNpw7NuIFtUcmFuc2l0QXBwXShodHRwczovL3ZhbGVudGluYS1nYXJjaWEtdmVsYXNxdWV6LnNoaW55YXBwcy5pby9UcmFuc2l0QVBQXzIwMjAvKSwgZG9uZGUgbGEgaW5mb3JtYWNpw7NuIGEgbGEgcXVlIHNlIGFjY2VkZSBlc3RhcsOhIHByZXNlbnRhZGEgZGUgdW5hIGZvcm1hIGludGVyYWN0aXZhIGUgaW50dWl0aXZhLCBwYXJhIG9idGVuZXIgdW4gbWVqb3IgZW50ZW5kaW1pZW50byBkZWwgdXN1YXJpby4NCg0KRW4gZWwgcHJlc2VudGUgcmVwb3J0ZSBzZSBlbmN1ZW50cmEgaW5mb3JtYWNpw7NuIGRldGFsbGFkYSByZXNwZWN0byBhIGxhIGRlcHVyYWNpw7NuLCBpbXB1dGFjacOzbiwgYW7DoWxpc2lzIGRlc2NyaXB0aXZvLCBjcmVhY2nDs24gZGUgY2x1c3RlcnMgeSBtb2RlbG9zIHByZWRpY3Rpdm9zIHJlYWxpemFkb3MgcGFyYSBjcmVhciBsYSBhcGxpY2FjacOzbiBbVHJhbnNpdEFwcF0oaHR0cHM6Ly92YWxlbnRpbmEtZ2FyY2lhLXZlbGFzcXVlei5zaGlueWFwcHMuaW8vVHJhbnNpdEFQUF8yMDIwLykuIFNlIHZlcsOhIHF1ZSBsb3MgbW9kZWxvcyBtaXh0b3MgKG1vZGVsb3MgamVyw6FycXVpY29zKSBwcmVzZW50YW4gdW5hIGJ1ZW5hIGVzdGltYWNpw7NuIGRlIGxhIGFjY2lkZW50YWxpZGFkIChuw7ptZXJvIGRlIGFjY2lkZW50ZXMpIGVuIGxhIGNpdWRhZCBkZSBNZWRlbGzDrW4uDQoNCkVubGFjZSBhcGxpY2F0aXZvIFRyYW5zaXRBcHA6IGh0dHBzOi8vdmFsZW50aW5hLWdhcmNpYS12ZWxhc3F1ZXouc2hpbnlhcHBzLmlvL1RyYW5zaXRBUFBfMjAyMC8NCg0KRW5sYWNlIHJlcG9zaXRvcmlvIEdpdEh1YjogaHR0cHM6Ly9naXRodWIuY29tL3ZhZ2FyY2lhdmUvVHJhbnNpdEFwcF8xLjAvDQoNCiMgSnVzdGlmaWNhY2nDs24NCg0KTGEgY2l1ZGFkIGRlIE1lZGVsbMOtbiBwcmVzZW50YSB1biDDrW5kaWNlIGRlIGFjY2lkZW50YWxpZGFkIHZpYWwgYmFzdGFudGUgYWx0byBjb21wYXJhZGEgY29uIG90cmFzIGNpdWRhZGVzIGRlIGxhIHJlZ2nDs24gZSBpbmNsdXNvIGNvbiBsYSBjYXBpdGFsIGRlbCBwYcOtcywgQm9nb3TDoS4gU2Vnw7puIGVsICJSw6Fua2luZyAoc2ljKSBMYXRpbm9hbWVyaWNhbm8gZGUgQ2l1ZGFkZXMgRmF0YWxlcyIgZGUgMjAxOCwgaW5mb3JtZSByZWFsaXphZG8gcG9yIGVsIGNlbnRybyBkZSBwZW5zYW1pZW50byAqTEEgTmV0d29yayosIE1lZGVsbMOtbiBlc3RhYmEgcmFucXVlYWRhIGVuIGVsIHB1ZXN0byAyOSBkZSBsYXMgY2l1ZGFkZXMgY29uIG3DoXMgbXVlcnRlcyBlbiBsYXMgdsOtYXMgZGUgTGF0aW5vYW3DqXJpY2EsIGNvbiAxMC45IG11ZXJ0b3MgcG9yIGNhZGEgMTAwIG1pbCBoYWJpdGFudGVzLiBBZGVtw6FzLCBkdXJhbnRlIGVsIGHDsW8gMjAxNyBodWJvIHVuIHRvdGFsIDQxLjY2NyBhY2NpZGVudGVzIHZpYWxlcyBlbiBNZWRlbGzDrW4sIGxvcyBjdWFsZXMgb2Nhc2lvbmFyb24gMjU4IG11ZXJ0ZXMuDQoNClRhbWJpw6luIGVzIG5lY2VzYXJpbyB0ZW5lciBlbiBjdWVudGEgYWwgc2lzdGVtYSBkZSBzYWx1ZCBlbiBsb3MgYWNjaWRlbnRlcyB2aWFsZXMsIGRlYmlkbyBhIHF1ZSBlc3RvcyBhZmVjdGFuIGdyYXZlbWVudGUgbGEgY2FwYWNpZGFkIGRlIGNvYmVydHVyYSBwYXJhIG90cm8gdGlwbyBkZSBlbWVyZ2VuY2lhcy4gU29sbyBlbiAyMDE3LCAxNDAwMCBkZSBsb3MgMzAwMDAgaGVyaWRvcyBlbiBsb3MgYWNjaWRlbnRlcyB2aWFsZXMgcmVxdWlyaWVyb24gYXNpc3RlbmNpYSBtw6lkaWNhLCB5IGRlIGVzdGUgZ3J1cG8sIDM4MDAgcHJlc2VudGFyb24gaGVyaWRhcyBncmF2ZXMuIEF1bnF1ZSwgZHVyYW50ZSBsb3MgYcOxb3MgMjAxOSB5IDIwMjAgc2UgaGEgbm90YWRvIHVuYSBkaXNtaW51Y2nDs24gZGUgZXN0YXMgZXN0YWTDrXN0aWNhcyBzb2JyZSBsYSBhY2NpZGVudGFsaWRhZCB2aWFsLCBzZSBwdWVkZSBldmlkZW5jaWFyIHF1ZSBleGlzdGUgbGEgbmVjZXNpZGFkIGRlIHRlbmVyIHVuIG1heW9yIGVudGVuZGltaWVudG8gZGUgbG9zIGRhdG9zLCBlc3BlY2lhbG1lbnRlIHBhcmEgbG9zIGNvbmR1Y3RvcmVzLCBtb3RvY2ljbGlzdGFzIHkgaGFzdGEgY2ljbGlzdGFzIHkgcGVhdG9uZXMuIENvbiBsYSBpbXBsZW1lbnRhY2nDs24gZGVsIHNpc3RlbWEgcGxhbnRlYWRvIGVuIGVzdGUgdHJhYmFqbywgc2UgcHJldGVuZGUgY3JlYXIgdW5hIHBvbMOtdGljYSBkZSBwcmV2ZW5jacOzbiBkZSBhY2NpZGVudGFsaWRhZCB5IGFkZW3DoXMgdW5hIGNvbmNpZW5jaWEgY2l1ZGFkYW5hIHBhcmEgbWFuZWphciBjb24gbWF5b3IgcHJlY2F1Y2nDs24gZW4gY2llcnRvcyBsdWdhcmVzIHkgcG9kZXIgcGxhbmVhciBtZWpvciBzdXMgdmlhamVzLg0KDQojIE9iamV0aXZvcw0KDQpFbCBhbsOhbGlzaXMgeSBsb3MgbW9kZWxvcyBxdWUgc2UgcHJldGVuZGVuIGNvbnN0cnVpciBzw7NsbyBhYmFyY2EgZWwgw6FyZWEgdXJiYW5hIGRlIE1lZGVsbMOtbiBjb3JyZXNwb25kaWVudGUgYSBzdXMgMTYgY29tdW5hcyB5IHN1cyByZXNwZWN0aXZvcyBiYXJyaW9zLg0KDQojIyBPYmpldGl2byBnZW5lcmFsDQoNCkNvbnN0cnVpciB1biBzaXN0ZW1hIHF1ZSBsZSBwZXJtaXRhIGEgbGEgU2VjcmV0YXLDrWEgZGUgTW92aWxpZGFkIGRlIE1lZGVsbMOtbiB0b21hciBkZWNpc2lvbmVzIGVuIGxhIGNyZWFjacOzbiBkZSBlc3RyYXRlZ2lhcyBxdWUgYXl1ZGVuIGEgcmVkdWNpciBsYSBhY2NpZGVudGFsaWRhZCBlbiB6b25hIGVzcGVjw61maWNhcyBkZSBNZWRlbGzDrW4sIG9ic2VydmFuZG8gY3VhbGVzIHNvbiBsb3MgdGlwb3MgZGUgYWNjaWRlbnRlcyBtw6FzIGZyZWN1ZW50ZXMgZW4gbGFzIGRpZmVyZW50ZXMgY29tdW5hcyB5IHN1cyBiYXJyaW9zLg0KDQpUYW1iacOpbiBzZSBidXNjYSBxdWUgZWwgc2lzdGVtYSBsZXMgcGVybWl0YSBhIHRvZG9zIGxvcyBjaXVkYWRhbm9zIHF1ZSBzZSBtb3ZpbGl6YW4gZW4gdW4gdmVow61jdWxvIHRvbWFyIHByZWNhdWNpb25lcyByZXNwZWN0byBhIGxvcyBhY2NpZGVudGVzIG3DoXMgZnJlY3VlbnRlcyBxdWUgc3VjZWRlbiBlbiBsdWdhcmVzIGVzcGVjw61maWNvcy4NCg0KTG8gYW50ZXJpb3IgY3JlYW5kbyB1bmEgaW50ZXJmYXogYW1pZ2FibGUgcGFyYSBsb3MgdXN1YXJpb3MgeSBmw6FjaWwgZGUgdXRpbGl6YXIuDQoNCiMjIE9iamV0aXZvcyBlc3BlY8OtZmljb3MNCg0KLSBDb25zdHJ1aXIgbW9kZWxvcyBxdWUgcHJlZGlnYW4gZWwgbsO6bWVybyBkZSBhY2NpZGVudGVzIGRlIGNhZGEgdGlwbywgdG9tYW5kbyBjb21vIGVudHJhZGFzIHVuYSB2ZW50YW5hIHkgdW5hIHJlc29sdWNpw7NuIHRlbXBvcmFsIGVzcGVjw61maWNhcywgYWRlbcOhcyBkZSB1bmEgem9uYSBlc3BhY2lhbCBxdWUgcHVlZGUgc2VyIHVuIGJhcnJpbyBvIGNvbXVuYSBkZSBNZWRlbGzDrW4uDQoNCi0gRWxhYm9yYXIgdW4gc2lzdGVtYSBxdWUgYWdydXBlIGJhcnJpb3MgY29uIGNhcmFjdGVyw61zdGljYXMgc2ltaWxhcmVzIHBvciBsb3MgdGlwb3MgZGUgYWNjaWRlbnRlcyAoY2xhc2UpIHkgbGEgZ3JhdmVkYWQgcXVlIHRpZW5lbiBsdWdhciBlbiBlc3Rvcy4NCg0KLSBDcmVhciB1bmEgaW50ZXJmYXogZ3LDoWZpY2EgcXVlIGxlIHBlcm1pdGEgYWwgdXN1YXJpbyB2aXN1YWxpemFyIGNvbiBtYXlvciBjb21vZGlkYWQgbGEgYWNjaWRlbnRhbGlkYWQgcXVlIGhheSBlbiBNZWRlbGzDrW4geSBsYXMgcHJlZGljY2lvbmVzIGRlIGVzdGEgYSBmdXR1cm8uDQoNCg0KDQojIERlc2NyaXBjacOzbiB5IExpbXBpZXphIGRlIGxvcyBkYXRvcw0KDQpMb3MgZGF0b3MgdXRpbGl6YWRvcyBzZSBlbmN1ZW50cmFuIGVuIGxhcyBiYXNlcyBkZSBkYXRvcyBkZSBHZW9tZWRlbGzDrW4gKFBvcnRhbCBHZW9ncsOhZmljbyBkZWwgTXVuaWNpcGlvIGRlIE1lZGVsbMOtbikgeSBjb250aWVuZW4gaW5mb3JtYWNpw7NuIHJlZmVyZW50ZSBhIG3Dumx0aXBsZXMgYWNjaWRlbnRlcyBkZSB0csOhbnNpdG8sIGVuIGxvcyBxdWUgc2UgZGV0YWxsYSBlbCB0aXBvIGRlIGFjY2lkZW50ZSwgZMOzbmRlIHkgY3XDoW5kbyBvY3VycmnDsy4gTGEgYmFzZSBkZSBkYXRvcyB1dGlsaXphZGEgZW4gZXN0ZSB0cmFiYWpvIGVzIHVuYSB1bmnDs24gZGUgbGFzIGJhc2VzIGRlIGluY2lkZW50ZXMgZW4gMjAxNCwgMjAxNSwgMjAxNiwgMjAxNyB5IDIwMTgsIHNlIHVzYXLDoSBlc3RlIMO6bHRpbW8gYcOxbyBwYXJhIHZhbGlkYXIgbG9zIG1vZGVsb3MgcGxhbnRlYWRvcy4NCg0KTGEgYmFzZSBkZSBkYXRvcyBvcmlnaW5hbCBjdWVudGEgY29uIGxhcyBzaWd1aWVudGVzIHZhcmlhYmxlczoNCg0KLSBYOiBDb21wb25lbnRlIGRlIGNvb3JkZW5hZGEuDQotIFk6IENvbXBvbmVudGUgZGUgY29vcmRlbmFkYS4NCi0gT0JKRUNUSUQ6IElkIGRlIGNhZGEgaW5jaWRlbnRlLg0KLSBSQURJQ0FETzogQ8OzZGlnbyBlbWl0aWRvIHBvciBsYSBzZWNyZXRhcsOtYSBkZSBtb3ZpbGlkYWQgZGUgTWVkZWxsw61uLg0KLSBGRUNIQTogRmVjaGEgZGVsIGluY2lkZW50ZS4NCi0gSE9SQTogSG9yYSBkZWwgaW5jaWRlbnRlLg0KLSBESUE6IETDrWEgZGVsIG1lcyBlbiBlbCBxdWUgb2N1cnJlIGVsIGluY2lkZW50ZQ0KLSBQRVJJT0RPOiBBw7FvIGRlbCBpbmNpZGVudGUuDQotIENMQVNFOiBUaXBvIGRlIGFjY2lkZW50ZQ0KLSBESVJFQ0NJT04uDQotIERJUkVDQ0lPTl9FTkMuDQotIENCTUw6IEPDs2RpZ28gZGUgdWJpY2FjacOzbiBkZWwgcHJlZGlvIGVuIGxhIGNpdWRhZC4NCi0gVElQT19HRU9DT0Q6IFRpcG8gZGUgDQotIEdSQVZFREFEOiByZXBlcmN1c2lvbmVzIGRlbCBhY2NpZGVudGUNCi0gQkFSUklPLg0KLSBDT01VTkEuDQotIERJU0VOTzogY2xhc2lmaWNhY2nDs24gZGVsIGx1Z2FyIGRlbCBhY2NpZGVudGUuDQotIERJQV9OT01CUkU6IETDrWEgZGUgbGEgc2VtYW5hIGVuIGVsIHF1ZSBvY3VycmUgZWwgaW5jaWRlbnRlDQotIE1FUzogTWVzIGRlbCBpbmNpZGVudGUgZW4gbsO6bWVybyAoZGVsIDEgYWwgMTIpDQotIE1FU19OT01CUkU6IE1lcyBkZWwgaW5jaWRlbnRlDQotIFhfTUFHTkFNRUQ6IENvbXBvbmVudGUgZGUgY29vcmRlbmFkYQ0KLSBZX01BR05BTUVEOiBDb21wb25lbnRlIGRlIGNvb3JkZW5hZGENCi0gTE9OR0lUVUQ6IENvbXBvbmVudGUgZGUgY29vcmRlbmFkYQ0KLSBMQVRJVFVEOiBDb21wb25lbnRlIGRlIGNvb3JkZW5hZGENCg0KDQpTZSBkZWNpZGVuIGVsaW1pbmFyIGxhcyB2YXJpYWJsZXMgIlgiLCAiWSIsICJYX01BR05BTUVEIiB5ICJZX01BR05BTUVEIiB5YSBxdWUgY3VtcGxlbiBsYSBtaXNtYSBmdW5jacOzbiBxdWUgbGFzIHZhcmlhYmxlcyAiTE9OR0lUVUQiIHkgIkxBVElUVUQiLiBUYW1iacOpbiBzZSBlbGltaW5hIGxhIHZhcmlhYmxlICJSQURJQ0FETyIgeWEgcXVlIHNpcnZlIHBhcmEgaWRlbnRpZmljYXIgYSB1biByZXNwZWN0aXZvIGluY2lkZW50ZSwgYWwgaWd1YWwgcXVlIGxhIHZhcmlhYmxlICJPQkpFQ1RJRCIuIFNlIGVsaW1pbmEgbGEgdmFyaWFibGUgIk1FU19OT01CUkUiIHlhIHF1ZSBlcyByZWR1bmRhbnRlIGVsIGxhIGJhc2UgZGUgZGF0b3MsIGRlYmlkbyBhIHF1ZSBzZSBlbmN1ZW50cmEgbGEgbWlzbWEgaW5mb3JtYWNpw7NuIGVuIGxhIHZhcmlhYmxlICJNRVMiLiBBZGVtw6FzIHBvbmVybGUgbG9zIG5vbWJyZXMgYSBwYXJ0aXIgZGUgbGEgdmFyaWFibGUgIk1FUyIgdHJhZXLDrWEgdW4gYXVtZW50byBhbCBjb3N0ZSBjb21wdXRhY2lvbmFsIGlubmVjZXNhcmlvLiBUYW1iacOpbiBzZSBkZWNpZGUgZWxpbWluYXIgbGFzIHZhcmlhYmxlcyAiRElSRUNDSU9OIiwgIkRJUkVDQ0lPTl9FTkMiLCAiQ0JNTCIsICJUSVBPX0dFT0NPRCIgeSAiSE9SQSIgeWEgbm8gc2Vyw6FuIGRlIHV0aWxpZGFkIGVuIGVsIG1vZGVsby4NCg0KQWRlbcOhcyBzZSBjcmVhIG90cmEgdmFyaWFibGUgbGxhbWFkYSAiRElBX0ZFU1RJVk8iLiBQYXJhIHBvZGVyIGFuYWxpemFyIGVsIG7Dum1lcm8gZGUgYWNjaWRlbnRlcyBlbiBsb3MgZMOtYXMgZmVzdGl2b3MgeSBkZW3DoXMgZmVjaGFzIGVzcGVjaWFsZXMuIFBvciBsbyB0YW50bywgbGFzIHZhcmlhYmxlcyBkZSBpbnRlcsOpcyBxdWUgc2UgdXNhbiBlbiBlc3RlIHByb3llY3RvIHNvbiBsYXMgc2lndWllbnRlczoNCg0KLSBPQkpFQ1RJRDogSWQgZGUgY2FkYSBpbmNpZGVudGUuDQotIENMQVNFOiBUaXBvIGRlIGFjY2lkZW50ZQ0KLSBHUkFWRURBRDogcmVwZXJjdXNpb25lcyBkZWwgYWNjaWRlbnRlDQotIENPTVVOQS4NCi0gQkFSUklPLg0KLSBESVNFTk86IGNsYXNpZmljYWNpw7NuIGRlbCBsdWdhciBkZWwgYWNjaWRlbnRlLg0KLSBMQVRJVFVEOiBDb21wb25lbnRlIGRlIGNvb3JkZW5hZGENCi0gTE9OR0lUVUQ6IENvbXBvbmVudGUgZGUgY29vcmRlbmFkYQ0KLSBGRUNIQTogRmVjaGEgZGVsIGluY2lkZW50ZS4NCi0gRElBOiBEw61hIGRlbCBtZXMgZW4gZWwgcXVlIG9jdXJyZSBlbCBpbmNpZGVudGUNCi0gTUVTOiBNZXMgZGVsIGluY2lkZW50ZSBlbiBuw7ptZXJvIChkZWwgMSBhbCAxMikNCi0gUEVSSU9ETzogQcOxbyBkZWwgaW5jaWRlbnRlLg0KLSBESUFfTk9NQlJFOiBEw61hIGRlIGxhIHNlbWFuYSBlbiBlbCBxdWUgb2N1cnJlIGVsIGluY2lkZW50ZQ0KLSBESUFfRkVTVElWTy4NCg0KRGVmaW5pZG8gbG8gYW50ZXJpb3IsIHNlIHJlYWxpemEgdW5hIGxpbXBpZXphIGVuIGxhIGJhc2UgZGUgZGF0b3MsIHlhIHF1ZSBoYXkgcmVnaXN0cm9zIHUgb2JzZXJ2YWNpb25lcyBxdWUgZXN0w6FuIG1hbCBlc2NyaXRvcyBvIHNpbXBsZW1lbnRlIG5vIGRlYmVyw61hbiBlc3Rhci4gQSBjb250aW51YWNpw7NuIHNlIGV4cGxpY2FuIGxvcyBjYW1iaW9zIHJlYWxpemFkb3MuDQoNCiMjIERlcHVyYWNpw7NuDQoNClNlIGRlY2lkZSBxdWl0YXIgbG9zIGFjZW50b3MgYSBjYWRhIHVuYSBkZSBsYXMgdmFyaWFibGVzIGNhdGVnw7NyaWNhcyBkZWJpZG8gYSBxdWUgaGF5IHZhbG9yZXMgcmVwZXRpZG9zIGxvcyBjdWFsZXMgcmVwcmVzZW50YW4gZWwgbWlzbW8gbml2ZWwgbyBjYXRlZ29yaWEsIHBlcm8gY29uIGFjZW50byB5IHNpbiBhY2VudG8uIFVuIGVqZW1wbG8gZGUgZXN0byBlcyBlbCBiYXJyaW8gQmVybHDDrW4gZGUgbGEgY29tdW5hIEFyYW5qdWV6LCBlbCBjdWFsIGFwYXJlY2UgNjQ3IHZlY2VzIGNvbiBlbCBub21icmUgZGUgIkJlcmzDrW4iIHkgMTUgdmVjZXMgY29uIGVsIG5vbWJyZSBkZSAiQmVybMOtbiIuIFBvciBsbyB0YW50byBzZSBkZWNpZGUgYXJyZWdsYXIgZXN0ZSBwcm9ibGVtYS4NCg0KIyMjIFBhcmEgQ09NVU5BDQoNCkxhIHZhcmlhYmxlIENPTVVOQSBkZWJlIHRlbmVyIGxhcyBjb211bmFzIHVyYmFuYXMgZGUgTWVkZWxsw61uIHkgc3VzIGNvcnJlZ2ltaWVudG9zLg0KDQpTZSBzYWJlIHF1ZSBlbiBNZWRlbGzDrW4gaGF5IDE2IGNvbXVuYXMgdXJiYW5hcyB5IDUgY29ycmVnaW1pZW50b3MsIGFtYm9zIGVzdMOhbiBjb21wdWVzdG9zIHBvciBiYXJyaW9zLCBwb3IgbG8gcXVlIGxhIHZhcmlhYmxlIGRlYmVyw61hIHRlbmVyIDE2ICsgNSA9IDIxIG5pdmVsZXMuIFBlcm8gYWwgb2JzZXJ2YXIgbG9zIG5pdmVsZXMgZGUgbGEgdmFyaWFibGUgIkNPTVVOQSIgZW4gZWwgY29uanVudG8gZGUgZW50cmVuYW1pZW50bywgc2UgZXZpZGVuY2lhbiA4NCBjb211bmFzLCBwb3IgbG8gY3VhbCBzZSBkZWNpZGUgYnVzY2FyIGxhcyByYXpvbmVzIGRlIGVzdG8geSB0cmF0YXIgZGUgY29ycmVnaXJsby4NCg0KKipDb211bmFzOioqIFBvcHVsYXIsIFNhbnRhIENydXosIE1hbnJpcXVlLCBBcmFuanVleiwgQ2FzdGlsbGEsIERvY2UgZGUgT2N0dWJyZSwgUm9ibGVkbywgVmlsbGEgSGVybW9zYSwgQnVlbm9zIEFpcmVzLCBMYSBDYW5kZWxhcmlhLCBMYXVyZWxlcy1Fc3RhZGlvLCBMYSBBbcOpcmljYSwgU2FuIEphdmllciwgRWwgUG9ibGFkbywgR3VheWFiYWwsIEJlbMOpbi4NCg0KKipDb3JyZWdpbWllbnRvczoqKiBDb3JyZWdpbWllbnRvIGRlIFNhbiBDcmlzdMOzYmFsLCBDb3JyZWdpbWllbnRvIGRlIFNhbiBBbnRvbmlvIGRlIFByYWRvLCBDb3JyZWdpbWllbnRvIGRlIFNhbnRhIEVsZW5hLCBDb3JyZWdpbWllbnRvIGRlIEFsdGF2aXN0YSwgQ29ycmVnaW1pZW50byBkZSBTYW4gU2ViYXN0acOhbiBkZSBQYWxtaXRhcy4NCg0KVW5vIGRlIGxvcyBwcm9ibGVtYXMgcXVlIHNlIGVuY3VlbnRyYSBlcyBxdWUgbGEgcGVyc29uYSBlbmNhcmdhZGEgZGUgZGlnaXRhciBsb3MgZGF0b3Mgc2UgY29uZnVuZGnDsyBlbnRyZSBsYXMgdmFyaWFibGVzICJDT01VTkEiIHkgIkJBUlJJTyIuIFVuIGVqZW1wbG8gZGUgZXN0byBlcyBlbCBiYXJyaW8gQm9zdG9uIHF1ZSBhcGFyZWNlIGNvbW8gY29tdW5hIGVuIDIgb2JzZXJ2YWNpb25lcywgY29uIHN1IHJlc3BlY3RpdmEgY29tdW5hIChMYSBjYW5kZWxhcmlhKSBlbiBiYXJyaW8uIEFzw60gY29tbyBlbCBlamVtcGxvIGFudGVyaW9yLCBoYXkgdmFyaW9zIGNhc29zLiBQb3IgbG8gY3VhbCwgZXN0YXMgY29tdW5hcyB5IGJhcnJpb3Mgc2UgcG9uZW4gZW4gc3UgcG9zaWNpw7NuIGNvcnJlY3RhLg0KDQpMdWVnbyBkZSByZXNvbHZlciBlbCBwcm9ibGVtYSBhbnRlcmlvciwgc2UgZW5jdWVudHJhIHF1ZSBhw7puIGhheSBjb211bmEgcXVlIG5vIHBlcnRlbmVjZW4gYSBsYXMgMjEgbWVuY2lvbmFkYXMgYW50ZXJpb3JtZW50ZSwgZXN0YXMgc29uOiAiSW4iLCAiQVUiLCAiU04iLCAiMCIuIEFsIG5vIGVuY29udHJhciBpbmZvcm1hY2nDs24gZGUgZXN0b3MgdmFsb3JlcyBlbiBsYSBww6FnaW5hIG9maWNpYWwgbyBlbiBpbnRlcm5ldCwgc2UgZGVjaWRlIHJlZW1wbGF6YXIgZXN0b3MgdmFsb3JlcyBjb24gc3VzIHJlc3BlY3Rpdm9zIGJhcnJpb3MgY29tbyBkYXRvcyBmYWx0YW50ZXMgbyBOQS4NCg0KIyMjIFBhcmEgQkFSUklPDQoNClNlIGRldGVjdGEgcXVlIGxvcyBiYXJyaW9zIGNvbnRpZW5lbiBhbGd1bm9zIHByb2JsZW1hcyBkZSBlc3BhY2lvcywgYWxndW5vcyBlamVtcGxvcyBzb246DQoNCi0gIkFzb21hZGVyYSBOby4gMSIgeSAiQXNvbWFkZXJhIE5vLjEiDQotICJBdXJlcyBOby4gMiIgeSAiQXVyZXMgTm8uMiINCi0gIkJvbWJvbmEgTm8uIDEiIHkgIkJvbWJvbmEgTm8uMSINCi0gIkIuIENlcnJvICBFbCBWb2xhZG9yIiB5ICJCLiBDZXJybyBFbCBWb2xhZG9yIg0KDQpQb3IgbG8gdGFudG8gc2UgYXJyZWdsYSBlc3RlIHByb2JsZW1hIHF1aXRhbmRvIGVsIGVzcGFjaW8gcXVlIGhheSBlbnRyZSAiTm8uIiB5IHN1IG7Dum1lcm8gY29ycmVzcG9uZGllbnRlIGVuIGxvcyBiYXJyaW9zIHF1ZSB0aWVuZW4gZXN0YSBjYXJhY3RlcsOtc3RpY2EuIFRhbWJpw6luIHNlIGVsaW1pbmFuIGxvcyBlc3BhY2lvcyBxdWUgaGF5IGFudGVzIGRlIGxhIHByaW1lcmEgbGV0cmEgeSBkZXNwdcOpcyBkZSBsYSDDumx0aW1hIGxldHJhLg0KDQpUYW1iacOpbiBzZSByZWVtcGxhemEgIkJhcnJpb3MgZGUgSmVzw7pzIiBwb3IgIkJhcnJpbyBkZSBKZXPDunMiLCAiTnVldmEgVmlsbGEgZGUgTGEgSWd1YW5hIiBwb3IgIk51ZXZhIFZpbGxhIGRlIGxhIElndWFuYSIsICAiU2FudGEgTWFyw61hIGRlIExvcyDDgW5nZWxlcyIgcG9yICJTYW50YSBNYXLDrWEgZGUgbG9zIMOBbmdlbGVzIiwgIlZpbGxhIExpbGxpYW0iIHBvciAiVmlsbGEgTGlsaWFtIi4NCg0KIyMjIFBhcmEgQ0xBU0UNCg0KIkNhaWRhIGRlIE9jdXBhbnRlIiBzZSByZWVtcGxhemEgcG9yICJDYWlkYSBPY3VwYW50ZSIgeWEgcXVlIHNlIGNvbnNpZGVyYW4gZXF1aXZhbGVudGVzLiBUYW1iacOpbiBzZSBlbGltaW5hIGxhIG9ic2VydmFjacOzbiBjb24gQ0xBU0UgPSAiQ2hvcXVlIHkgQXRyb3BlbGxvIiB5YSBxdWUgc29sbyBoYXkgdW5hLg0KDQojIyMgUGFyYSBESUFfTk9NQlJFDQoNClNlIGVsaW1pbmFuIGxvcyBlc3BhY2lvcyBxdWUgaGF5IGFudGVzIGRlIGxhIHByaW1lcmEgbGV0cmEgeSBkZXNwdcOpcyBkZSBsYSDDumx0aW1hIGxldHJhIGVuIHRvZGFzIGxhcyBvYnNlcnZhY2lvbmVzLg0KDQojIyBJbXB1dGFjacOzbg0KDQpFbiBsb3MgZGF0b3MgZmFsdGFudGVzIGRlIGxhIHZhcmlhYmxlIERJU0VOTywgc2UgZGVjaWRlIHVzYXIgZWwgbm9tYnJlIGRlICJObyBSZWdpc3RyYWRvIiBwYXJhIHJlZW1wbGF6YXJsb3MuDQoNCkVuIGxhIGJhc2UgZGUgZGF0b3Mgc2UgdGllbmUgbGEgc2lndWllbnRlIGNhbnRpZGFkIGRlIGRhdG9zIGZhbHRhbnRlcyBwb3IgdmFyaWFibGU6IGxhIHZhcmlhYmxlIEJBUlJJTyB0aWVuZSAxOTk1NyBkZSBkYXRvcyBmYWx0YW50ZXMsIENPTVVOQSB0aWVuZSAxOTk1NyB5IENMQVNFIHRpZW5lIDcuIExhcyBkZW3DoXMgdmFyaWFibGVzIG5vIGNvbnRpZW5lbiBkYXRvcyBmYWx0YW50ZXMuDQoNCkNvbW8gbGEgdmFyaWFibGUgQ0xBU0Ugc29sbyB0aWVuZSA3IGRhdG9zIGZhbHRhbnRlcywgc2UgZGVjaWRlIGVsaW1pbmFyIGVzdGFzIG9ic2VydmFjaW9uZXMuIFBvciBlbCBjb250cmFyaW8sIGNvbW8gQkFSUklPIHkgQ09NVU5BIHByZXNlbnRhbiB1bmEgY2FudGlkYWQgaW1wb3J0YW50ZSBkZSBsb3MgZGF0b3MsIHNlIGRlY2lkZSByZWFsaXphciB1bmEgaW1wdXRhY2nDs24gZGUgbG9zIG1pc21vcy4NCg0KIyMjIFBhcmEgQ09NVU5BDQoNCg0KUHJpbWVybyBzZSBkZWNpZGUgcmVhbGl6YXIgbGEgaW1wdXRhY2nDs24gZW4gbGEgdmFyaWFibGUgQ09NVU5BLCBzZSB1dGlsaXphIHVuIG1vZGVsbyBrbm4gKGstTmVhcmVzdCBOZWlnaGJvdXIpIGNvbiB2YXJpYWJsZSByZXNwdWVzdGEgQ09NVU5BIHkgY29tbyBwcmVkaWN0b3JhcyBsYXMgdmFyaWFibGVzIExBVElUVUQgeSBMT05HSVRVRCBlc2NhbGFkYXMuIERhZG8gcXVlIGVzdGUgZXMgdW4gbW9kZWxvIHF1ZSB1c2EgbGEgZGlzdGFuY2lhIGV1Y2xpZGlhbmEgcGFyYSBjbGFzaWZpY2FyIG9ic2VydmFjaW9uZXMsIHNlIHBpZW5zYSBxdWUgZnVuY2lvbmFyw61hIGJpZW4gcGFyYSBjbGFzaWZpY2FyIGEgbGFzIGNvbXVuYXMgdGVuaWVuZG8gc3UgdWJpY2FjacOzbiBlbiBsYXRpdHVkIHkgbG9uZ2l0dWQuDQoNClBhcmEgYWp1c3RhciBlbCBtb2RlbG8gc2UgdXPDsyBsYSBmdW5jacOzbiBgdHJhaW5gIGRlbCBwYXF1ZXRlIGBjYXJldGAsIHVzYW5kbyBLLUZvbGQgQ1YgY29uICpLPTEwKiB5IGVsIG7Dum1lcm8gZGUgdmVjaW5vcyBpZ3VhbCBhIDEsIDQsIDcsIDEwLCAxMywgMTYgeSAxOS4gU2UgZW50cmVuw7MgZWwgbW9kZWxvIHVzYW5kbyBsb3MgYcOxb3MgZGUgMjAxNCBhIDIwMTcgeSBzZSB2YWxpZMOzIGNvbiBlbCBhw7FvIDIwMTguIFNlIHVzw7MgbGEgcHJlY2lzacOzbiBkZSBwcnVlYmEgZGVsIG1vZGVsbyBjb21vIGZ1bmNpw7NuIGRlIG9wdGltaXphY2nDs24uIExvcyByZXN1bHRhZG9zIG9idGVuaWRvcyBzb24gbG9zIHNpZ3VpZW50ZXM6DQoNClxiZWdpbnt0YWJsZX1baF0NClxiZWdpbntjZW50ZXJ9DQpcYmVnaW57dGFidWxhcn17fGN8Y3xjfGN8Y3xjfH0NClxobGluZQ0KQWNjdXJhY3kgJiBLYXBwYSAgJiBBY2N1cmFjeUxvd2VyICYgQWNjdXJhY3lVcHBlciAmIEFjY3VyYWN5TnVsbCAmIEFjY3VyYWN5UFZhbHVlIFxcDQpcaGxpbmUNCjAuOTk4NSAmIDAuOTk4NCAmIDAuOTk4MSAmIDAuOTk4OSAmIDAuMjA2MiAmIDAgXFwNClxobGluZSAgICAgICAgIA0KXGVuZHt0YWJ1bGFyfQ0KXGVuZHtjZW50ZXJ9DQpcZW5ke3RhYmxlfQ0KDQoNCiAqKkFjY3VyYWN5KiogfCAqKkthcHBhKiogfCAqKkFjY3VyYWN5TG93ZXIqKiB8ICoqQWNjdXJhY3lVcHBlcioqIHwgKipBY2N1cmFjeU51bGwqKiB8ICoqQWNjdXJhY3lQVmFsdWUqKiB8DQotLS0tLS0tLS0tLS0tfCAtLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18IC0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwgLS0tLS0tLS0tLS0tLXwNCjAuOTk4NSB8IDAuOTk4NCB8IDAuOTk4MSB8IDAuOTk4OSB8IDAuMjA2MiB8IDAgIA0KDQohW10ocHJlY2lzaW9uX2NvbXVuYV9OQS5wbmcpeyNpZCAuY2xhc3Mgd2lkdGg9NTAlIGhlaWdodD01MCV9DQoNCg0KTG9zIHJlc3VsdGFkb3Mgc2UgY29uc2lkZXJhbiBidWVub3MgeSBzZSBkZWNpZGUgcmVhbGl6YXIgZWwgcmVlbXBsYXpvIGRlIGxvcyB2YWxvcmVzIGZhbHRhbnRlcyBkZSBDT01VTkEgcG9yIG1lZGlvIGRlIGVzdGUgbW9kZWxvLg0KDQpcbmV3cGFnZQ0KDQojIyMgUGFyYSBCQVJSSU8NCg0KU2UgZGVjaWRlIHVzYXIgdW4gbW9kZWxvIGtubiAoay1OZWFyZXN0IE5laWdoYm91cikgY29uIHZhcmlhYmxlIHJlc3B1ZXN0YSBCQVJSSU8geSBjb21vIHByZWRpY3RvcmFzIGxhcyB2YXJpYWJsZXMgTEFUSVRVRCB5IExPTkdJVFVEIGVzY2FsYWRhcyB5IENPTVVOQS4NCg0KRGFkbyBxdWUgaGFiw61hbiB2YWxvcmVzIGRlIGJhcnJpb3MgcXVlIGVzdMOhbiBlbiBlbCBhw7FvIDIwMTggcGVybyBubyBlbiBsb3MgZGVtw6FzLCBubyBzZSBwdWRvIGhhY2VyIHVzbyBkZWwgcGFxdWV0ZSBgY2FyZXRgIHlhIHF1ZSBwcmVzZW50YWJhIHVuIGVycm9yIGFsIGVudHJlbmFyIGVsIG1vZGVsbywgcG9yIGxvIHF1ZSBzZSBkZWNpZGUgdXNhciAgbGEgZnVuY2nDs24gYGtubi5jdmAgZGVsIHBhcXVldGUgYGNsYXNzYCwgcGFyYSBtZWRpciBlbCBjb21wb3J0YW1pZW50byBkZWwgbW9kZWxvIGtubiBjb24gayA9IDEgbWVkaWFudGUgTE9PQ1YsIGVudHJlbmFuZG8gZWwgbW9kZWxvIGNvbiBsb3MgYcOxb3MgZGUgMjAxNCBoYXN0YSAyMDE3IHkgdmFsaWRhbmRvIGVsIHJlc3VsdGFkbyBjb24gZWwgYcOxbyAyMDE4LiBTZSBvYnRpZW5lIHVuYSBwcmVjaXNpw7NuIGRlIHBydWViYSBkZSAwLjk5NzUsIHBvciBsbyBxdWUgc2UgZGVjaWRlIHVzYXIgZXN0ZSBtb2RlbG8gcGFyYSBpbXB1dGFyIGxvcyBkYXRvcyBmYWx0YW50ZXMgZW4gQkFSUklPLg0KDQojIyBCYXNlIGZpbmFsDQoNCkZpbmFsbWVudGUgc2UgZGVjaWRlIHVzYXIgc29sbyBsYXMgY29tdW5hcyBkZWwgw6FyZWEgdXJiYW5hIGRlIE1lZGVsbMOtbiB5IGRlamFyIGEgdW4gbGFkbyBsb3MgY29ycmVnaW1pZW50b3MsIGVzIGRlY2lyLCBzb2xvIHNlIHRlbmRyw6FuIGxhcyAxNiBjb211bmFzIG1lbmNpb25hZGFzIGFudGVyaW9ybWVudGUgZW4gZXN0ZSByZXBvcnRlLg0KDQpUcmFzIGxhcyBtb2RpZmljYWNpb25lcyBtZW5jaW9uYWRhcywgZGUgbGFzIDIyODY5MyBvYnNlcnZhY2lvbmVzIG9yaWdpbmFsZXMgZW50cmUgbGFzIGJhc2VzIGRlIGRhdG9zIGRlbCAyMDE0IGFsIDIwMTgsIHNlIHV0aWxpemFyw6FuIDIwNDAwMiBvYnNlcnZhY2lvbmVzIGVuIGVsIGFuw6FsaXNpcyB5IGNvbnN0cnVjY2nDs24gZGUgbG9zIG1vZGVsb3MuIExhIGJhc2UgZGUgZGF0b3MgbHVjZSBkZSBlc3RhIG1hbmVyYToNCg0KYGBge3IsIHJvd3MucHJpbnQgPSA1LCBlY2hvPUZ9DQpsb2FkKGZpbGUgPSAiQmFzZV9kZWZpbml0aXZhLlJEYXRhIikNCmBgYA0KDQpBIGNvbnRpbnVhY2nDs24gc2UgZW5jdWVudHJhIGVsIGFjY2VzbyBhbCBjw7NkaWdvIHV0aWxpemFkbyBlbiB0b2RvIGVzdGUgcHJvY2Vzbw0KDQpFbmxhY2U6IGh0dHBzOi8vZ2l0aHViLmNvbS92YWdhcmNpYXZlL1RyYW5zaXRBcHBfMS4wL2Jsb2IvbWFzdGVyL2xpbXBpZXphL0RlcHVyYWNpb24uUm1kDQoNCiMgQW7DoWxpc2lzIGRlc2NyaXB0aXZvDQoNCiMjIFNvYnJlIGxhIGJhc2UgZGUgZGF0b3MNCg0KYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GLCBtZXNzYWdlPUZ9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KTHVlZ28gZGUgbGEgZGVwdXJhY2nDs24gZSBpbXB1dGFjacOzbiBkZSBsb3MgZGF0b3MsIHNlIGN1ZW50YSBjb24gdW4gdG90YWwgZGUgMjA0MDAyIGluY2lkZW50ZXMgZGUgdHLDoW5zaXRvLCBsb3MgY3VhbGVzIHRpZW5lbiAxNCBjYXJhY3RlcsOtc3RpY2FzIHF1ZSBzZSBwdWVkZW4gbGxhbWFyICJ2YXJpYWJsZXMiLiBEZSBsYXMgMTQgdmFyaWFibGVzIDcgc29uIGNhdGVnb3LDrWNhcyAoT0JKRUNUSUQsIENMQVNFICwgR1JBVkVEQUQsIENPTVVOQSwgQkFSUklPLCBESVNFTk8sIERJQV9OT01CUkUpLiBIYXkgdW4gdG90YWwgZGUgMTYgY29tdW5hcywgMjY4IGJhcnJpb3MsIDYgY2xhc2VzIGRlIGFjY2lkZW50ZSwgMyBuaXZlbGVzIGRlIGdyYXZlZGFkLCAxMyB0aXBvcyBkZSBkaXNlw7FvIGRlIHbDrWEuDQoNClBhcmEgZXN0ZSBhbsOhbGlzaXMgbm8gc2UgY29uc2lkZXJhcsOhbiBsYXMgdmFyaWFibGVzIEZFQ0hBLCBMQVRJVFVEIHkgTE9OR0lUVUQuDQoNCiMjIFBlcmlvZG8NCg0KYGBge3IgZWNobz1GQUxTRSwgZmlnLmhlaWdodD00fQ0KcGVyIDwtIHRhYmxlKGRmJFBFUklPRE8pDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmJhcnhwZXJpb2RvIDwtIGJhcnBsb3QocGVyLCB5bGltID0gYygwLDUwMDAwKSwgeGxhYiA9ICJBw7FvIiwNCiAgICAgICAgICAgICAgIHlsYWIgPSAiQ2FudGlkYWQgZGUgYWNjaWRlbnRlcyIsIG1haW4gPSAiQUNDSURFTlRFUyBNRURFTExJTiAoMjAxNC0yMDE4KSIsDQogICAgICAgICAgICAgICBjZXguYXhpcyA9ICIwLjgiLGNleC5sYWIgPSAiMS41IiwNCiAgICAgICAgICAgICAgIGNvbD0gYnJld2VyLnBhbCg1LCAiU2V0MyIpLCBsYXMgPSAxKQ0KdGV4dCh4PWJhcnhwZXJpb2RvLCB5PXBlciwgcG9zPTMsIGNleD0xLCBjb2w9ImJsYWNrIiwgbGFiZWxzID0gcGVyKQ0KYGBgDQoNCkxhIGNhbnRpZGFkIHRvdGFsIGRlIGFjY2lkZW50ZXMgcG9yIHBlcmlvZG8gZXMgYmFzdGFudGUgc2ltdWxhciwgc2Ugbm90YSB1bmEgbGV2ZSByZWR1Y2Npw7NuIHBhcmEgZWwgMjAxOC4NCg0KDQojIyBDbGFzZQ0KDQoNCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZWNobz1GfQ0KZGYgJT4lIGdyb3VwX2J5KE1FUyxDTEFTRSwgUEVSSU9ETykgJT4lIA0KICBzdW1tYXJpc2UodG90YWwgPSBuKCkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gTUVTLCB5ID0gdG90YWwgLCBjb2xvciA9IENMQVNFKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIGZhY2V0X3dyYXAoflBFUklPRE8pICsgDQogIHNjYWxlX3hfZGlzY3JldGUoIk1lcyIsIGxpbWl0cz1jKDE6MTIpKQ0KICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpDQoNCmBgYA0KDQoNClBhcmEgY2xhc2UsIGVzIGNsYXJvIHF1ZSBlbiBjYWRhIHBlcmlvZG8gbG8gcXVlIG3DoXMgc2UgcHJlc2VudGFuIHNvbiBjaG9xdWVzLCBkZSBtYW5lcmEgYW7DoWxvZ2EgZXMgcG9jbyBjb23Dum4gcXVlIGhheWFuIGluY2VuZGlvcywgZGUgaWd1YWwgZm9ybWEgbG9zIHZvbGNhbWllbnRvcyB0YW1iacOpbiBzb24gcG9jbyBjb211bmVzLiAgUGFyYSBsYXMgY2xhc2VzIGF0cm9wZWxsbywgY2HDrWRhIGRlIG9jdXBhbnRlIHkgb3RybyBwYXJlY2UgaGFiZXIgY2FudGlkYWRlcyBtdXkgc2ltaWxhcmVzLCBlc3RvcyBjb21wb3J0YW1pZW50b3Mgc29uIHBhcmVjaWRvcyBlbiBjYWRhIHBlcmlvZG8gcGVybyBoYXkgZGlmZXJlbmNpYXMgcXVlIHBvZHLDrWFuIHNlciBzaWduaWZpY2F0aXZhcyBlbiBsb3MgbW9kZWxvcy4NCg0KIyMgR3JhdmVkYWQNCg0KYGBge3IsIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBlY2hvPUZ9DQpkZiAlPiUgZ3JvdXBfYnkoTUVTLCBHUkFWRURBRCwgUEVSSU9ETykgJT4lIA0KICBzdW1tYXJpc2UodG90YWwgPSBuKCkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gTUVTLCB5ID0gdG90YWwgLCBjb2xvciA9IEdSQVZFREFEKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdlb21fcG9pbnQoKSArDQogIGZhY2V0X3dyYXAoflBFUklPRE8pICsgDQogIHNjYWxlX3hfZGlzY3JldGUoIk1lcyIsIGxpbWl0cz1jKDE6MTIpKQ0KICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpDQpgYGANCg0KRW4gbG9zIGFjY2lkZW50ZXMgZGUgdHLDoW5zaXRvIGxvIG3DoXMgY29tw7puIGVzIHF1ZSBzZSBwcmVzZW50ZW4gaGVyaWRvcywgc2VndWlkbyBwb3Igc29sbyBkYcOxb3MsIHBvciBvdHJhIHBhcnRlIGVsIG7Dum1lcm8gZGUgbXVlcnRvcyBwYXJhIGNhZGEgcGVyaW9kbyBlcyBtdXkgYmFqbywgY29tcGFyYWRvIGNvbiBsb3Mgb3Ryb3MgdGlwb3MgZGUgZ3JhdmVkYWQuIFBhcmEgZWwgYcOxbyAyMDE4IHNlIG5vdGEgdW5hIGxldmUgZGlzbWludWNpw7NuIGVuIGxhIGNhbnRpZGFkIGRlIGhlcmlkb3MuDQoNCiMjIENvbXVuYQ0KDQpgYGBge3IsIGVjaG89RkFMU0UsIGZpZy5oZWlnaHQ9NC41fQ0KZGZfY29tdW5hIDwtIHRhYmxlKGRmJENPTVVOQSkNCmFjY2lkZW50ZXN4Y29tdW5hIDwtIGJhcnBsb3QoZGZfY29tdW5hLCB5bGltID0gYygwLDQ3MDAwKSwgeGxhYiA9ICIgIiwNCiAgICAgICAgICAgICAgICB5bGFiID0gIk7Dum1lcm8gZGUgYWNjaWRlbnRlcyIsIG1haW4gPSAiQ0FOVElEQUQgREUgQUNDSURFTlRFUyBFTiBDT01VTkFTIERFICBNRURFTExJTg0KICAgICAgICAgICAgICAgKDIwMTQtMjAxOCkiLCBjZXguYXhpcyA9ICIwLjgiLGNleC5sYWIgPSAiMS41IiwNCiAgICAgICAgICAgICAgICBjb2wgPSBicmV3ZXIucGFsKDE2LCAiU2V0MyIpLCBsYXM9MywgY2V4Lm5hbWVzID0gMC42KQ0KdGV4dCh4PWFjY2lkZW50ZXN4Y29tdW5hLCB5PWRmX2NvbXVuYSwgcG9zPTMsIGNleD0wLjcsIGNvbD0iYmxhY2siLGxhYmVsPWRmX2NvbXVuYSkNCmBgYA0KDQoNCkVuIGxvcyBhY2NpZGVudGVzIHBvciBjb211bmEgc2UgZXZpZGVuY2lhIHF1ZSBsYSBjb211bmEgIkxhIENhbmRlbGFyaWEiIGVzIGxhIHF1ZSBtYXMgYWNjaWRlbnRlcyBoYSByZWdpc3RyYWRvIGR1cmFudGUgbG9zIHBlcmlvZG9zIGFuYWxpemFkb3MsIGxhIGRlIG1lbm9yIGNhbnRpZGFkIGRlIGFjY2lkZW50ZXMgZXMgbGEgY29tdW5hICJTYW50YSBDcnV6IiwgZXN0byBlcyBjb24gZWwgbsO6bWVybyBkZSBhY2NpZGVudGVzIG9ic2VydmFkbywgZGVsIDIwMTQgYWwgMjAxOC4NCg0KIyMgQ29tdW5hcyBwb3IgcGVyaW9kbw0KDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGVjaG89Rn0NCmRmX2NvbXVuYSA8LSBkZiAlPiUgDQogIGdyb3VwX2J5KENPTVVOQSwgUEVSSU9ETykgJT4lIA0KICBzdW1tYXJpc2UodG90YWwgPSBuKCkpICU+JSBhcnJhbmdlKHRvdGFsLCBDT01VTkEpDQoNCmRmX2NvbXVuYSAlPiUgZ2dwbG90KGFlcyhDT01VTkEpKSArDQogIGdlb21fY29sKGFlcyh4PUNPTVVOQSx5PXRvdGFsLGZpbGw9Q09NVU5BKSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBzaXplID0gNyksbGVnZW5kLnBvc2l0aW9uPSdub25lJykgKw0KICBmYWNldF93cmFwKH5QRVJJT0RPKQ0KYGBgDQpBaG9yYSBkaXNjcmltaW5hbmRvIGVsIG7Dum1lcm8gZGUgYWNjaWRlbnRlcyBlbiBsYXMgY29tdW5hcyBwb3IgcGVyaW9kbywgc2Ugb2JzZXJ2YSBxdWUgc2UgcHJlc2VudGEgdW5hIHRlbmRlbmNpYSBzaW1pbGFyIHBhcmEgY2FkYSBwZXJpb2RvLCBwb3IgbG8gcXVlIHNlIHBpZW5zYSBxdWUgY2FkYSBhw7FvIHZhbiBhIGV4aXN0aXIgdGVuZGVuY2lhcyBzaW1pbGFyZXMgZGUgbGEgYWNjaWRlbnRhbGlkYWQgcG9yIGNvbXVuYS4NCg0KDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpjb21wbGV0YV9ncmF2ZWRhZCA8LSBkZiAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KFBFUklPRE8sIE1FUyxCQVJSSU8sR1JBVkVEQUQpJT4lDQogICAgZ3JvdXBfYnkoUEVSSU9ETywgTUVTLEJBUlJJTyxHUkFWRURBRCklPiUNCiAgICBzdW1tYXJpc2UoQ09OVEVPPWxlbmd0aChQRVJJT0RPKSkNCmNvbXBsZXRhX2JhcnJpbyA8LSBjb21wbGV0YV9ncmF2ZWRhZCAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KFBFUklPRE8sIE1FUyxCQVJSSU8sIENPTlRFTyklPiUNCiAgICBncm91cF9ieShQRVJJT0RPLCBNRVMsQkFSUklPKSU+JQ0KICAgIHN1bW1hcmlzZShUT1RBTD1zdW0oQ09OVEVPKSkNCmNvbXBsZXRhIDwtIGxlZnRfam9pbihjb21wbGV0YV9ncmF2ZWRhZCxjb21wbGV0YV9iYXJyaW8sIA0KICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiUEVSSU9ETyIsICJCQVJSSU8iLCAiTUVTIikpDQoNCmdlbmVyYWw8LSBjb21wbGV0YVssIGMoIkJBUlJJTyIsICJDT05URU8iKV0gJT4lDQogICAgZHBseXI6OnNlbGVjdChCQVJSSU8sIENPTlRFTykgJT4lDQogICAgZ3JvdXBfYnkoQkFSUklPKSAlPiUNCiAgICBzdW1tYXJpc2UoVE9UQUwgPXN1bShDT05URU8pKQ0KDQpnZW5lcmFsX2dyYXZlZGFkPC1kZlssYygiQkFSUklPIiwgIkdSQVZFREFEIildJT4lDQogICAgZHBseXI6OnNlbGVjdChCQVJSSU8sR1JBVkVEQUQpJT4lDQogICAgZ3JvdXBfYnkoQkFSUklPLCBHUkFWRURBRCklPiUNCiAgICBzdW1tYXJpc2UoQ09OVEVPPWxlbmd0aChCQVJSSU8pKSANCg0Kb3JkZW5hbWllbnRvPC1nZW5lcmFsW29yZGVyKC1nZW5lcmFsJFRPVEFMKSxdDQpvcmRlbmFtaWVudG88LWhlYWQob3JkZW5hbWllbnRvLDUpDQpvcmRlbmFtaWVudG8kQkFSUklPPC1hcy5jaGFyYWN0ZXIob3JkZW5hbWllbnRvJEJBUlJJTykNCg0KZ2VuZXJhbF9nPC1pbm5lcl9qb2luKGdlbmVyYWxfZ3JhdmVkYWQsb3JkZW5hbWllbnRvLGJ5PSJCQVJSSU8iKQ0KZ2VuZXJhbF9nPC1nZW5lcmFsX2dbb3JkZXIoLWdlbmVyYWxfZyRUT1RBTCksXQ0KYGBgDQoNCg0KIyMgQmFycmlvcyBwb3IgcGVyaW9kbw0KDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGVjaG89Rn0NCmRmX2JhcnJpbzwtIGRmICU+JSANCiAgZ3JvdXBfYnkoQkFSUklPLCBQRVJJT0RPKSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsID0gbigpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyh0b3RhbCksIEJBUlJJTykgICU+JQ0KICBncm91cF9ieShQRVJJT0RPKSAlPiUNCiAgdG9wX24obiA9IDEwKQ0KDQpkZl9iYXJyaW8gJT4lIGdncGxvdChhZXMoQkFSUklPKSkgKw0KICBnZW9tX2NvbChhZXMoeD1CQVJSSU8seT10b3RhbCxmaWxsPUJBUlJJTykpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IDcpLGxlZ2VuZC5wb3NpdGlvbj0nbm9uZScpICsNCiAgZmFjZXRfd3JhcCh+UEVSSU9ETykNCg0KYGBgDQoNClBhcmEgbG9zIGJhcnJpb3Mgc2UgdGllbmUgZWwgY3VlbnRhIGVsIHRvcCAxMCBjb24gbcOhcyBhY2NpZGVudGVzIHBvciBjYWRhIHBlcmlvZG8sIGVsIGJhcnJpbyBxdWUgcHJlc2VudMOzIG1heW9yIG7Dum1lcm8gZGUgYWNjaWRlbnRlcyBkZSAyMDE0IGEgMjAxNyBmdWUgbGEgQ2FuZGVsYXJpYSwgcGFyYSAyMDE4IGVzdGUgYmFycmlvIGZ1ZSBzdXBlcmFkbyBwb3IgdW5hIGNhbnRpZGFkIG5vIG11eSBncmFuZGUgcG9yIGVsIGJhcnJpbyBjYW1wbyBhbW9yLCBzZSBldmlkZW5jaWEgY29tbyBhIHRyYXbDqXMgZGVsIHRpZW1wbyBhbGd1bm9zIGJhcnJpb3MgaW5ncmVzYW4gbyBzYWxlbiBkZWwgdG9wIDEwLCBwb3IgZWplbXBsbyBlbCBDYXJsb3MgRS4gUmVzdHJlcG8gZW1wZXrDsyBhIHRlbmVyIHVuYSBhY2NpZGVudGFsaWRhZCBtw6FzIGFsdGEgYSBwYXJ0aXIgZGVsIDIwMTYsIHBvciBzdSBwYXJ0ZSBHdWF5YXF1aWwgcmVkdWpvIHN1IGFjY2lkZW50YWxpZGFkIHBhcmEgMjAxOCwgZWwgYmFycmlvIE5hcmFuamFsIHNvbG8gZXN0dXZvIGVuIGVsIHRvcCAxMCBlbiBlbCBhw7FvIDIwMTUuDQoNCioqTG9zIHByaW1lcm9zIDUgYmFycmlvcyBjb24gbWFzIGNhbnRpZGFkIGRlIGFjY2lkZW50ZXMgcG9yIGdyYXZlZGFkKioNCg0KDQpgYGB7ciBlY2hvPUZBTFNFLCBpbmNsdWRlID0gRn0NCmJhcl9iYXJyaW8gPC0gcGxvdF9seSh4ID0gZ2VuZXJhbF9nJEJBUlJJTywgeSA9IGdlbmVyYWxfZyRDT05URU8sIHR5cGUgPSAnYmFyJywgDQogICAgICAgICAgICBuYW1lID0gZ2VuZXJhbF9nJEdSQVZFREFEICxjb2xvciA9IGdlbmVyYWxfZyRHUkFWRURBRCkgJT4lDQogICAgICAgICAgICBsYXlvdXQodGl0bGU9IlRvcCA1Iix5YXhpcyA9IGxpc3QodGl0bGUgPSAnQ2FudGlkYWQnKSwgDQogICAgICAgICAgICAgICAgICAgeGF4aXM9bGlzdChjYXRlZ29yeW9yZGVyPSdhcnJheScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXRlZ29yeWFycmF5PWdlbmVyYWxfZyRUT1RBTCksDQogICAgICAgICAgICAgICAgICAgYmFybW9kZSA9ICdzdGFjaycsDQogICAgICAgICAgICAgICAgICAgY29sb3J3YXkgPSBjKCcjNGMzZDY2JywgJyM3OTgyY2UnLCAnI2ZmOTc1YicsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnI2EyNjJhOScsICcjNmY0ZDk2JywgJyMzZDNiNzInLCAnIzE4Mjg0NCcpKQ0KYmFyX2JhcnJpbw0KYGBgDQoNCg0KRXN0b3Mgc29uIGxvcyA1IGJhcnJpb3MgY29uIG1hcyBjYW50aWRhZCBkZSBhY2NpZGVudGVzLCBsb3MgY3VhbGVzIHNlIGNsYXNpZmljYW4gcG9yIGxhIGdyYXZlZGFkLCBxdWUgc29uOiJzb2xvIGRhw7FvcyIsIkhlcmlkbyIgeSAiTXVlcnRvIiwgc2UgaWRlbnRpZmljYXJvbiBsb3MgcHJpbWVyb3MgYmFycmlvcyBjb24gbWFzIGFjY2lkZW50YWxpZGFkIHBvciBhw7FvLCBub3RhciBxdWUgbGEgZ3JhdmVkYWQgbWVub3MgY29uY3VycmVudGUgZXMgIk11ZXJ0byIsIGF1bnF1ZSBsYSBDYW5kZWxhcmlhIGVzIGVsIGJhcnJpbyBjb24gbWFzIGFjY2lkZW50ZXMgcG9yIGHDsW8sIHRhbWliaWVuIG5vdGUgcXVlIENhc3RpbGxhIHRpZW5lIG1hcyBhY2NpZGVudGVzIGNvbiBncmF2ZWRhZCBkZSBtdWVydGVzIG1hcyBhbHRhIHF1ZSBsYSBkZSBsb3MgZGVtYXMgYmFycmlvcy4NCg0KDQojIyBEaXNlw7FvDQogDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGVjaG89Rn0NCmRmICU+JSBncm91cF9ieShNRVMsIERJU0VOTywgUEVSSU9ETykgJT4lIA0KICBzdW1tYXJpc2UodG90YWwgPSBuKCkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gTUVTLCB5ID0gdG90YWwgLCBjb2xvciA9IERJU0VOTykpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBmYWNldF93cmFwKH5QRVJJT0RPKSArIA0KICBzY2FsZV94X2Rpc2NyZXRlKCJNZXMiLCBsaW1pdHM9YygxOjEyKSkNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKQ0KYGBgDQoNCkVsIGRpc2XDsW8gcXVlIG3DoXMgYWNjaWRlbnRhbGlkYWQgcHJlc2VudGEgZXMgZWwgdHJhbW8gZGUgdsOtYSwgZXN0byBwYXJhIHRvZG9zIGxvcyBwZXJpb2Rvcy4gRGUgMjAxNCBhIDIwMTggaHVibyB1bmEgZGlzbWludWNpw7NuIGVuIGVzdGUgdGlwbyBkZSBhY2NpZGVudGVzLCBwb3Igc3UgbGFkbyBsb3MgYWNjaWRlbnRlcyBwYXJhIGludGVyc2VjY2nDs24geSBMb3RlIG8gcHJlZGlvIGF1bWVudGFyb24gbGV2ZW1lbnRlIGRlIDIwMTQgYSAyMDE4Lg0KDQoNCiMjIEFjY2lkZW50YWxpZGFkIHBvciBtZXMNCg0KYGBge3IsIG1lc3NhZ2U9Riwgd2FybmluZz1GLCBlY2hvPUZ9DQpkZiAlPiUgZ3JvdXBfYnkoTUVTLCBQRVJJT0RPKSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsID0gbigpKSAlPiUNCiAgZ2dwbG90KGFlcyh5PXRvdGFsLCB4ID0gTUVTLGNvbG9yPWZhY3RvcihQRVJJT0RPKSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKCkgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKSArDQogIHRoZW1lX2J3KCkgKyANCiAgc2NhbGVfeF9kaXNjcmV0ZSgiTWVzIiwgbGltaXRzPWMoMToxMikpDQpgYGANCg0KU2UgcHVlZGUgYXByZWNpYXIgcXVlIGxhIGFjY2lkZW50YWxpZGFkIHBhcmEgMjAxOCBlcyBtZW5vciBjb21wYXJhZGEgY29uIG90cm9zIGHDsW9zLCBlc3RvIHBhcmEgY2FzaSB0b2RvcyBsb3MgbWVzZXMsIHNlIG9ic2VydmEgY29tbyBoYXkgZGlmZXJlbmNpYXMgcGFyYSBjYWRhIHBlcmlvZG8geSBjYWRhIGHDsW8sIHBvciBsbyBjdWFsIHVuYSB2YXJpYWJsZSB0ZW1wb3JhbCBlbiBsb3MgbW9kZWxvcyBwcmVkaWN0aXZvcyBwb2Ryw61hIHNyIHNpZ25pZmljYXRpdmEuIFBhcmEgbG9zIG1lc2VzIGRlIEVuZXJvIGEgTWFyem8gbGEgYWNjaWRlbnRhbGlkYWQgcGFyZWNlIHNlciBtw6FzIGJhamEsIHBhcmEgZWwgbWVzIGRlIEp1bmlvIGxvcyBhY2NpZGVudGVzIGRpc21pbnV5ZW4uIERlIEFnb3N0byBhIE9jdHVicmUgbGEgYWNjaWRlbnRhbGlkYWQgZW4gbcOhcyBhbHRhLg0KDQojIyBEw61hIGRlIGxhIHNlbWFuYQ0KDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUYsIGVjaG89Rn0NCmRmICU+JSBncm91cF9ieShESUFfTk9NQlJFLCBESUFfRkVTVElWTykgJT4lDQogIHN1bW1hcmlzZSh0b3RhbCA9IG4oKSkgJT4lDQogIG11dGF0ZShESUFfRkVTVElWTyA9IGFzLmZhY3RvcihESUFfRkVTVElWTyksDQogICAgICAgICBESUFfTk9NQlJFID0gZmFjdG9yKERJQV9OT01CUkUsIGxldmVscyA9IGMoIkxVTkVTIiwiTUFSVEVTIiwiTUlFUkNPTEVTIiwgIkpVRVZFUyIsIlZJRVJORVMiLCJTQUJBRE8iLCJET01JTkdPIikpKSAlPiUNCiAgZ2dwbG90KGFlcyh4PURJQV9OT01CUkUsIHk9dG90YWwsIGZpbGwgPSBESUFfRkVTVElWTykpICsgDQogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKQ0KDQpgYGANCg0KRXMgY2xhcm8gcXVlIGxvcyBkw61hcyBmZXN0aXZvcyBzb24gdW4gZmFjdG9yIHJlYWxtZW50ZSBpbmZsdXllbnRlIGVuIGVsIG7Dum1lcm8gZGUgYWNjaWRlbnRlcywgcHVlcyBwYXJhIGVzdG9zIHNlIHByZXNlbnRhbiBtZW5vciBjYW50aWRhZCBkZSBhY2NpZGVudGVzLCBwYXJhIGVsIGTDrWEgZG9taW5nbyBlbCB0b3RhbCBkZSBhY2NpZGVudGVzIGVzIG1lbm9yLCBwYXJhIGxvcyBkZW3DoXMgZMOtYXMgbm8gc2Ugb2JzZXJ2YSB1bmEgZGlmZXJlbmNpYSBzaWduaWZpY2F0aXZhLg0KDQojIyBDb25jbHVzacOzbiBkZWwgYW7DoWxpc2lzDQoNCkRlbCBhbsOhbGlzaXMgZGVzY3JpcHRpdm8gc2UgY29uY2x1eWUgcXVlIGxhcyB2YXJpYWJsZXMgdGVtcG9yYWxlcyBubyBzb24gaW5mbHV5ZW50ZXMgZW4gbGEgYWNjaWRlbnRhbGlkYWQsIHBhcmEgZWwgbWVzIGhheSB2YXJpYWNpb25lcyBzaWduaWZpY2F0aXZhcyBlbiBlbCBuw7ptZXJvIHRvdGFsIGRlIGFjY2lkZW50ZXMsIHBvciBzdSBwYXJ0ZSBwYXJhIGxhIGNsYXNlIGRlIGFjY2lkZW50ZSwgZ3JhdmVkYWQgeSBkaXNlw7FvIHRhbWJpw6luIHZhcsOtYSBlbCB0b3RhbCBkZSBhY2NpZGVudGVzLiBQcmluY2lwYWxtZW50ZSBsYSB2YXJpYWJpbGlkYWQgYSBuaXZlbCBkZSBhY2NpZGVudGFsaWRhZCBkZXBlbmRlIGVuIG1heW9yIG1lZGlkYSBkZSBiYXJyaW8geSBjb211bmENCg0KDQoNCiMgTW9kZWxvcyBQcmVkaWN0aXZvcw0KDQpTZSBkZWZpbmUgbGEgYWNjaWRlbnRhbGlkYWQgY29tbyBlbCBuw7ptZXJvIGRlIGFjY2lkZW50ZXMgcXVlIGhheSBhIG5pdmVsIGRpYXJpbywgc2VtYW5hbCB5IG1lbnN1YWwsIGRpc2NyaW1pbmFuZG8gcG9yIHRpcG8gZGUgYWNjaWRlbnRlIChDTEFTRSkgeSBiYXJyaW8gbyBjb211bmEgZG9uZGUgw6lzdGUgb2N1cnJlLiBMbyBhbnRlcmlvciBkZWJpZG8gYSBxdWUgZXhpc3RlIHVuYSB2YXJpYWJpbGlkYWQgbm90YWJsZSBhIG5pdmVsIGRlIGFjY2lkZW50YWxpZGFkIHBhcmEgY2FkYSBjb2x1bW5hIHkgcGFyYSBjYWRhIGJhcnJpbyBjb21vIHNlIG9ic2VydsOzIGVuIGVsIGFuw6FsaXNpcyBkZXNjcmlwdGl2by4NCg0KRGFkbyBxdWUgZWwgb2JqZXRpdm8gZXMgcHJlZGVjaXIgbGEgYWNjaWRlbnRhbGlkYWQgYSBuaXZlbCBkaWFyaW8sIG1lbnN1YWwgbyBzZW1hbmFsLCBzZSBidXNjYSBjb25zdHJ1aXIgbW9kZWxvcyBxdWUgcHJlZGlnYW4gZWwgbsO6bWVybyBkZSBhY2NpZGVudGVzIGVuIGNhZGEgdW5vIGRlIGxvcyByYW5nb3MgdGVtcG9yYWxlcyBlcyBkZWNpciBzZSBjcmVhcsOhbiBtb2RlbG9zIGVzcGVjw61maWNvcyBwYXJhIGNhZGEgY29tdW5hL2JhcnJpbyBzZWfDum4gbGEgdW5pZGFkIHRlbXBvcmFsLg0KDQpTZSBwaWVuc2EgcXVlIGxvcyBtb2RlbG9zIG1peHRvcyBvIG1vZGVsb3MgamVyw6FycXVpY29zIHB1ZWRlbiByZXByZXNlbnRhciBiaWVuIGVzdGEgZGVmaW5pY2nDs24gZGUgYWNjaWRlbnRhbGlkYWQsIGRlYmlkbyBhIGxhIGFncnVwYWNpw7NuIHF1ZSBleGlzdGUgYWwgbW9tZW50byBkZSBkZWZpbmlyIGxhIGFjY2lkZW50YWxpZGFkLCBlcyBkZWNpciwgZXhpc3RlIHVuYSBhZ3J1cGFjacOzbiBlbnRyZSBjb211bmEgeSBjbGFzZTsgeSBvdHJhIGFncnVwYWNpw7NuIGVudHJlIGJhcnJpbyB5IGNsYXNlLiBQb3IgbG8gcXVlIHNlIGRlY2lkZSBjcmVhciBlc3RvcyBtb2RlbG9zIGNvbiBsYSBheXVkYSBkZWwgcGFxdWV0ZSBgbG1lNGAgeSBtZWRpciBzdSBhanVzdGUuIEVuIGNhZGEgdW5vIGRlIGVzdG9zIGNhc29zIHNlIGNyZWEgdW4gbW9kZWxvIHF1ZSBwcmVkaWdhIGVsIG7Dum1lcm8gZGUgYWNjaWRlbnRlcywgcG9yIGxvIHF1ZSBzZSBjb25zaWRlcmEgcXVlIGxhIGFjY2lkZW50YWxpZGFkIHB1ZWRlIHNlZ3VpciB1bmEgZGlzdHJpYnVjacOzbiAqUG9pc3NvbiouDQoNClBhcmEgZXZhbHVhciBsb3MgbW9kZWxvcyBzZSBjcmVhbiBjb25qdW50b3MgZGUgZW50cmVuYW1pZW50byB5IGNvbmp1bnRvcyBkZSB2YWxpZGFjacOzbi4gTG9zIGNvbmp1bnRvcyBkZSBlbnRyZW5hbWllbnRvIGNvbnN0YW4gZGUgdG9kYXMgbGFzIGNvbWJpbmFjaW9uZXMgcG9zaWJsZXMgZGUgdGlwb3MgZGUgYWNjaWRlbnRlcyBzZWfDum4gc2kgZXMgY29tdW5hIG8gYmFycmlvIHkgc3UgdW5pZGFkIGRlIHRpZW1wbyBjb24gbG9zIGHDsW9zIChwZXJpb2RvcykgZGVsIDIwMTQgYWwgMjAxNywgZWwgY29uanVudG8gZGUgdmFsaWRhY2nDs24gc2Vyw6EgY29uIGVsIGHDsW8gMjAxOC4NCg0KTGEgbWVkaWRhIHBhcmEgZXZhbHVhciBlbCBhanVzdGUgZGUgbG9zIG1vZGVsb3Mgc2Vyw6EgZWwgZXJyb3IgY3VhZHLDoXRpY28gbWVkaW8gZW4gbGFzIHByZWRpY2Npb25lcyB0YW50byBwYXJhIGxvcyBjb25qdW50b3MgZGUgZW50cmVuYW1pZW50byBjb21vIHBhcmEgbG9zIGRlIHZhbGlkYWNpw7NuLg0KDQokJE1TRSA9IFxmcmFje1xzdW1fe2k9MX1eTiAoYWNjaWRlbnRhbGlkYWRfaSAtIFx3aWRlaGF0e2FjY2lkZW50YWxpZGFkX2kpXjJ9fXtOfSQkDQoNCkNvbiBsYSBheXVkYSBkZSBSIHNlIGNyZWEgbGEgc2lndWllbnRlIGZ1bmNpw7NuIHBhcmEgb2J0ZW5lcmxvOg0KDQpgYGB7cn0NCk1TRSA8LSBmdW5jdGlvbih5LCB5X2VzdCkgbWVhbigoeS15X2VzdCkqKjIpDQpgYGANCg0KU2UgdXNhcsOhbiBsb3Mgc2lndWllbnRlcyBwYXF1ZXRlcyBwYXJhIGFqdXN0YXIgbG9zIG1vZGVsb3MNCg0KYGBge3IsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQ0KbGlicmFyeShsbWU0KSAgICAgICMgUGFxdWV0ZSBwYXJhIGxhIGNyZWFjacOzbiBkZSBtb2RlbG9zIG1peHRvcyBwb2lzc29uDQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBQYXF1ZXRlIHBhcmEgbGEgY3JlYWNpw7NuIGRlIGxvcyBjb25qdW50b3MgZGUgZGF0b3MNCmBgYA0KDQojIyBBanVzdGUgZGUgbGEgYmFzZSBkZSBkYXRvcw0KDQpTZSBkZWJlIG1vZGlmaWNhciBsYSBiYXNlIGRlIGRhdG9zIGRlcHVyYWRhIHBhcmEgcG9kZXIgcmVhbGl6YXIgbG9zIG1vZGVsb3MuIFNlIGNyZWFuIHZhcmlhYmxlcyBkZSB0aWVtcG8gYSBuaXZlbCBkaWFyaW8sIHNlbWFuYWwgeSBtZW5zdWFsLCBhZGVtw6FzIGRlIGxhIHZhcmlhYmxlIGFjY2lkZW50YWxpZGFkIHkgZMOtYXMgZmVzdGl2b3MuDQoNCmBgYHtyLCBldmFsID0gRn0NCiMgIFZlY3RvciBjb24gZmVjaGFzIGRlIGRpYXMgZmVzdGl2b3MNCiAgIyBEZWZpbmlyIGRpYXMgZmVzdGl2b3MNCiAgZmVzdGl2b3MgPC0geW1kKGMoDQogICAgIzIwMTQNCiAgICAnMjAxNC0wMS0wMScsJzIwMTQtMDEtMDYnLCcyMDE0LTAzLTI0JywnMjAxNC0wNC0xNycsJzIwMTQtMDQtMTgnLCAnMjAxNC0wNS0wMScsDQogICAgJzIwMTQtMDYtMDInLCcyMDE0LTA2LTIzJywnMjAxNC0wNi0zMCcsJzIwMTQtMDctMjAnLCcyMDE0LTA4LTA3JywgJzIwMTQtMDgtMTgnLA0KICAgICcyMDE0LTEwLTEzJywnMjAxNC0xMS0wMycsJzIwMTQtMTEtMTcnLCcyMDE0LTEyLTA4JywnMjAxNC0xMi0yNScsDQogICAgIzIwMTUNCiAgICAnMjAxNS0wMS0wMScsJzIwMTUtMDEtMTInLCcyMDE1LTAzLTIzJywnMjAxNS0wMy0yOScsJzIwMTUtMDQtMDInLCcyMDE1LTA0LTAzJywNCiAgICAnMjAxNS0wNC0wNScsJzIwMTUtMDUtMDEnLCcyMDE1LTA1LTE4JywnMjAxNS0wNi0wOCcsJzIwMTUtMDYtMTUnLCcyMDE1LTA2LTI5JywNCiAgICAnMjAxNS0wNy0yMCcsJzIwMTUtMDgtMDcnLCAnMjAxNS0wOC0xNycsJzIwMTUtMTAtMTInLCcyMDE1LTExLTAyJywnMjAxNS0xMS0xNicsDQogICAgJzIwMTUtMTItMDgnLCcyMDE1LTEyLTI1JywNCiAgICAjMjAxNg0KICAgICcyMDE2LTAxLTAxJywnMjAxNi0wMS0xMScsJzIwMTYtMDMtMjAnLCcyMDE2LTAzLTIxJywnMjAxNi0wMy0yNCcsJzIwMTYtMDMtMjUnLA0KICAgICcyMDE2LTAzLTI3JywnMjAxNi0wNS0wMScsJzIwMTYtMDUtMDknLCcyMDE2LTA1LTMwJywnMjAxNi0wNi0wNicsJzIwMTYtMDctMDQnLA0KICAgICcyMDE2LTA3LTIwJywnMjAxNi0wOC0wNycsICcyMDE2LTA4LTE1JywnMjAxNi0xMC0xNycsJzIwMTYtMTEtMDcnLCcyMDE2LTExLTE0JywNCiAgICAnMjAxNi0xMi0wOCcsJzIwMTYtMTItMjUnLA0KICAgICMyMDE3DQogICAgJzIwMTctMDEtMDEnLCcyMDE3LTAxLTA5JywnMjAxNy0wMy0yMCcsJzIwMTctMDQtMDknLCcyMDE3LTA0LTEzJywnMjAxNy0wNC0xNCcsDQogICAgJzIwMTctMDQtMTYnLCcyMDE3LTA1LTAxJywnMjAxNy0wNS0yOScsJzIwMTctMDYtMTknLCcyMDE3LTA2LTI2JywnMjAxNy0wNy0wMycsDQogICAgJzIwMTctMDctMjAnLCcyMDE3LTA4LTA3JywgJzIwMTctMDgtMjEnLCcyMDE3LTEwLTE2JywnMjAxNy0xMS0wNicsJzIwMTctMTEtMTMnLA0KICAgICcyMDE3LTEyLTA4JywnMjAxNy0xMi0yNScsDQogICAgIzIwMTgNCiAgICAnMjAxOC0wMS0wMScsJzIwMTgtMDEtMDgnLCcyMDE4LTAzLTE5JywnMjAxOC0wMy0yNScsJzIwMTgtMDMtMjknLCcyMDE4LTAzLTMwJywNCiAgICAnMjAxOC0wNC0wMScsJzIwMTgtMDUtMDEnLCcyMDE4LTA1LTE0JywnMjAxOC0wNi0wNCcsJzIwMTgtMDYtMTEnLCcyMDE4LTA3LTAyJywNCiAgICAnMjAxOC0wNy0yMCcsJzIwMTgtMDgtMDcnLCAnMjAxOC0wOC0yMCcsJzIwMTgtMTAtMTUnLCcyMDE4LTExLTA1JywnMjAxOC0xMS0xMScsDQogICAgJzIwMTgtMTItMDgnLCcyMDE4LTEyLTI1JywNCiAgICAjMjAxOQ0KICAgICcyMDE5LTAxLTAxJywnMjAxOS0wMS0wNycsJzIwMTktMDMtMjUnLCcyMDE5LTA0LTE4JywnMjAxOS0wNC0xOScsJzIwMTktMDUtMScsDQogICAgJzIwMTktMDYtMDMnLCcyMDE5LTA2LTI0JywnMjAxOS0wNy0wMScsJzIwMTktMDctMjAnLCcyMDE5LTA4LTA3JywnMjAxOS0wOC0xOScsDQogICAgJzIwMTktMTAtMTQnLCcyMDE5LTExLTA0JywnMjAxOS0xMS0xMScsJzIwMTktMTItMDgnLCcyMDE5LTEyLTI1Jw0KICAgICkpDQoNCmRmIDwtIGRmICU+JSBzZWxlY3QoQ09NVU5BLCBDTEFTRSwgRkVDSEEsIFBFUklPRE8sIE1FUywgRElBX05PTUJSRSkNCg0KZGYkRkVDSEEgPC0gYXMuRGF0ZShkZiRGRUNIQSkNCg0KIyBTZSBhZ3JlZ2EgbGEgdmFyaWFibGUgVElFTVBPIHkgTUVTX05PTUJSRQ0KZGYkTUVTX05PTUJSRSA8LSBwYXN0ZShkZiRQRVJJT0RPLCBkZiRNRVMsIHNlcD0iLSIpICU+JSBhcy55ZWFybW9uKCIlWS0lbSIpDQoNCiMgUGFyYSBvYnRlbmVyIGxhIGludmVyc2Egc2UgdXNhcsOtYTogem9vOjphcy5EYXRlKGRmJEZFQ0hBLCBvcmlnaW49IjIwMTQtMDEtMDEiKQ0KZGYkVElFTVBPX0RJQSA8LSBhcy5udW1lcmljKGFzLkRhdGUoZGYkRkVDSEEpKSAtIGFzLm51bWVyaWMoYXMuRGF0ZSgiMjAxNC0wMS0wMSIpKSArIDENCg0KIyBTZSBjcmVhIGxhIHZhcmlhYmxlIFNFTUFOQQ0KZGYgPC0gZGYgJT4lIG11dGF0ZShTRU1BTkEgPSBzdHJmdGltZShGRUNIQSwgZm9ybWF0ID0gIiVZLSVWIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIFRJRU1QT19TRU1BTkEgPSBtYXRjaChTRU1BTkEsIHNvcnQodW5pcXVlKFNFTUFOQSkpKSkNCg0KIyBTZSBjcmVhIGxhIHZhcmlhYmxlIE1FUw0KZGYgPC0gZGYgJT4lIG11dGF0ZShNRVMgPSBzdHJmdGltZShGRUNIQSwgZm9ybWF0ID0gIiVZLSVtIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIFRJRU1QT19NRVMgPSBtYXRjaChNRVMsIHNvcnQodW5pcXVlKE1FUykpKSkNCg0KIyBkw61hcyBmZXN0aXZvcw0KZGYgPC0gZGYgJT4lIG11dGF0ZShESUFfRkVTVElWTyA9IGlmZWxzZSh5bWQoRkVDSEEpICVpbiUgZmVzdGl2b3MsMSwwKSkNCg0KIyBhY2NpZGVudGFsaWRhZA0KZGYgPC0gZGYgJT4lIG11dGF0ZShBQ0NJREVOVEFMSURBRCA9IDEpDQpgYGANCg0KDQojIyBNb2RlbG9zIHByZWRpY3Rpdm9zIHBhcmEgbGFzIENvbXVuYXMNCg0KUGFyYSBvYnRlbmVyIGxhIGJhc2UgZGF0b3MgZW4gbGEgY3VhbCBzZSBlbmN1ZW50cmUgZWwgbsO6bWVybyBkZSBhY2NpZGVudGVzIHBhcmEgY2FkYSBldmVudG8gY29uc2lkZXJhZG8sIHNlIGNyZWEgdW5hIGJhc2UgZGUgZGF0b3MgY29uIHRvZG9zIGxvcyBldmVudG9zIHBvc2libGVzIGNvbiBheXVkYSBkZSBsYSBmdW5jacOzbiBgZXhwYW5kLmdyaWRgLCBlbiBsYSBjdWFsIHNlIHRpZW5lIGVuIGN1ZW50YSB0b2RhcyBsYSBjb21iaW5hY2lvbmVzIGRlIGNvbXVuYSwgY2xhc2UgKHRpcG8gZGUgYWNjaWRlbnRlKSB5IGZlY2hhLg0KDQpgYGB7ciwgZXZhbCA9IEZ9DQpmZWNoYV92ZWN0b3IgPC0gYXMuRGF0ZShhcy5EYXRlKCIyMDE0LTAxLTAxIik6YXMuRGF0ZSgiMjAxOC0xMi0zMSIpKQ0KYmFzZSA8LSBleHBhbmQuZ3JpZChDT01VTkEgPSBsZXZlbHMoZGYkQ09NVU5BKSwgQ0xBU0UgPSBsZXZlbHMoZGYkQ0xBU0UpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGRUNIQSA9IGZlY2hhX3ZlY3RvcikNCmJhc2UgPC0gYmFzZSAlPiUgbXV0YXRlKFRJRU1QT19ESUEgPSBhcy5udW1lcmljKEZFQ0hBKSAtDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWMoYXMuRGF0ZSgiMjAxNC0wMS0wMSIpKSArIDEpDQoNCiMgUEVSSU9ETw0KYmFzZSA8LSBiYXNlICU+JSBtdXRhdGUoUEVSSU9ETyA9IGFzLm51bWVyaWMoZm9ybWF0KEZFQ0hBLCclWScpKSkNCg0KIyBTZSBjcmVhIGxhIHZhcmlhYmxlIFNFTUFOQQ0KYmFzZSA8LSBiYXNlICU+JSBtdXRhdGUoU0VNQU5BID0gc3RyZnRpbWUoRkVDSEEsIGZvcm1hdCA9ICIlWS0lViIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBUSUVNUE9fU0VNQU5BID0gbWF0Y2goU0VNQU5BLCBzb3J0KHVuaXF1ZShTRU1BTkEpKSkpDQoNCiMgU2UgY3JlYSBsYSB2YXJpYWJsZSBNRVMNCmJhc2UgPC0gYmFzZSAlPiUgbXV0YXRlKE1FUyA9IHN0cmZ0aW1lKEZFQ0hBLCBmb3JtYXQgPSAiJVktJW0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgVElFTVBPX01FUyA9IG1hdGNoKE1FUywgc29ydCh1bmlxdWUoTUVTKSkpKQ0KDQojIGTDrWFzIGZlc3Rpdm9zDQpiYXNlIDwtIGJhc2UgJT4lIG11dGF0ZShESUFfRkVTVElWTyA9IGlmZWxzZSh5bWQoRkVDSEEpICVpbiUgZmVzdGl2b3MsMSwwKSkNCmBgYA0KDQpMdWVmbyBzZSByZWFsaXphIHVuICpsZWZ0IGpvaW4qIGNvbiBsYSBiYXNlIHF1ZSBjb250aWVuZSB0b2RvcyBsb3MgcG9zaWJsZXMgZXZlbnRvcyB5IGxhIGJhc2UgZGUgZGF0b3MgcXVlIGNvbnRpZW5lIGxhIGluZm9ybWFjacOzbiBkZSBsb3MgYWNjaWRlbnRlcyAoYmFzZSBkZXB1cmFkYSkuDQoNCmBgYHtyLCBldmFsID0gRn0NCmJhc2UgPC0gbGVmdF9qb2luKGJhc2UsIHN1YnNldChkZiwgc2VsZWN0ID0gLURJQV9OT01CUkUpLA0KICAgICAgICAgICAgICAgICAgYnkgPSBjKCJDT01VTkEiLCAiQ0xBU0UiLCAiRkVDSEEiLCAiVElFTVBPX0RJQSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUEVSSU9ETyIsICJTRU1BTkEiLCAiVElFTVBPX1NFTUFOQSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVElFTVBPX01FUyIsICJESUFfRkVTVElWTyIpKQ0KYmFzZVtpcy5uYShiYXNlKV0gPC0gMA0KDQphY2NpZGVudGVzX2RpYV9jb211bmEgPC0gbGVmdF9qb2luKGJhc2UsIGRpc3RpbmN0KGRmWywgYygiRkVDSEEiLCAiRElBX05PTUJSRSIpXSksIGJ5ID0gIkZFQ0hBIikNCmBgYA0KDQojIyMgTW9kZWxvcyAtIHVuaWRhZCBkZSB0aWVtcG8gRMOtYQ0KDQpMYSBiYXNlIGRlIGRhdG9zIGNvbiBlbCBuw7ptZXJvIGRlIGFjY2lkZW50ZXMgcG9yIGNvbXVuYSwgY2xhc2UgeSBkw61hIHNlIG9idHV2byBhbnRlcmlvcm1lbnRlLCDDqXN0YSBjb250aWVuZSAxNzUyOTYgb2JzZXJ2YWNpb25lcy4NCg0KYGBge3IsIGluY2x1ZGUgPSBGfQ0KbG9hZChmaWxlID0gImFjY2lkZW50ZXNfZGlhX2NvbXVuYS5SRGF0YSIpICMgYmFzZSBkZSBkYXRvcw0KYGBgDQoNCmBgYHtyfQ0KZGltKGFjY2lkZW50ZXNfZGlhX2NvbXVuYSkNCmBgYA0KDQpMYSBiYXNlIGx1Y2UgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KYGBge3IsIGVjaG89RkFMU0UsIHJvd3MucHJpbnQgPSA1fQ0KYWNjaWRlbnRlc19kaWFfY29tdW5hIDwtIHN1YnNldChhY2NpZGVudGVzX2RpYV9jb211bmEsIHNlbGVjdD1jKDEsMiwzLDEyLDQsNSw2LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDcsOCw5LDEwLDExKSkNCmFjY2lkZW50ZXNfZGlhX2NvbXVuYQ0KYGBgDQoNClNlIHJlYWxpemEgbGEgcGFydGljacOzbiBkZSBsb3MgZGF0b3MgcGFyYSBzZWxlY2Npb25hciBlbCBjb25qdW50byBkZSBlbnRyZW5hbWllbnRvIHkgZWwgY29uanVudG8gZGUgcHJ1ZWJhLg0KDQpgYGB7cn0NCnRlc3RfZGlhX2NvbXVuYSA8LSBhY2NpZGVudGVzX2RpYV9jb211bmFbYWNjaWRlbnRlc19kaWFfY29tdW5hJFBFUklPRE8gPT0gMjAxOCwgXQ0KdHJhaW5fZGlhX2NvbXVuYSA8LSBhY2NpZGVudGVzX2RpYV9jb211bmFbYWNjaWRlbnRlc19kaWFfY29tdW5hJFBFUklPRE8gJWluJQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcpLCBdDQpgYGANCg0KU2UgcHJvY2VkZSBhIGxhIGNyZWFjacOzbiBkZSBtb2RlbG9zOg0KDQpTZSBjb25zaWRlcmFuIGRpc3RpbnRvcyBtb2RlbG9zIHBhcnRpZW5kbyBkZSB1biBtb2RlbG8gamVyw6FycXVpY28gY29uIDIgbml2ZWxlcyAoQ0xBU0UgeSBDT01VTkEpIGNvbiBzb2xvIHVuIGludGVyY2VwdG8sIGFtYm9zIG5pdmVsZXMgbyB2YXJpYWJsZXMgY29uIGVmZWN0b3MgYWxlYXRvcmlvcyBzZSBjb25zaWRlcmFuIGNvcnJlbGFjaW9uYWRvcyB5IHNlIHBvbmRyw6EgbGEgdmFyaWFibGUgQ0xBU0UgKHRpcG8gZGUgYWNjaWRlbnRlKSBkZW50cm8gZGUgbGEgdmFyaWFibGUgY29tdW5hLg0KDQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0NCmxvYWQoZmlsZSA9ICJtb2RfZGlhX2NvbXVuYTAuUkRhdGEiKQ0KbG9hZChmaWxlID0gIm1vZF9kaWFfY29tdW5hMS5SRGF0YSIpDQpsb2FkKGZpbGUgPSAibW9kX2RpYV9jb211bmEyLlJEYXRhIikNCmxvYWQoZmlsZSA9ICJtb2RfZGlhX2NvbXVuYTMuUkRhdGEiKQ0KbG9hZChmaWxlID0gIm1vZF9kaWFfY29tdW5hNC5SRGF0YSIpDQpgYGANCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCm1vZF9kaWFfY29tdW5hMCA8LSBnbG1lcihBQ0NJREVOVEFMSURBRCB+IDEgKyAoMSB8IENPTVVOQS9DTEFTRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2RpYV9jb211bmEsIGZhbWlseT0gcG9pc3NvbigpKQ0KbW9kX2RpYV9jb211bmExIDwtIGdsbWVyKEFDQ0lERU5UQUxJREFEIH4gRElBX0ZFU1RJVk8gKyAoMSB8IENPTVVOQS9DTEFTRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX2RpYV9jb211bmEsIGZhbWlseT0gcG9pc3NvbigpKQ0KbW9kX2RpYV9jb211bmEyIDwtIGdsbWVyKEFDQ0lERU5UQUxJREFEIH4gRElBX0ZFU1RJVk8gKyBUSUVNUE9fRElBICsgKDEgfCBDT01VTkEvQ0xBU0UpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kaWFfY29tdW5hLCBmYW1pbHk9IHBvaXNzb24oKSkNCm1vZF9kaWFfY29tdW5hMyA8LSBnbG1lcihBQ0NJREVOVEFMSURBRCB+IERJQV9GRVNUSVZPICsgRElBX05PTUJSRSArICgxIHwgQ09NVU5BL0NMQVNFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fZGlhX2NvbXVuYSwgZmFtaWx5PSBwb2lzc29uKCkpDQptb2RfZGlhX2NvbXVuYTQgPC0gZ2xtZXIoQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArIERJQV9OT01CUkUgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgKDEgKyBESUFfRkVTVElWT3wgQ09NVU5BL0NMQVNFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fZGlhX2NvbXVuYSwgZmFtaWx5PSBwb2lzc29uKCkpDQpgYGANCg0KU2UgY29tcGFyYW4gbG9zIG1vZGVsb3MgcG9yIHVuIGFuYWzDrXNpcyBkZSB2YXJpYW56YSBBTk9WQToNCg0KYGBge3J9DQphbm92YShtb2RfZGlhX2NvbXVuYTAsIG1vZF9kaWFfY29tdW5hMSwgbW9kX2RpYV9jb211bmEyLCBtb2RfZGlhX2NvbXVuYTMsIG1vZF9kaWFfY29tdW5hNCkNCmBgYA0KDQpBbCBwYXJlY2VyIGNhZGEgbW9kZWxvIGV4cGxpY2EgbWVqb3IgbGEgYWNjaWRlbnRhbGlkYWQgcXVlIGVsIGFudGVyaW9yLCBwZXJvIHNlIGRlYmUgcmVjb3JkYXIgcXVlIGVsICpWYWxvci1QKiBlcyBzZW5zaWJsZSBhbCBuw7ptZXJvIGRlIGRhdG9zLiBFbiBsYSBiYXNlIGRlIGVudHJlbmFtaWVudG8gaGF5IDE0MDI1NiBvYnNlcnZhY2lvbmVzLCBlc3RvIHNlIGNvbnNpZGVyYSBncmFuZGUsIHBvciBsbyBxdWUgbm8gaGF5IHF1ZSBmaWphcnNlIG11Y2hvIGVuIGVsICpWYWxvci1QKiBkYWRvIHF1ZSBlcyBtw6FzIGbDoWNpbCBxdWUgcmVjaGFjZSBsYXMgaGlww7N0ZXNpcyBudWxhcy4NCg0KU2UgcHJvY2VkZSBhIGNhbGN1bGFyIGVsIE1TRSBkZSBlbnRyZW5hbWllbnRvIHkgZGUgcHJ1ZWJhIGVuIGNhZGEgdW5vIGRlIGxvcyBtb2RlbG9zLCBjYWJlIHJlc2FsdGFyIHF1ZSBsb3MgdmFsb3JlcyBwcmVkaWNob3Mgc2UgcmVkb25kZWFyw6FuIGFsIGVudGVybyBtw6FzIGNlcmNhbm8gZGViaWRvIGEgcXVlIHNvbiBkYXRvcyBkZSBjb250ZW8geSBsYSBmdW5jacOzbiBgcHJlZGljdGAgZGV2dWVsdmUgdmFsb3JlcyBlbiBsYSBlc2NhbGEgb3JpZ2luYWwgcGVybyBjb24gZMOpY2ltYWxlcy4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIE1vZGVsbyAwDQp5X2VzdF90cmFpbl9kaWFfY29tdW5hMCA8LSByb3VuZChwcmVkaWN0KG1vZF9kaWFfY29tdW5hMCwgbmV3ZGF0YSA9IHRyYWluX2RpYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9kaWFfY29tdW5hMCA8LSByb3VuZChwcmVkaWN0KG1vZF9kaWFfY29tdW5hMCwgbmV3ZGF0YSA9IHRlc3RfZGlhX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCm1zZV90cmFpbl9kaWFfY29tdW5hMCA8LSByb3VuZChNU0UodHJhaW5fZGlhX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fZGlhX2NvbXVuYTApLDQpDQptc2VfdGVzdF9kaWFfY29tdW5hMCA8LSByb3VuZChNU0UodGVzdF9kaWFfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdGVzdF9kaWFfY29tdW5hMCksNCkNCg0KIyBNb2RlbG8gMQ0KeV9lc3RfdHJhaW5fZGlhX2NvbXVuYTEgPC0gcm91bmQocHJlZGljdChtb2RfZGlhX2NvbXVuYTEsIG5ld2RhdGEgPSB0cmFpbl9kaWFfY29tdW5hLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCnlfZXN0X3Rlc3RfZGlhX2NvbXVuYTEgPC0gcm91bmQocHJlZGljdChtb2RfZGlhX2NvbXVuYTEsIG5ld2RhdGEgPSB0ZXN0X2RpYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQptc2VfdHJhaW5fZGlhX2NvbXVuYTEgPC0gcm91bmQoTVNFKHRyYWluX2RpYV9jb211bmEkQUNDSURFTlRBTElEQUQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3RyYWluX2RpYV9jb211bmExKSw0KQ0KbXNlX3Rlc3RfZGlhX2NvbXVuYTEgPC0gcm91bmQoTVNFKHRlc3RfZGlhX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2VzdF90ZXN0X2RpYV9jb211bmExKSw0KQ0KDQojIE1vZGVsbyAyDQp5X2VzdF90cmFpbl9kaWFfY29tdW5hMiA8LSByb3VuZChwcmVkaWN0KG1vZF9kaWFfY29tdW5hMiwgbmV3ZGF0YSA9IHRyYWluX2RpYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9kaWFfY29tdW5hMiA8LSByb3VuZChwcmVkaWN0KG1vZF9kaWFfY29tdW5hMiwgbmV3ZGF0YSA9IHRlc3RfZGlhX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCm1zZV90cmFpbl9kaWFfY29tdW5hMiA8LSByb3VuZChNU0UodHJhaW5fZGlhX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fZGlhX2NvbXVuYTIpLDQpDQptc2VfdGVzdF9kaWFfY29tdW5hMiA8LSByb3VuZChNU0UodGVzdF9kaWFfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3Rlc3RfZGlhX2NvbXVuYTIpLDQpDQoNCiMgTW9kZWxvIDMNCnlfZXN0X3RyYWluX2RpYV9jb211bmEzIDwtIHJvdW5kKHByZWRpY3QobW9kX2RpYV9jb211bmEzLCBuZXdkYXRhID0gdHJhaW5fZGlhX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQp5X2VzdF90ZXN0X2RpYV9jb211bmEzIDwtIHJvdW5kKHByZWRpY3QobW9kX2RpYV9jb211bmEzLCBuZXdkYXRhID0gdGVzdF9kaWFfY29tdW5hLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KbXNlX3RyYWluX2RpYV9jb211bmEzIDwtIHJvdW5kKE1TRSh0cmFpbl9kaWFfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2VzdF90cmFpbl9kaWFfY29tdW5hMyksNCkNCm1zZV90ZXN0X2RpYV9jb211bmEzIDwtIHJvdW5kKE1TRSh0ZXN0X2RpYV9jb211bmEkQUNDSURFTlRBTElEQUQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdGVzdF9kaWFfY29tdW5hMyksNCkNCg0KIyBNb2RlbG8gNA0KeV9lc3RfdHJhaW5fZGlhX2NvbXVuYTQgPC0gcm91bmQocHJlZGljdChtb2RfZGlhX2NvbXVuYTQsIG5ld2RhdGEgPSB0cmFpbl9kaWFfY29tdW5hLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCnlfZXN0X3Rlc3RfZGlhX2NvbXVuYTQgPC0gcm91bmQocHJlZGljdChtb2RfZGlhX2NvbXVuYTQsIG5ld2RhdGEgPSB0ZXN0X2RpYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQptc2VfdHJhaW5fZGlhX2NvbXVuYTQgPC0gcm91bmQoTVNFKHRyYWluX2RpYV9jb211bmEkQUNDSURFTlRBTElEQUQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3RyYWluX2RpYV9jb211bmE0KSw0KQ0KbXNlX3Rlc3RfZGlhX2NvbXVuYTQgPC0gcm91bmQoTVNFKHRlc3RfZGlhX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2VzdF90ZXN0X2RpYV9jb211bmE0KSw0KQ0KDQpgYGANCg0KDQpgYGB7ciwgaW5jbHVkZSA9IEZ9DQp5X2VzdF90cmFpbl9kaWFfY29tdW5hNCA8LSByb3VuZChwcmVkaWN0KG1vZF9kaWFfY29tdW5hNCwgbmV3ZGF0YSA9IHRyYWluX2RpYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9kaWFfY29tdW5hNCA8LSByb3VuZChwcmVkaWN0KG1vZF9kaWFfY29tdW5hNCwgbmV3ZGF0YSA9IHRlc3RfZGlhX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCm1zZV90cmFpbl9kaWFfY29tdW5hNCA8LSByb3VuZChNU0UodHJhaW5fZGlhX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fZGlhX2NvbXVuYTQpLDQpDQptc2VfdGVzdF9kaWFfY29tdW5hNCA8LSByb3VuZChNU0UodGVzdF9kaWFfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3Rlc3RfZGlhX2NvbXVuYTQpLDQpDQpgYGANCg0KDQpgYGB7ciwgaW5jbHVkZT1GLCBldmFsID0gRn0NCm1zZV9jb211bmFfZGlhIDwtIGRhdGEuZnJhbWUoTW9kZWxvX01peHRvX1BvaXNzb24gPSBjKCJBQ0NJREVOVEFMSURBRCB+IDEgKyAoMSB8IENPTVVOQS9DTEFTRSkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFDQ0lERU5UQUxJREFEIH4gRElBX0ZFU1RJVk8gKyAoMSB8IENPTVVOQS9DTEFTRSkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFDQ0lERU5UQUxJREFEIH4gRElBX0ZFU1RJVk8gKyBUSUVNUE9fRElBICsgKDEgfCBDT01VTkEvQ0xBU0UpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBQ0NJREVOVEFMSURBRCB+IERJQV9GRVNUSVZPICsgRElBX05PTUJSRSArICgxIHwgQ09NVU5BL0NMQVNFKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArIERJQV9OT01CUkUgKyAoMSArIERJQV9GRVNUSVZPIHwgQ09NVU5BL0NMQVNFKSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgVHJhaW5fTVNFID0gYyhtc2VfdHJhaW5fZGlhX2NvbXVuYTAsIG1zZV90cmFpbl9kaWFfY29tdW5hMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNlX3RyYWluX2RpYV9jb211bmEyLCBtc2VfdHJhaW5fZGlhX2NvbXVuYTMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zZV90cmFpbl9kaWFfY29tdW5hNCksDQogICAgICAgICAgICAgICAgICAgICAgICBUZXN0X01TRSA9IGMobXNlX3Rlc3RfZGlhX2NvbXVuYTAsIG1zZV90ZXN0X2RpYV9jb211bmExLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zZV90ZXN0X2RpYV9jb211bmEyLCBtc2VfdGVzdF9kaWFfY29tdW5hMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtc2VfdGVzdF9kaWFfY29tdW5hNCkpDQptc2VfY29tdW5hX2RpYSA8LSBtc2VfY29tdW5hX2RpYSAlPiUNCiAgbXV0YXRlKFBvcmNlbnRhamVfVmFyaWFjaW9uID0gcm91bmQoMTAwKmFicyhUcmFpbl9NU0UtVGVzdF9NU0UpLyhUcmFpbl9NU0UrVGVzdF9NU0UpLCAyKSkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZSA9IEZ9DQpsb2FkKGZpbGUgPSAibXNlX2NvbXVuYV9kaWEuUkRhdGEiKQ0KYGBgDQoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjprYWJsZShtc2VfY29tdW5hX2RpYSkNCmBgYA0KDQpFbiBsb3MgbW9kZWxvcyAqbW9kX2RpYV9jb211bmEzKiB5ICptb2RfZGlhX2NvbXVuYTQqIHNlIGRlc2NhcnRhIHVzYXIgbGEgdmFyaWFibGUgVElFTVBPX0RJQSBkZWJpZG8gYSBxdWUgZW4gbHVnYXIgZW4gZGlzbWludWlyIGVsIFRlc3RfTVNFLCBsbyBhdW1lbnTDsywgeSB0YW1wb2NvIG1lam9yw7MgZWwgVHJhaW5fTVNFIHNpZ25pZmljYXRpdmFtZW50ZSwgcG9yIGxvIHF1ZSBzZSBjb25zaWRlcmEgcXVlIG5vIGVzIHNpZ25pZmljYXRpdmEgcGFyYSBleHBsaWNhciBsYSBhY2NpZGVudGFsaWRhZCBlbiBsYXMgY29tdW5hcyBkZSBNZWRlbGzDrW4gcG9yIHRpcG8gZGUgYWNjaWRlbnRlLg0KDQpGaW5hbG1lbnRlIHNlIG9ic2VydmEgcXVlIGVsIG1vZGVsbyBjb24gaW50ZXJjZXB0byB5IHBlbmRpZW50ZSBhbGVhdG9yaWEgKiptb2RfZGlhX2NvbXVuYTQqKjoNCg0KJCRcd2lkZWhhdHtcdGV4dHtBQ0NJREVOVEFMSURBRH19ID0gXHRleHR7RElBX0ZFU1RJVk99ICsgXHRleHR7RElBX05PTUJSRX0gKyAoMSArIFx0ZXh0e0RJQV9GRVNUSVZPfSB8IFx0ZXh0e0NPTVVOQS9DTEFTRX0pJCQNCg0KRXMgZWwgcXVlIG9idGllbmUgZWwgbWVub3IgKlRyYWluX01TRSogeSAqVGVzdF9NU0UqLCBwb3IgbG8gcXVlIHNlIGVzY29nZSBlc3RlIG1vZGVsbyBwYXJhIGxhIGV4cGxpY2FjacOzbiBkZSBsYSBhY2NpZGVudGFsaWRhZCBlbiBjb211bmEgcG9yIGTDrWEuDQoNCkEgY29udGludWFjacOzbiBzZSBtdWVzdHJhbiBhbGd1bm9zIGRlIGxvcyB2YWxvcmVzIG9ic2VydmFkb3MgZGUgbGEgYWNjaWRlbnRhbGlkYWQgZGlhcmlhIHBvciBjbGFzZSB5IHBvciBjb211bmEsIGNvbiBzdSByZXNwZWN0aXZvIHZhbG9yIHByZWRpY2hvIMO6bHRpbWEgY29sdW1uYSkgZW4gZWwgY29uanVudG8gZGUgcHJ1ZWJhLg0KDQpgYGB7ciwgcm93cy5wcmludCA9IDUsIGVjaG8gPSBGfQ0KZGF0YS5mcmFtZSh0ZXN0X2RpYV9jb211bmEsIEEuUFJFRElDSEEgPSB5X2VzdF90ZXN0X2RpYV9jb211bmE0KQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZ9DQpyZW1vdmUoeV9lc3RfdHJhaW5fZGlhX2NvbXVuYTAsIHlfZXN0X3RyYWluX2RpYV9jb211bmExLCB5X2VzdF90cmFpbl9kaWFfY29tdW5hMiwgeV9lc3RfdHJhaW5fZGlhX2NvbXVuYTMsIHlfZXN0X3RyYWluX2RpYV9jb211bmE0LCB5X2VzdF90ZXN0X2RpYV9jb211bmEwLCB5X2VzdF90ZXN0X2RpYV9jb211bmExLCB5X2VzdF90ZXN0X2RpYV9jb211bmEyLCB5X2VzdF90ZXN0X2RpYV9jb211bmEzLCB5X2VzdF90ZXN0X2RpYV9jb211bmE0LG1zZV90cmFpbl9kaWFfY29tdW5hMCxtc2VfdHJhaW5fZGlhX2NvbXVuYTEsbXNlX3RyYWluX2RpYV9jb211bmEyLG1zZV90cmFpbl9kaWFfY29tdW5hMyxtc2VfdHJhaW5fZGlhX2NvbXVuYTQsbXNlX3Rlc3RfZGlhX2NvbXVuYTAsbXNlX3Rlc3RfZGlhX2NvbXVuYTEsbXNlX3Rlc3RfZGlhX2NvbXVuYTIsbXNlX3Rlc3RfZGlhX2NvbXVuYTMsbXNlX3Rlc3RfZGlhX2NvbXVuYTQpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9Rn0NCnJlbW92ZShtb2RfZGlhX2NvbXVuYTAsIG1vZF9kaWFfY29tdW5hMSwgbW9kX2RpYV9jb211bmEyLCBtb2RfZGlhX2NvbXVuYTMsIG1vZF9kaWFfY29tdW5hNCkNCmBgYA0KDQoNCiMjIyBNb2RlbG9zIC0gdW5pZGFkIGRlIHRpZW1wbyBTZW1hbmENCg0KUGFyYSBlc3RlIG1vZGVsbyBzZSBhZ3J1cGEgbGEgdW5pZGFkIGRlIHRpZW1wbyBwb3Igc2VtYW5hcywgZW4gbGFzIGN1YWxlcyBzZSBzdW1hIGxhIGNhbnRpZGFkIGRlIGFjY2lkZW50ZXMgcXVlIHN1Y2VkZW4gZWwgbGEgbWlzbWEsIHRhbWJpw6luIHNlIHN1bWEgZWwgbsO6bWVybyBkZSBkw61hcyBmZXN0aXZvcy4gTGEgYmFzZSBsdWNlIGNvbW8gc2lndWU6DQoNCmBgYHtyLCByb3dzLnByaW50ID0gNX0NCmFjY2lkZW50ZXNfc2VtYW5hX2NvbXVuYSA8LSBhY2NpZGVudGVzX2RpYV9jb211bmEgJT4lDQogIGdyb3VwX2J5KENPTVVOQSwgQ0xBU0UsIFBFUklPRE8sIFNFTUFOQSwgVElFTVBPX1NFTUFOQSkgJT4lDQogIHN1bW1hcmlzZShESUFfRkVTVElWTyA9IHN1bShESUFfRkVTVElWTyksIEFDQ0lERU5UQUxJREFEID0gc3VtKEFDQ0lERU5UQUxJREFEKSkNCg0KYWNjaWRlbnRlc19zZW1hbmFfY29tdW5hDQpgYGANCg0KDQpTZSBwcm9jZWRlIGEgcmVhbGl6YXIgbGEgcGFydGljacOzbiBkZWwgY29uanVudG8gZGUgZW50cmVuYW1pZW50byB5IGVsIGNvbmp1bnRvIGRlIHBydWViYToNCg0KYGBge3J9DQp0ZXN0X3NlbWFuYV9jb211bmEgPC0gYWNjaWRlbnRlc19zZW1hbmFfY29tdW5hW2FjY2lkZW50ZXNfc2VtYW5hX2NvbXVuYSRQRVJJT0RPID09IDIwMTgsIF0NCnRyYWluX3NlbWFuYV9jb211bmEgPC0gYWNjaWRlbnRlc19zZW1hbmFfY29tdW5hW2FjY2lkZW50ZXNfc2VtYW5hX2NvbXVuYSRQRVJJT0RPICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygyMDE0LCAyMDE1LCAyMDE2LCAyMDE3KSwgXQ0KYGBgDQoNCkFob3JhIHNlIGFqdXN0YW4gbG9zIG1vZGVsb3MgbWl4dG9zIGNvbiBlZmVjdG9zIGFsZWF0b3Jpb3MgZW4gQ09NVU5BIHkgQ0xBU0UgYWwgaWd1YWwgcXVlIHNlIGhpem8gYSBuaXZlbCBkaWFyaW8sIGVzIGRlY2lyLCBDTEFTRSBkZW50cm8gZGUgQ09NVU5BLg0KDQpgYGB7ciwgZWNobz1GfQ0KbG9hZChmaWxlID0gIm1vZF9zZW1hbmFfY29tdW5hMC5SRGF0YSIpDQpsb2FkKGZpbGUgPSAibW9kX3NlbWFuYV9jb211bmExLlJEYXRhIikNCmxvYWQoZmlsZSA9ICJtb2Rfc2VtYW5hX2NvbXVuYTIuUkRhdGEiKQ0KbG9hZChmaWxlID0gIm1vZF9zZW1hbmFfY29tdW5hMy5SRGF0YSIpDQpgYGANCg0KYGBge3IsIGV2YWwgPSBGfQ0KbW9kX3NlbWFuYV9jb211bmEwIDwtIGdsbWVyKEFDQ0lERU5UQUxJREFEIH4gIDEgKyAoMSB8IENPTVVOQS9DTEFTRSksDQogICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fc2VtYW5hX2NvbXVuYSwgZmFtaWx5PSBwb2lzc29uKCkpDQptb2Rfc2VtYW5hX2NvbXVuYTEgPC0gZ2xtZXIoQUNDSURFTlRBTElEQUQgfiAgRElBX0ZFU1RJVk8gKyAoMSB8IENPTVVOQS9DTEFTRSksDQogICAgICAgICAgICAgICBkYXRhID0gdHJhaW5fc2VtYW5hX2NvbXVuYSwgZmFtaWx5PSBwb2lzc29uKCkpDQptb2Rfc2VtYW5hX2NvbXVuYTIgPC0gZ2xtZXIoQUNDSURFTlRBTElEQUQgfiAgRElBX0ZFU1RJVk8gKyBUSUVNUE9fU0VNQU5BICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgxIHwgQ09NVU5BL0NMQVNFKSwNCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9zZW1hbmFfY29tdW5hLCBmYW1pbHk9IHBvaXNzb24oKSkNCm1vZF9zZW1hbmFfY29tdW5hMyA8LSBnbG1lcihBQ0NJREVOVEFMSURBRCB+ICBESUFfRkVTVElWTyArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoMSArIERJQV9GRVNUSVZPIHwgQ09NVU5BL0NMQVNFKSwNCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9zZW1hbmFfY29tdW5hLCBmYW1pbHk9IHBvaXNzb24oKSkNCmBgYA0KDQpTZSBjb21wYXJhbiBsb3MgbW9kZWxvcyBwb3IgdW4gYW5hbMOtc2lzIGRlIHZhcmlhbnphIEFOT1ZBOg0KDQpgYGB7cn0NCmFub3ZhKG1vZF9zZW1hbmFfY29tdW5hMCwgbW9kX3NlbWFuYV9jb211bmExLCBtb2Rfc2VtYW5hX2NvbXVuYTIsIG1vZF9zZW1hbmFfY29tdW5hMykNCmBgYA0KDQpTZSB0aWVuZSBlbCBtaXNtbyBwcm9ibGVtYSBkZWwgdGFtYcOxbyBkZSBtdWVzdHJhIHF1ZSBlbiBlbCBtb2RlbG8gZGlhcmlvLiBBaG9yYSwgc2UgcHJvY2VkZSBhIGNhbGN1bGFyIGVsIE1TRSBkZSBlbnRyZW5hbWllbnRvIHkgZGUgcHJ1ZWJhIGVuIGNhZGEgdW5vIGRlIGxvcyBtb2RlbG9zLCBjYWJlIHJlc2FsdGFyIHF1ZSBsb3MgdmFsb3JlcyBwcmVkaWNob3Mgc2UgcmVkb25kZWFyw6FuIGFsIGVudGVybyBtw6FzIGNlcmNhbm8gZGViaWRvIGEgcXVlIHNvbiBkYXRvcyBkZSBjb250ZW8geSBsYSBmdW5jacOzbiBgcHJlZGljdGAgZGV2dWVsdmUgdmFsb3JlcyBlbiBsYSBlc2NhbGEgb3JpZ2luYWwgcGVybyBjb24gZMOpY2ltYWxlcy4NCg0KYGBge3J9DQojIE1vZGVsbyAwDQp5X2VzdF90cmFpbl9zZW1hbmFfY29tdW5hMCA8LSByb3VuZChwcmVkaWN0KG1vZF9zZW1hbmFfY29tdW5hMCwgbmV3ZGF0YSA9IHRyYWluX3NlbWFuYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9zZW1hbmFfY29tdW5hMCA8LSByb3VuZChwcmVkaWN0KG1vZF9zZW1hbmFfY29tdW5hMCwgbmV3ZGF0YSA9IHRlc3Rfc2VtYW5hX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCm1zZV90cmFpbl9zZW1hbmFfY29tdW5hMCA8LSByb3VuZChNU0UodHJhaW5fc2VtYW5hX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fc2VtYW5hX2NvbXVuYTApLDQpDQptc2VfdGVzdF9zZW1hbmFfY29tdW5hMCA8LSByb3VuZChNU0UodGVzdF9zZW1hbmFfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdGVzdF9zZW1hbmFfY29tdW5hMCksNCkNCg0KIyBNb2RlbG8gMQ0KeV9lc3RfdHJhaW5fc2VtYW5hX2NvbXVuYTEgPC0gcm91bmQocHJlZGljdChtb2Rfc2VtYW5hX2NvbXVuYTEsIG5ld2RhdGEgPSB0cmFpbl9zZW1hbmFfY29tdW5hLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCnlfZXN0X3Rlc3Rfc2VtYW5hX2NvbXVuYTEgPC0gcm91bmQocHJlZGljdChtb2Rfc2VtYW5hX2NvbXVuYTEsIG5ld2RhdGEgPSB0ZXN0X3NlbWFuYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQptc2VfdHJhaW5fc2VtYW5hX2NvbXVuYTEgPC0gcm91bmQoTVNFKHRyYWluX3NlbWFuYV9jb211bmEkQUNDSURFTlRBTElEQUQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3RyYWluX3NlbWFuYV9jb211bmExKSw0KQ0KbXNlX3Rlc3Rfc2VtYW5hX2NvbXVuYTEgPC0gcm91bmQoTVNFKHRlc3Rfc2VtYW5hX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2VzdF90ZXN0X3NlbWFuYV9jb211bmExKSw0KQ0KDQojIE1vZGVsbyAyDQp5X2VzdF90cmFpbl9zZW1hbmFfY29tdW5hMiA8LSByb3VuZChwcmVkaWN0KG1vZF9zZW1hbmFfY29tdW5hMiwgbmV3ZGF0YSA9IHRyYWluX3NlbWFuYV9jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9zZW1hbmFfY29tdW5hMiA8LSByb3VuZChwcmVkaWN0KG1vZF9zZW1hbmFfY29tdW5hMiwgbmV3ZGF0YSA9IHRlc3Rfc2VtYW5hX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCm1zZV90cmFpbl9zZW1hbmFfY29tdW5hMiA8LSByb3VuZChNU0UodHJhaW5fc2VtYW5hX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fc2VtYW5hX2NvbXVuYTIpLDQpDQptc2VfdGVzdF9zZW1hbmFfY29tdW5hMiA8LSByb3VuZChNU0UodGVzdF9zZW1hbmFfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3Rlc3Rfc2VtYW5hX2NvbXVuYTIpLDQpDQoNCiMgTW9kZWxvIDMNCnlfZXN0X3RyYWluX3NlbWFuYV9jb211bmEzIDwtIHJvdW5kKHByZWRpY3QobW9kX3NlbWFuYV9jb211bmEzLCBuZXdkYXRhID0gdHJhaW5fc2VtYW5hX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQp5X2VzdF90ZXN0X3NlbWFuYV9jb211bmEzIDwtIHJvdW5kKHByZWRpY3QobW9kX3NlbWFuYV9jb211bmEzLCBuZXdkYXRhID0gdGVzdF9zZW1hbmFfY29tdW5hLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KbXNlX3RyYWluX3NlbWFuYV9jb211bmEzIDwtIHJvdW5kKE1TRSh0cmFpbl9zZW1hbmFfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2VzdF90cmFpbl9zZW1hbmFfY29tdW5hMyksNCkNCm1zZV90ZXN0X3NlbWFuYV9jb211bmEzIDwtIHJvdW5kKE1TRSh0ZXN0X3NlbWFuYV9jb211bmEkQUNDSURFTlRBTElEQUQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdGVzdF9zZW1hbmFfY29tdW5hMyksNCkNCmBgYA0KDQoNCg0KYGBge3IsIGluY2x1ZGU9Rn0NCmRhdG9zX21zZSA8LSBkYXRhLmZyYW1lKE1vZGVsb19NaXh0b19Qb2lzc29uID0gYygiQUNDSURFTlRBTElEQUQgfiAxICsgKDEgfCBDT01VTkEvQ0xBU0UpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBQ0NJREVOVEFMSURBRCB+IERJQV9GRVNUSVZPICsgKDEgfCBDT01VTkEvQ0xBU0UpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBQ0NJREVOVEFMSURBRCB+IERJQV9GRVNUSVZPICsgVElFTVBPX1NFTUFOQSArICgxIHwgQ09NVU5BL0NMQVNFKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArICgxICsgRElBX0ZFU1RJVk8gfCBDT01VTkEvQ0xBU0UpIiksDQogICAgICAgICAgICAgICAgICAgICAgICBUcmFpbl9NU0UgPSBjKG1zZV90cmFpbl9zZW1hbmFfY29tdW5hMCwgbXNlX3RyYWluX3NlbWFuYV9jb211bmExLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtc2VfdHJhaW5fc2VtYW5hX2NvbXVuYTIsIG1zZV90cmFpbl9zZW1hbmFfY29tdW5hMyksDQogICAgICAgICAgICAgICAgICAgICAgICBUZXN0X01TRSA9IGMobXNlX3Rlc3Rfc2VtYW5hX2NvbXVuYTAsIG1zZV90ZXN0X3NlbWFuYV9jb211bmExLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1zZV90ZXN0X3NlbWFuYV9jb211bmEyLCBtc2VfdGVzdF9zZW1hbmFfY29tdW5hMykpDQpkYXRvc19tc2UgPC0gZGF0b3NfbXNlICU+JQ0KICBtdXRhdGUoUG9yY2VudGFqZV9WYXJpYWNpb24gPSByb3VuZCgxMDAqYWJzKFRyYWluX01TRS1UZXN0X01TRSkvKFRyYWluX01TRStUZXN0X01TRSksIDIpKQ0KYGBgDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQprbml0cjo6a2FibGUoZGF0b3NfbXNlKQ0KYGBgDQoNCkVuIGVsIG1vZGVsbyAqbW9kX3NlbWFuYV9jb211bmEzKiBzZSBkZXNjYXJ0YSB1c2FyIGxhIHZhcmlhYmxlIFRJRU1QT19TRU1BTkEgZGViaWRvIGEgcXVlIGVuIGx1Z2FyIGVuIGRpc21pbnVpciBlbCBUZXN0X01TRSwgbG8gYXVtZW50w7MsIHkgdGFtcG9jbyBtZWpvcsOzIGVsIFRyYWluX01TRSBzaWduaWZpY2F0aXZhbWVudGUsIHBvciBsbyBxdWUgc2UgY29uc2lkZXJhIHF1ZSBubyBlcyBzaWduaWZpY2F0aXZhIHBhcmEgZXhwbGljYXIgbGEgYWNjaWRlbnRhbGlkYWQgZW4gbGFzIGNvbXVuYXMgZGUgTWVkZWxsw61uIHBvciB0aXBvIGRlIGFjY2lkZW50ZS4NCg0KRmluYWxtZW50ZSBzZSBvYnNlcnZhIHF1ZSBlbCBtb2RlbG8gY29uIGludGVyY2VwdG8geSBwZW5kaWVudGUgYWxlYXRvcmlhICoqbW9kX3NlbWFuYV9jb211bmEzKio6DQoNCiQkXHdpZGVoYXR7XHRleHR7QUNDSURFTlRBTElEQUR9fSA9IFx0ZXh0e0RJQV9GRVNUSVZPfSArICgxICsgXHRleHR7RElBX0ZFU1RJVk99IHwgXHRleHR7Q09NVU5BL0NMQVNFfSkkJA0KDQpFcyBlbCBxdWUgb2J0aWVuZSBlbCBtZW5vciAqVHJhaW5fTVNFKiB5ICpUZXN0X01TRSosIHBvciBsbyBxdWUgc2UgZXNjb2dlIGVzdGUgbW9kZWxvIHBhcmEgbGEgZXhwbGljYWNpw7NuIGRlIGxhIGFjY2lkZW50YWxpZGFkIGVuIGNvbXVuYSBwb3Igc2VtYW5hLg0KDQpBIGNvbnRpbnVhY2nDs24gc2UgbXVlc3RyYW4gYWxndW5vcyBkZSBsb3MgdmFsb3JlcyBvYnNlcnZhZG9zIGRlIGxhIGFjY2lkZW50YWxpZGFkIHNlbWFuYWwgcG9yIGNsYXNlIHkgcG9yIGNvbXVuYSwgY29uIHN1IHJlc3BlY3Rpdm8gdmFsb3IgcHJlZGljaG8gKMO6bHRpbWEgY29sdW1uYSkgZW4gZWwgY29uanVudG8gZGUgcHJ1ZWJhLg0KDQpgYGB7ciwgcm93cy5wcmludCA9IDUsIGVjaG8gPSBGfQ0KZGF0YS5mcmFtZSh0ZXN0X3NlbWFuYV9jb211bmEsIEEuUFJFRElDSEEgPSB5X2VzdF90ZXN0X3NlbWFuYV9jb211bmEzKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZ9DQpyZW1vdmUoeV9lc3RfdHJhaW5fc2VtYW5hX2NvbXVuYTAsIHlfZXN0X3RyYWluX3NlbWFuYV9jb211bmExLCB5X2VzdF90cmFpbl9zZW1hbmFfY29tdW5hMiwgeV9lc3RfdHJhaW5fc2VtYW5hX2NvbXVuYTMsIHlfZXN0X3Rlc3Rfc2VtYW5hX2NvbXVuYTAsIHlfZXN0X3Rlc3Rfc2VtYW5hX2NvbXVuYTEsIHlfZXN0X3Rlc3Rfc2VtYW5hX2NvbXVuYTIsIHlfZXN0X3Rlc3Rfc2VtYW5hX2NvbXVuYTMsbXNlX3RyYWluX3NlbWFuYV9jb211bmEwLG1zZV90cmFpbl9zZW1hbmFfY29tdW5hMSxtc2VfdHJhaW5fc2VtYW5hX2NvbXVuYTIsbXNlX3RyYWluX3NlbWFuYV9jb211bmEzLG1zZV90ZXN0X3NlbWFuYV9jb211bmEwLG1zZV90ZXN0X3NlbWFuYV9jb211bmExLG1zZV90ZXN0X3NlbWFuYV9jb211bmEyLG1zZV90ZXN0X3NlbWFuYV9jb211bmEzKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZ9DQpyZW1vdmUobW9kX3NlbWFuYV9jb211bmEwLCBtb2Rfc2VtYW5hX2NvbXVuYTEsIG1vZF9zZW1hbmFfY29tdW5hMiwgbW9kX3NlbWFuYV9jb211bmEzKQ0KYGBgDQoNCiMjIyBNb2RlbG9zIC0gdW5pZGFkIGRlIHRpZW1wbyBNZXMNCg0KUGFyYSBlc3RlIG1vZGVsbyBzZSBhZ3J1cGEgbGEgdW5pZGFkIGRlIHRpZW1wbyBwb3IgbWVzZXMsIGVuIGxvcyBjdWFsZXMgc2Ugc3VtYSBsYSBjYW50aWRhZCBkZSBhY2NpZGVudGVzIHF1ZSBzdWNlZGVuIGVsIGVsIG1pc21vLCB0YW1iacOpbiBzZSBzdW1hIGVsIG7Dum1lcm8gZGUgZMOtYXMgZmVzdGl2b3MgcXVlIGhheSBlbiBkaWNobyBtZXMuIExhIGJhc2UgbHVjZSBjb21vIHNpZ3VlOg0KDQpgYGB7cn0NCmFjY2lkZW50ZXNfbWVzX2NvbXVuYSA8LSBhY2NpZGVudGVzX2RpYV9jb211bmEgJT4lIGdyb3VwX2J5KENPTVVOQSwgQ0xBU0UsIFBFUklPRE8sIE1FUywgVElFTVBPX01FUykgJT4lDQogIHN1bW1hcmlzZShESUFfRkVTVElWTyA9IHN1bShESUFfRkVTVElWTyksIEFDQ0lERU5UQUxJREFEID0gc3VtKEFDQ0lERU5UQUxJREFEKSkNCg0KYWNjaWRlbnRlc19tZXNfY29tdW5hDQpgYGANCg0KU2UgcmVhbGl6YSBsYSBwYXJ0aWNpw7NuIGRlIGxhIGJhc2UgZGUgZW50cmVuYW1pZW50byB5IGRlIHBydWViYQ0KDQpgYGB7cn0NCnRlc3RfbWVzX2NvbXVuYSA8LSBhY2NpZGVudGVzX21lc19jb211bmFbYWNjaWRlbnRlc19tZXNfY29tdW5hJFBFUklPRE8gPT0gMjAxOCwgXQ0KdHJhaW5fbWVzX2NvbXVuYSA8LSBhY2NpZGVudGVzX21lc19jb211bmFbYWNjaWRlbnRlc19tZXNfY29tdW5hJFBFUklPRE8gJWluJQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKDIwMTQsIDIwMTUsIDIwMTYsIDIwMTcpLCBdDQpgYGANCg0KQWhvcmEgc2UgYWp1c3RhbiBsb3MgbW9kZWxvcyBtaXh0b3MgY29uIGVmZWN0b3MgYWxlYXRvcmlvcyBlbiBDT01VTkEgeSBDTEFTRSBhbCBpZ3VhbCBxdWUgc2UgaGl6byBhIG5pdmVsIGRpYXJpbyB5IHNlbWFuYWwsIGVzIGRlY2lyLCBDTEFTRSBkZW50cm8gZGUgQ09NVU5BLg0KDQpgYGB7ciwgaW5jbHVkZSA9IEZ9DQpsb2FkKGZpbGUgPSAibW9kX21lc19jb211bmEwLlJEYXRhIikNCmxvYWQoZmlsZSA9ICJtb2RfbWVzX2NvbXVuYTEuUkRhdGEiKQ0KbG9hZChmaWxlID0gIm1vZF9tZXNfY29tdW5hMi5SRGF0YSIpDQpgYGANCg0KYGBge3IsIGV2YWw9RkFMU0V9DQptb2RfbWVzX2NvbXVuYTAgPC0gZ2xtZXIoQUNDSURFTlRBTElEQUQgfiAgMSArICgxIHwgQ09NVU5BL0NMQVNFKSwNCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9tZXNfY29tdW5hLCBmYW1pbHk9IHBvaXNzb24oKSkNCm1vZF9tZXNfY29tdW5hMSA8LSBnbG1lcihBQ0NJREVOVEFMSURBRCB+ICBESUFfRkVTVElWTyArICgxIHwgQ09NVU5BL0NMQVNFKSwNCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9tZXNfY29tdW5hLCBmYW1pbHk9IHBvaXNzb24oKSkNCm1vZF9tZXNfY29tdW5hMiA8LSBnbG1lcihBQ0NJREVOVEFMSURBRCB+ICBESUFfRkVTVElWTyArICgxICsgRElBX0ZFU1RJVk8gfCBDT01VTkEvQ0xBU0UpLA0KICAgICAgICAgICAgICAgZGF0YSA9IHRyYWluX21lc19jb211bmEsIGZhbWlseT0gcG9pc3NvbigpKQ0KYGBgDQoNCkFuw6FsaXNpcyBkZSB2YXJpYW56YSBBTk9WQQ0KDQpgYGB7cn0NCmFub3ZhKG1vZF9tZXNfY29tdW5hMCwgbW9kX21lc19jb211bmExLCBtb2RfbWVzX2NvbXVuYTIpDQpgYGANCg0KU2Ugb2JzZXJ2YSBxdWUgZWwgbW9kZWxvICptb2RfbWVzX2NvbXVuYTIqLCBlbCBjdWFsIHRpZW5lIGludGVyY2VwdG8geSBwZW5kaWVudGUgYWxlYXRvcmlhIGNvbiBsYSBjYXJhY3RlcsOtc3RpY2EgRElBX0ZFU1RJVk8gbm8gYXBvcnRhIHNpZ25pZmljYXRpdmFtZW50ZSBhIGxhIGV4cGxpY2FjacOzbiBkZSBsYSBhY2NpZGVudGFsaWRhZCBzZWfDum4gZWwgYW7DoWxpc2lzIGRlIHZhcmlhbnphIEFOT1ZBLiBTaW4gZW1iYXJnbywgc2UgcHJvY2VkZSBhIGNhbGN1bGFyIGxvcyBNU0UgZGUgZW50cmVuYW1pZW50byB5IGRlIHBydWViYS4NCg0KYGBge3J9DQojIE1vZGVsbyAwDQp5X2VzdF90cmFpbl9tZXNfY29tdW5hMCA8LSByb3VuZChwcmVkaWN0KG1vZF9tZXNfY29tdW5hMCwgbmV3ZGF0YSA9IHRyYWluX21lc19jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9tZXNfY29tdW5hMCA8LSByb3VuZChwcmVkaWN0KG1vZF9tZXNfY29tdW5hMCwgbmV3ZGF0YSA9IHRlc3RfbWVzX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCm1zZV90cmFpbl9tZXNfY29tdW5hMCA8LSByb3VuZChNU0UodHJhaW5fbWVzX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fbWVzX2NvbXVuYTApLDQpDQptc2VfdGVzdF9tZXNfY29tdW5hMCA8LSByb3VuZChNU0UodGVzdF9tZXNfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdGVzdF9tZXNfY29tdW5hMCksNCkNCg0KIyBNb2RlbG8gMQ0KeV9lc3RfdHJhaW5fbWVzX2NvbXVuYTEgPC0gcm91bmQocHJlZGljdChtb2RfbWVzX2NvbXVuYTEsIG5ld2RhdGEgPSB0cmFpbl9tZXNfY29tdW5hLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCnlfZXN0X3Rlc3RfbWVzX2NvbXVuYTEgPC0gcm91bmQocHJlZGljdChtb2RfbWVzX2NvbXVuYTEsIG5ld2RhdGEgPSB0ZXN0X21lc19jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQptc2VfdHJhaW5fbWVzX2NvbXVuYTEgPC0gcm91bmQoTVNFKHRyYWluX21lc19jb211bmEkQUNDSURFTlRBTElEQUQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3RyYWluX21lc19jb211bmExKSw0KQ0KbXNlX3Rlc3RfbWVzX2NvbXVuYTEgPC0gcm91bmQoTVNFKHRlc3RfbWVzX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2VzdF90ZXN0X21lc19jb211bmExKSw0KQ0KDQojIE1vZGVsbyAyDQp5X2VzdF90cmFpbl9tZXNfY29tdW5hMiA8LSByb3VuZChwcmVkaWN0KG1vZF9tZXNfY29tdW5hMiwgbmV3ZGF0YSA9IHRyYWluX21lc19jb211bmEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9tZXNfY29tdW5hMiA8LSByb3VuZChwcmVkaWN0KG1vZF9tZXNfY29tdW5hMiwgbmV3ZGF0YSA9IHRlc3RfbWVzX2NvbXVuYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlc3BvbnNlIiksMCkNCm1zZV90cmFpbl9tZXNfY29tdW5hMiA8LSByb3VuZChNU0UodHJhaW5fbWVzX2NvbXVuYSRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fbWVzX2NvbXVuYTIpLDQpDQptc2VfdGVzdF9tZXNfY29tdW5hMiA8LSByb3VuZChNU0UodGVzdF9tZXNfY29tdW5hJEFDQ0lERU5UQUxJREFELA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3Rlc3RfbWVzX2NvbXVuYTIpLDQpDQpgYGANCg0KDQpgYGB7ciwgaW5jbHVkZT1GfQ0KZGF0b3NfbXNlIDwtIGRhdGEuZnJhbWUoTW9kZWxvX01peHRvX1BvaXNzb24gPSBjKCJBQ0NJREVOVEFMSURBRCB+IDEgKyAoMSB8IENPTVVOQS9DTEFTRSkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFDQ0lERU5UQUxJREFEIH4gRElBX0ZFU1RJVk8gKyAoMSB8IENPTVVOQS9DTEFTRSkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFDQ0lERU5UQUxJREFEIH4gRElBX0ZFU1RJVk8gKyAoMSArIERJQV9GRVNUSVZPIHwgQ09NVU5BL0NMQVNFKSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgVHJhaW5fTVNFID0gYyhtc2VfdHJhaW5fbWVzX2NvbXVuYTAsIG1zZV90cmFpbl9tZXNfY29tdW5hMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNlX3RyYWluX21lc19jb211bmEyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIFRlc3RfTVNFID0gYyhtc2VfdGVzdF9tZXNfY29tdW5hMCwgbXNlX3Rlc3RfbWVzX2NvbXVuYTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXNlX3Rlc3RfbWVzX2NvbXVuYTIpKQ0KZGF0b3NfbXNlIDwtIGRhdG9zX21zZSAlPiUNCiAgbXV0YXRlKFBvcmNlbnRhamVfVmFyaWFjaW9uID0gcm91bmQoMTAwKmFicyhUcmFpbl9NU0UtVGVzdF9NU0UpLyhUcmFpbl9NU0UrVGVzdF9NU0UpLCAyKSkNCmBgYA0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmthYmxlKGRhdG9zX21zZSkNCmBgYA0KDQpBdW5xdWUgZWwgbW9kZWxvICptb2RfbWVzX2NvbXVuYTIqIG5vIHRpZW5lIHVuYSBtZWpvcmEgbXV5IHNpZ25pZmljYXRpdmEgcmVzcGVjdG8gYWwgbW9kZWxvICptb2RfbWVzX2NvbXVuYTEqLCBzaWd1ZSBzaWVuZG8gbWVqb3IgY29uIGVsIGNyw610ZXJpbyBkZWwgKlRlc3RfTVNFKiwgcG9yIGxvIHF1ZSBlbCBtb2RlbG8gZWxlZ2lkbyBlcyBlbCBtb2RlbG8gKiptb2RfbWVzX2NvbXVuYTIqKg0KDQokJFx3aWRlaGF0e1x0ZXh0e0FDQ0lERU5UQUxJREFEfX0gPSBcdGV4dHtESUFfRkVTVElWT30gKyAoMSArIFx0ZXh0e0RJQV9GRVNUSVZPfSB8IFx0ZXh0e0NPTVVOQS9DTEFTRX0pJCQNCkEgY29udGludWFjacOzbiBzZSBlbnNlw7FhIGxhIGNvbXBhcmFjacOzbiBlbnRyZSBsYSBhY2NpZGVudGFsaWRhZCBvYnNlcnZhZGEgeSBsYSBhY2NpZGVudGFsaWRhZCBwcmVkaWNoYSBtZW5zdWFsbWVudGUgcGFyYSBsYSBiYXNlIGRlIHBydWViYSAoY29sdW1uYSBmaW5hbCkuDQoNCmBgYHtyLCByb3dzLnByaW50ID0gNX0NCmRhdGEuZnJhbWUodGVzdF9tZXNfY29tdW5hLCBBLlBSRURJQ0hBID0geV9lc3RfdGVzdF9tZXNfY29tdW5hMikNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GfQ0KcmVtb3ZlKHlfZXN0X3RyYWluX21lc19jb211bmEwLHlfZXN0X3RyYWluX21lc19jb211bmExLHlfZXN0X3RyYWluX21lc19jb211bmEyLHlfZXN0X3Rlc3RfbWVzX2NvbXVuYTAseV9lc3RfdGVzdF9tZXNfY29tdW5hMSx5X2VzdF90ZXN0X21lc19jb211bmEyLG1zZV90cmFpbl9tZXNfY29tdW5hMCxtc2VfdHJhaW5fbWVzX2NvbXVuYTEsbXNlX3RyYWluX21lc19jb211bmEyLG1zZV90ZXN0X21lc19jb211bmEwLG1zZV90ZXN0X21lc19jb211bmExLG1zZV90ZXN0X21lc19jb211bmEyKQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPUZ9DQpyZW1vdmUobW9kX21lc19jb211bmEwLCBtb2RfbWVzX2NvbXVuYTEsIG1vZF9tZXNfY29tdW5hMikNCmBgYA0KDQojIyBNb2RlbG9zIHByZWRpY3Rpdm9zIHBhcmEgbG9zIEJhcnJpb3MNCg0KTGEgYmFzZSBkZSBkYXRvcyBwYXJhIHJlYWxpemFyIGVsIGFqdXN0ZSBkZSBsb3MgYmFycmlvcyBzZSBvYnR1dm8gaWd1YWwgYSBjb21vIHNlIHJlYWxpesOzIHBhcmEgbGFzIGNvbXVuYXMsIGVzIGRlY2lyLCBjb24gdW4gYGV4cGFuZC5ncmlkYCBwZXJvIGVzdGEgdmV6IGFncnVwYW5kbyBsYSBiYXNlIGRlIGRhdG9zIHBvciBiYXJyaW9zLg0KDQpSZWFsaXphbmRvIGVsIG1pc21vIG3DqXRvZG8gdmlzdG8gYW50ZXJpb3JtZW50ZSBwYXJhIGxhIHNlbGVjY2nDs24gZGUgbW9kZWxvcyBlbiBsYXMgY29tdW5hcywgc2UgZW5jdWVudHJhbiBsb3Mgc2lndWllbnRlIG1vZGVsb3MgcGFyYSBsb3MgYmFycmlvcy4NCg0KIyMjIE1vZGVsbyAtIHVuaWRhZCBkZSB0aWVtcG8gRMOtYQ0KDQpgYGB7ciwgaW5jbHVkZT1GfQ0KbG9hZChmaWxlID0gImFjY2lkZW50ZXNfZGlhX2JhcnJpby5SRGF0YSIpDQpgYGANCg0KQmFzZSBkZSBkYXRvcyBhZ3J1cGFkYSBwYXJhIGxhIGFjY2lkZW50YWxpZGFkIChuw7ptZXJvIGRlIGFjY2lkZW50ZXMpIGRpYXJpYS4NCg0KYGBge3IsIHJvd3MucHJpbnQgPSA1fQ0KYWNjaWRlbnRlc19kaWFfYmFycmlvICMgQmFzZSBkZSBkYXRvcyBkaWFyaWENCmBgYA0KDQpDb25qdW50byBkZSBwcnVlYmEgeSBjb25qdW50byBkZSB2YWxpZGFjacOzbjoNCg0KYGBge3J9DQp0ZXN0X2RpYV9iYXJyaW8gPC0gYWNjaWRlbnRlc19kaWFfYmFycmlvW2FjY2lkZW50ZXNfZGlhX2JhcnJpbyRQRVJJT0RPID09IDIwMTgsIF0NCnRyYWluX2RpYV9iYXJyaW8gPC0gYWNjaWRlbnRlc19kaWFfYmFycmlvW2FjY2lkZW50ZXNfZGlhX2JhcnJpbyRQRVJJT0RPICVpbiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygyMDE0LCAyMDE1LCAyMDE2LCAyMDE3KSwgXQ0KYGBgDQoNClNlIGVuY29udHLDsyBxdWUgZWwgbW9kZWxvIHF1ZSBtZWpvciBleHBsaWNhIGVzdGEgYWNjaWRlbnRhbGlkYWQgZXM6DQoNCmBgYHtyLCBpbmNsdWRlPUZ9DQpsb2FkKGZpbGUgPSAibW9kX2RpYV9iYXJyaW8uUkRhdGEiKQ0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbW9kX2RpYV9iYXJyaW8gPC0gZ2xtZXIoQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArICgxIHwgQkFSUklPL0NMQVNFKSwNCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9kaWFfYmFycmlvLCBmYW1pbHk9IHBvaXNzb24oKSkNCmBgYA0KDQpDb24gbG9zIHNpZ3VpZW50ZXMgKlRyYWluX01TRSogeSAqVGVzdF9NU0UqDQoNCmBgYHtyLCBldmFsID0gRn0NCnlfZXN0X3RyYWluX2RpYV9iYXJyaW8gPC0gcm91bmQocHJlZGljdChtb2RfZGlhX2JhcnJpbywgbmV3ZGF0YSA9IHRyYWluX2RpYV9iYXJyaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9kaWFfYmFycmlvIDwtIHJvdW5kKHByZWRpY3QobW9kX2RpYV9iYXJyaW8sIG5ld2RhdGEgPSB0ZXN0X2RpYV9iYXJyaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQptc2VfdHJhaW5fZGlhX2JhcnJpbyA8LSByb3VuZChNU0UodHJhaW5fZGlhX2JhcnJpbyRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fZGlhX2JhcnJpbyksNCkNCm1zZV90ZXN0X2RpYV9iYXJyaW8gPC0gcm91bmQoTVNFKHRlc3RfZGlhX2JhcnJpbyRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3Rlc3RfZGlhX2JhcnJpbyksNCkNCmBgYA0KDQpgYGB7ciwgZXZhbD1GLCBpbmNsdWRlPUZ9DQptc2VfYmFycmlvX2RpYSA8LSBkYXRhLmZyYW1lKE1vZGVsb19NaXh0b19Qb2lzc29uID0gYygiQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArICgxIHwgQkFSUklPL0NMQVNFKSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgVHJhaW5fTVNFID0gYyhtc2VfdHJhaW5fZGlhX2JhcnJpbyksDQogICAgICAgICAgICAgICAgICAgICAgICBUZXN0X01TRSA9IGMobXNlX3Rlc3RfZGlhX2JhcnJpbykpDQptc2VfYmFycmlvX2RpYSA8LSBtc2VfYmFycmlvX2RpYSAlPiUNCiAgbXV0YXRlKFBvcmNlbnRhamVfVmFyaWFjaW9uID0gcm91bmQoMTAwKmFicyhUcmFpbl9NU0UtVGVzdF9NU0UpLyhUcmFpbl9NU0UrVGVzdF9NU0UpLCAyKSkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GfQ0KbG9hZChmaWxlID0gIm1zZV9iYXJyaW9fZGlhLlJEYXRhIikNCmBgYA0KDQpgYGB7ciwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6OmthYmxlKG1zZV9iYXJyaW9fZGlhKQ0KYGBgDQoNCk1vZGVsbzoNCg0KJCRcd2lkZWhhdHtcdGV4dHtBQ0NJREVOVEFMSURBRH19ID0gXHRleHR7RElBX0ZFU1RJVk99ICsgKDEgfnx+IFx0ZXh0e0NPTVVOQS9DTEFTRX0pJCQNCg0KYGBge3IsIGluY2x1ZGU9Rn0NCnJlbW92ZShtb2RfZGlhX2JhcnJpbykNCmBgYA0KDQoNCiMjIyBNb2RlbG8gLSB1bmlkYWQgZGUgdGllbXBvIFNlbWFuYQ0KDQpCYXNlIHBhcmEgZWwgbW9kZWxvIHNlbWFuYWwNCg0KYGBge3J9DQphY2NpZGVudGVzX3NlbWFuYV9iYXJyaW8gPC0gYWNjaWRlbnRlc19kaWFfYmFycmlvICU+JSBncm91cF9ieShCQVJSSU8sIENMQVNFLCBQRVJJT0RPLCBTRU1BTkEsIFRJRU1QT19TRU1BTkEpICU+JQ0KICBzdW1tYXJpc2UoRElBX0ZFU1RJVk8gPSBzdW0oRElBX0ZFU1RJVk8pLCBBQ0NJREVOVEFMSURBRCA9IHN1bShBQ0NJREVOVEFMSURBRCkpDQpgYGANCg0KYGBge3IsIHJvd3MucHJpbnQgPSA1fQ0KYWNjaWRlbnRlc19zZW1hbmFfYmFycmlvICMgQmFzZSBkZSBkYXRvcyBzZW1hbmFyaWENCmBgYA0KDQpDb25qdW50byBkZSBwcnVlYmEgeSBjb25qdW50byBkZSB2YWxpZGFjacOzbjoNCg0KYGBge3J9DQp0ZXN0X3NlbWFuYV9iYXJyaW8gPC0gYWNjaWRlbnRlc19zZW1hbmFfYmFycmlvW2FjY2lkZW50ZXNfc2VtYW5hX2JhcnJpbyRQRVJJT0RPID09IDIwMTgsIF0NCnRyYWluX3NlbWFuYV9iYXJyaW8gPC0gYWNjaWRlbnRlc19zZW1hbmFfYmFycmlvW2FjY2lkZW50ZXNfc2VtYW5hX2JhcnJpbyRQRVJJT0RPICVpbiUgYygyMDE0LCAyMDE1LCAyMDE2LCAyMDE3KSwgXQ0KYGBgDQoNClNlIGVuY29udHLDsyBxdWUgZWwgbW9kZWxvIHF1ZSBtZWpvciBleHBsaWNhIGVzdGEgYWNjaWRlbnRhbGlkYWQgZXM6DQoNCmBgYHtyLCBpbmNsdWRlPUZ9DQpsb2FkKGZpbGUgPSAibW9kX3NlbWFuYV9iYXJyaW8uUkRhdGEiKQ0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbW9kX3NlbWFuYV9iYXJyaW8gPC0gZ2xtZXIoQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArICgxIHwgQkFSUklPL0NMQVNFKSwNCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9zZW1hbmFfYmFycmlvLCBmYW1pbHk9IHBvaXNzb24oKSkNCmBgYA0KDQoNCmBgYHtyLCBldmFsID0gRn0NCnlfZXN0X3RyYWluX3NlbWFuYV9iYXJyaW8gPC0gcm91bmQocHJlZGljdChtb2Rfc2VtYW5hX2JhcnJpbywgbmV3ZGF0YSA9IHRyYWluX3NlbWFuYV9iYXJyaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9zZW1hbmFfYmFycmlvIDwtIHJvdW5kKHByZWRpY3QobW9kX3NlbWFuYV9iYXJyaW8sIG5ld2RhdGEgPSB0ZXN0X3NlbWFuYV9iYXJyaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQptc2VfdHJhaW5fc2VtYW5hX2JhcnJpbyA8LSByb3VuZChNU0UodHJhaW5fc2VtYW5hX2JhcnJpbyRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fc2VtYW5hX2JhcnJpbyksNCkNCm1zZV90ZXN0X3NlbWFuYV9iYXJyaW8gPC0gcm91bmQoTVNFKHRlc3Rfc2VtYW5hX2JhcnJpbyRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3Rlc3Rfc2VtYW5hX2JhcnJpbyksNCkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GLCBldmFsPUZ9DQptc2VfYmFycmlvX3NlbWFuYSA8LSBkYXRhLmZyYW1lKE1vZGVsb19NaXh0b19Qb2lzc29uID0gYygiQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArICgxIHwgQkFSUklPL0NMQVNFKSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgVHJhaW5fTVNFID0gYyhtc2VfdHJhaW5fc2VtYW5hX2JhcnJpbyksDQogICAgICAgICAgICAgICAgICAgICAgICBUZXN0X01TRSA9IGMobXNlX3Rlc3Rfc2VtYW5hX2JhcnJpbykpDQptc2VfYmFycmlvX3NlbWFuYSA8LSBtc2VfYmFycmlvX3NlbWFuYSAlPiUNCiAgbXV0YXRlKFBvcmNlbnRhamVfVmFyaWFjaW9uID0gcm91bmQoMTAwKmFicyhUcmFpbl9NU0UtVGVzdF9NU0UpLyhUcmFpbl9NU0UrVGVzdF9NU0UpLCAyKSkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZSA9IEZ9DQpsb2FkKGZpbGUgPSAibXNlX2JhcnJpb19zZW1hbmEuUkRhdGEiKQ0KYGBgDQoNCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjprYWJsZShtc2VfYmFycmlvX3NlbWFuYSkNCmBgYA0KDQpNb2RlbG86DQoNCiQkXHdpZGVoYXR7XHRleHR7QUNDSURFTlRBTElEQUR9fSA9IFx0ZXh0e0RJQV9GRVNUSVZPfSArICgxIH58fiBcdGV4dHtDT01VTkEvQ0xBU0V9KSQkDQoNCiMjIyBNb2RlbG8gLSB1bmlkYWQgZGUgdGllbXBvIE1lcw0KDQpCYXNlIHBhcmEgZWwgbW9kZWxvIG1lbnN1YWwNCg0KYGBge3J9DQphY2NpZGVudGVzX21lc19iYXJyaW8gPC0gYWNjaWRlbnRlc19kaWFfYmFycmlvICU+JSBncm91cF9ieShCQVJSSU8sIENMQVNFLCBQRVJJT0RPLCBNRVMsIFRJRU1QT19NRVMpICU+JQ0KICBzdW1tYXJpc2UoRElBX0ZFU1RJVk8gPSBzdW0oRElBX0ZFU1RJVk8pLCBBQ0NJREVOVEFMSURBRCA9IHN1bShBQ0NJREVOVEFMSURBRCkpDQpgYGANCg0KYGBge3IsIHJvd3MucHJpbnQgPSA1fQ0KYWNjaWRlbnRlc19tZXNfYmFycmlvICMgQmFzZSBkZSBkYXRvcyBtZXMNCmBgYA0KDQpDb25qdW50byBkZSBwcnVlYmEgeSBjb25qdW50byBkZSB2YWxpZGFjacOzbjoNCg0KYGBge3J9DQp0ZXN0X21lc19iYXJyaW8gPC0gYWNjaWRlbnRlc19tZXNfYmFycmlvW2FjY2lkZW50ZXNfbWVzX2JhcnJpbyRQRVJJT0RPID09IDIwMTgsIF0NCnRyYWluX21lc19iYXJyaW8gPC0gYWNjaWRlbnRlc19tZXNfYmFycmlvW2FjY2lkZW50ZXNfbWVzX2JhcnJpbyRQRVJJT0RPICVpbiUgYygyMDE0LCAyMDE1LCAyMDE2LCAyMDE3KSwgXQ0KYGBgDQoNClNlIGVuY29udHLDsyBxdWUgZWwgbW9kZWxvIHF1ZSBtZWpvciBleHBsaWNhIGVzdGEgYWNjaWRlbnRhbGlkYWQgZXM6DQoNCmBgYHtyLCBpbmNsdWRlPUZ9DQpsb2FkKGZpbGUgPSAibW9kX21lc19iYXJyaW8uUkRhdGEiKQ0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbW9kX21lc19iYXJyaW8gPC0gZ2xtZXIoQUNDSURFTlRBTElEQUQgfiBESUFfRkVTVElWTyArICgxIHwgQkFSUklPL0NMQVNFKSwNCiAgICAgICAgICAgICAgIGRhdGEgPSB0cmFpbl9tZXNfYmFycmlvLCBmYW1pbHk9IHBvaXNzb24oKSkNCmBgYA0KDQpgYGB7cn0NCnlfZXN0X3RyYWluX21lc19iYXJyaW8gPC0gcm91bmQocHJlZGljdChtb2RfbWVzX2JhcnJpbywgbmV3ZGF0YSA9IHRyYWluX21lc19iYXJyaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVzcG9uc2UiKSwwKQ0KeV9lc3RfdGVzdF9tZXNfYmFycmlvIDwtIHJvdW5kKHByZWRpY3QobW9kX21lc19iYXJyaW8sIG5ld2RhdGEgPSB0ZXN0X21lc19iYXJyaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJyZXNwb25zZSIpLDApDQptc2VfdHJhaW5fbWVzX2JhcnJpbyA8LSByb3VuZChNU0UodHJhaW5fbWVzX2JhcnJpbyRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9lc3RfdHJhaW5fbWVzX2JhcnJpbyksNCkNCm1zZV90ZXN0X21lc19iYXJyaW8gPC0gcm91bmQoTVNFKHRlc3RfbWVzX2JhcnJpbyRBQ0NJREVOVEFMSURBRCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlfZXN0X3Rlc3RfbWVzX2JhcnJpbyksNCkNCmBgYA0KDQpgYGB7ciwgaW5jbHVkZT1GfQ0KZGF0b3NfbXNlIDwtIGRhdGEuZnJhbWUoTW9kZWxvX01peHRvX1BvaXNzb24gPSBjKCJBQ0NJREVOVEFMSURBRCB+IERJQV9GRVNUSVZPICsgKDEgfCBCQVJSSU8vQ0xBU0UpIiksDQogICAgICAgICAgICAgICAgICAgICAgICBUcmFpbl9NU0UgPSBjKG1zZV90cmFpbl9tZXNfYmFycmlvKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIFRlc3RfTVNFID0gYyhtc2VfdGVzdF9tZXNfYmFycmlvKSkNCmRhdG9zX21zZSA8LSBkYXRvc19tc2UgJT4lDQogIG11dGF0ZShQb3JjZW50YWplX1ZhcmlhY2lvbiA9IHJvdW5kKDEwMCphYnMoVHJhaW5fTVNFLVRlc3RfTVNFKS8oVHJhaW5fTVNFK1Rlc3RfTVNFKSwgMikpDQpgYGANCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmtuaXRyOjprYWJsZShkYXRvc19tc2UpDQpgYGANCg0KTW9kZWxvOg0KDQokJFx3aWRlaGF0e1x0ZXh0e0FDQ0lERU5UQUxJREFEfX0gPSBcdGV4dHtESUFfRkVTVElWT30gKyAoMSB+fH4gXHRleHR7Q09NVU5BL0NMQVNFfSkkJA0KDQpBIGNvbnRpbnVhY2nDs24gc2UgZW5zZcOxYSBsYSBjb21wYXJhY2nDs24gZW50cmUgbGEgYWNjaWRlbnRhbGlkYWQgb2JzZXJ2YWRhIHkgbGEgYWNjaWRlbnRhbGlkYWQgcHJlZGljaGEgbWVuc3VhbG1lbnRlIHBhcmEgbGEgYmFzZSBkZSBwcnVlYmEgKGNvbHVtbmEgZmluYWwpLg0KDQpgYGB7ciwgcm93cy5wcmludCA9IDV9DQpkYXRhLmZyYW1lKHRlc3RfbWVzX2JhcnJpbywgQS5QUkVESUNIQSA9IHlfZXN0X3Rlc3RfbWVzX2JhcnJpbykNCmBgYA0KDQpgYGB7cn0NCnJlbW92ZShtb2RfZGlhX2JhcnJpbykNCmBgYA0KDQoNCiMgQ2x1c3RlcmluZw0KDQpTZWfDum4gbG8gZGVzY3JpdG8gZW4gbGEgaW50cm9kdWNjacOzbiwgZXMgbmVjZXNhcmlvIGNlbnRyYXJzZSBlbiBsb3MgbcOpdG9kb3MgcHJldmVudGl2b3MgbcOhcyBxdWUgZW4gbGFzIHNhbmNpb25lcywgZGViaWRvIGEgcXVlLCBzaSBsYSBwb2JsYWNpw7NuIGNvbm9jZSBzdXMgY2lmcmFzIHkgbG9ncmEgZW50ZW5kZXIgcXXDqSBlcyBsbyBxdWUgZXN0YSBwYXNhbmRvIGRlbnRybyBkZSBsYSBjaXVkYWQsIHNlIGxvZ3JhcsOhIG5vIHPDs2xvIHJlZHVjaXIgbG9zIGluY2lkZW50ZXMgZGUgdHLDoW5zaXRvLCBzaW5vIHRhbWJpw6luIGNyZWFyIGNvbmNpZW5jaWEgZW4gbGFzIGdlbmVyYWNpb25lcyBmdXR1cmFzLg0KDQpBc2ltaXNtbywgcGFyYSByZWR1Y2lyIGxvcyBhY2NpZGVudGVzIGRlIHRyYW5zaXRvIGVuIGxhIGNpdWRhZCBlcyBuZWNlc2FyaW8gY29tcHJlbmRlciBxdcOpIGVzdGEgc3VjZWRpZW5kbyBhIHByb2Z1bmRpZGFkIGRlbnRybyBkZSBlbGxhLCB5LCBncmFjaWFzIGFsIGFjY2VzbyBhIGxhcyBiYXNlcyBkZSBkYXRvcyBhbnVhbGVzIGRlIEdlb21lZGVsbGluLCBlcyBwb3NpYmxlIGNsYXNpZmljYXIgbGFzIHpvbmFzIGRvbmRlIG3DoXMgb2N1cnJlbiwgcGFyYSBxdWUgZXN0YXMgc2VhbiBpbnRlcnZlbmlkYXMgZGUgdW5hIGZvcm1hIG3DoXMgcmlndXJvc2EuIEVuIGVzdGEgc2VjY2nDs24gZGVsIHByb3llY3RvIGZ1ZSBuZWNlc2FyaW8gcGxhbnRlYXJub3MgbGEgc2lndWllbnRlIHByZWd1bnRhOiDCv0PDs21vIHBvZHLDrWFtb3MgY2xhc2lmaWNhciBsb3MgYmFycmlvcyBkZSBNZWRlbGzDrW4gZGUgYWN1ZXJkbyBhIHN1IGFjY2lkZW50YWxpZGFkPy4gDQoNCkNvbnNpZGVyYW5kbyBsYXMgY2FyYWN0ZXJpc3RpY2FzIGRlIE1lZGVsbMOtbiB5IGRlbCB2YWxsZSBkZSBBYnVycsOhIGVuIGdlbmVyYWwsIHB1ZWRlbiBleGlzdGlyIG11Y2hvcyBmYWN0b3JlcyBxdWUgY2F0YWxvZ2FuIHVuIGJhcnJpbywgZW4gY3VhbnRvIGEgc2VndXJpZGFkIHZpYWwsIGNvbW8gcGVsaWdyb3NvIG8gc2VndXJvLiBEw61hIGEgZMOtYSBlbiBsYSBjaXVkYWQgdHJhbnNpdGFuIHRvZG8gdGlwbyBkZSB2ZWjDrWN1bG9zLCBxdWUgZGFkYXMgbGFzIGNvbmRpY2lvbmVzIGRlIGxhIHpvbmEsIGxhcyBjYWxsZXMgYW5nb3N0YXMgZW4gYWxndW5vcyBzZWN0b3JlcywgbGFzIHbDrWFzIGVuIGVzdGFkbyBkZSBkZXRlcmlvcm8geSBsYSBpbXBydWRlbmNpYSBkZSBsYSBnZW50ZSwgaGFjZW4gcXVlIHNlYSBtdXkgY29tcGxpY2FkbyBpciBkZSB1biBsdWdhciBhIG90cm8gc2luIHRlbmVyIGFsZ8O6biB0aXBvIGRlIGFsdGVyY2FkbyBlbiBhbGfDum4gbW9tZW50byBkZSBsYSB2aWRhIGRlIHVuYSBwZXJzb25hLiBQb3IgZXN0ZSBtb3Rpdm8sIGVsIGNyaXRlcmlvIGVzY29naWRvIHBhcmEgY2xhc2lmaWNhciB1biBiYXJyaW8gZW4gdmlzdGEgZGUgc3UgYWNjaWRlbnRhbGlkYWQsIGNvbiBsb3MgZGF0b3MgYnJpbmRhZG9zIGRlIGdlb21lZGVsbGluLCBmdWUgbGEgZ3JhdmVkYWQgZGVsIGFjY2lkZW50ZS4gQWRpY2lvbmFsbWVudGUsIGFsIHNlciBzb2xvIDMgdGlwb3MgZGUgZ3JhdmVkYWQgZXMgZmFjaWwgZGUgcmVwcmVzZW50YXIgZWwgYW7DoWxpc2lzIGRlIGZvcm1hIG3DoXMgZ3LDoWZpY2EuDQoNCkVuIHByaW1lciBsdWdhciwgbGEgZ3JhdmVkYWQgZGVsIGFjY2lkZW50ZSBoYWJsYSBtdWNobyBkZSBsYXMgY29uZGljaW9uZXMgZW4gbGFzIHF1ZSBzZSBkaW8gZWwgbWlzbW8sIHlhIHF1ZSBtdWNoYXMgdmVjZXMgdW4gbWF5b3IgZGHDsW8gZXMgY2F1c2FkbyBwb3IgdW4gbWF5b3IgZ3JhZG8gZGUgaXJyZXNwb25zYWJpbGlkYWQuIEVuIGNvbnNlY3VlbmNpYSwgZXMgcG9zaWJsZSBpbmZlcmlyIHF1ZSBsb3MgYmFycmlvcyBlbiBsb3MgcXVlIHNlIG11ZXN0cmFuIGxvcyBwZW9yZXMgYWNjaWRlbnRlcyB0ZW5nYW4gbGEgbWF5b3IgY2FudGlkYWQgZGUgZXN0b3MgZW4gZ2VuZXJhbCAoYXBsaWNhIHBhcmEgZWwgY2FzbyBjb250cmFyaW8pLiBEZSBtYW5lcmEgYW7Ds2xhZ2EsIGVuIGVsIGNhc28gZGUgcXVlIGxvIGFudGVyaW9yIG5vIHNlIGN1bXBsYSwgY29uIGVzdGUgZGF0byBwb3IgbG8gbWVub3Mgc2UgcG9kcsOhIGlkZW50aWZpY2FyIGxvcyBiYXJyaW9zIGNvbiBsb3MgYWNjaWRlbnRlcyBtw6FzIGdyYXZlcywgcXVlIGRlbCBtaXNtbyBtb2RvLCBzZXJ2aXLDoSBwYXJhIHByZXZlbmlyIGEgbGEgY2l1ZGFkYW7DrWEgeSB0cmF0YXIgZGUgaWRlbnRpZmljYXIgZGUgbWFuZXJhIHByb2Z1bmRhIGxvIHF1ZSBlc3TDoSBwYXNhbmRvIGVuIGVsIGx1Z2FyLiBBbCBmaW4geSBhbCBjYWJvIHJlZHVjaXIgbG9zIGRhw7FvcyBtYXRlcmlhbGVzIGVzIGltcG9ydGFudGUsIHBlcm8gcmVkdWNpciBsYSBjYW50aWRhZCBkZSBtdWVydG9zIGVuIE1lZGVsbMOtbiBkZWJlIHNlciBsYSBwcmlvcmlkYWQuDQoNCkVuIGN1YW50byBhbCBjbHVzdGVyaW5nIGRlc2Fycm9sbGFkbyBwYXJhIGxhIGNsYXNpZmljYWNpw7NuIGRlIGxvcyBiYXJyaW9zLCBzZSB1dGlsaXrDsyBlbCBtw6l0b2RvIGRlIEstTWVhbnMuIEFxdcOtLCBzZSB0b23DsyBsYSBkZWNpc2nDs24gZGUgYmFzYXJub3MgZW4gbGEgY29sdW1uYSBkZSBsYSBncmF2ZWRhZCwgeWEgcXVlLCBubyBzb2xvIG1vc3RyYXLDrWEgbG9zIGJhcnJpb3MgY29uIG3DoXMgYWNjaWRlbnRhbGlkYWQsIHNpbm8gZWwgcGVsaWdybyBxdWUgZXN0b3MgcmVwcmVzZW50YW4gZW4gY3VhbnRvIGEgc2VndXJpZGFkIHZpYWwuDQoNClByaW1lcm8sIGZ1ZSBuZWNlc2FyaW8gZXh0cmFlciBsYXMgY29sdW1uYXMgQkFSUklPIHkgR1JBVkVEQUQgZGUgbGEgYmFzZSBkZSBkYXRvcywgcGFyYSBhc8OtIHNvbG8gY2VudHJhcm5vcyBlbiBsbyBpbXBvcnRhbnRlIGR1cmFudGUgZWwgcHJvY2Vzby4gDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCByb3dzLnByaW50ID0gNX0NCmRmIDwtIHJlYWQuY3N2KGZpbGUgPSAiQW5hbGlzaXMxLmNzdiIsIGhlYWRlciA9IFQsIG5yb3dzID0gNTAsDQogICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gVCwgZmlsZUVuY29kaW5nPSJ1dGYtOCIpDQpkZjsgcmVtb3ZlKGRmKQ0KYGBgDQoNClBvc3Rlcmlvcm1lbnRlLCBmdWUgbmVjZXNhcmlvIGhhY2VyIDIgcGFzb3M6IHByaW1lcm8gc2UgY3JlYXJvbiAzIGNvbHVtbmFzIGNvcnJlc3BvbmRpZW50ZXMgYSBsb3MgdGlwb3MgZGUgZ3JhdmVkYWQsIGFzaWduYW5kbyB1biB2YWxvciBkZSB1bm8gZW4gbGEgZmlsYSBjb3JyZXNwb25kaWVudGUgYWwgbWlzbW8gdGlwbyB5IHVuIHZhbG9yIGRlIGNlcm8gcGFyYSBsYXMgZGVtw6FzOyBkZXNwdWVzLCBmdWUgbmVjZXNhcmlvIGFncnVwYXIgbGFzIGNvbHVtbmFzIHBvciBiYXJyaW8sIHBhcmEgb2J0ZW5lciBsYSBzdW1hIHRvdGFsIGRlIGFjY2lkZW50ZXMgcG9yIGJhcnJpbywgZGFuZG8gY29tbyByZXN1bHRhZG8gbGEgdGFibGEgcXVlIHNlIGVuc2XDsWEgYSBjb250aW51YWNpw7NuDQoNCg0KYGBge3IsIGVjaG89RkFMU0UsIHJvd3MucHJpbnQgPSA1fQ0KZGYgPC0gcmVhZC5jc3YoZmlsZSA9ICJBbmFsaXNpczMuY3N2IiwgaGVhZGVyID0gVCwNCiAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBULCBmaWxlRW5jb2Rpbmc9InV0Zi04IikNCmRmOyByZW1vdmUoZGYpDQpgYGANCg0KTcOhcyBhZGVsYW50ZSB5IGFob3JhIGNvbiBzw7NsbyBsb3MgZGF0b3MgbmVjZXNhcmlvcywgc2UgcmVhbGl6w7MgZWwgbcOpdG9kbyBkZWwgY29kbyBwYXJhIGVuY29udHJhciBlbCBuw7ptZXJvIGRlIGNsdXN0ZXJzLCBhbCBtaXNtbyB0aWVtcG9zIHF1ZSBzZSBlc2NvZ8OtYSBsYSBtZWpvciBkaXZpc2nDs24gdXRpbGl6YW5kbyBlbCBtw6l0b2RvIGstbWVhbnMrKyBxdWUgcG9zZWUgcHl0aG9uLiBUb2RvIGVzdG8gYXJyb2rDsyBxdWUgbG8gbWVqb3Igc2Vyw61hIGRpdmlkaXIgbG9zIGRhdG9zIGVuIDQgY2x1c3RlcnMuDQoNCiFbXShQYXJ0ZTQucG5nKXsjaWQgLmNsYXNzIHdpZHRoPTUwJSBoZWlnaHQ9NTAlfQ0KDQpBbCByZWFsaXphciBsYSByZXNwZWN0aXZhIGNsYXNpZmljYWNpw7NuIHNlIGFycm9qw7MgbGEgc2lndWllbnRlIGdyw6FmaWNhLCBkb25kZSBzZSBwdWVkZSBvYnNlcnZhciBsYSBkaXN0cmlidWNpw7NuIGRlIGxvcyBiYXJyaW9zIHkgcGVybWl0ZSBhY2VwdGFyIGxhIHNpZ3VpZW50ZSBwcmVtaXNhOiBsb3MgMyB0aXBvcyBkZSBncmF2ZWRhZCBzZSByZWxhY2lvbmFuIGVudHJlIHPDrSwgZXZpZGVuY2lhbmRvc2UgcXVlIGEgbWF5b3IgbnVtZXJvIGRlIGhlcmlkb3MsIHRhbWJpw6luIGhheSBtYXlvciBuw7ptZXJvIGRlIHNvbG8gZGHDsW9zIHkgbXVlcnRvcyBlbiBwcm9tZWRpby4gRW4gZXNlIG9yZGVuIGRlIGlkZWFzLCBzZSBtdWVzdHJhIG90cmEgaW5mb3JtYWNpw7NuIGltcG9ydGFudGU6IFVub3MgY8O6YW50b3MgYmFycmlvcyBzb24gbG9zIHF1ZSBwcmVzZW50YW4gbGEgbWF5b3IgY29uY2VudHJhY2nDs24gZGUgYWNjaWRlbnRlcywgY29uIHVuYSBmcmVjdWVuY2lhIG1heW9yIGNvbiByZXNwZWN0byBhIGxvcyBtw6FzIHNlZ3Vyb3MuDQoNCiFbXSgzdGFibGFzLmpwZWcpeyNpZCAuY2xhc3Mgd2lkdGg9NjAlIGhlaWdodD02MCV9DQoNClRlbmllbmRvIGVuIGN1ZW50YSBsbyBhbnRlcmlvciwgc2UgYW5hbGl6w7MgbGEgbWVkaWEgZGUgYWNjaWRlbnRlcyBwb3IgY2x1c3RlciwgbG8gcXVlIGFycm9qw7MgdW5hIGRpZmVyZW5jaWEgc2lnbmlmaWNhdGl2YSBlbnRyZSBlbGxvcyBhIGxhIGhvcmEgZGUgYW5hbGl6YXIgbG9zIGhlcmlkb3MsIG11ZXJ0b3MgeSBkYcOxb3Mgb2Nhc2lvbmFkb3MuIEVsIGhlYXRtYXAgcXVlIHNlIGVuY3VlbnRyYSBhIGNvbnRpbnVhY2nDs24gZGVzY3JpYmUgbG8gdmlzdG8gZW4gbGFzIGdyw6FmaWNhcyBhbnRlcmlvcmVzIGRlIHVuYSBtYW5lcmEgbWFzIHByZWNpc2EuIFBvciBsbyB0YW50bywgbG9zIG7Dum1lcm9zIG11ZXN0cmFuIHVuYSBkaWZlcmVuY2lhIG11Y2hvIG1heW9yIGN1YW5kbyBzZSBjb21wYXJhbiBsb3MgMiBncnVwb3MgbcOhcyBzZWd1cm9zIGNvbiBsb3MgMiBtw6FzIHBlbGlncm9zb3MsIGRvbmRlIHZpc3VhbG1lbnRlIHNlIHB1ZWRlIG5vdGFyIGFsIGlndWFsIHF1ZSBlbiBsb3MgZ3LDoWZpY29zIGFudGVyaW9yZXMuIERlIGFow60gcXVlLCBlcyBpbXBvcnRudGUgcmVzYWx0YXIgcXVlIGVuIGxhcyAzIGNvbXBvbmVudGVzLCBlbCBwcm9tZWRpbyBkZWwgY2x1c3RlciBjb24gbcOhcyBhY2NpZGVudGVzIGVzIG1heW9yIGEgbGEgc3VtYSBkZSBsb3Mgb3Ryb3MgMw0KDQpFc3RvcyBkYXRvcyBzZSBtdWVzdHJhbiBlbiBsYSBhcGxpY2FjacOzbiBkZSBzaGlueSwgZW4gbGEgcGFydGUgZGUgYWJham8gZGUgbGEgc2VjY2nDs24gZGUgYWdydXBhbWllbnRvLg0KDQohW10oSGVhdG1hcC5wbmcpeyNpZCAuY2xhc3Mgd2lkdGg9NTAlIGhlaWdodD01MCV9DQoNCkFsIGNvbnRhciBlbCBuw7ptZXJvIGRlIGJhcnJpb3MsIGVuY29udHJhbW9zIG90cm8gZGF0byBtdXkgaW50ZXJlc2FudGU6IEFkZW3DoXMgZGUgcXVlIGVsIG7Dum1lcm8gZGUgYmFycmlvcyBjYW1iaWEgbXVjaG8gZGUgdW4gY2x1c3RlciBhIG90cm8sIGVsIGNsdXN0ZXIgcXVlIHRpZW5lIHVuYSBtYXlvciBhY2NpZGVudGFsaWRhZCwgcXVlIGVuIHByb21lZGlvIGVxdWl2YWxlIGEgY2FzaSBsYSBtaXRhZCBkZSB0b2RvcyBsb3MgYWNjaWRlbnRlcywgc29sbyBzZSBjb21wb25lIGRlIDkgYmFycmlvcy4NCg0KYGBge3IsIGVjaG89RkFMU0UsIHJvd3MucHJpbnQgPSA1fQ0KZGYgPC0gcmVhZC5jc3YoZmlsZSA9ICJmcmVjdWVuY2lhLmNzdiIsIGhlYWRlciA9IFQsIG5yb3dzID0gNTAsDQogICAgICAgICAgICAgICBzdHJpbmdzQXNGYWN0b3JzID0gVCwgZmlsZUVuY29kaW5nPSJ1dGYtOCIpDQpkZjsgcmVtb3ZlKGRmKQ0KYGBgDQoNCkFsIHRlbmVyIGVzdGEgaW5mb3JtYWNpw7NuIHkgY29uIGVsIGZpbiBkZSByZWR1Y2lyIGNvbnNpZGVyYWJsZW1lbnRlIGVzdG9zIGluY2lkZW50ZXMgdmlhbGVzIGVuIE1lZGVsbMOtbiwgZXMgbmVjZXNhcmlvIHByZXZlbmlyIGEgbG9zIGN1aWRhZGFub3MgZGUgbG9zIHNpZ3VpZW50ZXMgYmFycmlvcywgYSBzdSB2ZXogbGEgYWxjYWxkw61hIHBsYW50ZWEgcG9zaWJsZXMgc29sdWNpb25lcyBlbiBsYSBtb3ZpbGlkYWQgZGUgZXN0b3M6DQoNCmBgYHtyLCBlY2hvPUZBTFNFLCByb3dzLnByaW50ID0gNX0NCmRmIDwtIHJlYWQuY3N2KGZpbGUgPSAiOWJhcnJpb3MuY3N2IiwgaGVhZGVyID0gVCwgbnJvd3MgPSA1MCwNCiAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBULCBmaWxlRW5jb2Rpbmc9InV0Zi04IikNCmRmOyByZW1vdmUoZGYpDQpgYGANCg0KVGVuaWVuZG8gZW4gY3VlbnRhIGxhIGluZm9ybWFjacOzbiBhbnRlcmlvciB5IHRlbmllbmRvbG9zIGRlIG1hbmVyYSBncsOhZmljYSBlbiBlbCBtYXBhLCBsYSBtYXlvcsOtYSBkZSBsb3MgcHJvYmxlbWFzIGRlIG1vdmlsaWRhZCBkZSBsYSBjaXVkYWQsIGNvbW8gZXJhIGRlIGVzcGVyYXJzZSwgb2N1cnJlbiBlbiB6b25hcyBjZW50cmFsZXMsIGVzcGVjaWZpY2FtZW50ZSBlbiBiYXJyaW9zIGNvbW8gQ2FyaWJlIHkgTGEgQ2FuZGVsYXJpYS4NCg0KQWwgaWd1YWwgcXVlIGxhIGluZm9ybWFjacOzbiBkZWwgaGVhdG1hcCwgZXN0b3MgZGF0b3Mgc2UgbXVlc3RyYW4gZW4gbGEgYXBsaWNhY2nDs24gZGUgc2hpbnksIGRlYmFqbyBkZSBsYSBzZWNjacOzbiBkZSBhZ3J1cGFtaWVudG8uDQoNCiFbXShtYXBhLnBuZyl7I2lkIC5jbGFzcyB3aWR0aD01MCUgaGVpZ2h0PTUwJX0NCg0KDQpQYXJhIGZpbmFsaXphciBlc3RhIHNlY2Npw7NuLCBzZSBhZ3JlZ8OzIGxhIHRhYmxhIHF1ZSBjbGFzaWZpY2EgZWwgcmllc2dvIGRlbCBiYXJyaW8gZW4gbGEgYmFzZSBkZSBkYXRvcyBwcmljaXBhbCwgcGFyYSBwcm94aW1hbWVudGUgbW9zdHJhciBlc3RhIGRpc3RyaWJ1Y2nDs24gZW4gZWwgbWFwYSBkZSBNZWRlbGzDrW4gYXNpZ25hbmRvIGNvbG9yZXMgYSBsb3MgY2x1c3RlcnMuIExhIGNvbHVtbmEgcXVlZMOzIGNvbiBlbCBub21icmUgU0VHVVJJREFEX0JBUlJJTy4NCg0KIyBDb25jbHVzaW9uZXMNCiAgDQpFbCBtb2RlbG8gbWl4dG8gbyBtb2RlbG8gamVyw6FycXVpY28gZGVtdWVzdHJhIHNlciB1bmEgYnVlbmEgYWx0ZXJuYXRpdmEgcGFyYSBwcmVkZWNpciBsYSBhY2NpZGVudGFsaWRhZCBlbiBsYXMgY29tdW5hIHkgYmFycmlvcyBkZSBNZWRlbGzDrW4gZW4gbGFzIGRpZmVyZW50ZXMgdW5pZGFkZXMgZGUgdGllbXBvIHBsYW50ZWFkYXMgZW4gZXN0ZSB0cmFiYWpvIChkw61hLCBzZW1hbmEsIG1lcyksIHlhIHF1ZSBwcmVzZW50YSB1biAqVHJhaW5fTVNFKiB5IHVuICpUZXN0X01TRSogcmVsYXRpdmFtZW50ZSBwZXF1ZcOxby4NCg0KQWwgaW5jbHVpciB0b2RvcyBsb3MgY2Fzb3MgcG9zaWJsZXMgZW4gbGEgY29uc3RydWNjacOzbiBkZSBsb3MgbW9kZWxvcywgZXMgZGVjaXIsIGluY2x1c28gbG9zIGV2ZW50b3MgZG9uZGUgbm8gb2N1cnJlbiBhY2NpZGVudGVzLCBsb3MgbW9kZWxvcyBtaXh0b3Mgc2UgaGFjZW4gbXV5IHBlc2Fkb3MgY29tcHV0YWNpb25hbG1lbnRlLCB5IGxhcyBiYXNlcyBkZSBkYXRvcyBjb25zaWRlcmFzIGNyZWNlbiBlbiBvYnNlcnZhY2lvbmVzIHNpZ25pZmljYXRpdmFtZW50ZSwgcG9yIGxvIHF1ZSBzZSByZWNvbWllbmRhIGNyZWFyIHVuYSBhbHRlcm5hdGl2YSBkZSBvcHRpbWl6YWNpw7NuIHBhcmEgZWwgdXNvIGRlIGxvcyBtaXNtb3MuDQoNCkVsIGNsdXN0ZXJpbmcgcmVhbGl6YWRvIHBhcmEgZWwgYWdydXBhbWllbnRvIGRlIG1hcGFzIHkgZWwgY3JpdGVyaW8gZWxlZ2lkbyBwYXJhIGFncnVwYXJsb3MgKG7Dum1lcm8gZGUgYWNjaWRlbnRlcykgZGVtdWVzdHJhbiBzZXIgYmllbiBlbGVnaWRvcyBkZWJpZG8gYSBxdWUgbGEgZm9ybWEgZW4gcXVlIHNlIGFncnVwYW4gbG9zIGRhdG9zIHRpZW5lIHNlbnRpZG8gY29uIGxhIHJlYWxpZGFkIGRlIGxhIGNpdWRhZCAoTGEgQ2FuZGVsYXJpYSB5IExhdXJlbGVzIHNvbiBiYXJyaW9zIGNvbiBtdWNobyBmbHVqbyB2ZWjDrWN1bGFyIHkgc2UgZW5jdWVudHJhbiBlbiB6b25hcyBkb25kZSBoYXkgbXVjaGEgYWZsdWVuY2lhIGRlIHBlcnNvbmFzIGRlIHRvZG8gZWwgVmFsbGUgZGUgQWJ1cnLDoSkNCg0KRW4gbG9zIG1lc2VzIGRlIGFnb3N0byBzZSBwdWVkZSBvYnNlcnZhciBxdWUgbGEgYWNjaWRlbnRhbGlkYWQgZXMgbXVjaG8gbWFzIGFsdGEgcXVlIGVuIGxvcyBkZW3DoXMgbWVzZXMsIGFsZ28gYSBkZXN0YWNhciBlcyBxdWUgZWwgbWVzIGRlIGFnb3N0byBlbiBsb3MgYcOxb3MgYW5hbGl6YWRvcyBzZSBmZXN0ZWphYmEgbGEgZmVyaWEgZGUgZmxvcmVzLCBlc3RvIGxsZXZhIGEgcXVlIGxhIGNhbnRpZGFkIGRlIHBlcnNvbmFzIGVuIGxhIGNpdWRhZCBkZSBNZWRlbGzDrW4gc2VhIG1hcyBhbHRhIHkgcG9yIGVuZGUgbWFzIHByb2JhYmlsaWRhZCBkZSBhY2NpZGVudGVzIGFicmEsIHlhIHF1ZSBsYSBjaXVkYWQgZXN0YXLDoSBtYXMgY29uZ2VzdGlvbmFkYSwgZW4gY2FtYmlvIHF1ZSBlbiBsb3MgbWVzZXMgZGUgZGljaWVtYnJlIHkgZW5lcm8gbGEgY2l1ZGFkIGVzdGEgdW4gcG9jbyBtYXMgZGVzY29uZ2VzdGlvbmFkYSBlc3RvIGNhdXNhIHVuYSBwb3NpYmxlIGRpc21pbnVjacOzbiBlbiBsYSBhY2NpZGVudGFsaWRhZCBkZSBNZWRlbGzDrW4uDQoNCg0KIyBSZWNvbWVuZGFjaW9uZXMNCg0KQ3JlYXIgdW4gcGxhbiBkZSBhY2Npw7NuIGlubWVkaWF0byBlbiBsb3MgOSBiYXJyaW9zIHF1ZSBzZSBlbmN1ZW50cmFuIGNvbiBsYSBjYXRlZ29yw61hIGRlICJBY2NpZGVudGFsaWRhZCBhbHRhIiB5YSBxdWUgcHJlc2VudGFuIMOtbmRpY2VzIG11eSBhbHRvcyBxdWUgcHVlZGVuIHRlbmVyIGNvbW8gY29uc2VjdWVuY2lhIHVuIGluY3JlbWVudG8gZW4gICBsYSBhY2NpZGVudGFsaWRhZCB5IG11ZXJ0ZXMgZW4gbGFzIHbDrWFzLg0KICANCkludmVydGlyIGVuIHVuYSBjYW1wYcOxYSBkZSBjb25jaWVuY2lhIHkgcmVzcG9uc2FiaWxpZGFkIGF1dG9tb3ZpbGlzdGEgZW4gZWwgY2VudHJvIHlhIHF1ZSBlbiBlc3RlIGx1Z2FyIGVzIGRvbmRlIG1hcyBzZSBwcmVzZW50YW4gYWNjaWRlbnRlcyBlbiBNZWRlbGzDrW4uDQoNCkN1YW5kbyBoYXkgZXZlbnRvcyBjb21vIGxhIGZlcmlhIGRlIGZsb3JlcyB0ZW5lciBwbGFuZXMgZGUgbW92aWxpZGFkICBtYXMgZXN0cmljdGFzIGVzdG8gY29uIGVsIGZpbiBkZSBkaXNtaW51aXIgbGEgYWx0YSBhY2NpZGVudGFsaWRhZCBlbiBlc2EgZmVzdGl2aWRhZC4NCg0KIyBSZWZlcmVuY2lhcw0KDQogIEFuZHJldyBHZWxtYW4sIEplbm5pZmVyIEhpbGwgKDIwMDcpLiBEYXRhIEFuYWx5c2lzIFVzaW5nIFJlZ3Jlc3Npb24gYW5kDQogIE11bHRpbGV2ZWwvSGllcmFyY2hpY2FsIE1vZGVscy4NCg0KICBEb3VnbGFzIEJhdGVzLCBNYXJ0aW4gTWFlY2hsZXIsIEJlbiBCb2xrZXIsIFN0ZXZlIFdhbGtlciAoMjAxNSkuIEZpdHRpbmcNCiAgTGluZWFyIE1peGVkLUVmZmVjdHMgTW9kZWxzIFVzaW5nIGxtZTQuIEpvdXJuYWwgb2YgU3RhdGlzdGljYWwgU29mdHdhcmUsDQogIDY3KDEpLCAxLTQ4LiBkb2k6MTAuMTg2MzcvanNzLnYwNjcuaTAxLg0KDQogIFdpY2toYW0gZXQgYWwuLCAoMjAxOSkuIFdlbGNvbWUgdG8gdGhlIHRpZHl2ZXJzZS4gSm91cm5hbCBvZiBPcGVuIFNvdXJjZQ0KICBTb2Z0d2FyZSwgNCg0MyksIDE2ODYsIGh0dHBzOi8vZG9pLm9yZy8xMC4yMTEwNS9qb3NzLjAxNjg2DQoNCiAgQWNoaW0gWmVpbGVpcyBhbmQgR2Fib3IgR3JvdGhlbmRpZWNrICgyMDA1KS4gem9vOiBTMyBJbmZyYXN0cnVjdHVyZSBmb3INCiAgUmVndWxhciBhbmQgSXJyZWd1bGFyIFRpbWUgU2VyaWVzLiBKb3VybmFsIG9mIFN0YXRpc3RpY2FsIFNvZnR3YXJlLCAxNCg2KSwNCiAgMS0yNy4gZG9pOjEwLjE4NjM3L2pzcy52MDE0LmkwNg0KDQogIEMuIFNpZXZlcnQuIEludGVyYWN0aXZlIFdlYi1CYXNlZCBEYXRhIFZpc3VhbGl6YXRpb24gd2l0aCBSLCBwbG90bHksIGFuZA0KICBzaGlueS4gQ2hhcG1hbiBhbmQgSGFsbC9DUkMgRmxvcmlkYSwgMjAyMC4NCiAgDQogIFJzdHVkaW8uZ2l0aHViLmlvLiAyMDIwLiBMZWFmbGV0IEZvciBSIC0gSW50cm9kdWN0aW9uLiBbb25saW5lXSBBdmFpbGFibGUgYXQ6IDxodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL2xlYWZsZXQvPiBbQWNjZXNzZWQgMjAgTm92ZW1iZXIgMjAyMF0uDQogIA0KDQogIFRpZW1wbywgQy4sIDIwMjAuIEVzdG9zIFNvbiBMb3MgNSBQdW50b3MgQ29uIE3DoXMgQWNjaWRlbnRlcyBEZSBUcsOhbnNpdG8gRW4gTWVkZWxsw61uLiBbb25saW5lXSBFbCBUaWVtcG8uIEF2YWlsYWJsZSBhdDogPGh0dHBzOi8vd3d3LmVsdGllbXBvLmNvbS9jb2xvbWJpYS9tZWRlbGxpbi9lc3Rvcy1zb24tbG9zLTUtdW50b3MtY29uLW1hcy1hY2NpZGVudGVzLWRlLXRyYW5zaXRvLWVuLW1lZGVsbGluLTIyOTUzND4gW0FjY2Vzc2VkIDIwIE5vdmVtYmVyIDIwMjBdLg0KICANCiAgQ3R1bWVkZWxsaW4uY29tLiAyMDIwLiBNZWRlbGzDrW4sIFVuYSBEZSBMYXMgQ2l1ZGFkZXMgTcOhcyBMZXRhbGVzIFBhcmEgTWFuZWphciDigJMgQ1RVIENPTE9NQklBLiBbb25saW5lXSBBdmFpbGFibGUgYXQ6IDxodHRwOi8vY3R1bWVkZWxsaW4uY29tL3NpdGlvLzIwMTgvMDEvMTYvbWVkZWxsaW4tdW5hLWRlLWxhcy1jaXVkYWRlcy1tYXMtbGV0YWxlcy1wYXJhLW1hbmVqYXIvPiBbQWNjZXNzZWQgMjAgTm92ZW1iZXIgMjAyMF0uDQoNCiAgTEEuTmV0d29yay4gMjAyMC4gRXN0YXMgU29uIExhcyAxMCBDaXVkYWRlcyBMYXRpbm9hbWVyaWNhbmFzIENvbiBNw6FzIE11ZXJ0ZXMgRW4gTGFzIFbDrWFzLiBbb25saW5lXSBBdmFpbGFibGUgYXQ6IDxodHRwczovL2xhLm5ldHdvcmsvY2l1ZGFkZXMtbGF0aW5vYW1lcmljYW5hcy1tdWVydGVzLXZpYXMvPiBbQWNjZXNzZWQgMjAgTm92ZW1iZXIgMjAyMF0uDQoNCg==