Components and supplies
Arduino Due
Project description
Code
Processing & java for the factory simulator
processing
This is the laptop based factory simulator.
1// TODO ---- FOR THE FACTORY 2// delete factories from the lists 3// box factory onto the projector 4// takes 2 uploads to get going 5// double name from serial creates a factory !!! clear the read fryden state.... 6// bug when 1st uploading - a com port has crap left in it uncleaned 7// add a delete key to remove a factory 8// comment blocks 9 10import processing.serial.*; 11import java.nio.ByteBuffer; 12import java.util.*; 13 14int factorySel = 0; 15int factorySpeed = 8; 16 17PGraphics pg; 18PImage machineImg; 19PImage robotImg; 20PImage greenTruckImg; 21PImage redTruckImg; 22PImage inspectorImg; 23PImage panelImg; 24PImage frydenImg; 25 26float xmax = 400; 27float ymax = 400; 28float xmin = xmax * -1; 29float ymin = ymax * -1; 30 31int ms; 32 33String[] boxNames = new String[5]; 34 35ArrayList<Serial> recievers = new ArrayList<Serial>(); 36HashMap<String,Integer> nameCnts = new HashMap<String,Integer>(); 37HashMap<String,dueParams> data = new HashMap<String,dueParams>(); 38HashMap<String,factory> factories = new HashMap<String,factory>(); 39 40color gRed = color(192,0,0); // R 41color gOrange = color(180,60,7); // O 42color gYellow = color(150,150,0); // Y 43color gBlue = color(0,0,192); // B 44color gPurple = color(192,0,192); // P 45color gGreen = color(0,192,0); // G 46color gTeal = color(94,192,192); // T 47color gBlack = color(0,0,0); // B 48color gWhite = color(180,180,180); // W 49 50 51void setup() { 52 size(3500,2000,P2D); 53 54 pg = createGraphics(1100,500); 55 56 String ports[] = Serial.list(); 57 println(ports); 58 for (int i=0; i<ports.length; i++) { 59 recievers.add(new Serial(this, ports[i], 115200)); 60 } 61 delay(2000); 62 63 Iterator<Serial> itr = recievers.iterator(); 64 while (itr.hasNext()) { 65 Serial s = itr.next(); 66 while (s.available() > 0) { 67 char c = s.readChar(); 68 print(c); 69 delay(1); 70 } 71 s.clear(); 72 } 73 println(); 74 println(); 75 76 machineImg = loadImage("machine.PNG"); 77 robotImg = loadImage("robot.PNG"); 78 greenTruckImg = loadImage("greentruck.PNG"); 79 redTruckImg = loadImage("redtruck.PNG"); 80 inspectorImg = loadImage("inspector.jpg"); 81 panelImg = loadImage("panel.jpg"); 82 frydenImg = loadImage("fryden.png"); 83 84 ms = 0; 85 86 87} 88 89void draw() { 90 91 // check for upload conenctions 92 if (millis() - ms > 3000) { 93 readFrydens(); 94 ms = millis(); 95 } 96 97 // run the factories 98 for (String k: factories.keySet()) { 99 factory f = factories.get(k); 100 dueParams dp = data.get(k); 101 int nc = nameCnts.get(k); 102 if (nc > f.lastUpload) { 103 f.upLoaded = true; 104 f.lastUpload = nc; 105 106 float[] w = new float[3]; 107 w[0] = dp.nnWeights[0]; 108 w[1] = dp.nnWeights[1]; 109 w[2] = dp.nnWeights[2]; 110 f.ptron.setWeights(w); 111 f.ptron.c = dp.nnLearningC; 112 f.goodBoxRadius = dp.goodBoxRadius ; 113 f.trainCycles = dp.trainCycles; 114 f.totalTrainingExamples = dp.totalTrainingExamples; 115 f.totalCorrect = dp.totalCorrect; 116 f.workModeAverage = dp.workModeAverage; 117 f.workModeBest = dp.workModeBest; 118 119 } 120 121 // check to see if a new upload has happened 122 123 if (f.upLoaded) { 124 f.run(); 125 } 126 } 127 128 background(0); 129 130 131 if (factories.size() > 0) { 132 133 // fetch the selected factory 134 factory f = factories.get(boxNames[factorySel]); 135 136 if (f.upLoaded) { 137 renderFactory(f); 138 } else { 139 textSize(150); 140 text("brain not yet uploaded",1000,600); 141 } 142 143 dueParams dp = data.get(boxNames[factorySel]); 144 // glyph 145 pushMatrix(); 146 translate(50,200); 147 String ss = "A "; 148 ss += dp.guildName; 149 ss += " factory"; 150 fill(255); 151 textSize(60); 152 text(ss,0,0); 153 for (int x=0; x<8; x++) { 154 for (int y=0; y<8; y++) { 155 color c = color(0,0,0); 156 switch (dp.guildGlyph[x][y]) { 157 case 'R': 158 c = gRed; 159 break; 160 case 'O': 161 c = gOrange; 162 break; 163 case 'Y': 164 c = gYellow; 165 break; 166 case 'B': 167 c = gBlue; 168 break; 169 case 'T': 170 c = gTeal; 171 break; 172 case 'G': 173 c = gGreen; 174 break; 175 case 'P': 176 c = gPurple; 177 break; 178 case 'W': 179 c = gWhite; 180 break; 181 case ' ': 182 c =gBlack; 183 break; 184 default: 185 c = gBlack; 186 break; 187 } 188 fill(c); 189 stroke(0); 190 strokeWeight(5); 191 rect(80+x*40,70+y*40,40,40); 192 } 193 } 194 popMatrix(); 195 196 image(frydenImg, 2800, 1200, 1276*0.5,1400*0.5); 197 198 199 // score lines 200 pushMatrix(); 201 202 translate(50,1000); 203 204 stroke(128); 205 strokeWeight(8); 206 line(0,600,2500,600); 207 textSize(35); 208 fill(128); 209 for (int xm=30; xm<=100; xm+=10) { 210 float xmp = (xm-25) * (2500/75); 211 text(xm+"%",xmp,560); 212 } 213 214 int yp =0; 215 for (String k: factories.keySet()) { 216 f = factories.get(k); 217 218 // plot min 25% to 100% - into 2500 pixels 219 float score = f.score; 220 if (score<25.0) 221 score = 25; 222 223 float xPos = (score-25) * (2500/75); 224 225 pushMatrix(); 226 227 translate(0,600); 228 fill(255); 229 stroke(255); 230 strokeWeight(4); 231 ellipse(xPos,0,40,40); 232 233 if (!f.name.equals(boxNames[factorySel])) { 234 line(xPos,0,xPos,yp*70+60); 235 textSize(50); 236 fill(255); 237 text(f.name,xPos+10,yp*70+60); 238 } 239 240 if (f.name.equals(boxNames[factorySel])) { 241 fill(255,255,0); 242 line(xPos,0,xPos,-500); 243 textSize(100); 244 text(f.name,xPos+10,-400); 245 246 fill(255); 247 String s = "Accuracy = " + String.format("%.0f", f.score) + "%"; 248 textSize(60); 249 text(s,xPos+10,-320); 250 s = "Score = " + f.correct + " out of " + f.inspected; 251 text(s,xPos+10,-240); 252 s = "Training exmaples = " + (f.trainCycles*5); 253 text(s,xPos+10,-160); 254 255 } 256 257 popMatrix(); 258 259 yp++; 260 } 261 262 popMatrix(); 263 264 } else { 265 textSize(150); 266 text("no brains uploaded!",1000,600); 267 } 268 269 270} 271 272 273 274 275 276void renderFactory(factory f) { 277 278 pushMatrix(); 279 280 translate(2800,ymax+200); 281 282 textSize(30); 283 // draw the boundary / box gen circles 284 strokeWeight(2); 285 stroke(0,128,0); 286 noFill(); 287 ellipse(-400,400,f.goodBoxRadius*800,f.goodBoxRadius*800); 288 stroke(128,0,0); 289 noFill(); 290 ellipse(400,-400,f.goodBoxRadius*800,f.goodBoxRadius*800); 291 292 // draw the graphs, and the descision lines 293 strokeWeight(2); 294 stroke(128); 295 float x1 = xmin; 296 float y1 = f(x1,-1,0); 297 float x2 = xmax; 298 float y2 = f(x2,-1,0); 299 line(x1,-1*y1,x2,-1*y2); 300 301 302 // Draw the line based on the current weights 303 // Formula is weights[0]*x + weights[1]*y + weights[2] = 0 304 stroke(200,200,0); 305 strokeWeight(2); 306 float[] weights = f.ptron.getWeights(); 307 x1 = xmin; 308 y1 = (-weights[2] - weights[0]*x1)/weights[1]; 309 x2 = xmax; 310 y2 = (-weights[2] - weights[0]*x2)/weights[1]; 311 // trap div 0 and >>> inf. 312 if (y1 > 32000) y1 = 32000; 313 if (y1 < -32000) y1 = -32000; 314 if (y2 > 32000) y2 = 32000; 315 if (y2 < -32000) y2 = -32000; 316 line(x1,-1*y1,x2,-1*y2); 317 318 //blank out some stuff 319 fill(0); 320 noStroke(); 321 rect(-1200,-400,800,800); 322 rect(-1200,400,2800,1200); 323 rect(-800,-800,2800,400); 324 rect(400,-400,800,800); 325 326 327 //draw and label the axis 328 stroke(255); 329 strokeWeight(8); 330 line(-405,405,-405,-405); 331 line(-405,405,405,405); 332 fill(255); 333 text("small",-405,439); 334 text("large",350,439); 335 text("green",-498,400); 336 text("red",-470,-390); 337 338 // plot the data 339 noStroke(); 340 for (int i=0; i<f.boxes.size(); i++) { 341 box b = f.boxes.get(i); 342 343 float c = ((b.col+1)/2)*255; 344 345 fill(c,255-c,0); 346 rect(b.xs, -1*b.ys, (b.size+1)*25,(b.size+1)*25); 347 348 if (b.classified) { 349 if (b.classification==1) { 350 fill(255,0,0); 351 text("large red",b.xs+(b.size+1)*13,(-1*b.ys)); 352 } 353 else { 354 fill(0,255,0); 355 text("small green",b.xs+(b.size+1)*13,(-1*b.ys)); 356 } 357 } 358 else { 359 fill(255); 360 text("not tested",b.xs+(b.size+1)*13,(-1*b.ys)); 361 } 362 363 } 364 365 popMatrix(); 366 367 368 pg.beginDraw(); 369 370 pg.background(0); 371 372 // draw the inpectors 373 pg.image(inspectorImg, 800, 385-135*0.6, 90*0.6,135*0.6); 374 pg.image(inspectorImg, 800, 385-150*0.8-135*0.6, 90*0.6,135*0.6); 375 pg.noFill(); 376 pg.stroke(200); 377 pg.strokeWeight(5); 378 pg.rect(800, 385-135*0.6, 90*0.6,135*0.6); 379 pg.rect(800, 385-150*0.8-135*0.6, 90*0.6,135*0.6); 380 381 // draw the boxes 382 pg.stroke(192); 383 pg.strokeWeight(2); 384 for (int i=0; i<f.boxes.size(); i++) { 385 box b = f.boxes.get(i); 386 float c = ((b.col+1)/2)*255; 387 pg.fill(c,255-c,0); 388 if (b.classification == 0 || b.classification == -1) 389 pg.rect(b.xPos, 400-15-((b.size+1)*25), (b.size+1)*25,(b.size+1)*25); 390 else 391 pg.rect(b.xPos, 400-15-((b.size+1)*25) - (150*.8), (b.size+1)*25,(b.size+1)*25); 392 393 //text(b.xs,b.xPos-25, 500); 394 //text(b.ys,b.xPos-25, 520); 395 } 396 397 //draw the front conveyor 398 pg.fill(128); 399 pg.stroke(200); 400 pg.strokeWeight(5); 401 pg.rect(0,400-15,505,15); 402 403 //draw the back conveyors 404 pg.fill(128); 405 pg.stroke(200); 406 pg.strokeWeight(5); 407 pg.rect(505,400-15,365,15); 408 pg.rect(505,400-150*0.8-15,365,15); 409 410 //draw the machine 411 pg.tint(255, 127); 412 pg.image(machineImg, 0, 400-163, 250,163); 413 pg.noFill(); 414 pg.stroke(200); 415 pg.strokeWeight(15); 416 pg.rect(0,400-163,250,163); 417 pg.noTint(); 418 419 // draw the panel 420 pg.image(panelImg, 482,0, 540*0.35,580*0.35); 421 422 // draw the robot 423 pg.tint(255, 200); 424 pg.image(robotImg, 500, 400-200, 150,200); 425 pg.noFill(); 426 pg.stroke(200); 427 pg.strokeWeight(15); 428 pg.rect(500, 400-200, 150,200); 429 pg.noTint(); 430 431 // draw the green truck 432 pg.image(greenTruckImg, 875, 425-150*0.8, 260*0.8,150*0.8); 433 434 // draw the red truck 435 pg.image(redTruckImg, 875, 425-300*0.8, 260*0.8,150*0.8); 436 437 // draw the matrix 438 int gridSize = 102; 439 int xPos = 527; 440 int yPos = 48; 441 float ledSpace = (gridSize / 8); 442 float ledSize = ((gridSize / 8) * 0.7); 443 444 float bs = (f.currentBoxSize+1)*4; 445 int bsInt = (int) floor(bs); 446 float rc = (f.currentBoxCol+1)/2; 447 float gc = 1-((f.currentBoxCol+1)/2); 448 float bc = 0; 449 rc*=255; 450 gc*=255; 451 bc*=255; 452 453 pg.noStroke(); 454 pg.fill(64); 455 pg.rect(xPos,yPos+ledSize,gridSize,gridSize); 456 457 for (int c=0; c<8; c++) { 458 for (int r=0; r<8; r++) { 459 pg.fill(0); 460 pg.rect(c*ledSpace+xPos+ledSize/2,gridSize + yPos - (r*ledSpace) - ledSize/2,ledSize,ledSize); 461 } 462 } 463 464 for (int c=0; c<bsInt; c++) { 465 for (int r=0; r<bsInt; r++) { 466 pg.fill(color(rc,gc,bc)); 467 pg.rect(c*ledSpace+xPos+ledSize/2,gridSize + yPos - (r*ledSpace) - ledSize/2,ledSize,ledSize); 468 } 469 } 470 471 if (bsInt<8) { 472 for (int r=0; r<bsInt+1; r++) { 473 int c = bsInt; 474 pg.fill(color(rc*(bs-bsInt),gc*(bs-bsInt),bc*(bs-bsInt))); 475 pg.rect(c*ledSpace+xPos+ledSize/2,gridSize + yPos - (r*ledSpace) - ledSize/2,ledSize,ledSize); 476 } 477 for (int c=0; c<bsInt+1; c++) { 478 int r = bsInt; 479 pg.fill(color(rc*(bs-bsInt),gc*(bs-bsInt),bc*(bs-bsInt))); 480 pg.rect(c*ledSpace+xPos+ledSize/2,gridSize + yPos - (r*ledSpace) - ledSize/2,ledSize,ledSize); 481 } 482 } 483 484 // show the current guess on the LCD 485 pg.fill(64,128,255); 486 pg.textSize(15); 487 String g = ""; 488 if (f.currentGuess == -1) 489 g = "Small Green"; 490 else if (f.currentGuess == 1) 491 g = "Large Red"; 492 pg.text(g,532,39); 493 494 495 496 pg.endDraw(); 497 498 image(pg, 50, 200,1100*1.9,500*1.9); 499 500} 501 502 503void keyPressed() { 504 if (key == CODED) { 505 if (keyCode == UP) { 506 factorySel++; 507 if (factorySel == factories.size()) 508 factorySel = 0; 509 } else if (keyCode == DOWN) { 510 factorySel--; 511 if (factorySel < 0) 512 factorySel = factories.size()-1; 513 } else if (keyCode == LEFT) { 514 factorySpeed--; 515 if (factorySpeed < 1) 516 factorySpeed = 1; 517 setSpeeds(); 518 } else if (keyCode == RIGHT) { 519 factorySpeed++; 520 if (factorySpeed > 30) 521 factorySpeed = 30; 522 setSpeeds(); 523 } 524 } else { 525 526 if (key == 'r' || key == 'R') 527 resetScores(); 528 529 } 530} 531 532void setSpeeds() { 533 for (String k: factories.keySet()) { 534 factory f = factories.get(k); 535 f.setSpeed(factorySpeed); 536 } 537} 538 539void resetScores() { 540 for (String k: factories.keySet()) { 541 factory f = factories.get(k); 542 f.resetScores(); 543 } 544} 545 546 547float f(float x,float m, float c) { 548 return m*x+c; 549} 550 551// time out after s.avail - 1 seconds 552 553 554void readFrydens() { 555 556 Iterator<Serial> itr = recievers.iterator(); 557 while (itr.hasNext()) { 558 Serial s = itr.next(); 559 560 String state = "SoS"; 561 char inByteT0 = '-'; 562 char inByteT1 = '-'; 563 char inByteT2 = '-'; 564 boolean done = false; 565 boolean complete = false; 566 int expN = 20; 567 int nCnt = 0; 568 String name = ""; 569 int expG = 20; 570 int gCnt = 0; 571 String guild = ""; 572 573 boolean avail = false; 574 int ms = millis(); 575 576 int glCnt = 0; 577 int expGl = 64; 578 char[][] glyphIn = new char[8][8]; 579 580 int plCnt = 0; 581 int expPl = 40; 582 byte[] paramsIn = new byte[40]; 583 584 585 while ((s.available() > 0) && !done) { 586 587 if (!avail) { 588 ms = millis(); 589 avail = true; 590 } 591 592 if (millis()-ms > 5000) { 593 done = true; 594 } 595 596 inByteT2 = inByteT1; 597 inByteT1 = inByteT0; 598 inByteT0 = s.readChar(); 599 600 switch(state) { 601 case "SoS": 602 if (inByteT0 == 'S' && inByteT1 == 'o' && inByteT2 == 'S') { 603 state = "Name"; 604 nCnt = 0; 605 name = ""; 606 } 607 break; 608 case "Name": 609 name += inByteT0; 610 nCnt++; 611 if (nCnt == expN) { 612 state = "Guild"; 613 gCnt = 0; 614 guild = ""; 615 } 616 break; 617 case "Guild": 618 guild += inByteT0; 619 gCnt++; 620 if (gCnt == expG) { 621 state = "Glyph"; 622 glCnt = 0; 623 } 624 break; 625 case "Glyph": 626 int x = glCnt%8; 627 int y = glCnt>>3; 628 glyphIn[x][y] = inByteT0; 629 glCnt++; 630 if (glCnt == expGl) { 631 state = "Params"; 632 plCnt = 0; 633 } 634 break; 635 case "Params": 636 paramsIn[plCnt] = (byte) inByteT0; 637 plCnt++; 638 if (plCnt == expPl) { 639 done = true; 640 complete = true; 641 } 642 break; 643 default: 644 break; 645 } 646 delay(1); 647 } 648 649 if (complete) { 650 name = name.trim(); 651 guild = guild.trim(); 652 println("Processing"); 653 if (data.containsKey(name)) { 654 nameCnts.put(name, nameCnts.get(name) + 1); 655 dueParams dp = data.get(name); 656 dp.bytesToParams(paramsIn); 657 dp.boxName = name; 658 dp.guildName = guild; 659 dp.guildGlyph = glyphIn; 660 data.put(name,dp); 661 } else { 662 // we have a new box so create the entries in the tables 663 if (factories.size()<5) { 664 factory f = new factory(name); 665 factories.put(name,f); 666 nameCnts.put(name,0); 667 dueParams dp = new dueParams(); 668 dp.bytesToParams(paramsIn); 669 dp.boxName = name; 670 dp.guildName = guild; 671 dp.guildGlyph = glyphIn; 672 data.put(name,dp); 673 boxNames[factories.size()-1] = name; 674 } 675 } 676 } 677 678 if (avail) { 679 println("***Serial Acticity***"); 680 println(s.port); 681 println(complete); 682 println(name); 683 } 684 685 } 686 687} 688 689 690/* 691void readFrydens() { 692 693 boolean readName = false; 694 boolean readGuild = false; 695 boolean readGlyph = false; 696 boolean readFloats = false; 697 //boolean inState = false; 698 boolean skipByte; 699 //boolean haveWeights = false; 700 String nameIn = ""; 701 String guildIn = ""; 702 int expChars = 64; 703 char[][] glyphIn = new char[8][8]; 704 int expBytes = 40; 705 byte[] bytesIn = new byte[40]; 706 707 char inByte = '0'; 708 char lastByte = '0'; 709 int numBytes = 0; 710 int numChars = 0; 711 712 713 Iterator<Serial> itr = recievers.iterator(); 714 while (itr.hasNext()) { 715 Serial s = itr.next(); 716 717 readName = false; 718 readGuild = false; 719 readGlyph = false; 720 readFloats = false; 721 inByte = '0'; 722 lastByte = '0'; 723 nameIn = ""; 724 guildIn = ""; 725 numChars = 0; 726 numBytes = 0; 727 728 729 println("**********************"); 730 731 while (s.available() > 0) { 732 733 lastByte = inByte; 734 inByte = s.readChar(); 735 skipByte = false; 736 737 if (lastByte == '~' && inByte == '^') { 738 readName = true; 739 readGuild = false; 740 readGlyph = false; 741 readFloats = false; 742 nameIn = ""; 743 } 744 if (lastByte == '^' && inByte == '~') { 745 readName = false; 746 readGuild = false; 747 readGlyph = false; 748 readFloats = false; 749 } 750 if (lastByte == '#' && inByte == '!') { 751 readName = false; 752 readGuild = true; 753 readGlyph = false; 754 readFloats = false; 755 guildIn = ""; 756 } 757 if (lastByte == '!' && inByte == '#') { // end of guild name - beg. of glyph 758 readName = false; 759 readGuild = false; 760 readGlyph = true; 761 readFloats = false; 762 skipByte = true; 763 numChars = 0; 764 } 765 if ((numChars == expChars) && (!readFloats)) { // end of glyph - beg. of bytes 766 readName = false; 767 readGuild = false; 768 readGlyph = false; 769 readFloats = true; 770 numBytes = 0; 771 numChars = 0; 772 } 773 774 775 if (!skipByte) { 776 777 if (readName) { 778 nameIn += inByte; 779 println("fomr name"); 780 println(nameIn); 781 println(guildIn); 782 } else if (readGuild) { 783 guildIn += inByte; 784 println("formguild"); 785 println(nameIn); 786 println(guildIn); 787 } else if (readGlyph) { 788 int x = numChars%8; 789 int y = numChars>>3; 790 glyphIn[x][y] = inByte; 791 numChars++; 792 println("assemble glyph"); 793 println(nameIn); 794 println(guildIn); 795 } else if (readFloats) { 796 bytesIn[numBytes++] = (byte) inByte; 797 // PROCESS ALL the BYTES we have collected 798 if (numBytes == expBytes) { 799 readFloats = false; 800 readName = false; 801 readGuild = true; 802 readGlyph = false; 803 readFloats = false; 804 numChars = 0; 805 numBytes = 0; 806 println("conv bytes"); 807 println(nameIn); 808 println(guildIn); 809 nameIn = nameIn.substring(1,nameIn.length()-1); 810 guildIn = guildIn.substring(1,guildIn.length()-1); 811 if (data.containsKey(nameIn)) { 812 nameCnts.put(nameIn, nameCnts.get(nameIn) + 1); 813 dueParams dp = data.get(nameIn); 814 dp.bytesToParams(bytesIn); 815 dp.boxName = nameIn; 816 dp.guildName = guildIn; 817 dp.guildGlyph = glyphIn; 818 data.put(nameIn,dp); 819 } else { 820 // we have a new box so create the entries in the tables 821 if (factories.size()<5) { 822 factory f = new factory(nameIn); 823 factories.put(nameIn,f); 824 nameCnts.put(nameIn,0); 825 dueParams dp = new dueParams(); 826 dp.bytesToParams(bytesIn); 827 dp.boxName = nameIn; 828 dp.guildName = guildIn; 829 dp.guildGlyph = glyphIn; 830 data.put(nameIn,dp); 831 boxNames[factories.size()-1] = nameIn; 832 } 833 } 834 }// PROCESS BYTES 835 } // read floats 836 837 }// skip byte 838 839 840 delay(1); 841 } 842 843 844 845 846 } 847 848}*/
more processing code...
processing
1// Daniel Shiffman 2// The Nature of Code 3// http://www.shiffman.net/teaching/nature 4// Simple Perceptron Example 5// See: http://en.wikipedia.org/wiki/Perceptron 6 7// Perceptron Class 8 9class perceptron { 10 float[] weights; // Array of weights for inputs 11 float c; // learning constant 12 13 // Perceptron is created with n weights and learning constant 14 perceptron(int n, float c_) { 15 weights = new float[n]; 16 // Start with random weights 17 //for (int i = 0; i < weights.length; i++) { 18 // weights[i] = random(-1,1); 19 //} 20 // fix the wieghts to give the 50/50 case 21 weights[0] = -1; 22 weights[1] = 1; 23 weights[2] = 0; 24 c = c_; 25 } 26 27 // Function to train the Perceptron 28 // Weights are adjusted based on "desired" answer 29 void train(float[] inputs, int desired) { 30 // Guess the result 31 int guess = feedforward(inputs); 32 // Compute the factor for changing the weight based on the error 33 // Error = desired output - guessed output 34 // Note this can only be 0, -2, or 2 35 // Multiply by learning constant 36 float error = desired - guess; 37 // Adjust weights based on weightChange * input 38 for (int i = 0; i < weights.length; i++) { 39 weights[i] += c * error * inputs[i]; 40 } 41 } 42 43 // Guess -1 or 1 based on input values 44 int feedforward(float[] inputs) { 45 // Sum all values 46 float sum = 0; 47 for (int i = 0; i < weights.length; i++) { 48 sum += inputs[i]*weights[i]; 49 } 50 // Result is sign of the sum, -1 or 1 51 return activate(sum); 52 } 53 54 int activate(float sum) { 55 if (sum > 0) return 1; 56 else return -1; 57 } 58 59 // Return weights 60 float[] getWeights() { 61 return weights; 62 } 63 64 void setWeights(float[] weights) { 65 for (int i=0; i<weights.length; i++) { 66 this.weights[i] = weights[i]; 67 } 68 } 69}
more processing code...
processing
1// Daniel Shiffman 2// The Nature of Code 3// http://www.shiffman.net/teaching/nature 4// Simple Perceptron Example 5// See: http://en.wikipedia.org/wiki/Perceptron 6 7// Perceptron Class 8 9class perceptron { 10 float[] weights; // Array of weights for inputs 11 float c; // learning constant 12 13 // Perceptron is created with n weights and learning constant 14 perceptron(int n, float c_) { 15 weights = new float[n]; 16 // Start with random weights 17 //for (int i = 0; i < weights.length; i++) { 18 // weights[i] = random(-1,1); 19 //} 20 // fix the wieghts to give the 50/50 case 21 weights[0] = -1; 22 weights[1] = 1; 23 weights[2] = 0; 24 c = c_; 25 } 26 27 // Function to train the Perceptron 28 // Weights are adjusted based on "desired" answer 29 void train(float[] inputs, int desired) { 30 // Guess the result 31 int guess = feedforward(inputs); 32 // Compute the factor for changing the weight based on the error 33 // Error = desired output - guessed output 34 // Note this can only be 0, -2, or 2 35 // Multiply by learning constant 36 float error = desired - guess; 37 // Adjust weights based on weightChange * input 38 for (int i = 0; i < weights.length; i++) { 39 weights[i] += c * error * inputs[i]; 40 } 41 } 42 43 // Guess -1 or 1 based on input values 44 int feedforward(float[] inputs) { 45 // Sum all values 46 float sum = 0; 47 for (int i = 0; i < weights.length; i++) { 48 sum += inputs[i]*weights[i]; 49 } 50 // Result is sign of the sum, -1 or 1 51 return activate(sum); 52 } 53 54 int activate(float sum) { 55 if (sum > 0) return 1; 56 else return -1; 57 } 58 59 // Return weights 60 float[] getWeights() { 61 return weights; 62 } 63 64 void setWeights(float[] weights) { 65 for (int i=0; i<weights.length; i++) { 66 this.weights[i] = weights[i]; 67 } 68 } 69}
more processing code...
processing
1 2 3 4 5class dueParams { 6 7String boxName; 8String guildName; 9float[] nnWeights = new float[3]; 10float nnLearningC; 11int trainCycles; 12int totalTrainingExamples; 13int totalCorrect; 14float workModeAverage; 15int workModeBest; 16float goodBoxRadius; 17char[][] guildGlyph = new char[8][8]; 18 19 dueParams() { 20 21 } 22 23 void bytesToParams(byte[] params) { 24 25 int i=0; 26 int temp; 27 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 28 nnLearningC = Float.intBitsToFloat(temp); 29 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 30 goodBoxRadius = Float.intBitsToFloat(temp); 31 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 32 nnWeights[0] = Float.intBitsToFloat(temp); 33 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 34 nnWeights[1] = Float.intBitsToFloat(temp); 35 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 36 nnWeights[2] = Float.intBitsToFloat(temp); 37 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 38 workModeAverage = Float.intBitsToFloat(temp); 39 trainCycles = (int)(((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 40 totalCorrect = (int)(((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 41 totalTrainingExamples = (int)(((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 42 workModeBest = (int)(((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 43 44 } 45 46 47}
more processing code...
processing
1 2import java.util.Iterator; 3 4class factory { 5 6 ArrayList<box> boxes = new ArrayList<box>(); 7 String name; 8 9 int trainCycles; 10 int totalTrainingExamples; 11 int totalCorrect; 12 float workModeAverage; 13 int workModeBest; 14 15 perceptron ptron; 16 int correct = 0; 17 int inspected = 0; 18 float score = 0; 19 20 int lastUpload = 0; 21 22 float currentBoxSize = -1; 23 float currentBoxCol = 0; 24 int currentGuess = 0; 25 26 // run time params 27 int speed = 12; 28 float cMax = 400; 29 float goodBoxRadius = 1.1; 30 31 boolean upLoaded; 32 33 factory(String name) { 34 35 this.name = name; 36 //this.goodBoxRadius = goodBoxRadius; 37 ///this.cMax = cMax; 38 39 ptron = new perceptron(3, 0.0001); 40 boolean upLoaded = false; 41 42 } 43 44 void run() { 45 46 // make new boxes 47 if (boxes.size() < 1) 48 makeNewBox(); 49 else { 50 box b = boxes.get(boxes.size()-1); 51 if (b.xPos - b.size > 100) 52 makeNewBox(); 53 } 54 55 //update all boxes 56 for (int i=0; i<boxes.size(); i++) { 57 box b = boxes.get(i); 58 // move the box along 59 b.incBoxPosX(speed); 60 // is the box in the truck? if so then kill it 61 if (b.xPos > 900) { 62 b.killBox(); 63 } 64 // is the box in the inspector 65 if (b.xPos > 800 && !b.inspected) { 66 inspected++; 67 if (b.answer == b.classification) 68 correct++; 69 score = 100.0 * float(correct)/float(inspected); 70 b.addInspection(); 71 } 72 // is the box in the robot? if so then classifiy it 73 if (b.xPos > 550 && !b.classified) { 74 float[] vecIn = {b.xs,b.ys,1.0}; 75 int c = ptron.feedforward(vecIn); 76 b.addClassifier(c); 77 currentBoxSize = b.size; 78 currentBoxCol = b.col; 79 currentGuess = c; 80 } 81 } 82 83 // finally remove any killed boxes 84 Iterator<box> boxesIterator = boxes.iterator(); 85 while (boxesIterator.hasNext()) { 86 box b = boxesIterator.next(); 87 if (b.kill) 88 boxesIterator.remove(); 89 } 90 91 } 92 93 void makeNewBox() { 94 box b = new box(0, height/2, cMax, goodBoxRadius); 95 boxes.add(b); 96 } 97 98 void setSpeed(int speed) { 99 this.speed = speed; 100 } 101 102 void resetScores() { 103 correct = 0; 104 inspected = 0; 105 } 106}
fryden-due-boxfactory-camp-v1.76.ino
c_cpp
This is the main Arduino application used in: http://www.fryden-learning.com/box-facto
1binary |- DQpTdHJpbmcgdmVyTnVtID0gInYxLjc2IjsNCi8vIEZJWEVEIGNhbXAgZXJyb3JzDQoNCi8vICoqKioqKioqKlRPRE8gZHVlDQovLyB1c2UganNvbiBvciB4bWwgdG8gc2VuZCBkYXRhIHRvIHRoZSBzaW11bGF0b3INCi8vIA0KLy8gdGVzdCB0aGUgc2VyaWFsIHR4IHN0YXRlIG1hY2hpbmUgd2l0aCByYW5kb20gZGVsYXlzIGFuZCBub2lzZQ0KLy8gZml4IHJlc2V0IG1vZGUgLSBtYWtlIHN1cmUgZXZlcnl0aGluZyByZXNldHMgc28gd2UgZG9udCBoYXZlIHRvIHB1bGwgdGhlIGZsYXNoIGNhcmQNCi8vICh0ZXh0IGZvciByZWQgdG8gZXhpdD8gb24gdHJhaW5pbmcvd29yayBtb2RlcykNCi8vIHBsYW4gdG8gcHJlcCBhbGwgdGhlIGZsYXNoIGNhcmRzLi4uKGRlbGV0ZSBzZXR0aW5ncyBmaWxlIHRvIGVuc3VyZSBpdCBib290cykNCi8vIGF1dG9kZWN0IGkyYyBhZGRyZXNzIGFuZCBhdXRvIGNvbmZpZyBvbiBib290IC0gbm90IHN1cmUgdGhpcyBpcyBwb3NzaWJsZQ0KLy8gY2FsaWJyYXRlIGRpYWxzIHRvIDUxMiBhdCB0aGUgY2VudGVyDQovLyBzY3JlZW4gc2F2ZSAtIGJ1bmNoZXMgYXQgdGhlIHRvcD8NCi8vIGluc3RydWN0aW9ucyB0ZXh0IGludG8gdGhlIG1vZGUgT1IgcHVsbCBpbnN0cnVjdGlvbnMgbW9kZS4NCi8vIGNvbW1lbnQgYmxvY2tzIGFib3ZlIGFsbCBmdW5jdGlvbnMgYW5kIG5hbWVzIGF0IHRoZSB0b3AgdG8gc2VhcmNoIGFnYWluc3QNCi8vIGJvaW5nIHNjb3JlIC0gY2FwdHVyZSAyIHNjb3J3cyBiYXNlZCBvbiBsZW5ndGggb2YgcmFsbHkgYW5kIHdobyBkcm9wcGVkIHRoZSBiYWxsDQovLyBOT1QgRE9ORSAtIHdhdiAtIGZpbGVzIHBsYWNlaG9sZGVycyBmb3IgYWxsIC0gd2VsY29tZSB0byB0aGUgZnJ5ZGVuIGF1ZGlvDQovLyBOT1QgRE9ORSAtIHdhdiAtIGF1ZGlvIGludGVydXB0IGNvbGxpc2lvbnMgd2hlbiB1c2luZyB0aGUgd2F2ZmlsZSBwYWx5ZXIgYW5kIHRoZSB0b25lIGxpYi4uLi4NCi8vIE5PVCBET05FIC0gd2F2IC0gcmVtZW1iZXIgcGxheXdhdnMgaW4gdGhlIHNldHRpbmdzDQovLyBOT1QgRE9ORSAtIHRyaWNreSAtIHNoYXBlIHRoZSBjb2xvcnMgdG8gbWFrZSB0aGUgbWlkIGNhc2Ugb2Ygb3JhbmdlIGJldHRlciB0byBzZWUgLSBsZXNzIGdyZWVuLi4uDQovLyBET05FIC0gQlVHIC0gc2V0dGluZyBndWlsZCBQT1Qgc2VsZWN0cyBhIGJsYW5rIG9wdGlvbi4NCi8vIERPTkUgLSBCVUcgLSBlbnRlcm5hbWUgLSBjbGVhciBzY3JlZW4NCi8vIERPTkUgLSBzdG9wIHNlbmRpbmcgYWZ0ZXIgNSB1cGxvYWQgYXR0ZW10cw0KLy8gRE9ORSAtIHJlZGVzaWduIGEgc2FmZXIgc3RhdGUgbWFjaGluZSBmb3IgdGhlIHJlY2lldmUgYnl0ZXMNCi8vIERPTkUgLSBwbGFjZWhvbGRlciBmb3Igd2VsY29tZSB0dW5lLg0KLy8gRE9ORSAtIGFsbCBwYXJhbXMgdG8gZmlsZSBzZXIvZGUtc2VyIGFjY3Jvc3MgdGhlIHNlcmlhbCBsaW5rIGluYy4gZ2x5cGhzDQovLyBET05FIC0gbmFtZXMgLSBaQVBQQSBTWU5USCAmIGJvaW5nDQovLyBET05FIC0gbWFrZSB0aGUgYmluYXJ5IHNhdmUgdG8gZmlsZSBmb3IgaWYgd2Ugd2FudCB0byBzYXZlIGVkaXRlZCBnbHlwaHMNCi8vIERPTkUgLSBsb2NrIHN5bWJvbHMgb3ZlciB3cml0ZSB0aGUgbWVudSBiYXIgYnkgd3JhcHBpbmcgYXJvdW5kDQovLyBET05FIC0gbG9jayBzeW1ib2wgYXBwZWFycyBvbiBzdGV0dGluZ3MgbWVudQ0KLy8gRE9ORSAtIGxpZ3RoZW5pbmcgc3BlbHQgd3JvbmcNCi8vIERPTkUgLSBzY3JlZW4gc2F2ZSB4IHNlY3MgYWZ0ZXIgdGhlIG1lbnUgaW50ZXJhY3Rpb25zDQovLyBET05FIC0gbW9yZSBwaHJhc2VzIGludG8gdGhlICJ0aGFua3MgZm9yIHRlYWNoaW5nIG1lIiAieWVzIGkga25vdy4uLiINCi8vIERPTkUgLSBwb25nIHNvdW5kcw0KLy8gRE9ORSAtIGRpYWwgZm9yIDAuOCB0byAxLjQgPSBiZSBhYmxlIHRvIGNoYW5nZSBsZWFybmluZyByYXRlIGFuZCBnYlJhZGl1cyBieSBzZXR0aW5ncyAtIGdicmFkaXVzIG1ha2VzIHRoZSBnYW1lIGhhcmRlcg0KLy8gRE9ORSAtIG1ha2UgdGhlIGdseXBoIGNvbG9ycyBjb25zdGFudHMuDQovLyBET05FIC0gYmFzaWMgc3lzbnRoIGNvZGUgbmVlZHMgYWRkaW5nDQovLyBET05FIC0gc3ludGggLSBtYWtlIDIgb24gdGhlIGpveXN0aWNrLi4uDQovLyBET05FIC0gc2NyZWVuIHNhdmUgbWVzc2FnZXMgLSBjb2RlIGFuZCB2b2NhYiBhbnN3ZXJzDQovLyBET05FIC0gY3VzdG9tIGdseXBoIG9uIHN0YXJ0IHNjcmVlbiAmIExFRCBtYXRyaXguDQovLyBET05FIC0gYWRkIHRoZSBndWlsZCBuYW1lcyB0byB0aGUgbmFtZSAvIGRlc2NyaXB0aW9uIGFsbCB0aGUgd2F5IHRocm91Z2ggdG8gdGhlIHNpbWx1YXRvciAvIGd1aWxkIGNvbWVzIGFmdGVyIG5hbWluZw0KLy8gRE9ORSAtIGVudGVyIGN1c3RvbSBuYW1lIGluIHNldHRpbmdzIC0tIC8vIHNldHRpbmdzIC0gYWRkIG5hbWUgZnJvbSBhIGZpbGUgLy8gYWRkIHlvdSBvd24gbmFtZSBmb3IgY3VzdG9tIG5hbWVzIC0gcmVzZXQgLSBpZiBuZXZlciBzZXQgdGhlbiBzZXQgaXQgDQovLyBET05FIC0gbmFtZSBmbG93IC0gdW5uYW1lZCAtIG11c3QgZm9yY2UgbmFtaW5nIGFmdGVyIHJlc2V0DQovLyBET05FIC0gZ3VpbGQgbmFtZSBpbnRvIHNldHRpbmdzDQovLyBET05FIC0gb24gcG93ZXIgdXAgYW5kIGZsYXNoIHRoZSBndWlsZCBzeW1ib2xzIGFuZCBzYXkgIkkgYW0uLi4iIG9mIHRoZQ0KLy8gRE9ORSAtIGNsZWFyIHRoZSBuZW8gcGl4ZWwgb24gc3RhcnQgdXANCi8vIERPTkUgLSBwdXQgTXIgQnJ5ZGVucyBnbHlwaHMgaW4uDQoNCi8vICoqKioqKioqKipOb3RlcyBhbmQgb3RoZXIgbGVzcyBjcml0aWNhbCB0b2RvJ3MNCi8vIEJPRVIgLSBuZWVkcyBhIGZhY3RvcnkgcmVzdGV0IHRvIGJlIHJlcHJvZ3JhbW1lZC4uLi4NCi8vIENyYXNoIG9uIHByb2Nlc3NpbmcgQVBQIGlmIGl0IHJlYWRzIGNvcnJ1b3QgZGF0YSAtIG5lZWRzIHRvIHJlY292ZXINCi8vIHVwZ3JhZGUgdHdvIHByb3RvcyB0byB3b3JrIG9uIFBDQiB2ZXJzaW9ucw0KLy8gU3RhdGUgb2YgbWluZCBjcmFzaGVkIGZvciBzb21lIHJlYXNvbiAtIG1heSBoYXZlIGJlZW4gdGhlIH5+IG5hbWUgbWFya2Vycz8NCi8vIE5PVEUgLSA1IHRyYWluZyBzZXRzIGF0IDAuMDAwMSwgMS4yIHRvIGdldCAxMDAlDQovLyBkZXNpZ24gYW5kIGRvYyB0aGUgZmFzdGVzdCB0ZXN0IHBsYW4gYXQgdGhpcyByYXRlLg0KLy8gYWRkIGEgZmFjdG9yeSByZXNldCAtIG9uIGJvb3QgLSB0byByZXNldCB0aGUgZmlsZSBzeXN0ZW0NCi8vIGlkZWxseSBtYWtlIGEgc3BsaXQyMCBmdW5jdGlvbiBmb3IgZWFzaWVyIHRleHQgY3JlYXRpb24gLSBoYXJkIC0gbmVlZHMgdG8gZmluZCBzcGFjZXMgIA0KLy8gbGluZXJhaXplIGpveXN0aWNrIG1hcCBwb3RlbmRzIDItMTAyMA0KLy8gcmVkbyBhbGwgdGhlIHNvdW5kcyB0byBhdm9pZCBsb3cgZnJlcSdzIC8vIG1ha2UgbmV3IGxlYXJuaW5nIHNvdW5kIGZvciB0aGUgbm4ncw0KLy8gY2hhbmdlIG5uIHRvIHBlcmNlcHRyb24gLSB0ZXh0IGFuZCBjb2RlDQovLyBtYWtlIHN1cmUgeW91IGNhbnQgYWRkIG1vcmUgdGhhbiAxNiBtZW51cyBvciAzMiBwYWdlcyBsaW5lcyAtIGFuZCB0ZXN0IGl0DQovLyBmaW5kIGFuZCByZW1vdmUgYWxsIGRlYnVnIHByaW50bG5zIC8vIGNoZWNrIHRoZSBzZXJpYWwgcG9ydCBmb3IgYWN0dml0aXR5DQovLyB0ZXN0IFNEIGNhcmQgaW5pdCBmYWlsIG1lc3NhZ2Ugb24gTENEDQovLyBmdW5jdGlvbiBncm91cGluZywgY29kaW5nLCBjb21tZW50aW5nIGFuZCB0aWR5aW5nDQovLyBnbyBhbGwgdGhyb3VnaCBkZWxheSBhbmQgY29zdGFudHMgaW4gdGhlIGNvZGUgYW5kICNkZWZpbmUNCi8vIFBlcmNlcHJvdG4gbm90ZXM6IHByZWRpY3Rpb24gMSA9IGxhcmdlIHJlZCAgICAtMSA9IHNtYWxsIGdyZWVuDQovLyBib3ggc2l6ZS9jb2xvciByYW5nZXMNCi8vIGJveFNpemUgPSAwLi4zMSA7IDMyIHN0ZXBzIDsgOCBsZWRzIHggNCBsZXZlbCBvZiBicmlndGhuZXNzIA0KLy8gY29sVmFsID0gbWF4IDMyICsgMTI4ID0gMzIuLjE1OSA7IHdvcmtzIGJlc3QgZm9yIG5lb3BpeGVsIGRpc3BsYXkgDQoNClN0cmluZyBib3hOYW1lID0gIkJSQUlOIEJPWCI7DQpTdHJpbmcgYm94R3VpbGQgPSAiTklOSkEiOw0KDQovL0R1ZSBib2FyZC9zaGllbGQgSU8NCiNkZWZpbmUgcG90TGVmdCBBMA0KI2RlZmluZSBwb3RDZW50ZXIgQTENCiNkZWZpbmUgcG90UmlnaHQgQTINCiNkZWZpbmUgcmVkQnV0dG9uIDQNCiNkZWZpbmUgZ3JlZW5CdXR0b24gMw0KI2RlZmluZSBibHVlQnV0dG9uIDINCiNkZWZpbmUgam95SCBBNA0KI2RlZmluZSBqb3lCdXR0b24gNQ0KI2RlZmluZSBqb3lWIEE1DQojZGVmaW5lIGFtcEVuYWJsZSBBMw0KI2RlZmluZSBzZENzIDM4DQojZGVmaW5lIG5lb1Bpbk1hdHJpeCA3IA0KI2RlZmluZSBuZW9QaW5TaW5nbGUgNiANCg0KLy8gYXBwIHBhcmFtcyANCiNkZWZpbmUgYnV0dG9uUmVsZWFzZURlbGF5IDE1MA0KI2RlZmluZSBMQ0RzY3JvbGxTcGVlZCAyMDANCiNkZWZpbmUgTkVPc2Nyb2xsU3BlZWQgNzUNCiNkZWZpbmUgbWFrZUJveER1cmF0aW9uIDIwMDANCiNkZWZpbmUgbWFrZUJveER1cmF0aW9uQnkyIDEwMDANCi8vI2RlZmluZSBtYWtlU291bmQgdHJ1ZQ0KI2RlZmluZSBhbmFseXplQm94RHVyYXRpb24gMTUwMA0KLy8jZGVmaW5lIGFuYWx5emVCb3hEdXJhdGlvbkJ5MiA3NTANCiNkZWZpbmUgdHJhaW5Cb3hEdXJhdGlvbiAyMDAwDQovLyNkZWZpbmUgdHJhaW5Cb3hEdXJhdGlvbkJ5MiA3NTANCiNkZWZpbmUgY01heCA0MDANCiNkZWZpbmUgbGVhcm5pbmdSYXRlIDAuMDAwMQ0KDQojaW5jbHVkZSA8V2lyZS5oPg0KI2luY2x1ZGUgPExpcXVpZENyeXN0YWxfUENGODU3NC5oPg0KI2luY2x1ZGUgPEFkYWZydWl0X05lb01hdHJpeC5oPg0KI2luY2x1ZGUgPEFkYWZydWl0X05lb1BpeGVsLmg+DQojaW5jbHVkZSA8U0QuaD4NCiNpbmNsdWRlIDxTUEkuaD4NCiNpbmNsdWRlIDxBdWRpby5oPg0KDQplbnVtIHBvdFBvc3Rpb24gew0KICBsZWZ0LA0KICByaWdodCwNCiAgY2VudGVyDQp9OyANCg0KZW51bSBidXR0b25Db2xvciB7DQogIGJsdWUsDQogIHJlZCwNCiAgZ3JlZW4sDQogIGpveSwNCiAgYW55DQp9OyANCi8vSkYtDQpMaXF1aWRDcnlzdGFsX1BDRjg1NzQgbGNkKDB4M0YpOyAgLy8gc2V0IHRoZSBMQ0QgYWRkcmVzcw0KLy9MaXF1aWRDcnlzdGFsX1BDRjg1NzQgbGNkKDB4MjcpOyAgLy8gc2V0IHRoZSBMQ0QgYWRkcmVzcw0KDQpBZGFmcnVpdF9OZW9NYXRyaXggbWF0cml4ID0gQWRhZnJ1aXRfTmVvTWF0cml4KDgsIDgsIG5lb1Bpbk1hdHJpeCwNCiAgTkVPX01BVFJJWF9MRUZUICAgICArIE5FT19NQVRSSVhfVE9QICsNCiAgTkVPX01BVFJJWF9ST1dTICsgTkVPX01BVFJJWF9QUk9HUkVTU0lWRSwNCiAgTkVPX0dSQiAgICAgICAgICAgICsgTkVPX0tIWjgwMCk7DQoNCkFkYWZydWl0X05lb1BpeGVsIGxlZHMgPSBBZGFmcnVpdF9OZW9QaXhlbCgxLCBuZW9QaW5TaW5nbGUsIE5FT19SR0IgKyBORU9fS0haODAwKTsNCg0KdW5zaWduZWQgbG9uZyBzY3JvbGxORU9NaWxsaVNlYzsNClN0cmluZyBzY3JvbGxORU9NZXNzYWdlID0gIi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uIjsNCmludCBzY3JvbGxORU9NZXNzYWdlUmVzZXQ7DQppbnQgc2Nyb2xsTkVPTWVzc2FnZVBvczsNCnVpbnQxNl90IHNjcm9sbE5FT0NvbG9yOw0KDQp1bnNpZ25lZCBsb25nIGxhc3RQcmVzc2VkOw0KDQpmbG9hdCBnb29kQm94UmFkaXVzID0gMS4xOw0KaW50IHRyYWluQ3ljbGVzID0gMDsNCmludCB0b3RhbFRyYWluaW5nRXhhbXBsZXMgPSAwOw0KaW50IHRvdGFsQ29ycmVjdCA9IDA7DQpmbG9hdCB3b3JrTW9kZUF2ZXJhZ2UgPSAwOw0KaW50IHdvcmtNb2RlQmVzdCA9IDA7DQoNCi8vIG1lbnUgJiB0ZXh0LXBhZ2VzIGdsb2JhbHMNCnVuc2lnbmVkIGxvbmcgbGFzdFJlYWQgPSAwOw0KZW51bSBqb3lWRGlyIHsNCiAgZG93biwNCiAgdXAsDQogIG1pZGRsZQ0KfTsgDQpTdHJpbmcgYnMgPSAiICAgICAgICAgICAgICAgICAgICAgICI7DQpqb3lWRGlyIHBvc05vdyA9IG1pZGRsZTsNCmpveVZEaXIgcG9zTGFzdCA9IG1pZGRsZTsNCmludCBlbnRyeVNlbD0wOw0KaW50IG1lbnVOdW1FbnRyaWVzPTA7DQpTdHJpbmcgbWVudUVudHJpZXNbMTZdID0ge2JzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzfTs7DQpTdHJpbmcgbWVudUhlYWRpbmc7DQpib29sZWFuIG1lbnVVcGRhdGVMQ0Q7DQppbnQgcGFnZU51bUVudHJpZXM9MDsNClN0cmluZyBwYWdlRW50cmllc1szMl0gPSB7YnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnN9Ow0KU3RyaW5nIHBhZ2VIZWFkaW5nOw0KYm9vbGVhbiBwYWdlVXBkYXRlTENEOw0KDQovLyBpbml0aWFsaXplIHRoZSBuZXVyYWwgbmV0IHdhaXRzIGFuZCBsZWFybmluZyBjb25zdGFudA0KZmxvYXQgbm5XZWlnaHRzWzNdID0gey0xLjAsMS4wLDAuMH07DQpmbG9hdCBubkxlYXJuaW5nQyA9IGxlYXJuaW5nUmF0ZTsNCg0KLy8gbWFpbiBtZW51IG9wdGlvbnMNCiNkZWZpbmUgbWFpbk1lbnVTaXplIDkNCi8vIi0tLS0tLS0tLS0tLS0tLS0tIiAxNyBjaGFyIHJlZg0KU3RyaW5nIG1haW5NZW51RW50cmllc1ttYWluTWVudVNpemVdID0gew0KICAiU2hvdyBicmFpbiBzdGF0ZSIsDQogICJUcmFpbmluZyBtb2RlIiwNCiAgIldvcmsgbW9kZSIsDQogICJVcGxvYWQgdG8gZmFjdG9yeSIsDQogICJBbmFseXplIG1vZGUiLA0KICAiUGxheSBCb2luZyIsDQogICJaYXBwYSBTeW50aCIsDQogICJJbnN0cnVjdGlvbnMiLA0KICAiU2V0dGluZ3MiDQp9Ow0KDQpib29sZWFuIG1lbnVMb2Nrc1ttYWluTWVudVNpemVdID0gezAsMCwwLDAsMCwxLDEsMCwwfTsNCi8vYm9vbGVhbiBtZW51TG9ja3NbbWFpbk1lbnVTaXplXSA9IHswLDAsMCwwLDAsMCwwLDAsMH07DQojZGVmaW5lIHBvbmdMb2NrIDUNCiNkZWZpbmUgc3ludGhMb2NrIDYNCg0KLy8iLS0tLS0tLS0tLS0tLS0tLS0iIDE3IGNoYXIgcmVmDQojZGVmaW5lIHNldHRpbmdzTWVudVNpemUgNg0KU3RyaW5nIHNldHRpbmdzTWVudUVudHJpZXNbbWFpbk1lbnVTaXplXSA9IHsNCiAgIlZvbHVtZSIsDQogICJTZXQgZGlmZmljdWx0eSIsDQogICJOYW1lIHRoZSBicmFpbiIsDQogICJSZXNldCBicmFpbiIsDQogICJBYm91dCIsDQogICJNYWluIG1lbnUiDQp9Ow0KDQplbnVtIG1vZGVUeXBlIHsNCiAgd2VsY29tZSwNCiAgd29yaywNCiAgYnJhaW5zdGF0ZSwNCiAgbWVudSwNCiAgdHJhaW4sDQogIGFuYWx5emUsDQogIGZhY3RvcnksDQogIHNldHRpbmdzLA0KICBpbnN0cnVjdGlvbnMsDQogIHBvbmcsDQogIHN5bnRoDQp9Ow0KbW9kZVR5cGUgbW9kZSA9IHdlbGNvbWU7DQpTdHJpbmcgbW9kZURlc2M7IA0KDQojZGVmaW5lIFNJTkVfU0FNUExFUyA4ODIgLy8gNDQuMWtoeiAvIDUwaHogPSA4ODIgc2FtcGxlcyBuZWVkIGZvciBhIGZ1bGwgNTAgaHogc2luZSB3YXZlDQp1aW50MTZfdCBzaW5lV2F2ZVtTSU5FX1NBTVBMRVNdOw0KLy8gdGhlIHBoYXNlIGFjY3VtdWxhdG9yIHBvaW50cyB0byB0aGUgY3VycmVudCBzYW1wbGUgaW4gb3VyIHdhdmV0YWJsZQ0KdWludDMyX3QgdWxQaGFzZUFjY3VtdWxhdG9yQSA9IDA7DQp1aW50MzJfdCB1bFBoYXNlQWNjdW11bGF0b3JCID0gMDsNCi8vIHRoZSBwaGFzZSBpbmNyZW1lbnQgY29udHJvbHMgdGhlIHJhdGUgYXQgd2hpY2ggd2UgbW92ZSB0aHJvdWdoIHRoZSB3YXZlIHRhYmxlDQovLyBoaWdoZXIgdmFsdWVzID0gaGlnaGVyIGZyZXF1ZW5jaWVzDQp2b2xhdGlsZSB1aW50MzJfdCB1bFBoYXNlSW5jcmVtZW50QSA9IDA7ICAgLy8gMzIgYml0IHBoYXNlIGluY3JlbWVudCwgc2VlIGJlbG93DQp2b2xhdGlsZSB1aW50MzJfdCB1bFBoYXNlSW5jcmVtZW50QiA9IDA7ICAgLy8gMzIgYml0IHBoYXNlIGluY3JlbWVudCwgc2VlIGJlbG93DQovLyBmdWxsIHdhdmVmb3JtID0gMCB0byBTQU1QTEVTX1BFUl9DWUNMRQ0KLy8gUGhhc2UgSW5jcmVtZW50IGZvciAxIEh6ID0oU0FNUExFU19QRVJfQ1lDTEVfRklYRURQT0lOVC9TQU1QTEVfUkFURSkgPSAxSHoNCi8vIFBoYXNlIEluY3JlbWVudCBmb3IgZnJlcXVlbmN5IEYgPSAoU0FNUExFU19QRVJfQ1lDTEUvU0FNUExFX1JBVEUpKkYNCiNkZWZpbmUgU0FNUExFX1JBVEUgNDQxMDAuMA0KI2RlZmluZSBTQU1QTEVTX1BFUl9DWUNMRSA4ODINCiNkZWZpbmUgU0FNUExFU19QRVJfQ1lDTEVfRklYRURQT0lOVCAoU0FNUExFU19QRVJfQ1lDTEU8PDIwKQ0KI2RlZmluZSBUSUNLU19QRVJfQ1lDTEUgKGZsb2F0KSgoZmxvYXQpU0FNUExFU19QRVJfQ1lDTEVfRklYRURQT0lOVC8oZmxvYXQpU0FNUExFX1JBVEUpDQojZGVmaW5lIE1JRElfTk9URVMgMTI4DQp1aW50MzJfdCBuTWlkaVBoYXNlSW5jcmVtZW50W01JRElfTk9URVNdOw0KZmxvYXQgdG9uZU1peEE7DQpmbG9hdCB0b25lTWl4QjsgDQpib29sZWFuIHBsYXlEdWFsID0gZmFsc2U7DQoNCnVuc2lnbmVkIGxvbmcgdFRpbWU7DQppbnQgdER1cmF0aW9uOw0KYm9vbGVhbiB0b25lQWN0aXZlID0gZmFsc2U7DQoNCmJvb2xlYW4gc2RJbml0ID0gZmFsc2U7DQoNCiNkZWZpbmUgcGFyYW1MZW4gNDANCmJ5dGUgcGFyYW1zW3BhcmFtTGVuXTsNCmJvb2xlYW4gbG9hZGVkU2V0dGluZ3MgPSBmYWxzZTsNCg0KaW50IHZvbHVtZSA9IDM7DQoNClN0cmluZyBndWlsZE5hbWVzWzNdID0geyJOSU5KQSIsIlBIT0VOSVgiLCJMSUdIVE5JTkcifTsNCg0KY29uc3QgdWludDMyX3QgZ1JlZCA9IG1hdHJpeC5Db2xvcigxMjgsMCwwKTsgICAgICAgIC8vIFIgDQpjb25zdCB1aW50MzJfdCBnT3JhbmdlID0gbWF0cml4LkNvbG9yKDEyMCw0MCwyKTsgICAgLy8gTw0KY29uc3QgdWludDMyX3QgZ1llbGxvdyA9IG1hdHJpeC5Db2xvcigxMDAsODAsMCk7ICAgIC8vIFkNCmNvbnN0IHVpbnQzMl90IGdCbHVlID0gbWF0cml4LkNvbG9yKDAsMCwxMjgpOyAgICAgICAvLyBCDQpjb25zdCB1aW50MzJfdCBnUHVycGxlID0gbWF0cml4LkNvbG9yKDEyOCwwLDEyOCk7ICAgLy8gUA0KY29uc3QgdWludDMyX3QgZ0dyZWVuID0gbWF0cml4LkNvbG9yKDAsMTI4LDApOyAgICAgIC8vIEcNCmNvbnN0IHVpbnQzMl90IGdUZWFsID0gbWF0cml4LkNvbG9yKDMyLDY0LDY0KTsgICAgICAvLyBUDQpjb25zdCB1aW50MzJfdCBnQmxhY2sgPSBtYXRyaXguQ29sb3IoMCwwLDApOyAgICAgICAgLy8gQg0KY29uc3QgdWludDMyX3QgZ1doaXRlID0gbWF0cml4LkNvbG9yKDEwMCw4MCwxMDApOyAgIC8vIFcNCg0KY2hhciBndWlsZEdseXBoc1szXVs4XVs4XSA9IHt7DQogIHsnTycsJ08nLCdPJywnTycsJyAnLCcgJywnICcsJ08nfSwNCiAgeycgJywnTycsJ08nLCdPJywnTycsJyAnLCdPJywnTyd9LA0KICB7JyAnLCcgJywnTycsJ08nLCdPJywnTycsJ08nLCdPJ30sDQogIHsnICcsJ08nLCdPJywnICcsJyAnLCdPJywnTycsJ08nfSwNCiAgeydPJywnTycsJ08nLCcgJywnICcsJ08nLCdPJywnICd9LA0KICB7J08nLCdPJywnTycsJ08nLCdPJywnTycsJyAnLCcgJ30sDQogIHsnTycsJ08nLCcgJywnTycsJ08nLCdPJywnTycsJyAnfSwNCiAgeydPJywnICcsJyAnLCcgJywnTycsJ08nLCdPJywnTyd9DQp9LHsNCiAgeycgJywnICcsJyAnLCcgJywnICcsJyAnLCcgJywnICd9LA0KICB7JyAnLCcgJywnICcsJyAnLCdSJywnICcsJyAnLCcgJ30sDQogIHsnICcsJyAnLCcgJywnUicsJ1InLCcgJywnICcsJyAnfSwNCiAgeycgJywnUicsJyAnLCdSJywnUicsJyAnLCdSJywnICd9LA0KICB7JyAnLCdSJywnUicsJ1InLCdPJywnUicsJ1InLCcgJ30sDQogIHsnICcsJ1InLCdPJywnTycsJ1knLCdPJywnUicsJyAnfSwNCiAgeycgJywnUicsJ1knLCdZJywnWScsJ1knLCdSJywnICd9LA0KICB7JyAnLCcgJywnUicsJ1knLCdZJywnWScsJ1InLCcgJ30NCn0sew0KICB7JyAnLCcgJywnICcsJyAnLCdCJywnVCcsJ0InLCcgJ30sDQogIHsnICcsJyAnLCcgJywnQicsJ1QnLCdCJywnICcsJyAnfSwNCiAgeycgJywnICcsJ0InLCdUJywnQicsJyAnLCcgJywnICd9LA0KICB7JyAnLCdCJywnVCcsJ1QnLCdUJywnVCcsJ1QnLCdCJ30sDQogIHsnQicsJ1QnLCdUJywnVCcsJ1QnLCdUJywnQicsJyAnfSwNCiAgeycgJywnICcsJyAnLCdCJywnVCcsJ0InLCcgJywnICd9LA0KICB7JyAnLCcgJywnQicsJ1QnLCdCJywnICcsJyAnLCcgJ30sDQogIHsnICcsJ0InLCdUJywnQicsJyAnLCcgJywnICcsJyAnfQ0KfX07DQoNCmludCB0aWxlWzhdWzhdOw0KYm9vbGVhbiBtb3ZlZFs4XVs4XTsNCg0KYnl0ZSBsb2NrWzhdID0gew0KICBCMDExMTAsDQogIEIxMTAxMSwNCiAgQjEwMDAxLA0KICBCMTAwMDEsDQogIEIxMTExMSwNCiAgQjExMDExLA0KICBCMTEwMTEsDQogIEIxMTExMQ0KfTsNCg0KI2RlZmluZSBzY3JlZW5TYXZlclRpbWUgNjAwMDANCiNkZWZpbmUgc2F2ZXJUZXh0TWluU2hvdyA1MDAwDQojZGVmaW5lIHNhdmVyVGV4dE51bSAzMw0KU3RyaW5nIHNhdmVyVGV4dFszM11bNF0gPSB7DQogIHsiUEVSQ0VQVFJPTjogaXMgYSBvbmUiLCJOT0RFIE5FVVJBTCBORVRXT1JLIiwidGhhdCBjYW4gQ0xBU1NJRlkiLCAiTElORUFSIFNFUEFSQVRFIERBVEEifSwgDQogIHsiQ0xBU1NJRlk6IHNvcnQgZGF0YSIsImludG8gZGlmZmVyZW50IiwiY2F0ZWdvcmllcyBvciB0eXBlcyIsImJ5IGdpdmluZyBpdCBhIG5hbWUifSwNCiAgeyJMSU5FQVIgU0VQQVJBVEUiLCJEQVRBOiBkYXRhIHRoYXQgY2FuIiwic2VwYXJhdGVkIGJ5IGEgbGluZSIsImRyYXduIG9uIGEgZ3JhcGgifSwgDQogIHsiTkVVUkFMIE5FVFdPUks6IGlzIGEiLCJzaW1wbGUgbW9kZWwgb2YgaG93IiwiYmlvbG9naWNhbCBuZXVyb25zIiwiY29vcGVyYXRlIGluIGEgYnJhaW4ifSwNCiAgeyJORVVSQUwgTkVUV09SSzogY2FuIiwibGVhcm4gYnkgVFJBSU5JTkcgdG8iLCJwZXJmb3JtIHRhc2tzIGJ5IiwiYmVpbmcgc2hvd24gZXhhbXBsZXMifSwNCiAgeyJORVVSQUwgTkVUV09SSzogaXMgYSIsIm5ldHdvcmsgb2YgTk9ERVMiLCJ0aGF0IGFyZSBjb25uZWN0ZWQiLCJ0b2dldGhlciBieSBXRUlHSFRTIn0sDQogIHsiV0VJR0hUIE1FTU9SWTogaXMgYSIsInN0b3JlIG9mIFdFSUdIVFMiLCJ0aGF0IGFjdHMgYXMgbG9uZyIsInRlcm0gbWVtb3J5In0sDQogIHsiV0VJR0hUUzogbnVtYmVycyIsInRoYXQgc2hvdyBhIHN0cmVuZ3RoIiwib2YgY29ubmVjdGlvbiIsImJldHdlZW4gdGhlIE5PREVTIn0sDQogIHsiV0VJR0hUUzogYXJlIGxlYXJudCIsImFuZCBhZGp1c3RlZCBkdXJpbmciLCJUUkFJTklORyBhbmQgY29ubmVjdCIsIk5PREVTIHRvZ2V0aGVyIn0sDQogIHsiTk9ERVM6IGFyZSBzaW5nbGUiLCJwcm9jZXNzaW5nIHVuaXRzIiwidGhhdCBtaW1pYyBhIHJlYWwiLCJiaW9sb2dpY2FsIG5ldXJvbiJ9LCANCiAgeyJOT0RFUzogY2FsY3VsYXRlIiwiLWlucHV0cyBYIFdFSUdIVFMtIiwiYW5kIG91dHB1dHMgYSBzaWduYWwiLCJ0byBvdGhlciBub2RlcyJ9LA0KICB7Ik5PREVTOiBmaXJlcyBhbiIsIm91dHB1dCBzaWduYWwgd2hlbiIsInRoZSBzdW0gb2YgaXRzIGlucHV0IiwiZXhjZWVkcyBhIFRIUkVTSE9MRCJ9LA0KICB7IlRIUkVTSE9MRDogYSBudW1iZXIiLCJ0byBjb21wYXJlIGFnYWluc3QiLCJ0byBzYXkgd2hhdCBjYXRlZ29yeSIsInNvbWV0aGluZyBpcyJ9LA0KICB7Ik1BUFBJTkc6IHR1cm5zIHJlYWwiLCJ3b3JsZCBkYXRhIGxpa2UiLCJjb2xvciBhbmQgc2l6ZSBpbnRvIiwiSU5QVVQgU0lHTkFMUyJ9LA0KICB7Ik1BUFBJTkc6IHR1cm5zIHRoZSIsIk9VVFBVVCBTSUdOQUxTIiwiaW50byByZWFsIHdvcmxkIGRhdGEiLCJsaWtlIC1ib3ggdHlwZS0ifSwNCiAgeyJJTlBVVCBTSUdOQUxTOiBhcmUiLCJudW1iZXJzIHRoYXQgZmVlZCIsInRoZSBpbnB1dHMgb2YgYSIsIk5FVVJBTCBORVRXT1JLIn0sDQogIHsiT1VUUFVUIFNJR05BTFM6IGFyZSIsImNhbGN1bGF0ZWQgYnkgdGhlIiwiTkVVUkFMIE5FVFdPUksgdG8iLCJDTEFTU0lGWSBpbnB1dCBkYXRhIn0sIA0KICB7IkxFQVJOSU5HOiBnZXR0aW5nIiwiYmV0dGVyIGF0IHBlcmZvcm1pbmciLCJhIHRhc2sgYnkgcmVjZWl2aW5nIiwiVFJBSU5JTkcifSwNCiAgeyJMRUFSTklORzoga25vd2xlZGdlIiwiZ2FpbmVkIGJ5IHNlZWluZyIsIm1hbnkgZ29vZCBhbmQgYmFkIiwiZXhhbXBsZXMgb2YgYSB0aGluZyJ9LCANCiAgeyJMRUFSTklORzogTkVVUkFMIiwiTkVUV09SS1MgbGVhcm4gYnkgYSIsImEgbWV0aG9kIGNhbGxlZCBCQUNLIiwiUFJPUEFHQVRJT04ifSwgDQogIHsiVFJBSU5JTkc6IGEgcHJvY2VzcyIsIm9mIHN0cnVjdHVyZWQiLCJMRUFSTklORyB0aGF0IHVzZXMiLCJUUkFJTklORyBFWEFNUExFUyJ9LA0KICB7IlRSQUlOSU5HIEVYQU1QTEVTOiIsImEgcHJlLXBsYW5uZWQgc2V0IG9mIiwiZ29vZCAmIGJhZCBleGFtcGxlcyIsInRvIHRlYWNoIHdpdGgifSwgDQogIHsiQkFDSyBQUk9QQUdBVElPTjoiLCJ1c2VzIGFuIEVSUk9SIFNJR05BTCIsInRvIGFkanVzdCB0aGUgV0VJR0hUIiwiTUVNT1JZIGNvbnRlbnRzIn0sDQogIHsiQkFDSyBQUk9QQUdBVElPTjogaXMiLCJ0aGUgdHlwZSBvZiBMRUFSTklORyIsInVzZWQgYnkgYSBORVVSQUwiLCJORVRXT1JLIn0sDQogIHsiRVJST1IgU0lHTkFMOiBpcyB0aGUiLCJkaWZmLiBiZXR3ZWVuIE9VVFBVVCIsIlNJR05BTFMgYW5kIHRoZSIsIlRSQUlOSU5HIEVYQU1QTEVTIn0sDQogIHsiRVJST1IgU0lHTkFMOiBpcyBhIiwid2F5IHRvIHRlbGwgYSBORVVSQUwiLCJORVRXT1JLIGlmIGl0IGlzIiwiY29ycmVjdCBvciBub3QifSwNCiAgeyI8Ym94IG5hbWU+IHVzZXMgYSIsIlBFUkNFUFRST04gdG8iLCJDTEFTU0lGWSBkaWZmZXJlbnQiLCJzaXplIGFuZCBjb2xvciBib3hlcyJ9LA0KICB7Ijxib3ggbmFtZT4gaXMgYSIsInNpbXBsZSBleGFtcGxlIG9mIiwiTUFDSElORSBMRUFSTklORyBhbmQiLCJORVVSQUwgTkVUV09SS1MifSwNCiAgeyJNQUNISU5FIExFQVJOSU5HOiBpcyIsImEgc3Vic2V0IG9mIEFJIGFuZCIsImlzIGEgYnJhbmNoIG9mIHN0dWR5IiwiaW4gQ29tcHV0ZXIgU2NpZW5jZSJ9LCAgDQogIHsiTUFDSElORSBMRUFSTklORzoiLCJhbGxvd3MgbWFjaGluZXMgdG8iLCJsZWFybiBuZXcgdGFza3MiLCJ3aXRob3V0IHByb2dyYW1taW5nIn0sDQogIHsiTUFDSElORSBMRUFSTklORzoiLCJjb21tb25seSB1c2VzIE5FVVJBTCIsIk5FVFdPUktTIGFzIHRoZSBtYWluIiwiZm9ybSBvZiBpbnRlbGxpZ2VuY2UifSwNCiAgeyJBSTogYWltcyB0byBtYWtlIiwiY29tcHV0ZXJzIGFzIHNtYXJ0Iiwib3Igc21hcnRlciB0aGFuIGEiLCJodW1hbiEifSwNCiAgeyJBSTogdXNlcyBNQUNISU5FIiwiTEVBUk5JTkcgYXMgYSB0b29sIiwidG8gYmVjb21pbmcgbW9yZSIsImludGVsbGlnZW50In0sIA0KfTsNCg0KI2RlZmluZSBwb3RNYXggNzAwDQojZGVmaW5lIHBvdE1pbiAzMDANCg0KZW51bSBwb25nR2FtZU1vZGUgew0KICBwb25nUGxheSwNCiAgcG9uZ1Nob3dTY29yZSwNCiAgcG9uZ1dhaXQsDQogIHBvbmdFeGl0DQp9Ow0KDQpwb25nR2FtZU1vZGUgcG9uZ01vZGUgPSBwb25nV2FpdDsNCg0KaW50IGJhbGxTcGVlZCA9IDIwMDsNCmludCBiYWxsUG9zWDsNCmludCBiYWxsUG9zWTsNCmludCBiYWxsRGlyWDsNCmludCBiYWxsRGlyWTsNCmludCByaWdodFBhZGRsZVBvczsNCmludCBsZWZ0UGFkZGxlUG9zOw0KYm9vbGVhbiBzdGlja0JhbGxUb1BhZGRsZTsNCmludCBiYWxsT25QYWRkbGU7DQp1bnNpZ25lZCBsb25nIGxhc3RCYWxsVXBkYXRlOw0KYm9vbGVhbiBjaGVja0JhbGw7DQoNCmludCBwb25nTGl2ZXM7DQp1bnNpZ25lZCBsb25nIGludCBwb25nU2NvcmU7DQp1bnNpZ25lZCBsb25nIGludCBwb25nU2NvcmVJbmNyZW1lbnQgPSAxMDsNCg0KU3RyaW5nIHRyYWluQ29ycmVjdFs1XSA9IHsNCiAgIllFUywgSSBrbmV3IGl0IHdhcyIsDQogICJIQSEgYXMgSSB0aG91Z2h0LCAiLA0KICAiT0ggWUVBSCAtIHRoYXQncyIsDQogICJUaGFua3lvdS4gSSBrbm93IGl0cyIsDQogICJCT09NLiBJIHdhcyByaWdodCEiIA0KfTsNCg0KU3RyaW5nIHRyYWluV3JvbmdbNV0gPSB7DQogICJOTyEgSSB3YXMgc3VyZSBpdHMiLA0KICAiT0gsIEkgdGhvdWdodCBpdCB3YXMiLA0KICAiSFVIIEkgd2FzIHdyb25nIHdpdGgiLA0KICAiSSdtIHNob2NrZWQgaXRzIG5vdCIsDQogICJOb3cgSSBzZWUgaXRzIG5vdCIgDQp9Ow0KDQp2b2lkIHNldHVwKCkgew0KDQogIFNlcmlhbC5iZWdpbigxMTUyMDApOw0KICANCiAgcGluTW9kZShwb3RMZWZ0LCBJTlBVVCk7DQogIHBpbk1vZGUocG90Q2VudGVyLCBJTlBVVCk7DQogIHBpbk1vZGUocG90UmlnaHQsIElOUFVUKTsNCiAgcGluTW9kZShncmVlbkJ1dHRvbiwgSU5QVVQpOw0KICBwaW5Nb2RlKGJsdWVCdXR0b24sIElOUFVUKTsNCiAgcGluTW9kZShyZWRCdXR0b24sIElOUFVUKTsNCiAgcGluTW9kZShqb3lCdXR0b24sIElOUFVUKTsNCiAgcGluTW9kZShqb3lILCBJTlBVVCk7DQogIHBpbk1vZGUoam95ViwgSU5QVVQpOw0KICBwaW5Nb2RlKGFtcEVuYWJsZSwgT1VUUFVUKTsNCg0KICAvLyBzZXR1cCBTRC1jYXJkDQogIGlmICghU0QuYmVnaW4oc2RDcykpIHsNCiAgICBzZEluaXQgPSBmYWxzZTsNCiAgfSBlbHNlIHsNCiAgICBzZEluaXQgPSB0cnVlOw0KICB9DQogICAgDQogIC8qIHR1cm4gb24gdGhlIHRpbWVyIGNsb2NrIGluIHRoZSBwb3dlciBtYW5hZ2VtZW50IGNvbnRyb2xsZXIgKi8NCiAgcG1jX3NldF93cml0ZXByb3RlY3QoZmFsc2UpOw0KICBwbWNfZW5hYmxlX3BlcmlwaF9jbGsoSURfVEM0KTsNCiAgLyogd2Ugd2FudCB3YXZlc2VsIDAxIHdpdGggUkMgKi8NCiAgVENfQ29uZmlndXJlKC8qIGNsb2NrICovVEMxLC8qIGNoYW5uZWwgKi8xLCBUQ19DTVJfV0FWRSB8IFRDX0NNUl9XQVZTRUxfVVBfUkMgfCBUQ19DTVJfVENDTEtTX1RJTUVSX0NMT0NLMik7DQogIFRDX1NldFJDKFRDMSwgMSwgMjM4KTsgLy8gc2V0cyA8PiA0NC4xIEtoeiBpbnRlcnJ1cHQgcmF0ZQ0KICBUQ19TdGFydChUQzEsIDEpOyANCiAgLy8gZW5hYmxlIHRpbWVyIGludGVycnVwdHMgb24gdGhlIHRpbWVyIA0KICBUQzEtPlRDX0NIQU5ORUxbMV0uVENfSUVSPVRDX0lFUl9DUENTOw0KICBUQzEtPlRDX0NIQU5ORUxbMV0uVENfSURSPX5UQ19JRVJfQ1BDUzsgDQogIC8qIEVuYWJsZSB0aGUgaW50ZXJydXB0IGluIHRoZSBuZXN0ZWQgdmVjdG9yIGludGVycnVwdCBjb250cm9sbGVyICovDQogIC8qIFRDNF9JUlFuIHdoZXJlIDQgaXMgdGhlIHRpbWVyIG51bWJlciAqIHRpbWVyIGNoYW5uZWxzICgzKSArIHRoZSBjaGFubmVsIG51bWJlciAoPSgxKjMpKzEpIGZvciB0aW1lcjEgY2hhbm5lbDEgKi8NCiAgTlZJQ19FbmFibGVJUlEoVEM0X0lSUW4pOw0KICAvLyBtYWtlIHRoZSBsb29rIHVwIHRhYmxlcw0KICBjcmVhdGVOb3RlVGFibGUoU0FNUExFX1JBVEUpOw0KICBtYWtlU2luZVdhdmUoKTsNCiAgLy9zZXQgdXAgdGhlIGRhYw0KICBhbmFsb2dXcml0ZVJlc29sdXRpb24oMTIpOw0KICBhbmFsb2dXcml0ZShEQUMxLCAwKTsNCg0KICBsY2QuYmVnaW4oMjAsIDQpOyAvLyBpbml0aWFsaXplIHRoZSBsY2QNCiAgbGNkLnNldEJhY2tsaWdodCgxKTsgDQogIGxjZC5jcmVhdGVDaGFyKDAsIGxvY2spOw0KDQogIG1hdHJpeC5iZWdpbigpOw0KICBtYXRyaXguc2V0VGV4dFdyYXAoZmFsc2UpOw0KICBtYXRyaXguc2V0QnJpZ2h0bmVzcyg2MCk7DQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguY2xlYXIoKTsNCiAgbGVkcy5iZWdpbigpOyAgDQogIGxlZHMuc2V0QnJpZ2h0bmVzcyg2MCk7DQogIGxlZHMuY2xlYXIoKTsNCiAgbGVkcy5zaG93KCk7DQoNCiAgLy8gSkYtDQogIC8vIHVuY29tbWVudCBsaW5lcyBiZWxvdyBpZiB5b3UgbmVlZCB0byBkZWxldGUgYSBjb3JydXB0IGxvZyBmaWxlDQogIC8vaWYgKFNELmV4aXN0cygic2V0dGluZ3MudHh0IikpDQogIC8vICBTRC5yZW1vdmUoInNldHRpbmdzLnR4dCIpOw0KDQogIGxvYWRlZFNldHRpbmdzID0gcmVhZFNldHRpbmdzKCk7DQoNCiAgc2VlZFJORygpOw0KDQogIGxhc3RCYWxsVXBkYXRlID0gbWlsbGlzKCk7DQogIGNoZWNrQmFsbCA9IGZhbHNlOw0KICByZWFkUGFkZGxlUG9zaXRpb24oKTsNCiAgc3RpY2tCYWxsVG9QYWRkbGUgPSB0cnVlOw0KICBiYWxsT25QYWRkbGUgPSByYW5kb20oMik7DQoNCiAgDQogIGxlZHMuY2xlYXIoKTsNCiAgbGVkcy5zaG93KCk7DQoNCiAgU2VyaWFsLnByaW50KGJveE5hbWUpOw0KICBTZXJpYWwucHJpbnQoIiBmbHVzaCBzZXJpYWwgcG9ydC4uLi4iKTsNCiAgU2VyaWFsLmZsdXNoKCk7DQoNCn0NCg0Kdm9pZCBlbnRlck5hbWUoKSB7DQoNCiAgLy8gMTYgY2hhcnMNCiAgLy8gc2hvdyBjdXJzb3INCiAgLy8gQS1aDQogIC8vIGpveSBzdGljayB2IC0gbW92ZSBjdXJzb3INCiAgLy8gam95IGJ1dXRvbiB0byBzZWxlY3QgLSBhbnkgb3RoZSBidXR0b24gdG8gZmluaXNoDQogIC8vIG1pZGRsZSBkaWFsIHRvIHNlbGVjdCBndWlsZA0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICANCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwwKTsNCiAgbGNkLnByaW50KCJVc2UgdGhlIGRpYWxzIHRvICIpOw0KICBsY2Quc2V0Q3Vyc29yKDAsMSk7DQogIGxjZC5wcmludCgibmFtZSB5b3VyIGJyYWluIGFuZCIpOw0KICBsY2Quc2V0Q3Vyc29yKDAsMik7DQogIGxjZC5wcmludCgic2VsZWN0IHlvdXIgZ3VpbGQuIik7DQoNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICB9DQoNCiAgbGNkLmNsZWFyKCk7DQoNCiAgaW50IGNQb3MgPSAwOw0KICBpbnQgY1NlbCA9IDA7DQogIGludCBjUG9zTGFzdCA9IC0xOw0KICBpbnQgY1NlbExhc3QgPSAtMTsNCiAgaW50IHB2ID0gMDsNCg0KICBTdHJpbmcgbmV3TmFtZSA9IHBhZFN0cmluZygxMixib3hOYW1lKTsNCiAgDQogIGJvb2xlYW4gbmFtZVNldCA9IGZhbHNlOw0KICB3aGlsZSghbmFtZVNldCkgew0KDQogICAgcHYgPSBhbmFsb2dSZWFkKHBvdFJpZ2h0KTsNCiAgICBwdiA9IGZsb29yKHB2LzM0Mik7ICANCg0KICAgIC8vIG5lZWQgdG8gY29weSB0aGlzIGlmIG1vZGRlZCB0byB3ZWxjb21lL3NldC1uYW1lDQogICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICB1aW50MzJfdCBjID0gbWF0cml4LkNvbG9yKDAsMCwwKTsNCiAgICAgICAgc3dpdGNoIChndWlsZEdseXBoc1twdl1beF1beV0pIHsNCiAgICAgICAgICBjYXNlICdSJzoNCiAgICAgICAgICAgIGMgPSBnUmVkOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnTyc6DQogICAgICAgICAgICBjID0gZ09yYW5nZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1knOg0KICAgICAgICAgICAgYyA9IGdZZWxsb3c7DQogICAgICAgICAgICBicmVhazsNCiAgICAgICAgICBjYXNlICdCJzoNCiAgICAgICAgICAgIGMgPSBnQmx1ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1QnOg0KICAgICAgICAgICAgYyA9IGdUZWFsOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnRyc6DQogICAgICAgICAgICBjID0gZ0dyZWVuOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnUCc6DQogICAgICAgICAgICBjID0gZ1B1cnBsZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1cnOg0KICAgICAgICAgICAgYyA9IGdXaGl0ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJyAnOg0KICAgICAgICAgICAgYyA9Z0JsYWNrOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgZGVmYXVsdDoNCiAgICAgICAgICAgIGMgPSBnQmxhY2s7DQogICAgICAgICAgICBicmVhazsgIA0KICAgICAgICB9DQogICAgICAgIG1hdHJpeC5kcmF3UGl4ZWwoeSx4LGMpOw0KICAgICAgfQ0KICAgIH0NCg0KICAgIGNQb3MgPSBhbmFsb2dSZWFkKHBvdExlZnQpOw0KICAgIGNQb3MgPSBmbG9vcihjUG9zLzg2KTsNCg0KICAgIGNTZWwgPSBhbmFsb2dSZWFkKHBvdENlbnRlcik7DQogICAgY1NlbCA9IGZsb29yKGNTZWwvMzkpOw0KDQogICAgaWYgKGNTZWwgIT0gY1NlbExhc3QpIHsNCiAgICAgIGNoYXIgYyA9IGNTZWwgKyA2NTsNCiAgICAgIGlmIChjU2VsID09IDI2KQ0KICAgICAgICBjID0gJyAnOw0KICAgICAgbmV3TmFtZS5zZXRDaGFyQXQoY1BvcyxjKTsNCiAgICAgIGxjZC5zZXRDdXJzb3IoNCwwKTsNCiAgICAgIGxjZC5wcmludChuZXdOYW1lKTsNCiAgICB9DQoNCiAgICANCiAgICBpZiAoY1BvcyAhPSBjUG9zTGFzdCkgew0KICAgICAgbGNkLnNldEN1cnNvcigwLDEpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiICIpKTsNCiAgICAgIGxjZC5zZXRDdXJzb3IoY1Bvcys0LDEpOw0KICAgICAgbGNkLnByaW50KCJeIik7DQogICAgfQ0KICAgIA0KICAgIC8vbGNkLm5vQ3Vyc29yKCk7DQogICAgbGNkLnNldEN1cnNvcigwLDMpOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsZ3VpbGROYW1lc1twdl0pKTsNCg0KICAgIG1hdHJpeC5zaG93KCk7DQoNCiAgICBjU2VsTGFzdCA9IGNTZWw7DQogICAgY1Bvc0xhc3QgPSBjUG9zOw0KDQogICAgaWYgKGJ1dHRvblByZXNzZWQoYW55KSkNCiAgICAgIG5hbWVTZXQgPSB0cnVlOw0KDQogIH0NCg0KICBib3hOYW1lID0gbmV3TmFtZTsgDQogIGJveE5hbWUudHJpbSgpOw0KICBib3hHdWlsZCA9IGd1aWxkTmFtZXNbcHZdOw0KICBsb2dTZXR0aW5ncygpOw0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICANCn0NCg0Kdm9pZCBmYWN0b3J5TW9kZSgpIHsgDQoNCiAgdW5zaWduZWQgbG9uZyB0ID0gMDsvL21pbGxpcygpOw0KICB1bmlvbiB7Ynl0ZSBiWzRdO2Zsb2F0IGY7fSB0ZW1wOw0KICBieXRlICogYjsNCg0KICBsb2dTZXR0aW5ncygpOw0KDQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwwKTsNCiAgbGNkLnByaW50KCJVcGxvYWRpbmcgYnJhaW4iKTsNCiAgbGNkLnNldEN1cnNvcigwLDEpOw0KICBsY2QucHJpbnQoInRvIHRoZSBib3ggZmFjdG9yeS4iKTsNCg0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCg0KICBpbnQgaSA9IDA7DQoNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSAmJiAoaTw1KSkgew0KDQogICAgaWYgKG1pbGxpcygpLXQgPiA1MDAwKSB7DQogICANCiAgICAgIFNlcmlhbC5wcmludCgiU29TIik7DQogICAgICBTZXJpYWwuZmx1c2goKTsNCiAgICAgIFNlcmlhbC5wcmludChwYWRTdHJpbmcoMjAsYm94TmFtZSkpOw0KICAgICAgU2VyaWFsLmZsdXNoKCk7DQogICAgICBTZXJpYWwucHJpbnQocGFkU3RyaW5nKDIwLGJveEd1aWxkKSk7DQoNCiAgICAgIGludCBwdiA9IDA7DQogICAgICBpZiAoYm94R3VpbGQgPT0gIlBIT0VOSVgiKQ0KICAgICAgICBwdiA9IDE7DQogICAgICBpZiAoYm94R3VpbGQgPT0gIkxJR0hUTklORyIpDQogICAgICAgIHB2ID0gMjsNCiAgICAgIGZvciAoaW50IHg9MDsgeDw4OyB4KyspIHsNCiAgICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICAgIFNlcmlhbC5wcmludChndWlsZEdseXBoc1twdl1beF1beV0pOyAgICAgICAgIA0KICAgICAgICB9DQogICAgICAgIFNlcmlhbC5mbHVzaCgpOw0KICAgICAgfQ0KICAgICAgDQogICAgICBmb3IgKGludCBpPTA7IGk8cGFyYW1MZW47IGkrKykgew0KICAgICAgICAgIHRlbXAuYltpJTRdID0gcGFyYW1zW2ldOw0KICAgICAgICAgIGlmIChpJTQgPT0gMykgew0KICAgICAgICAgICAgYiA9IChieXRlICopICZ0ZW1wLmY7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlswXSk7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlsxXSk7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlsyXSk7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlszXSk7ICAgDQogICAgICAgICAgICBTZXJpYWwuZmx1c2goKTsgICANCiAgICAgICAgICB9ICAgICAgICANCiAgICAgIH0NCg0KDQoNCiAgICAgIGkrKzsNCiAgICAgIA0KICAgICAgbGNkLnNldEN1cnNvcigwLDMpOw0KICAgICAgbGNkLnByaW50KCJzZW50OiIrU3RyaW5nKGkpKTsNCiAgICAgIA0KICAgICAgdCA9IG1pbGxpcygpOw0KICAgIA0KICAgIH0NCiAgICANCiAgfQ0KDQogIG1vZGUgPSBtZW51Ow0KfQ0KDQoNCnZvaWQgbG9vcCgpIHsNCg0KICBzd2l0Y2ggKG1vZGUpIHsNCiAgICBjYXNlIHdlbGNvbWU6DQogICAgICBtb2RlRGVzYyA9ICJXZWxjb21lIE1vZGUiOw0KICAgICAgd2VsY29tZU1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2Ugd29yazoNCiAgICAgIG1vZGVEZXNjID0gIldvcmsgTW9kZSI7DQogICAgICB3b3JrTW9kZSgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBicmFpbnN0YXRlOg0KICAgICAgbW9kZURlc2MgPSAiU3RhdGUgTW9kZSI7DQogICAgICBzdGF0ZU9mTWluZCgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBtZW51Og0KICAgICAgbW9kZURlc2MgPSAiTWVudSBNb2RlIjsNCiAgICAgIG1haW5NZW51KCk7DQogICAgICBicmVhazsNCiAgICBjYXNlIHRyYWluOg0KICAgICAgbW9kZURlc2MgPSAiVHJhaW4gTW9kZSI7DQogICAgICB0cmFpbk1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2UgYW5hbHl6ZToNCiAgICAgIG1vZGVEZXNjID0gIkFuYWx5emUgTW9kZSI7DQogICAgICBhbmFseXplTW9kZSgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBmYWN0b3J5Og0KICAgICAgbW9kZURlc2MgPSAiRmFjdG9yeSBNb2RlIjsNCiAgICAgIGZhY3RvcnlNb2RlKCk7DQogICAgICBicmVhazsNCiAgICBjYXNlIHNldHRpbmdzOg0KICAgICAgbW9kZURlc2MgPSAiU2V0dGluZ3MgTW9kZSI7DQogICAgICBzZXR0aW5nc01vZGUoKTsNCiAgICAgIGJyZWFrOyAgICANCiAgICBjYXNlIGluc3RydWN0aW9uczoNCiAgICAgIG1vZGVEZXNjID0gIkluc3RyLiBNb2RlIjsNCiAgICAgIGluc3RydWN0aW9uc01vZGUoKTsNCiAgICAgIGJyZWFrOyAgDQogICAgY2FzZSBwb25nOg0KICAgICAgbW9kZURlc2MgPSAiUG9uZyBNb2RlIjsNCiAgICAgIHBvbmdMb29wKCk7DQogICAgICBicmVhazsgIA0KICAgIGNhc2Ugc3ludGg6DQogICAgICBtb2RlRGVzYyA9ICJTeW50aCI7DQogICAgICBzeW50aE1vZGUoKTsNCiAgICAgIGJyZWFrOyAgICAgICAgDQogIH0NCiAgIA0KfQ0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIHN0YXRlT2ZNaW5kDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCnZvaWQgc3RhdGVPZk1pbmQoKSB7DQoNCiAgbGNkLmNsZWFyKCk7DQogIHBhZ2VDbGVhcigpOw0KICBwYWdlQWRkSGVhZGluZygiLS0tLUJSQUlOLS1TVEFURS0tLS0iKTsNCg0KICBwYWdlQWRkRW50cnkoMCwgIkkgYW0gIiArIGJveE5hbWUpOw0KICBwYWdlQWRkRW50cnkoMSwgYm94R3VpbGQgKyAiIGd1aWxkIik7DQogIHBhZ2VBZGRFbnRyeSgyLCAiVHJhaW5pbmcgc2V0cz0iICsgU3RyaW5nKHRyYWluQ3ljbGVzKSk7DQogIHBhZ2VBZGRFbnRyeSgzLCAiQWNjdXJhY3k9IiArIFN0cmluZyh3b3JrTW9kZUF2ZXJhZ2UsMikpOw0KICBwYWdlQWRkRW50cnkoNCwgIkJlc3Qgc2NvcmU9IiArIFN0cmluZyh3b3JrTW9kZUJlc3QpKTsNCiAgcGFnZUFkZEVudHJ5KDUsICJQZXJjZXB0cm9uIHdlaWdodDoiKTsNCiAgcGFnZUFkZEVudHJ5KDYsICItLVcwPSIgKyBTdHJpbmcobm5XZWlnaHRzWzBdLDEzKSk7ICANCiAgcGFnZUFkZEVudHJ5KDcsICItLVcxPSIgKyBTdHJpbmcobm5XZWlnaHRzWzFdLDEzKSk7DQogIHBhZ2VBZGRFbnRyeSg4LCAiLS1XMj0iICsgU3RyaW5nKG5uV2VpZ2h0c1syXSwxMykpOyANCiAgcGFnZUFkZEVudHJ5KDksICJMZWFybmluZyByYXRlOiIpOw0KICBwYWdlQWRkRW50cnkoMTAsICItLXJhdGU9IisgU3RyaW5nKG5uTGVhcm5pbmdDLDExKSk7ICANCiAgcGFnZUFkZEVudHJ5KDExLCAiQm94IGdlbmVyYXRvcnM6Iik7DQogIHBhZ2VBZGRFbnRyeSgxMiwgIi0tY01heD0iICsgU3RyaW5nKGNNYXgpKTsNCiAgcGFnZUFkZEVudHJ5KDEzLCAiLS1nYlJhZGl1cz0iICsgU3RyaW5nKGdvb2RCb3hSYWRpdXMsNCkpOw0KDQogIGludCBzZWxlY3RlZCA9IDA7DQogIHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICANCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICAgIHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KDQogICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICBpbnQgeHMgPSByYW5kb20oMCwgMTAwKTsgLy9jbWF4KjIgLyA4ID0gMTAwDQogICAgICAgIGludCB5cyA9IHJhbmRvbSgwLCAxMDApOw0KICAgICAgICB4cyArPSAoeC00KSoxMDA7DQogICAgICAgIHlzICs9ICh5LTQpKjEwMDsgICAgDQogICAgICAgIGZsb2F0IHByZWRpY3Rpb24gPSAobm5GZWVkRm9yd2FyZCh4cywgeXMpICsgMS4wKS8yLjA7DQogICAgICAgIHByZWRpY3Rpb24gKj0gMTI3LjA7DQogICAgICAgIHVpbnQxNl90IFJHQiA9IG1hdHJpeC5Db2xvcihwcmVkaWN0aW9uLCAxMjgtcHJlZGljdGlvbiwgMCk7DQogICAgICAgIG1hdHJpeC5kcmF3UGl4ZWwoeCwgNy15LCBSR0IpOyAgIA0KICAgICAgfSAgICAgIA0KICAgIH0NCg0KIA0KICAgICBtYXRyaXguc2hvdygpOw0KICAgIA0KICB9DQoNCg0KICAvKg0KICAvLyBtYXAgdGhlIGxlYXJuaW5nIHN0YXRlIHRvIGEgY29sb3I6IDUwIG9yIGxvd2VyIGJhZCA9IHJlZCAuLi4uIDEwMCBnb29kID0gZ3JlZW4NCiAgZmxvYXQgY29sID0gKCh3b3JrTW9kZUF2ZXJhZ2UtNTApLzUwKSoxMjg7DQogIGlmIChjb2wgPCAwKQ0KICAgIGNvbCA9IDA7ICANCiAgc2V0TkVPU2Nyb2xsTWVzc2FnZSgiU0hPV0lORyBNWSBTVEFURSBPRiBNSU5EICAiLG1hdHJpeC5Db2xvcigxMjgtY29sLCBjb2wsIDApKTsNCg0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogICAgdXBkYXRlTkVPU2Nyb2xsTWVzc2FnZSgpOw0KICAgIHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICB9Ki8NCg0KICBtb2RlID0gbWVudTsNCiAgDQp9DQoNCg0Kdm9pZCBhbmFseXplTW9kZSgpIHsNCg0KICBsY2QuY2xlYXIoKTsNCiAgbWF0cml4LmNsZWFyKCk7DQogIG1hdHJpeC5zaG93KCk7DQoNCg0KICANCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLS0tQU5BTFlaRS1NT0RFLS0tLSIpOw0KICBwYWdlQWRkRW50cnkoMCwiVXNlIHRoZSBkaWFscyB0byIpOw0KICBwYWdlQWRkRW50cnkoMSwibWFrZSBjb2xvcmVkIik7DQogIHBhZ2VBZGRFbnRyeSgyLCJib3hlcyAuLi4uLiIpOw0KLy9uZWVkIG5vcmUNCiAgICANCiAgaW50IHNlbGVjdGVkID0gMDsNCiAgc2VsZWN0ZWQgPSBwYWdlVXBkYXRlKCk7DQogICAgDQogIHdoaWxlKCFidXR0b25QcmVzc2VkKGFueSkpIHsNCiAgICAvL3VwZGF0ZU5FT1Njcm9sbE1lc3NhZ2UoKTsNCiAgICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCiAgfQ0KIA0KICBsY2QuY2xlYXIoKTsNCiAgDQogIGZsb2F0IHhzID0gMDsNCiAgZmxvYXQgeXMgPSAwOw0KDQogIC8vIG1ha2UgYSBib3ggdW50aWwgYW55IGJ1dHRvbiBpcyBwdXNoZWQNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYmx1ZSkpIHsNCiAgICB4cyA9ICgoKGZsb2F0KWFuYWxvZ1JlYWQocG90TGVmdCkgLyA1MTEuNSktMS4wKSpjTWF4Ow0KICAgIGlmICh4cyA8IC0zNzQpIHhzID0gLTM3NDsNCiAgICB5cyA9ICgoKGZsb2F0KWFuYWxvZ1JlYWQocG90UmlnaHQpIC8gNTExLjUpLTEuMCkqY01heDsNCiAgICBpbnQgYm94U2l6ZSA9ICgoeHMrY01heCkvKGNNYXgqMikpKjMxOw0KICAgIGludCBib3hDb2xvciA9ICgoKHlzK2NNYXgpLyhjTWF4KjIpKSoxMjcpKzMyOw0KICAgIGRyYXdCb3goYm94U2l6ZSwgYm94Q29sb3IsIHRydWUpOw0KICAgIC8vIHJ1biB0aGUgbmV1cmFsIG5ldCBmb3J3YXJkDQogICAgaW50IHByZWRpY3Rpb24gPSBubkZlZWRGb3J3YXJkKHhzLCB5cyk7IA0KICAgICAgLy8gcHJlZGljdGlvbiAxID0gbGFyZ2UgcmVkICAgIC0xID0gc21hbGwgZ3JlZW4NCiAgICANCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIlVzZSB0aGUgZGlhbHMgdG8iKSk7DQogICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJtYWtlIGJveGVzLiIpKTsNCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIkkgdGhpbmsgdGhpcyBpcyBhICIpKTsNCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgIGlmIChwcmVkaWN0aW9uID09IDEpIA0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwibGFyZ2UgcmVkIGJveC4iKSk7DQogICAgZWxzZSAgDQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJzbWFsbCBncmVlbiBib3guIikpOw0KICB9DQoNCiAgbGNkLmNsZWFyKCk7DQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICANCiAgbW9kZSA9IG1lbnU7DQogIHJldHVybjsNCg0KfQ0KDQp2b2lkIGFib3V0TW9kZSgpIHsNCg0KICBsY2QuY2xlYXIoKTsNCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLUZSWURFTi1MRUFSTklORy0tIik7DQoNCiAgcGFnZUFkZEVudHJ5KDAsICJCb3ggZmFjdG9yeSB2ZXI6Iik7DQogIHBhZ2VBZGRFbnRyeSgxLCB2ZXJOdW0pOw0KICBwYWdlQWRkRW50cnkoMiwgIlBsZWFzZSB2aXNpdDoiKTsNCiAgcGFnZUFkZEVudHJ5KDMsICJmcnlkZW4tbGVhcm5pbmcuY29tIik7DQogIHBhZ2VBZGRFbnRyeSg0LCAiU3VwcG9ydGVkIGJ5OiIpOw0KICBwYWdlQWRkRW50cnkoNSwgIkFybSBJbmMuIik7DQogIHBhZ2VBZGRFbnRyeSg2LCAiU3Vuc3RvbmUgQ2lyY3VpdHMiKTsNCg0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogICAgaW50IHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICB9DQoNCn0NCg0Kdm9pZCBpbnN0cnVjdGlvbnNNb2RlKCkgew0KICBsY2QuY2xlYXIoKTsNCiAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgbGNkLnByaW50KCIuLi5pbiAiK21vZGVEZXNjKTsNCiAgZGVsYXkoMjAwMCk7DQogIG1vZGUgPSBtZW51Ow0KfQ0KDQp2b2lkIHNldHRpbmdzTW9kZSgpIHsNCg0KICBib29sZWFuIGxlYXZlID0gZmFsc2U7DQoNCiAgd2hpbGUgKCFsZWF2ZSkgew0KICANCiAgICBsY2QuY2xlYXIoKTsNCiAgICBtZW51Q2xlYXIoKTsNCiAgICBtZW51QWRkSGVhZGluZygiLS0tLS0tU0VUVElOR1MtLS0tLS0iKTsNCiAgICBmb3IgKGludCBpPTA7IGk8c2V0dGluZ3NNZW51U2l6ZTsgaSsrKSB7DQogICAgICBtZW51QWRkRW50cnkoaSwgc2V0dGluZ3NNZW51RW50cmllc1tpXSk7DQogICAgfQ0KICANCiAgICBpbnQgc2VsZWN0ZWQgPSAwOyAgDQogICAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICAgICAgc2VsZWN0ZWQgPSBtZW51VXBkYXRlKGZhbHNlKTsNCiAgICB9DQoNCiAgICBzd2l0Y2ggKHNlbGVjdGVkKSB7DQogICAgICBjYXNlIDA6DQogICAgICAgIHNldFZvbHVtZSgpOw0KICAgICAgICBicmVhazsNCiAgICAgIGNhc2UgMToNCiAgICAgICAgc2V0RGlmZmljdWx0eSgpOw0KICAgICAgICBicmVhazsNCiAgICAgIGNhc2UgMjoNCiAgICAgICBlbnRlck5hbWUoKTsNCiAgICAgICBicmVhazsNCiAgICAgIGNhc2UgMzoNCiAgICAgICAgcmVzZXRCcmFpbigpOw0KICAgICAgICBicmVhazsNCiAgICAgIGNhc2UgNDoNCiAgICAgICAgYWJvdXRNb2RlKCk7DQogICAgICAgIGJyZWFrOw0KICAgICAgY2FzZSA1Og0KICAgICAgICBsZWF2ZSA9IHRydWU7DQogICAgICAgIGJyZWFrOyAgDQogICAgICBkZWZhdWx0Og0KICAgICAgICByZXR1cm47DQogICAgfQ0KICAgICAgIA0KICB9DQoNCiAgbW9kZSA9IG1lbnU7DQoNCn0NCg0Kdm9pZCByZXNldEJyYWluKCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICBsY2QucHJpbnQoIkdyZWVuID0gcmVzZXQgYnJhaW4iKTsNCiAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgbGNkLnByaW50KCJSZWQgPSBjYW5jZWwiKTsNCg0KICBib29sZWFuIGFuc3dlcmVkID0gZmFsc2U7DQogIHdoaWxlKCFhbnN3ZXJlZCkgew0KICAgDQogICAgaWYgKGJ1dHRvblByZXNzZWQocmVkKSkgew0KICAgICAgYW5zd2VyZWQgPSB0cnVlOyANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgICBsY2QucHJpbnQoIkJyYWluIG5vdCByZXNldC4iKTsNCiAgICB9IGVsc2UgaWYgKGJ1dHRvblByZXNzZWQoZ3JlZW4pKSB7DQogICAgICBhbnN3ZXJlZCA9IHRydWU7DQogICAgICAgIGJveE5hbWUgPSAiQlJBSU4gQk9YIjsgDQogICAgICAgIGJveEd1aWxkID0gIk5JTkpBIjsNCiAgICAgICAgbm5XZWlnaHRzWzBdID0gLTEuMDsNCiAgICAgICAgbm5XZWlnaHRzWzFdID0gMS4wOw0KICAgICAgICBubldlaWdodHNbMl0gPSAwLjA7DQogICAgICAgIG5uTGVhcm5pbmdDID0gbGVhcm5pbmdSYXRlOw0KICAgICAgICB0cmFpbkN5Y2xlcyA9IDA7DQogICAgICAgIHRvdGFsVHJhaW5pbmdFeGFtcGxlcyA9IDA7DQogICAgICAgIHRvdGFsQ29ycmVjdCA9IDA7DQogICAgICAgIHdvcmtNb2RlQXZlcmFnZSA9IDA7DQogICAgICAgIHdvcmtNb2RlQmVzdCA9IDA7DQogICAgICAgIGdvb2RCb3hSYWRpdXMgPSAxLjE7DQogICAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgICAgIGxjZC5wcmludCgiQnJhaW4gcmVzZXQuIik7DQogICAgfSAgICAgIA0KICAgICAgDQogIH0NCiAgcmVtb3ZlU2V0dGluZ3NMb2coKTsNCiAgZGVsYXkoMTUwMCk7DQogIHJldHVybjsNCn0NCg0Kdm9pZCBzZXRWb2x1bWUoKSB7DQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwwKTsNCiAgbGNkLnByaW50KCJVc2UgdGhlIG1pZGRsZSBkaWFsIik7DQogIGxjZC5zZXRDdXJzb3IoMCwxKTsNCiAgbGNkLnByaW50KCJ0byBhZGp1c3QgdGhlIHZvbHVtZSIpOw0KICANCiAgdW5zaWduZWQgbG9uZyB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogIGJvb2xlYW4gaGlMb3cgPSBmYWxzZTsNCiAgDQogIGFtcE9uKCk7DQogIHdoaWxlKCFidXR0b25QcmVzc2VkKGFueSkpIHsNCg0KICAgIGludCBwdiA9IHBvdFZhbHVlKGNlbnRlciwgMC4wMSk7DQogICAgaWYgKHB2IDwgMCkNCiAgICAgIHB2ID0gMDsNCiAgICBpZiAocHYgPiAxMCkNCiAgICAgIHB2ID0gMTA7DQoNCiAgICB2b2x1bWUgPSBwdjsNCg0KICAgIGxjZC5zZXRDdXJzb3IoMCwzKTsNCiAgICBsY2QucHJpbnQoIlZvbHVtZT0iK1N0cmluZyh2b2x1bWUpKyIgICAgIik7DQoNCiAgICBpZiAobWlsbGlzKCkgLSB0b25lVGltZVN0YW1wID4gMzAwKSB7IA0KICAgICAgICB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICAgIGlmIChoaUxvdykgDQogICAgICAgICAgcGxheVRvbmUoNjAsMTAwMCk7DQogICAgICAgIGVsc2UNCiAgICAgICAgICBwbGF5VG9uZSg5MCwxMDAwKTsNCiAgICAgICAgaGlMb3cgPSAhaGlMb3c7ICAgDQogICAgfSANCiAgIA0KICB9DQogIGFtcE9mZigpOw0KDQogIHJldHVybjsNCn0NCg0Kdm9pZCByZW1vdmVTZXR0aW5nc0xvZygpIHsNCiAgaWYgKHNkSW5pdCkgew0KICAgIGlmIChTRC5leGlzdHMoInNldHRpbmdzLnR4dCIpKQ0KICAgICAgU0QucmVtb3ZlKCJzZXR0aW5ncy50eHQiKTsNCiAgfQ0KfQ0KDQp2b2lkIGxvZ1NldHRpbmdzKCkgew0KICBpZiAoc2RJbml0KSB7DQoNCiAgICBpZiAoU0QuZXhpc3RzKCJzZXR0aW5ncy50eHQiKSkNCiAgICAgIFNELnJlbW92ZSgic2V0dGluZ3MudHh0Iik7DQogICANCiAgICBwYXJhbXNUb0J5dGVzKCk7DQogIA0KICAgIEZpbGUgc2V0dGluZ3MgPSBTRC5vcGVuKCJzZXR0aW5ncy50eHQiLCBGSUxFX1dSSVRFKTsNCiAgDQogICAgaWYgKHNldHRpbmdzKSB7DQogICAgICBzZXR0aW5ncy5wcmludCgifiIgKyBib3hOYW1lICsgIn4iKTsNCiAgICAgIHNldHRpbmdzLnByaW50KCIhIiArIGJveEd1aWxkICsgIiEiKTsNCiAgICAgIGZvciAoaW50IGk9MDsgaTxwYXJhbUxlbjsgaSsrKSB7DQogICAgICAgIHNldHRpbmdzLndyaXRlKHBhcmFtc1tpXSk7DQogICAgICB9DQogICAgICBzZXR0aW5ncy5jbG9zZSgpOw0KICAgIH0gZWxzZSB7DQogICAgICANCiAgICB9DQogIH0NCn0NCg0KYm9vbGVhbiByZWFkU2V0dGluZ3MoKSB7DQoNCiAgYm9vbGVhbiBsb2FkZWQgPSBmYWxzZTsNCiAgDQogIGlmIChzZEluaXQpIHsNCiAgICBpZiAoU0QuZXhpc3RzKCJzZXR0aW5ncy50eHQiKSkgew0KICAgICAgRmlsZSBzZXR0aW5ncyA9IFNELm9wZW4oInNldHRpbmdzLnR4dCIpOw0KICAgICAgY2hhciBjOw0KICAgICAgaW50IHRmPTA7DQogICAgICBTdHJpbmcgbiA9ICIiOw0KICAgICAgd2hpbGUgKHRmPDIpIHsNCiAgICAgICAgYyA9IChjaGFyKSBzZXR0aW5ncy5yZWFkKCk7DQogICAgICAgIGlmIChjPT0nficpDQogICAgICAgICAgdGYrKzsNCiAgICAgICAgbiArPSBjOw0KICAgICAgfQ0KDQogICAgICB0ZiA9IDA7DQogICAgICBTdHJpbmcgZyA9ICIiOw0KICAgICAgd2hpbGUgKHRmPDIpIHsNCiAgICAgICAgYyA9IChjaGFyKSBzZXR0aW5ncy5yZWFkKCk7DQogICAgICAgIGlmIChjPT0nIScpDQogICAgICAgICAgdGYrKzsNCiAgICAgICAgZyArPSBjOw0KICAgICAgfQ0KDQogICAgICBpbnQgaT0wOw0KICAgICAgYnl0ZSBiOw0KICAgICAgd2hpbGUoc2V0dGluZ3MuYXZhaWxhYmxlKCkgJiYgaTxwYXJhbUxlbikgew0KICAgICAgICBiID0gKGJ5dGUpIHNldHRpbmdzLnJlYWQoKTsNCiAgICAgICAgcGFyYW1zW2krK10gPSBiOyAgDQogICAgICB9DQoNCiAgICAgIGxvYWRlZCA9IHRydWU7DQogICAgICBieXRlc1RvUGFyYW1zKCk7ICANCiAgICAgIA0KICAgICAgYm94TmFtZSA9IG4uc3Vic3RyaW5nKDEsbi5sZW5ndGgoKS0xKTsgICANCiAgICAgIGJveEd1aWxkID0gZy5zdWJzdHJpbmcoMSxnLmxlbmd0aCgpLTEpOyANCiAgICB9DQogIH0NCg0KDQogIHJldHVybiBsb2FkZWQ7DQogIA0KfQ0KDQp2b2lkIHBhcmFtc1RvQnl0ZXMoKSB7DQogICAgaW50IGk9MDsNCiAgICBieXRlICogYjsNCiAgICB1bmlvbiB7Ynl0ZSBiWzRdO2Zsb2F0IGY7fSB0ZW1wOw0KDQogICAgdGVtcC5mID0gbm5MZWFybmluZ0M7IHBhcmFtc1tpKytdID0gdGVtcC5iWzBdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsxXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzNdOw0KICAgIHRlbXAuZiA9IGdvb2RCb3hSYWRpdXM7IHBhcmFtc1tpKytdID0gdGVtcC5iWzBdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsxXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzNdOw0KICAgIHRlbXAuZiA9IG5uV2VpZ2h0c1swXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMF07IHBhcmFtc1tpKytdID0gdGVtcC5iWzFdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsyXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbM107DQogICAgdGVtcC5mID0gbm5XZWlnaHRzWzFdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlswXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMV07IHBhcmFtc1tpKytdID0gdGVtcC5iWzJdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlszXTsNCiAgICB0ZW1wLmYgPSBubldlaWdodHNbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzBdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsxXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzNdOw0KICAgIHRlbXAuZiA9IHdvcmtNb2RlQXZlcmFnZTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMF07IHBhcmFtc1tpKytdID0gdGVtcC5iWzFdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsyXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbM107DQogICAgYiA9IChieXRlICopICZ0cmFpbkN5Y2xlczsgcGFyYW1zW2krK10gPSBiWzBdOyBwYXJhbXNbaSsrXSA9IGJbMV07IHBhcmFtc1tpKytdID0gYlsyXTsgcGFyYW1zW2krK10gPSBiWzNdOw0KICAgIGIgPSAoYnl0ZSAqKSAmdG90YWxDb3JyZWN0OyBwYXJhbXNbaSsrXSA9IGJbMF07IHBhcmFtc1tpKytdID0gYlsxXTsgcGFyYW1zW2krK10gPSBiWzJdOyBwYXJhbXNbaSsrXSA9IGJbM107DQogICAgYiA9IChieXRlICopICZ0b3RhbFRyYWluaW5nRXhhbXBsZXM7IHBhcmFtc1tpKytdID0gYlswXTsgcGFyYW1zW2krK10gPSBiWzFdOyBwYXJhbXNbaSsrXSA9IGJbMl07IHBhcmFtc1tpKytdID0gYlszXTsNCiAgICBiID0gKGJ5dGUgKikgJndvcmtNb2RlQmVzdDsgcGFyYW1zW2krK10gPSBiWzBdOyBwYXJhbXNbaSsrXSA9IGJbMV07IHBhcmFtc1tpKytdID0gYlsyXTsgcGFyYW1zW2krK10gPSBiWzNdOw0KDQp9DQoNCnZvaWQgYnl0ZXNUb1BhcmFtcygpIHsNCiAgaW50IGk9MDsNCiAgdW5pb24ge2J5dGUgYls0XTtmbG9hdCBmO30gdGVtcDsNCiAgDQogIHRlbXAuYlswXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsxXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsyXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlszXSA9IChwYXJhbXNbaSsrXSk7DQogIG5uTGVhcm5pbmdDID0gdGVtcC5mOw0KICB0ZW1wLmJbMF0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMV0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMl0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbM10gPSAocGFyYW1zW2krK10pOw0KICBnb29kQm94UmFkaXVzID0gdGVtcC5mOw0KICB0ZW1wLmJbMF0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMV0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMl0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbM10gPSAocGFyYW1zW2krK10pOw0KICBubldlaWdodHNbMF0gPSB0ZW1wLmY7DQogIHRlbXAuYlswXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsxXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsyXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlszXSA9IChwYXJhbXNbaSsrXSk7DQogIG5uV2VpZ2h0c1sxXSA9IHRlbXAuZjsNCiAgdGVtcC5iWzBdID0gKHBhcmFtc1tpKytdKTsgdGVtcC5iWzFdID0gKHBhcmFtc1tpKytdKTsgdGVtcC5iWzJdID0gKHBhcmFtc1tpKytdKTsgdGVtcC5iWzNdID0gKHBhcmFtc1tpKytdKTsNCiAgbm5XZWlnaHRzWzJdID0gdGVtcC5mOw0KICB0ZW1wLmJbMF0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMV0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMl0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbM10gPSAocGFyYW1zW2krK10pOw0KICB3b3JrTW9kZUF2ZXJhZ2UgPSB0ZW1wLmY7DQogIHRyYWluQ3ljbGVzID0gKGludCkoKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDApIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDgpIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDE2KSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCAyNCkpOw0KICB0b3RhbENvcnJlY3QgPSAoaW50KSgoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgMCkgfCAoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgOCkgfCAoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgMTYpIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDI0KSk7DQogIHRvdGFsVHJhaW5pbmdFeGFtcGxlcyA9IChpbnQpKCgocGFyYW1zW2krK10gJiAweGZmKSA8PCAwKSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCA4KSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCAxNikgfCAoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgMjQpKTsNCiAgd29ya01vZGVCZXN0ID0gKGludCkoKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDApIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDgpIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDE2KSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCAyNCkpOw0KfQ0KDQp2b2lkIHBsYXlJbnRyb1R1bmUoKSB7DQogIC8qDQogIGFtcE9uKCk7DQoNCiAgcGxheUR1YWxUb25lKDc1LCAxMDUsIDAuMSwgMTAwMDAwKTsNCiAgZGVsYXkoMTAwMCk7DQogIHBsYXlEdWFsVG9uZSg3NSwgMTA1LCAwLjMzLCAxMDAwMDApOw0KICBkZWxheSgxMDAwKTsNCiAgcGxheUR1YWxUb25lKDc1LCAxMDUsIDAuNjYsIDEwMDAwMCk7DQogIGRlbGF5KDEwMDApOw0KICBwbGF5RHVhbFRvbmUoNzUsIDEwNSwgMC45LCAxMDAwMDApOw0KICBkZWxheSgxMDAwKTsNCg0KICBhbXBPZmYoKTsNCiAgKi8NCn0NCg0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIHdlbGNvbWVNb2RlDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCnZvaWQgd2VsY29tZU1vZGUoKSB7DQoNCiAgdW5zaWduZWQgbG9uZyB3ZWxjb21lVGltZVN0YW1wOw0KDQogIGxjZC5jbGVhcigpOw0KDQogIGlmICghbG9hZGVkU2V0dGluZ3MpIHsNCiAgICBlbnRlck5hbWUoKTsNCiAgfQ0KDQogIGlmICghc2RJbml0KSB7IA0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgbGNkLnByaW50KCJTRCBDYXJkIGluaXQgZmFpbGVkISIpOw0KICAgIGRlbGF5KDUwMDApOw0KICB9IA0KICBsY2QuY2xlYXIoKTsNCg0KICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICBsY2QucHJpbnQoIkJveCBGYWN0b3J5ICAiICsgdmVyTnVtICsgIiAgICIpOw0KICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICBsY2QucHJpbnQoIkkgYW0gIiArIGJveE5hbWUpOw0KICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICBsY2QucHJpbnQoYm94R3VpbGQgKyAiIGd1aWxkIik7DQogIA0KDQogIHdlbGNvbWVUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCg0KICBpbnQgcHYgPSAwOw0KICBpZiAoYm94R3VpbGQgPT0gIlBIT0VOSVgiKQ0KICAgIHB2ID0gMTsNCiAgaWYgKGJveEd1aWxkID09ICJMSUdIVE5JTkciKQ0KICAgIHB2ID0gMjsNCg0KICBwbGF5SW50cm9UdW5lKCk7DQogIA0KICB3aGlsZSAoKG1pbGxpcygpIC0gd2VsY29tZVRpbWVTdGFtcCA8IDE1MDAwKSAmJiAoIWJ1dHRvblByZXNzZWQoYW55KSkpIHsNCg0KICAgIC8vIG5lZWQgdG8gY29weSB0aGlzIGlmIG1vZGRlZCB0byB3ZWxjb21lL3NldC1uYW1lDQogICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICB1aW50MzJfdCBjID0gbWF0cml4LkNvbG9yKDAsMCwwKTsNCiAgICAgICAgc3dpdGNoIChndWlsZEdseXBoc1twdl1beF1beV0pIHsNCiAgICAgICAgICBjYXNlICdSJzoNCiAgICAgICAgICAgIGMgPSBnUmVkOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnTyc6DQogICAgICAgICAgICBjID0gZ09yYW5nZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1knOg0KICAgICAgICAgICAgYyA9IGdZZWxsb3c7DQogICAgICAgICAgICBicmVhazsNCiAgICAgICAgICBjYXNlICdCJzoNCiAgICAgICAgICAgIGMgPSBnQmx1ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1QnOg0KICAgICAgICAgICAgYyA9IGdUZWFsOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnRyc6DQogICAgICAgICAgICBjID0gZ0dyZWVuOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnUCc6DQogICAgICAgICAgICBjID0gZ1B1cnBsZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1cnOg0KICAgICAgICAgICAgYyA9IGdXaGl0ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJyAnOg0KICAgICAgICAgICAgYyA9IGdCbGFjazsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGRlZmF1bHQ6DQogICAgICAgICAgICBjID0gZ0JsYWNrOw0KICAgICAgICAgICAgYnJlYWs7ICANCiAgICAgICAgfQ0KICAgICAgICBtYXRyaXguZHJhd1BpeGVsKHkseCxjKTsNCiAgICAgIH0NCiAgICB9DQogICAgDQogICAgbWF0cml4LnNob3coKTsNCiAgDQogIH0NCiAgbWF0cml4LmZpbGxTY3JlZW4oMCk7DQogIG1vZGUgPSBtZW51Ow0KICAgIA0KfQ0KDQoNCg0Kdm9pZCBtYWluTWVudSgpIHsNCg0KICBwb25nTW9kZSA9IHBvbmdXYWl0Ow0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICBsZWRzLmNsZWFyKCk7DQogIGxlZHMuc2hvdygpOw0KICANCiAgbGNkLmNsZWFyKCk7DQogIG1lbnVDbGVhcigpOw0KICBtZW51QWRkSGVhZGluZygiLS0tLS1NQUlOLS1NRU5VLS0tLS0iKTsNCiAgZm9yIChpbnQgaT0wOyBpPG1haW5NZW51U2l6ZTsgaSsrKSB7DQogICAgbWVudUFkZEVudHJ5KGksIG1haW5NZW51RW50cmllc1tpXSk7DQogIH0NCg0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICBpbnQgbGFzdFNlbGVjdGVkID0gMDsNCiAgaW50IHNjdCA9IG1pbGxpcygpOw0KDQogIGJvb2xlYW4gYW5zd2VyZWQgPSBmYWxzZTsNCiAgDQogIHdoaWxlKCFhbnN3ZXJlZCkgew0KICAgIHNlbGVjdGVkID0gbWVudVVwZGF0ZSh0cnVlKTsNCiAgICBpZiAobGFzdFNlbGVjdGVkICE9IHNlbGVjdGVkKQ0KICAgICAgc2N0ID0gbWlsbGlzKCk7DQogICAgbGFzdFNlbGVjdGVkID0gc2VsZWN0ZWQ7DQogICAgaWYgKG1pbGxpcygpLXNjdCA+IHNjcmVlblNhdmVyVGltZSkgew0KICAgICAgc2NyZWVuU2F2ZXIoKTsNCiAgICAgIG1lbnVVcGRhdGVMQ0QgPSB0cnVlOw0KICAgICAgc2N0ID0gbWlsbGlzKCk7ICANCiAgICAgIG1hdHJpeC5jbGVhcigpOw0KICAgICAgbWF0cml4LnNob3coKTsNCiAgICAgIGxjZC5jbGVhcigpOw0KICAgIH0NCiAgICBpZiAoYnV0dG9uUHJlc3NlZChhbnkpICYmICFtZW51TG9ja3Nbc2VsZWN0ZWRdKQ0KICAgICAgYW5zd2VyZWQgPSB0cnVlOyANCiAgfQ0KICANCiAgc3dpdGNoIChzZWxlY3RlZCkgew0KICBjYXNlIDA6DQogICAgbW9kZSA9IGJyYWluc3RhdGU7DQogICAgcmV0dXJuOw0KICAgIGJyZWFrOw0KICBjYXNlIDE6DQogICAgbW9kZSA9IHRyYWluOw0KICAgIHJldHVybjsNCiAgICBicmVhazsNCiAgY2FzZSAyOg0KICAgIG1vZGUgPSB3b3JrOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgIA0KICBjYXNlIDM6DQogICAgbW9kZSA9IGZhY3Rvcnk7DQogICAgcmV0dXJuOw0KICAgIGJyZWFrOyANCiAgY2FzZSA0Og0KICAgIG1vZGUgPSBhbmFseXplOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgDQogIGNhc2UgNToNCiAgICBtb2RlID0gcG9uZzsNCiAgICByZXR1cm47DQogICAgYnJlYWs7IA0KICBjYXNlIDY6DQogICAgbW9kZSA9IHN5bnRoOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgDQogIGNhc2UgNzoNCiAgICBtb2RlID0gaW5zdHJ1Y3Rpb25zOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgDQogIGNhc2UgODoNCiAgICBtb2RlID0gc2V0dGluZ3M7DQogICAgcmV0dXJuOw0KICAgIGJyZWFrOyANCiAgZGVmYXVsdDoNCiAgICBtb2RlID0gbWVudTsNCiAgICByZXR1cm47DQogICAgYnJlYWs7DQogIH0NCiAgDQp9DQoNCnZvaWQgd29ya01vZGUoKSB7DQoNCiAgaW50IGJveFNpemUgPSAwOw0KICBpbnQgYm94Q29sb3IgPSAwOw0KICB1bnNpZ25lZCBsb25nIG1ha2VCb3hUaW1lU3RhbXA7DQogIHVuc2lnbmVkIGxvbmcgYW5hbHl6ZUJveFRpbWVTdGFtcDsNCiAgdW5zaWduZWQgbG9uZyB0b25lVGltZVN0YW1wOw0KICBpbnQgdG9uZUR1cmF0aW9uOw0KICBpbnQgc2NvcmUgPSAwOw0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICBsY2QuY2xlYXIoKTsNCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLS0tLVdPUkstLU1PREUtLS0tLSIpOw0KICBwYWdlQWRkRW50cnkoMCwiTXkgYnJhaW4gd2lsbCB3b3JrIik7DQogIHBhZ2VBZGRFbnRyeSgxLCJvbiBhIHNtYWxsIHNldCBvZiAxMCIpOw0KICBwYWdlQWRkRW50cnkoMiwiZXhhbXBsZXMgdG8gc2VlIGhvdyIpOw0KICBwYWdlQWRkRW50cnkoMywiaG93IHdlbGwgSSBjYW4gdGVsbCIpOw0KICBwYWdlQWRkRW50cnkoNCwidGhlIGRpZmZlcmVuZW5jZSIpOw0KICBwYWdlQWRkRW50cnkoNSwiYmV0d2VlbiBzbWFsbCBncmVlbiIpOw0KICBwYWdlQWRkRW50cnkoNiwiYm94ZXMgYW5kIGxhcmdlIHJlZCIpOw0KICBwYWdlQWRkRW50cnkoNywiYm94ZXMuIik7DQoNCiAgaW50IHNlbGVjdGVkID0gMDsNCiAgc2VsZWN0ZWQgPSBwYWdlVXBkYXRlKCk7DQoNCiAgYm9vbGVhbiBhbnN3ZXJlZCA9IGZhbHNlOw0KICB3aGlsZSghYW5zd2VyZWQpIHsNCiAgICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCiAgICBpZiAoYnV0dG9uUHJlc3NlZChyZWQpKSB7DQogICAgICBtb2RlID0gbWVudTsNCiAgICAgIHJldHVybjsgDQogICAgfQ0KICAgIGlmIChidXR0b25QcmVzc2VkKGJsdWUpIHx8IGJ1dHRvblByZXNzZWQoZ3JlZW4pIHx8IGJ1dHRvblByZXNzZWQoam95KSkgew0KICAgICAgYW5zd2VyZWQgPSB0cnVlOw0KICAgIH0NCiAgfQ0KDQogIGRlbGF5KDUwMCk7DQoNCiAgZm9yIChpbnQgaj0wOyBqPDEwOyBqKyspIHsNCg0KICAgIGxjZC5jbGVhcigpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgbGNkLnByaW50KCJNYWtpbmcgYSBzYW1wbGUgYm94Iik7DQogICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICBsY2QucHJpbnQoIlBsZWFzZSB3YWl0Li4uLi4iKTsNCg0KICAgIG1ha2VCb3hUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCiAgICB0b25lVGltZVN0YW1wID0gMDsNCg0KICAgIGludCBib3hUeXBlID0gMDsNCiAgICBmbG9hdCB4cyA9IDA7DQogICAgZmxvYXQgeXMgPSAwOw0KICAgIA0KICAgIGFtcE9uKCk7DQogICAgd2hpbGUgKG1pbGxpcygpIC0gbWFrZUJveFRpbWVTdGFtcCA8IG1ha2VCb3hEdXJhdGlvbikgew0KDQogICAgICBtYXRyaXguY2xlYXIoKTsNCg0KICAgICAgZmxvYXQgeCA9IG1pbGxpcygpIC0gbWFrZUJveFRpbWVTdGFtcDsNCiAgICAgIHggPSAoKHgtbWFrZUJveER1cmF0aW9uQnkyKS9tYWtlQm94RHVyYXRpb25CeTIpKjY7DQogICAgICBmbG9hdCBzQ3VydmUgPSAxLygxK2V4cCgteCoxLjMpKTsNCiAgICAgIGludCBzcGFya2xlUHJvYiA9IChpbnQpIChzQ3VydmUgKiAzMDApOw0KICAgICAgc0N1cnZlID0gMS8oMStleHAoLXgqMS4wKSk7DQogICAgICBpbnQgYm94UmF0ZSA9IChpbnQpIChzQ3VydmUgKiAyMDApICsgMzA7DQoNCiAgICAgIGRyYXdCb3goYm94U2l6ZSwgYm94Q29sb3IsIGZhbHNlKTsNCiAgDQogICAgICBmb3IgKGludCBpPTA7IGk8NjQ7IGkrKykgew0KICAgICAgICBpbnQgeCA9IHJhbmRvbSg4KTsNCiAgICAgICAgaW50IHkgPSByYW5kb20oOCk7DQogICAgICAgIGludCBiID0gcmFuZG9tKDEyOCk7DQogICAgICAgIHVpbnQxNl90IFJHQiA9IG1hdHJpeC5Db2xvcigwLCAwLCBiKTsNCiAgICAgICAgaWYgKHJhbmRvbShzcGFya2xlUHJvYikgPT0gMCkNCiAgICAgICAgICBtYXRyaXguZHJhd1BpeGVsKHgsIHksIFJHQik7DQogICAgICB9DQoNCiAgICAgIGlmIChtaWxsaXMoKSAtIHRvbmVUaW1lU3RhbXAgPiB0b25lRHVyYXRpb24pIHsgDQogICAgICAgIHRvbmVUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCiAgICAgICAgdG9uZUR1cmF0aW9uID0gYm94UmF0ZTsNCiAgICAgICAgcGxheVRvbmUocmFuZG9tKDYwKSs2MCx0b25lRHVyYXRpb24pOw0KICAgICAgICB0b25lRHVyYXRpb24gPSB0b25lRHVyYXRpb24gKiAxLjM7DQogICAgICAgIA0KICAgICAgICBib29sZWFuIHZhbGlkID0gZmFsc2U7DQogICAgICANCiAgICAgICAgd2hpbGUoIXZhbGlkKSB7DQogICAgICAgICAgeHMgPSByYW5kb20oMjYsIGNNYXgqMik7DQogICAgICAgICAgeXMgPSByYW5kb20oMCwgY01heCoyKTsgICAgDQogICAgICAgICAgZmxvYXQgdkRpc3QgPSBzcXJ0KCh4cyp4cykgKyAoeXMqeXMpKTsNCiAgICAgICAgICBpZiAodkRpc3QgPCAoZ29vZEJveFJhZGl1cypjTWF4KSkgew0KICAgICAgICAgICAgaW50IGJjID0gKGludCkgcmFuZG9tKDIpOw0KICAgICAgICAgICAgaWYgKGJjPT0xKSB7DQogICAgICAgICAgICAgIHhzIC09IGNNYXg7DQogICAgICAgICAgICAgIHlzIC09IGNNYXg7DQogICAgICAgICAgICAgIGJveFR5cGUgPSAtMTsNCiAgICAgICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgICAgIGZsb2F0IHR4cyA9IHhzOw0KICAgICAgICAgICAgICB4cyA9ICh5cyotMSkrY01heDsNCiAgICAgICAgICAgICAgeXMgPSAodHhzKi0xKStjTWF4Ow0KICAgICAgICAgICAgICBib3hUeXBlID0gMTsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIHZhbGlkID0gdHJ1ZTsgIA0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KDQogICAgICAgIGJveFNpemUgPSAoKHhzK2NNYXgpLyhjTWF4KjIpKSozMTsNCiAgICAgICAgYm94Q29sb3IgPSAoKCh5cytjTWF4KS8oY01heCoyKSkqMTI3KSszMjsNCiAgICAgIH0gLy8gaWYgZm9yIG1ha2luZyB0b25lLg0KICAgICAgDQogICAgICBtYXRyaXguc2hvdygpOw0KICAgICAgICAgICAgDQogICAgfSAvLyB3aGlsZQ0KICAgIA0KICAgIGFtcE9mZigpOw0KICAgIGNsZWFyVG9uZSgpOw0KDQogICAgLy8gZXZhbCBib3gNCiAgICBkcmF3Qm94KGJveFNpemUsIGJveENvbG9yLCB0cnVlKTsNCg0KICAgIGxjZC5jbGVhcigpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgbGNkLnByaW50KCJBbmFseWl6aW5nIGJveCIpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgbGNkLnByaW50KCJQbGVhc2Ugd2FpdC4uLiIpOw0KDQogICAgaW50IHByZWRpY3Rpb24gPSBubkZlZWRGb3J3YXJkKHhzLCB5cyk7DQogICAgU3RyaW5nIHByZWRpY3Rpb25EZXNjID0gIlNNQUxMIEdSRUVOIGJveD8iOw0KICAgIGlmIChwcmVkaWN0aW9uID09IDEpIA0KICAgICAgcHJlZGljdGlvbkRlc2MgPSAiTEFSR0UgUkVEIGJveD8iOw0KDQogICAgZGVsYXkoMjUwKTsNCiAgICBhbmFseXplQm94VGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgdG9uZVRpbWVTdGFtcCA9IG1pbGxpcygpOw0KICAgIHRvbmVEdXJhdGlvbiA9IDEwMDsNCg0KDQogICAgYW1wT24oKTsNCiAgICB3aGlsZSAobWlsbGlzKCkgLSBhbmFseXplQm94VGltZVN0YW1wIDwgYW5hbHl6ZUJveER1cmF0aW9uKSB7DQogICAgICBpZiAobWlsbGlzKCkgLSB0b25lVGltZVN0YW1wID4gdG9uZUR1cmF0aW9uICogMS4zKSB7IA0KICAgICAgICB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICAgIHBsYXlUb25lKHJhbmRvbSg0MCkrMzAsIHRvbmVEdXJhdGlvbik7DQogICAgICB9IC8vIGlmIGZvciBtYWtpbmcgdG9uZS4gICAgICAgICANCiAgICB9IC8vIHdoaWxlDQogICAgYW1wT2ZmKCk7DQogICAgY2xlYXJUb25lKCk7DQoNCiAgICAvLyBydW4gTk4NCiAgICAvLyBzaG93IHJlc3VsdCAgICAgDQogICAgbGNkLmNsZWFyKCk7DQogICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICBsY2QucHJpbnQoIkkgdGhpbmsgdGhpcyBib3ggaXMgIik7DQogICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICBsY2QucHJpbnQoImEgIik7DQogICAgbGNkLnNldEN1cnNvcigyLCAxKTsNCiAgICBsY2QucHJpbnQocHJlZGljdGlvbkRlc2MpOw0KDQogICAgYW1wT24oKTsNCiAgICBpZihwcmVkaWN0aW9uID09IGJveFR5cGUpIHsNCiAgICAgIHNjb3JlKys7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KCItLS0tLS1DT1JSRUNULS0tLS0tLSIpOyAgDQogICAgICBwbGF5VG9uZSg2OCwyNTApOw0KICAgICAgZGVsYXkoMzAwKTsNCiAgICAgIHBsYXlUb25lKDY4LDE1MCk7DQogICAgICBkZWxheSgxODApOw0KICAgICAgcGxheVRvbmUoODAsMTAwMCk7DQogICAgICBkZWxheSgxMzAwKTsNCiAgICB9IGVsc2Ugew0KICAgICAgbGNkLnNldEN1cnNvcigwLCAzKTsNCiAgICAgIGxjZC5wcmludCgiLS0tLS0tLS1XUk9ORy0tLS0tLS0iKTsgIA0KICAgICAgcGxheVRvbmUoNjIsMzAwKTsNCiAgICAgIGRlbGF5KDM5MCk7DQogICAgICBwbGF5VG9uZSg1NiwzMDApOw0KICAgICAgZGVsYXkoMzkwKTsNCiAgICAgIHBsYXlUb25lKDQ1LDEwMDApOw0KICAgICAgZGVsYXkoMTMwMCk7ICANCiAgICB9DQogICAgYW1wT2ZmKCk7DQogICAgY2xlYXJUb25lKCk7DQogICAgZGVsYXkoMTAwMCk7DQogICANCiAgfQ0KDQogIC8vIHNob3cgcmVzdWx0ICAgICANCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIldvcmsgUmVzdWx0czoiKSk7ICAgDQogIGxjZC5zZXRDdXJzb3IoMCwgMik7DQogIFN0cmluZyBmaW5hbFNjb3JlID0gIiI7DQogIGlmIChzY29yZSA8IDEwKQ0KICAgIGZpbmFsU2NvcmUgKz0gIjAiICsgU3RyaW5nKHNjb3JlKTsNCiAgZWxzZQ0KICAgIGZpbmFsU2NvcmUgKz0gU3RyaW5nKHNjb3JlKTsNCiAgZmluYWxTY29yZSArPSAiLzEwIjsNCiAgICANCiAgbGNkLnByaW50KHBhZFN0cmluZygyMCxmaW5hbFNjb3JlKSk7IA0KICBkZWxheSgzMDAwKTsNCg0KICB0b3RhbENvcnJlY3QgKz0gc2NvcmU7DQogIHRvdGFsVHJhaW5pbmdFeGFtcGxlcyArPSAxMDsNCg0KICB3b3JrTW9kZUF2ZXJhZ2UgPSAxMDAgKiAoKGZsb2F0KXRvdGFsQ29ycmVjdCAvIChmbG9hdCl0b3RhbFRyYWluaW5nRXhhbXBsZXMpOw0KICANCiAgaWYgKHNjb3JlID4gd29ya01vZGVCZXN0KQ0KICAgIHdvcmtNb2RlQmVzdCA9IHNjb3JlOw0KDQogIGlmIChzY29yZSA9PSAxMCkNCiAgICBtZW51TG9ja3NbcG9uZ0xvY2tdID0gMDsgDQoNCiAgYW1wT2ZmKCk7DQoNCiAgbG9nU2V0dGluZ3MoKTsNCiAgDQogIG1vZGUgPSBicmFpbnN0YXRlOw0KDQp9DQoNCnZvaWQgdHJhaW5Nb2RlKCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBtYXRyaXguY2xlYXIoKTsNCiAgbWF0cml4LnNob3coKTsNCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLS1UUkFJTklORy0tTU9ERS0tLSIpOw0KICBwYWdlQWRkRW50cnkoMCwiVXNlIHRoZSBkaWFscyB0byIpOw0KICBwYWdlQWRkRW50cnkoMSwibWFrZSBmaXZlIGNvbG9yZWQiKTsNCiAgcGFnZUFkZEVudHJ5KDIsImJveGVzIGFzIGV4YW1wbGVzIHRvIik7DQogIHBhZ2VBZGRFbnRyeSgzLCJ0ZWFjaCBteSBicmFpbi4iKTsNCiAgcGFnZUFkZEVudHJ5KDQsIkl0IHdpbGwgaGVscCBtZSIpOw0KICBwYWdlQWRkRW50cnkoNSwibGVhcm4gaWYgeW91IHVzZSIpOw0KICBwYWdlQWRkRW50cnkoNiwid2VsbCB0aG91Z2h0LW91dCIpOw0KICBwYWdlQWRkRW50cnkoNywiZXhhbXBsZXMuICAiKTsNCiAgcGFnZUFkZEVudHJ5KDgsIkkgd2lsbCBndWVzcyB3aGF0Iik7DQogIHBhZ2VBZGRFbnRyeSg5LCJ0aGUgYm94ZXMgYXJlLCBhbmQgIik7DQogIHBhZ2VBZGRFbnRyeSgxMCwibGVhcm4gZnJvbSBteSAiKTsNCiAgcGFnZUFkZEVudHJ5KDExLCJtaXN0YWtlcy4iKTsNCg0KICBpbnQgc2NvcmUgPSAwOw0KICAgIA0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCiAgDQogIGJvb2xlYW4gYW5zd2VyZWQgPSBmYWxzZTsNCiAgd2hpbGUoIWFuc3dlcmVkKSB7DQogICAgc2VsZWN0ZWQgPSBwYWdlVXBkYXRlKCk7DQogICAgaWYgKGJ1dHRvblByZXNzZWQocmVkKSkgew0KICAgICAgbW9kZSA9IG1lbnU7DQogICAgICByZXR1cm47IA0KICAgIH0NCiAgICBpZiAoYnV0dG9uUHJlc3NlZChibHVlKSB8fCBidXR0b25QcmVzc2VkKGdyZWVuKSB8fCBidXR0b25QcmVzc2VkKGpveSkpIHsNCiAgICAgIGFuc3dlcmVkID0gdHJ1ZTsNCiAgICB9DQogIH0NCiANCiAgZm9yIChpbnQgaT0wOyBpPDU7IGkrKykgew0KDQogICAgbGNkLmNsZWFyKCk7DQogICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJVc2UgdGhlIGRpYWxzIHRvIikpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwibWFrZSBhIGJveC4iKSk7IA0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiUHJlc3MgYmx1ZSB3aGVuIGRvbmUuIikpOyAgICAgDQogICAgDQogICAgZmxvYXQgeHMgPSAwOw0KICAgIGZsb2F0IHlzID0gMDsNCiAgICBpbnQgZXJyb3IgPSAwOw0KDQogICAgLy8gbWFrZSBhIGJveCB1bnRpbCB0aGUgYmx1ZSBidXR0b24gaXMgcHVzaGVkDQogICAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYmx1ZSkpIHsNCiAgICAgIHhzID0gKCgoZmxvYXQpYW5hbG9nUmVhZChwb3RMZWZ0KSAvIDUxMS41KS0xLjApKmNNYXg7DQogICAgICBpZiAoeHMgPCAtMzc0KSB4cyA9IC0zNzQ7DQogICAgICB5cyA9ICgoKGZsb2F0KWFuYWxvZ1JlYWQocG90UmlnaHQpIC8gNTExLjUpLTEuMCkqY01heDsNCiAgICAgIGludCBib3hTaXplID0gKCh4cytjTWF4KS8oY01heCoyKSkqMzE7DQogICAgICBpbnQgYm94Q29sb3IgPSAoKCh5cytjTWF4KS8oY01heCoyKSkqMTI3KSszMjsNCiAgICAgIGRyYXdCb3goYm94U2l6ZSwgYm94Q29sb3IsIHRydWUpOw0KICAgICAgaW50IHByZWRpY3Rpb24gPSBubkZlZWRGb3J3YXJkKHhzLCB5cyk7IC8vIHJ1biBhIHNuZWFreSBwcmVkaWN0aW9uIA0KICAgICAgLy8gcHJlZGljdGlvbiAxID0gbGFyZ2UgcmVkICAgIC0xID0gc21hbGwgZ3JlZW4NCiAgICAgIHVpbnQzMl90IGxlZFJHQiA9IGxlZHMuQ29sb3IoOCwwLDApOw0KICAgICAgaWYgKHByZWRpY3Rpb24gPT0gLTEpDQogICAgICAgIGxlZFJHQiA9IGxlZHMuQ29sb3IoMCw4LDApOyANCiAgICAgIGxlZHMuc2V0UGl4ZWxDb2xvcigwLCBsZWRSR0IpOw0KICAgICAgbGVkcy5zaG93KCk7DQoNCiAgICB9DQoNCiAgICAvLyBydW4gdGhlIG5ldXJhbCBuZXQgZm9yd2FyZA0KICAgIGludCBwcmVkaWN0aW9uID0gbm5GZWVkRm9yd2FyZCh4cywgeXMpOyANCiAgICAvLyBwcmVkaWN0aW9uIDEgPSBsYXJnZSByZWQgICAgLTEgPSBzbWFsbCBncmVlbg0KDQogICAgYm9vbGVhbiBhbnN3ZXJlZCA9IGZhbHNlOw0KICAgIHdoaWxlKCFhbnN3ZXJlZCkgew0KICAgICANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJXaGF0IHR5cGUgb2YgYm94IikpOyANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJpcyB0aGlzPyIpKTsgDQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiR3JlZW4gPSBzbWFsbCBncmVlbi4iKSk7ICANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJSZWQgPSBsYXJnZSByZWQuIikpOyANCg0KICAgICAgaWYgKGJ1dHRvblByZXNzZWQocmVkKSkgew0KICAgICAgICBhbnN3ZXJlZCA9IHRydWU7DQogICAgICAgIGVycm9yID0gMSAtIHByZWRpY3Rpb247IA0KICAgICAgfSBlbHNlIGlmIChidXR0b25QcmVzc2VkKGdyZWVuKSkgew0KICAgICAgICBhbnN3ZXJlZCA9IHRydWU7DQogICAgICAgIGVycm9yID0gLTEgLSBwcmVkaWN0aW9uOw0KICAgICAgfSAgICAgIA0KICAgICAgICANCiAgICB9DQoNCiAgICBsY2QuY2xlYXIoKTsNCg0KICAgIGlmIChlcnJvciAhPSAwKSB7DQogIA0KICAgICAgbm5BZGp1c3RXZWlnaHRzKHhzLCB5cywgZXJyb3IpOw0KDQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCx0cmFpbldyb25nW3JhbmRvbSg1KV0pKTsNCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBpZiAocHJlZGljdGlvbiA9PSAtMSkNCiAgICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiYSBzbWFsbCBncmVlbiBib3giKSk7DQogICAgICBlbHNlDQogICAgICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsImEgbGFyZ2VyIHJlZCBib3giKSk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiQXBwbHlpbmcgbGVhcm5pbmcuLi4iKSk7DQogICAgICAgDQogICAgICB1bnNpZ25lZCBsb25nIGxlYXJuaW5nVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICB1bnNpZ25lZCBsb25nIHRvbmVUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCiAgICAgIGludCB0b25lRHVyYXRpb24gPSAxMDA7DQogICAgICANCiAgICAgIGFtcE9uKCk7DQogICAgICB3aGlsZSAobWlsbGlzKCkgLSBsZWFybmluZ1RpbWVTdGFtcCA8IHRyYWluQm94RHVyYXRpb24pIHsNCiAgICAgICAgaWYgKG1pbGxpcygpIC0gdG9uZVRpbWVTdGFtcCA+IHRvbmVEdXJhdGlvbiAqIDEuMykgeyANCiAgICAgICAgICB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICAgICAgcGxheVRvbmUocmFuZG9tKDQwKSszMCwgdG9uZUR1cmF0aW9uKTsNCiAgICAgICAgfSAvLyBpZiBmb3IgbWFraW5nIHRvbmUuICAgICAgICAgDQogICAgICB9IC8vIHdoaWxlDQogICAgICAgICANCiAgICAgIGFtcE9mZigpOw0KICAgICAgY2xlYXJUb25lKCk7DQogICAgICBzY29yZSsrOw0KDQogICAgfSBlbHNlIHsNCiAgICAgIA0KICAgICAgbGNkLmNsZWFyKCk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCx0cmFpbkNvcnJlY3RbcmFuZG9tKDUpXSkpOw0KICAgICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICAgIGlmIChwcmVkaWN0aW9uID09IC0xKQ0KICAgICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJhIGdyZWVuIGJveCIpKTsNCiAgICAgIGVsc2UNCiAgICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiYSByZWQgYm94IikpOw0KICAgICAgDQogICAgICB1bnNpZ25lZCBsb25nIGxlYXJuaW5nVGltZVN0YW1wID0gbWlsbGlzKCk7ICAgICAgDQogICAgICB3aGlsZSAobWlsbGlzKCkgLSBsZWFybmluZ1RpbWVTdGFtcCA8IHRyYWluQm94RHVyYXRpb24pIHsNCiAgICAgIH0gLy8gd2hpbGUNCiAgICB9DQogIH0NCg0KICB0cmFpbkN5Y2xlcysrOyANCg0KICBsb2dTZXR0aW5ncygpOw0KICANCiAgbW9kZSA9IGJyYWluc3RhdGU7DQoNCiAgaWYgKHNjb3JlPT01KSANCiAgICBtZW51TG9ja3Nbc3ludGhMb2NrXSA9IDA7DQogIA0KICByZXR1cm47DQogIA0KfQ0KDQp2b2lkIGRyYXdCb3goaW50IGJveFNpemUsIGludCBib3hDb2xvciwgYm9vbGVhbiBkcmF3SW1tZWRpYXRlKXsNCiAgDQogIGludCBib3hTaXplSW50ID0gYm94U2l6ZSA+PiAyOw0KICBpbnQgYm94U2l6ZUZyYWMgPSBib3hTaXplICYgMzsNCiAgaW50IHIgPSBib3hDb2xvcjsNCiAgaW50IGcgPSAxNjAtYm94Q29sb3I7DQogIGludCBiID0gMDsNCiAgICANCiAgLy9pZiAoYm94U2l6ZSA+IDE2KSB7DQogIC8vciA9IDk2LWNvbFZhbDsNCiAgLy9nID0gMDsNCiAgLy9iID0gY29sVmFsOw0KICAvL30NCiAgDQogIHVpbnQxNl90IGJveENvbG9yUkdCID0gbWF0cml4LkNvbG9yKHIsIGcsIGIpOw0KDQogIGlmIChkcmF3SW1tZWRpYXRlKQ0KICAgIG1hdHJpeC5jbGVhcigpOw0KICANCiAgZm9yIChpbnQgeD0wOyB4PGJveFNpemVJbnQ7IHgrKykgew0KICAgIGZvciAoaW50IHk9MDsgeTxib3hTaXplSW50OyB5KyspIHsNCiAgICAgIG1hdHJpeC5kcmF3UGl4ZWwoeCwgNy15LCBib3hDb2xvclJHQik7DQogICAgfSAgIA0KICB9DQoNCiAgaWYgKGJveFNpemVGcmFjID09IDApIHsNCiAgICByID0gMDsNCiAgICBnID0gMDsNCiAgICBiID0gMDsNCiAgfQ0KICBpZiAoYm94U2l6ZUZyYWMgPT0gMSkgew0KICAgIHIgPSByID4+IDI7DQogICAgZyA9IGcgPj4gMjsNCiAgICBiID0gYiA+PiAyOw0KICB9DQogIGlmIChib3hTaXplRnJhYyA9PSAyKSB7DQogICAgciA9IHIgPj4gMTsNCiAgICBnID0gZyA+PiAxOw0KICAgIGIgPSBiID4+IDE7DQogIH0NCiAgaWYgKGJveFNpemVGcmFjID09IDMpIHsNCiAgICByID0gKHIgPj4gMSkgKyAociA+PiAyKTsNCiAgICBnID0gKGcgPj4gMSkgKyAoZyA+PiAyKTsNCiAgICBiID0gKGIgPj4gMSkgKyAoYiA+PiAyKTsNCiAgfQ0KICBib3hDb2xvclJHQiA9IG1hdHJpeC5Db2xvcihyLCBnLCBiKTsNCiAgICANCiAgZm9yIChpbnQgeT0wOyB5PGJveFNpemVJbnQ7IHkrKykgew0KICAgIG1hdHJpeC5kcmF3UGl4ZWwoYm94U2l6ZUludCwgNy15LCBib3hDb2xvclJHQik7DQogIH0NCiAgZm9yIChpbnQgeD0wOyB4PD1ib3hTaXplSW50OyB4KyspIHsNCiAgICBtYXRyaXguZHJhd1BpeGVsKHgsIDctYm94U2l6ZUludCwgYm94Q29sb3JSR0IpOw0KICB9ICAgICANCg0KICBpZiAoZHJhd0ltbWVkaWF0ZSkNCiAgICBtYXRyaXguc2hvdygpOw0KDQp9DQoNCg0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQovLyBwb3RWYWx1ZQ0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQppbnQgcG90VmFsdWUocG90UG9zdGlvbiB3aGljaFBvdCwgZmxvYXQgc2NhbGUpIHsNCiAgaW50IHZhbHVlID0gLTE7DQogIHN3aXRjaCAod2hpY2hQb3QpIHsNCiAgICBjYXNlIGxlZnQ6ICAgDQogICAgICB2YWx1ZSA9IGFuYWxvZ1JlYWQocG90TGVmdCk7DQogICAgICBicmVhazsNCiAgICBjYXNlIHJpZ2h0Og0KICAgICAgdmFsdWUgPSBhbmFsb2dSZWFkKHBvdFJpZ2h0KTsgDQogICAgICBicmVhazsNCiAgICBjYXNlIGNlbnRlcjoNCiAgICAgIHZhbHVlID0gYW5hbG9nUmVhZChwb3RDZW50ZXIpOw0KICAgICAgYnJlYWs7DQogIH0NCiAgdmFsdWUgPSAoaW50KSB2YWx1ZSAqIHNjYWxlOw0KICByZXR1cm4gdmFsdWU7DQp9DQoNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KLy8gYnV0dG9uUHJlc3NlZA0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQpib29sZWFuIGJ1dHRvblByZXNzZWQoYnV0dG9uQ29sb3Igd2hpY2hCdXR0b24pIHsNCiAgaW50IGpveVByZXNzID0gZGlnaXRhbFJlYWQoam95QnV0dG9uKTsNCiAgaW50IGdyZWVuUHJlc3MgPSBkaWdpdGFsUmVhZChncmVlbkJ1dHRvbik7DQogIGludCBibHVlUHJlc3MgPSBkaWdpdGFsUmVhZChibHVlQnV0dG9uKTsNCiAgaW50IHJlZFByZXNzID0gZGlnaXRhbFJlYWQocmVkQnV0dG9uKTsNCiAgYm9vbGVhbiBwcmVzc2VkID0gZmFsc2U7DQoNCiAgc3dpdGNoICh3aGljaEJ1dHRvbikgew0KICAgIGNhc2UgYmx1ZToNCiAgICAgIGlmIChibHVlUHJlc3MgPT0gMCkNCiAgICAgICAgcHJlc3NlZCA9IHRydWU7DQogICAgICBicmVhazsNCiAgICBjYXNlIHJlZDoNCiAgICAgIGlmIChyZWRQcmVzcyA9PSAwKQ0KICAgICAgICBwcmVzc2VkID0gdHJ1ZTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2Ugam95Og0KICAgICAgaWYgKGpveVByZXNzID09IDApDQogICAgICAgIHByZXNzZWQgPSB0cnVlOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBncmVlbjoNCiAgICAgIGlmIChncmVlblByZXNzID09IDApDQogICAgICAgIHByZXNzZWQgPSB0cnVlOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBhbnk6DQogICAgICBpZiAoKGJsdWVQcmVzcyA9PSAwKSB8fCAocmVkUHJlc3MgPT0gMCkgfHwgKGpveVByZXNzID09IDApIHx8IChncmVlblByZXNzID09IDApKQ0KICAgICAgICBwcmVzc2VkID0gdHJ1ZTsNCiAgICAgIGJyZWFrOw0KICAgIGRlZmF1bHQ6DQogICAgICBwcmVzc2VkID0gZmFsc2U7DQogIH0NCg0KICB1bnNpZ25lZCBsb25nIHRpbWVTaW5jZSA9IG1pbGxpcygpIC0gbGFzdFByZXNzZWQ7DQogIGlmICgocHJlc3NlZCkgJiYgKHRpbWVTaW5jZSA8IGJ1dHRvblJlbGVhc2VEZWxheSkpIHsNCiAgICBsYXN0UHJlc3NlZCA9IG1pbGxpcygpOw0KICAgIHByZXNzZWQgPSBmYWxzZTsNCiAgfSBlbHNlIGlmIChwcmVzc2VkKSB7DQogICAgbGFzdFByZXNzZWQgPSBtaWxsaXMoKTsNCiAgfQ0KDQogIHJldHVybiBwcmVzc2VkOw0KICANCn0NCg0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQovLyBzZXRORU9TY3JvbGxNZXNzYWdlDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCnZvaWQgc2V0TkVPU2Nyb2xsTWVzc2FnZShTdHJpbmcgbWVzc2FnZSwgdWludDE2X3QgY29sb3IpIHsNCiAgc2Nyb2xsTkVPTWVzc2FnZSA9IG1lc3NhZ2U7DQogIHNjcm9sbE5FT01pbGxpU2VjID0gbWlsbGlzKCk7DQogIHNjcm9sbE5FT01lc3NhZ2VSZXNldCA9IC02ICogc2Nyb2xsTkVPTWVzc2FnZS5sZW5ndGgoKTsNCiAgc2Nyb2xsTkVPTWVzc2FnZVBvcyA9IG1hdHJpeC53aWR0aCgpOw0KICBzY3JvbGxORU9Db2xvciA9IGNvbG9yOw0KfQ0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIHVwZGF0ZU5FT1Njcm9sbE1lc3NhZ2UNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0Kdm9pZCB1cGRhdGVORU9TY3JvbGxNZXNzYWdlKCl7DQogIGlmIChtaWxsaXMoKS1zY3JvbGxORU9NaWxsaVNlYyA+IE5FT3Njcm9sbFNwZWVkKSB7DQogICAgbWF0cml4LmZpbGxTY3JlZW4oMCk7DQogICAgbWF0cml4LnNldEN1cnNvcihzY3JvbGxORU9NZXNzYWdlUG9zLCAwKTsNCiAgICBtYXRyaXguc2V0VGV4dENvbG9yKHNjcm9sbE5FT0NvbG9yKTsNCiAgICBtYXRyaXgucHJpbnQoc2Nyb2xsTkVPTWVzc2FnZSk7DQogICAgaWYoLS1zY3JvbGxORU9NZXNzYWdlUG9zIDwgc2Nyb2xsTkVPTWVzc2FnZVJlc2V0KSB7DQogICAgICBzY3JvbGxORU9NZXNzYWdlUG9zID0gbWF0cml4LndpZHRoKCk7DQogICAgfQ0KICAgIG1hdHJpeC5zaG93KCk7DQogICAgc2Nyb2xsTkVPTWlsbGlTZWMgPSBtaWxsaXMoKTsNCiAgfQ0KfQ0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIG5uRmVlZEZvcndhcmQNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KaW50IG5uRmVlZEZvcndhcmQoZmxvYXQgeHMsIGZsb2F0IHlzKSB7DQogIGZsb2F0IHN1bSA9IDA7DQogIGZsb2F0IGlucHV0c1szXTsNCiAgaW5wdXRzWzBdID0geHM7IA0KICBpbnB1dHNbMV0gPSB5czsNCiAgaW5wdXRzWzJdID0gMS4wOw0KICBmb3IgKGludCBpPTA7IGk8MzsgaSsrKSB7DQogICAgc3VtICs9IGlucHV0c1tpXSAqIG5uV2VpZ2h0c1tpXTsgIA0KICB9DQogIHJldHVybiBubkFjdGl2YXRlKHN1bSk7DQp9DQoNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KLy8gbm5BY3RpdmF0ZQ0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQppbnQgbm5BY3RpdmF0ZShmbG9hdCBzdW0pew0KICBpZiAoc3VtPjApIHJldHVybiAxOw0KICBlbHNlIHJldHVybiAtMTsNCn0NCg0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQovLyBubkFkanVzdFdlaWdodHMNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KaW50IG5uQWRqdXN0V2VpZ2h0cyhmbG9hdCB4cywgZmxvYXQgeXMsIGludCBlcnJvcikgew0KICBmbG9hdCBpbnB1dHNbM107DQogIGlucHV0c1swXSA9IHhzOyANCiAgaW5wdXRzWzFdID0geXM7DQogIGlucHV0c1syXSA9IDEuMDsNCiAgZm9yIChpbnQgaT0wOyBpPDM7IGkrKykgew0KICAgIG5uV2VpZ2h0c1tpXSArPSBubkxlYXJuaW5nQyAqIChmbG9hdCllcnJvciAqIGlucHV0c1tpXTsgICAgICAgICANCiAgfQ0KfQ0KDQppbnQgbWVudVVwZGF0ZShib29sZWFuIHNob3dJY29ucykgew0KDQogIGlmIChtaWxsaXMoKSAtIGxhc3RSZWFkID4gMTUwKSB7DQogICAgaW50IHYgPSBhbmFsb2dSZWFkKGpveVYpOw0KDQogICAgcG9zTGFzdCA9IHBvc05vdzsNCiAgICANCiAgICBpZiAodiA+IDgwMCkNCiAgICAgIHBvc05vdyA9IGRvd247DQogICAgZWxzZSBpZiAodiA8IDMwMCkNCiAgICAgIHBvc05vdyA9IHVwOw0KICAgIGVsc2UgaWYgKHYgPCA2MDAgJiYgdiA+IDQwMCkNCiAgICAgIHBvc05vdyA9IG1pZGRsZTsNCg0KICAgIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT1kb3duKXsNCiAgICAgIGVudHJ5U2VsKys7DQogICAgICBtZW51VXBkYXRlTENEID0gdHJ1ZTsNCiAgICAgIGlmIChlbnRyeVNlbCA9PSBtZW51TnVtRW50cmllcykNCiAgICAgICAgZW50cnlTZWwgPSBtZW51TnVtRW50cmllcy0xOw0KICAgIH0NCiAgICBlbHNlIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT11cCkgew0KICAgICAgZW50cnlTZWwtLTsNCiAgICAgIG1lbnVVcGRhdGVMQ0QgPSB0cnVlOyAgIA0KICAgICAgaWYgKGVudHJ5U2VsIDwgMCkNCiAgICAgICAgZW50cnlTZWwgPSAwOw0KICAgIH0gICAgDQogICAgbGFzdFJlYWQgPSBtaWxsaXMoKTsNCg0KDQogIH0NCg0KICBpZiAobWVudVVwZGF0ZUxDRCkgeyANCiAgICANCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgIGxjZC5wcmludChtZW51SGVhZGluZyk7DQogICAgDQogICAgbGNkLnNldEN1cnNvcigwLCAyKTsNCiAgICBsY2QucHJpbnQoIi0+Iik7DQogIA0KICAgIA0KICAgIA0KICAgIGxjZC5zZXRDdXJzb3IoMiwgMik7DQogICAgaWYgKG1lbnVMb2Nrc1tlbnRyeVNlbF0gJiYgc2hvd0ljb25zKSB7DQogICAgICBsY2Qud3JpdGUoYnl0ZSgwKSk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDMsIDIpOw0KICAgIH0gDQogICAgbGNkLnByaW50KG1lbnVFbnRyaWVzW2VudHJ5U2VsXSk7DQogIA0KICAgIGlmIChlbnRyeVNlbD09MCkgew0KICAgICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIiAiKSk7ICANCiAgICB9IGVsc2Ugew0KICAgICAgbGNkLnNldEN1cnNvcigyLCAxKTsNCiAgICAgIGlmIChtZW51TG9ja3NbZW50cnlTZWwtMV0gJiYgc2hvd0ljb25zKSB7DQogICAgICAgIGxjZC53cml0ZShieXRlKDApKTsNCiAgICAgICAgbGNkLnNldEN1cnNvcigzLCAxKTsNCiAgICAgIH0NCiAgICAgIGxjZC5wcmludChtZW51RW50cmllc1tlbnRyeVNlbC0xXSk7DQogICAgfSANCiAgDQogICAgaWYgKGVudHJ5U2VsPT1tZW51TnVtRW50cmllcy0xKSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiICIpKTsgIA0KICAgIH0gZWxzZSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDIsIDMpOw0KICAgICAgaWYgKG1lbnVMb2Nrc1tlbnRyeVNlbCsxXSAmJiBzaG93SWNvbnMpIHsNCiAgICAgICAgbGNkLndyaXRlKGJ5dGUoMCkpOw0KICAgICAgICBsY2Quc2V0Q3Vyc29yKDMsIDMpOw0KICAgICAgfQ0KICAgICAgbGNkLnByaW50KG1lbnVFbnRyaWVzW2VudHJ5U2VsKzFdKTsNCiAgICB9DQogICAgbWVudVVwZGF0ZUxDRCA9IGZhbHNlOw0KICB9DQoNCiAgcmV0dXJuIGVudHJ5U2VsOw0KICANCn0NCg0Kdm9pZCBtZW51QWRkSGVhZGluZyhTdHJpbmcgaCkgew0KICBtZW51SGVhZGluZyA9IHBhZFN0cmluZygyMCxoKTsNCn0NCg0Kdm9pZCBtZW51QWRkRW50cnkoaW50IGksIFN0cmluZyBlKSB7DQogIGlmIChpPDE2KSB7DQogICAgbWVudUVudHJpZXNbaV0gPSBwYWRTdHJpbmcoMTcsZSk7IA0KICAgIG1lbnVOdW1FbnRyaWVzKys7DQogICAgbWVudVVwZGF0ZUxDRCA9IHRydWU7DQogIH0NCg0KfQ0KDQp2b2lkIG1lbnVDbGVhcigpIHsNCiAgbWVudU51bUVudHJpZXMgPSAwOw0KICBlbnRyeVNlbD0wOw0KICBtZW51SGVhZGluZyA9ICIgIjsNCiAgZm9yIChpbnQgaT0wOyBpPDE2OyBpKyspIHsNCiAgICBtZW51RW50cmllc1tpXSA9ICIgIjsgICAgDQogIH0NCiAgbWVudVVwZGF0ZUxDRCA9IHRydWU7DQp9DQoNCmludCBwYWdlVXBkYXRlKCkgew0KDQogIGlmIChtaWxsaXMoKSAtIGxhc3RSZWFkID4gMTUwKSB7DQogICAgaW50IHYgPSBhbmFsb2dSZWFkKGpveVYpOw0KDQogICAgcG9zTGFzdCA9IHBvc05vdzsNCiAgICANCiAgICBpZiAodiA+IDkwMCkNCiAgICAgIHBvc05vdyA9IGRvd247DQogICAgZWxzZSBpZiAodiA8IDIwMCkNCiAgICAgIHBvc05vdyA9IHVwOw0KICAgIGVsc2UgaWYgKHYgPCA1NzYgJiYgdiA+IDQ0OCkNCiAgICAgIHBvc05vdyA9IG1pZGRsZTsNCg0KICAgIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT1kb3duKXsNCiAgICAgIGVudHJ5U2VsKys7DQogICAgICBwYWdlVXBkYXRlTENEID0gdHJ1ZTsNCiAgICAgIGlmIChlbnRyeVNlbCA9PSBwYWdlTnVtRW50cmllcykNCiAgICAgICAgZW50cnlTZWwgPSBwYWdlTnVtRW50cmllcy0xOw0KICAgIH0NCiAgICBlbHNlIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT11cCkgew0KICAgICAgZW50cnlTZWwtLTsNCiAgICAgIHBhZ2VVcGRhdGVMQ0QgPSB0cnVlOyAgIA0KICAgICAgaWYgKGVudHJ5U2VsIDwgMCkNCiAgICAgICAgZW50cnlTZWwgPSAwOw0KICAgIH0gICAgDQogICAgbGFzdFJlYWQgPSBtaWxsaXMoKTsNCg0KICB9DQoNCiAgaWYgKHBhZ2VVcGRhdGVMQ0QpIHsgDQogICAgDQogICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICBsY2QucHJpbnQocGFnZUhlYWRpbmcpOw0KICANCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICAgIGxjZC5wcmludChwYWdlRW50cmllc1tlbnRyeVNlbF0pOw0KICANCiAgICBpZiAoZW50cnlTZWw9PTApIHsNCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCIgIikpOyAgDQogICAgfSBlbHNlIHsNCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBsY2QucHJpbnQocGFnZUVudHJpZXNbZW50cnlTZWwtMV0pOw0KICAgIH0NCiAgDQogICAgaWYgKGVudHJ5U2VsPT1wYWdlTnVtRW50cmllcy0xKSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiICIpKTsgIA0KICAgIH0gZWxzZSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZ2VFbnRyaWVzW2VudHJ5U2VsKzFdKTsNCiAgICB9DQogICAgcGFnZVVwZGF0ZUxDRCA9IGZhbHNlOw0KICB9DQoNCiAgcmV0dXJuIGVudHJ5U2VsOw0KICANCn0NCg0KDQp2b2lkIHBhZ2VBZGRIZWFkaW5nKFN0cmluZyBoKSB7DQogIHBhZ2VIZWFkaW5nID0gcGFkU3RyaW5nKDIwLGgpOw0KfQ0KDQp2b2lkIHBhZ2VBZGRFbnRyeShpbnQgaSwgU3RyaW5nIGUpIHsNCiAgaWYgKGk8MzIpIHsNCiAgICBwYWdlRW50cmllc1tpXSA9IHBhZFN0cmluZygyMCxlKTsgDQogICAgcGFnZU51bUVudHJpZXMrKzsNCiAgICBwYWdlVXBkYXRlTENEID0gdHJ1ZTsNCiAgfQ0KfQ0KDQp2b2lkIHBhZ2VDbGVhcigpIHsNCiAgcGFnZU51bUVudHJpZXMgPSAwOw0KICBlbnRyeVNlbD0wOw0KICBwYWdlSGVhZGluZyA9ICIgIjsNCiAgZm9yIChpbnQgaT0wOyBpPDMyOyBpKyspIHsNCiAgICBwYWdlRW50cmllc1tpXSA9ICIgIjsgICAgDQogIH0NCiAgcGFnZVVwZGF0ZUxDRCA9IHRydWU7DQp9DQoNCg0KU3RyaW5nIHBhZFN0cmluZyhpbnQgbGVuLCBTdHJpbmcgaW4pIHsNCiAgU3RyaW5nIG91dDsNCiAgaWYgKGluLmxlbmd0aCgpIDwgbGVuKSB7IA0KICAgIG91dCA9IGluOw0KICAgIGludCBsID0gbGVuLWluLmxlbmd0aCgpOw0KICAgIGZvciAoaW50IGk9MDsgaTxsOyBpKyspIHsNCiAgICAgIG91dCs9IiAiOyAgDQogICAgfQ0KICB9IGVsc2Ugew0KICAgIG91dCA9IGluLnN1YnN0cmluZygwLGxlbik7DQogIH0NCiAgcmV0dXJuIG91dDsgIA0KfQ0KDQp2b2lkIHBsYXlUb25lKGludCBtaWRpQSwgaW50IGR1cmF0aW9uKSB7DQogIHRUaW1lID0gbWlsbGlzKCk7DQogIHREdXJhdGlvbiA9IGR1cmF0aW9uOw0KICB0b25lQWN0aXZlID0gdHJ1ZTsNCiAgcGxheUR1YWwgPSBmYWxzZTsNCg0KICAvLyA4ODIgdG8gZ28gPSA2NTgtNjY1IHplcm8gY3Jvc3NpbmcNCg0KICAvL3NhbXBsZXMgPSAoKGR1cmF0aW9uICogMTAwMCkgLyAyMi43KTsvLyAtIDg4MjsNCiAgLy9pZiAoc2FtcGxlcyA8IDApIHNhbXBsZXMgPSAwOyANCiAgLy9jb3VudFNhbXBsZXMgPSAwOw0KDQogIHVsUGhhc2VJbmNyZW1lbnRBID0gbk1pZGlQaGFzZUluY3JlbWVudFttaWRpQV07DQp9DQoNCnZvaWQgcGxheUR1YWxUb25lKGludCBtaWRpQSwgaW50IG1pZGlCLCBmbG9hdCBtaXgsIGludCBkdXJhdGlvbikgew0KICB0VGltZSA9IG1pbGxpcygpOw0KICB0RHVyYXRpb24gPSBkdXJhdGlvbjsNCiAgdG9uZUFjdGl2ZSA9IHRydWU7DQogIHBsYXlEdWFsID0gdHJ1ZTsNCg0KICB1bFBoYXNlSW5jcmVtZW50QSA9IG5NaWRpUGhhc2VJbmNyZW1lbnRbbWlkaUFdOw0KICB1bFBoYXNlSW5jcmVtZW50QiA9IG5NaWRpUGhhc2VJbmNyZW1lbnRbbWlkaUJdOw0KDQogIGlmIChtaXggPDAuMCkgbWl4ID0gMC4wOw0KICBpZiAobWl4ID4xLjApIG1peCA9IDEuMDsNCg0KICB0b25lTWl4QSA9IG1peDsNCiAgdG9uZU1peEIgPSAxLTAgLSBtaXg7DQogIA0KfQ0KDQp2b2lkIGFtcE9uKCkgew0KICBkaWdpdGFsV3JpdGUoYW1wRW5hYmxlLEhJR0gpOyANCn0NCg0Kdm9pZCBhbXBPZmYoKSB7DQogIGRpZ2l0YWxXcml0ZShhbXBFbmFibGUsTE9XKTsgDQp9DQoNCnZvaWQgY2xlYXJUb25lKCkgew0KICB0b25lQWN0aXZlID0gZmFsc2U7DQp9DQoNCnZvaWQgVEM0X0hhbmRsZXIoKQ0Kew0KICANCiAgDQogIC8vIFdlIG5lZWQgdG8gZ2V0IHRoZSBzdGF0dXMgdG8gY2xlYXIgaXQgYW5kIGFsbG93IHRoZSBpbnRlcnJ1cHQgdG8gZmlyZSBhZ2Fpbg0KICBUQ19HZXRTdGF0dXMoVEMxLCAxKTsNCiANCiAgaWYgKHRvbmVBY3RpdmUpIHsNCg0KICAgIHVsUGhhc2VBY2N1bXVsYXRvckEgKz0gdWxQaGFzZUluY3JlbWVudEE7ICAgLy8gMzIgYml0IHBoYXNlIGluY3JlbWVudCwgc2VlIGJlbG93DQogICAgdWxQaGFzZUFjY3VtdWxhdG9yQiArPSB1bFBoYXNlSW5jcmVtZW50QjsgIA0KICANCiAgICAvLyBpZiB0aGUgcGhhc2UgYWNjdW11bGF0b3Igb3ZlciBmbG93cyAtIHdlIGhhdmUgYmVlbiB0aHJvdWdoIG9uZSBjeWNsZSBhdCB0aGUgY3VycmVudCBwaXRjaCwNCiAgICAvLyBub3cgd2UgbmVlZCB0byByZXNldCB0aGUgZ3JhaW5zIHJlYWR5IGZvciBvdXIgbmV4dCBjeWNsZQ0KICAgIGlmKHVsUGhhc2VBY2N1bXVsYXRvckEgPiBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UKQ0KICAgICAgdWxQaGFzZUFjY3VtdWxhdG9yQSAtPSBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UOw0KICAgIGlmKHVsUGhhc2VBY2N1bXVsYXRvckIgPiBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UKQ0KICAgICAgdWxQaGFzZUFjY3VtdWxhdG9yQiAtPSBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UOw0KICAgICAgDQogICAgdWludDMyX3QgcGhhc2VBZGp1c3RQQWNjQSA9ICh1bFBoYXNlQWNjdW11bGF0b3JBPj4yMCkgJSBTSU5FX1NBTVBMRVM7DQogICAgdWludDMyX3QgcGhhc2VBZGp1c3RQQWNjQiA9ICh1bFBoYXNlQWNjdW11bGF0b3JCPj4yMCkgJSBTSU5FX1NBTVBMRVM7DQoNCiAgICAvLyBnZXQgdGhlIGN1cnJlbnQgc2FtcGxlICAgDQogICAgdWludDMyX3QgdWxPdXRwdXRBID0gc2luZVdhdmVbcGhhc2VBZGp1c3RQQWNjQV07DQogICAgdWludDMyX3QgdWxPdXRwdXRCID0gc2luZVdhdmVbcGhhc2VBZGp1c3RQQWNjQl07DQoNCiAgICB1aW50MzJfdCB1bE91dHB1dDsNCg0KICAgIGlmICghcGxheUR1YWwpDQogICAgICB1bE91dHB1dCA9IHVsT3V0cHV0QTsNCiAgICBlbHNlIHsNCiAgICAgIHVsT3V0cHV0ID0gKHVpbnQzMl90KSh1bE91dHB1dEEgKiB0b25lTWl4QSkgKyAodWludDMyX3QpKHVsT3V0cHV0QiAqIHRvbmVNaXhCKTsNCiAgICB9DQoNCiAgICB1bE91dHB1dCA9IHVsT3V0cHV0ICogKHZvbHVtZS8xMC4wKTsNCiAgIA0KICAgIGRhY2Nfd3JpdGVfY29udmVyc2lvbl9kYXRhKERBQ0NfSU5URVJGQUNFLCB1bE91dHB1dCk7DQoNCiAgICBpZiAobWlsbGlzKCkgLSB0VGltZSA+IHREdXJhdGlvbikgew0KICAgICAgdG9uZUFjdGl2ZSA9IGZhbHNlOyANCiAgICAgIC8vZGlnaXRhbFdyaXRlKDQxLExPVyk7DQogICAgfQ0KICB9IA0KDQp9DQoNCnZvaWQgbWFrZVNpbmVXYXZlKCkNCnsNCiAgZm9yKGludCBpID0gMDtpIDwgU0lORV9TQU1QTEVTOyBpKyspIHsNCiAgICBzaW5lV2F2ZVtpXSA9ICh1aW50MTZfdCkgICgoKDErc2luKCgoMi4wKlBJKS9TSU5FX1NBTVBMRVMpKmkpKSo0MDk1LjApLzIpOw0KICB9DQp9DQoNCi8vIGZpbGwgdGhlIG5vdGUgdGFibGUgd2l0aCB0aGUgcGhhc2UgaW5jcmVtZW50IHZhbHVlcyB3ZSByZXF1aXJlIHRvIGdlbmVyYXRlIHRoZSBub3RlDQp2b2lkIGNyZWF0ZU5vdGVUYWJsZShmbG9hdCBmU2FtcGxlUmF0ZSkNCnsNCiAgZm9yKHVpbnQzMl90IHVuTWlkaU5vdGUgPSAwO3VuTWlkaU5vdGUgPCBNSURJX05PVEVTO3VuTWlkaU5vdGUrKykgew0KICAgIC8vIENvcnJlY3QgY2FsY3VsYXRpb24gZm9yIGZyZXF1ZW5jeQ0KICAgIGZsb2F0IGZGcmVxdWVuY3kgPSAoKHBvdygyLjAsKHVuTWlkaU5vdGUtNjkuMCkvMTIuMCkpICogNDQwLjApOw0KICAgIG5NaWRpUGhhc2VJbmNyZW1lbnRbdW5NaWRpTm90ZV0gPSBmRnJlcXVlbmN5KlRJQ0tTX1BFUl9DWUNMRTsNCiAgfQ0KfQ0KDQp2b2lkIHNjcmVlblNhdmVyKCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBtYXRyaXguY2xlYXIoKTsNCiAgbWF0cml4LnNob3coKTsNCg0KICBmb3IgKGludCB4PTA7IHg8ODsgeCsrKSB7DQogICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgdGlsZVt4XVt5XSA9IDA7DQogICAgfQ0KICB9DQogIA0KICBmb3IgKGludCBpPTA7IGk8MzI7IGkrKykgew0KICAgIGJvb2xlYW4gc2V0ID0gZmFsc2U7DQogICAgd2hpbGUgKCFzZXQpIHsNCiAgICAgIGludCB4ID0gcmFuZG9tKDgpOw0KICAgICAgaW50IHkgPSByYW5kb20oOCk7DQogICAgICBpZiAodGlsZVt4XVt5XT09MCkgew0KICAgICAgICB0aWxlW3hdW3ldID0gcmFuZG9tKDEyOCkrNjQ7DQogICAgICAgIHNldCA9IHRydWU7DQogICAgICB9DQogICAgfQ0KICB9DQoNCiAgaW50IHN0cyA9IDA7DQogIGludCB0dHMgPSAwOw0KICBpbnQgdFdhaXQgPSBzYXZlclRleHRNaW5TaG93Ow0KDQogIHdoaWxlICghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQoNCiAgICBpZiAobWlsbGlzKCktdHRzID4gdFdhaXQpIHsNCiAgICAgIGludCByID0gcmFuZG9tKHNhdmVyVGV4dE51bSk7DQogICAgICBmb3IgKGludCBpPTA7IGk8NDsgaSsrKSB7DQogICAgICAgIGxjZC5zZXRDdXJzb3IoMCxpKTsNCg0KICAgICAgICBTdHJpbmcgdGVtcCA9IHNhdmVyVGV4dFtyXVtpXTsNCiAgICAgICAgaWYgKHRlbXAuc3Vic3RyaW5nKDAsMTApLmVxdWFscygiPGJveCBuYW1lPiIpKQ0KICAgICAgICAgIHRlbXAgPSBib3hOYW1lICsgdGVtcC5zdWJzdHJpbmcoMTApOw0KICAgICAgICANCiAgICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCx0ZW1wKSk7IA0KICAgICAgfSANCiAgICAgIHR0cyA9IG1pbGxpcygpOw0KICAgICAgdFdhaXQgPSByYW5kb20oMTAwMDApK3NhdmVyVGV4dE1pblNob3c7ICAgDQogICAgfQ0KDQogICAgLy8gZXZlcnkgMTAwbXMgLSBzaHVmZmxlIHRoZSBib2FyZA0KICAgIGlmIChtaWxsaXMoKS1zdHMgPiAxMDApIHsNCiAgICAgIA0KICAgICAgbWF0cml4LmNsZWFyKCk7DQogICAgICBmb3IgKGludCB4PTA7IHg8ODsgeCsrKSB7DQogICAgICAgIGZvciAoaW50IHk9MDsgeTw4OyB5KyspIHsNCiAgICAgICAgICBpZiAodGlsZVt4XVt5XSE9MCkgew0KICAgICAgICAgICAgbWF0cml4LmRyYXdQaXhlbCh4LHksbWF0cml4LkNvbG9yKHRpbGVbeF1beV0sMCwxOTItdGlsZVt4XVt5XSkpOw0KICAgICAgICAgIH0gICAgICAgICANCiAgICAgICAgfQ0KICAgICAgfQ0KICAgICAgbWF0cml4LnNob3coKTsgDQoNCiAgICAgIGZvciAoaW50IHg9MDsgeDw4OyB4KyspIHsNCiAgICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICAgIG1vdmVkW3hdW3ldID0gZmFsc2U7DQogICAgICAgIH0NCiAgICAgIH0NCg0KICAgICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgICBmb3IgKGludCB5PTA7IHk8ODsgeSsrKSB7DQogICAgDQogICAgICAgICAgaWYgKHRpbGVbeF1beV0hPTAgJiAhbW92ZWRbeF1beV0pIHsNCiAgICAgICAgICAgIGJvb2xlYW4gZnJlZSA9IGZhbHNlOw0KICAgICAgICAgICAgaW50IHRyaWVzID0gMDsNCiAgICAgICAgICAgIHdoaWxlICghZnJlZSkgew0KICAgICAgICAgICAgICBpbnQgeGQgPSByYW5kb20oMyktMTsNCiAgICAgICAgICAgICAgaW50IHlkID0gcmFuZG9tKDMpLTE7DQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgICBpZiAoKHhkIT0wICYmIHlkPT0wKSB8fCAoeGQ9PTAgJiYgeWQhPTApICl7DQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIGludCB4cCA9IHgreGQ7DQogICAgICAgICAgICAgICAgaWYgKHhwPDApIHhwID0gMDsNCiAgICAgICAgICAgICAgICBpZiAoeHA+NykgeHAgPSA3Ow0KICAgICAgICAgICAgICAgIGludCB5cCA9IHkreWQ7DQogICAgICAgICAgICAgICAgaWYgKHlwPDApIHlwID0gMDsNCiAgICAgICAgICAgICAgICBpZiAoeXA+NykgeXAgPSA3Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICBpZiAodGlsZVt4cF1beXBdPT0wKSB7DQogICAgICAgICAgICAgICAgICB0aWxlW3hwXVt5cF0gPSB0aWxlW3hdW3ldOw0KICAgICAgICAgICAgICAgICAgdGlsZVt4XVt5XSA9IDA7DQogICAgICAgICAgICAgICAgICBtb3ZlZFt4cF1beXBdID0gdHJ1ZTsNCiAgICAgICAgICAgICAgICAgIGZyZWUgPSB0cnVlOw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICB0cmllcyArKzsNCiAgICAgICAgICAgICAgICBpZiAodHJpZXMgPT0gMTApIHsNCiAgICAgICAgICAgICAgICAgIGZyZWUgPSB0cnVlOyAgDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgfQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgfQ0KICAgICAgDQogICAgICBzdHMgPSBtaWxsaXMoKTsNCiAgICAgICAgDQogICAgfS8vIGV2cnkgMTAwbXMgc2h1ZmZsZSB0aGUgdGlsZXMNCiAgICANCiAgfQ0KICANCn0NCg0Kdm9pZCBzZXREaWZmaWN1bHR5KCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBwYWdlQ2xlYXIoKTsNCiAgcGFnZUFkZEhlYWRpbmcoIi0tLS0tRElGRklDVUxUWS0tLS0tIik7DQoNCiAgcGFnZUFkZEVudHJ5KDAsICJVc2UgdGhlIGRpYWxzIHRvIHNldCIpOw0KICBwYWdlQWRkRW50cnkoMSwgInRoZSBkaWZmaWN1bHR5IG9mIik7DQogIHBhZ2VBZGRFbnRyeSgyLCAiV29yayBNb2RlLiIpOw0KICBwYWdlQWRkRW50cnkoMywgIlRoaXMgc2V0dGluZyBhZGp1c3RzIik7DQogIHBhZ2VBZGRFbnRyeSg0LCAidGhlIHJhZGl1cyBvZiB0aGUiKTsNCiAgcGFnZUFkZEVudHJ5KDUsICJhcmVhIHRoYXQgdGhlIGJveCIpOw0KICBwYWdlQWRkRW50cnkoNiwgImZhY3Rvcnkgd2lsbCBtYWtlIik7DQogIHBhZ2VBZGRFbnRyeSg3LCAiYm94ZXMuIik7DQogIA0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogICAgaW50IHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICB9DQoNCiAgbGNkLmNsZWFyKCk7DQogIA0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQoNCiAgICBpbnQgcHYgPSBwb3RWYWx1ZShjZW50ZXIsIDAuMDEpOw0KICAgIGlmIChwdiA8IDApDQogICAgICBwdiA9IDA7DQogICAgaWYgKHB2ID4gMTApDQogICAgICBwdiA9IDEwOw0KDQogICAgZ29vZEJveFJhZGl1cyA9IDAuOSArICgoZmxvYXQpKHB2Pj4xKSAvIDEwLjApOyAgDQoNCiAgICBTdHJpbmcgZGlmZkEgPSAiTUVESVVNOiBtYWtlIHNvbWUiOw0KICAgIFN0cmluZyBkaWZmQiA9ICJtZWRpdW0gb3Igb3JhbmdlIjsNCiAgICBTdHJpbmcgZGlmZkMgPSAiYm94ZXMiOw0KICAgIGlmIChnb29kQm94UmFkaXVzIDw9IDEuMDUpIHsNCiAgICAgIGRpZmZBID0gIkVBU1k6IG1ha2UgbGVzcyI7DQogICAgICBkaWZmQiA9ICJtZWRpdW0gb3Igb3JhbmdlIjsNCiAgICAgIGRpZmZDID0gImJveGVzIjsNCiAgICB9DQogICAgaWYgKGdvb2RCb3hSYWRpdXMgPj0gMS4yNSkgew0KICAgICAgZGlmZkEgPSAiSEFSRDogbWFrZSBtb3JlIjsNCiAgICAgIGRpZmZCID0gIm1lZGl1bSBvciBvcmFuZ2UiOw0KICAgICAgZGlmZkMgPSAiYm94ZXMiOw0KICAgIH0NCiAgICBsY2Quc2V0Q3Vyc29yKDAsMCk7DQogICAgbGNkLnByaW50KHBhZFN0cmluZygyMCxkaWZmQSkpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwxKTsNCiAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLGRpZmZCKSk7DQogICAgbGNkLnNldEN1cnNvcigwLDIpOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsZGlmZkMpKTsNCiAgICBsY2Quc2V0Q3Vyc29yKDAsMyk7DQogICAgbGNkLnByaW50KCJCb3ggUmFkaXVzID0gIiArIFN0cmluZyhnb29kQm94UmFkaXVzLDEpKTsNCg0KICB9DQoNCiAgbG9nU2V0dGluZ3MoKTsNCiAgcmV0dXJuOw0KfQ0KDQoNCg0Kdm9pZCBzeW50aE1vZGUoKSB7DQogIGxjZC5jbGVhcigpOw0KICBsY2Quc2V0Q3Vyc29yKDAsMCk7DQogIGxjZC5wcmludCgiLS0tLVpBUFBBLS1TWU5USC0tLS0iKTsNCiAgbGNkLnNldEN1cnNvcigwLDEpOw0KICBsY2QucHJpbnQoIlVzZSB0aGUgZGlhbHMgYW5kICAgIik7DQogIGxjZC5zZXRDdXJzb3IoMCwyKTsNCiAgbGNkLnByaW50KCJqb3lzdGljayB0byBtYWtlIik7DQogIGxjZC5zZXRDdXJzb3IoMCwzKTsNCiAgbGNkLnByaW50KCJzeW50aGVzaXplciBzb3VuZHMiKTsNCiAgDQogIGludCB0ZW1wVm9sdW1lID0gdm9sdW1lOw0KDQogIGFtcE9uKCk7DQoNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICAgDQogICAgaW50IHB2ID0gcG90VmFsdWUobGVmdCwgMC4wMSk7DQogICAgaWYgKHB2IDwgMCkNCiAgICAgIHB2ID0gMDsNCiAgICBpZiAocHYgPiAxMCkNCiAgICAgIHB2ID0gMTA7DQogICAgdm9sdW1lID0gcHY7DQoNCiAgICBpbnQgaG9yaXogPSBhbmFsb2dSZWFkKGpveUgpOw0KICAgIGludCB2ZXJ0ID0gYW5hbG9nUmVhZChqb3lWKTsNCiAgICBob3JpeiA9IChob3Jpej4+NCkrNDA7DQogICAgdmVydCA9ICh2ZXJ0Pj40KSs0MDsNCiAgICBpbnQgbWl4ID0gcG90VmFsdWUoY2VudGVyLCAxLjApOw0KICAgIGZsb2F0IG1peFMgPSAoZmxvYXQpbWl4LzEwMjMuMDsNCiAgICBwbGF5RHVhbFRvbmUoaG9yaXosdmVydCxtaXhTLDEwMDAwMDAwMCk7DQogICAgDQogIH0NCiAgDQogIG1vZGUgPSBtZW51Ow0KICB2b2x1bWUgPSB0ZW1wVm9sdW1lOw0KICBjbGVhclRvbmUoKTsNCiAgYW1wT2ZmKCk7DQp9DQoNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KLy8gc2VlZFJORw0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQp2b2lkIHNlZWRSTkcoKSB7DQogIGxvbmcgYjBfYjkgPSAobG9uZykgYW5hbG9nUmVhZChwb3RMZWZ0KTsNCiAgbG9uZyBiMTBfYjE5ID0gKGxvbmcpIGFuYWxvZ1JlYWQocG90Q2VudGVyKTsNCiAgbG9uZyBiMjBfYjI5ID0gKGxvbmcpIGFuYWxvZ1JlYWQocG90UmlnaHQpOw0KICBsb25nIHNlZWQgPSBiMF9iOSB8IChiMTBfYjE5IDw8IDEwKSB8IChiMjBfYjI5IDw8IDIwKTsNCiAgcmFuZG9tU2VlZChzZWVkKTsNCn0NCg0Kdm9pZCBwb25nTG9vcCgpIHsNCg0KICBzd2l0Y2ggKHBvbmdNb2RlKSB7DQogICAgY2FzZSBwb25nV2FpdDoNCiAgICAgIHBvbmdXYWl0TW9kZSgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBwb25nU2hvd1Njb3JlOg0KICAgICAgcG9uZ1Nob3dTY29yZU1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2UgcG9uZ1BsYXk6DQogICAgICBwb25nUGxheU1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2UgcG9uZ0V4aXQ6DQogICAgICBtb2RlID0gbWVudTsNCiAgICAgIGJyZWFrOw0KICB9DQogIA0KfQ0KDQp2b2lkIHBvbmdQbGF5TW9kZSgpIHsNCiANCiAgbWF0cml4LmNsZWFyKCk7DQogIA0KICByZWFkUGFkZGxlUG9zaXRpb24oKTsNCg0KICBpZiAoc3RpY2tCYWxsVG9QYWRkbGUpIHsNCg0KICAgIGlmIChiYWxsT25QYWRkbGUgPT0gMCkgew0KICAgICAgYmFsbFBvc1ggPSAxOw0KICAgICAgYmFsbFBvc1kgPSBsZWZ0UGFkZGxlUG9zOw0KICAgIH0gZWxzZSB7DQogICAgICBiYWxsUG9zWCA9IDY7DQogICAgICBiYWxsUG9zWSA9IHJpZ2h0UGFkZGxlUG9zOw0KICAgIH0NCg0KICAgIGlmIChidXR0b25QcmVzc2VkKGFueSkpIHsNCiAgICAgIHN0aWNrQmFsbFRvUGFkZGxlID0gZmFsc2U7DQogICAgICBpZiAoYmFsbE9uUGFkZGxlID09IDApDQogICAgICAgIGJhbGxEaXJYID0gMTsNCiAgICAgIGVsc2UNCiAgICAgICAgYmFsbERpclggPSAtMTsNCiAgICAgIGJhbGxEaXJZID0gcmFuZG9tKDMpIC0gMTsgDQogICAgICBsYXN0QmFsbFVwZGF0ZSA9IG1pbGxpcygpOyANCiAgICB9DQogICAgICAgICAgDQogIH0gZWxzZSB7DQogICAgaWYgKG1pbGxpcygpIC0gbGFzdEJhbGxVcGRhdGUgPiBiYWxsU3BlZWQpIHsNCiAgICAgIGJhbGxQb3NYICs9IGJhbGxEaXJYOw0KICAgICAgYmFsbFBvc1kgKz0gYmFsbERpclk7DQoNCiAgICAgIGxhc3RCYWxsVXBkYXRlID0gbWlsbGlzKCk7DQogICAgICBjaGVja0JhbGwgPSB0cnVlOw0KDQogICAgfQ0KICB9DQogICAgDQogIG1hdHJpeC5kcmF3UGl4ZWwoYmFsbFBvc1gsIGJhbGxQb3NZLG1hdHJpeC5Db2xvcigwLDE4MCwwKSk7DQogIGZvciAoaW50IGk9LTE7IGk8MjsgaSsrKSB7DQogICAgbWF0cml4LmRyYXdQaXhlbCgwLGxlZnRQYWRkbGVQb3MraSxtYXRyaXguQ29sb3IoMTgwLDAsMCkpOw0KICAgIG1hdHJpeC5kcmF3UGl4ZWwoNyxyaWdodFBhZGRsZVBvcytpLG1hdHJpeC5Db2xvcigwLDAsMTgwKSk7DQogIH0NCiAgbWF0cml4LnNob3coKTsNCg0KICBpZiAoY2hlY2tCYWxsKSB7DQoNCiAgICAvLyBib3VuY2Ugb2ZmIHRoZSBsZWZ0IHBhZGRsZQ0KICAgIGlmIChiYWxsUG9zWCA9PSAxKSB7DQogICAgICBpZiAoYmFsbFBvc1kgPD0gbGVmdFBhZGRsZVBvcysxICYmIGJhbGxQb3NZID49IGxlZnRQYWRkbGVQb3MtMSkgew0KICAgICAgICBiYWxsRGlyWCAqPSAtMTsNCiAgICAgICAgYmFsbERpclkgPSBiYWxsUG9zWSAtIGxlZnRQYWRkbGVQb3M7ICAgICAgICANCiAgICAgICAgaWYgKHJhbmRvbSg1KSA9PSAwKSANCiAgICAgICAgICBiYWxsRGlyWSA9IHJhbmRvbSgzKSAtIDE7DQogICAgICAgIGlmIChiYWxsRGlyWSA9PSAxICYmIGJhbGxQb3NZID09IDcpDQogICAgICAgICAgYmFsbERpclkgPSAtMTsNCiAgICAgICAgZWxzZSBpZiAoYmFsbERpclkgPT0gLTEgJiYgYmFsbFBvc1kgPT0gMCkNCiAgICAgICAgICBiYWxsRGlyWSA9IDE7DQogICAgICAgIA0KICAgICAgICBjaGVja0JhbGwgPSBmYWxzZTsgDQogICAgICAgIHBvbmdTY29yZSArPSBtYXAoYmFsbFNwZWVkLCAzMCwgMjAwLCA5ODc3LCAxMCk7DQogICAgICAgIHBsYXlUb25lKDEwMiw1MCk7DQogICAgICAgIGJhbGxTcGVlZCAqPSAwLjk4Ow0KICAgICAgICBpZiAoYmFsbFNwZWVkIDwgMzApIHsNCiAgICAgICAgICBiYWxsU3BlZWQgPSAzMDsgICAgICAgDQogICAgICAgIH0NCiAgICAgICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICAgICAgbGNkLnByaW50KHBvbmdTY29yZSk7DQogICAgICB9DQogICAgfQ0KICANCiAgICAvLyBib3VuY2Ugb2ZmIHRoZSByaWdodCBwYWRkbGUNCiAgICBpZiAoYmFsbFBvc1ggPT0gNikgew0KICAgICAgaWYgKGJhbGxQb3NZIDw9IHJpZ2h0UGFkZGxlUG9zKzEgJiYgYmFsbFBvc1kgPj0gcmlnaHRQYWRkbGVQb3MtMSkgew0KICAgICAgICBiYWxsRGlyWCAqPSAtMTsNCiAgICAgICAgYmFsbERpclkgPSBiYWxsUG9zWSAtIHJpZ2h0UGFkZGxlUG9zOw0KICAgICAgICBpZiAocmFuZG9tKDUpID09IDApIA0KICAgICAgICAgIGJhbGxEaXJZID0gcmFuZG9tKDMpIC0gMTsNCiAgICAgICAgaWYgKGJhbGxEaXJZID09IDEgJiYgYmFsbFBvc1kgPT0gNykNCiAgICAgICAgICBiYWxsRGlyWSA9IC0xOw0KICAgICAgICBlbHNlIGlmIChiYWxsRGlyWSA9PSAtMSAmJiBiYWxsUG9zWSA9PSAwKQ0KICAgICAgICAgIGJhbGxEaXJZID0gMTsNCiAgICAgICAgY2hlY2tCYWxsID0gZmFsc2U7DQogICAgICAgIHBsYXlUb25lKDEwNyw1MCk7DQogICAgICAgIHBvbmdTY29yZSArPSBtYXAoYmFsbFNwZWVkLCAzMCwgMjAwLCA5ODc3LCAxMCk7DQogICAgICAgIGJhbGxTcGVlZCAqPSAwLjk4Ow0KICAgICAgICBpZiAoYmFsbFNwZWVkIDwgMzApIHsNCiAgICAgICAgICBiYWxsU3BlZWQgPSAzMDsNCiAgICAgICAgfQ0KICAgICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgICBsY2QucHJpbnQocG9uZ1Njb3JlKTsNCiAgICAgIH0NCiAgICB9DQoNCiAgfQ0KDQogIGlmIChjaGVja0JhbGwpIHsNCiAgICAvLyBib3VuY2Ugb2ZmIHRoZSB0b3AgYW5kIGJvdHRvbSB3YWxscyANCiAgICBpZiAoKGJhbGxQb3NZID09IDcgfHwgYmFsbFBvc1kgPT0gMCkgJiYgYmFsbERpclkgIT0gMCkgew0KICAgICAgYmFsbERpclkgKj0gLTE7DQogICAgICBjaGVja0JhbGwgPSBmYWxzZTsNCiAgICB9DQogIH0NCg0KICBpZiAoY2hlY2tCYWxsKSB7DQogICAgLy8gaWYgdGhlIGJhbGxzIG1pc3NlcyB0aGUgcGFkZGxlIGFuZCBoYXMgZ29uZSBvZmYgdGhlIHNjcmVlbiAtIHJlc2V0IHRoZSBiYWxsDQogICAgaWYgKGJhbGxQb3NYIDwgLTEgfHwgYmFsbFBvc1ggPiA4KSB7DQogICAgICBzdGlja0JhbGxUb1BhZGRsZSA9IHRydWU7DQogICAgICBiYWxsT25QYWRkbGUgPSByYW5kb20oMik7DQogICAgICBjaGVja0JhbGwgPSBmYWxzZTsNCiAgICAgIGJhbGxTcGVlZCA9IDIwMDsNCiAgICAgIHBvbmdMaXZlcy0tOw0KICAgICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICAgIGxjZC5wcmludCgiTGl2ZXMgbGVmdCA9ICIrU3RyaW5nKHBvbmdMaXZlcy0xKSk7DQogICAgICBwbGF5VG9uZSg2NSwzMDApOw0KICAgICAgZGVsYXkoMzkwKTsNCiAgICAgIHBsYXlUb25lKDU5LDMwMCk7DQogICAgICBkZWxheSgzOTApOw0KICAgICAgcGxheVRvbmUoNDYsMTAwMCk7DQogICAgICBkZWxheSgxMzAwKTsgIA0KICAgICAgaWYgKHBvbmdMaXZlcyA9PSAwKSB7DQogICAgICAgIHBvbmdNb2RlID0gcG9uZ1Nob3dTY29yZTsNCiAgICAgICAgYW1wT2ZmKCk7DQogICAgICB9ICAgICANCiAgICB9DQogIH0NCg0KDQp9DQoNCnZvaWQgcG9uZ1Nob3dTY29yZU1vZGUoKSB7DQoNCiAgbWF0cml4LmNsZWFyKCk7DQogIG1hdHJpeC5zaG93KCk7DQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogIGxjZC5wcmludCgiLS0tLSBHQU1FICBPVkVSIC0tLS0iKTsNCiAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgbGNkLnByaW50KHBvbmdTY29yZSk7DQogIHdoaWxlICghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogIH0gDQoNCiAgcG9uZ01vZGUgPSBwb25nV2FpdDsNCiAgDQp9DQoNCnZvaWQgcmVhZFBhZGRsZVBvc2l0aW9uKCkgew0KDQogIGludCBsZWZ0UG90VmFsID0gYW5hbG9nUmVhZChwb3RMZWZ0KTsNCiAgaW50IHJpZ2h0UG90VmFsID0gYW5hbG9nUmVhZChwb3RSaWdodCk7DQogIGlmIChsZWZ0UG90VmFsID4gcG90TWF4KQ0KICAgIGxlZnRQb3RWYWwgPSBwb3RNYXg7DQogIGlmIChsZWZ0UG90VmFsIDwgcG90TWluKQ0KICAgIGxlZnRQb3RWYWwgPSBwb3RNaW47ICAgICANCiAgaWYgKHJpZ2h0UG90VmFsID4gcG90TWF4KQ0KICAgIHJpZ2h0UG90VmFsID0gcG90TWF4Ow0KICBpZiAocmlnaHRQb3RWYWwgPCBwb3RNaW4pDQogICAgcmlnaHRQb3RWYWwgPSBwb3RNaW47DQoNCiAgbGVmdFBhZGRsZVBvcyA9ICgobGVmdFBvdFZhbC1wb3RNaW4pLzQ0LjQpLTE7DQogIHJpZ2h0UGFkZGxlUG9zID0gOC0oKHJpZ2h0UG90VmFsLXBvdE1pbikvNDQuNCk7DQoNCiAgaWYgKHN0aWNrQmFsbFRvUGFkZGxlKSB7DQogICAgaWYgKGxlZnRQYWRkbGVQb3MgPiA2KQ0KICAgICAgbGVmdFBhZGRsZVBvcyA9IDY7DQogICAgaWYgKGxlZnRQYWRkbGVQb3MgPCAxKQ0KICAgICAgbGVmdFBhZGRsZVBvcyA9IDE7ICANCiAgICBpZiAocmlnaHRQYWRkbGVQb3MgPiA2KQ0KICAgICAgcmlnaHRQYWRkbGVQb3MgPSA2Ow0KICAgIGlmIChyaWdodFBhZGRsZVBvcyA8IDEpDQogICAgICByaWdodFBhZGRsZVBvcyA9IDE7ICANCiAgfQ0KICANCn0NCg0Kdm9pZCBwb25nV2FpdE1vZGUoKSB7DQoNCiAgbWF0cml4LmNsZWFyKCk7DQogIG1hdHJpeC5zaG93KCk7DQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogIGxjZC5wcmludCgiLS0tLS0tLUJPSU5HIS0tLS0tLS0iKTsNCiAgbGNkLnNldEN1cnNvcigwLCAyKTsNCiAgbGNkLnByaW50KCJQdXNoIGdyZWVuIHRvIHBsYXkiKTsNCiAgbGNkLnNldEN1cnNvcigwLCAzKTsNCiAgbGNkLnByaW50KCJQdXNoIHJlZCB0byBleGl0Iik7DQoNCiAgYW1wT2ZmKCk7DQoNCiAgYm9vbGVhbiBhbnN3ZXJlZCA9IGZhbHNlOw0KICB3aGlsZSAoIWFuc3dlcmVkKSB7DQoNCiAgICBpZiAoYnV0dG9uUHJlc3NlZChncmVlbikpIHsNCiAgICAgIA0KICAgICAgYW1wT24oKTsNCiAgICAgIA0KICAgICAgcG9uZ0xpdmVzID0gNDsNCiAgICAgIHBvbmdTY29yZSA9IDA7DQogICAgICBwb25nTW9kZSA9IHBvbmdQbGF5Ow0KICAgICAgbGNkLmNsZWFyKCk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgbGNkLnByaW50KHBvbmdTY29yZSk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDEpOw0KICAgICAgbGNkLnByaW50KCJMaXZlcyBsZWZ0ID0gIitTdHJpbmcocG9uZ0xpdmVzLTEpKTsNCiAgICAgIHBsYXlUb25lKDY5LDI1MCk7DQogICAgICBkZWxheSgzMDApOw0KICAgICAgcGxheVRvbmUoNjksMTUwKTsNCiAgICAgIGRlbGF5KDE4MCk7DQogICAgICBwbGF5VG9uZSg4MCwxMDAwKTsNCiAgICAgIGRlbGF5KDEzMDApOw0KICAgICAgYW5zd2VyZWQgPSB0cnVlOyAgICAgIA0KICAgIH0NCiAgICBpZiAoYnV0dG9uUHJlc3NlZChyZWQpKSB7DQogICAgICBwb25nTW9kZSA9IHBvbmdFeGl0Ow0KICAgICAgYW5zd2VyZWQgPSB0cnVlOw0KICAgIH0NCiAgICANCiAgfQ0KICANCn0NCg0KLyogTWlkaSwgRnJlcSwgUGhhc2UgQWNjL0luYw0KAAAAAAAAAAAAAAAwIDguMTggMTcxNDU4DQoxIDguNjYgMTgxNjU0DQoyIDkuMTggMTkyNDU2DQozIDkuNzIgMjAzOTAwDQo0IDEwLjMwIDIxNjAyNA0KNSAxMC45MSAyMjg4NzANCjYgMTEuNTYgMjQyNDc5DQo3IDEyLjI1IDI1Njg5OA0KOCAxMi45OCAyNzIxNzQNCjkgMTMuNzUgMjg4MzU4DQoxMCAxNC41NyAzMDU1MDUNCjExIDE1LjQzIDMyMzY3MQ0KMTIgMTYuMzUgMzQyOTE3DQoxMyAxNy4zMiAzNjMzMDgNCjE0IDE4LjM1IDM4NDkxMg0KMTUgMTkuNDUgNDA3ODAwDQoxNiAyMC42MCA0MzIwNDkNCjE3IDIxLjgzIDQ1Nzc0MA0KMTggMjMuMTIgNDg0OTU5DQoxOSAyNC41MCA1MTM3OTYNCjIwIDI1Ljk2IDU0NDM0OA0KMjEgMjcuNTAgNTc2NzE2DQoyMiAyOS4xNCA2MTEwMTANCjIzIDMwLjg3IDY0NzM0Mg0KMjQgMzIuNzAgNjg1ODM1DQoyNSAzNC42NSA3MjY2MTcNCjI2IDM2LjcxIDc2OTgyNA0KMjcgMzguODkgODE1NjAwDQoyOCA0MS4yMCA4NjQwOTgNCjI5IDQzLjY1IDkxNTQ4MA0KMzAgNDYuMjUgOTY5OTE4DQozMSA0OS4wMCAxMDI3NTkyDQozMiA1MS45MSAxMDg4Njk2DQozMyA1NS4wMCAxMTUzNDMzDQozNCA1OC4yNyAxMjIyMDIwDQozNSA2MS43NCAxMjk0Njg1DQozNiA2NS40MSAxMzcxNjcxDQozNyA2OS4zMCAxNDUzMjM1DQozOCA3My40MiAxNTM5NjQ5DQozOSA3Ny43OCAxNjMxMjAxDQo0MCA4Mi40MSAxNzI4MTk3DQo0MSA4Ny4zMSAxODMwOTYxDQo0MiA5Mi41MCAxOTM5ODM2DQo0MyA5OC4wMCAyMDU1MTg0DQo0NCAxMDMuODMgMjE3NzM5Mg0KNDUgMTEwLjAwIDIzMDY4NjcNCjQ2IDExNi41NCAyNDQ0MDQwDQo0NyAxMjMuNDcgMjU4OTM3MA0KNDggMTMwLjgxIDI3NDMzNDMNCjQ5IDEzOC41OSAyOTA2NDcwDQo1MCAxNDYuODMgMzA3OTI5OA0KNTEgMTU1LjU2IDMyNjI0MDINCjUyIDE2NC44MSAzNDU2Mzk1DQo1MyAxNzQuNjEgMzY2MTkyMw0KNTQgMTg1LjAwIDM4Nzk2NzINCjU1IDE5Ni4wMCA0MTEwMzY5DQo1NiAyMDcuNjUgNDM1NDc4NQ0KNTcgMjIwLjAwIDQ2MTM3MzQNCjU4IDIzMy4wOCA0ODg4MDgxDQo1OSAyNDYuOTQgNTE3ODc0MQ0KNjAgMjYxLjYzIDU0ODY2ODYNCjYxIDI3Ny4xOCA1ODEyOTQwDQo2MiAyOTMuNjYgNjE1ODU5Ng0KNjMgMzExLjEzIDY1MjQ4MDUNCjY0IDMyOS42MyA2OTEyNzkxDQo2NSAzNDkuMjMgNzMyMzg0Nw0KNjYgMzY5Ljk5IDc3NTkzNDUNCjY3IDM5Mi4wMCA4MjIwNzM5DQo2OCA0MTUuMzAgODcwOTU3MA0KNjkgNDQwLjAwIDkyMjc0NjkNCjcwIDQ2Ni4xNiA5Nzc2MTYyDQo3MSA0OTMuODggMTAzNTc0ODMNCjcyIDUyMy4yNSAxMDk3MzM3Mg0KNzMgNTU0LjM3IDExNjI1ODgxDQo3NCA1ODcuMzMgMTIzMTcxOTMNCjc1IDYyMi4yNSAxMzA0OTYxMQ0KNzYgNjU5LjI2IDEzODI1NTgyDQo3NyA2OTguNDYgMTQ2NDc2OTQNCjc4IDczOS45OSAxNTUxODY5MA0KNzkgNzgzLjk5IDE2NDQxNDc5DQo4MCA4MzAuNjEgMTc0MTkxNDANCjgxIDg4MC4wMCAxODQ1NDkzOA0KODIgOTMyLjMzIDE5NTUyMzI0DQo4MyA5ODcuNzcgMjA3MTQ5NjYNCjg0IDEwNDYuNTAgMjE5NDY3NDQNCjg1IDExMDguNzMgMjMyNTE3NjINCjg2IDExNzQuNjYgMjQ2MzQzODYNCjg3IDEyNDQuNTEgMjYwOTkyMjINCjg4IDEzMTguNTEgMjc2NTExNjQNCjg5IDEzOTYuOTEgMjkyOTUzODgNCjkwIDE0NzkuOTggMzEwMzczODANCjkxIDE1NjcuOTggMzI4ODI5NTgNCjkyIDE2NjEuMjIgMzQ4MzgyODANCjkzIDE3NjAuMDAgMzY5MDk4NzYNCjk0IDE4NjQuNjYgMzkxMDQ2NDgNCjk1IDE5NzUuNTMgNDE0Mjk5MzINCjk2IDIwOTMuMDAgNDM4OTM0ODgNCjk3IDIyMTcuNDYgNDY1MDM1MjQNCjk4IDIzNDkuMzIgNDkyNjg3NzINCjk5IDI0ODkuMDIgNTIxOTg0NDQNCjEwMCAyNjM3LjAyIDU1MzAyMzI4DQoxMDEgMjc5My44MyA1ODU5MDc3Ng0KMTAyIDI5NTkuOTYgNjIwNzQ3NjANCjEwMyAzMTM1Ljk2IDY1NzY1OTE2DQoxMDQgMzMyMi40NCA2OTY3NjU2MA0KMTA1IDM1MjAuMDAgNzM4MTk3NTINCjEwNiAzNzI5LjMxIDc4MjA5Mjk2DQoxMDcgMzk1MS4wNyA4Mjg1OTg2NA0KMTA4IDQxODYuMDEgODc3ODY5NzYNCjEwOSA0NDM0LjkyIDkzMDA3MDQ4DQoxMTAgNDY5OC42NCA5ODUzNzU0NA0KMTExIDQ5NzguMDMgMTA0Mzk2ODg4DQoxMTIgNTI3NC4wNCAxMTA2MDQ2NTYNCjExMyA1NTg3LjY1IDExNzE4MTU1Mg0KMTE0IDU5MTkuOTEgMTI0MTQ5NTIwDQoxMTUgNjI3MS45MyAxMzE1MzE4MzINCjExNiA2NjQ0Ljg4IDEzOTM1MzEyMA0KMTE3IDcwNDAuMDAgMTQ3NjM5NTA0DQoxMTggNzQ1OC42MiAxNTY0MTg1OTINCjExOSA3OTAyLjEzIDE2NTcxOTcyOA0KMTIwIDgzNzIuMDIgMTc1NTczOTUyDQoxMjEgODg2OS44NCAxODYwMTQwOTYNCjEyMiA5Mzk3LjI3IDE5NzA3NTA4OA0KMTIzIDk5NTYuMDYgMjA4NzkzNzc2DQoxMjQgMTA1NDguMDggMjIxMjA5MzEyDQoxMjUgMTExNzUuMzAgMjM0MzYzMTA0DQoxMjYgMTE4MzkuODIgMjQ4Mjk5MDQwDQoxMjcgMTI1NDMuODUgMjYzMDYzNjY0DQoqLw0KDQoNCg0
fryden-due-boxfactory-camp-v1.76.ino
c_cpp
This is the main Arduino application used in: http://www.fryden-learning.com/box-facto
1binary |- 2 DQpTdHJpbmcgdmVyTnVtID0gInYxLjc2IjsNCi8vIEZJWEVEIGNhbXAgZXJyb3JzDQoNCi8vICoqKioqKioqKlRPRE8gZHVlDQovLyB1c2UganNvbiBvciB4bWwgdG8gc2VuZCBkYXRhIHRvIHRoZSBzaW11bGF0b3INCi8vIA0KLy8gdGVzdCB0aGUgc2VyaWFsIHR4IHN0YXRlIG1hY2hpbmUgd2l0aCByYW5kb20gZGVsYXlzIGFuZCBub2lzZQ0KLy8gZml4IHJlc2V0IG1vZGUgLSBtYWtlIHN1cmUgZXZlcnl0aGluZyByZXNldHMgc28gd2UgZG9udCBoYXZlIHRvIHB1bGwgdGhlIGZsYXNoIGNhcmQNCi8vICh0ZXh0IGZvciByZWQgdG8gZXhpdD8gb24gdHJhaW5pbmcvd29yayBtb2RlcykNCi8vIHBsYW4gdG8gcHJlcCBhbGwgdGhlIGZsYXNoIGNhcmRzLi4uKGRlbGV0ZSBzZXR0aW5ncyBmaWxlIHRvIGVuc3VyZSBpdCBib290cykNCi8vIGF1dG9kZWN0IGkyYyBhZGRyZXNzIGFuZCBhdXRvIGNvbmZpZyBvbiBib290IC0gbm90IHN1cmUgdGhpcyBpcyBwb3NzaWJsZQ0KLy8gY2FsaWJyYXRlIGRpYWxzIHRvIDUxMiBhdCB0aGUgY2VudGVyDQovLyBzY3JlZW4gc2F2ZSAtIGJ1bmNoZXMgYXQgdGhlIHRvcD8NCi8vIGluc3RydWN0aW9ucyB0ZXh0IGludG8gdGhlIG1vZGUgT1IgcHVsbCBpbnN0cnVjdGlvbnMgbW9kZS4NCi8vIGNvbW1lbnQgYmxvY2tzIGFib3ZlIGFsbCBmdW5jdGlvbnMgYW5kIG5hbWVzIGF0IHRoZSB0b3AgdG8gc2VhcmNoIGFnYWluc3QNCi8vIGJvaW5nIHNjb3JlIC0gY2FwdHVyZSAyIHNjb3J3cyBiYXNlZCBvbiBsZW5ndGggb2YgcmFsbHkgYW5kIHdobyBkcm9wcGVkIHRoZSBiYWxsDQovLyBOT1QgRE9ORSAtIHdhdiAtIGZpbGVzIHBsYWNlaG9sZGVycyBmb3IgYWxsIC0gd2VsY29tZSB0byB0aGUgZnJ5ZGVuIGF1ZGlvDQovLyBOT1QgRE9ORSAtIHdhdiAtIGF1ZGlvIGludGVydXB0IGNvbGxpc2lvbnMgd2hlbiB1c2luZyB0aGUgd2F2ZmlsZSBwYWx5ZXIgYW5kIHRoZSB0b25lIGxpYi4uLi4NCi8vIE5PVCBET05FIC0gd2F2IC0gcmVtZW1iZXIgcGxheXdhdnMgaW4gdGhlIHNldHRpbmdzDQovLyBOT1QgRE9ORSAtIHRyaWNreSAtIHNoYXBlIHRoZSBjb2xvcnMgdG8gbWFrZSB0aGUgbWlkIGNhc2Ugb2Ygb3JhbmdlIGJldHRlciB0byBzZWUgLSBsZXNzIGdyZWVuLi4uDQovLyBET05FIC0gQlVHIC0gc2V0dGluZyBndWlsZCBQT1Qgc2VsZWN0cyBhIGJsYW5rIG9wdGlvbi4NCi8vIERPTkUgLSBCVUcgLSBlbnRlcm5hbWUgLSBjbGVhciBzY3JlZW4NCi8vIERPTkUgLSBzdG9wIHNlbmRpbmcgYWZ0ZXIgNSB1cGxvYWQgYXR0ZW10cw0KLy8gRE9ORSAtIHJlZGVzaWduIGEgc2FmZXIgc3RhdGUgbWFjaGluZSBmb3IgdGhlIHJlY2lldmUgYnl0ZXMNCi8vIERPTkUgLSBwbGFjZWhvbGRlciBmb3Igd2VsY29tZSB0dW5lLg0KLy8gRE9ORSAtIGFsbCBwYXJhbXMgdG8gZmlsZSBzZXIvZGUtc2VyIGFjY3Jvc3MgdGhlIHNlcmlhbCBsaW5rIGluYy4gZ2x5cGhzDQovLyBET05FIC0gbmFtZXMgLSBaQVBQQSBTWU5USCAmIGJvaW5nDQovLyBET05FIC0gbWFrZSB0aGUgYmluYXJ5IHNhdmUgdG8gZmlsZSBmb3IgaWYgd2Ugd2FudCB0byBzYXZlIGVkaXRlZCBnbHlwaHMNCi8vIERPTkUgLSBsb2NrIHN5bWJvbHMgb3ZlciB3cml0ZSB0aGUgbWVudSBiYXIgYnkgd3JhcHBpbmcgYXJvdW5kDQovLyBET05FIC0gbG9jayBzeW1ib2wgYXBwZWFycyBvbiBzdGV0dGluZ3MgbWVudQ0KLy8gRE9ORSAtIGxpZ3RoZW5pbmcgc3BlbHQgd3JvbmcNCi8vIERPTkUgLSBzY3JlZW4gc2F2ZSB4IHNlY3MgYWZ0ZXIgdGhlIG1lbnUgaW50ZXJhY3Rpb25zDQovLyBET05FIC0gbW9yZSBwaHJhc2VzIGludG8gdGhlICJ0aGFua3MgZm9yIHRlYWNoaW5nIG1lIiAieWVzIGkga25vdy4uLiINCi8vIERPTkUgLSBwb25nIHNvdW5kcw0KLy8gRE9ORSAtIGRpYWwgZm9yIDAuOCB0byAxLjQgPSBiZSBhYmxlIHRvIGNoYW5nZSBsZWFybmluZyByYXRlIGFuZCBnYlJhZGl1cyBieSBzZXR0aW5ncyAtIGdicmFkaXVzIG1ha2VzIHRoZSBnYW1lIGhhcmRlcg0KLy8gRE9ORSAtIG1ha2UgdGhlIGdseXBoIGNvbG9ycyBjb25zdGFudHMuDQovLyBET05FIC0gYmFzaWMgc3lzbnRoIGNvZGUgbmVlZHMgYWRkaW5nDQovLyBET05FIC0gc3ludGggLSBtYWtlIDIgb24gdGhlIGpveXN0aWNrLi4uDQovLyBET05FIC0gc2NyZWVuIHNhdmUgbWVzc2FnZXMgLSBjb2RlIGFuZCB2b2NhYiBhbnN3ZXJzDQovLyBET05FIC0gY3VzdG9tIGdseXBoIG9uIHN0YXJ0IHNjcmVlbiAmIExFRCBtYXRyaXguDQovLyBET05FIC0gYWRkIHRoZSBndWlsZCBuYW1lcyB0byB0aGUgbmFtZSAvIGRlc2NyaXB0aW9uIGFsbCB0aGUgd2F5IHRocm91Z2ggdG8gdGhlIHNpbWx1YXRvciAvIGd1aWxkIGNvbWVzIGFmdGVyIG5hbWluZw0KLy8gRE9ORSAtIGVudGVyIGN1c3RvbSBuYW1lIGluIHNldHRpbmdzIC0tIC8vIHNldHRpbmdzIC0gYWRkIG5hbWUgZnJvbSBhIGZpbGUgLy8gYWRkIHlvdSBvd24gbmFtZSBmb3IgY3VzdG9tIG5hbWVzIC0gcmVzZXQgLSBpZiBuZXZlciBzZXQgdGhlbiBzZXQgaXQgDQovLyBET05FIC0gbmFtZSBmbG93IC0gdW5uYW1lZCAtIG11c3QgZm9yY2UgbmFtaW5nIGFmdGVyIHJlc2V0DQovLyBET05FIC0gZ3VpbGQgbmFtZSBpbnRvIHNldHRpbmdzDQovLyBET05FIC0gb24gcG93ZXIgdXAgYW5kIGZsYXNoIHRoZSBndWlsZCBzeW1ib2xzIGFuZCBzYXkgIkkgYW0uLi4iIG9mIHRoZQ0KLy8gRE9ORSAtIGNsZWFyIHRoZSBuZW8gcGl4ZWwgb24gc3RhcnQgdXANCi8vIERPTkUgLSBwdXQgTXIgQnJ5ZGVucyBnbHlwaHMgaW4uDQoNCi8vICoqKioqKioqKipOb3RlcyBhbmQgb3RoZXIgbGVzcyBjcml0aWNhbCB0b2RvJ3MNCi8vIEJPRVIgLSBuZWVkcyBhIGZhY3RvcnkgcmVzdGV0IHRvIGJlIHJlcHJvZ3JhbW1lZC4uLi4NCi8vIENyYXNoIG9uIHByb2Nlc3NpbmcgQVBQIGlmIGl0IHJlYWRzIGNvcnJ1b3QgZGF0YSAtIG5lZWRzIHRvIHJlY292ZXINCi8vIHVwZ3JhZGUgdHdvIHByb3RvcyB0byB3b3JrIG9uIFBDQiB2ZXJzaW9ucw0KLy8gU3RhdGUgb2YgbWluZCBjcmFzaGVkIGZvciBzb21lIHJlYXNvbiAtIG1heSBoYXZlIGJlZW4gdGhlIH5+IG5hbWUgbWFya2Vycz8NCi8vIE5PVEUgLSA1IHRyYWluZyBzZXRzIGF0IDAuMDAwMSwgMS4yIHRvIGdldCAxMDAlDQovLyBkZXNpZ24gYW5kIGRvYyB0aGUgZmFzdGVzdCB0ZXN0IHBsYW4gYXQgdGhpcyByYXRlLg0KLy8gYWRkIGEgZmFjdG9yeSByZXNldCAtIG9uIGJvb3QgLSB0byByZXNldCB0aGUgZmlsZSBzeXN0ZW0NCi8vIGlkZWxseSBtYWtlIGEgc3BsaXQyMCBmdW5jdGlvbiBmb3IgZWFzaWVyIHRleHQgY3JlYXRpb24gLSBoYXJkIC0gbmVlZHMgdG8gZmluZCBzcGFjZXMgIA0KLy8gbGluZXJhaXplIGpveXN0aWNrIG1hcCBwb3RlbmRzIDItMTAyMA0KLy8gcmVkbyBhbGwgdGhlIHNvdW5kcyB0byBhdm9pZCBsb3cgZnJlcSdzIC8vIG1ha2UgbmV3IGxlYXJuaW5nIHNvdW5kIGZvciB0aGUgbm4ncw0KLy8gY2hhbmdlIG5uIHRvIHBlcmNlcHRyb24gLSB0ZXh0IGFuZCBjb2RlDQovLyBtYWtlIHN1cmUgeW91IGNhbnQgYWRkIG1vcmUgdGhhbiAxNiBtZW51cyBvciAzMiBwYWdlcyBsaW5lcyAtIGFuZCB0ZXN0IGl0DQovLyBmaW5kIGFuZCByZW1vdmUgYWxsIGRlYnVnIHByaW50bG5zIC8vIGNoZWNrIHRoZSBzZXJpYWwgcG9ydCBmb3IgYWN0dml0aXR5DQovLyB0ZXN0IFNEIGNhcmQgaW5pdCBmYWlsIG1lc3NhZ2Ugb24gTENEDQovLyBmdW5jdGlvbiBncm91cGluZywgY29kaW5nLCBjb21tZW50aW5nIGFuZCB0aWR5aW5nDQovLyBnbyBhbGwgdGhyb3VnaCBkZWxheSBhbmQgY29zdGFudHMgaW4gdGhlIGNvZGUgYW5kICNkZWZpbmUNCi8vIFBlcmNlcHJvdG4gbm90ZXM6IHByZWRpY3Rpb24gMSA9IGxhcmdlIHJlZCAgICAtMSA9IHNtYWxsIGdyZWVuDQovLyBib3ggc2l6ZS9jb2xvciByYW5nZXMNCi8vIGJveFNpemUgPSAwLi4zMSA7IDMyIHN0ZXBzIDsgOCBsZWRzIHggNCBsZXZlbCBvZiBicmlndGhuZXNzIA0KLy8gY29sVmFsID0gbWF4IDMyICsgMTI4ID0gMzIuLjE1OSA7IHdvcmtzIGJlc3QgZm9yIG5lb3BpeGVsIGRpc3BsYXkgDQoNClN0cmluZyBib3hOYW1lID0gIkJSQUlOIEJPWCI7DQpTdHJpbmcgYm94R3VpbGQgPSAiTklOSkEiOw0KDQovL0R1ZSBib2FyZC9zaGllbGQgSU8NCiNkZWZpbmUgcG90TGVmdCBBMA0KI2RlZmluZSBwb3RDZW50ZXIgQTENCiNkZWZpbmUgcG90UmlnaHQgQTINCiNkZWZpbmUgcmVkQnV0dG9uIDQNCiNkZWZpbmUgZ3JlZW5CdXR0b24gMw0KI2RlZmluZSBibHVlQnV0dG9uIDINCiNkZWZpbmUgam95SCBBNA0KI2RlZmluZSBqb3lCdXR0b24gNQ0KI2RlZmluZSBqb3lWIEE1DQojZGVmaW5lIGFtcEVuYWJsZSBBMw0KI2RlZmluZSBzZENzIDM4DQojZGVmaW5lIG5lb1Bpbk1hdHJpeCA3IA0KI2RlZmluZSBuZW9QaW5TaW5nbGUgNiANCg0KLy8gYXBwIHBhcmFtcyANCiNkZWZpbmUgYnV0dG9uUmVsZWFzZURlbGF5IDE1MA0KI2RlZmluZSBMQ0RzY3JvbGxTcGVlZCAyMDANCiNkZWZpbmUgTkVPc2Nyb2xsU3BlZWQgNzUNCiNkZWZpbmUgbWFrZUJveER1cmF0aW9uIDIwMDANCiNkZWZpbmUgbWFrZUJveER1cmF0aW9uQnkyIDEwMDANCi8vI2RlZmluZSBtYWtlU291bmQgdHJ1ZQ0KI2RlZmluZSBhbmFseXplQm94RHVyYXRpb24gMTUwMA0KLy8jZGVmaW5lIGFuYWx5emVCb3hEdXJhdGlvbkJ5MiA3NTANCiNkZWZpbmUgdHJhaW5Cb3hEdXJhdGlvbiAyMDAwDQovLyNkZWZpbmUgdHJhaW5Cb3hEdXJhdGlvbkJ5MiA3NTANCiNkZWZpbmUgY01heCA0MDANCiNkZWZpbmUgbGVhcm5pbmdSYXRlIDAuMDAwMQ0KDQojaW5jbHVkZSA8V2lyZS5oPg0KI2luY2x1ZGUgPExpcXVpZENyeXN0YWxfUENGODU3NC5oPg0KI2luY2x1ZGUgPEFkYWZydWl0X05lb01hdHJpeC5oPg0KI2luY2x1ZGUgPEFkYWZydWl0X05lb1BpeGVsLmg+DQojaW5jbHVkZSA8U0QuaD4NCiNpbmNsdWRlIDxTUEkuaD4NCiNpbmNsdWRlIDxBdWRpby5oPg0KDQplbnVtIHBvdFBvc3Rpb24gew0KICBsZWZ0LA0KICByaWdodCwNCiAgY2VudGVyDQp9OyANCg0KZW51bSBidXR0b25Db2xvciB7DQogIGJsdWUsDQogIHJlZCwNCiAgZ3JlZW4sDQogIGpveSwNCiAgYW55DQp9OyANCi8vSkYtDQpMaXF1aWRDcnlzdGFsX1BDRjg1NzQgbGNkKDB4M0YpOyAgLy8gc2V0IHRoZSBMQ0QgYWRkcmVzcw0KLy9MaXF1aWRDcnlzdGFsX1BDRjg1NzQgbGNkKDB4MjcpOyAgLy8gc2V0IHRoZSBMQ0QgYWRkcmVzcw0KDQpBZGFmcnVpdF9OZW9NYXRyaXggbWF0cml4ID0gQWRhZnJ1aXRfTmVvTWF0cml4KDgsIDgsIG5lb1Bpbk1hdHJpeCwNCiAgTkVPX01BVFJJWF9MRUZUICAgICArIE5FT19NQVRSSVhfVE9QICsNCiAgTkVPX01BVFJJWF9ST1dTICsgTkVPX01BVFJJWF9QUk9HUkVTU0lWRSwNCiAgTkVPX0dSQiAgICAgICAgICAgICsgTkVPX0tIWjgwMCk7DQoNCkFkYWZydWl0X05lb1BpeGVsIGxlZHMgPSBBZGFmcnVpdF9OZW9QaXhlbCgxLCBuZW9QaW5TaW5nbGUsIE5FT19SR0IgKyBORU9fS0haODAwKTsNCg0KdW5zaWduZWQgbG9uZyBzY3JvbGxORU9NaWxsaVNlYzsNClN0cmluZyBzY3JvbGxORU9NZXNzYWdlID0gIi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uLi4uIjsNCmludCBzY3JvbGxORU9NZXNzYWdlUmVzZXQ7DQppbnQgc2Nyb2xsTkVPTWVzc2FnZVBvczsNCnVpbnQxNl90IHNjcm9sbE5FT0NvbG9yOw0KDQp1bnNpZ25lZCBsb25nIGxhc3RQcmVzc2VkOw0KDQpmbG9hdCBnb29kQm94UmFkaXVzID0gMS4xOw0KaW50IHRyYWluQ3ljbGVzID0gMDsNCmludCB0b3RhbFRyYWluaW5nRXhhbXBsZXMgPSAwOw0KaW50IHRvdGFsQ29ycmVjdCA9IDA7DQpmbG9hdCB3b3JrTW9kZUF2ZXJhZ2UgPSAwOw0KaW50IHdvcmtNb2RlQmVzdCA9IDA7DQoNCi8vIG1lbnUgJiB0ZXh0LXBhZ2VzIGdsb2JhbHMNCnVuc2lnbmVkIGxvbmcgbGFzdFJlYWQgPSAwOw0KZW51bSBqb3lWRGlyIHsNCiAgZG93biwNCiAgdXAsDQogIG1pZGRsZQ0KfTsgDQpTdHJpbmcgYnMgPSAiICAgICAgICAgICAgICAgICAgICAgICI7DQpqb3lWRGlyIHBvc05vdyA9IG1pZGRsZTsNCmpveVZEaXIgcG9zTGFzdCA9IG1pZGRsZTsNCmludCBlbnRyeVNlbD0wOw0KaW50IG1lbnVOdW1FbnRyaWVzPTA7DQpTdHJpbmcgbWVudUVudHJpZXNbMTZdID0ge2JzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzLGJzfTs7DQpTdHJpbmcgbWVudUhlYWRpbmc7DQpib29sZWFuIG1lbnVVcGRhdGVMQ0Q7DQppbnQgcGFnZU51bUVudHJpZXM9MDsNClN0cmluZyBwYWdlRW50cmllc1szMl0gPSB7YnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnMsYnN9Ow0KU3RyaW5nIHBhZ2VIZWFkaW5nOw0KYm9vbGVhbiBwYWdlVXBkYXRlTENEOw0KDQovLyBpbml0aWFsaXplIHRoZSBuZXVyYWwgbmV0IHdhaXRzIGFuZCBsZWFybmluZyBjb25zdGFudA0KZmxvYXQgbm5XZWlnaHRzWzNdID0gey0xLjAsMS4wLDAuMH07DQpmbG9hdCBubkxlYXJuaW5nQyA9IGxlYXJuaW5nUmF0ZTsNCg0KLy8gbWFpbiBtZW51IG9wdGlvbnMNCiNkZWZpbmUgbWFpbk1lbnVTaXplIDkNCi8vIi0tLS0tLS0tLS0tLS0tLS0tIiAxNyBjaGFyIHJlZg0KU3RyaW5nIG1haW5NZW51RW50cmllc1ttYWluTWVudVNpemVdID0gew0KICAiU2hvdyBicmFpbiBzdGF0ZSIsDQogICJUcmFpbmluZyBtb2RlIiwNCiAgIldvcmsgbW9kZSIsDQogICJVcGxvYWQgdG8gZmFjdG9yeSIsDQogICJBbmFseXplIG1vZGUiLA0KICAiUGxheSBCb2luZyIsDQogICJaYXBwYSBTeW50aCIsDQogICJJbnN0cnVjdGlvbnMiLA0KICAiU2V0dGluZ3MiDQp9Ow0KDQpib29sZWFuIG1lbnVMb2Nrc1ttYWluTWVudVNpemVdID0gezAsMCwwLDAsMCwxLDEsMCwwfTsNCi8vYm9vbGVhbiBtZW51TG9ja3NbbWFpbk1lbnVTaXplXSA9IHswLDAsMCwwLDAsMCwwLDAsMH07DQojZGVmaW5lIHBvbmdMb2NrIDUNCiNkZWZpbmUgc3ludGhMb2NrIDYNCg0KLy8iLS0tLS0tLS0tLS0tLS0tLS0iIDE3IGNoYXIgcmVmDQojZGVmaW5lIHNldHRpbmdzTWVudVNpemUgNg0KU3RyaW5nIHNldHRpbmdzTWVudUVudHJpZXNbbWFpbk1lbnVTaXplXSA9IHsNCiAgIlZvbHVtZSIsDQogICJTZXQgZGlmZmljdWx0eSIsDQogICJOYW1lIHRoZSBicmFpbiIsDQogICJSZXNldCBicmFpbiIsDQogICJBYm91dCIsDQogICJNYWluIG1lbnUiDQp9Ow0KDQplbnVtIG1vZGVUeXBlIHsNCiAgd2VsY29tZSwNCiAgd29yaywNCiAgYnJhaW5zdGF0ZSwNCiAgbWVudSwNCiAgdHJhaW4sDQogIGFuYWx5emUsDQogIGZhY3RvcnksDQogIHNldHRpbmdzLA0KICBpbnN0cnVjdGlvbnMsDQogIHBvbmcsDQogIHN5bnRoDQp9Ow0KbW9kZVR5cGUgbW9kZSA9IHdlbGNvbWU7DQpTdHJpbmcgbW9kZURlc2M7IA0KDQojZGVmaW5lIFNJTkVfU0FNUExFUyA4ODIgLy8gNDQuMWtoeiAvIDUwaHogPSA4ODIgc2FtcGxlcyBuZWVkIGZvciBhIGZ1bGwgNTAgaHogc2luZSB3YXZlDQp1aW50MTZfdCBzaW5lV2F2ZVtTSU5FX1NBTVBMRVNdOw0KLy8gdGhlIHBoYXNlIGFjY3VtdWxhdG9yIHBvaW50cyB0byB0aGUgY3VycmVudCBzYW1wbGUgaW4gb3VyIHdhdmV0YWJsZQ0KdWludDMyX3QgdWxQaGFzZUFjY3VtdWxhdG9yQSA9IDA7DQp1aW50MzJfdCB1bFBoYXNlQWNjdW11bGF0b3JCID0gMDsNCi8vIHRoZSBwaGFzZSBpbmNyZW1lbnQgY29udHJvbHMgdGhlIHJhdGUgYXQgd2hpY2ggd2UgbW92ZSB0aHJvdWdoIHRoZSB3YXZlIHRhYmxlDQovLyBoaWdoZXIgdmFsdWVzID0gaGlnaGVyIGZyZXF1ZW5jaWVzDQp2b2xhdGlsZSB1aW50MzJfdCB1bFBoYXNlSW5jcmVtZW50QSA9IDA7ICAgLy8gMzIgYml0IHBoYXNlIGluY3JlbWVudCwgc2VlIGJlbG93DQp2b2xhdGlsZSB1aW50MzJfdCB1bFBoYXNlSW5jcmVtZW50QiA9IDA7ICAgLy8gMzIgYml0IHBoYXNlIGluY3JlbWVudCwgc2VlIGJlbG93DQovLyBmdWxsIHdhdmVmb3JtID0gMCB0byBTQU1QTEVTX1BFUl9DWUNMRQ0KLy8gUGhhc2UgSW5jcmVtZW50IGZvciAxIEh6ID0oU0FNUExFU19QRVJfQ1lDTEVfRklYRURQT0lOVC9TQU1QTEVfUkFURSkgPSAxSHoNCi8vIFBoYXNlIEluY3JlbWVudCBmb3IgZnJlcXVlbmN5IEYgPSAoU0FNUExFU19QRVJfQ1lDTEUvU0FNUExFX1JBVEUpKkYNCiNkZWZpbmUgU0FNUExFX1JBVEUgNDQxMDAuMA0KI2RlZmluZSBTQU1QTEVTX1BFUl9DWUNMRSA4ODINCiNkZWZpbmUgU0FNUExFU19QRVJfQ1lDTEVfRklYRURQT0lOVCAoU0FNUExFU19QRVJfQ1lDTEU8PDIwKQ0KI2RlZmluZSBUSUNLU19QRVJfQ1lDTEUgKGZsb2F0KSgoZmxvYXQpU0FNUExFU19QRVJfQ1lDTEVfRklYRURQT0lOVC8oZmxvYXQpU0FNUExFX1JBVEUpDQojZGVmaW5lIE1JRElfTk9URVMgMTI4DQp1aW50MzJfdCBuTWlkaVBoYXNlSW5jcmVtZW50W01JRElfTk9URVNdOw0KZmxvYXQgdG9uZU1peEE7DQpmbG9hdCB0b25lTWl4QjsgDQpib29sZWFuIHBsYXlEdWFsID0gZmFsc2U7DQoNCnVuc2lnbmVkIGxvbmcgdFRpbWU7DQppbnQgdER1cmF0aW9uOw0KYm9vbGVhbiB0b25lQWN0aXZlID0gZmFsc2U7DQoNCmJvb2xlYW4gc2RJbml0ID0gZmFsc2U7DQoNCiNkZWZpbmUgcGFyYW1MZW4gNDANCmJ5dGUgcGFyYW1zW3BhcmFtTGVuXTsNCmJvb2xlYW4gbG9hZGVkU2V0dGluZ3MgPSBmYWxzZTsNCg0KaW50IHZvbHVtZSA9IDM7DQoNClN0cmluZyBndWlsZE5hbWVzWzNdID0geyJOSU5KQSIsIlBIT0VOSVgiLCJMSUdIVE5JTkcifTsNCg0KY29uc3QgdWludDMyX3QgZ1JlZCA9IG1hdHJpeC5Db2xvcigxMjgsMCwwKTsgICAgICAgIC8vIFIgDQpjb25zdCB1aW50MzJfdCBnT3JhbmdlID0gbWF0cml4LkNvbG9yKDEyMCw0MCwyKTsgICAgLy8gTw0KY29uc3QgdWludDMyX3QgZ1llbGxvdyA9IG1hdHJpeC5Db2xvcigxMDAsODAsMCk7ICAgIC8vIFkNCmNvbnN0IHVpbnQzMl90IGdCbHVlID0gbWF0cml4LkNvbG9yKDAsMCwxMjgpOyAgICAgICAvLyBCDQpjb25zdCB1aW50MzJfdCBnUHVycGxlID0gbWF0cml4LkNvbG9yKDEyOCwwLDEyOCk7ICAgLy8gUA0KY29uc3QgdWludDMyX3QgZ0dyZWVuID0gbWF0cml4LkNvbG9yKDAsMTI4LDApOyAgICAgIC8vIEcNCmNvbnN0IHVpbnQzMl90IGdUZWFsID0gbWF0cml4LkNvbG9yKDMyLDY0LDY0KTsgICAgICAvLyBUDQpjb25zdCB1aW50MzJfdCBnQmxhY2sgPSBtYXRyaXguQ29sb3IoMCwwLDApOyAgICAgICAgLy8gQg0KY29uc3QgdWludDMyX3QgZ1doaXRlID0gbWF0cml4LkNvbG9yKDEwMCw4MCwxMDApOyAgIC8vIFcNCg0KY2hhciBndWlsZEdseXBoc1szXVs4XVs4XSA9IHt7DQogIHsnTycsJ08nLCdPJywnTycsJyAnLCcgJywnICcsJ08nfSwNCiAgeycgJywnTycsJ08nLCdPJywnTycsJyAnLCdPJywnTyd9LA0KICB7JyAnLCcgJywnTycsJ08nLCdPJywnTycsJ08nLCdPJ30sDQogIHsnICcsJ08nLCdPJywnICcsJyAnLCdPJywnTycsJ08nfSwNCiAgeydPJywnTycsJ08nLCcgJywnICcsJ08nLCdPJywnICd9LA0KICB7J08nLCdPJywnTycsJ08nLCdPJywnTycsJyAnLCcgJ30sDQogIHsnTycsJ08nLCcgJywnTycsJ08nLCdPJywnTycsJyAnfSwNCiAgeydPJywnICcsJyAnLCcgJywnTycsJ08nLCdPJywnTyd9DQp9LHsNCiAgeycgJywnICcsJyAnLCcgJywnICcsJyAnLCcgJywnICd9LA0KICB7JyAnLCcgJywnICcsJyAnLCdSJywnICcsJyAnLCcgJ30sDQogIHsnICcsJyAnLCcgJywnUicsJ1InLCcgJywnICcsJyAnfSwNCiAgeycgJywnUicsJyAnLCdSJywnUicsJyAnLCdSJywnICd9LA0KICB7JyAnLCdSJywnUicsJ1InLCdPJywnUicsJ1InLCcgJ30sDQogIHsnICcsJ1InLCdPJywnTycsJ1knLCdPJywnUicsJyAnfSwNCiAgeycgJywnUicsJ1knLCdZJywnWScsJ1knLCdSJywnICd9LA0KICB7JyAnLCcgJywnUicsJ1knLCdZJywnWScsJ1InLCcgJ30NCn0sew0KICB7JyAnLCcgJywnICcsJyAnLCdCJywnVCcsJ0InLCcgJ30sDQogIHsnICcsJyAnLCcgJywnQicsJ1QnLCdCJywnICcsJyAnfSwNCiAgeycgJywnICcsJ0InLCdUJywnQicsJyAnLCcgJywnICd9LA0KICB7JyAnLCdCJywnVCcsJ1QnLCdUJywnVCcsJ1QnLCdCJ30sDQogIHsnQicsJ1QnLCdUJywnVCcsJ1QnLCdUJywnQicsJyAnfSwNCiAgeycgJywnICcsJyAnLCdCJywnVCcsJ0InLCcgJywnICd9LA0KICB7JyAnLCcgJywnQicsJ1QnLCdCJywnICcsJyAnLCcgJ30sDQogIHsnICcsJ0InLCdUJywnQicsJyAnLCcgJywnICcsJyAnfQ0KfX07DQoNCmludCB0aWxlWzhdWzhdOw0KYm9vbGVhbiBtb3ZlZFs4XVs4XTsNCg0KYnl0ZSBsb2NrWzhdID0gew0KICBCMDExMTAsDQogIEIxMTAxMSwNCiAgQjEwMDAxLA0KICBCMTAwMDEsDQogIEIxMTExMSwNCiAgQjExMDExLA0KICBCMTEwMTEsDQogIEIxMTExMQ0KfTsNCg0KI2RlZmluZSBzY3JlZW5TYXZlclRpbWUgNjAwMDANCiNkZWZpbmUgc2F2ZXJUZXh0TWluU2hvdyA1MDAwDQojZGVmaW5lIHNhdmVyVGV4dE51bSAzMw0KU3RyaW5nIHNhdmVyVGV4dFszM11bNF0gPSB7DQogIHsiUEVSQ0VQVFJPTjogaXMgYSBvbmUiLCJOT0RFIE5FVVJBTCBORVRXT1JLIiwidGhhdCBjYW4gQ0xBU1NJRlkiLCAiTElORUFSIFNFUEFSQVRFIERBVEEifSwgDQogIHsiQ0xBU1NJRlk6IHNvcnQgZGF0YSIsImludG8gZGlmZmVyZW50IiwiY2F0ZWdvcmllcyBvciB0eXBlcyIsImJ5IGdpdmluZyBpdCBhIG5hbWUifSwNCiAgeyJMSU5FQVIgU0VQQVJBVEUiLCJEQVRBOiBkYXRhIHRoYXQgY2FuIiwic2VwYXJhdGVkIGJ5IGEgbGluZSIsImRyYXduIG9uIGEgZ3JhcGgifSwgDQogIHsiTkVVUkFMIE5FVFdPUks6IGlzIGEiLCJzaW1wbGUgbW9kZWwgb2YgaG93IiwiYmlvbG9naWNhbCBuZXVyb25zIiwiY29vcGVyYXRlIGluIGEgYnJhaW4ifSwNCiAgeyJORVVSQUwgTkVUV09SSzogY2FuIiwibGVhcm4gYnkgVFJBSU5JTkcgdG8iLCJwZXJmb3JtIHRhc2tzIGJ5IiwiYmVpbmcgc2hvd24gZXhhbXBsZXMifSwNCiAgeyJORVVSQUwgTkVUV09SSzogaXMgYSIsIm5ldHdvcmsgb2YgTk9ERVMiLCJ0aGF0IGFyZSBjb25uZWN0ZWQiLCJ0b2dldGhlciBieSBXRUlHSFRTIn0sDQogIHsiV0VJR0hUIE1FTU9SWTogaXMgYSIsInN0b3JlIG9mIFdFSUdIVFMiLCJ0aGF0IGFjdHMgYXMgbG9uZyIsInRlcm0gbWVtb3J5In0sDQogIHsiV0VJR0hUUzogbnVtYmVycyIsInRoYXQgc2hvdyBhIHN0cmVuZ3RoIiwib2YgY29ubmVjdGlvbiIsImJldHdlZW4gdGhlIE5PREVTIn0sDQogIHsiV0VJR0hUUzogYXJlIGxlYXJudCIsImFuZCBhZGp1c3RlZCBkdXJpbmciLCJUUkFJTklORyBhbmQgY29ubmVjdCIsIk5PREVTIHRvZ2V0aGVyIn0sDQogIHsiTk9ERVM6IGFyZSBzaW5nbGUiLCJwcm9jZXNzaW5nIHVuaXRzIiwidGhhdCBtaW1pYyBhIHJlYWwiLCJiaW9sb2dpY2FsIG5ldXJvbiJ9LCANCiAgeyJOT0RFUzogY2FsY3VsYXRlIiwiLWlucHV0cyBYIFdFSUdIVFMtIiwiYW5kIG91dHB1dHMgYSBzaWduYWwiLCJ0byBvdGhlciBub2RlcyJ9LA0KICB7Ik5PREVTOiBmaXJlcyBhbiIsIm91dHB1dCBzaWduYWwgd2hlbiIsInRoZSBzdW0gb2YgaXRzIGlucHV0IiwiZXhjZWVkcyBhIFRIUkVTSE9MRCJ9LA0KICB7IlRIUkVTSE9MRDogYSBudW1iZXIiLCJ0byBjb21wYXJlIGFnYWluc3QiLCJ0byBzYXkgd2hhdCBjYXRlZ29yeSIsInNvbWV0aGluZyBpcyJ9LA0KICB7Ik1BUFBJTkc6IHR1cm5zIHJlYWwiLCJ3b3JsZCBkYXRhIGxpa2UiLCJjb2xvciBhbmQgc2l6ZSBpbnRvIiwiSU5QVVQgU0lHTkFMUyJ9LA0KICB7Ik1BUFBJTkc6IHR1cm5zIHRoZSIsIk9VVFBVVCBTSUdOQUxTIiwiaW50byByZWFsIHdvcmxkIGRhdGEiLCJsaWtlIC1ib3ggdHlwZS0ifSwNCiAgeyJJTlBVVCBTSUdOQUxTOiBhcmUiLCJudW1iZXJzIHRoYXQgZmVlZCIsInRoZSBpbnB1dHMgb2YgYSIsIk5FVVJBTCBORVRXT1JLIn0sDQogIHsiT1VUUFVUIFNJR05BTFM6IGFyZSIsImNhbGN1bGF0ZWQgYnkgdGhlIiwiTkVVUkFMIE5FVFdPUksgdG8iLCJDTEFTU0lGWSBpbnB1dCBkYXRhIn0sIA0KICB7IkxFQVJOSU5HOiBnZXR0aW5nIiwiYmV0dGVyIGF0IHBlcmZvcm1pbmciLCJhIHRhc2sgYnkgcmVjZWl2aW5nIiwiVFJBSU5JTkcifSwNCiAgeyJMRUFSTklORzoga25vd2xlZGdlIiwiZ2FpbmVkIGJ5IHNlZWluZyIsIm1hbnkgZ29vZCBhbmQgYmFkIiwiZXhhbXBsZXMgb2YgYSB0aGluZyJ9LCANCiAgeyJMRUFSTklORzogTkVVUkFMIiwiTkVUV09SS1MgbGVhcm4gYnkgYSIsImEgbWV0aG9kIGNhbGxlZCBCQUNLIiwiUFJPUEFHQVRJT04ifSwgDQogIHsiVFJBSU5JTkc6IGEgcHJvY2VzcyIsIm9mIHN0cnVjdHVyZWQiLCJMRUFSTklORyB0aGF0IHVzZXMiLCJUUkFJTklORyBFWEFNUExFUyJ9LA0KICB7IlRSQUlOSU5HIEVYQU1QTEVTOiIsImEgcHJlLXBsYW5uZWQgc2V0IG9mIiwiZ29vZCAmIGJhZCBleGFtcGxlcyIsInRvIHRlYWNoIHdpdGgifSwgDQogIHsiQkFDSyBQUk9QQUdBVElPTjoiLCJ1c2VzIGFuIEVSUk9SIFNJR05BTCIsInRvIGFkanVzdCB0aGUgV0VJR0hUIiwiTUVNT1JZIGNvbnRlbnRzIn0sDQogIHsiQkFDSyBQUk9QQUdBVElPTjogaXMiLCJ0aGUgdHlwZSBvZiBMRUFSTklORyIsInVzZWQgYnkgYSBORVVSQUwiLCJORVRXT1JLIn0sDQogIHsiRVJST1IgU0lHTkFMOiBpcyB0aGUiLCJkaWZmLiBiZXR3ZWVuIE9VVFBVVCIsIlNJR05BTFMgYW5kIHRoZSIsIlRSQUlOSU5HIEVYQU1QTEVTIn0sDQogIHsiRVJST1IgU0lHTkFMOiBpcyBhIiwid2F5IHRvIHRlbGwgYSBORVVSQUwiLCJORVRXT1JLIGlmIGl0IGlzIiwiY29ycmVjdCBvciBub3QifSwNCiAgeyI8Ym94IG5hbWU+IHVzZXMgYSIsIlBFUkNFUFRST04gdG8iLCJDTEFTU0lGWSBkaWZmZXJlbnQiLCJzaXplIGFuZCBjb2xvciBib3hlcyJ9LA0KICB7Ijxib3ggbmFtZT4gaXMgYSIsInNpbXBsZSBleGFtcGxlIG9mIiwiTUFDSElORSBMRUFSTklORyBhbmQiLCJORVVSQUwgTkVUV09SS1MifSwNCiAgeyJNQUNISU5FIExFQVJOSU5HOiBpcyIsImEgc3Vic2V0IG9mIEFJIGFuZCIsImlzIGEgYnJhbmNoIG9mIHN0dWR5IiwiaW4gQ29tcHV0ZXIgU2NpZW5jZSJ9LCAgDQogIHsiTUFDSElORSBMRUFSTklORzoiLCJhbGxvd3MgbWFjaGluZXMgdG8iLCJsZWFybiBuZXcgdGFza3MiLCJ3aXRob3V0IHByb2dyYW1taW5nIn0sDQogIHsiTUFDSElORSBMRUFSTklORzoiLCJjb21tb25seSB1c2VzIE5FVVJBTCIsIk5FVFdPUktTIGFzIHRoZSBtYWluIiwiZm9ybSBvZiBpbnRlbGxpZ2VuY2UifSwNCiAgeyJBSTogYWltcyB0byBtYWtlIiwiY29tcHV0ZXJzIGFzIHNtYXJ0Iiwib3Igc21hcnRlciB0aGFuIGEiLCJodW1hbiEifSwNCiAgeyJBSTogdXNlcyBNQUNISU5FIiwiTEVBUk5JTkcgYXMgYSB0b29sIiwidG8gYmVjb21pbmcgbW9yZSIsImludGVsbGlnZW50In0sIA0KfTsNCg0KI2RlZmluZSBwb3RNYXggNzAwDQojZGVmaW5lIHBvdE1pbiAzMDANCg0KZW51bSBwb25nR2FtZU1vZGUgew0KICBwb25nUGxheSwNCiAgcG9uZ1Nob3dTY29yZSwNCiAgcG9uZ1dhaXQsDQogIHBvbmdFeGl0DQp9Ow0KDQpwb25nR2FtZU1vZGUgcG9uZ01vZGUgPSBwb25nV2FpdDsNCg0KaW50IGJhbGxTcGVlZCA9IDIwMDsNCmludCBiYWxsUG9zWDsNCmludCBiYWxsUG9zWTsNCmludCBiYWxsRGlyWDsNCmludCBiYWxsRGlyWTsNCmludCByaWdodFBhZGRsZVBvczsNCmludCBsZWZ0UGFkZGxlUG9zOw0KYm9vbGVhbiBzdGlja0JhbGxUb1BhZGRsZTsNCmludCBiYWxsT25QYWRkbGU7DQp1bnNpZ25lZCBsb25nIGxhc3RCYWxsVXBkYXRlOw0KYm9vbGVhbiBjaGVja0JhbGw7DQoNCmludCBwb25nTGl2ZXM7DQp1bnNpZ25lZCBsb25nIGludCBwb25nU2NvcmU7DQp1bnNpZ25lZCBsb25nIGludCBwb25nU2NvcmVJbmNyZW1lbnQgPSAxMDsNCg0KU3RyaW5nIHRyYWluQ29ycmVjdFs1XSA9IHsNCiAgIllFUywgSSBrbmV3IGl0IHdhcyIsDQogICJIQSEgYXMgSSB0aG91Z2h0LCAiLA0KICAiT0ggWUVBSCAtIHRoYXQncyIsDQogICJUaGFua3lvdS4gSSBrbm93IGl0cyIsDQogICJCT09NLiBJIHdhcyByaWdodCEiIA0KfTsNCg0KU3RyaW5nIHRyYWluV3JvbmdbNV0gPSB7DQogICJOTyEgSSB3YXMgc3VyZSBpdHMiLA0KICAiT0gsIEkgdGhvdWdodCBpdCB3YXMiLA0KICAiSFVIIEkgd2FzIHdyb25nIHdpdGgiLA0KICAiSSdtIHNob2NrZWQgaXRzIG5vdCIsDQogICJOb3cgSSBzZWUgaXRzIG5vdCIgDQp9Ow0KDQp2b2lkIHNldHVwKCkgew0KDQogIFNlcmlhbC5iZWdpbigxMTUyMDApOw0KICANCiAgcGluTW9kZShwb3RMZWZ0LCBJTlBVVCk7DQogIHBpbk1vZGUocG90Q2VudGVyLCBJTlBVVCk7DQogIHBpbk1vZGUocG90UmlnaHQsIElOUFVUKTsNCiAgcGluTW9kZShncmVlbkJ1dHRvbiwgSU5QVVQpOw0KICBwaW5Nb2RlKGJsdWVCdXR0b24sIElOUFVUKTsNCiAgcGluTW9kZShyZWRCdXR0b24sIElOUFVUKTsNCiAgcGluTW9kZShqb3lCdXR0b24sIElOUFVUKTsNCiAgcGluTW9kZShqb3lILCBJTlBVVCk7DQogIHBpbk1vZGUoam95ViwgSU5QVVQpOw0KICBwaW5Nb2RlKGFtcEVuYWJsZSwgT1VUUFVUKTsNCg0KICAvLyBzZXR1cCBTRC1jYXJkDQogIGlmICghU0QuYmVnaW4oc2RDcykpIHsNCiAgICBzZEluaXQgPSBmYWxzZTsNCiAgfSBlbHNlIHsNCiAgICBzZEluaXQgPSB0cnVlOw0KICB9DQogICAgDQogIC8qIHR1cm4gb24gdGhlIHRpbWVyIGNsb2NrIGluIHRoZSBwb3dlciBtYW5hZ2VtZW50IGNvbnRyb2xsZXIgKi8NCiAgcG1jX3NldF93cml0ZXByb3RlY3QoZmFsc2UpOw0KICBwbWNfZW5hYmxlX3BlcmlwaF9jbGsoSURfVEM0KTsNCiAgLyogd2Ugd2FudCB3YXZlc2VsIDAxIHdpdGggUkMgKi8NCiAgVENfQ29uZmlndXJlKC8qIGNsb2NrICovVEMxLC8qIGNoYW5uZWwgKi8xLCBUQ19DTVJfV0FWRSB8IFRDX0NNUl9XQVZTRUxfVVBfUkMgfCBUQ19DTVJfVENDTEtTX1RJTUVSX0NMT0NLMik7DQogIFRDX1NldFJDKFRDMSwgMSwgMjM4KTsgLy8gc2V0cyA8PiA0NC4xIEtoeiBpbnRlcnJ1cHQgcmF0ZQ0KICBUQ19TdGFydChUQzEsIDEpOyANCiAgLy8gZW5hYmxlIHRpbWVyIGludGVycnVwdHMgb24gdGhlIHRpbWVyIA0KICBUQzEtPlRDX0NIQU5ORUxbMV0uVENfSUVSPVRDX0lFUl9DUENTOw0KICBUQzEtPlRDX0NIQU5ORUxbMV0uVENfSURSPX5UQ19JRVJfQ1BDUzsgDQogIC8qIEVuYWJsZSB0aGUgaW50ZXJydXB0IGluIHRoZSBuZXN0ZWQgdmVjdG9yIGludGVycnVwdCBjb250cm9sbGVyICovDQogIC8qIFRDNF9JUlFuIHdoZXJlIDQgaXMgdGhlIHRpbWVyIG51bWJlciAqIHRpbWVyIGNoYW5uZWxzICgzKSArIHRoZSBjaGFubmVsIG51bWJlciAoPSgxKjMpKzEpIGZvciB0aW1lcjEgY2hhbm5lbDEgKi8NCiAgTlZJQ19FbmFibGVJUlEoVEM0X0lSUW4pOw0KICAvLyBtYWtlIHRoZSBsb29rIHVwIHRhYmxlcw0KICBjcmVhdGVOb3RlVGFibGUoU0FNUExFX1JBVEUpOw0KICBtYWtlU2luZVdhdmUoKTsNCiAgLy9zZXQgdXAgdGhlIGRhYw0KICBhbmFsb2dXcml0ZVJlc29sdXRpb24oMTIpOw0KICBhbmFsb2dXcml0ZShEQUMxLCAwKTsNCg0KICBsY2QuYmVnaW4oMjAsIDQpOyAvLyBpbml0aWFsaXplIHRoZSBsY2QNCiAgbGNkLnNldEJhY2tsaWdodCgxKTsgDQogIGxjZC5jcmVhdGVDaGFyKDAsIGxvY2spOw0KDQogIG1hdHJpeC5iZWdpbigpOw0KICBtYXRyaXguc2V0VGV4dFdyYXAoZmFsc2UpOw0KICBtYXRyaXguc2V0QnJpZ2h0bmVzcyg2MCk7DQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguY2xlYXIoKTsNCiAgbGVkcy5iZWdpbigpOyAgDQogIGxlZHMuc2V0QnJpZ2h0bmVzcyg2MCk7DQogIGxlZHMuY2xlYXIoKTsNCiAgbGVkcy5zaG93KCk7DQoNCiAgLy8gSkYtDQogIC8vIHVuY29tbWVudCBsaW5lcyBiZWxvdyBpZiB5b3UgbmVlZCB0byBkZWxldGUgYSBjb3JydXB0IGxvZyBmaWxlDQogIC8vaWYgKFNELmV4aXN0cygic2V0dGluZ3MudHh0IikpDQogIC8vICBTRC5yZW1vdmUoInNldHRpbmdzLnR4dCIpOw0KDQogIGxvYWRlZFNldHRpbmdzID0gcmVhZFNldHRpbmdzKCk7DQoNCiAgc2VlZFJORygpOw0KDQogIGxhc3RCYWxsVXBkYXRlID0gbWlsbGlzKCk7DQogIGNoZWNrQmFsbCA9IGZhbHNlOw0KICByZWFkUGFkZGxlUG9zaXRpb24oKTsNCiAgc3RpY2tCYWxsVG9QYWRkbGUgPSB0cnVlOw0KICBiYWxsT25QYWRkbGUgPSByYW5kb20oMik7DQoNCiAgDQogIGxlZHMuY2xlYXIoKTsNCiAgbGVkcy5zaG93KCk7DQoNCiAgU2VyaWFsLnByaW50KGJveE5hbWUpOw0KICBTZXJpYWwucHJpbnQoIiBmbHVzaCBzZXJpYWwgcG9ydC4uLi4iKTsNCiAgU2VyaWFsLmZsdXNoKCk7DQoNCn0NCg0Kdm9pZCBlbnRlck5hbWUoKSB7DQoNCiAgLy8gMTYgY2hhcnMNCiAgLy8gc2hvdyBjdXJzb3INCiAgLy8gQS1aDQogIC8vIGpveSBzdGljayB2IC0gbW92ZSBjdXJzb3INCiAgLy8gam95IGJ1dXRvbiB0byBzZWxlY3QgLSBhbnkgb3RoZSBidXR0b24gdG8gZmluaXNoDQogIC8vIG1pZGRsZSBkaWFsIHRvIHNlbGVjdCBndWlsZA0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICANCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwwKTsNCiAgbGNkLnByaW50KCJVc2UgdGhlIGRpYWxzIHRvICIpOw0KICBsY2Quc2V0Q3Vyc29yKDAsMSk7DQogIGxjZC5wcmludCgibmFtZSB5b3VyIGJyYWluIGFuZCIpOw0KICBsY2Quc2V0Q3Vyc29yKDAsMik7DQogIGxjZC5wcmludCgic2VsZWN0IHlvdXIgZ3VpbGQuIik7DQoNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICB9DQoNCiAgbGNkLmNsZWFyKCk7DQoNCiAgaW50IGNQb3MgPSAwOw0KICBpbnQgY1NlbCA9IDA7DQogIGludCBjUG9zTGFzdCA9IC0xOw0KICBpbnQgY1NlbExhc3QgPSAtMTsNCiAgaW50IHB2ID0gMDsNCg0KICBTdHJpbmcgbmV3TmFtZSA9IHBhZFN0cmluZygxMixib3hOYW1lKTsNCiAgDQogIGJvb2xlYW4gbmFtZVNldCA9IGZhbHNlOw0KICB3aGlsZSghbmFtZVNldCkgew0KDQogICAgcHYgPSBhbmFsb2dSZWFkKHBvdFJpZ2h0KTsNCiAgICBwdiA9IGZsb29yKHB2LzM0Mik7ICANCg0KICAgIC8vIG5lZWQgdG8gY29weSB0aGlzIGlmIG1vZGRlZCB0byB3ZWxjb21lL3NldC1uYW1lDQogICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICB1aW50MzJfdCBjID0gbWF0cml4LkNvbG9yKDAsMCwwKTsNCiAgICAgICAgc3dpdGNoIChndWlsZEdseXBoc1twdl1beF1beV0pIHsNCiAgICAgICAgICBjYXNlICdSJzoNCiAgICAgICAgICAgIGMgPSBnUmVkOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnTyc6DQogICAgICAgICAgICBjID0gZ09yYW5nZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1knOg0KICAgICAgICAgICAgYyA9IGdZZWxsb3c7DQogICAgICAgICAgICBicmVhazsNCiAgICAgICAgICBjYXNlICdCJzoNCiAgICAgICAgICAgIGMgPSBnQmx1ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1QnOg0KICAgICAgICAgICAgYyA9IGdUZWFsOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnRyc6DQogICAgICAgICAgICBjID0gZ0dyZWVuOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnUCc6DQogICAgICAgICAgICBjID0gZ1B1cnBsZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1cnOg0KICAgICAgICAgICAgYyA9IGdXaGl0ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJyAnOg0KICAgICAgICAgICAgYyA9Z0JsYWNrOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgZGVmYXVsdDoNCiAgICAgICAgICAgIGMgPSBnQmxhY2s7DQogICAgICAgICAgICBicmVhazsgIA0KICAgICAgICB9DQogICAgICAgIG1hdHJpeC5kcmF3UGl4ZWwoeSx4LGMpOw0KICAgICAgfQ0KICAgIH0NCg0KICAgIGNQb3MgPSBhbmFsb2dSZWFkKHBvdExlZnQpOw0KICAgIGNQb3MgPSBmbG9vcihjUG9zLzg2KTsNCg0KICAgIGNTZWwgPSBhbmFsb2dSZWFkKHBvdENlbnRlcik7DQogICAgY1NlbCA9IGZsb29yKGNTZWwvMzkpOw0KDQogICAgaWYgKGNTZWwgIT0gY1NlbExhc3QpIHsNCiAgICAgIGNoYXIgYyA9IGNTZWwgKyA2NTsNCiAgICAgIGlmIChjU2VsID09IDI2KQ0KICAgICAgICBjID0gJyAnOw0KICAgICAgbmV3TmFtZS5zZXRDaGFyQXQoY1BvcyxjKTsNCiAgICAgIGxjZC5zZXRDdXJzb3IoNCwwKTsNCiAgICAgIGxjZC5wcmludChuZXdOYW1lKTsNCiAgICB9DQoNCiAgICANCiAgICBpZiAoY1BvcyAhPSBjUG9zTGFzdCkgew0KICAgICAgbGNkLnNldEN1cnNvcigwLDEpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiICIpKTsNCiAgICAgIGxjZC5zZXRDdXJzb3IoY1Bvcys0LDEpOw0KICAgICAgbGNkLnByaW50KCJeIik7DQogICAgfQ0KICAgIA0KICAgIC8vbGNkLm5vQ3Vyc29yKCk7DQogICAgbGNkLnNldEN1cnNvcigwLDMpOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsZ3VpbGROYW1lc1twdl0pKTsNCg0KICAgIG1hdHJpeC5zaG93KCk7DQoNCiAgICBjU2VsTGFzdCA9IGNTZWw7DQogICAgY1Bvc0xhc3QgPSBjUG9zOw0KDQogICAgaWYgKGJ1dHRvblByZXNzZWQoYW55KSkNCiAgICAgIG5hbWVTZXQgPSB0cnVlOw0KDQogIH0NCg0KICBib3hOYW1lID0gbmV3TmFtZTsgDQogIGJveE5hbWUudHJpbSgpOw0KICBib3hHdWlsZCA9IGd1aWxkTmFtZXNbcHZdOw0KICBsb2dTZXR0aW5ncygpOw0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICANCn0NCg0Kdm9pZCBmYWN0b3J5TW9kZSgpIHsgDQoNCiAgdW5zaWduZWQgbG9uZyB0ID0gMDsvL21pbGxpcygpOw0KICB1bmlvbiB7Ynl0ZSBiWzRdO2Zsb2F0IGY7fSB0ZW1wOw0KICBieXRlICogYjsNCg0KICBsb2dTZXR0aW5ncygpOw0KDQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwwKTsNCiAgbGNkLnByaW50KCJVcGxvYWRpbmcgYnJhaW4iKTsNCiAgbGNkLnNldEN1cnNvcigwLDEpOw0KICBsY2QucHJpbnQoInRvIHRoZSBib3ggZmFjdG9yeS4iKTsNCg0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCg0KICBpbnQgaSA9IDA7DQoNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSAmJiAoaTw1KSkgew0KDQogICAgaWYgKG1pbGxpcygpLXQgPiA1MDAwKSB7DQogICANCiAgICAgIFNlcmlhbC5wcmludCgiU29TIik7DQogICAgICBTZXJpYWwuZmx1c2goKTsNCiAgICAgIFNlcmlhbC5wcmludChwYWRTdHJpbmcoMjAsYm94TmFtZSkpOw0KICAgICAgU2VyaWFsLmZsdXNoKCk7DQogICAgICBTZXJpYWwucHJpbnQocGFkU3RyaW5nKDIwLGJveEd1aWxkKSk7DQoNCiAgICAgIGludCBwdiA9IDA7DQogICAgICBpZiAoYm94R3VpbGQgPT0gIlBIT0VOSVgiKQ0KICAgICAgICBwdiA9IDE7DQogICAgICBpZiAoYm94R3VpbGQgPT0gIkxJR0hUTklORyIpDQogICAgICAgIHB2ID0gMjsNCiAgICAgIGZvciAoaW50IHg9MDsgeDw4OyB4KyspIHsNCiAgICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICAgIFNlcmlhbC5wcmludChndWlsZEdseXBoc1twdl1beF1beV0pOyAgICAgICAgIA0KICAgICAgICB9DQogICAgICAgIFNlcmlhbC5mbHVzaCgpOw0KICAgICAgfQ0KICAgICAgDQogICAgICBmb3IgKGludCBpPTA7IGk8cGFyYW1MZW47IGkrKykgew0KICAgICAgICAgIHRlbXAuYltpJTRdID0gcGFyYW1zW2ldOw0KICAgICAgICAgIGlmIChpJTQgPT0gMykgew0KICAgICAgICAgICAgYiA9IChieXRlICopICZ0ZW1wLmY7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlswXSk7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlsxXSk7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlsyXSk7DQogICAgICAgICAgICBTZXJpYWwud3JpdGUoYlszXSk7ICAgDQogICAgICAgICAgICBTZXJpYWwuZmx1c2goKTsgICANCiAgICAgICAgICB9ICAgICAgICANCiAgICAgIH0NCg0KDQoNCiAgICAgIGkrKzsNCiAgICAgIA0KICAgICAgbGNkLnNldEN1cnNvcigwLDMpOw0KICAgICAgbGNkLnByaW50KCJzZW50OiIrU3RyaW5nKGkpKTsNCiAgICAgIA0KICAgICAgdCA9IG1pbGxpcygpOw0KICAgIA0KICAgIH0NCiAgICANCiAgfQ0KDQogIG1vZGUgPSBtZW51Ow0KfQ0KDQoNCnZvaWQgbG9vcCgpIHsNCg0KICBzd2l0Y2ggKG1vZGUpIHsNCiAgICBjYXNlIHdlbGNvbWU6DQogICAgICBtb2RlRGVzYyA9ICJXZWxjb21lIE1vZGUiOw0KICAgICAgd2VsY29tZU1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2Ugd29yazoNCiAgICAgIG1vZGVEZXNjID0gIldvcmsgTW9kZSI7DQogICAgICB3b3JrTW9kZSgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBicmFpbnN0YXRlOg0KICAgICAgbW9kZURlc2MgPSAiU3RhdGUgTW9kZSI7DQogICAgICBzdGF0ZU9mTWluZCgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBtZW51Og0KICAgICAgbW9kZURlc2MgPSAiTWVudSBNb2RlIjsNCiAgICAgIG1haW5NZW51KCk7DQogICAgICBicmVhazsNCiAgICBjYXNlIHRyYWluOg0KICAgICAgbW9kZURlc2MgPSAiVHJhaW4gTW9kZSI7DQogICAgICB0cmFpbk1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2UgYW5hbHl6ZToNCiAgICAgIG1vZGVEZXNjID0gIkFuYWx5emUgTW9kZSI7DQogICAgICBhbmFseXplTW9kZSgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBmYWN0b3J5Og0KICAgICAgbW9kZURlc2MgPSAiRmFjdG9yeSBNb2RlIjsNCiAgICAgIGZhY3RvcnlNb2RlKCk7DQogICAgICBicmVhazsNCiAgICBjYXNlIHNldHRpbmdzOg0KICAgICAgbW9kZURlc2MgPSAiU2V0dGluZ3MgTW9kZSI7DQogICAgICBzZXR0aW5nc01vZGUoKTsNCiAgICAgIGJyZWFrOyAgICANCiAgICBjYXNlIGluc3RydWN0aW9uczoNCiAgICAgIG1vZGVEZXNjID0gIkluc3RyLiBNb2RlIjsNCiAgICAgIGluc3RydWN0aW9uc01vZGUoKTsNCiAgICAgIGJyZWFrOyAgDQogICAgY2FzZSBwb25nOg0KICAgICAgbW9kZURlc2MgPSAiUG9uZyBNb2RlIjsNCiAgICAgIHBvbmdMb29wKCk7DQogICAgICBicmVhazsgIA0KICAgIGNhc2Ugc3ludGg6DQogICAgICBtb2RlRGVzYyA9ICJTeW50aCI7DQogICAgICBzeW50aE1vZGUoKTsNCiAgICAgIGJyZWFrOyAgICAgICAgDQogIH0NCiAgIA0KfQ0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIHN0YXRlT2ZNaW5kDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCnZvaWQgc3RhdGVPZk1pbmQoKSB7DQoNCiAgbGNkLmNsZWFyKCk7DQogIHBhZ2VDbGVhcigpOw0KICBwYWdlQWRkSGVhZGluZygiLS0tLUJSQUlOLS1TVEFURS0tLS0iKTsNCg0KICBwYWdlQWRkRW50cnkoMCwgIkkgYW0gIiArIGJveE5hbWUpOw0KICBwYWdlQWRkRW50cnkoMSwgYm94R3VpbGQgKyAiIGd1aWxkIik7DQogIHBhZ2VBZGRFbnRyeSgyLCAiVHJhaW5pbmcgc2V0cz0iICsgU3RyaW5nKHRyYWluQ3ljbGVzKSk7DQogIHBhZ2VBZGRFbnRyeSgzLCAiQWNjdXJhY3k9IiArIFN0cmluZyh3b3JrTW9kZUF2ZXJhZ2UsMikpOw0KICBwYWdlQWRkRW50cnkoNCwgIkJlc3Qgc2NvcmU9IiArIFN0cmluZyh3b3JrTW9kZUJlc3QpKTsNCiAgcGFnZUFkZEVudHJ5KDUsICJQZXJjZXB0cm9uIHdlaWdodDoiKTsNCiAgcGFnZUFkZEVudHJ5KDYsICItLVcwPSIgKyBTdHJpbmcobm5XZWlnaHRzWzBdLDEzKSk7ICANCiAgcGFnZUFkZEVudHJ5KDcsICItLVcxPSIgKyBTdHJpbmcobm5XZWlnaHRzWzFdLDEzKSk7DQogIHBhZ2VBZGRFbnRyeSg4LCAiLS1XMj0iICsgU3RyaW5nKG5uV2VpZ2h0c1syXSwxMykpOyANCiAgcGFnZUFkZEVudHJ5KDksICJMZWFybmluZyByYXRlOiIpOw0KICBwYWdlQWRkRW50cnkoMTAsICItLXJhdGU9IisgU3RyaW5nKG5uTGVhcm5pbmdDLDExKSk7ICANCiAgcGFnZUFkZEVudHJ5KDExLCAiQm94IGdlbmVyYXRvcnM6Iik7DQogIHBhZ2VBZGRFbnRyeSgxMiwgIi0tY01heD0iICsgU3RyaW5nKGNNYXgpKTsNCiAgcGFnZUFkZEVudHJ5KDEzLCAiLS1nYlJhZGl1cz0iICsgU3RyaW5nKGdvb2RCb3hSYWRpdXMsNCkpOw0KDQogIGludCBzZWxlY3RlZCA9IDA7DQogIHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICANCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICAgIHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KDQogICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICBpbnQgeHMgPSByYW5kb20oMCwgMTAwKTsgLy9jbWF4KjIgLyA4ID0gMTAwDQogICAgICAgIGludCB5cyA9IHJhbmRvbSgwLCAxMDApOw0KICAgICAgICB4cyArPSAoeC00KSoxMDA7DQogICAgICAgIHlzICs9ICh5LTQpKjEwMDsgICAgDQogICAgICAgIGZsb2F0IHByZWRpY3Rpb24gPSAobm5GZWVkRm9yd2FyZCh4cywgeXMpICsgMS4wKS8yLjA7DQogICAgICAgIHByZWRpY3Rpb24gKj0gMTI3LjA7DQogICAgICAgIHVpbnQxNl90IFJHQiA9IG1hdHJpeC5Db2xvcihwcmVkaWN0aW9uLCAxMjgtcHJlZGljdGlvbiwgMCk7DQogICAgICAgIG1hdHJpeC5kcmF3UGl4ZWwoeCwgNy15LCBSR0IpOyAgIA0KICAgICAgfSAgICAgIA0KICAgIH0NCg0KIA0KICAgICBtYXRyaXguc2hvdygpOw0KICAgIA0KICB9DQoNCg0KICAvKg0KICAvLyBtYXAgdGhlIGxlYXJuaW5nIHN0YXRlIHRvIGEgY29sb3I6IDUwIG9yIGxvd2VyIGJhZCA9IHJlZCAuLi4uIDEwMCBnb29kID0gZ3JlZW4NCiAgZmxvYXQgY29sID0gKCh3b3JrTW9kZUF2ZXJhZ2UtNTApLzUwKSoxMjg7DQogIGlmIChjb2wgPCAwKQ0KICAgIGNvbCA9IDA7ICANCiAgc2V0TkVPU2Nyb2xsTWVzc2FnZSgiU0hPV0lORyBNWSBTVEFURSBPRiBNSU5EICAiLG1hdHJpeC5Db2xvcigxMjgtY29sLCBjb2wsIDApKTsNCg0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogICAgdXBkYXRlTkVPU2Nyb2xsTWVzc2FnZSgpOw0KICAgIHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICB9Ki8NCg0KICBtb2RlID0gbWVudTsNCiAgDQp9DQoNCg0Kdm9pZCBhbmFseXplTW9kZSgpIHsNCg0KICBsY2QuY2xlYXIoKTsNCiAgbWF0cml4LmNsZWFyKCk7DQogIG1hdHJpeC5zaG93KCk7DQoNCg0KICANCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLS0tQU5BTFlaRS1NT0RFLS0tLSIpOw0KICBwYWdlQWRkRW50cnkoMCwiVXNlIHRoZSBkaWFscyB0byIpOw0KICBwYWdlQWRkRW50cnkoMSwibWFrZSBjb2xvcmVkIik7DQogIHBhZ2VBZGRFbnRyeSgyLCJib3hlcyAuLi4uLiIpOw0KLy9uZWVkIG5vcmUNCiAgICANCiAgaW50IHNlbGVjdGVkID0gMDsNCiAgc2VsZWN0ZWQgPSBwYWdlVXBkYXRlKCk7DQogICAgDQogIHdoaWxlKCFidXR0b25QcmVzc2VkKGFueSkpIHsNCiAgICAvL3VwZGF0ZU5FT1Njcm9sbE1lc3NhZ2UoKTsNCiAgICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCiAgfQ0KIA0KICBsY2QuY2xlYXIoKTsNCiAgDQogIGZsb2F0IHhzID0gMDsNCiAgZmxvYXQgeXMgPSAwOw0KDQogIC8vIG1ha2UgYSBib3ggdW50aWwgYW55IGJ1dHRvbiBpcyBwdXNoZWQNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYmx1ZSkpIHsNCiAgICB4cyA9ICgoKGZsb2F0KWFuYWxvZ1JlYWQocG90TGVmdCkgLyA1MTEuNSktMS4wKSpjTWF4Ow0KICAgIGlmICh4cyA8IC0zNzQpIHhzID0gLTM3NDsNCiAgICB5cyA9ICgoKGZsb2F0KWFuYWxvZ1JlYWQocG90UmlnaHQpIC8gNTExLjUpLTEuMCkqY01heDsNCiAgICBpbnQgYm94U2l6ZSA9ICgoeHMrY01heCkvKGNNYXgqMikpKjMxOw0KICAgIGludCBib3hDb2xvciA9ICgoKHlzK2NNYXgpLyhjTWF4KjIpKSoxMjcpKzMyOw0KICAgIGRyYXdCb3goYm94U2l6ZSwgYm94Q29sb3IsIHRydWUpOw0KICAgIC8vIHJ1biB0aGUgbmV1cmFsIG5ldCBmb3J3YXJkDQogICAgaW50IHByZWRpY3Rpb24gPSBubkZlZWRGb3J3YXJkKHhzLCB5cyk7IA0KICAgICAgLy8gcHJlZGljdGlvbiAxID0gbGFyZ2UgcmVkICAgIC0xID0gc21hbGwgZ3JlZW4NCiAgICANCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIlVzZSB0aGUgZGlhbHMgdG8iKSk7DQogICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJtYWtlIGJveGVzLiIpKTsNCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIkkgdGhpbmsgdGhpcyBpcyBhICIpKTsNCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgIGlmIChwcmVkaWN0aW9uID09IDEpIA0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwibGFyZ2UgcmVkIGJveC4iKSk7DQogICAgZWxzZSAgDQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJzbWFsbCBncmVlbiBib3guIikpOw0KICB9DQoNCiAgbGNkLmNsZWFyKCk7DQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICANCiAgbW9kZSA9IG1lbnU7DQogIHJldHVybjsNCg0KfQ0KDQp2b2lkIGFib3V0TW9kZSgpIHsNCg0KICBsY2QuY2xlYXIoKTsNCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLUZSWURFTi1MRUFSTklORy0tIik7DQoNCiAgcGFnZUFkZEVudHJ5KDAsICJCb3ggZmFjdG9yeSB2ZXI6Iik7DQogIHBhZ2VBZGRFbnRyeSgxLCB2ZXJOdW0pOw0KICBwYWdlQWRkRW50cnkoMiwgIlBsZWFzZSB2aXNpdDoiKTsNCiAgcGFnZUFkZEVudHJ5KDMsICJmcnlkZW4tbGVhcm5pbmcuY29tIik7DQogIHBhZ2VBZGRFbnRyeSg0LCAiU3VwcG9ydGVkIGJ5OiIpOw0KICBwYWdlQWRkRW50cnkoNSwgIkFybSBJbmMuIik7DQogIHBhZ2VBZGRFbnRyeSg2LCAiU3Vuc3RvbmUgQ2lyY3VpdHMiKTsNCg0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogICAgaW50IHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICB9DQoNCn0NCg0Kdm9pZCBpbnN0cnVjdGlvbnNNb2RlKCkgew0KICBsY2QuY2xlYXIoKTsNCiAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgbGNkLnByaW50KCIuLi5pbiAiK21vZGVEZXNjKTsNCiAgZGVsYXkoMjAwMCk7DQogIG1vZGUgPSBtZW51Ow0KfQ0KDQp2b2lkIHNldHRpbmdzTW9kZSgpIHsNCg0KICBib29sZWFuIGxlYXZlID0gZmFsc2U7DQoNCiAgd2hpbGUgKCFsZWF2ZSkgew0KICANCiAgICBsY2QuY2xlYXIoKTsNCiAgICBtZW51Q2xlYXIoKTsNCiAgICBtZW51QWRkSGVhZGluZygiLS0tLS0tU0VUVElOR1MtLS0tLS0iKTsNCiAgICBmb3IgKGludCBpPTA7IGk8c2V0dGluZ3NNZW51U2l6ZTsgaSsrKSB7DQogICAgICBtZW51QWRkRW50cnkoaSwgc2V0dGluZ3NNZW51RW50cmllc1tpXSk7DQogICAgfQ0KICANCiAgICBpbnQgc2VsZWN0ZWQgPSAwOyAgDQogICAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICAgICAgc2VsZWN0ZWQgPSBtZW51VXBkYXRlKGZhbHNlKTsNCiAgICB9DQoNCiAgICBzd2l0Y2ggKHNlbGVjdGVkKSB7DQogICAgICBjYXNlIDA6DQogICAgICAgIHNldFZvbHVtZSgpOw0KICAgICAgICBicmVhazsNCiAgICAgIGNhc2UgMToNCiAgICAgICAgc2V0RGlmZmljdWx0eSgpOw0KICAgICAgICBicmVhazsNCiAgICAgIGNhc2UgMjoNCiAgICAgICBlbnRlck5hbWUoKTsNCiAgICAgICBicmVhazsNCiAgICAgIGNhc2UgMzoNCiAgICAgICAgcmVzZXRCcmFpbigpOw0KICAgICAgICBicmVhazsNCiAgICAgIGNhc2UgNDoNCiAgICAgICAgYWJvdXRNb2RlKCk7DQogICAgICAgIGJyZWFrOw0KICAgICAgY2FzZSA1Og0KICAgICAgICBsZWF2ZSA9IHRydWU7DQogICAgICAgIGJyZWFrOyAgDQogICAgICBkZWZhdWx0Og0KICAgICAgICByZXR1cm47DQogICAgfQ0KICAgICAgIA0KICB9DQoNCiAgbW9kZSA9IG1lbnU7DQoNCn0NCg0Kdm9pZCByZXNldEJyYWluKCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICBsY2QucHJpbnQoIkdyZWVuID0gcmVzZXQgYnJhaW4iKTsNCiAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgbGNkLnByaW50KCJSZWQgPSBjYW5jZWwiKTsNCg0KICBib29sZWFuIGFuc3dlcmVkID0gZmFsc2U7DQogIHdoaWxlKCFhbnN3ZXJlZCkgew0KICAgDQogICAgaWYgKGJ1dHRvblByZXNzZWQocmVkKSkgew0KICAgICAgYW5zd2VyZWQgPSB0cnVlOyANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgICBsY2QucHJpbnQoIkJyYWluIG5vdCByZXNldC4iKTsNCiAgICB9IGVsc2UgaWYgKGJ1dHRvblByZXNzZWQoZ3JlZW4pKSB7DQogICAgICBhbnN3ZXJlZCA9IHRydWU7DQogICAgICAgIGJveE5hbWUgPSAiQlJBSU4gQk9YIjsgDQogICAgICAgIGJveEd1aWxkID0gIk5JTkpBIjsNCiAgICAgICAgbm5XZWlnaHRzWzBdID0gLTEuMDsNCiAgICAgICAgbm5XZWlnaHRzWzFdID0gMS4wOw0KICAgICAgICBubldlaWdodHNbMl0gPSAwLjA7DQogICAgICAgIG5uTGVhcm5pbmdDID0gbGVhcm5pbmdSYXRlOw0KICAgICAgICB0cmFpbkN5Y2xlcyA9IDA7DQogICAgICAgIHRvdGFsVHJhaW5pbmdFeGFtcGxlcyA9IDA7DQogICAgICAgIHRvdGFsQ29ycmVjdCA9IDA7DQogICAgICAgIHdvcmtNb2RlQXZlcmFnZSA9IDA7DQogICAgICAgIHdvcmtNb2RlQmVzdCA9IDA7DQogICAgICAgIGdvb2RCb3hSYWRpdXMgPSAxLjE7DQogICAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgICAgIGxjZC5wcmludCgiQnJhaW4gcmVzZXQuIik7DQogICAgfSAgICAgIA0KICAgICAgDQogIH0NCiAgcmVtb3ZlU2V0dGluZ3NMb2coKTsNCiAgZGVsYXkoMTUwMCk7DQogIHJldHVybjsNCn0NCg0Kdm9pZCBzZXRWb2x1bWUoKSB7DQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwwKTsNCiAgbGNkLnByaW50KCJVc2UgdGhlIG1pZGRsZSBkaWFsIik7DQogIGxjZC5zZXRDdXJzb3IoMCwxKTsNCiAgbGNkLnByaW50KCJ0byBhZGp1c3QgdGhlIHZvbHVtZSIpOw0KICANCiAgdW5zaWduZWQgbG9uZyB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogIGJvb2xlYW4gaGlMb3cgPSBmYWxzZTsNCiAgDQogIGFtcE9uKCk7DQogIHdoaWxlKCFidXR0b25QcmVzc2VkKGFueSkpIHsNCg0KICAgIGludCBwdiA9IHBvdFZhbHVlKGNlbnRlciwgMC4wMSk7DQogICAgaWYgKHB2IDwgMCkNCiAgICAgIHB2ID0gMDsNCiAgICBpZiAocHYgPiAxMCkNCiAgICAgIHB2ID0gMTA7DQoNCiAgICB2b2x1bWUgPSBwdjsNCg0KICAgIGxjZC5zZXRDdXJzb3IoMCwzKTsNCiAgICBsY2QucHJpbnQoIlZvbHVtZT0iK1N0cmluZyh2b2x1bWUpKyIgICAgIik7DQoNCiAgICBpZiAobWlsbGlzKCkgLSB0b25lVGltZVN0YW1wID4gMzAwKSB7IA0KICAgICAgICB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICAgIGlmIChoaUxvdykgDQogICAgICAgICAgcGxheVRvbmUoNjAsMTAwMCk7DQogICAgICAgIGVsc2UNCiAgICAgICAgICBwbGF5VG9uZSg5MCwxMDAwKTsNCiAgICAgICAgaGlMb3cgPSAhaGlMb3c7ICAgDQogICAgfSANCiAgIA0KICB9DQogIGFtcE9mZigpOw0KDQogIHJldHVybjsNCn0NCg0Kdm9pZCByZW1vdmVTZXR0aW5nc0xvZygpIHsNCiAgaWYgKHNkSW5pdCkgew0KICAgIGlmIChTRC5leGlzdHMoInNldHRpbmdzLnR4dCIpKQ0KICAgICAgU0QucmVtb3ZlKCJzZXR0aW5ncy50eHQiKTsNCiAgfQ0KfQ0KDQp2b2lkIGxvZ1NldHRpbmdzKCkgew0KICBpZiAoc2RJbml0KSB7DQoNCiAgICBpZiAoU0QuZXhpc3RzKCJzZXR0aW5ncy50eHQiKSkNCiAgICAgIFNELnJlbW92ZSgic2V0dGluZ3MudHh0Iik7DQogICANCiAgICBwYXJhbXNUb0J5dGVzKCk7DQogIA0KICAgIEZpbGUgc2V0dGluZ3MgPSBTRC5vcGVuKCJzZXR0aW5ncy50eHQiLCBGSUxFX1dSSVRFKTsNCiAgDQogICAgaWYgKHNldHRpbmdzKSB7DQogICAgICBzZXR0aW5ncy5wcmludCgifiIgKyBib3hOYW1lICsgIn4iKTsNCiAgICAgIHNldHRpbmdzLnByaW50KCIhIiArIGJveEd1aWxkICsgIiEiKTsNCiAgICAgIGZvciAoaW50IGk9MDsgaTxwYXJhbUxlbjsgaSsrKSB7DQogICAgICAgIHNldHRpbmdzLndyaXRlKHBhcmFtc1tpXSk7DQogICAgICB9DQogICAgICBzZXR0aW5ncy5jbG9zZSgpOw0KICAgIH0gZWxzZSB7DQogICAgICANCiAgICB9DQogIH0NCn0NCg0KYm9vbGVhbiByZWFkU2V0dGluZ3MoKSB7DQoNCiAgYm9vbGVhbiBsb2FkZWQgPSBmYWxzZTsNCiAgDQogIGlmIChzZEluaXQpIHsNCiAgICBpZiAoU0QuZXhpc3RzKCJzZXR0aW5ncy50eHQiKSkgew0KICAgICAgRmlsZSBzZXR0aW5ncyA9IFNELm9wZW4oInNldHRpbmdzLnR4dCIpOw0KICAgICAgY2hhciBjOw0KICAgICAgaW50IHRmPTA7DQogICAgICBTdHJpbmcgbiA9ICIiOw0KICAgICAgd2hpbGUgKHRmPDIpIHsNCiAgICAgICAgYyA9IChjaGFyKSBzZXR0aW5ncy5yZWFkKCk7DQogICAgICAgIGlmIChjPT0nficpDQogICAgICAgICAgdGYrKzsNCiAgICAgICAgbiArPSBjOw0KICAgICAgfQ0KDQogICAgICB0ZiA9IDA7DQogICAgICBTdHJpbmcgZyA9ICIiOw0KICAgICAgd2hpbGUgKHRmPDIpIHsNCiAgICAgICAgYyA9IChjaGFyKSBzZXR0aW5ncy5yZWFkKCk7DQogICAgICAgIGlmIChjPT0nIScpDQogICAgICAgICAgdGYrKzsNCiAgICAgICAgZyArPSBjOw0KICAgICAgfQ0KDQogICAgICBpbnQgaT0wOw0KICAgICAgYnl0ZSBiOw0KICAgICAgd2hpbGUoc2V0dGluZ3MuYXZhaWxhYmxlKCkgJiYgaTxwYXJhbUxlbikgew0KICAgICAgICBiID0gKGJ5dGUpIHNldHRpbmdzLnJlYWQoKTsNCiAgICAgICAgcGFyYW1zW2krK10gPSBiOyAgDQogICAgICB9DQoNCiAgICAgIGxvYWRlZCA9IHRydWU7DQogICAgICBieXRlc1RvUGFyYW1zKCk7ICANCiAgICAgIA0KICAgICAgYm94TmFtZSA9IG4uc3Vic3RyaW5nKDEsbi5sZW5ndGgoKS0xKTsgICANCiAgICAgIGJveEd1aWxkID0gZy5zdWJzdHJpbmcoMSxnLmxlbmd0aCgpLTEpOyANCiAgICB9DQogIH0NCg0KDQogIHJldHVybiBsb2FkZWQ7DQogIA0KfQ0KDQp2b2lkIHBhcmFtc1RvQnl0ZXMoKSB7DQogICAgaW50IGk9MDsNCiAgICBieXRlICogYjsNCiAgICB1bmlvbiB7Ynl0ZSBiWzRdO2Zsb2F0IGY7fSB0ZW1wOw0KDQogICAgdGVtcC5mID0gbm5MZWFybmluZ0M7IHBhcmFtc1tpKytdID0gdGVtcC5iWzBdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsxXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzNdOw0KICAgIHRlbXAuZiA9IGdvb2RCb3hSYWRpdXM7IHBhcmFtc1tpKytdID0gdGVtcC5iWzBdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsxXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzNdOw0KICAgIHRlbXAuZiA9IG5uV2VpZ2h0c1swXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMF07IHBhcmFtc1tpKytdID0gdGVtcC5iWzFdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsyXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbM107DQogICAgdGVtcC5mID0gbm5XZWlnaHRzWzFdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlswXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMV07IHBhcmFtc1tpKytdID0gdGVtcC5iWzJdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlszXTsNCiAgICB0ZW1wLmYgPSBubldlaWdodHNbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzBdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsxXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMl07IHBhcmFtc1tpKytdID0gdGVtcC5iWzNdOw0KICAgIHRlbXAuZiA9IHdvcmtNb2RlQXZlcmFnZTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbMF07IHBhcmFtc1tpKytdID0gdGVtcC5iWzFdOyBwYXJhbXNbaSsrXSA9IHRlbXAuYlsyXTsgcGFyYW1zW2krK10gPSB0ZW1wLmJbM107DQogICAgYiA9IChieXRlICopICZ0cmFpbkN5Y2xlczsgcGFyYW1zW2krK10gPSBiWzBdOyBwYXJhbXNbaSsrXSA9IGJbMV07IHBhcmFtc1tpKytdID0gYlsyXTsgcGFyYW1zW2krK10gPSBiWzNdOw0KICAgIGIgPSAoYnl0ZSAqKSAmdG90YWxDb3JyZWN0OyBwYXJhbXNbaSsrXSA9IGJbMF07IHBhcmFtc1tpKytdID0gYlsxXTsgcGFyYW1zW2krK10gPSBiWzJdOyBwYXJhbXNbaSsrXSA9IGJbM107DQogICAgYiA9IChieXRlICopICZ0b3RhbFRyYWluaW5nRXhhbXBsZXM7IHBhcmFtc1tpKytdID0gYlswXTsgcGFyYW1zW2krK10gPSBiWzFdOyBwYXJhbXNbaSsrXSA9IGJbMl07IHBhcmFtc1tpKytdID0gYlszXTsNCiAgICBiID0gKGJ5dGUgKikgJndvcmtNb2RlQmVzdDsgcGFyYW1zW2krK10gPSBiWzBdOyBwYXJhbXNbaSsrXSA9IGJbMV07IHBhcmFtc1tpKytdID0gYlsyXTsgcGFyYW1zW2krK10gPSBiWzNdOw0KDQp9DQoNCnZvaWQgYnl0ZXNUb1BhcmFtcygpIHsNCiAgaW50IGk9MDsNCiAgdW5pb24ge2J5dGUgYls0XTtmbG9hdCBmO30gdGVtcDsNCiAgDQogIHRlbXAuYlswXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsxXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsyXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlszXSA9IChwYXJhbXNbaSsrXSk7DQogIG5uTGVhcm5pbmdDID0gdGVtcC5mOw0KICB0ZW1wLmJbMF0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMV0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMl0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbM10gPSAocGFyYW1zW2krK10pOw0KICBnb29kQm94UmFkaXVzID0gdGVtcC5mOw0KICB0ZW1wLmJbMF0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMV0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMl0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbM10gPSAocGFyYW1zW2krK10pOw0KICBubldlaWdodHNbMF0gPSB0ZW1wLmY7DQogIHRlbXAuYlswXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsxXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlsyXSA9IChwYXJhbXNbaSsrXSk7IHRlbXAuYlszXSA9IChwYXJhbXNbaSsrXSk7DQogIG5uV2VpZ2h0c1sxXSA9IHRlbXAuZjsNCiAgdGVtcC5iWzBdID0gKHBhcmFtc1tpKytdKTsgdGVtcC5iWzFdID0gKHBhcmFtc1tpKytdKTsgdGVtcC5iWzJdID0gKHBhcmFtc1tpKytdKTsgdGVtcC5iWzNdID0gKHBhcmFtc1tpKytdKTsNCiAgbm5XZWlnaHRzWzJdID0gdGVtcC5mOw0KICB0ZW1wLmJbMF0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMV0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbMl0gPSAocGFyYW1zW2krK10pOyB0ZW1wLmJbM10gPSAocGFyYW1zW2krK10pOw0KICB3b3JrTW9kZUF2ZXJhZ2UgPSB0ZW1wLmY7DQogIHRyYWluQ3ljbGVzID0gKGludCkoKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDApIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDgpIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDE2KSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCAyNCkpOw0KICB0b3RhbENvcnJlY3QgPSAoaW50KSgoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgMCkgfCAoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgOCkgfCAoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgMTYpIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDI0KSk7DQogIHRvdGFsVHJhaW5pbmdFeGFtcGxlcyA9IChpbnQpKCgocGFyYW1zW2krK10gJiAweGZmKSA8PCAwKSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCA4KSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCAxNikgfCAoKHBhcmFtc1tpKytdICYgMHhmZikgPDwgMjQpKTsNCiAgd29ya01vZGVCZXN0ID0gKGludCkoKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDApIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDgpIHwgKChwYXJhbXNbaSsrXSAmIDB4ZmYpIDw8IDE2KSB8ICgocGFyYW1zW2krK10gJiAweGZmKSA8PCAyNCkpOw0KfQ0KDQp2b2lkIHBsYXlJbnRyb1R1bmUoKSB7DQogIC8qDQogIGFtcE9uKCk7DQoNCiAgcGxheUR1YWxUb25lKDc1LCAxMDUsIDAuMSwgMTAwMDAwKTsNCiAgZGVsYXkoMTAwMCk7DQogIHBsYXlEdWFsVG9uZSg3NSwgMTA1LCAwLjMzLCAxMDAwMDApOw0KICBkZWxheSgxMDAwKTsNCiAgcGxheUR1YWxUb25lKDc1LCAxMDUsIDAuNjYsIDEwMDAwMCk7DQogIGRlbGF5KDEwMDApOw0KICBwbGF5RHVhbFRvbmUoNzUsIDEwNSwgMC45LCAxMDAwMDApOw0KICBkZWxheSgxMDAwKTsNCg0KICBhbXBPZmYoKTsNCiAgKi8NCn0NCg0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIHdlbGNvbWVNb2RlDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCnZvaWQgd2VsY29tZU1vZGUoKSB7DQoNCiAgdW5zaWduZWQgbG9uZyB3ZWxjb21lVGltZVN0YW1wOw0KDQogIGxjZC5jbGVhcigpOw0KDQogIGlmICghbG9hZGVkU2V0dGluZ3MpIHsNCiAgICBlbnRlck5hbWUoKTsNCiAgfQ0KDQogIGlmICghc2RJbml0KSB7IA0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgbGNkLnByaW50KCJTRCBDYXJkIGluaXQgZmFpbGVkISIpOw0KICAgIGRlbGF5KDUwMDApOw0KICB9IA0KICBsY2QuY2xlYXIoKTsNCg0KICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICBsY2QucHJpbnQoIkJveCBGYWN0b3J5ICAiICsgdmVyTnVtICsgIiAgICIpOw0KICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICBsY2QucHJpbnQoIkkgYW0gIiArIGJveE5hbWUpOw0KICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICBsY2QucHJpbnQoYm94R3VpbGQgKyAiIGd1aWxkIik7DQogIA0KDQogIHdlbGNvbWVUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCg0KICBpbnQgcHYgPSAwOw0KICBpZiAoYm94R3VpbGQgPT0gIlBIT0VOSVgiKQ0KICAgIHB2ID0gMTsNCiAgaWYgKGJveEd1aWxkID09ICJMSUdIVE5JTkciKQ0KICAgIHB2ID0gMjsNCg0KICBwbGF5SW50cm9UdW5lKCk7DQogIA0KICB3aGlsZSAoKG1pbGxpcygpIC0gd2VsY29tZVRpbWVTdGFtcCA8IDE1MDAwKSAmJiAoIWJ1dHRvblByZXNzZWQoYW55KSkpIHsNCg0KICAgIC8vIG5lZWQgdG8gY29weSB0aGlzIGlmIG1vZGRlZCB0byB3ZWxjb21lL3NldC1uYW1lDQogICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICB1aW50MzJfdCBjID0gbWF0cml4LkNvbG9yKDAsMCwwKTsNCiAgICAgICAgc3dpdGNoIChndWlsZEdseXBoc1twdl1beF1beV0pIHsNCiAgICAgICAgICBjYXNlICdSJzoNCiAgICAgICAgICAgIGMgPSBnUmVkOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnTyc6DQogICAgICAgICAgICBjID0gZ09yYW5nZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1knOg0KICAgICAgICAgICAgYyA9IGdZZWxsb3c7DQogICAgICAgICAgICBicmVhazsNCiAgICAgICAgICBjYXNlICdCJzoNCiAgICAgICAgICAgIGMgPSBnQmx1ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1QnOg0KICAgICAgICAgICAgYyA9IGdUZWFsOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnRyc6DQogICAgICAgICAgICBjID0gZ0dyZWVuOw0KICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgY2FzZSAnUCc6DQogICAgICAgICAgICBjID0gZ1B1cnBsZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJ1cnOg0KICAgICAgICAgICAgYyA9IGdXaGl0ZTsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGNhc2UgJyAnOg0KICAgICAgICAgICAgYyA9IGdCbGFjazsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIGRlZmF1bHQ6DQogICAgICAgICAgICBjID0gZ0JsYWNrOw0KICAgICAgICAgICAgYnJlYWs7ICANCiAgICAgICAgfQ0KICAgICAgICBtYXRyaXguZHJhd1BpeGVsKHkseCxjKTsNCiAgICAgIH0NCiAgICB9DQogICAgDQogICAgbWF0cml4LnNob3coKTsNCiAgDQogIH0NCiAgbWF0cml4LmZpbGxTY3JlZW4oMCk7DQogIG1vZGUgPSBtZW51Ow0KICAgIA0KfQ0KDQoNCg0Kdm9pZCBtYWluTWVudSgpIHsNCg0KICBwb25nTW9kZSA9IHBvbmdXYWl0Ow0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICBsZWRzLmNsZWFyKCk7DQogIGxlZHMuc2hvdygpOw0KICANCiAgbGNkLmNsZWFyKCk7DQogIG1lbnVDbGVhcigpOw0KICBtZW51QWRkSGVhZGluZygiLS0tLS1NQUlOLS1NRU5VLS0tLS0iKTsNCiAgZm9yIChpbnQgaT0wOyBpPG1haW5NZW51U2l6ZTsgaSsrKSB7DQogICAgbWVudUFkZEVudHJ5KGksIG1haW5NZW51RW50cmllc1tpXSk7DQogIH0NCg0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICBpbnQgbGFzdFNlbGVjdGVkID0gMDsNCiAgaW50IHNjdCA9IG1pbGxpcygpOw0KDQogIGJvb2xlYW4gYW5zd2VyZWQgPSBmYWxzZTsNCiAgDQogIHdoaWxlKCFhbnN3ZXJlZCkgew0KICAgIHNlbGVjdGVkID0gbWVudVVwZGF0ZSh0cnVlKTsNCiAgICBpZiAobGFzdFNlbGVjdGVkICE9IHNlbGVjdGVkKQ0KICAgICAgc2N0ID0gbWlsbGlzKCk7DQogICAgbGFzdFNlbGVjdGVkID0gc2VsZWN0ZWQ7DQogICAgaWYgKG1pbGxpcygpLXNjdCA+IHNjcmVlblNhdmVyVGltZSkgew0KICAgICAgc2NyZWVuU2F2ZXIoKTsNCiAgICAgIG1lbnVVcGRhdGVMQ0QgPSB0cnVlOw0KICAgICAgc2N0ID0gbWlsbGlzKCk7ICANCiAgICAgIG1hdHJpeC5jbGVhcigpOw0KICAgICAgbWF0cml4LnNob3coKTsNCiAgICAgIGxjZC5jbGVhcigpOw0KICAgIH0NCiAgICBpZiAoYnV0dG9uUHJlc3NlZChhbnkpICYmICFtZW51TG9ja3Nbc2VsZWN0ZWRdKQ0KICAgICAgYW5zd2VyZWQgPSB0cnVlOyANCiAgfQ0KICANCiAgc3dpdGNoIChzZWxlY3RlZCkgew0KICBjYXNlIDA6DQogICAgbW9kZSA9IGJyYWluc3RhdGU7DQogICAgcmV0dXJuOw0KICAgIGJyZWFrOw0KICBjYXNlIDE6DQogICAgbW9kZSA9IHRyYWluOw0KICAgIHJldHVybjsNCiAgICBicmVhazsNCiAgY2FzZSAyOg0KICAgIG1vZGUgPSB3b3JrOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgIA0KICBjYXNlIDM6DQogICAgbW9kZSA9IGZhY3Rvcnk7DQogICAgcmV0dXJuOw0KICAgIGJyZWFrOyANCiAgY2FzZSA0Og0KICAgIG1vZGUgPSBhbmFseXplOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgDQogIGNhc2UgNToNCiAgICBtb2RlID0gcG9uZzsNCiAgICByZXR1cm47DQogICAgYnJlYWs7IA0KICBjYXNlIDY6DQogICAgbW9kZSA9IHN5bnRoOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgDQogIGNhc2UgNzoNCiAgICBtb2RlID0gaW5zdHJ1Y3Rpb25zOw0KICAgIHJldHVybjsNCiAgICBicmVhazsgDQogIGNhc2UgODoNCiAgICBtb2RlID0gc2V0dGluZ3M7DQogICAgcmV0dXJuOw0KICAgIGJyZWFrOyANCiAgZGVmYXVsdDoNCiAgICBtb2RlID0gbWVudTsNCiAgICByZXR1cm47DQogICAgYnJlYWs7DQogIH0NCiAgDQp9DQoNCnZvaWQgd29ya01vZGUoKSB7DQoNCiAgaW50IGJveFNpemUgPSAwOw0KICBpbnQgYm94Q29sb3IgPSAwOw0KICB1bnNpZ25lZCBsb25nIG1ha2VCb3hUaW1lU3RhbXA7DQogIHVuc2lnbmVkIGxvbmcgYW5hbHl6ZUJveFRpbWVTdGFtcDsNCiAgdW5zaWduZWQgbG9uZyB0b25lVGltZVN0YW1wOw0KICBpbnQgdG9uZUR1cmF0aW9uOw0KICBpbnQgc2NvcmUgPSAwOw0KDQogIG1hdHJpeC5jbGVhcigpOw0KICBtYXRyaXguc2hvdygpOw0KICBsY2QuY2xlYXIoKTsNCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLS0tLVdPUkstLU1PREUtLS0tLSIpOw0KICBwYWdlQWRkRW50cnkoMCwiTXkgYnJhaW4gd2lsbCB3b3JrIik7DQogIHBhZ2VBZGRFbnRyeSgxLCJvbiBhIHNtYWxsIHNldCBvZiAxMCIpOw0KICBwYWdlQWRkRW50cnkoMiwiZXhhbXBsZXMgdG8gc2VlIGhvdyIpOw0KICBwYWdlQWRkRW50cnkoMywiaG93IHdlbGwgSSBjYW4gdGVsbCIpOw0KICBwYWdlQWRkRW50cnkoNCwidGhlIGRpZmZlcmVuZW5jZSIpOw0KICBwYWdlQWRkRW50cnkoNSwiYmV0d2VlbiBzbWFsbCBncmVlbiIpOw0KICBwYWdlQWRkRW50cnkoNiwiYm94ZXMgYW5kIGxhcmdlIHJlZCIpOw0KICBwYWdlQWRkRW50cnkoNywiYm94ZXMuIik7DQoNCiAgaW50IHNlbGVjdGVkID0gMDsNCiAgc2VsZWN0ZWQgPSBwYWdlVXBkYXRlKCk7DQoNCiAgYm9vbGVhbiBhbnN3ZXJlZCA9IGZhbHNlOw0KICB3aGlsZSghYW5zd2VyZWQpIHsNCiAgICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCiAgICBpZiAoYnV0dG9uUHJlc3NlZChyZWQpKSB7DQogICAgICBtb2RlID0gbWVudTsNCiAgICAgIHJldHVybjsgDQogICAgfQ0KICAgIGlmIChidXR0b25QcmVzc2VkKGJsdWUpIHx8IGJ1dHRvblByZXNzZWQoZ3JlZW4pIHx8IGJ1dHRvblByZXNzZWQoam95KSkgew0KICAgICAgYW5zd2VyZWQgPSB0cnVlOw0KICAgIH0NCiAgfQ0KDQogIGRlbGF5KDUwMCk7DQoNCiAgZm9yIChpbnQgaj0wOyBqPDEwOyBqKyspIHsNCg0KICAgIGxjZC5jbGVhcigpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgbGNkLnByaW50KCJNYWtpbmcgYSBzYW1wbGUgYm94Iik7DQogICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICBsY2QucHJpbnQoIlBsZWFzZSB3YWl0Li4uLi4iKTsNCg0KICAgIG1ha2VCb3hUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCiAgICB0b25lVGltZVN0YW1wID0gMDsNCg0KICAgIGludCBib3hUeXBlID0gMDsNCiAgICBmbG9hdCB4cyA9IDA7DQogICAgZmxvYXQgeXMgPSAwOw0KICAgIA0KICAgIGFtcE9uKCk7DQogICAgd2hpbGUgKG1pbGxpcygpIC0gbWFrZUJveFRpbWVTdGFtcCA8IG1ha2VCb3hEdXJhdGlvbikgew0KDQogICAgICBtYXRyaXguY2xlYXIoKTsNCg0KICAgICAgZmxvYXQgeCA9IG1pbGxpcygpIC0gbWFrZUJveFRpbWVTdGFtcDsNCiAgICAgIHggPSAoKHgtbWFrZUJveER1cmF0aW9uQnkyKS9tYWtlQm94RHVyYXRpb25CeTIpKjY7DQogICAgICBmbG9hdCBzQ3VydmUgPSAxLygxK2V4cCgteCoxLjMpKTsNCiAgICAgIGludCBzcGFya2xlUHJvYiA9IChpbnQpIChzQ3VydmUgKiAzMDApOw0KICAgICAgc0N1cnZlID0gMS8oMStleHAoLXgqMS4wKSk7DQogICAgICBpbnQgYm94UmF0ZSA9IChpbnQpIChzQ3VydmUgKiAyMDApICsgMzA7DQoNCiAgICAgIGRyYXdCb3goYm94U2l6ZSwgYm94Q29sb3IsIGZhbHNlKTsNCiAgDQogICAgICBmb3IgKGludCBpPTA7IGk8NjQ7IGkrKykgew0KICAgICAgICBpbnQgeCA9IHJhbmRvbSg4KTsNCiAgICAgICAgaW50IHkgPSByYW5kb20oOCk7DQogICAgICAgIGludCBiID0gcmFuZG9tKDEyOCk7DQogICAgICAgIHVpbnQxNl90IFJHQiA9IG1hdHJpeC5Db2xvcigwLCAwLCBiKTsNCiAgICAgICAgaWYgKHJhbmRvbShzcGFya2xlUHJvYikgPT0gMCkNCiAgICAgICAgICBtYXRyaXguZHJhd1BpeGVsKHgsIHksIFJHQik7DQogICAgICB9DQoNCiAgICAgIGlmIChtaWxsaXMoKSAtIHRvbmVUaW1lU3RhbXAgPiB0b25lRHVyYXRpb24pIHsgDQogICAgICAgIHRvbmVUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCiAgICAgICAgdG9uZUR1cmF0aW9uID0gYm94UmF0ZTsNCiAgICAgICAgcGxheVRvbmUocmFuZG9tKDYwKSs2MCx0b25lRHVyYXRpb24pOw0KICAgICAgICB0b25lRHVyYXRpb24gPSB0b25lRHVyYXRpb24gKiAxLjM7DQogICAgICAgIA0KICAgICAgICBib29sZWFuIHZhbGlkID0gZmFsc2U7DQogICAgICANCiAgICAgICAgd2hpbGUoIXZhbGlkKSB7DQogICAgICAgICAgeHMgPSByYW5kb20oMjYsIGNNYXgqMik7DQogICAgICAgICAgeXMgPSByYW5kb20oMCwgY01heCoyKTsgICAgDQogICAgICAgICAgZmxvYXQgdkRpc3QgPSBzcXJ0KCh4cyp4cykgKyAoeXMqeXMpKTsNCiAgICAgICAgICBpZiAodkRpc3QgPCAoZ29vZEJveFJhZGl1cypjTWF4KSkgew0KICAgICAgICAgICAgaW50IGJjID0gKGludCkgcmFuZG9tKDIpOw0KICAgICAgICAgICAgaWYgKGJjPT0xKSB7DQogICAgICAgICAgICAgIHhzIC09IGNNYXg7DQogICAgICAgICAgICAgIHlzIC09IGNNYXg7DQogICAgICAgICAgICAgIGJveFR5cGUgPSAtMTsNCiAgICAgICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgICAgIGZsb2F0IHR4cyA9IHhzOw0KICAgICAgICAgICAgICB4cyA9ICh5cyotMSkrY01heDsNCiAgICAgICAgICAgICAgeXMgPSAodHhzKi0xKStjTWF4Ow0KICAgICAgICAgICAgICBib3hUeXBlID0gMTsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIHZhbGlkID0gdHJ1ZTsgIA0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KDQogICAgICAgIGJveFNpemUgPSAoKHhzK2NNYXgpLyhjTWF4KjIpKSozMTsNCiAgICAgICAgYm94Q29sb3IgPSAoKCh5cytjTWF4KS8oY01heCoyKSkqMTI3KSszMjsNCiAgICAgIH0gLy8gaWYgZm9yIG1ha2luZyB0b25lLg0KICAgICAgDQogICAgICBtYXRyaXguc2hvdygpOw0KICAgICAgICAgICAgDQogICAgfSAvLyB3aGlsZQ0KICAgIA0KICAgIGFtcE9mZigpOw0KICAgIGNsZWFyVG9uZSgpOw0KDQogICAgLy8gZXZhbCBib3gNCiAgICBkcmF3Qm94KGJveFNpemUsIGJveENvbG9yLCB0cnVlKTsNCg0KICAgIGxjZC5jbGVhcigpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgbGNkLnByaW50KCJBbmFseWl6aW5nIGJveCIpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgbGNkLnByaW50KCJQbGVhc2Ugd2FpdC4uLiIpOw0KDQogICAgaW50IHByZWRpY3Rpb24gPSBubkZlZWRGb3J3YXJkKHhzLCB5cyk7DQogICAgU3RyaW5nIHByZWRpY3Rpb25EZXNjID0gIlNNQUxMIEdSRUVOIGJveD8iOw0KICAgIGlmIChwcmVkaWN0aW9uID09IDEpIA0KICAgICAgcHJlZGljdGlvbkRlc2MgPSAiTEFSR0UgUkVEIGJveD8iOw0KDQogICAgZGVsYXkoMjUwKTsNCiAgICBhbmFseXplQm94VGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgdG9uZVRpbWVTdGFtcCA9IG1pbGxpcygpOw0KICAgIHRvbmVEdXJhdGlvbiA9IDEwMDsNCg0KDQogICAgYW1wT24oKTsNCiAgICB3aGlsZSAobWlsbGlzKCkgLSBhbmFseXplQm94VGltZVN0YW1wIDwgYW5hbHl6ZUJveER1cmF0aW9uKSB7DQogICAgICBpZiAobWlsbGlzKCkgLSB0b25lVGltZVN0YW1wID4gdG9uZUR1cmF0aW9uICogMS4zKSB7IA0KICAgICAgICB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICAgIHBsYXlUb25lKHJhbmRvbSg0MCkrMzAsIHRvbmVEdXJhdGlvbik7DQogICAgICB9IC8vIGlmIGZvciBtYWtpbmcgdG9uZS4gICAgICAgICANCiAgICB9IC8vIHdoaWxlDQogICAgYW1wT2ZmKCk7DQogICAgY2xlYXJUb25lKCk7DQoNCiAgICAvLyBydW4gTk4NCiAgICAvLyBzaG93IHJlc3VsdCAgICAgDQogICAgbGNkLmNsZWFyKCk7DQogICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICBsY2QucHJpbnQoIkkgdGhpbmsgdGhpcyBib3ggaXMgIik7DQogICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICBsY2QucHJpbnQoImEgIik7DQogICAgbGNkLnNldEN1cnNvcigyLCAxKTsNCiAgICBsY2QucHJpbnQocHJlZGljdGlvbkRlc2MpOw0KDQogICAgYW1wT24oKTsNCiAgICBpZihwcmVkaWN0aW9uID09IGJveFR5cGUpIHsNCiAgICAgIHNjb3JlKys7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KCItLS0tLS1DT1JSRUNULS0tLS0tLSIpOyAgDQogICAgICBwbGF5VG9uZSg2OCwyNTApOw0KICAgICAgZGVsYXkoMzAwKTsNCiAgICAgIHBsYXlUb25lKDY4LDE1MCk7DQogICAgICBkZWxheSgxODApOw0KICAgICAgcGxheVRvbmUoODAsMTAwMCk7DQogICAgICBkZWxheSgxMzAwKTsNCiAgICB9IGVsc2Ugew0KICAgICAgbGNkLnNldEN1cnNvcigwLCAzKTsNCiAgICAgIGxjZC5wcmludCgiLS0tLS0tLS1XUk9ORy0tLS0tLS0iKTsgIA0KICAgICAgcGxheVRvbmUoNjIsMzAwKTsNCiAgICAgIGRlbGF5KDM5MCk7DQogICAgICBwbGF5VG9uZSg1NiwzMDApOw0KICAgICAgZGVsYXkoMzkwKTsNCiAgICAgIHBsYXlUb25lKDQ1LDEwMDApOw0KICAgICAgZGVsYXkoMTMwMCk7ICANCiAgICB9DQogICAgYW1wT2ZmKCk7DQogICAgY2xlYXJUb25lKCk7DQogICAgZGVsYXkoMTAwMCk7DQogICANCiAgfQ0KDQogIC8vIHNob3cgcmVzdWx0ICAgICANCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIldvcmsgUmVzdWx0czoiKSk7ICAgDQogIGxjZC5zZXRDdXJzb3IoMCwgMik7DQogIFN0cmluZyBmaW5hbFNjb3JlID0gIiI7DQogIGlmIChzY29yZSA8IDEwKQ0KICAgIGZpbmFsU2NvcmUgKz0gIjAiICsgU3RyaW5nKHNjb3JlKTsNCiAgZWxzZQ0KICAgIGZpbmFsU2NvcmUgKz0gU3RyaW5nKHNjb3JlKTsNCiAgZmluYWxTY29yZSArPSAiLzEwIjsNCiAgICANCiAgbGNkLnByaW50KHBhZFN0cmluZygyMCxmaW5hbFNjb3JlKSk7IA0KICBkZWxheSgzMDAwKTsNCg0KICB0b3RhbENvcnJlY3QgKz0gc2NvcmU7DQogIHRvdGFsVHJhaW5pbmdFeGFtcGxlcyArPSAxMDsNCg0KICB3b3JrTW9kZUF2ZXJhZ2UgPSAxMDAgKiAoKGZsb2F0KXRvdGFsQ29ycmVjdCAvIChmbG9hdCl0b3RhbFRyYWluaW5nRXhhbXBsZXMpOw0KICANCiAgaWYgKHNjb3JlID4gd29ya01vZGVCZXN0KQ0KICAgIHdvcmtNb2RlQmVzdCA9IHNjb3JlOw0KDQogIGlmIChzY29yZSA9PSAxMCkNCiAgICBtZW51TG9ja3NbcG9uZ0xvY2tdID0gMDsgDQoNCiAgYW1wT2ZmKCk7DQoNCiAgbG9nU2V0dGluZ3MoKTsNCiAgDQogIG1vZGUgPSBicmFpbnN0YXRlOw0KDQp9DQoNCnZvaWQgdHJhaW5Nb2RlKCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBtYXRyaXguY2xlYXIoKTsNCiAgbWF0cml4LnNob3coKTsNCiAgcGFnZUNsZWFyKCk7DQogIHBhZ2VBZGRIZWFkaW5nKCItLS1UUkFJTklORy0tTU9ERS0tLSIpOw0KICBwYWdlQWRkRW50cnkoMCwiVXNlIHRoZSBkaWFscyB0byIpOw0KICBwYWdlQWRkRW50cnkoMSwibWFrZSBmaXZlIGNvbG9yZWQiKTsNCiAgcGFnZUFkZEVudHJ5KDIsImJveGVzIGFzIGV4YW1wbGVzIHRvIik7DQogIHBhZ2VBZGRFbnRyeSgzLCJ0ZWFjaCBteSBicmFpbi4iKTsNCiAgcGFnZUFkZEVudHJ5KDQsIkl0IHdpbGwgaGVscCBtZSIpOw0KICBwYWdlQWRkRW50cnkoNSwibGVhcm4gaWYgeW91IHVzZSIpOw0KICBwYWdlQWRkRW50cnkoNiwid2VsbCB0aG91Z2h0LW91dCIpOw0KICBwYWdlQWRkRW50cnkoNywiZXhhbXBsZXMuICAiKTsNCiAgcGFnZUFkZEVudHJ5KDgsIkkgd2lsbCBndWVzcyB3aGF0Iik7DQogIHBhZ2VBZGRFbnRyeSg5LCJ0aGUgYm94ZXMgYXJlLCBhbmQgIik7DQogIHBhZ2VBZGRFbnRyeSgxMCwibGVhcm4gZnJvbSBteSAiKTsNCiAgcGFnZUFkZEVudHJ5KDExLCJtaXN0YWtlcy4iKTsNCg0KICBpbnQgc2NvcmUgPSAwOw0KICAgIA0KICBpbnQgc2VsZWN0ZWQgPSAwOw0KICBzZWxlY3RlZCA9IHBhZ2VVcGRhdGUoKTsNCiAgDQogIGJvb2xlYW4gYW5zd2VyZWQgPSBmYWxzZTsNCiAgd2hpbGUoIWFuc3dlcmVkKSB7DQogICAgc2VsZWN0ZWQgPSBwYWdlVXBkYXRlKCk7DQogICAgaWYgKGJ1dHRvblByZXNzZWQocmVkKSkgew0KICAgICAgbW9kZSA9IG1lbnU7DQogICAgICByZXR1cm47IA0KICAgIH0NCiAgICBpZiAoYnV0dG9uUHJlc3NlZChibHVlKSB8fCBidXR0b25QcmVzc2VkKGdyZWVuKSB8fCBidXR0b25QcmVzc2VkKGpveSkpIHsNCiAgICAgIGFuc3dlcmVkID0gdHJ1ZTsNCiAgICB9DQogIH0NCiANCiAgZm9yIChpbnQgaT0wOyBpPDU7IGkrKykgew0KDQogICAgbGNkLmNsZWFyKCk7DQogICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJVc2UgdGhlIGRpYWxzIHRvIikpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwibWFrZSBhIGJveC4iKSk7IA0KICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiUHJlc3MgYmx1ZSB3aGVuIGRvbmUuIikpOyAgICAgDQogICAgDQogICAgZmxvYXQgeHMgPSAwOw0KICAgIGZsb2F0IHlzID0gMDsNCiAgICBpbnQgZXJyb3IgPSAwOw0KDQogICAgLy8gbWFrZSBhIGJveCB1bnRpbCB0aGUgYmx1ZSBidXR0b24gaXMgcHVzaGVkDQogICAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYmx1ZSkpIHsNCiAgICAgIHhzID0gKCgoZmxvYXQpYW5hbG9nUmVhZChwb3RMZWZ0KSAvIDUxMS41KS0xLjApKmNNYXg7DQogICAgICBpZiAoeHMgPCAtMzc0KSB4cyA9IC0zNzQ7DQogICAgICB5cyA9ICgoKGZsb2F0KWFuYWxvZ1JlYWQocG90UmlnaHQpIC8gNTExLjUpLTEuMCkqY01heDsNCiAgICAgIGludCBib3hTaXplID0gKCh4cytjTWF4KS8oY01heCoyKSkqMzE7DQogICAgICBpbnQgYm94Q29sb3IgPSAoKCh5cytjTWF4KS8oY01heCoyKSkqMTI3KSszMjsNCiAgICAgIGRyYXdCb3goYm94U2l6ZSwgYm94Q29sb3IsIHRydWUpOw0KICAgICAgaW50IHByZWRpY3Rpb24gPSBubkZlZWRGb3J3YXJkKHhzLCB5cyk7IC8vIHJ1biBhIHNuZWFreSBwcmVkaWN0aW9uIA0KICAgICAgLy8gcHJlZGljdGlvbiAxID0gbGFyZ2UgcmVkICAgIC0xID0gc21hbGwgZ3JlZW4NCiAgICAgIHVpbnQzMl90IGxlZFJHQiA9IGxlZHMuQ29sb3IoOCwwLDApOw0KICAgICAgaWYgKHByZWRpY3Rpb24gPT0gLTEpDQogICAgICAgIGxlZFJHQiA9IGxlZHMuQ29sb3IoMCw4LDApOyANCiAgICAgIGxlZHMuc2V0UGl4ZWxDb2xvcigwLCBsZWRSR0IpOw0KICAgICAgbGVkcy5zaG93KCk7DQoNCiAgICB9DQoNCiAgICAvLyBydW4gdGhlIG5ldXJhbCBuZXQgZm9yd2FyZA0KICAgIGludCBwcmVkaWN0aW9uID0gbm5GZWVkRm9yd2FyZCh4cywgeXMpOyANCiAgICAvLyBwcmVkaWN0aW9uIDEgPSBsYXJnZSByZWQgICAgLTEgPSBzbWFsbCBncmVlbg0KDQogICAgYm9vbGVhbiBhbnN3ZXJlZCA9IGZhbHNlOw0KICAgIHdoaWxlKCFhbnN3ZXJlZCkgew0KICAgICANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJXaGF0IHR5cGUgb2YgYm94IikpOyANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJpcyB0aGlzPyIpKTsgDQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiR3JlZW4gPSBzbWFsbCBncmVlbi4iKSk7ICANCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMyk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJSZWQgPSBsYXJnZSByZWQuIikpOyANCg0KICAgICAgaWYgKGJ1dHRvblByZXNzZWQocmVkKSkgew0KICAgICAgICBhbnN3ZXJlZCA9IHRydWU7DQogICAgICAgIGVycm9yID0gMSAtIHByZWRpY3Rpb247IA0KICAgICAgfSBlbHNlIGlmIChidXR0b25QcmVzc2VkKGdyZWVuKSkgew0KICAgICAgICBhbnN3ZXJlZCA9IHRydWU7DQogICAgICAgIGVycm9yID0gLTEgLSBwcmVkaWN0aW9uOw0KICAgICAgfSAgICAgIA0KICAgICAgICANCiAgICB9DQoNCiAgICBsY2QuY2xlYXIoKTsNCg0KICAgIGlmIChlcnJvciAhPSAwKSB7DQogIA0KICAgICAgbm5BZGp1c3RXZWlnaHRzKHhzLCB5cywgZXJyb3IpOw0KDQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCx0cmFpbldyb25nW3JhbmRvbSg1KV0pKTsNCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBpZiAocHJlZGljdGlvbiA9PSAtMSkNCiAgICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiYSBzbWFsbCBncmVlbiBib3giKSk7DQogICAgICBlbHNlDQogICAgICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsImEgbGFyZ2VyIHJlZCBib3giKSk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiQXBwbHlpbmcgbGVhcm5pbmcuLi4iKSk7DQogICAgICAgDQogICAgICB1bnNpZ25lZCBsb25nIGxlYXJuaW5nVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICB1bnNpZ25lZCBsb25nIHRvbmVUaW1lU3RhbXAgPSBtaWxsaXMoKTsNCiAgICAgIGludCB0b25lRHVyYXRpb24gPSAxMDA7DQogICAgICANCiAgICAgIGFtcE9uKCk7DQogICAgICB3aGlsZSAobWlsbGlzKCkgLSBsZWFybmluZ1RpbWVTdGFtcCA8IHRyYWluQm94RHVyYXRpb24pIHsNCiAgICAgICAgaWYgKG1pbGxpcygpIC0gdG9uZVRpbWVTdGFtcCA+IHRvbmVEdXJhdGlvbiAqIDEuMykgeyANCiAgICAgICAgICB0b25lVGltZVN0YW1wID0gbWlsbGlzKCk7DQogICAgICAgICAgcGxheVRvbmUocmFuZG9tKDQwKSszMCwgdG9uZUR1cmF0aW9uKTsNCiAgICAgICAgfSAvLyBpZiBmb3IgbWFraW5nIHRvbmUuICAgICAgICAgDQogICAgICB9IC8vIHdoaWxlDQogICAgICAgICANCiAgICAgIGFtcE9mZigpOw0KICAgICAgY2xlYXJUb25lKCk7DQogICAgICBzY29yZSsrOw0KDQogICAgfSBlbHNlIHsNCiAgICAgIA0KICAgICAgbGNkLmNsZWFyKCk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCx0cmFpbkNvcnJlY3RbcmFuZG9tKDUpXSkpOw0KICAgICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICAgIGlmIChwcmVkaWN0aW9uID09IC0xKQ0KICAgICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCJhIGdyZWVuIGJveCIpKTsNCiAgICAgIGVsc2UNCiAgICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiYSByZWQgYm94IikpOw0KICAgICAgDQogICAgICB1bnNpZ25lZCBsb25nIGxlYXJuaW5nVGltZVN0YW1wID0gbWlsbGlzKCk7ICAgICAgDQogICAgICB3aGlsZSAobWlsbGlzKCkgLSBsZWFybmluZ1RpbWVTdGFtcCA8IHRyYWluQm94RHVyYXRpb24pIHsNCiAgICAgIH0gLy8gd2hpbGUNCiAgICB9DQogIH0NCg0KICB0cmFpbkN5Y2xlcysrOyANCg0KICBsb2dTZXR0aW5ncygpOw0KICANCiAgbW9kZSA9IGJyYWluc3RhdGU7DQoNCiAgaWYgKHNjb3JlPT01KSANCiAgICBtZW51TG9ja3Nbc3ludGhMb2NrXSA9IDA7DQogIA0KICByZXR1cm47DQogIA0KfQ0KDQp2b2lkIGRyYXdCb3goaW50IGJveFNpemUsIGludCBib3hDb2xvciwgYm9vbGVhbiBkcmF3SW1tZWRpYXRlKXsNCiAgDQogIGludCBib3hTaXplSW50ID0gYm94U2l6ZSA+PiAyOw0KICBpbnQgYm94U2l6ZUZyYWMgPSBib3hTaXplICYgMzsNCiAgaW50IHIgPSBib3hDb2xvcjsNCiAgaW50IGcgPSAxNjAtYm94Q29sb3I7DQogIGludCBiID0gMDsNCiAgICANCiAgLy9pZiAoYm94U2l6ZSA+IDE2KSB7DQogIC8vciA9IDk2LWNvbFZhbDsNCiAgLy9nID0gMDsNCiAgLy9iID0gY29sVmFsOw0KICAvL30NCiAgDQogIHVpbnQxNl90IGJveENvbG9yUkdCID0gbWF0cml4LkNvbG9yKHIsIGcsIGIpOw0KDQogIGlmIChkcmF3SW1tZWRpYXRlKQ0KICAgIG1hdHJpeC5jbGVhcigpOw0KICANCiAgZm9yIChpbnQgeD0wOyB4PGJveFNpemVJbnQ7IHgrKykgew0KICAgIGZvciAoaW50IHk9MDsgeTxib3hTaXplSW50OyB5KyspIHsNCiAgICAgIG1hdHJpeC5kcmF3UGl4ZWwoeCwgNy15LCBib3hDb2xvclJHQik7DQogICAgfSAgIA0KICB9DQoNCiAgaWYgKGJveFNpemVGcmFjID09IDApIHsNCiAgICByID0gMDsNCiAgICBnID0gMDsNCiAgICBiID0gMDsNCiAgfQ0KICBpZiAoYm94U2l6ZUZyYWMgPT0gMSkgew0KICAgIHIgPSByID4+IDI7DQogICAgZyA9IGcgPj4gMjsNCiAgICBiID0gYiA+PiAyOw0KICB9DQogIGlmIChib3hTaXplRnJhYyA9PSAyKSB7DQogICAgciA9IHIgPj4gMTsNCiAgICBnID0gZyA+PiAxOw0KICAgIGIgPSBiID4+IDE7DQogIH0NCiAgaWYgKGJveFNpemVGcmFjID09IDMpIHsNCiAgICByID0gKHIgPj4gMSkgKyAociA+PiAyKTsNCiAgICBnID0gKGcgPj4gMSkgKyAoZyA+PiAyKTsNCiAgICBiID0gKGIgPj4gMSkgKyAoYiA+PiAyKTsNCiAgfQ0KICBib3hDb2xvclJHQiA9IG1hdHJpeC5Db2xvcihyLCBnLCBiKTsNCiAgICANCiAgZm9yIChpbnQgeT0wOyB5PGJveFNpemVJbnQ7IHkrKykgew0KICAgIG1hdHJpeC5kcmF3UGl4ZWwoYm94U2l6ZUludCwgNy15LCBib3hDb2xvclJHQik7DQogIH0NCiAgZm9yIChpbnQgeD0wOyB4PD1ib3hTaXplSW50OyB4KyspIHsNCiAgICBtYXRyaXguZHJhd1BpeGVsKHgsIDctYm94U2l6ZUludCwgYm94Q29sb3JSR0IpOw0KICB9ICAgICANCg0KICBpZiAoZHJhd0ltbWVkaWF0ZSkNCiAgICBtYXRyaXguc2hvdygpOw0KDQp9DQoNCg0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQovLyBwb3RWYWx1ZQ0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQppbnQgcG90VmFsdWUocG90UG9zdGlvbiB3aGljaFBvdCwgZmxvYXQgc2NhbGUpIHsNCiAgaW50IHZhbHVlID0gLTE7DQogIHN3aXRjaCAod2hpY2hQb3QpIHsNCiAgICBjYXNlIGxlZnQ6ICAgDQogICAgICB2YWx1ZSA9IGFuYWxvZ1JlYWQocG90TGVmdCk7DQogICAgICBicmVhazsNCiAgICBjYXNlIHJpZ2h0Og0KICAgICAgdmFsdWUgPSBhbmFsb2dSZWFkKHBvdFJpZ2h0KTsgDQogICAgICBicmVhazsNCiAgICBjYXNlIGNlbnRlcjoNCiAgICAgIHZhbHVlID0gYW5hbG9nUmVhZChwb3RDZW50ZXIpOw0KICAgICAgYnJlYWs7DQogIH0NCiAgdmFsdWUgPSAoaW50KSB2YWx1ZSAqIHNjYWxlOw0KICByZXR1cm4gdmFsdWU7DQp9DQoNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KLy8gYnV0dG9uUHJlc3NlZA0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQpib29sZWFuIGJ1dHRvblByZXNzZWQoYnV0dG9uQ29sb3Igd2hpY2hCdXR0b24pIHsNCiAgaW50IGpveVByZXNzID0gZGlnaXRhbFJlYWQoam95QnV0dG9uKTsNCiAgaW50IGdyZWVuUHJlc3MgPSBkaWdpdGFsUmVhZChncmVlbkJ1dHRvbik7DQogIGludCBibHVlUHJlc3MgPSBkaWdpdGFsUmVhZChibHVlQnV0dG9uKTsNCiAgaW50IHJlZFByZXNzID0gZGlnaXRhbFJlYWQocmVkQnV0dG9uKTsNCiAgYm9vbGVhbiBwcmVzc2VkID0gZmFsc2U7DQoNCiAgc3dpdGNoICh3aGljaEJ1dHRvbikgew0KICAgIGNhc2UgYmx1ZToNCiAgICAgIGlmIChibHVlUHJlc3MgPT0gMCkNCiAgICAgICAgcHJlc3NlZCA9IHRydWU7DQogICAgICBicmVhazsNCiAgICBjYXNlIHJlZDoNCiAgICAgIGlmIChyZWRQcmVzcyA9PSAwKQ0KICAgICAgICBwcmVzc2VkID0gdHJ1ZTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2Ugam95Og0KICAgICAgaWYgKGpveVByZXNzID09IDApDQogICAgICAgIHByZXNzZWQgPSB0cnVlOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBncmVlbjoNCiAgICAgIGlmIChncmVlblByZXNzID09IDApDQogICAgICAgIHByZXNzZWQgPSB0cnVlOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBhbnk6DQogICAgICBpZiAoKGJsdWVQcmVzcyA9PSAwKSB8fCAocmVkUHJlc3MgPT0gMCkgfHwgKGpveVByZXNzID09IDApIHx8IChncmVlblByZXNzID09IDApKQ0KICAgICAgICBwcmVzc2VkID0gdHJ1ZTsNCiAgICAgIGJyZWFrOw0KICAgIGRlZmF1bHQ6DQogICAgICBwcmVzc2VkID0gZmFsc2U7DQogIH0NCg0KICB1bnNpZ25lZCBsb25nIHRpbWVTaW5jZSA9IG1pbGxpcygpIC0gbGFzdFByZXNzZWQ7DQogIGlmICgocHJlc3NlZCkgJiYgKHRpbWVTaW5jZSA8IGJ1dHRvblJlbGVhc2VEZWxheSkpIHsNCiAgICBsYXN0UHJlc3NlZCA9IG1pbGxpcygpOw0KICAgIHByZXNzZWQgPSBmYWxzZTsNCiAgfSBlbHNlIGlmIChwcmVzc2VkKSB7DQogICAgbGFzdFByZXNzZWQgPSBtaWxsaXMoKTsNCiAgfQ0KDQogIHJldHVybiBwcmVzc2VkOw0KICANCn0NCg0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQovLyBzZXRORU9TY3JvbGxNZXNzYWdlDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCnZvaWQgc2V0TkVPU2Nyb2xsTWVzc2FnZShTdHJpbmcgbWVzc2FnZSwgdWludDE2X3QgY29sb3IpIHsNCiAgc2Nyb2xsTkVPTWVzc2FnZSA9IG1lc3NhZ2U7DQogIHNjcm9sbE5FT01pbGxpU2VjID0gbWlsbGlzKCk7DQogIHNjcm9sbE5FT01lc3NhZ2VSZXNldCA9IC02ICogc2Nyb2xsTkVPTWVzc2FnZS5sZW5ndGgoKTsNCiAgc2Nyb2xsTkVPTWVzc2FnZVBvcyA9IG1hdHJpeC53aWR0aCgpOw0KICBzY3JvbGxORU9Db2xvciA9IGNvbG9yOw0KfQ0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIHVwZGF0ZU5FT1Njcm9sbE1lc3NhZ2UNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0Kdm9pZCB1cGRhdGVORU9TY3JvbGxNZXNzYWdlKCl7DQogIGlmIChtaWxsaXMoKS1zY3JvbGxORU9NaWxsaVNlYyA+IE5FT3Njcm9sbFNwZWVkKSB7DQogICAgbWF0cml4LmZpbGxTY3JlZW4oMCk7DQogICAgbWF0cml4LnNldEN1cnNvcihzY3JvbGxORU9NZXNzYWdlUG9zLCAwKTsNCiAgICBtYXRyaXguc2V0VGV4dENvbG9yKHNjcm9sbE5FT0NvbG9yKTsNCiAgICBtYXRyaXgucHJpbnQoc2Nyb2xsTkVPTWVzc2FnZSk7DQogICAgaWYoLS1zY3JvbGxORU9NZXNzYWdlUG9zIDwgc2Nyb2xsTkVPTWVzc2FnZVJlc2V0KSB7DQogICAgICBzY3JvbGxORU9NZXNzYWdlUG9zID0gbWF0cml4LndpZHRoKCk7DQogICAgfQ0KICAgIG1hdHJpeC5zaG93KCk7DQogICAgc2Nyb2xsTkVPTWlsbGlTZWMgPSBtaWxsaXMoKTsNCiAgfQ0KfQ0KDQovLyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCi8vIG5uRmVlZEZvcndhcmQNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KaW50IG5uRmVlZEZvcndhcmQoZmxvYXQgeHMsIGZsb2F0IHlzKSB7DQogIGZsb2F0IHN1bSA9IDA7DQogIGZsb2F0IGlucHV0c1szXTsNCiAgaW5wdXRzWzBdID0geHM7IA0KICBpbnB1dHNbMV0gPSB5czsNCiAgaW5wdXRzWzJdID0gMS4wOw0KICBmb3IgKGludCBpPTA7IGk8MzsgaSsrKSB7DQogICAgc3VtICs9IGlucHV0c1tpXSAqIG5uV2VpZ2h0c1tpXTsgIA0KICB9DQogIHJldHVybiBubkFjdGl2YXRlKHN1bSk7DQp9DQoNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KLy8gbm5BY3RpdmF0ZQ0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQppbnQgbm5BY3RpdmF0ZShmbG9hdCBzdW0pew0KICBpZiAoc3VtPjApIHJldHVybiAxOw0KICBlbHNlIHJldHVybiAtMTsNCn0NCg0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQovLyBubkFkanVzdFdlaWdodHMNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KaW50IG5uQWRqdXN0V2VpZ2h0cyhmbG9hdCB4cywgZmxvYXQgeXMsIGludCBlcnJvcikgew0KICBmbG9hdCBpbnB1dHNbM107DQogIGlucHV0c1swXSA9IHhzOyANCiAgaW5wdXRzWzFdID0geXM7DQogIGlucHV0c1syXSA9IDEuMDsNCiAgZm9yIChpbnQgaT0wOyBpPDM7IGkrKykgew0KICAgIG5uV2VpZ2h0c1tpXSArPSBubkxlYXJuaW5nQyAqIChmbG9hdCllcnJvciAqIGlucHV0c1tpXTsgICAgICAgICANCiAgfQ0KfQ0KDQppbnQgbWVudVVwZGF0ZShib29sZWFuIHNob3dJY29ucykgew0KDQogIGlmIChtaWxsaXMoKSAtIGxhc3RSZWFkID4gMTUwKSB7DQogICAgaW50IHYgPSBhbmFsb2dSZWFkKGpveVYpOw0KDQogICAgcG9zTGFzdCA9IHBvc05vdzsNCiAgICANCiAgICBpZiAodiA+IDgwMCkNCiAgICAgIHBvc05vdyA9IGRvd247DQogICAgZWxzZSBpZiAodiA8IDMwMCkNCiAgICAgIHBvc05vdyA9IHVwOw0KICAgIGVsc2UgaWYgKHYgPCA2MDAgJiYgdiA+IDQwMCkNCiAgICAgIHBvc05vdyA9IG1pZGRsZTsNCg0KICAgIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT1kb3duKXsNCiAgICAgIGVudHJ5U2VsKys7DQogICAgICBtZW51VXBkYXRlTENEID0gdHJ1ZTsNCiAgICAgIGlmIChlbnRyeVNlbCA9PSBtZW51TnVtRW50cmllcykNCiAgICAgICAgZW50cnlTZWwgPSBtZW51TnVtRW50cmllcy0xOw0KICAgIH0NCiAgICBlbHNlIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT11cCkgew0KICAgICAgZW50cnlTZWwtLTsNCiAgICAgIG1lbnVVcGRhdGVMQ0QgPSB0cnVlOyAgIA0KICAgICAgaWYgKGVudHJ5U2VsIDwgMCkNCiAgICAgICAgZW50cnlTZWwgPSAwOw0KICAgIH0gICAgDQogICAgbGFzdFJlYWQgPSBtaWxsaXMoKTsNCg0KDQogIH0NCg0KICBpZiAobWVudVVwZGF0ZUxDRCkgeyANCiAgICANCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgIGxjZC5wcmludChtZW51SGVhZGluZyk7DQogICAgDQogICAgbGNkLnNldEN1cnNvcigwLCAyKTsNCiAgICBsY2QucHJpbnQoIi0+Iik7DQogIA0KICAgIA0KICAgIA0KICAgIGxjZC5zZXRDdXJzb3IoMiwgMik7DQogICAgaWYgKG1lbnVMb2Nrc1tlbnRyeVNlbF0gJiYgc2hvd0ljb25zKSB7DQogICAgICBsY2Qud3JpdGUoYnl0ZSgwKSk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDMsIDIpOw0KICAgIH0gDQogICAgbGNkLnByaW50KG1lbnVFbnRyaWVzW2VudHJ5U2VsXSk7DQogIA0KICAgIGlmIChlbnRyeVNlbD09MCkgew0KICAgICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsIiAiKSk7ICANCiAgICB9IGVsc2Ugew0KICAgICAgbGNkLnNldEN1cnNvcigyLCAxKTsNCiAgICAgIGlmIChtZW51TG9ja3NbZW50cnlTZWwtMV0gJiYgc2hvd0ljb25zKSB7DQogICAgICAgIGxjZC53cml0ZShieXRlKDApKTsNCiAgICAgICAgbGNkLnNldEN1cnNvcigzLCAxKTsNCiAgICAgIH0NCiAgICAgIGxjZC5wcmludChtZW51RW50cmllc1tlbnRyeVNlbC0xXSk7DQogICAgfSANCiAgDQogICAgaWYgKGVudHJ5U2VsPT1tZW51TnVtRW50cmllcy0xKSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiICIpKTsgIA0KICAgIH0gZWxzZSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDIsIDMpOw0KICAgICAgaWYgKG1lbnVMb2Nrc1tlbnRyeVNlbCsxXSAmJiBzaG93SWNvbnMpIHsNCiAgICAgICAgbGNkLndyaXRlKGJ5dGUoMCkpOw0KICAgICAgICBsY2Quc2V0Q3Vyc29yKDMsIDMpOw0KICAgICAgfQ0KICAgICAgbGNkLnByaW50KG1lbnVFbnRyaWVzW2VudHJ5U2VsKzFdKTsNCiAgICB9DQogICAgbWVudVVwZGF0ZUxDRCA9IGZhbHNlOw0KICB9DQoNCiAgcmV0dXJuIGVudHJ5U2VsOw0KICANCn0NCg0Kdm9pZCBtZW51QWRkSGVhZGluZyhTdHJpbmcgaCkgew0KICBtZW51SGVhZGluZyA9IHBhZFN0cmluZygyMCxoKTsNCn0NCg0Kdm9pZCBtZW51QWRkRW50cnkoaW50IGksIFN0cmluZyBlKSB7DQogIGlmIChpPDE2KSB7DQogICAgbWVudUVudHJpZXNbaV0gPSBwYWRTdHJpbmcoMTcsZSk7IA0KICAgIG1lbnVOdW1FbnRyaWVzKys7DQogICAgbWVudVVwZGF0ZUxDRCA9IHRydWU7DQogIH0NCg0KfQ0KDQp2b2lkIG1lbnVDbGVhcigpIHsNCiAgbWVudU51bUVudHJpZXMgPSAwOw0KICBlbnRyeVNlbD0wOw0KICBtZW51SGVhZGluZyA9ICIgIjsNCiAgZm9yIChpbnQgaT0wOyBpPDE2OyBpKyspIHsNCiAgICBtZW51RW50cmllc1tpXSA9ICIgIjsgICAgDQogIH0NCiAgbWVudVVwZGF0ZUxDRCA9IHRydWU7DQp9DQoNCmludCBwYWdlVXBkYXRlKCkgew0KDQogIGlmIChtaWxsaXMoKSAtIGxhc3RSZWFkID4gMTUwKSB7DQogICAgaW50IHYgPSBhbmFsb2dSZWFkKGpveVYpOw0KDQogICAgcG9zTGFzdCA9IHBvc05vdzsNCiAgICANCiAgICBpZiAodiA+IDkwMCkNCiAgICAgIHBvc05vdyA9IGRvd247DQogICAgZWxzZSBpZiAodiA8IDIwMCkNCiAgICAgIHBvc05vdyA9IHVwOw0KICAgIGVsc2UgaWYgKHYgPCA1NzYgJiYgdiA+IDQ0OCkNCiAgICAgIHBvc05vdyA9IG1pZGRsZTsNCg0KICAgIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT1kb3duKXsNCiAgICAgIGVudHJ5U2VsKys7DQogICAgICBwYWdlVXBkYXRlTENEID0gdHJ1ZTsNCiAgICAgIGlmIChlbnRyeVNlbCA9PSBwYWdlTnVtRW50cmllcykNCiAgICAgICAgZW50cnlTZWwgPSBwYWdlTnVtRW50cmllcy0xOw0KICAgIH0NCiAgICBlbHNlIGlmIChwb3NOb3c9PW1pZGRsZSAmJiBwb3NMYXN0PT11cCkgew0KICAgICAgZW50cnlTZWwtLTsNCiAgICAgIHBhZ2VVcGRhdGVMQ0QgPSB0cnVlOyAgIA0KICAgICAgaWYgKGVudHJ5U2VsIDwgMCkNCiAgICAgICAgZW50cnlTZWwgPSAwOw0KICAgIH0gICAgDQogICAgbGFzdFJlYWQgPSBtaWxsaXMoKTsNCg0KICB9DQoNCiAgaWYgKHBhZ2VVcGRhdGVMQ0QpIHsgDQogICAgDQogICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICBsY2QucHJpbnQocGFnZUhlYWRpbmcpOw0KICANCiAgICBsY2Quc2V0Q3Vyc29yKDAsIDIpOw0KICAgIGxjZC5wcmludChwYWdlRW50cmllc1tlbnRyeVNlbF0pOw0KICANCiAgICBpZiAoZW50cnlTZWw9PTApIHsNCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLCIgIikpOyAgDQogICAgfSBlbHNlIHsNCiAgICAgIGxjZC5zZXRDdXJzb3IoMCwgMSk7DQogICAgICBsY2QucHJpbnQocGFnZUVudHJpZXNbZW50cnlTZWwtMV0pOw0KICAgIH0NCiAgDQogICAgaWYgKGVudHJ5U2VsPT1wYWdlTnVtRW50cmllcy0xKSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCwiICIpKTsgIA0KICAgIH0gZWxzZSB7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDMpOw0KICAgICAgbGNkLnByaW50KHBhZ2VFbnRyaWVzW2VudHJ5U2VsKzFdKTsNCiAgICB9DQogICAgcGFnZVVwZGF0ZUxDRCA9IGZhbHNlOw0KICB9DQoNCiAgcmV0dXJuIGVudHJ5U2VsOw0KICANCn0NCg0KDQp2b2lkIHBhZ2VBZGRIZWFkaW5nKFN0cmluZyBoKSB7DQogIHBhZ2VIZWFkaW5nID0gcGFkU3RyaW5nKDIwLGgpOw0KfQ0KDQp2b2lkIHBhZ2VBZGRFbnRyeShpbnQgaSwgU3RyaW5nIGUpIHsNCiAgaWYgKGk8MzIpIHsNCiAgICBwYWdlRW50cmllc1tpXSA9IHBhZFN0cmluZygyMCxlKTsgDQogICAgcGFnZU51bUVudHJpZXMrKzsNCiAgICBwYWdlVXBkYXRlTENEID0gdHJ1ZTsNCiAgfQ0KfQ0KDQp2b2lkIHBhZ2VDbGVhcigpIHsNCiAgcGFnZU51bUVudHJpZXMgPSAwOw0KICBlbnRyeVNlbD0wOw0KICBwYWdlSGVhZGluZyA9ICIgIjsNCiAgZm9yIChpbnQgaT0wOyBpPDMyOyBpKyspIHsNCiAgICBwYWdlRW50cmllc1tpXSA9ICIgIjsgICAgDQogIH0NCiAgcGFnZVVwZGF0ZUxDRCA9IHRydWU7DQp9DQoNCg0KU3RyaW5nIHBhZFN0cmluZyhpbnQgbGVuLCBTdHJpbmcgaW4pIHsNCiAgU3RyaW5nIG91dDsNCiAgaWYgKGluLmxlbmd0aCgpIDwgbGVuKSB7IA0KICAgIG91dCA9IGluOw0KICAgIGludCBsID0gbGVuLWluLmxlbmd0aCgpOw0KICAgIGZvciAoaW50IGk9MDsgaTxsOyBpKyspIHsNCiAgICAgIG91dCs9IiAiOyAgDQogICAgfQ0KICB9IGVsc2Ugew0KICAgIG91dCA9IGluLnN1YnN0cmluZygwLGxlbik7DQogIH0NCiAgcmV0dXJuIG91dDsgIA0KfQ0KDQp2b2lkIHBsYXlUb25lKGludCBtaWRpQSwgaW50IGR1cmF0aW9uKSB7DQogIHRUaW1lID0gbWlsbGlzKCk7DQogIHREdXJhdGlvbiA9IGR1cmF0aW9uOw0KICB0b25lQWN0aXZlID0gdHJ1ZTsNCiAgcGxheUR1YWwgPSBmYWxzZTsNCg0KICAvLyA4ODIgdG8gZ28gPSA2NTgtNjY1IHplcm8gY3Jvc3NpbmcNCg0KICAvL3NhbXBsZXMgPSAoKGR1cmF0aW9uICogMTAwMCkgLyAyMi43KTsvLyAtIDg4MjsNCiAgLy9pZiAoc2FtcGxlcyA8IDApIHNhbXBsZXMgPSAwOyANCiAgLy9jb3VudFNhbXBsZXMgPSAwOw0KDQogIHVsUGhhc2VJbmNyZW1lbnRBID0gbk1pZGlQaGFzZUluY3JlbWVudFttaWRpQV07DQp9DQoNCnZvaWQgcGxheUR1YWxUb25lKGludCBtaWRpQSwgaW50IG1pZGlCLCBmbG9hdCBtaXgsIGludCBkdXJhdGlvbikgew0KICB0VGltZSA9IG1pbGxpcygpOw0KICB0RHVyYXRpb24gPSBkdXJhdGlvbjsNCiAgdG9uZUFjdGl2ZSA9IHRydWU7DQogIHBsYXlEdWFsID0gdHJ1ZTsNCg0KICB1bFBoYXNlSW5jcmVtZW50QSA9IG5NaWRpUGhhc2VJbmNyZW1lbnRbbWlkaUFdOw0KICB1bFBoYXNlSW5jcmVtZW50QiA9IG5NaWRpUGhhc2VJbmNyZW1lbnRbbWlkaUJdOw0KDQogIGlmIChtaXggPDAuMCkgbWl4ID0gMC4wOw0KICBpZiAobWl4ID4xLjApIG1peCA9IDEuMDsNCg0KICB0b25lTWl4QSA9IG1peDsNCiAgdG9uZU1peEIgPSAxLTAgLSBtaXg7DQogIA0KfQ0KDQp2b2lkIGFtcE9uKCkgew0KICBkaWdpdGFsV3JpdGUoYW1wRW5hYmxlLEhJR0gpOyANCn0NCg0Kdm9pZCBhbXBPZmYoKSB7DQogIGRpZ2l0YWxXcml0ZShhbXBFbmFibGUsTE9XKTsgDQp9DQoNCnZvaWQgY2xlYXJUb25lKCkgew0KICB0b25lQWN0aXZlID0gZmFsc2U7DQp9DQoNCnZvaWQgVEM0X0hhbmRsZXIoKQ0Kew0KICANCiAgDQogIC8vIFdlIG5lZWQgdG8gZ2V0IHRoZSBzdGF0dXMgdG8gY2xlYXIgaXQgYW5kIGFsbG93IHRoZSBpbnRlcnJ1cHQgdG8gZmlyZSBhZ2Fpbg0KICBUQ19HZXRTdGF0dXMoVEMxLCAxKTsNCiANCiAgaWYgKHRvbmVBY3RpdmUpIHsNCg0KICAgIHVsUGhhc2VBY2N1bXVsYXRvckEgKz0gdWxQaGFzZUluY3JlbWVudEE7ICAgLy8gMzIgYml0IHBoYXNlIGluY3JlbWVudCwgc2VlIGJlbG93DQogICAgdWxQaGFzZUFjY3VtdWxhdG9yQiArPSB1bFBoYXNlSW5jcmVtZW50QjsgIA0KICANCiAgICAvLyBpZiB0aGUgcGhhc2UgYWNjdW11bGF0b3Igb3ZlciBmbG93cyAtIHdlIGhhdmUgYmVlbiB0aHJvdWdoIG9uZSBjeWNsZSBhdCB0aGUgY3VycmVudCBwaXRjaCwNCiAgICAvLyBub3cgd2UgbmVlZCB0byByZXNldCB0aGUgZ3JhaW5zIHJlYWR5IGZvciBvdXIgbmV4dCBjeWNsZQ0KICAgIGlmKHVsUGhhc2VBY2N1bXVsYXRvckEgPiBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UKQ0KICAgICAgdWxQaGFzZUFjY3VtdWxhdG9yQSAtPSBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UOw0KICAgIGlmKHVsUGhhc2VBY2N1bXVsYXRvckIgPiBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UKQ0KICAgICAgdWxQaGFzZUFjY3VtdWxhdG9yQiAtPSBTQU1QTEVTX1BFUl9DWUNMRV9GSVhFRFBPSU5UOw0KICAgICAgDQogICAgdWludDMyX3QgcGhhc2VBZGp1c3RQQWNjQSA9ICh1bFBoYXNlQWNjdW11bGF0b3JBPj4yMCkgJSBTSU5FX1NBTVBMRVM7DQogICAgdWludDMyX3QgcGhhc2VBZGp1c3RQQWNjQiA9ICh1bFBoYXNlQWNjdW11bGF0b3JCPj4yMCkgJSBTSU5FX1NBTVBMRVM7DQoNCiAgICAvLyBnZXQgdGhlIGN1cnJlbnQgc2FtcGxlICAgDQogICAgdWludDMyX3QgdWxPdXRwdXRBID0gc2luZVdhdmVbcGhhc2VBZGp1c3RQQWNjQV07DQogICAgdWludDMyX3QgdWxPdXRwdXRCID0gc2luZVdhdmVbcGhhc2VBZGp1c3RQQWNjQl07DQoNCiAgICB1aW50MzJfdCB1bE91dHB1dDsNCg0KICAgIGlmICghcGxheUR1YWwpDQogICAgICB1bE91dHB1dCA9IHVsT3V0cHV0QTsNCiAgICBlbHNlIHsNCiAgICAgIHVsT3V0cHV0ID0gKHVpbnQzMl90KSh1bE91dHB1dEEgKiB0b25lTWl4QSkgKyAodWludDMyX3QpKHVsT3V0cHV0QiAqIHRvbmVNaXhCKTsNCiAgICB9DQoNCiAgICB1bE91dHB1dCA9IHVsT3V0cHV0ICogKHZvbHVtZS8xMC4wKTsNCiAgIA0KICAgIGRhY2Nfd3JpdGVfY29udmVyc2lvbl9kYXRhKERBQ0NfSU5URVJGQUNFLCB1bE91dHB1dCk7DQoNCiAgICBpZiAobWlsbGlzKCkgLSB0VGltZSA+IHREdXJhdGlvbikgew0KICAgICAgdG9uZUFjdGl2ZSA9IGZhbHNlOyANCiAgICAgIC8vZGlnaXRhbFdyaXRlKDQxLExPVyk7DQogICAgfQ0KICB9IA0KDQp9DQoNCnZvaWQgbWFrZVNpbmVXYXZlKCkNCnsNCiAgZm9yKGludCBpID0gMDtpIDwgU0lORV9TQU1QTEVTOyBpKyspIHsNCiAgICBzaW5lV2F2ZVtpXSA9ICh1aW50MTZfdCkgICgoKDErc2luKCgoMi4wKlBJKS9TSU5FX1NBTVBMRVMpKmkpKSo0MDk1LjApLzIpOw0KICB9DQp9DQoNCi8vIGZpbGwgdGhlIG5vdGUgdGFibGUgd2l0aCB0aGUgcGhhc2UgaW5jcmVtZW50IHZhbHVlcyB3ZSByZXF1aXJlIHRvIGdlbmVyYXRlIHRoZSBub3RlDQp2b2lkIGNyZWF0ZU5vdGVUYWJsZShmbG9hdCBmU2FtcGxlUmF0ZSkNCnsNCiAgZm9yKHVpbnQzMl90IHVuTWlkaU5vdGUgPSAwO3VuTWlkaU5vdGUgPCBNSURJX05PVEVTO3VuTWlkaU5vdGUrKykgew0KICAgIC8vIENvcnJlY3QgY2FsY3VsYXRpb24gZm9yIGZyZXF1ZW5jeQ0KICAgIGZsb2F0IGZGcmVxdWVuY3kgPSAoKHBvdygyLjAsKHVuTWlkaU5vdGUtNjkuMCkvMTIuMCkpICogNDQwLjApOw0KICAgIG5NaWRpUGhhc2VJbmNyZW1lbnRbdW5NaWRpTm90ZV0gPSBmRnJlcXVlbmN5KlRJQ0tTX1BFUl9DWUNMRTsNCiAgfQ0KfQ0KDQp2b2lkIHNjcmVlblNhdmVyKCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBtYXRyaXguY2xlYXIoKTsNCiAgbWF0cml4LnNob3coKTsNCg0KICBmb3IgKGludCB4PTA7IHg8ODsgeCsrKSB7DQogICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgdGlsZVt4XVt5XSA9IDA7DQogICAgfQ0KICB9DQogIA0KICBmb3IgKGludCBpPTA7IGk8MzI7IGkrKykgew0KICAgIGJvb2xlYW4gc2V0ID0gZmFsc2U7DQogICAgd2hpbGUgKCFzZXQpIHsNCiAgICAgIGludCB4ID0gcmFuZG9tKDgpOw0KICAgICAgaW50IHkgPSByYW5kb20oOCk7DQogICAgICBpZiAodGlsZVt4XVt5XT09MCkgew0KICAgICAgICB0aWxlW3hdW3ldID0gcmFuZG9tKDEyOCkrNjQ7DQogICAgICAgIHNldCA9IHRydWU7DQogICAgICB9DQogICAgfQ0KICB9DQoNCiAgaW50IHN0cyA9IDA7DQogIGludCB0dHMgPSAwOw0KICBpbnQgdFdhaXQgPSBzYXZlclRleHRNaW5TaG93Ow0KDQogIHdoaWxlICghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQoNCiAgICBpZiAobWlsbGlzKCktdHRzID4gdFdhaXQpIHsNCiAgICAgIGludCByID0gcmFuZG9tKHNhdmVyVGV4dE51bSk7DQogICAgICBmb3IgKGludCBpPTA7IGk8NDsgaSsrKSB7DQogICAgICAgIGxjZC5zZXRDdXJzb3IoMCxpKTsNCg0KICAgICAgICBTdHJpbmcgdGVtcCA9IHNhdmVyVGV4dFtyXVtpXTsNCiAgICAgICAgaWYgKHRlbXAuc3Vic3RyaW5nKDAsMTApLmVxdWFscygiPGJveCBuYW1lPiIpKQ0KICAgICAgICAgIHRlbXAgPSBib3hOYW1lICsgdGVtcC5zdWJzdHJpbmcoMTApOw0KICAgICAgICANCiAgICAgICAgbGNkLnByaW50KHBhZFN0cmluZygyMCx0ZW1wKSk7IA0KICAgICAgfSANCiAgICAgIHR0cyA9IG1pbGxpcygpOw0KICAgICAgdFdhaXQgPSByYW5kb20oMTAwMDApK3NhdmVyVGV4dE1pblNob3c7ICAgDQogICAgfQ0KDQogICAgLy8gZXZlcnkgMTAwbXMgLSBzaHVmZmxlIHRoZSBib2FyZA0KICAgIGlmIChtaWxsaXMoKS1zdHMgPiAxMDApIHsNCiAgICAgIA0KICAgICAgbWF0cml4LmNsZWFyKCk7DQogICAgICBmb3IgKGludCB4PTA7IHg8ODsgeCsrKSB7DQogICAgICAgIGZvciAoaW50IHk9MDsgeTw4OyB5KyspIHsNCiAgICAgICAgICBpZiAodGlsZVt4XVt5XSE9MCkgew0KICAgICAgICAgICAgbWF0cml4LmRyYXdQaXhlbCh4LHksbWF0cml4LkNvbG9yKHRpbGVbeF1beV0sMCwxOTItdGlsZVt4XVt5XSkpOw0KICAgICAgICAgIH0gICAgICAgICANCiAgICAgICAgfQ0KICAgICAgfQ0KICAgICAgbWF0cml4LnNob3coKTsgDQoNCiAgICAgIGZvciAoaW50IHg9MDsgeDw4OyB4KyspIHsNCiAgICAgICAgZm9yIChpbnQgeT0wOyB5PDg7IHkrKykgew0KICAgICAgICAgIG1vdmVkW3hdW3ldID0gZmFsc2U7DQogICAgICAgIH0NCiAgICAgIH0NCg0KICAgICAgZm9yIChpbnQgeD0wOyB4PDg7IHgrKykgew0KICAgICAgICBmb3IgKGludCB5PTA7IHk8ODsgeSsrKSB7DQogICAgDQogICAgICAgICAgaWYgKHRpbGVbeF1beV0hPTAgJiAhbW92ZWRbeF1beV0pIHsNCiAgICAgICAgICAgIGJvb2xlYW4gZnJlZSA9IGZhbHNlOw0KICAgICAgICAgICAgaW50IHRyaWVzID0gMDsNCiAgICAgICAgICAgIHdoaWxlICghZnJlZSkgew0KICAgICAgICAgICAgICBpbnQgeGQgPSByYW5kb20oMyktMTsNCiAgICAgICAgICAgICAgaW50IHlkID0gcmFuZG9tKDMpLTE7DQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgICBpZiAoKHhkIT0wICYmIHlkPT0wKSB8fCAoeGQ9PTAgJiYgeWQhPTApICl7DQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgIGludCB4cCA9IHgreGQ7DQogICAgICAgICAgICAgICAgaWYgKHhwPDApIHhwID0gMDsNCiAgICAgICAgICAgICAgICBpZiAoeHA+NykgeHAgPSA3Ow0KICAgICAgICAgICAgICAgIGludCB5cCA9IHkreWQ7DQogICAgICAgICAgICAgICAgaWYgKHlwPDApIHlwID0gMDsNCiAgICAgICAgICAgICAgICBpZiAoeXA+NykgeXAgPSA3Ow0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICBpZiAodGlsZVt4cF1beXBdPT0wKSB7DQogICAgICAgICAgICAgICAgICB0aWxlW3hwXVt5cF0gPSB0aWxlW3hdW3ldOw0KICAgICAgICAgICAgICAgICAgdGlsZVt4XVt5XSA9IDA7DQogICAgICAgICAgICAgICAgICBtb3ZlZFt4cF1beXBdID0gdHJ1ZTsNCiAgICAgICAgICAgICAgICAgIGZyZWUgPSB0cnVlOw0KICAgICAgICAgICAgICAgIH0NCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICB0cmllcyArKzsNCiAgICAgICAgICAgICAgICBpZiAodHJpZXMgPT0gMTApIHsNCiAgICAgICAgICAgICAgICAgIGZyZWUgPSB0cnVlOyAgDQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgfQ0KICAgICAgICAgIH0NCiAgICAgICAgfQ0KICAgICAgfQ0KICAgICAgDQogICAgICBzdHMgPSBtaWxsaXMoKTsNCiAgICAgICAgDQogICAgfS8vIGV2cnkgMTAwbXMgc2h1ZmZsZSB0aGUgdGlsZXMNCiAgICANCiAgfQ0KICANCn0NCg0Kdm9pZCBzZXREaWZmaWN1bHR5KCkgew0KDQogIGxjZC5jbGVhcigpOw0KICBwYWdlQ2xlYXIoKTsNCiAgcGFnZUFkZEhlYWRpbmcoIi0tLS0tRElGRklDVUxUWS0tLS0tIik7DQoNCiAgcGFnZUFkZEVudHJ5KDAsICJVc2UgdGhlIGRpYWxzIHRvIHNldCIpOw0KICBwYWdlQWRkRW50cnkoMSwgInRoZSBkaWZmaWN1bHR5IG9mIik7DQogIHBhZ2VBZGRFbnRyeSgyLCAiV29yayBNb2RlLiIpOw0KICBwYWdlQWRkRW50cnkoMywgIlRoaXMgc2V0dGluZyBhZGp1c3RzIik7DQogIHBhZ2VBZGRFbnRyeSg0LCAidGhlIHJhZGl1cyBvZiB0aGUiKTsNCiAgcGFnZUFkZEVudHJ5KDUsICJhcmVhIHRoYXQgdGhlIGJveCIpOw0KICBwYWdlQWRkRW50cnkoNiwgImZhY3Rvcnkgd2lsbCBtYWtlIik7DQogIHBhZ2VBZGRFbnRyeSg3LCAiYm94ZXMuIik7DQogIA0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogICAgaW50IHNlbGVjdGVkID0gcGFnZVVwZGF0ZSgpOw0KICB9DQoNCiAgbGNkLmNsZWFyKCk7DQogIA0KICB3aGlsZSghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQoNCiAgICBpbnQgcHYgPSBwb3RWYWx1ZShjZW50ZXIsIDAuMDEpOw0KICAgIGlmIChwdiA8IDApDQogICAgICBwdiA9IDA7DQogICAgaWYgKHB2ID4gMTApDQogICAgICBwdiA9IDEwOw0KDQogICAgZ29vZEJveFJhZGl1cyA9IDAuOSArICgoZmxvYXQpKHB2Pj4xKSAvIDEwLjApOyAgDQoNCiAgICBTdHJpbmcgZGlmZkEgPSAiTUVESVVNOiBtYWtlIHNvbWUiOw0KICAgIFN0cmluZyBkaWZmQiA9ICJtZWRpdW0gb3Igb3JhbmdlIjsNCiAgICBTdHJpbmcgZGlmZkMgPSAiYm94ZXMiOw0KICAgIGlmIChnb29kQm94UmFkaXVzIDw9IDEuMDUpIHsNCiAgICAgIGRpZmZBID0gIkVBU1k6IG1ha2UgbGVzcyI7DQogICAgICBkaWZmQiA9ICJtZWRpdW0gb3Igb3JhbmdlIjsNCiAgICAgIGRpZmZDID0gImJveGVzIjsNCiAgICB9DQogICAgaWYgKGdvb2RCb3hSYWRpdXMgPj0gMS4yNSkgew0KICAgICAgZGlmZkEgPSAiSEFSRDogbWFrZSBtb3JlIjsNCiAgICAgIGRpZmZCID0gIm1lZGl1bSBvciBvcmFuZ2UiOw0KICAgICAgZGlmZkMgPSAiYm94ZXMiOw0KICAgIH0NCiAgICBsY2Quc2V0Q3Vyc29yKDAsMCk7DQogICAgbGNkLnByaW50KHBhZFN0cmluZygyMCxkaWZmQSkpOw0KICAgIGxjZC5zZXRDdXJzb3IoMCwxKTsNCiAgICBsY2QucHJpbnQocGFkU3RyaW5nKDIwLGRpZmZCKSk7DQogICAgbGNkLnNldEN1cnNvcigwLDIpOw0KICAgIGxjZC5wcmludChwYWRTdHJpbmcoMjAsZGlmZkMpKTsNCiAgICBsY2Quc2V0Q3Vyc29yKDAsMyk7DQogICAgbGNkLnByaW50KCJCb3ggUmFkaXVzID0gIiArIFN0cmluZyhnb29kQm94UmFkaXVzLDEpKTsNCg0KICB9DQoNCiAgbG9nU2V0dGluZ3MoKTsNCiAgcmV0dXJuOw0KfQ0KDQoNCg0Kdm9pZCBzeW50aE1vZGUoKSB7DQogIGxjZC5jbGVhcigpOw0KICBsY2Quc2V0Q3Vyc29yKDAsMCk7DQogIGxjZC5wcmludCgiLS0tLVpBUFBBLS1TWU5USC0tLS0iKTsNCiAgbGNkLnNldEN1cnNvcigwLDEpOw0KICBsY2QucHJpbnQoIlVzZSB0aGUgZGlhbHMgYW5kICAgIik7DQogIGxjZC5zZXRDdXJzb3IoMCwyKTsNCiAgbGNkLnByaW50KCJqb3lzdGljayB0byBtYWtlIik7DQogIGxjZC5zZXRDdXJzb3IoMCwzKTsNCiAgbGNkLnByaW50KCJzeW50aGVzaXplciBzb3VuZHMiKTsNCiAgDQogIGludCB0ZW1wVm9sdW1lID0gdm9sdW1lOw0KDQogIGFtcE9uKCk7DQoNCiAgd2hpbGUoIWJ1dHRvblByZXNzZWQoYW55KSkgew0KICAgDQogICAgaW50IHB2ID0gcG90VmFsdWUobGVmdCwgMC4wMSk7DQogICAgaWYgKHB2IDwgMCkNCiAgICAgIHB2ID0gMDsNCiAgICBpZiAocHYgPiAxMCkNCiAgICAgIHB2ID0gMTA7DQogICAgdm9sdW1lID0gcHY7DQoNCiAgICBpbnQgaG9yaXogPSBhbmFsb2dSZWFkKGpveUgpOw0KICAgIGludCB2ZXJ0ID0gYW5hbG9nUmVhZChqb3lWKTsNCiAgICBob3JpeiA9IChob3Jpej4+NCkrNDA7DQogICAgdmVydCA9ICh2ZXJ0Pj40KSs0MDsNCiAgICBpbnQgbWl4ID0gcG90VmFsdWUoY2VudGVyLCAxLjApOw0KICAgIGZsb2F0IG1peFMgPSAoZmxvYXQpbWl4LzEwMjMuMDsNCiAgICBwbGF5RHVhbFRvbmUoaG9yaXosdmVydCxtaXhTLDEwMDAwMDAwMCk7DQogICAgDQogIH0NCiAgDQogIG1vZGUgPSBtZW51Ow0KICB2b2x1bWUgPSB0ZW1wVm9sdW1lOw0KICBjbGVhclRvbmUoKTsNCiAgYW1wT2ZmKCk7DQp9DQoNCi8vICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KLy8gc2VlZFJORw0KLy8gKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQp2b2lkIHNlZWRSTkcoKSB7DQogIGxvbmcgYjBfYjkgPSAobG9uZykgYW5hbG9nUmVhZChwb3RMZWZ0KTsNCiAgbG9uZyBiMTBfYjE5ID0gKGxvbmcpIGFuYWxvZ1JlYWQocG90Q2VudGVyKTsNCiAgbG9uZyBiMjBfYjI5ID0gKGxvbmcpIGFuYWxvZ1JlYWQocG90UmlnaHQpOw0KICBsb25nIHNlZWQgPSBiMF9iOSB8IChiMTBfYjE5IDw8IDEwKSB8IChiMjBfYjI5IDw8IDIwKTsNCiAgcmFuZG9tU2VlZChzZWVkKTsNCn0NCg0Kdm9pZCBwb25nTG9vcCgpIHsNCg0KICBzd2l0Y2ggKHBvbmdNb2RlKSB7DQogICAgY2FzZSBwb25nV2FpdDoNCiAgICAgIHBvbmdXYWl0TW9kZSgpOw0KICAgICAgYnJlYWs7DQogICAgY2FzZSBwb25nU2hvd1Njb3JlOg0KICAgICAgcG9uZ1Nob3dTY29yZU1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2UgcG9uZ1BsYXk6DQogICAgICBwb25nUGxheU1vZGUoKTsNCiAgICAgIGJyZWFrOw0KICAgIGNhc2UgcG9uZ0V4aXQ6DQogICAgICBtb2RlID0gbWVudTsNCiAgICAgIGJyZWFrOw0KICB9DQogIA0KfQ0KDQp2b2lkIHBvbmdQbGF5TW9kZSgpIHsNCiANCiAgbWF0cml4LmNsZWFyKCk7DQogIA0KICByZWFkUGFkZGxlUG9zaXRpb24oKTsNCg0KICBpZiAoc3RpY2tCYWxsVG9QYWRkbGUpIHsNCg0KICAgIGlmIChiYWxsT25QYWRkbGUgPT0gMCkgew0KICAgICAgYmFsbFBvc1ggPSAxOw0KICAgICAgYmFsbFBvc1kgPSBsZWZ0UGFkZGxlUG9zOw0KICAgIH0gZWxzZSB7DQogICAgICBiYWxsUG9zWCA9IDY7DQogICAgICBiYWxsUG9zWSA9IHJpZ2h0UGFkZGxlUG9zOw0KICAgIH0NCg0KICAgIGlmIChidXR0b25QcmVzc2VkKGFueSkpIHsNCiAgICAgIHN0aWNrQmFsbFRvUGFkZGxlID0gZmFsc2U7DQogICAgICBpZiAoYmFsbE9uUGFkZGxlID09IDApDQogICAgICAgIGJhbGxEaXJYID0gMTsNCiAgICAgIGVsc2UNCiAgICAgICAgYmFsbERpclggPSAtMTsNCiAgICAgIGJhbGxEaXJZID0gcmFuZG9tKDMpIC0gMTsgDQogICAgICBsYXN0QmFsbFVwZGF0ZSA9IG1pbGxpcygpOyANCiAgICB9DQogICAgICAgICAgDQogIH0gZWxzZSB7DQogICAgaWYgKG1pbGxpcygpIC0gbGFzdEJhbGxVcGRhdGUgPiBiYWxsU3BlZWQpIHsNCiAgICAgIGJhbGxQb3NYICs9IGJhbGxEaXJYOw0KICAgICAgYmFsbFBvc1kgKz0gYmFsbERpclk7DQoNCiAgICAgIGxhc3RCYWxsVXBkYXRlID0gbWlsbGlzKCk7DQogICAgICBjaGVja0JhbGwgPSB0cnVlOw0KDQogICAgfQ0KICB9DQogICAgDQogIG1hdHJpeC5kcmF3UGl4ZWwoYmFsbFBvc1gsIGJhbGxQb3NZLG1hdHJpeC5Db2xvcigwLDE4MCwwKSk7DQogIGZvciAoaW50IGk9LTE7IGk8MjsgaSsrKSB7DQogICAgbWF0cml4LmRyYXdQaXhlbCgwLGxlZnRQYWRkbGVQb3MraSxtYXRyaXguQ29sb3IoMTgwLDAsMCkpOw0KICAgIG1hdHJpeC5kcmF3UGl4ZWwoNyxyaWdodFBhZGRsZVBvcytpLG1hdHJpeC5Db2xvcigwLDAsMTgwKSk7DQogIH0NCiAgbWF0cml4LnNob3coKTsNCg0KICBpZiAoY2hlY2tCYWxsKSB7DQoNCiAgICAvLyBib3VuY2Ugb2ZmIHRoZSBsZWZ0IHBhZGRsZQ0KICAgIGlmIChiYWxsUG9zWCA9PSAxKSB7DQogICAgICBpZiAoYmFsbFBvc1kgPD0gbGVmdFBhZGRsZVBvcysxICYmIGJhbGxQb3NZID49IGxlZnRQYWRkbGVQb3MtMSkgew0KICAgICAgICBiYWxsRGlyWCAqPSAtMTsNCiAgICAgICAgYmFsbERpclkgPSBiYWxsUG9zWSAtIGxlZnRQYWRkbGVQb3M7ICAgICAgICANCiAgICAgICAgaWYgKHJhbmRvbSg1KSA9PSAwKSANCiAgICAgICAgICBiYWxsRGlyWSA9IHJhbmRvbSgzKSAtIDE7DQogICAgICAgIGlmIChiYWxsRGlyWSA9PSAxICYmIGJhbGxQb3NZID09IDcpDQogICAgICAgICAgYmFsbERpclkgPSAtMTsNCiAgICAgICAgZWxzZSBpZiAoYmFsbERpclkgPT0gLTEgJiYgYmFsbFBvc1kgPT0gMCkNCiAgICAgICAgICBiYWxsRGlyWSA9IDE7DQogICAgICAgIA0KICAgICAgICBjaGVja0JhbGwgPSBmYWxzZTsgDQogICAgICAgIHBvbmdTY29yZSArPSBtYXAoYmFsbFNwZWVkLCAzMCwgMjAwLCA5ODc3LCAxMCk7DQogICAgICAgIHBsYXlUb25lKDEwMiw1MCk7DQogICAgICAgIGJhbGxTcGVlZCAqPSAwLjk4Ow0KICAgICAgICBpZiAoYmFsbFNwZWVkIDwgMzApIHsNCiAgICAgICAgICBiYWxsU3BlZWQgPSAzMDsgICAgICAgDQogICAgICAgIH0NCiAgICAgICAgbGNkLnNldEN1cnNvcigwLCAwKTsNCiAgICAgICAgbGNkLnByaW50KHBvbmdTY29yZSk7DQogICAgICB9DQogICAgfQ0KICANCiAgICAvLyBib3VuY2Ugb2ZmIHRoZSByaWdodCBwYWRkbGUNCiAgICBpZiAoYmFsbFBvc1ggPT0gNikgew0KICAgICAgaWYgKGJhbGxQb3NZIDw9IHJpZ2h0UGFkZGxlUG9zKzEgJiYgYmFsbFBvc1kgPj0gcmlnaHRQYWRkbGVQb3MtMSkgew0KICAgICAgICBiYWxsRGlyWCAqPSAtMTsNCiAgICAgICAgYmFsbERpclkgPSBiYWxsUG9zWSAtIHJpZ2h0UGFkZGxlUG9zOw0KICAgICAgICBpZiAocmFuZG9tKDUpID09IDApIA0KICAgICAgICAgIGJhbGxEaXJZID0gcmFuZG9tKDMpIC0gMTsNCiAgICAgICAgaWYgKGJhbGxEaXJZID09IDEgJiYgYmFsbFBvc1kgPT0gNykNCiAgICAgICAgICBiYWxsRGlyWSA9IC0xOw0KICAgICAgICBlbHNlIGlmIChiYWxsRGlyWSA9PSAtMSAmJiBiYWxsUG9zWSA9PSAwKQ0KICAgICAgICAgIGJhbGxEaXJZID0gMTsNCiAgICAgICAgY2hlY2tCYWxsID0gZmFsc2U7DQogICAgICAgIHBsYXlUb25lKDEwNyw1MCk7DQogICAgICAgIHBvbmdTY29yZSArPSBtYXAoYmFsbFNwZWVkLCAzMCwgMjAwLCA5ODc3LCAxMCk7DQogICAgICAgIGJhbGxTcGVlZCAqPSAwLjk4Ow0KICAgICAgICBpZiAoYmFsbFNwZWVkIDwgMzApIHsNCiAgICAgICAgICBiYWxsU3BlZWQgPSAzMDsNCiAgICAgICAgfQ0KICAgICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgICBsY2QucHJpbnQocG9uZ1Njb3JlKTsNCiAgICAgIH0NCiAgICB9DQoNCiAgfQ0KDQogIGlmIChjaGVja0JhbGwpIHsNCiAgICAvLyBib3VuY2Ugb2ZmIHRoZSB0b3AgYW5kIGJvdHRvbSB3YWxscyANCiAgICBpZiAoKGJhbGxQb3NZID09IDcgfHwgYmFsbFBvc1kgPT0gMCkgJiYgYmFsbERpclkgIT0gMCkgew0KICAgICAgYmFsbERpclkgKj0gLTE7DQogICAgICBjaGVja0JhbGwgPSBmYWxzZTsNCiAgICB9DQogIH0NCg0KICBpZiAoY2hlY2tCYWxsKSB7DQogICAgLy8gaWYgdGhlIGJhbGxzIG1pc3NlcyB0aGUgcGFkZGxlIGFuZCBoYXMgZ29uZSBvZmYgdGhlIHNjcmVlbiAtIHJlc2V0IHRoZSBiYWxsDQogICAgaWYgKGJhbGxQb3NYIDwgLTEgfHwgYmFsbFBvc1ggPiA4KSB7DQogICAgICBzdGlja0JhbGxUb1BhZGRsZSA9IHRydWU7DQogICAgICBiYWxsT25QYWRkbGUgPSByYW5kb20oMik7DQogICAgICBjaGVja0JhbGwgPSBmYWxzZTsNCiAgICAgIGJhbGxTcGVlZCA9IDIwMDsNCiAgICAgIHBvbmdMaXZlcy0tOw0KICAgICAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgICAgIGxjZC5wcmludCgiTGl2ZXMgbGVmdCA9ICIrU3RyaW5nKHBvbmdMaXZlcy0xKSk7DQogICAgICBwbGF5VG9uZSg2NSwzMDApOw0KICAgICAgZGVsYXkoMzkwKTsNCiAgICAgIHBsYXlUb25lKDU5LDMwMCk7DQogICAgICBkZWxheSgzOTApOw0KICAgICAgcGxheVRvbmUoNDYsMTAwMCk7DQogICAgICBkZWxheSgxMzAwKTsgIA0KICAgICAgaWYgKHBvbmdMaXZlcyA9PSAwKSB7DQogICAgICAgIHBvbmdNb2RlID0gcG9uZ1Nob3dTY29yZTsNCiAgICAgICAgYW1wT2ZmKCk7DQogICAgICB9ICAgICANCiAgICB9DQogIH0NCg0KDQp9DQoNCnZvaWQgcG9uZ1Nob3dTY29yZU1vZGUoKSB7DQoNCiAgbWF0cml4LmNsZWFyKCk7DQogIG1hdHJpeC5zaG93KCk7DQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogIGxjZC5wcmludCgiLS0tLSBHQU1FICBPVkVSIC0tLS0iKTsNCiAgbGNkLnNldEN1cnNvcigwLCAxKTsNCiAgbGNkLnByaW50KHBvbmdTY29yZSk7DQogIHdoaWxlICghYnV0dG9uUHJlc3NlZChhbnkpKSB7DQogIH0gDQoNCiAgcG9uZ01vZGUgPSBwb25nV2FpdDsNCiAgDQp9DQoNCnZvaWQgcmVhZFBhZGRsZVBvc2l0aW9uKCkgew0KDQogIGludCBsZWZ0UG90VmFsID0gYW5hbG9nUmVhZChwb3RMZWZ0KTsNCiAgaW50IHJpZ2h0UG90VmFsID0gYW5hbG9nUmVhZChwb3RSaWdodCk7DQogIGlmIChsZWZ0UG90VmFsID4gcG90TWF4KQ0KICAgIGxlZnRQb3RWYWwgPSBwb3RNYXg7DQogIGlmIChsZWZ0UG90VmFsIDwgcG90TWluKQ0KICAgIGxlZnRQb3RWYWwgPSBwb3RNaW47ICAgICANCiAgaWYgKHJpZ2h0UG90VmFsID4gcG90TWF4KQ0KICAgIHJpZ2h0UG90VmFsID0gcG90TWF4Ow0KICBpZiAocmlnaHRQb3RWYWwgPCBwb3RNaW4pDQogICAgcmlnaHRQb3RWYWwgPSBwb3RNaW47DQoNCiAgbGVmdFBhZGRsZVBvcyA9ICgobGVmdFBvdFZhbC1wb3RNaW4pLzQ0LjQpLTE7DQogIHJpZ2h0UGFkZGxlUG9zID0gOC0oKHJpZ2h0UG90VmFsLXBvdE1pbikvNDQuNCk7DQoNCiAgaWYgKHN0aWNrQmFsbFRvUGFkZGxlKSB7DQogICAgaWYgKGxlZnRQYWRkbGVQb3MgPiA2KQ0KICAgICAgbGVmdFBhZGRsZVBvcyA9IDY7DQogICAgaWYgKGxlZnRQYWRkbGVQb3MgPCAxKQ0KICAgICAgbGVmdFBhZGRsZVBvcyA9IDE7ICANCiAgICBpZiAocmlnaHRQYWRkbGVQb3MgPiA2KQ0KICAgICAgcmlnaHRQYWRkbGVQb3MgPSA2Ow0KICAgIGlmIChyaWdodFBhZGRsZVBvcyA8IDEpDQogICAgICByaWdodFBhZGRsZVBvcyA9IDE7ICANCiAgfQ0KICANCn0NCg0Kdm9pZCBwb25nV2FpdE1vZGUoKSB7DQoNCiAgbWF0cml4LmNsZWFyKCk7DQogIG1hdHJpeC5zaG93KCk7DQoNCiAgbGNkLmNsZWFyKCk7DQogIGxjZC5zZXRDdXJzb3IoMCwgMCk7DQogIGxjZC5wcmludCgiLS0tLS0tLUJPSU5HIS0tLS0tLS0iKTsNCiAgbGNkLnNldEN1cnNvcigwLCAyKTsNCiAgbGNkLnByaW50KCJQdXNoIGdyZWVuIHRvIHBsYXkiKTsNCiAgbGNkLnNldEN1cnNvcigwLCAzKTsNCiAgbGNkLnByaW50KCJQdXNoIHJlZCB0byBleGl0Iik7DQoNCiAgYW1wT2ZmKCk7DQoNCiAgYm9vbGVhbiBhbnN3ZXJlZCA9IGZhbHNlOw0KICB3aGlsZSAoIWFuc3dlcmVkKSB7DQoNCiAgICBpZiAoYnV0dG9uUHJlc3NlZChncmVlbikpIHsNCiAgICAgIA0KICAgICAgYW1wT24oKTsNCiAgICAgIA0KICAgICAgcG9uZ0xpdmVzID0gNDsNCiAgICAgIHBvbmdTY29yZSA9IDA7DQogICAgICBwb25nTW9kZSA9IHBvbmdQbGF5Ow0KICAgICAgbGNkLmNsZWFyKCk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDApOw0KICAgICAgbGNkLnByaW50KHBvbmdTY29yZSk7DQogICAgICBsY2Quc2V0Q3Vyc29yKDAsIDEpOw0KICAgICAgbGNkLnByaW50KCJMaXZlcyBsZWZ0ID0gIitTdHJpbmcocG9uZ0xpdmVzLTEpKTsNCiAgICAgIHBsYXlUb25lKDY5LDI1MCk7DQogICAgICBkZWxheSgzMDApOw0KICAgICAgcGxheVRvbmUoNjksMTUwKTsNCiAgICAgIGRlbGF5KDE4MCk7DQogICAgICBwbGF5VG9uZSg4MCwxMDAwKTsNCiAgICAgIGRlbGF5KDEzMDApOw0KICAgICAgYW5zd2VyZWQgPSB0cnVlOyAgICAgIA0KICAgIH0NCiAgICBpZiAoYnV0dG9uUHJlc3NlZChyZWQpKSB7DQogICAgICBwb25nTW9kZSA9IHBvbmdFeGl0Ow0KICAgICAgYW5zd2VyZWQgPSB0cnVlOw0KICAgIH0NCiAgICANCiAgfQ0KICANCn0NCg0KLyogTWlkaSwgRnJlcSwgUGhhc2UgQWNjL0luYw0KAAAAAAAAAAAAAAAwIDguMTggMTcxNDU4DQoxIDguNjYgMTgxNjU0DQoyIDkuMTggMTkyNDU2DQozIDkuNzIgMjAzOTAwDQo0IDEwLjMwIDIxNjAyNA0KNSAxMC45MSAyMjg4NzANCjYgMTEuNTYgMjQyNDc5DQo3IDEyLjI1IDI1Njg5OA0KOCAxMi45OCAyNzIxNzQNCjkgMTMuNzUgMjg4MzU4DQoxMCAxNC41NyAzMDU1MDUNCjExIDE1LjQzIDMyMzY3MQ0KMTIgMTYuMzUgMzQyOTE3DQoxMyAxNy4zMiAzNjMzMDgNCjE0IDE4LjM1IDM4NDkxMg0KMTUgMTkuNDUgNDA3ODAwDQoxNiAyMC42MCA0MzIwNDkNCjE3IDIxLjgzIDQ1Nzc0MA0KMTggMjMuMTIgNDg0OTU5DQoxOSAyNC41MCA1MTM3OTYNCjIwIDI1Ljk2IDU0NDM0OA0KMjEgMjcuNTAgNTc2NzE2DQoyMiAyOS4xNCA2MTEwMTANCjIzIDMwLjg3IDY0NzM0Mg0KMjQgMzIuNzAgNjg1ODM1DQoyNSAzNC42NSA3MjY2MTcNCjI2IDM2LjcxIDc2OTgyNA0KMjcgMzguODkgODE1NjAwDQoyOCA0MS4yMCA4NjQwOTgNCjI5IDQzLjY1IDkxNTQ4MA0KMzAgNDYuMjUgOTY5OTE4DQozMSA0OS4wMCAxMDI3NTkyDQozMiA1MS45MSAxMDg4Njk2DQozMyA1NS4wMCAxMTUzNDMzDQozNCA1OC4yNyAxMjIyMDIwDQozNSA2MS43NCAxMjk0Njg1DQozNiA2NS40MSAxMzcxNjcxDQozNyA2OS4zMCAxNDUzMjM1DQozOCA3My40MiAxNTM5NjQ5DQozOSA3Ny43OCAxNjMxMjAxDQo0MCA4Mi40MSAxNzI4MTk3DQo0MSA4Ny4zMSAxODMwOTYxDQo0MiA5Mi41MCAxOTM5ODM2DQo0MyA5OC4wMCAyMDU1MTg0DQo0NCAxMDMuODMgMjE3NzM5Mg0KNDUgMTEwLjAwIDIzMDY4NjcNCjQ2IDExNi41NCAyNDQ0MDQwDQo0NyAxMjMuNDcgMjU4OTM3MA0KNDggMTMwLjgxIDI3NDMzNDMNCjQ5IDEzOC41OSAyOTA2NDcwDQo1MCAxNDYuODMgMzA3OTI5OA0KNTEgMTU1LjU2IDMyNjI0MDINCjUyIDE2NC44MSAzNDU2Mzk1DQo1MyAxNzQuNjEgMzY2MTkyMw0KNTQgMTg1LjAwIDM4Nzk2NzINCjU1IDE5Ni4wMCA0MTEwMzY5DQo1NiAyMDcuNjUgNDM1NDc4NQ0KNTcgMjIwLjAwIDQ2MTM3MzQNCjU4IDIzMy4wOCA0ODg4MDgxDQo1OSAyNDYuOTQgNTE3ODc0MQ0KNjAgMjYxLjYzIDU0ODY2ODYNCjYxIDI3Ny4xOCA1ODEyOTQwDQo2MiAyOTMuNjYgNjE1ODU5Ng0KNjMgMzExLjEzIDY1MjQ4MDUNCjY0IDMyOS42MyA2OTEyNzkxDQo2NSAzNDkuMjMgNzMyMzg0Nw0KNjYgMzY5Ljk5IDc3NTkzNDUNCjY3IDM5Mi4wMCA4MjIwNzM5DQo2OCA0MTUuMzAgODcwOTU3MA0KNjkgNDQwLjAwIDkyMjc0NjkNCjcwIDQ2Ni4xNiA5Nzc2MTYyDQo3MSA0OTMuODggMTAzNTc0ODMNCjcyIDUyMy4yNSAxMDk3MzM3Mg0KNzMgNTU0LjM3IDExNjI1ODgxDQo3NCA1ODcuMzMgMTIzMTcxOTMNCjc1IDYyMi4yNSAxMzA0OTYxMQ0KNzYgNjU5LjI2IDEzODI1NTgyDQo3NyA2OTguNDYgMTQ2NDc2OTQNCjc4IDczOS45OSAxNTUxODY5MA0KNzkgNzgzLjk5IDE2NDQxNDc5DQo4MCA4MzAuNjEgMTc0MTkxNDANCjgxIDg4MC4wMCAxODQ1NDkzOA0KODIgOTMyLjMzIDE5NTUyMzI0DQo4MyA5ODcuNzcgMjA3MTQ5NjYNCjg0IDEwNDYuNTAgMjE5NDY3NDQNCjg1IDExMDguNzMgMjMyNTE3NjINCjg2IDExNzQuNjYgMjQ2MzQzODYNCjg3IDEyNDQuNTEgMjYwOTkyMjINCjg4IDEzMTguNTEgMjc2NTExNjQNCjg5IDEzOTYuOTEgMjkyOTUzODgNCjkwIDE0NzkuOTggMzEwMzczODANCjkxIDE1NjcuOTggMzI4ODI5NTgNCjkyIDE2NjEuMjIgMzQ4MzgyODANCjkzIDE3NjAuMDAgMzY5MDk4NzYNCjk0IDE4NjQuNjYgMzkxMDQ2NDgNCjk1IDE5NzUuNTMgNDE0Mjk5MzINCjk2IDIwOTMuMDAgNDM4OTM0ODgNCjk3IDIyMTcuNDYgNDY1MDM1MjQNCjk4IDIzNDkuMzIgNDkyNjg3NzINCjk5IDI0ODkuMDIgNTIxOTg0NDQNCjEwMCAyNjM3LjAyIDU1MzAyMzI4DQoxMDEgMjc5My44MyA1ODU5MDc3Ng0KMTAyIDI5NTkuOTYgNjIwNzQ3NjANCjEwMyAzMTM1Ljk2IDY1NzY1OTE2DQoxMDQgMzMyMi40NCA2OTY3NjU2MA0KMTA1IDM1MjAuMDAgNzM4MTk3NTINCjEwNiAzNzI5LjMxIDc4MjA5Mjk2DQoxMDcgMzk1MS4wNyA4Mjg1OTg2NA0KMTA4IDQxODYuMDEgODc3ODY5NzYNCjEwOSA0NDM0LjkyIDkzMDA3MDQ4DQoxMTAgNDY5OC42NCA5ODUzNzU0NA0KMTExIDQ5NzguMDMgMTA0Mzk2ODg4DQoxMTIgNTI3NC4wNCAxMTA2MDQ2NTYNCjExMyA1NTg3LjY1IDExNzE4MTU1Mg0KMTE0IDU5MTkuOTEgMTI0MTQ5NTIwDQoxMTUgNjI3MS45MyAxMzE1MzE4MzINCjExNiA2NjQ0Ljg4IDEzOTM1MzEyMA0KMTE3IDcwNDAuMDAgMTQ3NjM5NTA0DQoxMTggNzQ1OC42MiAxNTY0MTg1OTINCjExOSA3OTAyLjEzIDE2NTcxOTcyOA0KMTIwIDgzNzIuMDIgMTc1NTczOTUyDQoxMjEgODg2OS44NCAxODYwMTQwOTYNCjEyMiA5Mzk3LjI3IDE5NzA3NTA4OA0KMTIzIDk5NTYuMDYgMjA4NzkzNzc2DQoxMjQgMTA1NDguMDggMjIxMjA5MzEyDQoxMjUgMTExNzUuMzAgMjM0MzYzMTA0DQoxMjYgMTE4MzkuODIgMjQ4Mjk5MDQwDQoxMjcgMTI1NDMuODUgMjYzMDYzNjY0DQoqLw0KDQoNCg0
more processing code...
processing
1 2 3 4 5class dueParams { 6 7String boxName; 8String guildName; 9float[] 10 nnWeights = new float[3]; 11float nnLearningC; 12int trainCycles; 13int totalTrainingExamples; 14int 15 totalCorrect; 16float workModeAverage; 17int workModeBest; 18float goodBoxRadius; 19char[][] 20 guildGlyph = new char[8][8]; 21 22 dueParams() { 23 24 } 25 26 27 void bytesToParams(byte[] params) { 28 29 int i=0; 30 int temp; 31 32 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] 33 & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 34 nnLearningC = Float.intBitsToFloat(temp); 35 36 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] 37 & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 38 goodBoxRadius = Float.intBitsToFloat(temp); 39 40 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] 41 & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 42 nnWeights[0] = Float.intBitsToFloat(temp); 43 44 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] 45 & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 46 nnWeights[1] = Float.intBitsToFloat(temp); 47 48 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] 49 & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 50 nnWeights[2] = Float.intBitsToFloat(temp); 51 52 temp = (((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] 53 & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 54 workModeAverage = Float.intBitsToFloat(temp); 55 56 trainCycles = (int)(((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) 57 | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 58 totalCorrect 59 = (int)(((params[i++] & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] 60 & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 61 totalTrainingExamples = (int)(((params[i++] 62 & 0xff) << 0) | ((params[i++] & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] 63 & 0xff) << 24)); 64 workModeBest = (int)(((params[i++] & 0xff) << 0) | ((params[i++] 65 & 0xff) << 8) | ((params[i++] & 0xff) << 16) | ((params[i++] & 0xff) << 24)); 66 67 68 } 69 70 71}
more processing code...
processing
1class box { 2 3 int xPos; 4 int yPos; 5 float xs; 6 float 7 ys; 8 float size; 9 float col; 10 float cMax; 11 float goodBoxRadius; 12 13 int classification; 14 int answer; 15 boolean kill; 16 boolean classified; 17 18 boolean inspected; 19 20 box(int xPos, int yPos, float cMax, float goodBoxRadius) 21 { 22 this.xPos = xPos; 23 this.yPos = yPos; 24 this.cMax = cMax; 25 26 this.goodBoxRadius = goodBoxRadius; 27 setSize(); 28 classification 29 = 0; 30 kill = false; 31 classified = false; 32 33 34 } 35 36 37 void incBoxPosX(int xInc) { 38 xPos += xInc; 39 } 40 41 void incBoxPosY(int 42 yInc) { 43 yPos += yInc; 44 } 45 46 void killBox() { 47 kill = 48 true; 49 } 50 51 void addClassifier(int classification) { 52 this.classification 53 = classification; 54 classified = true; 55 } 56 57 void addInspection() 58 { 59 inspected = true; 60 } 61 62 void setSize() { 63 //make the 64 box - set the answer... 65 66 boolean valid = false; 67 while(!valid) 68 { 69 xs = random(26, cMax*2); 70 ys = random(0, cMax*2); 71 float 72 vDist = sqrt((xs*xs) + (ys*ys)); 73 if (vDist < (goodBoxRadius*cMax)) { 74 75 int bc = (int) random(2); 76 if (bc==1) { 77 xs -= cMax; 78 79 ys -= cMax; 80 answer = -1; 81 } else { 82 float 83 txs = xs; 84 xs = (ys*-1)+cMax; 85 ys = (txs*-1)+cMax; 86 answer 87 = 1; 88 } 89 valid = true; 90 } 91 } 92 93 size 94 = xs / cMax; 95 col = ys /cMax; 96 97 98 } 99 100 101 102}
more processing code...
processing
1 2import java.util.Iterator; 3 4class factory { 5 6 ArrayList<box> 7 boxes = new ArrayList<box>(); 8 String name; 9 10 int trainCycles; 11 12 int totalTrainingExamples; 13 int totalCorrect; 14 float workModeAverage; 15 16 int workModeBest; 17 18 perceptron ptron; 19 int correct = 0; 20 int inspected 21 = 0; 22 float score = 0; 23 24 int lastUpload = 0; 25 26 float currentBoxSize 27 = -1; 28 float currentBoxCol = 0; 29 int currentGuess = 0; 30 31 // run 32 time params 33 int speed = 12; 34 float cMax = 400; 35 float goodBoxRadius 36 = 1.1; 37 38 boolean upLoaded; 39 40 factory(String name) { 41 42 43 this.name = name; 44 //this.goodBoxRadius = goodBoxRadius; 45 ///this.cMax 46 = cMax; 47 48 ptron = new perceptron(3, 0.0001); 49 boolean upLoaded 50 = false; 51 52 } 53 54 void run() { 55 56 // make new boxes 57 if 58 (boxes.size() < 1) 59 makeNewBox(); 60 else { 61 box b = boxes.get(boxes.size()-1); 62 63 if (b.xPos - b.size > 100) 64 makeNewBox(); 65 } 66 67 //update 68 all boxes 69 for (int i=0; i<boxes.size(); i++) { 70 box b = boxes.get(i); 71 72 // move the box along 73 b.incBoxPosX(speed); 74 // is the box 75 in the truck? if so then kill it 76 if (b.xPos > 900) { 77 b.killBox(); 78 79 } 80 // is the box in the inspector 81 if (b.xPos > 800 && 82 !b.inspected) { 83 inspected++; 84 if (b.answer == b.classification) 85 86 correct++; 87 score = 100.0 * float(correct)/float(inspected); 88 89 b.addInspection(); 90 } 91 // is the box in the robot? 92 if so then classifiy it 93 if (b.xPos > 550 && !b.classified) { 94 float[] 95 vecIn = {b.xs,b.ys,1.0}; 96 int c = ptron.feedforward(vecIn); 97 b.addClassifier(c); 98 99 currentBoxSize = b.size; 100 currentBoxCol = b.col; 101 currentGuess 102 = c; 103 } 104 } 105 106 // finally remove any killed boxes 107 Iterator<box> 108 boxesIterator = boxes.iterator(); 109 while (boxesIterator.hasNext()) { 110 box 111 b = boxesIterator.next(); 112 if (b.kill) 113 boxesIterator.remove(); 114 115 } 116 117 } 118 119 void makeNewBox() { 120 box b = new box(0, height/2, 121 cMax, goodBoxRadius); 122 boxes.add(b); 123 } 124 125 void setSpeed(int 126 speed) { 127 this.speed = speed; 128 } 129 130 void resetScores() { 131 132 correct = 0; 133 inspected = 0; 134 } 135}
more processing code...
processing
1// Daniel Shiffman 2// The Nature of Code 3// http://www.shiffman.net/teaching/nature 4// 5 Simple Perceptron Example 6// See: http://en.wikipedia.org/wiki/Perceptron 7 8// 9 Perceptron Class 10 11class perceptron { 12 float[] weights; // Array of weights 13 for inputs 14 float c; // learning constant 15 16 // Perceptron is 17 created with n weights and learning constant 18 perceptron(int n, float c_) { 19 20 weights = new float[n]; 21 // Start with random weights 22 //for (int 23 i = 0; i < weights.length; i++) { 24 // weights[i] = random(-1,1); 25 //} 26 27 // fix the wieghts to give the 50/50 case 28 weights[0] = -1; 29 weights[1] 30 = 1; 31 weights[2] = 0; 32 c = c_; 33 } 34 35 // Function to train 36 the Perceptron 37 // Weights are adjusted based on "desired" answer 38 void 39 train(float[] inputs, int desired) { 40 // Guess the result 41 int guess 42 = feedforward(inputs); 43 // Compute the factor for changing the weight based 44 on the error 45 // Error = desired output - guessed output 46 // Note this 47 can only be 0, -2, or 2 48 // Multiply by learning constant 49 float error 50 = desired - guess; 51 // Adjust weights based on weightChange * input 52 for 53 (int i = 0; i < weights.length; i++) { 54 weights[i] += c * error * inputs[i]; 55 56 } 57 } 58 59 // Guess -1 or 1 based on input values 60 int 61 feedforward(float[] inputs) { 62 // Sum all values 63 float sum = 0; 64 65 for (int i = 0; i < weights.length; i++) { 66 sum += inputs[i]*weights[i]; 67 68 } 69 // Result is sign of the sum, -1 or 1 70 return activate(sum); 71 72 } 73 74 int activate(float sum) { 75 if (sum > 0) return 1; 76 else 77 return -1; 78 } 79 80 // Return weights 81 float[] getWeights() { 82 83 return weights; 84 } 85 86 void setWeights(float[] weights) { 87 for 88 (int i=0; i<weights.length; i++) { 89 this.weights[i] = weights[i]; 90 } 91 92 } 93}
Downloadable files
Build instructions
Build instructions
Build instructions
Build instructions
Comments
Only logged in users can leave comments