knitr::opts_chunk$set(echo = TRUE, size = "footnotesize",error = TRUE)
load(file=".RData")

Data and Model

Intermediate variables

Case 1:\(A_{jt}^{U},A_{jt}^{L}\) both exist

\[V(A_{jt}) \geq V(A_{jt}^{U})\] \[V(A_{jt}) \geq V(A_{jt}^{L})\] \[L \leq \epsilon_{jt} \leq U\] Case 2: \(A_{jt}^{U}\) does not exist

\[L \leq \epsilon_{jt} \leq +\infty\]

Case 3: \(A_{jt}^{L}\) does not exist

\[L_0 \leq \epsilon_{jt} \leq U\]

Case 4: Do not advertise, \(A_{jt}^{U}\) exists

\[-\infty \leq \epsilon_{jt} \leq U\] Case 5: Do not advertise, \(A_{jt}^{U}\) does not exist

\[-\infty \leq \epsilon_{jt} \leq +\infty\] - Choice probability

\[Prob(A_{jt}|\bar{y}) = Prob(L \leq \epsilon_{jt} \leq U)\]

Coding Process

Step 0: Preparation

arank <- read.csv("actual_rank.csv",head = TRUE, sep= ",")
nrank <- read.csv("nominal_rank.csv",head = TRUE, sep= ",")
cost <- read.csv("price.csv",head = TRUE, sep= ",")
arank <- arank[1:254,2:7]
nrank <- nrank[1:254,2:7]
cost <- cost[,2:6]
p=list(nrow(arank))  # each day we have one clicking probability matrix
for(i in 1:nrow(arank)){ # i represents day
  for(j in 1:6){  # j represents advertiser
    for(k in 1:5){  # k represents rank
      p[[i]][j,k] = exp(dot(c(k,advertiser[[j]][i]),para_click))/(1+exp(dot(c(k,advertiser[[j]][i]),para_click)))
    }
  }
}
#  p[[i]][j,k]: clicking choice probability of advertiser j on position k in day i

Step 1: Compute \(A_{jt}^{U}\),\(A_{jt}^{L}\)

AU <- matrix(data = 0,nrow = 254, ncol = 6) #origin value==0
AL <- matrix(data = 0,nrow = 254, ncol = 6)
AUr<- matrix(data = 0,nrow = 254, ncol = 6)
ALr<- matrix(data = 0,nrow = 254, ncol = 6)
i=144
# suppose day i=144
nrank[i,]  # nominal rank
arank[i,]  # actual rank
p[[i]]
          [,1]      [,2]      [,3]      [,4]       [,5]
[1,] 0.8400993 0.8001484 0.7848633 0.5529304 0.02375946
[2,] 0.9580755 0.8469773 0.7322925 0.7071344 0.23153331
[3,] 0.8205928 0.7013163 0.5742524 0.1583170 0.15064743
[4,] 0.9731791 0.9103690 0.6006388 0.3108546 0.29336418
[5,] 0.9000588 0.5915042 0.5086688 0.3074411 0.27022673
[6,] 0.6660993 0.6162511 0.5416386 0.4032623 0.35280491
ind1 <- which(nrank[i,]!= 0) # who purchases, could move down
ind2 <- which(nrank[i,]!= arank[i,]) # purchases, actual rank != nominal rank, who could move up
ind3 <- setdiff(c(1:6),ind1)  # who does not purchase, could only move up if available
ind1
ind2
ind3
n <- length(ind2)
    if (n > 1){
      temp <- sort(as.numeric(nrank[i,ind2]),index.return = TRUE) # sort the advertisers nominal rank
        index1 <- ind2[temp$ix]  # get advertiser index
        nr <- as.numeric(nrank[i,ind2[temp$ix]]) # get nominal rank
        ar <- as.numeric(arank[i,ind2[temp$ix]]) # get actual rank
        for (j in 2:n){ #start from the second advertiser, the first could not move up
            aU<-setdiff(c(1:nr[j-1]),nrank[i,ind1])  # get all available nominal upper positions for advertiser j
            aUr<-rep(c(0),length(aU)) # compute actual rank for each nominal rank
            for (k in 1:length(aU)){
                temp1 <- sort(c(nr[-j],aU[k])) 
                aUr[k] <- which(temp1==aU[k])
            }
          AUindex <- which.min((cost[i,aU]-cost[i,nr[j]])/(p[[i]][index1[j],aUr]-p[[i]][index1[j],ar[j]])) # minimum of possible upper bounds
          AU[i,index1[j]]<-aU[AUindex] # upper bound of choice:nominal rank
          AUr[i,index1[j]]<-aUr[AUindex] # actual rank 
          }
    }

AU[i,]
AUr[i,]
 #Find available lower position
    n <- length(ind1)
    temp <- sort(as.numeric(nrank[i,ind1]),index.return = TRUE)
    index1 <- ind1[temp$ix]
    nr <- as.numeric(nrank[i,ind1[temp$ix]])
    ar <- as.numeric(arank[i,ind1[temp$ix]])
    if(n>1){
      for (j in 1:(n-1)){
          aL<-setdiff(c(nr[j+1]:5),nr)
          aLr<-rep(c(0),length(aL))
          if (length(aL)>0){
          for (k in 1:length(aL)){
                  temp1 <- sort(c(nr[-j],aL[k]))
                  aLr[k] <- which(temp1==aL[k])
              }
              ALindex <- which.max((cost[i,nr[j]]-cost[i,aL])/(p[[i]][index1[j],ar[j]]-p[[i]][index1[j],aLr]))
              AL[i,index1[j]]<-aL[ALindex]
              ALr[i,index1[j]]<-aLr[ALindex]
          }
      }
    }
AL[i,]
ALr[i,]
 n <- length(ind3)
    temp <- sort(as.numeric(nrank[i,ind1]),index.return = TRUE)
    index1 <- ind1[temp$ix]
    nr <- as.numeric(nrank[i,ind1[temp$ix]])
    ar <- as.numeric(arank[i,ind1[temp$ix]])
    aU <- setdiff(c(1:5),nr)
    if (length(aU)>0){
      for (k in 1:length(aU)){
            temp1 <- sort(c(nr,aU[k]))
            aUr[k] <- which(temp1==aU[k])
        }
      for (j in 1:n){
            AUindex <- which.min(cost[i,aU]/p[[i]][ind3[j],aUr])
            AU[i,ind3[j]]<-aU[AUindex]
            AUr[i,ind3[j]]<-aUr[AUindex]
        }
    }
    
AU[i,]
AUr[i,]
for(i in 1:254){
  
  # all the above code
  
}

Check Case 1 to Case 5, create boundary of \(\epsilon_{jt}\)

j = 1
if(nrank[i,j]==0){  # do not purchase
                if (AU[i,j]!=0){ # do not purchase, AU exists
                  prob <- pnorm(cost[i,AU[i,j]]/p[j,AUr[i,j]]-Y[j])
                }
} else{#already purchase
                  if (AU[i,j]==0&AL[i,j]!=0){ # AU does not exist, AL exists
                    prob <- 1-pnorm((cost[i,AL[i,j]]-cost[i,nrank[i,j]])/
                                   (p[[i]][j,ALr[i,j]]-p[[i]][j,arank[i,j]])-Y[j]) 
                  }else if(AU[i,j]!=0&AL[i,j]!=0){ #AU exists, AL exists
                    prob <- pnorm((cost[i,AU[i,j]]-cost[i,nrank[i,j]])/
                                   (p[[i]][j,AUr[i,j]]-p[[i]][j,arank[i,j]])-Y[j])
                                  -pnorm((cost[i,AL[i,j]]-cost[i,nrank[i,j]])/
                                   (p[[i]][j,ALr[i,j]]-p[[i]][j,arank[i,j]])-Y[j])
                  }else if(AU[i,j]!=0&AL[i,j]==0){ #AU does not exist, AL exists
                    prob <- pnorm((cost[i,AU[i,j]]-cost[i,nrank[i,j]])/
                                   (p[[i]][j,AUr[i,j]]-p[[i]][j,arank[i,j]])-Y[j])
                              -pnorm(cost[i,nrank[i,j]]/p[[i]][j,arank[i,j]]-Y[j])
                      
                  }else{  #AU does not exist, AL does not exists
                  prob <- 1-pnorm(cost[i,nrank[i,j]]/p[[i]][j,arank[i,j]]-Y[j])
                }
}

Step 3: Define likelihood function over all j and i

LL <- function(Y)
{
   ll<-c(0)
   for(i in 1:254){
        for(j in 1:6){
            if(nrank[i,j]==0){
                if (AU[i,j]!=0){
                  prob <- pnorm(cost[i,AU[i,j]]/p[j,AUr[i,j]]-Y[j])
                }
            }else{      
                if (AU[i,j]==0&AL[i,j]!=0){
                  prob <- 1-pnorm((cost[i,AL[i,j]]-cost[i,nrank[i,j]])/
                                   (p[j,ALr[i,j]]-p[j,arank[i,j]])-Y[j])
                }else if(AU[i,j]!=0&AL[i,j]!=0){
                  prob <- pnorm((cost[i,AU[i,j]]-cost[i,nrank[i,j]])/
                                   (p[j,AUr[i,j]]-p[j,arank[i,j]])-Y[j])
                         -pnorm((cost[i,AL[i,j]]-cost[i,nrank[i,j]])/
                                   (p[j,ALr[i,j]]-p[j,arank[i,j]])-Y[j])
                }else if(AU[i,j]!=0&AL[i,j]==0){
                  prob <- pnorm((cost[i,AU[i,j]]-cost[i,nrank[i,j]])/
                                   (p[j,AUr[i,j]]-p[j,arank[i,j]])-Y[j])
                          -pnorm(cost[i,nrank[i,j]]/p[j,arank[i,j]]-Y[j])
                      
                }else{
                  prob <- 1-pnorm(cost[i,nrank[i,j]]/p[j,arank[i,j]]-Y[j])
                }
            }
          ll <- ll + log(prob)
        }
   }
     
return(-ll)
}

Step 4: MLE

#maximize log likelihood function
y0 <- rep(c(1),6)
res <- optim(y0,LL)
yhat <- res$par
LS0tCnRpdGxlOiAnQXNzaWdubWVudCA0OiBFc3RpbWF0ZSBtZWFuIGV4cGVjdGVkIHByb2ZpdCBwZXIgY2xpY2sgb2YgYWR2ZXJ0aXNlcicKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKYGBge3Igc2V0dXB9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgc2l6ZSA9ICJmb290bm90ZXNpemUiLGVycm9yID0gVFJVRSkKbG9hZChmaWxlPSIuUkRhdGEiKQpgYGAKCgojIyBEYXRhIGFuZCBNb2RlbAotIERhdGE6IE5vbWluYWwgUmFuaywgQWR2ZXJ0aXNlciBhdHRyaWJ1dGVzLCBCSU4gcHJpY2UKCi0gTW9kZWwgZWxlbWVudHMKCiAgICAtIERlY2lzaW9uIFZhcmlhYmxlOiBQb3NpdGlvbiAkQV97anR9JAogICAgCiAgICAtIEtub3duIHZhcmlhYmxlczogQWR2ZXJ0aXNlciBhdHRyaWJ1dGVzICRTX3tqdH0kLCBCSU4gcHJpY2UgJEMoQV97anR9KSQsIGNsaWNraW5nIHByb2JhYmlsaXR5IHBhcmFtZXRlcnMKICAgIAogICAgLSBVbmtub3duIHBhcmFtZXRlcnM6IE1lYW4gZXhwZWN0ZWQgcHJvZml0IHBlciBjbGljayAkXGJhcnt5X2p9JAogICAgCi0gRGlzY3JldGUgY2hvaWNlIHByb2JsZW0KCiAgICAtIEdpdmVuIGNvbXBldGl0b3JzJyBjaG9pY2VzLCRcYmFye0FfdH0kLCBob3cgdG8gY2hvb3NlICRBX3tqdH0kPwogICAgCiAgICAtIENob2ljZSBwcm9iYWJpbGl0eTogJFByb2IoQV97anR9fFxiYXJ7eX0pJAogICAgCiAgICAtIExpa2VsaWhvb2QgJEwoXGJhcnt5fSk9XFBpX3tqLHR9IFByb2IoQV97anR9fFxiYXJ7eX0pJAogICAgCiMjIEludGVybWVkaWF0ZSB2YXJpYWJsZXMKLSBDb25zdW1lciBDbGlja2luZyBwcm9iYWJpbGl0eTogJFByKEFfe2p0fSxcYmFye0FfdH0sU197anR9KSQKICAgIAotIFV0aWxpdHkgZm9yICRBX3tqdH0kLCBnaXZlbiAkXGJhcntBX3R9JDogJCRWKEFfe2p0fSxcYmFye0FfdH0sU197anR9KSA9IChcYmFye3lfan0rXGVwc2lsb25fe2p0fSlQcihBX3tqdH0sXGJhcntBX3R9LFNfe2p0fSktQyhBX3tqdH0pJCQKICAgIApDYXNlIDE6JEFfe2p0fV57VX0sQV97anR9XntMfSQgYm90aCBleGlzdAoKJCRWKEFfe2p0fSkgXGdlcSBWKEFfe2p0fV57VX0pJCQKJCRWKEFfe2p0fSkgXGdlcSBWKEFfe2p0fV57TH0pJCQKJCRMIFxsZXEgXGVwc2lsb25fe2p0fSBcbGVxIFUkJApDYXNlIDI6ICRBX3tqdH1ee1V9JCBkb2VzIG5vdCBleGlzdCAKICAgIAokJEwgXGxlcSBcZXBzaWxvbl97anR9IFxsZXEgK1xpbmZ0eSQkCgpDYXNlIDM6ICRBX3tqdH1ee0x9JCBkb2VzIG5vdCBleGlzdAogICAgCiQkTF8wIFxsZXEgXGVwc2lsb25fe2p0fSBcbGVxIFUkJAoKQ2FzZSA0OiBEbyBub3QgYWR2ZXJ0aXNlLCAkQV97anR9XntVfSQgZXhpc3RzCgokJC1caW5mdHkgXGxlcSBcZXBzaWxvbl97anR9IFxsZXEgVSQkCkNhc2UgNTogRG8gbm90IGFkdmVydGlzZSwgJEFfe2p0fV57VX0kIGRvZXMgbm90IGV4aXN0CgokJC1caW5mdHkgXGxlcSBcZXBzaWxvbl97anR9IFxsZXEgK1xpbmZ0eSQkCi0gQ2hvaWNlIHByb2JhYmlsaXR5IAoKCiQkUHJvYihBX3tqdH18XGJhcnt5fSkgPSBQcm9iKEwgXGxlcSBcZXBzaWxvbl97anR9IFxsZXEgVSkkJAoKIyMgQ29kaW5nIFByb2Nlc3MKCi0gR2l2ZW4gbm9taW5hbCByYW5rLCBhY3R1YWwgcmFuaywgY29tcHV0ZSAkQV97anR9XntVfSQsJEFfe2p0fV57TH0kLCBleGlzaW5nIG9yIG5vdCBmb3IgZWFjaCBqLHQKLSBDaGVjayBDYXNlIDEgdG8gQ2FzZSA1LCBjcmVhdGUgYm91bmRhcnkgb2YgXGVwc2lsb25fe2p0fSAgZnJvbSAkQV97anR9XntVfSQsJEFfe2p0fV57TH0kLCRBX3tqdH0kCi0gQ2FsY3VsYXRlIGNob2ljZSBwcm9iYWJpbGl0eSBhcyBmdW5jdGlvbiBvZiAkXGJhcnt5fSQsICRQcm9iKEFfe2p0fXxcYmFye3l9KSQKLSBDb21wdXRlIGxpa2VsaWhvb2QgYXMgZnVuY3Rpb24gb2YgJFxiYXJ7eX0kLCRMKFxiYXJ7eX0pJAotIE1heGltaXplIEwgb3ZlciAkXGJhcnt5fSQKCgojIyBTdGVwIDA6IFByZXBhcmF0aW9uCi0gUmVhZCBEYXRhLGVhY2ggcm93IGlzIGZvciBvbmUgZGF5CmBgYHtyLGV2YWw9RkFMU0V9CmFyYW5rIDwtIHJlYWQuY3N2KCJhY3R1YWxfcmFuay5jc3YiLGhlYWQgPSBUUlVFLCBzZXA9ICIsIikKbnJhbmsgPC0gcmVhZC5jc3YoIm5vbWluYWxfcmFuay5jc3YiLGhlYWQgPSBUUlVFLCBzZXA9ICIsIikKY29zdCA8LSByZWFkLmNzdigicHJpY2UuY3N2IixoZWFkID0gVFJVRSwgc2VwPSAiLCIpCmFyYW5rIDwtIGFyYW5rWzE6MjU0LDI6N10KbnJhbmsgPC0gbnJhbmtbMToyNTQsMjo3XQpjb3N0IDwtIGNvc3RbLDI6Nl0KYGBgCi0gQ3JlYXRlIGNob2ljZSBwcm9iYWJpbGl0eSBmcm9tIHRoZSByZXN1bHQgb2YgZGlzY3JldGUgY2hvaWNlIG1vZGVsIG9mIGNsaWNraW5nCmBgYHtyLGV2YWw9RkFMU0V9CnA9bGlzdChucm93KGFyYW5rKSkgICMgZWFjaCBkYXkgd2UgaGF2ZSBvbmUgY2xpY2tpbmcgcHJvYmFiaWxpdHkgbWF0cml4CmZvcihpIGluIDE6bnJvdyhhcmFuaykpeyAjIGkgcmVwcmVzZW50cyBkYXkKICBmb3IoaiBpbiAxOjYpeyAgIyBqIHJlcHJlc2VudHMgYWR2ZXJ0aXNlcgogICAgZm9yKGsgaW4gMTo1KXsgICMgayByZXByZXNlbnRzIHJhbmsKICAgICAgcFtbaV1dW2osa10gPSBleHAoZG90KGMoayxhZHZlcnRpc2VyW1tqXV1baV0pLHBhcmFfY2xpY2spKS8oMStleHAoZG90KGMoayxhZHZlcnRpc2VyW1tqXV1baV0pLHBhcmFfY2xpY2spKSkKICAgIH0KICB9Cn0KIyAgcFtbaV1dW2osa106IGNsaWNraW5nIGNob2ljZSBwcm9iYWJpbGl0eSBvZiBhZHZlcnRpc2VyIGogb24gcG9zaXRpb24gayBpbiBkYXkgaQpgYGAKCgoKCiMjIFN0ZXAgMTogQ29tcHV0ZSAkQV97anR9XntVfSQsJEFfe2p0fV57TH0kCgoKCi0gQ3JlYXRlIG1hdHJpeGVzIGZvciBhdmFpbGFibGUgbm9taW5hbCB1cHBlciBhbmQgbG93ZXIgcG9zaXRpb25zICYgYWN0dWFsIHVwcGVyIGFuZCBsb3dlciBwb3NpdGlvbnMgCmBgYHtyfQpBVSA8LSBtYXRyaXgoZGF0YSA9IDAsbnJvdyA9IDI1NCwgbmNvbCA9IDYpICNvcmlnaW4gdmFsdWU9PTAKQUwgPC0gbWF0cml4KGRhdGEgPSAwLG5yb3cgPSAyNTQsIG5jb2wgPSA2KQpBVXI8LSBtYXRyaXgoZGF0YSA9IDAsbnJvdyA9IDI1NCwgbmNvbCA9IDYpCkFMcjwtIG1hdHJpeChkYXRhID0gMCxucm93ID0gMjU0LCBuY29sID0gNikKYGBgCgotIE9ubHkgbG9vayBhdCBvbmUgZGF5CmBgYHtyfQppPTE0NAojIHN1cHBvc2UgZGF5IGk9MTQ0Cm5yYW5rW2ksXSAgIyBub21pbmFsIHJhbmsKYXJhbmtbaSxdICAjIGFjdHVhbCByYW5rCnBbW2ldXQpgYGAKCi0gVGhyZWUgY29uZGl0aW9ucyBvZiBhZHZlcnRpc2VycwpgYGB7cn0KaW5kMSA8LSB3aGljaChucmFua1tpLF0hPSAwKSAjIHdobyBwdXJjaGFzZXMsIGNvdWxkIG1vdmUgZG93bgppbmQyIDwtIHdoaWNoKG5yYW5rW2ksXSE9IGFyYW5rW2ksXSkgIyBwdXJjaGFzZXMsIGFjdHVhbCByYW5rICE9IG5vbWluYWwgcmFuaywgd2hvIGNvdWxkIG1vdmUgdXAKaW5kMyA8LSBzZXRkaWZmKGMoMTo2KSxpbmQxKSAgIyB3aG8gZG9lcyBub3QgcHVyY2hhc2UsIGNvdWxkIG9ubHkgbW92ZSB1cCBpZiBhdmFpbGFibGUKaW5kMQppbmQyCmluZDMKYGBgCgoKLSBDb25kaXRpb24gMTogQWxyZWFkeSBQdXJjaGFzZSwgYnV0IGNvdWxkIG1vdmUgdXAgY29tcHV0ZSBBVSxBVXIKYGBge3J9Cm4gPC0gbGVuZ3RoKGluZDIpCiAgICBpZiAobiA+IDEpewogICAgICB0ZW1wIDwtIHNvcnQoYXMubnVtZXJpYyhucmFua1tpLGluZDJdKSxpbmRleC5yZXR1cm4gPSBUUlVFKSAjIHNvcnQgdGhlIGFkdmVydGlzZXJzIG5vbWluYWwgcmFuawoJICAgIGluZGV4MSA8LSBpbmQyW3RlbXAkaXhdICAjIGdldCBhZHZlcnRpc2VyIGluZGV4CgkgICAgbnIgPC0gYXMubnVtZXJpYyhucmFua1tpLGluZDJbdGVtcCRpeF1dKSAjIGdldCBub21pbmFsIHJhbmsKCSAgICBhciA8LSBhcy5udW1lcmljKGFyYW5rW2ksaW5kMlt0ZW1wJGl4XV0pICMgZ2V0IGFjdHVhbCByYW5rCgkgICAgZm9yIChqIGluIDI6bil7ICNzdGFydCBmcm9tIHRoZSBzZWNvbmQgYWR2ZXJ0aXNlciwgdGhlIGZpcnN0IGNvdWxkIG5vdCBtb3ZlIHVwCgkJICAgIGFVPC1zZXRkaWZmKGMoMTpucltqLTFdKSxucmFua1tpLGluZDFdKSAgIyBnZXQgYWxsIGF2YWlsYWJsZSBub21pbmFsIHVwcGVyIHBvc2l0aW9ucyBmb3IgYWR2ZXJ0aXNlciBqCgkJICAgIGFVcjwtcmVwKGMoMCksbGVuZ3RoKGFVKSkgIyBjb21wdXRlIGFjdHVhbCByYW5rIGZvciBlYWNoIG5vbWluYWwgcmFuawoJCSAgICBmb3IgKGsgaW4gMTpsZW5ndGgoYVUpKXsKCQkJICAgIHRlbXAxIDwtIHNvcnQoYyhuclstal0sYVVba10pKSAKCQkJICAgIGFVcltrXSA8LSB3aGljaCh0ZW1wMT09YVVba10pCgkJICAgIH0KCQkgIEFVaW5kZXggPC0gd2hpY2gubWluKChjb3N0W2ksYVVdLWNvc3RbaSxucltqXV0pLyhwW1tpXV1baW5kZXgxW2pdLGFVcl0tcFtbaV1dW2luZGV4MVtqXSxhcltqXV0pKSAjIG1pbmltdW0gb2YgcG9zc2libGUgdXBwZXIgYm91bmRzCgkJICBBVVtpLGluZGV4MVtqXV08LWFVW0FVaW5kZXhdICMgdXBwZXIgYm91bmQgb2YgY2hvaWNlOm5vbWluYWwgcmFuawoJCSAgQVVyW2ksaW5kZXgxW2pdXTwtYVVyW0FVaW5kZXhdICMgYWN0dWFsIHJhbmsgCgkJICB9CiAgICB9CgpBVVtpLF0KQVVyW2ksXQpgYGAKCgotIENvbmRpdGlvbiAyOiBBbHJlYWR5IHB1cmNoYXNlLCBjb3VsZCBtb3ZlIGRvd24sIGNvbXB1dGUgQUwsQUxyCgpgYGB7cn0KICNGaW5kIGF2YWlsYWJsZSBsb3dlciBwb3NpdGlvbgogICAgbiA8LSBsZW5ndGgoaW5kMSkKICAgIHRlbXAgPC0gc29ydChhcy5udW1lcmljKG5yYW5rW2ksaW5kMV0pLGluZGV4LnJldHVybiA9IFRSVUUpCiAgICBpbmRleDEgPC0gaW5kMVt0ZW1wJGl4XQogICAgbnIgPC0gYXMubnVtZXJpYyhucmFua1tpLGluZDFbdGVtcCRpeF1dKQogICAgYXIgPC0gYXMubnVtZXJpYyhhcmFua1tpLGluZDFbdGVtcCRpeF1dKQogICAgaWYobj4xKXsKICAgICAgZm9yIChqIGluIDE6KG4tMSkpewoJICAgICAgYUw8LXNldGRpZmYoYyhucltqKzFdOjUpLG5yKQoJICAgICAgYUxyPC1yZXAoYygwKSxsZW5ndGgoYUwpKQoJICAgICAgaWYgKGxlbmd0aChhTCk+MCl7CiAgICAgIAkgIGZvciAoayBpbiAxOmxlbmd0aChhTCkpewoJCQkgICAgICB0ZW1wMSA8LSBzb3J0KGMobnJbLWpdLGFMW2tdKSkKCQkJICAgICAgYUxyW2tdIDwtIHdoaWNoKHRlbXAxPT1hTFtrXSkKCQkgICAgICB9CgkJICAgICAgQUxpbmRleCA8LSB3aGljaC5tYXgoKGNvc3RbaSxucltqXV0tY29zdFtpLGFMXSkvKHBbW2ldXVtpbmRleDFbal0sYXJbal1dLXBbW2ldXVtpbmRleDFbal0sYUxyXSkpCgkJICAgICAgQUxbaSxpbmRleDFbal1dPC1hTFtBTGluZGV4XQoJCSAgICAgIEFMcltpLGluZGV4MVtqXV08LWFMcltBTGluZGV4XQoJICAgICAgfQogICAgICB9CiAgICB9CkFMW2ksXQpBTHJbaSxdCmBgYAoKCi0gQ29uZGl0aW9uIDM6IERvIG5vdCBwdXJjaGFzZSwgY291bGQgbW92ZSB1cCBpZiBhdmFpbGFiZSwgYnV0IGNvdWxkIG5vdCBtb3ZlIGRvd24sY29tcHV0ZSBBVSxBVXIKCmBgYHtyfQogbiA8LSBsZW5ndGgoaW5kMykKICAgIHRlbXAgPC0gc29ydChhcy5udW1lcmljKG5yYW5rW2ksaW5kMV0pLGluZGV4LnJldHVybiA9IFRSVUUpCiAgICBpbmRleDEgPC0gaW5kMVt0ZW1wJGl4XQogICAgbnIgPC0gYXMubnVtZXJpYyhucmFua1tpLGluZDFbdGVtcCRpeF1dKQogICAgYXIgPC0gYXMubnVtZXJpYyhhcmFua1tpLGluZDFbdGVtcCRpeF1dKQogICAgYVUgPC0gc2V0ZGlmZihjKDE6NSksbnIpCiAgICBpZiAobGVuZ3RoKGFVKT4wKXsKICAgICAgZm9yIChrIGluIDE6bGVuZ3RoKGFVKSl7CgkJICAgIHRlbXAxIDwtIHNvcnQoYyhucixhVVtrXSkpCgkJICAgIGFVcltrXSA8LSB3aGljaCh0ZW1wMT09YVVba10pCgkgICAgfQogICAgICBmb3IgKGogaW4gMTpuKXsKCQkgICAgQVVpbmRleCA8LSB3aGljaC5taW4oY29zdFtpLGFVXS9wW1tpXV1baW5kM1tqXSxhVXJdKQoJCSAgICBBVVtpLGluZDNbal1dPC1hVVtBVWluZGV4XQoJCSAgICBBVXJbaSxpbmQzW2pdXTwtYVVyW0FVaW5kZXhdCgkgICAgfQogICAgfQogICAgCkFVW2ksXQpBVXJbaSxdCmBgYAoKCi0gVXNlIGZvciBsb29wIHRvIGdvIHRocm91Z2ggZWFjaCBkYXkKCmBgYHtyLGV2YWw9RkFMU0V9CmZvcihpIGluIDE6MjU0KXsKICAKICAjIGFsbCB0aGUgYWJvdmUgY29kZQogIAp9CmBgYAoKIyMgQ2hlY2sgQ2FzZSAxIHRvIENhc2UgNSwgY3JlYXRlIGJvdW5kYXJ5IG9mICRcZXBzaWxvbl97anR9JAoKLSBGb3IgYWR2ZXJ0aXNlciBqIG9uIGRheSBpLCBjaGVjayBjb25kaXRpb25zIGFuZCBjYWxjdWxhdGUgcHJvYmFiaWxpdGllcwpgYGB7ci5ldmFsPUZBTFNFfQpqID0gMQppZihucmFua1tpLGpdPT0wKXsgICMgZG8gbm90IHB1cmNoYXNlCgkJCSAgICBpZiAoQVVbaSxqXSE9MCl7ICMgZG8gbm90IHB1cmNoYXNlLCBBVSBleGlzdHMKCQkJICAgICAgcHJvYiA8LSBwbm9ybShjb3N0W2ksQVVbaSxqXV0vcFtqLEFVcltpLGpdXS1ZW2pdKQoJCQkgICAgfQp9IGVsc2V7I2FscmVhZHkgcHVyY2hhc2UKCQkJICAgICAgaWYgKEFVW2ksal09PTAmQUxbaSxqXSE9MCl7ICMgQVUgZG9lcyBub3QgZXhpc3QsIEFMIGV4aXN0cwoJCQkgICAgICAgIHByb2IgPC0gMS1wbm9ybSgoY29zdFtpLEFMW2ksal1dLWNvc3RbaSxucmFua1tpLGpdXSkvCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBbW2ldXVtqLEFMcltpLGpdXS1wW1tpXV1baixhcmFua1tpLGpdXSktWVtqXSkgCgkJCSAgICAgIH1lbHNlIGlmKEFVW2ksal0hPTAmQUxbaSxqXSE9MCl7ICNBVSBleGlzdHMsIEFMIGV4aXN0cwoJCQkgICAgICAgIHByb2IgPC0gcG5vcm0oKGNvc3RbaSxBVVtpLGpdXS1jb3N0W2ksbnJhbmtbaSxqXV0pLwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwW1tpXV1baixBVXJbaSxqXV0tcFtbaV1dW2osYXJhbmtbaSxqXV0pLVlbal0pCgkJCSAgICAgCSAgICAgICAgICAgICAgLXBub3JtKChjb3N0W2ksQUxbaSxqXV0tY29zdFtpLG5yYW5rW2ksal1dKS8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocFtbaV1dW2osQUxyW2ksal1dLXBbW2ldXVtqLGFyYW5rW2ksal1dKS1ZW2pdKQoJCQkgICAgICB9ZWxzZSBpZihBVVtpLGpdIT0wJkFMW2ksal09PTApeyAjQVUgZG9lcyBub3QgZXhpc3QsIEFMIGV4aXN0cwoJCQkgICAgICAgIHByb2IgPC0gcG5vcm0oKGNvc3RbaSxBVVtpLGpdXS1jb3N0W2ksbnJhbmtbaSxqXV0pLwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChwW1tpXV1baixBVXJbaSxqXV0tcFtbaV1dW2osYXJhbmtbaSxqXV0pLVlbal0pCgkJCQkgICAgICAgICAgICAgIC1wbm9ybShjb3N0W2ksbnJhbmtbaSxqXV0vcFtbaV1dW2osYXJhbmtbaSxqXV0tWVtqXSkKICAgICAgICAgICAgICAgICAgICAgIAoJCQkgICAgICB9ZWxzZXsgICNBVSBkb2VzIG5vdCBleGlzdCwgQUwgZG9lcyBub3QgZXhpc3RzCgkJCSAgICAgIHByb2IgPC0gMS1wbm9ybShjb3N0W2ksbnJhbmtbaSxqXV0vcFtbaV1dW2osYXJhbmtbaSxqXV0tWVtqXSkKCQkJICAgIH0KfQpgYGAKCiMjIFN0ZXAgMzogRGVmaW5lIGxpa2VsaWhvb2QgZnVuY3Rpb24gb3ZlciBhbGwgaiBhbmQgaQoKYGBge3J9CkxMIDwtIGZ1bmN0aW9uKFkpCnsKICAgbGw8LWMoMCkKICAgZm9yKGkgaW4gMToyNTQpewoJICAgIGZvcihqIGluIDE6Nil7CgkJICAgIGlmKG5yYW5rW2ksal09PTApewoJCQkgICAgaWYgKEFVW2ksal0hPTApewoJCQkgICAgICBwcm9iIDwtIHBub3JtKGNvc3RbaSxBVVtpLGpdXS9wW2osQVVyW2ksal1dLVlbal0pCgkJCSAgICB9CgkJICAgIH1lbHNlewkJCgkJCSAgICBpZiAoQVVbaSxqXT09MCZBTFtpLGpdIT0wKXsKCQkJICAgICAgcHJvYiA8LSAxLXBub3JtKChjb3N0W2ksQUxbaSxqXV0tY29zdFtpLG5yYW5rW2ksal1dKS8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocFtqLEFMcltpLGpdXS1wW2osYXJhbmtbaSxqXV0pLVlbal0pCgkJCSAgICB9ZWxzZSBpZihBVVtpLGpdIT0wJkFMW2ksal0hPTApewoJCQkgICAgICBwcm9iIDwtIHBub3JtKChjb3N0W2ksQVVbaSxqXV0tY29zdFtpLG5yYW5rW2ksal1dKS8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocFtqLEFVcltpLGpdXS1wW2osYXJhbmtbaSxqXV0pLVlbal0pCgkJCSAgICAgCSAgICAgLXBub3JtKChjb3N0W2ksQUxbaSxqXV0tY29zdFtpLG5yYW5rW2ksal1dKS8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocFtqLEFMcltpLGpdXS1wW2osYXJhbmtbaSxqXV0pLVlbal0pCgkJCSAgICB9ZWxzZSBpZihBVVtpLGpdIT0wJkFMW2ksal09PTApewoJCQkgICAgICBwcm9iIDwtIHBub3JtKChjb3N0W2ksQVVbaSxqXV0tY29zdFtpLG5yYW5rW2ksal1dKS8KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAocFtqLEFVcltpLGpdXS1wW2osYXJhbmtbaSxqXV0pLVlbal0pCgkJCQkgICAgICAgICAgLXBub3JtKGNvc3RbaSxucmFua1tpLGpdXS9wW2osYXJhbmtbaSxqXV0tWVtqXSkKICAgICAgICAgICAgICAgICAgICAgIAoJCQkgICAgfWVsc2V7CgkJCSAgICAgIHByb2IgPC0gMS1wbm9ybShjb3N0W2ksbnJhbmtbaSxqXV0vcFtqLGFyYW5rW2ksal1dLVlbal0pCgkJCSAgICB9CgkJICAgIH0KCSAgICAgIGxsIDwtIGxsICsgbG9nKHByb2IpCgkgICAgfQogICB9CgkgCnJldHVybigtbGwpCn0KYGBgCgoKIyMgU3RlcCA0OiBNTEUKCmBgYHtyLGV2YWw9RkFMU0V9CiNtYXhpbWl6ZSBsb2cgbGlrZWxpaG9vZCBmdW5jdGlvbgp5MCA8LSByZXAoYygxKSw2KQpyZXMgPC0gb3B0aW0oeTAsTEwpCnloYXQgPC0gcmVzJHBhcgpgYGAKCgoKCgogIA==