<commit_before>var http = require('http');
var fs = require('fs');
var readChunk = require('read-chunk');
var fileType = require("file-type");
var imageSize = require("image-size");
var config = require("./config");
var crypto = require("crypto");

// Schemas
var Account = require("./db/schemas/account").Account;
var Skin = require("./db/schemas/skin").Skin;
var Traffic = require("./db/schemas/traffic").Traffic;

module.exports = {}

module.exports.checkTraffic = function (req, res) {
    return new Promise(function (fullfill) {
        var ip = req.realAddress;
        console.log(("IP: " + ip).debug);

        module.exports.getGeneratorDelay().then(function (delay) {
            Traffic.findOne({ip: ip}, function (err, traffic) {
                if (err) return console.log(err);
                if (!traffic) {// First request
                    fullfill(true, delay);
                } else {
                    var time = Date.now() / 1000;

                    if ((traffic.lastRequest.getTime() / 1000) > time - delay) {
                        res.status(429).json({error: "Too many requests", nextRequest: time + delay + 10, delay: delay});
                        fullfill(false, delay);
                    } else {
                        fullfill(true, delay);
                    }

                }
            })
        })
    })
};

module.exports.validateImage = function (req, res, file) {
    var stats = fs.statSync(file);
    var size = stats.size;
    if (size <= 0 || size > 16000) {
        res.status(400).json({error: "Invalid file size (" + size + ")"});
        return false;
    }

    try {
        var dimensions = imageSize(file);
        console.log(("Dimensions: " + JSON.stringify(dimensions)).debug);
        if ((dimensions.width !== 64) || (dimensions.height !== 64 && dimensions.height !== 32)) {
            res.status(400).json({error: "Invalid skin dimensions. Must be 64x32 or 64x64. (Were " + dimensions.width + "x" + dimensions.height + ")"});
            return false;
        }
    } catch (e) {
        console.log(e)
        res.status(500).json({error: "Failed to get image dimensions", err: e});
        return;
    }

    var imageBuffer = readChunk.sync(file, 0, 4100);
    var type = fileType(imageBuffer);
    if (!type || type.ext !== "png" || type.mime !== "image/png") {
        res.status(400).json({error: "Invalid image type. Must be PNG. (Is " + type.ext + " / " + type.mime + ")"});
        return false;
    }

    return true;
}

module.exports.getGeneratorDelay = function () {
    return new Promise(function (fullfill, reject) {
        Account.count({enabled: true}, function (err, count) {
            if (err) return console.log(err);

            var delay = Math.round(60 / Math.max(1, count));
            fullfill(delay);
        })
    })
};

module.exports.skinToJson = function (skin, delay) {
    return {
        id: skin.id,
        name: skin.name,
        data: {
            uuid: skin.uuid,
            texture: {
                value: skin.value,
                signature: skin.signature,
                url: skin.url,
                urls:{
                    skin:skin.url,
                    cape:skin.capeUrl
                }
            }
        },
        timestamp: skin.time,
        duration: skin.generateDuration,
        accountId: skin.account,
        private: (skin.visibility !== 0),
        views: skin.views,
        nextRequest: delay || 0
    }
};

module.exports.crypto = require("./encryption");
<commit_msg>include model in response<commit_after>var http = require('http');
var fs = require('fs');
var readChunk = require('read-chunk');
var fileType = require("file-type");
var imageSize = require("image-size");
var config = require("./config");
var crypto = require("crypto");

// Schemas
var Account = require("./db/schemas/account").Account;
var Skin = require("./db/schemas/skin").Skin;
var Traffic = require("./db/schemas/traffic").Traffic;

module.exports = {}

module.exports.checkTraffic = function (req, res) {
    return new Promise(function (fullfill) {
        var ip = req.realAddress;
        console.log(("IP: " + ip).debug);

        module.exports.getGeneratorDelay().then(function (delay) {
            Traffic.findOne({ip: ip}, function (err, traffic) {
                if (err) return console.log(err);
                if (!traffic) {// First request
                    fullfill(true, delay);
                } else {
                    var time = Date.now() / 1000;

                    if ((traffic.lastRequest.getTime() / 1000) > time - delay) {
                        res.status(429).json({error: "Too many requests", nextRequest: time + delay + 10, delay: delay});
                        fullfill(false, delay);
                    } else {
                        fullfill(true, delay);
                    }

                }
            })
        })
    })
};

module.exports.validateImage = function (req, res, file) {
    var stats = fs.statSync(file);
    var size = stats.size;
    if (size <= 0 || size > 16000) {
        res.status(400).json({error: "Invalid file size (" + size + ")"});
        return false;
    }

    try {
        var dimensions = imageSize(file);
        console.log(("Dimensions: " + JSON.stringify(dimensions)).debug);
        if ((dimensions.width !== 64) || (dimensions.height !== 64 && dimensions.height !== 32)) {
            res.status(400).json({error: "Invalid skin dimensions. Must be 64x32 or 64x64. (Were " + dimensions.width + "x" + dimensions.height + ")"});
            return false;
        }
    } catch (e) {
        console.log(e)
        res.status(500).json({error: "Failed to get image dimensions", err: e});
        return;
    }

    var imageBuffer = readChunk.sync(file, 0, 4100);
    var type = fileType(imageBuffer);
    if (!type || type.ext !== "png" || type.mime !== "image/png") {
        res.status(400).json({error: "Invalid image type. Must be PNG. (Is " + type.ext + " / " + type.mime + ")"});
        return false;
    }

    return true;
}

module.exports.getGeneratorDelay = function () {
    return new Promise(function (fullfill, reject) {
        Account.count({enabled: true}, function (err, count) {
            if (err) return console.log(err);

            var delay = Math.round(60 / Math.max(1, count));
            fullfill(delay);
        })
    })
};

module.exports.skinToJson = function (skin, delay) {
    return {
        id: skin.id,
        name: skin.name,
        model: skin.model,
        data: {
            uuid: skin.uuid,
            texture: {
                value: skin.value,
                signature: skin.signature,
                url: skin.url,
                urls: {
                    skin: skin.url,
                    cape: skin.capeUrl
                }
            }
        },
        timestamp: skin.time,
        duration: skin.generateDuration,
        accountId: skin.account,
        private: (skin.visibility !== 0),
        views: skin.views,
        nextRequest: delay || 0
    }
};

module.exports.crypto = require("./encryption");
<|endoftext|>


<commit_before>/**
 * Sets application global configuration variables
 */

var vars = {
    app: {
        verbose: false,
        port: process.env.PORT || 3000,
        allowed_domains: ["*"]
    },
    es: {
        host: "127.0.0.1:9200",
        name: "geonames",
        collection: "cities",
        size: 30
    },
    mongo: {
        url: "geonames",
        countrynames: "countrynames",
        admincodes: "admincodes"
    },
    geo: {
        geolitepath: './resources/data/GeoLiteCity.dat',
        default_lon: 0,
        default_lat: 0
    }
};

// do not touch
module.exports = vars;
<commit_msg>Delete unused file<commit_after><|endoftext|>


<commit_before>// VVVV.js -- Visual Webclient Programming
// (c) 2011 Matthias Zauner
// VVVV.js is freely distributable under the MIT license.
// Additional authors of sub components are mentioned at the specific code locations.

/** @define {string} */
var VVVV_ENV = 'development';

// some prerequisites ...
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
  if ( options.dataType == 'script' || originalOptions.dataType == 'script' ) {
      options.cache = true;
  }
});

if(!window.console) {
  window.console = {
    log : function(str) {
    }
  };
}

// actual VVVV.js initialization code
VVVV = {};
VVVV.Config = {};
VVVV.Config.auto_undo = false;
VVVV.Nodes = {};
VVVV.PinTypes = {};
VVVV.NodeLibrary = {};
VVVV.NodeNames = [];
VVVV.Patches = {};

VVVV.onNotImplemented = function(nodename) {
  console.log("Warning: "+nodename+" is not implemented.");
};

VVVV.loadCounter = 0;
VVVV.loadScript = function(url, callback) {
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.async = false;
    script.src = VVVV.Root + '/' +url;
    if (callback)
      script.addEventListener('load', callback);
    VVVV.loadCounter++;
    head.appendChild(script);
};

/**
 * Adds the neccessary JavaScripts to the head, calls the callback once everything is in place.
 * @param {String} path_to_vvvv points to the folder of your vvvv.js. This is relative to your html-file
 * @param {String} mode. Can be either "full", "vvvviewer" or "run". Depends on what you want to do
 * @param {Function} callback will be called once all the scripts and initialisations have been finished.
 */
VVVV.init = function (path_to_vvvv, mode, callback) {
  VVVV.Root = path_to_vvvv || './';

  if (VVVV_ENV=='development') console.log('loading vvvv.js ...');

  if (VVVV_ENV=='development') {
    var head = document.getElementsByTagName('head')[0];

    function loadMonitor(event) {
      event.target.removeEventListener('load', loadMonitor);
      if (--VVVV.loadCounter <= 0) {
        initialisationComplete();
      };
    }

    if ($('script[src*=thirdparty]').length==0)
      VVVV.loadScript('thirdparty.js', loadMonitor);
    if ($('script[src*=underscore]').length==0)
      VVVV.loadScript('lib/underscore/underscore-min.js', loadMonitor);
    if ($('script[src*="d3.js"]').length==0 && (mode=='full' || mode=='vvvviewer'))
      VVVV.loadScript('lib/d3-v3/d3.v3.min.js', loadMonitor);
    if ($('script[src*=glMatrix]').length==0 && (mode=='full' || mode=='run'))
      VVVV.loadScript('lib/glMatrix-0.9.5.min.js', loadMonitor);

    if ($('script[src*="vvvv.core.js"]').length==0) {
      VVVV.loadScript('core/vvvv.core.js', loadMonitor);
      VVVV.loadScript('core/vvvv.core.vvvvconnector.js', loadMonitor);
      if (mode=='run' || mode=='full') {
        VVVV.loadScript('mainloop/vvvv.mainloop.js', loadMonitor);
        VVVV.loadScript('mainloop/vvvv.dominterface.js', loadMonitor);

        VVVV.loadScript('nodes/vvvv.nodes.value.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.string.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.boolean.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.color.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.spreads.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.spectral.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.animation.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.network.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.system.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.canvas.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.html5.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.transform.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.vectors.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.webgl.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.complex.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.enumerations.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.2d.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.3d.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.node.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.astronomy.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.xml.js', loadMonitor);
      }
      VVVV.loadScript('editors/vvvv.editors.browser_editor.js', loadMonitor);
    }
  }

  function initialisationComplete() {
    var p = new VVVV.Core.Patch('');
    _(VVVV.Nodes).each(function(n) {
      var x = new n(0, p);
      if (VVVV_ENV=='development') console.log("Registering "+x.nodename);
      VVVV.NodeLibrary[x.nodename.toLowerCase()] = n;
      VVVV.NodeNames.push(x.nodename);
    });

    if (VVVV_ENV=='development') console.log('done ...');

    VVVV.MainLoops = [];

    $("script[language='VVVV']").each(function(i) {
      var p = new VVVV.Core.Patch($(this).attr('src'), function() {
        var m = new VVVV.Core.MainLoop(this);
        VVVV.MainLoops.push(m);
      });
      VVVV.Patches[i] = p;
    });

    if (typeof callback === 'function') callback.call();
  }

  if (VVVV_ENV=='production')
    initialisationComplete();
};

<commit_msg>removes core/vvvv.core.vvvvconnector from list of include files<commit_after>// VVVV.js -- Visual Webclient Programming
// (c) 2011 Matthias Zauner
// VVVV.js is freely distributable under the MIT license.
// Additional authors of sub components are mentioned at the specific code locations.

/** @define {string} */
var VVVV_ENV = 'development';

// some prerequisites ...
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
  if ( options.dataType == 'script' || originalOptions.dataType == 'script' ) {
      options.cache = true;
  }
});

if(!window.console) {
  window.console = {
    log : function(str) {
    }
  };
}

// actual VVVV.js initialization code
VVVV = {};
VVVV.Config = {};
VVVV.Config.auto_undo = false;
VVVV.Nodes = {};
VVVV.PinTypes = {};
VVVV.NodeLibrary = {};
VVVV.NodeNames = [];
VVVV.Patches = {};
VVVV.Editors = {};

VVVV.onNotImplemented = function(nodename) {
  console.log("Warning: "+nodename+" is not implemented.");
};

VVVV.loadCounter = 0;
VVVV.loadScript = function(url, callback) {
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.async = false;
    script.src = VVVV.Root + '/' +url;
    if (callback)
      script.addEventListener('load', callback);
    VVVV.loadCounter++;
    head.appendChild(script);
};

/**
 * Adds the neccessary JavaScripts to the head, calls the callback once everything is in place.
 * @param {String} path_to_vvvv points to the folder of your vvvv.js. This is relative to your html-file
 * @param {String} mode. Can be either "full", "vvvviewer" or "run". Depends on what you want to do
 * @param {Function} callback will be called once all the scripts and initialisations have been finished.
 */
VVVV.init = function (path_to_vvvv, mode, callback) {
  VVVV.Root = path_to_vvvv || './';

  if (VVVV_ENV=='development') console.log('loading vvvv.js ...');

  if (VVVV_ENV=='development') {
    var head = document.getElementsByTagName('head')[0];

    function loadMonitor(event) {
      event.target.removeEventListener('load', loadMonitor);
      if (--VVVV.loadCounter <= 0) {
        initialisationComplete();
      };
    }

    if ($('script[src*=thirdparty]').length==0)
      VVVV.loadScript('thirdparty.js', loadMonitor);
    if ($('script[src*=underscore]').length==0)
      VVVV.loadScript('lib/underscore/underscore-min.js', loadMonitor);
    if ($('script[src*="d3.js"]').length==0 && (mode=='full' || mode=='vvvviewer'))
      VVVV.loadScript('lib/d3-v3/d3.v3.min.js', loadMonitor);
    if ($('script[src*=glMatrix]').length==0 && (mode=='full' || mode=='run'))
      VVVV.loadScript('lib/glMatrix-0.9.5.min.js', loadMonitor);

    if ($('script[src*="vvvv.core.js"]').length==0) {
      VVVV.loadScript('core/vvvv.core.js', loadMonitor);
      if (mode=='run' || mode=='full') {
        VVVV.loadScript('mainloop/vvvv.mainloop.js', loadMonitor);
        VVVV.loadScript('mainloop/vvvv.dominterface.js', loadMonitor);

        VVVV.loadScript('nodes/vvvv.nodes.value.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.string.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.boolean.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.color.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.spreads.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.spectral.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.animation.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.network.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.system.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.canvas.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.html5.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.transform.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.vectors.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.webgl.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.complex.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.enumerations.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.2d.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.3d.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.node.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.astronomy.js', loadMonitor);
        VVVV.loadScript('nodes/vvvv.nodes.xml.js', loadMonitor);
      }
      VVVV.loadScript('editors/vvvv.editors.browser_editor.js', loadMonitor);
    }
  }

  function initialisationComplete() {
    var p = new VVVV.Core.Patch('');
    _(VVVV.Nodes).each(function(n) {
      var x = new n(0, p);
      if (VVVV_ENV=='development') console.log("Registering "+x.nodename);
      VVVV.NodeLibrary[x.nodename.toLowerCase()] = n;
      VVVV.NodeNames.push(x.nodename);
    });

    if (VVVV_ENV=='development') console.log('done ...');

    VVVV.MainLoops = [];

    $("script[language='VVVV']").each(function(i) {
      var p = new VVVV.Core.Patch($(this).attr('src'), function() {
        var m = new VVVV.Core.MainLoop(this);
        VVVV.MainLoops.push(m);
      });
      VVVV.Patches[i] = p;
    });

    if (typeof callback === 'function') callback.call();
  }

  if (VVVV_ENV=='production')
    initialisationComplete();
};

<|endoftext|>


<commit_before>var map, currentLayer, attractionLayer;
var interval = 25;
var speeds = {
  realTime: {
    speed: 0.01,
    duration: 1180
  },
  slow: {
    speed: 1,
    duration: 110
  },
  normal: {
    speed: 2,
    duration: 55
  },
  fast: {
    speed: 6,
    duration: 19
  },
  superSpeed: {
    speed: 15,
    duration: 6
  }
};
var speed = speeds.normal.speed;

var distanceScale,
    durationScale,
    paceScale,
    startScale,
    endScale;

var colorings = {
  direction: {
    getStyle: function(feature) {
      var color = feature.properties.start === 'north' ? 'rgb(255, 51, 0)' : 'rgb(0, 51, 255)';
      return {
        color: color,
        opacity: 0.5
      };
    }
  },
  distance: {
    getStyle: function(feature) {
      var scale = distanceScale(feature.properties.distance);
      var colorNum = scale - (scale % 100);
      var color = palette.indigo[colorNum];
      return {
        color: color,
        opacity: 0.6
      };
    }
  },
  duration: {
    getStyle: function(feature) {
      var scale = durationScale(feature.properties.maxTick);
      var colorNum = scale - (scale % 100);
      var color = palette.red[colorNum];
      return {
        color: color,
        opacity: 0.6
      };
    }
  },
  pace: {
    getStyle: function(feature) {
      var scale = paceScale(feature.properties.pace);
      var colorNum = scale - (scale % 100);
      var color = palette.purple[colorNum];
      return {
        color: color,
        opacity: 0.6
      };
    }
  },
  start: {
    getStyle: function(feature) {
      var scale = feature.properties.start === 'north' ?
        startScale(feature.properties.startTick) :
        endScale(feature.properties.startTick);
      var colorNum = scale - (scale % 100);
      var color = feature.properties.start === 'north' ?
        palette.deepOrange[colorNum] : palette.blue[colorNum];
      return {
        color: color,
        opacity: 0.5
      };
    }
  }
};
var coloring = colorings.direction;

var tiles = {
  Mapbox: {
    url: 'https://{s}.tiles.mapbox.com/v3/sedenardi.kfmi8afc/{z}/{x}/{y}.png',
    attribution: 'Map data © OpenStreetMap contributors, ' +
      'CC-BY-SA, ' +
      'Imagery © Mapbox'
  },
  OpenStreetMap: {
    url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    attribution: 'Map data © OpenStreetMap contributors'
  },
  OpenMapSurferRoads: {
    url: 'http://openmapsurfer.uni-hd.de/tiles/roads/x={x}&y={y}&z={z}',
    attribution: 'Imagery from GIScience Research Group @ ' +
      'University of Heidelberg — Map data © ' +
      'OpenStreetMap'
  },
  HyddaFull: {
    url: 'http://{s}.tile.openstreetmap.se/hydda/full/{z}/{x}/{y}.png',
    attribution: 'Tiles courtesy of OpenStreetMap ' +
      'Sweden — Map data © OpenStreetMap'
  }
};
var tile = tiles.Mapbox;

var initMap = function() {
	var a = geoJson.lineStrings[0].features[0].geometry.coordinates;
	var first = a[0],
		last = a[a.length-1],
		lon = (first[0] + last[0])/2,
		lat = (first[1] + last[1])/2;

  var zoom = $('#map').height() < 680 ? 15 : 16;

	map = L.map('map').setView([lat, lon], zoom);
  L.tileLayer(tile.url, {
    maxZoom: 20,
    attribution: tile.attribution
  }).addTo(map);

  initScales();
  initControls();
  resetMap();
  showAttractions();
};1

var getPathsAtTick = function(tick) {
  var paths = [];
  for (var i = 0; i < geoJson.lineStrings.length; i++) {
    var endIndex = geoJson.lineStrings[i].features[0].properties.ticks.length;
    for (var j = 0; j < geoJson.lineStrings[i].features[0].properties.ticks.length; j++) {
      var theTick = geoJson.lineStrings[i].features[0].properties.ticks[j];
      if (tick < theTick) {
        endIndex = j;
        break;
      }
    }
    var path = {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          properties: {
            name: geoJson.lineStrings[i].features[0].properties.name,
            time: geoJson.lineStrings[i].features[0].properties.time,
            start: geoJson.lineStrings[i].features[0].properties.start,
            pathLength: geoJson.lineStrings[i].features[0].properties.pathLength,
            maxTick: geoJson.lineStrings[i].features[0].properties.maxTick,
            distance: geoJson.lineStrings[i].features[0].properties.distance,
            pace: geoJson.lineStrings[i].features[0].properties.pace,
            startTick: geoJson.lineStrings[i].features[0].properties.startTick
          },
          geometry: {
            type: 'LineString',
            coordinates: geoJson.lineStrings[i].features[0].geometry.coordinates.slice(0,(endIndex))
          }
        }
      ]
    };
    paths.push(path);
  }
  return paths;
};

var initScales = function() {
  distanceScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings, function(d) {
        return d.features[0].properties.distance;
    }),
      d3.max(geoJson.lineStrings, function(d) {
        return d.features[0].properties.distance;
    })])
    .rangeRound([100, 900]);

  durationScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings, function(d) {
        return d.features[0].properties.maxTick;
    }),
      d3.max(geoJson.lineStrings, function(d) {
        return d.features[0].properties.maxTick;
    })])
    .rangeRound([100, 900]);

  paceScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings, function(d) {
        return d.features[0].properties.pace;
    }),
      d3.max(geoJson.lineStrings, function(d) {
        return d.features[0].properties.pace;
    })])
    .rangeRound([100, 900]);

  startScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'north';
      }), function(d) {
        return d.features[0].properties.startTick;
    }),
      d3.max(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'north';
      }), function(d) {
        return d.features[0].properties.startTick;
    })])
    .rangeRound([300, 900]);

  endScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'south';
      }), function(d) {
        return d.features[0].properties.startTick;
    }),
      d3.max(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'south';
      }), function(d) {
        return d.features[0].properties.startTick;
    })])
    .rangeRound([300, 900]);
};

var currentTick = 0,
    playing = false,
    paused = false,
    startTime,
    endTime;
var mapTick = function() {
  playing = true;
  var lines = getPathsAtTick(currentTick);

  var nextLayer = L.geoJson(lines, {
    style: coloring.getStyle,
    onEachFeature: function(feature,layer) {
      layer.on({
        mouseover: function(e) {
          layer.setStyle({
            color: palette.grey[900],
            opacity: 1
          });
          if (!L.Browser.ie && !L.Browser.opera) {
            layer.bringToFront();
          }
          $('#start').html(moment(feature.properties.time).format('ddd MMM D h:mm A'));
          var minutes = Math.floor(feature.properties.maxTick/60);
          var seconds = feature.properties.maxTick % 60;
          var duration = minutes + ' minutes ' + seconds + ' seconds';
          var pMin = Math.floor(feature.properties.pace/60);
          var pSec = feature.properties.pace % 60;
          var pace = pMin + ' minutes ' + (pSec !== 0 ? (pSec + ' seconds') : '');

          $('#duration').html(duration);
          $('#distance').html(feature.properties.distance + ' mi');
          $('#pace').html(pace);

          var x = e.originalEvent.x + 5,
              y = e.originalEvent.y - 30;
          if (x + 245 > $(window).width()) x = x - 245;
          if (y + 95 > $(window).height()) y = $(window).height() - 95;
          $('#pathTooltip').css('left', x);
          $('#pathTooltip').css('top', y);
          $('#pathTooltip').show();

        },
        mouseout: function(e) {
          layer.setStyle(coloring.getStyle(feature));
          $('#pathTooltip').hide();
        }
      });
    }
  }).addTo(map);

  if (currentLayer) map.removeLayer(currentLayer);
  currentLayer = nextLayer;

  if (paused) {
    return;
  } else if (currentTick < geoJson.maxTick) {
    currentTick += speed;
    setTimeout(function() {
      mapTick();
    },interval);
  } else {
    playing = false;
    if (startTime) {
      endTime = new Date();
      console.log('Duration - ' + (endTime - startTime));
    }
    syncControlState();
  }
};

var resetMap = function() {
  playing = false;
  paused = false;
  currentTick = geoJson.maxTick;
  mapTick();
  syncControlState();
};

var syncControlState = function() {
  var $toggleIcon = $('.playbackControl[data-control="toggle"] > i');
  if (playing && !paused) {
    $toggleIcon.removeClass('fa-play').addClass('fa-pause');
  } else {
    $toggleIcon.removeClass('fa-pause').addClass('fa-play');
  }
};

var showAttractions = function() {
  attractionLayer = L.geoJson(attractions, {
    pointToLayer: function(feature, latlng) {
      var c = 'icon-custom icon-' + feature.properties.type;
      var icon = L.divIcon({
        className: c,
        iconSize: L.point(16, 16)
      });
      return L.marker(latlng, {icon: icon});
    },
    onEachFeature: function(feature,layer) {
      var title = '' +
        feature.properties.name + ' ';
      var popupTitle = '
' +
        title + '
';
      var popupDescription = '
' +
        feature.properties.description + '
';
      var popupContent = '
' +
        popupTitle + popupDescription + '
';
      var popupClass = feature.properties.name
        .toLowerCase()
        .replace(/ /g, '-')
        .replace(/'/g, '')
        .replace(/\./g, '')
        .replace(/[0-9]/g, '')
        .replace(/&/g, 'and');
      var popupContainer = '
' +
        popupContent + '
';
      layer.bindPopup(popupContainer);
    }
  }).addTo(map);
};

var initControls = function() {
  $('.aboutModal').click(function(e) {
    $('#aboutModal').modal('show');
    e.preventDefault();
  });

  $('.playbackControl').click(function(e) {
    var control = $(this).attr('data-control');
    if (control === 'toggle') {
      $toggleIcon = $(this).children('i');
      if (!paused) {
        if (playing) {
          paused = true;
        } else {
          startTime = new Date();
          currentTick = 0;
          mapTick();
        }
      } else {
        paused = false;
        mapTick();
      }
      syncControlState();
    } else if (control === 'stop') {
      resetMap();
    }
    e.preventDefault();
  });

  $('#speedControl').change(function() {
    speed = speeds[$(this).val()].speed;
  });

  $('#colorControl').change(function() {
    coloring = colorings[$(this).val()];
    if (!playing || paused)
      mapTick();
  });

  $('#attCheckbox').change(function() {
    if ($('#attCheckbox').is(':checked')) {
      showAttractions();
    } else if (attractionLayer) {
      map.removeLayer(attractionLayer);
    }
  });

  $('#attrToggle').click(function() {
    $('#attCheckbox').prop('checked', !$('#attCheckbox').is(':checked'))
      .change();
  });
};

var initWalk = function(cb) {
  $.ajax({
    url: 'coordinates.json',
    dataType: 'json',
    success: function(geoRes) {
      geoJson = geoRes;
      $.ajax({
        url: 'attractions.json',
        dataType: 'json',
        success: function(attRes) {
          attractions = attRes;
          cb();
        }
      });
    }
  });
};

initWalk(initMap);<commit_msg>handle path and attraction clicks<commit_after>var map,
    currentLayer,
    lastClickedPath,
    lastClickedAttraction,
    attractionLayer;
var interval = 25;
var speeds = {
  realTime: {
    speed: 0.01,
    duration: 1180
  },
  slow: {
    speed: 1,
    duration: 110
  },
  normal: {
    speed: 2,
    duration: 55
  },
  fast: {
    speed: 6,
    duration: 19
  },
  superSpeed: {
    speed: 15,
    duration: 6
  }
};
var speed = speeds.normal.speed;

var distanceScale,
    durationScale,
    paceScale,
    startScale,
    endScale;

var colorings = {
  direction: {
    getStyle: function(feature) {
      var color = feature.properties.start === 'north' ? 'rgb(255, 51, 0)' : 'rgb(0, 51, 255)';
      return {
        color: color,
        opacity: 0.5
      };
    }
  },
  distance: {
    getStyle: function(feature) {
      var scale = distanceScale(feature.properties.distance);
      var colorNum = scale - (scale % 100);
      var color = palette.indigo[colorNum];
      return {
        color: color,
        opacity: 0.6
      };
    }
  },
  duration: {
    getStyle: function(feature) {
      var scale = durationScale(feature.properties.maxTick);
      var colorNum = scale - (scale % 100);
      var color = palette.red[colorNum];
      return {
        color: color,
        opacity: 0.6
      };
    }
  },
  pace: {
    getStyle: function(feature) {
      var scale = paceScale(feature.properties.pace);
      var colorNum = scale - (scale % 100);
      var color = palette.purple[colorNum];
      return {
        color: color,
        opacity: 0.6
      };
    }
  },
  start: {
    getStyle: function(feature) {
      var scale = feature.properties.start === 'north' ?
        startScale(feature.properties.startTick) :
        endScale(feature.properties.startTick);
      var colorNum = scale - (scale % 100);
      var color = feature.properties.start === 'north' ?
        palette.deepOrange[colorNum] : palette.blue[colorNum];
      return {
        color: color,
        opacity: 0.5
      };
    }
  }
};
var coloring = colorings.direction;

var tiles = {
  Mapbox: {
    url: 'https://{s}.tiles.mapbox.com/v3/sedenardi.kfmi8afc/{z}/{x}/{y}.png',
    attribution: 'Map data © OpenStreetMap contributors, ' +
      'CC-BY-SA, ' +
      'Imagery © Mapbox'
  },
  OpenStreetMap: {
    url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    attribution: 'Map data © OpenStreetMap contributors'
  },
  OpenMapSurferRoads: {
    url: 'http://openmapsurfer.uni-hd.de/tiles/roads/x={x}&y={y}&z={z}',
    attribution: 'Imagery from GIScience Research Group @ ' +
      'University of Heidelberg — Map data © ' +
      'OpenStreetMap'
  },
  HyddaFull: {
    url: 'http://{s}.tile.openstreetmap.se/hydda/full/{z}/{x}/{y}.png',
    attribution: 'Tiles courtesy of OpenStreetMap ' +
      'Sweden — Map data © OpenStreetMap'
  }
};
var tile = tiles.Mapbox;

var initMap = function() {
	var a = geoJson.lineStrings[0].features[0].geometry.coordinates;
	var first = a[0],
		last = a[a.length-1],
		lon = (first[0] + last[0])/2,
		lat = (first[1] + last[1])/2;

  var zoom = $('#map').height() < 680 ? 15 : 16;

	map = L.map('map').setView([lat, lon], zoom);
  map.on('click', function(e) {
    hideTooltip();
  });
  L.tileLayer(tile.url, {
    maxZoom: 20,
    attribution: tile.attribution
  }).addTo(map);

  initScales();
  initControls();
  resetMap();
  showAttractions();
};1

var getPathsAtTick = function(tick) {
  var paths = [];
  for (var i = 0; i < geoJson.lineStrings.length; i++) {
    var endIndex = geoJson.lineStrings[i].features[0].properties.ticks.length;
    for (var j = 0; j < geoJson.lineStrings[i].features[0].properties.ticks.length; j++) {
      var theTick = geoJson.lineStrings[i].features[0].properties.ticks[j];
      if (tick < theTick) {
        endIndex = j;
        break;
      }
    }
    var path = {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          properties: {
            name: geoJson.lineStrings[i].features[0].properties.name,
            time: geoJson.lineStrings[i].features[0].properties.time,
            start: geoJson.lineStrings[i].features[0].properties.start,
            pathLength: geoJson.lineStrings[i].features[0].properties.pathLength,
            maxTick: geoJson.lineStrings[i].features[0].properties.maxTick,
            distance: geoJson.lineStrings[i].features[0].properties.distance,
            pace: geoJson.lineStrings[i].features[0].properties.pace,
            startTick: geoJson.lineStrings[i].features[0].properties.startTick
          },
          geometry: {
            type: 'LineString',
            coordinates: geoJson.lineStrings[i].features[0].geometry.coordinates.slice(0,(endIndex))
          }
        }
      ]
    };
    paths.push(path);
  }
  return paths;
};

var initScales = function() {
  distanceScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings, function(d) {
        return d.features[0].properties.distance;
    }),
      d3.max(geoJson.lineStrings, function(d) {
        return d.features[0].properties.distance;
    })])
    .rangeRound([100, 900]);

  durationScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings, function(d) {
        return d.features[0].properties.maxTick;
    }),
      d3.max(geoJson.lineStrings, function(d) {
        return d.features[0].properties.maxTick;
    })])
    .rangeRound([100, 900]);

  paceScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings, function(d) {
        return d.features[0].properties.pace;
    }),
      d3.max(geoJson.lineStrings, function(d) {
        return d.features[0].properties.pace;
    })])
    .rangeRound([100, 900]);

  startScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'north';
      }), function(d) {
        return d.features[0].properties.startTick;
    }),
      d3.max(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'north';
      }), function(d) {
        return d.features[0].properties.startTick;
    })])
    .rangeRound([300, 900]);

  endScale = d3.scale.linear()
    .domain([
      d3.min(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'south';
      }), function(d) {
        return d.features[0].properties.startTick;
    }),
      d3.max(geoJson.lineStrings.filter(function(d){
        return d.features[0].properties.start === 'south';
      }), function(d) {
        return d.features[0].properties.startTick;
    })])
    .rangeRound([300, 900]);
};

var showTooltip = function(feature, layer, e) {
  $('#start').html(moment(feature.properties.time).format('ddd MMM D h:mm A'));
  var minutes = Math.floor(feature.properties.maxTick/60);
  var seconds = feature.properties.maxTick % 60;
  var duration = minutes + ' minutes ' + seconds + ' seconds';
  var pMin = Math.floor(feature.properties.pace/60);
  var pSec = feature.properties.pace % 60;
  var pace = pMin + ' minutes ' + (pSec !== 0 ? (pSec + ' seconds') : '');

  $('#duration').html(duration);
  $('#distance').html(feature.properties.distance + ' mi');
  $('#pace').html(pace);

  var x = e.originalEvent.x + 5,
      y = e.originalEvent.y - 30;
  if (x + 245 > $(window).width()) x = x - 245;
  if (y + 95 > $(window).height()) y = $(window).height() - 95;
  $('#pathTooltip').css('left', x);
  $('#pathTooltip').css('top', y);
  $('#pathTooltip').show();
};

var hideTooltip = function() {
  $('#pathTooltip').removeClass('clicked');
  $('#pathTooltip').hide();
  if (lastClickedPath)
    currentLayer.resetStyle(lastClickedPath);
};

var currentTick = 0,
    playing = false,
    paused = false,
    startTime,
    endTime;
var mapTick = function() {
  playing = true;
  var lines = getPathsAtTick(currentTick);

  var nextLayer = L.geoJson(lines, {
    style: coloring.getStyle,
    onEachFeature: function(feature,layer) {
      layer.on({
        click: function(e) {
          if (lastClickedPath)
            currentLayer.resetStyle(lastClickedPath);
          if (lastClickedAttraction)
            lastClickedAttraction.closePopup();

          layer.setStyle({
            color: palette.grey[900],
            opacity: 1
          });
          if (!L.Browser.ie && !L.Browser.opera) {
            layer.bringToFront();
          }

          showTooltip(feature, layer, e);
          $('#pathTooltip').addClass('clicked');

          lastClickedPath = layer;
        },
        mouseover: function(e) {
          if ($('#pathTooltip').hasClass('clicked')) {
            return;
          }
          layer.setStyle({
            color: palette.grey[900],
            opacity: 1
          });
          if (!L.Browser.ie && !L.Browser.opera) {
            layer.bringToFront();
          }

          showTooltip(feature, layer, e);
        },
        mouseout: function(e) {
          if ($('#pathTooltip').hasClass('clicked')) {
            return;
          }
          currentLayer.resetStyle(layer);
          $('#pathTooltip').hide();
        }
      });
    }
  }).addTo(map);

  if (currentLayer) map.removeLayer(currentLayer);
  currentLayer = nextLayer;

  if (paused) {
    return;
  } else if (currentTick < geoJson.maxTick) {
    currentTick += speed;
    setTimeout(function() {
      mapTick();
    },interval);
  } else {
    playing = false;
    if (startTime) {
      endTime = new Date();
      console.log('Duration - ' + (endTime - startTime));
    }
    syncControlState();
  }
};

var resetMap = function() {
  playing = false;
  paused = false;
  currentTick = geoJson.maxTick;
  mapTick();
  syncControlState();
};

var syncControlState = function() {
  var $toggleIcon = $('.playbackControl[data-control="toggle"] > i');
  if (playing && !paused) {
    $toggleIcon.removeClass('fa-play').addClass('fa-pause');
  } else {
    $toggleIcon.removeClass('fa-pause').addClass('fa-play');
  }
};

var showAttractions = function() {
  attractionLayer = L.geoJson(attractions, {
    pointToLayer: function(feature, latlng) {
      var c = 'icon-custom icon-' + feature.properties.type;
      var icon = L.divIcon({
        className: c,
        iconSize: L.point(16, 16)
      });
      return L.marker(latlng, {icon: icon});
    },
    onEachFeature: function(feature,layer) {
      var title = '' +
        feature.properties.name + ' ';
      var popupTitle = '
' +
        title + '
';
      var popupDescription = '
' +
        feature.properties.description + '
';
      var popupContent = '
' +
        popupTitle + popupDescription + '
';
      var popupClass = feature.properties.name
        .toLowerCase()
        .replace(/ /g, '-')
        .replace(/'/g, '')
        .replace(/\./g, '')
        .replace(/[0-9]/g, '')
        .replace(/&/g, 'and');
      var popupContainer = '
' +
        popupContent + '
';
      layer.bindPopup(popupContainer);
      layer.on('click', function() {
        lastClickedAttraction = layer;
        hideTooltip();
      });
    }
  }).addTo(map);
};

var initControls = function() {
  $('.aboutModal').click(function(e) {
    $('#aboutModal').modal('show');
    e.preventDefault();
  });

  $('.playbackControl').click(function(e) {
    var control = $(this).attr('data-control');
    if (control === 'toggle') {
      $toggleIcon = $(this).children('i');
      if (!paused) {
        if (playing) {
          paused = true;
        } else {
          startTime = new Date();
          currentTick = 0;
          mapTick();
        }
      } else {
        paused = false;
        mapTick();
      }
      syncControlState();
    } else if (control === 'stop') {
      resetMap();
    }
    e.preventDefault();
  });

  $('#speedControl').change(function() {
    speed = speeds[$(this).val()].speed;
  });

  $('#colorControl').change(function() {
    coloring = colorings[$(this).val()];
    if (!playing || paused)
      mapTick();
  });

  $('#attCheckbox').change(function() {
    if ($('#attCheckbox').is(':checked')) {
      showAttractions();
    } else if (attractionLayer) {
      map.removeLayer(attractionLayer);
    }
  });

  $('#attrToggle').click(function() {
    $('#attCheckbox').prop('checked', !$('#attCheckbox').is(':checked'))
      .change();
  });
};

var initWalk = function(cb) {
  $.ajax({
    url: 'coordinates.json',
    dataType: 'json',
    success: function(geoRes) {
      geoJson = geoRes;
      $.ajax({
        url: 'attractions.json',
        dataType: 'json',
        success: function(attRes) {
          attractions = attRes;
          cb();
        }
      });
    }
  });
};

initWalk(initMap);<|endoftext|>


<commit_before>"use strict";

Number.prototype.between = function (a, b, inclusive) {
  var min = Math.min.apply(Math, [a, b]),
      max = Math.max.apply(Math, [a, b]);
  return inclusive ? this >= min && this <= max : this > min && this < max;
};

var keyCodeToString = function keyCodeToString(keyCode) {
  if (keyCode == 38) {
    return "UP";
  } else if (keyCode == 37) {
    return "LEFT";
  } else if (keyCode == 39) {
    return "RIGHT";
  } else if (keyCode == 40) {
    return "DOWN";
  } else {
    return String.fromCharCode(keyCode);
  }
};

var unitsToMiliseconds = function unitsToMiliseconds(time, units) {
  if (units == "miliseconds" || units == "milisecond") {
    return time;
  } else if (units == "seconds" || units == "second") {
    return time * 1000;
  } else if (units == "minutes" || units == "minute") {
    return time * 1000 * 60;
  } else {
    throw Error("Unrecognized Time");
  }
};

var randomInt = function randomInt(low, high) {
  return Math.floor(Math.random() * high + low);
};

var Project = function Project(canvasId) {
  var _this = this;

  this.sprites = [];
  this.backdrops = [];
  this.backdrop = 0;

  try {
    this._canvas = document.getElementById(canvasId);
  } catch (e) {
    console.error(e);
    console.error("Could not find a canvas on the page with id " + canvasId);
    return null;
  }
  this._context = this._canvas.getContext("2d");
  this.height = this._canvas.height;
  this.width = this._canvas.width;

  this._render = function () {
    this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
    this._renderBackdrop();
    this._renderSprites();
  };

  this._renderBackdrop = function () {
    if (this.backdrops[this.backdrop]) {
      var image = this.backdrops[this.backdrop];
      project._context.drawImage(image, 0, 0);
    }
  };

  this._renderSprites = function () {
    _this.sprites.forEach(function (sprite) {
      sprite._render(_this);
    });
  };

  this.addSprite = function () {
    var sprite = new Sprite(this);
    this.sprites.push(sprite);
    return sprite;
  };

  this.addBackdropURL = function (url) {
    var backdrop = new Image();
    backdrop.src = url;
    this.backdrops.push(backdrop);
  };

  this.stopAll = function () {
    _this._render();
    clearInterval(renderInterval);

    _this._everys.forEach(clearInterval);
    _this._afters.forEach(clearInterval);

    _this.sprites.forEach(function (sprite) {
      return sprite.delete();
    });
  };

  this.mouseDown = false;
  var mousedown = function mousedown() {
    _this.mouseDown = true;
  };
  var mouseup = function mouseup() {
    _this.mouseDown = false;
  };
  document.body.addEventListener("mousedown", mousedown);
  document.body.addEventListener("mouseup", mouseup);
  document.body.addEventListener("touchstart", mousedown);
  document.body.addEventListener("touchend", mouseup);

  this.mouseX = 0;
  this.mouseY = 0;
  document.body.addEventListener("mousemove", function (event) {
    _this.mouseX = event.clientX;
    _this.mouseY = event.clientY;
  });
  this._canvas.addEventListener("touchmove", function (event) {
    _this.mouseX = event.targetTouches[0].pageX;
    _this.mouseY = event.targetTouches[0].pageY;
    event.preventDefault();
  });

  this.keysDown = [];
  document.body.addEventListener("keydown", function (event) {
    var key = keyCodeToString(event.keyCode);
    if (!_this.keysDown.includes(key)) {
      _this.keysDown.push(key);
    }
  });
  document.body.addEventListener("keyup", function (event) {
    var key = keyCodeToString(event.keyCode);
    if (_this.keysDown.includes(key)) {
      _this.keysDown.splice(_this.keysDown.indexOf(key), 1);
    }
  });

  this._everys = [];
  this.every = function (time, units, func) {
    func();
    _this._everys.push(setInterval(func, unitsToMiliseconds(time, units)));
  };

  this._afters = [];
  this.after = function (time, units, func) {
    _this._afters.push(setTimeout(func, unitsToMiliseconds(time, units)));
  };

  this._onloads = [];
  document.body.addEventListener("onload", function (event) {
    _this._onloads.forEach(function (func) {
      func.call();
    });
  });

  var renderInterval = setInterval(function () {
    try {
      _this._render();
    } catch (e) {
      console.error(e);
      console.error("Error in render: " + e.message);
      clearInterval(renderInterval);
    }
  }, 40);
};

var Sprite = function Sprite(project) {
  var _this2 = this;

  this.project = project;

  this.xPosition = 0;
  this.yPosition = 0;

  this.angle = 0;

  this.costumes = [];
  this.costume = 0;
  this.height = null;
  this.width = null;

  this.rotationStyle = "ROTATE";

  this.showing = true;

  this.addCostumeURL = function (url) {
    var costume = new Image();
    costume.src = url;
    this.costumes.push(costume);
    return this.costumes.length - 1;
  };

  this.setText = function (text, x, y, size, color, font, align) {
    var s = size || 12;
    var c = color || "black";
    var f = font || "Arial";
    var a = align || "left";
    _this2.costumes[0] = { text: text, x: x, y: y, size: s, color: c, font: f, align: a };
  };

  this._render = function () {
    var costume = this.costumes[this.costume];

    var angle;
    if (this.rotationStyle == "ROTATE") {
      angle = this.angle;
    } else if (this.rotationStyle == "NO ROTATE") {
      angle = 0;
    }

    if (costume && this.showing) {
      this.project._context.save();
      this.project._context.translate(this.xPosition, this.yPosition);
      this.project._context.translate(costume, costume.width / 2, costume.height / 2);
      this.project._context.rotate(angle * Math.PI / 180);

      if (costume.nodeName == "IMG") {
        this.project._context.drawImage(costume, -costume.width / 2, -costume.height / 2);
      } else if (costume.text) {
        this.project._context.font = costume.size + "px " + costume.font;
        this.project._context.fillStyle = costume.color;
        this.project._context.textAlign = costume.align;
        this.project._context.fillText(costume.text, costume.x, costume.y);
      } else if (costume.radius) {
        this.project._context.beginPath();
        this.project._context.arc(costume.x, costume.y, costume.radius, 0, 2 * Math.PI);
        this.project._context.fillStyle = costume.color;
        this.project._context.fill();
      }
      this.project._context.restore();
    }
  };

  this.addCostumeCircle = function (x, y, radius, color) {
    _this2.costumes.push({ x: x, y: y, radius: radius, color: color });
  };

  this.move = function (steps) {
    this.xPosition += steps * Math.cos(this.angle * Math.PI / 180);
    this.yPosition += steps * Math.sin(this.angle * Math.PI / 180);
  };

  this.setRotationStyle = function (style) {
    if (style == "ROTATE") {
      _this2.rotationStyle = "ROTATE";
    } else if (style == "NO ROTATE") {
      _this2.rotationStyle = "NO ROTATE";
    } else {
      throw Error("Unrecognized rotation style: " + style);
    }
  };

  this.bounds = function () {
    var leftBounds = _this2.xPosition - _this2.width() / 2;
    var rightBounds = _this2.xPosition + _this2.width() / 2;
    var topBounds = _this2.yPosition - _this2.height() / 2;
    var bottomBounds = _this2.yPosition + _this2.height() / 2;
    return { left: leftBounds, right: rightBounds, top: topBounds, bottom: bottomBounds };
  };

  this.touching = function (sprite) {
    var r1 = _this2.bounds();
    var r2 = sprite.bounds();

    return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top);
  };

  this.mouseOver = function () {
    // TODO account for rotation
    var belowTop = this.project.mouseY >= this.yPosition - this.height() / 2;
    var aboveBottom = this.project.mouseY <= this.yPosition + this.height() / 2;
    var rightLeft = this.project.mouseX >= this.xPosition - this.width() / 2;
    var leftRight = this.project.mouseX <= this.xPosition + this.width() / 2;
    return belowTop && aboveBottom && rightLeft && leftRight;
  };

  this.currentCostume = function () {
    return _this2.costumes[_this2.costume];
  };

  this.sendToBack = function () {
    var sprites = _this2.project.sprites;
    sprites.splice(0, 0, sprites.splice(sprites.indexOf(_this2), 1)[0]);
  };

  this.sendToFront = function () {
    var sprites = _this2.project.sprites;
    sprites.splice(sprites.length, 0, sprites.splice(sprites.indexOf(_this2), 1)[0]);
  };

  this.pointTowards = function (sprite) {
    var x1 = _this2.xPosition;
    var y1 = _this2.yPosition;
    var x2 = sprite.xPosition;
    var y2 = sprite.yPosition;

    _this2.angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
  };

  this.pointTowards = function (x2, y2) {
    var x1 = _this2.xPosition;
    var y1 = _this2.yPosition;

    _this2.angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
  };

  this.height = function () {
    return _this2.currentCostume().height;
  };

  this.width = function () {
    return _this2.currentCostume().width;
  };

  this.delete = function () {
    if (_this2.project.sprites.includes(_this2)) {
      _this2.project.sprites.splice(_this2.project.sprites.indexOf(_this2), 1);
      _this2._everys.forEach(clearInterval);
      _this2._afters.forEach(clearInterval);
    }
  };
};
<commit_msg>Name spaced top level functions to Woof.<commit_after>"use strict";

var Project = function Project() {
  console.error('In this version of Woof, please use "Woof.Project" instead of "Project"');
};

var Woof = {};

Number.prototype.between = function (a, b, inclusive) {
  var min = Math.min.apply(Math, [a, b]),
      max = Math.max.apply(Math, [a, b]);
  return inclusive ? this >= min && this <= max : this > min && this < max;
};

Woof.keyCodeToString = function (keyCode) {
  if (keyCode == 38) {
    return "UP";
  } else if (keyCode == 37) {
    return "LEFT";
  } else if (keyCode == 39) {
    return "RIGHT";
  } else if (keyCode == 40) {
    return "DOWN";
  } else {
    return String.fromCharCode(keyCode);
  }
};

Woof.unitsToMiliseconds = function (time, units) {
  if (units == "milliseconds" || units == "millisecond") {
    return time;
  } else if (units == "seconds" || units == "second") {
    return time * 1000;
  } else if (units == "minutes" || units == "minute") {
    return time * 1000 * 60;
  } else {
    throw Error("Unrecognized Time");
  }
};

Woof.randomInt = function (low, high) {
  return Math.floor(Math.random() * high + low);
};

Woof.Project = function (canvasId) {
  var _this = this;

  this.sprites = [];
  this.backdrops = [];
  this.backdrop = 0;

  try {
    this._canvas = document.getElementById(canvasId);
  } catch (e) {
    console.error(e);
    console.error("Could not find a canvas on the page with id " + canvasId);
    return null;
  }
  this._context = this._canvas.getContext("2d");
  this.height = this._canvas.height;
  this.width = this._canvas.width;

  this._render = function () {
    this._context.clearRect(0, 0, this._canvas.width, this._canvas.height);
    this._renderBackdrop();
    this._renderSprites();
  };

  this._renderBackdrop = function () {
    if (this.backdrops[this.backdrop]) {
      var image = this.backdrops[this.backdrop];
      project._context.drawImage(image, 0, 0);
    }
  };

  this._renderSprites = function () {
    _this.sprites.forEach(function (sprite) {
      sprite._render(_this);
    });
  };

  this.addSprite = function () {
    var sprite = new Woof.Sprite(this);
    this.sprites.push(sprite);
    return sprite;
  };

  this.addBackdropURL = function (url) {
    var backdrop = new Image();
    backdrop.src = url;
    this.backdrops.push(backdrop);
  };

  this.stopAll = function () {
    _this._render();
    clearInterval(renderInterval);

    _this._everys.forEach(clearInterval);
    _this._afters.forEach(clearInterval);

    _this.sprites.forEach(function (sprite) {
      return sprite.delete();
    });
  };

  this.mouseDown = false;
  var mousedown = function mousedown() {
    _this.mouseDown = true;
  };
  var mouseup = function mouseup() {
    _this.mouseDown = false;
  };
  document.body.addEventListener("mousedown", mousedown);
  document.body.addEventListener("mouseup", mouseup);
  document.body.addEventListener("touchstart", mousedown);
  document.body.addEventListener("touchend", mouseup);

  this.mouseX = 0;
  this.mouseY = 0;
  document.body.addEventListener("mousemove", function (event) {
    _this.mouseX = event.clientX;
    _this.mouseY = event.clientY;
  });
  this._canvas.addEventListener("touchmove", function (event) {
    _this.mouseX = event.targetTouches[0].pageX;
    _this.mouseY = event.targetTouches[0].pageY;
    event.preventDefault();
  });

  this.keysDown = [];
  document.body.addEventListener("keydown", function (event) {
    var key = Woof.keyCodeToString(event.keyCode);
    if (!_this.keysDown.includes(key)) {
      _this.keysDown.push(key);
    }
  });
  document.body.addEventListener("keyup", function (event) {
    var key = Woof.keyCodeToString(event.keyCode);
    if (_this.keysDown.includes(key)) {
      _this.keysDown.splice(_this.keysDown.indexOf(key), 1);
    }
  });

  this._everys = [];
  this.every = function (time, units, func) {
    func();
    _this._everys.push(setInterval(func, Woof.unitsToMiliseconds(time, units)));
  };

  this._afters = [];
  this.after = function (time, units, func) {
    _this._afters.push(setTimeout(func, Woof.unitsToMiliseconds(time, units)));
  };

  this._onloads = [];
  document.body.addEventListener("onload", function (event) {
    _this._onloads.forEach(function (func) {
      func.call();
    });
  });

  var renderInterval = setInterval(function () {
    try {
      _this._render();
    } catch (e) {
      console.error(e);
      console.error("Error in render: " + e.message);
      clearInterval(renderInterval);
    }
  }, 40);
};

Woof.Sprite = function (project) {
  var _this2 = this;

  this.project = project;

  this.xPosition = 0;
  this.yPosition = 0;

  this.angle = 0;

  this.costumes = [];
  this.costume = 0;
  this.height = null;
  this.width = null;

  this.rotationStyle = "ROTATE";

  this.showing = true;

  this.addCostumeURL = function (url) {
    var costume = new Image();
    costume.src = url;
    this.costumes.push(costume);
    return this.costumes.length - 1;
  };

  this.setText = function (text, x, y, size, color, font, align) {
    var s = size || 12;
    var c = color || "black";
    var f = font || "Arial";
    var a = align || "left";
    _this2.costumes[0] = { text: text, x: x, y: y, size: s, color: c, font: f, align: a };
  };

  this._render = function () {
    var costume = this.costumes[this.costume];

    var angle;
    if (this.rotationStyle == "ROTATE") {
      angle = this.angle;
    } else if (this.rotationStyle == "NO ROTATE") {
      angle = 0;
    }

    if (costume && this.showing) {
      this.project._context.save();
      this.project._context.translate(this.xPosition, this.yPosition);
      this.project._context.translate(costume, costume.width / 2, costume.height / 2);
      this.project._context.rotate(angle * Math.PI / 180);

      if (costume.nodeName == "IMG") {
        this.project._context.drawImage(costume, -costume.width / 2, -costume.height / 2);
      } else if (costume.text) {
        this.project._context.font = costume.size + "px " + costume.font;
        this.project._context.fillStyle = costume.color;
        this.project._context.textAlign = costume.align;
        this.project._context.fillText(costume.text, costume.x, costume.y);
      } else if (costume.radius) {
        this.project._context.beginPath();
        this.project._context.arc(costume.x, costume.y, costume.radius, 0, 2 * Math.PI);
        this.project._context.fillStyle = costume.color;
        this.project._context.fill();
      }
      this.project._context.restore();
    }
  };

  this.addCostumeCircle = function (x, y, radius, color) {
    _this2.costumes.push({ x: x, y: y, radius: radius, color: color });
  };

  this.move = function (steps) {
    this.xPosition += steps * Math.cos(this.angle * Math.PI / 180);
    this.yPosition += steps * Math.sin(this.angle * Math.PI / 180);
  };

  this.setRotationStyle = function (style) {
    if (style == "ROTATE") {
      _this2.rotationStyle = "ROTATE";
    } else if (style == "NO ROTATE") {
      _this2.rotationStyle = "NO ROTATE";
    } else {
      throw Error("Unrecognized rotation style: " + style);
    }
  };

  this.bounds = function () {
    var leftBounds = _this2.xPosition - _this2.width() / 2;
    var rightBounds = _this2.xPosition + _this2.width() / 2;
    var topBounds = _this2.yPosition - _this2.height() / 2;
    var bottomBounds = _this2.yPosition + _this2.height() / 2;
    return { left: leftBounds, right: rightBounds, top: topBounds, bottom: bottomBounds };
  };

  this.touching = function (sprite) {
    var r1 = _this2.bounds();
    var r2 = sprite.bounds();

    return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top);
  };

  this.mouseOver = function () {
    // TODO account for rotation
    var belowTop = this.project.mouseY >= this.yPosition - this.height() / 2;
    var aboveBottom = this.project.mouseY <= this.yPosition + this.height() / 2;
    var rightLeft = this.project.mouseX >= this.xPosition - this.width() / 2;
    var leftRight = this.project.mouseX <= this.xPosition + this.width() / 2;
    return belowTop && aboveBottom && rightLeft && leftRight;
  };

  this.currentCostume = function () {
    return _this2.costumes[_this2.costume];
  };

  this.sendToBack = function () {
    var sprites = _this2.project.sprites;
    sprites.splice(0, 0, sprites.splice(sprites.indexOf(_this2), 1)[0]);
  };

  this.sendToFront = function () {
    var sprites = _this2.project.sprites;
    sprites.splice(sprites.length, 0, sprites.splice(sprites.indexOf(_this2), 1)[0]);
  };

  this.pointTowards = function (sprite) {
    var x1 = _this2.xPosition;
    var y1 = _this2.yPosition;
    var x2 = sprite.xPosition;
    var y2 = sprite.yPosition;

    _this2.angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
  };

  this.pointTowards = function (x2, y2) {
    var x1 = _this2.xPosition;
    var y1 = _this2.yPosition;

    _this2.angle = Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
  };

  this.height = function () {
    return _this2.currentCostume().height;
  };

  this.width = function () {
    return _this2.currentCostume().width;
  };

  this.delete = function () {
    if (_this2.project.sprites.includes(_this2)) {
      _this2.project.sprites.splice(_this2.project.sprites.indexOf(_this2), 1);
      _this2._everys.forEach(clearInterval);
      _this2._afters.forEach(clearInterval);
    }
  };
};
<|endoftext|>


<commit_before>angular.module('services.xbmc', ['services.io'])
    .factory('xbmc', ['$rootScope', '$q', '$parse', '$interval', 'io',
        function($rootScope, $q, $parse, $interval, io) {
            // We return this object to anything injecting our service
            var factory = {};
            var activePlayer = -1;
            var activePlaylist = -1;
            var volume = 0;

            factory.connect = function(url, port) {
                return io.connect(url, port);
            }

            factory.isConnected = function() {
                return io.isConnected();
            }

            factory.register = function(method, callback) {
                io.register(method, callback);
            }

            factory.unregister = function(method, callback) {
                io.unregister(method, callback);
            }

            factory.up = function() {
                io.send('Input.Up');
            };
            factory.down = function() {
                io.send('Input.Down');
            };
            factory.left = function() {
                io.send('Input.Left');
            };
            factory.right = function() {
                io.send('Input.Right');
            };
            factory.select = function() {
                io.send('Input.Select');
            };
            factory.back = function() {
                io.send('Input.Back');
            };
            factory.contextmenu = function() {
                io.send('Input.ContextMenu');
            };
            factory.info = function() {
                io.send('Input.Info');
            };
            factory.home = function() {
                io.send('Input.Home');
            };
            factory.sendText = function (textToSend) {
                io.send('Input.io.sendText', {'text' : textToSend});
            }
            factory.showOSD = function () {
                io.send('Input.ShowOSD');
            };

            factory.getActivePlayers = function(cb) {
                io.send('Player.GetActivePlayers', null, true, 'result').then(cb);
            };

            factory.setActivePlayer = function(playerId) {
                activePlayer = playerId;
            }

            factory.setActivePlaylist = function(playlistId) {
                activePlaylist = playlistId;
            }

            factory.getPlayerItem = function(cb, playerId) {
                playerId = playerId || activePlayer;
                io.send('Player.GetItem', {
                    'properties': ['title', 'artist', 'albumartist', 'genre',
                        'year', 'rating', 'album', 'track', 'duration', 'comment', 'lyrics',
                        'musicbrainztrackid', 'musicbrainzartistid', 'musicbrainzalbumid',
                        'musicbrainzalbumartistid', 'playcount', 'fanart', 'director', 'trailer',
                        'tagline', 'plot', 'plotoutline', 'originaltitle', 'lastplayed', 'writer',
                        'studio', 'mpaa', 'cast', 'country', 'imdbnumber', 'premiered', 'productioncode',
                        'runtime', 'set', 'showlink', 'streamdetails', 'top250', 'votes', 'firstaired',
                        'season', 'episode', 'showtitle', 'thumbnail', 'file', 'resume', 'artistid',
                        'albumid', 'tvshowid', 'setid', 'watchedepisodes', 'disc', 'tag', 'art', 'genreid',
                        'displayartist', 'albumartistid', 'description', 'theme', 'mood', 'style',
                        'albumlabel', 'sorttitle', 'episodeguide', 'uniqueid', 'dateadded', 'channel',
                        'channeltype', 'hidden', 'locked', 'channelnumber', 'starttime', 'endtime'
                    ],
                    'playerid': playerId
                }, true, 'result.item').then(cb);
            };

            factory.getPlayerProperties = function(cb) {
                io.send('Player.GetProperties', {
                    'properties': ['percentage', 'time', 'totaltime',
                        'speed', 'playlistid',
                        'currentsubtitle', 'subtitles',
                        'audiostreams', 'currentaudiostream', 'type'
                    ],
                    'playerid': activePlayer
                }, true, 'result').then(cb);
            };

            factory.goTo = function(index) {
                io.send('Player.GoTo', {
                    'playerid': activePlayer,
                    'to': index
                });
            };

            factory.next = function() {
                io.send('Player.GoTo', {
                    'playerid': activePlayer,
                    'to': 'next'
                });
            };

            factory.open = function(item) {
                io.send('Player.Open', {
                    'item': item
                });
            };

            factory.previous = function() {
                io.send('Player.GoTo', {
                    'playerid': activePlayer,
                    'to': 'previous'
                });
            };

            factory.togglePlay = function() {
                io.send('Player.PlayPause', {
                    'playerid': activePlayer
                });
            };

            factory.seek = function(newValue) {
                io.send('Player.Seek', {
                    'playerid': activePlayer,
                    'value': newValue
                });
            };

            factory.setAudioStream = function(audioStream) {
                io.send('Player.SetAudioStream', {
                    'playerid': activePlayer,
                    'stream': audioStream
                });
            };

            factory.setSubtitle = function(subtitle) {
                io.send('Player.SetSubtitle', {
                    'playerid': activePlayer,
                    'subtitle': subtitle,
                    'enable': true
                });
            };

            factory.setSpeed = function(speed) {
                io.send('Player.SetSpeed', {
                    'playerid': activePlayer,
                    'speed': speed
                });
            };

            factory.stop = function() {
                io.send('Player.Stop', {
                    'playerid': activePlayer
                });
            };

            (function getVolume(cb) {
                io.send('Application.GetProperties', {
                    'properties': ['volume']
                }, true, 'result.volume').then(function(value) {
                    volume = value;
                });
            })();

            factory.increaseVolume = function() {
                volume = Math.min(volume + 1, 100);
                io.send('Application.SetVolume', {
                    'volume': volume
                });
            };
            factory.decreaseVolume = function() {
                volume = Math.max(volume - 1, 0);
                io.send('Application.SetVolume', {
                    'volume':volume
                });
            };
            factory.mute = function() {
                io.send('Application.SetMute', {
                    'mute': 'toggle'
                });
            };

            factory.shutdown = function() {
                io.send('System.Shutdown');
            };

            factory.activateWindow = function(params) {
                io.send('GUI.ActivateWindow', params);
            };

            factory.getPlaylistItems = function(cb) {
                io.send('Playlist.GetItems', {
                    'playlistid': activePlaylist,
                    'properties': ['title', 'art', 'duration', 'runtime', 'thumbnail']
                }, true, 'result.items').then(cb);
            };

            factory.queue = function(item) {
                if (activePlaylist > -1) {
                    io.send('Playlist.Add', {
                        'playlistid': activePlaylist,
                        'item': item
                    });
                }
            };

            factory.getMovies = function(cb) {
                io.send('VideoLibrary.GetMovies', {
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'properties': ['title', 'genre', 'rating', 'thumbnail', 'runtime', 'playcount', 'streamdetails'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    }
                }, true, 'result.movies').then(cb);
            };

            factory.getMovieDetails = function(movieId, cb) {
                io.send('VideoLibrary.GetMovieDetails', {
                    'properties': ['title', 'genre', 'rating', 'thumbnail', 'plot',
                        'studio', 'director', 'fanart', 'runtime', 'trailer', 'imdbnumber'
                    ],
                    'movieid': movieId
                }, true, 'result.moviedetails').then(cb);

            };

            factory.getAlbums = function(filter, cb) {
                var params = {
                    'limits': {
                        'start': 0,
                        'end': 100
                    },
                    'properties': ['title', 'artist', 'thumbnail', 'year', 'genre'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    },
                };
                if (filter && filter.key) {
                    params.filter = {};
                    params.filter[filter.key] = filter.value;
                }
                io.send('AudioLibrary.GetAlbums', params, true, 'result.albums').then(cb);
            };

            factory.getArtists = function(cb) {
                io.send('AudioLibrary.GetArtists', {
                    'limits': {
                        'start': 0,
                        'end': 100
                    },
                    'properties': ['genre', 'thumbnail'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    }
                }, true, 'result.artists').then(cb);

            };

            factory.getSongs = function(filter, cb) {
                var params = {
                    'limits': {
                        'start': 0,
                        'end': 500
                    },
                    'properties': ['title', 'artist', 'album', 'albumid', 'thumbnail', 'duration', 'track', 'year'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    }
                };
                if (filter && filter.key) {
                    params.filter = {};
                    params.filter[filter.key] = filter.value;
                    params.sort.method = 'track';
                }
                io.send('AudioLibrary.GetSongs', params, true, 'result.songs').then(cb);
            };

            factory.getTVShows = function(cb) {
                io.send('VideoLibrary.GetTVShows', {
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'properties': ['genre', 'title', 'rating', 'art', 'playcount'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label'
                    }
                }, true, 'result.tvshows').then(cb);
            };
            factory.getSeasons = function(tvShowId, cb) {
                io.send('VideoLibrary.GetSeasons', {
                    'tvshowid': tvShowId,
                    'properties': ['season', 'showtitle', 'fanart', 'thumbnail'],
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'sort': {
                        'order': 'ascending',
                        'method': 'label'
                    }
                }, true, 'result.seasons').then(cb);
            };
            factory.getEpisodes = function(tvShowId, season, cb) {
                io.send('VideoLibrary.GetEpisodes', {
                    'tvshowid': tvShowId,
                    'season': season,
                    'properties': ['title', 'rating', 'firstaired', 'runtime', 'season', 'episode', 'thumbnail', 'art'],
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'sort': {
                        'order': 'ascending',
                        'method': 'label'
                    }
                }, true, 'result.episodes').then(cb);
            };
            factory.getEpisodeDetails = function(episodeId, cb) {
                io.send('VideoLibrary.GetEpisodeDetails', {
                    'episodeid': episodeId,
                    'properties': ['title', 'plot', 'rating', 'firstaired', 'runtime', 'thumbnail', 'art']
                }, true, 'result.episodedetails').then(cb);
            };

            return factory;
        }
    ])<commit_msg>[Feature] Prepare for XBMC Gotham<commit_after>angular.module('services.xbmc', ['services.io'])
    .factory('xbmc', ['$rootScope', '$q', '$parse', '$interval', 'io',
        function($rootScope, $q, $parse, $interval, io) {
            // We return this object to anything injecting our service
            var factory = {};
            var activePlayer = -1;
            var activePlaylist = -1;
            var volume = 0;

            factory.connect = function(url, port) {
                return io.connect(url, port);
            }

            factory.isConnected = function() {
                return io.isConnected();
            }

            factory.register = function(method, callback) {
                io.register(method, callback);
            }

            factory.unregister = function(method, callback) {
                io.unregister(method, callback);
            }

            factory.up = function() {
                io.send('Input.Up');
            };
            factory.down = function() {
                io.send('Input.Down');
            };
            factory.left = function() {
                io.send('Input.Left');
            };
            factory.right = function() {
                io.send('Input.Right');
            };
            factory.select = function() {
                io.send('Input.Select');
            };
            factory.back = function() {
                io.send('Input.Back');
            };
            factory.contextmenu = function() {
                io.send('Input.ContextMenu');
            };
            factory.info = function() {
                io.send('Input.Info');
            };
            factory.home = function() {
                io.send('Input.Home');
            };
            factory.sendText = function (textToSend) {
                io.send('Input.io.sendText', {'text' : textToSend});
            }
            factory.showOSD = function () {
                io.send('Input.ShowOSD');
            };

            factory.getActivePlayers = function(cb) {
                io.send('Player.GetActivePlayers', null, true, 'result').then(cb);
            };

            factory.setActivePlayer = function(playerId) {
                activePlayer = playerId;
            }

            factory.setActivePlaylist = function(playlistId) {
                activePlaylist = playlistId;
            }

            factory.getPlayerItem = function(cb, playerId) {
                playerId = playerId || activePlayer;
                io.send('Player.GetItem', {
                    'properties': ['title', 'artist', 'albumartist', 'genre',
                        'year', 'rating', 'album', 'track', 'duration', 'comment', 'lyrics',
                        'musicbrainztrackid', 'musicbrainzartistid', 'musicbrainzalbumid',
                        'musicbrainzalbumartistid', 'playcount', 'fanart', 'director', 'trailer',
                        'tagline', 'plot', 'plotoutline', 'originaltitle', 'lastplayed', 'writer',
                        'studio', 'mpaa', 'cast', 'country', 'imdbnumber', 'premiered', 'productioncode',
                        'runtime', 'set', 'showlink', 'streamdetails', 'top250', 'votes', 'firstaired',
                        'season', 'episode', 'showtitle', 'thumbnail', 'file', 'resume', 'artistid',
                        'albumid', 'tvshowid', 'setid', 'watchedepisodes', 'disc', 'tag', 'art', 'genreid',
                        'displayartist', 'albumartistid', 'description', 'theme', 'mood', 'style',
                        'albumlabel', 'sorttitle', 'episodeguide', 'uniqueid', 'dateadded', 'channel',
                        'channeltype', 'hidden', 'locked', 'channelnumber', 'starttime', 'endtime'
                    ],
                    'playerid': playerId
                }, true, 'result.item').then(cb);
            };

            factory.getPlayerProperties = function(cb) {
                io.send('Player.GetProperties', {
                    'properties': ['percentage', 'time', 'totaltime',
                        'speed', 'playlistid',
                        'currentsubtitle', 'subtitles',
                        'audiostreams', 'currentaudiostream', 'type'
                    ],
                    'playerid': activePlayer
                }, true, 'result').then(cb);
            };

            factory.goTo = function(index) {
                io.send('Player.GoTo', {
                    'playerid': activePlayer,
                    'to': index
                });
            };

            factory.next = function() {
                io.send('Player.GoTo', {
                    'playerid': activePlayer,
                    'to': 'next'
                });
            };

            factory.open = function(item) {
                io.send('Player.Open', {
                    'item': item
                });
            };

            factory.previous = function() {
                io.send('Player.GoTo', {
                    'playerid': activePlayer,
                    'to': 'previous'
                });
            };

            factory.togglePlay = function() {
                io.send('Player.PlayPause', {
                    'playerid': activePlayer
                });
            };

            factory.seek = function(newValue) {
                io.send('Player.Seek', {
                    'playerid': activePlayer,
                    'value': newValue
                });
            };

            factory.setAudioStream = function(audioStream) {
                io.send('Player.SetAudioStream', {
                    'playerid': activePlayer,
                    'stream': audioStream
                });
            };

            var subtitleState = null;
            factory.toggleSubtitles = function () {
                if(subtitleState === null) {
                    factory.setSubtitle('off');
                    subtitleState = 'off';
                } else {
                    factory.setSubtitle(1);
                    subtitleState = null;
                }

                factory.setSubtitle(1);
            },

            factory.setSubtitle = function(subtitle) {
                io.send('Player.SetSubtitle', {
                    'playerid': activePlayer,
                    'subtitle': subtitle,
                    'enable': true
                });
            };

            factory.setSpeed = function(speed) {
                io.send('Player.SetSpeed', {
                    'playerid': activePlayer,
                    'speed': speed
                });
            };

            factory.stop = function() {
                io.send('Player.Stop', {
                    'playerid': activePlayer
                });
            };

            (function getVolume(cb) {
                io.send('Application.GetProperties', {
                    'properties': ['volume']
                }, true, 'result.volume').then(function(value) {
                    volume = value;
                });
            })();

            factory.increaseVolume = function() {
                volume = Math.min(volume + 1, 100);
                io.send('Application.SetVolume', {
                    'volume': volume
                });
            };
            factory.decreaseVolume = function() {
                volume = Math.max(volume - 1, 0);
                io.send('Application.SetVolume', {
                    'volume':volume
                });
            };
            factory.mute = function() {
                io.send('Application.SetMute', {
                    'mute': 'toggle'
                });
            };

            factory.shutdown = function() {
                io.send('System.Shutdown');
            };

            factory.activateWindow = function(params) {
                io.send('GUI.ActivateWindow', params);
            };

            factory.getPlaylistItems = function(cb) {
                io.send('Playlist.GetItems', {
                    'playlistid': activePlaylist,
                    'properties': ['title', 'art', 'duration', 'runtime', 'thumbnail']
                }, true, 'result.items').then(cb);
            };

            factory.queue = function(item) {
                if (activePlaylist > -1) {
                    io.send('Playlist.Add', {
                        'playlistid': activePlaylist,
                        'item': item
                    });
                }
            };

            factory.getMovies = function(cb) {
                io.send('VideoLibrary.GetMovies', {
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'properties': ['title', 'genre', 'rating', 'thumbnail', 'runtime', 'playcount', 'streamdetails'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    }
                }, true, 'result.movies').then(cb);
            };

            factory.getMovieDetails = function(movieId, cb) {
                io.send('VideoLibrary.GetMovieDetails', {
                    'properties': ['title', 'genre', 'rating', 'thumbnail', 'plot',
                        'studio', 'director', 'fanart', 'runtime', 'trailer', 'imdbnumber'
                    ],
                    'movieid': movieId
                }, true, 'result.moviedetails').then(cb);

            };

            factory.getAlbums = function(filter, cb) {
                var params = {
                    'limits': {
                        'start': 0,
                        'end': 100
                    },
                    'properties': ['title', 'artist', 'thumbnail', 'year', 'genre'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    },
                };
                if (filter && filter.key) {
                    params.filter = {};
                    params.filter[filter.key] = filter.value;
                }
                io.send('AudioLibrary.GetAlbums', params, true, 'result.albums').then(cb);
            };

            factory.getArtists = function(cb) {
                io.send('AudioLibrary.GetArtists', {
                    'limits': {
                        'start': 0,
                        'end': 100
                    },
                    'properties': ['genre', 'thumbnail'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    }
                }, true, 'result.artists').then(cb);

            };

            factory.getSongs = function(filter, cb) {
                var params = {
                    'limits': {
                        'start': 0,
                        'end': 500
                    },
                    'properties': ['title', 'artist', 'album', 'albumid', 'thumbnail', 'duration', 'track', 'year'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label',
                        'ignorearticle': true
                    }
                };
                if (filter && filter.key) {
                    params.filter = {};
                    params.filter[filter.key] = filter.value;
                    params.sort.method = 'track';
                }
                io.send('AudioLibrary.GetSongs', params, true, 'result.songs').then(cb);
            };

            factory.getTVShows = function(cb) {
                io.send('VideoLibrary.GetTVShows', {
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'properties': ['genre', 'title', 'rating', 'art', 'playcount'],
                    'sort': {
                        'order': 'ascending',
                        'method': 'label'
                    }
                }, true, 'result.tvshows').then(cb);
            };
            factory.getSeasons = function(tvShowId, cb) {
                io.send('VideoLibrary.GetSeasons', {
                    'tvshowid': tvShowId,
                    'properties': ['season', 'showtitle', 'fanart', 'thumbnail'],
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'sort': {
                        'order': 'ascending',
                        'method': 'label'
                    }
                }, true, 'result.seasons').then(cb);
            };
            factory.getEpisodes = function(tvShowId, season, cb) {
                io.send('VideoLibrary.GetEpisodes', {
                    'tvshowid': tvShowId,
                    'season': season,
                    'properties': ['title', 'rating', 'firstaired', 'runtime', 'season', 'episode', 'thumbnail', 'art'],
                    'limits': {
                        'start': 0,
                        'end': 75
                    },
                    'sort': {
                        'order': 'ascending',
                        'method': 'label'
                    }
                }, true, 'result.episodes').then(cb);
            };
            factory.getEpisodeDetails = function(episodeId, cb) {
                io.send('VideoLibrary.GetEpisodeDetails', {
                    'episodeid': episodeId,
                    'properties': ['title', 'plot', 'rating', 'firstaired', 'runtime', 'thumbnail', 'art']
                }, true, 'result.episodedetails').then(cb);
            };

            return factory;
        }
    ])<|endoftext|>


<commit_before>$(function() {
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  var ctx = new AudioContext();

  var handleStart = function(event) {
    var request;
    var zhtext;
    var pinyin;
    var num;
    var anshtml;
    var mp3elmid;
    zhtext = $(event.target).data('zh');
    pinyin = $(event.target).data('pinyin');
    num = $(event.target).data('num');
    if(zhtext) {
      $(event.target).css('border', '2px solid #000');
      anshtml = '';
      if(pinyin) {
        anshtml = anshtml + '<ruby>' + zhtext + '<rt>' + pinyin + '</rt></ruby>';
      } else {
        anshtml = anshtml + zhtext;
      }
      mp3elmid = 'mp3elm_' + num;
      anshtml = anshtml + '
-';
      $(event.target).html(anshtml);
      $(event.target).off('touchstart', handleStart);

      // ----------------------------------------
      // 音声MP3データのダウンロード
      // ----------------------------------------
      var elm = document.getElementById(mp3elmid);
      var mp3 = "/mp3/" + zhtext + ".mp3";
      var xhr = new XMLHttpRequest();

      xhr.open('GET', mp3, true);
      xhr.responseType = "arraybuffer";
      xhr.onload = function () {
        if(xhr.status == 200) {
          $(elm).html('');
          $(elm).click(function() {
            var src = ctx.createBufferSource();
            // オーディオをデコード
            ctx.decodeAudioData(xhr.response, function (buf) {
              src.buffer = buf;
              src.loop = false;
              src.connect(ctx.destination);
              src.start(0);
            });
          });
        }
      };
      xhr.send(null);

      // ----------------------------------------
      // 15秒後に表示を元に戻す
      // ----------------------------------------
      setTimeout(function() {
        $(event.target).html($(event.target).data('jp'));
        $(event.target).css('border', '2px solid #fff');
        $(event.target).on('touchstart', handleStart);
        ctx.close();
      }, 15000);
    }
  };

  var handleEnd = function(event) {
    $(event.target).html($(event.target).data('jp'));
    $(document).off('touchend', handleEnd);
  };

  var q = $.url().param().q;
  var wordsjson = "y7words.json";
  if(q)
    wordsjson = q;

  var time1;
  time1 = new Date();
  $.getJSON("json/" + wordsjson + "?" + time1.getTime(), function(words) {
    var i, cnt, template;
    cnt = 0;
    for(i = 0; i < words.length; i++) {
      if(words[i] && words[i][0] && words[i][0]!=='END') {
        cnt = cnt + 1;
        if(words[i][1]) {
          template = '';
          template = template + '
';
          template = template + '
' + words[i][0];
          template = template + '
';
          template = template + '
';
        } else {
          template = '
' + words[i][0] + '
';
        }
        $("main").append(template);
      }
      $("#navbar1").text(cnt);
    }
    $(".word").on('touchstart', handleStart);
    $(".word").on('click', handleStart);
  });

  //iOS版
  var request;
  var status = 0;

  function downloadMP3(zhtext) {
    request = new XMLHttpRequest();
    request.open("GET", "/mp3/" + zhtext + ".mp3", true);
    request.responseType = "arraybuffer";
    request.onload = completeOnLoad;
    request.send();
  }

  function clickPlay() {
    if (status == 0) {
      status = 1;
      request = new XMLHttpRequest();
      request.open("GET", "/mp3/出口仓库.mp3", true);
      request.responseType = "arraybuffer";
      request.onload = completeOnLoad;
      request.send();
    } else if (status == 2) {
      window.AudioContext = window.AudioContext || window.webkitAudioContext;
      context = new AudioContext();

      source = context.createBufferSource();

      // オーディオをデコード
      context.decodeAudioData(request.response, function (buf) {
        source.buffer = buf;
        source.loop = false;
        source.connect(context.destination);
        source.start(0);
      });
    }
  };

  function completeOnLoad() {
    status = 2;
    var elem = document.getElementById("mp3play1");
    elem.innerText = "再生";
  }

  $("#mp3play1").click(clickPlay);

});
<commit_msg>2019-01-09<commit_after>$(function() {
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  var ctx = new AudioContext();

  var handleStart = function(event) {
    var request;
    var zhtext;
    var pinyin;
    var num;
    var anshtml;
    var mp3elmid;
    zhtext = $(event.target).data('zh');
    pinyin = $(event.target).data('pinyin');
    num = $(event.target).data('num');
    if(zhtext) {
      $(event.target).css('border', '2px solid #000');
      anshtml = '';
      if(pinyin) {
        anshtml = anshtml + '<ruby>' + zhtext + '<rt>' + pinyin + '</rt></ruby>';
      } else {
        anshtml = anshtml + zhtext;
      }
      mp3elmid = 'mp3elm_' + num;
      anshtml = anshtml + '
-';
      $(event.target).html(anshtml);
      $(event.target).off('touchstart', handleStart);

      // ----------------------------------------
      // 音声MP3データのダウンロード
      // ----------------------------------------
      var elm = document.getElementById(mp3elmid);
      var mp3 = "/mp3/" + zhtext + ".mp3";
      var xhr = new XMLHttpRequest();

      xhr.open('GET', mp3, true);
      xhr.responseType = "arraybuffer";
      xhr.onload = function () {
        if(xhr.status == 200) {
          $(elm).html('');
          $(elm).click(function() {
            var src = ctx.createBufferSource();
            // オーディオをデコード
            ctx.decodeAudioData(xhr.response, function (buf) {
              src.buffer = buf;
              src.loop = false;
              src.connect(ctx.destination);
              src.start(0);
            });
          });
        }
      };
      xhr.send(null);

      // ----------------------------------------
      // 15秒後に表示を元に戻す
      // ----------------------------------------
      setTimeout(function() {
        $(event.target).html($(event.target).data('jp'));
        $(event.target).css('border', '2px solid #fff');
        $(event.target).on('touchstart', handleStart);
        ctx.close();
      }, 15000);
    }
  };

  var handleEnd = function(event) {
    $(event.target).html($(event.target).data('jp'));
    $(document).off('touchend', handleEnd);
  };

  var q = $.url().param().q;
  var wordsjson = "y7words.json";
  if(q)
    wordsjson = q;

  var time1;
  time1 = new Date();
  $.getJSON("json/" + wordsjson + "?" + time1.getTime(), function(words) {
    var i, cnt, template;
    cnt = 0;
    for(i = 0; i < words.length; i++) {
      if(words[i] && words[i][0] && words[i][0]!=='END') {
        cnt = cnt + 1;
        if(words[i][1]) {
          template = '';
          template = template + '
';
          template = template + '
' + words[i][0];
          template = template + '
';
          template = template + '
';
        } else {
          template = '
' + words[i][0] + '
';
        }
        $("main").append(template);
      }
      $("#navbar1").text(cnt);
    }
    $(".word").on('touchstart', handleStart);
    $(".word").on('click', handleStart);
  });
});
<|endoftext|>


<commit_before>b6b47f9c-973a-11e6-b514-8086f2004150<commit_msg>having coffee<commit_after>b6b51344-973a-11e6-b514-8086f2004150<|endoftext|>