R Code for Simulation

## Function to get trace of a m atrix
func_trace <- function(X){
  n <- dim(X)[1] 
  tr <- 0    ### initialize trace 
  
  for (j in 1:n){
    k <- X[j,j]
    tr <- tr + k
  }
  return(tr[[1]])
}


# Function to compute inv(J)
func_Jinv <- function(X,Z,W,G_inv){
  D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
  D2h_BU <- t(X)%*%W%*%Z
  D2h_UB <- t(Z)%*%W%*%X
  D2h_UU <- t(Z)%*%W%*%Z + G_inv
  J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (143+9) by  (9+143) Jacobian
  J <- as.matrix(J)
  J_inv <- solve(J)
  return(J_inv)
  
}

## Simulated fixed effects data
sim_x <- function(j){
  X <- c()   
  if(j==2){
    for (i in 1:m){
      Xsim <- as.matrix(sample(c(1,0),n,replace=TRUE))
      X <- rbind(X, Xsim)
    }  
  }else if(j==3){
    for (i in 1:m){
      Xsim = as.matrix(sample(c("XC1","XC2","XC3"),n,replace=TRUE))
      X <- rbind(X, Xsim)
    }
  }
  return(X)
}
########### ---------------------------------------------------------#############
###########                        Simulate data - START             #############
########### ---------------------------------------------------------#############


# areas <- c(5,10,20,30)   # Select number of small areas
# sample_size <- c(30,50,100,500)  # area wise sample size

areas <- c(5)   # Select number of small areas
sample_size <- c(30,50,100,500)  # area wise sample size
nsim <- 1000
# set.seed(123)
sim_seed <- seq(1000,1999,1)


theta_sim <- 0.1  # theta to create simulated data
beta_sim <- c(-1.5,1.3,1.5)
beta_sim <- as.matrix(beta_sim)

all_iters <- names_iter <- run_time_all <- u_sim_ls3 <- list()
final_ests <- list()

for(q in 1:length(areas)){
  
  # q <- 4
  m <- areas[q]
  u_sim <- as.matrix(rnorm(m,0,sd=sqrt(theta_sim)))
  
  conv_beta <- beta_sim; conv_u <- u_sim; conv_theta <- theta_sim; conv_iter <- 0;
  mean_beta_hglm <- data.frame(True=beta_sim); mean_u_hglm <- data.frame(True=u_sim); 
  mean_theta_hglm <- data.frame(True=theta_sim); mean_beta_glmm <- data.frame(True=beta_sim);
  mean_u_glmm <- data.frame(True=u_sim); mean_theta_glmm <- data.frame(True=theta_sim)
  MSE_glmm <- list()
  glmm_nameB <- hglm_nameB <- glmm_nameU<-hglm_nameU<-glmm_nameT<- hglm_nameT<- "true" ; 
  MSE_temp <- c(); name_MSE <- c();conv_name <- c()
  conv_iter_all <- MSE_glmm0 <- u_sim_ls2  <- list()
  run_time_s <- c()
  
  for(s in 1:length(sample_size)){
    
    # s <- 4
    all_beta_sim <- data.frame(True=beta_sim); all_u_sim <- data.frame(True=u_sim); 
    all_theta_sim <- data.frame(True=theta_sim)
    all_beta_glmm <- all_u_glmm <- all_theta_glmm <- u_sim_ls <- list()
    err_all_sims <- namesErr <- conv_iter <- c()
    SSE_beta_glmm <- rep(0,length(beta_sim)); SSE_u_glmm <- rep(0,m); 
    SSE_theta_glmm <- rep(0,length(theta_sim))
    
    start_time <- Sys.time()
    
    for(r in 1:nsim){
      # r <- 1
      set.seed(sim_seed[r]) 
      n <- sample_size[s]   # Areawise sample size
      grps <- c(2,2)  # Select the number of categorical fixed effects and groups in each var
      j <- 0   # Select the number of fixed effects (continuous vars)
      theta0 <- 0.1 
      N <- n*m    # Total sample size
      
      # create county variable
      county <- c()
      for (i in 1:m){
        cnty <- as.matrix(rep(c(i),n))
        county <- rbind(county, cnty)
      } 
      
      # create each discrete var and combine to a df
      fixed_eff_ds <- data.frame(county)
      for(k in 1:length(grps)){
        tempX <- sim_x(grps[k])   # call func and create dis fixed effects data
        colnames(tempX) <- paste0("X",k)
        fixed_eff_ds <- cbind.data.frame(fixed_eff_ds,tempX)
      }
      
      
      fixed_eff_ct <- cbind.data.frame(XX1=log(rnorm(N,mean=60,sd=3)),
                                       XX2=log(rnorm(N,mean=80000,sd=30)))
      
      char_var <- colnames(fixed_eff_ds)  # col names of fixed effects - discrete
      vars_ds <- char_var[1:(length(grps)+1)]   # No of fixed effects(discrete) to consider for modelling
      
      cnt_var <- colnames(fixed_eff_ct)  # col names of fixed effects - continuous
      if(j!=0){  # No of fixed effects (continuous) for modelling
        vars_ct <- cnt_var[1:j]  
      }else{
        vars_ct <- NULL
      }
      df_sim <- cbind.data.frame(fixed_eff_ds[,colnames(fixed_eff_ds)%in%vars_ds],
                                 fixed_eff_ct[,colnames(fixed_eff_ct)%in%vars_ct])
      df_sim <- df_sim[order(df_sim$county), ]
      
      colnames(df_sim) <- c(colnames(fixed_eff_ds)[which(colnames(fixed_eff_ds)%in%vars_ds)],
                            colnames(fixed_eff_ct)[which(colnames(fixed_eff_ct)%in%vars_ct)])
      
      table(df_sim$county,df_sim$X1)
      table(df_sim$county,df_sim$X2)
      
      
      ## Simulated random effects given theta
      # theta_sim <- 1   
      # u_sim <- as.matrix(rnorm(m,0,sd=sqrt(theta_sim)))
      # u_sim <- as.matrix(qnorm(runif(m, min=pnorm(-2, sd=sqrt(theta_sim)),
      #                                max=pnorm(2, sd=sqrt(theta_sim))), 
      #                          sd=sqrt(theta_sim)))
      u_sim0 <- cbind.data.frame(county=unique(df_sim$county),u_sim)
      
      # Merge simulated fixed and random effects data
      data_all <- merge(df_sim,u_sim0,by.x="county",by.y="county")  
      data_all <- data_all[order(data_all$county), ]
      
      # # fixed effect - design matrix
      Xvars_ds <- vars_ds[!vars_ds %in% "county"]
      if(length(vars_ct) !=0){
        dm_form <-  as.formula(paste('~',paste('as.factor(',Xvars_ds,')', collapse = "+"),"+",vars_ct))
      }else if(length(vars_ct)==0){
        dm_form <-  as.formula(paste('~',paste('as.factor(',Xvars_ds,')', collapse = "+")))  
      }
      
      X <- model.matrix(dm_form,data=data_all)
      
      
      ##### Assign initial betas
      # beta_sim <- runif(ncol(X),min=0.5,max=2)   # beta for data simulation
      # beta_sim <- runif(ncol(X),min=-1,max=2)
      # beta_sim <- c(1.5,1.8,-2,1.2,-1.5)
      beta_sim <- as.matrix(beta_sim[1:ncol(X)])
      u <- as.matrix(data_all$u_sim)
      
      # Calculate binomial p 
      p0 <- exp(X%*%beta_sim+u)/(1+exp(X%*%beta_sim+u))
      y <- rbinom(N,1,p0)
      table(y)
      data <- cbind.data.frame(data_all,y)
      table(data$y, data$county)
      
      ### Define matrices and values for hglm modelling
      data <- data[order(data$county),]
      X <- X
      Z <- model.matrix(~0+as.factor(data$county))
      y <- data[,"y"]
      m <- m
      N <- n*m
      p <- ncol(X)
      
      ## Fit logit model to get initial fixed effects parameters 
      all_vars <- c(Xvars_ds,vars_ct)
      glm_formula <- as.formula(paste("y",'~',paste(all_vars, collapse = "+")))
      # glm_fit <- glm(y~as.factor(X3)+as.factor(X2)+as.factor(X1),family = binomial(link=logit),data=data)
      glm_fit <- glm(formula = glm_formula,family = binomial(link=logit),data=data)
      
      
      
      # Initial parameters
      beta0 <- as.numeric(glm_fit$coefficients)
      
      u0 <- as.matrix(runif(m,(u_sim-0.1),(u_sim+0.1)))
      
      
      
      ########### ---------------------------------------------------------#############
      ###########                        Simulate data - END               #############
      ########### ---------------------------------------------------------#############
      ###########                   Parameter Estimation - START           #############
      ########### ---------------------------------------------------------#############
      
      
      beta_new <- beta0
      u_new <- u0
      theta_new <- theta0
      
      beta_new_all <- data.frame(True=beta_sim) ;
      theta_new_FS <- data.frame(True=theta_sim) ; 
      theta_new_all <- data.frame(True=theta_sim);
      u_new_all <- data.frame(True=u_sim); 
      theta_all <- data.frame(True=theta_new)
      delta_final <- data.frame(True="NA")
      delta <- NULL ; 
      iter <- 0; iter_all <- "iter0"
      
      
      repeat{
        
        beta <- as.vector(beta_new)
        u <- as.vector(u_new)
        theta <- theta_new
        
        BU_old <- rbind(as.matrix(beta),as.matrix(u))
        
        theta_inv <- solve(theta)
        G_inv <- kronecker(theta_inv, diag(m))
        # G_inv
        
        P <- 1/(1+exp(-(X%*%beta+Z%*%u)))
        W <- diag(as.vector(P*(1-P)))
        D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
        D2h_BU <- t(X)%*%W%*%Z
        D2h_UB <- t(Z)%*%W%*%X
        D2h_UU <- t(Z)%*%W%*%Z + G_inv
        J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (m+p) by  (p+m) Jacobian
        J <- as.matrix(J)
        J_inv <- solve(J)
        
        
        D1h_B <- t(X)%*%(y-P)
        D1h_u <- t(Z)%*%(y-P)- G_inv%*%u
        S <- as.vector(rbind(D1h_B, D1h_u))    # Gradient (score function) vector  
        
        # Fisher scoring algorithm
        BU_new = BU_old + (J_inv%*%S)    
        
        beta_new <- as.vector(BU_new[1:length(beta)])
        u_new <- as.vector(BU_new[(length(beta)+1):length(BU_new)])
        
        # convergence_beta <- abs(beta_new[-1]-beta[-1])  
        convergence_beta <- abs(beta_new-beta)
        convergence_u <- abs(u_new-u)
        max(convergence_beta)
        max(convergence_u)
        
        beta_new_all <- cbind.data.frame(beta_new_all,value=round(beta_new,6))
        u_new_all <- cbind.data.frame(u_new_all,value=round(u_new,6))
        # iter <- c(iter0,iter)
        
        rm(P); rm(W); rm(J);
        # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
        #                                                                                 #
        #                                Bias Correction                                  #
        #                                                                                 #
        # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
        
        # Bias Corr step 1: update J with estimated beta and u
        
        P <- 1/(1+exp(-(X%*%beta_new+Z%*%u_new)))
        pp <- P*(1-P)
        W <- Diagonal(x=pp)
        
        D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
        D2h_BU <- t(X)%*%W%*%Z
        D2h_UB <- t(Z)%*%W%*%X
        D2h_UU <- t(Z)%*%W%*%Z + G_inv
        J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (m+p) by  (p+m) Jacobian
        J <- as.matrix(J)
        
        Jhat_Inv <- pseudoinverse(J)
        Tau <- Jhat_Inv[(p+1):(p+m),(p+1):(p+m)]
        Taut <- diag(Tau)
        zeta <- theta/(theta+Taut)
        corr_u <- zeta*u_new
        
        rm(P);rm(W); rm(J);
        # Use corrected u to estimate theta
        
        ########### ---------------------------------------------------------#############      
        ###########             Estimate theta=sigma^2 using Dh/Dtheta=0     #############
        ########### ---------------------------------------------------------#############
        
        
        ## Using SAE6 to estimate theta
        theta_inv <- solve(theta)
        G_inv <- kronecker(theta_inv, diag(m))
        
        P <- 1/(1+exp(-(X%*%beta_new+Z%*%corr_u)))
        W <- diag(as.vector(P*(1-P)))
        
        D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
        D2h_BU <- t(X)%*%W%*%Z
        D2h_UB <- t(Z)%*%W%*%X
        D2h_UU <- t(Z)%*%W%*%Z + G_inv
        J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (143+9) by  (9+143) Jacobian
        J <- as.matrix(J)
        J_inv <- solve(J)
        
        ###Estimate theta 
        J_inv22 <- J_inv[(p+1):(p+m),(p+1):(p+m)]
        theta_new <- 1/m*(t(u_new)%*%u_new)+1/m*func_trace(J_inv22)
        theta_new_all <- cbind.data.frame(theta_new_all,value=theta_new)
        
        convergence_theta <- abs(theta_new-theta)
        delta <- max(convergence_beta,convergence_theta)
        delta_final <- cbind.data.frame(delta_final,value=delta)
        
        est_out <- rbind.data.frame(beta_new_all,u_new_all,theta_new_all,value=delta_final)
        rownames(est_out) <- c(colnames(X),paste0("u_",unique(df_sim$county)),"theta","delta")
        
        
        ## rbind only beta, u and theta estimated values
        est_pars <- rbind.data.frame(beta_new_all,u_new_all,theta_new_all)
        
        iter <- iter + 1
        
        iter_all <- c(iter_all,paste0("iter",iter))
        
        if(delta <= 1e-5)break
      }
      
      colnames(u_new_all) <- iter_all
      u_sim_ls[[r]] <- u_new_all
      
      conv_iter <- c(conv_iter,iter)
      conv_iter_all[[s]] <- conv_iter
      
      
      SqErr_beta <- (beta_sim-beta_new)^2
      SqErr_u <- (u_sim-u_new)^2
      SqErr_theta <- (theta_sim-theta_new)^2
      
      
      err_all <- rbind.data.frame(SqErr_beta,SqErr_u,SqErr_theta)
      err_all_sims <- c(err_all_sims,err_all)
      err_all_sims <- data.frame(err_all_sims)
      rownames(err_all_sims) <- c(colnames(X),paste0("u_",unique(df_sim$county)),"theta")
      namesErr <- c(namesErr,paste0("Sq_Err_",r,"_sims")) 
      
      # print(paste0("Small area with sample size: ",n, " & No of sims: ",r))
      
      
      beta_new <- data.frame(beta_new)
      u_new <- data.frame(u_new)
      theta_new <- data.frame(theta_new)
      
      colnames(beta_new) <- paste0("sim_beta_",r,"_sims")
      colnames(u_new) <- paste0("sim_u_",r,"_sims")
      colnames(theta_new) <- paste0("sim_theta_",r,"_sims")
      
      all_beta_sim <- cbind.data.frame(all_beta_sim,beta_new)
      all_u_sim <- cbind.data.frame(all_u_sim, u_new)
      all_theta_sim <- cbind.data.frame(all_theta_sim, theta_new)
      
      
      ## poststratification method
      
      glmm_sim <- glmer(y ~ as.factor(X1) + as.factor(X2) + (1|county), 
                        data = data, family = binomial, weights=NULL, 
                        control = glmerControl(optimizer = "bobyqa"), nAGQ = 10)
      
      beta_glmm <- glmm_sim@beta
      u_glmm <- glmm_sim@u
      theta_glmm <- glmm_sim@theta
      
      ## Sum squared error of glmm estimates
      SSE_beta_glmm <-  SSE_beta_glmm + (beta_sim-beta_glmm)^2
      SSE_u_glmm <- SSE_u_glmm + (u_sim-u_glmm)^2
      SSE_theta_glmm <- SSE_theta_glmm + (theta_sim-theta_glmm)^2
      SSE_glmm <- rbind(SSE_beta_glmm,SSE_u_glmm,SSE_theta_glmm)
      row.names(SSE_glmm) <- c(colnames(X),paste0("glmm_u_",unique(df_sim$county)),"theta")
      
      all_beta_glmm[[r]] <- beta_glmm
      all_u_glmm[[r]] <- u_glmm
      all_theta_glmm[[r]] <- theta_glmm
    }
    
    u_sim_ls2[[s]] <- u_sim_ls
    
    colnames(err_all_sims) <- namesErr
    MSE <- rowSums(err_all_sims)/nsim
    MSE_temp <- cbind(MSE_temp,MSE)
    name_MSE <- c(name_MSE,paste0("MSE_",areas[q],"_",sample_size[s]))
    
    
    mean_beta_hglm <- cbind.data.frame(mean_beta_hglm,rowSums(all_beta_sim[,2:ncol(all_beta_sim)])/nsim)
    mean_u_hglm <- cbind.data.frame(mean_u_hglm,rowSums(all_u_sim[,2:ncol(all_u_sim)])/nsim)
    mean_theta_hglm <- cbind.data.frame(mean_theta_hglm,rowSums(all_theta_sim[,2:ncol(all_theta_sim)])/nsim)
    
    glmm_nameB <- c(glmm_nameB,paste0("glmm_mean_beta_",areas[q],"_",sample_size[s]))
    glmm_nameU <- c(glmm_nameU,paste0("glmm_mean_u_",areas[q],"_",sample_size[s]))
    glmm_nameT <- c(glmm_nameT,paste0("glmm_mean_theta_",areas[q],"_",sample_size[s]))
    
    hglm_nameB <- c(hglm_nameB,paste0("hglm_mean_beta_",areas[q],"_",sample_size[s]))
    hglm_nameU <- c(hglm_nameU,paste0("hglm_mean_u_",areas[q],"_",sample_size[s]))
    hglm_nameT <- c(hglm_nameT,paste0("hglm_mean_theta_",areas[q],"_",sample_size[s]))
    
    
    ### MSE and estimated parameters using glmm
    MSE_beta_glmm0 <- SSE_beta_glmm/nsim
    MSE_u_glmm0 <- SSE_u_glmm/nsim
    # MSE_glmm0 <- SSE_glmm/nsim
    MSE_glmm0[[s]] <- SSE_glmm/nsim
    
    all_beta_glmm <- do.call(cbind,all_beta_glmm)
    all_u_glmm <- do.call(cbind,all_u_glmm)
    all_theta_glmm <- do.call(cbind,all_theta_glmm)
    
    mean_beta_glmm <- cbind.data.frame(mean_beta_glmm, rowSums(all_beta_glmm)/nsim)
    mean_u_glmm <- cbind.data.frame(mean_u_glmm, rowSums(all_u_glmm)/nsim)
    mean_theta_glmm <- cbind.data.frame(mean_theta_glmm, rowSums(all_theta_glmm)/nsim)
    
    
    End_time <- Sys.time()
    run_time <- End_time-start_time
    run_time_s <- cbind(run_time_s,run_time)
    run_time_s <- data.frame(run_time_s)
    
    # cat(paste0("\n ",s," areas Finish ! \n"))
    
    conv_name <- c(conv_name,paste0("m_",areas[q],"n_",sample_size[s]))
    
  }
  
  u_sim_ls3[[q]] <- u_sim_ls2
  
  
  run_time_all[[q]] <- run_time_s
  
  conv_iter_df <- do.call(cbind.data.frame,conv_iter_all)
  
  # colnames(conv_iter_df) <- conv_name
  all_iters[[q]] <- conv_iter_df
  names_iter[[q]] <- conv_name
  
  
  
  MSE_all <- data.frame(MSE_temp)
  colnames(MSE_all) <- name_MSE 
  colnames(mean_beta_hglm) <- hglm_nameB
  colnames(mean_u_hglm) <- hglm_nameU
  colnames(mean_theta_hglm) <- hglm_nameT
  
  MSE_glmm <- do.call(cbind,MSE_glmm0)
  colnames(MSE_glmm) <- name_MSE
  colnames(mean_beta_glmm) <- glmm_nameB
  colnames(mean_u_glmm) <- glmm_nameU
  colnames(mean_theta_glmm) <- glmm_nameT
  
  MSE_u_df <- MSE_all[(ncol(X)+1):((ncol(X)+1)+length(u_sim)-1),]
  MSE_u <- colSums(MSE_u_df)/length(u_sim)
  MSE_hglm <- rbind.data.frame(MSE_all,MSE_final=MSE_u)
  MSE_hglm <- MSE_hglm[-nrow(MSE_hglm), ]
  
  rownames(mean_beta_hglm) <- c(colnames(X))
  rownames(mean_u_hglm) <- c(paste0("u_",unique(df_sim$county)))
  rownames(mean_theta_hglm) <- c("theta")
  
  beta_glmm_hglm <- data.frame(mean_beta_hglm,mean_beta_glmm)
  u_glmm_hglm <- data.frame(mean_u_hglm,mean_u_glmm)
  theta_glmm_hglm <- data.frame(mean_theta_hglm,mean_theta_glmm)
  MSE_glmm_hglm <- data.frame(MSE_glmm, MSE_hglm)
  
  # write.csv(beta_glmm_hglm,paste0(path,"/out/mean_beta_hglm"),row.names = FALSE)
  print(mean_beta_glmm)
  print(beta_glmm_hglm)
  print(mean_u_hglm)
  print(mean_theta_hglm)
  print(MSE_hglm)
  print(mean_beta_glmm)
  print(mean_u_glmm) 
  print(mean_theta_glmm)
  print(MSE_glmm)
  print(u_sim_ls3)
  
  final_ests[[q]] <- list(beta_glmm_hglm,u_glmm_hglm,theta_glmm_hglm,MSE_glmm_hglm)
  
}

all_iters_df <- do.call(cbind.data.frame,all_iters)
iter_names <-  unlist(names_iter)
colnames(all_iters_df) <- iter_names

run_time_final <- do.call(cbind.data.frame,run_time_all)
colnames(run_time_final) <- iter_names


save(final_ests,beta_glmm_hglm,mean_beta_glmm,mean_u_hglm,mean_theta_hglm,MSE_hglm,
     mean_beta_glmm, mean_u_glmm, mean_theta_glmm, MSE_glmm,
     u_sim_ls3,all_iters_df,run_time_final, file="/work/dai/niroshapr/HGLM/out_BiasC/est_all_sim.RData")

Using YRBFSS Data set - HGLM vs GLMM

Integrated functions
# colx <- df 
f_lvls <- function(colx,x){
  colx <- colx[,paste0(x)]
  lvls=unique(colx)
  return(lvls)
}


### Create groups combining levels
new_grp <- function(df,x){
  # df <- df_sub; x <- "age"
  df <- df[order(df$county), ]
  varx <- df[, paste0(x)]
  varx <- ifelse(df$age %in% c(1:n1),"1",
                 ifelse(df$age %in% c((n1+1):n2), "2","3"))
  df <- df[,!colnames(df)%in%paste0(x)]
  cnames <- colnames(df)
  df <- data.frame(df, varx)
  colnames(df) <- c(cnames,paste0(x))
  return(df)
}



# yrbss_dat
## Grouping the response variable, 1=ecig_no, 2=ecig_yes
# df <- df_sub or df <- data, resp 
df_y <- function(df,y){
  temp <- df[, y]
  temp <- ifelse(temp==1,0,ifelse(temp==2,1,temp))
  temp <- as.integer(temp)
  temp <- data.frame(temp)
  colnames(temp) <- y
  df <- data.frame(temp,df)
  df <- df[,!colnames(df) %in% paste0(y,".1")]
  return(df)
}




# This function create model formula combining 
# discrete and cont variables depending on the
# model algorithm
my.form <-  function(dis_vars,cont_vars){
  fac_fomular <- paste0(resp,"~")
  for(i in 1:length(dis_vars)){
    temp <- paste0("as.factor(",dis_vars[i],")+")
    fac_fomular <- paste0(fac_fomular,temp) 
  }
  
  cont_fomular <- fac_fomular
  
  if(length(cont_vars)!=0){
    
    if(model.type=="glmm"){
      for(j in 1:length(cont_vars)){
        temp <- paste0(cont_vars[j])
        cont_fomular <- paste0(cont_fomular,temp)
      }
    }else if(model.type=="hglm"){
      for(j in 1:length(cont_vars)){
        temp <- paste0(cont_vars[j])
        cont_fomular <- paste0(cont_fomular,temp)
      }
    }
  }else{
    cont_fomular <- fac_fomular
  }
  return(cont_fomular)
}




## Levels of each discrete var

ls_func <- function(dis_vars){
  ls_disc <- list()
  for(i in 1:length(dis_vars)){
    # i <- 3
    dis_vars <- dis_vars[order(dis_vars)]
    v <- dis_vars[i]
    lvls <- f_lvls(data,paste0(v))
    lvls <- lvls[!is.na(lvls)]
    lvls <- lvls[order(lvls)]
    X <- c(noquote("Levels of"),v,as.vector(lvls))
    ls_disc[[i]] <- X 
  }
  return(ls_disc)
}


## Function to get trace of a m atrix
func_trace <- function(X){
  n <- dim(X)[1] 
  tr <- 0    ### initialize trace 
  
  for (j in 1:n){
    k <- X[j,j]
    tr <- tr + k
  }
  return(tr[[1]])
}


plot_func <- function(df,us_state){
  # us_state <- usmap::us_map(regions = "counties")
  us_state$fips <- as.numeric(us_state$fips)
  df$county <- as.numeric(df$county)
  colnames(df) <- ifelse(colnames(df)%in%"county","fips",colnames(df))
  data_all0 <- left_join(us_state,df,by="fips")
  
  # get the center location for each state
  
  if(plot_by_year=="YES"){
    plot_data<- list()
    for(j in 1:length(yr)){
      # j <- 1
      data_all <- data_all0[data_all0$year==yr[j],]
      
      df_state <- data_all %>% group_by(abbr) %>% summarise(mlong=mean(long),mlat=mean(lat))
      
      no_classes <- 7
      labels <- c()
      quantiles <- quantile(data_all$pred_cnty_prev,
                            probs = seq(0, 1, length.out = no_classes + 1),na.rm=TRUE)
      # Custom labels, rounding
      labels <- c()
      for(idx in 1:length(quantiles)){
        labels <- c(labels, paste0(round(quantiles[idx], 2),
                                   "_",
                                   round(quantiles[idx + 1], 2)))
      }
      # Minus one label to remove the odd ending one
      labels <- labels[1:length(labels)-1]
      
      # Create new variable for fill
      data_all$prev_quant <- cut(data_all$pred_cnty_prev,
                                 breaks = quantiles,
                                 labels = labels,
                                 include.lowest = T)
      plot_data[[j]] <- data_all
      
    }
  }else if(plot_by_year=="NO"){
    
    data_all <- data_all0 %>% dplyr::select(long,lat,fips,year,pred_cnty_prev) %>% 
      group_by(fips) %>% summarize(AvgPrev=mean(pred_cnty_prev))
    data_all <- data.frame(data_all)
    
    data_all1 <- data_all0[,!colnames(data_all0)%in% c("year","pred_cnty_prev","logit_prob","true_prevalence")]
    data_all1 <- unique(data_all1)
    data_all2 <- merge(data_all1,data_all, by="fips")
    
    df_state <- data_all2 %>% group_by(abbr) %>% summarise(mlong=mean(long),mlat=mean(lat))
    
    no_classes <- 7
    labels <- c()
    quantiles <- quantile(data_all2$AvgPrev,
                          probs = seq(0, 1, length.out = no_classes + 1),na.rm=TRUE)
    # Custom labels, rounding
    labels <- c()
    for(idx in 1:length(quantiles)){
      labels <- c(labels, paste0(round(quantiles[idx], 2),
                                 "_",
                                 round(quantiles[idx + 1], 2)))
    }
    # Minus one label to remove the odd ending one
    labels <- labels[1:length(labels)-1]
    
    # Create new variable for fill
    data_all2$prev_quant <- cut(data_all2$AvgPrev,
                                breaks = quantiles,
                                labels = labels,
                                include.lowest = T)
    plot_data <- data_all2
  }
  
  return(plot_data)
}


resp_title <- function(resp){
  if(resp=="ecig_ever"){
    tit_y <- "Ever Ecig"
  }else if(resp=="ecig_current"){
    tit_y <- "Current Ecig"
  }else if(resp=="smoke_current"){
    tit_y <- "Current Smoke"
  }else if(resp=="smoke_ever"){
    tit_y <- "Ever Smoke"
  }
  return(tit_y)
}


# get the center location for each state
mean_log_lat <- function(df){
  # df <- pred_prev_cnty
  us_state <- usmap::us_map(regions = "counties")
  colnames(us_state) <- c("long","lat","order","hole","piece","group","fips","abbr","full","county")
  us_state$fips <- as.numeric(us_state$fips)
  
  colnames(df) <- ifelse(colnames(df)%in%"county","fips",colnames(df))
  data_all0 <- left_join(us_state,df,by="fips")
  
  if(plot_by_year=="YES"){
    df_state <- data_all %>% group_by(abbr) %>% summarise(mlong=mean(long),mlat=mean(lat))
  }else{
    df_state <- data_all0 %>% group_by(abbr) %>% summarise(mlong=mean(long),mlat=mean(lat))
  }
  
  # data_all <- data_all0[data_all0$year==yr[1],]
  return(df_state)
}

Real Data Analysis using HGLM in SAE






# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
#                                                                                 #
#                                  Call packages                                  #
#                                                                                 #
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
rm(list=ls())

packages <- c("sae", "data.table","readxl", "dplyr", "gmodels",
              "pdftools", "reshape2","broom","tidyr","BayesSAE","corpcor",
              "fastDummies","maps","ggmap","geosphere","sqldf","lme4")

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)
}

ipak(packages)

dir_path <- getwd()

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
#                                                                                 #
#                                    Read Data                                    #
#                                                                                 #
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #

source(paste0(dir_path,"/C1_Census_DataPrep.R"))
source(paste0(dir_path,"/hglm_glmm_integrated_funcV2.R"))


data <- data.frame(data.table::fread(paste0(dir_path,"/data/YRBSSNew.csv")))

df <- data
df <- df[order(df$county), ]
resp <- "ecig_ever"   # ecig_current,  ecig_ever, smoke_current, smoke_ever
dis_vars <- c("age","sex","race4","year")   ### consider year later
cont_vars <- c("povt_rate")
wght <- "wt1"
re <- "county"
model.type <- "hglm"    
save.out <- "YES"
data_change <- "NO"  ## If YES heed to calculate distance for adjcent counties
fit.model <- "YES"
plot_by_year <- "NO"
save.plot <- "YES"

## Age levels 1:3=1, 4:5=2, & 6:7=3
n1 <- 3; n2=5 

# after re-joining levels, enter how many levels in each dis var
DX0 <- expand.grid(age=c("1","2","3"),sex=c("1","2"), race4=c("1","2","3","4"), year=c("1","2"))
out.path <- paste0(dir_path,"/out/",resp,"/")
dis_vars <- dis_vars[order(dis_vars)]
dis_vars


if("year" %in% colnames(df)){
  df$year <- as.numeric(df$year)
  df$year <- ifelse(df$year=="2015",1,
                    ifelse(df$year=="2017",2,df$year))
}


# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
#                                                                                 #
#                                                                                 #
#                                    Data Prep                                    #
#                                                                                 #
#                                                                                 #
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #



if("FIPS" %in% colnames(df)){
  colnames(df) <- "county"
}else{
  colnames(df) <- colnames(df)
}

#** Filter variables from original data set
df_sub <- data.frame(df[, colnames(df) %in% c(resp,re,dis_vars,cont_vars,wght)])
wt <- data.frame(df[, colnames(df) %in% c(wght)])
colnames(wt) <- "wt"
df_sub <- df_sub[complete.cases(df_sub), ]

#** Levels of age variable
lvls <- f_lvls(df_sub,"age")
lvls



#** Create age grouping
df_sub <- new_grp(df_sub,"age")
#** group response variable using function
df_sub <- df_y(df=df_sub,y=resp)   #
yrbss_df <- df_sub     ##  obs , this df will be used in area est modelling section

#** with new grouping for age
print("Freq table with new grouping: ")
table(yrbss_df$age)
table(yrbss_df$year)
table(yrbss_df$sex)
table(yrbss_df$race4)


# ******************************************************************************* #
#                                                                                 #
#                        Calculate true prevalence                                #
#                                                                                 #
# ******************************************************************************* #
# Calculate county wise prevalence for each year and combine dfs 


yr <- unique(df_sub$year)
#** df_sub0 <- df_sub
true_prev1 <- list()
for(i in 1:length(yr)){
  # i <- 2
  df_sub0 <- df_sub[df_sub$year%in%yr[i], ] 
  myFormula <- sprintf("county~%s", resp)
  true_prev0 <- sqldf:: sqldf(paste0("select * from df_sub0 where ",resp," is not null")) %>% 
    dcast(as.formula(myFormula)) %>%    # total # of records for each county
    gather(variable, value, -county) %>%   ## 
    group_by(county) %>%
    mutate(percentage = value/sum(value)) %>% 
    # select(-value) %>% 
    spread(variable, percentage)
  true_prev0 <- data.frame(true_prev0)
  true_prev0 <- data.frame(true_prev0, logit_prob=log(true_prev0$X1/(1-true_prev0$X1)))
  true_prev0 <- true_prev0[!is.na(true_prev0$logit_prob), ]
  true_prev1[[i]] <- data.frame(true_prev0, year=yr[i])
  rm(true_prev0)
}
true_prev <- do.call(rbind,true_prev1)
head(true_prev)


#** Remove -Inf for prevalence
if("-Inf" %in% true_prev$logit_prob){
  rem_cnty <- as.numeric(true_prev$county[which(true_prev$logit_prob =="-Inf")])
  true_prev <- true_prev[true_prev$logit_prob !="-Inf",]
}else{
  true_prev <- true_prev
  true_prev <- true_prev[!is.na(true_prev$logit_prob), ]
}

true_prev <- true_prev[, !colnames(true_prev) %in% c("value","X0","X1")]
head(true_prev)



#** Combine YRBSS data with pov data and create dummy colns for dis vars
# counties in YRBSS data for y
com_cnty <- unique(yrbss_df$county)   

if("year" %in% colnames(pov_pop)){
  pov_pop$year <- ifelse(pov_pop$year=="2015",1,
                         ifelse(pov_pop$year=="2017",2,pov_pop$year))  
}
pov_pop_sub <- pov_pop[pov_pop$county %in% com_cnty, ]

dis_vars0 <- dis_vars[!dis_vars%in%"year"]
Xdata_dummy <- fastDummies::dummy_cols(yrbss_df,select_columns = dis_vars)%>% 
  # dplyr::select(-c(y)) %>% 
  left_join(pov_pop_sub, by=c("county","year")) %>%   # Join popn and poverty data
  left_join(true_prev, by=c("county","year")) %>%   # Join prev data
  dplyr::select(-c(paste0(dis_vars0)))   ### Remove dis vars except year
yrbss_dummy <- Xdata_dummy
yrbss_dummy <- yrbss_dummy[,!colnames(yrbss_dummy) %like% "_NA"]

# yrbss_dummy <- data.frame(lapply(yrbss_dummy,function(x)(as.numeric(x))))
yrbss_dummy <- yrbss_dummy[order(yrbss_dummy$county),]

print("Combining YRBSS data with pov rate and creating dummy cols for dis vars")
head(yrbss_dummy)



#** remove rows that has na for logit prob
na_rows <- which(is.na(yrbss_dummy$logit_prob))
if(length(na_rows) != 0){
  yrbss_dummy <- yrbss_dummy[-na_rows, ]
}else{
  yrbss_dummy <- yrbss_dummy
}
colnames(yrbss_dummy) <- gsub("_","",colnames(yrbss_dummy))

head(yrbss_dummy)

#** merge with dummy county data
keep_vars <- colnames(census_SexAgeRace_DX)[!colnames(census_SexAgeRace_DX) %in% dis_vars] # remove original dis vars
keep_vars <- c(keep_vars, "year")
Census_dummy <- census_SexAgeRace_DX[census_SexAgeRace_DX$county%in%com_cnty,
                                     colnames(census_SexAgeRace_DX)%in% keep_vars]
head(Census_dummy)



# ******************************************************************************* #
#                                                                                 #
#                        Calculate entroid of each county                         #
#                                                                                 #
# ******************************************************************************* #


#### Estimate centroid of each county using long and lat data

long_lat_cnty <- map_data('county')
data("county.fips")

cnty_fips0 <- tstrsplit(county.fips$polyname,",", names=TRUE)
cnty_fips <- data.frame(county=county.fips$fips,region=cnty_fips0$V1,subregion=cnty_fips0$V2)
cnty_fips$region <- as.character(cnty_fips$region)
cnty_fips$subregion <- as.character(cnty_fips$subregion)
long_lat_dat <- long_lat_cnty %>% left_join(cnty_fips,by=c("region","subregion"))
long_lat_dat <- long_lat_dat %>%dplyr::select(county,long,lat)

df_by_cnty <- split(long_lat_dat, long_lat_dat$county)   ## Split data frame by county
cnty_centrd <- list()  # CREATE list of Data frames
centrd_by_cnty <- list()

### Long and lat for al counties
for (i in 1:length(df_by_cnty)){
  # i <- 1
  cnty_centrd[[i]] <- as.data.frame((df_by_cnty[i]),row.names = NULL)
  colnames(cnty_centrd[[i]]) <- colnames(long_lat_dat)
  centrd_by_cnty0 <- centroid(cnty_centrd[[i]][,2:3])
  centrd_by_cnty[[i]] <- cbind.data.frame(county=unique(cnty_centrd[[i]][,1]),centrd_by_cnty0)
}

cnty_centrd_df <- rbindlist(centrd_by_cnty)  #Requires library "data.table"

# out_ls <- list(com_cnty,yrbss_dummy,true_prev0,yrbss_unit,Xmean_sub,cnty_pop,cnty_centrd_df,perc_tbl,pop_dat,true_prev)
data_prep <- list(df_sub,wt,com_cnty,yrbss_dummy,Census_dummy,cnty_centrd_df,pop_dat,true_prev)



# ******************************************************************************* #
#                                                                                 #
#                               Obtain initial Parameters                         #
#                                                                                 #
# ******************************************************************************* #
data_all <- merge(df_sub,pov_pop,by=c("county","year"))
data_all <- data_all[with(data_all, order(county, year)),  ]
head(data_all)

## Filter variables to create design matrix for dis vars
# DX_0 <- data_all[, c(resp,cont_vars,dis_vars)]
DX_out <- data_all[, c(resp,cont_vars)]
for(i in 1:length(dis_vars)){
  # i <- 1
  var_temp <- dis_vars[i]
  DX_temp <- data_all[,var_temp]
  DX_temp <- as.factor(DX_temp)
  DX_out <- cbind.data.frame(DX_out,DX_temp)
}
colnames(DX_out) <- c(resp,cont_vars,dis_vars)

DX11 <- model.matrix(as.formula(paste0(resp,"~.")), data=DX_out,
                     contrasts.arg =list(age=contrasts(DX_out$age, contrasts = F),
                                         race4=contrasts(DX_out$race4, contrasts = F),
                                         sex=contrasts(DX_out$sex, contrasts = F),
                                         year=contrasts(DX_out$year, contrasts = F)))

DX11 <- cbind.data.frame(county=data_all$county,
                         resp=data_all[ , paste0(resp)], DX11)
ref_grp <- c("age1","race44","sex1","year1")    ### Ref group
DX <- DX11[ ,!colnames(DX11)%in%ref_grp]    ### Remove ref group
X <- DX[ ,3:ncol(DX)]
X <- X[ ,order(colnames(X))]
y <- DX[ ,"resp"]


#*** define parameters 
# y <- data_all[data_all$county %in% cnty0, ]   #paste0(resp)
m <- length(unique(data_all$county))
N <- nrow(data_all)
Z <- model.matrix(~0+as.factor(DX11$county))
p <- ncol(X)
X <- as.matrix(X)

cnty <- unique(data_all$county)
length(cnty)


## Fit logit model to get initial fixed effects parameters 
my_form <- my.form(dis_vars,cont_vars)
glm_formula <- as.formula(my_form)
data_all$race4 <- as.factor(data_all$race4)
data_all$race4 <- relevel(data_all$race4, ref="4")   # race44 is ref group

glm_fit <- glm(formula = glm_formula,family = binomial(link=logit),data=data_all)

theta0 <- 0.1
u0 <- as.matrix(rnorm(m,0,sd=sqrt(theta0)))


re_names <- c()
for(i in 1:length(cnty)){ 
  re_names <- c(re_names,paste0(cnty[i]))  
}
re_names <- as.numeric(re_names)
str(re_names)
u0 <- data.frame(county = re_names,est=u0) 


## beta values for all parameters (including ref group)
beta0 <- data.frame(summary(glm_fit)$coefficients[,1])
beta0 <- data.frame(parameter=rownames(beta0),est=beta0[,1])
rownames(beta0) <- NULL



# ============================***********************=========================== #  
beta0_cont <- beta0[!beta0$parameter %like% "as.factor",] ## beta for Cont vars
beta0_Int <- beta0_cont[!beta0_cont$parameter %in% cont_vars, ]
beta0_cont <- beta0_cont[beta0_cont$parameter %in% cont_vars, ]
beta0_cont$parameter <- gsub("_","",beta0_cont$parameter)
beta0_Int$parameter <- gsub("\\(Intercept\\)","Int",beta0_Int$parameter)

beta0_dis <- beta0[beta0$parameter %like% "as.factor",]  # beta for disc vars
beta0_dis$parameter <- gsub("as.factor\\(","",beta0_dis$parameter)
beta0_dis$parameter <- gsub("\\)","_",beta0_dis$parameter)


beta0_dis$col <- gsub("_.*","",beta0_dis$parameter)
unq <- unique(beta0_dis$col)
beta0_dis$parameter <- gsub("_","",beta0_dis$parameter)
beta0_dis$col <- NULL


beta0 <- rbind(beta0_cont,beta0_dis)
if(!is.character(beta0$parameter)){beta0$parameter <- as.character(beta0$parameter)}
beta0 <- beta0[order(beta0$parameter), ]
beta0$est <- round(as.numeric(beta0$est),5)
beta0 <- rbind.data.frame(beta0_Int,beta0)

# ===============================*************************========================= #
# ******************************************************************************* #
#                                                                                 #
#                                hglm model fit                                   #
#                                                                                 #
# ******************************************************************************* #

fit.hglm <- match.call(); namedList <- list()

X <- as.matrix(X)
beta_new <- as.matrix(beta0$est)
u_new <- u0$est
theta_new <- theta0

delta <- NULL
beta_new_all <- beta_new ;u_new_all <- u_new; theta_all <- theta_new
theta_new_all <- c(theta_new); delta_final <- 0 ; conv_iter <- 0; iter <- 0
col_names <- c()

dim(X)
length(beta_new)
length(u_new)
dim(Z)
length(y)


repeat{
  
  beta <- as.vector(beta_new)
  beta <- round(beta,10)
  # beta <- beta_new
  u <- as.vector(u_new)
  theta <- theta_new
  
  BU_old <- rbind(as.matrix(beta),as.matrix(u))
  
  theta_inv <- solve(theta)
  G_inv <- kronecker(theta_inv, diag(m))
  
  P <- 1/(1+exp(-(X%*%beta+Z%*%u)))
  pp <- P*(1-P)
  W <- Diagonal(x=pp)
  
  D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
  D2h_BU <- t(X)%*%W%*%Z
  D2h_UB <- t(Z)%*%W%*%X
  D2h_UU <- t(Z)%*%W%*%Z + G_inv
  J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (m+p) by  (p+m) Jacobian
  J <- as.matrix(J)
  
  # library(corpcor)
  # J_inv <- solve(J, tol=10^-20)
  J_inv <- pseudoinverse(J)  # For non-singular matrices the pseudoinverse is equivalent to the standard inverse.
  
  # J_inv <- func_Jinv(beta,u_new,G_inv)
  
  # yp <- y - P
  D1h_B <- t(X)%*%(y-P)
  D1h_u <- t(Z)%*%(y-P)- G_inv%*%u
  
  S <- as.vector(rbind(D1h_B, D1h_u))    # Gradient (score function) vector
  
  BU_new = BU_old + (J_inv%*%S)    # Newton Raphson 
  
  beta_new <- as.vector(BU_new[1:length(beta)])
  u_new <- as.vector(BU_new[(length(beta)+1):length(BU_new)])
  
  # convergence_beta <- abs(beta_new[-1]-beta[-1])  
  convergence_beta <- abs(beta_new-beta)
  convergence_u <- abs(u_new-u)
  max(convergence_beta)
  max(convergence_u)
  
  beta_new_all <- cbind.data.frame(beta_new_all,value=round(beta_new,6))
  u_new_all <- cbind.data.frame(u_new_all,value=round(u_new,6))
  
  rm(P); rm(W); rm(J);
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  #                                                                                 #
  #                                Bias Correction                                  #
  #                                                                                 #
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  # Bias Corr step 1: update J with estimated beta and u
  
  P <- 1/(1+exp(-(X%*%beta_new+Z%*%u_new)))
  pp <- P*(1-P)
  W <- Diagonal(x=pp)
  
  D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
  D2h_BU <- t(X)%*%W%*%Z
  D2h_UB <- t(Z)%*%W%*%X
  D2h_UU <- t(Z)%*%W%*%Z + G_inv
  J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (m+p) by  (p+m) Jacobian
  J <- as.matrix(J)
  
  Jhat_Inv <- pseudoinverse(J)
  Tau <- Jhat_Inv[(p+1):(p+m),(p+1):(p+m)]
  Taut <- diag(Tau)
  zeta <- theta/(theta+Taut)
  corr_u <- zeta*u_new     # Corrected u_new
  
  rm(P); rm(W); rm(J);
  
 
  
  iter <- iter + 1
  ########### ---------------------------------------------------------#############      
  ###########             Estimate theta=sigma^2 using Dh/Dtheta=0     #############
  ########### ---------------------------------------------------------#############
  
  
  ## Using SAE6 to estimate theta
  theta_inv <- solve(theta)
  G_inv <- kronecker(theta_inv, diag(m))
  
  P <- 1/(1+exp(-(X%*%beta_new+Z%*%corr_u)))
  # W <- diag(as.vector(P*(1-P)))
  W <- Diagonal(x=as.vector(P*(1-P)))
  
  D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
  D2h_BU <- t(X)%*%W%*%Z
  D2h_UB <- t(Z)%*%W%*%X
  D2h_UU <- t(Z)%*%W%*%Z + G_inv
  J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (143+9) by  (9+143) Jacobian
  J <- as.matrix(J)
  J_inv <- pseudoinverse(J)
  
  # J_inv <- func_Jinv(beta=beta_new,u_new,G_inv)
  
  dim(J_inv)
  
  ###Estimate theta 
  J_inv22 <- J_inv[(p+1):(p+m),(p+1):(p+m)]
  theta_new <- 1/m*(t(u_new)%*%u_new)+1/m*func_trace(J_inv22)
  theta_new_all <- cbind.data.frame(theta_new_all,value=theta_new)
  
 
    
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  
  ### To get the variance of u based on J 
  theta_inv <- solve(theta_new)
  G_inv <- kronecker(theta_inv, diag(m))
  
  P <- 1/(1+exp(-(X%*%beta_new+Z%*%u_new)))    
  W <- Diagonal(x=as.vector(P*(1-P)))
  
  D2h_BB <- t(X)%*%W%*%X   # or crossprod(t(crossprod(X,W)),X)
  D2h_BU <- t(X)%*%W%*%Z
  D2h_UB <- t(Z)%*%W%*%X
  D2h_UU <- t(Z)%*%W%*%Z + G_inv
  J <- rbind(cbind(D2h_BB,D2h_BU),cbind(D2h_UB,D2h_UU))   # (143+9) by  (9+143) Jacobian
  J <- as.matrix(J)
  J_inv <- pseudoinverse(J)
  
  # J_inv <- func_Jinv(beta=beta_new,u_new,G_inv)
  
  fe.cov <- J_inv[1:p,1:p]       ## Var Cov matrix of fixed effects
  re.cov  <- J_inv[(p+1):(p+m),(p+1):(p+m)]    ## Var Cov matrix of random effects
  
  fe.var <- diag(fe.cov)    ### Var of fixed effects
  fe.var <- round(fe.var,10)
  fe.var <- fe.var[fe.var != 0]  ## Remove coefs of ref group(which has very small values)
  fe.std.err <- round(sqrt(fe.var), 5)
  
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
  
  convergence_theta <- abs(theta_new-theta)
  delta <- max(convergence_beta,convergence_theta)
  delta_final <- cbind.data.frame(delta_final,value=delta)
  
  col_names <- c(col_names,paste0("iter",iter))
  
  
  cat(paste0("delta: ",delta,"\n \n"))
  
  if(delta <= 1e-10){break}
  
}


colnames(theta_new_all) <- col_names
colnames(beta_new_all) <- col_names
rownames(beta_new_all) <- beta0$parameter
colnames(u_new_all) <- col_names
rownames(u_new_all) <- u0$county

cat(paste0("Converged in ",iter," iterations with tol = ",delta,". \n \n"))


# *************************************************************************************** #
#                                                                                         #
#                                Get model estimates                                      #
#                                                                                         #
# *************************************************************************************** #

est.beta <- beta_new_all[,ncol(beta_new_all)]
est.theta <- theta_new_all[,ncol(theta_new_all)]
est.re <- data.frame(county=rownames(u_new_all),
                     est=u_new_all[,ncol(u_new_all)])
beta_hat <- round(beta_new_all[,ncol(beta_new_all)],5)
beta_hat <- beta_hat[beta_hat!=0]
z1 <- beta_hat/fe.std.err

est.fe <- data.frame(est=beta_hat,
                     std.err=fe.std.err,
                     Z0 = round(z1,5),
                     P = round(2*pnorm(-abs(z1)),5))

rownames(est.fe) <- rownames(beta_new_all)[round(beta_new_all[,ncol(beta_new_all)],5) !=0]    # rownames(beta_new_all)


colnames(est.fe) <- c("Estimate","Std.Error","Z Value","P(>|Z|)")

est.beta <- round(est.beta,5)
est.beta <- data.frame(Variable=rownames(beta_new_all),Estimate=est.beta)

fit.hglm$iter <- iter
fit.hglm$est.beta <- est.fe
fit.hglm$re <- est.re
fit.hglm$var.par <- est.theta
fit.hglm$fe.cov <- fe.cov
fit.hglm$re.cov <- re.cov

colnames(fe.cov) <- rownames(beta_new_all)
rownames(fe.cov) <- rownames(beta_new_all)

# *************************************************************************************** # 
# ****************************      model estimates   *********************************** #
# *************************************************************************************** #
# ****************************      Calculate AIC, BIC     *********************************** #
est.beta <- as.vector(est.beta$Estimate)

P <- 1/(1+exp(-(X%*%est.beta+Z%*%(est.re$est))))
yt <- 1-y
loglikel <- y*log(P) +yt*log(1-P)
sumloglik <- sum(loglikel)

AIC <- -2*sum(loglikel) + 2*(length(est.beta)+1)
BIC <- -2*sum(loglikel) + (length(est.beta)+1)*log(N)
model.sel <- cbind.data.frame(AIC, BIC,LogLik=sumloglik)

# ****************************      Calculate AIC     *********************************** #
namedList <- list(`hglm model inference`= model.sel, iter=iter,`fixed effects estimates`=est.fe,
                  ` `=paste0("Converged in ",iter," iterations with tol = ",delta,".")
)
class(namedList) <- "summary.hglm.fit"

fit.hglm$summary.hglm <- namedList

if(save.out=="YES"){
  if(length(out.path)==0){
    stop("output path is not defined !!")
  }else if(length(out.path)!=0){
    write.csv(theta_new_all, paste0(out.path,model.type,"/",model.type,"_theta_all.csv"),row.names = T)
    write.csv(beta_new_all, paste0(out.path,model.type,"/",model.type,"_beta_new_all.csv"), row.names = T)
    write.csv(u_new_all, paste0(out.path,model.type,"/",model.type,"_u_new_all.csv"), row.names = T)

    write.csv(est.theta, paste0(out.path,model.type,"/",model.type,"_theta_est.csv"),row.names = F)
    write.csv(est.fe, paste0(out.path,model.type,"/",model.type,"_fe_est.csv"), row.names = T)
    write.csv(est.re, paste0(out.path,model.type,"/",model.type,"_re_est.csv"), row.names = F)
    write.csv(fe.cov, paste0(out.path,model.type,"/",model.type,"_fe_VarCov_est.csv"), row.names = T)
    write.csv(re.cov, paste0(out.path,model.type,"/",model.type,"_re_VarCov_est.csv"), row.names = T)

    # save(paste0(out.path,"fit.hglm.RData"))
  }
  print(paste0("hglm model fit output is saved in ",out.path))
}



# *************************************************************************************** #
#                                                                                         #
#                                  Model prediction                                       #
#                                                                                         #
# *************************************************************************************** #

pred.out <- match.call()

DX1 <- data.frame(Int=rep(1,nrow(DX0)))
for(i in 1:length(dis_vars)){
  # i <- 1
  temp <- paste0(dis_vars[i],"+")
  temp_mtx <- model.matrix(as.formula(paste0("~",temp,"0")),DX0)
  DX1 <- cbind.data.frame(DX1, temp_mtx)
}


if(resp=="ecig_ever"){
  tit_y <- "Ever"
}else if(resp=="ecig_current"){
  tit_y <- "Current"
}else if(resp=="smoke_ever"){
  tit_y <- "Ever"
}else if(resp=="smoke_current"){
  tit_y <- "Current"
}

out_path <- paste0(dir_path,"/out/",resp,"/",model.type)

if(save.out=="YES"){
  if(length(out.path)==0){
    stop("Output path is not defined !!")
  }else if(length(out.path!=0)){
    beta_est <- data.frame(read.csv(paste0(out.path,model.type,"/",model.type,"_fe_est.csv")))
    theta_est <- data.frame(read.csv(paste0(out.path,model.type,"/",model.type,"_theta_est.csv")))
    u_est <- data.frame(read.csv(paste0(out.path,model.type,"/",model.type,"_re_est.csv")))
  }
}else{
  beta_est <- fit.hglm$fe
  u_est <- fit.hglm$re
  theta_est <- fit.hglm$var.par
}


## Center of each county
cnty_centrd_df <- data.frame(cnty_centrd_df)

### Random effects available for these counties
# est_rand_eff_cnty <- cnty_centrd_df[cnty_centrd_df$county %in% com_cnty,]    
No_rand_effect_cnty <- cnty_centrd_df[!cnty_centrd_df$county %in% u_est$county,]
est_random_effect <- u_est
colnames(est_random_effect) <- c("county","rand_eff")

# est_random_effect$county <- substring(est_random_effect$county,2,nchar(est_random_effect$county))
# est_random_effect$county <- as.integer(est_random_effect$county)
# est_random_effect$rand_eff <- as.numeric(est_random_effect$rand_eff)
# est_random_effect <- est_random_effect[est_random_effect$county %in% est_rand_eff_cnty$county, ]

if(data_change=="YES"){
  pred_adj_cnty_df <- pred_adjc_cnty(df1=est_rand_eff_cnty,df2=No_rand_effect_cnty)
  write.csv(pred_adj_cnty_df,paste0(dir_path,"/out/",resp,"/",model.type,"/pred_adj_cnty_df.csv"),row.names = F)
}else if(data_change=="NO"){
  # ## read adjacent county information 
  pred_adj_cnty_df <- read.csv(paste0(dir_path,"/out/",resp,"/",model.type,"/pred_adj_cnty_df.csv"))
}

dim(pred_adj_cnty_df)


## Left join with predicted adjcent county 
pred_adj_cnty_final <- pred_adj_cnty_df %>% 
  left_join(est_random_effect, by=c("pred_adj_cnty"="county")) 

## All random effects (combine predicted and estimated random effects)
all_random_effect <- rbind(data.frame(county=pred_adj_cnty_final$county,
                                      rand_eff=pred_adj_cnty_final$rand_eff),
                           est_random_effect)
all_random_effect <- all_random_effect[order(all_random_effect$county), ]

dim(all_random_effect)
head(all_random_effect)  ## incuding estimates random effets


# $$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
if("FIPS" %in% colnames(df)){
  colnames(df) <- "county"
}else{
  colnames(df) <- colnames(df)
}

df_sub <- data.frame(df[, colnames(df) %in% c(dis_vars)])
df_sub <- df_sub[complete.cases(df_sub), ]

### Create age grouping
df_sub$age <- ifelse(df_sub$age %in% c(1:n1),"1",
                     ifelse(df_sub$age %in% c((n1+1):n2), "2","3"))

table(df_sub$age)
# $$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$


### Reg coefficients from hglm model
if(!is.character(beta_est[,1])){
  beta_est[,1] <- as.character(beta_est[,1])
}
cont_vars0 <- gsub("_","",cont_vars)
beta_disc <- beta_est[!beta_est[,1] %in% c(cont_vars0),]

if(length(beta_disc[,1][!beta_disc[,1] %in% names(DX1)])==0){
  est_beta0 <- rbind.data.frame(beta_disc[ ,1:2],
                               cbind(X=ref_grp,Estimate=rep(0,length(ref_grp))))
  est_beta1 <- est_beta0[2:nrow(est_beta0), ]
  est_beta2 <- est_beta0[1, ]
  est_beta1 <- est_beta1[order(est_beta1$X), ]
  estBeta <- rbind.data.frame(est_beta2,est_beta1)
  estBeta$Estimate <- as.numeric(estBeta$Estimate)
  est_beta <- as.matrix(estBeta$Estimate)
  DX <- as.matrix(DX1)
}else{
  stop("Check for the dimension of fixed effects and design matrix !")
}

X_beta0 <- DX %*% est_beta
X_beta <- X_beta0

poverty_pop <- merge(pov_pop,all_random_effect, by="county")
in_cnty <- est_random_effect$county


## ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ##
## ---------- predict prev for missing counties for each combination of dis vars - START -------------- ##
## ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ##

## counties long and lat available but no prevalence data
oot_cnty <- all_random_effect$county[!all_random_effect$county%in%in_cnty]
random_effect_oot <- all_random_effect[all_random_effect$county%in%oot_cnty, ]
poverty_oot <- poverty_pop[poverty_pop$county%in%oot_cnty,]
poverty_oot <- poverty_oot[order(poverty_oot$county), ]
random_effect_oot <- random_effect_oot[order(random_effect_oot$county), ]



### predict county level prevalence using eqn (3) for all counties
# beta for cont vars
beta_cont <- beta_est[beta_est[,1] %in% cont_vars0,] 
if(is.factor(beta_cont$X)){
  beta_cont$X <- as.character(beta_cont$X)  
}

beta_cont_var <- beta_cont[,"Estimate"] # coefs for cont vars


cnty_pred <- list(); cnty_pred_all<-list()
for(j in 1:length(unique(poverty_pop$year))){
  # j <- 2
  yr <- unique(poverty_pop$year)[j]
  pov_rate_val <- poverty_pop[poverty_pop$year==yr,]
  pov_rate_val <- pov_rate_val[order(pov_rate_val$county), ]
  oot_com_cnt <- intersect(pov_rate_val$county,all_random_effect$county)
  re_temp <- all_random_effect[all_random_effect$county%in%oot_com_cnt, ]
  re_temp <- re_temp[order(re_temp$county), ]
  
  
  if(j==1){
    temp_X_beta <- X_beta[1:(length(X_beta)/2)]
    temp_DX1 <- DX1[1:(length(X_beta)/2),!colnames(DX1)%in%"year2017"]
    temp_DX1 <- temp_DX1[,-ncol(temp_DX1)]
  }else if(j==2){
    temp_X_beta <- X_beta[(length(X_beta)/2):(length(X_beta))]
    temp_DX1 <- DX1[(length(X_beta)/2):(length(X_beta)),!colnames(DX1)%in%"year2015"]
    temp_DX1 <- temp_DX1[,-ncol(temp_DX1)]
  }
  
  
  for(i in 1:nrow(re_temp)){
    # i <-1
    temp_pvt_rate <- pov_rate_val$povt_rate[i]
    cnty_pred[[i]] <- data.frame(county=re_temp$county[i],temp_DX1,temp_X_beta,pov_rate_val$povt_rate[i],re_temp$rand_eff[i])
    # cnty_pred[[i]] <- data.frame(county=re_temp$county[i],DX1,X_beta,pov_rate_val$povt_rate[i],re_temp[i])
  }
  cnty_pred_yr <- do.call(rbind,cnty_pred)
  cnty_pred_yr <- data.frame(year=yr,cnty_pred_yr,
                             logitP=cnty_pred_yr$temp_X_beta+
                               cnty_pred_yr$pov_rate_val.povt_rate.i.+
                               cnty_pred_yr$re_temp.rand_eff.i.)
  cnty_predicted_prevalence <- data.frame(cnty_pred_yr,
                                          pred_prevalence=round(exp(cnty_pred_yr$logitP)/(1+exp(cnty_pred_yr$logitP))*100,2))
  
  cnty_pred_all[[j]] <- cnty_predicted_prevalence 
}

cnty_pred_all <- do.call(rbind,cnty_pred_all)
cnty_pred_all$year1 <- NULL
cnty_pred_all <- fastDummies::dummy_columns(cnty_pred_all,select_columns = "year")
colnames(cnty_pred_all) <- gsub("_","",colnames(cnty_pred_all))
cnty_pred_all <- cnty_pred_all[,!colnames(cnty_pred_all)%in%dis_vars]


## ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ##
## ----------  predict prev for missing counties for each combination of dis vars - END  -------------- ##
## ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ##

merge_by_var <- c(colnames(DX1),"county")
merge_by_var <- merge_by_var[merge_by_var!="Int"]

final_3way_df <- merge(census_SexAgeRace_DX,cnty_pred_all,
                       by=merge_by_var,all.x=TRUE)

final_3way_df <- final_3way_df[order(final_3way_df$county), ]
head(final_3way_df)
final_3way_df <- data.frame(final_3way_df,
                            prob_cnty=(final_3way_df$predprevalence)*final_3way_df$popn) 
final_3way_df <- final_3way_df[order(final_3way_df$county), ]

pred_prev_cnty <- sqldf("SELECT county,year ,round(SUM(prob_cnty)/SUM(popn),2) as pred_cnty_prev  
                        FROM final_3way_df GROUP BY county, year") 
head(pred_prev_cnty)
dim(pred_prev_cnty)

##### combine pred_prev_cnty with available YRBSS county prevalence

true_prev=data.frame(true_prev,
                     true_prevalence=round(exp(true_prev$logit_prob)/(1+exp(true_prev$logit_prob))*100,2))
prev_pred_all <- merge(pred_prev_cnty,true_prev, by=c("county","year"),all.x=TRUE)
head(prev_pred_all)


######### ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ############
######### +++++++++++++++++++                          +++++++++++++++++ ############
######### +++++++++++++++++++ Create US map prevalnce  +++++++++++++++++ ############
######### +++++++++++++++++++                          +++++++++++++++++ ############
######### ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ############

us_state <- usmap::us_map(regions = "counties")
colnames(us_state) <- c("long","lat","order","hole","piece","group","fips","abbr","full","county")
plot_data<- list()
data_all <- data.frame(plot_func(pred_prev_cnty,us_state)[1])   ### Call the plot function
# df_state <- data.frame(plot_func(pred_prev_cnty)[2])



pred.out$tit_y <- tit_y
pred.out$prev_all <- prev_pred_all
pred.out$pred_prev_cnty <- pred_prev_cnty

if(save.out=="YES"){
  write.csv(pred_prev_cnty, 
            paste0(out_path,"/pred_prev_cnty.csv"), row.names = F)
  
  write.csv(prev_pred_all, 
            paste0(out_path,"/prev_pred_all.csv"), row.names = F)
  
  write.csv(all_random_effect, 
            paste0(out_path,"/all_random_effect.csv"), row.names = F)
  
  write.csv(cnty_predicted_prevalence, 
            paste0(out_path,"/cnty_predicted_prevalence.csv"), row.names = F)
  
}



# *************************************************************************************** #
#                                                                                         #
#                                  Prevalence map                                         #
#                                                                                         #
# *************************************************************************************** #

if(fit.model=="YES"){
  # hglm.fit <- hglm_3model_fit(X,Z,beta0,u0,theta0,save.out,out.path)
  beta_est <- beta_est   # hglm.fit$summary.hglm$`fixed effects estimates`
  theta_est <- theta_est   # hglm.fit$var.par
  u_est <-  u_est  # hglm.fit$re
  # pred.out <- hglm_4pred(DX0,resp,dis_vars,cnty_centrd_df,data_change,out.path)
  pred_prev_cnty <- pred.out$pred_prev_cnty
  tit_y <- pred.out$tit_y
  prev_all <- pred.out$prev_all
}else{
  beta_est <- data.frame(read.csv(paste0(out.path,model.type,"/",model.type,"_fe_est.csv")))
  theta_est <- data.frame(read.csv(paste0(out.path,model.type,"/",model.type,"_theta_est.csv")))
  u_est <- data.frame(read.csv(paste0(out.path,model.type,"/",model.type,"_re_est.csv")))
  prev_all <- data.frame(read.csv(paste0(out.path,model.type,"/prev_pred_all.csv")))
  pred_prev_cnty <- data.frame(read.csv(paste0(out.path,model.type,"/pred_prev_cnty.csv")))
  tit_y <- resp_title(resp=resp) 
}

beta_est

yr <- unique(df$year)
yr

obs_pred_prev <- prev_all[!is.na(prev_all$true_prevalence), ]
obs_pred_prev <- obs_pred_prev[!is.na(obs_pred_prev$pred_cnty_prev), ]

if(is.factor(pred_prev_cnty$year)){pred_prev_cnty$year <- as.numeric(as.character(pred_prev_cnty$year))}
resp0 <- gsub("_"," ",resp)
df_state <- data.frame(mean_log_lat(pred_prev_cnty))


if(plot_by_year=="YES"){
  if(is.factor(pred_prev_cnty$year)){
    pred_prev_cnty$year <- as.numeric(as.character(pred_prev_cnty$year))
  }
  
  plots <- list()
  for(j in 1:length(yr)){
    # j <- 1
    obs_pred_cor <- obs_pred_prev[obs_pred_prev$year==yr[j] ,]
    
    us_state <- usmap::us_map(regions = "counties")
    colnames(us_state) <- c("long","lat","order","hole","piece","group","fips","abbr","full","county")
    data_all <- plot_func(pred_prev_cnty,us_state)[[j]]
    
    # Pearson and Spearman correlation for predicted and observed prev
    pear_cor <- round(cor(obs_pred_cor$pred_cnty_prev, 
                          obs_pred_cor$true_prevalence, method = "pearson"), 2)
    spea_cor <- round(cor(obs_pred_cor$pred_cnty_prev, 
                          obs_pred_cor$true_prevalence, method = "spearman"),2)
    
    plot_prev <- 
      ggplot(data = data_all,aes(x=long,y=lat))+
      geom_polygon(mapping = aes(x = long, y = lat,
                                 group = fips,
                                 fill = prev_quant),colour="gray", size = 0.4)+
      scale_fill_brewer(palette ="Oranges")+
      xlab("longitude")+ylab("latitude") +
      guides(fill=guide_legend(title=paste0(resp0 ,": ")))+ 
      theme(legend.position="bottom")+ 
      annotate("text",x=df_state$mlong,y=df_state$mlat,label=df_state$abbr) +
      borders("state") +
      ggtitle(paste0("County prevalence of ",resp0," - ",yr[j]),
              subtitle = substitute(paste("Correlation = (",rho^{P},", ",rho^{S},")"," = (",pear_cor,", ",spea_cor,")"),
                                    list(pear_cor=pear_cor,spea_cor=spea_cor)))+
      theme(plot.subtitle = element_text(color = "Brown", size=12, face="italic"))
    
    plots[[j]] <- plot_prev
    
    
    if(save.plot=="YES"){
      ggsave(paste0(dir_path,"/out/",resp,"/",model.type,"/cnty_prev_",yr[j],".png"),plot=plots[[j]],width = 8,height = 6)  
    }
  }
  
}else if(plot_by_year=="NO"){
  obs_pred_cor0 <- obs_pred_prev
  obs_pred_cor <- obs_pred_cor0 %>% dplyr::select(county,pred_cnty_prev,true_prevalence) %>% 
    group_by(county) %>% 
    summarise(ObsAvgPrev=mean(true_prevalence),PredAvgPrev=mean(pred_cnty_prev))
  obs_pred_cor <- data.frame(obs_pred_cor)
  
  us_state <- usmap::us_map(regions = "counties")
  colnames(us_state) <- c("long","lat","order","hole","piece","group","fips","abbr","full","county")
  data_all <- plot_func(pred_prev_cnty,us_state)
  
  # Pearson and Spearman correlation for predicted and observed prev
  pear_cor <- round(cor(obs_pred_cor$PredAvgPrev, 
                        obs_pred_cor$ObsAvgPrev, method = "pearson"), 2)
  spea_cor <- round(cor(obs_pred_cor$PredAvgPrev, 
                        obs_pred_cor$ObsAvgPrev, method = "spearman"),2)
  plot_prev <- 
    ggplot(data = data_all,aes(x=long,y=lat))+
    geom_polygon(mapping = aes(x = long, y = lat,
                               group = fips,
                               fill = prev_quant),colour="gray", size = 0.4)+
    scale_fill_brewer(palette ="Oranges")+
    xlab("longitude")+ylab("latitude") +
    guides(fill=guide_legend(title=paste0(resp0,": ")))+ 
    theme(legend.position="bottom")+ 
    annotate("text",x=df_state$mlong,y=df_state$mlat,label=df_state$abbr) +
    borders("state") +
    ggtitle(paste0("County prevalence of ",resp0,", 2015 and 2017 combined"),
            subtitle = substitute(paste("Correlation = (",rho^{P},", ",rho^{S},")"," = (",pear_cor,", ",spea_cor,")"),
                                  list(pear_cor=pear_cor,spea_cor=spea_cor)))+
    theme(plot.subtitle = element_text(color = "Brown", size=12, face="italic"))
  
  if(save.plot=="YES"){
    ggsave(paste0(dir_path,"/out/",resp,"/",model.type,"/cnty_prev_2015_2017",".png"),plot=plot_prev,width = 8,height = 6)  
  }
}

Author: Nirosha Rathnayake, Department of Biostatistics, University of Nebraska Medical Center, Omaha, NE.

Prepared using R Markdown

LS0tDQp0aXRsZTogIlIgQ29kZSAtIFNtYWxsIEFyZWEgRXN0aW1hdGlvbiB1c2luZyBIR0xNIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KDQoNCg0KIyMgUiBDb2RlIGZvciBTaW11bGF0aW9uDQoNCg0KLSBUaGlzIG5vdGUgYm9vayBjb250YWlucyAqUiBjb2RlKiBmb3IgTUMgc2ltdWxhdGlvbiBhbmQgZm9yIHJlYWwgZGF0YSBhbmFseXNpcyB1c2luZyBZUkJGUyBkYXRhIHNldCB0byBldmFsdWF0ZSB0aGUgcHJvcG9zZWQgKkhpZXJhcmNoaWNhbCBnZW5lcmFsaXplZCBtb2RlbGxpbmcgYXBwcm9hY2gqIGluIHNtYWxsIGFyZWEgZXN0aW1hdGlvbi4NCg0KDQoNCi0gKk1DIFNpbXVsYXRpb24gdG8gY29tcGFyZSBIR0xNIGFuZCBHTE1NIHJlc3VsdHMqDQoNCmBgYHtyfQ0KIyMgRnVuY3Rpb24gdG8gZ2V0IHRyYWNlIG9mIGEgbSBhdHJpeA0KZnVuY190cmFjZSA8LSBmdW5jdGlvbihYKXsNCiAgbiA8LSBkaW0oWClbMV0gDQogIHRyIDwtIDAgICAgIyMjIGluaXRpYWxpemUgdHJhY2UgDQogIA0KICBmb3IgKGogaW4gMTpuKXsNCiAgICBrIDwtIFhbaixqXQ0KICAgIHRyIDwtIHRyICsgaw0KICB9DQogIHJldHVybih0cltbMV1dKQ0KfQ0KDQoNCiMgRnVuY3Rpb24gdG8gY29tcHV0ZSBpbnYoSikNCmZ1bmNfSmludiA8LSBmdW5jdGlvbihYLFosVyxHX2ludil7DQogIEQyaF9CQiA8LSB0KFgpJSolVyUqJVggICAjIG9yIGNyb3NzcHJvZCh0KGNyb3NzcHJvZChYLFcpKSxYKQ0KICBEMmhfQlUgPC0gdChYKSUqJVclKiVaDQogIEQyaF9VQiA8LSB0KFopJSolVyUqJVgNCiAgRDJoX1VVIDwtIHQoWiklKiVXJSolWiArIEdfaW52DQogIEogPC0gcmJpbmQoY2JpbmQoRDJoX0JCLEQyaF9CVSksY2JpbmQoRDJoX1VCLEQyaF9VVSkpICAgIyAoMTQzKzkpIGJ5ICAoOSsxNDMpIEphY29iaWFuDQogIEogPC0gYXMubWF0cml4KEopDQogIEpfaW52IDwtIHNvbHZlKEopDQogIHJldHVybihKX2ludikNCiAgDQp9DQoNCiMjIFNpbXVsYXRlZCBmaXhlZCBlZmZlY3RzIGRhdGENCnNpbV94IDwtIGZ1bmN0aW9uKGopew0KICBYIDwtIGMoKSAgIA0KICBpZihqPT0yKXsNCiAgICBmb3IgKGkgaW4gMTptKXsNCiAgICAgIFhzaW0gPC0gYXMubWF0cml4KHNhbXBsZShjKDEsMCksbixyZXBsYWNlPVRSVUUpKQ0KICAgICAgWCA8LSByYmluZChYLCBYc2ltKQ0KICAgIH0gIA0KICB9ZWxzZSBpZihqPT0zKXsNCiAgICBmb3IgKGkgaW4gMTptKXsNCiAgICAgIFhzaW0gPSBhcy5tYXRyaXgoc2FtcGxlKGMoIlhDMSIsIlhDMiIsIlhDMyIpLG4scmVwbGFjZT1UUlVFKSkNCiAgICAgIFggPC0gcmJpbmQoWCwgWHNpbSkNCiAgICB9DQogIH0NCiAgcmV0dXJuKFgpDQp9DQoNCmBgYA0KDQoNCg0KDQotIFNpbXVsYXRpb24gU3R1ZHkgDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIyMjIyMjIyMjIyMjIw0KIyMjIyMjIyMjIyMgICAgICAgICAgICAgICAgICAgICAgICBTaW11bGF0ZSBkYXRhIC0gU1RBUlQgICAgICAgICAgICAgIyMjIyMjIyMjIyMjIw0KIyMjIyMjIyMjIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIyMjIyMjIyMjIyMjIw0KDQoNCiMgYXJlYXMgPC0gYyg1LDEwLDIwLDMwKSAgICMgU2VsZWN0IG51bWJlciBvZiBzbWFsbCBhcmVhcw0KIyBzYW1wbGVfc2l6ZSA8LSBjKDMwLDUwLDEwMCw1MDApICAjIGFyZWEgd2lzZSBzYW1wbGUgc2l6ZQ0KDQphcmVhcyA8LSBjKDUpICAgIyBTZWxlY3QgbnVtYmVyIG9mIHNtYWxsIGFyZWFzDQpzYW1wbGVfc2l6ZSA8LSBjKDMwLDUwLDEwMCw1MDApICAjIGFyZWEgd2lzZSBzYW1wbGUgc2l6ZQ0KbnNpbSA8LSAxMDAwDQojIHNldC5zZWVkKDEyMykNCnNpbV9zZWVkIDwtIHNlcSgxMDAwLDE5OTksMSkNCg0KDQp0aGV0YV9zaW0gPC0gMC4xICAjIHRoZXRhIHRvIGNyZWF0ZSBzaW11bGF0ZWQgZGF0YQ0KYmV0YV9zaW0gPC0gYygtMS41LDEuMywxLjUpDQpiZXRhX3NpbSA8LSBhcy5tYXRyaXgoYmV0YV9zaW0pDQoNCmFsbF9pdGVycyA8LSBuYW1lc19pdGVyIDwtIHJ1bl90aW1lX2FsbCA8LSB1X3NpbV9sczMgPC0gbGlzdCgpDQpmaW5hbF9lc3RzIDwtIGxpc3QoKQ0KDQpmb3IocSBpbiAxOmxlbmd0aChhcmVhcykpew0KICANCiAgIyBxIDwtIDQNCiAgbSA8LSBhcmVhc1txXQ0KICB1X3NpbSA8LSBhcy5tYXRyaXgocm5vcm0obSwwLHNkPXNxcnQodGhldGFfc2ltKSkpDQogIA0KICBjb252X2JldGEgPC0gYmV0YV9zaW07IGNvbnZfdSA8LSB1X3NpbTsgY29udl90aGV0YSA8LSB0aGV0YV9zaW07IGNvbnZfaXRlciA8LSAwOw0KICBtZWFuX2JldGFfaGdsbSA8LSBkYXRhLmZyYW1lKFRydWU9YmV0YV9zaW0pOyBtZWFuX3VfaGdsbSA8LSBkYXRhLmZyYW1lKFRydWU9dV9zaW0pOyANCiAgbWVhbl90aGV0YV9oZ2xtIDwtIGRhdGEuZnJhbWUoVHJ1ZT10aGV0YV9zaW0pOyBtZWFuX2JldGFfZ2xtbSA8LSBkYXRhLmZyYW1lKFRydWU9YmV0YV9zaW0pOw0KICBtZWFuX3VfZ2xtbSA8LSBkYXRhLmZyYW1lKFRydWU9dV9zaW0pOyBtZWFuX3RoZXRhX2dsbW0gPC0gZGF0YS5mcmFtZShUcnVlPXRoZXRhX3NpbSkNCiAgTVNFX2dsbW0gPC0gbGlzdCgpDQogIGdsbW1fbmFtZUIgPC0gaGdsbV9uYW1lQiA8LSBnbG1tX25hbWVVPC1oZ2xtX25hbWVVPC1nbG1tX25hbWVUPC0gaGdsbV9uYW1lVDwtICJ0cnVlIiA7IA0KICBNU0VfdGVtcCA8LSBjKCk7IG5hbWVfTVNFIDwtIGMoKTtjb252X25hbWUgPC0gYygpDQogIGNvbnZfaXRlcl9hbGwgPC0gTVNFX2dsbW0wIDwtIHVfc2ltX2xzMiAgPC0gbGlzdCgpDQogIHJ1bl90aW1lX3MgPC0gYygpDQogIA0KICBmb3IocyBpbiAxOmxlbmd0aChzYW1wbGVfc2l6ZSkpew0KICAgIA0KICAgICMgcyA8LSA0DQogICAgYWxsX2JldGFfc2ltIDwtIGRhdGEuZnJhbWUoVHJ1ZT1iZXRhX3NpbSk7IGFsbF91X3NpbSA8LSBkYXRhLmZyYW1lKFRydWU9dV9zaW0pOyANCiAgICBhbGxfdGhldGFfc2ltIDwtIGRhdGEuZnJhbWUoVHJ1ZT10aGV0YV9zaW0pDQogICAgYWxsX2JldGFfZ2xtbSA8LSBhbGxfdV9nbG1tIDwtIGFsbF90aGV0YV9nbG1tIDwtIHVfc2ltX2xzIDwtIGxpc3QoKQ0KICAgIGVycl9hbGxfc2ltcyA8LSBuYW1lc0VyciA8LSBjb252X2l0ZXIgPC0gYygpDQogICAgU1NFX2JldGFfZ2xtbSA8LSByZXAoMCxsZW5ndGgoYmV0YV9zaW0pKTsgU1NFX3VfZ2xtbSA8LSByZXAoMCxtKTsgDQogICAgU1NFX3RoZXRhX2dsbW0gPC0gcmVwKDAsbGVuZ3RoKHRoZXRhX3NpbSkpDQogICAgDQogICAgc3RhcnRfdGltZSA8LSBTeXMudGltZSgpDQogICAgDQogICAgZm9yKHIgaW4gMTpuc2ltKXsNCiAgICAgICMgciA8LSAxDQogICAgICBzZXQuc2VlZChzaW1fc2VlZFtyXSkgDQogICAgICBuIDwtIHNhbXBsZV9zaXplW3NdICAgIyBBcmVhd2lzZSBzYW1wbGUgc2l6ZQ0KICAgICAgZ3JwcyA8LSBjKDIsMikgICMgU2VsZWN0IHRoZSBudW1iZXIgb2YgY2F0ZWdvcmljYWwgZml4ZWQgZWZmZWN0cyBhbmQgZ3JvdXBzIGluIGVhY2ggdmFyDQogICAgICBqIDwtIDAgICAjIFNlbGVjdCB0aGUgbnVtYmVyIG9mIGZpeGVkIGVmZmVjdHMgKGNvbnRpbnVvdXMgdmFycykNCiAgICAgIHRoZXRhMCA8LSAwLjEgDQogICAgICBOIDwtIG4qbSAgICAjIFRvdGFsIHNhbXBsZSBzaXplDQogICAgICANCiAgICAgICMgY3JlYXRlIGNvdW50eSB2YXJpYWJsZQ0KICAgICAgY291bnR5IDwtIGMoKQ0KICAgICAgZm9yIChpIGluIDE6bSl7DQogICAgICAgIGNudHkgPC0gYXMubWF0cml4KHJlcChjKGkpLG4pKQ0KICAgICAgICBjb3VudHkgPC0gcmJpbmQoY291bnR5LCBjbnR5KQ0KICAgICAgfSANCiAgICAgIA0KICAgICAgIyBjcmVhdGUgZWFjaCBkaXNjcmV0ZSB2YXIgYW5kIGNvbWJpbmUgdG8gYSBkZg0KICAgICAgZml4ZWRfZWZmX2RzIDwtIGRhdGEuZnJhbWUoY291bnR5KQ0KICAgICAgZm9yKGsgaW4gMTpsZW5ndGgoZ3Jwcykpew0KICAgICAgICB0ZW1wWCA8LSBzaW1feChncnBzW2tdKSAgICMgY2FsbCBmdW5jIGFuZCBjcmVhdGUgZGlzIGZpeGVkIGVmZmVjdHMgZGF0YQ0KICAgICAgICBjb2xuYW1lcyh0ZW1wWCkgPC0gcGFzdGUwKCJYIixrKQ0KICAgICAgICBmaXhlZF9lZmZfZHMgPC0gY2JpbmQuZGF0YS5mcmFtZShmaXhlZF9lZmZfZHMsdGVtcFgpDQogICAgICB9DQogICAgICANCiAgICAgIA0KICAgICAgZml4ZWRfZWZmX2N0IDwtIGNiaW5kLmRhdGEuZnJhbWUoWFgxPWxvZyhybm9ybShOLG1lYW49NjAsc2Q9MykpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWFgyPWxvZyhybm9ybShOLG1lYW49ODAwMDAsc2Q9MzApKSkNCiAgICAgIA0KICAgICAgY2hhcl92YXIgPC0gY29sbmFtZXMoZml4ZWRfZWZmX2RzKSAgIyBjb2wgbmFtZXMgb2YgZml4ZWQgZWZmZWN0cyAtIGRpc2NyZXRlDQogICAgICB2YXJzX2RzIDwtIGNoYXJfdmFyWzE6KGxlbmd0aChncnBzKSsxKV0gICAjIE5vIG9mIGZpeGVkIGVmZmVjdHMoZGlzY3JldGUpIHRvIGNvbnNpZGVyIGZvciBtb2RlbGxpbmcNCiAgICAgIA0KICAgICAgY250X3ZhciA8LSBjb2xuYW1lcyhmaXhlZF9lZmZfY3QpICAjIGNvbCBuYW1lcyBvZiBmaXhlZCBlZmZlY3RzIC0gY29udGludW91cw0KICAgICAgaWYoaiE9MCl7ICAjIE5vIG9mIGZpeGVkIGVmZmVjdHMgKGNvbnRpbnVvdXMpIGZvciBtb2RlbGxpbmcNCiAgICAgICAgdmFyc19jdCA8LSBjbnRfdmFyWzE6al0gIA0KICAgICAgfWVsc2V7DQogICAgICAgIHZhcnNfY3QgPC0gTlVMTA0KICAgICAgfQ0KICAgICAgZGZfc2ltIDwtIGNiaW5kLmRhdGEuZnJhbWUoZml4ZWRfZWZmX2RzWyxjb2xuYW1lcyhmaXhlZF9lZmZfZHMpJWluJXZhcnNfZHNdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml4ZWRfZWZmX2N0Wyxjb2xuYW1lcyhmaXhlZF9lZmZfY3QpJWluJXZhcnNfY3RdKQ0KICAgICAgZGZfc2ltIDwtIGRmX3NpbVtvcmRlcihkZl9zaW0kY291bnR5KSwgXQ0KICAgICAgDQogICAgICBjb2xuYW1lcyhkZl9zaW0pIDwtIGMoY29sbmFtZXMoZml4ZWRfZWZmX2RzKVt3aGljaChjb2xuYW1lcyhmaXhlZF9lZmZfZHMpJWluJXZhcnNfZHMpXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xuYW1lcyhmaXhlZF9lZmZfY3QpW3doaWNoKGNvbG5hbWVzKGZpeGVkX2VmZl9jdCklaW4ldmFyc19jdCldKQ0KICAgICAgDQogICAgICB0YWJsZShkZl9zaW0kY291bnR5LGRmX3NpbSRYMSkNCiAgICAgIHRhYmxlKGRmX3NpbSRjb3VudHksZGZfc2ltJFgyKQ0KICAgICAgDQogICAgICANCiAgICAgICMjIFNpbXVsYXRlZCByYW5kb20gZWZmZWN0cyBnaXZlbiB0aGV0YQ0KICAgICAgIyB0aGV0YV9zaW0gPC0gMSAgIA0KICAgICAgIyB1X3NpbSA8LSBhcy5tYXRyaXgocm5vcm0obSwwLHNkPXNxcnQodGhldGFfc2ltKSkpDQogICAgICAjIHVfc2ltIDwtIGFzLm1hdHJpeChxbm9ybShydW5pZihtLCBtaW49cG5vcm0oLTIsIHNkPXNxcnQodGhldGFfc2ltKSksDQogICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXg9cG5vcm0oMiwgc2Q9c3FydCh0aGV0YV9zaW0pKSksIA0KICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgc2Q9c3FydCh0aGV0YV9zaW0pKSkNCiAgICAgIHVfc2ltMCA8LSBjYmluZC5kYXRhLmZyYW1lKGNvdW50eT11bmlxdWUoZGZfc2ltJGNvdW50eSksdV9zaW0pDQogICAgICANCiAgICAgICMgTWVyZ2Ugc2ltdWxhdGVkIGZpeGVkIGFuZCByYW5kb20gZWZmZWN0cyBkYXRhDQogICAgICBkYXRhX2FsbCA8LSBtZXJnZShkZl9zaW0sdV9zaW0wLGJ5Lng9ImNvdW50eSIsYnkueT0iY291bnR5IikgIA0KICAgICAgZGF0YV9hbGwgPC0gZGF0YV9hbGxbb3JkZXIoZGF0YV9hbGwkY291bnR5KSwgXQ0KICAgICAgDQogICAgICAjICMgZml4ZWQgZWZmZWN0IC0gZGVzaWduIG1hdHJpeA0KICAgICAgWHZhcnNfZHMgPC0gdmFyc19kc1shdmFyc19kcyAlaW4lICJjb3VudHkiXQ0KICAgICAgaWYobGVuZ3RoKHZhcnNfY3QpICE9MCl7DQogICAgICAgIGRtX2Zvcm0gPC0gIGFzLmZvcm11bGEocGFzdGUoJ34nLHBhc3RlKCdhcy5mYWN0b3IoJyxYdmFyc19kcywnKScsIGNvbGxhcHNlID0gIisiKSwiKyIsdmFyc19jdCkpDQogICAgICB9ZWxzZSBpZihsZW5ndGgodmFyc19jdCk9PTApew0KICAgICAgICBkbV9mb3JtIDwtICBhcy5mb3JtdWxhKHBhc3RlKCd+JyxwYXN0ZSgnYXMuZmFjdG9yKCcsWHZhcnNfZHMsJyknLCBjb2xsYXBzZSA9ICIrIikpKSAgDQogICAgICB9DQogICAgICANCiAgICAgIFggPC0gbW9kZWwubWF0cml4KGRtX2Zvcm0sZGF0YT1kYXRhX2FsbCkNCiAgICAgIA0KICAgICAgDQogICAgICAjIyMjIyBBc3NpZ24gaW5pdGlhbCBiZXRhcw0KICAgICAgIyBiZXRhX3NpbSA8LSBydW5pZihuY29sKFgpLG1pbj0wLjUsbWF4PTIpICAgIyBiZXRhIGZvciBkYXRhIHNpbXVsYXRpb24NCiAgICAgICMgYmV0YV9zaW0gPC0gcnVuaWYobmNvbChYKSxtaW49LTEsbWF4PTIpDQogICAgICAjIGJldGFfc2ltIDwtIGMoMS41LDEuOCwtMiwxLjIsLTEuNSkNCiAgICAgIGJldGFfc2ltIDwtIGFzLm1hdHJpeChiZXRhX3NpbVsxOm5jb2woWCldKQ0KICAgICAgdSA8LSBhcy5tYXRyaXgoZGF0YV9hbGwkdV9zaW0pDQogICAgICANCiAgICAgICMgQ2FsY3VsYXRlIGJpbm9taWFsIHAgDQogICAgICBwMCA8LSBleHAoWCUqJWJldGFfc2ltK3UpLygxK2V4cChYJSolYmV0YV9zaW0rdSkpDQogICAgICB5IDwtIHJiaW5vbShOLDEscDApDQogICAgICB0YWJsZSh5KQ0KICAgICAgZGF0YSA8LSBjYmluZC5kYXRhLmZyYW1lKGRhdGFfYWxsLHkpDQogICAgICB0YWJsZShkYXRhJHksIGRhdGEkY291bnR5KQ0KICAgICAgDQogICAgICAjIyMgRGVmaW5lIG1hdHJpY2VzIGFuZCB2YWx1ZXMgZm9yIGhnbG0gbW9kZWxsaW5nDQogICAgICBkYXRhIDwtIGRhdGFbb3JkZXIoZGF0YSRjb3VudHkpLF0NCiAgICAgIFggPC0gWA0KICAgICAgWiA8LSBtb2RlbC5tYXRyaXgofjArYXMuZmFjdG9yKGRhdGEkY291bnR5KSkNCiAgICAgIHkgPC0gZGF0YVssInkiXQ0KICAgICAgbSA8LSBtDQogICAgICBOIDwtIG4qbQ0KICAgICAgcCA8LSBuY29sKFgpDQogICAgICANCiAgICAgICMjIEZpdCBsb2dpdCBtb2RlbCB0byBnZXQgaW5pdGlhbCBmaXhlZCBlZmZlY3RzIHBhcmFtZXRlcnMgDQogICAgICBhbGxfdmFycyA8LSBjKFh2YXJzX2RzLHZhcnNfY3QpDQogICAgICBnbG1fZm9ybXVsYSA8LSBhcy5mb3JtdWxhKHBhc3RlKCJ5IiwnficscGFzdGUoYWxsX3ZhcnMsIGNvbGxhcHNlID0gIisiKSkpDQogICAgICAjIGdsbV9maXQgPC0gZ2xtKHl+YXMuZmFjdG9yKFgzKSthcy5mYWN0b3IoWDIpK2FzLmZhY3RvcihYMSksZmFtaWx5ID0gYmlub21pYWwobGluaz1sb2dpdCksZGF0YT1kYXRhKQ0KICAgICAgZ2xtX2ZpdCA8LSBnbG0oZm9ybXVsYSA9IGdsbV9mb3JtdWxhLGZhbWlseSA9IGJpbm9taWFsKGxpbms9bG9naXQpLGRhdGE9ZGF0YSkNCiAgICAgIA0KICAgICAgDQogICAgICANCiAgICAgICMgSW5pdGlhbCBwYXJhbWV0ZXJzDQogICAgICBiZXRhMCA8LSBhcy5udW1lcmljKGdsbV9maXQkY29lZmZpY2llbnRzKQ0KICAgICAgDQogICAgICB1MCA8LSBhcy5tYXRyaXgocnVuaWYobSwodV9zaW0tMC4xKSwodV9zaW0rMC4xKSkpDQogICAgICANCiAgICAgIA0KICAgICAgDQogICAgICAjIyMjIyMjIyMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jIyMjIyMjIyMjIyMjDQogICAgICAjIyMjIyMjIyMjIyAgICAgICAgICAgICAgICAgICAgICAgIFNpbXVsYXRlIGRhdGEgLSBFTkQgICAgICAgICAgICAgICAjIyMjIyMjIyMjIyMjDQogICAgICAjIyMjIyMjIyMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jIyMjIyMjIyMjIyMjDQogICAgICAjIyMjIyMjIyMjIyAgICAgICAgICAgICAgICAgICBQYXJhbWV0ZXIgRXN0aW1hdGlvbiAtIFNUQVJUICAgICAgICAgICAjIyMjIyMjIyMjIyMjDQogICAgICAjIyMjIyMjIyMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jIyMjIyMjIyMjIyMjDQogICAgICANCiAgICAgIA0KICAgICAgYmV0YV9uZXcgPC0gYmV0YTANCiAgICAgIHVfbmV3IDwtIHUwDQogICAgICB0aGV0YV9uZXcgPC0gdGhldGEwDQogICAgICANCiAgICAgIGJldGFfbmV3X2FsbCA8LSBkYXRhLmZyYW1lKFRydWU9YmV0YV9zaW0pIDsNCiAgICAgIHRoZXRhX25ld19GUyA8LSBkYXRhLmZyYW1lKFRydWU9dGhldGFfc2ltKSA7IA0KICAgICAgdGhldGFfbmV3X2FsbCA8LSBkYXRhLmZyYW1lKFRydWU9dGhldGFfc2ltKTsNCiAgICAgIHVfbmV3X2FsbCA8LSBkYXRhLmZyYW1lKFRydWU9dV9zaW0pOyANCiAgICAgIHRoZXRhX2FsbCA8LSBkYXRhLmZyYW1lKFRydWU9dGhldGFfbmV3KQ0KICAgICAgZGVsdGFfZmluYWwgPC0gZGF0YS5mcmFtZShUcnVlPSJOQSIpDQogICAgICBkZWx0YSA8LSBOVUxMIDsgDQogICAgICBpdGVyIDwtIDA7IGl0ZXJfYWxsIDwtICJpdGVyMCINCiAgICAgIA0KICAgICAgDQogICAgICByZXBlYXR7DQogICAgICAgIA0KICAgICAgICBiZXRhIDwtIGFzLnZlY3RvcihiZXRhX25ldykNCiAgICAgICAgdSA8LSBhcy52ZWN0b3IodV9uZXcpDQogICAgICAgIHRoZXRhIDwtIHRoZXRhX25ldw0KICAgICAgICANCiAgICAgICAgQlVfb2xkIDwtIHJiaW5kKGFzLm1hdHJpeChiZXRhKSxhcy5tYXRyaXgodSkpDQogICAgICAgIA0KICAgICAgICB0aGV0YV9pbnYgPC0gc29sdmUodGhldGEpDQogICAgICAgIEdfaW52IDwtIGtyb25lY2tlcih0aGV0YV9pbnYsIGRpYWcobSkpDQogICAgICAgICMgR19pbnYNCiAgICAgICAgDQogICAgICAgIFAgPC0gMS8oMStleHAoLShYJSolYmV0YStaJSoldSkpKQ0KICAgICAgICBXIDwtIGRpYWcoYXMudmVjdG9yKFAqKDEtUCkpKQ0KICAgICAgICBEMmhfQkIgPC0gdChYKSUqJVclKiVYICAgIyBvciBjcm9zc3Byb2QodChjcm9zc3Byb2QoWCxXKSksWCkNCiAgICAgICAgRDJoX0JVIDwtIHQoWCklKiVXJSolWg0KICAgICAgICBEMmhfVUIgPC0gdChaKSUqJVclKiVYDQogICAgICAgIEQyaF9VVSA8LSB0KFopJSolVyUqJVogKyBHX2ludg0KICAgICAgICBKIDwtIHJiaW5kKGNiaW5kKEQyaF9CQixEMmhfQlUpLGNiaW5kKEQyaF9VQixEMmhfVVUpKSAgICMgKG0rcCkgYnkgIChwK20pIEphY29iaWFuDQogICAgICAgIEogPC0gYXMubWF0cml4KEopDQogICAgICAgIEpfaW52IDwtIHNvbHZlKEopDQogICAgICAgIA0KICAgICAgICANCiAgICAgICAgRDFoX0IgPC0gdChYKSUqJSh5LVApDQogICAgICAgIEQxaF91IDwtIHQoWiklKiUoeS1QKS0gR19pbnYlKiV1DQogICAgICAgIFMgPC0gYXMudmVjdG9yKHJiaW5kKEQxaF9CLCBEMWhfdSkpICAgICMgR3JhZGllbnQgKHNjb3JlIGZ1bmN0aW9uKSB2ZWN0b3IgIA0KICAgICAgICANCiAgICAgICAgIyBGaXNoZXIgc2NvcmluZyBhbGdvcml0aG0NCiAgICAgICAgQlVfbmV3ID0gQlVfb2xkICsgKEpfaW52JSolUykgICAgDQogICAgICAgIA0KICAgICAgICBiZXRhX25ldyA8LSBhcy52ZWN0b3IoQlVfbmV3WzE6bGVuZ3RoKGJldGEpXSkNCiAgICAgICAgdV9uZXcgPC0gYXMudmVjdG9yKEJVX25ld1sobGVuZ3RoKGJldGEpKzEpOmxlbmd0aChCVV9uZXcpXSkNCiAgICAgICAgDQogICAgICAgICMgY29udmVyZ2VuY2VfYmV0YSA8LSBhYnMoYmV0YV9uZXdbLTFdLWJldGFbLTFdKSAgDQogICAgICAgIGNvbnZlcmdlbmNlX2JldGEgPC0gYWJzKGJldGFfbmV3LWJldGEpDQogICAgICAgIGNvbnZlcmdlbmNlX3UgPC0gYWJzKHVfbmV3LXUpDQogICAgICAgIG1heChjb252ZXJnZW5jZV9iZXRhKQ0KICAgICAgICBtYXgoY29udmVyZ2VuY2VfdSkNCiAgICAgICAgDQogICAgICAgIGJldGFfbmV3X2FsbCA8LSBjYmluZC5kYXRhLmZyYW1lKGJldGFfbmV3X2FsbCx2YWx1ZT1yb3VuZChiZXRhX25ldyw2KSkNCiAgICAgICAgdV9uZXdfYWxsIDwtIGNiaW5kLmRhdGEuZnJhbWUodV9uZXdfYWxsLHZhbHVlPXJvdW5kKHVfbmV3LDYpKQ0KICAgICAgICAjIGl0ZXIgPC0gYyhpdGVyMCxpdGVyKQ0KICAgICAgICANCiAgICAgICAgcm0oUCk7IHJtKFcpOyBybShKKTsNCiAgICAgICAgIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmlhcyBDb3JyZWN0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgICAgICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgICAgICAgIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiAgICAgICAgDQogICAgICAgICMgQmlhcyBDb3JyIHN0ZXAgMTogdXBkYXRlIEogd2l0aCBlc3RpbWF0ZWQgYmV0YSBhbmQgdQ0KICAgICAgICANCiAgICAgICAgUCA8LSAxLygxK2V4cCgtKFglKiViZXRhX25ldytaJSoldV9uZXcpKSkNCiAgICAgICAgcHAgPC0gUCooMS1QKQ0KICAgICAgICBXIDwtIERpYWdvbmFsKHg9cHApDQogICAgICAgIA0KICAgICAgICBEMmhfQkIgPC0gdChYKSUqJVclKiVYICAgIyBvciBjcm9zc3Byb2QodChjcm9zc3Byb2QoWCxXKSksWCkNCiAgICAgICAgRDJoX0JVIDwtIHQoWCklKiVXJSolWg0KICAgICAgICBEMmhfVUIgPC0gdChaKSUqJVclKiVYDQogICAgICAgIEQyaF9VVSA8LSB0KFopJSolVyUqJVogKyBHX2ludg0KICAgICAgICBKIDwtIHJiaW5kKGNiaW5kKEQyaF9CQixEMmhfQlUpLGNiaW5kKEQyaF9VQixEMmhfVVUpKSAgICMgKG0rcCkgYnkgIChwK20pIEphY29iaWFuDQogICAgICAgIEogPC0gYXMubWF0cml4KEopDQogICAgICAgIA0KICAgICAgICBKaGF0X0ludiA8LSBwc2V1ZG9pbnZlcnNlKEopDQogICAgICAgIFRhdSA8LSBKaGF0X0ludlsocCsxKToocCttKSwocCsxKToocCttKV0NCiAgICAgICAgVGF1dCA8LSBkaWFnKFRhdSkNCiAgICAgICAgemV0YSA8LSB0aGV0YS8odGhldGErVGF1dCkNCiAgICAgICAgY29ycl91IDwtIHpldGEqdV9uZXcNCiAgICAgICAgDQogICAgICAgIHJtKFApO3JtKFcpOyBybShKKTsNCiAgICAgICAgIyBVc2UgY29ycmVjdGVkIHUgdG8gZXN0aW1hdGUgdGhldGENCiAgICAgICAgDQogICAgICAgICMjIyMjIyMjIyMjIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSMjIyMjIyMjIyMjIyMgICAgICANCiAgICAgICAgIyMjIyMjIyMjIyMgICAgICAgICAgICAgRXN0aW1hdGUgdGhldGE9c2lnbWFeMiB1c2luZyBEaC9EdGhldGE9MCAgICAgIyMjIyMjIyMjIyMjIw0KICAgICAgICAjIyMjIyMjIyMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jIyMjIyMjIyMjIyMjDQogICAgICAgIA0KICAgICAgICANCiAgICAgICAgIyMgVXNpbmcgU0FFNiB0byBlc3RpbWF0ZSB0aGV0YQ0KICAgICAgICB0aGV0YV9pbnYgPC0gc29sdmUodGhldGEpDQogICAgICAgIEdfaW52IDwtIGtyb25lY2tlcih0aGV0YV9pbnYsIGRpYWcobSkpDQogICAgICAgIA0KICAgICAgICBQIDwtIDEvKDErZXhwKC0oWCUqJWJldGFfbmV3K1olKiVjb3JyX3UpKSkNCiAgICAgICAgVyA8LSBkaWFnKGFzLnZlY3RvcihQKigxLVApKSkNCiAgICAgICAgDQogICAgICAgIEQyaF9CQiA8LSB0KFgpJSolVyUqJVggICAjIG9yIGNyb3NzcHJvZCh0KGNyb3NzcHJvZChYLFcpKSxYKQ0KICAgICAgICBEMmhfQlUgPC0gdChYKSUqJVclKiVaDQogICAgICAgIEQyaF9VQiA8LSB0KFopJSolVyUqJVgNCiAgICAgICAgRDJoX1VVIDwtIHQoWiklKiVXJSolWiArIEdfaW52DQogICAgICAgIEogPC0gcmJpbmQoY2JpbmQoRDJoX0JCLEQyaF9CVSksY2JpbmQoRDJoX1VCLEQyaF9VVSkpICAgIyAoMTQzKzkpIGJ5ICAoOSsxNDMpIEphY29iaWFuDQogICAgICAgIEogPC0gYXMubWF0cml4KEopDQogICAgICAgIEpfaW52IDwtIHNvbHZlKEopDQogICAgICAgIA0KICAgICAgICAjIyNFc3RpbWF0ZSB0aGV0YSANCiAgICAgICAgSl9pbnYyMiA8LSBKX2ludlsocCsxKToocCttKSwocCsxKToocCttKV0NCiAgICAgICAgdGhldGFfbmV3IDwtIDEvbSoodCh1X25ldyklKiV1X25ldykrMS9tKmZ1bmNfdHJhY2UoSl9pbnYyMikNCiAgICAgICAgdGhldGFfbmV3X2FsbCA8LSBjYmluZC5kYXRhLmZyYW1lKHRoZXRhX25ld19hbGwsdmFsdWU9dGhldGFfbmV3KQ0KICAgICAgICANCiAgICAgICAgY29udmVyZ2VuY2VfdGhldGEgPC0gYWJzKHRoZXRhX25ldy10aGV0YSkNCiAgICAgICAgZGVsdGEgPC0gbWF4KGNvbnZlcmdlbmNlX2JldGEsY29udmVyZ2VuY2VfdGhldGEpDQogICAgICAgIGRlbHRhX2ZpbmFsIDwtIGNiaW5kLmRhdGEuZnJhbWUoZGVsdGFfZmluYWwsdmFsdWU9ZGVsdGEpDQogICAgICAgIA0KICAgICAgICBlc3Rfb3V0IDwtIHJiaW5kLmRhdGEuZnJhbWUoYmV0YV9uZXdfYWxsLHVfbmV3X2FsbCx0aGV0YV9uZXdfYWxsLHZhbHVlPWRlbHRhX2ZpbmFsKQ0KICAgICAgICByb3duYW1lcyhlc3Rfb3V0KSA8LSBjKGNvbG5hbWVzKFgpLHBhc3RlMCgidV8iLHVuaXF1ZShkZl9zaW0kY291bnR5KSksInRoZXRhIiwiZGVsdGEiKQ0KICAgICAgICANCiAgICAgICAgDQogICAgICAgICMjIHJiaW5kIG9ubHkgYmV0YSwgdSBhbmQgdGhldGEgZXN0aW1hdGVkIHZhbHVlcw0KICAgICAgICBlc3RfcGFycyA8LSByYmluZC5kYXRhLmZyYW1lKGJldGFfbmV3X2FsbCx1X25ld19hbGwsdGhldGFfbmV3X2FsbCkNCiAgICAgICAgDQogICAgICAgIGl0ZXIgPC0gaXRlciArIDENCiAgICAgICAgDQogICAgICAgIGl0ZXJfYWxsIDwtIGMoaXRlcl9hbGwscGFzdGUwKCJpdGVyIixpdGVyKSkNCiAgICAgICAgDQogICAgICAgIGlmKGRlbHRhIDw9IDFlLTUpYnJlYWsNCiAgICAgIH0NCiAgICAgIA0KICAgICAgY29sbmFtZXModV9uZXdfYWxsKSA8LSBpdGVyX2FsbA0KICAgICAgdV9zaW1fbHNbW3JdXSA8LSB1X25ld19hbGwNCiAgICAgIA0KICAgICAgY29udl9pdGVyIDwtIGMoY29udl9pdGVyLGl0ZXIpDQogICAgICBjb252X2l0ZXJfYWxsW1tzXV0gPC0gY29udl9pdGVyDQogICAgICANCiAgICAgIA0KICAgICAgU3FFcnJfYmV0YSA8LSAoYmV0YV9zaW0tYmV0YV9uZXcpXjINCiAgICAgIFNxRXJyX3UgPC0gKHVfc2ltLXVfbmV3KV4yDQogICAgICBTcUVycl90aGV0YSA8LSAodGhldGFfc2ltLXRoZXRhX25ldyleMg0KICAgICAgDQogICAgICANCiAgICAgIGVycl9hbGwgPC0gcmJpbmQuZGF0YS5mcmFtZShTcUVycl9iZXRhLFNxRXJyX3UsU3FFcnJfdGhldGEpDQogICAgICBlcnJfYWxsX3NpbXMgPC0gYyhlcnJfYWxsX3NpbXMsZXJyX2FsbCkNCiAgICAgIGVycl9hbGxfc2ltcyA8LSBkYXRhLmZyYW1lKGVycl9hbGxfc2ltcykNCiAgICAgIHJvd25hbWVzKGVycl9hbGxfc2ltcykgPC0gYyhjb2xuYW1lcyhYKSxwYXN0ZTAoInVfIix1bmlxdWUoZGZfc2ltJGNvdW50eSkpLCJ0aGV0YSIpDQogICAgICBuYW1lc0VyciA8LSBjKG5hbWVzRXJyLHBhc3RlMCgiU3FfRXJyXyIsciwiX3NpbXMiKSkgDQogICAgICANCiAgICAgICMgcHJpbnQocGFzdGUwKCJTbWFsbCBhcmVhIHdpdGggc2FtcGxlIHNpemU6ICIsbiwgIiAmIE5vIG9mIHNpbXM6ICIscikpDQogICAgICANCiAgICAgIA0KICAgICAgYmV0YV9uZXcgPC0gZGF0YS5mcmFtZShiZXRhX25ldykNCiAgICAgIHVfbmV3IDwtIGRhdGEuZnJhbWUodV9uZXcpDQogICAgICB0aGV0YV9uZXcgPC0gZGF0YS5mcmFtZSh0aGV0YV9uZXcpDQogICAgICANCiAgICAgIGNvbG5hbWVzKGJldGFfbmV3KSA8LSBwYXN0ZTAoInNpbV9iZXRhXyIsciwiX3NpbXMiKQ0KICAgICAgY29sbmFtZXModV9uZXcpIDwtIHBhc3RlMCgic2ltX3VfIixyLCJfc2ltcyIpDQogICAgICBjb2xuYW1lcyh0aGV0YV9uZXcpIDwtIHBhc3RlMCgic2ltX3RoZXRhXyIsciwiX3NpbXMiKQ0KICAgICAgDQogICAgICBhbGxfYmV0YV9zaW0gPC0gY2JpbmQuZGF0YS5mcmFtZShhbGxfYmV0YV9zaW0sYmV0YV9uZXcpDQogICAgICBhbGxfdV9zaW0gPC0gY2JpbmQuZGF0YS5mcmFtZShhbGxfdV9zaW0sIHVfbmV3KQ0KICAgICAgYWxsX3RoZXRhX3NpbSA8LSBjYmluZC5kYXRhLmZyYW1lKGFsbF90aGV0YV9zaW0sIHRoZXRhX25ldykNCiAgICAgIA0KICAgICAgDQogICAgICAjIyBwb3N0c3RyYXRpZmljYXRpb24gbWV0aG9kDQogICAgICANCiAgICAgIGdsbW1fc2ltIDwtIGdsbWVyKHkgfiBhcy5mYWN0b3IoWDEpICsgYXMuZmFjdG9yKFgyKSArICgxfGNvdW50eSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGEsIGZhbWlseSA9IGJpbm9taWFsLCB3ZWlnaHRzPU5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGdsbWVyQ29udHJvbChvcHRpbWl6ZXIgPSAiYm9ieXFhIiksIG5BR1EgPSAxMCkNCiAgICAgIA0KICAgICAgYmV0YV9nbG1tIDwtIGdsbW1fc2ltQGJldGENCiAgICAgIHVfZ2xtbSA8LSBnbG1tX3NpbUB1DQogICAgICB0aGV0YV9nbG1tIDwtIGdsbW1fc2ltQHRoZXRhDQogICAgICANCiAgICAgICMjIFN1bSBzcXVhcmVkIGVycm9yIG9mIGdsbW0gZXN0aW1hdGVzDQogICAgICBTU0VfYmV0YV9nbG1tIDwtICBTU0VfYmV0YV9nbG1tICsgKGJldGFfc2ltLWJldGFfZ2xtbSleMg0KICAgICAgU1NFX3VfZ2xtbSA8LSBTU0VfdV9nbG1tICsgKHVfc2ltLXVfZ2xtbSleMg0KICAgICAgU1NFX3RoZXRhX2dsbW0gPC0gU1NFX3RoZXRhX2dsbW0gKyAodGhldGFfc2ltLXRoZXRhX2dsbW0pXjINCiAgICAgIFNTRV9nbG1tIDwtIHJiaW5kKFNTRV9iZXRhX2dsbW0sU1NFX3VfZ2xtbSxTU0VfdGhldGFfZ2xtbSkNCiAgICAgIHJvdy5uYW1lcyhTU0VfZ2xtbSkgPC0gYyhjb2xuYW1lcyhYKSxwYXN0ZTAoImdsbW1fdV8iLHVuaXF1ZShkZl9zaW0kY291bnR5KSksInRoZXRhIikNCiAgICAgIA0KICAgICAgYWxsX2JldGFfZ2xtbVtbcl1dIDwtIGJldGFfZ2xtbQ0KICAgICAgYWxsX3VfZ2xtbVtbcl1dIDwtIHVfZ2xtbQ0KICAgICAgYWxsX3RoZXRhX2dsbW1bW3JdXSA8LSB0aGV0YV9nbG1tDQogICAgfQ0KICAgIA0KICAgIHVfc2ltX2xzMltbc11dIDwtIHVfc2ltX2xzDQogICAgDQogICAgY29sbmFtZXMoZXJyX2FsbF9zaW1zKSA8LSBuYW1lc0Vycg0KICAgIE1TRSA8LSByb3dTdW1zKGVycl9hbGxfc2ltcykvbnNpbQ0KICAgIE1TRV90ZW1wIDwtIGNiaW5kKE1TRV90ZW1wLE1TRSkNCiAgICBuYW1lX01TRSA8LSBjKG5hbWVfTVNFLHBhc3RlMCgiTVNFXyIsYXJlYXNbcV0sIl8iLHNhbXBsZV9zaXplW3NdKSkNCiAgICANCiAgICANCiAgICBtZWFuX2JldGFfaGdsbSA8LSBjYmluZC5kYXRhLmZyYW1lKG1lYW5fYmV0YV9oZ2xtLHJvd1N1bXMoYWxsX2JldGFfc2ltWywyOm5jb2woYWxsX2JldGFfc2ltKV0pL25zaW0pDQogICAgbWVhbl91X2hnbG0gPC0gY2JpbmQuZGF0YS5mcmFtZShtZWFuX3VfaGdsbSxyb3dTdW1zKGFsbF91X3NpbVssMjpuY29sKGFsbF91X3NpbSldKS9uc2ltKQ0KICAgIG1lYW5fdGhldGFfaGdsbSA8LSBjYmluZC5kYXRhLmZyYW1lKG1lYW5fdGhldGFfaGdsbSxyb3dTdW1zKGFsbF90aGV0YV9zaW1bLDI6bmNvbChhbGxfdGhldGFfc2ltKV0pL25zaW0pDQogICAgDQogICAgZ2xtbV9uYW1lQiA8LSBjKGdsbW1fbmFtZUIscGFzdGUwKCJnbG1tX21lYW5fYmV0YV8iLGFyZWFzW3FdLCJfIixzYW1wbGVfc2l6ZVtzXSkpDQogICAgZ2xtbV9uYW1lVSA8LSBjKGdsbW1fbmFtZVUscGFzdGUwKCJnbG1tX21lYW5fdV8iLGFyZWFzW3FdLCJfIixzYW1wbGVfc2l6ZVtzXSkpDQogICAgZ2xtbV9uYW1lVCA8LSBjKGdsbW1fbmFtZVQscGFzdGUwKCJnbG1tX21lYW5fdGhldGFfIixhcmVhc1txXSwiXyIsc2FtcGxlX3NpemVbc10pKQ0KICAgIA0KICAgIGhnbG1fbmFtZUIgPC0gYyhoZ2xtX25hbWVCLHBhc3RlMCgiaGdsbV9tZWFuX2JldGFfIixhcmVhc1txXSwiXyIsc2FtcGxlX3NpemVbc10pKQ0KICAgIGhnbG1fbmFtZVUgPC0gYyhoZ2xtX25hbWVVLHBhc3RlMCgiaGdsbV9tZWFuX3VfIixhcmVhc1txXSwiXyIsc2FtcGxlX3NpemVbc10pKQ0KICAgIGhnbG1fbmFtZVQgPC0gYyhoZ2xtX25hbWVULHBhc3RlMCgiaGdsbV9tZWFuX3RoZXRhXyIsYXJlYXNbcV0sIl8iLHNhbXBsZV9zaXplW3NdKSkNCiAgICANCiAgICANCiAgICAjIyMgTVNFIGFuZCBlc3RpbWF0ZWQgcGFyYW1ldGVycyB1c2luZyBnbG1tDQogICAgTVNFX2JldGFfZ2xtbTAgPC0gU1NFX2JldGFfZ2xtbS9uc2ltDQogICAgTVNFX3VfZ2xtbTAgPC0gU1NFX3VfZ2xtbS9uc2ltDQogICAgIyBNU0VfZ2xtbTAgPC0gU1NFX2dsbW0vbnNpbQ0KICAgIE1TRV9nbG1tMFtbc11dIDwtIFNTRV9nbG1tL25zaW0NCiAgICANCiAgICBhbGxfYmV0YV9nbG1tIDwtIGRvLmNhbGwoY2JpbmQsYWxsX2JldGFfZ2xtbSkNCiAgICBhbGxfdV9nbG1tIDwtIGRvLmNhbGwoY2JpbmQsYWxsX3VfZ2xtbSkNCiAgICBhbGxfdGhldGFfZ2xtbSA8LSBkby5jYWxsKGNiaW5kLGFsbF90aGV0YV9nbG1tKQ0KICAgIA0KICAgIG1lYW5fYmV0YV9nbG1tIDwtIGNiaW5kLmRhdGEuZnJhbWUobWVhbl9iZXRhX2dsbW0sIHJvd1N1bXMoYWxsX2JldGFfZ2xtbSkvbnNpbSkNCiAgICBtZWFuX3VfZ2xtbSA8LSBjYmluZC5kYXRhLmZyYW1lKG1lYW5fdV9nbG1tLCByb3dTdW1zKGFsbF91X2dsbW0pL25zaW0pDQogICAgbWVhbl90aGV0YV9nbG1tIDwtIGNiaW5kLmRhdGEuZnJhbWUobWVhbl90aGV0YV9nbG1tLCByb3dTdW1zKGFsbF90aGV0YV9nbG1tKS9uc2ltKQ0KICAgIA0KICAgIA0KICAgIEVuZF90aW1lIDwtIFN5cy50aW1lKCkNCiAgICBydW5fdGltZSA8LSBFbmRfdGltZS1zdGFydF90aW1lDQogICAgcnVuX3RpbWVfcyA8LSBjYmluZChydW5fdGltZV9zLHJ1bl90aW1lKQ0KICAgIHJ1bl90aW1lX3MgPC0gZGF0YS5mcmFtZShydW5fdGltZV9zKQ0KICAgIA0KICAgICMgY2F0KHBhc3RlMCgiXG4gIixzLCIgYXJlYXMgRmluaXNoICEgXG4iKSkNCiAgICANCiAgICBjb252X25hbWUgPC0gYyhjb252X25hbWUscGFzdGUwKCJtXyIsYXJlYXNbcV0sIm5fIixzYW1wbGVfc2l6ZVtzXSkpDQogICAgDQogIH0NCiAgDQogIHVfc2ltX2xzM1tbcV1dIDwtIHVfc2ltX2xzMg0KICANCiAgDQogIHJ1bl90aW1lX2FsbFtbcV1dIDwtIHJ1bl90aW1lX3MNCiAgDQogIGNvbnZfaXRlcl9kZiA8LSBkby5jYWxsKGNiaW5kLmRhdGEuZnJhbWUsY29udl9pdGVyX2FsbCkNCiAgDQogICMgY29sbmFtZXMoY29udl9pdGVyX2RmKSA8LSBjb252X25hbWUNCiAgYWxsX2l0ZXJzW1txXV0gPC0gY29udl9pdGVyX2RmDQogIG5hbWVzX2l0ZXJbW3FdXSA8LSBjb252X25hbWUNCiAgDQogIA0KICANCiAgTVNFX2FsbCA8LSBkYXRhLmZyYW1lKE1TRV90ZW1wKQ0KICBjb2xuYW1lcyhNU0VfYWxsKSA8LSBuYW1lX01TRSANCiAgY29sbmFtZXMobWVhbl9iZXRhX2hnbG0pIDwtIGhnbG1fbmFtZUINCiAgY29sbmFtZXMobWVhbl91X2hnbG0pIDwtIGhnbG1fbmFtZVUNCiAgY29sbmFtZXMobWVhbl90aGV0YV9oZ2xtKSA8LSBoZ2xtX25hbWVUDQogIA0KICBNU0VfZ2xtbSA8LSBkby5jYWxsKGNiaW5kLE1TRV9nbG1tMCkNCiAgY29sbmFtZXMoTVNFX2dsbW0pIDwtIG5hbWVfTVNFDQogIGNvbG5hbWVzKG1lYW5fYmV0YV9nbG1tKSA8LSBnbG1tX25hbWVCDQogIGNvbG5hbWVzKG1lYW5fdV9nbG1tKSA8LSBnbG1tX25hbWVVDQogIGNvbG5hbWVzKG1lYW5fdGhldGFfZ2xtbSkgPC0gZ2xtbV9uYW1lVA0KICANCiAgTVNFX3VfZGYgPC0gTVNFX2FsbFsobmNvbChYKSsxKTooKG5jb2woWCkrMSkrbGVuZ3RoKHVfc2ltKS0xKSxdDQogIE1TRV91IDwtIGNvbFN1bXMoTVNFX3VfZGYpL2xlbmd0aCh1X3NpbSkNCiAgTVNFX2hnbG0gPC0gcmJpbmQuZGF0YS5mcmFtZShNU0VfYWxsLE1TRV9maW5hbD1NU0VfdSkNCiAgTVNFX2hnbG0gPC0gTVNFX2hnbG1bLW5yb3coTVNFX2hnbG0pLCBdDQogIA0KICByb3duYW1lcyhtZWFuX2JldGFfaGdsbSkgPC0gYyhjb2xuYW1lcyhYKSkNCiAgcm93bmFtZXMobWVhbl91X2hnbG0pIDwtIGMocGFzdGUwKCJ1XyIsdW5pcXVlKGRmX3NpbSRjb3VudHkpKSkNCiAgcm93bmFtZXMobWVhbl90aGV0YV9oZ2xtKSA8LSBjKCJ0aGV0YSIpDQogIA0KICBiZXRhX2dsbW1faGdsbSA8LSBkYXRhLmZyYW1lKG1lYW5fYmV0YV9oZ2xtLG1lYW5fYmV0YV9nbG1tKQ0KICB1X2dsbW1faGdsbSA8LSBkYXRhLmZyYW1lKG1lYW5fdV9oZ2xtLG1lYW5fdV9nbG1tKQ0KICB0aGV0YV9nbG1tX2hnbG0gPC0gZGF0YS5mcmFtZShtZWFuX3RoZXRhX2hnbG0sbWVhbl90aGV0YV9nbG1tKQ0KICBNU0VfZ2xtbV9oZ2xtIDwtIGRhdGEuZnJhbWUoTVNFX2dsbW0sIE1TRV9oZ2xtKQ0KICANCiAgIyB3cml0ZS5jc3YoYmV0YV9nbG1tX2hnbG0scGFzdGUwKHBhdGgsIi9vdXQvbWVhbl9iZXRhX2hnbG0iKSxyb3cubmFtZXMgPSBGQUxTRSkNCiAgcHJpbnQobWVhbl9iZXRhX2dsbW0pDQogIHByaW50KGJldGFfZ2xtbV9oZ2xtKQ0KICBwcmludChtZWFuX3VfaGdsbSkNCiAgcHJpbnQobWVhbl90aGV0YV9oZ2xtKQ0KICBwcmludChNU0VfaGdsbSkNCiAgcHJpbnQobWVhbl9iZXRhX2dsbW0pDQogIHByaW50KG1lYW5fdV9nbG1tKSANCiAgcHJpbnQobWVhbl90aGV0YV9nbG1tKQ0KICBwcmludChNU0VfZ2xtbSkNCiAgcHJpbnQodV9zaW1fbHMzKQ0KICANCiAgZmluYWxfZXN0c1tbcV1dIDwtIGxpc3QoYmV0YV9nbG1tX2hnbG0sdV9nbG1tX2hnbG0sdGhldGFfZ2xtbV9oZ2xtLE1TRV9nbG1tX2hnbG0pDQogIA0KfQ0KDQphbGxfaXRlcnNfZGYgPC0gZG8uY2FsbChjYmluZC5kYXRhLmZyYW1lLGFsbF9pdGVycykNCml0ZXJfbmFtZXMgPC0gIHVubGlzdChuYW1lc19pdGVyKQ0KY29sbmFtZXMoYWxsX2l0ZXJzX2RmKSA8LSBpdGVyX25hbWVzDQoNCnJ1bl90aW1lX2ZpbmFsIDwtIGRvLmNhbGwoY2JpbmQuZGF0YS5mcmFtZSxydW5fdGltZV9hbGwpDQpjb2xuYW1lcyhydW5fdGltZV9maW5hbCkgPC0gaXRlcl9uYW1lcw0KDQoNCnNhdmUoZmluYWxfZXN0cyxiZXRhX2dsbW1faGdsbSxtZWFuX2JldGFfZ2xtbSxtZWFuX3VfaGdsbSxtZWFuX3RoZXRhX2hnbG0sTVNFX2hnbG0sDQogICAgIG1lYW5fYmV0YV9nbG1tLCBtZWFuX3VfZ2xtbSwgbWVhbl90aGV0YV9nbG1tLCBNU0VfZ2xtbSwNCiAgICAgdV9zaW1fbHMzLGFsbF9pdGVyc19kZixydW5fdGltZV9maW5hbCwgZmlsZT0iL3dvcmsvZGFpL25pcm9zaGFwci9IR0xNL291dF9CaWFzQy9lc3RfYWxsX3NpbS5SRGF0YSIpDQoNCmBgYA0KDQoNCg0KIyMjIFVzaW5nIFlSQkZTUyBEYXRhIHNldCAtIEhHTE0gdnMgR0xNTSANCg0KDQojIyMjIyMgSW50ZWdyYXRlZCBmdW5jdGlvbnMgDQoNCmBgYHtyfQ0KIyBjb2x4IDwtIGRmIA0KZl9sdmxzIDwtIGZ1bmN0aW9uKGNvbHgseCl7DQogIGNvbHggPC0gY29seFsscGFzdGUwKHgpXQ0KICBsdmxzPXVuaXF1ZShjb2x4KQ0KICByZXR1cm4obHZscykNCn0NCg0KDQojIyMgQ3JlYXRlIGdyb3VwcyBjb21iaW5pbmcgbGV2ZWxzDQpuZXdfZ3JwIDwtIGZ1bmN0aW9uKGRmLHgpew0KICAjIGRmIDwtIGRmX3N1YjsgeCA8LSAiYWdlIg0KICBkZiA8LSBkZltvcmRlcihkZiRjb3VudHkpLCBdDQogIHZhcnggPC0gZGZbLCBwYXN0ZTAoeCldDQogIHZhcnggPC0gaWZlbHNlKGRmJGFnZSAlaW4lIGMoMTpuMSksIjEiLA0KICAgICAgICAgICAgICAgICBpZmVsc2UoZGYkYWdlICVpbiUgYygobjErMSk6bjIpLCAiMiIsIjMiKSkNCiAgZGYgPC0gZGZbLCFjb2xuYW1lcyhkZiklaW4lcGFzdGUwKHgpXQ0KICBjbmFtZXMgPC0gY29sbmFtZXMoZGYpDQogIGRmIDwtIGRhdGEuZnJhbWUoZGYsIHZhcngpDQogIGNvbG5hbWVzKGRmKSA8LSBjKGNuYW1lcyxwYXN0ZTAoeCkpDQogIHJldHVybihkZikNCn0NCg0KDQoNCiMgeXJic3NfZGF0DQojIyBHcm91cGluZyB0aGUgcmVzcG9uc2UgdmFyaWFibGUsIDE9ZWNpZ19ubywgMj1lY2lnX3llcw0KIyBkZiA8LSBkZl9zdWIgb3IgZGYgPC0gZGF0YSwgcmVzcCANCmRmX3kgPC0gZnVuY3Rpb24oZGYseSl7DQogIHRlbXAgPC0gZGZbLCB5XQ0KICB0ZW1wIDwtIGlmZWxzZSh0ZW1wPT0xLDAsaWZlbHNlKHRlbXA9PTIsMSx0ZW1wKSkNCiAgdGVtcCA8LSBhcy5pbnRlZ2VyKHRlbXApDQogIHRlbXAgPC0gZGF0YS5mcmFtZSh0ZW1wKQ0KICBjb2xuYW1lcyh0ZW1wKSA8LSB5DQogIGRmIDwtIGRhdGEuZnJhbWUodGVtcCxkZikNCiAgZGYgPC0gZGZbLCFjb2xuYW1lcyhkZikgJWluJSBwYXN0ZTAoeSwiLjEiKV0NCiAgcmV0dXJuKGRmKQ0KfQ0KDQoNCg0KDQojIFRoaXMgZnVuY3Rpb24gY3JlYXRlIG1vZGVsIGZvcm11bGEgY29tYmluaW5nIA0KIyBkaXNjcmV0ZSBhbmQgY29udCB2YXJpYWJsZXMgZGVwZW5kaW5nIG9uIHRoZQ0KIyBtb2RlbCBhbGdvcml0aG0NCm15LmZvcm0gPC0gIGZ1bmN0aW9uKGRpc192YXJzLGNvbnRfdmFycyl7DQogIGZhY19mb211bGFyIDwtIHBhc3RlMChyZXNwLCJ+IikNCiAgZm9yKGkgaW4gMTpsZW5ndGgoZGlzX3ZhcnMpKXsNCiAgICB0ZW1wIDwtIHBhc3RlMCgiYXMuZmFjdG9yKCIsZGlzX3ZhcnNbaV0sIikrIikNCiAgICBmYWNfZm9tdWxhciA8LSBwYXN0ZTAoZmFjX2ZvbXVsYXIsdGVtcCkgDQogIH0NCiAgDQogIGNvbnRfZm9tdWxhciA8LSBmYWNfZm9tdWxhcg0KICANCiAgaWYobGVuZ3RoKGNvbnRfdmFycykhPTApew0KICAgIA0KICAgIGlmKG1vZGVsLnR5cGU9PSJnbG1tIil7DQogICAgICBmb3IoaiBpbiAxOmxlbmd0aChjb250X3ZhcnMpKXsNCiAgICAgICAgdGVtcCA8LSBwYXN0ZTAoY29udF92YXJzW2pdKQ0KICAgICAgICBjb250X2ZvbXVsYXIgPC0gcGFzdGUwKGNvbnRfZm9tdWxhcix0ZW1wKQ0KICAgICAgfQ0KICAgIH1lbHNlIGlmKG1vZGVsLnR5cGU9PSJoZ2xtIil7DQogICAgICBmb3IoaiBpbiAxOmxlbmd0aChjb250X3ZhcnMpKXsNCiAgICAgICAgdGVtcCA8LSBwYXN0ZTAoY29udF92YXJzW2pdKQ0KICAgICAgICBjb250X2ZvbXVsYXIgPC0gcGFzdGUwKGNvbnRfZm9tdWxhcix0ZW1wKQ0KICAgICAgfQ0KICAgIH0NCiAgfWVsc2V7DQogICAgY29udF9mb211bGFyIDwtIGZhY19mb211bGFyDQogIH0NCiAgcmV0dXJuKGNvbnRfZm9tdWxhcikNCn0NCg0KDQoNCg0KIyMgTGV2ZWxzIG9mIGVhY2ggZGlzY3JldGUgdmFyDQoNCmxzX2Z1bmMgPC0gZnVuY3Rpb24oZGlzX3ZhcnMpew0KICBsc19kaXNjIDwtIGxpc3QoKQ0KICBmb3IoaSBpbiAxOmxlbmd0aChkaXNfdmFycykpew0KICAgICMgaSA8LSAzDQogICAgZGlzX3ZhcnMgPC0gZGlzX3ZhcnNbb3JkZXIoZGlzX3ZhcnMpXQ0KICAgIHYgPC0gZGlzX3ZhcnNbaV0NCiAgICBsdmxzIDwtIGZfbHZscyhkYXRhLHBhc3RlMCh2KSkNCiAgICBsdmxzIDwtIGx2bHNbIWlzLm5hKGx2bHMpXQ0KICAgIGx2bHMgPC0gbHZsc1tvcmRlcihsdmxzKV0NCiAgICBYIDwtIGMobm9xdW90ZSgiTGV2ZWxzIG9mIiksdixhcy52ZWN0b3IobHZscykpDQogICAgbHNfZGlzY1tbaV1dIDwtIFggDQogIH0NCiAgcmV0dXJuKGxzX2Rpc2MpDQp9DQoNCg0KIyMgRnVuY3Rpb24gdG8gZ2V0IHRyYWNlIG9mIGEgbSBhdHJpeA0KZnVuY190cmFjZSA8LSBmdW5jdGlvbihYKXsNCiAgbiA8LSBkaW0oWClbMV0gDQogIHRyIDwtIDAgICAgIyMjIGluaXRpYWxpemUgdHJhY2UgDQogIA0KICBmb3IgKGogaW4gMTpuKXsNCiAgICBrIDwtIFhbaixqXQ0KICAgIHRyIDwtIHRyICsgaw0KICB9DQogIHJldHVybih0cltbMV1dKQ0KfQ0KDQoNCnBsb3RfZnVuYyA8LSBmdW5jdGlvbihkZix1c19zdGF0ZSl7DQogICMgdXNfc3RhdGUgPC0gdXNtYXA6OnVzX21hcChyZWdpb25zID0gImNvdW50aWVzIikNCiAgdXNfc3RhdGUkZmlwcyA8LSBhcy5udW1lcmljKHVzX3N0YXRlJGZpcHMpDQogIGRmJGNvdW50eSA8LSBhcy5udW1lcmljKGRmJGNvdW50eSkNCiAgY29sbmFtZXMoZGYpIDwtIGlmZWxzZShjb2xuYW1lcyhkZiklaW4lImNvdW50eSIsImZpcHMiLGNvbG5hbWVzKGRmKSkNCiAgZGF0YV9hbGwwIDwtIGxlZnRfam9pbih1c19zdGF0ZSxkZixieT0iZmlwcyIpDQogIA0KICAjIGdldCB0aGUgY2VudGVyIGxvY2F0aW9uIGZvciBlYWNoIHN0YXRlDQogIA0KICBpZihwbG90X2J5X3llYXI9PSJZRVMiKXsNCiAgICBwbG90X2RhdGE8LSBsaXN0KCkNCiAgICBmb3IoaiBpbiAxOmxlbmd0aCh5cikpew0KICAgICAgIyBqIDwtIDENCiAgICAgIGRhdGFfYWxsIDwtIGRhdGFfYWxsMFtkYXRhX2FsbDAkeWVhcj09eXJbal0sXQ0KICAgICAgDQogICAgICBkZl9zdGF0ZSA8LSBkYXRhX2FsbCAlPiUgZ3JvdXBfYnkoYWJicikgJT4lIHN1bW1hcmlzZShtbG9uZz1tZWFuKGxvbmcpLG1sYXQ9bWVhbihsYXQpKQ0KICAgICAgDQogICAgICBub19jbGFzc2VzIDwtIDcNCiAgICAgIGxhYmVscyA8LSBjKCkNCiAgICAgIHF1YW50aWxlcyA8LSBxdWFudGlsZShkYXRhX2FsbCRwcmVkX2NudHlfcHJldiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IHNlcSgwLCAxLCBsZW5ndGgub3V0ID0gbm9fY2xhc3NlcyArIDEpLG5hLnJtPVRSVUUpDQogICAgICAjIEN1c3RvbSBsYWJlbHMsIHJvdW5kaW5nDQogICAgICBsYWJlbHMgPC0gYygpDQogICAgICBmb3IoaWR4IGluIDE6bGVuZ3RoKHF1YW50aWxlcykpew0KICAgICAgICBsYWJlbHMgPC0gYyhsYWJlbHMsIHBhc3RlMChyb3VuZChxdWFudGlsZXNbaWR4XSwgMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQocXVhbnRpbGVzW2lkeCArIDFdLCAyKSkpDQogICAgICB9DQogICAgICAjIE1pbnVzIG9uZSBsYWJlbCB0byByZW1vdmUgdGhlIG9kZCBlbmRpbmcgb25lDQogICAgICBsYWJlbHMgPC0gbGFiZWxzWzE6bGVuZ3RoKGxhYmVscyktMV0NCiAgICAgIA0KICAgICAgIyBDcmVhdGUgbmV3IHZhcmlhYmxlIGZvciBmaWxsDQogICAgICBkYXRhX2FsbCRwcmV2X3F1YW50IDwtIGN1dChkYXRhX2FsbCRwcmVkX2NudHlfcHJldiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHF1YW50aWxlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVCkNCiAgICAgIHBsb3RfZGF0YVtbal1dIDwtIGRhdGFfYWxsDQogICAgICANCiAgICB9DQogIH1lbHNlIGlmKHBsb3RfYnlfeWVhcj09Ik5PIil7DQogICAgDQogICAgZGF0YV9hbGwgPC0gZGF0YV9hbGwwICU+JSBkcGx5cjo6c2VsZWN0KGxvbmcsbGF0LGZpcHMseWVhcixwcmVkX2NudHlfcHJldikgJT4lIA0KICAgICAgZ3JvdXBfYnkoZmlwcykgJT4lIHN1bW1hcml6ZShBdmdQcmV2PW1lYW4ocHJlZF9jbnR5X3ByZXYpKQ0KICAgIGRhdGFfYWxsIDwtIGRhdGEuZnJhbWUoZGF0YV9hbGwpDQogICAgDQogICAgZGF0YV9hbGwxIDwtIGRhdGFfYWxsMFssIWNvbG5hbWVzKGRhdGFfYWxsMCklaW4lIGMoInllYXIiLCJwcmVkX2NudHlfcHJldiIsImxvZ2l0X3Byb2IiLCJ0cnVlX3ByZXZhbGVuY2UiKV0NCiAgICBkYXRhX2FsbDEgPC0gdW5pcXVlKGRhdGFfYWxsMSkNCiAgICBkYXRhX2FsbDIgPC0gbWVyZ2UoZGF0YV9hbGwxLGRhdGFfYWxsLCBieT0iZmlwcyIpDQogICAgDQogICAgZGZfc3RhdGUgPC0gZGF0YV9hbGwyICU+JSBncm91cF9ieShhYmJyKSAlPiUgc3VtbWFyaXNlKG1sb25nPW1lYW4obG9uZyksbWxhdD1tZWFuKGxhdCkpDQogICAgDQogICAgbm9fY2xhc3NlcyA8LSA3DQogICAgbGFiZWxzIDwtIGMoKQ0KICAgIHF1YW50aWxlcyA8LSBxdWFudGlsZShkYXRhX2FsbDIkQXZnUHJldiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSBzZXEoMCwgMSwgbGVuZ3RoLm91dCA9IG5vX2NsYXNzZXMgKyAxKSxuYS5ybT1UUlVFKQ0KICAgICMgQ3VzdG9tIGxhYmVscywgcm91bmRpbmcNCiAgICBsYWJlbHMgPC0gYygpDQogICAgZm9yKGlkeCBpbiAxOmxlbmd0aChxdWFudGlsZXMpKXsNCiAgICAgIGxhYmVscyA8LSBjKGxhYmVscywgcGFzdGUwKHJvdW5kKHF1YW50aWxlc1tpZHhdLCAyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJfIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHF1YW50aWxlc1tpZHggKyAxXSwgMikpKQ0KICAgIH0NCiAgICAjIE1pbnVzIG9uZSBsYWJlbCB0byByZW1vdmUgdGhlIG9kZCBlbmRpbmcgb25lDQogICAgbGFiZWxzIDwtIGxhYmVsc1sxOmxlbmd0aChsYWJlbHMpLTFdDQogICAgDQogICAgIyBDcmVhdGUgbmV3IHZhcmlhYmxlIGZvciBmaWxsDQogICAgZGF0YV9hbGwyJHByZXZfcXVhbnQgPC0gY3V0KGRhdGFfYWxsMiRBdmdQcmV2LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBxdWFudGlsZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxhYmVscywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUKQ0KICAgIHBsb3RfZGF0YSA8LSBkYXRhX2FsbDINCiAgfQ0KICANCiAgcmV0dXJuKHBsb3RfZGF0YSkNCn0NCg0KDQpyZXNwX3RpdGxlIDwtIGZ1bmN0aW9uKHJlc3Apew0KICBpZihyZXNwPT0iZWNpZ19ldmVyIil7DQogICAgdGl0X3kgPC0gIkV2ZXIgRWNpZyINCiAgfWVsc2UgaWYocmVzcD09ImVjaWdfY3VycmVudCIpew0KICAgIHRpdF95IDwtICJDdXJyZW50IEVjaWciDQogIH1lbHNlIGlmKHJlc3A9PSJzbW9rZV9jdXJyZW50Iil7DQogICAgdGl0X3kgPC0gIkN1cnJlbnQgU21va2UiDQogIH1lbHNlIGlmKHJlc3A9PSJzbW9rZV9ldmVyIil7DQogICAgdGl0X3kgPC0gIkV2ZXIgU21va2UiDQogIH0NCiAgcmV0dXJuKHRpdF95KQ0KfQ0KDQoNCiMgZ2V0IHRoZSBjZW50ZXIgbG9jYXRpb24gZm9yIGVhY2ggc3RhdGUNCm1lYW5fbG9nX2xhdCA8LSBmdW5jdGlvbihkZil7DQogICMgZGYgPC0gcHJlZF9wcmV2X2NudHkNCiAgdXNfc3RhdGUgPC0gdXNtYXA6OnVzX21hcChyZWdpb25zID0gImNvdW50aWVzIikNCiAgY29sbmFtZXModXNfc3RhdGUpIDwtIGMoImxvbmciLCJsYXQiLCJvcmRlciIsImhvbGUiLCJwaWVjZSIsImdyb3VwIiwiZmlwcyIsImFiYnIiLCJmdWxsIiwiY291bnR5IikNCiAgdXNfc3RhdGUkZmlwcyA8LSBhcy5udW1lcmljKHVzX3N0YXRlJGZpcHMpDQogIA0KICBjb2xuYW1lcyhkZikgPC0gaWZlbHNlKGNvbG5hbWVzKGRmKSVpbiUiY291bnR5IiwiZmlwcyIsY29sbmFtZXMoZGYpKQ0KICBkYXRhX2FsbDAgPC0gbGVmdF9qb2luKHVzX3N0YXRlLGRmLGJ5PSJmaXBzIikNCiAgDQogIGlmKHBsb3RfYnlfeWVhcj09IllFUyIpew0KICAgIGRmX3N0YXRlIDwtIGRhdGFfYWxsICU+JSBncm91cF9ieShhYmJyKSAlPiUgc3VtbWFyaXNlKG1sb25nPW1lYW4obG9uZyksbWxhdD1tZWFuKGxhdCkpDQogIH1lbHNlew0KICAgIGRmX3N0YXRlIDwtIGRhdGFfYWxsMCAlPiUgZ3JvdXBfYnkoYWJicikgJT4lIHN1bW1hcmlzZShtbG9uZz1tZWFuKGxvbmcpLG1sYXQ9bWVhbihsYXQpKQ0KICB9DQogIA0KICAjIGRhdGFfYWxsIDwtIGRhdGFfYWxsMFtkYXRhX2FsbDAkeWVhcj09eXJbMV0sXQ0KICByZXR1cm4oZGZfc3RhdGUpDQp9DQoNCg0KYGBgDQoNCg0KIyMjIyBSZWFsIERhdGEgQW5hbHlzaXMgdXNpbmcgSEdMTSBpbiBTQUUNCg0KYGBge3J9DQoNCg0KDQoNCg0KIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENhbGwgcGFja2FnZXMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyAjDQpybShsaXN0PWxzKCkpDQoNCnBhY2thZ2VzIDwtIGMoInNhZSIsICJkYXRhLnRhYmxlIiwicmVhZHhsIiwgImRwbHlyIiwgImdtb2RlbHMiLA0KICAgICAgICAgICAgICAicGRmdG9vbHMiLCAicmVzaGFwZTIiLCJicm9vbSIsInRpZHlyIiwiQmF5ZXNTQUUiLCJjb3JwY29yIiwNCiAgICAgICAgICAgICAgImZhc3REdW1taWVzIiwibWFwcyIsImdnbWFwIiwiZ2Vvc3BoZXJlIiwic3FsZGYiLCJsbWU0IikNCg0KaXBhayA8LSBmdW5jdGlvbihwa2cpew0KICBuZXcucGtnIDwtIHBrZ1shKHBrZyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpWywgIlBhY2thZ2UiXSldDQogIGlmKGxlbmd0aChuZXcucGtnKSkgDQogICAgaW5zdGFsbC5wYWNrYWdlcyhuZXcucGtnLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICBzYXBwbHkocGtnLCByZXF1aXJlLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQp9DQoNCmlwYWsocGFja2FnZXMpDQoNCmRpcl9wYXRoIDwtIGdldHdkKCkNCg0KIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUmVhZCBEYXRhICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyAjDQoNCnNvdXJjZShwYXN0ZTAoZGlyX3BhdGgsIi9DMV9DZW5zdXNfRGF0YVByZXAuUiIpKQ0Kc291cmNlKHBhc3RlMChkaXJfcGF0aCwiL2hnbG1fZ2xtbV9pbnRlZ3JhdGVkX2Z1bmNWMi5SIikpDQoNCg0KZGF0YSA8LSBkYXRhLmZyYW1lKGRhdGEudGFibGU6OmZyZWFkKHBhc3RlMChkaXJfcGF0aCwiL2RhdGEvWVJCU1NOZXcuY3N2IikpKQ0KDQpkZiA8LSBkYXRhDQpkZiA8LSBkZltvcmRlcihkZiRjb3VudHkpLCBdDQpyZXNwIDwtICJlY2lnX2V2ZXIiICAgIyBlY2lnX2N1cnJlbnQsICBlY2lnX2V2ZXIsIHNtb2tlX2N1cnJlbnQsIHNtb2tlX2V2ZXINCmRpc192YXJzIDwtIGMoImFnZSIsInNleCIsInJhY2U0IiwieWVhciIpICAgIyMjIGNvbnNpZGVyIHllYXIgbGF0ZXINCmNvbnRfdmFycyA8LSBjKCJwb3Z0X3JhdGUiKQ0Kd2dodCA8LSAid3QxIg0KcmUgPC0gImNvdW50eSINCm1vZGVsLnR5cGUgPC0gImhnbG0iICAgIA0Kc2F2ZS5vdXQgPC0gIllFUyINCmRhdGFfY2hhbmdlIDwtICJOTyIgICMjIElmIFlFUyBoZWVkIHRvIGNhbGN1bGF0ZSBkaXN0YW5jZSBmb3IgYWRqY2VudCBjb3VudGllcw0KZml0Lm1vZGVsIDwtICJZRVMiDQpwbG90X2J5X3llYXIgPC0gIk5PIg0Kc2F2ZS5wbG90IDwtICJZRVMiDQoNCiMjIEFnZSBsZXZlbHMgMTozPTEsIDQ6NT0yLCAmIDY6Nz0zDQpuMSA8LSAzOyBuMj01IA0KDQojIGFmdGVyIHJlLWpvaW5pbmcgbGV2ZWxzLCBlbnRlciBob3cgbWFueSBsZXZlbHMgaW4gZWFjaCBkaXMgdmFyDQpEWDAgPC0gZXhwYW5kLmdyaWQoYWdlPWMoIjEiLCIyIiwiMyIpLHNleD1jKCIxIiwiMiIpLCByYWNlND1jKCIxIiwiMiIsIjMiLCI0IiksIHllYXI9YygiMSIsIjIiKSkNCm91dC5wYXRoIDwtIHBhc3RlMChkaXJfcGF0aCwiL291dC8iLHJlc3AsIi8iKQ0KZGlzX3ZhcnMgPC0gZGlzX3ZhcnNbb3JkZXIoZGlzX3ZhcnMpXQ0KZGlzX3ZhcnMNCg0KDQppZigieWVhciIgJWluJSBjb2xuYW1lcyhkZikpew0KICBkZiR5ZWFyIDwtIGFzLm51bWVyaWMoZGYkeWVhcikNCiAgZGYkeWVhciA8LSBpZmVsc2UoZGYkeWVhcj09IjIwMTUiLDEsDQogICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZiR5ZWFyPT0iMjAxNyIsMixkZiR5ZWFyKSkNCn0NCg0KDQojICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGF0YSBQcmVwICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysgIw0KDQoNCg0KaWYoIkZJUFMiICVpbiUgY29sbmFtZXMoZGYpKXsNCiAgY29sbmFtZXMoZGYpIDwtICJjb3VudHkiDQp9ZWxzZXsNCiAgY29sbmFtZXMoZGYpIDwtIGNvbG5hbWVzKGRmKQ0KfQ0KDQojKiogRmlsdGVyIHZhcmlhYmxlcyBmcm9tIG9yaWdpbmFsIGRhdGEgc2V0DQpkZl9zdWIgPC0gZGF0YS5mcmFtZShkZlssIGNvbG5hbWVzKGRmKSAlaW4lIGMocmVzcCxyZSxkaXNfdmFycyxjb250X3ZhcnMsd2dodCldKQ0Kd3QgPC0gZGF0YS5mcmFtZShkZlssIGNvbG5hbWVzKGRmKSAlaW4lIGMod2dodCldKQ0KY29sbmFtZXMod3QpIDwtICJ3dCINCmRmX3N1YiA8LSBkZl9zdWJbY29tcGxldGUuY2FzZXMoZGZfc3ViKSwgXQ0KDQojKiogTGV2ZWxzIG9mIGFnZSB2YXJpYWJsZQ0KbHZscyA8LSBmX2x2bHMoZGZfc3ViLCJhZ2UiKQ0KbHZscw0KDQoNCg0KIyoqIENyZWF0ZSBhZ2UgZ3JvdXBpbmcNCmRmX3N1YiA8LSBuZXdfZ3JwKGRmX3N1YiwiYWdlIikNCiMqKiBncm91cCByZXNwb25zZSB2YXJpYWJsZSB1c2luZyBmdW5jdGlvbg0KZGZfc3ViIDwtIGRmX3koZGY9ZGZfc3ViLHk9cmVzcCkgICAjDQp5cmJzc19kZiA8LSBkZl9zdWIgICAgICMjICBvYnMgLCB0aGlzIGRmIHdpbGwgYmUgdXNlZCBpbiBhcmVhIGVzdCBtb2RlbGxpbmcgc2VjdGlvbg0KDQojKiogd2l0aCBuZXcgZ3JvdXBpbmcgZm9yIGFnZQ0KcHJpbnQoIkZyZXEgdGFibGUgd2l0aCBuZXcgZ3JvdXBpbmc6ICIpDQp0YWJsZSh5cmJzc19kZiRhZ2UpDQp0YWJsZSh5cmJzc19kZiR5ZWFyKQ0KdGFibGUoeXJic3NfZGYkc2V4KQ0KdGFibGUoeXJic3NfZGYkcmFjZTQpDQoNCg0KIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICAgICAgICAgICAgICAgICAgICAgICAgQ2FsY3VsYXRlIHRydWUgcHJldmFsZW5jZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAjDQojIENhbGN1bGF0ZSBjb3VudHkgd2lzZSBwcmV2YWxlbmNlIGZvciBlYWNoIHllYXIgYW5kIGNvbWJpbmUgZGZzIA0KDQoNCnlyIDwtIHVuaXF1ZShkZl9zdWIkeWVhcikNCiMqKiBkZl9zdWIwIDwtIGRmX3N1Yg0KdHJ1ZV9wcmV2MSA8LSBsaXN0KCkNCmZvcihpIGluIDE6bGVuZ3RoKHlyKSl7DQogICMgaSA8LSAyDQogIGRmX3N1YjAgPC0gZGZfc3ViW2RmX3N1YiR5ZWFyJWluJXlyW2ldLCBdIA0KICBteUZvcm11bGEgPC0gc3ByaW50ZigiY291bnR5fiVzIiwgcmVzcCkNCiAgdHJ1ZV9wcmV2MCA8LSBzcWxkZjo6IHNxbGRmKHBhc3RlMCgic2VsZWN0ICogZnJvbSBkZl9zdWIwIHdoZXJlICIscmVzcCwiIGlzIG5vdCBudWxsIikpICU+JSANCiAgICBkY2FzdChhcy5mb3JtdWxhKG15Rm9ybXVsYSkpICU+JSAgICAjIHRvdGFsICMgb2YgcmVjb3JkcyBmb3IgZWFjaCBjb3VudHkNCiAgICBnYXRoZXIodmFyaWFibGUsIHZhbHVlLCAtY291bnR5KSAlPiUgICAjIyANCiAgICBncm91cF9ieShjb3VudHkpICU+JQ0KICAgIG11dGF0ZShwZXJjZW50YWdlID0gdmFsdWUvc3VtKHZhbHVlKSkgJT4lIA0KICAgICMgc2VsZWN0KC12YWx1ZSkgJT4lIA0KICAgIHNwcmVhZCh2YXJpYWJsZSwgcGVyY2VudGFnZSkNCiAgdHJ1ZV9wcmV2MCA8LSBkYXRhLmZyYW1lKHRydWVfcHJldjApDQogIHRydWVfcHJldjAgPC0gZGF0YS5mcmFtZSh0cnVlX3ByZXYwLCBsb2dpdF9wcm9iPWxvZyh0cnVlX3ByZXYwJFgxLygxLXRydWVfcHJldjAkWDEpKSkNCiAgdHJ1ZV9wcmV2MCA8LSB0cnVlX3ByZXYwWyFpcy5uYSh0cnVlX3ByZXYwJGxvZ2l0X3Byb2IpLCBdDQogIHRydWVfcHJldjFbW2ldXSA8LSBkYXRhLmZyYW1lKHRydWVfcHJldjAsIHllYXI9eXJbaV0pDQogIHJtKHRydWVfcHJldjApDQp9DQp0cnVlX3ByZXYgPC0gZG8uY2FsbChyYmluZCx0cnVlX3ByZXYxKQ0KaGVhZCh0cnVlX3ByZXYpDQoNCg0KIyoqIFJlbW92ZSAtSW5mIGZvciBwcmV2YWxlbmNlDQppZigiLUluZiIgJWluJSB0cnVlX3ByZXYkbG9naXRfcHJvYil7DQogIHJlbV9jbnR5IDwtIGFzLm51bWVyaWModHJ1ZV9wcmV2JGNvdW50eVt3aGljaCh0cnVlX3ByZXYkbG9naXRfcHJvYiA9PSItSW5mIildKQ0KICB0cnVlX3ByZXYgPC0gdHJ1ZV9wcmV2W3RydWVfcHJldiRsb2dpdF9wcm9iICE9Ii1JbmYiLF0NCn1lbHNlew0KICB0cnVlX3ByZXYgPC0gdHJ1ZV9wcmV2DQogIHRydWVfcHJldiA8LSB0cnVlX3ByZXZbIWlzLm5hKHRydWVfcHJldiRsb2dpdF9wcm9iKSwgXQ0KfQ0KDQp0cnVlX3ByZXYgPC0gdHJ1ZV9wcmV2WywgIWNvbG5hbWVzKHRydWVfcHJldikgJWluJSBjKCJ2YWx1ZSIsIlgwIiwiWDEiKV0NCmhlYWQodHJ1ZV9wcmV2KQ0KDQoNCg0KIyoqIENvbWJpbmUgWVJCU1MgZGF0YSB3aXRoIHBvdiBkYXRhIGFuZCBjcmVhdGUgZHVtbXkgY29sbnMgZm9yIGRpcyB2YXJzDQojIGNvdW50aWVzIGluIFlSQlNTIGRhdGEgZm9yIHkNCmNvbV9jbnR5IDwtIHVuaXF1ZSh5cmJzc19kZiRjb3VudHkpICAgDQoNCmlmKCJ5ZWFyIiAlaW4lIGNvbG5hbWVzKHBvdl9wb3ApKXsNCiAgcG92X3BvcCR5ZWFyIDwtIGlmZWxzZShwb3ZfcG9wJHllYXI9PSIyMDE1IiwxLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShwb3ZfcG9wJHllYXI9PSIyMDE3IiwyLHBvdl9wb3AkeWVhcikpICANCn0NCnBvdl9wb3Bfc3ViIDwtIHBvdl9wb3BbcG92X3BvcCRjb3VudHkgJWluJSBjb21fY250eSwgXQ0KDQpkaXNfdmFyczAgPC0gZGlzX3ZhcnNbIWRpc192YXJzJWluJSJ5ZWFyIl0NClhkYXRhX2R1bW15IDwtIGZhc3REdW1taWVzOjpkdW1teV9jb2xzKHlyYnNzX2RmLHNlbGVjdF9jb2x1bW5zID0gZGlzX3ZhcnMpJT4lIA0KICAjIGRwbHlyOjpzZWxlY3QoLWMoeSkpICU+JSANCiAgbGVmdF9qb2luKHBvdl9wb3Bfc3ViLCBieT1jKCJjb3VudHkiLCJ5ZWFyIikpICU+JSAgICMgSm9pbiBwb3BuIGFuZCBwb3ZlcnR5IGRhdGENCiAgbGVmdF9qb2luKHRydWVfcHJldiwgYnk9YygiY291bnR5IiwieWVhciIpKSAlPiUgICAjIEpvaW4gcHJldiBkYXRhDQogIGRwbHlyOjpzZWxlY3QoLWMocGFzdGUwKGRpc192YXJzMCkpKSAgICMjIyBSZW1vdmUgZGlzIHZhcnMgZXhjZXB0IHllYXINCnlyYnNzX2R1bW15IDwtIFhkYXRhX2R1bW15DQp5cmJzc19kdW1teSA8LSB5cmJzc19kdW1teVssIWNvbG5hbWVzKHlyYnNzX2R1bW15KSAlbGlrZSUgIl9OQSJdDQoNCiMgeXJic3NfZHVtbXkgPC0gZGF0YS5mcmFtZShsYXBwbHkoeXJic3NfZHVtbXksZnVuY3Rpb24oeCkoYXMubnVtZXJpYyh4KSkpKQ0KeXJic3NfZHVtbXkgPC0geXJic3NfZHVtbXlbb3JkZXIoeXJic3NfZHVtbXkkY291bnR5KSxdDQoNCnByaW50KCJDb21iaW5pbmcgWVJCU1MgZGF0YSB3aXRoIHBvdiByYXRlIGFuZCBjcmVhdGluZyBkdW1teSBjb2xzIGZvciBkaXMgdmFycyIpDQpoZWFkKHlyYnNzX2R1bW15KQ0KDQoNCg0KIyoqIHJlbW92ZSByb3dzIHRoYXQgaGFzIG5hIGZvciBsb2dpdCBwcm9iDQpuYV9yb3dzIDwtIHdoaWNoKGlzLm5hKHlyYnNzX2R1bW15JGxvZ2l0X3Byb2IpKQ0KaWYobGVuZ3RoKG5hX3Jvd3MpICE9IDApew0KICB5cmJzc19kdW1teSA8LSB5cmJzc19kdW1teVstbmFfcm93cywgXQ0KfWVsc2V7DQogIHlyYnNzX2R1bW15IDwtIHlyYnNzX2R1bW15DQp9DQpjb2xuYW1lcyh5cmJzc19kdW1teSkgPC0gZ3N1YigiXyIsIiIsY29sbmFtZXMoeXJic3NfZHVtbXkpKQ0KDQpoZWFkKHlyYnNzX2R1bW15KQ0KDQojKiogbWVyZ2Ugd2l0aCBkdW1teSBjb3VudHkgZGF0YQ0Ka2VlcF92YXJzIDwtIGNvbG5hbWVzKGNlbnN1c19TZXhBZ2VSYWNlX0RYKVshY29sbmFtZXMoY2Vuc3VzX1NleEFnZVJhY2VfRFgpICVpbiUgZGlzX3ZhcnNdICMgcmVtb3ZlIG9yaWdpbmFsIGRpcyB2YXJzDQprZWVwX3ZhcnMgPC0gYyhrZWVwX3ZhcnMsICJ5ZWFyIikNCkNlbnN1c19kdW1teSA8LSBjZW5zdXNfU2V4QWdlUmFjZV9EWFtjZW5zdXNfU2V4QWdlUmFjZV9EWCRjb3VudHklaW4lY29tX2NudHksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbmFtZXMoY2Vuc3VzX1NleEFnZVJhY2VfRFgpJWluJSBrZWVwX3ZhcnNdDQpoZWFkKENlbnN1c19kdW1teSkNCg0KDQoNCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAjDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgIENhbGN1bGF0ZSBlbnRyb2lkIG9mIGVhY2ggY291bnR5ICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogIw0KDQoNCiMjIyMgRXN0aW1hdGUgY2VudHJvaWQgb2YgZWFjaCBjb3VudHkgdXNpbmcgbG9uZyBhbmQgbGF0IGRhdGENCg0KbG9uZ19sYXRfY250eSA8LSBtYXBfZGF0YSgnY291bnR5JykNCmRhdGEoImNvdW50eS5maXBzIikNCg0KY250eV9maXBzMCA8LSB0c3Ryc3BsaXQoY291bnR5LmZpcHMkcG9seW5hbWUsIiwiLCBuYW1lcz1UUlVFKQ0KY250eV9maXBzIDwtIGRhdGEuZnJhbWUoY291bnR5PWNvdW50eS5maXBzJGZpcHMscmVnaW9uPWNudHlfZmlwczAkVjEsc3VicmVnaW9uPWNudHlfZmlwczAkVjIpDQpjbnR5X2ZpcHMkcmVnaW9uIDwtIGFzLmNoYXJhY3RlcihjbnR5X2ZpcHMkcmVnaW9uKQ0KY250eV9maXBzJHN1YnJlZ2lvbiA8LSBhcy5jaGFyYWN0ZXIoY250eV9maXBzJHN1YnJlZ2lvbikNCmxvbmdfbGF0X2RhdCA8LSBsb25nX2xhdF9jbnR5ICU+JSBsZWZ0X2pvaW4oY250eV9maXBzLGJ5PWMoInJlZ2lvbiIsInN1YnJlZ2lvbiIpKQ0KbG9uZ19sYXRfZGF0IDwtIGxvbmdfbGF0X2RhdCAlPiVkcGx5cjo6c2VsZWN0KGNvdW50eSxsb25nLGxhdCkNCg0KZGZfYnlfY250eSA8LSBzcGxpdChsb25nX2xhdF9kYXQsIGxvbmdfbGF0X2RhdCRjb3VudHkpICAgIyMgU3BsaXQgZGF0YSBmcmFtZSBieSBjb3VudHkNCmNudHlfY2VudHJkIDwtIGxpc3QoKSAgIyBDUkVBVEUgbGlzdCBvZiBEYXRhIGZyYW1lcw0KY2VudHJkX2J5X2NudHkgPC0gbGlzdCgpDQoNCiMjIyBMb25nIGFuZCBsYXQgZm9yIGFsIGNvdW50aWVzDQpmb3IgKGkgaW4gMTpsZW5ndGgoZGZfYnlfY250eSkpew0KICAjIGkgPC0gMQ0KICBjbnR5X2NlbnRyZFtbaV1dIDwtIGFzLmRhdGEuZnJhbWUoKGRmX2J5X2NudHlbaV0pLHJvdy5uYW1lcyA9IE5VTEwpDQogIGNvbG5hbWVzKGNudHlfY2VudHJkW1tpXV0pIDwtIGNvbG5hbWVzKGxvbmdfbGF0X2RhdCkNCiAgY2VudHJkX2J5X2NudHkwIDwtIGNlbnRyb2lkKGNudHlfY2VudHJkW1tpXV1bLDI6M10pDQogIGNlbnRyZF9ieV9jbnR5W1tpXV0gPC0gY2JpbmQuZGF0YS5mcmFtZShjb3VudHk9dW5pcXVlKGNudHlfY2VudHJkW1tpXV1bLDFdKSxjZW50cmRfYnlfY250eTApDQp9DQoNCmNudHlfY2VudHJkX2RmIDwtIHJiaW5kbGlzdChjZW50cmRfYnlfY250eSkgICNSZXF1aXJlcyBsaWJyYXJ5ICJkYXRhLnRhYmxlIg0KDQojIG91dF9scyA8LSBsaXN0KGNvbV9jbnR5LHlyYnNzX2R1bW15LHRydWVfcHJldjAseXJic3NfdW5pdCxYbWVhbl9zdWIsY250eV9wb3AsY250eV9jZW50cmRfZGYscGVyY190YmwscG9wX2RhdCx0cnVlX3ByZXYpDQpkYXRhX3ByZXAgPC0gbGlzdChkZl9zdWIsd3QsY29tX2NudHkseXJic3NfZHVtbXksQ2Vuc3VzX2R1bW15LGNudHlfY2VudHJkX2RmLHBvcF9kYXQsdHJ1ZV9wcmV2KQ0KDQoNCg0KIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE9idGFpbiBpbml0aWFsIFBhcmFtZXRlcnMgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAjDQpkYXRhX2FsbCA8LSBtZXJnZShkZl9zdWIscG92X3BvcCxieT1jKCJjb3VudHkiLCJ5ZWFyIikpDQpkYXRhX2FsbCA8LSBkYXRhX2FsbFt3aXRoKGRhdGFfYWxsLCBvcmRlcihjb3VudHksIHllYXIpKSwgIF0NCmhlYWQoZGF0YV9hbGwpDQoNCiMjIEZpbHRlciB2YXJpYWJsZXMgdG8gY3JlYXRlIGRlc2lnbiBtYXRyaXggZm9yIGRpcyB2YXJzDQojIERYXzAgPC0gZGF0YV9hbGxbLCBjKHJlc3AsY29udF92YXJzLGRpc192YXJzKV0NCkRYX291dCA8LSBkYXRhX2FsbFssIGMocmVzcCxjb250X3ZhcnMpXQ0KZm9yKGkgaW4gMTpsZW5ndGgoZGlzX3ZhcnMpKXsNCiAgIyBpIDwtIDENCiAgdmFyX3RlbXAgPC0gZGlzX3ZhcnNbaV0NCiAgRFhfdGVtcCA8LSBkYXRhX2FsbFssdmFyX3RlbXBdDQogIERYX3RlbXAgPC0gYXMuZmFjdG9yKERYX3RlbXApDQogIERYX291dCA8LSBjYmluZC5kYXRhLmZyYW1lKERYX291dCxEWF90ZW1wKQ0KfQ0KY29sbmFtZXMoRFhfb3V0KSA8LSBjKHJlc3AsY29udF92YXJzLGRpc192YXJzKQ0KDQpEWDExIDwtIG1vZGVsLm1hdHJpeChhcy5mb3JtdWxhKHBhc3RlMChyZXNwLCJ+LiIpKSwgZGF0YT1EWF9vdXQsDQogICAgICAgICAgICAgICAgICAgICBjb250cmFzdHMuYXJnID1saXN0KGFnZT1jb250cmFzdHMoRFhfb3V0JGFnZSwgY29udHJhc3RzID0gRiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhY2U0PWNvbnRyYXN0cyhEWF9vdXQkcmFjZTQsIGNvbnRyYXN0cyA9IEYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9Y29udHJhc3RzKERYX291dCRzZXgsIGNvbnRyYXN0cyA9IEYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyPWNvbnRyYXN0cyhEWF9vdXQkeWVhciwgY29udHJhc3RzID0gRikpKQ0KDQpEWDExIDwtIGNiaW5kLmRhdGEuZnJhbWUoY291bnR5PWRhdGFfYWxsJGNvdW50eSwNCiAgICAgICAgICAgICAgICAgICAgICAgICByZXNwPWRhdGFfYWxsWyAsIHBhc3RlMChyZXNwKV0sIERYMTEpDQpyZWZfZ3JwIDwtIGMoImFnZTEiLCJyYWNlNDQiLCJzZXgxIiwieWVhcjEiKSAgICAjIyMgUmVmIGdyb3VwDQpEWCA8LSBEWDExWyAsIWNvbG5hbWVzKERYMTEpJWluJXJlZl9ncnBdICAgICMjIyBSZW1vdmUgcmVmIGdyb3VwDQpYIDwtIERYWyAsMzpuY29sKERYKV0NClggPC0gWFsgLG9yZGVyKGNvbG5hbWVzKFgpKV0NCnkgPC0gRFhbICwicmVzcCJdDQoNCg0KIyoqKiBkZWZpbmUgcGFyYW1ldGVycyANCiMgeSA8LSBkYXRhX2FsbFtkYXRhX2FsbCRjb3VudHkgJWluJSBjbnR5MCwgXSAgICNwYXN0ZTAocmVzcCkNCm0gPC0gbGVuZ3RoKHVuaXF1ZShkYXRhX2FsbCRjb3VudHkpKQ0KTiA8LSBucm93KGRhdGFfYWxsKQ0KWiA8LSBtb2RlbC5tYXRyaXgofjArYXMuZmFjdG9yKERYMTEkY291bnR5KSkNCnAgPC0gbmNvbChYKQ0KWCA8LSBhcy5tYXRyaXgoWCkNCg0KY250eSA8LSB1bmlxdWUoZGF0YV9hbGwkY291bnR5KQ0KbGVuZ3RoKGNudHkpDQoNCg0KIyMgRml0IGxvZ2l0IG1vZGVsIHRvIGdldCBpbml0aWFsIGZpeGVkIGVmZmVjdHMgcGFyYW1ldGVycyANCm15X2Zvcm0gPC0gbXkuZm9ybShkaXNfdmFycyxjb250X3ZhcnMpDQpnbG1fZm9ybXVsYSA8LSBhcy5mb3JtdWxhKG15X2Zvcm0pDQpkYXRhX2FsbCRyYWNlNCA8LSBhcy5mYWN0b3IoZGF0YV9hbGwkcmFjZTQpDQpkYXRhX2FsbCRyYWNlNCA8LSByZWxldmVsKGRhdGFfYWxsJHJhY2U0LCByZWY9IjQiKSAgICMgcmFjZTQ0IGlzIHJlZiBncm91cA0KDQpnbG1fZml0IDwtIGdsbShmb3JtdWxhID0gZ2xtX2Zvcm11bGEsZmFtaWx5ID0gYmlub21pYWwobGluaz1sb2dpdCksZGF0YT1kYXRhX2FsbCkNCg0KdGhldGEwIDwtIDAuMQ0KdTAgPC0gYXMubWF0cml4KHJub3JtKG0sMCxzZD1zcXJ0KHRoZXRhMCkpKQ0KDQoNCnJlX25hbWVzIDwtIGMoKQ0KZm9yKGkgaW4gMTpsZW5ndGgoY250eSkpeyANCiAgcmVfbmFtZXMgPC0gYyhyZV9uYW1lcyxwYXN0ZTAoY250eVtpXSkpICANCn0NCnJlX25hbWVzIDwtIGFzLm51bWVyaWMocmVfbmFtZXMpDQpzdHIocmVfbmFtZXMpDQp1MCA8LSBkYXRhLmZyYW1lKGNvdW50eSA9IHJlX25hbWVzLGVzdD11MCkgDQoNCg0KIyMgYmV0YSB2YWx1ZXMgZm9yIGFsbCBwYXJhbWV0ZXJzIChpbmNsdWRpbmcgcmVmIGdyb3VwKQ0KYmV0YTAgPC0gZGF0YS5mcmFtZShzdW1tYXJ5KGdsbV9maXQpJGNvZWZmaWNpZW50c1ssMV0pDQpiZXRhMCA8LSBkYXRhLmZyYW1lKHBhcmFtZXRlcj1yb3duYW1lcyhiZXRhMCksZXN0PWJldGEwWywxXSkNCnJvd25hbWVzKGJldGEwKSA8LSBOVUxMDQoNCg0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT0qKioqKioqKioqKioqKioqKioqKioqKj09PT09PT09PT09PT09PT09PT09PT09PT09PSAjICANCmJldGEwX2NvbnQgPC0gYmV0YTBbIWJldGEwJHBhcmFtZXRlciAlbGlrZSUgImFzLmZhY3RvciIsXSAjIyBiZXRhIGZvciBDb250IHZhcnMNCmJldGEwX0ludCA8LSBiZXRhMF9jb250WyFiZXRhMF9jb250JHBhcmFtZXRlciAlaW4lIGNvbnRfdmFycywgXQ0KYmV0YTBfY29udCA8LSBiZXRhMF9jb250W2JldGEwX2NvbnQkcGFyYW1ldGVyICVpbiUgY29udF92YXJzLCBdDQpiZXRhMF9jb250JHBhcmFtZXRlciA8LSBnc3ViKCJfIiwiIixiZXRhMF9jb250JHBhcmFtZXRlcikNCmJldGEwX0ludCRwYXJhbWV0ZXIgPC0gZ3N1YigiXFwoSW50ZXJjZXB0XFwpIiwiSW50IixiZXRhMF9JbnQkcGFyYW1ldGVyKQ0KDQpiZXRhMF9kaXMgPC0gYmV0YTBbYmV0YTAkcGFyYW1ldGVyICVsaWtlJSAiYXMuZmFjdG9yIixdICAjIGJldGEgZm9yIGRpc2MgdmFycw0KYmV0YTBfZGlzJHBhcmFtZXRlciA8LSBnc3ViKCJhcy5mYWN0b3JcXCgiLCIiLGJldGEwX2RpcyRwYXJhbWV0ZXIpDQpiZXRhMF9kaXMkcGFyYW1ldGVyIDwtIGdzdWIoIlxcKSIsIl8iLGJldGEwX2RpcyRwYXJhbWV0ZXIpDQoNCg0KYmV0YTBfZGlzJGNvbCA8LSBnc3ViKCJfLioiLCIiLGJldGEwX2RpcyRwYXJhbWV0ZXIpDQp1bnEgPC0gdW5pcXVlKGJldGEwX2RpcyRjb2wpDQpiZXRhMF9kaXMkcGFyYW1ldGVyIDwtIGdzdWIoIl8iLCIiLGJldGEwX2RpcyRwYXJhbWV0ZXIpDQpiZXRhMF9kaXMkY29sIDwtIE5VTEwNCg0KDQpiZXRhMCA8LSByYmluZChiZXRhMF9jb250LGJldGEwX2RpcykNCmlmKCFpcy5jaGFyYWN0ZXIoYmV0YTAkcGFyYW1ldGVyKSl7YmV0YTAkcGFyYW1ldGVyIDwtIGFzLmNoYXJhY3RlcihiZXRhMCRwYXJhbWV0ZXIpfQ0KYmV0YTAgPC0gYmV0YTBbb3JkZXIoYmV0YTAkcGFyYW1ldGVyKSwgXQ0KYmV0YTAkZXN0IDwtIHJvdW5kKGFzLm51bWVyaWMoYmV0YTAkZXN0KSw1KQ0KYmV0YTAgPC0gcmJpbmQuZGF0YS5mcmFtZShiZXRhMF9JbnQsYmV0YTApDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSoqKioqKioqKioqKioqKioqKioqKioqKio9PT09PT09PT09PT09PT09PT09PT09PT09ICMNCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAjDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGdsbSBtb2RlbCBmaXQgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjDQojICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogIw0KDQpmaXQuaGdsbSA8LSBtYXRjaC5jYWxsKCk7IG5hbWVkTGlzdCA8LSBsaXN0KCkNCg0KWCA8LSBhcy5tYXRyaXgoWCkNCmJldGFfbmV3IDwtIGFzLm1hdHJpeChiZXRhMCRlc3QpDQp1X25ldyA8LSB1MCRlc3QNCnRoZXRhX25ldyA8LSB0aGV0YTANCg0KZGVsdGEgPC0gTlVMTA0KYmV0YV9uZXdfYWxsIDwtIGJldGFfbmV3IDt1X25ld19hbGwgPC0gdV9uZXc7IHRoZXRhX2FsbCA8LSB0aGV0YV9uZXcNCnRoZXRhX25ld19hbGwgPC0gYyh0aGV0YV9uZXcpOyBkZWx0YV9maW5hbCA8LSAwIDsgY29udl9pdGVyIDwtIDA7IGl0ZXIgPC0gMA0KY29sX25hbWVzIDwtIGMoKQ0KDQpkaW0oWCkNCmxlbmd0aChiZXRhX25ldykNCmxlbmd0aCh1X25ldykNCmRpbShaKQ0KbGVuZ3RoKHkpDQoNCg0KcmVwZWF0ew0KICANCiAgYmV0YSA8LSBhcy52ZWN0b3IoYmV0YV9uZXcpDQogIGJldGEgPC0gcm91bmQoYmV0YSwxMCkNCiAgIyBiZXRhIDwtIGJldGFfbmV3DQogIHUgPC0gYXMudmVjdG9yKHVfbmV3KQ0KICB0aGV0YSA8LSB0aGV0YV9uZXcNCiAgDQogIEJVX29sZCA8LSByYmluZChhcy5tYXRyaXgoYmV0YSksYXMubWF0cml4KHUpKQ0KICANCiAgdGhldGFfaW52IDwtIHNvbHZlKHRoZXRhKQ0KICBHX2ludiA8LSBrcm9uZWNrZXIodGhldGFfaW52LCBkaWFnKG0pKQ0KICANCiAgUCA8LSAxLygxK2V4cCgtKFglKiViZXRhK1olKiV1KSkpDQogIHBwIDwtIFAqKDEtUCkNCiAgVyA8LSBEaWFnb25hbCh4PXBwKQ0KICANCiAgRDJoX0JCIDwtIHQoWCklKiVXJSolWCAgICMgb3IgY3Jvc3Nwcm9kKHQoY3Jvc3Nwcm9kKFgsVykpLFgpDQogIEQyaF9CVSA8LSB0KFgpJSolVyUqJVoNCiAgRDJoX1VCIDwtIHQoWiklKiVXJSolWA0KICBEMmhfVVUgPC0gdChaKSUqJVclKiVaICsgR19pbnYNCiAgSiA8LSByYmluZChjYmluZChEMmhfQkIsRDJoX0JVKSxjYmluZChEMmhfVUIsRDJoX1VVKSkgICAjIChtK3ApIGJ5ICAocCttKSBKYWNvYmlhbg0KICBKIDwtIGFzLm1hdHJpeChKKQ0KICANCiAgIyBsaWJyYXJ5KGNvcnBjb3IpDQogICMgSl9pbnYgPC0gc29sdmUoSiwgdG9sPTEwXi0yMCkNCiAgSl9pbnYgPC0gcHNldWRvaW52ZXJzZShKKSAgIyBGb3Igbm9uLXNpbmd1bGFyIG1hdHJpY2VzIHRoZSBwc2V1ZG9pbnZlcnNlIGlzIGVxdWl2YWxlbnQgdG8gdGhlIHN0YW5kYXJkIGludmVyc2UuDQogIA0KICAjIEpfaW52IDwtIGZ1bmNfSmludihiZXRhLHVfbmV3LEdfaW52KQ0KICANCiAgIyB5cCA8LSB5IC0gUA0KICBEMWhfQiA8LSB0KFgpJSolKHktUCkNCiAgRDFoX3UgPC0gdChaKSUqJSh5LVApLSBHX2ludiUqJXUNCiAgDQogIFMgPC0gYXMudmVjdG9yKHJiaW5kKEQxaF9CLCBEMWhfdSkpICAgICMgR3JhZGllbnQgKHNjb3JlIGZ1bmN0aW9uKSB2ZWN0b3INCiAgDQogIEJVX25ldyA9IEJVX29sZCArIChKX2ludiUqJVMpICAgICMgTmV3dG9uIFJhcGhzb24gDQogIA0KICBiZXRhX25ldyA8LSBhcy52ZWN0b3IoQlVfbmV3WzE6bGVuZ3RoKGJldGEpXSkNCiAgdV9uZXcgPC0gYXMudmVjdG9yKEJVX25ld1sobGVuZ3RoKGJldGEpKzEpOmxlbmd0aChCVV9uZXcpXSkNCiAgDQogICMgY29udmVyZ2VuY2VfYmV0YSA8LSBhYnMoYmV0YV9uZXdbLTFdLWJldGFbLTFdKSAgDQogIGNvbnZlcmdlbmNlX2JldGEgPC0gYWJzKGJldGFfbmV3LWJldGEpDQogIGNvbnZlcmdlbmNlX3UgPC0gYWJzKHVfbmV3LXUpDQogIG1heChjb252ZXJnZW5jZV9iZXRhKQ0KICBtYXgoY29udmVyZ2VuY2VfdSkNCiAgDQogIGJldGFfbmV3X2FsbCA8LSBjYmluZC5kYXRhLmZyYW1lKGJldGFfbmV3X2FsbCx2YWx1ZT1yb3VuZChiZXRhX25ldyw2KSkNCiAgdV9uZXdfYWxsIDwtIGNiaW5kLmRhdGEuZnJhbWUodV9uZXdfYWxsLHZhbHVlPXJvdW5kKHVfbmV3LDYpKQ0KICANCiAgcm0oUCk7IHJtKFcpOyBybShKKTsNCiAgIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmlhcyBDb3JyZWN0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiAgIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiAgIyBCaWFzIENvcnIgc3RlcCAxOiB1cGRhdGUgSiB3aXRoIGVzdGltYXRlZCBiZXRhIGFuZCB1DQogIA0KICBQIDwtIDEvKDErZXhwKC0oWCUqJWJldGFfbmV3K1olKiV1X25ldykpKQ0KICBwcCA8LSBQKigxLVApDQogIFcgPC0gRGlhZ29uYWwoeD1wcCkNCiAgDQogIEQyaF9CQiA8LSB0KFgpJSolVyUqJVggICAjIG9yIGNyb3NzcHJvZCh0KGNyb3NzcHJvZChYLFcpKSxYKQ0KICBEMmhfQlUgPC0gdChYKSUqJVclKiVaDQogIEQyaF9VQiA8LSB0KFopJSolVyUqJVgNCiAgRDJoX1VVIDwtIHQoWiklKiVXJSolWiArIEdfaW52DQogIEogPC0gcmJpbmQoY2JpbmQoRDJoX0JCLEQyaF9CVSksY2JpbmQoRDJoX1VCLEQyaF9VVSkpICAgIyAobStwKSBieSAgKHArbSkgSmFjb2JpYW4NCiAgSiA8LSBhcy5tYXRyaXgoSikNCiAgDQogIEpoYXRfSW52IDwtIHBzZXVkb2ludmVyc2UoSikNCiAgVGF1IDwtIEpoYXRfSW52WyhwKzEpOihwK20pLChwKzEpOihwK20pXQ0KICBUYXV0IDwtIGRpYWcoVGF1KQ0KICB6ZXRhIDwtIHRoZXRhLyh0aGV0YStUYXV0KQ0KICBjb3JyX3UgPC0gemV0YSp1X25ldyAgICAgIyBDb3JyZWN0ZWQgdV9uZXcNCiAgDQogIHJtKFApOyBybShXKTsgcm0oSik7DQogIA0KIA0KICANCiAgaXRlciA8LSBpdGVyICsgMQ0KICAjIyMjIyMjIyMjIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0jIyMjIyMjIyMjIyMjICAgICAgDQogICMjIyMjIyMjIyMjICAgICAgICAgICAgIEVzdGltYXRlIHRoZXRhPXNpZ21hXjIgdXNpbmcgRGgvRHRoZXRhPTAgICAgICMjIyMjIyMjIyMjIyMNCiAgIyMjIyMjIyMjIyMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIyMjIyMjIyMjIyMjIw0KICANCiAgDQogICMjIFVzaW5nIFNBRTYgdG8gZXN0aW1hdGUgdGhldGENCiAgdGhldGFfaW52IDwtIHNvbHZlKHRoZXRhKQ0KICBHX2ludiA8LSBrcm9uZWNrZXIodGhldGFfaW52LCBkaWFnKG0pKQ0KICANCiAgUCA8LSAxLygxK2V4cCgtKFglKiViZXRhX25ldytaJSolY29ycl91KSkpDQogICMgVyA8LSBkaWFnKGFzLnZlY3RvcihQKigxLVApKSkNCiAgVyA8LSBEaWFnb25hbCh4PWFzLnZlY3RvcihQKigxLVApKSkNCiAgDQogIEQyaF9CQiA8LSB0KFgpJSolVyUqJVggICAjIG9yIGNyb3NzcHJvZCh0KGNyb3NzcHJvZChYLFcpKSxYKQ0KICBEMmhfQlUgPC0gdChYKSUqJVclKiVaDQogIEQyaF9VQiA8LSB0KFopJSolVyUqJVgNCiAgRDJoX1VVIDwtIHQoWiklKiVXJSolWiArIEdfaW52DQogIEogPC0gcmJpbmQoY2JpbmQoRDJoX0JCLEQyaF9CVSksY2JpbmQoRDJoX1VCLEQyaF9VVSkpICAgIyAoMTQzKzkpIGJ5ICAoOSsxNDMpIEphY29iaWFuDQogIEogPC0gYXMubWF0cml4KEopDQogIEpfaW52IDwtIHBzZXVkb2ludmVyc2UoSikNCiAgDQogICMgSl9pbnYgPC0gZnVuY19KaW52KGJldGE9YmV0YV9uZXcsdV9uZXcsR19pbnYpDQogIA0KICBkaW0oSl9pbnYpDQogIA0KICAjIyNFc3RpbWF0ZSB0aGV0YSANCiAgSl9pbnYyMiA8LSBKX2ludlsocCsxKToocCttKSwocCsxKToocCttKV0NCiAgdGhldGFfbmV3IDwtIDEvbSoodCh1X25ldyklKiV1X25ldykrMS9tKmZ1bmNfdHJhY2UoSl9pbnYyMikNCiAgdGhldGFfbmV3X2FsbCA8LSBjYmluZC5kYXRhLmZyYW1lKHRoZXRhX25ld19hbGwsdmFsdWU9dGhldGFfbmV3KQ0KICANCiANCiAgICANCiAgIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysgIw0KICAjICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyAjDQogICMgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiAgDQogICMjIyBUbyBnZXQgdGhlIHZhcmlhbmNlIG9mIHUgYmFzZWQgb24gSiANCiAgdGhldGFfaW52IDwtIHNvbHZlKHRoZXRhX25ldykNCiAgR19pbnYgPC0ga3JvbmVja2VyKHRoZXRhX2ludiwgZGlhZyhtKSkNCiAgDQogIFAgPC0gMS8oMStleHAoLShYJSolYmV0YV9uZXcrWiUqJXVfbmV3KSkpICAgIA0KICBXIDwtIERpYWdvbmFsKHg9YXMudmVjdG9yKFAqKDEtUCkpKQ0KICANCiAgRDJoX0JCIDwtIHQoWCklKiVXJSolWCAgICMgb3IgY3Jvc3Nwcm9kKHQoY3Jvc3Nwcm9kKFgsVykpLFgpDQogIEQyaF9CVSA8LSB0KFgpJSolVyUqJVoNCiAgRDJoX1VCIDwtIHQoWiklKiVXJSolWA0KICBEMmhfVVUgPC0gdChaKSUqJVclKiVaICsgR19pbnYNCiAgSiA8LSByYmluZChjYmluZChEMmhfQkIsRDJoX0JVKSxjYmluZChEMmhfVUIsRDJoX1VVKSkgICAjICgxNDMrOSkgYnkgICg5KzE0MykgSmFjb2JpYW4NCiAgSiA8LSBhcy5tYXRyaXgoSikNCiAgSl9pbnYgPC0gcHNldWRvaW52ZXJzZShKKQ0KICANCiAgIyBKX2ludiA8LSBmdW5jX0ppbnYoYmV0YT1iZXRhX25ldyx1X25ldyxHX2ludikNCiAgDQogIGZlLmNvdiA8LSBKX2ludlsxOnAsMTpwXSAgICAgICAjIyBWYXIgQ292IG1hdHJpeCBvZiBmaXhlZCBlZmZlY3RzDQogIHJlLmNvdiAgPC0gSl9pbnZbKHArMSk6KHArbSksKHArMSk6KHArbSldICAgICMjIFZhciBDb3YgbWF0cml4IG9mIHJhbmRvbSBlZmZlY3RzDQogIA0KICBmZS52YXIgPC0gZGlhZyhmZS5jb3YpICAgICMjIyBWYXIgb2YgZml4ZWQgZWZmZWN0cw0KICBmZS52YXIgPC0gcm91bmQoZmUudmFyLDEwKQ0KICBmZS52YXIgPC0gZmUudmFyW2ZlLnZhciAhPSAwXSAgIyMgUmVtb3ZlIGNvZWZzIG9mIHJlZiBncm91cCh3aGljaCBoYXMgdmVyeSBzbWFsbCB2YWx1ZXMpDQogIGZlLnN0ZC5lcnIgPC0gcm91bmQoc3FydChmZS52YXIpLCA1KQ0KICANCiAgIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysgIw0KICAjICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyAjDQogICMgKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMNCiAgDQogIGNvbnZlcmdlbmNlX3RoZXRhIDwtIGFicyh0aGV0YV9uZXctdGhldGEpDQogIGRlbHRhIDwtIG1heChjb252ZXJnZW5jZV9iZXRhLGNvbnZlcmdlbmNlX3RoZXRhKQ0KICBkZWx0YV9maW5hbCA8LSBjYmluZC5kYXRhLmZyYW1lKGRlbHRhX2ZpbmFsLHZhbHVlPWRlbHRhKQ0KICANCiAgY29sX25hbWVzIDwtIGMoY29sX25hbWVzLHBhc3RlMCgiaXRlciIsaXRlcikpDQogIA0KICANCiAgY2F0KHBhc3RlMCgiZGVsdGE6ICIsZGVsdGEsIlxuIFxuIikpDQogIA0KICBpZihkZWx0YSA8PSAxZS0xMCl7YnJlYWt9DQogIA0KfQ0KDQoNCmNvbG5hbWVzKHRoZXRhX25ld19hbGwpIDwtIGNvbF9uYW1lcw0KY29sbmFtZXMoYmV0YV9uZXdfYWxsKSA8LSBjb2xfbmFtZXMNCnJvd25hbWVzKGJldGFfbmV3X2FsbCkgPC0gYmV0YTAkcGFyYW1ldGVyDQpjb2xuYW1lcyh1X25ld19hbGwpIDwtIGNvbF9uYW1lcw0Kcm93bmFtZXModV9uZXdfYWxsKSA8LSB1MCRjb3VudHkNCg0KY2F0KHBhc3RlMCgiQ29udmVyZ2VkIGluICIsaXRlciwiIGl0ZXJhdGlvbnMgd2l0aCB0b2wgPSAiLGRlbHRhLCIuIFxuIFxuIikpDQoNCg0KIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR2V0IG1vZGVsIGVzdGltYXRlcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogIw0KDQplc3QuYmV0YSA8LSBiZXRhX25ld19hbGxbLG5jb2woYmV0YV9uZXdfYWxsKV0NCmVzdC50aGV0YSA8LSB0aGV0YV9uZXdfYWxsWyxuY29sKHRoZXRhX25ld19hbGwpXQ0KZXN0LnJlIDwtIGRhdGEuZnJhbWUoY291bnR5PXJvd25hbWVzKHVfbmV3X2FsbCksDQogICAgICAgICAgICAgICAgICAgICBlc3Q9dV9uZXdfYWxsWyxuY29sKHVfbmV3X2FsbCldKQ0KYmV0YV9oYXQgPC0gcm91bmQoYmV0YV9uZXdfYWxsWyxuY29sKGJldGFfbmV3X2FsbCldLDUpDQpiZXRhX2hhdCA8LSBiZXRhX2hhdFtiZXRhX2hhdCE9MF0NCnoxIDwtIGJldGFfaGF0L2ZlLnN0ZC5lcnINCg0KZXN0LmZlIDwtIGRhdGEuZnJhbWUoZXN0PWJldGFfaGF0LA0KICAgICAgICAgICAgICAgICAgICAgc3RkLmVycj1mZS5zdGQuZXJyLA0KICAgICAgICAgICAgICAgICAgICAgWjAgPSByb3VuZCh6MSw1KSwNCiAgICAgICAgICAgICAgICAgICAgIFAgPSByb3VuZCgyKnBub3JtKC1hYnMoejEpKSw1KSkNCg0Kcm93bmFtZXMoZXN0LmZlKSA8LSByb3duYW1lcyhiZXRhX25ld19hbGwpW3JvdW5kKGJldGFfbmV3X2FsbFssbmNvbChiZXRhX25ld19hbGwpXSw1KSAhPTBdICAgICMgcm93bmFtZXMoYmV0YV9uZXdfYWxsKQ0KDQoNCmNvbG5hbWVzKGVzdC5mZSkgPC0gYygiRXN0aW1hdGUiLCJTdGQuRXJyb3IiLCJaIFZhbHVlIiwiUCg+fFp8KSIpDQoNCmVzdC5iZXRhIDwtIHJvdW5kKGVzdC5iZXRhLDUpDQplc3QuYmV0YSA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlPXJvd25hbWVzKGJldGFfbmV3X2FsbCksRXN0aW1hdGU9ZXN0LmJldGEpDQoNCmZpdC5oZ2xtJGl0ZXIgPC0gaXRlcg0KZml0LmhnbG0kZXN0LmJldGEgPC0gZXN0LmZlDQpmaXQuaGdsbSRyZSA8LSBlc3QucmUNCmZpdC5oZ2xtJHZhci5wYXIgPC0gZXN0LnRoZXRhDQpmaXQuaGdsbSRmZS5jb3YgPC0gZmUuY292DQpmaXQuaGdsbSRyZS5jb3YgPC0gcmUuY292DQoNCmNvbG5hbWVzKGZlLmNvdikgPC0gcm93bmFtZXMoYmV0YV9uZXdfYWxsKQ0Kcm93bmFtZXMoZmUuY292KSA8LSByb3duYW1lcyhiZXRhX25ld19hbGwpDQoNCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICMgDQojICoqKioqKioqKioqKioqKioqKioqKioqKioqKiogICAgICBtb2RlbCBlc3RpbWF0ZXMgICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAjDQojICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiAjDQojICoqKioqKioqKioqKioqKioqKioqKioqKioqKiogICAgICBDYWxjdWxhdGUgQUlDLCBCSUMgICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICMNCmVzdC5iZXRhIDwtIGFzLnZlY3Rvcihlc3QuYmV0YSRFc3RpbWF0ZSkNCg0KUCA8LSAxLygxK2V4cCgtKFglKiVlc3QuYmV0YStaJSolKGVzdC5yZSRlc3QpKSkpDQp5dCA8LSAxLXkNCmxvZ2xpa2VsIDwtIHkqbG9nKFApICt5dCpsb2coMS1QKQ0Kc3VtbG9nbGlrIDwtIHN1bShsb2dsaWtlbCkNCg0KQUlDIDwtIC0yKnN1bShsb2dsaWtlbCkgKyAyKihsZW5ndGgoZXN0LmJldGEpKzEpDQpCSUMgPC0gLTIqc3VtKGxvZ2xpa2VsKSArIChsZW5ndGgoZXN0LmJldGEpKzEpKmxvZyhOKQ0KbW9kZWwuc2VsIDwtIGNiaW5kLmRhdGEuZnJhbWUoQUlDLCBCSUMsTG9nTGlrPXN1bWxvZ2xpaykNCg0KIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqICAgICAgQ2FsY3VsYXRlIEFJQyAgICAgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogIw0KbmFtZWRMaXN0IDwtIGxpc3QoYGhnbG0gbW9kZWwgaW5mZXJlbmNlYD0gbW9kZWwuc2VsLCBpdGVyPWl0ZXIsYGZpeGVkIGVmZmVjdHMgZXN0aW1hdGVzYD1lc3QuZmUsDQogICAgICAgICAgICAgICAgICBgIGA9cGFzdGUwKCJDb252ZXJnZWQgaW4gIixpdGVyLCIgaXRlcmF0aW9ucyB3aXRoIHRvbCA9ICIsZGVsdGEsIi4iKQ0KKQ0KY2xhc3MobmFtZWRMaXN0KSA8LSAic3VtbWFyeS5oZ2xtLmZpdCINCg0KZml0LmhnbG0kc3VtbWFyeS5oZ2xtIDwtIG5hbWVkTGlzdA0KDQppZihzYXZlLm91dD09IllFUyIpew0KICBpZihsZW5ndGgob3V0LnBhdGgpPT0wKXsNCiAgICBzdG9wKCJvdXRwdXQgcGF0aCBpcyBub3QgZGVmaW5lZCAhISIpDQogIH1lbHNlIGlmKGxlbmd0aChvdXQucGF0aCkhPTApew0KICAgIHdyaXRlLmNzdih0aGV0YV9uZXdfYWxsLCBwYXN0ZTAob3V0LnBhdGgsbW9kZWwudHlwZSwiLyIsbW9kZWwudHlwZSwiX3RoZXRhX2FsbC5jc3YiKSxyb3cubmFtZXMgPSBUKQ0KICAgIHdyaXRlLmNzdihiZXRhX25ld19hbGwsIHBhc3RlMChvdXQucGF0aCxtb2RlbC50eXBlLCIvIixtb2RlbC50eXBlLCJfYmV0YV9uZXdfYWxsLmNzdiIpLCByb3cubmFtZXMgPSBUKQ0KICAgIHdyaXRlLmNzdih1X25ld19hbGwsIHBhc3RlMChvdXQucGF0aCxtb2RlbC50eXBlLCIvIixtb2RlbC50eXBlLCJfdV9uZXdfYWxsLmNzdiIpLCByb3cubmFtZXMgPSBUKQ0KDQogICAgd3JpdGUuY3N2KGVzdC50aGV0YSwgcGFzdGUwKG91dC5wYXRoLG1vZGVsLnR5cGUsIi8iLG1vZGVsLnR5cGUsIl90aGV0YV9lc3QuY3N2Iikscm93Lm5hbWVzID0gRikNCiAgICB3cml0ZS5jc3YoZXN0LmZlLCBwYXN0ZTAob3V0LnBhdGgsbW9kZWwudHlwZSwiLyIsbW9kZWwudHlwZSwiX2ZlX2VzdC5jc3YiKSwgcm93Lm5hbWVzID0gVCkNCiAgICB3cml0ZS5jc3YoZXN0LnJlLCBwYXN0ZTAob3V0LnBhdGgsbW9kZWwudHlwZSwiLyIsbW9kZWwudHlwZSwiX3JlX2VzdC5jc3YiKSwgcm93Lm5hbWVzID0gRikNCiAgICB3cml0ZS5jc3YoZmUuY292LCBwYXN0ZTAob3V0LnBhdGgsbW9kZWwudHlwZSwiLyIsbW9kZWwudHlwZSwiX2ZlX1ZhckNvdl9lc3QuY3N2IiksIHJvdy5uYW1lcyA9IFQpDQogICAgd3JpdGUuY3N2KHJlLmNvdiwgcGFzdGUwKG91dC5wYXRoLG1vZGVsLnR5cGUsIi8iLG1vZGVsLnR5cGUsIl9yZV9WYXJDb3ZfZXN0LmNzdiIpLCByb3cubmFtZXMgPSBUKQ0KDQogICAgIyBzYXZlKHBhc3RlMChvdXQucGF0aCwiZml0LmhnbG0uUkRhdGEiKSkNCiAgfQ0KICBwcmludChwYXN0ZTAoImhnbG0gbW9kZWwgZml0IG91dHB1dCBpcyBzYXZlZCBpbiAiLG91dC5wYXRoKSkNCn0NCg0KDQoNCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTW9kZWwgcHJlZGljdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMNCiMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICMNCg0KcHJlZC5vdXQgPC0gbWF0Y2guY2FsbCgpDQoNCkRYMSA8LSBkYXRhLmZyYW1lKEludD1yZXAoMSxucm93KERYMCkpKQ0KZm9yKGkgaW4gMTpsZW5ndGgoZGlzX3ZhcnMpKXsNCiAgIyBpIDwtIDENCiAgdGVtcCA8LSBwYXN0ZTAoZGlzX3ZhcnNbaV0sIisiKQ0KICB0ZW1wX210eCA8LSBtb2RlbC5tYXRyaXgoYXMuZm9ybXVsYShwYXN0ZTAoIn4iLHRlbXAsIjAiKSksRFgwKQ0KICBEWDEgPC0gY2JpbmQuZGF0YS5mcmFtZShEWDEsIHRlbXBfbXR4KQ0KfQ0KDQoNCmlmKHJlc3A9PSJlY2lnX2V2ZXIiKXsNCiAgdGl0X3kgPC0gIkV2ZXIiDQp9ZWxzZSBpZihyZXNwPT0iZWNpZ19jdXJyZW50Iil7DQogIHRpdF95IDwtICJDdXJyZW50Ig0KfWVsc2UgaWYocmVzcD09InNtb2tlX2V2ZXIiKXsNCiAgdGl0X3kgPC0gIkV2ZXIiDQp9ZWxzZSBpZihyZXNwPT0ic21va2VfY3VycmVudCIpew0KICB0aXRfeSA8LSAiQ3VycmVudCINCn0NCg0Kb3V0X3BhdGggPC0gcGFzdGUwKGRpcl9wYXRoLCIvb3V0LyIscmVzcCwiLyIsbW9kZWwudHlwZSkNCg0KaWYoc2F2ZS5vdXQ9PSJZRVMiKXsNCiAgaWYobGVuZ3RoKG91dC5wYXRoKT09MCl7DQogICAgc3RvcCgiT3V0cHV0IHBhdGggaXMgbm90IGRlZmluZWQgISEiKQ0KICB9ZWxzZSBpZihsZW5ndGgob3V0LnBhdGghPTApKXsNCiAgICBiZXRhX2VzdCA8LSBkYXRhLmZyYW1lKHJlYWQuY3N2KHBhc3RlMChvdXQucGF0aCxtb2RlbC50eXBlLCIvIixtb2RlbC50eXBlLCJfZmVfZXN0LmNzdiIpKSkNCiAgICB0aGV0YV9lc3QgPC0gZGF0YS5mcmFtZShyZWFkLmNzdihwYXN0ZTAob3V0LnBhdGgsbW9kZWwudHlwZSwiLyIsbW9kZWwudHlwZSwiX3RoZXRhX2VzdC5jc3YiKSkpDQogICAgdV9lc3QgPC0gZGF0YS5mcmFtZShyZWFkLmNzdihwYXN0ZTAob3V0LnBhdGgsbW9kZWwudHlwZSwiLyIsbW9kZWwudHlwZSwiX3JlX2VzdC5jc3YiKSkpDQogIH0NCn1lbHNlew0KICBiZXRhX2VzdCA8LSBmaXQuaGdsbSRmZQ0KICB1X2VzdCA8LSBmaXQuaGdsbSRyZQ0KICB0aGV0YV9lc3QgPC0gZml0LmhnbG0kdmFyLnBhcg0KfQ0KDQoNCiMjIENlbnRlciBvZiBlYWNoIGNvdW50eQ0KY250eV9jZW50cmRfZGYgPC0gZGF0YS5mcmFtZShjbnR5X2NlbnRyZF9kZikNCg0KIyMjIFJhbmRvbSBlZmZlY3RzIGF2YWlsYWJsZSBmb3IgdGhlc2UgY291bnRpZXMNCiMgZXN0X3JhbmRfZWZmX2NudHkgPC0gY250eV9jZW50cmRfZGZbY250eV9jZW50cmRfZGYkY291bnR5ICVpbiUgY29tX2NudHksXSAgICANCk5vX3JhbmRfZWZmZWN0X2NudHkgPC0gY250eV9jZW50cmRfZGZbIWNudHlfY2VudHJkX2RmJGNvdW50eSAlaW4lIHVfZXN0JGNvdW50eSxdDQplc3RfcmFuZG9tX2VmZmVjdCA8LSB1X2VzdA0KY29sbmFtZXMoZXN0X3JhbmRvbV9lZmZlY3QpIDwtIGMoImNvdW50eSIsInJhbmRfZWZmIikNCg0KIyBlc3RfcmFuZG9tX2VmZmVjdCRjb3VudHkgPC0gc3Vic3RyaW5nKGVzdF9yYW5kb21fZWZmZWN0JGNvdW50eSwyLG5jaGFyKGVzdF9yYW5kb21fZWZmZWN0JGNvdW50eSkpDQojIGVzdF9yYW5kb21fZWZmZWN0JGNvdW50eSA8LSBhcy5pbnRlZ2VyKGVzdF9yYW5kb21fZWZmZWN0JGNvdW50eSkNCiMgZXN0X3JhbmRvbV9lZmZlY3QkcmFuZF9lZmYgPC0gYXMubnVtZXJpYyhlc3RfcmFuZG9tX2VmZmVjdCRyYW5kX2VmZikNCiMgZXN0X3JhbmRvbV9lZmZlY3QgPC0gZXN0X3JhbmRvbV9lZmZlY3RbZXN0X3JhbmRvbV9lZmZlY3QkY291bnR5ICVpbiUgZXN0X3JhbmRfZWZmX2NudHkkY291bnR5LCBdDQoNCmlmKGRhdGFfY2hhbmdlPT0iWUVTIil7DQogIHByZWRfYWRqX2NudHlfZGYgPC0gcHJlZF9hZGpjX2NudHkoZGYxPWVzdF9yYW5kX2VmZl9jbnR5LGRmMj1Ob19yYW5kX2VmZmVjdF9jbnR5KQ0KICB3cml0ZS5jc3YocHJlZF9hZGpfY250eV9kZixwYXN0ZTAoZGlyX3BhdGgsIi9vdXQvIixyZXNwLCIvIixtb2RlbC50eXBlLCIvcHJlZF9hZGpfY250eV9kZi5jc3YiKSxyb3cubmFtZXMgPSBGKQ0KfWVsc2UgaWYoZGF0YV9jaGFuZ2U9PSJOTyIpew0KICAjICMjIHJlYWQgYWRqYWNlbnQgY291bnR5IGluZm9ybWF0aW9uIA0KICBwcmVkX2Fkal9jbnR5X2RmIDwtIHJlYWQuY3N2KHBhc3RlMChkaXJfcGF0aCwiL291dC8iLHJlc3AsIi8iLG1vZGVsLnR5cGUsIi9wcmVkX2Fkal9jbnR5X2RmLmNzdiIpKQ0KfQ0KDQpkaW0ocHJlZF9hZGpfY250eV9kZikNCg0KDQojIyBMZWZ0IGpvaW4gd2l0aCBwcmVkaWN0ZWQgYWRqY2VudCBjb3VudHkgDQpwcmVkX2Fkal9jbnR5X2ZpbmFsIDwtIHByZWRfYWRqX2NudHlfZGYgJT4lIA0KICBsZWZ0X2pvaW4oZXN0X3JhbmRvbV9lZmZlY3QsIGJ5PWMoInByZWRfYWRqX2NudHkiPSJjb3VudHkiKSkgDQoNCiMjIEFsbCByYW5kb20gZWZmZWN0cyAoY29tYmluZSBwcmVkaWN0ZWQgYW5kIGVzdGltYXRlZCByYW5kb20gZWZmZWN0cykNCmFsbF9yYW5kb21fZWZmZWN0IDwtIHJiaW5kKGRhdGEuZnJhbWUoY291bnR5PXByZWRfYWRqX2NudHlfZmluYWwkY291bnR5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYW5kX2VmZj1wcmVkX2Fkal9jbnR5X2ZpbmFsJHJhbmRfZWZmKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVzdF9yYW5kb21fZWZmZWN0KQ0KYWxsX3JhbmRvbV9lZmZlY3QgPC0gYWxsX3JhbmRvbV9lZmZlY3Rbb3JkZXIoYWxsX3JhbmRvbV9lZmZlY3QkY291bnR5KSwgXQ0KDQpkaW0oYWxsX3JhbmRvbV9lZmZlY3QpDQpoZWFkKGFsbF9yYW5kb21fZWZmZWN0KSAgIyMgaW5jdWRpbmcgZXN0aW1hdGVzIHJhbmRvbSBlZmZldHMNCg0KDQojICQkICQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQNCmlmKCJGSVBTIiAlaW4lIGNvbG5hbWVzKGRmKSl7DQogIGNvbG5hbWVzKGRmKSA8LSAiY291bnR5Ig0KfWVsc2V7DQogIGNvbG5hbWVzKGRmKSA8LSBjb2xuYW1lcyhkZikNCn0NCg0KZGZfc3ViIDwtIGRhdGEuZnJhbWUoZGZbLCBjb2xuYW1lcyhkZikgJWluJSBjKGRpc192YXJzKV0pDQpkZl9zdWIgPC0gZGZfc3ViW2NvbXBsZXRlLmNhc2VzKGRmX3N1YiksIF0NCg0KIyMjIENyZWF0ZSBhZ2UgZ3JvdXBpbmcNCmRmX3N1YiRhZ2UgPC0gaWZlbHNlKGRmX3N1YiRhZ2UgJWluJSBjKDE6bjEpLCIxIiwNCiAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShkZl9zdWIkYWdlICVpbiUgYygobjErMSk6bjIpLCAiMiIsIjMiKSkNCg0KdGFibGUoZGZfc3ViJGFnZSkNCiMgJCQgJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJA0KDQoNCiMjIyBSZWcgY29lZmZpY2llbnRzIGZyb20gaGdsbSBtb2RlbA0KaWYoIWlzLmNoYXJhY3RlcihiZXRhX2VzdFssMV0pKXsNCiAgYmV0YV9lc3RbLDFdIDwtIGFzLmNoYXJhY3RlcihiZXRhX2VzdFssMV0pDQp9DQpjb250X3ZhcnMwIDwtIGdzdWIoIl8iLCIiLGNvbnRfdmFycykNCmJldGFfZGlzYyA8LSBiZXRhX2VzdFshYmV0YV9lc3RbLDFdICVpbiUgYyhjb250X3ZhcnMwKSxdDQoNCmlmKGxlbmd0aChiZXRhX2Rpc2NbLDFdWyFiZXRhX2Rpc2NbLDFdICVpbiUgbmFtZXMoRFgxKV0pPT0wKXsNCiAgZXN0X2JldGEwIDwtIHJiaW5kLmRhdGEuZnJhbWUoYmV0YV9kaXNjWyAsMToyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYmluZChYPXJlZl9ncnAsRXN0aW1hdGU9cmVwKDAsbGVuZ3RoKHJlZl9ncnApKSkpDQogIGVzdF9iZXRhMSA8LSBlc3RfYmV0YTBbMjpucm93KGVzdF9iZXRhMCksIF0NCiAgZXN0X2JldGEyIDwtIGVzdF9iZXRhMFsxLCBdDQogIGVzdF9iZXRhMSA8LSBlc3RfYmV0YTFbb3JkZXIoZXN0X2JldGExJFgpLCBdDQogIGVzdEJldGEgPC0gcmJpbmQuZGF0YS5mcmFtZShlc3RfYmV0YTIsZXN0X2JldGExKQ0KICBlc3RCZXRhJEVzdGltYXRlIDwtIGFzLm51bWVyaWMoZXN0QmV0YSRFc3RpbWF0ZSkNCiAgZXN0X2JldGEgPC0gYXMubWF0cml4KGVzdEJldGEkRXN0aW1hdGUpDQogIERYIDwtIGFzLm1hdHJpeChEWDEpDQp9ZWxzZXsNCiAgc3RvcCgiQ2hlY2sgZm9yIHRoZSBkaW1lbnNpb24gb2YgZml4ZWQgZWZmZWN0cyBhbmQgZGVzaWduIG1hdHJpeCAhIikNCn0NCg0KWF9iZXRhMCA8LSBEWCAlKiUgZXN0X2JldGENClhfYmV0YSA8LSBYX2JldGEwDQoNCnBvdmVydHlfcG9wIDwtIG1lcmdlKHBvdl9wb3AsYWxsX3JhbmRvbV9lZmZlY3QsIGJ5PSJjb3VudHkiKQ0KaW5fY250eSA8LSBlc3RfcmFuZG9tX2VmZmVjdCRjb3VudHkNCg0KDQojIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMjDQojIyAtLS0tLS0tLS0tIHByZWRpY3QgcHJldiBmb3IgbWlzc2luZyBjb3VudGllcyBmb3IgZWFjaCBjb21iaW5hdGlvbiBvZiBkaXMgdmFycyAtIFNUQVJUIC0tLS0tLS0tLS0tLS0tICMjDQojIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMjDQoNCiMjIGNvdW50aWVzIGxvbmcgYW5kIGxhdCBhdmFpbGFibGUgYnV0IG5vIHByZXZhbGVuY2UgZGF0YQ0Kb290X2NudHkgPC0gYWxsX3JhbmRvbV9lZmZlY3QkY291bnR5WyFhbGxfcmFuZG9tX2VmZmVjdCRjb3VudHklaW4laW5fY250eV0NCnJhbmRvbV9lZmZlY3Rfb290IDwtIGFsbF9yYW5kb21fZWZmZWN0W2FsbF9yYW5kb21fZWZmZWN0JGNvdW50eSVpbiVvb3RfY250eSwgXQ0KcG92ZXJ0eV9vb3QgPC0gcG92ZXJ0eV9wb3BbcG92ZXJ0eV9wb3AkY291bnR5JWluJW9vdF9jbnR5LF0NCnBvdmVydHlfb290IDwtIHBvdmVydHlfb290W29yZGVyKHBvdmVydHlfb290JGNvdW50eSksIF0NCnJhbmRvbV9lZmZlY3Rfb290IDwtIHJhbmRvbV9lZmZlY3Rfb290W29yZGVyKHJhbmRvbV9lZmZlY3Rfb290JGNvdW50eSksIF0NCg0KDQoNCiMjIyBwcmVkaWN0IGNvdW50eSBsZXZlbCBwcmV2YWxlbmNlIHVzaW5nIGVxbiAoMykgZm9yIGFsbCBjb3VudGllcw0KIyBiZXRhIGZvciBjb250IHZhcnMNCmJldGFfY29udCA8LSBiZXRhX2VzdFtiZXRhX2VzdFssMV0gJWluJSBjb250X3ZhcnMwLF0gDQppZihpcy5mYWN0b3IoYmV0YV9jb250JFgpKXsNCiAgYmV0YV9jb250JFggPC0gYXMuY2hhcmFjdGVyKGJldGFfY29udCRYKSAgDQp9DQoNCmJldGFfY29udF92YXIgPC0gYmV0YV9jb250WywiRXN0aW1hdGUiXSAjIGNvZWZzIGZvciBjb250IHZhcnMNCg0KDQpjbnR5X3ByZWQgPC0gbGlzdCgpOyBjbnR5X3ByZWRfYWxsPC1saXN0KCkNCmZvcihqIGluIDE6bGVuZ3RoKHVuaXF1ZShwb3ZlcnR5X3BvcCR5ZWFyKSkpew0KICAjIGogPC0gMg0KICB5ciA8LSB1bmlxdWUocG92ZXJ0eV9wb3AkeWVhcilbal0NCiAgcG92X3JhdGVfdmFsIDwtIHBvdmVydHlfcG9wW3BvdmVydHlfcG9wJHllYXI9PXlyLF0NCiAgcG92X3JhdGVfdmFsIDwtIHBvdl9yYXRlX3ZhbFtvcmRlcihwb3ZfcmF0ZV92YWwkY291bnR5KSwgXQ0KICBvb3RfY29tX2NudCA8LSBpbnRlcnNlY3QocG92X3JhdGVfdmFsJGNvdW50eSxhbGxfcmFuZG9tX2VmZmVjdCRjb3VudHkpDQogIHJlX3RlbXAgPC0gYWxsX3JhbmRvbV9lZmZlY3RbYWxsX3JhbmRvbV9lZmZlY3QkY291bnR5JWluJW9vdF9jb21fY250LCBdDQogIHJlX3RlbXAgPC0gcmVfdGVtcFtvcmRlcihyZV90ZW1wJGNvdW50eSksIF0NCiAgDQogIA0KICBpZihqPT0xKXsNCiAgICB0ZW1wX1hfYmV0YSA8LSBYX2JldGFbMToobGVuZ3RoKFhfYmV0YSkvMildDQogICAgdGVtcF9EWDEgPC0gRFgxWzE6KGxlbmd0aChYX2JldGEpLzIpLCFjb2xuYW1lcyhEWDEpJWluJSJ5ZWFyMjAxNyJdDQogICAgdGVtcF9EWDEgPC0gdGVtcF9EWDFbLC1uY29sKHRlbXBfRFgxKV0NCiAgfWVsc2UgaWYoaj09Mil7DQogICAgdGVtcF9YX2JldGEgPC0gWF9iZXRhWyhsZW5ndGgoWF9iZXRhKS8yKToobGVuZ3RoKFhfYmV0YSkpXQ0KICAgIHRlbXBfRFgxIDwtIERYMVsobGVuZ3RoKFhfYmV0YSkvMik6KGxlbmd0aChYX2JldGEpKSwhY29sbmFtZXMoRFgxKSVpbiUieWVhcjIwMTUiXQ0KICAgIHRlbXBfRFgxIDwtIHRlbXBfRFgxWywtbmNvbCh0ZW1wX0RYMSldDQogIH0NCiAgDQogIA0KICBmb3IoaSBpbiAxOm5yb3cocmVfdGVtcCkpew0KICAgICMgaSA8LTENCiAgICB0ZW1wX3B2dF9yYXRlIDwtIHBvdl9yYXRlX3ZhbCRwb3Z0X3JhdGVbaV0NCiAgICBjbnR5X3ByZWRbW2ldXSA8LSBkYXRhLmZyYW1lKGNvdW50eT1yZV90ZW1wJGNvdW50eVtpXSx0ZW1wX0RYMSx0ZW1wX1hfYmV0YSxwb3ZfcmF0ZV92YWwkcG92dF9yYXRlW2ldLHJlX3RlbXAkcmFuZF9lZmZbaV0pDQogICAgIyBjbnR5X3ByZWRbW2ldXSA8LSBkYXRhLmZyYW1lKGNvdW50eT1yZV90ZW1wJGNvdW50eVtpXSxEWDEsWF9iZXRhLHBvdl9yYXRlX3ZhbCRwb3Z0X3JhdGVbaV0scmVfdGVtcFtpXSkNCiAgfQ0KICBjbnR5X3ByZWRfeXIgPC0gZG8uY2FsbChyYmluZCxjbnR5X3ByZWQpDQogIGNudHlfcHJlZF95ciA8LSBkYXRhLmZyYW1lKHllYXI9eXIsY250eV9wcmVkX3lyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dpdFA9Y250eV9wcmVkX3lyJHRlbXBfWF9iZXRhKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNudHlfcHJlZF95ciRwb3ZfcmF0ZV92YWwucG92dF9yYXRlLmkuKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNudHlfcHJlZF95ciRyZV90ZW1wLnJhbmRfZWZmLmkuKQ0KICBjbnR5X3ByZWRpY3RlZF9wcmV2YWxlbmNlIDwtIGRhdGEuZnJhbWUoY250eV9wcmVkX3lyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZF9wcmV2YWxlbmNlPXJvdW5kKGV4cChjbnR5X3ByZWRfeXIkbG9naXRQKS8oMStleHAoY250eV9wcmVkX3lyJGxvZ2l0UCkpKjEwMCwyKSkNCiAgDQogIGNudHlfcHJlZF9hbGxbW2pdXSA8LSBjbnR5X3ByZWRpY3RlZF9wcmV2YWxlbmNlIA0KfQ0KDQpjbnR5X3ByZWRfYWxsIDwtIGRvLmNhbGwocmJpbmQsY250eV9wcmVkX2FsbCkNCmNudHlfcHJlZF9hbGwkeWVhcjEgPC0gTlVMTA0KY250eV9wcmVkX2FsbCA8LSBmYXN0RHVtbWllczo6ZHVtbXlfY29sdW1ucyhjbnR5X3ByZWRfYWxsLHNlbGVjdF9jb2x1bW5zID0gInllYXIiKQ0KY29sbmFtZXMoY250eV9wcmVkX2FsbCkgPC0gZ3N1YigiXyIsIiIsY29sbmFtZXMoY250eV9wcmVkX2FsbCkpDQpjbnR5X3ByZWRfYWxsIDwtIGNudHlfcHJlZF9hbGxbLCFjb2xuYW1lcyhjbnR5X3ByZWRfYWxsKSVpbiVkaXNfdmFyc10NCg0KDQojIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMjDQojIyAtLS0tLS0tLS0tICBwcmVkaWN0IHByZXYgZm9yIG1pc3NpbmcgY291bnRpZXMgZm9yIGVhY2ggY29tYmluYXRpb24gb2YgZGlzIHZhcnMgLSBFTkQgIC0tLS0tLS0tLS0tLS0tICMjDQojIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrICMjDQoNCm1lcmdlX2J5X3ZhciA8LSBjKGNvbG5hbWVzKERYMSksImNvdW50eSIpDQptZXJnZV9ieV92YXIgPC0gbWVyZ2VfYnlfdmFyW21lcmdlX2J5X3ZhciE9IkludCJdDQoNCmZpbmFsXzN3YXlfZGYgPC0gbWVyZ2UoY2Vuc3VzX1NleEFnZVJhY2VfRFgsY250eV9wcmVkX2FsbCwNCiAgICAgICAgICAgICAgICAgICAgICAgYnk9bWVyZ2VfYnlfdmFyLGFsbC54PVRSVUUpDQoNCmZpbmFsXzN3YXlfZGYgPC0gZmluYWxfM3dheV9kZltvcmRlcihmaW5hbF8zd2F5X2RmJGNvdW50eSksIF0NCmhlYWQoZmluYWxfM3dheV9kZikNCmZpbmFsXzN3YXlfZGYgPC0gZGF0YS5mcmFtZShmaW5hbF8zd2F5X2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JfY250eT0oZmluYWxfM3dheV9kZiRwcmVkcHJldmFsZW5jZSkqZmluYWxfM3dheV9kZiRwb3BuKSANCmZpbmFsXzN3YXlfZGYgPC0gZmluYWxfM3dheV9kZltvcmRlcihmaW5hbF8zd2F5X2RmJGNvdW50eSksIF0NCg0KcHJlZF9wcmV2X2NudHkgPC0gc3FsZGYoIlNFTEVDVCBjb3VudHkseWVhciAscm91bmQoU1VNKHByb2JfY250eSkvU1VNKHBvcG4pLDIpIGFzIHByZWRfY250eV9wcmV2ICANCiAgICAgICAgICAgICAgICAgICAgICAgIEZST00gZmluYWxfM3dheV9kZiBHUk9VUCBCWSBjb3VudHksIHllYXIiKSANCmhlYWQocHJlZF9wcmV2X2NudHkpDQpkaW0ocHJlZF9wcmV2X2NudHkpDQoNCiMjIyMjIGNvbWJpbmUgcHJlZF9wcmV2X2NudHkgd2l0aCBhdmFpbGFibGUgWVJCU1MgY291bnR5IHByZXZhbGVuY2UNCg0KdHJ1ZV9wcmV2PWRhdGEuZnJhbWUodHJ1ZV9wcmV2LA0KICAgICAgICAgICAgICAgICAgICAgdHJ1ZV9wcmV2YWxlbmNlPXJvdW5kKGV4cCh0cnVlX3ByZXYkbG9naXRfcHJvYikvKDErZXhwKHRydWVfcHJldiRsb2dpdF9wcm9iKSkqMTAwLDIpKQ0KcHJldl9wcmVkX2FsbCA8LSBtZXJnZShwcmVkX3ByZXZfY250eSx0cnVlX3ByZXYsIGJ5PWMoImNvdW50eSIsInllYXIiKSxhbGwueD1UUlVFKQ0KaGVhZChwcmV2X3ByZWRfYWxsKQ0KDQoNCiMjIyMjIyMjIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyAjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyArKysrKysrKysrKysrKysrKysrICAgICAgICAgICAgICAgICAgICAgICAgICArKysrKysrKysrKysrKysrKyAjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyArKysrKysrKysrKysrKysrKysrIENyZWF0ZSBVUyBtYXAgcHJldmFsbmNlICArKysrKysrKysrKysrKysrKyAjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyArKysrKysrKysrKysrKysrKysrICAgICAgICAgICAgICAgICAgICAgICAgICArKysrKysrKysrKysrKysrKyAjIyMjIyMjIyMjIyMNCiMjIyMjIyMjIyArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKyAjIyMjIyMjIyMjIyMNCg0KdXNfc3RhdGUgPC0gdXNtYXA6OnVzX21hcChyZWdpb25zID0gImNvdW50aWVzIikNCmNvbG5hbWVzKHVzX3N0YXRlKSA8LSBjKCJsb25nIiwibGF0Iiwib3JkZXIiLCJob2xlIiwicGllY2UiLCJncm91cCIsImZpcHMiLCJhYmJyIiwiZnVsbCIsImNvdW50eSIpDQpwbG90X2RhdGE8LSBsaXN0KCkNCmRhdGFfYWxsIDwtIGRhdGEuZnJhbWUocGxvdF9mdW5jKHByZWRfcHJldl9jbnR5LHVzX3N0YXRlKVsxXSkgICAjIyMgQ2FsbCB0aGUgcGxvdCBmdW5jdGlvbg0KIyBkZl9zdGF0ZSA8LSBkYXRhLmZyYW1lKHBsb3RfZnVuYyhwcmVkX3ByZXZfY250eSlbMl0pDQoNCg0KDQpwcmVkLm91dCR0aXRfeSA8LSB0aXRfeQ0KcHJlZC5vdXQkcHJldl9hbGwgPC0gcHJldl9wcmVkX2FsbA0KcHJlZC5vdXQkcHJlZF9wcmV2X2NudHkgPC0gcHJlZF9wcmV2X2NudHkNCg0KaWYoc2F2ZS5vdXQ9PSJZRVMiKXsNCiAgd3JpdGUuY3N2KHByZWRfcHJldl9jbnR5LCANCiAgICAgICAgICAgIHBhc3RlMChvdXRfcGF0aCwiL3ByZWRfcHJldl9jbnR5LmNzdiIpLCByb3cubmFtZXMgPSBGKQ0KICANCiAgd3JpdGUuY3N2KHByZXZfcHJlZF9hbGwsIA0KICAgICAgICAgICAgcGFzdGUwKG91dF9wYXRoLCIvcHJldl9wcmVkX2FsbC5jc3YiKSwgcm93Lm5hbWVzID0gRikNCiAgDQogIHdyaXRlLmNzdihhbGxfcmFuZG9tX2VmZmVjdCwgDQogICAgICAgICAgICBwYXN0ZTAob3V0X3BhdGgsIi9hbGxfcmFuZG9tX2VmZmVjdC5jc3YiKSwgcm93Lm5hbWVzID0gRikNCiAgDQogIHdyaXRlLmNzdihjbnR5X3ByZWRpY3RlZF9wcmV2YWxlbmNlLCANCiAgICAgICAgICAgIHBhc3RlMChvdXRfcGF0aCwiL2NudHlfcHJlZGljdGVkX3ByZXZhbGVuY2UuY3N2IiksIHJvdy5uYW1lcyA9IEYpDQogIA0KfQ0KDQoNCg0KIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcmV2YWxlbmNlIG1hcCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIw0KIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogIw0KDQppZihmaXQubW9kZWw9PSJZRVMiKXsNCiAgIyBoZ2xtLmZpdCA8LSBoZ2xtXzNtb2RlbF9maXQoWCxaLGJldGEwLHUwLHRoZXRhMCxzYXZlLm91dCxvdXQucGF0aCkNCiAgYmV0YV9lc3QgPC0gYmV0YV9lc3QgICAjIGhnbG0uZml0JHN1bW1hcnkuaGdsbSRgZml4ZWQgZWZmZWN0cyBlc3RpbWF0ZXNgDQogIHRoZXRhX2VzdCA8LSB0aGV0YV9lc3QgICAjIGhnbG0uZml0JHZhci5wYXINCiAgdV9lc3QgPC0gIHVfZXN0ICAjIGhnbG0uZml0JHJlDQogICMgcHJlZC5vdXQgPC0gaGdsbV80cHJlZChEWDAscmVzcCxkaXNfdmFycyxjbnR5X2NlbnRyZF9kZixkYXRhX2NoYW5nZSxvdXQucGF0aCkNCiAgcHJlZF9wcmV2X2NudHkgPC0gcHJlZC5vdXQkcHJlZF9wcmV2X2NudHkNCiAgdGl0X3kgPC0gcHJlZC5vdXQkdGl0X3kNCiAgcHJldl9hbGwgPC0gcHJlZC5vdXQkcHJldl9hbGwNCn1lbHNlew0KICBiZXRhX2VzdCA8LSBkYXRhLmZyYW1lKHJlYWQuY3N2KHBhc3RlMChvdXQucGF0aCxtb2RlbC50eXBlLCIvIixtb2RlbC50eXBlLCJfZmVfZXN0LmNzdiIpKSkNCiAgdGhldGFfZXN0IDwtIGRhdGEuZnJhbWUocmVhZC5jc3YocGFzdGUwKG91dC5wYXRoLG1vZGVsLnR5cGUsIi8iLG1vZGVsLnR5cGUsIl90aGV0YV9lc3QuY3N2IikpKQ0KICB1X2VzdCA8LSBkYXRhLmZyYW1lKHJlYWQuY3N2KHBhc3RlMChvdXQucGF0aCxtb2RlbC50eXBlLCIvIixtb2RlbC50eXBlLCJfcmVfZXN0LmNzdiIpKSkNCiAgcHJldl9hbGwgPC0gZGF0YS5mcmFtZShyZWFkLmNzdihwYXN0ZTAob3V0LnBhdGgsbW9kZWwudHlwZSwiL3ByZXZfcHJlZF9hbGwuY3N2IikpKQ0KICBwcmVkX3ByZXZfY250eSA8LSBkYXRhLmZyYW1lKHJlYWQuY3N2KHBhc3RlMChvdXQucGF0aCxtb2RlbC50eXBlLCIvcHJlZF9wcmV2X2NudHkuY3N2IikpKQ0KICB0aXRfeSA8LSByZXNwX3RpdGxlKHJlc3A9cmVzcCkgDQp9DQoNCmJldGFfZXN0DQoNCnlyIDwtIHVuaXF1ZShkZiR5ZWFyKQ0KeXINCg0Kb2JzX3ByZWRfcHJldiA8LSBwcmV2X2FsbFshaXMubmEocHJldl9hbGwkdHJ1ZV9wcmV2YWxlbmNlKSwgXQ0Kb2JzX3ByZWRfcHJldiA8LSBvYnNfcHJlZF9wcmV2WyFpcy5uYShvYnNfcHJlZF9wcmV2JHByZWRfY250eV9wcmV2KSwgXQ0KDQppZihpcy5mYWN0b3IocHJlZF9wcmV2X2NudHkkeWVhcikpe3ByZWRfcHJldl9jbnR5JHllYXIgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIocHJlZF9wcmV2X2NudHkkeWVhcikpfQ0KcmVzcDAgPC0gZ3N1YigiXyIsIiAiLHJlc3ApDQpkZl9zdGF0ZSA8LSBkYXRhLmZyYW1lKG1lYW5fbG9nX2xhdChwcmVkX3ByZXZfY250eSkpDQoNCg0KaWYocGxvdF9ieV95ZWFyPT0iWUVTIil7DQogIGlmKGlzLmZhY3RvcihwcmVkX3ByZXZfY250eSR5ZWFyKSl7DQogICAgcHJlZF9wcmV2X2NudHkkeWVhciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihwcmVkX3ByZXZfY250eSR5ZWFyKSkNCiAgfQ0KICANCiAgcGxvdHMgPC0gbGlzdCgpDQogIGZvcihqIGluIDE6bGVuZ3RoKHlyKSl7DQogICAgIyBqIDwtIDENCiAgICBvYnNfcHJlZF9jb3IgPC0gb2JzX3ByZWRfcHJldltvYnNfcHJlZF9wcmV2JHllYXI9PXlyW2pdICxdDQogICAgDQogICAgdXNfc3RhdGUgPC0gdXNtYXA6OnVzX21hcChyZWdpb25zID0gImNvdW50aWVzIikNCiAgICBjb2xuYW1lcyh1c19zdGF0ZSkgPC0gYygibG9uZyIsImxhdCIsIm9yZGVyIiwiaG9sZSIsInBpZWNlIiwiZ3JvdXAiLCJmaXBzIiwiYWJiciIsImZ1bGwiLCJjb3VudHkiKQ0KICAgIGRhdGFfYWxsIDwtIHBsb3RfZnVuYyhwcmVkX3ByZXZfY250eSx1c19zdGF0ZSlbW2pdXQ0KICAgIA0KICAgICMgUGVhcnNvbiBhbmQgU3BlYXJtYW4gY29ycmVsYXRpb24gZm9yIHByZWRpY3RlZCBhbmQgb2JzZXJ2ZWQgcHJldg0KICAgIHBlYXJfY29yIDwtIHJvdW5kKGNvcihvYnNfcHJlZF9jb3IkcHJlZF9jbnR5X3ByZXYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNfcHJlZF9jb3IkdHJ1ZV9wcmV2YWxlbmNlLCBtZXRob2QgPSAicGVhcnNvbiIpLCAyKQ0KICAgIHNwZWFfY29yIDwtIHJvdW5kKGNvcihvYnNfcHJlZF9jb3IkcHJlZF9jbnR5X3ByZXYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNfcHJlZF9jb3IkdHJ1ZV9wcmV2YWxlbmNlLCBtZXRob2QgPSAic3BlYXJtYW4iKSwyKQ0KICAgIA0KICAgIHBsb3RfcHJldiA8LSANCiAgICAgIGdncGxvdChkYXRhID0gZGF0YV9hbGwsYWVzKHg9bG9uZyx5PWxhdCkpKw0KICAgICAgZ2VvbV9wb2x5Z29uKG1hcHBpbmcgPSBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGZpcHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gcHJldl9xdWFudCksY29sb3VyPSJncmF5Iiwgc2l6ZSA9IDAuNCkrDQogICAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0iT3JhbmdlcyIpKw0KICAgICAgeGxhYigibG9uZ2l0dWRlIikreWxhYigibGF0aXR1ZGUiKSArDQogICAgICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9cGFzdGUwKHJlc3AwICwiOiAiKSkpKyANCiAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikrIA0KICAgICAgYW5ub3RhdGUoInRleHQiLHg9ZGZfc3RhdGUkbWxvbmcseT1kZl9zdGF0ZSRtbGF0LGxhYmVsPWRmX3N0YXRlJGFiYnIpICsNCiAgICAgIGJvcmRlcnMoInN0YXRlIikgKw0KICAgICAgZ2d0aXRsZShwYXN0ZTAoIkNvdW50eSBwcmV2YWxlbmNlIG9mICIscmVzcDAsIiAtICIseXJbal0pLA0KICAgICAgICAgICAgICBzdWJ0aXRsZSA9IHN1YnN0aXR1dGUocGFzdGUoIkNvcnJlbGF0aW9uID0gKCIscmhvXntQfSwiLCAiLHJob157U30sIikiLCIgPSAoIixwZWFyX2NvciwiLCAiLHNwZWFfY29yLCIpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXN0KHBlYXJfY29yPXBlYXJfY29yLHNwZWFfY29yPXNwZWFfY29yKSkpKw0KICAgICAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJCcm93biIsIHNpemU9MTIsIGZhY2U9Iml0YWxpYyIpKQ0KICAgIA0KICAgIHBsb3RzW1tqXV0gPC0gcGxvdF9wcmV2DQogICAgDQogICAgDQogICAgaWYoc2F2ZS5wbG90PT0iWUVTIil7DQogICAgICBnZ3NhdmUocGFzdGUwKGRpcl9wYXRoLCIvb3V0LyIscmVzcCwiLyIsbW9kZWwudHlwZSwiL2NudHlfcHJldl8iLHlyW2pdLCIucG5nIikscGxvdD1wbG90c1tbal1dLHdpZHRoID0gOCxoZWlnaHQgPSA2KSAgDQogICAgfQ0KICB9DQogIA0KfWVsc2UgaWYocGxvdF9ieV95ZWFyPT0iTk8iKXsNCiAgb2JzX3ByZWRfY29yMCA8LSBvYnNfcHJlZF9wcmV2DQogIG9ic19wcmVkX2NvciA8LSBvYnNfcHJlZF9jb3IwICU+JSBkcGx5cjo6c2VsZWN0KGNvdW50eSxwcmVkX2NudHlfcHJldix0cnVlX3ByZXZhbGVuY2UpICU+JSANCiAgICBncm91cF9ieShjb3VudHkpICU+JSANCiAgICBzdW1tYXJpc2UoT2JzQXZnUHJldj1tZWFuKHRydWVfcHJldmFsZW5jZSksUHJlZEF2Z1ByZXY9bWVhbihwcmVkX2NudHlfcHJldikpDQogIG9ic19wcmVkX2NvciA8LSBkYXRhLmZyYW1lKG9ic19wcmVkX2NvcikNCiAgDQogIHVzX3N0YXRlIDwtIHVzbWFwOjp1c19tYXAocmVnaW9ucyA9ICJjb3VudGllcyIpDQogIGNvbG5hbWVzKHVzX3N0YXRlKSA8LSBjKCJsb25nIiwibGF0Iiwib3JkZXIiLCJob2xlIiwicGllY2UiLCJncm91cCIsImZpcHMiLCJhYmJyIiwiZnVsbCIsImNvdW50eSIpDQogIGRhdGFfYWxsIDwtIHBsb3RfZnVuYyhwcmVkX3ByZXZfY250eSx1c19zdGF0ZSkNCiAgDQogICMgUGVhcnNvbiBhbmQgU3BlYXJtYW4gY29ycmVsYXRpb24gZm9yIHByZWRpY3RlZCBhbmQgb2JzZXJ2ZWQgcHJldg0KICBwZWFyX2NvciA8LSByb3VuZChjb3Iob2JzX3ByZWRfY29yJFByZWRBdmdQcmV2LCANCiAgICAgICAgICAgICAgICAgICAgICAgIG9ic19wcmVkX2NvciRPYnNBdmdQcmV2LCBtZXRob2QgPSAicGVhcnNvbiIpLCAyKQ0KICBzcGVhX2NvciA8LSByb3VuZChjb3Iob2JzX3ByZWRfY29yJFByZWRBdmdQcmV2LCANCiAgICAgICAgICAgICAgICAgICAgICAgIG9ic19wcmVkX2NvciRPYnNBdmdQcmV2LCBtZXRob2QgPSAic3BlYXJtYW4iKSwyKQ0KICBwbG90X3ByZXYgPC0gDQogICAgZ2dwbG90KGRhdGEgPSBkYXRhX2FsbCxhZXMoeD1sb25nLHk9bGF0KSkrDQogICAgZ2VvbV9wb2x5Z29uKG1hcHBpbmcgPSBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBmaXBzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBwcmV2X3F1YW50KSxjb2xvdXI9ImdyYXkiLCBzaXplID0gMC40KSsNCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0iT3JhbmdlcyIpKw0KICAgIHhsYWIoImxvbmdpdHVkZSIpK3lsYWIoImxhdGl0dWRlIikgKw0KICAgIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT1wYXN0ZTAocmVzcDAsIjogIikpKSsgDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSsgDQogICAgYW5ub3RhdGUoInRleHQiLHg9ZGZfc3RhdGUkbWxvbmcseT1kZl9zdGF0ZSRtbGF0LGxhYmVsPWRmX3N0YXRlJGFiYnIpICsNCiAgICBib3JkZXJzKCJzdGF0ZSIpICsNCiAgICBnZ3RpdGxlKHBhc3RlMCgiQ291bnR5IHByZXZhbGVuY2Ugb2YgIixyZXNwMCwiLCAyMDE1IGFuZCAyMDE3IGNvbWJpbmVkIiksDQogICAgICAgICAgICBzdWJ0aXRsZSA9IHN1YnN0aXR1dGUocGFzdGUoIkNvcnJlbGF0aW9uID0gKCIscmhvXntQfSwiLCAiLHJob157U30sIikiLCIgPSAoIixwZWFyX2NvciwiLCAiLHNwZWFfY29yLCIpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdChwZWFyX2Nvcj1wZWFyX2NvcixzcGVhX2Nvcj1zcGVhX2NvcikpKSsNCiAgICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIkJyb3duIiwgc2l6ZT0xMiwgZmFjZT0iaXRhbGljIikpDQogIA0KICBpZihzYXZlLnBsb3Q9PSJZRVMiKXsNCiAgICBnZ3NhdmUocGFzdGUwKGRpcl9wYXRoLCIvb3V0LyIscmVzcCwiLyIsbW9kZWwudHlwZSwiL2NudHlfcHJldl8yMDE1XzIwMTciLCIucG5nIikscGxvdD1wbG90X3ByZXYsd2lkdGggPSA4LGhlaWdodCA9IDYpICANCiAgfQ0KfQ0KDQoNCmBgYA0KDQoNCg0KDQoqQXV0aG9yOiBOaXJvc2hhIFJhdGhuYXlha2UsIERlcGFydG1lbnQgb2YgQmlvc3RhdGlzdGljcywgVW5pdmVyc2l0eSBvZiBOZWJyYXNrYSBNZWRpY2FsIENlbnRlciwgT21haGEsIE5FLioNCg0KDQoqUHJlcGFyZWQgdXNpbmcgKiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSk=