Instruções

Ambiente

1 Leitura e limpeza dos dados

  1. Os nomes das colunas originais estão em inglês. Para ver o dicionário de dados — documentação sobre cada uma das colunas — visite https://www.kaggle.com/datasets/crisparada/brazilian-cities?select=Data_Dictionary.csv.

  2. Eis uma função para renomear as colunas para português. Ela simplesmente retorna um vetor com os novos nomes, na mesma ordem que as colunas originais.

    renomear <- function(x) {
    
      c(
        'cidade',
        'estado',
        'capital',
        'pop_resid',
        'pop_resid_bras',
        'pop_resid_estr',
        'unidades_domest',
        'unidades_domest_urban',
        'unidades_domest_rural',
        'pop_regular',
        'pop_regular_1',
        'pop_regular_1_4',
        'pop_regular_5_9',
        'pop_regular_10_14',
        'pop_regular_15_59',
        'pop_regular_60_mais',
        'area_cultivada',
        'producao_rural',
        'idhm_ranking',
        'idhm',
        'idhm_renda',
        'idhm_longevidade',
        'idhm_educacao',
        'longitude',
        'latitude',
        'altitude',
        'tv_assinatura',
        'telefones_fixos',
        'area',
        'regiao_turismo',
        'categoria_turismo',
        'pop_estimada',
        'tipo',
        'gva_agropec',
        'gva_industria',
        'gva_servicos',
        'gva_publico',
        'gva_total',
        'impostos',
        'pib',
        'pop_pib',
        'pib_capita',
        'atividade_principal',
        'despesas_municipais',
        'empresas_tot',
        'empresas_a',
        'empresas_b',
        'empresas_c',
        'empresas_d',
        'empresas_e',
        'empresas_f',
        'empresas_g',
        'empresas_h',
        'empresas_i',
        'empresas_j',
        'empresas_k',
        'empresas_l',
        'empresas_m',
        'empresas_n',
        'empresas_o',
        'empresas_p',
        'empresas_q',
        'empresas_r',
        'empresas_s',
        'empresas_t',
        'empresas_u',
        'hoteis',
        'camas',
        'agencias_priv',
        'agencias_publ',
        'bancos_priv',
        'bancos_publ',
        'patrimonio_bancos_priv',
        'patrimonio_bancos_publ',
        'carros',
        'motos',
        'tratores',
        'uber',
        'mac',
        'walmart',
        'correios'
      )
    
    }
  3. Ler os dados, renomear as colunas e mudar o tipo de duas delas:

    cidades <- read_csv(
      'dados/BRAZIL_CITIES_REV2022.CSV'
    ) %>% 
      rename_with(.fn = renomear) %>% 
      mutate(
        capital = as.logical(capital),
        uber = as.logical(uber)
      )
    ## Rows: 5578 Columns: 81
    ## ── Column specification ─────────────────────────────────────────────────────────────
    ## Delimiter: ","
    ## chr  (6): CITY, STATE, REGIAO_TUR, CATEGORIA_TUR, RURAL_URBAN, GVA_MAIN
    ## dbl (75): CAPITAL, IBGE_RES_POP, IBGE_RES_POP_BRAS, IBGE_RES_POP_ESTR, IBGE_DU, I...
    ## 
    ## ℹ Use `spec()` to retrieve the full column specification for this data.
    ## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
  4. Examinar a tibble com dfSummary:

    cidades %>% 
      dfSummary() %>% 
      print(method = 'render')
    Variável Estatísticas / Valores Freqs (% de Válidos) Faltante
    cidade [character]
    1. Bom Jesus
    2. São Domingos
    3. Bonito
    4. Planalto
    5. Santa Helena
    6. Santa Inês
    7. Santa Luzia
    8. Santa Terezinha
    9. São Francisco
    10. Vera Cruz
    [ 5290 outros ]
    5 ( 0,1% )
    5 ( 0,1% )
    4 ( 0,1% )
    4 ( 0,1% )
    4 ( 0,1% )
    4 ( 0,1% )
    4 ( 0,1% )
    4 ( 0,1% )
    4 ( 0,1% )
    4 ( 0,1% )
    5536 ( 99,2% )
    0 (0,0%)
    estado [character]
    1. MG
    2. SP
    3. RS
    4. BA
    5. PR
    6. SC
    7. GO
    8. PB
    9. PI
    10. MA
    [ 17 outros ]
    853 ( 15,3% )
    646 ( 11,6% )
    499 ( 8,9% )
    418 ( 7,5% )
    400 ( 7,2% )
    295 ( 5,3% )
    246 ( 4,4% )
    224 ( 4,0% )
    224 ( 4,0% )
    217 ( 3,9% )
    1556 ( 27,9% )
    0 (0,0%)
    capital [logical]
    1. FALSE
    2. TRUE
    5545 ( 99,4% )
    33 ( 0,6% )
    0 (0,0%)
    pop_resid [numeric]
    Média (dp) : 34223,1 (202882,9)
    mín < mediana < máx:
    0 < 10926,5 < 11253503
    IQE (CV) : 18192 (5,9)
    5044 valores distintos 0 (0,0%)
    pop_resid_bras [numeric]
    Média (dp) : 34145,7 (201262,7)
    mín < mediana < máx:
    0 < 10916 < 11133776
    IQE (CV) : 18166 (5,9)
    5072 valores distintos 0 (0,0%)
    pop_resid_estr [numeric]
    Média (dp) : 77,4 (1793,8)
    mín < mediana < máx:
    0 < 0 < 119727
    IQE (CV) : 10 (23,2)
    359 valores distintos 0 (0,0%)
    unidades_domest [numeric]
    Média (dp) : 10283,1 (64692)
    mín < mediana < máx:
    0 < 3167 < 3576148
    IQE (CV) : 5157,2 (6,3)
    4197 valores distintos 0 (0,0%)
    unidades_domest_urban [numeric]
    Média (dp) : 8842,3 (64285,7)
    mín < mediana < máx:
    0 < 1839,5 < 3548433
    IQE (CV) : 3748,8 (7,3)
    3769 valores distintos 0 (0,0%)
    unidades_domest_rural [numeric]
    Média (dp) : 1440,8 (1690,5)
    mín < mediana < máx:
    0 < 916 < 33809
    IQE (CV) : 1342,5 (1,2)
    2653 valores distintos 0 (0,0%)
    pop_regular [numeric]
    Média (dp) : 27552,7 (185746,8)
    mín < mediana < máx:
    0 < 6156 < 10463636
    IQE (CV) : 12514,5 (6,7)
    4785 valores distintos 0 (0,0%)
    pop_regular_1 [numeric]
    Média (dp) : 382,7 (2324,2)
    mín < mediana < máx:
    0 < 92 < 129464
    IQE (CV) : 194 (6,1)
    1030 valores distintos 0 (0,0%)
    pop_regular_1_4 [numeric]
    Média (dp) : 1542,1 (9242,6)
    mín < mediana < máx:
    0 < 376 < 514794
    IQE (CV) : 791,8 (6)
    2019 valores distintos 0 (0,0%)
    pop_regular_5_9 [numeric]
    Média (dp) : 2066 (12299,6)
    mín < mediana < máx:
    0 < 514 < 684443
    IQE (CV) : 1080 (6)
    2314 valores distintos 0 (0,0%)
    pop_regular_10_14 [numeric]
    Média (dp) : 2377,6 (14170)
    mín < mediana < máx:
    0 < 587 < 783702
    IQE (CV) : 1219,5 (6)
    2472 valores distintos 0 (0,0%)
    pop_regular_15_59 [numeric]
    Média (dp) : 18184,2 (125063,7)
    mín < mediana < máx:
    0 < 3835,5 < 7058221
    IQE (CV) : 7863 (6,9)
    4478 valores distintos 0 (0,0%)
    pop_regular_60_mais [numeric]
    Média (dp) : 3000,2 (23221,5)
    mín < mediana < máx:
    0 < 720,5 < 1293012
    IQE (CV) : 1383,8 (7,7)
    2622 valores distintos 0 (0,0%)
    area_cultivada [numeric]
    Média (dp) : 14170,8 (44031,1)
    mín < mediana < máx:
    0 < 3462 < 1205669
    IQE (CV) : 10288,5 (3,1)
    4339 valores distintos 0 (0,0%)
    producao_rural [numeric]
    Média (dp) : 57356,2 (148075)
    mín < mediana < máx:
    0 < 13838,5 < 3274885
    IQE (CV) : 53306,2 (2,6)
    5010 valores distintos 0 (0,0%)
    idhm_ranking [numeric]
    Média (dp) : 2777,3 (1609,5)
    mín < mediana < máx:
    0 < 2776,5 < 5565
    IQE (CV) : 2786,5 (0,6)
    5566 valores distintos 0 (0,0%)
    idhm [numeric]
    Média (dp) : 0,7 (0,1)
    mín < mediana < máx:
    0 < 0,7 < 0,9
    IQE (CV) : 0,1 (0,1)
    350 valores distintos 0 (0,0%)
    idhm_renda [numeric]
    Média (dp) : 0,6 (0,1)
    mín < mediana < máx:
    0 < 0,7 < 0,9
    IQE (CV) : 0,1 (0,1)
    391 valores distintos 0 (0,0%)
    idhm_longevidade [numeric]
    Média (dp) : 0,8 (0,1)
    mín < mediana < máx:
    0 < 0,8 < 0,9
    IQE (CV) : 0,1 (0,1)
    221 valores distintos 0 (0,0%)
    idhm_educacao [numeric]
    Média (dp) : 0,6 (0,1)
    mín < mediana < máx:
    0 < 0,6 < 0,8
    IQE (CV) : 0,1 (0,2)
    467 valores distintos 0 (0,0%)
    longitude [numeric]
    Média (dp) : -46,1 (6,8)
    mín < mediana < máx:
    -72,9 < -46,5 < 0
    IQE (CV) : 9,5 (-0,1)
    5496 valores distintos 0 (0,0%)
    latitude [numeric]
    Média (dp) : -16,4 (8,3)
    mín < mediana < máx:
    -33,7 < -18,1 < 4,6
    IQE (CV) : 14,4 (-0,5)
    5489 valores distintos 0 (0,0%)
    altitude [numeric]
    Média (dp) : 416,9 (289)
    mín < mediana < máx:
    0 < 406,2 < 1639,2
    IQE (CV) : 459,5 (0,7)
    5549 valores distintos 0 (0,0%)
    tv_assinatura [numeric]
    Média (dp) : 3092,8 (35769,4)
    mín < mediana < máx:
    0 < 246,5 < 2047668
    IQE (CV) : 727 (11,6)
    1923 valores distintos 0 (0,0%)
    telefones_fixos [numeric]
    Média (dp) : 6562,2 (87934,3)
    mín < mediana < máx:
    0 < 327 < 5543127
    IQE (CV) : 1032,8 (13,4)
    2237 valores distintos 0 (0,0%)
    area [numeric]
    Média (dp) : 1526,1 (5604)
    mín < mediana < máx:
    0 < 416,6 < 159533,3
    IQE (CV) : 822,2 (3,7)
    5556 valores distintos 0 (0,0%)
    regiao_turismo [character]
    1. 0
    2. Corredores Das Águas
    3. Vale Do Contestado
    4. Amazônia Atlântica
    5. Araguaia-Tocantins
    6. Cariri
    7. Trilhas Do Rio Doce
    8. Chapada Diamantina
    9. Vale Das Águas
    10. Rota Do Yucumã
    [ 312 outros ]
    2290 ( 41,1% )
    59 ( 1,1% )
    45 ( 0,8% )
    40 ( 0,7% )
    39 ( 0,7% )
    37 ( 0,7% )
    37 ( 0,7% )
    35 ( 0,6% )
    33 ( 0,6% )
    32 ( 0,6% )
    2931 ( 52,5% )
    0 (0,0%)
    categoria_turismo [character]
    1. 0
    2. A
    3. B
    4. C
    5. D
    6. E
    2290 ( 41,1% )
    52 ( 0,9% )
    168 ( 3,0% )
    522 ( 9,4% )
    1893 ( 33,9% )
    653 ( 11,7% )
    0 (0,0%)
    pop_estimada [numeric]
    Média (dp) : 37405,8 (219816,2)
    mín < mediana < máx:
    0 < 11574 < 12176866
    IQE (CV) : 19851,8 (5,9)
    5096 valores distintos 0 (0,0%)
    tipo [character]
    1. 0
    2. Intermediário Adjacente
    3. Intermediário Remoto
    4. Rural Adjacente
    5. Rural Remoto
    6. Sem classificação
    7. Urbano
    5 ( 0,1% )
    688 ( 12,3% )
    60 ( 1,1% )
    3040 ( 54,5% )
    323 ( 5,8% )
    5 ( 0,1% )
    1457 ( 26,1% )
    0 (0,0%)
    gva_agropec [numeric]
    Média (dp) : 55000,6 (92020,5)
    mín < mediana < máx:
    0 < 27028 < 1402282
    IQE (CV) : 50761,5 (1,7)
    5373 valores distintos 0 (0,0%)
    gva_industria [numeric]
    Média (dp) : 206310,4 (1296665)
    mín < mediana < máx:
    0 < 11701,5 < 63306755
    IQE (CV) : 59850,8 (6,3)
    5126 valores distintos 0 (0,0%)
    gva_servicos [numeric]
    Média (dp) : 541092,6 (7133989)
    mín < mediana < máx:
    0 < 46623 < 464656988
    IQE (CV) : 129230 (13,2)
    5460 valores distintos 0 (0,0%)
    gva_publico [numeric]
    Média (dp) : 169565,1 (1558102)
    mín < mediana < máx:
    0 < 47242,5 < 92051448
    IQE (CV) : 75242 (9,2)
    5435 valores distintos 0 (0,0%)
    gva_total [numeric]
    Média (dp) : 971968,7 (9411596)
    mín < mediana < máx:
    0 < 158949 < 569910503
    IQE (CV) : 340389,8 (9,7)
    5537 valores distintos 0 (0,0%)
    impostos [numeric]
    Média (dp) : 152362,9 (1964351)
    mín < mediana < máx:
    -14159 < 8660 < 117125387
    IQE (CV) : 29175,5 (12,9)
    4981 valores distintos 0 (0,0%)
    pib [numeric]
    Média (dp) : 1124332 (11352213)
    mín < mediana < máx:
    0 < 168298,5 < 687035890
    IQE (CV) : 369649,2 (10,1)
    5530 valores distintos 0 (0,0%)
    pop_pib [numeric]
    Média (dp) : 36972,6 (216862,9)
    mín < mediana < máx:
    0 < 11570,5 < 12038175
    IQE (CV) : 19609,8 (5,9)
    5114 valores distintos 0 (0,0%)
    pib_capita [numeric]
    Média (dp) : 21110,8 (20328,6)
    mín < mediana < máx:
    0 < 15865 < 314638
    IQE (CV) : 17106,2 (1)
    5046 valores distintos 0 (0,0%)
    atividade_principal [character]
    1. 0
    2. Administração, defesa, ed
    3. Agricultura, inclusive ap
    4. Comércio e reparação de v
    5. Construção
    6. Demais serviços
    7. Eletricidade e gás, água,
    8. Indústrias de transformaç
    9. Indústrias extrativas
    10. Pecuária, inclusive apoio
    11. Produção florestal, pesca
    5 ( 0,1% )
    2725 ( 48,9% )
    735 ( 13,2% )
    46 ( 0,8% )
    7 ( 0,1% )
    1480 ( 26,5% )
    98 ( 1,8% )
    261 ( 4,7% )
    35 ( 0,6% )
    161 ( 2,9% )
    25 ( 0,4% )
    0 (0,0%)
    despesas_municipais [numeric]
    Média (dp) : 76314304 (740935036)
    mín < mediana < máx:
    0 < 17733204 < 45772497944
    IQE (CV) : 41455946 (9,7)
    4071 valores distintos 0 (0,0%)
    empresas_tot [numeric]
    Média (dp) : 906,4 (8327,9)
    mín < mediana < máx:
    0 < 162 < 530446
    IQE (CV) : 380 (9,2)
    1458 valores distintos 0 (0,0%)
    empresas_a [numeric]
    Média (dp) : 18,2 (81)
    mín < mediana < máx:
    0 < 2 < 1948
    IQE (CV) : 7 (4,4)
    247 valores distintos 0 (0,0%)
    empresas_b [numeric]
    Média (dp) : 1,9 (6,2)
    mín < mediana < máx:
    0 < 0 < 274
    IQE (CV) : 2 (3,3)
    55 valores distintos 0 (0,0%)
    empresas_c [numeric]
    Média (dp) : 73,4 (499,5)
    mín < mediana < máx:
    0 < 11 < 31566
    IQE (CV) : 36 (6,8)
    483 valores distintos 0 (0,0%)
    empresas_d [numeric]
    Média (dp) : 0,4 (6,3)
    mín < mediana < máx:
    0 < 0 < 332
    IQE (CV) : 0 (14,9)
    26 valores distintos 0 (0,0%)
    empresas_e [numeric]
    Média (dp) : 2 (11,7)
    mín < mediana < máx:
    0 < 0 < 657
    IQE (CV) : 1 (5,8)
    63 valores distintos 0 (0,0%)
    empresas_f [numeric]
    Média (dp) : 43,2 (407,2)
    mín < mediana < máx:
    0 < 4 < 25222
    IQE (CV) : 14 (9,4)
    345 valores distintos 0 (0,0%)
    empresas_g [numeric]
    Média (dp) : 347,9 (2428,8)
    mín < mediana < máx:
    0 < 74 < 150633
    IQE (CV) : 168 (7)
    996 valores distintos 0 (0,0%)
    empresas_h [numeric]
    Média (dp) : 41 (300,3)
    mín < mediana < máx:
    0 < 7 < 19515
    IQE (CV) : 24 (7,3)
    344 valores distintos 0 (0,0%)
    empresas_i [numeric]
    Média (dp) : 55,9 (483,9)
    mín < mediana < máx:
    0 < 7 < 29290
    IQE (CV) : 22 (8,7)
    396 valores distintos 0 (0,0%)
    empresas_j [numeric]
    Média (dp) : 24,7 (547,2)
    mín < mediana < máx:
    0 < 1 < 38720
    IQE (CV) : 5 (22,1)
    211 valores distintos 0 (0,0%)
    empresas_k [numeric]
    Média (dp) : 15,5 (340,6)
    mín < mediana < máx:
    0 < 0 < 23738
    IQE (CV) : 2 (21,9)
    173 valores distintos 0 (0,0%)
    empresas_l [numeric]
    Média (dp) : 15,1 (212,5)
    mín < mediana < máx:
    0 < 0 < 14003
    IQE (CV) : 3 (14)
    193 valores distintos 0 (0,0%)
    empresas_m [numeric]
    Média (dp) : 51,3 (766,9)
    mín < mediana < máx:
    0 < 4 < 49181
    IQE (CV) : 12 (15)
    317 valores distintos 0 (0,0%)
    empresas_n [numeric]
    Média (dp) : 83,6 (1231,7)
    mín < mediana < máx:
    0 < 4 < 76757
    IQE (CV) : 13 (14,7)
    398 valores distintos 0 (0,0%)
    empresas_o [numeric]
    Média (dp) : 3,3 (6,1)
    mín < mediana < máx:
    0 < 2 < 204
    IQE (CV) : 1 (1,9)
    47 valores distintos 0 (0,0%)
    empresas_p [numeric]
    Média (dp) : 30,9 (260,8)
    mín < mediana < máx:
    0 < 6 < 16030
    IQE (CV) : 15 (8,4)
    276 valores distintos 0 (0,0%)
    empresas_q [numeric]
    Média (dp) : 34,1 (366)
    mín < mediana < máx:
    0 < 3 < 22248
    IQE (CV) : 11 (10,7)
    296 valores distintos 0 (0,0%)
    empresas_r [numeric]
    Média (dp) : 12,2 (122,2)
    mín < mediana < máx:
    0 < 2 < 6687
    IQE (CV) : 6 (10)
    163 valores distintos 0 (0,0%)
    empresas_s [numeric]
    Média (dp) : 51,6 (429,4)
    mín < mediana < máx:
    0 < 12 < 24832
    IQE (CV) : 26 (8,3)
    340 valores distintos 0 (0,0%)
    empresas_t [numeric] 1 valor distinto
    0 : 5578 ( 100,0% )
    0 (0,0%)
    empresas_u [numeric]
    Média (dp) : 0,1 (1,9)
    mín < mediana < máx:
    0 < 0 < 123
    IQE (CV) : 0 (38,4)
    0 : 5551 ( 99,5% )
    1 : 14 ( 0,3% )
    2 : 2 ( 0,0% )
    3 : 4 ( 0,1% )
    5 : 1 ( 0,0% )
    7 : 1 ( 0,0% )
    8 : 2 ( 0,0% )
    35 : 1 ( 0,0% )
    64 : 1 ( 0,0% )
    123 : 1 ( 0,0% )
    0 (0,0%)
    hoteis [numeric]
    Média (dp) : 0,5 (2,9)
    mín < mediana < máx:
    0 < 0 < 97
    IQE (CV) : 0 (5,7)
    33 valores distintos 0 (0,0%)
    camas [numeric]
    Média (dp) : 41 (307,6)
    mín < mediana < máx:
    0 < 0 < 13247
    IQE (CV) : 0 (7,5)
    369 valores distintos 0 (0,0%)
    agencias_priv [numeric]
    Média (dp) : 2 (26,5)
    mín < mediana < máx:
    0 < 0 < 1693
    IQE (CV) : 1 (13,1)
    61 valores distintos 0 (0,0%)
    agencias_publ [numeric]
    Média (dp) : 1,7 (11,2)
    mín < mediana < máx:
    0 < 1 < 626
    IQE (CV) : 2 (6,6)
    51 valores distintos 0 (0,0%)
    bancos_priv [numeric]
    Média (dp) : 0,8 (1,8)
    mín < mediana < máx:
    0 < 0 < 83
    IQE (CV) : 1 (2,3)
    20 valores distintos 0 (0,0%)
    bancos_publ [numeric]
    Média (dp) : 0,9 (1,1)
    mín < mediana < máx:
    0 < 1 < 8
    IQE (CV) : 2 (1,1)
    0 : 2654 ( 47,6% )
    1 : 1181 ( 21,2% )
    2 : 1187 ( 21,3% )
    3 : 500 ( 9,0% )
    4 : 54 ( 1,0% )
    5 : 1 ( 0,0% )
    8 : 1 ( 0,0% )
    0 (0,0%)
    patrimonio_bancos_priv [numeric]
    Média (dp) : 5500436242 (277575211170)
    mín < mediana < máx:
    0 < 0 < 19470765412654
    IQE (CV) : 47748535 (50,5)
    2333 valores distintos 0 (0,0%)
    patrimonio_bancos_publ [numeric]
    Média (dp) : 3598663230 (116432715033)
    mín < mediana < máx:
    0 < 23199252 < 8016164488595
    IQE (CV) : 199119090 (32,4)
    2921 valores distintos 0 (0,0%)
    carros [numeric]
    Média (dp) : 9839,8 (91757,3)
    mín < mediana < máx:
    0 < 1431,5 < 5740995
    IQE (CV) : 3485 (9,3)
    3577 valores distintos 0 (0,0%)
    motos [numeric]
    Média (dp) : 4869,6 (20916,7)
    mín < mediana < máx:
    0 < 1280 < 1134570
    IQE (CV) : 2704,8 (4,3)
    3358 valores distintos 0 (0,0%)
    tratores [numeric]
    Média (dp) : 5,7 (55,3)
    mín < mediana < máx:
    0 < 0 < 3236
    IQE (CV) : 1 (9,6)
    130 valores distintos 0 (0,0%)
    uber [logical]
    1. FALSE
    2. TRUE
    5453 ( 97,8% )
    125 ( 2,2% )
    0 (0,0%)
    mac [numeric]
    Média (dp) : 0,1 (2,2)
    mín < mediana < máx:
    0 < 0 < 130
    IQE (CV) : 0 (16,9)
    20 valores distintos 0 (0,0%)
    walmart [numeric]
    Média (dp) : 0 (0,5)
    mín < mediana < máx:
    0 < 0 < 26
    IQE (CV) : 0 (14,1)
    12 valores distintos 0 (0,0%)
    correios [numeric]
    Média (dp) : 2 (4,4)
    mín < mediana < máx:
    0 < 1 < 225
    IQE (CV) : 1 (2,2)
    36 valores distintos 0 (0,0%)

    Gerado por summarytools 1.0.0 (R versão 4.2.0)
    2022-05-12

2 Análise exploratória

2.1 IDHM

  1. Pesquise o que é IDHM.

    Segundo a Wikipedia (consultada em 02/06/2022):

    O Índice de Desenvolvimento Humano Municipal é uma versão modificada do IDH usado para calcular o IDH das unidades federativas do Brasil. Por ser uma versão modificada do IDH, não é recomendada a comparação com outros países que usam o IDH padrão.

    Foi criado para ser um índice similar ao IDH que se adequasse à demografia brasileira.

    O índice tem 3 indicadores: IDHM Longevidade, IDHM Educação, IDHM Renda.

  2. Qual o valor máximo possível? Qual o valor máximo na tibble?

    Segundo a mesma fonte, o valor máximo é \(1\).

    Na tibble, o valor máximo é

    cidades %>%
      slice_max(idhm, n = 1) %>% 
      select(cidade, estado, idhm)

2.2 Estados e capitais

  1. Compare a quantidade de estados com a quantidade de capitais. O que está errado? Conserte a situação.

    Como capital é uma coluna booleana, usamos sum para obter a quantidade de municípios para os quais capital é verdadeiro:

    cidades %>% 
      summarize(
        estados = n_distinct(estado),
        capitais = sum(capital)
      )

    As quantidades são diferentes!

    Listando as capitais com seus respectivos estados:

    cidades %>% 
      filter(capital) %>% 
      select(estado, cidade) %>% 
      arrange(estado)

    Em alguns estados, existem cidades — não-capitais — que têm o mesmo nome que capitais de outros estados. Estas cidades estão marcadas como capitais.

    repetidas <- cidades %>% 
      filter(capital) %>% 
      select(estado, cidade) %>% 
      arrange(estado) %>% 
      add_count(estado) %>% 
      filter(n > 1)
    
    repetidas

    Vamos consertar:

    nao_capitais <- repetidas %>% 
      slice(-c(3, 4, 8, 9))
    
    cidades <- cidades %>% 
      mutate(
        capital = case_when(
          !(estado %in% nao_capitais$estado) ~ capital, 
          !(cidade %in% nao_capitais$cidade) ~ capital, 
          TRUE ~ FALSE
        )
      )

    E conferir:

    cidades %>% 
      filter(capital) %>% 
      select(estado, cidade) %>% 
      arrange(estado)

2.3 Populações

  1. Verifique se a coluna pop_resid (população de residentes) é a soma de pop_resid_bras (população de residentes brasileiros) com pop_resid_estr (população de residentes estrangeiros). Use a função all.

    cidades %>% 
      summarize(
        all(pop_resid == pop_resid_bras + pop_resid_estr)
      )

    Sim.

2.4 Unidades domésticas

  1. Verifique se a coluna unidades_domest (unidades domésticas) é a soma de unidades_domest_urban (urbanas) com unidades_domest_rural (rurais). Use a função all.

    cidades %>% 
      summarize(
        all(
          unidades_domest == unidades_domest_urban + unidades_domest_rural
        )
      )

    Não.

    dif <- cidades %>% 
      mutate(
        diferenca = 
          unidades_domest - unidades_domest_urban - unidades_domest_rural
      ) %>% 
      filter(
        diferenca != 0
      ) %>% 
      select(cidade, diferenca)
    
    dif
    dif %>% 
      distinct(diferenca)

    A diferença nunca é maior que \(1\).

2.5 Categorias de turismo

  1. Na coluna categoria_turismo, substitua os zeros por NA e converta tudo para um fator ordenado com níveis \(E < D < C < B < A\). Use a função factor.

    categoria_fator <- cidades %>% 
      pull(categoria_turismo) %>% 
      factor(
        levels = c('E', 'D', 'C', 'B', 'A'),
        ordered = TRUE
      )
    cidades <- cidades %>% 
      mutate(
        categoria_turismo = categoria_fator
      )
    cidades %>% 
      count(categoria_turismo)

2.6 Tipos

  1. Na coluna tipo, substitua os zeros por NA e converta tudo para um fator não-ordenado.

    tipo_fator <- cidades %>% 
      pull(tipo)
    
    tipo_fator[tipo_fator == '0'] <- NA
    
    tipo_fator <- factor(tipo_fator, ordered = FALSE)
    cidades <- cidades %>% 
      mutate(
        tipo = tipo_fator
      )
    cidades %>% 
      count(tipo)

2.7 Atividades principais

  1. Na coluna atividade_principal, substitua os zeros por NA e converta tudo para um fator não-ordenado.

    ap_fator <- cidades %>% 
      pull(atividade_principal)
    
    ap_fator[ap_fator == '0'] <- NA
    
    ap_fator <- factor(ap_fator, ordered = FALSE)
    cidades <- cidades %>% 
      mutate(
        atividade_principal = ap_fator
      )
    cidades %>% 
      count(atividade_principal)

2.8 Regiões geográficas

  1. Crie uma nova coluna, do tipo fator, chamada regiao, com a região geográfica (Norte, Nordeste, Centro-Oeste, Sudeste, ou Sul) onde está cada município. Use os níveis ‘N’, ‘NE’, ‘CO’, ‘SE’, ‘S’.

    estados <- unique(cidades$estado) %>% sort()
    
    regioes <- c(
      'N', 'NE', 'N', 'N', 'NE', 'NE', 'CO', 'SE', 'CO', 'NE', 
      'SE', 'CO', 'CO', 'N', 'NE', 'NE', 'NE', 'S', 'SE', 'NE', 
      'N', 'N', 'S', 'S', 'NE', 'SE', 'N'
    )
    
    names(regioes) <- estados
    
    cidades <- cidades %>% 
      mutate(
        regiao = factor(regioes[estado])
      )
    cidades %>%
      distinct(regiao, estado) %>% 
      arrange(regiao)

2.9 Regiões de turismo

  1. Na coluna regiao_turismo, substitua os zeros por NA.

    Quantos zeros são?

    cidades %>% 
      count(regiao_turismo == '0')
    cidades <- cidades %>% 
      mutate(
        regiao_turismo = 
          if_else(
            regiao_turismo == '0', NA_character_, regiao_turismo
          )
      )

    Vamos conferir:

    cidades %>% 
      count(regiao_turismo == '0')
    cidades %>% 
      count(is.na(regiao_turismo))
  2. Quantas regiões de turismo são?

    n_distinct(cidades$regiao_turismo, na.rm = TRUE)
    ## [1] 321
  3. Qual tem mais municípios?

    cidades %>% 
      filter(!is.na(regiao_turismo)) %>% 
      group_by(regiao_turismo) %>% 
      summarize(municipios = n()) %>% 
      slice_max(municipios, n = 1)
  4. Qual tem menos municípios?

    cidades %>% 
      filter(!is.na(regiao_turismo)) %>% 
      group_by(regiao_turismo) %>% 
      summarize(municipios = n()) %>% 
      slice_min(municipios, n = 1)
  5. Quantos municípios não fazem parte de região de turismo?

    cidades %>% 
      filter(is.na(regiao_turismo)) %>% 
      nrow()
    ## [1] 2290
  6. Existe alguma região de turismo contendo cidades de estados diferentes?

    cidades %>% 
      filter(!is.na(regiao_turismo)) %>% 
      group_by(regiao_turismo) %>% 
      summarise(estados = n_distinct(estado)) %>% 
      filter(estados > 1)

2.10 Nomes das regiões de turismo

  1. Gere uma tibble com todos os valores distintos de regiao_turismo, sem repetições.

  2. Quais são as \(10\) palavras mais comuns que iniciam os nomes de regiões de turismo? Use a função word.

    mais_comuns <- cidades %>% 
      distinct(regiao_turismo) %>% 
      transmute(primeira = word(regiao_turismo)) %>% 
      count(primeira, sort = TRUE) %>% 
      head(10)
    
    mais_comuns
  3. Liste, em ordem alfabética, os nomes completos das regiões de turismo cujos nomes começam com palavras desta lista.

    cidades %>% 
      distinct(regiao_turismo) %>% 
      filter(
        word(regiao_turismo) %in% mais_comuns$primeira
      ) %>% 
      select(regiao_turismo) %>% 
      arrange(regiao_turismo)

2.11 PIB

  1. Verifique se a coluna pib_capita é o resultado da divisão de pib por pop_pib. Use a função all.

2.12 Carros

  1. Quais as \(10\) cidades que têm a maior quantidade de carros por habitante?

    Se usarmos pop_regular, algumas cidades têm zero neste campo:

    cidades %>% 
      mutate(
        carros_por_habitante = carros / pop_regular
      ) %>% 
      slice_max(carros_por_habitante, n = 10) %>% 
      select(cidade, estado, carros_por_habitante, pop_regular)

    Vamos excluí-las:

    carros_pop_regular <- cidades %>% 
      filter(pop_regular > 0) %>% 
      mutate(
        carros_por_habitante = carros / pop_regular
      ) %>% 
      slice_max(carros_por_habitante, n = 10) %>% 
      select(cidade, estado, carros_por_habitante, tipo)
    
    carros_pop_regular

    Ou podemos usar a população residente, também eliminando as cidades com zero neste campo:

    carros_pop_resid <- cidades %>% 
      filter(pop_resid > 0) %>% 
      mutate(
        carros_por_habitante = carros / pop_resid
      ) %>% 
      slice_max(carros_por_habitante, n = 10) %>% 
      select(cidade, estado, carros_por_habitante, tipo)
    
    carros_pop_resid

    Ou podemos usar a população estimada, onde as cidades com zero habitantes têm zero carros — e o R calcula \(0/0\) como NaN, não como Inf:

    carros_pop_est <- cidades %>% 
      mutate(
        carros_por_habitante = carros / pop_estimada
      ) %>% 
      slice_max(carros_por_habitante, n = 10) %>% 
      select(cidade, estado, carros_por_habitante, tipo)
    
    carros_pop_est

    Vamos comparar:

    tibble(
      regular = paste(
        carros_pop_regular$cidade,
        carros_pop_regular$estado,
        sep = ', '
      ),
      resid = paste(
        carros_pop_resid$cidade,
        carros_pop_resid$estado,
        sep = ', '
      ),
      estim = paste(
        carros_pop_est$cidade,
        carros_pop_est$estado,
        sep = ', '
      )
    )
  2. Quais as \(10\) cidades que têm a menor quantidade de carros por habitante?

    Vamos ignorar as cidades com zero carros.

    Usando a população regular:

    carros_pop_regular <- cidades %>%
      filter(carros > 0) %>% 
      mutate(
        carros_por_habitante = carros / pop_regular
      ) %>% 
      slice_min(carros_por_habitante, n = 10) %>% 
      select(cidade, estado, carros_por_habitante, tipo)
    
    carros_pop_regular

    Usando a população residente:

    carros_pop_resid <- cidades %>% 
      filter(carros > 0) %>% 
      mutate(
        carros_por_habitante = carros / pop_resid
      ) %>% 
      slice_min(carros_por_habitante, n = 10) %>% 
      select(cidade, estado, carros_por_habitante, tipo)
    
    carros_pop_resid

    Usando a população estimada:

    carros_pop_est <- cidades %>% 
      filter(carros > 0) %>% 
      mutate(
        carros_por_habitante = carros / pop_estimada
      ) %>% 
      slice_min(carros_por_habitante, n = 10) %>% 
      select(cidade, estado, carros_por_habitante, tipo)
    
    carros_pop_est

    Vamos comparar:

    tibble(
      regular = paste(
        carros_pop_regular$cidade,
        carros_pop_regular$estado,
        sep = ', '
      ),
      resid = paste(
        carros_pop_resid$cidade,
        carros_pop_resid$estado,
        sep = ', '
      ),
      estim = paste(
        carros_pop_est$cidade,
        carros_pop_est$estado,
        sep = ', '
      )
    )
  3. Quais são os tipos destas cidades?

    Já incluídos nos resultados acima.

  4. Comente os resultados.

    As cidades com mais carros por habitante são todas da região Sul ou Sudeste.

    Por um dos critérios, são todas do tipo rural adjacente.

    As únicas capitais que aparecem são Belo Horizonte e Curitiba.

    As cidades com menos carros por habitante são todas da região Norte, onde o transporte rodoviário é pouco desenvolvido.

    São todas do tipo rural remoto ou intermediário remoto.

2.13 Motos

  1. Quais as \(10\) cidades que têm a maior quantidade de motos por habitante?

    Se usarmos pop_regular, algumas cidades têm zero neste campo:

    cidades %>% 
      mutate(
        motos_por_habitante = motos / pop_regular
      ) %>% 
      slice_max(motos_por_habitante, n = 10) %>% 
      select(cidade, estado, motos_por_habitante, pop_regular)

    Vamos excluí-las:

    motos_pop_regular <- cidades %>% 
      filter(pop_regular > 0) %>% 
      mutate(
        motos_por_habitante = motos / pop_regular
      ) %>% 
      slice_max(motos_por_habitante, n = 10) %>% 
      select(cidade, estado, motos_por_habitante, tipo)
    
    motos_pop_regular

    Ou podemos usar a população residente, também eliminando as cidades com zero neste campo:

    motos_pop_resid <- cidades %>% 
      filter(pop_resid > 0) %>% 
      mutate(
        motos_por_habitante = motos / pop_resid
      ) %>% 
      slice_max(motos_por_habitante, n = 10) %>% 
      select(cidade, estado, motos_por_habitante, tipo)
    
    motos_pop_resid

    Ou podemos usar a população estimada, onde as cidades com zero habitantes têm zero motos — e o R calcula \(0/0\) como NaN, não como Inf:

    motos_pop_est <- cidades %>% 
      mutate(
        motos_por_habitante = motos / pop_estimada
      ) %>% 
      slice_max(motos_por_habitante, n = 10) %>% 
      select(cidade, estado, motos_por_habitante, tipo)
    
    motos_pop_est

    Vamos comparar:

    tibble(
      regular = paste(
        motos_pop_regular$cidade,
        motos_pop_regular$estado,
        sep = ', '
      ),
      resid = paste(
        motos_pop_resid$cidade,
        motos_pop_resid$estado,
        sep = ', '
      ),
      estim = paste(
        motos_pop_est$cidade,
        motos_pop_est$estado,
        sep = ', '
      )
    )
  2. Quais as \(10\) cidades que têm a menor quantidade de motos por habitante?

    Vamos ignorar as cidades com zero motos.

    Usando a população regular:

    motos_pop_regular <- cidades %>%
      filter(motos > 0) %>% 
      mutate(
        motos_por_habitante = motos / pop_regular
      ) %>% 
      slice_min(motos_por_habitante, n = 10) %>% 
      select(cidade, estado, motos_por_habitante, tipo)
    
    motos_pop_regular

    Usando a população residente:

    motos_pop_resid <- cidades %>% 
      filter(motos > 0) %>% 
      mutate(
        motos_por_habitante = motos / pop_resid
      ) %>% 
      slice_min(motos_por_habitante, n = 10) %>% 
      select(cidade, estado, motos_por_habitante, tipo)
    
    motos_pop_resid

    Usando a população estimada:

    motos_pop_est <- cidades %>% 
      filter(motos > 0) %>% 
      mutate(
        motos_por_habitante = motos / pop_estimada
      ) %>% 
      slice_min(motos_por_habitante, n = 10) %>% 
      select(cidade, estado, motos_por_habitante, tipo)
    
    motos_pop_est

    Vamos comparar:

    tibble(
      regular = paste(
        motos_pop_regular$cidade,
        motos_pop_regular$estado,
        sep = ', '
      ),
      resid = paste(
        motos_pop_resid$cidade,
        motos_pop_resid$estado,
        sep = ', '
      ),
      estim = paste(
        motos_pop_est$cidade,
        motos_pop_est$estado,
        sep = ', '
      )
    )
  3. Quais são os tipos destas cidades?

    Já incluídos nos resultados acima.

  4. Comente os resultados.

    Por dois dos critérios, as cidades com mais motos por habitante são todas da região Norte ou Nordeste.

    São do tipo rural adjacente ou urbano.

    As cidades com menos motos por habitante são todas da região Norte, onde o transporte rodoviário é pouco desenvolvido.

    São todas do tipo rural remoto ou rural adjacente.

2.14 Tratores

  1. Quais as \(10\) cidades que têm a maior quantidade de tratores por habitante? Ignore as cidades que têm zero tratores.

  2. Quais as \(10\) cidades que têm a menor quantidade de tratores por habitante? Ignore as cidades que têm zero tratores.

  3. Quais são os tipos destas cidades?

  4. Comente os resultados.

2.15 Áreas

  1. Quais as \(10\) cidades que têm a maior área?

  2. Quais as \(10\) cidades que têm a menor área?

  3. Quais são os tipos destas cidades?

  4. Comente os resultados.

2.16 Produção rural

  1. Quais as \(10\) cidades que têm a maior produção rural?

    cidades %>% 
      slice_max(producao_rural, n = 10) %>% 
      select(cidade, estado, producao_rural, tipo)
  2. Quais as \(10\) cidades que têm a menor produção rural?

    cidades %>% 
      filter(producao_rural > 0) %>% 
      slice_min(producao_rural, n = 10) %>% 
      select(cidade, estado, producao_rural, tipo)
  3. Quais são os tipos destas cidades? Ignore as cidades que têm zero produção rural.

    Já incluídos nas tabelas acima.

  4. Comente os resultados.

    Muitas cidades do tipo urbano na lista de maiores produções rurais.

2.17 Produção rural per capita

  1. Quais as \(10\) cidades que têm a maior produção rural per capita?

  2. Quais as \(10\) cidades que têm a menor produção rural per capita?

  3. Quais são os tipos destas cidades? Ignore as cidades que têm zero produção rural.

  4. Comente os resultados.

2.18 Densidade demográfica

  1. Quais as \(10\) cidades que têm a maior densidade demográfica?

    Vamos usar a população residente.

    cidades_dd <- cidades %>% 
      mutate(
        dens = pop_resid / area
      )
    cidades_dd %>% 
      slice_max(dens, n = 10) %>% 
      select(cidade, estado, dens, tipo)
  2. Quais as \(10\) cidades que têm a menor densidade demográfica?

    cidades_dd %>% 
      slice_min(dens, n = 10) %>% 
      select(cidade, estado, dens, tipo)

    Problema: há cidades com zero habitantes. Vamos ignorá-las:

    cidades_dd %>% 
      filter(dens > 0) %>% 
      slice_min(dens, n = 10) %>% 
      select(cidade, estado, dens, tipo)
  3. Quais são os tipos destas cidades?

    Incluídos nas tabelas acima.

  4. Comente os resultados.

    Com exceção de Olinda e Fortaleza, as cidades de maior densidade demográfica estão no Rio de Janeiro e em São Paulo.

    As de menor densidade demográfica ficam na região Norte, com exceção de Rondolândia.

2.19 Cidades extremas

  1. Quais são as \(10\) cidades de maior e menor latitude?

    Maior latitude:

    cidades %>% 
      slice_max(latitude, n = 10) %>% 
      select(cidade, estado, latitude)    

    Menor latitude:

    cidades %>% 
      slice_min(latitude, n = 10) %>% 
      select(cidade, estado, latitude)    

    A expressão “do Oiapoque ao Chuí” não é exata. O certo parece ser “de Uiramutã ao Chuí”.

  2. Quais são as \(10\) cidades de maior e menor longitude?

    Maior longitude:

    cidades %>% 
      slice_max(longitude, n = 10) %>% 
      select(cidade, estado, longitude)    

    Temos um problema: longitude zero é em Londres!

    Os dados estão errados. Vamos ignorar cidades com zero no campo longitude:

    cidades %>% 
      filter(longitude != 0) %>% 
      slice_max(longitude, n = 10) %>% 
      select(cidade, estado, longitude)    

    Menor longitude:

    cidades %>% 
      slice_min(longitude, n = 10) %>% 
      select(cidade, estado, longitude)    
  3. Quais são as \(10\) cidades de maior e menor altitude?

    Maior altitude:

    cidades %>% 
     slice_max(altitude, n = 10) %>% 
     select(cidade, estado, altitude)    

    Menor altitude:

    cidades %>% 
     slice_min(altitude, n = 10) %>% 
     select(cidade, estado, altitude)    
  4. Responda as perguntas acima por região geográfica. Você vai precisar da resposta desta questão.

    Latitude:

    Só a região Norte pode ter cidades com latitude zero.

    cidades %>% 
      filter(latitude != 0 | regiao == 'N') %>% 
      group_by(regiao) %>% 
      slice_max(latitude, n = 10) %>% 
      select(cidade, estado, regiao, latitude)
    cidades %>% 
      group_by(regiao) %>% 
      slice_min(latitude, n = 10) %>% 
      select(cidade, estado, regiao, latitude)

    Longitude:

    cidades %>% 
      filter(longitude != 0) %>% 
      group_by(regiao) %>% 
      slice_max(longitude, n = 10) %>% 
      select(cidade, estado, regiao, longitude)
    cidades %>% 
      filter(longitude != 0) %>% 
      group_by(regiao) %>% 
      slice_min(longitude, n = 10) %>% 
      select(cidade, estado, regiao, longitude)

    Altitude:

    cidades %>% 
      group_by(regiao) %>% 
      slice_max(altitude, n = 10) %>% 
      select(cidade, estado, regiao, altitude)
    cidades %>% 
      group_by(regiao) %>% 
      slice_min(altitude, n = 10) %>% 
      select(cidade, estado, regiao, altitude)

2.20 Faixas etárias

  1. Quais as \(10\) cidades com a maior proporção de idosos (60 anos ou mais)?

  2. Quais as \(10\) cidades com a menor proporção de idosos (60 anos ou mais)?

  3. Quais são os tipos destas cidades?

  4. Comente os resultados.

3 Visualização

  • Todos os gráficos devem ser feitos com o pacote ggplot2.

  • Todos os gráficos devem incluir títulos, rótulos, legendas, e outros elementos para facilitar a compreensão. Imagine que seus gráficos serão publicados em uma revista científica.

3.1 População e McDonald’s

  1. Apenas para as cidades que têm McDonald’s, faça um scatterplot de quantidade de McDonald’s (no eixo \(y\)) por população (no eixo \(x\)).

    grafico <- cidades %>% 
      filter(mac > 0) %>% 
      ggplot(
        aes(x = pop_resid, y = mac)
      ) +
        geom_point() +
        scale_x_continuous(
          labels = scales::number_format(
            scale = 1e-6,
            suffix = 'M'
          )
        ) +
        labs(
          title = 'Quantidade de McDonald\'s por população',
          x = 'população',
          y = 'Qtde de\nMcDonald\'s'
        )
    
    grafico

    Restringindo a cidades de até \(2\) milhões de habitantes, eliminando os outliers:

    grafico2 <- grafico +
      scale_x_continuous(
        limits = c(0, 2e6),
        labels = scales::number_format(
          scale = 1e-6,
          suffix = 'M'
        )
      )
    ## Scale for 'x' is already present. Adding another scale for 'x', which will replace
    ## the existing scale.
    grafico2
    ## Warning: Removed 6 rows containing missing values (geom_point).

  2. Use geom_smooth para gerar uma reta de regressão (com method = 'lm' e se = FALSE).

    grafico +
      geom_smooth(
        method = 'lm',
        se = FALSE
      )
    ## `geom_smooth()` using formula 'y ~ x'

    Restringindo a cidades de até \(2\) milhões de habitantes, eliminando os outliers:

    grafico2 +
      geom_smooth(
        method = 'lm',
        se = FALSE
      )
    ## `geom_smooth()` using formula 'y ~ x'
    ## Warning: Removed 6 rows containing non-finite values (stat_smooth).
    ## Warning: Removed 6 rows containing missing values (geom_point).

  3. Existe alguma correlação entre as quantidades? Comente.

    Sim, mas quando retiramos os outliers, a correlação diminui:

    df <- cidades %>% 
      filter(mac > 0)
    
    cor(df$pop_resid, df$mac)
    ## [1] 0,9665813
    df <- df %>% 
      filter(pop_resid < 2e6)
    
    cor(df$pop_resid, df$mac)
    ## [1] 0,694311

3.2 População e Walmart

  1. Apenas para as cidades que têm Walmart, faça um scatterplot de quantidade de Walmarts (no eixo \(y\)) por população (no eixo \(x\)).

  2. Use geom_smooth para gerar uma reta de regressão (com method = 'lm' e se = FALSE).

  3. Existe alguma correlação entre as quantidades? Comente.

3.3 IDHM e PIB per capita

  1. Faça um scatterplot de IDHM (no eixo \(y\)) por PIB per capita (no eixo \(x\)).

  2. Use geom_smooth para gerar uma reta de regressão (com method = 'lm' e se = FALSE).

  3. Existe alguma correlação entre as quantidades? Comente.

3.4 IDHM e despesas municipais

  1. Faça um scatterplot de IDHM (no eixo \(y\)) por despesas municipais (no eixo \(x\)).

    cidades %>% 
      ggplot() +
        geom_point(
          aes(x = despesas_municipais, y = idhm)
        ) +
        scale_x_continuous(
          labels = scales::number_format(
            scale = 1e-9
          )
        ) +
        labs(
          title = 'IDHM por despesas municipais',
          x = 'despesas municipais\n(bilhões R$)',
          y = 'IDHM'
        )

    Horrível. Vamos limitar a despesas maiores que zero e menores que \(1\) bilhão, e ignorar as cidades com IDHM igual a zero:

    grafico <- 
      cidades %>% 
        filter(
          between(despesas_municipais, 1, 1e9),
          idhm > 0
        ) %>% 
        ggplot(
          aes(x = despesas_municipais, y = idhm)
        ) +
          geom_point() +
          scale_x_continuous(
            labels = scales::number_format(
              scale = 1e-6
            )
          ) +
          labs(
            title = 'IDHM por despesas municipais',
            x = 'despesas municipais\n(milhões R$)',
            y = 'IDHM'
          )
    
    grafico

  2. Use geom_smooth para gerar uma reta de regressão (com method = 'lm' e se = FALSE).

    grafico +
      geom_smooth(method = 'lm', se = FALSE)
    ## `geom_smooth()` using formula 'y ~ x'

  3. Existe alguma correlação entre as quantidades? Comente.

    É razoável pensar que despesas municipais maiores estão associadas a um IDHM maior, por causa de investimentos em saúde, educação, etc.

    A reta de regressão mostra que sim, embora a correlação não seja tão grande:

    cor(cidades$idhm, cidades$despesas_municipais)
    ## [1] 0,1104154

    Existem cidades com despesas baixas e IDHM alto.

    Acima de \(250\) milhões de despesas, nenhuma cidade tem IDHM menor que \(0{,}6\).

3.5 IDHM e carros

  1. Faça um scatterplot de IDHM (no eixo \(y\)) por quantidade de carros (no eixo \(x\)).

  2. Use geom_smooth para gerar uma reta de regressão (com method = 'lm' e se = FALSE).

  3. Existe alguma correlação entre as quantidades? Comente.

3.6 IDHM e motos

  1. Faça um scatterplot de IDHM (no eixo \(y\)) por quantidade de motos (no eixo \(x\)).

  2. Use geom_smooth para gerar uma reta de regressão (com method = 'lm' e se = FALSE).

  3. Existe alguma correlação entre as quantidades? Comente.

3.7 IDHM e tratores

  1. Faça um scatterplot de IDHM (no eixo \(y\)) por quantidade de tratores (no eixo \(x\)). Ignore as cidades que têm zero tratores.

  2. Use geom_smooth para gerar uma reta de regressão (com method = 'lm' e se = FALSE).

  3. Existe alguma correlação entre as quantidades? Comente.

3.8 Correios

  1. Faça um histograma da quantidade de agências de correios. Use o número de classes que você achar mais adequado.

  2. Comente os resultados.

3.9 Correios per capita

  1. Faça um histograma da razão (número de agências de correio) / (população). Use o número de classes que você achar mais adequado.

  2. Comente os resultados.

3.10 Agências bancárias (públicas)

  1. Faça um histograma da quantidade de agências bancárias públicas. Use o número de classes que você achar mais adequado.

    Existem muitas cidades com zero agências públicas:

    cidades %>% 
      count(agencias_publ)

    Vamos ignorá-las:

    cidades %>% 
      filter(agencias_publ > 0) %>% 
      ggplot() +
        geom_histogram(aes(x = agencias_publ))
    ## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

    Ainda assim, a grande quantidade de cidades com só uma agência faz o histograma ficar não-interessante.

    Vamos fazer um histograma do logaritmo do número de agências.

    publicas <- cidades %>% 
      filter(agencias_publ > 0) %>% 
      mutate(log_publ = log(agencias_publ, 2)) %>% 
      ggplot() +
        geom_histogram(
          aes(x = log_publ),
          breaks = 0:10
        ) +
        scale_x_continuous(
          labels = function(x) 2^x,
          breaks = 0:10
        ) +
        labs(
          title = 'Quantidade de agências públicas',
          subtitle = '(escala logarítmica)',
          x = 'agências',
          y = NULL
        ) +
        ylim(0, 2500) +
        theme(axis.text.x = element_text(angle = 45))
    
    publicas

    Perceba como os rótulos do eixo \(x\) são as quantidades de agências, não os logaritmos.

  2. Compare com a distribuição de agências privadas.

    Veja a distribuição de agências privadas aqui.

    privadas + publicas

    Vamos ver alguma tabelas.

    Totais de agências:

    cidades %>% 
      summarize(
        privadas = sum(agencias_priv),
        públicas = sum(agencias_publ)
      )

    No total, existem mais agências de bancos privados!

    Quantidade de cidades atendidas:

    cidades %>% 
      summarize(
        privadas = sum(agencias_priv > 0),
        públicas = sum(agencias_publ > 0)
      )

    Existem mais cidades com pelo menos uma agência de banco público do que cidades com pelo menos uma agência de banco privado.

    Ou, comparando a quantidade de cidades sem agências:

    cidades %>% 
      summarize(
        sem_privadas = sum(agencias_priv == 0),
        sem_públicas = sum(agencias_publ == 0),
        sem_qualquer = sum(agencias_publ == 0 & agencias_priv == 0)
      )

    Lembre-se de que o total de cidades é

    nrow(cidades)
    ## [1] 5578

    Ou seja, cerca de \(40\%\) de cidades não têm agências bancárias, nem privadas, nem públicas!

    Aliás, existe alguma cidade que tenha agência privada, mas não pública? Quantas?

    cidades %>% 
      filter(
        agencias_priv > 0 & agencias_publ == 0
      ) %>% 
      select(cidade, estado, starts_with('agencias'))

    E existe alguma cidade que tenha agência pública, mas não privada? Quantas?

    cidades %>% 
      filter(
        agencias_priv == 0 & agencias_publ > 0
      ) %>% 
      select(cidade, estado, starts_with('agencias'))
  3. Comente os resultados.

    Comentários incluídos nas respostas acima.

3.11 Agências bancárias (públicas) per capita

  1. Faça um histograma da razão (número de agências bancárias públicas) / (população). Use o número de classes que você achar mais adequado.

    Existem muitas cidades com zero agências públicas:

    cidades %>% 
      count(agencias_publ)

    Vamos ignorá-las.

    publicaspc <- cidades %>% 
      filter(agencias_publ > 0) %>% 
      mutate(
        publicas_per_capita = agencias_publ / pop_resid
      ) %>% 
      ggplot() +
        geom_histogram(
          aes(x = publicas_per_capita),
          breaks = seq(0, .0009, .00005)
        ) +
        labs(
          title = 'Agências públicas per capita',
          x = 'agências',
          y = NULL
        ) +
        theme(axis.text.x = element_text(angle = 45))
    
    publicaspc
    ## Warning: Removed 1 rows containing non-finite values (stat_bin).

  2. Compare com a distribuição de agências privadas.

    privadaspc + publicaspc
    ## Warning: Removed 1 rows containing non-finite values (stat_bin).

    Para quase todos os valores de agências per capita, existem mais cidades com agências públicas do que cidades com agências privadas.

    Isto é consequência de que, no total, existem mais cidades atendidas por bancos públicos do que por bancos privados.

    Mas eu devia ter pedido um scatterplot de agências por população para um insight interessante.

    Aqui, descartamos as cidades com mais de \(3\) milhões de habitantes.

    cidades %>% 
      filter(
        agencias_priv > 0,
        agencias_publ > 0,
        pop_resid < 3e6
      ) %>% 
      ggplot() +
        geom_point(
          aes(
            x = pop_resid, 
            y = agencias_publ, 
            color = 'publ'
          ),
          alpha = .4
        ) +
        geom_smooth(
          aes(
            x = pop_resid, 
            y = agencias_publ, 
            color = 'publ'
          ),
          method = 'lm',
          se = FALSE
        ) +
        geom_point(
          aes(
            x = pop_resid, 
            y = agencias_priv, 
            color = 'priv'
          ),
          alpha = .2
        ) +
        geom_smooth(
          aes(
            x = pop_resid, 
            y = agencias_priv, 
            color = 'priv'
          ),
          method = 'lm',
          se = FALSE
        ) +
        scale_color_discrete(
          type = c('blue', 'red')
        ) +
        scale_x_continuous(
          breaks = seq(0, 3e6, .5e6),
          labels = scales::label_number(
            scale = 1e-6,
            suffix = 'M'
          )
        ) +
        labs(
          title = 'Agências bancárias por população',
          x = 'população',
          y = 'agências',
          color = NULL
        )
    ## `geom_smooth()` using formula 'y ~ x'
    ## `geom_smooth()` using formula 'y ~ x'

    As retas mostram como o número de agências aumenta à medida que a população aumenta.

    Para os bancos privados, o aumento é mais rápido.

    Em outras palavras: para uma mesma população, existem, em média, mais agências privadas do que públicas, e, quanto maior a população, maior a diferença.

  3. Comente os resultados.

    Comentários incluídos nas respostas acima.

3.12 Agências bancárias (privadas)

  1. Faça um histograma da quantidade de agências bancárias privadas. Use o número de classes que você achar mais adequado.

    Existem muitas cidades com zero agências privadas:

    cidades %>% 
      count(agencias_priv)

    Vamos ignorá-las:

    cidades %>% 
      filter(agencias_priv > 0) %>% 
      ggplot() +
        geom_histogram(aes(x = agencias_priv))
    ## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

    Ainda assim, a grande quantidade de cidades com só uma agência faz o histograma ficar não-interessante.

    Vamos fazer um histograma do logaritmo do número de agências.

    privadas <- cidades %>% 
      filter(agencias_priv > 0) %>% 
      mutate(log_priv = log(agencias_priv, 2)) %>% 
      ggplot() +
        geom_histogram(
          aes(x = log_priv),
          breaks = 0:10
        ) +
        scale_x_continuous(
          labels = function(x) 2^x,
          breaks = 0:10
        ) +
        labs(
          title = 'Quantidade de agências privadas',
          subtitle = '(escala logarítmica)',
          x = 'agências',
          y = NULL
        ) +
        ylim(0, 2500) +
        theme(axis.text.x = element_text(angle = 45))
    
    privadas

    Perceba como os rótulos do eixo \(x\) são as quantidades de agências, não os logaritmos.

  2. Compare com a distribuição de agências públicas.

    Veja a distribuição de agências públicas aqui.

    privadas + publicas

    Vamos ver alguma tabelas.

    Totais de agências:

    cidades %>% 
      summarize(
        privadas = sum(agencias_priv),
        públicas = sum(agencias_publ)
      )

    No total, existem mais agências de bancos privados!

    Quantidade de cidades atendidas:

    cidades %>% 
      summarize(
        privadas = sum(agencias_priv > 0),
        públicas = sum(agencias_publ > 0)
      )

    Existem mais cidades com pelo menos uma agência de banco público do que cidades com pelo menos uma agência de banco privado.

    Ou, comparando a quantidade de cidades sem agências:

    cidades %>% 
      summarize(
        sem_privadas = sum(agencias_priv == 0),
        sem_públicas = sum(agencias_publ == 0),
        sem_qualquer = sum(agencias_publ == 0 & agencias_priv == 0)
      )

    Lembre-se de que o total de cidades é

    nrow(cidades)
    ## [1] 5578

    Ou seja, cerca de \(40\%\) de cidades não têm agências bancárias, nem privadas, nem públicas!

    Aliás, existe alguma cidade que tenha agência privada, mas não pública? Quantas?

    cidades %>% 
      filter(
        agencias_priv > 0 & agencias_publ == 0
      ) %>% 
      select(cidade, estado, starts_with('agencias'))

    E existe alguma cidade que tenha agência pública, mas não privada? Quantas?

    cidades %>% 
      filter(
        agencias_priv == 0 & agencias_publ > 0
      ) %>% 
      select(cidade, estado, starts_with('agencias'))
  3. Comente os resultados.

3.13 Agências bancárias (privadas) per capita

  1. Faça um histograma da razão (número de agências bancárias privadas) / (população). Use o número de classes que você achar mais adequado.

    Existem muitas cidades com zero agências privadas:

    cidades %>% 
      count(agencias_priv)

    Vamos ignorá-las.

    privadaspc <- cidades %>% 
      filter(agencias_priv > 0) %>% 
      mutate(
        privadas_per_capita = agencias_priv / pop_resid
      ) %>% 
      ggplot() +
        geom_histogram(
          aes(x = privadas_per_capita),
          breaks = seq(0, .0009, .00005)
        ) +
        labs(
          title = 'Agências privadas per capita',
          x = 'agências',
          y = NULL
        ) +
        theme(axis.text.x = element_text(angle = 45)) +
        scale_y_continuous(
          breaks = seq(0, 1250, 250),
          limits = c(0, 1250)
        )
    
    privadaspc

  2. Compare com a distribuição de agências públicas.

    privadaspc + publicaspc
    ## Warning: Removed 1 rows containing non-finite values (stat_bin).

    Para quase todos os valores de agências per capita, existem mais cidades com agências públicas do que cidades com agências privadas.

    Isto é consequência de que, no total, existem mais cidades atendidas por bancos públicos do que por bancos privados.

    Mas eu devia ter pedido um scatterplot de agências por população para um insight interessante.

    Aqui, descartamos as cidades com mais de \(3\) milhões de habitantes.

    cidades %>% 
      filter(
        agencias_priv > 0,
        agencias_publ > 0,
        pop_resid < 3e6
      ) %>% 
      ggplot() +
        geom_point(
          aes(
            x = pop_resid, 
            y = agencias_publ, 
            color = 'publ'
          ),
          alpha = .4
        ) +
        geom_smooth(
          aes(
            x = pop_resid, 
            y = agencias_publ, 
            color = 'publ'
          ),
          method = 'lm',
          se = FALSE
        ) +
        geom_point(
          aes(
            x = pop_resid, 
            y = agencias_priv, 
            color = 'priv'
          ),
          alpha = .2
        ) +
        geom_smooth(
          aes(
            x = pop_resid, 
            y = agencias_priv, 
            color = 'priv'
          ),
          method = 'lm',
          se = FALSE
        ) +
        scale_color_discrete(
          type = c('blue', 'red')
        ) +
        scale_x_continuous(
          breaks = seq(0, 3e6, .5e6),
          labels = scales::label_number(
            scale = 1e-6,
            suffix = 'M'
          )
        ) +
        labs(
          title = 'Agências bancárias por população',
          x = 'população',
          y = 'agências',
          color = NULL
        )
    ## `geom_smooth()` using formula 'y ~ x'
    ## `geom_smooth()` using formula 'y ~ x'

    As retas mostram como o número de agências aumenta à medida que a população aumenta.

    Para os bancos privados, o aumento é mais rápido.

    Em outras palavras: para uma mesma população, existem, em média, mais agências privadas do que públicas, e, quanto maior a população, maior a diferença.

  3. Comente os resultados.

    Comentários incluídos nas respostas acima.

3.14 Áreas

  1. Faça um histograma das áreas das cidades. Use o número de classes que você achar mais adequado.

    Primeira tentativa:

    cidades %>% 
      ggplot() +
        geom_histogram(
          aes(area),
          bins = 100
        ) +
        labs(
          y = NULL,
          x = 'Área (km²)'
        )

    Existem muitas cidades com área pequena, e poucos com área grande. Uma boa chance de usar uma escala logarítmica:

    cidades %>% 
      ggplot() +
        geom_histogram(
          aes(area),
          bins = 50
        ) +
        scale_x_log10() +
        labs(
          title = 'Áreas (escala logarítmica)',
          y = NULL,
          x = 'Área (km²)'
        )
    ## Warning: Transformation introduced infinite values in continuous x-axis
    ## Warning: Removed 3 rows containing non-finite values (stat_bin).

    Podemos examinar apenas as cidades com área entre \(0\) e \(1000\) km² (com escala linear):

    cidades %>% 
      filter(between(area, 0, 1000)) %>% 
      ggplot() +
        geom_histogram(
          aes(area),
          breaks = seq(0, 1000, 100)
        ) +
        scale_x_continuous(
          breaks = seq(0, 1000, 100)
        ) +
        labs(
          title = 'Área (até 1000km²)',
          y = NULL,
          x = 'Área (km²)'
        )

  2. Comente os resultados.

    Alguns comentários incluídos nas respostas acima.

    A classe modal é entre \(100\) e \(200\) km².

3.15 Áreas (com facetas)

  1. Faça histogramas das áreas das cidades, facetados por região geográfica. Use o número de classes que você achar mais adequado. Você vai precisar da resposta desta questão.

  2. Comente os resultados.

3.16 Populações

  1. Faça um histograma das populações das cidades. Use o número de classes que você achar mais adequado.

    Primeira tentativa:

    cidades %>% 
      ggplot() +
        geom_histogram(
          aes(x = pop_resid)
        )
    ## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

    Usando escala logarítmica:

    cidades %>% 
      ggplot() +
        geom_histogram(
          aes(x = pop_resid)
        ) +
        scale_x_log10(
          labels = scales::number_format(
            scale = 1e-3,
            suffix = 'k'
          )
        ) +
        labs(
          title = 'Populações',
          y = NULL,
          x = 'população'
        )
    ## Warning: Transformation introduced infinite values in continuous x-axis
    ## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
    ## Warning: Removed 10 rows containing non-finite values (stat_bin).

    Vamos limitar a cidades de no máximo \(100\) mil habitantes, com escala linear:

    cidades %>% 
      filter(pop_resid < 1e5) %>% 
      ggplot() +
        geom_histogram(
          aes(x = pop_resid),
          breaks = seq(0, 1e5, 10000)
        ) +
        scale_x_continuous(
          breaks = seq(0, 1e5, 10000),
          labels = scales::number_format(
            scale = 1e-3,
            suffix = 'k'
          )
        ) +
        labs(
          title = 'Populações (até 100 mil)',
          y = NULL,
          x = 'população'
        )

  2. Comente os resultados.

    Há muito mais cidades com poucos habitantes.

    A classe modal é a de cidades com até \(10\) mil habitantes.

    A população mediana é

    cidades$pop_resid %>% median()
    ## [1] 10926,5

    o que diz que aproximadamente metade das cidades tem menos de \(11\) mil habitantes.

    Qual a população total destas cidades pequenas?

    cidades %>% 
      mutate(
        tamanho = case_when(
          pop_resid < 11000 ~ 'Pequenas',
          TRUE ~ 'Grandes'
        )
      ) %>% 
      group_by(tamanho) %>% 
      summarize(populacao = sum(pop_resid))

    Embora metade das cidades tenha \(11\) mil habitantes ou menos, sua população total é \(10\) vezes menor que a população total da outra metade.

3.17 Populações (com facetas)

  1. Faça histogramas das populações das cidades, facetados por região geográfica. Use o número de classes que você achar mais adequado. Você vai precisar da resposta desta questão.

  2. Comente os resultados.

3.18 PIB

  1. Faça um histograma do valor do PIB. Use o número de classes que você achar mais adequado.

  2. Comente os resultados.

3.19 PIB per capita

  1. Faça um histograma do valor do PIB per capita. Use o número de classes que você achar mais adequado.

    cidades %>% 
      ggplot() +
        geom_histogram(
          aes(x = pib_capita)
        ) +
        labs(
          y = NULL,
          x = 'PIB per capita (R$)'
        ) +
        scale_x_continuous(
          labels = scales::number_format(
            scale = 1e-3,
            suffix = 'k'
          )
        )
    ## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

    Em escala logarítmica:

    cidades %>% 
      ggplot() +
        geom_histogram(
          aes(x = pib_capita)
        ) +
        labs(
          title = 'PIB per capita (escala logarítmica)',
          y = NULL,
          x = 'PIB per capita (R$)'
        ) +
        scale_x_log10(
          labels = scales::number_format(
            scale = 1e-3,
            suffix = 'k'
          )
        )
    ## Warning: Transformation introduced infinite values in continuous x-axis
    ## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
    ## Warning: Removed 5 rows containing non-finite values (stat_bin).

    Restringindo a um valor máximo:

    cidades %>% 
      filter(pib_capita < 1e5) %>% 
      ggplot() +
        geom_histogram(
          aes(x = pib_capita),
          breaks = seq(0, 1e5, 1e4)
        ) +
        labs(
          title = 'PIB per capita (até 100 mil)',
          y = NULL,
          x = 'PIB per capita (R$)'
        ) +
        scale_x_continuous(
          breaks = seq(0, 1e5, 1e4),
          labels = scales::number_format(
            scale = 1e-3,
            suffix = 'k'
          )
        )

  2. Comente os resultados.

    É uma distribuição assimétrica, com uma longa cauda à direita.

    A classe modal é entre \(10\) e \(20\) mil reais.

3.20 Telefones fixos per capita (com facetas)

  1. Faça histogramas das quantidades de telefones fixos per capita, facetados por região geográfica. Use o número de classes que você achar mais adequado. Você vai precisar da resposta desta questão.

  2. Comente os resultados.

3.21 Assinaturas de TV per capita (com facetas)

  1. Faça histogramas das quantidades de assinaturas de TV por assinatura per capita, facetados por região geográfica. Use o número de classes que você achar mais adequado. Você vai precisar da resposta desta questão.

  2. Comente os resultados.

3.22 PIB e atividade principal

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) do PIB, com um boxplot para cada atividade principal. Faça com que os boxplots sejam horizontais, para facilitar a leitura dos nomes das atividades.

  2. Comente os resultados.

3.23 PIB per capita e atividade principal

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) do PIB per capita, com um boxplot para cada atividade principal. Faça com que os boxplots sejam horizontais, para facilitar a leitura dos nomes das atividades.

    Primeira tentativa:

    cidades %>% 
      ggplot() +
        geom_boxplot(
          aes(x = atividade_principal, y = pib_capita)
        ) +
      coord_flip()

    Vamos abreviar os nomes das atividades:

    cidades %>% 
      mutate(
        atividade_principal = word(atividade_principal, end = 5)
      ) %>% 
      ggplot() +
        geom_boxplot(
          aes(x = atividade_principal, y = pib_capita)
        ) +
        labs(
          title = 'PIB per capita por atividade principal',
          y = 'PIB per capita',
          x = NULL
        ) +
        coord_flip()

    Podemos usar uma escala logarítmica:

    cidades %>% 
      mutate(
        atividade_principal = word(atividade_principal, end = 5)
      ) %>% 
      ggplot() +
        geom_boxplot(
          aes(x = atividade_principal, y = pib_capita)
        ) +
        scale_y_log10() +
        labs(
          title = 'PIB per capita por atividade principal',
          subtitle = '(escala logarítmica)',
          y = 'PIB per capita',
          x = NULL
        ) +
        coord_flip()
    ## Warning: Transformation introduced infinite values in continuous y-axis
    ## Warning: Removed 5 rows containing non-finite values (stat_boxplot).

  2. Comente os resultados.

    As atividades associadas ao maior PIB per capita mediano são (1) eletricidade, gás, água e esgoto e (2) comércio e reparação de veículos.

    As atividades associadas ao menor PIB per capita mediano são administração, defesa, educação e saúde.

3.24 Hotéis e categoria de turismo

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) da quantidade de hotéis, com um boxplot para cada categoria de turismo.

    cidades %>% 
      ggplot() +
        geom_boxplot(
          aes(x = fct_rev(categoria_turismo), y = hoteis)
        ) +
        labs(
          title = 'Quantidade de hotéis por categoria de turismo',
          x = 'categoria de turismo'
        )

  2. Comente os resultados.

    Como era de se esperar, a quantidade de hotéis é muito maior em cidades da categoria A.

3.25 Populações por região

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) das populações, com um boxplot para cada região geográfica. Você vai precisar da resposta desta questão.

  2. Comente os resultados.

3.26 Densidade demográfica por região

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) das densidades demográficas, com um boxplot para cada região geográfica. Você vai precisar da resposta desta questão.

  2. Comente os resultados.

3.27 Carros per capita por tipo de cidade

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) da quantidade de carros per capita, com um boxplot para cada tipo de cidade.

  2. Comente os resultados.

3.28 Motos per capita por tipo de cidade

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) da quantidade de motos per capita, com um boxplot para cada tipo de cidade.

    cidades %>% 
      filter(pop_resid > 0) %>% 
      mutate(mpc = motos / pop_resid) %>% 
      ggplot() +
        geom_boxplot(aes(x = tipo, y = mpc)) +
        scale_x_discrete(
          labels = function(x) {
            str_split(x, ' ') %>% 
              map_chr(paste, collapse = '\n')
          }
        ) +
        labs(
          title = 'Motos per capita por tipo de cidade',
          x = 'tipo de cidade',
          y = 'motos\nper capita'
        )

  2. Comente os resultados.

    Medianas semelhantes.

    Sem outliers em cidades do tipo intermediário remoto — que, ironicamente, têm a maior variabilidade (em termos do IQR).

3.29 Tratores per capita por tipo de cidade

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) da quantidade de tratores per capita, com um boxplot para cada tipo de cidade.

  2. Comente os resultados.

3.30 Hotéis e Uber

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) da quantidade de hotéis, com um boxplot para cada valor de uber.

  2. Comente os resultados.

3.31 PIB per capita e Uber

  1. Faça boxplots lado a lado (no mesmo gráfico, sem facetar) do valor do PIB per capita, com um boxplot para cada valor de uber.

  2. Comente os resultados.

3.32 Cidades por região geográfica

  1. Faça um gráfico de barras das quantidades de cidades, com uma barra por região. Você vai precisar da resposta desta questão.

    cidades %>% 
      ggplot() +
        geom_bar(
          aes(x = regiao)
        ) +
        labs(
          title = 'Quantidade de cidades por região geográfica',
          y = NULL
        )

  2. Use a função fct_reorder para dispor as barras em ordem decrescente de altura.

    cidades %>% 
      ggplot() +
        geom_bar(
          aes(
            x = fct_reorder(
              regiao, 
              cidade, 
              .fun = length, 
              .desc = TRUE
            )
          )
        ) +
        labs(
          title = 'Quantidade de cidades por região geográfica',
          y = NULL,
          x = 'região'
        )

  3. Em outro gráfico, use a função fct_reorder para dispor as barras em ordem crescente de altura.

    cidades %>% 
      ggplot() +
        geom_bar(
          aes(
            x = fct_reorder(
              regiao, 
              cidade, 
              .fun = length
            )
          )
        ) +
        labs(
          title = 'Quantidade de cidades por região geográfica',
          y = NULL,
          x = 'região'
        )

  4. Comente os resultados.

    Quais são as áreas totais das regiões?

    cidades %>% 
      group_by(regiao) %>% 
      summarize(area = sum(area)) %>% 
      arrange(area)

    A região Norte tem a maior área, mas o menor número de cidades.

    A região Centro-Oeste tem a segunda maior área, mas o segundo menor número de cidades.

    As outras regiões seguem a mesma ordem, tanto em área quanto em número de cidades.

3.33 Populações por região geográfica

  1. Faça um gráfico de barras das populações totais, com uma barra por região. Você vai precisar da resposta desta questão.

    cidades %>% 
      ggplot() +
        geom_col(
          aes(x = regiao, y = pop_resid)
        ) +
        scale_y_continuous(
          labels = scales::number_format(
            scale = 1e-6,
            suffix = 'M'
          )
        ) +
        labs(
          title = 'População total por região geográfica',
          x = 'região',
          y = 'população'
        )

  2. Use a função fct_reorder para dispor as barras em ordem decrescente de altura.

    cidades %>% 
      ggplot() +
        geom_col(
          aes(
            x = fct_reorder(
              regiao,
              pop_resid,
              sum,
              .desc = TRUE
            ), 
            y = pop_resid
          )
        ) +
        scale_y_continuous(
          labels = scales::number_format(
            scale = 1e-6,
            suffix = 'M'
          )
        ) +
        labs(
          title = 'População total por região geográfica',
          x = 'região',
          y = 'população'
        )

  3. Em outro gráfico, use a função fct_reorder para dispor as barras em ordem crescente de altura.

    cidades %>% 
      ggplot() +
        geom_col(
          aes(
            x = fct_reorder(
              regiao,
              pop_resid,
              sum
            ), 
            y = pop_resid
          )
        ) +
        scale_y_continuous(
          labels = scales::number_format(
            scale = 1e-6,
            suffix = 'M'
          )
        ) +
        labs(
          title = 'População total por região geográfica',
          x = 'região',
          y = 'população'
        )

  4. Comente os resultados.

    A região Sudeste é, de longe, a mais populosa, seguida da região Nordeste.

    A região Centro-Oeste é (um pouco) menos populosa do que a região Norte, ao contrário do que eu esperava.

    É interessante comparar com o gráfico dos PIBs totais por região e constatar que, com exceção do primeiro lugar, toda a ordenação muda.

3.34 PIB por região geográfica

  1. Faça um gráfico de barras dos PIBs totais, com uma barra por região. Você vai precisar da resposta desta questão.

    cidades %>% 
      ggplot() +
        geom_col(
          aes(x = regiao, y = pib)
        ) +
        scale_y_continuous(
          labels = scales::number_format(
            scale = 1e-9,
            suffix = 'B'
          )
        ) +
        labs(
          title = 'PIB por região geográfica',
          x = 'região',
          y = 'PIB'
        )

  2. Use a função fct_reorder para dispor as barras em ordem decrescente de altura.

    cidades %>% 
      ggplot() +
        geom_col(
          aes(
            x = fct_reorder(
              regiao,
              pib,
              sum,
              .desc = TRUE
            ), 
            y = pib
          )
        ) +
        scale_y_continuous(
          labels = scales::number_format(
            scale = 1e-9,
            suffix = 'B'
          )
        ) +
        labs(
          title = 'PIB por região geográfica',
          x = 'região',
          y = 'PIB'
        )

  3. Em outro gráfico, use a função fct_reorder para dispor as barras em ordem crescente de altura.

    cidades %>% 
      ggplot() +
        geom_col(
          aes(
            x = fct_reorder(
              regiao,
              pib,
              sum
            ), 
            y = pib
          )
        ) +
        scale_y_continuous(
          labels = scales::number_format(
            scale = 1e-9,
            suffix = 'B'
          )
        ) +
        labs(
          title = 'PIB por região geográfica',
          x = 'região',
          y = 'PIB'
        )

  4. Comente os resultados.

    A ordenação é óbvia.

    É interessante comparar com o gráfico das populações totais por região e constatar que, com exceção do primeiro lugar, toda a ordenação muda.

3.35 Produção rural por região geográfica

  1. Faça um gráfico de barras das produções rurais totais, com uma barra por região. Você vai precisar da resposta desta questão.

  2. Use a função fct_reorder para dispor as barras em ordem decrescente de altura.

  3. Em outro gráfico, use a função fct_reorder para dispor as barras em ordem crescente de altura.

  4. Comente os resultados.

3.36 Faixas etárias

  1. Faça um gráfico de barras da população brasileira, com uma barra por faixa etária.

  2. Use a função fct_reorder para dispor as barras em ordem decrescente de altura.

  3. Em outro gráfico, use a função fct_reorder para dispor as barras em ordem crescente de altura.

  4. Em qual ordem você acha que as barras devem aparecer? Por quê?

  5. Comente os resultados.

3.37 Faixas etárias por região geográfica

  1. Faça um gráfico de barras da população brasileira, com um conjunto de barras para cada região. Você vai precisar da resposta desta questão.

    Veja abaixo.

  2. Cada conjunto deve ter \(6\) barras lado a lado, uma para cada faixa etária. Use o argumento dodge na geometria adequada.

    df_faixas <- cidades %>% 
      pivot_longer(
        cols = starts_with('pop_regular_'),
        names_to = 'faixa',
        names_prefix = 'pop_regular_',
        values_to = 'pop'
      ) %>% 
      mutate(
        faixa = case_when(
          faixa == '1' ~ 'até 1',
          faixa == '1_4' ~ '1 a 4',
          faixa == '5_9' ~ '5 a 9',
          faixa == '10_14' ~ '10 a 14',
          faixa == '15_59' ~ '15 a 59',
          faixa == '60_mais' ~ '60 ou mais'
        )
      ) %>% 
      mutate(
        faixa = factor(
          faixa,
          levels = unique(faixa),
          ordered = TRUE
        )
      ) %>% 
      select(cidade, regiao, faixa, pop)
    
    df_faixas
    df_faixas %>% 
      ggplot() +
        geom_col(
          aes(x = regiao, y = pop, fill = faixa),
          position = 'dodge'
        ) +
        labs(
          title = 'População por região, por faixa etária',
          x = 'região',
          y = NULL,
          fill = NULL
        ) +
        scale_y_continuous(
          labels = scales::label_number(
            scale = 1e-6,
            suffix = 'M'
          )
        )

  3. Comente os resultados.

    Perceba que as faixas etárias têm larguras diferentes.

    As únicas comparações razoáveis são entre \(1\) a \(4\), \(5\) a \(9\), e \(10\) a \(14\), que têm larguras aproximadamente iguais.

    Em todas as regiões, há mais pessoas da faixa \(10\) a \(14\) do que das faixas mais jovens.

    As regiões Centro-Oeste e Norte são as únicas onde há menos idosos do que jovens de \(10\) a \(14\).

3.38 Faixas etárias por região geográfica, proporções

  1. Faça um gráfico de barras da população brasileira, com uma barra por região. Você vai precisar da resposta desta questão.

    Veja abaixo.

  2. Todas as barras devem ser da mesma altura, e o eixo \(y\) deve ir de \(0\) até \(1\), representando proporções.

    Veja abaixo.

  3. Cada barra deve ser subdividida em faixas horizontais de cores diferentes, uma faixa colorida para cada faixa etária, de acordo com as proporções de cada faixa etária em cada região.

    df_faixas <- cidades %>% 
      pivot_longer(
        cols = starts_with('pop_regular_'),
        names_to = 'faixa',
        names_prefix = 'pop_regular_',
        values_to = 'pop'
      ) %>% 
      mutate(
        faixa = case_when(
          faixa == '1' ~ 'até 1',
          faixa == '1_4' ~ '1 a 4',
          faixa == '5_9' ~ '5 a 9',
          faixa == '10_14' ~ '10 a 14',
          faixa == '15_59' ~ '15 a 59',
          faixa == '60_mais' ~ '60 ou mais'
        )
      ) %>% 
      mutate(
        faixa = factor(
          faixa,
          levels = unique(faixa),
          ordered = TRUE
        )
      ) %>% 
      select(cidade, regiao, faixa, pop)
    
    df_faixas
    df_faixas %>% 
      ggplot() +
        geom_col(
          aes(x = regiao, y = pop, fill = fct_rev(faixa)),
          position = 'fill'
        ) +
        labs(
          title = 'População por região, por faixa etária',
          subtitle = '(proporções)',
          x = 'região',
          y = NULL,
          fill = NULL
        )

  4. Comente os resultados.

    As proporções são semelhantes entre as regiões.

    A região Norte tem a menor proporção de idosos, e a maior proporção de pessoas até \(14\) anos.

    As regiões Sul e Sudeste têm a maior proporção de idosos.

3.39 Faixas etárias por tipo de cidade

  1. Faça um gráfico de barras da população brasileira, com um conjunto de barras para cada tipo de cidade.

    Veja abaixo.

  2. Cada conjunto deve ter \(6\) barras lado a lado, uma para cada faixa etária. Use o argumento dodge na geometria adequada.

    df_faixas <- cidades %>% 
      pivot_longer(
        cols = starts_with('pop_regular_'),
        names_to = 'faixa',
        names_prefix = 'pop_regular_',
        values_to = 'pop'
      ) %>% 
      mutate(
        faixa = case_when(
          faixa == '1' ~ 'até 1',
          faixa == '1_4' ~ '1 a 4',
          faixa == '5_9' ~ '5 a 9',
          faixa == '10_14' ~ '10 a 14',
          faixa == '15_59' ~ '15 a 59',
          faixa == '60_mais' ~ '60 ou mais'
        )
      ) %>% 
      mutate(
        faixa = factor(
          faixa,
          levels = unique(faixa),
          ordered = TRUE
        )
      ) %>% 
      select(cidade, tipo, faixa, pop)
    
    df_faixas
    df_faixas %>% 
      ggplot() +
        geom_col(
          aes(x = tipo, y = pop, fill = faixa),
          position = 'dodge'
        ) +
        labs(
          title = 'População por tipo de cidade, por faixa etária',
          x = 'tipo de cidade',
          y = NULL,
          fill = NULL
        )

    A população de cidades do tipo urbano é tão grande que os outros tipos ficam quase invisíveis.

    Veja a próxima questão, que resolve este problema mostrando as proporções das diversas faixas etárias.

    Vamos excluir o tipo urbano do gráfico:

    df_faixas %>% 
      filter(tipo != 'Urbano') %>% 
      ggplot() +
        geom_col(
          aes(x = tipo, y = pop, fill = faixa),
          position = 'dodge'
        ) +
        labs(
          title = 'População por tipo de cidade, por faixa etária',
          subtitle = 'exceto centros urbanos',
          x = 'tipo de cidade',
          y = NULL,
          fill = NULL
        )

    Vamos melhorar os rótulos do eixo \(x\) e ignorar as cidades sem classificação:

    df_faixas %>% 
      filter(tipo != 'Urbano') %>% 
      filter(tipo != 'Sem classificação') %>% 
      ggplot() +
        geom_col(
          aes(x = tipo, y = pop, fill = faixa),
          position = 'dodge'
        ) +
        labs(
          title = 'População por tipo de cidade, por faixa etária',
          subtitle = 'exceto centros urbanos',
          x = 'tipo de cidade',
          y = NULL,
          fill = NULL
        ) +
        scale_x_discrete(
          labels = function(x) {
            str_split(x, ' ') %>% 
              map_chr(paste, collapse = '\n')
          }
        )

  3. Comente os resultados.

    Os centros urbanos têm uma população muito maior do que os outros tipos de cidade.

    Cidades do tipo urbano e intermediário adjacente parecem ter uma proporção significativamente maior de pessoas entre \(15\) a \(59\) anos.

3.40 Faixas etárias por tipo de cidade, proporções

  1. Faça um gráfico de barras da população brasileira, com uma barra por tipo de cidade.

    Veja abaixo.

  2. Todas as barras devem ser da mesma altura, e o eixo \(y\) deve ir de \(0\) até \(1\), representando proporções.

    Veja abaixo.

  3. Cada barra deve ser subdividida em faixas horizontais de cores diferentes, uma faixa colorida para cada faixa etária, de acordo com as proporções de cada faixa etária em cada tipo de cidade.

    df_faixas <- cidades %>% 
      pivot_longer(
        cols = starts_with('pop_regular_'),
        names_to = 'faixa',
        names_prefix = 'pop_regular_',
        values_to = 'pop'
      ) %>% 
      mutate(
        faixa = case_when(
          faixa == '1' ~ 'até 1',
          faixa == '1_4' ~ '1 a 4',
          faixa == '5_9' ~ '5 a 9',
          faixa == '10_14' ~ '10 a 14',
          faixa == '15_59' ~ '15 a 59',
          faixa == '60_mais' ~ '60 ou mais'
        )
      ) %>% 
      mutate(
        faixa = factor(
          faixa,
          levels = unique(faixa),
          ordered = TRUE
        )
      ) %>% 
      select(cidade, tipo, faixa, pop)
    
    df_faixas
    df_faixas %>% 
      ggplot() +
        geom_col(
          aes(x = tipo, y = pop, fill = fct_rev(faixa)),
          position = 'fill'
        ) +
        labs(
          title = 'População por tipo de cidade, por faixa etária',
          subtitle = '(proporções)',
          x = 'tipo de cidade',
          y = NULL,
          fill = NULL
        )
    ## Warning: Removed 60 rows containing missing values (geom_col).

    Vamos melhorar os rótulos do eixo \(x\) e ignorar as cidades sem classificação:

    df_faixas %>% 
      filter(tipo != 'Sem classificação') %>% 
      ggplot() +
        geom_col(
          aes(x = tipo, y = pop, fill = fct_rev(faixa)),
          position = 'fill'
        ) +
        labs(
          title = 'População por tipo de cidade, por faixa etária',
          subtitle = '(proporções)',
          x = 'tipo de cidade',
          y = NULL,
          fill = NULL
        ) +
        scale_x_discrete(
          labels = function(x) {
            str_split(x, ' ') %>% 
              map_chr(paste, collapse = '\n')
          }
        )

  4. Comente os resultados.

    Proporcionalmente. há mais idosos em cidades de tipos urbano, intermediário adjacente e rural adjacente.

    Proporcionalmente. há mais jovens em cidades de tipos intermediário remoto e rural remoto.

4 Mapa interativo

4.1 Marcadores

  1. Leia algum tutorial sobre o pacote leaflet:

  2. Escolha qualquer uma das questões do tipo “Quais as \(10\) cidades…”, na seção de análise exploratória.

  3. Resolva a questão e modifique o código abaixo para criar marcadores mostrando as cidades da resposta, rotulados com os nomes das cidades (use o argumento label).

  4. Quando o usuário clicar o mouse sobre a cidade, deve aparecer a informação relevante pedida pela questão (use o argumento popup).

  5. Acrescente outras informações que você achar importantes — por exemplo, a classificação da cidade na ordenação que a questão pede.

    library(leaflet)
    
    # Um exemplo, apenas. Substitua com a tibble da sua resposta:
    df <- cidades %>% 
      filter(
        cidade %in% c('Manaus', 'Brasília', 'Porto Alegre')
      )
    
    # O mapa:
    leaflet(df) %>% 
      setView(
        lng = mean(df$longitude), 
        lat = mean(df$latitude),
        zoom = 4
      ) %>% 
      addTiles() %>% 
      addMarkers()
    ## Assuming "longitude" and "latitude" are longitude and latitude, respectively
  6. Faça um segundo mapa interativo com marcadores para as cidades que satisfazem algum critério que você ache interessante. Use a imaginação.

LS0tCnRpdGxlOiAnQ2lkYWRlcyBicmFzaWxlaXJhczogcmVzcG9zdGFzJwpzdWJ0aXRsZTogJ0xpc3RhIGF2YWxpYXRpdmEgLS0gUHJvYmFiaWxpZGFkZSBlIEVzdGF0w61zdGljYSAtLSAyMDIyLjEnCmF1dGhvcjogJ2ZuYXVmZWwnCmVtYWlsOiAnaHR0cHM6Ly9mbmF1ZmVsLmdpdGh1Yi5pby8nCmRhdGU6ICcodi4gYHIgZm9ybWF0KFN5cy5EYXRlKCksICIlZC8lbS8lWSIpYCknCmxhbmc6ICdwdC1icicKCm91dHB1dDogCiAgIyBUbyBpbnN0YWxsIHRoZXNlIG91dHB1dCBmb3JtYXRzLCBydW4KICAjICAgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQogICMgICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImZuYXVmZWwvZm5hdWZlbFJtZCIpCiAgZm5hdWZlbFJtZDo6aHRtbF9yZXBvcnQ6CiAgICBbXQogICAgIyBjc3M6CiAgICAjICAgLSBkZWZhdWx0CiAgICAjICAgLSBodG1sX2ZpbGVzL3dlYmV4LmNzcwogICAgIyBpbmNsdWRlczoKICAgICMgICBhZnRlcl9ib2R5OiAKICAgICMgICAtIGh0bWxfZmlsZXMvd2ViZXguanMKCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMgVGhlIG5leHQgY29tbWFuZCBjb25maWd1cmVzIE1BTlkgdGhpbmdzIGFuZCBsb2FkcyBxdWl0ZSBhIGZldyBwYWNrYWdlcy4KIyAKIyBJZiB5b3Ugd2FudCB0byBzZWUgd2hhdCdzIGJlaW5nIGRvbmUsIGV4ZWN1dGUgCiMgCiMgICBjYXQoCiMgICAgIHN5c3RlbS5maWxlKAojICAgICAgICJybWFya2Rvd24vcmVzb3VyY2VzL1IvX2NvbW1vbl9yZXBvcnQuUiIsIAojICAgICAgIHBhY2thZ2UgPSAiZm5hdWZlbFJtZCIKIyAgICAgKQojICAgKQojIAojIHRvIGZpbmQgb3V0IHRoZSBsb2NhdGlvbiBvZiB0aGUgZmlsZS4gVGhlbiBvcGVuIHRoZSBmaWxlLgojIAojIElmIHlvdSB3YW50IHRvIGNoYW5nZSB0aGUgY29uZmlndXJhdGlvbiwgY29weSB0aGUgZmlsZSwgZWRpdCBpdCwgYW5kCiMgc291cmNlIGl0IGluc3RlYWQgb2YgdGhlIHBhY2thZ2UgZmlsZS4gCiMgCiMgT3Igc2ltcGx5IHdyaXRlIHlvdXIgY29tbWFuZHMgaGVyZSBpbiB0aGlzIGNvZGUgY2h1bmsuCgpzb3VyY2UoCiAgc3lzdGVtLmZpbGUoCiAgICAicm1hcmtkb3duL3Jlc291cmNlcy9SL19jb21tb25fcmVwb3J0LlIiLAogICAgcGFja2FnZSA9ICJmbmF1ZmVsUm1kIgogICkKKQoKIyBPcMOnw7VlcyBwYXJhIGRmU3VtbWFyeQpzdF9vcHRpb25zKAogIGRmU3VtbWFyeS5ncmFwaC5jb2wgPSBGQUxTRSwKKQoKCiMgMyBjYXNhcyBkZWNpbWFpcyBlbSBuw7ptZXJvcyBubyB0ZXh0bwpvcHRpb25zKGZtZGlnaXRzID0gMykKCiMgUGFyYSBtYXBhcyBpbnRlcmF0aXZvcwpsaWJyYXJ5KGxlYWZsZXQpCgojIFBhcmEgZ3LDoWZpY29zIGxhZG8gYSBsYWRvCmxpYnJhcnkocGF0Y2h3b3JrKQpgYGAKCgojIEluc3RydcOnw7VlcyB7LX0KCiogVmVqYSBuYSB0YWJlbGEgYWJhaXhvIG9zIG7Dum1lcm9zIGRhcyBxdWVzdMO0ZXMgcXVlIGZvcmFtIHNvcnRlYWRhcyBwYXJhIHZvY8OqLiBbU2Ugc2V1IG7Dum1lcm8gZGUgbWF0csOtY3VsYSBuw6NvIGVzdGl2ZXIgbmEgdGFiZWxhLCBlbnRyZSBlbSBjb250YXRvIGNvbWlnbyBwZWxvIFRlbGVncmFtLl17LmhsfQoKICAgIGBgYHtyIGVjaG89RkFMU0V9CiAgICBzZXQuc2VlZCgxMjM1KQogICAgZWRhIDwtIHNhbXBsZSgxOjIwKQogICAgdml6MSA8LSBzYW1wbGUoMToyMCkKICAgIHZpejIgPC0gc2FtcGxlKDIxOjQwKQogICAgbWFwYSA8LSAxCiAgICBtYXRyaWN1bGFzIDwtIGMoCiAgICAgICcyMTgwNjAwNTInLAogICAgICAnMTE1MDYwMDQ3JywKICAgICAgJzExOTA2MDAxMScsCiAgICAgICcyMTgwNjAwNzYnLAogICAgICAnMTE5MDYwMDI1JywKICAgICAgJzIxODA2MDA1MycsCiAgICAgICcxMjAwNjAwMDUnLAogICAgICAnMDIwMDYwMDAzJywKICAgICAgJzkyMDA2MDA3MycsCiAgICAgICcyMTkwNjAwODYnLAogICAgICAnMjIwMDYwMDQ3JywKICAgICAgJzEyMDA2MDAwOScsCiAgICAgICcyMTgwNjAwNzAnLAogICAgICAnMDIwMDYwMDAxJywKICAgICAgJzExNDA2MDA0MycsCiAgICAgICcxMTkwNjAwMDcnLAogICAgICAnMjIwMDYwMDU5JywKICAgICAgJzEyMDA2MDAwNycsCiAgICAgICcyMjAwNjAwNjMnLAogICAgICAnMTE4MDYwMDI5JyAgICAgIAogICAgKQogICAgCiAgICB0aWJibGUoCiAgICAgIG1hdHLDrWN1bGEgPSBtYXRyaWN1bGFzLAogICAgICAnYW7DoWxpc2UgZXhwbG9yYXTDs3JpYScgPSBwYXN0ZTAoJzIuJywgYXMuY2hhcmFjdGVyKGVkYSksICcsJyksCiAgICAgICd2aXN1YWxpemHDp8OjbycgPSBwYXN0ZTAoCiAgICAgICAgcGFzdGUwKCczLicsIGFzLmNoYXJhY3Rlcih2aXoxKSksCiAgICAgICAgJywgJywKICAgICAgICBwYXN0ZTAoJzMuJywgYXMuY2hhcmFjdGVyKHZpejIpKSwKICAgICAgICAnLCcKICAgICAgKSwKICAgICAgJ21hcGEnID0gJzQuMScKICAgICkgJT4lIAogICAgICBhcnJhbmdlKG1hdHLDrWN1bGEpICU+JSAKICAgICAga2JsKAogICAgICAgIGFsaWduID0gJ3InLAogICAgICAgIGNvbC5uYW1lcyA9IGMoCiAgICAgICAgICAnbWF0csOtY3VsYScsCiAgICAgICAgICAnJywgJycsICcnCiAgICAgICAgKQogICAgICApICU+JSAKICAgICAga2FibGVfcGFwZXIoCiAgICAgICAgYygnc3RyaXBlZCcsICdob3ZlcicpLAogICAgICAgIGZ1bGxfd2lkdGggPSBGQUxTRQogICAgICApCiAgICBgYGAKCiogQ2xpcXVlIG8gYm90w6NvIGBDb2RlYCwgbm8gaW7DrWNpbyBkZXN0YSBww6FnaW5hLCBwYXJhIGJhaXhhciBvIGFycXVpdm8gUm1kIGRlc3RlIGRvY3VtZW50by4KCiogRWRpdGUgbyBhcnF1aXZvIFJtZCBwYXJhIHJlc29sdmVyIGFzIHN1YXMgcXVlc3TDtWVzLiAKCiogU2UgcXVpc2VyIHJlc29sdmVyIHF1ZXN0w7VlcyBxdWUgbsOjbyBmb3JhbSBzb3J0ZWFkYXMgcGFyYSB2b2PDqiwgZmlxdWUgw6Agdm9udGFkZS4gTmEgdmVyZGFkZSwgZW0gYWxndW5zIGNhc29zLCB1bWEgcXVlc3TDo28gc3VhIHBvZGUgZGVwZW5kZXIgZGEgcmVzcG9zdGEgZGEgcXVlc3TDo28gZGUgb3V0cm8gYWx1bm8uCgoqIEVzY3JldmEgbyBtw6F4aW1vIHBvc3PDrXZlbCBzb2JyZSBvIHNldSByYWNpb2PDrW5pby4gSnVzdGlmaXF1ZSBzdWFzIHJlc3Bvc3Rhcy4KCiogVGVzdGUgc3VhcyByZXNwb3N0YXMuIFR1ZG8gZGV2ZSBlc3RhciBleGVjdXRhbmRvIHNlbSBlcnJvcy4KCiogW0VudmllIG5vIE1vb2RsZTogXXsuaGx9CgogIDEuIE8gYXJxdWl2byBSbWQgY29tIGFzIHN1YXMgcmVzb2x1w6fDtWVzIGUKICAKICAxLiBVbSB2w61kZW8gZGUgYXTDqSAkNSQgbWludXRvcyBleHBsaWNhbmRvIGFzIHN1YXMgcmVzb2x1w6fDtWVzLgoKKiBCb20gdHJhYmFsaG8uCgoKIyBBbWJpZW50ZSB7LX0KCiogUGFyYSBnZXJhciB1bSBhcnF1aXZvIEhUTUwgYSBwYXJ0aXIgZGVzdGUgZG9jdW1lbnRvLCB2b2PDqiBwcmVjaXNhIGRvcyBzZWd1aW50ZXMgcGFjb3RlcyBkbyBSOgoKICBgYGB7ciBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KICBwYWNvdGVzIDwtIHNlc3Npb25faW5mbygnYXR0YWNoZWQnKSRwYWNrYWdlcyRwYWNrYWdlCiAgcGFjb3Rlc190aWR5IDwtIGdldE5hbWVzcGFjZSgidGlkeXZlcnNlIikkY29yZQogIHBhY290ZXMgPC0gYygKICAgIHNldGRpZmYocGFjb3RlcywgcGFjb3Rlc190aWR5KSwKICAgICdmbmF1ZmVsUm1kJywKICAgICdkZXZ0b29scycKICApICU+JSAKICAgIHNvcnQoKQogICAKICBwYXN0ZSgnICAqIGAnLCBwYWNvdGVzLCAnYCcsIGNvbGxhcHNlID0gJ1xuXG4nKSAlPiUgCiAgICBjYXQoKQogIGBgYAoKKiBTZSB2b2PDqiBlc3RpdmVyIHVzYW5kbyBvIFVidW50dSwgdm9jw6ogcHJlY2lzYSBpbnN0YWxhciAtLS0gW3BlbG8gc2lzdGVtYSwgbsOjbyBwZWxvIFJdey5obH0gLS0tIG8gcGFjb3RlIGBsaWJnZGFsLWRldmAuIEZhw6dhIGlzdG8gW2FudGVzXXsuaGx9IGRlIGV4ZWN1dGFyIG8gY8OzZGlnbyBhYmFpeG8uCgoqIEV4ZWN1dGUgbyBzZWd1aW50ZSBjw7NkaWdvIHBhcmEgaW5zdGFsYXIgb3MgcGFjb3RlcyBxdWUgZXN0w6NvIGZhbHRhbmRvIG5vIHNldSBhbWJpZW50ZToKCiAgICBgYGB7ciBtZXNzYWdlPUZBTFNFfQogICAgaWYgKCFyZXF1aXJlKCdkZXZ0b29scycpKQogICAgICBpbnN0YWxsLnBhY2thZ2VzKCdkZXZ0b29scycpCiAgICAKICAgIGlmICghcmVxdWlyZSgnZm5hdWZlbFJtZCcpKQogICAgICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImZuYXVmZWwvZm5hdWZlbFJtZCIpCiAgICAKICAgIHBhY290ZXMgPC0gYygKICAgICAgJ2NvbmZsaWN0ZWQnLAogICAgICAna2FibGVFeHRyYScsCiAgICAgICdrbml0cicsCiAgICAgICdsYXRleDJleHAnLAogICAgICAnbGVhZmxldCcsCiAgICAgICdzZXNzaW9uaW5mbycsCiAgICAgICdzdW1tYXJ5dG9vbHMnLAogICAgICAndGlkeXZlcnNlJwogICAgKQogICAgCiAgICBpbnN0YWxhcl9zZV9wcmVjaXNvIDwtIGZ1bmN0aW9uKHgpIHsKICAgICAgCiAgICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKQogICAgICAgIGluc3RhbGwucGFja2FnZXMoeCkKICAgICAgCiAgICB9CiAgICAKICAgIGludmlzaWJsZShzYXBwbHkocGFjb3RlcywgaW5zdGFsYXJfc2VfcHJlY2lzbykpCiAgICBgYGAKCiogU2UgaG91dmVyIGVycm8gbmEgaW5zdGFsYcOnw6NvLCBlbnRyZSBlbSBjb250YXRvIGNvbWlnbyBwZWxvIFRlbGVncmFtLCBbZW52aWFuZG8gdG9kYXMgYXMgbWVuc2FnZW5zIGVtaXRpZGFzIHF1YW5kbyB2b2PDqiBleGVjdXRvdSBvcyBjb21hbmRvc117LmhsfS4KCgojIExlaXR1cmEgZSBsaW1wZXphIGRvcyBkYWRvcwoKMS4gT3Mgbm9tZXMgZGFzIGNvbHVuYXMgb3JpZ2luYWlzIGVzdMOjbyBlbSBpbmdsw6pzLiBQYXJhIHZlciBvIFtkaWNpb27DoXJpbyBkZSBkYWRvc117LmhsfSAtLS0gZG9jdW1lbnRhw6fDo28gc29icmUgY2FkYSB1bWEgZGFzIGNvbHVuYXMgLS0tIHZpc2l0ZSBodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL2NyaXNwYXJhZGEvYnJhemlsaWFuLWNpdGllcz9zZWxlY3Q9RGF0YV9EaWN0aW9uYXJ5LmNzdi4KCjEuIEVpcyB1bWEgZnVuw6fDo28gcGFyYSByZW5vbWVhciBhcyBjb2x1bmFzIHBhcmEgcG9ydHVndcOqcy4gRWxhIHNpbXBsZXNtZW50ZSByZXRvcm5hIHVtIHZldG9yIGNvbSBvcyBub3ZvcyBub21lcywgbmEgbWVzbWEgb3JkZW0gcXVlIGFzIGNvbHVuYXMgb3JpZ2luYWlzLgoKICAgIGBgYHtyfQogICAgcmVub21lYXIgPC0gZnVuY3Rpb24oeCkgewogICAgICAKICAgICAgYygKICAgICAgICAnY2lkYWRlJywKICAgICAgICAnZXN0YWRvJywKICAgICAgICAnY2FwaXRhbCcsCiAgICAgICAgJ3BvcF9yZXNpZCcsCiAgICAgICAgJ3BvcF9yZXNpZF9icmFzJywKICAgICAgICAncG9wX3Jlc2lkX2VzdHInLAogICAgICAgICd1bmlkYWRlc19kb21lc3QnLAogICAgICAgICd1bmlkYWRlc19kb21lc3RfdXJiYW4nLAogICAgICAgICd1bmlkYWRlc19kb21lc3RfcnVyYWwnLAogICAgICAgICdwb3BfcmVndWxhcicsCiAgICAgICAgJ3BvcF9yZWd1bGFyXzEnLAogICAgICAgICdwb3BfcmVndWxhcl8xXzQnLAogICAgICAgICdwb3BfcmVndWxhcl81XzknLAogICAgICAgICdwb3BfcmVndWxhcl8xMF8xNCcsCiAgICAgICAgJ3BvcF9yZWd1bGFyXzE1XzU5JywKICAgICAgICAncG9wX3JlZ3VsYXJfNjBfbWFpcycsCiAgICAgICAgJ2FyZWFfY3VsdGl2YWRhJywKICAgICAgICAncHJvZHVjYW9fcnVyYWwnLAogICAgICAgICdpZGhtX3JhbmtpbmcnLAogICAgICAgICdpZGhtJywKICAgICAgICAnaWRobV9yZW5kYScsCiAgICAgICAgJ2lkaG1fbG9uZ2V2aWRhZGUnLAogICAgICAgICdpZGhtX2VkdWNhY2FvJywKICAgICAgICAnbG9uZ2l0dWRlJywKICAgICAgICAnbGF0aXR1ZGUnLAogICAgICAgICdhbHRpdHVkZScsCiAgICAgICAgJ3R2X2Fzc2luYXR1cmEnLAogICAgICAgICd0ZWxlZm9uZXNfZml4b3MnLAogICAgICAgICdhcmVhJywKICAgICAgICAncmVnaWFvX3R1cmlzbW8nLAogICAgICAgICdjYXRlZ29yaWFfdHVyaXNtbycsCiAgICAgICAgJ3BvcF9lc3RpbWFkYScsCiAgICAgICAgJ3RpcG8nLAogICAgICAgICdndmFfYWdyb3BlYycsCiAgICAgICAgJ2d2YV9pbmR1c3RyaWEnLAogICAgICAgICdndmFfc2Vydmljb3MnLAogICAgICAgICdndmFfcHVibGljbycsCiAgICAgICAgJ2d2YV90b3RhbCcsCiAgICAgICAgJ2ltcG9zdG9zJywKICAgICAgICAncGliJywKICAgICAgICAncG9wX3BpYicsCiAgICAgICAgJ3BpYl9jYXBpdGEnLAogICAgICAgICdhdGl2aWRhZGVfcHJpbmNpcGFsJywKICAgICAgICAnZGVzcGVzYXNfbXVuaWNpcGFpcycsCiAgICAgICAgJ2VtcHJlc2FzX3RvdCcsCiAgICAgICAgJ2VtcHJlc2FzX2EnLAogICAgICAgICdlbXByZXNhc19iJywKICAgICAgICAnZW1wcmVzYXNfYycsCiAgICAgICAgJ2VtcHJlc2FzX2QnLAogICAgICAgICdlbXByZXNhc19lJywKICAgICAgICAnZW1wcmVzYXNfZicsCiAgICAgICAgJ2VtcHJlc2FzX2cnLAogICAgICAgICdlbXByZXNhc19oJywKICAgICAgICAnZW1wcmVzYXNfaScsCiAgICAgICAgJ2VtcHJlc2FzX2onLAogICAgICAgICdlbXByZXNhc19rJywKICAgICAgICAnZW1wcmVzYXNfbCcsCiAgICAgICAgJ2VtcHJlc2FzX20nLAogICAgICAgICdlbXByZXNhc19uJywKICAgICAgICAnZW1wcmVzYXNfbycsCiAgICAgICAgJ2VtcHJlc2FzX3AnLAogICAgICAgICdlbXByZXNhc19xJywKICAgICAgICAnZW1wcmVzYXNfcicsCiAgICAgICAgJ2VtcHJlc2FzX3MnLAogICAgICAgICdlbXByZXNhc190JywKICAgICAgICAnZW1wcmVzYXNfdScsCiAgICAgICAgJ2hvdGVpcycsCiAgICAgICAgJ2NhbWFzJywKICAgICAgICAnYWdlbmNpYXNfcHJpdicsCiAgICAgICAgJ2FnZW5jaWFzX3B1YmwnLAogICAgICAgICdiYW5jb3NfcHJpdicsCiAgICAgICAgJ2JhbmNvc19wdWJsJywKICAgICAgICAncGF0cmltb25pb19iYW5jb3NfcHJpdicsCiAgICAgICAgJ3BhdHJpbW9uaW9fYmFuY29zX3B1YmwnLAogICAgICAgICdjYXJyb3MnLAogICAgICAgICdtb3RvcycsCiAgICAgICAgJ3RyYXRvcmVzJywKICAgICAgICAndWJlcicsCiAgICAgICAgJ21hYycsCiAgICAgICAgJ3dhbG1hcnQnLAogICAgICAgICdjb3JyZWlvcycKICAgICAgKQogICAgICAKICAgIH0KICAgIGBgYAoKMS4gTGVyIG9zIGRhZG9zLCByZW5vbWVhciBhcyBjb2x1bmFzIGUgbXVkYXIgbyB0aXBvIGRlIGR1YXMgZGVsYXM6CgogICAgYGBge3J9CiAgICBjaWRhZGVzIDwtIHJlYWRfY3N2KAogICAgICAnZGFkb3MvQlJBWklMX0NJVElFU19SRVYyMDIyLkNTVicKICAgICkgJT4lIAogICAgICByZW5hbWVfd2l0aCguZm4gPSByZW5vbWVhcikgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgY2FwaXRhbCA9IGFzLmxvZ2ljYWwoY2FwaXRhbCksCiAgICAgICAgdWJlciA9IGFzLmxvZ2ljYWwodWJlcikKICAgICAgKQogICAgYGBgCgoxLiBFeGFtaW5hciBhICp0aWJibGUqIGNvbSBgZGZTdW1tYXJ5YDoKCiAgICBgYGB7ciBjYWNoZT1UUlVFfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGRmU3VtbWFyeSgpICU+JSAKICAgICAgcHJpbnQobWV0aG9kID0gJ3JlbmRlcicpCiAgICBgYGAKCgojIEFuw6FsaXNlIGV4cGxvcmF0w7NyaWEgeyNlZGF9CgojIyBJREhNCgoxLiBQZXNxdWlzZSBvIHF1ZSDDqSBJREhNLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBTZWd1bmRvIGEgW1dpa2lwZWRpYSAoY29uc3VsdGFkYSBlbSAwMi8wNi8yMDIyKV0oaHR0cHM6Ly9wdC53aWtpcGVkaWEub3JnL3dpa2kvJUMzJThEbmRpY2VfZGVfRGVzZW52b2x2aW1lbnRvX0h1bWFub19NdW5pY2lwYWwpOgogICAKICAgPiBPIMONbmRpY2UgZGUgRGVzZW52b2x2aW1lbnRvIEh1bWFubyBNdW5pY2lwYWwgw6kgdW1hIHZlcnPDo28gbW9kaWZpY2FkYSBkbyBJREggdXNhZG8gcGFyYSBjYWxjdWxhciBvIElESCBkYXMgdW5pZGFkZXMgZmVkZXJhdGl2YXMgZG8gQnJhc2lsLiBQb3Igc2VyIHVtYSB2ZXJzw6NvIG1vZGlmaWNhZGEgZG8gSURILCBuw6NvIMOpIHJlY29tZW5kYWRhIGEgY29tcGFyYcOnw6NvIGNvbSBvdXRyb3MgcGHDrXNlcyBxdWUgdXNhbSBvIElESCBwYWRyw6NvLgogICAKICAgPiBGb2kgY3JpYWRvIHBhcmEgc2VyIHVtIMOtbmRpY2Ugc2ltaWxhciBhbyBJREggcXVlIHNlIGFkZXF1YXNzZSDDoCBkZW1vZ3JhZmlhIGJyYXNpbGVpcmEuCiAgICAgCiAgID4gTyDDrW5kaWNlIHRlbSAzIGluZGljYWRvcmVzOiBJREhNIExvbmdldmlkYWRlLCBJREhNIEVkdWNhw6fDo28sIElESE0gUmVuZGEuCgogICA6OjoKICAgCjEuIFF1YWwgbyB2YWxvciBtw6F4aW1vIHBvc3PDrXZlbD8gUXVhbCBvIHZhbG9yIG3DoXhpbW8gbmEgKnRpYmJsZSo/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFNlZ3VuZG8gW2EgbWVzbWEgZm9udGVdKGh0dHBzOi8vcHQud2lraXBlZGlhLm9yZy93aWtpLyVDMyU4RG5kaWNlX2RlX0Rlc2Vudm9sdmltZW50b19IdW1hbm9fTXVuaWNpcGFsKSwgbyB2YWxvciBtw6F4aW1vIMOpICQxJC4KICAgCiAgIE5hICp0aWJibGUqLCBvIHZhbG9yIG3DoXhpbW8gw6kKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lCiAgICAgIHNsaWNlX21heChpZGhtLCBuID0gMSkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGlkaG0pCiAgICBgYGAKICAgCiAgIDo6OgogICAKICAgICAKIyMgRXN0YWRvcyBlIGNhcGl0YWlzCgoxLiBDb21wYXJlIGEgcXVhbnRpZGFkZSBkZSBlc3RhZG9zIGNvbSBhIHF1YW50aWRhZGUgZGUgY2FwaXRhaXMuIE8gcXVlIGVzdMOhIGVycmFkbz8gQ29uc2VydGUgYSBzaXR1YcOnw6NvLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBDb21vIGBjYXBpdGFsYCDDqSB1bWEgY29sdW5hIGJvb2xlYW5hLCB1c2Ftb3MgYHN1bWAgcGFyYSBvYnRlciBhIHF1YW50aWRhZGUgZGUgbXVuaWPDrXBpb3MgcGFyYSBvcyBxdWFpcyBgY2FwaXRhbGAgw6kgdmVyZGFkZWlybzoKCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBzdW1tYXJpemUoCiAgICAgICAgZXN0YWRvcyA9IG5fZGlzdGluY3QoZXN0YWRvKSwKICAgICAgICBjYXBpdGFpcyA9IHN1bShjYXBpdGFsKQogICAgICApCiAgICBgYGAKICAgIAogICBBcyBxdWFudGlkYWRlcyBzw6NvIGRpZmVyZW50ZXMhCiAgIAogICBMaXN0YW5kbyBhcyBjYXBpdGFpcyBjb20gc2V1cyByZXNwZWN0aXZvcyBlc3RhZG9zOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihjYXBpdGFsKSAlPiUgCiAgICAgIHNlbGVjdChlc3RhZG8sIGNpZGFkZSkgJT4lIAogICAgICBhcnJhbmdlKGVzdGFkbykKICAgIGBgYAoKICAgRW0gYWxndW5zIGVzdGFkb3MsIGV4aXN0ZW0gY2lkYWRlcyAtLS0gbsOjby1jYXBpdGFpcyAtLS0gcXVlIHTDqm0gbyBtZXNtbyBub21lIHF1ZSBjYXBpdGFpcyBkZSBvdXRyb3MgZXN0YWRvcy4gRXN0YXMgY2lkYWRlcyBlc3TDo28gbWFyY2FkYXMgY29tbyBjYXBpdGFpcy4KICAgCiAgICBgYGB7cn0KICAgIHJlcGV0aWRhcyA8LSBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKGNhcGl0YWwpICU+JSAKICAgICAgc2VsZWN0KGVzdGFkbywgY2lkYWRlKSAlPiUgCiAgICAgIGFycmFuZ2UoZXN0YWRvKSAlPiUgCiAgICAgIGFkZF9jb3VudChlc3RhZG8pICU+JSAKICAgICAgZmlsdGVyKG4gPiAxKQogICAgCiAgICByZXBldGlkYXMKICAgIGBgYAoKICAgVmFtb3MgY29uc2VydGFyOgogICAKICAgIGBgYHtyfQogICAgbmFvX2NhcGl0YWlzIDwtIHJlcGV0aWRhcyAlPiUgCiAgICAgIHNsaWNlKC1jKDMsIDQsIDgsIDkpKQogICAgCiAgICBjaWRhZGVzIDwtIGNpZGFkZXMgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgY2FwaXRhbCA9IGNhc2Vfd2hlbigKICAgICAgICAgICEoZXN0YWRvICVpbiUgbmFvX2NhcGl0YWlzJGVzdGFkbykgfiBjYXBpdGFsLCAKICAgICAgICAgICEoY2lkYWRlICVpbiUgbmFvX2NhcGl0YWlzJGNpZGFkZSkgfiBjYXBpdGFsLCAKICAgICAgICAgIFRSVUUgfiBGQUxTRQogICAgICAgICkKICAgICAgKQogICAgYGBgCiAgIAogICBFIGNvbmZlcmlyOgoKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihjYXBpdGFsKSAlPiUgCiAgICAgIHNlbGVjdChlc3RhZG8sIGNpZGFkZSkgJT4lIAogICAgICBhcnJhbmdlKGVzdGFkbykKICAgIGBgYAogICAKICAgOjo6CgoKIyMgUG9wdWxhw6fDtWVzCgoxLiBWZXJpZmlxdWUgc2UgYSBjb2x1bmEgYHBvcF9yZXNpZGAgKHBvcHVsYcOnw6NvIGRlIHJlc2lkZW50ZXMpIMOpIGEgc29tYSBkZSBgcG9wX3Jlc2lkX2JyYXNgIChwb3B1bGHDp8OjbyBkZSByZXNpZGVudGVzIGJyYXNpbGVpcm9zKSBjb20gYHBvcF9yZXNpZF9lc3RyYCAocG9wdWxhw6fDo28gZGUgcmVzaWRlbnRlcyBlc3RyYW5nZWlyb3MpLiBVc2UgYSBmdW7Dp8OjbyBgYWxsYC4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIHN1bW1hcml6ZSgKICAgICAgICBhbGwocG9wX3Jlc2lkID09IHBvcF9yZXNpZF9icmFzICsgcG9wX3Jlc2lkX2VzdHIpCiAgICAgICkKICAgIGBgYAogICAKICAgU2ltLgogICAKICAgOjo6CgoKIyMgVW5pZGFkZXMgZG9tw6lzdGljYXMKCjEuIFZlcmlmaXF1ZSBzZSBhIGNvbHVuYSBgdW5pZGFkZXNfZG9tZXN0YCAodW5pZGFkZXMgZG9tw6lzdGljYXMpIMOpIGEgc29tYSBkZSBgdW5pZGFkZXNfZG9tZXN0X3VyYmFuYCAodXJiYW5hcykgY29tIGB1bmlkYWRlc19kb21lc3RfcnVyYWxgIChydXJhaXMpLiBVc2UgYSBmdW7Dp8OjbyBgYWxsYC4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIHN1bW1hcml6ZSgKICAgICAgICBhbGwoCiAgICAgICAgICB1bmlkYWRlc19kb21lc3QgPT0gdW5pZGFkZXNfZG9tZXN0X3VyYmFuICsgdW5pZGFkZXNfZG9tZXN0X3J1cmFsCiAgICAgICAgKQogICAgICApCiAgICBgYGAKCiAgIE7Do28uCiAgIAogICAgYGBge3J9CiAgICBkaWYgPC0gY2lkYWRlcyAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBkaWZlcmVuY2EgPSAKICAgICAgICAgIHVuaWRhZGVzX2RvbWVzdCAtIHVuaWRhZGVzX2RvbWVzdF91cmJhbiAtIHVuaWRhZGVzX2RvbWVzdF9ydXJhbAogICAgICApICU+JSAKICAgICAgZmlsdGVyKAogICAgICAgIGRpZmVyZW5jYSAhPSAwCiAgICAgICkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBkaWZlcmVuY2EpCiAgICAKICAgIGRpZgogICAgCiAgICBkaWYgJT4lIAogICAgICBkaXN0aW5jdChkaWZlcmVuY2EpCiAgICBgYGAKICAgCiAgIEEgZGlmZXJlbsOnYSBudW5jYSDDqSBtYWlvciBxdWUgJDEkLgoKICAgOjo6CiAgIAoKIyMgQ2F0ZWdvcmlhcyBkZSB0dXJpc21vCgoxLiBOYSBjb2x1bmEgYGNhdGVnb3JpYV90dXJpc21vYCwgc3Vic3RpdHVhIG9zIHplcm9zIHBvciBgTkFgIGUgY29udmVydGEgdHVkbyBwYXJhIHVtIFtmYXRvciBvcmRlbmFkb117LmhsfSBjb20gbsOtdmVpcyAkRSA8IEQgPCBDIDwgQiA8IEEkLiBVc2UgYSBmdW7Dp8OjbyBgZmFjdG9yYC4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2F0ZWdvcmlhX2ZhdG9yIDwtIGNpZGFkZXMgJT4lIAogICAgICBwdWxsKGNhdGVnb3JpYV90dXJpc21vKSAlPiUgCiAgICAgIGZhY3RvcigKICAgICAgICBsZXZlbHMgPSBjKCdFJywgJ0QnLCAnQycsICdCJywgJ0EnKSwKICAgICAgICBvcmRlcmVkID0gVFJVRQogICAgICApCiAgICBgYGAKCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgPC0gY2lkYWRlcyAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBjYXRlZ29yaWFfdHVyaXNtbyA9IGNhdGVnb3JpYV9mYXRvcgogICAgICApCiAgICBgYGAKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBjb3VudChjYXRlZ29yaWFfdHVyaXNtbykKICAgIGBgYAogICAKICAgOjo6CgoKIyMgVGlwb3MKCjEuIE5hIGNvbHVuYSBgdGlwb2AsIHN1YnN0aXR1YSBvcyB6ZXJvcyBwb3IgYE5BYCBlIGNvbnZlcnRhIHR1ZG8gcGFyYSB1bSBbZmF0b3IgbsOjby1vcmRlbmFkb117LmhsfS4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgdGlwb19mYXRvciA8LSBjaWRhZGVzICU+JSAKICAgICAgcHVsbCh0aXBvKQoKICAgIHRpcG9fZmF0b3JbdGlwb19mYXRvciA9PSAnMCddIDwtIE5BCiAgICAKICAgIHRpcG9fZmF0b3IgPC0gZmFjdG9yKHRpcG9fZmF0b3IsIG9yZGVyZWQgPSBGQUxTRSkKICAgIGBgYAoKICAgIGBgYHtyfQogICAgY2lkYWRlcyA8LSBjaWRhZGVzICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIHRpcG8gPSB0aXBvX2ZhdG9yCiAgICAgICkKICAgIGBgYAogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGNvdW50KHRpcG8pCiAgICBgYGAKICAgCiAgIDo6OgoKCiMjIEF0aXZpZGFkZXMgcHJpbmNpcGFpcwoKMS4gTmEgY29sdW5hIGBhdGl2aWRhZGVfcHJpbmNpcGFsYCwgc3Vic3RpdHVhIG9zIHplcm9zIHBvciBgTkFgIGUgY29udmVydGEgdHVkbyBwYXJhIHVtIFtmYXRvciBuw6NvLW9yZGVuYWRvXXsuaGx9LgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBhcF9mYXRvciA8LSBjaWRhZGVzICU+JSAKICAgICAgcHVsbChhdGl2aWRhZGVfcHJpbmNpcGFsKQoKICAgIGFwX2ZhdG9yW2FwX2ZhdG9yID09ICcwJ10gPC0gTkEKICAgIAogICAgYXBfZmF0b3IgPC0gZmFjdG9yKGFwX2ZhdG9yLCBvcmRlcmVkID0gRkFMU0UpCiAgICBgYGAKCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgPC0gY2lkYWRlcyAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBhdGl2aWRhZGVfcHJpbmNpcGFsID0gYXBfZmF0b3IKICAgICAgKQogICAgYGBgCiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgY291bnQoYXRpdmlkYWRlX3ByaW5jaXBhbCkKICAgIGBgYAogICAKICAgOjo6CgoKIyMgUmVnacO1ZXMgZ2VvZ3LDoWZpY2FzIHsjcmVnaW9lcy1nZW99CgoxLiBDcmllIHVtYSBub3ZhIGNvbHVuYSwgW2RvIHRpcG8gZmF0b3Jdey5obH0sIGNoYW1hZGEgYHJlZ2lhb2AsIGNvbSBhIHJlZ2nDo28gZ2VvZ3LDoWZpY2EgKE5vcnRlLCBOb3JkZXN0ZSwgQ2VudHJvLU9lc3RlLCBTdWRlc3RlLCBvdSBTdWwpIG9uZGUgZXN0w6EgY2FkYSBtdW5pY8OtcGlvLiBVc2Ugb3MgbsOtdmVpcyAnTicsICdORScsICdDTycsICdTRScsICdTJy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgZXN0YWRvcyA8LSB1bmlxdWUoY2lkYWRlcyRlc3RhZG8pICU+JSBzb3J0KCkKICAgIAogICAgcmVnaW9lcyA8LSBjKAogICAgICAnTicsICdORScsICdOJywgJ04nLCAnTkUnLCAnTkUnLCAnQ08nLCAnU0UnLCAnQ08nLCAnTkUnLCAKICAgICAgJ1NFJywgJ0NPJywgJ0NPJywgJ04nLCAnTkUnLCAnTkUnLCAnTkUnLCAnUycsICdTRScsICdORScsIAogICAgICAnTicsICdOJywgJ1MnLCAnUycsICdORScsICdTRScsICdOJwogICAgKQogICAgCiAgICBuYW1lcyhyZWdpb2VzKSA8LSBlc3RhZG9zCiAgICAKICAgIGNpZGFkZXMgPC0gY2lkYWRlcyAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICByZWdpYW8gPSBmYWN0b3IocmVnaW9lc1tlc3RhZG9dKQogICAgICApCiAgICBgYGAKICAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JQogICAgICBkaXN0aW5jdChyZWdpYW8sIGVzdGFkbykgJT4lIAogICAgICBhcnJhbmdlKHJlZ2lhbykKICAgIGBgYAogICAgCiAgIDo6OgoKCiMjIFJlZ2nDtWVzIGRlIHR1cmlzbW8KCjEuIE5hIGNvbHVuYSBgcmVnaWFvX3R1cmlzbW9gLCBzdWJzdGl0dWEgb3MgemVyb3MgcG9yIGBOQWAuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFF1YW50b3MgemVyb3Mgc8Ojbz8KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBjb3VudChyZWdpYW9fdHVyaXNtbyA9PSAnMCcpCiAgICBgYGAKCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgPC0gY2lkYWRlcyAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICByZWdpYW9fdHVyaXNtbyA9IAogICAgICAgICAgaWZfZWxzZSgKICAgICAgICAgICAgcmVnaWFvX3R1cmlzbW8gPT0gJzAnLCBOQV9jaGFyYWN0ZXJfLCByZWdpYW9fdHVyaXNtbwogICAgICAgICAgKQogICAgICApCiAgICBgYGAKICAgCiAgIFZhbW9zIGNvbmZlcmlyOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGNvdW50KHJlZ2lhb190dXJpc21vID09ICcwJykKICAgIGBgYAoKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGNvdW50KGlzLm5hKHJlZ2lhb190dXJpc21vKSkKICAgIGBgYAogICAKICAgOjo6CiAgIAoKMS4gUXVhbnRhcyByZWdpw7VlcyBkZSB0dXJpc21vIHPDo28/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIG5fZGlzdGluY3QoY2lkYWRlcyRyZWdpYW9fdHVyaXNtbywgbmEucm0gPSBUUlVFKQogICAgYGBgCiAgIAogICA6OjoKICAgCjEuIFF1YWwgdGVtIG1haXMgbXVuaWPDrXBpb3M/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIoIWlzLm5hKHJlZ2lhb190dXJpc21vKSkgJT4lIAogICAgICBncm91cF9ieShyZWdpYW9fdHVyaXNtbykgJT4lIAogICAgICBzdW1tYXJpemUobXVuaWNpcGlvcyA9IG4oKSkgJT4lIAogICAgICBzbGljZV9tYXgobXVuaWNpcGlvcywgbiA9IDEpCiAgICBgYGAKICAgCiAgIDo6OgogICAKMS4gUXVhbCB0ZW0gbWVub3MgbXVuaWPDrXBpb3M/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIoIWlzLm5hKHJlZ2lhb190dXJpc21vKSkgJT4lIAogICAgICBncm91cF9ieShyZWdpYW9fdHVyaXNtbykgJT4lIAogICAgICBzdW1tYXJpemUobXVuaWNpcGlvcyA9IG4oKSkgJT4lIAogICAgICBzbGljZV9taW4obXVuaWNpcGlvcywgbiA9IDEpCiAgICBgYGAKICAgCiAgIDo6OgoKMS4gUXVhbnRvcyBtdW5pY8OtcGlvcyBuw6NvIGZhemVtIHBhcnRlIGRlIHJlZ2nDo28gZGUgdHVyaXNtbz8KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihpcy5uYShyZWdpYW9fdHVyaXNtbykpICU+JSAKICAgICAgbnJvdygpCiAgICBgYGAKICAgCiAgIDo6OgogICAKMS4gRXhpc3RlIGFsZ3VtYSByZWdpw6NvIGRlIHR1cmlzbW8gY29udGVuZG8gY2lkYWRlcyBkZSBlc3RhZG9zIGRpZmVyZW50ZXM/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIoIWlzLm5hKHJlZ2lhb190dXJpc21vKSkgJT4lIAogICAgICBncm91cF9ieShyZWdpYW9fdHVyaXNtbykgJT4lIAogICAgICBzdW1tYXJpc2UoZXN0YWRvcyA9IG5fZGlzdGluY3QoZXN0YWRvKSkgJT4lIAogICAgICBmaWx0ZXIoZXN0YWRvcyA+IDEpCiAgICBgYGAKICAgCiAgIDo6OgoKCiMjIE5vbWVzIGRhcyByZWdpw7VlcyBkZSB0dXJpc21vCgoxLiBHZXJlIHVtYSAqdGliYmxlKiBjb20gdG9kb3Mgb3MgdmFsb3JlcyBkaXN0aW50b3MgZGUgYHJlZ2lhb190dXJpc21vYCwgc2VtIHJlcGV0acOnw7Vlcy4gCgoxLiBRdWFpcyBzw6NvIGFzICQxMCQgcGFsYXZyYXMgbWFpcyBjb211bnMgcXVlIGluaWNpYW0gb3Mgbm9tZXMgZGUgcmVnacO1ZXMgZGUgdHVyaXNtbz8gVXNlIGEgZnVuw6fDo28gYHdvcmRgLgogICAKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBtYWlzX2NvbXVucyA8LSBjaWRhZGVzICU+JSAKICAgICAgZGlzdGluY3QocmVnaWFvX3R1cmlzbW8pICU+JSAKICAgICAgdHJhbnNtdXRlKHByaW1laXJhID0gd29yZChyZWdpYW9fdHVyaXNtbykpICU+JSAKICAgICAgY291bnQocHJpbWVpcmEsIHNvcnQgPSBUUlVFKSAlPiUgCiAgICAgIGhlYWQoMTApCiAgICAKICAgIG1haXNfY29tdW5zCiAgICBgYGAKICAgCiAgIDo6OgoKMS4gTGlzdGUsIGVtIG9yZGVtIGFsZmFiw6l0aWNhLCBvcyBub21lcyBjb21wbGV0b3MgZGFzIHJlZ2nDtWVzIGRlIHR1cmlzbW8gY3Vqb3Mgbm9tZXMgY29tZcOnYW0gY29tIHBhbGF2cmFzIGRlc3RhIGxpc3RhLiAKCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGRpc3RpbmN0KHJlZ2lhb190dXJpc21vKSAlPiUgCiAgICAgIGZpbHRlcigKICAgICAgICB3b3JkKHJlZ2lhb190dXJpc21vKSAlaW4lIG1haXNfY29tdW5zJHByaW1laXJhCiAgICAgICkgJT4lIAogICAgICBzZWxlY3QocmVnaWFvX3R1cmlzbW8pICU+JSAKICAgICAgYXJyYW5nZShyZWdpYW9fdHVyaXNtbykKICAgIGBgYAogICAKICAgOjo6CgoKIyMgUElCCgoxLiBWZXJpZmlxdWUgc2UgYSBjb2x1bmEgYHBpYl9jYXBpdGFgIMOpIG8gcmVzdWx0YWRvIGRhIGRpdmlzw6NvIGRlIGBwaWJgIHBvciBgcG9wX3BpYmAuIFVzZSBhIGZ1bsOnw6NvIGBhbGxgLgoKCiMjIENhcnJvcwoKMS4gUXVhaXMgYXMgJDEwJCBjaWRhZGVzIHF1ZSB0w6ptIGEgW21haW9yIHF1YW50aWRhZGUgZGUgY2Fycm9zIHBvciBoYWJpdGFudGVdey5obH0/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFNlIHVzYXJtb3MgYHBvcF9yZWd1bGFyYCwgYWxndW1hcyBjaWRhZGVzIHTDqm0gemVybyBuZXN0ZSBjYW1wbzoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgY2Fycm9zX3Bvcl9oYWJpdGFudGUgPSBjYXJyb3MgLyBwb3BfcmVndWxhcgogICAgICApICU+JSAKICAgICAgc2xpY2VfbWF4KGNhcnJvc19wb3JfaGFiaXRhbnRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBjYXJyb3NfcG9yX2hhYml0YW50ZSwgcG9wX3JlZ3VsYXIpCiAgICBgYGAKCiAgIFZhbW9zIGV4Y2x1w60tbGFzOgogICAKICAgIGBgYHtyfQogICAgY2Fycm9zX3BvcF9yZWd1bGFyIDwtIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIocG9wX3JlZ3VsYXIgPiAwKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBjYXJyb3NfcG9yX2hhYml0YW50ZSA9IGNhcnJvcyAvIHBvcF9yZWd1bGFyCiAgICAgICkgJT4lIAogICAgICBzbGljZV9tYXgoY2Fycm9zX3Bvcl9oYWJpdGFudGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGNhcnJvc19wb3JfaGFiaXRhbnRlLCB0aXBvKQogICAgCiAgICBjYXJyb3NfcG9wX3JlZ3VsYXIKICAgIGBgYCAgIAoKICAgT3UgcG9kZW1vcyB1c2FyIGEgcG9wdWxhw6fDo28gcmVzaWRlbnRlLCB0YW1iw6ltIGVsaW1pbmFuZG8gYXMgY2lkYWRlcyBjb20gemVybyBuZXN0ZSBjYW1wbzoKICAgCiAgICBgYGB7cn0KICAgIGNhcnJvc19wb3BfcmVzaWQgPC0gY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihwb3BfcmVzaWQgPiAwKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBjYXJyb3NfcG9yX2hhYml0YW50ZSA9IGNhcnJvcyAvIHBvcF9yZXNpZAogICAgICApICU+JSAKICAgICAgc2xpY2VfbWF4KGNhcnJvc19wb3JfaGFiaXRhbnRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBjYXJyb3NfcG9yX2hhYml0YW50ZSwgdGlwbykKICAgIAogICAgY2Fycm9zX3BvcF9yZXNpZAogICAgYGBgICAgICAgCgogICBPdSBwb2RlbW9zIHVzYXIgYSBwb3B1bGHDp8OjbyBlc3RpbWFkYSwgb25kZSBhcyBjaWRhZGVzIGNvbSB6ZXJvIGhhYml0YW50ZXMgdMOqbSB6ZXJvIGNhcnJvcyAtLS0gZSBvIFIgY2FsY3VsYSAkMC8wJCBjb21vIGBOYU5gLCBuw6NvIGNvbW8gYEluZmA6CiAgIAogICAgYGBge3J9CiAgICBjYXJyb3NfcG9wX2VzdCA8LSBjaWRhZGVzICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIGNhcnJvc19wb3JfaGFiaXRhbnRlID0gY2Fycm9zIC8gcG9wX2VzdGltYWRhCiAgICAgICkgJT4lIAogICAgICBzbGljZV9tYXgoY2Fycm9zX3Bvcl9oYWJpdGFudGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGNhcnJvc19wb3JfaGFiaXRhbnRlLCB0aXBvKQogICAgCiAgICBjYXJyb3NfcG9wX2VzdAogICAgYGBgICAgCgogICBWYW1vcyBjb21wYXJhcjoKCiAgICBgYGB7cn0KICAgIHRpYmJsZSgKICAgICAgcmVndWxhciA9IHBhc3RlKAogICAgICAgIGNhcnJvc19wb3BfcmVndWxhciRjaWRhZGUsCiAgICAgICAgY2Fycm9zX3BvcF9yZWd1bGFyJGVzdGFkbywKICAgICAgICBzZXAgPSAnLCAnCiAgICAgICksCiAgICAgIHJlc2lkID0gcGFzdGUoCiAgICAgICAgY2Fycm9zX3BvcF9yZXNpZCRjaWRhZGUsCiAgICAgICAgY2Fycm9zX3BvcF9yZXNpZCRlc3RhZG8sCiAgICAgICAgc2VwID0gJywgJwogICAgICApLAogICAgICBlc3RpbSA9IHBhc3RlKAogICAgICAgIGNhcnJvc19wb3BfZXN0JGNpZGFkZSwKICAgICAgICBjYXJyb3NfcG9wX2VzdCRlc3RhZG8sCiAgICAgICAgc2VwID0gJywgJwogICAgICApCiAgICApCiAgICBgYGAKCiAgIDo6OgoKMS4gUXVhaXMgYXMgJDEwJCBjaWRhZGVzIHF1ZSB0w6ptIGEgW21lbm9yIHF1YW50aWRhZGUgZGUgY2Fycm9zIHBvciBoYWJpdGFudGVdey5obH0/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFZhbW9zIGlnbm9yYXIgYXMgY2lkYWRlcyBjb20gemVybyBjYXJyb3MuCiAgIAogICBVc2FuZG8gYSBwb3B1bGHDp8OjbyByZWd1bGFyOgogICAKICAgIGBgYHtyfQogICAgY2Fycm9zX3BvcF9yZWd1bGFyIDwtIGNpZGFkZXMgJT4lCiAgICAgIGZpbHRlcihjYXJyb3MgPiAwKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBjYXJyb3NfcG9yX2hhYml0YW50ZSA9IGNhcnJvcyAvIHBvcF9yZWd1bGFyCiAgICAgICkgJT4lIAogICAgICBzbGljZV9taW4oY2Fycm9zX3Bvcl9oYWJpdGFudGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGNhcnJvc19wb3JfaGFiaXRhbnRlLCB0aXBvKQogICAgCiAgICBjYXJyb3NfcG9wX3JlZ3VsYXIKICAgIGBgYAoKICAgVXNhbmRvIGEgcG9wdWxhw6fDo28gcmVzaWRlbnRlOgogICAKICAgIGBgYHtyfQogICAgY2Fycm9zX3BvcF9yZXNpZCA8LSBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKGNhcnJvcyA+IDApICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIGNhcnJvc19wb3JfaGFiaXRhbnRlID0gY2Fycm9zIC8gcG9wX3Jlc2lkCiAgICAgICkgJT4lIAogICAgICBzbGljZV9taW4oY2Fycm9zX3Bvcl9oYWJpdGFudGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGNhcnJvc19wb3JfaGFiaXRhbnRlLCB0aXBvKQogICAgCiAgICBjYXJyb3NfcG9wX3Jlc2lkCiAgICBgYGAgICAgICAKCiAgIFVzYW5kbyBhIHBvcHVsYcOnw6NvIGVzdGltYWRhOgogICAKICAgIGBgYHtyfQogICAgY2Fycm9zX3BvcF9lc3QgPC0gY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihjYXJyb3MgPiAwKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBjYXJyb3NfcG9yX2hhYml0YW50ZSA9IGNhcnJvcyAvIHBvcF9lc3RpbWFkYQogICAgICApICU+JSAKICAgICAgc2xpY2VfbWluKGNhcnJvc19wb3JfaGFiaXRhbnRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBjYXJyb3NfcG9yX2hhYml0YW50ZSwgdGlwbykKICAgIAogICAgY2Fycm9zX3BvcF9lc3QKICAgIGBgYCAgIAoKICAgVmFtb3MgY29tcGFyYXI6CgogICAgYGBge3J9CiAgICB0aWJibGUoCiAgICAgIHJlZ3VsYXIgPSBwYXN0ZSgKICAgICAgICBjYXJyb3NfcG9wX3JlZ3VsYXIkY2lkYWRlLAogICAgICAgIGNhcnJvc19wb3BfcmVndWxhciRlc3RhZG8sCiAgICAgICAgc2VwID0gJywgJwogICAgICApLAogICAgICByZXNpZCA9IHBhc3RlKAogICAgICAgIGNhcnJvc19wb3BfcmVzaWQkY2lkYWRlLAogICAgICAgIGNhcnJvc19wb3BfcmVzaWQkZXN0YWRvLAogICAgICAgIHNlcCA9ICcsICcKICAgICAgKSwKICAgICAgZXN0aW0gPSBwYXN0ZSgKICAgICAgICBjYXJyb3NfcG9wX2VzdCRjaWRhZGUsCiAgICAgICAgY2Fycm9zX3BvcF9lc3QkZXN0YWRvLAogICAgICAgIHNlcCA9ICcsICcKICAgICAgKQogICAgKQogICAgYGBgCgogICA6OjoKCjEuIFF1YWlzIHPDo28gb3MgdGlwb3MgZGVzdGFzIGNpZGFkZXM/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIErDoSBpbmNsdcOtZG9zIG5vcyByZXN1bHRhZG9zIGFjaW1hLgogICAKICAgOjo6CiAgIAoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIEFzIGNpZGFkZXMgY29tIFttYWlzXXsuaGx9IGNhcnJvcyBwb3IgaGFiaXRhbnRlIHPDo28gdG9kYXMgZGEgcmVnacOjbyBTdWwgb3UgU3VkZXN0ZS4KICAgCiAgIFBvciB1bSBkb3MgY3JpdMOpcmlvcywgc8OjbyB0b2RhcyBkbyB0aXBvIHJ1cmFsIGFkamFjZW50ZS4KICAgCiAgIEFzIMO6bmljYXMgY2FwaXRhaXMgcXVlIGFwYXJlY2VtIHPDo28gQmVsbyBIb3Jpem9udGUgZSBDdXJpdGliYS4KICAgCiAgIEFzIGNpZGFkZXMgY29tIFttZW5vc117LmhsfSBjYXJyb3MgcG9yIGhhYml0YW50ZSBzw6NvIHRvZGFzIGRhIHJlZ2nDo28gTm9ydGUsIG9uZGUgbyB0cmFuc3BvcnRlIHJvZG92acOhcmlvIMOpIHBvdWNvIGRlc2Vudm9sdmlkby4KICAgCiAgIFPDo28gdG9kYXMgZG8gdGlwbyBydXJhbCByZW1vdG8gb3UgaW50ZXJtZWRpw6FyaW8gcmVtb3RvLgogICAKICAgOjo6CiAgIAoKIyMgTW90b3MKCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttYWlvciBxdWFudGlkYWRlIGRlIG1vdG9zIHBvciBoYWJpdGFudGVdey5obH0/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFNlIHVzYXJtb3MgYHBvcF9yZWd1bGFyYCwgYWxndW1hcyBjaWRhZGVzIHTDqm0gemVybyBuZXN0ZSBjYW1wbzoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgbW90b3NfcG9yX2hhYml0YW50ZSA9IG1vdG9zIC8gcG9wX3JlZ3VsYXIKICAgICAgKSAlPiUgCiAgICAgIHNsaWNlX21heChtb3Rvc19wb3JfaGFiaXRhbnRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBtb3Rvc19wb3JfaGFiaXRhbnRlLCBwb3BfcmVndWxhcikKICAgIGBgYAoKICAgVmFtb3MgZXhjbHXDrS1sYXM6CiAgIAogICAgYGBge3J9CiAgICBtb3Rvc19wb3BfcmVndWxhciA8LSBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKHBvcF9yZWd1bGFyID4gMCkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgbW90b3NfcG9yX2hhYml0YW50ZSA9IG1vdG9zIC8gcG9wX3JlZ3VsYXIKICAgICAgKSAlPiUgCiAgICAgIHNsaWNlX21heChtb3Rvc19wb3JfaGFiaXRhbnRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBtb3Rvc19wb3JfaGFiaXRhbnRlLCB0aXBvKQogICAgCiAgICBtb3Rvc19wb3BfcmVndWxhcgogICAgYGBgICAgCgogICBPdSBwb2RlbW9zIHVzYXIgYSBwb3B1bGHDp8OjbyByZXNpZGVudGUsIHRhbWLDqW0gZWxpbWluYW5kbyBhcyBjaWRhZGVzIGNvbSB6ZXJvIG5lc3RlIGNhbXBvOgogICAKICAgIGBgYHtyfQogICAgbW90b3NfcG9wX3Jlc2lkIDwtIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIocG9wX3Jlc2lkID4gMCkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgbW90b3NfcG9yX2hhYml0YW50ZSA9IG1vdG9zIC8gcG9wX3Jlc2lkCiAgICAgICkgJT4lIAogICAgICBzbGljZV9tYXgobW90b3NfcG9yX2hhYml0YW50ZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgbW90b3NfcG9yX2hhYml0YW50ZSwgdGlwbykKICAgIAogICAgbW90b3NfcG9wX3Jlc2lkCiAgICBgYGAgICAgICAKCiAgIE91IHBvZGVtb3MgdXNhciBhIHBvcHVsYcOnw6NvIGVzdGltYWRhLCBvbmRlIGFzIGNpZGFkZXMgY29tIHplcm8gaGFiaXRhbnRlcyB0w6ptIHplcm8gbW90b3MgLS0tIGUgbyBSIGNhbGN1bGEgJDAvMCQgY29tbyBgTmFOYCwgbsOjbyBjb21vIGBJbmZgOgogICAKICAgIGBgYHtyfQogICAgbW90b3NfcG9wX2VzdCA8LSBjaWRhZGVzICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIG1vdG9zX3Bvcl9oYWJpdGFudGUgPSBtb3RvcyAvIHBvcF9lc3RpbWFkYQogICAgICApICU+JSAKICAgICAgc2xpY2VfbWF4KG1vdG9zX3Bvcl9oYWJpdGFudGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIG1vdG9zX3Bvcl9oYWJpdGFudGUsIHRpcG8pCiAgICAKICAgIG1vdG9zX3BvcF9lc3QKICAgIGBgYCAgIAoKICAgVmFtb3MgY29tcGFyYXI6CgogICAgYGBge3J9CiAgICB0aWJibGUoCiAgICAgIHJlZ3VsYXIgPSBwYXN0ZSgKICAgICAgICBtb3Rvc19wb3BfcmVndWxhciRjaWRhZGUsCiAgICAgICAgbW90b3NfcG9wX3JlZ3VsYXIkZXN0YWRvLAogICAgICAgIHNlcCA9ICcsICcKICAgICAgKSwKICAgICAgcmVzaWQgPSBwYXN0ZSgKICAgICAgICBtb3Rvc19wb3BfcmVzaWQkY2lkYWRlLAogICAgICAgIG1vdG9zX3BvcF9yZXNpZCRlc3RhZG8sCiAgICAgICAgc2VwID0gJywgJwogICAgICApLAogICAgICBlc3RpbSA9IHBhc3RlKAogICAgICAgIG1vdG9zX3BvcF9lc3QkY2lkYWRlLAogICAgICAgIG1vdG9zX3BvcF9lc3QkZXN0YWRvLAogICAgICAgIHNlcCA9ICcsICcKICAgICAgKQogICAgKQogICAgYGBgCgogICA6OjoKCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttZW5vciBxdWFudGlkYWRlIGRlIG1vdG9zIHBvciBoYWJpdGFudGVdey5obH0/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFZhbW9zIGlnbm9yYXIgYXMgY2lkYWRlcyBjb20gemVybyBtb3Rvcy4KICAgCiAgIFVzYW5kbyBhIHBvcHVsYcOnw6NvIHJlZ3VsYXI6CiAgIAogICAgYGBge3J9CiAgICBtb3Rvc19wb3BfcmVndWxhciA8LSBjaWRhZGVzICU+JQogICAgICBmaWx0ZXIobW90b3MgPiAwKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBtb3Rvc19wb3JfaGFiaXRhbnRlID0gbW90b3MgLyBwb3BfcmVndWxhcgogICAgICApICU+JSAKICAgICAgc2xpY2VfbWluKG1vdG9zX3Bvcl9oYWJpdGFudGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIG1vdG9zX3Bvcl9oYWJpdGFudGUsIHRpcG8pCiAgICAKICAgIG1vdG9zX3BvcF9yZWd1bGFyCiAgICBgYGAKCiAgIFVzYW5kbyBhIHBvcHVsYcOnw6NvIHJlc2lkZW50ZToKICAgCiAgICBgYGB7cn0KICAgIG1vdG9zX3BvcF9yZXNpZCA8LSBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKG1vdG9zID4gMCkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgbW90b3NfcG9yX2hhYml0YW50ZSA9IG1vdG9zIC8gcG9wX3Jlc2lkCiAgICAgICkgJT4lIAogICAgICBzbGljZV9taW4obW90b3NfcG9yX2hhYml0YW50ZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgbW90b3NfcG9yX2hhYml0YW50ZSwgdGlwbykKICAgIAogICAgbW90b3NfcG9wX3Jlc2lkCiAgICBgYGAgICAgICAKCiAgIFVzYW5kbyBhIHBvcHVsYcOnw6NvIGVzdGltYWRhOgogICAKICAgIGBgYHtyfQogICAgbW90b3NfcG9wX2VzdCA8LSBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKG1vdG9zID4gMCkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgbW90b3NfcG9yX2hhYml0YW50ZSA9IG1vdG9zIC8gcG9wX2VzdGltYWRhCiAgICAgICkgJT4lIAogICAgICBzbGljZV9taW4obW90b3NfcG9yX2hhYml0YW50ZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgbW90b3NfcG9yX2hhYml0YW50ZSwgdGlwbykKICAgIAogICAgbW90b3NfcG9wX2VzdAogICAgYGBgICAgCgogICBWYW1vcyBjb21wYXJhcjoKCiAgICBgYGB7cn0KICAgIHRpYmJsZSgKICAgICAgcmVndWxhciA9IHBhc3RlKAogICAgICAgIG1vdG9zX3BvcF9yZWd1bGFyJGNpZGFkZSwKICAgICAgICBtb3Rvc19wb3BfcmVndWxhciRlc3RhZG8sCiAgICAgICAgc2VwID0gJywgJwogICAgICApLAogICAgICByZXNpZCA9IHBhc3RlKAogICAgICAgIG1vdG9zX3BvcF9yZXNpZCRjaWRhZGUsCiAgICAgICAgbW90b3NfcG9wX3Jlc2lkJGVzdGFkbywKICAgICAgICBzZXAgPSAnLCAnCiAgICAgICksCiAgICAgIGVzdGltID0gcGFzdGUoCiAgICAgICAgbW90b3NfcG9wX2VzdCRjaWRhZGUsCiAgICAgICAgbW90b3NfcG9wX2VzdCRlc3RhZG8sCiAgICAgICAgc2VwID0gJywgJwogICAgICApCiAgICApCiAgICBgYGAKCiAgIDo6OgoKMS4gUXVhaXMgc8OjbyBvcyB0aXBvcyBkZXN0YXMgY2lkYWRlcz8KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgSsOhIGluY2x1w61kb3Mgbm9zIHJlc3VsdGFkb3MgYWNpbWEuCiAgIAogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgUG9yIGRvaXMgZG9zIGNyaXTDqXJpb3MsIGFzIGNpZGFkZXMgY29tIFttYWlzXXsuaGx9IG1vdG9zIHBvciBoYWJpdGFudGUgc8OjbyB0b2RhcyBkYSByZWdpw6NvIE5vcnRlIG91IE5vcmRlc3RlLgogICAKICAgU8OjbyBkbyB0aXBvIHJ1cmFsIGFkamFjZW50ZSBvdSB1cmJhbm8uCiAgIAogICBBcyBjaWRhZGVzIGNvbSBbbWVub3Ndey5obH0gbW90b3MgcG9yIGhhYml0YW50ZSBzw6NvIHRvZGFzIGRhIHJlZ2nDo28gTm9ydGUsIG9uZGUgbyB0cmFuc3BvcnRlIHJvZG92acOhcmlvIMOpIHBvdWNvIGRlc2Vudm9sdmlkby4KICAgCiAgIFPDo28gdG9kYXMgZG8gdGlwbyBydXJhbCByZW1vdG8gb3UgcnVyYWwgYWRqYWNlbnRlLgogICAKICAgOjo6CgoKIyMgVHJhdG9yZXMKCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttYWlvciBxdWFudGlkYWRlIGRlIHRyYXRvcmVzIHBvciBoYWJpdGFudGVdey5obH0/IElnbm9yZSBhcyBjaWRhZGVzIHF1ZSB0w6ptIHplcm8gdHJhdG9yZXMuCgoxLiBRdWFpcyBhcyAkMTAkIGNpZGFkZXMgcXVlIHTDqm0gYSBbbWVub3IgcXVhbnRpZGFkZSBkZSB0cmF0b3JlcyBwb3IgaGFiaXRhbnRlXXsuaGx9PyBJZ25vcmUgYXMgY2lkYWRlcyBxdWUgdMOqbSB6ZXJvIHRyYXRvcmVzLgoKMS4gUXVhaXMgc8OjbyBvcyB0aXBvcyBkZXN0YXMgY2lkYWRlcz8KCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCgojIyDDgXJlYXMKCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttYWlvciDDoXJlYV17LmhsfT8KCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttZW5vciDDoXJlYV17LmhsfT8KCjEuIFF1YWlzIHPDo28gb3MgdGlwb3MgZGVzdGFzIGNpZGFkZXM/CgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgUHJvZHXDp8OjbyBydXJhbAoKMS4gUXVhaXMgYXMgJDEwJCBjaWRhZGVzIHF1ZSB0w6ptIGEgW21haW9yIHByb2R1w6fDo28gcnVyYWxdey5obH0/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBzbGljZV9tYXgocHJvZHVjYW9fcnVyYWwsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIHByb2R1Y2FvX3J1cmFsLCB0aXBvKQogICAgYGBgCgogICA6OjoKICAgCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttZW5vciBwcm9kdcOnw6NvIHJ1cmFsXXsuaGx9PwoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKHByb2R1Y2FvX3J1cmFsID4gMCkgJT4lIAogICAgICBzbGljZV9taW4ocHJvZHVjYW9fcnVyYWwsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIHByb2R1Y2FvX3J1cmFsLCB0aXBvKQogICAgYGBgCgogICA6OjoKCjEuIFF1YWlzIHPDo28gb3MgdGlwb3MgZGVzdGFzIGNpZGFkZXM/IElnbm9yZSBhcyBjaWRhZGVzIHF1ZSB0w6ptIHplcm8gcHJvZHXDp8OjbyBydXJhbC4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgSsOhIGluY2x1w61kb3MgbmFzIHRhYmVsYXMgYWNpbWEuCiAgIAogICA6OjoKICAgCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgTXVpdGFzIGNpZGFkZXMgZG8gdGlwbyB1cmJhbm8gbmEgbGlzdGEgZGUgbWFpb3JlcyBwcm9kdcOnw7VlcyBydXJhaXMuCiAgIAogICA6OjoKICAgCgojIyBQcm9kdcOnw6NvIHJ1cmFsICpwZXIgY2FwaXRhKgoKMS4gUXVhaXMgYXMgJDEwJCBjaWRhZGVzIHF1ZSB0w6ptIGEgW21haW9yIHByb2R1w6fDo28gcnVyYWwgKnBlciBjYXBpdGEqXXsuaGx9PwoKMS4gUXVhaXMgYXMgJDEwJCBjaWRhZGVzIHF1ZSB0w6ptIGEgW21lbm9yIHByb2R1w6fDo28gcnVyYWwgKnBlciBjYXBpdGEqXXsuaGx9PwoKMS4gUXVhaXMgc8OjbyBvcyB0aXBvcyBkZXN0YXMgY2lkYWRlcz8gSWdub3JlIGFzIGNpZGFkZXMgcXVlIHTDqm0gemVybyBwcm9kdcOnw6NvIHJ1cmFsLgoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKCiMjIERlbnNpZGFkZSBkZW1vZ3LDoWZpY2EKCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttYWlvciBkZW5zaWRhZGUgZGVtb2dyw6FmaWNhXXsuaGx9PwoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBWYW1vcyB1c2FyIGEgcG9wdWxhw6fDo28gcmVzaWRlbnRlLgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlc19kZCA8LSBjaWRhZGVzICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIGRlbnMgPSBwb3BfcmVzaWQgLyBhcmVhCiAgICAgICkKICAgIGBgYAoKICAgIGBgYHtyfQogICAgY2lkYWRlc19kZCAlPiUgCiAgICAgIHNsaWNlX21heChkZW5zLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBkZW5zLCB0aXBvKQogICAgYGBgCgogICA6OjoKICAgCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBxdWUgdMOqbSBhIFttZW5vciBkZW5zaWRhZGUgZGVtb2dyw6FmaWNhXXsuaGx9PwoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzX2RkICU+JSAKICAgICAgc2xpY2VfbWluKGRlbnMsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGRlbnMsIHRpcG8pCiAgICBgYGAKICAgCiAgIFByb2JsZW1hOiBow6EgY2lkYWRlcyBjb20gemVybyBoYWJpdGFudGVzLiBWYW1vcyBpZ25vcsOhLWxhczoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXNfZGQgJT4lIAogICAgICBmaWx0ZXIoZGVucyA+IDApICU+JSAKICAgICAgc2xpY2VfbWluKGRlbnMsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGRlbnMsIHRpcG8pCiAgICBgYGAKICAgCiAgIDo6OgogICAKMS4gUXVhaXMgc8OjbyBvcyB0aXBvcyBkZXN0YXMgY2lkYWRlcz8gCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIEluY2x1w61kb3MgbmFzIHRhYmVsYXMgYWNpbWEuCiAgIAogICA6OjoKICAgCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgQ29tIGV4Y2XDp8OjbyBkZSBPbGluZGEgZSBGb3J0YWxlemEsIGFzIGNpZGFkZXMgZGUgbWFpb3IgZGVuc2lkYWRlIGRlbW9ncsOhZmljYSBlc3TDo28gbm8gUmlvIGRlIEphbmVpcm8gZSBlbSBTw6NvIFBhdWxvLgogICAKICAgQXMgZGUgbWVub3IgZGVuc2lkYWRlIGRlbW9ncsOhZmljYSBmaWNhbSBuYSByZWdpw6NvIE5vcnRlLCBjb20gZXhjZcOnw6NvIGRlIFJvbmRvbMOibmRpYS4KICAgCiAgIDo6OgogICAKCiMjIENpZGFkZXMgZXh0cmVtYXMKCjEuIFF1YWlzIHPDo28gYXMgJDEwJCBjaWRhZGVzIGRlIFttYWlvciBlIG1lbm9yIGxhdGl0dWRlXXsuaGx9PwoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBNYWlvciBsYXRpdHVkZToKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBzbGljZV9tYXgobGF0aXR1ZGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGxhdGl0dWRlKSAgICAKICAgIGBgYAoKICAgTWVub3IgbGF0aXR1ZGU6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgc2xpY2VfbWluKGxhdGl0dWRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBsYXRpdHVkZSkgICAgCiAgICBgYGAKICAgCiAgIEEgZXhwcmVzc8OjbyAiZG8gT2lhcG9xdWUgYW8gQ2h1w60iIG7Do28gw6kgZXhhdGEuIE8gY2VydG8gcGFyZWNlIHNlciAiZGUgVWlyYW11dMOjIGFvIENodcOtIi4KICAgCiAgIDo6OgoKMS4gUXVhaXMgc8OjbyBhcyAkMTAkIGNpZGFkZXMgZGUgW21haW9yIGUgbWVub3IgbG9uZ2l0dWRlXXsuaGx9PwoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBNYWlvciBsb25naXR1ZGU6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgc2xpY2VfbWF4KGxvbmdpdHVkZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgbG9uZ2l0dWRlKSAgICAKICAgIGBgYAoKICAgVGVtb3MgdW0gcHJvYmxlbWE6IGxvbmdpdHVkZSB6ZXJvIMOpIGVtIExvbmRyZXMhIAogICAKICAgT3MgZGFkb3MgZXN0w6NvIGVycmFkb3MuIFZhbW9zIGlnbm9yYXIgY2lkYWRlcyBjb20gemVybyBubyBjYW1wbyBgbG9uZ2l0dWRlYDoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIobG9uZ2l0dWRlICE9IDApICU+JSAKICAgICAgc2xpY2VfbWF4KGxvbmdpdHVkZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgbG9uZ2l0dWRlKSAgICAKICAgIGBgYAogICAKICAgTWVub3IgbG9uZ2l0dWRlOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIHNsaWNlX21pbihsb25naXR1ZGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGxvbmdpdHVkZSkgICAgCiAgICBgYGAKICAgCiAgIDo6OgoKMS4gUXVhaXMgc8OjbyBhcyAkMTAkIGNpZGFkZXMgZGUgW21haW9yIGUgbWVub3IgYWx0aXR1ZGVdey5obH0/CgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIE1haW9yIGFsdGl0dWRlOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgc2xpY2VfbWF4KGFsdGl0dWRlLCBuID0gMTApICU+JSAKICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIGFsdGl0dWRlKSAgICAKICAgIGBgYAoKICAgTWVub3IgYWx0aXR1ZGU6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICBzbGljZV9taW4oYWx0aXR1ZGUsIG4gPSAxMCkgJT4lIAogICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgYWx0aXR1ZGUpICAgIAogICAgYGBgCiAgIAogICA6OjoKCjEuIFJlc3BvbmRhIGFzIHBlcmd1bnRhcyBhY2ltYSBbcG9yIHJlZ2nDo28gZ2VvZ3LDoWZpY2Fdey5obH0uIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIExhdGl0dWRlOgogICAKICAgU8OzIGEgcmVnacOjbyBOb3J0ZSBwb2RlIHRlciBjaWRhZGVzIGNvbSBsYXRpdHVkZSB6ZXJvLgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihsYXRpdHVkZSAhPSAwIHwgcmVnaWFvID09ICdOJykgJT4lIAogICAgICBncm91cF9ieShyZWdpYW8pICU+JSAKICAgICAgc2xpY2VfbWF4KGxhdGl0dWRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCByZWdpYW8sIGxhdGl0dWRlKQogICAgYGBgCiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ3JvdXBfYnkocmVnaWFvKSAlPiUgCiAgICAgIHNsaWNlX21pbihsYXRpdHVkZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgcmVnaWFvLCBsYXRpdHVkZSkKICAgIGBgYAogICAKICAgTG9uZ2l0dWRlOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihsb25naXR1ZGUgIT0gMCkgJT4lIAogICAgICBncm91cF9ieShyZWdpYW8pICU+JSAKICAgICAgc2xpY2VfbWF4KGxvbmdpdHVkZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgcmVnaWFvLCBsb25naXR1ZGUpCiAgICBgYGAKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIobG9uZ2l0dWRlICE9IDApICU+JSAKICAgICAgZ3JvdXBfYnkocmVnaWFvKSAlPiUgCiAgICAgIHNsaWNlX21pbihsb25naXR1ZGUsIG4gPSAxMCkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIHJlZ2lhbywgbG9uZ2l0dWRlKQogICAgYGBgCgogICBBbHRpdHVkZToKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBncm91cF9ieShyZWdpYW8pICU+JSAKICAgICAgc2xpY2VfbWF4KGFsdGl0dWRlLCBuID0gMTApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCByZWdpYW8sIGFsdGl0dWRlKQogICAgYGBgCiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ3JvdXBfYnkocmVnaWFvKSAlPiUgCiAgICAgIHNsaWNlX21pbihhbHRpdHVkZSwgbiA9IDEwKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgcmVnaWFvLCBhbHRpdHVkZSkKICAgIGBgYAoKICAgOjo6CgoKIyMgRmFpeGFzIGV0w6FyaWFzCgoxLiBRdWFpcyBhcyAkMTAkIGNpZGFkZXMgY29tIGEgW21haW9yIHByb3BvcsOnw6NvIGRlIGlkb3NvcyAoNjAgYW5vcyBvdSBtYWlzKV17LmhsfT8KCjEuIFF1YWlzIGFzICQxMCQgY2lkYWRlcyBjb20gYSBbbWVub3IgcHJvcG9yw6fDo28gZGUgaWRvc29zICg2MCBhbm9zIG91IG1haXMpXXsuaGx9PwoKMS4gUXVhaXMgc8OjbyBvcyB0aXBvcyBkZXN0YXMgY2lkYWRlcz8gCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyBWaXN1YWxpemHDp8OjbwoKOjo6IHsucm1kaW1wb3J0YW50IGxhdGV4PTF9CgoqIFRvZG9zIG9zIGdyw6FmaWNvcyBkZXZlbSBzZXIgZmVpdG9zIGNvbSBvIHBhY290ZSBnZ3Bsb3QyLgoKKiBUb2RvcyBvcyBncsOhZmljb3MgZGV2ZW0gaW5jbHVpciB0w610dWxvcywgcsOzdHVsb3MsIGxlZ2VuZGFzLCBlIG91dHJvcyBlbGVtZW50b3MgcGFyYSBmYWNpbGl0YXIgYSBjb21wcmVlbnPDo28uIEltYWdpbmUgcXVlIHNldXMgZ3LDoWZpY29zIHNlcsOjbyBwdWJsaWNhZG9zIGVtIHVtYSByZXZpc3RhIGNpZW50w61maWNhLgoKOjo6CgoKIyMgUG9wdWxhw6fDo28gZSBNY0RvbmFsZCdzCgoxLiBbQXBlbmFzIHBhcmEgYXMgY2lkYWRlcyBxdWUgdMOqbSBNY0RvbmFsZCdzXXsuaGx9LCBmYcOnYSB1bSAqc2NhdHRlcnBsb3QqIGRlIHF1YW50aWRhZGUgZGUgTWNEb25hbGQncyAobm8gZWl4byAkeSQpIHBvciBwb3B1bGHDp8OjbyAobm8gZWl4byAkeCQpLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBncmFmaWNvIDwtIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIobWFjID4gMCkgJT4lIAogICAgICBnZ3Bsb3QoCiAgICAgICAgYWVzKHggPSBwb3BfcmVzaWQsIHkgPSBtYWMpCiAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KAogICAgICAgICAgICBzY2FsZSA9IDFlLTYsCiAgICAgICAgICAgIHN1ZmZpeCA9ICdNJwogICAgICAgICAgKQogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICdRdWFudGlkYWRlIGRlIE1jRG9uYWxkXCdzIHBvciBwb3B1bGHDp8OjbycsCiAgICAgICAgICB4ID0gJ3BvcHVsYcOnw6NvJywKICAgICAgICAgIHkgPSAnUXRkZSBkZVxuTWNEb25hbGRcJ3MnCiAgICAgICAgKQogICAgCiAgICBncmFmaWNvCiAgICBgYGAKICAgCiAgIFJlc3RyaW5naW5kbyBhIGNpZGFkZXMgZGUgYXTDqSAkMiQgbWlsaMO1ZXMgZGUgaGFiaXRhbnRlcywgZWxpbWluYW5kbyBvcyAqb3V0bGllcnMqOgogICAKICAgIGBgYHtyfQogICAgZ3JhZmljbzIgPC0gZ3JhZmljbyArCiAgICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgICBsaW1pdHMgPSBjKDAsIDJlNiksCiAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KAogICAgICAgICAgc2NhbGUgPSAxZS02LAogICAgICAgICAgc3VmZml4ID0gJ00nCiAgICAgICAgKQogICAgICApCiAgICAKICAgIGdyYWZpY28yCiAgICBgYGAKICAgCiAgIAogICA6OjoKICAgCjEuIFVzZSBgZ2VvbV9zbW9vdGhgIHBhcmEgZ2VyYXIgdW1hIHJldGEgZGUgcmVncmVzc8OjbyAoY29tIGBtZXRob2QgPSAnbG0nYCBlIGBzZSA9IEZBTFNFYCkuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGdyYWZpY28gKwogICAgICBnZW9tX3Ntb290aCgKICAgICAgICBtZXRob2QgPSAnbG0nLAogICAgICAgIHNlID0gRkFMU0UKICAgICAgKQogICAgYGBgCgogICBSZXN0cmluZ2luZG8gYSBjaWRhZGVzIGRlIGF0w6kgJDIkIG1pbGjDtWVzIGRlIGhhYml0YW50ZXMsIGVsaW1pbmFuZG8gb3MgKm91dGxpZXJzKjoKCiAgICBgYGB7cn0KICAgIGdyYWZpY28yICsKICAgICAgZ2VvbV9zbW9vdGgoCiAgICAgICAgbWV0aG9kID0gJ2xtJywKICAgICAgICBzZSA9IEZBTFNFCiAgICAgICkKICAgIGBgYAogICAKICAgOjo6CiAgIAoxLiBFeGlzdGUgYWxndW1hIGNvcnJlbGHDp8OjbyBlbnRyZSBhcyBxdWFudGlkYWRlcz8gQ29tZW50ZS4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgU2ltLCBtYXMgcXVhbmRvIHJldGlyYW1vcyBvcyAqb3V0bGllcnMqLCBhIGNvcnJlbGHDp8OjbyBkaW1pbnVpOgogICAKICAgIGBgYHtyfQogICAgZGYgPC0gY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihtYWMgPiAwKQogICAgICAKICAgIGNvcihkZiRwb3BfcmVzaWQsIGRmJG1hYykKICAgIAogICAgZGYgPC0gZGYgJT4lIAogICAgICBmaWx0ZXIocG9wX3Jlc2lkIDwgMmU2KQogICAgCiAgICBjb3IoZGYkcG9wX3Jlc2lkLCBkZiRtYWMpCiAgICBgYGAKICAgCiAgIDo6OgogICAKCiMjIFBvcHVsYcOnw6NvIGUgV2FsbWFydAoKMS4gW0FwZW5hcyBwYXJhIGFzIGNpZGFkZXMgcXVlIHTDqm0gV2FsbWFydF17LmhsfSwgZmHDp2EgdW0gKnNjYXR0ZXJwbG90KiBkZSBxdWFudGlkYWRlIGRlIFdhbG1hcnRzIChubyBlaXhvICR5JCkgcG9yIHBvcHVsYcOnw6NvIChubyBlaXhvICR4JCkuCgoxLiBVc2UgYGdlb21fc21vb3RoYCBwYXJhIGdlcmFyIHVtYSByZXRhIGRlIHJlZ3Jlc3PDo28gKGNvbSBgbWV0aG9kID0gJ2xtJ2AgZSBgc2UgPSBGQUxTRWApLgoKMS4gRXhpc3RlIGFsZ3VtYSBjb3JyZWxhw6fDo28gZW50cmUgYXMgcXVhbnRpZGFkZXM/IENvbWVudGUuCgoKIyMgSURITSBlIFBJQiAqcGVyIGNhcGl0YSoKCjEuIEZhw6dhIHVtICpzY2F0dGVycGxvdCogZGUgSURITSAobm8gZWl4byAkeSQpIHBvciBQSUIgKnBlciBjYXBpdGEqIChubyBlaXhvICR4JCkuCgoxLiBVc2UgYGdlb21fc21vb3RoYCBwYXJhIGdlcmFyIHVtYSByZXRhIGRlIHJlZ3Jlc3PDo28gKGNvbSBgbWV0aG9kID0gJ2xtJ2AgZSBgc2UgPSBGQUxTRWApLgoKMS4gRXhpc3RlIGFsZ3VtYSBjb3JyZWxhw6fDo28gZW50cmUgYXMgcXVhbnRpZGFkZXM/IENvbWVudGUuCgoKIyMgSURITSBlIGRlc3Blc2FzIG11bmljaXBhaXMKCjEuIEZhw6dhIHVtICpzY2F0dGVycGxvdCogZGUgSURITSAobm8gZWl4byAkeSQpIHBvciBkZXNwZXNhcyBtdW5pY2lwYWlzIChubyBlaXhvICR4JCkuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9wb2ludCgKICAgICAgICAgIGFlcyh4ID0gZGVzcGVzYXNfbXVuaWNpcGFpcywgeSA9IGlkaG0pCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KAogICAgICAgICAgICBzY2FsZSA9IDFlLTkKICAgICAgICAgICkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnSURITSBwb3IgZGVzcGVzYXMgbXVuaWNpcGFpcycsCiAgICAgICAgICB4ID0gJ2Rlc3Blc2FzIG11bmljaXBhaXNcbihiaWxow7VlcyBSJCknLAogICAgICAgICAgeSA9ICdJREhNJwogICAgICAgICkKICAgIGBgYAogICAKICAgSG9ycsOtdmVsLiBWYW1vcyBsaW1pdGFyIGEgZGVzcGVzYXMgbWFpb3JlcyBxdWUgemVybyBlIG1lbm9yZXMgcXVlICQxJCBiaWxow6NvLCBlIGlnbm9yYXIgYXMgY2lkYWRlcyBjb20gSURITSBpZ3VhbCBhIHplcm86CgogICAgYGBge3J9CiAgICBncmFmaWNvIDwtIAogICAgICBjaWRhZGVzICU+JSAKICAgICAgICBmaWx0ZXIoCiAgICAgICAgICBiZXR3ZWVuKGRlc3Blc2FzX211bmljaXBhaXMsIDEsIDFlOSksCiAgICAgICAgICBpZGhtID4gMAogICAgICAgICkgJT4lIAogICAgICAgIGdncGxvdCgKICAgICAgICAgIGFlcyh4ID0gZGVzcGVzYXNfbXVuaWNpcGFpcywgeSA9IGlkaG0pCiAgICAgICAgKSArCiAgICAgICAgICBnZW9tX3BvaW50KCkgKwogICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoCiAgICAgICAgICAgICAgc2NhbGUgPSAxZS02CiAgICAgICAgICAgICkKICAgICAgICAgICkgKwogICAgICAgICAgbGFicygKICAgICAgICAgICAgdGl0bGUgPSAnSURITSBwb3IgZGVzcGVzYXMgbXVuaWNpcGFpcycsCiAgICAgICAgICAgIHggPSAnZGVzcGVzYXMgbXVuaWNpcGFpc1xuKG1pbGjDtWVzIFIkKScsCiAgICAgICAgICAgIHkgPSAnSURITScKICAgICAgICAgICkKICAgIAogICAgZ3JhZmljbwogICAgYGBgCiAgIAogICA6OjoKICAgCjEuIFVzZSBgZ2VvbV9zbW9vdGhgIHBhcmEgZ2VyYXIgdW1hIHJldGEgZGUgcmVncmVzc8OjbyAoY29tIGBtZXRob2QgPSAnbG0nYCBlIGBzZSA9IEZBTFNFYCkuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGdyYWZpY28gKwogICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nLCBzZSA9IEZBTFNFKQogICAgYGBgCiAgIAogICA6OjoKICAgCjEuIEV4aXN0ZSBhbGd1bWEgY29ycmVsYcOnw6NvIGVudHJlIGFzIHF1YW50aWRhZGVzPyBDb21lbnRlLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICDDiSByYXpvw6F2ZWwgcGVuc2FyIHF1ZSBkZXNwZXNhcyBtdW5pY2lwYWlzIG1haW9yZXMgZXN0w6NvIGFzc29jaWFkYXMgYSB1bSBJREhNIG1haW9yLCBwb3IgY2F1c2EgZGUgaW52ZXN0aW1lbnRvcyBlbSBzYcO6ZGUsIGVkdWNhw6fDo28sIGV0Yy4KICAgCiAgIEEgcmV0YSBkZSByZWdyZXNzw6NvIG1vc3RyYSBxdWUgc2ltLCBlbWJvcmEgYSBjb3JyZWxhw6fDo28gbsOjbyBzZWphIHTDo28gZ3JhbmRlOgogICAKICAgIGBgYHtyfQogICAgY29yKGNpZGFkZXMkaWRobSwgY2lkYWRlcyRkZXNwZXNhc19tdW5pY2lwYWlzKQogICAgYGBgCiAgIAogICBFeGlzdGVtIGNpZGFkZXMgY29tIGRlc3Blc2FzIGJhaXhhcyBlIElESE0gYWx0by4KICAgCiAgIEFjaW1hIGRlICQyNTAkIG1pbGjDtWVzIGRlIGRlc3Blc2FzLCBuZW5odW1hIGNpZGFkZSB0ZW0gSURITSBtZW5vciBxdWUgJDB7LH02JC4gCiAgIAogICA6OjoKICAgCgojIyBJREhNIGUgY2Fycm9zCgoxLiBGYcOnYSB1bSAqc2NhdHRlcnBsb3QqIGRlIElESE0gKG5vIGVpeG8gJHkkKSBwb3IgcXVhbnRpZGFkZSBkZSBjYXJyb3MgKG5vIGVpeG8gJHgkKS4KCjEuIFVzZSBgZ2VvbV9zbW9vdGhgIHBhcmEgZ2VyYXIgdW1hIHJldGEgZGUgcmVncmVzc8OjbyAoY29tIGBtZXRob2QgPSAnbG0nYCBlIGBzZSA9IEZBTFNFYCkuCgoxLiBFeGlzdGUgYWxndW1hIGNvcnJlbGHDp8OjbyBlbnRyZSBhcyBxdWFudGlkYWRlcz8gQ29tZW50ZS4KCgojIyBJREhNIGUgbW90b3MKCjEuIEZhw6dhIHVtICpzY2F0dGVycGxvdCogZGUgSURITSAobm8gZWl4byAkeSQpIHBvciBxdWFudGlkYWRlIGRlIG1vdG9zIChubyBlaXhvICR4JCkuCgoxLiBVc2UgYGdlb21fc21vb3RoYCBwYXJhIGdlcmFyIHVtYSByZXRhIGRlIHJlZ3Jlc3PDo28gKGNvbSBgbWV0aG9kID0gJ2xtJ2AgZSBgc2UgPSBGQUxTRWApLgoKMS4gRXhpc3RlIGFsZ3VtYSBjb3JyZWxhw6fDo28gZW50cmUgYXMgcXVhbnRpZGFkZXM/IENvbWVudGUuCgoKIyMgSURITSBlIHRyYXRvcmVzCgoxLiBGYcOnYSB1bSAqc2NhdHRlcnBsb3QqIGRlIElESE0gKG5vIGVpeG8gJHkkKSBwb3IgcXVhbnRpZGFkZSBkZSB0cmF0b3JlcyAobm8gZWl4byAkeCQpLiBJZ25vcmUgYXMgY2lkYWRlcyBxdWUgdMOqbSB6ZXJvIHRyYXRvcmVzLgoKMS4gVXNlIGBnZW9tX3Ntb290aGAgcGFyYSBnZXJhciB1bWEgcmV0YSBkZSByZWdyZXNzw6NvIChjb20gYG1ldGhvZCA9ICdsbSdgIGUgYHNlID0gRkFMU0VgKS4KCjEuIEV4aXN0ZSBhbGd1bWEgY29ycmVsYcOnw6NvIGVudHJlIGFzIHF1YW50aWRhZGVzPyBDb21lbnRlLgoKCiMjIENvcnJlaW9zCgoxLiBGYcOnYSB1bSBoaXN0b2dyYW1hIGRhIHF1YW50aWRhZGUgZGUgYWfDqm5jaWFzIGRlIGNvcnJlaW9zLiBVc2UgbyBuw7ptZXJvIGRlIGNsYXNzZXMgcXVlIHZvY8OqIGFjaGFyIG1haXMgYWRlcXVhZG8uCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgQ29ycmVpb3MgKnBlciBjYXBpdGEqCgoxLiBGYcOnYSB1bSBoaXN0b2dyYW1hIGRhIHJhesOjbyBbKG7Dum1lcm8gZGUgYWfDqm5jaWFzIGRlIGNvcnJlaW8pIC8gKHBvcHVsYcOnw6NvKV17LmhsfS4gVXNlIG8gbsO6bWVybyBkZSBjbGFzc2VzIHF1ZSB2b2PDqiBhY2hhciBtYWlzIGFkZXF1YWRvLgoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKCiMjIEFnw6puY2lhcyBiYW5jw6FyaWFzIChww7pibGljYXMpCgoxLiBGYcOnYSB1bSBoaXN0b2dyYW1hIGRhIHF1YW50aWRhZGUgZGUgYWfDqm5jaWFzIGJhbmPDoXJpYXMgcMO6YmxpY2FzLiBVc2UgbyBuw7ptZXJvIGRlIGNsYXNzZXMgcXVlIHZvY8OqIGFjaGFyIG1haXMgYWRlcXVhZG8uCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIEV4aXN0ZW0gbXVpdGFzIGNpZGFkZXMgY29tIHplcm8gYWfDqm5jaWFzIHDDumJsaWNhczoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBjb3VudChhZ2VuY2lhc19wdWJsKQogICAgYGBgCiAgIAogICBWYW1vcyBpZ25vcsOhLWxhczoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIoYWdlbmNpYXNfcHVibCA+IDApICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gYWdlbmNpYXNfcHVibCkpCiAgICBgYGAKICAgCiAgIEFpbmRhIGFzc2ltLCBhIGdyYW5kZSBxdWFudGlkYWRlIGRlIGNpZGFkZXMgY29tIHPDsyB1bWEgYWfDqm5jaWEgZmF6IG8gaGlzdG9ncmFtYSBmaWNhciBuw6NvLWludGVyZXNzYW50ZS4gCiAgIAogICBWYW1vcyBmYXplciB1bSBoaXN0b2dyYW1hIGRvIFtsb2dhcml0bW9dey5obH0gZG8gbsO6bWVybyBkZSBhZ8OqbmNpYXMuIAogICAKICAgIGBgYHtyfQogICAgcHVibGljYXMgPC0gY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihhZ2VuY2lhc19wdWJsID4gMCkgJT4lIAogICAgICBtdXRhdGUobG9nX3B1YmwgPSBsb2coYWdlbmNpYXNfcHVibCwgMikpICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKAogICAgICAgICAgYWVzKHggPSBsb2dfcHVibCksCiAgICAgICAgICBicmVha3MgPSAwOjEwCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgMl54LAogICAgICAgICAgYnJlYWtzID0gMDoxMAogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICdRdWFudGlkYWRlIGRlIGFnw6puY2lhcyBww7pibGljYXMnLAogICAgICAgICAgc3VidGl0bGUgPSAnKGVzY2FsYSBsb2dhcsOtdG1pY2EpJywKICAgICAgICAgIHggPSAnYWfDqm5jaWFzJywKICAgICAgICAgIHkgPSBOVUxMCiAgICAgICAgKSArCiAgICAgICAgeWxpbSgwLCAyNTAwKSArCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpCiAgICAKICAgIHB1YmxpY2FzCiAgICBgYGAKCiAgIFBlcmNlYmEgY29tbyBvcyByw7N0dWxvcyBkbyBlaXhvICR4JCBzw6NvIGFzIHF1YW50aWRhZGVzIGRlIGFnw6puY2lhcywgbsOjbyBvcyBsb2dhcml0bW9zLgogICAKICAgOjo6CgoxLiBDb21wYXJlIGNvbSBhIGRpc3RyaWJ1acOnw6NvIGRlIGFnw6puY2lhcyBwcml2YWRhcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyIGhpc3RvZ3JhbWEtcHJpdmFkYXMsIGluY2x1ZGU9RkFMU0V9CiAgICBwcml2YWRhcyA8LSBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKGFnZW5jaWFzX3ByaXYgPiAwKSAlPiUgCiAgICAgIG11dGF0ZShsb2dfcHJpdiA9IGxvZyhhZ2VuY2lhc19wcml2LCAyKSkgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9oaXN0b2dyYW0oCiAgICAgICAgICBhZXMoeCA9IGxvZ19wcml2KSwKICAgICAgICAgIGJyZWFrcyA9IDA6MTAKICAgICAgICApICsKICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgICAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSAyXngsCiAgICAgICAgICBicmVha3MgPSAwOjEwCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1F1YW50aWRhZGUgZGUgYWfDqm5jaWFzIHByaXZhZGFzJywKICAgICAgICAgIHN1YnRpdGxlID0gJyhlc2NhbGEgbG9nYXLDrXRtaWNhKScsCiAgICAgICAgICB4ID0gJ2Fnw6puY2lhcycsCiAgICAgICAgICB5ID0gTlVMTAogICAgICAgICkgKwogICAgICAgIHlsaW0oMCwgMjUwMCkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQogICAgCiAgICBwcml2YWRhcwogICAgYGBgCiAgIAogICBbVmVqYSBhIGRpc3RyaWJ1acOnw6NvIGRlIGFnw6puY2lhcyBwcml2YWRhcyBhcXVpLl0oI2FnJUMzJUFBbmNpYXMtYmFuYyVDMyVBMXJpYXMtcHJpdmFkYXMpCgogICAgYGBge3J9CiAgICBwcml2YWRhcyArIHB1YmxpY2FzCiAgICBgYGAKICAgCiAgIFZhbW9zIHZlciBhbGd1bWEgdGFiZWxhcy4KICAgCiAgIFRvdGFpcyBkZSBhZ8OqbmNpYXM6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgc3VtbWFyaXplKAogICAgICAgIHByaXZhZGFzID0gc3VtKGFnZW5jaWFzX3ByaXYpLAogICAgICAgIHDDumJsaWNhcyA9IHN1bShhZ2VuY2lhc19wdWJsKQogICAgICApCiAgICBgYGAKICAgCiAgIFtObyB0b3RhbCwgZXhpc3RlbSBtYWlzIGFnw6puY2lhcyBkZSBiYW5jb3MgcHJpdmFkb3MhXXsuaGx9CiAgIAogICBRdWFudGlkYWRlIGRlIGNpZGFkZXMgYXRlbmRpZGFzOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIHN1bW1hcml6ZSgKICAgICAgICBwcml2YWRhcyA9IHN1bShhZ2VuY2lhc19wcml2ID4gMCksCiAgICAgICAgcMO6YmxpY2FzID0gc3VtKGFnZW5jaWFzX3B1YmwgPiAwKQogICAgICApCiAgICBgYGAKICAgCiAgIFtFeGlzdGVtIG1haXMgY2lkYWRlcyBjb20gcGVsbyBtZW5vcyB1bWEgYWfDqm5jaWEgZGUgYmFuY28gcMO6YmxpY28gZG8gcXVlIGNpZGFkZXMgY29tIHBlbG8gbWVub3MgdW1hIGFnw6puY2lhIGRlIGJhbmNvIHByaXZhZG8uXXsuaGx9CiAgIAogICBPdSwgY29tcGFyYW5kbyBhIHF1YW50aWRhZGUgZGUgY2lkYWRlcyBbc2VtXXsuaGx9IGFnw6puY2lhczoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBzdW1tYXJpemUoCiAgICAgICAgc2VtX3ByaXZhZGFzID0gc3VtKGFnZW5jaWFzX3ByaXYgPT0gMCksCiAgICAgICAgc2VtX3DDumJsaWNhcyA9IHN1bShhZ2VuY2lhc19wdWJsID09IDApLAogICAgICAgIHNlbV9xdWFscXVlciA9IHN1bShhZ2VuY2lhc19wdWJsID09IDAgJiBhZ2VuY2lhc19wcml2ID09IDApCiAgICAgICkKICAgIGBgYAogICAKICAgTGVtYnJlLXNlIGRlIHF1ZSBvIHRvdGFsIGRlIGNpZGFkZXMgw6kKICAgCiAgICBgYGB7cn0KICAgIG5yb3coY2lkYWRlcykKICAgIGBgYAogICAKICAgT3Ugc2VqYSwgW2NlcmNhIGRlICRgciAoMTAwICogMjIzMy9ucm93KGNpZGFkZXMpKSAlPiUgZm0oMClgXCUkIGRlIGNpZGFkZXMgbsOjbyB0w6ptIGFnw6puY2lhcyBiYW5jw6FyaWFzLCBuZW0gcHJpdmFkYXMsIG5lbSBww7pibGljYXMhXXsuaGx9CiAgIAogICBBbGnDoXMsIGV4aXN0ZSBhbGd1bWEgY2lkYWRlIHF1ZSB0ZW5oYSBhZ8OqbmNpYSBwcml2YWRhLCBtYXMgbsOjbyBww7pibGljYT8gUXVhbnRhcz8KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIoCiAgICAgICAgYWdlbmNpYXNfcHJpdiA+IDAgJiBhZ2VuY2lhc19wdWJsID09IDAKICAgICAgKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIGVzdGFkbywgc3RhcnRzX3dpdGgoJ2FnZW5jaWFzJykpCiAgICBgYGAKICAgCiAgIEUgZXhpc3RlIGFsZ3VtYSBjaWRhZGUgcXVlIHRlbmhhIGFnw6puY2lhIHDDumJsaWNhLCBtYXMgbsOjbyBwcml2YWRhPyBRdWFudGFzPwogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcigKICAgICAgICBhZ2VuY2lhc19wcml2ID09IDAgJiBhZ2VuY2lhc19wdWJsID4gMAogICAgICApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBzdGFydHNfd2l0aCgnYWdlbmNpYXMnKSkKICAgIGBgYAoKICAgOjo6CgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIENvbWVudMOhcmlvcyBpbmNsdcOtZG9zIG5hcyByZXNwb3N0YXMgYWNpbWEuCiAgIAogICA6OjoKICAgCgojIyBBZ8OqbmNpYXMgYmFuY8OhcmlhcyAocMO6YmxpY2FzKSAqcGVyIGNhcGl0YSoKCjEuIEZhw6dhIHVtIGhpc3RvZ3JhbWEgZGEgcmF6w6NvIFsobsO6bWVybyBkZSBhZ8OqbmNpYXMgYmFuY8OhcmlhcyBww7pibGljYXMpIC8gKHBvcHVsYcOnw6NvKV17LmhsfS4gVXNlIG8gbsO6bWVybyBkZSBjbGFzc2VzIHF1ZSB2b2PDqiBhY2hhciBtYWlzIGFkZXF1YWRvLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3IgcHJpdmFkYXMtcGVyLWNhcGl0YSwgaW5jbHVkZT1GQUxTRX0KICAgIHByaXZhZGFzcGMgPC0gY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihhZ2VuY2lhc19wcml2ID4gMCkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgcHJpdmFkYXNfcGVyX2NhcGl0YSA9IGFnZW5jaWFzX3ByaXYgLyBwb3BfcmVzaWQKICAgICAgKSAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2hpc3RvZ3JhbSgKICAgICAgICAgIGFlcyh4ID0gcHJpdmFkYXNfcGVyX2NhcGl0YSksCiAgICAgICAgICBicmVha3MgPSBzZXEoMCwgLjAwMDksIC4wMDAwNSkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnQWfDqm5jaWFzIHByaXZhZGFzIHBlciBjYXBpdGEnLAogICAgICAgICAgeCA9ICdhZ8OqbmNpYXMnLAogICAgICAgICAgeSA9IE5VTEwKICAgICAgICApICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1KSkgKwogICAgICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAxMjUwLCAyNTApLAogICAgICAgICAgbGltaXRzID0gYygwLCAxMjUwKQogICAgICAgICkKICAgIAogICAgcHJpdmFkYXNwYwogICAgYGBgCiAgIAogICBFeGlzdGVtIG11aXRhcyBjaWRhZGVzIGNvbSB6ZXJvIGFnw6puY2lhcyBww7pibGljYXM6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgY291bnQoYWdlbmNpYXNfcHVibCkKICAgIGBgYAogICAKICAgVmFtb3MgaWdub3LDoS1sYXMuCiAgIAogICAgYGBge3J9CiAgICBwdWJsaWNhc3BjIDwtIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIoYWdlbmNpYXNfcHVibCA+IDApICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIHB1YmxpY2FzX3Blcl9jYXBpdGEgPSBhZ2VuY2lhc19wdWJsIC8gcG9wX3Jlc2lkCiAgICAgICkgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9oaXN0b2dyYW0oCiAgICAgICAgICBhZXMoeCA9IHB1YmxpY2FzX3Blcl9jYXBpdGEpLAogICAgICAgICAgYnJlYWtzID0gc2VxKDAsIC4wMDA5LCAuMDAwMDUpCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ0Fnw6puY2lhcyBww7pibGljYXMgcGVyIGNhcGl0YScsCiAgICAgICAgICB4ID0gJ2Fnw6puY2lhcycsCiAgICAgICAgICB5ID0gTlVMTAogICAgICAgICkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQogICAgCiAgICBwdWJsaWNhc3BjCiAgICBgYGAKICAgCiAgIDo6OgoKMS4gQ29tcGFyZSBjb20gYSBkaXN0cmlidWnDp8OjbyBkZSBhZ8OqbmNpYXMgcHJpdmFkYXMuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIHByaXZhZGFzcGMgKyBwdWJsaWNhc3BjCiAgICBgYGAKCiAgIFBhcmEgcXVhc2UgdG9kb3Mgb3MgdmFsb3JlcyBkZSBhZ8OqbmNpYXMgKnBlciBjYXBpdGEqLCBleGlzdGVtIG1haXMgY2lkYWRlcyBjb20gYWfDqm5jaWFzIHDDumJsaWNhcyBkbyBxdWUgY2lkYWRlcyBjb20gYWfDqm5jaWFzIHByaXZhZGFzLiAKICAgCiAgIElzdG8gw6kgY29uc2VxdcOqbmNpYSBkZSBxdWUsIG5vIHRvdGFsLCBbZXhpc3RlbSBtYWlzIGNpZGFkZXMgYXRlbmRpZGFzIHBvciBiYW5jb3MgcMO6YmxpY29zIGRvIHF1ZSBwb3IgYmFuY29zIHByaXZhZG9zXSgjYWclQzMlQUFuY2lhcy1iYW5jJUMzJUExcmlhcy1wJUMzJUJBYmxpY2FzKS4KICAgCiAgIE1hcyBldSBkZXZpYSB0ZXIgcGVkaWRvIHVtICpzY2F0dGVycGxvdCogZGUgYWfDqm5jaWFzIHBvciBwb3B1bGHDp8OjbyBwYXJhIHVtICppbnNpZ2h0KiBpbnRlcmVzc2FudGUuCiAgIAogICBBcXVpLCBkZXNjYXJ0YW1vcyBhcyBjaWRhZGVzIGNvbSBtYWlzIGRlICQzJCBtaWxow7VlcyBkZSBoYWJpdGFudGVzLgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcigKICAgICAgICBhZ2VuY2lhc19wcml2ID4gMCwKICAgICAgICBhZ2VuY2lhc19wdWJsID4gMCwKICAgICAgICBwb3BfcmVzaWQgPCAzZTYKICAgICAgKSAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gcG9wX3Jlc2lkLCAKICAgICAgICAgICAgeSA9IGFnZW5jaWFzX3B1YmwsIAogICAgICAgICAgICBjb2xvciA9ICdwdWJsJwogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjQKICAgICAgICApICsKICAgICAgICBnZW9tX3Ntb290aCgKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IHBvcF9yZXNpZCwgCiAgICAgICAgICAgIHkgPSBhZ2VuY2lhc19wdWJsLCAKICAgICAgICAgICAgY29sb3IgPSAncHVibCcKICAgICAgICAgICksCiAgICAgICAgICBtZXRob2QgPSAnbG0nLAogICAgICAgICAgc2UgPSBGQUxTRQogICAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBwb3BfcmVzaWQsIAogICAgICAgICAgICB5ID0gYWdlbmNpYXNfcHJpdiwgCiAgICAgICAgICAgIGNvbG9yID0gJ3ByaXYnCiAgICAgICAgICApLAogICAgICAgICAgYWxwaGEgPSAuMgogICAgICAgICkgKwogICAgICAgIGdlb21fc21vb3RoKAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gcG9wX3Jlc2lkLCAKICAgICAgICAgICAgeSA9IGFnZW5jaWFzX3ByaXYsIAogICAgICAgICAgICBjb2xvciA9ICdwcml2JwogICAgICAgICAgKSwKICAgICAgICAgIG1ldGhvZCA9ICdsbScsCiAgICAgICAgICBzZSA9IEZBTFNFCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfY29sb3JfZGlzY3JldGUoCiAgICAgICAgICB0eXBlID0gYygnYmx1ZScsICdyZWQnKQogICAgICAgICkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAzZTYsIC41ZTYpLAogICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoCiAgICAgICAgICAgIHNjYWxlID0gMWUtNiwKICAgICAgICAgICAgc3VmZml4ID0gJ00nCiAgICAgICAgICApCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ0Fnw6puY2lhcyBiYW5jw6FyaWFzIHBvciBwb3B1bGHDp8OjbycsCiAgICAgICAgICB4ID0gJ3BvcHVsYcOnw6NvJywKICAgICAgICAgIHkgPSAnYWfDqm5jaWFzJywKICAgICAgICAgIGNvbG9yID0gTlVMTAogICAgICAgICkKICAgIGBgYAogICAKICAgQXMgcmV0YXMgbW9zdHJhbSBjb21vIG8gbsO6bWVybyBkZSBhZ8OqbmNpYXMgYXVtZW50YSDDoCBtZWRpZGEgcXVlIGEgcG9wdWxhw6fDo28gYXVtZW50YS4KICAgCiAgIFBhcmEgb3MgYmFuY29zIHByaXZhZG9zLCBvIGF1bWVudG8gw6kgbWFpcyByw6FwaWRvLgogICAKICAgRW0gb3V0cmFzIHBhbGF2cmFzOiBbcGFyYSB1bWEgbWVzbWEgcG9wdWxhw6fDo29dey5obH0sIGV4aXN0ZW0sIGVtIG3DqWRpYSwgW21haXMgYWfDqm5jaWFzIHByaXZhZGFzIGRvIHF1ZSBww7pibGljYXNdey5obH0sIGUsIHF1YW50byBtYWlvciBhIHBvcHVsYcOnw6NvLCBtYWlvciBhIGRpZmVyZW7Dp2EuCgogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgQ29tZW50w6FyaW9zIGluY2x1w61kb3MgbmFzIHJlc3Bvc3RhcyBhY2ltYS4KICAgCiAgIDo6OgoKCiMjIEFnw6puY2lhcyBiYW5jw6FyaWFzIChwcml2YWRhcykKCjEuIEZhw6dhIHVtIGhpc3RvZ3JhbWEgZGEgcXVhbnRpZGFkZSBkZSBhZ8OqbmNpYXMgYmFuY8OhcmlhcyBwcml2YWRhcy4gVXNlIG8gbsO6bWVybyBkZSBjbGFzc2VzIHF1ZSB2b2PDqiBhY2hhciBtYWlzIGFkZXF1YWRvLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBFeGlzdGVtIG11aXRhcyBjaWRhZGVzIGNvbSB6ZXJvIGFnw6puY2lhcyBwcml2YWRhczoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBjb3VudChhZ2VuY2lhc19wcml2KQogICAgYGBgCiAgIAogICBWYW1vcyBpZ25vcsOhLWxhczoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIoYWdlbmNpYXNfcHJpdiA+IDApICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gYWdlbmNpYXNfcHJpdikpCiAgICBgYGAKICAgCiAgIEFpbmRhIGFzc2ltLCBhIGdyYW5kZSBxdWFudGlkYWRlIGRlIGNpZGFkZXMgY29tIHPDsyB1bWEgYWfDqm5jaWEgZmF6IG8gaGlzdG9ncmFtYSBmaWNhciBuw6NvLWludGVyZXNzYW50ZS4gCiAgIAogICBWYW1vcyBmYXplciB1bSBoaXN0b2dyYW1hIGRvIFtsb2dhcml0bW9dey5obH0gZG8gbsO6bWVybyBkZSBhZ8OqbmNpYXMuIAogICAKICAgIGBgYHtyIHJlZi5sYWJlbD0naGlzdG9ncmFtYS1wcml2YWRhcyd9CiAgICBgYGAKCiAgIFBlcmNlYmEgY29tbyBvcyByw7N0dWxvcyBkbyBlaXhvICR4JCBzw6NvIGFzIHF1YW50aWRhZGVzIGRlIGFnw6puY2lhcywgbsOjbyBvcyBsb2dhcml0bW9zLgogICAKICAgOjo6CgoxLiBDb21wYXJlIGNvbSBhIGRpc3RyaWJ1acOnw6NvIGRlIGFnw6puY2lhcyBww7pibGljYXMuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFtWZWphIGEgZGlzdHJpYnVpw6fDo28gZGUgYWfDqm5jaWFzIHDDumJsaWNhcyBhcXVpLl0oI2FnJUMzJUFBbmNpYXMtYmFuYyVDMyVBMXJpYXMtcCVDMyVCQWJsaWNhcykKCiAgICBgYGB7cn0KICAgIHByaXZhZGFzICsgcHVibGljYXMKICAgIGBgYAogICAKICAgVmFtb3MgdmVyIGFsZ3VtYSB0YWJlbGFzLgogICAKICAgVG90YWlzIGRlIGFnw6puY2lhczoKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBzdW1tYXJpemUoCiAgICAgICAgcHJpdmFkYXMgPSBzdW0oYWdlbmNpYXNfcHJpdiksCiAgICAgICAgcMO6YmxpY2FzID0gc3VtKGFnZW5jaWFzX3B1YmwpCiAgICAgICkKICAgIGBgYAogICAKICAgW05vIHRvdGFsLCBleGlzdGVtIG1haXMgYWfDqm5jaWFzIGRlIGJhbmNvcyBwcml2YWRvcyFdey5obH0KICAgCiAgIFF1YW50aWRhZGUgZGUgY2lkYWRlcyBhdGVuZGlkYXM6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgc3VtbWFyaXplKAogICAgICAgIHByaXZhZGFzID0gc3VtKGFnZW5jaWFzX3ByaXYgPiAwKSwKICAgICAgICBww7pibGljYXMgPSBzdW0oYWdlbmNpYXNfcHVibCA+IDApCiAgICAgICkKICAgIGBgYAogICAKICAgW0V4aXN0ZW0gbWFpcyBjaWRhZGVzIGNvbSBwZWxvIG1lbm9zIHVtYSBhZ8OqbmNpYSBkZSBiYW5jbyBww7pibGljbyBkbyBxdWUgY2lkYWRlcyBjb20gcGVsbyBtZW5vcyB1bWEgYWfDqm5jaWEgZGUgYmFuY28gcHJpdmFkby5dey5obH0KICAgCiAgIE91LCBjb21wYXJhbmRvIGEgcXVhbnRpZGFkZSBkZSBjaWRhZGVzIFtzZW1dey5obH0gYWfDqm5jaWFzOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIHN1bW1hcml6ZSgKICAgICAgICBzZW1fcHJpdmFkYXMgPSBzdW0oYWdlbmNpYXNfcHJpdiA9PSAwKSwKICAgICAgICBzZW1fcMO6YmxpY2FzID0gc3VtKGFnZW5jaWFzX3B1YmwgPT0gMCksCiAgICAgICAgc2VtX3F1YWxxdWVyID0gc3VtKGFnZW5jaWFzX3B1YmwgPT0gMCAmIGFnZW5jaWFzX3ByaXYgPT0gMCkKICAgICAgKQogICAgYGBgCiAgIAogICBMZW1icmUtc2UgZGUgcXVlIG8gdG90YWwgZGUgY2lkYWRlcyDDqQogICAKICAgIGBgYHtyfQogICAgbnJvdyhjaWRhZGVzKQogICAgYGBgCiAgIAogICBPdSBzZWphLCBbY2VyY2EgZGUgJGByICgxMDAgKiAyMjMzL25yb3coY2lkYWRlcykpICU+JSBmbSgwKWBcJSQgZGUgY2lkYWRlcyBuw6NvIHTDqm0gYWfDqm5jaWFzIGJhbmPDoXJpYXMsIG5lbSBwcml2YWRhcywgbmVtIHDDumJsaWNhcyFdey5obH0KICAgCiAgIEFsacOhcywgZXhpc3RlIGFsZ3VtYSBjaWRhZGUgcXVlIHRlbmhhIGFnw6puY2lhIHByaXZhZGEsIG1hcyBuw6NvIHDDumJsaWNhPyBRdWFudGFzPwogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcigKICAgICAgICBhZ2VuY2lhc19wcml2ID4gMCAmIGFnZW5jaWFzX3B1YmwgPT0gMAogICAgICApICU+JSAKICAgICAgc2VsZWN0KGNpZGFkZSwgZXN0YWRvLCBzdGFydHNfd2l0aCgnYWdlbmNpYXMnKSkKICAgIGBgYAogICAKICAgRSBleGlzdGUgYWxndW1hIGNpZGFkZSBxdWUgdGVuaGEgYWfDqm5jaWEgcMO6YmxpY2EsIG1hcyBuw6NvIHByaXZhZGE/IFF1YW50YXM/CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKAogICAgICAgIGFnZW5jaWFzX3ByaXYgPT0gMCAmIGFnZW5jaWFzX3B1YmwgPiAwCiAgICAgICkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCBlc3RhZG8sIHN0YXJ0c193aXRoKCdhZ2VuY2lhcycpKQogICAgYGBgCgogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCgojIyBBZ8OqbmNpYXMgYmFuY8OhcmlhcyAocHJpdmFkYXMpICpwZXIgY2FwaXRhKgoKMS4gRmHDp2EgdW0gaGlzdG9ncmFtYSBkYSByYXrDo28gWyhuw7ptZXJvIGRlIGFnw6puY2lhcyBiYW5jw6FyaWFzIHByaXZhZGFzKSAvIChwb3B1bGHDp8Ojbyldey5obH0uIFVzZSBvIG7Dum1lcm8gZGUgY2xhc3NlcyBxdWUgdm9jw6ogYWNoYXIgbWFpcyBhZGVxdWFkby4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgRXhpc3RlbSBtdWl0YXMgY2lkYWRlcyBjb20gemVybyBhZ8OqbmNpYXMgcHJpdmFkYXM6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgY291bnQoYWdlbmNpYXNfcHJpdikKICAgIGBgYAogICAKICAgVmFtb3MgaWdub3LDoS1sYXMuCiAgIAogICAgYGBge3IgcmVmLmxhYmVsPSdwcml2YWRhcy1wZXItY2FwaXRhJ30KICAgIGBgYAogICAKICAgOjo6CgoxLiBDb21wYXJlIGNvbSBhIGRpc3RyaWJ1acOnw6NvIGRlIGFnw6puY2lhcyBww7pibGljYXMuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIHByaXZhZGFzcGMgKyBwdWJsaWNhc3BjCiAgICBgYGAKCiAgIFBhcmEgcXVhc2UgdG9kb3Mgb3MgdmFsb3JlcyBkZSBhZ8OqbmNpYXMgKnBlciBjYXBpdGEqLCBleGlzdGVtIG1haXMgY2lkYWRlcyBjb20gYWfDqm5jaWFzIHDDumJsaWNhcyBkbyBxdWUgY2lkYWRlcyBjb20gYWfDqm5jaWFzIHByaXZhZGFzLiAKICAgCiAgIElzdG8gw6kgY29uc2VxdcOqbmNpYSBkZSBxdWUsIG5vIHRvdGFsLCBbZXhpc3RlbSBtYWlzIGNpZGFkZXMgYXRlbmRpZGFzIHBvciBiYW5jb3MgcMO6YmxpY29zIGRvIHF1ZSBwb3IgYmFuY29zIHByaXZhZG9zXSgjYWclQzMlQUFuY2lhcy1iYW5jJUMzJUExcmlhcy1wJUMzJUJBYmxpY2FzKS4KICAgCiAgIE1hcyBldSBkZXZpYSB0ZXIgcGVkaWRvIHVtICpzY2F0dGVycGxvdCogZGUgYWfDqm5jaWFzIHBvciBwb3B1bGHDp8OjbyBwYXJhIHVtICppbnNpZ2h0KiBpbnRlcmVzc2FudGUuCiAgIAogICBBcXVpLCBkZXNjYXJ0YW1vcyBhcyBjaWRhZGVzIGNvbSBtYWlzIGRlICQzJCBtaWxow7VlcyBkZSBoYWJpdGFudGVzLgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcigKICAgICAgICBhZ2VuY2lhc19wcml2ID4gMCwKICAgICAgICBhZ2VuY2lhc19wdWJsID4gMCwKICAgICAgICBwb3BfcmVzaWQgPCAzZTYKICAgICAgKSAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3BvaW50KAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gcG9wX3Jlc2lkLCAKICAgICAgICAgICAgeSA9IGFnZW5jaWFzX3B1YmwsIAogICAgICAgICAgICBjb2xvciA9ICdwdWJsJwogICAgICAgICAgKSwKICAgICAgICAgIGFscGhhID0gLjQKICAgICAgICApICsKICAgICAgICBnZW9tX3Ntb290aCgKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IHBvcF9yZXNpZCwgCiAgICAgICAgICAgIHkgPSBhZ2VuY2lhc19wdWJsLCAKICAgICAgICAgICAgY29sb3IgPSAncHVibCcKICAgICAgICAgICksCiAgICAgICAgICBtZXRob2QgPSAnbG0nLAogICAgICAgICAgc2UgPSBGQUxTRQogICAgICAgICkgKwogICAgICAgIGdlb21fcG9pbnQoCiAgICAgICAgICBhZXMoCiAgICAgICAgICAgIHggPSBwb3BfcmVzaWQsIAogICAgICAgICAgICB5ID0gYWdlbmNpYXNfcHJpdiwgCiAgICAgICAgICAgIGNvbG9yID0gJ3ByaXYnCiAgICAgICAgICApLAogICAgICAgICAgYWxwaGEgPSAuMgogICAgICAgICkgKwogICAgICAgIGdlb21fc21vb3RoKAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gcG9wX3Jlc2lkLCAKICAgICAgICAgICAgeSA9IGFnZW5jaWFzX3ByaXYsIAogICAgICAgICAgICBjb2xvciA9ICdwcml2JwogICAgICAgICAgKSwKICAgICAgICAgIG1ldGhvZCA9ICdsbScsCiAgICAgICAgICBzZSA9IEZBTFNFCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfY29sb3JfZGlzY3JldGUoCiAgICAgICAgICB0eXBlID0gYygnYmx1ZScsICdyZWQnKQogICAgICAgICkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAzZTYsIC41ZTYpLAogICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpsYWJlbF9udW1iZXIoCiAgICAgICAgICAgIHNjYWxlID0gMWUtNiwKICAgICAgICAgICAgc3VmZml4ID0gJ00nCiAgICAgICAgICApCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ0Fnw6puY2lhcyBiYW5jw6FyaWFzIHBvciBwb3B1bGHDp8OjbycsCiAgICAgICAgICB4ID0gJ3BvcHVsYcOnw6NvJywKICAgICAgICAgIHkgPSAnYWfDqm5jaWFzJywKICAgICAgICAgIGNvbG9yID0gTlVMTAogICAgICAgICkKICAgIGBgYAogICAKICAgQXMgcmV0YXMgbW9zdHJhbSBjb21vIG8gbsO6bWVybyBkZSBhZ8OqbmNpYXMgYXVtZW50YSDDoCBtZWRpZGEgcXVlIGEgcG9wdWxhw6fDo28gYXVtZW50YS4KICAgCiAgIFBhcmEgb3MgYmFuY29zIHByaXZhZG9zLCBvIGF1bWVudG8gw6kgbWFpcyByw6FwaWRvLgogICAKICAgRW0gb3V0cmFzIHBhbGF2cmFzOiBbcGFyYSB1bWEgbWVzbWEgcG9wdWxhw6fDo29dey5obH0sIGV4aXN0ZW0sIGVtIG3DqWRpYSwgW21haXMgYWfDqm5jaWFzIHByaXZhZGFzIGRvIHF1ZSBww7pibGljYXNdey5obH0sIGUsIHF1YW50byBtYWlvciBhIHBvcHVsYcOnw6NvLCBtYWlvciBhIGRpZmVyZW7Dp2EuCgogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgQ29tZW50w6FyaW9zIGluY2x1w61kb3MgbmFzIHJlc3Bvc3RhcyBhY2ltYS4KICAgCiAgIDo6OgoKCiMjIMOBcmVhcwoKMS4gRmHDp2EgdW0gaGlzdG9ncmFtYSBkYXMgw6FyZWFzIGRhcyBjaWRhZGVzLiBVc2UgbyBuw7ptZXJvIGRlIGNsYXNzZXMgcXVlIHZvY8OqIGFjaGFyIG1haXMgYWRlcXVhZG8uCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFByaW1laXJhIHRlbnRhdGl2YToKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9oaXN0b2dyYW0oCiAgICAgICAgICBhZXMoYXJlYSksCiAgICAgICAgICBiaW5zID0gMTAwCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHkgPSBOVUxMLAogICAgICAgICAgeCA9ICfDgXJlYSAoa23CsiknCiAgICAgICAgKQogICAgYGBgCiAgIAogICBFeGlzdGVtIG11aXRhcyBjaWRhZGVzIGNvbSDDoXJlYSBwZXF1ZW5hLCBlIHBvdWNvcyBjb20gw6FyZWEgZ3JhbmRlLiBVbWEgYm9hIGNoYW5jZSBkZSB1c2FyIHVtYSBlc2NhbGEgbG9nYXLDrXRtaWNhOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2hpc3RvZ3JhbSgKICAgICAgICAgIGFlcyhhcmVhKSwKICAgICAgICAgIGJpbnMgPSA1MAogICAgICAgICkgKwogICAgICAgIHNjYWxlX3hfbG9nMTAoKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ8OBcmVhcyAoZXNjYWxhIGxvZ2Fyw610bWljYSknLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICB4ID0gJ8OBcmVhIChrbcKyKScKICAgICAgICApCiAgICBgYGAgICAKICAgCiAgIFBvZGVtb3MgZXhhbWluYXIgYXBlbmFzIGFzIGNpZGFkZXMgY29tIMOhcmVhIGVudHJlICQwJCBlICQxMDAwJCBrbcKyIChjb20gZXNjYWxhIGxpbmVhcik6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZmlsdGVyKGJldHdlZW4oYXJlYSwgMCwgMTAwMCkpICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKAogICAgICAgICAgYWVzKGFyZWEpLAogICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDEwMDAsIDEwMCkKICAgICAgICApICsKICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMTAwMCwgMTAwKQogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICfDgXJlYSAoYXTDqSAxMDAwa23CsiknLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICB4ID0gJ8OBcmVhIChrbcKyKScKICAgICAgICApCiAgICBgYGAgICAgICAKCiAgIDo6OgoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBBbGd1bnMgY29tZW50w6FyaW9zIGluY2x1w61kb3MgbmFzIHJlc3Bvc3RhcyBhY2ltYS4KICAgCiAgIEEgY2xhc3NlIG1vZGFsIMOpIGVudHJlICQxMDAkIGUgJDIwMCQga23Csi4KICAgCiAgIDo6OgoKCiMjIMOBcmVhcyAoY29tIGZhY2V0YXMpCgoxLiBGYcOnYSBoaXN0b2dyYW1hcyBkYXMgw6FyZWFzIGRhcyBjaWRhZGVzLCBbZmFjZXRhZG9zIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhXXsuaGx9LiBVc2UgbyBuw7ptZXJvIGRlIGNsYXNzZXMgcXVlIHZvY8OqIGFjaGFyIG1haXMgYWRlcXVhZG8uIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgUG9wdWxhw6fDtWVzCgoxLiBGYcOnYSB1bSBoaXN0b2dyYW1hIGRhcyBwb3B1bGHDp8O1ZXMgZGFzIGNpZGFkZXMuIFVzZSBvIG7Dum1lcm8gZGUgY2xhc3NlcyBxdWUgdm9jw6ogYWNoYXIgbWFpcyBhZGVxdWFkby4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgUHJpbWVpcmEgdGVudGF0aXZhOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2hpc3RvZ3JhbSgKICAgICAgICAgIGFlcyh4ID0gcG9wX3Jlc2lkKQogICAgICAgICkKICAgIGBgYAogICAKICAgVXNhbmRvIGVzY2FsYSBsb2dhcsOtdG1pY2E6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKAogICAgICAgICAgYWVzKHggPSBwb3BfcmVzaWQpCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfeF9sb2cxMCgKICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdCgKICAgICAgICAgICAgc2NhbGUgPSAxZS0zLAogICAgICAgICAgICBzdWZmaXggPSAnaycKICAgICAgICAgICkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUG9wdWxhw6fDtWVzJywKICAgICAgICAgIHkgPSBOVUxMLAogICAgICAgICAgeCA9ICdwb3B1bGHDp8OjbycKICAgICAgICApCiAgICBgYGAKCiAgIFZhbW9zIGxpbWl0YXIgYSBjaWRhZGVzIGRlIG5vIG3DoXhpbW8gJDEwMCQgbWlsIGhhYml0YW50ZXMsIGNvbSBlc2NhbGEgbGluZWFyOgoKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihwb3BfcmVzaWQgPCAxZTUpICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKAogICAgICAgICAgYWVzKHggPSBwb3BfcmVzaWQpLAogICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDFlNSwgMTAwMDApCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDFlNSwgMTAwMDApLAogICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KAogICAgICAgICAgICBzY2FsZSA9IDFlLTMsCiAgICAgICAgICAgIHN1ZmZpeCA9ICdrJwogICAgICAgICAgKQogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICdQb3B1bGHDp8O1ZXMgKGF0w6kgMTAwIG1pbCknLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICB4ID0gJ3BvcHVsYcOnw6NvJwogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIEjDoSBtdWl0byBtYWlzIGNpZGFkZXMgY29tIHBvdWNvcyBoYWJpdGFudGVzLgogICAKICAgQSBjbGFzc2UgbW9kYWwgw6kgYSBkZSBjaWRhZGVzIGNvbSBhdMOpICQxMCQgbWlsIGhhYml0YW50ZXMuCiAgIAogICBBIHBvcHVsYcOnw6NvIG1lZGlhbmEgw6kKICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMkcG9wX3Jlc2lkICU+JSBtZWRpYW4oKQogICAgYGBgCiAgIAogICBvIHF1ZSBkaXogcXVlIGFwcm94aW1hZGFtZW50ZSBtZXRhZGUgZGFzIGNpZGFkZXMgdGVtIG1lbm9zIGRlICQxMSQgbWlsIGhhYml0YW50ZXMuCiAgIAogICBRdWFsIGEgcG9wdWxhw6fDo28gdG90YWwgZGVzdGFzIGNpZGFkZXMgcGVxdWVuYXM/CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIHRhbWFuaG8gPSBjYXNlX3doZW4oCiAgICAgICAgICBwb3BfcmVzaWQgPCAxMTAwMCB+ICdQZXF1ZW5hcycsCiAgICAgICAgICBUUlVFIH4gJ0dyYW5kZXMnCiAgICAgICAgKQogICAgICApICU+JSAKICAgICAgZ3JvdXBfYnkodGFtYW5obykgJT4lIAogICAgICBzdW1tYXJpemUocG9wdWxhY2FvID0gc3VtKHBvcF9yZXNpZCkpCiAgICBgYGAKICAgCiAgIEVtYm9yYSBtZXRhZGUgZGFzIGNpZGFkZXMgdGVuaGEgJDExJCBtaWwgaGFiaXRhbnRlcyBvdSBtZW5vcywgc3VhIHBvcHVsYcOnw6NvIHRvdGFsIMOpIFskMTAkIHZlemVzIG1lbm9yXXsuaGx9IHF1ZSBhIHBvcHVsYcOnw6NvIHRvdGFsIGRhIG91dHJhIG1ldGFkZS4KICAgCiAgIDo6OgoKCiMjIFBvcHVsYcOnw7VlcyAoY29tIGZhY2V0YXMpCgoxLiBGYcOnYSBoaXN0b2dyYW1hcyBkYXMgcG9wdWxhw6fDtWVzIGRhcyBjaWRhZGVzLCBbZmFjZXRhZG9zIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhXXsuaGx9LiBVc2UgbyBuw7ptZXJvIGRlIGNsYXNzZXMgcXVlIHZvY8OqIGFjaGFyIG1haXMgYWRlcXVhZG8uIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgUElCCgoxLiBGYcOnYSB1bSBoaXN0b2dyYW1hIGRvIHZhbG9yIGRvIFBJQi4gVXNlIG8gbsO6bWVybyBkZSBjbGFzc2VzIHF1ZSB2b2PDqiBhY2hhciBtYWlzIGFkZXF1YWRvLgoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKCiMjIFBJQiAqcGVyIGNhcGl0YSoKCjEuIEZhw6dhIHVtIGhpc3RvZ3JhbWEgZG8gdmFsb3IgZG8gUElCICpwZXIgY2FwaXRhKi4gVXNlIG8gbsO6bWVybyBkZSBjbGFzc2VzIHF1ZSB2b2PDqiBhY2hhciBtYWlzIGFkZXF1YWRvLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21faGlzdG9ncmFtKAogICAgICAgICAgYWVzKHggPSBwaWJfY2FwaXRhKQogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB5ID0gTlVMTCwKICAgICAgICAgIHggPSAnUElCIHBlciBjYXBpdGEgKFIkKScKICAgICAgICApICsKICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoCiAgICAgICAgICAgIHNjYWxlID0gMWUtMywKICAgICAgICAgICAgc3VmZml4ID0gJ2snCiAgICAgICAgICApCiAgICAgICAgKQogICAgYGBgCiAgIAogICBFbSBlc2NhbGEgbG9nYXLDrXRtaWNhOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2hpc3RvZ3JhbSgKICAgICAgICAgIGFlcyh4ID0gcGliX2NhcGl0YSkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUElCIHBlciBjYXBpdGEgKGVzY2FsYSBsb2dhcsOtdG1pY2EpJywKICAgICAgICAgIHkgPSBOVUxMLAogICAgICAgICAgeCA9ICdQSUIgcGVyIGNhcGl0YSAoUiQpJwogICAgICAgICkgKwogICAgICAgIHNjYWxlX3hfbG9nMTAoCiAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoCiAgICAgICAgICAgIHNjYWxlID0gMWUtMywKICAgICAgICAgICAgc3VmZml4ID0gJ2snCiAgICAgICAgICApCiAgICAgICAgKQogICAgYGBgCgogICBSZXN0cmluZ2luZG8gYSB1bSB2YWxvciBtw6F4aW1vOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcihwaWJfY2FwaXRhIDwgMWU1KSAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2hpc3RvZ3JhbSgKICAgICAgICAgIGFlcyh4ID0gcGliX2NhcGl0YSksCiAgICAgICAgICBicmVha3MgPSBzZXEoMCwgMWU1LCAxZTQpCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1BJQiBwZXIgY2FwaXRhIChhdMOpIDEwMCBtaWwpJywKICAgICAgICAgIHkgPSBOVUxMLAogICAgICAgICAgeCA9ICdQSUIgcGVyIGNhcGl0YSAoUiQpJwogICAgICAgICkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAxZTUsIDFlNCksCiAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoCiAgICAgICAgICAgIHNjYWxlID0gMWUtMywKICAgICAgICAgICAgc3VmZml4ID0gJ2snCiAgICAgICAgICApCiAgICAgICAgKQogICAgYGBgCiAgIAogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQoKICAgw4kgdW1hIGRpc3RyaWJ1acOnw6NvIGFzc2ltw6l0cmljYSwgY29tIHVtYSBsb25nYSBjYXVkYSDDoCBkaXJlaXRhLiAgIAoKICAgQSBjbGFzc2UgbW9kYWwgw6kgZW50cmUgJDEwJCBlICQyMCQgbWlsIHJlYWlzLgogICAKICAgOjo6CiAgIAoKIyMgVGVsZWZvbmVzIGZpeG9zICpwZXIgY2FwaXRhKiAoY29tIGZhY2V0YXMpCgoxLiBGYcOnYSBoaXN0b2dyYW1hcyBkYXMgcXVhbnRpZGFkZXMgZGUgdGVsZWZvbmVzIGZpeG9zICpwZXIgY2FwaXRhKiwgW2ZhY2V0YWRvcyBwb3IgcmVnacOjbyBnZW9ncsOhZmljYV17LmhsfS4gVXNlIG8gbsO6bWVybyBkZSBjbGFzc2VzIHF1ZSB2b2PDqiBhY2hhciBtYWlzIGFkZXF1YWRvLiBWb2PDqiB2YWkgcHJlY2lzYXIgZGEgcmVzcG9zdGEgW2Rlc3RhIHF1ZXN0w6NvXSgjcmVnaW9lcy1nZW8pLgoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKCiMjIEFzc2luYXR1cmFzIGRlIFRWICpwZXIgY2FwaXRhKiAoY29tIGZhY2V0YXMpCgoxLiBGYcOnYSBoaXN0b2dyYW1hcyBkYXMgcXVhbnRpZGFkZXMgZGUgYXNzaW5hdHVyYXMgZGUgVFYgcG9yIGFzc2luYXR1cmEgKnBlciBjYXBpdGEqLCBbZmFjZXRhZG9zIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhXXsuaGx9LiBVc2UgbyBuw7ptZXJvIGRlIGNsYXNzZXMgcXVlIHZvY8OqIGFjaGFyIG1haXMgYWRlcXVhZG8uIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgUElCIGUgYXRpdmlkYWRlIHByaW5jaXBhbAoKMS4gRmHDp2EgKmJveHBsb3RzKiBsYWRvIGEgbGFkbyBbKG5vIG1lc21vIGdyw6FmaWNvLCBzZW0gZmFjZXRhcildey5obH0gZG8gUElCLCBjb20gdW0gKmJveHBsb3QqIHBhcmEgY2FkYSBhdGl2aWRhZGUgcHJpbmNpcGFsLiBGYcOnYSBjb20gcXVlIG9zICpib3hwbG90cyogc2VqYW0gaG9yaXpvbnRhaXMsIHBhcmEgZmFjaWxpdGFyIGEgbGVpdHVyYSBkb3Mgbm9tZXMgZGFzIGF0aXZpZGFkZXMuCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgUElCICpwZXIgY2FwaXRhKiBlIGF0aXZpZGFkZSBwcmluY2lwYWwKCjEuIEZhw6dhICpib3hwbG90cyogbGFkbyBhIGxhZG8gWyhubyBtZXNtbyBncsOhZmljbywgc2VtIGZhY2V0YXIpXXsuaGx9IGRvIFBJQiAqcGVyIGNhcGl0YSosIGNvbSB1bSAqYm94cGxvdCogcGFyYSBjYWRhIGF0aXZpZGFkZSBwcmluY2lwYWwuIEZhw6dhIGNvbSBxdWUgb3MgKmJveHBsb3RzKiBzZWphbSBob3Jpem9udGFpcywgcGFyYSBmYWNpbGl0YXIgYSBsZWl0dXJhIGRvcyBub21lcyBkYXMgYXRpdmlkYWRlcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgUHJpbWVpcmEgdGVudGF0aXZhOgogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2JveHBsb3QoCiAgICAgICAgICBhZXMoeCA9IGF0aXZpZGFkZV9wcmluY2lwYWwsIHkgPSBwaWJfY2FwaXRhKQogICAgICAgICkgKwogICAgICBjb29yZF9mbGlwKCkKICAgIGBgYAogICAKICAgVmFtb3MgYWJyZXZpYXIgb3Mgbm9tZXMgZGFzIGF0aXZpZGFkZXM6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIGF0aXZpZGFkZV9wcmluY2lwYWwgPSB3b3JkKGF0aXZpZGFkZV9wcmluY2lwYWwsIGVuZCA9IDUpCiAgICAgICkgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgICAgYWVzKHggPSBhdGl2aWRhZGVfcHJpbmNpcGFsLCB5ID0gcGliX2NhcGl0YSkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUElCIHBlciBjYXBpdGEgcG9yIGF0aXZpZGFkZSBwcmluY2lwYWwnLAogICAgICAgICAgeSA9ICdQSUIgcGVyIGNhcGl0YScsCiAgICAgICAgICB4ID0gTlVMTAogICAgICAgICkgKwogICAgICAgIGNvb3JkX2ZsaXAoKQogICAgYGBgCgogICBQb2RlbW9zIHVzYXIgdW1hIGVzY2FsYSBsb2dhcsOtdG1pY2E6CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIGF0aXZpZGFkZV9wcmluY2lwYWwgPSB3b3JkKGF0aXZpZGFkZV9wcmluY2lwYWwsIGVuZCA9IDUpCiAgICAgICkgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9ib3hwbG90KAogICAgICAgICAgYWVzKHggPSBhdGl2aWRhZGVfcHJpbmNpcGFsLCB5ID0gcGliX2NhcGl0YSkKICAgICAgICApICsKICAgICAgICBzY2FsZV95X2xvZzEwKCkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICdQSUIgcGVyIGNhcGl0YSBwb3IgYXRpdmlkYWRlIHByaW5jaXBhbCcsCiAgICAgICAgICBzdWJ0aXRsZSA9ICcoZXNjYWxhIGxvZ2Fyw610bWljYSknLAogICAgICAgICAgeSA9ICdQSUIgcGVyIGNhcGl0YScsCiAgICAgICAgICB4ID0gTlVMTAogICAgICAgICkgKwogICAgICAgIGNvb3JkX2ZsaXAoKQogICAgYGBgCiAgIAogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgQXMgYXRpdmlkYWRlcyBhc3NvY2lhZGFzIGFvIFttYWlvcl17LmhsfSBQSUIgKnBlciBjYXBpdGEqIFttZWRpYW5vXXsuaGx9IHPDo28gKDEpIGVsZXRyaWNpZGFkZSwgZ8Ohcywgw6FndWEgZSBlc2dvdG8gZSAoMikgY29tw6lyY2lvIGUgcmVwYXJhw6fDo28gZGUgdmXDrWN1bG9zLgogICAKICAgQXMgYXRpdmlkYWRlcyBhc3NvY2lhZGFzIGFvIFttZW5vcl17LmhsfSBQSUIgKnBlciBjYXBpdGEqIFttZWRpYW5vXXsuaGx9IHPDo28gYWRtaW5pc3RyYcOnw6NvLCBkZWZlc2EsIGVkdWNhw6fDo28gZSBzYcO6ZGUuCiAgIAogICA6OjoKCgojIyBIb3TDqWlzIGUgY2F0ZWdvcmlhIGRlIHR1cmlzbW8KCjEuIEZhw6dhICpib3hwbG90cyogbGFkbyBhIGxhZG8gWyhubyBtZXNtbyBncsOhZmljbywgc2VtIGZhY2V0YXIpXXsuaGx9IGRhIHF1YW50aWRhZGUgZGUgaG90w6lpcywgY29tIHVtICpib3hwbG90KiBwYXJhIGNhZGEgY2F0ZWdvcmlhIGRlIHR1cmlzbW8uIAoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fYm94cGxvdCgKICAgICAgICAgIGFlcyh4ID0gZmN0X3JldihjYXRlZ29yaWFfdHVyaXNtbyksIHkgPSBob3RlaXMpCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1F1YW50aWRhZGUgZGUgaG90w6lpcyBwb3IgY2F0ZWdvcmlhIGRlIHR1cmlzbW8nLAogICAgICAgICAgeCA9ICdjYXRlZ29yaWEgZGUgdHVyaXNtbycKICAgICAgICApCiAgICBgYGAKCiAgIDo6OgogICAKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBDb21vIGVyYSBkZSBzZSBlc3BlcmFyLCBhIHF1YW50aWRhZGUgZGUgaG90w6lpcyDDqSBtdWl0byBtYWlvciBlbSBjaWRhZGVzIGRhIGNhdGVnb3JpYSBBLgogICAKICAgOjo6CgogICAKIyMgUG9wdWxhw6fDtWVzIHBvciByZWdpw6NvCgoxLiBGYcOnYSAqYm94cGxvdHMqIGxhZG8gYSBsYWRvIFsobm8gbWVzbW8gZ3LDoWZpY28sIHNlbSBmYWNldGFyKV17LmhsfSBkYXMgcG9wdWxhw6fDtWVzLCBjb20gdW0gKmJveHBsb3QqIHBhcmEgY2FkYSByZWdpw6NvIGdlb2dyw6FmaWNhLiBWb2PDqiB2YWkgcHJlY2lzYXIgZGEgcmVzcG9zdGEgW2Rlc3RhIHF1ZXN0w6NvXSgjcmVnaW9lcy1nZW8pLgoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKCiMjIERlbnNpZGFkZSBkZW1vZ3LDoWZpY2EgcG9yIHJlZ2nDo28KCjEuIEZhw6dhICpib3hwbG90cyogbGFkbyBhIGxhZG8gWyhubyBtZXNtbyBncsOhZmljbywgc2VtIGZhY2V0YXIpXXsuaGx9IGRhcyBkZW5zaWRhZGVzIGRlbW9ncsOhZmljYXMsIGNvbSB1bSAqYm94cGxvdCogcGFyYSBjYWRhIHJlZ2nDo28gZ2VvZ3LDoWZpY2EuIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgQ2Fycm9zICpwZXIgY2FwaXRhKiBwb3IgdGlwbyBkZSBjaWRhZGUKCjEuIEZhw6dhICpib3hwbG90cyogbGFkbyBhIGxhZG8gWyhubyBtZXNtbyBncsOhZmljbywgc2VtIGZhY2V0YXIpXXsuaGx9IGRhIHF1YW50aWRhZGUgZGUgY2Fycm9zICpwZXIgY2FwaXRhKiwgY29tIHVtICpib3hwbG90KiBwYXJhIGNhZGEgdGlwbyBkZSBjaWRhZGUuIAoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKCiMjIE1vdG9zICpwZXIgY2FwaXRhKiBwb3IgdGlwbyBkZSBjaWRhZGUKCjEuIEZhw6dhICpib3hwbG90cyogbGFkbyBhIGxhZG8gWyhubyBtZXNtbyBncsOhZmljbywgc2VtIGZhY2V0YXIpXXsuaGx9IGRhIHF1YW50aWRhZGUgZGUgbW90b3MgKnBlciBjYXBpdGEqLCBjb20gdW0gKmJveHBsb3QqIHBhcmEgY2FkYSB0aXBvIGRlIGNpZGFkZS4gCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBmaWx0ZXIocG9wX3Jlc2lkID4gMCkgJT4lIAogICAgICBtdXRhdGUobXBjID0gbW90b3MgLyBwb3BfcmVzaWQpICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fYm94cGxvdChhZXMoeCA9IHRpcG8sIHkgPSBtcGMpKSArCiAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZSgKICAgICAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHsKICAgICAgICAgICAgc3RyX3NwbGl0KHgsICcgJykgJT4lIAogICAgICAgICAgICAgIG1hcF9jaHIocGFzdGUsIGNvbGxhcHNlID0gJ1xuJykKICAgICAgICAgIH0KICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnTW90b3MgcGVyIGNhcGl0YSBwb3IgdGlwbyBkZSBjaWRhZGUnLAogICAgICAgICAgeCA9ICd0aXBvIGRlIGNpZGFkZScsCiAgICAgICAgICB5ID0gJ21vdG9zXG5wZXIgY2FwaXRhJwogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CiAgIAoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIE1lZGlhbmFzIHNlbWVsaGFudGVzLgogICAKICAgU2VtICpvdXRsaWVycyogZW0gY2lkYWRlcyBkbyB0aXBvIGludGVybWVkacOhcmlvIHJlbW90byAtLS0gcXVlLCBpcm9uaWNhbWVudGUsIHTDqm0gYSBtYWlvciB2YXJpYWJpbGlkYWRlIChlbSB0ZXJtb3MgZG8gSVFSKS4KICAgCiAgIDo6OgogICAKCiMjIFRyYXRvcmVzICpwZXIgY2FwaXRhKiBwb3IgdGlwbyBkZSBjaWRhZGUKCjEuIEZhw6dhICpib3hwbG90cyogbGFkbyBhIGxhZG8gWyhubyBtZXNtbyBncsOhZmljbywgc2VtIGZhY2V0YXIpXXsuaGx9IGRhIHF1YW50aWRhZGUgZGUgdHJhdG9yZXMgKnBlciBjYXBpdGEqLCBjb20gdW0gKmJveHBsb3QqIHBhcmEgY2FkYSB0aXBvIGRlIGNpZGFkZS4gCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgSG90w6lpcyBlIFViZXIKCjEuIEZhw6dhICpib3hwbG90cyogbGFkbyBhIGxhZG8gWyhubyBtZXNtbyBncsOhZmljbywgc2VtIGZhY2V0YXIpXXsuaGx9IGRhIHF1YW50aWRhZGUgZGUgaG90w6lpcywgY29tIHVtICpib3hwbG90KiBwYXJhIGNhZGEgdmFsb3IgZGUgYHViZXJgLiAKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCgojIyBQSUIgKnBlciBjYXBpdGEqIGUgVWJlcgoKMS4gRmHDp2EgKmJveHBsb3RzKiBsYWRvIGEgbGFkbyBbKG5vIG1lc21vIGdyw6FmaWNvLCBzZW0gZmFjZXRhcildey5obH0gZG8gdmFsb3IgZG8gUElCICpwZXIgY2FwaXRhKiwgY29tIHVtICpib3hwbG90KiBwYXJhIGNhZGEgdmFsb3IgZGUgYHViZXJgLiAKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCgojIyBDaWRhZGVzIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhCgoxLiBGYcOnYSB1bSBncsOhZmljbyBkZSBiYXJyYXMgZGFzIHF1YW50aWRhZGVzIGRlIGNpZGFkZXMsIGNvbSB1bWEgYmFycmEgcG9yIHJlZ2nDo28uIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9iYXIoCiAgICAgICAgICBhZXMoeCA9IHJlZ2lhbykKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUXVhbnRpZGFkZSBkZSBjaWRhZGVzIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhJywKICAgICAgICAgIHkgPSBOVUxMCiAgICAgICAgKQogICAgYGBgCiAgIAogICA6OjoKCjEuIFVzZSBhIGZ1bsOnw6NvIGBmY3RfcmVvcmRlcmAgcGFyYSBkaXNwb3IgYXMgYmFycmFzIGVtIG9yZGVtIFtkZWNyZXNjZW50ZV17LmhsfSBkZSBhbHR1cmEuIAoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fYmFyKAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gZmN0X3Jlb3JkZXIoCiAgICAgICAgICAgICAgcmVnaWFvLCAKICAgICAgICAgICAgICBjaWRhZGUsIAogICAgICAgICAgICAgIC5mdW4gPSBsZW5ndGgsIAogICAgICAgICAgICAgIC5kZXNjID0gVFJVRQogICAgICAgICAgICApCiAgICAgICAgICApCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1F1YW50aWRhZGUgZGUgY2lkYWRlcyBwb3IgcmVnacOjbyBnZW9ncsOhZmljYScsCiAgICAgICAgICB5ID0gTlVMTCwKICAgICAgICAgIHggPSAncmVnacOjbycKICAgICAgICApCiAgICBgYGAKICAgCiAgIDo6OgoKMS4gRW0gb3V0cm8gZ3LDoWZpY28sIHVzZSBhIGZ1bsOnw6NvIGBmY3RfcmVvcmRlcmAgcGFyYSBkaXNwb3IgYXMgYmFycmFzIGVtIG9yZGVtIFtjcmVzY2VudGVdey5obH0gZGUgYWx0dXJhLiAKCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2JhcigKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGZjdF9yZW9yZGVyKAogICAgICAgICAgICAgIHJlZ2lhbywgCiAgICAgICAgICAgICAgY2lkYWRlLCAKICAgICAgICAgICAgICAuZnVuID0gbGVuZ3RoCiAgICAgICAgICAgICkKICAgICAgICAgICkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUXVhbnRpZGFkZSBkZSBjaWRhZGVzIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhJywKICAgICAgICAgIHkgPSBOVUxMLAogICAgICAgICAgeCA9ICdyZWdpw6NvJwogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFF1YWlzIHPDo28gYXMgw6FyZWFzIHRvdGFpcyBkYXMgcmVnacO1ZXM/CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ3JvdXBfYnkocmVnaWFvKSAlPiUgCiAgICAgIHN1bW1hcml6ZShhcmVhID0gc3VtKGFyZWEpKSAlPiUgCiAgICAgIGFycmFuZ2UoYXJlYSkKICAgIGBgYAogICAKICAgQSByZWdpw6NvIE5vcnRlIHRlbSBhIG1haW9yIMOhcmVhLCBtYXMgbyBtZW5vciBuw7ptZXJvIGRlIGNpZGFkZXMuCiAgIAogICBBIHJlZ2nDo28gQ2VudHJvLU9lc3RlIHRlbSBhIHNlZ3VuZGEgbWFpb3Igw6FyZWEsIG1hcyBvIHNlZ3VuZG8gbWVub3IgbsO6bWVybyBkZSBjaWRhZGVzLgogICAKICAgQXMgb3V0cmFzIHJlZ2nDtWVzIHNlZ3VlbSBhIG1lc21hIG9yZGVtLCB0YW50byBlbSDDoXJlYSBxdWFudG8gZW0gbsO6bWVybyBkZSBjaWRhZGVzLgogICAKICAgOjo6CgoKIyMgUG9wdWxhw6fDtWVzIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhCgoxLiBGYcOnYSB1bSBncsOhZmljbyBkZSBiYXJyYXMgZGFzIHBvcHVsYcOnw7VlcyB0b3RhaXMsIGNvbSB1bWEgYmFycmEgcG9yIHJlZ2nDo28uIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGNpZGFkZXMgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9jb2woCiAgICAgICAgICBhZXMoeCA9IHJlZ2lhbywgeSA9IHBvcF9yZXNpZCkKICAgICAgICApICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoCiAgICAgICAgICAgIHNjYWxlID0gMWUtNiwKICAgICAgICAgICAgc3VmZml4ID0gJ00nCiAgICAgICAgICApCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1BvcHVsYcOnw6NvIHRvdGFsIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhJywKICAgICAgICAgIHggPSAncmVnacOjbycsCiAgICAgICAgICB5ID0gJ3BvcHVsYcOnw6NvJwogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CgoxLiBVc2UgYSBmdW7Dp8OjbyBgZmN0X3Jlb3JkZXJgIHBhcmEgZGlzcG9yIGFzIGJhcnJhcyBlbSBvcmRlbSBbZGVjcmVzY2VudGVdey5obH0gZGUgYWx0dXJhLiAKCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2NvbCgKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGZjdF9yZW9yZGVyKAogICAgICAgICAgICAgIHJlZ2lhbywKICAgICAgICAgICAgICBwb3BfcmVzaWQsCiAgICAgICAgICAgICAgc3VtLAogICAgICAgICAgICAgIC5kZXNjID0gVFJVRQogICAgICAgICAgICApLCAKICAgICAgICAgICAgeSA9IHBvcF9yZXNpZAogICAgICAgICAgKQogICAgICAgICkgKwogICAgICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdCgKICAgICAgICAgICAgc2NhbGUgPSAxZS02LAogICAgICAgICAgICBzdWZmaXggPSAnTScKICAgICAgICAgICkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUG9wdWxhw6fDo28gdG90YWwgcG9yIHJlZ2nDo28gZ2VvZ3LDoWZpY2EnLAogICAgICAgICAgeCA9ICdyZWdpw6NvJywKICAgICAgICAgIHkgPSAncG9wdWxhw6fDo28nCiAgICAgICAgKQogICAgYGBgCiAgIAogICA6OjoKCjEuIEVtIG91dHJvIGdyw6FmaWNvLCB1c2UgYSBmdW7Dp8OjbyBgZmN0X3Jlb3JkZXJgIHBhcmEgZGlzcG9yIGFzIGJhcnJhcyBlbSBvcmRlbSBbY3Jlc2NlbnRlXXsuaGx9IGRlIGFsdHVyYS4gW117I3BvcC1wb3ItcmVnaWFvfQoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fY29sKAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gZmN0X3Jlb3JkZXIoCiAgICAgICAgICAgICAgcmVnaWFvLAogICAgICAgICAgICAgIHBvcF9yZXNpZCwKICAgICAgICAgICAgICBzdW0KICAgICAgICAgICAgKSwgCiAgICAgICAgICAgIHkgPSBwb3BfcmVzaWQKICAgICAgICAgICkKICAgICAgICApICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoCiAgICAgICAgICAgIHNjYWxlID0gMWUtNiwKICAgICAgICAgICAgc3VmZml4ID0gJ00nCiAgICAgICAgICApCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1BvcHVsYcOnw6NvIHRvdGFsIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhJywKICAgICAgICAgIHggPSAncmVnacOjbycsCiAgICAgICAgICB5ID0gJ3BvcHVsYcOnw6NvJwogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIEEgcmVnacOjbyBTdWRlc3RlIMOpLCBkZSBsb25nZSwgYSBtYWlzIHBvcHVsb3NhLCBzZWd1aWRhIGRhIHJlZ2nDo28gTm9yZGVzdGUuCiAgIAogICBBIHJlZ2nDo28gQ2VudHJvLU9lc3RlIMOpICh1bSBwb3VjbykgbWVub3MgcG9wdWxvc2EgZG8gcXVlIGEgcmVnacOjbyBOb3J0ZSwgYW8gY29udHLDoXJpbyBkbyBxdWUgZXUgZXNwZXJhdmEuCgogICDDiSBpbnRlcmVzc2FudGUgY29tcGFyYXIgY29tIG8gW2dyw6FmaWNvIGRvcyBQSUJzIHRvdGFpcyBwb3IgcmVnacOjb10oI3BpYi1wb3ItcmVnaWFvKSBlIGNvbnN0YXRhciBxdWUsIGNvbSBleGNlw6fDo28gZG8gcHJpbWVpcm8gbHVnYXIsIHRvZGEgYSBvcmRlbmHDp8OjbyBtdWRhLgogICAKICAgOjo6CiAgIAoKIyMgUElCIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhCgoxLiBGYcOnYSB1bSBncsOhZmljbyBkZSBiYXJyYXMgZG9zIFBJQnMgdG90YWlzLCBjb20gdW1hIGJhcnJhIHBvciByZWdpw6NvLiBWb2PDqiB2YWkgcHJlY2lzYXIgZGEgcmVzcG9zdGEgW2Rlc3RhIHF1ZXN0w6NvXSgjcmVnaW9lcy1nZW8pLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fY29sKAogICAgICAgICAgYWVzKHggPSByZWdpYW8sIHkgPSBwaWIpCiAgICAgICAgKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKAogICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpudW1iZXJfZm9ybWF0KAogICAgICAgICAgICBzY2FsZSA9IDFlLTksCiAgICAgICAgICAgIHN1ZmZpeCA9ICdCJwogICAgICAgICAgKQogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICdQSUIgcG9yIHJlZ2nDo28gZ2VvZ3LDoWZpY2EnLAogICAgICAgICAgeCA9ICdyZWdpw6NvJywKICAgICAgICAgIHkgPSAnUElCJwogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CgoxLiBVc2UgYSBmdW7Dp8OjbyBgZmN0X3Jlb3JkZXJgIHBhcmEgZGlzcG9yIGFzIGJhcnJhcyBlbSBvcmRlbSBbZGVjcmVzY2VudGVdey5obH0gZGUgYWx0dXJhLiAKCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgY2lkYWRlcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2NvbCgKICAgICAgICAgIGFlcygKICAgICAgICAgICAgeCA9IGZjdF9yZW9yZGVyKAogICAgICAgICAgICAgIHJlZ2lhbywKICAgICAgICAgICAgICBwaWIsCiAgICAgICAgICAgICAgc3VtLAogICAgICAgICAgICAgIC5kZXNjID0gVFJVRQogICAgICAgICAgICApLCAKICAgICAgICAgICAgeSA9IHBpYgogICAgICAgICAgKQogICAgICAgICkgKwogICAgICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdCgKICAgICAgICAgICAgc2NhbGUgPSAxZS05LAogICAgICAgICAgICBzdWZmaXggPSAnQicKICAgICAgICAgICkKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUElCIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhJywKICAgICAgICAgIHggPSAncmVnacOjbycsCiAgICAgICAgICB5ID0gJ1BJQicKICAgICAgICApCiAgICBgYGAKICAgCiAgIDo6OgoKMS4gRW0gb3V0cm8gZ3LDoWZpY28sIHVzZSBhIGZ1bsOnw6NvIGBmY3RfcmVvcmRlcmAgcGFyYSBkaXNwb3IgYXMgYmFycmFzIGVtIG9yZGVtIFtjcmVzY2VudGVdey5obH0gZGUgYWx0dXJhLiBbXXsjcGliLXBvci1yZWdpYW99IAoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICAgYGBge3J9CiAgICBjaWRhZGVzICU+JSAKICAgICAgZ2dwbG90KCkgKwogICAgICAgIGdlb21fY29sKAogICAgICAgICAgYWVzKAogICAgICAgICAgICB4ID0gZmN0X3Jlb3JkZXIoCiAgICAgICAgICAgICAgcmVnaWFvLAogICAgICAgICAgICAgIHBpYiwKICAgICAgICAgICAgICBzdW0KICAgICAgICAgICAgKSwgCiAgICAgICAgICAgIHkgPSBwaWIKICAgICAgICAgICkKICAgICAgICApICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoCiAgICAgICAgICAgIHNjYWxlID0gMWUtOSwKICAgICAgICAgICAgc3VmZml4ID0gJ0InCiAgICAgICAgICApCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1BJQiBwb3IgcmVnacOjbyBnZW9ncsOhZmljYScsCiAgICAgICAgICB4ID0gJ3JlZ2nDo28nLAogICAgICAgICAgeSA9ICdQSUInCiAgICAgICAgKQogICAgYGBgCiAgIAogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgQSBvcmRlbmHDp8OjbyDDqSDDs2J2aWEuCiAgIAogICDDiSBpbnRlcmVzc2FudGUgY29tcGFyYXIgY29tIG8gW2dyw6FmaWNvIGRhcyBwb3B1bGHDp8O1ZXMgdG90YWlzIHBvciByZWdpw6NvXSgjcG9wLXBvci1yZWdpYW8pIGUgY29uc3RhdGFyIHF1ZSwgY29tIGV4Y2XDp8OjbyBkbyBwcmltZWlybyBsdWdhciwgdG9kYSBhIG9yZGVuYcOnw6NvIG11ZGEuCiAgIAogICA6OjoKICAgCgojIyBQcm9kdcOnw6NvIHJ1cmFsIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhCgoxLiBGYcOnYSB1bSBncsOhZmljbyBkZSBiYXJyYXMgZGFzIHByb2R1w6fDtWVzIHJ1cmFpcyB0b3RhaXMsIGNvbSB1bWEgYmFycmEgcG9yIHJlZ2nDo28uIFZvY8OqIHZhaSBwcmVjaXNhciBkYSByZXNwb3N0YSBbZGVzdGEgcXVlc3TDo29dKCNyZWdpb2VzLWdlbykuCgoxLiBVc2UgYSBmdW7Dp8OjbyBgZmN0X3Jlb3JkZXJgIHBhcmEgZGlzcG9yIGFzIGJhcnJhcyBlbSBvcmRlbSBbZGVjcmVzY2VudGVdey5obH0gZGUgYWx0dXJhLiAKCjEuIEVtIG91dHJvIGdyw6FmaWNvLCB1c2UgYSBmdW7Dp8OjbyBgZmN0X3Jlb3JkZXJgIHBhcmEgZGlzcG9yIGFzIGJhcnJhcyBlbSBvcmRlbSBbY3Jlc2NlbnRlXXsuaGx9IGRlIGFsdHVyYS4gCgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgoKIyMgRmFpeGFzIGV0w6FyaWFzCgoxLiBGYcOnYSB1bSBncsOhZmljbyBkZSBiYXJyYXMgZGEgcG9wdWxhw6fDo28gYnJhc2lsZWlyYSwgY29tIHVtYSBiYXJyYSBwb3IgZmFpeGEgZXTDoXJpYS4KCjEuIFVzZSBhIGZ1bsOnw6NvIGBmY3RfcmVvcmRlcmAgcGFyYSBkaXNwb3IgYXMgYmFycmFzIGVtIG9yZGVtIFtkZWNyZXNjZW50ZV17LmhsfSBkZSBhbHR1cmEuIAoKMS4gRW0gb3V0cm8gZ3LDoWZpY28sIHVzZSBhIGZ1bsOnw6NvIGBmY3RfcmVvcmRlcmAgcGFyYSBkaXNwb3IgYXMgYmFycmFzIGVtIG9yZGVtIFtjcmVzY2VudGVdey5obH0gZGUgYWx0dXJhLgoKMS4gRW0gcXVhbCBvcmRlbSB2b2PDqiBhY2hhIHF1ZSBhcyBiYXJyYXMgZGV2ZW0gYXBhcmVjZXI/IFBvciBxdcOqPwoKMS4gQ29tZW50ZSBvcyByZXN1bHRhZG9zLgoKCiMjIEZhaXhhcyBldMOhcmlhcyBwb3IgcmVnacOjbyBnZW9ncsOhZmljYQoKMS4gRmHDp2EgdW0gZ3LDoWZpY28gZGUgYmFycmFzIGRhIHBvcHVsYcOnw6NvIGJyYXNpbGVpcmEsIGNvbSB1bSBbY29uanVudG8gZGUgYmFycmFzIHBhcmEgY2FkYSByZWdpw6NvXXsuaGx9LiBWb2PDqiB2YWkgcHJlY2lzYXIgZGEgcmVzcG9zdGEgW2Rlc3RhIHF1ZXN0w6NvXSgjcmVnaW9lcy1nZW8pLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBWZWphIGFiYWl4by4KICAgCiAgIDo6OgoKMS4gQ2FkYSBjb25qdW50byBkZXZlIHRlciAkNiQgYmFycmFzIGxhZG8gYSBsYWRvLCB1bWEgcGFyYSBjYWRhIGZhaXhhIGV0w6FyaWEuIFVzZSBvIGFyZ3VtZW50byBgZG9kZ2VgIG5hIGdlb21ldHJpYSBhZGVxdWFkYS4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgZGZfZmFpeGFzIDwtIGNpZGFkZXMgJT4lIAogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IHN0YXJ0c193aXRoKCdwb3BfcmVndWxhcl8nKSwKICAgICAgICBuYW1lc190byA9ICdmYWl4YScsCiAgICAgICAgbmFtZXNfcHJlZml4ID0gJ3BvcF9yZWd1bGFyXycsCiAgICAgICAgdmFsdWVzX3RvID0gJ3BvcCcKICAgICAgKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBmYWl4YSA9IGNhc2Vfd2hlbigKICAgICAgICAgIGZhaXhhID09ICcxJyB+ICdhdMOpIDEnLAogICAgICAgICAgZmFpeGEgPT0gJzFfNCcgfiAnMSBhIDQnLAogICAgICAgICAgZmFpeGEgPT0gJzVfOScgfiAnNSBhIDknLAogICAgICAgICAgZmFpeGEgPT0gJzEwXzE0JyB+ICcxMCBhIDE0JywKICAgICAgICAgIGZhaXhhID09ICcxNV81OScgfiAnMTUgYSA1OScsCiAgICAgICAgICBmYWl4YSA9PSAnNjBfbWFpcycgfiAnNjAgb3UgbWFpcycKICAgICAgICApCiAgICAgICkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgZmFpeGEgPSBmYWN0b3IoCiAgICAgICAgICBmYWl4YSwKICAgICAgICAgIGxldmVscyA9IHVuaXF1ZShmYWl4YSksCiAgICAgICAgICBvcmRlcmVkID0gVFJVRQogICAgICAgICkKICAgICAgKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIHJlZ2lhbywgZmFpeGEsIHBvcCkKICAgIAogICAgZGZfZmFpeGFzCiAgICBgYGAKICAgCiAgICBgYGB7cn0KICAgIGRmX2ZhaXhhcyAlPiUgCiAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX2NvbCgKICAgICAgICAgIGFlcyh4ID0gcmVnaWFvLCB5ID0gcG9wLCBmaWxsID0gZmFpeGEpLAogICAgICAgICAgcG9zaXRpb24gPSAnZG9kZ2UnCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1BvcHVsYcOnw6NvIHBvciByZWdpw6NvLCBwb3IgZmFpeGEgZXTDoXJpYScsCiAgICAgICAgICB4ID0gJ3JlZ2nDo28nLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICBmaWxsID0gTlVMTAogICAgICAgICkgKwogICAgICAgIHNjYWxlX3lfY29udGludW91cygKICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6bGFiZWxfbnVtYmVyKAogICAgICAgICAgICBzY2FsZSA9IDFlLTYsCiAgICAgICAgICAgIHN1ZmZpeCA9ICdNJwogICAgICAgICAgKQogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFBlcmNlYmEgcXVlIGFzIGZhaXhhcyBldMOhcmlhcyB0w6ptIGxhcmd1cmFzIGRpZmVyZW50ZXMuIAogICAKICAgQXMgw7puaWNhcyBjb21wYXJhw6fDtWVzIHJhem/DoXZlaXMgc8OjbyBlbnRyZSBbJDEkIGEgJDQkXXsuaGx9LCBbJDUkIGEgJDkkXXsuaGx9LCBlIFskMTAkIGEgJDE0JF17LmhsfSwgcXVlIHTDqm0gbGFyZ3VyYXMgYXByb3hpbWFkYW1lbnRlIGlndWFpcy4KICAgCiAgIEVtIHRvZGFzIGFzIHJlZ2nDtWVzLCBow6EgbWFpcyBwZXNzb2FzIGRhIGZhaXhhICQxMCQgYSAkMTQkIGRvIHF1ZSBkYXMgZmFpeGFzIG1haXMgam92ZW5zLgogICAKICAgQXMgcmVnacO1ZXMgQ2VudHJvLU9lc3RlIGUgTm9ydGUgc8OjbyBhcyDDum5pY2FzIG9uZGUgaMOhIG1lbm9zIGlkb3NvcyBkbyBxdWUgam92ZW5zIGRlICQxMCQgYSAkMTQkLgogICAKICAgOjo6CgoKIyMgRmFpeGFzIGV0w6FyaWFzIHBvciByZWdpw6NvIGdlb2dyw6FmaWNhLCBwcm9wb3LDp8O1ZXMKCjEuIEZhw6dhIHVtIGdyw6FmaWNvIGRlIGJhcnJhcyBkYSBwb3B1bGHDp8OjbyBicmFzaWxlaXJhLCBjb20gdW1hIGJhcnJhIHBvciByZWdpw6NvLiBWb2PDqiB2YWkgcHJlY2lzYXIgZGEgcmVzcG9zdGEgW2Rlc3RhIHF1ZXN0w6NvXSgjcmVnaW9lcy1nZW8pLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBWZWphIGFiYWl4by4KICAgCiAgIDo6OgoKMS4gVG9kYXMgYXMgYmFycmFzIGRldmVtIHNlciBkYSBtZXNtYSBhbHR1cmEsIGUgbyBlaXhvICR5JCBkZXZlIGlyIGRlICQwJCBhdMOpICQxJCwgcmVwcmVzZW50YW5kbyBwcm9wb3LDp8O1ZXMuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIFZlamEgYWJhaXhvLgogICAKICAgOjo6CgoxLiBDYWRhIGJhcnJhIGRldmUgc2VyIHN1YmRpdmlkaWRhIGVtIGZhaXhhcyBob3Jpem9udGFpcyBkZSBjb3JlcyBkaWZlcmVudGVzLCB1bWEgZmFpeGEgY29sb3JpZGEgcGFyYSBjYWRhIGZhaXhhIGV0w6FyaWEsIGRlIGFjb3JkbyBjb20gYXMgcHJvcG9yw6fDtWVzIGRlIGNhZGEgZmFpeGEgZXTDoXJpYSBlbSBjYWRhIHJlZ2nDo28uCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgICBgYGB7cn0KICAgIGRmX2ZhaXhhcyA8LSBjaWRhZGVzICU+JSAKICAgICAgcGl2b3RfbG9uZ2VyKAogICAgICAgIGNvbHMgPSBzdGFydHNfd2l0aCgncG9wX3JlZ3VsYXJfJyksCiAgICAgICAgbmFtZXNfdG8gPSAnZmFpeGEnLAogICAgICAgIG5hbWVzX3ByZWZpeCA9ICdwb3BfcmVndWxhcl8nLAogICAgICAgIHZhbHVlc190byA9ICdwb3AnCiAgICAgICkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgZmFpeGEgPSBjYXNlX3doZW4oCiAgICAgICAgICBmYWl4YSA9PSAnMScgfiAnYXTDqSAxJywKICAgICAgICAgIGZhaXhhID09ICcxXzQnIH4gJzEgYSA0JywKICAgICAgICAgIGZhaXhhID09ICc1XzknIH4gJzUgYSA5JywKICAgICAgICAgIGZhaXhhID09ICcxMF8xNCcgfiAnMTAgYSAxNCcsCiAgICAgICAgICBmYWl4YSA9PSAnMTVfNTknIH4gJzE1IGEgNTknLAogICAgICAgICAgZmFpeGEgPT0gJzYwX21haXMnIH4gJzYwIG91IG1haXMnCiAgICAgICAgKQogICAgICApICU+JSAKICAgICAgbXV0YXRlKAogICAgICAgIGZhaXhhID0gZmFjdG9yKAogICAgICAgICAgZmFpeGEsCiAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUoZmFpeGEpLAogICAgICAgICAgb3JkZXJlZCA9IFRSVUUKICAgICAgICApCiAgICAgICkgJT4lIAogICAgICBzZWxlY3QoY2lkYWRlLCByZWdpYW8sIGZhaXhhLCBwb3ApCiAgICAKICAgIGRmX2ZhaXhhcwogICAgYGBgCiAgIAogICAgYGBge3J9CiAgICBkZl9mYWl4YXMgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9jb2woCiAgICAgICAgICBhZXMoeCA9IHJlZ2lhbywgeSA9IHBvcCwgZmlsbCA9IGZjdF9yZXYoZmFpeGEpKSwKICAgICAgICAgIHBvc2l0aW9uID0gJ2ZpbGwnCiAgICAgICAgKSArCiAgICAgICAgbGFicygKICAgICAgICAgIHRpdGxlID0gJ1BvcHVsYcOnw6NvIHBvciByZWdpw6NvLCBwb3IgZmFpeGEgZXTDoXJpYScsCiAgICAgICAgICBzdWJ0aXRsZSA9ICcocHJvcG9yw6fDtWVzKScsCiAgICAgICAgICB4ID0gJ3JlZ2nDo28nLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICBmaWxsID0gTlVMTAogICAgICAgICkKICAgIGBgYAogICAKICAgOjo6CgoxLiBDb21lbnRlIG9zIHJlc3VsdGFkb3MuCgogICA6Ojogey5ybWRib3ggbGF0ZXg9MX0KICAgCiAgIEFzIHByb3BvcsOnw7VlcyBzw6NvIHNlbWVsaGFudGVzIGVudHJlIGFzIHJlZ2nDtWVzLgogICAKICAgQSByZWdpw6NvIE5vcnRlIHRlbSBhIG1lbm9yIHByb3BvcsOnw6NvIGRlIGlkb3NvcywgZSBhIG1haW9yIHByb3BvcsOnw6NvIGRlIHBlc3NvYXMgYXTDqSAkMTQkIGFub3MuCiAgIAogICBBcyByZWdpw7VlcyBTdWwgZSBTdWRlc3RlIHTDqm0gYSBtYWlvciBwcm9wb3LDp8OjbyBkZSBpZG9zb3MuCiAgIAogICA6OjoKCgojIyBGYWl4YXMgZXTDoXJpYXMgcG9yIHRpcG8gZGUgY2lkYWRlCgoxLiBGYcOnYSB1bSBncsOhZmljbyBkZSBiYXJyYXMgZGEgcG9wdWxhw6fDo28gYnJhc2lsZWlyYSwgY29tIHVtIFtjb25qdW50byBkZSBiYXJyYXMgcGFyYSBjYWRhIHRpcG8gZGUgY2lkYWRlXXsuaGx9LgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBWZWphIGFiYWl4by4KICAgCiAgIDo6OgoKMS4gQ2FkYSBjb25qdW50byBkZXZlIHRlciAkNiQgYmFycmFzIGxhZG8gYSBsYWRvLCB1bWEgcGFyYSBjYWRhIGZhaXhhIGV0w6FyaWEuIFVzZSBvIGFyZ3VtZW50byBgZG9kZ2VgIG5hIGdlb21ldHJpYSBhZGVxdWFkYS4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgZGZfZmFpeGFzIDwtIGNpZGFkZXMgJT4lIAogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IHN0YXJ0c193aXRoKCdwb3BfcmVndWxhcl8nKSwKICAgICAgICBuYW1lc190byA9ICdmYWl4YScsCiAgICAgICAgbmFtZXNfcHJlZml4ID0gJ3BvcF9yZWd1bGFyXycsCiAgICAgICAgdmFsdWVzX3RvID0gJ3BvcCcKICAgICAgKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBmYWl4YSA9IGNhc2Vfd2hlbigKICAgICAgICAgIGZhaXhhID09ICcxJyB+ICdhdMOpIDEnLAogICAgICAgICAgZmFpeGEgPT0gJzFfNCcgfiAnMSBhIDQnLAogICAgICAgICAgZmFpeGEgPT0gJzVfOScgfiAnNSBhIDknLAogICAgICAgICAgZmFpeGEgPT0gJzEwXzE0JyB+ICcxMCBhIDE0JywKICAgICAgICAgIGZhaXhhID09ICcxNV81OScgfiAnMTUgYSA1OScsCiAgICAgICAgICBmYWl4YSA9PSAnNjBfbWFpcycgfiAnNjAgb3UgbWFpcycKICAgICAgICApCiAgICAgICkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgZmFpeGEgPSBmYWN0b3IoCiAgICAgICAgICBmYWl4YSwKICAgICAgICAgIGxldmVscyA9IHVuaXF1ZShmYWl4YSksCiAgICAgICAgICBvcmRlcmVkID0gVFJVRQogICAgICAgICkKICAgICAgKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIHRpcG8sIGZhaXhhLCBwb3ApCiAgICAKICAgIGRmX2ZhaXhhcwogICAgYGBgCiAgIAogICAgYGBge3J9CiAgICBkZl9mYWl4YXMgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9jb2woCiAgICAgICAgICBhZXMoeCA9IHRpcG8sIHkgPSBwb3AsIGZpbGwgPSBmYWl4YSksCiAgICAgICAgICBwb3NpdGlvbiA9ICdkb2RnZScKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUG9wdWxhw6fDo28gcG9yIHRpcG8gZGUgY2lkYWRlLCBwb3IgZmFpeGEgZXTDoXJpYScsCiAgICAgICAgICB4ID0gJ3RpcG8gZGUgY2lkYWRlJywKICAgICAgICAgIHkgPSBOVUxMLAogICAgICAgICAgZmlsbCA9IE5VTEwKICAgICAgICApCiAgICBgYGAKCiAgIEEgcG9wdWxhw6fDo28gZGUgY2lkYWRlcyBkbyB0aXBvIHVyYmFubyDDqSB0w6NvIGdyYW5kZSBxdWUgb3Mgb3V0cm9zIHRpcG9zIGZpY2FtIHF1YXNlIGludmlzw612ZWlzLgogICAKICAgW1ZlamEgYSBwcsOzeGltYSBxdWVzdMOjb10oI3Byb3BvcmNvZXMpLCBxdWUgcmVzb2x2ZSBlc3RlIHByb2JsZW1hIG1vc3RyYW5kbyBhcyBbcHJvcG9yw6fDtWVzXXsuaGx9IGRhcyBkaXZlcnNhcyBmYWl4YXMgZXTDoXJpYXMuCiAgIAogICBWYW1vcyBleGNsdWlyIG8gdGlwbyB1cmJhbm8gZG8gZ3LDoWZpY286CiAgIAogICAgYGBge3J9CiAgICBkZl9mYWl4YXMgJT4lIAogICAgICBmaWx0ZXIodGlwbyAhPSAnVXJiYW5vJykgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9jb2woCiAgICAgICAgICBhZXMoeCA9IHRpcG8sIHkgPSBwb3AsIGZpbGwgPSBmYWl4YSksCiAgICAgICAgICBwb3NpdGlvbiA9ICdkb2RnZScKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUG9wdWxhw6fDo28gcG9yIHRpcG8gZGUgY2lkYWRlLCBwb3IgZmFpeGEgZXTDoXJpYScsCiAgICAgICAgICBzdWJ0aXRsZSA9ICdleGNldG8gY2VudHJvcyB1cmJhbm9zJywKICAgICAgICAgIHggPSAndGlwbyBkZSBjaWRhZGUnLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICBmaWxsID0gTlVMTAogICAgICAgICkKICAgIGBgYAoKICAgVmFtb3MgbWVsaG9yYXIgb3MgcsOzdHVsb3MgZG8gZWl4byAkeCQgZSBpZ25vcmFyIGFzIGNpZGFkZXMgc2VtIGNsYXNzaWZpY2HDp8OjbzoKICAgCiAgICBgYGB7cn0KICAgIGRmX2ZhaXhhcyAlPiUgCiAgICAgIGZpbHRlcih0aXBvICE9ICdVcmJhbm8nKSAlPiUgCiAgICAgIGZpbHRlcih0aXBvICE9ICdTZW0gY2xhc3NpZmljYcOnw6NvJykgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9jb2woCiAgICAgICAgICBhZXMoeCA9IHRpcG8sIHkgPSBwb3AsIGZpbGwgPSBmYWl4YSksCiAgICAgICAgICBwb3NpdGlvbiA9ICdkb2RnZScKICAgICAgICApICsKICAgICAgICBsYWJzKAogICAgICAgICAgdGl0bGUgPSAnUG9wdWxhw6fDo28gcG9yIHRpcG8gZGUgY2lkYWRlLCBwb3IgZmFpeGEgZXTDoXJpYScsCiAgICAgICAgICBzdWJ0aXRsZSA9ICdleGNldG8gY2VudHJvcyB1cmJhbm9zJywKICAgICAgICAgIHggPSAndGlwbyBkZSBjaWRhZGUnLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICBmaWxsID0gTlVMTAogICAgICAgICkgKwogICAgICAgIHNjYWxlX3hfZGlzY3JldGUoCiAgICAgICAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgIHN0cl9zcGxpdCh4LCAnICcpICU+JSAKICAgICAgICAgICAgICBtYXBfY2hyKHBhc3RlLCBjb2xsYXBzZSA9ICdcbicpCiAgICAgICAgICB9CiAgICAgICAgKQogICAgYGBgCgogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgT3MgY2VudHJvcyB1cmJhbm9zIHTDqm0gdW1hIHBvcHVsYcOnw6NvIG11aXRvIG1haW9yIGRvIHF1ZSBvcyBvdXRyb3MgdGlwb3MgZGUgY2lkYWRlLgogICAKICAgQ2lkYWRlcyBkbyB0aXBvIHVyYmFubyBlIGludGVybWVkacOhcmlvIGFkamFjZW50ZSBwYXJlY2VtIHRlciB1bWEgcHJvcG9yw6fDo28gc2lnbmlmaWNhdGl2YW1lbnRlIG1haW9yIGRlIHBlc3NvYXMgZW50cmUgJDE1JCBhICQ1OSQgYW5vcy4KICAgCiAgIDo6OgogICAKCiMjIEZhaXhhcyBldMOhcmlhcyBwb3IgdGlwbyBkZSBjaWRhZGUsIHByb3BvcsOnw7VlcyB7ICNwcm9wb3Jjb2VzIH0KCjEuIEZhw6dhIHVtIGdyw6FmaWNvIGRlIGJhcnJhcyBkYSBwb3B1bGHDp8OjbyBicmFzaWxlaXJhLCBjb20gdW1hIGJhcnJhIHBvciB0aXBvIGRlIGNpZGFkZS4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgVmVqYSBhYmFpeG8uCiAgIAogICA6OjoKCjEuIFRvZGFzIGFzIGJhcnJhcyBkZXZlbSBzZXIgZGEgbWVzbWEgYWx0dXJhLCBlIG8gZWl4byAkeSQgZGV2ZSBpciBkZSAkMCQgYXTDqSAkMSQsIHJlcHJlc2VudGFuZG8gcHJvcG9yw6fDtWVzLgoKICAgOjo6IHsucm1kYm94IGxhdGV4PTF9CiAgIAogICBWZWphIGFiYWl4by4KICAgCiAgIDo6OgoKMS4gQ2FkYSBiYXJyYSBkZXZlIHNlciBzdWJkaXZpZGlkYSBlbSBmYWl4YXMgaG9yaXpvbnRhaXMgZGUgY29yZXMgZGlmZXJlbnRlcywgdW1hIGZhaXhhIGNvbG9yaWRhIHBhcmEgY2FkYSBmYWl4YSBldMOhcmlhLCBkZSBhY29yZG8gY29tIGFzIHByb3BvcsOnw7VlcyBkZSBjYWRhIGZhaXhhIGV0w6FyaWEgZW0gY2FkYSB0aXBvIGRlIGNpZGFkZS4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgIGBgYHtyfQogICAgZGZfZmFpeGFzIDwtIGNpZGFkZXMgJT4lIAogICAgICBwaXZvdF9sb25nZXIoCiAgICAgICAgY29scyA9IHN0YXJ0c193aXRoKCdwb3BfcmVndWxhcl8nKSwKICAgICAgICBuYW1lc190byA9ICdmYWl4YScsCiAgICAgICAgbmFtZXNfcHJlZml4ID0gJ3BvcF9yZWd1bGFyXycsCiAgICAgICAgdmFsdWVzX3RvID0gJ3BvcCcKICAgICAgKSAlPiUgCiAgICAgIG11dGF0ZSgKICAgICAgICBmYWl4YSA9IGNhc2Vfd2hlbigKICAgICAgICAgIGZhaXhhID09ICcxJyB+ICdhdMOpIDEnLAogICAgICAgICAgZmFpeGEgPT0gJzFfNCcgfiAnMSBhIDQnLAogICAgICAgICAgZmFpeGEgPT0gJzVfOScgfiAnNSBhIDknLAogICAgICAgICAgZmFpeGEgPT0gJzEwXzE0JyB+ICcxMCBhIDE0JywKICAgICAgICAgIGZhaXhhID09ICcxNV81OScgfiAnMTUgYSA1OScsCiAgICAgICAgICBmYWl4YSA9PSAnNjBfbWFpcycgfiAnNjAgb3UgbWFpcycKICAgICAgICApCiAgICAgICkgJT4lIAogICAgICBtdXRhdGUoCiAgICAgICAgZmFpeGEgPSBmYWN0b3IoCiAgICAgICAgICBmYWl4YSwKICAgICAgICAgIGxldmVscyA9IHVuaXF1ZShmYWl4YSksCiAgICAgICAgICBvcmRlcmVkID0gVFJVRQogICAgICAgICkKICAgICAgKSAlPiUgCiAgICAgIHNlbGVjdChjaWRhZGUsIHRpcG8sIGZhaXhhLCBwb3ApCiAgICAKICAgIGRmX2ZhaXhhcwogICAgYGBgCiAgIAogICAgYGBge3J9CiAgICBkZl9mYWl4YXMgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9jb2woCiAgICAgICAgICBhZXMoeCA9IHRpcG8sIHkgPSBwb3AsIGZpbGwgPSBmY3RfcmV2KGZhaXhhKSksCiAgICAgICAgICBwb3NpdGlvbiA9ICdmaWxsJwogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICdQb3B1bGHDp8OjbyBwb3IgdGlwbyBkZSBjaWRhZGUsIHBvciBmYWl4YSBldMOhcmlhJywKICAgICAgICAgIHN1YnRpdGxlID0gJyhwcm9wb3LDp8O1ZXMpJywKICAgICAgICAgIHggPSAndGlwbyBkZSBjaWRhZGUnLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICBmaWxsID0gTlVMTAogICAgICAgICkKICAgIGBgYAogICAKICAgVmFtb3MgbWVsaG9yYXIgb3MgcsOzdHVsb3MgZG8gZWl4byAkeCQgZSBpZ25vcmFyIGFzIGNpZGFkZXMgc2VtIGNsYXNzaWZpY2HDp8OjbzoKICAgCiAgICBgYGB7cn0KICAgIGRmX2ZhaXhhcyAlPiUgCiAgICAgIGZpbHRlcih0aXBvICE9ICdTZW0gY2xhc3NpZmljYcOnw6NvJykgJT4lIAogICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9jb2woCiAgICAgICAgICBhZXMoeCA9IHRpcG8sIHkgPSBwb3AsIGZpbGwgPSBmY3RfcmV2KGZhaXhhKSksCiAgICAgICAgICBwb3NpdGlvbiA9ICdmaWxsJwogICAgICAgICkgKwogICAgICAgIGxhYnMoCiAgICAgICAgICB0aXRsZSA9ICdQb3B1bGHDp8OjbyBwb3IgdGlwbyBkZSBjaWRhZGUsIHBvciBmYWl4YSBldMOhcmlhJywKICAgICAgICAgIHN1YnRpdGxlID0gJyhwcm9wb3LDp8O1ZXMpJywKICAgICAgICAgIHggPSAndGlwbyBkZSBjaWRhZGUnLAogICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICBmaWxsID0gTlVMTAogICAgICAgICkgKwogICAgICAgIHNjYWxlX3hfZGlzY3JldGUoCiAgICAgICAgICBsYWJlbHMgPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgIHN0cl9zcGxpdCh4LCAnICcpICU+JSAKICAgICAgICAgICAgICBtYXBfY2hyKHBhc3RlLCBjb2xsYXBzZSA9ICdcbicpCiAgICAgICAgICB9CiAgICAgICAgKQogICAgYGBgCgogICA6OjoKCjEuIENvbWVudGUgb3MgcmVzdWx0YWRvcy4KCiAgIDo6OiB7LnJtZGJveCBsYXRleD0xfQogICAKICAgUHJvcG9yY2lvbmFsbWVudGUuIGjDoSBtYWlzIGlkb3NvcyBlbSBjaWRhZGVzIGRlIHRpcG9zIHVyYmFubywgaW50ZXJtZWRpw6FyaW8gYWRqYWNlbnRlIGUgcnVyYWwgYWRqYWNlbnRlLgogICAKICAgUHJvcG9yY2lvbmFsbWVudGUuIGjDoSBtYWlzIGpvdmVucyBlbSBjaWRhZGVzIGRlIHRpcG9zIGludGVybWVkacOhcmlvIHJlbW90byBlIHJ1cmFsIHJlbW90by4KICAgCiAgIDo6OgogICAKCiMgTWFwYSBpbnRlcmF0aXZvCgojIyBNYXJjYWRvcmVzCgoxLiBMZWlhIGFsZ3VtIHR1dG9yaWFsIHNvYnJlIG8gcGFjb3RlIGBsZWFmbGV0YDoKCiAgICogRW0gaW5nbMOqczogaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9sZWFmbGV0LyAoYmFzdGEgbGVyIG9zICQ1JCBwcmltZWlyb3MgaXRlbnMgZG8gbWVudSkuCiAgIAogICAqIEVtIHBvcnR1Z3XDqnM6IGh0dHA6Ly9zaWxsYXNnb256YWdhLmNvbS9tYXRlcmlhbC9jZHIvaHRtbHdpZGdldHMuaHRtbCNsZWFmbGV0IChhdMOpICJNYXJjYWRvcmVzIikuCiAgICAgCjEuIEVzY29saGEgcXVhbHF1ZXIgdW1hIGRhcyBxdWVzdMO1ZXMgZG8gdGlwbyAiUXVhaXMgYXMgJDEwJCBjaWRhZGVzLi4uIiwgbmEgW3Nlw6fDo28gZGUgYW7DoWxpc2UgZXhwbG9yYXTDs3JpYV0oI2VkYSkuCgoxLiBSZXNvbHZhIGEgcXVlc3TDo28gZSBtb2RpZmlxdWUgbyBjw7NkaWdvIGFiYWl4byBwYXJhIGNyaWFyIG1hcmNhZG9yZXMgbW9zdHJhbmRvIGFzIGNpZGFkZXMgZGEgcmVzcG9zdGEsIFtyb3R1bGFkb3MgY29tIG9zIG5vbWVzIGRhcyBjaWRhZGVzXXsuaGx9ICh1c2UgbyBhcmd1bWVudG8gYGxhYmVsYCkuCgoxLiBRdWFuZG8gbyB1c3XDoXJpbyBjbGljYXIgbyAqbW91c2UqIHNvYnJlIGEgY2lkYWRlLCBkZXZlIGFwYXJlY2VyIGEgaW5mb3JtYcOnw6NvIHJlbGV2YW50ZSBwZWRpZGEgcGVsYSBxdWVzdMOjbyAodXNlIG8gYXJndW1lbnRvIGBwb3B1cGApLgoKMS4gQWNyZXNjZW50ZSBvdXRyYXMgaW5mb3JtYcOnw7VlcyBxdWUgdm9jw6ogYWNoYXIgaW1wb3J0YW50ZXMgLS0tIHBvciBleGVtcGxvLCBhIGNsYXNzaWZpY2HDp8OjbyBkYSBjaWRhZGUgbmEgb3JkZW5hw6fDo28gcXVlIGEgcXVlc3TDo28gcGVkZS4KCiAgICBgYGB7cn0KICAgIGxpYnJhcnkobGVhZmxldCkKICAgIAogICAgIyBVbSBleGVtcGxvLCBhcGVuYXMuIFN1YnN0aXR1YSBjb20gYSB0aWJibGUgZGEgc3VhIHJlc3Bvc3RhOgogICAgZGYgPC0gY2lkYWRlcyAlPiUgCiAgICAgIGZpbHRlcigKICAgICAgICBjaWRhZGUgJWluJSBjKCdNYW5hdXMnLCAnQnJhc8OtbGlhJywgJ1BvcnRvIEFsZWdyZScpCiAgICAgICkKICAgIAogICAgIyBPIG1hcGE6CiAgICBsZWFmbGV0KGRmKSAlPiUgCiAgICAgIHNldFZpZXcoCiAgICAgICAgbG5nID0gbWVhbihkZiRsb25naXR1ZGUpLCAKICAgICAgICBsYXQgPSBtZWFuKGRmJGxhdGl0dWRlKSwKICAgICAgICB6b29tID0gNAogICAgICApICU+JSAKICAgICAgYWRkVGlsZXMoKSAlPiUgCiAgICAgIGFkZE1hcmtlcnMoKQogICAgYGBgCgoxLiBGYcOnYSBbdW0gc2VndW5kbyBtYXBhIGludGVyYXRpdm9dey5obH0gY29tIG1hcmNhZG9yZXMgcGFyYSBhcyBjaWRhZGVzIHF1ZSBzYXRpc2ZhemVtIGFsZ3VtIGNyaXTDqXJpbyBxdWUgdm9jw6ogYWNoZSBpbnRlcmVzc2FudGUuIFVzZSBhIGltYWdpbmHDp8Ojby4KCg==