Indice:






El operador del sistema eléctrico en España Red Eléctrica,proporciona desde su página información de la demanda de energía eléctrica en el mercado español y además pone a disposición de terceros,de forma libre estos datos a traves de su api.La documentación para el consumo de ésta se encuentra disponible aquí.Para poder utilizarla es necesario tener un token personal que puede solicitarse por correo en la dirección consultasios@ree.es.

Mi interés es poder crear un modelo de predicción de la demanda agregada en España del consumo eléctrico por hora. Como primer paso, necesito recuperar un set de datos con la serie histórica de los últimos años que me sirva de entrenamiento y lo haré por medio de este api. He obtenido un token personal para su uso y me apoyaré en el paquete requests de python para realizar la gestión de la conexión http y la descarga de sus datos.




OBTENCIÓN DE DATOS DE DEMANDA DE ENERGIA ELECTRICA


Los pasos que seguiré son los siguientes:


A continuación el código en python desarrollado para obtener los datos:



Los identifcadores para nuestros servicios son: y la fecha de nuestro periodo de estudio:





Recuperada la información deseada,inicio una primer exploración de los datos. Para ello voy a utilizar el paquete highcharter en r que proporciona un wrapper muy sencillo de la librería highchart en javascript.

############### Datos de demanda real
library(dplyr)
library(highcharter)
library(htmltools)
library(xts)
demandaReal<-read.csv('Datos_Demanda_Real.csv',sep=';',stringsAsFactors = F)
diagramaPolar<-function(df,anno){
  df<-df[substr(df$Fecha,1,4)==anno, c('Fecha','Valor')]
  demandaReal<-df %>% group_by(Fecha) %>%summarise('Max'=max(Valor),'Min'=min(Valor),'Mean'=mean(Valor))
  demandaReal$Fecha<-as.Date(demandaReal$Fecha)
  demandaReal$Mean<-round(demandaReal$Mean)
  x <- c("Min", "Mean", "Max")
  y <- sprintf("{point.%s}", c("Min", "Mean", "Max"))
  tltip <- tooltip_table(x, y)
  maxL<-mean(demandaReal$Max)
  
  p<-hchart(demandaReal, type = "columnrange",
            hcaes(x = Fecha, low = Min, high = Max,
                  color = Mean)) %>% 
    hc_chart(polar = TRUE) %>%
    hc_yAxis( max = maxL+10000, min =10000, labels = list(format = "{value} GWh"),
              showFirstLabel = FALSE) %>% 
    hc_xAxis(
      title = list(text = ''), gridLineWidth = 0.5,
      labels = list(format = "{value: %b}")) %>% 
    hc_tooltip(useHTML = TRUE, pointFormat = tltip,
               headerFormat = as.character(tags$small("{point.x:%d %B, %Y}")))  %>%
    hc_title(text=paste0('Digrama anual de la demanda real de energía en España durante el ','Año: ','- ',anno,' -'))  %>%
    hc_subtitle(text='Valores Máximos ,Mínimos y Medios diarios')
  return(p)
  
}
dp<-diagramaPolar(demandaReal,'2017')
################################
serieHora<-function(df,HORA){
  demandaReal<-df[substr(df$Hora,1,2)==HORA,c('Fecha','Valor')]
  demandaReal$Fecha<-as.Date(demandaReal$Fecha)
  demandaReal<-xts(demandaReal$Valor,order.by =demandaReal$Fecha )
  hc <- highchart(type = "stock") %>% 
   hc_title(text = "Diagrama de la demanda real de energía en España durante los años 2014-2018") %>% 
    hc_subtitle(text = paste0("La serie contiene la demanda agregada a las ",HORA,' horas')) %>% 
    hc_add_series(demandaReal) 
  return(hc)
}
ser<-serieHora(demandaReal,'22')
#############################
mapaCalor<-function(df,Trimestre, Anno){
  demandaReal2017<-df[substr(df$Fecha,1,4)==Anno,c('Fecha','Hora','Valor')]
  demandaReal2017$Hora<-substr(demandaReal2017$Hora,1,2)
  demandaReal2017$Hora<-as.integer(demandaReal2017$Hora)
  demandaReal2017$Dia<-as.POSIXlt(demandaReal2017$Fecha)$yday
  
  M<-matrix(rep(0,24*365),nrow=24,ncol=365,byrow = T)
  
  for(i in (0:23)){
    for(j in (1:365)){
      #print(paste0(i,' ',j))
      M[i+1,j]=demandaReal2017[(demandaReal2017$Dia==j) & (demandaReal2017$Hora==i),'Valor'][1]
    }
  }
  if(Trimestre==1){
    ini=1
    fin=90
  }else if (Trimestre==2){
    ini=91
    fin=180
  }else if (Trimestre==3){
    ini=181
    fin=20
  }else{
    ini=271
    fin=365
  }  
    
    
  s<-hchart(M[c(1:24),c(ini:fin)]) %>% 
    hc_colorAxis(stops = color_stops(colors = viridis::inferno(10))) %>%
    hc_title(text = "Diagrama de calor de la demanda real agregada de energía en España") %>% 
    hc_subtitle(text = paste0(Trimestre,'º Tirmestre',' del ', Anno, '/ Columna: Hora, Fila= Dia secuencial del año'))
  return(s)
}
c1<-mapaCalor(demandaReal,1,'2015')
c2<-mapaCalor(demandaReal,1,'2016')
c3<-mapaCalor(demandaReal,1,'2017')
c4<-mapaCalor(demandaReal,1,'2018')
lst <- list(
  c1,
  c2,
  c3,
  c4
)
s<-hw_grid(lst, rowheight = 600)  %>% browsable()




DIAGRAMA DE CALOR


s





SERIE TEMPORAL


ser





DIAGRAMA POLAR


dp




Esta visualizacion forma parte del estudio y modelo de predicción de la demanda real eléctrica en el mercado español




LS0tCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAotLS0KPGltZyBzcmM9J2NhYmVjZXJhLnBuZyc+Cgo8ZGl2IHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNGQkVGRjIiPgo8YnI+Cgo8YnI+CjxoMj48Y2VudGVyPkluZGljZTo8L2NlbnRlcj48L2gyPgo8YnI+Cgo8dWw+CjxsaT48Yj5PYnRlbmNpw7NuIGRlIGRhdG9zIGRlIGRlbWFuZGEgZWzDqWN0cmljYTo8L2I+IFVzbyBkZSBhcGkgZGUgUmVkIEVsw6ljdHJpY2EuPC9saT4KPGxpPjxiPkRpYWdyYW1hIGRlIENhbG9yPC9iPjogQ29tcGFyYXRpdmEgZGUgbGEgZGVtYW5kYSBwb3IgaG9yYSBkaWFyaWEgZGVsIDHCuiBUcmltZXN0cmUgZGVsIHBlcmlvZG8gMjAxNS0yMDE4IDwvbGk+CjxsaT48Yj5TZXJpZSBUZW1wb3JhbDwvYj46IFJlcHJlc2VudGFjacOzbiBkZSBsYSBkZW1hbmRhIGR1cmFudGUgZWwgcGVyaW9kbyAyMDE0LTIwMTggKGhvcmEgZGUgZWplbXBsbzogMjIuMDApPC9saT4KPGxpPjxiPkRpYWdyYW1hIFBvbGFyPC9iPjogUmVwcmVzZW50YWNpw7NuIGRlbCByYW5nbyBkZSBsYSBkZW1hbmRhIGRpYXJpYSBkdXJhbnRlIGVsIGHDsW8gMjAxNzwvbGk+CjwvdWw+Cgo8YnI+Cjxicj4KPC9kaXY+Cjxocj4KPGJyPgogIEVsIG9wZXJhZG9yIGRlbCBzaXN0ZW1hIGVsw6ljdHJpY28gZW4gRXNwYcOxYSA8Yj5SZWQgRWzDqWN0cmljYTwvYj4scHJvcG9yY2lvbmEgZGVzZGUgc3UgPGEgaHJlZj0iaHR0cHM6Ly93d3cuZXNpb3MucmVlLmVzL2VzIj5ww6FnaW5hPC9hPiBpbmZvcm1hY2nDs24gZGUgbGEgZGVtYW5kYSBkZSBlbmVyZ8OtYSBlbMOpY3RyaWNhIGVuIGVsIG1lcmNhZG8gZXNwYcOxb2wgeSBhZGVtw6FzIHBvbmUgYSBkaXNwb3NpY2nDs24gZGUgdGVyY2Vyb3MsZGUgZm9ybWEgbGlicmUgZXN0b3MgZGF0b3MgYSB0cmF2ZXMgZGUgc3UgYXBpLkxhIGRvY3VtZW50YWNpw7NuIHBhcmEgZWwgY29uc3VtbyBkZSDDqXN0YSBzZSBlbmN1ZW50cmEgZGlzcG9uaWJsZSA8YSBocmVmPSdodHRwczovL2FwaS5lc2lvcy5yZWUuZXMnPmFxdcOtLjwvYT5QYXJhIHBvZGVyIHV0aWxpemFybGEgZXMgbmVjZXNhcmlvIHRlbmVyIHVuIHRva2VuIHBlcnNvbmFsIHF1ZSBwdWVkZSBzb2xpY2l0YXJzZSBwb3IgY29ycmVvIGVuIGxhIGRpcmVjY2nDs24gY29uc3VsdGFzaW9zQHJlZS5lcy4KCiAgTWkgaW50ZXLDqXMgZXMgcG9kZXIgY3JlYXIgdW4gbW9kZWxvIGRlIHByZWRpY2Npw7NuIGRlIGxhIGRlbWFuZGEgYWdyZWdhZGEgZW4gRXNwYcOxYSBkZWwgY29uc3VtbyBlbMOpY3RyaWNvIHBvciBob3JhLiBDb21vIHByaW1lciBwYXNvLCBuZWNlc2l0byByZWN1cGVyYXIgdW4gc2V0IGRlIGRhdG9zIGNvbiBsYSBzZXJpZSBoaXN0w7NyaWNhIGRlIGxvcyDDumx0aW1vcyBhw7FvcyBxdWUgbWUgc2lydmEgZGUgZW50cmVuYW1pZW50byB5IGxvIGhhcsOpIHBvciBtZWRpbyBkZSBlc3RlIGFwaS4gSGUgb2J0ZW5pZG8gdW4gdG9rZW4gcGVyc29uYWwgcGFyYSBzdSB1c28geSBtZSBhcG95YXLDqSBlbiBlbCBwYXF1ZXRlIDxiPnJlcXVlc3RzPC9iPiBkZSA8Yj5weXRob248L2I+IHBhcmEgcmVhbGl6YXIgbGEgZ2VzdGnDs24gZGUgbGEgY29uZXhpw7NuIDxpPmh0dHA8L2k+IHkgbGEgZGVzY2FyZ2EgZGUgc3VzIGRhdG9zLgogIAo8YnI+Cjxicj4KPGRpdiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojRjhFQ0UwIj4KPGJyPgogIDxoMz48Y2VudGVyPk9CVEVOQ0nDk04gREUgREFUT1MgREUgREVNQU5EQSBERSBFTkVSR0lBIEVMRUNUUklDQTwvY2VudGVyPjwvaDM+Cjxicj4KCjwvZGl2PiAgCiAgCiAgTG9zIHBhc29zIHF1ZSBzZWd1aXLDqSBzb24gbG9zIHNpZ3VpZW50ZXM6CiAgPGJyPgogIDxicj4KICA8dWw+CiAgPGxpPkRlc2NhcmdhcsOpIGxvcyBpZGVudGlmaWNhZG9yZXMgZGUgc2VydmljaW8uSGFyw6kgdW5hIHBldGljacOzbiBodHRwICBhIGxhIGRpcmVjY2lvbiAiaHR0cHM6Ly9hcGkuZXNpb3MucmVlLmVzL2luZGljYXRvcnMiIHBhcmEgb2J0ZW5lciBsYSBsaXN0YSAoanNvbikgZGUgc2VydmljaW9zIC0gaW5kaWNhZG9yZXMgLSBjb24gbG9zIHF1ZSBjdWVudGEgbGEgYXBpLiBVc2Fyw6kgIGVsIG3DqXRvZG8gPGI+Z2V0KCk8L2I+IGRlbCBwYXF1ZXRlIDxiPnJlcXVlc3RzPC9iPiBwYXJhIHJlYWxpemFyIGxhIGxsYW1hZGEgZG9uZGUgcG9yIHBhcsOhbWV0cm8gcGFzYXLDqSBsYSBkaXJlY2Npw7NuIHkgZWwgdG9rZW4gcGVyc29uYWwuPC9saT4KICA8bGk+QnVzY2Fyw6kgbG9zIGlkZW50aWZpY2Fkb3JlcyBkZSA8Yj5EZW1hbmRhIHJlYWw8L2I+IHkgPGI+cHJldmlzacOzbiBtZW5zdWFsIGRlIGxhIGRlbWFuZGEgZWzDqWN0cmljYTwvYj4uIEVzdGEgw7psdGltbyBtZSBwcm9wb3JjaW9uYXLDoSAgdW4gYmVuY2htYXJrIGVudHJlIGxhIHByZWRpY2Npw7NuIHDDumJsaWNhIHkgbGEgcXVlIHB1ZWRhIGRlc2Fycm9sbGFyIHBlcnNvbmFsbWVudGUuPC9saT4KICA8bGk+Q3JlYXLDqSAgbGFzIGZlY2hhcyBkZWwgcGVyaW9kbyBkZSBkYXRvcyBxdWUgcXVpZXJvIGVzdHVkaWFyIGluaWNpYWxtZW50ZS5DdWF0cm9zIGHDsW9zIGRlc2RlIGxhIGZlY2hhIGFjdHVhbC48L2xpPgogIDxsaT5IYXLDqSAgdW5hIHNlZ3VuZGEgbGxhbWFkYSBhbCBhcGksIGVzdGEgdmV6IHBhcmEgb2J0ZW5lciBsb3MgZGF0b3MgcmVhbGVzIGRlIGNvbnN1bW8gZW4gZWwgcGVyaW9kbyB5IHBhcmEgZWxsbyBjb21wb25kcsOpICBsYSBkaXJlY2Npw7NuIGh0dHBzOi8vYXBpLmVzaW9zLnJlZS5lcy9pbmRpY2F0b3JzLyVzP3N0YXJ0X2RhdGU9JXNUMjI6MDA6MDBaJmVuZF9kYXRlPSVzVDIxOjAwOjAwWiZ0aW1lX3RydW5jPWhvdXIgY29uIGxvcyBwYXLDoW1ldHJvcyBpZCBkZWwgc2VydmljaW8geSBsYSBmZWNoYSBkZSBpbmljaW8geSBmaW4gZGUgbGEgcGV0aWNpw7NuLjwvbGk+CiAgPGxpPlBvciDDumx0aW1vIGNvbXBvbmRyw6kgIGRvcyA8aT5kYXRhZnJhbWU8L2k+IGNvbiBsYSByZXNwdWVzdGEgZGUgY2FkYSB1bm8gZGUgbG9zIGluZGljYWRvcmVzLjwvbGk+CiAgPC91bD4KCjxicj4KQSBjb250aW51YWNpw7NuIGVsIGPDs2RpZ28gZW4gcHl0aG9uIGRlc2Fycm9sbGFkbyBwYXJhIG9idGVuZXIgbG9zIGRhdG9zOgo8YnI+Cjxicj4KPGltZyBzcmM9J2NvZDEucG5nJz4KPGJyPgo8YnI+CkxvcyBpZGVudGlmY2Fkb3JlcyBwYXJhIG51ZXN0cm9zIHNlcnZpY2lvcyBzb246Cjx1bD4KPGxpPkRlbWFuZGEgcmVhbDogMTI5MzwvbGk+CjxsaT5QcmV2aXNpb24gbWVuc3VhbCBkZSBsYSBkZW1hbmRhIGVsw6ljdHJpY2EgcGVuaW5zdWxhcjogNDYxPC9saT4KPC91bD4KeSBsYSBmZWNoYSBkZSBudWVzdHJvIHBlcmlvZG8gZGUgZXN0dWRpbzoKPHVsPgo8bGk+ZmVjaGEgZGUgaW5pY2lvOiAyMDE0LTA3LTI5PC9saT4KPGxpPmZlY2hhIGZpbjogMjAxOC0wNy0yNzwvbGk+CjwvdWw+Cjxicj4KPGJyPgo8aW1nIHNyYz0nY29kMi5wbmcnPgo8YnI+Cjxicj4KUmVjdXBlcmFkYSBsYSBpbmZvcm1hY2nDs24gZGVzZWFkYSxpbmljaW8gdW5hIHByaW1lciBleHBsb3JhY2nDs24gZGUgbG9zIGRhdG9zLiBQYXJhIGVsbG8gdm95IGEgdXRpbGl6YXIgZWwgcGFxdWV0ZSA8Yj5oaWdoY2hhcnRlcjwvYj4gZW4gPGI+cjwvYj4gcXVlIHByb3BvcmNpb25hIHVuIDxpPndyYXBwZXI8L2k+IG11eSBzZW5jaWxsbyBkZSBsYSBsaWJyZXLDrWEgPGk+aGlnaGNoYXJ0PC9pPiBlbiBqYXZhc2NyaXB0Lgo8YnI+Cjxicj4KYGBge3J9CiMjIyMjIyMjIyMjIyMjIyBEYXRvcyBkZSBkZW1hbmRhIHJlYWwKbGlicmFyeShkcGx5cikKbGlicmFyeShoaWdoY2hhcnRlcikKbGlicmFyeShodG1sdG9vbHMpCmxpYnJhcnkoeHRzKQoKZGVtYW5kYVJlYWw8LXJlYWQuY3N2KCdEYXRvc19EZW1hbmRhX1JlYWwuY3N2JyxzZXA9JzsnLHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQoKZGlhZ3JhbWFQb2xhcjwtZnVuY3Rpb24oZGYsYW5ubyl7CiAgZGY8LWRmW3N1YnN0cihkZiRGZWNoYSwxLDQpPT1hbm5vLCBjKCdGZWNoYScsJ1ZhbG9yJyldCiAgZGVtYW5kYVJlYWw8LWRmICU+JSBncm91cF9ieShGZWNoYSkgJT4lc3VtbWFyaXNlKCdNYXgnPW1heChWYWxvciksJ01pbic9bWluKFZhbG9yKSwnTWVhbic9bWVhbihWYWxvcikpCiAgZGVtYW5kYVJlYWwkRmVjaGE8LWFzLkRhdGUoZGVtYW5kYVJlYWwkRmVjaGEpCiAgZGVtYW5kYVJlYWwkTWVhbjwtcm91bmQoZGVtYW5kYVJlYWwkTWVhbikKICB4IDwtIGMoIk1pbiIsICJNZWFuIiwgIk1heCIpCiAgeSA8LSBzcHJpbnRmKCJ7cG9pbnQuJXN9IiwgYygiTWluIiwgIk1lYW4iLCAiTWF4IikpCiAgdGx0aXAgPC0gdG9vbHRpcF90YWJsZSh4LCB5KQoKICBtYXhMPC1tZWFuKGRlbWFuZGFSZWFsJE1heCkKICAKICBwPC1oY2hhcnQoZGVtYW5kYVJlYWwsIHR5cGUgPSAiY29sdW1ucmFuZ2UiLAogICAgICAgICAgICBoY2Flcyh4ID0gRmVjaGEsIGxvdyA9IE1pbiwgaGlnaCA9IE1heCwKICAgICAgICAgICAgICAgICAgY29sb3IgPSBNZWFuKSkgJT4lIAogICAgaGNfY2hhcnQocG9sYXIgPSBUUlVFKSAlPiUKICAgIGhjX3lBeGlzKCBtYXggPSBtYXhMKzEwMDAwLCBtaW4gPTEwMDAwLCBsYWJlbHMgPSBsaXN0KGZvcm1hdCA9ICJ7dmFsdWV9IEdXaCIpLAogICAgICAgICAgICAgIHNob3dGaXJzdExhYmVsID0gRkFMU0UpICU+JSAKICAgIGhjX3hBeGlzKAogICAgICB0aXRsZSA9IGxpc3QodGV4dCA9ICcnKSwgZ3JpZExpbmVXaWR0aCA9IDAuNSwKICAgICAgbGFiZWxzID0gbGlzdChmb3JtYXQgPSAie3ZhbHVlOiAlYn0iKSkgJT4lIAogICAgaGNfdG9vbHRpcCh1c2VIVE1MID0gVFJVRSwgcG9pbnRGb3JtYXQgPSB0bHRpcCwKICAgICAgICAgICAgICAgaGVhZGVyRm9ybWF0ID0gYXMuY2hhcmFjdGVyKHRhZ3Mkc21hbGwoIntwb2ludC54OiVkICVCLCAlWX0iKSkpICAlPiUKICAgIGhjX3RpdGxlKHRleHQ9cGFzdGUwKCdEaWdyYW1hIGFudWFsIGRlIGxhIGRlbWFuZGEgcmVhbCBkZSBlbmVyZ8OtYSBlbiBFc3Bhw7FhIGR1cmFudGUgZWwgJywnQcOxbzogJywnLSAnLGFubm8sJyAtJykpICAlPiUKICAgIGhjX3N1YnRpdGxlKHRleHQ9J1ZhbG9yZXMgTcOheGltb3MgLE3DrW5pbW9zIHkgTWVkaW9zIGRpYXJpb3MnKQogIHJldHVybihwKQogIAp9CgpkcDwtZGlhZ3JhbWFQb2xhcihkZW1hbmRhUmVhbCwnMjAxNycpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKc2VyaWVIb3JhPC1mdW5jdGlvbihkZixIT1JBKXsKICBkZW1hbmRhUmVhbDwtZGZbc3Vic3RyKGRmJEhvcmEsMSwyKT09SE9SQSxjKCdGZWNoYScsJ1ZhbG9yJyldCiAgZGVtYW5kYVJlYWwkRmVjaGE8LWFzLkRhdGUoZGVtYW5kYVJlYWwkRmVjaGEpCiAgZGVtYW5kYVJlYWw8LXh0cyhkZW1hbmRhUmVhbCRWYWxvcixvcmRlci5ieSA9ZGVtYW5kYVJlYWwkRmVjaGEgKQoKICBoYyA8LSBoaWdoY2hhcnQodHlwZSA9ICJzdG9jayIpICU+JSAKICAgaGNfdGl0bGUodGV4dCA9ICJEaWFncmFtYSBkZSBsYSBkZW1hbmRhIHJlYWwgZGUgZW5lcmfDrWEgZW4gRXNwYcOxYSBkdXJhbnRlIGxvcyBhw7FvcyAyMDE0LTIwMTgiKSAlPiUgCiAgICBoY19zdWJ0aXRsZSh0ZXh0ID0gcGFzdGUwKCJMYSBzZXJpZSBjb250aWVuZSBsYSBkZW1hbmRhIGFncmVnYWRhIGEgbGFzICIsSE9SQSwnIGhvcmFzJykpICU+JSAKICAgIGhjX2FkZF9zZXJpZXMoZGVtYW5kYVJlYWwpIAoKICByZXR1cm4oaGMpCn0KCnNlcjwtc2VyaWVIb3JhKGRlbWFuZGFSZWFsLCcyMicpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKbWFwYUNhbG9yPC1mdW5jdGlvbihkZixUcmltZXN0cmUsIEFubm8pewogIGRlbWFuZGFSZWFsMjAxNzwtZGZbc3Vic3RyKGRmJEZlY2hhLDEsNCk9PUFubm8sYygnRmVjaGEnLCdIb3JhJywnVmFsb3InKV0KICBkZW1hbmRhUmVhbDIwMTckSG9yYTwtc3Vic3RyKGRlbWFuZGFSZWFsMjAxNyRIb3JhLDEsMikKICBkZW1hbmRhUmVhbDIwMTckSG9yYTwtYXMuaW50ZWdlcihkZW1hbmRhUmVhbDIwMTckSG9yYSkKICBkZW1hbmRhUmVhbDIwMTckRGlhPC1hcy5QT1NJWGx0KGRlbWFuZGFSZWFsMjAxNyRGZWNoYSkkeWRheQogIAogIE08LW1hdHJpeChyZXAoMCwyNCozNjUpLG5yb3c9MjQsbmNvbD0zNjUsYnlyb3cgPSBUKQogIAogIGZvcihpIGluICgwOjIzKSl7CiAgICBmb3IoaiBpbiAoMTozNjUpKXsKICAgICAgI3ByaW50KHBhc3RlMChpLCcgJyxqKSkKICAgICAgTVtpKzEsal09ZGVtYW5kYVJlYWwyMDE3WyhkZW1hbmRhUmVhbDIwMTckRGlhPT1qKSAmIChkZW1hbmRhUmVhbDIwMTckSG9yYT09aSksJ1ZhbG9yJ11bMV0KICAgIH0KICB9CiAgaWYoVHJpbWVzdHJlPT0xKXsKICAgIGluaT0xCiAgICBmaW49OTAKICB9ZWxzZSBpZiAoVHJpbWVzdHJlPT0yKXsKICAgIGluaT05MQogICAgZmluPTE4MAogIH1lbHNlIGlmIChUcmltZXN0cmU9PTMpewogICAgaW5pPTE4MQogICAgZmluPTIwCiAgfWVsc2V7CiAgICBpbmk9MjcxCiAgICBmaW49MzY1CiAgfSAgCiAgICAKICAgIAogIHM8LWhjaGFydChNW2MoMToyNCksYyhpbmk6ZmluKV0pICU+JSAKICAgIGhjX2NvbG9yQXhpcyhzdG9wcyA9IGNvbG9yX3N0b3BzKGNvbG9ycyA9IHZpcmlkaXM6OmluZmVybm8oMTApKSkgJT4lCiAgICBoY190aXRsZSh0ZXh0ID0gIkRpYWdyYW1hIGRlIGNhbG9yIGRlIGxhIGRlbWFuZGEgcmVhbCBhZ3JlZ2FkYSBkZSBlbmVyZ8OtYSBlbiBFc3Bhw7FhIikgJT4lIAogICAgaGNfc3VidGl0bGUodGV4dCA9IHBhc3RlMChUcmltZXN0cmUsJ8K6IFRpcm1lc3RyZScsJyBkZWwgJywgQW5ubywgJy8gQ29sdW1uYTogSG9yYSwgRmlsYT0gRGlhIHNlY3VlbmNpYWwgZGVsIGHDsW8nKSkKICByZXR1cm4ocykKfQoKCmMxPC1tYXBhQ2Fsb3IoZGVtYW5kYVJlYWwsMSwnMjAxNScpCmMyPC1tYXBhQ2Fsb3IoZGVtYW5kYVJlYWwsMSwnMjAxNicpCmMzPC1tYXBhQ2Fsb3IoZGVtYW5kYVJlYWwsMSwnMjAxNycpCmM0PC1tYXBhQ2Fsb3IoZGVtYW5kYVJlYWwsMSwnMjAxOCcpCgoKbHN0IDwtIGxpc3QoCiAgYzEsCiAgYzIsCiAgYzMsCiAgYzQKKQoKczwtaHdfZ3JpZChsc3QsIHJvd2hlaWdodCA9IDYwMCkgICU+JSBicm93c2FibGUoKQpgYGAKCjxicj4KPGJyPgo8YnI+CjxkaXYgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I0Y4RUNFMCI+Cjxicj4KICA8aDM+PGNlbnRlcj5ESUFHUkFNQSBERSBDQUxPUjwvY2VudGVyPjwvaDM+Cjxicj4KCjwvZGl2PgoKCgoKYGBge3J9CnMKYGBgCgo8YnI+Cjxicj4KPGJyPgoKPGRpdiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojRjhFQ0UwIj4KPGJyPgogIDxoMz48Y2VudGVyPlNFUklFIFRFTVBPUkFMPC9jZW50ZXI+PC9oMz4KPGJyPgoKPC9kaXY+CgoKYGBge3J9CnNlcgpgYGAKPGJyPgo8YnI+Cjxicj4KCjxkaXYgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I0Y4RUNFMCI+Cjxicj4KICA8aDM+PGNlbnRlcj5ESUFHUkFNQSBQT0xBUjwvY2VudGVyPjwvaDM+Cjxicj4KCjwvZGl2PgpgYGB7cn0KZHAKYGBgCjxicj4KPGJyPgo8aHI+CjxkaXYgc3R5bGU9ImJhY2tncm91bmQtY29sb3I6I0Y4RUNFMCI+Cjxicj4KICA8cD48Y2VudGVyPkVzdGEgdmlzdWFsaXphY2lvbiBmb3JtYSBwYXJ0ZSBkZWwgZXN0dWRpbyB5IG1vZGVsbyBkZSBwcmVkaWNjacOzbiBkZSBsYSBkZW1hbmRhIHJlYWwgZWzDqWN0cmljYSBlbiBlbCBtZXJjYWRvIGVzcGHDsW9sPC9pPjwvY2VudGVyPjwvcD4KPGJyPgoKPC9kaXY+Cjxicj4KPGJyPgo=