library(tidyverse)
library(caret)
library(reshape2)
options(scipen = 4)
dados <- read.csv("../dados/train.csv", encoding = "UTF-8")

Analisando os dados é possível perceber que existe um grande número de NA'S(ausência de dados) nas colunas referentes as variáveis recursos_de_outros_candidatos.comites, recursos_de_partidos, recursos_de_pessoas_físicas, recursos_de_pessoas_juridicas e recursos_proprios. Afim de solucionar este problema, substitui esses valores pela mediana de cada variável.

#substituindo os valores NA pela mediana das suas respectivas colunas
dados$recursos_de_outros_candidatos.comites[is.na(dados$recursos_de_outros_candidatos.comites)]<-median (dados$recursos_de_outros_candidatos.comites, na.rm = TRUE)
dados$recursos_de_partidos[is.na(dados$recursos_de_partidos)]<-median (dados$recursos_de_partidos, na.rm = TRUE)
dados$recursos_de_pessoas_físicas[is.na(dados$recursos_de_pessoas_físicas)]<-median (dados$recursos_de_pessoas_físicas, na.rm = TRUE)
dados$recursos_de_pessoas_juridicas[is.na(dados$recursos_de_pessoas_juridicas)]<-median (dados$recursos_de_pessoas_juridicas, na.rm = TRUE)
dados$recursos_proprios[is.na(dados$recursos_proprios)]<-median (dados$recursos_proprios, na.rm = TRUE)

Algumas variáveis que causavam problemas ao gerar o modelo de regressão ou com muitos valores #NULO, como setor_economico_receita, foram removidas a fim de trazer mais clareza aos modelos de regressão.

#removendo variáveis
dados <- dados %>% select(-nome, -cargo, -setor_economico_receita, -setor_economico_despesa)

Usando todas as variáveis disponíveis, tune (usando validação cruzada):

  • (i) um modelo de regressão Ridge,
  • (ii) um modelo de regressão Lasso e
  • (iii) um modelo KNN. Para os modelos de regressão linear.

O parâmetro a ser tunado é o lambda (penalização dos coeficientes) e o KNN o número de vizinhos.

Modelo de Regressão Ridge Os dados consistem em 4152 observações, o modelo de regressão foi gerado considerando 10-fold e 30 valores distintos para lambda entre o intervalo [102;10-10].

O valor lambda = 0.04893901 gerou o menor RMSE.

Modelo de Regressão Lasso No modelo de regressão Lasso também foi utilizado 10-fold e o parametro de variação do fraction definido como 30 valores no intervalo [0.001; 1].

O fraction = 0.04413793 gerou o menor RMSE observado.

Modelo de Regressão KNN Para o modelo de regressão KNN foi mantido o padrão 10-fold o parametro referente ao número de vizinhos foi definido como 20 valores no intervalo[5;25].

O menor RMSE foi observado ao se considerar 11 vizinhos.

Compare os três modelos em termos do erro RMSE de validação cruzada.

Todos os modelos em questão considereram um k-fold = 10.

ridge
Ridge Regression 

4152 samples
  21 predictors

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 3736, 3737, 3737, 3736, 3737, 3737, ... 
Resampling results across tuning parameters:

  lambda        RMSE       Rsquared   MAE     
  1.000000e-10   31632.50  0.5186225  13125.79
  2.592944e-10   31632.50  0.5186225  13125.79
  6.723358e-10   31632.50  0.5186225  13125.79
  1.743329e-09   31632.50  0.5186226  13125.78
  4.520354e-09   31632.50  0.5186226  13125.77
  1.172102e-08   31632.49  0.5186228  13125.75
  3.039195e-08   31632.48  0.5186232  13125.68
  7.880463e-08   31632.44  0.5186244  13125.52
  2.043360e-07   31632.35  0.5186273  13125.09
  5.298317e-07   31632.11  0.5186348  13123.99
  1.373824e-06   31631.51  0.5186540  13121.16
  3.562248e-06   31630.01  0.5187014  13113.99
  9.236709e-06   31626.63  0.5188098  13096.50
  2.395027e-05   31620.53  0.5190116  13057.86
  6.210169e-05   31616.06  0.5191948  12989.88
  1.610262e-04   31632.22  0.5188079  12913.19
  4.175319e-04   31685.56  0.5172976  12882.96
  1.082637e-03   31744.68  0.5154169  12897.64
  2.807216e-03   31762.59  0.5143103  12920.65
  7.278954e-03   31720.00  0.5142718  12926.48
  1.887392e-02   31627.05  0.5151862  12932.10
  4.893901e-02   31569.86  0.5165545  12975.24
  1.268961e-01   31744.87  0.5186835  13128.08
  3.290345e-01   32835.34  0.5229714  13802.75
  8.531679e-01   37898.09  0.5276280  17002.38
  2.212216e+00   54347.88  0.5287590  27243.63
  5.736153e+00   86544.78  0.5268711  46720.81
  1.487352e+01  124267.35  0.5248639  69266.15
  3.856620e+01  152224.31  0.5237282  85872.14
  1.000000e+02  167145.75  0.5232183  94717.13

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was lambda = 0.04893901.
lasso
The lasso 

4152 samples
  21 predictors

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 3737, 3736, 3737, 3737, 3736, 3737, ... 
Resampling results across tuning parameters:

  fraction    RMSE      Rsquared   MAE     
  0.01000000  33812.41  0.4856537  15376.54
  0.04413793  31507.49  0.5070080  12673.27
  0.07827586  31598.83  0.5098798  12662.09
  0.11241379  31639.08  0.5105318  12854.10
  0.14655172  31659.85  0.5107295  12925.01
  0.18068966  31651.79  0.5110887  12935.17
  0.21482759  31637.96  0.5115238  12931.53
  0.24896552  31623.46  0.5119332  12929.06
  0.28310345  31610.41  0.5123001  12929.53
  0.31724138  31601.49  0.5125486  12934.54
  0.35137931  31592.54  0.5128071  12938.58
  0.38551724  31586.97  0.5129959  12944.65
  0.41965517  31579.16  0.5132144  12950.87
  0.45379310  31572.12  0.5134159  12958.90
  0.48793103  31566.50  0.5135746  12968.67
  0.52206897  31562.17  0.5136962  12979.35
  0.55620690  31558.87  0.5137900  12990.40
  0.59034483  31556.91  0.5138444  13001.00
  0.62448276  31555.58  0.5138757  13010.76
  0.65862069  31554.72  0.5138924  13019.72
  0.69275862  31553.22  0.5139263  13025.75
  0.72689655  31552.97  0.5139324  13030.50
  0.76103448  31552.49  0.5139426  13033.26
  0.79517241  31552.11  0.5139507  13036.04
  0.82931034  31551.80  0.5139561  13038.87
  0.86344828  31551.65  0.5139576  13041.87
  0.89758621  31551.61  0.5139563  13045.14
  0.93172414  31551.68  0.5139523  13048.68
  0.96586207  31551.84  0.5139457  13052.42
  1.00000000  31552.12  0.5139358  13056.25

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was fraction = 0.04413793.
knn
k-Nearest Neighbors 

4152 samples
  21 predictors

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 3737, 3737, 3736, 3737, 3737, 3736, ... 
Resampling results across tuning parameters:

  k   RMSE      Rsquared   MAE      
   5  30690.77  0.5414005  10005.869
   6  29957.05  0.5578997   9764.648
   7  29647.07  0.5667090   9565.662
   8  29332.98  0.5740823   9451.566
   9  29105.54  0.5806458   9369.017
  10  29020.98  0.5829502   9338.637
  11  28992.60  0.5840708   9323.506
  12  29012.90  0.5842446   9346.578
  13  29153.57  0.5808812   9396.547
  14  29265.26  0.5781717   9450.271
  15  29355.69  0.5763039   9475.520
  16  29468.85  0.5733570   9507.781
  17  29609.94  0.5701898   9558.753
  18  29612.63  0.5708761   9577.454
  19  29758.52  0.5672583   9624.907
  20  29908.37  0.5640371   9666.899
  21  30026.40  0.5613456   9693.138
  22  30173.44  0.5584159   9746.040
  23  30324.52  0.5544399   9789.161
  24  30420.51  0.5532902   9836.902
  25  30560.95  0.5502751   9899.022

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was k = 11.

O modelo que apresentou menor RMSE foi o KNN com 28992.60, seguido de Lasso (31507.49) e Ridge (31569.86). Também é interessante observar que considerando a magnetude do RMSE a diferença entre os modelos é miníma.

Quais as variáveis mais importantes segundo o modelo de regressão Ridge e Lasso? Variáveis foram descartadas pelo Lasso? Quais?

ggplot(varImp(ridge)) +
theme(axis.title.y=element_blank()) +
ggtitle("Ridge - Variável X Importância")

ggplot(varImp(lasso)) +
theme(axis.title.y=element_blank()) +
ggtitle("Lasso - Variável X Importância")

Tanto Ridge como Lasso apresentam as mesmas variáveis como as mais importantes( total_receita, total_despesa e recusrsos_de_pessoas_juridicas). O Modelo Lasso não descartou nenhuma variável mas é possível perceber que variáveis como recursos_proprios e UF praticamente não tem importância.

Re-treine o melhor modelo (usando os melhores valores de parâmetros encontrados em todos os dados, sem usar validação cruzada).

Como visto anteriormente o modelo com menor RMSE foi o KNN. Para re-treinar o modelo o 10-fold foi mantido e número de vizinhos fixado no melhor valor encontrado 11. Como método de validação do modelo foi utilizado o boot.

#definindo um novo método para validação do modelo
fitControl <- trainControl(method = "boot" , number = 10)
#fixando número de vizinhos
visinhos <- expand.grid(k = seq(11, 11, length=1))
#re-treino do modelo KNN
knn <- train(votos ~.,data = dados, 
                  method='knn', 
                  metric="RMSE",
                  tuneGrid = vizinhos)

Use esse último modelo treinado para prever os dados de teste que disponibilizaremos por meio da plataforma Kaggle.

teste <- read.csv("../dados/test.csv", encoding="UTF-8")

teste$recursos_de_outros_candidatos.comites[is.na(teste$recursos_de_outros_candidatos.comites)]<-median (teste$recursos_de_outros_candidatos.comites, na.rm = TRUE)

teste$recursos_de_partidos[is.na(teste$recursos_de_partidos)]<-median (teste$recursos_de_partidos, na.rm = TRUE)

teste$recursos_de_pessoas_físicas[is.na(teste$recursos_de_pessoas_físicas)]<-median (teste$recursos_de_pessoas_físicas, na.rm = TRUE)

teste$recursos_de_pessoas_juridicas[is.na(teste$recursos_de_pessoas_juridicas)]<-median (teste$recursos_de_pessoas_juridicas, na.rm = TRUE)

teste$recursos_proprios[is.na(teste$recursos_proprios)]<-median (teste$recursos_proprios, na.rm = TRUE)

submissao <- read.csv("../dados/sample_submission.csv")
teste <- teste %>% select(-nome, -cargo, -setor_economico_receita, -setor_economico_despesa)

submission_predict <- predict(knn, teste)

for(i in 1:length(submission_predict)){
  print(submission_predict[i])
  submissao$votos[i] = abs(submission_predict[i])
}

write.csv(submissao, file = "../dados/submissao.csv", row.names = FALSE)
LS0tCnRpdGxlOiAiUHJlZGnDp8OjbyBkZSBWb3Rhw6fDo28gZGUgRGVwdXRhZG9zIgphdXRob3I6ICJEaW9nbyBGbG9yw6puY2lvIgpkYXRlOiAiMTMgZGUgbm92ZW1icm8gZGUgMjAxNyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogcmVhZGFibGUgCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgZmlnX3dpZHRoOiA1CiAgICBmaWdfaGVpZ2h0OiA0CmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KHJlc2hhcGUyKQpvcHRpb25zKHNjaXBlbiA9IDQpCmRhZG9zIDwtIHJlYWQuY3N2KCIuLi9kYWRvcy90cmFpbi5jc3YiLCBlbmNvZGluZyA9ICJVVEYtOCIpCmBgYAoKQW5hbGlzYW5kbyBvcyBkYWRvcyDDqSBwb3Nzw612ZWwgcGVyY2ViZXIgcXVlIGV4aXN0ZSB1bSBncmFuZGUgbsO6bWVybyBkZSBgTkEnU2AoYXVzw6puY2lhIGRlIGRhZG9zKSBuYXMgY29sdW5hcyByZWZlcmVudGVzIGFzIHZhcmnDoXZlaXMgYHJlY3Vyc29zX2RlX291dHJvc19jYW5kaWRhdG9zLmNvbWl0ZXNgLCBgcmVjdXJzb3NfZGVfcGFydGlkb3NgLCBgcmVjdXJzb3NfZGVfcGVzc29hc19mw61zaWNhc2AsIGByZWN1cnNvc19kZV9wZXNzb2FzX2p1cmlkaWNhc2AgZSBgcmVjdXJzb3NfcHJvcHJpb3NgLiBBZmltIGRlIHNvbHVjaW9uYXIgZXN0ZSBwcm9ibGVtYSwgc3Vic3RpdHVpIGVzc2VzIHZhbG9yZXMgcGVsYSBtZWRpYW5hIGRlIGNhZGEgdmFyacOhdmVsLiAKCmBgYHtyfQojc3Vic3RpdHVpbmRvIG9zIHZhbG9yZXMgTkEgcGVsYSBtZWRpYW5hIGRhcyBzdWFzIHJlc3BlY3RpdmFzIGNvbHVuYXMKZGFkb3MkcmVjdXJzb3NfZGVfb3V0cm9zX2NhbmRpZGF0b3MuY29taXRlc1tpcy5uYShkYWRvcyRyZWN1cnNvc19kZV9vdXRyb3NfY2FuZGlkYXRvcy5jb21pdGVzKV08LW1lZGlhbiAoZGFkb3MkcmVjdXJzb3NfZGVfb3V0cm9zX2NhbmRpZGF0b3MuY29taXRlcywgbmEucm0gPSBUUlVFKQoKZGFkb3MkcmVjdXJzb3NfZGVfcGFydGlkb3NbaXMubmEoZGFkb3MkcmVjdXJzb3NfZGVfcGFydGlkb3MpXTwtbWVkaWFuIChkYWRvcyRyZWN1cnNvc19kZV9wYXJ0aWRvcywgbmEucm0gPSBUUlVFKQoKZGFkb3MkcmVjdXJzb3NfZGVfcGVzc29hc19mw61zaWNhc1tpcy5uYShkYWRvcyRyZWN1cnNvc19kZV9wZXNzb2FzX2bDrXNpY2FzKV08LW1lZGlhbiAoZGFkb3MkcmVjdXJzb3NfZGVfcGVzc29hc19mw61zaWNhcywgbmEucm0gPSBUUlVFKQoKZGFkb3MkcmVjdXJzb3NfZGVfcGVzc29hc19qdXJpZGljYXNbaXMubmEoZGFkb3MkcmVjdXJzb3NfZGVfcGVzc29hc19qdXJpZGljYXMpXTwtbWVkaWFuIChkYWRvcyRyZWN1cnNvc19kZV9wZXNzb2FzX2p1cmlkaWNhcywgbmEucm0gPSBUUlVFKQoKZGFkb3MkcmVjdXJzb3NfcHJvcHJpb3NbaXMubmEoZGFkb3MkcmVjdXJzb3NfcHJvcHJpb3MpXTwtbWVkaWFuIChkYWRvcyRyZWN1cnNvc19wcm9wcmlvcywgbmEucm0gPSBUUlVFKQpgYGAKCkFsZ3VtYXMgdmFyacOhdmVpcyBxdWUgY2F1c2F2YW0gcHJvYmxlbWFzIGFvIGdlcmFyIG8gbW9kZWxvIGRlIHJlZ3Jlc3PDo28gb3UgY29tIG11aXRvcyB2YWxvcmVzIGAjTlVMT2AsIGNvbW8gYHNldG9yX2Vjb25vbWljb19yZWNlaXRhYCwgIGZvcmFtIHJlbW92aWRhcyBhIGZpbSBkZSB0cmF6ZXIgbWFpcyBjbGFyZXphIGFvcyBtb2RlbG9zIGRlIHJlZ3Jlc3PDo28uCgpgYGB7cn0KI3JlbW92ZW5kbyB2YXJpw6F2ZWlzCmRhZG9zIDwtIGRhZG9zICU+JSBzZWxlY3QoLW5vbWUsIC1jYXJnbywgLXNldG9yX2Vjb25vbWljb19yZWNlaXRhLCAtc2V0b3JfZWNvbm9taWNvX2Rlc3Blc2EpCmBgYAoKIyMjVXNhbmRvIHRvZGFzIGFzIHZhcmnDoXZlaXMgZGlzcG9uw612ZWlzLCB0dW5lICh1c2FuZG8gdmFsaWRhw6fDo28gY3J1emFkYSk6IAogICogKiooaSkgdW0gbW9kZWxvIGRlIHJlZ3Jlc3PDo28gUmlkZ2UsKiogCiAgKiAqKihpaSkgdW0gbW9kZWxvIGRlIHJlZ3Jlc3PDo28gTGFzc28gZSoqIAogICogKiooaWlpKSB1bSBtb2RlbG8gS05OLiBQYXJhIG9zIG1vZGVsb3MgZGUgcmVncmVzc8OjbyBsaW5lYXIuKioKICAKKipPIHBhcsOibWV0cm8gYSBzZXIgdHVuYWRvIMOpIG8gbGFtYmRhIChwZW5hbGl6YcOnw6NvIGRvcyBjb2VmaWNpZW50ZXMpIGUgbyBLTk4gbyBuw7ptZXJvIGRlIHZpemluaG9zLioqCgoqKk1vZGVsbyBkZSBSZWdyZXNzw6NvIFJpZGdlKioKT3MgZGFkb3MgY29uc2lzdGVtIGVtIDQxNTIgb2JzZXJ2YcOnw7VlcywgbyBtb2RlbG8gZGUgcmVncmVzc8OjbyBmb2kgZ2VyYWRvIGNvbnNpZGVyYW5kbyAxMC1mb2xkIGUgMzAgdmFsb3JlcyBkaXN0aW50b3MgcGFyYSBsYW1iZGEgZW50cmUgbyBpbnRlcnZhbG8gWzEwXjI7MTBeLTEwXS4KCmBgYHtyfQpmaXRDb250cm9sIDwtIHRyYWluQ29udHJvbChtZXRob2Q9J2N2JywgbnVtYmVyID0gMTApCgojIHZhcmlhw6fDo28gZG8gbGFtYmRhCmxhbWJkYSA8LSBleHBhbmQuZ3JpZChsYW1iZGEgPSAxMF5zZXEoMiwgLTEwLCBsZW5ndGg9MzApKQoKI21vZGVsbyBkZSByZWdyZXNzw6NvIFJpZGdlCnJpZGdlIDwtIHRyYWluKHZvdG9zIH4uLGRhdGEgPSBkYWRvcywgCiAgICAgICAgICAgICAgICAgIG1ldGhvZD0ncmlkZ2UnLCAKICAgICAgICAgICAgICAgICAgbWV0cmljPSJSTVNFIiwKICAgICAgICAgICAgICAgICAgdHVuZUdyaWQgPSBsYW1iZGEsCiAgICAgICAgICAgICAgICAgIHRyQ29udHJvbD1maXRDb250cm9sKQpwbG90KHJpZGdlKQpgYGAKTyB2YWxvciBsYW1iZGEgPSAwLjA0ODkzOTAxIGdlcm91IG8gbWVub3IgUk1TRS4KCioqTW9kZWxvIGRlIFJlZ3Jlc3PDo28gTGFzc28qKgpObyBtb2RlbG8gZGUgcmVncmVzc8OjbyBMYXNzbyB0YW1iw6ltIGZvaSB1dGlsaXphZG8gMTAtZm9sZCBlIG8gcGFyYW1ldHJvIGRlIHZhcmlhw6fDo28gZG8gZnJhY3Rpb24gZGVmaW5pZG8gY29tbyAzMCB2YWxvcmVzIG5vIGludGVydmFsbyBbMC4wMDE7IDFdLgoKYGBge3J9CiMgdmFyaWHDp8OjbyBkbyBmcmFjdGlvbgpmcmFjdGlvbiA8LSBleHBhbmQuZ3JpZChmcmFjdGlvbiA9IHNlcSgwLjAxLCAxLCBsZW5ndGggPSAzMCkpCgojbW9kZWxvIGRlIHJlZ3Jlc3PDo28gTGFzc28KbGFzc28gPC0gdHJhaW4odm90b3Mgfi4sZGF0YSA9IGRhZG9zLCAKICAgICAgICAgICAgICAgICAgbWV0aG9kPSdsYXNzbycsIAogICAgICAgICAgICAgICAgICBtZXRyaWM9IlJNU0UiLAogICAgICAgICAgICAgICAgICB0dW5lR3JpZCA9IGZyYWN0aW9uLAogICAgICAgICAgICAgICAgICB0ckNvbnRyb2w9Zml0Q29udHJvbCkKcGxvdChsYXNzbykKYGBgCk8gZnJhY3Rpb24gPSAwLjA0NDEzNzkzIGdlcm91IG8gbWVub3IgUk1TRSBvYnNlcnZhZG8uIAoKKipNb2RlbG8gZGUgUmVncmVzc8OjbyBLTk4qKgpQYXJhIG8gbW9kZWxvIGRlIHJlZ3Jlc3PDo28gS05OIGZvaSBtYW50aWRvIG8gcGFkcsOjbyAxMC1mb2xkIG8gcGFyYW1ldHJvIHJlZmVyZW50ZSBhbyBuw7ptZXJvIGRlIHZpemluaG9zIGZvaSBkZWZpbmlkbyBjb21vIDIwIHZhbG9yZXMgbm8gaW50ZXJ2YWxvWzU7MjVdLgoKYGBge3J9CiMgdmFyaWHDp8OjbyBkZSB2aXppbmhvcwp2aXppbmhvcyA8LSBleHBhbmQuZ3JpZChrID0gc2VxKDUsIDI1KSkKCiNtb2RlbG8gZGUgcmVncmVzc8OjbyBLTk4Ka25uIDwtIHRyYWluKHZvdG9zIH4uLGRhdGEgPSBkYWRvcywgCiAgICAgICAgICAgICAgICAgIG1ldGhvZD0na25uJywgCiAgICAgICAgICAgICAgICAgIG1ldHJpYz0iUk1TRSIsCiAgICAgICAgICAgICAgICAgIHR1bmVHcmlkID0gdml6aW5ob3MsCiAgICAgICAgICAgICAgICAgIHRyQ29udHJvbD1maXRDb250cm9sKQpwbG90KGtubikKYGBgCk8gbWVub3IgUk1TRSBmb2kgb2JzZXJ2YWRvIGFvIHNlIGNvbnNpZGVyYXIgMTEgdml6aW5ob3MuCgojIyNDb21wYXJlIG9zIHRyw6pzIG1vZGVsb3MgZW0gdGVybW9zIGRvIGVycm8gUk1TRSBkZSB2YWxpZGHDp8OjbyBjcnV6YWRhLgoKVG9kb3Mgb3MgbW9kZWxvcyBlbSBxdWVzdMOjbyBjb25zaWRlcmVyYW0gdW0gay1mb2xkID0gMTAuCmBgYHtyfQpyaWRnZQpsYXNzbwprbm4KYGBgCk8gbW9kZWxvIHF1ZSBhcHJlc2VudG91IG1lbm9yIFJNU0UgZm9pIG8gS05OIGNvbSAyODk5Mi42MCwgc2VndWlkbyBkZSBMYXNzbyAoMzE1MDcuNDkpIGUgUmlkZ2UgKDMxNTY5Ljg2KS4gVGFtYsOpbSDDqSBpbnRlcmVzc2FudGUgb2JzZXJ2YXIgcXVlIGNvbnNpZGVyYW5kbyBhIG1hZ25ldHVkZSBkbyBSTVNFIGEgZGlmZXJlbsOnYSBlbnRyZSBvcyBtb2RlbG9zIMOpIG1pbsOtbWEuCgojIyNRdWFpcyBhcyB2YXJpw6F2ZWlzIG1haXMgaW1wb3J0YW50ZXMgc2VndW5kbyBvIG1vZGVsbyBkZSByZWdyZXNzw6NvIFJpZGdlIGUgTGFzc28/ICBWYXJpw6F2ZWlzIGZvcmFtIGRlc2NhcnRhZGFzIHBlbG8gTGFzc28/IFF1YWlzPwoKYGBge3J9CmdncGxvdCh2YXJJbXAocmlkZ2UpKSArCnRoZW1lKGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCkpICsKZ2d0aXRsZSgiUmlkZ2UgLSBWYXJpw6F2ZWwgWCBJbXBvcnTDom5jaWEiKQpgYGAKCgpgYGB7cn0KZ2dwbG90KHZhckltcChsYXNzbykpICsKdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSkgKwpnZ3RpdGxlKCJMYXNzbyAtIFZhcmnDoXZlbCBYIEltcG9ydMOibmNpYSIpCmBgYApUYW50byBSaWRnZSBjb21vIExhc3NvIGFwcmVzZW50YW0gYXMgbWVzbWFzIHZhcmnDoXZlaXMgY29tbyBhcyBtYWlzIGltcG9ydGFudGVzKCBgdG90YWxfcmVjZWl0YWAsIGB0b3RhbF9kZXNwZXNhYCBlIGByZWN1c3Jzb3NfZGVfcGVzc29hc19qdXJpZGljYXNgKS4gTyBNb2RlbG8gTGFzc28gbsOjbyBkZXNjYXJ0b3UgbmVuaHVtYSB2YXJpw6F2ZWwgbWFzIMOpIHBvc3PDrXZlbCBwZXJjZWJlciBxdWUgdmFyacOhdmVpcyBjb21vIGByZWN1cnNvc19wcm9wcmlvc2AgZSBgVUZgIHByYXRpY2FtZW50ZSBuw6NvIHRlbSBpbXBvcnTDom5jaWEuCgojIyNSZS10cmVpbmUgbyBtZWxob3IgbW9kZWxvICh1c2FuZG8gb3MgbWVsaG9yZXMgdmFsb3JlcyBkZSBwYXLDom1ldHJvcyBlbmNvbnRyYWRvcyBlbSB0b2RvcyBvcyBkYWRvcywgc2VtIHVzYXIgdmFsaWRhw6fDo28gY3J1emFkYSkuCgpDb21vIHZpc3RvIGFudGVyaW9ybWVudGUgbyBtb2RlbG8gY29tIG1lbm9yIFJNU0UgZm9pIG8gS05OLiBQYXJhIHJlLXRyZWluYXIgbyBtb2RlbG8gbyAxMC1mb2xkIGZvaSBtYW50aWRvIGUgbsO6bWVybyBkZSB2aXppbmhvcyBmaXhhZG8gbm8gbWVsaG9yIHZhbG9yIGVuY29udHJhZG8gYDExYC4gQ29tbyBtw6l0b2RvIGRlIHZhbGlkYcOnw6NvIGRvIG1vZGVsbyBmb2kgdXRpbGl6YWRvIG8gYGJvb3RgLgoKYGBge3J9CiNkZWZpbmluZG8gdW0gbm92byBtw6l0b2RvIHBhcmEgdmFsaWRhw6fDo28gZG8gbW9kZWxvCmZpdENvbnRyb2wgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJib290IiAsIG51bWJlciA9IDEwKQoKI2ZpeGFuZG8gbsO6bWVybyBkZSB2aXppbmhvcwp2aXNpbmhvcyA8LSBleHBhbmQuZ3JpZChrID0gc2VxKDExLCAxMSwgbGVuZ3RoPTEpKQoKI3JlLXRyZWlubyBkbyBtb2RlbG8gS05OCmtubiA8LSB0cmFpbih2b3RvcyB+LixkYXRhID0gZGFkb3MsIAogICAgICAgICAgICAgICAgICBtZXRob2Q9J2tubicsIAogICAgICAgICAgICAgICAgICBtZXRyaWM9IlJNU0UiLAogICAgICAgICAgICAgICAgICB0dW5lR3JpZCA9IHZpemluaG9zKQpgYGAKCiMjI1VzZSBlc3NlIMO6bHRpbW8gbW9kZWxvIHRyZWluYWRvIHBhcmEgcHJldmVyIG9zIGRhZG9zIGRlIHRlc3RlIHF1ZSBkaXNwb25pYmlsaXphcmVtb3MgcG9yIG1laW8gZGEgcGxhdGFmb3JtYSBLYWdnbGUuCgpgYGB7cn0KdGVzdGUgPC0gcmVhZC5jc3YoIi4uL2RhZG9zL3Rlc3QuY3N2IiwgZW5jb2Rpbmc9IlVURi04IikKCnRlc3RlJHJlY3Vyc29zX2RlX291dHJvc19jYW5kaWRhdG9zLmNvbWl0ZXNbaXMubmEodGVzdGUkcmVjdXJzb3NfZGVfb3V0cm9zX2NhbmRpZGF0b3MuY29taXRlcyldPC1tZWRpYW4gKHRlc3RlJHJlY3Vyc29zX2RlX291dHJvc19jYW5kaWRhdG9zLmNvbWl0ZXMsIG5hLnJtID0gVFJVRSkKCnRlc3RlJHJlY3Vyc29zX2RlX3BhcnRpZG9zW2lzLm5hKHRlc3RlJHJlY3Vyc29zX2RlX3BhcnRpZG9zKV08LW1lZGlhbiAodGVzdGUkcmVjdXJzb3NfZGVfcGFydGlkb3MsIG5hLnJtID0gVFJVRSkKCnRlc3RlJHJlY3Vyc29zX2RlX3Blc3NvYXNfZsOtc2ljYXNbaXMubmEodGVzdGUkcmVjdXJzb3NfZGVfcGVzc29hc19mw61zaWNhcyldPC1tZWRpYW4gKHRlc3RlJHJlY3Vyc29zX2RlX3Blc3NvYXNfZsOtc2ljYXMsIG5hLnJtID0gVFJVRSkKCnRlc3RlJHJlY3Vyc29zX2RlX3Blc3NvYXNfanVyaWRpY2FzW2lzLm5hKHRlc3RlJHJlY3Vyc29zX2RlX3Blc3NvYXNfanVyaWRpY2FzKV08LW1lZGlhbiAodGVzdGUkcmVjdXJzb3NfZGVfcGVzc29hc19qdXJpZGljYXMsIG5hLnJtID0gVFJVRSkKCnRlc3RlJHJlY3Vyc29zX3Byb3ByaW9zW2lzLm5hKHRlc3RlJHJlY3Vyc29zX3Byb3ByaW9zKV08LW1lZGlhbiAodGVzdGUkcmVjdXJzb3NfcHJvcHJpb3MsIG5hLnJtID0gVFJVRSkKCnN1Ym1pc3NhbyA8LSByZWFkLmNzdigiLi4vZGFkb3Mvc2FtcGxlX3N1Ym1pc3Npb24uY3N2IikKdGVzdGUgPC0gdGVzdGUgJT4lIHNlbGVjdCgtbm9tZSwgLWNhcmdvLCAtc2V0b3JfZWNvbm9taWNvX3JlY2VpdGEsIC1zZXRvcl9lY29ub21pY29fZGVzcGVzYSkKCnN1Ym1pc3Npb25fcHJlZGljdCA8LSBwcmVkaWN0KGtubiwgdGVzdGUpCgpmb3IoaSBpbiAxOmxlbmd0aChzdWJtaXNzaW9uX3ByZWRpY3QpKXsKICBwcmludChzdWJtaXNzaW9uX3ByZWRpY3RbaV0pCiAgc3VibWlzc2FvJHZvdG9zW2ldID0gYWJzKHN1Ym1pc3Npb25fcHJlZGljdFtpXSkKfQoKd3JpdGUuY3N2KHN1Ym1pc3NhbywgZmlsZSA9ICIuLi9kYWRvcy9zdWJtaXNzYW8uY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAo=