Part 1

input<-read_lines("../../AoCData/AOC2019/Day22.txt")

For part 1, I’m manipulating the deck

This reverses the deck:

newstack<-function(d){
  rev(d)}

This cuts it (both pos & neg work)

cutdeck<-function(d,n){
  n<-n%%length(d)
  outdeck<-d
  outdeck<-c(d[-c(1:n)],d[c(1:n)])
  outdeck}

This does the “deal with increment” shuffle

dwi<-function(d,n){
  outdeck<-c()
  for(i in 1:length(d)){
    x<-((i-1)*n+1)%%length(d)
    if(x==0){x<-length(d)}
    outdeck[x]<-d[i]}
  outdeck}

This function reads in the instructions, does them all and returns a shuffled, manipulated deck

shufflepart1<-function(d,instructions){
  i<-1
  while(i<=length(instructions)){
    inst<-unlist(str_split(instructions[i]," "))
    ### if the first word is cut, cut
    if(inst[1]=="cut"){
      d<-cutdeck(d,as.numeric(inst[2]))
    ### otherwise if the second word is "into" reverse the deck
    }else if(inst[2]=="into"){
      d<-newstack(d)
    ### otherwise if the second word is "with" then deal with increment
    }else if(inst[2]=="with"){
      d<-dwi(d,as.numeric(inst[4]))
    }else{cat("Someting went wrong\n")}
    i<-i+1}
  d}

Part 1 - run this against my input & get the answer

p1<-shufflepart1(0:10006,input)
part1<-which(p1==2019)-1
part1
[1] 2604
p1<-0:10006
x<-2019
for(i in 1:10){
  p1<-shufflepart1(p1,input)
  x<-which(p1==2019)-1
  cat(x,"\n")
}
2604 
1911 
9198 
6262 
6507 
5447 
9012 
940 
7885 
5816 

Part 2 -

My attempt to use modular arithmetic:

This takes the decksize & the instructions and returns with the coefficients of the equation that would solve it in one go:

modtransform<-function(decksize,instructions){
  a<-1
  b<-0
  m<-decksize
  i<-1
  while(i<=length(instructions)){
    inst<-unlist(str_split(instructions[i]," "))
    
    ### cut
    if(inst[1]=="cut"){
      c<-1
      d<- -as.numeric(inst[2])
    ### reverse
    }else if(inst[2]=="into"){
      c<- -1
      d<- -1
    ### deal with increment
    }else if(inst[2]=="with"){
      c<- as.numeric(inst[4])
      d<- 0
    }else{cat("Someting went wrong\n")}
    a<-(a*c)%%m
    b<-(b*c+d)%%m
    i<-i+1}
  c(a,b)}

For a deck size of 10007, this is the answer:

modtransform(10007,input)
[1] 9390 7459
###

The A is 9390. The B is 7459.

For a sanity check - this is what the old method gives for the position of card 2019 the first 10 shuffles of a 10007 card deck

p1<-0:10006
x<-2019
oldmethod<-c()
for(i in 1:10){
  p1<-shufflepart1(p1,input)
  x<-which(p1==2019)-1
  oldmethod<-c(oldmethod,x)
}
oldmethod
 [1] 2604 1911 9198 6262 6507 5447 9012  940 7885 5816

And this is what the new method gives

crd<-2019
newmethod<-c()
for(i in 1:10){
crd<-(9390*crd+7459)%%10007
newmethod<-c(newmethod,crd)}
newmethod
 [1] 2604 1911 9198 6262 6507 5447 9012  940 7885 5816
cat("compare old method and new method: ", oldmethod==newmethod,"\n")
compare old method and new method:  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 

They are the same - so I think that the modular is working.

This is just the function for composing Ax+B onto Cx+D mod M

cmps<-function(a,b,c,d,m){
  a<-(a*c)%%m
  b<-((b*c)+d)%%m
  c(a,b)}

This takes the function Ax+B and raises it to the k (shuffles multiple times)

multishuffle<-function(a,b,k,decksize,t){
  c<-1
  d<-0
  while(k>0){
    if(k%%2==1){
      g<-cmps(a,b,c,d,decksize)
      c<-g[1]
      d<-g[2]}
    k<-k%/%2
  f<-cmps(a,b,a,b,decksize)
  a<-f[1]
  b<-f[2]}
  (c*t+d)%%decksize}

And again, using 10007 and card 2019 - this is where it goes for the first 10 shuffles

multishuffleversion<-c()
for(i in 1:10){multishuffleversion<-c(multishuffleversion,multishuffle(9390,7459,i,10007,2019))}

multishuffleversion
 [1] 2604 1911 9198 6262 6507 5447 9012  940 7885 5816
cat("compare new method & multishuffle: ", multishuffleversion==newmethod,"\n")
compare new method & multishuffle:  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 

So this gives the same answer

BUT!!!!!!!!!!

The question asks for the card in position 2020, not where 2020 ends up. So, it needs the inverse function

And to find that, you find the inverse of A for that deck size

### A
modinv(9390,10007)
[1] 519
### B
(modinv(9390,10007)*-7459)%%10007
[1] 1488

So, to find what card was in that position, you can use 519 & 8519 (with these instructions on a deck of 10007) To show that makes sense, try it on the first 10 shuffle positions - all of them should return 2019:

sapply(1:10,function(x){multishuffle(519,1488,x,10007,multishuffleversion[x])})
 [1] 2019 2019 2019 2019 2019 2019 2019 2019 2019 2019
multishuffle(519,1488,10,10007,2020)
[1] 9248

Exactly as expected.


So trying this with a really, really, really big deck and a lot of shuffles:

largedeck<-as.bigz("119315717514047")
largeshuffle<-as.bigz("101741582076661")
AB<-modtransform(largedeck,input)
A<-as.bigz(AB[1])
B<-as.bigz(AB[2])
A
Big Integer ('bigz') :
[1] 28480444974763
B
Big Integer ('bigz') :
[1] 104343029082553

A=28480444974763 B=104343029082553

Invert the A & B:

### A
#iA<-modinv(A,largedeck)
### B
#iB<-(modinv(A,largedeck)*-B)%%largeDeck

Using wolfram alpha - iA = 82675948719931 iB = 403183578768

iA<-as.bigz("82675948719931")
iB<-as.bigz("403183578768")

And run that through multishuffle:

multishuffle(iA,iB,largeshuffle,largedeck,2020)
Big Integer ('bigz') :
[1] 79608410258462

So, trying this backwards:

This function does the reverse of everything. It cuts backwards, it reverses (which is the same either way), it deals into backwards.

inverstrans<-function(decksize,instructions){
  a<-1
  b<-0
  m<-decksize
  i<-1
  while(i<=length(instructions)){
    inst<-unlist(str_split(instructions[i]," "))
    if(inst[1]=="cut"){
      c<-1
      d<- -as.numeric(inst[2])
    }else if(inst[2]=="into"){
      c<- -1
      d<- -1
    }else if(inst[2]=="with"){
      c<- as.numeric(inst[4])
      d<- 0
    }else{cat("Someting went wrong\n")}
    ### invert it
    invc<-modinv(c,m)%%m
    invd<- (-d*modinv(c,m))%%m
    ###
    a<-(a*invc)%%m
    b<-(b*invc+invd)%%m
    i<-i+1}
  ### realigns to be 0 indexed
  c(a,b)}

Again showing that it works with 10007

inverstrans(10007,rev(input))
[1]  519 1488

And those numbers may look familiar - because they’re the same as above. And so it’s clear that this should work

This doesn’t work on the really big deck - because I can’t run bigz through modinv

LS0tDQp0aXRsZTogIkRheSAyMiBOb3RlYm9vayINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShnbXApDQpsaWJyYXJ5KG51bWJlcnMpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGNvbGxlY3Rpb25zKQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpDQpgYGANCg0KDQojIyBQYXJ0IDENCg0KYGBge3J9DQppbnB1dDwtcmVhZF9saW5lcygiLi4vLi4vQW9DRGF0YS9BT0MyMDE5L0RheTIyLnR4dCIpDQpgYGANCg0KRm9yIHBhcnQgMSwgSSdtIG1hbmlwdWxhdGluZyB0aGUgZGVjaw0KDQpUaGlzIHJldmVyc2VzIHRoZSBkZWNrOg0KYGBge3J9DQpuZXdzdGFjazwtZnVuY3Rpb24oZCl7DQogIHJldihkKX0NCmBgYA0KDQpUaGlzIGN1dHMgaXQgKGJvdGggcG9zICYgbmVnIHdvcmspDQpgYGB7cn0NCmN1dGRlY2s8LWZ1bmN0aW9uKGQsbil7DQogIG48LW4lJWxlbmd0aChkKQ0KICBvdXRkZWNrPC1kDQogIG91dGRlY2s8LWMoZFstYygxOm4pXSxkW2MoMTpuKV0pDQogIG91dGRlY2t9DQpgYGANCg0KVGhpcyBkb2VzIHRoZSAiZGVhbCB3aXRoIGluY3JlbWVudCIgc2h1ZmZsZQ0KDQpgYGB7cn0NCmR3aTwtZnVuY3Rpb24oZCxuKXsNCiAgb3V0ZGVjazwtYygpDQogIGZvcihpIGluIDE6bGVuZ3RoKGQpKXsNCiAgICB4PC0oKGktMSkqbisxKSUlbGVuZ3RoKGQpDQogICAgaWYoeD09MCl7eDwtbGVuZ3RoKGQpfQ0KICAgIG91dGRlY2tbeF08LWRbaV19DQogIG91dGRlY2t9DQpgYGANCg0KVGhpcyBmdW5jdGlvbiByZWFkcyBpbiB0aGUgaW5zdHJ1Y3Rpb25zLCBkb2VzIHRoZW0gYWxsIGFuZCByZXR1cm5zIGEgc2h1ZmZsZWQsIG1hbmlwdWxhdGVkIGRlY2sNCg0KYGBge3J9DQpzaHVmZmxlcGFydDE8LWZ1bmN0aW9uKGQsaW5zdHJ1Y3Rpb25zKXsNCiAgaTwtMQ0KICB3aGlsZShpPD1sZW5ndGgoaW5zdHJ1Y3Rpb25zKSl7DQogICAgaW5zdDwtdW5saXN0KHN0cl9zcGxpdChpbnN0cnVjdGlvbnNbaV0sIiAiKSkNCiAgICAjIyMgaWYgdGhlIGZpcnN0IHdvcmQgaXMgY3V0LCBjdXQNCiAgICBpZihpbnN0WzFdPT0iY3V0Iil7DQogICAgICBkPC1jdXRkZWNrKGQsYXMubnVtZXJpYyhpbnN0WzJdKSkNCiAgICAjIyMgb3RoZXJ3aXNlIGlmIHRoZSBzZWNvbmQgd29yZCBpcyAiaW50byIgcmV2ZXJzZSB0aGUgZGVjaw0KICAgIH1lbHNlIGlmKGluc3RbMl09PSJpbnRvIil7DQogICAgICBkPC1uZXdzdGFjayhkKQ0KICAgICMjIyBvdGhlcndpc2UgaWYgdGhlIHNlY29uZCB3b3JkIGlzICJ3aXRoIiB0aGVuIGRlYWwgd2l0aCBpbmNyZW1lbnQNCiAgICB9ZWxzZSBpZihpbnN0WzJdPT0id2l0aCIpew0KICAgICAgZDwtZHdpKGQsYXMubnVtZXJpYyhpbnN0WzRdKSkNCiAgICB9ZWxzZXtjYXQoIlNvbWV0aW5nIHdlbnQgd3JvbmdcbiIpfQ0KICAgIGk8LWkrMX0NCiAgZH0NCmBgYA0KDQpQYXJ0IDEgLSBydW4gdGhpcyBhZ2FpbnN0IG15IGlucHV0ICYgZ2V0IHRoZSBhbnN3ZXINCg0KYGBge3J9DQpwMTwtc2h1ZmZsZXBhcnQxKDA6MTAwMDYsaW5wdXQpDQpwYXJ0MTwtd2hpY2gocDE9PTIwMTkpLTENCnBhcnQxDQoNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCnAxPC0wOjEwMDA2DQp4PC0yMDE5DQpmb3IoaSBpbiAxOjEwKXsNCiAgcDE8LXNodWZmbGVwYXJ0MShwMSxpbnB1dCkNCiAgeDwtd2hpY2gocDE9PTIwMTkpLTENCiAgY2F0KHgsIlxuIikNCn0NCmBgYA0KDQoNCg0KIyMgUGFydCAyIC0gDQoNCk15IGF0dGVtcHQgdG8gdXNlIG1vZHVsYXIgYXJpdGhtZXRpYzoNCg0KDQpUaGlzIHRha2VzIHRoZSBkZWNrc2l6ZSAmIHRoZSBpbnN0cnVjdGlvbnMgYW5kIHJldHVybnMgd2l0aCB0aGUgY29lZmZpY2llbnRzIG9mIHRoZSBlcXVhdGlvbiB0aGF0IHdvdWxkIHNvbHZlIGl0IGluIG9uZSBnbzogDQpgYGB7cn0NCm1vZHRyYW5zZm9ybTwtZnVuY3Rpb24oZGVja3NpemUsaW5zdHJ1Y3Rpb25zKXsNCiAgYTwtMQ0KICBiPC0wDQogIG08LWRlY2tzaXplDQogIGk8LTENCiAgd2hpbGUoaTw9bGVuZ3RoKGluc3RydWN0aW9ucykpew0KICAgIGluc3Q8LXVubGlzdChzdHJfc3BsaXQoaW5zdHJ1Y3Rpb25zW2ldLCIgIikpDQogICAgDQogICAgIyMjIGN1dA0KICAgIGlmKGluc3RbMV09PSJjdXQiKXsNCiAgICAgIGM8LTENCiAgICAgIGQ8LSAtYXMubnVtZXJpYyhpbnN0WzJdKQ0KICAgICMjIyByZXZlcnNlDQogICAgfWVsc2UgaWYoaW5zdFsyXT09ImludG8iKXsNCiAgICAgIGM8LSAtMQ0KICAgICAgZDwtIC0xDQogICAgIyMjIGRlYWwgd2l0aCBpbmNyZW1lbnQNCiAgICB9ZWxzZSBpZihpbnN0WzJdPT0id2l0aCIpew0KICAgICAgYzwtIGFzLm51bWVyaWMoaW5zdFs0XSkNCiAgICAgIGQ8LSAwDQogICAgfWVsc2V7Y2F0KCJTb21ldGluZyB3ZW50IHdyb25nXG4iKX0NCiAgICBhPC0oYSpjKSUlbQ0KICAgIGI8LShiKmMrZCklJW0NCiAgICBpPC1pKzF9DQogIGMoYSxiKX0NCg0KYGBgDQoNCg0KRm9yIGEgZGVjayBzaXplIG9mIDEwMDA3LCB0aGlzIGlzIHRoZSBhbnN3ZXI6DQpgYGB7cn0NCm1vZHRyYW5zZm9ybSgxMDAwNyxpbnB1dCkNCiMjIw0KYGBgDQpUaGUgQSBpcyA5MzkwLiAgVGhlIEIgaXMgNzQ1OS4NCg0KRm9yIGEgc2FuaXR5IGNoZWNrIC0gdGhpcyBpcyB3aGF0IHRoZSBvbGQgbWV0aG9kIGdpdmVzIGZvciB0aGUgcG9zaXRpb24gb2YgY2FyZCAyMDE5IHRoZSBmaXJzdCAxMCBzaHVmZmxlcyBvZiBhIDEwMDA3IGNhcmQgZGVjaw0KDQpgYGB7cn0NCnAxPC0wOjEwMDA2DQp4PC0yMDE5DQpvbGRtZXRob2Q8LWMoKQ0KZm9yKGkgaW4gMToxMCl7DQogIHAxPC1zaHVmZmxlcGFydDEocDEsaW5wdXQpDQogIHg8LXdoaWNoKHAxPT0yMDE5KS0xDQogIG9sZG1ldGhvZDwtYyhvbGRtZXRob2QseCkNCn0NCm9sZG1ldGhvZA0KYGBgDQoNCg0KQW5kIHRoaXMgaXMgd2hhdCB0aGUgbmV3IG1ldGhvZCBnaXZlcw0KYGBge3J9DQpjcmQ8LTIwMTkNCm5ld21ldGhvZDwtYygpDQpmb3IoaSBpbiAxOjEwKXsNCmNyZDwtKDkzOTAqY3JkKzc0NTkpJSUxMDAwNw0KbmV3bWV0aG9kPC1jKG5ld21ldGhvZCxjcmQpfQ0KbmV3bWV0aG9kDQoNCmNhdCgiY29tcGFyZSBvbGQgbWV0aG9kIGFuZCBuZXcgbWV0aG9kOiAiLCBvbGRtZXRob2Q9PW5ld21ldGhvZCwiXG4iKQ0KDQoNCmBgYA0KVGhleSBhcmUgdGhlIHNhbWUgLSBzbyBJIHRoaW5rIHRoYXQgdGhlIG1vZHVsYXIgaXMgd29ya2luZy4NCg0KDQpUaGlzIGlzIGp1c3QgdGhlIGZ1bmN0aW9uIGZvciBjb21wb3NpbmcgQXgrQiBvbnRvIEN4K0QgbW9kIE0NCmBgYHtyfQ0KY21wczwtZnVuY3Rpb24oYSxiLGMsZCxtKXsNCiAgYTwtKGEqYyklJW0NCiAgYjwtKChiKmMpK2QpJSVtDQogIGMoYSxiKX0NCmBgYA0KDQoNClRoaXMgdGFrZXMgdGhlIGZ1bmN0aW9uIEF4K0IgYW5kIHJhaXNlcyBpdCB0byB0aGUgayAoc2h1ZmZsZXMgbXVsdGlwbGUgdGltZXMpDQpgYGB7cn0NCm11bHRpc2h1ZmZsZTwtZnVuY3Rpb24oYSxiLGssZGVja3NpemUsdCl7DQogIGM8LTENCiAgZDwtMA0KICB3aGlsZShrPjApew0KICAgIGlmKGslJTI9PTEpew0KICAgICAgZzwtY21wcyhhLGIsYyxkLGRlY2tzaXplKQ0KICAgICAgYzwtZ1sxXQ0KICAgICAgZDwtZ1syXX0NCiAgICBrPC1rJS8lMg0KICBmPC1jbXBzKGEsYixhLGIsZGVja3NpemUpDQogIGE8LWZbMV0NCiAgYjwtZlsyXX0NCiAgKGMqdCtkKSUlZGVja3NpemV9DQoNCmBgYA0KDQoNCkFuZCBhZ2FpbiwgdXNpbmcgMTAwMDcgYW5kIGNhcmQgMjAxOSAtIHRoaXMgaXMgd2hlcmUgaXQgZ29lcyBmb3IgdGhlIGZpcnN0IDEwIHNodWZmbGVzDQpgYGB7cn0NCg0KbXVsdGlzaHVmZmxldmVyc2lvbjwtYygpDQpmb3IoaSBpbiAxOjEwKXttdWx0aXNodWZmbGV2ZXJzaW9uPC1jKG11bHRpc2h1ZmZsZXZlcnNpb24sbXVsdGlzaHVmZmxlKDkzOTAsNzQ1OSxpLDEwMDA3LDIwMTkpKX0NCg0KbXVsdGlzaHVmZmxldmVyc2lvbg0KDQpjYXQoImNvbXBhcmUgbmV3IG1ldGhvZCAmIG11bHRpc2h1ZmZsZTogIiwgbXVsdGlzaHVmZmxldmVyc2lvbj09bmV3bWV0aG9kLCJcbiIpDQoNCmBgYA0KU28gdGhpcyBnaXZlcyB0aGUgc2FtZSBhbnN3ZXINCg0KQlVUISEhISEhISEhIQ0KDQpUaGUgcXVlc3Rpb24gYXNrcyBmb3IgdGhlIGNhcmQgaW4gcG9zaXRpb24gMjAyMCwgbm90IHdoZXJlIDIwMjAgZW5kcyB1cC4gIFNvLCBpdCBuZWVkcyB0aGUgaW52ZXJzZSBmdW5jdGlvbg0KDQpBbmQgdG8gZmluZCB0aGF0LCB5b3UgZmluZCB0aGUgaW52ZXJzZSBvZiBBIGZvciB0aGF0IGRlY2sgc2l6ZQ0KDQpgYGB7cn0NCiMjIyBBDQptb2RpbnYoOTM5MCwxMDAwNykNCiMjIyBCDQoobW9kaW52KDkzOTAsMTAwMDcpKi03NDU5KSUlMTAwMDcNCmBgYA0KU28sIHRvIGZpbmQgd2hhdCBjYXJkIHdhcyBpbiB0aGF0IHBvc2l0aW9uLCB5b3UgY2FuIHVzZSA1MTkgJiA4NTE5ICh3aXRoIHRoZXNlIGluc3RydWN0aW9ucyBvbiBhIGRlY2sgb2YgMTAwMDcpDQpUbyBzaG93IHRoYXQgbWFrZXMgc2Vuc2UsIHRyeSBpdCBvbiB0aGUgZmlyc3QgMTAgc2h1ZmZsZSBwb3NpdGlvbnMgLSBhbGwgb2YgdGhlbSBzaG91bGQgcmV0dXJuIDIwMTk6DQoNCmBgYHtyfQ0Kc2FwcGx5KDE6MTAsZnVuY3Rpb24oeCl7bXVsdGlzaHVmZmxlKDUxOSwxNDg4LHgsMTAwMDcsbXVsdGlzaHVmZmxldmVyc2lvblt4XSl9KQ0KYGBgDQpgYGB7cn0NCm11bHRpc2h1ZmZsZSg1MTksMTQ4OCwxMCwxMDAwNywyMDIwKQ0KYGBgDQoNCg0KRXhhY3RseSBhcyBleHBlY3RlZC4NCg0KLS0tLQ0KDQpTbyB0cnlpbmcgdGhpcyB3aXRoIGEgcmVhbGx5LCByZWFsbHksIHJlYWxseSBiaWcgZGVjayBhbmQgYSBsb3Qgb2Ygc2h1ZmZsZXM6DQoNCmBgYHtyfQ0KbGFyZ2VkZWNrPC1hcy5iaWd6KCIxMTkzMTU3MTc1MTQwNDciKQ0KbGFyZ2VzaHVmZmxlPC1hcy5iaWd6KCIxMDE3NDE1ODIwNzY2NjEiKQ0KYGBgDQoNCg0KYGBge3J9DQpBQjwtbW9kdHJhbnNmb3JtKGxhcmdlZGVjayxpbnB1dCkNCkE8LWFzLmJpZ3ooQUJbMV0pDQpCPC1hcy5iaWd6KEFCWzJdKQ0KQQ0KQg0KDQpgYGANCkE9Mjg0ODA0NDQ5NzQ3NjMNCkI9MTA0MzQzMDI5MDgyNTUzDQoNCg0KSW52ZXJ0IHRoZSBBICYgQjoNCmBgYHtyfQ0KIyMjIEENCiNpQTwtbW9kaW52KEEsbGFyZ2VkZWNrKQ0KIyMjIEINCiNpQjwtKG1vZGludihBLGxhcmdlZGVjaykqLUIpJSVsYXJnZURlY2sNCg0KYGBgDQpVc2luZyB3b2xmcmFtIGFscGhhIC0gaUEgPSA4MjY3NTk0ODcxOTkzMQ0KaUIgPSA0MDMxODM1Nzg3NjgNCg0KDQpgYGB7cn0NCmlBPC1hcy5iaWd6KCI4MjY3NTk0ODcxOTkzMSIpDQppQjwtYXMuYmlneigiNDAzMTgzNTc4NzY4IikNCmBgYA0KDQoNCkFuZCBydW4gdGhhdCB0aHJvdWdoIG11bHRpc2h1ZmZsZToNCg0KYGBge3J9DQptdWx0aXNodWZmbGUoaUEsaUIsbGFyZ2VzaHVmZmxlLGxhcmdlZGVjaywyMDIwKQ0KYGBgDQoNCg0KDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KU28sIHRyeWluZyB0aGlzIGJhY2t3YXJkczoNCg0KVGhpcyBmdW5jdGlvbiBkb2VzIHRoZSByZXZlcnNlIG9mIGV2ZXJ5dGhpbmcuICBJdCBjdXRzIGJhY2t3YXJkcywgaXQgcmV2ZXJzZXMgKHdoaWNoIGlzIHRoZSBzYW1lIGVpdGhlciB3YXkpLCBpdCBkZWFscyBpbnRvIGJhY2t3YXJkcy4NCg0KDQoNCg0KDQpgYGB7cn0NCmludmVyc3RyYW5zPC1mdW5jdGlvbihkZWNrc2l6ZSxpbnN0cnVjdGlvbnMpew0KICBhPC0xDQogIGI8LTANCiAgbTwtZGVja3NpemUNCiAgaTwtMQ0KICB3aGlsZShpPD1sZW5ndGgoaW5zdHJ1Y3Rpb25zKSl7DQogICAgaW5zdDwtdW5saXN0KHN0cl9zcGxpdChpbnN0cnVjdGlvbnNbaV0sIiAiKSkNCiAgICBpZihpbnN0WzFdPT0iY3V0Iil7DQogICAgICBjPC0xDQogICAgICBkPC0gLWFzLm51bWVyaWMoaW5zdFsyXSkNCiAgICB9ZWxzZSBpZihpbnN0WzJdPT0iaW50byIpew0KICAgICAgYzwtIC0xDQogICAgICBkPC0gLTENCiAgICB9ZWxzZSBpZihpbnN0WzJdPT0id2l0aCIpew0KICAgICAgYzwtIGFzLm51bWVyaWMoaW5zdFs0XSkNCiAgICAgIGQ8LSAwDQogICAgfWVsc2V7Y2F0KCJTb21ldGluZyB3ZW50IHdyb25nXG4iKX0NCiAgICAjIyMgaW52ZXJ0IGl0DQogICAgaW52YzwtbW9kaW52KGMsbSklJW0NCiAgICBpbnZkPC0gKC1kKm1vZGludihjLG0pKSUlbQ0KICAgICMjIw0KICAgIGE8LShhKmludmMpJSVtDQogICAgYjwtKGIqaW52YytpbnZkKSUlbQ0KICAgIGk8LWkrMX0NCiAgIyMjIHJlYWxpZ25zIHRvIGJlIDAgaW5kZXhlZA0KICBjKGEsYil9DQpgYGANCg0KQWdhaW4gc2hvd2luZyB0aGF0IGl0IHdvcmtzIHdpdGggMTAwMDcNCg0KYGBge3J9DQppbnZlcnN0cmFucygxMDAwNyxyZXYoaW5wdXQpKQ0KYGBgDQpBbmQgdGhvc2UgbnVtYmVycyBtYXkgbG9vayBmYW1pbGlhciAtIGJlY2F1c2UgdGhleSdyZSB0aGUgc2FtZSBhcyBhYm92ZS4gIEFuZCBzbyBpdCdzIGNsZWFyIHRoYXQgdGhpcyBzaG91bGQgd29yaw0KDQoNClRoaXMgZG9lc24ndCB3b3JrIG9uIHRoZSByZWFsbHkgYmlnIGRlY2sgLSBiZWNhdXNlIEkgY2FuJ3QgcnVuIGJpZ3ogdGhyb3VnaCBtb2RpbnYNCg==