├── LICENSE ├── README.md ├── dirty.html ├── experiments ├── swt.html ├── test.html └── test.js ├── images ├── aim916.png ├── images.js └── rotation.png ├── lib ├── jsfeat-custom.js └── lodash.js ├── models ├── params.js ├── zeus.js └── zeus.min.js ├── ocropy ├── clstm2js.py ├── lrpred ├── minilstm.py └── pyrnn2clstm.py └── src ├── chull.js ├── helpers.js ├── lstm.js └── swtcore.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Project Naptha 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ocracy 2 | pure javascript lstm rnn implementation based on ocropus 3 | -------------------------------------------------------------------------------- /dirty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /experiments/swt.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /experiments/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /experiments/test.js: -------------------------------------------------------------------------------- 1 | // var lineheight = 28, 2 | // hiddensize = 50; 3 | 4 | var hiddensize = fwdWGI.length, 5 | lineheight = fwdWGI[0].length - hiddensize - 1; 6 | 7 | codec = [""," ","!","\"","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~"] 8 | 9 | net = new SequenceRecognizer(lineheight, hiddensize, codec); 10 | 11 | var parallel = net.lstm.nets[0], 12 | softmax = net.lstm.nets[1], 13 | fwd = parallel.nets[0], 14 | rev = parallel.nets[1].net; 15 | 16 | 17 | var dict = ''; 18 | for(var i = 32; i < 126; i++){ 19 | if(i == 92 || i == 34 || i == 39 || i == 60) continue; 20 | dict += String.fromCharCode(i) 21 | } 22 | 23 | function vecparse(str){ 24 | if(typeof str != 'string') return str; 25 | var arr = new Float32Array(str.length); 26 | for(var i = 0; i < str.length; i++) 27 | arr[i] = 2 * encGamut * dict.indexOf(str[i]) / (dict.length - 1) - encGamut; 28 | return arr; 29 | } 30 | 31 | fwd.WGI = fwdWGI.map(vecparse) 32 | fwd.WGF = fwdWGF.map(vecparse) 33 | fwd.WGO = fwdWGO.map(vecparse) 34 | fwd.WCI = fwdWCI.map(vecparse) 35 | fwd.WIP = vecparse(fwdWIP); 36 | fwd.WFP = vecparse(fwdWFP); 37 | fwd.WOP = vecparse(fwdWOP); 38 | 39 | rev.WGI = revWGI.map(vecparse) 40 | rev.WGF = revWGF.map(vecparse) 41 | rev.WGO = revWGO.map(vecparse) 42 | rev.WCI = revWCI.map(vecparse) 43 | rev.WIP = vecparse(revWIP); 44 | rev.WFP = vecparse(revWFP); 45 | rev.WOP = vecparse(revWOP); 46 | 47 | softmax.W = softW.map(vecparse) 48 | softmax.B = vecparse(softB); 49 | 50 | 51 | function displayImage(image){ 52 | var canvas = document.createElement('canvas') 53 | var imgwidth = image.length, 54 | imgheight = image[0].length; 55 | canvas.width = imgwidth; 56 | canvas.height = imgheight; 57 | var ctx = canvas.getContext('2d'); 58 | var img = ctx.createImageData(imgwidth, imgheight); 59 | for(var i = 0; i < imgwidth; i++){ 60 | for(var j = 0; j < imgheight; j++){ 61 | var o = j * imgwidth + i; 62 | img.data[4 * o + 0] = img.data[4 * o + 1] = img.data[4 * o + 2] = Math.floor(image[i][j] * 255); 63 | img.data[4 * o + 3] = 255; 64 | } 65 | } 66 | ctx.putImageData(img, 0, 0) 67 | document.body.appendChild(canvas) 68 | } 69 | 70 | 71 | function visualizeOutput(output){ 72 | var canvas = document.createElement('canvas') 73 | var ctx = canvas.getContext('2d'); 74 | var imgwidth = output.length, 75 | imgheight = output[0].length; 76 | canvas.width = imgwidth; 77 | canvas.height = imgheight; 78 | // console.log(imgwidth, imgheight) 79 | var img = ctx.createImageData(imgwidth, imgheight); 80 | for(var i = 0; i < imgwidth; i++){ 81 | for(var j = 0; j < imgheight; j++){ 82 | var o = j * imgwidth + i; 83 | img.data[4 * o + 0] = img.data[4 * o + 1] = img.data[4 * o + 2] = Math.floor(output[i][j] * 255); 84 | img.data[4 * o + 3] = 255; 85 | } 86 | } 87 | ctx.putImageData(img, 0, 0) 88 | for(var j = 0; j < imgheight; j++){ 89 | var run_start = -1; 90 | for(var i = 0; i < imgwidth; i++){ 91 | if(output[i][j] > 0.1){ 92 | if(run_start < 0){ 93 | run_start = i 94 | } 95 | }else{ 96 | if(run_start >= 0){ 97 | ctx.fillStyle = 'green' 98 | ctx.font = '7px sans-serif' 99 | ctx.textAlign = 'center' 100 | ctx.fillText(codec[j], i / 2 + run_start / 2, j - 2) 101 | run_start = -1 102 | } 103 | } 104 | } 105 | } 106 | document.body.appendChild(canvas) 107 | 108 | } 109 | 110 | function sparkline(net){ 111 | var canvas = document.createElement('canvas') 112 | var ctx = canvas.getContext('2d'); 113 | var imgwidth = net.output.length, 114 | imgheight = net.output[0].length; 115 | canvas.width = imgwidth; 116 | canvas.height = 100; 117 | // console.log(imgwidth, imgheight) 118 | // var img = ctx.createImageData(imgwidth, imgheight); 119 | ctx.beginPath() 120 | // var merp = array_conv3(net.output.map(function(e){ return 1 - e[0] }), function(a, b, c){ 121 | // // return Math.max(a, b, c) * 0.5 + b * 0.5 122 | // // return Math.exp(b) / (Math.exp(a) + Math.exp(b) + Math.exp(c)) 123 | // // return Math.max(a, b, c) 124 | // // return 0.1 * a + 0.8 * b + 0.1 * c; 125 | // return Math.max(a, b) / 2 + Math.max(b, c) / 2 126 | // // return Math.max(b, c) 127 | // // return Math.max(a, b, c) / 2 + Math.min(a, b, c) / 2 128 | // // return b 129 | // }) 130 | 131 | 132 | 133 | // for(var i = 1; i < net.output.length; i++){ 134 | // var sum = 0; 135 | // for(var j = 1; j < net.output[0].length; j++){ 136 | // sum += Math.abs(net.output[i - 1][j] - net.output[i][j]) 137 | // } 138 | // // console.log(sum) 139 | // merp[i] *= 1-sum; 140 | // // if(sum > 0.5){ 141 | // // merp[i] = 0 142 | // // merp[i] *= (1-sum) 143 | // // } 144 | // } 145 | 146 | // var derp = array_conv3(merp, function(a, b, c){ 147 | // // return Math.max(a, b, c) * 0.5 + b * 0.5 148 | // // return Math.exp(b) / (Math.exp(a) + Math.exp(b) + Math.exp(c)) 149 | // // return Math.max(a, b, c) 150 | // return 0.1 * a + 0.8 * b + 0.1 * c; 151 | // // return Math.max(a, b) / 2 + Math.max(b, c) / 2 152 | // // return Math.max(b, c) 153 | // // return Math.max(a, b, c) / 2 + Math.min(a, b, c) / 2 154 | // // return b 155 | // }) 156 | 157 | 158 | 159 | for(var i = 0; i < imgwidth; i++) ctx.lineTo(i, 100 - 100 * net.output[i][0]); 160 | ctx.strokeStyle = 'orange' 161 | ctx.stroke() 162 | 163 | ctx.beginPath() 164 | for(var i = 0; i < imgwidth; i++) ctx.lineTo(i, 100 - 100 * net.output[i][1]); 165 | ctx.strokeStyle = 'green' 166 | ctx.stroke() 167 | 168 | // ctx.beginPath() 169 | // for(var i = 0; i < imgwidth; i++) ctx.lineTo(i, 100 - 100 * Array.prototype.slice.call(net.output[i], 2).reduce(function(a, b){ return a + b })); 170 | // ctx.strokeStyle = 'rgba(0,0,255,0.5)' 171 | // ctx.stroke() 172 | 173 | document.body.appendChild(canvas) 174 | 175 | } 176 | 177 | var outputs = [] 178 | 179 | function recognize(){ 180 | console.time('recognition start'); 181 | [img010001, img010002, img010003, img010004, img010005, img010006, img010007, img010008, img010009, img01000a, img01000b, img01000c, img01000d, img01000e, img01000f, img010010, img010011, img010012, img010013, img010014, img010015, img010016, img010017, img010018, img010019, img01001a].forEach(function(image, i){ 182 | 183 | document.body.appendChild(document.createTextNode(i)) 184 | document.body.appendChild(document.createElement('br')) 185 | displayImage(image); 186 | console.log(net.predictString(image)) 187 | document.body.appendChild(document.createElement('br')) 188 | // displayImage(net.output) 189 | visualizeOutput(net.output); 190 | document.body.appendChild(document.createElement('br')) 191 | sparkline(net) 192 | document.body.appendChild(document.createElement('br')) 193 | 194 | outputs[i] = net.output 195 | }) 196 | console.timeEnd('recognition start') 197 | 198 | } 199 | 200 | // function f(e){return 1 - e[0] > 0.4}; array_split(outputs[9], function(a, b){return f(a) == f(b)}).filter(function(e){return f(e[0])}).map(function(e){return e.map(function(k){return codec[max_index(k)]}).join('')}) 201 | 202 | 203 | // function f(e){return 1 - e[0] > 0.7}; array_split(outputs[9], function(a, b){return f(a) == f(b)}).filter(function(e){return f(e[0])}).map(function(e){return codec[max_index(array_zip(e).map(array_mean))]}).join('') 204 | 205 | // array_split(outputs[18], function(a, b){ 206 | // return f(a) == f(b) 207 | // }).filter(function(e){ 208 | // return e.map(function(k){ 209 | // return 1 -k[0] 210 | // }).reduce(function(a,b){return a + b}) > 0.8 211 | // }).map(function(e){ 212 | // return max_index(array_zip(e).map(array_mean)) 213 | // }).map(function(e){return codec[e]}).join('') 214 | 215 | onload = function(){ 216 | recognize() 217 | } -------------------------------------------------------------------------------- /images/aim916.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naptha/ocracy/6b008e0a403814954c42885fa718d157b01d21d1/images/aim916.png -------------------------------------------------------------------------------- /images/rotation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naptha/ocracy/6b008e0a403814954c42885fa718d157b01d21d1/images/rotation.png -------------------------------------------------------------------------------- /models/params.js: -------------------------------------------------------------------------------- 1 | encGamut = 4.000000; 2 | 3 | fwdWGI = ["TPPOPOOOOOOPPPQQQQQQQPPPPPPPPPOOPONOOOOOPOPOPPOOPPOOOPPPOPPPOOOOOPOOOPOOOPOPOOP", 4 | "NOPPPPPPQQQRVVSOQTSOMNPPPPPPPPPSPNOONPMOPOOIPPNPPKQPLNROPMOOQRONLSKTPMOPMMQROOP", 5 | "SOOOOOPOOONQRQQPNLKLMOPQQPPOPNROSPPQPNQONNOPOOMNOQQRQNOQNQQQNOPPQOQONPPOQPNOOQP", 6 | "POOOPPQRTVUUQQPNLIGKMMNNMNOOPORUMOOPPPSOPMPOQPLPNMRSOJSOOSPOPRONORMSONQPOPPNQRQ", 7 | "OOOOPONNNNONLMMMOOOOOPPQQQPPPPPOPQOPQOQQPPPOOOQOOPPOQPNPOMPONPQOOPOPOPQNQNOPPOO", 8 | "ROPPONMNMLLLMOONNMNPQOPPPPOOOOQQROONOOOOOSPNQPMOONQRNQQPOOPPQPONOMOOONMOONOROOQ", 9 | "QOPOPONNOPQRRPPPPPPOPPOPPPPPPORQNPPQONONNPOPMOPNOOPNQOPQONQPOQPOOPNQOPRNPQNPSPO", 10 | "QPOPPPPPPPOOONNNONNOPOOPPPPPOOPNPQOPPOPOOOOOOOQNOROOQONPOOPPOOPQOOQOOQPOPPNONPO", 11 | "OPPPOPPPPOPPPPPPPPOOOPPPPOOOOPOOOPPOOPOOPOPOPOPPOPPOPOOOPOOOOPPOOPOOPPPPONPOOON", 12 | "SOOPOPPPPPPQPOOQRQRRQQQQQPPOPOMPPPQPPPQNOKOQNOPOMPPQQQPPONPPPLPPPQQPOPPOPLPONMR", 13 | "OPPOPPPPQQQPPQQQQPPQQPOPPPPPPONPOPOPPONPOOONPPPOPPQONMQPORPPQPOPOQPPOPPOOPPNORM", 14 | "WPPOPPOOONOQQQQQQQQQQPOPPPPOPOOOPONOOOOOOOONOOONPPOPOPPPOPPPPOPOOPOOOPOOOPMPOOO", 15 | "QPPPPPPOOOOPPPQTTRQQPOPQPPPPPOPQOOPQOOQOPNPNNPOONOPNPOQPPPPPNQONOQOSOOQOONPPSQO", 16 | "TOPOPOOOONOOOPPPPPPPPPPPPPPPPONPQOMOOPOOOOPNPPNOPOOPNQQPOPOOPOOOOOONOONPNOOQNNP", 17 | "QPPOPPPRRSUSNMOPOKKOSRONNNOOOPPQMQOMPOQQPPQROPOOQPOONWPPPPOOPPPOPKOOPPQPQPOTPNS", 18 | "VOPPOOOOONMOPPQQRRPOLMOPOOOOOPOOPOPOOPOPPPPNNQOPQPPOOOQOPPOOPONOMOPOPPOPOOQQOPO", 19 | "POOPPOOOOOOOOONOPPOPPQPQQPPPPPOPPPOPOPPPPPPNPOPPOOPOPPPOPNOOOOOONOOQPOOPPMPQPOP", 20 | "NOOOPPOOOPQOOOPPPQSRQPOOOOOOPOPPSPPQPOMNNOOLOOOOOPPRMQOPONPPMQPONPOPOPQNPMPNPLN", 21 | "PPPPPOPPPPPPPPPPQPPQQQPPPPPPOPOPPPOOPPOPQOPOQPPONPPOOPPOPOOOPPOPOPPPPPOPOOPPOOP", 22 | "ROOPOPPPOOPQPONORRRQRRQQQPPPOOOPPPPPOOPNOMONOOOONOOQOOOPOOPPOOPOPQPQOPPOOMOPNOP", 23 | "QOOOPPQPOOOPOONNMKIJLMOOOPPPONRMQPPOQNPNNPOPOOMNPTRRQPNQNPQQOPQPQNRNNRRNRPNNOON", 24 | "QOOPPPPPOOPTTRRRQQQQRQPQQPPOOOPNPPOPPOOPNOONOONOOPNROMOPNQPPPQPPNMQOOQQOPMPQNQO", 25 | "OOOOOOOONMQRQOPPOOOPPONNNOOOONQQNPRPQNPONPNPNONONPROOMPPNRQQPQQPPMQRNPPOQPOPQTN", 26 | "QPOOOOOOOONNLLKKMNNORROPPPPOPNQRPQQRPNVQNNNRMORNNPQOSPOQNNQQMNPMQPNPNPPNQQOPPQQ", 27 | "TPOOOOOPPMLKKKMPQPPSTPPQPPPPPOMQMPONNNSNPMPLNOONPMOPNKQQONPPOOPNOSOQOKSNNNNKMQN", 28 | "ROPOOOOOOOPQQQQQPPOPQQPQQPPPPOQOPPOQPOONNNOOOOOOOPQPQNOPOOPPNOPOQPNPOOPNPPNNPPO", 29 | "PPPOPPOPOOPPPPPPPPPPPPPPPPPPOPPPPPOOPPOPPOPOQPPOOPPOPPPOPOOOPPPPOPPPPPOPPOPOOOP", 30 | "TOOOPPOPPOPPQQQQQQQQQQPPPPOOPOOOPOOOOPOOPOPOPOOOOPOOOPPPOPPPPOPOPPOOOPNOOPOPOOP", 31 | "QPOPOOOONNLLNMMOQQQQRRPOOOOOOMOMOPQOQNMOMPMOOONNOQOQPRMQMQQRPOQPPOQNNOQOQONOPNO", 32 | "QPOOPOOPOOPPPPPQQPPQQPPPPPPOOPOOPPOOOPOOPOPOPOPOOPOOPPPOPPOOPOPOOPOOPPOPOOPPPOP", 33 | "TPPOPOOOOOOPPPPQQQQQQPPPPPOPPOOOPOOOOOOOOOPOPOOOPPOOOPPPOPPPOOOOOPOOOPOOOPOPOOO", 34 | "POPPPPQQQRRQQQRRRQQQQQPOPOPPOOQPOPOQOOPPONOOOOOONONOORPPOOPPOQPONONROPQOONPQQPQ", 35 | "OOOOOONPQPOOPRTTRQOOMMOPPPPPOOQRNPPOOORNOPOOPOOOONRNPOPPOPPPPNPNQQPQONQOPNPMOQP", 36 | "PPPPPPPPONOOOPOOPPPPQPPPPPPPPPOOPPOOOPOPPPPNPOOPOOPPPPOOPOOOOOPONOOPPOOPPOOPOOO", 37 | "QPOPOOPPPPPOOOONONNOOOOPOOOPPNPNOQPQPNQQNNNQMOPNOROPQONQNOQQOPPQONQPNRRNQONPPPQ", 38 | "OPOOPONNOQOLORTSSTTRQOOPPPPPPPONRONOQPNQPTPNPPNPOQQROPPOPPOOPSOQLOPSPRQPPKQSRPQ", 39 | "UPOPPQRRQPOOMJLQPLKNQSSSSQPPPNMOQPONPONNNQOLOPMNONRROOQQNPQQPOPNPNMQNNPNNONQQPN", 40 | "QPOPPPPPPPOPOOMMMLKLMLMNNOOPOMOMORPPQNPOMQMQOOONRTOOQPNQMPRRPOQRPNTOMUPNRRNPQPQ", 41 | "RPPOPPQQRRRRQRQPOMKMONOPQPPPPNQPPOPMONONNRNMMONNQPQQOTPQNLQQNOPORPOONOPNOONQNNQ", 42 | "RPPPPOOPPOPPPPQQQQQQQPPPPPPPOOOOPPOOOPOOPOPOPOPOOPOOOPPOPPPOPOPOPPOOPPOPOOOPOOO", 43 | "ROPOPPOOOOOONNNKKKIJLNOPPPPPONQMPQPOQNQONPOPOOONPSSQQONQNOQQOOQPQPRONSRNRPMOPQO", 44 | "FOPPOOOPPPRSRPOOPONNNQPPQPPOORPPPONMQSKRSRQLTPNSOMQOOQOLSJMMRQPNRPMOSKOQPMTQONM", 45 | "LOPPPPPPPPPPPPOPPPPPPQPPPPPOOQPPPPPPPQOOQPPNROPPOPPOQOOOQNNNOQPPPPOPQPPPPOROPPO", 46 | "PPOPPPPOOONNOPOOPPPQRRPQQPPPPOPNNQOPPOOOOPOOPOPOOQQOPPOPOOPPPOPPPOPOOQPOPPOOPPO", 47 | "PPPPPPQQPQRQQPPQPPPQQQRSRPPOPOQMMPONPPLOOQOPQPOOOQRNOPOPOPPPQOPPONROOPPPPQPQLRP", 48 | "RPOOOOPPOOPQQQQRRRRQQQPPPPPOOOPNQQOPPOPQOOOPOOPONQOOQONPOQPPNPPQPNQOOQOOQPNPPPQ", 49 | "SOOPOOOOONOPONPSSQPOPPOOOOPPOMPONQQOPMPPMPNONOOMQQQNNNPRMQRRPPPOOPPOMPQMPRMNQQN", 50 | "PPPPPQSSRSQQQONOQROLMOONNNOPPOMPOOOPPONNOMOLOPMOQNPROOOPOPPPONPMQSMRONOOOOONOOO", 51 | "ROOOOOMLMLLPPNOPQPQRTSPOOPPPPOPPMOPNOOQLOPPOPPMONOROONQPOQPPOOPORPQOONPOOONOPQP", 52 | "ROOPPPPPPPOPQRRQRRRSSRQPPPOOPOQOOPPPPOPONNOOOOOOPPPPPOOPOOPPOOPPPPPPOPQOPNOOOOP"]; 53 | revWGI = ["SPPOOPPQQPPRRQQQQQQQRRQPPPOOPRLPOSPNQPPPPOQMQQORMORNPQSJORNSTNMPRQLPRLPPRPOROPP", 54 | "VPOOPPQQQQRTTRPPQRRSTSRQPPPOOQPQOOMQQQQNPOMQPPPOQROPSPOPOOONOQPQPPPQOQQNNSNOLMP", 55 | "UPPPPOOOPOOOOOOPPPPPPOOPPPPPOPOPOQOOOOOPPPOPNPOOQRPOQPPONPOPPQNOPPOOPPOOPQPQPOP", 56 | "SPOOOPPPPPQQPOOPPQRSSQPPPOOPPPPRNPORQRQNRNOQQOQOPONQSNNQQNPPOOOQPPQQNOQMORNPOOQ", 57 | "XOOOOPPQQPPQRQPPPQRRTSPPPOOOOQNQPMPQRQQNQOORPPPRPTOPSPPQPMPPPPPQRPPQNPQNOUNQOPQ", 58 | "SOPOOPPPPPNPQNLNOMMQQRSQPOOOOTQSNMKRRSQMNOPQPNQLMQMPRLSONKRRNNORMMRRNPRONSNLLKQ", 59 | "OPOPOPPQQRRRPOPPPPOPPPOPPPPPPPQNORNOOOPPNPMOPLOPQONOOOOPNPPPOOQOOPPPPPPOOOMNNMQ", 60 | "IPPOOOOOOONKKLLMLLLLMOOOOOOOPSSMORMMKMNROSOMNOLLLHRMMTQNLSOQONSMOTLQRQLPRHQOLMM", 61 | "TOPPPOOPPOOPPOPPPPOOPOOPOPPOOPOOOPOOOOOPOPOOOOOOQQPOPPOONPOPPPOOPPOOPPOOPPPQOOP", 62 | "PPOOOOOPPPPOPOOPPPPPQQPPPOOOOPRPOOOOPPPOOPNPQONNPPQNPRPOMPONOOQOPQOPPPOOPPOONNO", 63 | "RPOOOOOOOOOPPOOPPPPOOOOOPOPOOOOOOOOPOOOPOPOPOOOOPPOOPOOOOOPPPPOPOOPPPPPOOPPPOOP", 64 | "POOOPQSTTTVURNNOPOONOQRQPPPPPNPOOPPPPOPPMPKPQONNLORMNRNJNRPVTSNORRLPRKQOSNPQKOO", 65 | "POOPPPPPPQPPPPPPOONNNOPPOOOPOQQPOSPNPPOPPQPNPOOOMNQMPRRMLROQQOOPPQNOQNNPSPRPPOO", 66 | "QPOOOPPQQQMORRQSWUSPTXSPPOOOOOSPONQPPPPOROQNQUOLLLRRPUORMSOMNOUQQRMOOKOPSORQOPO", 67 | "KOOOOOOPQQRQPPPPPPPPPPPPPOOPPMQOOMPPOOOPNPPOPQONPJORLPLOQOPONOPPMNOPOPQRPKQMPPO", 68 | "FPOOOOPRQQPOOQPONNNOMONMNOOOPOPLROPOPOQQMOONPMNNIFOKIPOPQUQROLTNQRPPQPQQMINLNOM", 69 | "NPOPOPRRQRPNOQRV]VNNRVQOPPOOOOTQPPPRPQPNQOOOQSPLQKPOPQPSNLPLOPTQNQPPNNMPOOPNNMR", 70 | "QPPOOOOOPPQQOOPPPPPPPPOPPPPOPPQOOOOOPOPOOPOQPOOOQPPOPQOONOONNPPPPQPPOQPOPPOPPMP", 71 | "UPOPOOPPPPOQQOOQQQQRTSPPPPPPONNROOPPRRPMPONQRPQMQQOPTQNNQPONPPMSOOQQOOQNOTPPMPR", 72 | "ROOPOPQQQROOOMMNOOPRRQPQPOPPPQPPNMMQQQPOQOORVOQRWPLQQLMQSOPPQPPROPSQMSQONQORPLR", 73 | "JPPPPOOOOPPOOPPPPPPPOOPPPPOOPQPNOOOOONOQPONOOMOOORPPNNMPONQRPMQNOPOOPOOPONPOOOO", 74 | "ROPPOONOPQRRQPPPPQQRQPPOOPOOPPPPOPPPPPOOOPMQPOOPPQOOQPPONONNNQOPQPPPOPPOPQOPONQ", 75 | "MPPPPQRQQQRWWUUUUSRRSTQPPPPPOQRPOSPOPOQPMOPOOOPMLLPOMRRLPPQUQNNQPPOPPKOQSMNMNSO", 76 | "QOPPOOOOPPPPPPPQQPPQQPPPPPOPOPOOOOOPOPOOOPNPOOPPPQOOPNOPOOPQOOOPPPPPOPPOOPOPOOP", 77 | "RPPOPPRSSRPRQPOQSSSSTSPPPPPPPPPROSPPQQPNNNNNSNQQQNNQPMPOPQPQTPNQPOQQONPNNPOQNPS", 78 | "SOOOPPPPRRLLNJMPTSQNPMJMNOPPPJLPPRPQQQPOMNSPSNQLNPNTRSNLROOPPMORPKSPNQQNORLNMOQ", 79 | "QPOOOOOOPPQQRRQPQRSTTTQPPPPPPQQPOOOOPPPORPQQPPPPQPOOPPQONNPQQNOQMQOPONQPQPPQOPQ", 80 | "QOPPPQRRRQSRPOSTSOMPNPMMNOOOPLLQOMSOQPNPUPMNQSNTNLQMOQQPPLJMRUTPOTLQQMOQPOPQIQO", 81 | "SOOOOOPPPPPPPPQQPPQRRQQPPOOPPPPOOOMOPOOQRQQOOPNPQPQMPQQNNPPRSOMPMRMPRQOQOQROONO", 82 | "YOOOPPPPPPPQQPQRTSRSTSQQPOOPOPOROONRQRQNQONRQOQOPRNPUOOPPLQOOPPRPPQQNPQMOUMOMNR", 83 | "QOOOPPPRUWWUWVQRWUQPRQPOOOPOOKONOPTOOOOQJPQNPVMNKLSPNQPOLPPOPQOORQMOQFNQNMPMNQO", 84 | "SOPPOPQRSSRSRPOOPPPOOPPPPPOPPOQROPQPRQQOQOSPRQONOOQPQSOONQMNNQNROONQQNPORQPQSQR", 85 | "PPOOPPPPOPRWWUSSVUUTRPOOPOPPPRQPOLTOPPQONNPOPRNPMMQQPSPSLNNKOPSPQUNPOJOOKOOROSO", 86 | "UPPPPQSTUTSVVUSRQQQQPPPPOOOPPSOQPTQMQQPNNPRMPPPONNOQQQQMOROQQOOPONOPQLOOQQOPPPQ", 87 | "QPPOPOOOPOOPPOOPPPPPPPOOOOPPOOOOOONOPONPPPOOOOOOPOONOPONOOQQPNOPOPOPPPPQPPQPONP", 88 | "ROPPOPPPPPTUTQNMNQTVVRNOOOOOOVLONSPOPPPPPOSPNQOPKMQOOTUMMQMPUQKOMNMOQKPOONQSJQM", 89 | "TPPOPPPPQQQRSRRRSSRQRRPPOPOPOPOPOOOPQQPOOPOPPOPOPQPOQQQQLOOOPPPPRQPQOPPOMRPPONP", 90 | "QPPPOOOOPPOOOOOPQRRRRQPPOOOOPNQOOONOPOOPOPNOPONOQPPNPPPMOQOPOQOOPPOPPROONPQPNLO", 91 | "LOOPPOOOOPOOONOOOOOOONOOPPPOOQQOOOOOPOOPOOONPOONOLQOMOONNQPPPNQNNPNOQPOPOLPNPNO", 92 | "RPOOPPPQQQRQPPPPPPQPPQOPOOOOOOPPOOPOPPOPPPOPPPOQQPPOPQPNPPOPNQQPQROPPPPOPPPQOOO", 93 | "SPOOPPPQPPPRRRRSRRQRSRPPOOOOPPOQOONQQQPNPONPNNQPQQNPRMOPQMNOQQMQOPQQOQPNLSOQKMP", 94 | "LPOOOOPPQRQPPPPPPPPQPQPPPPPPOOQPOPPOOPOOOPNMPOOMPLPPLQNNOQOONNQONNNPPPPPOLPONNO", 95 | "QOPOPPPQQRRTTRRQQPPQQQPOPPPOPPPOONOQPOOOOPNPQNPPQQNOQONOQNQPONPOPPPPOPPNPQLONOP", 96 | "UPPPPPPQPNOQQQPOOPRSSPOOPPPPOLNPOOONQPPPQPQQQRNOOQRORSOKMQOOMQKPQOMQQNPPPRQQPOO", 97 | "QPPPOOOPPPPPPPPQQPPPQPPOOOPOPOOPOOOPPPOOPOOOOOPPPQOPPNNPPNPPPOOPOOPPOOPOOPOPOOP", 98 | "SOOOOPPPPQRRQPPPPPQRQPPPPPPPPNPQOPPPQQONPPOQROQOPSOPRPOOONPOPPNRPNQPOOQNPSOOPPQ", 99 | "TOPOOONNOPOOPSRPQSTTQONOOPOPPNSOOSLPQOPOONPQTPOQPPQMQSUPEQSPROMQPQOQPSQOIRRRPJQ", 100 | "PPOOOOOPQQQQMOSWUTSQRPNNNOOOOLQQOOROPPPOPOTMPSNKMMROQWPSDRKKKRQQQPMOPMMPMOUQPSO", 101 | "SPPPONNOPQQPNMPRLHJPNNQQPOOOOUTSNLJPQSQMNQLRPMQKOQPJROTLPOQRJPSQMRQQORPQTRNLLJP", 102 | "POOOOOOPPOOPPPOOOOPPPPOOOOPOOQONOPNOONNQQPPOONNPPORNOPOLMPQSPMPNPPMORPOQPOQOPNO"]; 103 | 104 | fwdWGF = ["OOOPPOOOOOOPPPPPPPPPPPPPPOOOOOPOPOPPOPPPOPOPOOOPOPOOPPOOOOPPOOPOPOOOOPMPPPPPPOP", 105 | "OPOPPOOOPQQRNNKLONMMRTQNNOOOPONMRRQRQOLNONNLNNOOQSQPQMMPNNPPOOQRQQSPOSOORNOMOQO", 106 | "QOPOPOOOOOPPNLKLOOPRQPPPPPPPPONPROPQNPRLOQOOOOPPPNOMPOQOONPPMMOONQNTOOKPOOOPOQQ", 107 | "TOPPPPNMNOPTQPPONNNORPONMNOOONSNOQRRRQOLNMMMSNONLRSOTGOQNNQQQMQRTLTPNSMPRONKNTO", 108 | "POPOOOOPPQPPPPPQRQQQQQPPPPPPPOONQOOPPONPOPOPOONPPPQPOQOOONPPPNPPOOPOOPNPPOOQOOP", 109 | "YOPOOONNNMOOOONOOOPRRQQQQPPOPRNQQOMLOQONSQRPSQMPNNRQNRRORPNMSMNOPOOOQOKQNNQPLNQ", 110 | "POOPPPPPPPRPOQSTUVWUSRONNOOOOPOQNNNMOPPMPQQNPQMPPNPPNOSOPMOONNNOOONOPNNPMNPQNOO", 111 | "QOPOPPPPPPOPPOPPPPPPPOOOOOOOOOOPRPOOOOPOOOONNOOOQOOQPPOPONPPONPOOPOOOONPONOQMNP", 112 | "OOPPPPPPQPPPPPPPPPPPOOPOOOOOOOOOPPQPPOOPOOOOOOOOOPPOONNPOPPPOPPPNPPOOPPOQOONPPN", 113 | "OOPPOONNONMQQQSPNRUPLKMMLMOOPPRNSPQTQPROPNPQJPRPRQPMRIONQMNOOMOQNOTQPQLQPNPLORN", 114 | "QOOOPPPQRQOONNOOOPPOONOOOOOOONQOOQPRQNNONONNLOONPQQOQOOQNOQQNOQPNOPSNRNNQONOPQP", 115 | "OOOOPOOOONOPPPPPPPPPPOOOOOOOPNPOQPQPPOPQORNQNNOOOQNNQONPNPPPNOPOOOOPOPLOPQPPPPO", 116 | "PPPPPPOOPPPPROMOPQRSVVPOOOOPPPNNOOPRQPPNPOPNOPLPNRQPQLQOPPOOLNOQPLQRPSNQOOQQPOR", 117 | "POPOOONNNNOOOPPPPOOOPPPPPPPPOPPQQOOPPPPOPPOOPPNPPOPPOPPOPPOOOOPOPOOOPOMPOPPPOOO", 118 | "PPOPPPPQQPMRQOPOORTUTPSPPPPOPPNMNQPOQRQKQJOPSOOPKRPPPEOOPRNNRHOSQOXKQRMROKPHJSN", 119 | "POPOPPPQRSQPPQQQPPPQTSPNNNOOPPRNPPPRQPOPPSOPOONPMQQOQPNOPQOOOPPQOOQQPROPQRQOOQQ", 120 | "QPPOOOOOOOPPPOOPPPPPPPPPPPPOPOOOQOOPPPOPOPOOOOOPOOPPOPPOOOOPPOPOOOOPPPMPPOPQPPP", 121 | "NPOOPPONNPQRRTUSSUUSQQONNNOOPPMSQOQQPQQPPNOQNPQQPQOONQRNPNOOQLOPQPSMPRLQNMQOOMT", 122 | "POOPOPPPPPQPPPPPQPPQPQQPPPPOPPOOPPOOOPPPPPPPPPPONPOOOPPPPNOOPOOPOOPOPQOPOOOPOOQ", 123 | "OOOPPOOPPPONOPQSUTRPPOPPPPOOOPLNOPPQPPNOPNOOOOQPPQQOPOOOPOOOONOQNOQPPRNPPNPOOPP", 124 | "POOPPOPPPPPOMMMOQRSTTTRPPPOOPPMPQOPOOPRNPOOPOPOPPNPOPPPOPNOOPMOOPOOQPPNQONPQMOQ", 125 | "ROPPOONNOONLLLLLOQRQQNONNOOOONROVPQRPONONMNOOOKOLQQUNKQPNQPQNPPPQOPQNQNOPNNMRPP", 126 | "NOOOPPPPQQONPPPOPTVUUSPNNNOOPPRQRPRMQQMNPOONMOOPPPOOPJQOPKOOQMOPQOROPOLQOMPNONR", 127 | "POPOOPQSSRRQPQSSSSSTSQPOOOOOOONQQPPPOPNOOOOMNONPONOONRPOOLPPPNOORPPOOOKPOPQPNMP", 128 | "JOOOOONNOORRWXVVVTRPNMMMMNOPOQQOPOPPPQHPQOQQPPNRPOUQOQONRMNNRMOPOKOHRMLRPORQQOO", 129 | "QPPPOOPQPQQONMNNOOOQQQPPPPOOOOMPQPPQOPPNONOOOOPOOOPOPQPPOOPPOLPOOQOROPKPONOONOQ", 130 | "OOPPOPOPPPQPPPPPPPPPPPPPPPOOPPOOPPPOOPPPPPOPPOPONPPOOOOPOOPOPOPPOOPPPPOPPOPPOOP", 131 | "OOOPOOOPPOOPPPPPPPPPPPPPOOOOOOPOPOPPOPPPOQNQOOOPOPNOPPOOOOOPOOPOPOOOOPMPPPPPOOP", 132 | "MPPOOOOOOOSWTRQPONOQPLNOOOOOPPONOPOQPQMOPOOSQONQQUOOSQONPMOOPMPTSOUKPSNRPQRLPKR", 133 | "OPOOPPOPPPPPPPPPPPPPPPPPPOPOPOPOPPPPPPPPOPOPOOPOOPOOPOOOOOPPPOPPOOPOOPNPPPPPPPP", 134 | "OOPPOOOOOOPPPPPPPPPPPPPPOOOOOOPOPOQPPPPPOPOPOOOPOPONPOOOOOPPOOPOOOOOOPMPPQPPPPO", 135 | "QPPOOONNOOOQQPNMOOOPRPONOPPOONQLNQQPRONONONONNMONTQOPLNPNPPQPMQQONSNNSNOQNONQRM", 136 | "NOPOPPPPQQQOOPPPNNMNRUQOOOPPOOOONQQPPONOOKONONPOOPMQNNNPONPPOQQPOQPPOOSNQLOLOMO", 137 | "QOPPOOOPPOPPPPOPPPOPQPPPPPPPOONPQOOOPPOOOPOOOONPPOPPPPPOOPPPONPOOOOOOOLPOOOQOOO", 138 | "NPOPPOOOOOOONNNPPPPQQQOOOOPOPPOQRPPNPPPOPPOOPOOPONPPPPOOPMOOPNOOOPOPPOOPOMQPOOP", 139 | "ROOOOONOQQRQONMLLONOQQSPPOOOONQMOQQQQOKNNPNTPNPOLRSQQMOPNNPPNMPRPQSNOSOOQONMSTP", 140 | "POPOPPONNOQRMNQRTUTQMLQRQPPOOPRORROTPQRMQGPTOOVPNRTMSMPOQLONOJORNSUNQQOQNIPINOR", 141 | "OOPPOONNNOQQMKKNNMORTTQPPPPPPONQPPRNOPQLPQOQPOMPPNSPOLQOPPOOOLPLQPNOPLLPOOQOOSO", 142 | "NOOPPONMMKKNQRQOQRRTTSRPONOPOPNORPORQPNMPOOPPOPPROPLQFQOPNOONLPPNNRRPOOPONPKMOQ", 143 | "OOPOPOOPPPPPPPPPPPPPPPPPPOOOOOOOPPPPPPPPOPOPPOOPOPOOPOOOOOPPOOPPOOOOOPNPPPPPPOP", 144 | "OPPPPPPPPPPONOOPQSRRSSQPPPOOOPMPQNOOOQQOPOPPOPOPROOOOPQOPMOOPMNNPQOOPONQNOQQMNQ", 145 | "[OPOPPQRRQPSSRRSSRRRSSQPOPPPPNPLOQQQPLPOMNONNNQMNQOPOONSMPRROQQPNPPPMPQLQPJPPOO", 146 | "POPPPOPPQQQRQPPQQPPQQQPPOPPOPOPOPPQQPOOOOPOOOOPOOQPOPNNPOPPPNPQPPOPPOQPNQQONPPO", 147 | "QOPPOOPQPPPPOOOOPPPQQQPPPPPOOOMOPPOOOPNOOOOONPOPQOPPOQPOONPPPMOOOPPOOOKPOOQPMOP", 148 | "OPPOOOPPONQSQOOONPRTRLLONNOOOOPQRPORPPPQOLNPPOLOLQRRNFSPONPPOKPQPPPPORNPOMOJJQM", 149 | "UOOOOPOPPPQQQRRRRRRRQQQPOPPOONPMQQPPQMRRNONRMNPMLRNOQONRNQRQMPQQPMQNMSPMQRLQPPS", 150 | "POOPOPQQQQTSOOOPQQSVUROOPPPOOOPQTPQOPPOOPROQOOKQNQSSOTPNPOOONLOQQLQLPQLQPQQOMNR", 151 | "QOOOOOOOPQRQONPSSRRPPQPOOOOOOOOPNQPRQPMOOKNPOONOORSPPNPOOMPPOKPROOTPOSOPOOOOQMP", 152 | "MPOOPPQRQQTTRRRRTTSRRNMMNNOOOQPOSOOOPQNMQOPMPPQQQQPQRNONQKNONKOQLQROQOIROMQNLOO", 153 | "OPPPPPPPPPQQPQQQPPPQQOOOOOOOOPOMQQPRPPNPPNOMOORPNRPOTLNOOMOOONPQOORQPSMPQNPQRQP"]; 154 | revWGF = ["NOOOOOPSUURRSRQRQQSTTRPPPPPPPPQOQMONNONOPQNMNNQRSNPLNPQMPMPPROROOSNOORMRPNMQONO", 155 | "NPPPPPOOOOQOORSRPPPPNPPOPPPPORPNQLROONOQRQSNPPNRMMOOMRRPPOQLOOROMNNOPOOPTMPHSSQ", 156 | "VOOOOOOOPPOOOOPQQPPPONOPPPPPPPOQOQPONQONNPPNHPQPPSOPONOONONPPQOOQNPOPNMPPOOQOPP", 157 | "UOOPOPPPPPQQRRRRRQQRSRPPPPOOPMMQRQRQQQQNQORQQRPRNNOPRRRQPOMMNSQQRNPQONQNQRNPRRQ", 158 | "OOOPOOMMNOTRRNKLMOQQPPQPPOOOORNPOPMQOPQONPQOONPOTNPQONQKPQRNQOINJLONPPNPRNONONO", 159 | "RPPOPOPQPOQQLJKKMMMQXWRPPPOOOMMPQKRNOQNNNPQLJUPNNOQOOWQLSONLNOSPQINOOONQSPQMPSP", 160 | "RPPOOONPQQQPOPPPPOOOPQQOOOPPOQPOOPOPOPOPQPOOOOPQOQPMQNRNNPQRPMQOOPNPPRPOTQNNQNR", 161 | "JOOOOOOOOPOMLMNNNMMMNPPOOOOOOQROPQOOKNOQOPOOOONNMIPPNRPQNPOOOOTNOSOSPPNOPIPOLOO", 162 | "TOOPOOOOPPPPPPPQQPPPOOOPPPPPPPOOOPPONPOOOPOMIOPPPSPOOOOONNOPOPONPNOOPOMPOONQNPP", 163 | "ROOOPPPPPPPPPPPQPPPPPPPPPPOPOQPQOQOPPQQOOPNPNOPOQRPOQOOOONPOOOPOPPPQOOOOQQNONOP", 164 | "TOOOOOOOOOPPOOOPPPPOONOPPPPPPPNOPPPNOPOOOPOOIOQPORPOQOOONOOQPPOOPNOOQNNOOQPPOPP", 165 | "PPPPPOOPQSSUURRRQOONPQONNOPPPOSQOGNOOQNNPQKNNMQKRNNNOQLONOSMMNPPNROONRNPOOQMMNP", 166 | "RPPOOOOOOOOPPPPPPOPPPOPOPOOPPOPQPNNONPNOQRNNNNOOPQPMRPONOPPPMPNPOQOPPPNPQQPNOOO", 167 | "OOOOONNNOPORROOUURPOQRQOPPPPPPPPPJLPOPONRRPNOMRPTNNKOKQNOQPUQLQPJRROOWNOSOOLRLR", 168 | "WPOPOOPPPPQRQQQQQQQQRQPPPPPOPOOPOPPPOPOOPPOQNOPQQVOOVOOOOOOPNPNOQOPOPOPKOVMPOOP", 169 | "XOOPOOOPPQQRQQQQQQQRSQPPPPOOPNOSQPQORSOLROOQOPQQQWOOYPNQONPOPQMQQPQQNNOGP]LSOPR", 170 | "NPPPOOQRQQTOJIKLMKOUTPNMMNOOOSQOPOLPOOPPUPRNQQRQVNLNOMSQUOOQUNROKTPPOWOOUOLPOLO", 171 | "ROOOOOOOOOOPOOOPOOOPPOOPPPPOOPPOPRPOOOPONPPQLPOOOQQOQPNONQOPOPOOPPOPPOOOQQNPPOP", 172 | "PPPPOOPPPPQLJORSVTSONPPPPPPPOPRMQTNONMOQOQPOMKPSQNNJNQRQMQOPSPSNOPPNNRMQQMNOQOO", 173 | "NOPPOONNNNQRQSSSSSRQPOOPPPPOOMNPPPSOOPNPOQNNLQOOKOPLONRLMOMPNRMOPKNOPOMPSOQKOSP", 174 | "JPOPOPPOPPPNOOPPOPPPOOPOPPPPPQONPOPOONOQPONOOMOONSPQNMLQPMQSPLRNPPOOPNOOONPNPPO", 175 | "OOPOOOOOONPQOOPPONOPPPOOOOPOOMPOPMPPOOPPQPOQOOPPNOOPOQNNQQONNPOPMPPOOQPPQOPOPPO", 176 | "POOPOONOPOOSSRRTTSTVVQPOPPPOPQRPOLNNOPPNOPOMIRQKPOONOPOOMPNKOPKONQONPPLPPOQMOPO", 177 | "SOOOOOOPPPPQQPPQQQQQRQPPPPPOPOOPPOPPOPPOOPNPPOPQPSOPQNNPONPQONPQQPQPOOPOOROPOPP", 178 | "MPOPONMMQTTUURTRMNRQQPOOOOPPPRQOPLPONOPPKRNMKNQPOMPKMLRMLQPQOOPNQROOOONRUMMLROP", 179 | "RPOOPPOOPPOUXTV]ZQORRPOOOOPOOOUOOSNJNPMOMPNPHLPNFRQNPUPLRQRVLNMNQONMQJNPUOQKNNP", 180 | "ROPPONNNOPRQMMNPPQQONNONNOOPOOQPOINNOPONMPMPKRPNPQQNQRPPNPNKNQNPTTPOOPPOPRQSJLO", 181 | "PPPPPPQSSRV[UORTSQQRRPPNNNNOOQTQQGNKOPNNQQQNMLPLLNPLQYRMOLPNMNOQHQPNMVMQQQSPPPQ", 182 | "QPOPOPQRRQRROMNOPONOQPQPPOOPOPSQPMLNOQMOOQPNJOOLQONPPPNNQOQQOLRPOOQOOOMPROOLPNQ", 183 | "RPOPPONNNNPLHIKMHILNKLONOOOOOSMMQWSSPNQRRPRQPMONHOQOPNOLNONSRNNQMJMORKRNYQOJRYQ", 184 | "SOOOPOONORTVURRSOMORSROOOOOOOPQPOGKLNPNOPSNLMKQOTRPFOSWIKOPLPOJOJWQNNYMRQPQUMJN", 185 | "OOOPPQQPOLNRRQRRRPNOPPPOOOOOPPPQPHONNPOOPRNNLNPQRPOMOPMQPNRONKUPPSPONSMRQOOONOP", 186 | "MPOOONKJMPSXUPPTJDIQUSPOOOOPPMROPDNMNONOMQPLOLONRPOLORLNOPPKJPPMMRQNNUMRNNPPSPO", 187 | "KPOPPPQPONPVVVURPPOMMILMMNOOOOOOPCMLMOOORRPLNIQKQLNJMOQKKORMPKVNHRRNNTORPLOLNON", 188 | "RPOPOOPPPPPPPPOPPPPQQPPOPPPPPOPQPPOPPQONOPMOLOPOOROOPONPOMPONOQQQPPPONPOQQNNNPP", 189 | "MPOOPPQQQQTVRGHMQTRPQRPONOPPPOQOPGKPMOOPSQPOOGQOSNLJNOOLNRSSTIRMOTPNMWNPQMOPNMN", 190 | "NPPPOPOONOPOOOQRRQRTURONOOOOOPQNPOOOOONPQPONLOPPSOONNPQORQQONOPNQOOOOPNQQNNQOMP", 191 | "QPOPOOOPPOOOOOPQPOPQQQPOOOOOONQOPPNOOOOOPQPPOPPOPPOOOQONPRPONPPOOOPPPPOPPOQPONO", 192 | "MOOOPOOPPPPOOOPPPPPPPOPPPPPOOQPOOPOPQOPPONOOPOOOOMPOONOONOPPPNQOPPOOPOOOOMPOONP", 193 | "QOOPPPPPOOPPONOOONNOPQOOOOOOONOPPPOPOPPOPPQPPPPPOPPOPQPPPOOPNQPPPQPPOPOPQPPPPPO", 194 | "OPOOPPOPPOUWNIIKKLOQROOPQPPOOOPOPKPOOPQOQQQNKQOQSPPKOPXLPMOPPOMMLNOOORMQROOQOKN", 195 | "SOPPOOPPPPQQQQRQQQQQQQPPPPPOPNOPPPPPOPOOOPORPOPQPRNPSONPPOPONPOOPOPPOPQKOSOPPOQ", 196 | "TOPOPOOOOPQSSRSSSRRRRQPPPPPOPMOPOMNQPPOOPPOQQOQPQSMPTNNOQMPONPMONOPOOPQLMTMPNOQ", 197 | "QOOPPPQQQSLJQVVUSPONQTQONNOOPRQQPNPNOQONOQOMNMPPQPNMOOQPNPPPOOTOOOQPNPNPMOORQNO", 198 | "TPOOPPPPPPPPPPPQQPPQQQPPPPOOOONPPOPPQPPOPOOPPOPPPSNPRNNPPNPPOOOPPOPPOOPNOROPOPQ", 199 | "PPOOOOOOOPPPOOPQQQQRRPQQPPPPOORROPPPORONMPLOGNQLOPNOOONPNNQNMPPPPOQOOMOQPOQMMPO", 200 | "PPOOOPQQQQNLLOQQQPPPRRQNNNOOOPOUOUQPNTOLNOOPINTPNOMQOMOPRQOOORUQSMQOPLPQSONNROS", 201 | "NPOOOOOPPQPNMLMPRPQRTQPOOOOOOVRQPKLPOQPNQQQMPLQOTNNKPLRKTOQSRKPOLQROMZNOTPNMPKP", 202 | "RPOOOPPPPMNRPMLPRPOQWVUQPPPPPRMQQIUMOPONRSVKLROSORQJQTXIQRNLTSMMJKNOPRLRSQRLPRO", 203 | "TOPOOOPPPPQRRRQQQQQQQQPOPPPOOMPQOOOPPQPNNPNPMPPNOTOPQONPKMPNLOPPRNPPNOOPMRMOPNO"]; 204 | 205 | fwdWGO = ["ROOOPPOOONONNOOOPPOOOOPPPPPPOPOPOONNPPNOPOPOQPNPOPPPOPQOPPOOPPOOPPPOPPOPOOPPONP", 206 | "SPPOPPPPQQQSUTRPRRQQSTQPPPPPPMONOPPOPNNOMNNLLNPMPPNOONOQMNRROPQPNPOQMQQNPNMPPON", 207 | "TOPOOOPOPPQSRQPPPPPPQQPQPPPOOMQNQQQRPMQOMMNPMNOMNQOPQMNRMQRRNPQPQPQPMQQMQQLNQQO", 208 | "TOOPPPQQQQQSSSSRRRRRQOOOOOOPOMRONPRPPMRNMNLOMNOMNPPOPMORMORRNPQPOQPRMPRMPNMOSPO", 209 | "QPOOOOOPPPQPOOOPQQQPPQPPPPPPPOPNPQPPQNPQONOPNNQNOPOOQPNQOMQPNPQPOPPPOPRNQNNQQNP", 210 | "SOPPOONMMLNOONNOOOPRSRQQPPPPOONPPPPMPOMOONOPPPNOOPRRNOPPOOPPRNOPPPPLOPNPNMOOMNO", 211 | "SPPPPPPPPPRSRQPQQQRRSROOOOPOPNQPMPPPONPNNOONMOPNOONNPNPQNNQQMRPOPSNRNPSMOOMPSPO", 212 | "QOPOPPPPPPPPPOOPPPOPPPOPPPPOPNPNPQPQPNQPNNOPMOQNOQNPQPNQNNQQNPQPPOPONQQNQONPOOP", 213 | "OPPPOPPQQQPPPPPOPQPOMMNOOOOOPPPPPQPPQOOPPNPOPOPOOQPPPNOPPOPOOQPQOPQOOQROQOONPPO", 214 | "VPPOPPQQQPQTTSRRRSTTSQPQPOPPPNNNQQQPPNPPNMNPNNONOQOQQPNQNPQQQNQQPQRONQOOQNNNNOP", 215 | "SPOPPPPQRRRRQQQQQQQQRQPOOPPPONQKNQONQNLPNQNPNOPMNRQPPNMQNOQQQOQQMORNNQPNQNMOOOO", 216 | "TOPOPPOOONONOPPPQQPONNOOOOOPPPOPNONNOPONPOPNQPNOOPPPNPQPPQOOPPOOPPPNPPOPOPOPOMP", 217 | "SOPPPOOOPPRTSQQSSSTTSQPPPOOPONPOQPQQPNQONNONNOONNPOOPNOQNOQQMPPPNPOSNQQNPMNPSPO", 218 | "TPPOOONNNMNNNOPOOOOOOPPPPPOPPPOPPNMNOPOOOOPNPPNOPOOPNQQOPOOPPOONOOOOPNNPNOORNNP", 219 | "UPOOOOOOOOQUTSSSTUUVUQOOOOOOONNOOQQPQNPNMNNPOOMMOQOQPNORMSQQPNQQRNSONQQNPPNNNOO", 220 | "WOPOPPPQQQPPQRRSSTSSQPOOOOOOONPMQOPPOOOONQNMMOOOPPOOOPPPNPQQNPPONOOQNPPNOPOPPOP", 221 | "QPPPPOOOPPPPPOOPPPPPPQPPPPPPPOPOPPOOPOPPOOOOOOPOOOOPPPOPOMPPOPPOOPOQOPPOPMOQQOP", 222 | "PPPPPPPOPPQQRSRRRSSRRQOOOOOOPNPNQQQQQNOPNNNONNPNNRMRQOMQMOQQOQQQOPRONRRNQMONOMQ", 223 | "PPPPPPOOPPPPOOOPPPPOOPPQQPPPPQOPPQOOPQOPQOPPROPONQQPPOPOQOONPPPQPPROPRPPPNPNONP", 224 | "RPOPPPPPPPPQQRQRSSSSSRPPPPPPPNNMQQPPQNPPNMOOONONNQORQPMQNPQQONQQOORONQPNQNNONNO", 225 | "SOOOOPPPOPQQPPPPQPPQQQPPOPOPONQMPQQQQMPOMNNPMNPMORPPQNMRMORQNPQPQOQNMQRMRPMOQOO", 226 | "UPOPPPPPPPQSRQQQRRRSTRPPPPPPPMQNQQQRPMPOMMMOMNOMOQPQPMNRMPRROPQPPOQOMQQMQOMOPPO", 227 | "NPPOPPONMMOSSSSQRRRRRQNNOOOOPNSPNPRQQNPOMONQNNNNNQPOPLOQNPQQPQQPRNRQNQQNQQMPPRP", 228 | "QOPPPPPQPPRQPQQQRRRRRRPOPPPOONPOOQQSPNRPMLNQMNQNNQNOQONQNOQQNOQPPOQPNQRNPONOPOQ", 229 | "UPPOOOOOONOOPQRTTTSTRPOPPOPPOMRPNPQQOLQOMNNOMNPMNOPNPMPRMORRMQQOOQNRMNRMPOLNTQO", 230 | "SPOPOOPPPPRQQPPPQPPQQQPPPPPOPNQNOPPQPNPOMMNONNPNOQPOPNNQNNQQNOQOPPOPNPPNQPMOQPO", 231 | "OPOPPPOOPPPPOOOPPPPOOPPQPPPPPPOPOQOOQPOPQOPOQOPONQQPQOOPPOOOOPPQOPROPQPPPNPNOOP", 232 | "RPOOPPOOOOOOOPPPPQPOOOPPPPPPPPNPOPNOPQOOPOPORPNPOPPPOPQOPPOOPPOPPPQOPPOPOOPPONP", 233 | "ROOOPPPOOOOQRPPQQQQRSRPOOOOOOLQMOQRQQMOPLNLRMMPMOROPQPLRLORSPORQQOSMLQRMRPMNQNQ", 234 | "PPPOPPPOOOOOOOOOPPPONOPQPPPPPPOPOPOOPPOOQOPOQPOONQQPPPPOPOOOOPPQPPQOPQPPPNPOONP", 235 | "QPOOPPOOOOOONOOOPPPONOOPOOOPPPOPNONOPQOOPOPNQPOPOPPPOPQOPPOOPPOPPPPOPPOPOOPOONP", 236 | "SOPPPPPPPQRRRRQQQRRSSQOOOPOPONQNOQQQPNQQNNNONNPNMQNOPPNQNOQQOPQQPPQQNRQNQNNOROQ", 237 | "RPOPPPPPQPRRQQRRQPOPPPPPPPPOONSONRQQPNPPNNNPONPNNQRORNNQNRQQOORQQPSNNQQMRQMKPQO", 238 | "QOPPOPPPOOPPPPPPQPPPQQPPPPPPPOOOPPOOPOOOOPONOOOOOOOPPOOPOOPPOPPOPPOPOPOOPONPPOO", 239 | "QPOPPPPPPPQOOOOOPOOPOPOOOOPPONPOOQQQPNRQMLNRLNQNOQOOQPNQNNQQOPQQONQONRSNQNNQPOR", 240 | "UPPOPPPPPPQRRRRQRRRSSRPPPOOPOMPNOQPPQMNOMONPNNOMNQRQPNNRMQRRPOQQPPROMRQMQOMNPPO", 241 | "UOPOPPPPPPQSRQRSSSSSSQRRQPPPOMPMORQQQNOPMLMRNNPMMRRPQNNRMRRRQOQROOSNMSQNQOMMOPP", 242 | "ROOPOPPOOOPPONNOONNOOPOOOOOOOLQOMQRQPMSOLMLSKNPMOQONQNNRLPRSNOQPQOQPLQSMQPMPRPR", 243 | "TPOOOPPPQPQSSSRRRQQQRQPOPOPPOMQMOQQPPMNMLPMONNNMNQQQQMNRMQRROPQQPORPMQQMQOMMPPO", 244 | "PPPPPPPOPOPOOOOPPPPOOOPPPPPPPPOPOPOOPQOOQOPORPOPNQQPPOPOPPOOOPPQPPQOPQPPPOPOONP", 245 | "TOPPOPPPPPQRQQQPQPPPQQPPPPOOONQMPQPQQMPPMNNQNNPMOQPQPONRMORQNPQPQOQOMQRMRPLPQPP", 246 | "PPOPPPQQQQRTSRRQQPQQQQPPPPOPONQOQRRRRNOONNMLOMQOOQPPRMNPNPQQPPRRNPRONPRNSNPLPPL", 247 | "NPOPPPPPPPQQPOOOPPPPOOOPPOOPOPPPPRQQQPOPPOOOQNOONRQOQLNPPOOOOQQRPOROPRQOQOPMOPN", 248 | "QPPPOPPPPPPPPPPPQQQRRRPPPPPPONPNNQPPPNOPNNOPNOPNOQPOPONQNNQQOPQPPPPNNQQNQPNPQOP", 249 | "TOOPOPPPPPRTSQQQQRSTTQPQPPOOOMQOPQPQPNNOMOMNNNNMOPQQOMORMORRPOQQPQQPMQQNQONNPPO", 250 | "PPPPPPPOOOOPOOOOPPPONOOOOPOOOPOQPQPPQPPOPMPOPOOONQPPQNOPPPOOOPPQPOROPRPOPOPNOOO", 251 | "UOPOPOOOOOPQPPQRRQQQQPOOOOOOOLROOQQQPLQOKNMQLMQLOQPNONNSLOSSMOQPPOPOLPQLPQKNRPP", 252 | "QOOOPPQRRRRRSRRRSTUTSQOOOOOPOMPNMQRRPNOOMMMPNNPMNRPPQNMQMPRRNOQQPPROMRRNQPLNPPO", 253 | "RPPOOPPPOOPSRSSSSSSTUSPOOOPPOMRONQQPPMOMMOMOONOMNPQOPMORMQRRNPRPPOPPMOQMQPMMQQN", 254 | "SOPOOOPPPPPQRRRRRSSSTRPPPPPOPNRMNQQPPNNOMONPONQNOQPOPNNQNOQQOPQQPPQONQQNQOMOPOO"]; 255 | revWGO = ["TOOPOOOPQQQQQRSUUUUUUSPPPPOOPOPQNPNQQQPNPOKOPOQQSQNOQOOOPNPPRPPPSRPQOPPONRNRMKP", 256 | "ROOOPQRRQOPTSRRQTVUTRQQQPPPOOOQPNMKNPQPOMPMOQMOOPQPLQTRNLOSRRLSOUXOPMSPPMPMUOFO", 257 | "SPPOOOOOONNNNNNONMMMLMOOPPPOPOOONPNOOONQQPPQQNNNOQQLORPKMQPTQOLPMONORPPOPOSOONP", 258 | "PPOPPOPPPPOOPQQQRSTSQPOPPPOPOQQPMPNOPPPOPONOPOONPOPOPOOOOPQPPOOOOQOPPPOOOPOQONO", 259 | "ZPPOPPPQQQPQRQPPQRRRTSPPPPPPOQORPNPQRRQMQOORQPRRQUNQUPOQRMPPOPPRRPQRNPRLQVNQOPR", 260 | "RPOOPPOMNNMMLJKNOQSTUTQRQPPPPRRUNSLQQTPKPPORQLTJRQLOSLRONOQSPLOSLOUQLSRNQSOPNJS", 261 | "ROOOPPPQQQQPONNOOOOPPPPPPPPPPQQPONMQPPPOPOOPQOPOSQMQQNNQQNPOPOQPNOQPOQPNNQMMNNP", 262 | "QPPOOOOOOPOMNNOONOPPOOPPPPPOPPPOOONQPOPPPOOPPPPOPOOPPNNPONOPONPPOPPPOQPONOOOONP", 263 | "ROPOOOOOOOOONNNONMNNMNOOPPPPPOONNPNOONNPPPPQPONNOPQMORPLNPOSQNNONONOQPPOONRPOMP", 264 | "QOPOOOOPQQQPPPPQQQQQQQQPPPOPPPRPOOOPPPQOPONQQPOOQQPOQQOPNOOMPPQOQROPOPONOQNPNNP", 265 | "QPOOOOOONNOOOOOOONNNMNNOPOOOOOPOOPNNOONPOPQQQOONNPPNOQPLNQORQPMONONOQOPOPNSPONQ", 266 | "UPPOPPQRRRRSRPQQPPQRSSQPPPOPPPPROLNQQRPMOPJQPNPMSROOSPLOPNPONOPRRSPQOQQMNSMPKMR", 267 | "OOOOOPPPPPPQRRQQQQQQQPPPPPOOPPPPPOOPQPPOPOPPRPPOQMOOOOOOOOOOQPOQOPQQOPPNOOPPOOQ", 268 | "TPOPOOOOPPORSRRUWUSSUTQPPOPPPOQRNJKQQRPNRQOOQNQMSQOMRPPMPOQQPMPQMSQPNUPORRNOMLQ", 269 | "NPOOPPOOOOPOOOPPOOPQPPOPPPPPOPQPOOMNPPOPPOONMQONPMPOORNOOPPONNQOQQNPQPONOOPPNMO", 270 | "SOOOOOPQQQOKLNNONOPSRPQPPPPPOSPQNPOQQRQMMOOPRQRPRQNRRNKTPLNOMNRPTPPQNNQMMSKNONQ", 271 | "OOOOOPPPPQSRQRRUWTQSUUPNOOOOPORRNLKQPRQMSONNNPQKUNNNPPPOPNPNQONQITRPNVNPQPPPKKP", 272 | "QOOOOOOOPPQQPPQPOOPPONOOPPPPPPQPPQNNPPPOOPOQPPOOOOQNPRPNMQNNNQPPPQOPPRPOPPPQOLP", 273 | "OPOOOPQRQNPVVUVWVWVWXTPPQPPPPORROKNPPRONTPPOSPPJTMPPQRMLTRQMPNOSNRPQPQPORPRQMPS", 274 | "VOPPPPPPQRPOPPPQRRRSRRQPPOOPPPORNONSQQPNQPNRTORPSSLQTKNRQMPOOOORONSQMRRMOTMOONR", 275 | "MPPPPOOOOOONMMNONNOPOOPOPPOOPQQRPOOQQRPNPNOQQOQNPNOQQNMQQOPPQNOQNPQQNPQNOQPPOOR", 276 | "RPPOOONOPPSSRQQQQQRRRPOPPPPPPOPPOPPPPPOOPONQPPPPPQOPQQPOOONNNQPQQPPPOPPNPQOQONQ", 277 | "POOOPPQQQQRTTSSSUTTUTQPPPPPOPRPQONOPQQQOOOQPQQROQNNQPNOPOOONPONQOOQQNOQOPPOORQR", 278 | "QOOPOOONOPOMMNNONNOPPPPPPPPPOPPPOOMPOPOOOPOOPPOMQQPNPPONMOOPPNNPNPOPPQOPOPOOOMP", 279 | "UPPPPPRRSRRSSRRSRRRSSSQPPPPOPPPSOOOQRRPMPOOPSORPRQMPSOPPPNPOSPOROORQMQQMNSNROOS", 280 | "LPOOPRUUSPLSYWXWXUQTUSPOOOPOOOQQNPRPRQRNRNRNSOQONIMQOPNTVPMMOPQSKPQQNOPOLNNNNPR", 281 | "SPPPOONOPQPQQPPPRSTUUSQPPPPOPMPROHMOQRPMQPOQPNQPSPMNQOOPOMPNNOORNQSPMSQOMROOONQ", 282 | "XOPPPPQRRQSUSRSSSRQRSQPOOOOOPNOSPNNQRSQMRPOQRPQPRRNOURPOQMNLPRORPQRRMQQNOUMPMMR", 283 | "VOOPOOOOPQPOOPQPPPRSUSQQPOOOPQQQONKPPQNORRPQNPNOSRPNSPQONNPQQONPNROPPSOOOTPOMMP", 284 | "TOPOOPQQQPQTPOSUURPORROOOOOPOQSQNNJNPQPNKPJSPNNEMTSKTXWJFPTOQLQPTUPONUPOMRSSMGO", 285 | "ZOPPPPQQRQSVVUTVVTSRTSPPOOOOOOPRNNMQPRPNQQNPPOQOTTNNSPQNNNPPQPLQNQQPNSQOPTMQLLQ", 286 | "WPPOOPPQQPQTRQQRRSSSSQPOOOOPOPPRNNOQQQPNQPNQRNPPRSPNTPNPOOPONOORQQPQORPOQTOPPOR", 287 | "OPPOOOMKKMU[TOPSSPQQSPNNOOOPPMPRNJNNOROMMPKLOJQGOPRJPRQKJOTNNNLOOVPOOUNQROQUNON", 288 | "WOPOPQRSTRSVUTSRRSTSRPPPOOOOORPROPOMQRPNMQLMQMPNNRPMSTRLLQQQQNSQSRPPPPOORTORLOP", 289 | "POPOOOOOOOONNNOOONOQPPPPPPPPPOQPOMJPOOOPNPPPSPOKPOONOQNMPPPQNNNQNOOPPRPOQPOMNMO", 290 | "TOPOOOOOOORUSPQTTUVWWROPOOOOOPPRNNLRQRQNQPOQPNRORPMPQMQOQMRSPNNQOQQQMQQNRQMPNMP", 291 | "TOPOOPPPPPPRSSTTUTSRSSQPPPPPPSPPNOMPQPPONPPOOQPPQQPOQQRSLNNMOPRPSPPQOQOPKROQPLP", 292 | "QPOOOONOOPOPPPQQQQSTSRPPPPPOOOSPOQLNOOOPNPMPONONQOONPRQMOSPONQPOPQPPPROONPRQNJO", 293 | "NOPPOOOOPPONNNOOOOPPOOPOPPPPPPQOOONPPPPPOOPOPPPOQMPPNOMPPOOOPOPOOPPPOPPONNOPPNP", 294 | "ROOOOOPQPPRSQPPPOOOOOPOOOOOOOPQPPQPMOPPPOPPPOPNQOPQMPTRMMRNPPROPPQNPOOOOQPPSPNO", 295 | "TPPPOPPPPPPSRQQQRRRSTRPOOOOOPOPRONMRQRPMPONPMNQNSQLQRKNOSMOOQQLQMMSQORPMLSMOKMQ", 296 | "NOPOPPPQQRRQQRRQPPPQQPPOPPOOPQOPPMNOPPOONPPNORPNQMPPNQOPOQNMOOPOPOOPPQPNONPQMNP", 297 | "POOPPPPQQQPQRRQPPPQQQPOPPPPPPQPPOMNPPPPOOONPQPPOQNOPPPNPPOONPOQPQQPPOPPONPOPNNQ", 298 | "VOPOPPPPPOORRRRSTTTUWURPPOOOPMOQOPMPQQPOOQMPPNOORRPNSNNLPPPROQJPPROQPPPOPSNQNLO", 299 | "QPPOPOOOPPOMMNOONNOPOOPPPPPOOPPPOONPPPPPOOOOPPPOPOPPPONPONOOPOOPOPPPPPPONPOOONP", 300 | "UOOOPOPPPQQQQPPPQQQRQQPPPPPPPNPROOQQQQONQPPRQOQPPTOOSPOPPMONPQNRPOQPNOQNPTOPOQS", 301 | "WPOPOPPPQQPQQRRRRRRQRQPPPPOPPQPPNSNRROPPQPORUOOQPRPOSOQQKNPQPOQRRQPQPQQOOTOPPMS", 302 | "UOOOPOPPPPQTSRSUUTSTURONOOOPOPOSOKMQRRPMRPPQRORORRNNSPPOOMQPQNMSMPRQNSQNPTOPONR", 303 | "POOOOPPPPPNPNMOSUTTUVVTQPOOOPOORNMNRRQRNLNPRQQRMTMMSRMNTUNOKIRRQNPSRMQRNJRKMNNP", 304 | "QOOOOOPPPPONOQQPPPRSSRQPPPPPORRPOOJOOPOOOPOQPPONSPPNQQPOMPPPNNQOQQOPPTNOOQPOOKQ"]; 305 | 306 | fwdWCI = ["OPPPOOMLLLMLLLKJIJKIILMNOOPPPRORNMOONPQORPRPPQORQNPOOQRNRONMQPMNOPOPRMRQMOPPOOQ", 307 | "MPPPONMOQQRTQMU]WSPKJJJOOPPOOPWMOPPPPNNPOQPSQPNQORUPPNLOPOOPQMOQMJPKPOMOQPPNSRM", 308 | "PPPPQRSRSQQTSRKFCEIIHFJLJJMOOOPQQPQPPPNRONPPJPJQOPSTOLRNPQOOQONOQPMLPPQPPONPOOS", 309 | "SPPPPQRTXSRZWTTWQMKKMKLNQQOOOQKNVKNORUPQQNPKORORPOLWPLQMQIMMPMMONHQRRSIUMLTULMP", 310 | "NPPPPPQTUVTRQQPQRRQQSSRPPPOOPPNOPPOMPQJPPOONPOOPQOQONQNOPOOOTMPPOOPPPQLQPOQPOPQ", 311 | "GOOPPPQRSSUVVYZWWVTTTPONOPPOOMTQSQXVRQOOMPJQRLPQKTPPYNJOMRPQMQTURPVROUORTQSLLRM", 312 | "NPPPPPQRSTWUSRTTSOMNNPSWVTQPPPNQQNSRRRTOOKLSNOJPPPROKJQOOMOONJQPTNPLPPMROQPLHPP", 313 | "OOOOOONNOOOPRSTUTSRRSSQOOOOOPPNORNOOSQLQPOOLQPLQQOOROSOOPPNOPOQNOMONPOLRPPSQLMN", 314 | "QPOPPPPPQRQNNONMLMNMLNOOOPPPPQPQPMPONQQOQRQPQPQQPNNOPSQNQMNNPPNOPPOQQNQQNPQQOMR", 315 | "SPOPQSSPNRSVXNCIMJIJHLLIHJNOONONJSNORMTOMNPUQOLORRORQKKQNSQQPQQRNCSRNPSLVJMONRO", 316 | "LOPPONLLKMPQPSSPPRSTOKMSQQPPPQLMQRNPQQSRRJQRMNRPPPQOVTKORMNNPKOPLURKQUOPRJOQLSP", 317 | "PPOPOONMMNNKKKJHHIIHHLMOOPPPOROROLNNMQRORPRQPRORQLPONRSMSOMMRPLNPPNQRMSRLOQQPNR", 318 | "QOOONJFHLLMNNQTPRYYRLIFGHKNOOPPQNRNMPQTPORPMSPRQSNOMTONNPSNOLQMSIPSWPOOQPORVPUP", 319 | "NPPOONMLKKKKKLKIIJJIJMMNOOPPOQLPMNLLNPPPQNQPNROQSNPPLOQNQONNROMMOQMNQNRPMONPNNO", 320 | "OPOOOMJIGHHGFINTUOOOJLT_XSRQPMRKNQPSNLNLMQMOVNJLNVKPQUMSLPSRMQRSQQYILRTMQRLQTQR", 321 | "OOOPOONLLNOQSRQQTWXTNPORRSRPPURSPMMPMRPPSQUNRSPTSLRPNSQLUMKKQRLNPONRTJNRNNTTUPT", 322 | "POOOOONLLLKLMNNMMNNMLNNNNOOPOPNQMOOONOQPOOQQNQPOPOPPOQQPPOOOOPNNPQNPOORONPMQPOP", 323 | "TPOPOMLPUWRMMIHKMNPQPQSURQPPPPMMOSPRPPRLRMRQSNTNNQSJQLNPQHPONNQRVTQMPRSMPRNHRTO", 324 | "PPPOOONMMMMMMMMLLLLLKLMNNOPPOPORPORQOPRNPQNPOOPQQNOORPPNPPOOONOPOPPPPNOQPPQOOOO", 325 | "OOPOOOONNLLONJJKMSVSOKJGHJMOONOTPQPQQNQNNMOLOOQOQLMRMPPPONPQLQPOPXNJNLRNOTQKJOO", 326 | "MOOOOONOOQOMLMRV[ZYXXVTOPPOOOOMRMNPONPQNPLNOQPMOOMPLNMQPOPOORMPMRSQPPLMQMOOMNPN", 327 | "OPPOOIBBFHNQONSTTQMNMNQ[ZVSQPOKHNMPQPRKSPRNRPQKQSQSWLRPNPTOOPPOQNSQQPONSORQQSPM", 328 | "UOPOPPPRUTOPRQSSTRPORTURRQOOOPJLWLNMNRMLPPPLPRHOMOKXLWPOPNOONOMPJSRSPPNSJKPSMKQ", 329 | "PPOOOOPOQQRVWVWTTQMKOSRQRRPPPOLNRMPPQRONOTMQSOJPSQOTSPONOROPSIQTTPURPSMSPNRNOOP", 330 | "TOOOORUURR=89ANW[XQHHLMLKLMOOPPOSRNPNMPPPPSQPORMPSPQPOPQONPPMWNQQNOOOQULMONNSRN", 331 | "UOPOPONLKKOONONLHILLIIMOONOOOPNPONOONOOPPRRNNRNOQQRPOKSPPPOOOSLNONJPPPRONOLROPO", 332 | "OOPOPPQQQRRRRRRSSRRSTRQQPPOOPOPMOQMNPONPONPOPPONOQPPNNOQOPPPPPPOPOOOOPONPONOPPO", 333 | "PPOOOOMLLLLKKLKIIJJIILMNOOPPPQNROMOONPQORPQPPQORQMQOOQSNRONNQOMNOPOQRNRQMOPQPOQ", 334 | "SOPOONKKKIUZ[XYYUQQTTTRNMNOPOPEXNNQMMSROPONSSPOSPGLONPTLQXNOTLNRNOPNRLJVMQWPOOP", 335 | "OOOPPPQRRRRSSRSTTSSTUSRQPPOOPNPMPQOPQONPNONOONONNQOPPMMQNPQQOPQPPOPNNQNNQPONPQN", 336 | "PPPPPPQRRRRSSRTUUUTUVSRPPPOOOMPMPRPPRONPMONOOMPMNQOPPMMQMPQRNORQOOPOMQMNRPONOQN", 337 | "ROOPOMLIHHLNNSQNNORUTNPSSRQPPOQSOPQRNOKUOOORROWQPJQONVOOONPPTPONMTOQOINPOKRRRLR", 338 | "FPPPPQPPSQSXYYURSVTLKKJMLMMOORSROQRQOPQORMRPONQROOKKSNOMRLMMPKOSOPPNROROPNQMPOP", 339 | "NPOPPPPQRRRRSSSTTSSSTRQPPPPOPPSOQQPPRPNPPONOQNOPNOPOPONOPPOOOPQPONQMPNMPROSNOQN", 340 | "OOOOPOPQPPRTRNRVXWUVUQQRRQPOOPNQQORMNRQOQQOORPMQPOROQTRMQLNORHOOQQNQQOLRNMSNOPS", 341 | "JPOOOPOKGDKQRSOILPRSRRMADGKNOOVRTNQQOMOQOVPKQQIOSMOWNVOQOMPPPWONPPOMONPNOUNQOIT", 342 | "OPPPOONLNNNQVQEA?IZTTUR^^YTQPOSSQQOSNPTOQRPPQNNMKJMSPMRQOLPOMTOOQRNSOKRLLMLJPOM", 343 | "OOOOONNOQRTUPMRUXYYY[^XQRRPOOPFPMQRMOSOMRONRVPNQRPSNPRRNQONNVCOKTMQNQOJSOMROLOR", 344 | "RPPPQPOQXXWWUTOKIMMEGKP__YTQPPVUMQPTQPQOPJPRSMMPNLOKSIPOPROOMPQPRQHTOORNQLPTMSP", 345 | "OOOPOOMMLMMKLMLJJKKJJLMNOOPPOQORONPPNPQORPQQPQPQPNPOOQRNRONNPONOPPPQQNRQNPPQONQ", 346 | "MOPOOOOOQTTRQSWY^]XVUVSPQPPOOPOQONPNOQOQPNOPOPOPPKPLPRROPMOOQMOLQTNSPMLQMNPQPNR", 347 | "COOOOOQSRPPPRQPRTQPRVSPRRQPPOOQLOQQOQMOSOROPOMNMNQNPROJRNRQPMPSQMOPONQPMSNMPPOK", 348 | "QPOOPOONNOOMNPPNMOOOMMNNOOPPOOPQOOQOOPPPOROQQPOPOOPPOQQOONOPRPOONPOQPOQQOOPQONQ", 349 | "NOOPOOPQRRRRSUUTUTRPRRPNOPOOPPQMPPPPQPLPQPNOPNQQRPMOQQLNPOOOQNRPLORQPNLQRLTNNNO", 350 | "POOOONKFE@IPPTUSRTTSPMF?@CHMOPLRNOQNRNTRPPQOMQMORQMMPORPPROOOQONYOPHPPPOOVNMSNQ", 351 | "POPPPOOOOOOMMNMLLLLLKMNOOOPPOQNSQORPPQPORRPORPPQONQPPQRNRNNNQONQNPQQROORONQPNNP", 352 | "POOOPSWVRSJHKTSMMPKDEBFLLMOOOQQNMTMPRMMQQNTLJPRNURJOQSMQPMPNLUNRMMPLPVTMQOLUOOQ", 353 | "OOPOOMKLLEIQQTZXRLJKHGIQSRPPPORQSNQRQLSQNKOILPNOKPPQTJQQOLQQOSPOPNISNRQMSNMMRVN", 354 | "JOOPOMIJLHYa_URSPLLNOOOUUSRPPQLKLNMOQRKPQOPVNQMQSNUNPDQNQRNNRLNRMLQOQOJROURSQWR", 355 | "SOOPPPONPUPHIPQNRUNHEHNONNNOOPWNNRORPMMMOOQULONNNSSTTWNQPNPPMPOPMOQPOUTNQPMPTLR"]; 356 | revWCI = ["PPOPRVZYVRCAGKSUTQRRRPQLMNOOORRMOTLPRNQNONNPNRRMSROQPQOTLQOQTLaMOMOOPLQMOPRPJMP", 357 | "GPOOONQSUZQKNOMPURPQQTUXTPOPPGMQRPNJOPMOIOUMMPQOQPOHMZYIIXLMLWTMPPROJQMRQOPUMFL", 358 | "IPPPOPPQRRRTSRSUUTRTVUQPPPPPPQPSNPQQRTRINMNQLOSNRUNQOMNQRJPLMPQNQPQPLNPNNQJNLPQ", 359 | "ROOOOOONNOPPQONKKJKMNPPPQPPPPPPSPNQTTRQMTMNRULSPOILTTKKSTLSSQLMTOOSSMOSLNSOOPST", 360 | "YOOPPMLMMP:-3=HLNQQQPNQUUSQPPQQNPLMQQNPQONPUQRONPNPRROKRLONRRQPSQNRQPSVUNSPQNOP", 361 | "SOPPPRTSRSJDJTSIIQTLLONMNOPPOSRTOSOTRTUMUKLQPKRRKMS]RIDUPNUMKQQRNMPRMGSLLRMNO[S", 362 | "MPOOONNONPSMJPXWUQOQRURPPPPPOPRNOQLPLNORPQKOPPNPQQNNOPRPOMPPOLROPQOPNTNRSMKNMKO", 363 | "=OOOOONMNOMGFILNMKIHIOONNOOPPTTMORPMDLPRLPOMNNMKH@RNLVRPLQOQPMVLMVMUQOLOQ@ROKON", 364 | "JOOOOOPQRRRUTRRTUSRSUTQPPPPPOQPUNPOQSTRMPMNOKORNPXOQRLNQQMOMKPONPQPPMOOMMSINLNL", 365 | "NOPOONNOMORKHMPQQOPRQSQQQPPPPQQNOUQOLOQPLOOQPONNORPSQPNTKNNMKPSNPNOONOPQONMMQOO", 366 | "SPPOPOONMNNKMNOMLMOOMNOPOOOPPOOLQQMONKNTOQQPUQLQPIQOOQQLOSPSRONNOPLOSOPOTNRQQNN", 367 | "PPPPPQQOQ^WJIQZYRLJKLOKFKOPPOROPOUNRRORPSPTROPQRPQPMOQSPTPRRQQEPCRLPPOPQQOOOLTN", 368 | "XOPPPQSRQPOQSSPOPPPOOMNONOOOOMMQPPPPSQPNROPPPOQQMWOMROVMJNORPPLQPNPOOMQPRVOOQPP", 369 | "UPPOONNOQTOIGL][SMHFFJJKLNOPPUNPNSMUSOPQTMSTRQPMSMLYQIKUTKOWTMNQGLRRRQTLPQQNPMP", 370 | "JPPOOMMOQRQRONQRRQOQSQPPPPOPOPPNNOORMORQMONMLMOOQPLTKLKUQKONKORQMNPPNRQTKIHNQMP", 371 | "LPOONNOPQTOJLOTTTQOJOXOMNOOOOMMRORSRPQTMPNVQQOSQJOKMNLRSNIPNMKNSGNVSGRROMNKQOTQ", 372 | "UOOOPRVUQQRMLQRQL@:NRQRVUSQQPNLQNOMSSPROQNRUTWPKUMORRNSLRJNUPTPSLMNTQQSQPPMNRPP", 373 | "KPPOOPQPPQNOOOSWWRNOPRPOPPPPOPMRNOQPORNOQOPMNLRQRTNQOJLPTLOQQOMPNOQPOONNMOLMNRR", 374 | "VPPPPQTQMMLHQZ[RTYZROLMMPQQPPUSMPXRNNMQQVNQNOTOWJIPVNPIWRPSSPQLORQKQP@NLOOMQV^P", 375 | "NPPOOOPSRQSTUXZ_`YX[[WSNMMOPPMORPKQQOQONQQQKNRQNGSOIPVUPNRMRPLNPMRPOOMIQTPTNMVN", 376 | "ZPPOPPPPPPOQQOMMNOPPPPPPPPPOPNOPOPNPPPQOOQQPNROPQMONQQRMNRNMNSMPQOOPOQPQPPOQPNO", 377 | "SOPOONLLMMPNNLKIGKNMNMOPPPPPOPNPQRORQOQONNQSPRPOLMPPRQSPKORSPMQQTPPPMIUNTRPPQPM", 378 | "OPOOONNOOSSPHJOQROOQSTRSSRQQQOOPOMGPNPOPKQSNQTOO`OOOPOINTNSNSOVQNJQPMSOPPOOMQKP", 379 | "POPPOOOOPPQQQPRTSQQRRQPPPOPOOOOROOQQPRQNOOMPPNRPPUNPROORPMQPNOPRQPRPMNQNORNPOQQ", 380 | "MPOOOPQRTYVTRJJFAFLLOQMFIMNOOQJRQSWMRQPLNMQSTSMTKOUOOQOQOQNMPULQQMNPMSQPMOONQJQ", 381 | "UOPPQQTSRPPHEKYXMEGKGJMNNOOOOSJNMZWPRNTPNLOTROONINQQONKVJLLPNVRPOMMSQPSOKOQRONP", 382 | "NOPPQTWVV[SNNTZXUOJKMPQPRRQPPNTOPHKPOPOOMOMMNTPKXONPNSHQPPOOKP^NQRQQOMLNRNPPNVP", 383 | "LPOONNOPORRQOPRQNLSgkj^QONOPPUSOPJOPMPPPPQNLOOQPUMOONROIRRRQLMMNNMOMQULNQOMPSTQ", 384 | "POPPPPONNIBFHD@AJSURQSSRPPPOOJMQPPQMSQPOPOSPPQQNNLQORRRMPROHLWESOOQOQSQPLSONQNN", 385 | "IPPPONPPOLQXSKLRTSSRWSOSPOOOPNMQQGMLLQMMOQNOJCPJNSKEKR]EKTNWKGSPKRRMLRMUWKSSNOM", 386 | "UPOONMLOL=CIEFQW]`VOLOQPPQQPPJKMOSOMMNRPNONROGQVJOMKNQSMMURGSPWOQVNOPNSPNLJRRRN", 387 | "LOOPRSRROB@JNT^[SIGNMNOHJMOPONLUQTQQNTSMPORSRTRRPMMJSMVNSVMMPWPRMOPQQQSORRPROOP", 388 | "XOONLHEDHRQRNSYT@JNPNTYYUQOPPHWNNSPSSOPQQONSQWNFRMTURNDRTOSQLYIQVPPSOPOOSQSPOOR", 389 | "KPPQWdoqmjRSROSRPLORPQUXRQPPPOQNPLOLMMMROQPKOPPQQONNOSQOMRQORK^OQROQLKGTOOMOSON", 390 | "GOPOOOOPPPQRQPRTTRPOQPNOOPPPPOQQPMQRPQRMNNLURMRMONKQKMNRQIROONPRNOSQKOSLKKJMKPT", 391 | "]OPPRX`b^YQPPJ@@FTXLOTTYYVRPPSQONOSOONNROPMUSYNRPNRTQSONTQRJSJ^QTQMOOHOPPPPPQOO", 392 | "IOOOOPQNORVRRNOSVSOPTWPMNOPPOMOOQVQMNNQQNQQLRTONHRQMPZUMUWONMQSNSLLNPHMOXQMNPQP", 393 | "KOOOOOPPPQRTTSTWVSONNNNOPPPOOMOQOJMQOQONOPNPQMPNSTNPMMNQOJNKORNONNRPOTOMHNLMLMR", 394 | "IOPOOOOOOPOKLNQQPPPPONOOOPPPPRQMOROPPNPQMMMPOMNNMLQPOOPONOQRPMRMPQNMQOOPPJONMMO", 395 | "TOOOOMKIHJMNLOOMKMQPMMQQPPPPOMPPPQPMPPQONOPMKQOPMJRORRTKLUQTQPKPOPMOQLPSVRTRRQN", 396 | "IOONMKKNNOWXWZXSSOPRPPONOOOOOPMNQHWKOMNROTQHOONZOQQFMP_PIKNKRQQKOROOPOHQLOPQQMN", 397 | "GPOOONMNPPQPNPSSRRRUTROPQQPPPOPMOONQNMPQLNQTSMPPPLKTJMLQQOOONPNPLLPQNSLQGIKNONN", 398 | "OOPPPQSQQNMQURMLLNNMLJNONOOOOSOONQNOPOPQPPNNLQMOKMROKQRPMQMOKLPOTONNPMMSSKQKSNK", 399 | "TOOPPQQNM[VFBADMTUTSSVVSRRQPOWTTRYLOQSQLSPLQSISPQIMPQNSOPORPRNLQKSROKWPQLRNKPHT", 400 | "QOPOOOPPPQQQPPRTSQPQQQOOOOOPONNRPOPPQROMROOOPNRPQWNPTNOPQMRQQPMQOOQPONPLPTORNRS", 401 | "OPPOONMLKIJNLLMNLMJDGJLONNOOOOLQQMQORQPMQNSUSPRMILOMPQTLNMQSPPJQLKOQONULLQOSMPR", 402 | "MPOOOOQNKJKLLOOPPNMOSTROPPPPOP@WQLYMPVQJMLTNPYS[HQNMRWSOZUFLIRKSTLJPOHRSTRNJNQM", 403 | "VOPPOOOORWPMJMGHT_[K?AKSTRQPPRTSOPNTQRRNRMSURLMMWLKUQLGTLLPXIKLTNOSRPRRMRQSMVOS", 404 | "TOPPPPOLNNLKNOLFDJOKJLOOPQPPPPRVOTIXRUUMVKPQQJQJPIK^RDDTXROTNOLTMITSQMULTSKLTUS", 405 | "JOOOOONNNOQNLNRTSPNNMPMNOPPPPONVPPSPPUPKPNRONMTOLROQRNQQNLQOQNLSJNSPLOPMOQPQNRT"]; 406 | 407 | fwdWIP = "PQNMRIQQPRPNNQRMOOOMUNMTIOOPROOONPQJNTNPUIPQREMNRO"; 408 | revWIP = "TQNPMJO,NPQKUPRPSOKY^OOSLLOQONQNPOQKQOMPRSGPTOTOGN"; 409 | 410 | fwdWFP = "PNQQOEKONOOOQOMPOPORNPMMQPPPNOOROPNSQMRPONNNO5PPNM"; 411 | revWFP = "NRP^QTR!OPOPZNVJOOSIpNOXMOQLNOOPOQPROOKNRU>NZPQQSO"; 412 | 413 | fwdWOP = "RONNRYOPNPRVOQOLNPONRPLRONOSNNLNQQOOPOQQQRMQNMOPRO"; 414 | revWOP = "PXIFMFRRJRRNJNRNPMHRUNQRQPRQMaNMJXRNQPROSQMQQOKNLM"; 415 | 416 | softW = ["KOTOQNTMJNRGTOHXMRIPRQXNYKUISUUNSUANR@OIRMKSRGSLQRO.K_OkMLMLTIPSLNYGp@RYLKQSOJI%INcKJQOMLTHMPNIG>LkN", 417 | "bPQXKEMO_FMhMbFoXNYPORVKMQEbOA>RQHNWJOH_OMYLOXNHWMBPYTFSOWVMI]TSOgPSRTCRITcWFCWQQfQHaMYQSOSRPWSgq[S`", 418 | "OOOPNMLOPOLOMOMPPNONPOPLNPPOQPPOPOONNNQOOQONNOOOQNQQPNNOQOPROTPNQLTPOPRNPOQSRQMOKMPSPSRQPNQOQLPNMLNL", 419 | "OPOOOOOOOPPOPPPOOOOOOOOOOOPOOPPOPPOPPOPOOPOPPOPPPONMOPOQPPOOPOOQPPQPQOROPPPPPPONOOQOOPNPOOOPOOPOOPQO", 420 | "OPOOOOOOOPPOPOPOOPOPOOOOPOPOOPPOPPOPPOPOOPOPPOPPPONNOPOQPOOOPOOQPPQPQOROPPPPPPONOOQOOPNPOOOPOOPOOPQO", 421 | "OPOOPOOPOPPOPOPOOPOOPOOOPOPOOPPOPPOOPOPOOPOPPOPPPONNOPOQPOOOPOOQPPQPQOQOPPOPPPONOOQPOPOOPOOPOPQOOQQP", 422 | "OPOOPOPPOPPOOPPNOPOOPOPPPOPOOPPOPPOPPOPOPPOPPOPQOPOMOPOQPOOPPOOQPOPPQPROPPOPPPONOOQOOPOOPOOPOPQOOQQO", 423 | "OPOPPOOPNQQOOOPNOQOOPNPPPOPONPPNQPPOOOPOPPNPPNQQOPOMOPOPPOOOPPOQPPQPQPROPPOOOQOOOOPOOQOPPOOPOPQNOOPO", 424 | "QGRWJQLHZXCSYOLQRKTUNOMORWJRPLMQKJROOPWRNBXHMYKIOPQUTPIQKOSNKUROSLXMORLQKP[ST@MH=MNcQKRNNINPRPNNNUKN", 425 | "OROPOOOOOMOOROOTOMOMOTPOQOPNQPPRPPOPPNNOOOOPQOONQMTRPPOPPPPSOLPNQOOOSQROSQQRRPMPMMTSOSROPNQOPSQOONMN", 426 | "OKOQPMPOPJPOMOMOOSNLOPQOOPPOOPPPMOPLUPSOPOOOKONKNMLOPPOOQPPNOSPQPLMPPOQOMPMSOQMRPMMROMMPPOQPPOPNLQNL", 427 | "OOQQPOPOOROOPOONONONOOPOOPPOPPPNQPOOPNQOPOOPOOPQPONOPPNPPPPPOOOPQOROOPROQPQPQMMLMNRQPPMPPNPOPNQNNQOO", 428 | "OPOPOOPPOPPOPOQNOOOOOPPPPOPOPPPOPPOPOOOOOOOPQNPQPPOMOPOPPOOOOPORPOQPQPROPPOQOPNNOPQNOONPPOOPOPQOOQPP", 429 | "LJQEOHNNOHPLLMWTPPMPMWOKIRRLTRRWNOQKXMPMPPPJIOJLNLTYOOXKMNOPRDPJKORLQNLTPLMMIWYTXIPZLSSDNSIOQ^KOQONK", 430 | "NQPTNJMPQPMNPNXQRJOLQWSPWSONRPPOLMRUFRKORMSLSPWNQTVMSNTJPQROOPRWPSXQQSLRMON]LGMJURRJQJLNPSQQQWNUNWJR", 431 | "MJQGOGHOQKMLQPDRSLNUPKNKKSQMXQRVPMP[PRIMSQQJYPKJLNSMRHSMMMQQPROHMNUMMTJSNKYPJ_WRVOQMLVVFNQIPR[EMVKMJ", 432 | "NOOMPNNPNMQNONSNOQORQTPNROPNPPQRNPPMRPNNQQOOOOONOPSPPPSOQPPROOPQQQPPOQQOPPOSRINMLONRQPLQPNQOPMQOMQMP", 433 | "OPNKPPQNPQNONOPOOSOQQMPQPNPOLPPNNOQOTRROPROOLOOKLULNOPOPQPPOPSPSPOMPQOPONPOQPPNQONLRPKMPPOQOONPNLTOO", 434 | "OMPTPNPPOOROPPJOOUOQPPQQMPPORPPLNPPMQPNOPLOOMOLLQKNQPPNOPPPNOVPMPOLPROONOOOPPTNRMNTSOSSOPPPOPQPONLOM", 435 | "PJOPQPQROQSONOPNOTOTQNORSOPOKPOLMPQKNRLOQOOQMOSKNNJQPPRPPPPOOSNPPPWQKPONPOROQVNKLQURPPQQPOOPOKPORLOP", 436 | "ONOQQPQRORSONOONOROMQNQROOPOOPPMMPQLKQLOQPNQLOSNMNJNOPNPOPOOOMOMPOOPROQONONNOQNPPLOOPSPPPPPPQPPONSPO", 437 | "ORONPPQQOSPOQOSMONONPPQQQOPOTPPNQPQRMQROQOPPSNOKSSMNOOOPPOOPPQPNPNMPTPQOOONPQQNQPLQTOTROPOPOPSPONTON", 438 | "OONQQPOQNNQONOOMNROMQNQPRNPOMPPNPQPLOPOOQQNQMNPTNPQNOPOPPPOQPQPSPOOPRPQOPPMQQQNPTOOROSQOPOOOOSPOOUPO", 439 | "OQOLPPQONPOONORNORONQNNQRNPONPPNPPPOPQROQQOQPNOONRRMOPOPQPOPPQPSPPOPSPQOPPNQQQNOSQORORPOPPPPOSPNOUPO", 440 | "OMOQQOQPNOQOPOMMORORPNPPPOPOOPPMOPPMRPOOPONPMNONNNMQPPQPQPPQOPOPQOPPNPQNQPPPQKNNLMTQPOMQPOPPPNPOMSOP", 441 | "OQNQQPQQNRPONPQNOQOMQNQQQOPOMPPMOPPMLPOOPQNQNOQSNRKOOPNPPPOPPNONPOOPRPQOOPONPQNPOMPPPSPPPOPPOPPOORPO", 442 | "PRNRQPPOOSOPMPSNOSOLQNRPSOPPLPOMNPRKMQMOPPOPMOOUMSLNPPPPQPPOOQPUPPNPQPPOOPNPPNNPOPNPPLLPPOPPOOPNLSPP", 443 | "OJPNNKJOPMOOOPLQQMORONQLORPOPPPRPNNSSNMOOQPMQPQMOOKQROOLOPQNOLOOPNSNKPRMNPRQIVROJOULNQOQONSOQLPMPLLJ", 444 | "NJNMOKLOOLPOMOOQPONNOSQMNQQNQPPUOOONUOROPROMJOONQNJSQOOLOOQPNIONOMRMLORNPPOPIUSSLMURMTPOOOQOQNPMOLMJ", 445 | "OPOOPOPOOPPOPPPOOOOOPOOOPOPOPPPOPPOPPOPOOPOPPOPPPONNOPOQPOOOOOOQPPQPQOROPPPPPPONOOQOOPNPOOOPOOQOOPQO", 446 | "NPOPOQOONONNUNRNOMOMORMRPPPNQQQMPPOSNNSNQMPPSNTRRTMLPPNNOPPOPLPOONROPQQONPMQLLPORMNLOQJPPQQNQNPPLVNM", 447 | "OPOOPOOPOPPOPOPOOOOOPOOOPOPOOPPOPPOPPOPOOPOPPOPPPONMOPOQPOOOPPOQPPQPQPROPPPPPPONOOQOOPNPPOOPOOQOOPQP", 448 | "NKQQQOPPOOLNMNLNONOLOLOOSPPNOQQLMQPNLNNNPROPLORLLQNSPKQNQOQSNPNSQJXOIQPNROPSRJMNKMRTPPLQOOOPSIMNKNMK", 449 | "ONONQPMONRSOOOONNPNNPNQMQOPONPPRSPONQOQOPROPMORQNRMOPPOOOPPOOQPSQRPQPQQNOPOOOMOPNOOQPOMQPOQPOPQPMROQ", 450 | "PTRTSQRRPWUPXOMLNGPOMLPTROOPPOOMRPRTIPWPSNPQTPYLOXSKNPQOQPNPQVOKNOKPTPNOLNLHQVQPVUPLOTPNPPMONWONPHRO", 451 | "OMNSQPOQOQSOLPNNOLOMQMQSLOPOMPPNRPPLLPROQQNQMOTYLRJMOPLQOPONPNPLOQNQTOOOLPMLOOOQPKKPPTQPPPPOPRPPOZPR", 452 | "OOMLOQPKPUOOPOSQPSOSROMQONPOKPPNKOQRVTQOQPOQNOQGOTPTPPTQNPPROKOKOQUMPPORRPYLSTNMKMPUQRTOPLLPOVQMTOLN", 453 | "OJLOQQPPOTSPNOHNOTPWRLPHNNOOJOPKNONIPRMPQQOPJPTILNLNPPNPRPPNOSPWPQMPNOOPOPOPPKNROMJNPILOPPRPOOPNMWPP", 454 | "PSOONOPOORNPKOPOPQPMONONOOOPLOONOOLLJMNPNROOMOOUPORUOOSKRPORPQLYPPZQNPNNWPSSTZNLIUUROUUSPOROKTPMWHJO", 455 | "OTOROOQOOOPOOONROPONOQOPPOPOPPPNPPNNKLPONNOPOOOORNTSPPNLRPPSOQOYQRXQQQPOUPPURHNKKPQQPSQQPOSNMRQOJUJS", 456 | "OOOKQPROPPROMOVOOROPRMPSSOPOKPPPOPSMPRLORQOQLORFMTQNOPPPPPOPOOPQOQNPRPOOROMPPQNRVQLRPUQPPONPNUPOPUPQ", 457 | "PLOTMRTPPKLPGPSIQEPKQQSSOQOPUOOPMNPSIPSPROQNQPN]QURQOOPQQPOOPVQLPRJPTONONOORRQOTKOKTPQQQPPQPNQPPPINS", 458 | "PQOSPOPPQMSOMPHTOQPQOOQRNNOOROPPOPNNKNKONJPPNPKIJHOROPOQPOOUOVOJSLIOSPOPOOPTTSNTMINQPQTQPNQRPQPQNIOL", 459 | "OONPQOQQNQSONPPNOTOSQOORMOPOOPPONPPMOPMOOMOQPOOLOLSNOPNQPPONPQPNQRMPTOQOOPORRNNQLNLRPSOPPOPPPNQOMSPR", 460 | "ORNRPPQPNSOOQOQNNNOMQNQRPOPONPPMRPPSQOQOQQNPPNQTORROOPPQPPORPOONPPPORPQPSPRMRSNNNMPRPRRNPNNOOSQNROOO", 461 | "ORPPONPOOMPOOOLRPMOPONQONOPOQPPQQPONLNNONPOOPOMJOLSMOPONQOPLOWOKNNPPUQOOSOQEOUNMLPRTOUVLPNOOPPPNXKNG", 462 | "PNQUQQTPPMSPMOJNNVPLILOUMPOPQOORRPQVROUPQSPOSPUVQVRPOPMPQPOQPUPLPQKQROONPPNPRRNSLNMRPTSPPOQNOPPNQKQR", 463 | "OONPORMPPKMOROWMOMOMSMTRRPPOIPPLOPQZPRJORSPOSOPRKUPOOPPQPPOPPTPLOPKPSOOOMPNQPPPUNLPSORRQPNRPOSPOPKQP", 464 | "PMMKNPQMQTSPOPSPPSPORLNTNNOPJOOMLNSLVUSPRNPNIQREMRMNOPORRPPOOSPXQRNPPOOOOPOOQMNQPOJNQILPQOORNNPOMWRQ", 465 | "OROSOPQOPSOOMOOPOLPMMMOLRPOPNOPMOONNJKSPPOPONPRSORMSPPQMQPPONSPUQSXRJQOLPPOVRHONHOPRSNMQPNRONNQPKOLS", 466 | "OPOOQPPPOQRONPSNORNOQNPQOOQOLPPOOPQMSQQOQQNQMOQMNRLPOPOPPPOOOQOQQQOPRPQNPPNPQONONPQQPPMPPOPQOOQONRPQ", 467 | "PQOOQQSOPTNPRPROOKPLQJOMWPOPNOOLRORPJPPPPQPPMPUXLVJROPPPPPONOQNLORNPKPONOPSJOXKQJOTRPOSPPORONNPMRKNP", 468 | "OINTQQPRORSOKOTONNOLRNQTWNPOLPPKLQQJGRHOQPNRKOSYOJOOOOOPOPOQPMPOOPNOOPNPQONNQPOSXOLSPWQPPNKPNVOPR[PO", 469 | "PINUPSRNQNRPQOGLNNPMNMOPNPOPROOKNPPKNORPNIPPIPOKMJQWOPNQPPOVOMQIRTLMSONOTPTORIPSHHSIPMURPNQNPUPRIUKS", 470 | "OPONNOPPOMRONOSMPTOUQMPOMNPOJPPSNOPOTQKOPROOQONKMQOOPPOQPPOOOSPNQPMPTPQONPNPRNOQLNOSPQQPPNQPONQONSPP", 471 | "OQNRQPOQNLQOOOQNOROQQNRRROPOKPPOOPPTRPMOPONQQOORMQQPOPROQPPQOPPPQQOPPPQOPPOQRKONLOPQPOMPPOPPPNPOMQNQ", 472 | "OOOSRRMQOLTOMOTONSOLPJQSSOPOMPPWSPPWQQNOQPNQTORWNSSQOPTOPPOQPPONPRNPQPOOQPOORIPPLNNTPQOQPOPNONQOLQNS", 473 | "OQOOPOPPOQQOPOPNOOOOPOPPOOPOOPPNQPPQPOPOPPNPPNQQOPNNOPOQPOOPPOOPPPQOQPROQPQOQQNNNNQPOQOOPOOPOPQNPPPO", 474 | "OLNTQQRQNNSOTOLLNLNJPQQTSNQOQPPKPQQPPPQOPMNRMNLTLKSQPPTNQPPSONNQQPPPLPOOSPNRRJONLPTQQJLQPOPPPLPOMMLP", 475 | "ONOOQPPQNQQOOOONOPOOONPQPNPONPPNPPOOPPPOPPNQONRNNOPNOPNQPPOPPOOPQPSOPPROQPROQRNMMNQQPQPPPNOPOPQNQOOO", 476 | "OPOOPOPPONPOOOOPOPONOPPOOOPOPPPOPPONQOQOOPOPNOONQNQPOPOPPPOQONOOQOPPSPROQQOQQPNONNPQORPPPOPPOQQNOPOO", 477 | "OPOOOOOPOPPOPPPOOOOOPOOOPOPOOPPOPPOPPOPOOPOPPOPPPONNOPOQPOOOPOOQPPQPQOROPPPPPPONOOQOPPNOOOOPOOQOOPQO", 478 | "ONOPPOPOONQONOOOOQOMOPPOOOPOPPPPPPPNROROPPOPNOONPNPPOPOPPOOQPPOOQNPPSPRNPPOQQQNPNNPQORPPPOPPOPQONOPM", 479 | "OPOOPOOOOPPOPPPOOPOPOOOOPOPOPPPOPPOOPOPOOPOPPOPPPONMOPOQPOOPPOOQPPQPQOROPPPPPPONOOQOOPNPPOOPOOQOOPQO", 480 | "OPOOOOOOOPPOPPPOOPOPOOOOPOPOOPPOPPOPPOPOOPOPPOPPPONMOPOQPOOOPOOQPOQPQOQOPPPPPPONOOQOPPNPOOOPOOQOOPQO", 481 | "OPOOOOOOOPPOPPPOOPOPOOOOPOPOPPPOPPOPPOPOOPOPPOPPPONMOPOQPOOOPOOQPPQPQOQOPPPPPPONOOQOPPNOOOOPOOQOOPQO", 482 | "RGSTORPSSfSS[ObNQRT[PLIRIQKSYLMQMNUFCYJSPJUOVTMDSJMULONTQOMPSULDPPBMLNLOSNNCQ[OUbUKCP>ULORKQNSLORBYO", 483 | "PKL`MPRSPXNQMPGQQSPVQJTSQNOQMOOKRPNSXNVPNPPOOOKWGIRPOOKNLONNPOP_KPROLOLPPNKPOIPRVOHDNCKPORQMOQMSO^UR", 484 | "PTRJNQPMQSLPUO]XQKQUQOLPVMNP[NOPNPNXWVSQONQQXQLARLLTPNSDJQPPNHLFQOOQGPKOTPYKHXZMJUUDPVSROPKQMKNQSOJT", 485 | "PSQANQTPP_JPOPTOPTQSQNBSIONPVNONOORORTSPNPPPTPQLVJ^QLLNVOMMOSUQJLNJMMKQPPNIMTRQPIN?bK]NLNRINRLNPQIVL", 486 | "QOMBNTNOQZNPPP]RQNSJSMMSNOMQZNNUSNOZ@ULRSPSPUSHROVQKNHTAKMNNPNN[KM]OARNOLPVYNXUIMUVFMGHPNQONOMONRILO", 487 | "OSMVMONONNOONOIQOOPNLQRLGNOOLPPOQPMJQLSOKPOPLONT]KaMOMONMOOQQ?OOOOKOFRQQSQQIQHNRIK;YNRNNOQPMSCQSPLNP", 488 | "QROFQQONQ^TQQP[ROPPLQWEQLOOQLNN]NPSEVUWQQOQQ@QMUVQMRNNUNQNOPQKNGOMTPJNNNROJORUOOQRWOOMOOOPOOMONOQFQO", 489 | "QFZ`PTSNONMQJPHMO>QSGGZLLQNQRNNNRPMVWOXQLQPRMQPXFTQQOMJTKOONQUPNLNMOLMLPNNLPLROT]UNBO?SNNRNNPOMST?QN", 490 | "OMSTMPLNOPINPOCMRPQTMJRKLRNOZOPQOONSIOBOMOQNVQJROOYLPOKOMPQKOLQHOLLNNOMPLOHMNMSQklBlP^MNOPSPPEOQTEUQ", 491 | "OPOQPNPOOMSOLOOQOSOKNWQPMPPOOPPTMPOLWNUOOOOPJOMQUMTMPPOPOPPMOIPMPQNPRNQONPMQQMNRXXKVPUNPQOPPOLQPPJQS", 492 | "OOPSMSTQOUKOLOSNODPOQCWSUOOOKPPISPPWNNOOQROPSOYQHVIPPNOLMNPMOENNMKNPJPMQOOPGJXUPRRUFPUMQNPOOQHNOPNNN", 493 | "OPQKMOMOPQFNPNIMQEQUPLN@SPNOQOQRLOPRHOROJSQKPPSEBLZKPNQRPOPNO[RFNKIPVPMODNRROTNWEKAXPWVLOQPQSQNMXIPS", 494 | "QVK@NM9MQHEQcRJMPDQJLOPSIRNQNNNMSNMMOKTQMNPNIQRT[MPSONJPOOONPTQKLONOJNNOQOMLNVNVXQJGOCQOOPPLOONQODRP", 495 | "QPaFOR]QPFHPRP@OPZQRDWHIKXNQWNOROOOONJXQHNQNZRKTTVUWONKROOOQPUPLOOMPIMORMPFQPUMWcQIFNAXMNSOPPRNRSFKO", 496 | "QOSJPROQRYKQSPcQQMSSLPMSPPMQZMNRPNQRdXRRNMRQZSPKWLSQNPMOKNNNQSPeLMMNLNNRQLKNPJPR`OCDKBMMNRSOOQLRQeRN", 497 | "PUQJQOBNOSZPSQGQPQPPOUHLJPOPLOO]OPLGWPRPNPPPFPMTRJNOPOKMNOONPSQZMOPOMPNPOPLOQJPRULFGOGMOOQQNONORMYQP", 498 | "PQOLPOPPPPSPLPUOOQOOPVIRNOPPSPOMNPROVQVPPNOPPOMKSJKQOPRPPPOOPKOLPRNQQNONQOLOQNOQUOWRPRNQPOPPNROPNMRS", 499 | "PTXHLQRNNHROOPDNRJQPLQQGGUOPTOPOSOKYODIPHUOKZPJWTJYVPMQJOOONOEPQNOGMEPMTROOMR=XKGNVAO@JQOQUMSBNSOMFQ", 500 | "OPLRNOPOPNMNGNUKPQQMSXPLLONOROPLOPPI>REPSNQOTQL[XLFNNOKJMMOLPIOFKLQONMPQMMKKMJVS_KGEL]JQMRMMQULSSYRM", 501 | "PXN[NPKNNNAOZPBTPQQUKQUNFLNPJOPQNPKNJKXPFMOQQPEOPG?TPNTMQOPNQLNKJMESDQNSNPXFJYPNLM[`NUQNOTSNPAOPRJHP", 502 | "QUPFLQVMPBOQKPWQQYRYQRFLPPMQNNNVNNNSYQ:QHPQITSDKITMPOOYWRPOPPQNDQNHPTKLOMNLLKTRV^VOGPGWQOOMRPNMMPGTO", 503 | "PVNQOQUOOCJPQPQPPTPQOWTQVNOPFOOKMOPZVOMPQOOQXOKTNTSPQOQLMPPNNNQPPPJPIOMQJPNSG>VTJRNEQFKRPPOPQMOWMPQU", 504 | "OVOVRPMQQDRPQOTPNWONQF:PPQOOHPP[VPQY?TJPQLPPVPYPQQOPPNVLMPPMOOPNNNLPLQNNOQNKKDYUQQPEPDJTOOMMOPPQJPRQ", 505 | "ORPMPRQQNIROWORJOKPQOXOQPQPPJPPIOPOQMOLOPPNQUOXUURLRPPRNOPPOOINNPONOKPPPNPRKKVRQONUKPSPPPOPPQKONPMMP", 506 | "NVPOQRKPOATOMNSRMROIN^UOWNPOKPPUPQQD^NQOPSORDOO[LTSTPMVMOOPNPOONLMIOLMMOONNRLJVRQOVFMGKROPNNQPMQLNNL", 507 | "PMOPPOPQORSPMPNMPUPVOSOOLOOPSOOKNPNHKOJPNQOQROPNTKLQPPRNOPPOOHMNPOSPJOOPNOSMOVMKKQTJPNOPPOQQOKONRMLQ", 508 | "OROQPOQPOMPONORROONMPSPQSOPORPPPNPPMNOPOPNOQNNNNRQSQOPPPPPPQOKOOQOPORPQORPOQQONPMMQRORPOPOPPPRQONQOM", 509 | "OPOOPOPOOOPOOPOOOOOOOPPOOOPOPPPOPPOOPOPOOPOPOOOPPOONOPOPPOOPPPOPPOPPRPROPPOQPPNONOPPOQOPOOOPOPQOOPPO", 510 | "OMOPPNPOOLQONOOPORNMOPPNNOPOPPPPOPPMTOSOPQOOMONMPMROOPNNQPOOPRPTPNTPRPQORPMTQPNPMOOROQMPPOQPOQQOMQNN", 511 | "OPOOPOPOOPOOOPPOOPOOPOOOOOPOPPPOPPOPOOPOOPOPPNPPPOOMOPOPPOOOPOOQPPQPQPROPPPPPPNNOPPPPQNPPOOPOOQOOPPP"]; 512 | softB = "}WNKKLLLkNNMLZS`NMMLLMLLLLLPPLOKOLNMOMMNMMRLMMMMMMLMNOMLNLLLMKMKKKPMPPUSNQUMMUOUVOKSVWPNQMSKMLML"; 513 | 514 | -------------------------------------------------------------------------------- /models/zeus.min.js: -------------------------------------------------------------------------------- 1 | encGamut = 4.000000; 2 | 3 | fwdWGI = ["QOPOOOOMNIKXYTRUSRPMJMOOOOPPPMPKQMNWRSOQQLMLPPONPHJQPONQSKOOKPQJRPWQKQTRSTMQRQN", 4 | "UOOPOPOQPPMOOPNNPPPPSQQOOPOPOPQONPMNMLSJOOPOTQROOQNSKRPMNMRJNPKQNPQPPPOPNQQQPRL", 5 | "PONQPOQSROSSKGJTTTSTSROOOOOONLNTPMKOUPOOROONPMRINOMQLLKSQMSNOOOOLKTNOQYMKUOOGNL", 6 | "OPPPOQRPQQRQPPRSRQPPNQPPQPPPOPPQPOPNPQQOPPRMNNQQOOJKOONMMNPPLOONOPPPMNORPNOOQQN", 7 | "MOOOPQPRTPRSRPTURTUTLIMPPQPONQPMTPORQMNQPLRNVMPONJOSQOPMKQOPNSQMPPNSMPNPNSQOQRP", 8 | "ROOPPOPOOPPPPQPPPOQQPQOPPOPOOPPPOOONPPPNOQOOOPPPOQPONQOOPOONPOPOPNOOPPQOPOOQPPP", 9 | "WOOPOQOPPOOPOMLMMMLJMNNOOPOOPQRSPONMQNUPNPQPQQRNQQNQJNQPPLPINOPVQOPQQSQNPPOOMMM", 10 | "DOOPOMKNNOQPRVTNQQVUQPNPQPOPOLMQRPOTMQQMPQSJOOMSLPMPXONQKPP]MXLVKUOLMSOSNNMMMQN", 11 | "QPOONOOOPORVXMEGKRVVQLLLNNPONRQIRRORNKQPTLJLLQRMMOOWMTPMRMRNNRPLOOPPSOPNNJNQIML", 12 | "ROOPPPMMNPONPOQPOPONLOOPQQQPOOLQKRPOMOPOMOQJOMRJPMSSMLTNNTRNRTMQNPPOLKPNPQPOOPQ", 13 | "SPOOOPPNOOPPNOPPPONOOOOOPPOOPMPSNNONQOPPNQRRQPOONPPOLPPONOPMQONSPOMNPPPQMSPOMOO", 14 | "MOPQOQRONNRTY[WTSRQPNKLKNOQQOQNQNTMLLPNUIPPKOLOKOQNTRJQNLQLSNQMRQOOLLKWOTSWLROR", 15 | "SPPNNOPPNJIONOPOOPPRSOOQOOOONPTEQUOMQPPPRPRURRPOKKNLMSMQOQMLPOLOKNNRNNNJROPQSWU", 16 | "MOOQPONOOQTQTUTPRSTRQTSQPQPOPPORNRORQOOPMROMQQQJKJPIQMQKORRPRNPNRQUPMLQNQSOTWMR", 17 | "NPPPOONOQTPQWXUVZ[]TPMKMNPOOPRMORTPHRNPKUFMPQJQQQXKMPQPONNOOLUNOLRPVTNNSNOLNPUP", 18 | "HPPPNLLMRTVTVSRRRROOORRRPNOOPTPRQLOSXLJTMIPNLSLMQSNP_LMOOLOZOLPSURSPSKRTHNRKQMU", 19 | "OOQOPOOQQPRTPMPTUTTRTPKNPQPOPSSMPWMRRPSQQPQJQPPLQLQNOQQRROLMOONKSPTQLOOOOLMRNPL", 20 | "POONPPQPOQPQSSSPQNPQQRRPNPOOOQRLPPOPOORPPRSOOONRLNNKORPMNQPNNNONSPQPMPMPOONTQQP", 21 | "QNPQOOOQPNJKMKLNQRPTQOMLMMOPPNPJQNPKKSRMRRKOPPQQJLJQOOOPOPRNRQQPLONPOOTOIPQQOKR", 22 | "NNONPPOQPQRUSTUUUVRPRTQOQPPPNRONPRPROQPMPQQQOOOOQMMOQOONNROOMMPJQQPQNPQNOPMPOPN", 23 | "UPPOPPPPPQONOQRQPQNPRPNMNOPOPPNQLONQPNPLNQOOTMTMOOPMKPOPNOOILMRNMMOQMNLRNPJOPRQ", 24 | "POPONOPPQQPMOTTQQSSSSSQOOOPPPQOMQOOMRRPOKUUIOORPKKOOSMQMKMNRPSPQQPNONLQPRLPPPSP", 25 | "QOPOPPOPPRTUUWUSTSRRPRRPOOPPNTNOOSOUQORJPTUKNITLPIOKNQRMLWQNTQNONPSMPORTPMMSRTT", 26 | "RPOOPOOONONPPQQPPPPPPPOPPPOPPOROONOOPNQPPOPPPPPPPQPONOPPPOPNPOPPPQNOPOOOPOOQPPN", 27 | "QOPOPOQPQQOPPQPTTUSQSPPPNOPPOPSKNNMMROPNRMORQPRPQQKUNPNNNMNNOOQQOQKOSQNSPPRNRQL", 28 | "RPPOPPQOONPQQRQRTSRPNOQPQOONPQNLSPQKPOPRQRPRQPPOQMNLNOOOQOTMOLORNONQPORRPRQOOQO", 29 | "POPPOPPPPQQOTUSQOOPQONPOPPOOPVQPQQNMOKRKPPOMMPONMMNRPPNONOONONQROQMOTPNPRLRTOPK", 30 | "POPOOPOMKLQRQPOQPPONNQRONOPOPMPIQNPPOPPQPRLMTTPOJJNONPOQONQPRPQNPOORPPQQNPTQMPN", 31 | "OOOOPNOOPNKIKOQPPPQQQOQPROOOOPQPPPPLORRRQNPQRMOPPNPLONNQQPVOQOOORQOQSNMMPOOQPRR", 32 | "RPONPOOPOQNLRUTTRRSQQPOOOOOOORPPNOOMPMRMQMNPTPPONTMOMLPPQQSLNPNUQOMPTOPNNMQOOOM", 33 | "QNPPOQPPOPPPPQPPPQPPOQPOPPOOPOPOPPNNPPQNPOPQQQQQOPPOOPPQPOPNOOPOQPOPPPPPQOOOQPO", 34 | "OOPPPPSSTQPNOOPOQOQSQMPSRRQPPVONQQPNOLSMOQVKOLSNOJMOONQMLQSNQLKPNPNPPRTOPOLOMPM", 35 | "QPPNOOOQPQSRQQORQQQRQNOPOPPNOPPLPNNOQNRORMMORQQNNQLQMPNQOMQNNQPQPPOPRQRPPPPPPNM", 36 | "MOOPPOMLPQQRQOQOLNNNPQPPOOQOPMPQQRNQQQPROPMPPLQPQMRTRQOONSRPPQQOMPNNMQOMRPPRQQQ", 37 | "ROOPPOOONNOQQPPOONMNOOPQOPOOONRQONQLRQPMOPNPRRPOQONOLRNQROPLQOOROONPOPPQNOPQONN", 38 | "QPPPPPPRRQRRWVRRRRPSTSQPOOOPPQNLOXQVSSSMUNOPMOPPKOOMRNORSPQOMNLNQQTPOMPNOMUPNXI", 39 | "PPPOOPPQQQQPPQQPOOOPOQPPOOQOOPROPOPOPOQONONPQQPQPOPQNPOPQOPNPOOPONNQOOQPPPQONPN", 40 | "TPOOOONMNMOSRNLMLLNNLKMNOPPONMLPOPQLMLPJOOSJRQQKKJOUMGRNQOSLPTKTJPPONLSPRQTNQSL", 41 | "PPPPNNOOORQQTSQOPQOPOPQOPOOPQPQLNNPLPNROQNQPPOPRPONROONQOOROOPNQPPPPROQPPNQOQQN", 42 | "SPPOOPQRQPPQRQPPQRQRROPOPOOOQQQOQOOOQQQQQRQSVPSNPOLOLQNOPPOLPNROMMMPQQQPORNQOQP", 43 | "OOOPOQPPPRRPOPPPQPRSQSRPOQPPNPPQROPPQPPOPPMMRNRPLNLSPQOQPNQNOOMPNRPPPNQSONPOOOL", 44 | "TPPOPPQQSQMJNQPOPRRPNOONOOOPOPOLOQQPORTMTMQNRLPOKUJROOPRQONLPRKRNMTOQKQOOORNSQK", 45 | "OPPPOPOQONNOPROOORSPOKLPNOOPOMMRMMOQMNQTNPOQLNOOOMSRPNORMNJOSQKPOQNPMLRNNQMNSOT", 46 | "PPOPPOQSTSPQRTQKIPUVPLNMMOPOPOEOQOPNMPRRTPNKLJKNJFKNOLSPPONLQPMOONPOKLQONKPMPOS", 47 | "QQOOOPPUQOPVUSSQOMKJIIMQPPPPOSNPQMNRNPQPKPSMNLNLLHOOMLQORRLOORNLQOQMFKNPSPPLJPR", 48 | "QOONPQQQOPQQSSRQQPRQNPRPQPOPOPQLRSOSRPQMPOSQPLSLONQMKSPHNVQLPNPNONQONNQPMPNQNTP", 49 | "QOPOPPRTSRPQRQONLLONNMPPNPPOPMRPQPOMPMPMOMQOPQTPTNOQOPPRLOTPOQNOMQNTOPRQPPRNQQR", 50 | "NOOPPPSSSSPSUXUTRTSRONPOPPPPQOOLIQOTMPRLQPSIGJOJLHONQSRMLRKQRQLNSQRKINPLRPITUUM", 51 | "PPOOPQPOPQRTUWUSQSPONMLPQRPOOSRRPOOMNNOPQMQOUQLPNQKMOLOMNROQQORLLRSOOQVQOSONTJP", 52 | "OOOOOPPQQPQPQRRQQROOPPPQOONOQQNNQQNOLMROTPPMMLPOMIPKNMPOJTQNQPKOPQNRNKPQOPPQLPQ"]; 53 | revWGI = ["OPOOPQOPTVQMLQLPTTMMPUURPOOQPQQVOSWQQINVQQLNNSLOTROMOPRKSMQTNNMOTOQMSRNTLROPIRQ", 54 | "TPOPOONMMMNPMMORQMLOQOMLNMPOOQQSLPRQRQPPSPOOOOKULSSMMSRLTRRMNKQNRKPUQLOQMTNOOMS", 55 | "KOOOPNNPRSRRTVXUVUTROOONPPOPPXJTXVSNPDOOLOUSKQRQQUJFTLSOOMMXGOINOTSNQPLMONSONTR", 56 | "OOOPPNONNPQTSPSRRSSSQRPRQRQOPNOLRVSSQPONQQSOISIJOPOPMRMOQLXQNJQKPMMNTONQPMUMPRL", 57 | "9PNPNMRVPTQRQQNNSRRTVVSOMNOOPSKOKNN=SLOJOGKSNIR]WMQQJ@LSMSMWZXVSUdNHXMPLOXMSQTR", 58 | "ONOOQPQQQQUURLNLMNOTRSPOOOOPOWMTMTRNQOSQRPKURRMQRXLJTPMSQVVPPPPSOQORVRLRRPORIPP", 59 | "KOPPOPPQQRPNPOPPPPOOPORPOOPOPPPNKOSOMPMRQMONQOPOOOQOQKQORNQNOOQOOTOKONLORPQONRM", 60 | "TPPPPQPQPPNPRNPSQOPTOPQOQQPOOWJTLSSQLNNMSRSNTSSQTQRJLTRNTRRPNPPPRLMHTPMKSTQOPQO", 61 | "SOOOOQQPOOQTRRSROPPNQQOQQOPPPOOMKVURPMMNSPNKMMLSPRYMORKMSOVQLPQPPNNORNMNSSNMPRK", 62 | "OPOOOQQONNOMLPRQPPRSOONMNMONOSKLRRSNQRRONPPQNPMVNSRQSOKWQSSQKOUOTPKQWUOLORLOQNQ", 63 | "UPPPONNOOQQPSNGCDGGLMNPRPOPOOROSNTSTMMMURRONSTJPNPMLKTOMSRTPQOPQQHSONTOSUQQOMLJ", 64 | "TPPPQQSQOIKNMMNOOQNKNPOMMNOQPQPPVTTQRRSPNQQQNNOKVPJRSTMPRUURSSOMOIUWSOPNKSNPRLR", 65 | "EOPOPQQQPONKLONNNOOQNPQQPQOPORMPUPSMPSONLSQONLREOKLSMINPOKPPNUYNNUOLSOKPLMRQQSP", 66 | "NPPOOOOMNOLHKPRRQPMJJMMOOPQOPTQMGSLMMPSLXMNHVNJVLMQJLNURPMPPRSPNOPWTQLOMNQNNHIT", 67 | "MOOPOPPQOOPNPVVNOTSRPRQPRPPPNKSQLKRNQSOVSNLTPIHOTTOMUMOQQMWOPMQPMPKLROQQOSMKLLS", 68 | "SPOPONLLILLNPMKLOPOPOOPRSQQPOQQROSQPMPTQLRNPPOPQOONNNRPNRQOPMNRKNLOSRONKTSNMOOI", 69 | "NPPPOOMNPPTRRMOOLJIHMNMKMOPPQGUNDSJRJIGWPMIPKQLTQORLOOPRNHPIQMONXPTIQLMXMLKMJPN", 70 | "LPOPNQORTTQLQVSPQSQQSVQPPPQPPSMUSNNPQNLKMNOQOTQOTRFONOMVOMQSJUPPRRKMSPOMLOLRRQW", 71 | "]PPPPOOOPPPQQQRSTRRRUSPQOPPONSOMQTPWNNPJOQPKNNMOSSTONZQPURTLMOQMSFPRNNMLRTQMNLQ", 72 | "JOOPPSRQLLPQV[]WSVVRMJPTTSPPNROIXPTLTQQCMPPRMOUNKQMUNJHWOPRSRPVPBUGUORNJRNPSQNU", 73 | "LOOPNNMNOPOPOPPUULLMOORQPQOPPRNOORMNOKNFMNMKRSMSKOSVOLVKNNQSPONSKQTWNPONMOROOSK", 74 | "KPOOPPQRRRZYVVWYYVVRRMNRRQQOPMPOPMPPNNLKORVHNOQQPPPMPNQNQPRQNNPJTOZGJPPPGMPHTRP", 75 | "KOOPPPPSUQNQTPLMORQORRNMNPPONMRRVPLQLSUULRWRSKQKPNOPKMJPPKOMKQQPLQVKLVNQHNQQPKH", 76 | "NQPPOPQRSURMILNLOQRKIOPRPPQOQLMQKQOMNNKUINLSSOGOIPRQRNKQPNVIPMWOLRJVTOPSRPKOPSR", 77 | "NQPPOQOPPOPPOQQPOPQPPOOOPOOPNPQNOPQQNPPPOPONPOOPNNPPNPOPPOPNNQNOPNPNNOPOPPPNOON", 78 | "NNOOQQSURRRINRMLQQRUSPNWVSPPPLLJOOVONOQLRPKLRJOVQNLIKMRIPRSOQMNKVQSJNOOKNPMOOON", 79 | "NQPOPPSRQTVTPTX[WQORLJLRTRRQPQUKMLTMSLIKUQOQLRJSMOJIRMQOOQLQSOPOURJORLNKRPLMPJT", 80 | "QOPQPPOOOPQQRRQRPQPPPPQPPQPOPPPNPQPSNOQQOQRNPPPPPOPQOSQOQOOOOPNNNLQNMOPMOSPNPPO", 81 | "LOPOOOOORUUQSVVNC=HQHFJJNPPOOOVMNQTNIJKLRQRORUIMPKMNLMMNNJMRLNPPPPVNNKOSQOTNOST", 82 | "QPPPNMIKPSTSONKOQJGFHORSRQQQPMTHQPMRTKQNQNONPPOKNOKSOPOOQURTLRRRRNQNKQQVMOURXUS", 83 | "OOOOONOPRTVUVVRQNKNPJOMOQQOOPSLNTRUPOPJJPORLNOJKNRSHQOQTSQWJQRQOVOMJRQORTQMRUNR", 84 | "PPPNOPPMNOQNPPRPNNOMLMLOQOONOLMMIROOMRPROOTRNSRPNPQNPPQNPQQROOSOPMXPNQNOPONTQNN", 85 | "RPONOOMLOMKNNHJQMHEJNRRPOMPOPPORNSRONOQKLQOEQKIUNJUKPRLOOSOISOLPTKJQOUPLSQMLOHQ", 86 | "WPOOPONNNOQRQQQQQPQPOMMPPPOPPPNPTTOWVRQKQOPNLQKPMPRPMWMNRTUQOOPMPGOQNQMPTQTOPPP", 87 | "IOOOPRPNPOMIRPLPQQPQMOSUPOPOQQMQQTROMLUJTOOHNHQJQSUSRKQMNSWPPTJRIVIJSPMSNMLNLQS", 88 | "KQQPPSWZ[SNNTWQSPNRQUWURQRPPOSTQJVSPUNLNVQKMNQQLRQTXPNQONJROHRSNOQMHTQOPQOLNVVN", 89 | "QPPPPOOQPPPOPQQPQQPQPOPPOOPPPNPPNPPPPMPOONONPOOQQRQPOPQPOPPPOOONPOQPNONOPPPOONN", 90 | "QOPOQQOSQQMMVTWPOUPURORXVSQOO`ISUKMO[XNPOOZLNPJSNVKSPQNUOPR]NZROVPOWWQOLNQPUMKS", 91 | "QOOPPRRTTRRQQSROQRQRMIMPOPNPNSRSRNMORNMQROQNQNSTSROJPPSSQPOTMQOLRNUVTNNNPSNROTT", 92 | "PPOOPQUUSRNJNRSSPLOPNRSPRPPOPPWPOSRMNLRNTPIMMLIOPRSQRPMKPOPLOOLMQPQPOPNKJTONQSO", 93 | "QOPONOPPRRMLNNNGIQOLHKQQQPOOQHNQOPPQSRQSRRTJQQIWLOJGMQLSQNSRPNTMNMINSTOSQNGOHIK", 94 | "NPPOONPPPQQPOPPOOOONOOPOPPOOOPQPMPPMLOQRPPOPQOPMOPOOQPPLQQPNOPORPPQMPQRQPQNNOPN", 95 | "TQOQRRTVSOMLHFFMOPPQKFHJJNNOPERSLTXOSMPRLONLXJNWILOKNSOLPQKKPLULSKKFTLONTUJMSQP", 96 | "NPPOONLLMNNMNNMMOQMKLNPMMLOPPMTPNSLOMMQQVOTIOOMQNLSIMMQOPGPVQKPJPOOHLQQ[RRJOGMM", 97 | "PNOPPPOPPOPPPOPPPQOPOPPONOPNOOOPOPOQNPOOPOPPPOQPPNOPOPOQNPNPNQOPPNQNNQPOPQPNNPO", 98 | "RPPPONNNNQROONJIHJLNQQPRPPOPPWQPONPNNIERWMPLVKPQRLRMNQJMRQNORPQLPNTMOPOOORPSMRL", 99 | "NPPOOMNMMMKNQLNPTQOOORRNQQOPONLOLRSPOOSOPOHTOFLWRQUMPNKLPRSLOKQKRQJPPSQROQLPOKP", 100 | "TPOOPOPPNPPQNKKNMLKPQOQPPPOPPMOOKQSQOKROSPQNNSQSNMPNMRQJSOLMMTMNLMPNGRNJSRSKSOL", 101 | "QPPQPQNLKMKNRNOOKMOMJPQPPNOPOJPSQQSPONLNMNITLJPRTNIFTRQSRQURSPROPMUOOHNLPPOHKPU", 102 | "QPOOONOOQOPLOMKLMPQRTQPONOPOOTNNOSMPLOJOUPPONMPPVLSJPPLTSKOLMOPORMNPRNMQQQSJGTM"]; 103 | 104 | fwdWGF = ["NPOOQPORSSTOKJKNTRQRVVQLMNNPPNSKMQMLJKPKTPRVKRNOQSNJOQNOQLQQPMPRMQOPSNNPPRPJQRR", 105 | "NOOOONRSSONPONLNSRQPSNNOOOOOPMQMNQPIGOQRQRUQLNPQLMQJQMUJLNPQNQMSLSHPTLQJONPHRVR", 106 | "LOOPOOPRVWRQTVUPMOPOKLOOPNPOPRWTMXNGLMSNRLNPLJRMORSLQUQMPTXROLJSNPOORNQQQPQSKWT", 107 | "QPPOOQSSTOLMMORRPPQPMORPQPPPPPUSOPPJPKQSNROSLPMQPQONNSLOQMQNQLKTLPMQPMPORSQQONN", 108 | "NPOOPPOOPOPSPOQPNNORQKMPPOQPPQWNOMPMHJQNPLNOKQQOOQQQOOPQMOPPPSQRNQMPPNOMROPNMOP", 109 | "RPOPPPQPOOQQQPQPQPPQPPPPOOOOPPPOPNOOOPPNQPPQPQPQOOONNQOPONQMPNOQQOOOQPQQQNOQPPP", 110 | "OPOOOQQOLMNLLNNNNQRSRPSOPPPPPKOLQLPMLKQQSKVWMMRPNRPMQNMPONRRSQMUIROOSOMQJPTKNTP", 111 | "^POOOOQSQTVRQSSRQRQTUPPQQQQOOOOQUJPLRPSQLRPRLUTPSKOOCSRSNQPCSLNQPHIRRTSSTPOSNQS", 112 | "NPOONOPQRSPJOTRPNOPOQRTQQQPOOSQMQKQLNPQPPRPTKUORNQMOPQPMPNQOSORRMPLQSQRQQSORNNP", 113 | "OPNPOPNOMONRRQOPOOOOPOPPOPOPPNMQQQOQLNNNOOQLPNPMNMQPONROPRPOQRKOOQTNNOOMPPPNNOQ", 114 | "OOOOPQNOOMNOOOPSSRQQRQNNOPOPPOQMOPNMRONROLNRNOLRNPNOQQPMMQPOLROSOORMRONMQRPQPRP", 115 | "MONPOOMMLNNKQUQOOLHGGJOOOPPOPUSNOSNLKLRNQOOQOTRKLSLIPRRRRPMRLLNSMRLPSMROOOVQJTM", 116 | "LOOOPNONLKJJKOPKJNNPTTPOMMOOOPVOUPONPROPWQOOKTQOTNOQQ^PMNRQURJQNSQSTQURNVSNPTUS", 117 | "POONNMNNORQJJNNNMPOOOPPNOPOPPORKMQNLKNPLQJLTPSOQUQQMNXMQNOQMUMLMLONSSJMMOLSTSQR", 118 | "EPPPONQUSSVYTPNONMJJQTSQPOPOPUZKQYMOEIOQVJOOKLPPMTUQU]SGHORXQPNLKTVORLORPORJIYY", 119 | "]QPPPPPPPPQTRQQPPQQQSPPPPPOONPPMPOKQINQNKOONPSSNONONCRPPNNPEPPPRJLPOPPQPROOSNSS", 120 | "QOPPRQQTQQWRSOJGHJMMLKILONONPOPISNPNOOOMTNSUNPPSRSOPMVQLONOPMPRQLOLQQNQPSRMOMTN", 121 | "QNPPQQSSPQNOPQOQQRRRPRPQPPPOPQRQQPOOQPRNPKOPNNQLQQMQMRROPNNNMQOSNONOQUMNRRQPQQO", 122 | "MOOPPQRQQRSMMQVWRPRQPPQPQPOOOKSSPRPPJNQOSORSLNQOOSQRPPLNKPORSPQQLRPOROMOKOPNNPP", 123 | "POPPOOOOPPOONQRQQNLIKSRONNNOPNPOOQQONPQMOLMPPONQRSPRPPPPSPSPNOJQKPQMROUMQNUPKTN", 124 | "LNNPPPSTRRSPMJIIHMOSQOUVUSOOPIOQPOOQRMPMSKNRROSQQQNPRRNNJMQRTQONNQSRQMSPGTSQRUS", 125 | "QOPOQQRRQPSROPPRQQQPRRRPPPPOPRPNQRPMOHQORLMTPQNOQSOQOPNPIPTOMNPSMOPTQOMPSSNQQRM", 126 | "OOPOMMLKIGLKLLJJNMNMPNPPNPPPPNNMONOKQKMPTKMTQRMROXPUOPOPKQWOONLTLNNQWPNNNNULRQQ", 127 | "UOQPOPPOPPOPQQQOOOOQPPQPOOQQPPPNOOPMPOSNOROPRQPPPOONMPPQOMPKPNPQPNNQPPPPQNOQOQO", 128 | "MPOONNPRQPKOLKKPURQOSPQQQPOPQRRPQUOOCQRQPRMNINPNSNOQPRTKIQQQQOOQKRKLSLRLSNPSMNS", 129 | "SOPQPPPQQQQQQQRSRQQONONOOPPPPRPRROPLMLQQQROQPSNQQOPPNPPSONMNMPOSQQMQPPRQPLRRQPP", 130 | "POOOPPPPPORNIGLPNOJIMQURONPPPOPTNLPLROMOQNPTORQPSUMROQLMQNTOQLPONPLPSRLOMVRQOSQ", 131 | "SPOOOMNNMNRLJQSROPPNLNSQQPPOOVWQJMPNOMQKIOOPOOSPPQPNMUOLPQMNPOMRPQQRNMLOUMPSLQN", 132 | "RPOPQQNOONQSRQQPPNNNONPQOPNPOORQQPROPMOOPOPRONNNLSPSQQRPQNKMLSPONQNOKKOPPOPPQWP", 133 | "NPOOOOOMOPSTMIIOQKKOUSQOOOPPPNRSQMPKLQPLRRNNMOJRPTPORWOOMMPQMRMOQSPOOLMNQRMSTQN", 134 | "RQPOPOPPOPQQPQQPPQPQPOPQQONPPQPMOPMNPPROPOOQRPPPOPNNMQOQPNQMOONPQONQQPRPRNNPQQP", 135 | "POOOOPOPNQSQRQPPPONOOPQPPPOOOUSKOQPLQMSMPNOVMQPOQOQROWLSNQPPQPOTMQLQRNNOQQQRRTR", 136 | "OOPPONMMMPRQLMNNONMNNPQPOPOPPNRPTNONONQOTMMTSORQRPPNNTMMMPTOOPMQSPNQSONRPMRORPP", 137 | "RPPPNOQSRRNOOQPQOMOPOSQPMMPPPPPLQPOONPONRMQPOOONKPOPJQNOOORLOQOOLPQNOPMMMPRQQUO", 138 | "ROOOOOPONNOPQQQNORRSRPOPPOOOPRLPQOPJPNOPQKPQNMNQOONOPNOPPNRNKPQNNPPOROOSOOOLRVM", 139 | "QPPOOQTQONPRRQKHILPOOQPPONNPPOSUMQQHNNNQQOOQNINPSRQUPTPIVNNOKMOTNOMPQPNOSMPRSSN", 140 | "TOPOPPOOPPQQOQQPPQQPPQPQOQPOPOPQPOQNSPPOOOOQRQQPPONPMQOPPOOKQMOPPNOQPQOPQOOPNOP", 141 | "RPPOPQOKKJKNNNOLLNQRPLOOOOOPOTNOUOPKILPOPNPQLMPRTQSROPOLMMOONONNLQOQRPKPTPQPPRS", 142 | "OOOOOPPPOPSQOONONPOONNPONNOOOVPNNQPJOMQQROMQMONRQNNPPTRMOOQPNPPPRPNOQNMNRNOQRQO", 143 | "NPOONOONKLPUOOOPNKHKLNPPQOPPPPRLQPPLKPQKOLOPPNROLOOSQJOLLRKQNUONRQNNOTORPONJSOL", 144 | "QPPPONQPNNUROPPNNPQRONOOONOPPRTPQLOFNORORMMQNOROROQVMTOLOOQNQPOUOOIRRSQNPQQPOPN", 145 | "MOOOOPPOPRLIJNQOOPORSSQPPPNOPQPUKNPMKPPLWUSPLNNNPRNMQWOMLOOSSMKORRLQOTNQKPOMZVP", 146 | "QQPPPPOPRSSNNSTRPPPOMQQOONPPORPLPROLLMSOOOOONNSNNRPSMQPNNPOLONSTLNNQQQNOLMSPNSO", 147 | "MPOPPONPSVTPQQOQUPNPRQROMOOPOLUSORPMPOPMOVOOGNOTORPVOYPJNORQLOQQOPMOPNPPQTPSQWS", 148 | "OPPPPONOOOPNOPRTQQNPTQOMNOOPORVJLQPKNMSPQMPRIMKSLRPRPUPQMQPOOMQRNQKMRNJPTQOQOWO", 149 | "LOPPOOOMIGNPOPQOLJMNOMKJILOOOWOIRPOKSNPNRLPRQSNTORNPQKPQQQTQQNNOPOQPTNQTSPTKQSN", 150 | "QOPPOOPPRQOKJMORQOMJINRPNNNOPQWVOLPJLJMONOKQPRLPSLQUOVPPPRRMOVLSNONLPMMNPMOSNOQ", 151 | "OOOPPNPSSPIHMPNKKMMLLKONOOPPPNRNRSNNPHMRPHKQQPRWJSRaOTPRPNSQHQSSOQMQUSLSORXOOSM", 152 | "OOPOPLOPNUUSQVRKIKNNLNPPOOPOORXTORPGKSTNINKTGQQONSQNPQRHPTTRTOOVSSTNPRWPUSPRHOS", 153 | "LOPOPONMLMMHLOQPRPOOPTQOONOPOLTNNMOJMNQOTMNOMNPPOQMWPOMQLOPRNUPUJOKORNLQOSROQWQ"]; 154 | revWGF = ["NOOPPMMORROKQVYSMMPTOJQQQOPPOOSNSJNODVOROPNRPQPIWUONUPNNPTWMNORTNRPMOPONKMPSMRL", 155 | "QNNNONOQQRSUQLMOKKMRYTPMLMMOPRNKOPNPHTLUPRPHMROLPQJKSQJNQMPLKVRQQQONNNMLLPHKOPM", 156 | "VPQPOPOPMIKNJLNOROJHIILNNNPPOJLKTMKRSMNQQNHQROMNJJUVKWPKPRQMOQ_PNHKQLPRPRRSRSPP", 157 | "OPPPONNOMOMLJLMJJKIJNUTPRPOOOMTUQMIOKKPTLMRNSNMMQMTRTOTSPQSONMKMOPPKTKRNOPPMQUR", 158 | "fOOOOQPOPPPQPPQSRPRSSQOOOPOPPOSSSPO]OQRPLSPNQROQONONO`MQTPMMNNKLO=QPMRTORRPJKKO", 159 | "LPPOPRQPRQPRSQQQTQPONSVPMNOPPRPRRMMQEQMRSPLLRSONSQMORMSMNQVSTQWUMSPRLNLRTLPQHPO", 160 | "YPPOPQPQPQQOONONONNONOPNNOPOORQRMSQQONNPRPMQRQORQPNOOUPQSPOPNOQRPLOPONOPQUONJQQ", 161 | "KOOPRTSRWXOPQJKIJIKPNOSLOPQQOPZNQKMPMSNTPSNSPQEMWMMLPMOMNMWNNOJMQTLORLLTJLMISQW", 162 | "LOOPOOOOPRSQQRRRPMMMLOPONQPPOQPOLNFPORQSNOQMPXVLUSJOPMUSNNRTMRRSQRUQRNPQNLNNTQS", 163 | "OOOONNOPPOSQQRNNORVRQNMOPPNPQQQTJHGPGKQXSOPOVQTOQNRSQOQPQMMRJMPKJQKPOOOONOTINLM", 164 | "MQQOPNOONOPPRUXWVSOSTSTPNLOOPPM^QJNNPVSNSOROITONPUMKRNJOOT^TJRNRLSRRTQPNDMMQPRW", 165 | "LOPPPQRVWXRRSQSQOPMV^ZRMMNPOOLMPREKPSMOTOOSMPTPJYLJVMMLMOSOSPUJTOQPOPSPWMLNYQSS", 166 | "PPPPOQNNPNMLNNPPPOPPQOPPPOPOOQJNSPRPUTOMOSPPMMQLQPNPOPONONQTOSTQQNQPROPONQRNPRQ", 167 | "PPONOPRTTWVTSQPRQQLKNOQPOPPOOJPPWJOQOJTPSORHPOUPHPGORQLUQJNNSQIPLMKKNPROMPLSOOV", 168 | "LOOOPPQNRSSTSSSLJRRQOQPOMOPPOWTQWLLNJOJTLRLQPLONNTMRLNMQQQRLONQNNRUXNPPSOOSTRQO", 169 | "NPOQQRSTRRURPPSMJNQVUPNKKMPOOLPRXOMM[SQSSMQKMPOPRMIMPMMROKRTNPNNORLMMKPSTLTNKQV", 170 | "OQPPOOPRTVPKNQTMOSURMOOLMMNPOSMPSQKSPPQSPQMSNQTHUPMURPPQPKLPSUNQLONKQTOQKLOTNPP", 171 | "MOOPPOPPSXWQOVVPPS[VPNNLPPOOOQVRSCKOJINPPRKLQIQKQQVRPNSPOKOPMORKNRMKMROVLNWSLMS", 172 | "HPPPOPQTRPPJLMOLMMJIIKOPOOQOPFRMKHNKNRMTPLQMNPKQLNQJQIKQNMQQMMQNN[KKLMLRULPPPQN", 173 | "QPOOMJIIIKSRQVRPNNOQJFJPPOPPOOMJPOQPIJK[OROLUNLMOOQSQRMMRRLKWSQKUPRONMPPLPOSQNL", 174 | "RPPOORUSTQRPSVSQPLJPTRQPOMNOOMNPOHMPOKLTMQPQPUPTQOQPSPMOOSSSONQMRMLONRPRQNNPLQP", 175 | "QPOPOPSUQOMHFMROMMFDIPPPNLPOONUQXQOTKOR]QNQSPNUIPPLWJQOWSLTRRPTQLNMASNNQIPOOMNW", 176 | "IPPOPQTUVTUYXWTSQOPVYSQNOPQPPOMRNJMNOTNNUPOLNPOJWYKQPKMHMTTLNRMWISKMQSMSROJXMOT", 177 | "TOOPOPPQPQOOQOSPOOPPNPOQRQPQPQQQSKJPLMLTPOOOTQPMJMLQMRNQQQUSNONKLMORLMPQRPSOKOL", 178 | "UPPPOQPQQOPRPPRRQRRRQPOOQOPOOPPOMRPRNNRQQPRNRLOSNOOQKTOQSMONMRNMOMQMLRMONQOMNON", 179 | "NPOOPQOQRSQUWOPRQONPTSNKPPPPORWPPJIPDKOXQROMWMOLRPGURQR[QRTKOVOULNJJSPQRKNRJOIU", 180 | "NOPPPPPQSQQJNZSIJLIOOMQNNOOOOOSWUNSOIKNXIQQWUTRORQKRQNLNPVSSMVLRNPQQPQOOLOSTSSM", 181 | "UOOOPPQPQPRQQQRQRRQRQQOPOPOOPPRPQRNVOMOPQOSMOQOSNNPOMVNNSNMNMNNJOHONINOLPVOMNPP", 182 | "QOOPPPOQRRSPNOORQLLNRPTPMOONPMRRLLKPLHT]FRFUWNSNMPJPPRQOONNOLPNLSLSPPRPUFOOQLPK", 183 | "UOOOPMKKLJKLMMLNPSTUROVRQPQOOWUTJHIOFJR[PMMSVPTSKHONLRPQPLNKKTRNOOLRWNRNSROSPJH", 184 | "IQOOPQRSRPMOQPRSURORQQTQOMNNOLRZPLPNHONZKMHVVSQLORHXTLHSPTQTJPPNOUPPLTORNNNQNSJ", 185 | "TQOPQQQPPOOQPRQPQPORTTTQPPNPOOOPQTMQQQVOOQPMOONQNOOOOSPRQPQPNPRMKKMTNOPQONQPQNS", 186 | "MPPOPQOSVSQTX_YQQUROMPQNMKPPPOMNQOQORPJMHOSOOFUIRSOZONOVPKPUOPONIRUNRSPWTOOQOQT", 187 | "QQPPOQPMJKONMLNNPLLLLJNNQPOOONFTS9OORTZRSOSPSPRJHMMQOPUTQLCFPUO]DOVPHSQLONNQSMM", 188 | "WOPOMOQPRRPIPWTLPUURNQPRQOPOPNSQTOKTKTWSSPUOTMOTSKLOOVQQRSRSVPJKOILRNLSMMRPPKNP", 189 | "OOPPPPNLMNMLMNNMRQONNPOJMMPOOIOLQKGPIKOTRSPHTLMNHLSPIOSLQJRHPQQMGNPPPTPSLPPSQMH", 190 | "TPOPOOOPPOOQPOOQQQOQPQPOONOOONRPNPNRNNQQPPPOQOORPPOQORPPSOPNOONPPNONMPNOPSNONNM", 191 | "LOOPQSPPTWUUXNHEMOSPNPRQRQPPOSPOJIKPBNRPSQKOUVULTORVSNNSOQSDOKNNKRQURNPPOLOMUWL", 192 | "NOQQPQQSOJNMNWVTUTRPOLMMNOOOOMPJRJONJPKVXONNQQQDOOVPOMMJQRQQMQQPCSQMKTNTMMSWMVK", 193 | "SQOPPOQQMNNKKNPRNKQUOOTQRQQOOOQOKKMPGLPWQPUJTNNLMTMNOQPOPNTLKSLPIMLJHKPQLNOMORP", 194 | "NPPOOPSRQPLMPZ]WVUWVSOPROPOOPMQPXNPNRQMQPQOSLNTJQSJWINMRPNOONSLWERPQQQONLPXRMQX", 195 | "QPPPPPOPQOPOOOQPOOPPPPOOOPPOPONSPPQQPPQSROOQNPRONQOOPRNOPPPPPPPPMMQMOOPORQQMOPO", 196 | "JOQOPQPOPOPVYTTSRRPTTRSOOPPPOMUPUJTLOPIYQRNOQLULNTMTPKJUOWTNQONOGTLNNONVROTPMTV", 197 | "QOPNOPOMKKRUUVSORSONNMRSRRPPOMSNSNLPRIRVNOQLNMUPOOHQQQJ]PVQMORPMMNKROQQTPQMPTO[", 198 | "SOPPPOOOPOOPOPPQPPQOQOPOOPONOOQONQPQOOQQPPOOPOOQNOPOORNPPPONPPMNONONPQPNORMOOPP", 199 | "TOPPONONPQOJLRPPRSRQPTRQOOPOPMQQSKILTJNWOOKMQQUSQQMOQPMSQRPSUNTOVPPONNQQOSPVKMJ", 200 | "QOOOOPQQRRPOLNPPQRQSQKPPSQQQPSONOLJPKQMWSSNISUNLRONSUQLMQSSMKSPMJNHRQRPTPOPPKRH", 201 | "RPQOPPONOPLOOPMHKQTKLLNMLKMOPLMJKNPOQNMMLNSSKNMRMNQSSQLTPJKQSGNMNOPRQQSTRRRRGOS", 202 | "MOPPOPOPSRTQQQRRSUUTQJLMNNPPOPPSNGROHNQYNSKXSNPKTRKTXOHNPSULHRJOMSNNTUMQSMUPPOQ", 203 | "NOPOOPOQONNNNQSQTUOMLPRSONOPPSPLMIMOJSPTPQRJOQWMLPJPUMPWPLQMOLNOTQTSONPXKNKVNQT"]; 204 | 205 | fwdWGO = ["VOOOOONMMMPWVSRPRRRRSQOPPPOPPQSJRNMKQNPPRQRRRPQTORHKKRPOMNOKMOOQNNPRTQQQSPONPSL", 206 | "WONOOOOOPNNKPPPNQPPPPSRPPOOPPRRQLMOJKISIPMQPVRQONTORJPRNPMRHMPJUOONORMPQNNQPRRL", 207 | "TQOPOPPPPOPTTSRTTUTUUSQPOOPOPPSPNOKNONPKQNPQVOTPOTIOJRMNLPPJNPNTNNOPUPOOORNQPRN", 208 | "QPPPPQRSSQPPRSTSRRTTRQQQOQPOOPSPOOQJNNQOROQPNOQOSOMMLQMLOOQMTKMRMQNPRPRUPORNPQP", 209 | "RPOOPQOQROQRRSUTTUTTPKMNPQOPPPSNOMOMPOPPPPOPSQROPNMSMQNSNNMLRPPOOOLOOPQQQRPPPON", 210 | "XOPPPPPPPNNOOOPPOOOPONPOOPPNNOMRQMRLPQQOPSOULRPRRPRPQQQQOLSLNOOPPOKQOPSPRONPQPP", 211 | "VPNPOPOQPPQPNPNPOOONOPPNONPOOPTQQNOMQQTMNQQTRSSOQRNNITOPOMQGOLPRQOPSOQPPPQMSNOM", 212 | "QQPPPPQSTURNQUTTSRRTTQONPOOPNNVOOOONQRRMQJJOSRRNMNOQNQMSUPRPTKNONPPPQPTPMOQULQO", 213 | "TPOOPPORSSRQSQPQSSSSTPPOOPONONUOROOLJOPMSPNSPQRPPQLRJTLOMOOKNNORJOJRTNNRNOPSNQR", 214 | "QOOOOOONQRSSTUTTTTSSRRQOQPPPOPNPOSPMTOQOLNQNRLPKOOQQPORPQRONQSPPOOSOLNNLQQOPQPN", 215 | "RNNPPPMNLOOMNOQRRRPPPPPQQQPOPORRMNOJPLPQPPPSRQQOQRMOLQOPMOPLNONTNONPSQMRNPROPON", 216 | "RNPPOPSRRSSSTVTTRRRQPPNNOOOOOOULKQNNKLRLPMPOSMRJLOKRMSPMMPLLMQMSNNPPNONQNQRNSVN", 217 | "OOPOOQQTPNPXWRVVWURSRQPOOOPOOQYHQNNLQQONSNPXRQRRLUNONRIPNPPONQSMMPIOSPKPUQRRRVR", 218 | "NPPOOPPQQSWUTUTQQQTSSRPQOOPOORVMPPNLKLQLRKPRPORSPVLPMTMMKOTNONOTKQPSWNJQPPRRQSO", 219 | "VOOQPPONONNONLMQSQPNMNQMNNNNOPRNQONOURVMSQNTQSTHSFMOKQNOKLPDPNQQIMFTLSRKLOPROUQ", 220 | "POPPQRPOPPPTPMNPOOONPQRQOONONTPLNRRNKNROQLSOLLNOOTULVKTQQPTUMQQPPNOQPRSNQPQMSQN", 221 | "OPPPPRRRROTWUSRQQRTWURNNOONPPSZKPQOHRPSNSNQUQNRSQQMNNTOMOOSNOLPRNNIPSMSQOQOQOSO", 222 | "RPPPOQRRRSPRSQQQNPNNORQPNOOPONSMMOOLJOROQNMMRNPOHOPRLLOMQORNSVNSIONMPMQQMSXNKRO", 223 | "SOOPOQQRRQOOPRQQRQRRURQQPOPQPMTNNNOIOOPLQONNRNSQNPLRKOOOONULPQOVMOLPRPQNORRQRQP", 224 | "QOOOPOPQPOOQUVWVVVQNQSPPQNOPOPRMMPONOPQNOOOROROPPOQSNPORPOQMSONNNNNNPRTPPOTQPTN", 225 | "VOPNQOSSTQRTSPPQPPORSSRQRPQPPQVLONPHRQRORPMTRQRRROORKQNQOMQIRMTSNMHQQRQTPPRQOSP", 226 | "SPOPOOPQOPRPQRQQOQQRUTSPONOPPQRLOLQHMNRLQQQRPQQRPSOONPNQKLRLNMNSPNISSPPPRPQOORP", 227 | "SOOOPOPPPQTTTVUTRRSQRSRQONOOOQQLQQNNNLRNTNRRQPTPPPMPISROKQVHOOMUMNLQUPOTQPRPQTQ", 228 | "ROPOQPOONOPPPONONOOPPNNPOQOOOOOONPOQPOQPPONORNQOONOPPPNOQPNOOPPQNQNPOQNPPNPPPRN", 229 | "OPPOOOOQRRPQRPPPTUSQOPPNOOPPOMPNKNMJRNQOSKLQKQQPQQKXNPNTPMRNORRQMOLPTPPROPRNQPK", 230 | "SOOPPOOOPONQRRSSTSSRQPPPQQOPOQTJPPQLROROPNMQRQOPOQQTNUQKSOMLRPOOMPLPNQPSRLQQNRM", 231 | "UOPQPQPSRRRQPOPPNNQQSTQPOOOOPRSQPKNHONPOQPNSRRTQPSMRKRNPONRKNKPTOOGQTPQQNORQNQO", 232 | "PPPOONQQNOTUSRSSONPRUSROPOOOOQXJMNOHNOSOOMLPOQPRJRLTOQMQNJOPOOQQMSKOQUQRRRSRKPK", 233 | "QPPOPONOQPNJLPPPPQRQPPQPQOPPOSQQQNPJNKSOOMPWQPPQRRQOOQMQNORNNLSTOPMVSKIOQONTQPS", 234 | "SOPPOPOOPONNRUWTSRRPONNNNPPPQRSPMMOIROQOPONRSRORPSOPMLPQRMRJMNRVTOIQURMORPQPNNM", 235 | "OOOOOPPOOPPNOPNPOPPOONOQOPPOOPPONQOOOOPOPPOOOPNPPOPPPOOPPPPPOPNOPOOPPPOPNOOOPPO", 236 | "TPOPOOQRSQQSSRQRQPPTSSOOQQOPOSTKQOQLNMTNSOPTQPSPPQLPLSPOMOSJPMNSNNNQSPPRPRQPNSO", 237 | "QPOPPPRSTWSRPQQSSSPOOQRPOPPPOQMLNQPLPKRMWHRUNKQOKPNQONNNLMNNLSMQPPMSNPNMGRSLSQO", 238 | "QPQOOQQQSSTRPRQQPPPQOPPNOPPOOPSLPONLONSPRMORQPQQOOMSMRNPPOPMOPOSLNNPQRMNPOSPOTO", 239 | "TPPOOPPPOONONPQOONMMLMPPPOOOOLORNLQKQQPMOLOPTPPMQRNQNQLSQLPKSOMQMONNQOPTMORPNMN", 240 | "SPOOPQRRRQRSTTQRQQRRTRQOPPPQOSTOQOQLNJTPTQQURQQTRSNLMTNOLMRLOKPSOOKQSRROPQPNRSL", 241 | "RPPPQPPQPPPPQPPOQRRPPQQOOOPOPOQOPPPNPPPNONOOQQQPONORMPQOOOPMPPOPMNNOPMQQPOQQNQP", 242 | "WOPPOPNONLMKNNMNNOOOMMMOOQOOPMQQNPOPQOTKMQTNVORIPMMOJRONNOMIPNLPJPQOMOMPNRNQORM", 243 | "QQOPONNPPRPSUTPONPOOPQPPOOPPONRKNPPKMOSRNNJNNPQSMOQZNPPNSNPMPRMPNONQQQOQRMTQOUN", 244 | "SPOPPOPSPMQURPOQQQOOOMOPPONNPTVKTQONUPQPPNQWTQRRPPNOLSMMOSQLOPTOPOIOQPPOQSPPOSP", 245 | "QPPPPOORQTTOPRSSRRRRRRPONOOONOSKNNOOLOROMNJNRPNMHKRXMSPPSQNMTSKPKNMNLPQPNPTSLQR", 246 | "VOPOPOQPQRPOQSSQQPPSTTQOOQQPPPSNQMOKOLTMTNRSQOQSPTIONTNLMLRJONLPMPOTUNQROQRORQL", 247 | "RPOPQQRRRSRQPRTRRRRRRPQPPPNPONSPPNOKOLRQPNNRPMQNNSNQNROPMNPNNONTPPMRRQNOLSQOORN", 248 | "TPPPPQRRRQQSRQQQRSTTTQOOPOOPQOTLRPOJRLRMRNQTQQRRPRLOMTPNKNSLLONRPNLSSPOSRSPRQSO", 249 | "VOOOOOQPQPRVUTTTSRSQRPPPOPOOPQULPMPJNPSNPOPTRQQRPNNPKSPQOORJOMORNOMPROQSSOQSNRO", 250 | "RNOOOQSRMMSWUTTSRSSRSPQPPOPOOQQMTONLPOQNSPRRRPTRRRMLKQPNNPRMQONRQNMPUPSQORRPOPP", 251 | "POPPOPQUTTSTXVVTQQQNOQQQOONPPPTJQPPIRPRMPEMQQNQRNQLROOOORMYPLRPSNPPPVNQQNOTNPSM", 252 | "TQNOOOOPPPQRRSSSSQRSSQPOPOOOOOTMROPMPNSNTOOUROSOOPNPJTNNLNRKOMOSPOMQQROROROSNSM", 253 | "NOOOPOPQPQQUWWWVSSTTYWPPQQOOPU]NNPOHNNUHRMPQTOSPNPHRNRNLONRPQOOSJPNPVMQUTQPPTPN", 254 | "QQOPONPPPQQPSSTRQQPPTURQOOPOPKQOMNPKLPSNQKKMOPPSLQLSNLOWNLUNMRLUMPMRRLMPPRQPMSO"]; 255 | revWGO = ["WPPOOPNNQQLKMOOQRQQPSSPPPNPPPPVRPRQTMJNOPQPKSPLOMNQOMUKOUNOOOOMPRIJKNOOMOSPOMNS", 256 | "VOPQOQOMPSNJQTXVQPTXPORLMOOOPUPTRJUUQRLROQSPTNSIMQNRRVYNTMQKSTYWPIULRLNKQQRQKRU", 257 | "PNONOOPROSQLLQSQRPPQRNNOMMOONUPNHUVRGOORNTHOWRQFSTORTPN?QSVQPOVMIKSRNRNSOPPSOVO", 258 | "SPPOONPOPOPPQORTTTSTQTRRPQOPONMQQVQTPNORRQKPNPINPPTNPUMMSPWNKKTHPILPPMMQPQSLLTM", 259 | "LOPPNJMQUQNLPPOOOUTOOOILONNPOTROPEOPPQOLPLKPTQQOPTNXPMMPMPNOTPSMNTPMNSSNNKRNRMK", 260 | "NOPOPOQTSSW^[[XWXVYYXUPONONPP[QLPOTPQPKKQRQQQLOLVXQRXNMKQSTSQLKRQNONSSMJORKOLUU", 261 | "PPOPOOOOPPQQQQOPPOPMNMPNONOPNSQQNRSMONKPMPMLQMQMPPNQONQNSQONNQPTQOONQNQNQRQMNOR", 262 | "YOPQPPQRRQOQOMNPOOPQOOONOPOQORQNOSOVMQORQSONRPQOQPPNNXMLTOOLNNMNMGLLONPLNVLMOQO", 263 | "SPNPPONPNQUVRRNPLJKKKNMOOOQPPRSNNULPIJP^SQNSSSUNQPRNQSNMSPWVISSTNKONXQMSQSKRPQI", 264 | "ROPOPOQRPORTUVTRPTTSSQOQPOPPPUPVSRIPLNPWPQOQXMSKNOOTOQOSSROMNOYRQNNNRQNNMRSINQP", 265 | "TOPPQOOQSSKKSRPQTRPPKNPNOPONPPMUTSNRXONWUPTVNRWOMLMMJTQNRMJWOSKKGH[RMOOUSSQIPXI", 266 | "WOOPPPQQQQRRQPRRQQPOQURNOOOOOLRQMOOWMPSUONKUONNSQRQOMTJLSQPKPKILKIMOLOOPMRNNLQO", 267 | "QOOPPOPQOPNNMNOPOQQQRPPOPPQPPQOQOQQRPPMPQPOPPPQORPMPMQOOQOQPPPQROMONRMNOQPOONQQ", 268 | "RPPOPPQRRRSOPPUVWTQQTUQPQOOPPURQRTNRNOORKNOJWKRMPNJUQSSVQOQJRTTLQLPMSOORNPNOJMS", 269 | "UOPQOQPOPQQSRRPNPRRRQSQPQOPPOQTQNSLTJOQTMPOPRONQOQPOPUMRSOPNMLMOOJMNNPOPOULOONP", 270 | "ROOPOORSQNLMPOOJJOSYZSMMOOOPOQLOMSPNQPTRQRULSOTOJKKKOQLPSLMPTNUKFKFDRNPHPSKKTOL", 271 | "QPOOOPNPQOOQROOQQRSTXUQOOONOPOSSJPETFQSZLNPRTQUMNNNOOSTSQKMEJMPNKLSKQQOSNNMONHK", 272 | "LOPQQPNPVWTRSOPRTUZYWUOOPPPPPRWWPLFOIHJNNKJRSROTKPRQMMOSQOKHMMRMMRLOQNPMTPSSNKN", 273 | "[NQQPNOQQTOJHGHKKIGIJOONOOOOOOSORXJSGHTSQROQPQZMQFQNOWWKURNILQVLTITPMNNHVTTIRGI", 274 | "OPPOONNONQTXXZWURQOOSSQOOMOOOPNNOWPRJLSXNQOTTOTRTNKQOPLMSNQROUKPONSMMQOOQQLPOUG", 275 | "NPOPOOQQSPQSUSSTTPOPTRRQQPPPOLRSOTKPINQXRORNROQMOOIROOPPPQRLJPMQGPOKLONMNPHPNVO", 276 | "QNOOPOQQQPSXWYUSUXWURONOPPOOPLUNONLQLNLYOQTVTOPRPTOSJRITRQQRMHPLMKQQJQQSKRHVPNS", 277 | "ROOOPPRQRPRWUQNMOPRSTNNNOQOPOMQPOSKRPPRVKQQPPSNMONOPJROLRNPNOPSPKKSNOSMRMRQRPMK", 278 | "PPPPOPPSRQSNKOUSQSTTTQPOPOOOOTRPQSHQHJMUMQQKTLRIMNIRJONURPPKMSROOQOHOMNQQQPLMPP", 279 | "NPPPPPOOPOPNNNOMNOOONOPOPQPOPOPOOPPPNQQQPPQPONQONPMPPOPRPOPMOPPOPPONPONPPPPPNOP", 280 | "QPPPOQPTUUSPQRRQRSQQPPOOOPQPPWSUUOHQMLRVSPNSYKTOQSOROSRWUQOROPPQMLOLUOPSPUPOJMP", 281 | "VPPPPPQQQQTTRPQPNPQRSPPOOPNPOPWSMQLULLPUMONPVPNOORORNVNPTSSMONPOSIMNRNNPQUNLNOO", 282 | "OOPOPOOOQPPPOQPONOPOPNPOOQOPPPOOPPQNOOPOOPQOPNPPOOOOOOPPPPOPPPOOPPPOPPOPNPOOOOP", 283 | "NPQOPOORRTPOQSUTTRSURPPOOPOOPNSTLQLQKNPWMQJURMQNOPKQLPJQQQNLLTPQKPOKLOMONSNQMWL", 284 | "ROOOPPQRQOMLOQRONQTQNVTRPOQPOXSPRVPQPNSQSOOUQUUMSQNNMRILQPKUGLLOGLGSRNMTQSUQKXS", 285 | "VOOOOOPPRRSPPRSRRQQSPOPNPQPPPRTVOSOTMMOTNRPQQQSORROOOTOQTRROKPNPOJOIRQLPPTPPNPL", 286 | "TPOOQTUSTRORQRPSROPKHNTUSQPQPPMULMXSLTMSKQPPSKPKRWJRYTOTOQWOISVUPHPLXQQSPOJUVSU", 287 | "MOPQQPQRTTXYZZUXWWVSROPQQNPPOSSQRPLMLLMSLPRNUGWRQPUUONSTRMKQKRLKKQNEPWNNPSNOLPI", 288 | "WOOOQPNMKOOLLPSSPKIBBDLMOPPOOTNOTXQUYPPHPQNPHGNPNL]TRUOORMUSNPPINJSYMLNQONWISRP", 289 | "MPPPPPRRSROMRVSPNQTRQQRPMOPPOVSTOQJRNONUTPTRNRRNPRPNUOMUSPQRKQRODMNLSOMRTRQNJTS", 290 | "SOPNPQQRQRRTSQQQQPQSUSPPQQPOOQSMOSPTKMJQQPNMTLPTNOQNLTNTSMQMMMPMOJMQMNOPPSPNMPP", 291 | "TOPOPPOPRPQOPPQPPPPPNPNPOOPOPNOPMNQOOOMPPOOOPOMQPSQNPPOORPPOPPPOQPPNOPQOQPNOPOP", 292 | "UOPPOQOPQRRTQMSRRRQTVROOPOOOOQPRNRLVNRRTPNPLUPQMQMPRPTNOUOOLOQRQNKRQQNNMOTNOMRQ", 293 | "VPOOPOQSTSTUTTVXVQSVTOOQOPPOOKRRMOMRONMVQPPLSPOLPPNRMSNPSPSNLQQPOKQNPQOOPRPONRL", 294 | "ROQOOORRRUQNJLTSQQTYWYVRPOPPOXQKOTIPKJTOLLOIVMPNRWUMURPXSUTNKNRUNOIJMRMWQPOOIOR", 295 | "ONPPOMPRUSPPQSUUTRTUSSRRQQPOPOTTMPMSJIPYJRMPVGSMQSKTOOJORRQMLSMPJOPHPSNPOQOQJNJ", 296 | "ROOOPPOQSSRQNQROLMPPQPPOOPOPNQPRPSOPNQNRQOPPPPSMMOOOPSMPONPPNNQRPMOKUPOQRQOONQN", 297 | "WPPPPOPSSQOMNMNPRPPRRONMNOOPOITROOLSQNMYWNMRUMPSLONQITOQTNPNNNOMLJONMNNQOVLKNSM", 298 | "POPOOMMKMMSVRQSRSQSRTQRONPPPOPWOOSIPOKUYHQPLTKSLMGRPSOQPQJKQOORGUNPKLLOTNTRLNGJ", 299 | "UPPOPOPOQPRQPQQRQNPQPMNPOPPPPPOPPRRMTOONROMROOPSPOPONTPNOQMPPPNQPJNSROQNPTNOPPQ", 300 | "ROPPOPPQRSTQSRRSQPQRPRQPNOOOORRUTRMURKJTOOIPOJPOMQPOOUJMQOSPMORITGQMSPMTKTRRMRL", 301 | "POOPPQPPRSQJKMLOOSSVUTQPRPOOQWSVSRMSFPMSPLOKULWJOMLORRNRPPPJLSTKMMKHNNPIQSSLOMO", 302 | "ROOPORSQNJILJPSTVTSSXURSURPOOUJ^RSOT@FN[KPN[VGSOSMBWQRNWRJMKWYbOMOJHTTNMLQSOINN", 303 | "TOPNPOPRQQQSTRRQRQRQRSQPQOOOPOSRKRNVLLOUQPLSRPPQOSQOPTPOUSRMKOMPOKONOQMPTTNMLOO", 304 | "UPOPNOMOQPNNMJJKNPLMQPRSPOOPOVUXOMGSHORVQQQRRRUKRKLOQUSURKLMKPILPHSRRQPSRRVMJNL"]; 305 | 306 | fwdWCI = ["IPNOH97@CLVXWY]UOOOGEKNSV[WQOLQKJPNNMKOPKQOJITNOIQLFSLQTQMKPJOOKRPQMLQJNWQNLRSN", 307 | "IPOPOQUWWXY^]Z`cc``RTVXURRQPPNLOQWLNORRQOPQQJKOTMLOROOSMORLPMMPPRPNQLQRQNTNQLPM", 308 | "SPOPSSRPRMA?AJOUVQOLLMMNRLKNPVZONLMJSNOJOKQSXWNLKSPFPTMPRKQGPJJSRMMPTRKRVJMMUFP", 309 | "LPNORV[_]POTTRNJMQSRQOPY[YTPOVKUNVQUPOOQMRYMMRQPTPREPQSQMGQQSLPUTRSPRMQKLLKQUOS", 310 | "MPOOPRRUTNNSPNUTYTMFGHQVVUSROLGKHMNWNRLVKUULMPTPNKLNNJQPIUQRPPOQNPNJJOQMQSPMQNS", 311 | "]OOOOPPOPOPONPOOOOOOONPOQOOPPSOQPNHPROTMMSQNURRQSNMMPPQOOLPDOMMRONOROPNQPOOQQOO", 312 | "RPPONKKPMI:86=9;>C=?EAGMPPPQPMNTMPJPQVLMOZOEWTRPROJPRSIWOUKSRPTONNSMPMMQMKNUMMR", 313 | "POOQORSQMGLLOPRRSNLSQNMSUSQNPPRIXJOKOSHUOMQMRXKTSTONOJKUTFJPOKTWYNKQL[ONMNRJOJJ", 314 | "POPORPKLLSUUVPABCLSVVQHJJLMOOGFJSHQKPLLWQLNMVOPPOKPOPPLOOLVOMLQONLMPKSSMNRRLFDT", 315 | "QOOOQPSVRTTUVTTSPQSTTUUUVSQOQXLNSMNPGTTVRSKOMOLQPMKTQLLPLOOOOLUITOPPOXTPNONLOGN", 316 | "MOOONLNOSOLRVQJKLLJHJHLMLKMOOPTPQJPVNKTRLRNRRTOSMRJKPSLOQMQOTKKQSONQTUOQIQNQLKO", 317 | "MPOPPQOPMGNQNNNPSX``TMNRRPNPPNNIL]RUJNNMPPROCROKMNPTQRUPJRKXRGRNPTPOIQYMRROTPZR", 318 | "[POPPKIGCCIDFKNQRNOQMLOMMOPPOSLORKOLMUONBRORSTRHSRLHO@QQSKUMSPOSOORYQSQPSNMTP>J", 319 | "QPOMGAAAGHHKOQKOMRPLJJKTXXTRPQTJPUPQURPLPOSLQNMMMMIFPUQQQSIKSOPLQLRSMSMOKJQLS^K", 320 | "SPPOORWTSONMNMRWZWUUUYXPQSRPQS_GWJWNRFQV`cSWSVRSNRUKTrRJUPXPLIPLaONKVLJPVSHSKQZ", 321 | "LPOPPOPRRSRXXVSSSSRQRRRPPPOPOQYKQOLOPOOONHLSLUPONQRRTRKPPMOROQMNOMOQTLQQNLSPPRS", 322 | "OPPOHGKMQRMLMNTVVQLNSSY^[]WQPTRKOPOLJLNMMJNVORSTTSNXNKNSKJRLKPSONOJTQOURYYWLMGR", 323 | "PNPQRQQQTULORLGLPQPPPQTROQQPOTTOQSNQTTUPKMRSOMNQKSKGLPMPLNINKKROYPRTRPJQTPKRRNK", 324 | "SOOPPNMQULRcd`UJJKMOQRNMJLOQORPOPIRMMNLMJOTJJPNOQWTCPMPRSONRPMPNPQNNUNIPONJORVL", 325 | "MPPONONNMLVWYNHHNUXTJHIV[ZTQPXZRLSMLRROKOMUSMRMRSQQHNUNLLLQOMLMPRPQQRQUOWMOPPJM", 326 | "QPPOOOPSRLPTTTY__VPOTPNNNNNNOQ[NMSPLRNPOULQQGJLYJTVKMbRKQQSUMMRLPTQLLVNOPPKJISO", 327 | "UPPPQROMRRRQOMMOSPKHIJONPQPPOTSRKMRFIOLRLN^OMROOUONQPOTQNRPRRNPSOTHOORMSMIMJKVT", 328 | "NOOTbpuwvbQLLNNPQPNMPRRLMJKNOORPVUQNMLPSOOJJLJQWSQOTRQNOSMQQLUPNTPSNMQNRSNQUNQL", 329 | "VPOPNPPOPRPNMNNNMMMNLOPONOOPOQPNPRUOSQPOOPPKLLOQQNRPXNPPPMPUONPOMSQPMOQPSMPOPSO", 330 | "TOPOOQRRQPLQTROTTPT[`XSQONOOOS^PMZOTDS]LQYQRJHPMUMQIOZQPLLJSXIILZRRMHUVMNKJ]PKL", 331 | "YOOPPORSOOOSRRSLMNNFHLQOQRRPQSGTUMSJOOPQJQOOPOQUROLRNHRTMQRIKUSVTOKSONMSUQNJRUN", 332 | "PQOPPOLNQRPNSSTTSSPNHHJHLOOPPLTGOKOQNYNORMITRSOTOSNLPLLQOMTNTOKHLOOPSPXJU^TPTLQ", 333 | "NOOPNQRTRTULLPNKNOOJORPNQRRPP_QQUSRMMPLRLOLSSVPLXLJXQKUQTOYNNQNSNNMOQLQQTMZO?OO", 334 | "OOPNPPPNOQOKFHNOPMIHIPPMPQPPOZKUNQNOSNQQJURLTPTORLNOKNSIQQMKNLPKOMOQIOLOPNNROIL", 335 | "SPOPNNOTOS]ZWSGIFBBSY[[SPOPOONPJNQQPTKQRSNTNMKLPKIUKMRPNMTSONDSPRPRNMSRNIRRGLXN", 336 | "MPOOPOOOPONLNNOMMOMMMPOONPOPOMRNNQUSNNNRPPPMKMONNQQRVPQKNQMYQOROKTOMNQNMMQRPNQM", 337 | "TOPONPNLNTIHHLLHHPSUPRVbb^YRPSSMPKOMUKQLPRQNQWOQTRRPLTMHUSNMSROKNPPLRNQWQPVPIHK", 338 | "LOOPUXVWTMKPOMOONNKIGHIPPPPQPFQKQSPPSNUQUNIQURPPLLPYOPQLPUQMLPNNNLOIGQPPOWPLVXN", 339 | "SPOQTUVWQLJLPSTRQPRUMMLJHJLOPOONNNLSNPKVLTKNOPMRPQRXJSOTPMNROOTSQSCNSOENTKMTMKR", 340 | "QONOQPTWUQOKOSUUVUURTQQRPOPONSRMPSNIQNVNUNMQPKRSLTMROONNMRVMPRTPIPRMVKOTPQUHUXL", 341 | "OOPOOONPK=HOQSXYTPNOMJFHOONPPOMYKMNIMOPRWIMTLOSMPWPKMJIQPJNOONPTRPIQSLUTKTPKPCL", 342 | "MPOOONOMLOMMLPRONPNOLKLNNNPPOLMRKQPPIKNNSNNPINLMMSTNUORMMQOWQRNLNSPNLNPLLLNOPPP", 343 | "JPOONMIEFJFEIOHFHJLGBEKNQRQPNMERIPK]TMLULQVNPONLQNYFMLTRVVNORTRRWOTNKSRMQLIPQJQ", 344 | "OPOPOPQTSOSTPTVSTUTROPONPQQPNQMQMSQQPLQTRQTPIPOQSQNNQNOKJPSOMMNR]PSOSMOPNMLMUPR", 345 | "IPPPPOMNLQY[[WTUSRXWWXSONNPOOPMKPSNJOJRNWITPJOOTMSSMMPQQLUVTPONTOPNNWPMOPJRNPOQ", 346 | "QOOORTPRQGFQSQRSQPXVSMLQPPPQPPHQURKJOKKRRSVMJYQXLVMROJQMLIKOKSPSLOQKRQIRQLOOUIK", 347 | "SOONPRQRRSTQNE@IORPRRQRVXVSPPLDSMJWPNPJOIMUWNOURUORQLFNHPQROTOOPEOMOSPLMLNTHQBN", 348 | "QOOOQRPQSOQONTUSRMLSWRNNOPPPOXKJLNOOTWRMMKTOOQOPSPWLPTPVYQMOTJIKIOUKSNMQUJJNJON", 349 | "OOOPNMMLJGW[UTZWJBENONOTTTSPOVNCQKMOSWQTDQTMIKPXSIOHMQQMOMXPOPLRPQPRMPSJRPTTFJP", 350 | "LOOPUYYUQLOOPRQMIFJV^a`]VPONNIRTMJMQSOPJPTZUSQNIJPNLOPPMLPMONJQQPOMRSSOSTNQHPPS", 351 | "OPOONRPRZaVONNMNNRNKOX]dff]QOSTLWTQSKPRPTKIRKSPPPNPXROQOPTNRVUONOPPRRMQOLP[LQ_W", 352 | "RQOOPPNOQRRRSTTNMRUQLMNOMNONPPKYONOLMNNRJPUIORLJSNUOMIQOOOQKUWNPMMSMKJNNROLRRCT", 353 | "UOPPQPPLJ;:IRVVRRTSQPOPRRNNPQJRIMPSKWQLQQOTQ^QRVUPSLTLOSNRLPRMOKOKRMQPJPVPPIH[P", 354 | "XOOOMNNNQOPSXZZTQQQSROMRTSQPPNKEQVTXLRQPZSOHIQTLQIONRIQVLYPPMOKKMRMSLNQOKLKWMYM", 355 | "OOOPNMMNOPNNNMGFCILRSQUQPQROPSVQKHOIMSOIFVRPSNSQUKNNQRRKKPJLNMOXOMMLRMQPMMNQSMS"]; 356 | revWCI = ["PPOOMKOU[Y97=BPYYQSTSUQOQQPPONHTMWPPJWWHOTNVXQTQIRLOKPLZPQJPNVRLJNIPSRNGSMQNKPQ", 357 | "OPOPRWVZXY`geYKJHBUa_`ZQONOOOSKPMKPQJMPQQLJNTKJPVMPOLRKQMKRLTOPLMQEMNSOKITPNTKO", 358 | "UOOPLJKHIPLJNNLNNJAAEFMSSQPPOQROBVMOLEQQPCOLXMIWJHOGMVSLPMOUMNCLRFLMNLVISVOQORK", 359 | "ROPOMIHGFAFHJKLNNKDCABBLNPONONUXL[GTJLYFPOPLVLTMDDGRJSROTLJ;LRVHIGMSHKRHLMRLSJL", 360 | "GPPOONRSZ[TRSSLPSOSX]WSOMONOPQQQK7VLIIOY`IRPMOWRQ?OKNHSQJN=NQNMWCQPFPPPJPUAQYQM", 361 | "ROOOQSRRUWWXZTLILJNMLORKJNMPNQOKNLMOUYTOUMKMPUXKMVUMUOZUNNJTVP_VRSURSIPOROYRRSW", 362 | "HONPPOQSTUQMMQPOQRNNMPPMMNNOPRQULNTVLOPQSKMMROPSNRPMRSQJMNTMRQLKMDRLKSOOPLVPKRO", 363 | "XPPPPMNLQSORME856;?61.2FQROOPMDSVUQOTLNMPMPQOIVTFKOKRPLQRVLQPTUTHNQOJORSOQORTSP", 364 | "POPOMLJIKNGCDHFFJIJNKKOCGILPPFNQO^STUENXJOPPX=SOBEOSLRJNSNSQQTZLLGRHWPOKTTIUFKF", 365 | "SPPNLKJKOSRUUOJFHIRPSQJ?FILPOFQZKVNOJRQVCQMXQMPIWKSPOQMMNOOSLOMIZN`PXXOMGRPKXQF", 366 | "LPPRT^b`_fupjea_[TTUPWUTVQPPOMSULDRMOUOITNORNKMQZQNGVQNRL[YQFKMMMOMOKRQRISFOLVG", 367 | "TNPUZ_be_TBGHJHM[heNKJOVQOPPOLOLFLPKRNQPQQKPKYJNDOOOSPLFONITJNONCQPLQTOMPRQUPST", 368 | "^OOPPPPPOPQSSUTSTTUTTROOOOOPONPPUTPaQSPLNMRONPNLOIMRM^KQNKLNLNLGLAMQKRPOOLSKPNQ", 369 | "OPOPOLMMHFIKIFPWQPTSIDGNTTROOONFPUMNHRQUSMQD[LIMAMPRQKXNPNWNNLOOOSFTLMPGYOKRRHU", 370 | "PQOPOLLLMQWY[ZWR7>JKOPNRNOPOPFPSLSQQVIP]LRNRKTTKSHLNRPOTQMKMOONPHOMLROPTROLQRMP", 371 | "OPOONPOOQTTMMUVZYTVUUYVPNOQOPJUXNFLOGOMRDKORMQNRUNEWNQSZNQVNUMPP`QPWVOOTKROKLHP", 372 | "WOPPOPOPTVTSRYYSV[ZJJJETZVSPP[KHRPMNLKTXUQSL[LWOQQlTOVMRVXRVKMIMCQFOQWTLLSTOOTF", 373 | "LOOOOQVSSSOLMNJJLLHIMOOURSROOQTPMRJS>MNTRTTRXPQHTLLRLMQAONKHKVLMROMLHQLLKOMSPSK", 374 | "ZNOOPOLHDINLNGGCEECGFIMFGJNPP>L:!PgP_`T:gRUO:sHHKQf8SRV:MF9JS1 HKOW`/JST]IQUUTJ", 375 | "WOOOOOKFFCEGHMNNNOSIDGMKGFLNPMEVSWRPORMMVRXIPRGPNPMQKXPIRLRWKRMQGNQVRPPLSUFNKSX", 376 | "VPOOQQQRRSRLNLIKLC?FMOPNPPPONSGYSZUPTQRMPQOVFMSMMTNNQULVOQWQMXKMKIPNYNPMSPOMUPU", 377 | "WOQPPQPRXZRSSZ]WWR]XPXYSWVQQOTHDXK^J`IXKJ]USLOcSYYPWZNSYRPNUKUUYAVHJaZLYNMRUNS_", 378 | "HOOONPMOKGOWXXZ]]VMPTPLTXVQPQHNYQEKMPOPYJOTSPJMIXQCPIHM]MLSXSSPVRVINVSLSJLHSLFK", 379 | "POOOQTWWTTTKJSUSQPGGMRTWRMNOP[MQQPITHQNPNSMIPJXKSQOUMRTJPJOMUTNLTKTOZNNKHMMMHQQ", 380 | "QOPPPOPQQPRSQQQRQQQTQPPPOPOPONSNMSPQNNPQQPQNTKOTNLOPJTOQRNNMMROMPMPOMQPNNRNNNMN", 381 | "OPOOKELJJIRPMONKQVVSRPXpjdWQPWHSMHIMMMMSSSJPSNaJQQNQLNMRP_YPNKPNLP^RKENXLOOJPJW", 382 | "POONNLLKHKIIMHFC;BIMSSY[_]VPOKROLTMQNRISVMVKOYMPHHJPONRMOMQKPWHQRLLHHIRN`ONGPNS", 383 | "iNOOOOPPPQTWTTUVTUVUWSPQPOPPOMZTQTGiNLQQROWHNWR]POTJGfGL]LKIGHG@P6MI:HLFViQEHPO", 384 | "QQPOPPTROHOQRRXYZCIUWSRQLLNPPNQUMKUJUTVGFRQ^MURRZTRHPQMUONSOQQNNXRDSYPRFMQTPQLZ", 385 | "GPOQRSRPOMMTQTQLMQPNTVSRRRQQPMJWKUZOS[NKLQIOIMLVZUYNWOHIOUTXSOMBVNSR]NPORIVLTRR", 386 | "MOOOOMNRQPRURTTPPK@6547KRSSQPRVMPWMPYNUPOTSMLQNP@PKEOPSQMHORORLTSMOORPPQSPISMMP", 387 | "MPPNOLLIGGFIHLKJLIILJHKKKMOOPVHRQLTRVLKOMPPOTMPTRUJNSONSPRLRMKKSXMKDWOOPJVEOPVQ", 388 | "EOPPOPNPKJNHJHXbjZFQLIORQPQNOOJ[LHJNOQTWNMJLVPSMTO;LSHRHK]UVWQNULTKPLPNAQMKSPNE", 389 | "GOPOMJIIIIA27===?>=>BGRNMNPOOPM[P[OSTSPFLQIPMSKPM[QKTLTPOU]TILHMYSORYKMXLIPVQTZ", 390 | "TPPOPSRQRUSORPMLKKLPQLMTTRQOQROVOPPPNOOSSQBKRWIMMQKMRSLJPT_NKPVOOTONVMNSTTNJPQI", 391 | "NQNME5100DQPQQRPOSPRPNOB@GLOO[OSORRMVRPHORRMQSLTXNODPQTROLRRSONSWPXXPIOESPSOKLV", 392 | "QPPOPPNONNNMONMNMMOMMOPOOPPOPNOMMINHKRPSNNONPPORQPOQOJPSTOSONORPQXROOPOROKQPOPM", 393 | "OOONH:657?HHOYbaQIIJHIE@>AINOMSLKKIOGPNRPNOOQTULQSTPNONKNTOURPONNPMTROQMVNTJKTK", 394 | "VOOPNMKFD9ERSSUVQJNOOPVTOLMNPMRNMZKORPJPSPLSMJTOIO[NSSIWTLNHNLQQGQMMUTQ[HLTRMRP", 395 | "MPONORRTQTZNA8??AKRUPNQPOOPPQZLPPSPPYUOQTQOPOJOORPQGKPSVKLMMQPUKTKHJPNPXHNPLRJR", 396 | "NPPOPQLLPRVX]_YNQUSNKHIDDDIPONKQNPMRUPUSKOVLWTXORVKTSQQYMYUMSWSVXNIQXLOWWLRSLNL", 397 | "SOPOOQOMMNOQQQQQSRONQRRRRQQPPSPKMPITKOPOMPRLTPUSPPQPSTTQPNOMQQMQOIMRMQNORQKOMKK", 398 | "LQOQWbb^a_[XYJ+*/CBHJHLGCCJOORXRNSOONOQTKTNLSNRQWNOSROPRQTUQRIMGPRNTSORNOOSNKMO", 399 | "VPOPOOPVXVQPPPRQTUMLNRV``[VQPNLJLQSQLLMMSPKSKPWMSQZNZRMJR]VLJRSRGNANXLQKRQQRPMI", 400 | "NOPQOPPPPPOPQPQQPQPPRPPOPOOOOOQQOQPROOOPONNPTNOQOMMQNVOOMPLNROORPKOPOQQONSNOOOO", 401 | "IOOONJKILLMOPRPJLPVTOOPORQPQQQG_YOKUYNOPOIVUJVZLNLFQLORXPPJ]UXTOHMMRMOQIXL[INNZ", 402 | "IPOOQTSRQRQTOTUONMNOMNOHCHLPOWVTNKKOCSWNMQQQLNIUPXMHHMNVQVNDPKOOOWRWUMLTONPNDD[", 403 | "=OPOPMJGDFPPPPRUUTRWVSRWXVUQOTT[`KLKICSVFRTP]@R^RPI[JESWLSUNM`YMVYNIZQKCIMNJRNJ", 404 | "JQPTZ`b`^]QKJO]_[PG=:=DHMNPOPNNVPTTSQNNNTPTMXMOSJLHVPPHSOPOWMNSSMLMLKOPQONPMNQP", 405 | "SPPPOORPQPC;=?CFBB@JMSZTPPPPQLMMMUNPSRVGRJPPMMQLGJKDONOVQLIGPOPRMKIMXKPMQPJLMPN"]; 406 | 407 | fwdWIP = "KTPROTJGIPNIPTUANNURNQHLPSOQQUJMROSSLRRPOPPOPKKZIR"; 408 | revWIP = "SQWSRTGILQWKUKTRORNEQOTUWQNVKPHORWTMMPXSYZPORQRSPM"; 409 | 410 | fwdWFP = "OMQNOXQ QNPNOKNWRNNOOQUGMXOOOL@ROPKOFOQPOPORRQRQRN"; 411 | revWFP = "OOMQVOWPRPMPKQKNPOMTOTJOeNNdSOWSOMMRFPOPL[QQXQOROS"; 412 | 413 | fwdWOP = "TNQNNKMONQPOJKK]RJQSVMSNIGNONMAOOOPQITPROPNQOTPRNM"; 414 | revWOP = "UGNOVORNNPPR_OQUNRRRNOOOMOOLSMMPTMMM.QKUNVQIMSOZPJ"; 415 | 416 | softW = ["TRQMOPAPOVGJqJ NTMMPJOIJZWNOGFIN?PZYP>W:PgPNOJ_NLEO]OJPeOWBLDHRQSYLP}OJV=QXNLSLTO?YJKRHKOMRSLRSQN(TL", 417 | "SNOYZ=jZGSRMMREROLKQPJLLYLNOTRQQNPEYOwRQ^>PXVHODKNJHHOGWKR[KPMQDMDPE LJPNOLLEQRUQUMmHSPHRSNLWQJ_JMTK", 418 | "SNLVRPLYNRR?RKXSLVPFSIROOROPQNONSLNKLLOTANXZVRJDTJLQMSP[QOPTJOMKSSMKSNVROMOKMQSSIOQOURNNMSTKJKRSLSLP", 419 | "QQOOOONPPOONQOMQOPOPNOQNOOPOPONQNPQNNNOPPPONPOOOOOPPPPQPPNOPPNPOQPPPSNNQPPOPPNPPPOOOONNOOOOOOPPPPOON", 420 | "PQOOOPNOPOOOQOMRQPOPNPPMPPPPOOOPOPQONONOPPONPPOOONPPPPQOQONPPOOPPPPPSONPPPOOONPPPNOOOOONOPOOPPPPOOOO", 421 | "PRPPNPOOSPNNOQNQMPRQOQRNOPSPNOOPNOQLNONPOOPSPPMPOSSRQNOLPOMNPNPOSPQRRNMQOTQORPMOONPPRNONNNNONQPPMNQP", 422 | "OSQLMQOMMMNKNNNRRPRQOQRNPRNRPKNSOTQLQOKOLOOPLPTQNROQOOPOQOQMQNPPOPRSRNOORSPKSPMNMLQPONNNONUPKSPPNQNK", 423 | "MPVLMQQKPPUHNOONLVKNOSWOONMPLOOKLMPURPUOPQLKQONHVPSTQPJMOQJLNSNXPPXTQPKTNUQSUOLPKONPQPPLLOVSORQQLRMI", 424 | "LPHROWSRUMKJTWUOVKOUBX][NaFMNOIMIQN^LLTLLJQWCKQRWP=C^=S@O^iTe^HU`FDSTERVOPQNINPZL[M_WMNbJXAJIKNCNQZT", 425 | "XPUVQMMQKQOJPZRSBWPWVDTPLZFJVKNPJIOILJNRZUMPOTHDLQNUQOKWQTIMKQLMGRQDTKRVPORQQPQUSRPQTNOOP`NOTOROJQOP", 426 | "PRDPJLHRLVLYNNRSTSVIHMDMTLLRRELQ]DTSQKKTHHLIHXVXMYJQKSH`NTPPHOLIGSMITMKPOOQPPQNNROLSQUO[MLTQMRRMJRSU", 427 | "OQTNKQOKPPNIMQMOORVMKSUNNTNKPLOINORPQRRNWKWMOPTQSXJIUOMNQPMNQROQSQURRRFRQOQMGOPQNLPNROMSLTWOMSPPOUXO", 428 | "QPVQRPQLONJUEOMUTQOQMWNNMPPPRHNKMQRTQONRSOJNXOSOSSOHLONKPMLPRHNQMNTOTPTQMUQRPPPQKPRMOSNSKNNNMMQNPNYL", 429 | "KQKSOMYVPUMTQTTDRQJSEOGNRQNKQQORJRLTQNRLRVPOPLMRPNQOTERBLCEERLH]JTVQDNNUR^Ph_OTO[TKPWTQMR_KTPQMHMNR]", 430 | "NTSLTPSULNLHTQRTLRNRKMPQMQLPQLQQTRLNONPGNRPPOMLOQMRCSTVFOINNTELPQP[TFS^LLXPTKOQPCYLINVOOGKRSNPRQMIRG", 431 | "NTLNPPWSSSLNPQP^ETMRIMJWRMQRRMOPNPHQOOSMPRQGODQOPP^WTHPQU>Z^RJFUAVRJAXVQKVQ@SIPOW[NRYTMZH[RRORQKYPHU", 432 | "LWYNNPLLSOQOVYQNOOJRHPKPPNSLKSQPMMKVQMROLMIIWSTPVSLPULPOQQKNQVPQNPLQQPRQNMPLKPQWVOOJTENOSNLLXNOJMU]L", 433 | "XMOKPQOLJPRPNQOQOSSVQLUMPNKMPOMRMUNOQRUPSQRKGTNHOPTROPNQRPNVQRPGOOCORNPMLQRIGPFNPNORTOMOQNGPKOOJSJXT", 434 | "NMIMKNONQNOSKJQVSJNORWTMQHSSOQOPPLQPPNLOGHXMNPRQRXPSLRRQRLQRF@NLFOOFUNNPRSOLRQNLLVLLVQPKJONPKOPPOPGQ", 435 | "QSRMMPNPTNMMLMONRQLOJNRNTNSQMOPRNNQPMONNKQROVOPQOSUTPROLQNQPSPQLLNRYONSNJKORPQUONNNPRNNMJLMPMLPNWKJQ", 436 | "OTONNOLPSMMKMMOPQMJNLRQNTNTPNPPSPPSOONNKLNPNSNRPQUPRPPQPPLPNROPMWUMSQMLMOSPKSOOMNOLPPPOOQMMOIQPTLMUW", 437 | "NSTMMPLMMPNONRORKRJRPUMNOONQRKPPQPQSQMPPNNKJNNRNRMOPQPROPLOIQRPRQPSLRXLMQLQISPKOQNKPSNPNPPRNLQOSJJTL", 438 | "SRPPLOPOPNPIMLNPOSRLMOROLSSOMOPPNSQLOPMOKNQUTOOLRQSPSOPNPNMNPMOHSSQTROIPLWOPTQJNMNKQQNPOSMMQRTPNMMTS", 439 | "TRSNNPQOKNQPNRMQQRRRMPTNJPJLSQOQMUOUPQTOSOSNKQMNNOSPROOKPPKJOLPHRTUSSNIPLYPMUQLPNOLQQNOPTLOQOTQOOKXP", 440 | "ORQMLQNNTPNONMORQLIMNPNNRMPQMNOSNQRQPOLPJOQLLQQNPSNNSOQKQNNSROPPOPONRMRRNMQPNORQUMOMSMONPMPOQOPNLQSO", 441 | "KRKMNOOMRNQMPQOQPSTRNRQMMNSPMOOPKPPSOOTOKPSLJSLOPMQPPPNOQMNLRNOPTSPSQOLRORPMTOTMOMOOTNPSSOJNLRPRMOWS", 442 | "TSRKMQNQLPNFQLORQTOPOPUNQSQLTPOOMROLNPMPKQQXMPOKPLRSPPPQPMPTROQHLOJRQNPOPUPNPOLMNMSONNOQLMJOLOOMMOSW", 443 | "KTHJIMMOXQSITSRYAURHPGIQLPTNPOOLLLQEOIMQVHX^WHLWNXMPMLPWMTLSEKLKTULLWPVROPMMHOQSNSNRVWRMKSPOKMQLKRLW", 444 | "H[GSKMOP_QUNI]QQSVXSHMFOMLNMPMPWRLRSNONRQSMTXYKWTYKOMMMUNQNQHLPNSQPMVNSVQPMRPORUWQPPURRNNOSPJRPIMQKU", 445 | "NRTLNPMLOMMISSOQOPMQPSOONRJNWMPOQMRSQMPKRMNOSORPQMPOPPPORMPRPVQRQMSPPXOOVJQJLQLRMKQOSOOPRPVPPPPPULJM", 446 | "QUSOLONQJNVJUQNPKQZQOPOQOWMOPIOLTONCQOOQSRHGPNRSMOJRJUMOPPQZPYPISJVRMTWKYUPHSOIPFQLSXPOVHRZPFNOQIMUK", 447 | "KQJMKOONVMNOQSNTLOPRJQLNRPVNJKPNPPRLPNLPOMSQRNQROSIIRRPMQNLORQOMRPTUQRPNNXQVNPNQKPPNQPPRJOQPNNOQLMRM", 448 | "LRWJPPM]KKMKKOPNTSKNONXLRRIRRSPRRPRQMMMMEQPTPTUVRPKPUPNJRMOUROONNNOURKXTKMQLKNWP[NPPYNLOKJMNMMOIGPPM", 449 | "QRQOOQNMLPRNNROPNQPROMQNNPMNQNOPMMPMNNQQQSQMOSLLMQROSRPOPMNMROPQPOTRSOOPOSQTQPLONNMNNOONOOLPORQRMLTP", 450 | "OQ[NNQOITNPNJRMNQPLSRULRSNTNKJQPOPOVQQPNFSGFNTSRRPLQUPVLPNRLPSSSMKRUSNHPUWQKHPGH_LTPHTPQGNROSXPPYJOJ", 451 | "NPQONQQOIOQTSKLNUKSJOLNPNNUTOTPRRNNOQQQNTPNNPMONKERQONOSNNUNTOQKYVMUQJHKL[PHVOYNHOMQGQNLULNNIVOUOMXR", 452 | "UOSTPONLSOSNQROQQTNVPRSPMRHOSQPRLQOPOQTQTTQOMTNNNPXNMMSORMOMPWMNTRYXQMRSNQPJQQWQLGQPWMOMW^RRRIOHXOHT", 453 | "MMOKNQOLPPPOSHLPTQLLNNKPPL^RMSQOPNQMOQQOMRPPQLLOLJSSMLQRQIMUTRQHUODVPKPILRNUJOIJOKPQJLPOTTJOVPPKXMK_", 454 | "PNNONPRMLOQTRHNPROQQPMMPJLTQPSPRQRMTPOPONQSNNRKOMGYPQPPFOSNHPMOKXQUUXJXRLWPTQQPLFNVTVMOLYIQUNLOE`RQF", 455 | "NNOLOQQNMNPTQKLQSNRNOMMOMMTQMQONOJMSOOPMNLROOQLMNKOSPOSFOMJRPUPLWRTUWNbNOQPSJQBVPLVRQNMSPNNLOSQEEPYJ", 456 | "WQUUOONOPOQOOQNRPSLROUQOOQHPQOPQLRROOQSQQVPNKTMOLPSQLNRPOLNHTPOUSMUUSOOPPaOGUQUILPOPKSPLSKROSQRXKMSV", 457 | "PKMOOQPLHRPSRNKSOITJMOPOONTTPOOOOOOPPOQMONRMRTLKMIVIIPYSPKMXQ>QMSSSMQTSNSIRVVP`PKQMMKQNUPJCMKMPWXL]G", 458 | "TNIMPNOBOKRYKGWRNEQMTMISKHWTOUNKNFMJOLJQULYDSPTHMSNGHL_RLOOOEYNCMJRBRLKLPJNFSQQNKAOOfPPMQWSILFOLLYFW", 459 | "LSSVMNMHMQKRNOPQQFOULQQOOLRSMMOSOLRQPOORGOLHSQTMTNKPLRVPOOMLNOOTOMKORNQOPNOMOPQRSLMLHPQLLMLOPPQQNPQQ", 460 | "OOOPNPPOMNPRRMMSRKSNNMQOMLORPQNONLORPQPPRMRNNQLKNLLORPSJQNPERSNQSLPTTSHSPVPOIPMNWNWPYLOSVQXQMTPVVKML", 461 | "PJOQPNOLRPQRPLMRPPONQMOPMKUPNSQRPNONOOOOPQSKQQMJOKTSLPQLQLTINGOXDTQZTRRQNYNOQPSTIIKNEORMUR]RQVQHZNIZ", 462 | "PSQMLQRMVNQMRNPOTOPMRQOOKMRPMMNQNLPQORPPLNPKMRHJWKKPSOPSPNMERKQEOSRXTRINOGPRBPIGYQROGSNPGOGLSMO_LILK", 463 | "SRNPOQONUORQSMMQULOKQSMOKPRRMLNPOMRNNQPPKMPKFRLMUKIVMNSXQRJJSCS[KPRTSaTRSJQFRQIKBOTQLMMXINFKUVQTPPPL", 464 | "URTSMONISOPMORLRUVMXLTTOMRGPTPPRMPPSORVPPSPNLVOOMRRQLMRWROLRRRQDPLFTPKPMLRPWHQHGULMPKOORUXJNUPPKXKMY", 465 | "MQOPOPQLJPQRNOMPQMPNOJNPMMUSMPPLPLORMPQPQQPOQPLLLKRINQSOPLMSTUNHNLPVRJYLJHP[JP[MTONPTNPPGNNMLLPOHKVK", 466 | "TNTROQPNOOOLMOMQSNMTOUVOSQLNNQPQMUOHPQPPTTPMNPQLLPTQLOOOPNOMQQS]RUMVQRLLJRO]QOMQPMKSDLPNOONQXTPSUKIX", 467 | "NORLLPOKFPPTNLMRRLPOPLLNMLRRPQOQPOPQOQPNMRPPOPNLLIUQMLQMONRMXTRURCPTONQNPHRHOPJMUQXSIPNUCOJNIRPU[IOI", 468 | "NSNPNQSNYOMJPMOOGOYPTRNRJTQROIQMPRPQLSMPGSSXYTLON[VQNPWPNOLISMPTUTPVRMVQK[OLXQSMKPRRJMQPWMNOORPULNVJ", 469 | "LOMLNORMKJQWUJPTUGPQWTIQNIPVQUPRK^RJQRPPBQMKKOTNPMRXKMVTOTSUYUPRYLNKVMJOPCPUOQRXGJTRQOPJXUNO^QOOFUTR", 470 | "QLKKQONMLNRQQJNSTSQPOLQPNMKSPPNOQRPJOOTOSSRKDQMIMLSSMQTUQLOKLFOPKVNVQPQMMPORPOUIPMLONROMPKJOLQQWWKFV", 471 | "QQPOOQPNPPMLMJKRNNSLMOTMTSMTLMNHNRQMOMLNJOLPJQSQOKQSSQSLROLQQOPTOSQTQPNLPIPVNQMSUONNWQNQLOHNPMPWJPMN", 472 | "KPTCQRNFINSOLINLQKOWPJSOXHMYNPNRLTPLQSNOWSRJIJQREMPSLUQOQRKLLOSSPRTSOQJRPFSXQQGNWPQPVMORIOQKRQPWJPPK", 473 | "OQKOKONOUNOOMMOQRMPOLPKNQNPROMNSSNSROPMQKOPLOSORRUNMQQRLQNOJSQPRRNORQVLQTMPMIPNNQNSORLPRRQTPNPOSRLLM", 474 | "SPOMJQPMRQLMNLJQNJVEPNPPRPMUKMNLHTQLPPIQLJKQIQRYJWLQPPTKPSKQRVQROMNOSRMPRLPTSPOTQNROTIOTVOSNZRPMLPSM", 475 | "PRQOLOMNRQNPMNOQQPKNKNRPRNRQNMOQQMQPONNQOSOMPPNQOTRPQPRMQNONRPONQQRUTOOOMLPOLOROOOQQPMOLRONPPNOMSMNK", 476 | "LNPVTPOOHNVRQJQPQVELOJQOQQSOPQPROIPMOLNRRTOVWMJLOINWTQLURKKNUVNMLSOLPMOPTUQWRQSTNQPPUIMKXXLOXOOQOPVR", 477 | "QTLNMQNNRPNMNRIRMKRMNNPLSRMRMNNPNSQMPNMOMNQQIPSSPROOQONKSNNLOKOUMORMPRNPRZQQQPNPWLUMPSNOMRRPNSPRULKJ", 478 | "PRJVUOLQGPSUTPQTUFGPJLRMPIPUMTMXQPTJPLQSHIFLWKYNNIKQPRLWPUUPHOOLMSLLSLPPSLOOOQPNPXNPROQJLOSQNPQRIRIP", 479 | "PSQNMONOONOJPPNRNQNPPPRNOQONSPNOPRQNONNOQPPQQPROSPNOQOOPRPOPQLPNQNQPRPSNQQRPMOPOPNQNPONPMNQPRPOONMPN", 480 | "OQOOOPNOOOONQQLROPPPNOPNOOOPOOPPPQPONOPPPQPOPPPONOOPOOQPPONPPNPPPQOOSOOPPPPOPPPOONPOONOOPOPPOPPQONON", 481 | "OQPOOONPOOONOPMQPQOPNOPNOPPOPOOPOQQOOONOQPOOOPONOOOPOPQPPNNPONPOPPPPRNOPPOQOPOPOPNOPOOOOOOOPPPPPOOOO", 482 | "?TXKPPSPVMQPTRVAANUQ^SBTRMRIITUOSLNNRSOKOPNBHPSSTUMQSRPPMSTWQVO[NLGL=JOTQPM4POJMRYIIMWQ@LKNPG;OMLeSJ", 483 | "HIFQTRRSOPPQOMLIONSKMQaROQZOPLQGVRNLQTLMWQKORNOJLJHRRNMORORSJKPEWQ@RNRMKYPPUOONMDRMPIRMRVILQMJOOHPCL", 484 | "RM^TSLSTRPSUQTWOKLILWKKSPQFOSQRFQKMRPNQQSSBJMNPMSO^CMOJQMQWYKTNIKONLALRSNALT[O^RMKJMBNROVQfQbWOGaNNO", 485 | "QMWSVNLRLPOWTUZGGMNNYQJPOTFSVUPLQPPUOJNQROLINORMUPTESMKOMYVDUKOWUGGBBLLNPLN7VMOMRQOFTNSXXP9LLQOa_IEQ", 486 | "NJXRSORSIOOLSO]BNLROUPNPRPBPPSRVPVKbQSSPPHSIGIXLQKKOQNKSNZRPNTMEOHHM2KROMPOPGL[LOWnLMMQOIM[QCSPHUYDN", 487 | "QHMPQPRMVQPPFL]HR[WTZPMVISRNPQRLTPNEPTQMZMNcTTKMSVEGLPIHLMNETeSS[LMOOSTNJIPKNORQMUTPPIPIWKPQaPQJI]YP", 488 | "SKURNNPSJNSSRWUFRQPNTPIMQQSOUUOSUKNPOLQLSQHUTWQOSOTMUQGXLPUENIOVWRVTEIJROCOdTNRIKQFOLRPFPOCQFUONV[SR", 489 | "EGKPSQPPQQNPMJMIFQUHSV]TPPUMNRRSSRSRPSIVORQMO^TMNIKQKPLMNWUWPLMWL[TNKNJO[QOGSMSO[PFKHYNHSIWRGHNHJJZO", 490 | "BKOIOOIPMNPU=K^PCQSFSUcSJUMAUSULTSQVQILSRHWWXETsSSYPSVJJMPNIARPK8NH?VWGJOOLJROORSNQIQIT@`QIOPSNNUXQI", 491 | "JQQZRPLREOQTDOOPPDMYKRZOOQNRORQZUHRNMQMPRQPXXSSdPSKONQMLPQPNKNQTJOMNUNMMRPOPRQPRRMPMFOPLUMOROPQQJNPL", 492 | "LLPVQOPWGNKQNNOLMRILPNXOLNPRPMPJXSKONPOTSPLOUSOEIMTJPNNOPNVONXPTIPORURJO_DQJKNOLIN`PGSNTMNaRNUNNWIJI", 493 | "LIGS[PJ^VNL^NMfPGQFA[TOQINKSNRQ@T^RIPIJJQJIDTONATTLTRQNMMMUPCHN^CCM8QR^OPRMPWPPURGIIMYSO9GBQMYOJPWIX", 494 | "VMMKPPNIMLOXJLZFXOQPIOETMMVSPZXEMPRXSOQ]OSQTOKTSNUNLQTJRJZL`YcSARCSBTEBDPOJOGNJILTVRGFVU[V6PK>MUORJS", 495 | "VGJHTOSTVQK_GN[JLPMLIM;RMC]BYYTCLMLLSNNXKONWQOQ`KQPMKNPMM][POIMOIVKCEPLNROLPZNGG]QCKQRPSVKZON?MGPJ]P", 496 | "NN[MNNSOPMPOQPYHFPUM[TNSSRFJSNTRQSLPSRPMPRLMK>RQQRIJNPOMKWNQKYNBRN?K6TOVSWLYUMANPT?JOMQSUPGP]CNGLPEN", 497 | "RHIYTOSPRQSUJPPKZQMTOMBQPNWOKQQZQMKMPRQMQVPXLaQZKMNQNPJNRORUPUQGUQHVNRPOTPPQHOGLHMNQKPMLRMMOWENLLQIN", 498 | "RPSOMPQMRNPQROMOJORNQRMPOOMOSOOMOQPQPNMQPPNMNHMNLPQONPOQOMQBOMPZQWWQROKQNEOYSPORKRPPEJQLTNJO`EQ_IHNO", 499 | "KDCOUNRTWQSWSZROSOLH]KIRJOUIFRTOPSJRPLPJIEPUVM@`MPKROJJHKUU[[NORQGULVQTIOIKaPNa[ORMQQORcVQ`Pd_OVKVGR", 500 | "UTOTSPURONOPVVRGKJRMQQLSXS]QQZRLSQIKPTQISKMX]IOVNTSONLNRKQSKIOOQYQUN@RSMGIO=bORQ?RYPKQQ^ROaPKXRKBcTI", 501 | "ZBDOWMS]RNQOKTeGPQV``Q]PBPOTORPJNOM@MRRIRQLT=QIKQK?KHVLONGYZN@QNSIU>XXKQVNMHROYOMOJQLWQGIOXPD]MQOP6U", 502 | "SCGPWNIQHSSSIXTNPPUMPSJOQSFJURPTSROPSLOXMORTALTXKLWUJTOMONNL>FOX>UHTISLRNMNILOZPNO?MKVPOWIGOD8NHTOQ^", 503 | "PLGKVPVVXPGMVXMOMORONQRPQVGKSQQ?MXLKNQQKTLKWHCLNOOQZYIPLQSOZQQPUGOTMITTCKEPZGPOYTNULHTMRGLQOYAOZN[EM", 504 | "PPLUNPNODMXQTINJVOSOSSNQTKODNIPZTQOLPTQWSUXOSEMTLNVRGWNRLLMTGTTRMMVOIWKNONP[LMGLYRTTNNQNBOXPQJMPR`RO", 505 | "OOHMLOOQYOINQTMPLURSNRGORPRKLKPLOUOLPNMROOQVZLLQKVQKLTOPNPSHQTPVLLPRP_NOVKNOJPJLNOWNKMQYPQZOOQOS]LIL", 506 | "SRMVVOQTVQJIXZQLROTULNMPQVMTLPQTOMPNNUNKTQQVK[QRROSNOILOPTF]MQNOJLQOARWNVKQZZOKS`NYJTONKLKPRQ[QNP^LH", 507 | "CRQMLOQQXPJQTQMNPQOSMLIPSJWNNQRONQPHNONQRWMUQLJRPSTRTSNOOOQVQUPKTLROLKPIWHNLJPYMRQMOHOQLMOYNKRMTXRMO", 508 | "VM]LMONOMPROKGOQXWIXTTTORLEIOOMOWIQKSOQMWPOJVOTGYTMRMQOUQPONOTMROSPNUNQSQRPVPPPORWOPTMOKRUPSROPJNQPP", 509 | "LPLWVNMKMRVQNMQSTQGUMHUNRNNLPQMYRHPNNNPTVMVTTMJJSINNQTIURSSRJLPLJVOMRMPOOPQQLPQOOVOQUOPPMPUONROQMPLO", 510 | "NPNRMOONHSSSMNOORGIKMNUMPNSRNMLSSDOUPNMRKKGOQPTOOILGMQKORLOSRENPMRPNURPUPTRRKPTRKUTLQSNVNLQSHNPLLMWM", 511 | "OQPOOPNQNPOOOOMQQRONNOQMOOOONPNOOQQPOPPPPPPOQPNPOOOQNOQNQNMPPOPOPOOQROOPPPOONOQOPNPOONNNNQOPPPPPNOPO"]; 512 | softB = "}RNMMMONYOOMOPNPMPKMMMNNNNOGJMPMPNOOLLMONPKKMKOPNNNPNOMNPMNMNOLMMMURORZTPUSMPRNQSRMRTVRPRNRKMMNM"; 513 | 514 | -------------------------------------------------------------------------------- /ocropy/clstm2js.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import h5py 4 | import numpy 5 | import json 6 | import argparse 7 | 8 | parser = argparse.ArgumentParser("apply an RNN recognizer") 9 | parser.add_argument("file") 10 | 11 | parser.add_argument("-o","--out",default="params.js", 12 | help="Filename to export the parameters") 13 | 14 | parser.add_argument("-d","--dense",action="store_true", 15 | help="Dense file format") 16 | 17 | args = parser.parse_args() 18 | 19 | f = h5py.File(args.file, "r") 20 | 21 | js = open(args.out, 'w') 22 | 23 | dictionary = [] 24 | gamut = 4.0 25 | 26 | for i in range(32, 126): 27 | if i in [92, 34, 39, 60]: 28 | continue 29 | dictionary += chr(i) 30 | 31 | print len(dictionary) 32 | 33 | def encode(array): 34 | if isinstance(array[0], list): 35 | return [encode(el) for el in array] 36 | 37 | return ''.join([dictionary[int(round((float(len(dictionary) - 1)) * (max(-gamut, min(gamut, el)) + gamut) / (2.0 * gamut)))] for el in array]) 38 | 39 | def format(obj): 40 | if args.dense != True: 41 | return json.dumps(obj) 42 | 43 | return json.dumps(encode(obj), separators=(',\n',':')) 44 | 45 | js.write('encGamut = %f;\n\n' % gamut) 46 | 47 | for w in "WGI WGF WGO WCI".split(): 48 | js.write("fwd%s = %s;\n" % (w, format(f['.bidilstm.0.parallel.0.lstm.' + w][:].tolist()))) 49 | js.write("rev%s = %s;\n\n" % (w, format(f['.bidilstm.0.parallel.1.reversed.0.lstm.' + w][:].tolist()))) 50 | 51 | for w in "WIP WFP WOP".split(): 52 | js.write("fwd%s = %s;\n" % (w, format(f['.bidilstm.0.parallel.0.lstm.' + w][:][:,0].tolist()))) 53 | js.write("rev%s = %s;\n\n" % (w, format(f['.bidilstm.0.parallel.1.reversed.0.lstm.' + w][:,0].tolist()))) 54 | 55 | 56 | js.write("softW = %s;\n" % format(f['.bidilstm.1.softmax.W'][:].tolist())) 57 | js.write("softB = %s;\n\n" % format(f['.bidilstm.1.softmax.w'][:,0].tolist())) -------------------------------------------------------------------------------- /ocropy/lrpred: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import traceback 4 | import codecs 5 | from pylab import * 6 | import os.path 7 | import ocrolib 8 | import argparse 9 | import matplotlib 10 | from multiprocessing import Pool 11 | from ocrolib import edist 12 | from collections import Counter 13 | from ocrolib import minilstm as lstm 14 | # from ocrolib import lstm 15 | from scipy.ndimage import measurements 16 | 17 | parser = argparse.ArgumentParser("apply an RNN recognizer") 18 | 19 | # error checking 20 | parser.add_argument('-n','--nocheck',action="store_true", 21 | help="disable error checking on inputs") 22 | 23 | # line dewarping (usually contained in model) 24 | parser.add_argument("-e","--nolineest",action="store_true", 25 | help="target line height (overrides recognizer)") 26 | # parser.add_argument("-l","--height",default=-1,type=int, 27 | # help="target line height (overrides recognizer)") 28 | 29 | # recognition 30 | parser.add_argument('-m','--model',default="en-default.pyrnn.gz", 31 | help="line recognition model") 32 | 33 | parser.add_argument("--lineheight",type=int,default=48, 34 | help="# LSTM state units") 35 | parser.add_argument("-S","--hiddensize",type=int,default=100, 36 | help="# LSTM state units") 37 | 38 | parser.add_argument("-p","--pad",default=16,type=int, 39 | help="extra blank padding to the left and right of text line") 40 | parser.add_argument('-N',"--nonormalize",action="store_true", 41 | help="don't normalize the textual output from the recognizer") 42 | parser.add_argument('--llocs',action="store_true", 43 | help="output LSTM locations for characters") 44 | parser.add_argument('--alocs',action="store_true", 45 | help="output aligned LSTM locations for characters") 46 | 47 | # error measures 48 | parser.add_argument("-r","--estrate",action="store_true", 49 | help="estimate error rate only") 50 | parser.add_argument("-c","--estconf",type=int,default=20, 51 | help="estimate confusion matrix") 52 | parser.add_argument("-C","--compare",default="nospace", 53 | help="string comparison used for error rate estimate") 54 | parser.add_argument("--context",default=0,type=int, 55 | help="context for error reporting") 56 | 57 | # debugging 58 | parser.add_argument('-s','--show',default=-1,type=float, 59 | help="if >0, shows recognition output in a window and waits this many seconds") 60 | # parser.add_argument('-S','--save',default=None, 61 | # help="save debugging output image as PNG (for bug reporting)") 62 | parser.add_argument("-q","--quiet",action="store_true", 63 | help="turn off most output") 64 | 65 | # input files 66 | parser.add_argument("files",nargs="+", 67 | help="input files; glob and @ expansion performed") 68 | args = parser.parse_args() 69 | 70 | def check_line(image): 71 | if len(image.shape)==3: return "input image is color image %s"%(image.shape,) 72 | if mean(image)200: return "image too tall for a text line %s"%(image.shape,) 76 | if w<1.5*h: return "line too short %s"%(image.shape,) 77 | if w>4000: return "line too long %s"%(image.shape,) 78 | ratio = w*1.0/h 79 | _,ncomps = measurements.label(image>mean(image)) 80 | lo = int(0.5*ratio+0.5) 81 | hi = int(4*ratio)+1 82 | if ncomps=%d)"%(ncomps,lo) 83 | if ncomps>hi*ratio: return "too many connected components (got %d, wanted <=%d)"%(ncomps,hi) 84 | return None 85 | 86 | # compute the list of files to be classified 87 | 88 | if len(args.files)<1: 89 | parser.print_help() 90 | sys.exit(0) 91 | 92 | print 93 | print "#"*10,(" ".join(sys.argv))[:60] 94 | print 95 | 96 | 97 | inputs = ocrolib.glob_all(args.files) 98 | if not args.quiet: print "#inputs",len(inputs) 99 | 100 | import h5py 101 | import numpy 102 | 103 | f = h5py.File("models/6-2000.clstm", "r") 104 | 105 | # load the network used for classification 106 | 107 | charset = sorted(list(set(list(lstm.ascii_labels) + list(ocrolib.chars.default)))) 108 | charset = [""," ","~",]+[c for c in charset if c not in [" ","~"]] 109 | codec = lstm.Codec().init(charset) 110 | 111 | network = lstm.SeqRecognizer(args.lineheight, args.hiddensize, 112 | codec = codec, 113 | normalize = lstm.normalize_nfkc) 114 | 115 | parallel, softmax = network.lstm.nets 116 | nornet, rev = parallel.nets 117 | revnet = rev.net 118 | 119 | js = open('images.js', 'w') 120 | 121 | weights = "WGI WGF WGO WCI WIP WFP WOP" 122 | import json 123 | for w in weights.split(): 124 | # js.write("fwd%s = %s;\n" % (w, json.dumps(f['.bidilstm.0.parallel.0.lstm.' + w][:].tolist()))) 125 | # js.write("rev%s = %s;\n\n" % (w, json.dumps(f['.bidilstm.0.parallel.1.reversed.0.lstm.' + w][:].tolist()))) 126 | 127 | # there's a difference between (50, 1) and (50,) in terms of np array shape 128 | setattr(nornet, w, f['.bidilstm.0.parallel.0.lstm.' + w][:].reshape(getattr(nornet, w).shape)) 129 | setattr(revnet, w, f['.bidilstm.0.parallel.1.reversed.0.lstm.' + w][:].reshape(getattr(nornet, w).shape)) 130 | 131 | # js.write("softW = %s;\n" % json.dumps(f['.bidilstm.1.softmax.W'][:].tolist())) 132 | # js.write("softB = %s;\n\n" % json.dumps(f['.bidilstm.1.softmax.w'][:].tolist())) 133 | # js.close() 134 | 135 | # the first row is biases and the rest are weights 136 | softmax.W2 = numpy.hstack((f['.bidilstm.1.softmax.w'][:], f['.bidilstm.1.softmax.W'][:])) 137 | 138 | # ocrolib.save_object("from-clstm.pyrnn",network) 139 | 140 | 141 | # network = ocrolib.load_object(args.model,verbose=1) 142 | # for x in network.walk(): x.postLoad() 143 | # for x in network.walk(): 144 | # if isinstance(x,lstm.LSTM): 145 | # x.allocate(5000) 146 | 147 | 148 | # get the line normalizer from the loaded network, or optionally 149 | # let the user override it (this is not very useful) 150 | 151 | # lnorm = getattr(network,"lnorm",None) 152 | 153 | # if args.height>0: 154 | # lnorm.setHeight(args.height) 155 | from ocrolib import lineest 156 | lnorm = lineest.CenterNormalizer(args.lineheight) 157 | 158 | 159 | from pylab import amax, vstack, zeros 160 | def prepare_line(line,pad=16): 161 | """Prepare a line for recognition; this inverts it, transposes 162 | it, and pads it.""" 163 | line = line * 1.0/amax(line) 164 | line = amax(line)-line 165 | line = line.T 166 | if pad>0: 167 | w = line.shape[1] 168 | line = vstack([zeros((pad,w)),line,zeros((pad,w))]) 169 | return line 170 | 171 | # process one file 172 | 173 | def process1(arg): 174 | (trial,fname) = arg 175 | base,_ = ocrolib.allsplitext(fname) 176 | line = ocrolib.read_image_gray(fname) 177 | raw_line = line.copy() 178 | if prod(line.shape)==0: return None 179 | if amax(line)==amin(line): return None 180 | 181 | if not args.nocheck: 182 | check = check_line(amax(line)-line) 183 | if check is not None: 184 | print fname,"SKIPPED",check,"(use -n to disable this check)" 185 | return (0,[],0,trial,fname) 186 | 187 | if not args.nolineest: 188 | assert "dew.png" not in fname,"don't dewarp dewarped images" 189 | temp = amax(line)-line 190 | temp = temp*1.0/amax(temp) 191 | lnorm.measure(temp) 192 | line = lnorm.normalize(line,cval=amax(line)) 193 | else: 194 | assert "dew.png" in fname,"only apply to dewarped images" 195 | 196 | line = prepare_line(line,args.pad) 197 | fb = os.path.basename(fname).split(".")[0] 198 | js.write("img%s = %s;\n" % (fb, json.dumps(line.tolist()))) 199 | 200 | pred = network.predictString(line) 201 | # if fb == "01000a": 202 | # js.write("out%s = %s;\n" % (fb, json.dumps(network.outputs.tolist()))) 203 | 204 | # if args.llocs: 205 | # # output recognized LSTM locations of characters 206 | # result = lstm.translate_back(network.outputs,pos=1) 207 | # scale = len(raw_line.T)*1.0/(len(network.outputs)-2*args.pad) 208 | # #ion(); imshow(raw_line,cmap=cm.gray) 209 | # with codecs.open(base+".llocs","w","utf-8") as locs: 210 | # for r,c in result: 211 | # c = network.l2s([c]) 212 | # r = (r-args.pad)*scale 213 | # locs.write("%s\t%.1f\n"%(c,r)) 214 | # #plot([r,r],[0,20],'r' if c==" " else 'b') 215 | # #ginput(1,1000) 216 | 217 | 218 | if not args.nonormalize: 219 | pred = ocrolib.normalize_text(pred) 220 | 221 | if args.estrate: 222 | try: 223 | gt = ocrolib.read_text(base+".gt.txt") 224 | except: 225 | return (0,[],0,trial,fname) 226 | pred0 = ocrolib.project_text(pred,args.compare) 227 | gt0 = ocrolib.project_text(gt,args.compare) 228 | if args.estconf>0: 229 | err,conf = edist.xlevenshtein(pred0,gt0,context=args.context) 230 | else: 231 | err = edist.xlevenshtein(pred0,gt0) 232 | conf = [] 233 | if not args.quiet: 234 | print "%3d %3d"%(err,len(gt)),fname,":",pred 235 | sys.stdout.flush() 236 | return (err,conf,len(gt0),trial,fname) 237 | 238 | if not args.quiet: 239 | print fname,":",pred 240 | ocrolib.write_text(base+".txt",pred) 241 | 242 | return None 243 | 244 | result = [] 245 | for trial,fname in enumerate(inputs): 246 | result.append(process1((trial,fname))) 247 | 248 | # result = [x for x in result if x is not None] 249 | 250 | # confusions = [] 251 | 252 | # if args.estrate: 253 | # terr = 0 254 | # total = 0 255 | # for err,conf,n,trial,fname, in result: 256 | # terr += err 257 | # total += n 258 | # confusions += conf 259 | # print "%.5f"%(terr*1.0/total),terr,total,args.model 260 | # if args.estconf>0: 261 | # print "top",args.estconf,"confusions (count pred gt), comparison:",args.compare 262 | # for ((u,v),n) in Counter(confusions).most_common(args.estconf): 263 | # print "%6d %-4s %-4s"%(n,u,v) 264 | -------------------------------------------------------------------------------- /ocropy/minilstm.py: -------------------------------------------------------------------------------- 1 | # An implementation of LSTM networks, CTC alignment, and related classes. 2 | # 3 | # This code operates on sequences of vectors as inputs, and either outputs 4 | # sequences of vectors, or symbol sequences. Sequences of vectors are 5 | # represented as 2D arrays, with rows representing vectors at different 6 | # time steps. 7 | # 8 | # The code makes liberal use of array programming, including slicing, 9 | # both for speed and for simplicity. All arrays are actual narrays (not matrices), 10 | # so `*` means element-wise multiplication. If you're not familiar with array 11 | # programming style, the numerical code may be hard to follow. If you're familiar with 12 | # MATLAB, here is a side-by-side comparison: http://wiki.scipy.org/NumPy_for_Matlab_Users 13 | # 14 | # Implementations follow the mathematical formulas for forward and backward 15 | # propagation closely; these are not documented in the code, but you can find 16 | # them in the original publications or the slides for the LSTM tutorial 17 | # at http://lstm.iupr.com/ 18 | # 19 | # You can find a simple example of how to use this code in this worksheet: 20 | # https://docs.google.com/a/iupr.com/file/d/0B2VUW2Zx_hNoXzJQemFhOXlLN0U 21 | # More complex usage is illustrated by the ocropus-rpred and ocropus-rtrain 22 | # command line programs. 23 | # 24 | # Author: Thomas M. Breuel 25 | # License: Apache 2.0 26 | 27 | from pylab import rand, zeros, nan, ones, amax, array, dot, exp, tanh, isnan, concatenate, clip, argmax 28 | import unicodedata 29 | 30 | 31 | class Codec: 32 | """Translate between integer codes and characters.""" 33 | def init(self,charset): 34 | charset = sorted(list(set(charset))) 35 | self.code2char = {} 36 | self.char2code = {} 37 | for code,char in enumerate(charset): 38 | self.code2char[code] = char 39 | self.char2code[char] = code 40 | return self 41 | def size(self): 42 | """The total number of codes (use this for the number of output 43 | classes when training a classifier.""" 44 | return len(list(self.code2char.keys())) 45 | def encode(self,s): 46 | "Encode the string `s` into a code sequence." 47 | # tab = self.char2code 48 | dflt = self.char2code["~"] 49 | return [self.char2code.get(c,dflt) for c in s] 50 | def decode(self,l): 51 | "Decode a code sequence into a string." 52 | s = [self.code2char.get(c,"~") for c in l] 53 | return s 54 | 55 | ascii_labels = [""," ","~"] + [unichr(x) for x in range(33,126)] 56 | 57 | 58 | def normalize_nfkc(s): 59 | return unicodedata.normalize('NFKC',s) 60 | 61 | def ascii_codec(): 62 | "Create a codec containing just ASCII characters." 63 | return Codec().init(ascii_labels) 64 | 65 | def ocropus_codec(): 66 | """Create a codec containing ASCII characters plus the default 67 | character set from ocrolib.""" 68 | import ocrolib 69 | base = [c for c in ascii_labels] 70 | base_set = set(base) 71 | extra = [c for c in ocrolib.chars.default if c not in base_set] 72 | return Codec().init(base+extra) 73 | 74 | def getstates_for_display(net): 75 | """Get internal states of an LSTM network for making nice state 76 | plots. This only works on a few types of LSTM.""" 77 | if isinstance(net,LSTM): 78 | return net.state[:net.last_n] 79 | if isinstance(net,Stacked) and isinstance(net.nets[0],LSTM): 80 | return net.nets[0].state[:net.nets[0].last_n] 81 | return None 82 | 83 | 84 | 85 | 86 | initial_range = 0.1 87 | 88 | class RangeError(Exception): 89 | def __init__(self,s=None): 90 | Exception.__init__(self,s) 91 | 92 | def randu(*shape): 93 | """Generate uniformly random values in the range (-1,1). 94 | This can usually be used as a drop-in replacement for `randn` 95 | resulting in a different distribution for weight initializations. 96 | Empirically, the choice of randu/randn can make a difference 97 | for neural network initialization.""" 98 | return 2*rand(*shape)-1 99 | 100 | def sigmoid(x): 101 | """Compute the sigmoid function. 102 | We don't bother with clipping the input value because IEEE floating 103 | point behaves reasonably with this function even for infinities.""" 104 | return 1.0/(1.0+exp(-x)) 105 | 106 | 107 | 108 | class Softmax(): 109 | """A softmax layer, a straightforward implementation 110 | of the softmax equations. Uses 1-augmented vectors.""" 111 | 112 | def __init__(self,Nh,No,initial_range=initial_range,rand=rand): 113 | self.Nh = Nh 114 | self.No = No 115 | self.W2 = zeros((No,Nh+1))*initial_range 116 | 117 | def forward(self, ys): 118 | """Forward propagate activations. This updates the internal 119 | state for a subsequent call to `backward` and returns the output 120 | activations.""" 121 | n = len(ys) 122 | # inputs, zs = [None]*n,[None]*n 123 | zs = [None] * n 124 | 125 | for i in range(n): 126 | # inputs[i] = concatenate([ones(1), ys[i]]) 127 | # print self.W2[:,0] 128 | 129 | temp = dot(self.W2[:,1:], ys[i]) + self.W2[:,0] 130 | # print 'yss', ys[i].shape, self.W2[:,1:].shape, temp.shape 131 | # temp = dot(self.W2, inputs[i]) 132 | # print temp - dot(self.W2[:,1:], ys[i]) - self.W2[:,0] 133 | # print inputs[i].shape, self.W2.shape, temp.shape 134 | # print self.W2[i], i, n 135 | # temp = dot(self.W2[:,1:], ys[i]) + self.W2[:,0] 136 | temp = exp(clip(temp,-100,100)) 137 | temp /= sum(temp) 138 | zs[i] = temp 139 | # self.state = (inputs,zs) 140 | return zs 141 | 142 | # These are the nonlinearities used by the LSTM network. 143 | # We don't bother parameterizing them here 144 | 145 | def ffunc(x): 146 | "Nonlinearity used for gates." 147 | return 1.0/(1.0+exp(-x)) 148 | 149 | def gfunc(x): 150 | "Nonlinearity used for input to state." 151 | return tanh(x) 152 | 153 | # ATTENTION: try linear for hfunc 154 | def hfunc(x): 155 | "Nonlinearity used for output." 156 | return tanh(x) 157 | 158 | 159 | class LSTM(): 160 | """A standard LSTM network. This is a direct implementation of all the forward 161 | and backward propagation formulas, mainly for speed. (There is another, more 162 | abstract implementation as well, but that's significantly slower in Python 163 | due to function call overhead.)""" 164 | def __init__(self,ni,ns,initial=initial_range,maxlen=5000): 165 | na = 1+ni+ns 166 | self.dims = ni,ns,na 167 | self.init_weights(initial) 168 | self.allocate(maxlen) 169 | 170 | def init_weights(self,initial): 171 | "Initialize the weight matrices and derivatives" 172 | ni,ns,na = self.dims 173 | # gate weights 174 | for w in "WGI WGF WGO WCI".split(): 175 | setattr(self,w,randu(ns,na)*initial) 176 | setattr(self,"D"+w,zeros((ns,na))) 177 | # peep weights 178 | for w in "WIP WFP WOP".split(): 179 | setattr(self,w,randu(ns)*initial) 180 | setattr(self,"D"+w,zeros(ns)) 181 | 182 | def allocate(self,n): 183 | """Allocate space for the internal state variables. 184 | `n` is the maximum sequence length that can be processed.""" 185 | ni,ns,na = self.dims 186 | vars = "cix ci gix gi gox go gfx gf" 187 | vars += " state output" 188 | for v in vars.split(): 189 | setattr(self,v,nan*ones((n,ns))) 190 | self.source = nan*ones((n,na)) 191 | # self.sourceerr = nan*ones((n,na)) 192 | 193 | def reset(self,n): 194 | """Reset the contents of the internal state variables to `nan`""" 195 | vars = "cix ci gix gi gox go gfx gf" 196 | vars += " source state output" 197 | 198 | for v in vars.split(): 199 | getattr(self,v)[:,:] = nan 200 | 201 | def forward(self,xs): 202 | """Perform forward propagation of activations and update the 203 | internal state for a subsequent call to `backward`. 204 | Since this performs sequence classification, `xs` is a 2D 205 | array, with rows representing input vectors at each time step. 206 | Returns a 2D array whose rows represent output vectors for 207 | each input vector.""" 208 | ni,ns,na = self.dims 209 | assert len(xs[0])==ni 210 | n = len(xs) 211 | # self.last_n = n 212 | N = len(self.gi) 213 | if n>N: raise ocrolib.RecognitionError("input too large for LSTM model") 214 | self.reset(n) 215 | 216 | # Both functions are a straightforward implementation of the 217 | # LSTM equations. It is possible to abstract this further and 218 | # represent gates and memory cells as individual data structures. 219 | # However, that is several times slower and the extra abstraction 220 | # isn't actually all that useful. 221 | 222 | """Perform forward propagation of activations for a simple LSTM layer.""" 223 | for t in range(n): 224 | prev = zeros(ns) if t == 0 else self.output[t-1] 225 | self.source[t,0] = 1 226 | self.source[t,1:1+ni] = xs[t] 227 | self.source[t,1+ni:] = prev 228 | self.gix[t] = dot(self.WGI,self.source[t]) 229 | self.gfx[t] = dot(self.WGF,self.source[t]) 230 | self.gox[t] = dot(self.WGO,self.source[t]) 231 | self.cix[t] = dot(self.WCI,self.source[t]) 232 | if t > 0: 233 | self.gix[t] += self.WIP * self.state[t-1] 234 | self.gfx[t] += self.WFP * self.state[t-1] 235 | self.gi[t] = ffunc(self.gix[t]) 236 | self.gf[t] = ffunc(self.gfx[t]) 237 | self.ci[t] = gfunc(self.cix[t]) 238 | self.state[t] = self.ci[t] * self.gi[t] 239 | if t > 0: 240 | self.state[t] += self.gf[t] * self.state[t-1] 241 | self.gox[t] += self.WOP * self.state[t] 242 | self.go[t] = ffunc(self.gox[t]) 243 | self.output[t] = hfunc(self.state[t]) * self.go[t] 244 | 245 | assert not isnan(self.output[:n]).any() 246 | return self.output[:n] 247 | 248 | ################################################################ 249 | # combination classifiers 250 | ################################################################ 251 | 252 | 253 | class Stacked(): 254 | """Stack two networks on top of each other.""" 255 | def __init__(self,nets): 256 | self.nets = nets 257 | 258 | def forward(self,xs): 259 | for i,net in enumerate(self.nets): 260 | xs = net.forward(xs) 261 | return xs 262 | 263 | class Reversed(): 264 | """Run a network on the time-reversed input.""" 265 | def __init__(self,net): 266 | self.net = net 267 | 268 | def forward(self,xs): 269 | return self.net.forward(xs[::-1])[::-1] 270 | 271 | class Parallel(): 272 | """Run multiple networks in parallel on the same input.""" 273 | def __init__(self,*nets): 274 | self.nets = nets 275 | 276 | def forward(self,xs): 277 | # print 'xs shape', xs.shape 278 | outputs = [net.forward(xs) for net in self.nets] 279 | # print 'out1', len(outputs) 280 | outputs = zip(*outputs) 281 | # print 'out2', len(outputs) 282 | # print 'out2', len(outputs), [(x.shape, y.shape) for x,y in outputs] 283 | outputs = [concatenate(l) for l in outputs] 284 | # print 'out3', len(outputs), [x.shape for x in outputs] 285 | # print outputs 286 | return outputs 287 | 288 | def BIDILSTM(Ni,Ns,No): 289 | """A bidirectional LSTM, constructed from regular and reversed LSTMs.""" 290 | assert No>1 291 | lstm1 = LSTM(Ni, Ns) 292 | lstm2 = Reversed(LSTM(Ni, Ns)) 293 | bidi = Parallel(lstm1, lstm2) 294 | logreg = Softmax(2*Ns, No) 295 | stacked = Stacked([bidi, logreg]) 296 | return stacked 297 | 298 | def translate_back0(outputs,threshold=0.7): 299 | """Simple code for translating output from a classifier 300 | back into a list of classes. TODO/ATTENTION: this can 301 | probably be improved.""" 302 | ms = amax(outputs,axis=1) 303 | cs = argmax(outputs,axis=1) 304 | cs[ms0 333 | self.No = noutput 334 | self.lstm = BIDILSTM(ninput,nstates,noutput) 335 | # self.normalize = normalize 336 | self.codec = codec 337 | 338 | def predictSequence(self,xs): 339 | "Predict an integer sequence of codes." 340 | assert xs.shape[1]==self.Ni,\ 341 | "wrong image height (image: %d, expected: %d)"%(xs.shape[1],self.Ni) 342 | self.outputs = array(self.lstm.forward(xs)) 343 | return translate_back(self.outputs) 344 | 345 | def l2s(self,l): 346 | "Convert a code sequence into a unicode string after recognition." 347 | l = self.codec.decode(l) 348 | return u"".join(l) 349 | 350 | def predictString(self,xs): 351 | "Predict output as a string. This uses codec and normalizer." 352 | cs = self.predictSequence(xs) 353 | return self.l2s(cs) 354 | -------------------------------------------------------------------------------- /ocropy/pyrnn2clstm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | sys.path.append('/Users/kevin/ocropy') 5 | 6 | import h5py 7 | import numpy 8 | import json 9 | import argparse 10 | import ocrolib 11 | 12 | parser = argparse.ArgumentParser("convert pyrnn to clstm") 13 | parser.add_argument("file") 14 | 15 | parser.add_argument("-o","--out",default="en-default.hdf5", 16 | help="Filename to export the parameters") 17 | 18 | args = parser.parse_args() 19 | 20 | 21 | recognizer = ocrolib.load_object(args.file) 22 | # TODO: load gzipped things 23 | # recognizer = pickle.load(open('en-default.pyrnn')) 24 | 25 | parallel, softmax = recognizer.lstm.nets 26 | fwdnet, revnet = parallel.nets 27 | 28 | nf = h5py.File(args.out, "w") 29 | 30 | for w in "WGI WGF WGO WCI".split(): 31 | print getattr(fwdnet, w).shape 32 | dset = nf.create_dataset(".bidilstm.0.parallel.0.lstm." + w, getattr(fwdnet, w).shape, dtype='f') 33 | dset[...] = getattr(fwdnet, w) 34 | dset = nf.create_dataset(".bidilstm.0.parallel.1.reversed.0.lstm." + w, getattr(revnet.net, w).shape, dtype='f') 35 | dset[...] = getattr(revnet.net, w) 36 | 37 | for w in "WIP WFP WOP".split(): 38 | 39 | data = getattr(fwdnet, w).reshape((-1, 1)) 40 | print data.shape 41 | dset = nf.create_dataset(".bidilstm.0.parallel.0.lstm." + w, data.shape, dtype='f') 42 | dset[...] = data 43 | 44 | data = getattr(revnet.net, w).reshape((-1, 1)) 45 | dset = nf.create_dataset(".bidilstm.0.parallel.1.reversed.0.lstm." + w, data.shape, dtype='f') 46 | dset[...] = data 47 | 48 | print softmax.W2[:,0].shape 49 | dset = nf.create_dataset(".bidilstm.1.softmax.w", (softmax.W2[:,0].shape[0], 1), dtype='f') 50 | dset[:] = softmax.W2[:,0].reshape((-1, 1)) 51 | 52 | dset = nf.create_dataset(".bidilstm.1.softmax.W", softmax.W2[:,1:].shape, dtype='f') 53 | dset[:] = softmax.W2[:,1:] 54 | 55 | codec = numpy.array(range(recognizer.codec.size()), dtype='f').reshape((-1, 1)) 56 | dset = nf.create_dataset("codec", codec.shape, dtype='f') 57 | dset[:] = codec 58 | 59 | nf.close() -------------------------------------------------------------------------------- /src/chull.js: -------------------------------------------------------------------------------- 1 | var canvas = document.getElementById("canvas"), 2 | ctx = canvas.getContext('2d'); 3 | 4 | 5 | function rColor () { 6 | return '#'+Math.random().toString(16).slice(4) 7 | } 8 | 9 | var lobes = 5* Math.random() * Math.PI / 2 10 | var mess = Math.random()*5 11 | function rPoint() { 12 | var th = Math.random() * Math.PI * 2, 13 | r = Math.random() * Math.pow(Math.sin(th * lobes)+Math.cos(mess* th * lobes), 8); 14 | return { 15 | x: 400 + Math.cos(th) * r, 16 | y: 400 + Math.sin(th) * r 17 | } 18 | } 19 | 20 | function drawPoints ( P ) { 21 | for(var i=0; i< P.length; i++){ 22 | var p = P[i] 23 | ctx.beginPath() 24 | ctx.arc(p.x,p.y,2,0,2*Math.PI) 25 | ctx.fill() 26 | } 27 | } 28 | 29 | function drawPoly( P ){ 30 | ctx.beginPath() 31 | ctx.moveTo(P[0].x,P[0].y) 32 | for(var i=1; i< P.length; i++){ 33 | var p = P[i] 34 | ctx.lineTo(p.x,p.y) 35 | } 36 | ctx.closePath() 37 | ctx.stroke() 38 | } 39 | 40 | function fillPoly( P ){ 41 | ctx.beginPath() 42 | ctx.moveTo(P[0].x,P[0].y) 43 | for(var i=1; i< P.length; i++){ 44 | var p = P[i] 45 | ctx.lineTo(p.x,p.y) 46 | } 47 | ctx.closePath() 48 | ctx.fill() 49 | } 50 | 51 | function intersection(p1,a1,p2,a2) { 52 | 53 | var a = Math.cos(a1), 54 | b = - Math.sin(a1), 55 | c = - (a * p1.y + b * p1.x); 56 | 57 | var d = Math.cos(a2), 58 | e = - Math.sin(a2), 59 | f = - (d * p2.y + e * p2.x); 60 | 61 | var denom = -b*d+a*e 62 | return { x:(c*d-a*f)/denom, y:(-c*e+b*f)/denom} 63 | } 64 | 65 | function dist_line_point(origin,angle,p) { 66 | var b = -1, 67 | a = Math.tan(angle), 68 | c = origin.y - a*origin.x; 69 | return Math.abs(a*p.x + b*p.y + c)/Math.sqrt(a*a + b*b) 70 | } 71 | 72 | function cross(o, a, b) { 73 | return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x) 74 | } 75 | 76 | 77 | function convexHull(points) { 78 | points.sort(function(a, b) { 79 | return a.x == b.x ? a.y - b.y : a.x - b.x; 80 | }) 81 | 82 | var lower = []; 83 | for (var i = 0; i < points.length; i++) { 84 | while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) 85 | lower.pop(); 86 | lower.push(points[i]); 87 | } 88 | 89 | var upper = []; 90 | for (var i = points.length - 1; i >= 0; i--) { 91 | while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) 92 | upper.pop(); 93 | upper.push(points[i]); 94 | } 95 | 96 | upper.pop(); 97 | lower.pop(); 98 | return lower.concat(upper); 99 | } 100 | 101 | function min_enclosing_rect( poly ){ 102 | 103 | var minx = 0, 104 | miny = 0, 105 | maxx = 0, 106 | maxy = 0, 107 | numcals = 4; 108 | 109 | for (var i = 1; i < poly.length; i++) { 110 | var p = poly[i] 111 | if (p.x < poly[minx].x) minx = i; 112 | if (p.y < poly[miny].y) miny = i; 113 | if (p.x > poly[maxx].x) maxx = i; 114 | if (p.y > poly[maxy].y) maxy = i; 115 | } 116 | 117 | var cal = [], 118 | points = [miny, maxx, maxy, minx]; 119 | 120 | var dimension = function(n){ return dist_line_point(poly[cal[n].point], cal[n].angle, poly[cal[n+2].point]) } 121 | var corner = function(n){ return intersection(poly[cal[n].point], cal[n].angle, poly[cal[(n+1) % numcals].point], cal[(n+1) % numcals].angle) } 122 | 123 | for (var i = 0; i < numcals; i++) cal.push({ point: points[i], angle: i * Math.PI/2 }) 124 | 125 | var pminx = poly[minx], 126 | pminy = poly[miny], 127 | pmaxx = poly[maxx], 128 | pmaxy = poly[maxy], 129 | totalAngle = 0, 130 | minArea = (pmaxx.x - pminx.x) * (pmaxy.y - pminy.y), 131 | minRect = [ 132 | {x: pmaxx.x, y: pmaxy.y}, 133 | {x: pminx.x, y: pmaxy.y}, 134 | {x: pminx.x, y: pminy.y}, 135 | {x: pmaxx.x, y: pminy.y}, 136 | ]; 137 | 138 | while (totalAngle <= Math.PI/2) { 139 | var minAngle = Infinity, 140 | minCal = 0; 141 | 142 | for (var i = 0; i < numcals; i++) { 143 | var c = cal[i], 144 | p = poly[(c.point + 1) % poly.length], 145 | cp = poly[c.point], 146 | angle = Math.atan2(p.y - cp.y, p.x - cp.x) - c.angle; 147 | 148 | while (angle < 0) angle += Math.PI * 2; 149 | 150 | 151 | 152 | if (angle < minAngle) { 153 | minAngle = angle 154 | minCal = i 155 | } 156 | } 157 | 158 | cal[minCal].point = (cal[minCal].point + 1) % poly.length; 159 | 160 | for (var i = 0; i < numcals; i++) cal[i].angle += minAngle; 161 | 162 | var area = dimension(0) * dimension(1) 163 | if(area < minArea){ 164 | 165 | ctx.strokeStyle = rColor() 166 | 167 | for(var i = 0; i m) m = n[b = i]; 63 | return b; 64 | } 65 | 66 | // returns the maximal element according to a metric 67 | function max_element(n, metric){ 68 | var m = metric(n[0]), b = n[0]; 69 | for(var i = 1; i < n.length; i++){ 70 | var v = metric(n[i]); 71 | if(v > m){ 72 | m = v; 73 | b = n[i]; 74 | } 75 | } 76 | return b; 77 | } 78 | 79 | 80 | function array_split(arr, test){ 81 | if(!test) test = function(a, b) { return a == b }; 82 | var buf = [arr[0]], 83 | groups = []; 84 | for(var i = 1; i < arr.length; i++){ 85 | if(!test(arr[i - 1], arr[i])){ 86 | if(buf.length) groups.push(buf); 87 | buf = []; 88 | } 89 | buf.push(arr[i]) 90 | } 91 | if(buf.length) groups.push(buf); 92 | return groups 93 | } 94 | 95 | 96 | function array_zip(arr){ 97 | var out = []; 98 | for(var i = 0; i < arr[0].length; i++){ 99 | var temp = [] 100 | for(var j = 0; j < arr.length; j++){ 101 | temp.push(arr[j][i]) 102 | } 103 | out.push(temp) 104 | } 105 | return out 106 | } 107 | 108 | function array_sum(arr){ 109 | for(var i = 0, sum = 0; i < arr.length; i++) sum += arr[i]; 110 | return sum; 111 | } 112 | 113 | function array_mean(arr){ 114 | return array_sum(arr) / arr.length; 115 | } 116 | 117 | 118 | function array_conv3(arr, fn){ 119 | return arr.map(function(e, i){ 120 | return fn(arr[Math.max(0, i - 1)], arr[i], arr[Math.min(i + 1, arr.length - 1)]) 121 | }) 122 | } -------------------------------------------------------------------------------- /src/lstm.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a port of Thomas M. Breuel's lstm.py from OCROpus to Javascript 3 | * It's meant to be compatible with parameters trained with OCROpus' pyrnn 4 | * and clstm, so I've only implemented the methods for forward propagation. 5 | * 6 | * Authors: Kevin Kwok 7 | * Thomas M. Breuel (OCROpus and clstm) 8 | * 9 | * License: MIT License 10 | */ 11 | 12 | // Nonlinearity used for gates. 13 | function ffunc(vec){ 14 | var arr = new Float32Array(vec.length); 15 | for(var i = 0; i < vec.length; i++) 16 | arr[i] = 1.0 / (1.0 + Math.exp(-vec[i])); 17 | return arr; 18 | } 19 | 20 | // Nonlinearity used for input to state. 21 | function gfunc(vec){ 22 | var arr = new Float32Array(vec.length); 23 | for(var i = 0; i < vec.length; i++) arr[i] = tanh(vec[i]); 24 | return arr; 25 | } 26 | // Nonlinearity used for output 27 | function hfunc(vec){ 28 | var arr = new Float32Array(vec.length); 29 | for(var i = 0; i < vec.length; i++) arr[i] = tanh(vec[i]); 30 | return arr; 31 | } 32 | 33 | // This is a standard LSTM network with all the forward propagation formulas 34 | // optimized for speed. The lack of a real numpy-type standard numerics 35 | // package pretty much means I have to unroll the loops anyway so whatever. 36 | 37 | function LSTM(Ni, Ns) { 38 | this.Ni = Ni; 39 | this.Ns = Ns; 40 | this.Na = Ni + Ns + 1; 41 | this.allocate(5000) 42 | this.reset() 43 | } 44 | 45 | // Allocate space for the internal state variables, maxlen represents the 46 | // maximum length (width of any line) that can be processed 47 | 48 | LSTM.prototype.allocate = function(maxlen){ 49 | this.cix = mat(maxlen, this.Ns) 50 | this.ci = mat(maxlen, this.Ns) 51 | this.gix = mat(maxlen, this.Ns) 52 | this.gi = mat(maxlen, this.Ns) 53 | this.gox = mat(maxlen, this.Ns) 54 | this.go = mat(maxlen, this.Ns) 55 | this.gfx = mat(maxlen, this.Ns) 56 | this.gf = mat(maxlen, this.Ns) 57 | this.state = mat(maxlen, this.Ns) 58 | this.output = mat(maxlen, this.Ns) 59 | this.source = mat(maxlen, this.Na) 60 | } 61 | 62 | // Reset the internal state variables to NaN (anananananana batman!) 63 | LSTM.prototype.reset = function(){ 64 | rmat(this.cix); rmat(this.ci) 65 | rmat(this.gix); rmat(this.gi) 66 | rmat(this.gox); rmat(this.go) 67 | rmat(this.gfx); rmat(this.gf) 68 | rmat(this.source) 69 | rmat(this.state) 70 | rmat(this.output) 71 | } 72 | 73 | // Performs forward propagation of activations and updates internal 74 | // state. The input is a 2D array with rows representing input 75 | // vectors at each time step. Returns a 2D array whose rows represent 76 | // output vectors for each input vector 77 | 78 | LSTM.prototype.forward = function(xs){ 79 | // assert(xs[0].length == this.Ni) 80 | var n = xs.length, 81 | N = this.gi.length; 82 | if(n > N) throw "input too large for LSTM model"; 83 | this.reset(); 84 | var prev = new Float32Array(this.Ns) 85 | for(var t = 0; t < n; t++){ 86 | // assert(xs[t].length == this.Ni) 87 | this.source[t][0] = 1 88 | this.source[t].set(xs[t], 1) 89 | this.source[t].set(prev, 1 + this.Ni) 90 | for(var j = 0; j < this.Ns; j++){ 91 | this.gix[t][j] = 0; 92 | this.gfx[t][j] = 0; 93 | this.gox[t][j] = 0; 94 | this.cix[t][j] = 0; 95 | for(var k = 0; k < this.Na; k++){ 96 | var sk = this.source[t][k]; 97 | this.gix[t][j] += this.WGI[j][k] * sk 98 | this.gfx[t][j] += this.WGF[j][k] * sk 99 | this.gox[t][j] += this.WGO[j][k] * sk 100 | this.cix[t][j] += this.WCI[j][k] * sk 101 | } 102 | } 103 | if(t > 0){ 104 | addmulvec(this.gix[t], this.WIP, this.state[t-1]) 105 | addmulvec(this.gfx[t], this.WFP, this.state[t-1]) 106 | } 107 | this.gi[t] = ffunc(this.gix[t]) 108 | this.gf[t] = ffunc(this.gfx[t]) 109 | this.ci[t] = gfunc(this.cix[t]) 110 | setmulvec(this.state[t], this.ci[t], this.gi[t]); 111 | if(t > 0){ 112 | addmulvec(this.state[t], this.gf[t], this.state[t-1]) 113 | addmulvec(this.gox[t], this.WOP, this.state[t]) 114 | } 115 | this.go[t] = ffunc(this.gox[t]) 116 | setmulvec(this.output[t], hfunc(this.state[t]), this.go[t]) 117 | prev = this.output[t]; 118 | } 119 | // nanfree(this.output.slice(0, n)) 120 | return this.output.slice(0, n) 121 | } 122 | 123 | // Stack two or more networks on top of each other 124 | function Stacked(nets){ this.nets = nets } 125 | 126 | Stacked.prototype.forward = function(xs) { 127 | for(var i = 0; i < this.nets.length; i++) 128 | xs = this.nets[i].forward(xs); 129 | return xs; 130 | } 131 | 132 | // A time-reversed network 133 | function Reversed(net){ this.net = net } 134 | Reversed.prototype.forward = function(xs) { 135 | return this.net.forward(xs.slice(0).reverse()).slice(0).reverse(); 136 | }; 137 | 138 | // Run multiple networks on the same input in parallel 139 | function Parallel(nets){ this.nets = nets } 140 | Parallel.prototype.forward = function(xs) { 141 | var a = this.nets[0].forward(xs), 142 | b = this.nets[1].forward(xs); 143 | var m = mat(a.length, a[0].length + b[0].length) 144 | for(var i = 0; i < a.length; i++){ 145 | m[i].set(a[i]) 146 | m[i].set(b[i], a[0].length) 147 | } 148 | return m; 149 | } 150 | 151 | // A softmax layer 152 | function Softmax(Nh){ 153 | this.Nh = Nh; 154 | } 155 | 156 | Softmax.prototype.forward = function(ys){ 157 | var n = ys.length, 158 | zs = [], 159 | No = this.W.length; 160 | for(var i = 0; i < n; i++){ 161 | var temp = new Float32Array(No), 162 | total = 0; 163 | for(var j = 0; j < No; j++){ 164 | var v = this.B[j] 165 | for(var k = 0; k < this.Nh; k++){ 166 | v += this.W[j][k] * ys[i][k] 167 | } 168 | temp[j] = Math.exp(Math.min(100, Math.max(-100, v))) 169 | total += temp[j] 170 | } 171 | for(var j = 0; j < No; j++) temp[j] /= total; 172 | zs[i] = temp; 173 | } 174 | return zs; 175 | } 176 | 177 | // A bidirectional LSTM constructed from regular and reversed LSTMs. 178 | function BiDiLSTM(Ni, Ns){ 179 | var lstm1 = new LSTM(Ni, Ns), 180 | lstm2 = new Reversed(new LSTM(Ni, Ns)), 181 | bidi = new Parallel([lstm1, lstm2]), 182 | soft = new Softmax(2 * Ns), 183 | stack = new Stacked([bidi, soft]); 184 | return stack; 185 | } 186 | 187 | function SequenceRecognizer(ninput, nstates, codec) { 188 | this.codec = codec; 189 | this.Ni = ninput; 190 | this.Ns = nstates; 191 | this.No = codec.length; 192 | this.lstm = BiDiLSTM(this.Ni, this.Ns); 193 | } 194 | 195 | // predict an integer sequence of codes 196 | SequenceRecognizer.prototype.predictSequence = function(xs) { 197 | if(xs[0].length != this.Ni) throw "wrong image height"; 198 | 199 | this.output = this.lstm.forward(xs); 200 | 201 | function f(e){ return 1 - e[0] > 0.7 } 202 | 203 | return array_split(this.output, function(a, b){ 204 | return f(a) == f(b) 205 | }) 206 | .filter(function(e){ 207 | // return f(e[0]) // remove the groups not meeting the threshold 208 | return array_sum(e.map(function(k){return 1-k[0]})) > 0.9 209 | }).map(function(e){ 210 | // console.log(e) 211 | return max_index(array_zip(e).map(array_mean)) 212 | }) 213 | } 214 | 215 | 216 | SequenceRecognizer.prototype.predictString = function(xs) { 217 | return this.predictSequence(xs).map(function(x){return this.codec[x]}).join('') 218 | } 219 | -------------------------------------------------------------------------------- /src/swtcore.js: -------------------------------------------------------------------------------- 1 | 2 | // canny & sobel dx/dy 3 | function raw_swt(img_canny, img_dxdy, params){ 4 | var max_stroke = params.max_stroke, // maximum stroke width 5 | direction = params.direction, 6 | width = img_canny.cols, 7 | height = img_canny.rows; 8 | 9 | // nonzero Math.min function, if a is zero, returns b, otherwise minimizes 10 | function nzmin(a, b){ 11 | if(a === 0) return b; 12 | if(a < b) return a; 13 | return b; 14 | } 15 | 16 | var strokes = []; 17 | var swt = new jsfeat.matrix_t(width, height, jsfeat.U8C1_t) 18 | 19 | console.time("first pass") 20 | // first pass of stroke width transform 21 | for(var i = 0; i < width * height; i++){ 22 | if(img_canny.data[i] != 0xff) continue; // only apply on edge pixels 23 | 24 | var itheta = Math.atan2(img_dxdy.data[(i<<1) + 1], img_dxdy.data[i<<1]); // calculate the image gradient at this point by sobel 25 | var ray = [i]; 26 | var step = 1; 27 | 28 | var ix = i % width, iy = Math.floor(i / width); 29 | while(step < max_stroke){ 30 | // extrapolate the ray outwards depending on search direction 31 | // libccv is particularly clever in that it uses 32 | // bresenham's line drawing algorithm to pick out 33 | // the points along the line and also checks 34 | // neighboring pixels for corners 35 | 36 | var jx = Math.round(ix + Math.cos(itheta) * direction * step); 37 | var jy = Math.round(iy + Math.sin(itheta) * direction * step); 38 | step++; 39 | if(jx < 0 || jy < 0 || jx > width || jy > height) break; 40 | var j = jy * width + jx; 41 | ray.push(j) 42 | if(img_canny.data[j] != 0xff) continue; 43 | // calculate theta for this ray since we've reached the other side 44 | var jtheta = Math.atan2(img_dxdy.data[(j<<1) + 1], img_dxdy.data[j<<1]); 45 | 46 | if(Math.abs(Math.abs(itheta - jtheta) - Math.PI) < Math.PI / 2){ // check if theta reflects the starting angle approximately 47 | strokes.push(i) 48 | var sw = Math.sqrt((jx - ix) * (jx - ix) + (jy - iy) * (jy - iy)) // derive the stroke width 49 | for(var k = 0; k < ray.length; k++){ // iterate rays and set points along ray to minimum stroke width 50 | swt.data[ray[k]] = nzmin(swt.data[ray[k]], sw) // use nzmin because it's initially all 0's 51 | } 52 | } 53 | break; 54 | } 55 | } 56 | console.timeEnd("first pass") 57 | console.time("refinement pass") 58 | 59 | // second pass, refines swt values as median 60 | for(var k = 0; k < strokes.length; k++){ 61 | var i = strokes[k]; 62 | var itheta = Math.atan2(img_dxdy.data[(i<<1) + 1], img_dxdy.data[i<<1]); 63 | var ray = []; 64 | var widths = [] 65 | var step = 1; 66 | 67 | var ix = i % width, iy = Math.floor(i / width); 68 | while(step < max_stroke){ 69 | var jx = Math.round(ix + Math.cos(itheta) * direction * step); 70 | var jy = Math.round(iy + Math.sin(itheta) * direction * step); 71 | step++; 72 | var j = jy * width + jx; 73 | // record position of the ray and the stroke width there 74 | widths.push(swt.data[j]) 75 | ray.push(j) 76 | // stop when the ray is terminated 77 | if(img_canny.data[j] == 0xff) break; 78 | } 79 | var median = widths.sort(function(a, b){return a - b})[Math.floor(widths.length / 2)]; 80 | // set the high values to the median so that corners are nice 81 | for(var j = 0; j < ray.length; j++){ 82 | swt.data[ray[j]] = nzmin(swt.data[ray[j]], median) 83 | } 84 | // swt.data[ray[0]] = 0 85 | // swt.data[ray[ray.length - 1]] = 0 86 | } 87 | 88 | console.timeEnd("refinement pass") 89 | 90 | // TODO: get rid of strokes 91 | return { 92 | swt: swt, 93 | strokes: strokes 94 | } 95 | } 96 | 97 | 98 | 99 | // maybe in the future we should replace this with a strongly 100 | // connected components algorithm (or have some spatial heuristic to 101 | // determine how wise it would be to consider the connection valid) 102 | function connected_swt(swt, params){ 103 | var dx8 = [-1, 1, -1, 0, 1, -1, 0, 1]; 104 | var dy8 = [0, 0, -1, -1, -1, 1, 1, 1]; 105 | var width = swt.cols, 106 | height = swt.rows; 107 | 108 | var marker = new jsfeat.matrix_t(width, height, jsfeat.U8C1_t) 109 | var contours = [] 110 | 111 | for(var i = 0; i < width * height; i++){ 112 | if(marker.data[i] || !swt.data[i]) continue; 113 | 114 | var ix = i % width, iy = Math.floor(i / width) 115 | 116 | marker.data[i] = 1 117 | var contour = [] 118 | var stack = [i] 119 | var closed; 120 | 121 | while(closed = stack.shift()){ 122 | contour.push(closed) 123 | var cx = closed % width, cy = Math.floor(closed / width); 124 | var w = swt.data[closed]; 125 | for(var k = 0; k < 8; k++){ 126 | var nx = cx + dx8[k] 127 | var ny = cy + dy8[k] 128 | var n = ny * width + nx; 129 | 130 | if(nx >= 0 && nx < width && 131 | ny >= 0 && ny < height && 132 | swt.data[n] && 133 | !marker.data[n] && 134 | swt.data[n] <= params.stroke_ratio * w && 135 | swt.data[n] * params.stroke_ratio >= w){ 136 | marker.data[n] = 1 137 | // update the average stroke width 138 | w = (w * stack.length + swt.data[n]) / (stack.length + 1) 139 | stack.push(n) 140 | } 141 | } 142 | } 143 | // contours.push(contour) 144 | if(contour.length >= params.min_area){ 145 | contours.push(contour) 146 | } 147 | } 148 | return contours 149 | } 150 | 151 | 152 | 153 | function visualize_matrix(mat, letters){ 154 | var c = document.createElement('canvas') 155 | c.width = mat.cols; 156 | c.height = mat.rows; 157 | var cx = c.getContext('2d') 158 | var out = cx.createImageData(mat.cols, mat.rows); 159 | for(var i = 0; i < mat.rows * mat.cols; i++){ 160 | 161 | out.data[i * 4 + 3] = 255 162 | if(mat.data[i] == 1){ 163 | out.data[i * 4] = 255 164 | // out.data[i * 4 + 1] = out.data[i * 4 + 2] = 30 * mat.data[i] 165 | }else{ 166 | out.data[i * 4] = out.data[i * 4 + 1] = out.data[i * 4 + 2] = 30 * mat.data[i] 167 | } 168 | 169 | } 170 | cx.putImageData(out, 0, 0) 171 | 172 | if(letters){ 173 | cx.strokeStyle = 'red' 174 | for(var i = 0; i < letters.length; i++){ 175 | var letter = letters[i]; 176 | cx.strokeRect(letter.x0 + .5, letter.y0 + .5, letter.width, letter.height) 177 | } 178 | 179 | if(letters[0] && letters[0].letters){ 180 | // hey look not actually letters 181 | letters.forEach(function(line){ 182 | cx.beginPath() 183 | var colors = ['green', 'blue', 'red', 'purple', 'orange', 'yellow'] 184 | cx.strokeStyle = colors[Math.floor(colors.length * Math.random())] 185 | cx.lineWidth = 3 186 | 187 | line.letters 188 | .sort(function(a, b){ return a.cx - b.cx }) 189 | .forEach(function(letter){ 190 | cx.lineTo(letter.cx, letter.cy) 191 | }) 192 | 193 | cx.stroke() 194 | }) 195 | } 196 | } 197 | document.body.appendChild(c) 198 | 199 | // console.image(c.toDataURL('image/png')) 200 | 201 | return cx 202 | } 203 | 204 | 205 | function equivalence_classes(elements, is_equal){ 206 | var node = [] 207 | for(var i = 0; i < elements.length; i++){ 208 | node.push({ 209 | parent: 0, 210 | element: elements[i], 211 | rank: 0 212 | }) 213 | } 214 | for(var i = 0; i < node.length; i++){ 215 | var root = node[i] 216 | while(root.parent){ 217 | root = root.parent; 218 | } 219 | for(var j = 0; j < node.length; j++){ 220 | if(i == j) continue; 221 | if(!is_equal(node[i].element, node[j].element)) continue; 222 | var root2 = node[j]; 223 | while(root2.parent){ 224 | root2 = root2.parent; 225 | } 226 | if(root2 != root){ 227 | if(root.rank > root2.rank){ 228 | root2.parent = root; 229 | }else{ 230 | root.parent = root2; 231 | if(root.rank == root2.rank){ 232 | root2.rank++ 233 | } 234 | root = root2; 235 | } 236 | var node2 = node[j]; 237 | while(node2.parent){ 238 | var temp = node2; 239 | node2 = node2.parent; 240 | temp.parent = root; 241 | } 242 | var node2 = node[i]; 243 | while(node2.parent){ 244 | var temp = node2; 245 | node2 = node2.parent; 246 | temp.parent = root; 247 | } 248 | } 249 | } 250 | } 251 | var index = 0; 252 | var clusters = []; 253 | for(var i = 0; i < node.length; i++){ 254 | var j = -1; 255 | var node1 = node[i] 256 | while(node1.parent){ 257 | node1 = node1.parent 258 | } 259 | if(node1.rank >= 0){ 260 | node1.rank = ~index++; 261 | } 262 | j = ~node1.rank; 263 | 264 | if(clusters[j]){ 265 | clusters[j].push(elements[i]) 266 | }else{ 267 | clusters[j] = [elements[i]] 268 | } 269 | } 270 | return clusters; 271 | } --------------------------------------------------------------------------------