Iniciamos limpiando las variables del entorno de trabajo y definiendo las librerías a ser utilizadas

rm(list=ls())

library(airGRteaching)
library(tcltk)
library(Hmisc)
library(SoilHyP)
library(lubridate)
library(zoo)
library(airGR)

Defina la ruta de trabajo

path <- "Z:/My Drive/PERSONALES/TRABAJOS/DOCENCIA/2023 CURSO MODELACION UNICAUCA/2- MATERIAL/CLASES/SESION 4/TALLER GR4J"
setwd(path)

Defina el área de la cuenca.

Area_cuenca_km2 <- 156.6
Area_cuenca_m2 <- Area_cuenca_km2*1000000

Cargue el archivo con las variables de entrada al modelo

Entradas <- read.csv("DatosDiarios_CuencaSintetica.csv")
Entradas <- data.frame("DatesR"=Entradas$Fecha, "P"=Entradas$P_mm, "E"=Entradas$Etp_mm, "Qmm"=Entradas$Q_m3.s)
Entradas$Qmm <- Entradas$Qmm/Area_cuenca_m2*(60*60*24)*(1000)

Entradas$DatesR <- as.POSIXct(Entradas$DatesR, format="%d/%m/%Y", tz="UTC")

Defina el número de corridas


n <- 100 #numero de corridas

Defina los periodos de modelación


per.cal_warmup <- c("2003-01-01", "2003-12-31")
per.cal_warmup_extend <- seq(as.Date(per.cal_warmup[1]), as.Date(per.cal_warmup[2]), by="day")

per.cal <- c("2004-01-01", "2011-12-31")
per.cal_extend <- seq(as.Date(per.cal[1]), as.Date(per.cal[2]), by="day")

per.val_warmup <- c("2011-01-01", "2011-12-31")
per.val_warmup_extend <- seq(as.Date(per.val_warmup[1]), as.Date(per.val_warmup[2]), by="day")

per.val <- c("2012-01-01", "2015-12-31")
per.val_extend <- seq(as.Date(per.val[1]), as.Date(per.val[2]), by="day")

Defina el límite de los parámetros

## Simulation step using model parameters set by the user
par_names <- c("X1", "X2", "X3", "X4")
lim_inf <- c(20, -5,20,1)
lim_sup <- c(1200, 3, 500, 5)

Genere los conjuntos de parámetros a través del método Monte Carlo

# Montecarlo Parameters set - uniform distribution
parameters_set <- matrix(ncol = 4, nrow = n)
colnames(parameters_set) <- par_names

for(i in 1:length(par_names)){
  parameters_set[,i] <- runif(n, min=lim_inf[i], max=lim_sup[i])
}

Realice la calibración con las simulaciones Monte Carlo.

#aqui vamos a guardar los resultados de las n simulaciones y las n FO
Qsim <- list()
FO <- list()

PREP <- PrepGR(ObsDF = Entradas, HydroModel = "GR4J", CemaNeige = FALSE)

#barra de avance
pb <- tkProgressBar(title = "Calibrando GR4J", min = 0,
                    max = n, width = 300)

for(j in 1:n){
  
  SIM <- SimGR(PrepGR = PREP, Param = parameters_set[j,], EffCrit = "NSE",
               WupPer = per.cal_warmup, SimPer = per.cal )
  Qsim[[j]] <- SIM$OutputsModel$Qsim
  FO[[j]] <- SIM$EffCrit$CritValue
  
    #Darle paso a la barra de avance
  setTkProgressBar(pb, j, label=paste( round(j/n*100, 0),
                                       "% done"))
  
}

#Cerrar la barra de avance
close(pb)

Organice los resultados de las simulaciones

#Save Results

Qsim <- as.data.frame(do.call(cbind, Qsim))
Qsim <- cbind(seq(as.Date(per.cal[1]), as.Date(per.cal[2]), by="day"), Qsim)

FO <- do.call(rbind, FO)

Evalue la incertidumbre con la metodología GLUE

threshold <- 0.4 #limite para definir corridas comportamentales
parameters_beh <- parameters_set[FO > threshold,]
NSE_beh <- FO[FO > threshold]
Qsim_cal_beh <- Qsim[, FO > threshold]

Qsim_best <- Qsim[,(which.max(FO)+1)]
Qsim_best_m3s <- Qsim_best/(1000*60*60*24)*Area_cuenca_m2

weights <- NSE_beh - threshold
weights <- weights / sum(weights)

#con esto construyo la franja de 0.90 
limits <- apply(Qsim_cal_beh, 1, "wtd.quantile", weights = weights, probs = c(0.05,0.95), normwt=T)

limits_m3s <- limits/(1000*60*60*24)*Area_cuenca_m2

Qobs_cal <- as.Date(Entradas$DatesR)
Qobs_cal <- which(( Qobs_cal %in% per.cal_extend)==T)
Qobs_cal <- Entradas$Qmm[Qobs_cal]
Qobs_cal_m3s <- Qobs_cal/(1000*60*60*24)*Area_cuenca_m2

Grafico el intervalo de confianza

jpeg(filename = paste0( path,"/GLUE.jpeg"), width = 15, height = 10, units = "cm", res = 300) 
par(par(mfrow=c(2,2), mar=c(1, 5, 4, 1)+0.1, oma=c(0,0,0,0)+0.1))
plot(Qobs_cal_m3s, type="l", ylab="Q (m3/s)", xlab="", xaxt="n",
     main = "Banda de confianza")
lines(limits_m3s[1,], type="l", col="blue", lty=2)
lines(limits_m3s[2,], type="l", col="red", lty=3)
lines(Qsim_best_m3s, type="l", col="gray40")
lab <- seq(1,length(per.cal_extend),365)
axis(1,at=lab ,labels = year(per.cal_extend[lab]), las=2)
legend( "topleft",c("Qsim 95%","Qsim 5%", "Qsim","Qobs"), col = c("blue","red", "gray40", "black"), lty = c(2,3,1,1),
        cex=0.9, lwd=1)
dev.off()

Identifique la mejor FO y el mejor conjunto de parámetros

NSE_max <- max(FO)
NSE_max_pars <- parameters_set[which(FO==NSE_max),]

Haga sus dotty plots

#Dotty plots
jpeg(filename = paste0( path,"/DOTTY_PLOTS.jpeg"), width = 15, height = 10, units = "cm", res = 300) 
par(mfrow = c(2, 2), mar=rep(3,4), oma=c(0.5,1,0.5,0.5))
plot(parameters_set[,1], 1-FO, ylim=c(0,2), xlab="", ylab="", cex.lab=1, cex.axis=1) ; mtext("1-NSE",2, line = 2) ; mtext("X1",1, line = 2)
points(NSE_max_pars[1], 1-NSE_max, col="red", pch=15, cex=1)
plot(parameters_set[,2], 1-FO, ylim=c(0,2), xlab="", ylab="", cex.lab=1, cex.axis=1) ; mtext("1-NSE",2, line = 2) ; mtext("X2",1, line = 2)
points(NSE_max_pars[2], 1-NSE_max, col="red", pch=15, cex=1)
plot(parameters_set[,3], 1-FO, ylim=c(0,2), xlab="", ylab="", cex.lab=1, cex.axis=1) ; mtext("1-NSE",2, line = 2) ; mtext("X3",1, line = 2)
points(NSE_max_pars[3], 1-NSE_max, col="red", pch=15, cex=1)
plot(parameters_set[,4], 1-FO, ylim=c(0,2), xlab="", ylab="", cex.lab=1, cex.axis=1) ; mtext("1-NSE",2, line = 2) ; mtext("X4",1, line = 2)
points(NSE_max_pars[4], 1-NSE_max, col="red", pch=15, cex=1)
dev.off()

Grafique la mejor hidrógrafa de calibración

jpeg(filename = paste0( path,"/Hidro_Cal.jpeg"), width = 15, height = 10, units = "cm", res = 300)
par(par(mfrow=c(2,2),  mar=c(1, 5, 4, 1)+0.1, oma=c(0,0,0,0)+0.1))
plot(Qobs_cal_m3s, type="l", col="black", ylab="Q (m3/s)", xlab="", xaxt="n")
lines(Qsim_best_m3s, type="l", col ="red")
title(paste("NSE_Cal =",round(NSE_max,3)))
lab <- seq(1,length(per.cal_extend),365)
axis(1,at=lab ,labels = year(per.cal_extend[lab]), las=2)
legend( "topleft",c("Qsim", "Qobs"), col = c("red", "black"), lty = c(1,1))
dev.off()

Ahora se hace la validación

SIM <- SimGR(PrepGR = PREP, Param = NSE_max_pars, EffCrit = "NSE",
             WupPer = per.val_warmup, SimPer = per.val)
Qsim_val <- SIM$OutputsModel$Qsim
Qsim_val_m3s <- Qsim_val/(1000*60*60*24)*Area_cuenca_m2

FO_val <- SIM$EffCrit$CritValue

Qobs_val <- as.Date(Entradas$DatesR)
Qobs_val <- which(( Qobs_val %in% per.val_extend)==T)
Qobs_val <- Entradas$Qmm[Qobs_val]
Qobs_val_m3s <- Qobs_val/(1000*60*60*24)*Area_cuenca_m2

Grafique la validación

jpeg(filename = paste0( path,"/Hidro_Val.jpeg"), width = 15, height = 10, units = "cm", res = 300)
  plot(Qobs_val_m3s, type="l", col="black", ylab="Q (m3/s)", xlab="", xaxt="n")
lines(Qsim_val_m3s, type="l", col ="red")
title(paste("NSE_Val =",round(FO_val,3)))
lab <- seq(1,length(per.val_extend),366)
axis(1,at=lab ,labels = year(per.val_extend[lab]), las=2)
legend( "topright",c("Simulados", "Observados"), col = c("red", "black"), lty = c(1,1))
dev.off()

Guarde las series simuladas

#calibración
q_cal_save <- cbind(per.cal_extend,Qsim_best, Qsim_best_m3s)
q_cal_save <- as.data.frame(q_cal_save)
colnames(q_cal_save) <- c("Fecha", "Q(mm/dia)", "Q(m3/s)")
q_cal_save$Fecha <- as.Date(q_cal_save$Fecha)
write.csv(q_cal_save, "Resultados_calibración.csv", row.names = F)

#parámetros
write.csv(NSE_max_pars, "Parámetros.csv")

#validación
q_val_save <- cbind(per.val_extend,Qsim_val, Qsim_val_m3s)
q_val_save <- as.data.frame(q_val_save)
colnames(q_val_save) <- c("Fecha", "Q(mm/dia)", "Q(m3/s)")
q_val_save$Fecha <- as.Date(q_val_save$Fecha)
write.csv(q_val_save, "Resultados_validación.csv", row.names = F)
LS0tDQp0aXRsZTogIk1vZGVsbyBHUjRKIGVuIHVuYSBjdWVuY2Egc2ludMOpdGljYSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCkluaWNpYW1vcyBsaW1waWFuZG8gbGFzIHZhcmlhYmxlcyBkZWwgZW50b3JubyBkZSB0cmFiYWpvIHkgZGVmaW5pZW5kbyBsYXMgbGlicmVyw61hcyBhIHNlciB1dGlsaXphZGFzDQoNCmBgYHtyfQ0Kcm0obGlzdD1scygpKQ0KDQpsaWJyYXJ5KGFpckdSdGVhY2hpbmcpDQpsaWJyYXJ5KHRjbHRrKQ0KbGlicmFyeShIbWlzYykNCmxpYnJhcnkoU29pbEh5UCkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh6b28pDQpsaWJyYXJ5KGFpckdSKQ0KDQpgYGANCg0KRGVmaW5hIGxhIHJ1dGEgZGUgdHJhYmFqbw0KDQpgYGB7cn0NCnBhdGggPC0gIlo6L015IERyaXZlL1BFUlNPTkFMRVMvVFJBQkFKT1MvRE9DRU5DSUEvMjAyMyBDVVJTTyBNT0RFTEFDSU9OIFVOSUNBVUNBLzItIE1BVEVSSUFML0NMQVNFUy9TRVNJT04gNC9UQUxMRVIgR1I0SiINCnNldHdkKHBhdGgpDQpgYGANCg0KRGVmaW5hIGVsIMOhcmVhIGRlIGxhIGN1ZW5jYS4NCg0KYGBge3J9DQpBcmVhX2N1ZW5jYV9rbTIgPC0gMTU2LjYNCkFyZWFfY3VlbmNhX20yIDwtIEFyZWFfY3VlbmNhX2ttMioxMDAwMDAwDQoNCmBgYA0KDQpDYXJndWUgZWwgYXJjaGl2byBjb24gbGFzIHZhcmlhYmxlcyBkZSBlbnRyYWRhIGFsIG1vZGVsbw0KDQpgYGB7cn0NCkVudHJhZGFzIDwtIHJlYWQuY3N2KCJEYXRvc0RpYXJpb3NfQ3VlbmNhU2ludGV0aWNhLmNzdiIpDQpFbnRyYWRhcyA8LSBkYXRhLmZyYW1lKCJEYXRlc1IiPUVudHJhZGFzJEZlY2hhLCAiUCI9RW50cmFkYXMkUF9tbSwgIkUiPUVudHJhZGFzJEV0cF9tbSwgIlFtbSI9RW50cmFkYXMkUV9tMy5zKQ0KRW50cmFkYXMkUW1tIDwtIEVudHJhZGFzJFFtbS9BcmVhX2N1ZW5jYV9tMiooNjAqNjAqMjQpKigxMDAwKQ0KDQpFbnRyYWRhcyREYXRlc1IgPC0gYXMuUE9TSVhjdChFbnRyYWRhcyREYXRlc1IsIGZvcm1hdD0iJWQvJW0vJVkiLCB0ej0iVVRDIikNCg0KDQpgYGANCg0KRGVmaW5hIGVsIG7Dum1lcm8gZGUgY29ycmlkYXMNCg0KYGBge3J9DQoNCm4gPC0gMTAwICNudW1lcm8gZGUgY29ycmlkYXMNCmBgYA0KDQpEZWZpbmEgbG9zIHBlcmlvZG9zIGRlIG1vZGVsYWNpw7NuDQoNCmBgYHtyfQ0KDQpwZXIuY2FsX3dhcm11cCA8LSBjKCIyMDAzLTAxLTAxIiwgIjIwMDMtMTItMzEiKQ0KcGVyLmNhbF93YXJtdXBfZXh0ZW5kIDwtIHNlcShhcy5EYXRlKHBlci5jYWxfd2FybXVwWzFdKSwgYXMuRGF0ZShwZXIuY2FsX3dhcm11cFsyXSksIGJ5PSJkYXkiKQ0KDQpwZXIuY2FsIDwtIGMoIjIwMDQtMDEtMDEiLCAiMjAxMS0xMi0zMSIpDQpwZXIuY2FsX2V4dGVuZCA8LSBzZXEoYXMuRGF0ZShwZXIuY2FsWzFdKSwgYXMuRGF0ZShwZXIuY2FsWzJdKSwgYnk9ImRheSIpDQoNCnBlci52YWxfd2FybXVwIDwtIGMoIjIwMTEtMDEtMDEiLCAiMjAxMS0xMi0zMSIpDQpwZXIudmFsX3dhcm11cF9leHRlbmQgPC0gc2VxKGFzLkRhdGUocGVyLnZhbF93YXJtdXBbMV0pLCBhcy5EYXRlKHBlci52YWxfd2FybXVwWzJdKSwgYnk9ImRheSIpDQoNCnBlci52YWwgPC0gYygiMjAxMi0wMS0wMSIsICIyMDE1LTEyLTMxIikNCnBlci52YWxfZXh0ZW5kIDwtIHNlcShhcy5EYXRlKHBlci52YWxbMV0pLCBhcy5EYXRlKHBlci52YWxbMl0pLCBieT0iZGF5IikNCg0KDQpgYGANCg0KRGVmaW5hIGVsIGzDrW1pdGUgZGUgbG9zIHBhcsOhbWV0cm9zDQoNCmBgYHtyfQ0KIyMgU2ltdWxhdGlvbiBzdGVwIHVzaW5nIG1vZGVsIHBhcmFtZXRlcnMgc2V0IGJ5IHRoZSB1c2VyDQpwYXJfbmFtZXMgPC0gYygiWDEiLCAiWDIiLCAiWDMiLCAiWDQiKQ0KbGltX2luZiA8LSBjKDIwLCAtNSwyMCwxKQ0KbGltX3N1cCA8LSBjKDEyMDAsIDMsIDUwMCwgNSkNCmBgYA0KDQpHZW5lcmUgbG9zIGNvbmp1bnRvcyBkZSBwYXLDoW1ldHJvcyBhIHRyYXbDqXMgZGVsIG3DqXRvZG8gTW9udGUgQ2FybG8NCg0KYGBge3J9DQojIE1vbnRlY2FybG8gUGFyYW1ldGVycyBzZXQgLSB1bmlmb3JtIGRpc3RyaWJ1dGlvbg0KcGFyYW1ldGVyc19zZXQgPC0gbWF0cml4KG5jb2wgPSA0LCBucm93ID0gbikNCmNvbG5hbWVzKHBhcmFtZXRlcnNfc2V0KSA8LSBwYXJfbmFtZXMNCg0KZm9yKGkgaW4gMTpsZW5ndGgocGFyX25hbWVzKSl7DQogIHBhcmFtZXRlcnNfc2V0WyxpXSA8LSBydW5pZihuLCBtaW49bGltX2luZltpXSwgbWF4PWxpbV9zdXBbaV0pDQp9DQoNCmBgYA0KDQpSZWFsaWNlIGxhIGNhbGlicmFjacOzbiBjb24gbGFzIHNpbXVsYWNpb25lcyBNb250ZSBDYXJsby4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNhcXVpIHZhbW9zIGEgZ3VhcmRhciBsb3MgcmVzdWx0YWRvcyBkZSBsYXMgbiBzaW11bGFjaW9uZXMgeSBsYXMgbiBGTw0KUXNpbSA8LSBsaXN0KCkNCkZPIDwtIGxpc3QoKQ0KDQpQUkVQIDwtIFByZXBHUihPYnNERiA9IEVudHJhZGFzLCBIeWRyb01vZGVsID0gIkdSNEoiLCBDZW1hTmVpZ2UgPSBGQUxTRSkNCg0KI2JhcnJhIGRlIGF2YW5jZQ0KcGIgPC0gdGtQcm9ncmVzc0Jhcih0aXRsZSA9ICJDYWxpYnJhbmRvIEdSNEoiLCBtaW4gPSAwLA0KICAgICAgICAgICAgICAgICAgICBtYXggPSBuLCB3aWR0aCA9IDMwMCkNCg0KZm9yKGogaW4gMTpuKXsNCiAgDQogIFNJTSA8LSBTaW1HUihQcmVwR1IgPSBQUkVQLCBQYXJhbSA9IHBhcmFtZXRlcnNfc2V0W2osXSwgRWZmQ3JpdCA9ICJOU0UiLA0KICAgICAgICAgICAgICAgV3VwUGVyID0gcGVyLmNhbF93YXJtdXAsIFNpbVBlciA9IHBlci5jYWwgKQ0KICBRc2ltW1tqXV0gPC0gU0lNJE91dHB1dHNNb2RlbCRRc2ltDQogIEZPW1tqXV0gPC0gU0lNJEVmZkNyaXQkQ3JpdFZhbHVlDQogIA0KICAgICNEYXJsZSBwYXNvIGEgbGEgYmFycmEgZGUgYXZhbmNlDQogIHNldFRrUHJvZ3Jlc3NCYXIocGIsIGosIGxhYmVsPXBhc3RlKCByb3VuZChqL24qMTAwLCAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIlIGRvbmUiKSkNCiAgDQp9DQoNCiNDZXJyYXIgbGEgYmFycmEgZGUgYXZhbmNlDQpjbG9zZShwYikNCmBgYA0KDQpPcmdhbmljZSBsb3MgcmVzdWx0YWRvcyBkZSBsYXMgc2ltdWxhY2lvbmVzDQoNCmBgYHtyfQ0KI1NhdmUgUmVzdWx0cw0KDQpRc2ltIDwtIGFzLmRhdGEuZnJhbWUoZG8uY2FsbChjYmluZCwgUXNpbSkpDQpRc2ltIDwtIGNiaW5kKHNlcShhcy5EYXRlKHBlci5jYWxbMV0pLCBhcy5EYXRlKHBlci5jYWxbMl0pLCBieT0iZGF5IiksIFFzaW0pDQoNCkZPIDwtIGRvLmNhbGwocmJpbmQsIEZPKQ0KDQpgYGANCg0KRXZhbHVlIGxhIGluY2VydGlkdW1icmUgY29uIGxhIG1ldG9kb2xvZ8OtYSBHTFVFDQoNCmBgYHtyfQ0KdGhyZXNob2xkIDwtIDAuNCAjbGltaXRlIHBhcmEgZGVmaW5pciBjb3JyaWRhcyBjb21wb3J0YW1lbnRhbGVzDQpwYXJhbWV0ZXJzX2JlaCA8LSBwYXJhbWV0ZXJzX3NldFtGTyA+IHRocmVzaG9sZCxdDQpOU0VfYmVoIDwtIEZPW0ZPID4gdGhyZXNob2xkXQ0KUXNpbV9jYWxfYmVoIDwtIFFzaW1bLCBGTyA+IHRocmVzaG9sZF0NCg0KUXNpbV9iZXN0IDwtIFFzaW1bLCh3aGljaC5tYXgoRk8pKzEpXQ0KUXNpbV9iZXN0X20zcyA8LSBRc2ltX2Jlc3QvKDEwMDAqNjAqNjAqMjQpKkFyZWFfY3VlbmNhX20yDQoNCndlaWdodHMgPC0gTlNFX2JlaCAtIHRocmVzaG9sZA0Kd2VpZ2h0cyA8LSB3ZWlnaHRzIC8gc3VtKHdlaWdodHMpDQoNCiNjb24gZXN0byBjb25zdHJ1eW8gbGEgZnJhbmphIGRlIDAuOTAgDQpsaW1pdHMgPC0gYXBwbHkoUXNpbV9jYWxfYmVoLCAxLCAid3RkLnF1YW50aWxlIiwgd2VpZ2h0cyA9IHdlaWdodHMsIHByb2JzID0gYygwLjA1LDAuOTUpLCBub3Jtd3Q9VCkNCg0KbGltaXRzX20zcyA8LSBsaW1pdHMvKDEwMDAqNjAqNjAqMjQpKkFyZWFfY3VlbmNhX20yDQoNClFvYnNfY2FsIDwtIGFzLkRhdGUoRW50cmFkYXMkRGF0ZXNSKQ0KUW9ic19jYWwgPC0gd2hpY2goKCBRb2JzX2NhbCAlaW4lIHBlci5jYWxfZXh0ZW5kKT09VCkNClFvYnNfY2FsIDwtIEVudHJhZGFzJFFtbVtRb2JzX2NhbF0NClFvYnNfY2FsX20zcyA8LSBRb2JzX2NhbC8oMTAwMCo2MCo2MCoyNCkqQXJlYV9jdWVuY2FfbTINCg0KYGBgDQoNCkdyYWZpY28gZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YQ0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KanBlZyhmaWxlbmFtZSA9IHBhc3RlMCggcGF0aCwiL0dMVUUuanBlZyIpLCB3aWR0aCA9IDE1LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCByZXMgPSAzMDApIA0KcGFyKHBhcihtZnJvdz1jKDIsMiksIG1hcj1jKDEsIDUsIDQsIDEpKzAuMSwgb21hPWMoMCwwLDAsMCkrMC4xKSkNCnBsb3QoUW9ic19jYWxfbTNzLCB0eXBlPSJsIiwgeWxhYj0iUSAobTMvcykiLCB4bGFiPSIiLCB4YXh0PSJuIiwNCiAgICAgbWFpbiA9ICJCYW5kYSBkZSBjb25maWFuemEiKQ0KbGluZXMobGltaXRzX20zc1sxLF0sIHR5cGU9ImwiLCBjb2w9ImJsdWUiLCBsdHk9MikNCmxpbmVzKGxpbWl0c19tM3NbMixdLCB0eXBlPSJsIiwgY29sPSJyZWQiLCBsdHk9MykNCmxpbmVzKFFzaW1fYmVzdF9tM3MsIHR5cGU9ImwiLCBjb2w9ImdyYXk0MCIpDQpsYWIgPC0gc2VxKDEsbGVuZ3RoKHBlci5jYWxfZXh0ZW5kKSwzNjUpDQpheGlzKDEsYXQ9bGFiICxsYWJlbHMgPSB5ZWFyKHBlci5jYWxfZXh0ZW5kW2xhYl0pLCBsYXM9MikNCmxlZ2VuZCggInRvcGxlZnQiLGMoIlFzaW0gOTUlIiwiUXNpbSA1JSIsICJRc2ltIiwiUW9icyIpLCBjb2wgPSBjKCJibHVlIiwicmVkIiwgImdyYXk0MCIsICJibGFjayIpLCBsdHkgPSBjKDIsMywxLDEpLA0KICAgICAgICBjZXg9MC45LCBsd2Q9MSkNCmRldi5vZmYoKQ0KYGBgDQoNCklkZW50aWZpcXVlIGxhIG1lam9yIEZPIHkgZWwgbWVqb3IgY29uanVudG8gZGUgcGFyw6FtZXRyb3MNCg0KYGBge3J9DQpOU0VfbWF4IDwtIG1heChGTykNCk5TRV9tYXhfcGFycyA8LSBwYXJhbWV0ZXJzX3NldFt3aGljaChGTz09TlNFX21heCksXQ0KYGBgDQoNCkhhZ2Egc3VzIGRvdHR5IHBsb3RzDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojRG90dHkgcGxvdHMNCmpwZWcoZmlsZW5hbWUgPSBwYXN0ZTAoIHBhdGgsIi9ET1RUWV9QTE9UUy5qcGVnIiksIHdpZHRoID0gMTUsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHJlcyA9IDMwMCkgDQpwYXIobWZyb3cgPSBjKDIsIDIpLCBtYXI9cmVwKDMsNCksIG9tYT1jKDAuNSwxLDAuNSwwLjUpKQ0KcGxvdChwYXJhbWV0ZXJzX3NldFssMV0sIDEtRk8sIHlsaW09YygwLDIpLCB4bGFiPSIiLCB5bGFiPSIiLCBjZXgubGFiPTEsIGNleC5heGlzPTEpIDsgbXRleHQoIjEtTlNFIiwyLCBsaW5lID0gMikgOyBtdGV4dCgiWDEiLDEsIGxpbmUgPSAyKQ0KcG9pbnRzKE5TRV9tYXhfcGFyc1sxXSwgMS1OU0VfbWF4LCBjb2w9InJlZCIsIHBjaD0xNSwgY2V4PTEpDQpwbG90KHBhcmFtZXRlcnNfc2V0WywyXSwgMS1GTywgeWxpbT1jKDAsMiksIHhsYWI9IiIsIHlsYWI9IiIsIGNleC5sYWI9MSwgY2V4LmF4aXM9MSkgOyBtdGV4dCgiMS1OU0UiLDIsIGxpbmUgPSAyKSA7IG10ZXh0KCJYMiIsMSwgbGluZSA9IDIpDQpwb2ludHMoTlNFX21heF9wYXJzWzJdLCAxLU5TRV9tYXgsIGNvbD0icmVkIiwgcGNoPTE1LCBjZXg9MSkNCnBsb3QocGFyYW1ldGVyc19zZXRbLDNdLCAxLUZPLCB5bGltPWMoMCwyKSwgeGxhYj0iIiwgeWxhYj0iIiwgY2V4LmxhYj0xLCBjZXguYXhpcz0xKSA7IG10ZXh0KCIxLU5TRSIsMiwgbGluZSA9IDIpIDsgbXRleHQoIlgzIiwxLCBsaW5lID0gMikNCnBvaW50cyhOU0VfbWF4X3BhcnNbM10sIDEtTlNFX21heCwgY29sPSJyZWQiLCBwY2g9MTUsIGNleD0xKQ0KcGxvdChwYXJhbWV0ZXJzX3NldFssNF0sIDEtRk8sIHlsaW09YygwLDIpLCB4bGFiPSIiLCB5bGFiPSIiLCBjZXgubGFiPTEsIGNleC5heGlzPTEpIDsgbXRleHQoIjEtTlNFIiwyLCBsaW5lID0gMikgOyBtdGV4dCgiWDQiLDEsIGxpbmUgPSAyKQ0KcG9pbnRzKE5TRV9tYXhfcGFyc1s0XSwgMS1OU0VfbWF4LCBjb2w9InJlZCIsIHBjaD0xNSwgY2V4PTEpDQpkZXYub2ZmKCkNCg0KYGBgDQoNCkdyYWZpcXVlIGxhIG1lam9yIGhpZHLDs2dyYWZhIGRlIGNhbGlicmFjacOzbg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KanBlZyhmaWxlbmFtZSA9IHBhc3RlMCggcGF0aCwiL0hpZHJvX0NhbC5qcGVnIiksIHdpZHRoID0gMTUsIGhlaWdodCA9IDEwLCB1bml0cyA9ICJjbSIsIHJlcyA9IDMwMCkNCnBhcihwYXIobWZyb3c9YygyLDIpLCAgbWFyPWMoMSwgNSwgNCwgMSkrMC4xLCBvbWE9YygwLDAsMCwwKSswLjEpKQ0KcGxvdChRb2JzX2NhbF9tM3MsIHR5cGU9ImwiLCBjb2w9ImJsYWNrIiwgeWxhYj0iUSAobTMvcykiLCB4bGFiPSIiLCB4YXh0PSJuIikNCmxpbmVzKFFzaW1fYmVzdF9tM3MsIHR5cGU9ImwiLCBjb2wgPSJyZWQiKQ0KdGl0bGUocGFzdGUoIk5TRV9DYWwgPSIscm91bmQoTlNFX21heCwzKSkpDQpsYWIgPC0gc2VxKDEsbGVuZ3RoKHBlci5jYWxfZXh0ZW5kKSwzNjUpDQpheGlzKDEsYXQ9bGFiICxsYWJlbHMgPSB5ZWFyKHBlci5jYWxfZXh0ZW5kW2xhYl0pLCBsYXM9MikNCmxlZ2VuZCggInRvcGxlZnQiLGMoIlFzaW0iLCAiUW9icyIpLCBjb2wgPSBjKCJyZWQiLCAiYmxhY2siKSwgbHR5ID0gYygxLDEpKQ0KZGV2Lm9mZigpDQpgYGANCg0KQWhvcmEgc2UgaGFjZSBsYSB2YWxpZGFjacOzbg0KDQpgYGB7cn0NClNJTSA8LSBTaW1HUihQcmVwR1IgPSBQUkVQLCBQYXJhbSA9IE5TRV9tYXhfcGFycywgRWZmQ3JpdCA9ICJOU0UiLA0KICAgICAgICAgICAgIFd1cFBlciA9IHBlci52YWxfd2FybXVwLCBTaW1QZXIgPSBwZXIudmFsKQ0KUXNpbV92YWwgPC0gU0lNJE91dHB1dHNNb2RlbCRRc2ltDQpRc2ltX3ZhbF9tM3MgPC0gUXNpbV92YWwvKDEwMDAqNjAqNjAqMjQpKkFyZWFfY3VlbmNhX20yDQoNCkZPX3ZhbCA8LSBTSU0kRWZmQ3JpdCRDcml0VmFsdWUNCg0KUW9ic192YWwgPC0gYXMuRGF0ZShFbnRyYWRhcyREYXRlc1IpDQpRb2JzX3ZhbCA8LSB3aGljaCgoIFFvYnNfdmFsICVpbiUgcGVyLnZhbF9leHRlbmQpPT1UKQ0KUW9ic192YWwgPC0gRW50cmFkYXMkUW1tW1FvYnNfdmFsXQ0KUW9ic192YWxfbTNzIDwtIFFvYnNfdmFsLygxMDAwKjYwKjYwKjI0KSpBcmVhX2N1ZW5jYV9tMg0KYGBgDQoNCkdyYWZpcXVlIGxhIHZhbGlkYWNpw7NuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpqcGVnKGZpbGVuYW1lID0gcGFzdGUwKCBwYXRoLCIvSGlkcm9fVmFsLmpwZWciKSwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgcmVzID0gMzAwKQ0KICBwbG90KFFvYnNfdmFsX20zcywgdHlwZT0ibCIsIGNvbD0iYmxhY2siLCB5bGFiPSJRIChtMy9zKSIsIHhsYWI9IiIsIHhheHQ9Im4iKQ0KbGluZXMoUXNpbV92YWxfbTNzLCB0eXBlPSJsIiwgY29sID0icmVkIikNCnRpdGxlKHBhc3RlKCJOU0VfVmFsID0iLHJvdW5kKEZPX3ZhbCwzKSkpDQpsYWIgPC0gc2VxKDEsbGVuZ3RoKHBlci52YWxfZXh0ZW5kKSwzNjYpDQpheGlzKDEsYXQ9bGFiICxsYWJlbHMgPSB5ZWFyKHBlci52YWxfZXh0ZW5kW2xhYl0pLCBsYXM9MikNCmxlZ2VuZCggInRvcHJpZ2h0IixjKCJTaW11bGFkb3MiLCAiT2JzZXJ2YWRvcyIpLCBjb2wgPSBjKCJyZWQiLCAiYmxhY2siKSwgbHR5ID0gYygxLDEpKQ0KZGV2Lm9mZigpDQpgYGANCg0KR3VhcmRlIGxhcyBzZXJpZXMgc2ltdWxhZGFzDQoNCmBgYHtyfQ0KI2NhbGlicmFjacOzbg0KcV9jYWxfc2F2ZSA8LSBjYmluZChwZXIuY2FsX2V4dGVuZCxRc2ltX2Jlc3QsIFFzaW1fYmVzdF9tM3MpDQpxX2NhbF9zYXZlIDwtIGFzLmRhdGEuZnJhbWUocV9jYWxfc2F2ZSkNCmNvbG5hbWVzKHFfY2FsX3NhdmUpIDwtIGMoIkZlY2hhIiwgIlEobW0vZGlhKSIsICJRKG0zL3MpIikNCnFfY2FsX3NhdmUkRmVjaGEgPC0gYXMuRGF0ZShxX2NhbF9zYXZlJEZlY2hhKQ0Kd3JpdGUuY3N2KHFfY2FsX3NhdmUsICJSZXN1bHRhZG9zX2NhbGlicmFjacOzbi5jc3YiLCByb3cubmFtZXMgPSBGKQ0KDQojcGFyw6FtZXRyb3MNCndyaXRlLmNzdihOU0VfbWF4X3BhcnMsICJQYXLDoW1ldHJvcy5jc3YiKQ0KDQojdmFsaWRhY2nDs24NCnFfdmFsX3NhdmUgPC0gY2JpbmQocGVyLnZhbF9leHRlbmQsUXNpbV92YWwsIFFzaW1fdmFsX20zcykNCnFfdmFsX3NhdmUgPC0gYXMuZGF0YS5mcmFtZShxX3ZhbF9zYXZlKQ0KY29sbmFtZXMocV92YWxfc2F2ZSkgPC0gYygiRmVjaGEiLCAiUShtbS9kaWEpIiwgIlEobTMvcykiKQ0KcV92YWxfc2F2ZSRGZWNoYSA8LSBhcy5EYXRlKHFfdmFsX3NhdmUkRmVjaGEpDQp3cml0ZS5jc3YocV92YWxfc2F2ZSwgIlJlc3VsdGFkb3NfdmFsaWRhY2nDs24uY3N2Iiwgcm93Lm5hbWVzID0gRikNCg0KDQoNCmBgYA0K