回頁首

前言:從交易記錄到顧客價值

善用商業數據分析的工具和技巧,光靠一份最簡單的交易紀錄(只有顧客ID、交易日期和交易金額三個欄位),我們就可以做一系列很深入、很有價值的顧客價值分析和行銷策略規劃,包括:

圖一、顧客價值管理的層次

圖一、顧客價值管理的層次


從這一些分析我們可以看到公司主要的營收和獲利的重要來源,我們也可以看到這一些產生獲利的群組是不是有成長或者衰退的趨勢;據此我們可以設定行銷的重點,決定行銷的策略,和規劃行銷的工具。除了上述的敘述統計、集群分析、和資料視覺化之外,我們還可以利用這些簡單的交易紀錄:


利用這一些預測我們就可以進行全面客製化的:

圖二、顧客價值管理流程

圖二、顧客價值管理流程



Setup
Sys.setlocale("LC_ALL","C")
packages = c(
  "dplyr","ggplot2","googleVis","devtools","magrittr","caTools","ROCR","caTools")
existing = as.character(installed.packages()[,1])
for(pkg in packages[!(packages %in% existing)]) install.packages(pkg)

if(!is.element("chorddiag", existing))
  devtools::install_github("mattflor/chorddiag")
Library
rm(list=ls(all=T))
options(digits=4, scipen=12)
library(dplyr)
library(ggplot2)
library(caTools)
library(ROCR)
library(googleVis)
library(chorddiag)


1 1. 資料整理

1.1 交易資料 (X)
X = read.table(
  'purchases.txt', header=FALSE, sep='\t', stringsAsFactors=F)
names(X) = c('cid','amount','date')
X$date = as.Date(X$date) 
X
summary(X)                  # 交易次數 51243
      cid             amount          date           
 Min.   :    10   Min.   :   5   Min.   :2005-01-02  
 1st Qu.: 57720   1st Qu.:  25   1st Qu.:2009-01-17  
 Median :102440   Median :  30   Median :2011-11-23  
 Mean   :108935   Mean   :  62   Mean   :2011-07-14  
 3rd Qu.:160525   3rd Qu.:  60   3rd Qu.:2013-12-29  
 Max.   :264200   Max.   :4500   Max.   :2015-12-31  
par(cex=0.8)
hist(X$date, "years", las=2, freq=T, xlab="", main="No. Transaction by Year")

小組討論1.1

拿到交易紀錄首先我們可以畫hist來看Frequency隨時間的變化,要看Frequency用hist非常有用

n_distinct(X$cid)           # 顧客數 18417
[1] 18417
# n_distinct 看後面這個vector有多少不同的值,現在X$cid是customer id ,代表有18417個顧客。
1.2 顧客資料 (A)
A = X %>% 
  mutate(days = as.integer(as.Date("2016-01-01") - date)) %>% #用mutate長一個新欄位,叫做days
  group_by(cid) %>% summarise(
    recent = min(days),     # 最近購買距今天數
    freq = n(),             # 購買次數
    money = mean(amount),   # 平均購買金額
    senior = max(days),     # 第一次購買距今天數
    since = min(date)       # 第一次購買日期
  ) %>% data.frame
小組討論1.2
  • 光從交易紀錄我們就可以整理出r、m、f、s等四個有預測力的變數
  • 可以預測顧客在下一期是否會來購買,購買金額會是多少
1.4 顧客資料摘要
summary(A)
      cid             recent          freq           money     
 Min.   :    10   Min.   :   1   Min.   : 1.00   Min.   :   5  
 1st Qu.: 81990   1st Qu.: 244   1st Qu.: 1.00   1st Qu.:  22  
 Median :136430   Median :1070   Median : 2.00   Median :  30  
 Mean   :137574   Mean   :1253   Mean   : 2.78   Mean   :  58  
 3rd Qu.:195100   3rd Qu.:2130   3rd Qu.: 3.00   3rd Qu.:  50  
 Max.   :264200   Max.   :4014   Max.   :45.00   Max.   :4500  
     senior         since           
 Min.   :   1   Min.   :2005-01-02  
 1st Qu.: 988   1st Qu.:2007-10-23  
 Median :2087   Median :2010-04-15  
 Mean   :1984   Mean   :2010-07-26  
 3rd Qu.:2992   3rd Qu.:2013-04-18  
 Max.   :4016   Max.   :2015-12-31  
1.5 變數的分布狀況
p0 = par(cex=0.8, mfrow=c(2,2), mar=c(3,3,4,2))
hist(A$recent,20,main="recency",ylab="",xlab="")
hist(pmin(A$freq, 10),0:10,main="frequency",ylab="",xlab="")
hist(A$senior,20,main="seniority",ylab="",xlab="")
hist(log(A$money,10),,main="log(money)",ylab="",xlab="")

#將money取log,方便看出趨勢。


小組討論1.5
  • 從recency的hist圖可以看出最近還有來購買的顧客比較多,比較久沒來的顧客比較少
    • 可以用累積顧客點數的策略讓顧客增加購買力

2. 層級式集群分析

2.1 RFM顧客分群
set.seed(111)
A$grp = kmeans(scale(A[,2:4]),10)$cluster
table(A$grp)  # 族群大小

   1    2    3    4    5    6    7    8    9   10 
1073 2266 1296 2237 3207 1942 1781 2392 2096  127 
2.2 顧客群組屬性
group_by(A, grp) %>% summarise(
  recent=mean(recent), 
  freq=mean(freq), 
  money=mean(money), 
  size=n() ) %>% 
  mutate( revenue = size*money/1000 )  %>% 
  filter(size > 1) %>% 
  ggplot(aes(x=freq, y=money)) +
  geom_point(aes(size=revenue, col=recent),alpha=0.5) +
  scale_size(range=c(4,30)) +
  scale_color_gradient(low="green",high="red") +
  scale_x_log10() + scale_y_log10(limits=c(30,3000)) + 
  geom_text(aes(label = size ),size=3) +
  theme_bw() + guides(size=F) +
  labs(title="Customer Segements",
       subtitle="(bubble_size:revenue_contribution; text:group_size)",
       color="Recency") +
  xlab("Frequency (log)") + ylab("Average Transaction Amount (log)")

#每個泡泡都是一群,從泡泡的大小、顏色、x軸與y軸可以看出各群的特性。
#泡泡大小代表營收貢獻,綜合其他特點看起,可以知道營收來自哪個族群,藉此針對不同族群,實行不同行銷策略。


3. 規則分群

3.1 顧客分群規則
STS = c("N1","N2","R1","R2","S1","S2","S3")
Status = function(rx,fx,mx,sx,K) {factor(
  ifelse(sx < 2*K,
         ifelse(fx*mx > 50, "N2", "N1"),
         ifelse(rx < 2*K,
                ifelse(sx/fx < 0.75*K,"R2","R1"),
                ifelse(rx < 3*K,"S1",
                       ifelse(rx < 4*K,"S2","S3")))), STS)}

圖三、顧客分群規則

3.2 平均購買週期
K = as.integer(sum(A$senior[A$freq>1]) / sum(A$freq[A$freq>1])); K
[1] 521

回購顧客的平均購買週期 K = 521 days

3.3 滑動資料窗格
Y = list()              # 建立一個空的LIST
for(y in 2010:2015) {   # 每年年底將顧客資料彙整成一個資料框
  D = as.Date(paste0(c(y, y-1),"-12-31")) # 當期、前期的期末日期 
  Y[[paste0("Y",y)]] = X %>%        # 從交易資料做起
    filter(date <= D[1]) %>%        # 將資料切齊到期末日期
    mutate(days = 1 + as.integer(D[1] - date)) %>%   # 交易距期末天數
    group_by(cid) %>% summarise(    # 依顧客彙總 ...
      recent = min(days),           #   最後一次購買距期末天數   
      freq = n(),                   #   購買次數 (至期末為止)   
      money = mean(amount),         #   平均購買金額 (至期末為止)
      senior = max(days),           #   第一次購買距期末天數
      status = Status(recent,freq,money,senior,K),  # 期末狀態
      since = min(date),                      # 第一次購買日期
      y_freq = sum(date > D[2]),              # 當期購買次數
      y_revenue = sum(amount[date > D[2]])    # 當期購買金額
    ) %>% data.frame }
head(Y$Y2015)
3.4 每年年底的累計顧客人數
sapply(Y, nrow)
Y2010 Y2011 Y2012 Y2013 Y2014 Y2015 
10407 11674 13562 15468 16905 18417 
3.5 族群大小變化趨勢
cols = c("gold","orange","blue","green","pink","magenta","darkred")
sapply(Y, function(df) table(df$status)) %>% barplot(col=cols)
legend("topleft",rev(STS),fill=rev(cols))

3.6 族群屬性動態分析
CustSegments = do.call(rbind, lapply(Y, function(d) {
  group_by(d, status) %>% summarise(
    average_frequency = mean(freq),
    average_amount = mean(money),
    total_revenue = sum(y_revenue),
    total_no_orders = sum(y_freq),
    average_recency = mean(recent),
    average_seniority = mean(senior),
    group_size = n()
  )})) %>% ungroup %>% 
  mutate(year=rep(2010:2015, each=7)) %>% data.frame
head(CustSegments)
plot( gvisMotionChart(
  CustSegments, "status", "year",
  options=list(width=900, height=600) ) )

圖四、顧客分群規則

3.7 族群屬性動態分析
df = merge(Y$Y2014[,c(1,6)], Y$Y2015[,c(1,6)],
           by="cid", all.x=T)
tx = table(df$status.x, df$status.y) %>% 
  as.data.frame.matrix() %>% as.matrix()
tx    # 流量矩陣
     N1   N2   R1   R2  S1   S2   S3
N1 1705  381  144   45 831    0    0
N2    0 1131  267  430 263    0    0
R1    0    0 1240   43 819    0    0
R2    0    0  199 1742  75    0    0
S1    0    0  115    3 819 1026    0
S2    0    0   78    1   0  692 1339
S3    0    0   97    0   0    0 3420
tx %>% prop.table(1) %>% round(3)   # 流量矩陣(%)
      N1    N2    R1    R2    S1    S2    S3
N1 0.549 0.123 0.046 0.014 0.268 0.000 0.000
N2 0.000 0.541 0.128 0.206 0.126 0.000 0.000
R1 0.000 0.000 0.590 0.020 0.390 0.000 0.000
R2 0.000 0.000 0.099 0.864 0.037 0.000 0.000
S1 0.000 0.000 0.059 0.002 0.417 0.523 0.000
S2 0.000 0.000 0.037 0.000 0.000 0.328 0.635
S3 0.000 0.000 0.028 0.000 0.000 0.000 0.972
3.8 互動式流量分析
chorddiag(tx, groupColors=cols)


小組討論3.8
  • 首先用rmfs為顧客分群,建立S1、S2、S3、N1、N2、R1、R2等顧客status
  • 做出流量分析看出顧客在2014年到2015年間status的流動情形,例如R1流到S1有819人

4. 建立模型

在這個案例裡面,我們的資料是收到Y2015年底,所以我們可以假設現在的時間是Y2015年底,我們想要用現有的資料建立模型,來預測每一位顧客:

但是,我們並沒有Y2016的資料,為了要建立模型,我們需要先把時間回推一期,也就是說:

假如Y2016的情況(跟Y2015比)沒有太大的變化的話,接下來我們就可以

4.1 準備資料

我們用Y2014年底的資料做自變數,Y2015年的資料做應變數

CX = left_join(Y$Y2014, Y$Y2015[,c(1,8,9)], by="cid")
head(CX)
names(CX)[8:11] = c("freq0","revenue0","Retain", "Revenue")
CX$Retain = CX$Retain > 0
head(CX)
table(CX$Retain) %>% prop.table()  # 平均保留機率 = 22.54%

 FALSE   TRUE 
0.7701 0.2299 
4.2 建立類別模型
mRet = glm(Retain ~ ., CX[,c(2:3,6,8:10)], family=binomial())
summary(mRet)

Call:
glm(formula = Retain ~ ., family = binomial(), data = CX[, c(2:3, 
    6, 8:10)])

Deviance Residuals: 
   Min      1Q  Median      3Q     Max  
-3.689  -0.473  -0.298  -0.142   3.386  

Coefficients:
             Estimate Std. Error z value        Pr(>|z|)    
(Intercept) -1.074007   0.089431  -12.01         < 2e-16 ***
recent      -0.002067   0.000131  -15.73         < 2e-16 ***
freq         0.095217   0.013882    6.86 0.0000000000069 ***
statusN2     0.669429   0.070234    9.53         < 2e-16 ***
statusR1     0.488321   0.084389    5.79 0.0000000071864 ***
statusR2     1.290002   0.110841   11.64         < 2e-16 ***
statusS1     0.670604   0.146532    4.58 0.0000047279944 ***
statusS2     1.353554   0.208210    6.50 0.0000000000798 ***
statusS3     2.573689   0.275786    9.33         < 2e-16 ***
freq0        0.566557   0.065532    8.65         < 2e-16 ***
revenue0    -0.000132   0.000135   -0.98            0.33    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 18228  on 16904  degrees of freedom
Residual deviance: 11766  on 16894  degrees of freedom
AIC: 11788

Number of Fisher Scoring iterations: 6
4.3 估計類別模型的準確性
pred = predict(mRet,type="response")
table(pred>0.5,CX$Retain) 
       
        FALSE  TRUE
  FALSE 12045  1530
  TRUE    974  2356
# 混淆矩陣 (Confusion Matrix)  
table(pred>0.5,CX$Retain) %>% 
  {sum(diag(.))/sum(.)}            # 正確率(ACC): 85.19% 
[1] 0.8519
colAUC(pred,CX$Retain)             # 辯識率(AUC): 87.92%
                 [,1]
FALSE vs. TRUE 0.8792
prediction(pred, CX$Retain) %>%    # ROC CURVE 
  performance("tpr", "fpr") %>% 
  plot(print.cutoffs.at=seq(0,1,0.1))

4.4 建立數量模型
dx = subset(CX, Revenue > 0)  # 只對有來購買的人做模型
mRev = lm(log(Revenue) ~ recent + freq + log(1+money) + senior +
          status + freq0 + log(1+revenue0), dx)  
summary(mRev)                 # 判定係數:R2 = 0.713

Call:
lm(formula = log(Revenue) ~ recent + freq + log(1 + money) + 
    senior + status + freq0 + log(1 + revenue0), data = dx)

Residuals:
   Min     1Q Median     3Q    Max 
-3.245 -0.209 -0.067  0.205  3.435 

Coefficients:
                    Estimate Std. Error t value         Pr(>|t|)    
(Intercept)        0.0587930  0.0458344    1.28           0.1997    
recent             0.0003541  0.0000507    6.98 0.00000000000337 ***
freq               0.0526850  0.0046504   11.33          < 2e-16 ***
log(1 + money)     0.9320818  0.0135203   68.94          < 2e-16 ***
senior            -0.0001369  0.0000182   -7.52 0.00000000000007 ***
statusN2           0.0127716  0.0262656    0.49           0.6268    
statusR1           0.1927532  0.0407579    4.73 0.00000233405019 ***
statusR2           0.0297685  0.0352479    0.84           0.3984    
statusS1           0.0082406  0.0630355    0.13           0.8960    
statusS2          -0.2406398  0.0865731   -2.78           0.0055 ** 
statusS3          -0.3667341  0.1181061   -3.11           0.0019 ** 
freq0              0.0103133  0.0172551    0.60           0.5501    
log(1 + revenue0)  0.0632756  0.0094003    6.73 0.00000000001930 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 0.463 on 3873 degrees of freedom
Multiple R-squared:  0.713, Adjusted R-squared:  0.712 
F-statistic:  802 on 12 and 3873 DF,  p-value: <2e-16
plot(log(dx$Revenue), predict(mRev), col='pink', cex=0.65)
abline(0,1,col='red') 



5. 估計顧客終生價值

5.1 Y2016的預測值

使用模型對Y2015年底的資料做預測,對資料中的每一位顧客,預測她們在Y2016的保留率和購買金額。

CX = Y$Y2015
names(CX)[8:9] = c("freq0","revenue0")
# 預測Y2016保留率
CX$ProbRetain = predict(mRet,CX,type='response')
# 預測Y2016購買金額
CX$PredRevenue = exp(predict(mRev,CX))
par(mfrow=c(1,2), mar=c(4,3,3,2), cex=0.8)
hist(CX$ProbRetain,main="ProbRetain", ylab="")
hist(log(CX$PredRevenue,10),main="log(PredRevenue)", ylab="")


5.2 估計顧客終生價值(CLV)
顧客\(i\)的終生價值

\[ V_i = \sum_{t=0}^N g \times m_i \frac{r_i^t}{(1+d)^t} = g \times m_i \sum_{t=0}^N (\frac{r_i}{1+d})^t \]

\(m_i\)\(r_i\):顧客\(i\)的預期(每期)營收貢獻、保留機率
\(g\)\(d\):公司的(稅前)營業利潤利率、資金成本
g = 0.5   # (稅前)獲利率
N = 5     # 期數 = 5
d = 0.1   # 利率 = 10%
CX$CLV = g * CX$PredRevenue * rowSums(sapply(
  0:N, function(i) (CX$ProbRetain/(1+d))^i ) )
summary(CX$CLV)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
      3      16      24      51      45    5094 
par(mar=c(2,2,3,1), cex=0.8)
hist(log(CX$CLV,10), xlab="", ylab="")

5.3 比較各族群的價值
# 各族群的平均營收貢獻、保留機率、終生價值
sapply(CX[,10:12], tapply, CX$status, mean)
   ProbRetain PredRevenue    CLV
N1    0.20269       31.98  20.17
N2    0.44075      131.23 110.89
R1    0.34150       69.85  54.60
R2    0.74925       91.27 136.31
S1    0.05724       56.10  29.66
S2    0.03475       49.48  25.58
S3    0.02326       49.36  25.17
par(mar=c(3,3,4,2), cex=0.8)
boxplot(log(CLV)~status, CX, main="CLV by Groups")



6. 設定行銷策略、規劃行銷工具



7. 選擇行銷對象

給定某一行銷工具的成本和預期效益,選擇可以施行這項工具的對象。

7.1 對R2族群進行保留

R2族群的預測保留率和購買金額

par(mfrow=c(1,2), mar=c(4,3,3,2), cex=0.8)
hist(CX$ProbRetain[CX$status=="R2"],main="ProbRetain",xlab="")
hist(log(CX$PredRevenue[CX$status=="R2"],10),main="PredRevenue",xlab="")

7.2 估計預期報酬

假設行銷工具的成本和預期效益為

cost = 10        # 成本
effect = 0.75    # 效益:下一期的購買機率

估計這項行銷工具對每一位R2顧客的預期報酬

Target = subset(CX, status=="R2")
Target$ExpReturn = (effect - Target$ProbRetain) * Target$PredRevenue - cost
summary(Target$ExpReturn)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 -515.8   -15.4   -11.5   -10.3    -8.1   646.9 

這一項工具對R2顧客的預期報酬是負的

7.3 選擇行銷對象

但是,我們還是可以挑出許多預期報酬很大的行銷對象

Target %>% arrange(desc(ExpReturn)) %>% select(cid, ExpReturn) %>% head(15)
sum(Target$ExpReturn > 0)                 # 可實施對象:258
[1] 258

在R2之中,有258人的預期報酬大於零,如果對這258人使用這項工具,我們的期望報酬是:

sum(Target$ExpReturn[Target$ExpReturn > 0])   # 預期報酬:6464
[1] 6464
QUIZ:

我們可以算出對所有的族群實施這項工具的期望報酬 …

Target = CX
Target$ExpReturn = (effect - Target$ProbRetain) * Target$PredRevenue - cost
filter(Target, Target$ExpReturn > 0) %>%
  group_by(status) %>% summarise(
    No.Target = n(),
    AvgROI = mean(ExpReturn),
    TotalROI = sum(ExpReturn) ) %>% data.frame

這個結果是合理的嗎? 你想要怎麼修正這項分析的程序呢?

  • 不合理。前面的假設是以最為忠誠的R2這個族群,去設計行銷工具,本應該針對各個族群的特性,去予以適合的行銷工具,但這裡卻用的是R2的行銷工具,而因為R2族群是忠誠顧客,下次會再來購買的機率,理應高於其他族群,而用同樣的機率套用到其他族群,會使得ROI結果出現不合理的情形。所以不同族群之間,行銷效果也應該有所不同,不能全部用0.75去計算。
  • 我們可以分析不同族群,用適合的行銷工具去分析,不可以用R2的行銷工序



8. 結論

如果你只有顧客ID、交易日期、交易金額三個欄位的話,你可以做的分析包括:

一般而言,這一些分析的結果,足夠讓我們制定顧客發展和顧客保留策略;至於顧客吸收策略,我們通常還需要從CRM撈出顧客個人屬性資料才能做到。







DQotLS0NCnRpdGxlOiAiQ1ZN77ya6aGn5a6i5YO55YC8566h55CGICINCmF1dGhvcjogPGVtPuesrOS4gOe1hC3lionogrLpipjjgIHnjovmt6/kvbPjgIHpu4Pmn4/ono3jgIHkvZnmm5zlu7fjgIHmnpfkv57kvLbjgIHpmbPmraPorIA8L2VtPg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KPGJyPg0KPGRpdiBpZD0iaG9tZSIgY2xhc3M9InNpZGVuYXYiPg0KKyA8YSBocmVmPSIjMS4xIj4xLjHlsI/ntYToqI7oq5Y8L2E+DQoNCisgPGEgaHJlZj0iIzEuMiI+MS4y5bCP57WE6KiO6KuWPC9hPg0KDQorIDxhIGhyZWY9IiMxLjUiPjEuNeWwj+e1hOiojuirljwvYT4NCg0KKyA8YSBocmVmPSIjMy44Ij4zLjjlsI/ntYToqI7oq5Y8L2E+DQo8L2Rpdj4NCg0KDQo8ZGl2IGlkPSJteVNpZGVuYXYiIGNsYXNzPSJzaWRlbmF2Ij4NCjxwPjxhIGhyZWY9IiNob21lIiBpZD0iYWJvdXQiPuWbnumggemmljwvYT4gDQo8L2Rpdj4NCg0KDQojIyMg5YmN6KiA77ya5b6e5Lqk5piT6KiY6YyE5Yiw6aGn5a6i5YO55YC8DQoNCuWWhOeUqOWVhualreaVuOaTmuWIhuaekOeahOW3peWFt+WSjOaKgOW3p++8jOWFiemdoOS4gOS7veacgOewoeWWrueahOS6pOaYk+e0gOmMhCjlj6rmnInpoaflrqJJROOAgeS6pOaYk+aXpeacn+WSjOS6pOaYk+mHkemhjeS4ieWAi+ashOS9jSnvvIzmiJHlgJHlsLHlj6/ku6XlgZrkuIDns7vliJflvojmt7HlhaXjgIHlvojmnInlg7nlgLznmoTpoaflrqLlg7nlgLzliIbmnpDlkozooYzpirfnrZbnlaXopo/lioPvvIzljIXmi6zvvJoNCg0KKyAqKuS6pOaYk+iomOmMhOWIhuaekCoq77yaDQogICAgKyDmlZjov7DntbHoqIgNCiAgICArIOi2qOWLouOAgeS6pOWPieWIhuaekA0KICAgICsg6LOH5paZ6KaW6Ka65YyWDQoNCisgKirpoaflrqLnvqTntYToiIfmqJnnsaQqKu+8mg0KICAgICsg6ZuG576k5YiG5p6QDQogICAgKyDnvqTntYTlsazmgKfliIbmnpANCiAgICArIOe1hOmWk+a1geWLleapn+eOhw0KICAgICsg6aGn5a6iKOWAi+S6uinmtYHli5XmqZ/njocNCg0KDQo8Y2VudGVyPg0KDQohW+WcluS4gOOAgemhp+WuouWDueWAvOeuoeeQhueahOWxpOasoV0oZmlnL2ZpZzEucG5nKQ0KDQo8L2NlbnRlcj4NCg0KPGJyPuW+numAmeS4gOS6m+WIhuaekOaIkeWAkeWPr+S7peeci+WIsOWFrOWPuOS4u+imgeeahOeHn+aUtuWSjOeNsuWIqeeahOmHjeimgeS+hua6kO+8jOaIkeWAkeS5n+WPr+S7peeci+WIsOmAmeS4gOS6m+eUoueUn+eNsuWIqeeahOe+pOe1hOaYr+S4jeaYr+acieaIkOmVt+aIluiAheihsOmAgOeahOi2qOWLou+8m+aTmuatpOaIkeWAkeWPr+S7peioreWumuihjOmKt+eahOmHjem7nu+8jOaxuuWumuihjOmKt+eahOetlueVpe+8jOWSjOimj+WKg+ihjOmKt+eahOW3peWFt+OAgumZpOS6huS4iui/sOeahOaVmOi/sOe1seioiOOAgembhue+pOWIhuaekOOAgeWSjOizh+aWmeimluimuuWMluS5i+Wklu+8jOaIkeWAkemChOWPr+S7peWIqeeUqOmAmeS6m+ewoeWWrueahOS6pOaYk+e0gOmMhO+8mg0KDQorICoq5bu656uL6aCQ5ris5oCn5qih5Z6LKirvvIzpoJDmuKzmr4/kuIDkvY3poaflrqLnmoTvvJoNCiAgICArIOS/neeVmeapn+eOhw0KICAgICsg6aCQ5pyf54ef5pS2DQogICAgKyDntYTplpPorormj5vmqZ/njocNCiAgICArIOS4i+asoeWPr+iDveizvOiyt+aZgumWkw0KDQo8YnI+5Yip55So6YCZ5LiA5Lqb6aCQ5ris5oiR5YCR5bCx5Y+v5Lul6YCy6KGM5YWo6Z2i5a6i6KO95YyW55qE77yaIA0KDQorICoq6aGn5a6i5YO55YC8566h55CGKirvvJoNCiAgICArIOmhp+Wuoue1gueUn+WDueWAvA0KICAgICsg6aGn5a6i5ZC45pS2562W55WlDQogICAgKyDpoaflrqLnmbzlsZXnrZbnlaUNCiAgICArIOmhp+WuouS/neeVmeetlueVpQ0KDQorICoq6Yed5bCN5oCn6KGM6Yq3KirvvJoNCiAgICArIOioreioiOihjOmKt+aWueahiA0KICAgICsg6YG45pOH6KGM6Yq35pa55qGIDQogICAgKyDpgbjmk4fooYzpirflsI3osaENCg0KDQo8Y2VudGVyPg0KDQohW+WcluS6jOOAgemhp+WuouWDueWAvOeuoeeQhua1geeoi10oZmlnL2ZpZzIucG5nKQ0KDQo8L2NlbnRlcj4NCg0KDQoNCjxicj48aHI+DQoNCiMjIyMjIFNldHVwIA0KYGBge3J9DQpTeXMuc2V0bG9jYWxlKCJMQ19BTEwiLCJDIikNCnBhY2thZ2VzID0gYygNCiAgImRwbHlyIiwiZ2dwbG90MiIsImdvb2dsZVZpcyIsImRldnRvb2xzIiwibWFncml0dHIiLCJjYVRvb2xzIiwiUk9DUiIsImNhVG9vbHMiKQ0KZXhpc3RpbmcgPSBhcy5jaGFyYWN0ZXIoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdKQ0KZm9yKHBrZyBpbiBwYWNrYWdlc1shKHBhY2thZ2VzICVpbiUgZXhpc3RpbmcpXSkgaW5zdGFsbC5wYWNrYWdlcyhwa2cpDQoNCmlmKCFpcy5lbGVtZW50KCJjaG9yZGRpYWciLCBleGlzdGluZykpDQogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigibWF0dGZsb3IvY2hvcmRkaWFnIikNCmBgYA0KDQojIyMjIyBMaWJyYXJ5DQpgYGB7ciBlY2hvPVQsIG1lc3NhZ2U9RiwgY2FjaGU9Riwgd2FybmluZz1GfQ0Kcm0obGlzdD1scyhhbGw9VCkpDQpvcHRpb25zKGRpZ2l0cz00LCBzY2lwZW49MTIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShjYVRvb2xzKQ0KbGlicmFyeShST0NSKQ0KbGlicmFyeShnb29nbGVWaXMpDQpsaWJyYXJ5KGNob3JkZGlhZykNCmBgYA0KPGJyPjxocj4NCg0KIyMjIDEgMS4g6LOH5paZ5pW055CGDQoNCiMjIyMjIDEuMSDkuqTmmJPos4fmlpkgKFgpDQpgYGB7cn0NCiPmr4/nrYZjaWTmmK/kuI3lkIzkuqTmmJPntIDpjIQNClggPSByZWFkLnRhYmxlKA0KICAncHVyY2hhc2VzLnR4dCcsIGhlYWRlcj1GQUxTRSwgc2VwPSdcdCcsIHN0cmluZ3NBc0ZhY3RvcnM9RikNCm5hbWVzKFgpID0gYygnY2lkJywnYW1vdW50JywnZGF0ZScpDQpYJGRhdGUgPSBhcy5EYXRlKFgkZGF0ZSkgDQpYDQpzdW1tYXJ5KFgpICAgICAgICAgICAgICAgICAgIyDkuqTmmJPmrKHmlbggNTEyNDMNCg0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTcuMn0NCnBhcihjZXg9MC44KQ0KaGlzdChYJGRhdGUsICJ5ZWFycyIsIGxhcz0yLCBmcmVxPVQsIHhsYWI9IiIsIG1haW49Ik5vLiBUcmFuc2FjdGlvbiBieSBZZWFyIikNCmBgYA0KIyMjIyMjIDxzcGFuIGlkPScxLjEnPuWwj+e1hOiojuirljEuMTwvc3Bhbj4NCuaLv+WIsOS6pOaYk+e0gOmMhOmmluWFiOaIkeWAkeWPr+S7peeVq2hpc3TkvobnnItGcmVxdWVuY3npmqjmmYLplpPnmoTororljJbvvIzopoHnnItGcmVxdWVuY3nnlKhoaXN06Z2e5bi45pyJ55SoDQoNCmBgYHtyfQ0Kbl9kaXN0aW5jdChYJGNpZCkgICAgICAgICAgICMg6aGn5a6i5pW4IDE4NDE3DQojIG5fZGlzdGluY3Qg55yL5b6M6Z2i6YCZ5YCLdmVjdG9y5pyJ5aSa5bCR5LiN5ZCM55qE5YC877yM54++5ZyoWCRjaWTmmK9jdXN0b21lciBpZCDvvIzku6PooajmnIkxODQxN+WAi+mhp+WuouOAgg0KYGBgDQoNCiMjIyMjIDEuMiDpoaflrqLos4fmlpkgKEEpDQpgYGB7cn0NCkEgPSBYICU+JSANCiAgbXV0YXRlKGRheXMgPSBhcy5pbnRlZ2VyKGFzLkRhdGUoIjIwMTYtMDEtMDEiKSAtIGRhdGUpKSAlPiUgI+eUqG11dGF0ZemVt+S4gOWAi+aWsOashOS9je+8jOWPq+WBmmRheXMNCiAgZ3JvdXBfYnkoY2lkKSAlPiUgc3VtbWFyaXNlKA0KICAgIHJlY2VudCA9IG1pbihkYXlzKSwgICAgICMg5pyA6L+R6LO86LK36Led5LuK5aSp5pW4DQogICAgZnJlcSA9IG4oKSwgICAgICAgICAgICAgIyDos7zosrfmrKHmlbgNCiAgICBtb25leSA9IG1lYW4oYW1vdW50KSwgICAjIOW5s+Wdh+izvOiyt+mHkemhjQ0KICAgIHNlbmlvciA9IG1heChkYXlzKSwgICAgICMg56ys5LiA5qyh6LO86LK36Led5LuK5aSp5pW4DQogICAgc2luY2UgPSBtaW4oZGF0ZSkgICAgICAgIyDnrKzkuIDmrKHos7zosrfml6XmnJ8NCiAgKSAlPiUgZGF0YS5mcmFtZQ0KDQpgYGANCg0KIyMjIyMjIDxzcGFuIGlkPScxLjInPuWwj+e1hOiojuirljEuMjwvc3Bhbj4NCisg5YWJ5b6e5Lqk5piT57SA6YyE5oiR5YCR5bCx5Y+v5Lul5pW055CG5Ye6cuOAgW3jgIFm44CBc+etieWbm+WAi+aciemgkOa4rOWKm+eahOiuiuaVuA0KKyDlj6/ku6XpoJDmuKzpoaflrqLlnKjkuIvkuIDmnJ/mmK/lkKbmnIPkvobos7zosrfvvIzos7zosrfph5HpoY3mnIPmmK/lpJrlsJENCg0KIyMjIyMgMS40IOmhp+Wuouizh+aWmeaRmOimgQ0KYGBge3J9DQpzdW1tYXJ5KEEpDQpgYGANCg0KIyMjIyMgMS41IOiuiuaVuOeahOWIhuW4g+eLgOazgQ0KYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9OH0NCnAwID0gcGFyKGNleD0wLjgsIG1mcm93PWMoMiwyKSwgbWFyPWMoMywzLDQsMikpDQpoaXN0KEEkcmVjZW50LDIwLG1haW49InJlY2VuY3kiLHlsYWI9IiIseGxhYj0iIikNCmhpc3QocG1pbihBJGZyZXEsIDEwKSwwOjEwLG1haW49ImZyZXF1ZW5jeSIseWxhYj0iIix4bGFiPSIiKQ0KaGlzdChBJHNlbmlvciwyMCxtYWluPSJzZW5pb3JpdHkiLHlsYWI9IiIseGxhYj0iIikNCmhpc3QobG9nKEEkbW9uZXksMTApLG1haW49ImxvZyhtb25leSkiLHlsYWI9IiIseGxhYj0iIikNCiPlsIdtb25leeWPlmxvZ++8jOaWueS+v+eci+WHuui2qOWLouOAgg0KYGBgDQo8YnI+PGhyPg0KDQojIyMjIyMgPHNwYW4gaWQ9JzEuMSc+5bCP57WE6KiO6KuWMS41PC9zcGFuPg0KKyDlvp5yZWNlbmN555qEaGlzdOWcluWPr+S7peeci+WHuuacgOi/kemChOacieS+huizvOiyt+eahOmhp+WuouavlOi8g+Wkmu+8jOavlOi8g+S5heaykuS+hueahOmhp+WuouavlOi8g+WwkQ0KICAgICsg5Y+v5Lul55So57Sv56mN6aGn5a6i6bue5pW455qE562W55Wl6K6T6aGn5a6i5aKe5Yqg6LO86LK35YqbDQoNCg0KIyMjIDIuIOWxpOe0muW8j+mbhue+pOWIhuaekA0KDQojIyMjIyAyLjEgUkZN6aGn5a6i5YiG576kDQpgYGB7cn0NCnNldC5zZWVkKDExMSkNCkEkZ3JwID0ga21lYW5zKHNjYWxlKEFbLDI6NF0pLDEwKSRjbHVzdGVyDQp0YWJsZShBJGdycCkgICMg5peP576k5aSn5bCPDQpgYGANCg0KIyMjIyMgMi4yIOmhp+Wuoue+pOe1hOWxrOaApw0KYGBge3IgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD04fQ0KZ3JvdXBfYnkoQSwgZ3JwKSAlPiUgc3VtbWFyaXNlKA0KICByZWNlbnQ9bWVhbihyZWNlbnQpLCANCiAgZnJlcT1tZWFuKGZyZXEpLCANCiAgbW9uZXk9bWVhbihtb25leSksIA0KICBzaXplPW4oKSApICU+JSANCiAgbXV0YXRlKCByZXZlbnVlID0gc2l6ZSptb25leS8xMDAwICkgICU+JSANCiAgZmlsdGVyKHNpemUgPiAxKSAlPiUgDQogIGdncGxvdChhZXMoeD1mcmVxLCB5PW1vbmV5KSkgKw0KICBnZW9tX3BvaW50KGFlcyhzaXplPXJldmVudWUsIGNvbD1yZWNlbnQpLGFscGhhPTAuNSkgKw0KICBzY2FsZV9zaXplKHJhbmdlPWMoNCwzMCkpICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93PSJncmVlbiIsaGlnaD0icmVkIikgKw0KICBzY2FsZV94X2xvZzEwKCkgKyBzY2FsZV95X2xvZzEwKGxpbWl0cz1jKDMwLDMwMDApKSArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc2l6ZSApLHNpemU9MykgKw0KICB0aGVtZV9idygpICsgZ3VpZGVzKHNpemU9RikgKw0KICBsYWJzKHRpdGxlPSJDdXN0b21lciBTZWdlbWVudHMiLA0KICAgICAgIHN1YnRpdGxlPSIoYnViYmxlX3NpemU6cmV2ZW51ZV9jb250cmlidXRpb247IHRleHQ6Z3JvdXBfc2l6ZSkiLA0KICAgICAgIGNvbG9yPSJSZWNlbmN5IikgKw0KICB4bGFiKCJGcmVxdWVuY3kgKGxvZykiKSArIHlsYWIoIkF2ZXJhZ2UgVHJhbnNhY3Rpb24gQW1vdW50IChsb2cpIikNCg0KI+avj+WAi+azoeazoemDveaYr+S4gOe+pO+8jOW+nuazoeazoeeahOWkp+Wwj+OAgemhj+iJsuOAgXjou7joiId56Lu45Y+v5Lul55yL5Ye65ZCE576k55qE54m55oCn44CCDQoj5rOh5rOh5aSn5bCP5Luj6KGo54ef5pS26LKi542777yM57ac5ZCI5YW25LuW54m56bue55yL6LW377yM5Y+v5Lul55+l6YGT54ef5pS25L6G6Ieq5ZOq5YCL5peP576k77yM6JeJ5q2k6Yed5bCN5LiN5ZCM5peP576k77yM5a+m6KGM5LiN5ZCM6KGM6Yq3562W55Wl44CCDQpgYGANCjxicj48aHI+DQoNCiMjIyAzLiDopo/liYfliIbnvqQNCg0KIyMjIyMgMy4xIOmhp+WuouWIhue+pOimj+WJhw0KYGBge3J9DQpTVFMgPSBjKCJOMSIsIk4yIiwiUjEiLCJSMiIsIlMxIiwiUzIiLCJTMyIpDQpTdGF0dXMgPSBmdW5jdGlvbihyeCxmeCxteCxzeCxLKSB7ZmFjdG9yKA0KICBpZmVsc2Uoc3ggPCAyKkssDQogICAgICAgICBpZmVsc2UoZngqbXggPiA1MCwgIk4yIiwgIk4xIiksDQogICAgICAgICBpZmVsc2UocnggPCAyKkssDQogICAgICAgICAgICAgICAgaWZlbHNlKHN4L2Z4IDwgMC43NSpLLCJSMiIsIlIxIiksDQogICAgICAgICAgICAgICAgaWZlbHNlKHJ4IDwgMypLLCJTMSIsDQogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyeCA8IDQqSywiUzIiLCJTMyIpKSkpLCBTVFMpfQ0KYGBgDQoNCjxjZW50ZXI+DQoNCiFb5ZyW5LiJ44CB6aGn5a6i5YiG576k6KaP5YmHXShmaWcvZmlnMy5qZmlmKQ0KDQo8L2NlbnRlcj4NCg0KIyMjIyMgMy4yIOW5s+Wdh+izvOiyt+mAseacnw0KYGBge3J9DQpLID0gYXMuaW50ZWdlcihzdW0oQSRzZW5pb3JbQSRmcmVxPjFdKSAvIHN1bShBJGZyZXFbQSRmcmVxPjFdKSk7IEsNCmBgYA0K5Zue6LO86aGn5a6i55qE5bmz5Z2H6LO86LK36YCx5pyfIGBLID0gNTIxIGRheXNgDQoNCiMjIyMjIDMuMyDmu5Hli5Xos4fmlpnnqpfmoLwNCmBgYHtyfQ0KWSA9IGxpc3QoKSAgICAgICAgICAgICAgIyDlu7rnq4vkuIDlgIvnqbrnmoRMSVNUDQpmb3IoeSBpbiAyMDEwOjIwMTUpIHsgICAjIOavj+W5tOW5tOW6leWwh+mhp+Wuouizh+aWmeW9meaVtOaIkOS4gOWAi+izh+aWmeahhg0KICBEID0gYXMuRGF0ZShwYXN0ZTAoYyh5LCB5LTEpLCItMTItMzEiKSkgIyDnlbbmnJ/jgIHliY3mnJ/nmoTmnJ/mnKvml6XmnJ8gDQogIFlbW3Bhc3RlMCgiWSIseSldXSA9IFggJT4lICAgICAgICAjIOW+nuS6pOaYk+izh+aWmeWBmui1tw0KICAgIGZpbHRlcihkYXRlIDw9IERbMV0pICU+JSAgICAgICAgIyDlsIfos4fmlpnliIfpvYrliLDmnJ/mnKvml6XmnJ8NCiAgICBtdXRhdGUoZGF5cyA9IDEgKyBhcy5pbnRlZ2VyKERbMV0gLSBkYXRlKSkgJT4lICAgIyDkuqTmmJPot53mnJ/mnKvlpKnmlbgNCiAgICBncm91cF9ieShjaWQpICU+JSBzdW1tYXJpc2UoICAgICMg5L6d6aGn5a6i5b2Z57i9IC4uLg0KICAgICAgcmVjZW50ID0gbWluKGRheXMpLCAgICAgICAgICAgIyAgIOacgOW+jOS4gOasoeizvOiyt+i3neacn+acq+WkqeaVuCAgIA0KICAgICAgZnJlcSA9IG4oKSwgICAgICAgICAgICAgICAgICAgIyAgIOizvOiyt+asoeaVuCAo6Iez5pyf5pyr54K65q2iKSAgIA0KICAgICAgbW9uZXkgPSBtZWFuKGFtb3VudCksICAgICAgICAgIyAgIOW5s+Wdh+izvOiyt+mHkemhjSAo6Iez5pyf5pyr54K65q2iKQ0KICAgICAgc2VuaW9yID0gbWF4KGRheXMpLCAgICAgICAgICAgIyAgIOesrOS4gOasoeizvOiyt+i3neacn+acq+WkqeaVuA0KICAgICAgc3RhdHVzID0gU3RhdHVzKHJlY2VudCxmcmVxLG1vbmV5LHNlbmlvcixLKSwgICMg5pyf5pyr54uA5oWLDQogICAgICBzaW5jZSA9IG1pbihkYXRlKSwgICAgICAgICAgICAgICAgICAgICAgIyDnrKzkuIDmrKHos7zosrfml6XmnJ8NCiAgICAgIHlfZnJlcSA9IHN1bShkYXRlID4gRFsyXSksICAgICAgICAgICAgICAjIOeVtuacn+izvOiyt+asoeaVuA0KICAgICAgeV9yZXZlbnVlID0gc3VtKGFtb3VudFtkYXRlID4gRFsyXV0pICAgICMg55W25pyf6LO86LK36YeR6aGNDQogICAgKSAlPiUgZGF0YS5mcmFtZSB9DQpgYGANCg0KYGBge3J9DQpoZWFkKFkkWTIwMTUpDQpgYGANCg0KIyMjIyMgMy40IOavj+W5tOW5tOW6leeahOe0r+ioiOmhp+WuouS6uuaVuA0KYGBge3J9DQpzYXBwbHkoWSwgbnJvdykNCmBgYA0KDQojIyMjIyAzLjUg5peP576k5aSn5bCP6K6K5YyW6Lao5YuiDQpgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD04fQ0KY29scyA9IGMoImdvbGQiLCJvcmFuZ2UiLCJibHVlIiwiZ3JlZW4iLCJwaW5rIiwibWFnZW50YSIsImRhcmtyZWQiKQ0Kc2FwcGx5KFksIGZ1bmN0aW9uKGRmKSB0YWJsZShkZiRzdGF0dXMpKSAlPiUgYmFycGxvdChjb2w9Y29scykNCmxlZ2VuZCgidG9wbGVmdCIscmV2KFNUUyksZmlsbD1yZXYoY29scykpDQpgYGANCg0KIyMjIyMgMy42IOaXj+e+pOWxrOaAp+WLleaFi+WIhuaekA0KYGBge3J9DQpDdXN0U2VnbWVudHMgPSBkby5jYWxsKHJiaW5kLCBsYXBwbHkoWSwgZnVuY3Rpb24oZCkgew0KICBncm91cF9ieShkLCBzdGF0dXMpICU+JSBzdW1tYXJpc2UoDQogICAgYXZlcmFnZV9mcmVxdWVuY3kgPSBtZWFuKGZyZXEpLA0KICAgIGF2ZXJhZ2VfYW1vdW50ID0gbWVhbihtb25leSksDQogICAgdG90YWxfcmV2ZW51ZSA9IHN1bSh5X3JldmVudWUpLA0KICAgIHRvdGFsX25vX29yZGVycyA9IHN1bSh5X2ZyZXEpLA0KICAgIGF2ZXJhZ2VfcmVjZW5jeSA9IG1lYW4ocmVjZW50KSwNCiAgICBhdmVyYWdlX3Nlbmlvcml0eSA9IG1lYW4oc2VuaW9yKSwNCiAgICBncm91cF9zaXplID0gbigpDQogICl9KSkgJT4lIHVuZ3JvdXAgJT4lIA0KICBtdXRhdGUoeWVhcj1yZXAoMjAxMDoyMDE1LCBlYWNoPTcpKSAlPiUgZGF0YS5mcmFtZQ0KaGVhZChDdXN0U2VnbWVudHMpDQpgYGANCg0KYGBge3IgZXZhbD1GfQ0KcGxvdCggZ3Zpc01vdGlvbkNoYXJ0KA0KICBDdXN0U2VnbWVudHMsICJzdGF0dXMiLCAieWVhciIsDQogIG9wdGlvbnM9bGlzdCh3aWR0aD05MDAsIGhlaWdodD02MDApICkgKQ0KYGBgDQoNCjxjZW50ZXI+DQoNCiFb5ZyW5Zub44CB6aGn5a6i5YiG576k6KaP5YmHXShmaWcvZmlnNC5qZmlmKQ0KDQo8L2NlbnRlcj4NCg0KDQojIyMjIyAzLjcg5peP576k5bGs5oCn5YuV5oWL5YiG5p6QDQpgYGB7cn0NCmRmID0gbWVyZ2UoWSRZMjAxNFssYygxLDYpXSwgWSRZMjAxNVssYygxLDYpXSwNCiAgICAgICAgICAgYnk9ImNpZCIsIGFsbC54PVQpDQp0eCA9IHRhYmxlKGRmJHN0YXR1cy54LCBkZiRzdGF0dXMueSkgJT4lIA0KICBhcy5kYXRhLmZyYW1lLm1hdHJpeCgpICU+JSBhcy5tYXRyaXgoKQ0KdHggICAgIyDmtYHph4/nn6npmaMNCmBgYA0KDQpgYGB7cn0NCnR4ICU+JSBwcm9wLnRhYmxlKDEpICU+JSByb3VuZCgzKSAgICMg5rWB6YeP55+p6ZmjKCUpDQpgYGANCg0KIyMjIyMgMy44IOS6kuWLleW8j+a1gemHj+WIhuaekA0KYGBge3J9DQpjaG9yZGRpYWcodHgsIGdyb3VwQ29sb3JzPWNvbHMpDQpgYGANCg0KIVtdKGZpZy9jaG9yZC5qcGcpDQoNCjxicj48aHI+DQoNCg0KIyMjIyMjIDxzcGFuIGlkPScxLjEnPuWwj+e1hOiojuirljMuODwvc3Bhbj4NCisg6aaW5YWI55Socm1mc+eCuumhp+WuouWIhue+pO+8jOW7uueri1Mx44CBUzLjgIFTM+OAgU4x44CBTjLjgIFSMeOAgVIy562J6aGn5a6ic3RhdHVzDQorIOWBmuWHuua1gemHj+WIhuaekOeci+WHuumhp+WuouWcqDIwMTTlubTliLAyMDE15bm06ZaTc3RhdHVz55qE5rWB5YuV5oOF5b2i77yM5L6L5aaCUjHmtYHliLBTMeaciTgxOeS6ug0KDQojIyMgNC4g5bu656uL5qih5Z6LDQoNCuWcqOmAmeWAi+ahiOS+i+ijoemdou+8jOaIkeWAkeeahOizh+aWmeaYr+aUtuWIsFkyMDE15bm05bqV77yM5omA5Lul5oiR5YCR5Y+v5Lul5YGH6Kit54++5Zyo55qE5pmC6ZaT5pivWTIwMTXlubTlupXvvIzmiJHlgJHmg7PopoHnlKjnj77mnInnmoTos4fmlpnlu7rnq4vmqKHlnovvvIzkvobpoJDmuKzmr4/kuIDkvY3poaflrqLvvJoNCg0KKyDlnKhZMjAxNuW5tOaYr+WQpuacg+S+huizvOiytyAo5L+d55WZ546H77yaUmV0YWluKQ0KKyDlpbnkvobos7zosrfnmoToqbHvvIzmnIPosrflpJrlsJHpjKIgKOizvOiyt+mHkemhje+8mlJldmVudWUpDQoNCuS9huaYr++8jOaIkeWAkeS4puaykuaciVkyMDE255qE6LOH5paZ77yM54K65LqG6KaB5bu656uL5qih5Z6L77yM5oiR5YCR6ZyA6KaB5YWI5oqK5pmC6ZaT5Zue5o6o5LiA5pyf77yM5Lmf5bCx5piv6Kqq77yaDQoNCisg55SoWTIwMTTlubTlupXku6XliY3nmoTos4fmlpnmlbTnkIblh7rpoJDmuKzorormlbgoWCkgDQorIOeUqFkyMDE15bm055qE6LOH5paZ5pW055CG5Ye655uu5qiZ6K6K5pW4KFkpIA0KDQrlgYflpoJZMjAxNueahOaDheazgSjot59ZMjAxNeavlCnmspLmnInlpKrlpKfnmoTororljJbnmoToqbHvvIzmjqXkuIvkvobmiJHlgJHlsLHlj6/ku6UNCg0KKyDkvb/nlKjoqbLmqKHlnovvvIzku6VZMjAxNeW5tOW6leeahOizh+aWme+8jOmgkOa4rFkyMDE255qE54uA5rOBDQoNCiMjIyMjIDQuMSDmupblgpnos4fmlpkNCuaIkeWAkeeUqFkyMDE05bm05bqV55qE6LOH5paZ5YGa6Ieq6K6K5pW477yMWTIwMTXlubTnmoTos4fmlpnlgZrmh4norormlbgNCg0KYGBge3J9DQpDWCA9IGxlZnRfam9pbihZJFkyMDE0LCBZJFkyMDE1WyxjKDEsOCw5KV0sIGJ5PSJjaWQiKQ0KaGVhZChDWCkNCmBgYA0KDQpgYGB7cn0NCm5hbWVzKENYKVs4OjExXSA9IGMoImZyZXEwIiwicmV2ZW51ZTAiLCJSZXRhaW4iLCAiUmV2ZW51ZSIpDQpDWCRSZXRhaW4gPSBDWCRSZXRhaW4gPiAwDQpoZWFkKENYKQ0KYGBgDQoNCmBgYHtyfQ0KdGFibGUoQ1gkUmV0YWluKSAlPiUgcHJvcC50YWJsZSgpICAjIOW5s+Wdh+S/neeVmeapn+eOhyA9IDIyLjU0JQ0KYGBgDQoNCiMjIyMjIDQuMiDlu7rnq4vpoZ7liKXmqKHlnosNCmBgYHtyfQ0KbVJldCA9IGdsbShSZXRhaW4gfiAuLCBDWFssYygyOjMsNiw4OjEwKV0sIGZhbWlseT1iaW5vbWlhbCgpKQ0Kc3VtbWFyeShtUmV0KQ0KYGBgDQoNCiMjIyMjIDQuMyDkvLDoqIjpoZ7liKXmqKHlnovnmoTmupbnorrmgKcNCmBgYHtyfQ0KcHJlZCA9IHByZWRpY3QobVJldCx0eXBlPSJyZXNwb25zZSIpDQp0YWJsZShwcmVkPjAuNSxDWCRSZXRhaW4pIA0KIyDmt7fmt4bnn6npmaMgKENvbmZ1c2lvbiBNYXRyaXgpICANCmBgYA0KYGBge3J9DQp0YWJsZShwcmVkPjAuNSxDWCRSZXRhaW4pICU+JSANCiAge3N1bShkaWFnKC4pKS9zdW0oLil9ICAgICAgICAgICAgIyDmraPnorrnjocoQUNDKTogODUuMTklIA0KYGBgDQpgYGB7cn0NCmNvbEFVQyhwcmVkLENYJFJldGFpbikgICAgICAgICAgICAgIyDovq/orZjnjocoQVVDKTogODcuOTIlDQpgYGANCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTR9DQpwcmVkaWN0aW9uKHByZWQsIENYJFJldGFpbikgJT4lICAgICMgUk9DIENVUlZFIA0KICBwZXJmb3JtYW5jZSgidHByIiwgImZwciIpICU+JSANCiAgcGxvdChwcmludC5jdXRvZmZzLmF0PXNlcSgwLDEsMC4xKSkNCmBgYA0KDQojIyMjIyA0LjQg5bu656uL5pW46YeP5qih5Z6LDQpgYGB7cn0NCmR4ID0gc3Vic2V0KENYLCBSZXZlbnVlID4gMCkgICMg5Y+q5bCN5pyJ5L6G6LO86LK355qE5Lq65YGa5qih5Z6LDQptUmV2ID0gbG0obG9nKFJldmVudWUpIH4gcmVjZW50ICsgZnJlcSArIGxvZygxK21vbmV5KSArIHNlbmlvciArDQogICAgICAgICAgc3RhdHVzICsgZnJlcTAgKyBsb2coMStyZXZlbnVlMCksIGR4KSAgDQpzdW1tYXJ5KG1SZXYpICAgICAgICAgICAgICAgICAjIOWIpOWumuS/guaVuO+8mlIyID0gMC43MTMNCmBgYA0KYGBge3IgZmlnLmhlaWdodD00LjUsIGZpZy53aWR0aD00LjV9DQpwbG90KGxvZyhkeCRSZXZlbnVlKSwgcHJlZGljdChtUmV2KSwgY29sPSdwaW5rJywgY2V4PTAuNjUpDQphYmxpbmUoMCwxLGNvbD0ncmVkJykgDQpgYGANCjxicj48aHI+DQoNCiMjIyA1LiDkvLDoqIjpoaflrqLntYLnlJ/lg7nlgLwNCg0KIyMjIyMgNS4xIFkyMDE255qE6aCQ5ris5YC8DQrkvb/nlKjmqKHlnovlsI1ZMjAxNeW5tOW6leeahOizh+aWmeWBmumgkOa4rO+8jOWwjeizh+aWmeS4reeahOavj+S4gOS9jemhp+Wuou+8jOmgkOa4rOWlueWAkeWcqFkyMDE255qE5L+d55WZ546H5ZKM6LO86LK36YeR6aGN44CCDQpgYGB7cn0NCkNYID0gWSRZMjAxNQ0KbmFtZXMoQ1gpWzg6OV0gPSBjKCJmcmVxMCIsInJldmVudWUwIikNCg0KIyDpoJDmuKxZMjAxNuS/neeVmeeOhw0KQ1gkUHJvYlJldGFpbiA9IHByZWRpY3QobVJldCxDWCx0eXBlPSdyZXNwb25zZScpDQoNCiMg6aCQ5risWTIwMTbos7zosrfph5HpoY0NCkNYJFByZWRSZXZlbnVlID0gZXhwKHByZWRpY3QobVJldixDWCkpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD0yLjUsIGZpZy53aWR0aD04fQ0KcGFyKG1mcm93PWMoMSwyKSwgbWFyPWMoNCwzLDMsMiksIGNleD0wLjgpDQpoaXN0KENYJFByb2JSZXRhaW4sbWFpbj0iUHJvYlJldGFpbiIsIHlsYWI9IiIpDQpoaXN0KGxvZyhDWCRQcmVkUmV2ZW51ZSwxMCksbWFpbj0ibG9nKFByZWRSZXZlbnVlKSIsIHlsYWI9IiIpDQpgYGANCjxicj4NCg0KIyMjIyMgNS4yIOS8sOioiOmhp+Wuoue1gueUn+WDueWAvChDTFYpDQoNCjxjZW50ZXI+6aGn5a6iJGkk55qE57WC55Sf5YO55YC8PC9jZW50ZXI+DQoNCiQkIFZfaSA9IFxzdW1fe3Q9MH1eTiBnIFx0aW1lcyBtX2kgXGZyYWN7cl9pXnR9eygxK2QpXnR9ID0gZyBcdGltZXMgbV9pIFxzdW1fe3Q9MH1eTiAoXGZyYWN7cl9pfXsxK2R9KV50ICAkJA0KDQo8Y2VudGVyPiRtX2kk44CBJHJfaSTvvJrpoaflrqIkaSTnmoTpoJDmnJ8o5q+P5pyfKeeHn+aUtuiyoueNu+OAgeS/neeVmeapn+eOhzwvY2VudGVyPg0KDQo8Y2VudGVyPiRnJOOAgSRkJO+8muWFrOWPuOeahCjnqIXliY0p54ef5qWt5Yip5r2k5Yip546H44CB6LOH6YeR5oiQ5pysPC9jZW50ZXI+DQoNCmBgYHtyfQ0KZyA9IDAuNSAgICMgKOeoheWJjSnnjbLliKnnjocNCk4gPSA1ICAgICAjIOacn+aVuCA9IDUNCmQgPSAwLjEgICAjIOWIqeeOhyA9IDEwJQ0KQ1gkQ0xWID0gZyAqIENYJFByZWRSZXZlbnVlICogcm93U3VtcyhzYXBwbHkoDQogIDA6TiwgZnVuY3Rpb24oaSkgKENYJFByb2JSZXRhaW4vKDErZCkpXmkgKSApDQoNCnN1bW1hcnkoQ1gkQ0xWKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9Mi41LCBmaWcud2lkdGg9Ny4yfQ0KcGFyKG1hcj1jKDIsMiwzLDEpLCBjZXg9MC44KQ0KaGlzdChsb2coQ1gkQ0xWLDEwKSwgeGxhYj0iIiwgeWxhYj0iIikNCmBgYA0KDQojIyMjIyA1LjMg5q+U6LyD5ZCE5peP576k55qE5YO55YC8DQoNCmBgYHtyfQ0KIyDlkITml4/nvqTnmoTlubPlnYfnh5/mlLbosqLnjbvjgIHkv53nlZnmqZ/njofjgIHntYLnlJ/lg7nlgLwNCnNhcHBseShDWFssMTA6MTJdLCB0YXBwbHksIENYJHN0YXR1cywgbWVhbikNCmBgYA0KDQoNCmBgYHtyfQ0KcGFyKG1hcj1jKDMsMyw0LDIpLCBjZXg9MC44KQ0KYm94cGxvdChsb2coQ0xWKX5zdGF0dXMsIENYLCBtYWluPSJDTFYgYnkgR3JvdXBzIikNCg0KYGBgDQo8YnI+PGhyPg0KDQojIyMgNi4g6Kit5a6a6KGM6Yq3562W55Wl44CB6KaP5YqD6KGM6Yq35bel5YW3DQoNCjxicj48aHI+DQoNCiMjIyA3LiDpgbjmk4fooYzpirflsI3osaENCg0K57Wm5a6a5p+Q5LiA6KGM6Yq35bel5YW355qE5oiQ5pys5ZKM6aCQ5pyf5pWI55uK77yM6YG45pOH5Y+v5Lul5pa96KGM6YCZ6aCF5bel5YW355qE5bCN6LGh44CCIA0KDQojIyMjIyA3LjEg5bCNUjLml4/nvqTpgLLooYzkv53nlZkNClIy5peP576k55qE6aCQ5ris5L+d55WZ546H5ZKM6LO86LK36YeR6aGNDQpgYGB7ciBmaWcuaGVpZ2h0PTIuNSwgZmlnLndpZHRoPTh9DQpwYXIobWZyb3c9YygxLDIpLCBtYXI9Yyg0LDMsMywyKSwgY2V4PTAuOCkNCmhpc3QoQ1gkUHJvYlJldGFpbltDWCRzdGF0dXM9PSJSMiJdLG1haW49IlByb2JSZXRhaW4iLHhsYWI9IiIpDQpoaXN0KGxvZyhDWCRQcmVkUmV2ZW51ZVtDWCRzdGF0dXM9PSJSMiJdLDEwKSxtYWluPSJQcmVkUmV2ZW51ZSIseGxhYj0iIikNCmBgYA0KDQojIyMjIyA3LjIg5Lyw6KiI6aCQ5pyf5aCx6YWsDQrlgYfoqK3ooYzpirflt6XlhbfnmoTmiJDmnKzlkozpoJDmnJ/mlYjnm4rngroNCmBgYHtyfQ0KY29zdCA9IDEwICAgICAgICAjIOaIkOacrA0KZWZmZWN0ID0gMC43NSAgICAjIOaViOebiu+8muS4i+S4gOacn+eahOizvOiyt+apn+eOhw0KYGBgDQoNCuS8sOioiOmAmemgheihjOmKt+W3peWFt+Wwjeavj+S4gOS9jVIy6aGn5a6i55qE6aCQ5pyf5aCx6YWsDQpgYGB7cn0NClRhcmdldCA9IHN1YnNldChDWCwgc3RhdHVzPT0iUjIiKQ0KVGFyZ2V0JEV4cFJldHVybiA9IChlZmZlY3QgLSBUYXJnZXQkUHJvYlJldGFpbikgKiBUYXJnZXQkUHJlZFJldmVudWUgLSBjb3N0DQpzdW1tYXJ5KFRhcmdldCRFeHBSZXR1cm4pDQpgYGANCumAmeS4gOmgheW3peWFt+WwjVIy6aGn5a6i55qE6aCQ5pyf5aCx6YWs5piv6LKg55qEDQoNCiMjIyMjIDcuMyDpgbjmk4fooYzpirflsI3osaENCuS9huaYr++8jOaIkeWAkemChOaYr+WPr+S7peaMkeWHuuioseWkmumgkOacn+WgsemFrOW+iOWkp+eahOihjOmKt+WwjeixoQ0KYGBge3J9DQpUYXJnZXQgJT4lIGFycmFuZ2UoZGVzYyhFeHBSZXR1cm4pKSAlPiUgc2VsZWN0KGNpZCwgRXhwUmV0dXJuKSAlPiUgaGVhZCgxNSkNCmBgYA0KDQpgYGB7cn0NCnN1bShUYXJnZXQkRXhwUmV0dXJuID4gMCkgICAgICAgICAgICAgICAgICMg5Y+v5a+m5pa95bCN6LGh77yaMjU4DQpgYGANCuWcqFIy5LmL5Lit77yM5pyJMjU45Lq655qE6aCQ5pyf5aCx6YWs5aSn5pa86Zu277yM5aaC5p6c5bCN6YCZMjU45Lq65L2/55So6YCZ6aCF5bel5YW377yM5oiR5YCR55qE5pyf5pyb5aCx6YWs5piv77yaDQpgYGB7cn0NCnN1bShUYXJnZXQkRXhwUmV0dXJuW1RhcmdldCRFeHBSZXR1cm4gPiAwXSkgICAjIOmgkOacn+WgsemFrO+8mjY0NjQNCmBgYA0KDQojIyMjIyBRVUlaOg0K5oiR5YCR5Y+v5Lul566X5Ye65bCN5omA5pyJ55qE5peP576k5a+m5pa96YCZ6aCF5bel5YW355qE5pyf5pyb5aCx6YWsIC4uLg0KYGBge3J9DQpUYXJnZXQgPSBDWA0KVGFyZ2V0JEV4cFJldHVybiA9IChlZmZlY3QgLSBUYXJnZXQkUHJvYlJldGFpbikgKiBUYXJnZXQkUHJlZFJldmVudWUgLSBjb3N0DQpmaWx0ZXIoVGFyZ2V0LCBUYXJnZXQkRXhwUmV0dXJuID4gMCkgJT4lDQogIGdyb3VwX2J5KHN0YXR1cykgJT4lIHN1bW1hcmlzZSgNCiAgICBOby5UYXJnZXQgPSBuKCksDQogICAgQXZnUk9JID0gbWVhbihFeHBSZXR1cm4pLA0KICAgIFRvdGFsUk9JID0gc3VtKEV4cFJldHVybikgKSAlPiUgZGF0YS5mcmFtZQ0KYGBgDQrpgJnlgIvntZDmnpzmmK/lkIjnkIbnmoTll47vvJ8g5L2g5oOz6KaB5oCO6bq85L+u5q2j6YCZ6aCF5YiG5p6Q55qE56iL5bqP5ZGi77yfDQoNCisg5LiN5ZCI55CG44CC5YmN6Z2i55qE5YGH6Kit5piv5Lul5pyA54K65b+g6Kqg55qEUjLpgJnlgIvml4/nvqTvvIzljrvoqK3oqIjooYzpirflt6XlhbfvvIzmnKzmh4noqbLph53lsI3lkITlgIvml4/nvqTnmoTnibnmgKfvvIzljrvkuojku6XpganlkIjnmoTooYzpirflt6XlhbfvvIzkvYbpgJnoo6HljbvnlKjnmoTmmK9SMueahOihjOmKt+W3peWFt++8jOiAjOWboOeCulIy5peP576k5piv5b+g6Kqg6aGn5a6i77yM5LiL5qyh5pyD5YaN5L6G6LO86LK355qE5qmf546H77yM55CG5oeJ6auY5pa85YW25LuW5peP576k77yM6ICM55So5ZCM5qij55qE5qmf546H5aWX55So5Yiw5YW25LuW5peP576k77yM5pyD5L2/5b6XUk9J57WQ5p6c5Ye654++5LiN5ZCI55CG55qE5oOF5b2i44CC5omA5Lul5LiN5ZCM5peP576k5LmL6ZaT77yM6KGM6Yq35pWI5p6c5Lmf5oeJ6Kmy5pyJ5omA5LiN5ZCM77yM5LiN6IO95YWo6YOo55SoMC43NeWOu+ioiOeul+OAgg0KKyDmiJHlgJHlj6/ku6XliIbmnpDkuI3lkIzml4/nvqTvvIznlKjpganlkIjnmoTooYzpirflt6XlhbfljrvliIbmnpDvvIzkuI3lj6/ku6XnlKhSMueahOihjOmKt+W3peW6jw0KDQo8YnI+PGJyPjxocj4NCg0KIyMjIDguIOe1kOirlg0KDQrlpoLmnpzkvaDlj6rmnInpoaflrqJJROOAgeS6pOaYk+aXpeacn+OAgeS6pOaYk+mHkemhjeS4ieWAi+ashOS9jeeahOipse+8jOS9oOWPr+S7peWBmueahOWIhuaekOWMheaLrO+8mg0KDQorIOWFqOmrlOmhp+WuouWSjOavj+S4gOWAi+mhp+WuouWIhue+pOeahO+8mg0KICAgICsg5peP576k5aSn5bCP6IiH5oiQ6ZW36Lao5YuiDQogICAgKyDml4/nvqTlsazmgKfliIbmnpDvvJrlpoLlubPlnYdDTFbjgIHlubPlnYfnh5/mlLbosqLnjbvjgIHmiJDplbfnjofjgIHmr5vliKnnjoco6ZyA6KaB5pyJ5oiQ5pys6LOH5paZKeetieetiQ0KICAgICsg57WE6ZaT5rWB6YeP5ZKM5bmz5Z2H5rWB5YuV5qmf546HDQoNCisg5q+P5LiA5YCL6aGn5a6i55qE77yaDQogICAgKyDkv53nlZnnjofjgIHpoJDmnJ/os7zosrfph5HpoY3jgIHntYLouqvlg7nlgLwNCiAgICArIOebruWJjeaJgOWcqOe+pOe1hO+8jOS7peWPiuS4i+S4gOacn+acg+i9ieWIsOWAi+e+pOe1hOeahOapn+eOhw0KICAgICsg5aaC5p6c5pyJ6KGM6Yq35bel5YW355qE5L2/55So57SA6YyE55qE6Kmx77yM5oiR5YCR5Lmf5Y+v5Lul5Lyw6KiI5q+P5LiA5qij6KGM6Yq35bel5YW344CB5bCN5q+P5LiA5L2N6aGn5a6i55qE5oiQ5Yqf5qmf546HDQoNCuS4gOiIrOiAjOiogO+8jOmAmeS4gOS6m+WIhuaekOeahOe1kOaenO+8jOi2s+WkoOiuk+aIkeWAkeWItuWumumhp+WuoueZvOWxleWSjOmhp+WuouS/neeVmeetlueVpe+8m+iHs+aWvOmhp+WuouWQuOaUtuetlueVpe+8jOaIkeWAkemAmuW4uOmChOmcgOimgeW+nkNSTeaSiOWHuumhp+WuouWAi+S6uuWxrOaAp+izh+aWmeaJjeiDveWBmuWIsOOAgiANCg0KDQo8YnI+PGJyPjxocj48YnI+PGJyPjxicj4NCg0KPHN0eWxlPg0KLmNhcHRpb24gew0KICBjb2xvcjogIzc3NzsNCiAgbWFyZ2luLXRvcDogMTBweDsNCn0NCnAgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcHJlIHsNCiAgd29yZC1icmVhazogbm9ybWFsOw0KICB3b3JkLXdyYXA6IG5vcm1hbDsNCiAgbGluZS1oZWlnaHQ6IDE7DQp9DQpwcmUgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcCxsaSB7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQoucnsNCiAgbGluZS1oZWlnaHQ6IDEuMjsNCn0NCg0KdGl0bGV7DQogIGNvbG9yOiAjY2MwMDAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KYm9keXsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgxLGgyLGgzLGg0LGg1ew0KICBjb2xvcjogIzAwODgwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgzew0KICBjb2xvcjogIzAwODgwMDsNCiAgYmFja2dyb3VuZDogI2U2ZmZlNjsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpoNXsNCiAgY29sb3I6ICMwMDYwMDA7DQogIGJhY2tncm91bmQ6ICNmOGY4Zjg7DQogIGxpbmUtaGVpZ2h0OiAxLjU7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KaDYgew0KICAgIGNvbG9yOiAjMDA2MDAwOw0KICAgIGJhY2tncm91bmQ6ICMwMGZmZmY7DQogICAgbGluZS1oZWlnaHQ6IDI7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQplbXsNCiAgY29sb3I6ICMwMDAwYzA7DQogIGJhY2tncm91bmQ6ICNmMGYwZjA7DQogIH0NCiAgDQoNCiNteVNpZGVuYXYgew0KICAgIHRvcDogLTEwcHg7DQogICAgcG9zaXRpb246IGZpeGVkOw0KfSAgDQogIA0KI215U2lkZW5hdiBhIHsNCiAgICBwb3NpdGlvbjogYWJzb2x1dGU7DQogICAgbGVmdDogLTQwMHB4Ow0KICAgIHRyYW5zaXRpb246IDAuM3M7DQogICAgcGFkZGluZzogMTVweDsNCiAgICB3aWR0aDogMTUwcHg7DQogICAgdGV4dC1kZWNvcmF0aW9uOiBub25lOw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBjb2xvcjogd2hpdGU7DQogICAgYm9yZGVyLXJhZGl1czogMCA1cHggNXB4IDA7DQp9DQoNCg0KDQojYWJvdXQgew0KICAgIA0KICAgIGJhY2tncm91bmQtY29sb3I6ICNmNDQzMzY7DQp9DQoNCg0KDQo8L3N0eWxlPg0KDQo=