Parte I

1. Descargar el dataset de admis1.csv del GES.

2. Separe su dataset en 70% para el train y 30% para el test.

library(ggplot2)
library(readr)
admis <- read.csv("admis1.csv", stringsAsFactors = F)
head(admis)
train_index <- sample(1:nrow(admis), size = nrow(admis)*0.7)
test_index <- setdiff(1:nrow(admis), train_index)
train <- admis[train_index,]
test <- admis[test_index,]
c(nrow(train), nrow(test))
[1] 350 150

3. Diga cuales son las variables que tiene este dataset y que significa cada una.

Este dataset consta de las siguientes variables:

colnames(admis)
[1] "Serial.No."        "GRE.Score"         "TOEFL.Score"       "University.Rating" "SOP"               "LOR"              
[7] "CGPA"              "Research"          "Chance.of.Admit"  

Donde: * GRE Score: Por sus siglas en ingles, Graduate Record Examinations es una prueba estandarizada que es un requerimiento de admision en la mayoria de Universidades en Estados Unidos. Indica el punteo obtenido en esta prueba, el punteo mayor es de 340 puntos.

4. Realice una grafica separada para las variables: GRE.Score, TOEFL.Score, SOP, LOR, CGPA, University.Rating contra Chance.of.Admit.

ggplot(admis, aes(x = admis$GRE.Score, y = admis$Chance.of.Admit)) + 
  geom_point() +
  xlab("GRE Score") +
  ylab("Chance of Admit") + 
  labs(title = "GRE.Score vs Chance.of.Admit")

ggplot(admis, aes(x = admis$TOEFL.Score, y = admis$Chance.of.Admit)) + 
  geom_point()  +
  xlab("TOEFL Score") +
  ylab("Chance of Admit") + 
  labs(title = "TOEFL.Score vs Chance.of.Admit")

ggplot(admis, aes(x = admis$SOP, y = admis$Chance.of.Admit)) + 
  geom_point() +
  xlab("SOP") +
  ylab("Chance of Admit") + 
  labs(title = "SOP vs Chance.of.Admit")

ggplot(admis, aes(x = admis$LOR, y = admis$Chance.of.Admit)) + 
  geom_point() +
  xlab("LOR") +
  ylab("Chance of Admit") + 
  labs(title = "LOR vs Chance.of.Admit")

ggplot(admis, aes(x = admis$CGPA, y = admis$Chance.of.Admit)) + 
  geom_point() +
  xlab("CGPA") +
  ylab("Chance of Admit") + 
  labs(title = "CGPA vs Chance.of.Admit")

ggplot(admis, aes(x = admis$University.Rating, y = admis$Chance.of.Admit)) + 
  geom_point() +
  xlab("University Rating") +
  ylab("Chance of Admit") + 
  labs(title = "University.Rating vs Chance.of.Admit")

5. Diga que tipo de regresion utilizaria para construir un modelo de regresion que permita predecir el Chance.of.Admit, esto debe realizarlo con cada variable independiente es decir construir un modelo de dos variables, una explicada y una explicatoria.

fit1 <- lm(data=train, train$Chance.of.Admit~train$GRE.Score)
summary(fit1)

Call:
lm(formula = train$Chance.of.Admit ~ train$GRE.Score, data = train)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.33672 -0.04066  0.00886  0.05587  0.17559 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -2.3191838  0.1312614  -17.67   <2e-16 ***
train$GRE.Score  0.0096158  0.0004143   23.21   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.08481 on 348 degrees of freedom
Multiple R-squared:  0.6075,    Adjusted R-squared:  0.6064 
F-statistic: 538.6 on 1 and 348 DF,  p-value: < 2.2e-16
fit2 <- lm(data=train, train$Chance.of.Admit~train$TOEFL.Score)
summary(fit2)

Call:
lm(formula = train$Chance.of.Admit ~ train$TOEFL.Score, data = train)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.31565 -0.03692  0.01259  0.05759  0.19731 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -1.176496   0.082000  -14.35   <2e-16 ***
train$TOEFL.Score  0.017747   0.000764   23.23   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.08477 on 348 degrees of freedom
Multiple R-squared:  0.6079,    Adjusted R-squared:  0.6068 
F-statistic: 539.6 on 1 and 348 DF,  p-value: < 2.2e-16
fit3 <- lm(data=train, train$Chance.of.Admit~train$SOP)
summary(fit3)

Call:
lm(formula = train$Chance.of.Admit ~ train$SOP, data = train)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.44469 -0.05731  0.01638  0.06745  0.24220 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 0.405657   0.019200   21.13   <2e-16 ***
train$SOP   0.094759   0.005469   17.33   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.09919 on 348 degrees of freedom
Multiple R-squared:  0.4631,    Adjusted R-squared:  0.4616 
F-statistic: 300.2 on 1 and 348 DF,  p-value: < 2.2e-16
fit4 <- lm(data=train, train$Chance.of.Admit~train$LOR)
summary(fit4)

Call:
lm(formula = train$Chance.of.Admit ~ train$LOR, data = train)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.34314 -0.05775 -0.00003  0.07820  0.26552 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 0.405816   0.022082   18.38   <2e-16 ***
train$LOR   0.092442   0.006175   14.97   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1056 on 348 degrees of freedom
Multiple R-squared:  0.3917,    Adjusted R-squared:   0.39 
F-statistic: 224.1 on 1 and 348 DF,  p-value: < 2.2e-16
fit5 <- lm(data=train, train$Chance.of.Admit~poly(train$CGPA,2))
summary(fit5)

Call:
lm(formula = train$Chance.of.Admit ~ poly(train$CGPA, 2), data = train)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.278177 -0.025733  0.004768  0.036729  0.172836 

Coefficients:
                     Estimate Std. Error t value Pr(>|t|)    
(Intercept)          0.725400   0.003489 207.933   <2e-16 ***
poly(train$CGPA, 2)1 2.213273   0.065266  33.911   <2e-16 ***
poly(train$CGPA, 2)2 0.034825   0.065266   0.534    0.594    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06527 on 347 degrees of freedom
Multiple R-squared:  0.7682,    Adjusted R-squared:  0.7669 
F-statistic: 575.1 on 2 and 347 DF,  p-value: < 2.2e-16

6. Utilice el método smooth para mostrar en cada gráfica el modelo que mejor se ajusta a los datos, esto debe hacerlo para cada gráfica por separado

ggplot(admis, aes(x = admis$GRE.Score, y = admis$Chance.of.Admit)) + 
  geom_point() +
  geom_smooth() +
  xlab("GRE Score") +
  ylab("Chance of Admit") + 
  labs(title = "GRE.Score vs Chance.of.Admit")

ggplot(admis, aes(x = admis$TOEFL.Score, y = admis$Chance.of.Admit)) + 
  geom_point()  +
  geom_smooth() +
  xlab("TOEFL Score") +
  ylab("Chance of Admit") + 
  labs(title = "TOEFL.Score vs Chance.of.Admit")

ggplot(admis, aes(x = admis$SOP, y = admis$Chance.of.Admit)) + 
  geom_point() +
  geom_smooth() +
  xlab("SOP") +
  ylab("Chance of Admit") + 
  labs(title = "SOP vs Chance.of.Admit")

ggplot(admis, aes(x = admis$LOR, y = admis$Chance.of.Admit)) + 
  geom_point() +
  geom_smooth() +
  xlab("LOR") +
  ylab("Chance of Admit") + 
  labs(title = "LOR vs Chance.of.Admit")

ggplot(admis, aes(x = admis$CGPA, y = admis$Chance.of.Admit)) + 
  geom_point() +
  geom_smooth() +
  xlab("CGPA") +
  ylab("Chance of Admit") + 
  labs(title = "CGPA vs Chance.of.Admit")

ggplot(admis, aes(x = admis$University.Rating, y = admis$Chance.of.Admit)) + 
  geom_point() +
  geom_smooth() +
  xlab("University Rating") +
  ylab("Chance of Admit") + 
  labs(title = "University.Rating vs Chance.of.Admit")

7. Para cada caso produzca un modelo lo más aproximado que sea posible utilizando la función LM y muéstrelo graficado.

Parte II

1. Realice un modelo de regresión (lineal/no lineal) con todas las variables anteriores, y diga la significancia de cada una de las variables

fit_modelo <- lm(data = train, train$Chance.of.Admit ~ poly(train$GRE.Score,2)+ poly(train$TOEFL.Score,2) + train$CGPA + train$SOP + train$LOR + train$University.Rating)
summary(fit_modelo)

Call:
lm(formula = train$Chance.of.Admit ~ poly(train$GRE.Score, 2) + 
    poly(train$TOEFL.Score, 2) + train$CGPA + train$SOP + train$LOR + 
    train$University.Rating, data = train)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.282850 -0.022153  0.008705  0.033871  0.144877 

Coefficients:
                              Estimate Std. Error t value Pr(>|t|)    
(Intercept)                 -0.4541444  0.0936201  -4.851 1.87e-06 ***
poly(train$GRE.Score, 2)1    0.3982560  0.1204431   3.307 0.001045 ** 
poly(train$GRE.Score, 2)2    0.0250460  0.0798716   0.314 0.754033    
poly(train$TOEFL.Score, 2)1  0.2389666  0.1229526   1.944 0.052770 .  
poly(train$TOEFL.Score, 2)2 -0.0189624  0.0786073  -0.241 0.809522    
train$CGPA                   0.1269176  0.0117728  10.781  < 2e-16 ***
train$SOP                   -0.0009985  0.0057588  -0.173 0.862447    
train$LOR                    0.0183292  0.0049428   3.708 0.000243 ***
train$University.Rating      0.0099033  0.0047764   2.073 0.038885 *  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06044 on 341 degrees of freedom
Multiple R-squared:  0.8047,    Adjusted R-squared:  0.8001 
F-statistic: 175.6 on 8 and 341 DF,  p-value: < 2.2e-16

En este modelo podemos observar que el GRE Score es altamente significante incluso en segundo grado. También el CGPA es muy significante

2. Produzca el modelo que usted considere mejor para predecir el Chance.of.Admit.

fit_modelo2 <- lm(data = train, train$Chance.of.Admit ~ poly(train$GRE.Score,2) + train$CGPA + train$TOEFL.Score)
y_hat_train <- predict(fit_modelo2, train)
MSE6_train <- sum((train$Chance.of.Admit - y_hat_train)^2)
MSE6_train
[1] 1.344995
summary(fit_modelo2)

Call:
lm(formula = train$Chance.of.Admit ~ poly(train$GRE.Score, 2) + 
    train$CGPA + train$TOEFL.Score, data = train)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.292467 -0.020900  0.007207  0.036905  0.129618 

Coefficients:
                           Estimate Std. Error t value Pr(>|t|)    
(Intercept)               -0.888624   0.114698  -7.747 1.06e-13 ***
poly(train$GRE.Score, 2)1  0.386840   0.121100   3.194  0.00153 ** 
poly(train$GRE.Score, 2)2  0.021286   0.063464   0.335  0.73752    
train$CGPA                 0.151124   0.010781  14.018  < 2e-16 ***
train$TOEFL.Score          0.002963   0.001101   2.690  0.00748 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.06244 on 345 degrees of freedom
Multiple R-squared:  0.7891,    Adjusted R-squared:  0.7867 
F-statistic: 322.7 on 4 and 345 DF,  p-value: < 2.2e-16

3. Realice predicciones con el 30% de data resultante y compare los resultados estimados contra los resultados reales


prediccion_test <- predict(fit_modelo2,newdata=test)
LS0tDQp0aXRsZTogIkxhYm9yYXRvcmlvIDEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyBQYXJ0ZSBJDQoqKjEuIERlc2NhcmdhciBlbCBkYXRhc2V0IGRlIGFkbWlzMS5jc3YgZGVsIEdFUy4qKg0KDQoqKjIuIFNlcGFyZSBzdSBkYXRhc2V0IGVuIDcwJSBwYXJhIGVsIHRyYWluIHkgMzAlIHBhcmEgZWwgdGVzdC4qKg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmVhZHIpDQphZG1pcyA8LSByZWFkLmNzdigiYWRtaXMxLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQ0KaGVhZChhZG1pcykNCmBgYA0KDQpgYGB7cn0NCnRyYWluX2luZGV4IDwtIHNhbXBsZSgxOm5yb3coYWRtaXMpLCBzaXplID0gbnJvdyhhZG1pcykqMC43KQ0KdGVzdF9pbmRleCA8LSBzZXRkaWZmKDE6bnJvdyhhZG1pcyksIHRyYWluX2luZGV4KQ0KDQp0cmFpbiA8LSBhZG1pc1t0cmFpbl9pbmRleCxdDQp0ZXN0IDwtIGFkbWlzW3Rlc3RfaW5kZXgsXQ0KYyhucm93KHRyYWluKSwgbnJvdyh0ZXN0KSkNCmBgYA0KDQoqKjMuIERpZ2EgY3VhbGVzIHNvbiBsYXMgdmFyaWFibGVzIHF1ZSB0aWVuZSBlc3RlIGRhdGFzZXQgeSBxdWUgc2lnbmlmaWNhIGNhZGEgdW5hLioqDQoNCkVzdGUgZGF0YXNldCBjb25zdGEgZGUgbGFzIHNpZ3VpZW50ZXMgdmFyaWFibGVzOg0KYGBge3J9DQpjb2xuYW1lcyhhZG1pcykNCmBgYA0KRG9uZGU6DQoqICoqR1JFIFNjb3JlOioqIFBvciBzdXMgc2lnbGFzIGVuIGluZ2xlcywgKkdyYWR1YXRlIFJlY29yZCBFeGFtaW5hdGlvbnMqIGVzIHVuYSBwcnVlYmEgZXN0YW5kYXJpemFkYSBxdWUgZXMgdW4gcmVxdWVyaW1pZW50byBkZSBhZG1pc2lvbiBlbiBsYSBtYXlvcmlhIGRlIFVuaXZlcnNpZGFkZXMgZW4gRXN0YWRvcyBVbmlkb3MuIEluZGljYSBlbCBwdW50ZW8gb2J0ZW5pZG8gZW4gZXN0YSBwcnVlYmEsIGVsIHB1bnRlbyBtYXlvciBlcyBkZSAzNDAgcHVudG9zLg0KDQoqICoqVE9FRkwgU2NvcmU6KiogVGVzdCBvZiBFbmdsaXNoIGFzIGEgRm9yZWlnbiBMYW5ndWFnZSwgZXMgdW5hIHBydWViYSBlc3RhbmRhcml6YWRhIHBhcmEgbWVkaXIgZWwgZG9taW5pbyBkZWwgaWRpb21hIGluZ2xlcyBlbiBwZXJzb25hcyBjb24gZXNlIGxlbmd1YWplIG5vIG5hdGl2byB5IHF1ZSBkZXNlYW4gaW5ncmVzYXIgYSB1bmEgVW5pdmVyc2lkYWQgZGUgaGFibGEgaW5nbGVzLiBJbmRpY2EgZWwgcHVudGVvIG9idGVuaWRvIGVuIGVzdGEgcHJ1ZWJhLCBlbCBwdW50ZW8gbWF5b3IgZXMgZGUgMTIwIHB1bnRvcy4NCg0KKiAqKlVuaXZlcnNpdHkgUmF0aW5nOioqIEVzIHVuIHZhbG9yIGRlIDEgYSA1IHF1ZSBjb3JyZXNwb25kZSBhIHVuIHJhdGluZyBxdWUgbGUgZGEgbGEgVW5pdmVyc2lkYWQgYSBjYWRhIHNvbGljaXRhbnRlLg0KDQoqICoqU09QOioqIFBvciBzdXMgc2lnbGFzIGVuIGluZ2xlcyAqU3RhdGVtZW50IG9mIFB1cnBvc2UqIGVzIHVuIGVuc2F5byBlc2NyaXRvIHBvciB1biBwb3NpYmxlIGVzdHVkaWFudGUgcXVlIHNvbGljaXRhIGFkbWlzaW9uIGVuIGxhIFVuaXZlcnNpZGFkLiBFcyB1biB2YWxvciBkZSAxIGEgNSwgZG9uZGUgNSBzaW1ib2xpemFsYSBtYXlvciBjYWxpZmljYWNpb24uDQoNCiogKipMT1I6KiogUG9yIHN1cyBzaWdsYXMgZW4gaW5nbGVzICpMZXR0ZXIgb2YgUmVjb21tZW5kYXRpb24qIGVzIHVuIGRvY3VtZW50byBlbiBlbCBjdWFsIHNlIGV4cG9uZW4gbGFzIGN1YWxpZGFkZXMsIGNhcGFjaWRhZGVzIHkgY2FyYWN0ZXJpc3RpY2FzIGRlIHVuYSBwZXJzb25hIHF1ZSBlc3RhIHNpZW5kbyByZWNvbWVuZGFkYS4gRXMgdW4gdmFsb3IgZGUgMSBhIDUsIGRvbmRlIDUgc2ltYm9saXphbGEgbWF5b3IgY2FsaWZpY2FjaW9uLg0KDQoqICoqQ0dQQToqKiAqQ3VtdWxhdGl2ZSBHcmFkZSBQb2ludCBBdmVyYWdlKiBzZSByZWZpZXJlIGFsIGRlc2VtcGXDsW8gYWNhZGVtaWNvIGNvbW8gdW4gcHJvbWVkaW8gZGUgbG9zIHNlbWVzdHJlcyBjb21wbGV0YWRvcy4gRXMgdW4gcHJvbWVkaW8gZW50cmUgMCB5IDEwLg0KDQoqICoqUmVzZWFyY2g6KiogRXMgdW4gdmFsb3IgZGUgMCBvIDEgZGVwZW5kaWVuZG8gZGUgc2kgZWwgc29saWNpdGFudGUgdHV2byBleHBlcmllbmNpYSBkZSByZWFzZXJjaC4NCg0KKiAqKkNoYW5jZSBvZiBBZG1pdDoqKiBFcyBlbCBjaGFuY2UgZGUgYWRtaXNpb24gcXVlIHRpZW5lbiwgZXMgdW4gdmFsb3IgZW50cmUgMCB5IDEuIERvbmRlIDEgc2lnbmlmaWNhIHF1ZSB0aWVuZSBtYXlvciBjaGFuY2UgZGUgYWRtaXNpb24uDQoNCg0KKio0LiBSZWFsaWNlIHVuYSBncmFmaWNhIHNlcGFyYWRhIHBhcmEgbGFzIHZhcmlhYmxlczogR1JFLlNjb3JlLCBUT0VGTC5TY29yZSwgU09QLCBMT1IsIENHUEEsIFVuaXZlcnNpdHkuUmF0aW5nIGNvbnRyYSBDaGFuY2Uub2YuQWRtaXQuKioNCg0KYGBge3J9DQpnZ3Bsb3QoYWRtaXMsIGFlcyh4ID0gYWRtaXMkR1JFLlNjb3JlLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxhYigiR1JFIFNjb3JlIikgKw0KICB5bGFiKCJDaGFuY2Ugb2YgQWRtaXQiKSArIA0KICBsYWJzKHRpdGxlID0gIkdSRS5TY29yZSB2cyBDaGFuY2Uub2YuQWRtaXQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGFkbWlzLCBhZXMoeCA9IGFkbWlzJFRPRUZMLlNjb3JlLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICArDQogIHhsYWIoIlRPRUZMIFNjb3JlIikgKw0KICB5bGFiKCJDaGFuY2Ugb2YgQWRtaXQiKSArIA0KICBsYWJzKHRpdGxlID0gIlRPRUZMLlNjb3JlIHZzIENoYW5jZS5vZi5BZG1pdCIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoYWRtaXMsIGFlcyh4ID0gYWRtaXMkU09QLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxhYigiU09QIikgKw0KICB5bGFiKCJDaGFuY2Ugb2YgQWRtaXQiKSArIA0KICBsYWJzKHRpdGxlID0gIlNPUCB2cyBDaGFuY2Uub2YuQWRtaXQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGFkbWlzLCBhZXMoeCA9IGFkbWlzJExPUiwgeSA9IGFkbWlzJENoYW5jZS5vZi5BZG1pdCkpICsgDQogIGdlb21fcG9pbnQoKSArDQogIHhsYWIoIkxPUiIpICsNCiAgeWxhYigiQ2hhbmNlIG9mIEFkbWl0IikgKyANCiAgbGFicyh0aXRsZSA9ICJMT1IgdnMgQ2hhbmNlLm9mLkFkbWl0IikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChhZG1pcywgYWVzKHggPSBhZG1pcyRDR1BBLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgeGxhYigiQ0dQQSIpICsNCiAgeWxhYigiQ2hhbmNlIG9mIEFkbWl0IikgKyANCiAgbGFicyh0aXRsZSA9ICJDR1BBIHZzIENoYW5jZS5vZi5BZG1pdCIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoYWRtaXMsIGFlcyh4ID0gYWRtaXMkVW5pdmVyc2l0eS5SYXRpbmcsIHkgPSBhZG1pcyRDaGFuY2Uub2YuQWRtaXQpKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICB4bGFiKCJVbml2ZXJzaXR5IFJhdGluZyIpICsNCiAgeWxhYigiQ2hhbmNlIG9mIEFkbWl0IikgKyANCiAgbGFicyh0aXRsZSA9ICJVbml2ZXJzaXR5LlJhdGluZyB2cyBDaGFuY2Uub2YuQWRtaXQiKQ0KYGBgDQoNCioqNS4gRGlnYSBxdWUgdGlwbyBkZSByZWdyZXNpb24gdXRpbGl6YXJpYSBwYXJhIGNvbnN0cnVpciB1biBtb2RlbG8gZGUgcmVncmVzaW9uIHF1ZSBwZXJtaXRhIHByZWRlY2lyIGVsIENoYW5jZS5vZi5BZG1pdCwgZXN0byBkZWJlIHJlYWxpemFybG8gY29uIGNhZGEgdmFyaWFibGUgaW5kZXBlbmRpZW50ZSBlcyBkZWNpciBjb25zdHJ1aXIgdW4gbW9kZWxvIGRlIGRvcyB2YXJpYWJsZXMsIHVuYSBleHBsaWNhZGEgeSB1bmEgZXhwbGljYXRvcmlhLioqDQoNCmBgYHtyfQ0KZml0MSA8LSBsbShkYXRhPXRyYWluLCB0cmFpbiRDaGFuY2Uub2YuQWRtaXR+cG9seSh0cmFpbiRHUkUuU2NvcmUsMikpDQpzdW1tYXJ5KGZpdDEpDQpgYGANCg0KYGBge3J9DQpmaXQyIDwtIGxtKGRhdGE9dHJhaW4sIHRyYWluJENoYW5jZS5vZi5BZG1pdH50cmFpbiRUT0VGTC5TY29yZSkNCnN1bW1hcnkoZml0MikNCmBgYA0KDQpgYGB7cn0NCmZpdDMgPC0gbG0oZGF0YT10cmFpbiwgdHJhaW4kQ2hhbmNlLm9mLkFkbWl0fnRyYWluJFNPUCkNCnN1bW1hcnkoZml0MykNCmBgYA0KDQpgYGB7cn0NCmZpdDQgPC0gbG0oZGF0YT10cmFpbiwgdHJhaW4kQ2hhbmNlLm9mLkFkbWl0fnRyYWluJExPUikNCnN1bW1hcnkoZml0NCkNCmBgYA0KDQpgYGB7cn0NCmZpdDUgPC0gbG0oZGF0YT10cmFpbiwgdHJhaW4kQ2hhbmNlLm9mLkFkbWl0fnBvbHkodHJhaW4kQ0dQQSwyKSkNCnN1bW1hcnkoZml0NSkNCmBgYA0KDQoqKjYuIFV0aWxpY2UgZWwgbcOpdG9kbyBzbW9vdGggcGFyYSBtb3N0cmFyIGVuIGNhZGEgZ3LDoWZpY2EgZWwgbW9kZWxvIHF1ZSBtZWpvciBzZSBhanVzdGEgYSBsb3MgZGF0b3MsIGVzdG8gZGViZSBoYWNlcmxvIHBhcmEgY2FkYSBncsOhZmljYSBwb3Igc2VwYXJhZG8qKg0KDQpgYGB7cn0NCmdncGxvdChhZG1pcywgYWVzKHggPSBhZG1pcyRHUkUuU2NvcmUsIHkgPSBhZG1pcyRDaGFuY2Uub2YuQWRtaXQpKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX3Ntb290aCgpICsNCiAgeGxhYigiR1JFIFNjb3JlIikgKw0KICB5bGFiKCJDaGFuY2Ugb2YgQWRtaXQiKSArIA0KICBsYWJzKHRpdGxlID0gIkdSRS5TY29yZSB2cyBDaGFuY2Uub2YuQWRtaXQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGFkbWlzLCBhZXMoeCA9IGFkbWlzJFRPRUZMLlNjb3JlLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICArDQogIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCJUT0VGTCBTY29yZSIpICsNCiAgeWxhYigiQ2hhbmNlIG9mIEFkbWl0IikgKyANCiAgbGFicyh0aXRsZSA9ICJUT0VGTC5TY29yZSB2cyBDaGFuY2Uub2YuQWRtaXQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGFkbWlzLCBhZXMoeCA9IGFkbWlzJFNPUCwgeSA9IGFkbWlzJENoYW5jZS5vZi5BZG1pdCkpICsgDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCJTT1AiKSArDQogIHlsYWIoIkNoYW5jZSBvZiBBZG1pdCIpICsgDQogIGxhYnModGl0bGUgPSAiU09QIHZzIENoYW5jZS5vZi5BZG1pdCIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoYWRtaXMsIGFlcyh4ID0gYWRtaXMkTE9SLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoIkxPUiIpICsNCiAgeWxhYigiQ2hhbmNlIG9mIEFkbWl0IikgKyANCiAgbGFicyh0aXRsZSA9ICJMT1IgdnMgQ2hhbmNlLm9mLkFkbWl0IikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChhZG1pcywgYWVzKHggPSBhZG1pcyRDR1BBLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoIkNHUEEiKSArDQogIHlsYWIoIkNoYW5jZSBvZiBBZG1pdCIpICsgDQogIGxhYnModGl0bGUgPSAiQ0dQQSB2cyBDaGFuY2Uub2YuQWRtaXQiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGFkbWlzLCBhZXMoeCA9IGFkbWlzJFVuaXZlcnNpdHkuUmF0aW5nLCB5ID0gYWRtaXMkQ2hhbmNlLm9mLkFkbWl0KSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoIlVuaXZlcnNpdHkgUmF0aW5nIikgKw0KICB5bGFiKCJDaGFuY2Ugb2YgQWRtaXQiKSArIA0KICBsYWJzKHRpdGxlID0gIlVuaXZlcnNpdHkuUmF0aW5nIHZzIENoYW5jZS5vZi5BZG1pdCIpDQpgYGANCg0KDQoqKjcuIFBhcmEgY2FkYSBjYXNvIHByb2R1emNhIHVuIG1vZGVsbyBsbyBtw6FzIGFwcm94aW1hZG8gcXVlIHNlYSBwb3NpYmxlIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gTE0geSBtdcOpc3RyZWxvIGdyYWZpY2Fkby4qKg0KDQojIyBQYXJ0ZSBJSQ0KDQoqKjEuIFJlYWxpY2UgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gKGxpbmVhbC9ubyBsaW5lYWwpIGNvbiB0b2RhcyBsYXMgdmFyaWFibGVzIGFudGVyaW9yZXMsIHkgZGlnYSBsYSBzaWduaWZpY2FuY2lhIGRlIGNhZGEgdW5hIGRlIGxhcyB2YXJpYWJsZXMqKg0KDQpgYGB7cn0NCmZpdF9tb2RlbG8gPC0gbG0oZGF0YSA9IHRyYWluLCB0cmFpbiRDaGFuY2Uub2YuQWRtaXQgfiBwb2x5KHRyYWluJEdSRS5TY29yZSwyKSsgcG9seSh0cmFpbiRUT0VGTC5TY29yZSwyKSArIHRyYWluJENHUEEgKyB0cmFpbiRTT1AgKyB0cmFpbiRMT1IgKyB0cmFpbiRVbml2ZXJzaXR5LlJhdGluZykNCnN1bW1hcnkoZml0X21vZGVsbykNCmBgYA0KDQpFbiBlc3RlIG1vZGVsbyBwb2RlbW9zIG9ic2VydmFyIHF1ZSBlbCAqR1JFIFNjb3JlKiBlcyBhbHRhbWVudGUgc2lnbmlmaWNhbnRlIGluY2x1c28gZW4gc2VndW5kbyBncmFkby4gVGFtYmnDqW4gZWwgQ0dQQSBlcyBtdXkgc2lnbmlmaWNhbnRlDQoNCioqMi4gUHJvZHV6Y2EgZWwgbW9kZWxvIHF1ZSB1c3RlZCBjb25zaWRlcmUgbWVqb3IgcGFyYSBwcmVkZWNpciBlbCBDaGFuY2Uub2YuQWRtaXQuKioNCg0KYGBge3J9DQpmaXRfbW9kZWxvMiA8LSBsbShkYXRhID0gdHJhaW4sIHRyYWluJENoYW5jZS5vZi5BZG1pdCB+IHBvbHkodHJhaW4kR1JFLlNjb3JlLDIpICsgdHJhaW4kQ0dQQSArIHRyYWluJFRPRUZMLlNjb3JlKQ0KeV9oYXRfdHJhaW4gPC0gcHJlZGljdChmaXRfbW9kZWxvMiwgdHJhaW4pDQoNCk1TRTZfdHJhaW4gPC0gc3VtKCh0cmFpbiRDaGFuY2Uub2YuQWRtaXQgLSB5X2hhdF90cmFpbileMikNCk1TRTZfdHJhaW4NCnN1bW1hcnkoZml0X21vZGVsbzIpDQpgYGANCg0KDQoqKjMuIFJlYWxpY2UgcHJlZGljY2lvbmVzIGNvbiBlbCAzMCUgZGUgZGF0YSByZXN1bHRhbnRlIHkgY29tcGFyZSBsb3MgcmVzdWx0YWRvcyBlc3RpbWFkb3MgY29udHJhIGxvcyByZXN1bHRhZG9zIHJlYWxlcyoqDQoNCmBgYHtyfQ0KDQpwcmVkaWNjaW9uX3Rlc3QgPC0gcHJlZGljdChmaXRfbW9kZWxvMixuZXdkYXRhPXRlc3QpDQoNCmBgYA0KDQo=