├── .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 | [![Build Status](https://travis-ci.org/bgrins/javascript-astar.png?branch=master)](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 | 30 | 36 |
    37 | 38 | 48 | 49 |
    50 | 51 | 52 |
    53 | 54 | 55 |
    56 | 57 | 58 |
    59 | 60 | 61 |
    62 | 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 | "

    " + escapeText( document.title ) + "

    " + 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 += ""; 452 | 453 | if ( actual !== expected ) { 454 | output += ""; 455 | output += ""; 456 | } 457 | 458 | source = sourceFromStacktrace(); 459 | 460 | if ( source ) { 461 | details.source = source; 462 | output += ""; 463 | } 464 | 465 | output += "
      Expected:
      " + expected + "
      Result:
      " + actual + "
      Diff:
      " + QUnit.diff( expected, actual ) + "
      Source:
      " + escapeText( source ) + "
      "; 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 += ""; 497 | } 498 | 499 | if ( source ) { 500 | details.source = source; 501 | output += ""; 502 | } 503 | 504 | output += "
      Result:
      " + escapeText( actual ) + "
      Source:
      " + escapeText( source ) + "
      "; 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 += ""; 611 | } else { 612 | 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 += ""; 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 | --------------------------------------------------------------------------------