├── .npmignore
├── .gitignore
├── .travis.yml
├── test
├── index.html
├── qunit.css
├── tests.js
└── qunit.js
├── Gruntfile.js
├── package.json
├── LICENSE
├── benchmark
├── benchmark.js
├── index.html
├── grid_100x100.js
└── grid_150x150.js
├── index.html
├── README.md
├── demo
├── index.html
├── demo.js
└── demo.css
└── astar.js
/.npmignore:
--------------------------------------------------------------------------------
1 | benchmark
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.11"
4 | before_script:
5 | - npm install -g grunt-cli
6 | script:
7 | - grunt default --verbose
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | QUnit Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = function(grunt) {
3 |
4 | grunt.initConfig({
5 | pkg: grunt.file.readJSON('package.json'),
6 |
7 | qunit: {
8 | all: ['test/index.html']
9 | },
10 |
11 |
12 | jshint: {
13 | options: {
14 | browser: true,
15 | sub: true,
16 | undef: true,
17 | unused: true
18 | },
19 | all: ['astar.js', 'test/tests.js', 'demo/demo.js']
20 | }
21 | });
22 |
23 |
24 | grunt.loadNpmTasks('grunt-contrib-jshint');
25 | grunt.loadNpmTasks('grunt-contrib-qunit');
26 |
27 | grunt.registerTask('default', ['jshint', 'qunit']);
28 |
29 | };
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "javascript-astar",
3 | "version": "0.4.1",
4 | "description": "astar search algorithm in JavaScript",
5 | "main": "astar.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/bgrins/javascript-astar.git"
9 | },
10 | "keywords": [
11 | ],
12 | "author": "Brian Grinstead",
13 | "license": "MIT",
14 | "bugs": {
15 | "url": "https://github.com/bgrins/javascript-astar/issues"
16 | },
17 | "main": "./astar.js",
18 | "homepage": "http://bgrins.github.io/javascript-astar",
19 | "devDependencies": {
20 | "grunt": "~0.4.5",
21 | "grunt-contrib-qunit": "~0.5.0",
22 | "grunt-contrib-jshint": "~0.10.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) Brian Grinstead, http://briangrinstead.com
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/benchmark/benchmark.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 | var running = false;
3 | $("#runall").click(function() {
4 | if (running) {
5 | return;
6 | }
7 | running = true;
8 |
9 | var graph = new Graph(grid),
10 | start = graph.grid[0][0],
11 | end = graph.grid[140][140],
12 | results = [],
13 | times = 0;
14 |
15 | for (var i = 0; i < 1000; i++) {
16 | var startTime = performance ? performance.now() : new Date().getTime(),
17 | result = astar.search(graph, start, end),
18 | endTime = performance ? performance.now() : new Date().getTime();
19 | times = times + (endTime - startTime);
20 |
21 | results.push(
22 | 'Found path with ' + result.length + ' steps. ' +
23 | 'Took ' + (endTime - startTime).toFixed(2) + ' milliseconds. '
24 | );
25 | }
26 |
27 | $("#graph").html(graph.toString());
28 | $("#summary").html('Average time: ' + (times / 1000).toFixed(2) + 'ms');
29 | $("#results").html(results.join(''));
30 |
31 | running = false;
32 | return false;
33 | });
34 | });
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | JavaScript A* Search Algorithm
6 |
7 |
8 |
9 |
10 |
23 |
24 |
25 |
A* Search Algorithm
26 |
27 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/benchmark/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Benchmark - JavaScript A* Search Algorithm
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
28 |
29 |
30 |
Benchmark
31 |
32 |
Run benchmark
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # javascript-astar
2 |
3 | ## An implementation of the A* Search Algorithm in JavaScript
4 |
5 | See a demo at http://www.briangrinstead.com/files/astar/
6 |
7 | ## Sample Usage
8 |
9 | If you want just the A* search code (not the demo visualization), use code like this http://gist.github.com/581352
10 | ```js
11 |
12 |
42 | ```
43 | A few notes about weight values:
44 |
45 | 1. A weight of 0 denotes a wall.
46 | 2. A weight cannot be negative.
47 | 3. A weight cannot be between 0 and 1 (exclusive).
48 | 4. A weight can contain decimal values (greater than 1).
49 |
50 | ### Original (slower) implementation
51 |
52 | The original version of the algorithm used a list, and was a bit clearer but much slower. It was based off the [original blog post](http://www.briangrinstead.com/blog/astar-search-algorithm-in-javascript). The code is available at: https://github.com/bgrins/javascript-astar/tree/0.0.1/original-implementation.
53 |
54 | The newest version of the algorithm using a Binary Heap. It is quite faster than the original.
55 | http://www.briangrinstead.com/blog/astar-search-algorithm-in-javascript-updated
56 | Binary Heap taken from http://eloquentjavascript.net/appendix2.html (license: http://creativecommons.org/licenses/by/3.0/)
57 |
58 |
59 | ## Running the test suite
60 |
61 | [](https://travis-ci.org/bgrins/javascript-astar)
62 |
63 | If you don't have grunt installed, follow the [grunt getting started guide](http://gruntjs.com/getting-started) first.
64 |
65 | Pull down the project, then run:
66 |
67 | npm install
68 | grunt
69 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Demo - JavaScript A* Search Algorithm
7 |
8 |
9 |
10 |
23 |
24 |
25 |
Demonstration
26 |
27 |
28 |
29 |
Wall Frequency:
30 |
31 | 10%
32 | 20%
33 | 30%
34 | 40%
35 |
36 |
37 |
Grid Size:
38 |
39 | 10x10
40 | 15x15
41 | 20x20
42 | 30x30
43 | 40x40
44 | 50x50
45 | 100x100
46 | 150x150
47 |
48 |
49 |
50 |
Show search info?
51 |
52 |
53 |
Allow diagonal movement?
54 |
55 |
56 |
Closest node if target unreachable?
57 |
58 |
59 |
Add random weights?
60 |
61 |
62 |
Display weight values?
63 |
64 |
65 |
66 |
67 | Key:
68 |
69 | Weight of 1
70 |
71 | Weight of 3
72 |
73 | Weight of 5
74 |
75 | Wall (imapassable)
76 |
77 |
78 |
Click on a grid position to search
79 |
80 |
81 |
82 |
Loading grid...
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/test/qunit.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * QUnit 1.14.0
3 | * http://qunitjs.com/
4 | *
5 | * Copyright 2013 jQuery Foundation and other contributors
6 | * Released under the MIT license
7 | * http://jquery.org/license
8 | *
9 | * Date: 2014-01-31T16:40Z
10 | */
11 |
12 | /** Font Family and Sizes */
13 |
14 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
15 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
16 | }
17 |
18 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
19 | #qunit-tests { font-size: smaller; }
20 |
21 |
22 | /** Resets */
23 |
24 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 |
30 | /** Header */
31 |
32 | #qunit-header {
33 | padding: 0.5em 0 0.5em 1em;
34 |
35 | color: #8699A4;
36 | background-color: #0D3349;
37 |
38 | font-size: 1.5em;
39 | line-height: 1em;
40 | font-weight: 400;
41 |
42 | border-radius: 5px 5px 0 0;
43 | }
44 |
45 | #qunit-header a {
46 | text-decoration: none;
47 | color: #C2CCD1;
48 | }
49 |
50 | #qunit-header a:hover,
51 | #qunit-header a:focus {
52 | color: #FFF;
53 | }
54 |
55 | #qunit-testrunner-toolbar label {
56 | display: inline-block;
57 | padding: 0 0.5em 0 0.1em;
58 | }
59 |
60 | #qunit-banner {
61 | height: 5px;
62 | }
63 |
64 | #qunit-testrunner-toolbar {
65 | padding: 0.5em 0 0.5em 2em;
66 | color: #5E740B;
67 | background-color: #EEE;
68 | overflow: hidden;
69 | }
70 |
71 | #qunit-userAgent {
72 | padding: 0.5em 0 0.5em 2.5em;
73 | background-color: #2B81AF;
74 | color: #FFF;
75 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
76 | }
77 |
78 | #qunit-modulefilter-container {
79 | float: right;
80 | }
81 |
82 | /** Tests: Pass/Fail */
83 |
84 | #qunit-tests {
85 | list-style-position: inside;
86 | }
87 |
88 | #qunit-tests li {
89 | padding: 0.4em 0.5em 0.4em 2.5em;
90 | border-bottom: 1px solid #FFF;
91 | list-style-position: inside;
92 | }
93 |
94 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
95 | display: none;
96 | }
97 |
98 | #qunit-tests li strong {
99 | cursor: pointer;
100 | }
101 |
102 | #qunit-tests li a {
103 | padding: 0.5em;
104 | color: #C2CCD1;
105 | text-decoration: none;
106 | }
107 | #qunit-tests li a:hover,
108 | #qunit-tests li a:focus {
109 | color: #000;
110 | }
111 |
112 | #qunit-tests li .runtime {
113 | float: right;
114 | font-size: smaller;
115 | }
116 |
117 | .qunit-assert-list {
118 | margin-top: 0.5em;
119 | padding: 0.5em;
120 |
121 | background-color: #FFF;
122 |
123 | border-radius: 5px;
124 | }
125 |
126 | .qunit-collapsed {
127 | display: none;
128 | }
129 |
130 | #qunit-tests table {
131 | border-collapse: collapse;
132 | margin-top: 0.2em;
133 | }
134 |
135 | #qunit-tests th {
136 | text-align: right;
137 | vertical-align: top;
138 | padding: 0 0.5em 0 0;
139 | }
140 |
141 | #qunit-tests td {
142 | vertical-align: top;
143 | }
144 |
145 | #qunit-tests pre {
146 | margin: 0;
147 | white-space: pre-wrap;
148 | word-wrap: break-word;
149 | }
150 |
151 | #qunit-tests del {
152 | background-color: #E0F2BE;
153 | color: #374E0C;
154 | text-decoration: none;
155 | }
156 |
157 | #qunit-tests ins {
158 | background-color: #FFCACA;
159 | color: #500;
160 | text-decoration: none;
161 | }
162 |
163 | /*** Test Counts */
164 |
165 | #qunit-tests b.counts { color: #000; }
166 | #qunit-tests b.passed { color: #5E740B; }
167 | #qunit-tests b.failed { color: #710909; }
168 |
169 | #qunit-tests li li {
170 | padding: 5px;
171 | background-color: #FFF;
172 | border-bottom: none;
173 | list-style-position: inside;
174 | }
175 |
176 | /*** Passing Styles */
177 |
178 | #qunit-tests li li.pass {
179 | color: #3C510C;
180 | background-color: #FFF;
181 | border-left: 10px solid #C6E746;
182 | }
183 |
184 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
185 | #qunit-tests .pass .test-name { color: #366097; }
186 |
187 | #qunit-tests .pass .test-actual,
188 | #qunit-tests .pass .test-expected { color: #999; }
189 |
190 | #qunit-banner.qunit-pass { background-color: #C6E746; }
191 |
192 | /*** Failing Styles */
193 |
194 | #qunit-tests li li.fail {
195 | color: #710909;
196 | background-color: #FFF;
197 | border-left: 10px solid #EE5757;
198 | white-space: pre;
199 | }
200 |
201 | #qunit-tests > li:last-child {
202 | border-radius: 0 0 5px 5px;
203 | }
204 |
205 | #qunit-tests .fail { color: #000; background-color: #EE5757; }
206 | #qunit-tests .fail .test-name,
207 | #qunit-tests .fail .module-name { color: #000; }
208 |
209 | #qunit-tests .fail .test-actual { color: #EE5757; }
210 | #qunit-tests .fail .test-expected { color: #008000; }
211 |
212 | #qunit-banner.qunit-fail { background-color: #EE5757; }
213 |
214 |
215 | /** Result */
216 |
217 | #qunit-testresult {
218 | padding: 0.5em 0.5em 0.5em 2.5em;
219 |
220 | color: #2B81AF;
221 | background-color: #D2E0E6;
222 |
223 | border-bottom: 1px solid #FFF;
224 | }
225 | #qunit-testresult .module-name {
226 | font-weight: 700;
227 | }
228 |
229 | /** Fixture */
230 |
231 | #qunit-fixture {
232 | position: absolute;
233 | top: -10000px;
234 | left: -10000px;
235 | width: 1000px;
236 | height: 1000px;
237 | }
238 |
--------------------------------------------------------------------------------
/demo/demo.js:
--------------------------------------------------------------------------------
1 | /* demo.js http://github.com/bgrins/javascript-astar
2 | MIT License
3 |
4 | Set up the demo page for the A* Search
5 | */
6 | /* global Graph, astar, $ */
7 |
8 | var WALL = 0,
9 | performance = window.performance;
10 |
11 | $(function() {
12 |
13 | var $grid = $("#search_grid"),
14 | $selectWallFrequency = $("#selectWallFrequency"),
15 | $selectGridSize = $("#selectGridSize"),
16 | $checkDebug = $("#checkDebug"),
17 | $searchDiagonal = $("#searchDiagonal"),
18 | $checkClosest = $("#checkClosest");
19 |
20 | var opts = {
21 | wallFrequency: $selectWallFrequency.val(),
22 | gridSize: $selectGridSize.val(),
23 | debug: $checkDebug.is("checked"),
24 | diagonal: $searchDiagonal.is("checked"),
25 | closest: $checkClosest.is("checked")
26 | };
27 |
28 | var grid = new GraphSearch($grid, opts, astar.search);
29 |
30 | $("#btnGenerate").click(function() {
31 | grid.initialize();
32 | });
33 |
34 | $selectWallFrequency.change(function() {
35 | grid.setOption({wallFrequency: $(this).val()});
36 | grid.initialize();
37 | });
38 |
39 | $selectGridSize.change(function() {
40 | grid.setOption({gridSize: $(this).val()});
41 | grid.initialize();
42 | });
43 |
44 | $checkDebug.change(function() {
45 | grid.setOption({debug: $(this).is(":checked")});
46 | });
47 |
48 | $searchDiagonal.change(function() {
49 | var val = $(this).is(":checked");
50 | grid.setOption({diagonal: val});
51 | grid.graph.diagonal = val;
52 | });
53 |
54 | $checkClosest.change(function() {
55 | grid.setOption({closest: $(this).is(":checked")});
56 | });
57 |
58 | $("#generateWeights").click( function () {
59 | if ($("#generateWeights").prop("checked")) {
60 | $('#weightsKey').slideDown();
61 | } else {
62 | $('#weightsKey').slideUp();
63 | }
64 | });
65 |
66 | });
67 |
68 | var css = { start: "start", finish: "finish", wall: "wall", active: "active" };
69 |
70 | function GraphSearch($graph, options, implementation) {
71 | this.$graph = $graph;
72 | this.search = implementation;
73 | this.opts = $.extend({wallFrequency:0.1, debug:true, gridSize:10}, options);
74 | this.initialize();
75 | }
76 | GraphSearch.prototype.setOption = function(opt) {
77 | this.opts = $.extend(this.opts, opt);
78 | this.drawDebugInfo();
79 | };
80 | GraphSearch.prototype.initialize = function() {
81 | this.grid = [];
82 | var self = this,
83 | nodes = [],
84 | $graph = this.$graph;
85 |
86 | $graph.empty();
87 |
88 | var cellWidth = ($graph.width()/this.opts.gridSize)-2, // -2 for border
89 | cellHeight = ($graph.height()/this.opts.gridSize)-2,
90 | $cellTemplate = $(" ").addClass("grid_item").width(cellWidth).height(cellHeight),
91 | startSet = false;
92 |
93 | for(var x = 0; x < this.opts.gridSize; x++) {
94 | var $row = $("
"),
95 | nodeRow = [],
96 | gridRow = [];
97 |
98 | for(var y = 0; y < this.opts.gridSize; y++) {
99 | var id = "cell_"+x+"_"+y,
100 | $cell = $cellTemplate.clone();
101 | $cell.attr("id", id).attr("x", x).attr("y", y);
102 | $row.append($cell);
103 | gridRow.push($cell);
104 |
105 | var isWall = Math.floor(Math.random()*(1/self.opts.wallFrequency));
106 | if(isWall === 0) {
107 | nodeRow.push(WALL);
108 | $cell.addClass(css.wall);
109 | }
110 | else {
111 | var cell_weight = ($("#generateWeights").prop("checked") ? (Math.floor(Math.random() * 3)) * 2 + 1 : 1);
112 | nodeRow.push(cell_weight);
113 | $cell.addClass('weight' + cell_weight);
114 | if ($("#displayWeights").prop("checked")) {
115 | $cell.html(cell_weight);
116 | }
117 | if (!startSet) {
118 | $cell.addClass(css.start);
119 | startSet = true;
120 | }
121 | }
122 | }
123 | $graph.append($row);
124 |
125 | this.grid.push(gridRow);
126 | nodes.push(nodeRow);
127 | }
128 |
129 | this.graph = new Graph(nodes);
130 |
131 | // bind cell event, set start/wall positions
132 | this.$cells = $graph.find(".grid_item");
133 | this.$cells.click(function() {
134 | self.cellClicked($(this));
135 | });
136 | };
137 | GraphSearch.prototype.cellClicked = function($end) {
138 |
139 | var end = this.nodeFromElement($end);
140 |
141 | if($end.hasClass(css.wall) || $end.hasClass(css.start)) {
142 | return;
143 | }
144 |
145 | this.$cells.removeClass(css.finish);
146 | $end.addClass("finish");
147 | var $start = this.$cells.filter("." + css.start),
148 | start = this.nodeFromElement($start);
149 |
150 | var sTime = performance ? performance.now() : new Date().getTime();
151 |
152 | var path = this.search(this.graph, start, end, {
153 | closest: this.opts.closest
154 | });
155 | var fTime = performance ? performance.now() : new Date().getTime(),
156 | duration = (fTime-sTime).toFixed(2);
157 |
158 | if(path.length === 0) {
159 | $("#message").text("couldn't find a path (" + duration + "ms)");
160 | this.animateNoPath();
161 | }
162 | else {
163 | $("#message").text("search took " + duration + "ms.");
164 | this.drawDebugInfo();
165 | this.animatePath(path);
166 | }
167 | };
168 | GraphSearch.prototype.drawDebugInfo = function() {
169 | this.$cells.html(" ");
170 | var that = this;
171 | if(this.opts.debug) {
172 | that.$cells.each(function() {
173 | var node = that.nodeFromElement($(this)),
174 | debug = false;
175 | if (node.visited) {
176 | debug = "F: " + node.f + " G: " + node.g + " H: " + node.h;
177 | }
178 |
179 | if (debug) {
180 | $(this).html(debug);
181 | }
182 | });
183 | }
184 | };
185 | GraphSearch.prototype.nodeFromElement = function($cell) {
186 | return this.graph.grid[parseInt($cell.attr("x"))][parseInt($cell.attr("y"))];
187 | };
188 | GraphSearch.prototype.animateNoPath = function() {
189 | var $graph = this.$graph;
190 | var jiggle = function(lim, i) {
191 | if(i>=lim) { $graph.css("top", 0).css("left", 0); return; }
192 | if(!i) i=0;
193 | i++;
194 | $graph.css("top", Math.random()*6).css("left", Math.random()*6);
195 | setTimeout(function() {
196 | jiggle(lim, i);
197 | }, 5);
198 | };
199 | jiggle(15);
200 | };
201 | GraphSearch.prototype.animatePath = function(path) {
202 | var grid = this.grid,
203 | timeout = 1000 / grid.length,
204 | elementFromNode = function(node) {
205 | return grid[node.x][node.y];
206 | };
207 |
208 | var self = this;
209 | // will add start class if final
210 | var removeClass = function(path, i) {
211 | if(i >= path.length) { // finished removing path, set start positions
212 | return setStartClass(path, i);
213 | }
214 | elementFromNode(path[i]).removeClass(css.active);
215 | setTimeout(function() {
216 | removeClass(path, i+1);
217 | }, timeout*path[i].getCost());
218 | };
219 | var setStartClass = function(path, i) {
220 | if(i === path.length) {
221 | self.$graph.find("." + css.start).removeClass(css.start);
222 | elementFromNode(path[i-1]).addClass(css.start);
223 | }
224 | };
225 | var addClass = function(path, i) {
226 | if(i >= path.length) { // Finished showing path, now remove
227 | return removeClass(path, 0);
228 | }
229 | elementFromNode(path[i]).addClass(css.active);
230 | setTimeout(function() {
231 | addClass(path, i+1);
232 | }, timeout*path[i].getCost());
233 | };
234 |
235 | addClass(path, 0);
236 | this.$graph.find("." + css.start).removeClass(css.start);
237 | this.$graph.find("." + css.finish).removeClass(css.finish).addClass(css.start);
238 | };
239 |
--------------------------------------------------------------------------------
/test/tests.js:
--------------------------------------------------------------------------------
1 |
2 | /* global Graph, astar, ok, test, equal */
3 |
4 | test( "Sanity Checks", function() {
5 | ok (typeof Graph !== "undefined", "Graph exists");
6 | ok (typeof astar !== "undefined", "Astar exists");
7 | });
8 |
9 | test( "Basic Horizontal", function() {
10 |
11 | var result1 = runSearch([[1],[1]], [0,0], [1,0]);
12 | equal (result1.text, "(1,0)", "One step down");
13 |
14 | var result2 = runSearch([[1],[1],[1]], [0,0], [2,0]);
15 | equal (result2.text, "(1,0)(2,0)", "Two steps down");
16 |
17 | var result3 = runSearch([[1],[1],[1],[1]], [0,0], [3,0]);
18 | equal (result3.text, "(1,0)(2,0)(3,0)", "Three steps down");
19 |
20 | });
21 |
22 | test( "Basic Vertical", function() {
23 |
24 | var result1 = runSearch([[1, 1]], [0,0], [0,1]);
25 | equal (result1.text, "(0,1)", "One step across");
26 |
27 | var result2 = runSearch([[1, 1, 1]], [0,0], [0,2]);
28 | equal (result2.text, "(0,1)(0,2)", "Two steps across");
29 |
30 | var result3 = runSearch([[1, 1, 1, 1]], [0,0], [0,3]);
31 | equal (result3.text, "(0,1)(0,2)(0,3)", "Three steps across");
32 |
33 | });
34 |
35 | test( "Basic Weighting", function() {
36 |
37 | var result1 = runSearch([[1, 1],
38 | [2, 1]], [0,0], [1,1]);
39 | equal (result1.text, "(0,1)(1,1)", "Takes less weighted path");
40 |
41 | var result2 = runSearch([[1, 2],
42 | [1, 1]], [0,0], [1,1]);
43 | equal (result2.text, "(1,0)(1,1)", "Takes less weighted path");
44 |
45 | });
46 |
47 | test( "Pathfinding", function() {
48 | var result1 = runSearch([
49 | [1,1,1,1],
50 | [0,1,1,0],
51 | [0,0,1,1]
52 | ], [0,0], [2,3]);
53 |
54 | equal (result1.text, "(0,1)(1,1)(1,2)(2,2)(2,3)", "Result is expected");
55 | });
56 |
57 | test( "Diagonal Pathfinding", function() {
58 | var result1 = runSearch(new Graph([
59 | [1,1,1,1],
60 | [0,1,1,0],
61 | [0,0,1,1]
62 | ], { diagonal: true}), [0,0], [2,3]);
63 |
64 | equal (result1.text, "(1,1)(2,2)(2,3)", "Result is expected");
65 | });
66 |
67 | test( "Pathfinding to closest", function() {
68 | var result1 = runSearch([
69 | [1,1,1,1],
70 | [0,1,1,0],
71 | [0,0,1,1]
72 | ], [0,0], [2,1], {closest: true});
73 |
74 | equal (result1.text, "(0,1)(1,1)", "Result is expected - pathed to closest node");
75 |
76 | var result2 = runSearch([
77 | [1,0,1,1],
78 | [0,1,1,0],
79 | [0,0,1,1]
80 | ], [0,0], [2,1], {closest: true});
81 |
82 | equal (result2.text, "", "Result is expected - start node was closest node");
83 |
84 | var result3 = runSearch([
85 | [1,1,1,1],
86 | [0,1,1,0],
87 | [0,1,1,1]
88 | ], [0,0], [2,1], {closest: true});
89 |
90 | equal (result3.text, "(0,1)(1,1)(2,1)", "Result is expected - target node was reachable");
91 | });
92 |
93 | test( "Path costs", function() {
94 | var graph1 = new Graph([
95 | [1,2,2],
96 | [1,1,2],
97 | [1,1,2],
98 | ], { diagonal: true});
99 |
100 | var straightNeighbor = graph1.grid[1][0].getCost(graph1.grid[0][0]),
101 | diagonalNeighbor = graph1.grid[1][1].getCost(graph1.grid[0][0]),
102 | diagonalWeightedNeighbor = graph1.grid[2][2].getCost(graph1.grid[1][1]);
103 |
104 | equal ((straightNeighbor == 1) , true, "Result is expected - neighbor cost is 1");
105 | equal ((diagonalNeighbor > 1 && diagonalNeighbor < 2) , true, "Result is expected - diagonal neighbor cost is more than 1, less than 2");
106 | equal ((diagonalWeightedNeighbor > 2 && diagonalWeightedNeighbor < 4), true, "Result is expected - diagonal neighbor cost for 2 weight node is more than 2, less than 4");
107 | });
108 |
109 | // Make sure that start / end position are re-opened between searches
110 | // See https://github.com/bgrins/javascript-astar/issues/43.
111 | test( "Multiple runs on the same graph", function() {
112 | var graph = new Graph([
113 | [1,1,0,1],
114 | [0,1,1,0],
115 | [0,0,1,1]
116 | ]);
117 |
118 | var result1 = runSearch(graph, [0,0], [2,3]);
119 | equal (result1.text, "(0,1)(1,1)(1,2)(2,2)(2,3)", "Result is expected");
120 |
121 | var result2 = runSearch(graph, [2,3], [0,0]);
122 | equal (result2.text, "(2,2)(1,2)(1,1)(0,1)(0,0)", "Result is expected");
123 |
124 | });
125 |
126 | function runSearch(graph, start, end, options) {
127 | if (!(graph instanceof Graph)) {
128 | graph = new Graph(graph);
129 | }
130 | start = graph.grid[start[0]][start[1]];
131 | end = graph.grid[end[0]][end[1]];
132 | var sTime = new Date(),
133 | result = astar.search(graph, start, end, options),
134 | eTime = new Date();
135 | return {
136 | result: result,
137 | text: pathToString(result),
138 | time: (eTime - sTime)
139 | };
140 | }
141 |
142 | function pathToString(result) {
143 | return result.map(function(node) {
144 | return "(" + node.x + "," + node.y + ")";
145 | }).join("");
146 | }
147 |
148 | test( "GPS Pathfinding", function() {
149 | var data = [
150 | {name: "Paris", lat: 48.8567, lng: 2.3508},
151 | {name: "Lyon", lat: 45.76, lng: 4.84},
152 | {name: "Marseille", lat: 43.2964, lng: 5.37},
153 | {name: "Bordeaux", lat: 44.84, lng: -0.58},
154 | {name: "Cannes", lat: 43.5513, lng: 7.0128},
155 | {name: "Toulouse", lat: 43.6045, lng: 1.444},
156 | {name: "Reims", lat: 49.2628, lng: 4.0347}
157 | ],
158 | links = {
159 | "Paris": ["Lyon", "Bordeaux", "Reims"],
160 | "Lyon": ["Paris", "Marseille"],
161 | "Marseille": ["Lyon", "Cannes", "Toulouse"],
162 | "Bordeaux": ["Toulouse", "Paris"],
163 | "Cannes": ["Marseille"],
164 | "Toulouse": ["Marseille", "Bordeaux"],
165 | "Reims": ["Paris"]
166 | };
167 |
168 | function CityGraph(data, links) {
169 | this.nodes = [];
170 | this.links = links;
171 | this.cities = {};
172 |
173 | for (var i = 0; i < data.length; ++i) {
174 | var city = data[i],
175 | obj = new CityNode(city.name, city.lat, city.lng);
176 |
177 | if (this.nodes.indexOf(obj) == -1) {
178 | this.nodes.push(obj);
179 | }
180 |
181 | this.cities[obj.name] = obj;
182 | }
183 |
184 | this.init();
185 | }
186 |
187 | CityGraph.prototype.init= Graph.prototype.init;
188 |
189 | CityGraph.prototype.cleanDirty = Graph.prototype.cleanDirty;
190 |
191 | CityGraph.prototype.markDirty = Graph.prototype.markDirty;
192 |
193 | CityGraph.prototype.neighbors = function (node) {
194 | var neighbors = [],
195 | ids = this.links[node.name];
196 | for (var i = 0, len = ids.length; i < len; ++i) {
197 | var name = ids[i],
198 | neighbor = this.cities[name];
199 | neighbors.push(neighbor);
200 | }
201 | return neighbors;
202 | };
203 |
204 | function CityNode(name, lat, lng) {
205 | this.name = name;
206 | this.lat = lat;
207 | this.lng = lng;
208 | this.longRad = this.lng * Math.PI / 180;
209 | this.latRad = this.lat * Math.PI / 180;
210 | }
211 | CityNode.prototype.weight = 1;
212 | CityNode.prototype.toString = function() {
213 | return "[" + this.name + " (" + this.lat + ", " + this.lng + ")]";
214 | };
215 | CityNode.prototype.isWall = function() {
216 | return this.weight === 0;
217 | };
218 | // Heuristic function
219 | CityNode.prototype.GPS_distance = function(city) {
220 | var x = (city.longRad - this.longRad) * Math.cos((this.latRad + city.latRad)/2),
221 | y = city.latRad - this.latRad,
222 | res = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) * 6371;
223 | return res;
224 | };
225 | // Real cost function
226 | CityNode.prototype.getCost = function(city) {
227 | // Re-use heuristic function for now
228 | // TODO: Determine the real distance between cities (from another data set)
229 | return this.GPS_distance(city);
230 | };
231 |
232 | var graph = new CityGraph(data, links);
233 |
234 | var start = graph.cities["Paris"],
235 | end = graph.cities["Cannes"];
236 |
237 | var GPSheuristic = function(node0, node1) {
238 | return node0.GPS_distance(node1);
239 | };
240 |
241 | var result = astar.search(graph, start, end, {heuristic: GPSheuristic});
242 | equal(result.length, 3, "Cannes is 3 cities away from Paris");
243 | equal(result[0].name, "Lyon", "City #1 is Lyon");
244 | equal(result[1].name, "Marseille", "City #2 is Marseille");
245 | equal(result[2].name, "Cannes", "City #3 is Cannes");
246 | });
247 |
248 | // // https://gist.github.com/bgrins/581352
249 | // function runBasic() {
250 | // var graph = new Graph([
251 | // [1,1,1,1],
252 | // [0,1,1,0],
253 | // [0,0,1,1]
254 | // ]);
255 | // var start = graph.grid[0][0];
256 | // var end = graph.grid[1][2];
257 | // var result = astar.search(graph, start, end);
258 |
259 | // return "" + result.join(", ") + " ";
260 | // }
261 |
262 | // $(function() {
263 | // $("#runall").click(function() {
264 |
265 | // var result1 = runTest([
266 | // [1,1,1,1],
267 | // [0,1,1,0],
268 | // [0,0,1,1]
269 | // ], [0,0], [2,3]);
270 |
271 | // $("#test-output").append(result1.text);
272 | // $("#test-output").append(runBasic());
273 | // return false;
274 | // });
275 | // });
276 |
277 |
--------------------------------------------------------------------------------
/astar.js:
--------------------------------------------------------------------------------
1 | // javascript-astar 0.4.1
2 | // http://github.com/bgrins/javascript-astar
3 | // Freely distributable under the MIT License.
4 | // Implements the astar search algorithm in javascript using a Binary Heap.
5 | // Includes Binary Heap (with modifications) from Marijn Haverbeke.
6 | // http://eloquentjavascript.net/appendix2.html
7 | (function(definition) {
8 | /* global module, define */
9 | if (typeof module === 'object' && typeof module.exports === 'object') {
10 | module.exports = definition();
11 | } else if (typeof define === 'function' && define.amd) {
12 | define([], definition);
13 | } else {
14 | var exports = definition();
15 | window.astar = exports.astar;
16 | window.Graph = exports.Graph;
17 | }
18 | })(function() {
19 |
20 | function pathTo(node) {
21 | var curr = node;
22 | var path = [];
23 | while (curr.parent) {
24 | path.unshift(curr);
25 | curr = curr.parent;
26 | }
27 | return path;
28 | }
29 |
30 | function getHeap() {
31 | return new BinaryHeap(function(node) {
32 | return node.f;
33 | });
34 | }
35 |
36 | var astar = {
37 | /**
38 | * Perform an A* Search on a graph given a start and end node.
39 | * @param {Graph} graph
40 | * @param {GridNode} start
41 | * @param {GridNode} end
42 | * @param {Object} [options]
43 | * @param {bool} [options.closest] Specifies whether to return the
44 | path to the closest node if the target is unreachable.
45 | * @param {Function} [options.heuristic] Heuristic function (see
46 | * astar.heuristics).
47 | */
48 | search: function(graph, start, end, options) {
49 | graph.cleanDirty();
50 | options = options || {};
51 | var heuristic = options.heuristic || astar.heuristics.manhattan;
52 | var closest = options.closest || false;
53 |
54 | var openHeap = getHeap();
55 | var closestNode = start; // set the start node to be the closest if required
56 |
57 | start.h = heuristic(start, end);
58 | graph.markDirty(start);
59 |
60 | openHeap.push(start);
61 |
62 | while (openHeap.size() > 0) {
63 |
64 | // Grab the lowest f(x) to process next. Heap keeps this sorted for us.
65 | var currentNode = openHeap.pop();
66 |
67 | // End case -- result has been found, return the traced path.
68 | if (currentNode === end) {
69 | return pathTo(currentNode);
70 | }
71 |
72 | // Normal case -- move currentNode from open to closed, process each of its neighbors.
73 | currentNode.closed = true;
74 |
75 | // Find all neighbors for the current node.
76 | var neighbors = graph.neighbors(currentNode);
77 |
78 | for (var i = 0, il = neighbors.length; i < il; ++i) {
79 | var neighbor = neighbors[i];
80 |
81 | if (neighbor.closed || neighbor.isWall()) {
82 | // Not a valid node to process, skip to next neighbor.
83 | continue;
84 | }
85 |
86 | // The g score is the shortest distance from start to current node.
87 | // We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet.
88 | var gScore = currentNode.g + neighbor.getCost(currentNode);
89 | var beenVisited = neighbor.visited;
90 |
91 | if (!beenVisited || gScore < neighbor.g) {
92 |
93 | // Found an optimal (so far) path to this node. Take score for node to see how good it is.
94 | neighbor.visited = true;
95 | neighbor.parent = currentNode;
96 | neighbor.h = neighbor.h || heuristic(neighbor, end);
97 | neighbor.g = gScore;
98 | neighbor.f = neighbor.g + neighbor.h;
99 | graph.markDirty(neighbor);
100 | if (closest) {
101 | // If the neighbour is closer than the current closestNode or if it's equally close but has
102 | // a cheaper path than the current closest node then it becomes the closest node
103 | if (neighbor.h < closestNode.h || (neighbor.h === closestNode.h && neighbor.g < closestNode.g)) {
104 | closestNode = neighbor;
105 | }
106 | }
107 |
108 | if (!beenVisited) {
109 | // Pushing to heap will put it in proper place based on the 'f' value.
110 | openHeap.push(neighbor);
111 | } else {
112 | // Already seen the node, but since it has been rescored we need to reorder it in the heap
113 | openHeap.rescoreElement(neighbor);
114 | }
115 | }
116 | }
117 | }
118 |
119 | if (closest) {
120 | return pathTo(closestNode);
121 | }
122 |
123 | // No result was found - empty array signifies failure to find path.
124 | return [];
125 | },
126 | // See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html
127 | heuristics: {
128 | manhattan: function(pos0, pos1) {
129 | var d1 = Math.abs(pos1.x - pos0.x);
130 | var d2 = Math.abs(pos1.y - pos0.y);
131 | return d1 + d2;
132 | },
133 | diagonal: function(pos0, pos1) {
134 | var D = 1;
135 | var D2 = Math.sqrt(2);
136 | var d1 = Math.abs(pos1.x - pos0.x);
137 | var d2 = Math.abs(pos1.y - pos0.y);
138 | return (D * (d1 + d2)) + ((D2 - (2 * D)) * Math.min(d1, d2));
139 | }
140 | },
141 | cleanNode: function(node) {
142 | node.f = 0;
143 | node.g = 0;
144 | node.h = 0;
145 | node.visited = false;
146 | node.closed = false;
147 | node.parent = null;
148 | }
149 | };
150 |
151 | /**
152 | * A graph memory structure
153 | * @param {Array} gridIn 2D array of input weights
154 | * @param {Object} [options]
155 | * @param {bool} [options.diagonal] Specifies whether diagonal moves are allowed
156 | */
157 | function Graph(gridIn, options) {
158 | options = options || {};
159 | this.nodes = [];
160 | this.diagonal = !!options.diagonal;
161 | this.grid = [];
162 | for (var x = 0; x < gridIn.length; x++) {
163 | this.grid[x] = [];
164 |
165 | for (var y = 0, row = gridIn[x]; y < row.length; y++) {
166 | var node = new GridNode(x, y, row[y]);
167 | this.grid[x][y] = node;
168 | this.nodes.push(node);
169 | }
170 | }
171 | this.init();
172 | }
173 |
174 | Graph.prototype.init = function() {
175 | this.dirtyNodes = [];
176 | for (var i = 0; i < this.nodes.length; i++) {
177 | astar.cleanNode(this.nodes[i]);
178 | }
179 | };
180 |
181 | Graph.prototype.cleanDirty = function() {
182 | for (var i = 0; i < this.dirtyNodes.length; i++) {
183 | astar.cleanNode(this.dirtyNodes[i]);
184 | }
185 | this.dirtyNodes = [];
186 | };
187 |
188 | Graph.prototype.markDirty = function(node) {
189 | this.dirtyNodes.push(node);
190 | };
191 |
192 | Graph.prototype.neighbors = function(node) {
193 | var ret = [];
194 | var x = node.x;
195 | var y = node.y;
196 | var grid = this.grid;
197 |
198 | // West
199 | if (grid[x - 1] && grid[x - 1][y]) {
200 | ret.push(grid[x - 1][y]);
201 | }
202 |
203 | // East
204 | if (grid[x + 1] && grid[x + 1][y]) {
205 | ret.push(grid[x + 1][y]);
206 | }
207 |
208 | // South
209 | if (grid[x] && grid[x][y - 1]) {
210 | ret.push(grid[x][y - 1]);
211 | }
212 |
213 | // North
214 | if (grid[x] && grid[x][y + 1]) {
215 | ret.push(grid[x][y + 1]);
216 | }
217 |
218 | if (this.diagonal) {
219 | // Southwest
220 | if (grid[x - 1] && grid[x - 1][y - 1]) {
221 | ret.push(grid[x - 1][y - 1]);
222 | }
223 |
224 | // Southeast
225 | if (grid[x + 1] && grid[x + 1][y - 1]) {
226 | ret.push(grid[x + 1][y - 1]);
227 | }
228 |
229 | // Northwest
230 | if (grid[x - 1] && grid[x - 1][y + 1]) {
231 | ret.push(grid[x - 1][y + 1]);
232 | }
233 |
234 | // Northeast
235 | if (grid[x + 1] && grid[x + 1][y + 1]) {
236 | ret.push(grid[x + 1][y + 1]);
237 | }
238 | }
239 |
240 | return ret;
241 | };
242 |
243 | Graph.prototype.toString = function() {
244 | var graphString = [];
245 | var nodes = this.grid;
246 | for (var x = 0; x < nodes.length; x++) {
247 | var rowDebug = [];
248 | var row = nodes[x];
249 | for (var y = 0; y < row.length; y++) {
250 | rowDebug.push(row[y].weight);
251 | }
252 | graphString.push(rowDebug.join(" "));
253 | }
254 | return graphString.join("\n");
255 | };
256 |
257 | function GridNode(x, y, weight) {
258 | this.x = x;
259 | this.y = y;
260 | this.weight = weight;
261 | }
262 |
263 | GridNode.prototype.toString = function() {
264 | return "[" + this.x + " " + this.y + "]";
265 | };
266 |
267 | GridNode.prototype.getCost = function(fromNeighbor) {
268 | // Take diagonal weight into consideration.
269 | if (fromNeighbor && fromNeighbor.x != this.x && fromNeighbor.y != this.y) {
270 | return this.weight * 1.41421;
271 | }
272 | return this.weight;
273 | };
274 |
275 | GridNode.prototype.isWall = function() {
276 | return this.weight === 0;
277 | };
278 |
279 | function BinaryHeap(scoreFunction) {
280 | this.content = [];
281 | this.scoreFunction = scoreFunction;
282 | }
283 |
284 | BinaryHeap.prototype = {
285 | push: function(element) {
286 | // Add the new element to the end of the array.
287 | this.content.push(element);
288 |
289 | // Allow it to sink down.
290 | this.sinkDown(this.content.length - 1);
291 | },
292 | pop: function() {
293 | // Store the first element so we can return it later.
294 | var result = this.content[0];
295 | // Get the element at the end of the array.
296 | var end = this.content.pop();
297 | // If there are any elements left, put the end element at the
298 | // start, and let it bubble up.
299 | if (this.content.length > 0) {
300 | this.content[0] = end;
301 | this.bubbleUp(0);
302 | }
303 | return result;
304 | },
305 | remove: function(node) {
306 | var i = this.content.indexOf(node);
307 |
308 | // When it is found, the process seen in 'pop' is repeated
309 | // to fill up the hole.
310 | var end = this.content.pop();
311 |
312 | if (i !== this.content.length - 1) {
313 | this.content[i] = end;
314 |
315 | if (this.scoreFunction(end) < this.scoreFunction(node)) {
316 | this.sinkDown(i);
317 | } else {
318 | this.bubbleUp(i);
319 | }
320 | }
321 | },
322 | size: function() {
323 | return this.content.length;
324 | },
325 | rescoreElement: function(node) {
326 | this.sinkDown(this.content.indexOf(node));
327 | },
328 | sinkDown: function(n) {
329 | // Fetch the element that has to be sunk.
330 | var element = this.content[n];
331 |
332 | // When at 0, an element can not sink any further.
333 | while (n > 0) {
334 |
335 | // Compute the parent element's index, and fetch it.
336 | var parentN = ((n + 1) >> 1) - 1;
337 | var parent = this.content[parentN];
338 | // Swap the elements if the parent is greater.
339 | if (this.scoreFunction(element) < this.scoreFunction(parent)) {
340 | this.content[parentN] = element;
341 | this.content[n] = parent;
342 | // Update 'n' to continue at the new position.
343 | n = parentN;
344 | }
345 | // Found a parent that is less, no need to sink any further.
346 | else {
347 | break;
348 | }
349 | }
350 | },
351 | bubbleUp: function(n) {
352 | // Look up the target element and its score.
353 | var length = this.content.length;
354 | var element = this.content[n];
355 | var elemScore = this.scoreFunction(element);
356 |
357 | while (true) {
358 | // Compute the indices of the child elements.
359 | var child2N = (n + 1) << 1;
360 | var child1N = child2N - 1;
361 | // This is used to store the new position of the element, if any.
362 | var swap = null;
363 | var child1Score;
364 | // If the first child exists (is inside the array)...
365 | if (child1N < length) {
366 | // Look it up and compute its score.
367 | var child1 = this.content[child1N];
368 | child1Score = this.scoreFunction(child1);
369 |
370 | // If the score is less than our element's, we need to swap.
371 | if (child1Score < elemScore) {
372 | swap = child1N;
373 | }
374 | }
375 |
376 | // Do the same checks for the other child.
377 | if (child2N < length) {
378 | var child2 = this.content[child2N];
379 | var child2Score = this.scoreFunction(child2);
380 | if (child2Score < (swap === null ? elemScore : child1Score)) {
381 | swap = child2N;
382 | }
383 | }
384 |
385 | // If the element needs to be moved, swap it, and continue.
386 | if (swap !== null) {
387 | this.content[n] = this.content[swap];
388 | this.content[swap] = element;
389 | n = swap;
390 | }
391 | // Otherwise, we are done.
392 | else {
393 | break;
394 | }
395 | }
396 | }
397 | };
398 |
399 | return {
400 | astar: astar,
401 | Graph: Graph
402 | };
403 |
404 | });
--------------------------------------------------------------------------------
/demo/demo.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height:100%;
3 | margin:0;
4 | }
5 | body {
6 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
7 | color: #222;
8 | }
9 |
10 | .clearfix {
11 | *zoom: 1;
12 | }
13 | .clearfix:before, .clearfix:after {
14 | display: table;
15 | content: "";
16 | }
17 | .clearfix:after {
18 | clear: both;
19 | }
20 | h2 {
21 | font-weight:normal;
22 | }
23 | .links {
24 | clear:both;
25 | background: rgba(0, 0, 0, .1);
26 | padding: 4px;
27 | padding-left: 20px;
28 | padding-bottom:5px;
29 | }
30 | .links a {
31 | padding: 3px;
32 | color: #339;
33 | }
34 | .buttons {
35 | float:right;
36 | position:relative;
37 | right: 10px;
38 | top: 10px;
39 | }
40 | .buttons a {
41 | text-decoration: none;
42 | }
43 |
44 | #graph {
45 | overflow-x:scroll;
46 | width: 90%;
47 | font-size: .8em;
48 | margin:0 auto;
49 | white-space:pre;
50 | border:none;
51 | }
52 | #content {
53 | margin:0 auto;
54 | width:98%;
55 | }
56 | #header, #footer {
57 | background:#ddf;
58 | }
59 | #header h1 {
60 | margin:0;
61 | float:left;
62 | margin-bottom: 10px;
63 | margin-left: 5px;
64 | }
65 | #header {
66 | border-bottom:solid 8px #333;
67 | margin-bottom:15px;
68 | position: relative;
69 | }
70 | #footer {
71 | border-top:solid 2px #fff;
72 | margin-top:20px;
73 | padding-top:5px;
74 | }
75 | #header a, #footer a {
76 | font-size:.9em;
77 | font-family: Georgia;
78 | }
79 | ul.basics {
80 | list-style-type:none;
81 | }
82 | ul.basics li {
83 | margin-bottom: .45em;
84 | }
85 | .result-panel {
86 | width:80%;
87 | padding:10px;
88 | margin:10px;
89 | -moz-border-radius: 5px;
90 | -webkit-border-radius: 5px;
91 | border: 1px solid #000;
92 | }
93 | pre {
94 | padding-left:10px;
95 | border-left: solid 5px #99b;
96 | }
97 | .result-panel pre {
98 | border-left: solid 5px #b99;
99 | }
100 | .result-panel pre span {
101 | font-size:1.4em;
102 | color: #f11;
103 | font-weight:bold;
104 | }
105 | pre span.key {
106 | color: #f11;
107 | font-weight:normal;
108 | }
109 |
110 |
111 | .left {
112 | float:left;
113 | }
114 | .right {
115 | float: right;
116 | }
117 | .clear:after {
118 | content: ".";
119 | display: block;
120 | height: 0;
121 | clear: both;
122 | visibility: hidden;
123 | }
124 |
125 | #message {
126 | color:#f00;
127 | font-size:1.2em;
128 | }
129 | #controls {
130 | border: dashed 3px #9999BB;
131 | border-left:none;
132 | border-right:none;
133 | margin-bottom: 25px;
134 | padding:5px 0;
135 | width:650px;
136 | }
137 | #search_grid {
138 | width:650px;
139 | height:650px;
140 | position: relative;
141 | }
142 |
143 | .grid_item {
144 | display: block;
145 | border: 1px solid #bbb;
146 | float: left;
147 | line-height:12px;
148 | font-size:10px;
149 | }
150 | .grid_item.wall {
151 | background-color: #000000;
152 | }
153 | .grid_item.weight1 {
154 | background-color: #ffffff;
155 | }
156 | .grid_item.weight3 {
157 | background-color: #D6EAFF;
158 | }
159 | .grid_item.weight5 {
160 | background-color: #ABD1FF;
161 | }
162 | .grid_item.start {
163 | background-color: #FF703F;
164 | }
165 | .grid_item.active {
166 | background-color: #FF703F;
167 | }
168 | .grid_item.finish {
169 |
170 | }
171 | #weightsKey {
172 | display: none;
173 | }
174 |
175 | .btn {
176 | display: inline-block;
177 | padding: 4px 10px 4px;
178 | margin-bottom: 0;
179 | font-size: 13px;
180 | line-height: 18px;
181 | color: #333333;
182 | text-align: center;
183 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
184 | vertical-align: middle;
185 | background-color: #f5f5f5;
186 | background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
187 | background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
188 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
189 | background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
190 | background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
191 | background-image: linear-gradient(top, #ffffff, #e6e6e6);
192 | background-repeat: repeat-x;
193 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
194 | border-color: #e6e6e6 #e6e6e6 #bfbfbf;
195 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
196 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
197 | border: 1px solid #ccc;
198 | border-bottom-color: #bbb;
199 | -webkit-border-radius: 4px;
200 | -moz-border-radius: 4px;
201 | border-radius: 4px;
202 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
203 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
204 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
205 | cursor: pointer;
206 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
207 | *margin-left: .3em;
208 | }
209 | .btn:hover,
210 | .btn:active,
211 | .btn.active,
212 | .btn.disabled,
213 | .btn[disabled] {
214 | background-color: #e6e6e6;
215 | }
216 | .btn:active, .btn.active {
217 | background-color: #cccccc \9;
218 | }
219 | .btn:first-child {
220 | *margin-left: 0;
221 | }
222 | .btn:hover {
223 | color: #333333;
224 | text-decoration: none;
225 | background-color: #e6e6e6;
226 | background-position: 0 -15px;
227 | -webkit-transition: background-position 0.1s linear;
228 | -moz-transition: background-position 0.1s linear;
229 | -ms-transition: background-position 0.1s linear;
230 | -o-transition: background-position 0.1s linear;
231 | transition: background-position 0.1s linear;
232 | }
233 | .btn:focus {
234 | outline: thin dotted #333;
235 | outline: 5px auto -webkit-focus-ring-color;
236 | outline-offset: -2px;
237 | }
238 | .btn.active, .btn:active {
239 | background-image: none;
240 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
241 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
242 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
243 | background-color: #e6e6e6;
244 | background-color: #d9d9d9 \9;
245 | outline: 0;
246 | }
247 | .btn.disabled, .btn[disabled] {
248 | cursor: default;
249 | background-image: none;
250 | background-color: #e6e6e6;
251 | opacity: 0.65;
252 | filter: alpha(opacity=65);
253 | -webkit-box-shadow: none;
254 | -moz-box-shadow: none;
255 | box-shadow: none;
256 | }
257 | .btn-large {
258 | padding: 9px 14px;
259 | font-size: 15px;
260 | line-height: normal;
261 | -webkit-border-radius: 5px;
262 | -moz-border-radius: 5px;
263 | border-radius: 5px;
264 | }
265 | .btn-large [class^="icon-"] {
266 | margin-top: 1px;
267 | }
268 | .btn-small {
269 | padding: 5px 9px;
270 | font-size: 11px;
271 | line-height: 16px;
272 | }
273 | .btn-small [class^="icon-"] {
274 | margin-top: -1px;
275 | }
276 | .btn-mini {
277 | padding: 2px 6px;
278 | font-size: 11px;
279 | line-height: 14px;
280 | }
281 | .btn-primary,
282 | .btn-primary:hover,
283 | .btn-warning,
284 | .btn-warning:hover,
285 | .btn-danger,
286 | .btn-danger:hover,
287 | .btn-success,
288 | .btn-success:hover,
289 | .btn-info,
290 | .btn-info:hover,
291 | .btn-inverse,
292 | .btn-inverse:hover {
293 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
294 | color: #ffffff;
295 | }
296 | .btn-primary.active,
297 | .btn-warning.active,
298 | .btn-danger.active,
299 | .btn-success.active,
300 | .btn-info.active,
301 | .btn-dark.active {
302 | color: rgba(255, 255, 255, 0.75);
303 | }
304 | .btn-primary {
305 | background-color: #006dcc;
306 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
307 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
308 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
309 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
310 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
311 | background-image: linear-gradient(top, #0088cc, #0044cc);
312 | background-repeat: repeat-x;
313 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
314 | border-color: #0044cc #0044cc #002a80;
315 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
316 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
317 | }
318 | .btn-primary:hover,
319 | .btn-primary:active,
320 | .btn-primary.active,
321 | .btn-primary.disabled,
322 | .btn-primary[disabled] {
323 | background-color: #0044cc;
324 | }
325 | .btn-primary:active, .btn-primary.active {
326 | background-color: #003399 \9;
327 | }
328 | .btn-warning {
329 | background-color: #faa732;
330 | background-image: -moz-linear-gradient(top, #fbb450, #f89406);
331 | background-image: -ms-linear-gradient(top, #fbb450, #f89406);
332 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
333 | background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
334 | background-image: -o-linear-gradient(top, #fbb450, #f89406);
335 | background-image: linear-gradient(top, #fbb450, #f89406);
336 | background-repeat: repeat-x;
337 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
338 | border-color: #f89406 #f89406 #ad6704;
339 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
340 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
341 | }
342 | .btn-warning:hover,
343 | .btn-warning:active,
344 | .btn-warning.active,
345 | .btn-warning.disabled,
346 | .btn-warning[disabled] {
347 | background-color: #f89406;
348 | }
349 | .btn-warning:active, .btn-warning.active {
350 | background-color: #c67605 \9;
351 | }
352 | .btn-danger {
353 | background-color: #da4f49;
354 | background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
355 | background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);
356 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
357 | background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
358 | background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
359 | background-image: linear-gradient(top, #ee5f5b, #bd362f);
360 | background-repeat: repeat-x;
361 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);
362 | border-color: #bd362f #bd362f #802420;
363 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
364 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
365 | }
366 | .btn-danger:hover,
367 | .btn-danger:active,
368 | .btn-danger.active,
369 | .btn-danger.disabled,
370 | .btn-danger[disabled] {
371 | background-color: #bd362f;
372 | }
373 | .btn-danger:active, .btn-danger.active {
374 | background-color: #942a25 \9;
375 | }
376 | .btn-success {
377 | background-color: #5bb75b;
378 | background-image: -moz-linear-gradient(top, #62c462, #51a351);
379 | background-image: -ms-linear-gradient(top, #62c462, #51a351);
380 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
381 | background-image: -webkit-linear-gradient(top, #62c462, #51a351);
382 | background-image: -o-linear-gradient(top, #62c462, #51a351);
383 | background-image: linear-gradient(top, #62c462, #51a351);
384 | background-repeat: repeat-x;
385 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);
386 | border-color: #51a351 #51a351 #387038;
387 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
388 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
389 | }
390 | .btn-success:hover,
391 | .btn-success:active,
392 | .btn-success.active,
393 | .btn-success.disabled,
394 | .btn-success[disabled] {
395 | background-color: #51a351;
396 | }
397 | .btn-success:active, .btn-success.active {
398 | background-color: #408140 \9;
399 | }
400 | .btn-info {
401 | background-color: #49afcd;
402 | background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
403 | background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);
404 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
405 | background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
406 | background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
407 | background-image: linear-gradient(top, #5bc0de, #2f96b4);
408 | background-repeat: repeat-x;
409 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);
410 | border-color: #2f96b4 #2f96b4 #1f6377;
411 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
412 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
413 | }
414 | .btn-info:hover,
415 | .btn-info:active,
416 | .btn-info.active,
417 | .btn-info.disabled,
418 | .btn-info[disabled] {
419 | background-color: #2f96b4;
420 | }
421 | .btn-info:active, .btn-info.active {
422 | background-color: #24748c \9;
423 | }
424 | .btn-inverse {
425 | background-color: #393939;
426 | background-image: -moz-linear-gradient(top, #454545, #262626);
427 | background-image: -ms-linear-gradient(top, #454545, #262626);
428 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626));
429 | background-image: -webkit-linear-gradient(top, #454545, #262626);
430 | background-image: -o-linear-gradient(top, #454545, #262626);
431 | background-image: linear-gradient(top, #454545, #262626);
432 | background-repeat: repeat-x;
433 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0);
434 | border-color: #262626 #262626 #000000;
435 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
436 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
437 | }
438 | .btn-inverse:hover,
439 | .btn-inverse:active,
440 | .btn-inverse.active,
441 | .btn-inverse.disabled,
442 | .btn-inverse[disabled] {
443 | background-color: #262626;
444 | }
445 | .btn-inverse:active, .btn-inverse.active {
446 | background-color: #0c0c0c \9;
447 | }
448 | button.btn, input[type="submit"].btn {
449 | *padding-top: 2px;
450 | *padding-bottom: 2px;
451 | }
452 | button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner {
453 | padding: 0;
454 | border: 0;
455 | }
456 | button.btn.large, input[type="submit"].btn.large {
457 | *padding-top: 7px;
458 | *padding-bottom: 7px;
459 | }
460 | button.btn.small, input[type="submit"].btn.small {
461 | *padding-top: 3px;
462 | *padding-bottom: 3px;
463 | }
464 | .btn-group {
465 | position: relative;
466 | *zoom: 1;
467 | *margin-left: .3em;
468 | }
469 | .btn-group:before, .btn-group:after {
470 | display: table;
471 | content: "";
472 | }
473 | .btn-group:after {
474 | clear: both;
475 | }
476 | .btn-group:first-child {
477 | *margin-left: 0;
478 | }
479 | .btn-group + .btn-group {
480 | margin-left: 5px;
481 | }
482 | .btn-toolbar {
483 | margin-top: 9px;
484 | margin-bottom: 9px;
485 | }
486 | .btn-toolbar .btn-group {
487 | display: inline-block;
488 | *display: inline;
489 | /* IE7 inline-block hack */
490 |
491 | *zoom: 1;
492 | }
493 | .btn-group .btn {
494 | position: relative;
495 | float: left;
496 | margin-left: -1px;
497 | -webkit-border-radius: 0;
498 | -moz-border-radius: 0;
499 | border-radius: 0;
500 | }
501 | .btn-group .btn:first-child {
502 | margin-left: 0;
503 | -webkit-border-top-left-radius: 4px;
504 | -moz-border-radius-topleft: 4px;
505 | border-top-left-radius: 4px;
506 | -webkit-border-bottom-left-radius: 4px;
507 | -moz-border-radius-bottomleft: 4px;
508 | border-bottom-left-radius: 4px;
509 | }
510 | .btn-group .btn:last-child, .btn-group .dropdown-toggle {
511 | -webkit-border-top-right-radius: 4px;
512 | -moz-border-radius-topright: 4px;
513 | border-top-right-radius: 4px;
514 | -webkit-border-bottom-right-radius: 4px;
515 | -moz-border-radius-bottomright: 4px;
516 | border-bottom-right-radius: 4px;
517 | }
518 | .btn-group .btn.large:first-child {
519 | margin-left: 0;
520 | -webkit-border-top-left-radius: 6px;
521 | -moz-border-radius-topleft: 6px;
522 | border-top-left-radius: 6px;
523 | -webkit-border-bottom-left-radius: 6px;
524 | -moz-border-radius-bottomleft: 6px;
525 | border-bottom-left-radius: 6px;
526 | }
527 | .btn-group .btn.large:last-child, .btn-group .large.dropdown-toggle {
528 | -webkit-border-top-right-radius: 6px;
529 | -moz-border-radius-topright: 6px;
530 | border-top-right-radius: 6px;
531 | -webkit-border-bottom-right-radius: 6px;
532 | -moz-border-radius-bottomright: 6px;
533 | border-bottom-right-radius: 6px;
534 | }
535 | .btn-group .btn:hover,
536 | .btn-group .btn:focus,
537 | .btn-group .btn:active,
538 | .btn-group .btn.active {
539 | z-index: 2;
540 | }
541 | .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle {
542 | outline: 0;
543 | }
544 | .btn-group .dropdown-toggle {
545 | padding-left: 8px;
546 | padding-right: 8px;
547 | -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
548 | -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
549 | box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
550 | *padding-top: 5px;
551 | *padding-bottom: 5px;
552 | }
553 | .btn-group.open {
554 | *z-index: 1000;
555 | }
556 | .btn-group.open .dropdown-menu {
557 | display: block;
558 | margin-top: 1px;
559 | -webkit-border-radius: 5px;
560 | -moz-border-radius: 5px;
561 | border-radius: 5px;
562 | }
563 | .btn-group.open .dropdown-toggle {
564 | background-image: none;
565 | -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
566 | -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
567 | box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
568 | }
569 | .btn .caret {
570 | margin-top: 7px;
571 | margin-left: 0;
572 | }
573 | .btn:hover .caret, .open.btn-group .caret {
574 | opacity: 1;
575 | filter: alpha(opacity=100);
576 | }
577 | .btn-primary .caret,
578 | .btn-danger .caret,
579 | .btn-info .caret,
580 | .btn-success .caret,
581 | .btn-inverse .caret {
582 | border-top-color: #ffffff;
583 | opacity: 0.75;
584 | filter: alpha(opacity=75);
585 | }
586 | .btn-small .caret {
587 | margin-top: 4px;
588 | }
589 | .btn {
590 | text-decoration: underline;
591 | }
--------------------------------------------------------------------------------
/benchmark/grid_100x100.js:
--------------------------------------------------------------------------------
1 | var grid = [[1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1],[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1],[1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,0,1,0,1,1,0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],[1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1],[0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1],[1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1],[0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1],[1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1],[1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],[1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1],[1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0],[1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1],[1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1],[1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1],[1,1,0,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1],[1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0],[1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1],[1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,0,1,0,1,0,1,0,0,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1],[0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1],[1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0],[1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1],[1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0],[1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1],[1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1],[1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1],[1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1],[1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1],[1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1],[1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1],[1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,0,0,1,1,1,1,1],[1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1],[1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1],[1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]];
--------------------------------------------------------------------------------
/benchmark/grid_150x150.js:
--------------------------------------------------------------------------------
1 | var grid = [[1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,1],[1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1,1,0,1,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,1,1,0,1,0,0,1,0,0,1],[1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0],[0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,1,0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0],[1,0,1,0,0,0,0,1,1,1,0,0,1,1,0,1,1,1,0,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,0,1,1,1,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,0,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,0,1,0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1],[0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,0,0,1,1,0,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1],[1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,1,0,0,0,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,0,1,0,1,0,0,1,1,1,1],[1,1,0,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,0,0,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,0,1,1],[1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,0,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1],[1,1,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,0,0,1,0,1,1,1,1,0,0,1,1,1,1,1],[1,1,0,0,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,1,1,1,0,1,0,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,0,1,0,1,0],[1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,1,0,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,1,1,0,0,1,1,0,1,1],[0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,0,0,1,1,1,0,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,0,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,0,0,1,0,1,0,1,1,1,0,1,0,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,1,0,1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1],[1,1,0,1,1,0,1,1,1,1,0,1,0,1,0,0,0,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,0,1,1,0,0,0,1,0,1,1,0,1,1,0,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,0,1,0,0,1,1,0,1,1,0,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0],[1,1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,0,1,0,1,0,1,1,0,1,1,1,1,0],[1,0,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,0,1,0,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,1,1,0,0,1,1,1,0,0,1,0,1,1,1,1,0,1,1,1,0,0,0,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,1,0,0,0,0,0,1,1],[0,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0,1,1,1],[1,0,1,1,1,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,1,1,0,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0],[0,0,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,1,0,1,1,1,0,0,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0],[0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,1,0,0,0,1,1,1,0,1,1,1,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,0,0,1,0,0,1,1,1,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,1,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0],[0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,0,0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,0,1,1,1,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1],[1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,0,1,0,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1],[1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0,1,0,1,1,1,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,0,0,1,1,0,1,0,1,0,1,0,1,1,1,1,0,1,1],[1,1,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,0,1,0,1,1,1,1,0,0,0,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,0,1,1,0],[1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,0,0,1,0,1,1,0,1,0,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,1],[1,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,0,0,1,0,0,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1],[0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,1,1,1,0,1,1,1,1,0,1,0,1,0,1,1,1,1,0,1,1,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1],[1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,1,0,1,0,1,0,1,0,1,0,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1],[1,0,1,1,0,1,0,1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1,1,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,0,0,1,1,1,1,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0],[1,1,1,0,0,1,1,1,0,1,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,0,1,0,0,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,0,0,1,0,1,0,1,1,1,0,1],[1,0,0,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,1,1,1,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,0,1,1,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,1],[0,1,1,0,0,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,0,1,0,1,1,0,1,1,1,1,0,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,1,0,1,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1],[1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,1,0,1,0,1,1,0,1,1,1,0,1,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1],[1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,1,1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,0,0,0,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1],[1,1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0,0,0,1,1,0,1,1,1,1,0,1,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,0,0,0,1,0,1,1,1,1,0,1,0,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,0,0,1,1,0,0,1,1,1,1,0,0,1,1,1,0,1,1,0,1,0,1,1,0,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1],[0,0,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,0,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,0,1,0],[1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,0,1,1,1,0,1,0,1,0,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,0,1,0,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,0,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,0,1,0,1,0,1,0,0],[1,1,1,0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,0,1,1,1,0,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,0,0,1,0,0,1,0,1,0],[1,1,1,0,1,1,0,0,1,1,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,0,1,0,1,0,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0],[1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,0,0,1,1,0,1,0,0,0,0,1,1,1,1,1,0,1,1,0,0,1,0,1,0,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,1,1,1,0,0,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0],[1,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,0,0,0,0,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1,0,0,0,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1],[1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,0,0,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,0,1,0,1,1,1,0,0,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,0,1,0],[1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,0,0,1,0,1,0,1,1,1,1,0,0,0,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,0,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,0,1,1,0,0,1,0,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,0,0,1,1,1,1],[1,0,1,1,1,0,1,0,0,0,1,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,1,0,0,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,1,0,0,1,0,1,1,1,1,1,1],[1,1,0,1,0,0,1,0,1,1,1,0,1,1,0,0,1,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0],[0,1,1,1,0,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,0,0,0,1,1,1,0,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,1,0,1,0,0,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,0,0,1,0,1],[0,1,1,1,0,0,1,0,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,0,1,0,1,1,1,0,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,0,0,1,0,1,0,1,1,0,1,0,1,1,1,1,0,0,0,0,0,0,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,0,1,0,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1,1],[0,0,1,1,1,1,1,0,1,1,1,1,0,1,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,0,0,1,1,1,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,0,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,0,1],[0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,0,1,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,1,0,1,1,1,1,0,0,1,1,0],[0,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,0,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,1,1,1,1],[1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,0,1,1,1,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0,1,1,1,0,1,1,0,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,0,1,0,0,0],[1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,0,0,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1],[0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,0,1,1,1,0,1,0,0,0,1,1,0,0,1,0,1,0,1,1,0,1,0,0,1,1,1,0,0,1,0,1,1,0,0,1,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,1,0,1,0,1,1,1,1,1],[1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,0,0,0,1,1,1,1,0,1,1,0,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,1,0,1,1,1,0,1,1,1],[0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1],[1,1,0,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,0,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,1,0,1,0,1,0,1,1],[1,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,1,1,1],[0,1,0,1,0,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,1,1,0,1,1,0],[1,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,0,1,0,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1],[1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,1,1,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,0,0,1,0,0,0,0,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,0,1,0,1,1,0,1,1,1,0,1,1,0,0,0,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,0],[1,0,1,1,1,1,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1],[1,1,0,1,1,0,1,1,1,0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,1,0,1,1,1,1,0,1,1,1,1,1,1,0,0,1,0,0,1,0,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,1],[1,1,1,1,1,0,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,0,1,1],[1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0,1,1,1,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1],[1,1,0,0,1,0,0,1,1,1,0,0,1,0,1,1,1,0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,0,1,1,0,0,1,0,0,1,1,1,1,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,0,1,1,1,1,0,1,1],[0,1,1,0,1,1,0,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,0,1,1,0,1,0,0,0,0,0,1,1,0,1,0,1,0,0,1,1,0,0,1,0,1,1,1,1,1,1,0,1,0,0,1,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,0],[0,1,1,1,1,0,1,1,0,1,0,1,1,0,1,0,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,0,1,1,1,1,1,0,0,1,1,1],[1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,1,1,1,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,0,1,0,0,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,1,1,0,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1],[1,1,0,1,1,0,1,1,1,0,1,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,0,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,0,0,0,0,1,1,0,1,0,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1],[1,0,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0],[1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,0,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,0,1,0,0,0,0,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,1,0,0,1,0,0,0,1,1,0,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1],[1,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1],[1,1,0,1,1,0,1,1,0,1,1,1,0,1,0,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,0,1,0,1,1,1,1,0,0,1,0,0,0,1,0,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,1,0,1,1,0,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,1],[0,0,0,1,1,1,0,0,1,0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,1,0,1,1,1,0,0,1,0,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,0],[1,1,0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,0,1,0,0,0,1,0,0,1,1,0,1,0,1,1,0,1,0,0,1,0,0,1,0,1,1,0,1,0,0,0,1,1,1,0,1,1,1,0,1,1,1,1],[1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,0,0,0,0],[1,0,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,0,0,1,0,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,1,1,1,0,1,0,0,0,1,0,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0],[1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,0,1,0,0,0,0,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,0,0,1,1,1,1,0,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,0,1,0,1,0,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1],[1,0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,0,0,0,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,0,1,1,0,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1],[1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,0,0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,0,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1],[1,1,1,1,1,1,1,1,0,0,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,1,0,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,1,1,1,1,1,0,1,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1],[1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1],[0,1,1,1,1,0,0,1,1,1,1,0,0,0,0,1,0,0,1,1,1,0,1,1,0,1,1,1,0,1,0,0,0,0,1,0,0,0,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0],[0,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,1,0,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,1,1],[1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,0,0,0,1,1],[1,0,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,0,1,0,0,0,1,0,1,1,0,0,1,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1],[0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,0,0,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,1,0,1,1,0,0,1,1,1,0,1,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,0,1,1,1,1,1,0,1,1,1],[0,1,1,1,1,0,0,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,1,0,0,1,1,0,0,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,0,0,0,1,1,1,0,0,1,0,0,0,1,1,0,0,0,1,1,0,0,1,1,0,0,0,0,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,0,1,1,0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0,0,0,1,0,1],[1,1,0,0,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1],[0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,0,1,0,1,0,0,1,0,1,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,0],[1,1,0,0,1,0,1,0,0,0,1,1,1,1,0,0,1,0,0,1,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0],[1,0,1,0,0,1,1,0,1,0,1,1,1,0,1,0,0,0,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,0,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,1,1,0,0,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,0,1,1,1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,1],[1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,0,0,0,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,0,0,0,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1,0,1,0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,1,1],[0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,0,1,0,1,1,0,0,1,1,1,0,1,1,1,0,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,0,1,1,0,1,1,1,0,1,1,1],[1,1,0,1,1,1,0,0,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,0,1,1,0,1,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,0,1,0,0,1,1],[1,0,1,0,1,0,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,0,0,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1],[1,0,1,0,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0,1,1,1,1,0,1,0,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,0,0,1],[0,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,0,1,0,1,1,1,0,0,0,1,0,1,1,0,1,1,0,1,0,0,1,1,1,1,1,0,1,0,0,1,0,0,1,1,0,1,0,0,1,1,0,0,0],[0,1,1,0,1,1,1,0,1,1,1,1,1,0,0,0,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,0,0,1,1,0,1,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1],[0,1,1,0,0,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,1,0,1,1,0,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1],[0,0,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,1,1,0,1,1,0,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0],[0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,0,0,1,0,0,1,0,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,1,0,1,1,1],[1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,1,1,0,0,1,0,1,0,1,1,1,0,1,1,0,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0],[1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,0,1,0,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,0,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,0,1,0,1,1,0,1,1,0,1,0,1,0,1,1,1,0,1,1,0,1,1,1,1,0,0,1,0,1,1,1,0,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,1,1,0,0,0,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,0,0,0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,1,1,0,1,1,0,1,0,0,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,0,1,0,1,1],[1,1,0,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,0,1,1,1,1,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1],[0,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,0,1,1,1,0,0,1,1,0,1,1,0,0,0,1,0,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,0,0,1,0,1],[0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,1,0,1,0,1,0,1,1,1,0,1,0,1,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1],[1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,0,0,0,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,0,0,1,1,1,1,0,1,0,1,0,0,1,1,1,0,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,0,0,0,0,0,1,0,1,0,1,1,0,1,1],[1,1,1,1,1,0,0,1,1,1,1,0,0,0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,0,1,0,0,1,1,1,0,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,0],[1,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,1,1],[1,0,0,0,1,1,0,0,1,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,1,1,0,0,1,0],[1,0,1,0,1,0,0,1,1,0,1,1,0,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,0,0,1,1,1,0,1,1,1,0,1,0,0,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,0],[1,1,1,0,0,0,1,0,1,1,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,0,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,0,0,1,1,1,0,0,1,0,1,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,0,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1],[1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,0,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,0],[1,0,1,1,0,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,0,1,1,1,0,0,1,0,0,0,1,1,1,1,0,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,1,1,1,1,0,0,1,0,0,0,0,1,1,0,0,1,1,1,1,0,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,1,1,1,0],[1,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,1,0,1,1,1,1,1,1,0,0,0,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,0,0,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1],[0,1,1,0,1,0,1,0,0,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,0,1,1,1,0,1,0,0,1,1,1,1,1,0,0,1,1,1,0,1,0,1,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,0,1,0,0,1,1,1,1],[0,1,0,1,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,1,1,0,0,1,0,1,1,1,1,0,0,0,0,1,1,0,1,0,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0,0,1,1,0,1,1,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,1,0,0,0,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1],[1,0,1,1,1,1,1,0,1,0,1,0,1,1,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,0],[1,1,0,1,0,1,1,1,1,1,0,0,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,1,0,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,0,0,1,1,1,0],[1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1,0,1,1,1,0,0,0,0,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0],[0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,0,1,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,1,1,0,0,0,1,0,1,0,1,1,0,1,1,1,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1],[1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1],[1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,1,1,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,0,1,0,1,1,1,0,0],[1,0,1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1,1,1,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,0,0,1,0,1,1,0,1,0,0,0,1,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0,1,0,1,1,0,0,1,1,0,1,1,0,1,1,0,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0],[1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,0,1,0,1,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,0,0,0,1,1,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,1,0,1,0,0,1,1,0,0,0,1,0,1,1,1,1],[1,0,1,0,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,0,1,0,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1],[1,0,1,1,1,1,1,1,0,1,1,0,0,0,1,0,1,1,0,1,1,1,1,0,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,0,0,1,1,1,0,1,0,1,1,1,0,1,1,0,0,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,1],[0,1,0,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,0,1,0,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,1,0,1,0,1,0,0,1,1,0,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1],[1,0,0,0,1,0,0,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,0,1,1,1,1,1,0,0,0,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0,0,1,1,1,1,0,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1],[1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,0,1,1,0,1,0,1,0,0,1,1,1,1,1],[1,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,1,0,1,0,0,1,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,0,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,1,1,1],[1,1,1,0,1,1,1,1,0,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,1,1,1,0,1,1,1,1,1,1,1,0,0,0,1,1,1,1,0,1,0,1,0,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1],[0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,0,1,1,0,0,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,0,0,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,1,1,0,0,1,1,0,0,1,1,0,1,0,1,0,1,0,1],[1,0,1,0,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,1,0,0,1,0,0,1,0],[0,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,0,1,1,1,1,0],[1,1,0,1,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,0,1,0,0,1,0,1,1,1,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1,0,0,1,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1],[0,1,1,1,1,0,0,1,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,1,1,1,0,1,0,0,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0,1,1,1,1,0,0],[1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,0,1,0,1,1,1,1,0,0,1,1,1,1,0,1],[0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,0,1,0,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,0,1,1,0,0,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,0,1,0,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,1,0,0,0,1,0,1,1,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,0,0,0,1,1,1,1],[1,0,0,1,1,0,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,0,1,1,0,1,0,1,1,1,0,1,1,0,1,1,1,1,0,1,1,1,1,0,0,1,1,0,1,1,1,1,0,1,0,1,1,0,1,0,1,1,0,0,0,1,0,1,1],[1,1,1,1,1,0,1,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,0,0,0,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,1,1,0,1,1,1,0,0,0,1,1,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1],[1,1,0,1,1,1,0,1,1,0,0,1,1,0,0,1,0,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,1,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,0,1,0,0,1,1,1,1,0,0,1,1,1,1,1,0,1,0,1,0,0,0,1,1,0,1,1,1,1,1,1,0,1,0,0,1,0,1,1,0],[0,1,1,0,1,1,1,0,0,1,0,1,1,1,1,0,0,0,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,0,0,1,0,0,1,1,1,1,1,1,1,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,0,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,0,0,1],[1,0,1,0,1,1,1,0,1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,1,0,0,1,1,1,0,1,1,1,1,1,0,0,1,0,0,1,0,1,0,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,0,0,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,0,1]];
--------------------------------------------------------------------------------
/test/qunit.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * QUnit 1.14.0
3 | * http://qunitjs.com/
4 | *
5 | * Copyright 2013 jQuery Foundation and other contributors
6 | * Released under the MIT license
7 | * http://jquery.org/license
8 | *
9 | * Date: 2014-01-31T16:40Z
10 | */
11 |
12 | (function( window ) {
13 |
14 | var QUnit,
15 | assert,
16 | config,
17 | onErrorFnPrev,
18 | testId = 0,
19 | fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
20 | toString = Object.prototype.toString,
21 | hasOwn = Object.prototype.hasOwnProperty,
22 | // Keep a local reference to Date (GH-283)
23 | Date = window.Date,
24 | setTimeout = window.setTimeout,
25 | clearTimeout = window.clearTimeout,
26 | defined = {
27 | document: typeof window.document !== "undefined",
28 | setTimeout: typeof window.setTimeout !== "undefined",
29 | sessionStorage: (function() {
30 | var x = "qunit-test-string";
31 | try {
32 | sessionStorage.setItem( x, x );
33 | sessionStorage.removeItem( x );
34 | return true;
35 | } catch( e ) {
36 | return false;
37 | }
38 | }())
39 | },
40 | /**
41 | * Provides a normalized error string, correcting an issue
42 | * with IE 7 (and prior) where Error.prototype.toString is
43 | * not properly implemented
44 | *
45 | * Based on http://es5.github.com/#x15.11.4.4
46 | *
47 | * @param {String|Error} error
48 | * @return {String} error message
49 | */
50 | errorString = function( error ) {
51 | var name, message,
52 | errorString = error.toString();
53 | if ( errorString.substring( 0, 7 ) === "[object" ) {
54 | name = error.name ? error.name.toString() : "Error";
55 | message = error.message ? error.message.toString() : "";
56 | if ( name && message ) {
57 | return name + ": " + message;
58 | } else if ( name ) {
59 | return name;
60 | } else if ( message ) {
61 | return message;
62 | } else {
63 | return "Error";
64 | }
65 | } else {
66 | return errorString;
67 | }
68 | },
69 | /**
70 | * Makes a clone of an object using only Array or Object as base,
71 | * and copies over the own enumerable properties.
72 | *
73 | * @param {Object} obj
74 | * @return {Object} New object with only the own properties (recursively).
75 | */
76 | objectValues = function( obj ) {
77 | // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
78 | /*jshint newcap: false */
79 | var key, val,
80 | vals = QUnit.is( "array", obj ) ? [] : {};
81 | for ( key in obj ) {
82 | if ( hasOwn.call( obj, key ) ) {
83 | val = obj[key];
84 | vals[key] = val === Object(val) ? objectValues(val) : val;
85 | }
86 | }
87 | return vals;
88 | };
89 |
90 |
91 | // Root QUnit object.
92 | // `QUnit` initialized at top of scope
93 | QUnit = {
94 |
95 | // call on start of module test to prepend name to all tests
96 | module: function( name, testEnvironment ) {
97 | config.currentModule = name;
98 | config.currentModuleTestEnvironment = testEnvironment;
99 | config.modules[name] = true;
100 | },
101 |
102 | asyncTest: function( testName, expected, callback ) {
103 | if ( arguments.length === 2 ) {
104 | callback = expected;
105 | expected = null;
106 | }
107 |
108 | QUnit.test( testName, expected, callback, true );
109 | },
110 |
111 | test: function( testName, expected, callback, async ) {
112 | var test,
113 | nameHtml = "" + escapeText( testName ) + " ";
114 |
115 | if ( arguments.length === 2 ) {
116 | callback = expected;
117 | expected = null;
118 | }
119 |
120 | if ( config.currentModule ) {
121 | nameHtml = "" + escapeText( config.currentModule ) + " : " + nameHtml;
122 | }
123 |
124 | test = new Test({
125 | nameHtml: nameHtml,
126 | testName: testName,
127 | expected: expected,
128 | async: async,
129 | callback: callback,
130 | module: config.currentModule,
131 | moduleTestEnvironment: config.currentModuleTestEnvironment,
132 | stack: sourceFromStacktrace( 2 )
133 | });
134 |
135 | if ( !validTest( test ) ) {
136 | return;
137 | }
138 |
139 | test.queue();
140 | },
141 |
142 | // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
143 | expect: function( asserts ) {
144 | if (arguments.length === 1) {
145 | config.current.expected = asserts;
146 | } else {
147 | return config.current.expected;
148 | }
149 | },
150 |
151 | start: function( count ) {
152 | // QUnit hasn't been initialized yet.
153 | // Note: RequireJS (et al) may delay onLoad
154 | if ( config.semaphore === undefined ) {
155 | QUnit.begin(function() {
156 | // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
157 | setTimeout(function() {
158 | QUnit.start( count );
159 | });
160 | });
161 | return;
162 | }
163 |
164 | config.semaphore -= count || 1;
165 | // don't start until equal number of stop-calls
166 | if ( config.semaphore > 0 ) {
167 | return;
168 | }
169 | // ignore if start is called more often then stop
170 | if ( config.semaphore < 0 ) {
171 | config.semaphore = 0;
172 | QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
173 | return;
174 | }
175 | // A slight delay, to avoid any current callbacks
176 | if ( defined.setTimeout ) {
177 | setTimeout(function() {
178 | if ( config.semaphore > 0 ) {
179 | return;
180 | }
181 | if ( config.timeout ) {
182 | clearTimeout( config.timeout );
183 | }
184 |
185 | config.blocking = false;
186 | process( true );
187 | }, 13);
188 | } else {
189 | config.blocking = false;
190 | process( true );
191 | }
192 | },
193 |
194 | stop: function( count ) {
195 | config.semaphore += count || 1;
196 | config.blocking = true;
197 |
198 | if ( config.testTimeout && defined.setTimeout ) {
199 | clearTimeout( config.timeout );
200 | config.timeout = setTimeout(function() {
201 | QUnit.ok( false, "Test timed out" );
202 | config.semaphore = 1;
203 | QUnit.start();
204 | }, config.testTimeout );
205 | }
206 | }
207 | };
208 |
209 | // We use the prototype to distinguish between properties that should
210 | // be exposed as globals (and in exports) and those that shouldn't
211 | (function() {
212 | function F() {}
213 | F.prototype = QUnit;
214 | QUnit = new F();
215 | // Make F QUnit's constructor so that we can add to the prototype later
216 | QUnit.constructor = F;
217 | }());
218 |
219 | /**
220 | * Config object: Maintain internal state
221 | * Later exposed as QUnit.config
222 | * `config` initialized at top of scope
223 | */
224 | config = {
225 | // The queue of tests to run
226 | queue: [],
227 |
228 | // block until document ready
229 | blocking: true,
230 |
231 | // when enabled, show only failing tests
232 | // gets persisted through sessionStorage and can be changed in UI via checkbox
233 | hidepassed: false,
234 |
235 | // by default, run previously failed tests first
236 | // very useful in combination with "Hide passed tests" checked
237 | reorder: true,
238 |
239 | // by default, modify document.title when suite is done
240 | altertitle: true,
241 |
242 | // by default, scroll to top of the page when suite is done
243 | scrolltop: true,
244 |
245 | // when enabled, all tests must call expect()
246 | requireExpects: false,
247 |
248 | // add checkboxes that are persisted in the query-string
249 | // when enabled, the id is set to `true` as a `QUnit.config` property
250 | urlConfig: [
251 | {
252 | id: "noglobals",
253 | label: "Check for Globals",
254 | tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
255 | },
256 | {
257 | id: "notrycatch",
258 | label: "No try-catch",
259 | tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
260 | }
261 | ],
262 |
263 | // Set of all modules.
264 | modules: {},
265 |
266 | // logging callback queues
267 | begin: [],
268 | done: [],
269 | log: [],
270 | testStart: [],
271 | testDone: [],
272 | moduleStart: [],
273 | moduleDone: []
274 | };
275 |
276 | // Initialize more QUnit.config and QUnit.urlParams
277 | (function() {
278 | var i, current,
279 | location = window.location || { search: "", protocol: "file:" },
280 | params = location.search.slice( 1 ).split( "&" ),
281 | length = params.length,
282 | urlParams = {};
283 |
284 | if ( params[ 0 ] ) {
285 | for ( i = 0; i < length; i++ ) {
286 | current = params[ i ].split( "=" );
287 | current[ 0 ] = decodeURIComponent( current[ 0 ] );
288 |
289 | // allow just a key to turn on a flag, e.g., test.html?noglobals
290 | current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
291 | if ( urlParams[ current[ 0 ] ] ) {
292 | urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] );
293 | } else {
294 | urlParams[ current[ 0 ] ] = current[ 1 ];
295 | }
296 | }
297 | }
298 |
299 | QUnit.urlParams = urlParams;
300 |
301 | // String search anywhere in moduleName+testName
302 | config.filter = urlParams.filter;
303 |
304 | // Exact match of the module name
305 | config.module = urlParams.module;
306 |
307 | config.testNumber = [];
308 | if ( urlParams.testNumber ) {
309 |
310 | // Ensure that urlParams.testNumber is an array
311 | urlParams.testNumber = [].concat( urlParams.testNumber );
312 | for ( i = 0; i < urlParams.testNumber.length; i++ ) {
313 | current = urlParams.testNumber[ i ];
314 | config.testNumber.push( parseInt( current, 10 ) );
315 | }
316 | }
317 |
318 | // Figure out if we're running the tests from a server or not
319 | QUnit.isLocal = location.protocol === "file:";
320 | }());
321 |
322 | extend( QUnit, {
323 |
324 | config: config,
325 |
326 | // Initialize the configuration options
327 | init: function() {
328 | extend( config, {
329 | stats: { all: 0, bad: 0 },
330 | moduleStats: { all: 0, bad: 0 },
331 | started: +new Date(),
332 | updateRate: 1000,
333 | blocking: false,
334 | autostart: true,
335 | autorun: false,
336 | filter: "",
337 | queue: [],
338 | semaphore: 1
339 | });
340 |
341 | var tests, banner, result,
342 | qunit = id( "qunit" );
343 |
344 | if ( qunit ) {
345 | qunit.innerHTML =
346 | "" +
347 | " " +
348 | "
" +
349 | " " +
350 | " ";
351 | }
352 |
353 | tests = id( "qunit-tests" );
354 | banner = id( "qunit-banner" );
355 | result = id( "qunit-testresult" );
356 |
357 | if ( tests ) {
358 | tests.innerHTML = "";
359 | }
360 |
361 | if ( banner ) {
362 | banner.className = "";
363 | }
364 |
365 | if ( result ) {
366 | result.parentNode.removeChild( result );
367 | }
368 |
369 | if ( tests ) {
370 | result = document.createElement( "p" );
371 | result.id = "qunit-testresult";
372 | result.className = "result";
373 | tests.parentNode.insertBefore( result, tests );
374 | result.innerHTML = "Running... ";
375 | }
376 | },
377 |
378 | // Resets the test setup. Useful for tests that modify the DOM.
379 | /*
380 | DEPRECATED: Use multiple tests instead of resetting inside a test.
381 | Use testStart or testDone for custom cleanup.
382 | This method will throw an error in 2.0, and will be removed in 2.1
383 | */
384 | reset: function() {
385 | var fixture = id( "qunit-fixture" );
386 | if ( fixture ) {
387 | fixture.innerHTML = config.fixture;
388 | }
389 | },
390 |
391 | // Safe object type checking
392 | is: function( type, obj ) {
393 | return QUnit.objectType( obj ) === type;
394 | },
395 |
396 | objectType: function( obj ) {
397 | if ( typeof obj === "undefined" ) {
398 | return "undefined";
399 | }
400 |
401 | // Consider: typeof null === object
402 | if ( obj === null ) {
403 | return "null";
404 | }
405 |
406 | var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
407 | type = match && match[1] || "";
408 |
409 | switch ( type ) {
410 | case "Number":
411 | if ( isNaN(obj) ) {
412 | return "nan";
413 | }
414 | return "number";
415 | case "String":
416 | case "Boolean":
417 | case "Array":
418 | case "Date":
419 | case "RegExp":
420 | case "Function":
421 | return type.toLowerCase();
422 | }
423 | if ( typeof obj === "object" ) {
424 | return "object";
425 | }
426 | return undefined;
427 | },
428 |
429 | push: function( result, actual, expected, message ) {
430 | if ( !config.current ) {
431 | throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
432 | }
433 |
434 | var output, source,
435 | details = {
436 | module: config.current.module,
437 | name: config.current.testName,
438 | result: result,
439 | message: message,
440 | actual: actual,
441 | expected: expected
442 | };
443 |
444 | message = escapeText( message ) || ( result ? "okay" : "failed" );
445 | message = "" + message + " ";
446 | output = message;
447 |
448 | if ( !result ) {
449 | expected = escapeText( QUnit.jsDump.parse(expected) );
450 | actual = escapeText( QUnit.jsDump.parse(actual) );
451 | output += "Expected: " + expected + " ";
452 |
453 | if ( actual !== expected ) {
454 | output += "Result: " + actual + " ";
455 | output += "Diff: " + QUnit.diff( expected, actual ) + " ";
456 | }
457 |
458 | source = sourceFromStacktrace();
459 |
460 | if ( source ) {
461 | details.source = source;
462 | output += "Source: " + escapeText( source ) + " ";
463 | }
464 |
465 | output += "
";
466 | }
467 |
468 | runLoggingCallbacks( "log", QUnit, details );
469 |
470 | config.current.assertions.push({
471 | result: !!result,
472 | message: output
473 | });
474 | },
475 |
476 | pushFailure: function( message, source, actual ) {
477 | if ( !config.current ) {
478 | throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
479 | }
480 |
481 | var output,
482 | details = {
483 | module: config.current.module,
484 | name: config.current.testName,
485 | result: false,
486 | message: message
487 | };
488 |
489 | message = escapeText( message ) || "error";
490 | message = "" + message + " ";
491 | output = message;
492 |
493 | output += "";
494 |
495 | if ( actual ) {
496 | output += "Result: " + escapeText( actual ) + " ";
497 | }
498 |
499 | if ( source ) {
500 | details.source = source;
501 | output += "Source: " + escapeText( source ) + " ";
502 | }
503 |
504 | output += "
";
505 |
506 | runLoggingCallbacks( "log", QUnit, details );
507 |
508 | config.current.assertions.push({
509 | result: false,
510 | message: output
511 | });
512 | },
513 |
514 | url: function( params ) {
515 | params = extend( extend( {}, QUnit.urlParams ), params );
516 | var key,
517 | querystring = "?";
518 |
519 | for ( key in params ) {
520 | if ( hasOwn.call( params, key ) ) {
521 | querystring += encodeURIComponent( key ) + "=" +
522 | encodeURIComponent( params[ key ] ) + "&";
523 | }
524 | }
525 | return window.location.protocol + "//" + window.location.host +
526 | window.location.pathname + querystring.slice( 0, -1 );
527 | },
528 |
529 | extend: extend,
530 | id: id,
531 | addEvent: addEvent,
532 | addClass: addClass,
533 | hasClass: hasClass,
534 | removeClass: removeClass
535 | // load, equiv, jsDump, diff: Attached later
536 | });
537 |
538 | /**
539 | * @deprecated: Created for backwards compatibility with test runner that set the hook function
540 | * into QUnit.{hook}, instead of invoking it and passing the hook function.
541 | * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
542 | * Doing this allows us to tell if the following methods have been overwritten on the actual
543 | * QUnit object.
544 | */
545 | extend( QUnit.constructor.prototype, {
546 |
547 | // Logging callbacks; all receive a single argument with the listed properties
548 | // run test/logs.html for any related changes
549 | begin: registerLoggingCallback( "begin" ),
550 |
551 | // done: { failed, passed, total, runtime }
552 | done: registerLoggingCallback( "done" ),
553 |
554 | // log: { result, actual, expected, message }
555 | log: registerLoggingCallback( "log" ),
556 |
557 | // testStart: { name }
558 | testStart: registerLoggingCallback( "testStart" ),
559 |
560 | // testDone: { name, failed, passed, total, runtime }
561 | testDone: registerLoggingCallback( "testDone" ),
562 |
563 | // moduleStart: { name }
564 | moduleStart: registerLoggingCallback( "moduleStart" ),
565 |
566 | // moduleDone: { name, failed, passed, total }
567 | moduleDone: registerLoggingCallback( "moduleDone" )
568 | });
569 |
570 | if ( !defined.document || document.readyState === "complete" ) {
571 | config.autorun = true;
572 | }
573 |
574 | QUnit.load = function() {
575 | runLoggingCallbacks( "begin", QUnit, {} );
576 |
577 | // Initialize the config, saving the execution queue
578 | var banner, filter, i, j, label, len, main, ol, toolbar, val, selection,
579 | urlConfigContainer, moduleFilter, userAgent,
580 | numModules = 0,
581 | moduleNames = [],
582 | moduleFilterHtml = "",
583 | urlConfigHtml = "",
584 | oldconfig = extend( {}, config );
585 |
586 | QUnit.init();
587 | extend(config, oldconfig);
588 |
589 | config.blocking = false;
590 |
591 | len = config.urlConfig.length;
592 |
593 | for ( i = 0; i < len; i++ ) {
594 | val = config.urlConfig[i];
595 | if ( typeof val === "string" ) {
596 | val = {
597 | id: val,
598 | label: val
599 | };
600 | }
601 | config[ val.id ] = QUnit.urlParams[ val.id ];
602 | if ( !val.value || typeof val.value === "string" ) {
603 | urlConfigHtml += "" + val.label + " ";
611 | } else {
612 | urlConfigHtml += "" + val.label +
615 | ": ";
619 | selection = false;
620 | if ( QUnit.is( "array", val.value ) ) {
621 | for ( j = 0; j < val.value.length; j++ ) {
622 | urlConfigHtml += "" + escapeText( val.value[j] ) + " ";
627 | }
628 | } else {
629 | for ( j in val.value ) {
630 | if ( hasOwn.call( val.value, j ) ) {
631 | urlConfigHtml += "" + escapeText( val.value[j] ) + " ";
636 | }
637 | }
638 | }
639 | if ( config[ val.id ] && !selection ) {
640 | urlConfigHtml += "" +
642 | escapeText( config[ val.id ] ) +
643 | " ";
644 | }
645 | urlConfigHtml += " ";
646 | }
647 | }
648 | for ( i in config.modules ) {
649 | if ( config.modules.hasOwnProperty( i ) ) {
650 | moduleNames.push(i);
651 | }
652 | }
653 | numModules = moduleNames.length;
654 | moduleNames.sort( function( a, b ) {
655 | return a.localeCompare( b );
656 | });
657 | moduleFilterHtml += "Module: < All Modules > ";
660 |
661 |
662 | for ( i = 0; i < numModules; i++) {
663 | moduleFilterHtml += "" + escapeText(moduleNames[i]) + " ";
666 | }
667 | moduleFilterHtml += " ";
668 |
669 | // `userAgent` initialized at top of scope
670 | userAgent = id( "qunit-userAgent" );
671 | if ( userAgent ) {
672 | userAgent.innerHTML = navigator.userAgent;
673 | }
674 |
675 | // `banner` initialized at top of scope
676 | banner = id( "qunit-header" );
677 | if ( banner ) {
678 | banner.innerHTML = "" + banner.innerHTML + " ";
679 | }
680 |
681 | // `toolbar` initialized at top of scope
682 | toolbar = id( "qunit-testrunner-toolbar" );
683 | if ( toolbar ) {
684 | // `filter` initialized at top of scope
685 | filter = document.createElement( "input" );
686 | filter.type = "checkbox";
687 | filter.id = "qunit-filter-pass";
688 |
689 | addEvent( filter, "click", function() {
690 | var tmp,
691 | ol = id( "qunit-tests" );
692 |
693 | if ( filter.checked ) {
694 | ol.className = ol.className + " hidepass";
695 | } else {
696 | tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
697 | ol.className = tmp.replace( / hidepass /, " " );
698 | }
699 | if ( defined.sessionStorage ) {
700 | if (filter.checked) {
701 | sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
702 | } else {
703 | sessionStorage.removeItem( "qunit-filter-passed-tests" );
704 | }
705 | }
706 | });
707 |
708 | if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
709 | filter.checked = true;
710 | // `ol` initialized at top of scope
711 | ol = id( "qunit-tests" );
712 | ol.className = ol.className + " hidepass";
713 | }
714 | toolbar.appendChild( filter );
715 |
716 | // `label` initialized at top of scope
717 | label = document.createElement( "label" );
718 | label.setAttribute( "for", "qunit-filter-pass" );
719 | label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
720 | label.innerHTML = "Hide passed tests";
721 | toolbar.appendChild( label );
722 |
723 | urlConfigContainer = document.createElement("span");
724 | urlConfigContainer.innerHTML = urlConfigHtml;
725 | // For oldIE support:
726 | // * Add handlers to the individual elements instead of the container
727 | // * Use "click" instead of "change" for checkboxes
728 | // * Fallback from event.target to event.srcElement
729 | addEvents( urlConfigContainer.getElementsByTagName("input"), "click", function( event ) {
730 | var params = {},
731 | target = event.target || event.srcElement;
732 | params[ target.name ] = target.checked ?
733 | target.defaultValue || true :
734 | undefined;
735 | window.location = QUnit.url( params );
736 | });
737 | addEvents( urlConfigContainer.getElementsByTagName("select"), "change", function( event ) {
738 | var params = {},
739 | target = event.target || event.srcElement;
740 | params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
741 | window.location = QUnit.url( params );
742 | });
743 | toolbar.appendChild( urlConfigContainer );
744 |
745 | if (numModules > 1) {
746 | moduleFilter = document.createElement( "span" );
747 | moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
748 | moduleFilter.innerHTML = moduleFilterHtml;
749 | addEvent( moduleFilter.lastChild, "change", function() {
750 | var selectBox = moduleFilter.getElementsByTagName("select")[0],
751 | selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
752 |
753 | window.location = QUnit.url({
754 | module: ( selectedModule === "" ) ? undefined : selectedModule,
755 | // Remove any existing filters
756 | filter: undefined,
757 | testNumber: undefined
758 | });
759 | });
760 | toolbar.appendChild(moduleFilter);
761 | }
762 | }
763 |
764 | // `main` initialized at top of scope
765 | main = id( "qunit-fixture" );
766 | if ( main ) {
767 | config.fixture = main.innerHTML;
768 | }
769 |
770 | if ( config.autostart ) {
771 | QUnit.start();
772 | }
773 | };
774 |
775 | if ( defined.document ) {
776 | addEvent( window, "load", QUnit.load );
777 | }
778 |
779 | // `onErrorFnPrev` initialized at top of scope
780 | // Preserve other handlers
781 | onErrorFnPrev = window.onerror;
782 |
783 | // Cover uncaught exceptions
784 | // Returning true will suppress the default browser handler,
785 | // returning false will let it run.
786 | window.onerror = function ( error, filePath, linerNr ) {
787 | var ret = false;
788 | if ( onErrorFnPrev ) {
789 | ret = onErrorFnPrev( error, filePath, linerNr );
790 | }
791 |
792 | // Treat return value as window.onerror itself does,
793 | // Only do our handling if not suppressed.
794 | if ( ret !== true ) {
795 | if ( QUnit.config.current ) {
796 | if ( QUnit.config.current.ignoreGlobalErrors ) {
797 | return true;
798 | }
799 | QUnit.pushFailure( error, filePath + ":" + linerNr );
800 | } else {
801 | QUnit.test( "global failure", extend( function() {
802 | QUnit.pushFailure( error, filePath + ":" + linerNr );
803 | }, { validTest: validTest } ) );
804 | }
805 | return false;
806 | }
807 |
808 | return ret;
809 | };
810 |
811 | function done() {
812 | config.autorun = true;
813 |
814 | // Log the last module results
815 | if ( config.previousModule ) {
816 | runLoggingCallbacks( "moduleDone", QUnit, {
817 | name: config.previousModule,
818 | failed: config.moduleStats.bad,
819 | passed: config.moduleStats.all - config.moduleStats.bad,
820 | total: config.moduleStats.all
821 | });
822 | }
823 | delete config.previousModule;
824 |
825 | var i, key,
826 | banner = id( "qunit-banner" ),
827 | tests = id( "qunit-tests" ),
828 | runtime = +new Date() - config.started,
829 | passed = config.stats.all - config.stats.bad,
830 | html = [
831 | "Tests completed in ",
832 | runtime,
833 | " milliseconds. ",
834 | "",
835 | passed,
836 | " assertions of ",
837 | config.stats.all,
838 | " passed, ",
839 | config.stats.bad,
840 | " failed."
841 | ].join( "" );
842 |
843 | if ( banner ) {
844 | banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
845 | }
846 |
847 | if ( tests ) {
848 | id( "qunit-testresult" ).innerHTML = html;
849 | }
850 |
851 | if ( config.altertitle && defined.document && document.title ) {
852 | // show ✖ for good, ✔ for bad suite result in title
853 | // use escape sequences in case file gets loaded with non-utf-8-charset
854 | document.title = [
855 | ( config.stats.bad ? "\u2716" : "\u2714" ),
856 | document.title.replace( /^[\u2714\u2716] /i, "" )
857 | ].join( " " );
858 | }
859 |
860 | // clear own sessionStorage items if all tests passed
861 | if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
862 | // `key` & `i` initialized at top of scope
863 | for ( i = 0; i < sessionStorage.length; i++ ) {
864 | key = sessionStorage.key( i++ );
865 | if ( key.indexOf( "qunit-test-" ) === 0 ) {
866 | sessionStorage.removeItem( key );
867 | }
868 | }
869 | }
870 |
871 | // scroll back to top to show results
872 | if ( config.scrolltop && window.scrollTo ) {
873 | window.scrollTo(0, 0);
874 | }
875 |
876 | runLoggingCallbacks( "done", QUnit, {
877 | failed: config.stats.bad,
878 | passed: passed,
879 | total: config.stats.all,
880 | runtime: runtime
881 | });
882 | }
883 |
884 | /** @return Boolean: true if this test should be ran */
885 | function validTest( test ) {
886 | var include,
887 | filter = config.filter && config.filter.toLowerCase(),
888 | module = config.module && config.module.toLowerCase(),
889 | fullName = ( test.module + ": " + test.testName ).toLowerCase();
890 |
891 | // Internally-generated tests are always valid
892 | if ( test.callback && test.callback.validTest === validTest ) {
893 | delete test.callback.validTest;
894 | return true;
895 | }
896 |
897 | if ( config.testNumber.length > 0 ) {
898 | if ( inArray( test.testNumber, config.testNumber ) < 0 ) {
899 | return false;
900 | }
901 | }
902 |
903 | if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
904 | return false;
905 | }
906 |
907 | if ( !filter ) {
908 | return true;
909 | }
910 |
911 | include = filter.charAt( 0 ) !== "!";
912 | if ( !include ) {
913 | filter = filter.slice( 1 );
914 | }
915 |
916 | // If the filter matches, we need to honour include
917 | if ( fullName.indexOf( filter ) !== -1 ) {
918 | return include;
919 | }
920 |
921 | // Otherwise, do the opposite
922 | return !include;
923 | }
924 |
925 | // so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
926 | // Later Safari and IE10 are supposed to support error.stack as well
927 | // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
928 | function extractStacktrace( e, offset ) {
929 | offset = offset === undefined ? 3 : offset;
930 |
931 | var stack, include, i;
932 |
933 | if ( e.stacktrace ) {
934 | // Opera
935 | return e.stacktrace.split( "\n" )[ offset + 3 ];
936 | } else if ( e.stack ) {
937 | // Firefox, Chrome
938 | stack = e.stack.split( "\n" );
939 | if (/^error$/i.test( stack[0] ) ) {
940 | stack.shift();
941 | }
942 | if ( fileName ) {
943 | include = [];
944 | for ( i = offset; i < stack.length; i++ ) {
945 | if ( stack[ i ].indexOf( fileName ) !== -1 ) {
946 | break;
947 | }
948 | include.push( stack[ i ] );
949 | }
950 | if ( include.length ) {
951 | return include.join( "\n" );
952 | }
953 | }
954 | return stack[ offset ];
955 | } else if ( e.sourceURL ) {
956 | // Safari, PhantomJS
957 | // hopefully one day Safari provides actual stacktraces
958 | // exclude useless self-reference for generated Error objects
959 | if ( /qunit.js$/.test( e.sourceURL ) ) {
960 | return;
961 | }
962 | // for actual exceptions, this is useful
963 | return e.sourceURL + ":" + e.line;
964 | }
965 | }
966 | function sourceFromStacktrace( offset ) {
967 | try {
968 | throw new Error();
969 | } catch ( e ) {
970 | return extractStacktrace( e, offset );
971 | }
972 | }
973 |
974 | /**
975 | * Escape text for attribute or text content.
976 | */
977 | function escapeText( s ) {
978 | if ( !s ) {
979 | return "";
980 | }
981 | s = s + "";
982 | // Both single quotes and double quotes (for attributes)
983 | return s.replace( /['"<>&]/g, function( s ) {
984 | switch( s ) {
985 | case "'":
986 | return "'";
987 | case "\"":
988 | return """;
989 | case "<":
990 | return "<";
991 | case ">":
992 | return ">";
993 | case "&":
994 | return "&";
995 | }
996 | });
997 | }
998 |
999 | function synchronize( callback, last ) {
1000 | config.queue.push( callback );
1001 |
1002 | if ( config.autorun && !config.blocking ) {
1003 | process( last );
1004 | }
1005 | }
1006 |
1007 | function process( last ) {
1008 | function next() {
1009 | process( last );
1010 | }
1011 | var start = new Date().getTime();
1012 | config.depth = config.depth ? config.depth + 1 : 1;
1013 |
1014 | while ( config.queue.length && !config.blocking ) {
1015 | if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
1016 | config.queue.shift()();
1017 | } else {
1018 | setTimeout( next, 13 );
1019 | break;
1020 | }
1021 | }
1022 | config.depth--;
1023 | if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
1024 | done();
1025 | }
1026 | }
1027 |
1028 | function saveGlobal() {
1029 | config.pollution = [];
1030 |
1031 | if ( config.noglobals ) {
1032 | for ( var key in window ) {
1033 | if ( hasOwn.call( window, key ) ) {
1034 | // in Opera sometimes DOM element ids show up here, ignore them
1035 | if ( /^qunit-test-output/.test( key ) ) {
1036 | continue;
1037 | }
1038 | config.pollution.push( key );
1039 | }
1040 | }
1041 | }
1042 | }
1043 |
1044 | function checkPollution() {
1045 | var newGlobals,
1046 | deletedGlobals,
1047 | old = config.pollution;
1048 |
1049 | saveGlobal();
1050 |
1051 | newGlobals = diff( config.pollution, old );
1052 | if ( newGlobals.length > 0 ) {
1053 | QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
1054 | }
1055 |
1056 | deletedGlobals = diff( old, config.pollution );
1057 | if ( deletedGlobals.length > 0 ) {
1058 | QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
1059 | }
1060 | }
1061 |
1062 | // returns a new Array with the elements that are in a but not in b
1063 | function diff( a, b ) {
1064 | var i, j,
1065 | result = a.slice();
1066 |
1067 | for ( i = 0; i < result.length; i++ ) {
1068 | for ( j = 0; j < b.length; j++ ) {
1069 | if ( result[i] === b[j] ) {
1070 | result.splice( i, 1 );
1071 | i--;
1072 | break;
1073 | }
1074 | }
1075 | }
1076 | return result;
1077 | }
1078 |
1079 | function extend( a, b ) {
1080 | for ( var prop in b ) {
1081 | if ( hasOwn.call( b, prop ) ) {
1082 | // Avoid "Member not found" error in IE8 caused by messing with window.constructor
1083 | if ( !( prop === "constructor" && a === window ) ) {
1084 | if ( b[ prop ] === undefined ) {
1085 | delete a[ prop ];
1086 | } else {
1087 | a[ prop ] = b[ prop ];
1088 | }
1089 | }
1090 | }
1091 | }
1092 |
1093 | return a;
1094 | }
1095 |
1096 | /**
1097 | * @param {HTMLElement} elem
1098 | * @param {string} type
1099 | * @param {Function} fn
1100 | */
1101 | function addEvent( elem, type, fn ) {
1102 | if ( elem.addEventListener ) {
1103 |
1104 | // Standards-based browsers
1105 | elem.addEventListener( type, fn, false );
1106 | } else if ( elem.attachEvent ) {
1107 |
1108 | // support: IE <9
1109 | elem.attachEvent( "on" + type, fn );
1110 | } else {
1111 |
1112 | // Caller must ensure support for event listeners is present
1113 | throw new Error( "addEvent() was called in a context without event listener support" );
1114 | }
1115 | }
1116 |
1117 | /**
1118 | * @param {Array|NodeList} elems
1119 | * @param {string} type
1120 | * @param {Function} fn
1121 | */
1122 | function addEvents( elems, type, fn ) {
1123 | var i = elems.length;
1124 | while ( i-- ) {
1125 | addEvent( elems[i], type, fn );
1126 | }
1127 | }
1128 |
1129 | function hasClass( elem, name ) {
1130 | return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
1131 | }
1132 |
1133 | function addClass( elem, name ) {
1134 | if ( !hasClass( elem, name ) ) {
1135 | elem.className += (elem.className ? " " : "") + name;
1136 | }
1137 | }
1138 |
1139 | function removeClass( elem, name ) {
1140 | var set = " " + elem.className + " ";
1141 | // Class name may appear multiple times
1142 | while ( set.indexOf(" " + name + " ") > -1 ) {
1143 | set = set.replace(" " + name + " " , " ");
1144 | }
1145 | // If possible, trim it for prettiness, but not necessarily
1146 | elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
1147 | }
1148 |
1149 | function id( name ) {
1150 | return defined.document && document.getElementById && document.getElementById( name );
1151 | }
1152 |
1153 | function registerLoggingCallback( key ) {
1154 | return function( callback ) {
1155 | config[key].push( callback );
1156 | };
1157 | }
1158 |
1159 | // Supports deprecated method of completely overwriting logging callbacks
1160 | function runLoggingCallbacks( key, scope, args ) {
1161 | var i, callbacks;
1162 | if ( QUnit.hasOwnProperty( key ) ) {
1163 | QUnit[ key ].call(scope, args );
1164 | } else {
1165 | callbacks = config[ key ];
1166 | for ( i = 0; i < callbacks.length; i++ ) {
1167 | callbacks[ i ].call( scope, args );
1168 | }
1169 | }
1170 | }
1171 |
1172 | // from jquery.js
1173 | function inArray( elem, array ) {
1174 | if ( array.indexOf ) {
1175 | return array.indexOf( elem );
1176 | }
1177 |
1178 | for ( var i = 0, length = array.length; i < length; i++ ) {
1179 | if ( array[ i ] === elem ) {
1180 | return i;
1181 | }
1182 | }
1183 |
1184 | return -1;
1185 | }
1186 |
1187 | function Test( settings ) {
1188 | extend( this, settings );
1189 | this.assertions = [];
1190 | this.testNumber = ++Test.count;
1191 | }
1192 |
1193 | Test.count = 0;
1194 |
1195 | Test.prototype = {
1196 | init: function() {
1197 | var a, b, li,
1198 | tests = id( "qunit-tests" );
1199 |
1200 | if ( tests ) {
1201 | b = document.createElement( "strong" );
1202 | b.innerHTML = this.nameHtml;
1203 |
1204 | // `a` initialized at top of scope
1205 | a = document.createElement( "a" );
1206 | a.innerHTML = "Rerun";
1207 | a.href = QUnit.url({ testNumber: this.testNumber });
1208 |
1209 | li = document.createElement( "li" );
1210 | li.appendChild( b );
1211 | li.appendChild( a );
1212 | li.className = "running";
1213 | li.id = this.id = "qunit-test-output" + testId++;
1214 |
1215 | tests.appendChild( li );
1216 | }
1217 | },
1218 | setup: function() {
1219 | if (
1220 | // Emit moduleStart when we're switching from one module to another
1221 | this.module !== config.previousModule ||
1222 | // They could be equal (both undefined) but if the previousModule property doesn't
1223 | // yet exist it means this is the first test in a suite that isn't wrapped in a
1224 | // module, in which case we'll just emit a moduleStart event for 'undefined'.
1225 | // Without this, reporters can get testStart before moduleStart which is a problem.
1226 | !hasOwn.call( config, "previousModule" )
1227 | ) {
1228 | if ( hasOwn.call( config, "previousModule" ) ) {
1229 | runLoggingCallbacks( "moduleDone", QUnit, {
1230 | name: config.previousModule,
1231 | failed: config.moduleStats.bad,
1232 | passed: config.moduleStats.all - config.moduleStats.bad,
1233 | total: config.moduleStats.all
1234 | });
1235 | }
1236 | config.previousModule = this.module;
1237 | config.moduleStats = { all: 0, bad: 0 };
1238 | runLoggingCallbacks( "moduleStart", QUnit, {
1239 | name: this.module
1240 | });
1241 | }
1242 |
1243 | config.current = this;
1244 |
1245 | this.testEnvironment = extend({
1246 | setup: function() {},
1247 | teardown: function() {}
1248 | }, this.moduleTestEnvironment );
1249 |
1250 | this.started = +new Date();
1251 | runLoggingCallbacks( "testStart", QUnit, {
1252 | name: this.testName,
1253 | module: this.module
1254 | });
1255 |
1256 | /*jshint camelcase:false */
1257 |
1258 |
1259 | /**
1260 | * Expose the current test environment.
1261 | *
1262 | * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
1263 | */
1264 | QUnit.current_testEnvironment = this.testEnvironment;
1265 |
1266 | /*jshint camelcase:true */
1267 |
1268 | if ( !config.pollution ) {
1269 | saveGlobal();
1270 | }
1271 | if ( config.notrycatch ) {
1272 | this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
1273 | return;
1274 | }
1275 | try {
1276 | this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
1277 | } catch( e ) {
1278 | QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
1279 | }
1280 | },
1281 | run: function() {
1282 | config.current = this;
1283 |
1284 | var running = id( "qunit-testresult" );
1285 |
1286 | if ( running ) {
1287 | running.innerHTML = "Running: " + this.nameHtml;
1288 | }
1289 |
1290 | if ( this.async ) {
1291 | QUnit.stop();
1292 | }
1293 |
1294 | this.callbackStarted = +new Date();
1295 |
1296 | if ( config.notrycatch ) {
1297 | this.callback.call( this.testEnvironment, QUnit.assert );
1298 | this.callbackRuntime = +new Date() - this.callbackStarted;
1299 | return;
1300 | }
1301 |
1302 | try {
1303 | this.callback.call( this.testEnvironment, QUnit.assert );
1304 | this.callbackRuntime = +new Date() - this.callbackStarted;
1305 | } catch( e ) {
1306 | this.callbackRuntime = +new Date() - this.callbackStarted;
1307 |
1308 | QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
1309 | // else next test will carry the responsibility
1310 | saveGlobal();
1311 |
1312 | // Restart the tests if they're blocking
1313 | if ( config.blocking ) {
1314 | QUnit.start();
1315 | }
1316 | }
1317 | },
1318 | teardown: function() {
1319 | config.current = this;
1320 | if ( config.notrycatch ) {
1321 | if ( typeof this.callbackRuntime === "undefined" ) {
1322 | this.callbackRuntime = +new Date() - this.callbackStarted;
1323 | }
1324 | this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
1325 | return;
1326 | } else {
1327 | try {
1328 | this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
1329 | } catch( e ) {
1330 | QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
1331 | }
1332 | }
1333 | checkPollution();
1334 | },
1335 | finish: function() {
1336 | config.current = this;
1337 | if ( config.requireExpects && this.expected === null ) {
1338 | QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
1339 | } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
1340 | QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
1341 | } else if ( this.expected === null && !this.assertions.length ) {
1342 | QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
1343 | }
1344 |
1345 | var i, assertion, a, b, time, li, ol,
1346 | test = this,
1347 | good = 0,
1348 | bad = 0,
1349 | tests = id( "qunit-tests" );
1350 |
1351 | this.runtime = +new Date() - this.started;
1352 | config.stats.all += this.assertions.length;
1353 | config.moduleStats.all += this.assertions.length;
1354 |
1355 | if ( tests ) {
1356 | ol = document.createElement( "ol" );
1357 | ol.className = "qunit-assert-list";
1358 |
1359 | for ( i = 0; i < this.assertions.length; i++ ) {
1360 | assertion = this.assertions[i];
1361 |
1362 | li = document.createElement( "li" );
1363 | li.className = assertion.result ? "pass" : "fail";
1364 | li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
1365 | ol.appendChild( li );
1366 |
1367 | if ( assertion.result ) {
1368 | good++;
1369 | } else {
1370 | bad++;
1371 | config.stats.bad++;
1372 | config.moduleStats.bad++;
1373 | }
1374 | }
1375 |
1376 | // store result when possible
1377 | if ( QUnit.config.reorder && defined.sessionStorage ) {
1378 | if ( bad ) {
1379 | sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
1380 | } else {
1381 | sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
1382 | }
1383 | }
1384 |
1385 | if ( bad === 0 ) {
1386 | addClass( ol, "qunit-collapsed" );
1387 | }
1388 |
1389 | // `b` initialized at top of scope
1390 | b = document.createElement( "strong" );
1391 | b.innerHTML = this.nameHtml + " (" + bad + " , " + good + " , " + this.assertions.length + ") ";
1392 |
1393 | addEvent(b, "click", function() {
1394 | var next = b.parentNode.lastChild,
1395 | collapsed = hasClass( next, "qunit-collapsed" );
1396 | ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
1397 | });
1398 |
1399 | addEvent(b, "dblclick", function( e ) {
1400 | var target = e && e.target ? e.target : window.event.srcElement;
1401 | if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
1402 | target = target.parentNode;
1403 | }
1404 | if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
1405 | window.location = QUnit.url({ testNumber: test.testNumber });
1406 | }
1407 | });
1408 |
1409 | // `time` initialized at top of scope
1410 | time = document.createElement( "span" );
1411 | time.className = "runtime";
1412 | time.innerHTML = this.runtime + " ms";
1413 |
1414 | // `li` initialized at top of scope
1415 | li = id( this.id );
1416 | li.className = bad ? "fail" : "pass";
1417 | li.removeChild( li.firstChild );
1418 | a = li.firstChild;
1419 | li.appendChild( b );
1420 | li.appendChild( a );
1421 | li.appendChild( time );
1422 | li.appendChild( ol );
1423 |
1424 | } else {
1425 | for ( i = 0; i < this.assertions.length; i++ ) {
1426 | if ( !this.assertions[i].result ) {
1427 | bad++;
1428 | config.stats.bad++;
1429 | config.moduleStats.bad++;
1430 | }
1431 | }
1432 | }
1433 |
1434 | runLoggingCallbacks( "testDone", QUnit, {
1435 | name: this.testName,
1436 | module: this.module,
1437 | failed: bad,
1438 | passed: this.assertions.length - bad,
1439 | total: this.assertions.length,
1440 | runtime: this.runtime,
1441 | // DEPRECATED: this property will be removed in 2.0.0, use runtime instead
1442 | duration: this.runtime
1443 | });
1444 |
1445 | QUnit.reset();
1446 |
1447 | config.current = undefined;
1448 | },
1449 |
1450 | queue: function() {
1451 | var bad,
1452 | test = this;
1453 |
1454 | synchronize(function() {
1455 | test.init();
1456 | });
1457 | function run() {
1458 | // each of these can by async
1459 | synchronize(function() {
1460 | test.setup();
1461 | });
1462 | synchronize(function() {
1463 | test.run();
1464 | });
1465 | synchronize(function() {
1466 | test.teardown();
1467 | });
1468 | synchronize(function() {
1469 | test.finish();
1470 | });
1471 | }
1472 |
1473 | // `bad` initialized at top of scope
1474 | // defer when previous test run passed, if storage is available
1475 | bad = QUnit.config.reorder && defined.sessionStorage &&
1476 | +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
1477 |
1478 | if ( bad ) {
1479 | run();
1480 | } else {
1481 | synchronize( run, true );
1482 | }
1483 | }
1484 | };
1485 |
1486 | // `assert` initialized at top of scope
1487 | // Assert helpers
1488 | // All of these must either call QUnit.push() or manually do:
1489 | // - runLoggingCallbacks( "log", .. );
1490 | // - config.current.assertions.push({ .. });
1491 | assert = QUnit.assert = {
1492 | /**
1493 | * Asserts rough true-ish result.
1494 | * @name ok
1495 | * @function
1496 | * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
1497 | */
1498 | ok: function( result, msg ) {
1499 | if ( !config.current ) {
1500 | throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
1501 | }
1502 | result = !!result;
1503 | msg = msg || ( result ? "okay" : "failed" );
1504 |
1505 | var source,
1506 | details = {
1507 | module: config.current.module,
1508 | name: config.current.testName,
1509 | result: result,
1510 | message: msg
1511 | };
1512 |
1513 | msg = "" + escapeText( msg ) + " ";
1514 |
1515 | if ( !result ) {
1516 | source = sourceFromStacktrace( 2 );
1517 | if ( source ) {
1518 | details.source = source;
1519 | msg += "Source: " +
1520 | escapeText( source ) +
1521 | "
";
1522 | }
1523 | }
1524 | runLoggingCallbacks( "log", QUnit, details );
1525 | config.current.assertions.push({
1526 | result: result,
1527 | message: msg
1528 | });
1529 | },
1530 |
1531 | /**
1532 | * Assert that the first two arguments are equal, with an optional message.
1533 | * Prints out both actual and expected values.
1534 | * @name equal
1535 | * @function
1536 | * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
1537 | */
1538 | equal: function( actual, expected, message ) {
1539 | /*jshint eqeqeq:false */
1540 | QUnit.push( expected == actual, actual, expected, message );
1541 | },
1542 |
1543 | /**
1544 | * @name notEqual
1545 | * @function
1546 | */
1547 | notEqual: function( actual, expected, message ) {
1548 | /*jshint eqeqeq:false */
1549 | QUnit.push( expected != actual, actual, expected, message );
1550 | },
1551 |
1552 | /**
1553 | * @name propEqual
1554 | * @function
1555 | */
1556 | propEqual: function( actual, expected, message ) {
1557 | actual = objectValues(actual);
1558 | expected = objectValues(expected);
1559 | QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
1560 | },
1561 |
1562 | /**
1563 | * @name notPropEqual
1564 | * @function
1565 | */
1566 | notPropEqual: function( actual, expected, message ) {
1567 | actual = objectValues(actual);
1568 | expected = objectValues(expected);
1569 | QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
1570 | },
1571 |
1572 | /**
1573 | * @name deepEqual
1574 | * @function
1575 | */
1576 | deepEqual: function( actual, expected, message ) {
1577 | QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
1578 | },
1579 |
1580 | /**
1581 | * @name notDeepEqual
1582 | * @function
1583 | */
1584 | notDeepEqual: function( actual, expected, message ) {
1585 | QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
1586 | },
1587 |
1588 | /**
1589 | * @name strictEqual
1590 | * @function
1591 | */
1592 | strictEqual: function( actual, expected, message ) {
1593 | QUnit.push( expected === actual, actual, expected, message );
1594 | },
1595 |
1596 | /**
1597 | * @name notStrictEqual
1598 | * @function
1599 | */
1600 | notStrictEqual: function( actual, expected, message ) {
1601 | QUnit.push( expected !== actual, actual, expected, message );
1602 | },
1603 |
1604 | "throws": function( block, expected, message ) {
1605 | var actual,
1606 | expectedOutput = expected,
1607 | ok = false;
1608 |
1609 | // 'expected' is optional
1610 | if ( !message && typeof expected === "string" ) {
1611 | message = expected;
1612 | expected = null;
1613 | }
1614 |
1615 | config.current.ignoreGlobalErrors = true;
1616 | try {
1617 | block.call( config.current.testEnvironment );
1618 | } catch (e) {
1619 | actual = e;
1620 | }
1621 | config.current.ignoreGlobalErrors = false;
1622 |
1623 | if ( actual ) {
1624 |
1625 | // we don't want to validate thrown error
1626 | if ( !expected ) {
1627 | ok = true;
1628 | expectedOutput = null;
1629 |
1630 | // expected is an Error object
1631 | } else if ( expected instanceof Error ) {
1632 | ok = actual instanceof Error &&
1633 | actual.name === expected.name &&
1634 | actual.message === expected.message;
1635 |
1636 | // expected is a regexp
1637 | } else if ( QUnit.objectType( expected ) === "regexp" ) {
1638 | ok = expected.test( errorString( actual ) );
1639 |
1640 | // expected is a string
1641 | } else if ( QUnit.objectType( expected ) === "string" ) {
1642 | ok = expected === errorString( actual );
1643 |
1644 | // expected is a constructor
1645 | } else if ( actual instanceof expected ) {
1646 | ok = true;
1647 |
1648 | // expected is a validation function which returns true is validation passed
1649 | } else if ( expected.call( {}, actual ) === true ) {
1650 | expectedOutput = null;
1651 | ok = true;
1652 | }
1653 |
1654 | QUnit.push( ok, actual, expectedOutput, message );
1655 | } else {
1656 | QUnit.pushFailure( message, null, "No exception was thrown." );
1657 | }
1658 | }
1659 | };
1660 |
1661 | /**
1662 | * @deprecated since 1.8.0
1663 | * Kept assertion helpers in root for backwards compatibility.
1664 | */
1665 | extend( QUnit.constructor.prototype, assert );
1666 |
1667 | /**
1668 | * @deprecated since 1.9.0
1669 | * Kept to avoid TypeErrors for undefined methods.
1670 | */
1671 | QUnit.constructor.prototype.raises = function() {
1672 | QUnit.push( false, false, false, "QUnit.raises has been deprecated since 2012 (fad3c1ea), use QUnit.throws instead" );
1673 | };
1674 |
1675 | /**
1676 | * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
1677 | * Kept to avoid TypeErrors for undefined methods.
1678 | */
1679 | QUnit.constructor.prototype.equals = function() {
1680 | QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
1681 | };
1682 | QUnit.constructor.prototype.same = function() {
1683 | QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
1684 | };
1685 |
1686 | // Test for equality any JavaScript type.
1687 | // Author: Philippe Rathé
1688 | QUnit.equiv = (function() {
1689 |
1690 | // Call the o related callback with the given arguments.
1691 | function bindCallbacks( o, callbacks, args ) {
1692 | var prop = QUnit.objectType( o );
1693 | if ( prop ) {
1694 | if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
1695 | return callbacks[ prop ].apply( callbacks, args );
1696 | } else {
1697 | return callbacks[ prop ]; // or undefined
1698 | }
1699 | }
1700 | }
1701 |
1702 | // the real equiv function
1703 | var innerEquiv,
1704 | // stack to decide between skip/abort functions
1705 | callers = [],
1706 | // stack to avoiding loops from circular referencing
1707 | parents = [],
1708 | parentsB = [],
1709 |
1710 | getProto = Object.getPrototypeOf || function ( obj ) {
1711 | /*jshint camelcase:false */
1712 | return obj.__proto__;
1713 | },
1714 | callbacks = (function () {
1715 |
1716 | // for string, boolean, number and null
1717 | function useStrictEquality( b, a ) {
1718 | /*jshint eqeqeq:false */
1719 | if ( b instanceof a.constructor || a instanceof b.constructor ) {
1720 | // to catch short annotation VS 'new' annotation of a
1721 | // declaration
1722 | // e.g. var i = 1;
1723 | // var j = new Number(1);
1724 | return a == b;
1725 | } else {
1726 | return a === b;
1727 | }
1728 | }
1729 |
1730 | return {
1731 | "string": useStrictEquality,
1732 | "boolean": useStrictEquality,
1733 | "number": useStrictEquality,
1734 | "null": useStrictEquality,
1735 | "undefined": useStrictEquality,
1736 |
1737 | "nan": function( b ) {
1738 | return isNaN( b );
1739 | },
1740 |
1741 | "date": function( b, a ) {
1742 | return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
1743 | },
1744 |
1745 | "regexp": function( b, a ) {
1746 | return QUnit.objectType( b ) === "regexp" &&
1747 | // the regex itself
1748 | a.source === b.source &&
1749 | // and its modifiers
1750 | a.global === b.global &&
1751 | // (gmi) ...
1752 | a.ignoreCase === b.ignoreCase &&
1753 | a.multiline === b.multiline &&
1754 | a.sticky === b.sticky;
1755 | },
1756 |
1757 | // - skip when the property is a method of an instance (OOP)
1758 | // - abort otherwise,
1759 | // initial === would have catch identical references anyway
1760 | "function": function() {
1761 | var caller = callers[callers.length - 1];
1762 | return caller !== Object && typeof caller !== "undefined";
1763 | },
1764 |
1765 | "array": function( b, a ) {
1766 | var i, j, len, loop, aCircular, bCircular;
1767 |
1768 | // b could be an object literal here
1769 | if ( QUnit.objectType( b ) !== "array" ) {
1770 | return false;
1771 | }
1772 |
1773 | len = a.length;
1774 | if ( len !== b.length ) {
1775 | // safe and faster
1776 | return false;
1777 | }
1778 |
1779 | // track reference to avoid circular references
1780 | parents.push( a );
1781 | parentsB.push( b );
1782 | for ( i = 0; i < len; i++ ) {
1783 | loop = false;
1784 | for ( j = 0; j < parents.length; j++ ) {
1785 | aCircular = parents[j] === a[i];
1786 | bCircular = parentsB[j] === b[i];
1787 | if ( aCircular || bCircular ) {
1788 | if ( a[i] === b[i] || aCircular && bCircular ) {
1789 | loop = true;
1790 | } else {
1791 | parents.pop();
1792 | parentsB.pop();
1793 | return false;
1794 | }
1795 | }
1796 | }
1797 | if ( !loop && !innerEquiv(a[i], b[i]) ) {
1798 | parents.pop();
1799 | parentsB.pop();
1800 | return false;
1801 | }
1802 | }
1803 | parents.pop();
1804 | parentsB.pop();
1805 | return true;
1806 | },
1807 |
1808 | "object": function( b, a ) {
1809 | /*jshint forin:false */
1810 | var i, j, loop, aCircular, bCircular,
1811 | // Default to true
1812 | eq = true,
1813 | aProperties = [],
1814 | bProperties = [];
1815 |
1816 | // comparing constructors is more strict than using
1817 | // instanceof
1818 | if ( a.constructor !== b.constructor ) {
1819 | // Allow objects with no prototype to be equivalent to
1820 | // objects with Object as their constructor.
1821 | if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
1822 | ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
1823 | return false;
1824 | }
1825 | }
1826 |
1827 | // stack constructor before traversing properties
1828 | callers.push( a.constructor );
1829 |
1830 | // track reference to avoid circular references
1831 | parents.push( a );
1832 | parentsB.push( b );
1833 |
1834 | // be strict: don't ensure hasOwnProperty and go deep
1835 | for ( i in a ) {
1836 | loop = false;
1837 | for ( j = 0; j < parents.length; j++ ) {
1838 | aCircular = parents[j] === a[i];
1839 | bCircular = parentsB[j] === b[i];
1840 | if ( aCircular || bCircular ) {
1841 | if ( a[i] === b[i] || aCircular && bCircular ) {
1842 | loop = true;
1843 | } else {
1844 | eq = false;
1845 | break;
1846 | }
1847 | }
1848 | }
1849 | aProperties.push(i);
1850 | if ( !loop && !innerEquiv(a[i], b[i]) ) {
1851 | eq = false;
1852 | break;
1853 | }
1854 | }
1855 |
1856 | parents.pop();
1857 | parentsB.pop();
1858 | callers.pop(); // unstack, we are done
1859 |
1860 | for ( i in b ) {
1861 | bProperties.push( i ); // collect b's properties
1862 | }
1863 |
1864 | // Ensures identical properties name
1865 | return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
1866 | }
1867 | };
1868 | }());
1869 |
1870 | innerEquiv = function() { // can take multiple arguments
1871 | var args = [].slice.apply( arguments );
1872 | if ( args.length < 2 ) {
1873 | return true; // end transition
1874 | }
1875 |
1876 | return (function( a, b ) {
1877 | if ( a === b ) {
1878 | return true; // catch the most you can
1879 | } else if ( a === null || b === null || typeof a === "undefined" ||
1880 | typeof b === "undefined" ||
1881 | QUnit.objectType(a) !== QUnit.objectType(b) ) {
1882 | return false; // don't lose time with error prone cases
1883 | } else {
1884 | return bindCallbacks(a, callbacks, [ b, a ]);
1885 | }
1886 |
1887 | // apply transition with (1..n) arguments
1888 | }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) );
1889 | };
1890 |
1891 | return innerEquiv;
1892 | }());
1893 |
1894 | /**
1895 | * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
1896 | * http://flesler.blogspot.com Licensed under BSD
1897 | * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
1898 | *
1899 | * @projectDescription Advanced and extensible data dumping for Javascript.
1900 | * @version 1.0.0
1901 | * @author Ariel Flesler
1902 | * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
1903 | */
1904 | QUnit.jsDump = (function() {
1905 | function quote( str ) {
1906 | return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
1907 | }
1908 | function literal( o ) {
1909 | return o + "";
1910 | }
1911 | function join( pre, arr, post ) {
1912 | var s = jsDump.separator(),
1913 | base = jsDump.indent(),
1914 | inner = jsDump.indent(1);
1915 | if ( arr.join ) {
1916 | arr = arr.join( "," + s + inner );
1917 | }
1918 | if ( !arr ) {
1919 | return pre + post;
1920 | }
1921 | return [ pre, inner + arr, base + post ].join(s);
1922 | }
1923 | function array( arr, stack ) {
1924 | var i = arr.length, ret = new Array(i);
1925 | this.up();
1926 | while ( i-- ) {
1927 | ret[i] = this.parse( arr[i] , undefined , stack);
1928 | }
1929 | this.down();
1930 | return join( "[", ret, "]" );
1931 | }
1932 |
1933 | var reName = /^function (\w+)/,
1934 | jsDump = {
1935 | // type is used mostly internally, you can fix a (custom)type in advance
1936 | parse: function( obj, type, stack ) {
1937 | stack = stack || [ ];
1938 | var inStack, res,
1939 | parser = this.parsers[ type || this.typeOf(obj) ];
1940 |
1941 | type = typeof parser;
1942 | inStack = inArray( obj, stack );
1943 |
1944 | if ( inStack !== -1 ) {
1945 | return "recursion(" + (inStack - stack.length) + ")";
1946 | }
1947 | if ( type === "function" ) {
1948 | stack.push( obj );
1949 | res = parser.call( this, obj, stack );
1950 | stack.pop();
1951 | return res;
1952 | }
1953 | return ( type === "string" ) ? parser : this.parsers.error;
1954 | },
1955 | typeOf: function( obj ) {
1956 | var type;
1957 | if ( obj === null ) {
1958 | type = "null";
1959 | } else if ( typeof obj === "undefined" ) {
1960 | type = "undefined";
1961 | } else if ( QUnit.is( "regexp", obj) ) {
1962 | type = "regexp";
1963 | } else if ( QUnit.is( "date", obj) ) {
1964 | type = "date";
1965 | } else if ( QUnit.is( "function", obj) ) {
1966 | type = "function";
1967 | } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
1968 | type = "window";
1969 | } else if ( obj.nodeType === 9 ) {
1970 | type = "document";
1971 | } else if ( obj.nodeType ) {
1972 | type = "node";
1973 | } else if (
1974 | // native arrays
1975 | toString.call( obj ) === "[object Array]" ||
1976 | // NodeList objects
1977 | ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
1978 | ) {
1979 | type = "array";
1980 | } else if ( obj.constructor === Error.prototype.constructor ) {
1981 | type = "error";
1982 | } else {
1983 | type = typeof obj;
1984 | }
1985 | return type;
1986 | },
1987 | separator: function() {
1988 | return this.multiline ? this.HTML ? " " : "\n" : this.HTML ? " " : " ";
1989 | },
1990 | // extra can be a number, shortcut for increasing-calling-decreasing
1991 | indent: function( extra ) {
1992 | if ( !this.multiline ) {
1993 | return "";
1994 | }
1995 | var chr = this.indentChar;
1996 | if ( this.HTML ) {
1997 | chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
1998 | }
1999 | return new Array( this.depth + ( extra || 0 ) ).join(chr);
2000 | },
2001 | up: function( a ) {
2002 | this.depth += a || 1;
2003 | },
2004 | down: function( a ) {
2005 | this.depth -= a || 1;
2006 | },
2007 | setParser: function( name, parser ) {
2008 | this.parsers[name] = parser;
2009 | },
2010 | // The next 3 are exposed so you can use them
2011 | quote: quote,
2012 | literal: literal,
2013 | join: join,
2014 | //
2015 | depth: 1,
2016 | // This is the list of parsers, to modify them, use jsDump.setParser
2017 | parsers: {
2018 | window: "[Window]",
2019 | document: "[Document]",
2020 | error: function(error) {
2021 | return "Error(\"" + error.message + "\")";
2022 | },
2023 | unknown: "[Unknown]",
2024 | "null": "null",
2025 | "undefined": "undefined",
2026 | "function": function( fn ) {
2027 | var ret = "function",
2028 | // functions never have name in IE
2029 | name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
2030 |
2031 | if ( name ) {
2032 | ret += " " + name;
2033 | }
2034 | ret += "( ";
2035 |
2036 | ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
2037 | return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
2038 | },
2039 | array: array,
2040 | nodelist: array,
2041 | "arguments": array,
2042 | object: function( map, stack ) {
2043 | /*jshint forin:false */
2044 | var ret = [ ], keys, key, val, i;
2045 | QUnit.jsDump.up();
2046 | keys = [];
2047 | for ( key in map ) {
2048 | keys.push( key );
2049 | }
2050 | keys.sort();
2051 | for ( i = 0; i < keys.length; i++ ) {
2052 | key = keys[ i ];
2053 | val = map[ key ];
2054 | ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
2055 | }
2056 | QUnit.jsDump.down();
2057 | return join( "{", ret, "}" );
2058 | },
2059 | node: function( node ) {
2060 | var len, i, val,
2061 | open = QUnit.jsDump.HTML ? "<" : "<",
2062 | close = QUnit.jsDump.HTML ? ">" : ">",
2063 | tag = node.nodeName.toLowerCase(),
2064 | ret = open + tag,
2065 | attrs = node.attributes;
2066 |
2067 | if ( attrs ) {
2068 | for ( i = 0, len = attrs.length; i < len; i++ ) {
2069 | val = attrs[i].nodeValue;
2070 | // IE6 includes all attributes in .attributes, even ones not explicitly set.
2071 | // Those have values like undefined, null, 0, false, "" or "inherit".
2072 | if ( val && val !== "inherit" ) {
2073 | ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
2074 | }
2075 | }
2076 | }
2077 | ret += close;
2078 |
2079 | // Show content of TextNode or CDATASection
2080 | if ( node.nodeType === 3 || node.nodeType === 4 ) {
2081 | ret += node.nodeValue;
2082 | }
2083 |
2084 | return ret + open + "/" + tag + close;
2085 | },
2086 | // function calls it internally, it's the arguments part of the function
2087 | functionArgs: function( fn ) {
2088 | var args,
2089 | l = fn.length;
2090 |
2091 | if ( !l ) {
2092 | return "";
2093 | }
2094 |
2095 | args = new Array(l);
2096 | while ( l-- ) {
2097 | // 97 is 'a'
2098 | args[l] = String.fromCharCode(97+l);
2099 | }
2100 | return " " + args.join( ", " ) + " ";
2101 | },
2102 | // object calls it internally, the key part of an item in a map
2103 | key: quote,
2104 | // function calls it internally, it's the content of the function
2105 | functionCode: "[code]",
2106 | // node calls it internally, it's an html attribute value
2107 | attribute: quote,
2108 | string: quote,
2109 | date: quote,
2110 | regexp: literal,
2111 | number: literal,
2112 | "boolean": literal
2113 | },
2114 | // if true, entities are escaped ( <, >, \t, space and \n )
2115 | HTML: false,
2116 | // indentation unit
2117 | indentChar: " ",
2118 | // if true, items in a collection, are separated by a \n, else just a space.
2119 | multiline: true
2120 | };
2121 |
2122 | return jsDump;
2123 | }());
2124 |
2125 | /*
2126 | * Javascript Diff Algorithm
2127 | * By John Resig (http://ejohn.org/)
2128 | * Modified by Chu Alan "sprite"
2129 | *
2130 | * Released under the MIT license.
2131 | *
2132 | * More Info:
2133 | * http://ejohn.org/projects/javascript-diff-algorithm/
2134 | *
2135 | * Usage: QUnit.diff(expected, actual)
2136 | *
2137 | * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
2138 | */
2139 | QUnit.diff = (function() {
2140 | /*jshint eqeqeq:false, eqnull:true */
2141 | function diff( o, n ) {
2142 | var i,
2143 | ns = {},
2144 | os = {};
2145 |
2146 | for ( i = 0; i < n.length; i++ ) {
2147 | if ( !hasOwn.call( ns, n[i] ) ) {
2148 | ns[ n[i] ] = {
2149 | rows: [],
2150 | o: null
2151 | };
2152 | }
2153 | ns[ n[i] ].rows.push( i );
2154 | }
2155 |
2156 | for ( i = 0; i < o.length; i++ ) {
2157 | if ( !hasOwn.call( os, o[i] ) ) {
2158 | os[ o[i] ] = {
2159 | rows: [],
2160 | n: null
2161 | };
2162 | }
2163 | os[ o[i] ].rows.push( i );
2164 | }
2165 |
2166 | for ( i in ns ) {
2167 | if ( hasOwn.call( ns, i ) ) {
2168 | if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
2169 | n[ ns[i].rows[0] ] = {
2170 | text: n[ ns[i].rows[0] ],
2171 | row: os[i].rows[0]
2172 | };
2173 | o[ os[i].rows[0] ] = {
2174 | text: o[ os[i].rows[0] ],
2175 | row: ns[i].rows[0]
2176 | };
2177 | }
2178 | }
2179 | }
2180 |
2181 | for ( i = 0; i < n.length - 1; i++ ) {
2182 | if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
2183 | n[ i + 1 ] == o[ n[i].row + 1 ] ) {
2184 |
2185 | n[ i + 1 ] = {
2186 | text: n[ i + 1 ],
2187 | row: n[i].row + 1
2188 | };
2189 | o[ n[i].row + 1 ] = {
2190 | text: o[ n[i].row + 1 ],
2191 | row: i + 1
2192 | };
2193 | }
2194 | }
2195 |
2196 | for ( i = n.length - 1; i > 0; i-- ) {
2197 | if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
2198 | n[ i - 1 ] == o[ n[i].row - 1 ]) {
2199 |
2200 | n[ i - 1 ] = {
2201 | text: n[ i - 1 ],
2202 | row: n[i].row - 1
2203 | };
2204 | o[ n[i].row - 1 ] = {
2205 | text: o[ n[i].row - 1 ],
2206 | row: i - 1
2207 | };
2208 | }
2209 | }
2210 |
2211 | return {
2212 | o: o,
2213 | n: n
2214 | };
2215 | }
2216 |
2217 | return function( o, n ) {
2218 | o = o.replace( /\s+$/, "" );
2219 | n = n.replace( /\s+$/, "" );
2220 |
2221 | var i, pre,
2222 | str = "",
2223 | out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
2224 | oSpace = o.match(/\s+/g),
2225 | nSpace = n.match(/\s+/g);
2226 |
2227 | if ( oSpace == null ) {
2228 | oSpace = [ " " ];
2229 | }
2230 | else {
2231 | oSpace.push( " " );
2232 | }
2233 |
2234 | if ( nSpace == null ) {
2235 | nSpace = [ " " ];
2236 | }
2237 | else {
2238 | nSpace.push( " " );
2239 | }
2240 |
2241 | if ( out.n.length === 0 ) {
2242 | for ( i = 0; i < out.o.length; i++ ) {
2243 | str += "" + out.o[i] + oSpace[i] + "";
2244 | }
2245 | }
2246 | else {
2247 | if ( out.n[0].text == null ) {
2248 | for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
2249 | str += "" + out.o[n] + oSpace[n] + "";
2250 | }
2251 | }
2252 |
2253 | for ( i = 0; i < out.n.length; i++ ) {
2254 | if (out.n[i].text == null) {
2255 | str += "" + out.n[i] + nSpace[i] + " ";
2256 | }
2257 | else {
2258 | // `pre` initialized at top of scope
2259 | pre = "";
2260 |
2261 | for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
2262 | pre += "" + out.o[n] + oSpace[n] + "";
2263 | }
2264 | str += " " + out.n[i].text + nSpace[i] + pre;
2265 | }
2266 | }
2267 | }
2268 |
2269 | return str;
2270 | };
2271 | }());
2272 |
2273 | // For browser, export only select globals
2274 | if ( typeof window !== "undefined" ) {
2275 | extend( window, QUnit.constructor.prototype );
2276 | window.QUnit = QUnit;
2277 | }
2278 |
2279 | // For CommonJS environments, export everything
2280 | if ( typeof module !== "undefined" && module.exports ) {
2281 | module.exports = QUnit;
2282 | }
2283 |
2284 |
2285 | // Get a reference to the global object, like window in browsers
2286 | }( (function() {
2287 | return this;
2288 | })() ));
2289 |
--------------------------------------------------------------------------------