<commit_before>var assert = require('assert')
var fs = require('fs')
var path = require('path')
var level = require('level')
var hyperdrive = require('hyperdrive')
var raf = require('random-access-file')
var encoding = require('dat-encoding')
var debug = require('debug')('dat-node')

module.exports = function (opts, cb) {
  assert.ok(opts, 'lib/init-archive opts required')
  assert.ok(opts.dir, 'dir option required')
  assert.ok(typeof cb === 'function', 'lib/init-archive callback function required')

  var archive
  var drive
  var db
  var dir = opts.dir
  var dbPath = opts.dbPath || path.join(dir, '.dat')
  var createIfMissing = opts.createIfMissing === false ? opts.createIfMissing : true
  var errorIfExists = opts.errorIfExists || false

  // opts.resume backwards compat. TODO: Remove in v2
  if (opts.resume) createIfMissing = false
  if (opts.resume === false) errorIfExists = true

  if (!opts.file) {
    // TODO: do we always want this set?
    opts.file = function (name, opts) {
      return raf(path.join(dir, name), opts && typeof opts.length === 'number' && {length: opts.length})
    }
  }

  if (opts.db || opts.drive) {
    drive = opts.drive || hyperdrive(opts.db)
    db = opts.db ? opts.db : drive.core._db
    return checkDriveKeys()
  }

  if (createIfMissing !== false) return createDb()

  try {
    // check if existing dbPath
    if (!fs.statSync(dbPath).isDirectory()) throw new Error('No existing .dat folder')
    return createDb()
  } catch (e) {
    return cb(e)
  }

  function createDb () {
    debug('Making/Reading archive database')
    level(dbPath, function (err, _db) {
      if (err) return cb(err)
      db = _db
      drive = hyperdrive(db)
      checkDriveKeys()
    })
  }

  function checkDriveKeys () {
    // Try to resume archives if there are keys in the drive
    debug('Reading existing keys in drive')
    drive.core.list(function (err, vals) {
      if (err) return cb(err)
      if (vals.length > 2 && !opts.key) return cb(new Error('Drive has multiple archives. Must specify key.'))
      else if (errorIfExists && vals.length) {
        return db.close(function () {
          cb(new Error('Existing feeds in database.'))
        })
      } else if (!vals.length || opts.key) {
        if (!vals.length) debug('No existing feeds in drive')
        if (opts.key) debug('Resuming using key option', opts.key)
        if (opts.key && typeof opts.key === 'string') opts.key = encoding.toBuf(opts.key)
        archive = drive.createArchive(opts.key, opts)
        archive.resumed = false
        return doneArchive(!vals.length && opts.key) // do not open if new drive and external key (e.g. downloading)
      }
      debug(`Drive has ${vals.length} existing keys. Getting archive key.`)

      // Try to guess metadata and maybe fail
      debug('Making archive with key', vals[vals.length - 1].toString('hex'))
      archive = drive.createArchive(vals[vals.length - 1], opts)
      var openTimeout = setTimeout(function () {
        debug('Timeout Open')
        tryOtherKey()
      }, 150)
      archive.open(function (err) {
        clearTimeout(openTimeout)
        if (!err) return doneArchive()
        var badKey = err && (err.message.indexOf('Unknown message type') > -1 || err.message.indexOf('Key not found in database') > -1)
        if (err & !badKey) return cb(err)
        tryOtherKey()
      })

      function tryOtherKey () {
        debug('Bad Key. Trying other key.')
        archive = drive.createArchive(vals[0], opts)
        doneArchive()
      }
    })
  }

  function doneArchive (doNotOpen) {
    debug('Archive created')
    // doNotOpen = true if no existing feeds in drive
    // Opening would have to wait for swarm connection
    if (doNotOpen) return cb(null, archive, db)

    if (archive.resumed !== false) archive.resumed = true

    if (archive.key) debug('Opening archive', archive.key.toString('hex'))
    else debug('Opening snapshot archive')
    archive.open(function (err) {
      if (err) return cb(err)
      debug('Archive opened')
      cb(null, archive, db)
    })
  }
}
<commit_msg>fix error message for no .dat folder<commit_after>var assert = require('assert')
var fs = require('fs')
var path = require('path')
var level = require('level')
var hyperdrive = require('hyperdrive')
var raf = require('random-access-file')
var encoding = require('dat-encoding')
var debug = require('debug')('dat-node')

module.exports = function (opts, cb) {
  assert.ok(opts, 'lib/init-archive opts required')
  assert.ok(opts.dir, 'dir option required')
  assert.ok(typeof cb === 'function', 'lib/init-archive callback function required')

  var archive
  var drive
  var db
  var dir = opts.dir
  var dbPath = opts.dbPath || path.join(dir, '.dat')
  var createIfMissing = opts.createIfMissing === false ? opts.createIfMissing : true
  var errorIfExists = opts.errorIfExists || false

  // opts.resume backwards compat. TODO: Remove in v2
  if (opts.resume) createIfMissing = false
  if (opts.resume === false) errorIfExists = true

  if (!opts.file) {
    // TODO: do we always want this set?
    opts.file = function (name, opts) {
      return raf(path.join(dir, name), opts && typeof opts.length === 'number' && {length: opts.length})
    }
  }

  if (opts.db || opts.drive) {
    drive = opts.drive || hyperdrive(opts.db)
    db = opts.db ? opts.db : drive.core._db
    return checkDriveKeys()
  }

  if (createIfMissing !== false) return createDb()

  try {
    // check if existing dbPath
    if (!fs.statSync(dbPath).isDirectory()) throw new Error('.dat folder not a dir')
    return createDb()
  } catch (e) {
    return cb('No existing .dat folder')
  }

  function createDb () {
    debug('Making/Reading archive database')
    level(dbPath, function (err, _db) {
      if (err) return cb(err)
      db = _db
      drive = hyperdrive(db)
      checkDriveKeys()
    })
  }

  function checkDriveKeys () {
    // Try to resume archives if there are keys in the drive
    debug('Reading existing keys in drive')
    drive.core.list(function (err, vals) {
      if (err) return cb(err)
      if (vals.length > 2 && !opts.key) return cb(new Error('Drive has multiple archives. Must specify key.'))
      else if (errorIfExists && vals.length) {
        return db.close(function () {
          cb(new Error('Existing feeds in database.'))
        })
      } else if (!vals.length || opts.key) {
        if (!vals.length) debug('No existing feeds in drive')
        if (opts.key) debug('Resuming using key option', opts.key)
        if (opts.key && typeof opts.key === 'string') opts.key = encoding.toBuf(opts.key)
        archive = drive.createArchive(opts.key, opts)
        archive.resumed = false
        return doneArchive(!vals.length && opts.key) // do not open if new drive and external key (e.g. downloading)
      }
      debug(`Drive has ${vals.length} existing keys. Getting archive key.`)

      // Try to guess metadata and maybe fail
      debug('Making archive with key', vals[vals.length - 1].toString('hex'))
      archive = drive.createArchive(vals[vals.length - 1], opts)
      var openTimeout = setTimeout(function () {
        debug('Timeout Open')
        tryOtherKey()
      }, 150)
      archive.open(function (err) {
        clearTimeout(openTimeout)
        if (!err) return doneArchive()
        var badKey = err && (err.message.indexOf('Unknown message type') > -1 || err.message.indexOf('Key not found in database') > -1)
        if (err & !badKey) return cb(err)
        tryOtherKey()
      })

      function tryOtherKey () {
        debug('Bad Key. Trying other key.')
        archive = drive.createArchive(vals[0], opts)
        doneArchive()
      }
    })
  }

  function doneArchive (doNotOpen) {
    debug('Archive created')
    // doNotOpen = true if no existing feeds in drive
    // Opening would have to wait for swarm connection
    if (doNotOpen) return cb(null, archive, db)

    if (archive.resumed !== false) archive.resumed = true

    if (archive.key) debug('Opening archive', archive.key.toString('hex'))
    else debug('Opening snapshot archive')
    archive.open(function (err) {
      if (err) return cb(err)
      debug('Archive opened')
      cb(null, archive, db)
    })
  }
}
<|endoftext|>


<commit_before>/*global System, before, after, beforeEach, afterEach, describe, it*/

import { expect } from "mocha-es6";

import { removeDir, createFiles } from "./helpers.js";

import { getSystem, searchLoadedModules, loadedModules } from "../src/system.js";
import mod from "../src/module.js";
import { importPackage, removePackage, searchInPackage } from "../src/packages.js";

const dir = System.decanonicalize("lively.modules/tests/"),
      testProjectDir = dir + "search-test-project/",
      testProjectSpec = {
        "file1.js": "import { y } from './file2.js';\nexport var x = 'hello';",
        "file2.js": "export var y = 'world'; // comment",
        "package.json": '{"name":"search-test-project","main":"file1.js"}'
      },
      file1m = testProjectDir + "file1.js",
      file2m = testProjectDir + "file2.js";

describe("search", () => {

  let S, module1, module2;
  before(async () => {
    S = getSystem("test", {baseURL: dir});
    module1 = mod(S, file1m);
    module2 = mod(S, file2m);
    await createFiles(testProjectDir, testProjectSpec);
  });

  after(async () => {
    await removeDir(testProjectDir);
  });

  describe("in modules", () => {

    it("finds string constants", async () => {
      const res = await module1.search("hello");
      expect(res).to.containSubset([{
        moduleId: file1m,
        pathInPackage: "./file1.js",
        packageName: "search-test-project",
        lineString: "export var x = 'hello';",
        line: 2,
        column: 16,
        length: 5
      }]);
    });

    it("finds comments", async () => {
      const res = await module2.search("comment");
      expect(res).to.containSubset([{
        moduleId: file2m,
        lineString: "export var y = 'world'; // comment",
        line: 1,
        column: 27,
        length: 7
      }]);
    });

    describe("by regex", () => {
      it("finds comments", async () => {
        const res = await module1.search(/(im|ex)port/);
        expect(res).to.containSubset([{
          moduleId: file1m,
          line: 1,
          column: 0,
          length: 6
        }, {
          moduleId: file1m,
          line: 2,
          column: 0,
          length: 6
        }]);
      });
    });
  });

  describe("in all loaded modules", () => {

    it("does not find unloaded string constants", async () => {
      module1.unload(); module2.unload();
      const res = await searchLoadedModules(S, "hello");
      expect(res).to.containSubset([]);
    });

    it("finds string constants", async () => {
      await S.import(file1m);
      const res = await searchLoadedModules(S, "hello");
      expect(res).to.containSubset([{
        moduleId: file1m,
        line: 2,
        column: 16,
        length: 5
      }]);
    });

    it("finds comments", async () => {
      await S.import(file1m);
      const res = await searchLoadedModules(S, "comment");
      expect(res).to.containSubset([{
        moduleId: file2m,
        line: 1,
        column: 27,
        length: 7
      }]);
    });

    it("finds syntax", async () => {
      await S.import(file1m);
      await S.import(file2m);
      const res = await searchLoadedModules(S, "export");
      expect(res).to.containSubset([{
        moduleId: file1m,
        line: 2,
        column: 0,
        length: 6
      },{
        moduleId: file2m,
        line: 1,
        column: 0,
        length: 6
      }]);
    });

    describe("by regex", () => {
      it("finds comments", async () => {
        const res = await searchLoadedModules(S, /(im|ex)port/);
        expect(res).to.containSubset([{
          moduleId: file1m,
          line: 1,
          column: 0,
          length: 6
        }, {
          moduleId: file1m,
          line: 2,
          column: 0,
          length: 6
        }, {
          moduleId: file2m,
          line: 1,
          column: 0,
          length: 6
        }]);
      });
    });

    describe("can exclude modules", () => {
      it("finds comments", async () => {
        const res = await searchLoadedModules(S, /(im|ex)port/, {excludedModules: [file1m]});
        expect(res).to.have.length(1);
        expect(res).to.containSubset([
          {moduleId: file2m, line: 1, column: 0, length: 6}]);
      });
    });
  });

  describe("in packages", () => {

    beforeEach(async () => await importPackage(S, testProjectDir));
    afterEach(async () => await removePackage(S, testProjectDir));

    it("finds string constants", async () => {
      const res = await searchInPackage(S, testProjectDir, "hello");
      expect(res).to.containSubset([{
        moduleId: file1m,
        line: 2,
        column: 16,
        length: 5
      }]);
    });

    it("finds comments", async () => {
      const res = await searchInPackage(S, testProjectDir, "comment");
      expect(res).to.containSubset([{
        moduleId: file2m,
        line: 1,
        column: 27,
        length: 7
      }]);
    });

    describe("by regex", () => {
      it("finds comments", async () => {
        const res = await searchInPackage(S, testProjectDir, /(im|ex)port/);
        expect(res).to.containSubset([{
          moduleId: file1m,
          line: 1,
          column: 0,
          length: 6
        }, {
          moduleId: file1m,
          line: 2,
          column: 0,
          length: 6
        }, {
          moduleId: file2m,
          line: 1,
          column: 0,
          length: 6
        }]);
      });
    });

    it("can exclude modules", async () => {
      const res = await searchInPackage(S, testProjectDir, /(im|ex)port/, {excludedModules: [file1m]});
      expect(res).to.have.length(1);
      expect(res).to.containSubset([
        {moduleId: file2m, line: 1, column: 0, length: 6}]);
    });

    it("can exclude modules via regex matches", async () => {
      const res = await searchInPackage(S, testProjectDir, /(im|ex)port/, {excludedModules: [/file1.js/]});
      expect(res).to.have.length(1);
      expect(res).to.containSubset([
        {moduleId: file2m, line: 1, column: 0, length: 6}]);
    });

  });

});<commit_msg>test fix<commit_after>/*global System, before, after, beforeEach, afterEach, describe, it*/

import { expect } from "mocha-es6";

import { removeDir, createFiles } from "./helpers.js";

import { getSystem, searchLoadedModules, loadedModules } from "../src/system.js";
import mod from "../src/module.js";
import { importPackage, removePackage, searchInPackage } from "../src/packages.js";

const dir = System.decanonicalize("lively.modules/tests/"),
      testProjectDir = dir + "search-test-project/",
      testProjectSpec = {
        "file1.js": "import { y } from './file2.js';\nexport var x = 'hello';",
        "file2.js": "export var y = 'world'; // comment",
        "package.json": '{"name":"search-test-project","main":"file1.js"}'
      },
      file1m = testProjectDir + "file1.js",
      file2m = testProjectDir + "file2.js";

describe("search", () => {

  let S, module1, module2;
  before(async () => {
    S = getSystem("test", {baseURL: dir});
    module1 = mod(S, file1m);
    module2 = mod(S, file2m);
    await createFiles(testProjectDir, testProjectSpec);
  });

  after(async () => {
    await removeDir(testProjectDir);
  });

  describe("in modules", () => {

    it("finds string constants", async () => {
      const res = await module1.search("hello");
      expect(res).to.containSubset([{
        moduleId: file1m,
        lineString: "export var x = 'hello';",
        line: 2,
        column: 16,
        length: 5
      }]);
    });

    it("finds comments", async () => {
      const res = await module2.search("comment");
      expect(res).to.containSubset([{
        moduleId: file2m,
        lineString: "export var y = 'world'; // comment",
        line: 1,
        column: 27,
        length: 7
      }]);
    });

    describe("by regex", () => {
      it("finds comments", async () => {
        const res = await module1.search(/(im|ex)port/);
        expect(res).to.containSubset([{
          moduleId: file1m,
          line: 1,
          column: 0,
          length: 6
        }, {
          moduleId: file1m,
          line: 2,
          column: 0,
          length: 6
        }]);
      });
    });
  });

  describe("in all loaded modules", () => {

    it("does not find unloaded string constants", async () => {
      module1.unload(); module2.unload();
      const res = await searchLoadedModules(S, "hello");
      expect(res).to.containSubset([]);
    });

    it("finds string constants", async () => {
      await S.import(file1m);
      const res = await searchLoadedModules(S, "hello");
      expect(res).to.containSubset([{
        moduleId: file1m,
        line: 2,
        column: 16,
        length: 5
      }]);
    });

    it("finds comments", async () => {
      await S.import(file1m);
      const res = await searchLoadedModules(S, "comment");
      expect(res).to.containSubset([{
        moduleId: file2m,
        line: 1,
        column: 27,
        length: 7
      }]);
    });

    it("finds syntax", async () => {
      await S.import(file1m);
      await S.import(file2m);
      const res = await searchLoadedModules(S, "export");
      expect(res).to.containSubset([{
        moduleId: file1m,
        line: 2,
        column: 0,
        length: 6
      },{
        moduleId: file2m,
        line: 1,
        column: 0,
        length: 6
      }]);
    });

    describe("by regex", () => {
      it("finds comments", async () => {
        const res = await searchLoadedModules(S, /(im|ex)port/);
        expect(res).to.containSubset([{
          moduleId: file1m,
          line: 1,
          column: 0,
          length: 6
        }, {
          moduleId: file1m,
          line: 2,
          column: 0,
          length: 6
        }, {
          moduleId: file2m,
          line: 1,
          column: 0,
          length: 6
        }]);
      });
    });

    describe("can exclude modules", () => {
      it("finds comments", async () => {
        const res = await searchLoadedModules(S, /(im|ex)port/, {excludedModules: [file1m]});
        expect(res).to.have.length(1);
        expect(res).to.containSubset([
          {moduleId: file2m, line: 1, column: 0, length: 6}]);
      });
    });
  });

  describe("in packages", () => {

    beforeEach(async () => await importPackage(S, testProjectDir));
    afterEach(async () => await removePackage(S, testProjectDir));

    it("finds string constants", async () => {
      const res = await searchInPackage(S, testProjectDir, "hello");
      expect(res).to.containSubset([{
        pathInPackage: "./file1.js",
        packageName: "search-test-project",
        moduleId: file1m,
        line: 2,
        column: 16,
        length: 5
      }]);
    });

    it("finds comments", async () => {
      const res = await searchInPackage(S, testProjectDir, "comment");
      expect(res).to.containSubset([{
        moduleId: file2m,
        line: 1,
        column: 27,
        length: 7
      }]);
    });

    describe("by regex", () => {
      it("finds comments", async () => {
        const res = await searchInPackage(S, testProjectDir, /(im|ex)port/);
        expect(res).to.containSubset([{
          moduleId: file1m,
          line: 1,
          column: 0,
          length: 6
        }, {
          moduleId: file1m,
          line: 2,
          column: 0,
          length: 6
        }, {
          moduleId: file2m,
          line: 1,
          column: 0,
          length: 6
        }]);
      });
    });

    it("can exclude modules", async () => {
      const res = await searchInPackage(S, testProjectDir, /(im|ex)port/, {excludedModules: [file1m]});
      expect(res).to.have.length(1);
      expect(res).to.containSubset([
        {moduleId: file2m, line: 1, column: 0, length: 6}]);
    });

    it("can exclude modules via regex matches", async () => {
      const res = await searchInPackage(S, testProjectDir, /(im|ex)port/, {excludedModules: [/file1.js/]});
      expect(res).to.have.length(1);
      expect(res).to.containSubset([
        {moduleId: file2m, line: 1, column: 0, length: 6}]);
    });

  });

});<|endoftext|>


<commit_before>const inquirer = require('inquirer')

module.exports = exports = (configFilename) => {
  return (env, options) => {
    const questions = [
      {
        name: 'file_exist',
        message: 'A configuration file already exist. Do you want to continue ?',
        type: 'confirm',
        when: () => fileExist(configFilename)
      },
      {
        name: 'repo_name',
        message: 'Url config file repo:',
        type: 'input',
        when: (data) => !fileExist(configFilename) || data.file_exist === true
      }
    ]

    inquirer.prompt(questions)
      .then((a) => {
        console.log(a)
      })
  }
}

function fileExist(filename) {
  try {
    fs.accessSync(configFilename)
  } catch (e) {
    return false
  }

  return true
}
<commit_msg>fix regression in init command<commit_after>const fs = require('fs')
const inquirer = require('inquirer')

module.exports = exports = (configFilename) => {
  return (env, options) => {
    const questions = [
      {
        name: 'file_exist',
        message: 'A configuration file already exist. Do you want to continue ?',
        type: 'confirm',
        when: () => fileExist(configFilename)
      },
      {
        name: 'repo_name',
        message: 'Url config file repo:',
        type: 'input',
        when: (data) => !fileExist(configFilename) || data.file_exist === true
      }
    ]

    inquirer.prompt(questions)
      .then((a) => {
        console.log(a)
      })
  }
}

function fileExist(filename) {
  try {
    fs.accessSync(filename)
  } catch (e) {
    return false
  }

  return true
}
<|endoftext|>


<commit_before>'use strict';

var Installation = require('./schema.js'),
    moment = require('moment'),
    _ = require('lodash');

var InstallationModel = function (connection, collection) {

    var model,
        schema,

        createInstallation = function (installation, user, cb) {

            //installation.updatedAt.date = moment();
            //installation.updatedAt.user = user;

            var thisInstallation = new model(installation);

            thisInstallation
                .save(function (err) {
                    if (err) {
                        cb(err, null);
                    } else {
                        cb(null, installation);
                    }
                });
        },

        allInstallations = function (cb) {

            model.find(function (err, installations) {
                if (err) {
                    cb(err, null);
                } else {
                    cb(null, installations);
                }
            });
        },

        getInstallation = function (id, cb) {

            model.findOne({_id: id}, function (err, installation) {
                if (err) {
                    cb(err, null);
                } else {
                    cb(null, installation);
                }
            });
        },

        updateInstallation = function (id, user, installation, cb) {

            installation.updatedAt.date = moment();
            installation.updatedAt.user = user;

            model.findOneAndUpdate({_id: id}, installation, function (err, installation) {
                if (err) {
                    cb(err);
                } else {
                    cb(null);
                }
            });
        },

        removeInstallation = function (id, cb) {

            model.findOneAndRemove({_id: id}, function (err) {
                if (err) {
                    cb(err);
                } else {
                    cb(null);
                }

            });

        },
        getDevice = function (deviceid, cb) {

            model.findOne({devices: {$elemMatch: {id: deviceid }}}, function (err, installation) {
                if (err) {
                    cb(err, null);
                } else {
                    if (installation) {
                        var device = _.filter(installation.devices, { 'id': deviceid })
                        cb(null, device[0]._doc);
                    } else {
                        cb(null, "Couldn't find device: " + deviceid);
                    }
                }
            });
        },

        updateTriggerValue = function (deviceid, triggerIndex, value, cb) {

            model.findOne({devices: {$elemMatch: {id: deviceid }}}, function (err, installation) {
                if (err) {
                    cb(err, null);
                } else {
                    if (installation) {
                        var index = _.findIndex(installation.devices, { 'id': deviceid })
                        if (_.isNumber(index)) {
                            var installationDoc = installation.toObject();
                            installationDoc.devices[index].triggers[triggerIndex].triggered_value = value;
                            model.update({_id: installation._id}, installationDoc, {upsert: true},function (err) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, null);
                                }
                            });
                        }
                    } else {
                        cb(null, "Couldn't find device: " + deviceid);
                    }
                }
            });
        };

    function init(connection, collection) {

        if (connection.modelNames().indexOf(collection) >= 0) {
            model = connection.model(collection);
        } else {
            schema = Installation;
            connection.model(collection, schema);
            model = connection.model(collection);
        }
    }

    init(connection, collection);

    /* Return model api */
    return {
        createInstallation: createInstallation,
        allInstallations: allInstallations,
        getInstallation: getInstallation,
        updateInstallation: updateInstallation,
        getDevice: getDevice,
        updateTriggerValue: updateTriggerValue
    };
};

module.exports = InstallationModel;
<commit_msg>remove mongo id from document before saving<commit_after>'use strict';

var Installation = require('./schema.js'),
    moment = require('moment'),
    _ = require('lodash');

var InstallationModel = function (connection, collection) {

    var model,
        schema,

        createInstallation = function (installation, user, cb) {

            //installation.updatedAt.date = moment();
            //installation.updatedAt.user = user;

            var thisInstallation = new model(installation);

            thisInstallation
                .save(function (err) {
                    if (err) {
                        cb(err, null);
                    } else {
                        cb(null, installation);
                    }
                });
        },

        allInstallations = function (cb) {

            model.find(function (err, installations) {
                if (err) {
                    cb(err, null);
                } else {
                    cb(null, installations);
                }
            });
        },

        getInstallation = function (id, cb) {

            model.findOne({_id: id}, function (err, installation) {
                if (err) {
                    cb(err, null);
                } else {
                    cb(null, installation);
                }
            });
        },

        updateInstallation = function (id, user, installation, cb) {

            installation.updatedAt.date = moment();
            installation.updatedAt.user = user;

            model.findOneAndUpdate({_id: id}, installation, function (err, installation) {
                if (err) {
                    cb(err);
                } else {
                    cb(null);
                }
            });
        },

        removeInstallation = function (id, cb) {

            model.findOneAndRemove({_id: id}, function (err) {
                if (err) {
                    cb(err);
                } else {
                    cb(null);
                }

            });

        },
        getDevice = function (deviceid, cb) {

            model.findOne({devices: {$elemMatch: {id: deviceid }}}, function (err, installation) {
                if (err) {
                    cb(err, null);
                } else {
                    if (installation) {
                        var device = _.filter(installation.devices, { 'id': deviceid })
                        cb(null, device[0]._doc);
                    } else {
                        cb(null, "Couldn't find device: " + deviceid);
                    }
                }
            });
        },

        updateTriggerValue = function (deviceid, triggerIndex, value, cb) {

            model.findOne({devices: {$elemMatch: {id: deviceid }}}, function (err, installation) {
                if (err) {
                    cb(err, null);
                } else {
                    if (installation) {
                        var index = _.findIndex(installation.devices, { 'id': deviceid })
                        if (_.isNumber(index)) {
                            var installationDoc = installation.toObject();
                            installationDoc = _.omit(installationDoc,'_id');
                            installationDoc.devices[index].triggers[triggerIndex].triggered_value = value;
                            model.update({_id: installation._id}, installationDoc, {upsert: true},function (err) {
                                if (err) {
                                    cb(err, null);
                                } else {
                                    cb(null, null);
                                }
                            });
                        }
                    } else {
                        cb(null, "Couldn't find device: " + deviceid);
                    }
                }
            });
        };

    function init(connection, collection) {

        if (connection.modelNames().indexOf(collection) >= 0) {
            model = connection.model(collection);
        } else {
            schema = Installation;
            connection.model(collection, schema);
            model = connection.model(collection);
        }
    }

    init(connection, collection);

    /* Return model api */
    return {
        createInstallation: createInstallation,
        allInstallations: allInstallations,
        getInstallation: getInstallation,
        updateInstallation: updateInstallation,
        getDevice: getDevice,
        updateTriggerValue: updateTriggerValue
    };
};

module.exports = InstallationModel;
<|endoftext|>


<commit_before>/*
 * Flushes stats to Instrumental (https://instrumentalapp.com).
 *
 * To enable this backend, include 'statsd-instrumental-backend' in the
 * backends configuration array:
 *
 *   backends: ['statsd-instrumental-backend']
 *
 * The backend will read the configuration options from the following
 * 'instrumental' hash defined in the main statsd config file:
 *
 *  instrumental : {
 *    key     : API Token for your application,
 *    host    : Instrumental server address (default: "collector.instrumentalapp.com")
 *    port    : Instrumental server port (default: 8001)
 *    timeout : Connection and read timeout (default: 10000 [10s])
 *  }
 */

// TODO: Log some internal stats (error rate, reconnect, metrics sent)

var net  = require("net"),
    util = require("util"),
    tls  = require("tls"),
    fs   = require("fs"),
    path = require("path"),
    buffering_aggregation = require("./instrumental/buffering_aggregation"),
    p    = require("./instrumental/protocol");

var debug;
var error = false;
var caChainPath = path.join("..", "certs");
var key, host, port, timeout, flushInterval, secure, verifyCert, caChain;

var instrumentalStats = {};

function build_payload(metrics, time_stamp) {
  var payload = [];
  // Iterators: key and value.
  var k, v;

  // increment item.count 200 121820381
  for(k in metrics.counters) {
    v = metrics.counters[k];

    // Skip any counters that would not change the value
    if(v !== 0) {
      payload.push(p.inc(k, v, time_stamp));
    }

    var vps = metrics.counter_rates[k];
    payload.push(p.gauge_abs([k, "rate"].join("."), vps, time_stamp));
  }

  // gauge item.time 7292 121820381
  for(k in metrics.timer_data){
    for (var timer_data_key in metrics.timer_data[k]) {
      if (typeof(metrics.timer_data[k][timer_data_key]) === 'number') {
        payload.push(p.gauge_abs([k, timer_data_key].join("."), metrics.timer_data[k][timer_data_key], time_stamp));
      } else {
        for (var timer_data_sub_key in metrics.timer_data[k][timer_data_key]) {
          v = metrics.timer_data[k][timer_data_key][timer_data_sub_key];
          if(timer_data_sub_key.indexOf("bin") == 0){
            // This is histogram data, just increment the known server values
            payload.push(p.inc([k, timer_data_sub_key].join("."), v, time_stamp));
          } else {
            payload.push(p.gauge_abs([k, timer_data_sub_key].join("."), v, time_stamp));
          }

        }
      }
    }
  }

  // gauge item.gauge 7292 121820381
  for(k in metrics.gauges) {
    payload.push(p.gauge(k, metrics.gauges[k], time_stamp));
  }

  for(k in metrics.sets) {
    payload.push(p.gauge_abs(k, metrics.sets[k].values().length, time_stamp));
  }

  // By this point in time we should have an array of commands to send to the
  // instrumental server. We'll convert that array into a string blob in the
  // appropriate protocol.
  return payload;
}

function instrumental_connection(host, port, onConnectCb){
  var connection;
  if (secure){
    connection = tls.connect({ port: port, host: host, rejectUnauthorized: verifyCert, ca: caChain }, function(){
      if(verifyCert && !connection.authorized){
        throw new Exception("Instrumental connection cannot be encrypted, certificate not secured");
      }
      onConnectCb(connection);
    });
  } else {
    connection = net.createConnection({ port: port, host: host}, onConnectCB);
  }
  // All communication with the server is done in ASCII.
  connection.setEncoding("ascii");
  return connection;
}

// Push data to instrumental
function instrumental_send(payload) {
  var state = "cold";

  var client = instrumental_connection(host, port, function(_client){
    state = "connected";

    // Write the authentication header
    _client.write(
      "hello version 1.0\n" +
      "authenticate " + key + "\n"
    );
  });

  // We need to handle the timeout. I think we should only care about read
  // timeouts. That is we write out data, if we don't hear back in timeout
  // seconds then the data probably hasn't reached the server.
  client.setTimeout(timeout, function() {
    // ZOMG FAILED WRITING WE ARE BAD AT COMPUTER SCIENCE
    if(state == "connected") {
      // We're waiting to hear back from the server and it has timed out. It's
      // unlikely that the server will suddenly wake up and send us our data so
      // lets disconnect and go shopping.
      client.end();
    }
  });

  // HOW WE HANDLE ERRORS. We should probably reconnect, maybe retry.
  client.addListener("error", function(exception){
    if(debug) {
      util.log(exception);
    }
    instrumentalStats.last_exception = Math.round(new Date().getTime() / 1000);
  });

  // What do we do when instrumental talks to us
  //
  // You know, we're early in the development cycle. We will (at most) expect
  // to receive "ok\nok\n" back from the server (ACK our header). Such a small
  // amount of data shouldn't be split into multiple packets... though I guess
  // we will find out.
  client.on("data", function(buffer) {
    if(debug) {
      util.puts("Received:", buffer);
    }

    // Authorization success
    if(buffer == "ok\nok\n") {
      error = false;

      if(debug) {
        util.puts("Sending:", payload.join("\n"));
      }

      client.end(payload.join("\n") + "\n", function() {
        state = "sent";
      });

      instrumentalStats.last_flush = Math.round(new Date().getTime() / 1000);

    // Authorization failure
    } else if(buffer == "ok\nfail\n") {
      // TODO: Actually do something with this
      error = true;

      instrumentalStats.last_exception = Math.round(new Date().getTime() / 1000);
    }
  });
}

function instrumental_flush(time_stamp, metrics) {
  if(flushInterval < 60000){
    metrics = buffering_aggregation(metrics, time_stamp, flushInterval);
  }
  var payload = build_payload(metrics, time_stamp);

  // Right now payload is at a minimum "\n"
  if(payload.length > 0) {
    instrumental_send(payload);
  }
}

function instrumental_status(writeCb) {
  for (stat in instrumentalStats) {
    writeCb(null, 'instrumental', stat, instrumentalStats[stat]);
  }
  writeCb(null, 'instrumental', 'error', error ? 1 : 0);
}

exports.init = function instrumental_init(startup_time, config, events) {
  debug = config.debug;

  if(config.instrumental) {
    key  = config.instrumental.key;
    host = config.instrumental.host || "collector.instrumentalapp.com";

    // Default 10s timeout
    timeout = Number(config.instrumental.timeout || 10000);

    if(typeof(config.instrumental.secure) == 'undefined'){
      secure = true;
    } else {
      secure = config.instrumental.secure;
    }
    if(typeof(config.instrumental.verify_cert) == 'undefined'){
      verifyCert = true;
    } else {
      verifyCert = config.instrumental.verify_cert;
    }
    if(secure && verifyCert){
      var certDir = path.join(__dirname, caChainPath);
      var certs = fs.readdirSync(certDir);
      caChain = [];
      for(var i = 0; i < certs.length; i ++){
        var certPath = path.join(certDir, certs[i]);
        caChain.push(fs.readFileSync(certPath));
      }
    }

    var defaultPort = secure ? 8001 : 8000;

    port = Number(config.instrumental.port || defaultPort);
  }

  flushInterval = config.flushInterval;

  // Check for credentials
  if(!key) {
    util.log("Missing instrumental.key from the config.");
    return false;
  }

  instrumentalStats.last_flush = startup_time;
  instrumentalStats.last_exception = startup_time;

  events.on("flush", instrumental_flush);
  events.on("status", instrumental_status);

  return true;
};
<commit_msg>hardcode certs used in the intermediate chain<commit_after>/*
 * Flushes stats to Instrumental (https://instrumentalapp.com).
 *
 * To enable this backend, include 'statsd-instrumental-backend' in the
 * backends configuration array:
 *
 *   backends: ['statsd-instrumental-backend']
 *
 * The backend will read the configuration options from the following
 * 'instrumental' hash defined in the main statsd config file:
 *
 *  instrumental : {
 *    key     : API Token for your application,
 *    host    : Instrumental server address (default: "collector.instrumentalapp.com")
 *    port    : Instrumental server port (default: 8001)
 *    timeout : Connection and read timeout (default: 10000 [10s])
 *  }
 */

// TODO: Log some internal stats (error rate, reconnect, metrics sent)

var net  = require("net"),
    util = require("util"),
    tls  = require("tls"),
    fs   = require("fs"),
    path = require("path"),
    buffering_aggregation = require("./instrumental/buffering_aggregation"),
    p    = require("./instrumental/protocol");

var debug;
var error = false;
var caChainPath = path.join("..", "certs");
var knownCerts  = ["equifax", "geotrust", "rapidssl"];
var key, host, port, timeout, flushInterval, secure, verifyCert, caChain;

var instrumentalStats = {};

function build_payload(metrics, time_stamp) {
  var payload = [];
  // Iterators: key and value.
  var k, v;

  // increment item.count 200 121820381
  for(k in metrics.counters) {
    v = metrics.counters[k];

    // Skip any counters that would not change the value
    if(v !== 0) {
      payload.push(p.inc(k, v, time_stamp));
    }

    var vps = metrics.counter_rates[k];
    payload.push(p.gauge_abs([k, "rate"].join("."), vps, time_stamp));
  }

  // gauge item.time 7292 121820381
  for(k in metrics.timer_data){
    for (var timer_data_key in metrics.timer_data[k]) {
      if (typeof(metrics.timer_data[k][timer_data_key]) === 'number') {
        payload.push(p.gauge_abs([k, timer_data_key].join("."), metrics.timer_data[k][timer_data_key], time_stamp));
      } else {
        for (var timer_data_sub_key in metrics.timer_data[k][timer_data_key]) {
          v = metrics.timer_data[k][timer_data_key][timer_data_sub_key];
          if(timer_data_sub_key.indexOf("bin") == 0){
            // This is histogram data, just increment the known server values
            payload.push(p.inc([k, timer_data_sub_key].join("."), v, time_stamp));
          } else {
            payload.push(p.gauge_abs([k, timer_data_sub_key].join("."), v, time_stamp));
          }

        }
      }
    }
  }

  // gauge item.gauge 7292 121820381
  for(k in metrics.gauges) {
    payload.push(p.gauge(k, metrics.gauges[k], time_stamp));
  }

  for(k in metrics.sets) {
    payload.push(p.gauge_abs(k, metrics.sets[k].values().length, time_stamp));
  }

  // By this point in time we should have an array of commands to send to the
  // instrumental server. We'll convert that array into a string blob in the
  // appropriate protocol.
  return payload;
}

function instrumental_connection(host, port, onConnectCb){
  var connection;
  if (secure){
    connection = tls.connect({ port: port, host: host, rejectUnauthorized: verifyCert, ca: caChain }, function(){
      if(verifyCert && !connection.authorized){
        throw new Exception("Instrumental connection cannot be encrypted, certificate not secured");
      }
      onConnectCb(connection);
    });
  } else {
    connection = net.createConnection({ port: port, host: host}, onConnectCB);
  }
  // All communication with the server is done in ASCII.
  connection.setEncoding("ascii");
  return connection;
}

// Push data to instrumental
function instrumental_send(payload) {
  var state = "cold";

  var client = instrumental_connection(host, port, function(_client){
    state = "connected";

    // Write the authentication header
    _client.write(
      "hello version 1.0\n" +
      "authenticate " + key + "\n"
    );
  });

  // We need to handle the timeout. I think we should only care about read
  // timeouts. That is we write out data, if we don't hear back in timeout
  // seconds then the data probably hasn't reached the server.
  client.setTimeout(timeout, function() {
    // ZOMG FAILED WRITING WE ARE BAD AT COMPUTER SCIENCE
    if(state == "connected") {
      // We're waiting to hear back from the server and it has timed out. It's
      // unlikely that the server will suddenly wake up and send us our data so
      // lets disconnect and go shopping.
      client.end();
    }
  });

  // HOW WE HANDLE ERRORS. We should probably reconnect, maybe retry.
  client.addListener("error", function(exception){
    if(debug) {
      util.log(exception);
    }
    instrumentalStats.last_exception = Math.round(new Date().getTime() / 1000);
  });

  // What do we do when instrumental talks to us
  //
  // You know, we're early in the development cycle. We will (at most) expect
  // to receive "ok\nok\n" back from the server (ACK our header). Such a small
  // amount of data shouldn't be split into multiple packets... though I guess
  // we will find out.
  client.on("data", function(buffer) {
    if(debug) {
      util.puts("Received:", buffer);
    }

    // Authorization success
    if(buffer == "ok\nok\n") {
      error = false;

      if(debug) {
        util.puts("Sending:", payload.join("\n"));
      }

      client.end(payload.join("\n") + "\n", function() {
        state = "sent";
      });

      instrumentalStats.last_flush = Math.round(new Date().getTime() / 1000);

    // Authorization failure
    } else if(buffer == "ok\nfail\n") {
      // TODO: Actually do something with this
      error = true;

      instrumentalStats.last_exception = Math.round(new Date().getTime() / 1000);
    }
  });
}

function instrumental_flush(time_stamp, metrics) {
  if(flushInterval < 60000){
    metrics = buffering_aggregation(metrics, time_stamp, flushInterval);
  }
  var payload = build_payload(metrics, time_stamp);

  // Right now payload is at a minimum "\n"
  if(payload.length > 0) {
    instrumental_send(payload);
  }
}

function instrumental_status(writeCb) {
  for (stat in instrumentalStats) {
    writeCb(null, 'instrumental', stat, instrumentalStats[stat]);
  }
  writeCb(null, 'instrumental', 'error', error ? 1 : 0);
}

exports.init = function instrumental_init(startup_time, config, events) {
  debug = config.debug;

  if(config.instrumental) {
    key  = config.instrumental.key;
    host = config.instrumental.host || "collector.instrumentalapp.com";

    // Default 10s timeout
    timeout = Number(config.instrumental.timeout || 10000);

    if(typeof(config.instrumental.secure) == 'undefined'){
      secure = true;
    } else {
      secure = config.instrumental.secure;
    }
    if(typeof(config.instrumental.verify_cert) == 'undefined'){
      verifyCert = true;
    } else {
      verifyCert = config.instrumental.verify_cert;
    }
    if(secure && verifyCert){
      var certDir = path.join(__dirname, caChainPath);
      caChain = [];
      for(var i = 0; i < knownCerts.length; i ++){
        var certPath = path.join(certDir, knownCerts[i] + ".ca.pem");
        caChain.push(fs.readFileSync(certPath));
      }
    }

    var defaultPort = secure ? 8001 : 8000;

    port = Number(config.instrumental.port || defaultPort);
  }

  flushInterval = config.flushInterval;

  // Check for credentials
  if(!key) {
    util.log("Missing instrumental.key from the config.");
    return false;
  }

  instrumentalStats.last_flush = startup_time;
  instrumentalStats.last_exception = startup_time;

  events.on("flush", instrumental_flush);
  events.on("status", instrumental_status);

  return true;
};
<|endoftext|>


<commit_before>'use strict';

var method = require('./../method');
var assign = require('lodash.assign');

/**
 * @memberof job
 * @method waitfor
 * @description Wait for the job with the given id to enter a certain job
 * state. This action polls the server and returns only when we detect that the job
 * has transitioned into the given state. States available are:
 *   - running
 *   - stopped
 *
 * When the callback is called, the returned object will be information about the job.
 * @param {object} params - Job waitfor parameters
 * @param {string} params.jobId - Id of the job to wait for
 * @param {string} params.state - Name of the state to wait for
 * @param {function} cb - Node-style error-first callback function
 * @returns {object} job - The job JSON object
 * @example
 * paperspace.job.waitfor({
 *   jobId: 'j123abc',
 *   state: 'stopped',
 * }, function(err, resp) {
 *   // handle error or http response
 * });
 * @example
 * $ paperspace jobs waitfor \
 *     --jobId "j123abc" \
 *     --state "stopped"
 * @example
 * # HTTP request:
 * # The waitefor method is only available using the API client.
 * # Use the show job to query the state of the job via HTTP.
 * @example
 * //Example return value:
 * {
 *   "id": "j123abc",
 *   "name": "My Job",
 *   "state": "stopped"
 * }
 */

var INTERVAL = 5000; // ms

function waitfor(params, cb) {
	if (!params.state) {
		return cb(new Error('Missing required parameter state'));
	}
	var state = ('' + params.state).toLowerCase();
	var targetState;
	switch (state) {
		case 'running':
		case 'stopped':
			targetState = state;
			break;
		default:
			console.log(state);
			return cb(new Error('state must be either running or stopped'));
	}
	return method(waitfor, params, function _cb(err, resp) {
		if (err) {
			return cb(err);
		}
		var job = resp.body;
		if (job && job.state === targetState) {
			return cb(null, resp);
		}
		var interval = setTimeout(function _interval() {
			return waitfor(params, cb);
		}, INTERVAL);
		return interval;
	});
}

assign(waitfor, {
	auth: true,
	group: 'jobs',
	name: 'waitfor',
	method: 'get',
	route: '/jobs/getJob',
	requires: {
		jobId: 'string',
		state: 'string',
	},
	returns: {},
});

module.exports = waitfor;
<commit_msg>fix jobs waitfor doc entry<commit_after>'use strict';

var method = require('./../method');
var assign = require('lodash.assign');

/**
 * @memberof jobs
 * @method waitfor
 * @description Wait for the job with the given id to enter a certain job
 * state. This action polls the server and returns only when we detect that the job
 * has transitioned into the given state. States available are:
 *   - running
 *   - stopped
 *
 * When the callback is called, the returned object will be information about the job.
 * @param {object} params - Job waitfor parameters
 * @param {string} params.jobId - Id of the job to wait for
 * @param {string} params.state - Name of the state to wait for
 * @param {function} cb - Node-style error-first callback function
 * @returns {object} job - The job JSON object
 * @example
 * paperspace.job.waitfor({
 *   jobId: 'j123abc',
 *   state: 'stopped',
 * }, function(err, resp) {
 *   // handle error or http response
 * });
 * @example
 * $ paperspace jobs waitfor \
 *     --jobId "j123abc" \
 *     --state "stopped"
 * @example
 * # HTTP request:
 * # The waitefor method is only available using the API client.
 * # Use the show job to query the state of the job via HTTP.
 * @example
 * //Example return value:
 * {
 *   "id": "j123abc",
 *   "name": "My Job",
 *   "state": "stopped"
 * }
 */

var INTERVAL = 5000; // ms

function waitfor(params, cb) {
	if (!params.state) {
		return cb(new Error('Missing required parameter state'));
	}
	var state = ('' + params.state).toLowerCase();
	var targetState;
	switch (state) {
		case 'running':
		case 'stopped':
			targetState = state;
			break;
		default:
			console.log(state);
			return cb(new Error('state must be either running or stopped'));
	}
	return method(waitfor, params, function _cb(err, resp) {
		if (err) {
			return cb(err);
		}
		var job = resp.body;
		if (job && job.state === targetState) {
			return cb(null, resp);
		}
		var interval = setTimeout(function _interval() {
			return waitfor(params, cb);
		}, INTERVAL);
		return interval;
	});
}

assign(waitfor, {
	auth: true,
	group: 'jobs',
	name: 'waitfor',
	method: 'get',
	route: '/jobs/getJob',
	requires: {
		jobId: 'string',
		state: 'string',
	},
	returns: {},
});

module.exports = waitfor;
<|endoftext|>


<commit_before>/*!
 * jQuery Stepy - A Wizard Plugin
 *
 * The MIT License
 *
 * @author:  Washington Botelho
 * @doc:     wbotelhos.com/stepy
 * @version: 1.1.0
 *
 */

;(function($) {
  'use strict';

  var methods = {
    init: function(settings) {
      return this.each(function() {
        methods.destroy.call(this);

        this.opt = $.extend({}, $.fn.stepy.defaults, settings);

        var self = $(this);

        methods._generateId.call(this);

        // Remove Validator...
        if (this.opt.validate) {
          jQuery.validator.setDefaults({ ignore: this.opt.ignore });

          self.append($('<div />', { 'class': 'stepy-errors' }));
        }

        if (this.opt.header) {
          this.header = methods._header.call(this);
        }

        this.steps = self.children('fieldset');

        var that = this;

        this.steps.each(function(index) {
          $(this).addClass('stepy-step');

          if (that.opt.header) {
            methods._createHead.call(that, this, index);
          }

          methods._createButtons.call(that, this, index);
          methods._stateButton.call(that, index, that.steps);
        });

        methods._bindFinishButton.call(this);

        if (this.opt.header) {
          methods._bindHeader.call(this);
        }

        if (that.opt.enter) {
          methods._bindEnter.call(that);
        }

        that.steps.first().find(':input:visible:enabled').first().select().focus();

        methods._setState.call(this, { settings: this.opt, index: 0, stepy: true });
      });
    },

    _bindBackButton: function(step) {
      var button = $(step).find(this.opt.backButton);

      if (!button.length) {
        return;
      }

      button.on('click.stepy', function(e) {
        e.preventDefault();

        var index = $(this).data('index') - 1;

        if (!this.opt.back || methods._execute.call(this, this.opt.back, index, this.steps.length)) {
          methods.step.call(this, index);
        }
      }.bind(this));
    },

    _bindEnter: function() {
      var that = this;

      this.steps.delegate(':text, :password', 'keypress', function(evt) {
        var key = (evt.keyCode ? evt.keyCode : evt.which);

        if (key === 13) {
          evt.preventDefault();

          var
            step    = $(this).closest('fieldset'),
            hasNext = step.next('fieldset').length;

          if (hasNext) {
            step.find('.stepy-next').trigger('click');
          } else if (that.finishButton) {
            that.finishButton.trigger('click');
          }
        }
      });
    },

    _bindFinishButton: function() {
      this.finishButton = $(this).find('.stepy-finish');

      if (!this.finishButton.length) {
        return $.error('submit button ".stepy-finish" missing.');
      }

      this.finishButton.hide().on('click.stepy', methods._onFinishButton.bind(this));
    },

    _bindHeader: function() {
      this.heads = this.header.children('li');

      this.heads.first().addClass('stepy-active');

      if (this.opt.titleClick) {
        this.heads.on('click', methods._bindHeaderHandler.bind(this));
      } else {
        this.heads.css('cursor', 'default');
      }
    },

    _bindHeaderHandler: function() {
      var
        words   = this.heads.filter('.stepy-active').attr('id').split('-'), // TODO: try keep the number in an attribute.
        current = parseInt(words[words.length - 1], 10),
        clicked = $(this).index();

      if (clicked > current) {
        if (this.opt.next && !methods._execute.call(this, this.opt.next, clicked)) {
          return false;
        }
      } else if (clicked < current) {
        if (this.opt.back && !methods._execute.call(this, this.opt.back, clicked)) {
          return false;
        }
      }

      if (clicked != current) {
        methods.step.call(this, clicked);
      }
    },

    _bindNextButton: function() {
      var button = $(this).find(this.opt.nextButton);

      if (!button.length) {
        return;
      }

      button.on('click.stepy', function(e) {
        e.preventDefault();

        var index = $(this).data('index') + 1;

        if (!this.opt.next || methods._execute.call(this, this.opt.next, index, this.steps.length)) {
          methods.step.call(this, index);
        }
      }.bind(this));
    },

    _createButtons: function(step, index) {
      if (index === 0) {
        if (this.steps.length > 1) {
          methods._bindNextButton.call(this, step);
        }
      } else {
        $(step).hide();

        methods._bindBackButton.call(this, step);

        if (index < this.steps.length - 1) {
          methods._bindNextButton.call(this, step);
        }
      }
    },

    _createHead: function(step, index) {
      var
        step = $(step).attr('id', this.id + '-step-' + index),
        head = methods._head.call(this, index);

      head.append(methods._title.call(this, step));

      if (this.opt.description) {
        head.append(methods._description.call(this, step));
      }

      this.header.append(head);
    },

    _description: function(step) {
      var legend = step.children('legend');

      if (!this.opt.legend) {
        legend.hide();
      }

      if (legend.length) {
        return $('<span />', { html: legend.html() });
      }

      methods._error.call(this, '<legend /> element missing!');
    },

    _error: function(message) {
      $(this).html(message);

      $.error(message);
    },

    _execute: function(callback, index, totalSteps) {
      if (callback === undefined) {
        return true;
      }

      var isValid = callback.call(this, index, totalSteps);

      return isValid || isValid === undefined;
    },

    _generateId: function() {
      if (this.id === undefined || this.id === '') {
        $(this).attr('id', 'stepy-' + Math.random().toString().substring(2));
      }
    },

    _head: function(index) {
      return $('<li />', { id: this.id + '-head-' + index });
    },

    _header: function() {
      var header = $('<ul />', { id: this.id + '-header', 'class': 'stepy-header' });

      if (this.opt.titleTarget) {
        header.appendTo(this.opt.titleTarget);
      } else {
        header.insertBefore(this);
      }

      return header;
    },

    _onFinishButton: function(evt) {
      var onSubmit = undefined;

      if (this.tagName === 'FORM') {
        onSubmit = this.getAttribute('onsubmit');

        this.setAttribute('onsubmit', 'return false;');
      }

      if (!methods._execute.call(this, this.opt.finish, this.steps.length - 1)) {
        evt.preventDefault();
      } else if (this.tagName === 'FORM') {
        if (onSubmit) {
          this.setAttribute('onsubmit', onSubmit);
        } else {
          this.removeAttribute('onsubmit');
        }

        var isSubmit = this.finishButton.attr('type') === 'submit';

        if (isSubmit && (!this.opt.validate || methods.validate.call(this, this.steps.length - 1))) {
          this.submit();
        }
      }
    },

    _setState: function(data) {
      var self = $(this);

      self.data($.extend({}, self.data(), data));
    },

    _stateButton: function(index, steps) {
      var
        self = $(this),
        step = steps.eq(index);

      if (index === 0) {
        step.find('.stepy-back').hide();
        step.find('.stepy-next').show();
        self.find('.stepy-finish').hide();
      } else if (index === steps.length - 1) {
        step.find('.stepy-back').show();
        step.find('.stepy-next').hide();
        self.find('.stepy-finish').show();
      } else {
        step.find('.stepy-back').show();
        step.find('.stepy-next').show();
        self.find('.stepy-finish').hide();
      }
    },

    _title: function(step) {
      return $('<div />', { html: step.attr('title') || '--' });
    },

    _transition: function(steps, max) {
      if (this.opt.transition === 'fade') {
        steps.fadeOut(this.opt.duration, function() {
          if (--steps.length > 0) {
            return;
          }

          steps.eq(max).fadeIn(this.opt.duration);
        });
      } else if (this.opt.transition === 'slide') {
        steps.slideUp(this.opt.duration, function() {
          if (--steps.length > 0) {
            return;
          }

          steps.eq(max).slideDown(this.opt.duration);
        });
      }
    },

    destroy: function() {
      return $(this).each(function() {
        var self = $(this);

        if (self.data('stepy')) {
          var steps = self.data('stepy', false).children('fieldset').css('display', '');

          self.children('.stepy-errors').remove();
        }
      });
    },

    step: function(index) {
      var
        max   = index,
        self  = $(this),
        steps = self.children('fieldset');

      if (index > steps.length - 1) {
        index = steps.length - 1;
      }

      if (this.opt.validate) {
        var isValid = true;

        for (var i = 0; i < index; i++) {
          isValid &= methods.validate.call(this, i);

          if (this.opt.block && !isValid) {
            max = i;
            break;
          }
        }
      }

      if (this.opt.transition) {
        methods._transition.call(this, steps, max);
      } else {
        steps.hide(this.opt.duration).eq(max).show(this.opt.duration);
      }

      if (this.opt.header) {
        this.heads.removeClass('stepy-active').eq(max).addClass('stepy-active');
      }

      if (this.tagName === 'FORM') {
        var fields = steps.eq(max);

        if (max === index) {
          fields = fields.find(':input:enabled:visible');
        } else {
          fields = fields.find('.error').trigger('select').trigger('focus');
        }

        fields.first().trigger('select').trigger('focus');
      }

      if (this.opt.select) {
        this.opt.select.call(this, max + 1, steps.length);
      }

      methods._stateButton.call(this, max, steps);
      methods._setState.call(this, { index: max });

      return self;
    },

    validate: function(index) {
      var self = $(this);

      if (!this.tagName === 'FORM') {
        return true;
      }

      var
        that      = this,
        step      = self.children('fieldset').eq(index),
        isValid   = true,
        $title    = $('#' + this.id + '-header').children().eq(index),
        $validate = self.validate();

      $(step.find(':input:enabled').get().reverse()).each(function() {
        var fieldIsValid = $validate.element($(this));

        if (fieldIsValid === undefined) {
          fieldIsValid = true;
        }

        isValid &= fieldIsValid;

        if (isValid) {
          if (that.opt.errorImage) {
            $title.removeClass('stepy-error');
          }
        } else {
          if (that.opt.errorImage) {
            $title.addClass('stepy-error');
          }

          $validate.focusInvalid();
        }
      });

      return isValid;
    }
  };

  $.fn.stepy = function(method) {
    if (methods[method]) {
      return methods[method].apply($(this)[0], Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error('Method ' + method + ' does not exist!');
    }
  };

  $.fn.stepy.defaults = {
    back:          undefined,
    backButton:    '.stepy-back',
    block:         false,
    description:   true,
    duration:      0,
    enter:         true,
    errorImage:    false,
    finish:        undefined,
    finishButton:  undefined,
    globalButtons: false,
    header:        true,
    ignore:        '',
    legend:        true,
    next:          undefined,
    nextButton:    '.stepy-next',
    select:        undefined,
    titleClick:    false,
    titleTarget:   undefined,
    transition:    undefined,
    validate:      false
  };

})(jQuery);
<commit_msg>using global state on buttons<commit_after>/*!
 * jQuery Stepy - A Wizard Plugin
 *
 * The MIT License
 *
 * @author:  Washington Botelho
 * @doc:     wbotelhos.com/stepy
 * @version: 1.1.0
 *
 */

;(function($) {
  'use strict';

  var methods = {
    init: function(settings) {
      return this.each(function() {
        methods.destroy.call(this);

        this.opt = $.extend({}, $.fn.stepy.defaults, settings);

        var self = $(this);

        methods._generateId.call(this);

        // Remove Validator...
        if (this.opt.validate) {
          jQuery.validator.setDefaults({ ignore: this.opt.ignore });

          self.append($('<div />', { 'class': 'stepy-errors' }));
        }

        if (this.opt.header) {
          this.header = methods._header.call(this);
        }

        this.steps = self.children('fieldset');

        var that = this;

        this.steps.each(function(index) {
          var self = $(this);

          self.addClass('stepy-step');

          if (index !== 0) {
            self.hide();
          }

          if (that.opt.header) {
            methods._createHead.call(that, this, index);
          }

          methods._stateButton.call(that, index, that.steps);
        });

        methods._bindNextButton.call(this);
        methods._bindBackButton.call(this);
        methods._bindFinishButton.call(this);

        if (this.opt.header) {
          methods._bindHeader.call(this);
        }

        if (that.opt.enter) {
          methods._bindEnter.call(that);
        }

        that.steps.first().find(':input:visible:enabled').first().select().focus();

        methods._setState.call(this, { settings: this.opt, index: 0, stepy: true });
      });
    },

    _bindBackButton: function() {
      var button = $(this).find(this.opt.backButton);

      if (!button.length) {
        return;
      }

      button.on('click.stepy', function(e) {
        e.preventDefault();

        var index = $(this).data('index') - 1;

        if (!this.opt.back || methods._execute.call(this, this.opt.back, index, this.steps.length)) {
          methods.step.call(this, index);
        }
      }.bind(this));
    },

    _bindEnter: function() {
      var that = this;

      this.steps.delegate(':text, :password', 'keypress', function(evt) {
        var key = (evt.keyCode ? evt.keyCode : evt.which);

        if (key === 13) {
          evt.preventDefault();

          var
            step    = $(this).closest('fieldset'),
            hasNext = step.next('fieldset').length;

          if (hasNext) {
            step.find('.stepy-next').trigger('click');
          } else if (that.finishButton) {
            that.finishButton.trigger('click');
          }
        }
      });
    },

    _bindFinishButton: function() {
      this.finishButton = $(this).find('.stepy-finish');

      if (!this.finishButton.length) {
        return $.error('submit button ".stepy-finish" missing.');
      }

      this.finishButton.hide().on('click.stepy', methods._onFinishButton.bind(this));
    },

    _bindHeader: function() {
      this.heads = this.header.children('li');

      this.heads.first().addClass('stepy-active');

      if (this.opt.titleClick) {
        this.heads.on('click', methods._bindHeaderHandler.bind(this));
      } else {
        this.heads.css('cursor', 'default');
      }
    },

    _bindHeaderHandler: function() {
      var
        words   = this.heads.filter('.stepy-active').attr('id').split('-'), // TODO: try keep the number in an attribute.
        current = parseInt(words[words.length - 1], 10),
        clicked = $(this).index();

      if (clicked > current) {
        if (this.opt.next && !methods._execute.call(this, this.opt.next, clicked)) {
          return false;
        }
      } else if (clicked < current) {
        if (this.opt.back && !methods._execute.call(this, this.opt.back, clicked)) {
          return false;
        }
      }

      if (clicked != current) {
        methods.step.call(this, clicked);
      }
    },

    _bindNextButton: function() {
      var button = $(this).find(this.opt.nextButton);

      if (!button.length) {
        return;
      }

      button.on('click.stepy', function(e) {
        e.preventDefault();

        var index = $(this).data('index') + 1;

        if (!this.opt.next || methods._execute.call(this, this.opt.next, index, this.steps.length)) {
          methods.step.call(this, index);
        }
      }.bind(this));
    },

    _createHead: function(step, index) {
      var
        step = $(step).attr('id', this.id + '-step-' + index),
        head = methods._head.call(this, index);

      head.append(methods._title.call(this, step));

      if (this.opt.description) {
        head.append(methods._description.call(this, step));
      }

      this.header.append(head);
    },

    _description: function(step) {
      var legend = step.children('legend');

      if (!this.opt.legend) {
        legend.hide();
      }

      if (legend.length) {
        return $('<span />', { html: legend.html() });
      }

      methods._error.call(this, '<legend /> element missing!');
    },

    _error: function(message) {
      $(this).html(message);

      $.error(message);
    },

    _execute: function(callback, index, totalSteps) {
      if (callback === undefined) {
        return true;
      }

      var isValid = callback.call(this, index, totalSteps);

      return isValid || isValid === undefined;
    },

    _generateId: function() {
      if (this.id === undefined || this.id === '') {
        $(this).attr('id', 'stepy-' + Math.random().toString().substring(2));
      }
    },

    _head: function(index) {
      return $('<li />', { id: this.id + '-head-' + index });
    },

    _header: function() {
      var header = $('<ul />', { id: this.id + '-header', 'class': 'stepy-header' });

      if (this.opt.titleTarget) {
        header.appendTo(this.opt.titleTarget);
      } else {
        header.insertBefore(this);
      }

      return header;
    },

    _onFinishButton: function(evt) {
      var onSubmit = undefined;

      if (this.tagName === 'FORM') {
        onSubmit = this.getAttribute('onsubmit');

        this.setAttribute('onsubmit', 'return false;');
      }

      if (!methods._execute.call(this, this.opt.finish, this.steps.length - 1)) {
        evt.preventDefault();
      } else if (this.tagName === 'FORM') {
        if (onSubmit) {
          this.setAttribute('onsubmit', onSubmit);
        } else {
          this.removeAttribute('onsubmit');
        }

        var isSubmit = this.finishButton.attr('type') === 'submit';

        if (isSubmit && (!this.opt.validate || methods.validate.call(this, this.steps.length - 1))) {
          this.submit();
        }
      }
    },

    _setState: function(data) {
      var self = $(this);

      self.data($.extend({}, self.data(), data));
    },

    _stateButton: function(index, steps) {
      var
        self = $(this),
        step = steps.eq(index);

      if (index === 0) {
        step.find('.stepy-back').hide();
        step.find('.stepy-next').show();
        self.find('.stepy-finish').hide();
      } else if (index === steps.length - 1) {
        step.find('.stepy-back').show();
        step.find('.stepy-next').hide();
        self.find('.stepy-finish').show();
      } else {
        step.find('.stepy-back').show();
        step.find('.stepy-next').show();
        self.find('.stepy-finish').hide();
      }
    },

    _title: function(step) {
      return $('<div />', { html: step.attr('title') || '--' });
    },

    _transition: function(steps, max) {
      if (this.opt.transition === 'fade') {
        steps.fadeOut(this.opt.duration, function() {
          if (--steps.length > 0) {
            return;
          }

          steps.eq(max).fadeIn(this.opt.duration);
        });
      } else if (this.opt.transition === 'slide') {
        steps.slideUp(this.opt.duration, function() {
          if (--steps.length > 0) {
            return;
          }

          steps.eq(max).slideDown(this.opt.duration);
        });
      }
    },

    destroy: function() {
      return $(this).each(function() {
        var self = $(this);

        if (self.data('stepy')) {
          var steps = self.data('stepy', false).children('fieldset').css('display', '');

          self.children('.stepy-errors').remove();
        }
      });
    },

    step: function(index) {
      var
        max   = index,
        self  = $(this),
        steps = self.children('fieldset');

      if (index > steps.length - 1) {
        index = steps.length - 1;
      }

      if (this.opt.validate) {
        var isValid = true;

        for (var i = 0; i < index; i++) {
          isValid &= methods.validate.call(this, i);

          if (this.opt.block && !isValid) {
            max = i;
            break;
          }
        }
      }

      if (this.opt.transition) {
        methods._transition.call(this, steps, max);
      } else {
        steps.hide(this.opt.duration).eq(max).show(this.opt.duration);
      }

      if (this.opt.header) {
        this.heads.removeClass('stepy-active').eq(max).addClass('stepy-active');
      }

      if (this.tagName === 'FORM') {
        var fields = steps.eq(max);

        if (max === index) {
          fields = fields.find(':input:enabled:visible');
        } else {
          fields = fields.find('.error').trigger('select').trigger('focus');
        }

        fields.first().trigger('select').trigger('focus');
      }

      if (this.opt.select) {
        this.opt.select.call(this, max + 1, steps.length);
      }

      methods._stateButton.call(this, max, steps);
      methods._setState.call(this, { index: max });

      return self;
    },

    validate: function(index) {
      var self = $(this);

      if (!this.tagName === 'FORM') {
        return true;
      }

      var
        that      = this,
        step      = self.children('fieldset').eq(index),
        isValid   = true,
        $title    = $('#' + this.id + '-header').children().eq(index),
        $validate = self.validate();

      $(step.find(':input:enabled').get().reverse()).each(function() {
        var fieldIsValid = $validate.element($(this));

        if (fieldIsValid === undefined) {
          fieldIsValid = true;
        }

        isValid &= fieldIsValid;

        if (isValid) {
          if (that.opt.errorImage) {
            $title.removeClass('stepy-error');
          }
        } else {
          if (that.opt.errorImage) {
            $title.addClass('stepy-error');
          }

          $validate.focusInvalid();
        }
      });

      return isValid;
    }
  };

  $.fn.stepy = function(method) {
    if (methods[method]) {
      return methods[method].apply($(this)[0], Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error('Method ' + method + ' does not exist!');
    }
  };

  $.fn.stepy.defaults = {
    back:          undefined,
    backButton:    '.stepy-back',
    block:         false,
    description:   true,
    duration:      0,
    enter:         true,
    errorImage:    false,
    finish:        undefined,
    finishButton:  undefined,
    globalButtons: false,
    header:        true,
    ignore:        '',
    legend:        true,
    next:          undefined,
    nextButton:    '.stepy-next',
    select:        undefined,
    titleClick:    false,
    titleTarget:   undefined,
    transition:    undefined,
    validate:      false
  };

})(jQuery);
<|endoftext|>


<commit_before>import delegate from './delegate'
import { each } from '../../utils/generic'

export default function initialize () {

	/**
	 * Let's take stock of which containers and sequences
	 * our current store of elements is actively using.
	 */
	let activeContainerIds = []
	let activeSequenceIds = []

	each(this.store.elements, element => {
		if (activeContainerIds.indexOf(element.containerId) === -1) {
			activeContainerIds.push(element.containerId)
		}
		if (activeSequenceIds.indexOf(element.sequence.id) === -1) {
			activeSequenceIds.push(element.sequence.id)
		}
	})

	/**
	 * Remove unused sequences.
	 */
	each(this.store.sequences, sequence => {
		if (activeSequenceIds.indexOf(sequence.id) === -1) {
			delete this.store.sequences[sequence.id]
		}
	})

	each(this.store.containers, container => {

		/**
		 * Remove unused containers.
		 */
		if (activeContainerIds.indexOf(container.id) === -1) {
			container.node.removeEventListener('scroll', delegate)
			container.node.removeEventListener('resize', delegate)
			delete this.store.containers[container.id]

		/**
		 * The default container is the <html> element, and in
		 * this case we listen for scroll events on the window.
		 */
		} else if (container.node === document.documentElement) {
			window.addEventListener('scroll', delegate.bind(this))
			window.addEventListener('resize', delegate.bind(this))

		/**
		 * Otherwise listen for scroll events directly on the container.
		 */
		} else {
			container.node.addEventListener('scroll', delegate.bind(this))
			container.node.addEventListener('resize', delegate.bind(this))
		}
	})

	/**
	 * Manually invoke delegate once to capture
	 * element and container dimensions, container
	 * scroll position, and trigger any valid reveals
	 */
	delegate.call(this)

	/**
	 * And with that, initialization is complete so
	 * let's update our initialization timeout and state.
	 */
	this.initTimeout = null
	this.initialized = true
}
<commit_msg>refactor let declarations as const during initialization<commit_after>import delegate from './delegate'
import { each } from '../../utils/generic'

export default function initialize () {

	/**
	 * Let's take stock of which containers and sequences
	 * our current store of elements is actively using.
	 */
	const activeContainerIds = []
	const activeSequenceIds = []

	each(this.store.elements, element => {
		if (activeContainerIds.indexOf(element.containerId) === -1) {
			activeContainerIds.push(element.containerId)
		}
		if (activeSequenceIds.indexOf(element.sequence.id) === -1) {
			activeSequenceIds.push(element.sequence.id)
		}
	})

	/**
	 * Remove unused sequences.
	 */
	each(this.store.sequences, sequence => {
		if (activeSequenceIds.indexOf(sequence.id) === -1) {
			delete this.store.sequences[sequence.id]
		}
	})

	each(this.store.containers, container => {

		/**
		 * Remove unused containers.
		 */
		if (activeContainerIds.indexOf(container.id) === -1) {
			container.node.removeEventListener('scroll', delegate)
			container.node.removeEventListener('resize', delegate)
			delete this.store.containers[container.id]

		/**
		 * The default container is the <html> element, and in
		 * this case we listen for scroll events on the window.
		 */
		} else if (container.node === document.documentElement) {
			window.addEventListener('scroll', delegate.bind(this))
			window.addEventListener('resize', delegate.bind(this))

		/**
		 * Otherwise listen for scroll events directly on the container.
		 */
		} else {
			container.node.addEventListener('scroll', delegate.bind(this))
			container.node.addEventListener('resize', delegate.bind(this))
		}
	})

	/**
	 * Manually invoke delegate once to capture
	 * element and container dimensions, container
	 * scroll position, and trigger any valid reveals
	 */
	delegate.call(this)

	/**
	 * And with that, initialization is complete so
	 * let's update our initialization timeout and state.
	 */
	this.initTimeout = null
	this.initialized = true
}
<|endoftext|>