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