Parte I
A continuacion haremos un ejemplo sobre un dataset de pruebas para generar una regresion lineal o no lineal para poder encontrar un modelo que nos permita predecir una variable objetivo.
Para ello utilizaremos el siguiente DataSet:
admis1 <- read_csv("~/maestria/2019/trimestre 2/Fiabilidad/Hoja de Trabajo 1/admis1.csv")
Parsed with column specification:
cols(
`Serial No.` = [32mcol_double()[39m,
`GRE Score` = [32mcol_double()[39m,
`TOEFL Score` = [32mcol_double()[39m,
`University Rating` = [32mcol_double()[39m,
SOP = [32mcol_double()[39m,
LOR = [32mcol_double()[39m,
CGPA = [32mcol_double()[39m,
Research = [32mcol_double()[39m,
`Chance of Admit` = [32mcol_double()[39m
)
admis1
Analizemos un poco la estructura del dataset
glimpse(admis1)
Observations: 500
Variables: 9
$ `Serial No.` [3m[38;5;246m<dbl>[39m[23m 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1…
$ `GRE Score` [3m[38;5;246m<dbl>[39m[23m 337, 324, 316, 322, 314, 330, 321, 308, 302, 323, 325, 327, 328,…
$ `TOEFL Score` [3m[38;5;246m<dbl>[39m[23m 118, 107, 104, 110, 103, 115, 109, 101, 102, 108, 106, 111, 112,…
$ `University Rating` [3m[38;5;246m<dbl>[39m[23m 4, 4, 3, 3, 2, 5, 3, 2, 1, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4…
$ SOP [3m[38;5;246m<dbl>[39m[23m 4.5, 4.0, 3.0, 3.5, 2.0, 4.5, 3.0, 3.0, 2.0, 3.5, 3.5, 4.0, 4.0,…
$ LOR [3m[38;5;246m<dbl>[39m[23m 4.5, 4.5, 3.5, 2.5, 3.0, 3.0, 4.0, 4.0, 1.5, 3.0, 4.0, 4.5, 4.5,…
$ CGPA [3m[38;5;246m<dbl>[39m[23m 9.65, 8.87, 8.00, 8.67, 8.21, 9.34, 8.20, 7.90, 8.00, 8.60, 8.40…
$ Research [3m[38;5;246m<dbl>[39m[23m 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0…
$ `Chance of Admit` [3m[38;5;246m<dbl>[39m[23m 0.92, 0.76, 0.72, 0.80, 0.65, 0.90, 0.75, 0.68, 0.50, 0.45, 0.52…
Como vemos este dataset nos cuenta estadisticas de de examenes de prerequsitos para entrar a una universidad y las probabilidades de ser admitidos en la universidad, la descripcion de las variables es la siguiente:
| Serial No |
Indica el numero de observacion con el que estamos trabajando. |
| GRE Score |
Corresponde al Graduate Record Examination y consiste en una prueba estandard de administion para todos los graduandos en Estados Unidos. |
| TOEFL Score |
Corresponde a Test of English as a Foreign Language y mide el dominio del Ingles para una persona que lo maneja como segundo idioma y desea acceder a una Universidad en Estados Unidos. |
| University Rating |
Corresponde al ranting de la universidad a la que se desea acceder y este va de 1 a 5. |
| LOR |
Corresponde a Letter of Recommendation se refiere a una carta de recomendacion dada al estudiante por algun mentor o guia. |
| SOP |
Corresponde a Statement of Purpose y es un ensayo largo que las universidades solicitan a todos sus aplicantes. |
| CGPA |
Corresponde a Cumulative Grade Points Average y se se refiere al promedio de notas obtenido por un estudiante de nivel medio. |
| Research |
Indica si el estudiante ha sido investigado o no, se denota con un 1 para si y 0 para no. |
| Chance of Admit |
Se refiere a un valor porcentual dado al estudiante basado en las variables anteriormente definidas. La cual sera el objeto de nuestro estudio. |
Antes de comenzar a trabajar partiremos nuestro dataset en dos, uno conteniendo el 70% de los datos y el otro el 30% de los datos. El primero nos servira para entrar el modelo, mientras que el segundo nos servira para probar nuestro modelo propuesto.
i_train <- sample(1:nrow(admis1),size = nrow(admis1)*0.7 )
train_data <- admis1[i_train,]
length(train_data$`Chance of Admit`)
[1] 350
length(train_data$`Chance of Admit`)/length(admis1$`Chance of Admit`)
[1] 0.7
Ahora calculamos la data de prueba:
i_test <- sample(1:nrow(admis1),size = nrow(admis1)*0.3 )
test_data <- admis1[i_test,]
length(test_data$`Chance of Admit`)
[1] 150
length(test_data$`Chance of Admit`)/length(admis1$`Chance of Admit`)
[1] 0.3
Realicemos una grafica de cada una de las variables que nos van a interesar:
Primero veamos GRE Score vs Chance of Admit
plot(train_data %>% select(`GRE Score`, `Chance of Admit`))

Ahora vamos TOEFL Score vs Chance of Admit
plot(train_data %>% select(`TOEFL Score`, `Chance of Admit`))

SOP vs Chance of Admit
plot(train_data %>% select(SOP, `Chance of Admit`))

LOR vs Chance of Admit
plot(train_data %>% select(LOR, `Chance of Admit`))

CGPA vs Chance of Admit
plot(train_data %>% select(CGPA, `Chance of Admit`))

Rating vs Chance of Admit
plot(train_data %>% select(`University Rating`, `Chance of Admit`))

Como podemos apreciar las variables SOP, LORy University Rating parece tener un caracter discreto, mientras que las variables GRE, TOEFL y CGPA parecen ser de caracter continuo.
Ahora vamos a proceder a construir modelos Lineales simples, donde unicamente utilicemos una variable independiente y la variable de Chance of Admit.
Primero Comensamos con GRE Score y Chance of Admit donde planteramos la ecuacion simple de y=mx+b para este caso y = Chance of Admit y x = GRE Score:
fit1 <- lm(data = train_data, `Chance of Admit`~`GRE Score`)
ggplot(fit1$model, aes(x = `GRE Score`, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(method = "lm", col = "red")

Ahora veamos con TOEFL Score y Chance of Admit donde planteramos la ecuacion simple de y=mx+b para este caso y = Chance of Admit y x = TOEFL Score:
fit_toefl <- lm(data = train_data, `Chance of Admit`~`TOEFL Score`)
ggplot(fit_toefl$model, aes(x = `TOEFL Score`, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(method = "lm", col = "red")

Ahora veamos con SOP y Chance of Admit donde planteramos la ecuacion simple de y=mx+b para este caso y = Chance of Admit y x = SOP:
fit_sop <- lm(data = train_data, `Chance of Admit`~`SOP`)
ggplot(fit_sop$model, aes(x = `SOP`, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(method = "lm", col = "red")

Ahora veamos con LOR y Chance of Admit donde planteramos la ecuacion simple de y=mx+b para este caso y = Chance of Admit y x = LOR:
fit_lor <- lm(data = train_data, `Chance of Admit`~`LOR`)
ggplot(fit_lor$model, aes(x = `LOR`, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(method = "lm", col = "red")

Ahora veamos con CGPA y Chance of Admit donde planteramos la ecuacion simple de y=mx+b para este caso y = Chance of Admit y x = CGPA:
fit_cgpa <- lm(data = train_data, `Chance of Admit`~`CGPA`)
ggplot(fit_cgpa$model, aes(x = `CGPA`, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(method = "lm", col = "red")

Ahora veamos con Rating y Chance of Admit donde planteramos la ecuacion simple de y=mx+b para este caso y = Chance of Admit y x = Rating:
fit_rating <- lm(data = train_data, `Chance of Admit`~`University Rating`)
ggplot(fit_rating$model, aes(x = `University Rating`, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(method = "lm", col = "red")

Parte II
Ahora procederemos a crear un modelo con todas las variables y veremos la significancia de cada una, comenzaremos con uno lineal utilizando todas las variables:
fit_lineal <- lm(data = train_data, `Chance of Admit`~`GRE Score`+`TOEFL Score`+`University Rating`+SOP+LOR+CGPA)
summary(fit_lineal)
Call:
lm(formula = `Chance of Admit` ~ `GRE Score` + `TOEFL Score` +
`University Rating` + SOP + LOR + CGPA, data = train_data)
Residuals:
Min 1Q Median 3Q Max
-0.284200 -0.022486 0.005245 0.030623 0.158929
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -1.4324778 0.1070904 -13.376 < 2e-16 ***
`GRE Score` 0.0025907 0.0005286 4.901 1.47e-06 ***
`TOEFL Score` 0.0023747 0.0009871 2.406 0.0167 *
`University Rating` 0.0051420 0.0041676 1.234 0.2181
SOP 0.0013548 0.0051324 0.264 0.7920
LOR 0.0227016 0.0046106 4.924 1.32e-06 ***
CGPA 0.1145512 0.0103479 11.070 < 2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.05708 on 343 degrees of freedom
Multiple R-squared: 0.8436, Adjusted R-squared: 0.8408
F-statistic: 308.3 on 6 and 343 DF, p-value: < 2.2e-16
Como podemos ver podemos realizar el siguiente analisis
| GRE Score |
Estimado 0.002 y 4.34 para T value |
Vemos que el valor de estimacion es pequeno, por lo que esta variable en este modelo contribuye muy poco |
| TOEFL Score |
Estimado 0.002 y 2.68 |
Como vemos el estimado es igualmente pequeno que el GRE Score |
| Rating |
0.003 y 0.611 |
El estimado es ligeramente mayor y su t value es cercano a 0 por lo que la hipotesis nula se puede descartar pero no por mucho |
| SOP |
0.001 Y 0.28 |
Su estimado es bajo y su t value tambien, aporta poco al modelo |
| LOR |
0.018 Y 3.49 |
Aporta mas al modelo que las variables anteriores |
| CGPA |
0.12 y 9.88 |
Su estimado es el mas alto, al igual que su T value, es por ello que esta variable parece ser la mas significativa para el modelo |
Como vemos las variables mas significativos del modelo son el promedio y la carta de recomendacion, por lo que podriamos enfocarnos unicamnete en estas dos variables para realizar un modelo, sin embargo el GRE y TOEFL tienen un valor alto en T Value por lo que podriamos considerar manteneralas. Por lo que unicamnete sacaremos del model el Rating y el SOP.
Por lo tanto definimos nuestro modelo lineal como CA = GRE + TOEFL + LOR +CGPA, luego procederemos a calcular la prediccion con la data de entrenamiento y la data de prueba, calcularemos los minimos cuadrados y vemos veremos como quedan lso coeficientes para la data de prueba y la de entrenamiento:
ggplot(train_data, aes(x = `GRE Score`+`TOEFL Score`+LOR+CGPA, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(model=fit_1, col = "red")
Ignoring unknown parameters: model

Con esto vemos la diferencia de cuaentre el valor de la preccion para la data de entrenamiento y la data prueba, la diferencia es relativamente grande. Veamos que sucede si convertimos esto en un modelo cuadratico:
ggplot(train_data, aes(x = `GRE Score`+`TOEFL Score`+LOR+CGPA, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(model=fit_2, col = "red")
Ignoring unknown parameters: model

Vemos que no ha variado mucho, aumentemolo a un modelo cubico:
ggplot(train_data, aes(x = `GRE Score`+`TOEFL Score`+LOR+CGPA, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(model=fit_3, col = "red")
Ignoring unknown parameters: model

Finalmente probraremos con una ecuacion elevada a la 4ta:
ggplot(train_data, aes(x = `GRE Score`+`TOEFL Score`+LOR+CGPA, y = `Chance of Admit`)) +
geom_point() +
stat_smooth(model=fit_4, col = "red")
Ignoring unknown parameters: model

Ahora procederemos a anlizar las 4 regresiones y sus predicciones:
plot(1:4,
c(MSE1_train,MSE2_train,MSE3_train,MSE4_train),
ylim=c(0,2),
type='l')
points(1:4,
c(MSE1_test,MSE2_test,MSE3_test,MSE4_test),
col='red',
type='l')

LS0tCnRpdGxlOiAiRmlhYmlsaWRhZCBIb2phIGRlIFRyYWJham8gMSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KbGlicmFyeShyZWFkcikKbGlicmFyeShnZ3Bsb3QyKQpgYGAKCiMjIyBQYXJ0ZSBJCgpBIGNvbnRpbnVhY2lvbiBoYXJlbW9zIHVuIGVqZW1wbG8gc29icmUgdW4gZGF0YXNldCBkZSBwcnVlYmFzIHBhcmEgZ2VuZXJhciB1bmEgcmVncmVzaW9uIGxpbmVhbCBvIG5vIGxpbmVhbCBwYXJhIHBvZGVyIGVuY29udHJhciB1biBtb2RlbG8gcXVlIG5vcyBwZXJtaXRhIHByZWRlY2lyIHVuYSB2YXJpYWJsZSBvYmpldGl2by4KClBhcmEgZWxsbyB1dGlsaXphcmVtb3MgZWwgc2lndWllbnRlIERhdGFTZXQ6CgpgYGB7cn0KYWRtaXMxIDwtIHJlYWRfY3N2KCJ+L21hZXN0cmlhLzIwMTkvdHJpbWVzdHJlIDIvRmlhYmlsaWRhZC9Ib2phIGRlIFRyYWJham8gMS9hZG1pczEuY3N2IikKYWRtaXMxCmBgYApBbmFsaXplbW9zIHVuIHBvY28gbGEgZXN0cnVjdHVyYSBkZWwgZGF0YXNldApgYGB7cn0KZ2xpbXBzZShhZG1pczEpCmBgYAoKQ29tbyB2ZW1vcyBlc3RlIGRhdGFzZXQgbm9zIGN1ZW50YSBlc3RhZGlzdGljYXMgZGUgZGUgZXhhbWVuZXMgZGUgcHJlcmVxdXNpdG9zIHBhcmEgZW50cmFyIGEgdW5hIHVuaXZlcnNpZGFkIHkgbGFzIHByb2JhYmlsaWRhZGVzIGRlIHNlciBhZG1pdGlkb3MgZW4gbGEgdW5pdmVyc2lkYWQsIGxhIGRlc2NyaXBjaW9uIGRlIGxhcyB2YXJpYWJsZXMgZXMgbGEgc2lndWllbnRlOgoKfENvbHVtbmF8RGVzY3JpcGNpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfFNlcmlhbCBOb3wgSW5kaWNhIGVsIG51bWVybyBkZSBvYnNlcnZhY2lvbiBjb24gZWwgcXVlIGVzdGFtb3MgdHJhYmFqYW5kby58CnxHUkUgU2NvcmV8IENvcnJlc3BvbmRlIGFsIGBHcmFkdWF0ZSBSZWNvcmQgRXhhbWluYXRpb25gIHkgY29uc2lzdGUgZW4gdW5hIHBydWViYSBlc3RhbmRhcmQgZGUgYWRtaW5pc3Rpb24gcGFyYSB0b2RvcyBsb3MgZ3JhZHVhbmRvcyBlbiBFc3RhZG9zIFVuaWRvcy58CnxUT0VGTCBTY29yZXwgQ29ycmVzcG9uZGUgYSBgVGVzdCBvZiBFbmdsaXNoIGFzIGEgRm9yZWlnbiBMYW5ndWFnZWAgeSBtaWRlIGVsIGRvbWluaW8gZGVsIEluZ2xlcyBwYXJhIHVuYSBwZXJzb25hIHF1ZSBsbyBtYW5lamEgY29tbyBzZWd1bmRvIGlkaW9tYSB5IGRlc2VhIGFjY2VkZXIgYSB1bmEgVW5pdmVyc2lkYWQgZW4gRXN0YWRvcyBVbmlkb3MufAp8VW5pdmVyc2l0eSBSYXRpbmd8IENvcnJlc3BvbmRlIGFsIHJhbnRpbmcgZGUgbGEgdW5pdmVyc2lkYWQgYSBsYSBxdWUgc2UgZGVzZWEgYWNjZWRlciB5IGVzdGUgdmEgZGUgMSBhIDUufAp8TE9SfCBDb3JyZXNwb25kZSBhIGBMZXR0ZXIgb2YgUmVjb21tZW5kYXRpb25gIHNlIHJlZmllcmUgYSB1bmEgY2FydGEgZGUgcmVjb21lbmRhY2lvbiBkYWRhIGFsIGVzdHVkaWFudGUgcG9yIGFsZ3VuIG1lbnRvciBvIGd1aWEufAp8U09QfCBDb3JyZXNwb25kZSBhIGBTdGF0ZW1lbnQgb2YgUHVycG9zZWAgeSBlcyB1biBlbnNheW8gbGFyZ28gcXVlIGxhcyB1bml2ZXJzaWRhZGVzIHNvbGljaXRhbiBhIHRvZG9zIHN1cyBhcGxpY2FudGVzLnwKfENHUEF8IENvcnJlc3BvbmRlIGEgYEN1bXVsYXRpdmUgR3JhZGUgUG9pbnRzIEF2ZXJhZ2VgIHkgc2Ugc2UgcmVmaWVyZSBhbCBwcm9tZWRpbyBkZSBub3RhcyBvYnRlbmlkbyBwb3IgdW4gZXN0dWRpYW50ZSBkZSBuaXZlbCBtZWRpby58CnxSZXNlYXJjaHwgSW5kaWNhIHNpIGVsIGVzdHVkaWFudGUgaGEgc2lkbyBpbnZlc3RpZ2FkbyBvIG5vLCBzZSBkZW5vdGEgY29uIHVuIDEgcGFyYSBzaSB5IDAgcGFyYSBuby58CnxDaGFuY2Ugb2YgQWRtaXR8IFNlIHJlZmllcmUgYSB1biB2YWxvciBwb3JjZW50dWFsIGRhZG8gYWwgZXN0dWRpYW50ZSBiYXNhZG8gZW4gbGFzIHZhcmlhYmxlcyBhbnRlcmlvcm1lbnRlIGRlZmluaWRhcy4gTGEgY3VhbCBzZXJhIGVsIG9iamV0byBkZSBudWVzdHJvIGVzdHVkaW8ufAoKQW50ZXMgZGUgY29tZW56YXIgYSB0cmFiYWphciBwYXJ0aXJlbW9zIG51ZXN0cm8gZGF0YXNldCBlbiBkb3MsIHVubyBjb250ZW5pZW5kbyBlbCA3MCUgZGUgbG9zIGRhdG9zIHkgZWwgb3RybyBlbCAzMCUgZGUgbG9zIGRhdG9zLiBFbCBwcmltZXJvIG5vcyBzZXJ2aXJhIHBhcmEgZW50cmFyIGVsIG1vZGVsbywgbWllbnRyYXMgcXVlIGVsIHNlZ3VuZG8gbm9zIHNlcnZpcmEgcGFyYSBwcm9iYXIgbnVlc3RybyBtb2RlbG8gcHJvcHVlc3RvLgoKYGBge3J9CmlfdHJhaW4gPC0gc2FtcGxlKDE6bnJvdyhhZG1pczEpLHNpemUgPSBucm93KGFkbWlzMSkqMC43ICkKdHJhaW5fZGF0YSA8LSBhZG1pczFbaV90cmFpbixdCmxlbmd0aCh0cmFpbl9kYXRhJGBDaGFuY2Ugb2YgQWRtaXRgKQpsZW5ndGgodHJhaW5fZGF0YSRgQ2hhbmNlIG9mIEFkbWl0YCkvbGVuZ3RoKGFkbWlzMSRgQ2hhbmNlIG9mIEFkbWl0YCkKYGBgCkFob3JhIGNhbGN1bGFtb3MgbGEgZGF0YSBkZSBwcnVlYmE6CgpgYGB7cn0KaV90ZXN0IDwtIHNhbXBsZSgxOm5yb3coYWRtaXMxKSxzaXplID0gbnJvdyhhZG1pczEpKjAuMyApCnRlc3RfZGF0YSA8LSBhZG1pczFbaV90ZXN0LF0KbGVuZ3RoKHRlc3RfZGF0YSRgQ2hhbmNlIG9mIEFkbWl0YCkKbGVuZ3RoKHRlc3RfZGF0YSRgQ2hhbmNlIG9mIEFkbWl0YCkvbGVuZ3RoKGFkbWlzMSRgQ2hhbmNlIG9mIEFkbWl0YCkKCmBgYAoKClJlYWxpY2Vtb3MgdW5hIGdyYWZpY2EgZGUgY2FkYSB1bmEgZGUgbGFzIHZhcmlhYmxlcyBxdWUgbm9zIHZhbiBhIGludGVyZXNhcjoKClByaW1lcm8gdmVhbW9zIEdSRSBTY29yZSB2cyBDaGFuY2Ugb2YgQWRtaXQKYGBge3J9CnBsb3QodHJhaW5fZGF0YSAlPiUgc2VsZWN0KGBHUkUgU2NvcmVgLCBgQ2hhbmNlIG9mIEFkbWl0YCkpCmBgYApBaG9yYSB2YW1vcyBUT0VGTCBTY29yZSB2cyBDaGFuY2Ugb2YgQWRtaXQKCmBgYHtyfQpwbG90KHRyYWluX2RhdGEgJT4lIHNlbGVjdChgVE9FRkwgU2NvcmVgLCBgQ2hhbmNlIG9mIEFkbWl0YCkpCmBgYApTT1AgdnMgQ2hhbmNlIG9mIEFkbWl0CgpgYGB7cn0KcGxvdCh0cmFpbl9kYXRhICU+JSBzZWxlY3QoU09QLCBgQ2hhbmNlIG9mIEFkbWl0YCkpCmBgYApMT1IgdnMgQ2hhbmNlIG9mIEFkbWl0CgpgYGB7cn0KcGxvdCh0cmFpbl9kYXRhICU+JSBzZWxlY3QoTE9SLCBgQ2hhbmNlIG9mIEFkbWl0YCkpCmBgYAoKQ0dQQSB2cyBDaGFuY2Ugb2YgQWRtaXQKYGBge3J9CnBsb3QodHJhaW5fZGF0YSAlPiUgc2VsZWN0KENHUEEsIGBDaGFuY2Ugb2YgQWRtaXRgKSkKYGBgClJhdGluZyB2cyBDaGFuY2Ugb2YgQWRtaXQKCmBgYHtyfQpwbG90KHRyYWluX2RhdGEgJT4lIHNlbGVjdChgVW5pdmVyc2l0eSBSYXRpbmdgLCBgQ2hhbmNlIG9mIEFkbWl0YCkpCmBgYAoKQ29tbyBwb2RlbW9zIGFwcmVjaWFyIGxhcyB2YXJpYWJsZXMgU09QLCBMT1J5IFVuaXZlcnNpdHkgUmF0aW5nIHBhcmVjZSB0ZW5lciB1biBjYXJhY3RlciBkaXNjcmV0bywgbWllbnRyYXMgcXVlIGxhcyB2YXJpYWJsZXMgR1JFLCBUT0VGTCB5IENHUEEgcGFyZWNlbiBzZXIgZGUgY2FyYWN0ZXIgY29udGludW8uCgpBaG9yYSB2YW1vcyBhIHByb2NlZGVyIGEgY29uc3RydWlyIG1vZGVsb3MgTGluZWFsZXMgc2ltcGxlcywgZG9uZGUgdW5pY2FtZW50ZSB1dGlsaWNlbW9zIHVuYSB2YXJpYWJsZSBpbmRlcGVuZGllbnRlIHkgbGEgdmFyaWFibGUgZGUgYENoYW5jZSBvZiBBZG1pdGAuCgpQcmltZXJvIENvbWVuc2Ftb3MgY29uIGBHUkUgU2NvcmVgIHkgYENoYW5jZSBvZiBBZG1pdGAgZG9uZGUgcGxhbnRlcmFtb3MgbGEgZWN1YWNpb24gc2ltcGxlIGRlIGB5PW14K2JgIHBhcmEgZXN0ZSBjYXNvIGB5ID0gQ2hhbmNlIG9mIEFkbWl0YCB5IGB4ID0gR1JFIFNjb3JlYDoKCmBgYHtyfQpmaXQxIDwtIGxtKGRhdGEgPSB0cmFpbl9kYXRhLCBgQ2hhbmNlIG9mIEFkbWl0YH5gR1JFIFNjb3JlYCkKCmdncGxvdChmaXQxJG1vZGVsLCBhZXMoeCA9IGBHUkUgU2NvcmVgLCB5ID0gYENoYW5jZSBvZiBBZG1pdGApKSArIAogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIpCmBgYApBaG9yYSB2ZWFtb3MgIGNvbiBgVE9FRkwgU2NvcmVgIHkgYENoYW5jZSBvZiBBZG1pdGAgZG9uZGUgcGxhbnRlcmFtb3MgbGEgZWN1YWNpb24gc2ltcGxlIGRlIGB5PW14K2JgIHBhcmEgZXN0ZSBjYXNvIGB5ID0gQ2hhbmNlIG9mIEFkbWl0YCB5IGB4ID0gVE9FRkwgU2NvcmVgOgoKYGBge3J9CmZpdF90b2VmbCA8LSBsbShkYXRhID0gdHJhaW5fZGF0YSwgYENoYW5jZSBvZiBBZG1pdGB+YFRPRUZMIFNjb3JlYCkKCmdncGxvdChmaXRfdG9lZmwkbW9kZWwsIGFlcyh4ID0gYFRPRUZMIFNjb3JlYCwgeSA9IGBDaGFuY2Ugb2YgQWRtaXRgKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJyZWQiKQoKYGBgCkFob3JhIHZlYW1vcyAgY29uIGBTT1BgIHkgYENoYW5jZSBvZiBBZG1pdGAgZG9uZGUgcGxhbnRlcmFtb3MgbGEgZWN1YWNpb24gc2ltcGxlIGRlIGB5PW14K2JgIHBhcmEgZXN0ZSBjYXNvIGB5ID0gQ2hhbmNlIG9mIEFkbWl0YCB5IGB4ID0gU09QYDoKCmBgYHtyfQpmaXRfc29wIDwtIGxtKGRhdGEgPSB0cmFpbl9kYXRhLCBgQ2hhbmNlIG9mIEFkbWl0YH5gU09QYCkKCmdncGxvdChmaXRfc29wJG1vZGVsLCBhZXMoeCA9IGBTT1BgLCB5ID0gYENoYW5jZSBvZiBBZG1pdGApKSArIAogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gInJlZCIpCgpgYGAKQWhvcmEgdmVhbW9zICBjb24gYExPUmAgeSBgQ2hhbmNlIG9mIEFkbWl0YCBkb25kZSBwbGFudGVyYW1vcyBsYSBlY3VhY2lvbiBzaW1wbGUgZGUgYHk9bXgrYmAgcGFyYSBlc3RlIGNhc28gYHkgPSBDaGFuY2Ugb2YgQWRtaXRgIHkgYHggPSBMT1JgOgoKYGBge3J9CmZpdF9sb3IgPC0gbG0oZGF0YSA9IHRyYWluX2RhdGEsIGBDaGFuY2Ugb2YgQWRtaXRgfmBMT1JgKQoKZ2dwbG90KGZpdF9sb3IkbW9kZWwsIGFlcyh4ID0gYExPUmAsIHkgPSBgQ2hhbmNlIG9mIEFkbWl0YCkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAicmVkIikKCmBgYApBaG9yYSB2ZWFtb3MgIGNvbiBgQ0dQQWAgeSBgQ2hhbmNlIG9mIEFkbWl0YCBkb25kZSBwbGFudGVyYW1vcyBsYSBlY3VhY2lvbiBzaW1wbGUgZGUgYHk9bXgrYmAgcGFyYSBlc3RlIGNhc28gYHkgPSBDaGFuY2Ugb2YgQWRtaXRgIHkgYHggPSBDR1BBYDoKCmBgYHtyfQpmaXRfY2dwYSA8LSBsbShkYXRhID0gdHJhaW5fZGF0YSwgYENoYW5jZSBvZiBBZG1pdGB+YENHUEFgKQoKZ2dwbG90KGZpdF9jZ3BhJG1vZGVsLCBhZXMoeCA9IGBDR1BBYCwgeSA9IGBDaGFuY2Ugb2YgQWRtaXRgKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbCA9ICJyZWQiKQoKYGBgCgpBaG9yYSB2ZWFtb3MgIGNvbiBgUmF0aW5nYCB5IGBDaGFuY2Ugb2YgQWRtaXRgIGRvbmRlIHBsYW50ZXJhbW9zIGxhIGVjdWFjaW9uIHNpbXBsZSBkZSBgeT1teCtiYCBwYXJhIGVzdGUgY2FzbyBgeSA9IENoYW5jZSBvZiBBZG1pdGAgeSBgeCA9IFJhdGluZ2A6CgpgYGB7cn0KZml0X3JhdGluZyA8LSBsbShkYXRhID0gdHJhaW5fZGF0YSwgYENoYW5jZSBvZiBBZG1pdGB+YFVuaXZlcnNpdHkgUmF0aW5nYCkKCmdncGxvdChmaXRfcmF0aW5nJG1vZGVsLCBhZXMoeCA9IGBVbml2ZXJzaXR5IFJhdGluZ2AsIHkgPSBgQ2hhbmNlIG9mIEFkbWl0YCkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAicmVkIikKCmBgYAoKIyMjIFBhcnRlIElJCgpBaG9yYSBwcm9jZWRlcmVtb3MgYSBjcmVhciB1biBtb2RlbG8gY29uIHRvZGFzIGxhcyB2YXJpYWJsZXMgeSB2ZXJlbW9zIGxhIHNpZ25pZmljYW5jaWEgZGUgY2FkYSB1bmEsIGNvbWVuemFyZW1vcyBjb24gdW5vIGxpbmVhbCB1dGlsaXphbmRvIHRvZGFzIGxhcyB2YXJpYWJsZXM6CgpgYGB7cn0KZml0X2xpbmVhbCA8LSBsbShkYXRhID0gdHJhaW5fZGF0YSwgYENoYW5jZSBvZiBBZG1pdGB+YEdSRSBTY29yZWArYFRPRUZMIFNjb3JlYCtgVW5pdmVyc2l0eSBSYXRpbmdgK1NPUCtMT1IrQ0dQQSkKCnN1bW1hcnkoZml0X2xpbmVhbCkKYGBgCkNvbW8gcG9kZW1vcyB2ZXIgcG9kZW1vcyByZWFsaXphciBlbCBzaWd1aWVudGUgYW5hbGlzaXMKCnwgVmFyaWFibGUgfCBDb2VmaWNpZW50ZXMgfCBBbmFsaXNpcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSB8CnxHUkUgU2NvcmV8IEVzdGltYWRvIDAuMDAyIHkgNC4zNCBwYXJhIFQgdmFsdWV8IFZlbW9zIHF1ZSBlbCB2YWxvciBkZSBlc3RpbWFjaW9uIGVzIHBlcXVlbm8sIHBvciBsbyBxdWUgZXN0YSB2YXJpYWJsZSBlbiBlc3RlIG1vZGVsbyBjb250cmlidXllIG11eSBwb2NvfAp8VE9FRkwgU2NvcmV8IEVzdGltYWRvIDAuMDAyIHkgMi42OCB8IENvbW8gdmVtb3MgZWwgZXN0aW1hZG8gZXMgaWd1YWxtZW50ZSBwZXF1ZW5vIHF1ZSBlbCBHUkUgU2NvcmV8CnxSYXRpbmd8IDAuMDAzIHkgMC42MTEgfCBFbCBlc3RpbWFkbyBlcyBsaWdlcmFtZW50ZSBtYXlvciB5IHN1IHQgdmFsdWUgZXMgY2VyY2FubyBhIDAgcG9yIGxvIHF1ZSBsYSBoaXBvdGVzaXMgbnVsYSBzZSBwdWVkZSBkZXNjYXJ0YXIgcGVybyBubyBwb3IgbXVjaG98CnxTT1AgfCAwLjAwMSBZIDAuMjggfCBTdSBlc3RpbWFkbyBlcyBiYWpvIHkgc3UgdCB2YWx1ZSB0YW1iaWVuLCBhcG9ydGEgcG9jbyBhbCBtb2RlbG8gfAp8TE9SIHwgMC4wMTggWSAzLjQ5IHwgQXBvcnRhIG1hcyBhbCBtb2RlbG8gcXVlIGxhcyB2YXJpYWJsZXMgYW50ZXJpb3JlcyB8CnxDR1BBfCAwLjEyIHkgOS44OCB8IFN1IGVzdGltYWRvIGVzIGVsIG1hcyBhbHRvLCBhbCBpZ3VhbCBxdWUgc3UgVCB2YWx1ZSwgZXMgcG9yIGVsbG8gcXVlIGVzdGEgdmFyaWFibGUgcGFyZWNlIHNlciBsYSBtYXMgc2lnbmlmaWNhdGl2YSBwYXJhIGVsIG1vZGVsbyB8CgpDb21vIHZlbW9zIGxhcyB2YXJpYWJsZXMgbWFzIHNpZ25pZmljYXRpdm9zIGRlbCBtb2RlbG8gc29uIGVsIHByb21lZGlvIHkgbGEgY2FydGEgZGUgcmVjb21lbmRhY2lvbiwgcG9yIGxvIHF1ZSBwb2RyaWFtb3MgZW5mb2Nhcm5vcyB1bmljYW1uZXRlIGVuIGVzdGFzIGRvcyB2YXJpYWJsZXMgcGFyYSByZWFsaXphciB1biBtb2RlbG8sIHNpbiBlbWJhcmdvIGVsIEdSRSB5IFRPRUZMIHRpZW5lbiB1biB2YWxvciBhbHRvIGVuIFQgVmFsdWUgcG9yIGxvIHF1ZSBwb2RyaWFtb3MgY29uc2lkZXJhciBtYW50ZW5lcmFsYXMuIFBvciBsbyBxdWUgdW5pY2FtbmV0ZSBzYWNhcmVtb3MgZGVsIG1vZGVsIGVsIFJhdGluZyB5IGVsIFNPUC4KClBvciBsbyB0YW50byBkZWZpbmltb3MgbnVlc3RybyBtb2RlbG8gbGluZWFsIGNvbW8gYENBID0gR1JFICsgVE9FRkwgKyBMT1IgK0NHUEFgLCBsdWVnbyBwcm9jZWRlcmVtb3MgYSBjYWxjdWxhciBsYSBwcmVkaWNjaW9uIGNvbiBsYSBkYXRhIGRlIGVudHJlbmFtaWVudG8geSBsYSBkYXRhIGRlIHBydWViYSwgY2FsY3VsYXJlbW9zIGxvcyBtaW5pbW9zIGN1YWRyYWRvcyB5IHZlbW9zIHZlcmVtb3MgY29tbyBxdWVkYW4gbHNvIGNvZWZpY2llbnRlcyBwYXJhIGxhIGRhdGEgZGUgcHJ1ZWJhIHkgbGEgZGUgZW50cmVuYW1pZW50bzoKCmBgYHtyfQpmaXRfMSA8LSBsbShkYXRhID0gdHJhaW5fZGF0YSwgYENoYW5jZSBvZiBBZG1pdGB+YEdSRSBTY29yZWArYFRPRUZMIFNjb3JlYCtMT1IrQ0dQQSkKYWNfaGF0X3RyYWluIDwtIHByZWRpY3QoZml0XzEsIHRyYWluX2RhdGEpCgphY19oYXRfdGVzdCA8LSBwcmVkaWN0KGZpdF8xLCB0ZXN0X2RhdGEpCgpNU0UxX3RyYWluIDwtIHN1bSgodHJhaW5fZGF0YSRgQ2hhbmNlIG9mIEFkbWl0YC0gYWNfaGF0X3RyYWluKV4yKQpNU0UxX3Rlc3QgPC0gc3VtKCh0ZXN0X2RhdGEkYENoYW5jZSBvZiBBZG1pdGAtIGFjX2hhdF90ZXN0KV4yKQoKTVNFMV90cmFpbgpNU0UxX3Rlc3QKCgpnZ3Bsb3QodHJhaW5fZGF0YSwgYWVzKHggPSBgR1JFIFNjb3JlYCtgVE9FRkwgU2NvcmVgK0xPUitDR1BBLCB5ID0gYENoYW5jZSBvZiBBZG1pdGApKSArIAogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobW9kZWw9Zml0XzEsIGNvbCA9ICJyZWQiKQpgYGAKCkNvbiBlc3RvIHZlbW9zIGxhIGRpZmVyZW5jaWEgZGUgY3VhZW50cmUgZWwgdmFsb3IgZGUgbGEgcHJlY2Npb24gcGFyYSBsYSBkYXRhIGRlIGVudHJlbmFtaWVudG8geSBsYSBkYXRhIHBydWViYSwgbGEgZGlmZXJlbmNpYSBlcyByZWxhdGl2YW1lbnRlIGdyYW5kZS4gVmVhbW9zIHF1ZSBzdWNlZGUgc2kgY29udmVydGltb3MgZXN0byBlbiB1biBtb2RlbG8gY3VhZHJhdGljbzoKCmBgYHtyfQpmaXRfMiA8LSBsbShkYXRhID0gdHJhaW5fZGF0YSwgYENoYW5jZSBvZiBBZG1pdGB+YEdSRSBTY29yZWArSShgR1JFIFNjb3JlYF4yKStgVE9FRkwgU2NvcmVgK0koYFRPRUZMIFNjb3JlYF4yKStMT1IrSShMT1JeMikrQ0dQQStJKENHUEFeMikpCgphY19oYXRfdHJhaW4gPC0gcHJlZGljdChmaXRfMiwgdHJhaW5fZGF0YSkKCmFjX2hhdF90ZXN0IDwtIHByZWRpY3QoZml0XzIsIHRlc3RfZGF0YSkKCk1TRTJfdHJhaW4gPC0gc3VtKCh0cmFpbl9kYXRhJGBDaGFuY2Ugb2YgQWRtaXRgLSBhY19oYXRfdHJhaW4pXjIpCk1TRTJfdGVzdCA8LSBzdW0oKHRlc3RfZGF0YSRgQ2hhbmNlIG9mIEFkbWl0YC0gYWNfaGF0X3Rlc3QpXjIpCgpNU0UyX3RyYWluCk1TRTJfdGVzdAoKZ2dwbG90KHRyYWluX2RhdGEsIGFlcyh4ID0gYEdSRSBTY29yZWArYFRPRUZMIFNjb3JlYCtMT1IrQ0dQQSwgeSA9IGBDaGFuY2Ugb2YgQWRtaXRgKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1vZGVsPWZpdF8yLCBjb2wgPSAicmVkIikKYGBgClZlbW9zIHF1ZSBubyBoYSB2YXJpYWRvIG11Y2hvLCBhdW1lbnRlbW9sbyBhIHVuIG1vZGVsbyBjdWJpY286CgpgYGB7cn0KZml0XzMgPC0gbG0oZGF0YSA9IHRyYWluX2RhdGEsIGBDaGFuY2Ugb2YgQWRtaXRgfmBHUkUgU2NvcmVgK0koYEdSRSBTY29yZWBeMikrSShgR1JFIFNjb3JlYF4zKStgVE9FRkwgU2NvcmVgK0koYFRPRUZMIFNjb3JlYF4yKStJKGBUT0VGTCBTY29yZWBeMykrTE9SK0koTE9SXjIpK0koTE9SXjMpK0NHUEErSShDR1BBXjIpK0koQ0dQQV4zKSkKCmFjX2hhdF90cmFpbiA8LSBwcmVkaWN0KGZpdF8zLCB0cmFpbl9kYXRhKQoKYWNfaGF0X3Rlc3QgPC0gcHJlZGljdChmaXRfMywgdGVzdF9kYXRhKQoKTVNFM190cmFpbiA8LSBzdW0oKHRyYWluX2RhdGEkYENoYW5jZSBvZiBBZG1pdGAtIGFjX2hhdF90cmFpbileMikKTVNFM190ZXN0IDwtIHN1bSgodGVzdF9kYXRhJGBDaGFuY2Ugb2YgQWRtaXRgLSBhY19oYXRfdGVzdCleMikKCk1TRTNfdHJhaW4KTVNFM190ZXN0CgpnZ3Bsb3QodHJhaW5fZGF0YSwgYWVzKHggPSBgR1JFIFNjb3JlYCtgVE9FRkwgU2NvcmVgK0xPUitDR1BBLCB5ID0gYENoYW5jZSBvZiBBZG1pdGApKSArIAogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobW9kZWw9Zml0XzMsIGNvbCA9ICJyZWQiKQpgYGAKCkZpbmFsbWVudGUgcHJvYnJhcmVtb3MgY29uIHVuYSBlY3VhY2lvbiBlbGV2YWRhIGEgbGEgNHRhOgoKYGBge3J9CmZpdF80IDwtIGxtKGRhdGEgPSB0cmFpbl9kYXRhLCBgQ2hhbmNlIG9mIEFkbWl0YH5gR1JFIFNjb3JlYCtJKGBHUkUgU2NvcmVgXjIpK0koYEdSRSBTY29yZWBeMykrSShgR1JFIFNjb3JlYF40KStgVE9FRkwgU2NvcmVgK0koYFRPRUZMIFNjb3JlYF4yKStJKGBUT0VGTCBTY29yZWBeMykrSShgVE9FRkwgU2NvcmVgXjQpK0xPUitJKExPUl4yKStJKExPUl4zKStJKExPUl40KStDR1BBK0koQ0dQQV4yKStJKENHUEFeMykrSShMT1JeNCkpCgphY19oYXRfdHJhaW4gPC0gcHJlZGljdChmaXRfNCwgdHJhaW5fZGF0YSkKCmFjX2hhdF90ZXN0IDwtIHByZWRpY3QoZml0XzQsIHRlc3RfZGF0YSkKCk1TRTRfdHJhaW4gPC0gc3VtKCh0cmFpbl9kYXRhJGBDaGFuY2Ugb2YgQWRtaXRgLSBhY19oYXRfdHJhaW4pXjIpCk1TRTRfdGVzdCA8LSBzdW0oKHRlc3RfZGF0YSRgQ2hhbmNlIG9mIEFkbWl0YC0gYWNfaGF0X3Rlc3QpXjIpCgpNU0U0X3RyYWluCk1TRTRfdGVzdAoKZ2dwbG90KHRyYWluX2RhdGEsIGFlcyh4ID0gYEdSRSBTY29yZWArYFRPRUZMIFNjb3JlYCtMT1IrQ0dQQSwgeSA9IGBDaGFuY2Ugb2YgQWRtaXRgKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1vZGVsPWZpdF80LCBjb2wgPSAicmVkIikKYGBgCkFob3JhIHByb2NlZGVyZW1vcyBhIGFubGl6YXIgbGFzIDQgcmVncmVzaW9uZXMgeSBzdXMgcHJlZGljY2lvbmVzOgoKYGBge3J9CnBsb3QoMTo0LAogICAgIGMoTVNFMV90cmFpbixNU0UyX3RyYWluLE1TRTNfdHJhaW4sTVNFNF90cmFpbiksCiAgICAgeWxpbT1jKDAsMiksCiAgICAgdHlwZT0nbCcpCnBvaW50cygxOjQsCiAgICAgICBjKE1TRTFfdGVzdCxNU0UyX3Rlc3QsTVNFM190ZXN0LE1TRTRfdGVzdCksCiAgICAgICBjb2w9J3JlZCcsCiAgICAgICB0eXBlPSdsJykKYGBgCiMjIyBDb25jbHVzaW9uCgpDb21vIHZlbW9zIGxvcyB2YWxvcmVzIGVudHJlIGxhIHByZWRpY2Npb24gcmVhbCB5IGxhIHByZWRpY2Npb24gZGUgcHJ1ZWJhIHNvbiBjb25zdGFudGVzIHNpbiBpbXBvcnRhciBzaSB1dGlsaXphbW9zIHVuIG1vZGVsbyBsaW5lYWwgbyB1bm8gYSBsYSBjdWFydGEsIHBvciBsbyBxdWUgdmVtb3MgcXVlIGVsIG1vZGVsbyBsaW5lYWwgc2VyaWEgZWwgaW5kaWNhZG8sIGFzaSBtaXNtbyB2ZW1vcyBxdWUgbGEgZGlmZXJlbmNpYSBlcyBtdXkgcG9jYSBwb3IgbG8gcXVlIHBvZGVtb3MgdXRpbGl6YXIgdW5pY2FtZW50ZSBlbCBtb2RlbG8gbGluZWFsLg==