Primero, importamos todas las librerías que vamos a usar a lo largo de la realización de este proyecto:

if (!require('RColorBrewer')) install.packages('RColorBrewer')
if (!require('corrplot')) install.packages('corrplot')
if (!require('GGally')) install.packages('GGally')
if (!require('moments')) install.packages('moments')
if (!require('fitdistrplus')) install.packages('fitdistrplus')
if (!require('tidyverse')) install.packages('tidyverse')
if (!require('psych')) install.packages('psych')
if (!require('nortest')) install.packages('nortest')
library('RColorBrewer')
library('corrplot')
library('GGally')
library('moments')
library('fitdistrplus')
library('tidyverse')
library('dplyr')
library('tidyselect')
Aviso: package ‘tidyselect’ was built under R version 4.4.3
library('psych')
library('nortest')

Luego, importamos la base de datos como un dataframe, cabe aclarar que revisamos la clase del dataframe. Esto nos ayudará a verificar que la base se haya cargado correctamente, porque en caso de no haberse cargado, aparecerá como “function”:

datos_u <- data

class(datos_u)
[1] "tbl_df"     "tbl"        "data.frame"

Inicialmente hacemos el análisis de variables categóricas, para ello crearemos una variable aparte y ajustaremos sus tipos de datos:

base_cate <- datos_u %>%
  dplyr::select(-`Previous qualification (grade)`,
                -`Mother's qualification`,
                -`Father's qualification`,
                -`Mother's occupation`,
                -`Father's occupation`,
                -`Admission grade`,
                -`Age at enrollment`,
                -`Curricular units 1st sem (credited)`,
                -`Curricular units 1st sem (enrolled)`,
                -`Curricular units 1st sem (evaluations)`,
                -`Curricular units 1st sem (approved)`,
                -`Curricular units 1st sem (grade)`,
                -`Curricular units 1st sem (without evaluations)`,
                -`Curricular units 2nd sem (credited)`,
                -`Curricular units 2nd sem (enrolled)`,
                -`Curricular units 2nd sem (evaluations)`,
                -`Curricular units 2nd sem (approved)`,
                -`Curricular units 2nd sem (grade)`,
                -`Curricular units 2nd sem (without evaluations)`,
                -`Unemployment rate`,
                -`Inflation rate`,
                -`GDP`) %>%
  glimpse()
Rows: 4,424
Columns: 15
$ `Marital status`             <dbl> 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ `Application mode`           <dbl> 17, 15, 1, 17, 39, 39, 1, 18, 1, 1, 1, 1, 1, 53, …
$ `Application order`          <dbl> 5, 1, 5, 2, 1, 1, 1, 4, 3, 1, 1, 1, 2, 1, 1, 1, 1…
$ Course                       <dbl> 171, 9254, 9070, 9773, 8014, 9991, 9500, 9254, 92…
$ `Daytime/evening attendance` <dbl> 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1…
$ `Previous qualification`     <dbl> 1, 1, 1, 1, 1, 19, 1, 1, 1, 1, 1, 1, 1, 42, 1, 1,…
$ Nacionality                  <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 1, 1, 1, 1, 1, 1, …
$ Displaced                    <dbl> 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1…
$ `Educational special needs`  <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ Debtor                       <dbl> 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0…
$ `Tuition fees up to date`    <dbl> 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1…
$ Gender                       <dbl> 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0…
$ `Scholarship holder`         <dbl> 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0…
$ International                <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0…
$ Target                       <chr> "Dropout", "Graduate", "Dropout", "Graduate", "Gr…
# Análisis Descriptivo: ----

# Univariadas: ----

base_cate <- base_cate %>% 
  mutate(across(c(`Application mode`,
                  `Application order`,
                  `Course`,
                  `Daytime/evening attendance`,
                  `Previous qualification`,
                  `Nacionality`,
                  `Displaced`,
                  `Educational special needs`,
                  `Debtor`,
                  `Tuition fees up to date`,
                  `Gender`,
                  `Scholarship holder`,
                  `International`,
                  `Marital status`,
                  `Target`), as.factor))

Construimos las tablas de frecuencia y sus respectivas gráficas. Para esto usaremos las siguientes funciones:

tabla_frec <- function(columna) {
  tabla <- table(base_cate[[columna]])
  return(prop.table(tabla))
}

grafica <- function(columna){
  base_cate %>%
    ggplot(aes(x = .data[[columna]])) +
    geom_bar(color = "black", fill = "purple") +
    ggtitle(paste("Diagrama de barras de", columna)) +
    labs(x = columna, y = "Frecuencia") +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 30, size = 8))
}


tabla_grafica <- function(columna){
  print(tabla_frec(columna))
  grafica(columna)
}

Ejecutamos cada uno de los análisis que se obtuvieron desde las gráficas:

tabla_grafica("Marital status")

           1            2            3            4            5            6 
0.8858499096 0.0856690778 0.0009041591 0.0205696203 0.0056509946 0.0013562387 

cat("Podemos notar que el 88.5849% de los estudiantes son solteros y tambien que 
    el 8.5669% son casados.\n")
Podemos notar que el 88.5849% de los estudiantes son solteros y tambien que 
    el 8.5669% son casados.
tabla_grafica("Course")

         33         171        8014        9003        9070        9085        9119 
0.002712477 0.048598553 0.048598553 0.047468354 0.051084991 0.076175407 0.038426763 
       9130        9147        9238        9254        9500        9556        9670 
0.031871609 0.085895118 0.080244123 0.056962025 0.173146474 0.019439421 0.060578662 
       9773        9853        9991 
0.074819168 0.043399638 0.060578662 

cat("El curso con más porcentaje de inscripción es el 9500, el cual es
    Enfermería, mientras que el que tiene menos, es el curso 33, el cual
    Tecnologías de Producción de Biocombustibles.\n")
El curso con más porcentaje de inscripción es el 9500, el cual es
    Enfermería, mientras que el que tiene menos, es el curso 33, el cual
    Tecnologías de Producción de Biocombustibles.
tabla_grafica("Daytime/evening attendance")

        0         1 
0.1091772 0.8908228 

cat("El 89.0822% de los estudiantes estudia de día, mientras que el 10.9177% de 
    noche.\n")
El 89.0822% de los estudiantes estudia de día, mientras que el 10.9177% de 
    noche.
tabla_grafica("Previous qualification")

           1            2            3            4            5            6 
0.8401898734 0.0051989150 0.0284810127 0.0018083183 0.0002260398 0.0036166365 
           9           10           12           14           15           19 
0.0024864376 0.0009041591 0.0101717902 0.0002260398 0.0004520796 0.0366184448 
          38           39           40           42           43 
0.0015822785 0.0495027125 0.0090415913 0.0081374322 0.0013562387 

cat("El último título del 84.0189% de los estudiantes es la Escuela Secundaria, 
    mientras que el del 28.4810% es de Educación Superior.\n")
El último título del 84.0189% de los estudiantes es la Escuela Secundaria, 
    mientras que el del 28.4810% es de Educación Superior.
tabla_grafica("Nacionality")

           1            2            6           11           13           14 
0.9751356239 0.0004520796 0.0029385172 0.0006781193 0.0002260398 0.0002260398 
          17           21           22           24           25           26 
0.0002260398 0.0004520796 0.0029385172 0.0011301989 0.0004520796 0.0031645570 
          32           41           62          100          101          103 
0.0002260398 0.0085895118 0.0004520796 0.0006781193 0.0004520796 0.0006781193 
         105          108          109 
0.0004520796 0.0002260398 0.0002260398 

cat("El 97.5135% de los estudiantes es de Portugal, mientras que el porcentaje 
    de estudiantes colombianos es de 0,0226% :( \n")
El 97.5135% de los estudiantes es de Portugal, mientras que el porcentaje 
    de estudiantes colombianos es de 0,0226% :( 
tabla_grafica("Displaced")

        0         1 
0.4516275 0.5483725 

cat("El 54.8372% de los estudiantes son desplazados, lo cual llega ser un 
    porcentaje alto.\n")
El 54.8372% de los estudiantes son desplazados, lo cual llega ser un 
    porcentaje alto.
tabla_grafica("Debtor")

       0        1 
0.886302 0.113698 

cat("Análisis")
Análisis
tabla_grafica("Tuition fees up to date")

       0        1 
0.119349 0.880651 

cat("El 88.0651% de los estudiantes tienen su matrícula al día.\n")
El 88.0651% de los estudiantes tienen su matrícula al día.
tabla_grafica("Gender")

        0         1 
0.6482821 0.3517179 

cat("Podemos evidenciar que el porcentaje de mujeres con respecto a hombres es 
    más alto, esto con un 64.8282% de estudiantes mujeres y un 35.1717% de 
    estudiantes hombres.\n")
Podemos evidenciar que el porcentaje de mujeres con respecto a hombres es 
    más alto, esto con un 64.8282% de estudiantes mujeres y un 35.1717% de 
    estudiantes hombres.
tabla_grafica("Scholarship holder")

        0         1 
0.7515823 0.2484177 

cat("Logramos evidenciar que el porcentaje de estudiantes becados es muy bajo,
    siendo sólo el 24.8417% estudiantes becados, mientras que el 75.1582% no son
    becados.\n")
Logramos evidenciar que el porcentaje de estudiantes becados es muy bajo,
    siendo sólo el 24.8417% estudiantes becados, mientras que el 75.1582% no son
    becados.
tabla_grafica("International")

         0          1 
0.97513562 0.02486438 

cat("Análisis")
Análisis
tabla_grafica("Target")

  Dropout  Enrolled  Graduate 
0.3212025 0.1794756 0.4993219 

cat("El porcentaje de los estudiantes que se gradúan es el 49.9321%, mientras que
    los que no logran graduarse es el 32.1202%.\n")
El porcentaje de los estudiantes que se gradúan es el 49.9321%, mientras que
    los que no logran graduarse es el 32.1202%.
tabla_grafica("Educational special needs")

         0          1 
0.98847197 0.01152803 

cat("EL porcentaje de estudiantes que necesitan Educación Especial es muy bajo,
    con un 1.1528% de estudiantes.\n")
EL porcentaje de estudiantes que necesitan Educación Especial es muy bajo,
    con un 1.1528% de estudiantes.

Ahora, haremos el análisis bivariado para cada una de las variables relevantes con respecto a Target(Estado del estudiante: Graduate, Dropout, Enrolled):

# Tablas de frecuencia y gráficos bivariados:---------

tabladoble <- function(columna1,columna2){
  tabla2 <- table(base_cate[[columna1]],base_cate[[columna2]])
  return(round(prop.table(tabla2),4))
}

# graficadoble <- function(columna1,columna2){
#   grafica <- ggplot(base_cate,
#              aes(x=base_cate[[columna1]],fill=base_cate[[columna2]]))+
#              geom_bar()+theme_minimal()+
#              theme(axis.text.x=element_text(angle=30,size=8))
#     return(grafica)
# }

grafico_apilado <- function(variable1,variable2){
  barras_target <- ggplot(base_cate, aes(x = .data[[variable1]], fill = .data[[variable2]])) + 
    geom_bar(position="fill")+ theme_minimal()+
    theme(axis.text.x = element_text(angle=30, size=8))
  return(barras_target)
}

TGO <- function(columna1,columna2){
  print(tabladoble(columna1,columna2))
  grafico_apilado(columna1,columna2)
}
TGO("Target","Nacionality")
          
                1      2      6     11     13     14     17     21     22     24     25
  Dropout  0.3140 0.0000 0.0009 0.0000 0.0000 0.0000 0.0002 0.0002 0.0009 0.0002 0.0000
  Enrolled 0.1741 0.0000 0.0011 0.0000 0.0000 0.0000 0.0000 0.0002 0.0002 0.0000 0.0002
  Graduate 0.4871 0.0005 0.0009 0.0007 0.0002 0.0002 0.0000 0.0000 0.0018 0.0009 0.0002
          
               26     32     41     62    100    101    103    105    108    109
  Dropout  0.0002 0.0000 0.0032 0.0000 0.0005 0.0002 0.0002 0.0002 0.0000 0.0002
  Enrolled 0.0011 0.0002 0.0014 0.0002 0.0002 0.0000 0.0000 0.0002 0.0002 0.0000
  Graduate 0.0018 0.0000 0.0041 0.0002 0.0000 0.0002 0.0005 0.0000 0.0000 0.0000

cat("Los estudiantes con más porcentaje de graduación son de Portugal con el
    31.40%, entonces concuerda con que sea el país con más estudiantes. Ahora,
    sin considerar a Portugal, el país con más porcentaje de graduación es
    Brasil, con un 3.2% de graduados.\n")
Los estudiantes con más porcentaje de graduación son de Portugal con el
    31.40%, entonces concuerda con que sea el país con más estudiantes. Ahora,
    sin considerar a Portugal, el país con más porcentaje de graduación es
    Brasil, con un 3.2% de graduados.
TGO("Target","Educational special needs")
          
                0      1
  Dropout  0.3174 0.0038
  Enrolled 0.1770 0.0025
  Graduate 0.4941 0.0052

cat("Podemos observar que los estudiantes que necesitan Educación Especial tienen
    mayor porcentaje de deserción, con un 5.2%, mientras que su porcentaje de
    graduación es del 3.8%.\n")
Podemos observar que los estudiantes que necesitan Educación Especial tienen
    mayor porcentaje de deserción, con un 5.2%, mientras que su porcentaje de
    graduación es del 3.8%.
TGO("Target","Gender")
          
                0      1
  Dropout  0.1627 0.1585
  Enrolled 0.1101 0.0694
  Graduate 0.3755 0.1239

cat("El porcentaje de hombres que no se gradúan, con un 15.85%, es mayor al
    porcentaje de aquellos que se gradúan.\n")
El porcentaje de hombres que no se gradúan, con un 15.85%, es mayor al
    porcentaje de aquellos que se gradúan.
TGO("Target","Tuition fees up to date")
          
                0      1
  Dropout  0.1033 0.2179
  Enrolled 0.0095 0.1700
  Graduate 0.0066 0.4928

cat("Los estudiantes que no están al día con su pago y tienden a no graduarse, es
    del 10.33%.\n")
Los estudiantes que no están al día con su pago y tienden a no graduarse, es
    del 10.33%.
TGO("Target","Daytime/evening attendance")
          
                0      1
  Dropout  0.0468 0.2744
  Enrolled 0.0170 0.1625
  Graduate 0.0454 0.4539

cat("Al ser el porcentaje de personas que estudian en la noche, es mucho más bajo
    que aquellos que estudian de día, por lo tanto, no tiene mucho sentido
    compararlos, sin embargo, el porcentaje de estudiantes que estudian en la
    noche y se gradúan es levemente más pequeño que el porcentaje de aquellos que
    no se gradúan.Así, vemos que el 4.54% se gradua y el 4.68% no se gradua.\n")
Al ser el porcentaje de personas que estudian en la noche, es mucho más bajo
    que aquellos que estudian de día, por lo tanto, no tiene mucho sentido
    compararlos, sin embargo, el porcentaje de estudiantes que estudian en la
    noche y se gradúan es levemente más pequeño que el porcentaje de aquellos que
    no se gradúan.Así, vemos que el 4.54% se gradua y el 4.68% no se gradua.
TGO("Target","Scholarship holder")
          
                0      1
  Dropout  0.2909 0.0303
  Enrolled 0.1501 0.0294
  Graduate 0.3106 0.1887

cat("El porcentaje de estudiantes becados que se gradúan, es mayor que aquellos
    becados que no se gradúan. Esto con un 18.87% de becados graduados y un 3.03%
    de becados no graduados.\n")
El porcentaje de estudiantes becados que se gradúan, es mayor que aquellos
    becados que no se gradúan. Esto con un 18.87% de becados graduados y un 3.03%
    de becados no graduados.

Hacemos lo mismo para las variables cualitativas. Para analizar las variables cuantitativas del conjunto de datos, implementamos varias funciones que nos permiten conocer cómo se comportan:

base_cuant <- datos_u %>%
  dplyr::select(-`Marital status`,
                -`Application mode`,
                -`Application order`,
                -`Course`,
                -`Daytime/evening attendance`,
                -`Previous qualification`,
                -`Nacionality`,
                -`Displaced`,
                -`Educational special needs`,
                -`Debtor`,
                -`Tuition fees up to date`,
                -`Gender`,
                -`Scholarship holder`,
                -`International`,
                -`Target`) %>%
  glimpse()
Rows: 4,424
Columns: 22
$ `Previous qualification (grade)`                 <chr> "122.0", "160.0", "122.0", "1…
$ `Mother's qualification`                         <dbl> 19, 1, 37, 38, 37, 37, 19, 37…
$ `Father's qualification`                         <dbl> 12, 3, 37, 37, 38, 37, 38, 37…
$ `Mother's occupation`                            <dbl> 5, 3, 9, 5, 9, 9, 7, 9, 9, 4,…
$ `Father's occupation`                            <dbl> 9, 3, 9, 3, 9, 7, 10, 9, 9, 7…
$ `Admission grade`                                <chr> "127.3", "142.5", "124.8", "1…
$ `Age at enrollment`                              <dbl> 20, 19, 19, 20, 45, 50, 18, 2…
$ `Curricular units 1st sem (credited)`            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ `Curricular units 1st sem (enrolled)`            <dbl> 0, 6, 6, 6, 6, 5, 7, 5, 6, 6,…
$ `Curricular units 1st sem (evaluations)`         <dbl> 0, 6, 0, 8, 9, 10, 9, 5, 8, 9…
$ `Curricular units 1st sem (approved)`            <dbl> 0, 6, 0, 6, 5, 5, 7, 0, 6, 5,…
$ `Curricular units 1st sem (grade)`               <chr> "0.0", "14.0", "0.0", "1.3428…
$ `Curricular units 1st sem (without evaluations)` <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ `Curricular units 2nd sem (credited)`            <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,…
$ `Curricular units 2nd sem (enrolled)`            <dbl> 0, 6, 6, 6, 6, 5, 8, 5, 6, 6,…
$ `Curricular units 2nd sem (evaluations)`         <dbl> 0, 6, 0, 10, 6, 17, 8, 5, 7, …
$ `Curricular units 2nd sem (approved)`            <dbl> 0, 6, 0, 5, 6, 5, 8, 0, 6, 2,…
$ `Curricular units 2nd sem (grade)`               <chr> "0.0", "1.36666666666666E16",…
$ `Curricular units 2nd sem (without evaluations)` <dbl> 0, 0, 0, 0, 0, 5, 0, 0, 0, 0,…
$ `Unemployment rate`                              <dttm> 2025-08-10, 2025-09-13, 2025…
$ `Inflation rate`                                 <chr> "45748.0", "-0.3", "45748.0",…
$ GDP                                              <chr> "1.74", "0.79", "1.74", "-3.1…

Ahora, convertimos todas nuestras variables cuantitatias a tipo numeric, esto con el fin de poder las gráficas de los boxplot, histrogramas y pruebas de correlación, así mismo miramos que se hayan transformado:

base_cuant <- datos_u %>% dplyr::select(all_of(vars_cuant)) %>% dplyr::mutate(across(everything(),~as.numeric(.))) 
base_cuant %>% dim()
[1] 4424   22
sapply(base_cuant, class)
                Previous qualification (grade) 
                                     "numeric" 
                        Mother's qualification 
                                     "numeric" 
                        Father's qualification 
                                     "numeric" 
                           Mother's occupation 
                                     "numeric" 
                           Father's occupation 
                                     "numeric" 
                               Admission grade 
                                     "numeric" 
                             Age at enrollment 
                                     "numeric" 
           Curricular units 1st sem (credited) 
                                     "numeric" 
           Curricular units 1st sem (enrolled) 
                                     "numeric" 
        Curricular units 1st sem (evaluations) 
                                     "numeric" 
           Curricular units 1st sem (approved) 
                                     "numeric" 
              Curricular units 1st sem (grade) 
                                     "numeric" 
Curricular units 1st sem (without evaluations) 
                                     "numeric" 
           Curricular units 2nd sem (credited) 
                                     "numeric" 
           Curricular units 2nd sem (enrolled) 
                                     "numeric" 
        Curricular units 2nd sem (evaluations) 
                                     "numeric" 
           Curricular units 2nd sem (approved) 
                                     "numeric" 
              Curricular units 2nd sem (grade) 
                                     "numeric" 
Curricular units 2nd sem (without evaluations) 
                                     "numeric" 
                             Unemployment rate 
                                     "numeric" 
                                Inflation rate 
                                     "numeric" 
                                           GDP 
                                     "numeric" 
vars_cuant <- c(
  "Previous qualification (grade)",
  "Mother's qualification",
  "Father's qualification",
  "Mother's occupation",
  "Father's occupation",
  "Admission grade",
  "Age at enrollment",
  "Curricular units 1st sem (credited)",
  "Curricular units 1st sem (enrolled)",
  "Curricular units 1st sem (evaluations)",
  "Curricular units 1st sem (approved)",
  "Curricular units 1st sem (grade)",
  "Curricular units 1st sem (without evaluations)",
  "Curricular units 2nd sem (credited)",
  "Curricular units 2nd sem (enrolled)",
  "Curricular units 2nd sem (evaluations)",
  "Curricular units 2nd sem (approved)",
  "Curricular units 2nd sem (grade)",
  "Curricular units 2nd sem (without evaluations)",
  "Unemployment rate",
  "Inflation rate",
  "GDP"
)

sapply(base_cuant, class)
                Previous qualification (grade) 
                                     "numeric" 
                        Mother's qualification 
                                     "numeric" 
                        Father's qualification 
                                     "numeric" 
                           Mother's occupation 
                                     "numeric" 
                           Father's occupation 
                                     "numeric" 
                               Admission grade 
                                     "numeric" 
                             Age at enrollment 
                                     "numeric" 
           Curricular units 1st sem (credited) 
                                     "numeric" 
           Curricular units 1st sem (enrolled) 
                                     "numeric" 
        Curricular units 1st sem (evaluations) 
                                     "numeric" 
           Curricular units 1st sem (approved) 
                                     "numeric" 
              Curricular units 1st sem (grade) 
                                     "numeric" 
Curricular units 1st sem (without evaluations) 
                                     "numeric" 
           Curricular units 2nd sem (credited) 
                                     "numeric" 
           Curricular units 2nd sem (enrolled) 
                                     "numeric" 
        Curricular units 2nd sem (evaluations) 
                                     "numeric" 
           Curricular units 2nd sem (approved) 
                                     "numeric" 
              Curricular units 2nd sem (grade) 
                                     "numeric" 
Curricular units 2nd sem (without evaluations) 
                                     "numeric" 
                             Unemployment rate 
                                     "numeric" 
                                Inflation rate 
                                     "numeric" 
                                           GDP 
                                     "numeric" 
summary(base_cuant)
 Previous qualification (grade) Mother's qualification Father's qualification
 Min.   : 95.0                  Min.   : 1.00          Min.   : 1.00         
 1st Qu.:125.0                  1st Qu.: 2.00          1st Qu.: 3.00         
 Median :133.1                  Median :19.00          Median :19.00         
 Mean   :132.6                  Mean   :19.56          Mean   :22.28         
 3rd Qu.:140.0                  3rd Qu.:37.00          3rd Qu.:37.00         
 Max.   :190.0                  Max.   :44.00          Max.   :44.00         
 Mother's occupation Father's occupation Admission grade Age at enrollment
 Min.   :  0.00      Min.   :  0.00      Min.   : 95.0   Min.   :17.00    
 1st Qu.:  4.00      1st Qu.:  4.00      1st Qu.:117.9   1st Qu.:19.00    
 Median :  5.00      Median :  7.00      Median :126.1   Median :20.00    
 Mean   : 10.96      Mean   : 11.03      Mean   :127.0   Mean   :23.27    
 3rd Qu.:  9.00      3rd Qu.:  9.00      3rd Qu.:134.8   3rd Qu.:25.00    
 Max.   :194.00      Max.   :195.00      Max.   :190.0   Max.   :70.00    
 Curricular units 1st sem (credited) Curricular units 1st sem (enrolled)
 Min.   : 0.00                       Min.   : 0.000                     
 1st Qu.: 0.00                       1st Qu.: 5.000                     
 Median : 0.00                       Median : 6.000                     
 Mean   : 0.71                       Mean   : 6.271                     
 3rd Qu.: 0.00                       3rd Qu.: 7.000                     
 Max.   :20.00                       Max.   :26.000                     
 Curricular units 1st sem (evaluations) Curricular units 1st sem (approved)
 Min.   : 0.000                         Min.   : 0.000                     
 1st Qu.: 6.000                         1st Qu.: 3.000                     
 Median : 8.000                         Median : 5.000                     
 Mean   : 8.299                         Mean   : 4.707                     
 3rd Qu.:10.000                         3rd Qu.: 6.000                     
 Max.   :45.000                         Max.   :26.000                     
 Curricular units 1st sem (grade) Curricular units 1st sem (without evaluations)
 Min.   :                0        Min.   : 0.0000                               
 1st Qu.:               12        1st Qu.: 0.0000                               
 Median :            45788        Median : 0.0000                               
 Mean   : 4458090894470000        Mean   : 0.1377                               
 3rd Qu.:12166666666700000        3rd Qu.: 0.0000                               
 Max.   :17333333333300000        Max.   :12.0000                               
 Curricular units 2nd sem (credited) Curricular units 2nd sem (enrolled)
 Min.   : 0.0000                     Min.   : 0.000                     
 1st Qu.: 0.0000                     1st Qu.: 5.000                     
 Median : 0.0000                     Median : 6.000                     
 Mean   : 0.5418                     Mean   : 6.232                     
 3rd Qu.: 0.0000                     3rd Qu.: 7.000                     
 Max.   :19.0000                     Max.   :23.000                     
 Curricular units 2nd sem (evaluations) Curricular units 2nd sem (approved)
 Min.   : 0.000                         Min.   : 0.000                     
 1st Qu.: 6.000                         1st Qu.: 2.000                     
 Median : 8.000                         Median : 5.000                     
 Mean   : 8.063                         Mean   : 4.436                     
 3rd Qu.:10.000                         3rd Qu.: 6.000                     
 Max.   :33.000                         Max.   :20.000                     
 Curricular units 2nd sem (grade) Curricular units 2nd sem (without evaluations)
 Min.   :                0        Min.   : 0.0000                               
 1st Qu.:               11        1st Qu.: 0.0000                               
 Median :            45760        Median : 0.0000                               
 Mean   : 3928633958070000        Mean   : 0.1503                               
 3rd Qu.:11666666666700000        3rd Qu.: 0.0000                               
 Max.   :18571428571400000        Max.   :12.0000                               
 Unemployment rate    Inflation rate         GDP          
 Min.   :1736553600   Min.   :   -0.8   Min.   :   -4.06  
 1st Qu.:1744156800   1st Qu.:    0.3   1st Qu.:   -1.70  
 Median :1749254400   Median :45748.0   Median :    0.32  
 Mean   :1748359367   Mean   :23605.0   Mean   : 4275.50  
 3rd Qu.:1754784000   3rd Qu.:45810.0   3rd Qu.:    1.79  
 Max.   :1757721600   Max.   :45871.0   Max.   :45690.00  

Lo siguiente es calcular los estadísticos descriptivos, es decir, los valores que nos resumen lo más importante de una variable numérica, como por ejemplo, media, desviación estándar, varianza, entre otros. Para ello se mostrarán dos gráficos, un boxplot para ver si hay valores atípicos y un histograma para ver cómo se distribuyen los datos a comparación de una curva normal teórica y ver si siguen una distribución normal:

# Estadígrafos, Histogramas y Boxplots Descriptivos Univariados de Variables Cuantitativas: ----

analisis_cuant <- function(variable) {datos <- base_cuant[[variable]]

 # Cálculo de estadígrafos
  resumen <- resumen_variable(datos)
  
  # Impresión
  cat("Análisis de la variable:", variable, "\n\n")
  print(resumen)
  
  # Interpretación básica automática
  cat("\n Interpretación:\n")
  if (resumen$asimetria > 0.5) {
    cat("- Distribución asimétrica positiva (cola hacia la derecha).\n")
  } else if (resumen$asimetria < -0.5) {
    cat("- Distribución asimétrica negativa (cola hacia la izquierda).\n")
  } else {
    cat("- Distribución aproximadamente simétrica.\n")
  }
  
  if (resumen$curtosis > 3) {
    cat("- Leptocúrtica (picos altos, colas pesadas).\n")
  } else if (resumen$curtosis < 3) {
    cat("- Platicúrtica (más plana que una normal).\n")
  } else {
    cat("- Curtosis cercana a la distribución normal.\n")
  }
  
# Boxplot
  box <- ggplot(base_cuant, aes(y = .data[[variable]])) +
    geom_boxplot(fill = "#65ce67", outlier.color = "red", alpha = 0.7) +
    theme_minimal() +
    labs(title = paste("Boxplot de", variable), y = variable)
  
  print(box)
  
# Histograma con curva normal
  histo <- ggplot(base_cuant, aes(x = .data[[variable]])) +
    geom_histogram(aes(y = after_stat(density)), bins = 30, fill = "#cb96eb", color = "black", alpha = 0.7) +
    stat_function(fun = dnorm,
                  args = list(mean = mean(datos, na.rm = TRUE),
                              sd = sd(datos, na.rm = TRUE)),
                  color = "red", linewidth = 1) +
    theme_minimal() +
    labs(title = paste("Histograma de", variable, "con curva normal"), x = variable, y = "Densidad")
  
  print(histo)
  
  invisible(resumen)
}

Ahora, realizamos los respectivos análisis sobre el comportamiento de estas variables:

analisis_cuant("Previous qualification (grade)")
Análisis de la variable: Previous qualification (grade) 

 Interpretación:
- Distribución aproximadamente simétrica.
- Leptocúrtica (picos altos, colas pesadas).

cat("La nota promedio de la titulación previa es de 133, con una distribución casi 
    simétrica y picos marcados (curtosis ≈ 4). Esto indica que la mayoría de 
    estudiantes tiene calificaciones similares, aunque por supuesto, hay algunos 
    casos más extremos, los cuales no permiten la normalidad.\n")
La nota promedio de la titulación previa es de 133, con una distribución casi 
    simétrica y picos marcados (curtosis ≈ 4). Esto indica que la mayoría de 
    estudiantes tiene calificaciones similares, aunque por supuesto, hay algunos 
    casos más extremos, los cuales no permiten la normalidad.
analisis_cuant("Admission grade")
Análisis de la variable: Admission grade 

 Interpretación:
- Distribución asimétrica positiva (cola hacia la derecha).
- Leptocúrtica (picos altos, colas pesadas).

cat("La nota de admisión promedio es 127, con una asimetría positiva y una 
    distribución más picuda de lo normal (leptocúrtica). Esto sugiere que la
    mayoría de los estudiantes tiene notas de admisión ligeramente por 
    debajo del promedio, pero hay algunos con notas notablemente altas.\n")
La nota de admisión promedio es 127, con una asimetría positiva y una 
    distribución más picuda de lo normal (leptocúrtica). Esto sugiere que la
    mayoría de los estudiantes tiene notas de admisión ligeramente por 
    debajo del promedio, pero hay algunos con notas notablemente altas.
analisis_cuant("Curricular units 1st sem (grade)")
Análisis de la variable: Curricular units 1st sem (grade) 

 Interpretación:
- Distribución asimétrica positiva (cola hacia la derecha).
- Platicúrtica (más plana que una normal).

cat("La variable presenta valores atípicos muy altos y estos hacen que no haya una medida clara de centralidad, con una media extrañamente elevada de 4.46e15. La mediana es 13.5, y la distribución es asimétrica positiva y platicúrtica. Entonces se puede concluir que es necesario limpiar los datos para obtener un análisis más confiable.\n")
La variable presenta valores atípicos muy altos y estos hacen que no haya una medida clara de centralidad, con una media extrañamente elevada de 4.46e15. La mediana es 13.5, y la distribución es asimétrica positiva y platicúrtica. Entonces se puede concluir que es necesario limpiar los datos para obtener un análisis más confiable.
analisis_cuant("Curricular units 2nd sem (grade)")
Análisis de la variable: Curricular units 2nd sem (grade) 

 Interpretación:
- Distribución asimétrica positiva (cola hacia la derecha).
- Platicúrtica (más plana que una normal).

cat("Ocurre lo mismo que en el primer semestre: hay valores extremadamente altos, en este caso la media es de 3.93e15. La mediana es 13, y la distribución también es asimétrica positiva y más plana de lo normal (platicúrtica).\n")
Ocurre lo mismo que en el primer semestre: hay valores extremadamente altos, en este caso la media es de 3.93e15. La mediana es 13, y la distribución también es asimétrica positiva y más plana de lo normal (platicúrtica).
analisis_cuant("Unemployment rate")
Análisis de la variable: Unemployment rate 

 Interpretación:
- Distribución aproximadamente simétrica.
- Platicúrtica (más plana que una normal).

cat("Se cuenta con una tasa promedio de desempleo de 11.6% con distribución simétrica y dispersa. La mayoría de los valores están cerca de la media, pero hay cierta variabilidad (SD = 2.66).\n")
Se cuenta con una tasa promedio de desempleo de 11.6% con distribución simétrica y dispersa. La mayoría de los valores están cerca de la media, pero hay cierta variabilidad (SD = 2.66).
analisis_cuant("Inflation rate")
Análisis de la variable: Inflation rate 

 Interpretación:
- Distribución aproximadamente simétrica.
- Platicúrtica (más plana que una normal).

cat("Inflación media de 1.23, también con distribución simétrica y plana (platicúrtica). Los valores están relativamente concentrados entre el 0 y el 2.5.\n")
Inflación media de 1.23, también con distribución simétrica y plana (platicúrtica). Los valores están relativamente concentrados entre el 0 y el 2.5.
analisis_cuant("GDP")
Análisis de la variable: GDP 

 Interpretación:
- Distribución asimétrica positiva (cola hacia la derecha).
- Leptocúrtica (picos altos, colas pesadas).

cat("El PIB tiene una media cercana a cero (0.00197) debido a valores negativos y positivos. A pesar de eso, muestra una distribución simétrica y más dispersa, con una alta desviación estándar (2.27).\n")
El PIB tiene una media cercana a cero (0.00197) debido a valores negativos y positivos. A pesar de eso, muestra una distribución simétrica y más dispersa, con una alta desviación estándar (2.27).

Luego, procedemos a hacer el Análisis Bivariado Cuantitativo, donde lo haremos mediante la correlación que presenten las variables:

# Análisis Bivariado Cuantitativo: ----

analisis_bi_cuant <- function(var1, var2) {
  x <- base_cuant[[var1]]
  y <- base_cuant[[var2]]
  
  # Calcular correlación
  cor_val <- cor(x, y, use = "complete.obs")
  
  # Interpretación textual
  interpretacion <- case_when(
    abs(cor_val) < 0.2 ~ "Muy débil o nula",
    abs(cor_val) < 0.4 ~ "Débil",
    abs(cor_val) < 0.6 ~ "Moderada",
    abs(cor_val) < 0.8 ~ "Fuerte",
    TRUE ~ "Muy fuerte"
  )
  
  direccion <- ifelse(cor_val > 0, "positiva", "negativa")
  
  cat("Análisis bivariado:", var1, "vs", var2, "\n")
  cat("Coeficiente de correlación:", round(cor_val, 4), "\n")
  cat("Interpretación: Correlación", interpretacion, direccion, "\n\n")
  
  # Diagrama de dispersión
  p <- ggplot(base_cuant, aes(x = .data[[var1]], y = .data[[var2]])) +
    geom_point(color = "darkblue", alpha = 0.6) +
    geom_smooth(method = "lm", se = FALSE, color = "red", linewidth = 1) +
    theme_minimal() +
    labs(title = paste("Dispersión:", var1, "vs", var2),
         subtitle = paste("Correlación:", round(cor_val, 4)),
         x = var1, y = var2)
  
  print(p)
  
  invisible(cor_val)
}

Su comportamiento o correlación se verá de la siguiente manera:

analisis_bi_cuant("Previous qualification (grade)", "GDP")
Análisis bivariado: Previous qualification (grade) vs GDP 
Coeficiente de correlación: -0.0589 
Interpretación: Correlación Muy débil o nula negativa 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Curricular units 1st sem (credited)", "Curricular units 2nd sem (credited)")
Análisis bivariado: Curricular units 1st sem (credited) vs Curricular units 2nd sem (credited) 
Coeficiente de correlación: 0.9448 
Interpretación: Correlación Muy fuerte positiva 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Curricular units 1st sem (evaluations)", "Curricular units 1st sem (approved)")
Análisis bivariado: Curricular units 1st sem (evaluations) vs Curricular units 1st sem (approved) 
Coeficiente de correlación: 0.5224 
Interpretación: Correlación Moderada positiva 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Curricular units 1st sem (grade)", "Curricular units 1st sem (without evaluations)")
Análisis bivariado: Curricular units 1st sem (grade) vs Curricular units 1st sem (without evaluations) 
Coeficiente de correlación: -0.041 
Interpretación: Correlación Muy débil o nula negativa 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Mother's occupation", "Father's occupation")
Análisis bivariado: Mother's occupation vs Father's occupation 
Coeficiente de correlación: 0.9105 
Interpretación: Correlación Muy fuerte positiva 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Previous qualification (grade)", "Admission grade")
Análisis bivariado: Previous qualification (grade) vs Admission grade 
Coeficiente de correlación: 0.5804 
Interpretación: Correlación Moderada positiva 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Curricular units 1st sem (enrolled)", "Inflation rate")
Análisis bivariado: Curricular units 1st sem (enrolled) vs Inflation rate 
Coeficiente de correlación: 0.0353 
Interpretación: Correlación Muy débil o nula positiva 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Curricular units 1st sem (approved)", "Curricular units 2nd sem (approved)")
Análisis bivariado: Curricular units 1st sem (approved) vs Curricular units 2nd sem (approved) 
Coeficiente de correlación: 0.904 
Interpretación: Correlación Muy fuerte positiva 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Curricular units 2nd sem (credited)", "Curricular units 2nd sem (approved)")
Análisis bivariado: Curricular units 2nd sem (credited) vs Curricular units 2nd sem (approved) 
Coeficiente de correlación: 0.5191 
Interpretación: Correlación Moderada positiva 

`geom_smooth()` using formula = 'y ~ x'

analisis_bi_cuant("Unemployment rate", "GDP")
Análisis bivariado: Unemployment rate vs GDP 
Coeficiente de correlación: -0.5728 
Interpretación: Correlación Moderada negativa 

`geom_smooth()` using formula = 'y ~ x'

# Diagrama de Correlación:

corrplot(cor(base_cuant), method = "shade", tl.cex = 0.6,
         col=brewer.pal(n=8, name="PuOr"),addCoef.col = "black",
         number.cex=0.4,type = "upper", diag = FALSE)


# Análisis de Modelo Distribucional: ----

cat("Ahora, miraremos si las variables cuantitativas cuentan con una distribución conocida como normal, gamma o lognormal, para ello estableceremos nuestra H0: la variable podría seguir una distribución normal vs H1: no H0.")
Ahora, miraremos si las variables cuantitativas cuentan con una distribución conocida como normal, gamma o lognormal, para ello estableceremos nuestra H0: la variable podría seguir una distribución normal vs H1: no H0.
analisis_distribucional <- function(variable) {
  x <- base_cuant[[variable]]
  x <- na.omit(x)
  
  cat("Análisis de Modelo Distribucional para:", variable, "\n\n")
  
  # 1. Test de normalidad
  p_shapiro <- shapiro.test(x)$p.value
  cat("Test de Shapiro-Wilk (normalidad): p-value =", round(p_shapiro, 5), "\n")
  cat(ifelse(p_shapiro > 0.05,
             "- No se rechaza H0: la variable podría seguir una distribución normal.\n",
             "- Se rechaza H0: la variable NO sigue una distribución normal.\n"))
  
  # 2. Histograma + curva normal teórica
  histo <- ggplot(base_cuant, aes(x = .data[[variable]])) +
    geom_histogram(aes(y = after_stat(density)), bins = 30, fill = "lightblue", color = "black") +
    stat_function(fun = dnorm,
                  args = list(mean = mean(x), sd = sd(x)),
                  color = "red", linewidth = 1) +
    theme_minimal() +
    labs(title = paste("Histograma con curva normal:", variable),
         x = variable, y = "Densidad")
  
  print(histo)
  
  # 3. Ajuste de distribuciones conocidas
  library(fitdistrplus)
  
  modelos <- list()
  modelos$norm <- fitdist(x, "norm")
  
  if (all(x > 0)) {
    modelos$lnorm <- fitdist(x, "lnorm")
    modelos$gamma <- fitdist(x, "gamma")
  }
  
  # 4. Evaluar AIC
  if (length(modelos) > 1) {
    gof <- gofstat(modelos)
    aic_table <- as_tibble_row(gof$aic)
  } else {
    aic_table <- tibble(norm = modelos$norm$aic)
  }
  
  aic_table <- aic_table %>%
    pivot_longer(everything(), names_to = "Distribucion", values_to = "AIC") %>%
    arrange(AIC)
  
  print(aic_table)
  
  cat("\n Distribución con menor AIC:", aic_table$Distribucion[1], "\n")
  
  invisible(list(
    p_shapiro = p_shapiro,
    aic = aic_table
  ))
}

analisis_distribucional("Previous qualification (grade)")
Análisis de Modelo Distribucional para: Previous qualification (grade) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: 3-mle-gamma 

analisis_distribucional("Mother's qualification")
Análisis de Modelo Distribucional para: Mother's qualification 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: 3-mle-gamma 

analisis_distribucional("Father's qualification")
Análisis de Modelo Distribucional para: Father's qualification 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: 3-mle-gamma 

analisis_distribucional("Mother's occupation")
Análisis de Modelo Distribucional para: Mother's occupation 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Father's occupation")
Análisis de Modelo Distribucional para: Father's occupation 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Admission grade")
Análisis de Modelo Distribucional para: Admission grade 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: 2-mle-lnorm 

analisis_distribucional("Age at enrollment")
Análisis de Modelo Distribucional para: Age at enrollment 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: 2-mle-lnorm 

analisis_distribucional("Curricular units 1st sem (credited)")
Análisis de Modelo Distribucional para: Curricular units 1st sem (credited) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 1st sem (enrolled)")
Análisis de Modelo Distribucional para: Curricular units 1st sem (enrolled) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 1st sem (evaluations)")
Análisis de Modelo Distribucional para: Curricular units 1st sem (evaluations) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 1st sem (approved)")
Análisis de Modelo Distribucional para: Curricular units 1st sem (approved) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 1st sem (grade)")
Análisis de Modelo Distribucional para: Curricular units 1st sem (grade) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 1st sem (without evaluations)")
Análisis de Modelo Distribucional para: Curricular units 1st sem (without evaluations) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 2nd sem (credited)")
Análisis de Modelo Distribucional para: Curricular units 2nd sem (credited) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 2nd sem (enrolled)")
Análisis de Modelo Distribucional para: Curricular units 2nd sem (enrolled) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 2nd sem (evaluations)")
Análisis de Modelo Distribucional para: Curricular units 2nd sem (evaluations) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 2nd sem (approved)")
Análisis de Modelo Distribucional para: Curricular units 2nd sem (approved) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 2nd sem (grade)")
Análisis de Modelo Distribucional para: Curricular units 2nd sem (grade) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Curricular units 2nd sem (without evaluations)")
Análisis de Modelo Distribucional para: Curricular units 2nd sem (without evaluations) 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("Unemployment rate")
Análisis de Modelo Distribucional para: Unemployment rate 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: 1-mle-norm 

analisis_distribucional("Inflation rate")
Análisis de Modelo Distribucional para: Inflation rate 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

analisis_distribucional("GDP")
Análisis de Modelo Distribucional para: GDP 

Test de Shapiro-Wilk (normalidad): p-value = 0 
- Se rechaza H0: la variable NO sigue una distribución normal.

 Distribución con menor AIC: norm 

# Interpretación del Modelo Distribucional ----

cat("Se evaluó el ajuste de cada variable cuantitativa a tres distribuciones teóricas: Normal, Log-Normal y Gamma, utilizando el Test de Shapiro-Wilk (normalidad).\n\n")
Se evaluó el ajuste de cada variable cuantitativa a tres distribuciones teóricas: Normal, Log-Normal y Gamma, utilizando el Test de Shapiro-Wilk (normalidad).
cat("Para cada variable, se seleccionó la distribución con menor AIC como la de mejor ajuste.\n\n")
Para cada variable, se seleccionó la distribución con menor AIC como la de mejor ajuste.
cat("En general, se observaron los siguientes patrones:\n")
En general, se observaron los siguientes patrones:
cat("- Las variables como 'Previous qualification (grade)', 'Mother's qualification' y 'Age at enrollment' mostraron mejor ajuste con distribuciones gamma o log-normal, lo cual sugiere una asimetría positiva y valores no negativos.\n")
- Las variables como 'Previous qualification (grade)', 'Mother's qualification' y 'Age at enrollment' mostraron mejor ajuste con distribuciones gamma o log-normal, lo cual sugiere una asimetría positiva y valores no negativos.
cat("- Algunas variables como 'Mother's occupation' y 'Curricular units' solo pudieron ajustarse con la distribución normal, debido a la presencia de valores cero o negativos que impiden el uso de gamma o log-normal.\n")
- Algunas variables como 'Mother's occupation' y 'Curricular units' solo pudieron ajustarse con la distribución normal, debido a la presencia de valores cero o negativos que impiden el uso de gamma o log-normal.
cat("- Variables como 'GDP' e 'Inflation rate' también mostraron ajuste exclusivo a la distribución normal.\n\n")
- Variables como 'GDP' e 'Inflation rate' también mostraron ajuste exclusivo a la distribución normal.
cat("Esto implica que muchas de las variables analizadas (por no decir, Todas), no siguen una distribución normal clásica, por lo cual se rechaza la H0 y es recomendable considerar transformaciones o el uso de métodos no paramétricos si se requieren supuestos de normalidad en análisis posteriores.\n")
Esto implica que muchas de las variables analizadas (por no decir, Todas), no siguen una distribución normal clásica, por lo cual se rechaza la H0 y es recomendable considerar transformaciones o el uso de métodos no paramétricos si se requieren supuestos de normalidad en análisis posteriores.

Hacemos el analisis bivariado mixto

cat("Estamos haciendo análisis con respecto a la variable Target \n")
Estamos haciendo análisis con respecto a la variable Target 
histograma_bi <- function(variable1, variable2) {
  histograma <- datos_u %>%
    ggplot(aes(x = !!sym(variable1))) +
    geom_histogram(fill = "yellow", color = "black", bins = 15) +
    ggtitle(variable1) +
    labs(x = variable1, y = "Frecuencias") +
    facet_wrap(vars(!!sym(variable2)), scales = "free") +
    theme_minimal() +
    theme(plot.title = element_text(hjust = 0.05))
  
  return(histograma)
}


boxplot_bi <- function(variable1, variable2) {
  ggplot(datos_u, aes(x = .data[[variable1]], y = .data[[variable2]])) +
    geom_boxplot(fill = "skyblue", outlier.color = "red") +
    theme_minimal() +
    labs(
      title = paste("Boxplot de", variable2, "según", variable1),
      x = variable1,
      y = variable2
    )
}
descripcion <- function(variable1,variable2){
  return(describeBy(datos_u[[variable1]],group=datos_u[[variable2]]))  
}
histograma_bi("Curricular units 1st sem (approved)","Target")

descripcion("Curricular units 1st sem (approved)","Target")

 Descriptive statistics by group 
group: Dropout
------------------------------------------------------------------ 
group: Enrolled
------------------------------------------------------------------ 
group: Graduate
histograma_bi( "Curricular units 2nd sem (approved)","Target")

descripcion("Curricular units 2nd sem (approved)","Target")

 Descriptive statistics by group 
group: Dropout
------------------------------------------------------------------ 
group: Enrolled
------------------------------------------------------------------ 
group: Graduate
boxplot_bi("Curricular units 1st sem (approved)","Target")


boxplot_bi("Curricular units 2nd sem (approved)","Target")


boxplot_bi("Age at enrollment","Target")


boxplot_bi("Unemployment rate","Target")

NA
NA

Comenzamos con las pruebas de hipotesis

cat("Pruebas de Hipótesis\n")
Pruebas de Hipótesis
mean(datos_u$`Curricular units 1st sem (enrolled)`)
[1] 6.27057

Primera prueba de hipótesis:

Anteriormente pudimos ver que la media de los valores de los créditos inscritos en primer semestre es de 6.27057, por ende centremos nuestra hipótesis sobre esto.

H0: 6.27 > miu vs H1: miu <= 6.27

cat("Vamos a verificar si sigue una normal:\n")
Vamos a verificar si sigue una normal:
analisis_cuant("Curricular units 1st sem (enrolled)")
Análisis de la variable: Curricular units 1st sem (enrolled) 

 Interpretación:
- Distribución asimétrica positiva (cola hacia la derecha).
- Leptocúrtica (picos altos, colas pesadas).

lillie.test(datos_u$`Curricular units 1st sem (enrolled)`)

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  datos_u$`Curricular units 1st sem (enrolled)`
D = 0.25478, p-value < 0.00000000000000022
cat("No sigue la normal, por lo tanto tendremos que suponer 
    normalidad :(
    Así que para ello aplicaremos el t test.")
No sigue la normal, por lo tanto tendremos que suponer 
    normalidad :(
    Así que para ello aplicaremos el t test.
t.test(datos_u$`Curricular units 1st sem (enrolled)`, alternative="less", mu = 6.27)

    One Sample t-test

data:  datos_u$`Curricular units 1st sem (enrolled)`
t = 0.015276, df = 4423, p-value = 0.5061
alternative hypothesis: true mean is less than 6.27
95 percent confidence interval:
     -Inf 6.331917
sample estimates:
mean of x 
  6.27057 

Para la segunda muestra evidenciamos que la proporcion de estudiantes que necesitan Educación Especial es de 0.01152803, por ende vamos a verificar que la proporcion poblacional de los estudiantes que necesitan educacion especial es menor al 2%, contra que sea mayor o igual al 2%

H0: miu < 0.02 vs H1: miu >= 0.02”)

prop.table(table(datos_u$`Educational special needs`))

         0          1 
0.98847197 0.01152803 
table(datos_u$`Educational special needs`)

   0    1 
4373   51 
cat("Implementamos el prop test:\n")
Implementamos el prop test:
prop.test(51,
          n = length(datos_u$`Educational special needs`),
          p = 0.02,
          alternative = "less",
          correct = FALSE)

    1-sample proportions test without continuity correction

data:  51 out of length(datos_u$`Educational special needs`), null probability 0.02
X-squared = 16.2, df = 1, p-value = 0.00002849
alternative hypothesis: true p is less than 0.02
95 percent confidence interval:
 0.00000000 0.01448245
sample estimates:
         p 
0.01152803 

se rechaza comenzamos con bondad de ajuste

cat("H0: Los creditos aprobados en segundo semestre siguen una 
distribucion binomial 
vs
H1: No H0")
H0: Los creditos aprobados en segundo semestre siguen una 
distribucion binomial 
vs
H1: No H0
frecuencias <- table(datos_u$`Curricular units 2nd sem (approved)`)
frecuencias 

  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  16  17  18  19  20 
870 114 198 285 414 726 965 331 321  36  38  48  34  21   6   2   8   2   3   2 
valores <- as.numeric(names(frecuencias))
valores 
 [1]  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 16 17 18 19 20
cat("Tenemos que hallar la cantidad de intentos para conseguir un éxito, 
entonces analizaremos los créditos inscritos:\n") 
Tenemos que hallar la cantidad de intentos para conseguir un éxito, 
entonces analizaremos los créditos inscritos:
maX <- sort(unique(datos_u$`Curricular units 2nd sem (enrolled)`), decreasing = TRUE)[2]
maX
[1] 21
cat("Tomaremos 19, luego borramos los datos que sean menores a 19...\n")
Tomaremos 19, luego borramos los datos que sean menores a 19...
datos2 <- datos_u[datos_u$`Curricular units 2nd sem (enrolled)`<=19,]

diagrama_creditosins<- boxplot(datos_u$`Curricular units 2nd sem (enrolled)`,horizontal=TRUE)

datos_u %>% dim()
[1] 4424   37
datos2 %>% count(`Curricular units 2nd sem (enrolled)`)

mean(datos_u$`Curricular units 2nd sem (enrolled)`)
[1] 6.232143
cat("Podemos ver que el máximo de créditos inscritos es 23, sin embargo 
mayormente los datos están entre 4 y 7, aún así, para no perder datos 
consideraremos el máximo:\n") 
Podemos ver que el máximo de créditos inscritos es 23, sin embargo 
mayormente los datos están entre 4 y 7, aún así, para no perder datos 
consideraremos el máximo:
p <- sum(datos2$`Curricular units 2nd sem (approved)`)/(19*4421)
p
[1] 0.2329313
n <- datos_u %>% dim
p_i <- dbinom(valores,19,p)
p_i
 [1] 0.006484111844922015 0.037410868883912561 0.102243098183286613 0.175936263529149872
 [5] 0.213702229119323767 0.194681195115019717 0.137941354302626051 0.077791741582523943
 [9] 0.035433858794491943 0.013151107339584982 0.003993521428558655 0.000992200724982270
[13] 0.000200863940165268 0.000032843570331155 0.000004274322366529 0.000000032845314182
[17] 0.000000001760108541 0.000000000059386898 0.000000000000949141 0.000000000000000000
b <- chisq.test(frecuencias,p=p_i,rescale.p=TRUE)
Aviso en chisq.test(frecuencias, p = p_i, rescale.p = TRUE) :
  Chi-squared approximation may be incorrect
b

    Chi-squared test for given probabilities

data:  frecuencias
X-squared = Inf, df = 19, p-value < 0.00000000000000022
b$expected
                  0                   1                   2                   3 
 28.685723212899084 165.505755548990152 452.323662062047447 778.342366605115785 
                  4                   5                   6                   7 
945.419070662281683 861.269979819884270 610.252815462526542 344.150813658966513 
                  8                   9                  10                  11 
156.759459129281993  58.180524042301990  17.667346443773859   4.389497906450984 
                 12                  13                  14                  16 
  0.888622455756313   0.145300018009520   0.018909610330826   0.000145307732807 
                 17                  18                  19                  20 
  0.000007786723555   0.000000262727748   0.000000004199002   0.000000000000000 
cat("Bucamos 0 inflado:\n")
Bucamos 0 inflado:

con categoricas

H0:course sigue una distribucion uniforme vs H1:no H0

observado <- table(base_cate$Course)

total <- sum(observado)

esperado <- rep(total/length(observado),length(observado))

resultado <- chisq.test(x=observado,p=esperado/total)
resultado

    Chi-squared test for given probabilities

data:  observado
X-squared = 1602.4, df = 16, p-value < 0.00000000000000022
print("el p-value es muy bajo, entonces se rechaza la hipotesis nula")
[1] "el p-value es muy bajo, entonces se rechaza la hipotesis nula"
#sin embargo algo interesante es que course podria seguir una distribucion zipf
#para mirar si sigue esta distribucion usamos la grafica log-log 

frecuencias <- as.data.frame(table(base_cate$Course))
colnames(frecuencias) <- c("course","count")
frecuencias <- frecuencias[order(-frecuencias$count),]

frecuencias$Rank <- 1:nrow(frecuencias)


log_log <- ggplot(frecuencias, aes(x = Rank, y = frecuencias$count)) +
  geom_point(color = "blue") +
  geom_smooth(method = "lm", formula = y ~ x, se = FALSE, color = "red") +
  scale_x_log10() +
  scale_y_log10() +
  labs(title = "Ajuste lineal en escala log-log",
       x = "Rango del curso (log)",
       y = "Frecuencia (log)") +
  theme_minimal()

log_log
Aviso: Use of `frecuencias$count` is discouraged.
ℹ Use `count` instead.
Aviso: Use of `frecuencias$count` is discouraged.
ℹ Use `count` instead.

como podemos ver el grafico, no sigue la linea, entonces no sigue la distribucion, lo intentamos :(

test_independencia <- function(var1, var2) {
  tabla <- table(datos_u[[var1]], datos_u[[var2]])
  
  cat("\n¿Hay independencia entre", var1, "y", var2, "?\n\n")
  
  min_esperado <- min(chisq.test(tabla)$expected)
  
  if (any(tabla < 5) || min_esperado < 5) {
    test <- fisher.test(tabla)
    metodo <- "Test exacto de Fisher"
  } else {
    test <- chisq.test(tabla)
    metodo <- "Chi-cuadrado de independencia"
  }
  
  cat("Método:", metodo, "\n")
  cat("p-valor =", signif(test$p.value, 6), "\n\n")
  
  if (test$p.value < 0.05) {
    cat("Se rechaza H0: hay evidencia de dependencia entre", var1, "y", var2, "\n\n")
  } else {
    cat("No se rechaza H0: no hay evidencia suficiente de dependencia entre", var1, "y", var2, "\n\n")
  }
  
  cat("Tabla de contingencia (% por fila):\n")
  print(round(prop.table(tabla, margin = 1) * 100, 2))
  
  invisible(test)
  
  p <- grafico_apilado(var1, var2)
  
  print(p)
}


test_independencia("Target", "Scholarship holder")

¿Hay independencia entre Target y Scholarship holder ?

Método: Chi-cuadrado de independencia 
p-valor = 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000959393 

Se rechaza H0: hay evidencia de dependencia entre Target y Scholarship holder 

Tabla de contingencia (% por fila):
          
               0     1
  Dropout  90.57  9.43
  Enrolled 83.63 16.37
  Graduate 62.20 37.80

test_independencia("Target", "Daytime/evening attendance")

¿Hay independencia entre Target y Daytime/evening attendance ?

Método: Chi-cuadrado de independencia 
p-valor = 0.000000574383 

Se rechaza H0: hay evidencia de dependencia entre Target y Daytime/evening attendance 

Tabla de contingencia (% por fila):
          
               0     1
  Dropout  14.57 85.43
  Enrolled  9.45 90.55
  Graduate  9.10 90.90

test_independencia("Target", "Gender")

¿Hay independencia entre Target y Gender ?

Método: Chi-cuadrado de independencia 
p-valor = 0.00000000000000000000000000000000000000000000000000222248 

Se rechaza H0: hay evidencia de dependencia entre Target y Gender 

Tabla de contingencia (% por fila):
          
               0     1
  Dropout  50.67 49.33
  Enrolled 61.34 38.66
  Graduate 75.19 24.81

test_independencia("Debtor", "Scholarship holder")

¿Hay independencia entre Debtor y Scholarship holder ?

Método: Chi-cuadrado de independencia 
p-valor = 0.00000924454 

Se rechaza H0: hay evidencia de dependencia entre Debtor y Scholarship holder 

Tabla de contingencia (% por fila):
   
        0     1
  0 74.11 25.89
  1 83.30 16.70

test_independencia("Target", "Tuition fees up to date")

¿Hay independencia entre Target y Tuition fees up to date ?

Método: Chi-cuadrado de independencia 
p-valor = 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000147163 

Se rechaza H0: hay evidencia de dependencia entre Target y Tuition fees up to date 

Tabla de contingencia (% por fila):
          
               0     1
  Dropout  32.16 67.84
  Enrolled  5.29 94.71
  Graduate  1.31 98.69

residuales_posthoc <- function(var1, var2) {
  tabla <- table(datos_u[[var1]], datos_u[[var2]])
  
  test <- chisq.test(tabla)
  
  residuales <- test$stdres
  
  cat("Análisis post-hoc de residuales estandarizados:\n")
  print(round(residuales, 2))
  
  sig_res <- abs(residuales) >= 2
  
  cat("\n Celdas con contribución significativa (|residual| ≥ 2):\n")
  print(which(sig_res, arr.ind = TRUE))
  
  library(reshape2)
  df_res <- melt(residuales)
  
  ggplot(df_res, aes(x = Var2, y = Var1, fill = value)) +
    geom_tile(color = "purple") +
    geom_text(aes(label = round(value, 2)), color = "black", size = 3) +
    scale_fill_gradient2(low = "yellow", mid = "lightblue", high = "red", midpoint = 0) +
    labs(title = paste("Residuales estandarizados:", var1, "vs", var2),
         x = var2, y = var1) +
    theme_minimal()
}

residuales_posthoc("Target", "Scholarship holder")
Análisis post-hoc de residuales estandarizados:
          
                0      1
  Dropout   16.32 -16.32
  Enrolled   6.10  -6.10
  Graduate -19.92  19.92

 Celdas con contribución significativa (|residual| ≥ 2):
         row col
Dropout    1   1
Enrolled   2   1
Graduate   3   1
Dropout    1   2
Enrolled   2   2
Graduate   3   2
Aviso: package ‘reshape2’ was built under R version 4.4.3

Adjuntando el paquete: ‘reshape2’

The following object is masked from ‘package:tidyr’:

    smiths

residuales_posthoc("Target", "Daytime/evening attendance")
Análisis post-hoc de residuales estandarizados:
          
               0     1
  Dropout   5.35 -5.35
  Enrolled -1.47  1.47
  Graduate -3.87  3.87

 Celdas con contribución significativa (|residual| ≥ 2):
         row col
Dropout    1   1
Graduate   3   1
Dropout    1   2
Graduate   3   2

residuales_posthoc("Target", "Gender")
Análisis post-hoc de residuales estandarizados:
          
                0      1
  Dropout  -13.57  13.57
  Enrolled  -2.28   2.28
  Graduate  14.42 -14.42

 Celdas con contribución significativa (|residual| ≥ 2):
         row col
Dropout    1   1
Enrolled   2   1
Graduate   3   1
Dropout    1   2
Enrolled   2   2
Graduate   3   2

residuales_posthoc("Debtor", "Scholarship holder")
Análisis post-hoc de residuales estandarizados:
   
        0     1
  0 -4.49  4.49
  1  4.49 -4.49

 Celdas con contribución significativa (|residual| ≥ 2):
  row col
0   1   1
1   2   1
0   1   2
1   2   2

residuales_posthoc("Target", "Tuition fees up to date")
Análisis post-hoc de residuales estandarizados:
          
                0      1
  Dropout   28.54 -28.54
  Enrolled  -6.38   6.38
  Graduate -21.76  21.76

 Celdas con contribución significativa (|residual| ≥ 2):
         row col
Dropout    1   1
Enrolled   2   1
Graduate   3   1
Dropout    1   2
Enrolled   2   2
Graduate   3   2

Pruebas Ks


# Pruebas K-S :3

# Cargar la base de datos

library(readr)
library(tidyverse)

data <- read_delim("data.csv", delim = ";", 
                   escape_double = FALSE, trim_ws = TRUE)
Rows: 4424 Columns: 37
── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ";"
chr  (1): Target
dbl (36): Marital status, Application mode, Application order, Course, Daytime/eveni...

ℹ 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.
datos_u <- data
datos_u %>% dim()
[1] 4424   37
# Como K-S es útil para bondad de ajuste de variables cuantitativas continuas,
# se usará a continuación:



# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
# Notas del examen de admisión (admission grade)
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

admission_grade <- datos_u$`Admission grade`
admission_grade
   [1] 127.3 142.5 124.8 119.6 141.5 114.8 128.4 113.1 129.3 123.0 130.6 119.3 130.2
  [14] 111.8 137.1 120.7 137.4 127.3 136.3 124.6 120.3 121.8 125.5 114.9 123.9 157.0
  [27] 116.4 131.0 122.1 118.8 150.0 130.0 138.8 134.5 131.4 102.5 128.8 122.9 113.9
  [40] 120.0 121.1 120.4 100.6 121.4 109.7 134.1 127.6 132.4 133.4 126.1 113.5 121.3
  [53] 121.8 159.3 120.0 129.1 130.0 155.3 139.8 115.2 114.9 131.9 126.0 130.2 120.9
  [66] 126.0 128.2 130.0 120.1 100.0 134.0 130.8 135.8 111.7 132.9 115.5 106.0 120.3
  [79] 130.8 117.0 110.2 155.7 180.4 125.5 110.0 161.0 100.0 117.6 128.7 112.2 100.8
  [92] 105.0 100.0 115.5 114.0 137.0 124.9 120.3 134.3 111.5 128.8 110.0 113.5 160.0
 [105] 117.4 122.2 118.2 106.7 108.2 107.0 136.1 115.3 139.8 157.0 131.0 100.0 140.4
 [118] 113.4 137.0 121.8 131.0 118.6 122.3 127.9 121.3 117.1 160.0 145.3 122.6 128.0
 [131] 124.9 123.7 120.1 131.7 133.2 109.3 113.0 157.9 112.1 174.7 128.8 110.1  99.7
 [144] 121.0 131.7 119.1 124.7 117.2 128.8 131.5 121.7 123.4 124.7 132.8 108.7 138.1
 [157] 126.5 127.4 123.6 122.0 118.2 123.9 125.8 123.3 124.4 126.0 170.0 121.5 130.0
 [170] 117.0 130.0 108.0 132.3 148.0 122.6 123.0 102.5 113.3 133.0 140.0 128.3 140.0
 [183] 104.0 122.3 135.0 119.1 126.6 129.0 162.3 163.4 121.5 122.8 118.0 134.0 129.8
 [196] 152.0 122.8 150.0 131.8 105.9 132.1 127.4 129.5 126.7 116.5 119.1 126.5 149.8
 [209] 115.1 124.5 128.3 136.0 140.0 126.3 126.9 145.0 115.8 100.0 102.5 131.5 147.0
 [222] 122.5 117.5 150.0 127.5 140.0 130.0 133.3  97.0 112.0 123.6 130.5 133.3 132.1
 [235] 100.0 140.4 141.7 119.7 122.5 140.0 119.4 155.0 119.1 122.7 117.9 130.0 120.0
 [248] 130.0 116.8 123.4 125.4 127.2 103.4 123.2 124.1  99.5 124.9 110.8 118.9 118.8
 [261] 137.0 100.0 120.0 122.8 121.6 149.2 140.0 133.4 126.2 127.8 150.0 113.7 117.8
 [274] 136.7 144.7 139.8 113.7 140.0 142.3 119.6 123.7 143.0 100.1 119.4 122.1 100.0
 [287] 113.9 101.0 111.8 140.0 124.4 150.0 140.0 116.0 135.6 121.0 118.7 125.7 107.1
 [300] 125.5 127.0 113.5 154.4 122.0 128.0 115.5 117.2 150.0 155.3 120.0 116.1 118.9
 [313] 127.3 113.7 118.5 146.7 124.3 137.8 130.2 147.8 150.0 100.0 155.6 117.4 128.8
 [326] 117.5 120.4 130.9 125.0 136.8 121.6 151.0 103.5 119.4 134.4 143.0 110.0 132.5
 [339] 114.7 166.9 125.9 178.3 117.0 150.0 130.0 135.1 110.0 136.2 116.0 100.0 116.3
 [352] 134.0 124.2 134.5 120.7 127.1 133.0 128.2 130.0 172.0 128.5 128.5 112.0 142.5
 [365] 133.0 106.0 125.5 131.2 112.9 124.8 140.9 148.0 148.4 129.7 128.2 104.0 119.9
 [378] 141.0 116.6 140.0 140.0 100.0 121.0 117.0 140.2 129.3 145.3 146.2 122.5 156.1
 [391] 140.0 140.0 128.4 115.0 158.7 124.5 111.9 150.0 114.2  96.0 128.9 121.7 114.8
 [404] 127.0 131.3 137.1 120.0 139.0 129.1 128.2 120.8 135.8 118.9 140.0 127.1 137.0
 [417] 127.4  97.0 126.3 127.5 126.6 120.0 140.0 131.5 112.2 150.5 121.0 112.2 129.4
 [430] 114.4 120.3 120.0 114.5 127.8 124.6 130.3 118.2 118.8 133.0 129.0 100.0 120.7
 [443] 132.5 120.3 114.6 116.5 127.8 129.9 118.9 114.3 114.8 123.0 122.1 123.7 132.4
 [456] 114.8 130.0 122.3 152.4 120.1 155.1 124.5 126.9 153.2 129.8 135.0 131.3 125.2
 [469] 141.3 117.1 126.5 120.1 128.4 140.0 110.0 116.8 104.5 140.0 113.2 118.6 123.8
 [482] 126.7 133.8 140.0 100.6 132.7 106.6 140.4 128.3 118.6 123.4 124.0 121.3 101.0
 [495] 116.9 130.0 120.0 130.4 118.7 131.5 120.4 129.1 132.0 130.0 132.8 143.7 152.8
 [508] 133.5 146.2 115.2 120.7 101.8 100.0 121.9 120.4 120.4 148.8 123.0 100.0 112.1
 [521] 126.8 115.9 132.5 132.2 183.5 136.0 100.9 114.5 110.3 137.2 116.9 121.8 127.3
 [534] 120.0 150.0 100.0 150.0 116.9 140.0 122.1 160.0 118.4 150.0 144.9 121.1 121.8
 [547] 146.8 138.0 138.0 116.3 122.5 115.0 115.0 119.8  95.0 150.0 117.8 144.2 130.0
 [560] 128.2 135.3 143.9 140.7 130.4 123.2 118.0 120.0 118.9 117.2 120.0 118.1 124.8
 [573] 106.5 116.8 109.3 120.0 137.5 150.0 120.4 136.7 118.5 133.0 128.8 133.0 102.0
 [586] 133.9 127.0 120.4 124.5 123.9 117.8 126.7 110.0 134.7 113.2 141.0 111.5 140.0
 [599] 134.3 125.3 140.0 119.6 170.0 150.5 128.0 108.7 121.6 125.3 117.6 124.3 106.1
 [612] 139.9 110.8 118.0 117.8 127.5 129.7 130.6 126.3 140.0 105.0 114.6 114.6 131.0
 [625] 109.0 132.0 130.0 109.5 115.9 131.6 120.0 109.7 136.4 120.0 132.6 112.9 134.3
 [638] 123.2 117.2 129.8 158.0 116.5 121.0 133.8 115.0 131.8 121.0 152.4 110.2 113.5
 [651] 144.4 143.3 100.0 126.3 115.9 114.9 121.0 112.3 127.0 120.0 180.0 117.4 115.8
 [664] 136.5 129.0 137.6 129.5 129.1 130.2 134.3 138.4 120.0 123.5 116.1 110.8 142.8
 [677] 155.5 126.7 163.5 161.9 123.3 137.5 166.6 103.5 110.0 128.2 137.7 128.8 170.0
 [690] 116.4 100.9 136.0 130.0 100.0 157.0 152.1 162.9 137.2 140.0 146.5 130.0 128.0
 [703] 190.0 133.2 124.3 138.1 144.3 140.0 148.3  96.0 121.7 160.0 110.3 129.0 150.0
 [716] 100.0 107.5 170.0 123.0 138.5 140.0 113.6 170.0 115.5 130.0 140.0 126.6 143.2
 [729] 131.4 133.3 118.3 140.0 124.7 140.0 150.0 115.6 116.9 123.4 146.5 117.1 113.9
 [742] 128.7 132.9 123.0 129.8 156.1 120.0 117.2 107.0 128.4 123.4 126.7 123.0 137.2
 [755] 125.9 138.0 128.2 126.5 112.4 109.0 100.0 144.7 120.0 100.0 154.0 111.3 150.0
 [768] 100.0 162.5 134.1 133.0 119.0 131.1 129.4 123.9 140.0 162.0 131.6 110.6 117.4
 [781] 137.8 106.7 156.9 129.0 124.8 115.1 146.7 132.8 159.1 137.6 124.0 149.0 129.6
 [794] 110.0 116.1 133.3 144.3 133.6 123.2 137.2 130.0 110.0 118.0 128.4 113.6 113.5
 [807] 146.9 141.3 129.7 121.3 109.1 107.1 129.2 154.1 147.2 120.0 130.8 120.8 125.4
 [820] 121.3 127.0 151.6 131.6 106.0 111.6 117.3 121.4 126.1 137.0 120.8 128.7 118.0
 [833] 120.0 160.0 150.0 121.8 125.4 126.6 150.0 114.5 107.0 115.7 120.0 134.8 133.6
 [846] 129.0 128.4 122.2 113.3 129.9 126.2 112.6 149.0 120.0 120.4 128.1 141.7 130.0
 [859] 113.3 105.9 122.7 120.0 119.8 122.9 160.0 125.2 143.4  96.7 126.9 143.1 114.5
 [872] 140.0 113.7 131.5 143.5 126.8 115.2 100.0 121.4 120.0 129.9 151.1 120.0 130.0
 [885] 119.0 122.0 129.7 112.5 136.0 133.1 151.3 133.3 130.8 140.0 150.0 130.0 125.3
 [898] 124.0 113.8 124.4 107.7 110.0 130.0 138.8 126.3 114.5 116.5 128.6 130.0 134.6
 [911] 146.8 135.7 120.0 138.0 135.5 120.0 111.7 100.0 160.0 114.8 131.0  97.0 131.7
 [924] 120.0 110.0 133.0 140.0 100.0 129.3 137.0 122.2 108.0 110.0 127.7 121.3 140.1
 [937] 114.8 150.0 131.7 110.0 105.5 127.3 130.0 130.0 122.7 113.9 151.1 125.8 128.2
 [950] 135.1 120.2 132.8 140.0 129.3 108.2 125.4 140.2 116.1 137.8 128.4 106.0 130.2
 [963] 126.0 141.0 113.0 120.0 130.9 120.0 134.1 120.0 114.8 123.0 118.0 100.0 151.1
 [976] 116.9 106.0 127.1 155.5 101.0 128.2 113.0 122.8 145.6 116.5 142.0 150.0 133.3
 [989] 115.8 100.0 128.6 137.1 149.0 147.0 150.0 103.5 107.8 130.0 109.4 143.6
 [ reached getOption("max.print") -- omitted 3424 entries ]
# ¿Se ajusta a una normal?
# H0: Las notas de admisión se ajustan a una distribución normal
# H1: No H0

# Gráfico de las CDFs

grid <- seq(min(pull(admission_grade)), max(pull(admission_grade)), length.out = 100)
Error en UseMethod("pull"): 
  no applicable method for 'pull' applied to an object of class "c('double', 'numeric')"

normalidad

vamos a mirar las pruebas de normalidad sobre las variables continuas, las variables continuas son: previous qualification (grade) admission grade curricular units 1st sem(grade) curricular units 2nd sem(grade) uneployment rate inflation rate GDP

base_2 <- datos_u
base_2$transformada <- 0 

histo_norm <- function(a){
  
  base_2[[a]] <- as.numeric(base_2[[a]])
  asime <- skewness(base_2[[a]], na.rm = TRUE)
  
  b <- base_2%>% ggplot(aes(x=base_2[[a]],y=..density..))+
    geom_histogram(fill="seagreen2",color="white")+
    geom_line(aes(x=base_2[[a]],y=dnorm(base_2[[a]],mean(base_2[[a]]),sd(base_2[[a]]))),color="deeppink4",size=1)+
    ggtitle(a)+
    labs(x=a,y="densidad ")+
    theme_minimal()
  print(paste("Asimetría:", asime))
  print(lillie.test(base_2[[a]]))
  return(b)
}


library(dplyr)
library(e1071)  # Para usar skewness()


#1
histo_norm("Previous qualification (grade)")
[1] "Asimetría: 0.312655358535117"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.090842, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

print("no sigue una normal, ahora miraremos entre las transformaciones a ver cual ajusta la variable
      a una normal")
[1] "no sigue una normal, ahora miraremos entre las transformaciones a ver cual ajusta la variable\n      a una normal"
base_2$`Previous qualification (grade)` <- as.numeric(base_2$`Previous qualification (grade)`)
columna=base_2$`Previous qualification (grade)`
base_2$`Previous qualification (grade)` <- as.numeric(base_2$`Previous qualification (grade)`)
#hacemos transformacion
base_2 <- base_2 %>% mutate(transformada = sqrt(base_2$`Previous qualification (grade)`))
histo_norm("transformada")
[1] "Asimetría: 0.103692788984921"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.083663, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

base_2 <-  base_2 %>% mutate(transformada = log1p(columna + 1))
histo_norm("transformada")
[1] "Asimetría: -0.0975132315158571"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.092936, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

base_2 <-  base_2  %>% mutate(transformada = 1 / (columna + 1))
histo_norm("transformada")
[1] "Asimetría: 0.511592397367028"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.11288, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#en este caso la mas cercana fue la transformacion al cuadrado sin embargo sigue sin seguir 
#una distribucion normal, esto debido a que se rechazan las pruebas,por lo tanto se tienen que #hacer pruebas no parametricas sobre esta"

#2
base_2$`Admission grade` <- as.numeric(base_2$`Admission grade`)

# Visualiza el histograma original
histo_norm("Admission grade")
[1] "Asimetría: 0.530240105257676"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.065863, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

print("No sigue una normal, sin embargo se podría aproximar con una transformación.")
[1] "No sigue una normal, sin embargo se podría aproximar con una transformación."
# Guarda la columna original
columna1 <- base_2$`Admission grade`

# --- Transformación raíz cuadrada ---
base_2 <- base_2 %>% mutate(transformada = sqrt(columna1))
print("Transformación: raíz cuadrada")
[1] "Transformación: raíz cuadrada"
histo_norm("transformada")
[1] "Asimetría: 0.337736379573868"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.054623, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación logarítmica ---
base_2 <- base_2 %>% mutate(transformada = log1p(columna1 + 1))
print("Transformación: logarítmica")
[1] "Transformación: logarítmica"
histo_norm("transformada")
[1] "Asimetría: 0.156192262192071"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.044161, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación inversa ---
base_2 <- base_2 %>% mutate(transformada = 1 / (columna1 + 1))
print("Transformación: inversa")
[1] "Transformación: inversa"
histo_norm("transformada")
[1] "Asimetría: 0.206335391318819"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.043315, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

#el que presento menos asimetria fue la transformacion logaritmica, sin embargo sigue sin seguir una 
#distribucion normal y rechaza las pruebas de hipotesis entonces se tienen que hace pruebas no parametricas 
#sobre esta 


#3
# Asegura que la variable sea numérica
base_2 <- datos_u
base_2$transformada <-0 

base_2$`Curricular units 1st sem (credited)` <- as.numeric(base_2$`Curricular units 1st sem (credited)`)

# Visualiza el histograma original

histo_norm("Curricular units 1st sem (credited)")
[1] "Asimetría: 4.16622208152399"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.48778, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

print("No sigue una normal, sin embargo se podría aproximar con una transformación.")
[1] "No sigue una normal, sin embargo se podría aproximar con una transformación."
print("intentaremos ver como se comporta si retiramos los valores que son 0")
[1] "intentaremos ver como se comporta si retiramos los valores que son 0"
base_2<- base_2[datos_u$`Curricular units 1st sem (credited)`>0,]
base_2 %>% dim()
[1] 577  38
print("se pierden demasiados datos, no vale la pena ")
[1] "se pierden demasiados datos, no vale la pena "
histo_norm("Curricular units 1st sem (credited)")
[1] "Asimetría: 1.08461384035436"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.15327, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Guarda la columna original
columna2 <- base_2$`Curricular units 1st sem (credited)`

# --- Transformación raíz cuadrada ---
base_2 <- base_2 %>% mutate(transformada = sqrt(columna2))
print("Transformación: raíz cuadrada")
[1] "Transformación: raíz cuadrada"
histo_norm("transformada")
[1] "Asimetría: 0.429406388978208"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.12473, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación logarítmica ---
base_2 <- base_2 %>% mutate(transformada = log1p(columna2 + 1))
print("Transformación: logarítmica")
[1] "Transformación: logarítmica"
histo_norm("transformada")
[1] "Asimetría: 0.198546122229408"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.12695, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación inversa ---
base_2 <- base_2 %>% mutate(transformada = 1 / (columna2 + 1))
print("Transformación: inversa")
[1] "Transformación: inversa"
histo_norm("transformada")
[1] "Asimetría: 0.762692480623509"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.16174, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

print("se tiene que proceder con pruebas no parametricas") 
[1] "se tiene que proceder con pruebas no parametricas"
#4
# Asegura que la variable sea numérica
base_2 <- datos_u
base_2$transformada <- 0

base_2$`Curricular units 2nd sem (grade)` <- as.numeric(base_2$`Curricular units 2nd sem (grade)`)

# Visualiza el histograma original
histo_norm("Curricular units 2nd sem (grade)")
[1] "Asimetría: 0.904985181350275"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.42806, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

print("No sigue una normal, sin embargo se podría aproximar con una transformación.")
[1] "No sigue una normal, sin embargo se podría aproximar con una transformación."
print("Intentaremos ver cómo se comporta si retiramos los valores que son 0")
[1] "Intentaremos ver cómo se comporta si retiramos los valores que son 0"
# Retira los ceros
base_2 <- base_2[base_2$`Curricular units 2nd sem (grade)` > 0, ]
base_2 %>% dim()
[1] 3554   38
print("En este caso perdemos cerca de 1000 datos")
[1] "En este caso perdemos cerca de 1000 datos"
histo_norm("Curricular units 2nd sem (grade)")
[1] "Asimetría: 0.557442281715525"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.38706, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Guarda la columna original
columna3 <- base_2$`Curricular units 2nd sem (grade)`

# --- Transformación raíz cuadrada ---
base_2 <- base_2 %>% mutate(transformada = sqrt(columna3))
print("Transformación: raíz cuadrada")
[1] "Transformación: raíz cuadrada"
histo_norm("transformada")
[1] "Asimetría: 0.50326402541313"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.39143, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación logarítmica ---
base_2 <- base_2 %>% mutate(transformada = log1p(columna3 + 1))
print("Transformación: logarítmica")
[1] "Transformación: logarítmica"
histo_norm("transformada")
[1] "Asimetría: 0.288817167697241"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.2709, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación inversa ---
base_2 <- base_2 %>% mutate(transformada = 1 / (columna3 + 1))
print("Transformación: inversa")
[1] "Transformación: inversa"
histo_norm("transformada")
[1] "Asimetría: 1.07368030709016"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.45525, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Conclusión
print("Se debe considerar usar pruebas no paramétricas si las transformaciones no logran normalizar la variable.")
[1] "Se debe considerar usar pruebas no paramétricas si las transformaciones no logran normalizar la variable."
#5
# Asegura que la variable sea numérica y reinicia base_2
base_2 <- datos_u
base_2$transformada <- 0

base_2$`Inflation rate` <- as.numeric(base_2$`Inflation rate`)

# Visualiza el histograma original
histo_norm("Inflation rate")
[1] "Asimetría: -0.0614843495211974"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.34866, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

print("No sigue una normal, sin embargo se podría aproximar con una transformación.")
[1] "No sigue una normal, sin embargo se podría aproximar con una transformación."
print("Intentaremos ver cómo se comporta si retiramos los valores que son 0")
[1] "Intentaremos ver cómo se comporta si retiramos los valores que son 0"
# Retira los ceros
base_2 <- base_2[base_2$`Inflation rate` != 0, ]
base_2 %>% dim()
[1] 4424   38
print("podemos ver que se pierden mas de mil datos")
[1] "podemos ver que se pierden mas de mil datos"
# Revisa de nuevo el histograma con los datos sin ceros
histo_norm("Inflation rate")
[1] "Asimetría: -0.0614843495211974"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.34866, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Guarda la columna original sin ceros
columna4 <- base_2$`Inflation rate`

# --- Transformación raíz cuadrada ---
base_2 <- base_2 %>% mutate(transformada = sqrt(columna4))
Aviso: There was 1 warning in `mutate()`.
ℹ In argument: `transformada = sqrt(columna4)`.
Caused by warning in `sqrt()`:
! Se han producido NaNs
print("Transformación: raíz cuadrada")
[1] "Transformación: raíz cuadrada"
histo_norm("transformada")
[1] "Asimetría: -0.634429754110677"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.41868, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Aviso: Removed 923 rows containing non-finite outside the scale range (`stat_bin()`).
Aviso: Removed 4424 rows containing missing values or values outside the scale range
(`geom_line()`).

# --- Transformación logarítmica ---
base_2 <- base_2 %>% mutate(transformada = log1p(columna4 + 1))
print("Transformación: logarítmica")
[1] "Transformación: logarítmica"
histo_norm("transformada")
[1] "Asimetría: -0.067007839899423"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.34897, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación inversa ---
base_2 <- base_2 %>% mutate(transformada = 1 / (columna4 + 1))
print("Transformación: inversa")
[1] "Transformación: inversa"
histo_norm("transformada")
[1] "Asimetría: 1.99843146943972"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.32869, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Conclusión
print("ni con trtamiento atipico de datos, ni con trasnformaciones se pudo evidenciar que siguiera una normal, se debe proceder con pruebas no parametricas ")
[1] "ni con trtamiento atipico de datos, ni con trasnformaciones se pudo evidenciar que siguiera una normal, se debe proceder con pruebas no parametricas "
#6

# Asegura que la variable sea numérica y reinicia base_2
base_2 <- datos_u
base_2$transformada <- 0

base_2$GDP <- as.numeric(base_2$GDP)

# Visualiza el histograma original
histo_norm("GDP")
[1] "Asimetría: 2.78997323116808"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.53231, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

print("No sigue una normal, sin embargo se podría aproximar con una transformación.")
[1] "No sigue una normal, sin embargo se podría aproximar con una transformación."
print("Intentaremos ver cómo se comporta si retiramos los valores que son 0")
[1] "Intentaremos ver cómo se comporta si retiramos los valores que son 0"
# Retira los ceros
base_2 <- base_2[base_2$GDP > 0, ]
base_2 %>% dim()
[1] 2713   38
print("se pierden mas de 2000 datos")
[1] "se pierden mas de 2000 datos"
# Revisa de nuevo el histograma con los datos sin ceros
histo_norm("GDP")
[1] "Asimetría: 1.93108563062652"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.51168, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Guarda la columna original sin ceros
columna5 <- base_2$GDP

# --- Transformación raíz cuadrada ---
base_2 <- base_2 %>% mutate(transformada = sqrt(columna5))
print("Transformación: raíz cuadrada")
[1] "Transformación: raíz cuadrada"
histo_norm("transformada")
[1] "Asimetría: 1.93096869623263"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.50827, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación logarítmica ---
base_2 <- base_2 %>% mutate(transformada = log1p(columna5 + 1))
print("Transformación: logarítmica")
[1] "Transformación: logarítmica"
histo_norm("transformada")
[1] "Asimetría: 1.90589861228058"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.45762, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# --- Transformación inversa ---
base_2 <- base_2 %>% mutate(transformada = 1 / (columna5 + 1))
print("Transformación: inversa")
[1] "Transformación: inversa"
histo_norm("transformada")
[1] "Asimetría: -0.0151785374435241"

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  base_2[[a]]
D = 0.20153, p-value < 0.00000000000000022
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
Aviso: Use of `base_2[[a]]` is discouraged.
ℹ Use `.data[[a]]` instead.
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

# Conclusión
print("a pesar de las trasnformaciones no muestra seguir una distribucion normal, se tendra que manejar con pruebas no parametricas ")
[1] "a pesar de las trasnformaciones no muestra seguir una distribucion normal, se tendra que manejar con pruebas no parametricas "

““” NInguna de las variables continuas se puede manejar como una normal, por lo tanto a todas se les tendra que hacer pruebas no parametricas

““”

cat("h0: La media muestral (o mediana) de créditos aprobados en el primer semestre de los Dropout es menor o igual a la de los Graduados.

H₁: La media muestral de los que aprueban todos sus créditos en primer semestre pero no se gradúan es mayor que la de los que sí se gradúan.
")
h0: La media muestral (o mediana) de créditos aprobados en el primer semestre de los Dropout es menor o igual a la de los Graduados.

H₁: La media muestral de los que aprueban todos sus créditos en primer semestre pero no se gradúan es mayor que la de los que sí se gradúan.
cat("Miramos si el comportamiento de las dos gráficas es normal:\n")
Miramos si el comportamiento de las dos gráficas es normal:
histograma_bi("Curricular units 1st sem (approved)","Target")


cat("Notamos que no siguen una distribución normal, por lo tanto 
usamos transformaciones:\n")
Notamos que no siguen una distribución normal, por lo tanto 
usamos transformaciones:
datos_u <- datos_u %>% mutate(approves_log = log1p(`Curricular units 1st sem (approved)`))
histograma_bi("approves_log","Target")


cat("Probamos pruebas de normalidad sobre estas dos variables:\n")
Probamos pruebas de normalidad sobre estas dos variables:
descripcion("approves_log","Target")

 Descriptive statistics by group 
group: Dropout
------------------------------------------------------------------ 
group: Enrolled
------------------------------------------------------------------ 
group: Graduate
datos_drop <- datos_u %>% filter(Target == "Dropout")
datos_grad <- datos_u %>% filter(Target=="Graduate")

options(scipen = 999)

lillie.test(datos_drop$approves_log)

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  datos_drop$approves_log
D = 0.26696, p-value < 0.00000000000000022
lillie.test(datos_grad$approves_log)

    Lilliefors (Kolmogorov-Smirnov) normality test

data:  datos_grad$approves_log
D = 0.28477, p-value < 0.00000000000000022
cat("Aún no siguen una normal :( \n")
Aún no siguen una normal :( 
# Prueba No Paramétrica: -----

wilcox.test(
  datos_drop$`Curricular units 1st sem (approved)`, 
  datos_grad$`Curricular units 1st sem (approved)`, 
  alternative = "greater"
)

    Wilcoxon rank sum test with continuity correction

data:  datos_drop$`Curricular units 1st sem (approved)` and datos_grad$`Curricular units 1st sem (approved)`
W = 444728, p-value = 1
alternative hypothesis: true location shift is greater than 0

El p-value es mayor a 0.005 entonces no se rechaza h0.

LS0tDQp0aXRsZTogUHJveWVjdG8gYnJvYmFiaWxpZGFkIHkgZXN0YWRpc3RpY2EgMg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KUHJpbWVybywgaW1wb3J0YW1vcyB0b2RhcyBsYXMgbGlicmVyw61hcyBxdWUgdmFtb3MgYSB1c2FyIGEgbG8gbGFyZ28gZGUgbGEgcmVhbGl6YWNpw7NuIGRlIGVzdGUgcHJveWVjdG86DQoNCmBgYHtyfQ0KaWYgKCFyZXF1aXJlKCdSQ29sb3JCcmV3ZXInKSkgaW5zdGFsbC5wYWNrYWdlcygnUkNvbG9yQnJld2VyJykNCmlmICghcmVxdWlyZSgnY29ycnBsb3QnKSkgaW5zdGFsbC5wYWNrYWdlcygnY29ycnBsb3QnKQ0KaWYgKCFyZXF1aXJlKCdHR2FsbHknKSkgaW5zdGFsbC5wYWNrYWdlcygnR0dhbGx5JykNCmlmICghcmVxdWlyZSgnbW9tZW50cycpKSBpbnN0YWxsLnBhY2thZ2VzKCdtb21lbnRzJykNCmlmICghcmVxdWlyZSgnZml0ZGlzdHJwbHVzJykpIGluc3RhbGwucGFja2FnZXMoJ2ZpdGRpc3RycGx1cycpDQppZiAoIXJlcXVpcmUoJ3RpZHl2ZXJzZScpKSBpbnN0YWxsLnBhY2thZ2VzKCd0aWR5dmVyc2UnKQ0KaWYgKCFyZXF1aXJlKCdwc3ljaCcpKSBpbnN0YWxsLnBhY2thZ2VzKCdwc3ljaCcpDQppZiAoIXJlcXVpcmUoJ25vcnRlc3QnKSkgaW5zdGFsbC5wYWNrYWdlcygnbm9ydGVzdCcpDQpsaWJyYXJ5KCdSQ29sb3JCcmV3ZXInKQ0KbGlicmFyeSgnY29ycnBsb3QnKQ0KbGlicmFyeSgnR0dhbGx5JykNCmxpYnJhcnkoJ21vbWVudHMnKQ0KbGlicmFyeSgnZml0ZGlzdHJwbHVzJykNCmxpYnJhcnkoJ3RpZHl2ZXJzZScpDQpsaWJyYXJ5KCdkcGx5cicpDQpsaWJyYXJ5KCd0aWR5c2VsZWN0JykNCmxpYnJhcnkoJ3BzeWNoJykNCmxpYnJhcnkoJ25vcnRlc3QnKQ0KYGBgDQoNCkx1ZWdvLCBpbXBvcnRhbW9zIGxhIGJhc2UgZGUgZGF0b3MgY29tbyB1biBkYXRhZnJhbWUsIGNhYmUgYWNsYXJhciBxdWUgcmV2aXNhbW9zIGxhIGNsYXNlIGRlbCBkYXRhZnJhbWUuIEVzdG8gbm9zIGF5dWRhcsOhIGEgdmVyaWZpY2FyIHF1ZSBsYSBiYXNlIHNlIGhheWEgY2FyZ2FkbyBjb3JyZWN0YW1lbnRlLCBwb3JxdWUgZW4gY2FzbyBkZSBubyBoYWJlcnNlIGNhcmdhZG8sIGFwYXJlY2Vyw6EgY29tbyAiZnVuY3Rpb24iOg0KDQpgYGB7cn0NCmRhdG9zX3UgPC0gZGF0YQ0KDQpjbGFzcyhkYXRvc191KQ0KYGBgDQoNCkluaWNpYWxtZW50ZSBoYWNlbW9zIGVsIGFuw6FsaXNpcyBkZSB2YXJpYWJsZXMgY2F0ZWfDs3JpY2FzLCBwYXJhIGVsbG8gY3JlYXJlbW9zIHVuYSB2YXJpYWJsZSBhcGFydGUgeSBhanVzdGFyZW1vcyBzdXMgdGlwb3MgZGUgZGF0b3M6IA0KDQpgYGB7cn0NCmJhc2VfY2F0ZSA8LSBkYXRvc191ICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1gUHJldmlvdXMgcXVhbGlmaWNhdGlvbiAoZ3JhZGUpYCwNCiAgICAgICAgICAgICAgICAtYE1vdGhlcidzIHF1YWxpZmljYXRpb25gLA0KICAgICAgICAgICAgICAgIC1gRmF0aGVyJ3MgcXVhbGlmaWNhdGlvbmAsDQogICAgICAgICAgICAgICAgLWBNb3RoZXIncyBvY2N1cGF0aW9uYCwNCiAgICAgICAgICAgICAgICAtYEZhdGhlcidzIG9jY3VwYXRpb25gLA0KICAgICAgICAgICAgICAgIC1gQWRtaXNzaW9uIGdyYWRlYCwNCiAgICAgICAgICAgICAgICAtYEFnZSBhdCBlbnJvbGxtZW50YCwNCiAgICAgICAgICAgICAgICAtYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoY3JlZGl0ZWQpYCwNCiAgICAgICAgICAgICAgICAtYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZW5yb2xsZWQpYCwNCiAgICAgICAgICAgICAgICAtYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZXZhbHVhdGlvbnMpYCwNCiAgICAgICAgICAgICAgICAtYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoYXBwcm92ZWQpYCwNCiAgICAgICAgICAgICAgICAtYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZ3JhZGUpYCwNCiAgICAgICAgICAgICAgICAtYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAod2l0aG91dCBldmFsdWF0aW9ucylgLA0KICAgICAgICAgICAgICAgIC1gQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChjcmVkaXRlZClgLA0KICAgICAgICAgICAgICAgIC1gQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChlbnJvbGxlZClgLA0KICAgICAgICAgICAgICAgIC1gQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChldmFsdWF0aW9ucylgLA0KICAgICAgICAgICAgICAgIC1gQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChhcHByb3ZlZClgLA0KICAgICAgICAgICAgICAgIC1gQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChncmFkZSlgLA0KICAgICAgICAgICAgICAgIC1gQ3VycmljdWxhciB1bml0cyAybmQgc2VtICh3aXRob3V0IGV2YWx1YXRpb25zKWAsDQogICAgICAgICAgICAgICAgLWBVbmVtcGxveW1lbnQgcmF0ZWAsDQogICAgICAgICAgICAgICAgLWBJbmZsYXRpb24gcmF0ZWAsDQogICAgICAgICAgICAgICAgLWBHRFBgKSAlPiUNCiAgZ2xpbXBzZSgpDQoNCiMgQW7DoWxpc2lzIERlc2NyaXB0aXZvOiAtLS0tDQoNCiMgVW5pdmFyaWFkYXM6IC0tLS0NCg0KYmFzZV9jYXRlIDwtIGJhc2VfY2F0ZSAlPiUgDQogIG11dGF0ZShhY3Jvc3MoYyhgQXBwbGljYXRpb24gbW9kZWAsDQogICAgICAgICAgICAgICAgICBgQXBwbGljYXRpb24gb3JkZXJgLA0KICAgICAgICAgICAgICAgICAgYENvdXJzZWAsDQogICAgICAgICAgICAgICAgICBgRGF5dGltZS9ldmVuaW5nIGF0dGVuZGFuY2VgLA0KICAgICAgICAgICAgICAgICAgYFByZXZpb3VzIHF1YWxpZmljYXRpb25gLA0KICAgICAgICAgICAgICAgICAgYE5hY2lvbmFsaXR5YCwNCiAgICAgICAgICAgICAgICAgIGBEaXNwbGFjZWRgLA0KICAgICAgICAgICAgICAgICAgYEVkdWNhdGlvbmFsIHNwZWNpYWwgbmVlZHNgLA0KICAgICAgICAgICAgICAgICAgYERlYnRvcmAsDQogICAgICAgICAgICAgICAgICBgVHVpdGlvbiBmZWVzIHVwIHRvIGRhdGVgLA0KICAgICAgICAgICAgICAgICAgYEdlbmRlcmAsDQogICAgICAgICAgICAgICAgICBgU2Nob2xhcnNoaXAgaG9sZGVyYCwNCiAgICAgICAgICAgICAgICAgIGBJbnRlcm5hdGlvbmFsYCwNCiAgICAgICAgICAgICAgICAgIGBNYXJpdGFsIHN0YXR1c2AsDQogICAgICAgICAgICAgICAgICBgVGFyZ2V0YCksIGFzLmZhY3RvcikpDQpgYGANCg0KQ29uc3RydWltb3MgbGFzIHRhYmxhcyBkZSBmcmVjdWVuY2lhIHkgc3VzIHJlc3BlY3RpdmFzIGdyw6FmaWNhcy4gUGFyYSBlc3RvIHVzYXJlbW9zIGxhcyBzaWd1aWVudGVzIGZ1bmNpb25lczoNCg0KYGBge3J9DQp0YWJsYV9mcmVjIDwtIGZ1bmN0aW9uKGNvbHVtbmEpIHsNCiAgdGFibGEgPC0gdGFibGUoYmFzZV9jYXRlW1tjb2x1bW5hXV0pDQogIHJldHVybihwcm9wLnRhYmxlKHRhYmxhKSkNCn0NCg0KZ3JhZmljYSA8LSBmdW5jdGlvbihjb2x1bW5hKXsNCiAgYmFzZV9jYXRlICU+JQ0KICAgIGdncGxvdChhZXMoeCA9IC5kYXRhW1tjb2x1bW5hXV0pKSArDQogICAgZ2VvbV9iYXIoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gInB1cnBsZSIpICsNCiAgICBnZ3RpdGxlKHBhc3RlKCJEaWFncmFtYSBkZSBiYXJyYXMgZGUiLCBjb2x1bW5hKSkgKw0KICAgIGxhYnMoeCA9IGNvbHVtbmEsIHkgPSAiRnJlY3VlbmNpYSIpICsNCiAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHNpemUgPSA4KSkNCn0NCg0KDQp0YWJsYV9ncmFmaWNhIDwtIGZ1bmN0aW9uKGNvbHVtbmEpew0KICBwcmludCh0YWJsYV9mcmVjKGNvbHVtbmEpKQ0KICBncmFmaWNhKGNvbHVtbmEpDQp9DQoNCmBgYA0KDQpFamVjdXRhbW9zIGNhZGEgdW5vIGRlIGxvcyBhbsOhbGlzaXMgcXVlIHNlIG9idHV2aWVyb24gZGVzZGUgbGFzIGdyw6FmaWNhczogDQoNCmBgYHtyfQ0KdGFibGFfZ3JhZmljYSgiTWFyaXRhbCBzdGF0dXMiKQ0KY2F0KCJQb2RlbW9zIG5vdGFyIHF1ZSBlbCA4OC41ODQ5JSBkZSBsb3MgZXN0dWRpYW50ZXMgc29uIHNvbHRlcm9zIHkgdGFtYmllbiBxdWUgDQogICAgZWwgOC41NjY5JSBzb24gY2FzYWRvcy5cbiIpDQoNCmBgYA0KDQoNCg0KYGBge3J9DQp0YWJsYV9ncmFmaWNhKCJDb3Vyc2UiKQ0KY2F0KCJFbCBjdXJzbyBjb24gbcOhcyBwb3JjZW50YWplIGRlIGluc2NyaXBjacOzbiBlcyBlbCA5NTAwLCBlbCBjdWFsIGVzDQogICAgRW5mZXJtZXLDrWEsIG1pZW50cmFzIHF1ZSBlbCBxdWUgdGllbmUgbWVub3MsIGVzIGVsIGN1cnNvIDMzLCBlbCBjdWFsDQogICAgVGVjbm9sb2fDrWFzIGRlIFByb2R1Y2Npw7NuIGRlIEJpb2NvbWJ1c3RpYmxlcy5cbiIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KdGFibGFfZ3JhZmljYSgiRGF5dGltZS9ldmVuaW5nIGF0dGVuZGFuY2UiKQ0KY2F0KCJFbCA4OS4wODIyJSBkZSBsb3MgZXN0dWRpYW50ZXMgZXN0dWRpYSBkZSBkw61hLCBtaWVudHJhcyBxdWUgZWwgMTAuOTE3NyUgZGUgDQogICAgbm9jaGUuXG4iKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnRhYmxhX2dyYWZpY2EoIlByZXZpb3VzIHF1YWxpZmljYXRpb24iKQ0KY2F0KCJFbCDDumx0aW1vIHTDrXR1bG8gZGVsIDg0LjAxODklIGRlIGxvcyBlc3R1ZGlhbnRlcyBlcyBsYSBFc2N1ZWxhIFNlY3VuZGFyaWEsIA0KICAgIG1pZW50cmFzIHF1ZSBlbCBkZWwgMjguNDgxMCUgZXMgZGUgRWR1Y2FjacOzbiBTdXBlcmlvci5cbiIpDQoNCmBgYA0KDQoNCg0KYGBge3J9DQp0YWJsYV9ncmFmaWNhKCJOYWNpb25hbGl0eSIpDQpjYXQoIkVsIDk3LjUxMzUlIGRlIGxvcyBlc3R1ZGlhbnRlcyBlcyBkZSBQb3J0dWdhbCwgbWllbnRyYXMgcXVlIGVsIHBvcmNlbnRhamUgDQogICAgZGUgZXN0dWRpYW50ZXMgY29sb21iaWFub3MgZXMgZGUgMCwwMjI2JSA6KCBcbiIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KdGFibGFfZ3JhZmljYSgiRGlzcGxhY2VkIikNCmNhdCgiRWwgNTQuODM3MiUgZGUgbG9zIGVzdHVkaWFudGVzIHNvbiBkZXNwbGF6YWRvcywgbG8gY3VhbCBsbGVnYSBzZXIgdW4gDQogICAgcG9yY2VudGFqZSBhbHRvLlxuIikNCmBgYA0KDQoNCg0KYGBge3J9DQp0YWJsYV9ncmFmaWNhKCJEZWJ0b3IiKQ0KY2F0KCJBbsOhbGlzaXMiKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCnRhYmxhX2dyYWZpY2EoIlR1aXRpb24gZmVlcyB1cCB0byBkYXRlIikNCmNhdCgiRWwgODguMDY1MSUgZGUgbG9zIGVzdHVkaWFudGVzIHRpZW5lbiBzdSBtYXRyw61jdWxhIGFsIGTDrWEuXG4iKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KdGFibGFfZ3JhZmljYSgiR2VuZGVyIikNCmNhdCgiUG9kZW1vcyBldmlkZW5jaWFyIHF1ZSBlbCBwb3JjZW50YWplIGRlIG11amVyZXMgY29uIHJlc3BlY3RvIGEgaG9tYnJlcyBlcyANCiAgICBtw6FzIGFsdG8sIGVzdG8gY29uIHVuIDY0LjgyODIlIGRlIGVzdHVkaWFudGVzIG11amVyZXMgeSB1biAzNS4xNzE3JSBkZSANCiAgICBlc3R1ZGlhbnRlcyBob21icmVzLlxuIikNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCnRhYmxhX2dyYWZpY2EoIlNjaG9sYXJzaGlwIGhvbGRlciIpDQpjYXQoIkxvZ3JhbW9zIGV2aWRlbmNpYXIgcXVlIGVsIHBvcmNlbnRhamUgZGUgZXN0dWRpYW50ZXMgYmVjYWRvcyBlcyBtdXkgYmFqbywNCiAgICBzaWVuZG8gc8OzbG8gZWwgMjQuODQxNyUgZXN0dWRpYW50ZXMgYmVjYWRvcywgbWllbnRyYXMgcXVlIGVsIDc1LjE1ODIlIG5vIHNvbg0KICAgIGJlY2Fkb3MuXG4iKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KdGFibGFfZ3JhZmljYSgiSW50ZXJuYXRpb25hbCIpDQpjYXQoIkFuw6FsaXNpcyIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KdGFibGFfZ3JhZmljYSgiVGFyZ2V0IikNCmNhdCgiRWwgcG9yY2VudGFqZSBkZSBsb3MgZXN0dWRpYW50ZXMgcXVlIHNlIGdyYWTDumFuIGVzIGVsIDQ5LjkzMjElLCBtaWVudHJhcyBxdWUNCiAgICBsb3MgcXVlIG5vIGxvZ3JhbiBncmFkdWFyc2UgZXMgZWwgMzIuMTIwMiUuXG4iKQ0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KdGFibGFfZ3JhZmljYSgiRWR1Y2F0aW9uYWwgc3BlY2lhbCBuZWVkcyIpDQpjYXQoIkVMIHBvcmNlbnRhamUgZGUgZXN0dWRpYW50ZXMgcXVlIG5lY2VzaXRhbiBFZHVjYWNpw7NuIEVzcGVjaWFsIGVzIG11eSBiYWpvLA0KICAgIGNvbiB1biAxLjE1MjglIGRlIGVzdHVkaWFudGVzLlxuIikNCg0KYGBgDQoNCkFob3JhLCBoYXJlbW9zIGVsIGFuw6FsaXNpcyBiaXZhcmlhZG8gcGFyYSBjYWRhIHVuYSBkZSBsYXMgdmFyaWFibGVzIHJlbGV2YW50ZXMgY29uIHJlc3BlY3RvIGEgVGFyZ2V0KEVzdGFkbyBkZWwgZXN0dWRpYW50ZTogR3JhZHVhdGUsIERyb3BvdXQsIEVucm9sbGVkKToNCg0KYGBge3J9DQojIFRhYmxhcyBkZSBmcmVjdWVuY2lhIHkgZ3LDoWZpY29zIGJpdmFyaWFkb3M6LS0tLS0tLS0tDQoNCnRhYmxhZG9ibGUgPC0gZnVuY3Rpb24oY29sdW1uYTEsY29sdW1uYTIpew0KICB0YWJsYTIgPC0gdGFibGUoYmFzZV9jYXRlW1tjb2x1bW5hMV1dLGJhc2VfY2F0ZVtbY29sdW1uYTJdXSkNCiAgcmV0dXJuKHJvdW5kKHByb3AudGFibGUodGFibGEyKSw0KSkNCn0NCg0KIyBncmFmaWNhZG9ibGUgPC0gZnVuY3Rpb24oY29sdW1uYTEsY29sdW1uYTIpew0KIyAgIGdyYWZpY2EgPC0gZ2dwbG90KGJhc2VfY2F0ZSwNCiMgICAgICAgICAgICAgIGFlcyh4PWJhc2VfY2F0ZVtbY29sdW1uYTFdXSxmaWxsPWJhc2VfY2F0ZVtbY29sdW1uYTJdXSkpKw0KIyAgICAgICAgICAgICAgZ2VvbV9iYXIoKSt0aGVtZV9taW5pbWFsKCkrDQojICAgICAgICAgICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9MzAsc2l6ZT04KSkNCiMgICAgIHJldHVybihncmFmaWNhKQ0KIyB9DQoNCmdyYWZpY29fYXBpbGFkbyA8LSBmdW5jdGlvbih2YXJpYWJsZTEsdmFyaWFibGUyKXsNCiAgYmFycmFzX3RhcmdldCA8LSBnZ3Bsb3QoYmFzZV9jYXRlLCBhZXMoeCA9IC5kYXRhW1t2YXJpYWJsZTFdXSwgZmlsbCA9IC5kYXRhW1t2YXJpYWJsZTJdXSkpICsgDQogICAgZ2VvbV9iYXIocG9zaXRpb249ImZpbGwiKSsgdGhlbWVfbWluaW1hbCgpKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTMwLCBzaXplPTgpKQ0KICByZXR1cm4oYmFycmFzX3RhcmdldCkNCn0NCg0KVEdPIDwtIGZ1bmN0aW9uKGNvbHVtbmExLGNvbHVtbmEyKXsNCiAgcHJpbnQodGFibGFkb2JsZShjb2x1bW5hMSxjb2x1bW5hMikpDQogIGdyYWZpY29fYXBpbGFkbyhjb2x1bW5hMSxjb2x1bW5hMikNCn0NCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KVEdPKCJUYXJnZXQiLCJOYWNpb25hbGl0eSIpDQpjYXQoIkxvcyBlc3R1ZGlhbnRlcyBjb24gbcOhcyBwb3JjZW50YWplIGRlIGdyYWR1YWNpw7NuIHNvbiBkZSBQb3J0dWdhbCBjb24gZWwNCiAgICAzMS40MCUsIGVudG9uY2VzIGNvbmN1ZXJkYSBjb24gcXVlIHNlYSBlbCBwYcOtcyBjb24gbcOhcyBlc3R1ZGlhbnRlcy4gQWhvcmEsDQogICAgc2luIGNvbnNpZGVyYXIgYSBQb3J0dWdhbCwgZWwgcGHDrXMgY29uIG3DoXMgcG9yY2VudGFqZSBkZSBncmFkdWFjacOzbiBlcw0KICAgIEJyYXNpbCwgY29uIHVuIDMuMiUgZGUgZ3JhZHVhZG9zLlxuIikNCmBgYA0KDQoNCg0KYGBge3J9DQpUR08oIlRhcmdldCIsIkVkdWNhdGlvbmFsIHNwZWNpYWwgbmVlZHMiKQ0KY2F0KCJQb2RlbW9zIG9ic2VydmFyIHF1ZSBsb3MgZXN0dWRpYW50ZXMgcXVlIG5lY2VzaXRhbiBFZHVjYWNpw7NuIEVzcGVjaWFsIHRpZW5lbg0KICAgIG1heW9yIHBvcmNlbnRhamUgZGUgZGVzZXJjacOzbiwgY29uIHVuIDUuMiUsIG1pZW50cmFzIHF1ZSBzdSBwb3JjZW50YWplIGRlDQogICAgZ3JhZHVhY2nDs24gZXMgZGVsIDMuOCUuXG4iKQ0KYGBgDQoNCg0KDQpgYGB7cn0NClRHTygiVGFyZ2V0IiwiR2VuZGVyIikNCmNhdCgiRWwgcG9yY2VudGFqZSBkZSBob21icmVzIHF1ZSBubyBzZSBncmFkw7phbiwgY29uIHVuIDE1Ljg1JSwgZXMgbWF5b3IgYWwNCiAgICBwb3JjZW50YWplIGRlIGFxdWVsbG9zIHF1ZSBzZSBncmFkw7phbi5cbiIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KVEdPKCJUYXJnZXQiLCJUdWl0aW9uIGZlZXMgdXAgdG8gZGF0ZSIpDQpjYXQoIkxvcyBlc3R1ZGlhbnRlcyBxdWUgbm8gZXN0w6FuIGFsIGTDrWEgY29uIHN1IHBhZ28geSB0aWVuZGVuIGEgbm8gZ3JhZHVhcnNlLCBlcw0KICAgIGRlbCAxMC4zMyUuXG4iKQ0KYGBgDQoNCg0KDQpgYGB7cn0NClRHTygiVGFyZ2V0IiwiRGF5dGltZS9ldmVuaW5nIGF0dGVuZGFuY2UiKQ0KY2F0KCJBbCBzZXIgZWwgcG9yY2VudGFqZSBkZSBwZXJzb25hcyBxdWUgZXN0dWRpYW4gZW4gbGEgbm9jaGUsIGVzIG11Y2hvIG3DoXMgYmFqbw0KICAgIHF1ZSBhcXVlbGxvcyBxdWUgZXN0dWRpYW4gZGUgZMOtYSwgcG9yIGxvIHRhbnRvLCBubyB0aWVuZSBtdWNobyBzZW50aWRvDQogICAgY29tcGFyYXJsb3MsIHNpbiBlbWJhcmdvLCBlbCBwb3JjZW50YWplIGRlIGVzdHVkaWFudGVzIHF1ZSBlc3R1ZGlhbiBlbiBsYQ0KICAgIG5vY2hlIHkgc2UgZ3JhZMO6YW4gZXMgbGV2ZW1lbnRlIG3DoXMgcGVxdWXDsW8gcXVlIGVsIHBvcmNlbnRhamUgZGUgYXF1ZWxsb3MgcXVlDQogICAgbm8gc2UgZ3JhZMO6YW4uQXPDrSwgdmVtb3MgcXVlIGVsIDQuNTQlIHNlIGdyYWR1YSB5IGVsIDQuNjglIG5vIHNlIGdyYWR1YS5cbiIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KVEdPKCJUYXJnZXQiLCJTY2hvbGFyc2hpcCBob2xkZXIiKQ0KY2F0KCJFbCBwb3JjZW50YWplIGRlIGVzdHVkaWFudGVzIGJlY2Fkb3MgcXVlIHNlIGdyYWTDumFuLCBlcyBtYXlvciBxdWUgYXF1ZWxsb3MNCiAgICBiZWNhZG9zIHF1ZSBubyBzZSBncmFkw7phbi4gRXN0byBjb24gdW4gMTguODclIGRlIGJlY2Fkb3MgZ3JhZHVhZG9zIHkgdW4gMy4wMyUNCiAgICBkZSBiZWNhZG9zIG5vIGdyYWR1YWRvcy5cbiIpDQpgYGANCg0KSGFjZW1vcyBsbyBtaXNtbyBwYXJhIGxhcyB2YXJpYWJsZXMgY3VhbGl0YXRpdmFzLiBQYXJhIGFuYWxpemFyIGxhcyB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBkZWwgY29uanVudG8gZGUgZGF0b3MsIGltcGxlbWVudGFtb3MgdmFyaWFzIGZ1bmNpb25lcyBxdWUgbm9zIHBlcm1pdGVuIGNvbm9jZXIgY8OzbW8gc2UgY29tcG9ydGFuOg0KDQpgYGB7cn0NCmJhc2VfY3VhbnQgPC0gZGF0b3NfdSAlPiUNCiAgZHBseXI6OnNlbGVjdCgtYE1hcml0YWwgc3RhdHVzYCwNCiAgICAgICAgICAgICAgICAtYEFwcGxpY2F0aW9uIG1vZGVgLA0KICAgICAgICAgICAgICAgIC1gQXBwbGljYXRpb24gb3JkZXJgLA0KICAgICAgICAgICAgICAgIC1gQ291cnNlYCwNCiAgICAgICAgICAgICAgICAtYERheXRpbWUvZXZlbmluZyBhdHRlbmRhbmNlYCwNCiAgICAgICAgICAgICAgICAtYFByZXZpb3VzIHF1YWxpZmljYXRpb25gLA0KICAgICAgICAgICAgICAgIC1gTmFjaW9uYWxpdHlgLA0KICAgICAgICAgICAgICAgIC1gRGlzcGxhY2VkYCwNCiAgICAgICAgICAgICAgICAtYEVkdWNhdGlvbmFsIHNwZWNpYWwgbmVlZHNgLA0KICAgICAgICAgICAgICAgIC1gRGVidG9yYCwNCiAgICAgICAgICAgICAgICAtYFR1aXRpb24gZmVlcyB1cCB0byBkYXRlYCwNCiAgICAgICAgICAgICAgICAtYEdlbmRlcmAsDQogICAgICAgICAgICAgICAgLWBTY2hvbGFyc2hpcCBob2xkZXJgLA0KICAgICAgICAgICAgICAgIC1gSW50ZXJuYXRpb25hbGAsDQogICAgICAgICAgICAgICAgLWBUYXJnZXRgKSAlPiUNCiAgZ2xpbXBzZSgpDQpgYGANCg0KQWhvcmEsIGNvbnZlcnRpbW9zIHRvZGFzIG51ZXN0cmFzIHZhcmlhYmxlcyBjdWFudGl0YXRpYXMgYSB0aXBvIG51bWVyaWMsIGVzdG8gY29uIGVsIGZpbiBkZSBwb2RlciBsYXMgZ3LDoWZpY2FzIGRlIGxvcyBib3hwbG90LCBoaXN0cm9ncmFtYXMgeSBwcnVlYmFzIGRlIGNvcnJlbGFjacOzbiwgYXPDrSBtaXNtbyBtaXJhbW9zIHF1ZSBzZSBoYXlhbiB0cmFuc2Zvcm1hZG86DQoNCmBgYHtyfQ0KYmFzZV9jdWFudCA8LSBkYXRvc191ICU+JSBkcGx5cjo6c2VsZWN0KGFsbF9vZih2YXJzX2N1YW50KSkgJT4lIGRwbHlyOjptdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSx+YXMubnVtZXJpYyguKSkpIA0KYmFzZV9jdWFudCAlPiUgZGltKCkNCg0Kc2FwcGx5KGJhc2VfY3VhbnQsIGNsYXNzKQ0KDQp2YXJzX2N1YW50IDwtIGMoDQogICJQcmV2aW91cyBxdWFsaWZpY2F0aW9uIChncmFkZSkiLA0KICAiTW90aGVyJ3MgcXVhbGlmaWNhdGlvbiIsDQogICJGYXRoZXIncyBxdWFsaWZpY2F0aW9uIiwNCiAgIk1vdGhlcidzIG9jY3VwYXRpb24iLA0KICAiRmF0aGVyJ3Mgb2NjdXBhdGlvbiIsDQogICJBZG1pc3Npb24gZ3JhZGUiLA0KICAiQWdlIGF0IGVucm9sbG1lbnQiLA0KICAiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChjcmVkaXRlZCkiLA0KICAiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChlbnJvbGxlZCkiLA0KICAiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChldmFsdWF0aW9ucykiLA0KICAiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChhcHByb3ZlZCkiLA0KICAiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChncmFkZSkiLA0KICAiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtICh3aXRob3V0IGV2YWx1YXRpb25zKSIsDQogICJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGNyZWRpdGVkKSIsDQogICJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGVucm9sbGVkKSIsDQogICJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGV2YWx1YXRpb25zKSIsDQogICJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGFwcHJvdmVkKSIsDQogICJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGdyYWRlKSIsDQogICJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKHdpdGhvdXQgZXZhbHVhdGlvbnMpIiwNCiAgIlVuZW1wbG95bWVudCByYXRlIiwNCiAgIkluZmxhdGlvbiByYXRlIiwNCiAgIkdEUCINCikNCg0Kc2FwcGx5KGJhc2VfY3VhbnQsIGNsYXNzKQ0KDQpzdW1tYXJ5KGJhc2VfY3VhbnQpDQpgYGANCg0KTG8gc2lndWllbnRlIGVzIGNhbGN1bGFyIGxvcyBlc3RhZMOtc3RpY29zIGRlc2NyaXB0aXZvcywgZXMgZGVjaXIsIGxvcyB2YWxvcmVzIHF1ZSBub3MgcmVzdW1lbiBsbyBtw6FzIGltcG9ydGFudGUgZGUgdW5hIHZhcmlhYmxlIG51bcOpcmljYSwgY29tbyBwb3IgZWplbXBsbywgbWVkaWEsIGRlc3ZpYWNpw7NuIGVzdMOhbmRhciwgdmFyaWFuemEsIGVudHJlIG90cm9zLiBQYXJhIGVsbG8gc2UgbW9zdHJhcsOhbiBkb3MgZ3LDoWZpY29zLCB1biBib3hwbG90IHBhcmEgdmVyIHNpIGhheSB2YWxvcmVzIGF0w61waWNvcyB5IHVuIGhpc3RvZ3JhbWEgcGFyYSB2ZXIgY8OzbW8gc2UgZGlzdHJpYnV5ZW4gbG9zIGRhdG9zIGEgY29tcGFyYWNpw7NuIGRlIHVuYSBjdXJ2YSBub3JtYWwgdGXDs3JpY2EgeSB2ZXIgc2kgc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbDoNCg0KYGBge3J9ICANCiMgRXN0YWTDrWdyYWZvcywgSGlzdG9ncmFtYXMgeSBCb3hwbG90cyBEZXNjcmlwdGl2b3MgVW5pdmFyaWFkb3MgZGUgVmFyaWFibGVzIEN1YW50aXRhdGl2YXM6IC0tLS0NCg0KYW5hbGlzaXNfY3VhbnQgPC0gZnVuY3Rpb24odmFyaWFibGUpIHtkYXRvcyA8LSBiYXNlX2N1YW50W1t2YXJpYWJsZV1dDQoNCiAjIEPDoWxjdWxvIGRlIGVzdGFkw61ncmFmb3MNCiAgcmVzdW1lbiA8LSByZXN1bWVuX3ZhcmlhYmxlKGRhdG9zKQ0KICANCiAgIyBJbXByZXNpw7NuDQogIGNhdCgiQW7DoWxpc2lzIGRlIGxhIHZhcmlhYmxlOiIsIHZhcmlhYmxlLCAiXG5cbiIpDQogIHByaW50KHJlc3VtZW4pDQogIA0KICAjIEludGVycHJldGFjacOzbiBiw6FzaWNhIGF1dG9tw6F0aWNhDQogIGNhdCgiXG4gSW50ZXJwcmV0YWNpw7NuOlxuIikNCiAgaWYgKHJlc3VtZW4kYXNpbWV0cmlhID4gMC41KSB7DQogICAgY2F0KCItIERpc3RyaWJ1Y2nDs24gYXNpbcOpdHJpY2EgcG9zaXRpdmEgKGNvbGEgaGFjaWEgbGEgZGVyZWNoYSkuXG4iKQ0KICB9IGVsc2UgaWYgKHJlc3VtZW4kYXNpbWV0cmlhIDwgLTAuNSkgew0KICAgIGNhdCgiLSBEaXN0cmlidWNpw7NuIGFzaW3DqXRyaWNhIG5lZ2F0aXZhIChjb2xhIGhhY2lhIGxhIGl6cXVpZXJkYSkuXG4iKQ0KICB9IGVsc2Ugew0KICAgIGNhdCgiLSBEaXN0cmlidWNpw7NuIGFwcm94aW1hZGFtZW50ZSBzaW3DqXRyaWNhLlxuIikNCiAgfQ0KICANCiAgaWYgKHJlc3VtZW4kY3VydG9zaXMgPiAzKSB7DQogICAgY2F0KCItIExlcHRvY8O6cnRpY2EgKHBpY29zIGFsdG9zLCBjb2xhcyBwZXNhZGFzKS5cbiIpDQogIH0gZWxzZSBpZiAocmVzdW1lbiRjdXJ0b3NpcyA8IDMpIHsNCiAgICBjYXQoIi0gUGxhdGljw7pydGljYSAobcOhcyBwbGFuYSBxdWUgdW5hIG5vcm1hbCkuXG4iKQ0KICB9IGVsc2Ugew0KICAgIGNhdCgiLSBDdXJ0b3NpcyBjZXJjYW5hIGEgbGEgZGlzdHJpYnVjacOzbiBub3JtYWwuXG4iKQ0KICB9DQogIA0KIyBCb3hwbG90DQogIGJveCA8LSBnZ3Bsb3QoYmFzZV9jdWFudCwgYWVzKHkgPSAuZGF0YVtbdmFyaWFibGVdXSkpICsNCiAgICBnZW9tX2JveHBsb3QoZmlsbCA9ICIjNjVjZTY3Iiwgb3V0bGllci5jb2xvciA9ICJyZWQiLCBhbHBoYSA9IDAuNykgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJCb3hwbG90IGRlIiwgdmFyaWFibGUpLCB5ID0gdmFyaWFibGUpDQogIA0KICBwcmludChib3gpDQogIA0KIyBIaXN0b2dyYW1hIGNvbiBjdXJ2YSBub3JtYWwNCiAgaGlzdG8gPC0gZ2dwbG90KGJhc2VfY3VhbnQsIGFlcyh4ID0gLmRhdGFbW3ZhcmlhYmxlXV0pKSArDQogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgYmlucyA9IDMwLCBmaWxsID0gIiNjYjk2ZWIiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC43KSArDQogICAgc3RhdF9mdW5jdGlvbihmdW4gPSBkbm9ybSwNCiAgICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KG1lYW4gPSBtZWFuKGRhdG9zLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2QgPSBzZChkYXRvcywgbmEucm0gPSBUUlVFKSksDQogICAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBsaW5ld2lkdGggPSAxKSArDQogICAgdGhlbWVfbWluaW1hbCgpICsNCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIkhpc3RvZ3JhbWEgZGUiLCB2YXJpYWJsZSwgImNvbiBjdXJ2YSBub3JtYWwiKSwgeCA9IHZhcmlhYmxlLCB5ID0gIkRlbnNpZGFkIikNCiAgDQogIHByaW50KGhpc3RvKQ0KICANCiAgaW52aXNpYmxlKHJlc3VtZW4pDQp9DQpgYGANCg0KQWhvcmEsIHJlYWxpemFtb3MgbG9zIHJlc3BlY3Rpdm9zIGFuw6FsaXNpcyBzb2JyZSBlbCBjb21wb3J0YW1pZW50byBkZSBlc3RhcyB2YXJpYWJsZXM6DQoNCmBgYHtyfSANCmFuYWxpc2lzX2N1YW50KCJQcmV2aW91cyBxdWFsaWZpY2F0aW9uIChncmFkZSkiKQ0KDQpjYXQoIkxhIG5vdGEgcHJvbWVkaW8gZGUgbGEgdGl0dWxhY2nDs24gcHJldmlhIGVzIGRlIDEzMywgY29uIHVuYSBkaXN0cmlidWNpw7NuIGNhc2kgDQogICAgc2ltw6l0cmljYSB5IHBpY29zIG1hcmNhZG9zIChjdXJ0b3NpcyDiiYggNCkuIEVzdG8gaW5kaWNhIHF1ZSBsYSBtYXlvcsOtYSBkZSANCiAgICBlc3R1ZGlhbnRlcyB0aWVuZSBjYWxpZmljYWNpb25lcyBzaW1pbGFyZXMsIGF1bnF1ZSBwb3Igc3VwdWVzdG8sIGhheSBhbGd1bm9zIA0KICAgIGNhc29zIG3DoXMgZXh0cmVtb3MsIGxvcyBjdWFsZXMgbm8gcGVybWl0ZW4gbGEgbm9ybWFsaWRhZC5cbiIpDQpgYGANCg0KYGBge3J9DQphbmFsaXNpc19jdWFudCgiQWRtaXNzaW9uIGdyYWRlIikNCg0KY2F0KCJMYSBub3RhIGRlIGFkbWlzacOzbiBwcm9tZWRpbyBlcyAxMjcsIGNvbiB1bmEgYXNpbWV0csOtYSBwb3NpdGl2YSB5IHVuYSANCiAgICBkaXN0cmlidWNpw7NuIG3DoXMgcGljdWRhIGRlIGxvIG5vcm1hbCAobGVwdG9jw7pydGljYSkuIEVzdG8gc3VnaWVyZSBxdWUgbGENCiAgICBtYXlvcsOtYSBkZSBsb3MgZXN0dWRpYW50ZXMgdGllbmUgbm90YXMgZGUgYWRtaXNpw7NuIGxpZ2VyYW1lbnRlIHBvciANCiAgICBkZWJham8gZGVsIHByb21lZGlvLCBwZXJvIGhheSBhbGd1bm9zIGNvbiBub3RhcyBub3RhYmxlbWVudGUgYWx0YXMuXG4iKQ0KYGBgDQoNCmBgYHtyfQ0KYW5hbGlzaXNfY3VhbnQoIkN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZ3JhZGUpIikNCg0KY2F0KCJMYSB2YXJpYWJsZSBwcmVzZW50YSB2YWxvcmVzIGF0w61waWNvcyBtdXkgYWx0b3MgeSBlc3RvcyBoYWNlbiBxdWUgbm8gaGF5YSB1bmEgbWVkaWRhIGNsYXJhIGRlIGNlbnRyYWxpZGFkLCBjb24gdW5hIG1lZGlhIGV4dHJhw7FhbWVudGUgZWxldmFkYSBkZSA0LjQ2ZTE1LiBMYSBtZWRpYW5hIGVzIDEzLjUsIHkgbGEgZGlzdHJpYnVjacOzbiBlcyBhc2ltw6l0cmljYSBwb3NpdGl2YSB5IHBsYXRpY8O6cnRpY2EuIEVudG9uY2VzIHNlIHB1ZWRlIGNvbmNsdWlyIHF1ZSBlcyBuZWNlc2FyaW8gbGltcGlhciBsb3MgZGF0b3MgcGFyYSBvYnRlbmVyIHVuIGFuw6FsaXNpcyBtw6FzIGNvbmZpYWJsZS5cbiIpDQpgYGANCg0KYGBge3J9DQphbmFsaXNpc19jdWFudCgiQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChncmFkZSkiKQ0KDQpjYXQoIk9jdXJyZSBsbyBtaXNtbyBxdWUgZW4gZWwgcHJpbWVyIHNlbWVzdHJlOiBoYXkgdmFsb3JlcyBleHRyZW1hZGFtZW50ZSBhbHRvcywgZW4gZXN0ZSBjYXNvIGxhIG1lZGlhIGVzIGRlIDMuOTNlMTUuIExhIG1lZGlhbmEgZXMgMTMsIHkgbGEgZGlzdHJpYnVjacOzbiB0YW1iacOpbiBlcyBhc2ltw6l0cmljYSBwb3NpdGl2YSB5IG3DoXMgcGxhbmEgZGUgbG8gbm9ybWFsIChwbGF0aWPDunJ0aWNhKS5cbiIpDQpgYGANCg0KYGBge3J9DQphbmFsaXNpc19jdWFudCgiVW5lbXBsb3ltZW50IHJhdGUiKQ0KDQpjYXQoIlNlIGN1ZW50YSBjb24gdW5hIHRhc2EgcHJvbWVkaW8gZGUgZGVzZW1wbGVvIGRlIDExLjYlIGNvbiBkaXN0cmlidWNpw7NuIHNpbcOpdHJpY2EgeSBkaXNwZXJzYS4gTGEgbWF5b3LDrWEgZGUgbG9zIHZhbG9yZXMgZXN0w6FuIGNlcmNhIGRlIGxhIG1lZGlhLCBwZXJvIGhheSBjaWVydGEgdmFyaWFiaWxpZGFkIChTRCA9IDIuNjYpLlxuIikNCmBgYA0KDQpgYGB7cn0NCmFuYWxpc2lzX2N1YW50KCJJbmZsYXRpb24gcmF0ZSIpDQoNCmNhdCgiSW5mbGFjacOzbiBtZWRpYSBkZSAxLjIzLCB0YW1iacOpbiBjb24gZGlzdHJpYnVjacOzbiBzaW3DqXRyaWNhIHkgcGxhbmEgKHBsYXRpY8O6cnRpY2EpLiBMb3MgdmFsb3JlcyBlc3TDoW4gcmVsYXRpdmFtZW50ZSBjb25jZW50cmFkb3MgZW50cmUgZWwgMCB5IGVsIDIuNS5cbiIpDQpgYGANCg0KYGBge3J9DQphbmFsaXNpc19jdWFudCgiR0RQIikNCg0KY2F0KCJFbCBQSUIgdGllbmUgdW5hIG1lZGlhIGNlcmNhbmEgYSBjZXJvICgwLjAwMTk3KSBkZWJpZG8gYSB2YWxvcmVzIG5lZ2F0aXZvcyB5IHBvc2l0aXZvcy4gQSBwZXNhciBkZSBlc28sIG11ZXN0cmEgdW5hIGRpc3RyaWJ1Y2nDs24gc2ltw6l0cmljYSB5IG3DoXMgZGlzcGVyc2EsIGNvbiB1bmEgYWx0YSBkZXN2aWFjacOzbiBlc3TDoW5kYXIgKDIuMjcpLlxuIikNCmBgYA0KDQpMdWVnbywgcHJvY2VkZW1vcyBhIGhhY2VyIGVsIEFuw6FsaXNpcyBCaXZhcmlhZG8gQ3VhbnRpdGF0aXZvLCBkb25kZSBsbyBoYXJlbW9zIG1lZGlhbnRlIGxhIGNvcnJlbGFjacOzbiBxdWUgcHJlc2VudGVuIGxhcyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KIyBBbsOhbGlzaXMgQml2YXJpYWRvIEN1YW50aXRhdGl2bzogLS0tLQ0KDQphbmFsaXNpc19iaV9jdWFudCA8LSBmdW5jdGlvbih2YXIxLCB2YXIyKSB7DQogIHggPC0gYmFzZV9jdWFudFtbdmFyMV1dDQogIHkgPC0gYmFzZV9jdWFudFtbdmFyMl1dDQogIA0KICAjIENhbGN1bGFyIGNvcnJlbGFjacOzbg0KICBjb3JfdmFsIDwtIGNvcih4LCB5LCB1c2UgPSAiY29tcGxldGUub2JzIikNCiAgDQogICMgSW50ZXJwcmV0YWNpw7NuIHRleHR1YWwNCiAgaW50ZXJwcmV0YWNpb24gPC0gY2FzZV93aGVuKA0KICAgIGFicyhjb3JfdmFsKSA8IDAuMiB+ICJNdXkgZMOpYmlsIG8gbnVsYSIsDQogICAgYWJzKGNvcl92YWwpIDwgMC40IH4gIkTDqWJpbCIsDQogICAgYWJzKGNvcl92YWwpIDwgMC42IH4gIk1vZGVyYWRhIiwNCiAgICBhYnMoY29yX3ZhbCkgPCAwLjggfiAiRnVlcnRlIiwNCiAgICBUUlVFIH4gIk11eSBmdWVydGUiDQogICkNCiAgDQogIGRpcmVjY2lvbiA8LSBpZmVsc2UoY29yX3ZhbCA+IDAsICJwb3NpdGl2YSIsICJuZWdhdGl2YSIpDQogIA0KICBjYXQoIkFuw6FsaXNpcyBiaXZhcmlhZG86IiwgdmFyMSwgInZzIiwgdmFyMiwgIlxuIikNCiAgY2F0KCJDb2VmaWNpZW50ZSBkZSBjb3JyZWxhY2nDs246Iiwgcm91bmQoY29yX3ZhbCwgNCksICJcbiIpDQogIGNhdCgiSW50ZXJwcmV0YWNpw7NuOiBDb3JyZWxhY2nDs24iLCBpbnRlcnByZXRhY2lvbiwgZGlyZWNjaW9uLCAiXG5cbiIpDQogIA0KICAjIERpYWdyYW1hIGRlIGRpc3BlcnNpw7NuDQogIHAgPC0gZ2dwbG90KGJhc2VfY3VhbnQsIGFlcyh4ID0gLmRhdGFbW3ZhcjFdXSwgeSA9IC5kYXRhW1t2YXIyXV0pKSArDQogICAgZ2VvbV9wb2ludChjb2xvciA9ICJkYXJrYmx1ZSIsIGFscGhhID0gMC42KSArDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIiwgbGluZXdpZHRoID0gMSkgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJEaXNwZXJzacOzbjoiLCB2YXIxLCAidnMiLCB2YXIyKSwNCiAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIkNvcnJlbGFjacOzbjoiLCByb3VuZChjb3JfdmFsLCA0KSksDQogICAgICAgICB4ID0gdmFyMSwgeSA9IHZhcjIpDQogIA0KICBwcmludChwKQ0KICANCiAgaW52aXNpYmxlKGNvcl92YWwpDQp9DQpgYGANCg0KU3UgY29tcG9ydGFtaWVudG8gbyBjb3JyZWxhY2nDs24gc2UgdmVyw6EgZGUgbGEgc2lndWllbnRlIG1hbmVyYToNCg0KYGBge3J9DQphbmFsaXNpc19iaV9jdWFudCgiUHJldmlvdXMgcXVhbGlmaWNhdGlvbiAoZ3JhZGUpIiwgIkdEUCIpDQphbmFsaXNpc19iaV9jdWFudCgiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChjcmVkaXRlZCkiLCAiQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChjcmVkaXRlZCkiKQ0KYW5hbGlzaXNfYmlfY3VhbnQoIkN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZXZhbHVhdGlvbnMpIiwgIkN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoYXBwcm92ZWQpIikNCmFuYWxpc2lzX2JpX2N1YW50KCJDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGdyYWRlKSIsICJDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKHdpdGhvdXQgZXZhbHVhdGlvbnMpIikNCmFuYWxpc2lzX2JpX2N1YW50KCJNb3RoZXIncyBvY2N1cGF0aW9uIiwgIkZhdGhlcidzIG9jY3VwYXRpb24iKQ0KYW5hbGlzaXNfYmlfY3VhbnQoIlByZXZpb3VzIHF1YWxpZmljYXRpb24gKGdyYWRlKSIsICJBZG1pc3Npb24gZ3JhZGUiKQ0KYW5hbGlzaXNfYmlfY3VhbnQoIkN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZW5yb2xsZWQpIiwgIkluZmxhdGlvbiByYXRlIikNCmFuYWxpc2lzX2JpX2N1YW50KCJDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGFwcHJvdmVkKSIsICJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGFwcHJvdmVkKSIpDQphbmFsaXNpc19iaV9jdWFudCgiQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChjcmVkaXRlZCkiLCAiQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChhcHByb3ZlZCkiKQ0KYW5hbGlzaXNfYmlfY3VhbnQoIlVuZW1wbG95bWVudCByYXRlIiwgIkdEUCIpDQoNCiMgRGlhZ3JhbWEgZGUgQ29ycmVsYWNpw7NuOg0KDQpjb3JycGxvdChjb3IoYmFzZV9jdWFudCksIG1ldGhvZCA9ICJzaGFkZSIsIHRsLmNleCA9IDAuNiwNCiAgICAgICAgIGNvbD1icmV3ZXIucGFsKG49OCwgbmFtZT0iUHVPciIpLGFkZENvZWYuY29sID0gImJsYWNrIiwNCiAgICAgICAgIG51bWJlci5jZXg9MC40LHR5cGUgPSAidXBwZXIiLCBkaWFnID0gRkFMU0UpDQoNCiMgQW7DoWxpc2lzIGRlIE1vZGVsbyBEaXN0cmlidWNpb25hbDogLS0tLQ0KDQpjYXQoIkFob3JhLCBtaXJhcmVtb3Mgc2kgbGFzIHZhcmlhYmxlcyBjdWFudGl0YXRpdmFzIGN1ZW50YW4gY29uIHVuYSBkaXN0cmlidWNpw7NuIGNvbm9jaWRhIGNvbW8gbm9ybWFsLCBnYW1tYSBvIGxvZ25vcm1hbCwgcGFyYSBlbGxvIGVzdGFibGVjZXJlbW9zIG51ZXN0cmEgSDA6IGxhIHZhcmlhYmxlIHBvZHLDrWEgc2VndWlyIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCB2cyBIMTogbm8gSDAuIikNCg0KYW5hbGlzaXNfZGlzdHJpYnVjaW9uYWwgPC0gZnVuY3Rpb24odmFyaWFibGUpIHsNCiAgeCA8LSBiYXNlX2N1YW50W1t2YXJpYWJsZV1dDQogIHggPC0gbmEub21pdCh4KQ0KICANCiAgY2F0KCJBbsOhbGlzaXMgZGUgTW9kZWxvIERpc3RyaWJ1Y2lvbmFsIHBhcmE6IiwgdmFyaWFibGUsICJcblxuIikNCiAgDQogICMgMS4gVGVzdCBkZSBub3JtYWxpZGFkDQogIHBfc2hhcGlybyA8LSBzaGFwaXJvLnRlc3QoeCkkcC52YWx1ZQ0KICBjYXQoIlRlc3QgZGUgU2hhcGlyby1XaWxrIChub3JtYWxpZGFkKTogcC12YWx1ZSA9Iiwgcm91bmQocF9zaGFwaXJvLCA1KSwgIlxuIikNCiAgY2F0KGlmZWxzZShwX3NoYXBpcm8gPiAwLjA1LA0KICAgICAgICAgICAgICItIE5vIHNlIHJlY2hhemEgSDA6IGxhIHZhcmlhYmxlIHBvZHLDrWEgc2VndWlyIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC5cbiIsDQogICAgICAgICAgICAgIi0gU2UgcmVjaGF6YSBIMDogbGEgdmFyaWFibGUgTk8gc2lndWUgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsLlxuIikpDQogIA0KICAjIDIuIEhpc3RvZ3JhbWEgKyBjdXJ2YSBub3JtYWwgdGXDs3JpY2ENCiAgaGlzdG8gPC0gZ2dwbG90KGJhc2VfY3VhbnQsIGFlcyh4ID0gLmRhdGFbW3ZhcmlhYmxlXV0pKSArDQogICAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwgYmlucyA9IDMwLCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICAgIHN0YXRfZnVuY3Rpb24oZnVuID0gZG5vcm0sDQogICAgICAgICAgICAgICAgICBhcmdzID0gbGlzdChtZWFuID0gbWVhbih4KSwgc2QgPSBzZCh4KSksDQogICAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBsaW5ld2lkdGggPSAxKSArDQogICAgdGhlbWVfbWluaW1hbCgpICsNCiAgICBsYWJzKHRpdGxlID0gcGFzdGUoIkhpc3RvZ3JhbWEgY29uIGN1cnZhIG5vcm1hbDoiLCB2YXJpYWJsZSksDQogICAgICAgICB4ID0gdmFyaWFibGUsIHkgPSAiRGVuc2lkYWQiKQ0KICANCiAgcHJpbnQoaGlzdG8pDQogIA0KICAjIDMuIEFqdXN0ZSBkZSBkaXN0cmlidWNpb25lcyBjb25vY2lkYXMNCiAgbGlicmFyeShmaXRkaXN0cnBsdXMpDQogIA0KICBtb2RlbG9zIDwtIGxpc3QoKQ0KICBtb2RlbG9zJG5vcm0gPC0gZml0ZGlzdCh4LCAibm9ybSIpDQogIA0KICBpZiAoYWxsKHggPiAwKSkgew0KICAgIG1vZGVsb3MkbG5vcm0gPC0gZml0ZGlzdCh4LCAibG5vcm0iKQ0KICAgIG1vZGVsb3MkZ2FtbWEgPC0gZml0ZGlzdCh4LCAiZ2FtbWEiKQ0KICB9DQogIA0KICAjIDQuIEV2YWx1YXIgQUlDDQogIGlmIChsZW5ndGgobW9kZWxvcykgPiAxKSB7DQogICAgZ29mIDwtIGdvZnN0YXQobW9kZWxvcykNCiAgICBhaWNfdGFibGUgPC0gYXNfdGliYmxlX3Jvdyhnb2YkYWljKQ0KICB9IGVsc2Ugew0KICAgIGFpY190YWJsZSA8LSB0aWJibGUobm9ybSA9IG1vZGVsb3Mkbm9ybSRhaWMpDQogIH0NCiAgDQogIGFpY190YWJsZSA8LSBhaWNfdGFibGUgJT4lDQogICAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAiRGlzdHJpYnVjaW9uIiwgdmFsdWVzX3RvID0gIkFJQyIpICU+JQ0KICAgIGFycmFuZ2UoQUlDKQ0KICANCiAgcHJpbnQoYWljX3RhYmxlKQ0KICANCiAgY2F0KCJcbiBEaXN0cmlidWNpw7NuIGNvbiBtZW5vciBBSUM6IiwgYWljX3RhYmxlJERpc3RyaWJ1Y2lvblsxXSwgIlxuIikNCiAgDQogIGludmlzaWJsZShsaXN0KA0KICAgIHBfc2hhcGlybyA9IHBfc2hhcGlybywNCiAgICBhaWMgPSBhaWNfdGFibGUNCiAgKSkNCn0NCg0KYW5hbGlzaXNfZGlzdHJpYnVjaW9uYWwoIlByZXZpb3VzIHF1YWxpZmljYXRpb24gKGdyYWRlKSIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiTW90aGVyJ3MgcXVhbGlmaWNhdGlvbiIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiRmF0aGVyJ3MgcXVhbGlmaWNhdGlvbiIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiTW90aGVyJ3Mgb2NjdXBhdGlvbiIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiRmF0aGVyJ3Mgb2NjdXBhdGlvbiIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiQWRtaXNzaW9uIGdyYWRlIikNCmFuYWxpc2lzX2Rpc3RyaWJ1Y2lvbmFsKCJBZ2UgYXQgZW5yb2xsbWVudCIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChjcmVkaXRlZCkiKQ0KYW5hbGlzaXNfZGlzdHJpYnVjaW9uYWwoIkN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZW5yb2xsZWQpIikNCmFuYWxpc2lzX2Rpc3RyaWJ1Y2lvbmFsKCJDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGV2YWx1YXRpb25zKSIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChhcHByb3ZlZCkiKQ0KYW5hbGlzaXNfZGlzdHJpYnVjaW9uYWwoIkN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZ3JhZGUpIikNCmFuYWxpc2lzX2Rpc3RyaWJ1Y2lvbmFsKCJDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKHdpdGhvdXQgZXZhbHVhdGlvbnMpIikNCmFuYWxpc2lzX2Rpc3RyaWJ1Y2lvbmFsKCJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGNyZWRpdGVkKSIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChlbnJvbGxlZCkiKQ0KYW5hbGlzaXNfZGlzdHJpYnVjaW9uYWwoIkN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoZXZhbHVhdGlvbnMpIikNCmFuYWxpc2lzX2Rpc3RyaWJ1Y2lvbmFsKCJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGFwcHJvdmVkKSIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChncmFkZSkiKQ0KYW5hbGlzaXNfZGlzdHJpYnVjaW9uYWwoIkN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAod2l0aG91dCBldmFsdWF0aW9ucykiKQ0KYW5hbGlzaXNfZGlzdHJpYnVjaW9uYWwoIlVuZW1wbG95bWVudCByYXRlIikNCmFuYWxpc2lzX2Rpc3RyaWJ1Y2lvbmFsKCJJbmZsYXRpb24gcmF0ZSIpDQphbmFsaXNpc19kaXN0cmlidWNpb25hbCgiR0RQIikNCg0KDQojIEludGVycHJldGFjacOzbiBkZWwgTW9kZWxvIERpc3RyaWJ1Y2lvbmFsIC0tLS0NCg0KY2F0KCJTZSBldmFsdcOzIGVsIGFqdXN0ZSBkZSBjYWRhIHZhcmlhYmxlIGN1YW50aXRhdGl2YSBhIHRyZXMgZGlzdHJpYnVjaW9uZXMgdGXDs3JpY2FzOiBOb3JtYWwsIExvZy1Ob3JtYWwgeSBHYW1tYSwgdXRpbGl6YW5kbyBlbCBUZXN0IGRlIFNoYXBpcm8tV2lsayAobm9ybWFsaWRhZCkuXG5cbiIpDQoNCmNhdCgiUGFyYSBjYWRhIHZhcmlhYmxlLCBzZSBzZWxlY2Npb27DsyBsYSBkaXN0cmlidWNpw7NuIGNvbiBtZW5vciBBSUMgY29tbyBsYSBkZSBtZWpvciBhanVzdGUuXG5cbiIpDQoNCmNhdCgiRW4gZ2VuZXJhbCwgc2Ugb2JzZXJ2YXJvbiBsb3Mgc2lndWllbnRlcyBwYXRyb25lczpcbiIpDQpjYXQoIi0gTGFzIHZhcmlhYmxlcyBjb21vICdQcmV2aW91cyBxdWFsaWZpY2F0aW9uIChncmFkZSknLCAnTW90aGVyJ3MgcXVhbGlmaWNhdGlvbicgeSAnQWdlIGF0IGVucm9sbG1lbnQnIG1vc3RyYXJvbiBtZWpvciBhanVzdGUgY29uIGRpc3RyaWJ1Y2lvbmVzIGdhbW1hIG8gbG9nLW5vcm1hbCwgbG8gY3VhbCBzdWdpZXJlIHVuYSBhc2ltZXRyw61hIHBvc2l0aXZhIHkgdmFsb3JlcyBubyBuZWdhdGl2b3MuXG4iKQ0KY2F0KCItIEFsZ3VuYXMgdmFyaWFibGVzIGNvbW8gJ01vdGhlcidzIG9jY3VwYXRpb24nIHkgJ0N1cnJpY3VsYXIgdW5pdHMnIHNvbG8gcHVkaWVyb24gYWp1c3RhcnNlIGNvbiBsYSBkaXN0cmlidWNpw7NuIG5vcm1hbCwgZGViaWRvIGEgbGEgcHJlc2VuY2lhIGRlIHZhbG9yZXMgY2VybyBvIG5lZ2F0aXZvcyBxdWUgaW1waWRlbiBlbCB1c28gZGUgZ2FtbWEgbyBsb2ctbm9ybWFsLlxuIikNCmNhdCgiLSBWYXJpYWJsZXMgY29tbyAnR0RQJyBlICdJbmZsYXRpb24gcmF0ZScgdGFtYmnDqW4gbW9zdHJhcm9uIGFqdXN0ZSBleGNsdXNpdm8gYSBsYSBkaXN0cmlidWNpw7NuIG5vcm1hbC5cblxuIikNCg0KY2F0KCJFc3RvIGltcGxpY2EgcXVlIG11Y2hhcyBkZSBsYXMgdmFyaWFibGVzIGFuYWxpemFkYXMgKHBvciBubyBkZWNpciwgVG9kYXMpLCBubyBzaWd1ZW4gdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIGNsw6FzaWNhLCBwb3IgbG8gY3VhbCBzZSByZWNoYXphIGxhIEgwIHkgZXMgcmVjb21lbmRhYmxlIGNvbnNpZGVyYXIgdHJhbnNmb3JtYWNpb25lcyBvIGVsIHVzbyBkZSBtw6l0b2RvcyBubyBwYXJhbcOpdHJpY29zIHNpIHNlIHJlcXVpZXJlbiBzdXB1ZXN0b3MgZGUgbm9ybWFsaWRhZCBlbiBhbsOhbGlzaXMgcG9zdGVyaW9yZXMuXG4iKQ0KDQoNCmBgYA0KDQpIYWNlbW9zIGVsIGFuYWxpc2lzIGJpdmFyaWFkbyBtaXh0byANCmBgYHtyfQ0KY2F0KCJFc3RhbW9zIGhhY2llbmRvIGFuw6FsaXNpcyBjb24gcmVzcGVjdG8gYSBsYSB2YXJpYWJsZSBUYXJnZXQgXG4iKQ0KDQpoaXN0b2dyYW1hX2JpIDwtIGZ1bmN0aW9uKHZhcmlhYmxlMSwgdmFyaWFibGUyKSB7DQogIGhpc3RvZ3JhbWEgPC0gZGF0b3NfdSAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSAhIXN5bSh2YXJpYWJsZTEpKSkgKw0KICAgIGdlb21faGlzdG9ncmFtKGZpbGwgPSAieWVsbG93IiwgY29sb3IgPSAiYmxhY2siLCBiaW5zID0gMTUpICsNCiAgICBnZ3RpdGxlKHZhcmlhYmxlMSkgKw0KICAgIGxhYnMoeCA9IHZhcmlhYmxlMSwgeSA9ICJGcmVjdWVuY2lhcyIpICsNCiAgICBmYWNldF93cmFwKHZhcnMoISFzeW0odmFyaWFibGUyKSksIHNjYWxlcyA9ICJmcmVlIikgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuMDUpKQ0KICANCiAgcmV0dXJuKGhpc3RvZ3JhbWEpDQp9DQoNCg0KYm94cGxvdF9iaSA8LSBmdW5jdGlvbih2YXJpYWJsZTEsIHZhcmlhYmxlMikgew0KICBnZ3Bsb3QoZGF0b3NfdSwgYWVzKHggPSAuZGF0YVtbdmFyaWFibGUxXV0sIHkgPSAuZGF0YVtbdmFyaWFibGUyXV0pKSArDQogICAgZ2VvbV9ib3hwbG90KGZpbGwgPSAic2t5Ymx1ZSIsIG91dGxpZXIuY29sb3IgPSAicmVkIikgKw0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgbGFicygNCiAgICAgIHRpdGxlID0gcGFzdGUoIkJveHBsb3QgZGUiLCB2YXJpYWJsZTIsICJzZWfDum4iLCB2YXJpYWJsZTEpLA0KICAgICAgeCA9IHZhcmlhYmxlMSwNCiAgICAgIHkgPSB2YXJpYWJsZTINCiAgICApDQp9DQpkZXNjcmlwY2lvbiA8LSBmdW5jdGlvbih2YXJpYWJsZTEsdmFyaWFibGUyKXsNCiAgcmV0dXJuKGRlc2NyaWJlQnkoZGF0b3NfdVtbdmFyaWFibGUxXV0sZ3JvdXA9ZGF0b3NfdVtbdmFyaWFibGUyXV0pKSAgDQp9DQoNCmBgYA0KYGBge3J9DQpoaXN0b2dyYW1hX2JpKCJDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGFwcHJvdmVkKSIsIlRhcmdldCIpDQpkZXNjcmlwY2lvbigiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChhcHByb3ZlZCkiLCJUYXJnZXQiKQ0KYGBgDQoNCmBgYHtyfQ0KaGlzdG9ncmFtYV9iaSggIkN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoYXBwcm92ZWQpIiwiVGFyZ2V0IikNCmRlc2NyaXBjaW9uKCJDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGFwcHJvdmVkKSIsIlRhcmdldCIpDQoNCmBgYA0KDQpgYGB7cn0NCmJveHBsb3RfYmkoIkN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoYXBwcm92ZWQpIiwiVGFyZ2V0IikNCg0KYm94cGxvdF9iaSgiQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChhcHByb3ZlZCkiLCJUYXJnZXQiKQ0KDQpib3hwbG90X2JpKCJBZ2UgYXQgZW5yb2xsbWVudCIsIlRhcmdldCIpDQoNCmJveHBsb3RfYmkoIlVuZW1wbG95bWVudCByYXRlIiwiVGFyZ2V0IikNCg0KDQpgYGANCg0KQ29tZW56YW1vcyBjb24gbGFzIHBydWViYXMgZGUgaGlwb3Rlc2lzDQpgYGB7cn0NCmNhdCgiUHJ1ZWJhcyBkZSBIaXDDs3Rlc2lzXG4iKQ0KDQptZWFuKGRhdG9zX3UkYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoZW5yb2xsZWQpYCkNCg0KYGBgDQoNCg0KDQoNClByaW1lcmEgcHJ1ZWJhIGRlIGhpcMOzdGVzaXM6DQoNCkFudGVyaW9ybWVudGUgcHVkaW1vcyB2ZXIgcXVlIGxhIG1lZGlhIGRlIGxvcyB2YWxvcmVzIGRlIGxvcyBjcsOpZGl0b3MgDQppbnNjcml0b3MgZW4gcHJpbWVyIHNlbWVzdHJlIGVzIGRlIDYuMjcwNTcsIHBvciBlbmRlIGNlbnRyZW1vcyANCm51ZXN0cmEgaGlww7N0ZXNpcyBzb2JyZSBlc3RvLg0KDQpIMDogNi4yNyA+IG1pdSB2cyBIMTogbWl1IDw9IDYuMjcNCg0KYGBge3J9DQpjYXQoIlZhbW9zIGEgdmVyaWZpY2FyIHNpIHNpZ3VlIHVuYSBub3JtYWw6XG4iKQ0KDQphbmFsaXNpc19jdWFudCgiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChlbnJvbGxlZCkiKQ0KDQpsaWxsaWUudGVzdChkYXRvc191JGBDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGVucm9sbGVkKWApDQoNCmNhdCgiTm8gc2lndWUgbGEgbm9ybWFsLCBwb3IgbG8gdGFudG8gdGVuZHJlbW9zIHF1ZSBzdXBvbmVyIA0KICAgIG5vcm1hbGlkYWQgOigNCiAgICBBc8OtIHF1ZSBwYXJhIGVsbG8gYXBsaWNhcmVtb3MgZWwgdCB0ZXN0LiIpDQoNCnQudGVzdChkYXRvc191JGBDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGVucm9sbGVkKWAsIGFsdGVybmF0aXZlPSJsZXNzIiwgbXUgPSA2LjI3KQ0KDQpgYGANClBhcmEgbGEgc2VndW5kYSBtdWVzdHJhIGV2aWRlbmNpYW1vcyBxdWUgbGEgcHJvcG9yY2lvbiBkZSANCmVzdHVkaWFudGVzIHF1ZSBuZWNlc2l0YW4gRWR1Y2FjacOzbiBFc3BlY2lhbCBlcyBkZSAwLjAxMTUyODAzLA0KcG9yIGVuZGUgdmFtb3MgYSB2ZXJpZmljYXIgcXVlIGxhIHByb3BvcmNpb24gcG9ibGFjaW9uYWwgZGUgbG9zIA0KZXN0dWRpYW50ZXMgcXVlIG5lY2VzaXRhbiBlZHVjYWNpb24gZXNwZWNpYWwgZXMgDQptZW5vciBhbCAyJSwgY29udHJhIHF1ZSBzZWEgbWF5b3IgbyBpZ3VhbCBhbCAyJQ0KDQpIMDogbWl1IDwgMC4wMiB2cyBIMTogbWl1ID49IDAuMDIiKQ0KYGBge3J9DQpwcm9wLnRhYmxlKHRhYmxlKGRhdG9zX3UkYEVkdWNhdGlvbmFsIHNwZWNpYWwgbmVlZHNgKSkNCg0KdGFibGUoZGF0b3NfdSRgRWR1Y2F0aW9uYWwgc3BlY2lhbCBuZWVkc2ApDQoNCmNhdCgiSW1wbGVtZW50YW1vcyBlbCBwcm9wIHRlc3Q6XG4iKQ0KDQpwcm9wLnRlc3QoNTEsDQogICAgICAgICAgbiA9IGxlbmd0aChkYXRvc191JGBFZHVjYXRpb25hbCBzcGVjaWFsIG5lZWRzYCksDQogICAgICAgICAgcCA9IDAuMDIsDQogICAgICAgICAgYWx0ZXJuYXRpdmUgPSAibGVzcyIsDQogICAgICAgICAgY29ycmVjdCA9IEZBTFNFKQ0KDQoNCmBgYA0Kc2UgcmVjaGF6YSANCmNvbWVuemFtb3MgY29uIGJvbmRhZCBkZSBhanVzdGUgDQpgYGB7cn0NCmNhdCgiSDA6IExvcyBjcmVkaXRvcyBhcHJvYmFkb3MgZW4gc2VndW5kbyBzZW1lc3RyZSBzaWd1ZW4gdW5hIA0KZGlzdHJpYnVjaW9uIGJpbm9taWFsIA0KdnMNCkgxOiBObyBIMCIpDQoNCmZyZWN1ZW5jaWFzIDwtIHRhYmxlKGRhdG9zX3UkYEN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoYXBwcm92ZWQpYCkNCmZyZWN1ZW5jaWFzIA0KDQp2YWxvcmVzIDwtIGFzLm51bWVyaWMobmFtZXMoZnJlY3VlbmNpYXMpKQ0KdmFsb3JlcyANCg0KY2F0KCJUZW5lbW9zIHF1ZSBoYWxsYXIgbGEgY2FudGlkYWQgZGUgaW50ZW50b3MgcGFyYSBjb25zZWd1aXIgdW4gw6l4aXRvLCANCmVudG9uY2VzIGFuYWxpemFyZW1vcyBsb3MgY3LDqWRpdG9zIGluc2NyaXRvczpcbiIpIA0KDQptYVggPC0gc29ydCh1bmlxdWUoZGF0b3NfdSRgQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChlbnJvbGxlZClgKSwgZGVjcmVhc2luZyA9IFRSVUUpWzJdDQptYVgNCg0KY2F0KCJUb21hcmVtb3MgMTksIGx1ZWdvIGJvcnJhbW9zIGxvcyBkYXRvcyBxdWUgc2VhbiBtZW5vcmVzIGEgMTkuLi5cbiIpDQoNCmRhdG9zMiA8LSBkYXRvc191W2RhdG9zX3UkYEN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoZW5yb2xsZWQpYDw9MTksXQ0KDQpkaWFncmFtYV9jcmVkaXRvc2luczwtIGJveHBsb3QoZGF0b3NfdSRgQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChlbnJvbGxlZClgLGhvcml6b250YWw9VFJVRSkNCmRhdG9zX3UgJT4lIGRpbSgpDQoNCmRhdG9zMiAlPiUgY291bnQoYEN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoZW5yb2xsZWQpYCkNCg0KbWVhbihkYXRvc191JGBDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGVucm9sbGVkKWApDQoNCmNhdCgiUG9kZW1vcyB2ZXIgcXVlIGVsIG3DoXhpbW8gZGUgY3LDqWRpdG9zIGluc2NyaXRvcyBlcyAyMywgc2luIGVtYmFyZ28gDQptYXlvcm1lbnRlIGxvcyBkYXRvcyBlc3TDoW4gZW50cmUgNCB5IDcsIGHDum4gYXPDrSwgcGFyYSBubyBwZXJkZXIgZGF0b3MgDQpjb25zaWRlcmFyZW1vcyBlbCBtw6F4aW1vOlxuIikgDQoNCnAgPC0gc3VtKGRhdG9zMiRgQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChhcHByb3ZlZClgKS8oMTkqNDQyMSkNCnANCm4gPC0gZGF0b3NfdSAlPiUgZGltDQpwX2kgPC0gZGJpbm9tKHZhbG9yZXMsMTkscCkNCnBfaQ0KYiA8LSBjaGlzcS50ZXN0KGZyZWN1ZW5jaWFzLHA9cF9pLHJlc2NhbGUucD1UUlVFKQ0KYg0KDQpiJGV4cGVjdGVkDQoNCg0KY2F0KCJCdWNhbW9zIDAgaW5mbGFkbzpcbiIpDQoNCmBgYA0KY29uIGNhdGVnb3JpY2FzDQoNCkgwOmNvdXJzZSBzaWd1ZSB1bmEgZGlzdHJpYnVjaW9uIHVuaWZvcm1lIA0KdnMNCkgxOm5vIEgwDQpgYGB7cn0NCm9ic2VydmFkbyA8LSB0YWJsZShiYXNlX2NhdGUkQ291cnNlKQ0KDQp0b3RhbCA8LSBzdW0ob2JzZXJ2YWRvKQ0KDQplc3BlcmFkbyA8LSByZXAodG90YWwvbGVuZ3RoKG9ic2VydmFkbyksbGVuZ3RoKG9ic2VydmFkbykpDQoNCnJlc3VsdGFkbyA8LSBjaGlzcS50ZXN0KHg9b2JzZXJ2YWRvLHA9ZXNwZXJhZG8vdG90YWwpDQpyZXN1bHRhZG8NCg0KcHJpbnQoImVsIHAtdmFsdWUgZXMgbXV5IGJham8sIGVudG9uY2VzIHNlIHJlY2hhemEgbGEgaGlwb3Rlc2lzIG51bGEiKQ0KDQoNCiNzaW4gZW1iYXJnbyBhbGdvIGludGVyZXNhbnRlIGVzIHF1ZSBjb3Vyc2UgcG9kcmlhIHNlZ3VpciB1bmEgZGlzdHJpYnVjaW9uIHppcGYNCiNwYXJhIG1pcmFyIHNpIHNpZ3VlIGVzdGEgZGlzdHJpYnVjaW9uIHVzYW1vcyBsYSBncmFmaWNhIGxvZy1sb2cgDQoNCmZyZWN1ZW5jaWFzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoYmFzZV9jYXRlJENvdXJzZSkpDQpjb2xuYW1lcyhmcmVjdWVuY2lhcykgPC0gYygiY291cnNlIiwiY291bnQiKQ0KZnJlY3VlbmNpYXMgPC0gZnJlY3VlbmNpYXNbb3JkZXIoLWZyZWN1ZW5jaWFzJGNvdW50KSxdDQoNCmZyZWN1ZW5jaWFzJFJhbmsgPC0gMTpucm93KGZyZWN1ZW5jaWFzKQ0KDQoNCmxvZ19sb2cgPC0gZ2dwbG90KGZyZWN1ZW5jaWFzLCBhZXMoeCA9IFJhbmssIHkgPSBmcmVjdWVuY2lhcyRjb3VudCkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJibHVlIikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHgsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsNCiAgc2NhbGVfeF9sb2cxMCgpICsNCiAgc2NhbGVfeV9sb2cxMCgpICsNCiAgbGFicyh0aXRsZSA9ICJBanVzdGUgbGluZWFsIGVuIGVzY2FsYSBsb2ctbG9nIiwNCiAgICAgICB4ID0gIlJhbmdvIGRlbCBjdXJzbyAobG9nKSIsDQogICAgICAgeSA9ICJGcmVjdWVuY2lhIChsb2cpIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KbG9nX2xvZw0KYGBgDQpjb21vIHBvZGVtb3MgdmVyIGVsIGdyYWZpY28sIG5vIHNpZ3VlIGxhIGxpbmVhLCBlbnRvbmNlcyBubyBzaWd1ZSBsYSBkaXN0cmlidWNpb24sIA0KbG8gaW50ZW50YW1vcyA6KCANCmBgYHtyfQ0KdGVzdF9pbmRlcGVuZGVuY2lhIDwtIGZ1bmN0aW9uKHZhcjEsIHZhcjIpIHsNCiAgdGFibGEgPC0gdGFibGUoZGF0b3NfdVtbdmFyMV1dLCBkYXRvc191W1t2YXIyXV0pDQogIA0KICBjYXQoIlxuwr9IYXkgaW5kZXBlbmRlbmNpYSBlbnRyZSIsIHZhcjEsICJ5IiwgdmFyMiwgIj9cblxuIikNCiAgDQogIG1pbl9lc3BlcmFkbyA8LSBtaW4oY2hpc3EudGVzdCh0YWJsYSkkZXhwZWN0ZWQpDQogIA0KICBpZiAoYW55KHRhYmxhIDwgNSkgfHwgbWluX2VzcGVyYWRvIDwgNSkgew0KICAgIHRlc3QgPC0gZmlzaGVyLnRlc3QodGFibGEpDQogICAgbWV0b2RvIDwtICJUZXN0IGV4YWN0byBkZSBGaXNoZXIiDQogIH0gZWxzZSB7DQogICAgdGVzdCA8LSBjaGlzcS50ZXN0KHRhYmxhKQ0KICAgIG1ldG9kbyA8LSAiQ2hpLWN1YWRyYWRvIGRlIGluZGVwZW5kZW5jaWEiDQogIH0NCiAgDQogIGNhdCgiTcOpdG9kbzoiLCBtZXRvZG8sICJcbiIpDQogIGNhdCgicC12YWxvciA9Iiwgc2lnbmlmKHRlc3QkcC52YWx1ZSwgNiksICJcblxuIikNCiAgDQogIGlmICh0ZXN0JHAudmFsdWUgPCAwLjA1KSB7DQogICAgY2F0KCJTZSByZWNoYXphIEgwOiBoYXkgZXZpZGVuY2lhIGRlIGRlcGVuZGVuY2lhIGVudHJlIiwgdmFyMSwgInkiLCB2YXIyLCAiXG5cbiIpDQogIH0gZWxzZSB7DQogICAgY2F0KCJObyBzZSByZWNoYXphIEgwOiBubyBoYXkgZXZpZGVuY2lhIHN1ZmljaWVudGUgZGUgZGVwZW5kZW5jaWEgZW50cmUiLCB2YXIxLCAieSIsIHZhcjIsICJcblxuIikNCiAgfQ0KICANCiAgY2F0KCJUYWJsYSBkZSBjb250aW5nZW5jaWEgKCUgcG9yIGZpbGEpOlxuIikNCiAgcHJpbnQocm91bmQocHJvcC50YWJsZSh0YWJsYSwgbWFyZ2luID0gMSkgKiAxMDAsIDIpKQ0KICANCiAgaW52aXNpYmxlKHRlc3QpDQogIA0KICBwIDwtIGdyYWZpY29fYXBpbGFkbyh2YXIxLCB2YXIyKQ0KICANCiAgcHJpbnQocCkNCn0NCg0KDQp0ZXN0X2luZGVwZW5kZW5jaWEoIlRhcmdldCIsICJTY2hvbGFyc2hpcCBob2xkZXIiKQ0KdGVzdF9pbmRlcGVuZGVuY2lhKCJUYXJnZXQiLCAiRGF5dGltZS9ldmVuaW5nIGF0dGVuZGFuY2UiKQ0KdGVzdF9pbmRlcGVuZGVuY2lhKCJUYXJnZXQiLCAiR2VuZGVyIikNCnRlc3RfaW5kZXBlbmRlbmNpYSgiRGVidG9yIiwgIlNjaG9sYXJzaGlwIGhvbGRlciIpDQp0ZXN0X2luZGVwZW5kZW5jaWEoIlRhcmdldCIsICJUdWl0aW9uIGZlZXMgdXAgdG8gZGF0ZSIpDQoNCnJlc2lkdWFsZXNfcG9zdGhvYyA8LSBmdW5jdGlvbih2YXIxLCB2YXIyKSB7DQogIHRhYmxhIDwtIHRhYmxlKGRhdG9zX3VbW3ZhcjFdXSwgZGF0b3NfdVtbdmFyMl1dKQ0KICANCiAgdGVzdCA8LSBjaGlzcS50ZXN0KHRhYmxhKQ0KICANCiAgcmVzaWR1YWxlcyA8LSB0ZXN0JHN0ZHJlcw0KICANCiAgY2F0KCJBbsOhbGlzaXMgcG9zdC1ob2MgZGUgcmVzaWR1YWxlcyBlc3RhbmRhcml6YWRvczpcbiIpDQogIHByaW50KHJvdW5kKHJlc2lkdWFsZXMsIDIpKQ0KICANCiAgc2lnX3JlcyA8LSBhYnMocmVzaWR1YWxlcykgPj0gMg0KICANCiAgY2F0KCJcbiBDZWxkYXMgY29uIGNvbnRyaWJ1Y2nDs24gc2lnbmlmaWNhdGl2YSAofHJlc2lkdWFsfCDiiaUgMik6XG4iKQ0KICBwcmludCh3aGljaChzaWdfcmVzLCBhcnIuaW5kID0gVFJVRSkpDQogIA0KICBsaWJyYXJ5KHJlc2hhcGUyKQ0KICBkZl9yZXMgPC0gbWVsdChyZXNpZHVhbGVzKQ0KICANCiAgZ2dwbG90KGRmX3JlcywgYWVzKHggPSBWYXIyLCB5ID0gVmFyMSwgZmlsbCA9IHZhbHVlKSkgKw0KICAgIGdlb21fdGlsZShjb2xvciA9ICJwdXJwbGUiKSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHZhbHVlLCAyKSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMpICsNCiAgICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAieWVsbG93IiwgbWlkID0gImxpZ2h0Ymx1ZSIsIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAwKSArDQogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJSZXNpZHVhbGVzIGVzdGFuZGFyaXphZG9zOiIsIHZhcjEsICJ2cyIsIHZhcjIpLA0KICAgICAgICAgeCA9IHZhcjIsIHkgPSB2YXIxKSArDQogICAgdGhlbWVfbWluaW1hbCgpDQp9DQoNCnJlc2lkdWFsZXNfcG9zdGhvYygiVGFyZ2V0IiwgIlNjaG9sYXJzaGlwIGhvbGRlciIpDQpyZXNpZHVhbGVzX3Bvc3Rob2MoIlRhcmdldCIsICJEYXl0aW1lL2V2ZW5pbmcgYXR0ZW5kYW5jZSIpDQpyZXNpZHVhbGVzX3Bvc3Rob2MoIlRhcmdldCIsICJHZW5kZXIiKQ0KcmVzaWR1YWxlc19wb3N0aG9jKCJEZWJ0b3IiLCAiU2Nob2xhcnNoaXAgaG9sZGVyIikNCnJlc2lkdWFsZXNfcG9zdGhvYygiVGFyZ2V0IiwgIlR1aXRpb24gZmVlcyB1cCB0byBkYXRlIikNCg0KYGBgDQoNCg0KUHJ1ZWJhcyBLcw0KYGBge3J9DQoNCiMgUHJ1ZWJhcyBLLVMgOjMNCg0KIyBDYXJnYXIgbGEgYmFzZSBkZSBkYXRvcw0KDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCmRhdGEgPC0gcmVhZF9kZWxpbSgiZGF0YS5jc3YiLCBkZWxpbSA9ICI7IiwgDQogICAgICAgICAgICAgICAgICAgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLCB0cmltX3dzID0gVFJVRSkNCg0KZGF0b3NfdSA8LSBkYXRhDQpkYXRvc191ICU+JSBkaW0oKQ0KDQojIENvbW8gSy1TIGVzIMO6dGlsIHBhcmEgYm9uZGFkIGRlIGFqdXN0ZSBkZSB2YXJpYWJsZXMgY3VhbnRpdGF0aXZhcyBjb250aW51YXMsDQojIHNlIHVzYXLDoSBhIGNvbnRpbnVhY2nDs246DQoNCg0KDQojIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIA0KIyBOb3RhcyBkZWwgZXhhbWVuIGRlIGFkbWlzacOzbiAoYWRtaXNzaW9uIGdyYWRlKQ0KIyAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSANCg0KYWRtaXNzaW9uX2dyYWRlIDwtIGRhdG9zX3UkYEFkbWlzc2lvbiBncmFkZWANCmFkbWlzc2lvbl9ncmFkZQ0KDQojIMK/U2UgYWp1c3RhIGEgdW5hIG5vcm1hbD8NCiMgSDA6IExhcyBub3RhcyBkZSBhZG1pc2nDs24gc2UgYWp1c3RhbiBhIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbA0KIyBIMTogTm8gSDANCg0KIyBHcsOhZmljbyBkZSBsYXMgQ0RGcw0KDQpncmlkIDwtIHNlcShtaW4ocHVsbChhZG1pc3Npb25fZ3JhZGUpKSwgbWF4KHB1bGwoYWRtaXNzaW9uX2dyYWRlKSksIGxlbmd0aC5vdXQgPSAxMDApDQoNCnBsb3QoZ3JpZCwgDQogICAgIHBub3JtKGdyaWQsDQogICAgIG1lYW4gPSBtZWFuKHB1bGwoYWRtaXNzaW9uX2dyYWRlKSksIHNkID0gc2QocHVsbChhZG1pc3Npb25fZ3JhZGUpKSksIA0KICAgICB0eXBlID0gImwiLCB5bGltID0gYygwLCAxKSwgDQogICAgIHlsYWIgPSAiUHJvYmFiaWxpZGFkIGFjdW11bGFkYSIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiLA0KICAgICB4bGFiID0gIk5vdGEgZGUgYWRtaXNpw7NuIiwgDQogICAgIG1haW4gPSAiRnVuY2lvbmVzIGRlIGRpc3RyaWJ1Y2nDs24gYWN1bXVsYWRhcyIpDQoNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCANCiAgICAgICBsZWdlbmQgPSBjKCJEaXN0cmlidWNpw7NuIE5vcm1hbCAodGXDs3JpY2EpIiwgIkRpc3RyaWJ1Y2nDs24gZW1ww61yaWNhIiksIA0KICAgICAgIGNvbCA9IGMoInJlZCIsICJibGFjayIpLCANCiAgICAgICBsdHkgPSAxLCANCiAgICAgICBsd2QgPSAyKQ0KDQpsaW5lcyhlY2RmKHB1bGwoYWRtaXNzaW9uX2dyYWRlKSksIHZlcnRpY2FscyA9IFRSVUUsIGRvLnBvaW50cyA9IEZBTFNFLCBjb2wuMDFsaW5lID0gTlVMTCkNCiAgDQojIFRlc3QgZGUgSy1TDQoNCmtzLnRlc3QocHVsbChhZG1pc3Npb25fZ3JhZGUpLCAicG5vcm0iLCANCiAgICAgICAgbWVhbiA9IG1lYW4ocHVsbChhZG1pc3Npb25fZ3JhZGUpKSwgDQogICAgICAgIHNkID0gc2QocHVsbChhZG1pc3Npb25fZ3JhZGUpKSkNCg0KIyBSZXN1bHRhZG8NCg0KIyBEID0gMC4wNjU4NjMsIHAtdmFsdWUgPCAyLjJlLTE2DQojIGFsdGVybmF0aXZlIGh5cG90aGVzaXM6IHR3by1zaWRlZA0KDQojIENvbW8gcC12YWx1ZSA8IDAuMDUsIHNlIHJlY2hhemEgSDAgeSBzZSBjb25jbHV5ZSBxdWUgbGFzIG5vdGFzIGRlIGFkbWlzacOzbg0KIyBubyBzZSBhanVzdGFuIGEgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIHVzYW5kbyBLLVMgY29uIHVuYSBzaWduaWZpY2FuY2lhIGRlbCA1JS4gDQojIEVzIGltcG9ydGFudGUgcmVjYWxjYXIgcXVlIGVsIHRlc3QgSy1TIG5vIGZ1bmNpb25hIG11eSBiaWVuIGVuIG11ZXN0cmFzIA0KIyBncmFuZGVzIGFsIHRvbWFyIGxhIGRpZmVyZW5jaWEgbcOheGltYSBlbnRyZSBlbCBDREYgdGXDs3JpY28geSBtdWVzdHJhbC4NCg0KDQoNCiMgLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gDQojIFByb21lZGlvIGVuIHByaW1lciB5IHNlZ3VuZG8gc2VtZXN0cmUgDQojKEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbWVzdGVyIChncmFkZSkgLyBDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW1lc3RlciAoZ3JhZGUpKQ0KIyAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSANCg0KZ3JhZGVfYXZlcmFnZV8xc3QgPC0gZGF0b3NfdSAlPiUgc2VsZWN0KGBDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGdyYWRlKWApDQpncmFkZV9hdmVyYWdlXzJuZCA8LSBkYXRvc191ICU+JSBzZWxlY3QoYEN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoZ3JhZGUpYCkNCg0KIyBSZW1vdmVyIGxhcyBub3RhcyBkZSAwLCBxdWUgc29uIGxvIG3DoXMgY29tw7puIHNpIGh1Ym8gZGVzZXJjacOzbiANCg0KaGlzdChwdWxsKGdyYWRlX2F2ZXJhZ2VfMXN0KSkgIyBBbnRlcw0KDQpncmFkZV9hdmVyYWdlXzFzdFtncmFkZV9hdmVyYWdlXzFzdD09MF0gPC0gTkENCmdyYWRlX2F2ZXJhZ2VfMm5kW2dyYWRlX2F2ZXJhZ2VfMm5kPT0wXSA8LSBOQQ0KDQpoaXN0KHB1bGwoZ3JhZGVfYXZlcmFnZV8xc3QpKSAjIERlc3B1w6lzDQoNCiMgwr9TZSBhanVzdGFuIGEgdW5hIG5vcm1hbD8NCg0KIyBIMF8xOiBFbCBwcm9tZWRpbyBkZSBwcmltZXIgc2VtZXN0cmUgc2UgYWp1c3RhIGEgdW5hIGRpc3RyaWJ1Y2nDs24gTm9ybWFsDQojIEgxXzE6IE5vIEgwXzENCiMgDQojIEgwXzI6IEVsIHByb21lZGlvIGRlIHNlZ3VuZG8gc2VtZXN0cmUgc2UgYWp1c3RhIGEgdW5hIGRpc3RyaWJ1Y2nDs24gTm9ybWFsDQojIEgxXzI6IE5vIEgwXzINCg0KIyBHcsOhZmljbyBkZSBsYXMgQ0RGcyAoc2VtIDEpDQoNCmdyaWQgPC0gc2VxKDgsIDIwLCBsZW5ndGgub3V0ID0gMTAwKQ0KDQpwbG90KGdyaWQsIA0KICAgICBwbm9ybShncmlkLA0KICAgICAgICAgICAgbWVhbiA9IG1lYW4ocHVsbChuYS5vbWl0KGdyYWRlX2F2ZXJhZ2VfMXN0KSkpLA0KICAgICAgICAgICAgc2QgPSBzZChwdWxsKG5hLm9taXQoZ3JhZGVfYXZlcmFnZV8xc3QpKSkpLCANCiAgICAgdHlwZSA9ICJsIiwgeWxpbSA9IGMoMCwgMSksIA0KICAgICB5bGFiID0gIlByb2JhYmlsaWRhZCBhY3VtdWxhZGEiLCBsd2QgPSAyLCBjb2wgPSAicmVkIiwNCiAgICAgeGxhYiA9ICJQcm9tZWRpbyBkZWwgcHJpbWVyIHNlbWVzdHJlIiwgDQogICAgIG1haW4gPSAiRnVuY2lvbmVzIGRlIGRpc3RyaWJ1Y2nDs24gYWN1bXVsYWRhcyIpDQoNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCANCiAgICAgICBsZWdlbmQgPSBjKCJEaXN0cmlidWNpw7NuIE5vcm1hbCAodGXDs3JpY2EpIiwgIkRpc3RyaWJ1Y2nDs24gZW1ww61yaWNhIiksIA0KICAgICAgIGNvbCA9IGMoInJlZCIsICJibGFjayIpLCANCiAgICAgICBsdHkgPSAxLCANCiAgICAgICBsd2QgPSAyKQ0KDQpsaW5lcyhlY2RmKHB1bGwoZ3JhZGVfYXZlcmFnZV8xc3QpKSwgdmVydGljYWxzID0gVFJVRSwgZG8ucG9pbnRzID0gRkFMU0UsIGNvbC4wMWxpbmUgPSBOVUxMKQ0KDQoNCiMgR3LDoWZpY28gZGUgbGFzIENERnMgKHNlbSAyKQ0KDQpncmlkIDwtIHNlcSg4LCAyMCwgbGVuZ3RoLm91dCA9IDEwMCkNCg0KcGxvdChncmlkLCANCiAgICAgcG5vcm0oZ3JpZCwNCiAgICAgICAgICAgbWVhbiA9IG1lYW4ocHVsbChuYS5vbWl0KGdyYWRlX2F2ZXJhZ2VfMm5kKSkpLA0KICAgICAgICAgICBzZCA9IHNkKHB1bGwobmEub21pdChncmFkZV9hdmVyYWdlXzJuZCkpKSksIA0KICAgICB0eXBlID0gImwiLCB5bGltID0gYygwLCAxKSwgDQogICAgIHlsYWIgPSAiUHJvYmFiaWxpZGFkIGFjdW11bGFkYSIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiLA0KICAgICB4bGFiID0gIlByb21lZGlvIGRlbCBzZWd1bmRvIHNlbWVzdHJlIiwgDQogICAgIG1haW4gPSAiRnVuY2lvbmVzIGRlIGRpc3RyaWJ1Y2nDs24gYWN1bXVsYWRhcyIpDQoNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCANCiAgICAgICBsZWdlbmQgPSBjKCJEaXN0cmlidWNpw7NuIE5vcm1hbCAodGXDs3JpY2EpIiwgIkRpc3RyaWJ1Y2nDs24gZW1ww61yaWNhIiksIA0KICAgICAgIGNvbCA9IGMoInJlZCIsICJibGFjayIpLCANCiAgICAgICBsdHkgPSAxLCANCiAgICAgICBsd2QgPSAyKQ0KDQpsaW5lcyhlY2RmKHB1bGwoZ3JhZGVfYXZlcmFnZV8ybmQpKSwgdmVydGljYWxzID0gVFJVRSwgZG8ucG9pbnRzID0gRkFMU0UsIGNvbC4wMWxpbmUgPSBOVUxMKQ0KDQojIFRlc3RzIGRlIEstUw0KDQprcy50ZXN0KHB1bGwoZ3JhZGVfYXZlcmFnZV8xc3QpLCANCiAgICAgICAgInBub3JtIiwgbWVhbiA9IG1lYW4ocHVsbChuYS5vbWl0KGdyYWRlX2F2ZXJhZ2VfMXN0KSkpLCANCiAgICAgICAgc2QgPSBzZChwdWxsKG5hLm9taXQoZ3JhZGVfYXZlcmFnZV8xc3QpKSkpDQoNCmtzLnRlc3QocHVsbChncmFkZV9hdmVyYWdlXzJuZCksIA0KICAgICAgICAicG5vcm0iLCBtZWFuID0gbWVhbihwdWxsKG5hLm9taXQoZ3JhZGVfYXZlcmFnZV8ybmQpKSksIA0KICAgICAgICBzZCA9IHNkKHB1bGwobmEub21pdChncmFkZV9hdmVyYWdlXzJuZCkpKSkNCg0KIyBSZXN1bHRhZG9zDQoNCiMgU2VtZXN0cmUgMQ0KIyBkYXRhOiAgcHVsbChncmFkZV9hdmVyYWdlXzFzdCkNCiMgRCA9IDAuMDQ4OTYyLCBwLXZhbHVlID0gMy44MzhlLTA4DQojIGFsdGVybmF0aXZlIGh5cG90aGVzaXM6IHR3by1zaWRlZA0KDQojIFNlbWVzdHJlIDINCiMgZGF0YTogIHB1bGwoZ3JhZGVfYXZlcmFnZV8ybmQpDQojIEQgPSAwLjA0NDE4NCwgcC12YWx1ZSA9IDEuODgxZS0wNg0KIyBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzOiB0d28tc2lkZWQNCg0KIyBDb21vIHAtdmFsdWUgPCAwLjA1LCBzZSByZWNoYXphIEgwXzEgeSBIMF8yIHkgc2UgY29uY2x1eWUgcXVlIGxvcyBwcm9tZWRpb3MNCiMgbm8gc2UgYWp1c3RhbiBhIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCB1c2FuZG8gSy1TIGNvbiB1bmEgc2lnbmlmaWNhbmNpYSBkZWwgNSUuDQoNCg0KDQojIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIA0KIyBDb21wYXJhY2nDs24gZW50cmUgbGFzIGRpc3RyaWJ1Y2lvbmVzIGRlIG5vdGFzIGRlbCBleGFtZW4gZGUgYWRtaXNpw7NuDQojIGVudHJlIGVzdHVkaWFudGVzIGdyYWR1YWRvcyB5IGRlc2VydG9yZXMgKGFkbWlzc2lvbiBncmFkZSkNCiMgLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gDQoNCmFkbWlzc2lvbl9ncmFkZSA8LSBkYXRvc191ICU+JSBzZWxlY3QoYEFkbWlzc2lvbiBncmFkZWApDQphZG1pc3Npb25fZ3JhZGUNCg0KIyBFeGFtZW4gZGUgYWRtaXNpw7NuIGRlIGxvcyBlc3R1ZGlhbnRlcyBxdWUgZGVzZXJ0YXJvbg0KYWRtaXNzaW9uX2dyYWRlX2Ryb3BvdXQgPC0gZGF0b3NfdSAlPiUNCiAgZmlsdGVyKFRhcmdldCA9PSAiRHJvcG91dCIpICU+JQ0KICBwdWxsKGBBZG1pc3Npb24gZ3JhZGVgKQ0KDQojIEV4YW1lbiBkZSBhZG1pc2nDs24gZGUgbG9zIGVzdHVkaWFudGVzIHF1ZSBzZSBncmFkdWFyb24NCmFkbWlzc2lvbl9ncmFkZV9ncmFkdWF0ZSA8LSBkYXRvc191ICU+JQ0KICBmaWx0ZXIoVGFyZ2V0ID09ICJHcmFkdWF0ZSIpICU+JQ0KICBwdWxsKGBBZG1pc3Npb24gZ3JhZGVgKQ0KDQojIEdyw6FmaWNhIGRlIENERnMNCg0KcGxvdChlY2RmKGFkbWlzc2lvbl9ncmFkZV9kcm9wb3V0KSwgDQogICAgIHZlcnRpY2FscyA9IFRSVUUsIGRvLnBvaW50cyA9IEZBTFNFLCBjb2wuMDFsaW5lID0gTlVMTCwgDQogICAgIHhsYWIgPSAiTm90YSBkZWwgZXhhbWVuIGRlIGFkbWlzacOzbiIsIHlsYWIgPSAiUHJvYmFiaWxpZGFkIGFjdW11bGFkYSIsDQogICAgIG1haW4gPSAiRnVuY2lvbmVzIGRlIGRpc3RyaWJ1Y2nDs24gYWN1bXVsYWRhcyIpDQpsaW5lcyhlY2RmKGFkbWlzc2lvbl9ncmFkZV9ncmFkdWF0ZSksDQogICAgICB2ZXJ0aWNhbHMgPSBUUlVFLCBkby5wb2ludHMgPSBGQUxTRSwgY29sLjAxbGluZSA9IE5VTEwsIGNvbCA9IDQpDQoNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCANCiAgICAgICBsZWdlbmQgPSBjKCJFc3R1ZGlhbnRlcyBkZXNlcnRvcmVzIiwgIkVzdHVkaWFudGVzIGdyYWR1YWRvcyIpLCANCiAgICAgICBjb2wgPSBjKCJibGFjayIsIDQpLCANCiAgICAgICBsdHkgPSAxLCANCiAgICAgICBsd2QgPSAyKQ0KDQoNCiMgwr9MYXMgbm90YXMgZGVsIGV4YW1lbiBkZSBhZG1pc2nDs24gZGUgbG9zIGVzdHVkaWFudGVzIHF1ZSBzZSBncmFkdWFyb24NCiMgc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbD8NCg0KIyBIMDogTGFzIG5vdGFzIGRlbCBleGFtZW4gZGUgYWRtaXNpw7NuIGRlIGxvcyBlc3R1ZGlhbnRlcyBxdWUgc2UgZ3JhZHVhcm9uDQojIHNpZ3VlbiB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwNCiMgSDE6IE5vIEgwDQoNCiMgVGVzdCBLLVMNCmtzLnRlc3QoYWRtaXNzaW9uX2dyYWRlX2dyYWR1YXRlLCAicG5vcm0iLA0KICAgICAgICBtZWFuID0gbWVhbihhZG1pc3Npb25fZ3JhZGVfZ3JhZHVhdGUpLCANCiAgICAgICAgc2QgPSBzZChhZG1pc3Npb25fZ3JhZGVfZ3JhZHVhdGUpKQ0KDQojIFJlc3VsdGFkbyANCiMgZGF0YTogIGFkbWlzc2lvbl9ncmFkZV9ncmFkdWF0ZQ0KIyBEID0gMC4wNjg0NDgsIHAtdmFsdWUgPSAyLjA0OWUtMDkNCiMgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpczogdHdvLXNpZGVkDQoNCiMgQ29tbyBwLXZhbHVlIGVzIG1lbm9yIGEgMC4wNSwgc2UgcmVjaGF6YSBIMCBjb24gdW5hIHNpZ25pZmljYW5jaWEgZGVsIDUlLg0KDQoNCiMgwr9MYXMgbm90YXMgZGVsIGV4YW1lbiBkZSBhZG1pc2nDs24gZGUgbG9zIGVzdHVkaWFudGVzIHF1ZSBzZSBncmFkdWFyb24gc2lndWVuDQojIGxhIG1pc21hIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIHF1ZSBkZXNlcnRhcm9uPw0KDQojIFRlc3QgSy1TDQprcy50ZXN0KGFkbWlzc2lvbl9ncmFkZV9kcm9wb3V0LCBhZG1pc3Npb25fZ3JhZGVfZ3JhZHVhdGUsIHNpbXVsYXRlLnAudmFsdWUgPSBUUlVFKQ0KIyBTZSBzaW11bGEgZWwgcC12YWxvciB1c2FuZG8gTW9udGUgQ2FybG8gcG9yIGxhIGRpc2NyZXRpemFjacOzbiBkZSBhcHJveGltYXIgYSANCiMgdW4gZGVjaW1hbCAobG8gcXVlIGxsZXZhIGEgImVtcGF0ZXMiIGVudHJlIGRhdG9zKQ0KDQojIFJlc3VsdGFkb3MNCg0KIyBNb250ZS1DYXJsbyB0d28tc2FtcGxlIEtvbG1vZ29yb3YtU21pcm5vdiB0ZXN0DQojIGRhdGE6ICBhZG1pc3Npb25fZ3JhZGVfZHJvcG91dCBhbmQgYWRtaXNzaW9uX2dyYWRlX2dyYWR1YXRlDQojIEQgPSAwLjEzOTcxLCBwLXZhbHVlID0gMC4wMDA0OTk4DQojIGFsdGVybmF0aXZlIGh5cG90aGVzaXM6IHR3by1zaWRlZA0KDQojIENvbW8gcC12YWx1ZSBlcyBtZW5vciBhIDAuMDUsIHNlIHJlY2hhemEgSDAgY29uIHVuYSBzaWduaWZpY2FuY2lhIGRlbCA1JSB5IA0KIyBzZSBjb25jbHV5ZSBxdWUgbGFzIGRpc3RyaWJ1Y2lvbmVzIGRpZmllcmVuIHNpZ25pZmljYXRpdmFtZW50ZS4NCg0KYGBgDQpub3JtYWxpZGFkIA0KDQp2YW1vcyBhIG1pcmFyIGxhcyBwcnVlYmFzIGRlIG5vcm1hbGlkYWQgc29icmUgbGFzIHZhcmlhYmxlcyBjb250aW51YXMsIA0KbGFzIHZhcmlhYmxlcyBjb250aW51YXMgc29uOg0KcHJldmlvdXMgcXVhbGlmaWNhdGlvbiAoZ3JhZGUpDQphZG1pc3Npb24gZ3JhZGUNCmN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbShncmFkZSkNCmN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbShncmFkZSkNCnVuZXBsb3ltZW50IHJhdGUNCmluZmxhdGlvbiByYXRlDQpHRFANCg0KYGBge3J9DQpiYXNlXzIgPC0gZGF0b3NfdQ0KYmFzZV8yJHRyYW5zZm9ybWFkYSA8LSAwIA0KDQpoaXN0b19ub3JtIDwtIGZ1bmN0aW9uKGEpew0KICANCiAgYmFzZV8yW1thXV0gPC0gYXMubnVtZXJpYyhiYXNlXzJbW2FdXSkNCiAgYXNpbWUgPC0gc2tld25lc3MoYmFzZV8yW1thXV0sIG5hLnJtID0gVFJVRSkNCiAgDQogIGIgPC0gYmFzZV8yJT4lIGdncGxvdChhZXMoeD1iYXNlXzJbW2FdXSx5PS4uZGVuc2l0eS4uKSkrDQogICAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0ic2VhZ3JlZW4yIixjb2xvcj0id2hpdGUiKSsNCiAgICBnZW9tX2xpbmUoYWVzKHg9YmFzZV8yW1thXV0seT1kbm9ybShiYXNlXzJbW2FdXSxtZWFuKGJhc2VfMltbYV1dKSxzZChiYXNlXzJbW2FdXSkpKSxjb2xvcj0iZGVlcHBpbms0IixzaXplPTEpKw0KICAgIGdndGl0bGUoYSkrDQogICAgbGFicyh4PWEseT0iZGVuc2lkYWQgIikrDQogICAgdGhlbWVfbWluaW1hbCgpDQogIHByaW50KHBhc3RlKCJBc2ltZXRyw61hOiIsIGFzaW1lKSkNCiAgcHJpbnQobGlsbGllLnRlc3QoYmFzZV8yW1thXV0pKQ0KICByZXR1cm4oYikNCn0NCg0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShlMTA3MSkgICMgUGFyYSB1c2FyIHNrZXduZXNzKCkNCg0KDQojMQ0KaGlzdG9fbm9ybSgiUHJldmlvdXMgcXVhbGlmaWNhdGlvbiAoZ3JhZGUpIikNCnByaW50KCJubyBzaWd1ZSB1bmEgbm9ybWFsLCBhaG9yYSBtaXJhcmVtb3MgZW50cmUgbGFzIHRyYW5zZm9ybWFjaW9uZXMgYSB2ZXIgY3VhbCBhanVzdGEgbGEgdmFyaWFibGUNCiAgICAgIGEgdW5hIG5vcm1hbCIpDQpiYXNlXzIkYFByZXZpb3VzIHF1YWxpZmljYXRpb24gKGdyYWRlKWAgPC0gYXMubnVtZXJpYyhiYXNlXzIkYFByZXZpb3VzIHF1YWxpZmljYXRpb24gKGdyYWRlKWApDQpjb2x1bW5hPWJhc2VfMiRgUHJldmlvdXMgcXVhbGlmaWNhdGlvbiAoZ3JhZGUpYA0KYmFzZV8yJGBQcmV2aW91cyBxdWFsaWZpY2F0aW9uIChncmFkZSlgIDwtIGFzLm51bWVyaWMoYmFzZV8yJGBQcmV2aW91cyBxdWFsaWZpY2F0aW9uIChncmFkZSlgKQ0KI2hhY2Vtb3MgdHJhbnNmb3JtYWNpb24NCmJhc2VfMiA8LSBiYXNlXzIgJT4lIG11dGF0ZSh0cmFuc2Zvcm1hZGEgPSBzcXJ0KGJhc2VfMiRgUHJldmlvdXMgcXVhbGlmaWNhdGlvbiAoZ3JhZGUpYCkpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQpiYXNlXzIgPC0gIGJhc2VfMiAlPiUgbXV0YXRlKHRyYW5zZm9ybWFkYSA9IGxvZzFwKGNvbHVtbmEgKyAxKSkNCmhpc3RvX25vcm0oInRyYW5zZm9ybWFkYSIpDQpiYXNlXzIgPC0gIGJhc2VfMiAgJT4lIG11dGF0ZSh0cmFuc2Zvcm1hZGEgPSAxIC8gKGNvbHVtbmEgKyAxKSkNCmhpc3RvX25vcm0oInRyYW5zZm9ybWFkYSIpDQoNCiNlbiBlc3RlIGNhc28gbGEgbWFzIGNlcmNhbmEgZnVlIGxhIHRyYW5zZm9ybWFjaW9uIGFsIGN1YWRyYWRvIHNpbiBlbWJhcmdvIHNpZ3VlIHNpbiBzZWd1aXIgDQojdW5hIGRpc3RyaWJ1Y2lvbiBub3JtYWwsIGVzdG8gZGViaWRvIGEgcXVlIHNlIHJlY2hhemFuIGxhcyBwcnVlYmFzLHBvciBsbyB0YW50byBzZSB0aWVuZW4gcXVlICNoYWNlciBwcnVlYmFzIG5vIHBhcmFtZXRyaWNhcyBzb2JyZSBlc3RhIg0KDQojMg0KYmFzZV8yJGBBZG1pc3Npb24gZ3JhZGVgIDwtIGFzLm51bWVyaWMoYmFzZV8yJGBBZG1pc3Npb24gZ3JhZGVgKQ0KDQojIFZpc3VhbGl6YSBlbCBoaXN0b2dyYW1hIG9yaWdpbmFsDQpoaXN0b19ub3JtKCJBZG1pc3Npb24gZ3JhZGUiKQ0KcHJpbnQoIk5vIHNpZ3VlIHVuYSBub3JtYWwsIHNpbiBlbWJhcmdvIHNlIHBvZHLDrWEgYXByb3hpbWFyIGNvbiB1bmEgdHJhbnNmb3JtYWNpw7NuLiIpDQoNCiMgR3VhcmRhIGxhIGNvbHVtbmEgb3JpZ2luYWwNCmNvbHVtbmExIDwtIGJhc2VfMiRgQWRtaXNzaW9uIGdyYWRlYA0KDQojIC0tLSBUcmFuc2Zvcm1hY2nDs24gcmHDrXogY3VhZHJhZGEgLS0tDQpiYXNlXzIgPC0gYmFzZV8yICU+JSBtdXRhdGUodHJhbnNmb3JtYWRhID0gc3FydChjb2x1bW5hMSkpDQpwcmludCgiVHJhbnNmb3JtYWNpw7NuOiByYcOteiBjdWFkcmFkYSIpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQojIC0tLSBUcmFuc2Zvcm1hY2nDs24gbG9nYXLDrXRtaWNhIC0tLQ0KYmFzZV8yIDwtIGJhc2VfMiAlPiUgbXV0YXRlKHRyYW5zZm9ybWFkYSA9IGxvZzFwKGNvbHVtbmExICsgMSkpDQpwcmludCgiVHJhbnNmb3JtYWNpw7NuOiBsb2dhcsOtdG1pY2EiKQ0KaGlzdG9fbm9ybSgidHJhbnNmb3JtYWRhIikNCg0KIyAtLS0gVHJhbnNmb3JtYWNpw7NuIGludmVyc2EgLS0tDQpiYXNlXzIgPC0gYmFzZV8yICU+JSBtdXRhdGUodHJhbnNmb3JtYWRhID0gMSAvIChjb2x1bW5hMSArIDEpKQ0KcHJpbnQoIlRyYW5zZm9ybWFjacOzbjogaW52ZXJzYSIpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQojZWwgcXVlIHByZXNlbnRvIG1lbm9zIGFzaW1ldHJpYSBmdWUgbGEgdHJhbnNmb3JtYWNpb24gbG9nYXJpdG1pY2EsIHNpbiBlbWJhcmdvIHNpZ3VlIHNpbiBzZWd1aXIgdW5hIA0KI2Rpc3RyaWJ1Y2lvbiBub3JtYWwgeSByZWNoYXphIGxhcyBwcnVlYmFzIGRlIGhpcG90ZXNpcyBlbnRvbmNlcyBzZSB0aWVuZW4gcXVlIGhhY2UgcHJ1ZWJhcyBubyBwYXJhbWV0cmljYXMgDQojc29icmUgZXN0YSANCg0KDQojMw0KIyBBc2VndXJhIHF1ZSBsYSB2YXJpYWJsZSBzZWEgbnVtw6lyaWNhDQpiYXNlXzIgPC0gZGF0b3NfdQ0KYmFzZV8yJHRyYW5zZm9ybWFkYSA8LTAgDQoNCmJhc2VfMiRgQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChjcmVkaXRlZClgIDwtIGFzLm51bWVyaWMoYmFzZV8yJGBDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGNyZWRpdGVkKWApDQoNCiMgVmlzdWFsaXphIGVsIGhpc3RvZ3JhbWEgb3JpZ2luYWwNCg0KaGlzdG9fbm9ybSgiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChjcmVkaXRlZCkiKQ0KcHJpbnQoIk5vIHNpZ3VlIHVuYSBub3JtYWwsIHNpbiBlbWJhcmdvIHNlIHBvZHLDrWEgYXByb3hpbWFyIGNvbiB1bmEgdHJhbnNmb3JtYWNpw7NuLiIpDQpwcmludCgiaW50ZW50YXJlbW9zIHZlciBjb21vIHNlIGNvbXBvcnRhIHNpIHJldGlyYW1vcyBsb3MgdmFsb3JlcyBxdWUgc29uIDAiKQ0KYmFzZV8yPC0gYmFzZV8yW2RhdG9zX3UkYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoY3JlZGl0ZWQpYD4wLF0NCmJhc2VfMiAlPiUgZGltKCkNCnByaW50KCJzZSBwaWVyZGVuIGRlbWFzaWFkb3MgZGF0b3MsIG5vIHZhbGUgbGEgcGVuYSAiKQ0KaGlzdG9fbm9ybSgiQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChjcmVkaXRlZCkiKQ0KDQojIEd1YXJkYSBsYSBjb2x1bW5hIG9yaWdpbmFsDQpjb2x1bW5hMiA8LSBiYXNlXzIkYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoY3JlZGl0ZWQpYA0KDQojIC0tLSBUcmFuc2Zvcm1hY2nDs24gcmHDrXogY3VhZHJhZGEgLS0tDQpiYXNlXzIgPC0gYmFzZV8yICU+JSBtdXRhdGUodHJhbnNmb3JtYWRhID0gc3FydChjb2x1bW5hMikpDQpwcmludCgiVHJhbnNmb3JtYWNpw7NuOiByYcOteiBjdWFkcmFkYSIpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQojIC0tLSBUcmFuc2Zvcm1hY2nDs24gbG9nYXLDrXRtaWNhIC0tLQ0KYmFzZV8yIDwtIGJhc2VfMiAlPiUgbXV0YXRlKHRyYW5zZm9ybWFkYSA9IGxvZzFwKGNvbHVtbmEyICsgMSkpDQpwcmludCgiVHJhbnNmb3JtYWNpw7NuOiBsb2dhcsOtdG1pY2EiKQ0KaGlzdG9fbm9ybSgidHJhbnNmb3JtYWRhIikNCg0KIyAtLS0gVHJhbnNmb3JtYWNpw7NuIGludmVyc2EgLS0tDQpiYXNlXzIgPC0gYmFzZV8yICU+JSBtdXRhdGUodHJhbnNmb3JtYWRhID0gMSAvIChjb2x1bW5hMiArIDEpKQ0KcHJpbnQoIlRyYW5zZm9ybWFjacOzbjogaW52ZXJzYSIpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQpwcmludCgic2UgdGllbmUgcXVlIHByb2NlZGVyIGNvbiBwcnVlYmFzIG5vIHBhcmFtZXRyaWNhcyIpIA0KDQojNA0KIyBBc2VndXJhIHF1ZSBsYSB2YXJpYWJsZSBzZWEgbnVtw6lyaWNhDQpiYXNlXzIgPC0gZGF0b3NfdQ0KYmFzZV8yJHRyYW5zZm9ybWFkYSA8LSAwDQoNCmJhc2VfMiRgQ3VycmljdWxhciB1bml0cyAybmQgc2VtIChncmFkZSlgIDwtIGFzLm51bWVyaWMoYmFzZV8yJGBDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGdyYWRlKWApDQoNCiMgVmlzdWFsaXphIGVsIGhpc3RvZ3JhbWEgb3JpZ2luYWwNCmhpc3RvX25vcm0oIkN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoZ3JhZGUpIikNCnByaW50KCJObyBzaWd1ZSB1bmEgbm9ybWFsLCBzaW4gZW1iYXJnbyBzZSBwb2Ryw61hIGFwcm94aW1hciBjb24gdW5hIHRyYW5zZm9ybWFjacOzbi4iKQ0KcHJpbnQoIkludGVudGFyZW1vcyB2ZXIgY8OzbW8gc2UgY29tcG9ydGEgc2kgcmV0aXJhbW9zIGxvcyB2YWxvcmVzIHF1ZSBzb24gMCIpDQoNCiMgUmV0aXJhIGxvcyBjZXJvcw0KYmFzZV8yIDwtIGJhc2VfMltiYXNlXzIkYEN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoZ3JhZGUpYCA+IDAsIF0NCmJhc2VfMiAlPiUgZGltKCkNCnByaW50KCJFbiBlc3RlIGNhc28gcGVyZGVtb3MgY2VyY2EgZGUgMTAwMCBkYXRvcyIpDQoNCmhpc3RvX25vcm0oIkN1cnJpY3VsYXIgdW5pdHMgMm5kIHNlbSAoZ3JhZGUpIikNCg0KIyBHdWFyZGEgbGEgY29sdW1uYSBvcmlnaW5hbA0KY29sdW1uYTMgPC0gYmFzZV8yJGBDdXJyaWN1bGFyIHVuaXRzIDJuZCBzZW0gKGdyYWRlKWANCg0KIyAtLS0gVHJhbnNmb3JtYWNpw7NuIHJhw616IGN1YWRyYWRhIC0tLQ0KYmFzZV8yIDwtIGJhc2VfMiAlPiUgbXV0YXRlKHRyYW5zZm9ybWFkYSA9IHNxcnQoY29sdW1uYTMpKQ0KcHJpbnQoIlRyYW5zZm9ybWFjacOzbjogcmHDrXogY3VhZHJhZGEiKQ0KaGlzdG9fbm9ybSgidHJhbnNmb3JtYWRhIikNCg0KIyAtLS0gVHJhbnNmb3JtYWNpw7NuIGxvZ2Fyw610bWljYSAtLS0NCmJhc2VfMiA8LSBiYXNlXzIgJT4lIG11dGF0ZSh0cmFuc2Zvcm1hZGEgPSBsb2cxcChjb2x1bW5hMyArIDEpKQ0KcHJpbnQoIlRyYW5zZm9ybWFjacOzbjogbG9nYXLDrXRtaWNhIikNCmhpc3RvX25vcm0oInRyYW5zZm9ybWFkYSIpDQoNCiMgLS0tIFRyYW5zZm9ybWFjacOzbiBpbnZlcnNhIC0tLQ0KYmFzZV8yIDwtIGJhc2VfMiAlPiUgbXV0YXRlKHRyYW5zZm9ybWFkYSA9IDEgLyAoY29sdW1uYTMgKyAxKSkNCnByaW50KCJUcmFuc2Zvcm1hY2nDs246IGludmVyc2EiKQ0KaGlzdG9fbm9ybSgidHJhbnNmb3JtYWRhIikNCg0KIyBDb25jbHVzacOzbg0KcHJpbnQoIlNlIGRlYmUgY29uc2lkZXJhciB1c2FyIHBydWViYXMgbm8gcGFyYW3DqXRyaWNhcyBzaSBsYXMgdHJhbnNmb3JtYWNpb25lcyBubyBsb2dyYW4gbm9ybWFsaXphciBsYSB2YXJpYWJsZS4iKQ0KDQojNQ0KIyBBc2VndXJhIHF1ZSBsYSB2YXJpYWJsZSBzZWEgbnVtw6lyaWNhIHkgcmVpbmljaWEgYmFzZV8yDQpiYXNlXzIgPC0gZGF0b3NfdQ0KYmFzZV8yJHRyYW5zZm9ybWFkYSA8LSAwDQoNCmJhc2VfMiRgSW5mbGF0aW9uIHJhdGVgIDwtIGFzLm51bWVyaWMoYmFzZV8yJGBJbmZsYXRpb24gcmF0ZWApDQoNCiMgVmlzdWFsaXphIGVsIGhpc3RvZ3JhbWEgb3JpZ2luYWwNCmhpc3RvX25vcm0oIkluZmxhdGlvbiByYXRlIikNCnByaW50KCJObyBzaWd1ZSB1bmEgbm9ybWFsLCBzaW4gZW1iYXJnbyBzZSBwb2Ryw61hIGFwcm94aW1hciBjb24gdW5hIHRyYW5zZm9ybWFjacOzbi4iKQ0KcHJpbnQoIkludGVudGFyZW1vcyB2ZXIgY8OzbW8gc2UgY29tcG9ydGEgc2kgcmV0aXJhbW9zIGxvcyB2YWxvcmVzIHF1ZSBzb24gMCIpDQoNCiMgUmV0aXJhIGxvcyBjZXJvcw0KYmFzZV8yIDwtIGJhc2VfMltiYXNlXzIkYEluZmxhdGlvbiByYXRlYCAhPSAwLCBdDQpiYXNlXzIgJT4lIGRpbSgpDQpwcmludCgicG9kZW1vcyB2ZXIgcXVlIHNlIHBpZXJkZW4gbWFzIGRlIG1pbCBkYXRvcyIpDQoNCiMgUmV2aXNhIGRlIG51ZXZvIGVsIGhpc3RvZ3JhbWEgY29uIGxvcyBkYXRvcyBzaW4gY2Vyb3MNCmhpc3RvX25vcm0oIkluZmxhdGlvbiByYXRlIikNCg0KIyBHdWFyZGEgbGEgY29sdW1uYSBvcmlnaW5hbCBzaW4gY2Vyb3MNCmNvbHVtbmE0IDwtIGJhc2VfMiRgSW5mbGF0aW9uIHJhdGVgDQoNCiMgLS0tIFRyYW5zZm9ybWFjacOzbiByYcOteiBjdWFkcmFkYSAtLS0NCmJhc2VfMiA8LSBiYXNlXzIgJT4lIG11dGF0ZSh0cmFuc2Zvcm1hZGEgPSBzcXJ0KGNvbHVtbmE0KSkNCnByaW50KCJUcmFuc2Zvcm1hY2nDs246IHJhw616IGN1YWRyYWRhIikNCmhpc3RvX25vcm0oInRyYW5zZm9ybWFkYSIpDQoNCiMgLS0tIFRyYW5zZm9ybWFjacOzbiBsb2dhcsOtdG1pY2EgLS0tDQpiYXNlXzIgPC0gYmFzZV8yICU+JSBtdXRhdGUodHJhbnNmb3JtYWRhID0gbG9nMXAoY29sdW1uYTQgKyAxKSkNCnByaW50KCJUcmFuc2Zvcm1hY2nDs246IGxvZ2Fyw610bWljYSIpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQojIC0tLSBUcmFuc2Zvcm1hY2nDs24gaW52ZXJzYSAtLS0NCmJhc2VfMiA8LSBiYXNlXzIgJT4lIG11dGF0ZSh0cmFuc2Zvcm1hZGEgPSAxIC8gKGNvbHVtbmE0ICsgMSkpDQpwcmludCgiVHJhbnNmb3JtYWNpw7NuOiBpbnZlcnNhIikNCmhpc3RvX25vcm0oInRyYW5zZm9ybWFkYSIpDQoNCiMgQ29uY2x1c2nDs24NCnByaW50KCJuaSBjb24gdHJ0YW1pZW50byBhdGlwaWNvIGRlIGRhdG9zLCBuaSBjb24gdHJhc25mb3JtYWNpb25lcyBzZSBwdWRvIGV2aWRlbmNpYXIgcXVlIHNpZ3VpZXJhIHVuYSBub3JtYWwsIHNlIGRlYmUgcHJvY2VkZXIgY29uIHBydWViYXMgbm8gcGFyYW1ldHJpY2FzICIpDQoNCiM2DQoNCiMgQXNlZ3VyYSBxdWUgbGEgdmFyaWFibGUgc2VhIG51bcOpcmljYSB5IHJlaW5pY2lhIGJhc2VfMg0KYmFzZV8yIDwtIGRhdG9zX3UNCmJhc2VfMiR0cmFuc2Zvcm1hZGEgPC0gMA0KDQpiYXNlXzIkR0RQIDwtIGFzLm51bWVyaWMoYmFzZV8yJEdEUCkNCg0KIyBWaXN1YWxpemEgZWwgaGlzdG9ncmFtYSBvcmlnaW5hbA0KaGlzdG9fbm9ybSgiR0RQIikNCnByaW50KCJObyBzaWd1ZSB1bmEgbm9ybWFsLCBzaW4gZW1iYXJnbyBzZSBwb2Ryw61hIGFwcm94aW1hciBjb24gdW5hIHRyYW5zZm9ybWFjacOzbi4iKQ0KcHJpbnQoIkludGVudGFyZW1vcyB2ZXIgY8OzbW8gc2UgY29tcG9ydGEgc2kgcmV0aXJhbW9zIGxvcyB2YWxvcmVzIHF1ZSBzb24gMCIpDQoNCiMgUmV0aXJhIGxvcyBjZXJvcw0KYmFzZV8yIDwtIGJhc2VfMltiYXNlXzIkR0RQID4gMCwgXQ0KYmFzZV8yICU+JSBkaW0oKQ0KcHJpbnQoInNlIHBpZXJkZW4gbWFzIGRlIDIwMDAgZGF0b3MiKQ0KDQojIFJldmlzYSBkZSBudWV2byBlbCBoaXN0b2dyYW1hIGNvbiBsb3MgZGF0b3Mgc2luIGNlcm9zDQpoaXN0b19ub3JtKCJHRFAiKQ0KDQojIEd1YXJkYSBsYSBjb2x1bW5hIG9yaWdpbmFsIHNpbiBjZXJvcw0KY29sdW1uYTUgPC0gYmFzZV8yJEdEUA0KDQojIC0tLSBUcmFuc2Zvcm1hY2nDs24gcmHDrXogY3VhZHJhZGEgLS0tDQpiYXNlXzIgPC0gYmFzZV8yICU+JSBtdXRhdGUodHJhbnNmb3JtYWRhID0gc3FydChjb2x1bW5hNSkpDQpwcmludCgiVHJhbnNmb3JtYWNpw7NuOiByYcOteiBjdWFkcmFkYSIpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQojIC0tLSBUcmFuc2Zvcm1hY2nDs24gbG9nYXLDrXRtaWNhIC0tLQ0KYmFzZV8yIDwtIGJhc2VfMiAlPiUgbXV0YXRlKHRyYW5zZm9ybWFkYSA9IGxvZzFwKGNvbHVtbmE1ICsgMSkpDQpwcmludCgiVHJhbnNmb3JtYWNpw7NuOiBsb2dhcsOtdG1pY2EiKQ0KaGlzdG9fbm9ybSgidHJhbnNmb3JtYWRhIikNCg0KIyAtLS0gVHJhbnNmb3JtYWNpw7NuIGludmVyc2EgLS0tDQpiYXNlXzIgPC0gYmFzZV8yICU+JSBtdXRhdGUodHJhbnNmb3JtYWRhID0gMSAvIChjb2x1bW5hNSArIDEpKQ0KcHJpbnQoIlRyYW5zZm9ybWFjacOzbjogaW52ZXJzYSIpDQpoaXN0b19ub3JtKCJ0cmFuc2Zvcm1hZGEiKQ0KDQojIENvbmNsdXNpw7NuDQpwcmludCgiYSBwZXNhciBkZSBsYXMgdHJhc25mb3JtYWNpb25lcyBubyBtdWVzdHJhIHNlZ3VpciB1bmEgZGlzdHJpYnVjaW9uIG5vcm1hbCwgc2UgdGVuZHJhIHF1ZSBtYW5lamFyIGNvbiBwcnVlYmFzIG5vIHBhcmFtZXRyaWNhcyAiKQ0KDQoNCg0KDQpgYGANCg0KIiIiDQpOSW5ndW5hIGRlIGxhcyB2YXJpYWJsZXMgY29udGludWFzIHNlIHB1ZWRlIG1hbmVqYXIgY29tbyB1bmEgbm9ybWFsLCBwb3IgbG8gdGFudG8gYSB0b2RhcyBzZSBsZXMgdGVuZHJhIHF1ZSANCmhhY2VyIHBydWViYXMgbm8gcGFyYW1ldHJpY2FzIA0KDQoiIiINCg0KYGBge3J9DQpjYXQoImgwOiBMYSBtZWRpYSBtdWVzdHJhbCAobyBtZWRpYW5hKSBkZSBjcsOpZGl0b3MgYXByb2JhZG9zIGVuIGVsIHByaW1lciBzZW1lc3RyZSBkZSBsb3MgRHJvcG91dCBlcyBtZW5vciBvIGlndWFsIGEgbGEgZGUgbG9zIEdyYWR1YWRvcy4NCg0KSOKCgTogTGEgbWVkaWEgbXVlc3RyYWwgZGUgbG9zIHF1ZSBhcHJ1ZWJhbiB0b2RvcyBzdXMgY3LDqWRpdG9zIGVuIHByaW1lciBzZW1lc3RyZSBwZXJvIG5vIHNlIGdyYWTDumFuIGVzIG1heW9yIHF1ZSBsYSBkZSBsb3MgcXVlIHPDrSBzZSBncmFkw7phbi4NCiIpDQoNCmNhdCgiTWlyYW1vcyBzaSBlbCBjb21wb3J0YW1pZW50byBkZSBsYXMgZG9zIGdyw6FmaWNhcyBlcyBub3JtYWw6XG4iKQ0KDQpoaXN0b2dyYW1hX2JpKCJDdXJyaWN1bGFyIHVuaXRzIDFzdCBzZW0gKGFwcHJvdmVkKSIsIlRhcmdldCIpDQoNCmNhdCgiTm90YW1vcyBxdWUgbm8gc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCwgcG9yIGxvIHRhbnRvIA0KdXNhbW9zIHRyYW5zZm9ybWFjaW9uZXM6XG4iKQ0KDQpkYXRvc191IDwtIGRhdG9zX3UgJT4lIG11dGF0ZShhcHByb3Zlc19sb2cgPSBsb2cxcChgQ3VycmljdWxhciB1bml0cyAxc3Qgc2VtIChhcHByb3ZlZClgKSkNCmhpc3RvZ3JhbWFfYmkoImFwcHJvdmVzX2xvZyIsIlRhcmdldCIpDQoNCmNhdCgiUHJvYmFtb3MgcHJ1ZWJhcyBkZSBub3JtYWxpZGFkIHNvYnJlIGVzdGFzIGRvcyB2YXJpYWJsZXM6XG4iKQ0KDQpkZXNjcmlwY2lvbigiYXBwcm92ZXNfbG9nIiwiVGFyZ2V0IikNCg0KZGF0b3NfZHJvcCA8LSBkYXRvc191ICU+JSBmaWx0ZXIoVGFyZ2V0ID09ICJEcm9wb3V0IikNCmRhdG9zX2dyYWQgPC0gZGF0b3NfdSAlPiUgZmlsdGVyKFRhcmdldD09IkdyYWR1YXRlIikNCg0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpDQoNCmxpbGxpZS50ZXN0KGRhdG9zX2Ryb3AkYXBwcm92ZXNfbG9nKQ0KbGlsbGllLnRlc3QoZGF0b3NfZ3JhZCRhcHByb3Zlc19sb2cpDQoNCmNhdCgiQcO6biBubyBzaWd1ZW4gdW5hIG5vcm1hbCA6KCBcbiIpDQoNCiMgUHJ1ZWJhIE5vIFBhcmFtw6l0cmljYTogLS0tLS0NCg0Kd2lsY294LnRlc3QoDQogIGRhdG9zX2Ryb3AkYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoYXBwcm92ZWQpYCwgDQogIGRhdG9zX2dyYWQkYEN1cnJpY3VsYXIgdW5pdHMgMXN0IHNlbSAoYXBwcm92ZWQpYCwgDQogIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiDQopDQpgYGAgDQpFbCBwLXZhbHVlIGVzIG1heW9yIGEgMC4wMDUgZW50b25jZXMgbm8gc2UgcmVjaGF6YSBoMC4=