1 Primi comandi di R

1.1 Operazioni Aritmetiche

Come abbiamo già visto è possibile usare R per svolgere operazioni matematiche, usando i simboli standard.

Ad esempio, l’uso di + più tra due numeri farà comparire la loro somma. In modo analogo è possibile farne la differenza (-), il prodotto (*) e la divisione(/).

2+2 
[1] 4
2-2
[1] 0
2*2
[1] 4
2/2
[1] 1

Le potenze si possono esprimere usando il simbolo ^. Lo stesso simbolo si può utilizzare per il calcolo delle radici, anche se è possibile richiamare la radice quadrata usando il comando sqrt(). Si noti che tale funzione accetta anche valori complessi.

Per la divisione intera tra due numeri è possibile usare il simbolo %/%, mentre %% restituisce il resto di tale divisione.

Un altro comando di base che può risultare utile è il calcolo del valore assoluto ottenuto con il comando abs().

In modo analogo sono già definite alcune delle funzioni che sono alla base dei calcoli matematici più frequenti. Le vedremo nei prossimi paragrafi.

1.2 Esponenziale e logaritmi

E’ possibile calcolare i valori della funzione esponenziale usando il comando exp() mentre per il calcolo dei logaritmi è possibile usare più funzioni: log(), log10() e log2() che restituiscono il logaritmo naturale, base 10 e base 2 rispettivamente. Il comando log() permette anche di specificare una base differente da e, che è quella di default. Ad esempio, log( 5 , base = 3) restituisce il logaritmo in base 3 di 5.

1.3 Funzioni Trigonometriche

Le principali funzioni trigonometriche sono già implementate in R e si possono richiamare usando i comandi elencati sotto, i cui nomi richiamano le funzioni stesse. Va notato che l’input di queste funzioni è atteso in radianti, non gradi.

sin() # seno
cos() # cosen
tan() # tangente

E’ possibile utilizzare le stesse funzioni ma con desinenza pi (sinpi(), cospi() e tanpi()) se si intende considerare dei multipli di pi-greco.

Anche le funzioni inverse sono già implementate e si possono richiamare con i comandi acos(), asin(), atan().

1.4 Assegnazione e vettori

Fin ora abbiamo usato R per calcolare dei singoli valori, in modo analogo a come avremmo usato una calcolatrice. Tuttavia R permette di fare molto di più.

Come primo passo per scoprirne le potenzialità vedremo la possibilità di assegnare valori e di richiamarli successivamente, così come di lavorare con vettori o matrici, invece che con singoli valori.

Questa parte, così come alcune successive sono anche coperte dalle utili dispense, di cui ho già consigliato la lettura.

E’ possibile assegnare un valore ad una variabile usando la freccina ->. Stesso risultato si può ottenere usando = oppure assign(), tuttavia il primo è decisamente il comando più usato e di più facile lettura. Qui è possibile leggere una discussione sulle differenze nell’uso di = o di ->.

x  <- 6

Usando il precedente comando viene assegnato il valore 6 alla variabile x. In questo modo è possibile richiamarla successivamente, così come è possibile scrivere espressioni più complesse che coinvolgono x a prescindere dal suo valore. Questo sarà particolarmente utile se dovremo definire delle funzioni a cui è possibile passare per argomento diversi valori. Si noti che il comando 6 -> x produce gli stessi risultati del precedente.

Oltre ad assegnare un singolo valore, è possibile considerati dei vettori. Il comando

y <- c(1,2,3,4)
y[1]
[1] 1

assegna a y i valori contenuti nel comando c(). Tale comando combina i valori in un vettore colonna (ma lo visualizza come una riga!). L’accesso ai vettori avviene attraverso indicandone il nome, seguito da parentesi quadre. Ovviamente è possibile svolgere operazioni aritmetiche anche tra vettori, usando la stessa sintassi vista prima. Di default R considera operazioni puntuali tra vettori, cioè l’operazione richiesta viene svolta entrata per entrata. Questo richiede le dimensioni siano le stesse. Qualora non lo fossero, il contenuto del vettore più piccolo viene ripetuto un numero di volte sufficienti da rendere possibile l’operazione. Questo viene anche segnalato da un warnign.

E’ possibile ottenere le dimensioni di un vettore usando il comando length().

Un comando utile tra vettori è t() che traspone il vettore passato per argomento.

z <- t(y)
y
[1] 1 2 3 4
print(z)
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
z
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4

Chiamare una variabile senza indicare operazioni ne permette la stampa a video. Inserendo l’assegnazione tra parentesi tonde si ottiene lo stesso risultato. Anche il comando print() permetta la stampa a video. Inoltre questo comando, diversamente dai precedenti, permette di mostrare l’output anche quando è chiamata dentro una funzione o uno script.

Dal comando precedente vediamo che y e z hanno stessi valori ma dimensioni diverse. Tuttavia R permette di svolgere operazioni matematiche su di essi senza warning o errori.

Per svolgere operazioni tra vettori, come il prodotto righe per colonne si può considerare il comando %*%. In questo caso il risultato dipende dall’ordine.

y %*% z
     [,1] [,2] [,3] [,4]
[1,]    1    2    3    4
[2,]    2    4    6    8
[3,]    3    6    9   12
[4,]    4    8   12   16
z %*% y
     [,1]
[1,]   30

1.5 Sequenze

Nel caso si debba indicare una successione di valori è possibile farlo senza indicarli espressamente tutti, purché essi siano una sequenza regolare.

Ad esempio con a:b possiamo usare i due punti per indicare una sequenza di valori con passo 1 da a fino a b . Per indicare un passo diverso possiamo usare il comando seq(a,b,passo) che produrrà una sequenza di elementi da a fino a b distanziati di un valore uguale al passo indicato. Se il passo viene omesso è considerato 1 di default.

Per tutte le funzioni è possibile accedere all’help di R usando il comando help(Nome_funzione). Leggendo l’help di seq() vediamo ad esempio che possiamo anche indicare in ordine diverso i parametri, a patto di specificarli usando il nome indicato nell’help. Ad esempio seq(to = b, by = passo, from = a) restituisce lo stesso output di seq(a,b,passo).

Inoltre è possibile ripetere un valore o un vettore usando il comando rep(), ad esempio rep(1,5) restituisce cinque volte il valore 1. Nel caso di un vettore, il comando ripeterà 5 volte il vettore.

1.6 Operazioni su vettori

Oltre alle operazioni che abbiamo già visto esistono altre funzioni di R appositamente pensate per i vettori. Ad esempio le funzioni min e max restituiscono, rispettivamente, il minimo ed il massimo valore contenuto in un vettore. Per accedere alla posizione di tali valori si combinano i precedenti comandi con which. Ad esempio

x <- c(3, 5, 7, 1, 3, 3, 9, 8)
min(x)
[1] 1
which.min(x)
[1] 4
max(x)
[1] 9
which.max(x)
[1] 7

Altre funzioni molto utili per lavorare con i vettori sono la funzione sum() che calcola la somma di tutti gli elementi di un vettore e la funzione diff() che calcola la differenza di un valore da uno dei precedenti (è possibile indicare quanto prima “guardare”).

sum(x)
[1] 39
diff(x)
[1]  2  2 -6  2  0  6 -1
diff(x,2)
[1]  4 -4 -4  2  6  5

1.7 Operatori relazionali e logici

R ci permette anche di valutare espressioni relazionali o logiche. Il loro risultato sarà un valore logico indicato con TRUE o FALSE.

6 > 10
[1] FALSE
6 <= 10
[1] TRUE
is_bigger <- 6> 10
is_bigger
[1] FALSE
as.integer(is_bigger)
[1] 0

R permette di valutare diverse espressioni relazionari, oltre a maggiore (uguale) o minore (uguale). Ad esempio è possibile valutare se due valori o variabili siano diversi != o uguali ==. Questo può essere particolarmente utile quando si definiscono delle funzioni proprie e si valuta se una condizione è soddisfatta.

R permette anche di valutare gli operatori logici & (and), | (or), xor e ! (not).

Questi operatori possono essere valutati sia su vettori logici, che di numeri qualsiasi. Nel secondo caso, tuttavia, tutto ciò che è diverso da zero conterà come TRUE, e solo lo 0 conterà come FALSE. Nel caso in cui si definiscano dei vettori misti (dove sono presenti sia valori logici che interi/reali/complessi), verranno tutti convertiti nel formato numerico presente.

1.8 Matrici

Come abbiamo visto i vettori sono considerati in generale vettori riga, e non è possibile generare una matrice usando il comando c().

Tuttavia le matrici esistono e si possono definire usando la funzione cbind() che unisce i vettori passati come argomento in una matrice dove i vettori argomento sono le colonne. La funzione rbind() ha la stessa funzione, ma i vettori passati come argomento saranno le righe della matrice. La funzione dim() restituisce le dimensioni dell’oggetto passato come argomento. La funzione length() (che avevamo visto con i vettori) ci restituisce il prodotto delle dimensioni.

a <- cbind(c(1, 2, 3), c(4, 5, 6))
dim(a)
[1] 3 2
b <- cbind(c(1, 2, 3), c(4, 5, 6))
dim(b)
[1] 3 2
a
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6
b
     [,1] [,2]
[1,]    1    4
[2,]    2    5
[3,]    3    6

E’ possibile variare la dimensione di un oggetto usando gli stessi comandi length e dim come assegnazioni.

dim(a) <- c(2,3)
a
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

Il comando precedente cambia la forma della matrice, secondo la forma indicata. Tali comandi vanno comunque usati con attenzione, visto che non si ha controllo su come il contenuto verrà ridistribuito.

Altra utile funzione per creare matrici è la funzione array() che chiede di specificare gli elementi della matrice e le dimensioni. Risultato analogo si può otenere con la funzione matrix(elementi, num righe, num colonne). Si noti che con array() è possibile definire strutture con più di due dimensioni.

Gli elementi una matrice si accedono usando le parentesi quadre, indicando la posizione dell’elemento.

a[2,3]
[1] 6

Se si intende selezionare un’intera riga o colonna, basta lasciare vuoto tale campo. Per esempio a[1,] restitusce l’intera prima riga. Il comando sum(), visto in precedenza funziona anche con matrici, restituendo la somma di tutte le entrate. Per ottenere la somma delle righe o delle colonne è possibile usare i comandi rowSum() o colSum(), rispettivamente. Anche i comandi min() e max() restituiscono il min/max tra tutte le entrate. Mentre gli stessi comandi con il which restituiscono l’indice contando per colonne gli elementi.

Alcune funzioni come contour(), persp(), image() permettono di ottenere dei grafici, partendo da matrici.

1.9 Stringhe (vettori di caratteri)

R permette di manipolare anche vettori di caratteri, o stringhe, che possono essere salvati anche come vettori. Le stringhe vengono delimitate da doppie virgolette " " (o anche semplici virgolette ' ').

nomi <- c("Francesco", "Sofia", "Alessandro")
nomi[1]
[1] "Francesco"
nomi_e_numeri <- c("Francesco", "Sofia", "Alessandro", 45)

In R non possono convivere nello stesso array caratteri e numeri. Se ad esempio nell’assegnazione indichiamo nomi e numeri, questi ultimi verranno convertiti in caratteri.

Una funzione molto utile per maneggiare stringhe, ma anche altri risultati, è la funzione paste() che concatena dei vettori dopo averli trasformati in stringhe.

paste(1:12) 
 [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12"
(nth <- paste0(1:12, c("st", "nd", "rd", rep("th", 9))))
 [1] "1st"  "2nd"  "3rd"  "4th"  "5th"  "6th"  "7th"  "8th"  "9th" 
[10] "10th" "11th" "12th"

Questa funzione può essere molto utile, ad esempio, se si devono creare vettori di nomi per delle variabili.

Per capire il tipo di dati contenuto in un vettore possiamo usare il comando typeof().

1.10 Liste e data frame

Possiamo pensare ad una matrice come ad un metodo efficace per immagazzinare informazioni numeriche, ed è così! Però se il tipo di informazioni che dobbiamo immagazzinare è misto, ad esempio contiene sia numeri che caratteri, la loro efficienza viene meno e si possono preferire altri metodi.

Una lista è un insieme ordinato di oggetti. Si possono definire liste usando il comando list().

c <- list(destinazione = c("London", "Madrid"), compagnia = c("Ryanair", "EasyJet"), costo = c(60, 80), valuta = c("£", "€") )

Si può accedere al contenuto di una lista sia per posizione con le doppie parentesi c[[2]] oppure per nome c[["compagnia"]] o c$compagnia. Tutti i precedenti comandi restituiscono il contenuto della lista definito da compagnia. Se vogliamo accedere direttamente ad un elemento possiamo usare indifferentemente i comandi c[[2]][2], c[["compagnia"]][2] o c$compagnia[2].

1.10.1 Data frame

Un’altra struttura dati che permette di immagazzinate dati di tipo misto sono i data frame. Questa struttura è di gran lunga la più usata per leggere e manipolare dati in R.

I data frame sono liste di tipo “data.frame” contenenti variabili con lo stesso numero di righe, il identificativo per la riga è univoco.

L3 <- LETTERS[1:3]
fac <- sample(L3, 10, replace = TRUE)
(d <- data.frame(x = 1, y = 1:10, fac = fac))
data.frame(1, 1:10, fac)
## The "same" with automatic column names:
data.frame(rep(1,10), 1:10, fac)
data.frame(1, 1:10, sample(L3, 10, replace = TRUE))

Inoltre è possibile riempire manualmente un dataframe attraverso il comando fix().

1.10.2 Tidy data, please!

A huge amount of effort is spent cleaning data to get it ready for analysis, but there has been little research on how to make data cleaning as easy and effective as possible. This paper tackles a small, but important, component of data cleaning: data tidying. Tidy datasets are easy to manipulate, model and visualize, and have a specific structure: each variable is a column, each observation is a row, and each type of observational unit is a table. This framework makes it easy to tidy messy datasets because only a small set of tools are needed to deal with a wide range of un-tidy datasets. This structure also makes it easier to develop tidy tools for data analysis, tools that both input and output tidy datasets. The advantages of a consistent data structure and matching tools are demonstrated with a case study free from mundane data manipulation chores.

Tidy data - Hadley Wickham

Visto l’importanza dei dati nel mondo moderno e l’innegabile importanza del tempo nella nostra società, evitiamo di perdere troppo tempo a risistemare i nostri dati e cerchiamo di uniformarci ai tidy data da quando creiamo un dataset in poi. Questo ci farà risparmiare molto tempo e migliorerà la ripetibilità delle nostre analisi!

1.11 Programmazione in R

R permette di eseguire comandi che permetto l’iterazione, la valutazione di espressioni condizionali e la definizione di funzioni.

1.11.1 Condizioni: if

if (condizione) comando1 else comando2
#Oppure
ifelse(condizione,comando1,comando2)

La prima espressione verifica una condizione solo su singolo elemento. Al contrario, il comando ifelse permette di vettorializzare il controllo. Se la condizione è va valutata su un vettore, il comando ifelse la valuta su tutte le entrate e applica comando1 se soddisfatta per quell’entrata e comando2 in caso contrario. Qualora venisse passato un vettore all’espressione if, questo valuterebbe la condizione solo rispetto al primo elemento del vettore ed eseguirebbe il comando opportuno.

Si possono raggruppare più comandi usando le parentesi graffe e il punto e virgola. Ad esempio, nell’if è possibile in questo modo fare più operazioni per ogni caso.

1.11.2 Iterazioni: for - while - repeat

Si possono iterare dei comandi usando i comandi for, whileo repeat.

for (i in sequenza) comando1

for permette di iterare comando1 al variare di una variabile, in questo caso i. Questa espressione è molto utile quando si visitano dei vettori e alle diverse entrate viene applicato comando1. Usando le parentesi graffe è possibile indicare più comandi.

while (condizione) comando1

while ripete comando1 finche la condizione è vera. L’uso di while può essere rischioso qualora la condizione sia sempre soddisfatta e si rimanga bloccati in un loop infinito.

repeat ripete semplicemente un comando. break permette di interrompere qualsiasi iterazione ed è l’unico modo per fermare un ciclo repeat.

1.11.3 Definire funzioni

R permette all’utente di definire funzioni, attraverso il comando function.

nomeFunzione <- function( lista_argomenti ) comando1
return(valore)

La sintassi precedente permette di definire una funzione chiamata nomeFunzione che valuterà comando1 e restituirà valore.

L’uso di funzioni user-defined permette di richiamare nei passaggi successivi la funzione che è stata definita passando diversi argomenti. Usando le parentesi graffe è possibile specificare più comandi.

my_fun <- function( a , b , c) {
return(a*b + c)    
}
my_fun2 <- function( a , b , c) {
    y <- a**b 
return(y + a*b + c)    
}

Si possono salvare funzioni e script (usando l’estensione .R), che possono essere poi eseguiti attraverso il comando source(“nome_della_funzione.R”). Per richiamare tali funzioni è essenziale che siano nella cartella di lavoro, altrimenti va indicato il path per raggiungere il file.

1.12 Esercizi

1.12.1 Esercizio 1

Si trovino 2 modi differenti per calcolare la somma dai cavalli vapore (hp) di quelle auto contenute in mtcars che hanno più di 100 cavalli (hp). Suggerimento In un caso si definisca una funzione apposita e nell’altro si usino i comandi visti, così da ottenere il risultato con una sola riga di comandi.

1.12.2 Esercizio 2

Si definisca una funzione chiamata my_max che senza usare funzioni di libreria restituisce il massimo di un vettore.

1.12.3 Esercizio 3

Si definisca una funzione chiamata funzione my_mean che senza usare funzioni di libreria restituisce la media di un vettore.

1.12.4 Esercizio 4

Si definisca una funzione chiamata my_cov che verifica se una matrice può essere la matrice di covarianza di due variabili aleatorie.

1.12.5 Esercizio 5

Si definisca una funzione chiamata my_monte che al variare del numero di punti N, approssimi l’integrale delle funzioni, usando un metodo Monte Carlo:

  • \[f(x) = x^2, x \in (-1,1) \]
  • \[f(x) = e^{-x^2}, x\in \mathbb{R}\]
LS0tCnRpdGxlOiAiTGV6aW9uZSAyIgphdXRob3I6ICJGZWRlcmljbyBSZWFsaSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IG5vCiAgICAgIHNtb290aF9zY3JvbGw6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICB0aGVtZTogeWV0aQogICAgaGlnaGxpZ2h0OiB0YW5nbwotLS0KCiMgUHJpbWkgY29tYW5kaSBkaSBSCiFbXSguL21lZGlhL2FiYWN1cy5qcGcpCgoKIyMgT3BlcmF6aW9uaSBBcml0bWV0aWNoZQoKQ29tZSBhYmJpYW1vIGdpw6AgdmlzdG8gw6ggcG9zc2liaWxlIHVzYXJlIFIgcGVyIHN2b2xnZXJlIG9wZXJhemlvbmkgbWF0ZW1hdGljaGUsIHVzYW5kbyBpIHNpbWJvbGkgc3RhbmRhcmQuIAoKQWQgZXNlbXBpbywgbCd1c28gZGkgYCtgIHBpw7kgdHJhIGR1ZSBudW1lcmkgZmFyw6AgY29tcGFyaXJlIGxhIGxvcm8gc29tbWEuIApJbiBtb2RvIGFuYWxvZ28gw6ggcG9zc2liaWxlIGZhcm5lIGxhIGRpZmZlcmVuemEgKGAtYCksIGlsIHByb2RvdHRvIChgKmApIGUgbGEgZGl2aXNpb25lKGAvYCkuCgpgYGB7cn0KMisyIAoyLTIKMioyCjIvMgpgYGAKCkxlIHBvdGVuemUgc2kgcG9zc29ubyBlc3ByaW1lcmUgdXNhbmRvIGlsIHNpbWJvbG8gYF5gLiBMbyBzdGVzc28gc2ltYm9sbyBzaSBwdcOyIHV0aWxpenphcmUgcGVyIGlsIGNhbGNvbG8gZGVsbGUgcmFkaWNpLCBhbmNoZSBzZSDDqCBwb3NzaWJpbGUgcmljaGlhbWFyZSBsYSByYWRpY2UgcXVhZHJhdGEgdXNhbmRvIGlsIGNvbWFuZG8gYHNxcnQoKWAuIFNpIG5vdGkgY2hlIHRhbGUgZnVuemlvbmUgYWNjZXR0YSBhbmNoZSB2YWxvcmkgY29tcGxlc3NpLgoKUGVyIGxhIGRpdmlzaW9uZSBpbnRlcmEgdHJhIGR1ZSBudW1lcmkgw6ggcG9zc2liaWxlIHVzYXJlIGlsIHNpbWJvbG8gYCUvJWAsIG1lbnRyZSBgJSVgIHJlc3RpdHVpc2NlIGlsIHJlc3RvIGRpIHRhbGUgZGl2aXNpb25lLgoKVW4gYWx0cm8gY29tYW5kbyBkaSBiYXNlIGNoZSBwdcOyIHJpc3VsdGFyZSB1dGlsZSDDqCBpbCBjYWxjb2xvIGRlbCB2YWxvcmUgYXNzb2x1dG8gb3R0ZW51dG8gY29uIGlsIGNvbWFuZG8gYGFicygpYC4KCkluIG1vZG8gYW5hbG9nbyBzb25vIGdpw6AgZGVmaW5pdGUgYWxjdW5lIGRlbGxlIGZ1bnppb25pIGNoZSBzb25vIGFsbGEgYmFzZSBkZWkgY2FsY29saSBtYXRlbWF0aWNpIHBpw7kgZnJlcXVlbnRpLiBMZSB2ZWRyZW1vIG5laSBwcm9zc2ltaSBwYXJhZ3JhZmkuCgojIyBFc3BvbmVuemlhbGUgZSBsb2dhcml0bWkKCkUnIHBvc3NpYmlsZSBjYWxjb2xhcmUgaSB2YWxvcmkgZGVsbGEgZnVuemlvbmUgZXNwb25lbnppYWxlIHVzYW5kbyBpbCBjb21hbmRvIGBleHAoKWAgbWVudHJlIHBlciBpbCBjYWxjb2xvIGRlaSBsb2dhcml0bWkgw6ggcG9zc2liaWxlIHVzYXJlIHBpw7kgZnVuemlvbmk6CmBsb2coKSwgbG9nMTAoKWAgZSBgbG9nMigpYCBjaGUgcmVzdGl0dWlzY29ubyBpbCBsb2dhcml0bW8gbmF0dXJhbGUsIGJhc2UgMTAgZSBiYXNlIDIgcmlzcGV0dGl2YW1lbnRlLiBJbCBjb21hbmRvIGBsb2coKWAgcGVybWV0dGUgYW5jaGUgZGkgc3BlY2lmaWNhcmUgdW5hIGJhc2UgZGlmZmVyZW50ZSBkYSAqKiplKioqLCBjaGUgw6ggcXVlbGxhIGRpIGRlZmF1bHQuIEFkIGVzZW1waW8sIGBsb2coIDUgLCBiYXNlID0gMylgIHJlc3RpdHVpc2NlIGlsIGxvZ2FyaXRtbyBpbiBiYXNlIDMgZGkgNS4KCiMjIEZ1bnppb25pIFRyaWdvbm9tZXRyaWNoZQoKTGUgcHJpbmNpcGFsaSBmdW56aW9uaSB0cmlnb25vbWV0cmljaGUgc29ubyBnacOgIGltcGxlbWVudGF0ZSBpbiBSIGUgc2kgcG9zc29ubyByaWNoaWFtYXJlIHVzYW5kbyBpIGNvbWFuZGkgZWxlbmNhdGkgc290dG8sIGkgY3VpIG5vbWkgcmljaGlhbWFubyBsZSBmdW56aW9uaSBzdGVzc2UuIFZhIG5vdGF0byBjaGUgbCdpbnB1dCBkaSBxdWVzdGUgZnVuemlvbmkgw6ggYXR0ZXNvIGluIHJhZGlhbnRpLCAqKm5vbiBncmFkaSoqLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0Kc2luKCkgIyBzZW5vCmNvcygpICMgY29zZW4KdGFuKCkgIyB0YW5nZW50ZQpgYGAKCkUnIHBvc3NpYmlsZSB1dGlsaXp6YXJlIGxlIHN0ZXNzZSBmdW56aW9uaSBtYSBjb24gZGVzaW5lbnphICoqKnBpKioqIChgc2lucGkoKWAsIGBjb3NwaSgpYCBlIGB0YW5waSgpYCkgc2Ugc2kgaW50ZW5kZSBjb25zaWRlcmFyZSBkZWkgbXVsdGlwbGkgZGkgcGktZ3JlY28uCgpBbmNoZSBsZSBmdW56aW9uaSBpbnZlcnNlIHNvbm8gZ2nDoCBpbXBsZW1lbnRhdGUgZSBzaSBwb3Nzb25vIHJpY2hpYW1hcmUgY29uIGkgY29tYW5kaSBgYWNvcygpLCBhc2luKCksIGF0YW4oKWAuCgojIyBBc3NlZ25hemlvbmUgZSB2ZXR0b3JpCgpGaW4gb3JhIGFiYmlhbW8gdXNhdG8gUiBwZXIgY2FsY29sYXJlIGRlaSBzaW5nb2xpIHZhbG9yaSwgaW4gbW9kbyBhbmFsb2dvIGEgY29tZSBhdnJlbW1vIHVzYXRvIHVuYSBjYWxjb2xhdHJpY2UuIFR1dHRhdmlhIFIgcGVybWV0dGUgZGkgZmFyZSBtb2x0byBkaSBwacO5LiAKCkNvbWUgcHJpbW8gcGFzc28gcGVyIHNjb3ByaXJuZSAgbGUgcG90ZW56aWFsaXTDoCB2ZWRyZW1vIGxhIHBvc3NpYmlsaXTDoCBkaSBhc3NlZ25hcmUgdmFsb3JpIGUgZGkgcmljaGlhbWFybGkgc3VjY2Vzc2l2YW1lbnRlLCBjb3PDrCBjb21lIGRpIGxhdm9yYXJlIGNvbiB2ZXR0b3JpIG8gbWF0cmljaSwgaW52ZWNlIGNoZSBjb24gc2luZ29saSB2YWxvcmkuCgpRdWVzdGEgcGFydGUsIGNvc8OsIGNvbWUgYWxjdW5lIHN1Y2Nlc3NpdmUgc29ubyBhbmNoZSBjb3BlcnRlIGRhbGxlIHV0aWxpIFtkaXNwZW5zZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvZG9jL2NvbnRyaWIvTWluZW8tZGlzcGVuc2FSLnBkZiksIGRpIGN1aSBobyBnacOgIGNvbnNpZ2xpYXRvIGxhIGxldHR1cmEuCgpFJyBwb3NzaWJpbGUgYXNzZWduYXJlIHVuIHZhbG9yZSBhZCB1bmEgdmFyaWFiaWxlIHVzYW5kbyBsYSBmcmVjY2luYSBgLT5gLiBTdGVzc28gcmlzdWx0YXRvIHNpIHB1w7Igb3R0ZW5lcmUgdXNhbmRvIGA9YCBvcHB1cmUgYGFzc2lnbigpYCwgdHV0dGF2aWEgaWwgcHJpbW8gw6ggZGVjaXNhbWVudGUgaWwgY29tYW5kbyBwacO5IHVzYXRvIGUgZGkgcGnDuSBmYWNpbGUgbGV0dHVyYS4gW1F1aV0oaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xNzQxODIwL2Fzc2lnbm1lbnQtb3BlcmF0b3JzLWluLXItYW5kKSDDqCBwb3NzaWJpbGUgbGVnZ2VyZSB1bmEgZGlzY3Vzc2lvbmUgc3VsbGUgZGlmZmVyZW56ZSBuZWxsJ3VzbyBkaSBgPWAgbyBkaSBgLT5gLgoKYGBge3J9CnggIDwtIDYKYGBgCgpVc2FuZG8gaWwgcHJlY2VkZW50ZSBjb21hbmRvIHZpZW5lIGFzc2VnbmF0byBpbCB2YWxvcmUgNiBhbGxhIHZhcmlhYmlsZSB4LiBJbiBxdWVzdG8gbW9kbyDDqCBwb3NzaWJpbGUgcmljaGlhbWFybGEgc3VjY2Vzc2l2YW1lbnRlLCBjb3PDrCBjb21lIMOoIHBvc3NpYmlsZSBzY3JpdmVyZSBlc3ByZXNzaW9uaSBwacO5IGNvbXBsZXNzZSBjaGUgY29pbnZvbGdvbm8geCBhIHByZXNjaW5kZXJlIGRhbCBzdW8gdmFsb3JlLiBRdWVzdG8gc2Fyw6AgcGFydGljb2xhcm1lbnRlIHV0aWxlIHNlIGRvdnJlbW8gZGVmaW5pcmUgZGVsbGUgZnVuemlvbmkgYSBjdWkgw6ggcG9zc2liaWxlIHBhc3NhcmUgcGVyIGFyZ29tZW50byBkaXZlcnNpIHZhbG9yaS4KU2kgbm90aSBjaGUgaWwgY29tYW5kbyBgNiAtPiB4YCBwcm9kdWNlIGdsaSBzdGVzc2kgcmlzdWx0YXRpIGRlbCBwcmVjZWRlbnRlLgoKT2x0cmUgYWQgYXNzZWduYXJlIHVuIHNpbmdvbG8gdmFsb3JlLCDDqCBwb3NzaWJpbGUgIGNvbnNpZGVyYXRpIGRlaSB2ZXR0b3JpLgpJbCBjb21hbmRvIApgYGB7cn0KeSA8LSBjKDEsMiwzLDQpCnlbMV0KYGBgCmFzc2VnbmEgYSB5IGkgdmFsb3JpIGNvbnRlbnV0aSBuZWwgY29tYW5kbyBgYygpYC4gVGFsZSBjb21hbmRvIGNvbWJpbmEgaSB2YWxvcmkgaW4gdW4gdmV0dG9yZSBjb2xvbm5hIChtYSBsbyB2aXN1YWxpenphIGNvbWUgdW5hIHJpZ2EhKS4gTCdhY2Nlc3NvIGFpIHZldHRvcmkgYXZ2aWVuZSBhdHRyYXZlcnNvIGluZGljYW5kb25lIGlsIG5vbWUsIHNlZ3VpdG8gZGEgcGFyZW50ZXNpIHF1YWRyZS4gT3Z2aWFtZW50ZSDDqCBwb3NzaWJpbGUgc3ZvbGdlcmUgb3BlcmF6aW9uaSBhcml0bWV0aWNoZSBhbmNoZSB0cmEgdmV0dG9yaSwgdXNhbmRvIGxhIHN0ZXNzYSBzaW50YXNzaSB2aXN0YSBwcmltYS4gCkRpIGRlZmF1bHQgUiBjb25zaWRlcmEgb3BlcmF6aW9uaSBwdW50dWFsaSB0cmEgdmV0dG9yaSwgY2lvw6ggbCdvcGVyYXppb25lIHJpY2hpZXN0YSB2aWVuZSBzdm9sdGEgZW50cmF0YSBwZXIgZW50cmF0YS4gUXVlc3RvIHJpY2hpZWRlIGxlIGRpbWVuc2lvbmkgc2lhbm8gbGUgc3Rlc3NlLiBRdWFsb3JhIG5vbiBsbyBmb3NzZXJvLCBpbCBjb250ZW51dG8gZGVsIHZldHRvcmUgcGnDuSBwaWNjb2xvIHZpZW5lIHJpcGV0dXRvIHVuIG51bWVybyBkaSB2b2x0ZSBzdWZmaWNpZW50aSBkYSByZW5kZXJlIHBvc3NpYmlsZSBsJ29wZXJhemlvbmUuIFF1ZXN0byB2aWVuZSBhbmNoZSBzZWduYWxhdG8gZGEgdW4gd2Fybmlnbi4KCkUnIHBvc3NpYmlsZSBvdHRlbmVyZSBsZSBkaW1lbnNpb25pIGRpIHVuIHZldHRvcmUgdXNhbmRvIGlsIGNvbWFuZG8gYGxlbmd0aCgpYC4KClVuIGNvbWFuZG8gdXRpbGUgdHJhIHZldHRvcmkgw6ggYHQoKWAgY2hlIHRyYXNwb25lIGlsIHZldHRvcmUgcGFzc2F0byBwZXIgYXJnb21lbnRvLgoKYGBge3J9CnogPC0gdCh5KQp5CnByaW50KHopCnoKYGBgCkNoaWFtYXJlIHVuYSB2YXJpYWJpbGUgc2VuemEgaW5kaWNhcmUgb3BlcmF6aW9uaSBuZSBwZXJtZXR0ZSBsYSBzdGFtcGEgYSB2aWRlby4gSW5zZXJlbmRvIGwnYXNzZWduYXppb25lIHRyYSBwYXJlbnRlc2kgdG9uZGUgc2kgb3R0aWVuZSBsbyBzdGVzc28gcmlzdWx0YXRvLiBBbmNoZSBpbCBjb21hbmRvIGBwcmludCgpYCBwZXJtZXR0YSBsYSBzdGFtcGEgYSB2aWRlby4gSW5vbHRyZSBxdWVzdG8gY29tYW5kbywgZGl2ZXJzYW1lbnRlIGRhaSBwcmVjZWRlbnRpLCBwZXJtZXR0ZSBkaSBtb3N0cmFyZSBsJ291dHB1dCBhbmNoZSBxdWFuZG8gw6ggY2hpYW1hdGEgZGVudHJvIHVuYSBmdW56aW9uZSBvIHVubyBzY3JpcHQuCgpEYWwgY29tYW5kbyBwcmVjZWRlbnRlIHZlZGlhbW8gY2hlIHkgZSB6IGhhbm5vIHN0ZXNzaSB2YWxvcmkgbWEgZGltZW5zaW9uaSBkaXZlcnNlLiBUdXR0YXZpYSBSIHBlcm1ldHRlIGRpIHN2b2xnZXJlIG9wZXJhemlvbmkgbWF0ZW1hdGljaGUgc3UgZGkgZXNzaSBzZW56YSB3YXJuaW5nIG8gZXJyb3JpLgoKUGVyIHN2b2xnZXJlIG9wZXJhemlvbmkgdHJhIHZldHRvcmksIGNvbWUgaWwgcHJvZG90dG8gcmlnaGUgcGVyIGNvbG9ubmUgc2kgcHXDsiBjb25zaWRlcmFyZSBpbCBjb21hbmRvIGAlKiVgLiBJbiBxdWVzdG8gY2FzbyBpbCByaXN1bHRhdG8gZGlwZW5kZSBkYWxsJ29yZGluZS4KCmBgYHtyfQp5ICUqJSB6CnogJSolIHkKYGBgCgojIyBTZXF1ZW56ZQoKTmVsIGNhc28gc2kgZGViYmEgaW5kaWNhcmUgdW5hIHN1Y2Nlc3Npb25lIGRpIHZhbG9yaSDDqCBwb3NzaWJpbGUgZmFybG8gc2VuemEgaW5kaWNhcmxpIGVzcHJlc3NhbWVudGUgdHV0dGksIHB1cmNow6kgZXNzaSBzaWFubyB1bmEgc2VxdWVuemEgcmVnb2xhcmUuCgpBZCBlc2VtcGlvIGNvbiBgYTpiYCBwb3NzaWFtbyB1c2FyZSBpIGR1ZSBwdW50aSBwZXIgaW5kaWNhcmUgdW5hIHNlcXVlbnphIGRpIHZhbG9yaSBjb24gcGFzc28gMSAgZGEgKmEqIGZpbm8gYSAqYiogLiBQZXIgaW5kaWNhcmUgdW4gcGFzc28gZGl2ZXJzbyBwb3NzaWFtbyB1c2FyZSBpbCBjb21hbmRvIGBzZXEoYSxiLHBhc3NvKWAgY2hlICBwcm9kdXJyw6AgdW5hIHNlcXVlbnphIGRpIGVsZW1lbnRpIGRhICphKiBmaW5vIGEgKmIqIGRpc3RhbnppYXRpIGRpIHVuIHZhbG9yZSB1Z3VhbGUgYWwgKnBhc3NvKiBpbmRpY2F0by4gU2UgaWwgcGFzc28gdmllbmUgb21lc3NvIMOoIGNvbnNpZGVyYXRvIDEgZGkgZGVmYXVsdC4gCgpQZXIgdHV0dGUgbGUgZnVuemlvbmkgw6ggcG9zc2liaWxlIGFjY2VkZXJlIGFsbCdoZWxwIGRpIFIgdXNhbmRvIGlsIGNvbWFuZG8gYGhlbHAoTm9tZV9mdW56aW9uZSlgLiBMZWdnZW5kbyBsJ2hlbHAgZGkgYHNlcSgpYCB2ZWRpYW1vIGFkIGVzZW1waW8gY2hlIHBvc3NpYW1vIGFuY2hlIGluZGljYXJlIGluIG9yZGluZSBkaXZlcnNvIGkgcGFyYW1ldHJpLCBhIHBhdHRvIGRpIHNwZWNpZmljYXJsaSB1c2FuZG8gaWwgbm9tZSBpbmRpY2F0byBuZWxsJ2hlbHAuIEFkIGVzZW1waW8gYHNlcSh0byA9IGIsIGJ5ID0gcGFzc28sIGZyb20gPSBhKWAgcmVzdGl0dWlzY2UgbG8gc3Rlc3NvIG91dHB1dCBkaSBgc2VxKGEsYixwYXNzbylgLgoKSW5vbHRyZSDDqCBwb3NzaWJpbGUgcmlwZXRlcmUgdW4gdmFsb3JlIG8gdW4gdmV0dG9yZSB1c2FuZG8gaWwgY29tYW5kbyBgcmVwKClgLCBhZCBlc2VtcGlvIGByZXAoMSw1KWAgcmVzdGl0dWlzY2UgY2lucXVlIHZvbHRlIGlsIHZhbG9yZSAxLiBOZWwgY2FzbyBkaSB1biB2ZXR0b3JlLCBpbCBjb21hbmRvIHJpcGV0ZXLDoCA1IHZvbHRlIGlsIHZldHRvcmUuCgojIyBPcGVyYXppb25pIHN1IHZldHRvcmkKCk9sdHJlIGFsbGUgb3BlcmF6aW9uaSBjaGUgYWJiaWFtbyBnacOgIHZpc3RvIGVzaXN0b25vIGFsdHJlIGZ1bnppb25pIGRpIFIgYXBwb3NpdGFtZW50ZSBwZW5zYXRlIHBlciBpIHZldHRvcmkuIEFkIGVzZW1waW8gbGUgZnVuemlvbmkgYG1pbmAgZSBgbWF4YCByZXN0aXR1aXNjb25vLCByaXNwZXR0aXZhbWVudGUsIGlsIG1pbmltbyBlZCBpbCBtYXNzaW1vIHZhbG9yZSBjb250ZW51dG8gaW4gdW4gdmV0dG9yZS4gUGVyIGFjY2VkZXJlIGFsbGEgcG9zaXppb25lIGRpIHRhbGkgdmFsb3JpIHNpIGNvbWJpbmFubyBpIHByZWNlZGVudGkgY29tYW5kaSBjb24gYHdoaWNoYC4gQWQgZXNlbXBpbwoKYGBge3J9CnggPC0gYygzLCA1LCA3LCAxLCAzLCAzLCA5LCA4KQptaW4oeCkKd2hpY2gubWluKHgpCm1heCh4KQp3aGljaC5tYXgoeCkKYGBgCgpBbHRyZSBmdW56aW9uaSBtb2x0byB1dGlsaSBwZXIgbGF2b3JhcmUgY29uIGkgdmV0dG9yaSBzb25vIGxhIGZ1bnppb25lIGBzdW0oKWAgY2hlIGNhbGNvbGEgbGEgc29tbWEgZGkgdHV0dGkgZ2xpIGVsZW1lbnRpIGRpIHVuIHZldHRvcmUgZSBsYSBmdW56aW9uZSBgZGlmZigpYApjaGUgY2FsY29sYSBsYSBkaWZmZXJlbnphIGRpIHVuIHZhbG9yZSBkYSB1bm8gZGVpIHByZWNlZGVudGkgKMOoIHBvc3NpYmlsZSBpbmRpY2FyZSBxdWFudG8gcHJpbWEgImd1YXJkYXJlIikuCgpgYGB7cn0Kc3VtKHgpCmRpZmYoeCkKZGlmZih4LDIpCmBgYAoKIyMgT3BlcmF0b3JpIHJlbGF6aW9uYWxpIGUgbG9naWNpCgpSIGNpIHBlcm1ldHRlIGFuY2hlIGRpIHZhbHV0YXJlIGVzcHJlc3Npb25pIHJlbGF6aW9uYWxpIG8gbG9naWNoZS4gSWwgbG9ybyByaXN1bHRhdG8gc2Fyw6AgdW4gdmFsb3JlIGxvZ2ljbyBpbmRpY2F0byBjb24gVFJVRSBvIEZBTFNFLgpgYGB7cn0KNiA+IDEwCjYgPD0gMTAKaXNfYmlnZ2VyIDwtIDY+IDEwCmlzX2JpZ2dlcgphcy5pbnRlZ2VyKGlzX2JpZ2dlcikKYGBgCgpSIHBlcm1ldHRlIGRpIHZhbHV0YXJlIGRpdmVyc2UgZXNwcmVzc2lvbmkgcmVsYXppb25hcmksIG9sdHJlIGEgbWFnZ2lvcmUgKHVndWFsZSkgbyBtaW5vcmUgKHVndWFsZSkuIEFkIGVzZW1waW8gw6ggcG9zc2liaWxlIHZhbHV0YXJlIHNlIGR1ZSB2YWxvcmkgbyB2YXJpYWJpbGkgc2lhbm8gZGl2ZXJzaSBgIT1gIG8gdWd1YWxpIGA9PWAuIFF1ZXN0byBwdcOyIGVzc2VyZSBwYXJ0aWNvbGFybWVudGUgdXRpbGUgcXVhbmRvIHNpIGRlZmluaXNjb25vIGRlbGxlIGZ1bnppb25pIHByb3ByaWUgZSBzaSB2YWx1dGEgc2UgdW5hIGNvbmRpemlvbmUgw6ggc29kZGlzZmF0dGEuCgpSIHBlcm1ldHRlIGFuY2hlIGRpIHZhbHV0YXJlIGdsaSBvcGVyYXRvcmkgbG9naWNpIGAmYCAoYW5kKSwgYHxgIChvciksIGB4b3JgIGUgYCFgIChub3QpLiAKClF1ZXN0aSBvcGVyYXRvcmkgcG9zc29ubyBlc3NlcmUgdmFsdXRhdGkgc2lhIHN1IHZldHRvcmkgbG9naWNpLCBjaGUgZGkgbnVtZXJpIHF1YWxzaWFzaS4gTmVsIHNlY29uZG8gY2FzbywgdHV0dGF2aWEsIHR1dHRvIGNpw7IgY2hlIMOoIGRpdmVyc28gZGEgemVybyBjb250ZXLDoCBjb21lIFRSVUUsIGUgc29sbyBsbyAwIGNvbnRlcsOgIGNvbWUgRkFMU0UuIE5lbCBjYXNvIGluIGN1aSBzaSBkZWZpbmlzY2FubyBkZWkgdmV0dG9yaSBtaXN0aSAoZG92ZSBzb25vIHByZXNlbnRpIHNpYSB2YWxvcmkgbG9naWNpIGNoZSBpbnRlcmkvcmVhbGkvY29tcGxlc3NpKSwgdmVycmFubm8gdHV0dGkgY29udmVydGl0aSBuZWwgZm9ybWF0byBudW1lcmljbyBwcmVzZW50ZS4KCiMjIE1hdHJpY2kKCkNvbWUgYWJiaWFtbyB2aXN0byBpIHZldHRvcmkgc29ubyBjb25zaWRlcmF0aSBpbiBnZW5lcmFsZSB2ZXR0b3JpIHJpZ2EsIGUgbm9uIMOoIHBvc3NpYmlsZSBnZW5lcmFyZSB1bmEgbWF0cmljZSB1c2FuZG8gaWwgY29tYW5kbyBgYygpYC4gCgpUdXR0YXZpYSBsZSBtYXRyaWNpIGVzaXN0b25vIGUgc2kgcG9zc29ubyBkZWZpbmlyZSB1c2FuZG8gbGEgZnVuemlvbmUgYGNiaW5kKClgIGNoZSB1bmlzY2UgaSB2ZXR0b3JpIHBhc3NhdGkgY29tZSBhcmdvbWVudG8gaW4gdW5hIG1hdHJpY2UgZG92ZSBpIHZldHRvcmkgYXJnb21lbnRvIHNvbm8gbGUgY29sb25uZS4gTGEgZnVuemlvbmUgYHJiaW5kKClgIGhhIGxhIHN0ZXNzYSBmdW56aW9uZSwgbWEgaSB2ZXR0b3JpIHBhc3NhdGkgY29tZSBhcmdvbWVudG8gc2FyYW5ubyBsZSByaWdoZSBkZWxsYSBtYXRyaWNlLiBMYSBmdW56aW9uZSBgZGltKClgIHJlc3RpdHVpc2NlIGxlIGRpbWVuc2lvbmkgZGVsbCdvZ2dldHRvIHBhc3NhdG8gY29tZSBhcmdvbWVudG8uIExhIGZ1bnppb25lIGBsZW5ndGgoKWAgKGNoZSBhdmV2YW1vIHZpc3RvIGNvbiBpIHZldHRvcmkpIGNpIHJlc3RpdHVpc2NlIGlsICpwcm9kb3R0byogZGVsbGUgZGltZW5zaW9uaS4KCgpgYGB7cn0KYSA8LSBjYmluZChjKDEsIDIsIDMpLCBjKDQsIDUsIDYpKQpkaW0oYSkKYiA8LSBjYmluZChjKDEsIDIsIDMpLCBjKDQsIDUsIDYpKQpkaW0oYikKYQpiCmBgYAoKRScgcG9zc2liaWxlIHZhcmlhcmUgbGEgZGltZW5zaW9uZSBkaSB1biBvZ2dldHRvIHVzYW5kbyBnbGkgc3Rlc3NpIGNvbWFuZGkgYGxlbmd0aGAgZSBgZGltYCBjb21lIGFzc2VnbmF6aW9uaS4gCmBgYHtyfQpkaW0oYSkgPC0gYygyLDMpCmEKYGBgCgpJbCBjb21hbmRvIHByZWNlZGVudGUgY2FtYmlhIGxhIGZvcm1hIGRlbGxhIG1hdHJpY2UsIHNlY29uZG8gbGEgZm9ybWEgaW5kaWNhdGEuIFRhbGkgY29tYW5kaSB2YW5ubyBjb211bnF1ZSB1c2F0aSBjb24gYXR0ZW56aW9uZSwgdmlzdG8gY2hlIG5vbiBzaSBoYSBjb250cm9sbG8gc3UgY29tZSBpbCBjb250ZW51dG8gdmVycsOgIHJpZGlzdHJpYnVpdG8uCgpBbHRyYSB1dGlsZSBmdW56aW9uZSBwZXIgY3JlYXJlIG1hdHJpY2kgw6ggbGEgZnVuemlvbmUgYGFycmF5KClgIGNoZSBjaGllZGUgZGkgc3BlY2lmaWNhcmUgZ2xpIGVsZW1lbnRpIGRlbGxhIG1hdHJpY2UgZSBsZSBkaW1lbnNpb25pLiBSaXN1bHRhdG8gYW5hbG9nbyBzaSBwdcOyIG90ZW5lcmUgY29uIGxhIGZ1bnppb25lIGBtYXRyaXgoZWxlbWVudGksIG51bSByaWdoZSwgbnVtIGNvbG9ubmUpYC4gU2kgbm90aSBjaGUgY29uIGBhcnJheSgpYCDDqCBwb3NzaWJpbGUgZGVmaW5pcmUgc3RydXR0dXJlIGNvbiBwacO5IGRpIGR1ZSBkaW1lbnNpb25pLgoKR2xpIGVsZW1lbnRpIHVuYSBtYXRyaWNlIHNpIGFjY2Vkb25vIHVzYW5kbyBsZSBwYXJlbnRlc2kgcXVhZHJlLCBpbmRpY2FuZG8gbGEgcG9zaXppb25lIGRlbGwnZWxlbWVudG8uCgpgYGB7cn0KYVsyLDNdCmBgYAoKU2Ugc2kgaW50ZW5kZSBzZWxlemlvbmFyZSB1bidpbnRlcmEgcmlnYSBvIGNvbG9ubmEsIGJhc3RhIGxhc2NpYXJlIHZ1b3RvIHRhbGUgY2FtcG8uIFBlciBlc2VtcGlvIGBhWzEsXWAgcmVzdGl0dXNjZSBsJ2ludGVyYSBwcmltYSByaWdhLiBJbCBjb21hbmRvIGBzdW0oKWAsIHZpc3RvIGluIHByZWNlZGVuemEgZnVuemlvbmEgYW5jaGUgY29uIG1hdHJpY2ksIHJlc3RpdHVlbmRvIGxhIHNvbW1hIGRpIHR1dHRlIGxlIGVudHJhdGUuIFBlciBvdHRlbmVyZSBsYSBzb21tYSBkZWxsZSByaWdoZSBvIGRlbGxlIGNvbG9ubmUgw6ggcG9zc2liaWxlIHVzYXJlIGkgY29tYW5kaSBgcm93U3VtKClgIG8gYGNvbFN1bSgpYCwgcmlzcGV0dGl2YW1lbnRlLgpBbmNoZSBpIGNvbWFuZGkgYG1pbigpYCBlIGBtYXgoKWAgcmVzdGl0dWlzY29ubyBpbCBtaW4vbWF4IHRyYSBfdHV0dGVfIGxlIGVudHJhdGUuIE1lbnRyZSBnbGkgc3Rlc3NpIGNvbWFuZGkgY29uIGlsIGB3aGljaGAgcmVzdGl0dWlzY29ubyBsJ2luZGljZSBjb250YW5kbyBwZXIgY29sb25uZSBnbGkgZWxlbWVudGkuCgpBbGN1bmUgZnVuemlvbmkgY29tZSBgY29udG91cigpLCBwZXJzcCgpLCBpbWFnZSgpYCBwZXJtZXR0b25vIGRpIG90dGVuZXJlIGRlaSBncmFmaWNpLCBwYXJ0ZW5kbyBkYSBtYXRyaWNpLgoKIyMgU3RyaW5naGUgKHZldHRvcmkgZGkgY2FyYXR0ZXJpKQpSIHBlcm1ldHRlIGRpIG1hbmlwb2xhcmUgYW5jaGUgdmV0dG9yaSBkaSBjYXJhdHRlcmksIG8gc3RyaW5naGUsIGNoZSBwb3Nzb25vIGVzc2VyZSBzYWx2YXRpIGFuY2hlIGNvbWUgdmV0dG9yaS4gTGUgc3RyaW5naGUgdmVuZ29ubyBkZWxpbWl0YXRlIGRhIGRvcHBpZSB2aXJnb2xldHRlIGAiICJgIChvIGFuY2hlIHNlbXBsaWNpIHZpcmdvbGV0dGUgYCcgJ2ApLgoKYGBge3J9Cm5vbWkgPC0gYygiRnJhbmNlc2NvIiwgIlNvZmlhIiwgIkFsZXNzYW5kcm8iKQpub21pWzFdCgpub21pX2VfbnVtZXJpIDwtIGMoIkZyYW5jZXNjbyIsICJTb2ZpYSIsICJBbGVzc2FuZHJvIiwgNDUpCmBgYAoKSW4gUiBub24gcG9zc29ubyBjb252aXZlcmUgbmVsbG8gc3Rlc3NvIGFycmF5IGNhcmF0dGVyaSBlIG51bWVyaS4gU2UgYWQgZXNlbXBpbyBuZWxsJ2Fzc2VnbmF6aW9uZSBpbmRpY2hpYW1vIG5vbWkgZSBudW1lcmksIHF1ZXN0aSB1bHRpbWkgdmVycmFubm8gY29udmVydGl0aSBpbiBjYXJhdHRlcmkuCgpVbmEgZnVuemlvbmUgbW9sdG8gdXRpbGUgcGVyIG1hbmVnZ2lhcmUgc3RyaW5naGUsIG1hIGFuY2hlIGFsdHJpIHJpc3VsdGF0aSwgw6ggbGEgZnVuemlvbmUgYHBhc3RlKClgIGNoZSBjb25jYXRlbmEgZGVpIHZldHRvcmkgZG9wbyBhdmVybGkgdHJhc2Zvcm1hdGkgaW4gc3RyaW5naGUuCgpgYGB7cn0KcGFzdGUoMToxMikgCgoobnRoIDwtIHBhc3RlMCgxOjEyLCBjKCJzdCIsICJuZCIsICJyZCIsIHJlcCgidGgiLCA5KSkpKQpgYGAKClF1ZXN0YSBmdW56aW9uZSBwdcOyIGVzc2VyZSBtb2x0byB1dGlsZSwgYWQgZXNlbXBpbywgc2Ugc2kgZGV2b25vIGNyZWFyZSB2ZXR0b3JpIGRpIG5vbWkgcGVyIGRlbGxlIHZhcmlhYmlsaS4KClBlciBjYXBpcmUgaWwgdGlwbyBkaSBkYXRpIGNvbnRlbnV0byBpbiB1biB2ZXR0b3JlIHBvc3NpYW1vIHVzYXJlIGlsIGNvbWFuZG8gYHR5cGVvZigpYC4KCiMjIExpc3RlIGUgZGF0YSBmcmFtZQoKUG9zc2lhbW8gcGVuc2FyZSBhZCB1bmEgbWF0cmljZSBjb21lIGFkIHVuIG1ldG9kbyBlZmZpY2FjZSBwZXIgaW1tYWdhenppbmFyZSBpbmZvcm1hemlvbmkgbnVtZXJpY2hlLCBlZCDDqCBjb3PDrCEgUGVyw7Igc2UgaWwgdGlwbyBkaSBpbmZvcm1hemlvbmkgY2hlIGRvYmJpYW1vIGltbWFnYXp6aW5hcmUgw6ggbWlzdG8sIGFkIGVzZW1waW8gY29udGllbmUgc2lhIG51bWVyaSBjaGUgY2FyYXR0ZXJpLCBsYSBsb3JvIGVmZmljaWVuemEgdmllbmUgbWVubyBlIHNpIHBvc3Nvbm8gcHJlZmVyaXJlIGFsdHJpIG1ldG9kaS4KClVuYSBsaXN0YSDDqCB1biBpbnNpZW1lIG9yZGluYXRvIGRpIG9nZ2V0dGkuIFNpIHBvc3Nvbm8gZGVmaW5pcmUgbGlzdGUgdXNhbmRvIGlsIGNvbWFuZG8gYGxpc3QoKWAuIAoKYGBge3J9CmMgPC0gbGlzdChkZXN0aW5hemlvbmUgPSBjKCJMb25kb24iLCAiTWFkcmlkIiksIGNvbXBhZ25pYSA9IGMoIlJ5YW5haXIiLCAiRWFzeUpldCIpLCBjb3N0byA9IGMoNjAsIDgwKSwgdmFsdXRhID0gYygiwqMiLCAi4oKsIikgKQpgYGAKClNpIHB1w7IgYWNjZWRlcmUgYWwgY29udGVudXRvIGRpIHVuYSBsaXN0YSBzaWEgcGVyIHBvc2l6aW9uZSBjb24gbGUgZG9wcGllIHBhcmVudGVzaSBgY1tbMl1dYCAgb3BwdXJlIHBlciBub21lIGBjW1siY29tcGFnbmlhIl1dYCBvIGBjJGNvbXBhZ25pYWAuIFR1dHRpICBpIHByZWNlZGVudGkgY29tYW5kaSByZXN0aXR1aXNjb25vIGlsIGNvbnRlbnV0byBkZWxsYSBsaXN0YSBkZWZpbml0byBkYSAqY29tcGFnbmlhKi4gU2Ugdm9nbGlhbW8gYWNjZWRlcmUgZGlyZXR0YW1lbnRlIGFkIHVuIGVsZW1lbnRvIHBvc3NpYW1vIHVzYXJlIGluZGlmZmVyZW50ZW1lbnRlIGkgY29tYW5kaSBgY1tbMl1dWzJdYCwgYGNbWyJjb21wYWduaWEiXV1bMl1gIG8gYGMkY29tcGFnbmlhWzJdYC4KCiMjIyBEYXRhIGZyYW1lCgpVbidhbHRyYSBzdHJ1dHR1cmEgZGF0aSBjaGUgcGVybWV0dGUgZGkgaW1tYWdhenppbmF0ZSBkYXRpIGRpIHRpcG8gbWlzdG8gc29ubyBpICpkYXRhIGZyYW1lKi4gUXVlc3RhIHN0cnV0dHVyYSDDqCBkaSBncmFuIGx1bmdhIGxhIHBpw7kgdXNhdGEgcGVyIGxlZ2dlcmUgZSBtYW5pcG9sYXJlIGRhdGkgaW4gUi4gCgpJICpkYXRhIGZyYW1lKiBzb25vIGxpc3RlIGRpIHRpcG8gImRhdGEuZnJhbWUiIGNvbnRlbmVudGkgdmFyaWFiaWxpIGNvbiBsbyBzdGVzc28gbnVtZXJvIGRpIHJpZ2hlLCBpbCBpZGVudGlmaWNhdGl2byBwZXIgbGEgcmlnYSDDqCB1bml2b2NvLiAKCmBgYHtyfQpMMyA8LSBMRVRURVJTWzE6M10KZmFjIDwtIHNhbXBsZShMMywgMTAsIHJlcGxhY2UgPSBUUlVFKQooZCA8LSBkYXRhLmZyYW1lKHggPSAxLCB5ID0gMToxMCwgZmFjID0gZmFjKSkKYGBgCgpgYGB7cn0KZGF0YS5mcmFtZSgxLCAxOjEwLCBmYWMpCmBgYAoKYGBge3J9CiMjIFRoZSAic2FtZSIgd2l0aCBhdXRvbWF0aWMgY29sdW1uIG5hbWVzOgpkYXRhLmZyYW1lKHJlcCgxLDEwKSwgMToxMCwgZmFjKQpkYXRhLmZyYW1lKDEsIDE6MTAsIHNhbXBsZShMMywgMTAsIHJlcGxhY2UgPSBUUlVFKSkKYGBgCgpJbm9sdHJlIMOoIHBvc3NpYmlsZSByaWVtcGlyZSBtYW51YWxtZW50ZSB1biBkYXRhZnJhbWUgYXR0cmF2ZXJzbyBpbCBjb21hbmRvIGBmaXgoKWAuCgojIyMgVGlkeSBkYXRhLCBwbGVhc2UhCgo+ICAgQSBodWdlIGFtb3VudCBvZiBlZmZvcnQgaXMgc3BlbnQgY2xlYW5pbmcgZGF0YSB0byBnZXQgaXQgcmVhZHkgZm9yIAo+IGFuYWx5c2lzLCBidXQgdGhlcmUgaGFzIGJlZW4gbGl0dGxlIHJlc2VhcmNoIG9uIGhvdyB0byBtYWtlIGRhdGEgY2xlYW5pbmcgYXMgZWFzeSBhbmQgZWZmZWN0aXZlIGFzIHBvc3NpYmxlLiBUaGlzIHBhcGVyIHRhY2tsZXMgYSBzbWFsbCwgYnV0IGltcG9ydGFudCwgY29tcG9uZW50IG9mIGRhdGEgY2xlYW5pbmc6IGRhdGEgdGlkeWluZy4gKipUaWR5IGRhdGFzZXRzKiogYXJlIGVhc3kgdG8gbWFuaXB1bGF0ZSwgbW9kZWwgYW5kIHZpc3VhbGl6ZSwgYW5kICoqaGF2ZSBhIHNwZWNpZmljIHN0cnVjdHVyZTogZWFjaCB2YXJpYWJsZSBpcyBhIGNvbHVtbiwgZWFjaCBvYnNlcnZhdGlvbiBpcyBhIHJvdywgYW5kIGVhY2ggdHlwZSBvZiBvYnNlcnZhdGlvbmFsIHVuaXQgaXMgYSB0YWJsZSoqLiBUaGlzIGZyYW1ld29yayBtYWtlcyBpdCBlYXN5IHRvIHRpZHkgbWVzc3kgZGF0YXNldHMgYmVjYXVzZSBvbmx5IGEgc21hbGwgc2V0IG9mIHRvb2xzIGFyZSBuZWVkZWQgdG8gZGVhbCB3aXRoIGEgd2lkZSByYW5nZSBvZiB1bi10aWR5IGRhdGFzZXRzLiBUaGlzIHN0cnVjdHVyZSBhbHNvIG1ha2VzIGl0IGVhc2llciB0byBkZXZlbG9wIHRpZHkgdG9vbHMgZm9yIGRhdGEgYW5hbHlzaXMsIHRvb2xzIHRoYXQgYm90aCBpbnB1dCBhbmQgb3V0cHV0IHRpZHkgZGF0YXNldHMuIFRoZSBhZHZhbnRhZ2VzIG9mIGEgY29uc2lzdGVudCBkYXRhIHN0cnVjdHVyZSBhbmQgbWF0Y2hpbmcgdG9vbHMgYXJlIGRlbW9uc3RyYXRlZCB3aXRoIGEgY2FzZSBzdHVkeSBmcmVlIGZyb20gbXVuZGFuZSBkYXRhIG1hbmlwdWxhdGlvbiBjaG9yZXMuCj4gCjxjaXRlPiBbVGlkeSBkYXRhXShodHRwczovL3d3dy5qc3RhdHNvZnQub3JnL2FydGljbGUvdmlldy92MDU5aTEwKSAtIEhhZGxleSBXaWNraGFtIDxjaXRlPgoKVmlzdG8gbCdpbXBvcnRhbnphIGRlaSBkYXRpIG5lbCBtb25kbyBtb2Rlcm5vIGUgbCdpbm5lZ2FiaWxlIGltcG9ydGFuemEgZGVsIHRlbXBvIG5lbGxhIG5vc3RyYSBzb2NpZXTDoCwgZXZpdGlhbW8gZGkgcGVyZGVyZSB0cm9wcG8gdGVtcG8gYSByaXNpc3RlbWFyZSBpIG5vc3RyaSBkYXRpIGUgY2VyY2hpYW1vIGRpIHVuaWZvcm1hcmNpIGFpICp0aWR5IGRhdGEqIGRhIHF1YW5kbyBjcmVpYW1vIHVuIGRhdGFzZXQgaW4gcG9pLiBRdWVzdG8gY2kgZmFyw6AgcmlzcGFybWlhcmUgbW9sdG8gdGVtcG8gZSBtaWdsaW9yZXLDoCBsYSByaXBldGliaWxpdMOgIGRlbGxlIG5vc3RyZSBhbmFsaXNpIQoKCiMjIFByb2dyYW1tYXppb25lIGluIFIgCgpSIHBlcm1ldHRlIGRpIGVzZWd1aXJlIGNvbWFuZGkgY2hlIHBlcm1ldHRvIGwnaXRlcmF6aW9uZSwgbGEgdmFsdXRhemlvbmUgZGkgZXNwcmVzc2lvbmkgY29uZGl6aW9uYWxpIGUgbGEgZGVmaW5pemlvbmUgZGkgZnVuemlvbmkuCgojIyMgQ29uZGl6aW9uaTogaWYKCmBgYHtyLCBldmFsID0gRkFMU0V9CmlmIChjb25kaXppb25lKSBjb21hbmRvMSBlbHNlIGNvbWFuZG8yCiNPcHB1cmUKaWZlbHNlKGNvbmRpemlvbmUsY29tYW5kbzEsY29tYW5kbzIpCmBgYAoKTGEgcHJpbWEgZXNwcmVzc2lvbmUgdmVyaWZpY2EgdW5hICpjb25kaXppb25lKiAqKnNvbG8qKiBzdSBzaW5nb2xvIGVsZW1lbnRvLiBBbCBjb250cmFyaW8sIGlsIGNvbWFuZG8gYGlmZWxzZWAgcGVybWV0dGUgZGkgdmV0dG9yaWFsaXp6YXJlIGlsIGNvbnRyb2xsby4gU2UgbGEgKmNvbmRpemlvbmUqIMOoIHZhIHZhbHV0YXRhIHN1IHVuIHZldHRvcmUsIGlsIGNvbWFuZG8gYGlmZWxzZWAgbGEgdmFsdXRhIHN1IHR1dHRlIGxlIGVudHJhdGUgZSBhcHBsaWNhICpjb21hbmRvMSogc2Ugc29kZGlzZmF0dGEgcGVyIHF1ZWxsJ2VudHJhdGEgZSAqY29tYW5kbzIqIGluIGNhc28gY29udHJhcmlvLiBRdWFsb3JhIHZlbmlzc2UgcGFzc2F0byB1biB2ZXR0b3JlIGFsbCdlc3ByZXNzaW9uZSBgaWZgLCBxdWVzdG8gdmFsdXRlcmViYmUgbGEgKmNvbmRpemlvbmUqIHNvbG8gcmlzcGV0dG8gYWwgcHJpbW8gZWxlbWVudG8gZGVsIHZldHRvcmUgZWQgZXNlZ3VpcmViYmUgaWwgY29tYW5kbyBvcHBvcnR1bm8uCgpTaSBwb3Nzb25vIHJhZ2dydXBwYXJlIHBpw7kgY29tYW5kaSB1c2FuZG8gbGUgcGFyZW50ZXNpIGdyYWZmZSBlIGlsIHB1bnRvIGUgdmlyZ29sYS4gQWQgZXNlbXBpbywgbmVsbCdgaWZgIMOoIHBvc3NpYmlsZSBpbiBxdWVzdG8gbW9kbyBmYXJlIHBpw7kgb3BlcmF6aW9uaSBwZXIgb2duaSBjYXNvLgoKIyMjIEl0ZXJhemlvbmk6IGZvciAtIHdoaWxlIC0gcmVwZWF0CgpTaSBwb3Nzb25vIGl0ZXJhcmUgZGVpIGNvbWFuZGkgdXNhbmRvIGkgY29tYW5kaSBgZm9yYCwgYHdoaWxlYG8gYHJlcGVhdGAuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpmb3IgKGkgaW4gc2VxdWVuemEpIGNvbWFuZG8xCmBgYAoKYGZvcmAgcGVybWV0dGUgZGkgaXRlcmFyZSBjb21hbmRvMSBhbCB2YXJpYXJlIGRpIHVuYSB2YXJpYWJpbGUsIGluIHF1ZXN0byBjYXNvICppKi4gUXVlc3RhIGVzcHJlc3Npb25lIMOoIG1vbHRvIHV0aWxlIHF1YW5kbyBzaSB2aXNpdGFubyBkZWkgdmV0dG9yaSBlIGFsbGUgZGl2ZXJzZSBlbnRyYXRlIHZpZW5lIGFwcGxpY2F0byBjb21hbmRvMS4gVXNhbmRvIGxlIHBhcmVudGVzaSBncmFmZmUgw6ggcG9zc2liaWxlIGluZGljYXJlIHBpw7kgY29tYW5kaS4KCmBgYHtyLCBldmFsID0gRkFMU0V9CndoaWxlIChjb25kaXppb25lKSBjb21hbmRvMQpgYGAKCmB3aGlsZWAgcmlwZXRlIGNvbWFuZG8xIGZpbmNoZSBsYSBjb25kaXppb25lIMOoIHZlcmEuIEwndXNvIGRpIGB3aGlsZWAgcHXDsiBlc3NlcmUgcmlzY2hpb3NvIHF1YWxvcmEgbGEgY29uZGl6aW9uZSBzaWEgc2VtcHJlIHNvZGRpc2ZhdHRhIGUgc2kgcmltYW5nYSBibG9jY2F0aSBpbiB1biAqbG9vcCBpbmZpbml0byouCgpgcmVwZWF0YCByaXBldGUgc2VtcGxpY2VtZW50ZSB1biBjb21hbmRvLiBgYnJlYWtgIHBlcm1ldHRlIGRpIGludGVycm9tcGVyZSBxdWFsc2lhc2kgaXRlcmF6aW9uZSBlZCDDqCBsJ3VuaWNvIG1vZG8gcGVyIGZlcm1hcmUgdW4gY2ljbG8gYHJlcGVhdGAuCgojIyMgRGVmaW5pcmUgZnVuemlvbmkKClIgcGVybWV0dGUgYWxsJ3V0ZW50ZSBkaSBkZWZpbmlyZSBmdW56aW9uaSwgYXR0cmF2ZXJzbyBpbCBjb21hbmRvIGBmdW5jdGlvbmAuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpub21lRnVuemlvbmUgPC0gZnVuY3Rpb24oIGxpc3RhX2FyZ29tZW50aSApIGNvbWFuZG8xCnJldHVybih2YWxvcmUpCmBgYAoKTGEgc2ludGFzc2kgcHJlY2VkZW50ZSBwZXJtZXR0ZSBkaSBkZWZpbmlyZSB1bmEgZnVuemlvbmUgY2hpYW1hdGEgKm5vbWVGdW56aW9uZSogY2hlIHZhbHV0ZXLDoCBjb21hbmRvMSBlIHJlc3RpdHVpcsOgICp2YWxvcmUqLgoKTCd1c28gZGkgZnVuemlvbmkgKnVzZXItZGVmaW5lZCogcGVybWV0dGUgZGkgcmljaGlhbWFyZSBuZWkgcGFzc2FnZ2kgc3VjY2Vzc2l2aSBsYSBmdW56aW9uZSBjaGUgw6ggc3RhdGEgZGVmaW5pdGEgcGFzc2FuZG8gZGl2ZXJzaSBhcmdvbWVudGkuIFVzYW5kbyBsZSBwYXJlbnRlc2kgZ3JhZmZlIMOoIHBvc3NpYmlsZSBzcGVjaWZpY2FyZSBwacO5IGNvbWFuZGkuCgoKYGBge3J9Cm15X2Z1biA8LSBmdW5jdGlvbiggYSAsIGIgLCBjKSB7CnJldHVybihhKmIgKyBjKSAgICAKfQpgYGAKCmBgYHtyfQpteV9mdW4yIDwtIGZ1bmN0aW9uKCBhICwgYiAsIGMpIHsKICAgIHkgPC0gYSoqYiAKcmV0dXJuKHkgKyBhKmIgKyBjKSAgICAKfQpgYGAKClNpIHBvc3Nvbm8gc2FsdmFyZSBmdW56aW9uaSBlIHNjcmlwdCAodXNhbmRvIGwnZXN0ZW5zaW9uZSAuUiksIGNoZSBwb3Nzb25vIGVzc2VyZSBwb2kgZXNlZ3VpdGkgYXR0cmF2ZXJzbyBpbCBjb21hbmRvIGBzb3VyY2Uo4oCcbm9tZV9kZWxsYV9mdW56aW9uZS5S4oCdKWAuIFBlciByaWNoaWFtYXJlIHRhbGkgZnVuemlvbmkgw6ggZXNzZW56aWFsZSBjaGUgc2lhbm8gbmVsbGEgY2FydGVsbGEgZGkgbGF2b3JvLCBhbHRyaW1lbnRpIHZhIGluZGljYXRvIGlsIHBhdGggcGVyIHJhZ2dpdW5nZXJlIGlsIGZpbGUuCgojIyBFc2VyY2l6aQoKIyMjIEVzZXJjaXppbyAxClNpIHRyb3Zpbm8gMiBtb2RpIGRpZmZlcmVudGkgcGVyIGNhbGNvbGFyZSBsYSBzb21tYSBkYWkgY2F2YWxsaSB2YXBvcmUgKGhwKSBkaSBxdWVsbGUgYXV0byBjb250ZW51dGUgaW4gbXRjYXJzIGNoZSBoYW5ubyBwacO5IGRpIDEwMCBjYXZhbGxpIChocCkuCipTdWdnZXJpbWVudG8qIEluIHVuIGNhc28gc2kgZGVmaW5pc2NhIHVuYSBmdW56aW9uZSBhcHBvc2l0YSBlIG5lbGwnYWx0cm8gc2kgdXNpbm8gaSBjb21hbmRpIHZpc3RpLCBjb3PDrCBkYSBvdHRlbmVyZSBpbCByaXN1bHRhdG8gY29uIHVuYSBzb2xhIHJpZ2EgZGkgY29tYW5kaS4KCgojIyMgRXNlcmNpemlvIDIKU2kgZGVmaW5pc2NhIHVuYSBmdW56aW9uZSBjaGlhbWF0YSBteV9tYXggY2hlIHNlbnphIHVzYXJlIGZ1bnppb25pIGRpIGxpYnJlcmlhIHJlc3RpdHVpc2NlIGlsIG1hc3NpbW8gZGkgdW4gdmV0dG9yZS4KCiMjIyBFc2VyY2l6aW8gMwpTaSBkZWZpbmlzY2EgdW5hIGZ1bnppb25lIGNoaWFtYXRhIGZ1bnppb25lIG15X21lYW4gY2hlIHNlbnphIHVzYXJlIGZ1bnppb25pIGRpIGxpYnJlcmlhIHJlc3RpdHVpc2NlIGxhIG1lZGlhIGRpIHVuIHZldHRvcmUuCgojIyMgRXNlcmNpemlvIDQKU2kgZGVmaW5pc2NhIHVuYSBmdW56aW9uZSBjaGlhbWF0YSBteV9jb3YgY2hlIHZlcmlmaWNhIHNlIHVuYSBtYXRyaWNlIHB1w7IgZXNzZXJlIGxhIG1hdHJpY2UgZGkgY292YXJpYW56YSBkaSBkdWUgdmFyaWFiaWxpIGFsZWF0b3JpZS4KCgojIyMgRXNlcmNpemlvIDUKU2kgZGVmaW5pc2NhIHVuYSBmdW56aW9uZSBjaGlhbWF0YSBteV9tb250ZSBjaGUgYWwgdmFyaWFyZSBkZWwgbnVtZXJvIGRpIHB1bnRpIE4sIGFwcHJvc3NpbWkgbCdpbnRlZ3JhbGUgZGVsbGUgZnVuemlvbmksIHVzYW5kbyB1biBtZXRvZG8gTW9udGUgQ2FybG86CgotICQkZih4KSA9IHheMiwgeCBcaW4gKC0xLDEpICQkCi0gJCRmKHgpID0gZV57LXheMn0sIHhcaW4gXG1hdGhiYntSfSQkCg==