This document will show how to simulate polyploids in AlphaSimR and demonstrate several behaviors that are unique to polyploids.

Simulating polyploids

This script shows how to create polyploids with runMacs and how to set the probability of quadrivalent pairing.

library(AlphaSimR)
Loading required package: R6
# Changing ploidy argument in runMacs
founderPop = runMacs(nInd=100, nChr=10, segSites=1000, 
                     ploidy=4)

founderPop
An object of class "MapPop" 
Ploidy: 4 
Individuals: 100 
Chromosomes: 10 
Loci: 10000 
SP = SimParam$
  new(founderPop)$
  addTraitAD(1000, meanDD=0.2, varDD=0.1)$
  setVarE(H2=1)

# Variable for probability of quadrivalent pairing
SP$quadProb
[1] 0
pop = newPop(founderPop)

head(
  pullMarkerGeno(pop, 
                 markers=c("1_1", "2_1", "3_1", 
                           "4_1", "5_1", "6_1")),
  n=8
  )
  1_1 2_1 3_1 4_1 5_1 6_1
1   2   2   3   0   1   4
2   1   0   3   1   0   4
3   2   2   4   1   1   4
4   3   2   3   1   1   4
5   4   1   3   1   1   4
6   0   1   1   1   0   4
7   2   0   4   1   0   2
8   3   0   2   0   1   4
head(
  pullMarkerHaplo(pop, 
                  markers=c("1_1", "2_1", "3_1", 
                            "4_1", "5_1", "6_1")),
  n=8
)
    1_1 2_1 3_1 4_1 5_1 6_1
1_1   0   1   0   0   0   1
1_2   1   0   1   0   1   1
1_3   0   1   1   0   0   1
1_4   1   0   1   0   0   1
2_1   1   0   1   0   0   1
2_2   0   0   0   0   0   1
2_3   0   0   1   1   0   1
2_4   0   0   1   0   0   1

Double reductions

Double reductions result in two copies of a chromosome segment being passed to a gamete. This behavior can only occur in multivalent paring. This script will indirectly show the presence of double reductions by tracking inbreeding depression.

# Create variable to track population means
muA = muB = numeric(31)
A = B = pop

# Bivalent pairing only
SP$quadProb = 0

muA[1] = meanG(A)

for(i in 2:31){
  A = self(A)
  muA[i] = meanG(A)
}

# Quadrivalent pairing only
SP$quadProb = 1

muB[1] = meanG(B)

for(i in 2:31){
  B = self(B)
  muB[i] = meanG(B)
}

plot(0:30, muA, type="l", 
     ylab="Mean", xlab="Selfing Generation")
lines(0:30, muB, col="red")

NA
NA

Contribution of digenic dominance to response to selection

The digenic dominance in polyploids behaves similarly to additive-by-additive genetic variance with respect to response to selection. This will be demonstrated in the below script.

founderPop = quickHaplo(nInd=1000, nChr=10, 
                        segSites=1000, ploidy=4)

SP = SimParam$
  new(founderPop)$
  addTraitAD(1000, varDD=2)$
  setVarE(H2=1)

pop = newPop(founderPop)

varA(pop)
       Trait1
Trait1      1
varD(pop)
          Trait1
Trait1 0.7382906
pop2 = selectCross(pop, nInd=100, nCrosses=1000)

# Observed response to selection
meanG(pop2) - meanG(pop)
  Trait1 
1.612925 
# Expected response without digenic dominance
selInt(p=0.1) * varA(pop) / sqrt(varP(pop))
         Trait1
Trait1 1.335775
# Expected response with digenic dominance in an unselected population
selInt(p=0.1) * (varA(pop) + (1/3)*varD(pop)) / sqrt(varP(pop))
         Trait1
Trait1 1.664505
# Repeat measurement after multiple rounds of selecton
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.220221 
# Expected response without digenic dominance
selInt(p=0.1) * varA(pop) / sqrt(varP(pop))
         Trait1
Trait1 1.305264
# Expected response with digenic dominance in an unselected population
selInt(p=0.1) * (varA(pop) + (1/3)*varD(pop)) / sqrt(varP(pop))
         Trait1
Trait1 1.668836

Progressive heterosis

The below script will demonstrate the occurrence of progressive heterosis in tetraploids and its absence in diploids. This script comes from the AlphaSimR_Examples GitHub repository. It uses 100 replications, because progressive heterosis is not as reliably present as many of the other properties that have been presented.

het2sc = het4sc = het2dc = het4dc = numeric(100)
for(REP in 1:100){
  founderPop = quickHaplo(nInd=400, nChr=4, segSites=100, ploidy=4)
  
  SP = SimParam$
    new(founderPop)$
    addTraitAD(100, meanDD=0.6, varDD=0.2)$
    setVarE(h2=0.3)
  
  # Create 4 tetraploid populations
  tetraploid = vector("list", 4)
  tetraploid[[1]] = newPop(founderPop[1:100])
  tetraploid[[2]] = newPop(founderPop[101:200])
  tetraploid[[3]] = newPop(founderPop[201:300])
  tetraploid[[4]] = newPop(founderPop[301:400])
  
  # Create diploid populations from tetraploid populations
  diploid = vector("list", 4)
  for(i in 1:4){
    diploid[[i]] = reduceGenome(tetraploid[[i]])
  }
  
  # Perform 5 generations of recurrent selection
  for(gen in 1:5){ 
    for(i in 1:4){
      tetraploid[[i]] = selectCross(tetraploid[[i]], nInd=10, nCrosses=100)
      diploid[[i]] = selectCross(diploid[[i]], nInd=10, nCrosses=100)
    }
  }
  
  # Create single cross populations (1/2 and 3/4)
  tetraSC = list(randCross2(tetraploid[[1]], tetraploid[[2]], nCrosses=100),
                 randCross2(tetraploid[[3]], tetraploid[[4]], nCrosses=100))
  diploidSC = list(randCross2(diploid[[1]], diploid[[2]], nCrosses=100),
                   randCross2(diploid[[3]], diploid[[4]], nCrosses=100))
  
  # Create double cross populations
  tetraDouble = randCross2(tetraSC[[1]], tetraSC[[2]], nCrosses=1000)
  diploidDouble = randCross2(diploidSC[[1]], diploidSC[[2]], nCrosses=1000)
  
  # Calculate mean of all base populations
  meanTetra = mean(unlist(lapply(tetraploid,meanG)))
  meanDiploid = mean(unlist(lapply(diploid,meanG)))
  
  # Calculate mean of single cross populations
  meanTetraSC = mean(unlist(lapply(tetraSC,meanG)))
  meanDiploidSC = mean(unlist(lapply(diploidSC,meanG)))
  
  # Measure single cross heterosis
  het4sc[REP] = meanTetraSC - meanTetra
  het2sc[REP] = meanDiploidSC - meanDiploid
  
  # Measure double cross heterois
  het4dc[REP] = meanG(tetraDouble) - meanTetra 
  het2dc[REP] = meanG(diploidDouble) - meanDiploid 
}
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
boxplot(het2dc,het2sc,het4dc,het4sc, 
        names=c("Diploid D", "Diploid S",
                "Tetraploid D", "Tetraploid S"),
        las=2,
        main="Single (S) vs Double (D) Cross Means")

boxplot(het2dc-het2sc,het4dc-het4sc, 
        names=c("Diploid", "Tetraploid"),
        las=2,
        main="Progressive Heterosis")

Other polyploid behaviors

founderPop = quickHaplo(nInd=100, nChr=10, 
                        segSites=1000)

SP = SimParam$
  new(founderPop)$
  addTraitAD(1000, meanDD=0.6)

diploid = newPop(founderPop)

# Create tetraploids from diploids
tetraploid = doubleGenome(diploid)
tetraploid2 = randCross(tetraploid, 1000)

# Polyploids produced by doubling are partially inbred (not HWE)
meanG(tetraploid2) - meanG(tetraploid)
  Trait1 
13.19257 
# You can cross different ploidy levels
triploid = randCross2(diploid, tetraploid, 1000)

# Odd ploidy levels are dead ends
LS0tDQp0aXRsZTogIlF1YW50aXRhdGl2ZSBHZW5ldGljczogUG9seXBsb2lkcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClRoaXMgZG9jdW1lbnQgd2lsbCBzaG93IGhvdyB0byBzaW11bGF0ZSBwb2x5cGxvaWRzIGluIEFscGhhU2ltUiBhbmQgZGVtb25zdHJhdGUgc2V2ZXJhbCBiZWhhdmlvcnMgdGhhdCBhcmUgdW5pcXVlIHRvIHBvbHlwbG9pZHMuDQoNCiMjIFNpbXVsYXRpbmcgcG9seXBsb2lkcw0KDQpUaGlzIHNjcmlwdCBzaG93cyBob3cgdG8gY3JlYXRlIHBvbHlwbG9pZHMgd2l0aCBgcnVuTWFjc2AgYW5kIGhvdyB0byBzZXQgdGhlIHByb2JhYmlsaXR5IG9mIHF1YWRyaXZhbGVudCBwYWlyaW5nLg0KDQpgYGB7cn0NCmxpYnJhcnkoQWxwaGFTaW1SKQ0KDQojIENoYW5naW5nIHBsb2lkeSBhcmd1bWVudCBpbiBydW5NYWNzDQpmb3VuZGVyUG9wID0gcnVuTWFjcyhuSW5kPTEwMCwgbkNocj0xMCwgc2VnU2l0ZXM9MTAwMCwgDQogICAgICAgICAgICAgICAgICAgICBwbG9pZHk9NCkNCg0KZm91bmRlclBvcA0KDQpTUCA9IFNpbVBhcmFtJA0KICBuZXcoZm91bmRlclBvcCkkDQogIGFkZFRyYWl0QUQoMTAwMCwgbWVhbkREPTAuMiwgdmFyREQ9MC4xKSQNCiAgc2V0VmFyRShIMj0xKQ0KDQojIFZhcmlhYmxlIGZvciBwcm9iYWJpbGl0eSBvZiBxdWFkcml2YWxlbnQgcGFpcmluZw0KU1AkcXVhZFByb2INCg0KcG9wID0gbmV3UG9wKGZvdW5kZXJQb3ApDQoNCmhlYWQoDQogIHB1bGxNYXJrZXJHZW5vKHBvcCwgDQogICAgICAgICAgICAgICAgIG1hcmtlcnM9YygiMV8xIiwgIjJfMSIsICIzXzEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICI0XzEiLCAiNV8xIiwgIjZfMSIpKSwNCiAgbj04DQogICkNCg0KaGVhZCgNCiAgcHVsbE1hcmtlckhhcGxvKHBvcCwgDQogICAgICAgICAgICAgICAgICBtYXJrZXJzPWMoIjFfMSIsICIyXzEiLCAiM18xIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjRfMSIsICI1XzEiLCAiNl8xIikpLA0KICBuPTgNCikNCmBgYA0KDQoNCiMjIERvdWJsZSByZWR1Y3Rpb25zDQoNCkRvdWJsZSByZWR1Y3Rpb25zIHJlc3VsdCBpbiB0d28gY29waWVzIG9mIGEgY2hyb21vc29tZSBzZWdtZW50IGJlaW5nIHBhc3NlZCB0byBhIGdhbWV0ZS4gVGhpcyBiZWhhdmlvciBjYW4gb25seSBvY2N1ciBpbiBtdWx0aXZhbGVudCBwYXJpbmcuIFRoaXMgc2NyaXB0IHdpbGwgaW5kaXJlY3RseSBzaG93IHRoZSBwcmVzZW5jZSBvZiBkb3VibGUgcmVkdWN0aW9ucyBieSB0cmFja2luZyBpbmJyZWVkaW5nIGRlcHJlc3Npb24uDQoNCmBgYHtyfQ0KIyBDcmVhdGUgdmFyaWFibGUgdG8gdHJhY2sgcG9wdWxhdGlvbiBtZWFucw0KbXVBID0gbXVCID0gbnVtZXJpYygzMSkNCkEgPSBCID0gcG9wDQoNCiMgQml2YWxlbnQgcGFpcmluZyBvbmx5DQpTUCRxdWFkUHJvYiA9IDANCg0KbXVBWzFdID0gbWVhbkcoQSkNCg0KZm9yKGkgaW4gMjozMSl7DQogIEEgPSBzZWxmKEEpDQogIG11QVtpXSA9IG1lYW5HKEEpDQp9DQoNCiMgUXVhZHJpdmFsZW50IHBhaXJpbmcgb25seQ0KU1AkcXVhZFByb2IgPSAxDQoNCm11QlsxXSA9IG1lYW5HKEIpDQoNCmZvcihpIGluIDI6MzEpew0KICBCID0gc2VsZihCKQ0KICBtdUJbaV0gPSBtZWFuRyhCKQ0KfQ0KDQpwbG90KDA6MzAsIG11QSwgdHlwZT0ibCIsIA0KICAgICB5bGFiPSJNZWFuIiwgeGxhYj0iU2VsZmluZyBHZW5lcmF0aW9uIikNCmxpbmVzKDA6MzAsIG11QiwgY29sPSJyZWQiKQ0KDQoNCmBgYA0KDQojIyBDb250cmlidXRpb24gb2YgZGlnZW5pYyBkb21pbmFuY2UgdG8gcmVzcG9uc2UgdG8gc2VsZWN0aW9uDQoNClRoZSBkaWdlbmljIGRvbWluYW5jZSBpbiBwb2x5cGxvaWRzIGJlaGF2ZXMgc2ltaWxhcmx5IHRvIGFkZGl0aXZlLWJ5LWFkZGl0aXZlIGdlbmV0aWMgdmFyaWFuY2Ugd2l0aCByZXNwZWN0IHRvIHJlc3BvbnNlIHRvIHNlbGVjdGlvbi4gVGhpcyB3aWxsIGJlIGRlbW9uc3RyYXRlZCBpbiB0aGUgYmVsb3cgc2NyaXB0Lg0KDQpgYGB7cn0NCmZvdW5kZXJQb3AgPSBxdWlja0hhcGxvKG5JbmQ9MTAwMCwgbkNocj0xMCwgDQogICAgICAgICAgICAgICAgICAgICAgICBzZWdTaXRlcz0xMDAwLCBwbG9pZHk9NCkNCg0KU1AgPSBTaW1QYXJhbSQNCiAgbmV3KGZvdW5kZXJQb3ApJA0KICBhZGRUcmFpdEFEKDEwMDAsIHZhckREPTIpJA0KICBzZXRWYXJFKEgyPTEpDQoNCnBvcCA9IG5ld1BvcChmb3VuZGVyUG9wKQ0KDQp2YXJBKHBvcCkNCnZhckQocG9wKQ0KDQpwb3AyID0gc2VsZWN0Q3Jvc3MocG9wLCBuSW5kPTEwMCwgbkNyb3NzZXM9MTAwMCkNCg0KIyBPYnNlcnZlZCByZXNwb25zZSB0byBzZWxlY3Rpb24NCm1lYW5HKHBvcDIpIC0gbWVhbkcocG9wKQ0KDQojIEV4cGVjdGVkIHJlc3BvbnNlIHdpdGhvdXQgZGlnZW5pYyBkb21pbmFuY2UNCnNlbEludChwPTAuMSkgKiB2YXJBKHBvcCkgLyBzcXJ0KHZhclAocG9wKSkNCg0KIyBFeHBlY3RlZCByZXNwb25zZSB3aXRoIGRpZ2VuaWMgZG9taW5hbmNlIGluIGFuIHVuc2VsZWN0ZWQgcG9wdWxhdGlvbg0Kc2VsSW50KHA9MC4xKSAqICh2YXJBKHBvcCkgKyAoMS8zKSp2YXJEKHBvcCkpIC8gc3FydCh2YXJQKHBvcCkpDQoNCiMgUmVwZWF0IG1lYXN1cmVtZW50IGFmdGVyIG11bHRpcGxlIHJvdW5kcyBvZiBzZWxlY3Rvbg0KZm9yKGkgaW4gMToxMCl7DQogIHBvcCA9IHNlbGVjdENyb3NzKHBvcCwgbkluZD0xMDAsIG5Dcm9zc2VzPTEwMDApDQp9DQoNCnBvcDIgPSBzZWxlY3RDcm9zcyhwb3AsIG5JbmQ9MTAwLCBuQ3Jvc3Nlcz0xMDAwKQ0KDQojIE9ic2VydmVkIHJlc3BvbnNlIHRvIHNlbGVjdGlvbg0KbWVhbkcocG9wMikgLSBtZWFuRyhwb3ApDQoNCiMgRXhwZWN0ZWQgcmVzcG9uc2Ugd2l0aG91dCBkaWdlbmljIGRvbWluYW5jZQ0Kc2VsSW50KHA9MC4xKSAqIHZhckEocG9wKSAvIHNxcnQodmFyUChwb3ApKQ0KDQojIEV4cGVjdGVkIHJlc3BvbnNlIHdpdGggZGlnZW5pYyBkb21pbmFuY2UgaW4gYW4gdW5zZWxlY3RlZCBwb3B1bGF0aW9uDQpzZWxJbnQocD0wLjEpICogKHZhckEocG9wKSArICgxLzMpKnZhckQocG9wKSkgLyBzcXJ0KHZhclAocG9wKSkNCg0KYGBgDQoNCiMjIFByb2dyZXNzaXZlIGhldGVyb3Npcw0KDQpUaGUgYmVsb3cgc2NyaXB0IHdpbGwgZGVtb25zdHJhdGUgdGhlIG9jY3VycmVuY2Ugb2YgcHJvZ3Jlc3NpdmUgaGV0ZXJvc2lzIGluIHRldHJhcGxvaWRzIGFuZCBpdHMgYWJzZW5jZSBpbiBkaXBsb2lkcy4gVGhpcyBzY3JpcHQgY29tZXMgZnJvbSB0aGUgQWxwaGFTaW1SX0V4YW1wbGVzIEdpdEh1YiByZXBvc2l0b3J5LiBJdCB1c2VzIDEwMCByZXBsaWNhdGlvbnMsIGJlY2F1c2UgcHJvZ3Jlc3NpdmUgaGV0ZXJvc2lzIGlzIG5vdCBhcyByZWxpYWJseSBwcmVzZW50IGFzIG1hbnkgb2YgdGhlIG90aGVyIHByb3BlcnRpZXMgdGhhdCBoYXZlIGJlZW4gcHJlc2VudGVkLg0KDQpgYGB7cn0NCmhldDJzYyA9IGhldDRzYyA9IGhldDJkYyA9IGhldDRkYyA9IG51bWVyaWMoMTAwKQ0KZm9yKFJFUCBpbiAxOjEwMCl7DQogIGZvdW5kZXJQb3AgPSBxdWlja0hhcGxvKG5JbmQ9NDAwLCBuQ2hyPTQsIHNlZ1NpdGVzPTEwMCwgcGxvaWR5PTQpDQogIA0KICBTUCA9IFNpbVBhcmFtJA0KICAgIG5ldyhmb3VuZGVyUG9wKSQNCiAgICBhZGRUcmFpdEFEKDEwMCwgbWVhbkREPTAuNiwgdmFyREQ9MC4yKSQNCiAgICBzZXRWYXJFKGgyPTAuMykNCiAgDQogICMgQ3JlYXRlIDQgdGV0cmFwbG9pZCBwb3B1bGF0aW9ucw0KICB0ZXRyYXBsb2lkID0gdmVjdG9yKCJsaXN0IiwgNCkNCiAgdGV0cmFwbG9pZFtbMV1dID0gbmV3UG9wKGZvdW5kZXJQb3BbMToxMDBdKQ0KICB0ZXRyYXBsb2lkW1syXV0gPSBuZXdQb3AoZm91bmRlclBvcFsxMDE6MjAwXSkNCiAgdGV0cmFwbG9pZFtbM11dID0gbmV3UG9wKGZvdW5kZXJQb3BbMjAxOjMwMF0pDQogIHRldHJhcGxvaWRbWzRdXSA9IG5ld1BvcChmb3VuZGVyUG9wWzMwMTo0MDBdKQ0KICANCiAgIyBDcmVhdGUgZGlwbG9pZCBwb3B1bGF0aW9ucyBmcm9tIHRldHJhcGxvaWQgcG9wdWxhdGlvbnMNCiAgZGlwbG9pZCA9IHZlY3RvcigibGlzdCIsIDQpDQogIGZvcihpIGluIDE6NCl7DQogICAgZGlwbG9pZFtbaV1dID0gcmVkdWNlR2Vub21lKHRldHJhcGxvaWRbW2ldXSkNCiAgfQ0KICANCiAgIyBQZXJmb3JtIDUgZ2VuZXJhdGlvbnMgb2YgcmVjdXJyZW50IHNlbGVjdGlvbg0KICBmb3IoZ2VuIGluIDE6NSl7IA0KICAgIGZvcihpIGluIDE6NCl7DQogICAgICB0ZXRyYXBsb2lkW1tpXV0gPSBzZWxlY3RDcm9zcyh0ZXRyYXBsb2lkW1tpXV0sIG5JbmQ9MTAsIG5Dcm9zc2VzPTEwMCkNCiAgICAgIGRpcGxvaWRbW2ldXSA9IHNlbGVjdENyb3NzKGRpcGxvaWRbW2ldXSwgbkluZD0xMCwgbkNyb3NzZXM9MTAwKQ0KICAgIH0NCiAgfQ0KICANCiAgIyBDcmVhdGUgc2luZ2xlIGNyb3NzIHBvcHVsYXRpb25zICgxLzIgYW5kIDMvNCkNCiAgdGV0cmFTQyA9IGxpc3QocmFuZENyb3NzMih0ZXRyYXBsb2lkW1sxXV0sIHRldHJhcGxvaWRbWzJdXSwgbkNyb3NzZXM9MTAwKSwNCiAgICAgICAgICAgICAgICAgcmFuZENyb3NzMih0ZXRyYXBsb2lkW1szXV0sIHRldHJhcGxvaWRbWzRdXSwgbkNyb3NzZXM9MTAwKSkNCiAgZGlwbG9pZFNDID0gbGlzdChyYW5kQ3Jvc3MyKGRpcGxvaWRbWzFdXSwgZGlwbG9pZFtbMl1dLCBuQ3Jvc3Nlcz0xMDApLA0KICAgICAgICAgICAgICAgICAgIHJhbmRDcm9zczIoZGlwbG9pZFtbM11dLCBkaXBsb2lkW1s0XV0sIG5Dcm9zc2VzPTEwMCkpDQogIA0KICAjIENyZWF0ZSBkb3VibGUgY3Jvc3MgcG9wdWxhdGlvbnMNCiAgdGV0cmFEb3VibGUgPSByYW5kQ3Jvc3MyKHRldHJhU0NbWzFdXSwgdGV0cmFTQ1tbMl1dLCBuQ3Jvc3Nlcz0xMDAwKQ0KICBkaXBsb2lkRG91YmxlID0gcmFuZENyb3NzMihkaXBsb2lkU0NbWzFdXSwgZGlwbG9pZFNDW1syXV0sIG5Dcm9zc2VzPTEwMDApDQogIA0KICAjIENhbGN1bGF0ZSBtZWFuIG9mIGFsbCBiYXNlIHBvcHVsYXRpb25zDQogIG1lYW5UZXRyYSA9IG1lYW4odW5saXN0KGxhcHBseSh0ZXRyYXBsb2lkLG1lYW5HKSkpDQogIG1lYW5EaXBsb2lkID0gbWVhbih1bmxpc3QobGFwcGx5KGRpcGxvaWQsbWVhbkcpKSkNCiAgDQogICMgQ2FsY3VsYXRlIG1lYW4gb2Ygc2luZ2xlIGNyb3NzIHBvcHVsYXRpb25zDQogIG1lYW5UZXRyYVNDID0gbWVhbih1bmxpc3QobGFwcGx5KHRldHJhU0MsbWVhbkcpKSkNCiAgbWVhbkRpcGxvaWRTQyA9IG1lYW4odW5saXN0KGxhcHBseShkaXBsb2lkU0MsbWVhbkcpKSkNCiAgDQogICMgTWVhc3VyZSBzaW5nbGUgY3Jvc3MgaGV0ZXJvc2lzDQogIGhldDRzY1tSRVBdID0gbWVhblRldHJhU0MgLSBtZWFuVGV0cmENCiAgaGV0MnNjW1JFUF0gPSBtZWFuRGlwbG9pZFNDIC0gbWVhbkRpcGxvaWQNCiAgDQogICMgTWVhc3VyZSBkb3VibGUgY3Jvc3MgaGV0ZXJvaXMNCiAgaGV0NGRjW1JFUF0gPSBtZWFuRyh0ZXRyYURvdWJsZSkgLSBtZWFuVGV0cmEgDQogIGhldDJkY1tSRVBdID0gbWVhbkcoZGlwbG9pZERvdWJsZSkgLSBtZWFuRGlwbG9pZCANCn0NCmJveHBsb3QoaGV0MmRjLGhldDJzYyxoZXQ0ZGMsaGV0NHNjLCANCiAgICAgICAgbmFtZXM9YygiRGlwbG9pZCBEIiwgIkRpcGxvaWQgUyIsDQogICAgICAgICAgICAgICAgIlRldHJhcGxvaWQgRCIsICJUZXRyYXBsb2lkIFMiKSwNCiAgICAgICAgbGFzPTIsDQogICAgICAgIG1haW49IlNpbmdsZSAoUykgdnMgRG91YmxlIChEKSBDcm9zcyBNZWFucyIpDQpib3hwbG90KGhldDJkYy1oZXQyc2MsaGV0NGRjLWhldDRzYywgDQogICAgICAgIG5hbWVzPWMoIkRpcGxvaWQiLCAiVGV0cmFwbG9pZCIpLA0KICAgICAgICBsYXM9MiwNCiAgICAgICAgbWFpbj0iUHJvZ3Jlc3NpdmUgSGV0ZXJvc2lzIikNCg0KYGBgDQoNCiMjIE90aGVyIHBvbHlwbG9pZCBiZWhhdmlvcnMNCg0KYGBge3J9DQpmb3VuZGVyUG9wID0gcXVpY2tIYXBsbyhuSW5kPTEwMCwgbkNocj0xMCwgDQogICAgICAgICAgICAgICAgICAgICAgICBzZWdTaXRlcz0xMDAwKQ0KDQpTUCA9IFNpbVBhcmFtJA0KICBuZXcoZm91bmRlclBvcCkkDQogIGFkZFRyYWl0QUQoMTAwMCwgbWVhbkREPTAuNikNCg0KZGlwbG9pZCA9IG5ld1BvcChmb3VuZGVyUG9wKQ0KDQojIENyZWF0ZSB0ZXRyYXBsb2lkcyBmcm9tIGRpcGxvaWRzDQp0ZXRyYXBsb2lkID0gZG91YmxlR2Vub21lKGRpcGxvaWQpDQp0ZXRyYXBsb2lkMiA9IHJhbmRDcm9zcyh0ZXRyYXBsb2lkLCAxMDAwKQ0KDQojIFBvbHlwbG9pZHMgcHJvZHVjZWQgYnkgZG91YmxpbmcgYXJlIHBhcnRpYWxseSBpbmJyZWQgKG5vdCBIV0UpDQptZWFuRyh0ZXRyYXBsb2lkMikgLSBtZWFuRyh0ZXRyYXBsb2lkKQ0KDQojIFlvdSBjYW4gY3Jvc3MgZGlmZmVyZW50IHBsb2lkeSBsZXZlbHMNCnRyaXBsb2lkID0gcmFuZENyb3NzMihkaXBsb2lkLCB0ZXRyYXBsb2lkLCAxMDAwKQ0KDQojIE9kZCBwbG9pZHkgbGV2ZWxzIGFyZSBkZWFkIGVuZHMNCmBgYA0KDQo=