Regresión lineal múltiple

Estimación de los coeficientes de regresión

datos <- read.csv("ventas.csv")
head(datos)
##   TV     Radio Social_media Influencer     Sales
## 1 16  6.566231     2.907983       Mega  54.73276
## 2 13  9.237765     2.409567       Mega  46.67790
## 3 41 15.886446     2.913410       Mega 150.17783
## 4 83 30.020028     6.922304       Mega 298.24634
## 5 15  8.437408     1.405998      Micro  56.59418
## 6 29  9.614382     1.027163       Mega 105.88915

La data contiene datos sobre las ventas de una compañía y los montos asignados a publicidad en distintos medios (TV, radio y redes sociales).

Primero analizaremos mediante una regresión lineal simple si existe alguna relación entre:

Variable independiente X: TV - Presupuesto designado a promoción en Tv(millones de dólares)

Variable dependiente Y: Sales - Ventas de la empresa(millones de dólares)

X<-datos$TV
Y<-datos$Sales
data<-data.frame(X,Y)

Empleando la función lm() se genera un modelo de regresión lineal por mínimos cuadrados en el que la variable respuesta es Sales (Y) y el predictor TV (X)

modelo <- lm(Y ~ X, data=data)
modelo$coefficients
## (Intercept)           X 
##  -0.1263254   3.5614111

De donde: bo = -0.13 y b1 = 3.56

Con estos datos, podemos decir que la ecuación de regresión estimada es:

y = -0.13 + 3.56x

Sales = -0.13 + 3.56TV

El b1 = 3.56 significa que si el presupuesto destinado a TV se incremente en 1%, entonces en promedio las ventas de la empresa aumenta en 3.56 millones de dólares.

El b0 = -0.13 no tiene un significado real, y representa solo un intercepto de la ecuación de regresión, Si la variable TV es igual cero, las ventas de la empresa es de b0, lo cual no tiene sentido.

Ajuste del modelo - supuestos - resultados

Sin embargo, contamos con más datos que pueden servir para explicar o determinar mejor si la relación que existe entre las variables de interes es significativa o no. Por ello, podemos utilizar las siguientes variables:

Sales = β0 + β1TV + β2Radio + β3Social_media + u

regresion <- lm(Sales ~ TV+Radio+Social_media,
data=datos)
summary(regresion)
## 
## Call:
## lm(formula = Sales ~ TV + Radio + Social_media, data = datos)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -11.6158  -2.0002  -0.0075   2.0199  11.2581 
## 
## Coefficients:
##               Estimate Std. Error  t value            Pr(>|t|)    
## (Intercept)  -0.133963   0.102820   -1.303               0.193    
## TV            3.562570   0.003389 1051.118 <0.0000000000000002 ***
## Radio        -0.003970   0.009781   -0.406               0.685    
## Social_media  0.004964   0.024884    0.199               0.842    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.95 on 4542 degrees of freedom
##   (26 observations deleted due to missingness)
## Multiple R-squared:  0.999,  Adjusted R-squared:  0.999 
## F-statistic: 1.505e+06 on 3 and 4542 DF,  p-value: < 0.00000000000000022

Antes de interpretar los resultados, es necesario verificar los supuestos del modelo

ajuste<- datos %>%
add_residuals(regresion)
par(mfrow=c(2,2))
plot(regresion)

En la parte superior izquierda: Muestra la gráfica de residuales contra la variable estimada yˆ. Los residuales están dispersos alrededor del cero, sin mostrar ningún patrón o relación entre los residuales y la variable dependiente estimada, entonces nuestro modelo es apropiado.

En la parte superior derecha: Muestra la gráfica de probabilidad normal, sirve para comprobar que los residuales se distribuyen normalmente utilizando los residuales estandarizados, los residuales forman algo parecido a una recta de 45°, entonces los residuales son normales.

En la parte inferior izquierda: Muestra la gráfica de la raíz cuadrada del valor absoluto de los residuales estandarizados contra la variable dependiente estimada yˆ, la cuál sirve para determinar si los residuales son de varianza constante, al igual que la primera gráfica, se encuentra que los valores están dispersos sin mostrar ningún patrón, por tanto el modelo es adecuado.

En la parte inferior derecha: Muestra la gráfica de distancia de Cook, la cual sirve para identificar si existen algunos valores grandes que tengan una gran influencia sobre la estimación de los coeficientes, una gran distancia indica que esas observaciones tienen un gran peso sobre la estimación. La existencia de valores atípicos son una de las causas de heterocedasticidad.

summary(ajuste$resid)
##       Min.    1st Qu.     Median       Mean    3rd Qu.       Max.       NA's 
## -11.615811  -2.000239  -0.007466   0.000000   2.019922  11.258108         26
jarque.bera.test(na.omit(ajuste$resid))
## 
##  Jarque Bera Test
## 
## data:  na.omit(ajuste$resid)
## X-squared = 0.034132, df = 2, p-value = 0.9831
bptest(regresion)
## 
##  studentized Breusch-Pagan test
## 
## data:  regresion
## BP = 1.5262, df = 3, p-value = 0.6762

Los resultados indican que los residuales son normales, y se verifica que los errores si son homocedásticos.

Utilizando los resultados de la regresión, observamos que las variables independientes explican en 99.9% la variación de las ventas de la empresa estandarizadas, el estadístico F también indica que el modelo es significativo, pues en conjunto los coeficientes son distintos de cero. La variable de interés (TV) es positiva y significativa, es decir, aumentar el presupuesto destinado a TV, aumenta las ventas de la empresa, la variable es significativa al 100%. Aumentar el presupuesto destinado a TV en 1 millon, indica que las ventas promedio de la empresa aumenta 3.56 millones en promedio.

El resto de las variables resultaron poco significativas, es minimo el efecto que causa sobre las ventas de la empresa.

Dicho de otra forma, si las autoridades de la compañia desean aumentar las ventas de la empresa, necesitan tomar en cuenta las variables que son significativas, esta claro que la inversion a presupuesto en Tv seria la más rentable. Nota que es necesario tener en cuenta las unidades de la medida de la variable dependiente y las independiente:

En la variable Radio - un aumento de 1 millon en presupuesto para Radio, las ventas de la empresa disminuyen en promedio 3970 dolares

En la variable Social_media - un aumento de 1 millon en presupuesto para Social_media, las ventas de la empresa aumentan en promedio 4964 dolares.

Estos resultados son mejores que los de una regresión lineal simple, y le dan a los encargados de tomar decisiones un panorama más amplio sobre las condiciones que involucran en las ventas de la empresa.

Intervalo de confianza para los coeficientes de regresión

Intervalos de confianza del 95%:

regresion %>% confint
##                    2.5 %     97.5 %
## (Intercept)  -0.33554094 0.06761484
## TV            3.55592492 3.56921433
## Radio        -0.02314501 0.01520424
## Social_media -0.04381985 0.05374789

Luego el intervalo de confianza para b1 es 3.556 ≤ b1 ≤ 3.569

La interpretación de este intervalo de confianza es: Dado el coeficiente de confianza de 95%, en 95 de cada 100 casos, los intervalos como 3.556 ≤ b1 ≤ 3.569 contendrán al verdadero valor de b1.

Región de 95% de confianza para el intercepto y coeficiente de TV

library(car)
regresion |> confidenceEllipse(levels = 0.95, fill = T, which.coef = c(1,2), col = "forestgreen")

Relación entre las ventas y el tipo de marketing

Datos con tipo de Influencer “Mega”

datosMega= filter(datos,Influencer=="Mega")
regresion2 <- lm(Sales ~ TV+Radio+Social_media,
                 data=datosMega)
summary(regresion2)
## 
## Call:
## lm(formula = Sales ~ TV + Radio + Social_media, data = datosMega)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -8.8526 -1.9198 -0.0096  2.0114  9.2229 
## 
## Coefficients:
##               Estimate Std. Error t value            Pr(>|t|)    
## (Intercept)  -0.269568   0.199983  -1.348              0.1779    
## TV            3.553604   0.006674 532.459 <0.0000000000000002 ***
## Radio         0.016643   0.019090   0.872              0.3835    
## Social_media  0.089387   0.048608   1.839              0.0662 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.884 on 1148 degrees of freedom
##   (6 observations deleted due to missingness)
## Multiple R-squared:  0.999,  Adjusted R-squared:  0.999 
## F-statistic: 3.926e+05 on 3 and 1148 DF,  p-value: < 0.00000000000000022

Sales = -0.27 + 3.55TV + 0.02Radio + 0.09Social_media + u

ajuste<- datosMega %>%
add_residuals(regresion2)
par(mfrow=c(2,2))
plot(regresion2)

Datos con tipo de Influencer “Micro”

datosMicro= filter(datos,Influencer=="Micro")
regresion3 <- lm(Sales ~ TV+Radio+Social_media,
                 data=datosMicro)
summary(regresion3)
## 
## Call:
## lm(formula = Sales ~ TV + Radio + Social_media, data = datosMicro)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -9.2724 -1.9539  0.0007  1.9265 11.2374 
## 
## Coefficients:
##               Estimate Std. Error t value            Pr(>|t|)    
## (Intercept)   0.015624   0.201827   0.077               0.938    
## TV            3.560464   0.006792 524.209 <0.0000000000000002 ***
## Radio        -0.011560   0.019620  -0.589               0.556    
## Social_media  0.027872   0.050452   0.552               0.581    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.96 on 1144 degrees of freedom
##   (5 observations deleted due to missingness)
## Multiple R-squared:  0.999,  Adjusted R-squared:  0.999 
## F-statistic: 3.86e+05 on 3 and 1144 DF,  p-value: < 0.00000000000000022

Sales = 0.02 + 3.56TV - 0.01Radio + 0.03Social_media + u

ajuste<- datosMicro %>%
add_residuals(regresion3)
par(mfrow=c(2,2))
plot(regresion3)

Datos con tipo de Influencer “Macro”

datosMacro= filter(datos,Influencer=="Macro")
regresion4 <- lm(Sales ~ TV+Radio+Social_media,
                 data=datosMacro)
summary(regresion4)
## 
## Call:
## lm(formula = Sales ~ TV + Radio + Social_media, data = datosMacro)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -10.2031  -2.0688  -0.0353   2.1497   9.6834 
## 
## Coefficients:
##               Estimate Std. Error t value            Pr(>|t|)    
## (Intercept)   0.041207   0.214502   0.192              0.8477    
## TV            3.564927   0.006869 519.019 <0.0000000000000002 ***
## Radio         0.001163   0.019828   0.059              0.9532    
## Social_media -0.104408   0.049637  -2.103              0.0357 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.986 on 1108 degrees of freedom
##   (10 observations deleted due to missingness)
## Multiple R-squared:  0.999,  Adjusted R-squared:  0.999 
## F-statistic: 3.541e+05 on 3 and 1108 DF,  p-value: < 0.00000000000000022

Sales = 0.04 + 3.56TV + 0.001Radio - 0.10Social_media + u

ajuste<- datosMacro %>%
add_residuals(regresion4)
par(mfrow=c(2,2))
plot(regresion4)

Datos con tipo de Influencer “Nano”

datosNano= filter(datos,Influencer=="Nano")
regresion5 <- lm(Sales ~ TV+Radio+Social_media,
                 data=datosNano)
summary(regresion5)
## 
## Call:
## lm(formula = Sales ~ TV + Radio + Social_media, data = datosNano)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -11.535  -1.987  -0.054   2.000  10.190 
## 
## Coefficients:
##               Estimate Std. Error t value            Pr(>|t|)    
## (Intercept)  -0.324995   0.206713  -1.572               0.116    
## TV            3.571341   0.006782 526.588 <0.0000000000000002 ***
## Radio        -0.022907   0.019715  -1.162               0.246    
## Social_media  0.009709   0.050420   0.193               0.847    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 2.964 on 1130 degrees of freedom
##   (5 observations deleted due to missingness)
## Multiple R-squared:  0.999,  Adjusted R-squared:  0.999 
## F-statistic: 3.735e+05 on 3 and 1130 DF,  p-value: < 0.00000000000000022

Sales = -0.32 + 3.57TV - 0.02Radio + 0.009Social_media + u

ajuste<- datosNano %>%
add_residuals(regresion5)
par(mfrow=c(2,2))
plot(regresion5)

Se infiere que los valores de los coeficientes varia segun el tipo de Influencer que se filtre, si bien la variacion es minima, los cambios influirian en una toma de decisiones y conocer que publico es aquel que podria brindarnos mejor resultado. Analizando los residuales se aprecia minimamente y se compara asi para los 4 tipos de Influencer en mención.

Para nuestra elección segun el análisis previo optamos por el Mega y Nano

Se cuenta con 1158 observaciones para el Influencer tipo Mega

Se cuenta con 1153 observaciones para el Influencer tipo Micro

Se cuenta con 1122 observaciones para el Influencer tipo Macro

Se cuenta con 1139 observaciones para el Influencer tipo Nano

Luiggi Bravo

LS0tDQp0aXRsZTogIlRyYWJham8gLSBBbsOhbGlzaXMgZGUgUmVncmVzacOzbiINCmF1dGhvcjogIkx1aWdnaSBCcmF2byBZYXRhY28gLSAyMDIxMTgwOSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IFRSVUUNCiAgICB0b2NfZmxvYXQ6IFRSVUUNCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9RkFMU0V9DQpybShsaXN0ID0gbHMoKSkNCmNhdCgiXDAxNCIpDQpncmFwaGljcy5vZmYoKQ0Kb3B0aW9ucyhzY2lwZW49OTk5KQ0KDQojIFBhcXVldGVzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocGFjbWFuKQ0KcF9sb2FkKHRpZHl2ZXJzZSwgcGRmdG9vbHMsIHN0cmluZ3IsIHJlYWR4bCwgdGlkeXRleHQsIHRtLCANCiAgICAgICB3b3JkY2xvdWQyLCBmb3JjYXRzLCBwYXRjaHdvcmssIHdvcmRjbG91ZCkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobW9kZWxyKQ0KbGlicmFyeSh0c2VyaWVzKQ0KbGlicmFyeShsbXRlc3QpDQpgYGANCg0KIyMgKioqUmVncmVzacOzbiBsaW5lYWwgbcO6bHRpcGxlKioqDQoNCioqRXN0aW1hY2nDs24gZGUgbG9zIGNvZWZpY2llbnRlcyBkZSByZWdyZXNpw7NuKioNCg0KYGBge3J9DQpkYXRvcyA8LSByZWFkLmNzdigidmVudGFzLmNzdiIpDQpoZWFkKGRhdG9zKQ0KYGBgDQoNCkxhIGRhdGEgY29udGllbmUgZGF0b3Mgc29icmUgbGFzIHZlbnRhcyBkZSB1bmEgY29tcGHDscOtYSB5IGxvcyBtb250b3MgYXNpZ25hZG9zIGEgcHVibGljaWRhZCBlbiBkaXN0aW50b3MgbWVkaW9zIChUViwgcmFkaW8geSByZWRlcyBzb2NpYWxlcykuDQoNClByaW1lcm8gYW5hbGl6YXJlbW9zIG1lZGlhbnRlIHVuYSByZWdyZXNpw7NuIGxpbmVhbCBzaW1wbGUgc2kgZXhpc3RlIGFsZ3VuYSByZWxhY2nDs24gZW50cmU6DQoNCioqVmFyaWFibGUgaW5kZXBlbmRpZW50ZSBYKio6IFRWIC0gUHJlc3VwdWVzdG8gZGVzaWduYWRvIGEgcHJvbW9jacOzbiBlbiBUdihtaWxsb25lcyBkZSBkw7NsYXJlcykNCg0KKipWYXJpYWJsZSBkZXBlbmRpZW50ZSBZKio6IFNhbGVzIC0gVmVudGFzIGRlIGxhIGVtcHJlc2EobWlsbG9uZXMgZGUgZMOzbGFyZXMpDQoNCmBgYHtyfQ0KWDwtZGF0b3MkVFYNClk8LWRhdG9zJFNhbGVzDQpkYXRhPC1kYXRhLmZyYW1lKFgsWSkNCmBgYA0KDQpFbXBsZWFuZG8gbGEgZnVuY2nDs24gbG0oKSBzZSBnZW5lcmEgdW4gbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIHBvciBtw61uaW1vcyBjdWFkcmFkb3MgZW4gZWwgcXVlIGxhIHZhcmlhYmxlIHJlc3B1ZXN0YSBlcyBTYWxlcyAoWSkgeSBlbCBwcmVkaWN0b3IgVFYgKFgpDQoNCmBgYHtyfQ0KbW9kZWxvIDwtIGxtKFkgfiBYLCBkYXRhPWRhdGEpDQptb2RlbG8kY29lZmZpY2llbnRzDQpgYGANCg0KRGUgZG9uZGU6IGJvID0gLTAuMTMgeSBiMSA9IDMuNTYgDQoNCkNvbiBlc3RvcyBkYXRvcywgcG9kZW1vcyBkZWNpciBxdWUgbGEgZWN1YWNpw7NuIGRlIHJlZ3Jlc2nDs24gZXN0aW1hZGEgZXM6DQoNCiAgKip5ID0gLTAuMTMgKyAzLjU2eCoqDQogIA0KICAqKlNhbGVzID0gLTAuMTMgKyAzLjU2VFYqKg0KICANCkVsIGIxID0gMy41NiBzaWduaWZpY2EgcXVlIHNpIGVsIHByZXN1cHVlc3RvIGRlc3RpbmFkbyBhIFRWIHNlICoqaW5jcmVtZW50ZSBlbiAxJSoqLCBlbnRvbmNlcyBlbiBwcm9tZWRpbyBsYXMgdmVudGFzIGRlIGxhIGVtcHJlc2EgKiphdW1lbnRhIGVuIDMuNTYgbWlsbG9uZXMgZGUgZMOzbGFyZXMqKi4NCg0KRWwgYjAgPSAtMC4xMyBubyB0aWVuZSB1biBzaWduaWZpY2FkbyByZWFsLCB5IHJlcHJlc2VudGEgc29sbyB1biBpbnRlcmNlcHRvIGRlIGxhIGVjdWFjacOzbiBkZSByZWdyZXNpw7NuLCBTaSBsYSB2YXJpYWJsZSBUViBlcyBpZ3VhbCBjZXJvLCBsYXMgdmVudGFzIGRlIGxhIGVtcHJlc2EgZXMgZGUgYjAsIGxvIGN1YWwgbm8gdGllbmUgc2VudGlkby4NCg0KDQojIyAqKipBanVzdGUgZGVsIG1vZGVsbyAtIHN1cHVlc3RvcyAtIHJlc3VsdGFkb3MqKioNCg0KU2luIGVtYmFyZ28sIGNvbnRhbW9zIGNvbiBtw6FzIGRhdG9zIHF1ZSBwdWVkZW4gc2VydmlyIHBhcmEgZXhwbGljYXIgbyBkZXRlcm1pbmFyIG1lam9yIHNpIGxhIHJlbGFjacOzbiBxdWUNCmV4aXN0ZSBlbnRyZSBsYXMgdmFyaWFibGVzIGRlIGludGVyZXMgZXMgc2lnbmlmaWNhdGl2YSBvIG5vLiBQb3IgZWxsbywgcG9kZW1vcyB1dGlsaXphciBsYXMgc2lndWllbnRlcyB2YXJpYWJsZXM6DQoNCg0KKipTYWxlcyA9IM6yMCArIM6yMVRWICsgzrIyUmFkaW8gKyDOsjNTb2NpYWxfbWVkaWEgKyB1KioNCg0KYGBge3J9DQpyZWdyZXNpb24gPC0gbG0oU2FsZXMgfiBUVitSYWRpbytTb2NpYWxfbWVkaWEsDQpkYXRhPWRhdG9zKQ0Kc3VtbWFyeShyZWdyZXNpb24pDQoNCmBgYA0KDQoNCkFudGVzIGRlIGludGVycHJldGFyIGxvcyByZXN1bHRhZG9zLCBlcyBuZWNlc2FyaW8gdmVyaWZpY2FyIGxvcyBzdXB1ZXN0b3MgZGVsIG1vZGVsbw0KDQpgYGB7cn0NCmFqdXN0ZTwtIGRhdG9zICU+JQ0KYWRkX3Jlc2lkdWFscyhyZWdyZXNpb24pDQpwYXIobWZyb3c9YygyLDIpKQ0KcGxvdChyZWdyZXNpb24pDQoNCmBgYA0KDQoNCioqRW4gbGEgcGFydGUgc3VwZXJpb3IgaXpxdWllcmRhKio6IE11ZXN0cmEgbGEgZ3LDoWZpY2EgZGUgcmVzaWR1YWxlcyBjb250cmEgbGEgdmFyaWFibGUgZXN0aW1hZGEgecuGLiBMb3MNCnJlc2lkdWFsZXMgZXN0w6FuIGRpc3BlcnNvcyBhbHJlZGVkb3IgZGVsIGNlcm8sIHNpbiBtb3N0cmFyIG5pbmfDum4gcGF0csOzbiBvIHJlbGFjacOzbiBlbnRyZSBsb3MgcmVzaWR1YWxlcw0KeSBsYSB2YXJpYWJsZSBkZXBlbmRpZW50ZSBlc3RpbWFkYSwgZW50b25jZXMgbnVlc3RybyBtb2RlbG8gZXMgYXByb3BpYWRvLg0KDQoqKkVuIGxhIHBhcnRlIHN1cGVyaW9yIGRlcmVjaGEqKjogTXVlc3RyYSBsYSBncsOhZmljYSBkZSBwcm9iYWJpbGlkYWQgbm9ybWFsLCBzaXJ2ZSBwYXJhIGNvbXByb2JhciBxdWUNCmxvcyByZXNpZHVhbGVzIHNlIGRpc3RyaWJ1eWVuIG5vcm1hbG1lbnRlIHV0aWxpemFuZG8gbG9zIHJlc2lkdWFsZXMgZXN0YW5kYXJpemFkb3MsIGxvcyByZXNpZHVhbGVzDQpmb3JtYW4gYWxnbyBwYXJlY2lkbyBhIHVuYSByZWN0YSBkZSA0NcKwLCBlbnRvbmNlcyBsb3MgcmVzaWR1YWxlcyBzb24gbm9ybWFsZXMuDQoNCioqRW4gbGEgcGFydGUgaW5mZXJpb3IgaXpxdWllcmRhKio6IE11ZXN0cmEgbGEgZ3LDoWZpY2EgZGUgbGEgcmHDrXogY3VhZHJhZGEgZGVsIHZhbG9yIGFic29sdXRvIGRlIGxvcyByZXNpZHVhbGVzDQplc3RhbmRhcml6YWRvcyBjb250cmEgbGEgdmFyaWFibGUgZGVwZW5kaWVudGUgZXN0aW1hZGEgecuGLCBsYSBjdcOhbCBzaXJ2ZSBwYXJhIGRldGVybWluYXIgc2kgbG9zIHJlc2lkdWFsZXMNCnNvbiBkZSB2YXJpYW56YSBjb25zdGFudGUsIGFsIGlndWFsIHF1ZSBsYSBwcmltZXJhIGdyw6FmaWNhLCBzZSBlbmN1ZW50cmEgcXVlIGxvcyB2YWxvcmVzIGVzdMOhbg0KZGlzcGVyc29zIHNpbiBtb3N0cmFyIG5pbmfDum4gcGF0csOzbiwgcG9yIHRhbnRvIGVsIG1vZGVsbyBlcyBhZGVjdWFkby4NCg0KKipFbiBsYSBwYXJ0ZSBpbmZlcmlvciBkZXJlY2hhKio6IE11ZXN0cmEgbGEgZ3LDoWZpY2EgZGUgZGlzdGFuY2lhIGRlIENvb2ssIGxhIGN1YWwgc2lydmUgcGFyYSBpZGVudGlmaWNhciBzaQ0KZXhpc3RlbiBhbGd1bm9zIHZhbG9yZXMgZ3JhbmRlcyBxdWUgdGVuZ2FuIHVuYSBncmFuIGluZmx1ZW5jaWEgc29icmUgbGEgZXN0aW1hY2nDs24gZGUgbG9zIGNvZWZpY2llbnRlcywNCnVuYSBncmFuIGRpc3RhbmNpYSBpbmRpY2EgcXVlIGVzYXMgb2JzZXJ2YWNpb25lcyB0aWVuZW4gdW4gZ3JhbiBwZXNvIHNvYnJlIGxhIGVzdGltYWNpw7NuLiBMYSBleGlzdGVuY2lhDQpkZSB2YWxvcmVzIGF0w61waWNvcyBzb24gdW5hIGRlIGxhcyBjYXVzYXMgZGUgaGV0ZXJvY2VkYXN0aWNpZGFkLg0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShhanVzdGUkcmVzaWQpDQpgYGANCg0KYGBge3J9DQpqYXJxdWUuYmVyYS50ZXN0KG5hLm9taXQoYWp1c3RlJHJlc2lkKSkNCmBgYA0KDQpgYGB7cn0NCmJwdGVzdChyZWdyZXNpb24pDQpgYGANCg0KDQpMb3MgcmVzdWx0YWRvcyBpbmRpY2FuIHF1ZSBsb3MgcmVzaWR1YWxlcyBzb24gbm9ybWFsZXMsIHkgc2UgdmVyaWZpY2EgcXVlIGxvcyBlcnJvcmVzIHNpIHNvbiBob21vY2Vkw6FzdGljb3MuDQoNClV0aWxpemFuZG8gbG9zIHJlc3VsdGFkb3MgZGUgbGEgcmVncmVzacOzbiwgb2JzZXJ2YW1vcyBxdWUgbGFzIHZhcmlhYmxlcyBpbmRlcGVuZGllbnRlcyBleHBsaWNhbiBlbiA5OS45JSBsYQ0KdmFyaWFjacOzbiBkZSBsYXMgdmVudGFzIGRlIGxhIGVtcHJlc2EgZXN0YW5kYXJpemFkYXMsIGVsIGVzdGFkw61zdGljbyBGIHRhbWJpw6luIGluZGljYSBxdWUgZWwgbW9kZWxvDQplcyBzaWduaWZpY2F0aXZvLCBwdWVzIGVuIGNvbmp1bnRvIGxvcyBjb2VmaWNpZW50ZXMgc29uIGRpc3RpbnRvcyBkZSBjZXJvLiBMYSB2YXJpYWJsZSBkZSBpbnRlcsOpcyAoVFYpIGVzDQpwb3NpdGl2YSB5IHNpZ25pZmljYXRpdmEsIGVzIGRlY2lyLCBhdW1lbnRhciBlbCBwcmVzdXB1ZXN0byBkZXN0aW5hZG8gYSBUViwgYXVtZW50YSBsYXMgdmVudGFzIGRlIGxhIGVtcHJlc2EsIGxhIHZhcmlhYmxlIGVzIHNpZ25pZmljYXRpdmEgYWwgMTAwJS4gQXVtZW50YXIgZWwgcHJlc3VwdWVzdG8gZGVzdGluYWRvIGEgVFYgZW4gMSBtaWxsb24sIGluZGljYSBxdWUgbGFzIHZlbnRhcyBwcm9tZWRpbyBkZSBsYSBlbXByZXNhIGF1bWVudGEgMy41NiBtaWxsb25lcyBlbiBwcm9tZWRpby4NCg0KRWwgcmVzdG8gZGUgbGFzIHZhcmlhYmxlcyByZXN1bHRhcm9uIHBvY28gc2lnbmlmaWNhdGl2YXMsIGVzIG1pbmltbyBlbCBlZmVjdG8gcXVlIGNhdXNhIHNvYnJlIGxhcyB2ZW50YXMgZGUgbGEgZW1wcmVzYS4NCg0KRGljaG8gZGUgb3RyYSBmb3JtYSwgc2kgbGFzIGF1dG9yaWRhZGVzIGRlIGxhIGNvbXBhw7FpYSBkZXNlYW4gYXVtZW50YXIgbGFzIHZlbnRhcyBkZSBsYSBlbXByZXNhLCBuZWNlc2l0YW4gdG9tYXIgZW4gY3VlbnRhIGxhcyB2YXJpYWJsZXMgcXVlIHNvbiBzaWduaWZpY2F0aXZhcywgZXN0YSBjbGFybyBxdWUgbGEgaW52ZXJzaW9uIGEgcHJlc3VwdWVzdG8gZW4gVHYgc2VyaWEgbGEgbcOhcyByZW50YWJsZS4NCk5vdGEgcXVlIGVzIG5lY2VzYXJpbyB0ZW5lciBlbiBjdWVudGEgbGFzIHVuaWRhZGVzIGRlIGxhIG1lZGlkYQ0KZGUgbGEgdmFyaWFibGUgZGVwZW5kaWVudGUgeSBsYXMgaW5kZXBlbmRpZW50ZToNCg0KRW4gbGEgKip2YXJpYWJsZSBSYWRpbyoqIC0gdW4gYXVtZW50byBkZSAxIG1pbGxvbiBlbiBwcmVzdXB1ZXN0byBwYXJhIFJhZGlvLCBsYXMgdmVudGFzIGRlIGxhIGVtcHJlc2EgZGlzbWludXllbiBlbiBwcm9tZWRpbyAzOTcwIGRvbGFyZXMNCg0KRW4gbGEgKip2YXJpYWJsZSBTb2NpYWxfbWVkaWEqKiAtIHVuIGF1bWVudG8gZGUgMSBtaWxsb24gZW4gcHJlc3VwdWVzdG8gcGFyYSBTb2NpYWxfbWVkaWEsIGxhcyB2ZW50YXMgZGUgbGEgZW1wcmVzYSBhdW1lbnRhbiBlbiBwcm9tZWRpbyA0OTY0IGRvbGFyZXMuDQoNCkVzdG9zIHJlc3VsdGFkb3Mgc29uIG1lam9yZXMgcXVlIGxvcyBkZSB1bmEgcmVncmVzacOzbiBsaW5lYWwgc2ltcGxlLCB5IGxlIGRhbiBhIGxvcyBlbmNhcmdhZG9zIGRlIHRvbWFyIGRlY2lzaW9uZXMgdW4gcGFub3JhbWEgbcOhcyBhbXBsaW8gc29icmUgbGFzIGNvbmRpY2lvbmVzIHF1ZSBpbnZvbHVjcmFuIGVuIGxhcyB2ZW50YXMgZGUgbGEgZW1wcmVzYS4NCg0KIyMgKipJbnRlcnZhbG8gZGUgY29uZmlhbnphIHBhcmEgbG9zIGNvZWZpY2llbnRlcyBkZSByZWdyZXNpw7NuKioNCg0KSW50ZXJ2YWxvcyBkZSBjb25maWFuemEgZGVsIDk1JToNCg0KYGBge3J9DQpyZWdyZXNpb24gJT4lIGNvbmZpbnQNCmBgYA0KDQpMdWVnbyBlbCBpbnRlcnZhbG8gZGUgY29uZmlhbnphIHBhcmEgYjEgZXMgMy41NTYg4omkIGIxIOKJpCAzLjU2OQ0KDQpMYSBpbnRlcnByZXRhY2nDs24gZGUgZXN0ZSBpbnRlcnZhbG8gZGUgY29uZmlhbnphIGVzOiBEYWRvIGVsIGNvZWZpY2llbnRlIGRlIGNvbmZpYW56YSBkZSA5NSUsIGVuIDk1IGRlIGNhZGEgMTAwIGNhc29zLCBsb3MgaW50ZXJ2YWxvcyBjb21vIDMuNTU2IOKJpCBiMSDiiaQgMy41NjkgY29udGVuZHLDoW4gYWwgdmVyZGFkZXJvIHZhbG9yIGRlIGIxLg0KDQoNCg0KUmVnacOzbiBkZSA5NSUgZGUgY29uZmlhbnphIHBhcmEgZWwgaW50ZXJjZXB0byB5IGNvZWZpY2llbnRlIGRlIFRWDQoNCmBgYHtyfQ0KbGlicmFyeShjYXIpDQpyZWdyZXNpb24gfD4gY29uZmlkZW5jZUVsbGlwc2UobGV2ZWxzID0gMC45NSwgZmlsbCA9IFQsIHdoaWNoLmNvZWYgPSBjKDEsMiksIGNvbCA9ICJmb3Jlc3RncmVlbiIpDQpgYGANCg0KDQojIyAqKlJlbGFjacOzbiBlbnRyZSBsYXMgdmVudGFzIHkgZWwgdGlwbyBkZSBtYXJrZXRpbmcqKg0KDQoNCiMjIyAqKkRhdG9zIGNvbiB0aXBvIGRlIEluZmx1ZW5jZXIgIk1lZ2EiKioNCmBgYHtyfQ0KZGF0b3NNZWdhPSBmaWx0ZXIoZGF0b3MsSW5mbHVlbmNlcj09Ik1lZ2EiKQ0KcmVncmVzaW9uMiA8LSBsbShTYWxlcyB+IFRWK1JhZGlvK1NvY2lhbF9tZWRpYSwNCiAgICAgICAgICAgICAgICAgZGF0YT1kYXRvc01lZ2EpDQpzdW1tYXJ5KHJlZ3Jlc2lvbjIpDQpgYGANCg0KDQoqKlNhbGVzID0gLTAuMjcgKyAzLjU1VFYgKyAwLjAyUmFkaW8gKyAwLjA5U29jaWFsX21lZGlhICsgdSoqDQoNCmBgYHtyfQ0KYWp1c3RlPC0gZGF0b3NNZWdhICU+JQ0KYWRkX3Jlc2lkdWFscyhyZWdyZXNpb24yKQ0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QocmVncmVzaW9uMikNCmBgYA0KDQoNCiMjIyAqKkRhdG9zIGNvbiB0aXBvIGRlIEluZmx1ZW5jZXIgIk1pY3JvIioqDQpgYGB7cn0NCmRhdG9zTWljcm89IGZpbHRlcihkYXRvcyxJbmZsdWVuY2VyPT0iTWljcm8iKQ0KcmVncmVzaW9uMyA8LSBsbShTYWxlcyB+IFRWK1JhZGlvK1NvY2lhbF9tZWRpYSwNCiAgICAgICAgICAgICAgICAgZGF0YT1kYXRvc01pY3JvKQ0Kc3VtbWFyeShyZWdyZXNpb24zKQ0KYGBgDQoNCg0KKipTYWxlcyA9IDAuMDIgKyAzLjU2VFYgLSAwLjAxUmFkaW8gKyAwLjAzU29jaWFsX21lZGlhICsgdSoqDQoNCmBgYHtyfQ0KYWp1c3RlPC0gZGF0b3NNaWNybyAlPiUNCmFkZF9yZXNpZHVhbHMocmVncmVzaW9uMykNCnBhcihtZnJvdz1jKDIsMikpDQpwbG90KHJlZ3Jlc2lvbjMpDQpgYGANCg0KDQoNCiMjIyAqKkRhdG9zIGNvbiB0aXBvIGRlIEluZmx1ZW5jZXIgIk1hY3JvIioqDQpgYGB7cn0NCmRhdG9zTWFjcm89IGZpbHRlcihkYXRvcyxJbmZsdWVuY2VyPT0iTWFjcm8iKQ0KcmVncmVzaW9uNCA8LSBsbShTYWxlcyB+IFRWK1JhZGlvK1NvY2lhbF9tZWRpYSwNCiAgICAgICAgICAgICAgICAgZGF0YT1kYXRvc01hY3JvKQ0Kc3VtbWFyeShyZWdyZXNpb240KQ0KYGBgDQoNCg0KKipTYWxlcyA9IDAuMDQgKyAzLjU2VFYgKyAwLjAwMVJhZGlvIC0gMC4xMFNvY2lhbF9tZWRpYSArIHUqKg0KDQpgYGB7cn0NCmFqdXN0ZTwtIGRhdG9zTWFjcm8gJT4lDQphZGRfcmVzaWR1YWxzKHJlZ3Jlc2lvbjQpDQpwYXIobWZyb3c9YygyLDIpKQ0KcGxvdChyZWdyZXNpb240KQ0KYGBgDQoNCg0KIyMjICoqRGF0b3MgY29uIHRpcG8gZGUgSW5mbHVlbmNlciAiTmFubyIqKg0KYGBge3J9DQpkYXRvc05hbm89IGZpbHRlcihkYXRvcyxJbmZsdWVuY2VyPT0iTmFubyIpDQpyZWdyZXNpb241IDwtIGxtKFNhbGVzIH4gVFYrUmFkaW8rU29jaWFsX21lZGlhLA0KICAgICAgICAgICAgICAgICBkYXRhPWRhdG9zTmFubykNCnN1bW1hcnkocmVncmVzaW9uNSkNCmBgYA0KDQoNCioqU2FsZXMgPSAtMC4zMiArIDMuNTdUViAtIDAuMDJSYWRpbyArIDAuMDA5U29jaWFsX21lZGlhICsgdSoqDQoNCmBgYHtyfQ0KYWp1c3RlPC0gZGF0b3NOYW5vICU+JQ0KYWRkX3Jlc2lkdWFscyhyZWdyZXNpb241KQ0KcGFyKG1mcm93PWMoMiwyKSkNCnBsb3QocmVncmVzaW9uNSkNCmBgYA0KDQoNCioqU2UgaW5maWVyZSBxdWUgbG9zIHZhbG9yZXMgZGUgbG9zIGNvZWZpY2llbnRlcyB2YXJpYSBzZWd1biBlbCB0aXBvIGRlIEluZmx1ZW5jZXIgcXVlIHNlIGZpbHRyZSwgc2kgYmllbiBsYSB2YXJpYWNpb24gZXMgbWluaW1hLCBsb3MgY2FtYmlvcyBpbmZsdWlyaWFuIGVuIHVuYSB0b21hIGRlIGRlY2lzaW9uZXMgeSBjb25vY2VyIHF1ZSBwdWJsaWNvIGVzIGFxdWVsIHF1ZSBwb2RyaWEgYnJpbmRhcm5vcyBtZWpvciByZXN1bHRhZG8uIEFuYWxpemFuZG8gbG9zIHJlc2lkdWFsZXMgc2UgYXByZWNpYSBtaW5pbWFtZW50ZSB5IHNlIGNvbXBhcmEgYXNpIHBhcmEgbG9zIDQgdGlwb3MgZGUgSW5mbHVlbmNlciBlbiBtZW5jacOzbi4qKg0KDQoqKlBhcmEgbnVlc3RyYSBlbGVjY2nDs24gc2VndW4gZWwgYW7DoWxpc2lzIHByZXZpbyBvcHRhbW9zIHBvciBlbCBNZWdhIHkgTmFubyoqDQoNCioqU2UgY3VlbnRhIGNvbiAxMTU4IG9ic2VydmFjaW9uZXMgcGFyYSBlbCBJbmZsdWVuY2VyIHRpcG8gTWVnYSoqDQoNCioqU2UgY3VlbnRhIGNvbiAxMTUzIG9ic2VydmFjaW9uZXMgcGFyYSBlbCBJbmZsdWVuY2VyIHRpcG8gTWljcm8qKg0KDQoqKlNlIGN1ZW50YSBjb24gMTEyMiBvYnNlcnZhY2lvbmVzIHBhcmEgZWwgSW5mbHVlbmNlciB0aXBvIE1hY3JvKioNCg0KKipTZSBjdWVudGEgY29uIDExMzkgb2JzZXJ2YWNpb25lcyBwYXJhIGVsIEluZmx1ZW5jZXIgdGlwbyBOYW5vKioNCg0KDQoNCkx1aWdnaSBCcmF2byBbMjAyMTE4MDlcQGxhbW9saW5hLmVkdS5wZV0obWFpbHRvOjIwMjExODA5QGxhbW9saW5hLmVkdS5wZSl7LmVtYWlsfQ0KDQoNCjxkaXYgY2xhc3M9InRvY2lmeS1leHRlbmQtcGFnZSIgZGF0YS11bmlxdWU9InRvY2lmeS1leHRlbmQtcGFnZSIgc3R5bGU9ImhlaWdodDowOyI+PC9kaXY+DQo=