├── 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 | }
--------------------------------------------------------------------------------