<commit_before>'use strict';

let L = require('leaflet');
let EsriLeaflet = require('esri-leaflet');
let Proj4Leaflet = require('proj4leaflet');
require('leaflet-fullscreen');
require('leaflet.heat/dist/leaflet-heat');

// http://kartena.github.io/Proj4Leaflet/examples/wmts/
// http://kartena.github.io/Proj4Leaflet/examples/wmts/script.js
// Using-LDS-XYZ-tile-services-in-Leaflet-and-OpenLayers.pdf

// Inject esri and Proj4Leaflet plugins into Leaflet's L
L.esri = EsriLeaflet;
L.Proj = Proj4Leaflet;
L.Icon.Default.imagePath = '/assets/images';

let NpolarEsriLeaflet = function($http, $location, NpolarMessage) {
  'ngInject';

  let self = this;

  const EPSG = 53032;

  this.element = 'npolar-esri-leaflet-map'; // The map's html element @id

  this.base = '//geodata.npolar.no/arcgis/rest/services';

  this.uri = function(arg={ epsg: EPSG }) {
    let uri = self.base.replace(/\/$/, '');

    if (arg && arg.epsg) {
      let epsg = parseInt(arg.epsg);

      if (epsg === 25833) {
        uri += `/Basisdata/NP_Basiskart_Svalbard_WMTS_25833/MapServer`;
      } else if (epsg === 32661) {
        uri += `/Basisdata_Intern/NP_Arktis_WMTS_32661/MapServer`;
      } else if (epsg === 53032) {
        uri += `/Basisdata_Intern/NP_Verden_WMTS_53032/MapServer`;
      } else if (epsg === 4326) {
        // FIXME Use ESRI?
        uri += '';
      } else {
        console.error(`Unsupported EPSG ${epsg}`);
      }
      //console.log('epsg', epsg, '->', uri);
    }

    return uri;
  };

  // @return instance of Proj4Leaflet CRS (L.Proj.CRS)
  this.crsFactory = function(uri) {

    let crs;
    let path = uri.split(`${self.base}`)[1];

    if ($location.search().debug) {
      console.log(`${this.base}${path} debug info`);
      $http.get(`${this.base}${path}?f=json`).then(r => {
        console.log('spatialReference', r.data.spatialReference.wkid);
        let lods = r.data.tileInfo.lods;
        console.log('resolutions', lods.map(l => l.resolution));
        console.log('scales', lods.map(l => l.scale));
        console.log('levels', lods.map(l => l.level));
      });
    }

    if ((/(NP_Basiskart_Svalbard_WMTS_25833|NP_Nordomraadene_WMTS_25833|25833)/).test(path)) {
      crs = self.UTM_33N_CRSFactory();

    } else if ((/(NP_Arktis_WMTS_32661|NP_TopoArktis_UPSN_CLX|32661)/).test(path)) {
      crs = self.UPSN_CRSFactory();

    } else if ((/NP_Verden_WMTS_53032|53032/).test(path)) {
      crs = self.WMTS_53032_CRSFactory();

    } else if (/102016/.test(path)) {
      crs = self.EPSG_102016_CRSFactory();

    } else {
      crs = new L.Proj.CRS("EPSG:4326","+proj=longlat +datum=WGS84 +no_defs");
    }

    return crs;
  };

  // Polar stereographic north / WGS84
  // Projection definition for EPSG:32661 from http://epsg.io/32661.js
  this.UPSN_CRSFactory = function() {

    return new L.Proj.CRS(
      'EPSG:32661',
      '+proj=stere +lat_0=90 +lat_ts=90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs ',
      {
        transformation: new L.Transformation(1, 5120900, -1, 9998100),
        resolutions: [
          21674.7100160867,
          10837.35500804335,
          5418.677504021675,
          2709.3387520108377,
          1354.6693760054188,
          677.3346880027094,
          338.6673440013547,
          169.33367200067735,
          84.66683600033868,
          42.33341800016934
        ]
      }
    );
  };

  // UTM zone 33N / ETRS89
  // Projection definition for EPSG:25833 from http://epsg.io/25833.js
  this.UTM_33N_CRSFactory = function() {
    return new L.Proj.CRS(
      'EPSG:25833',
      '+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs',
      {
        transformation: new L.Transformation(1, 5120900, -1, 9998100),
        resolutions: [21674.7100160867,10837.35500804335,5418.677504021675,2709.3387520108377,1354.6693760054188,677.3346880027094,338.6673440013547,169.33367200067735,84.66683600033868,42.33341800016934,21.16670900008467,10.583354500042335,5.291677250021167,2.6458386250105836,1.3229193125052918,0.6614596562526459,0.33072982812632296,0.16536491406316148]
      }
    );
  };

  // ESRI:53032
  // Sphere Azimuthal Equidistant
  this.WMTS_53032_CRSFactory = function () {
    let resolutions = [173397.6801286936, 86698.8400643468, 43349.4200321734, 21674.7100160867, 10837.35500804335, 5418.677504021675, 2709.3387520108377, 1354.6693760054188, 677.3346880027094, 338.6673440013547];
    let origin = [-21986016.870795302, 21986016.870795317];

    return new L.Proj.CRS(
      'EPSG:53032', // or ESRI:53032?
      '+proj=aeqd +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs',
      {
        transformation: new L.Transformation(1, -21986016.870795302, -1, 21986016.870795317),
        resolutions,
        origin
      }
    );
  };

  this.EPSG_102016_CRSFactory = function () {
    let resolutions = [43349.4200321734, 21674.7100160867, 10837.35500804335, 5418.677504021675, 2709.3387520108377];
    let levels = [0, 1, 2, 3, 4];
    let origin = [-20004100, 20004100];

    return new L.Proj.CRS(
      'EPSG:102016', //http://epsg.io/102016.js
      '+proj=aeqd +lat_0=90 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs',
      {
        transformation: new L.Transformation(1, -20004100, -1, 20004100),
        resolutions,
        origin,
        levels
      }
    );
  };

  this.esriBaseUri = function() {
    return self.uri({ epsg: EPSG });
  };

  this.heatLayerFactory = function(points, heatConfig = {
    minOpacity: 0.9,
    useLocalExtrema: true,
    scaleRadius: true,
    radius: 6,
    }) {
    return L.heatLayer(points, heatConfig);
  };

  this.tileLayerFactory = function(esriBase = self.esriBaseUri(), config = {
    url: esriBase,
    //maxZoom: 7,
    //minZoom: 2,
    continuousWorld: true,
    attribution: null }) {

    return new L.esri.tiledMapLayer(config);
  };

  this.mapFactory = function(esriBase = self.esriBaseUri(), mapConfig={
      attributionControl: true,
      scrollWheelZoom: true,
      fullscreenControl: true,
      crs: self.crsFactory(esriBase)
    }, tileLayerConfig = undefined) {

    let map = new L.Map(self.element, mapConfig);
    map.addLayer(self.tileLayerFactory(esriBase, tileLayerConfig));
    map.setView([80, 0], 0);

    // Disable zoom handlers.
    map.touchZoom.disable();
    map.doubleClickZoom.disable();
    map.scrollWheelZoom.disable();
    map.keyboard.disable();

    return map;
  };

  return this;
};

module.exports = NpolarEsriLeaflet;<commit_msg>Yet-another fix for changing map services (UPSN)<commit_after>'use strict';

let L = require('leaflet');
let EsriLeaflet = require('esri-leaflet');
let Proj4Leaflet = require('proj4leaflet');
require('leaflet-fullscreen');
require('leaflet.heat/dist/leaflet-heat');

// http://kartena.github.io/Proj4Leaflet/examples/wmts/
// http://kartena.github.io/Proj4Leaflet/examples/wmts/script.js
// Using-LDS-XYZ-tile-services-in-Leaflet-and-OpenLayers.pdf

// Inject esri and Proj4Leaflet plugins into Leaflet's L
L.esri = EsriLeaflet;
L.Proj = Proj4Leaflet;
L.Icon.Default.imagePath = '/assets/images';

let NpolarEsriLeaflet = function($http, $location, NpolarMessage) {
  'ngInject';

  let self = this;

  const EPSG = 4326;

  this.element = 'npolar-esri-leaflet-map'; // The map's html element @id

  this.base = '//geodata.npolar.no/arcgis/rest/services';

  this.uri = function(arg={ epsg: EPSG }) {
    let uri = self.base.replace(/\/$/, '');

    if (arg && arg.epsg) {
      let epsg = parseInt(arg.epsg);

      if (epsg === 25833) {
        uri += `/Basisdata/NP_Basiskart_Svalbard_WMTS_25833/MapServer`;
      } else if (epsg === 32661) {
        uri += `/Basisdata_Intern/NP_Arktis_WMTS_32661/MapServer`;
      } else if (epsg === 53032) {
        uri += `/Basisdata_Intern/NP_Verden_WMTS_53032/MapServer`;
      } else if (epsg === 4326) {
        // FIXME Use ESRI?
        uri += `/Basisdata_Intern/NP_Verden_WMTS_4326/MapServer`;
      } else {
        console.error(`Unsupported EPSG ${epsg}`);
      }
      console.log('epsg', epsg, '->', uri);
    }
    return uri;
  };

  // @return instance of Proj4Leaflet CRS (L.Proj.CRS)
  this.crsFactory = function(uri) {
    let crs;
    let path = uri.split(`${self.base}`)[1];

    if ((/(WMTS_25833|25833)/).test(path)) {
      crs = self.UTM_33N_CRSFactory();

    } else if ((/(WMTS_32661|UPSN|32661)/).test(path)) {
      crs = self.UPSN_CRSFactory();

    } else if ((/53032/).test(path)) {
      crs = self.WMTS_53032_CRSFactory();

    } else {
      crs = null; //new L.Proj.CRS("EPSG:4326","+proj=longlat +datum=WGS84 +no_defs");
    }
    return crs;
  };

  // Polar stereographic north / WGS84
  // Projection definition for EPSG:32661 from http://epsg.io/32661.js
  // http://jsfiddle.net/12c9vheh/22/
  this.UPSN_CRSFactory = function() {
    console.log("EPSG:32661 CRS factory");
    let resolutions = [21674.7100160867, 10837.35500804335, 5418.677504021675, 2709.3387520108377, 1354.6693760054188, 677.3346880027094, 338.6673440013547, 169.33367200067735, 84.66683600033868, 42.33341800016934];
    let transformation = new L.Transformation(1, 28567900, -1, 32567900);
    return new L.Proj.CRS('EPSG:32661','+proj=stere +lat_0=90 +lat_ts=90 +lon_0=0 +k=0.994 +x_0=2000000 +y_0=2000000 +ellps=WGS84 +datum=WGS84 +units=m +no_defs',
      {transformation, resolutions});
  };

  // UTM zone 33N / ETRS89
  // Projection definition for EPSG:25833 from http://epsg.io/25833.js
  // http://jsfiddle.net/9ozgfLg7/125/
  this.UTM_33N_CRSFactory = function() {
    return new L.Proj.CRS(
      'EPSG:25833',
      '+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs',
      {
        transformation: new L.Transformation(1, 5120900, -1, 9998100),
        resolutions: [21674.7100160867,10837.35500804335,5418.677504021675,2709.3387520108377,1354.6693760054188,677.3346880027094,338.6673440013547,169.33367200067735,84.66683600033868,42.33341800016934,21.16670900008467,10.583354500042335,5.291677250021167,2.6458386250105836,1.3229193125052918,0.6614596562526459,0.33072982812632296,0.16536491406316148]
      }
    );
  };

  // ESRI:53032
  // Sphere Azimuthal Equidistant
  this.WMTS_53032_CRSFactory = function () {
    let resolutions = [173397.6801286936, 86698.8400643468, 43349.4200321734, 21674.7100160867, 10837.35500804335, 5418.677504021675, 2709.3387520108377, 1354.6693760054188, 677.3346880027094, 338.6673440013547];
    let origin = [-21986016.870795302, 21986016.870795317];

    return new L.Proj.CRS(
      'EPSG:53032', // or ESRI:53032?
      '+proj=aeqd +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs',
      {
        transformation: new L.Transformation(1, -21986016.870795302, -1, 21986016.870795317),
        resolutions,
        origin
      }
    );
  };

  this.esriBaseUri = function() {
    return self.uri({ epsg: EPSG });
  };

  this.heatLayerFactory = function(points, heatConfig = {
    minOpacity: 0.9,
    useLocalExtrema: true,
    scaleRadius: true,
    radius: 6,
    }) {
    return L.heatLayer(points, heatConfig);
  };

  this.tileLayerFactory = function(esriBase = self.esriBaseUri(), config = {
    url: esriBase,
    //maxZoom: 7,
    //minZoom: 2,
    continuousWorld: true,
    attribution: null }) {

    return new L.esri.tiledMapLayer(config);
  };

  this.mapFactory = function(esriBase = self.esriBaseUri(), mapConfig={
      attributionControl: true,
      scrollWheelZoom: true,
      fullscreenControl: true,
      crs: self.crsFactory(esriBase)
    }, tileLayerConfig = undefined) {

    let map = new L.Map(self.element, mapConfig);
    map.addLayer(self.tileLayerFactory(esriBase, tileLayerConfig));
    map.setView([80, 0], 0);

    // Disable zoom handlers.
    map.touchZoom.disable();
    map.doubleClickZoom.disable();
    map.scrollWheelZoom.disable();
    map.keyboard.disable();

    return map;
  };

  return this;
};

module.exports = NpolarEsriLeaflet;<|endoftext|>


<commit_before>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      27.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('logger.js');

/**
 * @class
 *
 * The root class for every controller.
 *
 */
M.Controller = M.Object.extend({

    lookupTable: null,

    lookupTableLoaded: NO,

    switchToView: function(view) {
        if(!this.lookupTableLoaded) {
            M.Logger.log('lookupTableLoaded');
            this.lookupTable = M.Controller.lookupTable;
            this.lookupTableLoaded = YES;
        }
        if(this.lookupTable) {
            if(this.lookupTable[view]) {
                location.href = location.href.substr(0, location.href.lastIndexOf('#')) + '#' + this.lookupTable[view];
            } else {
                M.Logger.log('"' + view + '" not found in lookupTable', M.ERROR);
            }
        } else {
            M.Logger.log('lookupTable undefined', M.ERROR);
        }
    }

});<commit_msg>Added an observable property and get/set-methods for data binding<commit_after>// ==========================================================================
// Project:   The M-Project - Mobile HTML5 Application Framework
// Copyright: 2010 M-Way Solutions GmbH. All rights reserved.
// Creator:   Dominik
// Date:      27.10.2010
// License:   Dual licensed under the MIT or GPL Version 2 licenses.
//            http://github.com/mwaylabs/The-M-Project/blob/master/MIT-LICENSE
//            http://github.com/mwaylabs/The-M-Project/blob/master/GPL-LICENSE
// ==========================================================================

m_require('observable.js');

/**
 * @class
 *
 * The root class for every controller.
 *
 */
M.Controller = M.Object.extend({

    lookupTable: null,

    lookupTableLoaded: NO,

    observable: M.Observable.extend({}),

    switchToView: function(view) {
        if(!this.lookupTableLoaded) {
            //M.Logger.log('lookupTableLoaded');
            this.lookupTable = M.Controller.lookupTable;
            this.lookupTableLoaded = YES;
        }
        if(this.lookupTable) {
            if(this.lookupTable[view]) {
                location.href = location.href.substr(0, location.href.lastIndexOf('#')) + '#' + this.lookupTable[view];
            } else {
                //M.Logger.log('"' + view + '" not found in lookupTable', M.ERROR);
            }
        } else {
            //M.Logger.log('lookupTable undefined', M.ERROR);
        }
    },

    /**
     * Returns the class property behind the given key and informs its observers.
     *
     * @param {String} key The key of the property to be changed.
     * @param {Object, String} value The value to be set.
     */
    set: function(key, value) {
        this[key] = value;
        for(entry in this.observable.bindingList) {
            alert(this.observable.bindingList[entry].observable);
            if(key == this.observable.bindingList[entry].observable) {
                //this.observable.bindingList[entry].observer.update();
                /* DO SOME UPDATE-SHIT */
            }
        }
    }

});<|endoftext|>


<commit_before>var events = require("events"),
    util = require("util");

var Map = require("./map");

var Game = module.exports = function Game() {
  events.EventEmitter.call(this);

  this.clients = [];
  this.players = [];
  this.map = new Map();

  this.last_eid = 0;

  this.name = "Minecraft.JS";
  this.max_players = 25;
  this.mode = 0;
  this.difficulty = 0;

  this.world = {
    type: "flat",
    dimension: 0,
  };

  this.tick = setInterval(this.emit.bind(this, "tick"), 100);
};
util.inherits(Game, events.EventEmitter);

Game.prototype.get_eid = function get_eid() {
  return this.last_eid++;
};

Game.prototype.add_client = function add_client(client) {
  this.clients.push(client);

  this.emit("client:connect", client);
  client.emit("game:connect", this);

  client.on("close", this.remove_client.bind(this, client));
};

Game.prototype.remove_client = function remove_client(client) {
  var index = this.clients.indexOf(client);

  if (index !== -1) {
    this.clients.splice(index, 1);
  }

  this.emit("client:disconnect", client);
  client.emit("game:disconnect", this);
};

Game.prototype.add_player = function add_player(player) {
  this.players.push(player);

  this.emit("player:join", player);
  player.emit("game:join", this);
};

Game.prototype.remove_player = function remove_player(player) {
  var index = this.players.indexOf(player);

  if (index !== -1) {
    this.players.splice(index, 1);
  }

  this.emit("player:leave", player);
  player.emit("game:leave", this);
};
<commit_msg>made Game a little more configurable<commit_after>var events = require("events"),
    util = require("util");

var Map = require("./map");

var Game = module.exports = function Game(config) {
  events.EventEmitter.call(this);

  if (!config) {
    config = {};
  }

  this.clients = [];
  this.players = [];
  this.map = config.map || new Map();

  this.last_eid = 0;

  this.name = config.name || "Minecraft.JS";
  this.max_players = config.max_players || 25;
  this.mode = config.mode || 0;
  this.difficulty = config.difficulty || 0;

  this.world = {
    type: "flat",
    dimension: 0,
  };

  this.tick = setInterval(this.emit.bind(this, "tick"), 100);
};
util.inherits(Game, events.EventEmitter);

Game.prototype.get_eid = function get_eid() {
  return this.last_eid++;
};

Game.prototype.add_client = function add_client(client) {
  this.clients.push(client);

  this.emit("client:connect", client);
  client.emit("game:connect", this);

  client.on("close", this.remove_client.bind(this, client));
};

Game.prototype.remove_client = function remove_client(client) {
  var index = this.clients.indexOf(client);

  if (index !== -1) {
    this.clients.splice(index, 1);
  }

  this.emit("client:disconnect", client);
  client.emit("game:disconnect", this);
};

Game.prototype.add_player = function add_player(player) {
  this.players.push(player);

  this.emit("player:join", player);
  player.emit("game:join", this);
};

Game.prototype.remove_player = function remove_player(player) {
  var index = this.players.indexOf(player);

  if (index !== -1) {
    this.players.splice(index, 1);
  }

  this.emit("player:leave", player);
  player.emit("game:leave", this);
};
<|endoftext|>


<commit_before>'use strict';

exports.SAVINGS_THRESHOLD = 8000;
exports.VALUABLES_MINIMUM = 500;

exports.CATEGORIES_OF_LAW = [
  {
    value: 'clinneg',
    name: 'Clinical negligence',
    covered: false
  },
  {
    value: 'commcare',
    name: 'Community care',
    covered: false
  },
  {
    value: 'debt',
    name: 'Debt',
    covered: true
  },
  {
    value: 'discrimination',
    name: 'Discrimination',
    covered: true
  },
  {
    value: 'education',
    name: 'Education',
    covered: true
  },
  {
    value: 'family',
    name: 'Family',
    covered: true
  },
  {
    value: 'housing',
    name: 'Housing',
    covered: true
  },
  {
    value: 'immigration',
    name: 'Immigration and asylum',
    covered: false
  },
  {
    value: 'mentalhealth',
    name: 'Mental health',
    covered: false
  },
  {
    value: 'pi',
    name: 'Personal injury',
    covered: false
  },
  {
    value: 'publiclaw',
    name: 'Public law',
    covered: false
  },
  {
    value: 'aap',
    name: 'Trouble with the police',
    covered: false
  },
  {
    value: 'violence',
    name: 'Domestic violence',
    covered: true
  },
  {
    value: 'benefits',
    name: 'Welfare benefits appeals',
    covered: true
  }
];

exports.ABOUT_YOU_QUESTIONS = [
  'have_partner',
  'in_dispute',
  'on_benefits',
  'have_children',
  'have_dependants',
  'have_savings',
  'have_valuables',
  'own_property',
  'is_employed',
  'is_self_employed',
  'aged_60_or_over'
];

exports.PROPERTY_QUESTIONS = [
  'properties-0-is_main_home',
  'properties-0-other_shareholders',
  'properties-0-is_rented',
  'properties-0-in_dispute'
];

exports.BENEFITS = [
  'income_support',
  'job_seekers_allowance',
  'pension_credit',
  'universal_credit',
  'employment_support',
  'other-benefit'
];

exports.SAVINGS_QUESTIONS = {
  MONEY: [
    {
      name: 'savings',
      errorText: 'Enter 0 if you have no savings'
    },
    {
      name: 'investments',
      errorText: 'Enter 0 if you have no investments'
    }
  ],
  VALUABLES: [
    {
      name: 'valuables',
      errorText: 'Enter 0 if you have no valuables'
    }
  ]
};

exports.EMPLOYMENT_QUESTIONS = {
  COMMON: [
    'maintenance',
    'pension',
    'other_income'
  ],
  EMPLOYED_MANDATORY: [
    'earnings',
    'income_tax',
    'national_insurance'
  ],
  EMPLOYED_OPTIONAL: [
    'working_tax_credit'
  ]
};

exports.CHILD_BENEFIT_QUESTIONS = [
  'child_benefit',
  'child_tax_credit'
];

exports.OUTGOINGS_QUESTIONS = [
  'rent',
  'maintenance',
  'childcare'
];

exports.INELIGIBLE_OUTCOMES = [
  {
    category: {
      label: 'Debt',
      value: 'debt'
    },
    link: {
      text: 'Advice Guide',
      href: 'http://www.adviceguide.org.uk'
    }
  },
  {
    category: {
      label: 'Domestic violence',
      value: 'violence'
    },
    link: {
      text: 'Child Maintenance Options',
      href: 'http://www.cmoptions.org/'
    }
  },
  {
    category: {
      label: 'Discrimination',
      value: 'discrimination'
    },
    link: {
      text: 'Equality Advisory Support Service',
      href: 'http://www.equalityadvisoryservice.com/'
    }
  },
  {
    category: {
      label: 'Education',
      value: 'education'
    },
    link: {
      text: 'Independent Parental Special Education Advice (IPSEA)',
      href: 'http://www.ipsea.org.uk'
    }
  },
  {
    category: {
      label: 'Family',
      value: 'family'
    },
    link: {
      text: 'Child Maintenance Options',
      href: 'http://www.cmoptions.org/'
    }
  },
  {
    category: {
      label: 'Housing',
      value: 'housing'
    },
    link: {
      text: 'Law Centre Network',
      href: 'http://www.lawcentres.org.uk/'
    }
  },
  {
    category: {
      label: 'Welfare benefits',
      value: 'benefits'
    },
    link: {
      text: 'Advice Guide',
      href: 'http://www.adviceguide.org.uk'
    }
  }
];
<commit_msg>fix test<commit_after>'use strict';

exports.SAVINGS_THRESHOLD = 8000;
exports.VALUABLES_MINIMUM = 500;

exports.CATEGORIES_OF_LAW = [
  {
    value: 'clinneg',
    name: 'Clinical negligence',
    covered: false
  },
  {
    value: 'commcare',
    name: 'Community care',
    covered: false
  },
  {
    value: 'debt',
    name: 'Debt',
    covered: true
  },
  {
    value: 'discrimination',
    name: 'Discrimination',
    covered: true
  },
  {
    value: 'education',
    name: 'Education',
    covered: true
  },
  {
    value: 'family',
    name: 'Family',
    covered: true
  },
  {
    value: 'housing',
    name: 'Housing',
    covered: true
  },
  {
    value: 'immigration',
    name: 'Immigration and asylum',
    covered: false
  },
  {
    value: 'mentalhealth',
    name: 'Mental health',
    covered: false
  },
  {
    value: 'pi',
    name: 'Personal injury',
    covered: false
  },
  {
    value: 'publiclaw',
    name: 'Public law',
    covered: false
  },
  {
    value: 'aap',
    name: 'Trouble with the police',
    covered: false
  },
  {
    value: 'violence',
    name: 'Domestic violence',
    covered: true
  },
  {
    value: 'benefits',
    name: 'Welfare benefits appeals',
    covered: true
  }
];

exports.ABOUT_YOU_QUESTIONS = [
  'have_partner',
  'in_dispute',
  'on_benefits',
  'have_children',
  'have_dependants',
  'have_savings',
  'have_valuables',
  'own_property',
  'is_employed',
  'is_self_employed',
  'aged_60_or_over'
];

exports.PROPERTY_QUESTIONS = [
  'properties-0-is_main_home',
  'properties-0-other_shareholders',
  'properties-0-is_rented',
  'properties-0-in_dispute'
];

exports.BENEFITS = [
  'income_support',
  'job_seekers_allowance',
  'pension_credit',
  'universal_credit',
  'employment_support',
  'other-benefit'
];

exports.SAVINGS_QUESTIONS = {
  MONEY: [
    {
      name: 'savings',
      errorText: 'Enter 0 if you have no savings'
    },
    {
      name: 'investments',
      errorText: 'Enter 0 if you have no investments'
    }
  ],
  VALUABLES: [
    {
      name: 'valuables',
      errorText: 'Valuable items must be at least £500'
    }
  ]
};

exports.EMPLOYMENT_QUESTIONS = {
  COMMON: [
    'maintenance',
    'pension',
    'other_income'
  ],
  EMPLOYED_MANDATORY: [
    'earnings',
    'income_tax',
    'national_insurance'
  ],
  EMPLOYED_OPTIONAL: [
    'working_tax_credit'
  ]
};

exports.CHILD_BENEFIT_QUESTIONS = [
  'child_benefit',
  'child_tax_credit'
];

exports.OUTGOINGS_QUESTIONS = [
  'rent',
  'maintenance',
  'childcare'
];

exports.INELIGIBLE_OUTCOMES = [
  {
    category: {
      label: 'Debt',
      value: 'debt'
    },
    link: {
      text: 'Advice Guide',
      href: 'http://www.adviceguide.org.uk'
    }
  },
  {
    category: {
      label: 'Domestic violence',
      value: 'violence'
    },
    link: {
      text: 'Child Maintenance Options',
      href: 'http://www.cmoptions.org/'
    }
  },
  {
    category: {
      label: 'Discrimination',
      value: 'discrimination'
    },
    link: {
      text: 'Equality Advisory Support Service',
      href: 'http://www.equalityadvisoryservice.com/'
    }
  },
  {
    category: {
      label: 'Education',
      value: 'education'
    },
    link: {
      text: 'Independent Parental Special Education Advice (IPSEA)',
      href: 'http://www.ipsea.org.uk'
    }
  },
  {
    category: {
      label: 'Family',
      value: 'family'
    },
    link: {
      text: 'Child Maintenance Options',
      href: 'http://www.cmoptions.org/'
    }
  },
  {
    category: {
      label: 'Housing',
      value: 'housing'
    },
    link: {
      text: 'Law Centre Network',
      href: 'http://www.lawcentres.org.uk/'
    }
  },
  {
    category: {
      label: 'Welfare benefits',
      value: 'benefits'
    },
    link: {
      text: 'Advice Guide',
      href: 'http://www.adviceguide.org.uk'
    }
  }
];
<|endoftext|>


<commit_before>var constants = require('../constants.js').game;
var directions = constants.board.directions;
var occupants = constants.board.occupants;
var Board = require('./board.js');
var Move = require('./move.js');
var debug = require('debug')('checkers:lib:game');
var Player = require('./player.js');

/* some utils functions */
var utils = require('./utils.js');
var getPlayerFromPiece = utils.getPlayerFromPiece;

function Game(data)
{
    data = data || {};
    var boardData = data.board;
    var turn = data.turn;

    this._gameStatus = constants.status.STARTED;
    this._turn = turn || constants.turn.P1;
    this._board = new Board(boardData);
    this._turnCount = 0;
    this._next_moves = this.get_available_moves();
    this._jump_again = false;
    this._jump_from_loc = null;
    this._P1 = data.P1 || new Player({turn : constants.turn.P1});
    this._P2 = data.P2 || new Player({turn : constants.turn.P2});
}

module.exports = Game;

Game.prototype.status = function(st) {
    if(st) this._gameStatus = st;
    return this._gameStatus;
}

Game.prototype.board = function(b) {
    if(b) this._board = b;
    return this._board.data();
}

Game.prototype.boardObj = function() {
    return this._board;
}

Game.prototype.increment_turn = function() {
    this._turnCount++;
    this._turn = this._turn == constants.turn.P1 ? constants.turn.P2 : constants.turn.P1;
}

Game.prototype.turn = function() {
    return this._turn;
}

Game.prototype.getNextPlayersMove = function() {
    var self = this;
    var turn = self.turn();
    var move;

    if(turn == constants.turn.P1) move = self._P1.get_move(self);
    else move = self._P2.get_move(self);

    return move;
}

Game.prototype.apply_move = function(move_info) {
    var self = this;

    if(!move_info) return null;

    var from = move_info._from;
    var to = move_info._to;
    var jump = move_info._jump;
    var nextMoves, jumpAgain = false;
    var occupant = self._board.get(from[0], from[1]);

    this._jump_again = false;
    this._jump_from_loc = null;

    // king me
    if(to[1] == 7 && occupant == occupants.P1)
        occupant = occupants.P1K;
    else if(to[1] == 0 && occupant == occupants.P2)
        occupant = occupants.P2K;

    self._board.set(to[0], to[1], occupant);
    self._board.set(from[0], from[1], occupants.EMPTY);

    if(jump) {
        self._board.set(jump[0], jump[1], occupants.EMPTY);
        nextMoves = self.get_available_moves_from_stp(to[0], to[1]);
        if(nextMoves.length > 0 && nextMoves[0]._jump) {
            this._jump_again = true;
            this._jump_from_loc = to;
        }
    }

    if(!this._jump_again) self.increment_turn();
}

Game.prototype.get_available_moves = function() {
    var self = this;
    var board = this._board;
    var jumpFlag = false;
    var availableMoves;

    if(self._jump_from_loc) {
        var x = self._jump_from_loc[0],
            y = self._jump_from_loc[1];
        var piece = board.get(x, y);
        var player = getPlayerFromPiece(piece);

        if(player != self.turn()) availableMoves = [];
        else availableMoves = self.get_available_moves_from_stp(x, y);
    }
    else {
        availableMoves = [];
        for(var x = 0; x < 8; x++) {
            for(var y = 0; y < 8; y++) {
                var piece = board.get(x, y);
                var player = getPlayerFromPiece(piece);

                if(player != self.turn()) continue;

                var movesForPiece = self.get_available_moves_from_stp(x, y);
                if(movesForPiece.length > 0) {
                    if(!jumpFlag && movesForPiece[0]._jump) {
                        jumpFlag = true;
                        availableMoves.splice(0, availableMoves.length);
                    }

                    if(!jumpFlag || (jumpFlag && movesForPiece[0]._jump)) {
                        availableMoves = availableMoves.concat(movesForPiece);
                    }
                }
            }
        }
    }

    return availableMoves;
}

Game.prototype.get_available_moves_from_stp = function(x, y) { // accepts an optional starting point for human user
    var self = this;
    var board = this._board;
    var startingPiece = board.get(x, y);
    var player, isKing;
    var availableDirections;
    var availableMoves = [];
    var jumpFlag = false;

    if(startingPiece == occupants.EMPTY ||
        (this._jump_from_loc && (this._jump_from_loc[0] != x || this._jump_from_loc[1] != y))) return [];

    player = getPlayerFromPiece(startingPiece);

    if(player != self.turn()) return [];

    isKing = startingPiece > occupants.P2;
    availableDirections = player == 1 ? [ directions.SE, directions.SW ] : [ directions.NE, directions.NW ];

    if(isKing) {
        availableDirections = [ directions.NE, directions.SE, directions.SW, directions.NW ];
    }

    // check distance 1
    for(var k = 0; k < availableDirections.length; k++) {
        var loc = board.getl(x, y, availableDirections[k], 1);
        var neighbor;
        var nplayer;

        if(loc) {
            // debug("Board.get_available_moves_from_stp() : DEBUG : exploring ", loc);

            neighbor = board.get(loc[0], loc[1]);
            nplayer = getPlayerFromPiece(neighbor);

            // debug("Board.get_available_moves_from_stp() : DEBUG : found ", neighbor);

            if(neighbor == occupants.EMPTY){
                if(!jumpFlag) {
                    availableMoves.push(new Move({
                        from : [x, y],
                        to : loc
                    }));
                }
            }
            else if(player != nplayer) {
                var oldloc = loc;
                loc = board.getl(x, y, availableDirections[k], 2);

                if(loc) {
                    neighbor = board.get(loc[0], loc[1]);

                    if(!jumpFlag) {
                        jumpFlag = true;
                        availableMoves.splice(0, availableMoves.length);
                    }

                    if(neighbor == occupants.EMPTY) {
                        availableMoves.push(new Move({
                            from : [x, y],
                            to : loc,
                            jump : oldloc,
                        }));
                    }
                }
            }
        }
    }

    // debug("Board.get_available_moves_from_stp() : DEBUG : given ", { x : x, y : y });
    // debug("Board.get_available_moves_from_stp() : DEBUG : got ", availableMoves);

    return availableMoves;
}

Game.prototype.hash = function(d) {
    d = d > 8 ? 8 :
        d > 5 ? 5 :
        d > 3 ? 3 :
        1;
    // return d + "," + this.turn + ',' + this._board.hash();
    return this.turn + ',' + this._board.hash();
}

Game.prototype.clone = function() {
    var self = this;
    var clone = Object.create(self);

    Object.keys(self).forEach(function(k) {
        clone[k] = self[k];
    });

    if(self['_jump_from_loc']) clone['_jump_from_loc'] = self['_jump_from_loc'].slice();
    clone['_board'] = self['_board'].clone();

    return clone;
}

<commit_msg>fixed next moves function's jump handling<commit_after>var constants = require('../constants.js').game;
var directions = constants.board.directions;
var occupants = constants.board.occupants;
var Board = require('./board.js');
var Move = require('./move.js');
var debug = require('debug')('checkers:lib:game');
var Player = require('./player.js');

/* some utils functions */
var utils = require('./utils.js');
var getPlayerFromPiece = utils.getPlayerFromPiece;

function Game(data)
{
    data = data || {};
    var boardData = data.board;
    var turn = data.turn;

    this._gameStatus = constants.status.STARTED;
    this._turn = turn || constants.turn.P1;
    this._board = new Board(boardData);
    this._turnCount = 0;
    this._next_moves = this.get_available_moves();
    this._jump_again = false;
    this._jump_from_loc = null;
    this._P1 = data.P1 || new Player({turn : constants.turn.P1});
    this._P2 = data.P2 || new Player({turn : constants.turn.P2});
}

module.exports = Game;

Game.prototype.status = function(st) {
    if(st) this._gameStatus = st;
    return this._gameStatus;
}

Game.prototype.board = function(b) {
    if(b) this._board = b;
    return this._board.data();
}

Game.prototype.boardObj = function() {
    return this._board;
}

Game.prototype.increment_turn = function() {
    this._turnCount++;
    this._turn = this._turn == constants.turn.P1 ? constants.turn.P2 : constants.turn.P1;
}

Game.prototype.turn = function() {
    return this._turn;
}

Game.prototype.getNextPlayersMove = function() {
    var self = this;
    var turn = self.turn();
    var move;

    if(turn == constants.turn.P1) move = self._P1.get_move(self);
    else move = self._P2.get_move(self);

    return move;
}

Game.prototype.apply_move = function(move_info) {
    var self = this;

    if(!move_info) return null;

    var from = move_info._from;
    var to = move_info._to;
    var jump = move_info._jump;
    var nextMoves, jumpAgain = false;
    var occupant = self._board.get(from[0], from[1]);

    this._jump_again = false;
    this._jump_from_loc = null;

    // king me
    if(to[1] == 7 && occupant == occupants.P1)
        occupant = occupants.P1K;
    else if(to[1] == 0 && occupant == occupants.P2)
        occupant = occupants.P2K;

    self._board.set(to[0], to[1], occupant);
    self._board.set(from[0], from[1], occupants.EMPTY);

    if(jump) {
        self._board.set(jump[0], jump[1], occupants.EMPTY);
        nextMoves = self.get_available_moves_from_stp(to[0], to[1]);
        if(nextMoves.length > 0 && nextMoves[0]._jump) {
            this._jump_again = true;
            this._jump_from_loc = to;
        }
    }

    if(!this._jump_again) self.increment_turn();
}

Game.prototype.get_available_moves = function() {
    var self = this;
    var board = this._board;
    var jumpFlag = false;
    var availableMoves;

    if(self._jump_from_loc) {
        var x = self._jump_from_loc[0],
            y = self._jump_from_loc[1];
        var piece = board.get(x, y);
        var player = getPlayerFromPiece(piece);

        if(player != self.turn()) availableMoves = [];
        else availableMoves = self.get_available_moves_from_stp(x, y);
    }
    else {
        availableMoves = [];
        for(var x = 0; x < 8; x++) {
            for(var y = 0; y < 8; y++) {
                var piece = board.get(x, y);
                var player = getPlayerFromPiece(piece);

                if(player != self.turn()) continue;

                var movesForPiece = self.get_available_moves_from_stp(x, y);
                if(movesForPiece.length > 0) {
                    if(!jumpFlag && movesForPiece[0]._jump) {
                        jumpFlag = true;
                        availableMoves.splice(0, availableMoves.length);
                    }

                    if(!jumpFlag || (jumpFlag && movesForPiece[0]._jump)) {
                        availableMoves = availableMoves.concat(movesForPiece);
                    }
                }
            }
        }
    }

    return availableMoves;
}

Game.prototype.get_available_moves_from_stp = function(x, y) { // accepts an optional starting point for human user
    var self = this;
    var board = this._board;
    var startingPiece = board.get(x, y);
    var player, isKing;
    var availableDirections;
    var availableMoves = [];
    var jumpFlag = false;

    if(startingPiece == occupants.EMPTY ||
        (this._jump_from_loc && (this._jump_from_loc[0] != x || this._jump_from_loc[1] != y))) return [];

    player = getPlayerFromPiece(startingPiece);

    if(player != self.turn()) return [];

    isKing = startingPiece > occupants.P2;
    availableDirections = player == 1 ? [ directions.SE, directions.SW ] : [ directions.NE, directions.NW ];

    if(isKing) {
        availableDirections = [ directions.NE, directions.SE, directions.SW, directions.NW ];
    }

    // check distance 1
    for(var k = 0; k < availableDirections.length; k++) {
        var loc = board.getl(x, y, availableDirections[k], 1);
        var neighbor;
        var nplayer;

        if(loc) {
            // debug("Board.get_available_moves_from_stp() : DEBUG : exploring ", loc);

            neighbor = board.get(loc[0], loc[1]);
            nplayer = getPlayerFromPiece(neighbor);

            // debug("Board.get_available_moves_from_stp() : DEBUG : found ", neighbor);

            if(neighbor == occupants.EMPTY){
                if(!jumpFlag) {
                    availableMoves.push(new Move({
                        from : [x, y],
                        to : loc
                    }));
                }
            }
            else if(player != nplayer) {
                var oldloc = loc;
                loc = board.getl(x, y, availableDirections[k], 2);

                if(loc) {
                    neighbor = board.get(loc[0], loc[1]);

                    if(neighbor == occupants.EMPTY) {
                        if(!jumpFlag) {
                            jumpFlag = true;
                            availableMoves.splice(0, availableMoves.length);
                        }

                        availableMoves.push(new Move({
                            from : [x, y],
                            to : loc,
                            jump : oldloc,
                        }));
                    }
                }
            }
        }
    }

    // debug("Board.get_available_moves_from_stp() : DEBUG : given ", { x : x, y : y });
    // debug("Board.get_available_moves_from_stp() : DEBUG : got ", availableMoves);

    return availableMoves;
}

Game.prototype.hash = function(d) {
    d = d > 8 ? 8 :
        d > 5 ? 5 :
        d > 3 ? 3 :
        1;
    // return d + "," + this.turn + ',' + this._board.hash();
    return this.turn + ',' + this._board.hash();
}

Game.prototype.clone = function() {
    var self = this;
    var clone = Object.create(self);

    Object.keys(self).forEach(function(k) {
        clone[k] = self[k];
    });

    if(self['_jump_from_loc']) clone['_jump_from_loc'] = self['_jump_from_loc'].slice();
    clone['_board'] = self['_board'].clone();

    return clone;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
var Blob = require('gear').Blob,
    Glob = require('glob'),
    async = require('async'),
    path  = require('path');

/**
 * Glob files. See https://github.com/isaacs/node-glob
 *
 * @param options {Object} Options object.
 * @param options.pattern {Object} Glob pattern.
 * @param options.limit {Number} Concurrency limit.
 * @param options.options {Object} Glob options.
 * @param done {Function} Callback on task completion.
 */
var glob = exports.glob = function(options, blobs, done) {
    options = options || {};
    var pattern = options.pattern,
        globoptions = options.options || {},
        encoding = options.encoding || 'utf8';

    Glob(pattern, globoptions, function(err, matches) {
        if (err) {
            done(err);
            return;
        }

        function onMatch(match, matchcb) {
            var filename = globoptions.cwd ? path.join(globoptions.cwd, match) : match;
            Blob.readFile(filename, encoding, matchcb);
        }

        function onFinish(err, results) {
            done(err, blobs.concat(results))
        }

        if (options.limit) {
            async.mapLimit(matches, options.limit, onMatch, onFinish);
        } else {
            async.map(matches, onMatch, onFinish);
        }
    });
};

glob.type = 'collect';
<commit_msg>minor tweak<commit_after>/*
 * Copyright (c) 2011-2012, Yahoo! Inc.  All rights reserved.
 * Copyrights licensed under the New BSD License.
 * See the accompanying LICENSE file for terms.
 */
var Blob = require('gear').Blob,
    Glob = require('glob'),
    async = require('async'),
    path  = require('path');

/**
 * Glob files. See https://github.com/isaacs/node-glob
 *
 * @param options {Object} Options object.
 * @param options.pattern {Object} Glob pattern.
 * @param options.limit {Number} Concurrency limit.
 * @param options.options {Object} Glob options.
 * @param done {Function} Callback on task completion.
 */
var glob = exports.glob = function(options, blobs, done) {
    options = options || {};
    var pattern = options.pattern,
        globoptions = options.options || {},
        encoding = options.encoding || 'utf8';

    Glob(pattern, globoptions, function(err, matches) {
        if (err) {
            done(err);
            return;
        }

        function onMatch(match, matchcb) {
            var filename = globoptions.cwd ? path.join(globoptions.cwd, match) : match;
            Blob.readFile(filename, encoding, matchcb);
        }

        function onFinish(err, results) {
            done(err, blobs.concat(results));
        }

        if (options.limit) {
            async.mapLimit(matches, options.limit, onMatch, onFinish);
        } else {
            async.map(matches, onMatch, onFinish);
        }
    });
};

glob.type = 'collect';
<|endoftext|>


<commit_before>/*
  A.hasOne(B)                 => B.aId
  A.belongsTo(B)              => A.bId
  A.hasMany(B)                => B.aId
  A.hasMany(B) + B.hasMany(A) => AB.aId + AB.bId
*/

SequelizeTable = function(sequelize, tableName, attributes) {
  var table = function(values) {
    var self = this
    SequelizeHelper.Hash.forEach(values, function(value, key) {
      if(attributes[key])
        self[key] = value
    })
    this.id = null // specify id as null to declare this object as unsaved and as not present in the database
    this.table = table
  }

  // class methods
  var classMethods = {
    associations: [],
    attributes: attributes,
    tableName: tableName,

    isCrossAssociatedWith: function(associatedTable) {
      var result = false
      var myTableName = table.tableName

      associatedTable.associations.forEach(function(association) {
        if((association.table.tableName == myTableName) && (association.type == 'hasMany'))
          result = true
      })
      return result
    },

    prepareAssociations: function(callback) {
      table.associations.forEach(function(association) {
        switch(association.type) {
          case 'hasMany':
            if(association.table.isCrossAssociatedWith(table)) {
              // many to many relation
              var _attributes = {}
              _attributes[table.identifier] = Sequelize.INTEGER
              _attributes[association.table.identifier] = Sequelize.INTEGER
              sequelize.define(SequelizeHelper.SQL.manyToManyTableName(table, association.table), _attributes)
            } else {
              // one to many relation
              association.table.attributes[table.identifier] = Sequelize.INTEGER
            }
            break
          case 'hasOne':
            // e.g. assocTable.myTableId = Sequelize.INTEGER
            association.table.attributes[table.identifier] = Sequelize.INTEGER
            break
          case 'belongsTo':
            // e.g. table.dayId = Sequelize.INTEGER
            table.attributes[association.table.identifier] = Sequelize.INTEGER
            break
        }
      })
      if(callback) callback()
    },

    sync: function(callback) {
      var fields = ["id INT NOT NULL auto_increment PRIMARY KEY"]
      SequelizeHelper.Hash.forEach(table.attributes, function(type, name) {
        fields.push(name + " " + type)
      })

      sequelize.query(
        Sequelize.sqlQueryFor( 'create', { table: table.tableName, fields: fields.join(', ') } ),
        function() { if(callback) callback(table) }
      )
    },

    drop: function(callback) {
      sequelize.query(
        Sequelize.sqlQueryFor('drop', { table: table.tableName }),
        function() { if(callback) callback(table) }
      )
    },

    findAll: function(options, callback) {
      // use the first param as callback if it is no object (hash)
      var _callback = (typeof options == 'object') ? callback : options
      var queryOptions = (typeof options == 'object')
        ? SequelizeHelper.Hash.merge(options, { table: table.tableName })
        : { table: table.tableName }

      sequelize.query(
        Sequelize.sqlQueryFor('select', queryOptions),
        function(result) {
          var objects = SequelizeHelper.Array.map(result, function(r) { return table.sqlResultToObject(r) })
          if(_callback) _callback(objects)
        }
      )
    },

    find: function(conditions, callback) {
      sequelize.query(
        Sequelize.sqlQueryFor('select', {
          table: table.tableName,
          where: SequelizeHelper.SQL.hashToWhereConditions(conditions, table.attributes),
          order: 'id DESC',
          limit: 1
        }), function(result) {
          var _result = result[0] ? table.sqlResultToObject(result[0]) : null
          if (callback) callback(_result)
        }
      )
    },

    sqlResultToObject: function(result) {
      if(typeof result == undefined) return null

      var object = new table(result)
      object.id = result.id
      return object
    },

    hasMany: function(assocName, _table) {
      table.associations.push({
        name: assocName,
        table: _table,
        type: 'hasMany'
      })

      // don't check inside of method to increase performance
      if(_table.isCrossAssociatedWith(table)) {
        table.prototype[assocName] = function(callback) {
          var Association = sequelize.tables[SequelizeHelper.SQL.manyToManyTableName(_table, table)].klass
          var whereConditions = [table.identifier, this.id].join("=")
          Association.findAll({ where: whereConditions }, function(result) {
            if(result.length > 0) {
              var ids = []
              result.forEach(function(resultSet) { ids.push(resultSet.id) })
              _table.findAll({where: "id IN (" + ids.join(",") + ")"}, callback)
            } else {
              if(callback) callback([])
            }
          })
        }
        table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(objects, callback) {
          var self = this
          var Association = sequelize.tables[SequelizeHelper.SQL.manyToManyTableName(_table, table)].klass
          var currentAssociations = null
          var objectIds = SequelizeHelper.Array.map(objects, function(obj) { return obj.id })

          var getAssociatedObjects = function(callback) {
            self[assocName](function(associations) {
              currentAssociations = associations
              callback(associations)
            })
          }
          var deleteObsoleteAssociations = function(callback) {
            var obsolete = []
            currentAssociations.forEach(function(association) {
              if(objectIds.indexOf(association.id) == -1) obsolete.push(association.id)
            })
            if(obsolete.length == 0)
              callback([])
            else
              sequelize.query(
                Sequelize.sqlQueryFor('delete', {table: Association.tableName, where: "id IN (" + obsolete.join(",") + ")", limit: null}),
                function(){ callback(obsolete) }
              )
          }
          var createNewAssociations = function(obsolete) {
            var currentIds = SequelizeHelper.Array.map(currentAssociations, function(assoc) { return assoc.id })
            var withoutExisting = SequelizeHelper.Array.reject(objects, function(o) {
              currentIds.indexOf(o.id) > -1
            })
            var savings = []
            withoutExisting.forEach(function(o) {
              if((o instanceof _table) && (self.id != null) && (o.id != null)) {
                var attributes = {}
                attributes[self.table.identifier] = self.id
                attributes[o.table.identifier] = o.id
                savings.push({save: new Association(attributes)})
              }
            })
            Sequelize.chainQueries(savings, function() {
              getAssociatedObjects(callback)
            })
          }

          getAssociatedObjects(function() {
            deleteObsoleteAssociations(function(obsolete) {
              createNewAssociations(obsolete)
            })
          })
        }
      } else {
        table.prototype[assocName] = function(callback) {
          var whereConditions = [table.identifier, this.id].join("=")
          _table.findAll({where: whereConditions}, callback)
        }
        table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(objects, callback) {
          var self = this
          var objectIds = SequelizeHelper.Array.map(objects, function(obj) { return obj.id })
          this[assocName](function(currentAssociations) {
            var currentIds = SequelizeHelper.Array.map(currentAssociations, function(assoc) { return assoc.id })
            var obsoleteAssociations = SequelizeHelper.Array.select(currentAssociations, function(assoc) { return objectsIds.indexOf(assoc.id) == -1 })
            var queries = []
            obsoleteAssociations.forEach(function(assoc) {
              var attr = {}; attr[table.identifier] = null
              queries.push({updateAttributes: assoc, params: [attr]})
            })
            var newAssociations = SequelizeHelper.Array.select(objects, function(o) { return currentIds.indexOf(o.id) == -1 })
            newAssociations.forEach(function(assoc) {
              var attr = {}; attr[table.identifier] = self.id
              queries.push({updateAttributes: assoc, params: [attr]})
            })
            Sequelize.chainQueries(queries, function() {
              self[assocName](callback)
            })
          })
        }
      }

      return table
    },

    hasOne: function(assocName, _table) {
      table.associations.push({
        name: assocName,
        table: _table,
        type: 'hasOne'
      })

      table.prototype[assocName] = function(callback) {
        var whereConditions = {}
        whereConditions[table.identifier] = this.id
        _table.find(whereConditions, callback)
      }

      table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(object, callback) {
        var self = this

        this[assocName](function(currentAssociation) {
          var attr = {}
          if(currentAssociation == null) {
            attr[table.identifier] = self.id
            object.updateAttributes(attr, callback)
          } else {
            if(object.id == currentAssociation.id) callback()
            else {
              attr[table.identifier] = null
              currentAssociation.updateAttributes(attr, function() {
                attr[table.identifier] = self.id
                object.updateAttributes(attr, callback)
              })
            }
          }
        })
      }

      return table
    },

    belongsTo: function(assocName, _table) {
      table.associations.push({
        name: assocName,
        table: _table,
        type: 'belongsTo'
      })

      table.prototype[assocName] = function(callback) {
        _table.find(this[_table.identifier], callback)
      }

      table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(object, callback) {
        var attr = {}; attr[object.table.identifier] = object.id
        var self = this
        this.updateAttributes(attr, function() {
          self[assocName](callback)
        })
      }

      return table
    }
  }
  // don't put this into the hash!
  classMethods.identifier = SequelizeHelper.SQL.asTableIdentifier(classMethods.tableName)

  // instance methods
  table.prototype = {
    get values() {
      var result = {}
      var self = this

      SequelizeHelper.Hash.keys(table.attributes).forEach(function(attribute) {
        result[attribute] = self[attribute] || null
      })

      return result
    },

    save: function(callback) {
      var query = null
      var self = this

      this.updatedAt = new Date()
      if(this.id == null) {
        this.createdAt = new Date()
        query = Sequelize.sqlQueryFor('insert', {
          table: table.tableName,
          fields: SequelizeHelper.SQL.fieldsForInsertQuery(this),
          values: SequelizeHelper.SQL.valuesForInsertQuery(this)
        })
      } else
        query = Sequelize.sqlQueryFor('update', { table: table.tableName, values: SequelizeHelper.SQL.valuesForUpdate(this), id: this.id })

      sequelize.query(query, function() {
        if(self.id == null) {
          table.find(self.values, function(result) {
            self.id = result.id
            if(callback) callback(self)
          })
        } else {
          if(callback) callback(self)
        }
      })
    },

    updateAttributes: function(newValues, callback) {
      var self = this
      SequelizeHelper.Hash.keys(table.attributes).forEach(function(attribute) {
        if(newValues[attribute])
          self[attribute] = newValues[attribute]
      })
      this.save(callback)
    },

    destroy: function(callback) {
      sequelize.query(
        Sequelize.sqlQueryFor('delete', { table: table.tableName, where: ['id', this.id].join("=") }),
        callback
      )
    }
  }

  SequelizeHelper.Hash.forEach(classMethods, function(method, methodName) {
    table[methodName] = method
  })

  return table
}<commit_msg>don't re-query after save<commit_after>/*
  A.hasOne(B)                 => B.aId
  A.belongsTo(B)              => A.bId
  A.hasMany(B)                => B.aId
  A.hasMany(B) + B.hasMany(A) => AB.aId + AB.bId
*/

SequelizeTable = function(sequelize, tableName, attributes) {
  var table = function(values) {
    var self = this
    SequelizeHelper.Hash.forEach(values, function(value, key) {
      if(attributes[key])
        self[key] = value
    })
    this.id = null // specify id as null to declare this object as unsaved and as not present in the database
    this.table = table
  }

  // class methods
  var classMethods = {
    associations: [],
    attributes: attributes,
    tableName: tableName,

    isCrossAssociatedWith: function(associatedTable) {
      var result = false
      var myTableName = table.tableName

      associatedTable.associations.forEach(function(association) {
        if((association.table.tableName == myTableName) && (association.type == 'hasMany'))
          result = true
      })
      return result
    },

    prepareAssociations: function(callback) {
      table.associations.forEach(function(association) {
        switch(association.type) {
          case 'hasMany':
            if(association.table.isCrossAssociatedWith(table)) {
              // many to many relation
              var _attributes = {}
              _attributes[table.identifier] = Sequelize.INTEGER
              _attributes[association.table.identifier] = Sequelize.INTEGER
              sequelize.define(SequelizeHelper.SQL.manyToManyTableName(table, association.table), _attributes)
            } else {
              // one to many relation
              association.table.attributes[table.identifier] = Sequelize.INTEGER
            }
            break
          case 'hasOne':
            // e.g. assocTable.myTableId = Sequelize.INTEGER
            association.table.attributes[table.identifier] = Sequelize.INTEGER
            break
          case 'belongsTo':
            // e.g. table.dayId = Sequelize.INTEGER
            table.attributes[association.table.identifier] = Sequelize.INTEGER
            break
        }
      })
      if(callback) callback()
    },

    sync: function(callback) {
      var fields = ["id INT NOT NULL auto_increment PRIMARY KEY"]
      SequelizeHelper.Hash.forEach(table.attributes, function(type, name) {
        fields.push(name + " " + type)
      })

      sequelize.query(
        Sequelize.sqlQueryFor( 'create', { table: table.tableName, fields: fields.join(', ') } ),
        function() { if(callback) callback(table) }
      )
    },

    drop: function(callback) {
      sequelize.query(
        Sequelize.sqlQueryFor('drop', { table: table.tableName }),
        function() { if(callback) callback(table) }
      )
    },

    findAll: function(options, callback) {
      // use the first param as callback if it is no object (hash)
      var _callback = (typeof options == 'object') ? callback : options
      var queryOptions = (typeof options == 'object')
        ? SequelizeHelper.Hash.merge(options, { table: table.tableName })
        : { table: table.tableName }

      sequelize.query(
        Sequelize.sqlQueryFor('select', queryOptions),
        function(result) {
          var objects = SequelizeHelper.Array.map(result, function(r) { return table.sqlResultToObject(r) })
          if(_callback) _callback(objects)
        }
      )
    },

    find: function(conditions, callback) {
      sequelize.query(
        Sequelize.sqlQueryFor('select', {
          table: table.tableName,
          where: SequelizeHelper.SQL.hashToWhereConditions(conditions, table.attributes),
          order: 'id DESC',
          limit: 1
        }), function(result) {
          var _result = result[0] ? table.sqlResultToObject(result[0]) : null
          if (callback) callback(_result)
        }
      )
    },

    sqlResultToObject: function(result) {
      if(typeof result == undefined) return null

      var object = new table(result)
      object.id = result.id
      return object
    },

    hasMany: function(assocName, _table) {
      table.associations.push({
        name: assocName,
        table: _table,
        type: 'hasMany'
      })

      // don't check inside of method to increase performance
      if(_table.isCrossAssociatedWith(table)) {
        table.prototype[assocName] = function(callback) {
          var Association = sequelize.tables[SequelizeHelper.SQL.manyToManyTableName(_table, table)].klass
          var whereConditions = [table.identifier, this.id].join("=")
          Association.findAll({ where: whereConditions }, function(result) {
            if(result.length > 0) {
              var ids = []
              result.forEach(function(resultSet) { ids.push(resultSet.id) })
              _table.findAll({where: "id IN (" + ids.join(",") + ")"}, callback)
            } else {
              if(callback) callback([])
            }
          })
        }
        table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(objects, callback) {
          var self = this
          var Association = sequelize.tables[SequelizeHelper.SQL.manyToManyTableName(_table, table)].klass
          var currentAssociations = null
          var objectIds = SequelizeHelper.Array.map(objects, function(obj) { return obj.id })

          var getAssociatedObjects = function(callback) {
            self[assocName](function(associations) {
              currentAssociations = associations
              callback(associations)
            })
          }
          var deleteObsoleteAssociations = function(callback) {
            var obsolete = []
            currentAssociations.forEach(function(association) {
              if(objectIds.indexOf(association.id) == -1) obsolete.push(association.id)
            })
            if(obsolete.length == 0)
              callback([])
            else
              sequelize.query(
                Sequelize.sqlQueryFor('delete', {table: Association.tableName, where: "id IN (" + obsolete.join(",") + ")", limit: null}),
                function(){ callback(obsolete) }
              )
          }
          var createNewAssociations = function(obsolete) {
            var currentIds = SequelizeHelper.Array.map(currentAssociations, function(assoc) { return assoc.id })
            var withoutExisting = SequelizeHelper.Array.reject(objects, function(o) {
              currentIds.indexOf(o.id) > -1
            })
            var savings = []
            withoutExisting.forEach(function(o) {
              if((o instanceof _table) && (self.id != null) && (o.id != null)) {
                var attributes = {}
                attributes[self.table.identifier] = self.id
                attributes[o.table.identifier] = o.id
                savings.push({save: new Association(attributes)})
              }
            })
            Sequelize.chainQueries(savings, function() {
              getAssociatedObjects(callback)
            })
          }

          getAssociatedObjects(function() {
            deleteObsoleteAssociations(function(obsolete) {
              createNewAssociations(obsolete)
            })
          })
        }
      } else {
        table.prototype[assocName] = function(callback) {
          var whereConditions = [table.identifier, this.id].join("=")
          _table.findAll({where: whereConditions}, callback)
        }
        table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(objects, callback) {
          var self = this
          var objectIds = SequelizeHelper.Array.map(objects, function(obj) { return obj.id })
          this[assocName](function(currentAssociations) {
            var currentIds = SequelizeHelper.Array.map(currentAssociations, function(assoc) { return assoc.id })
            var obsoleteAssociations = SequelizeHelper.Array.select(currentAssociations, function(assoc) { return objectsIds.indexOf(assoc.id) == -1 })
            var queries = []
            obsoleteAssociations.forEach(function(assoc) {
              var attr = {}; attr[table.identifier] = null
              queries.push({updateAttributes: assoc, params: [attr]})
            })
            var newAssociations = SequelizeHelper.Array.select(objects, function(o) { return currentIds.indexOf(o.id) == -1 })
            newAssociations.forEach(function(assoc) {
              var attr = {}; attr[table.identifier] = self.id
              queries.push({updateAttributes: assoc, params: [attr]})
            })
            Sequelize.chainQueries(queries, function() {
              self[assocName](callback)
            })
          })
        }
      }

      return table
    },

    hasOne: function(assocName, _table) {
      table.associations.push({
        name: assocName,
        table: _table,
        type: 'hasOne'
      })

      table.prototype[assocName] = function(callback) {
        var whereConditions = {}
        whereConditions[table.identifier] = this.id
        _table.find(whereConditions, callback)
      }

      table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(object, callback) {
        var self = this

        this[assocName](function(currentAssociation) {
          var attr = {}
          if(currentAssociation == null) {
            attr[table.identifier] = self.id
            object.updateAttributes(attr, callback)
          } else {
            if(object.id == currentAssociation.id) callback()
            else {
              attr[table.identifier] = null
              currentAssociation.updateAttributes(attr, function() {
                attr[table.identifier] = self.id
                object.updateAttributes(attr, callback)
              })
            }
          }
        })
      }

      return table
    },

    belongsTo: function(assocName, _table) {
      table.associations.push({
        name: assocName,
        table: _table,
        type: 'belongsTo'
      })

      table.prototype[assocName] = function(callback) {
        _table.find(this[_table.identifier], callback)
      }

      table.prototype[SequelizeHelper.SQL.addPrefix('set', assocName)] = function(object, callback) {
        var attr = {}; attr[object.table.identifier] = object.id
        var self = this
        this.updateAttributes(attr, function() {
          self[assocName](callback)
        })
      }

      return table
    }
  }
  // don't put this into the hash!
  classMethods.identifier = SequelizeHelper.SQL.asTableIdentifier(classMethods.tableName)

  // instance methods
  table.prototype = {
    get values() {
      var result = {}
      var self = this

      SequelizeHelper.Hash.keys(table.attributes).forEach(function(attribute) {
        result[attribute] = self[attribute] || null
      })

      return result
    },

    save: function(callback) {
      var query = null
      var self = this

      this.updatedAt = new Date()
      if(this.id == null) {
        this.createdAt = new Date()
        query = Sequelize.sqlQueryFor('insert', {
          table: table.tableName,
          fields: SequelizeHelper.SQL.fieldsForInsertQuery(this),
          values: SequelizeHelper.SQL.valuesForInsertQuery(this)
        })
      } else
        query = Sequelize.sqlQueryFor('update', { table: table.tableName, values: SequelizeHelper.SQL.valuesForUpdate(this), id: this.id })

      sequelize.query(query, function(result, stats) {
        self.id = self.id || stats.insert_id
        if(callback) callback(self)
      })
    },

    updateAttributes: function(newValues, callback) {
      var self = this
      SequelizeHelper.Hash.keys(table.attributes).forEach(function(attribute) {
        if(newValues[attribute])
          self[attribute] = newValues[attribute]
      })
      this.save(callback)
    },

    destroy: function(callback) {
      sequelize.query(
        Sequelize.sqlQueryFor('delete', { table: table.tableName, where: ['id', this.id].join("=") }),
        callback
      )
    }
  }

  SequelizeHelper.Hash.forEach(classMethods, function(method, methodName) {
    table[methodName] = method
  })

  return table
}<|endoftext|>


<commit_before>/**
 * Organized grunt task configuration
 *
 * Licensed under MIT.
 * Copyright (c) 2013 David Smith <https://github.com/codeactual/>
 */

/*jshint node:true*/
'use strict';

/**
 * Reference to GruntHorde.
 */
exports.GruntHorde = GruntHorde;

/**
 * Create a new GruntHorde.
 *
 * @return {object}
 */
exports.create = function() { return new GruntHorde(); };

/**
 * Extend GruntHorde.prototype.
 *
 * @param {object} ext
 * @return {object} Merge result.
 */
exports.extend = function(ext) { return extend(GruntHorde.prototype, ext); };

var requireComponent = require('../component/require');
var mergeDeep = requireComponent('assimilate').withStrategy('deep');
var clone = requireComponent('clone');
var extend = requireComponent('extend');

var path = require('path');
var shelljs = require('shelljs');

/**
 * GruntHorde constructor.
 *
 * Usage:
 *
 *     // Gruntfile.js
 *
 *     module.exports = function(grunt) {
 *       var horde = GruntHorde.create();
 *       horde
 *         .follow(grunt)
 *         .loot('my-base-config-module')
 *         .loot('./config/grunt')
 *         .attack();
 *     };
 *
 * Required before calling `attack()`:
 *
 * - `follow()`
 *
 * Properties:
 *
 * - `{object} config` Gruntfile.js sections
 *   - `{object} initConfig`
 *   - `{object} loadNpmTasks`
 *   - `{object} loadTasks`
 *   - `{object} registerMultiTask`
 *   - `{object} registerTask`
 * - `{object} grunt` Module collected from Gruntfile.js
 * - `{string} home` Absolute path to project root dir w/out trailing slash
 */
function GruntHorde() {
  this.home = process.cwd();
  this.grunt = null;
  this.config = {
    initConfig: {},
    loadNpmTasks: {},
    loadTasks: {},
    registerMultiTask: {},
    registerTask: {}
  };
}

GruntHorde.prototype.attack = function() {
  var self = this;

  var required = ['grunt', 'seek'];
  required.forEach(function(name) {
    if (!self[name]) {
      throw new Error(name + '() value is missing');
    }
  });

  this.grunt.initConfig(this.config.initConfig);

  Object.keys(this.config.loadTasks).forEach(function(name) {
    if (self.config.loadTasks[name]) {
      self.grunt.loadTasks(self.config.loadTasks[name]);
    }
  });

  Object.keys(this.config.loadNpmTasks).forEach(function(name) {
    if (self.config.loadNpmTasks[name]) {
      self.grunt.loadNpmTasks(self.config.loadNpmTasks[name]);
    }
  });

  Object.keys(this.config.registerTask).forEach(function(name) {
    self.grunt.registerTask.apply(self.grunt, self.config.registerTask[name]);
  });

  Object.keys(this.config.registerMultiTask).forEach(function(name) {
    self.grunt.registerMultiTask.apply(self.grunt, self.config.registerMultiTask[name]);
  });
};

GruntHorde.prototype.follow = function(grunt) {
  this.grunt = grunt;
};

GruntHorde.prototype.home = function(home) {
  this.home = home;
};

/**
 * Add a config module.
 *
 * Module payloads are merged recursively, last wins.
 *
 * Usage:
 *
 *     horde.home('/proj/home');
 *     horde.loot('base'); // require('/proj/home/node_modules/base');
 *     horde.loot('./base'); // require('/proj/home/base.js');
 *     horde.loot('/path/to/base'); // require('/path/to/base');
 *
 * @param {string} name `require()` path, see `Usage`
 * @see GruntHorde.prototype.home
 * @see GruntHorde.prototype.seek
 */
GruntHorde.prototype.loot = function(name) {
  this.config = mergeDeep(this.config, this.dirToConfigObj(name));
};

GruntHorde.prototype.requireConfigModule = function(name) {
  if (/^\.\//.test(name)) {
    name = this.home + '/' + name;
  } else if (/^[^\/]/.test(name)) {
    name = this.home + '/node_modules/' + name;
  }

  return this.require(name);
};

GruntHorde.prototype.require = function(name) {
  return require(name).apply(GruntHorde.createModuleContext(), this.grunt);
};

GruntHorde.prototype.requireIfExists = function(name) {
  if (shelljs.test('-e', name)) {
    return this.require(name);
  } else {
    return {};
  }
};

GruntHorde.prototype.requireDir = function(name) {
  var self = this;
  var index = {};
  var categorized = {};
  shelljs.ls(name + '/*.js').forEach(function(file) {
    if ('index.js' === file) { // Let it hold top-level keys
      index = self.require(file);
    } else { // All others go under top-level keys named after their files
      categorized = mergeDeep(categorized, self.require(file));
    }
  });
  return mergeDeep(index, categorized);
};

GruntHorde.prototype.requireDirIfExists = function(name) {
  if (shelljs.test('-e', name)) {
    return this.requireDir(name);
  } else {
    return {};
  }
};

GruntHorde.prototype.createModuleContext = function() {
  return {
    config: clone(this.grunt.config.getRaw()),
    path: path,
    require: this.require.bind(this),
    requireDir: this.requireDir.bind(this),
    shelljs: shelljs,
    t: this.t.bind(this)
  };
};

/**
 * Alias for `grunt.template.process()`.
 *
 * @see process http://gruntjs.com/api/grunt.template#grunt.template.process
 */
GruntHorde.prototype.t = function() {
  return this.grunt.template.process.apply(this.grunt, arguments);
};

/**
 * Using file layout conventions, convert a directory's contents into an
 * object for later merging into `this.config`.
 *
 * Directory types:
 *
 * - Base config module, ex. `node_modules/my-base-config`
 * - Project-local config module, ex. `config/grunt/`
 *
 * @param {string} name Absolute path to directory w/out trailing slash
 * @return {object}
 */
GruntHorde.prototype.dirToConfigObj = function(name) {
  var obj = {
    initConfig: this.requireDirIfExists(name + '/initConfig')
  };
  var files = ['loadTasks', 'loadNpmTasks', 'registerTask', 'registerMultiTask'];
  files.forEach(function(file) {
    obj[file] = this.requireIfExists(name + '/' + file + '.js');
  });
  return obj;
};
<commit_msg>fix(lib): Remove seek() artifacts<commit_after>/**
 * Organized grunt task configuration
 *
 * Licensed under MIT.
 * Copyright (c) 2013 David Smith <https://github.com/codeactual/>
 */

/*jshint node:true*/
'use strict';

/**
 * Reference to GruntHorde.
 */
exports.GruntHorde = GruntHorde;

/**
 * Create a new GruntHorde.
 *
 * @return {object}
 */
exports.create = function() { return new GruntHorde(); };

/**
 * Extend GruntHorde.prototype.
 *
 * @param {object} ext
 * @return {object} Merge result.
 */
exports.extend = function(ext) { return extend(GruntHorde.prototype, ext); };

var requireComponent = require('../component/require');
var mergeDeep = requireComponent('assimilate').withStrategy('deep');
var clone = requireComponent('clone');
var extend = requireComponent('extend');

var path = require('path');
var shelljs = require('shelljs');

/**
 * GruntHorde constructor.
 *
 * Usage:
 *
 *     // Gruntfile.js
 *
 *     module.exports = function(grunt) {
 *       var horde = GruntHorde.create();
 *       horde
 *         .follow(grunt)
 *         .loot('my-base-config-module')
 *         .loot('./config/grunt')
 *         .attack();
 *     };
 *
 * Required before calling `attack()`:
 *
 * - `follow()`
 *
 * Properties:
 *
 * - `{object} config` Gruntfile.js sections
 *   - `{object} initConfig`
 *   - `{object} loadNpmTasks`
 *   - `{object} loadTasks`
 *   - `{object} registerMultiTask`
 *   - `{object} registerTask`
 * - `{object} grunt` Module collected from Gruntfile.js
 * - `{string} home` Absolute path to project root dir w/out trailing slash
 */
function GruntHorde() {
  this.home = process.cwd();
  this.grunt = null;
  this.config = {
    initConfig: {},
    loadNpmTasks: {},
    loadTasks: {},
    registerMultiTask: {},
    registerTask: {}
  };
}

GruntHorde.prototype.attack = function() {
  var self = this;

  var required = ['grunt'];
  required.forEach(function(name) {
    if (!self[name]) {
      throw new Error(name + '() value is missing');
    }
  });

  this.grunt.initConfig(this.config.initConfig);

  Object.keys(this.config.loadTasks).forEach(function(name) {
    if (self.config.loadTasks[name]) {
      self.grunt.loadTasks(self.config.loadTasks[name]);
    }
  });

  Object.keys(this.config.loadNpmTasks).forEach(function(name) {
    if (self.config.loadNpmTasks[name]) {
      self.grunt.loadNpmTasks(self.config.loadNpmTasks[name]);
    }
  });

  Object.keys(this.config.registerTask).forEach(function(name) {
    self.grunt.registerTask.apply(self.grunt, self.config.registerTask[name]);
  });

  Object.keys(this.config.registerMultiTask).forEach(function(name) {
    self.grunt.registerMultiTask.apply(self.grunt, self.config.registerMultiTask[name]);
  });
};

GruntHorde.prototype.follow = function(grunt) {
  this.grunt = grunt;
};

GruntHorde.prototype.home = function(home) {
  this.home = home;
};

/**
 * Add a config module.
 *
 * Module payloads are merged recursively, last wins.
 *
 * Usage:
 *
 *     horde.home('/proj/home');
 *     horde.loot('base'); // require('/proj/home/node_modules/base');
 *     horde.loot('./base'); // require('/proj/home/base.js');
 *     horde.loot('/path/to/base'); // require('/path/to/base');
 *
 * @param {string} name `require()` path, see `Usage`
 * @see GruntHorde.prototype.home
 */
GruntHorde.prototype.loot = function(name) {
  this.config = mergeDeep(this.config, this.dirToConfigObj(name));
};

GruntHorde.prototype.requireConfigModule = function(name) {
  if (/^\.\//.test(name)) {
    name = this.home + '/' + name;
  } else if (/^[^\/]/.test(name)) {
    name = this.home + '/node_modules/' + name;
  }

  return this.require(name);
};

GruntHorde.prototype.require = function(name) {
  return require(name).apply(GruntHorde.createModuleContext(), this.grunt);
};

GruntHorde.prototype.requireIfExists = function(name) {
  if (shelljs.test('-e', name)) {
    return this.require(name);
  } else {
    return {};
  }
};

GruntHorde.prototype.requireDir = function(name) {
  var self = this;
  var index = {};
  var categorized = {};
  shelljs.ls(name + '/*.js').forEach(function(file) {
    if ('index.js' === file) { // Let it hold top-level keys
      index = self.require(file);
    } else { // All others go under top-level keys named after their files
      categorized = mergeDeep(categorized, self.require(file));
    }
  });
  return mergeDeep(index, categorized);
};

GruntHorde.prototype.requireDirIfExists = function(name) {
  if (shelljs.test('-e', name)) {
    return this.requireDir(name);
  } else {
    return {};
  }
};

GruntHorde.prototype.createModuleContext = function() {
  return {
    config: clone(this.grunt.config.getRaw()),
    path: path,
    require: this.require.bind(this),
    requireDir: this.requireDir.bind(this),
    shelljs: shelljs,
    t: this.t.bind(this)
  };
};

/**
 * Alias for `grunt.template.process()`.
 *
 * @see process http://gruntjs.com/api/grunt.template#grunt.template.process
 */
GruntHorde.prototype.t = function() {
  return this.grunt.template.process.apply(this.grunt, arguments);
};

/**
 * Using file layout conventions, convert a directory's contents into an
 * object for later merging into `this.config`.
 *
 * Directory types:
 *
 * - Base config module, ex. `node_modules/my-base-config`
 * - Project-local config module, ex. `config/grunt/`
 *
 * @param {string} name Absolute path to directory w/out trailing slash
 * @return {object}
 */
GruntHorde.prototype.dirToConfigObj = function(name) {
  var obj = {
    initConfig: this.requireDirIfExists(name + '/initConfig')
  };
  var files = ['loadTasks', 'loadNpmTasks', 'registerTask', 'registerMultiTask'];
  files.forEach(function(file) {
    obj[file] = this.requireIfExists(name + '/' + file + '.js');
  });
  return obj;
};
<|endoftext|>


<commit_before>/**
 * == @Spearal ==>
 *
 * Copyright (C) 2014 Franck WOLFF & William DRAI (http://www.spearal.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author Franck WOLFF
 */
class _SpearalDecoderBuffer {

	constructor(arrayBuffer) {
		this._view = new DataView(arrayBuffer);
		this._pos = 0;
	}

	readUint8() {
		try {
			return this._view.getUint8(this._pos++);
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readUintN(length0) {
		if (length0 < 0 || length0 > 3)
			throw "Illegal length0: " + length0;

		try {
			var value = 0;

			switch (length0) {
			case 3:
				value = this._view.getUint32(this._pos);
				this._pos += 4;
				break;
			case 2:
				value = this._view.getUint8(this._pos++) << 16;
			case 1:
				value |= this._view.getUint16(this._pos);
				this._pos += 2;
				break;
			case 0:
				value = this._view.getUint8(this._pos++);
				break;
			}

			return value;
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readFloat64() {
		try {
			var value = this._view.getFloat64(this._pos);
			this._pos += 8;
			return value;
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readUTF(length) {
		try {
			var utf = String.fromCharCode.apply(null, new Uint8Array(this._view.buffer, this._pos, length));
			this._pos += length;
			return utf;
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readByteArray(length) {
		if (!length)
			return new ArrayBuffer(0);

		var end = this._pos + length;
		if (end > this._view.buffer.byteLength)
			throw "EOF: cannot read " + length + " bytes";

		var array = this._view.buffer.slice(this._pos, end);
		this._pos = end;
		return array;
	}
}

class SpearalDecoder {

	constructor(context, buffer) {
		if (!(context instanceof SpearalContext))
			throw "Parameter 'context' must be a SpearalContext";
		if (!(buffer instanceof ArrayBuffer))
			throw "Parameter 'buffer' must be an ArrayBuffer";

		this._context = context;
		this._buffer = new _SpearalDecoderBuffer(buffer);
		this._sharedStrings = [];
		this._sharedObjects = [];
	}

	readAny() {
		return this._readAny(this._buffer.readUint8());
	}

	_readAny(parameterizedType) {
		var type = SpearalType.typeOf(parameterizedType),
			value = null;

		switch(type) {

		case SpearalType.NULL:
			value = null; break;

		case SpearalType.TRUE:
			value = true; break;
		case SpearalType.FALSE:
			value = false; break;

		case SpearalType.INTEGRAL:
			value = this._readIntegral(parameterizedType); break;
		case SpearalType.BIG_INTEGRAL:
			value = this._readBigIntegral(parameterizedType); break;

		case SpearalType.FLOATING:
			value = this._readFloating(parameterizedType); break;
		case SpearalType.BIG_FLOATING:
			value = this._readBigFloating(parameterizedType); break;

		case SpearalType.STRING:
			value = this._readString(parameterizedType); break;

		case SpearalType.BYTE_ARRAY:
			value = this._readByteArray(parameterizedType); break;

		case SpearalType.DATE_TIME:
			value = this._readDateTime(parameterizedType); break;

		case SpearalType.COLLECTION:
			value = this._readCollection(parameterizedType); break;
		case SpearalType.MAP:
			value = this._readMap(parameterizedType); break;

		case SpearalType.ENUM:
			value = this._readEnum(parameterizedType); break;
		case SpearalType.CLASS:
			value = this._readClass(parameterizedType); break;
		case SpearalType.BEAN:
			value = this._readBean(parameterizedType); break;

		default:
			throw new "Unknown data type: " + parameterizedType + "/" + SpearalType.typeOf(parameterizedType);
		}

		return this._context.getDecoder(type)(value);
	}

	_readIntegral(parameterizedType) {
		var length0 = (parameterizedType & 0x07),
			value;

		if (length0 <= 3)
			value = this._buffer.readUintN(length0);
		else
			value = (this._buffer.readUintN(3) * Math.pow(256, length0 - 3)) + this._buffer.readUintN(length0 - 4);

		return (((parameterizedType & 0x08) !== 0) ? -value : value);
	}

	_readBigIntegral(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);
		if (SpearalDecoder._isStringReference(parameterizedType))
			return this._sharedStrings[indexOrLength];

		var value = this._readBigNumberData(indexOrLength),
			iExp = value.indexOf('E');
		if (iExp === -1)
			return value;

		var zeros = parseInt(value.substr(iExp+1));
		value = value.substring(0, iExp);
		for (var i = 0; i < zeros; i++)
			value += '0';
		return value;
	}

	_readFloating(parameterizedType) {
		if ((parameterizedType & 0x08) === 0)
			return this._buffer.readFloat64();

		var v = this._buffer.readUintN(parameterizedType & 0x03);
		if ((parameterizedType & 0x04) !== 0)
			v = -v;
		return (v / 1000.0);
	}

	_readBigFloating(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);
		if (SpearalDecoder._isStringReference(parameterizedType))
			return this._sharedStrings[indexOrLength];
		return this._readBigNumberData(indexOrLength);
	}

	_readString(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isStringReference(parameterizedType))
			return this._sharedStrings[indexOrLength];

		if (indexOrLength === 0)
			return "";

		var value = decodeURIComponent(escape(this._buffer.readUTF(indexOrLength)));
		this._sharedStrings.push(value);
		return value;
	}

	_readByteArray(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var array = this._buffer.readByteArray(indexOrLength);
		this._sharedObjects.push(array);
		return array;
	}

	_readDateTime(parameterizedType) {
		var hasDate = ((parameterizedType & 0x08) != 0),
			hasTime = ((parameterizedType & 0x04) != 0),
			year = 0,
			month = 0,
			date = 0,
			hours = 0,
			minutes = 0,
			seconds = 0,
			millis = 0,
			subsecondsType;

		if (hasDate) {
			month = this._buffer.readUint8();
			date = this._buffer.readUint8();

			year = this._buffer.readUintN((month >>> 4) & 0x03);
			if ((month & 0x80) != 0)
				year = -year;
			year += 2000;

			month &= 0x0f;
			month--;
		}

		if (hasTime) {
			hours = this._buffer.readUint8();
			minutes = this._buffer.readUint8();
			seconds = this._buffer.readUint8();

			subsecondsType = (parameterizedType & 0x03);
			if (subsecondsType !== 0) {
				millis = this._buffer.readUintN(hours >>> 5);
				if (subsecondsType === 1)
					millis /= 1000000;
				else if (subsecondsType === 2)
					millis /= 1000;
    		}

    		hours &= 0x1f;
		}

		return new Date(Date.UTC(year, month, date, hours, minutes, seconds, millis));
	}

	_readCollection(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var value = new Array(indexOrLength);
		this._sharedObjects.push(value);
		for (var i = 0; i < indexOrLength; i++)
			value[i] = this.readAny();
		return value;
	}

	_readMap(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var value = new Map();
		this._sharedObjects.push(value);
		for (var i = 0; i < indexOrLength; i++) {
			var key = this.readAny();
			var val = this.readAny();
			value.set(key, val);
		}
		return value;
	}

	_readEnum(parameterizedType) {
		return {
			kind: this._readString(parameterizedType),
			name: this.readAny()
		};
	}

	_readClass(parameterizedType) {
		var className = this._readString(parameterizedType),
			cls = window[className];
		return (cls != null ? cls : className);
	}

	_readBean(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var description = (
			(parameterizedType & 0x04) !== 0 ?
			this._sharedStrings[indexOrLength] :
			decodeURIComponent(escape(this._buffer.readUTF(indexOrLength)))
		);

		var descriptor = _SpearalClassDescriptor.forDescription(description),
			value = this._context.getInstance(descriptor);

		this._sharedObjects.push(value);

		for (var name of descriptor.propertyNames)
			value[name] = this.readAny();

		return value;
	}

	_readBigNumberData(length) {
		var count = (length / 2) + (length % 2),
			value = "";

		for (var i = 0; i < count; i++) {
			var b = this._buffer.readUint8();
			value += SpearalBigNumber.charAt((b & 0xf0) >>> 4);
			if (value.length === length)
				break;
			value += SpearalBigNumber.charAt(b & 0x0f);
		}

		this._sharedStrings.push(value);
		return value;
	}

	_readIndexOrLength(parameterizedType) {
		return this._buffer.readUintN(parameterizedType & 0x03);
	}

	static _isObjectReference(parameterizedType) {
		return ((parameterizedType & 0x08) !== 0);
	}

	static _isStringReference(parameterizedType) {
		return ((parameterizedType & 0x04) !== 0);
	}
}

<commit_msg>Fix reference handling of bean description.<commit_after>/**
 * == @Spearal ==>
 *
 * Copyright (C) 2014 Franck WOLFF & William DRAI (http://www.spearal.io)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @author Franck WOLFF
 */
class _SpearalDecoderBuffer {

	constructor(arrayBuffer) {
		this._view = new DataView(arrayBuffer);
		this._pos = 0;
	}

	readUint8() {
		try {
			return this._view.getUint8(this._pos++);
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readUintN(length0) {
		if (length0 < 0 || length0 > 3)
			throw "Illegal length0: " + length0;

		try {
			var value = 0;

			switch (length0) {
			case 3:
				value = this._view.getUint32(this._pos);
				this._pos += 4;
				break;
			case 2:
				value = this._view.getUint8(this._pos++) << 16;
			case 1:
				value |= this._view.getUint16(this._pos);
				this._pos += 2;
				break;
			case 0:
				value = this._view.getUint8(this._pos++);
				break;
			}

			return value;
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readFloat64() {
		try {
			var value = this._view.getFloat64(this._pos);
			this._pos += 8;
			return value;
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readUTF(length) {
		try {
			var utf = String.fromCharCode.apply(null, new Uint8Array(this._view.buffer, this._pos, length));
			this._pos += length;
			return utf;
		}
		catch (e) {
			throw "EOF: " + e;
		}
	}

	readByteArray(length) {
		if (!length)
			return new ArrayBuffer(0);

		var end = this._pos + length;
		if (end > this._view.buffer.byteLength)
			throw "EOF: cannot read " + length + " bytes";

		var array = this._view.buffer.slice(this._pos, end);
		this._pos = end;
		return array;
	}
}

class SpearalDecoder {

	constructor(context, buffer) {
		if (!(context instanceof SpearalContext))
			throw "Parameter 'context' must be a SpearalContext";
		if (!(buffer instanceof ArrayBuffer))
			throw "Parameter 'buffer' must be an ArrayBuffer";

		this._context = context;
		this._buffer = new _SpearalDecoderBuffer(buffer);
		this._sharedStrings = [];
		this._sharedObjects = [];
	}

	readAny() {
		return this._readAny(this._buffer.readUint8());
	}

	_readAny(parameterizedType) {
		var type = SpearalType.typeOf(parameterizedType),
			value = null;

		switch(type) {

		case SpearalType.NULL:
			value = null; break;

		case SpearalType.TRUE:
			value = true; break;
		case SpearalType.FALSE:
			value = false; break;

		case SpearalType.INTEGRAL:
			value = this._readIntegral(parameterizedType); break;
		case SpearalType.BIG_INTEGRAL:
			value = this._readBigIntegral(parameterizedType); break;

		case SpearalType.FLOATING:
			value = this._readFloating(parameterizedType); break;
		case SpearalType.BIG_FLOATING:
			value = this._readBigFloating(parameterizedType); break;

		case SpearalType.STRING:
			value = this._readString(parameterizedType); break;

		case SpearalType.BYTE_ARRAY:
			value = this._readByteArray(parameterizedType); break;

		case SpearalType.DATE_TIME:
			value = this._readDateTime(parameterizedType); break;

		case SpearalType.COLLECTION:
			value = this._readCollection(parameterizedType); break;
		case SpearalType.MAP:
			value = this._readMap(parameterizedType); break;

		case SpearalType.ENUM:
			value = this._readEnum(parameterizedType); break;
		case SpearalType.CLASS:
			value = this._readClass(parameterizedType); break;
		case SpearalType.BEAN:
			value = this._readBean(parameterizedType); break;

		default:
			throw new "Unknown data type: " + parameterizedType + "/" + SpearalType.typeOf(parameterizedType);
		}

		return this._context.getDecoder(type)(value);
	}

	_readIntegral(parameterizedType) {
		var length0 = (parameterizedType & 0x07),
			value;

		if (length0 <= 3)
			value = this._buffer.readUintN(length0);
		else
			value = (this._buffer.readUintN(3) * Math.pow(256, length0 - 3)) + this._buffer.readUintN(length0 - 4);

		return (((parameterizedType & 0x08) !== 0) ? -value : value);
	}

	_readBigIntegral(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);
		if (SpearalDecoder._isStringReference(parameterizedType))
			return this._sharedStrings[indexOrLength];

		var value = this._readBigNumberData(indexOrLength),
			iExp = value.indexOf('E');
		if (iExp === -1)
			return value;

		var zeros = parseInt(value.substr(iExp+1));
		value = value.substring(0, iExp);
		for (var i = 0; i < zeros; i++)
			value += '0';
		return value;
	}

	_readFloating(parameterizedType) {
		if ((parameterizedType & 0x08) === 0)
			return this._buffer.readFloat64();

		var v = this._buffer.readUintN(parameterizedType & 0x03);
		if ((parameterizedType & 0x04) !== 0)
			v = -v;
		return (v / 1000.0);
	}

	_readBigFloating(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);
		if (SpearalDecoder._isStringReference(parameterizedType))
			return this._sharedStrings[indexOrLength];
		return this._readBigNumberData(indexOrLength);
	}

	_readString(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);
		return this._readStringData(parameterizedType, indexOrLength);
	}

	_readByteArray(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var array = this._buffer.readByteArray(indexOrLength);
		this._sharedObjects.push(array);
		return array;
	}

	_readDateTime(parameterizedType) {
		var hasDate = ((parameterizedType & 0x08) != 0),
			hasTime = ((parameterizedType & 0x04) != 0),
			year = 0,
			month = 0,
			date = 0,
			hours = 0,
			minutes = 0,
			seconds = 0,
			millis = 0,
			subsecondsType;

		if (hasDate) {
			month = this._buffer.readUint8();
			date = this._buffer.readUint8();

			year = this._buffer.readUintN((month >>> 4) & 0x03);
			if ((month & 0x80) != 0)
				year = -year;
			year += 2000;

			month &= 0x0f;
			month--;
		}

		if (hasTime) {
			hours = this._buffer.readUint8();
			minutes = this._buffer.readUint8();
			seconds = this._buffer.readUint8();

			subsecondsType = (parameterizedType & 0x03);
			if (subsecondsType !== 0) {
				millis = this._buffer.readUintN(hours >>> 5);
				if (subsecondsType === 1)
					millis /= 1000000;
				else if (subsecondsType === 2)
					millis /= 1000;
    		}

    		hours &= 0x1f;
		}

		return new Date(Date.UTC(year, month, date, hours, minutes, seconds, millis));
	}

	_readCollection(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var value = new Array(indexOrLength);
		this._sharedObjects.push(value);
		for (var i = 0; i < indexOrLength; i++)
			value[i] = this.readAny();
		return value;
	}

	_readMap(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var value = new Map();
		this._sharedObjects.push(value);
		for (var i = 0; i < indexOrLength; i++) {
			var key = this.readAny();
			var val = this.readAny();
			value.set(key, val);
		}
		return value;
	}

	_readEnum(parameterizedType) {
		return {
			kind: this._readString(parameterizedType),
			name: this.readAny()
		};
	}

	_readClass(parameterizedType) {
		var className = this._readString(parameterizedType),
			cls = window[className];
		return (cls != null ? cls : className);
	}

	_readBean(parameterizedType) {
		var indexOrLength = this._readIndexOrLength(parameterizedType);

		if (SpearalDecoder._isObjectReference(parameterizedType))
			return this._sharedObjects[indexOrLength];

		var description = this._readStringData(parameterizedType, indexOrLength),
			descriptor = _SpearalClassDescriptor.forDescription(description),
			value = this._context.getInstance(descriptor);

		this._sharedObjects.push(value);

		for (var name of descriptor.propertyNames)
			value[name] = this.readAny();

		return value;
	}

	_readBigNumberData(length) {
		var count = (length / 2) + (length % 2),
			value = "";

		for (var i = 0; i < count; i++) {
			var b = this._buffer.readUint8();
			value += SpearalBigNumber.charAt((b & 0xf0) >>> 4);
			if (value.length === length)
				break;
			value += SpearalBigNumber.charAt(b & 0x0f);
		}

		this._sharedStrings.push(value);
		return value;
	}

	_readIndexOrLength(parameterizedType) {
		return this._buffer.readUintN(parameterizedType & 0x03);
	}

	_readStringData(parameterizedType, indexOrLength) {
		if (SpearalDecoder._isStringReference(parameterizedType))
			return this._sharedStrings[indexOrLength];

		if (indexOrLength === 0)
			return "";

		var value = decodeURIComponent(escape(this._buffer.readUTF(indexOrLength)));
		this._sharedStrings.push(value);
		return value;
	}

	static _isObjectReference(parameterizedType) {
		return ((parameterizedType & 0x08) !== 0);
	}

	static _isStringReference(parameterizedType) {
		return ((parameterizedType & 0x04) !== 0);
	}
}

<|endoftext|>