<commit_before>import Ember from 'ember';
import computed from 'ember-computed';
const { observer, run, get, Mixin, guidFor, isPresent } = Ember;

/**
 * Merges 1 or more changesets together returning a fresh changeset
 * containing the changes and errors of all combined changesets.
 *
 * @param  {Changeset...} changesets
 * @public
 * @return {Changeset}
 */
export function compositeChangeset(...changesets) {
  let masterChangeset = changesets.shift();
  changesets.forEach((changeset) => masterChangeset = masterChangeset.merge(changeset));
  return masterChangeset;
}

export const SECTIONS = '_sections';
export const CHANGE_ACTION = '_change';
export const REMOVE_ACTION = '_remove';
export default Mixin.create({
  [SECTIONS]: null,

  title: null,

  init() {
    this[SECTIONS] = new Map();
    this._super();
  },

  changesetDidChange: observer('changeset._changes', 'changeset._errors', function() {
    let changeset = get(this, 'changeset');
    if (changeset.get('isDirty')) {
      this.send('_sendUpdate');
    }
  }),

  compositeChangeset: computed('changeset', SECTIONS, {
    get() {
      let masterChangeset = get(this, 'changeset');
      if (!isPresent(masterChangeset)) {
        return null;
      }

      return compositeChangeset(masterChangeset, ...this[SECTIONS].values());
    }
  }),

  changesetId: computed('changeset', {
    get() {
      return guidFor(get(this, 'changeset'));
    }
  }),

  change: computed.alias('compositeChangeset.change'),
  changes: computed.alias('compositeChangeset.changes'),
  error: computed.alias('compositeChangeset.error'),
  errors: computed.alias('compositeChangeset.errors'),

  actions: {
    /**
     * Handles changes from form inputs by field name and value, assigning the
     * result directly to this section's changeset.
     *
     * NOTE: There's no need to trigger an update here as we do so in the observer.
     *
     * @private
     */
    inputValueChanged(field, value) {
      let sectionChangeset = get(this, 'changeset');
      sectionChangeset.set(field, value);
      this.propertyDidChange('changeset');
      this.send('_sendUpdate');
    },

    /**
     * Handles changes from nested changesets, merging them with our own changeset,
     * then propagating the composite changeset to the parent section/form.
     *
     * @private
     */
    mergeSubChangeset({ id, changeset }) {
      let sections = get(this, SECTIONS);
      sections.set(id, changeset);
      this.propertyDidChange(SECTIONS);

      this.send('_sendUpdate');
    },

    removeSubChangeset({ id }) {
      let sections = get(this, SECTIONS);
      if (sections.has(id)) {
        sections.get(id).rollback();
        sections.delete(id);
        this.propertyDidChange(SECTIONS);
        this.send('_sendUpdate');
      }
    },

    _sendUpdate() {
      run.scheduleOnce('actions', this, function() {
        let changeset = this.get('changeset');
        if (!changeset) {
          return;
        }

        let compositeChangeset = this.get('compositeChangeset');
        let changesetId = get(this, 'changesetId');
        this.sendAction(CHANGE_ACTION, { id: changesetId, changeset: compositeChangeset });
      });
    }
  }
});
<commit_msg>Better observations of changeset<commit_after>import Ember from 'ember';
import computed from 'ember-computed';

const { observer, run, get, Mixin, guidFor, isPresent } = Ember;

/**
 * Merges 1 or more changesets together returning a fresh changeset
 * containing the changes and errors of all combined changesets.
 *
 * @param  {Changeset...} changesets
 * @public
 * @return {Changeset}
 */
export function compositeChangeset(...changesets) {
  let masterChangeset = changesets.shift();
  changesets.forEach((changeset) => masterChangeset = masterChangeset.merge(changeset));
  return masterChangeset;
}

export const SECTIONS = '_sections';
export const CHANGE_ACTION = '_change';
export const REMOVE_ACTION = '_remove';
export default Mixin.create({
  [SECTIONS]: null,

  title: null,

  init() {
    this[SECTIONS] = new Map();
    this._super();
  },

  changesetDidChange: observer('changeset.change', 'changeset.error', 'changeset', function() {
    // console.debug('changesetDidChange');
    let changeset = get(this, 'changeset');
    if (changeset.get('isDirty')) {
      this.send('_sendUpdate');
    }
  }),

  compositeChangeset: computed('changeset.change', 'changeset.error', 'changeset', SECTIONS, {
    get() {
      let masterChangeset = get(this, 'changeset');
      if (!isPresent(masterChangeset)) {
        return null;
      }

      return compositeChangeset(masterChangeset, ...this[SECTIONS].values());
    }
  }),

  changesetId: computed('changeset', {
    get() {
      return guidFor(get(this, 'changeset'));
    }
  }),

  change: computed.alias('compositeChangeset.change'),
  changes: computed.alias('compositeChangeset.changes'),
  error: computed.alias('compositeChangeset.error'),
  errors: computed.alias('compositeChangeset.errors'),

  actions: {
    /**
     * Handles changes from form inputs by field name and value, assigning the
     * result directly to this section's changeset.
     *
     * NOTE: There's no need to trigger an update here as we do so in the observer.
     *
     * @private
     */
    inputValueChanged(field, value) {
      let sectionChangeset = get(this, 'changeset');
      sectionChangeset.set(field, value);
      this.propertyDidChange('changeset');
      this.send('_sendUpdate');
    },

    /**
     * Handles changes from nested changesets, merging them with our own changeset,
     * then propagating the composite changeset to the parent section/form.
     *
     * @private
     */
    mergeSubChangeset({ id, changeset }) {
      let sections = get(this, SECTIONS);
      sections.set(id, changeset);
      this.propertyDidChange(SECTIONS);

      this.send('_sendUpdate');
    },

    removeSubChangeset({ id }) {
      let sections = get(this, SECTIONS);
      if (sections.has(id)) {
        sections.get(id).rollback();
        sections.delete(id);
        this.propertyDidChange(SECTIONS);
        this.send('_sendUpdate');
      }
    },

    _sendUpdate() {
      run.scheduleOnce('actions', this, function() {
        let changeset = this.get('changeset');
        if (!changeset) {
          return;
        }

        let compositeChangeset = this.get('compositeChangeset');
        let changesetId = get(this, 'changesetId');
        this.sendAction(CHANGE_ACTION, { id: changesetId, changeset: compositeChangeset });
      });
    }
  }
});
<|endoftext|>


<commit_before>game.module(
    'game.cardMenu'
).body(function() {

game.createClass('CardMenu', {

    cards: [
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null}
        ],

    init: function() {

        // Add a sprite to the game for each card
        for(var i = 0; i < this.cards.length; i++){
            this.cards[i].sprite = new game.Sprite(this.cards[i].name).addTo(game.scene.stage);
            this.cards[i].sprite.scale.x = this.cards[i].sprite.scale.y = 0.3;

            this.cards[i].sprite.interactive = true;

            // Click/tap
            this.cards[i].sprite.click = this.cards[i].sprite.tap = this.clickedCard.bind(this.cards[i].sprite);

            // Mouse over
            this.cards[i].sprite.mouseover = this.mouseOverCard.bind(this.cards[i].sprite);

            // Mouse out
            this.cards[i].sprite.mouseout = this.mouseOutCard.bind(this.cards[i].sprite);
        }

    },

    mouseOutCard: function(mousedata) {
        mousedata.target.scale.x = mousedata.target.scale.y = 0.3;
        //mousedata.target.position.y = game.system.height - this.cards[0].sprite.height*0.15;
        mousedata.target.position.y += 500;
    },

    mouseOverCard: function(mousedata) {
        //console.log("Mousing over card at (" + mousedata.global.x + "," + mousedata.global.y + ")");
        mousedata.target.scale.x = mousedata.target.scale.y = 0.5;
        mousedata.target.position.y -= 500;
    },

    clickedCard: function(mousedata){
        console.log("clicked card");
        //console.log("event target: " + mousedata.global.x);
    },

    // Update the cards to match cards in hand
    updateCards: function(cardsInHand) {

        if(cardsInHand.length == 0){
            console.log("No cards in hand! CardMenu will be empty");
            return;
        }

        // Update names and sprites in "cards"
        // Todo: update all 6 cards
        for(var i = 0; i < cardsInHand.length; i++){
            this.cards[i].name = cardsInHand[i];
            this.cards[i].sprite.setTexture( this.cards[i].name );
        }

        // Todo: check for number of cards in hand if less than 6
        for(var i = 0; i < 6; i++) {
            this.cards[i].sprite.position.set( 30 + this.cards[i].sprite.width*0.25*i, game.system.height - this.cards[i].sprite.height*0.1);

            //this.cards[i].sprite.position.set( (((game.system.width/ (this.cards.length+2) )*5 + this.cards[i].sprite.width)/this.cards.length) * i, game.system.height - this.cards[i].sprite.height*0.15);

        }

        this.printCards();
    },

    show: function() {
        // Show the card menu
    },

    hide: function() {
        // Hide the card menu
    },

    enlargeCard: function() {
        // Enlarge a card for inspection
    },

    // Print names of cards in console for debugging
    printCards: function() {
        console.log("Printing contents of \"cards\" in CardMenu...");
        for(var i = 0; i < this.cards.length; i++){
            console.log("cards[" + i + "]: " + this.cards[i].name );
        }
    }

});

});
<commit_msg>Card Selection Test<commit_after>game.module(
    'game.cardMenu'
).body(function() {

game.createClass('CardMenu', {

    cards: [
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null},
        {name: 'close', sprite: null}
        ],

    init: function() {

        // Add a sprite to the game for each card
        for(var i = 0; i < this.cards.length; i++){
            this.cards[i].sprite = new game.Sprite(this.cards[i].name).addTo(game.scene.stage);
            this.cards[i].sprite.scale.x = this.cards[i].sprite.scale.y = 0.3;

            this.cards[i].sprite.interactive = true;

            // Click/tap
            this.cards[i].sprite.click = this.cards[i].sprite.tap = this.clickedCard.bind(this.cards[i].sprite);

            // Mouse over
            this.cards[i].sprite.mouseover = this.mouseOverCard.bind(this.cards[i].sprite);

            // Mouse out
            this.cards[i].sprite.mouseout = this.mouseOutCard.bind(this.cards[i].sprite);
        }

    },

    mouseOutCard: function(mousedata) {
        mousedata.target.scale.x = mousedata.target.scale.y = 0.3;
        //mousedata.target.position.y = game.system.height - this.cards[0].sprite.height*0.15;
        mousedata.target.position.y += 500;
    },

    mouseOverCard: function(mousedata) {
        //console.log("Mousing over card at (" + mousedata.global.x + "," + mousedata.global.y + ")");
        mousedata.target.scale.x = mousedata.target.scale.y = 0.5;
        mousedata.target.position.y -= 500;
		//console.log("" + mousedata.target.position.x);

		// These numbers will have to be adjusted if card size is adjusted.
		if (mousedata.target.position.x <= 50)
			console.log("1");
		else if (mousedata.target.position.x <= 100)
			console.log("2");
		else if (mousedata.target.position.x <= 200)
			console.log("3");
		else if (mousedata.target.position.x <= 250)
			console.log("4");
		else if (mousedata.target.position.x <= 350)
			console.log("5");
		else
			console.log("6");
    },

    clickedCard: function(mousedata){
        console.log("clicked card");
        //console.log("event target: " + mousedata.global.x);
		if (mousedata.target.position.x <= 50)
			console.log("1");
		else if (mousedata.target.position.x <= 100)
			console.log("2");
		else if (mousedata.target.position.x <= 200)
			console.log("3");
		else if (mousedata.target.position.x <= 250)
			console.log("4");
		else if (mousedata.target.position.x <= 350)
			console.log("5");
		else
			console.log("6");
    },

    // Update the cards to match cards in hand
    updateCards: function(cardsInHand) {

        if(cardsInHand.length == 0){
            console.log("No cards in hand! CardMenu will be empty");
            return;
        }

        // Update names and sprites in "cards"
        // Todo: update all 6 cards
        for(var i = 0; i < cardsInHand.length; i++){
            this.cards[i].name = cardsInHand[i];
            this.cards[i].sprite.setTexture( this.cards[i].name );
        }

        // Todo: check for number of cards in hand if less than 6
        for(var i = 0; i < 6; i++) {
            this.cards[i].sprite.position.set( 30 + this.cards[i].sprite.width*0.25*i, game.system.height - this.cards[i].sprite.height*0.1);

            //this.cards[i].sprite.position.set( (((game.system.width/ (this.cards.length+2) )*5 + this.cards[i].sprite.width)/this.cards.length) * i, game.system.height - this.cards[i].sprite.height*0.15);

        }

        this.printCards();
    },

    show: function() {
        // Show the card menu
    },

    hide: function() {
        // Hide the card menu
    },

    enlargeCard: function() {
        // Enlarge a card for inspection
    },

    // Print names of cards in console for debugging
    printCards: function() {
        console.log("Printing contents of \"cards\" in CardMenu...");
        for(var i = 0; i < this.cards.length; i++){
            console.log("cards[" + i + "]: " + this.cards[i].name );
        }
    }

});

});
<|endoftext|>


<commit_before>// Gather actionNames from all registered modules for hot-key mapping

import { modules } from 'stripes-loader'; // eslint-disable-line
import stripesComponents from '@folio/stripes-components/package.json';

function addKeys(register, list) {
  if (list) {
    for (const actionName of list) {
      register[actionName] = true;
    }
  }
}

export default function gatherActions() {
  const allActions = {};

  for (const key of Object.keys(modules)) {
    const set = modules[key];
    for (const key2 of Object.keys(set)) {
      const module = set[key2];
      addKeys(allActions, module.actionNames);
    }
  }

  addKeys(allActions, stripesComponents.stripes.actionNames);

  return Object.keys(allActions);
}
<commit_msg>Gather names of modules that use action-names<commit_after>// Gather actionNames from all registered modules for hot-key mapping

import { modules } from 'stripes-loader'; // eslint-disable-line
import stripesComponents from '@folio/stripes-components/package.json';

function addKeys(moduleName, register, list) {
  if (list) {
    for (const actionName of list) {
      if (!register[actionName]) register[actionName] = [];
      register[actionName].push(moduleName);
    }
  }
}

export default function gatherActions() {
  const allActions = {};

  for (const key of Object.keys(modules)) {
    const set = modules[key];
    for (const key2 of Object.keys(set)) {
      const module = set[key2];
      addKeys(module.module, allActions, module.actionNames);
    }
  }

  addKeys('stripes-components', allActions, stripesComponents.stripes.actionNames);

  return Object.keys(allActions);
}
<|endoftext|>


<commit_before>'use strict';

const { memoize, fusionMerge } = require('../../utilities');

const { processEnv, ENV_VARS_PREFIX, basicNamesMap } = require('./constants');
const { transformEnvVars } = require('./transform');

// Retrieve environment variables related to this project,
// as a normalized object, ready to be used as options
// Environment variables must be prefixed with API_ENGINE__*
// They must be uppercased with underscore, e.g. `PAGE_SIZE` instead of pageSize
// The value will be transtyped, e.g. it can be a number or a boolean
// Nested variables can be indicated with double-underscores,
// e.g. `HTTP__HOST` becomes `{ http: { host } }`
// Array variables can be indicated the same way, but with indexes,
// e.g. `ARRAY__0`, `ARRAY__1`, etc.
const getEnvVars = function () {
  return mappers.reduce(
    (envVars, mapper) => mapper({ envVars }),
    {},
  );
};

// Exclude environment variables not meant for the api-engine
const filterEnvVars = function () {
  return Object.keys(processEnv)
    .filter(name => ENV_VARS_PREFIX.test(name) || basicNamesMap[name]);
};

// Transform to array of `{ name, value }`
const objectifyEnvVars = function ({ envVars }) {
  return envVars.map(name => ({ name, value: processEnv[name] }));
};

// Merge to final output
const mergeAll = function ({ envVars }) {
  const envVarsA = envVars
    .map(({ name, value }) => ({ [name]: value }));
  const envVarsB = fusionMerge({}, ...envVarsA);
  return envVarsB;
};

const mappers = [
  filterEnvVars,
  objectifyEnvVars,
  transformEnvVars,
  mergeAll,
];

const mGetEnvVars = memoize(getEnvVars);

module.exports = {
  getEnvVars: mGetEnvVars,
};
<commit_msg>Small refactoring<commit_after>'use strict';

const { memoize, fusionMerge } = require('../../utilities');

const { processEnv, ENV_VARS_PREFIX, basicNamesMap } = require('./constants');
const { transformEnvVars } = require('./transform');

// Retrieve environment variables related to this project,
// as a normalized object, ready to be used as options
// Environment variables must be prefixed with API_ENGINE__*
// They must be uppercased with underscore, e.g. `PAGE_SIZE` instead of pageSize
// The value will be transtyped, e.g. it can be a number or a boolean
// Nested variables can be indicated with double-underscores,
// e.g. `HTTP__HOST` becomes `{ http: { host } }`
// Array variables can be indicated the same way, but with indexes,
// e.g. `ARRAY__0`, `ARRAY__1`, etc.
const getEnvVars = function () {
  return mappers.reduce((envVars, mapper) => mapper({ envVars }), {});
};

// Exclude environment variables not meant for the api-engine
const filterEnvVars = function () {
  return Object.keys(processEnv)
    .filter(name => ENV_VARS_PREFIX.test(name) || basicNamesMap[name]);
};

// Transform to array of `{ name, value }`
const objectifyEnvVars = function ({ envVars }) {
  return envVars.map(name => ({ name, value: processEnv[name] }));
};

// Merge to final output
const mergeAll = function ({ envVars }) {
  const envVarsA = envVars
    .map(({ name, value }) => ({ [name]: value }));
  const envVarsB = fusionMerge({}, ...envVarsA);
  return envVarsB;
};

const mappers = [
  filterEnvVars,
  objectifyEnvVars,
  transformEnvVars,
  mergeAll,
];

const mGetEnvVars = memoize(getEnvVars);

module.exports = {
  getEnvVars: mGetEnvVars,
};
<|endoftext|>


<commit_before>import { scaleToSet, add, addSet, set, subtract, magnitude, magnitudeSqr } from 'pura/vector/tuple';
import { sign } from 'pura/math';
import state from 'state';
import { avngSprite, chldSprite, protSprite, persSprite, gemSprite } from 'overworld/graphics';
import { camera } from 'camera';
import { inputs } from 'controls';
import { viewWidth } from 'dom';

const direction = [0, 0];
const charSpeed = ()=> inputs.space || inputs.shift ? 6 : 3;

const follow =
  (sprite, distance) => {
    const relativePos = subtract(state.position, sprite);
    if(magnitude(relativePos) > distance) {
      addSet(sprite, scaleToSet(relativePos, charSpeed()));
    }
  };

export default () => {
  // Character Controls
  direction[0] = 0;
  direction[1] = 0;
  if(!state.dialog.script.length){
    if(inputs.w || inputs.up || inputs.s || inputs.down || inputs.d || inputs.right || inputs.a || inputs.left) state.target = null;
    if(inputs.w || inputs.up) direction[1] += 1;
    if(inputs.s || inputs.down) direction[1] -= 1;
    if(inputs.d || inputs.right) direction[0] += 1;
    if(inputs.a || inputs.left) direction[0] -= 1;
  }

  if(state.position[0] >= state.miasma - direction[0]*charSpeed()) {
    return;
  }

  const movement = scaleToSet(direction, charSpeed());
  addSet(state.position, movement);
  if(state.target !== null) {
    const diff = subtract(state.target, state.position);
    if(magnitudeSqr(diff) < 3) { state.target = null }
    addSet(state.position, scaleToSet(diff, charSpeed()));
  }
  state.position[1] = Math.min(Math.max(state.position[1], 5), 1000);
  avngSprite[0] = state.position[0];
  avngSprite[1] = state.position[1];
  follow(protSprite, 20 + Date.now() % 300 / 30);
  follow(chldSprite, 45 + Date.now() % 300 / 30);
  follow(persSprite, 70 + Date.now() % 300 / 30);
  follow(gemSprite, 90 + Date.now() % 300 / 30);
  const xDiff = state.position[0] - camera[0];
  if(Math.abs(xDiff) > viewWidth * 0.2) camera[0] += xDiff - sign(xDiff) * viewWidth * 0.2;
  set(camera, ...add(state.position, [0, -100]));
};
<commit_msg>Remove current bounding logic<commit_after>import { scaleToSet, add, addSet, set, subtract, magnitude, magnitudeSqr } from 'pura/vector/tuple';
import { sign } from 'pura/math';
import state from 'state';
import { avngSprite, chldSprite, protSprite, persSprite, gemSprite } from 'overworld/graphics';
import { camera } from 'camera';
import { inputs } from 'controls';
import { viewWidth } from 'dom';

const direction = [0, 0];
const charSpeed = ()=> inputs.space || inputs.shift ? 6 : 3;

const follow =
  (sprite, distance) => {
    const relativePos = subtract(state.position, sprite);
    if(magnitude(relativePos) > distance) {
      addSet(sprite, scaleToSet(relativePos, charSpeed()));
    }
  };

export default () => {
  // Character Controls
  direction[0] = 0;
  direction[1] = 0;
  if(!state.dialog.script.length){
    if(inputs.w || inputs.up || inputs.s || inputs.down || inputs.d || inputs.right || inputs.a || inputs.left) state.target = null;
    if(inputs.w || inputs.up) direction[1] += 1;
    if(inputs.s || inputs.down) direction[1] -= 1;
    if(inputs.d || inputs.right) direction[0] += 1;
    if(inputs.a || inputs.left) direction[0] -= 1;
  }

  const movement = scaleToSet(direction, charSpeed());
  addSet(state.position, movement);
  if(state.target !== null) {
    const diff = subtract(state.target, state.position);
    if(magnitudeSqr(diff) < 3) { state.target = null }
    addSet(state.position, scaleToSet(diff, charSpeed()));
  }
  avngSprite[0] = state.position[0];
  avngSprite[1] = state.position[1];
  follow(protSprite, 20 + Date.now() % 300 / 30);
  follow(chldSprite, 45 + Date.now() % 300 / 30);
  follow(persSprite, 70 + Date.now() % 300 / 30);
  follow(gemSprite, 90 + Date.now() % 300 / 30);
  const xDiff = state.position[0] - camera[0];
  if(Math.abs(xDiff) > viewWidth * 0.2) camera[0] += xDiff - sign(xDiff) * viewWidth * 0.2;
  set(camera, ...add(state.position, [0, -100]));
};
<|endoftext|>


<commit_before>/*
---

script: Object.js

description: An observable object

license: Public domain (http://unlicense.org).

authors: Yaroslaff Fedin

requires:
  - LSD

provides:
  - LSD.Object

...
*/

LSD.Object = function(object) {
  if (object) for (var key in object) this.set(key, object[key]);
}
LSD.Object.prototype = {
  set: function(key, value) {
    var old = this[key];
    if (old === value) return false;
    if (old) {
      var onBeforeChange = this._beforechange;
      if (onBeforeChange) for (var i = 0, fn; fn = onBeforeChange[i++];) fn(key, old, false);
    }
    if (key == 'person' && value == false) debugger
    this[key] = value;
    var onChange = this._change;
    if (onChange) for (var i = 0, fn; fn = onChange[i++];) fn(key, value, true);
    var watched = this._watched;
    if (watched && (watched = watched[key])) for (var i = 0, fn; fn = watched[i++];) fn(value, old);
    return true;
  },
  unset: function(key, value) {
    var old = this[key];
    if (old == null) return false;
    for (var i = 0, a = this._change, fn; a && (fn = a[i++]);) fn(key, old, false);
    var watched = this._watched;
    if (watched && (watched = watched[key])) for (var i = 0, fn; fn = watched[i++];) fn(null, old);
    delete this[key];
    return true;
  },
  addEvent: function(name, callback) {
    var key = '_' + name;
    (this[key] || (this[key] = [])).push(callback);
    return this;
  },
  removeEvent: function(name, callback) {
    var key = '_' + name;
    var index = this[key].indexOf(callback);
    if (index > -1) this[key].splice(0, 1);
    return this;
  },
  watch: function(name, callback, lazy) {
    var index = name.indexOf('.');
    if (index > -1) {
      var finder = function(value, old) {
        (value || old)[value ? 'watch' : 'unwatch'](name.substring(index + 1), callback);
      };
      finder.callback = callback;
      this.watch(name.substr(0, index), finder)
    } else {
      var watched = (this._watched || (this._watched = {}));
      (watched[name] || (watched[name] = [])).push(callback);
      var value = this[name];
      if (!lazy && value != null) callback(value);
    }
  },
  unwatch: function(name, callback) {
    var index = name.indexOf('.');
    if (index > -1) {
      this.unwatch(name.substr(0, index), callback)
    } else {
      var watched = this._watched[name];
      for (var i = 0, fn; fn = watched[i++];) {
        if (fn == callback || fn.callback == callback) {
          watched.splice(i, 1);
          if (value != null) fn(null, value);
          break;
        }
      }
    }
  },
  toObject: function() {
    var object = {};
    for (var name in this) if (this.hasProperty(name)) object[name] = this[name];
    return {};
  },
  hasProperty: function(name) {
    return this.hasOwnProperty(name) && (name.charAt(0) != '_')
  }
};

<commit_msg>remove debugger<commit_after>/*
---

script: Object.js

description: An observable object

license: Public domain (http://unlicense.org).

authors: Yaroslaff Fedin

requires:
  - LSD

provides:
  - LSD.Object

...
*/

LSD.Object = function(object) {
  if (object) for (var key in object) this.set(key, object[key]);
}
LSD.Object.prototype = {
  set: function(key, value) {
    var old = this[key];
    if (old === value) return false;
    if (old) {
      var onBeforeChange = this._beforechange;
      if (onBeforeChange) for (var i = 0, fn; fn = onBeforeChange[i++];) fn(key, old, false);
    }

    this[key] = value;
    var onChange = this._change;
    if (onChange) for (var i = 0, fn; fn = onChange[i++];) fn(key, value, true);
    var watched = this._watched;
    if (watched && (watched = watched[key])) for (var i = 0, fn; fn = watched[i++];) fn(value, old);
    return true;
  },
  unset: function(key, value) {
    var old = this[key];
    if (old == null) return false;
    for (var i = 0, a = this._change, fn; a && (fn = a[i++]);) fn(key, old, false);
    var watched = this._watched;
    if (watched && (watched = watched[key])) for (var i = 0, fn; fn = watched[i++];) fn(null, old);
    delete this[key];
    return true;
  },
  addEvent: function(name, callback) {
    var key = '_' + name;
    (this[key] || (this[key] = [])).push(callback);
    return this;
  },
  removeEvent: function(name, callback) {
    var key = '_' + name;
    var index = this[key].indexOf(callback);
    if (index > -1) this[key].splice(0, 1);
    return this;
  },
  watch: function(name, callback, lazy) {
    var index = name.indexOf('.');
    if (index > -1) {
      var finder = function(value, old) {
        (value || old)[value ? 'watch' : 'unwatch'](name.substring(index + 1), callback);
      };
      finder.callback = callback;
      this.watch(name.substr(0, index), finder)
    } else {
      var watched = (this._watched || (this._watched = {}));
      (watched[name] || (watched[name] = [])).push(callback);
      var value = this[name];
      if (!lazy && value != null) callback(value);
    }
  },
  unwatch: function(name, callback) {
    var index = name.indexOf('.');
    if (index > -1) {
      this.unwatch(name.substr(0, index), callback)
    } else {
      var watched = this._watched[name];
      for (var i = 0, fn; fn = watched[i++];) {
        if (fn == callback || fn.callback == callback) {
          watched.splice(i, 1);
          if (value != null) fn(null, value);
          break;
        }
      }
    }
  },
  toObject: function() {
    var object = {};
    for (var name in this) if (this.hasProperty(name)) object[name] = this[name];
    return {};
  },
  hasProperty: function(name) {
    return this.hasOwnProperty(name) && (name.charAt(0) != '_')
  }
};

<|endoftext|>


<commit_before>app.controller("OrganizationController", ["$scope", "$uibModal", "OrganizationService", function($scope, OrganizationService) {
	//add as needed
	$scope.organizations = [];
	$scope.alerts = [];
	$scope.isEditing = false;//look into this one

	//get orgs from api
	//come back for the other gets
	//make docblocks better
	$scope.getOrganizations = function() {
		OrganizationService.all()
				.then(function(result) {
					if(result.data.status === 200) {
						$scope.organizations = result.data.data;
					} else {
						$scope.alerts[0] = {type: "danger", msg: result.data.message};
					}
				});
	};

	//create new organization
	$scope.createOrganization = function(organization, validated) {
		if(validated === true) {
			OrganizationService.create(organization)
					.then(function(result) {
						if(result.data.status === 200) {
							$scope.alerts[0] = {type: "success", msg: result.data.message};
						} else {
							$scope.alerts[0] = {type: "danger", msg: result.data.message};
						}
					});
		}
	};

	//update the organization
	$scope.updateOrganization = function(organization, validated) {
		if(validated === true && $scope.isEditing === true) {
			OrganizationService.update(organization.orgId, organization)
					.then(function(result) {
						if(result.data.status === 200) {
							$scope.alerts[0] = {type: "success", msg: result.data.message};
						} else {
							$scope.alerts[0] = {type: "danger", msg: result.data.message};
						}
					});
		}
	};

	//delete the organization
	$scope.deleteOrganization = function(orgId) {
		//create a modal to ask for confirmation
		var message = "Do you really want to delete this organization?";
		var modalHtml = '
' + message + '

<button class="btn btn-primary" ng-click="yes()">Yes</button><button class="btn btn-warning" ng-click-"no()">No</button>
';
		var modalInstance = $uibModal.open({
			template: modalHtml,
			controller: ModalInstanceCtrl
		});

		//if yes is selected, delete the organization
		modalInstance.result.then(function() {
			OrganizationService.destroy(orgId)
					.then(function(result) {
						if(result.data.status === 200) {
							$scope.alerts[0] = {type: "success", msg: result.data.message};
						} else {
							$scope.alerts[0] = {type: "danger", msg: result.data.message};
						}
					})
		});
	};
}]);<commit_msg>more progress on organization controller https://app.asana.com/0/inbox/60990646650925/70724582720491/70724582720494<commit_after>app.controller("OrganizationController", ["$scope", "$uibModal", "OrganizationService", function($scope, OrganizationService) {
	//add as needed
	$scope.organizations = [];
	$scope.alerts = [];
	$scope.isEditing = false;

	//set the isEditing value to true
	//here in case we want to add an editing "well", may be omitted/altered later
	$scope.setEditedOrganization = function() {
		$scope.isEditing = true;
	};

	//cancels editing
	$scope.cancelEditing = function() {
		$scope.isEditing = false;
	}

	//get orgs from api
	//come back for the other gets
	//make docblocks better
	$scope.getOrganizations = function() {
		OrganizationService.all()
				.then(function(result) {
					if(result.data.status === 200) {
						$scope.organizations = result.data.data;
					} else {
						$scope.alerts[0] = {type: "danger", msg: result.data.message};
					}
				});
	};

	$scope.getOrganizationById = function(orgId, validated) {
		if(validated === true) {
			OrganizationService.fetch(orgId)
					.then(function(result) {
						if(result.data.status === 200) {
							$scope.organizations = result.data.data;
						} else {
							$scope.alerts[0] = {type: "danger", msg: result.data.message};
						}
					});
		}
	};

	//create new organization
	$scope.createOrganization = function(organization, validated) {
		if(validated === true) {
			OrganizationService.create(organization)
					.then(function(result) {
						if(result.data.status === 200) {
							$scope.alerts[0] = {type: "success", msg: result.data.message};
						} else {
							$scope.alerts[0] = {type: "danger", msg: result.data.message};
						}
					});
		}
	};

	//update the organization
	$scope.updateOrganization = function(organization, validated) {
		if(validated === true && $scope.isEditing === true) { //that scope.isEditing may change
			OrganizationService.update(organization.orgId, organization)
					.then(function(result) {
						if(result.data.status === 200) {
							$scope.alerts[0] = {type: "success", msg: result.data.message};
						} else {
							$scope.alerts[0] = {type: "danger", msg: result.data.message};
						}
					});
		}
	};

	//delete the organization
	$scope.deleteOrganization = function(orgId) {
		//create a modal to ask for confirmation
		var message = "Do you really want to delete this organization?";
		var modalHtml = '
' + message + '

<button class="btn btn-primary" ng-click="yes()">Yes</button><button class="btn btn-warning" ng-click-"no()">No</button>
';
		var modalInstance = $uibModal.open({
			template: modalHtml,
			controller: ModalInstanceCtrl
		});

		//if yes is selected, delete the organization
		modalInstance.result.then(function() {
			OrganizationService.destroy(orgId)
					.then(function(result) {
						if(result.data.status === 200) {
							$scope.alerts[0] = {type: "success", msg: result.data.message};
						} else {
							$scope.alerts[0] = {type: "danger", msg: result.data.message};
						}
					})
		});
	};
}]);

//modal instance controller for deletion prompt
var ModalInstanceCtrl = function($scope, $uibModalInstance) {
	$scope.yes = function() {
		$uibModalInstance.close();
	};
	$scope.no = function() {
		$uibModalInstance.dismiss('cancel');
	};
};<|endoftext|>


<commit_before>/*
---
name: UI.Widget
description: Base Widget Class
requires: [UI, UI.Sheet, Core/Class, Core/Events, Core/Options]
provides: UI.Widget
...
*/

(function(){

var widgets = UI.widgets = {}; UID = 0;
var focusedWidgets = {};

var Widget = UI.Widget = new Class({

	Implements: [Events, Options],

	name: 'widget',

	options: {
		/*
			onFocus: $empty,
			onBlur: $empty,
			onEnable: $empty,
			onDisable: $empty,
			parentWidgte: null,
			styles: {},
		*/
		id: '',
		className: ''
	},

	initialize: function(options){
		this.uid = ART.uniqueID();

		this.parentWidget = null;
		this._childWidgets = [];

		var parent;
		if (options) {
			if (options.parentWidget) {
				parent = options.parentWidget;
				delete options.parentWidget;
			}
		}

		this.setOptions(options);
		if (this.options.id) this.setID(this.options.id);

		this._classNames = [];
		if (this.options.className) this.options.className.split(' ').each(function(className){
			this.addClass(className);
		}, this);

		if (parent) this.register(parent);
	},

	/* ID */

	setID: function(id){
		this.id = id;
		return this;
	},

	/* classNames */

	addClass: function(className){
		this._classNames.push(className);
		return this;
	},

	removeClass: function(className){
		this._classNames.erase(className);
		return this;
	},

	hasClass: function(className){
		return this._classNames.contains(className);
	},

	setStyles: function(styles){
		this.setOptions({
			styles: styles
		});
	},

	/*
		states
	*/

	_states: {
		disabled: false,
		focus: false,
		active: false
	},

	setState: function(name, state) {
		this._states[name] = state;
		return this;
	},

	getState: function(name) {
		return this._states[name];
	},

	/* enable, disable */

	//enabled means you can interact with a widget
	//it can be activated, it can receive focus, it can update itself or animate itself.

	enable: function(){
		if ((this.parentWidget && this.parentWidget.getState('disabled')) || !this.getState('disabled')) return false;
		this._disabledByParent = false;
		this.setState('disabled', false);
		this.fireEvent('enable');

		this._childWidgets.each(function(child){
			if (child._disabledByParent) child.enable();
		});

		return true;
	},

	//disabled means you cannot interact with a widget
	//it cannot be activated, it cannot receive focus, it cannot update itself or animate itself.

	disable: function(){
		if (this.getState('disabled')) return false;

		this.blur();

		this._childWidgets.each(function(child){
			if (!child._states.disabled){
				child._disabledByParent = true;
				child.disable();
			}
		});

		this.setState('disabled', true);;
		this.fireEvent('disable');

		return true;
	},

	/* focus, blur */

	//the widget is in the foreground; this is unique among siblings
	//the widget can be activated

	focus: function(){
		if (this.getState('disabled') || this.getState('focused')) return false;

		this.setState('focused', true);
		this.fireEvent('focus');
		this._blurredByParent = false;

		for (var w in focusedWidgets){
			if (focusedWidgets[w]) var widget = widgets[w];
			if (widget && widget != this && !widget.contains(this) && !this.contains(widget)) widget.blur();
		}
		focusedWidgets[this.uid] = true;

		this._childWidgets.each(function(child) {
			if (child._blurredByParent) child.focus();
		});

		return true;
	},

	//the widget is not in the foreground
	//it cannot be activated

	blur: function(){
		if (this.getState('disabled') || !this.getState('focused')) return false;

		this.deactivate();
		this.setState('focused', false);
		this.fireEvent('blur');
		focusedWidgets[this.uid] = false;

		this._childWidgets.each(function(child){
			if (child.getState('focused')){
				child._blurredByParent = true;
				child.blur();
			}
		});

		return true;
	},

	/* activate, deactivate */

	//the widget is being interacted with presently
	//the button is depressed, the window is being dragged, the select list is dropped open

	activate: function(){
		if (this.getState('disabled') || this.getState('active')) return false;
		this.focus();
		this.setState('active', true);

		this.fireEvent('active');

		return true;
	},

	deactivate: function(){
		if (this.getState('disabled') || !this.getState('active')) return false;
		this.setState('active', false);
		this.fireEvent('inactive');

		return true;
	},

	/* child & parent relationship, registration */

	register: function(parentWidget){
		widgets[this.uid] = this;
		if (parentWidget && (parentWidget instanceof Widget) && this.parentWidget !== parentWidget){
			this.parentWidget && this.parentWidget._childWidgets.erase(this);
			this.parentWidget = parentWidget;
			parentWidget._childWidgets.push(this);
			this.fireEvent('register', parentWidget.fireEvent('registered', this));
		}
		if (this._disabledByParent) this.enable();
		return this;
	},

	unregister: function(){
		if (widgets[this.uid]){
			delete widgets[this.uid];
			if (this.getState('enabled')) {
				this.disable();
				this._disabledByParent = true;
			}
			if (this.parentWidget){
				this.parentWidget._childWidgets.erase(this);
				this.fireEvent('unregister', this.parentWidget);
				this.parentWidget.fireEvent('unregistered', this);
				this.parentWidget = null;
			}
		}
		return this;
	},

	contains: function(widget) {
		if (this._childWidgets.contains(widget)) return true;
		for(var len = this._childWidgets.length - 1; len > 0; len = len - 1) {
			if (this._childWidgets[len].contains(widget)) return true;
		}
		return false;
	},

	isDestroyed: function(){
		if (!this.element || !this.element.parentNode) return;
	},

	grab: function(){
		for (var i = 0; i < arguments.length; i++){
			var widget = arguments[i];
			if ((widget instanceof Widget)) widget.register(this);
		}
		return this;
	},

	/* Sheet integration */

	getSheet: function(){
		var sheet = UI.Sheet.lookup(this.toString());
		if (this.options.styles) sheet = $merge(sheet, this.options.styles);
		return sheet;
	},

	diffSheet: function(){
		var oldSheet = this._oldSheet;
		if (!oldSheet) return this._oldSheet = this.getSheet();
		var newSheet = this.getSheet();
		var mixSheet = {};

		for (var p in newSheet){
			var newValue = newSheet[p],
			    oldValue = oldSheet[p];
			if (String(newValue).toString() != String(oldValue).toString()){
				mixSheet[p] = oldSheet[p] = newValue;
			}
		}

		for (var mp in oldSheet) {
			if (newSheet[mp] == undefined) {
				delete this._oldSheet[mp];
				mixSheet[mp] = null;
			}
		}
		return mixSheet;
	}

});

Widget.prototype.toString = function(){
	var string = '';
	if (this.name) string += this.name;
	if (this.id) string += "#" + this.id;
	if (this._classNames.length) string += '.' + this._classNames.join('.');

	for (var s in this._states){
		if (this._states[s]) string += ':' + s;
	}

	var parentWidget = this.parentWidget;
	if (parentWidget) string = parentWidget.toString() + ' ' + string;

	return string;
};

})();
<commit_msg> - typo fix<commit_after>/*
---
name: UI.Widget
description: Base Widget Class
requires: [UI, UI.Sheet, Core/Class, Core/Events, Core/Options]
provides: UI.Widget
...
*/

(function(){

var widgets = UI.widgets = {}; UID = 0;
var focusedWidgets = {};

var Widget = UI.Widget = new Class({

	Implements: [Events, Options],

	name: 'widget',

	options: {
		/*
			onFocus: $empty,
			onBlur: $empty,
			onEnable: $empty,
			onDisable: $empty,
			parentWidgte: null,
			styles: {},
		*/
		id: '',
		className: ''
	},

	initialize: function(options){
		this.uid = ART.uniqueID();

		this.parentWidget = null;
		this._childWidgets = [];

		var parent;
		if (options) {
			if (options.parentWidget) {
				parent = options.parentWidget;
				delete options.parentWidget;
			}
		}

		this.setOptions(options);
		if (this.options.id) this.setID(this.options.id);

		this._classNames = [];
		if (this.options.className) this.options.className.split(' ').each(function(className){
			this.addClass(className);
		}, this);

		if (parent) this.register(parent);
	},

	/* ID */

	setID: function(id){
		this.id = id;
		return this;
	},

	/* classNames */

	addClass: function(className){
		this._classNames.push(className);
		return this;
	},

	removeClass: function(className){
		this._classNames.erase(className);
		return this;
	},

	hasClass: function(className){
		return this._classNames.contains(className);
	},

	setStyles: function(styles){
		this.setOptions({
			styles: styles
		});
	},

	/*
		states
	*/

	_states: {
		disabled: false,
		focused: false,
		active: false
	},

	setState: function(name, state) {
		this._states[name] = state;
		return this;
	},

	getState: function(name) {
		return this._states[name];
	},

	/* enable, disable */

	//enabled means you can interact with a widget
	//it can be activated, it can receive focus, it can update itself or animate itself.

	enable: function(){
		if ((this.parentWidget && this.parentWidget.getState('disabled')) || !this.getState('disabled')) return false;
		this._disabledByParent = false;
		this.setState('disabled', false);
		this.fireEvent('enable');

		this._childWidgets.each(function(child){
			if (child._disabledByParent) child.enable();
		});

		return true;
	},

	//disabled means you cannot interact with a widget
	//it cannot be activated, it cannot receive focus, it cannot update itself or animate itself.

	disable: function(){
		if (this.getState('disabled')) return false;

		this.blur();

		this._childWidgets.each(function(child){
			if (!child._states.disabled){
				child._disabledByParent = true;
				child.disable();
			}
		});

		this.setState('disabled', true);;
		this.fireEvent('disable');

		return true;
	},

	/* focus, blur */

	//the widget is in the foreground; this is unique among siblings
	//the widget can be activated

	focus: function(){
		if (this.getState('disabled') || this.getState('focused')) return false;

		this.setState('focused', true);
		this.fireEvent('focus');
		this._blurredByParent = false;

		for (var w in focusedWidgets){
			if (focusedWidgets[w]) var widget = widgets[w];
			if (widget && widget != this && !widget.contains(this) && !this.contains(widget)) widget.blur();
		}
		focusedWidgets[this.uid] = true;

		this._childWidgets.each(function(child) {
			if (child._blurredByParent) child.focus();
		});

		return true;
	},

	//the widget is not in the foreground
	//it cannot be activated

	blur: function(){
		if (this.getState('disabled') || !this.getState('focused')) return false;

		this.deactivate();
		this.setState('focused', false);
		this.fireEvent('blur');
		focusedWidgets[this.uid] = false;

		this._childWidgets.each(function(child){
			if (child.getState('focused')){
				child._blurredByParent = true;
				child.blur();
			}
		});

		return true;
	},

	/* activate, deactivate */

	//the widget is being interacted with presently
	//the button is depressed, the window is being dragged, the select list is dropped open

	activate: function(){
		if (this.getState('disabled') || this.getState('active')) return false;
		this.focus();
		this.setState('active', true);

		this.fireEvent('active');

		return true;
	},

	deactivate: function(){
		if (this.getState('disabled') || !this.getState('active')) return false;
		this.setState('active', false);
		this.fireEvent('inactive');

		return true;
	},

	/* child & parent relationship, registration */

	register: function(parentWidget){
		widgets[this.uid] = this;
		if (parentWidget && (parentWidget instanceof Widget) && this.parentWidget !== parentWidget){
			this.parentWidget && this.parentWidget._childWidgets.erase(this);
			this.parentWidget = parentWidget;
			parentWidget._childWidgets.push(this);
			this.fireEvent('register', parentWidget.fireEvent('registered', this));
		}
		if (this._disabledByParent) this.enable();
		return this;
	},

	unregister: function(){
		if (widgets[this.uid]){
			delete widgets[this.uid];
			if (this.getState('enabled')) {
				this.disable();
				this._disabledByParent = true;
			}
			if (this.parentWidget){
				this.parentWidget._childWidgets.erase(this);
				this.fireEvent('unregister', this.parentWidget);
				this.parentWidget.fireEvent('unregistered', this);
				this.parentWidget = null;
			}
		}
		return this;
	},

	contains: function(widget) {
		if (this._childWidgets.contains(widget)) return true;
		for(var len = this._childWidgets.length - 1; len > 0; len = len - 1) {
			if (this._childWidgets[len].contains(widget)) return true;
		}
		return false;
	},

	isDestroyed: function(){
		if (!this.element || !this.element.parentNode) return;
	},

	grab: function(){
		for (var i = 0; i < arguments.length; i++){
			var widget = arguments[i];
			if ((widget instanceof Widget)) widget.register(this);
		}
		return this;
	},

	/* Sheet integration */

	getSheet: function(){
		var sheet = UI.Sheet.lookup(this.toString());
		if (this.options.styles) sheet = $merge(sheet, this.options.styles);
		return sheet;
	},

	diffSheet: function(){
		var oldSheet = this._oldSheet;
		if (!oldSheet) return this._oldSheet = this.getSheet();
		var newSheet = this.getSheet();
		var mixSheet = {};

		for (var p in newSheet){
			var newValue = newSheet[p],
			    oldValue = oldSheet[p];
			if (String(newValue).toString() != String(oldValue).toString()){
				mixSheet[p] = oldSheet[p] = newValue;
			}
		}

		for (var mp in oldSheet) {
			if (newSheet[mp] == undefined) {
				delete this._oldSheet[mp];
				mixSheet[mp] = null;
			}
		}
		return mixSheet;
	}

});

Widget.prototype.toString = function(){
	var string = '';
	if (this.name) string += this.name;
	if (this.id) string += "#" + this.id;
	if (this._classNames.length) string += '.' + this._classNames.join('.');

	for (var s in this._states){
		if (this._states[s]) string += ':' + s;
	}

	var parentWidget = this.parentWidget;
	if (parentWidget) string = parentWidget.toString() + ' ' + string;

	return string;
};

})();
<|endoftext|>


<commit_before>/**
 * Patterns autosuggest - suggestion/completion support
 *
 * Copyright 2012-2013 Florian Friesdorf
 * Copyright 2012 JC Brand
 * Copyright 2013 Marko Durkovic
 */
define([
    "jquery",
    "pat-logger",
    "pat-parser",
    "pat-registry",
    "select2"
], function($, logger, Parser, registry) {
    "use strict";
    var log = logger.getLogger("calendar");
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("words-json");
    parser.add_argument("ajax-url", "");
    parser.add_argument("ajax-data-type", "");
    parser.add_argument("ajax-search-index", "");
    // "selection-classes" allows you to add custom CSS classes to currently
    // selected elements.
    // The value passed in must be an object with each id being the text inside
    // a selection and value being a list of classes to be added to the
    // selection.
    // e.g. {'BMW': ['selected', 'car'], 'BMX': ['selected', 'bicycle']}
    parser.add_argument("selection-classes", "");
    parser.add_argument("pre-fill", function($el) { return $el.val(); });
    parser.add_argument("data", "");
    parser.add_argument("maximum-selection-size", 0);
    parser.add_argument("placeholder", function($el) {
        return $el.attr("placeholder") || "Enter text";
    });

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1) {
                return $el.each(function() { _.init($(this), opts); });
            }
            var data, ids = [], d, words;
            var cfg = parser.parse($el, opts);

            if (cfg.wordsJson && cfg.wordsJson.length) {
                try {
                    words = $.parseJSON(cfg.wordsJson);
                } catch(SyntaxError) {
                    log.error("SyntaxError: non-JSON data given to pat-autosuggest");
                }
            } else {
                words = cfg.words ? cfg.words.split(/\s*,\s*/) : [];
            }
            var config = {
                placeholder: $el.attr("readonly") ? "" : cfg.placeholder,
                tags: words,
                tokenSeparators: [","],
                openOnEnter: false,
                maximumSelectionSize: cfg.maximumSelectionSize
            };

            if (cfg.selectionClasses) {
                // We need to customize the formatting/markup of the selection
                config.formatSelection = function(obj, container) {
                    var selectionClasses = null;
                    try {
                        selectionClasses = $.parseJSON(cfg.selectionClasses)[obj.text];
                    } catch(SyntaxError) {
                        log.error("SyntaxError: non-JSON data given to pat-autosuggest (selection-classes)");
                    }
                    if (selectionClasses) {
                        // According to Cornelis the classes need to be applied on
                        // the <li>, which is the container's parent
                        container.parent().addClass(selectionClasses.join(" "));
                    }
                    return obj.text;
                };
            }

            if (cfg.preFill.length) {
                var prefill = cfg.preFill.split(",");
                $el.val(prefill);
                config.initSelection = function (element, callback) {
                    var i, data = [],
                        values = element.val().split(",");
                    for (i=0; i<values.length; i++) {
                        data.push({id: values[i], text: values[i]});
                    }
                    callback(data);
                };
            }

            if (cfg.data.length) {
                /* We support two types of JSON data for preFill data:
                 *   {"john-snow": "John Snow", "tywin-lannister": "Tywin Lannister"}
                 * or
                 *   {
                 *    {"id": "john-snow", "text": "John Snow"},
                 *    {"id": "tywin-lannister", "text":"Tywin Lannister"}
                 *   }
                 */
                try {
                   data = $.parseJSON(cfg.data);
                    for (d in data) {
                        if (typeof d === "object") {
                            ids.push(d.id);
                        } else {
                            ids.push(data[d]);
                        }
                    }
                    $el.val(ids);
                    config.initSelection = function (element, callback) {
                        var d, _data = [];
                        for (d in data) {
                            if (typeof d === "object") {
                                _data.push(d);
                            } else {
                                _data.push({id: data[d], text: data[d]});
                            }
                        }
                        callback(_data);
                    };
                } catch(SyntaxError) {
                    log.error("SyntaxError: non-JSON data given to pat-autosuggest");
                }
            }

            if ((cfg.ajax) && (cfg.ajax.url)) {
                config = $.extend(true, {
                    minimumInputLength: 2,
                    ajax: {
                        url: cfg.ajax.url,
                        dataType: cfg.ajax["data-type"],
                        type: "POST",
                        quietMillis: 400,
                        data: function (term, page) {
                            return {
                                index: cfg.ajax["search-index"],
                                q: term, // search term
                                page_limit: 10,
                                page: page
                            };
                        },
                        results: function (data, page) {
                            // parse the results into the format expected by Select2.
                            // data must be a list of objects with keys "id" and "text"
                            return {results: data, page: page};
                        }
                    }
                }, config);
            }

            $el.select2(config);

            $el.on("pat-update", function (e, data) {
                if (data.pattern === "depends") {
                    if (data.enabled === true) {
                        $el.select2("enable", true);
                    } else if (data.enabled === false) {
                        $el.select2("disable", true);
                    }

                }
            });

            // suppress propagation for second input field
            $el.prev().on("input-change input-defocus input-change-delayed",
                function(e) { e.stopPropagation(); }
            );

            // Clear the values when a reset button is pressed
            $el.closest("form").find("button[type=reset]").on("click", function () {
                $el.select2("val", "");
            });
            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");
            $el.select2("destroy");
        },
        transform: function($content) {
            $content.findInclusive("input[type=text].pat-autosuggest").each(function() {
                var $src = $(this),
                    $dest = $("<input type='hidden'/>").insertAfter($src);

                // measure in IE8, otherwise hidden will have width 0
                if (document.all && !document.addEventListener) {
                    $dest.css("width", $src.outerWidth(false)+"px");
                }
                $src.detach();
                $.each($src.prop("attributes"), function() {
                    if (this.name !== "type") {
                        $dest.attr(this.name, this.value);
                    }
                });
                $src.remove();
            });
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<commit_msg>pat-autosuggest: Make sure the words-json datastructure is turned into an Array<commit_after>/**
 * Patterns autosuggest - suggestion/completion support
 *
 * Copyright 2012-2013 Florian Friesdorf
 * Copyright 2012 JC Brand
 * Copyright 2013 Marko Durkovic
 */
define([
    "jquery",
    "pat-logger",
    "pat-parser",
    "pat-registry",
    "select2"
], function($, logger, Parser, registry) {
    "use strict";
    var log = logger.getLogger("calendar");
    var parser = new Parser("autosuggest");
    parser.add_argument("words", "");
    parser.add_argument("words-json");
    parser.add_argument("ajax-url", "");
    parser.add_argument("ajax-data-type", "");
    parser.add_argument("ajax-search-index", "");
    // "selection-classes" allows you to add custom CSS classes to currently
    // selected elements.
    // The value passed in must be an object with each id being the text inside
    // a selection and value being a list of classes to be added to the
    // selection.
    // e.g. {'BMW': ['selected', 'car'], 'BMX': ['selected', 'bicycle']}
    parser.add_argument("selection-classes", "");
    parser.add_argument("pre-fill", function($el) { return $el.val(); });
    parser.add_argument("data", "");
    parser.add_argument("maximum-selection-size", 0);
    parser.add_argument("placeholder", function($el) {
        return $el.attr("placeholder") || "Enter text";
    });

    var _ = {
        name: "autosuggest",
        trigger: "input.pat-autosuggest",
        init: function($el, opts) {
            if ($el.length > 1) {
                return $el.each(function() { _.init($(this), opts); });
            }
            var data, ids = [], d, words;
            var cfg = parser.parse($el, opts);
            if (cfg.wordsJson && cfg.wordsJson.length) {
                try {
                    words = $.parseJSON(cfg.wordsJson);
                } catch(SyntaxError) {
                    words = [];
                    log.error("SyntaxError: non-JSON data given to pat-autosuggest");
                }
                if (! Array.isArray(words)) {
                    words = $.map(words, function (v, k) {
                        var x = {}; x[k] = v; return x;
                    });
                }
            } else {
                words = cfg.words ? cfg.words.split(/\s*,\s*/) : [];
            }

            var config = {
                placeholder: $el.attr("readonly") ? "" : cfg.placeholder,
                tags: words,
                tokenSeparators: [","],
                openOnEnter: false,
                maximumSelectionSize: cfg.maximumSelectionSize
            };

            if (cfg.selectionClasses) {
                // We need to customize the formatting/markup of the selection
                config.formatSelection = function(obj, container) {
                    var selectionClasses = null;
                    try {
                        selectionClasses = $.parseJSON(cfg.selectionClasses)[obj.text];
                    } catch(SyntaxError) {
                        log.error("SyntaxError: non-JSON data given to pat-autosuggest (selection-classes)");
                    }
                    if (selectionClasses) {
                        // According to Cornelis the classes need to be applied on
                        // the <li>, which is the container's parent
                        container.parent().addClass(selectionClasses.join(" "));
                    }
                    return obj.text;
                };
            }

            if (cfg.preFill.length) {
                var prefill = cfg.preFill.split(",");
                $el.val(prefill);
                config.initSelection = function (element, callback) {
                    var i, data = [],
                        values = element.val().split(",");
                    for (i=0; i<values.length; i++) {
                        data.push({id: values[i], text: values[i]});
                    }
                    callback(data);
                };
            }

            if (cfg.data.length) {
                /* We support two types of JSON data for preFill data:
                 *   {"john-snow": "John Snow", "tywin-lannister": "Tywin Lannister"}
                 * or
                 *   {
                 *    {"id": "john-snow", "text": "John Snow"},
                 *    {"id": "tywin-lannister", "text":"Tywin Lannister"}
                 *   }
                 */
                try {
                   data = $.parseJSON(cfg.data);
                    for (d in data) {
                        if (typeof d === "object") {
                            ids.push(d.id);
                        } else {
                            ids.push(data[d]);
                        }
                    }
                    $el.val(ids);
                    config.initSelection = function (element, callback) {
                        var d, _data = [];
                        for (d in data) {
                            if (typeof d === "object") {
                                _data.push(d);
                            } else {
                                _data.push({id: data[d], text: data[d]});
                            }
                        }
                        callback(_data);
                    };
                } catch(SyntaxError) {
                    log.error("SyntaxError: non-JSON data given to pat-autosuggest");
                }
            }

            if ((cfg.ajax) && (cfg.ajax.url)) {
                config = $.extend(true, {
                    minimumInputLength: 2,
                    ajax: {
                        url: cfg.ajax.url,
                        dataType: cfg.ajax["data-type"],
                        type: "POST",
                        quietMillis: 400,
                        data: function (term, page) {
                            return {
                                index: cfg.ajax["search-index"],
                                q: term, // search term
                                page_limit: 10,
                                page: page
                            };
                        },
                        results: function (data, page) {
                            // parse the results into the format expected by Select2.
                            // data must be a list of objects with keys "id" and "text"
                            return {results: data, page: page};
                        }
                    }
                }, config);
            }

            $el.select2(config);

            $el.on("pat-update", function (e, data) {
                if (data.pattern === "depends") {
                    if (data.enabled === true) {
                        $el.select2("enable", true);
                    } else if (data.enabled === false) {
                        $el.select2("disable", true);
                    }

                }
            });

            // suppress propagation for second input field
            $el.prev().on("input-change input-defocus input-change-delayed",
                function(e) { e.stopPropagation(); }
            );

            // Clear the values when a reset button is pressed
            $el.closest("form").find("button[type=reset]").on("click", function () {
                $el.select2("val", "");
            });
            return $el;
        },
        destroy: function($el) {
            $el.off(".pat-autosuggest");
            $el.select2("destroy");
        },
        transform: function($content) {
            $content.findInclusive("input[type=text].pat-autosuggest").each(function() {
                var $src = $(this),
                    $dest = $("<input type='hidden'/>").insertAfter($src);

                // measure in IE8, otherwise hidden will have width 0
                if (document.all && !document.addEventListener) {
                    $dest.css("width", $src.outerWidth(false)+"px");
                }
                $src.detach();
                $.each($src.prop("attributes"), function() {
                    if (this.name !== "type") {
                        $dest.attr(this.name, this.value);
                    }
                });
                $src.remove();
            });
        }
    };
    registry.register(_);
    return _;
});

// jshint indent: 4, browser: true, jquery: true, quotmark: double
// vim: sw=4 expandtab
<|endoftext|>


<commit_before>/*
 * changes to previous injection implementations
 * - no support for data-injection anymore, switch to new data-inject
 * - no support for data-href-next anymore, switch to data-inject: next-href
 * - XXX: add support for forms, see remnants in inject1 and ajaxify
 */
define([
    "jquery",
    "../core/parser",
    "../core/logger",
    "../lib/ajax",
    "../registry",
    "../utils",
    "../lib/htmlparser",
    "jquery_ext"  // for :scrollable for autoLoading-visible
], function($, Parser, logger, ajax, registry, utils, htmlparser) {
    var log = logger.getLogger("pat.inject"),
        parser = new Parser("inject");

    //parser.add_argument("selector", "body");
    parser.add_argument("selector");
    //XXX: (yet) unsupported: parser.add_argument("target", "$selector");
    parser.add_argument("target");
    parser.add_argument("data-type", "html");
    parser.add_argument("next-href");
    //XXX: (yet) unsupported: parser.add_argument("source", "$selector");
    parser.add_argument("source");
    parser.add_argument("trigger", "default", ["default", "autoload", "autoload-visible"]);
    // XXX: this should not be here but the parser would bail on
    // unknown parameters and expand/collapsible need to pass the url
    // to us
    parser.add_argument("url");
    parser.add_argument("class");

    var _ = {
        name: "inject",
        trigger: "a.pat-inject, form.pat-inject",
        init: function($el, opts) {
            if ($el.length > 1)
                return $el.each(function() { _.init($(this), opts); });

            var cfgs = _.extractConfig($el, opts);
            $el.data("patterns.inject", cfgs);

            // In case next-href is specified the anchor's href will
            // be set to it after the injection is triggered. In case
            // the next href already exists, we do not activate the
            // injection but instead just change the anchors href.
            //
            // XXX: This is used in only one project for linked
            // fullcalendars, it's sanity is wonky and we should
            // probably solve it differently. -- Maybe it's cool
            // after all.
            var $nexthref = $(cfgs[0].nextHref);
            if ($el.is("a") && $nexthref.length > 0) {
                log.debug("Skipping as next href already exists", $nexthref);
                // XXX: reconsider how the injection enters exhausted state
                return $el.attr({href: (window.location.href.split("#")[0] || "") +
                                 cfgs[0].nextHref});
            }

            switch (cfgs[0].trigger) {
            case "default":
                // setup event handlers
                if ($el.is("a"))
                    $el.on("click.pat-inject", _.onClick);
                else if ($el.is("form"))
                    $el.on("submit.pat-inject", _.onSubmit);
                break;
            case "autoload":
                _.onClick.apply($el[0], []);
                break;
            case "autoload-visible":
                _._initAutoloadVisible($el);
                break;
            }

            log.debug("initialised:", $el);

            return $el;
        },

        destroy: function($el) {
            $el.off(".pat-inject");
            $el.data("patterns.inject", null);
            return $el;
        },

        onClick: function(ev) {
            var cfgs = $(this).data("patterns.inject"),
                $el = $(this);
            if (ev)
                ev.preventDefault();
            $el.trigger("patterns-inject-triggered");
            _.execute(cfgs, $el);
        },

        onSubmit: function(ev) {
            var cfgs = $(this).data("patterns.inject"),
                $el = $(this);
            if (ev)
                ev.preventDefault();
            $el.trigger("patterns-inject-triggered");
            _.execute(cfgs, $el);
        },

        extractConfig: function($el, opts) {
            opts = $.extend({}, opts);

            var urlparts, cfgs, defaultSelector;
            // opts has priority, fallback to href/action
            opts.url = opts.url || $el.attr("href") || $el.attr("action") || "";

            // separate selector from url
            urlparts = opts.url.split("#");
            opts.url = urlparts[0];

            // if no selector, check for selector as part of original url
            defaultSelector = urlparts[1] && "#" + urlparts[1] || "body";

            if (urlparts.length > 2) {
                log.warn("Ignoring additional source ids:", urlparts.slice(2));
            }

            cfgs = parser.parse($el, opts, true);
            cfgs.forEach(function(cfg) {
                cfg.selector = cfg.selector || defaultSelector;
            });
            return cfgs;
        },
        // verify and post-process config
        // XXX: this should return a command instead of messing around on the config
        verifyConfig: function(cfgs, $el) {
            var url = cfgs[0].url;

            // verification for each cfg in the array needs to succeed
            return cfgs.every(function(cfg) {
                // in case of multi-injection, all injections need to use
                // the same url
                if (cfg.url !== url) {
                    log.error("Unsupported different urls for multi-inject");
                    return false;
                }

                // defaults
                cfg.source = cfg.source || cfg.selector;
                cfg.target = cfg.target || cfg.selector;

                if (!_._extractModifiers(cfg))
                    return false;

                // make sure target exist
                cfg.$target = cfg.$target || (cfg.target==="self" ? $el : $(cfg.target));
                if (cfg.$target.length === 0) {
                    if (!cfg.target) {
                        log.error("Need target selector", cfg);
                        return false;
                    }
                    cfg.$target = _._createTarget(cfg.target);
                    cfg.$injected = cfg.$target;
                }
                return true;
            });
        },

        _extractModifiers: function(cfg) {
            var source_re = /^(.*?)(::element)?$/,
                target_re = /^(.*?)(::element)?(::after|::before)?$/,
                source_match = source_re.exec(cfg.source),
                target_match = target_re.exec(cfg.target),
                targetMod, targetPosition;

            // source content or element?
            cfg.source = source_match[1];
            // XXX: turn into source processor
            cfg.sourceMod = source_match[2] ? "element" : "content";

            // will be added while the ajax request is in progress
            cfg.targetLoadClasses = "injecting";

            // target content or element?
            targetMod = target_match[2] ? "element" : "content";
            cfg.target = target_match[1];
            cfg.targetLoadClasses += " injecting-" + targetMod;

            // position relative to target
            targetPosition = (target_match[3] || "::").slice(2);
            if (targetPosition)
                cfg.targetLoadClasses += " injecting-" + targetPosition;

            cfg.action = targetMod + targetPosition;

            // Once we start detecting illegal combinations, we'll
            // return false in case of error
            return true;
        },

        // create a target that matches the selector
        //
        // XXX: so far we only support #target and create a div with
        // that id appended to the body.
        _createTarget: function(selector) {
            var $target;
            if (selector.slice(0,1) !== "#") {
                log.error("only id supported for non-existing target");
                return null;
            }
            $target = $("
").attr({id: selector.slice(1)});
            $("body").append($target);
            return $target;
        },

        execute: function(cfgs, $el) {
            // get a kinda deep copy, we scribble on it
            cfgs = cfgs.map(function(cfg) {
                return $.extend({}, cfg);
            });

            // XXX: this need to get functional, returning a command
            // for internal use, instead of passing on cfgs
            if (!_.verifyConfig(cfgs, $el))
                return;

            // possibility for spinners on targets
            cfgs.forEach(function(cfg) {
                cfg.$target.addClass(cfg.targetLoadClasses);
            });

            var onSuccess = function(ev) {
                var data = ev && ev.jqxhr && ev.jqxhr.responseText;
                if (!data) {
                    log.warn("No response content, aborting", ev);
                    return;
                }

                var sources$ = _.callTypeHandler(cfgs[0].dataType, "sources", $el, [cfgs, data, ev]);

                cfgs.forEach(function(cfg, idx) {
                    var $source = sources$[idx];

                    if (cfg.sourceMod === "content")
                        $source = $source.contents();

                    // perform injection
                    cfg.$target.each(function() {
                        var $target = $(this),
                            $src = $source.clone(),
                            $injected = cfg.$injected || $src;
                        if (_._inject($src, $target, cfg.action, cfg["class"])) {
                            $injected.filter(function() {
                                // setting data on textnode fails in IE8
                                return this.nodeType !== 3; //Node.TEXT_NODE
                            }).data("pat-injected", {origin: cfg.url});
                            $injected.addClass(cfg["class"])
                                .trigger("patterns-injected", cfg);
                        }
                    });
                });

                if (cfgs[0].nextHref) {
                    $el.attr({href: (window.location.href.split("#")[0] || "") +
                              cfgs[0].nextHref});
                    _.destroy($el);

                    // XXX: this used to be the case, but I don't see
                    // why that would be a good idea.
                    //
                    // jump to new href target
                    //if (!$el.hasClass("autoLoading-visible"))
                    //    window.location.href = $el.attr('href');
                }
                $el.off("pat-ajax-success.pat-inject");
                $el.off("pat-ajax-error.pat-inject");
            };

            var onError = function() {
                cfgs.forEach(function(cfg) {
                    cfg.$injected.remove();
                });
                $el.off("pat-ajax-success.pat-inject");
                $el.off("pat-ajax-error.pat-inject");
            };

            $el.on("pat-ajax-success.pat-inject", onSuccess);
            $el.on("pat-ajax-error.pat-inject", onError);

            ajax($el, {
                url: cfgs[0].url
            });
        },

        _inject: function($source, $target, action /* , classes */) {
            // action to jquery method mapping, except for "content"
            // and "element"
            var method = {
                contentbefore: "prepend",
                contentafter:  "append",
                elementbefore: "before",
                elementafter:  "after"
            }[action];

            if ($source.length === 0) {
                log.warn("Aborting injection, source not found:", $source);
                return false;
            }
            if ($target.length === 0) {
                log.warn("Aborting injection, target not found:", $target);
                return false;
            }

            if (action === "content")
                $target.empty().append($source);
            else if (action === "element")
                $target.replaceWith($source);
            else
                $target[method]($source);

            return true;
        },

        _sourcesFromHtml: function(html, url, sources) {
            var $html = _._parseRawHtml(html, url);
            return sources.map(function(source) {
                if (source === "body")
                    source = "#__original_body";

                var $source = $html.find(source);

                if ($source.length===0)
                    log.warn("No source elements for selector:", source, $html);

                $source.find("a[href^=\"#\"]").each(function() {
                    var href = this.getAttribute("href");
                    // Skip in-document links pointing to an id that is
                    // inside this fragment.
                    if (href.length===1 || $source.find(href).length)
                        return;
                    this.href=url+href;
                });

                return $source;
            });
        },

        _link_attributes: {
            A: "href",
            FORM: "action",
            IMG: "src"
        },

        _rebaseHTML: function(base, html) {
            var output = [],
                i, link_attribute, value;

            htmlparser.HTMLParser(html, {
                start: function(tag, attrs, unary) {
                    output.push("<"+tag);
                    link_attribute=_._link_attributes[tag.toUpperCase()];
                    for (i=0; i<attrs.length; i++) {
                        if (attrs[i].name.toLowerCase()===link_attribute) {
                            value=attrs[i].value;
                            // Do not rewrite Zope views or in-document links.
                            // In-document links will be processed later after
                            // extracting the right fragment.
                            if (value.slice(0, 2)!=="@@" && value[0]!=="#") {
                                value=utils.rebaseURL(base, value);
                                value=value.replace(/(^|[^\\])"/g, '$1\\\"');
                            }
                        }  else
                            value=attrs[i].escaped;
                        output.push(" "+attrs[i].name+"=\""+value+"\"");
                    }
                    output.push(unary ? "/>" : ">");
                },

                end: function(tag) {
                    output.push("</"+tag+">");
                },

                chars: function(text) {
                    output.push(text);
                },

                comment: function(text) {
                    output.push("");
                }
            });
            return output.join("");
        },

        _parseRawHtml: function(html, url) {
            url = url || "";

            // remove script tags and head and replace body by a div
            var clean_html = html
                    .replace(/


<commit_before><commit_msg>Change mustache to_html for render (#338)<commit_after><|endoftext|>


<commit_before>/* eslint-disable no-param-reassign */

var objectAssign = require('./object-assign');

function pick(object, keys) {
  return keys.reduce(function (prev, key) {
    if (object[key]) {
      prev[key] = object[key];
    }
    return prev;
  }, {});
}

function objectValues(obj) {
  var values = [];
  for (key in obj) {
    values.push(obj[key]);
  }
  return values;
}

function extend() {
  var params = objectValues(arguments);
  params.unshift({});
  return objectAssign.get().apply(undefined, params);
}

function merge(object, keys) {
  return {
    base: keys ? pick(object, keys) : object,
    with: function (object2, keys2) {
      object2 = keys2 ? pick(object2, keys2) : object2;
      return extend(this.base, object2);
    }
  };
}

function blacklist(object, blacklistedKeys) {
  return Object.keys(object).reduce(function (p, key) {
    if (blacklistedKeys.indexOf(key) === -1) {
      p[key] = object[key];
    }
    return p;
  }, {});
}

function camelToSnake(str) {
  var newKey = '';
  var index = 0;
  var code;
  var wasPrevNumber = true;
  var wasPrevUppercase = true;

  while (index < str.length) {
    code = str.charCodeAt(index);
    if ((!wasPrevUppercase && code >= 65 && code <= 90) || (!wasPrevNumber && code >= 48 && code <= 57)) {
      newKey += '_';
      newKey += str[index].toLowerCase();
    } else {
      newKey += str[index].toLowerCase();
    }
    wasPrevNumber = (code >= 48 && code <= 57);
    wasPrevUppercase = (code >= 65 && code <= 90);
    index++;
  }

  return newKey;
}

function snakeToCamel(str) {
  var parts = str.split('_');
  return parts.reduce(function (p, c) {
    return p + c.charAt(0).toUpperCase() + c.slice(1);
  }, parts.shift());
}

function toSnakeCase(object, exceptions) {
  exceptions = exceptions || [];

  return Object.keys(object).reduce(function (p, key) {
    var newKey = exceptions.indexOf(key) === -1 ? camelToSnake(key) : key;
    p[newKey] = typeof(object[key]) === 'object' ? toSnakeCase(object[key]) : object[key];
    return p;
  }, {});
}

function toCamelCase(object, exceptions) {
  exceptions = exceptions || [];

  return Object.keys(object).reduce(function (p, key) {
    var newKey = exceptions.indexOf(key) === -1 ? snakeToCamel(key) : key;
    p[newKey] = typeof(object[key]) === 'object' ? toCamelCase(object[key]) : object[key];
    return p;
  }, {});
}

module.exports = {
  toSnakeCase: toSnakeCase,
  toCamelCase: toCamelCase,
  blacklist: blacklist,
  merge: merge,
  pick: pick,
  extend: extend
};
<commit_msg>fix undefined valud in for<commit_after>/* eslint-disable no-param-reassign */

var objectAssign = require('./object-assign');

function pick(object, keys) {
  return keys.reduce(function (prev, key) {
    if (object[key]) {
      prev[key] = object[key];
    }
    return prev;
  }, {});
}

function objectValues(obj) {
  var values = [];
  for (var key in obj) {
    values.push(obj[key]);
  }
  return values;
}

function extend() {
  var params = objectValues(arguments);
  params.unshift({});
  return objectAssign.get().apply(undefined, params);
}

function merge(object, keys) {
  return {
    base: keys ? pick(object, keys) : object,
    with: function (object2, keys2) {
      object2 = keys2 ? pick(object2, keys2) : object2;
      return extend(this.base, object2);
    }
  };
}

function blacklist(object, blacklistedKeys) {
  return Object.keys(object).reduce(function (p, key) {
    if (blacklistedKeys.indexOf(key) === -1) {
      p[key] = object[key];
    }
    return p;
  }, {});
}

function camelToSnake(str) {
  var newKey = '';
  var index = 0;
  var code;
  var wasPrevNumber = true;
  var wasPrevUppercase = true;

  while (index < str.length) {
    code = str.charCodeAt(index);
    if ((!wasPrevUppercase && code >= 65 && code <= 90) || (!wasPrevNumber && code >= 48 && code <= 57)) {
      newKey += '_';
      newKey += str[index].toLowerCase();
    } else {
      newKey += str[index].toLowerCase();
    }
    wasPrevNumber = (code >= 48 && code <= 57);
    wasPrevUppercase = (code >= 65 && code <= 90);
    index++;
  }

  return newKey;
}

function snakeToCamel(str) {
  var parts = str.split('_');
  return parts.reduce(function (p, c) {
    return p + c.charAt(0).toUpperCase() + c.slice(1);
  }, parts.shift());
}

function toSnakeCase(object, exceptions) {
  exceptions = exceptions || [];

  return Object.keys(object).reduce(function (p, key) {
    var newKey = exceptions.indexOf(key) === -1 ? camelToSnake(key) : key;
    p[newKey] = typeof(object[key]) === 'object' ? toSnakeCase(object[key]) : object[key];
    return p;
  }, {});
}

function toCamelCase(object, exceptions) {
  exceptions = exceptions || [];

  return Object.keys(object).reduce(function (p, key) {
    var newKey = exceptions.indexOf(key) === -1 ? snakeToCamel(key) : key;
    p[newKey] = typeof(object[key]) === 'object' ? toCamelCase(object[key]) : object[key];
    return p;
  }, {});
}

module.exports = {
  toSnakeCase: toSnakeCase,
  toCamelCase: toCamelCase,
  blacklist: blacklist,
  merge: merge,
  pick: pick,
  extend: extend
};
<|endoftext|>