1 Dados

Os dados USArrests foram utilizados na aula para realizar a análise.

data("USArrests")
dados <- USArrests

knitr::kable(head(dados, 10)) |> 
  kableExtra::kable_styling(full_width = TRUE,
                            bootstrap_options = c("striped", "hover", "condensed", "responsive") 
                            )
Murder Assault UrbanPop Rape
Alabama 13.2 236 58 21.2
Alaska 10.0 263 48 44.5
Arizona 8.1 294 80 31.0
Arkansas 8.8 190 50 19.5
California 9.0 276 91 40.6
Colorado 7.9 204 78 38.7
Connecticut 3.3 110 77 11.1
Delaware 5.9 238 72 15.8
Florida 15.4 335 80 31.9
Georgia 17.4 211 60 25.8

De acordo com o chat gpt, o USArrests é um famoso conjunto de dados embutido no R, que contém informações sobre os crimes violentos cometidos nos Estados Unidos nos anos 1970. As colunas representam estatísticas sobre a taxa de crimes por estado. Cada linha do conjunto de dados corresponde a um estado dos EUA. Segue o que representa cada uma das colunas do conjunto de dados:

  1. Murder: Taxa de homicídios (assassinatos) por 100.000 habitantes.
  2. Assault: Taxa de agressões (assaltos) por 100.000 habitantes.
  3. UrbanPop: Percentual da população do estado que vive em áreas urbanas.
  4. Rape: Taxa de estupros por 100.000 habitantes.

2 Análise Exploratória

2.1 Cálculo de medidas descritivas

Inicialmente, vamos calcular as medidas descritivas dos dados.

resumo <- summary(dados); resumo
##      Murder          Assault         UrbanPop          Rape      
##  Min.   : 0.800   Min.   : 45.0   Min.   :32.00   Min.   : 7.30  
##  1st Qu.: 4.075   1st Qu.:109.0   1st Qu.:54.50   1st Qu.:15.07  
##  Median : 7.250   Median :159.0   Median :66.00   Median :20.10  
##  Mean   : 7.788   Mean   :170.8   Mean   :65.54   Mean   :21.23  
##  3rd Qu.:11.250   3rd Qu.:249.0   3rd Qu.:77.75   3rd Qu.:26.18  
##  Max.   :17.400   Max.   :337.0   Max.   :91.00   Max.   :46.00

Agora vamos calcular medidas de variabilidade.

var(dados$Murder); var(dados$Assault); var(dados$UrbanPop); var(dados$Rape) # variâncias
## [1] 18.97047
## [1] 6945.166
## [1] 209.5188
## [1] 87.72916

s1 <- sd(dados$Murder); s1  # desvios padroes
## [1] 4.35551
s2 <- sd(dados$Assault); s2
## [1] 83.33766
s3 <- sd(dados$UrbanPop);s3
## [1] 14.47476
s4 <- sd(dados$Rape); s4
## [1] 9.366385

s1/mean(dados$Murder) # coeficientes de variação
## [1] 0.5592591
s2/mean(dados$Assault)
## [1] 0.4880397
s3/mean(dados$UrbanPop)
## [1] 0.2208539
s4/mean(dados$Rape)
## [1] 0.4411447

2.2 Plotagem de gráficos

Agora vamos fazer histogramas para verificar a assimetria dos dados.

opar <- par(mfrow = c(2, 2))
hist(dados$Murder, main = "Taxa de homicídios", col = "lightgreen")
hist(dados$Assault, main = "Taxa de agressões", col = "red")
hist(dados$UrbanPop, main = "Percentual da população de áreas urbanas", col = "blue")
hist(dados$Rape, main = "Taxa de estupros", col = "orange")

Agora vamos verificar a presença de dados atípicos e de assimetria por meio de boxplots.

opar <- par(mfrow = c(2, 2))
boxplot(dados$Murder, main = "Taxa de homicidios", col = "lightgreen")
boxplot(dados$Assault, main = "Taxa de agressoes", col = "red")
boxplot(dados$UrbanPop, main = "Percentual da populacao de areas urbanas", col = "blue")
boxplot(dados$Rape, main = "Taxa de estupros", col = "orange")

## Os outliers do boxplot da taxa de estupros é referente aos estados: Alaska e Nevada

2.3 Em busca do estado mais violento e menos violento

2.3.1 Ranqueamento para cada variável

Homicídios

Vamos ordernar os dados e verificar os 5 estados com maior e menor taxa de homícidios.

maior <- head(arrange(dados, desc(Murder)), 5)
menor <- head(arrange(dados, Murder), 5)

cat("5 estados com maior taxa de homicídios:\n",
    paste(rownames(maior), collapse = "\n"))
## 5 estados com maior taxa de homicídios:
##  Georgia
## Mississippi
## Florida
## Louisiana
## South Carolina
cat("5 estados com menor taxa de homicídios:\n",
    paste(rownames(menor), collapse = "\n"))
## 5 estados com menor taxa de homicídios:
##  North Dakota
## Maine
## New Hampshire
## Iowa
## Vermont

Agressões

Vamos verificar os 5 estados com maior e menor taxa de agressões.

maior <- head(arrange(dados, desc(Assault)), 5)
menor <- head(arrange(dados, Assault), 5)

cat("5 estados com maior taxa de agressões:\n",
    paste(rownames(maior), collapse = "\n"))
## 5 estados com maior taxa de agressões:
##  North Carolina
## Florida
## Maryland
## Arizona
## New Mexico
cat("5 estados com menor taxa de agressões:\n",
    paste(rownames(menor), collapse = "\n"))
## 5 estados com menor taxa de agressões:
##  North Dakota
## Hawaii
## Vermont
## Wisconsin
## Iowa

população de áreas hurbanas

Agora vamos verificar quais os 5 estados com maior e menor percentual da população do estado que vive em áreas hurbanas.

menor <- head(arrange(dados, UrbanPop), 5)
maior <- head(arrange(dados, desc(UrbanPop)), 5)

cat("5 estados com maior percentual da população que vive em áreas hurbanas:\n",
    paste(rownames(maior), collapse = "\n"))
## 5 estados com maior percentual da população que vive em áreas hurbanas:
##  California
## New Jersey
## Rhode Island
## New York
## Massachusetts
cat("5 estados com menor percentual da população que vive em áreas hurbanas:\n",
    paste(rownames(menor), collapse = "\n"))
## 5 estados com menor percentual da população que vive em áreas hurbanas:
##  Vermont
## West Virginia
## Mississippi
## North Dakota
## North Carolina

Estupros

Vamos verificar quais os 5 estados com maior e menor taxa de estupros.

menor <- head(arrange(dados, Rape), 5)
maior <- head(arrange(dados, desc(Rape)), 5)

cat("5 estados com maior taxa de estupros:\n",
    paste(rownames(maior), collapse = "\n"))
## 5 estados com maior taxa de estupros:
##  Nevada
## Alaska
## California
## Colorado
## Michigan
cat("5 estados com menor taxa de estupros:\n",
    paste(rownames(menor), collapse = "\n"))
## 5 estados com menor taxa de estupros:
##  North Dakota
## Maine
## Rhode Island
## West Virginia
## New Hampshire

2.3.2 Criando a variável que mede o nível de violência

Vamos iniciar padronizando cada uma das variáveis.

z_murder <- (dados$Murder - mean(dados$Murder))/s1
z_assault <- (dados$Assault - mean(dados$Assault))/s2
z_urbanpop   <- (dados$UrbanPop  - mean(dados$UrbanPop))/s3
z_rape   <- (dados$Rape  - mean(dados$Rape))/s4

dados_pad <- cbind(z_murder, z_assault, z_urbanpop, z_rape)

Vamos criar a partir desses dados a variável violencia por meio da média das variáveis.

violencia <- rowMeans(dados_pad)

dados <- cbind(dados, violencia)

knitr::kable(head(dados, 10)) |> 
  kableExtra::kable_styling(full_width = TRUE,
                            bootstrap_options = c("striped", "hover", "condensed", "responsive") 
                            )
Murder Assault UrbanPop Rape violencia
Alabama 13.2 236 58 21.2 0.3752701
Alaska 10.0 263 48 44.5 0.7217809
Arizona 8.1 294 80 31.0 0.8980738
Arkansas 8.8 190 50 19.5 -0.1988230
California 9.0 276 91 40.6 1.3419566
Colorado 7.9 204 78 38.7 0.7875874
Connecticut 3.3 110 77 11.1 -0.5123798
Delaware 5.9 238 72 15.8 0.0599280
Florida 15.4 335 80 31.9 1.4640990
Georgia 17.4 211 60 25.8 0.6986703

2.3.3 Ordenando os estados com maior e menor nível de violência.

Vamos criar um ranking dos estados mais violentas de acordo com a variável criada.

menor <- head(arrange(dados, violencia), 5)
maior <- head(arrange(dados, desc(violencia)), 5)

cat("5 estados mais violentos:\n",
    paste(rownames(maior), collapse = "\n"))
## 5 estados mais violentos:
##  Florida
## Nevada
## California
## Michigan
## New York
cat("5 estados menos violentos:\n",
    paste(rownames(menor), collapse = "\n"))
## 5 estados menos violentos:
##  Vermont
## North Dakota
## Maine
## West Virginia
## New Hampshire

Como eu não acho razoável fazer uma média (porque estamos atribuindo o mesmo peso a variáveis que podem impactar em diferentes níveis na violência do estado), então será feito uma árvore de decisão para saber quais as variáveis que mais impactaram no nível de violência.

# divisao em treino e teste

set.seed(321)

indice_treino <- sample(1:nrow(dados), size = 0.7 * nrow(dados)) # 70% do bd é para treino

bd_treino <- dados[indice_treino, ]
bd_teste  <- dados[-indice_treino, ]

# arvore de decisao

arvore_cart_completa <- rpart(
  formula = violencia ~ .,        
  data = bd_treino,                   
  method = "anova" # regressao
)

# Plotando
rpart.plot(arvore_cart_completa,
           type = 0,
           extra = 101,
           fallen.leaves = TRUE)

# variaveis mais importantes
importancia <- arvore_cart_completa$variable.importance; importancia
##   Assault    Murder      Rape  UrbanPop 
## 13.695968 10.801362  8.040694  2.385421

As duas variáveis mais importantes foram Assault e Murder. Serão consideradas todas as variáveis na criação da variável violencia, atribuindo como peso a contribuição delas na árvore.

importancia <- importancia/sum(importancia)

violencia <- 
  z_assault*importancia[1] +
  z_murder*importancia[2] +
  z_rape*importancia[3] +
  z_urbanpop*importancia[4]     

dados$violencia <- violencia

knitr::kable(head(dados, 10)) |> 
  kableExtra::kable_styling(full_width = TRUE,
                            bootstrap_options = c("striped", "hover", "condensed", "responsive") 
                            )
Murder Assault UrbanPop Rape violencia
Alabama 13.2 236 58 21.2 0.6549490
Alaska 10.0 263 48 44.5 1.0803276
Arizona 8.1 294 80 31.0 0.9104438
Arkansas 8.8 190 50 19.5 0.0464966
California 9.0 276 91 40.6 1.1775363
Colorado 7.9 204 78 38.7 0.6525570
Connecticut 3.3 110 77 11.1 -0.7995995
Delaware 5.9 238 72 15.8 0.0793091
Florida 15.4 335 80 31.9 1.6438816
Georgia 17.4 211 60 25.8 0.9580594

Essa nova variável violencia resulta nos seguintes rankings.

menor <- head(arrange(dados, violencia), 5)
maior <- head(arrange(dados, desc(violencia)), 5)

cat("5 estados mais violentos:\n",
    paste(rownames(maior), collapse = "\n"))
## 5 estados mais violentos:
##  Florida
## Nevada
## California
## Michigan
## New Mexico
cat("5 estados menos violentos:\n",
    paste(rownames(menor), collapse = "\n"))
## 5 estados menos violentos:
##  North Dakota
## Vermont
## New Hampshire
## Iowa
## Maine

3 Análise de Cluster

Agora vamos fazer uma breve análise de cluster para verificar quais os estados mais semelhantes. Primeiramente calculamos a matriz de distâncias euclidianas.

dados_num <- as.matrix(dados)
D_E <- dist(dados_num, method = "euclidian")

O vizinho mais próximo

Vamos iniciar com o método do vizinho mais próximo.

# O vizinho mais proximo
m <- hclust(D_E, method = "single")
m$height
##  [1]  2.291863  3.842566  3.932045  6.238535  6.641778  7.356842  7.934484
##  [8]  8.031794  8.540646  8.766984  9.508521 10.305404 10.579231 10.922844
## [15] 11.071967 11.256321 11.461496 11.528739 11.766781 12.625298 13.045817
## [22] 13.300617 13.897105 14.501039 15.016435 15.068436 15.456981 15.504785
## [29] 16.068275 16.652992 16.816104 17.163838 18.715460 18.854213 19.701654
## [36] 19.920486 20.829570 21.167561 22.853147 23.195718 23.430697 23.643593
## [43] 24.708653 24.923564 25.747428 25.843604 27.556912 37.788912 38.534538
plot(m, cex = 0.7, hang = -1,
     main = "Dendograma - O vizinho mais próximo",
     xlab = "Estados", ylab = "")

O vizinho mais distante

Agora vamos para o método do vizinho mais distante.

m <- hclust(D_E, method = "complete")
m$height
##  [1]   2.291863   3.842566   3.932045   6.238535   6.641778   7.356842
##  [7]   8.031794   8.540646  10.860441  11.461496  12.425773  12.625298
## [13]  12.777374  13.045817  13.300617  13.354127  13.897105  14.501039
## [19]  15.416320  15.456981  15.631725  15.890349  16.998284  18.265170
## [25]  19.438594  19.904697  21.167561  22.376177  22.767529  24.895798
## [31]  25.094887  28.636468  29.251698  31.477346  31.621581  32.722227
## [37]  36.739860  36.848995  38.534538  41.491541  48.732526  53.594343
## [43]  57.271719  64.994674  68.775142  87.331230 102.865070 168.629805
## [49] 293.639928
plot(m, cex = 0.7, hang = -1,
     main = "Dendograma - O vizinho mais distante",
     xlab = "Estados", ylab = "")

Centroide

Agora utilizando o método do centroide.

m <- hclust(D_E, method = "centroid")
m$height
##  [1]   2.291863   3.842566   3.932045   6.238535   6.641778   7.356842
##  [7]   8.031794   8.540646   8.637018   8.899426   9.611515   9.675119
## [13]  10.364569   9.378527  11.461496  11.480792  11.808084  11.959271
## [19]  12.209114  12.625298  13.045817  13.300617  13.538437  13.897105
## [25]  11.979116  14.501039  15.262767  15.316522  16.477143  16.816104
## [31]  15.146299  17.043967  19.542440  19.969351  16.733851  21.027665
## [37]  21.167561  22.369746  22.804800  21.434675  23.034681  22.596466
## [43]  25.145353  29.478992  34.027865  38.534538  51.321137  54.450146
## [49] 100.090001
plot(m, cex = 0.7, hang = -1,
     main = "Dendograma - Centroide",
     xlab = "Estados", ylab = "")

Ligação média

E, para finalizar os método de clustering hierárquico vistos em sala, vamos fazer o método da ligação média.

m <- hclust(D_E, method = "average")
m$height
##  [1]   2.291863   3.842566   3.932045   6.238535   6.641778   7.356842
##  [7]   8.031794   8.540646  10.184481  10.738637  10.772179  11.461496
## [13]  12.441433  12.625298  12.878910  13.045817  13.300617  13.355529
## [19]  13.897105  14.501039  15.030098  15.125594  15.453392  15.456981
## [25]  16.426042  16.907194  18.423225  18.995012  20.200291  20.600798
## [31]  21.167561  22.599234  23.974017  26.370293  26.715015  27.781761
## [37]  28.012891  28.096690  29.058723  33.118936  38.534538  39.396599
## [43]  41.098395  44.285491  44.845174  54.751110  77.607316  89.237776
## [49] 152.321117
plot(m, cex = 0.7, hang = -1,
     main = "Dendograma - Ligação Média",
     xlab = "Estados", ylab = "")

K-means

Para a análise de cluster, também podemos utilizar o método do k-means. Porém, como a plotagem necessita de componentes principais, então não vamos fazê-la. O número de grupos igual a 2 vem da ideia de criar o cluster de estados perigosos e o cluster de estados seguros. O grupo que conter Florida será considerado perigoso (por conta dos rankings) e o grupo que conter North Dakota será considerado seguro.

set.seed(548254)
km <- kmeans(dados_num, centers = 2)

# Cluster 1
cat("Cluster 1:\n", paste(rownames(dados_num)[km$cluster == 1], collapse = "\n"), "\n\n")
## Cluster 1:
##  Connecticut
## Hawaii
## Idaho
## Indiana
## Iowa
## Kansas
## Kentucky
## Maine
## Massachusetts
## Minnesota
## Missouri
## Montana
## Nebraska
## New Hampshire
## New Jersey
## North Dakota
## Ohio
## Oklahoma
## Oregon
## Pennsylvania
## Rhode Island
## South Dakota
## Utah
## Vermont
## Virginia
## Washington
## West Virginia
## Wisconsin
## Wyoming
# Cluster 2
cat("Cluster 2:\n", paste(rownames(dados_num)[km$cluster == 2], collapse = "\n"), "\n\n")
## Cluster 2:
##  Alabama
## Alaska
## Arizona
## Arkansas
## California
## Colorado
## Delaware
## Florida
## Georgia
## Illinois
## Louisiana
## Maryland
## Michigan
## Mississippi
## Nevada
## New Mexico
## New York
## North Carolina
## South Carolina
## Tennessee
## Texas

4 Conclusão

De forma respectiva, os estados mais perigosos para se morar é Florida e Nevada, enquanto os mais seguros são Vermont e North Dakota.

LS0tDQp0aXRsZTogJ0Fuw6FsaXNlIE11bHRpdmFyaWFkYScNCmF1dGhvcjogJypKb25hcyBGcmVpcmUgUmliZWlybyAtIDU0ODI1NConDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICcqJWQgZGUgJUIsICAlWSonKWAiDQpsaW5rLWNpdGF0aW9uczogdHJ1ZQ0KbGFuZzogInB0LWJyIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOg0KICAgICAgYm9vdHN3YXRjaDogZmxhdGx5DQogICAgaGlnaGxpZ2h0OiBicmVlemVkYXJrDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgYW5jaG9yX3NlY3Rpb25zOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGZpZ19jYXB0aW9uOiB0cnVlDQogICAgY2l0YXRpb25fcGFja2FnZTogYmlibGF0ZXgNCi0tLQ0KDQojIERhZG9zDQoNCk9zIGRhZG9zIGBVU0FycmVzdHNgIGZvcmFtIHV0aWxpemFkb3MgbmEgYXVsYSBwYXJhIHJlYWxpemFyIGEgYW7DoWxpc2UuDQoNCmBgYHtyIHJlc3VsdHM9J2hpZGUnLCBlY2hvPUZBTFNFfQ0KaW5zdGFsbC5wYWNrYWdlcygia2FibGVFeHRyYSIpDQoNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkoa25pdHIpDQpgYGANCg0KDQpgYGB7cn0NCmRhdGEoIlVTQXJyZXN0cyIpDQpkYWRvcyA8LSBVU0FycmVzdHMNCg0Ka25pdHI6OmthYmxlKGhlYWQoZGFkb3MsIDEwKSkgfD4gDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIikgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCkRlIGFjb3JkbyBjb20gbyBjaGF0IGdwdCwgbyBgVVNBcnJlc3RzYCDDqSB1bSBmYW1vc28gY29uanVudG8gZGUgZGFkb3MgZW1idXRpZG8gbm8gUiwgcXVlIGNvbnTDqW0gaW5mb3JtYcOnw7VlcyBzb2JyZSBvcyBjcmltZXMgdmlvbGVudG9zIGNvbWV0aWRvcyBub3MgRXN0YWRvcyBVbmlkb3Mgbm9zIGFub3MgMTk3MC4gQXMgY29sdW5hcyByZXByZXNlbnRhbSBlc3RhdMOtc3RpY2FzIHNvYnJlIGEgdGF4YSBkZSBjcmltZXMgcG9yIGVzdGFkby4gQ2FkYSBsaW5oYSBkbyBjb25qdW50byBkZSBkYWRvcyBjb3JyZXNwb25kZSBhIHVtIGVzdGFkbyBkb3MgRVVBLiBTZWd1ZSBvIHF1ZSByZXByZXNlbnRhIGNhZGEgdW1hIGRhcyBjb2x1bmFzIGRvIGNvbmp1bnRvIGRlIGRhZG9zOg0KDQoxLiAqKk11cmRlcioqOiBUYXhhIGRlIGhvbWljw61kaW9zIChhc3Nhc3NpbmF0b3MpIHBvciAxMDAuMDAwIGhhYml0YW50ZXMuDQoxLiAqKkFzc2F1bHQqKjogVGF4YSBkZSBhZ3Jlc3PDtWVzIChhc3NhbHRvcykgcG9yIDEwMC4wMDAgaGFiaXRhbnRlcy4NCjEuICoqVXJiYW5Qb3AqKjogUGVyY2VudHVhbCBkYSBwb3B1bGHDp8OjbyBkbyBlc3RhZG8gcXVlIHZpdmUgZW0gw6FyZWFzIHVyYmFuYXMuDQoxLiAqKlJhcGUqKjogVGF4YSBkZSBlc3R1cHJvcyBwb3IgMTAwLjAwMCBoYWJpdGFudGVzLg0KDQojIEFuw6FsaXNlIEV4cGxvcmF0w7NyaWENCg0KIyMgQ8OhbGN1bG8gZGUgbWVkaWRhcyBkZXNjcml0aXZhcw0KDQpJbmljaWFsbWVudGUsIHZhbW9zIGNhbGN1bGFyIGFzIG1lZGlkYXMgZGVzY3JpdGl2YXMgZG9zIGRhZG9zLg0KYGBge3J9DQpyZXN1bW8gPC0gc3VtbWFyeShkYWRvcyk7IHJlc3Vtbw0KYGBgDQpBZ29yYSB2YW1vcyBjYWxjdWxhciBtZWRpZGFzIGRlIHZhcmlhYmlsaWRhZGUuDQpgYGB7ciBjb2xsYXBzZT1UUlVFfQ0KdmFyKGRhZG9zJE11cmRlcik7IHZhcihkYWRvcyRBc3NhdWx0KTsgdmFyKGRhZG9zJFVyYmFuUG9wKTsgdmFyKGRhZG9zJFJhcGUpICMgdmFyacOibmNpYXMNCg0KczEgPC0gc2QoZGFkb3MkTXVyZGVyKTsgczEgICMgZGVzdmlvcyBwYWRyb2VzDQpzMiA8LSBzZChkYWRvcyRBc3NhdWx0KTsgczINCnMzIDwtIHNkKGRhZG9zJFVyYmFuUG9wKTtzMw0KczQgPC0gc2QoZGFkb3MkUmFwZSk7IHM0DQoNCnMxL21lYW4oZGFkb3MkTXVyZGVyKSAjIGNvZWZpY2llbnRlcyBkZSB2YXJpYcOnw6NvDQpzMi9tZWFuKGRhZG9zJEFzc2F1bHQpDQpzMy9tZWFuKGRhZG9zJFVyYmFuUG9wKQ0KczQvbWVhbihkYWRvcyRSYXBlKQ0KYGBgDQoNCiMjIFBsb3RhZ2VtIGRlIGdyw6FmaWNvcw0KDQpBZ29yYSB2YW1vcyBmYXplciBoaXN0b2dyYW1hcyBwYXJhIHZlcmlmaWNhciBhIGFzc2ltZXRyaWEgZG9zIGRhZG9zLg0KYGBge3IgY29sbGFwc2U9VFJVRX0NCm9wYXIgPC0gcGFyKG1mcm93ID0gYygyLCAyKSkNCmhpc3QoZGFkb3MkTXVyZGVyLCBtYWluID0gIlRheGEgZGUgaG9taWPDrWRpb3MiLCBjb2wgPSAibGlnaHRncmVlbiIpDQpoaXN0KGRhZG9zJEFzc2F1bHQsIG1haW4gPSAiVGF4YSBkZSBhZ3Jlc3PDtWVzIiwgY29sID0gInJlZCIpDQpoaXN0KGRhZG9zJFVyYmFuUG9wLCBtYWluID0gIlBlcmNlbnR1YWwgZGEgcG9wdWxhw6fDo28gZGUgw6FyZWFzIHVyYmFuYXMiLCBjb2wgPSAiYmx1ZSIpDQpoaXN0KGRhZG9zJFJhcGUsIG1haW4gPSAiVGF4YSBkZSBlc3R1cHJvcyIsIGNvbCA9ICJvcmFuZ2UiKQ0KYGBgDQoNCkFnb3JhIHZhbW9zIHZlcmlmaWNhciBhIHByZXNlbsOnYSBkZSBkYWRvcyBhdMOtcGljb3MgZSBkZSBhc3NpbWV0cmlhIHBvciBtZWlvIGRlIGJveHBsb3RzLg0KYGBge3J9DQpvcGFyIDwtIHBhcihtZnJvdyA9IGMoMiwgMikpDQpib3hwbG90KGRhZG9zJE11cmRlciwgbWFpbiA9ICJUYXhhIGRlIGhvbWljaWRpb3MiLCBjb2wgPSAibGlnaHRncmVlbiIpDQpib3hwbG90KGRhZG9zJEFzc2F1bHQsIG1haW4gPSAiVGF4YSBkZSBhZ3Jlc3NvZXMiLCBjb2wgPSAicmVkIikNCmJveHBsb3QoZGFkb3MkVXJiYW5Qb3AsIG1haW4gPSAiUGVyY2VudHVhbCBkYSBwb3B1bGFjYW8gZGUgYXJlYXMgdXJiYW5hcyIsIGNvbCA9ICJibHVlIikNCmJveHBsb3QoZGFkb3MkUmFwZSwgbWFpbiA9ICJUYXhhIGRlIGVzdHVwcm9zIiwgY29sID0gIm9yYW5nZSIpDQpgYGANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmIgPC0gYm94cGxvdChkYWRvcyRSYXBlLCBtYWluID0gIlRheGEgZGUgZXN0dXByb3MiLCBjb2wgPSAib3JhbmdlIikNCm91dF92YWx1ZXMgPC0gYiRvdXQNCm91dF9zdGF0ZXMgPC0gcm93bmFtZXMoZGFkb3MpW2RhZG9zJFJhcGUgJWluJSBvdXRfdmFsdWVzXQ0KYGBgDQoNCmBgYHtyIGVjaG89RkFMU0V9DQpjYXQoIk9zIG91dGxpZXJzIGRvIGJveHBsb3QgZGEgdGF4YSBkZSBlc3R1cHJvcyDDqSByZWZlcmVudGUgYW9zIGVzdGFkb3M6Iiwgb3V0X3N0YXRlc1sxXSwgImUiLCBvdXRfc3RhdGVzWzJdLCJcbiIpDQpgYGANCg0KDQojIyBFbSBidXNjYSBkbyBlc3RhZG8gbWFpcyB2aW9sZW50byBlIG1lbm9zIHZpb2xlbnRvDQoNCiMjIyBSYW5xdWVhbWVudG8gcGFyYSBjYWRhIHZhcmnDoXZlbCB7LnRhYnNldCAudGFic2V0LWZhZGV9DQoNCiMjIyMgSG9taWPDrWRpb3Mgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KVmFtb3Mgb3JkZXJuYXIgb3MgZGFkb3MgZSB2ZXJpZmljYXIgb3MgNSBlc3RhZG9zIGNvbSBtYWlvciBlIG1lbm9yIHRheGEgZGUgaG9tw61jaWRpb3MuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmxpYnJhcnkoImRwbHlyIikNCmBgYA0KDQpgYGB7cn0NCm1haW9yIDwtIGhlYWQoYXJyYW5nZShkYWRvcywgZGVzYyhNdXJkZXIpKSwgNSkNCm1lbm9yIDwtIGhlYWQoYXJyYW5nZShkYWRvcywgTXVyZGVyKSwgNSkNCg0KY2F0KCI1IGVzdGFkb3MgY29tIG1haW9yIHRheGEgZGUgaG9taWPDrWRpb3M6XG4iLA0KICAgIHBhc3RlKHJvd25hbWVzKG1haW9yKSwgY29sbGFwc2UgPSAiXG4iKSkNCg0KDQpjYXQoIjUgZXN0YWRvcyBjb20gbWVub3IgdGF4YSBkZSBob21pY8OtZGlvczpcbiIsDQogICAgcGFzdGUocm93bmFtZXMobWVub3IpLCBjb2xsYXBzZSA9ICJcbiIpKQ0KYGBgDQoNCiMjIyMgQWdyZXNzw7VlcyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQ0KDQpWYW1vcyB2ZXJpZmljYXIgb3MgNSBlc3RhZG9zIGNvbSBtYWlvciBlIG1lbm9yIHRheGEgZGUgYWdyZXNzw7Vlcy4NCg0KYGBge3J9DQptYWlvciA8LSBoZWFkKGFycmFuZ2UoZGFkb3MsIGRlc2MoQXNzYXVsdCkpLCA1KQ0KbWVub3IgPC0gaGVhZChhcnJhbmdlKGRhZG9zLCBBc3NhdWx0KSwgNSkNCg0KY2F0KCI1IGVzdGFkb3MgY29tIG1haW9yIHRheGEgZGUgYWdyZXNzw7VlczpcbiIsDQogICAgcGFzdGUocm93bmFtZXMobWFpb3IpLCBjb2xsYXBzZSA9ICJcbiIpKQ0KDQoNCmNhdCgiNSBlc3RhZG9zIGNvbSBtZW5vciB0YXhhIGRlIGFncmVzc8O1ZXM6XG4iLA0KICAgIHBhc3RlKHJvd25hbWVzKG1lbm9yKSwgY29sbGFwc2UgPSAiXG4iKSkNCmBgYA0KDQojIyMjIHBvcHVsYcOnw6NvIGRlIMOhcmVhcyBodXJiYW5hcyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQ0KDQpBZ29yYSB2YW1vcyB2ZXJpZmljYXIgcXVhaXMgb3MgNSBlc3RhZG9zIGNvbSBtYWlvciBlIG1lbm9yIHBlcmNlbnR1YWwgZGEgcG9wdWxhw6fDo28gZG8gZXN0YWRvIHF1ZSB2aXZlIGVtIMOhcmVhcyBodXJiYW5hcy4NCmBgYHtyfQ0KbWVub3IgPC0gaGVhZChhcnJhbmdlKGRhZG9zLCBVcmJhblBvcCksIDUpDQptYWlvciA8LSBoZWFkKGFycmFuZ2UoZGFkb3MsIGRlc2MoVXJiYW5Qb3ApKSwgNSkNCg0KY2F0KCI1IGVzdGFkb3MgY29tIG1haW9yIHBlcmNlbnR1YWwgZGEgcG9wdWxhw6fDo28gcXVlIHZpdmUgZW0gw6FyZWFzIGh1cmJhbmFzOlxuIiwNCiAgICBwYXN0ZShyb3duYW1lcyhtYWlvciksIGNvbGxhcHNlID0gIlxuIikpDQoNCg0KY2F0KCI1IGVzdGFkb3MgY29tIG1lbm9yIHBlcmNlbnR1YWwgZGEgcG9wdWxhw6fDo28gcXVlIHZpdmUgZW0gw6FyZWFzIGh1cmJhbmFzOlxuIiwNCiAgICBwYXN0ZShyb3duYW1lcyhtZW5vciksIGNvbGxhcHNlID0gIlxuIikpDQpgYGANCg0KIyMjIyBFc3R1cHJvcyB7LnVubGlzdGVkIC51bm51bWJlcmVkfQ0KVmFtb3MgdmVyaWZpY2FyIHF1YWlzIG9zIDUgZXN0YWRvcyBjb20gbWFpb3IgZSBtZW5vciB0YXhhIGRlIGVzdHVwcm9zLg0KYGBge3J9DQptZW5vciA8LSBoZWFkKGFycmFuZ2UoZGFkb3MsIFJhcGUpLCA1KQ0KbWFpb3IgPC0gaGVhZChhcnJhbmdlKGRhZG9zLCBkZXNjKFJhcGUpKSwgNSkNCg0KY2F0KCI1IGVzdGFkb3MgY29tIG1haW9yIHRheGEgZGUgZXN0dXByb3M6XG4iLA0KICAgIHBhc3RlKHJvd25hbWVzKG1haW9yKSwgY29sbGFwc2UgPSAiXG4iKSkNCg0KDQpjYXQoIjUgZXN0YWRvcyBjb20gbWVub3IgdGF4YSBkZSBlc3R1cHJvczpcbiIsDQogICAgcGFzdGUocm93bmFtZXMobWVub3IpLCBjb2xsYXBzZSA9ICJcbiIpKQ0KYGBgDQoNCiMjIyBDcmlhbmRvIGEgdmFyacOhdmVsIHF1ZSBtZWRlIG8gbsOtdmVsIGRlIHZpb2zDqm5jaWENCg0KVmFtb3MgaW5pY2lhciBwYWRyb25pemFuZG8gY2FkYSB1bWEgZGFzIHZhcmnDoXZlaXMuDQoNCmBgYHtyfQ0Kel9tdXJkZXIgPC0gKGRhZG9zJE11cmRlciAtIG1lYW4oZGFkb3MkTXVyZGVyKSkvczENCnpfYXNzYXVsdCA8LSAoZGFkb3MkQXNzYXVsdCAtIG1lYW4oZGFkb3MkQXNzYXVsdCkpL3MyDQp6X3VyYmFucG9wCSA8LSAoZGFkb3MkVXJiYW5Qb3AJIC0gbWVhbihkYWRvcyRVcmJhblBvcCkpL3MzDQp6X3JhcGUJIDwtIChkYWRvcyRSYXBlCSAtIG1lYW4oZGFkb3MkUmFwZSkpL3M0DQoNCmRhZG9zX3BhZCA8LSBjYmluZCh6X211cmRlciwgel9hc3NhdWx0LCB6X3VyYmFucG9wLCB6X3JhcGUpDQpgYGANCg0KVmFtb3MgY3JpYXIgYSBwYXJ0aXIgZGVzc2VzIGRhZG9zIGEgdmFyacOhdmVsIGB2aW9sZW5jaWFgIHBvciBtZWlvIGRhIG3DqWRpYSBkYXMgdmFyacOhdmVpcy4NCmBgYHtyfQ0KdmlvbGVuY2lhIDwtIHJvd01lYW5zKGRhZG9zX3BhZCkNCg0KZGFkb3MgPC0gY2JpbmQoZGFkb3MsIHZpb2xlbmNpYSkNCg0Ka25pdHI6OmthYmxlKGhlYWQoZGFkb3MsIDEwKSkgfD4gDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIikgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCiMjIyBPcmRlbmFuZG8gb3MgZXN0YWRvcyBjb20gbWFpb3IgZSBtZW5vciBuw612ZWwgZGUgdmlvbMOqbmNpYS4NCg0KVmFtb3MgY3JpYXIgdW0gcmFua2luZyBkb3MgZXN0YWRvcyBtYWlzIHZpb2xlbnRhcyBkZSBhY29yZG8gY29tIGEgdmFyacOhdmVsIGNyaWFkYS4NCmBgYHtyfQ0KbWVub3IgPC0gaGVhZChhcnJhbmdlKGRhZG9zLCB2aW9sZW5jaWEpLCA1KQ0KbWFpb3IgPC0gaGVhZChhcnJhbmdlKGRhZG9zLCBkZXNjKHZpb2xlbmNpYSkpLCA1KQ0KDQpjYXQoIjUgZXN0YWRvcyBtYWlzIHZpb2xlbnRvczpcbiIsDQogICAgcGFzdGUocm93bmFtZXMobWFpb3IpLCBjb2xsYXBzZSA9ICJcbiIpKQ0KDQoNCmNhdCgiNSBlc3RhZG9zIG1lbm9zIHZpb2xlbnRvczpcbiIsDQogICAgcGFzdGUocm93bmFtZXMobWVub3IpLCBjb2xsYXBzZSA9ICJcbiIpKQ0KYGBgDQoNCkNvbW8gZXUgbsOjbyBhY2hvIHJhem/DoXZlbCBmYXplciB1bWEgbcOpZGlhIChwb3JxdWUgZXN0YW1vcyBhdHJpYnVpbmRvIG8gbWVzbW8gcGVzbyBhIHZhcmnDoXZlaXMgcXVlIHBvZGVtIGltcGFjdGFyIGVtIGRpZmVyZW50ZXMgbsOtdmVpcyBuYSB2aW9sw6puY2lhIGRvIGVzdGFkbyksIGVudMOjbyBzZXLDoSBmZWl0byB1bWEgw6Fydm9yZSBkZSBkZWNpc8OjbyBwYXJhIHNhYmVyIHF1YWlzIGFzIHZhcmnDoXZlaXMgcXVlIG1haXMgaW1wYWN0YXJhbSBubyBuw612ZWwgZGUgdmlvbMOqbmNpYS4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQppbnN0YWxsLnBhY2thZ2VzKCJycGFydCIpDQppbnN0YWxsLnBhY2thZ2VzKCJycGFydC5wbG90IikNCmxpYnJhcnkocnBhcnQpDQpsaWJyYXJ5KHJwYXJ0LnBsb3QpDQpgYGANCg0KDQpgYGB7cn0NCiMgZGl2aXNhbyBlbSB0cmVpbm8gZSB0ZXN0ZQ0KDQpzZXQuc2VlZCgzMjEpDQoNCmluZGljZV90cmVpbm8gPC0gc2FtcGxlKDE6bnJvdyhkYWRvcyksIHNpemUgPSAwLjcgKiBucm93KGRhZG9zKSkgIyA3MCUgZG8gYmQgw6kgcGFyYSB0cmVpbm8NCg0KYmRfdHJlaW5vIDwtIGRhZG9zW2luZGljZV90cmVpbm8sIF0NCmJkX3Rlc3RlICA8LSBkYWRvc1staW5kaWNlX3RyZWlubywgXQ0KDQojIGFydm9yZSBkZSBkZWNpc2FvDQoNCmFydm9yZV9jYXJ0X2NvbXBsZXRhIDwtIHJwYXJ0KA0KICBmb3JtdWxhID0gdmlvbGVuY2lhIH4gLiwgICAgICAgIA0KICBkYXRhID0gYmRfdHJlaW5vLCAgICAgICAgICAgICAgICAgICANCiAgbWV0aG9kID0gImFub3ZhIiAjIHJlZ3Jlc3Nhbw0KKQ0KDQojIFBsb3RhbmRvDQpycGFydC5wbG90KGFydm9yZV9jYXJ0X2NvbXBsZXRhLA0KICAgICAgICAgICB0eXBlID0gMCwNCiAgICAgICAgICAgZXh0cmEgPSAxMDEsDQogICAgICAgICAgIGZhbGxlbi5sZWF2ZXMgPSBUUlVFKQ0KDQojIHZhcmlhdmVpcyBtYWlzIGltcG9ydGFudGVzDQppbXBvcnRhbmNpYSA8LSBhcnZvcmVfY2FydF9jb21wbGV0YSR2YXJpYWJsZS5pbXBvcnRhbmNlOyBpbXBvcnRhbmNpYQ0KYGBgDQoNCg0KQXMgZHVhcyB2YXJpw6F2ZWlzIG1haXMgaW1wb3J0YW50ZXMgZm9yYW0gYEFzc2F1bHRgIGUgYE11cmRlcmAuIFNlcsOjbyBjb25zaWRlcmFkYXMgdG9kYXMgYXMgdmFyacOhdmVpcyBuYSBjcmlhw6fDo28gZGEgdmFyacOhdmVsIGB2aW9sZW5jaWFgLCBhdHJpYnVpbmRvIGNvbW8gcGVzbyBhIGNvbnRyaWJ1acOnw6NvIGRlbGFzIG5hIMOhcnZvcmUuDQoNCmBgYHtyfQ0KaW1wb3J0YW5jaWEgPC0gaW1wb3J0YW5jaWEvc3VtKGltcG9ydGFuY2lhKQ0KDQp2aW9sZW5jaWEgPC0gDQogIHpfYXNzYXVsdCppbXBvcnRhbmNpYVsxXSArDQogIHpfbXVyZGVyKmltcG9ydGFuY2lhWzJdICsNCiAgel9yYXBlKmltcG9ydGFuY2lhWzNdICsNCiAgel91cmJhbnBvcCppbXBvcnRhbmNpYVs0XSAJDQoNCmRhZG9zJHZpb2xlbmNpYSA8LSB2aW9sZW5jaWENCg0Ka25pdHI6OmthYmxlKGhlYWQoZGFkb3MsIDEwKSkgfD4gDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIsICJyZXNwb25zaXZlIikgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCkVzc2Egbm92YSB2YXJpw6F2ZWwgYHZpb2xlbmNpYWAgcmVzdWx0YSBub3Mgc2VndWludGVzIHJhbmtpbmdzLg0KYGBge3J9DQptZW5vciA8LSBoZWFkKGFycmFuZ2UoZGFkb3MsIHZpb2xlbmNpYSksIDUpDQptYWlvciA8LSBoZWFkKGFycmFuZ2UoZGFkb3MsIGRlc2ModmlvbGVuY2lhKSksIDUpDQoNCmNhdCgiNSBlc3RhZG9zIG1haXMgdmlvbGVudG9zOlxuIiwNCiAgICBwYXN0ZShyb3duYW1lcyhtYWlvciksIGNvbGxhcHNlID0gIlxuIikpDQoNCg0KY2F0KCI1IGVzdGFkb3MgbWVub3MgdmlvbGVudG9zOlxuIiwNCiAgICBwYXN0ZShyb3duYW1lcyhtZW5vciksIGNvbGxhcHNlID0gIlxuIikpDQpgYGANCg0KDQojIEFuw6FsaXNlIGRlIENsdXN0ZXIgey50YWJzZXQgLnRhYnNldC1mYWRlfQ0KDQpBZ29yYSB2YW1vcyBmYXplciB1bWEgYnJldmUgYW7DoWxpc2UgZGUgY2x1c3RlciBwYXJhIHZlcmlmaWNhciBxdWFpcyBvcyBlc3RhZG9zIG1haXMgc2VtZWxoYW50ZXMuIFByaW1laXJhbWVudGUgY2FsY3VsYW1vcyBhIG1hdHJpeiBkZSBkaXN0w6JuY2lhcyBldWNsaWRpYW5hcy4NCmBgYHtyfQ0KZGFkb3NfbnVtIDwtIGFzLm1hdHJpeChkYWRvcykNCkRfRSA8LSBkaXN0KGRhZG9zX251bSwgbWV0aG9kID0gImV1Y2xpZGlhbiIpDQpgYGANCg0KIyMgTyB2aXppbmhvIG1haXMgcHLDs3hpbW8gey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KVmFtb3MgaW5pY2lhciBjb20gbyBtw6l0b2RvIGRvIHZpemluaG8gbWFpcyBwcsOzeGltby4NCmBgYHtyIGNvbGxhcHNlPVRSVUV9DQojIE8gdml6aW5obyBtYWlzIHByb3hpbW8NCm0gPC0gaGNsdXN0KERfRSwgbWV0aG9kID0gInNpbmdsZSIpDQptJGhlaWdodA0KcGxvdChtLCBjZXggPSAwLjcsIGhhbmcgPSAtMSwNCiAgICAgbWFpbiA9ICJEZW5kb2dyYW1hIC0gTyB2aXppbmhvIG1haXMgcHLDs3hpbW8iLA0KICAgICB4bGFiID0gIkVzdGFkb3MiLCB5bGFiID0gIiIpDQpgYGANCg0KIyMgTyB2aXppbmhvIG1haXMgZGlzdGFudGUgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KQWdvcmEgdmFtb3MgcGFyYSBvIG3DqXRvZG8gZG8gdml6aW5obyBtYWlzIGRpc3RhbnRlLg0KYGBge3IgY29sbGFwc2U9VFJVRX0NCm0gPC0gaGNsdXN0KERfRSwgbWV0aG9kID0gImNvbXBsZXRlIikNCm0kaGVpZ2h0DQpwbG90KG0sIGNleCA9IDAuNywgaGFuZyA9IC0xLA0KICAgICBtYWluID0gIkRlbmRvZ3JhbWEgLSBPIHZpemluaG8gbWFpcyBkaXN0YW50ZSIsDQogICAgIHhsYWIgPSAiRXN0YWRvcyIsIHlsYWIgPSAiIikNCmBgYA0KDQojIyBDZW50cm9pZGUgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KQWdvcmEgdXRpbGl6YW5kbyBvIG3DqXRvZG8gZG8gY2VudHJvaWRlLg0KYGBge3IgY29sbGFwc2U9VFJVRX0NCm0gPC0gaGNsdXN0KERfRSwgbWV0aG9kID0gImNlbnRyb2lkIikNCm0kaGVpZ2h0DQpwbG90KG0sIGNleCA9IDAuNywgaGFuZyA9IC0xLA0KICAgICBtYWluID0gIkRlbmRvZ3JhbWEgLSBDZW50cm9pZGUiLA0KICAgICB4bGFiID0gIkVzdGFkb3MiLCB5bGFiID0gIiIpDQpgYGANCg0KIyMgTGlnYcOnw6NvIG3DqWRpYSB7LnVubGlzdGVkIC51bm51bWJlcmVkfQ0KDQpFLCBwYXJhIGZpbmFsaXphciBvcyBtw6l0b2RvIGRlIGNsdXN0ZXJpbmcgaGllcsOhcnF1aWNvIHZpc3RvcyBlbSBzYWxhLCB2YW1vcyBmYXplciBvIG3DqXRvZG8gZGEgbGlnYcOnw6NvIG3DqWRpYS4NCmBgYHtyIGNvbGxhcHNlPVRSVUV9DQptIDwtIGhjbHVzdChEX0UsIG1ldGhvZCA9ICJhdmVyYWdlIikNCm0kaGVpZ2h0DQpwbG90KG0sIGNleCA9IDAuNywgaGFuZyA9IC0xLA0KICAgICBtYWluID0gIkRlbmRvZ3JhbWEgLSBMaWdhw6fDo28gTcOpZGlhIiwNCiAgICAgeGxhYiA9ICJFc3RhZG9zIiwgeWxhYiA9ICIiKQ0KYGBgDQoNCiMjIEstbWVhbnMgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KUGFyYSBhIGFuw6FsaXNlIGRlIGNsdXN0ZXIsIHRhbWLDqW0gcG9kZW1vcyB1dGlsaXphciBvIG3DqXRvZG8gZG8gay1tZWFucy4gUG9yw6ltLCBjb21vIGEgcGxvdGFnZW0gbmVjZXNzaXRhIGRlIGNvbXBvbmVudGVzIHByaW5jaXBhaXMsIGVudMOjbyBuw6NvIHZhbW9zIGZhesOqLWxhLiBPIG7Dum1lcm8gZGUgZ3J1cG9zIGlndWFsIGEgMiB2ZW0gZGEgaWRlaWEgZGUgY3JpYXIgbyBjbHVzdGVyIGRlIGVzdGFkb3MgcGVyaWdvc29zIGUgbyBjbHVzdGVyIGRlIGVzdGFkb3Mgc2VndXJvcy4gTyBncnVwbyBxdWUgY29udGVyIEZsb3JpZGEgc2Vyw6EgY29uc2lkZXJhZG8gcGVyaWdvc28gKHBvciBjb250YSBkb3MgcmFua2luZ3MpIGUgbyBncnVwbyBxdWUgY29udGVyIE5vcnRoIERha290YSBzZXLDoSBjb25zaWRlcmFkbyBzZWd1cm8uDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQppbnN0YWxsLnBhY2thZ2VzKCJmYWN0b2V4dHJhIikNCnJlcXVpcmUoZ2dwbG90MikNCnJlcXVpcmUoZmFjdG9leHRyYSkNCmBgYA0KDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoNTQ4MjU0KQ0Ka20gPC0ga21lYW5zKGRhZG9zX251bSwgY2VudGVycyA9IDIpDQoNCiMgQ2x1c3RlciAxDQpjYXQoIkNsdXN0ZXIgMTpcbiIsIHBhc3RlKHJvd25hbWVzKGRhZG9zX251bSlba20kY2x1c3RlciA9PSAxXSwgY29sbGFwc2UgPSAiXG4iKSwgIlxuXG4iKQ0KDQojIENsdXN0ZXIgMg0KY2F0KCJDbHVzdGVyIDI6XG4iLCBwYXN0ZShyb3duYW1lcyhkYWRvc19udW0pW2ttJGNsdXN0ZXIgPT0gMl0sIGNvbGxhcHNlID0gIlxuIiksICJcblxuIikNCmBgYA0KDQojIENvbmNsdXPDo28NCg0KRGUgZm9ybWEgcmVzcGVjdGl2YSwgb3MgZXN0YWRvcyBtYWlzIHBlcmlnb3NvcyBwYXJhIHNlIG1vcmFyIMOpIGBGbG9yaWRhYCBlIGBOZXZhZGFgLCBlbnF1YW50byBvcyBtYWlzIHNlZ3Vyb3Mgc8OjbyBgVmVybW9udGAgZSBgTm9ydGggRGFrb3RhYC4=