This document will attempt to demonstrate the five behaviors caused
by epistasis described in the lecture.
Griffing effect
The below script will show how additive-by-additive epistasis
contributes to response to selection in an unselected population and how
this response diminishes in subsequent generations.
library(AlphaSimR)
Loading required package: R6
founderPop = quickHaplo(nInd=1000, nChr=10, segSites=1000)
# Setting a trait with strong epistasis
SP = SimParam$
new(founderPop)$
addTraitAE(1000, relAA=1)$
setVarE(H2=1)
pop = newPop(founderPop)
varA(pop)
Trait1
Trait1 1
varAA(pop)
Trait1
Trait1 0.9394489
pop2 = selectCross(pop, nInd=100, nCrosses=1000)
# Observed response to selection
meanG(pop2) - meanG(pop)
Trait1
1.819469
# Response expected from standard breeders equation
selInt(p=0.1) * varA(pop) / sqrt(varP(pop))
Trait1
Trait1 1.254025
# Response expected from the Griffing effect and no prior selection
selInt(p=0.1) * (varA(pop) + 0.5*varAA(pop)) / sqrt(varP(pop))
Trait1
Trait1 1.843072
# Repeat measurement after multiple rounds of selection
for(i in 1:10){
pop = selectCross(pop, nInd=100, nCrosses=1000)
}
pop2 = selectCross(pop, nInd=100, nCrosses=1000)
# Observed response to selection
meanG(pop2) - meanG(pop)
Trait1
1.153263
# Response expected from standard breeders equation
selInt(p=0.1) * varA(pop) / sqrt(varP(pop))
Trait1
Trait1 1.264255
# Response expected from the Griffing effect and no prior selection
selInt(p=0.1) * (varA(pop) + 0.5*varAA(pop)) / sqrt(varP(pop))
Trait1
Trait1 1.842631
“Conversion” of epistatic variance
This script will show how additive genetic variance can increase due
to epistatic effects. This property is due to drift, so the experiment
will be performed using populations of two different sizes. This example
comes from the AlphaSimR_Examples repository on GitHub.
library(ggplot2)
## User set variances
# VarA = 1, always
VarD = 1
VarAA = 1
VarE = 1
n = 1000 # Population size, must be divisible by 10
# Note that conversion is due to drift, so it occurs
# sooner in smaller populations
## Simulation
founderPop = quickHaplo(nInd=n,nChr=10,segSites=100)
SP = SimParam$
new(founderPop)$
addTraitADE(100, varDD=VarD*2, relAA=VarAA)$
setVarE(varE=VarE)
pop = newPop(founderPop)
MEAN = VARG = VARA = VARD = VARAA = numeric(101)
tmp = genParam(pop)
MEAN[1] = tmp$mu
VARG[1] = tmp$varG
VARA[1] = tmp$varA
VARD[1] = tmp$varD
VARAA[1] = tmp$varAA
for(i in 2:101){
pop = selectCross(pop,n*0.1,nCrosses=n)
tmp = genParam(pop)
MEAN[i] = tmp$mu
VARG[i] = tmp$varG
VARA[i] = tmp$varA
VARD[i] = tmp$varD
VARAA[i] = tmp$varAA
}
df = data.frame(Cycle=rep(0:100,4),
Source=rep(c("Vg","Va","Vd","Vaa"),each=101),
Variance=c(VARG,VARA,VARD,VARAA))
ggplot(df,aes(x=Cycle, y=Variance, color=Source))+
geom_line(linewidth=1)+
guides(alpha="none")+
theme_bw()

df2 = data.frame(Cycle=0:100,
Mean=MEAN)
ggplot(df2,aes(x=Cycle,y=Mean))+
geom_line(linewidth=1)+
guides(alpha="none")+
theme_bw()

### Rerunning the simulation with a smaller population
## User set variances
# VarA = 1, always
VarD = 1
VarAA = 1
VarE = 1
n = 100 # Population size, must be divisible by 10
# Note that conversion is due to drift, so it occurs
# sooner in smaller populations
## Simulation
founderPop = quickHaplo(nInd=n,nChr=10,segSites=100)
SP = SimParam$
new(founderPop)$
addTraitADE(100, varDD=VarD*2, relAA=VarAA)$
setVarE(varE=VarE)
pop = newPop(founderPop)
MEAN = VARG = VARA = VARD = VARAA = numeric(101)
tmp = genParam(pop)
MEAN[1] = tmp$mu
VARG[1] = tmp$varG
VARA[1] = tmp$varA
VARD[1] = tmp$varD
VARAA[1] = tmp$varAA
for(i in 2:101){
pop = selectCross(pop,n*0.1,nCrosses=n)
tmp = genParam(pop)
MEAN[i] = tmp$mu
VARG[i] = tmp$varG
VARA[i] = tmp$varA
VARD[i] = tmp$varD
VARAA[i] = tmp$varAA
}
df = data.frame(Cycle=rep(0:100,4),
Source=rep(c("Vg","Va","Vd","Vaa"),each=101),
Variance=c(VARG,VARA,VARD,VARAA))
ggplot(df,aes(x=Cycle, y=Variance, color=Source))+
geom_line(linewidth=1)+
guides(alpha="none")+
theme_bw()

df2 = data.frame(Cycle=0:100,
Mean=MEAN)
ggplot(df2,aes(x=Cycle,y=Mean))+
geom_line(linewidth=1)+
guides(alpha="none")+
theme_bw()

Hybrid depression
This script will show how epistasis can contribute to hybrid
depression. Hybrid depression is when the mean of the hybrid is less the
two parental populations. The simulation will create favorable
conditions for this phenomenon by breeding two population separately in
the presence of strong epistasis and the absence of dominance. Favorable
epistatic combinations will build up in each population that will only
partially be transmitted to the hybrids.
founderPop = runMacs(nInd=200, nChr=10, segSites=1000,
split=100, inbred=TRUE)
SP = SimParam$
new(founderPop[1:100])$
addTraitAE(1000, relAA=1)$
setVarE(H2=1)
A = newPop(founderPop[1:100])
B = newPop(founderPop[101:200])
A = makeDH( randCross(A, 1000) )
B = makeDH( randCross(B, 1000) )
F1 = randCross2(A, B, nCrosses=10000)
# Create variable for midparent and F1 means
meanMidPar = meanF1 = numeric(20)
meanMidPar[1] = (meanG(A)+meanG(B))/2
meanF1[1] = meanG(F1)
# Reciprical recurrent selection
for(i in 2:20){
A = makeDH( selectCross(A, nInd=100, nCrosses=1000) )
B = makeDH( selectCross(B, nInd=100, nCrosses=1000) )
F1 = randCross2(A, B, nCrosses=10000)
meanMidPar[i] = (meanG(A)+meanG(B))/2
meanF1[i] = meanG(F1)
}
# Plot midparent (black) and F1 (red) means over time
plot(1:20, meanMidPar, type="l",
xlab="Generation",
ylab="Genetic Value")
lines(1:20, meanF1, col="red")

Hybrid depression
The below script will attempt (and fail) to show heterosis due to
epistatic interactions. It is similar to the above script, but uses
reciprocal recurrent selection to attempt to build favorable epistatic
interaction between the populations.
founderPop = runMacs(nInd=200, nChr=10, segSites=1000,
split=100, inbred=TRUE)
SP = SimParam$
new(founderPop[1:100])$
addTraitAE(1000, relAA=1)$
setVarE(H2=1)
A = newPop(founderPop[1:100])
B = newPop(founderPop[101:200])
A = makeDH( randCross(A, 1000) )
B = makeDH( randCross(B, 1000) )
F1 = randCross2(A, B, nCrosses=10000)
# Create variable for midparent and F1 means
meanMidPar = meanF1 = numeric(20)
meanMidPar[1] = (meanG(A)+meanG(B))/2
meanF1[1] = meanG(F1)
# Reciprocal recurrent selection using random testers
for(i in 2:20){
A = setPhenoGCA(A, testers=B[sample(1000,10)], inbred=TRUE)
B = setPhenoGCA(B, testers=A[sample(1000,10)], inbred=TRUE)
A = makeDH( selectCross(A, nInd=100, nCrosses=1000) )
B = makeDH( selectCross(B, nInd=100, nCrosses=1000) )
F1 = randCross2(A, B, nCrosses=10000)
meanMidPar[i] = (meanG(A)+meanG(B))/2
meanF1[i] = meanG(F1)
}
# Plot midparent (black) and F1 (red) means over time
plot(1:20, meanMidPar, type="l",
xlab="Generation",
ylab="Genetic Value")
lines(1:20, meanF1, col="red")

Epistatic decay
This script will show how stabilizing selection on component traits
can explain progeny means being below the midparent values for elite
parents. This script also shows how complex epistasis can be modeled
using nonlinear interactions between component traits.
# Function for modeling epistasis as one component trait under
# directional selection and the rest under stabilizing selection.
specialSelect = function(X){
Y = X[,1] - rowSums( abs(X[,-1]) )
}
founderPop = quickHaplo(nInd=1000, nChr=10, segSites=1000,
inbred=TRUE)
# Simulating multiple traits to serve as component traits
SP = SimParam$
new(founderPop)$
addTraitA(1000,
mean = c(100, rep(0,10)),
var = rep(1,11),
corA = diag(11))$
setVarE(H2 = rep(1,11))
pop = newPop(founderPop)
hist(specialSelect( gv(pop) ),
main = "Histogram of Special Trait",
xlab = "Special Trait")

# Five generations of breeding
for(i in 1:5){
pop = selectCross(pop, nInd=100, nCrosses=1000,
trait=specialSelect)
pop = makeDH(pop)
}
# Select parents and make biparental crosses
parents = selectInd(pop, nInd=3, trait=specialSelect)
progeny12 = makeCross(parents, crossPlan=cbind(1,2))
progeny12 = makeDH(progeny12, nDH=100)
progeny13 = makeCross(parents, crossPlan=cbind(1,3))
progeny13 = makeDH(progeny13, nDH=100)
progeny23 = makeCross(parents, crossPlan=cbind(2,3))
progeny23 = makeDH(progeny23, nDH=100)
# Measure GV
gvPar = specialSelect(gv(parents))
gvProg12 = specialSelect(gv(progeny12))
gvProg13 = specialSelect(gv(progeny13))
gvProg23 = specialSelect(gv(progeny23))
# Measure difference between midparent and progeny mean
mean(gvPar[1:2]) - mean(gvProg12)
[1] 3.042156
mean(gvPar[c(1,3)]) - mean(gvProg13)
[1] 2.481761
mean(gvPar[2:3]) - mean(gvProg23)
[1] 2.799389
LS0tDQp0aXRsZTogIlF1YW50aXRhdGl2ZSBHZW5ldGljczogRXBpc3RhdGljIEVmZmVjdHMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGRvY3VtZW50IHdpbGwgYXR0ZW1wdCB0byBkZW1vbnN0cmF0ZSB0aGUgZml2ZSBiZWhhdmlvcnMgY2F1c2VkIGJ5IGVwaXN0YXNpcyBkZXNjcmliZWQgaW4gdGhlIGxlY3R1cmUuDQoNCg0KIyMgR3JpZmZpbmcgZWZmZWN0DQoNClRoZSBiZWxvdyBzY3JpcHQgd2lsbCBzaG93IGhvdyBhZGRpdGl2ZS1ieS1hZGRpdGl2ZSBlcGlzdGFzaXMgY29udHJpYnV0ZXMgdG8gcmVzcG9uc2UgdG8gc2VsZWN0aW9uIGluIGFuIHVuc2VsZWN0ZWQgcG9wdWxhdGlvbiBhbmQgaG93IHRoaXMgcmVzcG9uc2UgZGltaW5pc2hlcyBpbiBzdWJzZXF1ZW50IGdlbmVyYXRpb25zLg0KDQpgYGB7cn0NCmxpYnJhcnkoQWxwaGFTaW1SKQ0KDQpmb3VuZGVyUG9wID0gcXVpY2tIYXBsbyhuSW5kPTEwMDAsIG5DaHI9MTAsIHNlZ1NpdGVzPTEwMDApDQoNCiMgU2V0dGluZyBhIHRyYWl0IHdpdGggc3Ryb25nIGVwaXN0YXNpcw0KU1AgPSBTaW1QYXJhbSQNCiAgbmV3KGZvdW5kZXJQb3ApJA0KICBhZGRUcmFpdEFFKDEwMDAsIHJlbEFBPTEpJA0KICBzZXRWYXJFKEgyPTEpDQoNCnBvcCA9IG5ld1BvcChmb3VuZGVyUG9wKQ0KDQp2YXJBKHBvcCkNCnZhckFBKHBvcCkNCg0KcG9wMiA9IHNlbGVjdENyb3NzKHBvcCwgbkluZD0xMDAsIG5Dcm9zc2VzPTEwMDApDQoNCiMgT2JzZXJ2ZWQgcmVzcG9uc2UgdG8gc2VsZWN0aW9uDQptZWFuRyhwb3AyKSAtIG1lYW5HKHBvcCkNCg0KIyBSZXNwb25zZSBleHBlY3RlZCBmcm9tIHN0YW5kYXJkIGJyZWVkZXJzIGVxdWF0aW9uDQpzZWxJbnQocD0wLjEpICogdmFyQShwb3ApIC8gc3FydCh2YXJQKHBvcCkpDQoNCiMgUmVzcG9uc2UgZXhwZWN0ZWQgZnJvbSB0aGUgR3JpZmZpbmcgZWZmZWN0IGFuZCBubyBwcmlvciBzZWxlY3Rpb24NCnNlbEludChwPTAuMSkgKiAodmFyQShwb3ApICsgMC41KnZhckFBKHBvcCkpIC8gc3FydCh2YXJQKHBvcCkpDQoNCiMgUmVwZWF0IG1lYXN1cmVtZW50IGFmdGVyIG11bHRpcGxlIHJvdW5kcyBvZiBzZWxlY3Rpb24NCmZvcihpIGluIDE6MTApew0KICBwb3AgPSBzZWxlY3RDcm9zcyhwb3AsIG5JbmQ9MTAwLCBuQ3Jvc3Nlcz0xMDAwKQ0KfQ0KDQpwb3AyID0gc2VsZWN0Q3Jvc3MocG9wLCBuSW5kPTEwMCwgbkNyb3NzZXM9MTAwMCkNCg0KIyBPYnNlcnZlZCByZXNwb25zZSB0byBzZWxlY3Rpb24NCm1lYW5HKHBvcDIpIC0gbWVhbkcocG9wKQ0KDQojIFJlc3BvbnNlIGV4cGVjdGVkIGZyb20gc3RhbmRhcmQgYnJlZWRlcnMgZXF1YXRpb24NCnNlbEludChwPTAuMSkgKiB2YXJBKHBvcCkgLyBzcXJ0KHZhclAocG9wKSkNCg0KIyBSZXNwb25zZSBleHBlY3RlZCBmcm9tIHRoZSBHcmlmZmluZyBlZmZlY3QgYW5kIG5vIHByaW9yIHNlbGVjdGlvbg0Kc2VsSW50KHA9MC4xKSAqICh2YXJBKHBvcCkgKyAwLjUqdmFyQUEocG9wKSkgLyBzcXJ0KHZhclAocG9wKSkNCmBgYA0KDQojIyAiQ29udmVyc2lvbiIgb2YgZXBpc3RhdGljIHZhcmlhbmNlDQoNClRoaXMgc2NyaXB0IHdpbGwgc2hvdyBob3cgYWRkaXRpdmUgZ2VuZXRpYyB2YXJpYW5jZSBjYW4gaW5jcmVhc2UgZHVlIHRvIGVwaXN0YXRpYyBlZmZlY3RzLiBUaGlzIHByb3BlcnR5IGlzIGR1ZSB0byBkcmlmdCwgc28gdGhlIGV4cGVyaW1lbnQgd2lsbCBiZSBwZXJmb3JtZWQgdXNpbmcgcG9wdWxhdGlvbnMgb2YgdHdvIGRpZmZlcmVudCBzaXplcy4gVGhpcyBleGFtcGxlIGNvbWVzIGZyb20gdGhlIEFscGhhU2ltUl9FeGFtcGxlcyByZXBvc2l0b3J5IG9uIEdpdEh1Yi4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMjIFVzZXIgc2V0IHZhcmlhbmNlcw0KIyBWYXJBID0gMSwgYWx3YXlzDQpWYXJEID0gMSANClZhckFBID0gMQ0KVmFyRSA9IDENCm4gPSAxMDAwICMgUG9wdWxhdGlvbiBzaXplLCBtdXN0IGJlIGRpdmlzaWJsZSBieSAxMA0KIyBOb3RlIHRoYXQgY29udmVyc2lvbiBpcyBkdWUgdG8gZHJpZnQsIHNvIGl0IG9jY3Vycw0KIyBzb29uZXIgaW4gc21hbGxlciBwb3B1bGF0aW9ucw0KDQojIyBTaW11bGF0aW9uDQpmb3VuZGVyUG9wID0gcXVpY2tIYXBsbyhuSW5kPW4sbkNocj0xMCxzZWdTaXRlcz0xMDApDQoNClNQID0gU2ltUGFyYW0kDQogIG5ldyhmb3VuZGVyUG9wKSQNCiAgYWRkVHJhaXRBREUoMTAwLCB2YXJERD1WYXJEKjIsIHJlbEFBPVZhckFBKSQNCiAgc2V0VmFyRSh2YXJFPVZhckUpDQoNCnBvcCA9IG5ld1BvcChmb3VuZGVyUG9wKQ0KTUVBTiA9IFZBUkcgPSBWQVJBID0gVkFSRCA9IFZBUkFBID0gbnVtZXJpYygxMDEpDQoNCnRtcCA9IGdlblBhcmFtKHBvcCkNCk1FQU5bMV0gPSB0bXAkbXUNClZBUkdbMV0gPSB0bXAkdmFyRw0KVkFSQVsxXSA9IHRtcCR2YXJBDQpWQVJEWzFdID0gdG1wJHZhckQNClZBUkFBWzFdID0gdG1wJHZhckFBDQoNCmZvcihpIGluIDI6MTAxKXsNCiAgcG9wID0gc2VsZWN0Q3Jvc3MocG9wLG4qMC4xLG5Dcm9zc2VzPW4pDQogIHRtcCA9IGdlblBhcmFtKHBvcCkNCiAgTUVBTltpXSA9IHRtcCRtdQ0KICBWQVJHW2ldID0gdG1wJHZhckcNCiAgVkFSQVtpXSA9IHRtcCR2YXJBDQogIFZBUkRbaV0gPSB0bXAkdmFyRA0KICBWQVJBQVtpXSA9IHRtcCR2YXJBQQ0KfQ0KDQpkZiA9IGRhdGEuZnJhbWUoQ3ljbGU9cmVwKDA6MTAwLDQpLA0KICAgICAgICAgICAgICAgIFNvdXJjZT1yZXAoYygiVmciLCJWYSIsIlZkIiwiVmFhIiksZWFjaD0xMDEpLA0KICAgICAgICAgICAgICAgIFZhcmlhbmNlPWMoVkFSRyxWQVJBLFZBUkQsVkFSQUEpKQ0KDQpnZ3Bsb3QoZGYsYWVzKHg9Q3ljbGUsIHk9VmFyaWFuY2UsIGNvbG9yPVNvdXJjZSkpKw0KICBnZW9tX2xpbmUobGluZXdpZHRoPTEpKw0KICBndWlkZXMoYWxwaGE9Im5vbmUiKSsNCiAgdGhlbWVfYncoKQ0KDQpkZjIgPSBkYXRhLmZyYW1lKEN5Y2xlPTA6MTAwLA0KICAgICAgICAgICAgICAgICBNZWFuPU1FQU4pDQoNCmdncGxvdChkZjIsYWVzKHg9Q3ljbGUseT1NZWFuKSkrDQogIGdlb21fbGluZShsaW5ld2lkdGg9MSkrDQogIGd1aWRlcyhhbHBoYT0ibm9uZSIpKw0KICB0aGVtZV9idygpDQoNCg0KIyMjIFJlcnVubmluZyB0aGUgc2ltdWxhdGlvbiB3aXRoIGEgc21hbGxlciBwb3B1bGF0aW9uDQoNCiMjIFVzZXIgc2V0IHZhcmlhbmNlcw0KIyBWYXJBID0gMSwgYWx3YXlzDQpWYXJEID0gMSANClZhckFBID0gMQ0KVmFyRSA9IDENCm4gPSAxMDAgIyBQb3B1bGF0aW9uIHNpemUsIG11c3QgYmUgZGl2aXNpYmxlIGJ5IDEwDQojIE5vdGUgdGhhdCBjb252ZXJzaW9uIGlzIGR1ZSB0byBkcmlmdCwgc28gaXQgb2NjdXJzDQojIHNvb25lciBpbiBzbWFsbGVyIHBvcHVsYXRpb25zDQoNCiMjIFNpbXVsYXRpb24NCmZvdW5kZXJQb3AgPSBxdWlja0hhcGxvKG5JbmQ9bixuQ2hyPTEwLHNlZ1NpdGVzPTEwMCkNCg0KU1AgPSBTaW1QYXJhbSQNCiAgbmV3KGZvdW5kZXJQb3ApJA0KICBhZGRUcmFpdEFERSgxMDAsIHZhckREPVZhckQqMiwgcmVsQUE9VmFyQUEpJA0KICBzZXRWYXJFKHZhckU9VmFyRSkNCg0KcG9wID0gbmV3UG9wKGZvdW5kZXJQb3ApDQpNRUFOID0gVkFSRyA9IFZBUkEgPSBWQVJEID0gVkFSQUEgPSBudW1lcmljKDEwMSkNCg0KdG1wID0gZ2VuUGFyYW0ocG9wKQ0KTUVBTlsxXSA9IHRtcCRtdQ0KVkFSR1sxXSA9IHRtcCR2YXJHDQpWQVJBWzFdID0gdG1wJHZhckENClZBUkRbMV0gPSB0bXAkdmFyRA0KVkFSQUFbMV0gPSB0bXAkdmFyQUENCg0KZm9yKGkgaW4gMjoxMDEpew0KICBwb3AgPSBzZWxlY3RDcm9zcyhwb3AsbiowLjEsbkNyb3NzZXM9bikNCiAgdG1wID0gZ2VuUGFyYW0ocG9wKQ0KICBNRUFOW2ldID0gdG1wJG11DQogIFZBUkdbaV0gPSB0bXAkdmFyRw0KICBWQVJBW2ldID0gdG1wJHZhckENCiAgVkFSRFtpXSA9IHRtcCR2YXJEDQogIFZBUkFBW2ldID0gdG1wJHZhckFBDQp9DQoNCmRmID0gZGF0YS5mcmFtZShDeWNsZT1yZXAoMDoxMDAsNCksDQogICAgICAgICAgICAgICAgU291cmNlPXJlcChjKCJWZyIsIlZhIiwiVmQiLCJWYWEiKSxlYWNoPTEwMSksDQogICAgICAgICAgICAgICAgVmFyaWFuY2U9YyhWQVJHLFZBUkEsVkFSRCxWQVJBQSkpDQoNCmdncGxvdChkZixhZXMoeD1DeWNsZSwgeT1WYXJpYW5jZSwgY29sb3I9U291cmNlKSkrDQogIGdlb21fbGluZShsaW5ld2lkdGg9MSkrDQogIGd1aWRlcyhhbHBoYT0ibm9uZSIpKw0KICB0aGVtZV9idygpDQoNCmRmMiA9IGRhdGEuZnJhbWUoQ3ljbGU9MDoxMDAsDQogICAgICAgICAgICAgICAgIE1lYW49TUVBTikNCg0KZ2dwbG90KGRmMixhZXMoeD1DeWNsZSx5PU1lYW4pKSsNCiAgZ2VvbV9saW5lKGxpbmV3aWR0aD0xKSsNCiAgZ3VpZGVzKGFscGhhPSJub25lIikrDQogIHRoZW1lX2J3KCkNCmBgYA0KDQoNCiMjIEh5YnJpZCBkZXByZXNzaW9uDQoNClRoaXMgc2NyaXB0IHdpbGwgc2hvdyBob3cgZXBpc3Rhc2lzIGNhbiBjb250cmlidXRlIHRvIGh5YnJpZCBkZXByZXNzaW9uLiBIeWJyaWQgZGVwcmVzc2lvbiBpcyB3aGVuIHRoZSBtZWFuIG9mIHRoZSBoeWJyaWQgaXMgbGVzcyB0aGUgdHdvIHBhcmVudGFsIHBvcHVsYXRpb25zLiBUaGUgc2ltdWxhdGlvbiB3aWxsIGNyZWF0ZSBmYXZvcmFibGUgY29uZGl0aW9ucyBmb3IgdGhpcyBwaGVub21lbm9uIGJ5IGJyZWVkaW5nIHR3byBwb3B1bGF0aW9uIHNlcGFyYXRlbHkgaW4gdGhlIHByZXNlbmNlIG9mIHN0cm9uZyBlcGlzdGFzaXMgYW5kIHRoZSBhYnNlbmNlIG9mIGRvbWluYW5jZS4gRmF2b3JhYmxlIGVwaXN0YXRpYyBjb21iaW5hdGlvbnMgd2lsbCBidWlsZCB1cCBpbiBlYWNoIHBvcHVsYXRpb24gdGhhdCB3aWxsIG9ubHkgcGFydGlhbGx5IGJlIHRyYW5zbWl0dGVkIHRvIHRoZSBoeWJyaWRzLg0KDQoNCmBgYHtyfQ0KZm91bmRlclBvcCA9IHJ1bk1hY3MobkluZD0yMDAsIG5DaHI9MTAsIHNlZ1NpdGVzPTEwMDAsDQogICAgICAgICAgICAgICAgICAgICBzcGxpdD0xMDAsIGluYnJlZD1UUlVFKQ0KDQpTUCA9IFNpbVBhcmFtJA0KICBuZXcoZm91bmRlclBvcFsxOjEwMF0pJA0KICBhZGRUcmFpdEFFKDEwMDAsIHJlbEFBPTEpJA0KICBzZXRWYXJFKEgyPTEpDQoNCkEgPSBuZXdQb3AoZm91bmRlclBvcFsxOjEwMF0pDQpCID0gbmV3UG9wKGZvdW5kZXJQb3BbMTAxOjIwMF0pDQoNCkEgPSBtYWtlREgoIHJhbmRDcm9zcyhBLCAxMDAwKSApDQpCID0gbWFrZURIKCByYW5kQ3Jvc3MoQiwgMTAwMCkgKQ0KRjEgPSByYW5kQ3Jvc3MyKEEsIEIsIG5Dcm9zc2VzPTEwMDAwKQ0KDQojIENyZWF0ZSB2YXJpYWJsZSBmb3IgbWlkcGFyZW50IGFuZCBGMSBtZWFucw0KbWVhbk1pZFBhciA9IG1lYW5GMSA9IG51bWVyaWMoMjApDQoNCm1lYW5NaWRQYXJbMV0gPSAobWVhbkcoQSkrbWVhbkcoQikpLzINCm1lYW5GMVsxXSA9IG1lYW5HKEYxKQ0KDQojIFJlY2lwcmljYWwgcmVjdXJyZW50IHNlbGVjdGlvbg0KZm9yKGkgaW4gMjoyMCl7DQogIEEgPSBtYWtlREgoIHNlbGVjdENyb3NzKEEsIG5JbmQ9MTAwLCBuQ3Jvc3Nlcz0xMDAwKSApDQogIEIgPSBtYWtlREgoIHNlbGVjdENyb3NzKEIsIG5JbmQ9MTAwLCBuQ3Jvc3Nlcz0xMDAwKSApDQogIEYxID0gcmFuZENyb3NzMihBLCBCLCBuQ3Jvc3Nlcz0xMDAwMCkNCiAgDQogIG1lYW5NaWRQYXJbaV0gPSAobWVhbkcoQSkrbWVhbkcoQikpLzINCiAgbWVhbkYxW2ldID0gbWVhbkcoRjEpDQp9DQoNCiMgUGxvdCBtaWRwYXJlbnQgKGJsYWNrKSBhbmQgRjEgKHJlZCkgbWVhbnMgb3ZlciB0aW1lDQpwbG90KDE6MjAsIG1lYW5NaWRQYXIsIHR5cGU9ImwiLA0KICAgICB4bGFiPSJHZW5lcmF0aW9uIiwNCiAgICAgeWxhYj0iR2VuZXRpYyBWYWx1ZSIpDQpsaW5lcygxOjIwLCBtZWFuRjEsIGNvbD0icmVkIikNCmBgYA0KDQoNCiMjIEh5YnJpZCBkZXByZXNzaW9uDQoNClRoZSBiZWxvdyBzY3JpcHQgd2lsbCBhdHRlbXB0IChhbmQgZmFpbCkgdG8gc2hvdyBoZXRlcm9zaXMgZHVlIHRvIGVwaXN0YXRpYyBpbnRlcmFjdGlvbnMuIEl0IGlzIHNpbWlsYXIgdG8gdGhlIGFib3ZlIHNjcmlwdCwgYnV0IHVzZXMgcmVjaXByb2NhbCByZWN1cnJlbnQgc2VsZWN0aW9uIHRvIGF0dGVtcHQgdG8gYnVpbGQgZmF2b3JhYmxlIGVwaXN0YXRpYyBpbnRlcmFjdGlvbiBiZXR3ZWVuIHRoZSBwb3B1bGF0aW9ucy4NCg0KYGBge3J9DQpmb3VuZGVyUG9wID0gcnVuTWFjcyhuSW5kPTIwMCwgbkNocj0xMCwgc2VnU2l0ZXM9MTAwMCwNCiAgICAgICAgICAgICAgICAgICAgIHNwbGl0PTEwMCwgaW5icmVkPVRSVUUpDQoNClNQID0gU2ltUGFyYW0kDQogIG5ldyhmb3VuZGVyUG9wWzE6MTAwXSkkDQogIGFkZFRyYWl0QUUoMTAwMCwgcmVsQUE9MSkkDQogIHNldFZhckUoSDI9MSkNCg0KQSA9IG5ld1BvcChmb3VuZGVyUG9wWzE6MTAwXSkNCkIgPSBuZXdQb3AoZm91bmRlclBvcFsxMDE6MjAwXSkNCg0KQSA9IG1ha2VESCggcmFuZENyb3NzKEEsIDEwMDApICkNCkIgPSBtYWtlREgoIHJhbmRDcm9zcyhCLCAxMDAwKSApDQpGMSA9IHJhbmRDcm9zczIoQSwgQiwgbkNyb3NzZXM9MTAwMDApDQoNCiMgQ3JlYXRlIHZhcmlhYmxlIGZvciBtaWRwYXJlbnQgYW5kIEYxIG1lYW5zDQptZWFuTWlkUGFyID0gbWVhbkYxID0gbnVtZXJpYygyMCkNCg0KbWVhbk1pZFBhclsxXSA9IChtZWFuRyhBKSttZWFuRyhCKSkvMg0KbWVhbkYxWzFdID0gbWVhbkcoRjEpDQoNCiMgUmVjaXByb2NhbCByZWN1cnJlbnQgc2VsZWN0aW9uIHVzaW5nIHJhbmRvbSB0ZXN0ZXJzDQpmb3IoaSBpbiAyOjIwKXsNCiAgQSA9IHNldFBoZW5vR0NBKEEsIHRlc3RlcnM9QltzYW1wbGUoMTAwMCwxMCldLCBpbmJyZWQ9VFJVRSkNCiAgQiA9IHNldFBoZW5vR0NBKEIsIHRlc3RlcnM9QVtzYW1wbGUoMTAwMCwxMCldLCBpbmJyZWQ9VFJVRSkNCiAgDQogIEEgPSBtYWtlREgoIHNlbGVjdENyb3NzKEEsIG5JbmQ9MTAwLCBuQ3Jvc3Nlcz0xMDAwKSApDQogIEIgPSBtYWtlREgoIHNlbGVjdENyb3NzKEIsIG5JbmQ9MTAwLCBuQ3Jvc3Nlcz0xMDAwKSApDQogIEYxID0gcmFuZENyb3NzMihBLCBCLCBuQ3Jvc3Nlcz0xMDAwMCkNCiAgDQogIG1lYW5NaWRQYXJbaV0gPSAobWVhbkcoQSkrbWVhbkcoQikpLzINCiAgbWVhbkYxW2ldID0gbWVhbkcoRjEpDQp9DQoNCiMgUGxvdCBtaWRwYXJlbnQgKGJsYWNrKSBhbmQgRjEgKHJlZCkgbWVhbnMgb3ZlciB0aW1lDQpwbG90KDE6MjAsIG1lYW5NaWRQYXIsIHR5cGU9ImwiLA0KICAgICB4bGFiPSJHZW5lcmF0aW9uIiwNCiAgICAgeWxhYj0iR2VuZXRpYyBWYWx1ZSIpDQpsaW5lcygxOjIwLCBtZWFuRjEsIGNvbD0icmVkIikNCmBgYA0KDQojIyBFcGlzdGF0aWMgZGVjYXkNCg0KVGhpcyBzY3JpcHQgd2lsbCBzaG93IGhvdyBzdGFiaWxpemluZyBzZWxlY3Rpb24gb24gY29tcG9uZW50IHRyYWl0cyBjYW4gZXhwbGFpbiBwcm9nZW55IG1lYW5zIGJlaW5nIGJlbG93IHRoZSBtaWRwYXJlbnQgdmFsdWVzIGZvciBlbGl0ZSBwYXJlbnRzLiBUaGlzIHNjcmlwdCBhbHNvIHNob3dzIGhvdyBjb21wbGV4IGVwaXN0YXNpcyBjYW4gYmUgbW9kZWxlZCB1c2luZyBub25saW5lYXIgaW50ZXJhY3Rpb25zIGJldHdlZW4gY29tcG9uZW50IHRyYWl0cy4NCg0KDQoNCmBgYHtyfQ0KIyBGdW5jdGlvbiBmb3IgbW9kZWxpbmcgZXBpc3Rhc2lzIGFzIG9uZSBjb21wb25lbnQgdHJhaXQgdW5kZXINCiMgZGlyZWN0aW9uYWwgc2VsZWN0aW9uIGFuZCB0aGUgcmVzdCB1bmRlciBzdGFiaWxpemluZyBzZWxlY3Rpb24uDQpzcGVjaWFsU2VsZWN0ID0gZnVuY3Rpb24oWCl7DQogIFkgPSBYWywxXSAtIHJvd1N1bXMoIGFicyhYWywtMV0pICkNCn0NCg0KZm91bmRlclBvcCA9IHF1aWNrSGFwbG8obkluZD0xMDAwLCBuQ2hyPTEwLCBzZWdTaXRlcz0xMDAwLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGluYnJlZD1UUlVFKQ0KDQojIFNpbXVsYXRpbmcgbXVsdGlwbGUgdHJhaXRzIHRvIHNlcnZlIGFzIGNvbXBvbmVudCB0cmFpdHMNClNQID0gU2ltUGFyYW0kDQogIG5ldyhmb3VuZGVyUG9wKSQNCiAgYWRkVHJhaXRBKDEwMDAsIA0KICAgICAgICAgICAgbWVhbiA9IGMoMTAwLCByZXAoMCwxMCkpLA0KICAgICAgICAgICAgdmFyID0gcmVwKDEsMTEpLA0KICAgICAgICAgICAgY29yQSA9IGRpYWcoMTEpKSQNCiAgc2V0VmFyRShIMiA9IHJlcCgxLDExKSkNCg0KcG9wID0gbmV3UG9wKGZvdW5kZXJQb3ApDQoNCmhpc3Qoc3BlY2lhbFNlbGVjdCggZ3YocG9wKSApLA0KICAgICBtYWluID0gIkhpc3RvZ3JhbSBvZiBTcGVjaWFsIFRyYWl0IiwNCiAgICAgeGxhYiA9ICJTcGVjaWFsIFRyYWl0IikNCg0KIyBGaXZlIGdlbmVyYXRpb25zIG9mIGJyZWVkaW5nDQpmb3IoaSBpbiAxOjUpew0KICBwb3AgPSBzZWxlY3RDcm9zcyhwb3AsIG5JbmQ9MTAwLCBuQ3Jvc3Nlcz0xMDAwLA0KICAgICAgICAgICAgICAgICAgICB0cmFpdD1zcGVjaWFsU2VsZWN0KQ0KICBwb3AgPSBtYWtlREgocG9wKQ0KfQ0KDQojIFNlbGVjdCBwYXJlbnRzIGFuZCBtYWtlIGJpcGFyZW50YWwgY3Jvc3Nlcw0KcGFyZW50cyA9IHNlbGVjdEluZChwb3AsIG5JbmQ9MywgdHJhaXQ9c3BlY2lhbFNlbGVjdCkNCg0KcHJvZ2VueTEyID0gbWFrZUNyb3NzKHBhcmVudHMsIGNyb3NzUGxhbj1jYmluZCgxLDIpKQ0KcHJvZ2VueTEyID0gbWFrZURIKHByb2dlbnkxMiwgbkRIPTEwMCkNCg0KcHJvZ2VueTEzID0gbWFrZUNyb3NzKHBhcmVudHMsIGNyb3NzUGxhbj1jYmluZCgxLDMpKQ0KcHJvZ2VueTEzID0gbWFrZURIKHByb2dlbnkxMywgbkRIPTEwMCkNCg0KcHJvZ2VueTIzID0gbWFrZUNyb3NzKHBhcmVudHMsIGNyb3NzUGxhbj1jYmluZCgyLDMpKQ0KcHJvZ2VueTIzID0gbWFrZURIKHByb2dlbnkyMywgbkRIPTEwMCkNCg0KIyBNZWFzdXJlIEdWDQpndlBhciA9IHNwZWNpYWxTZWxlY3QoZ3YocGFyZW50cykpDQpndlByb2cxMiA9IHNwZWNpYWxTZWxlY3QoZ3YocHJvZ2VueTEyKSkNCmd2UHJvZzEzID0gc3BlY2lhbFNlbGVjdChndihwcm9nZW55MTMpKQ0KZ3ZQcm9nMjMgPSBzcGVjaWFsU2VsZWN0KGd2KHByb2dlbnkyMykpDQoNCiMgTWVhc3VyZSBkaWZmZXJlbmNlIGJldHdlZW4gbWlkcGFyZW50IGFuZCBwcm9nZW55IG1lYW4NCm1lYW4oZ3ZQYXJbMToyXSkgLSBtZWFuKGd2UHJvZzEyKQ0KbWVhbihndlBhcltjKDEsMyldKSAtIG1lYW4oZ3ZQcm9nMTMpDQptZWFuKGd2UGFyWzI6M10pIC0gbWVhbihndlByb2cyMykNCg0KYGBgDQoNCg==