In this assignment, we will use a different data set with 10000 customers and 13 periods total. We estimate the model on the first 7 (calibration) and test it on the final 6 periods (holdout).  

cal.rf.matrix <- read.csv("cal.rf.matrix.csv")
trans <- read.csv("annual_transactions.csv")
holdout <- read.csv("holdout.trans.rf.matrix.csv")

Question 1

Create a graph of aggregate transactions per year. What are the total number of purchases in year 8 after the first purchase?

Provide your answer without any decimals (e.g. 12)

trans <- trans$x

par(mfrow=c(1,1))
par(mai=c(.8,.8,.2,.2))
plot(seq(1,13,1),trans, type="b", ylab="Total number of repeat transactions", xlab="Year since first purchase", main="", xaxt='n')
axis(1, at = seq(0, 13, by = 1))
abline(v=7.5,col = "red", lwd = 2)
text(x = 6,y = 4500,"Calibration", cex=1, pos=3, col="black", font = 2)
text(x = 9,y = 4500,"Validation", cex=1, pos=3, col="black", font = 2)

Question 2

Estimate the BG/BB parameters using the calibration data, the first seven years. What are the parameters?

Provide your answers with a dot and two decimals (e.g. 0.12)

Initial Parameters:

rf.matrix <- cal.rf.matrix
par.start <- c(1, 1, 1, 1)

MLE Estimation:

params <- bgbb.EstimateParameters(rf.matrix, par.start)
round(params, 2)
## [1] 1.32 0.67 0.51 2.09
## Check log-likelihood of the params:
LL <- bgbb.rf.matrix.LL(params, rf.matrix)
LL
## [1] -33013

Question 3

Graph out the distributions of the transaction rate and dropout rate. What are the average values of each in the population?

Provide your answer with a dot and two decimals (e.g. 0.12)

Average transaction rate:

round(params[1]/(params[1]+params[2]),2)
## [1] 0.66
bgbb.PlotTransactionRateHeterogeneity(params)

##   [1] 0.000 0.193 0.241 0.275 0.303 0.326 0.346 0.365 0.382 0.398 0.413 0.427 0.441 0.454 0.466 0.479 0.490 0.502 0.513 0.524 0.535 0.545 0.556 0.566 0.576 0.586 0.596 0.606 0.616 0.625 0.635 0.645 0.654 0.664 0.674 0.683 0.693 0.703 0.712 0.722 0.732 0.742 0.751 0.761 0.771 0.781 0.792 0.802 0.812
##  [50] 0.823 0.834 0.844 0.855 0.867 0.878 0.889 0.901 0.913 0.925 0.938 0.950 0.963 0.976 0.990 1.004 1.018 1.033 1.048 1.064 1.080 1.096 1.114 1.131 1.150 1.169 1.190 1.211 1.233 1.256 1.280 1.306 1.334 1.363 1.394 1.427 1.463 1.502 1.545 1.592 1.644 1.702 1.768 1.844 1.933 2.040 2.173 2.345 2.586
##  [99] 2.963 3.730   Inf

Average dropout rate:

round(params[3]/(params[3]+params[4]),2)
## [1] 0.2
bgbb.PlotDropoutRateHeterogeneity(params)

##   [1]     Inf 7.41359 5.23277 4.24797 3.65150 3.23854 2.92955 2.68628 2.48774 2.32130 2.17884 2.05487 1.94553 1.84800 1.76019 1.68047 1.60761 1.54060 1.47864 1.42107 1.36737 1.31707 1.26980 1.22525 1.18312 1.14320 1.10527 1.06915 1.03469 1.00176 0.97022 0.93998 0.91093 0.88299 0.85608 0.83014
##  [37] 0.80509 0.78088 0.75746 0.73478 0.71280 0.69148 0.67078 0.65067 0.63112 0.61209 0.59356 0.57552 0.55792 0.54076 0.52402 0.50767 0.49170 0.47609 0.46083 0.44590 0.43129 0.41699 0.40299 0.38927 0.37583 0.36265 0.34973 0.33706 0.32463 0.31243 0.30045 0.28870 0.27715 0.26581 0.25467 0.24373
##  [73] 0.23298 0.22241 0.21202 0.20181 0.19177 0.18190 0.17220 0.16266 0.15328 0.14405 0.13499 0.12607 0.11731 0.10870 0.10024 0.09193 0.08377 0.07576 0.06790 0.06019 0.05265 0.04527 0.03805 0.03102 0.02419 0.01758 0.01124 0.00524 0.00000

Question 4

Graph out the actual and predicted transactions per year. What is the expected level of transactions in year 8 after the first purchase?

Provide your answer with zero decimals (e.g. 12)

Aggregate Forecasting:

pred <- bgbb.PlotTrackingInc(params, rf.matrix, trans)

## Q4 = 2817

Question 5

According to the model, what is the predicted number of transactions in the holdout for a customer who was “7 for 7” in the calibration period?  What is the actual number of holdout transactions for these customers?

Provide your answer with a dot and two decimals (e.g. 0.12)

Predicted:

bgbb.HeatmapHoldoutExpectedTrans(params, n.cal = 7, n.star = 6)
## layout: widths =  0.05 4 , heights =  0.25 4 ; lmat=
##      [,1] [,2]
## [1,]    0    3
## [2,]    2    1

##        0      1      2     3     4     5    6    7
## 0 0.0575 0.0000 0.0000 0.000 0.000 0.000 0.00 0.00
## 1 0.0000 0.0589 0.2629 0.551 0.830 1.049 1.21 1.31
## 2 0.0000 0.0000 0.0701 0.394 0.913 1.383 1.70 1.88
## 3 0.0000 0.0000 0.0000 0.109 0.692 1.553 2.15 2.45
## 4 0.0000 0.0000 0.0000 0.000 0.235 1.401 2.53 3.01
## 5 0.0000 0.0000 0.0000 0.000 0.000 0.698 2.75 3.58
## 6 0.0000 0.0000 0.0000 0.000 0.000 0.000 2.36 4.15
## 7 0.0000 0.0000 0.0000 0.000 0.000 0.000 0.00 4.71

Actual:

cbind(cal.rf.matrix, holdout)
##    x t.x n.cal custs    x
## 1  0   0     7  2900  152
## 2  1   1     7   933   50
## 3  1   2     7   218   58
## 4  2   2     7   489   29
## 5  1   3     7    95   67
## 6  2   3     7   160   61
## 7  3   3     7   292   14
## 8  1   4     7    73   75
## 9  2   4     7   113  104
## 10 3   4     7   130   74
## 11 4   4     7   189   50
## 12 1   5     7    51   59
## 13 2   5     7    98  113
## 14 3   5     7   131  219
## 15 4   5     7   137  250
## 16 5   5     7   161  153
## 17 1   6     7    34   39
## 18 2   6     7    92  155
## 19 3   6     7   168  367
## 20 4   6     7   162  426
## 21 5   6     7   204  569
## 22 6   6     7   209  479
## 23 1   7     7    50   56
## 24 2   7     7   104  190
## 25 3   7     7   205  493
## 26 4   7     7   320  956
## 27 5   7     7   401 1492
## 28 6   7     7   666 2783
## 29 7   7     7  1215 5738
# take total transactions for last row divided by customers:

act <- holdout$x[29]/cal.rf.matrix[29,4] #ind=29 has 7 of 7, the last obs.
## Actual = 4.72

Question 6

What is the CLV, assuming each transaction yields on average 50 in profit and the discount rate is 0.1? You can use 200 periods for the sum.

Provide your answer with zero decimals (e.g. 12)

BGBBCLV<-function(params,m,d,T) {
params<-unname(params)
al<-params[1]
be<-params[2]
ga<-params[3]
de<-params[4]
DET<-1   # at time zero there has to be a purchase
for (i in 1:T) {
    DET<-DET+(al/(al+be))*(beta(ga,de+i)/beta(ga,de))*1/(1+d)^{i}
}
CLV=m*DET  # convert discount expected purchases into expected value
return(CLV)    #return the CLV
}

CLV:

CLV <- BGBBCLV(params = params, m=50,d=.1,T=200)
CLV
## [1] 203

Question 7

What is the RLV for a 7 for 7 customer? Again, assume each transaction yields on average 50 in profit, and the discount rate is 0.1.  

Provide your answer with zero decimals (e.g. 12)

m <- 50
DERT <- bgbb.rf.matrix.DERT(params, rf.matrix = cal.rf.matrix, d=0.1)
RLV <- m*DERT

RLVmatrix <- cbind(cal.rf.matrix,round(RLV)) 
RLVmatrix
##    x t.x n.cal custs round(RLV)
## 1  0   0     7  2900          4
## 2  1   1     7   933          4
## 3  1   2     7   218         18
## 4  2   2     7   489          5
## 5  1   3     7    95         39
## 6  2   3     7   160         28
## 7  3   3     7   292          8
## 8  1   4     7    73         58
## 9  2   4     7   113         64
## 10 3   4     7   130         49
## 11 4   4     7   189         16
## 12 1   5     7    51         74
## 13 2   5     7    98         97
## 14 3   5     7   131        109
## 15 4   5     7   137         98
## 16 5   5     7   161         49
## 17 1   6     7    34         85
## 18 2   6     7    92        119
## 19 3   6     7   168        151
## 20 4   6     7   162        178
## 21 5   6     7   204        193
## 22 6   6     7   209        166
## 23 1   7     7    50         92
## 24 2   7     7   104        132
## 25 3   7     7   205        172
## 26 4   7     7   320        212
## 27 5   7     7   401        251
## 28 6   7     7   666        291
## 29 7   7     7  1215        331

RLV:

max(RLV)
## [1] 331

Question 8

Consider a charity with just one opportunity for people to donate per year. Consider a donor has donated 3 times in the past five years with the last donation occurring in year 4. In the context of the BG/BB model, what are the donor’s sufficient statistics: n, t_x, and x

n=5
t_x = 4
x = 3

Assume that = 0.6 and Θ = 0.2.

What is the likelihood of this customer’s donations?

Provide your answer with a dot and three decimals (e.g. 0.123)

n <- 5
t_x <- 4
x <- 3

p <- 0.6
theta <- 0.2

\[ L(p,\theta|x, t_x,n)=p^x(1-p)^{n-x}(1-\theta)^n +\sum^{n-t_x-1}_{j=0}p^x(1-p)^{t_x-x+j}\theta(1-\theta)^{t_x+j} \]

a <- (p^3)*(1-p)*((1-theta)^4)*theta
b <- (p^3)*(1-p)^2*((1-theta)^5) ## the last obs. does not have theta

likelihood <- a+b
round(likelihood,3)
## [1] 0.018

Question 9

What is the probability that the customer is alive at the end?

Provide your answer with a dot and three decimals (e.g. 0.123)

\[ \Pr(\text{alive at }n|x,t_x,n)=\frac{p^x(1-p)^{n-x}(1-\theta)^n}{L(p,\theta|x,t_x,n)} \]

(p^3)*((1-p)^2)*((1-theta)^5)/likelihood
## [1] 0.615
LS0tDQp0aXRsZTogIlF1aXogNzogQ0xWIC0gTm9uLWNvbnRyYWN0dWFsIHNldHRpbmdzIg0KYXV0aG9yOiAiRGFuaWVsIFJlZGVsIg0KZGF0ZTogIjIwMjMtMDEtMjYiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCm9wdGlvbnMoInNjaXBlbiI9MTAwLCAiZGlnaXRzIj0zLCB3aWR0aCA9IDMwMCkNCnJtKGxpc3Q9bHMoKSkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KCJCVFlEIikNCmBgYA0KDQpJbiB0aGlzIGFzc2lnbm1lbnQsIHdlIHdpbGwgdXNlIGEgZGlmZmVyZW50IGRhdGEgc2V0IHdpdGggMTAwMDAgY3VzdG9tZXJzIGFuZCBbKjEzIHBlcmlvZHMgdG90YWwqXXsudW5kZXJsaW5lfS4gV2UgZXN0aW1hdGUgdGhlIG1vZGVsIG9uIHRoZSAqKmZpcnN0IDcgKGNhbGlicmF0aW9uKSoqIGFuZCB0ZXN0IGl0IG9uIHRoZSAqKmZpbmFsIDYgcGVyaW9kcyAoaG9sZG91dCkqKi4gwqANCg0KYGBge3J9DQpjYWwucmYubWF0cml4IDwtIHJlYWQuY3N2KCJjYWwucmYubWF0cml4LmNzdiIpDQp0cmFucyA8LSByZWFkLmNzdigiYW5udWFsX3RyYW5zYWN0aW9ucy5jc3YiKQ0KaG9sZG91dCA8LSByZWFkLmNzdigiaG9sZG91dC50cmFucy5yZi5tYXRyaXguY3N2IikNCmBgYA0KDQojIFF1ZXN0aW9uIDENCg0KQ3JlYXRlIGEgZ3JhcGggb2YgYWdncmVnYXRlIHRyYW5zYWN0aW9ucyBwZXIgeWVhci7CoCoqV2hhdCBhcmUgdGhlIHRvdGFsIG51bWJlciBvZiBwdXJjaGFzZXMgaW4geWVhciA4IGFmdGVyIHRoZSBmaXJzdCBwdXJjaGFzZT8qKg0KDQoqUHJvdmlkZSB5b3VyIGFuc3dlciB3aXRob3V0IGFueSBkZWNpbWFscyAoZS5nLiAxMikqDQoNCmBgYHtyfQ0KdHJhbnMgPC0gdHJhbnMkeA0KDQpwYXIobWZyb3c9YygxLDEpKQ0KcGFyKG1haT1jKC44LC44LC4yLC4yKSkNCnBsb3Qoc2VxKDEsMTMsMSksdHJhbnMsIHR5cGU9ImIiLCB5bGFiPSJUb3RhbCBudW1iZXIgb2YgcmVwZWF0IHRyYW5zYWN0aW9ucyIsIHhsYWI9IlllYXIgc2luY2UgZmlyc3QgcHVyY2hhc2UiLCBtYWluPSIiLCB4YXh0PSduJykNCmF4aXMoMSwgYXQgPSBzZXEoMCwgMTMsIGJ5ID0gMSkpDQphYmxpbmUodj03LjUsY29sID0gInJlZCIsIGx3ZCA9IDIpDQp0ZXh0KHggPSA2LHkgPSA0NTAwLCJDYWxpYnJhdGlvbiIsIGNleD0xLCBwb3M9MywgY29sPSJibGFjayIsIGZvbnQgPSAyKQ0KdGV4dCh4ID0gOSx5ID0gNDUwMCwiVmFsaWRhdGlvbiIsIGNleD0xLCBwb3M9MywgY29sPSJibGFjayIsIGZvbnQgPSAyKQ0KDQpgYGANCg0KIyBRdWVzdGlvbiAyDQoNCkVzdGltYXRlIHRoZSBCRy9CQiBwYXJhbWV0ZXJzIHVzaW5nIHRoZSBjYWxpYnJhdGlvbiBkYXRhLCB0aGUgZmlyc3Qgc2V2ZW4geWVhcnMuwqAqKldoYXQgYXJlIHRoZSBwYXJhbWV0ZXJzPyoqDQoNCipQcm92aWRlIHlvdXIgYW5zd2VycyB3aXRoIGEgZG90IGFuZCB0d28gZGVjaW1hbHMgKGUuZy4gMC4xMikqDQoNCioqSW5pdGlhbCBQYXJhbWV0ZXJzKio6DQoNCmBgYHtyfQ0KcmYubWF0cml4IDwtIGNhbC5yZi5tYXRyaXgNCnBhci5zdGFydCA8LSBjKDEsIDEsIDEsIDEpDQoNCmBgYA0KDQoqKk1MRSBFc3RpbWF0aW9uKio6DQoNCmBgYHtyfQ0KcGFyYW1zIDwtIGJnYmIuRXN0aW1hdGVQYXJhbWV0ZXJzKHJmLm1hdHJpeCwgcGFyLnN0YXJ0KQ0Kcm91bmQocGFyYW1zLCAyKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgQ2hlY2sgbG9nLWxpa2VsaWhvb2Qgb2YgdGhlIHBhcmFtczoNCkxMIDwtIGJnYmIucmYubWF0cml4LkxMKHBhcmFtcywgcmYubWF0cml4KQ0KTEwNCmBgYA0KDQojIFF1ZXN0aW9uIDMNCg0KR3JhcGggb3V0IHRoZSBkaXN0cmlidXRpb25zIG9mIHRoZSB0cmFuc2FjdGlvbiByYXRlIGFuZCBkcm9wb3V0IHJhdGUuwqAqKldoYXQgYXJlIHRoZSBhdmVyYWdlIHZhbHVlcyBvZiBlYWNoIGluIHRoZSBwb3B1bGF0aW9uPyoqDQoNCipQcm92aWRlIHlvdXIgYW5zd2VyIHdpdGggYSBkb3QgYW5kIHR3byBkZWNpbWFscyAoZS5nLiAwLjEyKSoNCg0KWyoqQXZlcmFnZSB0cmFuc2FjdGlvbiByYXRlKipdey51bmRlcmxpbmV9Og0KDQpgYGB7cn0NCnJvdW5kKHBhcmFtc1sxXS8ocGFyYW1zWzFdK3BhcmFtc1syXSksMikNCmJnYmIuUGxvdFRyYW5zYWN0aW9uUmF0ZUhldGVyb2dlbmVpdHkocGFyYW1zKQ0KYGBgDQoNClsqKkF2ZXJhZ2UgZHJvcG91dCByYXRlKipdey51bmRlcmxpbmV9Og0KDQpgYGB7cn0NCnJvdW5kKHBhcmFtc1szXS8ocGFyYW1zWzNdK3BhcmFtc1s0XSksMikNCmJnYmIuUGxvdERyb3BvdXRSYXRlSGV0ZXJvZ2VuZWl0eShwYXJhbXMpDQpgYGANCg0KIyBRdWVzdGlvbiA0DQoNCkdyYXBoIG91dCB0aGUgYWN0dWFsIGFuZCBwcmVkaWN0ZWQgdHJhbnNhY3Rpb25zIHBlciB5ZWFyLsKgKipXaGF0IGlzIHRoZSBleHBlY3RlZCBsZXZlbCBvZiB0cmFuc2FjdGlvbnMgaW4geWVhciA4IGFmdGVyIHRoZSBmaXJzdCBwdXJjaGFzZT8qKg0KDQoqUHJvdmlkZSB5b3VyIGFuc3dlciB3aXRoIHplcm8gZGVjaW1hbHMgKGUuZy4gMTIpKg0KDQpbKipBZ2dyZWdhdGUgRm9yZWNhc3RpbmcqKl17LnVuZGVybGluZX06DQoNCmBgYHtyfQ0KcHJlZCA8LSBiZ2JiLlBsb3RUcmFja2luZ0luYyhwYXJhbXMsIHJmLm1hdHJpeCwgdHJhbnMpDQoNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmNhdCgiUTQgPSIscm91bmQocHJlZFsyLDhdKSwgIlxuIikNCmBgYA0KDQojIFF1ZXN0aW9uIDUNCg0KQWNjb3JkaW5nIHRvIHRoZSBtb2RlbCwgKip3aGF0IGlzIHRoZSBwcmVkaWN0ZWQgbnVtYmVyIG9mIHRyYW5zYWN0aW9ucyBpbiB0aGUgaG9sZG91dCBmb3IgYSBjdXN0b21lciB3aG8gd2FzICI3IGZvciA3IiBpbiB0aGUgY2FsaWJyYXRpb24gcGVyaW9kPyDCoFdoYXQgaXMgdGhlIGFjdHVhbCBudW1iZXIgb2YgaG9sZG91dCB0cmFuc2FjdGlvbnMgZm9yIHRoZXNlIGN1c3RvbWVycz8qKg0KDQoqUHJvdmlkZSB5b3VyIGFuc3dlciB3aXRoIGEgZG90IGFuZCB0d28gZGVjaW1hbHMgKGUuZy4gMC4xMikqDQoNClsqKlByZWRpY3RlZCoqXXsudW5kZXJsaW5lfToNCg0KYGBge3J9DQpiZ2JiLkhlYXRtYXBIb2xkb3V0RXhwZWN0ZWRUcmFucyhwYXJhbXMsIG4uY2FsID0gNywgbi5zdGFyID0gNikNCmBgYA0KDQpbKipBY3R1YWwqKl17LnVuZGVybGluZX06DQoNCmBgYHtyfQ0KY2JpbmQoY2FsLnJmLm1hdHJpeCwgaG9sZG91dCkNCg0KIyB0YWtlIHRvdGFsIHRyYW5zYWN0aW9ucyBmb3IgbGFzdCByb3cgZGl2aWRlZCBieSBjdXN0b21lcnM6DQoNCmFjdCA8LSBob2xkb3V0JHhbMjldL2NhbC5yZi5tYXRyaXhbMjksNF0gI2luZD0yOSBoYXMgNyBvZiA3LCB0aGUgbGFzdCBvYnMuDQoNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmNhdCgiQWN0dWFsID0iLHJvdW5kKGFjdCwyKSwgIlxuIikNCmBgYA0KDQojIFF1ZXN0aW9uIDYNCg0KKipXaGF0IGlzIHRoZSBDTFYqKiwgYXNzdW1pbmcgZWFjaCB0cmFuc2FjdGlvbiB5aWVsZHMgb24gYXZlcmFnZSA1MCBpbiBwcm9maXQgYW5kIHRoZSBkaXNjb3VudCByYXRlIGlzIDAuMT8gWW91IGNhbiB1c2UgMjAwIHBlcmlvZHMgZm9yIHRoZSBzdW0uDQoNCipQcm92aWRlIHlvdXIgYW5zd2VyIHdpdGggemVybyBkZWNpbWFscyAoZS5nLiAxMikqDQoNCmBgYHtyfQ0KQkdCQkNMVjwtZnVuY3Rpb24ocGFyYW1zLG0sZCxUKSB7DQpwYXJhbXM8LXVubmFtZShwYXJhbXMpDQphbDwtcGFyYW1zWzFdDQpiZTwtcGFyYW1zWzJdDQpnYTwtcGFyYW1zWzNdDQpkZTwtcGFyYW1zWzRdDQpERVQ8LTEgICAjIGF0IHRpbWUgemVybyB0aGVyZSBoYXMgdG8gYmUgYSBwdXJjaGFzZQ0KZm9yIChpIGluIDE6VCkgew0KICAgIERFVDwtREVUKyhhbC8oYWwrYmUpKSooYmV0YShnYSxkZStpKS9iZXRhKGdhLGRlKSkqMS8oMStkKV57aX0NCn0NCkNMVj1tKkRFVCAgIyBjb252ZXJ0IGRpc2NvdW50IGV4cGVjdGVkIHB1cmNoYXNlcyBpbnRvIGV4cGVjdGVkIHZhbHVlDQpyZXR1cm4oQ0xWKSAgICAjcmV0dXJuIHRoZSBDTFYNCn0NCmBgYA0KDQpbKipDTFYqKl17LnVuZGVybGluZX06DQoNCmBgYHtyfQ0KQ0xWIDwtIEJHQkJDTFYocGFyYW1zID0gcGFyYW1zLCBtPTUwLGQ9LjEsVD0yMDApDQpDTFYNCmBgYA0KDQojIFF1ZXN0aW9uIDcNCg0KKipXaGF0IGlzIHRoZSBSTFYgZm9yIGEgNyBmb3IgNyBjdXN0b21lcj8qKiBBZ2FpbiwgYXNzdW1lIGVhY2ggdHJhbnNhY3Rpb24geWllbGRzIG9uIGF2ZXJhZ2UgNTAgaW4gcHJvZml0LCBhbmQgdGhlIGRpc2NvdW50IHJhdGUgaXMgMC4xLiDCoA0KDQoqUHJvdmlkZSB5b3VyIGFuc3dlciB3aXRoIHplcm8gZGVjaW1hbHMgKGUuZy4gMTIpKg0KDQpgYGB7cn0NCm0gPC0gNTANCkRFUlQgPC0gYmdiYi5yZi5tYXRyaXguREVSVChwYXJhbXMsIHJmLm1hdHJpeCA9IGNhbC5yZi5tYXRyaXgsIGQ9MC4xKQ0KUkxWIDwtIG0qREVSVA0KDQpSTFZtYXRyaXggPC0gY2JpbmQoY2FsLnJmLm1hdHJpeCxyb3VuZChSTFYpKSANClJMVm1hdHJpeA0KYGBgDQoNClsqKlJMVioqXXsudW5kZXJsaW5lfToNCg0KYGBge3J9DQptYXgoUkxWKQ0KYGBgDQoNCiMgUXVlc3Rpb24gOA0KDQpDb25zaWRlciBhIGNoYXJpdHkgd2l0aCBqdXN0IG9uZSBvcHBvcnR1bml0eSBmb3IgcGVvcGxlIHRvIGRvbmF0ZSBwZXIgeWVhci4gQ29uc2lkZXIgYSBkb25vciBoYXMgZG9uYXRlZCAzIHRpbWVzIGluIHRoZSBwYXN0IGZpdmUgeWVhcnMgd2l0aCB0aGUgbGFzdCBkb25hdGlvbiBvY2N1cnJpbmcgaW4geWVhciA0LiBJbiB0aGUgY29udGV4dCBvZiB0aGUgQkcvQkIgbW9kZWwsIHdoYXQgYXJlIHRoZSBkb25vcidzIHN1ZmZpY2llbnQgc3RhdGlzdGljczogbiwgdF94LCBhbmQgeA0KDQpuPTVcDQp0X3ggPSA0XA0KeCA9IDMNCg0KQXNzdW1lIHRoYXQgPSAwLjYgYW5kwqAqzpgqwqA9IDAuMi4NCg0KKipXaGF0IGlzIHRoZSBsaWtlbGlob29kIG9mIHRoaXMgY3VzdG9tZXIncyBkb25hdGlvbnM/KioNCg0KKlByb3ZpZGUgeW91ciBhbnN3ZXIgd2l0aCBhIGRvdCBhbmQgdGhyZWUgZGVjaW1hbHMgKGUuZy4gMC4xMjMpKg0KDQpgYGB7cn0NCm4gPC0gNQ0KdF94IDwtIDQNCnggPC0gMw0KDQpwIDwtIDAuNg0KdGhldGEgPC0gMC4yDQpgYGANCg0KJCQNCkwocCxcdGhldGF8eCwgdF94LG4pPXBeeCgxLXApXntuLXh9KDEtXHRoZXRhKV5uDQorXHN1bV57bi10X3gtMX1fe2o9MH1wXngoMS1wKV57dF94LXgran1cdGhldGEoMS1cdGhldGEpXnt0X3gran0NCiQkDQoNCmBgYHtyfQ0KYSA8LSAocF4zKSooMS1wKSooKDEtdGhldGEpXjQpKnRoZXRhDQpiIDwtIChwXjMpKigxLXApXjIqKCgxLXRoZXRhKV41KSAjIyB0aGUgbGFzdCBvYnMuIGRvZXMgbm90IGhhdmUgdGhldGENCg0KbGlrZWxpaG9vZCA8LSBhK2INCnJvdW5kKGxpa2VsaWhvb2QsMykNCmBgYA0KDQojIFF1ZXN0aW9uIDkNCg0KKipXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSB0aGF0IHRoZSBjdXN0b21lciBpcyBhbGl2ZSBhdCB0aGUgZW5kPyoqDQoNCipQcm92aWRlIHlvdXIgYW5zd2VyIHdpdGggYSBkb3QgYW5kIHRocmVlIGRlY2ltYWxzIChlLmcuIDAuMTIzKSoNCg0KJCQNClxQcihcdGV4dHthbGl2ZSBhdCB9bnx4LHRfeCxuKT1cZnJhY3twXngoMS1wKV57bi14fSgxLVx0aGV0YSlebn17TChwLFx0aGV0YXx4LHRfeCxuKX0NCiQkDQoNCmBgYHtyfQ0KKHBeMykqKCgxLXApXjIpKigoMS10aGV0YSleNSkvbGlrZWxpaG9vZA0KYGBgDQo=