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

Q1

##Multi-Period: A Simple Inventory Model

#Holding cost per item per day
h.val=0.6

unit.price=400
unit.cost=250
#Profit margin per TV sold
unit.profit=unit.price-unit.cost

#Parameters of (r, q) inventory policy
r=30
q=130

#cost per delivery from supplier to the dealer
shipping.cost=500

#The number of simulation runs
M=5000
#The number of days
T_value=360

#The experiment will be repeated for 
# m in 1:M repetitions
# t in 1:T duration

#Vector initialization
#SL: service level
SL=rep(NA,M)
daily.profit=rep(NA,M)
set.seed(5566)

start.time <- Sys.time()
for(m in 1:M){
  #Initialization: Set inventory on-hand=q in day 0
  inv.onhand=c(q,rep(NA,T_value-1))
  sales=rep(NA,T_value)
  orderQ=rep(0,T_value)
  #Keep track of inventory on-order but not arrived yet
  inv.onorder=c()
  inv.onorder.stamp=c()
  #The number of deliveries from the supplier
  delivery=0
  #The total amount of lost sales 
  loss=0
  #The number of stockouts in a repetition
  stockout=0
  #Simulate Normal demand for T periods
  d=rnorm(T_value, mean = 12, sd = 2)
  #
  for(t in 1:T_value){
     if(t==1){
       #Selling process
       sales[t]=min(inv.onhand[t],d[t])
       #Check stockout
       if(d[t]>sales[t]){
         stockout=stockout+1
         loss=loss+(d[t]-sales[t])
       }
       #Compute inventory position
       inv.position=inv.onhand[1]
       #Ordering mechanism of (r, q)
       if(inv.position<=r){
         #Compute order quantity
         Q=q-inv.position
         #Update inventory on-order
         inv.onorder=c(inv.onorder,Q)
         #Simulate stochastic lead time
         time.to.arrive=t+sample(c(4,5),1,prob=c(0.5,0.5))+1
         #Update time stamp for invenory on-order
         inv.onorder.stamp=c(inv.onorder.stamp,time.to.arrive)
         #Record order quantity
         orderQ[t]=Q
       }
       #Update inventory on-hand in the end of each day
       inv.onhand[t+1]=inv.onhand[t]-sales[t]
     }
     #
     if(t>1){
        #Check if any inventory on-order should arrive
        if(any(inv.onorder.stamp==t)){
           #Update the number of deliveries
           delivery=delivery+1
           #Compute the total of arrived inventories
           index=which(inv.onorder.stamp==t)
           arrival=sum(inv.onorder[index])
           #Update inventory on-hand before starting the day
           inv.onhand[t]=inv.onhand[t]+arrival
           #Removed those just arrived from inventory on-order
           inv.onorder=inv.onorder[-index]
           inv.onorder.stamp=inv.onorder.stamp[-index]
           #cat("arrival time:",t)
        } #end t==1
       #Record sales
       sales[t]=min(inv.onhand[t],d[t])
       #Check if any stockout takes place
       if(d[t]>sales[t]){
         stockout=stockout+1
         loss=loss+d[t]-sales[t]
       }
       #Update inventory position
       inv.position=inv.onhand[t]+sum(inv.onorder)
       #Ordering mechanism of (r, q) inventory policy
       if(inv.position<=r){
         Q=q-inv.position
         inv.onorder=c(inv.onorder,Q)
         time.to.arrive=t+sample(c(4,5),1,prob=c(0.5,0.5))+1
         inv.onorder.stamp=c(inv.onorder.stamp,time.to.arrive)
         orderQ[t]=Q
       }
       #Update inventory on-hand in the end of the day
       inv.onhand[t+1]=inv.onhand[t]-sales[t]
     } #end t>1
     #cat("day:",t,";sales:",sales[t],";onhand:",inv.onhand[t],";onorder:",
     #     inv.onorder,";order:",orderQ[t],"\n") 
  } #end for t
  
  SL[m]=(T_value-stockout)/T_value  #Calculate the service rate; 
    
  #Calculate the average daily profit
  daily.profit[m]=(unit.profit*sum(sales)-sum(h.val*inv.onhand)-
                   shipping.cost*delivery-unit.profit*loss)/T_value
  #Simulation progress marker
  if(m%%100==0){cat("Repetitions:",m,"\n")} 

} #end for m
Repetitions: 100 
Repetitions: 200 
Repetitions: 300 
Repetitions: 400 
Repetitions: 500 
Repetitions: 600 
Repetitions: 700 
Repetitions: 800 
Repetitions: 900 
Repetitions: 1000 
Repetitions: 1100 
Repetitions: 1200 
Repetitions: 1300 
Repetitions: 1400 
Repetitions: 1500 
Repetitions: 1600 
Repetitions: 1700 
Repetitions: 1800 
Repetitions: 1900 
Repetitions: 2000 
Repetitions: 2100 
Repetitions: 2200 
Repetitions: 2300 
Repetitions: 2400 
Repetitions: 2500 
Repetitions: 2600 
Repetitions: 2700 
Repetitions: 2800 
Repetitions: 2900 
Repetitions: 3000 
Repetitions: 3100 
Repetitions: 3200 
Repetitions: 3300 
Repetitions: 3400 
Repetitions: 3500 
Repetitions: 3600 
Repetitions: 3700 
Repetitions: 3800 
Repetitions: 3900 
Repetitions: 4000 
Repetitions: 4100 
Repetitions: 4200 
Repetitions: 4300 
Repetitions: 4400 
Repetitions: 4500 
Repetitions: 4600 
Repetitions: 4700 
Repetitions: 4800 
Repetitions: 4900 
Repetitions: 5000 
end.time <- Sys.time()
time.taken <- end.time - start.time
time.taken
Time difference of 4.741276 secs
summary(daily.profit)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  647.4   714.7   728.8   729.4   743.2   818.7 
summary(SL)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.6528  0.6778  0.6806  0.6818  0.6861  0.7139 
##Search for optimal (R*, Q*)
R=seq(0,60,5)
Q=seq(90,360,10)

search.val=as.matrix(expand.grid(R,Q))
dim(search.val)
[1] 364   2
#The (r, q) model as a function for simulation
InvModel=function(i){
  r=search.val[i,1]
  q=search.val[i,2]
  #Vector initialization
  SL=rep(NA,M)
  daily.profit=rep(NA,M)
  for(m in 1:M){
    #Initialization: Set inventory on-hand=q in day 0
    inv.onhand=c(q,rep(NA,T_value-1))
    sales=rep(NA,T_value)
    orderQ=rep(0,T_value)
    #Keep track of inventory on-order but not arrived yet
    inv.onorder=c()
    inv.onorder.stamp=c()
    #The number of deliveries from the supplier
    delivery=0
    #The total amount of lost sales 
    loss=0
    #The number of stockouts in a repetition
    stockout=0
    #Simulate Normal demand for T periods
    d=rnorm(T_value, mean = 12, sd = 2)
    #
    for(t in 1:T_value){
      if(t==1){
        #Selling process
        sales[t]=min(inv.onhand[t],d[t])
        #Check stockout
        if(d[t]>sales[t]){
          stockout=stockout+1
          loss=loss+(d[t]-sales[t])
        }
        #Compute inventory position
        inv.position=inv.onhand[1]
        #Ordering mechanism of (r, q)
        if(inv.position<=r){
          #Compute order quantity
          Q=q-inv.position
          #Update inventory on-order
          inv.onorder=c(inv.onorder,Q)
          #Simulate stochastic lead time
          time.to.arrive=t+sample(c(4,5),1,prob=c(0.5,0.5))+1
          #Update time stamp for invenory on-order
          inv.onorder.stamp=c(inv.onorder.stamp,time.to.arrive)
          #Record order quantity
          orderQ[t]=Q
        }
        #Update inventory on-hand in the end of each day
        inv.onhand[t+1]=inv.onhand[t]-sales[t]
      }
      #
      if(t>1){
        #Check if any inventory on-order should arrive
        if(any(inv.onorder.stamp==t)){
          #Update the number of deliveries
          delivery=delivery+1
          #Compute the total of arrived inventories
          index=which(inv.onorder.stamp==t)
          arrival=sum(inv.onorder[index])
          #Update inventory on-hand before starting the day
          inv.onhand[t]=inv.onhand[t]+arrival
          #Removed those just arrived from inventory on-order
          inv.onorder=inv.onorder[-index]
          inv.onorder.stamp=inv.onorder.stamp[-index]
          #cat("arrival time:",t)
        } #end t==1
        #Record sales
        sales[t]=min(inv.onhand[t],d[t])
        #Check if any stockout takes place
        if(d[t]>sales[t]){
          stockout=stockout+1
          loss=loss+d[t]-sales[t]
        }
        #Update inventory position
        inv.position=inv.onhand[t]+sum(inv.onorder)
        #Ordering mechanism of (r, q) inventory policy
        if(inv.position<=r){
          Q=q-inv.position
          inv.onorder=c(inv.onorder,Q)
          time.to.arrive=t+sample(c(4,5),1,prob=c(0.5,0.5))+1
          inv.onorder.stamp=c(inv.onorder.stamp,time.to.arrive)
          orderQ[t]=Q
        }
        #Update inventory on-hand in the end of the day
        inv.onhand[t+1]=inv.onhand[t]-sales[t]
      } #end t>1
      #cat("day:",t,";sales:",sales[t],";onhand:",inv.onhand[t],";onorder:",
      #     inv.onorder,";order:",orderQ[t],"\n") 
    } #end for t
    
    SL[m]=(T_value-stockout)/T_value  #Calculate the service rate; 
    
    #Calculate the average daily profit
    daily.profit[m]=(unit.profit*sum(sales)-sum(h.val*inv.onhand)-
                       shipping.cost*delivery-unit.profit*loss)/T_value
    
  } #end for m
  c(mean(SL),mean(daily.profit),sd(daily.profit))
}


InvModel(1)
##Use parallel CPU computing for optimal search
library(foreach)
library(doParallel)
registerDoParallel(cores=6)
getDoParWorkers()
[1] 6
start.time <- Sys.time()
sim.results=foreach(i=1:nrow(search.val),
             .combine=rbind,.verbose=F) %dopar% InvModel(i)
##Apply the Hooke-Jeeves search algorithm
InvModel=function(par){
  r=par[1]
  q=par[2]
  #Vector initialization
  SL=rep(NA,M)
  daily.profit=rep(NA,M)
  for(m in 1:M){
    #Initialization: Set inventory on-hand=q in day 0
    inv.onhand=c(q,rep(NA,T_value-1))
    sales=rep(NA,T_value)
    orderQ=rep(0,T_value)
    #Keep track of inventory on-order but not arrived yet
    inv.onorder=c()
    inv.onorder.stamp=c()
    #The number of deliveries from the supplier
    delivery=0
    #The total amount of lost sales 
    loss=0
    #The number of stockouts in a repetition
    stockout=0
    #Simulate Normal demand for T periods
    d=rnorm(T_value, mean = 12, sd = 2)
    #
    for(t in 1:T_value){
      if(t==1){
        #Selling process
        sales[t]=min(inv.onhand[t],d[t])
        #Check stockout
        if(d[t]>sales[t]){
          stockout=stockout+1
          loss=loss+(d[t]-sales[t])
        }
        #Compute inventory position
        inv.position=inv.onhand[1]
        #Ordering mechanism of (r, q)
        if(inv.position<=r){
          #Compute order quantity
          Q=q-inv.position
          #Update inventory on-order
          inv.onorder=c(inv.onorder,Q)
          #Simulate stochastic lead time
          time.to.arrive=t+sample(c(4,5),1,prob=c(0.5,0.5))+1
          #Update time stamp for invenory on-order
          inv.onorder.stamp=c(inv.onorder.stamp,time.to.arrive)
          #Record order quantity
          orderQ[t]=Q
        }
        #Update inventory on-hand in the end of each day
        inv.onhand[t+1]=inv.onhand[t]-sales[t]
      }
      #
      if(t>1){
        #Check if any inventory on-order should arrive
        if(any(inv.onorder.stamp==t)){
          #Update the number of deliveries
          delivery=delivery+1
          #Compute the total of arrived inventories
          index=which(inv.onorder.stamp==t)
          arrival=sum(inv.onorder[index])
          #Update inventory on-hand before starting the day
          inv.onhand[t]=inv.onhand[t]+arrival
          #Removed those just arrived from inventory on-order
          inv.onorder=inv.onorder[-index]
          inv.onorder.stamp=inv.onorder.stamp[-index]
          #cat("arrival time:",t)
        } #end t==1
        #Record sales
        sales[t]=min(inv.onhand[t],d[t])
        #Check if any stockout takes place
        if(d[t]>sales[t]){
          stockout=stockout+1
          loss=loss+d[t]-sales[t]
        }
        #Update inventory position
        inv.position=inv.onhand[t]+sum(inv.onorder)
        #Ordering mechanism of (r, q) inventory policy
        if(inv.position<=r){
          Q=q-inv.position
          inv.onorder=c(inv.onorder,Q)
          time.to.arrive=t+sample(c(4,5),1,prob=c(0.5,0.5))+1
          inv.onorder.stamp=c(inv.onorder.stamp,time.to.arrive)
          orderQ[t]=Q
        }
        #Update inventory on-hand in the end of the day
        inv.onhand[t+1]=inv.onhand[t]-sales[t]
      } #end t>1
      #cat("day:",t,";sales:",sales[t],";onhand:",inv.onhand[t],";onorder:",
      #     inv.onorder,";order:",orderQ[t],"\n") 
    } #end for t
    
    SL[m]=(T_value-stockout)/T_value  #Calculate the service rate; 
    
    #Calculate the average daily profit
    daily.profit[m]=(unit.profit*sum(sales)-sum(h.val*inv.onhand)-
                       shipping.cost*delivery-unit.profit*loss)/T_value
    
  } #end for m
  #c(mean(SL),mean(daily.profit),sd(daily.profit))
  mean(daily.profit)
}
library(pracma)
res=fminsearch(InvModel,c(30,130),
         lower=c(20,80), 
         upper=c(150,250),
         method=c("Hooke-Jeeves"),
         minimize=FALSE)

res
$xmin
[1]  87.63159 215.07648

$fmin
[1] 1700.547

$count
[1] 479

$convergence
[1] 0

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

$info$iterations
[1] 26
LS0tCnRpdGxlOiAiSFc0X0dyb3VwMiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoK57WE5ZOh77ya5ZSQ5oCd55Cq44CB5p6X5pu46ZyG44CB5p+v54Kv5ZCN44CB57Ch5L2R6Ie744CB546L5am344CB6IOh56WQ6YqTCgojIyBRMQoKYGBge3J9CiMjTXVsdGktUGVyaW9kOiBBIFNpbXBsZSBJbnZlbnRvcnkgTW9kZWwKCiNIb2xkaW5nIGNvc3QgcGVyIGl0ZW0gcGVyIGRheQpoLnZhbD0wLjYKCnVuaXQucHJpY2U9NDAwCnVuaXQuY29zdD0yNTAKI1Byb2ZpdCBtYXJnaW4gcGVyIFRWIHNvbGQKdW5pdC5wcm9maXQ9dW5pdC5wcmljZS11bml0LmNvc3QKCiNQYXJhbWV0ZXJzIG9mIChyLCBxKSBpbnZlbnRvcnkgcG9saWN5CnI9MzAKcT0xMzAKCiNjb3N0IHBlciBkZWxpdmVyeSBmcm9tIHN1cHBsaWVyIHRvIHRoZSBkZWFsZXIKc2hpcHBpbmcuY29zdD01MDAKCiNUaGUgbnVtYmVyIG9mIHNpbXVsYXRpb24gcnVucwpNPTUwMDAKI1RoZSBudW1iZXIgb2YgZGF5cwpUX3ZhbHVlPTM2MAoKI1RoZSBleHBlcmltZW50IHdpbGwgYmUgcmVwZWF0ZWQgZm9yIAojIG0gaW4gMTpNIHJlcGV0aXRpb25zCiMgdCBpbiAxOlQgZHVyYXRpb24KCiNWZWN0b3IgaW5pdGlhbGl6YXRpb24KI1NMOiBzZXJ2aWNlIGxldmVsClNMPXJlcChOQSxNKQpkYWlseS5wcm9maXQ9cmVwKE5BLE0pCnNldC5zZWVkKDU1NjYpCgpzdGFydC50aW1lIDwtIFN5cy50aW1lKCkKZm9yKG0gaW4gMTpNKXsKICAjSW5pdGlhbGl6YXRpb246IFNldCBpbnZlbnRvcnkgb24taGFuZD1xIGluIGRheSAwCiAgaW52Lm9uaGFuZD1jKHEscmVwKE5BLFRfdmFsdWUtMSkpCiAgc2FsZXM9cmVwKE5BLFRfdmFsdWUpCiAgb3JkZXJRPXJlcCgwLFRfdmFsdWUpCiAgI0tlZXAgdHJhY2sgb2YgaW52ZW50b3J5IG9uLW9yZGVyIGJ1dCBub3QgYXJyaXZlZCB5ZXQKICBpbnYub25vcmRlcj1jKCkKICBpbnYub25vcmRlci5zdGFtcD1jKCkKICAjVGhlIG51bWJlciBvZiBkZWxpdmVyaWVzIGZyb20gdGhlIHN1cHBsaWVyCiAgZGVsaXZlcnk9MAogICNUaGUgdG90YWwgYW1vdW50IG9mIGxvc3Qgc2FsZXMgCiAgbG9zcz0wCiAgI1RoZSBudW1iZXIgb2Ygc3RvY2tvdXRzIGluIGEgcmVwZXRpdGlvbgogIHN0b2Nrb3V0PTAKICAjU2ltdWxhdGUgTm9ybWFsIGRlbWFuZCBmb3IgVCBwZXJpb2RzCiAgZD1ybm9ybShUX3ZhbHVlLCBtZWFuID0gMTIsIHNkID0gMikKICAjCiAgZm9yKHQgaW4gMTpUX3ZhbHVlKXsKICAgICBpZih0PT0xKXsKICAgICAgICNTZWxsaW5nIHByb2Nlc3MKICAgICAgIHNhbGVzW3RdPW1pbihpbnYub25oYW5kW3RdLGRbdF0pCiAgICAgICAjQ2hlY2sgc3RvY2tvdXQKICAgICAgIGlmKGRbdF0+c2FsZXNbdF0pewogICAgICAgICBzdG9ja291dD1zdG9ja291dCsxCiAgICAgICAgIGxvc3M9bG9zcysoZFt0XS1zYWxlc1t0XSkKICAgICAgIH0KICAgICAgICNDb21wdXRlIGludmVudG9yeSBwb3NpdGlvbgogICAgICAgaW52LnBvc2l0aW9uPWludi5vbmhhbmRbMV0KICAgICAgICNPcmRlcmluZyBtZWNoYW5pc20gb2YgKHIsIHEpCiAgICAgICBpZihpbnYucG9zaXRpb248PXIpewogICAgICAgICAjQ29tcHV0ZSBvcmRlciBxdWFudGl0eQogICAgICAgICBRPXEtaW52LnBvc2l0aW9uCiAgICAgICAgICNVcGRhdGUgaW52ZW50b3J5IG9uLW9yZGVyCiAgICAgICAgIGludi5vbm9yZGVyPWMoaW52Lm9ub3JkZXIsUSkKICAgICAgICAgI1NpbXVsYXRlIHN0b2NoYXN0aWMgbGVhZCB0aW1lCiAgICAgICAgIHRpbWUudG8uYXJyaXZlPXQrc2FtcGxlKGMoNCw1KSwxLHByb2I9YygwLjUsMC41KSkrMQogICAgICAgICAjVXBkYXRlIHRpbWUgc3RhbXAgZm9yIGludmVub3J5IG9uLW9yZGVyCiAgICAgICAgIGludi5vbm9yZGVyLnN0YW1wPWMoaW52Lm9ub3JkZXIuc3RhbXAsdGltZS50by5hcnJpdmUpCiAgICAgICAgICNSZWNvcmQgb3JkZXIgcXVhbnRpdHkKICAgICAgICAgb3JkZXJRW3RdPVEKICAgICAgIH0KICAgICAgICNVcGRhdGUgaW52ZW50b3J5IG9uLWhhbmQgaW4gdGhlIGVuZCBvZiBlYWNoIGRheQogICAgICAgaW52Lm9uaGFuZFt0KzFdPWludi5vbmhhbmRbdF0tc2FsZXNbdF0KICAgICB9CiAgICAgIwogICAgIGlmKHQ+MSl7CiAgICAgICAgI0NoZWNrIGlmIGFueSBpbnZlbnRvcnkgb24tb3JkZXIgc2hvdWxkIGFycml2ZQogICAgICAgIGlmKGFueShpbnYub25vcmRlci5zdGFtcD09dCkpewogICAgICAgICAgICNVcGRhdGUgdGhlIG51bWJlciBvZiBkZWxpdmVyaWVzCiAgICAgICAgICAgZGVsaXZlcnk9ZGVsaXZlcnkrMQogICAgICAgICAgICNDb21wdXRlIHRoZSB0b3RhbCBvZiBhcnJpdmVkIGludmVudG9yaWVzCiAgICAgICAgICAgaW5kZXg9d2hpY2goaW52Lm9ub3JkZXIuc3RhbXA9PXQpCiAgICAgICAgICAgYXJyaXZhbD1zdW0oaW52Lm9ub3JkZXJbaW5kZXhdKQogICAgICAgICAgICNVcGRhdGUgaW52ZW50b3J5IG9uLWhhbmQgYmVmb3JlIHN0YXJ0aW5nIHRoZSBkYXkKICAgICAgICAgICBpbnYub25oYW5kW3RdPWludi5vbmhhbmRbdF0rYXJyaXZhbAogICAgICAgICAgICNSZW1vdmVkIHRob3NlIGp1c3QgYXJyaXZlZCBmcm9tIGludmVudG9yeSBvbi1vcmRlcgogICAgICAgICAgIGludi5vbm9yZGVyPWludi5vbm9yZGVyWy1pbmRleF0KICAgICAgICAgICBpbnYub25vcmRlci5zdGFtcD1pbnYub25vcmRlci5zdGFtcFstaW5kZXhdCiAgICAgICAgICAgI2NhdCgiYXJyaXZhbCB0aW1lOiIsdCkKICAgICAgICB9ICNlbmQgdD09MQogICAgICAgI1JlY29yZCBzYWxlcwogICAgICAgc2FsZXNbdF09bWluKGludi5vbmhhbmRbdF0sZFt0XSkKICAgICAgICNDaGVjayBpZiBhbnkgc3RvY2tvdXQgdGFrZXMgcGxhY2UKICAgICAgIGlmKGRbdF0+c2FsZXNbdF0pewogICAgICAgICBzdG9ja291dD1zdG9ja291dCsxCiAgICAgICAgIGxvc3M9bG9zcytkW3RdLXNhbGVzW3RdCiAgICAgICB9CiAgICAgICAjVXBkYXRlIGludmVudG9yeSBwb3NpdGlvbgogICAgICAgaW52LnBvc2l0aW9uPWludi5vbmhhbmRbdF0rc3VtKGludi5vbm9yZGVyKQogICAgICAgI09yZGVyaW5nIG1lY2hhbmlzbSBvZiAociwgcSkgaW52ZW50b3J5IHBvbGljeQogICAgICAgaWYoaW52LnBvc2l0aW9uPD1yKXsKICAgICAgICAgUT1xLWludi5wb3NpdGlvbgogICAgICAgICBpbnYub25vcmRlcj1jKGludi5vbm9yZGVyLFEpCiAgICAgICAgIHRpbWUudG8uYXJyaXZlPXQrc2FtcGxlKGMoNCw1KSwxLHByb2I9YygwLjUsMC41KSkrMQogICAgICAgICBpbnYub25vcmRlci5zdGFtcD1jKGludi5vbm9yZGVyLnN0YW1wLHRpbWUudG8uYXJyaXZlKQogICAgICAgICBvcmRlclFbdF09UQogICAgICAgfQogICAgICAgI1VwZGF0ZSBpbnZlbnRvcnkgb24taGFuZCBpbiB0aGUgZW5kIG9mIHRoZSBkYXkKICAgICAgIGludi5vbmhhbmRbdCsxXT1pbnYub25oYW5kW3RdLXNhbGVzW3RdCiAgICAgfSAjZW5kIHQ+MQogICAgICNjYXQoImRheToiLHQsIjtzYWxlczoiLHNhbGVzW3RdLCI7b25oYW5kOiIsaW52Lm9uaGFuZFt0XSwiO29ub3JkZXI6IiwKICAgICAjICAgICBpbnYub25vcmRlciwiO29yZGVyOiIsb3JkZXJRW3RdLCJcbiIpIAogIH0gI2VuZCBmb3IgdAogIAogIFNMW21dPShUX3ZhbHVlLXN0b2Nrb3V0KS9UX3ZhbHVlICAjQ2FsY3VsYXRlIHRoZSBzZXJ2aWNlIHJhdGU7IAogICAgCiAgI0NhbGN1bGF0ZSB0aGUgYXZlcmFnZSBkYWlseSBwcm9maXQKICBkYWlseS5wcm9maXRbbV09KHVuaXQucHJvZml0KnN1bShzYWxlcyktc3VtKGgudmFsKmludi5vbmhhbmQpLQogICAgICAgICAgICAgICAgICAgc2hpcHBpbmcuY29zdCpkZWxpdmVyeS11bml0LnByb2ZpdCpsb3NzKS9UX3ZhbHVlCiAgI1NpbXVsYXRpb24gcHJvZ3Jlc3MgbWFya2VyCiAgaWYobSUlMTAwPT0wKXtjYXQoIlJlcGV0aXRpb25zOiIsbSwiXG4iKX0gCgp9ICNlbmQgZm9yIG0KCmVuZC50aW1lIDwtIFN5cy50aW1lKCkKdGltZS50YWtlbiA8LSBlbmQudGltZSAtIHN0YXJ0LnRpbWUKdGltZS50YWtlbgoKCnN1bW1hcnkoZGFpbHkucHJvZml0KQpzdW1tYXJ5KFNMKQpgYGAKCgpgYGB7cn0KIyNTZWFyY2ggZm9yIG9wdGltYWwgKFIqLCBRKikKUj1zZXEoMCw2MCw1KQpRPXNlcSg5MCwzNjAsMTApCgpzZWFyY2gudmFsPWFzLm1hdHJpeChleHBhbmQuZ3JpZChSLFEpKQpkaW0oc2VhcmNoLnZhbCkKCiNUaGUgKHIsIHEpIG1vZGVsIGFzIGEgZnVuY3Rpb24gZm9yIHNpbXVsYXRpb24KSW52TW9kZWw9ZnVuY3Rpb24oaSl7CiAgcj1zZWFyY2gudmFsW2ksMV0KICBxPXNlYXJjaC52YWxbaSwyXQogICNWZWN0b3IgaW5pdGlhbGl6YXRpb24KICBTTD1yZXAoTkEsTSkKICBkYWlseS5wcm9maXQ9cmVwKE5BLE0pCiAgZm9yKG0gaW4gMTpNKXsKICAgICNJbml0aWFsaXphdGlvbjogU2V0IGludmVudG9yeSBvbi1oYW5kPXEgaW4gZGF5IDAKICAgIGludi5vbmhhbmQ9YyhxLHJlcChOQSxUX3ZhbHVlLTEpKQogICAgc2FsZXM9cmVwKE5BLFRfdmFsdWUpCiAgICBvcmRlclE9cmVwKDAsVF92YWx1ZSkKICAgICNLZWVwIHRyYWNrIG9mIGludmVudG9yeSBvbi1vcmRlciBidXQgbm90IGFycml2ZWQgeWV0CiAgICBpbnYub25vcmRlcj1jKCkKICAgIGludi5vbm9yZGVyLnN0YW1wPWMoKQogICAgI1RoZSBudW1iZXIgb2YgZGVsaXZlcmllcyBmcm9tIHRoZSBzdXBwbGllcgogICAgZGVsaXZlcnk9MAogICAgI1RoZSB0b3RhbCBhbW91bnQgb2YgbG9zdCBzYWxlcyAKICAgIGxvc3M9MAogICAgI1RoZSBudW1iZXIgb2Ygc3RvY2tvdXRzIGluIGEgcmVwZXRpdGlvbgogICAgc3RvY2tvdXQ9MAogICAgI1NpbXVsYXRlIE5vcm1hbCBkZW1hbmQgZm9yIFQgcGVyaW9kcwogICAgZD1ybm9ybShUX3ZhbHVlLCBtZWFuID0gMTIsIHNkID0gMikKICAgICMKICAgIGZvcih0IGluIDE6VF92YWx1ZSl7CiAgICAgIGlmKHQ9PTEpewogICAgICAgICNTZWxsaW5nIHByb2Nlc3MKICAgICAgICBzYWxlc1t0XT1taW4oaW52Lm9uaGFuZFt0XSxkW3RdKQogICAgICAgICNDaGVjayBzdG9ja291dAogICAgICAgIGlmKGRbdF0+c2FsZXNbdF0pewogICAgICAgICAgc3RvY2tvdXQ9c3RvY2tvdXQrMQogICAgICAgICAgbG9zcz1sb3NzKyhkW3RdLXNhbGVzW3RdKQogICAgICAgIH0KICAgICAgICAjQ29tcHV0ZSBpbnZlbnRvcnkgcG9zaXRpb24KICAgICAgICBpbnYucG9zaXRpb249aW52Lm9uaGFuZFsxXQogICAgICAgICNPcmRlcmluZyBtZWNoYW5pc20gb2YgKHIsIHEpCiAgICAgICAgaWYoaW52LnBvc2l0aW9uPD1yKXsKICAgICAgICAgICNDb21wdXRlIG9yZGVyIHF1YW50aXR5CiAgICAgICAgICBRPXEtaW52LnBvc2l0aW9uCiAgICAgICAgICAjVXBkYXRlIGludmVudG9yeSBvbi1vcmRlcgogICAgICAgICAgaW52Lm9ub3JkZXI9YyhpbnYub25vcmRlcixRKQogICAgICAgICAgI1NpbXVsYXRlIHN0b2NoYXN0aWMgbGVhZCB0aW1lCiAgICAgICAgICB0aW1lLnRvLmFycml2ZT10K3NhbXBsZShjKDQsNSksMSxwcm9iPWMoMC41LDAuNSkpKzEKICAgICAgICAgICNVcGRhdGUgdGltZSBzdGFtcCBmb3IgaW52ZW5vcnkgb24tb3JkZXIKICAgICAgICAgIGludi5vbm9yZGVyLnN0YW1wPWMoaW52Lm9ub3JkZXIuc3RhbXAsdGltZS50by5hcnJpdmUpCiAgICAgICAgICAjUmVjb3JkIG9yZGVyIHF1YW50aXR5CiAgICAgICAgICBvcmRlclFbdF09UQogICAgICAgIH0KICAgICAgICAjVXBkYXRlIGludmVudG9yeSBvbi1oYW5kIGluIHRoZSBlbmQgb2YgZWFjaCBkYXkKICAgICAgICBpbnYub25oYW5kW3QrMV09aW52Lm9uaGFuZFt0XS1zYWxlc1t0XQogICAgICB9CiAgICAgICMKICAgICAgaWYodD4xKXsKICAgICAgICAjQ2hlY2sgaWYgYW55IGludmVudG9yeSBvbi1vcmRlciBzaG91bGQgYXJyaXZlCiAgICAgICAgaWYoYW55KGludi5vbm9yZGVyLnN0YW1wPT10KSl7CiAgICAgICAgICAjVXBkYXRlIHRoZSBudW1iZXIgb2YgZGVsaXZlcmllcwogICAgICAgICAgZGVsaXZlcnk9ZGVsaXZlcnkrMQogICAgICAgICAgI0NvbXB1dGUgdGhlIHRvdGFsIG9mIGFycml2ZWQgaW52ZW50b3JpZXMKICAgICAgICAgIGluZGV4PXdoaWNoKGludi5vbm9yZGVyLnN0YW1wPT10KQogICAgICAgICAgYXJyaXZhbD1zdW0oaW52Lm9ub3JkZXJbaW5kZXhdKQogICAgICAgICAgI1VwZGF0ZSBpbnZlbnRvcnkgb24taGFuZCBiZWZvcmUgc3RhcnRpbmcgdGhlIGRheQogICAgICAgICAgaW52Lm9uaGFuZFt0XT1pbnYub25oYW5kW3RdK2Fycml2YWwKICAgICAgICAgICNSZW1vdmVkIHRob3NlIGp1c3QgYXJyaXZlZCBmcm9tIGludmVudG9yeSBvbi1vcmRlcgogICAgICAgICAgaW52Lm9ub3JkZXI9aW52Lm9ub3JkZXJbLWluZGV4XQogICAgICAgICAgaW52Lm9ub3JkZXIuc3RhbXA9aW52Lm9ub3JkZXIuc3RhbXBbLWluZGV4XQogICAgICAgICAgI2NhdCgiYXJyaXZhbCB0aW1lOiIsdCkKICAgICAgICB9ICNlbmQgdD09MQogICAgICAgICNSZWNvcmQgc2FsZXMKICAgICAgICBzYWxlc1t0XT1taW4oaW52Lm9uaGFuZFt0XSxkW3RdKQogICAgICAgICNDaGVjayBpZiBhbnkgc3RvY2tvdXQgdGFrZXMgcGxhY2UKICAgICAgICBpZihkW3RdPnNhbGVzW3RdKXsKICAgICAgICAgIHN0b2Nrb3V0PXN0b2Nrb3V0KzEKICAgICAgICAgIGxvc3M9bG9zcytkW3RdLXNhbGVzW3RdCiAgICAgICAgfQogICAgICAgICNVcGRhdGUgaW52ZW50b3J5IHBvc2l0aW9uCiAgICAgICAgaW52LnBvc2l0aW9uPWludi5vbmhhbmRbdF0rc3VtKGludi5vbm9yZGVyKQogICAgICAgICNPcmRlcmluZyBtZWNoYW5pc20gb2YgKHIsIHEpIGludmVudG9yeSBwb2xpY3kKICAgICAgICBpZihpbnYucG9zaXRpb248PXIpewogICAgICAgICAgUT1xLWludi5wb3NpdGlvbgogICAgICAgICAgaW52Lm9ub3JkZXI9YyhpbnYub25vcmRlcixRKQogICAgICAgICAgdGltZS50by5hcnJpdmU9dCtzYW1wbGUoYyg0LDUpLDEscHJvYj1jKDAuNSwwLjUpKSsxCiAgICAgICAgICBpbnYub25vcmRlci5zdGFtcD1jKGludi5vbm9yZGVyLnN0YW1wLHRpbWUudG8uYXJyaXZlKQogICAgICAgICAgb3JkZXJRW3RdPVEKICAgICAgICB9CiAgICAgICAgI1VwZGF0ZSBpbnZlbnRvcnkgb24taGFuZCBpbiB0aGUgZW5kIG9mIHRoZSBkYXkKICAgICAgICBpbnYub25oYW5kW3QrMV09aW52Lm9uaGFuZFt0XS1zYWxlc1t0XQogICAgICB9ICNlbmQgdD4xCiAgICAgICNjYXQoImRheToiLHQsIjtzYWxlczoiLHNhbGVzW3RdLCI7b25oYW5kOiIsaW52Lm9uaGFuZFt0XSwiO29ub3JkZXI6IiwKICAgICAgIyAgICAgaW52Lm9ub3JkZXIsIjtvcmRlcjoiLG9yZGVyUVt0XSwiXG4iKSAKICAgIH0gI2VuZCBmb3IgdAogICAgCiAgICBTTFttXT0oVF92YWx1ZS1zdG9ja291dCkvVF92YWx1ZSAgI0NhbGN1bGF0ZSB0aGUgc2VydmljZSByYXRlOyAKICAgIAogICAgI0NhbGN1bGF0ZSB0aGUgYXZlcmFnZSBkYWlseSBwcm9maXQKICAgIGRhaWx5LnByb2ZpdFttXT0odW5pdC5wcm9maXQqc3VtKHNhbGVzKS1zdW0oaC52YWwqaW52Lm9uaGFuZCktCiAgICAgICAgICAgICAgICAgICAgICAgc2hpcHBpbmcuY29zdCpkZWxpdmVyeS11bml0LnByb2ZpdCpsb3NzKS9UX3ZhbHVlCiAgICAKICB9ICNlbmQgZm9yIG0KICBjKG1lYW4oU0wpLG1lYW4oZGFpbHkucHJvZml0KSxzZChkYWlseS5wcm9maXQpKQp9CgoKSW52TW9kZWwoMSkKYGBgCgoKYGBge3J9CiMjVXNlIHBhcmFsbGVsIENQVSBjb21wdXRpbmcgZm9yIG9wdGltYWwgc2VhcmNoCmxpYnJhcnkoZm9yZWFjaCkKbGlicmFyeShkb1BhcmFsbGVsKQpyZWdpc3RlckRvUGFyYWxsZWwoY29yZXM9NikKZ2V0RG9QYXJXb3JrZXJzKCkKCnN0YXJ0LnRpbWUgPC0gU3lzLnRpbWUoKQpzaW0ucmVzdWx0cz1mb3JlYWNoKGk9MTpucm93KHNlYXJjaC52YWwpLAogICAgICAgICAgICAgLmNvbWJpbmU9cmJpbmQsLnZlcmJvc2U9RikgJWRvcGFyJSBJbnZNb2RlbChpKQplbmQudGltZSA8LSBTeXMudGltZSgpCnRpbWUudGFrZW4gPC0gZW5kLnRpbWUgLSBzdGFydC50aW1lCnRpbWUudGFrZW4KCgojVXNlIG5vbi1wYXJhbGxlbCBjb21wdXRpbmcgZm9yIG9wdGltYWwgc2VhcmNoCnN0YXJ0LnRpbWUgPC0gU3lzLnRpbWUoKQpzaW0ucmVzdWx0c0lJPW1hdHJpeChOQSxuY29sPTMsbnJvdz1ucm93KHNlYXJjaC52YWwpKQpmb3IoaSBpbiAxOm5yb3coc2VhcmNoLnZhbCkpewogICBzaW0ucmVzdWx0c0lJW2ksXT1JbnZNb2RlbChpKQp9CmVuZC50aW1lIDwtIFN5cy50aW1lKCkKdGltZS50YWtlbiA8LSBlbmQudGltZSAtIHN0YXJ0LnRpbWUKdGltZS50YWtlbgoKI3NpbS5yZXN1bHRzSUkKc3VtbWFyeShzaW0ucmVzdWx0c0lJWywxXSkKc3VtbWFyeShzaW0ucmVzdWx0c0lJWywyXSkKd2hpY2gubWF4KHNpbS5yZXN1bHRzSUlbLDJdKQpzZWFyY2gudmFsW3doaWNoLm1heChzaW0ucmVzdWx0c0lJWywyXSksXQpgYGAKCgpgYGB7cn0KIyNBcHBseSB0aGUgSG9va2UtSmVldmVzIHNlYXJjaCBhbGdvcml0aG0KSW52TW9kZWw9ZnVuY3Rpb24ocGFyKXsKICByPXBhclsxXQogIHE9cGFyWzJdCiAgI1ZlY3RvciBpbml0aWFsaXphdGlvbgogIFNMPXJlcChOQSxNKQogIGRhaWx5LnByb2ZpdD1yZXAoTkEsTSkKICBmb3IobSBpbiAxOk0pewogICAgI0luaXRpYWxpemF0aW9uOiBTZXQgaW52ZW50b3J5IG9uLWhhbmQ9cSBpbiBkYXkgMAogICAgaW52Lm9uaGFuZD1jKHEscmVwKE5BLFRfdmFsdWUtMSkpCiAgICBzYWxlcz1yZXAoTkEsVF92YWx1ZSkKICAgIG9yZGVyUT1yZXAoMCxUX3ZhbHVlKQogICAgI0tlZXAgdHJhY2sgb2YgaW52ZW50b3J5IG9uLW9yZGVyIGJ1dCBub3QgYXJyaXZlZCB5ZXQKICAgIGludi5vbm9yZGVyPWMoKQogICAgaW52Lm9ub3JkZXIuc3RhbXA9YygpCiAgICAjVGhlIG51bWJlciBvZiBkZWxpdmVyaWVzIGZyb20gdGhlIHN1cHBsaWVyCiAgICBkZWxpdmVyeT0wCiAgICAjVGhlIHRvdGFsIGFtb3VudCBvZiBsb3N0IHNhbGVzIAogICAgbG9zcz0wCiAgICAjVGhlIG51bWJlciBvZiBzdG9ja291dHMgaW4gYSByZXBldGl0aW9uCiAgICBzdG9ja291dD0wCiAgICAjU2ltdWxhdGUgTm9ybWFsIGRlbWFuZCBmb3IgVCBwZXJpb2RzCiAgICBkPXJub3JtKFRfdmFsdWUsIG1lYW4gPSAxMiwgc2QgPSAyKQogICAgIwogICAgZm9yKHQgaW4gMTpUX3ZhbHVlKXsKICAgICAgaWYodD09MSl7CiAgICAgICAgI1NlbGxpbmcgcHJvY2VzcwogICAgICAgIHNhbGVzW3RdPW1pbihpbnYub25oYW5kW3RdLGRbdF0pCiAgICAgICAgI0NoZWNrIHN0b2Nrb3V0CiAgICAgICAgaWYoZFt0XT5zYWxlc1t0XSl7CiAgICAgICAgICBzdG9ja291dD1zdG9ja291dCsxCiAgICAgICAgICBsb3NzPWxvc3MrKGRbdF0tc2FsZXNbdF0pCiAgICAgICAgfQogICAgICAgICNDb21wdXRlIGludmVudG9yeSBwb3NpdGlvbgogICAgICAgIGludi5wb3NpdGlvbj1pbnYub25oYW5kWzFdCiAgICAgICAgI09yZGVyaW5nIG1lY2hhbmlzbSBvZiAociwgcSkKICAgICAgICBpZihpbnYucG9zaXRpb248PXIpewogICAgICAgICAgI0NvbXB1dGUgb3JkZXIgcXVhbnRpdHkKICAgICAgICAgIFE9cS1pbnYucG9zaXRpb24KICAgICAgICAgICNVcGRhdGUgaW52ZW50b3J5IG9uLW9yZGVyCiAgICAgICAgICBpbnYub25vcmRlcj1jKGludi5vbm9yZGVyLFEpCiAgICAgICAgICAjU2ltdWxhdGUgc3RvY2hhc3RpYyBsZWFkIHRpbWUKICAgICAgICAgIHRpbWUudG8uYXJyaXZlPXQrc2FtcGxlKGMoNCw1KSwxLHByb2I9YygwLjUsMC41KSkrMQogICAgICAgICAgI1VwZGF0ZSB0aW1lIHN0YW1wIGZvciBpbnZlbm9yeSBvbi1vcmRlcgogICAgICAgICAgaW52Lm9ub3JkZXIuc3RhbXA9YyhpbnYub25vcmRlci5zdGFtcCx0aW1lLnRvLmFycml2ZSkKICAgICAgICAgICNSZWNvcmQgb3JkZXIgcXVhbnRpdHkKICAgICAgICAgIG9yZGVyUVt0XT1RCiAgICAgICAgfQogICAgICAgICNVcGRhdGUgaW52ZW50b3J5IG9uLWhhbmQgaW4gdGhlIGVuZCBvZiBlYWNoIGRheQogICAgICAgIGludi5vbmhhbmRbdCsxXT1pbnYub25oYW5kW3RdLXNhbGVzW3RdCiAgICAgIH0KICAgICAgIwogICAgICBpZih0PjEpewogICAgICAgICNDaGVjayBpZiBhbnkgaW52ZW50b3J5IG9uLW9yZGVyIHNob3VsZCBhcnJpdmUKICAgICAgICBpZihhbnkoaW52Lm9ub3JkZXIuc3RhbXA9PXQpKXsKICAgICAgICAgICNVcGRhdGUgdGhlIG51bWJlciBvZiBkZWxpdmVyaWVzCiAgICAgICAgICBkZWxpdmVyeT1kZWxpdmVyeSsxCiAgICAgICAgICAjQ29tcHV0ZSB0aGUgdG90YWwgb2YgYXJyaXZlZCBpbnZlbnRvcmllcwogICAgICAgICAgaW5kZXg9d2hpY2goaW52Lm9ub3JkZXIuc3RhbXA9PXQpCiAgICAgICAgICBhcnJpdmFsPXN1bShpbnYub25vcmRlcltpbmRleF0pCiAgICAgICAgICAjVXBkYXRlIGludmVudG9yeSBvbi1oYW5kIGJlZm9yZSBzdGFydGluZyB0aGUgZGF5CiAgICAgICAgICBpbnYub25oYW5kW3RdPWludi5vbmhhbmRbdF0rYXJyaXZhbAogICAgICAgICAgI1JlbW92ZWQgdGhvc2UganVzdCBhcnJpdmVkIGZyb20gaW52ZW50b3J5IG9uLW9yZGVyCiAgICAgICAgICBpbnYub25vcmRlcj1pbnYub25vcmRlclstaW5kZXhdCiAgICAgICAgICBpbnYub25vcmRlci5zdGFtcD1pbnYub25vcmRlci5zdGFtcFstaW5kZXhdCiAgICAgICAgICAjY2F0KCJhcnJpdmFsIHRpbWU6Iix0KQogICAgICAgIH0gI2VuZCB0PT0xCiAgICAgICAgI1JlY29yZCBzYWxlcwogICAgICAgIHNhbGVzW3RdPW1pbihpbnYub25oYW5kW3RdLGRbdF0pCiAgICAgICAgI0NoZWNrIGlmIGFueSBzdG9ja291dCB0YWtlcyBwbGFjZQogICAgICAgIGlmKGRbdF0+c2FsZXNbdF0pewogICAgICAgICAgc3RvY2tvdXQ9c3RvY2tvdXQrMQogICAgICAgICAgbG9zcz1sb3NzK2RbdF0tc2FsZXNbdF0KICAgICAgICB9CiAgICAgICAgI1VwZGF0ZSBpbnZlbnRvcnkgcG9zaXRpb24KICAgICAgICBpbnYucG9zaXRpb249aW52Lm9uaGFuZFt0XStzdW0oaW52Lm9ub3JkZXIpCiAgICAgICAgI09yZGVyaW5nIG1lY2hhbmlzbSBvZiAociwgcSkgaW52ZW50b3J5IHBvbGljeQogICAgICAgIGlmKGludi5wb3NpdGlvbjw9cil7CiAgICAgICAgICBRPXEtaW52LnBvc2l0aW9uCiAgICAgICAgICBpbnYub25vcmRlcj1jKGludi5vbm9yZGVyLFEpCiAgICAgICAgICB0aW1lLnRvLmFycml2ZT10K3NhbXBsZShjKDQsNSksMSxwcm9iPWMoMC41LDAuNSkpKzEKICAgICAgICAgIGludi5vbm9yZGVyLnN0YW1wPWMoaW52Lm9ub3JkZXIuc3RhbXAsdGltZS50by5hcnJpdmUpCiAgICAgICAgICBvcmRlclFbdF09UQogICAgICAgIH0KICAgICAgICAjVXBkYXRlIGludmVudG9yeSBvbi1oYW5kIGluIHRoZSBlbmQgb2YgdGhlIGRheQogICAgICAgIGludi5vbmhhbmRbdCsxXT1pbnYub25oYW5kW3RdLXNhbGVzW3RdCiAgICAgIH0gI2VuZCB0PjEKICAgICAgI2NhdCgiZGF5OiIsdCwiO3NhbGVzOiIsc2FsZXNbdF0sIjtvbmhhbmQ6IixpbnYub25oYW5kW3RdLCI7b25vcmRlcjoiLAogICAgICAjICAgICBpbnYub25vcmRlciwiO29yZGVyOiIsb3JkZXJRW3RdLCJcbiIpIAogICAgfSAjZW5kIGZvciB0CiAgICAKICAgIFNMW21dPShUX3ZhbHVlLXN0b2Nrb3V0KS9UX3ZhbHVlICAjQ2FsY3VsYXRlIHRoZSBzZXJ2aWNlIHJhdGU7IAogICAgCiAgICAjQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIGRhaWx5IHByb2ZpdAogICAgZGFpbHkucHJvZml0W21dPSh1bml0LnByb2ZpdCpzdW0oc2FsZXMpLXN1bShoLnZhbCppbnYub25oYW5kKS0KICAgICAgICAgICAgICAgICAgICAgICBzaGlwcGluZy5jb3N0KmRlbGl2ZXJ5LXVuaXQucHJvZml0Kmxvc3MpL1RfdmFsdWUKICAgIAogIH0gI2VuZCBmb3IgbQogICNjKG1lYW4oU0wpLG1lYW4oZGFpbHkucHJvZml0KSxzZChkYWlseS5wcm9maXQpKQogIG1lYW4oZGFpbHkucHJvZml0KQp9CgpgYGAKCgpgYGB7cn0KbGlicmFyeShwcmFjbWEpCnJlcz1mbWluc2VhcmNoKEludk1vZGVsLGMoMzAsMTMwKSwKICAgICAgICAgbG93ZXI9YygyMCw4MCksIAogICAgICAgICB1cHBlcj1jKDE1MCwyNTApLAogICAgICAgICBtZXRob2Q9YygiSG9va2UtSmVldmVzIiksCiAgICAgICAgIG1pbmltaXplPUZBTFNFKQoKcmVzCmBgYAo=