<commit_before>'use strict';

var L = require('leaflet');
var JXON = require('jxon');
JXON.config({attrPrefix: '@'});
var FileSaver = require('file-saver');

var Control = L.Control.extend({
  includes: L.Mixin.Events,
  options: {
    toolContainerClass: "",
    editorButtonClass: "",
    josmButtonClass: "",
    debugButtonClass: "",
    mapillaryButtonClass: "",
    gpxButtonClass: "",
    localizationChooserClass: ""
  },

  initialize: function(localization, languages, options) {
    L.setOptions(this, options);
    this._local = localization;
    this._languages = languages;
  },

  onAdd: function(map) {
    var editorContainer,
      editorButton,
      josmContainer,
      josmButton,
      debugContainer,
      debugButton,
      mapillaryContainer,
      mapillaryButton,
      localizationButton,
      popupCloseButton,
      gpxContainer,
      gpxButton;
    this._container = L.DomUtil.create('div', 'leaflet-osrm-tools-container ' + this.options.toolsContainerClass);
    L.DomEvent.disableClickPropagation(this._container);
    editorContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-editor', this._container);
    editorButton = L.DomUtil.create('span', this.options.editorButtonClass, editorContainer);
    editorButton.title = this._local['Open in editor'];
    L.DomEvent.on(editorButton, 'click', this._openEditor, this);
    josmContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-josm', this._container);
    josmButton = L.DomUtil.create('span', this.options.josmButtonClass, josmContainer);
    josmButton.title = this._local['Open in JOSM'];
    L.DomEvent.on(josmButton, 'click', this._openJOSM, this);
    debugContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-debug', this._container);
    debugButton = L.DomUtil.create('span', this.options.debugButtonClass, debugContainer);
    debugButton.title = this._local['Open in Debug Map'];
    L.DomEvent.on(debugButton, 'click', this._openDebug, this);
    mapillaryContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-mapillary', this._container);
    mapillaryButton = L.DomUtil.create('span', this.options.mapillaryButtonClass, mapillaryContainer);
    mapillaryButton.title = this._local['Open in Mapillary'];
    L.DomEvent.on(mapillaryButton, 'click', this._openMapillary, this);
    gpxContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-gpx', this._container);
    gpxButton = L.DomUtil.create('span', this.options.gpxButtonClass, gpxContainer);
    this._gpxButton = gpxButton;
    gpxButton.title = this._local['GPX'];
    gpxButton.setAttribute('disabled', '');
    L.DomEvent.on(gpxButton, 'click', this._downloadGPX, this);
    this._localizationContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-localization', this._container);
    this._createLocalizationList(this._localizationContainer);
    return this._container;
  },

  onRemove: function() {},

  _openEditor: function() {
    var position = this._map.getCenter(),
      zoom = this._map.getZoom(),
      prec = 6;
    window.open("https://www.openstreetmap.org/edit?lat=" + position.lat.toFixed(prec) + "&lon=" + position.lng.toFixed(prec) + "&zoom=" + zoom);
  },

  _openJOSM: function() {
    var bounds = this._map.getBounds(),
      url = 'http://127.0.0.1:8111/load_and_zoom' +
      '?left=' + bounds.getWest() +
      '&right=' + bounds.getEast() +
      '&bottom=' + bounds.getSouth() +
      '&top=' + bounds.getNorth();
    window.open(url);
  },

  _openDebug: function() {
    var position = this._map.getCenter(),
      zoom = this._map.getZoom(),
      prec = 6;
    window.open("debug/#" + zoom + "/" + position.lat.toFixed(prec) + "/" + position.lng.toFixed(prec));
  },

  _openMapillary: function() {
    var position = this._map.getCenter(),
      zoom = this._map.getZoom(),
      prec = 6;
    window.open("https://www.mapillary.com/app/?lat=" + position.lat.toFixed(prec) + "&lng=" + position.lng.toFixed(prec) + "&z=" + zoom);
  },

  setRouteGeoJSON: function(routeGeoJSON) {
    this.routeGeoJSON = routeGeoJSON;
    if (this.routeGeoJSON) {
      this._gpxButton.removeAttribute('disabled');
    }
    else {
      this._gpxButton.setAttribute('disabled', '');
    }
  },

  _downloadGPX: function() {
    if (this.routeGeoJSON) {
      var properties = this.routeGeoJSON.properties;
      var metadata = {
        name: properties.name,
        copyright: {
          '@author': properties.copyright.author,
          license: properties.copyright.license
        },
        link: {
          '@href': properties.link.href,
          text: properties.link.text
        },
        time: properties.time
      };
      var trackPoints = this.routeGeoJSON.geometry.coordinates.map(function (coordinate) {
        return {
          '@lat': coordinate[1],
          '@lon': coordinate[0],
        };
      });
      var gpx = {
        'gpx': {
          '@xmlns': 'http://www.topografix.com/GPX/1/1',
          '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
          '@xsi:schemaLocation': 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd',
          '@version': '1.1',
          'metadata': metadata,
          'trk': {
            'trkseg': {
              'trkpt': trackPoints
            }
          }
        }
      };
      var gpxData = JXON.stringify(gpx);
      var blob = new Blob(['<?xml version="1.0" encoding="utf-8"?>', "\n", gpxData], {
        type: 'application/gpx+xml;charset=utf-8'
      }, false);
      FileSaver.saveAs(blob, 'route.gpx');
    }
  },

  _updatePopupPosition: function(button) {
    var rect = this._container.getBoundingClientRect(),
        left = 0;
    if (button)
    {
        left = button.getBoundingClientRect().left - rect.left;
    }
    this._popupWindow.style.position = 'absolute';
    this._popupWindow.style.left = left + 'px';
    this._popupWindow.style.bottom = rect.height + 'px';
  },

  _createLocalizationList: function(container) {
    var _this = this;
    var localizationSelect = L.DomUtil.create('select', _this.options.localizationChooserClass, container);
    localizationSelect.setAttribute('title', _this._local['Select language']);
    L.DomEvent.on(localizationSelect, 'change', function(event) {
        this.fire('languagechanged', {
            language: event.target.value
        });
    }, _this);
    Object.keys(this._languages).forEach(function(key) {
        var option = L.DomUtil.create('option', 'fill-osrm', localizationSelect);
        option.setAttribute('value', key);
        option.appendChild(
            document.createTextNode(_this._languages[key])
        );
        if (key == _this._local.key)
        {
            option.setAttribute('selected', '');
        }
    });
  }
});

module.exports = {
  control: function(localization, languages, options) {
    return new Control(localization, languages, options);
  }
};
<commit_msg>Add workaround for issues with GPX generation in IE11<commit_after>'use strict';

var L = require('leaflet');
var JXON = require('jxon');
JXON.config({attrPrefix: '@'});
var FileSaver = require('file-saver');

var Control = L.Control.extend({
  includes: L.Mixin.Events,
  options: {
    toolContainerClass: "",
    editorButtonClass: "",
    josmButtonClass: "",
    debugButtonClass: "",
    mapillaryButtonClass: "",
    gpxButtonClass: "",
    localizationChooserClass: ""
  },

  initialize: function(localization, languages, options) {
    L.setOptions(this, options);
    this._local = localization;
    this._languages = languages;
  },

  onAdd: function(map) {
    var editorContainer,
      editorButton,
      josmContainer,
      josmButton,
      debugContainer,
      debugButton,
      mapillaryContainer,
      mapillaryButton,
      localizationButton,
      popupCloseButton,
      gpxContainer,
      gpxButton;
    this._container = L.DomUtil.create('div', 'leaflet-osrm-tools-container ' + this.options.toolsContainerClass);
    L.DomEvent.disableClickPropagation(this._container);
    editorContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-editor', this._container);
    editorButton = L.DomUtil.create('span', this.options.editorButtonClass, editorContainer);
    editorButton.title = this._local['Open in editor'];
    L.DomEvent.on(editorButton, 'click', this._openEditor, this);
    josmContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-josm', this._container);
    josmButton = L.DomUtil.create('span', this.options.josmButtonClass, josmContainer);
    josmButton.title = this._local['Open in JOSM'];
    L.DomEvent.on(josmButton, 'click', this._openJOSM, this);
    debugContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-debug', this._container);
    debugButton = L.DomUtil.create('span', this.options.debugButtonClass, debugContainer);
    debugButton.title = this._local['Open in Debug Map'];
    L.DomEvent.on(debugButton, 'click', this._openDebug, this);
    mapillaryContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-mapillary', this._container);
    mapillaryButton = L.DomUtil.create('span', this.options.mapillaryButtonClass, mapillaryContainer);
    mapillaryButton.title = this._local['Open in Mapillary'];
    L.DomEvent.on(mapillaryButton, 'click', this._openMapillary, this);
    gpxContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-gpx', this._container);
    gpxButton = L.DomUtil.create('span', this.options.gpxButtonClass, gpxContainer);
    this._gpxButton = gpxButton;
    gpxButton.title = this._local['GPX'];
    gpxButton.setAttribute('disabled', '');
    L.DomEvent.on(gpxButton, 'click', this._downloadGPX, this);
    this._localizationContainer = L.DomUtil.create('div', 'leaflet-osrm-tools-localization', this._container);
    this._createLocalizationList(this._localizationContainer);
    return this._container;
  },

  onRemove: function() {},

  _openEditor: function() {
    var position = this._map.getCenter(),
      zoom = this._map.getZoom(),
      prec = 6;
    window.open("https://www.openstreetmap.org/edit?lat=" + position.lat.toFixed(prec) + "&lon=" + position.lng.toFixed(prec) + "&zoom=" + zoom);
  },

  _openJOSM: function() {
    var bounds = this._map.getBounds(),
      url = 'http://127.0.0.1:8111/load_and_zoom' +
      '?left=' + bounds.getWest() +
      '&right=' + bounds.getEast() +
      '&bottom=' + bounds.getSouth() +
      '&top=' + bounds.getNorth();
    window.open(url);
  },

  _openDebug: function() {
    var position = this._map.getCenter(),
      zoom = this._map.getZoom(),
      prec = 6;
    window.open("debug/#" + zoom + "/" + position.lat.toFixed(prec) + "/" + position.lng.toFixed(prec));
  },

  _openMapillary: function() {
    var position = this._map.getCenter(),
      zoom = this._map.getZoom(),
      prec = 6;
    window.open("https://www.mapillary.com/app/?lat=" + position.lat.toFixed(prec) + "&lng=" + position.lng.toFixed(prec) + "&z=" + zoom);
  },

  setRouteGeoJSON: function(routeGeoJSON) {
    this.routeGeoJSON = routeGeoJSON;
    if (this.routeGeoJSON) {
      this._gpxButton.removeAttribute('disabled');
    }
    else {
      this._gpxButton.setAttribute('disabled', '');
    }
  },

  _downloadGPX: function() {
    if (this.routeGeoJSON) {
      var properties = this.routeGeoJSON.properties;
      var metadata = {
        name: properties.name,
        copyright: {
          '@author': properties.copyright.author,
          license: properties.copyright.license
        },
        link: {
          '@href': properties.link.href,
          text: properties.link.text
        },
        time: properties.time
      };
      var trackPoints = this.routeGeoJSON.geometry.coordinates.map(function (coordinate) {
        return {
          '@lat': coordinate[1],
          '@lon': coordinate[0],
        };
      });
      var gpx = {
        'gpx': {
          '@xmlns': 'http://www.topografix.com/GPX/1/1',
          '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
          '@xsi:schemaLocation': 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd',
          '@version': '1.1',
          'metadata': metadata,
          'trk': {
            'trkseg': {
              'trkpt': trackPoints
            }
          }
        }
      };
      var gpxData = JXON.stringify(gpx);
      // Work around issues with XML name space generation in IE 11
      // (see also https://github.com/tyrasd/jxon/issues/42)
      gpxData = gpxData.replace(/\s+xmlns:NS\d+=""/g, '');
      gpxData = gpxData.replace(/NS\d+:/g, '');
      var blob = new Blob(['<?xml version="1.0" encoding="utf-8"?>', "\n", gpxData], {
        type: 'application/gpx+xml;charset=utf-8'
      }, false);
      FileSaver.saveAs(blob, 'route.gpx');
    }
  },

  _updatePopupPosition: function(button) {
    var rect = this._container.getBoundingClientRect(),
        left = 0;
    if (button)
    {
        left = button.getBoundingClientRect().left - rect.left;
    }
    this._popupWindow.style.position = 'absolute';
    this._popupWindow.style.left = left + 'px';
    this._popupWindow.style.bottom = rect.height + 'px';
  },

  _createLocalizationList: function(container) {
    var _this = this;
    var localizationSelect = L.DomUtil.create('select', _this.options.localizationChooserClass, container);
    localizationSelect.setAttribute('title', _this._local['Select language']);
    L.DomEvent.on(localizationSelect, 'change', function(event) {
        this.fire('languagechanged', {
            language: event.target.value
        });
    }, _this);
    Object.keys(this._languages).forEach(function(key) {
        var option = L.DomUtil.create('option', 'fill-osrm', localizationSelect);
        option.setAttribute('value', key);
        option.appendChild(
            document.createTextNode(_this._languages[key])
        );
        if (key == _this._local.key)
        {
            option.setAttribute('selected', '');
        }
    });
  }
});

module.exports = {
  control: function(localization, languages, options) {
    return new Control(localization, languages, options);
  }
};
<|endoftext|>


<commit_before>(function($) {
    "use strict";

    /**
     * Responsible for application-wide issues such as the creation of modules.
     *
     * @author Remo Brunschwiler
     * @namespace Tc
     * @class Application
     */
    Tc.Application = Class.extend({

        /**
         * Initializes the application.
         *
         * @method init
         * @return {void}
         * @constructor
         * @param {jQuery} $ctx
         *      The jquery context
         * @param {Object} config
         *      The configuration
         */
        init: function($ctx, config) {
            /**
             * The configuration.
             *
             * @property config
             * @type Object
             */
            this.config = $.extend(Tc.Config, config);

            /**
             * The jQuery context.
             *
             * @property $ctx
             * @type jQuery
             */
            this.$ctx = $ctx || $('body');

            /**
             * Contains references to all modules on the page. This can, for
             * example, be useful when there are interactions between Flash
             * objects and Javascript.
             *
             * @property modules
             * @type Array
             */
            this.modules = [];

            /**
             * Contains references to all connectors on the page.
             *
             * @property connectors
             * @type Object
             */
            this.connectors = {};

            /**
             * Contains references to all wildcard components on the page.
             *
             * @property wildcardComponents
             * @type Array
             */
            this.wildcardComponents = [];

            /**
             * The sandbox to get the resources from
             * This sandbox is shared between all modules.
             *
             * @property sandbox
             * @type Sandbox
             */
            this.sandbox = new Tc.Sandbox(this, this.config);
        },

        /**
         * Register modules withing scope
         * Automatically registers all modules within the scope,
         * as long as the modules use the OOCSS naming conventions.
         *
         * @method registerModules
         * @param {jQuery} $ctx
         *      The jQuery context.
         * @return {Array}
         *      A list containing the references of the registered modules.
         */
        registerModules : function($ctx) {
            var that = this,
                modules = [];

            $ctx = $ctx || this.$ctx;

            $ctx.find('.mod').each(function() {
                var $this = $(this);

                /**
                 * Indicates that it is a base module, this is the default and
                 * no JavaScript needs to be involved. It must occur excactly
                 * once.
                 * @config .mod
                 */

                /**
                 * Indicates that it is a module of type basic, which is
                 * derived from the base module. It can occur at most
                 * once. Example: .modBasic
                 * @config .mod{moduleName}
                 */

                /**
                 * Indicates that the module basic has the submarine skin. It
                 * will be decorated by the skin JS (if it exists). It can occur
                 * arbitrarily. Example: .skinBasicSubmarine
                 * @config .skin{moduleName}{skinName}
                 */

                /**
                 * A module can have a comma-separated list of data connectors.
                 * The list contains the IDs of the connectors in the following
                 * schema: {connectorName}{connectorId}{connectorRole}
                 *
                 * The example MasterSlave1Master decodes to: name =
                 * MasterSlave, id = 1, role = Master. This indicates that the
                 * module should notify the MasterSlave connector (the mediator)
                 * on all state changes. The connector id is used to chain the
                 * appropriate modules together and to improve the
                 * reusability of the connector. It can contain multiple
                 * connector ids (e.g. 1,2,MasterSlave1Master).
                 *
                 * @config data-connectors
                 */

                var classes = $this.attr('class').split(' ');

                if (classes.length > 1) {
                    var modName,
                        skins = [],
                        connectors = [];

                    for (var i = 0, len = classes.length; i < len; i++) {
                        var part = $.trim(classes[i]);

                        if (part.indexOf('mod') === 0 && part.length > 3) {
                            modName = part.substr(3);
                        }
                        else if (part.indexOf('skin') === 0) {
                            // Remove the mod name part from the skin name
                            skins.push(part.substr(4).replace(modName, ''));
                        }
                    }

                    if ($this.data('tc-connectors')) {
                        connectors = $this.data('tc-connectors').split(',');
                        for (var i = 0, len = connectors.length; i < len; i++) {
                            var connector = $.trim(connectors[i]);
                            if(connector) {
                                connectors[i] = connector;
                            }
                        }
                    }

                    if (modName && Tc.Module[modName]) {
                        modules.push(that.registerModule($this, modName, skins, connectors));
                    }
                }
            });

            return modules;
        },

        /**
         * Unregisters the modules given by the module instances.
         *
         * @method unregisterModule
         * @param {Array} modules
         *      A list containting the module instances to unregister
         * @return {void}
         */
        unregisterModules : function(modules) {
            var connectors = this.connectors,
                wildcardComponents = this.wildcardComponents;

            modules = modules || this.modules;

            if (modules === this.modules) {
                // Empty everything if the arrays are equal
                this.wildcardComponents = [];
                this.connectors = [];
                this.modules = [];
            }
            else {
                // Unregister the given modules
                for (var i = 0, len = modules.length; i < len; i++) {
                    var module = modules[i];
                    var index;

                    // Delete the references in the connectors
                    for (var connectorId in connectors) {
                        if (connectors.hasOwnProperty(connectorId)) {
                            connectors[connectorId].unregisterComponent(module);
                        }
                    }

                    // Delete the references in the wildcard components
                    index = $.inArray(module, wildcardComponents);
                    if(index > -1) {
                        delete wildcardComponents[index];
                    }

                    // Delete the module instance itself
                    index = $.inArray(module, this.modules);
                    if(index > -1) {
                        delete this.modules[index];
                    }
                }
            }
        },

        /**
         * Starts (intializes) the registered modules.
         *
         * @method start
         * @param {Array} modules
         *      A list of the modules to start
         * @return {void}
         */
        start: function(modules) {
            var wildcardComponents = this.wildcardComponents,
                connectors = this.connectors;

            modules = modules || this.modules;

            // Start the modules
            for (var i = 0, len = modules.length; i < len; i++) {
                modules[i].start();
            }

            /*
             * Special treatment for the wildcard connection (conn*) -> it will
             * be notified about all state changes from all connections and is
             * able to propagate its changes to all modules. This must be done on
             * init to make sure that all connectors on the page has been
             * instantiated. Only do this for the given modules.
             */
            for (var i = 0, len = wildcardComponents.length; i < len; i++) {
                var component = wildcardComponents[i];
                if ($.inArray(component, modules) > -1) {
                    for (var connectorId in connectors) {
                        if (connectors.hasOwnProperty(connectorId)) {
                            // The connector observes the component and attaches it as an observer
                            component.attachConnector(connectors[connectorId]);
                            connectors[connectorId].registerComponent(component, '*');
                        }
                    }
                }
            }
        },

        /**
         * Stops the registered modules.
         *
         * @method stop
         * @param {Array} modules
         *      A list containting the module instances to stop.
         * @return {void}
         */
        stop: function(modules) {
            modules = modules || this.modules;

            // Stop the modules
            for (var i = 0, len = modules.length; i < len; i++) {
                modules[i].stop();
            }
        },

        /**
         * Registers a module.
         *
         * @method registerModule
         * @param {jQuery} $node
         *      The module node.
         * @param {String} modName
         *      The module name. It must match the class name of the module
         *      (case sensitive).
         * @param {Array} skins
         *      A list of skin names. Each entry must match a class name of a
         *      skin (case sensitive).
         * @param {Array} connectors
         *      A list of connectors identifiers (e.g. MasterSlave1Master).
         *      Schema: {connectorName}{connectorId}{connectorRole}
         * @return {Module}
         *      The reference to the registered module.
         */
        registerModule : function($node, modName, skins, connectors) {
            var modules = this.modules;

            modName = modName || null;
            skins = skins || [];
            connectors = connectors || [];

            if (modName && Tc.Module[modName]) {
                // Generate a unique ID for every module
                var modId = modules.length;
                $node.data('tc-id', modId);

                modules[modId] = new Tc.Module[modName]($node, this.sandbox, modId);

                for (var i = 0, len = skins.length; i < len; i++) {
                    var skinName = skins[i];

                    if (Tc.Module[modName][skinName]) {
                        modules[modId] = modules[modId].getDecoratedModule(modName, skinName);
                    }
                }

                for (var i = 0, len = connectors.length; i < len; i++) {
                    this.registerConnection(connectors[i], modules[modId]);
                }

                return modules[modId];
            }

            return null;
        },

        /**
         * Registers a connection between a module and a connector.
         *
         * @method registerConnection
         * @param {String} connector
         *      The full connector name (e.g. MasterSlave1Slave).
         * @param {Module} component
         *      The module instance.
         * @return {void}
         */
        registerConnection : function(connector, component) {
            var connectorType = connector.replace(/[0-9]+[a-zA-Z]*$/, ''),
                connectorId = connector.replace(/[a-zA-Z]*$/, '').replace(/^[a-zA-Z]*/, ''),
                connectorRole = connector.replace(/^[a-zA-Z]*[0-9]*/, '');

            if(connectorId) {
                if (connectorId === '*' && connectorRole === '*') {
                    // Add the component to the wildcard component stack
                    this.wildcardComponents.push(component);
                }
                else {
                    var connectors = this.connectors;

                    if (!connectors[connectorId]) {
                        // Instantiate the appropriate connector if it does not
                // exist yet
                        if (connectorType === '') {
                            connectors[connectorId] = new Tc.Connector(connectorId);
                        }
                        else if (Tc.Connector[connectorType]) {
                            connectors[connectorId] = new Tc.Connector[connectorType](connectorId);
                        }
                    }

                    if (connectors[connectorId]) {
                        /**
                         * The connector observes the component and attaches it as
                         * an observer.
                         */
                        component.attachConnector(connectors[connectorId]);

                        /**
                         * The component wants to be informed over state changes.
                         * It registers it as connector member.
                         */
                        connectors[connectorId].registerComponent(component, connectorRole);
                    }
                }
            }
        },

        /**
         * Unregisters a module from a connector.
         *
         * @method unregisterConnection
         * @param {int} connectorId
         *      The connector channel id (e.g. 2).
         * @param {Module} component
         *      The module instance.
         * @return {void}
         */
        unregisterConnection : function(connectorId, component) {
            var wildcardComponents = this.wildcardComponents,
                connectors = this.connectors,
                connector = connectors[connectorId];

            // Delete the references in the connector and the module
            if (connector) {
                connector.unregisterComponent(component);
                component.detachConnector(connector);
            }

            // Delete the references in the wildcard components
            var index = $.inArray(component, wildcardComponents);
            if(index > -1) {
                delete wildcardComponents[index];
            }
        }
    });
})(Tc.$);

<commit_msg>Small performance improvements dealing with usage of $.data(elem) instead of $elem.data(), where possible, and caching the values. Note: to read data attributes from the DOM, the $elem.data() must have been used once!<commit_after>(function($) {
    "use strict";

    /**
     * Responsible for application-wide issues such as the creation of modules.
     *
     * @author Remo Brunschwiler
     * @namespace Tc
     * @class Application
     */
    Tc.Application = Class.extend({

        /**
         * Initializes the application.
         *
         * @method init
         * @return {void}
         * @constructor
         * @param {jQuery} $ctx
         *      The jquery context
         * @param {Object} config
         *      The configuration
         */
        init: function($ctx, config) {
            /**
             * The configuration.
             *
             * @property config
             * @type Object
             */
            this.config = $.extend(Tc.Config, config);

            /**
             * The jQuery context.
             *
             * @property $ctx
             * @type jQuery
             */
            this.$ctx = $ctx || $('body');

            /**
             * Contains references to all modules on the page. This can, for
             * example, be useful when there are interactions between Flash
             * objects and Javascript.
             *
             * @property modules
             * @type Array
             */
            this.modules = [];

            /**
             * Contains references to all connectors on the page.
             *
             * @property connectors
             * @type Object
             */
            this.connectors = {};

            /**
             * Contains references to all wildcard components on the page.
             *
             * @property wildcardComponents
             * @type Array
             */
            this.wildcardComponents = [];

            /**
             * The sandbox to get the resources from
             * This sandbox is shared between all modules.
             *
             * @property sandbox
             * @type Sandbox
             */
            this.sandbox = new Tc.Sandbox(this, this.config);
        },

        /**
         * Register modules withing scope
         * Automatically registers all modules within the scope,
         * as long as the modules use the OOCSS naming conventions.
         *
         * @method registerModules
         * @param {jQuery} $ctx
         *      The jQuery context.
         * @return {Array}
         *      A list containing the references of the registered modules.
         */
        registerModules : function($ctx) {
            var that = this,
                modules = [];

            $ctx = $ctx || this.$ctx;

            $ctx.find('.mod').each(function() {
                var $this = $(this);

                /**
                 * Indicates that it is a base module, this is the default and
                 * no JavaScript needs to be involved. It must occur excactly
                 * once.
                 * @config .mod
                 */

                /**
                 * Indicates that it is a module of type basic, which is
                 * derived from the base module. It can occur at most
                 * once. Example: .modBasic
                 * @config .mod{moduleName}
                 */

                /**
                 * Indicates that the module basic has the submarine skin. It
                 * will be decorated by the skin JS (if it exists). It can occur
                 * arbitrarily. Example: .skinBasicSubmarine
                 * @config .skin{moduleName}{skinName}
                 */

                /**
                 * A module can have a comma-separated list of data connectors.
                 * The list contains the IDs of the connectors in the following
                 * schema: {connectorName}{connectorId}{connectorRole}
                 *
                 * The example MasterSlave1Master decodes to: name =
                 * MasterSlave, id = 1, role = Master. This indicates that the
                 * module should notify the MasterSlave connector (the mediator)
                 * on all state changes. The connector id is used to chain the
                 * appropriate modules together and to improve the
                 * reusability of the connector. It can contain multiple
                 * connector ids (e.g. 1,2,MasterSlave1Master).
                 *
                 * @config data-connectors
                 */

                var classes = $this.attr('class').split(' '),
                    data_connectors;

                if (classes.length > 1) {
                    var modName,
                        skins = [],
                        connectors = [];

                    for (var i = 0, len = classes.length; i < len; i++) {
                        var part = $.trim(classes[i]);

                        if (part.indexOf('mod') === 0 && part.length > 3) {
                            modName = part.substr(3);
                        }
                        else if (part.indexOf('skin') === 0) {
                            // Remove the mod name part from the skin name
                            skins.push(part.substr(4).replace(modName, ''));
                        }
                    }

                    data_connectors = $.data($this, 'tc-connectors');

                    if (data_connectors) {
                        connectors = data_connectors.split(',');
                        for (var i = 0, len = connectors.length; i < len; i++) {
                            var connector = $.trim(connectors[i]);
                            if(connector) {
                                connectors[i] = connector;
                            }
                        }
                    }

                    if (modName && Tc.Module[modName]) {
                        modules.push(that.registerModule($this, modName, skins, connectors));
                    }
                }
            });

            return modules;
        },

        /**
         * Unregisters the modules given by the module instances.
         *
         * @method unregisterModule
         * @param {Array} modules
         *      A list containting the module instances to unregister
         * @return {void}
         */
        unregisterModules : function(modules) {
            var connectors = this.connectors,
                wildcardComponents = this.wildcardComponents;

            modules = modules || this.modules;

            if (modules === this.modules) {
                // Empty everything if the arrays are equal
                this.wildcardComponents = [];
                this.connectors = [];
                this.modules = [];
            }
            else {
                // Unregister the given modules
                for (var i = 0, len = modules.length; i < len; i++) {
                    var module = modules[i];
                    var index;

                    // Delete the references in the connectors
                    for (var connectorId in connectors) {
                        if (connectors.hasOwnProperty(connectorId)) {
                            connectors[connectorId].unregisterComponent(module);
                        }
                    }

                    // Delete the references in the wildcard components
                    index = $.inArray(module, wildcardComponents);
                    if(index > -1) {
                        delete wildcardComponents[index];
                    }

                    // Delete the module instance itself
                    index = $.inArray(module, this.modules);
                    if(index > -1) {
                        delete this.modules[index];
                    }
                }
            }
        },

        /**
         * Starts (intializes) the registered modules.
         *
         * @method start
         * @param {Array} modules
         *      A list of the modules to start
         * @return {void}
         */
        start: function(modules) {
            var wildcardComponents = this.wildcardComponents,
                connectors = this.connectors;

            modules = modules || this.modules;

            // Start the modules
            for (var i = 0, len = modules.length; i < len; i++) {
                modules[i].start();
            }

            /*
             * Special treatment for the wildcard connection (conn*) -> it will
             * be notified about all state changes from all connections and is
             * able to propagate its changes to all modules. This must be done on
             * init to make sure that all connectors on the page has been
             * instantiated. Only do this for the given modules.
             */
            for (var i = 0, len = wildcardComponents.length; i < len; i++) {
                var component = wildcardComponents[i];
                if ($.inArray(component, modules) > -1) {
                    for (var connectorId in connectors) {
                        if (connectors.hasOwnProperty(connectorId)) {
                            // The connector observes the component and attaches it as an observer
                            component.attachConnector(connectors[connectorId]);
                            connectors[connectorId].registerComponent(component, '*');
                        }
                    }
                }
            }
        },

        /**
         * Stops the registered modules.
         *
         * @method stop
         * @param {Array} modules
         *      A list containting the module instances to stop.
         * @return {void}
         */
        stop: function(modules) {
            modules = modules || this.modules;

            // Stop the modules
            for (var i = 0, len = modules.length; i < len; i++) {
                modules[i].stop();
            }
        },

        /**
         * Registers a module.
         *
         * @method registerModule
         * @param {jQuery} $node
         *      The module node.
         * @param {String} modName
         *      The module name. It must match the class name of the module
         *      (case sensitive).
         * @param {Array} skins
         *      A list of skin names. Each entry must match a class name of a
         *      skin (case sensitive).
         * @param {Array} connectors
         *      A list of connectors identifiers (e.g. MasterSlave1Master).
         *      Schema: {connectorName}{connectorId}{connectorRole}
         * @return {Module}
         *      The reference to the registered module.
         */
        registerModule : function($node, modName, skins, connectors) {
            var modules = this.modules;

            modName = modName || null;
            skins = skins || [];
            connectors = connectors || [];

            if (modName && Tc.Module[modName]) {
                // Generate a unique ID for every module
                var modId = modules.length;
                $.data($node[0], 'tc-id', modId);

                modules[modId] = new Tc.Module[modName]($node, this.sandbox, modId);

                for (var i = 0, len = skins.length; i < len; i++) {
                    var skinName = skins[i];

                    if (Tc.Module[modName][skinName]) {
                        modules[modId] = modules[modId].getDecoratedModule(modName, skinName);
                    }
                }

                for (var i = 0, len = connectors.length; i < len; i++) {
                    this.registerConnection(connectors[i], modules[modId]);
                }

                return modules[modId];
            }

            return null;
        },

        /**
         * Registers a connection between a module and a connector.
         *
         * @method registerConnection
         * @param {String} connector
         *      The full connector name (e.g. MasterSlave1Slave).
         * @param {Module} component
         *      The module instance.
         * @return {void}
         */
        registerConnection : function(connector, component) {
            var connectorType = connector.replace(/[0-9]+[a-zA-Z]*$/, ''),
                connectorId = connector.replace(/[a-zA-Z]*$/, '').replace(/^[a-zA-Z]*/, ''),
                connectorRole = connector.replace(/^[a-zA-Z]*[0-9]*/, '');

            if(connectorId) {
                if (connectorId === '*' && connectorRole === '*') {
                    // Add the component to the wildcard component stack
                    this.wildcardComponents.push(component);
                }
                else {
                    var connectors = this.connectors;

                    if (!connectors[connectorId]) {
                        // Instantiate the appropriate connector if it does not
                // exist yet
                        if (connectorType === '') {
                            connectors[connectorId] = new Tc.Connector(connectorId);
                        }
                        else if (Tc.Connector[connectorType]) {
                            connectors[connectorId] = new Tc.Connector[connectorType](connectorId);
                        }
                    }

                    if (connectors[connectorId]) {
                        /**
                         * The connector observes the component and attaches it as
                         * an observer.
                         */
                        component.attachConnector(connectors[connectorId]);

                        /**
                         * The component wants to be informed over state changes.
                         * It registers it as connector member.
                         */
                        connectors[connectorId].registerComponent(component, connectorRole);
                    }
                }
            }
        },

        /**
         * Unregisters a module from a connector.
         *
         * @method unregisterConnection
         * @param {int} connectorId
         *      The connector channel id (e.g. 2).
         * @param {Module} component
         *      The module instance.
         * @return {void}
         */
        unregisterConnection : function(connectorId, component) {
            var wildcardComponents = this.wildcardComponents,
                connectors = this.connectors,
                connector = connectors[connectorId];

            // Delete the references in the connector and the module
            if (connector) {
                connector.unregisterComponent(component);
                component.detachConnector(connector);
            }

            // Delete the references in the wildcard components
            var index = $.inArray(component, wildcardComponents);
            if(index > -1) {
                delete wildcardComponents[index];
            }
        }
    });
})(Tc.$);

<|endoftext|>


<commit_before>// ==========================================
// Begin Kitten Scientist's Automation Engine
// ==========================================

var version = 'Kitten Scientists version 1.1.5';
var game = gamePage;

var options = {
    interval: 3000,
    color: '#aa50fe', // dark purple
    amount: {
        consume: 0.5
    },
    auto: {
        build: [
            {name: 'field', require: 'catnip'},
            {name: 'pasture', require: 'catnip'},
            {name: 'mine', require: 'wood'},
            {name: 'library', require: 'wood'},
            {name: 'academy', require: 'wood'},
            {name: 'barn', require: 'wood'},
            {name: 'workshop', require: 'minerals'},
            {name: 'lumberMill', require: 'minerals'},
            {name: 'aqueduct', require: 'minerals'},
            {name: 'unicornPasture', require: false},
            {name: 'tradepost', require: 'gold'}
        ],
        craft: [
            {name: 'wood', require: 'catnip'},
            {name: 'beam', require: 'wood'},
            {name: 'slab', require: 'minerals'},
            {name: 'steel', require: 'coal'},
            {name: 'plate', require: 'iron'}
        ],
        house: [
            {name: 'hut', require: 'wood'},
            {name: 'logHouse', require: 'minerals'},
            {name: 'mansion', require: 'titanium'}
        ],
        luxury: [
            {name: 'manuscript', require: 'culture'},
            {name: 'compendium', require: 'science'}
        ]
    },
    limit: {
        build: 0.75,
        craft: 0.95,
        house: 0.85,
        hunt: 0.95,
        luxury: 0.99,
        faith: 0.99
    },
    stock: {
        compendium: 500,
        manuscript: 500,
        parchment: 500
    },
    toggle: {
        building: true,
        crafting: true,
        housing: true,
        hunting: true,
        luxury: true,
        praising: true
    }
};

// GameLog Modification
// ====================

var gameLog = com.nuclearunicorn.game.log.Console().static;

var message = function () {
    var args = Array.prototype.slice.call(arguments);
    args[1] = args[1] || 'ks-default';

    // update the color of the message immediately after adding
    gameLog.msg.apply(gameLog, args);
    $('.type_' + args[1]).css('color', options.color);
};

// Core Engine for Kitten Scientists
// =================================

var Engine = function () {
    this.buildManager = new BuildManager();
    this.craftManager = new CraftManager();
};

Engine.prototype = {
    buildManager: undefined,
    craftManager: undefined,
    loop: undefined,
    start: function () {
        if (this.loop) return;

        this.loop = setInterval(this.iterate.bind(this), options.interval);
        message('Starting the kitten scientists!');
    },
    stop: function () {
        if (!this.loop) return;

        clearInterval(this.loop);
        this.loop = undefined;
        message('Freezing the kitten scientists!');
    },
    iterate: function () {
        this.observeGameLog();
        if (options.toggle.praising) this.praiseSun();
        if (options.toggle.hunting) this.sendHunters();
        if (options.toggle.building) this.startBuilds('build', options.auto.build);
        if (options.toggle.housing) this.startBuilds('house', options.auto.house);
        if (options.toggle.crafting) this.startCrafts('craft', options.auto.craft);
    },
    observeGameLog: function () {
        $('#gameLog').find('input').click();
    },
    praiseSun: function () {
        var currentTab = game.activeTabId;
        var faith = this.craftManager.getResource('faith');

        if (faith.value / faith.maxValue >= options.limit.faith) {
            game.activeTabId = 'Religion';
            game.render();

            message('The sun has been praised!');
            $(".nosel:contains('Praise the sun!')").click();

            game.activeTabId = currentTab;
            game.render();
        }
    },
    sendHunters: function () {
        var catpower = this.craftManager.getResource('manpower');
        var workshop = game.workshop;
        var parchment = workshop.getCraft('parchment');

        if (catpower.value / catpower.maxValue > options.limit.hunt) {
            if (parchment.unlocked) {
                game.craftAll(parchment.name);
                message('Auto Hunt: crafted all parchments');
            }

            if (options.toggle.luxury) this.startCrafts('luxury', options.auto.luxury);

            message('Kittens Hunt: Hunters deployed!');
            $("a:contains('Send hunters')").click();
        }
    },
    startBuilds: function (type, builds) {
        var buildManager = this.buildManager;
        var craftManager = this.craftManager;
        var limit = options.limit[type];

        for (i in builds) {
            var build = builds[i];
            var require = !build.require ? !build.require : craftManager.getResource(build.require);

            if (require === true || limit <= require.value / require.maxValue) {
                buildManager.build(build.name);
            }
        }
    },
    startCrafts: function (type, crafts) {
        var limit = options.limit[type];
        var manager = this.craftManager;

        for (i in crafts) {
            var craft = crafts[i];
            var require = manager.getResource(craft.require);

            if (limit <= require.value / require.maxValue) {
                manager.craft(craft.name, manager.getLowestCraftAmount(craft.name));
            }
        }
    }
};

// Building manager
// ================

var BuildManager = function () {
    this.craftManager = new CraftManager();
};

BuildManager.prototype = {
    craftManager: undefined,
    build: function (name) {
        if (!this.isBuildable(name)) return;

        var label = this.getBuild(name).label;
        var button = $(".nosel:not('.disabled'):contains('" + label + "')");

        if (button.length === 0) return;

        button.click();
        message('Kittens Build: +1 ' + label);
    },
    isBuildable: function (name) {
        var buildable = this.getBuild(name).unlocked;

        if (buildable) {
            var manager = this.craftManager;
            var prices = this.getPrices(name);

            for (i in prices) {
                var price = prices[i];

                if (manager.getValueAvailable(price.name) < price.val) {
                    buildable = false;
                }
            }
        }

        return buildable;
    },
    getBuild: function (name) {
        return game.bld.getBuilding(name);
    },
    getPrices: function (name) {
        return game.bld.getPrices(name);
    }
};

// Crafting Manager
// ================

var CraftManager = function () {};

CraftManager.prototype = {
    craft: function (name, amount) {
        amount = Math.floor(amount);

        if (undefined === name || 1 > amount) return;
        if (!this.canCraft(name, amount)) return;

        var craft = this.getCraft(name);
        var ratio = ('wood' === name) ? 'refineRatio' : 'craftRatio';

        game.craft(craft.name, amount);

        // determine actual amount after crafting upgrades
        amount = (amount * (game.bld.getEffect(ratio) + 1)).toFixed(2);

        message('Kittens Craft: +' + amount + ' ' + name);
    },
    canCraft: function (name, amount) {
        var craft = this.getCraft(name);
        var result = false;

        if (craft.unlocked) {
            result = true;

            for (i in craft.prices) {
                var price = craft.prices[i];
                var value = this.getValueAvailable(price.name);

                if (value < price.val * amount) {
                    result = false;
                }
            }
        }

        return result;
    },
    getCraft: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.workshop.getCraft(name);
    },
    getLowestCraftAmount: function (name) {
        var amount = 0;
        var consume = options.amount.consume;
        var materials = this.getMaterials(name);

        for (i in materials) {
            var total = this.getValueAvailable(i) * consume / materials[i];

            amount = (0 === amount || total < amount) ? total : amount;
        }

        return amount;
    },
    getMaterials: function (name) {
        var materials = {};
        var prices = this.getCraft(name).prices;

        for (i in prices) {
            var price = prices[i];

            materials[price.name] = price.val;
        }

        return materials;
    },
    getResource: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.resPool.get(name);
    },
    getValue: function (name) {
        return this.getResource(name).value;
    },
    getValueAvailable: function (name) {
        var value = this.getValue(name);
        var stock = options.stock[name] || 0;

        if ('catnip' === name) {
            var resPerTick = game.getResourcePerTick(name, false, {
                modifiers: {
                    'catnip': 0.10 - game.calendar.getWeatherMod()
                }});

            if (resPerTick < 0) stock -= resPerTick * 202 * 5;
        }

        return value - stock;
    }
};

// ==============================
// Configure overall page display
// ==============================

var container = $('#game');
var column = $('.column');

container.css({
    fontFamily: 'Courier New',
    fontSize: '12px',
    minWidth: '1300px',
    top: '32px'
});

column.css({
    minHeight: 'inherit',
    maxWidth: 'inherit',
    padding: '1%',
    margin: 0
});

var left = $('#leftColumn');
var middle = $('#midColumn');
var right = $('#rightColumn');

left.css({
    height: '92%',
    width: '26%'
});

middle.css({
    marginTop: '1%',
    height: '92%',
    width: '48%'
});

right.css({
    height: '92%',
    width: '19%'
});

// Reconfigure dynamic page display
// ================================

var addRule = function (rule) {
    var sheets = document.styleSheets;
    sheets[0].insertRule(rule, 1);
};

addRule('#gameLog .msg {'
+ 'display: block;'
+ '}');

addRule('#resContainer .maxRes {'
+ 'color: #676766;'
+ '}');

addRule('#game .btn {'
+ 'border-radius: 0px;'
+ 'font-family: "Courier New";'
+ 'font-size: "10px";'
+ 'margin: 0 0 7px 0;'
+ '}');

addRule('#ks-options ul {'
+ 'list-style: none;'
+ 'margin: 0 0 5px;'
+ 'padding: 0;'
+ '}');

addRule('#ks-options ul:after {'
+ 'clear: both;'
+ 'content: " ";'
+ 'display: block;'
+ 'height: 0;'
+ '}');

addRule('#ks-options ul li {'
+ 'display: block;'
+ 'float: left;'
+ 'width: 50%;'
+ '}');

// Add options element
// ===================

var getToggle = function (name, text) {
    var li = $('<li/>');

    var label = $('<label/>', {
        'for': 'toggle-' + name,
        text: text
    });

    var toggle = $('<input/>', {
        id: 'toggle-' + name,
        type: 'checkbox',
        checked: 'checked'
    });

    return li.append(toggle, label);
};

var optionsElement = $('<div/>', {id: 'ks-options', css: {marginBottom: '10px'}});
var optionsListElement = $('<ul/>');
var optionsTitleElement = $('<div/>', {
    css: { borderBottom: '1px solid gray', marginBottom: '5px' },
    text: version
});

optionsElement.append(optionsTitleElement);

optionsListElement.append(getToggle('engine', 'Engine').css('width', '100%'));
optionsListElement.append(getToggle('crafting', 'Crafting'));
optionsListElement.append(getToggle('housing', 'Housing'));
optionsListElement.append(getToggle('building', 'Building'));
optionsListElement.append(getToggle('praising', 'Faith'));
optionsListElement.append(getToggle('hunting', 'Hunting'));
optionsListElement.append(getToggle('luxury', 'Luxury'));

// add the options above the game log
right.prepend(optionsElement.append(optionsListElement));

// Initialize and set toggles for Engine
// =====================================

var engine = new Engine();
var toggleEngine = $('#toggle-engine');

toggleEngine.on('change', function () {
    if (toggleEngine.is(':checked')) {
        engine.start();
    } else {
        engine.stop();
    }
});

toggleEngine.trigger('change');

// Add toggles for options
// =======================

var autoOptions = ['building', 'crafting', 'housing', 'hunting', 'luxury', 'praising'];

var ucfirst = function (string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
};

$.each(autoOptions, function (event, option) {
    var toggle = $('#toggle-' + option);

    toggle.on('change', function () {
        if (toggle.is(':checked')) {
            options.toggle[option] = true;
            message('Enabled Auto ' + ucfirst(option));
        } else {
            options.toggle[option] = false;
            message('Disable Auto ' + ucfirst(option));
        }
    });
});
<commit_msg>buildings: specify resource for unicornPasture<commit_after>// ==========================================
// Begin Kitten Scientist's Automation Engine
// ==========================================

var version = 'Kitten Scientists version 1.1.5';
var game = gamePage;

var options = {
    interval: 3000,
    color: '#aa50fe', // dark purple
    amount: {
        consume: 0.5
    },
    auto: {
        build: [
            {name: 'field', require: 'catnip'},
            {name: 'pasture', require: 'catnip'},
            {name: 'mine', require: 'wood'},
            {name: 'library', require: 'wood'},
            {name: 'academy', require: 'wood'},
            {name: 'barn', require: 'wood'},
            {name: 'workshop', require: 'minerals'},
            {name: 'lumberMill', require: 'minerals'},
            {name: 'aqueduct', require: 'minerals'},
            {name: 'unicornPasture', require: 'unicorns'},
            {name: 'tradepost', require: 'gold'}
        ],
        craft: [
            {name: 'wood', require: 'catnip'},
            {name: 'beam', require: 'wood'},
            {name: 'slab', require: 'minerals'},
            {name: 'steel', require: 'coal'},
            {name: 'plate', require: 'iron'}
        ],
        house: [
            {name: 'hut', require: 'wood'},
            {name: 'logHouse', require: 'minerals'},
            {name: 'mansion', require: 'titanium'}
        ],
        luxury: [
            {name: 'manuscript', require: 'culture'},
            {name: 'compendium', require: 'science'}
        ]
    },
    limit: {
        build: 0.75,
        craft: 0.95,
        house: 0.85,
        hunt: 0.95,
        luxury: 0.99,
        faith: 0.99
    },
    stock: {
        compendium: 500,
        manuscript: 500,
        parchment: 500
    },
    toggle: {
        building: true,
        crafting: true,
        housing: true,
        hunting: true,
        luxury: true,
        praising: true
    }
};

// GameLog Modification
// ====================

var gameLog = com.nuclearunicorn.game.log.Console().static;

var message = function () {
    var args = Array.prototype.slice.call(arguments);
    args[1] = args[1] || 'ks-default';

    // update the color of the message immediately after adding
    gameLog.msg.apply(gameLog, args);
    $('.type_' + args[1]).css('color', options.color);
};

// Core Engine for Kitten Scientists
// =================================

var Engine = function () {
    this.buildManager = new BuildManager();
    this.craftManager = new CraftManager();
};

Engine.prototype = {
    buildManager: undefined,
    craftManager: undefined,
    loop: undefined,
    start: function () {
        if (this.loop) return;

        this.loop = setInterval(this.iterate.bind(this), options.interval);
        message('Starting the kitten scientists!');
    },
    stop: function () {
        if (!this.loop) return;

        clearInterval(this.loop);
        this.loop = undefined;
        message('Freezing the kitten scientists!');
    },
    iterate: function () {
        this.observeGameLog();
        if (options.toggle.praising) this.praiseSun();
        if (options.toggle.hunting) this.sendHunters();
        if (options.toggle.building) this.startBuilds('build', options.auto.build);
        if (options.toggle.housing) this.startBuilds('house', options.auto.house);
        if (options.toggle.crafting) this.startCrafts('craft', options.auto.craft);
    },
    observeGameLog: function () {
        $('#gameLog').find('input').click();
    },
    praiseSun: function () {
        var currentTab = game.activeTabId;
        var faith = this.craftManager.getResource('faith');

        if (faith.value / faith.maxValue >= options.limit.faith) {
            game.activeTabId = 'Religion';
            game.render();

            message('The sun has been praised!');
            $(".nosel:contains('Praise the sun!')").click();

            game.activeTabId = currentTab;
            game.render();
        }
    },
    sendHunters: function () {
        var catpower = this.craftManager.getResource('manpower');
        var workshop = game.workshop;
        var parchment = workshop.getCraft('parchment');

        if (catpower.value / catpower.maxValue > options.limit.hunt) {
            if (parchment.unlocked) {
                game.craftAll(parchment.name);
                message('Auto Hunt: crafted all parchments');
            }

            if (options.toggle.luxury) this.startCrafts('luxury', options.auto.luxury);

            message('Kittens Hunt: Hunters deployed!');
            $("a:contains('Send hunters')").click();
        }
    },
    startBuilds: function (type, builds) {
        var buildManager = this.buildManager;
        var craftManager = this.craftManager;
        var limit = options.limit[type];

        for (i in builds) {
            var build = builds[i];
            var require = !build.require ? !build.require : craftManager.getResource(build.require);

            if (require === true || limit <= require.value / require.maxValue) {
                buildManager.build(build.name);
            }
        }
    },
    startCrafts: function (type, crafts) {
        var limit = options.limit[type];
        var manager = this.craftManager;

        for (i in crafts) {
            var craft = crafts[i];
            var require = manager.getResource(craft.require);

            if (limit <= require.value / require.maxValue) {
                manager.craft(craft.name, manager.getLowestCraftAmount(craft.name));
            }
        }
    }
};

// Building manager
// ================

var BuildManager = function () {
    this.craftManager = new CraftManager();
};

BuildManager.prototype = {
    craftManager: undefined,
    build: function (name) {
        if (!this.isBuildable(name)) return;

        var label = this.getBuild(name).label;
        var button = $(".nosel:not('.disabled'):contains('" + label + "')");

        if (button.length === 0) return;

        button.click();
        message('Kittens Build: +1 ' + label);
    },
    isBuildable: function (name) {
        var buildable = this.getBuild(name).unlocked;

        if (buildable) {
            var manager = this.craftManager;
            var prices = this.getPrices(name);

            for (i in prices) {
                var price = prices[i];

                if (manager.getValueAvailable(price.name) < price.val) {
                    buildable = false;
                }
            }
        }

        return buildable;
    },
    getBuild: function (name) {
        return game.bld.getBuilding(name);
    },
    getPrices: function (name) {
        return game.bld.getPrices(name);
    }
};

// Crafting Manager
// ================

var CraftManager = function () {};

CraftManager.prototype = {
    craft: function (name, amount) {
        amount = Math.floor(amount);

        if (undefined === name || 1 > amount) return;
        if (!this.canCraft(name, amount)) return;

        var craft = this.getCraft(name);
        var ratio = ('wood' === name) ? 'refineRatio' : 'craftRatio';

        game.craft(craft.name, amount);

        // determine actual amount after crafting upgrades
        amount = (amount * (game.bld.getEffect(ratio) + 1)).toFixed(2);

        message('Kittens Craft: +' + amount + ' ' + name);
    },
    canCraft: function (name, amount) {
        var craft = this.getCraft(name);
        var result = false;

        if (craft.unlocked) {
            result = true;

            for (i in craft.prices) {
                var price = craft.prices[i];
                var value = this.getValueAvailable(price.name);

                if (value < price.val * amount) {
                    result = false;
                }
            }
        }

        return result;
    },
    getCraft: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.workshop.getCraft(name);
    },
    getLowestCraftAmount: function (name) {
        var amount = 0;
        var consume = options.amount.consume;
        var materials = this.getMaterials(name);

        for (i in materials) {
            var total = this.getValueAvailable(i) * consume / materials[i];

            amount = (0 === amount || total < amount) ? total : amount;
        }

        return amount;
    },
    getMaterials: function (name) {
        var materials = {};
        var prices = this.getCraft(name).prices;

        for (i in prices) {
            var price = prices[i];

            materials[price.name] = price.val;
        }

        return materials;
    },
    getResource: function (name) {
        // adjust for spelling bug in core game logic
        if ('compendium' === name) name = 'compedium';

        return game.resPool.get(name);
    },
    getValue: function (name) {
        return this.getResource(name).value;
    },
    getValueAvailable: function (name) {
        var value = this.getValue(name);
        var stock = options.stock[name] || 0;

        if ('catnip' === name) {
            var resPerTick = game.getResourcePerTick(name, false, {
                modifiers: {
                    'catnip': 0.10 - game.calendar.getWeatherMod()
                }});

            if (resPerTick < 0) stock -= resPerTick * 202 * 5;
        }

        return value - stock;
    }
};

// ==============================
// Configure overall page display
// ==============================

var container = $('#game');
var column = $('.column');

container.css({
    fontFamily: 'Courier New',
    fontSize: '12px',
    minWidth: '1300px',
    top: '32px'
});

column.css({
    minHeight: 'inherit',
    maxWidth: 'inherit',
    padding: '1%',
    margin: 0
});

var left = $('#leftColumn');
var middle = $('#midColumn');
var right = $('#rightColumn');

left.css({
    height: '92%',
    width: '26%'
});

middle.css({
    marginTop: '1%',
    height: '92%',
    width: '48%'
});

right.css({
    height: '92%',
    width: '19%'
});

// Reconfigure dynamic page display
// ================================

var addRule = function (rule) {
    var sheets = document.styleSheets;
    sheets[0].insertRule(rule, 1);
};

addRule('#gameLog .msg {'
+ 'display: block;'
+ '}');

addRule('#resContainer .maxRes {'
+ 'color: #676766;'
+ '}');

addRule('#game .btn {'
+ 'border-radius: 0px;'
+ 'font-family: "Courier New";'
+ 'font-size: "10px";'
+ 'margin: 0 0 7px 0;'
+ '}');

addRule('#ks-options ul {'
+ 'list-style: none;'
+ 'margin: 0 0 5px;'
+ 'padding: 0;'
+ '}');

addRule('#ks-options ul:after {'
+ 'clear: both;'
+ 'content: " ";'
+ 'display: block;'
+ 'height: 0;'
+ '}');

addRule('#ks-options ul li {'
+ 'display: block;'
+ 'float: left;'
+ 'width: 50%;'
+ '}');

// Add options element
// ===================

var getToggle = function (name, text) {
    var li = $('<li/>');

    var label = $('<label/>', {
        'for': 'toggle-' + name,
        text: text
    });

    var toggle = $('<input/>', {
        id: 'toggle-' + name,
        type: 'checkbox',
        checked: 'checked'
    });

    return li.append(toggle, label);
};

var optionsElement = $('<div/>', {id: 'ks-options', css: {marginBottom: '10px'}});
var optionsListElement = $('<ul/>');
var optionsTitleElement = $('<div/>', {
    css: { borderBottom: '1px solid gray', marginBottom: '5px' },
    text: version
});

optionsElement.append(optionsTitleElement);

optionsListElement.append(getToggle('engine', 'Engine').css('width', '100%'));
optionsListElement.append(getToggle('crafting', 'Crafting'));
optionsListElement.append(getToggle('housing', 'Housing'));
optionsListElement.append(getToggle('building', 'Building'));
optionsListElement.append(getToggle('praising', 'Faith'));
optionsListElement.append(getToggle('hunting', 'Hunting'));
optionsListElement.append(getToggle('luxury', 'Luxury'));

// add the options above the game log
right.prepend(optionsElement.append(optionsListElement));

// Initialize and set toggles for Engine
// =====================================

var engine = new Engine();
var toggleEngine = $('#toggle-engine');

toggleEngine.on('change', function () {
    if (toggleEngine.is(':checked')) {
        engine.start();
    } else {
        engine.stop();
    }
});

toggleEngine.trigger('change');

// Add toggles for options
// =======================

var autoOptions = ['building', 'crafting', 'housing', 'hunting', 'luxury', 'praising'];

var ucfirst = function (string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
};

$.each(autoOptions, function (event, option) {
    var toggle = $('#toggle-' + option);

    toggle.on('change', function () {
        if (toggle.is(':checked')) {
            options.toggle[option] = true;
            message('Enabled Auto ' + ucfirst(option));
        } else {
            options.toggle[option] = false;
            message('Disable Auto ' + ucfirst(option));
        }
    });
});
<|endoftext|>


<commit_before>var asn_cnt   = null;
var asn_uuid  = null;
var tst_cnt   = null;
var tst_uuid  = null;
var fle_uuids = null;
var sub_uuid  = null;
var run_uuid  = null;
var timeout = null;
var ladda_submit = null;

function add_option_alpha(select, option) {
    var inserted = false;
    select.children("option").each(function() {
	if (option.text() < this.text) {
	    console.log("Inserting " + option.text());
	    option.insertBefore(this);
	    inserted = true;
	    return false;
        }
    });
    if ( inserted == false ) {
	console.log("Appending " + option.text());
	select.append(option);
	inserted = true;
    }
}

function submit_onload() {
    ladda_submit = Ladda.create(document.querySelector("button#submit"));
    assignments_get_submitable(update_asn_list, setup_error_callback);
}

function update_asn_list(data, status) {
    $("select#assignment").empty();
    var assignments = data.assignments;
    asn_cnt = assignments.length;
    console.log("assignments = " + assignments);
    console.log("asn_cnt = " + asn_cnt);
    if(asn_cnt > 0) {
        $.each(assignments, function(key, value) {
            var uuid = value;
            assignment_get(update_asn_list_item, setup_error_callback, uuid);
        });
    }
    else {
	var option = $("<option>", { value : ""}).text("No Assignments Accepting Submissions");
        $("select#assignment").append(option);
        $("select#assignment").prop("disabled", true);
    }
}

function update_asn_list_item(data, status) {
    var keys = Object.keys(data);
    var uuid = keys[0];
    var assignment = data[uuid];
    var option = $("<option>", { value : uuid}).text(assignment.name);
    var select = $("select#assignment");
    add_option_alpha(select, option);
    if ($("select#assignment option").size() == asn_cnt) {
	$("select#assignment").val($("select#assignment option:last").val());
        $("select#assignment").change();
        $("select#assignment").prop("disabled", false);
    }
}

function update_tst_list(data, status) {
    $("select#test").empty();
    var tests = data.tests;
    tst_cnt = tests.length;
    console.log("tests = " + tests);
    console.log("tst_cnt = " + tst_cnt);
    if(tst_cnt > 0) {
        $.each(tests, function(key, value) {
            var uuid = value;
            test_get(update_tst_list_item, setup_error_callback, uuid);
        });
    }
    else {
	var option = $("<option>", { value : ""}).text("No Tests Accepting Submissions");
        $("select#test").append(option);
        $("select#test").prop("disabled", true);
        $("input#file").prop("disabled", true);
        $("button#submit").prop("disabled", true);
    }
    clear_results()
}

function update_tst_list_item(data, status) {
    var keys = Object.keys(data);
    var uuid = keys[0];
    var test = data[uuid];
    var option = $("<option>", { value : uuid}).text(test.name);
    var select = $("select#test");
    add_option_alpha(select, option);
    if ($("select#test option").size() == tst_cnt) {
	$("select#test").val($("select#test option:last").val());
        $("select#test").change();
        $("select#test").prop("disabled", false);
        $("input#file").prop("disabled", false);
        $("button#submit").prop("disabled", false);
    }
}

// Submission Sequence

function upload_fle_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Save Files UUIDs
    fle_uuids = data.files;

    // Create Submission
    console.log("Creating Submission...");
    assignment_submission_create(create_sub_callback, submit_error_callback, asn_uuid);

}

function create_sub_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Save Submission UUID
    sub_uuid = data.submissions[0];

    // Add Files to Submission
    var file_lst = fle_uuids;
    console.log("Adding Files...");
    submission_add_files(add_files_callback, submit_error_callback, sub_uuid, file_lst);

}

function add_files_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Check Files
    console.log("Added files: " + data.files);

    // Launch Test Run
    console.log("Starting Test Run...");
    submission_run_test(run_test_callback, submit_error_callback, sub_uuid, tst_uuid);

}

function run_test_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Save Run UUID
    run_uuid = data.runs[0];

    // Log to Console
    console.log("asn_uuid  = " + asn_uuid);
    console.log("tst_uuid  = " + tst_uuid);
    console.log("fle_uuids = " + fle_uuids);
    console.log("sub_uuid  = " + sub_uuid);
    console.log("run_uuid  = " + run_uuid);

    // Output UUID
    $("span#run_uuid").text(run_uuid);

    // Check Results
    poll_results_callback()

}

function poll_results_callback() {

    // Update Results
    console.log("Getting Run Results...");
    run_get(check_result_callback, submit_error_callback, run_uuid);

}

function check_result_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Extract Results
    var keys = Object.keys(data);
    var uuid = keys[0];
    var run = data[uuid];

    // Update Status
    $("span#run_status").text(run.status);

    if(run.status.indexOf("complete") == 0) {

        // Output Results
        $("span#run_score").text(run.score);
        $("span#run_retcode").text(run.retcode);
        $("pre#run_output").text(run.output);

        // Unlock Form
        $("select#assignment").prop("disabled", false);
        $("select#test").prop("disabled", false);
        $("input#file").prop("disabled", false);
	    ladda_submit.stop();
        $("button#submit").children("span.ladda-label").html("Submit");

    }
    else {

        // Start Polling
        console.log("Waiting...");
        timeout = setTimeout(poll_results_callback, 1000);

    }

}

function update_max_score(data, status) {

    var keys = Object.keys(data);
    var uuid = keys[0];
    var tst = data[uuid];
    $("span#max_score").text(tst.maxscore);

}

function submit_error_callback(xhr, status, error) {

    // Log Error
    console.log("Status: " + status, ", Error: " + error);

    // Update Status
    $("span#run_status").text("API Error: " + error);

    // Output Results
    $("span#run_score").text("N/A");
    $("span#run_retcode").text("N/A");
    $("pre#run_output").text(xhr.responseText);

    // Unlock Form
    $("select#assignment").prop("disabled", false);
    $("select#test").prop("disabled", false);
    $("input#file").prop("disabled", false);
	ladda_submit.stop();
    $("button#submit").children("span.ladda-label").html("Submit");

}

function setup_error_callback(xhr, status, error) {

    // Log Error
    console.log("Status: " + status, ", Error: " + error);

    // Update Status
    $("span#run_status").text("API Error: " + error);

    // Output Results
    $("span#run_score").text("N/A");
    $("span#run_retcode").text("N/A");
    $("pre#run_output").text(xhr.responseText);

}

function clear_results() {
    $("span#run_status").text("TBD");
    $("span#run_score").text("TBD");
    $("span#run_retcode").text("TBD");
    $("span#run_uuid").text("TBD");
    $("pre#run_output").text("Grading output will appear here...");
}

$("select#assignment").change(function() {
    var uuid = $("select#assignment").val();
    console.log("Assignment changed to " + uuid)
    if(uuid.length > 0) {
        assignment_tests_get(update_tst_list, setup_error_callback, uuid);
    }
});

$("select#test").change(function() {
    var uuid = $("select#test").val();
    console.log("Test changed to " + uuid)
    if(uuid.length > 0) {
        test_get(update_max_score, setup_error_callback, uuid);
    }
});

$("form#submitform").submit(function() {

    // Start Button Animation
    ladda_submit.start();
    $("button#submit").children("span.ladda-label").html("Running...");

    // Get Input
    asn_uuid = $("select#assignment").val();
    tst_uuid = $("select#test").val();

    // Validate Data
    if((!asn_uuid) || (asn_uuid.length != 36)) {
        console.log("Valid Assignment UUID Required");
        $("button#submit").prop("disabled", false);
        return false;
    }
    if((!tst_uuid) || (tst_uuid.length != 36)) {
        console.log("Valid Test UUID Required");
        $("button#submit").prop("disabled", false);
        return false;
    }
    if($("input#file").val().length == 0) {
        console.log("Valid File Required");
        $("button#submit").prop("disabled", false);
        return false;
    }

    // Upload File
    var file_name = $("input#file").val();
    console.log("File Name = " + file_name);
    var file_ext = file_name.split('.').pop();
    console.log("File Extension = " + file_ext);
    if(file_ext == "zip") {
        $("input#file").attr('name', 'extract')
    }
    else {
        $("input#file").attr('name', 'submission')
    }
    var form_data = new FormData($('form#submitform')[0]);
    console.log("Submitting File...");
    file_post(upload_fle_callback, submit_error_callback, form_data);

    // Lock Form
    $("select#assignment").prop("disabled", true);
    $("select#test").prop("disabled", true);
    $("input#file").prop("disabled", true);

    // Return
    return false

});
<commit_msg>Refactoring and cleanup<commit_after>var asn_cnt      = null;
var asn_uuid     = null;
var tst_cnt      = null;
var tst_uuid     = null;
var fle_uuids    = null;
var sub_uuid     = null;
var run_uuid     = null;
var timeout      = null;
var ladda_submit = null;

function add_option_alpha(select, option) {
    var inserted = false;
    select.children("option").each(function() {
	    if (option.text() < this.text) {
	        console.log("Inserting " + option.text());
	        option.insertBefore(this);
	        inserted = true;
	        return false;
        }
    });
    if ( inserted == false ) {
	    console.log("Appending " + option.text());
	    select.append(option);
	    inserted = true;
    }
}

function submit_onload() {
    ladda_submit = Ladda.create(document.querySelector("button#submit"));
    assignments_get_submitable(update_asn_list, setup_error_callback);
}

function update_asn_list(data, status) {
    var assignments = data.assignments;
    var select = $("select#assignment");
    select.empty();
    asn_cnt = assignments.length;
    console.log("asn_cnt = " + asn_cnt);
    console.log("assignments = " + assignments);
    if(asn_cnt > 0) {
        $.each(assignments, function(key, uuid) {
            assignment_get(update_asn_list_item, setup_error_callback, uuid);
        });
    }
    else {
	    var option = $("<option>", { value : ""}).text("No Assignments Accepting Submissions");
        select.append(option);
        select.prop("disabled", true);
    }
}

function update_asn_list_item(data, status) {
    var keys = Object.keys(data);
    var uuid = keys[0];
    var assignment = data[uuid];
    var select = $("select#assignment");
    var option = $("<option>", { value : uuid}).text(assignment.name);
    add_option_alpha(select, option);
    if ( select.children("option").size() == asn_cnt ) {
	    select.val(select.children("option:last").val());
        select.change();
        select.prop("disabled", false);
    }
}

function update_tst_list(data, status) {
    var tests = data.tests;
    var select = $("select#test");
    select.empty();
    tst_cnt = tests.length;
    console.log("tst_cnt = " + tst_cnt);
    console.log("tests = " + tests);
    if(tst_cnt > 0) {
        $.each(tests, function(key, uuid) {
            test_get(update_tst_list_item, setup_error_callback, uuid);
        });
    }
    else {
	    var option = $("<option>", { value : ""}).text("No Tests Accepting Submissions");
        select.append(option);
        select.prop("disabled", true);
        $("input#file").prop("disabled", true);
        $("button#submit").prop("disabled", true);
    }
    clear_results()
}

function update_tst_list_item(data, status) {
    var keys = Object.keys(data);
    var uuid = keys[0];
    var test = data[uuid];
    var select = $("select#test");
    var option = $("<option>", { value : uuid}).text(test.name);
    add_option_alpha(select, option);
    if (select.children("option").size() == tst_cnt) {
	    select.val(select.children("option:last").val());
        select.change();
        select.prop("disabled", false);
        $("input#file").prop("disabled", false);
        $("button#submit").prop("disabled", false);
    }
}

// Submission Sequence

function upload_fle_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Save Files UUIDs
    fle_uuids = data.files;

    // Create Submission
    console.log("Creating Submission...");
    assignment_submission_create(create_sub_callback, submit_error_callback, asn_uuid);

}

function create_sub_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Save Submission UUID
    sub_uuid = data.submissions[0];

    // Add Files to Submission
    var file_lst = fle_uuids;
    console.log("Adding Files...");
    submission_add_files(add_files_callback, submit_error_callback, sub_uuid, file_lst);

}

function add_files_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Check Files
    console.log("Added files: " + data.files);

    // Launch Test Run
    console.log("Starting Test Run...");
    submission_run_test(run_test_callback, submit_error_callback, sub_uuid, tst_uuid);

}

function run_test_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Save Run UUID
    run_uuid = data.runs[0];

    // Log to Console
    console.log("asn_uuid  = " + asn_uuid);
    console.log("tst_uuid  = " + tst_uuid);
    console.log("fle_uuids = " + fle_uuids);
    console.log("sub_uuid  = " + sub_uuid);
    console.log("run_uuid  = " + run_uuid);

    // Output UUID
    $("span#run_uuid").text(run_uuid);

    // Check Results
    poll_results_callback()

}

function poll_results_callback() {

    // Update Results
    console.log("Getting Run Results...");
    run_get(check_result_callback, submit_error_callback, run_uuid);

}

function check_result_callback(data, status) {

    // Log Data
    console.log("data = " + JSON.stringify(data));

    // Extract Results
    var keys = Object.keys(data);
    var uuid = keys[0];
    var run = data[uuid];

    // Update Status
    $("span#run_status").text(run.status);

    if(run.status.indexOf("complete") == 0) {

        // Output Results
        $("span#run_score").text(run.score);
        $("span#run_retcode").text(run.retcode);
        $("pre#run_output").text(run.output);

        // Unlock Form
        $("select#assignment").prop("disabled", false);
        $("select#test").prop("disabled", false);
        $("input#file").prop("disabled", false);
	    ladda_submit.stop();
        $("button#submit").children("span.ladda-label").html("Submit");

    }
    else {

        // Start Polling
        console.log("Waiting...");
        timeout = setTimeout(poll_results_callback, 1000);

    }

}

function update_max_score(data, status) {

    var keys = Object.keys(data);
    var uuid = keys[0];
    var tst = data[uuid];
    $("span#max_score").text(tst.maxscore);

}

function submit_error_callback(xhr, status, error) {

    // Log Error
    console.log("Status: " + status, ", Error: " + error);

    // Update Status
    $("span#run_status").text("API Error: " + error);

    // Output Results
    $("span#run_score").text("N/A");
    $("span#run_retcode").text("N/A");
    $("pre#run_output").text(xhr.responseText);

    // Unlock Form
    $("select#assignment").prop("disabled", false);
    $("select#test").prop("disabled", false);
    $("input#file").prop("disabled", false);
	ladda_submit.stop();
    $("button#submit").children("span.ladda-label").html("Submit");

}

function setup_error_callback(xhr, status, error) {

    // Log Error
    console.log("Status: " + status, ", Error: " + error);

    // Update Status
    $("span#run_status").text("API Error: " + error);

    // Output Results
    $("span#run_score").text("N/A");
    $("span#run_retcode").text("N/A");
    $("pre#run_output").text(xhr.responseText);

}

function clear_results() {
    $("span#run_status").text("TBD");
    $("span#run_score").text("TBD");
    $("span#run_retcode").text("TBD");
    $("span#run_uuid").text("TBD");
    $("pre#run_output").text("Grading output will appear here...");
}

$("select#assignment").change(function() {
    var uuid = $("select#assignment").val();
    console.log("Assignment changed to " + uuid)
    if(uuid.length > 0) {
        assignment_tests_get(update_tst_list, setup_error_callback, uuid);
    }
});

$("select#test").change(function() {
    var uuid = $("select#test").val();
    console.log("Test changed to " + uuid)
    if(uuid.length > 0) {
        test_get(update_max_score, setup_error_callback, uuid);
    }
});

$("form#submitform").submit(function() {

    // Start Button Animation
    ladda_submit.start();
    $("button#submit").children("span.ladda-label").html("Running...");

    // Get Input
    asn_uuid = $("select#assignment").val();
    tst_uuid = $("select#test").val();

    // Validate Data
    if((!asn_uuid) || (asn_uuid.length != 36)) {
        console.log("Valid Assignment UUID Required");
        $("button#submit").prop("disabled", false);
        return false;
    }
    if((!tst_uuid) || (tst_uuid.length != 36)) {
        console.log("Valid Test UUID Required");
        $("button#submit").prop("disabled", false);
        return false;
    }
    if($("input#file").val().length == 0) {
        console.log("Valid File Required");
        $("button#submit").prop("disabled", false);
        return false;
    }

    // Upload File
    var file_name = $("input#file").val();
    console.log("File Name = " + file_name);
    var file_ext = file_name.split('.').pop();
    console.log("File Extension = " + file_ext);
    if(file_ext == "zip") {
        $("input#file").attr('name', 'extract')
    }
    else {
        $("input#file").attr('name', 'submission')
    }
    var form_data = new FormData($('form#submitform')[0]);
    console.log("Submitting File...");
    file_post(upload_fle_callback, submit_error_callback, form_data);

    // Lock Form
    $("select#assignment").prop("disabled", true);
    $("select#test").prop("disabled", true);
    $("input#file").prop("disabled", true);

    // Return
    return false

});
<|endoftext|>


<commit_before>import Sequelize from 'sequelize';
import database from '../';
import User from './user';

const blogPostDatabaseDefinition = database.define('blog_post', {
  id: {
    type: Sequelize.INTEGER,
    autoIncrement: true,
    primaryKey: true,
    field: 'id',
    allowNull: false
  },
  title: {
    type: Sequelize.STRING,
    field: 'title',
    allowNull: false
  },
  link: {
    type: Sequelize.STRING,
    field: 'link',
    allowNull: false
  },
  imageURI: {
    type: Sequelize.STRING,
    field: 'image_uri',
    allowNull: true
  },
  description: {
    type: Sequelize.TEXT,
    field: 'description',
    allowNull: false
  },
  dateUpdated: {
    type: Sequelize.DATE,
    field: 'date_updated',
    allowNull: false
  },
  datePublished: {
    type: Sequelize.DATE,
    field: 'date_published',
    allowNull: false
  },
}, {
  underscored: true
});

blogPostDatabaseDefinition.belongsTo(User, { as: 'author' });

export default blogPostDatabaseDefinition;
<commit_msg>Added a constraint so that all posts in database must have an author.<commit_after>import Sequelize from 'sequelize';
import database from '../';
import User from './user';

const blogPostDatabaseDefinition = database.define('blog_post', {
  id: {
    type: Sequelize.INTEGER,
    autoIncrement: true,
    primaryKey: true,
    field: 'id',
    allowNull: false
  },
  title: {
    type: Sequelize.STRING,
    field: 'title',
    allowNull: false
  },
  link: {
    type: Sequelize.STRING,
    field: 'link',
    allowNull: false
  },
  imageURI: {
    type: Sequelize.STRING,
    field: 'image_uri',
    allowNull: true
  },
  description: {
    type: Sequelize.TEXT,
    field: 'description',
    allowNull: false
  },
  dateUpdated: {
    type: Sequelize.DATE,
    field: 'date_updated',
    allowNull: false
  },
  datePublished: {
    type: Sequelize.DATE,
    field: 'date_published',
    allowNull: false
  },
}, {
  underscored: true
});

blogPostDatabaseDefinition.belongsTo(User, { as: 'author', foreignKey: { name: 'author_id', allowNull: false } });

export default blogPostDatabaseDefinition;
<|endoftext|>