quantmod es un paquete diseñado para ayudar a traders del mundo financiero a desarrollar modelos econométricos que puedan ayudarles a hacer su trading.

Este paquete contiene diversas funciones para poder recolectar, visualizar y gestionar data.
getSymbols() es una función que es parte de paquete de quantmod.Esta función crea una xts (extensible time series) con la que es posible descargar data financiera (como cierres de acciones, precios de ETFs, tasas de interés, etc) actual de diversas fuentes (por ejemplo yahoo finance, google finance, FRED y oanda)

En el chonk posterior se descagan a través de getSymbols los datos históricos de Tesla (TSLA) y Microsoft (MSFT) con una periodicidad diaria desde el primedio de enero de 2019 hasta el 28 de febrero de 2023. La fuente de estos datos de yahoo.

NOTA IMPORTANTE: para que se puedan descargar los datos de yahoo finance, es necesario utilizar el “ticker” de las compañías en vez de su nombre comercial. (ejemplo en vez de poner tesla es necesario poner TSLA)

En la función de getSymbols se agregaron los siguiente argumentos: -from= para indicar la fecha inicial de la serie de tiempo -to= para indicar la fecha límite de la serie de tiempo -src= para indicar la fuente de la cual se desean descargar los datos -periodicity= indica la periodicidad de los datos de la serie de tiempo (diaria, mensual, trimestral, anual)

library(quantmod) #esta función se agregó con la intención de descargar los datos del paquete de quantmod a la computadora 

getSymbols(c("MSFT","TSLA"), from="2019-01-01", to="2023-02-28",src="yahoo",periodicity="daily") 
[1] "MSFT" "TSLA"

Después de haber descargado los datos a través de getSymbols, es posible poder ver el contenido de estas series de tiempo.

En la base de datos que fue descargada por yahoo se incluyen diferentes columnas que indican el: -open -high -low -close -adjusted (precio ajustado) -volume data

Debido a que la series de tiempo descragadas son muy largas es posible ver el contenido de las primeras y de las últimas líneas de código a través de diversas funciones.

La función de head() sirve para poder ver las primeras líneas de código.


head(MSFT,5) 
           MSFT.Open MSFT.High MSFT.Low
2019-01-02     99.55    101.75    98.94
2019-01-03    100.10    100.19    97.20
2019-01-04     99.72    102.51    98.93
2019-01-07    101.64    103.27   100.98
2019-01-08    103.04    103.97   101.71
           MSFT.Close MSFT.Volume
2019-01-02     101.12    35329300
2019-01-03      97.40    42579100
2019-01-04     101.93    44060600
2019-01-07     102.06    35656100
2019-01-08     102.80    31514400
           MSFT.Adjusted
2019-01-02      96.63264
2019-01-03      93.07774
2019-01-04      97.40672
2019-01-07      97.53095
2019-01-08      98.23811
#se inclyó el número 5 para indicar que se desean visualizar la primera línea de los datos de la serie de tiempo. Se pueden poner otros argumentos para ver más líneas de la serie de tiempo (ejemplo si se quiere 10 datos se debería usar el código head(MSFT,10))

En el código posterior se utiliza la función tail() para poder ver las últimas líneas de la serie de tiempo

tail(MSFT, n=10)
           MSFT.Open MSFT.High MSFT.Low
2023-02-13    267.64    274.60   267.15
2023-02-14    272.67    274.97   269.28
2023-02-15    268.32    270.73   266.18
2023-02-16    264.02    266.74   261.90
2023-02-17    259.39    260.09   256.00
2023-02-21    254.48    255.49   251.59
2023-02-22    254.09    254.34   250.34
2023-02-23    255.56    256.84   250.48
2023-02-24    249.96    251.00   248.10
2023-02-27    252.46    252.82   249.39
           MSFT.Close MSFT.Volume
2023-02-13     271.32    44630900
2023-02-14     272.17    37047900
2023-02-15     269.32    28922400
2023-02-16     262.15    29603600
2023-02-17     258.06    30000100
2023-02-21     252.67    28397400
2023-02-22     251.51    22491100
2023-02-23     254.77    29219100
2023-02-24     249.22    24990900
2023-02-27     250.16    21190000
           MSFT.Adjusted
2023-02-13      270.6421
2023-02-14      271.4900
2023-02-15      269.3200
2023-02-16      262.1500
2023-02-17      258.0600
2023-02-21      252.6700
2023-02-22      251.5100
2023-02-23      254.7700
2023-02-24      249.2200
2023-02-27      250.1600
#se incluye en el código el argumento n=10, para indicar que se desean ver las últimas 10 líneas de la base de datos. Se pueden cambiar el número de líneas que se desean ver.

Es importante mencionar que el set de datos descargados de TESLA no inlcuye la columna de adjusted price, sin embargo es posible conocer este dato para dia través de la función que se muestra en el siguiente chunk:

adjTSLA = Ad(TSLA) 

#la función de ad sirve para descargar los datos históricos de los precios ajustados de tesla. 

adjTSLA = TSLA$TSLA.Adjusted
#se usa el $ para fijar la columna al data set 

#se nombró a la función ajdTSLA para poderla llamar más adelante

head(adjTSLA) #se utiliza la función head() para poder conocer los primeros 5 datos de la serie 
           TSLA.Adjusted
2019-01-02      20.67467
2019-01-03      20.02400
2019-01-04      21.17933
2019-01-07      22.33067
2019-01-08      22.35667
2019-01-09      22.56867

A continuación se muestra otra forma de seleccionar la columna que contiene el dato del precio ajustado de Tesla

NOTA IMPORTANTE: lo que se incluye en el chunk también puede ser aplicado en caso de que se quieran seleccionar otras columnas


adjTSLA = TSLA[, 6] #la columna de los precios ajustados es la 6, por eso se selecciona esta 

#NOTA IMPORTANTE: en todos los sets de datos se tienen dos dimensiones [filas,columnas]

#es importante nota que en este caso solamente se quiere la información de las columna de datos ajustados, pero se quieren mantener todas las filas. Es por lo anterior que se mantiene el espacio de la fila vacio.

dim(TSLA) #a través de la función dim es posible conocer las dimeciones de todos los sets de datos. 
[1] 1046    6
#con la función de dim es posible conocer que el número total de filas de la serie de datos es 1046, mientras que el total de columnas es 6

Además de poder seleccionar los dtaos específicos de una columna, también es posible seleccionar filas específicas utilizando el mismo método, es decir el de [fila, columna].

En el chunk que se muestra a continuación se muestra como se pueden elegir las primeras 10 filas de la serie de tiempo

TSLAfirstdays = TSLA[1:10,] #como solo se desean conocer las filas 1 a la 10 se utiliza la notación 1:10 .Pero con todas las columnas, entonces se deja el espacio de columnas vació 

TSLAfirstdays #se llama a la función 
           TSLA.Open TSLA.High TSLA.Low
2019-01-02  20.40667  21.00867 19.92000
2019-01-03  20.46667  20.62667 19.82533
2019-01-04  20.40000  21.20000 20.18200
2019-01-07  21.44800  22.44933 21.18333
2019-01-08  22.79733  22.93400 21.80133
2019-01-09  22.36667  22.90000 22.09800
2019-01-10  22.29333  23.02600 22.11933
2019-01-11  22.80600  23.22733 22.58467
2019-01-14  22.82533  22.83333 22.26667
2019-01-15  22.33333  23.25333 22.30000
           TSLA.Close TSLA.Volume
2019-01-02   20.67467   174879000
2019-01-03   20.02400   104478000
2019-01-04   21.17933   110911500
2019-01-07   22.33067   113268000
2019-01-08   22.35667   105127500
2019-01-09   22.56867    81493500
2019-01-10   22.99800    90846000
2019-01-11   23.15067    75586500
2019-01-14   22.29333    78709500
2019-01-15   22.96200    90849000
           TSLA.Adjusted
2019-01-02      20.67467
2019-01-03      20.02400
2019-01-04      21.17933
2019-01-07      22.33067
2019-01-08      22.35667
2019-01-09      22.56867
2019-01-10      22.99800
2019-01-11      23.15067
2019-01-14      22.29333
2019-01-15      22.96200

También es posible seleccionar columnas y filas específicas.

En el chunk que se muestra a continuación se ejemplifica como se puede seleccionar columnas y filas específicas al seleccionar los primeros 10 días de los precios ajustados de tesla

TSLA_adjusted_first_prices = TSLA[1:6,6] #se selecciona de las filas 1 a 10, pues contienen los primeros 10 datos. De igual manera se seleccionan la columna 6 que contiene los datos de los precios ajustados. 

head(TSLA_adjusted_first_prices)
           TSLA.Adjusted
2019-01-02      20.67467
2019-01-03      20.02400
2019-01-04      21.17933
2019-01-07      22.33067
2019-01-08      22.35667
2019-01-09      22.56867

Si se desea seleccionar más de una columna, entonces se puede utilizar el contenedor c() e indicar que columnas se desean seleccionar. A continuación se presenta un ejemplo en el que se desean conocer los datos del open y close (columnas 1 y 4) de los primero 10 días de la base de datos (fila 1 a 10)

TSLA_Open_Close = TSLA[1:10,c(1,4)]
head(TSLA_Open_Close)
           TSLA.Open TSLA.Close
2019-01-02  20.40667   20.67467
2019-01-03  20.46667   20.02400
2019-01-04  20.40000   21.17933
2019-01-07  21.44800   22.33067
2019-01-08  22.79733   22.35667
2019-01-09  22.36667   22.56867

Una nota importante es que también se pueden seleccionar filas utilizando el índice de fechas. Por ejemplo si se desean seleccionar todos los precios de la acción de Tesla del año 2021, entonces se puede hacer los siguiente:

TESLA_2021 = TSLA["2021-01-01/2021-12-31", ] #como no se mencionan argumentos de columnas, entonces se incluyen todas las columnas
head(TESLA_2021)
           TSLA.Open TSLA.High TSLA.Low
2021-01-04  239.8200  248.1633 239.0633
2021-01-05  241.2200  246.9467 239.7333
2021-01-06  252.8300  258.0000 249.7000
2021-01-07  259.2100  272.3300 258.4000
2021-01-08  285.3333  294.8300 279.4633
2021-01-11  283.1333  284.8100 267.8733
           TSLA.Close TSLA.Volume
2021-01-04   243.2567   145914600
2021-01-05   245.0367    96735600
2021-01-06   251.9933   134100000
2021-01-07   272.0133   154496700
2021-01-08   293.3400   225166500
2021-01-11   270.3967   177904800
           TSLA.Adjusted
2021-01-04      243.2567
2021-01-05      245.0367
2021-01-06      251.9933
2021-01-07      272.0133
2021-01-08      293.3400
2021-01-11      270.3967

También es posible combinar la selección de columnas y la selección de filas con el índice de fechas

TESLA_2021_adjusted = TSLA["2021-01-01/2021-12-31", "TSLA.Adjusted"]
#NOTA IMPORTANTE: es posible seleccionar las columnas al poner el número de columna, o su nombre.

head(TESLA_2021_adjusted) #se llaman los primeros 6 datos de la selección 
           TSLA.Adjusted
2021-01-04      243.2567
2021-01-05      245.0367
2021-01-06      251.9933
2021-01-07      272.0133
2021-01-08      293.3400
2021-01-11      270.3967

DATA MERGING

Se puede utilizar la función de merge() para unir a dos o más series de tiempo, para integrarlas a una sola data sheet

prices = merge(MSFT,TSLA)
# To get only Adjusted prices:
adjprices = Ad(prices)

También se puede utilizar una función dentro de otra función para tener mejor gestión de la data.

POr ejemplo es posible realizar todo el código del chunk anterior, con solamente una línea de código:

adjprices <- Ad(merge(MSFT,TSLA))

Ahora que se tiene una sola datasheet con los precios ajustados de ambas acciones, es posible cambiar el nombre de las columnas. Como se muestra a continuación:

names(adjprices)<-c("msft","tesla")

Ahora es posible hacer referencias a los precios ajustados utilizando estos nombres

head(adjprices$tesla) #se pone adjprices$tesla para indicar que se desea conocer los primeros 6 datos del precio ajustado de tesla 
              tesla
2019-01-02 20.67467
2019-01-03 20.02400
2019-01-04 21.17933
2019-01-07 22.33067
2019-01-08 22.35667
2019-01-09 22.56867
# si se quisiera conocer los primeros 6 datos del precio ajustado de microsft se utilizaría la siguiente función: head(adjprices$msft)

VISUALIZACIÓN DE LOS PRECIOS

Para entender de mejor manera y visualizar como han sido valuadas las acciones de tesla y de microsoft a lo largo del tiempo, es necesario graficar la función de adjprices

plot(adjprices)

Cuando ambas series tienen diferentes escalas es mejor graficarlas de manera separada

plot(adjprices,multi.panel=TRUE)

#con el argumento multi.panel=true, es posible comparar las dos gráficas por separado

Es importante considerar que al comparar dos acciones la magnitud del precio ajustado no pueden utilizarse para definir cual de las dos acciones tiene un valor de mercado más alto. Lo anterior se debe a que el valor de mercado se da a través del mercado de capitalización, es decir a través de la multiplicación del precio ajustado por el número de acciones. (valor de mercado=precio ajustado x número de acciones)

Se puede utiliza la función chartSeries, para poder visualizar tanto el precio ajustado de la acción como el trading volume

chartSeries(MSFT, theme=("white"))

#theme white se utiliza para que el fondo de la gráfica sea blanco. El único otro color que se puede aplicar la fondo de esta gráfica es negro

También es posible graficar periosos específicos, por ejemplo es posible graficar el comportamiento del precio ajustado de Microsoft en 2021 solamente:

chartSeries(MSFT, subset = '2021-01-01/2021-12-31')

#como se había mencionadp anteriormente chartSeries ayuda a graficar tanto el precio ajustado de la acción como el volumen

#se agrega el argumento subset, para así poder incluir el periodo de tiempo (o índice de tiempo) específico que se desea graficar 

RETORNOS FINANCIEROS PARA SERIES DE TIEMPO

Como es bien sabido existen múltiples maneras de obtener el retorno de una acción. Entre los principales métodos se encuentra el dividir el precio ajustado de una acción entre el precio ajustado del periodo anterior, y eso restarlo entre 1. (ejemplo para sacar el retorno de enero de 2022 sería necesario realizar lo siguiente: (precio ajustado enero 2022/precio ajustado diciembre 2021)-1)

El método más recomendable es el de sacar la diferencia del logaritmo del precio más reciente y del precio del periodo anterior. (ejemplo para sacar el retorno de enero de 2022 sería necesario realizar lo siguiente: log(precio ajustado enero 2022/precio ajustado diciembre 2021))

RETORNOS SIMPLES EN SERIES DE TIEMPO:

Para poder calcular el retorno simple deberá ser necesario utilizar el precio ajustado de las acciones. Para calcular el valor pasado del precio de una variable de series de tiempo se puede utilizar la función lag.

R = adjprices / stats::lag(adjprices,n=1) - 1 
head(R)
                   msft        tesla
2019-01-02           NA           NA
2019-01-03 -0.036787785 -0.031471704
2019-01-04  0.046509282  0.057697413
2019-01-07  0.001275364  0.054361202
2019-01-08  0.007250632  0.001164318
2019-01-09  0.014299491  0.009482585

RETORNOS COMPUESTOS CONTINUOS

Se pueden sacar los retornos compuestos continuos utilizando los valores descontads al utilizar las funciones de diff() y de log().

NOTA: la función diff calcula la diferencia entre el valor de tiempo de la serie y su valor pasado

r = diff(log(adjprices))
head(r)
                   msft        tesla
2019-01-02           NA           NA
2019-01-03 -0.037481523 -0.031977580
2019-01-04  0.045460132  0.056094294
2019-01-07  0.001274551  0.052935088
2019-01-08  0.007224472  0.001163641
2019-01-09  0.014198217  0.009437908

Es importante recordar que los log prices son retornos compuestos de manera continua en un periodo.

También se pueden graficar los retornos diarios que Tesla ha tenido a lo largo del timepo.

A continuación es posible ver que existe una alta volatilidad en los retornos diarios durante los meses que duró la pandemia. Esta volatilidad puede ser calculada a através de la desviación estándar

plot(R$tesla)

ESTADÍSTICAS DESCRIPTIVAS CON SERIES DE TIEMPO

El paquete PerfomanceAnalytics contiene diversas funciones para realizar estadísticas descriptivas

library(PerformanceAnalytics)
table1 <- table.Stats(R) #la función table.Stats sirve para conocer las medidas estadísticas descriptivas básicas de una serie de tiempo

table1 #se llama la función 

En caso de que se desee obtener estadísticas descriptivas específicas se pueden utilizar diferentes funciones, como mean() y sd

mean_tesla_R = mean(R$tesla, na.rm=TRUE) #la función mean() sirve conocer el promedio 

median_tesla_R = median(R$tesla, na.rm=TRUE)
#la función median() sirve conocer la mediana

sd_tesla_R = sd(R$tesla, na.rm=TRUE)
#la función sd() sirve para conocer la desviación estandar 

#NOTA IMPORTANTE na.rm=TRUE es una opción que ayuda a que se eliminen los valores NA antes de realizar los calculos 

cat("Tesla daily mean return is ",mean_tesla_R, "\n") 
Tesla daily mean return is  0.003113736 
#NOTA IMPORTANTE: la función cat (siglas para concentrate and prime) da salida a los datos en el formato deseado

A través de la línea de código 234 es posible conocer que la media del retorno diario de tesla es 0.0031

cat("Tesla daily median return is ",median_tesla_R, "\n")
Tesla daily median return is  0.002260816 

A través del código en el chunk anterior es posible conocer que la mediana del retorno diario de tesla es 0.00226

cat("Tesla daily volatility is ", sd_tesla_R)
Tesla daily volatility is  0.04253301

A través del código en el chunk anterior es posible conocer que la volatilidad (es decir la desviación estandar) del retorno diario de tesla es 0.04253

NOTA IMPORTANTE: cuando existen valores de NA en las columnas el programa no puede calcular las estadísticas descriptivas, a menos de que se utilicé la opción na.rm=TRUE.

Cuando la media y la mediana son muy diferentes, por lo general se toma como señal de que no hay normalidad en la distribución de la variable. En el ejemplo de tesla se puede ver que la mediana es mucho menor que la medio (media=0.14% y mediana 0.31%). La mediana es mejor métrica para medir los valores centrales de tendencia de retornos financieros.

NOTA IMPORTANTE: si la Kurtosis de la variable es mayor a 3, entonces la variable tiene valores más extremos que una distribución normal.

En el ejemplo de Tesla se puede ver que tanto la media como la mediana tienen valores nayores a tres.

NOTA IMPORTANTE: por lo general los retornos financieros tienen valores más extremos a comparación de variables que tienen distribución normal, por lo que la desviación estandar no es suficiente para entender de mejor manera la dispersión de los retornos.

NOTA IMPORTANTE: los quartiles dan una mejor percepción de la volatilidad de los retornos financieros. Por lo que se recomienda utilizar el gráfico de caja.

chart.Boxplot(R)


#los círculos rojos que se muestran en el gráfico son la media, la límea en medio es la mediana. 
#las cajas incluyen 50% de data del Q1 o Q1 (presentíl 25) al Q3. 
#las líneas verticales limitan los valores no extremos. 
#Los puntos son los valores extremos de la distribución

Ahora que se esta utlizando el gráfico de caja es posible entender de menor manera que Microsoft tiene más volatilidad que Tesla (ósea que es más riesgoso que tesla).

VISUALIZING HOLDING RETURNO OVER TIME

Se puede utilizar la función de charts.PerformanceSummary() para visualizar cuanto se generaría si se invirtiera $1 y se mantuviera por un periodo de tiempo.

charts.PerformanceSummary(R$tesla, 
                          main = "Performance of $1.00 Tesla",
                          wealth.index = TRUE)

También es posible calcular el exact holding period return al obtener el porcentaje de crecimiento de la serie a través del precio ajustado

hpr_tesla = as.numeric(adjprices$tesla[nrow(adjprices)]) / as.numeric(adjprices$tesla[1]) - 1
hpr_tesla
[1] 9.042725

Al expresar el dato arrojado por el programa en porcentaje se tiene 904.2725% de retorno de holding period.

Al interpretar lo anterior tenemos que si se invirtiera $1 en Tesla al inicio del periodo, entonces se tendría $10.04273 al final del periodo.

Este mismo ejercicio puede ser realizado para Microsoft:

charts.PerformanceSummary(R$msft, 
                          main = "Performance of $1.00 in Microsoft",
                          wealth.index = TRUE)


hpr_msft = as.numeric(adjprices$msft[nrow(adjprices)]) / as.numeric(adjprices$msft[1]) - 1
hpr_msft
[1] 1.588773
#Al expresar el dato arrojado por el programa en porcentaje se tiene 158.8773% de retorno de holding period. 

#Al interpretar lo anterior tenemos que si se invirtiera $1 en Microsoft al inicio del periodo, entonces se tendría $10.04273 al final del periodo. 

DATA STRUCTURES

Existen 3 estructuras de data set: -Series de tiempo (varios periodos de tiempo y se pueden tener varios sujetos que se muestran en columnas) -Cross sectional (muchos sujetos, pero solamente 1 periodo de tiempo) -Panel data structure (varios sujetos y más de un periodo de tiempo para cada sujeto)

DATA MANAGMENT FOR PANEL DATA

Antes de diseñar un modelo econométrico es necesario tener una gestión simple y sofisticada de la data que se va a manejar.

En el ejemplo se mostrará como combinar dos datasets (una serie de tiempo con la información histórica del IPyC, y un data ser con la información de cuartos de año de diferentes empresas mexicanas)

NOTA IMPORTANTE: solamente se pueden fusionar datasets que tengan la misma granularidad, es decir data sets que compartan la misma periodicidad. Lo que quiere decir que si se tiene dos series de tiempo, una con datos anuales y la otra con datos mensuales, entonces no se podrán fusionar.

En el chunk posterior se descargará la información del sitio economatica, y contiene la información de cuartos de año de rms mexicanas

# primero es importante descargar el paquete readxl que permite descargar documentos de excel de sitios web
library(readxl)
download.file("http://www.apradie.com/datos/datamx2020q4.xlsx",
              "firmspaneldata.xlsx", mode="wb")
trying URL 'http://www.apradie.com/datos/datamx2020q4.xlsx'
Content type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' length 5163617 bytes (4.9 MB)
==================================================
downloaded 4.9 MB
# se utiliza la función download file para descargar el archivo, y luego se pone como argumento el sitio de donde se va a descargar el archivo
# el último argumento indica que se va a descargar el excel como documento local 

paneldataset <- read_excel("firmspaneldata.xlsx")

Se necesita fusionar el retorno mensual del mercado con el data set anterior por lo que se necesita realizar los siguente 1. Descargar el mercado mensual de yahoo a través de la función getSymbols()

library(quantmod)
getSymbols("^MXX", from="2000-01-01", to= "2019-12-31",
            periodicity="monthly", src="yahoo")
[1] "^MXX"
  1. transformar (collapse) la data para que sea cuatrimestral
QMXX <- to.quarterly(MXX,indexAt='startof')
head(QMXX) #se utilizó head para poder ver el contenido de la data
           MXX.Open MXX.High MXX.Low MXX.Close
2000-01-01  7185.71  8417.33 6510.84   7473.25
2000-04-01  7459.75  7639.38 5516.77   6948.33
2000-07-01  6953.73  7548.57 6171.95   6334.56
2000-10-01  6334.64  6502.60 5148.02   5652.19
2001-01-01  5651.35  6615.83 5512.77   5727.89
2001-04-01  5733.67  6895.70 5541.68   6666.17
           MXX.Volume MXX.Adjusted
2000-01-01          0      7473.25
2000-04-01          0      6948.33
2000-07-01          0      6334.56
2000-10-01          0      5652.19
2001-01-01          0      5727.89
2001-04-01 4888424600      6666.17

Como se puede ver en la data anterior se muestran las columnas de open, high, low, colse, volumen y adjusted price. Sin embargo solamente se necesitará el precio ajustado para calcular el retorno, por lo que solamente se selecciona la columna de Close

QMXX = QMXX$MXX.Adjusted
#se le cambio el nombre a la columna 
colnames(QMXX) <- "MXXindex"

Ahora es posible calcular el retorno del mercado

QMXX$MXXreturns <- diff(log(QMXX)) #recordando que la función de diff() ayuda a sacar la diferencia en los datos y log() ayuda a sacar los logaritmos. 

Casi todo esta listo para poder fusionar esta data cuatrimestral con el panel dataset, sin embargo antes es necesario tener ambos data sets en una misma columna. En este caso la columna en común es la de un cuarto.

La función llamada QMXX tiene el índice de cuarto, pero no como columna, por lo que a continuación se creará un data frame con la columna de cuarto igual al índice

QMXX.df<-data.frame(quarter=index(QMXX),coredata(QMXX)) #se crea un dataframe con una columna de cuarto
#en este chunk se copia la inforación del índice QMXX y después se utiliza coredata() 
#coredata() es una función que copia la información de un objeto perio sin copiar el formato 

La columna en común debe de ser del mismo tipo para asegurar que la columna de cuarto del dataset sea Data type:

paneldataset$quarter<-as.Date(paneldataset$quarter)

3- fusionar la nueva serie de tiempo con el panel data

paneldataset<-merge(paneldataset,QMXX.df,by="quarter")
#después de utilizar la función de mergue ahora se tiene un dataset para las empresas mexicanas, la información histórica del IPyC y los retornos del IPyC. 

SETTING A PANEL DATA STRUCTURE

Es importante que el data set (ósea el paneldataset) tenga la estructura de un cuarto anual (para las empresas mexicanas de la data).

Para lo anterior es necesario definir al dataset como un panel de data. Esto se puede lograr utilizar la función de pdata.frame().

NOTA IMPORTANTE: para poder utilizar esta función es necesario instalar el paquete plm

En el chunk posterior se indica que el indice del data panel va a tener el a las empresas como sujeto y la columna con los cuartos como el tiempo

library(plm)
paneldataset <- pdata.frame(paneldataset, index= c("firmcode","quarter"))

DATA CALCULATIONS WITH PANEL DATA

Para poder realizar selecciones y calculos en panel data sets es necesario utilizar el paquete dplyr.

NOTA IMPORTANTE: dplyr es un paquete que tiene herramientas muy poderosas que pueden facilitar la gestión de panel data sets.

library(dplyr)

Es importante mencionar que el data set que se ha estado utilizando tiene información histórica quatrimestral de empresas que estan activas y no activas en la Bolsa Mexicana de Valores. Para este ejercicio solamente se van a necesitar las empresas que si están activas en la BMV.

En el chunk posterior se muestra como mantener solamente las empresas que son necesarias para el ejercicio.

activedata<-paneldataset[paneldataset$status=="active",]
activedata<-activedata[activedata$year>=2010,]

#como se puede observar se seleccionan las filas que se desean al incluir argumentos como que en la columna de status tengan el valor "active". 

Ahora que se seleccionaron las empresas que estan activas en la BMV, de acuerdo a la base de datos, es importate también seleccionar ciertas columnas de este data set que puedan ser de utilidad para hacer ciertas operaciones financieras.

Para poder realizar lo anterior se utilizará la operación “%>%” (que puede utilizarse después de instalar el paquete dplyr)

activedata<-activedata %>%
    select(firm,quarter,year,revenue,cogs,ebit,totalassets,
           adjustedstockprice, naics1)

#se seleccionan las columnas deseadas después de utilizar la operación %>%

CALCULATING FINANCIAL RETURNS AND RATIOS WITH PANEL DATA

Para poder calcular los retornos del panel data set se utiliza el mismo método que se tomo en cuenta para calcular los retornos de tesla y de microsoft (es decir sacar la diferencia de los logaritmos de los datos)

activedata$r = diff(log(activedata$adjustedstockprice))

Al realizar la acción anterior se agregó una columna al en el panel data. En caso de que existiera un cabio en alguna de las empresas no sería necesario calculcar los rendimientos de nuevo, solamente habría de revisar si los valores de los primeros cuartos de cada empresa tienen el valor de NA. A continuación se va a calcular el retorno sobre activos (ROA) utilizando el EBIT en vez de la utilidad neta:

activedata$ROA = activedata$ebit / activedata$totalassets

A contnuación se calcularán el margen de utilidad/profit margin(PM) y la rotación de activos (ATO). Para el calculo de del margen de utilidad se utilizará el EBIT en lugar de la utilidad neta:

activedata$PM = activedata$ebit / activedata$revenue
activedata$ATO = activedata$revenue / activedata$totalassets

USING CONDITIONALS TO CREATE COLUMNS

A continuación se va a crear una columna con variables binarias que ayuden a identificar de manera más sencilla si el ROA en un cuarto específico es mayor al ROA de cuatro cuartos (un año) previo.

Para poder lograr lo anterior será necesario utilizar la función ifelse().


activedata$ROAsignal = ifelse(activedata$ROA>
                    plm::lag(activedata$ROA, 4),1,0)

#en el primer parámetro de la función se usa un condición logica que puede ser verdadera o falsa. En este caso la condición evalua si el ROA es mayor que el ROA de cuatro periodos anteriores.

#En caso de la condición sea verdadera entonces se le asignará el valor del segundo parametro, si la condición es falsa se le asgnará el tercer parametro.

NOTA IMPORTANTE: ifelese() es una de gran utilidad especialmente en la gestión de data financiera, pues puede crear señales que comparen valores financeros. La estructura general de esta función es la siguiente: ifelse(data_condition, value_if_TRUE, value_if_FALSE)

A continuación se muestra un ejemplo de como puede ser utilizada la función

a=5
b=10
ifelse(a>b,1,0)
[1] 0
#debido a que “a” no es mayor a “b”, entonces la función arroja el resultado de 0.

DESCRIPTIVE STATISTICS WITH PANEL DATA

NOTA IMPORTANTE: el proceso para sacar las estadísticas descriptivas de un data panel no es el mismo que se usa para poder obtener las estadísticas descriptivas de una serie de tiempo. Es de suma importante tomar en cuenta el periodo del data panel a la hora de sacar estadísticas, pues el descuido de este aspecto puede resultar en la obtención de datos erróneos.

Es posible empezar a realizar el proceso de sacar las estadísticas descriptivas al seleccionar el último cuarto de la data:

data2019q4 = activedata[activedata$quarter=='2019-10-01',]
summary(data2019q4[,c(4:7,10)])
    revenue               cogs          
 Min.   :0.000e+00   Min.   :        0  
 1st Qu.:3.257e+06   1st Qu.:   672312  
 Median :1.063e+07   Median :  5771803  
 Mean   :5.096e+07   Mean   : 33001268  
 3rd Qu.:3.540e+07   3rd Qu.: 22720676  
 Max.   :1.007e+09   Max.   :630651367  
 NA's   :30          NA's   :30         
      ebit            totalassets       
 Min.   : -6734642   Min.   :2.454e+04  
 1st Qu.:   266741   1st Qu.:1.011e+07  
 Median :  1673254   Median :3.156e+07  
 Mean   :  6282411   Mean   :1.031e+08  
 3rd Qu.:  5079130   3rd Qu.:7.706e+07  
 Max.   :154840535   Max.   :1.580e+09  
 NA's   :25          NA's   :8          
       r           
 Min.   :-0.49758  
 1st Qu.:-0.04220  
 Median : 0.01014  
 Mean   : 0.02954  
 3rd Qu.: 0.08786  
 Max.   : 0.80507  
 NA's   :22        

En el chunk posterior se utilizará el paquete dplyr para seleccionar el último cuarto del data set, se agrupar a las empresas por industrias y se sacar la mediana de las variables principales.

industries<-unique(activedata$naics1)
activedata %>% 
   filter(quarter=='2019-10-01') %>%
  group_by(naics1) %>% 
  summarize(firms = n(),
            median_total_assets = median(totalassets, na.rm = TRUE),
            median_revenue = median(revenue, na.rm = TRUE),
            median_ebit = median(ebit, na.rm = TRUE))

Los datos anteriores muestran el estado del mercado financiero mexicano.

NOTA IMPORTANTE: la media aritmética no es el mejor instrumento para poder representar el estado actual del mercado. Es debido a lo anterior que es mejor utilizar la mediana, pues la mejor medida de tendencia central para medir variables financieras como ingreso total o activos totales es la mediana, pues

LOOKING AT THE 2 TABLES ABOVE, PROVIDE A GOOD DESCRIPTION OF A TYPICAL (AVERAGE) FIRM IN MEXICO, AND A DESCRIPTION OF THE MEXICAN MARKET IN TERMS OF FIRMS BY INDUSTRY AND FIRM SIZE FOR EACH INDUSTRY.

Como se puede observar en la última tabla, la industria con más empresas activas en la Bolsa de Valores Mexicana es la industria de manufactura,la segunda más grande es la de finanzas y seguros.

Las industras más pequeñas son las de las de gestión de empresas y de salud y asistencia social, pues estan cuentan con solamente 1 empresa respectivamente que cotiza en la BVM.

A pesar de que el sector de gestión y empresas es uno de los más pequeños es importante notar que de acuerdo a la mediana, es el sector con el total de activos, mayor revenue y EBIT. Lo que indica que el sector, o más bien dicho la empresa que esta activa en la BMV es muy rentable.

Por su parte es importante resaltar de igual manera que la industria de manufactura es la segunda con mayores activos, la tercera en revenue y la segunda con mayor EBIT. Es lo que indica que esta industria además de ser una industria muy grande, también es muy rentable.

LS0tCnRpdGxlOiAiV29ya3Nob3AgMSwgQWxnb3RpdGhtcyBhbmQgRGF0YSBBbmFseXNpcyIKYXV0b3I6IFZhbGVyaWEgRXN0ZWZhbsOtYSBQYWRpbGxhIEJhcm92aWVyCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCnF1YW50bW9kIGVzIHVuIHBhcXVldGUgZGlzZcOxYWRvIHBhcmEgYXl1ZGFyIGEgdHJhZGVycyBkZWwgbXVuZG8gZmluYW5jaWVybyBhIGRlc2Fycm9sbGFyIG1vZGVsb3MgZWNvbm9tw6l0cmljb3MgcXVlIHB1ZWRhbiBheXVkYXJsZXMgYSBoYWNlciBzdSB0cmFkaW5nLiAKCkVzdGUgcGFxdWV0ZSBjb250aWVuZSBkaXZlcnNhcyBmdW5jaW9uZXMgcGFyYSBwb2RlciByZWNvbGVjdGFyLCB2aXN1YWxpemFyIHkgZ2VzdGlvbmFyIGRhdGEuICAKZ2V0U3ltYm9scygpIGVzIHVuYSBmdW5jacOzbiBxdWUgZXMgcGFydGUgZGUgcGFxdWV0ZSBkZSBxdWFudG1vZC5Fc3RhIGZ1bmNpw7NuIGNyZWEgdW5hIHh0cyAoZXh0ZW5zaWJsZSB0aW1lIHNlcmllcykgY29uIGxhIHF1ZSBlcyBwb3NpYmxlIGRlc2NhcmdhciBkYXRhIGZpbmFuY2llcmEgKGNvbW8gY2llcnJlcyBkZSBhY2Npb25lcywgcHJlY2lvcyBkZSBFVEZzLCB0YXNhcyBkZSBpbnRlcsOpcywgZXRjKSBhY3R1YWwgZGUgZGl2ZXJzYXMgZnVlbnRlcyAocG9yIGVqZW1wbG8geWFob28gZmluYW5jZSwgZ29vZ2xlIGZpbmFuY2UsIEZSRUQgeSBvYW5kYSkKCkVuIGVsIGNob25rIHBvc3RlcmlvciBzZSBkZXNjYWdhbiBhIHRyYXbDqXMgZGUgZ2V0U3ltYm9scyBsb3MgZGF0b3MgaGlzdMOzcmljb3MgZGUgVGVzbGEgKFRTTEEpIHkgTWljcm9zb2Z0IChNU0ZUKSBjb24gdW5hIHBlcmlvZGljaWRhZCBkaWFyaWEgZGVzZGUgZWwgcHJpbWVkaW8gZGUgZW5lcm8gZGUgMjAxOSBoYXN0YSBlbCAyOCBkZSBmZWJyZXJvIGRlIDIwMjMuIExhIGZ1ZW50ZSBkZSBlc3RvcyBkYXRvcyBkZSB5YWhvby4gCgpOT1RBIElNUE9SVEFOVEU6IHBhcmEgcXVlIHNlIHB1ZWRhbiBkZXNjYXJnYXIgbG9zIGRhdG9zICBkZSB5YWhvbyBmaW5hbmNlLCBlcyBuZWNlc2FyaW8gdXRpbGl6YXIgZWwgInRpY2tlciIgZGUgbGFzIGNvbXBhw7HDrWFzIGVuIHZleiBkZSBzdSBub21icmUgY29tZXJjaWFsLiAoZWplbXBsbyBlbiB2ZXogZGUgcG9uZXIgdGVzbGEgZXMgbmVjZXNhcmlvIHBvbmVyIFRTTEEpCgpFbiBsYSBmdW5jacOzbiBkZSBnZXRTeW1ib2xzIHNlIGFncmVnYXJvbiBsb3Mgc2lndWllbnRlIGFyZ3VtZW50b3M6IAotZnJvbT0gcGFyYSBpbmRpY2FyIGxhIGZlY2hhIGluaWNpYWwgZGUgbGEgc2VyaWUgZGUgdGllbXBvCi10bz0gcGFyYSBpbmRpY2FyIGxhIGZlY2hhIGzDrW1pdGUgZGUgbGEgc2VyaWUgZGUgdGllbXBvIAotc3JjPSBwYXJhIGluZGljYXIgbGEgZnVlbnRlIGRlIGxhIGN1YWwgc2UgZGVzZWFuIGRlc2NhcmdhciBsb3MgZGF0b3MKLXBlcmlvZGljaXR5PSBpbmRpY2EgbGEgcGVyaW9kaWNpZGFkIGRlIGxvcyBkYXRvcyBkZSBsYSBzZXJpZSBkZSB0aWVtcG8gKGRpYXJpYSwgbWVuc3VhbCwgdHJpbWVzdHJhbCwgYW51YWwpCgpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkgI2VzdGEgZnVuY2nDs24gc2UgYWdyZWfDsyBjb24gbGEgaW50ZW5jacOzbiBkZSBkZXNjYXJnYXIgbG9zIGRhdG9zIGRlbCBwYXF1ZXRlIGRlIHF1YW50bW9kIGEgbGEgY29tcHV0YWRvcmEgCgpnZXRTeW1ib2xzKGMoIk1TRlQiLCJUU0xBIiksIGZyb209IjIwMTktMDEtMDEiLCB0bz0iMjAyMy0wMi0yOCIsc3JjPSJ5YWhvbyIscGVyaW9kaWNpdHk9ImRhaWx5IikgCgpgYGAKCkRlc3B1w6lzIGRlIGhhYmVyIGRlc2NhcmdhZG8gbG9zIGRhdG9zIGEgdHJhdsOpcyBkZSBnZXRTeW1ib2xzLCBlcyBwb3NpYmxlIHBvZGVyIHZlciBlbCBjb250ZW5pZG8gZGUgZXN0YXMgc2VyaWVzIGRlIHRpZW1wby4KCkVuIGxhIGJhc2UgZGUgZGF0b3MgcXVlIGZ1ZSBkZXNjYXJnYWRhIHBvciB5YWhvbyBzZSBpbmNsdXllbiBkaWZlcmVudGVzIGNvbHVtbmFzIHF1ZSBpbmRpY2FuIGVsOiAKLW9wZW4gCi1oaWdoCi1sb3cgCi1jbG9zZSAKLWFkanVzdGVkIChwcmVjaW8gYWp1c3RhZG8pCi12b2x1bWUgZGF0YQoKRGViaWRvIGEgcXVlIGxhIHNlcmllcyBkZSB0aWVtcG8gZGVzY3JhZ2FkYXMgc29uIG11eSBsYXJnYXMgZXMgcG9zaWJsZSB2ZXIgZWwgY29udGVuaWRvIGRlIGxhcyBwcmltZXJhcyB5IGRlIGxhcyDDumx0aW1hcyBsw61uZWFzIGRlIGPDs2RpZ28gYSB0cmF2w6lzIGRlIGRpdmVyc2FzIGZ1bmNpb25lcy4KCkxhIGZ1bmNpw7NuIGRlIGhlYWQoKSBzaXJ2ZSBwYXJhIHBvZGVyIHZlciBsYXMgcHJpbWVyYXMgbMOtbmVhcyBkZSBjw7NkaWdvLiAKCmBgYHtyfQoKaGVhZChNU0ZULDUpIAojc2UgaW5jbHnDsyBlbCBuw7ptZXJvIDUgcGFyYSBpbmRpY2FyIHF1ZSBzZSBkZXNlYW4gdmlzdWFsaXphciBsYSBwcmltZXJhIGzDrW5lYSBkZSBsb3MgZGF0b3MgZGUgbGEgc2VyaWUgZGUgdGllbXBvLiBTZSBwdWVkZW4gcG9uZXIgb3Ryb3MgYXJndW1lbnRvcyBwYXJhIHZlciBtw6FzIGzDrW5lYXMgZGUgbGEgc2VyaWUgZGUgdGllbXBvIChlamVtcGxvIHNpIHNlIHF1aWVyZSAxMCBkYXRvcyBzZSBkZWJlcsOtYSB1c2FyIGVsIGPDs2RpZ28gaGVhZChNU0ZULDEwKSkKYGBgCgpFbiBlbCBjw7NkaWdvIHBvc3RlcmlvciBzZSB1dGlsaXphIGxhIGZ1bmNpw7NuIHRhaWwoKSBwYXJhIHBvZGVyIHZlciBsYXMgw7psdGltYXMgbMOtbmVhcyBkZSBsYSBzZXJpZSBkZSB0aWVtcG8gCmBgYHtyfQp0YWlsKE1TRlQsIG49MTApCiNzZSBpbmNsdXllIGVuIGVsIGPDs2RpZ28gZWwgYXJndW1lbnRvIG49MTAsIHBhcmEgaW5kaWNhciBxdWUgc2UgZGVzZWFuIHZlciBsYXMgw7psdGltYXMgMTAgbMOtbmVhcyBkZSBsYSBiYXNlIGRlIGRhdG9zLiBTZSBwdWVkZW4gY2FtYmlhciBlbCBuw7ptZXJvIGRlIGzDrW5lYXMgcXVlIHNlIGRlc2VhbiB2ZXIuCmBgYAoKRXMgaW1wb3J0YW50ZSBtZW5jaW9uYXIgcXVlIGVsIHNldCBkZSBkYXRvcyBkZXNjYXJnYWRvcyBkZSBURVNMQSBubyBpbmxjdXllIGxhIGNvbHVtbmEgZGUgYWRqdXN0ZWQgcHJpY2UsIHNpbiBlbWJhcmdvIGVzIHBvc2libGUgY29ub2NlciBlc3RlIGRhdG8gcGFyYSBkaWEgdHJhdsOpcyBkZSBsYSBmdW5jacOzbiBxdWUgc2UgbXVlc3RyYSBlbiBlbCBzaWd1aWVudGUgY2h1bms6IAoKYGBge3J9CmFkalRTTEEgPSBBZChUU0xBKSAKCiNsYSBmdW5jacOzbiBkZSBhZCBzaXJ2ZSBwYXJhIGRlc2NhcmdhciBsb3MgZGF0b3MgaGlzdMOzcmljb3MgZGUgbG9zIHByZWNpb3MgYWp1c3RhZG9zIGRlIHRlc2xhLiAKCmFkalRTTEEgPSBUU0xBJFRTTEEuQWRqdXN0ZWQKI3NlIHVzYSBlbCAkIHBhcmEgZmlqYXIgbGEgY29sdW1uYSBhbCBkYXRhIHNldCAKCiNzZSBub21icsOzIGEgbGEgZnVuY2nDs24gYWpkVFNMQSBwYXJhIHBvZGVybGEgbGxhbWFyIG3DoXMgYWRlbGFudGUKCmhlYWQoYWRqVFNMQSkgI3NlIHV0aWxpemEgbGEgZnVuY2nDs24gaGVhZCgpIHBhcmEgcG9kZXIgY29ub2NlciBsb3MgcHJpbWVyb3MgNSBkYXRvcyBkZSBsYSBzZXJpZSAKYGBgCgoKQSBjb250aW51YWNpw7NuIHNlIG11ZXN0cmEgb3RyYSBmb3JtYSBkZSBzZWxlY2Npb25hciBsYSBjb2x1bW5hIHF1ZSBjb250aWVuZSBlbCBkYXRvIGRlbCBwcmVjaW8gYWp1c3RhZG8gZGUgVGVzbGEKCk5PVEEgSU1QT1JUQU5URTogbG8gcXVlIHNlIGluY2x1eWUgZW4gZWwgY2h1bmsgdGFtYmnDqW4gcHVlZGUgc2VyIGFwbGljYWRvIGVuIGNhc28gZGUgcXVlIHNlIHF1aWVyYW4gc2VsZWNjaW9uYXIgb3RyYXMgY29sdW1uYXMKCmBgYHtyfQoKYWRqVFNMQSA9IFRTTEFbLCA2XSAjbGEgY29sdW1uYSBkZSBsb3MgcHJlY2lvcyBhanVzdGFkb3MgZXMgbGEgNiwgcG9yIGVzbyBzZSBzZWxlY2Npb25hIGVzdGEgCgojTk9UQSBJTVBPUlRBTlRFOiBlbiB0b2RvcyBsb3Mgc2V0cyBkZSBkYXRvcyBzZSB0aWVuZW4gZG9zIGRpbWVuc2lvbmVzIFtmaWxhcyxjb2x1bW5hc10KCiNlcyBpbXBvcnRhbnRlIG5vdGEgcXVlIGVuIGVzdGUgY2FzbyBzb2xhbWVudGUgc2UgcXVpZXJlIGxhIGluZm9ybWFjacOzbiBkZSBsYXMgY29sdW1uYSBkZSBkYXRvcyBhanVzdGFkb3MsIHBlcm8gc2UgcXVpZXJlbiBtYW50ZW5lciB0b2RhcyBsYXMgZmlsYXMuIEVzIHBvciBsbyBhbnRlcmlvciBxdWUgc2UgbWFudGllbmUgZWwgZXNwYWNpbyBkZSBsYSBmaWxhIHZhY2lvLgoKZGltKFRTTEEpICNhIHRyYXbDqXMgZGUgbGEgZnVuY2nDs24gZGltIGVzIHBvc2libGUgY29ub2NlciBsYXMgZGltZWNpb25lcyBkZSB0b2RvcyBsb3Mgc2V0cyBkZSBkYXRvcy4gCgojY29uIGxhIGZ1bmNpw7NuIGRlIGRpbSBlcyBwb3NpYmxlIGNvbm9jZXIgcXVlIGVsIG7Dum1lcm8gdG90YWwgZGUgZmlsYXMgZGUgbGEgc2VyaWUgZGUgZGF0b3MgZXMgMTA0NiwgbWllbnRyYXMgcXVlIGVsIHRvdGFsIGRlIGNvbHVtbmFzIGVzIDYKYGBgCgpBZGVtw6FzIGRlIHBvZGVyIHNlbGVjY2lvbmFyIGxvcyBkdGFvcyBlc3BlY8OtZmljb3MgZGUgdW5hIGNvbHVtbmEsIHRhbWJpw6luIGVzIHBvc2libGUgc2VsZWNjaW9uYXIgZmlsYXMgZXNwZWPDrWZpY2FzIHV0aWxpemFuZG8gZWwgbWlzbW8gbcOpdG9kbywgZXMgZGVjaXIgZWwgZGUgW2ZpbGEsIGNvbHVtbmFdLiAKCkVuIGVsIGNodW5rIHF1ZSBzZSBtdWVzdHJhIGEgY29udGludWFjacOzbiBzZSBtdWVzdHJhIGNvbW8gc2UgcHVlZGVuIGVsZWdpciBsYXMgcHJpbWVyYXMgMTAgZmlsYXMgZGUgbGEgc2VyaWUgZGUgdGllbXBvCmBgYHtyfQpUU0xBZmlyc3RkYXlzID0gVFNMQVsxOjEwLF0gI2NvbW8gc29sbyBzZSBkZXNlYW4gY29ub2NlciBsYXMgZmlsYXMgMSBhIGxhIDEwIHNlIHV0aWxpemEgbGEgbm90YWNpw7NuIDE6MTAgLlBlcm8gY29uIHRvZGFzIGxhcyBjb2x1bW5hcywgZW50b25jZXMgc2UgZGVqYSBlbCBlc3BhY2lvIGRlIGNvbHVtbmFzIHZhY2nDsyAKClRTTEFmaXJzdGRheXMgI3NlIGxsYW1hIGEgbGEgZnVuY2nDs24gCmBgYAoKVGFtYmnDqW4gZXMgcG9zaWJsZSBzZWxlY2Npb25hciBjb2x1bW5hcyB5IGZpbGFzIGVzcGVjw61maWNhcy4gCgpFbiBlbCBjaHVuayBxdWUgc2UgbXVlc3RyYSBhIGNvbnRpbnVhY2nDs24gc2UgZWplbXBsaWZpY2EgY29tbyBzZSBwdWVkZSBzZWxlY2Npb25hciBjb2x1bW5hcyB5IGZpbGFzIGVzcGVjw61maWNhcyBhbCBzZWxlY2Npb25hciBsb3MgcHJpbWVyb3MgMTAgZMOtYXMgZGUgbG9zIHByZWNpb3MgYWp1c3RhZG9zIGRlIHRlc2xhCmBgYHtyfQpUU0xBX2FkanVzdGVkX2ZpcnN0X3ByaWNlcyA9IFRTTEFbMTo2LDZdICNzZSBzZWxlY2Npb25hIGRlIGxhcyBmaWxhcyAxIGEgMTAsIHB1ZXMgY29udGllbmVuIGxvcyBwcmltZXJvcyAxMCBkYXRvcy4gRGUgaWd1YWwgbWFuZXJhIHNlIHNlbGVjY2lvbmFuIGxhIGNvbHVtbmEgNiBxdWUgY29udGllbmUgbG9zIGRhdG9zIGRlIGxvcyBwcmVjaW9zIGFqdXN0YWRvcy4gCgpoZWFkKFRTTEFfYWRqdXN0ZWRfZmlyc3RfcHJpY2VzKQpgYGAKCgpTaSBzZSBkZXNlYSBzZWxlY2Npb25hciBtw6FzIGRlIHVuYSBjb2x1bW5hLCBlbnRvbmNlcyBzZSBwdWVkZSB1dGlsaXphciBlbCBjb250ZW5lZG9yIGMoKSBlIGluZGljYXIgcXVlIGNvbHVtbmFzIHNlIGRlc2VhbiBzZWxlY2Npb25hci4gCkEgY29udGludWFjacOzbiBzZSBwcmVzZW50YSB1biBlamVtcGxvIGVuIGVsIHF1ZSBzZSBkZXNlYW4gY29ub2NlciBsb3MgZGF0b3MgZGVsIG9wZW4geSBjbG9zZSAoY29sdW1uYXMgMSB5IDQpIGRlIGxvcyBwcmltZXJvIDEwIGTDrWFzIGRlIGxhIGJhc2UgZGUgZGF0b3MgKGZpbGEgMSBhIDEwKQpgYGB7cn0KVFNMQV9PcGVuX0Nsb3NlID0gVFNMQVsxOjEwLGMoMSw0KV0KaGVhZChUU0xBX09wZW5fQ2xvc2UpCmBgYAoKVW5hIG5vdGEgaW1wb3J0YW50ZSBlcyBxdWUgdGFtYmnDqW4gc2UgcHVlZGVuIHNlbGVjY2lvbmFyIGZpbGFzIHV0aWxpemFuZG8gZWwgw61uZGljZSBkZSBmZWNoYXMuIFBvciBlamVtcGxvIHNpIHNlIGRlc2VhbiBzZWxlY2Npb25hciB0b2RvcyBsb3MgcHJlY2lvcyBkZSBsYSBhY2Npw7NuIGRlIFRlc2xhIGRlbCBhw7FvIDIwMjEsIGVudG9uY2VzIHNlIHB1ZWRlIGhhY2VyIGxvcyBzaWd1aWVudGU6IApgYGB7cn0KVEVTTEFfMjAyMSA9IFRTTEFbIjIwMjEtMDEtMDEvMjAyMS0xMi0zMSIsIF0gI2NvbW8gbm8gc2UgbWVuY2lvbmFuIGFyZ3VtZW50b3MgZGUgY29sdW1uYXMsIGVudG9uY2VzIHNlIGluY2x1eWVuIHRvZGFzIGxhcyBjb2x1bW5hcwpoZWFkKFRFU0xBXzIwMjEpCmBgYApUYW1iacOpbiBlcyBwb3NpYmxlIGNvbWJpbmFyIGxhIHNlbGVjY2nDs24gZGUgY29sdW1uYXMgeSBsYSBzZWxlY2Npw7NuIGRlIGZpbGFzIGNvbiBlbCDDrW5kaWNlIGRlIGZlY2hhcwpgYGB7cn0KVEVTTEFfMjAyMV9hZGp1c3RlZCA9IFRTTEFbIjIwMjEtMDEtMDEvMjAyMS0xMi0zMSIsICJUU0xBLkFkanVzdGVkIl0KI05PVEEgSU1QT1JUQU5URTogZXMgcG9zaWJsZSBzZWxlY2Npb25hciBsYXMgY29sdW1uYXMgYWwgcG9uZXIgZWwgbsO6bWVybyBkZSBjb2x1bW5hLCBvIHN1IG5vbWJyZS4KCmhlYWQoVEVTTEFfMjAyMV9hZGp1c3RlZCkgI3NlIGxsYW1hbiBsb3MgcHJpbWVyb3MgNiBkYXRvcyBkZSBsYSBzZWxlY2Npw7NuIApgYGAKCkRBVEEgTUVSR0lORwoKU2UgcHVlZGUgdXRpbGl6YXIgbGEgZnVuY2nDs24gZGUgbWVyZ2UoKSBwYXJhIHVuaXIgYSBkb3MgbyBtw6FzIHNlcmllcyBkZSB0aWVtcG8sIHBhcmEgaW50ZWdyYXJsYXMgYSB1bmEgc29sYSBkYXRhIHNoZWV0CmBgYHtyfQpwcmljZXMgPSBtZXJnZShNU0ZULFRTTEEpCiMgVG8gZ2V0IG9ubHkgQWRqdXN0ZWQgcHJpY2VzOgphZGpwcmljZXMgPSBBZChwcmljZXMpCmBgYAoKVGFtYmnDqW4gc2UgcHVlZGUgdXRpbGl6YXIgdW5hIGZ1bmNpw7NuIGRlbnRybyBkZSBvdHJhIGZ1bmNpw7NuIHBhcmEgdGVuZXIgbWVqb3IgZ2VzdGnDs24gZGUgbGEgZGF0YS4gCgpQT3IgZWplbXBsbyBlcyBwb3NpYmxlIHJlYWxpemFyIHRvZG8gZWwgY8OzZGlnbyBkZWwgY2h1bmsgYW50ZXJpb3IsIGNvbiBzb2xhbWVudGUgdW5hIGzDrW5lYSBkZSBjw7NkaWdvOgpgYGB7cn0KYWRqcHJpY2VzIDwtIEFkKG1lcmdlKE1TRlQsVFNMQSkpCmBgYAoKQWhvcmEgcXVlIHNlIHRpZW5lIHVuYSBzb2xhIGRhdGFzaGVldCBjb24gbG9zIHByZWNpb3MgYWp1c3RhZG9zIGRlIGFtYmFzIGFjY2lvbmVzLCBlcyBwb3NpYmxlIGNhbWJpYXIgZWwgbm9tYnJlIGRlIGxhcyBjb2x1bW5hcy4gQ29tbyBzZSBtdWVzdHJhIGEgY29udGludWFjacOzbjogCmBgYHtyfQpuYW1lcyhhZGpwcmljZXMpPC1jKCJtc2Z0IiwidGVzbGEiKQpgYGAKCkFob3JhIGVzIHBvc2libGUgaGFjZXIgcmVmZXJlbmNpYXMgYSBsb3MgcHJlY2lvcyBhanVzdGFkb3MgdXRpbGl6YW5kbyBlc3RvcyBub21icmVzCmBgYHtyfQpoZWFkKGFkanByaWNlcyR0ZXNsYSkgI3NlIHBvbmUgYWRqcHJpY2VzJHRlc2xhIHBhcmEgaW5kaWNhciBxdWUgc2UgZGVzZWEgY29ub2NlciBsb3MgcHJpbWVyb3MgNiBkYXRvcyBkZWwgcHJlY2lvIGFqdXN0YWRvIGRlIHRlc2xhIAoKIyBzaSBzZSBxdWlzaWVyYSBjb25vY2VyIGxvcyBwcmltZXJvcyA2IGRhdG9zIGRlbCBwcmVjaW8gYWp1c3RhZG8gZGUgbWljcm9zZnQgc2UgdXRpbGl6YXLDrWEgbGEgc2lndWllbnRlIGZ1bmNpw7NuOiBoZWFkKGFkanByaWNlcyRtc2Z0KQpgYGAKClZJU1VBTElaQUNJw5NOIERFIExPUyBQUkVDSU9TCgpQYXJhIGVudGVuZGVyIGRlIG1lam9yIG1hbmVyYSB5IHZpc3VhbGl6YXIgY29tbyBoYW4gc2lkbyB2YWx1YWRhcyBsYXMgYWNjaW9uZXMgZGUgdGVzbGEgeSBkZSBtaWNyb3NvZnQgYSBsbyBsYXJnbyBkZWwgdGllbXBvLCBlcyBuZWNlc2FyaW8gZ3JhZmljYXIgbGEgZnVuY2nDs24gZGUgYWRqcHJpY2VzCmBgYHtyfQpwbG90KGFkanByaWNlcykKYGBgCgpDdWFuZG8gYW1iYXMgc2VyaWVzIHRpZW5lbiBkaWZlcmVudGVzIGVzY2FsYXMgZXMgbWVqb3IgZ3JhZmljYXJsYXMgZGUgbWFuZXJhIHNlcGFyYWRhCmBgYHtyfQpwbG90KGFkanByaWNlcyxtdWx0aS5wYW5lbD1UUlVFKQojY29uIGVsIGFyZ3VtZW50byBtdWx0aS5wYW5lbD10cnVlLCBlcyBwb3NpYmxlIGNvbXBhcmFyIGxhcyBkb3MgZ3LDoWZpY2FzIHBvciBzZXBhcmFkbwpgYGAKCkVzIGltcG9ydGFudGUgY29uc2lkZXJhciBxdWUgYWwgY29tcGFyYXIgZG9zIGFjY2lvbmVzIGxhIG1hZ25pdHVkIGRlbCBwcmVjaW8gYWp1c3RhZG8gbm8gcHVlZGVuIHV0aWxpemFyc2UgcGFyYSBkZWZpbmlyIGN1YWwgZGUgbGFzIGRvcyBhY2Npb25lcyB0aWVuZSB1biB2YWxvciBkZSBtZXJjYWRvIG3DoXMgYWx0by4gTG8gYW50ZXJpb3Igc2UgZGViZSBhIHF1ZSBlbCB2YWxvciBkZSBtZXJjYWRvIHNlIGRhIGEgdHJhdsOpcyBkZWwgbWVyY2FkbyBkZSBjYXBpdGFsaXphY2nDs24sIGVzIGRlY2lyIGEgdHJhdsOpcyBkZSBsYSBtdWx0aXBsaWNhY2nDs24gZGVsIHByZWNpbyBhanVzdGFkbyBwb3IgZWwgbsO6bWVybyBkZSBhY2Npb25lcy4gKHZhbG9yIGRlIG1lcmNhZG89cHJlY2lvIGFqdXN0YWRvIHggbsO6bWVybyBkZSBhY2Npb25lcykKClNlIHB1ZWRlIHV0aWxpemEgbGEgZnVuY2nDs24gY2hhcnRTZXJpZXMsIHBhcmEgcG9kZXIgdmlzdWFsaXphciB0YW50byBlbCBwcmVjaW8gYWp1c3RhZG8gZGUgbGEgYWNjacOzbiBjb21vIGVsIHRyYWRpbmcgdm9sdW1lCmBgYHtyfQpjaGFydFNlcmllcyhNU0ZULCB0aGVtZT0oIndoaXRlIikpCiN0aGVtZSB3aGl0ZSBzZSB1dGlsaXphIHBhcmEgcXVlIGVsIGZvbmRvIGRlIGxhIGdyw6FmaWNhIHNlYSBibGFuY28uIEVsIMO6bmljbyBvdHJvIGNvbG9yIHF1ZSBzZSBwdWVkZSBhcGxpY2FyIGxhIGZvbmRvIGRlIGVzdGEgZ3LDoWZpY2EgZXMgbmVncm8KYGBgCgpUYW1iacOpbiBlcyBwb3NpYmxlIGdyYWZpY2FyIHBlcmlvc29zIGVzcGVjw61maWNvcywgcG9yIGVqZW1wbG8gZXMgcG9zaWJsZSBncmFmaWNhciBlbCBjb21wb3J0YW1pZW50byBkZWwgcHJlY2lvIGFqdXN0YWRvIGRlIE1pY3Jvc29mdCBlbiAyMDIxIHNvbGFtZW50ZTogCmBgYHtyfQpjaGFydFNlcmllcyhNU0ZULCBzdWJzZXQgPSAnMjAyMS0wMS0wMS8yMDIxLTEyLTMxJykKI2NvbW8gc2UgaGFiw61hIG1lbmNpb25hZHAgYW50ZXJpb3JtZW50ZSBjaGFydFNlcmllcyBheXVkYSBhIGdyYWZpY2FyIHRhbnRvIGVsIHByZWNpbyBhanVzdGFkbyBkZSBsYSBhY2Npw7NuIGNvbW8gZWwgdm9sdW1lbgoKI3NlIGFncmVnYSBlbCBhcmd1bWVudG8gc3Vic2V0LCBwYXJhIGFzw60gcG9kZXIgaW5jbHVpciBlbCBwZXJpb2RvIGRlIHRpZW1wbyAobyDDrW5kaWNlIGRlIHRpZW1wbykgZXNwZWPDrWZpY28gcXVlIHNlIGRlc2VhIGdyYWZpY2FyIApgYGAKClJFVE9STk9TIEZJTkFOQ0lFUk9TIFBBUkEgU0VSSUVTIERFIFRJRU1QTyAKCkNvbW8gZXMgYmllbiBzYWJpZG8gZXhpc3RlbiBtw7psdGlwbGVzIG1hbmVyYXMgZGUgb2J0ZW5lciBlbCByZXRvcm5vIGRlIHVuYSBhY2Npw7NuLiBFbnRyZSBsb3MgcHJpbmNpcGFsZXMgbcOpdG9kb3Mgc2UgZW5jdWVudHJhIGVsIGRpdmlkaXIgZWwgcHJlY2lvIGFqdXN0YWRvIGRlIHVuYSBhY2Npw7NuIGVudHJlIGVsIHByZWNpbyBhanVzdGFkbyBkZWwgcGVyaW9kbyBhbnRlcmlvciwgeSBlc28gcmVzdGFybG8gZW50cmUgMS4gKGVqZW1wbG8gcGFyYSBzYWNhciBlbCByZXRvcm5vIGRlIGVuZXJvIGRlIDIwMjIgc2Vyw61hIG5lY2VzYXJpbyByZWFsaXphciBsbyBzaWd1aWVudGU6IChwcmVjaW8gYWp1c3RhZG8gZW5lcm8gMjAyMi9wcmVjaW8gYWp1c3RhZG8gZGljaWVtYnJlIDIwMjEpLTEpCgpFbCBtw6l0b2RvIG3DoXMgcmVjb21lbmRhYmxlIGVzIGVsIGRlIHNhY2FyIGxhIGRpZmVyZW5jaWEgZGVsIGxvZ2FyaXRtbyBkZWwgcHJlY2lvIG3DoXMgcmVjaWVudGUgeSBkZWwgcHJlY2lvIGRlbCBwZXJpb2RvIGFudGVyaW9yLiAoZWplbXBsbyBwYXJhIHNhY2FyIGVsIHJldG9ybm8gZGUgZW5lcm8gZGUgMjAyMiBzZXLDrWEgbmVjZXNhcmlvIHJlYWxpemFyIGxvIHNpZ3VpZW50ZTogbG9nKHByZWNpbyBhanVzdGFkbyBlbmVybyAyMDIyL3ByZWNpbyBhanVzdGFkbyBkaWNpZW1icmUgMjAyMSkpCgpSRVRPUk5PUyBTSU1QTEVTIEVOIFNFUklFUyBERSBUSUVNUE86CgpQYXJhIHBvZGVyIGNhbGN1bGFyIGVsIHJldG9ybm8gc2ltcGxlIGRlYmVyw6Egc2VyIG5lY2VzYXJpbyB1dGlsaXphciBlbCBwcmVjaW8gYWp1c3RhZG8gZGUgbGFzIGFjY2lvbmVzLiBQYXJhIGNhbGN1bGFyIGVsIHZhbG9yIHBhc2FkbyBkZWwgcHJlY2lvIGRlIHVuYSB2YXJpYWJsZSBkZSBzZXJpZXMgZGUgdGllbXBvIHNlIHB1ZWRlIHV0aWxpemFyIGxhIGZ1bmNpw7NuIGxhZy4gCmBgYHtyfQpSID0gYWRqcHJpY2VzIC8gc3RhdHM6OmxhZyhhZGpwcmljZXMsbj0xKSAtIDEgCmhlYWQoUikKYGBgCgpSRVRPUk5PUyBDT01QVUVTVE9TIENPTlRJTlVPUyAKClNlIHB1ZWRlbiBzYWNhciBsb3MgcmV0b3Jub3MgY29tcHVlc3RvcyBjb250aW51b3MgdXRpbGl6YW5kbyBsb3MgdmFsb3JlcyBkZXNjb250YWRzIGFsIHV0aWxpemFyIGxhcyBmdW5jaW9uZXMgZGUgZGlmZigpIHkgZGUgbG9nKCkuIAoKTk9UQTogbGEgZnVuY2nDs24gZGlmZiBjYWxjdWxhIGxhIGRpZmVyZW5jaWEgZW50cmUgZWwgdmFsb3IgZGUgdGllbXBvIGRlIGxhIHNlcmllIHkgc3UgdmFsb3IgcGFzYWRvCmBgYHtyfQpyID0gZGlmZihsb2coYWRqcHJpY2VzKSkKaGVhZChyKQpgYGAKCkVzIGltcG9ydGFudGUgcmVjb3JkYXIgcXVlIGxvcyBsb2cgcHJpY2VzIHNvbiByZXRvcm5vcyBjb21wdWVzdG9zIGRlIG1hbmVyYSBjb250aW51YSBlbiB1biBwZXJpb2RvLiAKClRhbWJpw6luIHNlIHB1ZWRlbiBncmFmaWNhciBsb3MgcmV0b3Jub3MgZGlhcmlvcyBxdWUgVGVzbGEgaGEgdGVuaWRvIGEgbG8gbGFyZ28gZGVsIHRpbWVwby4gCgpBIGNvbnRpbnVhY2nDs24gZXMgcG9zaWJsZSB2ZXIgcXVlIGV4aXN0ZSB1bmEgYWx0YSB2b2xhdGlsaWRhZCBlbiBsb3MgcmV0b3Jub3MgZGlhcmlvcyBkdXJhbnRlIGxvcyBtZXNlcyBxdWUgZHVyw7MgbGEgcGFuZGVtaWEuIEVzdGEgdm9sYXRpbGlkYWQgcHVlZGUgc2VyIGNhbGN1bGFkYSBhIGF0cmF2w6lzIGRlIGxhIGRlc3ZpYWNpw7NuIGVzdMOhbmRhcgpgYGB7cn0KcGxvdChSJHRlc2xhKQpgYGAKCkVTVEFEw41TVElDQVMgREVTQ1JJUFRJVkFTIENPTiBTRVJJRVMgREUgVElFTVBPCgpFbCBwYXF1ZXRlIFBlcmZvbWFuY2VBbmFseXRpY3MgY29udGllbmUgZGl2ZXJzYXMgZnVuY2lvbmVzIHBhcmEgcmVhbGl6YXIgZXN0YWTDrXN0aWNhcyBkZXNjcmlwdGl2YXMKYGBge3J9CmxpYnJhcnkoUGVyZm9ybWFuY2VBbmFseXRpY3MpCnRhYmxlMSA8LSB0YWJsZS5TdGF0cyhSKSAjbGEgZnVuY2nDs24gdGFibGUuU3RhdHMgc2lydmUgcGFyYSBjb25vY2VyIGxhcyBtZWRpZGFzIGVzdGFkw61zdGljYXMgZGVzY3JpcHRpdmFzIGLDoXNpY2FzIGRlIHVuYSBzZXJpZSBkZSB0aWVtcG8KCnRhYmxlMSAjc2UgbGxhbWEgbGEgZnVuY2nDs24gCmBgYAoKRW4gY2FzbyBkZSBxdWUgc2UgZGVzZWUgb2J0ZW5lciBlc3RhZMOtc3RpY2FzIGRlc2NyaXB0aXZhcyBlc3BlY8OtZmljYXMgc2UgcHVlZGVuIHV0aWxpemFyIGRpZmVyZW50ZXMgZnVuY2lvbmVzLCBjb21vIG1lYW4oKSB5IHNkCgpgYGB7cn0KbWVhbl90ZXNsYV9SID0gbWVhbihSJHRlc2xhLCBuYS5ybT1UUlVFKSAjbGEgZnVuY2nDs24gbWVhbigpIHNpcnZlIGNvbm9jZXIgZWwgcHJvbWVkaW8gCgptZWRpYW5fdGVzbGFfUiA9IG1lZGlhbihSJHRlc2xhLCBuYS5ybT1UUlVFKQojbGEgZnVuY2nDs24gbWVkaWFuKCkgc2lydmUgY29ub2NlciBsYSBtZWRpYW5hCgpzZF90ZXNsYV9SID0gc2QoUiR0ZXNsYSwgbmEucm09VFJVRSkKI2xhIGZ1bmNpw7NuIHNkKCkgc2lydmUgcGFyYSBjb25vY2VyIGxhIGRlc3ZpYWNpw7NuIGVzdGFuZGFyIAoKI05PVEEgSU1QT1JUQU5URSBuYS5ybT1UUlVFIGVzIHVuYSBvcGNpw7NuIHF1ZSBheXVkYSBhIHF1ZSBzZSBlbGltaW5lbiBsb3MgdmFsb3JlcyBOQSBhbnRlcyBkZSByZWFsaXphciBsb3MgY2FsY3Vsb3MgCgpjYXQoIlRlc2xhIGRhaWx5IG1lYW4gcmV0dXJuIGlzICIsbWVhbl90ZXNsYV9SLCAiXG4iKSAKCiNOT1RBIElNUE9SVEFOVEU6IGxhIGZ1bmNpw7NuIGNhdCAoc2lnbGFzIHBhcmEgY29uY2VudHJhdGUgYW5kIHByaW1lKSBkYSBzYWxpZGEgYSBsb3MgZGF0b3MgZW4gZWwgZm9ybWF0byBkZXNlYWRvCmBgYApBIHRyYXbDqXMgZGUgbGEgbMOtbmVhIGRlIGPDs2RpZ28gMjM0IGVzIHBvc2libGUgY29ub2NlciBxdWUgbGEgbWVkaWEgZGVsIHJldG9ybm8gZGlhcmlvIGRlIHRlc2xhIGVzIDAuMDAzMQoKYGBge3J9CmNhdCgiVGVzbGEgZGFpbHkgbWVkaWFuIHJldHVybiBpcyAiLG1lZGlhbl90ZXNsYV9SLCAiXG4iKQpgYGAKQSB0cmF2w6lzIGRlbCBjw7NkaWdvIGVuIGVsIGNodW5rIGFudGVyaW9yIGVzIHBvc2libGUgY29ub2NlciBxdWUgbGEgbWVkaWFuYSBkZWwgcmV0b3JubyBkaWFyaW8gZGUgdGVzbGEgZXMgMC4wMDIyNgoKCmBgYHtyfQpjYXQoIlRlc2xhIGRhaWx5IHZvbGF0aWxpdHkgaXMgIiwgc2RfdGVzbGFfUikKYGBgCkEgdHJhdsOpcyBkZWwgY8OzZGlnbyBlbiBlbCBjaHVuayBhbnRlcmlvciBlcyBwb3NpYmxlIGNvbm9jZXIgcXVlIGxhIHZvbGF0aWxpZGFkIChlcyBkZWNpciBsYSBkZXN2aWFjacOzbiBlc3RhbmRhcikgZGVsIHJldG9ybm8gZGlhcmlvIGRlIHRlc2xhIGVzIDAuMDQyNTMKCk5PVEEgSU1QT1JUQU5URTogY3VhbmRvIGV4aXN0ZW4gdmFsb3JlcyBkZSBOQSBlbiBsYXMgY29sdW1uYXMgZWwgcHJvZ3JhbWEgbm8gcHVlZGUgY2FsY3VsYXIgbGFzIGVzdGFkw61zdGljYXMgZGVzY3JpcHRpdmFzLCBhIG1lbm9zIGRlIHF1ZSBzZSB1dGlsaWPDqSBsYSBvcGNpw7NuIG5hLnJtPVRSVUUuCgpDdWFuZG8gbGEgbWVkaWEgeSBsYSBtZWRpYW5hIHNvbiBtdXkgZGlmZXJlbnRlcywgcG9yIGxvIGdlbmVyYWwgc2UgdG9tYSBjb21vIHNlw7FhbCBkZSBxdWUgbm8gaGF5IG5vcm1hbGlkYWQgZW4gbGEgZGlzdHJpYnVjacOzbiBkZSBsYSB2YXJpYWJsZS4gRW4gZWwgZWplbXBsbyBkZSB0ZXNsYSBzZSBwdWVkZSB2ZXIgcXVlIGxhIG1lZGlhbmEgZXMgbXVjaG8gbWVub3IgcXVlIGxhIG1lZGlvIChtZWRpYT0wLjE0JSB5IG1lZGlhbmEgMC4zMSUpLiBMYSBtZWRpYW5hIGVzIG1lam9yIG3DqXRyaWNhIHBhcmEgbWVkaXIgbG9zIHZhbG9yZXMgY2VudHJhbGVzIGRlIHRlbmRlbmNpYSBkZSByZXRvcm5vcyBmaW5hbmNpZXJvcy4gCgpOT1RBIElNUE9SVEFOVEU6IHNpIGxhIEt1cnRvc2lzIGRlIGxhIHZhcmlhYmxlIGVzIG1heW9yIGEgMywgZW50b25jZXMgbGEgdmFyaWFibGUgdGllbmUgdmFsb3JlcyBtw6FzIGV4dHJlbW9zIHF1ZSB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwuIAoKRW4gZWwgZWplbXBsbyBkZSBUZXNsYSBzZSBwdWVkZSB2ZXIgcXVlIHRhbnRvIGxhIG1lZGlhIGNvbW8gbGEgbWVkaWFuYSB0aWVuZW4gdmFsb3JlcyBuYXlvcmVzIGEgdHJlcy4gCgpOT1RBIElNUE9SVEFOVEU6IHBvciBsbyBnZW5lcmFsIGxvcyByZXRvcm5vcyBmaW5hbmNpZXJvcyB0aWVuZW4gdmFsb3JlcyBtw6FzIGV4dHJlbW9zIGEgY29tcGFyYWNpw7NuIGRlIHZhcmlhYmxlcyBxdWUgdGllbmVuIGRpc3RyaWJ1Y2nDs24gbm9ybWFsLCBwb3IgbG8gcXVlIGxhIGRlc3ZpYWNpw7NuIGVzdGFuZGFyIG5vIGVzIHN1ZmljaWVudGUgcGFyYSBlbnRlbmRlciBkZSBtZWpvciBtYW5lcmEgbGEgZGlzcGVyc2nDs24gZGUgbG9zIHJldG9ybm9zLiAKCk5PVEEgSU1QT1JUQU5URTogbG9zIHF1YXJ0aWxlcyBkYW4gdW5hIG1lam9yIHBlcmNlcGNpw7NuIGRlIGxhIHZvbGF0aWxpZGFkIGRlIGxvcyByZXRvcm5vcyBmaW5hbmNpZXJvcy4gUG9yIGxvIHF1ZSBzZSByZWNvbWllbmRhIHV0aWxpemFyIGVsIGdyw6FmaWNvIGRlIGNhamEuCmBgYHtyfQpjaGFydC5Cb3hwbG90KFIpCgojbG9zIGPDrXJjdWxvcyByb2pvcyBxdWUgc2UgbXVlc3RyYW4gZW4gZWwgZ3LDoWZpY28gc29uIGxhIG1lZGlhLCBsYSBsw61tZWEgZW4gbWVkaW8gZXMgbGEgbWVkaWFuYS4gCiNsYXMgY2FqYXMgaW5jbHV5ZW4gNTAlIGRlIGRhdGEgZGVsIFExIG8gUTEgKHByZXNlbnTDrWwgMjUpIGFsIFEzLiAKI2xhcyBsw61uZWFzIHZlcnRpY2FsZXMgbGltaXRhbiBsb3MgdmFsb3JlcyBubyBleHRyZW1vcy4gCiNMb3MgcHVudG9zIHNvbiBsb3MgdmFsb3JlcyBleHRyZW1vcyBkZSBsYSBkaXN0cmlidWNpw7NuCmBgYApBaG9yYSBxdWUgc2UgZXN0YSB1dGxpemFuZG8gZWwgZ3LDoWZpY28gZGUgY2FqYSBlcyBwb3NpYmxlIGVudGVuZGVyIGRlIG1lbm9yIG1hbmVyYSBxdWUgTWljcm9zb2Z0IHRpZW5lIG3DoXMgdm9sYXRpbGlkYWQgcXVlIFRlc2xhICjDs3NlYSBxdWUgZXMgbcOhcyByaWVzZ29zbyBxdWUgdGVzbGEpLgoKClZJU1VBTElaSU5HIEhPTERJTkcgUkVUVVJOTyBPVkVSIFRJTUUgCgpTZSBwdWVkZSB1dGlsaXphciBsYSBmdW5jacOzbiBkZSBjaGFydHMuUGVyZm9ybWFuY2VTdW1tYXJ5KCkgcGFyYSB2aXN1YWxpemFyIGN1YW50byBzZSBnZW5lcmFyw61hIHNpIHNlIGludmlydGllcmEgJDEgeSBzZSBtYW50dXZpZXJhIHBvciB1biBwZXJpb2RvIGRlIHRpZW1wby4gCmBgYHtyfQpjaGFydHMuUGVyZm9ybWFuY2VTdW1tYXJ5KFIkdGVzbGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgIG1haW4gPSAiUGVyZm9ybWFuY2Ugb2YgJDEuMDAgVGVzbGEiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdlYWx0aC5pbmRleCA9IFRSVUUpCmBgYAogVGFtYmnDqW4gZXMgcG9zaWJsZSBjYWxjdWxhciBlbCBleGFjdCBob2xkaW5nIHBlcmlvZCByZXR1cm4gYWwgb2J0ZW5lciBlbCBwb3JjZW50YWplIGRlIGNyZWNpbWllbnRvIGRlIGxhIHNlcmllIGEgdHJhdsOpcyBkZWwgcHJlY2lvIGFqdXN0YWRvCmBgYHtyfQpocHJfdGVzbGEgPSBhcy5udW1lcmljKGFkanByaWNlcyR0ZXNsYVtucm93KGFkanByaWNlcyldKSAvIGFzLm51bWVyaWMoYWRqcHJpY2VzJHRlc2xhWzFdKSAtIDEKaHByX3Rlc2xhCmBgYApBbCBleHByZXNhciBlbCBkYXRvIGFycm9qYWRvIHBvciBlbCBwcm9ncmFtYSBlbiBwb3JjZW50YWplIHNlIHRpZW5lIDkwNC4yNzI1JSBkZSByZXRvcm5vIGRlIGhvbGRpbmcgcGVyaW9kLiAKCkFsIGludGVycHJldGFyIGxvIGFudGVyaW9yIHRlbmVtb3MgcXVlIHNpIHNlIGludmlydGllcmEgJDEgZW4gVGVzbGEgYWwgaW5pY2lvIGRlbCBwZXJpb2RvLCBlbnRvbmNlcyBzZSB0ZW5kcsOtYSAkMTAuMDQyNzMgYWwgZmluYWwgZGVsIHBlcmlvZG8uIAoKRXN0ZSBtaXNtbyBlamVyY2ljaW8gcHVlZGUgc2VyIHJlYWxpemFkbyBwYXJhIE1pY3Jvc29mdDoKYGBge3J9CmNoYXJ0cy5QZXJmb3JtYW5jZVN1bW1hcnkoUiRtc2Z0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICBtYWluID0gIlBlcmZvcm1hbmNlIG9mICQxLjAwIGluIE1pY3Jvc29mdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2VhbHRoLmluZGV4ID0gVFJVRSkKCmhwcl9tc2Z0ID0gYXMubnVtZXJpYyhhZGpwcmljZXMkbXNmdFtucm93KGFkanByaWNlcyldKSAvIGFzLm51bWVyaWMoYWRqcHJpY2VzJG1zZnRbMV0pIC0gMQpocHJfbXNmdAoKI0FsIGV4cHJlc2FyIGVsIGRhdG8gYXJyb2phZG8gcG9yIGVsIHByb2dyYW1hIGVuIHBvcmNlbnRhamUgc2UgdGllbmUgMTU4Ljg3NzMlIGRlIHJldG9ybm8gZGUgaG9sZGluZyBwZXJpb2QuIAoKI0FsIGludGVycHJldGFyIGxvIGFudGVyaW9yIHRlbmVtb3MgcXVlIHNpIHNlIGludmlydGllcmEgJDEgZW4gTWljcm9zb2Z0IGFsIGluaWNpbyBkZWwgcGVyaW9kbywgZW50b25jZXMgc2UgdGVuZHLDrWEgJDEwLjA0MjczIGFsIGZpbmFsIGRlbCBwZXJpb2RvLiAKYGBgCgpEQVRBIFNUUlVDVFVSRVMgCgpFeGlzdGVuIDMgZXN0cnVjdHVyYXMgZGUgZGF0YSBzZXQ6IAotU2VyaWVzIGRlIHRpZW1wbyAodmFyaW9zIHBlcmlvZG9zIGRlIHRpZW1wbyB5IHNlIHB1ZWRlbiB0ZW5lciB2YXJpb3Mgc3VqZXRvcyBxdWUgc2UgbXVlc3RyYW4gZW4gY29sdW1uYXMpCi1Dcm9zcyBzZWN0aW9uYWwgKG11Y2hvcyBzdWpldG9zLCBwZXJvIHNvbGFtZW50ZSAxIHBlcmlvZG8gZGUgdGllbXBvKSAKLVBhbmVsIGRhdGEgc3RydWN0dXJlICh2YXJpb3Mgc3VqZXRvcyB5IG3DoXMgZGUgdW4gcGVyaW9kbyBkZSB0aWVtcG8gcGFyYSBjYWRhIHN1amV0bykKCkRBVEEgTUFOQUdNRU5UIEZPUiBQQU5FTCBEQVRBCgpBbnRlcyBkZSBkaXNlw7FhciB1biBtb2RlbG8gZWNvbm9tw6l0cmljbyBlcyBuZWNlc2FyaW8gdGVuZXIgdW5hIGdlc3Rpw7NuIHNpbXBsZSB5IHNvZmlzdGljYWRhIGRlIGxhIGRhdGEgcXVlIHNlIHZhIGEgbWFuZWphci4gCgpFbiBlbCBlamVtcGxvIHNlIG1vc3RyYXLDoSBjb21vIGNvbWJpbmFyIGRvcyBkYXRhc2V0cyAodW5hIHNlcmllIGRlIHRpZW1wbyBjb24gbGEgaW5mb3JtYWNpw7NuIGhpc3TDs3JpY2EgZGVsIElQeUMsIHkgdW4gZGF0YSBzZXIgY29uIGxhIGluZm9ybWFjacOzbiBkZSBjdWFydG9zIGRlIGHDsW8gZGUgZGlmZXJlbnRlcyBlbXByZXNhcyBtZXhpY2FuYXMpCgpOT1RBIElNUE9SVEFOVEU6IHNvbGFtZW50ZSBzZSBwdWVkZW4gZnVzaW9uYXIgZGF0YXNldHMgcXVlIHRlbmdhbiBsYSBtaXNtYSBncmFudWxhcmlkYWQsIGVzIGRlY2lyIGRhdGEgc2V0cyBxdWUgY29tcGFydGFuIGxhIG1pc21hIHBlcmlvZGljaWRhZC4gTG8gcXVlIHF1aWVyZSBkZWNpciBxdWUgc2kgc2UgdGllbmUgZG9zIHNlcmllcyBkZSB0aWVtcG8sIHVuYSBjb24gZGF0b3MgYW51YWxlcyB5IGxhIG90cmEgY29uIGRhdG9zIG1lbnN1YWxlcywgZW50b25jZXMgbm8gc2UgcG9kcsOhbiBmdXNpb25hci4gCgpFbiBlbCBjaHVuayBwb3N0ZXJpb3Igc2UgZGVzY2FyZ2Fyw6EgbGEgaW5mb3JtYWNpw7NuIGRlbCBzaXRpbyBlY29ub21hdGljYSwgeSBjb250aWVuZSBsYSBpbmZvcm1hY2nDs24gZGUgY3VhcnRvcyBkZSBhw7FvIGRlIHJtcyBtZXhpY2FuYXMKYGBge3J9CiMgcHJpbWVybyBlcyBpbXBvcnRhbnRlIGRlc2NhcmdhciBlbCBwYXF1ZXRlIHJlYWR4bCBxdWUgcGVybWl0ZSBkZXNjYXJnYXIgZG9jdW1lbnRvcyBkZSBleGNlbCBkZSBzaXRpb3Mgd2ViCmxpYnJhcnkocmVhZHhsKQpkb3dubG9hZC5maWxlKCJodHRwOi8vd3d3LmFwcmFkaWUuY29tL2RhdG9zL2RhdGFteDIwMjBxNC54bHN4IiwKICAgICAgICAgICAgICAiZmlybXNwYW5lbGRhdGEueGxzeCIsIG1vZGU9IndiIikKIyBzZSB1dGlsaXphIGxhIGZ1bmNpw7NuIGRvd25sb2FkIGZpbGUgcGFyYSBkZXNjYXJnYXIgZWwgYXJjaGl2bywgeSBsdWVnbyBzZSBwb25lIGNvbW8gYXJndW1lbnRvIGVsIHNpdGlvIGRlIGRvbmRlIHNlIHZhIGEgZGVzY2FyZ2FyIGVsIGFyY2hpdm8KIyBlbCDDumx0aW1vIGFyZ3VtZW50byBpbmRpY2EgcXVlIHNlIHZhIGEgZGVzY2FyZ2FyIGVsIGV4Y2VsIGNvbW8gZG9jdW1lbnRvIGxvY2FsIAoKcGFuZWxkYXRhc2V0IDwtIHJlYWRfZXhjZWwoImZpcm1zcGFuZWxkYXRhLnhsc3giKQpgYGAKClNlIG5lY2VzaXRhIGZ1c2lvbmFyIGVsIHJldG9ybm8gbWVuc3VhbCBkZWwgbWVyY2FkbyBjb24gZWwgZGF0YSBzZXQgYW50ZXJpb3IgcG9yIGxvIHF1ZSBzZSBuZWNlc2l0YSByZWFsaXphciBsb3Mgc2lndWVudGUgCjEuIERlc2NhcmdhciBlbCBtZXJjYWRvIG1lbnN1YWwgZGUgeWFob28gYSB0cmF2w6lzIGRlIGxhIGZ1bmNpw7NuIGdldFN5bWJvbHMoKQpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKZ2V0U3ltYm9scygiXk1YWCIsIGZyb209IjIwMDAtMDEtMDEiLCB0bz0gIjIwMTktMTItMzEiLAogICAgICAgICAgICBwZXJpb2RpY2l0eT0ibW9udGhseSIsIHNyYz0ieWFob28iKQpgYGAKMi4gdHJhbnNmb3JtYXIgKGNvbGxhcHNlKSBsYSBkYXRhIHBhcmEgcXVlIHNlYSBjdWF0cmltZXN0cmFsIApgYGB7cn0KUU1YWCA8LSB0by5xdWFydGVybHkoTVhYLGluZGV4QXQ9J3N0YXJ0b2YnKQpoZWFkKFFNWFgpICNzZSB1dGlsaXrDsyBoZWFkIHBhcmEgcG9kZXIgdmVyIGVsIGNvbnRlbmlkbyBkZSBsYSBkYXRhCmBgYApDb21vIHNlIHB1ZWRlIHZlciBlbiBsYSBkYXRhIGFudGVyaW9yIHNlIG11ZXN0cmFuIGxhcyBjb2x1bW5hcyBkZSBvcGVuLCBoaWdoLCBsb3csIGNvbHNlLCB2b2x1bWVuIHkgYWRqdXN0ZWQgcHJpY2UuIFNpbiBlbWJhcmdvIHNvbGFtZW50ZSBzZSBuZWNlc2l0YXLDoSBlbCBwcmVjaW8gYWp1c3RhZG8gcGFyYSBjYWxjdWxhciBlbCByZXRvcm5vLCBwb3IgbG8gcXVlIHNvbGFtZW50ZSBzZSBzZWxlY2Npb25hIGxhIGNvbHVtbmEgZGUgQ2xvc2UKYGBge3J9ClFNWFggPSBRTVhYJE1YWC5BZGp1c3RlZAojc2UgbGUgY2FtYmlvIGVsIG5vbWJyZSBhIGxhIGNvbHVtbmEgCmNvbG5hbWVzKFFNWFgpIDwtICJNWFhpbmRleCIKYGBgCgpBaG9yYSBlcyBwb3NpYmxlIGNhbGN1bGFyIGVsIHJldG9ybm8gZGVsIG1lcmNhZG8KYGBge3J9ClFNWFgkTVhYcmV0dXJucyA8LSBkaWZmKGxvZyhRTVhYKSkgI3JlY29yZGFuZG8gcXVlIGxhIGZ1bmNpw7NuIGRlIGRpZmYoKSBheXVkYSBhIHNhY2FyIGxhIGRpZmVyZW5jaWEgZW4gbG9zIGRhdG9zIHkgbG9nKCkgYXl1ZGEgYSBzYWNhciBsb3MgbG9nYXJpdG1vcy4gCmBgYAoKQ2FzaSB0b2RvIGVzdGEgbGlzdG8gcGFyYSBwb2RlciBmdXNpb25hciBlc3RhIGRhdGEgY3VhdHJpbWVzdHJhbCBjb24gZWwgcGFuZWwgZGF0YXNldCwgc2luIGVtYmFyZ28gYW50ZXMgZXMgbmVjZXNhcmlvIHRlbmVyIGFtYm9zIGRhdGEgc2V0cyBlbiB1bmEgbWlzbWEgY29sdW1uYS4gRW4gZXN0ZSBjYXNvIGxhIGNvbHVtbmEgZW4gY29tw7puIGVzIGxhIGRlIHVuIGN1YXJ0by4gCgpMYSBmdW5jacOzbiBsbGFtYWRhIFFNWFggdGllbmUgZWwgw61uZGljZSBkZSBjdWFydG8sIHBlcm8gbm8gY29tbyBjb2x1bW5hLCBwb3IgbG8gcXVlIGEgY29udGludWFjacOzbiBzZSBjcmVhcsOhIHVuIGRhdGEgZnJhbWUgY29uIGxhIGNvbHVtbmEgZGUgY3VhcnRvIGlndWFsIGFsIMOtbmRpY2UKYGBge3J9ClFNWFguZGY8LWRhdGEuZnJhbWUocXVhcnRlcj1pbmRleChRTVhYKSxjb3JlZGF0YShRTVhYKSkgI3NlIGNyZWEgdW4gZGF0YWZyYW1lIGNvbiB1bmEgY29sdW1uYSBkZSBjdWFydG8KI2VuIGVzdGUgY2h1bmsgc2UgY29waWEgbGEgaW5mb3JhY2nDs24gZGVsIMOtbmRpY2UgUU1YWCB5IGRlc3B1w6lzIHNlIHV0aWxpemEgY29yZWRhdGEoKSAKI2NvcmVkYXRhKCkgZXMgdW5hIGZ1bmNpw7NuIHF1ZSBjb3BpYSBsYSBpbmZvcm1hY2nDs24gZGUgdW4gb2JqZXRvIHBlcmlvIHNpbiBjb3BpYXIgZWwgZm9ybWF0byAKYGBgCgpMYSBjb2x1bW5hIGVuIGNvbcO6biBkZWJlIGRlIHNlciBkZWwgbWlzbW8gdGlwbyBwYXJhIGFzZWd1cmFyIHF1ZSBsYSBjb2x1bW5hIGRlIGN1YXJ0byBkZWwgZGF0YXNldCBzZWEgRGF0YSB0eXBlOiAKYGBge3J9CnBhbmVsZGF0YXNldCRxdWFydGVyPC1hcy5EYXRlKHBhbmVsZGF0YXNldCRxdWFydGVyKQpgYGAKCjMtIGZ1c2lvbmFyIGxhIG51ZXZhIHNlcmllIGRlIHRpZW1wbyBjb24gZWwgcGFuZWwgZGF0YSAKYGBge3J9CnBhbmVsZGF0YXNldDwtbWVyZ2UocGFuZWxkYXRhc2V0LFFNWFguZGYsYnk9InF1YXJ0ZXIiKQojZGVzcHXDqXMgZGUgdXRpbGl6YXIgbGEgZnVuY2nDs24gZGUgbWVyZ3VlIGFob3JhIHNlIHRpZW5lIHVuIGRhdGFzZXQgcGFyYSBsYXMgZW1wcmVzYXMgbWV4aWNhbmFzLCBsYSBpbmZvcm1hY2nDs24gaGlzdMOzcmljYSBkZWwgSVB5QyB5IGxvcyByZXRvcm5vcyBkZWwgSVB5Qy4gCmBgYAoKU0VUVElORyBBIFBBTkVMIERBVEEgU1RSVUNUVVJFCgpFcyBpbXBvcnRhbnRlIHF1ZSBlbCBkYXRhIHNldCAow7NzZWEgZWwgcGFuZWxkYXRhc2V0KSB0ZW5nYSBsYSBlc3RydWN0dXJhIGRlIHVuIGN1YXJ0byBhbnVhbCAocGFyYSBsYXMgZW1wcmVzYXMgbWV4aWNhbmFzIGRlIGxhIGRhdGEpLgoKUGFyYSBsbyBhbnRlcmlvciBlcyBuZWNlc2FyaW8gZGVmaW5pciBhbCBkYXRhc2V0IGNvbW8gdW4gcGFuZWwgZGUgZGF0YS4gRXN0byBzZSBwdWVkZSBsb2dyYXIgdXRpbGl6YXIgbGEgZnVuY2nDs24gZGUgcGRhdGEuZnJhbWUoKS4gCgpOT1RBIElNUE9SVEFOVEU6IHBhcmEgcG9kZXIgdXRpbGl6YXIgZXN0YSBmdW5jacOzbiBlcyBuZWNlc2FyaW8gaW5zdGFsYXIgZWwgcGFxdWV0ZSBwbG0KCgpFbiBlbCBjaHVuayBwb3N0ZXJpb3Igc2UgaW5kaWNhIHF1ZSBlbCBpbmRpY2UgZGVsIGRhdGEgcGFuZWwgdmEgYSB0ZW5lciBlbCBhIGxhcyBlbXByZXNhcyBjb21vIHN1amV0byB5IGxhIGNvbHVtbmEgY29uIGxvcyBjdWFydG9zIGNvbW8gZWwgdGllbXBvCmBgYHtyfQpsaWJyYXJ5KHBsbSkKcGFuZWxkYXRhc2V0IDwtIHBkYXRhLmZyYW1lKHBhbmVsZGF0YXNldCwgaW5kZXg9IGMoImZpcm1jb2RlIiwicXVhcnRlciIpKQpgYGAKCkRBVEEgQ0FMQ1VMQVRJT05TIFdJVEggUEFORUwgREFUQQoKUGFyYSBwb2RlciByZWFsaXphciBzZWxlY2Npb25lcyB5IGNhbGN1bG9zIGVuIHBhbmVsIGRhdGEgc2V0cyBlcyBuZWNlc2FyaW8gdXRpbGl6YXIgZWwgcGFxdWV0ZSBkcGx5ci4KCk5PVEEgSU1QT1JUQU5URTogZHBseXIgZXMgdW4gcGFxdWV0ZSBxdWUgdGllbmUgaGVycmFtaWVudGFzIG11eSBwb2Rlcm9zYXMgcXVlIHB1ZWRlbiBmYWNpbGl0YXIgbGEgZ2VzdGnDs24gZGUgcGFuZWwgZGF0YSBzZXRzLgpgYGB7cn0KbGlicmFyeShkcGx5cikKYGBgCgpFcyBpbXBvcnRhbnRlIG1lbmNpb25hciBxdWUgZWwgZGF0YSBzZXQgcXVlIHNlIGhhIGVzdGFkbyB1dGlsaXphbmRvIHRpZW5lIGluZm9ybWFjacOzbiBoaXN0w7NyaWNhIHF1YXRyaW1lc3RyYWwgZGUgZW1wcmVzYXMgcXVlIGVzdGFuIGFjdGl2YXMgeSBubyBhY3RpdmFzIGVuIGxhIEJvbHNhIE1leGljYW5hIGRlIFZhbG9yZXMuIFBhcmEgZXN0ZSBlamVyY2ljaW8gc29sYW1lbnRlIHNlIHZhbiBhIG5lY2VzaXRhciBsYXMgZW1wcmVzYXMgcXVlIHNpIGVzdMOhbiBhY3RpdmFzIGVuIGxhIEJNVi4gCgpFbiBlbCBjaHVuayBwb3N0ZXJpb3Igc2UgbXVlc3RyYSBjb21vIG1hbnRlbmVyIHNvbGFtZW50ZSBsYXMgZW1wcmVzYXMgcXVlIHNvbiBuZWNlc2FyaWFzIHBhcmEgZWwgZWplcmNpY2lvLgoKYGBge3J9CmFjdGl2ZWRhdGE8LXBhbmVsZGF0YXNldFtwYW5lbGRhdGFzZXQkc3RhdHVzPT0iYWN0aXZlIixdCmFjdGl2ZWRhdGE8LWFjdGl2ZWRhdGFbYWN0aXZlZGF0YSR5ZWFyPj0yMDEwLF0KCiNjb21vIHNlIHB1ZWRlIG9ic2VydmFyIHNlIHNlbGVjY2lvbmFuIGxhcyBmaWxhcyBxdWUgc2UgZGVzZWFuIGFsIGluY2x1aXIgYXJndW1lbnRvcyBjb21vIHF1ZSBlbiBsYSBjb2x1bW5hIGRlIHN0YXR1cyB0ZW5nYW4gZWwgdmFsb3IgImFjdGl2ZSIuIApgYGAKCkFob3JhIHF1ZSBzZSBzZWxlY2Npb25hcm9uIGxhcyBlbXByZXNhcyBxdWUgZXN0YW4gYWN0aXZhcyBlbiBsYSBCTVYsIGRlIGFjdWVyZG8gYSBsYSBiYXNlIGRlIGRhdG9zLCBlcyBpbXBvcnRhdGUgdGFtYmnDqW4gc2VsZWNjaW9uYXIgY2llcnRhcyBjb2x1bW5hcyBkZSBlc3RlIGRhdGEgc2V0IHF1ZSBwdWVkYW4gc2VyIGRlIHV0aWxpZGFkIHBhcmEgaGFjZXIgY2llcnRhcyBvcGVyYWNpb25lcyBmaW5hbmNpZXJhcy4KClBhcmEgcG9kZXIgcmVhbGl6YXIgbG8gYW50ZXJpb3Igc2UgdXRpbGl6YXLDoSBsYSBvcGVyYWNpw7NuICIlPiUiIChxdWUgcHVlZGUgdXRpbGl6YXJzZSBkZXNwdcOpcyBkZSBpbnN0YWxhciBlbCBwYXF1ZXRlIGRwbHlyKQpgYGB7cn0KYWN0aXZlZGF0YTwtYWN0aXZlZGF0YSAlPiUKICAgIHNlbGVjdChmaXJtLHF1YXJ0ZXIseWVhcixyZXZlbnVlLGNvZ3MsZWJpdCx0b3RhbGFzc2V0cywKICAgICAgICAgICBhZGp1c3RlZHN0b2NrcHJpY2UsIG5haWNzMSkKCiNzZSBzZWxlY2Npb25hbiBsYXMgY29sdW1uYXMgZGVzZWFkYXMgZGVzcHXDqXMgZGUgdXRpbGl6YXIgbGEgb3BlcmFjacOzbiAlPiUKYGBgCgpDQUxDVUxBVElORyBGSU5BTkNJQUwgUkVUVVJOUyBBTkQgUkFUSU9TIFdJVEggUEFORUwgREFUQSAKClBhcmEgcG9kZXIgY2FsY3VsYXIgbG9zIHJldG9ybm9zIGRlbCBwYW5lbCBkYXRhIHNldCBzZSB1dGlsaXphIGVsIG1pc21vIG3DqXRvZG8gcXVlIHNlIHRvbW8gZW4gY3VlbnRhIHBhcmEgY2FsY3VsYXIgbG9zIHJldG9ybm9zIGRlIHRlc2xhIHkgZGUgbWljcm9zb2Z0IChlcyBkZWNpciBzYWNhciBsYSBkaWZlcmVuY2lhIGRlIGxvcyBsb2dhcml0bW9zIGRlIGxvcyBkYXRvcykKCmBgYHtyfQphY3RpdmVkYXRhJHIgPSBkaWZmKGxvZyhhY3RpdmVkYXRhJGFkanVzdGVkc3RvY2twcmljZSkpCgpgYGAKCkFsIHJlYWxpemFyIGxhIGFjY2nDs24gYW50ZXJpb3Igc2UgYWdyZWfDsyB1bmEgY29sdW1uYSBhbCBlbiBlbCBwYW5lbCBkYXRhLiBFbiBjYXNvIGRlIHF1ZSBleGlzdGllcmEgdW4gY2FiaW8gZW4gYWxndW5hIGRlIGxhcyBlbXByZXNhcyBubyBzZXLDrWEgbmVjZXNhcmlvIGNhbGN1bGNhciBsb3MgcmVuZGltaWVudG9zIGRlIG51ZXZvLCBzb2xhbWVudGUgaGFicsOtYSBkZSByZXZpc2FyIHNpIGxvcyB2YWxvcmVzIGRlIGxvcyBwcmltZXJvcyBjdWFydG9zIGRlIGNhZGEgZW1wcmVzYSB0aWVuZW4gZWwgdmFsb3IgZGUgTkEuCkEgY29udGludWFjacOzbiBzZSB2YSBhIGNhbGN1bGFyIGVsIHJldG9ybm8gc29icmUgYWN0aXZvcyAoUk9BKSB1dGlsaXphbmRvIGVsIEVCSVQgZW4gdmV6IGRlIGxhIHV0aWxpZGFkIG5ldGE6CgpgYGB7cn0KYWN0aXZlZGF0YSRST0EgPSBhY3RpdmVkYXRhJGViaXQgLyBhY3RpdmVkYXRhJHRvdGFsYXNzZXRzCmBgYAoKQSBjb250bnVhY2nDs24gc2UgY2FsY3VsYXLDoW4gZWwgbWFyZ2VuIGRlIHV0aWxpZGFkL3Byb2ZpdCBtYXJnaW4oUE0pCiB5IGxhIHJvdGFjacOzbiBkZSBhY3Rpdm9zIChBVE8pLiBQYXJhIGVsIGNhbGN1bG8gZGUgZGVsIG1hcmdlbiBkZSB1dGlsaWRhZCBzZSB1dGlsaXphcsOhIGVsIEVCSVQgZW4gbHVnYXIgZGUgbGEgdXRpbGlkYWQgbmV0YToKYGBge3J9CmFjdGl2ZWRhdGEkUE0gPSBhY3RpdmVkYXRhJGViaXQgLyBhY3RpdmVkYXRhJHJldmVudWUKYWN0aXZlZGF0YSRBVE8gPSBhY3RpdmVkYXRhJHJldmVudWUgLyBhY3RpdmVkYXRhJHRvdGFsYXNzZXRzCmBgYAoKVVNJTkcgQ09ORElUSU9OQUxTIFRPIENSRUFURSBDT0xVTU5TIAoKQSBjb250aW51YWNpw7NuIHNlIHZhIGEgY3JlYXIgdW5hIGNvbHVtbmEgY29uIHZhcmlhYmxlcyBiaW5hcmlhcyBxdWUgYXl1ZGVuIGEgaWRlbnRpZmljYXIgZGUgbWFuZXJhIG3DoXMgc2VuY2lsbGEgc2kgZWwgUk9BIGVuIHVuIGN1YXJ0byBlc3BlY8OtZmljbyBlcyBtYXlvciBhbCBST0EgZGUgY3VhdHJvIGN1YXJ0b3MgKHVuIGHDsW8pIHByZXZpby4gCgpQYXJhIHBvZGVyIGxvZ3JhciBsbyBhbnRlcmlvciBzZXLDoSBuZWNlc2FyaW8gdXRpbGl6YXIgbGEgZnVuY2nDs24gaWZlbHNlKCkuCmBgYHtyfQoKYWN0aXZlZGF0YSRST0FzaWduYWwgPSBpZmVsc2UoYWN0aXZlZGF0YSRST0E+CiAgICAgICAgICAgICAgICAgICAgcGxtOjpsYWcoYWN0aXZlZGF0YSRST0EsIDQpLDEsMCkKCiNlbiBlbCBwcmltZXIgcGFyw6FtZXRybyBkZSBsYSBmdW5jacOzbiBzZSB1c2EgdW4gY29uZGljacOzbiBsb2dpY2EgcXVlIHB1ZWRlIHNlciB2ZXJkYWRlcmEgbyBmYWxzYS4gRW4gZXN0ZSBjYXNvIGxhIGNvbmRpY2nDs24gZXZhbHVhIHNpIGVsIFJPQSBlcyBtYXlvciBxdWUgZWwgUk9BIGRlIGN1YXRybyBwZXJpb2RvcyBhbnRlcmlvcmVzLgoKI0VuIGNhc28gZGUgbGEgY29uZGljacOzbiBzZWEgdmVyZGFkZXJhIGVudG9uY2VzIHNlIGxlIGFzaWduYXLDoSBlbCB2YWxvciBkZWwgc2VndW5kbyBwYXJhbWV0cm8sIHNpIGxhIGNvbmRpY2nDs24gZXMgZmFsc2Egc2UgbGUgYXNnbmFyw6EgZWwgdGVyY2VyIHBhcmFtZXRyby4KYGBgCgoKTk9UQSBJTVBPUlRBTlRFOiBpZmVsZXNlKCkgZXMgdW5hIGRlIGdyYW4gdXRpbGlkYWQgZXNwZWNpYWxtZW50ZSBlbiBsYSBnZXN0acOzbiBkZSBkYXRhIGZpbmFuY2llcmEsIHB1ZXMgcHVlZGUgY3JlYXIgc2XDsWFsZXMgcXVlIGNvbXBhcmVuIHZhbG9yZXMgZmluYW5jZXJvcy4gTGEgZXN0cnVjdHVyYSBnZW5lcmFsIGRlIGVzdGEgZnVuY2nDs24gZXMgbGEgc2lndWllbnRlOiBpZmVsc2UoZGF0YV9jb25kaXRpb24sIHZhbHVlX2lmX1RSVUUsIHZhbHVlX2lmX0ZBTFNFKQoKQSBjb250aW51YWNpw7NuIHNlIG11ZXN0cmEgdW4gZWplbXBsbyBkZSBjb21vIHB1ZWRlIHNlciB1dGlsaXphZGEgbGEgZnVuY2nDs24gCmBgYHtyfQphPTUKYj0xMAppZmVsc2UoYT5iLDEsMCkKCiNkZWJpZG8gYSBxdWUg4oCcYeKAnSBubyBlcyBtYXlvciBhIOKAnGLigJ0sIGVudG9uY2VzIGxhIGZ1bmNpw7NuIGFycm9qYSBlbCByZXN1bHRhZG8gZGUgMC4KYGBgCgpERVNDUklQVElWRSBTVEFUSVNUSUNTIFdJVEggUEFORUwgREFUQSAKCk5PVEEgSU1QT1JUQU5URTogZWwgcHJvY2VzbyBwYXJhIHNhY2FyIGxhcyBlc3RhZMOtc3RpY2FzIGRlc2NyaXB0aXZhcyBkZSB1biBkYXRhIHBhbmVsIG5vIGVzIGVsIG1pc21vIHF1ZSBzZSB1c2EgcGFyYSBwb2RlciBvYnRlbmVyIGxhcyBlc3RhZMOtc3RpY2FzIGRlc2NyaXB0aXZhcyBkZSB1bmEgc2VyaWUgZGUgdGllbXBvLiBFcyBkZSBzdW1hIGltcG9ydGFudGUgdG9tYXIgZW4gY3VlbnRhIGVsIHBlcmlvZG8gZGVsIGRhdGEgcGFuZWwgYSBsYSBob3JhIGRlIHNhY2FyIGVzdGFkw61zdGljYXMsIHB1ZXMgZWwgZGVzY3VpZG8gZGUgZXN0ZSBhc3BlY3RvIHB1ZWRlIHJlc3VsdGFyIGVuIGxhIG9idGVuY2nDs24gZGUgZGF0b3MgZXJyw7NuZW9zLiAKCkVzIHBvc2libGUgZW1wZXphciBhIHJlYWxpemFyIGVsIHByb2Nlc28gZGUgc2FjYXIgbGFzIGVzdGFkw61zdGljYXMgZGVzY3JpcHRpdmFzIGFsIHNlbGVjY2lvbmFyIGVsIMO6bHRpbW8gY3VhcnRvIGRlIGxhIGRhdGE6CmBgYHtyfQpkYXRhMjAxOXE0ID0gYWN0aXZlZGF0YVthY3RpdmVkYXRhJHF1YXJ0ZXI9PScyMDE5LTEwLTAxJyxdCnN1bW1hcnkoZGF0YTIwMTlxNFssYyg0OjcsMTApXSkKYGBgCgpFbiBlbCBjaHVuayBwb3N0ZXJpb3Igc2UgdXRpbGl6YXLDoSBlbCBwYXF1ZXRlIGRwbHlyIHBhcmEgc2VsZWNjaW9uYXIgZWwgw7psdGltbyBjdWFydG8gZGVsIGRhdGEgc2V0LCBzZSBhZ3J1cGFyIGEgbGFzIGVtcHJlc2FzIHBvciBpbmR1c3RyaWFzIHkgc2Ugc2FjYXIgbGEgbWVkaWFuYSBkZSBsYXMgdmFyaWFibGVzIHByaW5jaXBhbGVzLgoKYGBge3J9CmluZHVzdHJpZXM8LXVuaXF1ZShhY3RpdmVkYXRhJG5haWNzMSkKYWN0aXZlZGF0YSAlPiUgCiAgIGZpbHRlcihxdWFydGVyPT0nMjAxOS0xMC0wMScpICU+JQogIGdyb3VwX2J5KG5haWNzMSkgJT4lIAogIHN1bW1hcml6ZShmaXJtcyA9IG4oKSwKICAgICAgICAgICAgbWVkaWFuX3RvdGFsX2Fzc2V0cyA9IG1lZGlhbih0b3RhbGFzc2V0cywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVkaWFuX3JldmVudWUgPSBtZWRpYW4ocmV2ZW51ZSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVkaWFuX2ViaXQgPSBtZWRpYW4oZWJpdCwgbmEucm0gPSBUUlVFKSkKYGBgCgpMb3MgZGF0b3MgYW50ZXJpb3JlcyBtdWVzdHJhbiBlbCBlc3RhZG8gZGVsIG1lcmNhZG8gZmluYW5jaWVybyBtZXhpY2Fuby4gCgpOT1RBIElNUE9SVEFOVEU6IGxhIG1lZGlhIGFyaXRtw6l0aWNhIG5vIGVzICBlbCBtZWpvciBpbnN0cnVtZW50byBwYXJhIHBvZGVyIHJlcHJlc2VudGFyIGVsIGVzdGFkbyBhY3R1YWwgZGVsIG1lcmNhZG8uIEVzIGRlYmlkbyBhIGxvIGFudGVyaW9yIHF1ZSBlcyBtZWpvciB1dGlsaXphciBsYSBtZWRpYW5hLCBwdWVzIGxhIG1lam9yIG1lZGlkYSBkZSB0ZW5kZW5jaWEgY2VudHJhbCBwYXJhIG1lZGlyIHZhcmlhYmxlcyBmaW5hbmNpZXJhcyBjb21vIGluZ3Jlc28gdG90YWwgbyBhY3Rpdm9zIHRvdGFsZXMgZXMgbGEgbWVkaWFuYSwgcHVlcyAgCgpMT09LSU5HIEFUIFRIRSAyIFRBQkxFUyBBQk9WRSwgUFJPVklERSBBIEdPT0QgREVTQ1JJUFRJT04gT0YgQSBUWVBJQ0FMIChBVkVSQUdFKSBGSVJNIElOIE1FWElDTywgQU5EIEEgREVTQ1JJUFRJT04gT0YgVEhFIE1FWElDQU4gTUFSS0VUIElOIFRFUk1TIE9GIEZJUk1TIEJZIElORFVTVFJZIEFORCBGSVJNIFNJWkUgRk9SIEVBQ0ggSU5EVVNUUlkuCgpDb21vIHNlIHB1ZWRlIG9ic2VydmFyIGVuIGxhIMO6bHRpbWEgdGFibGEsIGxhIGluZHVzdHJpYSBjb24gbcOhcyBlbXByZXNhcyBhY3RpdmFzIGVuIGxhIEJvbHNhIGRlIFZhbG9yZXMgTWV4aWNhbmEgZXMgbGEgaW5kdXN0cmlhIGRlIG1hbnVmYWN0dXJhLGxhIHNlZ3VuZGEgbcOhcyBncmFuZGUgZXMgbGEgZGUgZmluYW56YXMgeSBzZWd1cm9zLiAKCkxhcyBpbmR1c3RyYXMgbcOhcyBwZXF1ZcOxYXMgc29uIGxhcyBkZSBsYXMgZGUgZ2VzdGnDs24gZGUgZW1wcmVzYXMgeSBkZSBzYWx1ZCB5IGFzaXN0ZW5jaWEgc29jaWFsLCBwdWVzIGVzdGFuIGN1ZW50YW4gY29uIHNvbGFtZW50ZSAxIGVtcHJlc2EgcmVzcGVjdGl2YW1lbnRlIHF1ZSBjb3RpemEgZW4gbGEgQlZNLiAgCgpBIHBlc2FyIGRlIHF1ZSBlbCBzZWN0b3IgZGUgZ2VzdGnDs24geSBlbXByZXNhcyBlcyB1bm8gZGUgbG9zIG3DoXMgcGVxdWXDsW9zIGVzIGltcG9ydGFudGUgbm90YXIgcXVlIGRlIGFjdWVyZG8gYSBsYSBtZWRpYW5hLCBlcyBlbCBzZWN0b3IgY29uIGVsIHRvdGFsIGRlIGFjdGl2b3MsIG1heW9yIHJldmVudWUgeSBFQklULiBMbyBxdWUgaW5kaWNhIHF1ZSBlbCBzZWN0b3IsIG8gbcOhcyBiaWVuIGRpY2hvIGxhIGVtcHJlc2EgcXVlIGVzdGEgYWN0aXZhIGVuIGxhIEJNViBlcyBtdXkgcmVudGFibGUuCgpQb3Igc3UgcGFydGUgZXMgaW1wb3J0YW50ZSByZXNhbHRhciBkZSBpZ3VhbCBtYW5lcmEgcXVlIGxhIGluZHVzdHJpYSBkZSBtYW51ZmFjdHVyYSBlcyBsYSBzZWd1bmRhIGNvbiBtYXlvcmVzIGFjdGl2b3MsIGxhIHRlcmNlcmEgZW4gcmV2ZW51ZSB5IGxhIHNlZ3VuZGEgY29uIG1heW9yIEVCSVQuIEVzIGxvIHF1ZSBpbmRpY2EgcXVlIGVzdGEgaW5kdXN0cmlhIGFkZW3DoXMgZGUgc2VyIHVuYSBpbmR1c3RyaWEgbXV5IGdyYW5kZSwgdGFtYmnDqW4gZXMgbXV5IHJlbnRhYmxlLgo=