組員:唐思琪、林書霆、柯炯名、簡佑臻、王婷、胡祐銓

Q1

(1)

library(pracma) # Hooke-Jeeves algorithm 套件

# 需求隨價格進行變化,輸入價格傳回對應需求量。
D=function(price, a=200, b=35){
  D.val=a-b*price+rnorm(1,0,20) # noise 為常態分配
  return(max(D.val,0))
}

profit1 = function(x){
  S = 5000 # 模擬五千次
  revenue = rep(0,S)   # 初始化
  price=floor(x[2])    # 取整數
  quantity=floor(x[1]) # 取整數
  for(i in 1:S){
    demand = D(price)  # 從demand分佈產生需求數量
    # 計算營收(套用公式)
    revenue[i] = price*min(demand, quantity) - 
      quantity*1 + 
      0.5*max(quantity-demand, 0) - 
      max(demand-quantity, 0)*1 
  }
  mean(revenue) # 營收期望值
}

# Hooke-Jeeves 最佳化
result = fminsearch(profit1,
               c(10,3),
               lower=c(10,1), 
               upper=c(200,5.5),
               method=c("Hooke-Jeeves"),
               minimize=FALSE)
result
$xmin
[1] 83.617156  4.212381

$fmin
[1] 165.4497

$count
[1] 493

$convergence
[1] 0

$info
$info$solver
[1] "Hooke-Jeeves"

$info$iterations
[1] 26

(2)

# 輸入價格回傳對應需求,noise 改成指數分佈
expD=function(price,a=200,b=35){
  D.val=a-b*price+rexp(1, rate=1/10) # noise 改為指數分佈
  return(max(D.val, 0))
}

profit2 = function(x){
  S = 5000
  revenue = rep(0, S)
  price=floor(x[2])
  quantity=floor(x[1])
  for(i in 1:S){
    demand = expD(price)
    revenue[i] = price*min(demand,quantity) - quantity*1 + 0.5*max(quantity-demand,0) - max(demand-quantity,0)*1
  }
  mean(revenue)
}

result2 = fminsearch(profit2,
                     c(10,3),
                     lower=c(10,1), 
                     upper=c(200,5.5),
                     method=c("Hooke-Jeeves"),
                     minimize=FALSE)
result2
$xmin
[1] 81.745067  4.709776

$fmin
[1] 199.3369

$count
[1] 479

$convergence
[1] 0

$info
$info$solver
[1] "Hooke-Jeeves"

$info$iterations
[1] 26

Q2

(1)

S = 10000 # 模擬次數
before_demand = round(rnorm(S,9000,2000),0) # 模擬比賽前的需求
price = 25
qty = seq(500,21000,1000) # 訂購數量區間

# 初始化賽前/賽後營收
early_earning = matrix(nrow = S, ncol = length(qty)) 
late_earning = matrix(nrow = S, ncol = length(qty))
# 初始化比賽前的剩餘銷量與最終營收
remain_qty = matrix(nrow=S, ncol=length(qty))
final_earning = matrix(nrow=S, ncol=length(qty))
# 初始化營收期望值與CVAR
avg_revenue = c()
cvar = c()

# 模擬比賽後的需求
win = sample(c(0,1), S, prob = c(0.6,0.4), replace=TRUE) # 模擬球賽的輸贏
after_demand = matrix(nrow=S, ncol=2)
for(i in 1:S){
  after_demand[i,1] = win[i] # column1存放球賽的結果
  if(win[i] == 0){ # 輸球,賽後結果服從gamma分配(mu=2000,sigma=1000) -> ~gamma(scale=500,shape=4)
    after_demand[i,2] = rgamma(1,shape=4,scale=500) # 賽後輸球的需求存入column2
  } else{
    after_demand[i,2] = rnorm(1,6000,2000) # 賽後贏球的需求存入column2
  }
}

# 模擬營收
for(q in 1:length(qty)){
  for(i in 1:S){
    early_earning[i,q] = min(qty[q], before_demand[i])*15 # 賽前獲利 = 賣出min(進貨量,比賽前需求)*淨利
    remain_qty[i,q] = qty[q]-before_demand[i] # 剩下的商品數量
    if(win[i]==0){ # 輸球
      salvage = 15-12.5 # 殘值 每件只賺2.5元
      # 賽後獲利 = min(剩餘數量,比賽後需求)*殘值利潤-剩下賣不出去的成本(虧損10元)
      late_earning[i,q] = min(max(remain_qty[i,q], 0), round(after_demand[i], 0))*salvage - 
        10*max((remain_qty[i,q] - after_demand[i]), 0)
    } else{ # 贏球
      salvage = 25-10
      # 賽後獲利 = min(剩餘數量,比賽後需求)*殘值利潤-剩下賣不出去的成本(虧損10元)
      late_earning[i,q] = min(max(remain_qty[i,q],0), round(after_demand[i],0))*salvage -
        10*max((remain_qty[i,q] - after_demand[i]), 0)
    }
    final_earning[i,q] = early_earning[i,q] + late_earning[i,q]
  }
}

for(i in 1:length(qty)){
  avg_revenue[i] = mean(final_earning[,i])   # 進貨數量所對應的平均收益
  cvar[i] = quantile(final_earning[,i], 0.1) # 進貨數量所對應的最差收益值
}

# 畫出訂貨數量的區間
plot(qty, avg_revenue, type='l',xlab="production quantity",lwd=3)
points(qty[which.max(avg_revenue)], max(avg_revenue), col="red",pch=1,cex=1)


# 計算最佳訂購量與其獲利
qty[which.max(avg_revenue)] # 最佳訂購量
[1] 9500
max(avg_revenue) # 最佳訂購量下的獲利
[1] 115441

(2)

qty[which.max(cvar)] # 在最大化CVAR(q=10%)條件下最佳訂購量
[1] 6500
max(cvar) # 在最大化CVAR(q=10%)條件下最佳訂購量下的獲利
[1] 95872.5

(3)

# 計算最佳service level
cu1=25-10
cu2=15-12.5
co=10
normal_service_level = cu1/(cu1+co)    # 贏球的service_level
disscount_service_level = cu2/(cu2+co) # 輸球的service_level

opt_before_demand = quantile(before_demand,normal_service_level) # 取得球賽前滿足服務水準的銷量
opt_lose_demand = quantile(after_demand[after_demand[,1]==0,],disscount_service_level) # 輸球的滿足服務水準的銷量
opt_win_demand = quantile(after_demand[after_demand[,1]==1,],normal_service_level) # 贏球的滿足服務水準的銷量

# 初始化
early_earning2 = matrix(nrow = S, ncol = 1)
remain_qty2 = matrix(nrow = S, ncol = 1)
late_earning2 = matrix(nrow = S, ncol = 1)
final_earning2 = matrix(nrow = S, ncol = 1)

# 模擬獲利
for(i in 1:S){
  early_earning2[i] = min(before_demand[i],opt_before_demand)*15
  remain_qty2[i] = before_demand[i]-opt_before_demand
  if(win[i]==0){
    late_earning2[i] = min(max(remain_qty2[i],0), opt_lose_demand)*cu2 -
      10*max((remain_qty2[i]-opt_lose_demand),0)
  }else{
    late_earning2[i] = min(max(remain_qty2[i],0), opt_win_demand)*cu1 -
      10*max((remain_qty2[i]-opt_win_demand),0)
  }
  final_earning2[i] = early_earning2[i]+late_earning2[i]
}

mean(final_earning2)-max(avg_revenue)
[1] 10848.02

Q3

S = 1000
dict = c('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec')
c1 = c('jan','sep')
c2 = c('may','jun','jul','aug')
c3 = c('feb','mar','apr','oct','nov','dec')
history_quantity = c(80,90,120,105,95,75,70,70,110,105,90,65) #from Jun
p = matrix(nrow = 12, ncol = S)
p[4,] = 63 #四月初剩餘的分析師人數
Q = seq(11,110,1)
econmy.simulation = rnorm(S,0,0.05)#模擬每年的經濟變化
#個月的分析師需求受到經濟與noise影響
Month_Demand = function(month,n){
  his = history_quantity[month]
  #econmy = rnorm(1,0,0.05)
  econmy = econmy.simulation[n]#對應年的經濟狀況
  noise = rnorm(1,0,0.1) #noise的影響
  month_demand = round(his*(1+econmy)*(1+noise))
  return(month_demand)
}
#初始化每年每月的分析師需求
d = matrix(nrow = 12,ncol=1000)
for (s in 1:S) {
  for (i in 1:12) {
    d[i,s] = Month_Demand(i,s)
  }
}

revenue = matrix(nrow=12, ncol=S)
Q_Revenue_table = matrix(nrow = 2,ncol = 100)
avg_rev = rep(0, 100)
h = 1

(a)

simulation = function(Q){
  for (q in Q){ # 所需要聘的分析師數量
    for (s in c(1:S)){    # 模擬到第幾年
      for (i in c(4:11)){ # 初始化該年有的分析師數目
        if (dict[i] %in% c1){ # 1、9月留存率0.8~1
          retention_rate = runif(1, 0.8, 1)
        } else if (dict[i] %in% c2){ # 5、6月、7、8月留存率0.95~1
          retention_rate = runif(1, 0.95, 1)
        } else { # 2、3、4月、10、11、12月留存率0.9~1
          retention_rate = runif(1, 0.9, 1)
        }

        # 6月進行招募7月的分析師數為6月的留存人數+接受發出offer的人數;其他時間為上個月的分析師數*留存率 
        if (i == 6){
          p[i+1,s] = round(p[i,s]*retention_rate + rbinom(1, q, 0.7))
        } else {
          p[i+1,s] = round(p[i,s]*retention_rate)
        }
      p[1,s] = round(p[12,s]*retention_rate)
      p[2,s] = round(p[1,s]*retention_rate)
      p[3,s] = round(p[2,s]*retention_rate)
      p[4,s] = round(p[3,s]*retention_rate) # 新一年4月的人數
      
      }
      # 比較模擬的需求數量與模擬的現存分析師算出獲利
      for (j in c(1:12)) {
        if (p[j,s] > d[j,s]) {     # 分析師數>需求數
          revenue[j,s] = 10000*d[j,s] - 6000*p[j,s]
        }else if(p[j,s] < d[j,s]){ # 分析師數<需求數
          revenue[j,s] = 4000*p[j,s] + 400*(d[j,s]-p[j,s])
        } else { # 分析師數=需求數
          revenue[j,s] = 4000*d[j,s]
        }
      }
    }
    Q_Revenue_table[1,h] = q # 紀錄數量
    Q_Revenue_table[2,h] = mean(colMeans(revenue)) # 數量所模擬出的年平均(1000年)
    h = h+1
  }
  Q_Revenue_table
}

result = simulation(Q)
result[1,which.max(result[2,])]
[1] 61
result[2,which.max(result[2,])]
[1] 248249.1
plot(x=Q, y=result[2,],
     xlab = "Q7-Flexible",
     ylab = "E-Flexible")
    #  ylim = c(15000, 350000))
points(x = result[1,which.max(result[2,])], y = max(result[2,]), col = "red",pch=22)

(b)

revenue = matrix(nrow=12, ncol=S)
Q_Revenue_table = matrix(nrow = 2,ncol = 100)
avg_rev = rep(0, 100)
h = 1

simulation2 = function(Q){
  for (q in Q){
    half_q = round(q/2)
    for (s in c(1:S)){
      for (i in c(4:11)){
        if (dict[i] %in% c1){
          retention_rate = runif(1, 0.8, 1)
        } else if (dict[i] %in% c2){
          retention_rate = runif(1, 0.95, 1)
        } else {
          retention_rate = runif(1, 0.9, 1)
        }

        if (i == 6 | i ==8){ # 在6月與8月都會進行招募
          p[i+1,s] = round(p[i,s]*retention_rate + rbinom(1, half_q, 0.7))
        } else {
          p[i+1,s] = round(p[i,s]*retention_rate)
        }

      p[1,s] = round(p[12,s]*retention_rate)
      p[2,s] = round(p[1,s]*retention_rate)
      p[3,s] = round(p[2,s]*retention_rate)
      p[4,s] = round(p[3,s]*retention_rate) # 新一年4月的人數
      
      }

      for (j in c(1:12)) {
        if (p[j,s] > d[j,s]){
          revenue[j,s] = 10000*d[j,s] - 6000*p[j,s]
        }else if(p[j,s] < d[j,s]){
          revenue[j,s] = 4000*p[j,s] + 400*(d[j,s]-p[j,s])
        } else { # equal
          revenue[j,s] = 4000*d[j,s]
        }
      }

    }
    Q_Revenue_table[1,h] = q
    Q_Revenue_table[2,h] = mean(colMeans(revenue))
    h = h+1
  }
  Q_Revenue_table
}

result = simulation2(Q)
result[1,which.max(result[2,])] # 數量
[1] 63
result[2,which.max(result[2,])] # 獲利
[1] 266721.9
plot(x=Q, y=result[2,],
     xlab = "Q7-Flexible",
     ylab = "E-Flexible")
points(x = result[1, which.max(result[2,])], y = max(result[2,]), col = "red", pch=22)

(c)

(a) Fixed start strategy

# Fixed start strategy + 12月進行招募
Fixed_Start = function(x){
  Q7 = floor(x[1])
  Q11 = floor(x[2])
  for (s in c(1:S)){
    for (i in c(4:11)){
      if (dict[i] %in% c1){
        retention_rate = runif(1, 0.8, 1)
      } else if (dict[i] %in% c2){
        retention_rate = runif(1, 0.95, 1)
      } else {
        retention_rate = runif(1, 0.9, 1)
      }

      if (i == 6){ # 6月招募7月上線
        p[i+1,s] = round(p[i,s]*retention_rate + rbinom(1, Q7, 0.7))
      }else if(i ==11){
        p[i+1,s] = round(p[i,s]*retention_rate + rbinom(1, Q11, 0.7))
      } 
      else {
        p[i+1,s] = round(p[i,s]*retention_rate)
      }
    p[1,s] = round(p[12,s]*retention_rate)
    p[2,s] = round(p[1,s]*retention_rate)
    p[3,s] = round(p[2,s]*retention_rate)
    p[4,s] = round(p[3,s]*retention_rate) # 新一年4月的人數
  }

    for (j in c(1:12)) {
      if (p[j,s] > d[j,s]) {
        revenue[j,s] = 10000*d[j,s] - 6000*p[j,s]
      }else if(p[j,s] < d[j,s]){
        revenue[j,s] = 4000*p[j,s] + 400*(d[j,s]-p[j,s])
      } else { # equal
        revenue[j,s] = 4000*d[j,s]
      }
    }
  }
  fix_start_revenue = mean(colMeans(revenue))
}

FsRevenue = fminsearch(Fixed_Start,
               c(11,55), # 起始點
               lower=c(11,11), 
               upper=c(110,110),
               method=c("Hooke-Jeeves"),
               minimize=FALSE)

FsRevenue # 獲利
$xmin
[1] 31.74335 41.76246

$fmin
[1] 260567.4

$count
[1] 446

$convergence
[1] 0

$info
$info$solver
[1] "Hooke-Jeeves"

$info$iterations
[1] 26

(b) Flexible start strategy

# Flexible start strategy + 12月進行招募
Flexible_Start = function(x){
  half_Q7 = floor(x[1]/2)
  Q11 = floor(x[2])
  for (s in c(1:S)){
    for (i in c(4:11)){
      if (dict[i] %in% c1){
        retention_rate = runif(1, 0.8, 1)
      } else if (dict[i] %in% c2){
        retention_rate = runif(1, 0.95, 1)
      } else {
        retention_rate = runif(1, 0.9, 1)
      }

      if (i == 6 || i ==8){  # 6月招募七月上線一半、8月招募9月上線一半
        p[i+1,s] = round(p[i,s]*retention_rate + rbinom(1, half_Q7, 0.7))
      }else if(i ==11){
        p[i+1,s] = round(p[i,s]*retention_rate + rbinom(1, Q11, 0.7))
      } 
      else {
        p[i+1,s] = round(p[i,s]*retention_rate)
      }
      
    p[1,s] = round(p[12,s]*retention_rate)
    p[2,s] = round(p[1,s]*retention_rate)
    p[3,s] = round(p[2,s]*retention_rate)
    p[4,s] = round(p[3,s]*retention_rate) # 新一年4月的人數
  }

    for (j in c(1:12)) {
      if (p[j,s] > d[j,s]) {
        revenue[j,s] = 10000*d[j,s] - 6000*p[j,s]
      }else if(p[j,s] < d[j,s]){
        revenue[j,s] = 4000*p[j,s] + 400*(d[j,s]-p[j,s])
      } else { # equal
        revenue[j,s] = 4000*d[j,s]
      }
    }
  }
  flex_start_revenue = mean(colMeans(revenue))
}

FlexRevenue = fminsearch(Flexible_Start,
               c(11,55), # 起始點
               lower=c(11,11), 
               upper=c(110,110),
               method=c("Hooke-Jeeves"),
               minimize=FALSE)
FlexRevenue
$xmin
[1] 67.86424 11.02790

$fmin
[1] 275723.8

$count
[1] 460

$convergence
[1] 0

$info
$info$solver
[1] "Hooke-Jeeves"

$info$iterations
[1] 26
LS0tCnRpdGxlOiAiSFczX0dyb3VwMiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoK57WE5ZOh77ya5ZSQ5oCd55Cq44CB5p6X5pu46ZyG44CB5p+v54Kv5ZCN44CB57Ch5L2R6Ie744CB546L5am344CB6IOh56WQ6YqTCgojIyBRMQoKIyMjICgxKQpgYGB7cn0KbGlicmFyeShwcmFjbWEpICMgSG9va2UtSmVldmVzIGFsZ29yaXRobSDlpZfku7YKCiMg6ZyA5rGC6Zqo5YO55qC86YCy6KGM6K6K5YyW77yM6Ly45YWl5YO55qC85YKz5Zue5bCN5oeJ6ZyA5rGC6YeP44CCCkQ9ZnVuY3Rpb24ocHJpY2UsIGE9MjAwLCBiPTM1KXsKICBELnZhbD1hLWIqcHJpY2Urcm5vcm0oMSwwLDIwKSAjIG5vaXNlIOeCuuW4uOaFi+WIhumFjQogIHJldHVybihtYXgoRC52YWwsMCkpCn0KCnByb2ZpdDEgPSBmdW5jdGlvbih4KXsKICBTID0gNTAwMCAjIOaooeaTrOS6lOWNg+asoQogIHJldmVudWUgPSByZXAoMCxTKSAgICMg5Yid5aeL5YyWCiAgcHJpY2U9Zmxvb3IoeFsyXSkgICAgIyDlj5bmlbTmlbgKICBxdWFudGl0eT1mbG9vcih4WzFdKSAjIOWPluaVtOaVuAogIGZvcihpIGluIDE6Uyl7CiAgICBkZW1hbmQgPSBEKHByaWNlKSAgIyDlvp5kZW1hbmTliIbkvYjnlKLnlJ/pnIDmsYLmlbjph48KICAgICMg6KiI566X54ef5pS2KOWll+eUqOWFrOW8jykKICAgIHJldmVudWVbaV0gPSBwcmljZSptaW4oZGVtYW5kLCBxdWFudGl0eSkgLSAKICAgICAgcXVhbnRpdHkqMSArIAogICAgICAwLjUqbWF4KHF1YW50aXR5LWRlbWFuZCwgMCkgLSAKICAgICAgbWF4KGRlbWFuZC1xdWFudGl0eSwgMCkqMSAKICB9CiAgbWVhbihyZXZlbnVlKSAjIOeHn+aUtuacn+acm+WAvAp9CgojIEhvb2tlLUplZXZlcyDmnIDkvbPljJYKcmVzdWx0ID0gZm1pbnNlYXJjaChwcm9maXQxLAogICAgICAgICAgICAgICBjKDEwLDMpLAogICAgICAgICAgICAgICBsb3dlcj1jKDEwLDEpLCAKICAgICAgICAgICAgICAgdXBwZXI9YygyMDAsNS41KSwKICAgICAgICAgICAgICAgbWV0aG9kPWMoIkhvb2tlLUplZXZlcyIpLAogICAgICAgICAgICAgICBtaW5pbWl6ZT1GQUxTRSkKcmVzdWx0CmBgYAoKIyMjICgyKQpgYGB7cn0KIyDovLjlhaXlg7nmoLzlm57lgrPlsI3mh4npnIDmsYLvvIxub2lzZSDmlLnmiJDmjIfmlbjliIbkvYgKZXhwRD1mdW5jdGlvbihwcmljZSxhPTIwMCxiPTM1KXsKICBELnZhbD1hLWIqcHJpY2UrcmV4cCgxLCByYXRlPTEvMTApICMgbm9pc2Ug5pS554K65oyH5pW45YiG5L2ICiAgcmV0dXJuKG1heChELnZhbCwgMCkpCn0KCnByb2ZpdDIgPSBmdW5jdGlvbih4KXsKICBTID0gNTAwMAogIHJldmVudWUgPSByZXAoMCwgUykKICBwcmljZT1mbG9vcih4WzJdKQogIHF1YW50aXR5PWZsb29yKHhbMV0pCiAgZm9yKGkgaW4gMTpTKXsKICAgIGRlbWFuZCA9IGV4cEQocHJpY2UpCiAgICByZXZlbnVlW2ldID0gcHJpY2UqbWluKGRlbWFuZCxxdWFudGl0eSkgLSBxdWFudGl0eSoxICsgMC41Km1heChxdWFudGl0eS1kZW1hbmQsMCkgLSBtYXgoZGVtYW5kLXF1YW50aXR5LDApKjEKICB9CiAgbWVhbihyZXZlbnVlKQp9CgpyZXN1bHQyID0gZm1pbnNlYXJjaChwcm9maXQyLAogICAgICAgICAgICAgICAgICAgICBjKDEwLDMpLAogICAgICAgICAgICAgICAgICAgICBsb3dlcj1jKDEwLDEpLCAKICAgICAgICAgICAgICAgICAgICAgdXBwZXI9YygyMDAsNS41KSwKICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPWMoIkhvb2tlLUplZXZlcyIpLAogICAgICAgICAgICAgICAgICAgICBtaW5pbWl6ZT1GQUxTRSkKcmVzdWx0MgpgYGAKCiMjIFEyCgojIyMgKDEpCmBgYHtyfQpTID0gMTAwMDAgIyDmqKHmk6zmrKHmlbgKYmVmb3JlX2RlbWFuZCA9IHJvdW5kKHJub3JtKFMsOTAwMCwyMDAwKSwwKSAjIOaooeaTrOavlOizveWJjeeahOmcgOaxggpwcmljZSA9IDI1CnF0eSA9IHNlcSg1MDAsMjEwMDAsMTAwMCkgIyDoqILos7zmlbjph4/ljYDplpMKCiMg5Yid5aeL5YyW6LO95YmNL+izveW+jOeHn+aUtgplYXJseV9lYXJuaW5nID0gbWF0cml4KG5yb3cgPSBTLCBuY29sID0gbGVuZ3RoKHF0eSkpIApsYXRlX2Vhcm5pbmcgPSBtYXRyaXgobnJvdyA9IFMsIG5jb2wgPSBsZW5ndGgocXR5KSkKIyDliJ3lp4vljJbmr5Tos73liY3nmoTlianppJjpirfph4/oiIfmnIDntYLnh5/mlLYKcmVtYWluX3F0eSA9IG1hdHJpeChucm93PVMsIG5jb2w9bGVuZ3RoKHF0eSkpCmZpbmFsX2Vhcm5pbmcgPSBtYXRyaXgobnJvdz1TLCBuY29sPWxlbmd0aChxdHkpKQojIOWIneWni+WMlueHn+aUtuacn+acm+WAvOiIh0NWQVIKYXZnX3JldmVudWUgPSBjKCkKY3ZhciA9IGMoKQoKIyDmqKHmk6zmr5Tos73lvoznmoTpnIDmsYIKd2luID0gc2FtcGxlKGMoMCwxKSwgUywgcHJvYiA9IGMoMC42LDAuNCksIHJlcGxhY2U9VFJVRSkgIyDmqKHmk6znkIPos73nmoTovLjotI8KYWZ0ZXJfZGVtYW5kID0gbWF0cml4KG5yb3c9UywgbmNvbD0yKQpmb3IoaSBpbiAxOlMpewogIGFmdGVyX2RlbWFuZFtpLDFdID0gd2luW2ldICMgY29sdW1uMeWtmOaUvueQg+izveeahOe1kOaenAogIGlmKHdpbltpXSA9PSAwKXsgIyDovLjnkIPvvIzos73lvozntZDmnpzmnI3lvp5nYW1tYeWIhumFjShtdT0yMDAwLHNpZ21hPTEwMDApIC0+IH5nYW1tYShzY2FsZT01MDAsc2hhcGU9NCkKICAgIGFmdGVyX2RlbWFuZFtpLDJdID0gcmdhbW1hKDEsc2hhcGU9NCxzY2FsZT01MDApICMg6LO95b6M6Ly455CD55qE6ZyA5rGC5a2Y5YWlY29sdW1uMgogIH0gZWxzZXsKICAgIGFmdGVyX2RlbWFuZFtpLDJdID0gcm5vcm0oMSw2MDAwLDIwMDApICMg6LO95b6M6LSP55CD55qE6ZyA5rGC5a2Y5YWlY29sdW1uMgogIH0KfQoKIyDmqKHmk6znh5/mlLYKZm9yKHEgaW4gMTpsZW5ndGgocXR5KSl7CiAgZm9yKGkgaW4gMTpTKXsKICAgIGVhcmx5X2Vhcm5pbmdbaSxxXSA9IG1pbihxdHlbcV0sIGJlZm9yZV9kZW1hbmRbaV0pKjE1ICMg6LO95YmN542y5YipID0g6LOj5Ye6bWluKOmAsuiyqOmHjyzmr5Tos73liY3pnIDmsYIpKua3qOWIqQogICAgcmVtYWluX3F0eVtpLHFdID0gcXR5W3FdLWJlZm9yZV9kZW1hbmRbaV0gIyDliankuIvnmoTllYblk4Hmlbjph48KICAgIGlmKHdpbltpXT09MCl7ICMg6Ly455CDCiAgICAgIHNhbHZhZ2UgPSAxNS0xMi41ICMg5q6Y5YC8IOavj+S7tuWPquizujIuNeWFgwogICAgICAjIOizveW+jOeNsuWIqSA9IG1pbijlianppJjmlbjph48s5q+U6LO95b6M6ZyA5rGCKSrmrpjlgLzliKnmvaQt5Ymp5LiL6LOj5LiN5Ye65Y6755qE5oiQ5pysKOiZp+aQjTEw5YWDKQogICAgICBsYXRlX2Vhcm5pbmdbaSxxXSA9IG1pbihtYXgocmVtYWluX3F0eVtpLHFdLCAwKSwgcm91bmQoYWZ0ZXJfZGVtYW5kW2ldLCAwKSkqc2FsdmFnZSAtIAogICAgICAgIDEwKm1heCgocmVtYWluX3F0eVtpLHFdIC0gYWZ0ZXJfZGVtYW5kW2ldKSwgMCkKICAgIH0gZWxzZXsgIyDotI/nkIMKICAgICAgc2FsdmFnZSA9IDI1LTEwCiAgICAgICMg6LO95b6M542y5YipID0gbWluKOWJqemkmOaVuOmHjyzmr5Tos73lvozpnIDmsYIpKuaumOWAvOWIqea9pC3liankuIvos6PkuI3lh7rljrvnmoTmiJDmnKwo6Jmn5pCNMTDlhYMpCiAgICAgIGxhdGVfZWFybmluZ1tpLHFdID0gbWluKG1heChyZW1haW5fcXR5W2kscV0sMCksIHJvdW5kKGFmdGVyX2RlbWFuZFtpXSwwKSkqc2FsdmFnZSAtCiAgICAgICAgMTAqbWF4KChyZW1haW5fcXR5W2kscV0gLSBhZnRlcl9kZW1hbmRbaV0pLCAwKQogICAgfQogICAgZmluYWxfZWFybmluZ1tpLHFdID0gZWFybHlfZWFybmluZ1tpLHFdICsgbGF0ZV9lYXJuaW5nW2kscV0KICB9Cn0KCmZvcihpIGluIDE6bGVuZ3RoKHF0eSkpewogIGF2Z19yZXZlbnVlW2ldID0gbWVhbihmaW5hbF9lYXJuaW5nWyxpXSkgICAjIOmAsuiyqOaVuOmHj+aJgOWwjeaHieeahOW5s+Wdh+aUtuebigogIGN2YXJbaV0gPSBxdWFudGlsZShmaW5hbF9lYXJuaW5nWyxpXSwgMC4xKSAjIOmAsuiyqOaVuOmHj+aJgOWwjeaHieeahOacgOW3ruaUtuebiuWAvAp9CgojIOeVq+WHuuioguiyqOaVuOmHj+eahOWNgOmWkwpwbG90KHF0eSwgYXZnX3JldmVudWUsIHR5cGU9J2wnLHhsYWI9InByb2R1Y3Rpb24gcXVhbnRpdHkiLGx3ZD0zKQpwb2ludHMocXR5W3doaWNoLm1heChhdmdfcmV2ZW51ZSldLCBtYXgoYXZnX3JldmVudWUpLCBjb2w9InJlZCIscGNoPTEsY2V4PTEpCgojIOioiOeul+acgOS9s+ioguizvOmHj+iIh+WFtueNsuWIqQpxdHlbd2hpY2gubWF4KGF2Z19yZXZlbnVlKV0gIyDmnIDkvbPoqILos7zph48KbWF4KGF2Z19yZXZlbnVlKSAjIOacgOS9s+ioguizvOmHj+S4i+eahOeNsuWIqQpgYGAKCiMjIyAoMikKYGBge3J9CnF0eVt3aGljaC5tYXgoY3ZhcildICMg5Zyo5pyA5aSn5YyWQ1ZBUihxPTEwJSnmop3ku7bkuIvmnIDkvbPoqILos7zph48KbWF4KGN2YXIpICMg5Zyo5pyA5aSn5YyWQ1ZBUihxPTEwJSnmop3ku7bkuIvmnIDkvbPoqILos7zph4/kuIvnmoTnjbLliKkKYGBgCgojIyMgKDMpCmBgYHtyfQojIOioiOeul+acgOS9s3NlcnZpY2UgbGV2ZWwKY3UxPTI1LTEwCmN1Mj0xNS0xMi41CmNvPTEwCm5vcm1hbF9zZXJ2aWNlX2xldmVsID0gY3UxLyhjdTErY28pICAgICMg6LSP55CD55qEc2VydmljZV9sZXZlbApkaXNzY291bnRfc2VydmljZV9sZXZlbCA9IGN1Mi8oY3UyK2NvKSAjIOi8uOeQg+eahHNlcnZpY2VfbGV2ZWwKCm9wdF9iZWZvcmVfZGVtYW5kID0gcXVhbnRpbGUoYmVmb3JlX2RlbWFuZCxub3JtYWxfc2VydmljZV9sZXZlbCkgIyDlj5blvpfnkIPos73liY3mu7/otrPmnI3li5nmsLTmupbnmoTpirfph48Kb3B0X2xvc2VfZGVtYW5kID0gcXVhbnRpbGUoYWZ0ZXJfZGVtYW5kW2FmdGVyX2RlbWFuZFssMV09PTAsXSxkaXNzY291bnRfc2VydmljZV9sZXZlbCkgIyDovLjnkIPnmoTmu7/otrPmnI3li5nmsLTmupbnmoTpirfph48Kb3B0X3dpbl9kZW1hbmQgPSBxdWFudGlsZShhZnRlcl9kZW1hbmRbYWZ0ZXJfZGVtYW5kWywxXT09MSxdLG5vcm1hbF9zZXJ2aWNlX2xldmVsKSAjIOi0j+eQg+eahOa7v+i2s+acjeWLmeawtOa6lueahOmKt+mHjwoKIyDliJ3lp4vljJYKZWFybHlfZWFybmluZzIgPSBtYXRyaXgobnJvdyA9IFMsIG5jb2wgPSAxKQpyZW1haW5fcXR5MiA9IG1hdHJpeChucm93ID0gUywgbmNvbCA9IDEpCmxhdGVfZWFybmluZzIgPSBtYXRyaXgobnJvdyA9IFMsIG5jb2wgPSAxKQpmaW5hbF9lYXJuaW5nMiA9IG1hdHJpeChucm93ID0gUywgbmNvbCA9IDEpCgojIOaooeaTrOeNsuWIqQpmb3IoaSBpbiAxOlMpewogIGVhcmx5X2Vhcm5pbmcyW2ldID0gbWluKGJlZm9yZV9kZW1hbmRbaV0sb3B0X2JlZm9yZV9kZW1hbmQpKjE1CiAgcmVtYWluX3F0eTJbaV0gPSBiZWZvcmVfZGVtYW5kW2ldLW9wdF9iZWZvcmVfZGVtYW5kCiAgaWYod2luW2ldPT0wKXsKICAgIGxhdGVfZWFybmluZzJbaV0gPSBtaW4obWF4KHJlbWFpbl9xdHkyW2ldLDApLCBvcHRfbG9zZV9kZW1hbmQpKmN1MiAtCiAgICAgIDEwKm1heCgocmVtYWluX3F0eTJbaV0tb3B0X2xvc2VfZGVtYW5kKSwwKQogIH1lbHNlewogICAgbGF0ZV9lYXJuaW5nMltpXSA9IG1pbihtYXgocmVtYWluX3F0eTJbaV0sMCksIG9wdF93aW5fZGVtYW5kKSpjdTEgLQogICAgICAxMCptYXgoKHJlbWFpbl9xdHkyW2ldLW9wdF93aW5fZGVtYW5kKSwwKQogIH0KICBmaW5hbF9lYXJuaW5nMltpXSA9IGVhcmx5X2Vhcm5pbmcyW2ldK2xhdGVfZWFybmluZzJbaV0KfQoKbWVhbihmaW5hbF9lYXJuaW5nMiktbWF4KGF2Z19yZXZlbnVlKQpgYGAKCgojIyBRMwoKYGBge3J9ClMgPSAxMDAwCmRpY3QgPSBjKCdqYW4nLCdmZWInLCdtYXInLCdhcHInLCdtYXknLCdqdW4nLCdqdWwnLCdhdWcnLCdzZXAnLCdvY3QnLCdub3YnLCdkZWMnKQpjMSA9IGMoJ2phbicsJ3NlcCcpCmMyID0gYygnbWF5JywnanVuJywnanVsJywnYXVnJykKYzMgPSBjKCdmZWInLCdtYXInLCdhcHInLCdvY3QnLCdub3YnLCdkZWMnKQpoaXN0b3J5X3F1YW50aXR5ID0gYyg4MCw5MCwxMjAsMTA1LDk1LDc1LDcwLDcwLDExMCwxMDUsOTAsNjUpICNmcm9tIEp1bgpwID0gbWF0cml4KG5yb3cgPSAxMiwgbmNvbCA9IFMpCnBbNCxdID0gNjMgI+Wbm+aciOWIneWJqemkmOeahOWIhuaekOW4q+S6uuaVuApRID0gc2VxKDExLDExMCwxKQplY29ubXkuc2ltdWxhdGlvbiA9IHJub3JtKFMsMCwwLjA1KSPmqKHmk6zmr4/lubTnmoTntpPmv5/ororljJYKI+WAi+aciOeahOWIhuaekOW4q+mcgOaxguWPl+WIsOe2k+a/n+iIh25vaXNl5b2x6Z+/Ck1vbnRoX0RlbWFuZCA9IGZ1bmN0aW9uKG1vbnRoLG4pewogIGhpcyA9IGhpc3RvcnlfcXVhbnRpdHlbbW9udGhdCiAgI2Vjb25teSA9IHJub3JtKDEsMCwwLjA1KQogIGVjb25teSA9IGVjb25teS5zaW11bGF0aW9uW25dI+WwjeaHieW5tOeahOe2k+a/n+eLgOazgQogIG5vaXNlID0gcm5vcm0oMSwwLDAuMSkgI25vaXNl55qE5b2x6Z+/CiAgbW9udGhfZGVtYW5kID0gcm91bmQoaGlzKigxK2Vjb25teSkqKDErbm9pc2UpKQogIHJldHVybihtb250aF9kZW1hbmQpCn0KI+WIneWni+WMluavj+W5tOavj+aciOeahOWIhuaekOW4q+mcgOaxggpkID0gbWF0cml4KG5yb3cgPSAxMixuY29sPTEwMDApCmZvciAocyBpbiAxOlMpIHsKICBmb3IgKGkgaW4gMToxMikgewogICAgZFtpLHNdID0gTW9udGhfRGVtYW5kKGkscykKICB9Cn0KCnJldmVudWUgPSBtYXRyaXgobnJvdz0xMiwgbmNvbD1TKQpRX1JldmVudWVfdGFibGUgPSBtYXRyaXgobnJvdyA9IDIsbmNvbCA9IDEwMCkKYXZnX3JldiA9IHJlcCgwLCAxMDApCmggPSAxCmBgYAoKIyMjIChhKQpgYGB7cn0Kc2ltdWxhdGlvbiA9IGZ1bmN0aW9uKFEpewogIGZvciAocSBpbiBRKXsgIyDmiYDpnIDopoHogZjnmoTliIbmnpDluKvmlbjph48KICAgIGZvciAocyBpbiBjKDE6UykpeyAgICAjIOaooeaTrOWIsOesrOW5vuW5tAogICAgICBmb3IgKGkgaW4gYyg0OjExKSl7ICMg5Yid5aeL5YyW6Kmy5bm05pyJ55qE5YiG5p6Q5bir5pW455uuCiAgICAgICAgaWYgKGRpY3RbaV0gJWluJSBjMSl7ICMgMeOAgTnmnIjnlZnlrZjnjocwLjh+MQogICAgICAgICAgcmV0ZW50aW9uX3JhdGUgPSBydW5pZigxLCAwLjgsIDEpCiAgICAgICAgfSBlbHNlIGlmIChkaWN0W2ldICVpbiUgYzIpeyAjIDXjgIE25pyI44CBN+OAgTjmnIjnlZnlrZjnjocwLjk1fjEKICAgICAgICAgIHJldGVudGlvbl9yYXRlID0gcnVuaWYoMSwgMC45NSwgMSkKICAgICAgICB9IGVsc2UgeyAjIDLjgIEz44CBNOaciOOAgTEw44CBMTHjgIExMuaciOeVmeWtmOeOhzAuOX4xCiAgICAgICAgICByZXRlbnRpb25fcmF0ZSA9IHJ1bmlmKDEsIDAuOSwgMSkKICAgICAgICB9CgogICAgICAgICMgNuaciOmAsuihjOaLm+WLnzfmnIjnmoTliIbmnpDluKvmlbjngro25pyI55qE55WZ5a2Y5Lq65pW4K+aOpeWPl+eZvOWHum9mZmVy55qE5Lq65pW477yb5YW25LuW5pmC6ZaT54K65LiK5YCL5pyI55qE5YiG5p6Q5bir5pW477yK55WZ5a2Y546HIAogICAgICAgIGlmIChpID09IDYpewogICAgICAgICAgcFtpKzEsc10gPSByb3VuZChwW2ksc10qcmV0ZW50aW9uX3JhdGUgKyByYmlub20oMSwgcSwgMC43KSkKICAgICAgICB9IGVsc2UgewogICAgICAgICAgcFtpKzEsc10gPSByb3VuZChwW2ksc10qcmV0ZW50aW9uX3JhdGUpCiAgICAgICAgfQogICAgICBwWzEsc10gPSByb3VuZChwWzEyLHNdKnJldGVudGlvbl9yYXRlKQogICAgICBwWzIsc10gPSByb3VuZChwWzEsc10qcmV0ZW50aW9uX3JhdGUpCiAgICAgIHBbMyxzXSA9IHJvdW5kKHBbMixzXSpyZXRlbnRpb25fcmF0ZSkKICAgICAgcFs0LHNdID0gcm91bmQocFszLHNdKnJldGVudGlvbl9yYXRlKSAjIOaWsOS4gOW5tDTmnIjnmoTkurrmlbgKICAgICAgCiAgICAgIH0KICAgICAgIyDmr5TovIPmqKHmk6znmoTpnIDmsYLmlbjph4/oiIfmqKHmk6znmoTnj77lrZjliIbmnpDluKvnrpflh7rnjbLliKkKICAgICAgZm9yIChqIGluIGMoMToxMikpIHsKICAgICAgICBpZiAocFtqLHNdID4gZFtqLHNdKSB7ICAgICAjIOWIhuaekOW4q+aVuD7pnIDmsYLmlbgKICAgICAgICAgIHJldmVudWVbaixzXSA9IDEwMDAwKmRbaixzXSAtIDYwMDAqcFtqLHNdCiAgICAgICAgfWVsc2UgaWYocFtqLHNdIDwgZFtqLHNdKXsgIyDliIbmnpDluKvmlbg86ZyA5rGC5pW4CiAgICAgICAgICByZXZlbnVlW2osc10gPSA0MDAwKnBbaixzXSArIDQwMCooZFtqLHNdLXBbaixzXSkKICAgICAgICB9IGVsc2UgeyAjIOWIhuaekOW4q+aVuD3pnIDmsYLmlbgKICAgICAgICAgIHJldmVudWVbaixzXSA9IDQwMDAqZFtqLHNdCiAgICAgICAgfQogICAgICB9CiAgICB9CiAgICBRX1JldmVudWVfdGFibGVbMSxoXSA9IHEgIyDntIDpjITmlbjph48KICAgIFFfUmV2ZW51ZV90YWJsZVsyLGhdID0gbWVhbihjb2xNZWFucyhyZXZlbnVlKSkgIyDmlbjph4/miYDmqKHmk6zlh7rnmoTlubTlubPlnYfvvIgxMDAw5bm077yJCiAgICBoID0gaCsxCiAgfQogIFFfUmV2ZW51ZV90YWJsZQp9CgpyZXN1bHQgPSBzaW11bGF0aW9uKFEpCnJlc3VsdFsxLHdoaWNoLm1heChyZXN1bHRbMixdKV0KcmVzdWx0WzIsd2hpY2gubWF4KHJlc3VsdFsyLF0pXQpgYGAKYGBge3J9CnBsb3QoeD1RLCB5PXJlc3VsdFsyLF0sCiAgICAgeGxhYiA9ICJRNy1GbGV4aWJsZSIsCiAgICAgeWxhYiA9ICJFLUZsZXhpYmxlIikKICAgICMgIHlsaW0gPSBjKDE1MDAwLCAzNTAwMDApKQpwb2ludHMoeCA9IHJlc3VsdFsxLHdoaWNoLm1heChyZXN1bHRbMixdKV0sIHkgPSBtYXgocmVzdWx0WzIsXSksIGNvbCA9ICJyZWQiLHBjaD0yMikKYGBgCgojIyMgKGIpCmBgYHtyfQpyZXZlbnVlID0gbWF0cml4KG5yb3c9MTIsIG5jb2w9UykKUV9SZXZlbnVlX3RhYmxlID0gbWF0cml4KG5yb3cgPSAyLG5jb2wgPSAxMDApCmF2Z19yZXYgPSByZXAoMCwgMTAwKQpoID0gMQoKc2ltdWxhdGlvbjIgPSBmdW5jdGlvbihRKXsKICBmb3IgKHEgaW4gUSl7CiAgICBoYWxmX3EgPSByb3VuZChxLzIpCiAgICBmb3IgKHMgaW4gYygxOlMpKXsKICAgICAgZm9yIChpIGluIGMoNDoxMSkpewogICAgICAgIGlmIChkaWN0W2ldICVpbiUgYzEpewogICAgICAgICAgcmV0ZW50aW9uX3JhdGUgPSBydW5pZigxLCAwLjgsIDEpCiAgICAgICAgfSBlbHNlIGlmIChkaWN0W2ldICVpbiUgYzIpewogICAgICAgICAgcmV0ZW50aW9uX3JhdGUgPSBydW5pZigxLCAwLjk1LCAxKQogICAgICAgIH0gZWxzZSB7CiAgICAgICAgICByZXRlbnRpb25fcmF0ZSA9IHJ1bmlmKDEsIDAuOSwgMSkKICAgICAgICB9CgoKICAgICAgICBpZiAoaSA9PSA2IHwgaSA9PTgpeyAjIOWcqDbmnIjoiIc45pyI6YO95pyD6YCy6KGM5oub5YufCiAgICAgICAgICBwW2krMSxzXSA9IHJvdW5kKHBbaSxzXSpyZXRlbnRpb25fcmF0ZSArIHJiaW5vbSgxLCBoYWxmX3EsIDAuNykpCiAgICAgICAgfSBlbHNlIHsKICAgICAgICAgIHBbaSsxLHNdID0gcm91bmQocFtpLHNdKnJldGVudGlvbl9yYXRlKQogICAgICAgIH0KCiAgICAgIHBbMSxzXSA9IHJvdW5kKHBbMTIsc10qcmV0ZW50aW9uX3JhdGUpCiAgICAgIHBbMixzXSA9IHJvdW5kKHBbMSxzXSpyZXRlbnRpb25fcmF0ZSkKICAgICAgcFszLHNdID0gcm91bmQocFsyLHNdKnJldGVudGlvbl9yYXRlKQogICAgICBwWzQsc10gPSByb3VuZChwWzMsc10qcmV0ZW50aW9uX3JhdGUpICMg5paw5LiA5bm0NOaciOeahOS6uuaVuAogICAgICAKICAgICAgfQoKICAgICAgZm9yIChqIGluIGMoMToxMikpIHsKICAgICAgICBpZiAocFtqLHNdID4gZFtqLHNdKXsKICAgICAgICAgIHJldmVudWVbaixzXSA9IDEwMDAwKmRbaixzXSAtIDYwMDAqcFtqLHNdCiAgICAgICAgfWVsc2UgaWYocFtqLHNdIDwgZFtqLHNdKXsKICAgICAgICAgIHJldmVudWVbaixzXSA9IDQwMDAqcFtqLHNdICsgNDAwKihkW2osc10tcFtqLHNdKQogICAgICAgIH0gZWxzZSB7ICMgZXF1YWwKICAgICAgICAgIHJldmVudWVbaixzXSA9IDQwMDAqZFtqLHNdCiAgICAgICAgfQogICAgICB9CgogICAgfQogICAgUV9SZXZlbnVlX3RhYmxlWzEsaF0gPSBxCiAgICBRX1JldmVudWVfdGFibGVbMixoXSA9IG1lYW4oY29sTWVhbnMocmV2ZW51ZSkpCiAgICBoID0gaCsxCiAgfQogIFFfUmV2ZW51ZV90YWJsZQp9CgpyZXN1bHQgPSBzaW11bGF0aW9uMihRKQpyZXN1bHRbMSx3aGljaC5tYXgocmVzdWx0WzIsXSldICMg5pW46YePCnJlc3VsdFsyLHdoaWNoLm1heChyZXN1bHRbMixdKV0gIyDnjbLliKkKYGBgCgpgYGB7cn0KcGxvdCh4PVEsIHk9cmVzdWx0WzIsXSwKICAgICB4bGFiID0gIlE3LUZsZXhpYmxlIiwKICAgICB5bGFiID0gIkUtRmxleGlibGUiKQpwb2ludHMoeCA9IHJlc3VsdFsxLCB3aGljaC5tYXgocmVzdWx0WzIsXSldLCB5ID0gbWF4KHJlc3VsdFsyLF0pLCBjb2wgPSAicmVkIiwgcGNoPTIyKQpgYGAKCiMjIyAoYykKCiMjIyMgKGEpIEZpeGVkIHN0YXJ0IHN0cmF0ZWd5CmBgYHtyfQojIEZpeGVkIHN0YXJ0IHN0cmF0ZWd5ICsgMTLmnIjpgLLooYzmi5vli58KRml4ZWRfU3RhcnQgPSBmdW5jdGlvbih4KXsKICBRNyA9IGZsb29yKHhbMV0pCiAgUTExID0gZmxvb3IoeFsyXSkKICBmb3IgKHMgaW4gYygxOlMpKXsKICAgIGZvciAoaSBpbiBjKDQ6MTEpKXsKICAgICAgaWYgKGRpY3RbaV0gJWluJSBjMSl7CiAgICAgICAgcmV0ZW50aW9uX3JhdGUgPSBydW5pZigxLCAwLjgsIDEpCiAgICAgIH0gZWxzZSBpZiAoZGljdFtpXSAlaW4lIGMyKXsKICAgICAgICByZXRlbnRpb25fcmF0ZSA9IHJ1bmlmKDEsIDAuOTUsIDEpCiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0ZW50aW9uX3JhdGUgPSBydW5pZigxLCAwLjksIDEpCiAgICAgIH0KCgogICAgICBpZiAoaSA9PSA2KXsgIyA25pyI5oub5YufN+aciOS4iue3mgogICAgICAgIHBbaSsxLHNdID0gcm91bmQocFtpLHNdKnJldGVudGlvbl9yYXRlICsgcmJpbm9tKDEsIFE3LCAwLjcpKQogICAgICB9ZWxzZSBpZihpID09MTEpewogICAgICAgIHBbaSsxLHNdID0gcm91bmQocFtpLHNdKnJldGVudGlvbl9yYXRlICsgcmJpbm9tKDEsIFExMSwgMC43KSkKICAgICAgfSAKICAgICAgZWxzZSB7CiAgICAgICAgcFtpKzEsc10gPSByb3VuZChwW2ksc10qcmV0ZW50aW9uX3JhdGUpCiAgICAgIH0KICAgIHBbMSxzXSA9IHJvdW5kKHBbMTIsc10qcmV0ZW50aW9uX3JhdGUpCiAgICBwWzIsc10gPSByb3VuZChwWzEsc10qcmV0ZW50aW9uX3JhdGUpCiAgICBwWzMsc10gPSByb3VuZChwWzIsc10qcmV0ZW50aW9uX3JhdGUpCiAgICBwWzQsc10gPSByb3VuZChwWzMsc10qcmV0ZW50aW9uX3JhdGUpICMg5paw5LiA5bm0NOaciOeahOS6uuaVuAogIH0KCiAgICBmb3IgKGogaW4gYygxOjEyKSkgewogICAgICBpZiAocFtqLHNdID4gZFtqLHNdKSB7CiAgICAgICAgcmV2ZW51ZVtqLHNdID0gMTAwMDAqZFtqLHNdIC0gNjAwMCpwW2osc10KICAgICAgfWVsc2UgaWYocFtqLHNdIDwgZFtqLHNdKXsKICAgICAgICByZXZlbnVlW2osc10gPSA0MDAwKnBbaixzXSArIDQwMCooZFtqLHNdLXBbaixzXSkKICAgICAgfSBlbHNlIHsgIyBlcXVhbAogICAgICAgIHJldmVudWVbaixzXSA9IDQwMDAqZFtqLHNdCiAgICAgIH0KICAgIH0KICB9CiAgZml4X3N0YXJ0X3JldmVudWUgPSBtZWFuKGNvbE1lYW5zKHJldmVudWUpKQp9CgpGc1JldmVudWUgPSBmbWluc2VhcmNoKEZpeGVkX1N0YXJ0LAogICAgICAgICAgICAgICBjKDExLDU1KSwgIyDotbflp4vpu54KICAgICAgICAgICAgICAgbG93ZXI9YygxMSwxMSksIAogICAgICAgICAgICAgICB1cHBlcj1jKDExMCwxMTApLAogICAgICAgICAgICAgICBtZXRob2Q9YygiSG9va2UtSmVldmVzIiksCiAgICAgICAgICAgICAgIG1pbmltaXplPUZBTFNFKQoKRnNSZXZlbnVlICMg542y5YipCmBgYAoKIyMjIyAoYikgRmxleGlibGUgc3RhcnQgc3RyYXRlZ3kKYGBge3J9CiMgRmxleGlibGUgc3RhcnQgc3RyYXRlZ3kgKyAxMuaciOmAsuihjOaLm+WLnwpGbGV4aWJsZV9TdGFydCA9IGZ1bmN0aW9uKHgpewogIGhhbGZfUTcgPSBmbG9vcih4WzFdLzIpCiAgUTExID0gZmxvb3IoeFsyXSkKICBmb3IgKHMgaW4gYygxOlMpKXsKICAgIGZvciAoaSBpbiBjKDQ6MTEpKXsKICAgICAgaWYgKGRpY3RbaV0gJWluJSBjMSl7CiAgICAgICAgcmV0ZW50aW9uX3JhdGUgPSBydW5pZigxLCAwLjgsIDEpCiAgICAgIH0gZWxzZSBpZiAoZGljdFtpXSAlaW4lIGMyKXsKICAgICAgICByZXRlbnRpb25fcmF0ZSA9IHJ1bmlmKDEsIDAuOTUsIDEpCiAgICAgIH0gZWxzZSB7CiAgICAgICAgcmV0ZW50aW9uX3JhdGUgPSBydW5pZigxLCAwLjksIDEpCiAgICAgIH0KCgogICAgICBpZiAoaSA9PSA2IHx8IGkgPT04KXsgICMgNuaciOaLm+WLn+S4g+aciOS4iue3muS4gOWNiuOAgTjmnIjmi5vli5855pyI5LiK57ea5LiA5Y2KCiAgICAgICAgcFtpKzEsc10gPSByb3VuZChwW2ksc10qcmV0ZW50aW9uX3JhdGUgKyByYmlub20oMSwgaGFsZl9RNywgMC43KSkKICAgICAgfWVsc2UgaWYoaSA9PTExKXsKICAgICAgICBwW2krMSxzXSA9IHJvdW5kKHBbaSxzXSpyZXRlbnRpb25fcmF0ZSArIHJiaW5vbSgxLCBRMTEsIDAuNykpCiAgICAgIH0gCiAgICAgIGVsc2UgewogICAgICAgIHBbaSsxLHNdID0gcm91bmQocFtpLHNdKnJldGVudGlvbl9yYXRlKQogICAgICB9CiAgICAgIAogICAgcFsxLHNdID0gcm91bmQocFsxMixzXSpyZXRlbnRpb25fcmF0ZSkKICAgIHBbMixzXSA9IHJvdW5kKHBbMSxzXSpyZXRlbnRpb25fcmF0ZSkKICAgIHBbMyxzXSA9IHJvdW5kKHBbMixzXSpyZXRlbnRpb25fcmF0ZSkKICAgIHBbNCxzXSA9IHJvdW5kKHBbMyxzXSpyZXRlbnRpb25fcmF0ZSkgIyDmlrDkuIDlubQ05pyI55qE5Lq65pW4CiAgfQoKICAgIGZvciAoaiBpbiBjKDE6MTIpKSB7CiAgICAgIGlmIChwW2osc10gPiBkW2osc10pIHsKICAgICAgICByZXZlbnVlW2osc10gPSAxMDAwMCpkW2osc10gLSA2MDAwKnBbaixzXQogICAgICB9ZWxzZSBpZihwW2osc10gPCBkW2osc10pewogICAgICAgIHJldmVudWVbaixzXSA9IDQwMDAqcFtqLHNdICsgNDAwKihkW2osc10tcFtqLHNdKQogICAgICB9IGVsc2UgeyAjIGVxdWFsCiAgICAgICAgcmV2ZW51ZVtqLHNdID0gNDAwMCpkW2osc10KICAgICAgfQogICAgfQogIH0KICBmbGV4X3N0YXJ0X3JldmVudWUgPSBtZWFuKGNvbE1lYW5zKHJldmVudWUpKQp9CgpGbGV4UmV2ZW51ZSA9IGZtaW5zZWFyY2goRmxleGlibGVfU3RhcnQsCiAgICAgICAgICAgICAgIGMoMTEsNTUpLCAjIOi1t+Wni+m7ngogICAgICAgICAgICAgICBsb3dlcj1jKDExLDExKSwgCiAgICAgICAgICAgICAgIHVwcGVyPWMoMTEwLDExMCksCiAgICAgICAgICAgICAgIG1ldGhvZD1jKCJIb29rZS1KZWV2ZXMiKSwKICAgICAgICAgICAgICAgbWluaW1pemU9RkFMU0UpCkZsZXhSZXZlbnVlCmBgYAo=