Macroeconimia II
Sebastián Alonso Sosa Pérez

Modelos de Regresión

Creado: 13-12-2020

En el siguiente post se vera como podemos descargar datos directamente del BCRP usando el Web Scraping y posteriormente se usara los difrenetes algoritmos de regresión los cuales son:

  • Regresión lineal simple.
  • Regresión polinomial.
  • Maquinas de soporte vectorial para regresión (SVR).
  • Arboles de desicion.
  • Bosques aleatorios.

Además se vera como corregir la autocorrelación en la parte final.

1 Web Scraping

1.1 Paquetes a utilizar

ipak <- function(pkg){
  new.pkg <- pkg[!(pkg %in% installed.packages()[, "Package"])]
  if (length(new.pkg)) 
    install.packages(new.pkg, dependencies = TRUE)
  sapply(pkg, require, character.only = TRUE)
}
packages <- c("tidyverse","data.table", "XML","httr","xts")
ipak(packages)

1.2 Función de extracción

extraccion<- function(codigo=NULL,start=NULL,end=NULL){
  vector<- vector()
  datos<- NULL
  for(i in 1:length(codigo)){
                               ex<-  paste0("https://estadisticas.bcrp.gob.pe/estadisticas/series/api/", 
                                                       codigo[i], "/xml/",start,"/",end)
                               
  
                               ObjXML <- httr::GET(ex)
                               L_parseXML <- xmlParse(ObjXML)
                              
                               L_XML <- xmlToList(L_parseXML)
                               
                               dt_BCRP <- data.table::data.table()
                               for (a in 1:length(L_XML$periods)){
                                                                   dt_temp <- data.table(
                                                                                         serie= L_XML$periods[[a]]$v)
                                                                   dt_BCRP <- rbind(dt_BCRP,dt_temp)
                               }
                               vector[i]<- dt_BCRP[,serie:=as.numeric(serie)] 
  }
  for(i in  1: length(codigo)){
    datos<- cbind(datos,vector[[i]])
  }
  datos<- as.data.frame(datos)
  names(datos)<- codigo
  return(datos)
  }

1.2.1 Prueba de la función

datos<-extraccion(c("PN01488BM","PN01210PM" ),"2000-1","2007-2")
names(datos)<- c("Exportaciones","Tipo_de_cambio")
attach(datos)

1.2.1.1 Represenrtación de los resultados

datos  %>%round(digits = 2) %>% DT::datatable()

2 Analísis de Regresión

2.1 Regresión Simple

datos=datos
modelo_r<- lm(Exportaciones~Tipo_de_cambio,data = datos)
linea<- predict(modelo_r,datos)    
a1<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
      geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
                                             y=linea))+theme_minimal()+
   xlab("Tipo de cambio")+labs(title ="Regresión lineal")
E_c_M_1= (Exportaciones-linea)^2 %>% mean()
a1

2.2 Regresión polinomial

modelo_r<- lm(Exportaciones~poly(Tipo_de_cambio,2),data = datos)
    linea_1<- predict(modelo_r,datos)    
    a2<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
      geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
                                                      y=linea_1))+theme_minimal()+
      xlab("Tipo de cambio")+labs(title ="Regresión polinomica")
    E_c_M_2= (Exportaciones-linea_1)^2 %>% mean()
a2    

2.3 Maquinas de soporte vectorial

library(e1071)
    modelo_r<- svm(Exportaciones~Tipo_de_cambio,data = datos)
    linea_2<- predict(modelo_r,datos)    
    a3<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
      geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
                                                      y=linea_2))+theme_minimal()+
    xlab("Tipo de cambio")+labs(title ="Maquina de soporte vectorial")
    
    E_c_M_3= (Exportaciones-linea_2)^2 %>% mean()
a3

2.4 Arboles de decisión

library(rpart)
    modelo_r<- rpart(Exportaciones~Tipo_de_cambio,data = datos)
    linea_3<- predict(modelo_r,datos)    
    a4<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
      geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
                                                      y=linea_3))+theme_minimal()+
      xlab("Tipo de cambio")+labs(title ="Arboles de desición")
    E_c_M_4= mean((Exportaciones-linea_3)^2)
  a4

2.5 Bosques aleatorios

# library(randomForest)
    modelo_r<- randomForest(Exportaciones~Tipo_de_cambio,data = datos)
    linea_4<- predict(modelo_r,datos)    
    a5<-ggplot(datos,mapping = aes(y=Exportaciones,x=Tipo_de_cambio))+
      geom_point(color="red")+geom_line(mapping = aes(x=Tipo_de_cambio,
                                                      y=linea_4))+theme_minimal()+
      xlab("Tipo de cambio")+labs(title ="Bosques Aleatorios")
    E_c_M_5= (Exportaciones-linea_4)^2 %>% mean()    
a5

2.6 Elección del mejor modelo

Nota: El mejor modelo es en el cual se aplico el metódo de Random forest pues presente un menor \(R^2\).

3 Corrección de la autocorrelación

Para ver si presenta autocorrelación usamos el test de durwin watson que nos permite ver si se presenta esto. Para corregirla se presenta las siguientes funciones.

3.1 Uso de la prueba de autocorrelación

modelo_r<- lm(Exportaciones~Tipo_de_cambio,data = datos)
summary(modelo_r)
## 
## Call:
## lm(formula = Exportaciones ~ Tipo_de_cambio, data = datos)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -536.5 -200.2  -24.1  190.2 1006.0 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)     14778.8      949.9   15.56   <2e-16 ***
## Tipo_de_cambio  -4021.5      277.7  -14.48   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 286.6 on 84 degrees of freedom
## Multiple R-squared:  0.714,  Adjusted R-squared:  0.7106 
## F-statistic: 209.7 on 1 and 84 DF,  p-value: < 2.2e-16
b<- modelo_r$residuals
acf(b)

pacf(b)

Resultado: podemos ver que de forma gráfica se presenta autocorrelación

Ahora aplicamos una prueba formal

lmtest::dwtest(modelo_r) 
## 
##  Durbin-Watson test
## 
## data:  modelo_r
## DW = 0.5182, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0

Podemos ver que el DW calculado es mayor a lo permitido así que podemos deducir que si presenta autocorrelación

3.2 Corrección

3.2.1 Agregando un resago

library(dynlm)      
modelo_a<- dynlm(Exportaciones~Tipo_de_cambio+L(Exportaciones))      
summary(modelo_a)
## Warning in summary.lm(modelo_a): essentially perfect fit: summary may be
## unreliable
## 
## Time series regression with "numeric" data:
## Start = 1, End = 86
## 
## Call:
## dynlm(formula = Exportaciones ~ Tipo_de_cambio + L(Exportaciones))
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -1.073e-13 -2.086e-14 -9.510e-15 -6.000e-17  7.833e-13 
## 
## Coefficients:
##                    Estimate Std. Error    t value Pr(>|t|)    
## (Intercept)       6.417e-12  5.901e-13  1.087e+01   <2e-16 ***
## Tipo_de_cambio   -1.762e-12  1.637e-13 -1.076e+01   <2e-16 ***
## L(Exportaciones)  1.000e+00  3.440e-17  2.907e+16   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 9.038e-14 on 83 degrees of freedom
## Multiple R-squared:      1,  Adjusted R-squared:      1 
## F-statistic: 1.477e+33 on 2 and 83 DF,  p-value: < 2.2e-16
c<- modelo_a$residuals

Analizando los resultados:

acf(c)

pacf(c)

lmtest::dwtest(modelo_a) 
## 
##  Durbin-Watson test
## 
## data:  modelo_a
## DW = 2.0655, p-value = 0.5445
## alternative hypothesis: true autocorrelation is greater than 0

Nota: Ahora este indicador se aproxima a 2 así que podemos decir que no presenta acutocrrelación.

3.2.2 Algortimo de ourcurt

library(orcutt)      
## Loading required package: lmtest
cor<-cochrane.orcutt(modelo_r)
summary.orcutt(cor)
## Call:
## lm(formula = Exportaciones ~ Tipo_de_cambio, data = datos)
## 
##                Estimate Std. Error t value Pr(>|t|)
## (Intercept)     1021.77    2150.97   0.475   0.6360
## Tipo_de_cambio   137.68     629.46   0.219   0.8274
## 
## Residual standard error: 165.273 on 83 degrees of freedom
## Multiple R-squared:  6e-04 ,  Adjusted R-squared:  -0.0115
## F-statistic: 0 on 1 and 83 DF,  p-value: < 8.274e-01
## 
## Durbin-Watson statistic 
## (original):    0.51820 , p-value: 1.866e-17
## (transformed): 2.77543 , p-value: 9.999e-01
LS0tDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgICNjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCjxjZW50ZXI+DQohW10oZG93bmxvYWQuanBnKQ0KPC9jZW50ZXI+DQo8Y2VudGVyPg0KICAgIDxiPk1hY3JvZWNvbmltaWEgSUk8L2I+PGJyPg0KICAgIDxiPlNlYmFzdGnDoW4gQWxvbnNvIFNvc2EgUMOpcmV6PC9iPg0KPGJyPg0KPGgxPk1vZGVsb3MgZGUgUmVncmVzacOzbjwvaDE+DQo8L2NlbnRlcj4NCjxjZW50ZXI+DQo8aT5DcmVhZG86ICAgICAxMy0xMi0yMDIwIA0KPC9jZW50ZXI+DQoNCkVuIGVsIHNpZ3VpZW50ZSBwb3N0IHNlIHZlcmEgY29tbyBwb2RlbW9zIGRlc2NhcmdhciBkYXRvcyBkaXJlY3RhbWVudGUgZGVsICoqQkNSUCoqIHVzYW5kbyBlbCAqKldlYiBTY3JhcGluZyoqIHkgcG9zdGVyaW9ybWVudGUgc2UgdXNhcmEgbG9zIGRpZnJlbmV0ZXMgYWxnb3JpdG1vcyBkZSByZWdyZXNpw7NuIGxvcyBjdWFsZXMgc29uOiANCg0KKiBSZWdyZXNpw7NuIGxpbmVhbCBzaW1wbGUuDQoqIFJlZ3Jlc2nDs24gcG9saW5vbWlhbC4gDQoqIE1hcXVpbmFzIGRlIHNvcG9ydGUgdmVjdG9yaWFsIHBhcmEgcmVncmVzacOzbiAoU1ZSKS4NCiogQXJib2xlcyBkZSBkZXNpY2lvbi4NCiogQm9zcXVlcyBhbGVhdG9yaW9zLg0KDQpBZGVtw6FzIHNlIHZlcmEgY29tbyBjb3JyZWdpciBsYSBhdXRvY29ycmVsYWNpw7NuIGVuIGxhIHBhcnRlIGZpbmFsLiANCg0KIyBXZWIgU2NyYXBpbmcNCg0KIyMgUGFxdWV0ZXMgYSB1dGlsaXphciANCg0KYGBge3IsZXZhbD1GQUxTRX0NCmlwYWsgPC0gZnVuY3Rpb24ocGtnKXsNCiAgbmV3LnBrZyA8LSBwa2dbIShwa2cgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKVssICJQYWNrYWdlIl0pXQ0KICBpZiAobGVuZ3RoKG5ldy5wa2cpKSANCiAgICBpbnN0YWxsLnBhY2thZ2VzKG5ldy5wa2csIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogIHNhcHBseShwa2csIHJlcXVpcmUsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCn0NCnBhY2thZ2VzIDwtIGMoInRpZHl2ZXJzZSIsImRhdGEudGFibGUiLCAiWE1MIiwiaHR0ciIsInh0cyIpDQppcGFrKHBhY2thZ2VzKQ0KYGBgDQoNCiMjIEZ1bmNpw7NuIGRlIGV4dHJhY2Npw7NuDQoNCmBgYHtyLGV2YWw9RkFMU0V9DQoNCmV4dHJhY2Npb248LSBmdW5jdGlvbihjb2RpZ289TlVMTCxzdGFydD1OVUxMLGVuZD1OVUxMKXsNCiAgdmVjdG9yPC0gdmVjdG9yKCkNCiAgZGF0b3M8LSBOVUxMDQogIGZvcihpIGluIDE6bGVuZ3RoKGNvZGlnbykpew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4PC0gIHBhc3RlMCgiaHR0cHM6Ly9lc3RhZGlzdGljYXMuYmNycC5nb2IucGUvZXN0YWRpc3RpY2FzL3Nlcmllcy9hcGkvIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29kaWdvW2ldLCAiL3htbC8iLHN0YXJ0LCIvIixlbmQpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9ialhNTCA8LSBodHRyOjpHRVQoZXgpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTF9wYXJzZVhNTCA8LSB4bWxQYXJzZShPYmpYTUwpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMX1hNTCA8LSB4bWxUb0xpc3QoTF9wYXJzZVhNTCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF9CQ1JQIDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUoKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoYSBpbiAxOmxlbmd0aChMX1hNTCRwZXJpb2RzKSl7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfdGVtcCA8LSBkYXRhLnRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZT0gTF9YTUwkcGVyaW9kc1tbYV1dJHYpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfQkNSUCA8LSByYmluZChkdF9CQ1JQLGR0X3RlbXApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY3RvcltpXTwtIGR0X0JDUlBbLHNlcmllOj1hcy5udW1lcmljKHNlcmllKV0gDQogIH0NCiAgZm9yKGkgaW4gIDE6IGxlbmd0aChjb2RpZ28pKXsNCiAgICBkYXRvczwtIGNiaW5kKGRhdG9zLHZlY3RvcltbaV1dKQ0KICB9DQogIGRhdG9zPC0gYXMuZGF0YS5mcmFtZShkYXRvcykNCiAgbmFtZXMoZGF0b3MpPC0gY29kaWdvDQogIHJldHVybihkYXRvcykNCiAgfQ0KYGBgDQoNCiMjIyBQcnVlYmEgZGUgbGEgZnVuY2nDs24gDQoNCmBgYHtyLGV2YWw9RkFMU0V9DQpkYXRvczwtZXh0cmFjY2lvbihjKCJQTjAxNDg4Qk0iLCJQTjAxMjEwUE0iICksIjIwMDAtMSIsIjIwMDctMiIpDQpuYW1lcyhkYXRvcyk8LSBjKCJFeHBvcnRhY2lvbmVzIiwiVGlwb19kZV9jYW1iaW8iKQ0KYXR0YWNoKGRhdG9zKQ0KYGBgDQoNCiMjIyMgUmVwcmVzZW5ydGFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcyANCg0KYGBge3IsZWNobz1GQUxTRSx3YXJuaW5nPVRSVUUsbWVzc2FnZT1UUlVFLGluY2x1ZGU9RkFMU0V9DQppcGFrIDwtIGZ1bmN0aW9uKHBrZyl7DQogIG5ldy5wa2cgPC0gcGtnWyEocGtnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLCAiUGFja2FnZSJdKV0NCiAgaWYgKGxlbmd0aChuZXcucGtnKSkgDQogICAgaW5zdGFsbC5wYWNrYWdlcyhuZXcucGtnLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICBzYXBwbHkocGtnLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQp9DQpwYWNrYWdlcyA8LSBjKCJ0aWR5dmVyc2UiLCJkYXRhLnRhYmxlIiwgIlhNTCIsImh0dHIiLCJ4dHMiKQ0KaXBhayhwYWNrYWdlcykNCmV4dHJhY2Npb248LSBmdW5jdGlvbihjb2RpZ289TlVMTCxzdGFydD1OVUxMLGVuZD1OVUxMKXsNCiAgdmVjdG9yPC0gdmVjdG9yKCkNCiAgZGF0b3M8LSBOVUxMDQogIGZvcihpIGluIDE6bGVuZ3RoKGNvZGlnbykpew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4PC0gIHBhc3RlMCgiaHR0cHM6Ly9lc3RhZGlzdGljYXMuYmNycC5nb2IucGUvZXN0YWRpc3RpY2FzL3Nlcmllcy9hcGkvIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29kaWdvW2ldLCAiL3htbC8iLHN0YXJ0LCIvIixlbmQpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9ialhNTCA8LSBodHRyOjpHRVQoZXgpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTF9wYXJzZVhNTCA8LSB4bWxQYXJzZShPYmpYTUwpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMX1hNTCA8LSB4bWxUb0xpc3QoTF9wYXJzZVhNTCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF9CQ1JQIDwtIGRhdGEudGFibGU6OmRhdGEudGFibGUoKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoYSBpbiAxOmxlbmd0aChMX1hNTCRwZXJpb2RzKSl7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfdGVtcCA8LSBkYXRhLnRhYmxlKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZT0gTF9YTUwkcGVyaW9kc1tbYV1dJHYpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfQkNSUCA8LSByYmluZChkdF9CQ1JQLGR0X3RlbXApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlY3RvcltpXTwtIGR0X0JDUlBbLHNlcmllOj1hcy5udW1lcmljKHNlcmllKV0gDQogIH0NCiAgZm9yKGkgaW4gIDE6IGxlbmd0aChjb2RpZ28pKXsNCiAgICBkYXRvczwtIGNiaW5kKGRhdG9zLHZlY3RvcltbaV1dKQ0KICB9DQogIGRhdG9zPC0gYXMuZGF0YS5mcmFtZShkYXRvcykNCiAgbmFtZXMoZGF0b3MpPC0gY29kaWdvDQogIHJldHVybihkYXRvcykNCiAgfQ0KZGF0b3M8LWV4dHJhY2Npb24oYygiUE4wMTQ4OEJNIiwiUE4wMTIxMFBNIiApLCIyMDAwLTEiLCIyMDA3LTIiKQ0KbmFtZXMoZGF0b3MpPC0gYygiRXhwb3J0YWNpb25lcyIsIlRpcG9fZGVfY2FtYmlvIikNCmF0dGFjaChkYXRvcykNCg0KYGBgDQpgYGB7cn0NCmRhdG9zICAlPiVyb3VuZChkaWdpdHMgPSAyKSAlPiUgRFQ6OmRhdGF0YWJsZSgpDQpgYGANCg0KDQojIEFuYWzDrXNpcyBkZSBSZWdyZXNpw7NuIA0KDQojIyBSZWdyZXNpw7NuIFNpbXBsZSANCg0KDQpgYGB7cixlY2hvPUZBTFNFLHdhcm5pbmc9VFJVRSxpbmNsdWRlPUZBTFNFfQ0KaXBhayA8LSBmdW5jdGlvbihwa2cpew0KICBuZXcucGtnIDwtIHBrZ1shKHBrZyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpWywgIlBhY2thZ2UiXSldDQogIGlmIChsZW5ndGgobmV3LnBrZykpIA0KICAgIGluc3RhbGwucGFja2FnZXMobmV3LnBrZywgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgc2FwcGx5KHBrZywgcmVxdWlyZSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQ0KfQ0KcGFja2FnZXMgPC0gYygidGlkeXZlcnNlIiwiZGF0YS50YWJsZSIsICJYTUwiLCJodHRyIiwieHRzIikNCmlwYWsocGFja2FnZXMpDQpleHRyYWNjaW9uPC0gZnVuY3Rpb24oY29kaWdvPU5VTEwsc3RhcnQ9TlVMTCxlbmQ9TlVMTCl7DQogIHZlY3RvcjwtIHZlY3RvcigpDQogIGRhdG9zPC0gTlVMTA0KICBmb3IoaSBpbiAxOmxlbmd0aChjb2RpZ28pKXsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleDwtICBwYXN0ZTAoImh0dHBzOi8vZXN0YWRpc3RpY2FzLmJjcnAuZ29iLnBlL2VzdGFkaXN0aWNhcy9zZXJpZXMvYXBpLyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvZGlnb1tpXSwgIi94bWwvIixzdGFydCwiLyIsZW5kKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBPYmpYTUwgPC0gaHR0cjo6R0VUKGV4KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExfcGFyc2VYTUwgPC0geG1sUGFyc2UoT2JqWE1MKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTF9YTUwgPC0geG1sVG9MaXN0KExfcGFyc2VYTUwpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHRfQkNSUCA8LSBkYXRhLnRhYmxlOjpkYXRhLnRhYmxlKCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGEgaW4gMTpsZW5ndGgoTF9YTUwkcGVyaW9kcykpew0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0X3RlbXAgPC0gZGF0YS50YWJsZSgNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWU9IExfWE1MJHBlcmlvZHNbW2FdXSR2KQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0X0JDUlAgPC0gcmJpbmQoZHRfQkNSUCxkdF90ZW1wKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZWN0b3JbaV08LSBkdF9CQ1JQWyxzZXJpZTo9YXMubnVtZXJpYyhzZXJpZSldIA0KICB9DQogIGZvcihpIGluICAxOiBsZW5ndGgoY29kaWdvKSl7DQogICAgZGF0b3M8LSBjYmluZChkYXRvcyx2ZWN0b3JbW2ldXSkNCiAgfQ0KICBkYXRvczwtIGFzLmRhdGEuZnJhbWUoZGF0b3MpDQogIG5hbWVzKGRhdG9zKTwtIGNvZGlnbw0KICByZXR1cm4oZGF0b3MpDQogIH0NCmRhdG9zPC1leHRyYWNjaW9uKGMoIlBOMDE0ODhCTSIsIlBOMDEyMTBQTSIgKSwiMjAwMC0xIiwiMjAwNy0yIikNCm5hbWVzKGRhdG9zKTwtIGMoIkV4cG9ydGFjaW9uZXMiLCJUaXBvX2RlX2NhbWJpbyIpDQphdHRhY2goZGF0b3MpDQpgYGANCg0KYGBge3J9DQpkYXRvcz1kYXRvcw0KbW9kZWxvX3I8LSBsbShFeHBvcnRhY2lvbmVzflRpcG9fZGVfY2FtYmlvLGRhdGEgPSBkYXRvcykNCmxpbmVhPC0gcHJlZGljdChtb2RlbG9fcixkYXRvcykgICAgDQphMTwtZ2dwbG90KGRhdG9zLG1hcHBpbmcgPSBhZXMoeT1FeHBvcnRhY2lvbmVzLHg9VGlwb19kZV9jYW1iaW8pKSsNCiAgICAgIGdlb21fcG9pbnQoY29sb3I9InJlZCIpK2dlb21fbGluZShtYXBwaW5nID0gYWVzKHg9VGlwb19kZV9jYW1iaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWxpbmVhKSkrdGhlbWVfbWluaW1hbCgpKw0KICAgeGxhYigiVGlwbyBkZSBjYW1iaW8iKStsYWJzKHRpdGxlID0iUmVncmVzacOzbiBsaW5lYWwiKQ0KRV9jX01fMT0gKEV4cG9ydGFjaW9uZXMtbGluZWEpXjIgJT4lIG1lYW4oKQ0KYTENCmBgYA0KDQoNCiMjIFJlZ3Jlc2nDs24gcG9saW5vbWlhbA0KDQpgYGB7cn0NCm1vZGVsb19yPC0gbG0oRXhwb3J0YWNpb25lc35wb2x5KFRpcG9fZGVfY2FtYmlvLDIpLGRhdGEgPSBkYXRvcykNCiAgICBsaW5lYV8xPC0gcHJlZGljdChtb2RlbG9fcixkYXRvcykgICAgDQogICAgYTI8LWdncGxvdChkYXRvcyxtYXBwaW5nID0gYWVzKHk9RXhwb3J0YWNpb25lcyx4PVRpcG9fZGVfY2FtYmlvKSkrDQogICAgICBnZW9tX3BvaW50KGNvbG9yPSJyZWQiKStnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4PVRpcG9fZGVfY2FtYmlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1saW5lYV8xKSkrdGhlbWVfbWluaW1hbCgpKw0KICAgICAgeGxhYigiVGlwbyBkZSBjYW1iaW8iKStsYWJzKHRpdGxlID0iUmVncmVzacOzbiBwb2xpbm9taWNhIikNCiAgICBFX2NfTV8yPSAoRXhwb3J0YWNpb25lcy1saW5lYV8xKV4yICU+JSBtZWFuKCkNCmEyICAgIA0KYGBgDQoNCiMjIE1hcXVpbmFzIGRlIHNvcG9ydGUgdmVjdG9yaWFsIA0KDQpgYGB7cn0NCmxpYnJhcnkoZTEwNzEpDQogICAgbW9kZWxvX3I8LSBzdm0oRXhwb3J0YWNpb25lc35UaXBvX2RlX2NhbWJpbyxkYXRhID0gZGF0b3MpDQogICAgbGluZWFfMjwtIHByZWRpY3QobW9kZWxvX3IsZGF0b3MpICAgIA0KICAgIGEzPC1nZ3Bsb3QoZGF0b3MsbWFwcGluZyA9IGFlcyh5PUV4cG9ydGFjaW9uZXMseD1UaXBvX2RlX2NhbWJpbykpKw0KICAgICAgZ2VvbV9wb2ludChjb2xvcj0icmVkIikrZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeD1UaXBvX2RlX2NhbWJpbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9bGluZWFfMikpK3RoZW1lX21pbmltYWwoKSsNCiAgICB4bGFiKCJUaXBvIGRlIGNhbWJpbyIpK2xhYnModGl0bGUgPSJNYXF1aW5hIGRlIHNvcG9ydGUgdmVjdG9yaWFsIikNCiAgICANCiAgICBFX2NfTV8zPSAoRXhwb3J0YWNpb25lcy1saW5lYV8yKV4yICU+JSBtZWFuKCkNCmEzDQpgYGANCg0KIyMgQXJib2xlcyBkZSBkZWNpc2nDs24gDQoNCmBgYHtyfQ0KbGlicmFyeShycGFydCkNCiAgICBtb2RlbG9fcjwtIHJwYXJ0KEV4cG9ydGFjaW9uZXN+VGlwb19kZV9jYW1iaW8sZGF0YSA9IGRhdG9zKQ0KICAgIGxpbmVhXzM8LSBwcmVkaWN0KG1vZGVsb19yLGRhdG9zKSAgICANCiAgICBhNDwtZ2dwbG90KGRhdG9zLG1hcHBpbmcgPSBhZXMoeT1FeHBvcnRhY2lvbmVzLHg9VGlwb19kZV9jYW1iaW8pKSsNCiAgICAgIGdlb21fcG9pbnQoY29sb3I9InJlZCIpK2dlb21fbGluZShtYXBwaW5nID0gYWVzKHg9VGlwb19kZV9jYW1iaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWxpbmVhXzMpKSt0aGVtZV9taW5pbWFsKCkrDQogICAgICB4bGFiKCJUaXBvIGRlIGNhbWJpbyIpK2xhYnModGl0bGUgPSJBcmJvbGVzIGRlIGRlc2ljacOzbiIpDQogICAgRV9jX01fND0gbWVhbigoRXhwb3J0YWNpb25lcy1saW5lYV8zKV4yKQ0KICBhNA0KYGBgDQoNCiMjIEJvc3F1ZXMgYWxlYXRvcmlvcw0KDQpgYGB7cixpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpgYGANCg0KDQpgYGB7cixtZXNzYWdlPVRSVUV9DQojIGxpYnJhcnkocmFuZG9tRm9yZXN0KQ0KICAgIG1vZGVsb19yPC0gcmFuZG9tRm9yZXN0KEV4cG9ydGFjaW9uZXN+VGlwb19kZV9jYW1iaW8sZGF0YSA9IGRhdG9zKQ0KICAgIGxpbmVhXzQ8LSBwcmVkaWN0KG1vZGVsb19yLGRhdG9zKSAgICANCiAgICBhNTwtZ2dwbG90KGRhdG9zLG1hcHBpbmcgPSBhZXMoeT1FeHBvcnRhY2lvbmVzLHg9VGlwb19kZV9jYW1iaW8pKSsNCiAgICAgIGdlb21fcG9pbnQoY29sb3I9InJlZCIpK2dlb21fbGluZShtYXBwaW5nID0gYWVzKHg9VGlwb19kZV9jYW1iaW8sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PWxpbmVhXzQpKSt0aGVtZV9taW5pbWFsKCkrDQogICAgICB4bGFiKCJUaXBvIGRlIGNhbWJpbyIpK2xhYnModGl0bGUgPSJCb3NxdWVzIEFsZWF0b3Jpb3MiKQ0KICAgIEVfY19NXzU9IChFeHBvcnRhY2lvbmVzLWxpbmVhXzQpXjIgJT4lIG1lYW4oKSAgICANCmE1DQpgYGANCg0KIyMgRWxlY2Npw7NuIGRlbCBtZWpvciBtb2RlbG8gDQpgYGB7cixpbmNsdWRlPUZBTFNFfQ0KcmVxdWlyZShncmlkRXh0cmEpDQoNCmBgYA0KDQoNCmBgYHtyLGVjaG89RkFMU0UsbWVzc2FnZT1UUlVFLHdhcm5pbmc9VFJVRX0NCmVycm9yZXM8LSBkYXRhLmZyYW1lKGVycm9yZXM9YyhFX2NfTV8xLEVfY19NXzIsRV9jX01fMyxFX2NfTV80LEVfY19NXzUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGV0aXF1ZXRhcz1jKCJyX2wiLCJyX3AiLCJzdm0iLCJ0cmVlIiwiZm9yZXN0IikpICAgDQphPC1nZ3Bsb3QoZXJyb3JlcyxtYXBwaW5nID0gYWVzKHg9MTo1LGVycm9yZXMsY29sb3I9ZXRpcXVldGFzKSkrZ2VvbV9wb2ludChzaXplPTQpDQphNjwtYSArIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImhvbmV5ZGV3MyIsIA0KICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiKSwgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiZG9kZ2VyYmx1ZTEiKSwgDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiksIA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIA0KICAgICAgICAgICAgZmFjZSA9ICJib2xkLml0YWxpYyIsIGNvbG91ciA9ICJibHVlNCIpLCANCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgDQogICAgICAgICAgICBmYWNlID0gImJvbGQiLCBjb2xvdXIgPSAiYnJvd24iKSwgDQogICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QobGluZXR5cGUgPSAiZG90dGVkIiksIA0KICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChzaXplID0gMS4yLCANCiAgICAgICAgICAgIGxpbmV0eXBlID0gInNvbGlkIiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCANCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgK2xhYnModGl0bGUgPSAiRWxlY2Npw7NuIGRlbCBtZWpvciBtb2RlbG8iLCANCiAgICAgICAgeCA9IE5VTEwsIGNvbG91ciA9ICJFcnJvcmVzIGN1YWRyYXRpY29zIikrdGhlbWVfbWluaW1hbCgpDQpncmlkLmFycmFuZ2UoYTEsYTIsYTMsYTQsYTUsYTYpDQpgYGANCg0KPiBOb3RhOiBFbCBtZWpvciBtb2RlbG8gZXMgZW4gZWwgY3VhbCBzZSBhcGxpY28gZWwgbWV0w7NkbyBkZSBSYW5kb20gZm9yZXN0IHB1ZXMgcHJlc2VudGUgdW4gbWVub3IgJFJeMiQuICANCg0KIyBDb3JyZWNjacOzbiBkZSBsYSBhdXRvY29ycmVsYWNpw7NuDQoNClBhcmEgdmVyIHNpIHByZXNlbnRhICoqYXV0b2NvcnJlbGFjacOzbioqIHVzYW1vcyBlbCB0ZXN0IGRlIGR1cndpbiB3YXRzb24gcXVlIG5vcyBwZXJtaXRlIHZlciBzaSBzZSBwcmVzZW50YSBlc3RvLiBQYXJhIGNvcnJlZ2lybGEgc2UgcHJlc2VudGEgbGFzIHNpZ3VpZW50ZXMgZnVuY2lvbmVzLiANCg0KYGBge3IsZWNobz1GQUxTRSx3YXJuaW5nPVRSVUUsaW5jbHVkZT1GQUxTRX0NCmlwYWsgPC0gZnVuY3Rpb24ocGtnKXsNCiAgbmV3LnBrZyA8LSBwa2dbIShwa2cgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKVssICJQYWNrYWdlIl0pXQ0KICBpZiAobGVuZ3RoKG5ldy5wa2cpKSANCiAgICBpbnN0YWxsLnBhY2thZ2VzKG5ldy5wa2csIGRlcGVuZGVuY2llcyA9IFRSVUUpDQogIHNhcHBseShwa2csIHJlcXVpcmUsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCn0NCnBhY2thZ2VzIDwtIGMoInRpZHl2ZXJzZSIsImRhdGEudGFibGUiLCAiWE1MIiwiaHR0ciIsInh0cyIpDQppcGFrKHBhY2thZ2VzKQ0KZXh0cmFjY2lvbjwtIGZ1bmN0aW9uKGNvZGlnbz1OVUxMLHN0YXJ0PU5VTEwsZW5kPU5VTEwpew0KICB2ZWN0b3I8LSB2ZWN0b3IoKQ0KICBkYXRvczwtIE5VTEwNCiAgZm9yKGkgaW4gMTpsZW5ndGgoY29kaWdvKSl7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXg8LSAgcGFzdGUwKCJodHRwczovL2VzdGFkaXN0aWNhcy5iY3JwLmdvYi5wZS9lc3RhZGlzdGljYXMvc2VyaWVzL2FwaS8iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2RpZ29baV0sICIveG1sLyIsc3RhcnQsIi8iLGVuZCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT2JqWE1MIDwtIGh0dHI6OkdFVChleCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMX3BhcnNlWE1MIDwtIHhtbFBhcnNlKE9ialhNTCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExfWE1MIDwtIHhtbFRvTGlzdChMX3BhcnNlWE1MKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR0X0JDUlAgPC0gZGF0YS50YWJsZTo6ZGF0YS50YWJsZSgpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChhIGluIDE6bGVuZ3RoKExfWE1MJHBlcmlvZHMpKXsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF90ZW1wIDwtIGRhdGEudGFibGUoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllPSBMX1hNTCRwZXJpb2RzW1thXV0kdikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdF9CQ1JQIDwtIHJiaW5kKGR0X0JDUlAsZHRfdGVtcCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVjdG9yW2ldPC0gZHRfQkNSUFssc2VyaWU6PWFzLm51bWVyaWMoc2VyaWUpXSANCiAgfQ0KICBmb3IoaSBpbiAgMTogbGVuZ3RoKGNvZGlnbykpew0KICAgIGRhdG9zPC0gY2JpbmQoZGF0b3MsdmVjdG9yW1tpXV0pDQogIH0NCiAgZGF0b3M8LSBhcy5kYXRhLmZyYW1lKGRhdG9zKQ0KICBuYW1lcyhkYXRvcyk8LSBjb2RpZ28NCiAgcmV0dXJuKGRhdG9zKQ0KICB9DQpkYXRvczwtZXh0cmFjY2lvbihjKCJQTjAxNDg4Qk0iLCJQTjAxMjEwUE0iICksIjIwMDAtMSIsIjIwMDctMiIpDQpuYW1lcyhkYXRvcyk8LSBjKCJFeHBvcnRhY2lvbmVzIiwiVGlwb19kZV9jYW1iaW8iKQ0KYXR0YWNoKGRhdG9zKQ0KYGBgDQoNCiMjIFVzbyBkZSBsYSBwcnVlYmEgZGUgYXV0b2NvcnJlbGFjacOzbiANCg0KYGBge3J9DQptb2RlbG9fcjwtIGxtKEV4cG9ydGFjaW9uZXN+VGlwb19kZV9jYW1iaW8sZGF0YSA9IGRhdG9zKQ0Kc3VtbWFyeShtb2RlbG9fcikNCmI8LSBtb2RlbG9fciRyZXNpZHVhbHMNCmFjZihiKQ0KcGFjZihiKQ0KYGBgDQoNCj4gUmVzdWx0YWRvOiBwb2RlbW9zIHZlciBxdWUgZGUgZm9ybWEgZ3LDoWZpY2Egc2UgcHJlc2VudGEgYXV0b2NvcnJlbGFjacOzbiANCg0KQWhvcmEgYXBsaWNhbW9zIHVuYSBwcnVlYmEgZm9ybWFsIA0KDQpgYGB7cn0NCmxtdGVzdDo6ZHd0ZXN0KG1vZGVsb19yKSANCmBgYA0KDQpQb2RlbW9zIHZlciBxdWUgZWwgKipEVyoqIGNhbGN1bGFkbyBlcyBtYXlvciBhIGxvIHBlcm1pdGlkbyBhc8OtIHF1ZSBwb2RlbW9zIGRlZHVjaXIgcXVlIHNpIHByZXNlbnRhIGF1dG9jb3JyZWxhY2nDs24gDQoNCiFbXShhYWFhYWEuanBnKQ0KDQojIyBDb3JyZWNjacOzbiANCg0KIyMjIEFncmVnYW5kbyB1biByZXNhZ28gDQoNCmBgYHtyfQ0KbGlicmFyeShkeW5sbSkgICAgICANCm1vZGVsb19hPC0gZHlubG0oRXhwb3J0YWNpb25lc35UaXBvX2RlX2NhbWJpbytMKEV4cG9ydGFjaW9uZXMpKSAgICAgIA0Kc3VtbWFyeShtb2RlbG9fYSkNCmM8LSBtb2RlbG9fYSRyZXNpZHVhbHMNCmBgYA0KDQpBbmFsaXphbmRvIGxvcyByZXN1bHRhZG9zOg0KDQpgYGB7cn0NCmFjZihjKQ0KcGFjZihjKQ0KbG10ZXN0Ojpkd3Rlc3QobW9kZWxvX2EpIA0KYGBgDQoNCj4gTm90YTogQWhvcmEgZXN0ZSBpbmRpY2Fkb3Igc2UgYXByb3hpbWEgYSAyIGFzw60gcXVlIHBvZGVtb3MgZGVjaXIgcXVlIG5vIHByZXNlbnRhIGFjdXRvY3JyZWxhY2nDs24uIA0KDQojIyMgQWxnb3J0aW1vIGRlIG91cmN1cnQNCg0KYGBge3J9DQpsaWJyYXJ5KG9yY3V0dCkgICAgICANCmNvcjwtY29jaHJhbmUub3JjdXR0KG1vZGVsb19yKQ0Kc3VtbWFyeS5vcmN1dHQoY29yKQ0KYGBgDQoNCg==