SHARE
TWEET

Reasoning Realm v0.3.1

a guest Apr 26th, 2018 23 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <!DOCTYPE html>
  2. <!-- blah 2016-2017-2018 -->
  3. <html>
  4.   <head>
  5.     <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
  6.     <style>
  7.       canvas { /* Credit: http://stackoverflow.com/questions/7615009/disable-interpolation-when-scaling-a-canvas */
  8.         image-rendering: optimizeSpeed;
  9.         image-rendering: -moz-crisp-edges;
  10.         image-rendering: -webkit-optimize-contrast;
  11.         image-rendering: -o-crisp-edges;
  12.         image-rendering: pixelated;
  13.         -ms-interpolation-mode: nearest-neighbor;
  14.       }
  15.       .selMenuItem:hover {
  16.         background-color:rgba(255,255,255,0.1);
  17.       }
  18.       .selMenuItemHighlighted {
  19.         background-color:white;
  20.         color:black;
  21.       }
  22.       .button {
  23.         background-color:#111;
  24.         color:white;
  25.         cursor:pointer;
  26.         border:1px solid black;
  27.         border-radius:4px;
  28.         padding:0px 4px 0px 4px;
  29.       }
  30.       .button:hover {
  31.         background-color:white;
  32.         color:#111;
  33.       }
  34.       .button:active {
  35.         background-color:#555;
  36.         color:#ccc;
  37.       }
  38.       .number {
  39.         font-family:consolas,monospace;
  40.       }
  41.       body, .button { /* Credit: http://stackoverflow.com/questions/6900124/how-to-make-certain-text-not-selectable-with-css */
  42.         -webkit-user-select: none;
  43.         -moz-user-select: none;
  44.         -ms-user-select: none;
  45.       }
  46.       body {
  47.         color:white;
  48.         font-family:sans-serif;
  49.         font-size:12px;
  50.         background-color:black;
  51.         margin:0;
  52.       }
  53.       html, body {
  54.         height: 100%;
  55.       }
  56.       input {
  57.         background-color:#000000;
  58.         color:white;
  59.         border:1px solid #ffff00;
  60.         border-radius:3px;
  61.         font-family:consolas,monospace;
  62.       }
  63.       input:hover {
  64.         background-color:#111111;
  65.       }
  66.       textarea {
  67.         background-color:#000000;
  68.         color:white;
  69.         border:1px solid #ffff00;
  70.         border-radius:3px;
  71.         font-family:consolas,monospace;
  72.         font-size: 12px;
  73.         height:15px;
  74.         padding:1px 1px 1px 1px;
  75.       }
  76.       textarea:hover {
  77.         background-color:#111111;
  78.       }
  79.       a {
  80.         color:#ffffff;
  81.       }
  82.       h1 {
  83.         text-align:center;
  84.       }
  85.       h2 {
  86.         text-align:center;
  87.       }
  88.       h3 {
  89.         margin:0;
  90.         margin-top:4px;
  91.       }
  92.       p {
  93.         margin:5px 0px 5px 0px;
  94.       }
  95.       p.date {
  96.         margin:0;
  97.         font-size:8px;
  98.       }
  99.       .changelist {
  100.         margin:0;
  101.       }
  102.       #blah {
  103.         font-weight:bold;
  104.       }
  105.       #blah:hover {
  106.         font-size:55px;
  107.         animation: blahgod 0.4s infinite;
  108.         color:rgba(0,0,0,0);
  109.       }
  110.       @keyframes blahgod {
  111.         0% {
  112.           font-size:55px;
  113.           text-shadow:20px 20px 5px #ff0;
  114.         }
  115.         10% {
  116.           text-shadow:10px -30px 15px #f0f;
  117.         }
  118.         20% {
  119.           text-shadow:2px 5px 10px #fff;
  120.         }
  121.         30% {
  122.           text-shadow:30px 300px 0px #777;
  123.         }
  124.         50% {
  125.           font-size:85px;
  126.           text-shadow:1px 1px 1px #f00;
  127.         }
  128.         55% {
  129.           text-shadow:1px 1px 5px #000;
  130.         }
  131.         60% {
  132.           text-shadow:1px -100px 5px #fff;
  133.         }
  134.         100% {
  135.           font-size:55px;
  136.           text-shadow:20px 20px 5px #ff0;
  137.         }
  138.       }
  139.       #HELP {
  140.         width:100%;
  141.         height:100%;
  142.         z-index:-1;
  143.         opacity:0;
  144.         position:relative;
  145.         background-color:rgba(0,0,0,0.75);
  146.         overflow:auto;
  147.         margin:auto;
  148.         cursor:auto;
  149.         -webkit-user-select: text;
  150.         -moz-user-select: text;
  151.         -ms-user-select: text;
  152.         font-size:12px;
  153.       }
  154.       #helpInner {
  155.         margin:0px 5px 0px 5px;
  156.       }
  157.       #bottombar {
  158.         position:absolute;
  159.         bottom:-1px;
  160.         background-color:rgba(0,0,0,0.75);
  161.         width:100%;
  162.         line-height:20px;
  163.       }
  164.       #bottombarinner {
  165.         margin:3px 5px 5px 5px;
  166.       }
  167.       #infoarea {
  168.         position:absolute;
  169.         top:0;
  170.         right:0;
  171.         padding:0px 6px 2px 0px;
  172.         text-shadow:0px 0px 2px black;
  173.         text-align:right;
  174.       }
  175.       #appContainer {
  176.         position:relative;
  177.         width:100%;
  178.         height:100%;
  179.         cursor:default;
  180.         overflow:hidden;
  181.         background-color:#404040;
  182.       }
  183.       .toolsel, .toolselactivated {
  184.         padding-left:3px;
  185.       }
  186.       .toolselactivated {
  187.         background-color:white;
  188.         color:black;
  189.       }
  190.       .toolsel:hover {
  191.         background-color:rgba(255,255,255,0.1);
  192.       }
  193.       .key {
  194.         font-weight:bold;
  195.       }
  196.     </style>
  197.     <title>Reasoning Realm</title>
  198.     <script>
  199. var baseDT       = 16;    //The amount of milliseconds between each tick. Never changes.
  200. var worldX       = 64;    //Width of the world.
  201. var worldY       = 64;    //Height of the world.
  202. var cellList     = [];    //List of every cell in the world.
  203. var colours      = [];    //Colour scheme. Modified by setRule().
  204. var names        = [];    //Names belonging to those colours. Not all states actually have names, though. #notallstates
  205. var running      = true;  //You can pause the simulation using this.
  206. var zoom         = 8;     //each cell is zoom squared pixels
  207. var drawType     = 1;     //The selected state.
  208. var mouseIsDown  = false; //Used for clicking and dragging.
  209. var cameraPanX   = 0;     //for panning the camera.
  210. var cameraPanY   = 0;     //It's measured in cells. X=0,Y=0 is the center of the world, not a corner.
  211. var eorc         = true;  //This variable is used by the resize function. It is whether to expand or contract the world. It's global because it can get modified by a button
  212. var dir          = 0;     //Also used by the resize function. The direction of expansion.
  213. var rectPosY     = 0;     //Selection location. This is the top left corner
  214. var rectPosX     = 0;
  215. var rectSizeY    = 1;     //Dimensions of the selection. going down right
  216. var rectSizeX    = 1;
  217. var rectDragging = false; //Whether or not the player is dragging the selection, or if they're first making it
  218. // Player? I wrote that over a year ago, I guess. Weird, this isn't a game.
  219. // CA are no game. This is serious business. -blah 2018
  220. var rectDragX    = 8;     //For when you drag the selection; it's the location of the cursor relative to the top left corner of the selection.
  221. var rectDragY    = 8;
  222. var rectCellList = [];    //List of every cell in the selection.
  223. var rectExists   = false;
  224. var clipboard    = [      //For copy/paste functionality on the selection tool. nothing to see here move along
  225. [1,0,1,0,1,1,1,0,0,1,1,0,0,0,1,0,0,1,1,0], //The clipboard doesn't need length or height variables cause we can just use clipboard.length for Y and clipboard[0].length for X
  226. [1,1,1,0,0,1,0,0,0,1,0,1,0,1,1,1,0,1,0,1],
  227. [1,0,1,0,1,1,1,0,0,1,1,0,0,1,0,1,0,1,0,1]];
  228. var appHeight    = 512;   //The height of the entire app, in pixels.
  229. var appWidth     = 512;   //See appHeight
  230. var panning      = [false,false,false,false]; //It's an array of the four directions. If the value for left is true, the camera will be panning to the left. More than one can be true at the same time. Allows fluid panning.
  231. var transitions  = [      //Transition table. Initialised, as you can see, to B3/S23. This obviously supports generations rules if you try, but I use a different function because it's faster.
  232. [0,0,0,1,0,0,0,0,0],
  233. [0,0,1,1,0,0,0,0,0]];
  234. var speedDT      = 1;     //Optimal delta time (amount of time between frames) multiplied by (baseDT)ms
  235. var speedMult    = 1;     //Amount of iterations per frame.
  236. var tickCount    = 0;     //Used internally to work with speedDT. Like, if speedDT == 2, it'll use this to only simulate every other frame
  237. var rule         = "";    //Used for the 'rule = whatever' part of RLE savecodes
  238. var pauselock    = false; //See interrobang
  239. var sparse       = [];    //Sparse array containing all of the cells that may change from one generation to the next. Used by 'Ignore non-changing cells' algorithm
  240. var nextSparse   = [];
  241. var difference   = [];    //The tick function puts the list of every cell that should change into this, and then applies it.
  242. var algorithm    = 1;     //0 is sparse algorithm, 1 is brute force
  243. var generation   = 0;     //Amount of generations since the pattern was loaded.
  244. var gpscount     = 0;     //Used to get generations per second.
  245. var tool         = 0;     //The tool selected. 0 is pen, 1 is rect select, 2 is colour picker, 3 is drag camera
  246. var camDragX     = 0;     //For dragging the camera
  247. var camDragY     = 0;
  248. var numOfStates  = 0;
  249. //That was the variables. Now we start listing out functions.
  250.  
  251. function drawWorld(){ //Render the world. never use this unless there's some clear reason to, because it draws every cell in the world.
  252.   drawEmpty();
  253.   for (y=0; y < worldY; y++){
  254.     for (x=0; x < worldX; x++){
  255.       if(cellList[y][x] > 0){
  256.         drawCellAt(x,y);
  257.       }
  258.     }
  259.   }
  260. }
  261.  
  262. function drawCell(x,y,type){ //Use this if you already know what the cell's state will be (faster than having this look it up when you already know)
  263.   d[0]   = colours[type][0];
  264.   d[1]   = colours[type][1];
  265.   d[2]   = colours[type][2];
  266.   canvas.putImageData(id,x,y);
  267. }
  268.  
  269. function drawCellAt(x,y){ //Otherwise use this
  270.   drawCell(x,y,cellList[y][x]);
  271. }
  272.  
  273. function getCell(x,y){ //Is the cell at [x,y] within the field? if so return its type
  274.   if (x > -1 && x < worldX && y > -1 && y < worldY){
  275.     return cellList[y][x];
  276.   } else {
  277.     return 0;
  278.   }
  279. }
  280.  
  281. function vonNeumannNeighbours(x,y,type){ //Returns amount of cells equal to type within the Von Neumann neighbourhood of x,y
  282.   var count=0;
  283.   if(cellList[y][x-1] == type){
  284.     count++;
  285.   }
  286.   if(cellList[y-1] != undefined && cellList[y-1][x] == type){
  287.     count++;
  288.   }
  289.   if(cellList[y][x+1] == type){
  290.     count++;
  291.   }
  292.   if(cellList[y+1] != undefined && cellList[y+1][x] == type){
  293.     count++;
  294.   }
  295.   return count;
  296. }
  297.  
  298. function mooreNeighbours(x,y,type){ //Returns amount of cells equal to type within the Moore neighbourhood of x,y
  299.   var count=0;
  300.   var bottom = cellList[y+1] != undefined;
  301.   var top = cellList[y-1] != undefined;
  302.   if(cellList[y][x-1] == type){
  303.     count++;
  304.   }
  305.   if(top && cellList[y-1][x] == type){
  306.     count++;
  307.   }
  308.   if(cellList[y][x+1] == type){
  309.     count++;
  310.   }
  311.   if(bottom && cellList[y+1][x] == type){
  312.     count++;
  313.   }
  314.   if(top && cellList[y-1][x-1] == type){
  315.     count++;
  316.   }
  317.   if(bottom && cellList[y+1][x-1] == type){
  318.     count++;
  319.   }
  320.   if(top && cellList[y-1][x+1] == type){
  321.     count++;
  322.   }
  323.   if(bottom && cellList[y+1][x+1] == type){
  324.     count++;
  325.   }
  326.   return count;
  327. }
  328.  
  329. function hexNeighbours(x,y,type){ //Returns amount of cells equal to type within the Hexagonal neighbourhood of x,y
  330.   var count=0;
  331.   var bottom = cellList[y+1] != undefined;
  332.   var top = cellList[y-1] != undefined;
  333.   if(cellList[y][x-1] == type){
  334.     count++;
  335.   }
  336.   if(top && cellList[y-1][x] == type){
  337.     count++;
  338.   }
  339.   if(cellList[y][x+1] == type){
  340.     count++;
  341.   }
  342.   if(bottom && cellList[y+1][x] == type){
  343.     count++;
  344.   }
  345.   if(top && cellList[y-1][x-1] == type){
  346.     count++;
  347.   }
  348.   if(bottom && cellList[y+1][x+1] == type){
  349.     count++;
  350.   }
  351.   return count;
  352. }
  353.  
  354. function putCell(x,y,type){ //This is for things where the player is editing the canvas. Notice it uses the moore neighbourhood specifically, for the sparse algorithm that is.
  355.   drawCell(x,y,type);
  356.   cellList[y][x] = type;
  357.   if(algorithm == 0){
  358.     if(!inSparse(x,y)){
  359.       sparse.push(y,x);
  360.     }
  361.     if(!inSparse(x-1,y)){
  362.       sparse.push(y,x-1);
  363.     }
  364.     if(!inSparse(x+1,y)){
  365.       sparse.push(y,x+1);
  366.     }
  367.     if(!inSparse(x,y-1)){
  368.       sparse.push(y-1,x);
  369.     }
  370.     if(!inSparse(x+1,y-1)){
  371.       sparse.push(y-1,x+1);
  372.     }
  373.     if(!inSparse(x-1,y-1)){
  374.       sparse.push(y-1,x-1);
  375.     }
  376.     if(!inSparse(x,y+1)){
  377.       sparse.push(y+1,x);
  378.     }
  379.     if(!inSparse(x+1,y+1)){
  380.       sparse.push(y+1,x+1);
  381.     }
  382.     if(!inSparse(x-1,y+1)){
  383.       sparse.push(y+1,x-1);
  384.     }
  385.   }
  386. }
  387.  
  388. function setCell(x,y,type){ //This is for the tick function.
  389.   drawCell(x,y,type);
  390.   difference.push(y,x,type);
  391.   if(algorithm == 0){
  392.     padSparse(x,y);
  393.   }
  394. }
  395.  
  396. function padSparseMoore(x,y){
  397.   if(!inSparse(x,y)){
  398.     nextSparse.push(y,x);
  399.   }
  400.   if(!inSparse(x-1,y)){
  401.     nextSparse.push(y,x-1);
  402.   }
  403.   if(!inSparse(x+1,y)){
  404.     nextSparse.push(y,x+1);
  405.   }
  406.   if(!inSparse(x,y-1)){
  407.     nextSparse.push(y-1,x);
  408.   }
  409.   if(!inSparse(x+1,y-1)){
  410.     nextSparse.push(y-1,x+1);
  411.   }
  412.   if(!inSparse(x-1,y-1)){
  413.     nextSparse.push(y-1,x-1);
  414.   }
  415.   if(!inSparse(x,y+1)){
  416.     nextSparse.push(y+1,x);
  417.   }
  418.   if(!inSparse(x+1,y+1)){
  419.     nextSparse.push(y+1,x+1);
  420.   }
  421.   if(!inSparse(x-1,y+1)){
  422.     nextSparse.push(y+1,x-1);
  423.   }
  424. }
  425.  
  426. function padSparseJvN(x,y){
  427.   if(!inSparse(x,y)){
  428.     nextSparse.push(y,x);
  429.   }
  430.   if(!inSparse(x-1,y)){
  431.     nextSparse.push(y,x-1);
  432.   }
  433.   if(!inSparse(x+1,y)){
  434.     nextSparse.push(y,x+1);
  435.   }
  436.   if(!inSparse(x,y-1)){
  437.     nextSparse.push(y-1,x);
  438.   }
  439.   if(!inSparse(x,y+1)){
  440.     nextSparse.push(y+1,x);
  441.   }
  442. }
  443.  
  444. function applyDifference(){
  445.   for(i=0;i<difference.length;i+=3){
  446.     cellList[difference[i]][difference[i+1]] = difference[i+2];
  447.   }
  448. }
  449.  
  450. function inSparse(x,y){
  451.   for(ib=0;ib<nextSparse.length;ib+=2){
  452.     if(nextSparse[ib] == y && nextSparse[ib+1] == x){
  453.       return true;
  454.     }
  455.   }
  456.   return false;
  457. }
  458.  
  459. function fillSparse(){
  460.   for(y=0;y<worldY;y++){
  461.     for(x=0;x<worldX;x++){
  462.       sparse.push(y,x);
  463.     }
  464.   }
  465. }
  466.  
  467. //Transition functions.
  468.  
  469. function transLife(x,y){ //Lifelike rules
  470.   return transitions[cellList[y][x]][typeNeighbours(x,y,1)];
  471. }
  472.  
  473. function transGenerations(x,y){ //Generations rules
  474.   cell = cellList[y][x];
  475.   if(cell<2){
  476.     return transitions[cell][typeNeighbours(x,y,1)];
  477.   } else if(cell==colours.length-1) {
  478.     return 0;
  479.   } else {
  480.     return cell+1;
  481.   }
  482. }
  483.  
  484. function transLL(x,y){ //Logic land
  485.   cell = cellList[y][x];
  486.   if(cell == 0){ //Empty Space
  487.     //Do nothing. Faster than running through all the other conditions, even if it requires an empty block.
  488.   } else if(cell == 1 && (vonNeumannNeighbours(x,y,2) > 0 || vonNeumannNeighbours(x,y,16) > 0 )){ //Inactive Wire
  489.     return 2;
  490.   } else if(cell == 2 && (vonNeumannNeighbours(x,y,3) > 0 || vonNeumannNeighbours(x,y,10))){ //Active Wire
  491.     return 3;
  492.   } else if(cell == 3){ //Inhibited Wire
  493.     return 1;
  494.   } else if(cell == 4){ //Cross Over. This one is complex and inefficient, so don't use Crossovers to speed up wires, cause it slows the simulation down in the long term.
  495.     if(x>0 && x < worldX-1 && y>0 &&  y < worldY-1 ){
  496.       friends = [cellList[y][x-1], cellList[y-1][x], cellList[y][x+1], cellList[y+1][x]];
  497.       friendLocs = [y,x-1,y-1,x,y,x+1,y+1,x];
  498.       for(i=0;i<4;i++){
  499.         if(friends[i] == 2 && friends[(i+2)%4] == 1){
  500.           setCell(friendLocs[((i+2)%4)*2+1],friendLocs[((i+2)%4)*2],2);
  501.         }
  502.         if(friends[i] == 3 && friends[(i+2)%4] == 2){
  503.           setCell(friendLocs[((i+2)%4)*2+1],friendLocs[((i+2)%4)*2],3);
  504.         }
  505.       }
  506.     }
  507.     return 4;
  508.   } else if(cell > 4 && cell < 9 && vonNeumannNeighbours(x,y,2) > 0){ //Inactive gates
  509.     return cell+6;
  510.   } else if(cell > 10 && cell < 15 && vonNeumannNeighbours(x,y,2) == 0){ //Active gates
  511.     return cell-6;
  512.   } else if(cell == 15 && vonNeumannNeighbours(x,y,3) > 0){ //Active T-flip flop
  513.     return 9;
  514.   } else if(cell == 9 && vonNeumannNeighbours(x,y,3) > 0){ //Inactive T-flip flop
  515.     return 15;
  516.   } else if(cell == 10 || cell == 16){ //Gate output
  517.     if(vonNeumannNeighbours(x,y,11) > 0 || vonNeumannNeighbours(x,y,5) > 0){ //NOR
  518.       if(vonNeumannNeighbours(x,y,11) == 0){
  519.         return 16;
  520.       } else {
  521.         return 10;
  522.       }
  523.     } else if(vonNeumannNeighbours(x,y,12) > 0 || vonNeumannNeighbours(x,y,6) > 0){ //OR
  524.       if(vonNeumannNeighbours(x,y,12) > 0){
  525.         return 16;
  526.       } else {
  527.         return 10;
  528.       }
  529.     } else if(vonNeumannNeighbours(x,y,13) > 0 || vonNeumannNeighbours(x,y,7) > 0){ //XOR
  530.       if(vonNeumannNeighbours(x,y,13) == 1){
  531.         return 16;
  532.       } else {
  533.         return 10;
  534.       }
  535.     } else if(vonNeumannNeighbours(x,y,14) > 0 || vonNeumannNeighbours(x,y,8) > 0){ //AND
  536.       if(vonNeumannNeighbours(x,y,8) == 0){
  537.         return 16;
  538.       } else {
  539.         return 10;
  540.       }
  541.     } else if(vonNeumannNeighbours(x,y,15) > 0 || vonNeumannNeighbours(x,y,9) > 0){ //T flip flop
  542.       if(vonNeumannNeighbours(x,y,9) > 0){
  543.         return 10;
  544.       } else {
  545.         return 16;
  546.       }
  547.     }
  548.   }
  549.   return cell;
  550. }
  551.  
  552. function transNorwire(x,y){ //Norwire. It's a secret rule, it isn't even in the changelog.
  553.   cell = cellList[y][x];
  554.   if(cell == 0){ //Empty Space
  555.     return 0;
  556.   } else if(cell == 1) { //Inactive Wire
  557.     if(vonNeumannNeighbours(x,y,2) > 0 || vonNeumannNeighbours(x,y,7)){
  558.       return 2;
  559.     }
  560.   } else if(cell == 2){ //Active Wire
  561.     if(vonNeumannNeighbours(x,y,3) > 0 || vonNeumannNeighbours(x,y,5)){
  562.       return 3;
  563.     }
  564.   } else if(cell == 3){ //Inhibited Wire
  565.     return 1;
  566.   } else if(cell == 4 || cell == 6){ //Gate input
  567.     if(vonNeumannNeighbours(x,y,2) > 0){
  568.       return 6;
  569.     }
  570.     return 4;
  571.   } else { //Gate output
  572.     if(vonNeumannNeighbours(x,y,4) > 0){
  573.       return 7;
  574.     }
  575.     return 5;
  576.   }
  577.   return cell;
  578. }
  579.  
  580. function transInst(x,y){ //Rychl√°dr√°t
  581.   cell = cellList[y][x];
  582.   if(cell == 0){ //Empty Space
  583.     return 0;
  584.   } else if(cell==3) {
  585.     //instSet(x,y,1,2);
  586.     if(!instNeighbours(x,y)){
  587.       instSet(x,y,2,1);
  588.       return 9;
  589.     }
  590.   } else if(cell==9) {
  591.     //instSet(x,y,2,1);
  592.     if(instNeighbours(x,y)){
  593.       instSet(x,y,1,2);
  594.       return 3;
  595.     }
  596.     //Logic gate inputs.
  597.   } else if(cell==4 || cell==10) { // NOR
  598.     if(vonNeumannNeighbours(x,y,2) > 0){
  599.       return 4;
  600.     } else {
  601.       return 10;
  602.     }
  603.   } else if(cell==5 || cell==11) { // OR
  604.     if(vonNeumannNeighbours(x,y,2) > 0){
  605.       return 11;
  606.     } else {
  607.       return 5;
  608.     }
  609.   } else if(cell==6 || cell==12) { // AND
  610.     if(vonNeumannNeighbours(x,y,1) == 0){
  611.       return 12;
  612.     } else {
  613.       return 6;
  614.     }
  615.   } else if(cell==7 || cell==13) { // NAND
  616.     if(vonNeumannNeighbours(x,y,1) == 0){
  617.       return 7;
  618.     } else {
  619.       return 13;
  620.     }
  621.   } else if(cell==8 || cell==14) { // XOR
  622.     if(vonNeumannNeighbours(x,y,2) == 1){
  623.       return 14;
  624.     } else {
  625.       return 8;
  626.     }
  627.   } else if(cell==15 || cell==16) { // switch
  628.     if(vonNeumannNeighbours(x,y,9) > 0){
  629.       return 15;
  630.     } else {
  631.       return 16;
  632.     }
  633.   }
  634.   return cell;
  635. }
  636. function instNeighbours(x,y){
  637.   if(cellList[y][x-1] > 9 && cellList[y][x-1] < 15){
  638.     return true;
  639.   }
  640.   if(cellList[y-1][x] > 9 && cellList[y-1][x] < 15){
  641.     return true;
  642.   }
  643.   if(cellList[y][x+1] > 9 && cellList[y][x+1] < 15){
  644.     return true;
  645.   }
  646.   if(cellList[y+1][x] > 9 && cellList[y+1][x] < 15){
  647.     return true;
  648.   }
  649.   return false;
  650. }
  651. function instSetCell(x,y,type){
  652.   difference.push(y,x,type);
  653.   if(cellList[y][x] != type){
  654.     drawCell(x,y,type);
  655.     padSparse(x,y);
  656.   }
  657. }
  658. function instSet(x,y,oldstate,newstate){
  659.   var loc = y-1;
  660.   var cellatloc = getCell(x,loc);
  661.   while(cellatloc == 1 || cellatloc == 2 || cellatloc == 16 || cellatloc == 17){
  662.     if(cellatloc != 16 && cellatloc != 17){
  663.       instSetCell(x,loc,newstate);
  664.     }
  665.     loc--;
  666.     cellatloc = getCell(x,loc);
  667.   }
  668.   var loc = y+1;
  669.   var cellatloc = getCell(x,loc);
  670.   while(cellatloc == 1 || cellatloc == 2 || cellatloc == 16 || cellatloc == 17){
  671.     if(cellatloc != 16 && cellatloc != 17){
  672.       instSetCell(x,loc,newstate);
  673.     }
  674.     loc++;
  675.     cellatloc = getCell(x,loc);
  676.   }
  677.   var loc = x-1;
  678.   cellatloc = getCell(loc,y);
  679.   while(cellatloc == 1 || cellatloc == 2 || cellatloc == 16 || cellatloc == 17){
  680.     if(cellatloc != 16 && cellatloc != 17){
  681.       instSetCell(loc,y,newstate);
  682.     }
  683.     loc--;
  684.     cellatloc = getCell(loc,y);
  685.   }
  686.   var loc = x+1;
  687.   cellatloc = getCell(loc,y);
  688.   while(cellatloc == 1 || cellatloc == 2 || cellatloc == 16 || cellatloc == 17){
  689.     if(cellatloc != 16 && cellatloc != 17){
  690.       instSetCell(loc,y,newstate);
  691.     }
  692.     loc++;
  693.     cellatloc = getCell(loc,y);
  694.   }
  695. }
  696.  
  697. function transLifeHistory(x,y){
  698.   cell = cellList[y][x];
  699.   if(cell == 0 || cell == 2){ //Empty Space
  700.     if(histNays(x,y) == 3){
  701.       return 1;
  702.     }
  703.   } else if(cell == 1){
  704.     if(!(histNays(x,y) == 2) && !(histNays(x,y) == 3)){ //aaaaa so inneficient I know
  705.       return 2;
  706.     }
  707.   } else if(cell == 3 || cell == 5){
  708.     if(!(histNays(x,y) == 2) && !(histNays(x,y) == 3)){ //aaaaa so inneficient I know
  709.       return 4;
  710.     }
  711.   } else if(cell == 4){
  712.     if(histNays(x,y) == 3){
  713.       return 3;
  714.     }
  715.   }
  716.   return cell;
  717. }
  718. function histNays(x,y){ //neighbour function for LifeHistory
  719.   var count=0;
  720.   var bottom = cellList[y+1] != undefined;
  721.   var top = cellList[y-1] != undefined;
  722.   if(cellList[y][x-1]%2 == 1){
  723.     count++;
  724.   }
  725.   if(top && cellList[y-1][x]%2 == 1){
  726.     count++;
  727.   }
  728.   if(cellList[y][x+1]%2 == 1){
  729.     count++;
  730.   }
  731.   if(bottom && cellList[y+1][x]%2 == 1){
  732.     count++;
  733.   }
  734.   if(top && cellList[y-1][x-1]%2 == 1){
  735.     count++;
  736.   }
  737.   if(bottom && cellList[y+1][x-1]%2 == 1){
  738.     count++;
  739.   }
  740.   if(top && cellList[y-1][x+1]%2 == 1){
  741.     count++;
  742.   }
  743.   if(bottom && cellList[y+1][x+1]%2 == 1){
  744.     count++;
  745.   }
  746.   return count;
  747. }
  748.  
  749. function transCyclic(x,y){ // Cyclic Cellular Automata
  750.   cell = cellList[y][x];
  751.   if(typeNeighbours(x,y,(cell+1)%numOfStates)>0){
  752.     return (cell+1)%numOfStates;
  753.   }
  754.   return cell;
  755. }
  756.  
  757. function transWire(x,y){ // Generalised Wire Automata
  758.   cell = cellList[y][x];
  759.   if(cell == 0){ //Empty Space
  760.     return 0;
  761.   } else if(cell<3) { //Electron Head/Tail
  762.     return cell+1;
  763.   } else { //Copper Wire
  764.     nays = typeNeighbours(x,y,1);
  765.     return transitions[0][nays]
  766.   }
  767.   return cell;
  768. }
  769.  
  770. function tick(){
  771.   if(!pauselock){
  772.     for(var framegen=0;framegen<speedMult;framegen++){
  773.       generation++;
  774.       document.getElementById("genNum").innerHTML = generation;
  775.       difference = [];
  776.       if(algorithm == 0){
  777.         nextSparse = [];
  778.         for(var si=0;si<sparse.length;si+=2){
  779.           var y = sparse[si];
  780.           var x = sparse[si+1];
  781.           if(y>=0 && y<worldY && x>=0 && x<worldX){
  782.             var newCell = transFunc(x,y);
  783.             if(newCell != cellList[y][x]){
  784.               setCell(x,y,newCell);
  785.             }
  786.           }
  787.         }
  788.         sparse = nextSparse.slice();
  789.  
  790.       } else if(algorithm == 1){
  791.         for(var y=0;y<worldY;y++){
  792.           for(var x=0;x<worldX;x++){
  793.             var newCell = transFunc(x,y);
  794.             if(newCell != cellList[y][x]){
  795.               setCell(x,y,newCell);
  796.             }
  797.           }
  798.         }
  799.       }
  800.       applyDifference();
  801.     }
  802.   }
  803. }
  804.  
  805. function mouseDown(event){ //Event called when the mouse gets first pressed
  806.   mouseIsDown = true;
  807.   cellx = Math.floor((event.clientX - crect.left)/zoom);
  808.   celly = Math.floor((event.clientY - crect.top)/zoom);
  809.   if(tool == 1){
  810.     if(cellx >= rectPosX && celly >= rectPosY && cellx <= rectPosX+rectSizeX && celly <= rectPosY+rectSizeY && rectExists){ //If you clicked on the selection
  811.       rectDragging = true;
  812.       rectDragX = cellx-rectPosX;
  813.       rectDragY = celly-rectPosY;
  814.     } else {
  815.       finishSelection();
  816.       rectExists = false;
  817.       rectDragging = false;
  818.       rectPosX = cellx;
  819.       rectPosY = celly;
  820.       rectSizeX = 0;
  821.       rectSizeY = 0;
  822.     }
  823.   } else if(tool == 0) {
  824.     if (cellx > -1 && cellx < worldX && celly > -1 && celly < worldY){ //If the mouse is over the play area
  825.       putCell(cellx,celly,drawType);
  826.     }
  827.   } else if(tool == 2){
  828.     changeDrawType(getCell(cellx,celly));
  829.     changeTool(0);
  830.   } else if(tool == 3){
  831.     camDragX = -((event.clientX - crect.left)/zoom - worldX/2)*2;
  832.     camDragY = -((event.clientY -  crect.top)/zoom - worldY/2)*2;
  833.   }
  834. }
  835.  
  836. function mouseMove(event){ //When the mouse moves (not just over the canvas, which is how you can draw behind the ui)
  837.   cellx = Math.floor((event.clientX - crect.left)/zoom); //Mathematics to get the cell you clicked on.
  838.   celly = Math.floor((event.clientY - crect.top)/zoom);
  839.   if (mouseIsDown && (cellx > -1 && cellx < worldX && celly > -1 && celly < worldY)){ //If the mouse is over the play area and the mouse is down
  840.     if(tool == 0){ // Pen Tool
  841.       putCell(cellx,celly,drawType);
  842.     } else if(tool == 1){ // Selection Tool
  843.       if(!rectDragging) { //Selection gets resized as the user drags the mouse
  844.         unDrawSelectionBox();
  845.         rectSizeX = cellx-rectPosX;
  846.         rectSizeY = celly-rectPosY;
  847.         drawSelectionBox();
  848.         displaySelectionDim();
  849.       } else { //Selection gets moved as player drags the mouse
  850.         if(cellx-rectDragX >= 0 && celly-rectDragY >= 0 && (cellx-rectDragX)+rectSizeX < worldX && (celly-rectDragY)+rectSizeY < worldY){ //If the selection would be moved to a place inside the world.
  851.           unDrawSelectionBox();
  852.           unDrawSelection();
  853.           rectPosX = cellx-rectDragX;
  854.           rectPosY = celly-rectDragY;
  855.           drawSelectionBox();
  856.           drawSelection();
  857.         }
  858.       }
  859.     }
  860.   }
  861.   if(tool == 3 && mouseIsDown){ // Drag Camera Tool
  862.     cameraPanX = (event.clientX -  appWidth/2)*2/zoom + camDragX; //Not sure how this works but I did it.
  863.     cameraPanY = (event.clientY - appHeight/2)*2/zoom + camDragY;
  864.     moveCanvas();
  865.   }
  866. }
  867.  
  868. function mouseUp(event){
  869.   mouseIsDown = false;
  870.   if(tool == 1 && !rectDragging && (cellx > -1 && cellx < worldX && celly > -1 && celly < worldY)){ //selection tool, finish making the selection
  871.     if(rectSizeX < 0){ //If the size is negative make it positve and move it over so our loops can handle it
  872.       rectPosX += rectSizeX;
  873.       rectSizeX = rectSizeX-rectSizeX-rectSizeX;
  874.     }
  875.     if(rectSizeY < 0){
  876.       rectPosY += rectSizeY;
  877.       rectSizeY = rectSizeY-rectSizeY-rectSizeY;
  878.     }
  879.     rectCellList = []; //We will create a list, rectCellList, of all the selected cells. This is useful
  880.     for(y=0;y<=rectSizeY;y++){
  881.       rectCellList[y] = [];
  882.       for(x=0;x<=rectSizeX;x++){
  883.         rectCellList[y][x] = cellList[y+rectPosY][x+rectPosX];
  884.         cellList[y+rectPosY][x+rectPosX] = 0;
  885.       }
  886.     }
  887.     rectExists = true;
  888.   }
  889. }
  890.  
  891. function unDrawSelection(){
  892.   for(var y=0;y<=rectSizeY;y++){
  893.     for(var x=0;x<=rectSizeX;x++){
  894.       if(rectCellList[y][x] != 0){
  895.         drawCellAt(x+rectPosX, y+rectPosY);
  896.       }
  897.     }
  898.   }
  899. }
  900.  
  901. function drawSelection(){ //Self explanatory.
  902.   for(var y=0;y<=rectSizeY;y++){
  903.     for(var x=0;x<=rectSizeX;x++){
  904.       if(rectCellList[y][x] != 0){
  905.         drawCell(x+rectPosX, y+rectPosY,rectCellList[y][x]);
  906.       }
  907.     }
  908.   }
  909. }
  910.  
  911. function finishSelection(){ //Places the selection into the world.
  912.   if(rectExists){
  913.     unDrawSelectionBox();
  914.     for(var y=0;y<=rectSizeY;y++){
  915.       for(var x=0;x<=rectSizeX;x++){
  916.         if(rectCellList[y][x] != 0){
  917.           putCell(x+rectPosX, y+rectPosY, rectCellList[y][x]);
  918.         }
  919.       }
  920.     }
  921.   }
  922. }
  923.  
  924. function drawSelectionBox(){ //It's poorly made but it works
  925.   canvas.beginPath();
  926.   canvas.strokeStyle = "#008888";
  927.   canvas.fillStyle = "#008888";
  928.   canvas.fillRect(rectPosX,rectPosY,1,1); //I have to fill in the corners myself because drawRect is antialiased. Innefficient I know
  929.   canvas.fillRect(rectPosX+rectSizeX,rectPosY,1,1);
  930.   canvas.fillRect(rectPosX,rectPosY+rectSizeY,1,1);
  931.   canvas.fillRect(rectPosX+rectSizeX,rectPosY+rectSizeY,1,1);
  932.   canvas.rect(rectPosX+0.5,rectPosY+0.5,rectSizeX,rectSizeY);
  933.   canvas.stroke();
  934. }
  935.  
  936. function unDrawSelectionBox(){ //replaces the pixels of the selection with the cells behind them. Simply put, undraws the selection box. Called when it has to be resized or moved or replaced or etc
  937.   for(y=0;y<=Math.abs(rectSizeY);y++){
  938.     if(rectSizeY >= 0){
  939.       drawCellAt(rectPosX, y+rectPosY);
  940.       drawCellAt(rectPosX+rectSizeX, y+rectPosY);
  941.     } else {
  942.       drawCellAt(rectPosX, rectPosY-y);
  943.       drawCellAt(rectPosX+rectSizeX, rectPosY-y);
  944.     }
  945.   }
  946.   for(x=0;x<=Math.abs(rectSizeX);x++){
  947.     if(rectSizeX >= 0){
  948.       drawCellAt(x+rectPosX, rectPosY);
  949.       drawCellAt(rectPosX+x, rectPosY+rectSizeY);
  950.     } else {
  951.       drawCellAt(rectPosX-x, rectPosY);
  952.       drawCellAt(rectPosX-x, rectPosY+rectSizeY);
  953.     }
  954.   }
  955. }
  956.  
  957. function displaySelectionDim(){
  958.   document.getElementById("rectdisy").innerHTML = Math.abs(rectSizeY)+1;
  959.   document.getElementById("rectdisx").innerHTML = Math.abs(rectSizeX)+1;
  960. }
  961.  
  962. function checkSelection(){ //If the selectioh is partially or fully out of the world, this moves it back in bounds.
  963.   if(rectPosX+rectSizeX>=worldX){
  964.     rectPosX = worldX-rectSizeX-1;
  965.   }
  966.   if(rectPosY+rectSizeY>=worldY){
  967.     rectPosY = worldY-rectSizeY-1;
  968.   }
  969. }
  970.  
  971. function changeZoom(n){ //It scales the canvas itself.
  972.   if(n>0){ //We don't want to be able to set zoom to 0, or -1, or whatever
  973.     zoom = n;
  974.     c.style.width = worldX * n + "px"; //Note the difference between c.width and c.style.width. This is only how big it appears.
  975.     c.style.height = worldY * n + "px";
  976.     document.getElementById("zoomCounter").innerHTML=zoom; //Display the level of zoom. Pretty obvious
  977.     moveCanvas()
  978.   }
  979. }
  980.  
  981. function changeDT(newDT){
  982.   if(newDT > 0){
  983.     speedDT = newDT;
  984.     document.getElementById("DTcounter").innerHTML = speedDT*baseDT+"ms ("+Math.round(1000/(speedDT*baseDT))+"fps)";
  985.   }
  986. }
  987.  
  988. function changeSpeedMult(newmult){
  989.   if(newmult > 0){
  990.     speedMult = newmult;
  991.     document.getElementById("multCounter").innerHTML = speedMult;
  992.   }
  993. }
  994.  
  995. function changeDrawType(newDrawType){ //Called by the items in the menu to the top left
  996.   if(newDrawType<names.length){
  997.     document.getElementById("sel"+drawType).className = "selMenuItem";
  998.     document.getElementById("sel"+newDrawType).className = "selMenuItemHighlighted";
  999.     drawType = newDrawType;
  1000.   }
  1001. }
  1002.  
  1003. function pausePlay(){ //This function pauses the sim if it's playing, plays it if it's paused
  1004.   if(!pauselock){
  1005.     running = !running;
  1006.     if(running){
  1007.       document.getElementById("pauseDisplay").innerHTML = "Pause";
  1008.     } else {
  1009.       document.getElementById("pauseDisplay").innerHTML = "Unpause";
  1010.     }
  1011.   }
  1012. }
  1013.  
  1014. function pauseLock(){
  1015.   pauselock = !pauselock;
  1016.   if(pauselock){
  1017.     document.getElementById("pauseLockDisplay").innerHTML = "Unlock";
  1018.   } else {
  1019.     document.getElementById("pauseLockDisplay").innerHTML = "Lock";
  1020.   }
  1021. }
  1022.  
  1023. //PLAGIARISED SAVECODE FUNCTIONS. cred to jack e (He didn't leave many comments on his code. I indented it myself)
  1024. var saveCodeCharacterSet = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  1025. var LLRRdiff = [0,1,2,3,4,5,11,6,12,7,13,8,14,9,15,10,16]; //Used to convert between Logic Land's cell values and Reasoning Realm's
  1026. var RRLLdiff = [0,1,2,3,4,5,7,9,11,13,15,6,8,10,12,14,16]; //Used to convert the other way. It's the inverse
  1027.  
  1028. function convertNumberIntoSaveCodeCharacter(number){
  1029.   return saveCodeCharacterSet.substring(number, number + 1);
  1030. }
  1031.  
  1032. function convertSaveCodeCharacterIntoNumber(character){
  1033.   return saveCodeCharacterSet.indexOf(character);
  1034. }
  1035.  
  1036. function convertSaveCodeIntoNumberList(text){
  1037.   var output = [];
  1038.   var index = 0;
  1039.   while (index < text.length){
  1040.     var tempCharacter = text.substring(index, index + 1);
  1041.     if (tempCharacter == "*"){
  1042.       tempCharacter = text.substring(index + 1, index + 2);
  1043.       var count = convertSaveCodeCharacterIntoNumber(tempCharacter);
  1044.       tempCharacter = text.substring(index + 2, index + 3);
  1045.       var tempNumber = convertSaveCodeCharacterIntoNumber(tempCharacter);
  1046.       while (count > 0){
  1047.         output.push(tempNumber);
  1048.         count -= 1;
  1049.       }
  1050.       index += 3;
  1051.     } else {
  1052.       var tempNumber = convertSaveCodeCharacterIntoNumber(tempCharacter);
  1053.       output.push(tempNumber);
  1054.       index += 1;
  1055.     }
  1056.   }
  1057.   //BEGIN SELF INSERT YEAH. This part converts the cell list of Logic Land, which seems to be 1D, to the two dimensional array format Reasoning Realm uses
  1058.   //It also converts between the cell type values.
  1059.   newOutput = [];
  1060.   for(y=0;y<worldY;y++){
  1061.     newOutput[y] = [];
  1062.     for(x=0;x<worldX;x++){
  1063.       newOutput[y][x] = LLRRdiff[output[y*worldX+x]];
  1064.     }
  1065.   }
  1066.   //END SELF INSERT NO
  1067.   return newOutput;
  1068. }
  1069.  
  1070. function setSaveCode(text){
  1071.   var startIndex = 0;
  1072.   while (text.substring(startIndex, startIndex + 1) == " ")
  1073.   {
  1074.     startIndex += 1;
  1075.   }
  1076.   var endIndex = text.length;
  1077.   while (text.substring(endIndex - 1, endIndex) == " ")
  1078.   {
  1079.     endIndex -= 1;
  1080.   }
  1081.   var tempIndex = text.indexOf("/");
  1082.   var tempList = text.substring(0, tempIndex).split(",");
  1083.   worldX = parseInt(tempList[0]);
  1084.   worldY = parseInt(tempList[1]);
  1085.   c.height = worldY;
  1086.   c.width = worldX;
  1087.   c.style.height = worldY*zoom+"px";
  1088.   c.style.width = worldX*zoom+"px";
  1089.   var tempText = text.substring(tempIndex + 1, text.length);
  1090.   cellList = convertSaveCodeIntoNumberList(tempText);
  1091.   drawWorld();
  1092.   //Set the world dimension display
  1093.   document.getElementById("worldXDisplay").innerHTML = worldX;
  1094.   document.getElementById("worldYDisplay").innerHTML = worldY;
  1095. }
  1096.  
  1097. function convertNumberListIntoSaveCode(numberList){
  1098.   var output = "";
  1099.   var startIndex = 0;
  1100.   var endIndex = 0;
  1101.   while (startIndex < numberList.length){
  1102.     endIndex = startIndex + 1;
  1103.     var startNumber = numberList[startIndex];
  1104.     var tempCharacter = convertNumberIntoSaveCodeCharacter(startNumber);
  1105.     var count = 1;
  1106.     while (endIndex < numberList.length && numberList[endIndex] == startNumber && count < saveCodeCharacterSet.length - 1){
  1107.       endIndex += 1;
  1108.       count += 1;
  1109.     }
  1110.     if (count < 4){
  1111.       while (count > 0){
  1112.       output += tempCharacter;
  1113.       count -= 1;
  1114.       }
  1115.     } else {
  1116.       var tempCharacter2 = convertNumberIntoSaveCodeCharacter(count);
  1117.       output += "*" + tempCharacter2 + tempCharacter;
  1118.     }
  1119.     startIndex = endIndex;
  1120.   }
  1121.   return output;
  1122. }
  1123.  
  1124. function displaySaveCode(){
  1125.   var saveCode = worldX + "," + worldY + "/";
  1126.   //SELF INSERT AGAIN. Just a reversed version of the other one. Converts 2d array into 1d so Jack's code will work on it
  1127.   newInput = [];
  1128.   for(y=0;y<worldY;y++){
  1129.     for(x=0;x<worldX;x++){
  1130.       newInput[y*worldX+x] = RRLLdiff[cellList[y][x]]; //Convert between value types and all
  1131.     }
  1132.   }
  1133.   //END SELF INSERT
  1134.   saveCode += convertNumberListIntoSaveCode(newInput);
  1135.   document.getElementById("RRFbox").value = saveCode;
  1136. }
  1137. //END PLAGIARY
  1138.  
  1139. keycodes = [0,0,0,0,0,0,0,0,0,0];
  1140.  
  1141. function keyPress(event){ //When a key is pressed, called by body.
  1142.   if(document.activeElement.nodeName != 'TEXTAREA' && document.activeElement.nodeName != 'INPUT'){ //Ignore key presses if a text box is selected. Credit: http://stackoverflow.com/questions/4575266/find-if-a-textbox-is-currently-selected
  1143.     var key = event.which;
  1144.     for(k=0;k<9;k++){
  1145.       keycodes[k] = keycodes[k+1];
  1146.     }
  1147.     keycodes[9] = key;
  1148.     if(keycodes[0] == 38 && keycodes[1] == 38 && keycodes[2] == 40 && keycodes[3] == 40 && keycodes[4] == 37 && keycodes[5] == 39 && keycodes[6] == 37 && keycodes[7] == 39 && keycodes[8] == 66 && keycodes[9] == 65 ){
  1149.       alert("Gullible.");
  1150.     }
  1151.     if(key == 32){ //Space (Pause)
  1152.       pausePlay();
  1153.     } else if(key == 37 || key == 65){ //Left cursor key (Pan left)
  1154.       startPan(0);
  1155.     } else if(key == 38 || key == 87){ //Up cursor key (Pan up)
  1156.       startPan(1);
  1157.     } else if(key == 39 || key == 68){ //Right cursor key (Pan right)
  1158.       startPan(2);
  1159.     } else if(key == 40 || key == 83){ //Down cursor key (Pan down)
  1160.       startPan(3);
  1161.     } else if(key >= 48 && key <= 57){ //Number keys (Set drawType)
  1162.       changeDrawType(key-48);
  1163.       changeTool(0);
  1164.     } else if(key == 82){ //R key (Select tool)
  1165.       changeTool(1);
  1166.     } else if(key == 79){ //O key (Zoom out)
  1167.       if(zoom>1){
  1168.         changeZoom(zoom-1);
  1169.       }
  1170.     } else if(key == 73){ //I key (Zoom in)
  1171.       changeZoom(zoom+1);
  1172.     } else if(key == 70){ //F key (Simulate one frame)
  1173.       if(!pauselock){tick()};
  1174.     } else if(key == 67){ //C key (Copy selection to clipboard)
  1175.       if(tool == 1){
  1176.         clipboard = JSON.parse(JSON.stringify(rectCellList)); //Makes clipboard into a deep clone of rectCellList
  1177.       }
  1178.     } else if(key == 86){ //V key (Paste clipboard to selection)
  1179.       if(tool == 1){
  1180.         if(clipboard[0].length>worldX || clipboard.length>worldY){
  1181.           alert("You tried to paste from the clipboard, but the world is too small to fit the contents of the clipboard. It doesn't matter where you tried to paste it, you have to expand the world. :^(");
  1182.           return 0;
  1183.         }
  1184.         finishSelection();
  1185.         rectCellList = JSON.parse(JSON.stringify(clipboard)); //Does the exact reverse of C
  1186.         rectSizeX = clipboard[0].length-1;
  1187.         rectSizeY = clipboard.length-1;
  1188.         displaySelectionDim();
  1189.         checkSelection();
  1190.         drawSelectionBox();
  1191.         drawSelection();
  1192.       }
  1193.     } else if (key == 69 || key == 88){ //E+X keys (Clear/cut selection)
  1194.       if(tool == 1){
  1195.         if(key == 88){ //X key (Cut)
  1196.           clipboard = JSON.parse(JSON.stringify(rectCellList)); //Makes clipboard into a deep clone of rectCellList
  1197.         } //E and X both clear. that's what this part does:
  1198.         unDrawSelection();
  1199.         drawSelectionBox();
  1200.         for(y=0;y<=rectSizeY;y++){
  1201.           for(x=0;x<=rectSizeX;x++){
  1202.             rectCellList[y][x] = 0;
  1203.           }
  1204.         }
  1205.       }
  1206.     } else if(key == 173){ //- key (Gate output)
  1207.       changeDrawType(10);
  1208.       changeTool(0);
  1209.     } else if(key == 219){ //[ key (Half zoom)
  1210.       changeZoom(Math.round(zoom/2));
  1211.     } else if(key == 221){ //] key (Double zoom)
  1212.       changeZoom(zoom*2);
  1213.     } else if(key == 77){ //M key (Mirror)
  1214.       if(tool == 1){
  1215.         var newList = []
  1216.         unDrawSelection();
  1217.         for(y=0;y<=rectSizeY;y++){
  1218.           newList[rectSizeY-y] = rectCellList[y].slice();
  1219.         }
  1220.         for(y=0;y<=rectSizeY;y++){
  1221.           rectCellList[y] = newList[y].slice();
  1222.         }
  1223.         drawSelectionBox();
  1224.         drawSelection();
  1225.       }
  1226.     } else if(key == 78){ //N key (Mirror)
  1227.       if(tool == 1){
  1228.         var newList = [];
  1229.         unDrawSelection();
  1230.         for(y=0;y<=rectSizeY;y++){
  1231.           newList[y] = [];
  1232.           for(x=0;x<=rectSizeX;x++){
  1233.             newList[y][rectSizeX-x] = rectCellList[y][x];
  1234.           }
  1235.         }
  1236.         for(y=0;y<=rectSizeY;y++){
  1237.           rectCellList[y] = newList[y].slice();
  1238.         }
  1239.         drawSelectionBox();
  1240.         drawSelection();
  1241.       }
  1242.     } else if(key == 84){ //T key (Rotate)
  1243.       if(tool == 1){
  1244.         if(rectSizeX>=worldY || rectSizeY>=worldX){
  1245.           alert("The world is too small to rotate the selection.");
  1246.           return 0;
  1247.         }
  1248.         var newList = [];
  1249.         unDrawSelection();
  1250.         unDrawSelectionBox();
  1251.         for(y=0;y<=rectSizeY;y++){
  1252.           newList[y] = [];
  1253.           for(x=0;x<=rectSizeX;x++){
  1254.             newList[y][rectSizeX-x] = rectCellList[y][x];
  1255.           }
  1256.         }
  1257.         for(y=0;y<=rectSizeY;y++){
  1258.           rectCellList[y] = newList[y].slice();
  1259.         }
  1260.  
  1261.         var newList = [];
  1262.         for(y=0;y<=rectSizeX;y++){
  1263.           newList[y] = [];
  1264.           for(x=0;x<=rectSizeY;x++){
  1265.             newList[y][x] = rectCellList[x][y];
  1266.           }
  1267.         }
  1268.         rectCellList = [];
  1269.         for(y=0;y<=newList.length-1;y++){
  1270.           rectCellList[y] = newList[y].slice();
  1271.         }
  1272.         rectSizeY = rectCellList.length-1;
  1273.         rectSizeX = rectCellList[0].length-1;
  1274.         displaySelectionDim();
  1275.         checkSelection();
  1276.         drawSelectionBox();
  1277.         drawSelection();
  1278.       }
  1279.     } else if(key == 81){ //Q key (Empty space)
  1280.       changeDrawType(0);
  1281.       changeTool(0);
  1282.     } else if(key == 72){ //H key (Center camera)
  1283.       centerCamera();
  1284.     } else if(key == 74){ //J key (Drag camera tool)
  1285.       changeTool(3);
  1286.     } else if(key == 90){ //Z key (State 17)
  1287.       changeDrawType(17);
  1288.       changeTool(0);
  1289.     } else if(key == 192){ //` key (Random fill)
  1290.       if(tool == 1){
  1291.         unDrawSelection();
  1292.         for(y=0;y<=rectSizeY;y++){
  1293.           for(x=0;x<=rectSizeX;x++){
  1294.             rectCellList[y][x] = Math.floor(Math.random()*(drawType+1));
  1295.           }
  1296.         }
  1297.         drawSelectionBox();
  1298.         drawSelection();
  1299.       }
  1300.     }
  1301.   }
  1302. }
  1303.  
  1304. function keyUp(event){
  1305.   var key = event.which;
  1306.   if(key == 37 || key == 65){ //Left cursor key (pan left)
  1307.     endPan(0);
  1308.   } else if(key == 38 || key == 87){ //Up cursor key (pan up)
  1309.     endPan(1);
  1310.   } else if(key == 39 || key == 68){ //Right cursor key (pan right)
  1311.     endPan(2);
  1312.   } else if(key == 40 || key == 83){ //Down cursor key (pan down)
  1313.     endPan(3);
  1314.   }
  1315. }
  1316.  
  1317. function startPan(dir){
  1318.   panning[dir] = true;
  1319. }
  1320. function endPan(dir){
  1321.   panning[dir] = false;
  1322. }
  1323.  
  1324. function continuousPan(){ //This is called every 50 milliseconds by the script at the end of this file.
  1325.   if(panning[0] || panning[1] || panning[2] || panning[3]){
  1326.     var panAmt = 128/zoom;
  1327.     if(panning[0]){
  1328.       cameraPanX += panAmt;
  1329.     }
  1330.     if(panning[1]){
  1331.       cameraPanY += panAmt;
  1332.     }
  1333.     if(panning[2]){
  1334.       cameraPanX -= panAmt;
  1335.     }
  1336.     if(panning[3]){
  1337.       cameraPanY -= panAmt;
  1338.     }
  1339.     moveCanvas();
  1340.   }
  1341. }
  1342.  
  1343. function pan(dir){ //This one is used by the arrow buttons in the menu.
  1344.   var panAmt = 128/zoom;
  1345.   if(dir == 0){
  1346.     cameraPanX += panAmt;
  1347.   } else if(dir == 1){
  1348.     cameraPanY += panAmt;
  1349.   } else if(dir == 2){
  1350.     cameraPanX -= panAmt;
  1351.   } else if(dir == 3){
  1352.     cameraPanY -= panAmt;
  1353.   }
  1354.   moveCanvas();
  1355. }
  1356.  
  1357. function resize(){ //Expand/contract (depending on eorc) in direction "dir" by amount "amt"
  1358.   var amt = Number(document.getElementById('expandAmount').value); //The number in the text box for the amount.
  1359.   var tempList = []; //This array is concatenated with cellList and/or its subarrays to expand the world
  1360.   //A large collection of ifs and elseifs that change the dimensions of the world, and then some operations to make sure it's drawn and rendered properly
  1361.   //Due to the nature of the 2D array, it turns out the elseif chain isn't that repetitive
  1362.   if(eorc){
  1363. //Expand left:
  1364.     if(dir == 0){
  1365.       for(i=0;i<amt;i++){
  1366.         tempList[i] = 0;
  1367.       }
  1368.       for(y=0;y<worldY;y++){ //Templist, which is a row of amt 0s, gets concatenated with each row. horizontal expansion.
  1369.         cellList[y] = tempList.concat(cellList[y]);
  1370.       }
  1371.       worldX += amt;
  1372. //Expand up:
  1373.     } else if(dir == 1){
  1374.       for(y=0;y<amt;y++){ //Templist will become a bunch of rows
  1375.         tempList[y] = [];
  1376.         for(x=0;x<worldX;x++){
  1377.           tempList[y][x] = 0;
  1378.         }
  1379.       }
  1380.       worldY += amt;
  1381.       cellList = tempList.concat(cellList); //templist gets concatenated to cellList
  1382. //Expand right:
  1383.     } else if(dir == 2){
  1384.       for(i=0;i<amt;i++){
  1385.         tempList[i] = 0;
  1386.       }
  1387.       for(y=0;y<worldY;y++){
  1388.         cellList[y] = cellList[y].concat(tempList);
  1389.       }
  1390.       worldX += amt;
  1391. //Expand down:
  1392.     } else if(dir == 3){
  1393.       for(y=0;y<amt;y++){ //this is line 420 right now lol
  1394.         cellList[worldY+y] = [];
  1395.         for(x=0;x<worldX;x++){
  1396.           cellList[worldY+y][x] = 0;
  1397.         }
  1398.       }
  1399.       worldY += amt;
  1400.     }
  1401.   } else {
  1402. //Contract from left:
  1403.     if(dir == 0){
  1404.       for(y=0;y<worldY;y++){
  1405.         cellList[y] = cellList[y].slice(amt);
  1406.       }
  1407.       worldX -= amt;
  1408. //contract from top:
  1409.     } else if(dir == 1){
  1410.       cellList = cellList.slice(amt);
  1411.       worldY -= amt;
  1412. //Contract from right:
  1413.     } else if(dir == 2){
  1414.       for(y=0;y<worldY;y++){
  1415.         cellList[y] = cellList[y].slice(0,worldX-amt);
  1416.       }
  1417.       worldX -= amt;
  1418. //Contract from bottom:
  1419.     } else if(dir == 3){
  1420.       cellList = cellList.slice(0, worldY-amt);
  1421.       worldY -= amt;
  1422.     }
  1423.   }
  1424.   c.height = worldY; //Estabish logical dimensions of the canvas after the resize.
  1425.   c.width = worldX;
  1426.   changeZoom(zoom); //The changezoom function does some things we're too lazy to put here
  1427.   drawWorld(); //Then we probably have to redraw, to be sure
  1428.   document.getElementById("worldXDisplay").innerHTML = worldX;
  1429.   document.getElementById("worldYDisplay").innerHTML = worldY;
  1430.   rectPosX = 0;
  1431.   rectPosY = 0;
  1432.   rectSizeX = 0;
  1433.   rectSizeY = 0;
  1434.   rectCellList = [[0]];
  1435.   if(algorithm == 0){
  1436.     fillSparse();
  1437.   }
  1438. }
  1439.  
  1440. function eorcf(){ //This function gets used by the button that expands or contracts the world. the f is for function
  1441.   eorc = !eorc;
  1442.   if(eorc){
  1443.     document.getElementById("eorcDisplay").innerHTML = "Expand";
  1444.   } else {
  1445.     document.getElementById("eorcDisplay").innerHTML = "Contract";
  1446.   }
  1447. }
  1448.  
  1449. var Dirnames = ["Left","Top","Right","Bottom"]; //Used to set the text of the direction button on the resize menu
  1450.  
  1451. function dirf(){ //The direction of expanding/contracting. the f is for function
  1452.   dir = (dir+1) % 4; //Cycles dir between 0,1,2,3
  1453.   document.getElementById("dirDisplay").innerHTML = Dirnames[dir]; //Use of Dirnames.
  1454. }
  1455.  
  1456. function moveCanvas(){
  1457.   c.style.left = Math.round(((worldX+cameraPanX)/2 *zoom)+ appWidth/2 - worldX*zoom) + "px";
  1458.   c.style.top = Math.round(((worldY+cameraPanY)/2 *zoom)+ appHeight/2 - worldY*zoom) + "px";
  1459.   crect = c.getBoundingClientRect(); //We know that this will (probably) change crect so we can reestablish it now
  1460. }
  1461.  
  1462. function clearWorld(){
  1463.   var row = [];
  1464.   for(x=0;x<worldX;x++){
  1465.     row[x] = 0;
  1466.   }
  1467.   cellList = [];
  1468.   for(y= -1;y<=worldY;y++){
  1469.     cellList[y] = row.slice();
  1470.   }
  1471.   drawEmpty();
  1472. }
  1473.  
  1474. function drawEmpty(){ //Draws the colour of state 0 everywhere. Useful in some places.
  1475.   canvas.fillStyle = "rgb("+colours[0]+")";
  1476.   canvas.fillRect(0,0,worldX,worldY);
  1477. }
  1478.  
  1479. var rleValues = ".ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  1480. function getRLE(subject,height,width){ //A very elegant function
  1481.   var output = "";
  1482.   var runLength = 0;
  1483.   var runType = 0;
  1484.   var dollarcount = 1; // his shirt was made out of MONEY SIGNS his lips were also VERY important xD
  1485.   var outlen = 0; // No I won't explain that comment
  1486.   var dollarnote = "";
  1487.   if(numOfStates == 2){
  1488.     var rleValuesGet = "bo";
  1489.   } else {
  1490.     var rleValuesGet = ".ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  1491.   }
  1492.  
  1493.   for(y=0;y<height;y++){
  1494.     runType = subject[y][0];
  1495.     runLength = 0;
  1496.     outlen = output.length;
  1497.     for(x=0;x<width;x++){
  1498.       if(subject[y][x] == runType){
  1499.         runLength++;
  1500.       } else {
  1501.         if(runLength>1){
  1502.           output += runLength;
  1503.         }
  1504.         output += rleValuesGet.charAt(runType);
  1505.         runLength = 1;
  1506.         runType = subject[y][x];
  1507.       }
  1508.     }
  1509.     if(runType != 0){
  1510.       if(runLength>1){
  1511.         output += runLength;
  1512.       }
  1513.       output += rleValuesGet.charAt(runType);
  1514.     }
  1515.     if(y>0){ //So we don't put a $ at the beginning
  1516.       if(outlen == output.length){ // This tells us if anything has been added. This way we can run length encode the $s! in fleek
  1517.         dollarcount++;
  1518.       } else {
  1519.         dollarnote = "";
  1520.         if(dollarcount>1){
  1521.           dollarnote += dollarcount;
  1522.         }
  1523.         dollarnote += "$";
  1524.         dollarcount = 1;
  1525.         output=output.substr(0,outlen) + dollarnote + output.substr(outlen);
  1526.       }
  1527.     }
  1528.   }
  1529.  
  1530.   output="x = "+width+", y = "+height+", rule = "+rule+"\n"+output+"!";
  1531.   document.getElementById('RLEbox').value = output;
  1532. }
  1533.  
  1534. function setRLE(text){
  1535.   var input = text.split("\n").filter(function(line){return line != "" && line.substring(0,1) != "#"});
  1536.   input[0] = input[0].replace(/ /g, "").split(",");
  1537.   worldX = Number(input[0][0].slice(2));
  1538.   worldY = Number(input[0][1].slice(2));
  1539.   if(input[0].length > 2){
  1540.     setRule(input[0][2].slice(5),false);
  1541.   } else {
  1542.     setRule("B3/S23",false);
  1543.   }
  1544.   input[0] = "";
  1545.   input = input.join("");
  1546.   c.height = worldY;
  1547.   c.width = worldX;
  1548.   c.style.height = worldY*zoom+"px";
  1549.   c.style.width = worldX*zoom+"px";
  1550.   clearWorld();
  1551.   document.getElementById("worldXDisplay").innerHTML = worldX;
  1552.   document.getElementById("worldYDisplay").innerHTML = worldY;
  1553.   var numberHoldString = "";
  1554.   var numberHoldInt = 1;
  1555.   var headX = 0;
  1556.   var headY = 0;
  1557.   var unterminated = true;
  1558.   for(index=0;index<input.length && unterminated;index++){
  1559.     var charat = input.charAt(index);
  1560.     if(charat == "$"){
  1561.       headX = 0;
  1562.       headY += numberHoldInt;
  1563.     } else if(charat == "." || charat == "b"){
  1564.       headX += numberHoldInt;
  1565.     } else if(charat == "o" || charat == "A"){
  1566.       for(i=0;i<numberHoldInt && headX < worldX;i++){
  1567.         cellList[headY][headX] = 1;
  1568.         drawCell(headX,headY,1);
  1569.         headX++;
  1570.       }
  1571.     } else {
  1572.       var charatloc = rleValues.indexOf(charat)
  1573.       if(charatloc > 1){
  1574.         for(i=0;i<numberHoldInt;i++){
  1575.           cellList[headY][headX] = charatloc;
  1576.           drawCell(headX,headY,charatloc);
  1577.           headX++;
  1578.         }
  1579.       } else if(charat == "!"){
  1580.         unterminated = true;
  1581.       }
  1582.     }
  1583.  
  1584.     if(input.charCodeAt(index) >= 48 && input.charCodeAt(index) <= 57){
  1585.       numberHoldString=numberHoldString+charat;
  1586.       numberHoldInt = Number(numberHoldString);
  1587.     } else {
  1588.       numberHoldInt = 1;
  1589.       numberHoldString = "";
  1590.     }
  1591.   }
  1592. }
  1593. // shoutout to simpleflips
  1594. function setRule(newRulestring,sanitise){
  1595.   var rulestring = newRulestring.toLowerCase();
  1596.   if(rulestring=="wireworld"){
  1597.       setRule("Wire12",true);
  1598.       return;
  1599.   } else if(rulestring=="bliptile"){
  1600.       setRule("Wire1v",true);
  1601.       return;
  1602.   }
  1603.  
  1604.   if(rulestring == "logicland"){ //Logic Land
  1605.     colours = [[150,230,230],[225,128,50],[255,255,0],[110,64,25],[128,128,128],[150,0,150],[255,255,255],[0,0,255],[255,0,0],[0,128,0],[0,0,0],[150,0,150],[255,255,255],[0,0,255],[255,0,0],[0,128,0],[0,0,0]];
  1606.     names = ["Empty Space","Inactive Wire","Active Wire","Inhibited Wire","Cross Over","NOR Gate","OR Gate","XOR Gate","AND Gate","T Flip Flop","Gate Output"];
  1607.     createSelMenu();
  1608.     transFunc = transLL;
  1609.     padSparse = padSparseJvN;
  1610.     newRulestring = "LogicLand";
  1611.   } else if(rulestring == "norwire"){ //Secret rule
  1612.     colours = [[0,127,0],[64,0,0],[255,0,0],[0,0,0],[160,80,0],[127,50,0],[160,80,0],[255,50,0]];
  1613.     names = ["Empty Space","Inactive Wire","Active Wire","Inhibited Wire","Gate Input","Gate Output"];
  1614.     createSelMenu();
  1615.     transFunc = transNorwire;
  1616.     padSparse = padSparseMoore;
  1617.   } else if(rulestring == "rychl√°dr√°t" || rulestring == "rychladrat"){ //instant wire thing
  1618.     colours = [[0,0,0],[64,64,64],[255,255,255],[37,37,69],[150,0,150],[150,150,0],[250,0,0],[0,250,250],[0,0,250],[32,32,64],[155,5,155],[155,155,5],[255,5,5],[5,255,255],[5,5,255],[0,127,0],[0,255,0],[127,127,127]];
  1619.     names = ["Empty Space","Inactive Wire","Active Wire","Gate Output","NOR Gate","OR Gate","AND Gate","NAND Gate","XOR Gate","Gate Output","NOR Gate","OR Gate","AND Gate","NAND Gate","XOR Gate","Inactive Switch","Active Switch","Insulated Wire"];
  1620.     createSelMenu();
  1621.     transFunc = transInst;
  1622.     padSparse = padSparseJvN;
  1623.     newRulestring = "Rychl√°dr√°t";
  1624.   } else if(rulestring == "lifehistory"){ //LifeHistory
  1625.     colours = [[48,48,48],[0,255,0],[0,0,128],[216,255,216],[255,0,0],[255,255,0],[96,96,96]];
  1626.     names = ["Dead Cell","Live Cell","History","Marked Live Cell","Marked Dead Cell","Start Live Cell","Wall"];
  1627.     createSelMenu();
  1628.     transFunc = transLifeHistory;
  1629.     padSparse = padSparseMoore;
  1630.     newRulestring = "LifeHistory";
  1631.  
  1632. } else if(rulestring.slice(0,6) == "cyclic"){ // Cyclic Cellular Automata
  1633.  
  1634.     // Isn't copying and pasting large sections of code just the worst?
  1635.     // It is.
  1636.     if(rulestring.slice(-1) == "v"){
  1637.       typeNeighbours = vonNeumannNeighbours;
  1638.       padSparse = padSparseJvN;
  1639.       rulestring=rulestring.slice(0,-1);
  1640.     } else if(rulestring.slice(-1) == "h"){
  1641.       typeNeighbours = hexNeighbours;
  1642.       padSparse = padSparseMoore;
  1643.       rulestring=rulestring.slice(0,-1);
  1644.     } else {
  1645.       padSparse = padSparseMoore;
  1646.       typeNeighbours = mooreNeighbours;
  1647.     }
  1648.  
  1649.     colours = [];
  1650.     names = [];
  1651.     numOfStates = Number(rulestring.slice(6));
  1652.     for(i=0;i<numOfStates;i++){
  1653.       var hue = HSVtoRGB(360*(i/numOfStates),1,1)
  1654.       colours[i] = [hue.r,hue.g,hue.b];
  1655.       names[i] = "State "+i;
  1656.     }
  1657.     createSelMenu();
  1658.     transFunc = transCyclic;
  1659.     padSparse = padSparseMoore;
  1660. } else if(rulestring.slice(0,4) == "wire"){ // Generalised Wire Automata
  1661.     // just the worst
  1662.     if(rulestring.slice(-1) == "v"){
  1663.       typeNeighbours = vonNeumannNeighbours;
  1664.       padSparse = padSparseJvN;
  1665.       rulestring=rulestring.slice(0,-1);
  1666.     } else if(rulestring.slice(-1) == "h"){
  1667.       typeNeighbours = hexNeighbours;
  1668.       padSparse = padSparseMoore;
  1669.       rulestring=rulestring.slice(0,-1);
  1670.     } else {
  1671.       padSparse = padSparseMoore;
  1672.       typeNeighbours = mooreNeighbours;
  1673.     }
  1674.     for(n=0;n<=8;n++){
  1675.       if(rulestring.includes(n)){
  1676.         transitions[0][n] = 1;
  1677.       } else {
  1678.         transitions[0][n] = 3;
  1679.       }
  1680.     }
  1681.     colours = [[0,0,0],[0,128,255],[255,255,255],[255,128,0]];
  1682.     names = ["Empty Space","Electron Head","Electron Tail","Copper Wire"];
  1683.     createSelMenu();
  1684.     transFunc = transWire;
  1685.   } else { //Try to interpret the rulestring as lifelike or generations.
  1686.     var splitrule = rulestring.split("/");
  1687.     if(splitrule.length == 2) { //Lifelike rules
  1688.       var bloc = rulestring.indexOf("b");
  1689.       var sloc = rulestring.indexOf("s");
  1690.       if(bloc>=sloc){ //Figuring out the order of the survival and birth conditions in the rulestring.
  1691.         splitrule[2] = splitrule[0];
  1692.         splitrule[0] = splitrule[1];
  1693.         splitrule[1] = splitrule[2];
  1694.       }
  1695.       for(t=0;t<=1;t++){
  1696.         for(n=0;n<=8;n++){
  1697.           if(splitrule[t].includes(n)){
  1698.             transitions[t][n] = 1;
  1699.           } else {
  1700.             transitions[t][n] = 0;
  1701.           }
  1702.         }
  1703.       }
  1704.       if(rulestring.slice(-1) == "v"){ //Shoutout to http://stackoverflow.com/questions/3884632/how-to-get-the-last-character-of-a-string#3884711
  1705.         typeNeighbours = vonNeumannNeighbours;
  1706.         padSparse = padSparseJvN;
  1707.       } else if(rulestring.slice(-1) == "h"){
  1708.         typeNeighbours = hexNeighbours;
  1709.         padSparse = padSparseMoore;
  1710.       } else {
  1711.         typeNeighbours = mooreNeighbours;
  1712.         padSparse = padSparseMoore;
  1713.       }
  1714.       colours = [[255,255,255],[0,0,0]];
  1715.       names = ["Dead Cell","Live Cell"];
  1716.       createSelMenu();
  1717.       transFunc = transLife;
  1718.  
  1719.  
  1720.     } else if(splitrule.length == 3){ //Generations rules
  1721.       if(rulestring.slice(-1) == "v"){
  1722.         typeNeighbours = vonNeumannNeighbours;
  1723.         padSparse = padSparseJvN;
  1724.         splitrule[2]=splitrule[2].slice(0,-1);
  1725.       } else if(rulestring.slice(-1) == "h"){
  1726.         typeNeighbours = hexNeighbours;
  1727.         padSparse = padSparseMoore;
  1728.         splitrule[2]=splitrule[2].slice(0,-1);
  1729.       } else {
  1730.         padSparse = padSparseMoore;
  1731.         typeNeighbours = mooreNeighbours;
  1732.       }
  1733.       var states = Number(splitrule[2]);
  1734.       if(isNaN(states) || states < 3){
  1735.         alert("Generations rule cannot be interpreted because the third parameter is invalid.");
  1736.         return 0;
  1737.       }
  1738.       //Now we know this is a rule we can interpret properly
  1739.       splitrule[-1] = splitrule[0]; //We have to swap b and s because I'm lazy
  1740.       splitrule[0] = splitrule[1];
  1741.       splitrule[1] = splitrule[-1];
  1742.       for(t=0;t<=1;t++){
  1743.         for(n=0;n<=8;n++){
  1744.           if(splitrule[t].includes(n)){
  1745.             transitions[t][n] = 1;
  1746.           } else {
  1747.             transitions[t][n] = 0+t+t;
  1748.           }
  1749.         }
  1750.       }
  1751.       colours = [[10,10,10],[0,0,255]];
  1752.       names = ["Dead Cell","Live Cell"];
  1753.       for(i=2;i<states;i++){
  1754.         var hue = 255-Math.round(255*(i/states));
  1755.         colours[i] = [Math.floor(hue/3),hue,0];
  1756.         names[i] = "Refractory";
  1757.       }
  1758.       createSelMenu();
  1759.       transFunc = transGenerations;
  1760.       padSparse = padSparseMoore;
  1761.     }
  1762.   }
  1763.   if(tickCount != 0 && sanitise){
  1764.     for(y=0;y<worldY;y++){
  1765.       for(x=0;x<worldX;x++){
  1766.         if(cellList[y][x] >= names.length){
  1767.           cellList[y][x] = 1;
  1768.         }
  1769.       }
  1770.     }
  1771.   }
  1772.   if(drawType >= names.length){
  1773.     drawType = 0;
  1774.   }
  1775.   changeDrawType(drawType);
  1776.   rule = newRulestring;
  1777.   numOfStates = colours.length;
  1778.   document.getElementById("ruledis").innerHTML = rule;
  1779. }
  1780.  
  1781. function createSelMenu(){
  1782.   selMenu.innerHTML="";
  1783.   for(i=0;i<names.length;i++){ //This loop generates the menu.
  1784.     selMenu.innerHTML = selMenu.innerHTML +
  1785.     '<div onmousedown="changeDrawType('+i+')" id="sel'+i+'" class="selMenuItem"><span style="background-color:rgb('+colours[i]+');padding:0px 4px 0px 4px;">¬†</span>'+i+' '+names[i]+'</div>';
  1786.   }
  1787. }
  1788.  
  1789. function centerCamera(){
  1790.   cameraPanX=0;
  1791.   cameraPanY=0;
  1792.   moveCanvas();
  1793. }
  1794.  
  1795. function changeAlgorithm(){
  1796.   if(algorithm == 0){
  1797.     algorithm = 1;
  1798.     document.getElementById("changealgobutton").innerHTML = "Brute¬†Force";
  1799.   } else {
  1800.     algorithm = 0;
  1801.     fillSparse();
  1802.     document.getElementById("changealgobutton").innerHTML = "Ignore¬†Non¬†Changing¬†Cells";
  1803.   }
  1804. }
  1805.  
  1806. function changeTool(newTool){
  1807.   if(newTool != tool){
  1808.     if(tool == 1){
  1809.       finishSelection();
  1810.       rectExists = false;
  1811.     }
  1812.     document.getElementById("tool-"+tool).className = "toolsel";
  1813.     tool = newTool;
  1814.     document.getElementById("tool-"+tool).className = "toolselactivated";
  1815.   }
  1816. }
  1817. //aaaaa
  1818. //http://stackoverflow.com/a/31490738
  1819. function mix(a, b, v)
  1820. {
  1821.     return (1-v)*a + v*b;
  1822. }
  1823.  
  1824. function HSVtoRGB(H, S, V)
  1825. {
  1826.     var V2 = V * (1 - S);
  1827.     var r  = ((H>=0 && H<=60) || (H>=300 && H<=360)) ? V : ((H>=120 && H<=240) ? V2 : ((H>=60 && H<=120) ? mix(V,V2,(H-60)/60) : ((H>=240 && H<=300) ? mix(V2,V,(H-240)/60) : 0)));
  1828.     var g  = (H>=60 && H<=180) ? V : ((H>=240 && H<=360) ? V2 : ((H>=0 && H<=60) ? mix(V2,V,H/60) : ((H>=180 && H<=240) ? mix(V,V2,(H-180)/60) : 0)));
  1829.     var b  = (H>=0 && H<=120) ? V2 : ((H>=180 && H<=300) ? V : ((H>=120 && H<=180) ? mix(V2,V,(H-120)/60) : ((H>=300 && H<=360) ? mix(V,V2,(H-300)/60) : 0)));
  1830.  
  1831.     return {
  1832.         r : Math.round(r * 255),
  1833.         g : Math.round(g * 255),
  1834.         b : Math.round(b * 255)
  1835.     };
  1836. }
  1837.  
  1838. function setPattern(text){
  1839.     fc=text.substring(0,1);
  1840.     if(fc=="1"||fc=="2"||fc=="3"||fc=="4"||fc=="5"||fc=="6"||fc=="7"||fc=="8"||fc=="9"){
  1841.         setRule("LogicLand");
  1842.         setSaveCode(text);
  1843.     } else {
  1844.         setRLE(text);
  1845.     }
  1846.     moveCanvas();
  1847.     fillSparse();
  1848.     generation = 0;
  1849.     document.getElementById("genNum").innerHTML = 0;
  1850. }
  1851.     </script>
  1852.   </head>
  1853.   <body onkeydown="keyPress(event)" onkeyup="keyUp(event)" onmouseup="mouseUp(event)">
  1854.     <div id="appContainer" onmousemove="mouseMove(event)">
  1855.       <canvas height="64" width="64" id="display" onmousedown="mouseDown(event)" style="width:512px;height:512px;position:absolute;left:100px;font-size:32px;">This text displays if you have javascript disabled, or I guess if your browser doesn't support canvases. If it is the latter please reconsider your life choices.</canvas>
  1856.       <div style="position:absolute;top:0px;left:0px;background-color:rgba(0,0,0,0.75);border-bottom-right-radius:4px;" id="elementSelector">
  1857.         <div id="tools">
  1858.           <div onmousedown="changeTool(0)" id="tool-0" class="toolselactivated" title="Draws single cells with the selected state.">Pen Tool</div>
  1859.           <div onmousedown="changeTool(1)" id="tool-1" class="toolsel" title="Hotkey R. Allows you to select and manipulate rectangles. You can click and drag selections to move them. N and M to mirror horizontally and vertically. T to rotate. X to cut, C to copy, V to paste (no ctrl, because browsers are finnicky with keys like that). E to erase selection. Glitchy.">Select Tool</div>
  1860.           <div onmousedown="changeTool(2)" id="tool-2" class="toolsel" title="Selects whatever element you clicked on and selects the pen tool when you click. Note it may not work in specific cases like Logic Land where some states aren't in the menu, and you try to pick one of those hidden states.">Colour Picker</div>
  1861.           <div onmousedown="changeTool(3)" id="tool-3" class="toolsel" title="i just didn't expect it to be so BIG. :O">Drag Camera</div>
  1862.         </div>
  1863.         <hr />
  1864.         <span id="elements"></span>
  1865.       </div>
  1866.       <div id="infoarea" onmousedown="mouseDown(event)">
  1867.         V0.3.1
  1868.         <!-- THE VERSION NUMBER IS HERE. Making it so it's easy to see in the source code. -->
  1869.         by blah,
  1870.         <a style="text-decoration:none;" href="http://www.ostracodfiles.com/logic/logicland.html">Inspired by Jack Eisenmann</a>
  1871.         <span class="button" onclick="help.style.zIndex='0';help.style.opacity='1'">‚ÄĹ</span><br />
  1872.         World:
  1873.         <span class="number" id="worldXDisplay">64</span>x<span class="number" id="worldYDisplay">64</span><br />
  1874.         Selection:
  1875.         <span class="number" id="rectdisx">420</span>x<span class="number" id="rectdisy">69</span><br />
  1876.         Generation <span class="number" id="genNum">413</span>, <span class="number" id="gpsdisplay">612</span> gens/second<br />
  1877.         Rule: <span id="ruledis">lol some rule who cares</span>
  1878.       </div>
  1879.       <div id="bottombar">
  1880.         <div id="bottombarinner">
  1881.           Zoom:
  1882.           <span class="button" onclick="changeZoom(zoom*2)">++</span>
  1883.           <span class="button" onclick="changeZoom(zoom+1)">+</span>
  1884.           <span id="zoomCounter" class="number">8</span>
  1885.           <span class="button" onclick="changeZoom(zoom-1)">-</span>
  1886.           <span class="button" onclick="changeZoom(Math.ceil(zoom/2))">--</span>
  1887.           | őĒt:
  1888.           <span class="button" onclick="changeDT(speedDT*2)">++</span>
  1889.           <span class="button" onclick="changeDT(speedDT+1)">+</span>
  1890.           <span id="DTcounter" class="number">??ms (??fps)</span>
  1891.           <span class="button" onclick="changeDT(speedDT-1)">-</span>
  1892.           <span class="button" onclick="changeDT(Math.ceil(speedDT/2))">--</span>
  1893.           | generations/frame:
  1894.           <span class="button" onclick="changeSpeedMult(speedMult*2)">++</span>
  1895.           <span class="button" onclick="changeSpeedMult(speedMult+1)">+</span>
  1896.           <span id="multCounter" class="number">1</span>
  1897.           <span class="button" onclick="changeSpeedMult(speedMult-1)">-</span>
  1898.           <span class="button" onclick="changeSpeedMult(Math.ceil(speedMult/2))">--</span>
  1899.           | Pan camera:
  1900.           <span class="button" onclick="pan(0)">‚Üź</span>
  1901.           <span class="button" onclick="pan(1)">‚ÜĎ</span>
  1902.           <span class="button" onclick="pan(2)">‚Üí</span>
  1903.           <span class="button" onclick="pan(3)">‚Üď</span>
  1904.           | <span class="button" onclick="pausePlay();" id="pauseDisplay">Pause</span>
  1905.           | Save Codes:
  1906.           <span class="button" onclick="getRLE(cellList,worldY,worldX)">get</span>
  1907.           <span class="button" onclick="getRLE(rectCellList,rectSizeY+1,rectSizeX+1)">get¬†selection</span>
  1908.           <span class="button" onclick="setPattern(document.getElementById('RLEbox').value)">set</span>
  1909.           <textarea id="RLEbox" onfocus="this.select()"></textarea>
  1910.           | <span class="button" onclick="if(!pauselock){tick()}">Simulate¬†one¬†frame</span> <!-- This has no-break spaces in the text so that part of the button doesn't be on a different line to the rest. That happened. Remember to use nbsps! -->
  1911.           | <span class="button" onclick="eorcf()" id="eorcDisplay">Expand</span>
  1912.           the world by
  1913.           <input type="text" id="expandAmount" size="4" value="16" onfocus="this.select()" />
  1914.           cells on the
  1915.           <span class="button" onclick="dirf()" id="dirDisplay">Left</span>
  1916.           <span class="button" onclick="resize()">Go</span>
  1917.           | <span class="button" onclick="centerCamera()">Center¬†Camera</span>
  1918.           | <span class="button" onclick="clearWorld();">Clear¬†World</span>
  1919.           | Change Rule:
  1920.           <span class="button" onclick="setRule(document.getElementById('ruleBox').value,true);drawWorld();if(algorithm==0){fillSparse()};">set</span>
  1921.           <input type="text" id="ruleBox" size="10" value="B3/S23" onfocus="this.select()" />
  1922.           | Algorithm:
  1923.           <span class="button" id="changealgobutton" onclick="changeAlgorithm()">Brute¬†Force</span>
  1924.         </div>
  1925.       </div>
  1926.  
  1927.  
  1928.  
  1929.  
  1930.       <div id="HELP">
  1931.         <span class="button" onclick="help.style.zIndex='-1';help.style.opacity='0'" style="float:right;">Close</span>
  1932.         <div id="helpInner">
  1933.           <!-- I've put comments in here marking sections -->
  1934.           <h1>Reasoning Realm</h1>
  1935.           <p>This is an implementation of cellular automata in HTML5 with javascript, in development since 2016-03-03. It originated as an attempt to re-implement Jack Eisenmann's "<a href="http://www.ostracodfiles.com/logic/logicland.html">Logic Land</a>" cellular automaton better than he did, but it grew far beyond that and became capable of running other rules. As such, "Reasoning Realm" was named after it; other names with this structure include "Intelligence Island", "Deduction Dimension", and "Smartness Sphere". Dan came up with the last two. The source code of this program is over 2000 lines, and it's all just one .html file. Reasoning Realm can currently run Lifelike CA, Generations rules, cylic cellular automata, and generalised wire automata (including Wireworld) with moore, JvN, and hexagonal neighbourhoods, Logic Land, Rychl√°dr√°t, and LifeHistory.</p>
  1936.  
  1937.           <p>I declare this to be free software. Feel free to reverse engineer it, distribute it, modify it, distribute modifed versions of it, etc (as if anyone cares enough). The source code is this file itself.</p>
  1938.  
  1939.           <p>Credit goes to <span id="blah">BLAH (ME)</span> for being, like, really smart, Jack Eisenmann for inspiration and Logic Land savecodes (the functions to handle that were taken straight from his code with his permission), and dan.</p>
  1940.           <!-- section -->
  1941.           <h2>Controls</h2>
  1942.           <p>
  1943.             <span class="key">wasd/arrow keys</span>: Move camera<br />
  1944.             <span class="key">F</span>: Simulate one frame<br />
  1945.             <span class="key">I</span>: Zoom in linearly<br />
  1946.             <span class="key">O</span>: Zoom out linearly<br />
  1947.             <span class="key">[</span>: Zoom out exponentially<br />
  1948.             <span class="key">]</span>: Zoom in exponentially<br />
  1949.             <span class="key">space</span>: Play/pause<br />
  1950.             <span class="key">E</span>: Erase selection<br />
  1951.             <span class="key">X</span>: Cut selection<br />
  1952.             <span class="key">C</span>: Copy selection<br />
  1953.             <span class="key">V</span>: Paste selection<br />
  1954.             <span class="key">M</span>: Mirror selection vertically<br />
  1955.             <span class="key">N</span>: Mirror selection horizontally<br />
  1956.             <span class="key">T</span>: Rotate selection<br />
  1957.             <span class="key">`</span>: Randomly fill selection with values from 0 up to the selected element (` key to the left of 1)<br />
  1958.             <span class="key">H</span>: Center camera<br />
  1959.             <span class="key">0,1,2,3,4,5,6,7,8,9</span>: Select corresponding state (and switches to the Pen tool if it isn't already selected)<br />
  1960.             <span class="key">Q</span>: Same as 0<br />
  1961.             <span class="key">-</span>: Select state 10 (the hyphen key, to the right of 0)<br />
  1962.             <span class="key">Z</span>: Select state 17<br />
  1963.             <span class="key">R</span>: Selection tool<br />
  1964.             <span class="key">J</span>: Drag Camera tool<br />
  1965.             <span class="key">alt+f4</span>: Close help menu
  1966.           </p>
  1967.           <p>Pause lock: If you enable this, you will not be able to pause or unpause. useful iff you=dan <span class="button" onclick="pauseLock()" id="pauseLockDisplay">Lock</span></p>
  1968.           <p>Logic Land save codes: This is the undocumented, strange, inefficient format Logic Land used. <span class="button" onclick="if(rule=='LogicLand'){displaySaveCode()}else if(confirm('The rule is currently not set to Logic Land. This may cause the save file to be heavily broken, and most likely you don\'t mean to do this. Do you want to do it anyway?')){displaySaveCode()}">get</span> <input type="text" id="RRFbox" size="16" onfocus="this.select()" /></p>
  1969.           <!-- section -->
  1970.           <h2>Changelog</h2>
  1971.           <h3>0.3.1</h3>
  1972.           <p class="date">2018-04-26</p>
  1973.           <p>The day is 2017-12-08, and I've decided to go back and fix some things after about 13 months of inactivity.</p>
  1974.           <p>... The month is 2018-04. I'm going back to finish this version now.</p>
  1975.           <ul class="changelist">
  1976.             <li>+A snake.</li>
  1977.             <li>+<a href="http://www.conwaylife.com/forums/viewtopic.php?f=11&t=1499">Generalised Wire Automata</a>. "WireWorld" and "Bliptile" are interpreted as their equivalent CA in this rulespace; Wire12 and Wire1v, respectively. Sadly, Bliptile used state numbers differently, so Bliptile patterns don't work directly.</li>
  1978.             <li>+*-There is now only one set rule button; it automatically detects which of the two supported formats you're using.</li>
  1979.             <li>+*Cyclic cellular automata now perceive neighbourhoods correctly. cyclic16 uses the moore neighbourhood, cyclic16v, the von neumann, and cyclic16h, the hexagonal. Does that make grammatical sense? Whatever.</li>
  1980.             <li>*Fixed bug where getRLE() would register amount of empty lines above the pattern as one less than it should be.</li>
  1981.             <li>*Apparently fixed bug where generations rules with hexagonal neighbourhoods would produce innacurate behaviour while using the sparse algorithm. I never experienced it but I guess it existed.</li>
  1982.           </ul>
  1983.           <!-- section -->
  1984.           <h2>Todo List</h2>
  1985.           <p>This is a list of easy and difficult goals. Some I will probably never bother to do. They are in no order whatsoever. This list is maintained poorly if at all.</p>
  1986.           <ul>
  1987.             <li>Add options for colour schemes</li>
  1988.             <li>Make the 'close' button in the help menu follow you as you scroll down</li>
  1989.             <li>Add support for unbounded grids</li>
  1990.             <li>Add support for other geometries, like cylinders, toruses, klein bottles, etc</li>
  1991.             <li>Allow multiple worlds loaded at once</li>
  1992.             <li>Add undo functionality</li>
  1993.             <li>Change the program to use a 1D array because it's probably faster</li>
  1994.           </ul>
  1995.           Bugs: <!--New bugs I found-->
  1996.           <ul>
  1997.             <li>The get selection tool is FUBAR.</li>
  1998.           </ul>
  1999.         </div>
  2000.       </div>
  2001.     </div>
  2002.     <script>
  2003. //Script at the end of <body> to initialize the app.
  2004. var c         = document.getElementById("display");
  2005. var canvas    = c.getContext("2d");
  2006. var crect     = c.getBoundingClientRect(); //This has to do with getting the location of the mouse over the canvas. See this stackoverflow page: http://stackoverflow.com/questions/17130395/canvas-html5-real-mouse-position
  2007. var id        = canvas.createImageData(1,1); //It's worth reading this stackoverflow page for info on this variable: http://stackoverflow.com/questions/4899799/whats-the-best-way-to-set-a-single-pixel-in-an-html5-canvas
  2008. var d         = id.data;
  2009. d[3]          = 255; //d[3] is opacity, which should be full.
  2010. var help      = document.getElementById("HELP");
  2011. var selMenu   = document.getElementById("elements");
  2012. var appWidth  = document.getElementById('appContainer').getBoundingClientRect().width;
  2013. var appHeight = document.getElementById('appContainer').getBoundingClientRect().height;
  2014.  
  2015. changeDT(1); //It's already 1, but this shows it in the menu.
  2016. changeDrawType(1); //We have to call this so the menu doesn't have no items selected. Having no items selected is not something the menu should ever be able to do
  2017. setInterval("if(running){tickCount++; if(tickCount%speedDT == 0){tick()}}", baseDT); //The if statement is here, not in the function, so we can manually simulate frames.
  2018. setInterval("crect = c.getBoundingClientRect(); appWidth = document.getElementById('appContainer').getBoundingClientRect().width; appHeight = document.getElementById('appContainer').getBoundingClientRect().height", 5000); //It re-establishes those variables every 5 seconds because I'm too lazy to find out how to trigger an event when body is resized
  2019. setInterval("continuousPan();", 50); //This function checks to see if the wasd/><^V keys are being pressed and if so moves the camera accordingly when it is called.
  2020. setInterval("document.getElementById('gpsdisplay').innerHTML = generation-gpscount; gpscount = generation;",1000); //Generations per second counter.
  2021. setPattern("#C Memetic go-faster stripes for my memetic drift. Also I edited this RLE manually to change the 7 in 2017 into an 8. I'm basically ramanujan.\nx = 160, y = 100, rule = Rychl√°dr√°t\n4.5B$4.B3.B69.KBQCK3.EAQIE3.EAQIE3.EAQIE3.EAQIE3.EAQIE3.KBQCK3.EAQIE3.KBQCK3.EA5QIE$4.5B69.C2.IB3.I3.A3.I3.A3.I3.A3.I3.A3.I3.A3.C3.B3.I3.A3.C3.B3.I7.A$4.B3.B63.EAI3.QA.2QAEIQA2.QBKCQB2.QAEIQA2.QAEIQA2.QAEIQA2.QAEIQA2.QAEIQA2.QBKCQB2.QAEIQA6.Q$4.5B63.I.E3.BN.3Q2.AH2.2Q2.AN2.2Q2.AH2.2Q2.AH2.2Q2.AH2.2Q2.BN2.2Q2.AH2.2Q2.BH2.2Q2.AH6.Q$3.2B3.2B62.A.B4.C.3Q3.I2.2Q3.C2.2Q3.I2.2Q3.I2.2Q3.I2.2Q3.C2.2Q3.I2.2Q3.I2.2Q3.I6.Q$3.B.3B.B62.E.C2QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB5.Q$3.2B3.2B62.I.K.IE.QE3QIE.QE.2QIE.QE.2QIE.QE.2QIE.QE.2QIE.QE.2QIE.QE.2QIE.QE.2QIE.QE.2QIE.QE5.Q$3.B.3B.B62.A.B.Q2.QI4Q2.QI.3Q2.QI.3Q2.QI.3Q2.QI.3Q2.QI.3Q2.QI.3Q2.QI.3Q2.QI.3Q2.QI5.Q$3.2B3.2B62.E.C.Q2.Q2A3Q2.QA.3Q2.QA.3Q2.QA.3Q2.QA.3Q2.QA.3Q2.QA.3Q2.QA.3Q2.QA.3Q2.QA5.Q$3.B.3B.B62.I.K.QIDBFI3QCJAFI3QIDBFI3QCJAFI3QCJAFI3QCJAFI3QIDBFI3QCJAFI3QCJAFI3QCJAFI4.Q$3.2B3.2B62.A.A.2Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.Q4.Q$3.B.3B.B62.E.I.2Q2.EA4Q2.EA4Q2.EA4Q2.EA4Q2.EA4Q2.EA4Q2.EA4Q2.EA4Q2.EA4Q2.EA4.Q$3.2B3.2B62.I.E.QA2.I.3QB2.I.3QA2.I.3QB2.I.3QB2.I.3QB2.I.3QA2.I.3QB2.I.3QB2.I.3QB2.I5.Q$3.B.3B.B62.A.A.AFAJA.2QAFBDA.2QAFAJA.2QAFAJA.2QAFAJA.2QAFAJA.2QAFAJA.2QAFBDA.2QAFAJA.2QAFBDA5.Q$3.2B3.2B62.E.I2.2IC2.QI.ICI2.QC.2IC2.QI.2IC2.QI.2IC2.QI.2IC2.QI.2IC2.QI.ICI2.QC.2IC2.QI.ICI6.Q$3.B.3B.B62.IAE2.ADB2.QE.AJA2.QK.ADB2.QE.ADB2.QE.ADB2.QE.ADB2.QE.ADB2.QE.AJA2.QK.ADB2.QE.AJA6.Q$3.2B3.2B69.BDIQA3.AJCQB3.BDIQA3.BDIQA3.BDIQA3.BDIQA3.BDIQA3.AJCQB3.BDIQA3.AJCBK2.Q$3.B.3B.B69.D2.Q4.J2.Q4.D2.Q4.D2.Q4.D2.Q4.D2.Q4.D2.Q4.J2.Q4.D2.Q4.J3.C2.Q$3.2B3.2B69.I2.CKB2QC2.IEA2QI2.IEA2QI2.IEA2QI2.IEA2QI2.IEA2QI2.CKB2QC2.IEA2QI2.CKB2QC3.Q2.Q$3.B.3B.B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B69.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B68.EA7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.6A52QI7.KB7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B10.6B60QC7.EA7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.6A2Q4A2Q4A2Q3A3Q3A2Q3A2Q4A2Q2AQ4A3Q4A18QI7.EA7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B10.6A2Q2AQ2AQ4AQ5AQ4AQ5AQ5AQ2AQ5AQ5A26QI7.EA7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.6A2Q2AQ2AQ2A3Q2AQ2AQ2A3Q2AQ2AQ2AQ2AQ2AQ2AQ2AQ2A37QI7.EA7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B10.6A2Q4A2Q4AQ2AQ2AQ3A2Q2AQ2AQ2AQ2AQ2AQ2AQ2AQ2A45QI7.EA7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.6A2Q2AQ2AQ4AQ5A2Q3AQ2AQ2AQ2AQ2AQ2AQ2AQ2AQ2AQ2A50QI7.KB7.Q7.Q3.Q2.Q$3.2B3.2B10.6B2Q2BQ2BQ2B3Q2BQ2B3Q2BQ2BQ2BQ2BQ2BQ2BQ2BQ2BQ2BQ2B58QC7.EA7.Q3.Q2.Q$3.B.3B.B10.6A2Q2AQ2AQ4AQ2AQ2AQ4AQ5AQ2AQ2AQ2AQ2AQ2AQ5A66QI7.KB3.Q2.Q$3.2B3.2B10.6B2Q2BQ2BQ4BQ2BQ2BQ3B3Q3B2Q2BQ2BQ2BQ2BQ2B2Q3B75QC4.Q2.Q$3.B.3B.B10.6A124QI4.Q2.Q$3.2B3.2B10.6B12Q4B2Q4B2Q3B2Q2B4Q7B74QC7.EA3.Q2.Q$3.B.3B.B10.6B12Q2BQ2BQ4BQ5BQ2B4Q8B65QC7.KB7.Q3.Q2.Q$3.2B3.2B10.6B12Q2BQ2BQ2B3Q2BQ2BQ2B4Q2BQ2BQ2B57QC7.KB7.Q7.Q3.Q2.Q$3.B.3B.B10.6B12Q4B2Q4BQ2BQ2BQ2B4Q2BQ2BQ2B49QC7.KB7.Q7.Q7.Q3.Q2.Q$3.2B3.2B10.6B12Q2BQ2BQ4BQ5BQ2B4Q2BQ2BQ2B41QC7.KB7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.6A12Q2AQ2AQ2A3Q2AQ2AQ2A4Q2AQ2AQ2A33QI7.KB7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B10.6A12Q2AQ2AQ4AQ2AQ2AQ5AQ2AQ2AQ2A25QI7.EA7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.6B12Q2BQ2BQ4BQ2BQ2BQ5BQ2BQ2BQ2B17QC7.EA7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B10.6B52QC7.KB7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.6B44QC7.KB7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.2B3.2B60.KB7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q7.Q3.Q2.Q$3.B.3B.B10.B.B2.B4.2B5.B33.C2QBKC2.C2QBKC2.C2QBKC2.I2QAEI2.I2QAEI2.C2QBKC2.C2QBKC2.C2QBKC2.C2QBKC2.C2QBKC2.I4QAEI$3.2B3.2B10.BABAB.B4.AB3.2BA32.J4.Q2.J4.Q2.J4.Q2.D4.Q2.D4.Q2.J4.Q2.J4.Q2.J4.Q2.J4.Q2.J4.Q2.D3.Q$3.B.3B.B10.BABABABA2.2B.A3.BA32.A3.BQCJA3.BQCJA3.AQIDB3.AQIDB3.BQCJA3.BQCJA3.BQCJA3.BQCJA3.BQCJA3.AQIDB3.B$3.2B3.2B11.B.ABABA3.AB4.BA32.AJA.KQ2.AJA.KQ2.AJA.EQ2.BDA.EQ2.BDA.KQ2.AJA.KQ2.AJA.KQ2.AJA.KQ2.AJA.KQ2.AJA.EQ2.BDA.K$3.B.3B.B11.BA2.B.AB.2B.AB.3B32.ICI.CQ2.ICI.CQ2.ICI.IQ2.C2I.IQ2.C2I.CQ2.ICI.CQ2.ICI.CQ2.ICI.CQ2.ICI.CQ2.ICI.IQ2.C2I.C$3.2B3.2B12.A3.A2.A.2A2.A.3A30.ADBFA2Q.ADBFA2Q.ADBFA2Q.AJAFA2Q.AJAFA2Q.ADBFA2Q.ADBFA2Q.ADBFA2Q.ADBFA2Q.ADBFA2Q.AJAFAQ$3.B.3B.B60.I2.A3Q.I2.B3Q.I2.A3Q.I2.A3Q.I2.A3Q.I2.A3Q.I2.B3Q.I2.B3Q.I2.B3Q.I2.A3Q.I2.B2Q$3.2B3.2B20.2B2.B3.3B.B.B24.AE2.4QAE2.4QAE2.4QAE2.4QAE2.4QAE2.4QAE2.4QAE2.4QAE2.4QAE2.4QAE2.3Q$3.B.3B.B10.2B2.B.B3.BAB.BA2.BABABABA23.Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.5Q3.3Q$3.2B3.2B10.BAB.BABA2.2B2AB2A.3BA3B2A22.IFBDI3QIFAJC3QIFBDI3QIFBDI3QIFBDI3QIFBDI3QIFAJC3QIFAJC3QIFAJC3QIFBDI3QIFAJC2Q$3.B.3B.B10.2B.A.B.A2.BAB.B2A.BABABAB2A19.EAI.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.3Q.AQ2.2Q$3.2B3.2B10.BAB2.BA3.2B2A3B.BABABAB2A19.I.E.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.3Q.IQ2.2Q$3.B.3B.B10.2B.A.BA4.2A.4A.8A19.A.B.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EI2Q.EQ.EIQ$3.2B3.2B11.2A3.A5.2A2.3A.A.A.A.A19.E.CQB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB4QB2QB2Q$3.B.3B.B56.I.K2.C3.2Q2.I3.2Q2.C3.2Q2.C3.2Q2.C3.2Q2.C3.2Q2.I3.2Q2.I3.2Q2.I3.2Q2.C3.2Q2.I3.Q$3.2B3.2B56.A.B2.NA2.2Q2.HB2.2Q2.NB2.2Q2.NB2.2Q2.NA2.2Q2.NA2.2Q2.HB2.2Q2.HB2.2Q2.HB2.2Q2.NB2.2Q2.HB2.Q$3.B.3B.B56.E.C2.BQCKBQ2.BQCKBQ2.AQIEAQ2.AQIEAQ2.BQCKBQ2.BQCKBQ2.BQCKBQ2.BQCKBQ2.BQCKBQ2.AQIEAQ2.BQCKB$3.2B3.2B56.I.K7.B3.C3.B3.C3.B3.C3.A3.I3.A3.I3.B3.C3.B3.C3.B3.C3.B3.C3.B3.C$3.B5.B56.A.A7.KCQBK3.KCQBK3.KCQBK3.EIQAE3.EIQAE3.KCQBK3.KCQBK3.KCQBK3.KCQBK3.KCQBK$3.B.B.B.B56.E.I$3.B5.B56.I.E$4.B.B.B57.A.A$5.3B58.E.I$6.B59.IAE$6.B$6.B$5.B.B15$2A3.A3.A3.A$2.A.A.A.2A2.A.A$.A2.A.A2.A3.A$A3.A.A2.A2.A.A$3A2.A2.3A2.A!");
  2022.     </script>
  2023.   </body>
  2024. </html>
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top