<commit_before>'use strict';

const config = {
  'java.wait': false,
  'patch.code': true,
  'search.in': 'perm:r--',
  'search.quiet': false,
  'stalker.event': 'compile',
  'stalker.timeout': 5 * 60,
  'stalker.in': 'raw',
  'hook.backtrace': true,
  'hook.verbose': true,
  'hook.logs': true,
  'hook.output': 'simple',
  'hook.usecmd': '',
  'file.log': '',
  'symbols.module': '',
  'symbols.unredact': Process.platform === 'darwin'
};

const configHelp = {
  'java.wait': configHelpJavaWait,
  'search.in': configHelpSearchIn,
  'stalker.event': configHelpStalkerEvent,
  'stalker.timeout': configHelpStalkerTimeout,
  'stalker.in': configHelpStalkerIn,
  'hook.backtrace': configHelpHookBacktrace,
  'hook.verbose': configHelpHookVerbose,
  'hook.usecmd': configHelpHookUseCmd,
  'hook.logs': configHelpHookLogs,
  'hook.output': configHelpHookOutput,
  'file.log': configHelpFileLog,
  'symbols.module': configHelpSymbolsModule,
  'symbols.unredact': configHelpSymbolsUnredact
};

const configValidator = {
  'java.wait': configValidateBoolean,
  'search.in': configValidateSearchIn,
  'stalker.event': configValidateStalkerEvent,
  'stalker.timeout': configValidateStalkerTimeout,
  'stalker.in': configValidateStalkerIn,
  'hook.backtrace': configValidateBoolean,
  'hook.verbose': configValidateBoolean,
  'hook.logs': configValidateBoolean,
  'hook.output': configValidateString,
  'file.log': configValidateString,
  'symbols.module': configValidateString,
  'symbols.unredact': configValidateBoolean
};

function configHelpJavaWait () {
  return 'Wait for Java classloader to be ready (boolean)';
}

function configHelpSearchIn () {
  return `Specify which memory ranges to search in, possible values:

    perm:---        filter by permissions (default: 'perm:r--')
    current         search the range containing current offset
    heap            search inside the heap allocated regions
    path:pattern    search ranges mapping paths containing 'pattern'
  `;
}

function configValidateSearchIn (val) {
  if (val === 'heap') {
    return true;
  }
  const valSplit = val.split(':');
  const [scope, param] = valSplit;

  if (param === undefined) {
    if (scope === 'current') {
      return valSplit.length === 1;
    }
    return false;
  }
  if (scope === 'perm') {
    const paramSplit = param.split('');
    if (paramSplit.length !== 3 || valSplit.length > 2) {
      return false;
    }
    const [r, w, x] = paramSplit;
    return (r === 'r' || r === '-') &&
      (w === 'w' || w === '-') &&
      (x === 'x' || x === '-');
  }
  return scope === 'path';
}

function configHelpStalkerEvent () {
  return `Specify the event to use when stalking, possible values:

    call            trace calls
    ret             trace returns
    exec            trace every instruction
    block           trace basic block execution (every time)
    compile         trace basic blocks once (this is the default)
  `;
}

function configValidateStalkerEvent (val) {
  return ['call', 'ret', 'exec', 'block', 'compile'].indexOf(val) !== -1;
}

function configHelpStalkerTimeout () {
  return `Time after which the stalker gives up (in seconds). Defaults to 5 minutes,
 set to 0 to disable.`;
}

function configValidateStalkerTimeout (val) {
  return val >= 0;
}

function configHelpFileLog () {
  return `Set filename to save all the tracing logs generated by :dt

    string        specify file path of the log file
  `;
}

function configHelpHookUseCmd () {
  return `Use the given command when registering a new trace (dt) or injection (di) to be executed when hits

    '' | 'r2cmd'  the r2 command will be executed from the host side and r2frida commands can be also recursively called
  `;
}

function configHelpHookVerbose () {
  return `Show trace messages to the console. They are also logged in :dtl

    true | false    to enable or disable the option
  `;
}

function configHelpHookLogs () {
  return `Save hook trace logs internally in the agent. Use :dtl to list them

    true | false    to enable or disable the option (enabled by default)
  `;
}

function configHelpHookOutput () {
  return `Choose output format.

    simple | json   (simple by default)
  `;
}

function configHelpHookBacktrace () {
  return `Append the backtrace on each trace hook registered with :dt commands

    true | false    to enable or disable the option
  `;
}

function configHelpStalkerIn () {
  return `Restrict stalker results based on where the event has originated:

    raw             stalk everywhere (the default)
    app             stalk only in the app module
    modules         stalk in app module and all linked libraries
  `;
}

function configHelpSymbolsModule () {
  return `When set ignore offset to tell frida which module to use for symbols:

    See :dm command to get all maps and :dmm for modules
  `;
}

function configHelpSymbolsUnredact () {
  return `Try to get symbol names from debug symbols when they're "redacted":

    true            try to unredact (the default)
    false           do not attempt to unredact
  `;
}

function configValidateStalkerIn (val) {
  return ['raw', 'app', 'modules'].indexOf(val) !== -1;
}

function configValidateString (val) {
  return typeof (val) === 'string';
}

function configValidateBoolean (val) {
  return isTrue(val) || isFalse(val);
}

function isTrue (x) {
  return (x === true || x === 1 || x === '1' || (/(true)/i).test(x));
}

function isFalse (x) {
  return (x === false || x === 0 || x === '0' || (/(false)/i).test(x));
}

function asR2Script () {
  return Object.keys(config)
    .map(k => 'e ' + k + '=' + config[k])
    .join('\n');
}

function set (k, v) {
  if (configValidator[k] !== undefined) {
    if (!configValidator[k](v)) {
      console.error(`Invalid value for ${k}`);
      return '';
    }
  }
  config[k] = v;
}

function helpFor (k) {
  if (configHelp[k] !== undefined) {
    return configHelp[k]();
  }
  console.error(`no help for ${k}`);
  return '';
}

module.exports = {
  values: config, // bad practice, dont expose
  set: set, // c(k, v) => config[k] = v,
  get: (k) => config[k],
  getBoolean: (k) => isTrue(config[k]),
  getString: (k) => (config[k]) ? '' + config[k] : '',
  asR2Script: asR2Script,
  helpFor: helpFor
};
<commit_msg>Use ':' prefix in the ':e' output<commit_after>'use strict';

const config = {
  'java.wait': false,
  'patch.code': true,
  'search.in': 'perm:r--',
  'search.quiet': false,
  'stalker.event': 'compile',
  'stalker.timeout': 5 * 60,
  'stalker.in': 'raw',
  'hook.backtrace': true,
  'hook.verbose': true,
  'hook.logs': true,
  'hook.output': 'simple',
  'hook.usecmd': '',
  'file.log': '',
  'symbols.module': '',
  'symbols.unredact': Process.platform === 'darwin'
};

const configHelp = {
  'java.wait': configHelpJavaWait,
  'search.in': configHelpSearchIn,
  'stalker.event': configHelpStalkerEvent,
  'stalker.timeout': configHelpStalkerTimeout,
  'stalker.in': configHelpStalkerIn,
  'hook.backtrace': configHelpHookBacktrace,
  'hook.verbose': configHelpHookVerbose,
  'hook.usecmd': configHelpHookUseCmd,
  'hook.logs': configHelpHookLogs,
  'hook.output': configHelpHookOutput,
  'file.log': configHelpFileLog,
  'symbols.module': configHelpSymbolsModule,
  'symbols.unredact': configHelpSymbolsUnredact
};

const configValidator = {
  'java.wait': configValidateBoolean,
  'search.in': configValidateSearchIn,
  'stalker.event': configValidateStalkerEvent,
  'stalker.timeout': configValidateStalkerTimeout,
  'stalker.in': configValidateStalkerIn,
  'hook.backtrace': configValidateBoolean,
  'hook.verbose': configValidateBoolean,
  'hook.logs': configValidateBoolean,
  'hook.output': configValidateString,
  'file.log': configValidateString,
  'symbols.module': configValidateString,
  'symbols.unredact': configValidateBoolean
};

function configHelpJavaWait () {
  return 'Wait for Java classloader to be ready (boolean)';
}

function configHelpSearchIn () {
  return `Specify which memory ranges to search in, possible values:

    perm:---        filter by permissions (default: 'perm:r--')
    current         search the range containing current offset
    heap            search inside the heap allocated regions
    path:pattern    search ranges mapping paths containing 'pattern'
  `;
}

function configValidateSearchIn (val) {
  if (val === 'heap') {
    return true;
  }
  const valSplit = val.split(':');
  const [scope, param] = valSplit;

  if (param === undefined) {
    if (scope === 'current') {
      return valSplit.length === 1;
    }
    return false;
  }
  if (scope === 'perm') {
    const paramSplit = param.split('');
    if (paramSplit.length !== 3 || valSplit.length > 2) {
      return false;
    }
    const [r, w, x] = paramSplit;
    return (r === 'r' || r === '-') &&
      (w === 'w' || w === '-') &&
      (x === 'x' || x === '-');
  }
  return scope === 'path';
}

function configHelpStalkerEvent () {
  return `Specify the event to use when stalking, possible values:

    call            trace calls
    ret             trace returns
    exec            trace every instruction
    block           trace basic block execution (every time)
    compile         trace basic blocks once (this is the default)
  `;
}

function configValidateStalkerEvent (val) {
  return ['call', 'ret', 'exec', 'block', 'compile'].indexOf(val) !== -1;
}

function configHelpStalkerTimeout () {
  return `Time after which the stalker gives up (in seconds). Defaults to 5 minutes,
 set to 0 to disable.`;
}

function configValidateStalkerTimeout (val) {
  return val >= 0;
}

function configHelpFileLog () {
  return `Set filename to save all the tracing logs generated by :dt

    string        specify file path of the log file
  `;
}

function configHelpHookUseCmd () {
  return `Use the given command when registering a new trace (dt) or injection (di) to be executed when hits

    '' | 'r2cmd'  the r2 command will be executed from the host side and r2frida commands can be also recursively called
  `;
}

function configHelpHookVerbose () {
  return `Show trace messages to the console. They are also logged in :dtl

    true | false    to enable or disable the option
  `;
}

function configHelpHookLogs () {
  return `Save hook trace logs internally in the agent. Use :dtl to list them

    true | false    to enable or disable the option (enabled by default)
  `;
}

function configHelpHookOutput () {
  return `Choose output format.

    simple | json   (simple by default)
  `;
}

function configHelpHookBacktrace () {
  return `Append the backtrace on each trace hook registered with :dt commands

    true | false    to enable or disable the option
  `;
}

function configHelpStalkerIn () {
  return `Restrict stalker results based on where the event has originated:

    raw             stalk everywhere (the default)
    app             stalk only in the app module
    modules         stalk in app module and all linked libraries
  `;
}

function configHelpSymbolsModule () {
  return `When set ignore offset to tell frida which module to use for symbols:

    See :dm command to get all maps and :dmm for modules
  `;
}

function configHelpSymbolsUnredact () {
  return `Try to get symbol names from debug symbols when they're "redacted":

    true            try to unredact (the default)
    false           do not attempt to unredact
  `;
}

function configValidateStalkerIn (val) {
  return ['raw', 'app', 'modules'].indexOf(val) !== -1;
}

function configValidateString (val) {
  return typeof (val) === 'string';
}

function configValidateBoolean (val) {
  return isTrue(val) || isFalse(val);
}

function isTrue (x) {
  return (x === true || x === 1 || x === '1' || (/(true)/i).test(x));
}

function isFalse (x) {
  return (x === false || x === 0 || x === '0' || (/(false)/i).test(x));
}

function asR2Script () {
  return Object.keys(config)
    .map(k => ':e ' + k + '=' + config[k])
    .join('\n');
}

function set (k, v) {
  if (configValidator[k] !== undefined) {
    if (!configValidator[k](v)) {
      console.error(`Invalid value for ${k}`);
      return '';
    }
  }
  config[k] = v;
}

function helpFor (k) {
  if (configHelp[k] !== undefined) {
    return configHelp[k]();
  }
  console.error(`no help for ${k}`);
  return '';
}

module.exports = {
  values: config, // bad practice, dont expose
  set: set, // c(k, v) => config[k] = v,
  get: (k) => config[k],
  getBoolean: (k) => isTrue(config[k]),
  getString: (k) => (config[k]) ? '' + config[k] : '',
  asR2Script: asR2Script,
  helpFor: helpFor
};
<|endoftext|>


<commit_before>var splineLoop1, splineLoop2, splineLoop3;
var hasMouseMoved;

document.addEventListener("DOMContentLoaded", function(){
    document.getElementById("sb-site").addEventListener('mousemove', function onFirstMouseMove() {
        hasMouseMoved = true;
        // stop listening
        document.getElementById("sb-site").removeEventListener('mousemove', onFirstMouseMove, false);
    }, false);
});

function setup() {
    var myCanvas = createCanvas(windowWidth, windowHeight);
    myCanvas.parent('splineLoops');
    background(0);
    frameRate(30);
    smooth();
    noFill();

    var teal = color('#0096AC');
    var pink = color('#FBD2CE');
    var purple = color('#796CAF');
    var green = color('#9CFCCF');
    var colorCombo1 = [teal, pink];
    var colorCombo2 = [teal, green];
    var colorCombo3 = [purple, pink];

    var splineSettings1 = {
        nPoints: 10,
        origin: {
            x: 0.33 * width,
            y: 0.6 * height
        },
        radius: 0.55 * height,
        distortFactor: 0.2 * 0.55 * height,
        colors: colorCombo1,
        interpolationSteps: 4,
        movement: {
            moveFactor: -0.2,    // 0 == no positional animation
            noiseFactor: 0.6,     // 0 == no noise
            easeFactor: 0.05,   // 1 == no easing
            tightnessFactor: 0  // 0 == no tightness animation
        }
    }
    splineLoop1 = new SplineLoop(splineSettings1);

    var splineSettings2 = {
        nPoints: 10,
        origin: {
            x: 0.7 * width,
            y: 0.6 * height
        },
        radius: 0.45 * height,
        distortFactor: 0.2 * 0.4 * height,
        colors: colorCombo2,
        interpolationSteps: 4,
        movement: {
            moveFactor: -0.2,   // 0 == no positional animation
            noiseFactor: 0.6,   // 0 == no noise
            easeFactor: 0.05,   // 1 == no easing
            tightnessFactor: 0  // 0 == no tightness animation
        }
    }
    splineLoop2 = new SplineLoop(splineSettings2);

    var splineSettings3 = {
        nPoints: 10,
        origin: {
            x: 0.5 * width,
            y: 0.4 * height
        },
        radius: 0.5 * height,
        distortFactor: 0.2 * 0.5 * height,
        colors: colorCombo3,
        interpolationSteps: 4,
        movement: {
            moveFactor: -0.2,   // 0 == no positional animation
            noiseFactor: 0.6,   // 0 == no noise
            easeFactor: 0.05,   // 1 == no easing
            tightnessFactor: 0  // 0 == no tightness animation
        }
    }
    splineLoop3 = new SplineLoop(splineSettings3);

    splineLoop1.drawSplines();
    splineLoop2.drawSplines();
    splineLoop3.drawSplines();
}

function draw() {
    // update if mousemove event has been detected
    if (hasMouseMoved) {
        background(0);
        splineLoop1.update();
        splineLoop1.drawSplines();

        splineLoop2.update();
        splineLoop2.drawSplines();

        splineLoop3.update();
        splineLoop3.drawSplines();
    }
}

function windowResized() {
    resizeCanvas(windowWidth, windowHeight);
}<commit_msg>optimize bg animation to update only during mouse movement<commit_after>var splineLoop1, splineLoop2, splineLoop3;
var hasMouseMoved, mouseTimeout;

document.addEventListener("DOMContentLoaded", function(){
    document.getElementById("sb-site").addEventListener('mousemove', function onFirstMouseMove() {
        hasMouseMoved = true;

        clearTimeout(mouseTimeout);
        mouseTimeout = setTimeout(function () {
            hasMouseMoved = false;
        }, 5000);

    }, false);
});

function setup() {
    var myCanvas = createCanvas(windowWidth, windowHeight);
    myCanvas.parent('splineLoops');
    background(0);
    frameRate(30);
    smooth();
    noFill();

    var teal = color('#0096AC');
    var pink = color('#FBD2CE');
    var purple = color('#796CAF');
    var green = color('#9CFCCF');
    var colorCombo1 = [teal, pink];
    var colorCombo2 = [teal, green];
    var colorCombo3 = [purple, pink];

    var splineSettings1 = {
        nPoints: 10,
        origin: {
            x: 0.33 * width,
            y: 0.6 * height
        },
        radius: 0.55 * height,
        distortFactor: 0.2 * 0.55 * height,
        colors: colorCombo1,
        interpolationSteps: 4,
        movement: {
            moveFactor: -0.2,    // 0 == no positional animation
            noiseFactor: 0.6,     // 0 == no noise
            easeFactor: 0.05,   // 1 == no easing
            tightnessFactor: 0  // 0 == no tightness animation
        }
    }
    splineLoop1 = new SplineLoop(splineSettings1);

    var splineSettings2 = {
        nPoints: 10,
        origin: {
            x: 0.7 * width,
            y: 0.6 * height
        },
        radius: 0.45 * height,
        distortFactor: 0.2 * 0.4 * height,
        colors: colorCombo2,
        interpolationSteps: 4,
        movement: {
            moveFactor: -0.2,   // 0 == no positional animation
            noiseFactor: 0.6,   // 0 == no noise
            easeFactor: 0.05,   // 1 == no easing
            tightnessFactor: 0  // 0 == no tightness animation
        }
    }
    splineLoop2 = new SplineLoop(splineSettings2);

    var splineSettings3 = {
        nPoints: 10,
        origin: {
            x: 0.5 * width,
            y: 0.4 * height
        },
        radius: 0.5 * height,
        distortFactor: 0.2 * 0.5 * height,
        colors: colorCombo3,
        interpolationSteps: 4,
        movement: {
            moveFactor: -0.2,   // 0 == no positional animation
            noiseFactor: 0.6,   // 0 == no noise
            easeFactor: 0.05,   // 1 == no easing
            tightnessFactor: 0  // 0 == no tightness animation
        }
    }
    splineLoop3 = new SplineLoop(splineSettings3);

    splineLoop1.drawSplines();
    splineLoop2.drawSplines();
    splineLoop3.drawSplines();
}

function draw() {
    // update if mousemove event has been detected
    if (hasMouseMoved) {
        background(0);
        splineLoop1.update();
        splineLoop1.drawSplines();

        splineLoop2.update();
        splineLoop2.drawSplines();

        splineLoop3.update();
        splineLoop3.drawSplines();
    }
}

function windowResized() {
    resizeCanvas(windowWidth, windowHeight);
}<|endoftext|>


<commit_before>import * as logger from '../logger';
import * as installer from '../installer';
import util from 'util';
import fs from 'fs';
import { spawn } from 'child-process-promise';
import Promise from 'bluebird';

var jspm = process.platform === "win32" ? "jspm.cmd" : "jspm";

function update(options) {
  if (options.nuclear) {
    logger.log('Going NUCLEAR!')
    logger.log('Clearing jspm packages...');
    moveJSPMPackages(function() {
      logger.log('Clearing npm packages...');
      moveNPMPackages(function() {
        normalUpdate();
      });
    });
  } else {
    logger.log('Updating normally...');
    normalUpdate();
  }
}

function unbundle() {
  logger.log('Running jspm unbundle');
  return spawn(jspm, ['unbundle']);
}

function normalUpdate() {
  var updateCommands = [];
  var repoList = readConfigJs();

  unbundle()
    .then(() => {
      installer
        .runNPMInstall(function() {
          logger.log('Successfully npm installed');
          logger.log('Updating all aurelia libs');
          repoList.forEach(repo => {
            updateCommands.push(spawn(jspm, ['install ' + repo]));
          });

          Promise.all(updateCommands)
            .then(function() {
              logger.log('LASTLY, CLEANING JSPM')
              spawn(jspm, ['clean']);
            });
        });
    })
    .fail((err)=>{
      console.log(err);
    });
}

function moveJSPMPackages(done) {
  fs.rename('./jspm_packages', './jspm_packages_backup', done);
}

function moveNPMPackages(done) {
  fs.rename('node_modules', 'node_modules_backup', done);
}

function canAddToRepoList(list, reponame) {
  return reponame.indexOf('github:aurelia/') !== -1;
}

function readConfigJs() {
  var cfg = {};
  var System = {
    config: function(_cfg) {
      for (var c in _cfg) {
        if (!_cfg.hasOwnProperty(c))
          continue;
        var v = _cfg[c];
        if (typeof v === 'object') {
          cfg[c] = cfg[c] || {};
          for (var p in v) {
            if (!v.hasOwnProperty(p))
              continue;
            cfg[c][p] = v[p];
          }
        } else
          cfg[c] = v;
      }
    },
    paths: {},
    map: {},
    versions: {}
  };
  var source;
  source = fs.readFileSync('config.js');
  eval(source.toString())
  var config = System.config;
  delete System.config;
  config(System);
  var repoList = getRepoList(cfg.map);
  return repoList;
}

function getRepoList(maps) {
  var list = [];
  for (let p in maps) {
    var v = maps[p];
    if (typeof v === 'object') {
      if (canAddToRepoList(list, p)) {
        list.push(p);
      }
    } else {
      if (canAddToRepoList(list, v)) {
        list.push(v);
      }
    }
  }
  return list;
}

module.exports = {
  update: update
}
<commit_msg>bug(updater): fix jspm install<commit_after>import * as logger from '../logger';
import * as installer from '../installer';
import util from 'util';
import fs from 'fs';
import {
  spawn, exec
}
from 'child-process-promise';
import Promise from 'bluebird';

var jspm = process.platform === "win32" ? "jspm.cmd" : "jspm";

function update(options) {
  if (options.nuclear) {
    logger.log('Going NUCLEAR!')
    logger.log('Clearing jspm packages...');
    moveJSPMPackages(function() {
      logger.log('Clearing npm packages...');
      moveNPMPackages(function() {
        normalUpdate();
      });
    });
  } else {
    logger.log('Updating normally...');
    normalUpdate();
  }
}

function unbundle() {
  logger.log('Running jspm unbundle');
  return spawn(jspm, ['unbundle']);
}

function normalUpdate() {
  var updateCommands = [];
  var repoList = readConfigJs();

  unbundle()
    .then(() => {
      installer
        .runNPMInstall(function() {
          logger.log('Successfully npm installed');
          logger.log('Updating all aurelia libs');

          Promise.all(repoList.map(repo => {
             return spawn('jspm.cmd', ['install', 'github:aurelia/animator-css@0.2.0'])
                .progress(function(cp) {
                  cp.stdout.on('data', function(data) {
                    logger.log(data.toString());
                  });

                  cp.stderr.on('data', function(data) {
                    logger.err('Errror: ', data.toString());
                  });
                });
            }))
            .then(function() {
              logger.log('LASTLY, CLEANING JSPM')
              spawn(jspm, ['clean']);
            });
        });
    })
    .fail((err) => {
      logger.err(err.toString());
    });
}

function moveJSPMPackages(done) {
  fs.rename('./jspm_packages', './jspm_packages_backup', done);
}

function moveNPMPackages(done) {
  fs.rename('node_modules', 'node_modules_backup', done);
}

function canAddToRepoList(list, reponame) {
  return reponame.indexOf('github:aurelia/') !== -1;
}

function readConfigJs() {
  var cfg = {};
  var System = {
    config: function(_cfg) {
      for (var c in _cfg) {
        if (!_cfg.hasOwnProperty(c))
          continue;
        var v = _cfg[c];
        if (typeof v === 'object') {
          cfg[c] = cfg[c] || {};
          for (var p in v) {
            if (!v.hasOwnProperty(p))
              continue;
            cfg[c][p] = v[p];
          }
        } else
          cfg[c] = v;
      }
    },
    paths: {},
    map: {},
    versions: {}
  };
  var source;
  source = fs.readFileSync('config.js');
  eval(source.toString())
  var config = System.config;
  delete System.config;
  config(System);
  var repoList = getRepoList(cfg.map);
  return repoList;
}

function getRepoList(maps) {
  var list = [];
  for (let p in maps) {
    var v = maps[p];
    if (typeof v === 'object') {
      if (canAddToRepoList(list, p)) {
        list.push(p);
      }
    } else {
      if (canAddToRepoList(list, v)) {
        list.push(v);
      }
    }
  }
  return list;
}

module.exports = {
  update: update
}
<|endoftext|>


<commit_before>// Project imports
var BotPlayer = require('./BotPlayer');
var MinionPlayer = require('./MinionPlayer');
var FakeSocket = require('./FakeSocket');
var PacketHandler = require('../PacketHandler');

function BotLoader(gameServer) {
    this.gameServer = gameServer;
    this.loadNames();
}

module.exports = BotLoader;

BotLoader.prototype.getName = function () {
    var name = "";

    // Picks a random name for the bot
    if (this.randomNames.length > 0) {
        var index = (this.randomNames.length * Math.random()) >>> 0;
        name = this.randomNames[index];
    } else {
        name = "bot" + ++this.nameIndex;
    }

    return name;
};

BotLoader.prototype.loadNames = function () {
    this.randomNames = [];
    var fs = require("fs");

    if (fs.existsSync("./ai/BotNames.txt")) {
        // Read and parse the names - filter out whitespace-only names
        this.randomNames = fs.readFileSync("./ai/BotNames.txt", "utf8").split(/[\r\n]+/).filter(function (x) {
            return x != ''; // filter empty names
        });
    }
    this.nameIndex = 0;
};

BotLoader.prototype.addBot = function () {
    var s = new FakeSocket(this.gameServer);
    s.playerTracker = new BotPlayer(this.gameServer, s);
    s.packetHandler = new PacketHandler(this.gameServer, s);

    // Add to client list
    this.gameServer.clients.push(s);

    // Add to world
    s.packetHandler.setNickname(this.getName());
};

BotLoader.prototype.addMinion = function(owner, name) {
    var s = new FakeSocket(this.gameServer);
    s.playerTracker = new MinionPlayer(this.gameServer, s, owner);
    s.packetHandler = new PacketHandler(this.gameServer, s);
    s.playerTracker.owner = owner;

    // Add to client list
    this.gameServer.clients.push(s);

    // Add to world & set name
    s.packetHandler.setNickname(name);
};
<commit_msg>Update BotLoader.js<commit_after>// Project imports
var BotPlayer = require('./BotPlayer');
var MinionPlayer = require('./MinionPlayer');
var FakeSocket = require('./FakeSocket');
var PacketHandler = require('../PacketHandler');

function BotLoader(gameServer) {
    this.gameServer = gameServer;
    this.loadNames();
}

module.exports = BotLoader;

BotLoader.prototype.getName = function () {
    var name = "";

    // Picks a random name for the bot
    if (this.randomNames.length > 0) {
        var index = (this.randomNames.length * Math.random()) >>> 0;
        name = this.randomNames[index];
    } else {
        name = "bot" + ++this.nameIndex;
    }

    return name;
};

BotLoader.prototype.loadNames = function () {
    this.randomNames = [];
    var fs = require("fs");

    if (fs.existsSync("./ai/BotNames.txt")) {
        // Read and parse the names - filter out whitespace-only names
        this.randomNames = fs.readFileSync("./ai/BotNames.txt", "utf8").split(/[\r\n]+/).filter(function (x) {
            return x != ''; // filter empty names
        });
    }
    this.nameIndex = 0;
};

BotLoader.prototype.addBot = function () {
    var s = new FakeSocket(this.gameServer);
    s.playerTracker = new BotPlayer(this.gameServer, s);
    s.packetHandler = new PacketHandler(this.gameServer, s);

    // Add to client list
    this.gameServer.clients.push(s);

    // Add to world
    s.packetHandler.setNickname(this.getName());
};

BotLoader.prototype.addMinion = function(owner, name) {
    var s = new FakeSocket(this.gameServer);
    s.playerTracker = new MinionPlayer(this.gameServer, s, owner);
    s.packetHandler = new PacketHandler(this.gameServer, s);
    s.playerTracker.owner = owner;

    // Add to client list
    this.gameServer.clients.push(s);

    // Add to world & set name
    if (typeof name == "undefined" || name == "") {
        name = this.gameServer.config.defaultName;
    }
    s.packetHandler.setNickname(name);
};
<|endoftext|>


<commit_before>/**
* Module that contains the animator implementations.
* Depends on core.js
*/
(function($) {
  if (typeof JSAV === "undefined") { return; }

  function backward() {
    if (this._undo.length === 0) { return; }
    var ops = this._undo.pop();
    for (var i = ops.length - 1; i >= 0; i--) {
      var prev = ops[i];
      prev[3].apply(prev[0], prev[2]);
    }
    this._redo.unshift(ops);
  }

  function forward() {
    if (this._redo.length === 0) { return; }
    var ops = this._redo.shift();
    for (var i = 0; i < ops.length; i++) {
      var next = ops[i];
      if (typeof next[3] === "undefined" || !$.isFunction(next[3])) {
        next[3] = function() {
          var obj = next[0],
            state = obj.state();
          return function() {
            obj.state(state);
          };
        }();
      }
      next[1].apply(next[0], next[2]);
    }
    this._undo.push(ops);
  }

  JSAV.init(function() {
    this._redo = [];
    this._undo = [];
    var that = this,
      $controls = $(".controls", $(this.container));
    if ($controls.size() === 0) {
      return; // no controls, no need to proceed
    }
    var beginHandler = function(e) {
      e.preventDefault();
      that.begin();
    };
    var backwardHandler = function(e) {
      e.preventDefault();
      that.backward();
    };
    var forwardHandler = function(e) {
      e.preventDefault();
      that.forward();
    };
    var endHandler = function(e) {
      e.preventDefault();
      that.end();
    };
    $("Begin").click(beginHandler).appendTo($controls);
    $("Backward").click(backwardHandler).appendTo($controls);
    $("Forward").click(forwardHandler).appendTo($controls);
    $("End").click(endHandler).appendTo($controls);
    this.container.bind({ "forward": forwardHandler,
                          "backward": backwardHandler,
                          "begin": beginHandler,
                          "end": endHandler });
  });

  function anim(effect, undo) {
    // a function that can be used to provide function calls that are applied later
    // when viewing the visualization
    return function() {
      var jsav = this;
      if (!jsav.hasOwnProperty("_redo")) { jsav = this.jsav; }
      var stackTop = jsav._redo[0];
      if (!stackTop) {
        stackTop = [];
        jsav._redo.push(stackTop);
      }
      if (jsav.options.animationMode == 'none') {
        effect.apply(this, arguments);
      } else {
        stackTop.push([this, effect, arguments, undo]);
      }
      return this;
    };
  }

  function begin() {
    var prevFx = $.fx.off;
    $.fx.off = true;
    while (this._undo.length) {
      this.backward();
    }
    $.fx.off = false;
    return this;
  }

  function end() {
    var prevFx = $.fx.off;
    $.fx.off = true;
    while (this._redo.length) {
      this.forward();
    }
    $.fx.off = false;
    return this;
  }

  /* Add the function effect to the animation queue */
  function queue(obj, effect) {
    if (!this._redo) { initQueue(this); }
    this._redo.push([obj, effect]);
  }
  JSAV.anim = anim;
  JSAV.ext.SPEED = 400;
  JSAV.ext.queue = queue;
  JSAV.ext.begin = begin;
  JSAV.ext.end = end;
  JSAV.ext.forward = forward;
  JSAV.ext.backward = backward;
  JSAV.ext.currentStep = function() {
    return this._undo.length;
  };
  JSAV.ext.step = function(options) {
    if (this._redo.length === 0 || this._redo[0].length === 0) { // ignore step if no operations in it
      return this;
    }
    this.forward();
    this._redo.push([]); // add new empty step to oper. stack
    if (options && this.message && options.message) {
      this.message(options.message);
    }
    return this;
  };
  JSAV.ext.substep = function(options) {
    // TODO: implement substep
    return this.step(options);
  };
  JSAV.ext.stepdone = function() {return this;};
  JSAV.ext.recorded = function() {
    console.log("Number of steps: ", this._undo.length)
    this.forward(); // apply the last steps
    this.RECORD = false;
    this.begin();
  };
})(jQuery);
<commit_msg>Removed old code, reorganized code, added comments<commit_after>/**
* Module that contains the animator implementations.
* Depends on core.js
*/
(function($) {
  if (typeof JSAV === "undefined") { return; }

  function backward() {
    if (this._undo.length === 0) { return; }
    var ops = this._undo.pop(); // get the operations in the step we're about to undo
    for (var i = ops.length - 1; i >= 0; i--) { // iterate the operations
      // operation contains: [target object, effect function, arguments, undo function]
      var prev = ops[i];
      prev[3].apply(prev[0], prev[2]);
    }
    this._redo.unshift(ops);
  }

  function forward() {
    if (this._redo.length === 0) { return; }
    var ops = this._redo.shift(); // get the operations in the step we're about to undo
    for (var i = 0; i < ops.length; i++) {
      // operation contains: [target object, effect function, arguments, undo function]
      var next = ops[i];
      if (typeof next[3] === "undefined" || !$.isFunction(next[3])) { // if no undo function
        next[3] = function() {
          var obj = next[0],
            state = obj.state();
          return function() { // we create one that will set the state of obj to its current state
            obj.state(state);
          };
        }();
      }
      next[1].apply(next[0], next[2]);
    }
    this._undo.push(ops);
  }

  function begin() {
    var prevFx = $.fx.off;
    $.fx.off = true;
    while (this._undo.length) {
      this.backward();
    }
    $.fx.off = false;
    return this;
  }

  function end() {
    var prevFx = $.fx.off;
    $.fx.off = true;
    while (this._redo.length) {
      this.forward();
    }
    $.fx.off = false;
    return this;
  }

  JSAV.init(function() {
    this._redo = []; // stack for operations to redo
    this._undo = []; // stack for operations to undo
    var that = this,
      $controls = $(".controls", $(this.container));
    if ($controls.size() === 0) {
      return; // no controls, no need to proceed
    }
    // reqister event handlers for the control buttons
    var beginHandler = function(e) {
      e.preventDefault();
      that.begin();
    };
    var backwardHandler = function(e) {
      e.preventDefault();
      that.backward();
    };
    var forwardHandler = function(e) {
      e.preventDefault();
      that.forward();
    };
    var endHandler = function(e) {
      e.preventDefault();
      that.end();
    };
    $("Begin").click(beginHandler).appendTo($controls);
    $("Backward").click(backwardHandler).appendTo($controls);
    $("Forward").click(forwardHandler).appendTo($controls);
    $("End").click(endHandler).appendTo($controls);
    // bind the handlers to events to enable control by triggering events
    this.container.bind({ "forward": forwardHandler,
                          "backward": backwardHandler,
                          "begin": beginHandler,
                          "end": endHandler });
  });

  // this function can be used to "decorate" effects to be applied when moving forward
  // in the animation
  function anim(effect, undo) {
    // returns a function that can be used to provide function calls that are applied later
    // when viewing the visualization
    return function() {
      var jsav = this; // this points to the objects whose function was decorated
      if (!jsav.hasOwnProperty("_redo")) { jsav = this.jsav; }
      var stackTop = jsav._redo[0];
      if (!stackTop) {
        stackTop = [];
        jsav._redo.push(stackTop);
      }
      if (jsav.options.animationMode == 'none') { // if not recording, apply immediately
        effect.apply(this, arguments);
      } else {
        // add to stack: [target object, effect function, arguments, undo function]
        stackTop.push([this, effect, arguments, undo]);
      }
      return this;
    };
  }

  JSAV.anim = anim;
  JSAV.ext.SPEED = 400;
  JSAV.ext.begin = begin;
  JSAV.ext.end = end;
  JSAV.ext.forward = forward;
  JSAV.ext.backward = backward;
  JSAV.ext.currentStep = function() {
    return this._undo.length;
  };
  JSAV.ext.step = function(options) {
    if (this._redo.length === 0 || this._redo[0].length === 0) { // ignore step if no operations in it
      return this;
    }
    this.forward();
    this._redo.push([]); // add new empty step to oper. stack
    if (options && this.message && options.message) {
      this.message(options.message);
    }
    return this;
  };
  JSAV.ext.substep = function(options) {
    // TODO: implement substep
    return this.step(options);
  };
  JSAV.ext.stepdone = function() {return this;};
  JSAV.ext.recorded = function() {
    if (console) { console.log("Number of steps: ", this._undo.length); }
    this.forward(); // apply the last steps
    this.RECORD = false;
    this.begin();
  };
})(jQuery);
<|endoftext|>


<commit_before>/*
 * Sift
 *
 * Copryright 2011, Craig Condon
 * Licensed under MIT
 *
 * Inspired by mongodb's query language
 */

(function() {

  "use strict";

  //traversable statements
  var TRAV_OP = {
    $and  : true,
    $or   : true,
    $nor  : true,
    $trav : true,
    $not  : true
  };

  var _testers = {

    /**
     */

    $eq: function(a, b) {
      return a.test(b);
    },

    /**
     */

    $ne: function(a, b) {
      return !a.test(b);
    },

    /**
     */

    $lt: function(a, b) {
      return a > b;
    },

    /**
     */

    $gt: function(a, b) {
      return a < b;
    },

    /**
     */

    $lte: function(a, b) {
      return a >= b;
    },

    /**
     */

    $gte: function(a, b) {
      return a <= b;
    },

    /**
     */

    $exists: function(a, b) {
      return a === (b != null);
    },

    /**
     */

    $in: function(a, b) {

      //intersecting an array
      if (b instanceof Array) {

        for (var i = b.length; i--;) {
          if (~a.indexOf(b[i])) return true;
        }

      } else {
        return ~a.indexOf(b);
      }

      return false;
    },

    /**
     */

    $not: function(a, b) {
      if (!a.test) throw new Error("$not test should include an expression, not a value. Use $ne instead.");
      return !a.test(b);
    },

    /**
     */

    $type: function(a, b, org) {
      //instanceof doesn't work for strings / boolean. instanceof works with inheritance
      return org != null ? org instanceof a || org.constructor == a : false;
    },

    /**
     */

    $nin: function(a, b) {
      return !_testers.$in(a, b);
    },

    /**
     */

    $mod: function(a, b) {
      return b % a[0] == a[1];
    },

    /**
     */

    $all: function(a, b) {
      if (!b) b = [];
      for (var i = a.length; i--;) {
        var a1 = a[i];
        var indexInB = ~b.indexOf(a1);
        if (!indexInB) return false;
      }

      return true;
    },

    /**
     */

    $size: function(a, b) {
      return b ? a === b.length : false;
    },

    /**
     */

    $or: function(a, b) {

      var i = a.length;
      var n = i;

      for (; i--;) {
        if (test(a[i], b)) {
          return true;
        }
      }

      return n === 0;
    },

    /**
     */

    $nor: function(a, b) {

      var i = a.length;

      for (; i--;) {
        if (test(a[i], b)) {
          return false;
        }
      }

      return true;
    },

    /**
     */

    $and: function(a, b) {

      for (var i = a.length; i--;) {
        if (!test(a[i], b)) {
          return false;
        }
      }

      return true;
    },

    /**
     */

    $trav: function(a, b) {

      if (b instanceof Array) {

        for (var i = b.length; i--;) {
          var subb = b[i];
          if (subb[a.k] && test(a, subb[a.k])) return true;
        }

        return false;
      }

      //continue to traverse even if there isn't a value - this is needed for
      //something like name:{$exists:false}
      return test(a, b ? b[a.k] : void 0);
    },

    /**
     */

    $regex: function(a, b) {
      var aRE = new RegExp(a);
      return aRE.test(b);
    },

    /**
     */

    $where: function(a, b) {
      return a.call(b, b);
    },

    /**
     */

    $elemMatch: function(a, b) {
      return a.test(b);
    }
  };

  var _prepare = {

    /**
     */

    $eq: function(a) {

      var fn;

      if (a instanceof RegExp) {
        return a;
      } else if (a instanceof Function) {
        fn = a;
      } else {
        fn = function(b) {
          if (b instanceof Array) {
            return ~b.indexOf(a);
          } else {
            return a === b;
          }
        };
      }

      return {
        test: fn
      };
    },

    /**
     */

    $ne: function(a) {
      return _prepare.$eq(a);
    },

    /**
     */

    $where: function(a) {

      if (typeof a === "string") {
        return new Function("obj", "return " + a);
      }

      return a;
    },

    /**
     */

    $elemMatch: function(a) {
      return parse(a);
    }
  };

  /**
   */

  function getExpr(type, key, value) {

    var v = comparable(value);

    return {

      //k key
      k: key,

      //v value
      v: _prepare[type] ? _prepare[type](v) : v,

      //e eval
      e: _testers[type]
    };
  }

  /**
   * tests against data
   */

  function test(statement, data) {

    var exprs    = statement.exprs;

    //generally, expressions are ordered from least efficient, to most efficient.
    for (var i = 0, n = exprs.length; i < n; i++) {

      var expr = exprs[i];

      if (!expr.e(expr.v, comparable(data), data)) return false;

    }

    return true;
  }

  /**
   * parses a statement into something evaluable
   */

  function parse(statement, key) {

    //fixes sift(null, []) issue
    if (!statement) statement = { $eq: statement };

    var testers = [];

    //if the statement is an object, then we're looking at something like: { key: match }
    if (statement && statement.constructor.toString() === "Object") {
      console.log("\nstatement is obj\n");

      for (var k in statement) {

        //find the apropriate operator. If one doesn't exist and the key does not start
        //with a $ character, then it's a property, which means we create a new statement
        //(traversing)
        var operator;
        if (!!_testers[k]) {
          operator = k;

        // $ == 36
        } else if (k.charCodeAt(0) !== 36) {
          operator = "$trav";
        } else {
          throw new Error("Unknown operator " + k + ".");
        }

        //value of given statement (the match)
        var value = statement[k];

        //default = match
        var exprValue = value;

        //if we're working with a traversable operator, then set the expr value
        if (TRAV_OP[operator]) {

          //using dot notation? convert into a sub-object
          if (~k.indexOf(".")) {
            var keyParts = k.split(".");
            k = keyParts.shift(); //we're using the first key, so remove it

            exprValue = value = convertDotToSubObject(keyParts, value);
          }

          //*if* the value is an array, then we're dealing with something like: $or, $and
          if (value instanceof Array) {

            exprValue = [];

            for (var i = value.length; i--;) {
              exprValue.push(parse(value[i]));
            }

          //otherwise we're dealing with $trav
          } else {
            exprValue = parse(value, k);
          }
        }

        testers.push(getExpr(operator, k, exprValue));
      }

    //otherwise we're comparing a particular value, so set to eq
    } else {
      testers.push(getExpr("$eq", key, statement));
    }

    var stmt =  {
      exprs: testers,
      k: key,
      test: function(value) {
        return test(stmt, value);
      }
    };

    return stmt;
  }

  /**
   */

  function comparable(value) {
    if (value instanceof Date) {
      return value.getTime();
    } else if (value instanceof Array) {
      return value.map(comparable);
    } else {
      return value;
    }
  }

  /**
   */

  function convertDotToSubObject(keyParts, value) {

    var subObject    = {};
    var currentValue = subObject;

    for (var i = 0, n = keyParts.length - 1; i < n; i++) {
      currentValue = currentValue[keyParts[i]] = {};
    }

    currentValue[keyParts[i]] = value;

    return subObject;
  }

  /**
   */

  function getSelector(selector) {

    if (!selector) {

      return function(value) {
        return value;
      };

    } else if (typeof selector == "function") {
      return selector;
    }

    throw new Error("Unknown sift selector " + selector);
  }

  /**
   * sifts the given function
   * @param query the mongodb query
   * @param target the target array
   * @param rawSelector the selector for plucking data from the given target
   */

  function sift(query, target, rawSelector) {

    //must be an array
    if (typeof target != "object") {
      rawSelector = target;
      target = void 0;
    }

    var selector = getSelector(rawSelector);

    //build the filter for the sifter
    var sifter = parse(query);

    function filter(value) {
      return sifter.test(selector(value));
    }

    if (target) return target.filter(filter);

    filter.query = query;

    return filter;
  }

  sift.use = function(options) {
    if (options.operators) sift.useOperators(options.operators);
    if (typeof options === "function") options(sift);
  };

  sift.useOperators = function(operators) {
    for (var key in operators) {
      sift.useOperator(key, operators[key]);
    }
  };

  sift.useOperator = function(operator, optionsOrFn) {

    var options = {};

    if (typeof optionsOrFn == "object") {
      options = optionsOrFn;
    } else {
      options = { test: optionsOrFn };
    }

    var key = "$" + operator;
    _testers[key] = options.test;

    if (options.traversable || options.traverse) {
      TRAV_OP[key] = true;
    }
  };

  sift.indexOf = function(query, target, rawSelector) {
    var selector = getSelector(rawSelector);

    //build the filter for the sifter
    var sifter = parse(query);

    for (var i = 0; i < target.length; i++) {
      if (sifter.test(selector(target[i]))) {
        return i;
      }
    }

    return -1;
  };

  /* istanbul ignore next */
  if ((typeof module != "undefined") && (typeof module.exports != "undefined")) {
    module.exports = sift;
  } else
  if (typeof window != "undefined") {
    window.sift = sift;
  }
})();
<commit_msg>Add alternative form of Object constructor.<commit_after>/*
 * Sift
 *
 * Copryright 2011, Craig Condon
 * Licensed under MIT
 *
 * Inspired by mongodb's query language
 */

(function() {

  "use strict";

  //traversable statements
  var TRAV_OP = {
    $and  : true,
    $or   : true,
    $nor  : true,
    $trav : true,
    $not  : true
  };

  var _testers = {

    /**
     */

    $eq: function(a, b) {
      return a.test(b);
    },

    /**
     */

    $ne: function(a, b) {
      return !a.test(b);
    },

    /**
     */

    $lt: function(a, b) {
      return a > b;
    },

    /**
     */

    $gt: function(a, b) {
      return a < b;
    },

    /**
     */

    $lte: function(a, b) {
      return a >= b;
    },

    /**
     */

    $gte: function(a, b) {
      return a <= b;
    },

    /**
     */

    $exists: function(a, b) {
      return a === (b != null);
    },

    /**
     */

    $in: function(a, b) {

      //intersecting an array
      if (b instanceof Array) {

        for (var i = b.length; i--;) {
          if (~a.indexOf(b[i])) return true;
        }

      } else {
        return ~a.indexOf(b);
      }

      return false;
    },

    /**
     */

    $not: function(a, b) {
      if (!a.test) throw new Error("$not test should include an expression, not a value. Use $ne instead.");
      return !a.test(b);
    },

    /**
     */

    $type: function(a, b, org) {
      //instanceof doesn't work for strings / boolean. instanceof works with inheritance
      return org != null ? org instanceof a || org.constructor == a : false;
    },

    /**
     */

    $nin: function(a, b) {
      return !_testers.$in(a, b);
    },

    /**
     */

    $mod: function(a, b) {
      return b % a[0] == a[1];
    },

    /**
     */

    $all: function(a, b) {
      if (!b) b = [];
      for (var i = a.length; i--;) {
        var a1 = a[i];
        var indexInB = ~b.indexOf(a1);
        if (!indexInB) return false;
      }

      return true;
    },

    /**
     */

    $size: function(a, b) {
      return b ? a === b.length : false;
    },

    /**
     */

    $or: function(a, b) {

      var i = a.length;
      var n = i;

      for (; i--;) {
        if (test(a[i], b)) {
          return true;
        }
      }

      return n === 0;
    },

    /**
     */

    $nor: function(a, b) {

      var i = a.length;

      for (; i--;) {
        if (test(a[i], b)) {
          return false;
        }
      }

      return true;
    },

    /**
     */

    $and: function(a, b) {

      for (var i = a.length; i--;) {
        if (!test(a[i], b)) {
          return false;
        }
      }

      return true;
    },

    /**
     */

    $trav: function(a, b) {

      if (b instanceof Array) {

        for (var i = b.length; i--;) {
          var subb = b[i];
          if (subb[a.k] && test(a, subb[a.k])) return true;
        }

        return false;
      }

      //continue to traverse even if there isn't a value - this is needed for
      //something like name:{$exists:false}
      return test(a, b ? b[a.k] : void 0);
    },

    /**
     */

    $regex: function(a, b) {
      var aRE = new RegExp(a);
      return aRE.test(b);
    },

    /**
     */

    $where: function(a, b) {
      return a.call(b, b);
    },

    /**
     */

    $elemMatch: function(a, b) {
      return a.test(b);
    }
  };

  var _prepare = {

    /**
     */

    $eq: function(a) {

      var fn;

      if (a instanceof RegExp) {
        return a;
      } else if (a instanceof Function) {
        fn = a;
      } else {
        fn = function(b) {
          if (b instanceof Array) {
            return ~b.indexOf(a);
          } else {
            return a === b;
          }
        };
      }

      return {
        test: fn
      };
    },

    /**
     */

    $ne: function(a) {
      return _prepare.$eq(a);
    },

    /**
     */

    $where: function(a) {

      if (typeof a === "string") {
        return new Function("obj", "return " + a);
      }

      return a;
    },

    /**
     */

    $elemMatch: function(a) {
      return parse(a);
    }
  };

  /**
   */

  function getExpr(type, key, value) {

    var v = comparable(value);

    return {

      //k key
      k: key,

      //v value
      v: _prepare[type] ? _prepare[type](v) : v,

      //e eval
      e: _testers[type]
    };
  }

  /**
   * tests against data
   */

  function test(statement, data) {

    var exprs    = statement.exprs;

    //generally, expressions are ordered from least efficient, to most efficient.
    for (var i = 0, n = exprs.length; i < n; i++) {

      var expr = exprs[i];

      if (!expr.e(expr.v, comparable(data), data)) return false;

    }

    return true;
  }

  /**
   * parses a statement into something evaluable
   */

  function parse(statement, key) {

    //fixes sift(null, []) issue
    if (!statement) statement = { $eq: statement };

    var testers = [];

    //if the statement is an object, then we're looking at something like: { key: match }
    if (statement && statement.constructor.toString() === "Object" || statement.constructor.toString() === "function Object() { [native code] }") {

      for (var k in statement) {

        //find the apropriate operator. If one doesn't exist and the key does not start
        //with a $ character, then it's a property, which means we create a new statement
        //(traversing)
        var operator;
        if (!!_testers[k]) {
          operator = k;

        // $ == 36
        } else if (k.charCodeAt(0) !== 36) {
          operator = "$trav";
        } else {
          throw new Error("Unknown operator " + k + ".");
        }

        //value of given statement (the match)
        var value = statement[k];

        //default = match
        var exprValue = value;

        //if we're working with a traversable operator, then set the expr value
        if (TRAV_OP[operator]) {

          //using dot notation? convert into a sub-object
          if (~k.indexOf(".")) {
            var keyParts = k.split(".");
            k = keyParts.shift(); //we're using the first key, so remove it

            exprValue = value = convertDotToSubObject(keyParts, value);
          }

          //*if* the value is an array, then we're dealing with something like: $or, $and
          if (value instanceof Array) {

            exprValue = [];

            for (var i = value.length; i--;) {
              exprValue.push(parse(value[i]));
            }

          //otherwise we're dealing with $trav
          } else {
            exprValue = parse(value, k);
          }
        }

        testers.push(getExpr(operator, k, exprValue));
      }

    //otherwise we're comparing a particular value, so set to eq
    } else {
      testers.push(getExpr("$eq", key, statement));
    }

    var stmt =  {
      exprs: testers,
      k: key,
      test: function(value) {
        return test(stmt, value);
      }
    };

    return stmt;
  }

  /**
   */

  function comparable(value) {
    if (value instanceof Date) {
      return value.getTime();
    } else if (value instanceof Array) {
      return value.map(comparable);
    } else {
      return value;
    }
  }

  /**
   */

  function convertDotToSubObject(keyParts, value) {

    var subObject    = {};
    var currentValue = subObject;

    for (var i = 0, n = keyParts.length - 1; i < n; i++) {
      currentValue = currentValue[keyParts[i]] = {};
    }

    currentValue[keyParts[i]] = value;

    return subObject;
  }

  /**
   */

  function getSelector(selector) {

    if (!selector) {

      return function(value) {
        return value;
      };

    } else if (typeof selector == "function") {
      return selector;
    }

    throw new Error("Unknown sift selector " + selector);
  }

  /**
   * sifts the given function
   * @param query the mongodb query
   * @param target the target array
   * @param rawSelector the selector for plucking data from the given target
   */

  function sift(query, target, rawSelector) {

    //must be an array
    if (typeof target != "object") {
      rawSelector = target;
      target = void 0;
    }

    var selector = getSelector(rawSelector);

    //build the filter for the sifter
    var sifter = parse(query);

    function filter(value) {
      return sifter.test(selector(value));
    }

    if (target) return target.filter(filter);

    filter.query = query;

    return filter;
  }

  sift.use = function(options) {
    if (options.operators) sift.useOperators(options.operators);
    if (typeof options === "function") options(sift);
  };

  sift.useOperators = function(operators) {
    for (var key in operators) {
      sift.useOperator(key, operators[key]);
    }
  };

  sift.useOperator = function(operator, optionsOrFn) {

    var options = {};

    if (typeof optionsOrFn == "object") {
      options = optionsOrFn;
    } else {
      options = { test: optionsOrFn };
    }

    var key = "$" + operator;
    _testers[key] = options.test;

    if (options.traversable || options.traverse) {
      TRAV_OP[key] = true;
    }
  };

  sift.indexOf = function(query, target, rawSelector) {
    var selector = getSelector(rawSelector);

    //build the filter for the sifter
    var sifter = parse(query);

    for (var i = 0; i < target.length; i++) {
      if (sifter.test(selector(target[i]))) {
        return i;
      }
    }

    return -1;
  };

  /* istanbul ignore next */
  if ((typeof module != "undefined") && (typeof module.exports != "undefined")) {
    module.exports = sift;
  } else
  if (typeof window != "undefined") {
    window.sift = sift;
  }
})();
<|endoftext|>


<commit_before>(function(){

    'use strict';

    angular.module('nvd3', [])

        .directive('nvd3', ['utils', function(utils){
            return {
                restrict: 'AE',
                scope: {
                    data: '=',      //chart data, [required]
                    options: '=',   //chart options, according to nvd3 core api, [required]
                    api: '=?',      //directive global api, [optional]
                    events: '=?',   //global events that directive would subscribe to, [optional]
                    config: '=?'    //global directive configuration, [optional]
                },
                link: function(scope, element, attrs){
                    var defaultConfig = {
                        extended: false,
                        visible: true,
                        disabled: false,
                        autorefresh: true,
                        refreshDataOnly: false,
                        deepWatchData: true,
                        debounce: 10 // default 10ms, time silence to prevent refresh while multiple options changes at a time
                    };

                    //basic directive configuration
                    scope._config = angular.extend(defaultConfig, scope.config);

                    //directive global api
                    scope.api = {
                        // Fully refresh directive
                        refresh: function(){
                            scope.api.updateWithOptions(scope.options);
                        },

                        // Update chart layout (for example if container is resized)
                        update: function() {
                            scope.chart.update();
                        },

                        // Update chart with new options
                        updateWithOptions: function(options){
                            // Clearing
                            scope.api.clearElement();

                            // Exit if options are not yet bound
                            if (angular.isDefined(options) === false) return;

                            // Exit if chart is hidden
                            if (!scope._config.visible) return;

                            // Initialize chart with specific type
                            scope.chart = nv.models[options.chart.type]();

                            // Generate random chart ID
                            scope.chart.id = Math.random().toString(36).substr(2, 15);

                            angular.forEach(scope.chart, function(value, key){
                                if ([
                                    'options',
                                    '_options',
                                    '_inherited',
                                    '_d3options',
                                    'state',
                                    'id',
                                    'resizeHandler'
                                ].indexOf(key) >= 0);

                                else if (key === 'dispatch') {
                                    if (options.chart[key] === undefined || options.chart[key] === null) {
                                        if (scope._config.extended) options.chart[key] = {};
                                    }
                                    configureEvents(scope.chart[key], options.chart[key]);
                                }

                                else if ([
                                    'lines',
                                    'lines1',
                                    'lines2',
                                    'bars',
                                    'bars1',
                                    'bars2',
                                    'stack1',
                                    'stack2',
                                    'stacked',
                                    'multibar',
                                    'discretebar',
                                    'pie',
                                    'scatter',
                                    'bullet',
                                    'sparkline',
                                    'legend',
                                    'distX',
                                    'distY',
                                    'xAxis',
                                    'x2Axis',
                                    'yAxis',
                                    'yAxis1',
                                    'yAxis2',
                                    'y1Axis',
                                    'y2Axis',
                                    'y3Axis',
                                    'y4Axis',
                                    'interactiveLayer',
                                    'controls'
                                ].indexOf(key) >= 0){
                                    if (options.chart[key] === undefined || options.chart[key] === null) {
                                        if (scope._config.extended) options.chart[key] = {};
                                    }
                                    configure(scope.chart[key], options.chart[key], options.chart.type);
                                }

                                //TODO: need to fix bug in nvd3
                                else if ((key === 'xTickFormat' || key === 'yTickFormat') && options.chart.type === 'lineWithFocusChart');

                                else if (options.chart[key] === undefined || options.chart[key] === null){
                                    if (scope._config.extended) options.chart[key] = value();
                                }

                                else scope.chart[key](options.chart[key]);
                            });

                            // Update with data
                            scope.api.updateWithData(scope.data);

                            // Configure wrappers
                            if (options['title'] || scope._config.extended) configureWrapper('title');
                            if (options['subtitle'] || scope._config.extended) configureWrapper('subtitle');
                            if (options['caption'] || scope._config.extended) configureWrapper('caption');

                            // Configure styles
                            if (options['styles'] || scope._config.extended) configureStyles();

                            nv.addGraph(function() {
                                // Update the chart when window resizes
                                scope.chart.resizeHandler = nv.utils.windowResize(function() { scope.chart.update(); });
                                return scope.chart;
                            }, options.chart['callback']);
                        },

                        // Update chart with new data
                        updateWithData: function (data){
                            if (data) {
                                scope.options.chart['transitionDuration'] = +scope.options.chart['transitionDuration'] || 250;
                                // remove whole svg element with old data
                                d3.select(element[0]).select('svg').remove();

                                // Select the current element to add <svg> element and to render the chart in
                                d3.select(element[0]).append('svg')
                                    .attr('height', scope.options.chart.height)
                                    .attr('width', scope.options.chart.width  || '100%')
                                    .datum(data)
                                    .transition().duration(scope.options.chart['transitionDuration'])
                                    .call(scope.chart);
                            }
                        },

                        // Fully clear directive element
                        clearElement: function (){
                            element.find('.title').remove();
                            element.find('.subtitle').remove();
                            element.find('.caption').remove();
                            element.empty();
                            if (scope.chart) {
                                // clear window resize event handler
                                if (scope.chart.resizeHandler) scope.chart.resizeHandler.clear();

                                // remove chart from nv.graph list
                                for (var i = 0; i < nv.graphs.length; i++)
                                    if (nv.graphs[i].id === scope.chart.id) {
                                        nv.graphs.splice(i, 1);
                                    }
                            }
                            scope.chart = null;
                            nv.tooltip.cleanup();
                        },

                        // Get full directive scope
                        getScope: function(){ return scope; }
                    };

                    // Configure the chart model with the passed options
                    function configure(chart, options, chartType){
                        if (chart && options){
                            angular.forEach(chart, function(value, key){
                                if (key === 'dispatch') {
                                    if (options[key] === undefined || options[key] === null) {
                                        if (scope._config.extended) options[key] = {};
                                    }
                                    configureEvents(value, options[key]);
                                }
                                else if ([
                                    'scatter',
                                    'defined',
                                    'options',
                                    'axis',
                                    'rangeBand',
                                    'rangeBands',
                                    '_options',
                                    '_inherited',
                                    '_d3options',
                                    '_calls'
                                ].indexOf(key) < 0){
                                    if (options[key] === undefined || options[key] === null){
                                        if (scope._config.extended) options[key] = value();
                                    }
                                    else chart[key](options[key]);
                                }
                            });
                        }
                    }

                    // Subscribe to the chart events (contained in 'dispatch')
                    // and pass eventHandler functions in the 'options' parameter
                    function configureEvents(dispatch, options){
                        if (dispatch && options){
                            angular.forEach(dispatch, function(value, key){
                                if (options[key] === undefined || options[key] === null){
                                    if (scope._config.extended) options[key] = value.on;
                                }
                                else dispatch.on(key + '._', options[key]);
                            });
                        }
                    }

                    // Configure 'title', 'subtitle', 'caption'.
                    // nvd3 has no sufficient models for it yet.
                    function configureWrapper(name){
                        var _ = utils.deepExtend(defaultWrapper(name), scope.options[name] || {});

                        if (scope._config.extended) scope.options[name] = _;

                        var wrapElement = angular.element('

').html(_['html'] || '')
                            .addClass(name).addClass(_.class)
                            .removeAttr('style')
                            .css(_.css);

                        if (!_['html']) wrapElement.text(_.text);

                        if (_.enable) {
                            if (name === 'title') element.prepend(wrapElement);
                            else if (name === 'subtitle') element.find('.title').after(wrapElement);
                            else if (name === 'caption') element.append(wrapElement);
                        }
                    }

                    // Add some styles to the whole directive element
                    function configureStyles(){
                        var _ = utils.deepExtend(defaultStyles(), scope.options['styles'] || {});

                        if (scope._config.extended) scope.options['styles'] = _;

                        angular.forEach(_.classes, function(value, key){
                            value ? element.addClass(key) : element.removeClass(key);
                        });

                        element.removeAttr('style').css(_.css);
                    }

                    // Default values for 'title', 'subtitle', 'caption'
                    function defaultWrapper(_){
                        switch (_){
                            case 'title': return {
                                enable: false,
                                text: 'Write Your Title',
                                class: 'h4',
                                css: {
                                    width: scope.options.chart.width + 'px',
                                    textAlign: 'center'
                                }
                            };
                            case 'subtitle': return {
                                enable: false,
                                text: 'Write Your Subtitle',
                                css: {
                                    width: scope.options.chart.width + 'px',
                                    textAlign: 'center'
                                }
                            };
                            case 'caption': return {
                                enable: false,
                                text: 'Figure 1. Write Your Caption text.',
                                css: {
                                    width: scope.options.chart.width + 'px',
                                    textAlign: 'center'
                                }
                            };
                        }
                    }

                    // Default values for styles
                    function defaultStyles(){
                        return {
                            classes: {
                                'with-3d-shadow': true,
                                'with-transitions': true,
                                'gallery': false
                            },
                            css: {}
                        };
                    }

                    /* Event Handling */
                    // Watching on options changing
                    scope.$watch('options', utils.debounce(function(newOptions){
                        if (!scope._config.disabled && scope._config.autorefresh) scope.api.refresh();
                    }, scope._config.debounce, true), true);

                    // Watching on data changing
                    scope.$watch('data', function(newData, oldData){
                        if (newData !== oldData && scope.chart){
                            if (!scope._config.disabled && scope._config.autorefresh) {
                                scope._config.refreshDataOnly ? scope.chart.update() : scope.api.refresh(); // if wanted to refresh data only, use chart.update method, otherwise use full refresh.
                            }
                        }
                    }, scope._config.deepWatchData);

                    // Watching on config changing
                    scope.$watch('config', function(newConfig, oldConfig){
                        if (newConfig !== oldConfig){
                            scope._config = angular.extend(defaultConfig, newConfig);
                            scope.api.refresh();
                        }
                    }, true);

                    //subscribe on global events
                    angular.forEach(scope.events, function(eventHandler, event){
                        scope.$on(event, function(e){
                            return eventHandler(e, scope);
                        });
                    });

                    // remove completely when directive is destroyed
                    element.on('$destroy', function () {
                        scope.api.clearElement();
                    });
                }
            };
        }])

        .factory('utils', function(){
            return {
                debounce: function(func, wait, immediate) {
                    var timeout;
                    return function() {
                        var context = this, args = arguments;
                        var later = function() {
                            timeout = null;
                            if (!immediate) func.apply(context, args);
                        };
                        var callNow = immediate && !timeout;
                        clearTimeout(timeout);
                        timeout = setTimeout(later, wait);
                        if (callNow) func.apply(context, args);
                    };
                },
                deepExtend: function(dst){
                    var me = this;
                    angular.forEach(arguments, function(obj) {
                        if (obj !== dst) {
                            angular.forEach(obj, function(value, key) {
                                if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
                                    me.deepExtend(dst[key], value);
                                } else {
                                    dst[key] = value;
                                }
                            });
                        }
                    });
                    return dst;
                }
            };
        });
})();<commit_msg>fix(angular-nvd3): remove usage of reserved word: `class`<commit_after>(function(){

    'use strict';

    angular.module('nvd3', [])

        .directive('nvd3', ['utils', function(utils){
            return {
                restrict: 'AE',
                scope: {
                    data: '=',      //chart data, [required]
                    options: '=',   //chart options, according to nvd3 core api, [required]
                    api: '=?',      //directive global api, [optional]
                    events: '=?',   //global events that directive would subscribe to, [optional]
                    config: '=?'    //global directive configuration, [optional]
                },
                link: function(scope, element, attrs){
                    var defaultConfig = {
                        extended: false,
                        visible: true,
                        disabled: false,
                        autorefresh: true,
                        refreshDataOnly: false,
                        deepWatchData: true,
                        debounce: 10 // default 10ms, time silence to prevent refresh while multiple options changes at a time
                    };

                    //basic directive configuration
                    scope._config = angular.extend(defaultConfig, scope.config);

                    //directive global api
                    scope.api = {
                        // Fully refresh directive
                        refresh: function(){
                            scope.api.updateWithOptions(scope.options);
                        },

                        // Update chart layout (for example if container is resized)
                        update: function() {
                            scope.chart.update();
                        },

                        // Update chart with new options
                        updateWithOptions: function(options){
                            // Clearing
                            scope.api.clearElement();

                            // Exit if options are not yet bound
                            if (angular.isDefined(options) === false) return;

                            // Exit if chart is hidden
                            if (!scope._config.visible) return;

                            // Initialize chart with specific type
                            scope.chart = nv.models[options.chart.type]();

                            // Generate random chart ID
                            scope.chart.id = Math.random().toString(36).substr(2, 15);

                            angular.forEach(scope.chart, function(value, key){
                                if ([
                                    'options',
                                    '_options',
                                    '_inherited',
                                    '_d3options',
                                    'state',
                                    'id',
                                    'resizeHandler'
                                ].indexOf(key) >= 0);

                                else if (key === 'dispatch') {
                                    if (options.chart[key] === undefined || options.chart[key] === null) {
                                        if (scope._config.extended) options.chart[key] = {};
                                    }
                                    configureEvents(scope.chart[key], options.chart[key]);
                                }

                                else if ([
                                    'lines',
                                    'lines1',
                                    'lines2',
                                    'bars',
                                    'bars1',
                                    'bars2',
                                    'stack1',
                                    'stack2',
                                    'stacked',
                                    'multibar',
                                    'discretebar',
                                    'pie',
                                    'scatter',
                                    'bullet',
                                    'sparkline',
                                    'legend',
                                    'distX',
                                    'distY',
                                    'xAxis',
                                    'x2Axis',
                                    'yAxis',
                                    'yAxis1',
                                    'yAxis2',
                                    'y1Axis',
                                    'y2Axis',
                                    'y3Axis',
                                    'y4Axis',
                                    'interactiveLayer',
                                    'controls'
                                ].indexOf(key) >= 0){
                                    if (options.chart[key] === undefined || options.chart[key] === null) {
                                        if (scope._config.extended) options.chart[key] = {};
                                    }
                                    configure(scope.chart[key], options.chart[key], options.chart.type);
                                }

                                //TODO: need to fix bug in nvd3
                                else if ((key === 'xTickFormat' || key === 'yTickFormat') && options.chart.type === 'lineWithFocusChart');

                                else if (options.chart[key] === undefined || options.chart[key] === null){
                                    if (scope._config.extended) options.chart[key] = value();
                                }

                                else scope.chart[key](options.chart[key]);
                            });

                            // Update with data
                            scope.api.updateWithData(scope.data);

                            // Configure wrappers
                            if (options['title'] || scope._config.extended) configureWrapper('title');
                            if (options['subtitle'] || scope._config.extended) configureWrapper('subtitle');
                            if (options['caption'] || scope._config.extended) configureWrapper('caption');

                            // Configure styles
                            if (options['styles'] || scope._config.extended) configureStyles();

                            nv.addGraph(function() {
                                // Update the chart when window resizes
                                scope.chart.resizeHandler = nv.utils.windowResize(function() { scope.chart.update(); });
                                return scope.chart;
                            }, options.chart['callback']);
                        },

                        // Update chart with new data
                        updateWithData: function (data){
                            if (data) {
                                scope.options.chart['transitionDuration'] = +scope.options.chart['transitionDuration'] || 250;
                                // remove whole svg element with old data
                                d3.select(element[0]).select('svg').remove();

                                // Select the current element to add <svg> element and to render the chart in
                                d3.select(element[0]).append('svg')
                                    .attr('height', scope.options.chart.height)
                                    .attr('width', scope.options.chart.width  || '100%')
                                    .datum(data)
                                    .transition().duration(scope.options.chart['transitionDuration'])
                                    .call(scope.chart);
                            }
                        },

                        // Fully clear directive element
                        clearElement: function (){
                            element.find('.title').remove();
                            element.find('.subtitle').remove();
                            element.find('.caption').remove();
                            element.empty();
                            if (scope.chart) {
                                // clear window resize event handler
                                if (scope.chart.resizeHandler) scope.chart.resizeHandler.clear();

                                // remove chart from nv.graph list
                                for (var i = 0; i < nv.graphs.length; i++)
                                    if (nv.graphs[i].id === scope.chart.id) {
                                        nv.graphs.splice(i, 1);
                                    }
                            }
                            scope.chart = null;
                            nv.tooltip.cleanup();
                        },

                        // Get full directive scope
                        getScope: function(){ return scope; }
                    };

                    // Configure the chart model with the passed options
                    function configure(chart, options, chartType){
                        if (chart && options){
                            angular.forEach(chart, function(value, key){
                                if (key === 'dispatch') {
                                    if (options[key] === undefined || options[key] === null) {
                                        if (scope._config.extended) options[key] = {};
                                    }
                                    configureEvents(value, options[key]);
                                }
                                else if ([
                                    'scatter',
                                    'defined',
                                    'options',
                                    'axis',
                                    'rangeBand',
                                    'rangeBands',
                                    '_options',
                                    '_inherited',
                                    '_d3options',
                                    '_calls'
                                ].indexOf(key) < 0){
                                    if (options[key] === undefined || options[key] === null){
                                        if (scope._config.extended) options[key] = value();
                                    }
                                    else chart[key](options[key]);
                                }
                            });
                        }
                    }

                    // Subscribe to the chart events (contained in 'dispatch')
                    // and pass eventHandler functions in the 'options' parameter
                    function configureEvents(dispatch, options){
                        if (dispatch && options){
                            angular.forEach(dispatch, function(value, key){
                                if (options[key] === undefined || options[key] === null){
                                    if (scope._config.extended) options[key] = value.on;
                                }
                                else dispatch.on(key + '._', options[key]);
                            });
                        }
                    }

                    // Configure 'title', 'subtitle', 'caption'.
                    // nvd3 has no sufficient models for it yet.
                    function configureWrapper(name){
                        var _ = utils.deepExtend(defaultWrapper(name), scope.options[name] || {});

                        if (scope._config.extended) scope.options[name] = _;

                        var wrapElement = angular.element('

').html(_['html'] || '')
                            .addClass(name).addClass(_.className)
                            .removeAttr('style')
                            .css(_.css);

                        if (!_['html']) wrapElement.text(_.text);

                        if (_.enable) {
                            if (name === 'title') element.prepend(wrapElement);
                            else if (name === 'subtitle') element.find('.title').after(wrapElement);
                            else if (name === 'caption') element.append(wrapElement);
                        }
                    }

                    // Add some styles to the whole directive element
                    function configureStyles(){
                        var _ = utils.deepExtend(defaultStyles(), scope.options['styles'] || {});

                        if (scope._config.extended) scope.options['styles'] = _;

                        angular.forEach(_.classes, function(value, key){
                            value ? element.addClass(key) : element.removeClass(key);
                        });

                        element.removeAttr('style').css(_.css);
                    }

                    // Default values for 'title', 'subtitle', 'caption'
                    function defaultWrapper(_){
                        switch (_){
                            case 'title': return {
                                enable: false,
                                text: 'Write Your Title',
                                className: 'h4',
                                css: {
                                    width: scope.options.chart.width + 'px',
                                    textAlign: 'center'
                                }
                            };
                            case 'subtitle': return {
                                enable: false,
                                text: 'Write Your Subtitle',
                                css: {
                                    width: scope.options.chart.width + 'px',
                                    textAlign: 'center'
                                }
                            };
                            case 'caption': return {
                                enable: false,
                                text: 'Figure 1. Write Your Caption text.',
                                css: {
                                    width: scope.options.chart.width + 'px',
                                    textAlign: 'center'
                                }
                            };
                        }
                    }

                    // Default values for styles
                    function defaultStyles(){
                        return {
                            classes: {
                                'with-3d-shadow': true,
                                'with-transitions': true,
                                'gallery': false
                            },
                            css: {}
                        };
                    }

                    /* Event Handling */
                    // Watching on options changing
                    scope.$watch('options', utils.debounce(function(newOptions){
                        if (!scope._config.disabled && scope._config.autorefresh) scope.api.refresh();
                    }, scope._config.debounce, true), true);

                    // Watching on data changing
                    scope.$watch('data', function(newData, oldData){
                        if (newData !== oldData && scope.chart){
                            if (!scope._config.disabled && scope._config.autorefresh) {
                                scope._config.refreshDataOnly ? scope.chart.update() : scope.api.refresh(); // if wanted to refresh data only, use chart.update method, otherwise use full refresh.
                            }
                        }
                    }, scope._config.deepWatchData);

                    // Watching on config changing
                    scope.$watch('config', function(newConfig, oldConfig){
                        if (newConfig !== oldConfig){
                            scope._config = angular.extend(defaultConfig, newConfig);
                            scope.api.refresh();
                        }
                    }, true);

                    //subscribe on global events
                    angular.forEach(scope.events, function(eventHandler, event){
                        scope.$on(event, function(e){
                            return eventHandler(e, scope);
                        });
                    });

                    // remove completely when directive is destroyed
                    element.on('$destroy', function () {
                        scope.api.clearElement();
                    });
                }
            };
        }])

        .factory('utils', function(){
            return {
                debounce: function(func, wait, immediate) {
                    var timeout;
                    return function() {
                        var context = this, args = arguments;
                        var later = function() {
                            timeout = null;
                            if (!immediate) func.apply(context, args);
                        };
                        var callNow = immediate && !timeout;
                        clearTimeout(timeout);
                        timeout = setTimeout(later, wait);
                        if (callNow) func.apply(context, args);
                    };
                },
                deepExtend: function(dst){
                    var me = this;
                    angular.forEach(arguments, function(obj) {
                        if (obj !== dst) {
                            angular.forEach(obj, function(value, key) {
                                if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
                                    me.deepExtend(dst[key], value);
                                } else {
                                    dst[key] = value;
                                }
                            });
                        }
                    });
                    return dst;
                }
            };
        });
})();<|endoftext|>