Buscando Ayuda
Las siguientes funciones pueden ser ?tiles al tener alguna duda respecto al lenguaje R
help.start()
help("pp")
?pp
??pp
example(topic)
Estructuras de datos
- Vectores (unidimensionales)
- Matrices (bidimensionales)
- Arrays (multidimensionales)
- Factores (vectores de variables categ?ricas, para agrupar los componentes de otro vector)
- Listas (colecci?n de objetos, cada uno puede ser de un tipo)
- Data Frames (generalizaci?n de matrices; cada fila es un elemento, cada columna una variable de diferente tipo)
- Funciones (objetos creados para hacer operaciones)
Estructura de datos: Vectores
R utiliza diferentes estructuras de datos. La estructura m?s simple es el vector, que es una colecci?n ordenada de numeros. Para crear un vector, por ejemplo x, consistente en cinco n?meros, por ejemplo 10.4, 5.6, 3.1, 6.4 y 21.7:
x <- c(10.4, 5.6, 3.1, 6.4, 21.7)
x
[1] 10.4 5.6 3.1 6.4 21.7
Podemos crear vectores de cadenas de texto de la misma forma que la presentada anteriormente:
x<-c("perro", "gato","pez", "hamster")
x
[1] "perro" "gato" "pez" "hamster"
Los ejemplos anteriores son ejemplos de la funci?n “asignaci?n”," en la que se utiliza la funci?n c() que, en este contexto, puede tener un n?mero arbitrario de vectores como argumento y cuyo valor es el vector obtenido mediante la concatenaci?n de todos ellos. Un n?mero, por s? mismo, se considera un vector de longitud uno. Advierta que el operador de asignaci?n, (‘<-’), no es el operador habitual, ‘=’, que se reserva para otro prop?sito, sino que consiste en dos caracteres, ‘<’ (‘menor que’) y ‘-’ (‘gui?n’), que obligatoriamente deben ir unidos y ?puntan’ hacia el objeto que recibe el valor de la expresi?n.
c(10.4, 5.6, 3.1, 6.4, 21.7) -> x
x
[1] 10.4 5.6 3.1 6.4 21.7
Si una expresi?n se utiliza como una orden por s? misma, su valor se imprime y se pierde. As? pues, la orden:
1/x
[1] 0.09615385 0.17857143 0.32258065 0.15625000 0.04608295
simplemente imprime los inversos de los cinco valores anteriores en la pantalla (por supuesto, el valor de x no se modifica).
Si a continuaci?n hace la asignaci?n
y <- c(x, 0, x)
y
[1] 10.4 5.6 3.1 6.4 21.7 0.0 10.4 5.6 3.1 6.4 21.7
crear? un vector, y, con 11 elementos, consistentes en dos copias de x con un cero entre ambas.
Aritm?tica Vectorial
Los vectores pueden usarse en expresiones aritm?ticas, en cuyo caso las operaciones se realizan elemento a elemento.
v <- 2*x + 1
v
[1] 21.8 12.2 7.2 13.8 44.4
v+x
[1] 32.2 17.8 10.3 20.2 66.1
v*x
[1] 226.72 68.32 22.32 88.32 963.48
Los operadores aritm?ticos elementales son los habituales +, -, *, / y ^ para elevar a una potencia. Adem?s, est?n disponibles las funciones log, exp, sin, cos, tan, sqrt, bien conocidas.
Existen muchas m?s funciones, entre otras, las siguientes: max y min que seleccionan respectivamente el mayor y el menor elemento de un vector; range cuyo valor es el vector de longitud dos, c(min(x), max(x)); length(x) que es el n?mero de elementos o longitud de x; sum(x) que es la suma de todos los elementos de x; y prod(x) que es el producto de todos ellos.
max(x)
[1] 21.7
min(x)
[1] 3.1
length(x)
[1] 5
sum(x)
[1] 47.2
Dos funciones estad?sticas son mean(x), que calcula la media, esto es,
sum(x)/length(x)
[1] 9.44
mean(x)
[1] 9.44
y var(x) que calcula la cuasi-varianza, esto es,
sum((x-mean(x))^2)/(length(x)-1)
[1] 53.853
var(x)
[1] 53.853
Generaci?n de sucesiones
En R existen varias funciones para generar sucesiones num?ricas. Por ejemplo, 1:30 es el vector c(1,2, …,29,30). El operador ‘dos puntos’ tiene m?xima prioridad en una expresi?n, as?, por ejemplo, 2*1:15 es el vector c(2,4,6, …,28,30).
n<-10
1:n-1
[1] 0 1 2 3 4 5 6 7 8 9
1:(n-1)
[1] 1 2 3 4 5 6 7 8 9
Vectores de ?ndices. Selecci?n y modificaci?n de subvectores
Puede seleccionar un subvector de un vector a?adiendo al nombre del mismo un vector de ?ndices entre corchetes, [ y ]. En general podr? obtener un subvector de cualquier expresi?n cuyo resultado sea un vector, sin m?s que a?adirle un vector de ?ndices entre corchetes.
Los vectores de ?ndices pueden ser de cuatro tipos distintos:
- Un vector l?gico. En este caso el vector de ?ndices debe tener la misma longitud que el vector al que refiere. S?lo se seleccionar?n los elementos correspondientes a valores T del vector de ?ndices y se omitir? el resto. Por ejemplo,
x<-c(x,NA,NA,NA,x,-x)
y <- x[!is.na(x)]
y
[1] 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7 -10.4 -5.6 -3.1 -6.4 -21.7
almacena en y los valores no-faltantes de x, en el mismo orden. Si x tiene valores faltantes, el vector y ser? m?s corto que x.
An?logamente,
(x+1)[(!is.na(x)) & x>0] -> z
z
[1] 11.4 6.6 4.1 7.4 22.7 11.4 6.6 4.1 7.4 22.7
almacena en z los elementos del vector x+1 para los que el correspondiente elemento de x es no-faltante y positivo.
- Un vector de n?meros naturales positivos. En este caso los elementos del vector de ?ndices deben pertenecer al conjunto {1, 2, . . ., length(x)}. El resultado es un vector formado por los elementos del vector referido que corresponden a estos ?ndices y en el orden en que aparecen en el vector de ?ndices. El vector de ?ndices puede tener cualquier longitud y el resultado ser? de esa misma longitud. Por ejemplo, x[6] es el sexto elemento de x, y
x[1:10]
[1] 10.4 5.6 3.1 6.4 21.7 NA NA NA 10.4 5.6
x[6]
[1] NA
es el vector formado por los diez primeros elementos de x, (supuesto que length(x) no es menor que 10). Por otra parte,
c("x","y")[rep(c(1,2,2,1), times=4)]
[1] "x" "y" "y" "x" "x" "y" "y" "x" "x" "y" "y" "x" "x" "y" "y" "x"
crea un vector de caracteres de longitud 16 formado por “x”, “y”, “y”, “x” repetido cuatro veces.
- Un vector de n?meros naturales negativos. En este caso, los ?ndices indican los elementos del vector referido que deben excluirse.
y <- x[-(1:5)]
y
[1] NA NA NA 10.4 5.6 3.1 6.4 21.7 -10.4 -5.6 -3.1 -6.4 -21.7
almacena en el vector y todos los elementos de x excepto los cinco primeros (suponiendo que x tiene al menos cinco elementos).
- Un vector de caracteres. Esta opci?n solo puede realizarse si el vector posee el atributo names (nombres) para identificar sus componentes, en cuyo caso se comportar? de modo similar al punto 2.
fruta <- c(5, 10, 1, 20)
names(fruta) <- c("naranja", "pl?tano", "manzana", "pera")
postre <- fruta[c("manzana","naranja")]
fruta
naranja pl?tano manzana pera
5 10 1 20
postre
manzana naranja
1 5
La ventaja en este caso es que los nombres son a menudo m?s f?ciles de recordar que los ?ndices num?ricos.
La variable de almacenamiento tambi?n puede ser indexada, en cuyo caso la asignaci?n se realiza solamente sobre los elementos referidos. La expresi?n debe ser de la forma vector[vector de ?ndices] ya que la utilizaci?n de una expresi?n arbitraria en vez del nombre de un vector no tiene mucho sentido. El vector asignado debe ser de la misma longitud que el vector de ?ndices y, en el caso de un vector de ?ndices l?gico, debe ser de la misma longitud del vector que indexa. Por ejemplo,
x[is.na(x)] <- 0
x
[1] 10.4 5.6 3.1 6.4 21.7 0.0 0.0 0.0 10.4 5.6 3.1 6.4 21.7 -10.4 -5.6 -3.1 -6.4 -21.7
sustituye cada valor faltante de x por un cero. Por otra parte,
y<-na.omit(y)
y[y < 0] <- -y[y < 0]
y
[1] 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7
attr(,"na.action")
[1] 1 2 3
attr(,"class")
[1] "omit"
equivale a
y <- abs(y)
y
[1] 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7
attr(,"na.action")
[1] 1 2 3
attr(,"class")
[1] "omit"
Factores Nominales y Ordinales
Un factor es un vector utilizado para especificar una clasificaci?n discreta de los elementos de otro vector de igual longitud. En R existen factores nominales y factores ordinales.
Suponga que dispone de una muestra de 30 personas de Australia de tal modo que su estado o territorio se especifica mediante un vector de caracteres con las abreviaturas de los mismos:
estado <- c("tas", "sa", "qld", "nsw", "nsw", "nt", "wa", "wa",
"qld", "vic", "nsw", "vic", "qld", "qld", "sa", "tas",
"sa", "nt", "wa", "vic", "qld", "nsw", "nsw", "wa",
"sa", "act", "nsw", "vic", "vic", "act")
Recuerde que, para un vector de caracteres, la palabra “ordenado” indica que est? en orden alfab?tico. Un factor se crea utilizando la funci?n factor():
FactorEstado <- factor(estado)
FactorEstado
[1] tas sa qld nsw nsw nt wa wa qld vic nsw vic qld qld sa tas sa nt wa vic qld nsw nsw wa sa act nsw
[28] vic vic act
Levels: act nsw nt qld sa tas vic wa
Puede utilizar la funci?n levels() para ver los niveles de un factor:
levels(FactorEstado)
[1] "act" "nsw" "nt" "qld" "sa" "tas" "vic" "wa"
Ahora, suponga que disponemos en otro vector de los ingresos de las mismas personas (medidos con unas unidades apropiadas)
ingresos <- c(60, 49, 40, 61, 64, 60, 59, 54, 62, 69, 70, 42, 56,
61, 61, 61, 58, 51, 48, 65, 49, 49, 41, 48, 52, 46,
59, 46, 58, 43)
Para calcular la media muestral para cada estado podemos usar la funci?n tapply() que devuelve el vector de medias con las componentes etiquetadas con los niveles:
MediaIngresos <- tapply(ingresos, FactorEstado, mean)
MediaIngresos
act nsw nt qld sa tas vic wa
44.50000 57.33333 55.50000 53.60000 55.00000 60.50000 56.00000 52.25000
La funci?n tapply() aplica una funci?n, en este ejemplo la funci?n mean(), a cada grupo de componentes del primer argumento, en este ejemplo ingresos, definidos por los niveles del segundo argumento, en este ejemplo FactorEstado, como si cada grupo fuese un vector por s? solo. El resultado es una estructura cuya longitud es el n?mero de niveles del factor. Puede consultar la ayuda para obtener m?s detalles. Suponga que ahora desea calcular las desviaciones t?picas de las medias de ingresos por estados. Para ello es necesario escribir una funci?n en R que calcule la desviaci?n t?pica de un vector. Aunque a?n no se ha explicado en este texto c?mo escribir funciones, puede admitir que existe la funci?n var() que calcula la varianza muestral o cuasi-varianza, y que la funci?n buscada puede construirse con la asignaci?n:
StdErr <- function(x) sqrt(var(x)/length(x))
Ahora puede calcular los valores buscados mediante dicha funci?n con el siguiente resultado:
ErrorTipicoIngresos <- tapply(ingresos, FactorEstado, StdErr)
ErrorTipicoIngresos
act nsw nt qld sa tas vic wa
1.500000 4.310195 4.500000 4.106093 2.738613 0.500000 5.244044 2.657536
La funci?n tapply() puede utilizarse para aplicar una funci?n a un vector indexado por diferentes categor?as simult?neamente. Por ejemplo, para dividir la muestra tanto por el estado como por el sexo. Los elementos del vector se dividir?n en grupos correspondientes a las distintas categor?as y se aplicar? la funci?n a cada uno de dichos grupos. El resultado es una variable indexada etiquetada con los niveles de cada categor?a.
Matrices
R posee facilidades para manipular y hacer operaciones con matrices. Las funciones rbind() y cbind() unen matrices con respecto a sus filas o columnas respectivamente:
m1 <- matrix(1, nr = 2, nc = 2)
m2 <- matrix(2, nr = 2, nc = 2)
rbind(m1, m2)
[,1] [,2]
[1,] 1 1
[2,] 1 1
[3,] 2 2
[4,] 2 2
cbind(m1, m2)
[,1] [,2] [,3] [,4]
[1,] 1 1 2 2
[2,] 1 1 2 2
El operador para el producto de dos matrices es ’%*%’. Por ejemplo, considerando las dos matrices m1 y m2:
rbind(m1, m2) %*% cbind(m1, m2)
[,1] [,2] [,3] [,4]
[1,] 2 2 4 4
[2,] 2 2 4 4
[3,] 4 4 8 8
[4,] 4 4 8 8
cbind(m1, m2) %*% rbind(m1, m2)
[,1] [,2]
[1,] 10 10
[2,] 10 10
La transposicion de una matriz se realiza con la funci?n “t”; esta funcion tambi?n funciona con marcos de datos.
t(cbind(m1, m2) %*% rbind(m1, m2))
[,1] [,2]
[1,] 10 10
[2,] 10 10
La funci?n diag se puede usar para extraer o modificar la diagonal de una matriz o para construir una matriz diagonal:
diag(m1)
[1] 1 1
diag(rbind(m1, m2) %*% cbind(m1, m2))
[1] 2 2 8 8
diag(m1) <- 10
m1
[,1] [,2]
[1,] 10 1
[2,] 1 10
diag(3)
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 0 0 1
v <- c(10, 20, 30)
diag(v)
[,1] [,2] [,3]
[1,] 10 0 0
[2,] 0 20 0
[3,] 0 0 30
diag(2.1, nr = 3, nc = 5)
[,1] [,2] [,3] [,4] [,5]
[1,] 2.1 0.0 0.0 0 0
[2,] 0.0 2.1 0.0 0 0
[3,] 0.0 0.0 2.1 0 0
Arrays
z <- array(1:24, dim=c(2,3,4))
z
, , 1
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
, , 2
[,1] [,2] [,3]
[1,] 7 9 11
[2,] 8 10 12
, , 3
[,1] [,2] [,3]
[1,] 13 15 17
[2,] 14 16 18
, , 4
[,1] [,2] [,3]
[1,] 19 21 23
[2,] 20 22 24
dim(z)
[1] 2 3 4
Elementos:
x <- matrix(1:12, nrow=3, ncol=4)
x[1,] # fila i
[1] 1 4 7 10
x[,2] # columna j
[1] 4 5 6
x[3,4] # elemento i,j
[1] 12
Generci?n de n?meros aleatorios
R tiene su propio mecanismo para generar n?meros aleatorios, en particular, puede generar n?mero aleatorios provenientes de las prinicipales familias de variables aleatorias utilizando las siguientes funciones:
| uniforme |
runif(n,min=0,max=1) |
|
|
|
| Normal |
rnorm(n,mean=0,sd=1) |
|
|
|
| exponencial |
rexp(n,rate=1) |
|
|
|
| gamma |
rgamma(n,shape,scale=1) |
|
|
|
| Poisson |
rpois(n,lambda) |
|
|
|
| binomial |
rbinom(n,size,prob) |
|
|
|
| geometrica |
rgeom(n,prob) |
|
|
|
| binomial |
rnbinom(n,size,prob) |
|
|
|
La posibilidad de generar datos aleatorios es bastante util en estad ?stica y R tiene la capacidad de hacer esto para un gran numero de funciones y distribuciones. Estas funciones son de la forma rfunc(n, p1, p2, …), donde func indica la disribucion, n es el numero de datos ge- nerado, y p1, p2, . . . son valores que toman los parametros de la distribuci ?n. La tabla anterior muestra los detalles de cada distribucion, y los posibles valores por defecto de los par ?metros (si no se indica, significa que el parametro debe ser especificado por el usuario). Todas estas funciones se pueden usar reemplazando la letra r con las letras d, p o q para obtener, la densidad de probabilidad (dfunc(x, …)), la densidad de probabilidad acumulada (pfunc(x, …)), y el valor del cuartil (qfunc(p, …), con 0 < p < 1) respectivamente.
Veremos la aplicaci?n de dichas funciones en la siguiente secci?n, con el fin de ejemplificar el m?todo para graficar datos en R.
Gr?ficos en R
R ofrece una increible variedad de graficos. Para darse una idea, escriba el comando demo(graphics). No nos es posible detallar aqui todas las posibilidades de R en terminos de generaci?n de gr?ficas. Cada funcion gr ?fica en R tiene un enorme n?mero de opciones permitiendo una gran flexibilidad en la produccion de gr ?ficos y el uso de cualquier otro paquete gr?fico palidece en comparaci ?n. El modus operandi de las funciones graficas es sustancialmente diferente del esquema esbozado al principio de este documento. Particularmente, el resultado de una funcion gr ?fica no puede ser asignado a un objeto11 sino que es enviado a un dispositivo grafico . Un dispositivo grafico es una ventana grafica o un archivo. Existen dos tipos de funciones graficas: las funciones de graficacion de alto nivel que crean una nueva grafica y las funciones de graficacion de bajo nivel que agregan elementos a una grafica ya existente. Las graficas se producen con respecto a parametros gr ?ficos que estan definidos por defecto y pueden ser modificados con la funcion? par. Primero veremos como manejar graficos y dispositivos gr ?ficos; despu?s veremos en detalle algunas funciones graficas y sus par ?metros. Veremos ejemplos pr ?cticos del uso de estas fun- cionalidades en la produccion de gr ?ficos. Finalmente, veremos los paquetes grid y lattice cuyo funcionamiento es diferente a las funciones graficas ‘normales’ de R.
Para ilustrar algunas de las funcionalidades graficas de R, consideremos un ejemplo simple de una gr?fica bivariada con 10 pares de coordenadas generadas al azar. ?stos valores se generaron con:
x <- rnorm(100)
y <- rnorm(100)
La grafica que queremos visualizar se puede obtener con plot(); simplemente se escribe el comando:
hist(x)

plot(x,type="l")

plot(x, y)

y la grafica ser? visible en el dispositivo gr?fico activo. Por defecto, R dibuja graficas de una manera “inteligente”: los espacios entre los marcadores de los ejes, la ubicacion de las etiquetas en los ejes, etc, son calculados autom?ticamente de tal manera que la grafica resultante sea lo mas legible posible. Sin embargo, el usuario puede cambiar la manera como se presenta la grafica, por ejemplo, para ajustarse a un estilo editorial pre-definido o para darle un toque personal para una charla.
Funciones
Objetos que pueden ser creados por el usuario para hacer, y repetir, operaciones espec?ficas
stddev <- function(x) {
res = sqrt(sum((x-mean(x))^2) / (length(x)-1))
return(res)
}
Se pueden usar y definir funciones dentro de funciones. El valor devuelto por una funci?n es el resultado de la ?ltima expresi?n evaluada o el especificado con el comando return Los argumentos de las funciones pueden especificarse por su posici?n o por su nombre. Puede haber argumentos con valores por defecto.
Funciones Iterativas
Recomiendo no utilizar ciclos en R (lentos).
lapply (calcula una funci?n para todos los elementos de una lista)
sapply (igual pero simplificando el resultado)
apply (calcula una funci?n para parte, columnas o filas, de una matriz)
tapply (calcula una funci?n para un subconjunto de un vector; ej. usando un factor)
a <- matrix(1:12, nrow=3, ncol=4)
a
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
b <- matrix(1:12,byrow=TRUE, nrow=3, ncol=4)
b
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
apply(a,1,mean) # medias por filas ("1")
[1] 5.5 6.5 7.5
rowMeans(a)
[1] 5.5 6.5 7.5
apply(a,1,sum)
[1] 22 26 30
rowSums(a)
[1] 22 26 30
apply(a,2,mean)# medias por columnas ("2")
[1] 2 5 8 11
apply(a,2,sum)
[1] 6 15 24 33
LS0tDQp0aXRsZTogIlFGVEM6IFR1dG9yaWFsIGRlIFIiDQphdXRob3I6ICJDbGF1ZGlvIEN1ZXZhcyBQYXpvcyINCm91dHB1dDogIA0KICAgIGh0bWxfbm90ZWJvb2s6DQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIG1hdGhqYXg6IG51bGwNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCi0tLQ0KI0luc3RhbGFjaT9uIGRlIFINCg0KW0Rlc2RlIGxhIHA/Z2luYSBSIHByb2plY3RdKGh0dHBzOi8vY3Jhbi5pdGFtLm14LykNCg0KI0luc3RhbGFjaT9uIGRlIFJTdHVkaW8NCg0KW0xpbmsgZGVzZGUgbGEgcD9naW5hIG9maWNpYWxdKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3Byb2R1Y3RzL3JzdHVkaW8vZG93bmxvYWQvKQ0KDQojQnVzY2FuZG8gQXl1ZGENCg0KTGFzIHNpZ3VpZW50ZXMgZnVuY2lvbmVzIHB1ZWRlbiBzZXIgP3RpbGVzIGFsIHRlbmVyIGFsZ3VuYSBkdWRhIHJlc3BlY3RvIGFsIGxlbmd1YWplIFINCg0KYGBge3IgZXZhbD1GQUxTRX0NCmhlbHAuc3RhcnQoKQkJCQkJCQkJCQkJDQpoZWxwKCJwcCIpCQkJCQkJCQkJCQkJDQo/cHAJCQkJCQkJCQkJCQkJCQkJDQo/P3BwCQkJCQkJCQkJCQkJCQkJDQpleGFtcGxlKHRvcGljKQkJCQkJCQkJDQoJCQkJDQpgYGANCg0KI0VzdHJ1Y3R1cmFzIGRlIGRhdG9zDQoNCiogVmVjdG9yZXMgKHVuaWRpbWVuc2lvbmFsZXMpDQoqIE1hdHJpY2VzIChiaWRpbWVuc2lvbmFsZXMpDQoqIEFycmF5cyAobXVsdGlkaW1lbnNpb25hbGVzKQ0KKiBGYWN0b3JlcyAodmVjdG9yZXMgZGUgdmFyaWFibGVzIGNhdGVnP3JpY2FzLCBwYXJhIGFncnVwYXIgbG9zDQogIGNvbXBvbmVudGVzIGRlIG90cm8gdmVjdG9yKQ0KKiBMaXN0YXMgKGNvbGVjY2k/biBkZSBvYmpldG9zLCBjYWRhIHVubyBwdWVkZSBzZXIgZGUgdW4gdGlwbykNCiogRGF0YSBGcmFtZXMgKGdlbmVyYWxpemFjaT9uIGRlIG1hdHJpY2VzOyBjYWRhIGZpbGEgZXMgdW4NCiAgZWxlbWVudG8sIGNhZGEgY29sdW1uYSB1bmEgdmFyaWFibGUgZGUgZGlmZXJlbnRlIHRpcG8pDQoqIEZ1bmNpb25lcyAob2JqZXRvcyBjcmVhZG9zIHBhcmEgaGFjZXIgb3BlcmFjaW9uZXMpDQoNCg0KI0VzdHJ1Y3R1cmEgZGUgZGF0b3M6IFZlY3RvcmVzDQoNClIgdXRpbGl6YSBkaWZlcmVudGVzIGVzdHJ1Y3R1cmFzIGRlIGRhdG9zLiBMYSBlc3RydWN0dXJhIG0/cyBzaW1wbGUgZXMgZWwgdmVjdG9yLCBxdWUgZXMNCnVuYSBjb2xlY2NpP24gb3JkZW5hZGEgZGUgbnVtZXJvcy4gUGFyYSBjcmVhciB1biB2ZWN0b3IsIHBvciBlamVtcGxvIHgsIGNvbnNpc3RlbnRlIGVuDQpjaW5jbyBuP21lcm9zLCBwb3IgZWplbXBsbyAxMC40LCA1LjYsIDMuMSwgNi40IHkgMjEuNzoNCmBgYHtyfQ0KeCA8LSBjKDEwLjQsIDUuNiwgMy4xLCA2LjQsIDIxLjcpDQoNCngNCmBgYA0KUG9kZW1vcyBjcmVhciB2ZWN0b3JlcyBkZSBjYWRlbmFzIGRlIHRleHRvIGRlIGxhIG1pc21hIGZvcm1hIHF1ZSBsYSBwcmVzZW50YWRhIGFudGVyaW9ybWVudGU6DQpgYGB7cn0NCng8LWMoInBlcnJvIiwgImdhdG8iLCJwZXoiLCAiaGFtc3RlciIpDQp4DQpgYGANCg0KLS0tDQoNCkxvcyBlamVtcGxvcyBhbnRlcmlvcmVzIHNvbiBlamVtcGxvcyBkZSBsYSBmdW5jaT9uICJhc2lnbmFjaT9uIiwiIGVuIGxhIHF1ZSBzZSB1dGlsaXphIGxhIGZ1bmNpP24gYygpIHF1ZSwgZW4gZXN0ZSBjb250ZXh0bywgcHVlZGUgdGVuZXIgdW4gbj9tZXJvIGFyYml0cmFyaW8gZGUgdmVjdG9yZXMgY29tbyBhcmd1bWVudG8geSBjdXlvIHZhbG9yIGVzIGVsIHZlY3RvciBvYnRlbmlkbw0KbWVkaWFudGUgbGEgY29uY2F0ZW5hY2k/biBkZSB0b2RvcyBlbGxvcy4NClVuIG4/bWVybywgcG9yIHM/IG1pc21vLCBzZSBjb25zaWRlcmEgdW4gdmVjdG9yIGRlIGxvbmdpdHVkIHVuby4NCkFkdmllcnRhIHF1ZSBlbCBvcGVyYWRvciBkZSBhc2lnbmFjaT9uLCAoJzwtJyksIG5vIGVzIGVsIG9wZXJhZG9yIGhhYml0dWFsLCAnPScsIHF1ZSBzZQ0KcmVzZXJ2YSBwYXJhIG90cm8gcHJvcD9zaXRvLCBzaW5vIHF1ZSBjb25zaXN0ZSBlbiBkb3MgY2FyYWN0ZXJlcywgJzwnICgnbWVub3IgcXVlJykgeSAnLScNCignZ3VpP24nKSwgcXVlIG9ibGlnYXRvcmlhbWVudGUgZGViZW4gaXIgdW5pZG9zIHkgP3B1bnRhbicgaGFjaWEgZWwgb2JqZXRvIHF1ZSByZWNpYmUgZWwNCnZhbG9yIGRlIGxhIGV4cHJlc2k/bi4NCmBgYHtyfQ0KYygxMC40LCA1LjYsIDMuMSwgNi40LCAyMS43KSAtPiB4DQp4DQpgYGANCg0KLS0tDQoNClNpIHVuYSBleHByZXNpP24gc2UgdXRpbGl6YSBjb21vIHVuYSBvcmRlbiBwb3Igcz8gbWlzbWEsIHN1IHZhbG9yIHNlIGltcHJpbWUgeSBzZSBwaWVyZGUuDQpBcz8gcHVlcywgbGEgb3JkZW46DQpgYGB7cn0NCjEveA0KYGBgDQpzaW1wbGVtZW50ZSBpbXByaW1lIGxvcyBpbnZlcnNvcyBkZSBsb3MgY2luY28gdmFsb3JlcyBhbnRlcmlvcmVzIGVuIGxhIHBhbnRhbGxhIChwb3Igc3VwdWVzdG8sDQplbCB2YWxvciBkZSB4IG5vIHNlIG1vZGlmaWNhKS4NCg0KDQpTaSBhIGNvbnRpbnVhY2k/biBoYWNlIGxhIGFzaWduYWNpP24gDQoNCmBgYHtyfQ0KeSA8LSBjKHgsIDAsIHgpDQp5DQpgYGANCmNyZWFyPyB1biB2ZWN0b3IsIHksIGNvbiAxMSBlbGVtZW50b3MsIGNvbnNpc3RlbnRlcyBlbiBkb3MgY29waWFzIGRlIHggY29uIHVuIGNlcm8gZW50cmUNCmFtYmFzLg0KDQoNCiNBcml0bT90aWNhIFZlY3RvcmlhbA0KDQpMb3MgdmVjdG9yZXMgcHVlZGVuIHVzYXJzZSBlbiBleHByZXNpb25lcyBhcml0bT90aWNhcywgZW4gY3V5byBjYXNvIGxhcyBvcGVyYWNpb25lcw0Kc2UgcmVhbGl6YW4gZWxlbWVudG8gYSBlbGVtZW50by4NCg0KDQpgYGB7cn0NCnYgPC0gMip4ICArIDENCg0Kdg0KDQp2K3gNCnYqeA0KYGBgDQoNCkxvcyBvcGVyYWRvcmVzIGFyaXRtP3RpY29zIGVsZW1lbnRhbGVzIHNvbiBsb3MgaGFiaXR1YWxlcyArLCAtLCAqLCAvIHkgXiBwYXJhIGVsZXZhcg0KYSB1bmEgcG90ZW5jaWEuIEFkZW0/cywgZXN0P24gZGlzcG9uaWJsZXMgbGFzIGZ1bmNpb25lcyBsb2csIGV4cCwgc2luLCBjb3MsIHRhbiwgc3FydCwNCmJpZW4gY29ub2NpZGFzLiANCg0KLS0tDQoNCkV4aXN0ZW4gbXVjaGFzIG0/cyBmdW5jaW9uZXMsIGVudHJlIG90cmFzLCBsYXMgc2lndWllbnRlczogbWF4IHkgbWluIHF1ZQ0Kc2VsZWNjaW9uYW4gcmVzcGVjdGl2YW1lbnRlIGVsIG1heW9yIHkgZWwgbWVub3IgZWxlbWVudG8gZGUgdW4gdmVjdG9yOyByYW5nZSBjdXlvIHZhbG9yDQplcyBlbCB2ZWN0b3IgZGUgbG9uZ2l0dWQgZG9zLCBjKG1pbih4KSwgbWF4KHgpKTsgbGVuZ3RoKHgpIHF1ZSBlcyBlbCBuP21lcm8gZGUgZWxlbWVudG9zDQpvIGxvbmdpdHVkIGRlIHg7IHN1bSh4KSBxdWUgZXMgbGEgc3VtYSBkZSB0b2RvcyBsb3MgZWxlbWVudG9zIGRlIHg7IHkgcHJvZCh4KSBxdWUgZXMgZWwNCnByb2R1Y3RvIGRlIHRvZG9zIGVsbG9zLg0KDQpgYGB7cn0NCm1heCh4KQ0KbWluKHgpDQpsZW5ndGgoeCkNCnN1bSh4KQ0KYGBgDQoNCkRvcyBmdW5jaW9uZXMgZXN0YWQ/c3RpY2FzIHNvbiBtZWFuKHgpLCBxdWUgY2FsY3VsYSBsYSBtZWRpYSwgZXN0byBlcywNCg0KDQpgYGB7cn0NCnN1bSh4KS9sZW5ndGgoeCkNCm1lYW4oeCkNCmBgYA0KDQp5IHZhcih4KSBxdWUgY2FsY3VsYSBsYSBjdWFzaS12YXJpYW56YSwgZXN0byBlcywNCg0KYGBge3J9DQpzdW0oKHgtbWVhbih4KSleMikvKGxlbmd0aCh4KS0xKQ0KdmFyKHgpDQpgYGANCg0KDQoNCiNHZW5lcmFjaT9uIGRlIHN1Y2VzaW9uZXMNCkVuIFIgZXhpc3RlbiB2YXJpYXMgZnVuY2lvbmVzIHBhcmEgZ2VuZXJhciBzdWNlc2lvbmVzIG51bT9yaWNhcy4gUG9yIGVqZW1wbG8sIDE6MzANCmVzIGVsIHZlY3RvciBjKDEsMiwgLi4uLDI5LDMwKS4gRWwgb3BlcmFkb3IgJ2RvcyBwdW50b3MnIHRpZW5lIG0/eGltYSBwcmlvcmlkYWQgZW4gdW5hDQpleHByZXNpP24sIGFzPywgcG9yIGVqZW1wbG8sIDIqMToxNSBlcyBlbCB2ZWN0b3IgYygyLDQsNiwgLi4uLDI4LDMwKS4NCg0KYGBge3J9DQpuPC0xMA0KMTpuLTENCjE6KG4tMSkNCmBgYA0KDQojVmVjdG9yZXMgZGUgP25kaWNlcy4gU2VsZWNjaT9uIHkgbW9kaWZpY2FjaT9uIGRlIHN1YnZlY3RvcmVzDQoNClB1ZWRlIHNlbGVjY2lvbmFyIHVuIHN1YnZlY3RvciBkZSB1biB2ZWN0b3IgYT9hZGllbmRvIGFsIG5vbWJyZSBkZWwgbWlzbW8gdW4gdmVjdG9yDQpkZSA/bmRpY2VzIGVudHJlIGNvcmNoZXRlcywgWyB5IF0uIEVuIGdlbmVyYWwgcG9kcj8gb2J0ZW5lciB1biBzdWJ2ZWN0b3IgZGUgY3VhbHF1aWVyDQpleHByZXNpP24gY3V5byByZXN1bHRhZG8gc2VhIHVuIHZlY3Rvciwgc2luIG0/cyBxdWUgYT9hZGlybGUgdW4gdmVjdG9yIGRlID9uZGljZXMgZW50cmUNCmNvcmNoZXRlcy4NCg0KDQpMb3MgdmVjdG9yZXMgZGUgP25kaWNlcyBwdWVkZW4gc2VyIGRlIGN1YXRybyB0aXBvcyBkaXN0aW50b3M6DQoNCjEuIFVuIHZlY3RvciBsP2dpY28uIEVuIGVzdGUgY2FzbyBlbCB2ZWN0b3IgZGUgP25kaWNlcyBkZWJlIHRlbmVyIGxhIG1pc21hIGxvbmdpdHVkIHF1ZQ0KZWwgdmVjdG9yIGFsIHF1ZSByZWZpZXJlLiBTP2xvIHNlIHNlbGVjY2lvbmFyP24gbG9zIGVsZW1lbnRvcyBjb3JyZXNwb25kaWVudGVzIGEgdmFsb3Jlcw0KVCBkZWwgdmVjdG9yIGRlID9uZGljZXMgeSBzZSBvbWl0aXI/IGVsIHJlc3RvLiBQb3IgZWplbXBsbywNCmBgYHtyfQ0KeDwtYyh4LE5BLE5BLE5BLHgsLXgpDQp5IDwtIHhbIWlzLm5hKHgpXQ0KeQ0KYGBgDQogDQphbG1hY2VuYSBlbiB5IGxvcyB2YWxvcmVzIG5vLWZhbHRhbnRlcyBkZSB4LCBlbiBlbCBtaXNtbyBvcmRlbi4gU2kgeCB0aWVuZSB2YWxvcmVzDQpmYWx0YW50ZXMsIGVsIHZlY3RvciB5IHNlcj8gbT9zIGNvcnRvIHF1ZSB4LiANCg0KLS0tDQoNCkFuP2xvZ2FtZW50ZSwNCmBgYHtyfQ0KKHgrMSlbKCFpcy5uYSh4KSkgJiB4PjBdIC0+IHoNCnoNCmBgYA0KIA0KYWxtYWNlbmEgZW4geiBsb3MgZWxlbWVudG9zIGRlbCB2ZWN0b3IgeCsxIHBhcmEgbG9zIHF1ZSBlbCBjb3JyZXNwb25kaWVudGUgZWxlbWVudG8NCmRlIHggZXMgbm8tZmFsdGFudGUgeSBwb3NpdGl2by4NCg0KMi4gVW4gdmVjdG9yIGRlIG4/bWVyb3MgbmF0dXJhbGVzIHBvc2l0aXZvcy4gRW4gZXN0ZSBjYXNvIGxvcyBlbGVtZW50b3MgZGVsIHZlY3RvciBkZQ0KP25kaWNlcyBkZWJlbiBwZXJ0ZW5lY2VyIGFsIGNvbmp1bnRvIHsxLCAyLCAuIC4gLiwgbGVuZ3RoKHgpfS4gRWwgcmVzdWx0YWRvIGVzIHVuIHZlY3Rvcg0KZm9ybWFkbyBwb3IgbG9zIGVsZW1lbnRvcyBkZWwgdmVjdG9yIHJlZmVyaWRvIHF1ZSBjb3JyZXNwb25kZW4gYSBlc3RvcyA/bmRpY2VzIHkgZW4NCmVsIG9yZGVuIGVuIHF1ZSBhcGFyZWNlbiBlbiBlbCB2ZWN0b3IgZGUgP25kaWNlcy4gRWwgdmVjdG9yIGRlID9uZGljZXMgcHVlZGUgdGVuZXINCmN1YWxxdWllciBsb25naXR1ZCB5IGVsIHJlc3VsdGFkbyBzZXI/IGRlIGVzYSBtaXNtYSBsb25naXR1ZC4gUG9yIGVqZW1wbG8sIHhbNl0gZXMgZWwNCnNleHRvIGVsZW1lbnRvIGRlIHgsIHkNCmBgYHtyfQ0KeFsxOjEwXQ0KeFs2XQ0KYGBgDQogDQogDQoNCmVzIGVsIHZlY3RvciBmb3JtYWRvIHBvciBsb3MgZGlleiBwcmltZXJvcyBlbGVtZW50b3MgZGUgeCwgKHN1cHVlc3RvIHF1ZSBsZW5ndGgoeCkgbm8NCmVzIG1lbm9yIHF1ZSAxMCkuIFBvciBvdHJhIHBhcnRlLA0KYGBge3J9DQpjKCJ4IiwieSIpW3JlcChjKDEsMiwyLDEpLCB0aW1lcz00KV0NCmBgYA0KIA0KY3JlYSB1biB2ZWN0b3IgZGUgY2FyYWN0ZXJlcyBkZSBsb25naXR1ZCAxNiBmb3JtYWRvIHBvciAieCIsICJ5IiwgInkiLCAieCIgcmVwZXRpZG8NCmN1YXRybyB2ZWNlcy4NCg0KMy4gVW4gdmVjdG9yIGRlIG4/bWVyb3MgbmF0dXJhbGVzIG5lZ2F0aXZvcy4gRW4gZXN0ZSBjYXNvLCBsb3MgP25kaWNlcyBpbmRpY2FuIGxvcyBlbGVtZW50b3MNCmRlbCB2ZWN0b3IgcmVmZXJpZG8gcXVlIGRlYmVuIGV4Y2x1aXJzZS4gDQoNCg0KDQoNCmBgYHtyfQ0KeSA8LSB4Wy0oMTo1KV0NCnkNCmBgYA0KIA0KYWxtYWNlbmEgZW4gZWwgdmVjdG9yIHkgdG9kb3MgbG9zIGVsZW1lbnRvcyBkZSB4IGV4Y2VwdG8gbG9zIGNpbmNvIHByaW1lcm9zIChzdXBvbmllbmRvDQpxdWUgeCB0aWVuZSBhbCBtZW5vcyBjaW5jbyBlbGVtZW50b3MpLg0KDQoNCjQuIFVuIHZlY3RvciBkZSBjYXJhY3RlcmVzLiBFc3RhIG9wY2k/biBzb2xvIHB1ZWRlIHJlYWxpemFyc2Ugc2kgZWwgdmVjdG9yIHBvc2VlIGVsIGF0cmlidXRvDQpuYW1lcyAobm9tYnJlcykgcGFyYSBpZGVudGlmaWNhciBzdXMgY29tcG9uZW50ZXMsIGVuIGN1eW8gY2FzbyBzZSBjb21wb3J0YXI/IGRlIG1vZG8NCnNpbWlsYXIgYWwgcHVudG8gMi4NCmBgYHtyfQ0KIGZydXRhIDwtIGMoNSwgMTAsIDEsIDIwKQ0KIG5hbWVzKGZydXRhKSA8LSBjKCJuYXJhbmphIiwgInBsP3Rhbm8iLCAibWFuemFuYSIsICJwZXJhIikNCiBwb3N0cmUgPC0gZnJ1dGFbYygibWFuemFuYSIsIm5hcmFuamEiKV0NCiBmcnV0YQ0KIHBvc3RyZQ0KYGBgDQoNCkxhIHZlbnRhamEgZW4gZXN0ZSBjYXNvIGVzIHF1ZSBsb3Mgbm9tYnJlcyBzb24gYSBtZW51ZG8gbT9zIGY/Y2lsZXMgZGUgcmVjb3JkYXIgcXVlDQpsb3MgP25kaWNlcyBudW0/cmljb3MuDQoNCkxhIHZhcmlhYmxlIGRlIGFsbWFjZW5hbWllbnRvIHRhbWJpP24gcHVlZGUgc2VyIGluZGV4YWRhLCBlbiBjdXlvIGNhc28gbGEgYXNpZ25hY2k/bg0Kc2UgcmVhbGl6YSBzb2xhbWVudGUgc29icmUgbG9zIGVsZW1lbnRvcyByZWZlcmlkb3MuIExhIGV4cHJlc2k/biBkZWJlIHNlciBkZSBsYSBmb3JtYQ0KdmVjdG9yW3ZlY3RvciBkZSA/bmRpY2VzXSB5YSBxdWUgbGEgdXRpbGl6YWNpP24gZGUgdW5hIGV4cHJlc2k/biBhcmJpdHJhcmlhIGVuIHZleiBkZWwgbm9tYnJlDQpkZSB1biB2ZWN0b3Igbm8gdGllbmUgbXVjaG8gc2VudGlkby4NCkVsIHZlY3RvciBhc2lnbmFkbyBkZWJlIHNlciBkZSBsYSBtaXNtYSBsb25naXR1ZCBxdWUgZWwgdmVjdG9yIGRlID9uZGljZXMgeSwgZW4gZWwgY2Fzbw0KZGUgdW4gdmVjdG9yIGRlID9uZGljZXMgbD9naWNvLCBkZWJlIHNlciBkZSBsYSBtaXNtYSBsb25naXR1ZCBkZWwgdmVjdG9yIHF1ZSBpbmRleGEuIFBvcg0KZWplbXBsbywNCg0KYGBge3J9DQp4W2lzLm5hKHgpXSA8LSAwDQp4DQpgYGANCiANCnN1c3RpdHV5ZSBjYWRhIHZhbG9yIGZhbHRhbnRlIGRlIHggcG9yIHVuIGNlcm8uIFBvciBvdHJhIHBhcnRlLA0KDQpgYGB7cn0NCnk8LW5hLm9taXQoeSkNCnlbeSA8IDBdIDwtIC15W3kgPCAwXQ0KeQ0KYGBgDQoNCmVxdWl2YWxlIGENCmBgYHtyfQ0KeSA8LSBhYnMoeSkNCnkNCmBgYA0KIA0KIA0KI0ZhY3RvcmVzIE5vbWluYWxlcyB5IE9yZGluYWxlcw0KIA0KIFVuIGZhY3RvciBlcyB1biB2ZWN0b3IgdXRpbGl6YWRvIHBhcmEgZXNwZWNpZmljYXIgdW5hIGNsYXNpZmljYWNpP24gZGlzY3JldGEgZGUgbG9zIGVsZW1lbnRvcw0KZGUgb3RybyB2ZWN0b3IgZGUgaWd1YWwgbG9uZ2l0dWQuIEVuIFIgZXhpc3RlbiBmYWN0b3JlcyBub21pbmFsZXMgeSBmYWN0b3JlcyBvcmRpbmFsZXMuDQoNClN1cG9uZ2EgcXVlIGRpc3BvbmUgZGUgdW5hIG11ZXN0cmEgZGUgMzAgcGVyc29uYXMgZGUgQXVzdHJhbGlhIGRlIHRhbCBtb2RvIHF1ZSBzdQ0KZXN0YWRvIG8gdGVycml0b3JpbyBzZSBlc3BlY2lmaWNhIG1lZGlhbnRlIHVuIHZlY3RvciBkZSBjYXJhY3RlcmVzIGNvbiBsYXMgYWJyZXZpYXR1cmFzIGRlIGxvcw0KbWlzbW9zXltQYXJhIHF1aWVuZXMgbm8gY29ub2NlbiBsYSBlc3RydWN0dXJhIGFkbWluaXN0cmF0aXZhIGRlIEF1c3RyYWxpYSwgZXhpc3RlbiBvY2hvIGVzdGFkb3MgeSB0ZXJyaXRvcmlvcw0KZW4gbGEgbWlzbWE6IEF1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRvcnksIE5ldyBTb3V0aCBXYWxlcywgTm9ydGhlcm4gVGVycml0b3J5LCBRdWVlbnNsYW5kLCBTb3V0aA0KQXVzdHJhbGlhLCBUYXNtYW5pYSwgVmljdG9yaWEsIHkgV2VzdGVybiBBdXN0cmFsaWE7IHkgc3VzIGNvcnJlc3BvbmRpZW50ZXMgYWJyZXZpYXR1cmFzIHNvbjogYWN0LCBuc3csDQpudCwgcWxkLCBzYSwgdGFzLCB2aWMsIHkgd2EuXToNCg0KDQpgYGB7cn0NCmVzdGFkbyA8LSBjKCJ0YXMiLCAic2EiLCAicWxkIiwgIm5zdyIsICJuc3ciLCAibnQiLCAid2EiLCAid2EiLA0KInFsZCIsICJ2aWMiLCAibnN3IiwgInZpYyIsICJxbGQiLCAicWxkIiwgInNhIiwgInRhcyIsDQoic2EiLCAibnQiLCAid2EiLCAidmljIiwgInFsZCIsICJuc3ciLCAibnN3IiwgIndhIiwNCiJzYSIsICJhY3QiLCAibnN3IiwgInZpYyIsICJ2aWMiLCAiYWN0IikNCmBgYA0KDQpSZWN1ZXJkZSBxdWUsIHBhcmEgdW4gdmVjdG9yIGRlIGNhcmFjdGVyZXMsIGxhIHBhbGFicmEgIm9yZGVuYWRvIiBpbmRpY2EgcXVlIGVzdD8gZW4NCm9yZGVuIGFsZmFiP3RpY28uDQpVbiBmYWN0b3Igc2UgY3JlYSB1dGlsaXphbmRvIGxhIGZ1bmNpP24gZmFjdG9yKCk6DQpgYGB7cn0NCkZhY3RvckVzdGFkbyA8LSBmYWN0b3IoZXN0YWRvKQ0KRmFjdG9yRXN0YWRvDQpgYGANCg0KUHVlZGUgdXRpbGl6YXIgbGEgZnVuY2k/biBsZXZlbHMoKSBwYXJhIHZlciBsb3Mgbml2ZWxlcyBkZSB1biBmYWN0b3I6DQpgYGB7cn0NCmxldmVscyhGYWN0b3JFc3RhZG8pDQpgYGANCg0KQWhvcmEsIHN1cG9uZ2EgcXVlIGRpc3BvbmVtb3MgZW4gb3RybyB2ZWN0b3IgZGUgbG9zDQppbmdyZXNvcyBkZSBsYXMgbWlzbWFzIHBlcnNvbmFzIChtZWRpZG9zIGNvbiB1bmFzIHVuaWRhZGVzIGFwcm9waWFkYXMpDQpgYGB7cn0NCmluZ3Jlc29zIDwtIGMoNjAsIDQ5LCA0MCwgNjEsIDY0LCA2MCwgNTksIDU0LCA2MiwgNjksIDcwLCA0MiwgNTYsDQo2MSwgNjEsIDYxLCA1OCwgNTEsIDQ4LCA2NSwgNDksIDQ5LCA0MSwgNDgsIDUyLCA0NiwNCjU5LCA0NiwgNTgsIDQzKQ0KYGBgDQoNClBhcmEgY2FsY3VsYXIgbGEgbWVkaWEgbXVlc3RyYWwgcGFyYSBjYWRhIGVzdGFkbyBwb2RlbW9zIHVzYXIgbGEgZnVuY2k/biB0YXBwbHkoKSBxdWUgZGV2dWVsdmUgZWwgdmVjdG9yIGRlIG1lZGlhcyBjb24gbGFzIGNvbXBvbmVudGVzIGV0aXF1ZXRhZGFzIGNvbiBsb3Mgbml2ZWxlczoNCmBgYHtyfQ0KTWVkaWFJbmdyZXNvcyA8LSB0YXBwbHkoaW5ncmVzb3MsIEZhY3RvckVzdGFkbywgbWVhbikNCk1lZGlhSW5ncmVzb3MNCmBgYA0KDQoNCkxhIGZ1bmNpP24gdGFwcGx5KCkgYXBsaWNhIHVuYSBmdW5jaT9uLCBlbiBlc3RlIGVqZW1wbG8gbGEgZnVuY2k/biBtZWFuKCksIGEgY2FkYSBncnVwbyBkZSBjb21wb25lbnRlcyBkZWwgcHJpbWVyIGFyZ3VtZW50bywgZW4gZXN0ZSBlamVtcGxvIGluZ3Jlc29zLCBkZWZpbmlkb3MgcG9yIGxvcyBuaXZlbGVzIGRlbCBzZWd1bmRvIGFyZ3VtZW50bywgZW4gZXN0ZSBlamVtcGxvIEZhY3RvckVzdGFkbywgY29tbyBzaSBjYWRhIGdydXBvIGZ1ZXNlIHVuIHZlY3RvciBwb3Igcz8gc29sby4gRWwgcmVzdWx0YWRvIGVzIHVuYSBlc3RydWN0dXJhIGN1eWEgbG9uZ2l0dWQgZXMgZWwgbj9tZXJvIGRlIG5pdmVsZXMgZGVsIGZhY3Rvci4gUHVlZGUgY29uc3VsdGFyIGxhIGF5dWRhIHBhcmEgb2J0ZW5lciBtP3MgZGV0YWxsZXMuIFN1cG9uZ2EgcXVlIGFob3JhIGRlc2VhIGNhbGN1bGFyIGxhcyBkZXN2aWFjaW9uZXMgdD9waWNhcyBkZSBsYXMgbWVkaWFzIGRlIGluZ3Jlc29zIHBvciBlc3RhZG9zLiBQYXJhIGVsbG8gZXMgbmVjZXNhcmlvIGVzY3JpYmlyIHVuYSBmdW5jaT9uIGVuIFIgcXVlIGNhbGN1bGUgbGEgZGVzdmlhY2k/biB0P3BpY2EgZGUgdW4gdmVjdG9yLiBBdW5xdWUgYT9uIG5vIHNlIGhhIGV4cGxpY2FkbyBlbiBlc3RlIHRleHRvIGM/bW8gZXNjcmliaXIgZnVuY2lvbmVzLCBwdWVkZSBhZG1pdGlyIHF1ZSBleGlzdGUgbGEgZnVuY2k/biB2YXIoKSBxdWUgY2FsY3VsYSBsYSB2YXJpYW56YSBtdWVzdHJhbCBvIGN1YXNpLXZhcmlhbnphLCB5IHF1ZSBsYSBmdW5jaT9uIGJ1c2NhZGEgcHVlZGUgY29uc3RydWlyc2UgY29uIGxhIGFzaWduYWNpP246DQpgYGB7cn0NClN0ZEVyciA8LSBmdW5jdGlvbih4KSBzcXJ0KHZhcih4KS9sZW5ndGgoeCkpDQpgYGANCg0KQWhvcmEgcHVlZGUgY2FsY3VsYXIgbG9zIHZhbG9yZXMgYnVzY2Fkb3MgbWVkaWFudGUgZGljaGEgZnVuY2k/biBjb24gZWwgc2lndWllbnRlIHJlc3VsdGFkbzoNCg0KYGBge3J9DQpFcnJvclRpcGljb0luZ3Jlc29zIDwtIHRhcHBseShpbmdyZXNvcywgRmFjdG9yRXN0YWRvLCBTdGRFcnIpDQpFcnJvclRpcGljb0luZ3Jlc29zDQpgYGANCg0KDQpMYSBmdW5jaT9uIHRhcHBseSgpIHB1ZWRlIHV0aWxpemFyc2UgcGFyYSBhcGxpY2FyIHVuYSBmdW5jaT9uIGEgdW4gdmVjdG9yIGluZGV4YWRvIHBvciBkaWZlcmVudGVzIGNhdGVnb3I/YXMgc2ltdWx0P25lYW1lbnRlLiBQb3IgZWplbXBsbywgcGFyYSBkaXZpZGlyIGxhIG11ZXN0cmEgdGFudG8gcG9yIGVsIGVzdGFkbyBjb21vIHBvciBlbCBzZXhvLiBMb3MgZWxlbWVudG9zIGRlbCB2ZWN0b3Igc2UgZGl2aWRpcj9uIGVuIGdydXBvcyBjb3JyZXNwb25kaWVudGVzIGEgbGFzIGRpc3RpbnRhcyBjYXRlZ29yP2FzIHkgc2UgYXBsaWNhcj8gbGEgZnVuY2k/biBhIGNhZGEgdW5vIGRlIGRpY2hvcyBncnVwb3MuIEVsIHJlc3VsdGFkbyBlcyB1bmEgdmFyaWFibGUgaW5kZXhhZGEgZXRpcXVldGFkYSBjb24gbG9zIG5pdmVsZXMgZGUgY2FkYSBjYXRlZ29yP2EuDQoNCg0KI01hdHJpY2VzDQoNClIgcG9zZWUgZmFjaWxpZGFkZXMgcGFyYSBtYW5pcHVsYXIgeSBoYWNlciBvcGVyYWNpb25lcyBjb24gbWF0cmljZXMuIExhcyBmdW5jaW9uZXMgcmJpbmQoKQ0KeSBjYmluZCgpIHVuZW4gbWF0cmljZXMgY29uIHJlc3BlY3RvIGEgc3VzIGZpbGFzIG8gY29sdW1uYXMgcmVzcGVjdGl2YW1lbnRlOg0KDQpgYGB7cn0NCm0xIDwtIG1hdHJpeCgxLCBuciA9IDIsIG5jID0gMikNCm0yIDwtIG1hdHJpeCgyLCBuciA9IDIsIG5jID0gMikNCg0KYGBgDQoNCmBgYHtyfQ0KcmJpbmQobTEsIG0yKQ0KDQpgYGANCg0KLS0tDQoNCmBgYHtyfQ0KY2JpbmQobTEsIG0yKQ0KYGBgDQoNCg0KDQpFbCBvcGVyYWRvciBwYXJhIGVsIHByb2R1Y3RvIGRlIGRvcyBtYXRyaWNlcyBlcyAnJSolJy4gUG9yIGVqZW1wbG8sIGNvbnNpZGVyYW5kbyBsYXMgZG9zDQptYXRyaWNlcyBtMSB5IG0yOg0KDQoNCmBgYHtyfQ0KcmJpbmQobTEsIG0yKSAlKiUgY2JpbmQobTEsIG0yKQ0KDQpgYGANCg0KLS0tDQoNCmBgYHtyfQ0KY2JpbmQobTEsIG0yKSAlKiUgcmJpbmQobTEsIG0yKQ0KYGBgDQoNCkxhIHRyYW5zcG9zaWNpb24gZGUgdW5hIG1hdHJpeiBzZSByZWFsaXphIGNvbiBsYSBmdW5jaT9uICJ0IjsgZXN0YSBmdW5jaW9uIHRhbWJpP24gZnVuY2lvbmEgY29uIG1hcmNvcyBkZSBkYXRvcy4NCg0KYGBge3J9DQp0KGNiaW5kKG0xLCBtMikgJSolIHJiaW5kKG0xLCBtMikpDQpgYGANCg0KTGEgZnVuY2k/biBkaWFnIHNlIHB1ZWRlIHVzYXIgcGFyYSBleHRyYWVyIG8gbW9kaWZpY2FyIGxhIGRpYWdvbmFsIGRlIHVuYSBtYXRyaXogbyBwYXJhDQpjb25zdHJ1aXIgdW5hIG1hdHJpeiBkaWFnb25hbDoNCg0KLS0tDQoNCmBgYHtyfQ0KZGlhZyhtMSkNCmBgYA0KDQpgYGB7cn0NCmRpYWcocmJpbmQobTEsIG0yKSAlKiUgY2JpbmQobTEsIG0yKSkNCg0KZGlhZyhtMSkgPC0gMTANCm0xDQpkaWFnKDMpDQp2IDwtIGMoMTAsIDIwLCAzMCkNCmRpYWcodikNCmRpYWcoMi4xLCBuciA9IDMsIG5jID0gNSkNCmBgYA0KDQojI0FycmF5cw0KYGBge3J9DQp6CTwtCWFycmF5KDE6MjQsCWRpbT1jKDIsMyw0KSkJDQp6CQ0KZGltKHopDQpgYGANCg0KRWxlbWVudG9zOg0KYGBge3J9DQp4CTwtCW1hdHJpeCgxOjEyLAlucm93PTMsCW5jb2w9NCkJCQ0KeFsxLF0JCQkJCSMJZmlsYQlpCQkJCQkJCQkJCQkJDQp4WywyXQkJCQkJIwljb2x1bW5hCWoJDQp4WzMsNF0JCQkJIwllbGVtZW50bwlpLGoNCmBgYA0KDQoNCiNHZW5lcmNpP24gZGUgbj9tZXJvcyBhbGVhdG9yaW9zDQoNClIgdGllbmUgc3UgcHJvcGlvIG1lY2FuaXNtbyBwYXJhIGdlbmVyYXIgbj9tZXJvcyBhbGVhdG9yaW9zLCBlbiBwYXJ0aWN1bGFyLCBwdWVkZSBnZW5lcmFyIG4/bWVybyBhbGVhdG9yaW9zIHByb3ZlbmllbnRlcyBkZSBsYXMgcHJpbmljaXBhbGVzIGZhbWlsaWFzIGRlIHZhcmlhYmxlcyBhbGVhdG9yaWFzIHV0aWxpemFuZG8gbGFzIHNpZ3VpZW50ZXMgZnVuY2lvbmVzOg0KDQp8IERpc3RyaWJ1Y2k/biAgICB8IENvbWFuZG8gZW4gUiAgICAgICAgICAgICAgICAgIHwgICB8ICAgfCAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLXwtLS18LS0tfA0KfCB1bmlmb3JtZSAgICAgICAgfCBydW5pZihuLG1pbj0wLG1heD0xKSAgICAgICAgICB8ICAgfCAgIHwgICB8DQp8IE5vcm1hbCAgICAgICAgICB8IHJub3JtKG4sbWVhbj0wLHNkPTEpICAgICAgICAgIHwgICB8ICAgfCAgIHwNCnwgZXhwb25lbmNpYWwgICAgIHwgcmV4cChuLHJhdGU9MSkgICAgICAgICAgICAgICAgfCAgIHwgICB8ICAgfA0KfCBnYW1tYSAgICAgICAgICAgfCByZ2FtbWEobixzaGFwZSxzY2FsZT0xKSAgICAgICB8ICAgfCAgIHwgICB8DQp8IFBvaXNzb24gICAgICAgICB8IHJwb2lzKG4sbGFtYmRhKSAgICAgICAgICAgICAgIHwgICB8ICAgfCAgIHwNCnwgYmlub21pYWwgICAgICAgIHwgcmJpbm9tKG4sc2l6ZSxwcm9iKSAgICAgICAgICAgfCAgIHwgICB8ICAgfA0KfCBnZW9tZXRyaWNhICAgICAgfCByZ2VvbShuLHByb2IpICAgICAgICAgICAgICAgICB8ICAgfCAgIHwgICB8DQp8IGJpbm9taWFsICAgICAgICB8IHJuYmlub20obixzaXplLHByb2IpICAgICAgICAgIHwgICB8ICAgfCAgIHwNCg0KLS0tDQoNCkxhIHBvc2liaWxpZGFkIGRlIGdlbmVyYXIgZGF0b3MgYWxlYXRvcmlvcyBlcyBiYXN0YW50ZSB1dGlsIGVuIGVzdGFkID9zdGljYSB5IFIgdGllbmUgbGEgY2FwYWNpZGFkIA0KZGUgaGFjZXIgZXN0byBwYXJhIHVuIGdyYW4gbnVtZXJvIGRlIGZ1bmNpb25lcyB5IGRpc3RyaWJ1Y2lvbmVzLiBFc3RhcyBmdW5jaW9uZXMgc29uIGRlIGxhIGZvcm1hIA0KcmZ1bmMobiwgcDEsIHAyLCAuLi4pLCBkb25kZSBmdW5jIGluZGljYSBsYSBkaXNyaWJ1Y2lvbiwgbiBlcyBlbCBudW1lcm8gZGUgZGF0b3MgZ2UtIA0KbmVyYWRvLCB5IHAxLCBwMiwgLiAuIC4gc29uIHZhbG9yZXMgcXVlIHRvbWFuIGxvcyBwYXJhbWV0cm9zIGRlIGxhIGRpc3RyaWJ1Y2kgP24uIExhIHRhYmxhIGFudGVyaW9yIA0KbXVlc3RyYSBsb3MgZGV0YWxsZXMgZGUgY2FkYSBkaXN0cmlidWNpb24sIHkgbG9zIHBvc2libGVzIHZhbG9yZXMgcG9yIGRlZmVjdG8gZGUgbG9zIHBhciA/bWV0cm9zIChzaSANCm5vIHNlIGluZGljYSwgc2lnbmlmaWNhIHF1ZSBlbCBwYXJhbWV0cm8gZGViZSBzZXIgZXNwZWNpZmljYWRvIHBvciBlbCB1c3VhcmlvKS4gDQpUb2RhcyBlc3RhcyBmdW5jaW9uZXMgc2UgcHVlZGVuIHVzYXIgcmVlbXBsYXphbmRvIGxhIGxldHJhIHIgY29uIGxhcyBsZXRyYXMgZCwgcCBvIHEgcGFyYQ0Kb2J0ZW5lciwgbGEgZGVuc2lkYWQgZGUgcHJvYmFiaWxpZGFkIChkZnVuYyh4LCAuLi4pKSwgbGEgZGVuc2lkYWQgZGUgcHJvYmFiaWxpZGFkIGFjdW11bGFkYQ0KKHBmdW5jKHgsIC4uLikpLCB5IGVsIHZhbG9yIGRlbCBjdWFydGlsIChxZnVuYyhwLCAuLi4pLCBjb24gMCA8IHAgPCAxKSByZXNwZWN0aXZhbWVudGUuDQoNClZlcmVtb3MgbGEgYXBsaWNhY2k/biBkZSBkaWNoYXMgZnVuY2lvbmVzIGVuIGxhIHNpZ3VpZW50ZSBzZWNjaT9uLCBjb24gZWwgZmluIGRlIGVqZW1wbGlmaWNhciBlbCBtP3RvZG8gcGFyYSBncmFmaWNhciBkYXRvcyBlbiBSLg0KDQojR3I/Zmljb3MgZW4gUg0KDQpSIG9mcmVjZSB1bmEgaW5jcmVpYmxlIHZhcmllZGFkIGRlIGdyYWZpY29zLiBQYXJhIGRhcnNlIHVuYSBpZGVhLCBlc2NyaWJhIGVsIGNvbWFuZG8gZGVtbyhncmFwaGljcykuDQpObyBub3MgZXMgcG9zaWJsZSBkZXRhbGxhciBhcXVpIHRvZGFzIGxhcyBwb3NpYmlsaWRhZGVzIGRlIFIgZW4gdGVybWlub3MgZGUgZ2VuZXJhY2k/biBkZSBncj9maWNhcy4gDQpDYWRhIGZ1bmNpb24gZ3IgP2ZpY2EgZW4gUiB0aWVuZSB1biBlbm9ybWUgbj9tZXJvIGRlIG9wY2lvbmVzIHBlcm1pdGllbmRvIHVuYSBncmFuIGZsZXhpYmlsaWRhZCANCmVuIGxhIHByb2R1Y2Npb24gZGUgZ3IgP2ZpY29zIHkgZWwgdXNvIGRlIGN1YWxxdWllciBvdHJvIHBhcXVldGUgZ3I/ZmljbyBwYWxpZGVjZSBlbiBjb21wYXJhY2kgP24uIA0KRWwgbW9kdXMgb3BlcmFuZGkgZGUgbGFzIGZ1bmNpb25lcyBncmFmaWNhcyBlcyBzdXN0YW5jaWFsbWVudGUgZGlmZXJlbnRlIGRlbCBlc3F1ZW1hIGVzYm96YWRvIGFsIHByaW5jaXBpbyBkZSBlc3RlIGRvY3VtZW50by4gUGFydGljdWxhcm1lbnRlLCBlbCByZXN1bHRhZG8gZGUgdW5hIGZ1bmNpb24gZ3IgP2ZpY2Egbm8gcHVlZGUgDQpzZXIgYXNpZ25hZG8gYSB1biBvYmpldG8xMSBzaW5vIHF1ZSBlcyBlbnZpYWRvIGEgdW4gZGlzcG9zaXRpdm8gZ3JhZmljbyAuIFVuIGRpc3Bvc2l0aXZvIGdyYWZpY28gZXMgDQp1bmEgdmVudGFuYSBncmFmaWNhIG8gdW4gYXJjaGl2by4gDQpFeGlzdGVuIGRvcyB0aXBvcyBkZSBmdW5jaW9uZXMgZ3JhZmljYXM6IGxhcyBmdW5jaW9uZXMgZGUgZ3JhZmljYWNpb24gZGUgYWx0byBuaXZlbCBxdWUgY3JlYW4NCnVuYSBudWV2YSBncmFmaWNhIHkgbGFzIGZ1bmNpb25lcyBkZSBncmFmaWNhY2lvbiBkZSBiYWpvIG5pdmVsIHF1ZSBhZ3JlZ2FuIGVsZW1lbnRvcyBhIHVuYSBncmFmaWNhIA0KeWEgZXhpc3RlbnRlLiBMYXMgZ3JhZmljYXMgc2UgcHJvZHVjZW4gY29uIHJlc3BlY3RvIGEgcGFyYW1ldHJvcyBnciA/Zmljb3MgcXVlIGVzdGFuIGRlZmluaWRvcyBwb3IgDQpkZWZlY3RvIHkgcHVlZGVuIHNlciBtb2RpZmljYWRvcyBjb24gbGEgZnVuY2lvbj8gcGFyLg0KUHJpbWVybyB2ZXJlbW9zIGNvbW8gbWFuZWphciBncmFmaWNvcyB5IGRpc3Bvc2l0aXZvcyBnciA/Zmljb3M7IGRlc3B1P3MgdmVyZW1vcyBlbiBkZXRhbGxlIA0KYWxndW5hcyBmdW5jaW9uZXMgZ3JhZmljYXMgeSBzdXMgcGFyID9tZXRyb3MuIFZlcmVtb3MgZWplbXBsb3MgcHIgP2N0aWNvcyBkZWwgdXNvIGRlIGVzdGFzIGZ1bi0gDQpjaW9uYWxpZGFkZXMgZW4gbGEgcHJvZHVjY2lvbiBkZSBnciA/Zmljb3MuIEZpbmFsbWVudGUsIHZlcmVtb3MgbG9zIHBhcXVldGVzIGdyaWQgeSBsYXR0aWNlIGN1eW8NCmZ1bmNpb25hbWllbnRvIGVzIGRpZmVyZW50ZSBhIGxhcyBmdW5jaW9uZXMgZ3JhZmljYXMgJ25vcm1hbGVzJyBkZSBSLg0KDQoNClBhcmEgaWx1c3RyYXIgYWxndW5hcyBkZSBsYXMgZnVuY2lvbmFsaWRhZGVzIGdyYWZpY2FzIGRlIFIsIGNvbnNpZGVyZW1vcyB1biBlamVtcGxvIHNpbXBsZSBkZSANCnVuYSBncj9maWNhIGJpdmFyaWFkYSBjb24gMTAgcGFyZXMgZGUgY29vcmRlbmFkYXMgZ2VuZXJhZGFzIGFsIGF6YXIuID9zdG9zIHZhbG9yZXMgc2UgZ2VuZXJhcm9uIA0KY29uOg0KDQpgYGB7cn0NCnggPC0gcm5vcm0oMTAwKQ0KeSA8LSBybm9ybSgxMDApDQpgYGANCg0KTGEgZ3JhZmljYSBxdWUgcXVlcmVtb3MgdmlzdWFsaXphciBzZSBwdWVkZSBvYnRlbmVyIGNvbiBwbG90KCk7IHNpbXBsZW1lbnRlIHNlIGVzY3JpYmUgZWwgY29tYW5kbzoNCg0KYGBge3J9DQpoaXN0KHgpDQpgYGANCg0KYGBge3J9DQpwbG90KHgsdHlwZT0ibCIpDQpgYGANCg0KDQpgYGB7cn0NCnBsb3QoeCwgeSkNCmBgYA0KDQp5IGxhIGdyYWZpY2Egc2VyPyB2aXNpYmxlIGVuIGVsIGRpc3Bvc2l0aXZvIGdyP2ZpY28gYWN0aXZvLiBQb3INCmRlZmVjdG8sIFIgZGlidWphIGdyYWZpY2FzIGRlIHVuYSBtYW5lcmEgImludGVsaWdlbnRlIjogbG9zIGVzcGFjaW9zIGVudHJlIGxvcyBtYXJjYWRvcmVzIGRlIGxvcw0KZWplcywgbGEgdWJpY2FjaW9uIGRlIGxhcyBldGlxdWV0YXMgZW4gbG9zIGVqZXMsIGV0Yywgc29uIGNhbGN1bGFkb3MgYXV0b20/dGljYW1lbnRlIGRlIHRhbCBtYW5lcmENCnF1ZSBsYSBncmFmaWNhIHJlc3VsdGFudGUgc2VhIGxvIG1hcyBsZWdpYmxlIHBvc2libGUuDQpTaW4gZW1iYXJnbywgZWwgdXN1YXJpbyBwdWVkZSBjYW1iaWFyIGxhIG1hbmVyYSBjb21vIHNlIHByZXNlbnRhIGxhIGdyYWZpY2EsIHBvciBlamVtcGxvLA0KcGFyYSBhanVzdGFyc2UgYSB1biBlc3RpbG8gZWRpdG9yaWFsIHByZS1kZWZpbmlkbyBvIHBhcmEgZGFybGUgdW4gdG9xdWUgcGVyc29uYWwgcGFyYSB1bmEgY2hhcmxhLg0KDQojRnVuY2lvbmVzDQoNCk9iamV0b3MgcXVlIHB1ZWRlbiBzZXIgY3JlYWRvcyBwb3IgZWwgdXN1YXJpbyBwYXJhIGhhY2VyLCB5IHJlcGV0aXIsIG9wZXJhY2lvbmVzIGVzcGVjP2ZpY2FzDQoNCmBgYHtyIGV2YWw9RkFMU0V9DQpzdGRkZXYJPC0gZnVuY3Rpb24oeCkJewkJCQkJCQkJCQkJCQkJCQkJCQkJCQkNCgkJCXJlcwk9CXNxcnQoc3VtKCh4LW1lYW4oeCkpXjIpCS8JKGxlbmd0aCh4KS0xKSkJDQoJCQlyZXR1cm4ocmVzKQkNCgl9DQpgYGANCg0KU2UgcHVlZGVuIHVzYXIgeSBkZWZpbmlyIGZ1bmNpb25lcyBkZW50cm8gZGUgZnVuY2lvbmVzLg0KRWwgdmFsb3IgZGV2dWVsdG8gcG9yIHVuYSBmdW5jaT9uIGVzIGVsIHJlc3VsdGFkbyBkZSBsYSA/bHRpbWEgZXhwcmVzaT9uIGV2YWx1YWRhIG8gZWwNCmVzcGVjaWZpY2FkbyBjb24gZWwgY29tYW5kbyByZXR1cm4NCkxvcyBhcmd1bWVudG9zIGRlIGxhcyBmdW5jaW9uZXMgcHVlZGVuIGVzcGVjaWZpY2Fyc2UgcG9yIHN1IHBvc2ljaT9uIG8gcG9yIHN1IG5vbWJyZS4NClB1ZWRlIGhhYmVyIGFyZ3VtZW50b3MgY29uIHZhbG9yZXMgcG9yIGRlZmVjdG8uDQoNCiNGdW5jaW9uZXMgSXRlcmF0aXZhcw0KDQpSZWNvbWllbmRvIG5vIHV0aWxpemFyIGNpY2xvcyBlbiBSIChsZW50b3MpLg0KDQoqIGxhcHBseSAoY2FsY3VsYSB1bmEgZnVuY2k/biBwYXJhIHRvZG9zIGxvcw0KICBlbGVtZW50b3MgZGUgdW5hIGxpc3RhKQ0KICANCiogc2FwcGx5IChpZ3VhbCBwZXJvIHNpbXBsaWZpY2FuZG8gZWwgcmVzdWx0YWRvKQ0KDQoqIGFwcGx5IChjYWxjdWxhIHVuYSBmdW5jaT9uIHBhcmEgcGFydGUsDQogIGNvbHVtbmFzIG8gZmlsYXMsIGRlIHVuYSBtYXRyaXopDQogIA0KKiB0YXBwbHkgKGNhbGN1bGEgdW5hIGZ1bmNpP24gcGFyYSB1bg0KICBzdWJjb25qdW50byBkZSB1biB2ZWN0b3I7IGVqLiB1c2FuZG8gdW4gZmFjdG9yKQ0KDQotLS0NCg0KYGBge3J9DQphCTwtCW1hdHJpeCgxOjEyLAlucm93PTMsCW5jb2w9NCkJCQkJCQkJCQkJCQkNCmEJDQpiCTwtCW1hdHJpeCgxOjEyLGJ5cm93PVRSVUUsCW5yb3c9MywJbmNvbD00KQkJCQkJCQkJCQkJCQ0KYg0KDQphcHBseShhLDEsbWVhbikJCSMJbWVkaWFzCXBvcglmaWxhcwkoIjEiKQ0Kcm93TWVhbnMoYSkJDQpgYGANCg0KLS0tDQoNCmBgYHtyfQ0KYXBwbHkoYSwxLHN1bSkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJDQpyb3dTdW1zKGEpCQ0KYXBwbHkoYSwyLG1lYW4pIwltZWRpYXMJcG9yCWNvbHVtbmFzCSgiMiIpCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJDQphcHBseShhLDIsc3VtKQkJCQ0KYGBg