<commit_before>
/*------------------------------DECLARING ARRAYS -----------------------------------------------------------------*/

var temp_array = [];    /*ARRAY FOR STORING THE TEMPRATUE VALUES*/
var input_arr = [];    /*ARRAY FOR STORING THE RATS POSITIONS AND FINAL OUTPUT*/
var min_array = [];    /*RATS POSITION ARRAY USED FOR INTERMIDIATE PHASES*/

function RatsPostions(input1,input2,input3)
{
	temp_array = input2.split(',');

        /*CREATING 2 DIMENSION ARRAY FOR THE TEMPRATURE*/

        for(var k=0;k<temp_array.length;k++)
        {
            temp_array.push(temp_array[0].split('#'));
            temp_array.shift();

        }

        /*CREATING 2 DIMENSION ARRAY FOR RATS POSITIONS*/

        input_arr = input1.split(',');

        for(var p=0;p<input_arr.length;p++)
        {
            input_arr.push(input_arr[0].split('#'));
            input_arr.shift();
        }

       /* FUNCTION TO FIND THE MINIMUM MAGNITUDE(TEMPRATURE DIFFERENCE) AND THE CURRENT RAT POSITIONS (i.e. BRICK DIMENSION) */

        function findMin(pos1,pos2) {

          var  Min;
          var  obj  = [pos1,pos2];
          var count = 0;

            /* CHECK TOP POSITION FROM THE CURRENT BRICK */

            if( pos1-1 >= 0 && pos2 >= 0) {

                Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1-1][pos2]);
                obj[0]=pos1-1;
                obj[1]=pos2;

            }

            /* CHECK RIGHT POSITION FROM THE CURRENT BRICK */

            if(pos1 >= 0 && pos2+1 < 5) {

              if( Min != undefined ) {

                if(Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2+1]) < Min) {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2+1]);
                    obj[0]=pos1;
                    obj[1]=pos2+1;

                    }

                } else {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2+1]);
                    obj[0]=pos1;
                    obj[1]=pos2+1;

                }
            }

	    /* CHECK BOTTOM POSITION FROM THE CURRENT BRICK */

            if(pos1+1 < 6 && pos2 >= 0) {

                if(Min != undefined ) {

                if(Math.abs(temp_array[pos1][pos2] - temp_array[pos1+1][pos2]) < Min) {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1+1][pos2]);

                    obj[0]=pos1+1;
                    obj[1]=pos2;

                    }

                } else {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1+1][pos2]);
                    obj[0]=pos1+1;
                    obj[1]=pos2;

                }
            }

           /* CHECK LEFT POSITION FROM THE CURRENT BRICK */

            if(pos1 >= 0 && pos2-1 >= 0 ) {

                if(Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2-1]) < Min) {

                   Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2-1]);
                   obj[0]=pos1;
                   obj[1]=pos2-1;
                }

            }

            return obj; /* RETURN NEXT POSITION BASED ON THE MINIMUM TEMPRATURE DIFFERENCE */

        } /*------------------------- END OF FINDMIN FUNCTION --------------------------------*/

        var count2=0;

        /*NO. OF ITERATION NEED TO PERFORM TO FIND THE FINAL POSTION OF RATS .*/
        /* TAKE INPUT3 FOR LOOPING CONSTRAINT WHICH PASSED AS ARGUMENT WHEN ratsPosition FUNCTION IS CALLED. */

        for(var x=0;x<input3;x++)
            {
                if(count2 === 0 ) {
                    for(var q=0;q<input_arr.length;q++)
                    {
                    	/* ARRAY START FROM 0TH POSTION SO WE NEED TO CHANGE THE INPUT */

                        input_arr[q][0] = input_arr[q][0] - 1;
                        input_arr[q][1] = input_arr[q][1] - 1;
                        min_array.push(findMin(input_arr[q][0],input_arr[q][1]));

                    }
                    count2++; /*ONLY ONCE WE NEED TO PEFORM -1 OPERATION */

                } else {

                    for(var q=0;q<input_arr.length;q++)
                    {
                        min_array.push(findMin(input_arr[q][0],input_arr[q][1]));

                    }

                } /*END OF ELSE */

                /*INPUT_ARR CONTAINS THE FINAL RESULT*/

                input_arr = []; /* FLUSH THE INPUT ARRAY FOR THE NEXT ITERATION */
                input_arr = min_array;
                min_array = []; /* FLUSH THE MIN_ARRAY FOR THE NEXT ITERATION. */

            } /*END OF FOR LOOP*/

           /*---------------------------------CREATE A STRING TO RETURN A FINAL RESULT-------------------*/
           var finalString = '';

           for(z=0;z<input_arr.length;z++) {

              finalString += (input_arr[z][0] + 1) + '#' + (input_arr[z][1] + 1) + ',';

           }

          /*RETURN THE FINAL OUTPUT*/

          return finalString.substr(0,(finalString.length - 1));

	}

/* CALL FUNCTION TO CHECK THE RESULT */
var finalRatsPositions = RatsPostions("1#1,2#5,3#3,6#3","2#6#8#6#-7,2#5#-5#-5#0,-1#3#-8#8#7,3#2#0#6#9,2#1#-4#5#8,-5#6#7#4#7",3);
console.log(finalRatsPositions);

<commit_msg>comment added<commit_after>
/*------------------------------DECLARING ARRAYS -----------------------------------------------------------------*/

var temp_array = [];    /*ARRAY FOR STORING THE TEMPRATUE VALUES*/
var input_arr = [];    /*ARRAY FOR STORING THE RATS POSITIONS AND FINAL OUTPUT*/
var min_array = [];    /*RATS POSITION ARRAY USED FOR INTERMIDIATE PHASES*/

function RatsPostions(input1,input2,input3)
{
	temp_array = input2.split(',');

        /*CREATING 2 DIMENSION ARRAY FOR THE TEMPRATURE*/

        for(var k=0;k<temp_array.length;k++)
        {
            temp_array.push(temp_array[0].split('#'));
            temp_array.shift();

        }

        /*CREATING 2 DIMENSION ARRAY FOR RATS POSITIONS*/

        input_arr = input1.split(',');

        for(var p=0;p<input_arr.length;p++)
        {
            input_arr.push(input_arr[0].split('#'));
            input_arr.shift();
        }

       /* FUNCTION TO FIND THE MINIMUM MAGNITUDE(TEMPRATURE DIFFERENCE) AND THE CURRENT RAT POSITIONS (i.e. BRICK DIMENSION) */

        function findMin(pos1,pos2) {

          var  Min;
          var  obj  = [pos1,pos2];
          var count = 0;

            /* CHECK TOP POSITION FROM THE CURRENT BRICK */

            if( pos1-1 >= 0 && pos2 >= 0) {

                Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1-1][pos2]);
                obj[0]=pos1-1;
                obj[1]=pos2;

            }

            /* CHECK RIGHT POSITION FROM THE CURRENT BRICK */

            if(pos1 >= 0 && pos2+1 < 5) {

              if( Min != undefined ) {

                if(Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2+1]) < Min) {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2+1]);
                    obj[0]=pos1;
                    obj[1]=pos2+1;

                    }

                } else {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2+1]);
                    obj[0]=pos1;
                    obj[1]=pos2+1;

                }
            }

	    /* CHECK BOTTOM POSITION FROM THE CURRENT BRICK */

            if(pos1+1 < 6 && pos2 >= 0) {

                if(Min != undefined ) {

                if(Math.abs(temp_array[pos1][pos2] - temp_array[pos1+1][pos2]) < Min) {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1+1][pos2]);

                    obj[0]=pos1+1;
                    obj[1]=pos2;

                    }

                } else {

                    Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1+1][pos2]);
                    obj[0]=pos1+1;
                    obj[1]=pos2;

                }
            }

           /* CHECK LEFT POSITION FROM THE CURRENT BRICK */

            if(pos1 >= 0 && pos2-1 >= 0 ) {

                if(Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2-1]) < Min) {

                   Min = Math.abs(temp_array[pos1][pos2] - temp_array[pos1][pos2-1]);
                   obj[0]=pos1;
                   obj[1]=pos2-1;
                }

            }

            return obj; /* RETURN NEXT POSITION BASED ON THE MINIMUM TEMPRATURE DIFFERENCE */

        } /*------------------------- END OF FINDMIN FUNCTION --------------------------------*/

        var count2=0;

        /*NO. OF ITERATION NEED TO PERFORM TO FIND THE FINAL POSTION OF RATS .*/
        /* TAKE INPUT3 FOR LOOPING CONSTRAINT WHICH PASSED AS ARGUMENT WHEN ratsPosition FUNCTION IS CALLED. */

        for(var x=0;x<input3;x++)
            {
                if(count2 === 0 ) {
                    for(var q=0;q<input_arr.length;q++)
                    {
                    	/* ARRAY START FROM 0TH POSTION SO WE NEED TO CHANGE THE INPUT */

                        input_arr[q][0] = input_arr[q][0] - 1;
                        input_arr[q][1] = input_arr[q][1] - 1;
                        min_array.push(findMin(input_arr[q][0],input_arr[q][1]));

                    }
                    count2++; /*ONLY ONCE WE NEED TO PEFORM -1 OPERATION */

                } else {

                    for(var q=0;q<input_arr.length;q++)
                    {
                        min_array.push(findMin(input_arr[q][0],input_arr[q][1]));

                    }

                } /*END OF ELSE */

                /*INPUT_ARR CONTAINS THE FINAL RESULT*/

                input_arr = []; /* FLUSH THE INPUT ARRAY FOR THE NEXT ITERATION */
                input_arr = min_array;
                min_array = []; /* FLUSH THE MIN_ARRAY FOR THE NEXT ITERATION. */

            } /*END OF FOR LOOP*/

           /*---------------------------------CREATE A STRING TO RETURN A FINAL RESULT-------------------*/
           var finalString = '';

           for(z=0;z<input_arr.length;z++) {

              finalString += (input_arr[z][0] + 1) + '#' + (input_arr[z][1] + 1) + ',';

           }

          /*RETURN THE FINAL OUTPUT*/

          return finalString.substr(0,(finalString.length - 1));

	}

/* CALL FUNCTION TO CHECK THE RESULT */
/* There are 3 arguments for the function. Tempratures,ratePositions and no. of iterations. */
var finalRatsPositions = RatsPostions("1#1,2#5,3#3,6#3","2#6#8#6#-7,2#5#-5#-5#0,-1#3#-8#8#7,3#2#0#6#9,2#1#-4#5#8,-5#6#7#4#7",3);
console.log(finalRatsPositions);

<|endoftext|>


<commit_before>exports.locate = function(load) {
  return window.location.protocol + '//' + load.name;
};

exports.fetch = function(load) {
  return new Promise(function(resolve, reject) {
    var head = document.getElementsByTagName('head')[0];
    var s = document.createElement('script');
    s.async = true;

    function complete(evt) {
      if (s.readyState && s.readyState !== 'loaded' && s.readyState != 'complete'){
        return;
      }
      cleanup();
      resolve('');
    }

    function error(evt) {
      cleanup();
      reject(evt);
    }

    if (s.attachEvent) {
      s.attachEvent('onreadystatechange', complete);
    }
    else {
      s.addEventListener('load', complete, false);
      s.addEventListener('error', error, false);
    }

    s.src = load.address;
    head.appendChild(s);

    function cleanup() {
      if (s.detachEvent){
        s.detachEvent('onreadystatechange', complete);
      }
      else {
        s.removeEventListener('load', complete, false);
        s.removeEventListener('error', error, false);
      }
      head.removeChild(s);
    }
  });
};<commit_msg>Added support for modules with protocols<commit_after>/*
 * https://www.npmjs.com/package/system-script
 * system.js plugin to load an import via a script tag instead of a XHR request which avoid CORS issues
 * */
'use strict';
exports.locate = function(load) {
  var name = load.name.replace(/^(https?:)?\/\//, '');
  return window.location.protocol + '//' + name;
};

exports.fetch = function(load) {
  return new Promise(function(resolve, reject) {
    var head = document.getElementsByTagName('head')[0];
    var s = document.createElement('script');
    s.async = true;

    function complete(/*evt*/) {
      if (s.readyState && s.readyState !== 'loaded' && s.readyState !== 'complete'){
        return;
      }
      cleanup();
      resolve('');
    }

    function error(evt) {
      cleanup();
      reject(evt);
    }

    if (s.attachEvent) {
      s.attachEvent('onreadystatechange', complete);
    }
    else {
      s.addEventListener('load', complete, false);
      s.addEventListener('error', error, false);
    }

    s.src = load.address;
    head.appendChild(s);

    function cleanup() {
      if (s.detachEvent){
        s.detachEvent('onreadystatechange', complete);
      }
      else {
        s.removeEventListener('load', complete, false);
        s.removeEventListener('error', error, false);
      }
      head.removeChild(s);
    }
  });
};
<|endoftext|>


<commit_before>/**
 * FeatureLayer.selection-complete
 * @external FeatureLayer#event:selection-complete
 * @see {link:https://developers.arcgis.com/javascript/jsapi/featurelayer-amd.html#event-selection-complete}
 * @member {Graphic[]} features - The features that were selected by a query.
 * @member {Number} method - The selection method.
 * @member {FeatureLayer} target - The feature layer that performed the selection.
 */

/**
 * Create map response
 * @external createMapResponse
 * @see {@link https://developers.arcgis.com/javascript/jsapi/esri.arcgis.utils-amd.html#createmap esri/arcgis/utils.createMap()
 * @member {external:esri/Map} map
 * @member {(EventHandler|undefined)} clickEventHandle
 * @member {(Function|undefined)} clickEventListener
 * @member {Object} itemInfo
 * @member {Object} itemInfo.item
 * @member {Object} itemInfo.itemData
 * @member {Object.<string, Error>} itemInfo.errors
 */

/**
 * dojo/Deferred
 * @description Deferred response from an asynchronous operation.
 * @external dojo/Deferred
 * @see {@link http://dojotoolkit.org/reference-guide/1.10/dojo/Deferred.html dojo/Deferred}
 */

require([
  "esri/config",
  "esri/map",
  "esri/geometry/geometryEngineAsync",
  "esri/tasks/query",
  "esri/layers/FeatureLayer",
  "esri/layers/ArcGISDynamicMapServiceLayer",
  "esri/dijit/FeatureTable",
  "esri/dijit/LayerList",
  "esri/dijit/HomeButton",
  "dijit/registry",
  "witpa/ProjectFilter",
  "dojo/parser",
  "dojo/dnd/Moveable",
  "esri/arcgis/utils",
  "esri/dijit/Search",
  "esri/dijit/BasemapGallery",
  "esri/dijit/Legend",
  "esri/tasks/QueryTask",
  "esri/tasks/StatisticDefinition",
  "esri/symbols/SimpleLineSymbol",
  "esri/Color",
  "witpa/infoWindowUtils",
  "witpa/wsdotMapUtils",
  "dojo/text!./webmap/item.json",
  "dojo/text!./webmap/itemdata.json",

  "dijit/layout/BorderContainer",
  "dijit/layout/ContentPane",
  "dijit/layout/AccordionContainer",
  "dijit/layout/AccordionPane"
], function (
  esriConfig,
  Map,
  geometryEngineAsync,
  Query,
  FeatureLayer,
  ArcGISDynamicMapServiceLayer,
  FeatureTable,
  LayerList,
  HomeButton,
  registry,
  ProjectFilter,
  parser,
  Moveable,
  arcgisUtils,
  Search,
  BasemapGallery,
  Legend,
  QueryTask,
  StatisticDefinition,
  SimpleLineSymbol,
  Color,
  infoWindowUtils,
  wsdotMapUtils,
  webmapItem,
  webmapItemData
) {
    "use strict";
    var projectFilter = new ProjectFilter(document.forms.filterForm);
    var filterPane = document.getElementById("filterPane");

    filterPane.appendChild(projectFilter.form);

    ["hqolymgis98d"].forEach(function (server) {
        esriConfig.defaults.io.corsEnabledServers.push(server);
    });

    // Parse the Dojo layout widgets defined in HTML markup.
    parser.parse();

    webmapItem = JSON.parse(webmapItem);
    webmapItemData = JSON.parse(webmapItemData);

    // Create the map using JSON webmap definition.
    arcgisUtils.createMap({
        item: webmapItem,
        itemData: webmapItemData
    }, "map", {
        mapOptions: wsdotMapUtils.defaultMapOptions
    }
    /**
     * Post map creation tasks.
     * @param {external:createMapResponse} response
     */
    ).then(function (response) {
        var map = response.map;

        infoWindowUtils.makeInfoWindowDraggable(response.map.infoWindow);

        var dynamicLayer = map.getLayer("PlannedProjects");

        var search = new Search({
            map: response.map
        }, "search");

        search.on("load", function () {
            var sources, source;
            sources = search.get("sources");
            source = search.defaultSource; //or sources[0];
            source.countryCode = "US";
            source.searchExtent = response.map.extent;
            search.set("sources", sources);
        });

        search.startup();

        var outFields = [
            "OBJECTID",
            "StateRouteNumber",
            "Project_Title",
            "County",
            "Legislative_District",
            "Revenue_Package",
            "Sub_Category",
            "PIN",
            "Improvement_Type",
            "Work_Description",
            "Sub_Program",
            "Region",
            "Program",
            "Begin_Preliminary_Engineering",
            "Advertisement_Date",
            "Operationally_Complete",
            "Congressional_District",
            "Begin_Mile_Post",
            "End_Mile_Post",
            "Total_Dollars",
            "Direction_Ind",
            "RouteID",
            "Begin_ARM",
            "End_ARM",
            "SRMP_Begin_AB_Ind",
            "SRMP_End_AB_Ind",
            "SRMP_Date",
            "LRSDATE",
            "RelRouteType",
            "RelRouteQual",
            "Mid_Arm",
            "Mid_Mile_Post",
            "Project_List",
            "LOC_ERROR"
        ];

        var table;

        // Create the feature layer that will be used by the FeatureTable and to highlight selected table rows on the map.
        var featureLayerUrl = [dynamicLayer.url, "0"].join("/");
        var layer = new FeatureLayer(featureLayerUrl, {
            id: "wsdotprojects",
            mode: FeatureLayer.MODE_SELECTION,
            outFields: outFields
        });

        map.addLayer(layer);

        var selectionSymbol = new SimpleLineSymbol().setColor(new Color([0, 255, 255, 1])).setWidth(2);
        layer.setSelectionSymbol(selectionSymbol);

        // When the user submits a query, set the feature layer's definition expression
        // so that only those rows are shown in the table.
        projectFilter.form.addEventListener("submit-query", function (e) {
            layer.clearSelection();
            layer.setDefinitionExpression(e.detail.where);
            dynamicLayer.setLayerDefinitions([
                e.detail.where
            ]);
            var query = new Query();
            query.where = e.detail.where;
            layer.queryExtent(query).then(function (queryExtentResponse) {
                var extent = queryExtentResponse.extent;
                map.setExtent(extent);
            });
            table.grid.refresh();

        });

        // Reset the definition expression to show all rows.
        projectFilter.form.addEventListener("reset", function (e) {
            layer.clearSelection();
            dynamicLayer.setDefaultLayerDefinitions();
            layer.setDefinitionExpression(layer.defaultDefinitionExpression);
            table.grid.refresh();
        });

        // Add the home button that allows the user to zoom to full extent.
        var homeButton = new HomeButton({
            map: map
        }, "homeButton");
        homeButton.startup();

        // Create the feature table
        table = new FeatureTable({
            featureLayer: layer,
            outFields: outFields,
            syncSelection: false,
            // The dateOptions are not actually honored: https://geonet.esri.com/message/520158
            /*
            dateOptions: {
              datePattern: "yyyyMMdd",
              timeEnabled: false,
              timePattern: null
            },
            */
            // These fields are hidden by default, but user can turn them back on.
            hiddenFields: [
              "LRSDate"
            ],
            showGridHeader: true,
            map: map
        }, "table");
        table.startup();

        function zoomToFeatures(features) {
            var geometries;
            if (features && features.length > 0) {
                if (features.length === 1) {
                    map.setExtent(features[0].geometry.getExtent(), true);
                } else {
                    geometries = features.map(function (graphic) {
                        return graphic.geometry;
                    });
                    geometryEngineAsync.union(geometries).then(function (unionedGeometry) {
                        map.setExtent(unionedGeometry.getExtent(), true);
                    });
                }
            }
        }

        /**
         * @typedef {Object} DGridRow
         * @property {Object} data
         * @property {number} data.OBJECTID
         * @property {HTMLElement} element
         * @property {string} id - A string containing the corresponding feature's Object ID.
         */

        /**
         * Selects or deselects features corresponding to row selected in the feature table.
         * @param {DGridRow[]} rows - An array of rows either selected or deselected from the feature table dGrid.
         * @param {Boolean} [deselect=false] - True to subtract the features associated with the rows to the feature layer selection, false to add them.
         * @returns {external:dojo/Deferred} Returns the promise from the selectFeatures function.
         */
        function selectOrDeselectFeatures(rows, deselect) {
            var selectionMethod = deselect ? FeatureLayer.SELECTION_SUBTRACT : FeatureLayer.SELECTION_ADD;
            var query = new Query();
            // Convert the array of rows into an array of corresponding object IDs.
            var objectIds = rows.map(function (row) {
                return parseInt(row.id, 10);
            });
            query.objectIds = objectIds;
            return layer.selectFeatures(query, selectionMethod);
        }

        layer.on("selection-complete", function (features, selectionMethod) {
            features = layer.getSelectedFeatures();
            zoomToFeatures(features);
        });

        /**
         *
         * @param {DGridRow[]} rows - The rows that were selected
         */
        table.on("row-select", function (rows) {
            selectOrDeselectFeatures(rows);
        });

        /**
         *
         * @param {DGridRow[]} rows - The rows that were unselected
         */
        table.on("row-deselect", function (rows) {
            selectOrDeselectFeatures(rows, true);
        });

        // resize panel when table close is toggled.
        table.tableCloseButton.addEventListener("click", function (e) {
            var gridMenuNode = registry.byId(table._gridMenu).domNode;
            var tableNode = registry.byId("tablePane").domNode;
            var borderContainer = registry.byId("borderContainer");
            var isOpening = e.target.classList.contains("toggleClosed");
            if (isOpening) {
                tableNode.style.height = tableNode.dataset.openHeight || "50%";
            } else {
                // Store the old height.
                tableNode.dataset.openHeight = tableNode.style.height || [tableNode.clientHeight, "px"].join("");
                // Set to "closed" height.
                tableNode.style.height = [gridMenuNode.clientHeight, "px"].join("");
            }
            borderContainer.resize();
        });

        var layerListItems = arcgisUtils.getLayerList(response);

        // Custom sort the layer list items array so that the item with the
        // title containing "WSDOT Projects" is last in the array. Other
        // items will remain in their original order.
        layerListItems.sort(function (a, b) {
            var re = /WSDOT Projects/i;
            var output;
            if (re.test(a.title)) {
                output = 1;
            } else if (re.test(b.title)) {
                output = -1;
            } else {
                output = 0;
            }
            return output;
        });

        // Create the layer list.
        var layerList = new LayerList({
            map: response.map,
            layers: layerListItems,
            showLegend: true,
            showOpacitySlider: true,
            showSublayers: true
        }, "layerList");
        layerList.startup();

        var basemapGallery = new BasemapGallery({
            map: response.map,
            basemapsGroup: {
                id: "085a9cb0bb664d29bf62b731ccc4aa64"
            },
            basemaps: [
                wsdotMapUtils.esriBasemaps["wsdot-multilevel"]
            ],
            basemapIds: wsdotMapUtils.esriBasemaps["wsdot-multilevel"].layers.map(function (layer) {
                return layer.id;
            })
        }, "basemapGallery");
        basemapGallery.startup();

        // Select the default basemap in the gallery.
        basemapGallery.on("load", function () {
            var basemap, basemaps = basemapGallery.basemaps, i;
            if (basemaps && basemaps.length > 0) {
                for (i = 0; i < basemaps.length; i++) {
                    basemap = basemaps[i];
                    if (/wsdot[\-\s]?multilevel/i.test(basemap.id)) {
                        basemapGallery.select(basemap.id);
                        break;
                    }
                }
            }
        });

        var legend = new Legend({
            map: response.map,
            layerInfos: arcgisUtils.getLegendLayers(response)
        }, "legend");
        legend.startup();

    });

    function getOperationalLayer(webMapData, opLayerId) {
        var opLayers = webMapData.operationalLayers;
        var opLayer;
        for (var i = 0; i < opLayers.length; i++) {
            if (opLayers[i].id === opLayerId) {
                opLayer = opLayers[i];
                break;
            }
        }
        return opLayer;
    }

    /**
     * Setup the background worker process for querying the 6-year project map service
     * for input suggestions.
     * @param {string} url - The URL for the map service layer to be queried.
     */
    (function (url) {

        if (!window.Worker) {
            console.log("This browser doesn't support web workers. Some features are not available.");
            return;
        }

        // Create the worker.
        var worker = new Worker("QueryWorker.js");

        /**
         * Handles messages from web worker.
         * @param {Event} e - worker message event
         * @param {Object} e.data - Data passed from worker.
         */
        worker.addEventListener("message", function (e) {

            /**
             * Adds values to the datalist corresponding to the given field name.
             * @param {string} fieldName - The name of a field in a map service layer.
             * @param {string[]} values - Values to be added to the datalist.
             */
            function addToDataList(fieldName, values) {
                var datalist, docFrag;
                datalist = document.querySelector("datalist[data-field-name='" + fieldName + "']");
                if (datalist) {
                    docFrag = document.createDocumentFragment();
                    values.forEach(function (value) {
                        var option = document.createElement("option");
                        option.value = value;
                        docFrag.appendChild(option);
                    });
                    datalist.appendChild(docFrag);
                }
            }

            /**
             * Adds attributes to input elements.
             * @param {Object.<string, Object.<string, string>>} values - Object containing objects containing date representation strings.
             */
            function addAttributes(values) {
                var fieldName, value, input, selector;
                for (fieldName in values) {
                    if (values.hasOwnProperty(fieldName)) {
                        value = values[fieldName];
                        selector = "input[type=date][name=" + fieldName + "]";
                        input = document.querySelector(selector);
                        if (input) {
                            for (var attrName in value) {
                                if (value.hasOwnProperty(attrName)) {
                                    input.setAttribute(attrName, value[attrName]);
                                }
                            }
                        } else {
                            console.error("Expected input element not found.", selector);
                        }
                    }
                }
            }

            // Get the data from the worker message.
            var data = e.data;
            // If the data contains a "fieldName" property, it is the result of
            // a query for unique values for a single field.
            //
            // If the data has a "ranges" property, it is the result of a query
            // for the min and max values of the date fields.
            if (data.fieldName) {
                addToDataList(data.fieldName, data.values);
            } else if (data.ranges) {
                addAttributes(data.ranges);
            }
        });

        // Set up worker event handler for error messages.
        worker.addEventListener("error", function (e) {
            console.error(e.data);
        });

        // Send the map service layer URL to the web worker, which will start it processing.
        worker.postMessage({ url: url });
    }(getOperationalLayer(webmapItemData, "PlannedProjects").url + "/0"));
});<commit_msg>Fixed layer list sorting to accommodate title change.<commit_after>/**
 * FeatureLayer.selection-complete
 * @external FeatureLayer#event:selection-complete
 * @see {link:https://developers.arcgis.com/javascript/jsapi/featurelayer-amd.html#event-selection-complete}
 * @member {Graphic[]} features - The features that were selected by a query.
 * @member {Number} method - The selection method.
 * @member {FeatureLayer} target - The feature layer that performed the selection.
 */

/**
 * Create map response
 * @external createMapResponse
 * @see {@link https://developers.arcgis.com/javascript/jsapi/esri.arcgis.utils-amd.html#createmap esri/arcgis/utils.createMap()
 * @member {external:esri/Map} map
 * @member {(EventHandler|undefined)} clickEventHandle
 * @member {(Function|undefined)} clickEventListener
 * @member {Object} itemInfo
 * @member {Object} itemInfo.item
 * @member {Object} itemInfo.itemData
 * @member {Object.<string, Error>} itemInfo.errors
 */

/**
 * dojo/Deferred
 * @description Deferred response from an asynchronous operation.
 * @external dojo/Deferred
 * @see {@link http://dojotoolkit.org/reference-guide/1.10/dojo/Deferred.html dojo/Deferred}
 */

require([
  "esri/config",
  "esri/map",
  "esri/geometry/geometryEngineAsync",
  "esri/tasks/query",
  "esri/layers/FeatureLayer",
  "esri/layers/ArcGISDynamicMapServiceLayer",
  "esri/dijit/FeatureTable",
  "esri/dijit/LayerList",
  "esri/dijit/HomeButton",
  "dijit/registry",
  "witpa/ProjectFilter",
  "dojo/parser",
  "dojo/dnd/Moveable",
  "esri/arcgis/utils",
  "esri/dijit/Search",
  "esri/dijit/BasemapGallery",
  "esri/dijit/Legend",
  "esri/tasks/QueryTask",
  "esri/tasks/StatisticDefinition",
  "esri/symbols/SimpleLineSymbol",
  "esri/Color",
  "witpa/infoWindowUtils",
  "witpa/wsdotMapUtils",
  "dojo/text!./webmap/item.json",
  "dojo/text!./webmap/itemdata.json",

  "dijit/layout/BorderContainer",
  "dijit/layout/ContentPane",
  "dijit/layout/AccordionContainer",
  "dijit/layout/AccordionPane"
], function (
  esriConfig,
  Map,
  geometryEngineAsync,
  Query,
  FeatureLayer,
  ArcGISDynamicMapServiceLayer,
  FeatureTable,
  LayerList,
  HomeButton,
  registry,
  ProjectFilter,
  parser,
  Moveable,
  arcgisUtils,
  Search,
  BasemapGallery,
  Legend,
  QueryTask,
  StatisticDefinition,
  SimpleLineSymbol,
  Color,
  infoWindowUtils,
  wsdotMapUtils,
  webmapItem,
  webmapItemData
) {
    "use strict";
    var projectFilter = new ProjectFilter(document.forms.filterForm);
    var filterPane = document.getElementById("filterPane");

    filterPane.appendChild(projectFilter.form);

    ["hqolymgis98d"].forEach(function (server) {
        esriConfig.defaults.io.corsEnabledServers.push(server);
    });

    // Parse the Dojo layout widgets defined in HTML markup.
    parser.parse();

    webmapItem = JSON.parse(webmapItem);
    webmapItemData = JSON.parse(webmapItemData);

    // Create the map using JSON webmap definition.
    arcgisUtils.createMap({
        item: webmapItem,
        itemData: webmapItemData
    }, "map", {
        mapOptions: wsdotMapUtils.defaultMapOptions
    }
    /**
     * Post map creation tasks.
     * @param {external:createMapResponse} response
     */
    ).then(function (response) {
        var map = response.map;

        infoWindowUtils.makeInfoWindowDraggable(response.map.infoWindow);

        var dynamicLayer = map.getLayer("PlannedProjects");

        var search = new Search({
            map: response.map
        }, "search");

        search.on("load", function () {
            var sources, source;
            sources = search.get("sources");
            source = search.defaultSource; //or sources[0];
            source.countryCode = "US";
            source.searchExtent = response.map.extent;
            search.set("sources", sources);
        });

        search.startup();

        var outFields = [
            "OBJECTID",
            "StateRouteNumber",
            "Project_Title",
            "County",
            "Legislative_District",
            "Revenue_Package",
            "Sub_Category",
            "PIN",
            "Improvement_Type",
            "Work_Description",
            "Sub_Program",
            "Region",
            "Program",
            "Begin_Preliminary_Engineering",
            "Advertisement_Date",
            "Operationally_Complete",
            "Congressional_District",
            "Begin_Mile_Post",
            "End_Mile_Post",
            "Total_Dollars",
            "Direction_Ind",
            "RouteID",
            "Begin_ARM",
            "End_ARM",
            "SRMP_Begin_AB_Ind",
            "SRMP_End_AB_Ind",
            "SRMP_Date",
            "LRSDATE",
            "RelRouteType",
            "RelRouteQual",
            "Mid_Arm",
            "Mid_Mile_Post",
            "Project_List",
            "LOC_ERROR"
        ];

        var table;

        // Create the feature layer that will be used by the FeatureTable and to highlight selected table rows on the map.
        var featureLayerUrl = [dynamicLayer.url, "0"].join("/");
        var layer = new FeatureLayer(featureLayerUrl, {
            id: "wsdotprojects",
            mode: FeatureLayer.MODE_SELECTION,
            outFields: outFields
        });

        map.addLayer(layer);

        var selectionSymbol = new SimpleLineSymbol().setColor(new Color([0, 255, 255, 1])).setWidth(2);
        layer.setSelectionSymbol(selectionSymbol);

        // When the user submits a query, set the feature layer's definition expression
        // so that only those rows are shown in the table.
        projectFilter.form.addEventListener("submit-query", function (e) {
            layer.clearSelection();
            layer.setDefinitionExpression(e.detail.where);
            dynamicLayer.setLayerDefinitions([
                e.detail.where
            ]);
            var query = new Query();
            query.where = e.detail.where;
            layer.queryExtent(query).then(function (queryExtentResponse) {
                var extent = queryExtentResponse.extent;
                map.setExtent(extent);
            });
            table.grid.refresh();

        });

        // Reset the definition expression to show all rows.
        projectFilter.form.addEventListener("reset", function (e) {
            layer.clearSelection();
            dynamicLayer.setDefaultLayerDefinitions();
            layer.setDefinitionExpression(layer.defaultDefinitionExpression);
            table.grid.refresh();
        });

        // Add the home button that allows the user to zoom to full extent.
        var homeButton = new HomeButton({
            map: map
        }, "homeButton");
        homeButton.startup();

        // Create the feature table
        table = new FeatureTable({
            featureLayer: layer,
            outFields: outFields,
            syncSelection: false,
            // The dateOptions are not actually honored: https://geonet.esri.com/message/520158
            /*
            dateOptions: {
              datePattern: "yyyyMMdd",
              timeEnabled: false,
              timePattern: null
            },
            */
            // These fields are hidden by default, but user can turn them back on.
            hiddenFields: [
              "LRSDate"
            ],
            showGridHeader: true,
            map: map
        }, "table");
        table.startup();

        function zoomToFeatures(features) {
            var geometries;
            if (features && features.length > 0) {
                if (features.length === 1) {
                    map.setExtent(features[0].geometry.getExtent(), true);
                } else {
                    geometries = features.map(function (graphic) {
                        return graphic.geometry;
                    });
                    geometryEngineAsync.union(geometries).then(function (unionedGeometry) {
                        map.setExtent(unionedGeometry.getExtent(), true);
                    });
                }
            }
        }

        /**
         * @typedef {Object} DGridRow
         * @property {Object} data
         * @property {number} data.OBJECTID
         * @property {HTMLElement} element
         * @property {string} id - A string containing the corresponding feature's Object ID.
         */

        /**
         * Selects or deselects features corresponding to row selected in the feature table.
         * @param {DGridRow[]} rows - An array of rows either selected or deselected from the feature table dGrid.
         * @param {Boolean} [deselect=false] - True to subtract the features associated with the rows to the feature layer selection, false to add them.
         * @returns {external:dojo/Deferred} Returns the promise from the selectFeatures function.
         */
        function selectOrDeselectFeatures(rows, deselect) {
            var selectionMethod = deselect ? FeatureLayer.SELECTION_SUBTRACT : FeatureLayer.SELECTION_ADD;
            var query = new Query();
            // Convert the array of rows into an array of corresponding object IDs.
            var objectIds = rows.map(function (row) {
                return parseInt(row.id, 10);
            });
            query.objectIds = objectIds;
            return layer.selectFeatures(query, selectionMethod);
        }

        layer.on("selection-complete", function (features, selectionMethod) {
            features = layer.getSelectedFeatures();
            zoomToFeatures(features);
        });

        /**
         *
         * @param {DGridRow[]} rows - The rows that were selected
         */
        table.on("row-select", function (rows) {
            selectOrDeselectFeatures(rows);
        });

        /**
         *
         * @param {DGridRow[]} rows - The rows that were unselected
         */
        table.on("row-deselect", function (rows) {
            selectOrDeselectFeatures(rows, true);
        });

        // resize panel when table close is toggled.
        table.tableCloseButton.addEventListener("click", function (e) {
            var gridMenuNode = registry.byId(table._gridMenu).domNode;
            var tableNode = registry.byId("tablePane").domNode;
            var borderContainer = registry.byId("borderContainer");
            var isOpening = e.target.classList.contains("toggleClosed");
            if (isOpening) {
                tableNode.style.height = tableNode.dataset.openHeight || "50%";
            } else {
                // Store the old height.
                tableNode.dataset.openHeight = tableNode.style.height || [tableNode.clientHeight, "px"].join("");
                // Set to "closed" height.
                tableNode.style.height = [gridMenuNode.clientHeight, "px"].join("");
            }
            borderContainer.resize();
        });

        var layerListItems = arcgisUtils.getLayerList(response);

        // Custom sort the layer list items array so that the item with the
        // title containing "Planned Projects" is last in the array. Other
        // items will remain in their original order.
        layerListItems.sort(function (a, b) {
            var re = /Planned\s?Projects/i;
            var output;
            if (re.test(a.title)) {
                output = 1;
            } else if (re.test(b.title)) {
                output = -1;
            } else {
                output = 0;
            }
            return output;
        });

        // Create the layer list.
        var layerList = new LayerList({
            map: response.map,
            layers: layerListItems,
            showLegend: true,
            showOpacitySlider: true,
            showSublayers: true
        }, "layerList");
        layerList.startup();

        var basemapGallery = new BasemapGallery({
            map: response.map,
            basemapsGroup: {
                id: "085a9cb0bb664d29bf62b731ccc4aa64"
            },
            basemaps: [
                wsdotMapUtils.esriBasemaps["wsdot-multilevel"]
            ],
            basemapIds: wsdotMapUtils.esriBasemaps["wsdot-multilevel"].layers.map(function (layer) {
                return layer.id;
            })
        }, "basemapGallery");
        basemapGallery.startup();

        // Select the default basemap in the gallery.
        basemapGallery.on("load", function () {
            var basemap, basemaps = basemapGallery.basemaps, i;
            if (basemaps && basemaps.length > 0) {
                for (i = 0; i < basemaps.length; i++) {
                    basemap = basemaps[i];
                    if (/wsdot[\-\s]?multilevel/i.test(basemap.id)) {
                        basemapGallery.select(basemap.id);
                        break;
                    }
                }
            }
        });

        var legend = new Legend({
            map: response.map,
            layerInfos: arcgisUtils.getLegendLayers(response)
        }, "legend");
        legend.startup();

    });

    function getOperationalLayer(webMapData, opLayerId) {
        var opLayers = webMapData.operationalLayers;
        var opLayer;
        for (var i = 0; i < opLayers.length; i++) {
            if (opLayers[i].id === opLayerId) {
                opLayer = opLayers[i];
                break;
            }
        }
        return opLayer;
    }

    /**
     * Setup the background worker process for querying the 6-year project map service
     * for input suggestions.
     * @param {string} url - The URL for the map service layer to be queried.
     */
    (function (url) {

        if (!window.Worker) {
            console.log("This browser doesn't support web workers. Some features are not available.");
            return;
        }

        // Create the worker.
        var worker = new Worker("QueryWorker.js");

        /**
         * Handles messages from web worker.
         * @param {Event} e - worker message event
         * @param {Object} e.data - Data passed from worker.
         */
        worker.addEventListener("message", function (e) {

            /**
             * Adds values to the datalist corresponding to the given field name.
             * @param {string} fieldName - The name of a field in a map service layer.
             * @param {string[]} values - Values to be added to the datalist.
             */
            function addToDataList(fieldName, values) {
                var datalist, docFrag;
                datalist = document.querySelector("datalist[data-field-name='" + fieldName + "']");
                if (datalist) {
                    docFrag = document.createDocumentFragment();
                    values.forEach(function (value) {
                        var option = document.createElement("option");
                        option.value = value;
                        docFrag.appendChild(option);
                    });
                    datalist.appendChild(docFrag);
                }
            }

            /**
             * Adds attributes to input elements.
             * @param {Object.<string, Object.<string, string>>} values - Object containing objects containing date representation strings.
             */
            function addAttributes(values) {
                var fieldName, value, input, selector;
                for (fieldName in values) {
                    if (values.hasOwnProperty(fieldName)) {
                        value = values[fieldName];
                        selector = "input[type=date][name=" + fieldName + "]";
                        input = document.querySelector(selector);
                        if (input) {
                            for (var attrName in value) {
                                if (value.hasOwnProperty(attrName)) {
                                    input.setAttribute(attrName, value[attrName]);
                                }
                            }
                        } else {
                            console.error("Expected input element not found.", selector);
                        }
                    }
                }
            }

            // Get the data from the worker message.
            var data = e.data;
            // If the data contains a "fieldName" property, it is the result of
            // a query for unique values for a single field.
            //
            // If the data has a "ranges" property, it is the result of a query
            // for the min and max values of the date fields.
            if (data.fieldName) {
                addToDataList(data.fieldName, data.values);
            } else if (data.ranges) {
                addAttributes(data.ranges);
            }
        });

        // Set up worker event handler for error messages.
        worker.addEventListener("error", function (e) {
            console.error(e.data);
        });

        // Send the map service layer URL to the web worker, which will start it processing.
        worker.postMessage({ url: url });
    }(getOperationalLayer(webmapItemData, "PlannedProjects").url + "/0"));
});<|endoftext|>


<commit_before>window.onload = function(){
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');

    /* Dynamic variables */
    var widthd = 16;
    var heightd = 27;
    var spriteXd = 385;
    var spriteYd = 149;
    var positionOnMapX = 100;
    var positionOnMapY = 140;
    /* Dynamic variables END*/

    /* move Mario data */
    var moveMan = false;
    var moveDirection;
    var spriteCount = 3;
    function marioMoveData(moveManData, moveDirectionData, spriteCountData){
        moveMan = moveManData;
        moveDirection = moveDirectionData;
        spriteCount = spriteCountData;
    }
    /* move Mario data END*/

    var treesItems = []; // Масив с данными деревьев
    var beforeTrees = false;

    window.requestAnimFrame = (function(){
        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            function( callback ){
                window.setTimeout(callback, 1000 / 60);
            };
    })();

    // Конструктор для создания сущностей
    function ItemData(width, height, spriteX, spriteY, positionOnCanvas_X, positionOnCanvas_Y){
        this.width = width;
        this.height = height;
        this.spriteX = spriteX;
        this.spriteY = spriteY;
        this.positionOnCanvas_X = positionOnCanvas_X;
        this.positionOnCanvas_Y = positionOnCanvas_Y;
    }

    function moveItem(direction, count, spriteCount){
        // Очистка координат Марио
        ctx.clearRect(positionOnMapX,positionOnMapY,widthd,heightd);

        var i=count % spriteCount;
        switch(direction){
            case 'right':
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapX++
                })(spriteCount,[
                        [311,122],
                        [328,122],
                        [345,122]
                    ]);
                break;
            case 'left' :
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapX--
                })(spriteCount,[
                        [296,122],
                        [279,122],
                        [262,122]
                    ]);
                break;
            case 'up' :
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapY--
                })(spriteCount,[
                        [410,122],
                        [427,122]
                    ]);
                break;
            case 'down' :
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapY++
                })(spriteCount,[
                        [385,178],
                        [402,178]
                    ]);
                break;
        }

        // Проверка на то, что Марио находится на координатах дерева
        for(var k=0; k<treesItems.length; k++){
            // Если Марио за деревом, то отрисовываем его первого
            if( treesItems[k].positionOnCanvas_Y <= manData.positionOnCanvas_Y+manData.height &&
                treesItems[k].positionOnCanvas_Y+treesItems[k].height >= manData.positionOnCanvas_Y &&
                treesItems[k].positionOnCanvas_X <= manData.positionOnCanvas_X+manData.width &&
                treesItems[k].positionOnCanvas_X+treesItems[k].width >= manData.positionOnCanvas_X
                ){
                // Если Марио находится перед деревом
                if( manData.positionOnCanvas_Y+manData.height >= treesItems[k].positionOnCanvas_Y+treesItems[k].height ){
                    createTrees(6,5, 160,140);
                    CreateMan(manData);
                } else {
                    CreateMan(manData);
                    createTrees(6,5, 160,140);
                }
                break;
            } else {
                CreateMan(manData);
            }
        }

    }

    // Отрисовка главного персонажа
    var sprite = new Image();
    sprite.src = 'images/sprite.png';
    var manData = new ItemData(widthd, heightd, spriteXd, spriteYd, positionOnMapX, positionOnMapY);
    function CreateMan(Data){
        Data.spriteX = spriteXd;
        Data.spriteY = spriteYd;
        Data.positionOnCanvas_X = positionOnMapX;
        Data.positionOnCanvas_Y = positionOnMapY;
        ctx.drawImage(sprite, spriteXd, spriteYd, widthd, heightd, positionOnMapX, positionOnMapY, widthd, heightd);
    }

    // Отрисовка деревьев
    function createTrees(countX,countY, distanceBtwTreesX,distanceBtwTreesY){
        treesItems = [];
        for(var i=0; i<countX; i++){
            for(var k=0; k<countY; k++){
                ctx.drawImage(sprite, 440, 299, 66, 100, i*distanceBtwTreesX-k*20, k*distanceBtwTreesY-i*30, 66, 100);
                treesItems.push( new ItemData(66,100, 440,299, i*distanceBtwTreesX-k*20,k*distanceBtwTreesY-i*30) );
            }
        }
    }

    // LOAD
    createTrees(6,5, 160,140);
    CreateMan(manData);

    // Главный цикл игры
    function loop(e){
        var loopCount = parseInt(e/150);

        // Движение и данные главного персонажа
        if(moveMan) moveItem(moveDirection, loopCount, spriteCount);
    }
    (function animationLoop(e){
        loop(e);
        requestAnimationFrame(animationLoop, canvas);
    })();

    // События
    document.onkeydown = checkKeycode;
    document.onkeyup = upKeycode;
    function checkKeycode(e) {
        var keycode;
        if (window.event) keycode = window.event.keyCode;
        else if (e) keycode = e.which;

        switch(keycode){
            case 38 :
                marioMoveData(true, 'up', 2);
                break;
            case 40 :
                marioMoveData(true, 'down', 2);
                break;
            case 37 :
                marioMoveData(true, 'left', 3);
                break;
            case 39 :
                marioMoveData(true, 'right', 3);
                break;
        }
    }
    function upKeycode(e) {
        var keycode;
        if (window.event) keycode = window.event.keyCode;
        else if (e) keycode = e.which;
        switch(keycode){
            case 38 :
                moveMan = false;
                spriteXd = 385;
                spriteYd = 149;
                break;
            case 40 :
                moveMan = false;
                spriteXd = 385;
                spriteYd = 149;
                break;
            case 37 :
                moveMan = false;
                spriteXd = 385;
                spriteYd = 149;
                break;
            case 39 :
                moveMan = false;
                spriteXd = 385;
                spriteYd = 149;
                break;
        }
    }

};
<commit_msg>fix mario animate on keyup<commit_after>window.onload = function(){
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');

    /* Dynamic variables */
    var widthd = 16;
    var heightd = 27;
    var spriteXd = 385;
    var spriteYd = 149;
    var positionOnMapX = 100;
    var positionOnMapY = 140;
    /* Dynamic variables END*/

    /* move Mario data */
    var moveMan = false;
    var moveDirection;
    var spriteCount = 3;
    function marioMoveData(moveManData, moveDirectionData, spriteCountData){
        moveMan = moveManData;
        moveDirection = moveDirectionData;
        spriteCount = spriteCountData;
    }
    /* move Mario data END*/

    var treesItems = []; // Масив с данными деревьев
    var beforeTrees = false;

    window.requestAnimFrame = (function(){
        return window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            function( callback ){
                window.setTimeout(callback, 1000 / 60);
            };
    })();

    // Конструктор для создания сущностей
    function ItemData(width, height, spriteX, spriteY, positionOnCanvas_X, positionOnCanvas_Y){
        this.width = width;
        this.height = height;
        this.spriteX = spriteX;
        this.spriteY = spriteY;
        this.positionOnCanvas_X = positionOnCanvas_X;
        this.positionOnCanvas_Y = positionOnCanvas_Y;
    }

    function moveItem(direction, count, spriteCount){
        // Очистка координат Марио
        ctx.clearRect(positionOnMapX,positionOnMapY,widthd,heightd);

        var i=count % spriteCount;
        switch(direction){
            case 'right':
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapX++
                })(spriteCount,[
                        [311,122],
                        [328,122],
                        [345,122]
                    ]);
                break;
            case 'left' :
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapX--
                })(spriteCount,[
                        [296,122],
                        [279,122],
                        [262,122]
                    ]);
                break;
            case 'up' :
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapY--
                })(spriteCount,[
                        [410,122],
                        [427,122]
                    ]);
                break;
            case 'down' :
                (function move(SpritesCount, positions){
                    spriteXd = positions[i][0];
                    spriteYd = positions[i][1];
                    positionOnMapY++
                })(spriteCount,[
                        [385,178],
                        [402,178]
                    ]);
                break;
            default :
                spriteXd = 385;
                spriteYd = 149;

        }

        // Проверка на то, что Марио находится на координатах дерева
        for(var k=0; k<treesItems.length; k++){
            // Если Марио за деревом, то отрисовываем его первого
            if( treesItems[k].positionOnCanvas_Y <= manData.positionOnCanvas_Y+manData.height &&
                treesItems[k].positionOnCanvas_Y+treesItems[k].height >= manData.positionOnCanvas_Y &&
                treesItems[k].positionOnCanvas_X <= manData.positionOnCanvas_X+manData.width &&
                treesItems[k].positionOnCanvas_X+treesItems[k].width >= manData.positionOnCanvas_X
                ){
                // Если Марио находится перед деревом
                if( manData.positionOnCanvas_Y+manData.height >= treesItems[k].positionOnCanvas_Y+treesItems[k].height ){
                    createTrees(6,5, 160,140);
                    CreateMan(manData);
                } else {
                    CreateMan(manData);
                    createTrees(6,5, 160,140);
                }
                break;
            } else {
                CreateMan(manData);
            }
        }

    }

    // Отрисовка главного персонажа
    var sprite = new Image();
    sprite.src = 'images/sprite.png';
    var manData = new ItemData(widthd, heightd, spriteXd, spriteYd, positionOnMapX, positionOnMapY);
    function CreateMan(Data){
        Data.spriteX = spriteXd;
        Data.spriteY = spriteYd;
        Data.positionOnCanvas_X = positionOnMapX;
        Data.positionOnCanvas_Y = positionOnMapY;
        ctx.drawImage(sprite, spriteXd, spriteYd, widthd, heightd, positionOnMapX, positionOnMapY, widthd, heightd);
    }

    // Отрисовка деревьев
    function createTrees(countX,countY, distanceBtwTreesX,distanceBtwTreesY){
        treesItems = [];
        for(var i=0; i<countX; i++){
            for(var k=0; k<countY; k++){
                ctx.drawImage(sprite, 440, 299, 66, 100, i*distanceBtwTreesX-k*20, k*distanceBtwTreesY-i*30, 66, 100);
                treesItems.push( new ItemData(66,100, 440,299, i*distanceBtwTreesX-k*20,k*distanceBtwTreesY-i*30) );
            }
        }
    }

    // LOAD
    createTrees(6,5, 160,140);
    CreateMan(manData);

    // Главный цикл игры
    function loop(e){
        var loopCount = parseInt(e/150);

        // Движение и данные главного персонажа
        if(moveMan) moveItem(moveDirection, loopCount, spriteCount);
    }
    (function animationLoop(e){
        loop(e);
        requestAnimationFrame(animationLoop, canvas);
    })();

    // События
    document.onkeydown = checkKeycode;
    document.onkeyup = upKeycode;
    function checkKeycode(e) {
        var keycode;
        if (window.event) keycode = window.event.keyCode;
        else if (e) keycode = e.which;

        switch(keycode){
            case 38 :
                marioMoveData(true, 'up', 2);
                break;
            case 40 :
                marioMoveData(true, 'down', 2);
                break;
            case 37 :
                marioMoveData(true, 'left', 3);
                break;
            case 39 :
                marioMoveData(true, 'right', 3);
                break;
        }
    }
    function upKeycode(e) {
        var keycode;
        if (window.event) keycode = window.event.keyCode;
        else if (e) keycode = e.which;
        switch(keycode){
            case 38 :
                moveMan = false;
                moveItem('default', 1, 1);
                break;
            case 40 :
                moveMan = false;
                moveItem('default', 1, 1);
                break;
            case 37 :
                moveMan = false;
                moveItem('default', 1, 1);
                break;
            case 39 :
                moveMan = false;
                moveItem('default', 1, 1);
                break;
        }
    }

};
<|endoftext|>


<commit_before>// ==UserScript==
// @name         UTS Timetable Generator
// @author       szdc
// @namespace    http://github.com/szdc
// @version      0.1
// @description  Timetable generator for UTS students
// @match        https://mysubjects.uts.edu.au/aplus2015/aptimetable*
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @copyright    2015+, szdc
// ==/UserScript==

$(document).ready(function () {
  'use strict';

  var subjects   = [],
      activities = [];

  init();

  function init() {
    // Find the table rows that hold the timetable data
    var table = $('table[cellspacing="1"] tr');

    // Process each row
    table.each(processRow);
    console.log('Subjects found: ' + subjects.length);

    // Get all activity groups.
    var activityGroups = getAllActivityGroups();
    console.log('Total activity groups: ' + activityGroups.length);

    // Get all timetable combinations
    var timetableCombinations = cartesianProductOf(activityGroups);
    timetableCombinations = timetableCombinations.map(function (timetable) {
      return new Timetable(timetable);
    });
    console.log('Timetable combinations: ' + timetableCombinations.length);

    var timetableList = new TimetableList(timetableCombinations);
  }

  /**
   * Processes a timetable row.
   */
  function processRow() {
    var isSubjectHeader = $(this).find('td > a').length > 0,
        isActivityRow   = $(this).attr('bgcolor') === '#eeeeee';

    if (isSubjectHeader) {
      // New subject
      subjects.push(Subject.fromTableRow($(this)));
    } else if (isActivityRow) {
      // New activity under the latest subject
      var subject = subjects[subjects.length - 1];
      subject.addActivity(Activity.fromTableRow($(this), subject));
    }
  }

  /**
   * Gets an array of all activity groups.
   */
  function getAllActivityGroups() {
    return subjects.reduce(function (activityGroups, subject) {
      var groups = subject.getActivityGroups(),
          keys = Object.keys(groups);

      keys.forEach(function (key) {
        activityGroups.push(groups[key]);
      });

      return activityGroups;
    }, []);
  }

  /**
   * Returns the cartesian product of N arrays.
   */
  function cartesianProductOf(arr) {
    return arr.reduce(function(a, b) {
      var ret = [];
      a.forEach(function(a) {
        b.forEach(function(b) {
          ret.push(a.concat([b]));
        });
      });
      return ret;
    }, [[]]);
  }
});

/**
 * Represents a UTS subject.
 */
function Subject(name, code, semester) {
  if (arguments.length < 3) {
    throw new Error('Too few arguments supplied to create the Subject object.');
  }

  var activityGroups = {};

  /**
   * Adds an activity.
   */
  function addActivity(activity) {
    var type = activity.getType(),
        activities = activityGroups[type];
    if (typeof activityGroups[type] === 'undefined') {
      activityGroups[type] = [];
    }

    var existingActivity = getExistingActivity(activityGroups[type], activity);
    if (existingActivity) {
      existingActivity.addNumbers(activity.getNumbers());
    } else {
      activityGroups[type].push(activity);
    }
  }

  /**
   * Retrieves an activity from the array if it matches the
   * activity given.
   */
  function getExistingActivity(existingActivities, activity) {
    for (var i = 0; i < existingActivities.length; i++) {
      var existingActivity = existingActivities[i];
      if (existingActivity.matches(activity)) {
        return existingActivity;
      }
    }
    return null;
  }

  return {
    addActivity: addActivity,
    getActivityGroups: function () { return activityGroups; },
    getCode: function () { return code; }
  };
}

/**
 * Creates a new Subject object from a table row.
 */
Subject.fromTableRow = function (row) {
  var content = row.find('b:first');

  var name     = content.text().substr(content.text().indexOf(':') + 1).trim(),
      code     = content.children('a').attr('href').match(/\d+/)[0],
      semester = /AUT/.test(content.text()) ? 'autumn' : 'spring';

  return new Subject(name, code, semester);
};

/**
 * Represents a UTS subject activity.
 */
function Activity(type, numbers, day, startTime, duration, finishTime, subject) {
  if (arguments.length < 5) {
    throw new Error('Too few arguments supplied to create the Activity object.');
  }

  /**
   * Determines if two activities clash.
   */
  function hasTimeClashWith(activity) {
    var timeClashExists = startTime < activity.getFinishTime() && finishTime > activity.getStartTime();
    return timeClashExists;
  }

  /**
   * Determines if two activities are essentially identical.
   */
  function matches(activity) {
    return type === activity.getType() && day === activity.getDay() &&
      startTime === activity.getStartTime() && finishTime === activity.getFinishTime() &&
      subject === activity.getSubject();
  }

  /**
   * Appends activity numbers to the numbers array.
   */
  function addNumbers(numbersArray) {
    numbers = numbers.concat(numbersArray);
  }

  function toString() {
    return day + ' ' + startTime + '-' + finishTime + ': ' + subject.getCode() + ' ' + type + ' ' + numbers.join(',') + ' (' + duration + ')';
  }

  return {
    hasTimeClashWith: hasTimeClashWith,
    getStartTime: function () { return startTime; },
    getFinishTime: function () { return finishTime; },
    getType: function () { return type; },
    getNumbers: function () { return numbers; },
    getDay: function () { return day; },
    getSubject: function () { return subject; },
    matches: matches,
    addNumbers: addNumbers,
    toString: toString
  };
}

/**
 * Creates a new Activity object from a table row.
 */
Activity.fromTableRow = function (row, subject) {
  var cells = row.children().map(function() {return this.innerHTML;});

  var type       = cells[0],
      numbers    = [cells[1]],
      day        = cells[2],
      startTime  = cells[3],
      duration   = cells[4],
      finishTime = new Date('1/1/2015 ' + startTime).addMinutes(duration).get24hrTime(),
      startTime = parseInt(startTime.replace(':', ''));

  return new Activity(type, numbers, day, startTime, duration, finishTime, subject);
};

/**
 * Compares two activities.
 */
Activity.compare = function (a, b) {
  var days = { "Mon": 0, "Tue": 1, "Wed": 2, "Thu": 3, "Fri": 4, "Sat": 5, "Sun": 6 };

  if (a.getDay() === b.getDay()) {
    return a.getStartTime() - b.getStartTime();
  } else {
    return days[a.getDay()] - days[b.getDay()];
  }
};

/**
 * Represents a list of Timetable objects.
 */
function TimetableList(timetables) {
  if (arguments.length < 1) {
    throw new Error('Too few arguments supplied to create the TimetableList object.');
  }

  // Filter the list to only valid timetable combinations
  timetables = timetables.filter(function (timetable) {
    return timetable.isValid();
  });
  console.log('Valid timetables: ' + timetables.length);

  /**
   * Returns a filtered array of timetables.
   */
  function filter(filterMethod, args) {
    return timetables.filter(filterMethod, args);
  }

  /**
   * Sorts the timetables.
   */
  function sort(compareMethod) {
    timetables.sort(compareMethod);
  }

  return {
    getTimetables: function () { return timetables; },
    filter: filter,
    sort: sort
  };
}

/**
 * A static object of common filtering methods.
 */
TimetableList.FilterBy = {
  /**
   * Filters by the number of days the timetable spans.
   *
   * Required: The 2nd parameter of the filter method must
   * contain an object with the following properties:
   *  days  {Number}  The maximum allowable number of days
   *  exact {Boolean} Whether or not to also include timetables
   *                  with less days in the results.
   */
  DaysAtUni: function (timetable) {
    if (typeof this.days === 'undefined') {
      throw new Error('Days property missing for filter.');
    }

    var daysAtUni = Object.keys(timetable.getDays()).length;
    return this.exact ? daysAtUni === this.days : daysAtUni <= this.days;
  },

  /**
   * Filters to only timetables that start later than the
   * specified time.
   *
   * Required: The 2nd parameter of the filter method must
   * contain an object with the following properties:
   *  time  {Number}  The earliest time an activity can start
   */
  LateStarts: function (timetable) {
    if (typeof this.time === 'undefined') {
      throw new Error('Time property missing for filter.');
    }

    return timetable.getActivities().every(function (activity) {
      return activity.getStartTime() >= this.time;
    }, this);
  }
};

/**
 * A static object of common sorting methods.
 */
TimetableList.SortBy = {
  /**
   * Sorts by the total number of hours spent on campus.
   * Hours spent each day = end of last class - start of first class
   */
  HoursOnCampus: function (a, b) {
    return a.getHours() - b.getHours();
  }
};

function Timetable(activities) {
  /**
   * Returns an object of days and times that the timetable spans.
   */
  function getDays() {
    var dayInfo = activities.reduce(function (days, activity) {
      var day = activity.getDay(),
          start  = activity.getStartTime(),
          finish = activity.getFinishTime();

      if (typeof days[day] === 'undefined') {
        days[day] = { start: start, finish: finish };
      } else {
        if (start < days[day].start) days[day].start = start;
        if (finish > days[day].finish) days[day].finish = finish;
      }

      return days;
    }, {});

    return dayInfo;
  }

  /**
   * Determines if a timetable is valid.
   * There must be no activity clashes to return true.
   */
  function isValid() {
    var invalidTimes = {
      "Mon": [], "Tue": [], "Wed": [], "Thu": [], "Fri": [], "Sat": [], "Sun": []
    };

    var valid = activities.every(function (activity) {
      var conflicts = invalidTimes[activity.getDay()];

      if (conflicts.length === 0) {
        conflicts.push(activity);
        return true;
      }

      for (var i = 0; i < conflicts.length; i++) {
        var existingActivity = conflicts[i];
        if (activity.hasTimeClashWith(existingActivity)) {
          return false;
        }
      }
      conflicts.push(activity);
      return true;
    });

    return valid;
  }

  /**
   * Calculates the total number of hours spent at uni.
   */
  function getHours() {
    var dayInfo = getDays();

    var hours = Object.keys(dayInfo).reduce(function (totalHours, day) {
      totalHours += getTimeDiffInHours(dayInfo[day].finish, dayInfo[day].start);
      return totalHours;
    }, 0);

    return hours;
  }

  /**
   * Gets the difference between two times in hours.
   */
  function getTimeDiffInHours(startTime, finishTime) {
    startTime = getHoursSinceMidnight(startTime);
    finishTime = getHoursSinceMidnight(finishTime);
    return startTime - finishTime;
  }

  /**
   * Gets the number of hours passed since midnight.
   */
  function getHoursSinceMidnight(time) {
    var time    = time / 100,
        hours   = Math.floor(time),
        minutes = (time - hours) / 0.6;

    return (hours + minutes).toFixed(1);
  }

  /**
   * Sorts the timetable.
   */
  function sort(compareFn) {
    activities.sort(compareFn);
  }

  return {
    getActivities: function () { return activities; },
    getDays: getDays,
    getHours: getHours,
    isValid: isValid,
    sort: sort
  };
}

/**
 * Adds minutes to the date object.
 */
Date.prototype.addMinutes = function (minutes) {
  return new Date(this.getTime() + parseInt(minutes) * 60000);
};

/**
 * Returns the 24hr-formatted time.
 */
Date.prototype.get24hrTime = function () {
  return this.getHours() * 100 + this.getMinutes();
};

<commit_msg>Improved on the LateStarts method to also support early finishes - renamed the method to TimeConstraint.<commit_after>// ==UserScript==
// @name         UTS Timetable Generator
// @author       szdc
// @namespace    http://github.com/szdc
// @version      0.1
// @description  Timetable generator for UTS students
// @match        https://mysubjects.uts.edu.au/aplus2015/aptimetable*
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @copyright    2015+, szdc
// ==/UserScript==

$(document).ready(function () {
  'use strict';

  var subjects   = [],
      activities = [];

  init();

  function init() {
    // Find the table rows that hold the timetable data
    var table = $('table[cellspacing="1"] tr');

    // Process each row
    table.each(processRow);
    console.log('Subjects found: ' + subjects.length);

    // Get all activity groups.
    var activityGroups = getAllActivityGroups();
    console.log('Total activity groups: ' + activityGroups.length);

    // Get all timetable combinations
    var timetableCombinations = cartesianProductOf(activityGroups);
    timetableCombinations = timetableCombinations.map(function (timetable) {
      return new Timetable(timetable);
    });
    console.log('Timetable combinations: ' + timetableCombinations.length);

    var timetableList = new TimetableList(timetableCombinations);
  }

  /**
   * Processes a timetable row.
   */
  function processRow() {
    var isSubjectHeader = $(this).find('td > a').length > 0,
        isActivityRow   = $(this).attr('bgcolor') === '#eeeeee';

    if (isSubjectHeader) {
      // New subject
      subjects.push(Subject.fromTableRow($(this)));
    } else if (isActivityRow) {
      // New activity under the latest subject
      var subject = subjects[subjects.length - 1];
      subject.addActivity(Activity.fromTableRow($(this), subject));
    }
  }

  /**
   * Gets an array of all activity groups.
   */
  function getAllActivityGroups() {
    return subjects.reduce(function (activityGroups, subject) {
      var groups = subject.getActivityGroups(),
          keys = Object.keys(groups);

      keys.forEach(function (key) {
        activityGroups.push(groups[key]);
      });

      return activityGroups;
    }, []);
  }

  /**
   * Returns the cartesian product of N arrays.
   */
  function cartesianProductOf(arr) {
    return arr.reduce(function(a, b) {
      var ret = [];
      a.forEach(function(a) {
        b.forEach(function(b) {
          ret.push(a.concat([b]));
        });
      });
      return ret;
    }, [[]]);
  }
});

/**
 * Represents a UTS subject.
 */
function Subject(name, code, semester) {
  if (arguments.length < 3) {
    throw new Error('Too few arguments supplied to create the Subject object.');
  }

  var activityGroups = {};

  /**
   * Adds an activity.
   */
  function addActivity(activity) {
    var type = activity.getType(),
        activities = activityGroups[type];
    if (typeof activityGroups[type] === 'undefined') {
      activityGroups[type] = [];
    }

    var existingActivity = getExistingActivity(activityGroups[type], activity);
    if (existingActivity) {
      existingActivity.addNumbers(activity.getNumbers());
    } else {
      activityGroups[type].push(activity);
    }
  }

  /**
   * Retrieves an activity from the array if it matches the
   * activity given.
   */
  function getExistingActivity(existingActivities, activity) {
    for (var i = 0; i < existingActivities.length; i++) {
      var existingActivity = existingActivities[i];
      if (existingActivity.matches(activity)) {
        return existingActivity;
      }
    }
    return null;
  }

  return {
    addActivity: addActivity,
    getActivityGroups: function () { return activityGroups; },
    getCode: function () { return code; }
  };
}

/**
 * Creates a new Subject object from a table row.
 */
Subject.fromTableRow = function (row) {
  var content = row.find('b:first');

  var name     = content.text().substr(content.text().indexOf(':') + 1).trim(),
      code     = content.children('a').attr('href').match(/\d+/)[0],
      semester = /AUT/.test(content.text()) ? 'autumn' : 'spring';

  return new Subject(name, code, semester);
};

/**
 * Represents a UTS subject activity.
 */
function Activity(type, numbers, day, startTime, duration, finishTime, subject) {
  if (arguments.length < 5) {
    throw new Error('Too few arguments supplied to create the Activity object.');
  }

  /**
   * Determines if two activities clash.
   */
  function hasTimeClashWith(activity) {
    var timeClashExists = startTime < activity.getFinishTime() && finishTime > activity.getStartTime();
    return timeClashExists;
  }

  /**
   * Determines if two activities are essentially identical.
   */
  function matches(activity) {
    return type === activity.getType() && day === activity.getDay() &&
      startTime === activity.getStartTime() && finishTime === activity.getFinishTime() &&
      subject === activity.getSubject();
  }

  /**
   * Appends activity numbers to the numbers array.
   */
  function addNumbers(numbersArray) {
    numbers = numbers.concat(numbersArray);
  }

  function toString() {
    return day + ' ' + startTime + '-' + finishTime + ': ' + subject.getCode() + ' ' + type + ' ' + numbers.join(',') + ' (' + duration + ')';
  }

  return {
    hasTimeClashWith: hasTimeClashWith,
    getStartTime: function () { return startTime; },
    getFinishTime: function () { return finishTime; },
    getType: function () { return type; },
    getNumbers: function () { return numbers; },
    getDay: function () { return day; },
    getSubject: function () { return subject; },
    matches: matches,
    addNumbers: addNumbers,
    toString: toString
  };
}

/**
 * Creates a new Activity object from a table row.
 */
Activity.fromTableRow = function (row, subject) {
  var cells = row.children().map(function() {return this.innerHTML;});

  var type       = cells[0],
      numbers    = [cells[1]],
      day        = cells[2],
      startTime  = cells[3],
      duration   = cells[4],
      finishTime = new Date('1/1/2015 ' + startTime).addMinutes(duration).get24hrTime(),
      startTime = parseInt(startTime.replace(':', ''));

  return new Activity(type, numbers, day, startTime, duration, finishTime, subject);
};

/**
 * Compares two activities.
 */
Activity.compare = function (a, b) {
  var days = { "Mon": 0, "Tue": 1, "Wed": 2, "Thu": 3, "Fri": 4, "Sat": 5, "Sun": 6 };

  if (a.getDay() === b.getDay()) {
    return a.getStartTime() - b.getStartTime();
  } else {
    return days[a.getDay()] - days[b.getDay()];
  }
};

/**
 * Represents a list of Timetable objects.
 */
function TimetableList(timetables) {
  if (arguments.length < 1) {
    throw new Error('Too few arguments supplied to create the TimetableList object.');
  }

  // Filter the list to only valid timetable combinations
  timetables = timetables.filter(function (timetable) {
    return timetable.isValid();
  });
  console.log('Valid timetables: ' + timetables.length);

  /**
   * Returns a filtered array of timetables.
   */
  function filter(filterMethod, args) {
    return timetables.filter(filterMethod, args);
  }

  /**
   * Sorts the timetables.
   */
  function sort(compareMethod) {
    timetables.sort(compareMethod);
  }

  return {
    getTimetables: function () { return timetables; },
    filter: filter,
    sort: sort
  };
}

/**
 * A static object of common filtering methods.
 */
TimetableList.FilterBy = {
  /**
   * Filters by the number of days the timetable spans.
   *
   * Required: The 2nd parameter of the filter method must
   * contain an object with the following properties:
   *  days  {Number}  The maximum allowable number of days
   *  exact {Boolean} Whether or not to also include timetables
   *                  with less days in the results.
   */
  DaysAtUni: function (timetable) {
    if (typeof this.days === 'undefined') {
      throw new Error('Days property missing for filter.');
    }

    var daysAtUni = Object.keys(timetable.getDays()).length;
    return this.exact ? daysAtUni === this.days : daysAtUni <= this.days;
  },

  /**
   * Filters to only timetables that always start later or finish
   * earlier than the specified time.
   *
   * Required: The 2nd parameter of the filter method must
   * contain an object with the following properties:
   *  time  {Number}  The earliest time an activity can start
   *  constraint {String} 'start' for later than; 'finish' for earlier than
   */
  TimeConstraint: function (timetable) {
    if (typeof this.time === 'undefined' || typeof this.constraint === 'undefined') {
      throw new Error('Time or Constraint property missing for filter.');
    }

    return timetable.getActivities().every(function (activity) {
      if (this.constraint === 'start') {
        return activity.getStartTime() >= this.time;
      } else {
        return activity.getFinishTime() <= this.time;
      }
    }, this);
  }
};

/**
 * A static object of common sorting methods.
 */
TimetableList.SortBy = {
  /**
   * Sorts by the total number of hours spent on campus.
   * Hours spent each day = end of last class - start of first class
   */
  HoursOnCampus: function (a, b) {
    return a.getHours() - b.getHours();
  }
};

function Timetable(activities) {
  /**
   * Returns an object of days and times that the timetable spans.
   */
  function getDays() {
    var dayInfo = activities.reduce(function (days, activity) {
      var day = activity.getDay(),
          start  = activity.getStartTime(),
          finish = activity.getFinishTime();

      if (typeof days[day] === 'undefined') {
        days[day] = { start: start, finish: finish };
      } else {
        if (start < days[day].start) days[day].start = start;
        if (finish > days[day].finish) days[day].finish = finish;
      }

      return days;
    }, {});

    return dayInfo;
  }

  /**
   * Determines if a timetable is valid.
   * There must be no activity clashes to return true.
   */
  function isValid() {
    var invalidTimes = {
      "Mon": [], "Tue": [], "Wed": [], "Thu": [], "Fri": [], "Sat": [], "Sun": []
    };

    var valid = activities.every(function (activity) {
      var conflicts = invalidTimes[activity.getDay()];

      if (conflicts.length === 0) {
        conflicts.push(activity);
        return true;
      }

      for (var i = 0; i < conflicts.length; i++) {
        var existingActivity = conflicts[i];
        if (activity.hasTimeClashWith(existingActivity)) {
          return false;
        }
      }
      conflicts.push(activity);
      return true;
    });

    return valid;
  }

  /**
   * Calculates the total number of hours spent at uni.
   */
  function getHours() {
    var dayInfo = getDays();

    var hours = Object.keys(dayInfo).reduce(function (totalHours, day) {
      totalHours += getTimeDiffInHours(dayInfo[day].finish, dayInfo[day].start);
      return totalHours;
    }, 0);

    return hours;
  }

  /**
   * Gets the difference between two times in hours.
   */
  function getTimeDiffInHours(startTime, finishTime) {
    startTime = getHoursSinceMidnight(startTime);
    finishTime = getHoursSinceMidnight(finishTime);
    return startTime - finishTime;
  }

  /**
   * Gets the number of hours passed since midnight.
   */
  function getHoursSinceMidnight(time) {
    var time    = time / 100,
        hours   = Math.floor(time),
        minutes = (time - hours) / 0.6;

    return (hours + minutes).toFixed(1);
  }

  /**
   * Sorts the timetable.
   */
  function sort(compareFn) {
    activities.sort(compareFn);
  }

  return {
    getActivities: function () { return activities; },
    getDays: getDays,
    getHours: getHours,
    isValid: isValid,
    sort: sort
  };
}

/**
 * Adds minutes to the date object.
 */
Date.prototype.addMinutes = function (minutes) {
  return new Date(this.getTime() + parseInt(minutes) * 60000);
};

/**
 * Returns the 24hr-formatted time.
 */
Date.prototype.get24hrTime = function () {
  return this.getHours() * 100 + this.getMinutes();
};

<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import UserBadge from '../user/user_badge';
import BottomBar from '../utilities/bottom_bar';
import { ITEM } from '../../consts/types';

class ItemCard extends Component {
  open() {
    const { item, open, modal, itemType } = this.props;
    if (!modal) {
      open(itemType, item.id);
    }
  }
  shouldComponentUpdate(nextProps) {
    if (
      this.props.theme === nextProps.theme
      && this.props.item === nextProps.item
    ) {
      return false;
    }
    return true;
  }
  renderCollab() {
    const { item, itemType } = this.props;
    if (itemType !== ITEM.COLLAB.NAME) {
      return null;
    }
    return (

        Project Type
        {item.c_type_long}
        {
          item.c_description ?

              Description
              {item.c_description}

            : null
        }
        {
          item.c_tech_stack ?

              Tech Stack
              {item.c_tech_stack}

            : null
        }
        {
          item.c_team_size ?

              Current Team Size
              {item.c_team_size}

            : null
        }
        {
          item.c_url ?

              Project Url
              {item.c_url}

            : null
        }

    );
  }
  render() {
    const { item, theme, vote, modal, itemType } = this.props;
    const user = {
      avatar: item.user_avatar,
      score: item.user_score,
      id: item.user_id,
      username: item.user_username,
    };
    const image = item.attached_image;
    return (
      <div
        className={`item_card ${modal ? null : 'shadow'}`}
        style={{
          backgroundColor: theme.item_card.backgroundColor,
          color: theme.item_card.color,
        }}
      >
        <UserBadge user={user} theme={theme} />

 this.open()}
        >

            { itemType === ITEM.COLLAB.NAME ?
              Summary : null
            }
            {item.text}
            { this.renderCollab() }

          { image !== '' ?  : null }

        <BottomBar
          score={item.score}
          comments={item.num_comments}
          isUpvoted={item.vote_state}
          vote={vote}
          id={item.id}
        />

    );
  }
}

ItemCard.propTypes = {
  item: PropTypes.object.isRequired,
  theme: PropTypes.object.isRequired,
  vote: PropTypes.func.isRequired,
  itemType: PropTypes.string, //eslint-disable-line
  open: PropTypes.func, // eslint-disable-line
  modal: PropTypes.bool, //eslint-disable-line
};

export default ItemCard;
<commit_msg>Fixed linting<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import UserBadge from '../user/user_badge';
import BottomBar from '../utilities/bottom_bar';
import { ITEM } from '../../consts/types';

class ItemCard extends Component {
  shouldComponentUpdate(nextProps) {
    if (
      this.props.theme === nextProps.theme
      && this.props.item === nextProps.item
    ) {
      return false;
    }
    return true;
  }
  open() {
    const { item, open, modal, itemType } = this.props;
    if (!modal) {
      open(itemType, item.id);
    }
  }
  renderCollab() {
    const { item, itemType } = this.props;
    if (itemType !== ITEM.COLLAB.NAME) {
      return null;
    }
    return (

        Project Type
        {item.c_type_long}
        {
          item.c_description ?

              Description
              {item.c_description}

            : null
        }
        {
          item.c_tech_stack ?

              Tech Stack
              {item.c_tech_stack}

            : null
        }
        {
          item.c_team_size ?

              Current Team Size
              {item.c_team_size}

            : null
        }
        {
          item.c_url ?

              Project Url
              {item.c_url}

            : null
        }

    );
  }
  render() {
    const { item, theme, vote, modal, itemType } = this.props;
    const user = {
      avatar: item.user_avatar,
      score: item.user_score,
      id: item.user_id,
      username: item.user_username,
    };
    const image = item.attached_image;
    return (
      <div
        className={`item_card ${modal ? null : 'shadow'}`}
        style={{
          backgroundColor: theme.item_card.backgroundColor,
          color: theme.item_card.color,
        }}
      >
        <UserBadge user={user} theme={theme} />

 this.open()}
        >

            { itemType === ITEM.COLLAB.NAME ?
              Summary : null
            }
            {item.text}
            { this.renderCollab() }

          { image !== '' ?  : null }

        <BottomBar
          score={item.score}
          comments={item.num_comments}
          isUpvoted={item.vote_state}
          vote={vote}
          id={item.id}
        />

    );
  }
}

ItemCard.propTypes = {
  item: PropTypes.object.isRequired,
  theme: PropTypes.object.isRequired,
  vote: PropTypes.func.isRequired,
  itemType: PropTypes.string, //eslint-disable-line
  open: PropTypes.func, // eslint-disable-line
  modal: PropTypes.bool, //eslint-disable-line
};

export default ItemCard;
<|endoftext|>