<<<<----- Return to Wes Mantooth
            /**
             * Finds individual shapes within a map
             * This map can be a bitmap if code is added to get canvas img data
             * This is just a proof of concept for the [Find the length of a coastline] project
             *
             * http://jeremyheminger.com/article/programming/find-length-coastline-hypothesis
             * http://jeremyheminger.com/find-length-coastline-programming-part-1
             * http://jeremyheminger.com/find-length-coastline-programming-part-2
             * http://jeremyheminger.com/find-length-coastline-programming-part-3
             *
             * To view the resulting array Right-Click and Inspect
             * */
             
            //@param {Number} reference the canvas
            var i;
            //@param {Array}
            var LOOP = [];
            //@param {Array}
            var RESULT = [];
            //@param {Number}
            var MAXLOOPS = 200;
            //@param {Number}
            var _I = 0;
            //@param {Number}
            var _L = 0;
            //@param {Number}
            var yl = xy.length;
            //@param {Number}
            var xl = xy[0].length;
            //@param {Array} this is the map we will be testing
            var xy = [
                     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
                     [0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
                     [0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
                     [0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0],
                     [0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0],
                     [0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,1,1,1,1,1,0,0,0],
                     [0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0],
                     [0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,0,0,0],
                     [0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,0,0,0],
                     [0,0,0,0,0,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,1,1,1,1,1,0,0,0],
                     [0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,0,1,0],
                     [0,0,0,0,1,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,0,1,0],
                     [0,0,0,0,1,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,1,0],
                     [0,0,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,0,1,0],
                     [0,0,0,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,1,1,0,1,0],
                     [0,0,0,0,0,0,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0],
                     [0,0,0,0,0,0,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0],
                     [0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0],
                     [0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0],
                     [0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0],
                     [0,0,0,0,0,1,1,1,1,0,0,0,0,1,0,0,0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0],
                     [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,1,0,0,0],
                     [0,0,0,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0],
                     [0,1,1,0,0,0,0,1,1,1,1,1,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0],
                     [0,0,1,0,0,0,0,1,1,1,1,1,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0],
                     [0,0,1,1,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0],
                     [0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],
                     [0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],
                     [0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],
                     [0,0,0,0,1,1,1,0,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],
                     [0,0,0,0,1,1,1,1,1,1,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
                     [0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
                     [0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
                     [0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
                     [0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
                     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0],
                     [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
                     ];
            // when the browser is ready
            window.onload = function() {
    
                'use strict';
                
                // initialize a Wes Mantooth canvas
                i = $w.canvas.init(document.getElementById('target'));
                // draw the grid
                $w.draw.grid(i,1000,1000,10);
                run();
            }
            /**
             * run everything when ready
             * @returns {Void}
             **/
            function run() {
                // loop the map
                for(var y=0; y<yl; y++) {
                    for(var x=0; x<xl; x++) {
                        // if this pixel is a target and has not yet been tested
                        if (xy[y][x] == 1) {
                            // draw a dot here
                            $w.canvas.rectangle(i,x*10,y*10,10,10,'#2c07b9','fill');
                            // add the x,y coordinate to an array
                            LOOP.push([x,y]);
                        }
                    }
                }
                // get the length of the loop array
                _L = LOOP.length;
                // run the loop with a promise in order to allow asynchronous 
                let promise = look(xy,LOOP[_I][0],LOOP[_I][1]);
                promise.then(successCallback, failureCallback);
            }
            /**
             * @returns {Void}
             * */
            function successCallback() {
                _I++;
                if (_I<_L) {
                    setTimeout(function(){
                        console.log('RUNNING');
                        let promise = look(xy,LOOP[_I][0],LOOP[_I][1]);
                        promise.then(successCallback, failureCallback);
                    },100);
                }else{
                    console.log(RESULT);
                }
            }
            /**
             * @returns {Void}
             * */
            function failureCallback(error) {
                console.log('failureCallback');
                console.log(error);
            }
            /**
             * @param {Array}
             * @param {Number}
             * #param {Number}
             * @returns {Void}
             * */
            async function look(xy,x,y) {
                // check if this shape has already been found 
                if (xy[y][x] != 1) {
                    console.log('NO NEED TO RUN');
                    return;
                }
                // @param {Array} a local array to test against
                var RESULTnow = [];
                
                console.log('look');
                //@param {Object}
                var obj = {
                    x:x,
                    y:y,
                    xy:xy,
                    m:true,
                    i:0
                }
                // run a test on the first pixel
                obj = move(obj);
                
                //@param {Boolean}
                var moves = true;
                //@param {Number}
                var j = 0;
                //@param {Number}
                var id = setInterval(function() {
                    if(obj.i == 2)
                        RESULTnow.push([obj.x,obj.y]);
                    // run the test
                    obj = move(obj);
                    // update if there are any moves left
                    moves = obj.m;
                    // increment the counter
                    j++;
                    // if the test has run too many times its likely never to complete
                    if (j > MAXLOOPS) {
                        console.log('MAX LOOPS');
                        moves = false;
                        j = 0;
                    }
                    if (!moves) {
                        clearInterval(id);
                        console.log("NO MORE MOVES");
                        var duplicate = false;
                        var rl = RESULT.length;
                        var rnl = RESULTnow.length;
                        for(var j=0; j<rl; j++) {
                            for(var k = 0; k<rnl;k++) {
                                if (RESULTnow[k][0] == RESULT[j][0] && RESULTnow[j][1] == RESULT[k][1]) {
                                    duplicate = true;
                                }
                            }
                        }
                        if (!duplicate) {
                            RESULT.push(RESULTnow);
                        }
                    }
                },1);
            }
            function move(obj) {
                //@param {Number}
                let max = 15;
                //@param {Boolean}
                let moved = false;
                
                // increment the current map locations weight
                obj.xy[obj.y][obj.x]++;
                obj.i = obj.xy[obj.y][obj.x];
                //@param {Number}
                let c = obj.xy[obj.y][obj.x] * 10;
                //@param {String}
                let color = $w.color.rgbToHex(c*2,c*3,200);
                // update the dot color on the map
                $w.canvas.rectangle(0,(obj.x)*10,(obj.y)*10,10,10,color,'fill');
                //@param {Array}
                let dirs = [null,null,null,null];
                
                // if the value of a key is set get its current weight
                if (undefined !== obj.xy[obj.y-1] && obj.xy[obj.y-1][obj.x] > 0)dirs[0] = obj.xy[obj.y-1][obj.x];
                if (undefined !== obj.xy[obj.y][obj.x+1] && obj.xy[obj.y][obj.x+1] > 0)dirs[1] = obj.xy[obj.y][obj.x+1];
                if (undefined !== obj.xy[obj.y+1] && obj.xy[obj.y+1][obj.x] > 0)dirs[2] = obj.xy[obj.y+1][obj.x];
                if (undefined !== obj.xy[obj.y][obj.x-1] && obj.xy[obj.y][obj.x-1] > 0)dirs[3] = obj.xy[obj.y][obj.x-1];
                
                // loop the directions to get the lowest weight
                var min = max, dir = 0;
                for(let i = 0; i<4; i++) {
                    if (dirs[i] != null)
                        if (dirs[i] < min){
                            min = dirs[i];
                            dir = i;
                        }
                }
                // make sure that the weight is less than the max
                if (min < max) {
                    // move the test based on the direction with the lowest weight
                    switch(dir) {
                        case 0:
                            obj.y--;
                            moved = true;
                            break;
                        case 1:
                            obj.x++;
                            moved = true;
                            break;
                        case 2:
                            obj.y++;
                            moved = true;
                            break;
                        case 3:
                            obj.x--;
                            moved = true;
                            break;
                    }
                }
                
                // if a move was made then pass that result back
                if (!moved)obj.m = false;
                
                return obj;
            }