Teoría Regresión cuantilíca

La regresión cuantílica (Quantile Regression) es una técnica estadística que permite modelar la relación entre una variable dependiente y una o más variables independientes en distintos puntos de la distribución condicional de la variable dependiente.

¿Por qué usar Quantile Regression?

  • Permite obtener intervalos de predicción, lo cual es útil para la toma de decisiones en negocios.
  • A diferencia de los métodos no lineales tradicionales de aprendizaje supervisado, ofrece una forma explícita de obtener intervalos de predicción.
  • Mejora la precisión en comparación con el uso de intervalos de predicción basados en regresión lineal estándar.

¿Para qué sirve la Quantile Regression?

  • Es útil para analizar distribuciones asimétricas y detectar efectos diferenciados en distintos niveles.

  • Proporciona una mejor comprensión de la heterogeneidad en los datos.

  • Es robusta a valores atípicos, ya que minimiza una función de pérdida asimétrica.

  • Se usa en análisis económico, modelos de riesgo, bioestadística y otras aplicaciones donde la variabilidad es clave.

  • Permite modelar relaciones no capturadas por la regresión lineal ordinaria.

  • Es aplicable cuando la relación entre las variables cambia en distintos puntos de la distribución.

Diferencias clave entre OLS y Quantile Regression

  • OLS (Regresión Lineal Ordinaria): Minimiza el error cuadrático medio (MSE) y modela la media condicional.

  • Quantile Regression: Minimiza una función de pérdida ponderada, lo que permite estimar distintos cuantiles.

  • Robustez: Quantile Regression es menos sensible a valores atípicos que OLS.

  • Flexibilidad: Mientras OLS asume homocedasticidad (varianza constante del error), Quantile Regression permite heterocedasticidad.

Ejemplos de Aplicación

  • Economía: Evaluación de desigualdad en ingresos, determinando cómo factores afectan diferentes niveles salariales.
  • Finanzas: Modelado de riesgos en mercados financieros.
  • Medicina: Análisis de percentiles en medidas biomédicas como presión arterial o peso infantil.
  • Ciencias sociales: Evaluación de impacto de políticas en distintos grupos poblacionales.

Cargar las líbrerias necesarias

#install.packages("quantreg")
library(quantreg)
#install.packages("ggplot")
library(ggplot2)

Descripción del Análisis

En este ejemplo, usaremos Quantile Regression para analizar el impacto del peso del auto (wt)en el consumo de combustible (mpg) usando el dataset mtcars.

Cargar datos (mtcars)

#Esta base de datos viene ya dentro de R
data(mtcars)

Revisar las primeras filas del dataset

head(mtcars) 
##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

Definir Variables

df <- mtcars
df$X <- df$wt  # Peso del auto
df$y <- df$mpg  # Millas por galón

Ajustar un modelo de Quantile Regression para diferentes cuantiles

quantiles <- c(0.1, 0.5, 0.9)  # Percentiles 10, 50 y 90
models <- lapply(quantiles, function(q) rq(y ~ X, tau = q, data = df)) 
# q representa cada uno de los percetiles 
#tau controla qué parte de la distribución condicional estamos modelando.
summary(quantiles)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     0.1     0.3     0.5     0.5     0.7     0.9

Ajustar un modelo de Regresión Lineal estándar para comparación

lm_model <- lm(y ~ X, data = df)

Crear un dataframe para almacenar predicciones

# Creamos un data frame con una secuencia de valores de X que van desde el mínimo hasta el máximo en df$X
X_seq <- data.frame(X = seq(min(df$X), max(df$X), length.out = 100))
# Crear un nuevo data frame para almacenar las predicciones del modelo de regresión
pred_df <- data.frame(
  X = X_seq$X,
  OLS = predict(lm_model, newdata = X_seq)
)

Agregar predicciones de regresión cuantílica

#loop que recorre todos los cuantiles definidos en la variable 'quantiles'
for (i in 1:length(quantiles)) {
  pred_df[[paste0("Q", quantiles[i] * 100)]] <- predict(models[[i]], newdata = X_seq)
}

Graficar resultados

plot <- ggplot(data = df, aes(x = X, y = y)) +
  geom_point(alpha = 0.5) +  # Puntos de datos reales
  geom_line(data = pred_df, aes(x = X, y = OLS, color = "OLS"), linetype = "dashed") +
  geom_line(data = pred_df, aes(x = X, y = Q10, color = "Quantile 10")) +
  geom_line(data = pred_df, aes(x = X, y = Q50, color = "Quantile 50")) +
  geom_line(data = pred_df, aes(x = X, y = Q90, color = "Quantile 90")) +
  scale_color_manual(values = c("black", "blue", "red", "green")) +
  labs(title = "Comparación de Regresión Cuantílica y Lineal",
       x = "Peso del Auto (wt)",
       y = "Millas por Galón (mpg)",
       color = "Modelo") +
  theme_minimal()
print(plot)

Explicación

  • La línea negra discontinua representa la regresión lineal estándar (OLS).

  • Las líneas azul, roja y verde representan las regresiones cuantílicas para los percentiles 10, 50 y 90. *Línea azul (Quantile 10): Muestra cómo los autos con menor consumo de gasolina (percentil 10) están afectados por el peso.

    *Línea roja (Quantile 50 - Mediana): Representa la relación mediana entre wt y mpg, equivalente a la regresión cuantílica en el percentil 50.

    *Línea verde (Quantile 90): Modela la relación para los autos con mejor consumo de gasolina (percentil 90).

-OLS subestima o sobreestima en ciertas regiones, ya que solo modela la media de mpg, mientras que Quantile Regression permite entender cómo cambia mpg en diferentes niveles.

Referencias

  • Ngieng Kianyew, Understanding How Quantile Regression Works, Medium (2023).
LS0tCnRpdGxlOiAiUXVhbnRpbGUgUmVncmVzc2lvbiIKYXV0aG9yOiAiVml2aWFuYSBEdXLDoW5fIEEwMDgzNzc3NiIKZGF0ZTogIjIwMjUtMDItMjciCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKICAgIHRoZW1lOiBqb3VybmFsCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKLS0tCgojIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHB1cnBsZTsiPlRlb3LDrWEgUmVncmVzacOzbiBjdWFudGlsw61jYSA8L3NwYW4+CkxhIHJlZ3Jlc2nDs24gY3VhbnTDrWxpY2EgKFF1YW50aWxlIFJlZ3Jlc3Npb24pIGVzIHVuYSB0w6ljbmljYSBlc3RhZMOtc3RpY2EgcXVlIHBlcm1pdGUgbW9kZWxhciBsYSByZWxhY2nDs24gZW50cmUgdW5hIHZhcmlhYmxlIGRlcGVuZGllbnRlIHkgdW5hIG8gbcOhcyB2YXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMgZW4gZGlzdGludG9zIHB1bnRvcyBkZSBsYSBkaXN0cmlidWNpw7NuIGNvbmRpY2lvbmFsIGRlIGxhIHZhcmlhYmxlIGRlcGVuZGllbnRlLgogCiMjIyA8c3BhbiBzdHlsZT0gIkNvbG9yOiB2aW9sZXQ7Ij7Cv1BvciBxdcOpIHVzYXIgUXVhbnRpbGUgUmVncmVzc2lvbj88L3NwYW4+Ci0gUGVybWl0ZSBvYnRlbmVyIGludGVydmFsb3MgZGUgcHJlZGljY2nDs24sIGxvIGN1YWwgZXMgw7p0aWwgcGFyYSBsYSB0b21hIGRlIGRlY2lzaW9uZXMgZW4gbmVnb2Npb3MuCi0gQSBkaWZlcmVuY2lhIGRlIGxvcyBtw6l0b2RvcyBubyBsaW5lYWxlcyB0cmFkaWNpb25hbGVzIGRlIGFwcmVuZGl6YWplIHN1cGVydmlzYWRvLCBvZnJlY2UgdW5hIGZvcm1hIGV4cGzDrWNpdGEgZGUgb2J0ZW5lciBpbnRlcnZhbG9zIGRlIHByZWRpY2Npw7NuLgotIE1lam9yYSBsYSBwcmVjaXNpw7NuIGVuIGNvbXBhcmFjacOzbiBjb24gZWwgdXNvIGRlIGludGVydmFsb3MgZGUgcHJlZGljY2nDs24gYmFzYWRvcyBlbiByZWdyZXNpw7NuIGxpbmVhbCBlc3TDoW5kYXIuCgojIyMgPHNwYW4gc3R5bGU9ICJDb2xvcjogdmlvbGV0OyI+wr9QYXJhIHF1w6kgc2lydmUgbGEgUXVhbnRpbGUgUmVncmVzc2lvbj88L3NwYW4+Ci0gRXMgw7p0aWwgcGFyYSBhbmFsaXphciBkaXN0cmlidWNpb25lcyBhc2ltw6l0cmljYXMgeSBkZXRlY3RhciBlZmVjdG9zIGRpZmVyZW5jaWFkb3MgZW4gZGlzdGludG9zIG5pdmVsZXMuCgotIFByb3BvcmNpb25hIHVuYSBtZWpvciBjb21wcmVuc2nDs24gZGUgbGEgaGV0ZXJvZ2VuZWlkYWQgZW4gbG9zIGRhdG9zLgotIEVzIHJvYnVzdGEgYSB2YWxvcmVzIGF0w61waWNvcywgeWEgcXVlIG1pbmltaXphIHVuYSBmdW5jacOzbiBkZSBww6lyZGlkYSBhc2ltw6l0cmljYS4KLSBTZSB1c2EgZW4gYW7DoWxpc2lzIGVjb27Ds21pY28sIG1vZGVsb3MgZGUgcmllc2dvLCBiaW9lc3RhZMOtc3RpY2EgeSBvdHJhcyBhcGxpY2FjaW9uZXMgZG9uZGUgbGEgdmFyaWFiaWxpZGFkIGVzIGNsYXZlLgotIFBlcm1pdGUgbW9kZWxhciByZWxhY2lvbmVzIG5vIGNhcHR1cmFkYXMgcG9yIGxhIHJlZ3Jlc2nDs24gbGluZWFsIG9yZGluYXJpYS4KIC0gRXMgYXBsaWNhYmxlIGN1YW5kbyBsYSByZWxhY2nDs24gZW50cmUgbGFzIHZhcmlhYmxlcyBjYW1iaWEgZW4gZGlzdGludG9zIHB1bnRvcyBkZSBsYSBkaXN0cmlidWNpw7NuLgoKIyMjIDxzcGFuIHN0eWxlPSAiQ29sb3I6dmlvbGV0OyI+RGlmZXJlbmNpYXMgY2xhdmUgZW50cmUgT0xTIHkgUXVhbnRpbGUgUmVncmVzc2lvbjwvc3Bhbj4KLSAqKk9MUyAoUmVncmVzacOzbiBMaW5lYWwgT3JkaW5hcmlhKToqKiBNaW5pbWl6YSBlbCBlcnJvciBjdWFkcsOhdGljbyBtZWRpbyAoTVNFKSB5IG1vZGVsYSBsYSBtZWRpYSBjb25kaWNpb25hbC4KCi0gKipRdWFudGlsZSBSZWdyZXNzaW9uOioqIE1pbmltaXphIHVuYSBmdW5jacOzbiBkZSBww6lyZGlkYSBwb25kZXJhZGEsIGxvIHF1ZSBwZXJtaXRlIGVzdGltYXIgZGlzdGludG9zIGN1YW50aWxlcy4KCi0gKipSb2J1c3RlejoqKiBRdWFudGlsZSBSZWdyZXNzaW9uIGVzIG1lbm9zIHNlbnNpYmxlIGEgdmFsb3JlcyBhdMOtcGljb3MgcXVlIE9MUy4KLSAqKkZsZXhpYmlsaWRhZDoqKiBNaWVudHJhcyBPTFMgYXN1bWUgaG9tb2NlZGFzdGljaWRhZCAodmFyaWFuemEgY29uc3RhbnRlIGRlbCBlcnJvciksIFF1YW50aWxlIFJlZ3Jlc3Npb24gcGVybWl0ZSBoZXRlcm9jZWRhc3RpY2lkYWQuCgojIyMgPHNwYW4gc3R5bGU9ICJDb2xvcjogdmlvbGV0OyI+RWplbXBsb3MgZGUgQXBsaWNhY2nDs248L3NwYW4+Ci0gKipFY29ub23DrWE6KiogRXZhbHVhY2nDs24gZGUgZGVzaWd1YWxkYWQgZW4gaW5ncmVzb3MsIGRldGVybWluYW5kbyBjw7NtbyBmYWN0b3JlcyBhZmVjdGFuIGRpZmVyZW50ZXMgbml2ZWxlcyBzYWxhcmlhbGVzLgotICoqRmluYW56YXM6KiogTW9kZWxhZG8gZGUgcmllc2dvcyBlbiBtZXJjYWRvcyBmaW5hbmNpZXJvcy4KLSAqKk1lZGljaW5hOioqIEFuw6FsaXNpcyBkZSBwZXJjZW50aWxlcyBlbiBtZWRpZGFzIGJpb23DqWRpY2FzIGNvbW8gcHJlc2nDs24gYXJ0ZXJpYWwgbyBwZXNvIGluZmFudGlsLgotICoqQ2llbmNpYXMgc29jaWFsZXM6KiogRXZhbHVhY2nDs24gZGUgaW1wYWN0byBkZSBwb2zDrXRpY2FzIGVuIGRpc3RpbnRvcyBncnVwb3MgcG9ibGFjaW9uYWxlcy4KCiMgPHNwYW4gc3R5bGU9ICJDb2xvcjogcHVycGxlOyI+Q2FyZ2FyIGxhcyBsw61icmVyaWFzIG5lY2VzYXJpYXM8L3NwYW4+CmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNpbnN0YWxsLnBhY2thZ2VzKCJxdWFudHJlZyIpCmxpYnJhcnkocXVhbnRyZWcpCiNpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QiKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyA8c3BhbiBzdHlsZT0gIkNvbG9yOiBwdXJwbGU7Ij5EZXNjcmlwY2nDs24gZGVsIEFuw6FsaXNpcyA8L3NwYW4+CgpFbiBlc3RlIGVqZW1wbG8sIHVzYXJlbW9zIFF1YW50aWxlIFJlZ3Jlc3Npb24gcGFyYSBhbmFsaXphciBlbCBpbXBhY3RvIGRlbCBwZXNvIGRlbCBhdXRvICh3dCllbiBlbCBjb25zdW1vIGRlIGNvbWJ1c3RpYmxlIChtcGcpIHVzYW5kbyBlbCBkYXRhc2V0IG10Y2Fycy4KCgojIyA8c3BhbiBzdHlsZT0gIkNvbG9yOiB2aW9sZXQ7Ij5DYXJnYXIgZGF0b3MgKG10Y2FycykgPC9zcGFuPgpgYGB7cn0KI0VzdGEgYmFzZSBkZSBkYXRvcyB2aWVuZSB5YSBkZW50cm8gZGUgUgpkYXRhKG10Y2FycykKYGBgCgojIyA8c3BhbiBzdHlsZT0gIkNvbG9yOiB2aW9sZXQ7Ij5SZXZpc2FyIGxhcyBwcmltZXJhcyBmaWxhcyBkZWwgZGF0YXNldDwvc3Bhbj4KCmBgYHtyfQpoZWFkKG10Y2FycykgCmBgYAoKCiMjIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHZpb2xldDsiPkRlZmluaXIgVmFyaWFibGVzPC9zcGFuPgpgYGB7cn0KZGYgPC0gbXRjYXJzCmRmJFggPC0gZGYkd3QgICMgUGVzbyBkZWwgYXV0bwpkZiR5IDwtIGRmJG1wZyAgIyBNaWxsYXMgcG9yIGdhbMOzbgpgYGAKCiMjIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHZpb2xldDsiPkFqdXN0YXIgdW4gbW9kZWxvIGRlIFF1YW50aWxlIFJlZ3Jlc3Npb24gcGFyYSBkaWZlcmVudGVzIGN1YW50aWxlczwvc3Bhbj4KYGBge3J9CnF1YW50aWxlcyA8LSBjKDAuMSwgMC41LCAwLjkpICAjIFBlcmNlbnRpbGVzIDEwLCA1MCB5IDkwCm1vZGVscyA8LSBsYXBwbHkocXVhbnRpbGVzLCBmdW5jdGlvbihxKSBycSh5IH4gWCwgdGF1ID0gcSwgZGF0YSA9IGRmKSkgCiMgcSByZXByZXNlbnRhIGNhZGEgdW5vIGRlIGxvcyBwZXJjZXRpbGVzIAojdGF1IGNvbnRyb2xhIHF1w6kgcGFydGUgZGUgbGEgZGlzdHJpYnVjacOzbiBjb25kaWNpb25hbCBlc3RhbW9zIG1vZGVsYW5kby4KYGBgCgpgYGB7cn0Kc3VtbWFyeShxdWFudGlsZXMpCmBgYAoKCiMjIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHZpb2xldDsiPiBBanVzdGFyIHVuIG1vZGVsbyBkZSBSZWdyZXNpw7NuIExpbmVhbCBlc3TDoW5kYXIgcGFyYSBjb21wYXJhY2nDs248L3NwYW4+CgpgYGB7cn0KbG1fbW9kZWwgPC0gbG0oeSB+IFgsIGRhdGEgPSBkZikKYGBgCgojIyA8c3BhbiBzdHlsZT0gIkNvbG9yOiB2aW9sZXQ7Ij4gQ3JlYXIgdW4gZGF0YWZyYW1lIHBhcmEgYWxtYWNlbmFyIHByZWRpY2Npb25lczwvc3Bhbj4KCmBgYHtyfQojIENyZWFtb3MgdW4gZGF0YSBmcmFtZSBjb24gdW5hIHNlY3VlbmNpYSBkZSB2YWxvcmVzIGRlIFggcXVlIHZhbiBkZXNkZSBlbCBtw61uaW1vIGhhc3RhIGVsIG3DoXhpbW8gZW4gZGYkWApYX3NlcSA8LSBkYXRhLmZyYW1lKFggPSBzZXEobWluKGRmJFgpLCBtYXgoZGYkWCksIGxlbmd0aC5vdXQgPSAxMDApKQojIENyZWFyIHVuIG51ZXZvIGRhdGEgZnJhbWUgcGFyYSBhbG1hY2VuYXIgbGFzIHByZWRpY2Npb25lcyBkZWwgbW9kZWxvIGRlIHJlZ3Jlc2nDs24KcHJlZF9kZiA8LSBkYXRhLmZyYW1lKAogIFggPSBYX3NlcSRYLAogIE9MUyA9IHByZWRpY3QobG1fbW9kZWwsIG5ld2RhdGEgPSBYX3NlcSkKKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHZpb2xldDsiPiBBZ3JlZ2FyIHByZWRpY2Npb25lcyBkZSByZWdyZXNpw7NuIGN1YW50w61saWNhPC9zcGFuPgoKYGBge3J9CiNsb29wIHF1ZSByZWNvcnJlIHRvZG9zIGxvcyBjdWFudGlsZXMgZGVmaW5pZG9zIGVuIGxhIHZhcmlhYmxlICdxdWFudGlsZXMnCmZvciAoaSBpbiAxOmxlbmd0aChxdWFudGlsZXMpKSB7CiAgcHJlZF9kZltbcGFzdGUwKCJRIiwgcXVhbnRpbGVzW2ldICogMTAwKV1dIDwtIHByZWRpY3QobW9kZWxzW1tpXV0sIG5ld2RhdGEgPSBYX3NlcSkKfQpgYGAKCiMjIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHZpb2xldDsiPiBHcmFmaWNhciByZXN1bHRhZG9zPC9zcGFuPgpgYGB7cn0KcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IFgsIHkgPSB5KSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsgICMgUHVudG9zIGRlIGRhdG9zIHJlYWxlcwogIGdlb21fbGluZShkYXRhID0gcHJlZF9kZiwgYWVzKHggPSBYLCB5ID0gT0xTLCBjb2xvciA9ICJPTFMiKSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fbGluZShkYXRhID0gcHJlZF9kZiwgYWVzKHggPSBYLCB5ID0gUTEwLCBjb2xvciA9ICJRdWFudGlsZSAxMCIpKSArCiAgZ2VvbV9saW5lKGRhdGEgPSBwcmVkX2RmLCBhZXMoeCA9IFgsIHkgPSBRNTAsIGNvbG9yID0gIlF1YW50aWxlIDUwIikpICsKICBnZW9tX2xpbmUoZGF0YSA9IHByZWRfZGYsIGFlcyh4ID0gWCwgeSA9IFE5MCwgY29sb3IgPSAiUXVhbnRpbGUgOTAiKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJibHVlIiwgInJlZCIsICJncmVlbiIpKSArCiAgbGFicyh0aXRsZSA9ICJDb21wYXJhY2nDs24gZGUgUmVncmVzacOzbiBDdWFudMOtbGljYSB5IExpbmVhbCIsCiAgICAgICB4ID0gIlBlc28gZGVsIEF1dG8gKHd0KSIsCiAgICAgICB5ID0gIk1pbGxhcyBwb3IgR2Fsw7NuIChtcGcpIiwKICAgICAgIGNvbG9yID0gIk1vZGVsbyIpICsKICB0aGVtZV9taW5pbWFsKCkKcHJpbnQocGxvdCkKYGBgCgojIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHB1cnBsZTsiPkV4cGxpY2FjacOzbjwvc3Bhbj4KLSBMYSBsw61uZWEgbmVncmEgZGlzY29udGludWEgcmVwcmVzZW50YSBsYSByZWdyZXNpw7NuIGxpbmVhbCBlc3TDoW5kYXIgKE9MUykuCi0gTGFzIGzDrW5lYXMgYXp1bCwgcm9qYSB5IHZlcmRlIHJlcHJlc2VudGFuIGxhcyByZWdyZXNpb25lcyBjdWFudMOtbGljYXMgcGFyYSBsb3MgcGVyY2VudGlsZXMgMTAsIDUwIHkgOTAuCiAqTMOtbmVhIGF6dWwgKFF1YW50aWxlIDEwKTogTXVlc3RyYSBjw7NtbyBsb3MgYXV0b3MgY29uIG1lbm9yIGNvbnN1bW8gZGUgZ2Fzb2xpbmEgKHBlcmNlbnRpbCAxMCkgZXN0w6FuIGFmZWN0YWRvcyBwb3IgZWwgcGVzby4KIAogICpMw61uZWEgcm9qYSAoUXVhbnRpbGUgNTAgLSBNZWRpYW5hKTogUmVwcmVzZW50YSBsYSByZWxhY2nDs24gbWVkaWFuYSBlbnRyZSB3dCB5IG1wZywgZXF1aXZhbGVudGUgYSBsYSByZWdyZXNpw7NuIGN1YW50w61saWNhIGVuIGVsIHBlcmNlbnRpbCA1MC4KICAKICAqTMOtbmVhIHZlcmRlIChRdWFudGlsZSA5MCk6IE1vZGVsYSBsYSByZWxhY2nDs24gcGFyYSBsb3MgYXV0b3MgY29uIG1lam9yIGNvbnN1bW8gZGUgZ2Fzb2xpbmEgKHBlcmNlbnRpbCA5MCkuCgotT0xTIHN1YmVzdGltYSBvIHNvYnJlZXN0aW1hIGVuIGNpZXJ0YXMgcmVnaW9uZXMsIHlhIHF1ZSBzb2xvIG1vZGVsYSBsYSBtZWRpYSBkZSBtcGcsIG1pZW50cmFzIHF1ZSBRdWFudGlsZSBSZWdyZXNzaW9uIHBlcm1pdGUgZW50ZW5kZXIgY8OzbW8gY2FtYmlhIG1wZyBlbiBkaWZlcmVudGVzIG5pdmVsZXMuCgojIDxzcGFuIHN0eWxlPSAiQ29sb3I6IHB1cnBsZTsiPlJlZmVyZW5jaWFzPC9zcGFuPgotIE5naWVuZyBLaWFueWV3LCAqVW5kZXJzdGFuZGluZyBIb3cgUXVhbnRpbGUgUmVncmVzc2lvbiBXb3JrcyosIE1lZGl1bSAoMjAyMyku