<commit_before>#!/usr/bin/env node
var fs = require("fs");
var net = require("net");
var tls = require("tls");
var path = require("path");
var url = require("url");

var async = require("async");
var dmp_module = require("diff_match_patch");
var DMP = new dmp_module.diff_match_patch();
var optimist = require("optimist");
var _ = require("underscore");

var lib = require("./lib");
var log = lib.log;
var api = lib.api;

log.set_log_level("log");

var parse_url = function (workspace_url) {
  var parsed_url,
    re = /\/r\/([\-\@\+\.\w]+)\/([\-\w]+)/,
    res;

  parsed_url = url.parse(workspace_url);
  res = parsed_url.path.match(re);

  return {
    host: parsed_url.hostname,
    port: parsed_url.protocol === "http" ? 3148 : 3448,
    klass: parsed_url.protocol === "http" ? net : tls,
    owner: res && res[1],
    workspace: res && res[2]
  };
};

var parse_floorc = function () {
  var floorc = {},
    floorc_path,
    floorc_lines;

  try {
    floorc_path = path.join(process.env[(process.platform === "win32") ? "USERPROFILE" : "HOME"], ".floorc");
    /*jslint stupid: true */
    floorc_lines = fs.readFileSync(floorc_path, "utf-8").split("\n");
    /*jslint stupid: false */
    _.each(floorc_lines, function (line) {
      var space,
        key,
        value;
      /*jslint regexp: true */
      if (line.match(/^\s*#.*/)) {
        return;
      }
      /*jslint regexp: false */
      space = line.indexOf(" ");
      key = line.slice(0, space).toLowerCase();
      value = line.slice(space + 1);
      floorc[key] = value;
    });
  } catch (e) {
    log.error("no ~/.floorc file was found");
  }
  return floorc;
};

var parse_dot_floo = function () {
  var data,
    floo_file,
    parsed_url = {};
  try {
    /*jslint stupid: true */
    floo_file = fs.readFileSync(".floo");
    /*jslint stupid: false */
    data = JSON.parse(floo_file);
    parsed_url = parse_url(data.url);
  } catch (e) {
    log.log("no .floo file in current directory");
  }
  return parsed_url;
};

var parse_args = function () {
  var floorc = parse_floorc(),
    parsed_url = parse_dot_floo();

  return optimist
    .usage('Usage: $0 -o [owner] -w [workspace] -u [username] -s [secret] --url [url] --create [name] --delete --read-only --send-local --hooks [path_to_hooks] --verbose')
    .default('H', parsed_url.host || 'floobits.com')
    .default('p', 3448)
    .describe('u', 'Your Floobits username. Defaults to your ~/.floorc defined username.')
    .default('u', floorc.username)
    .describe('s', 'Your Floobits secret. Defaults to your ~/.floorc defined secret.')
    .default('s', floorc.secret)
    .describe('w', 'The Floobits Workspace')
    .default('w', parsed_url.workspace)
    .describe('o', 'The owner of the Workspace. Defaults to the .floo file\'s owner or your ~/.floorc username.')
    .default('o', parsed_url.owner || floorc.username)
    .describe('create', 'Creates a new workspace if possible (any value passed will override -w) If not -w, defaults to the dirname.')
    .describe('delete', 'Deletes the workspace if possible (can be used with --create to overwrite an existing workspace).')
    .describe('H', 'Host to connect to. For debugging/development. Defaults to floobits.com.')
    .describe('p', 'Port to use. For debugging/development. Defaults to 3448.')
    .describe('send-local', "Overwrites the workspace's files with your local files on startup.")
    .describe('hooks', "Hooks to run after stuff is changed.  Must be a node require-able file")
    // .describe('readonly', 'Will not send patches for local modifications (Always enabled for OS X).')
    .demand(['H', 'p', 'u', 's'])
    .argv;
};

exports.run = function () {
  var cwd = process.cwd(),
    floorc,
    floo_file,
    data,
    parsed_url,
    series = [],
    raw_hooks = {},
    args = parse_args();

  if (args.verbose) {
    log.set_log_level("debug");
  }

  if (args.help || args.h) {
    optimist.showHelp();
    process.exit(0);
  }

  args.o = args.o || args.u;
  if (args.create && args.create === true) {
    args.create = path.basename(process.cwd());
  }
  args.w = args.create || args.w;

  if (args.url) {
    parsed_url = parse_url(args.url);
    args.w = args.w || parsed_url.workspace;
    args.o = args.o || parsed_url.owner;
  }

  if (!args.w) {
    optimist.showHelp();
    log.error('I need a workspace name.');
    process.exit(0);
  }

  if (args['delete']) {
    series.push(api.del.bind(api, args.H, args.o, args.s, args.w));
  }

  if (args.create) {
    series.push(api.create.bind(api, args.H, args.o, args.s, args.w, args.perms));
  }

  async.series(series, function (err) {
    var parallel = {},
      floo_conn,
      floo_listener,
      hooker = new lib.Hooks(args.hooks);

    if (err) {
      return log.error(err);
    }
    floo_conn = new lib.FlooConnection(args.H, args.p, args.o, args.w, args.u, args.s, args['read-only'], hooker);

    parallel.conn = function (cb) {
      log.log('Joining', 'https://' + args.H + '/' + args.o + '/' + args.w);
      floo_conn.connect(cb);
    };

    parallel.listen = function (cb) {
      floo_listener = new lib.Listener(process.cwd(), floo_conn, hooker);
      floo_listener.inspect(cb);
    };

    async.parallel(parallel, function (err) {
      if (err) {
        return log.error(err);
      }
      // if (!args.readonly && process.platform !== 'darwin') {
      //   floo_listener.fs_watch();
      // }
      floo_conn.start_syncing(floo_listener, args.create || args['send-local']);
    });
  });
};
<commit_msg>Warn about OS X's file watcher.<commit_after>#!/usr/bin/env node
var fs = require("fs");
var net = require("net");
var tls = require("tls");
var path = require("path");
var url = require("url");

var async = require("async");
var dmp_module = require("diff_match_patch");
var DMP = new dmp_module.diff_match_patch();
var optimist = require("optimist");
var _ = require("underscore");

var lib = require("./lib");
var log = lib.log;
var api = lib.api;

log.set_log_level("log");

var parse_url = function (workspace_url) {
  var parsed_url,
    re = /\/r\/([\-\@\+\.\w]+)\/([\-\w]+)/,
    res;

  parsed_url = url.parse(workspace_url);
  res = parsed_url.path.match(re);

  return {
    host: parsed_url.hostname,
    port: parsed_url.protocol === "http" ? 3148 : 3448,
    klass: parsed_url.protocol === "http" ? net : tls,
    owner: res && res[1],
    workspace: res && res[2]
  };
};

var parse_floorc = function () {
  var floorc = {},
    floorc_path,
    floorc_lines;

  try {
    floorc_path = path.join(process.env[(process.platform === "win32") ? "USERPROFILE" : "HOME"], ".floorc");
    /*jslint stupid: true */
    floorc_lines = fs.readFileSync(floorc_path, "utf-8").split("\n");
    /*jslint stupid: false */
    _.each(floorc_lines, function (line) {
      var space,
        key,
        value;
      /*jslint regexp: true */
      if (line.match(/^\s*#.*/)) {
        return;
      }
      /*jslint regexp: false */
      space = line.indexOf(" ");
      key = line.slice(0, space).toLowerCase();
      value = line.slice(space + 1);
      floorc[key] = value;
    });
  } catch (e) {
    log.error("no ~/.floorc file was found");
  }
  return floorc;
};

var parse_dot_floo = function () {
  var data,
    floo_file,
    parsed_url = {};
  try {
    /*jslint stupid: true */
    floo_file = fs.readFileSync(".floo");
    /*jslint stupid: false */
    data = JSON.parse(floo_file);
    parsed_url = parse_url(data.url);
  } catch (e) {
    log.log("no .floo file in current directory");
  }
  return parsed_url;
};

var parse_args = function () {
  var floorc = parse_floorc(),
    parsed_url = parse_dot_floo();

  return optimist
    .usage('Usage: $0 -o [owner] -w [workspace] -u [username] -s [secret] --url [url] --create [name] --delete --read-only --send-local --hooks [path_to_hooks] --verbose')
    .default('H', parsed_url.host || 'floobits.com')
    .default('p', 3448)
    .describe('u', 'Your Floobits username. Defaults to your ~/.floorc defined username.')
    .default('u', floorc.username)
    .describe('s', 'Your Floobits secret. Defaults to your ~/.floorc defined secret.')
    .default('s', floorc.secret)
    .describe('w', 'The Floobits Workspace')
    .default('w', parsed_url.workspace)
    .describe('o', 'The owner of the Workspace. Defaults to the .floo file\'s owner or your ~/.floorc username.')
    .default('o', parsed_url.owner || floorc.username)
    .describe('create', 'Creates a new workspace if possible (any value passed will override -w) If not -w, defaults to the dirname.')
    .describe('delete', 'Deletes the workspace if possible (can be used with --create to overwrite an existing workspace).')
    .describe('H', 'Host to connect to. For debugging/development. Defaults to floobits.com.')
    .describe('p', 'Port to use. For debugging/development. Defaults to 3448.')
    .describe('send-local', "Overwrites the workspace's files with your local files on startup.")
    .describe('hooks', "Hooks to run after stuff is changed.  Must be a node require-able file")
    // .describe('readonly', 'Will not send patches for local modifications (Always enabled for OS X).')
    .demand(['H', 'p', 'u', 's'])
    .argv;
};

exports.run = function () {
  var cwd = process.cwd(),
    floorc,
    floo_file,
    data,
    parsed_url,
    series = [],
    raw_hooks = {},
    args = parse_args();

  if (args.verbose) {
    log.set_log_level("debug");
  }

  if (args.help || args.h) {
    optimist.showHelp();
    process.exit(0);
  }

  args.o = args.o || args.u;
  if (args.create && args.create === true) {
    args.create = path.basename(process.cwd());
  }
  args.w = args.create || args.w;

  if (args.url) {
    parsed_url = parse_url(args.url);
    args.w = args.w || parsed_url.workspace;
    args.o = args.o || parsed_url.owner;
  }

  if (!args.w) {
    optimist.showHelp();
    log.error('I need a workspace name.');
    process.exit(0);
  }

  if (args['delete']) {
    series.push(api.del.bind(api, args.H, args.o, args.s, args.w));
  }

  if (args.create) {
    series.push(api.create.bind(api, args.H, args.o, args.s, args.w, args.perms));
  }

  async.series(series, function (err) {
    var parallel = {},
      floo_conn,
      floo_listener,
      hooker = new lib.Hooks(args.hooks);

    if (err) {
      return log.error(err);
    }
    floo_conn = new lib.FlooConnection(args.H, args.p, args.o, args.w, args.u, args.s, args['read-only'], hooker);

    parallel.conn = function (cb) {
      log.log('Joining', 'https://' + args.H + '/' + args.o + '/' + args.w);
      floo_conn.connect(cb);
    };

    parallel.listen = function (cb) {
      floo_listener = new lib.Listener(process.cwd(), floo_conn, hooker);
      floo_listener.inspect(cb);
    };

    async.parallel(parallel, function (err) {
      if (err) {
        return log.error(err);
      }
      if (!args.readonly) {
        if (process.platform === 'darwin') {
          log.error("Sorry, node.js's file watcher doesn't work with more than 200 files on OS X. Local changes will not be synced to the workspace.");
        } else {
          floo_listener.fs_watch();
        }
      }
      floo_conn.start_syncing(floo_listener, args.create || args['send-local']);
    });
  });
};
<|endoftext|>


<commit_before>var parser = exports;

var ometajs = require('../ometajs');

//
// ### function Parser (code)
// #### @code {String} input source code
// Parser's constructor
//
function Parser(code) {
  this.code = code;
  this.lexer = ometajs.lexer.create(code);
  this.state = 'empty';
  this.active = true;

  // State information needed for AST creation
  this.ast = ['topLevel', []];
  this.current = this.ast[1];
  this.stack = [this.ast[1]];

  // Tokens history for look-ahead
  this.tokens = [];
  this.stagingTokens = [];
}

//
// ### function create (code)
// #### @code {String} input source code
// Returns Parser's instance
//
parser.create = function create(code) {
  return new Parser(code);
};

//
// ### function execute ()
// Returns AST of source code
//
Parser.prototype.execute = function execute() {
  while (this.active) {
    this.parseGrammar();
  }

  return this.ast;
};

//
// ### function parseGrammar ()
// Parser's routine
//
Parser.prototype.parseGrammar = function parseGrammar() {
  // ometa %GrammarName%
  if (!this.token('keyword', 'ometa')) return;
  this.state = 'grammar';
  this.push(['grammar', this.token('name').value]);

  // Nested grammars, <: %GrammarName%
  this.push(
    this.optional('punc', '<:') && this.commit() ?
        this.token('name').value
        :
        null
  );
  this.pop();

  // Prepare for rules
  this.token('punc', '{');
  this.push([]);

  this.parseUntil('punc', '}', function parseRules() {
    this.parseRule();
  });
  this.commit();

  this.pop();
  this.pop();

  this.state = 'empty';
};

//
// ### function parseRule ()
// Parser's routine
//
Parser.prototype.parseRule = function parseRule() {
  // Handle grammar end
  if (this.optional('punc', '}') && this.commmit()) {
    // Leave rules and grammar
    this.pop();
    this.pop();

    // Wait for next grammar
    return;
  }

  var name;

  // Rule name
  if (name = this.optional('name')) {
    this.commit();
    this.push(['rule', name.value]);
  } else {
    this.push(['rule', null]);
  }

  // Parse rule's expressions
  var end = this.parseUntil('punc', ['}', ','], function parseExpressions() {
    var end;

    // Parse left expression
    end = this.parseUntil('punc', ['=', ',', '}'], function parseLeft() {
      this.parseExpression('left');
      this.pop();
    });

    // Parse right expression
    if (matchToken(end, 'punc', '=')) {
      this.commit();
      end = this.parseUntil('punc', [',', '}'], function parseRight() {
        this.parseExpression('right');
        this.pop();
      });
    }

    this.fail();
  });

  if (end.value === ',') {
    // Continue parsing next rule
    this.commit();
  } else {
    // Let others parse '}'
    this.fail();
  }

  this.pop();
};

//
// ### function parseExpression (type)
// #### @type {String} left, right, interleave, parens
// Parser's routine
//
Parser.prototype.parseExpression = function parseExpression(type) {
  if (type === 'left') {
    var arg;

    // :name
    if (this.optional('punc', ':', true) && this.commit()) {
      arg = this.token('name');
      this.push(['arg', null, [], arg.value]);
    // rule(...args...) or rule(...args...):name
    } else if (arg = this.optional('name', null, true)) {
      this.commit();
      this.push(['arg', arg.value]);

      // Parse arguments
      this.push([]);
      if (this.optional('punc', '(')) {
        this.commit();
        this.parseUntil('punc', ')', function() {
          this.parseHostExpression();
          this.pop();
          if (this.optional('punc', ',')) this.commit();
        });
        this.commit();
      }
      this.pop();

      // Parse name
      if (this.optional('punc', ':', true) && this.commit()) {
        this.push(this.token('name').value);
      } else {
        this.token('space');
        this.push(null);
      }
      this.pop();
    // -> { javascript body }
    } else if (this.optional('punc', '->') && this.commit()) {
      this.push(['body']);
      this.parseHostExpression();
      this.pop();
    }
  } else if (type === 'right') {
    // Parse multiple choices for a rule's right side
    this.branch('choice', 'punc', '|', function parseChoices() {
      this.parseExpression('interleave');
    });
  } else if (type === 'interleave') {
    // Parse multiple interleaves
    // a && b && c
    this.branch('choice', 'punc', '&&', function parseInterleaves() {
      this.parseExpression('parens');
    });
  } else if (type === 'parens') {
    // Parse interleave in parens or with modificator
    // (a) or a or a* or a+ or a?
    if (this.optional('punc', '(') && this.commit()) {
      this.parseExpression('left');
      this.token('punc', ')');
      this.wrap(['mod', 'none']);
    } else {
      this.parseExpression('left');
      var mod;
      if (this.current.length == 2) {
        mod = this.current[1][0];
        if (mod !== '*' && mod !== '+' && mod !== '?') mod = 'none';
      } else {
        mod = 'none';
      }
      this.wrap(['mod', mod]);
    }
  }
};

//
// ### function parseHostExpression ()
// Parser's routine
//
Parser.prototype.parseHostExpression = function parseHostExpression() {
  var token,
      depth = 0,
      dived = false,
      code = [];

  for (;;) {
    token = this.optional(null, null, true)

    if (matchToken(token, 'punc', ['{', '(', '['])) {
      depth++;
      dived = true;
    } else if (matchToken(token, 'punc', ['}', ')', ']'])) {
      depth--;
      dived = true;
    }

    if (dived && depth < 0 || depth <= 0 && matchToken(token, 'punc', ',')) {
      this.fail();
      break;
    }

    this.commit();

    code.push(
      (token.type === 'string' || token.type === 'token') ?
        JSON.stringify(token.value)
        :
        token.value
    );
  }

  this.push(code.join(''));
};

//
// ### function branch (op, type, value, parse)
// #### @op {String}
// #### @type {String}
// #### @value {String|Array}
// #### @parse {Function}
// Parser's helper
//
Parser.prototype.branch = function branch(op, type, value, parse) {
  var token;
  do {
    if (token) {
      // Wrap previous expression into a branch
      this.wrap([op, token.value]);
      // Commit token
      this.commit();
    }
    parse.call(this);
  } while (this.active && (token = this.optional(type, value)));
  this.fail();
};

//
// ### function parseUntil (type, value, parse)
// #### @type {String}
// #### @value {String|Array}
// #### @parse {Function}
// Parser's helper
//
Parser.prototype.parseUntil = function parseUntil(type, value, parse) {
  var end;
  while (this.active && !(end = this.optional(type, value))) {
    parse.call(this);
  }

  return end;
};

//
// ### function matchToken (token, type, value)
// #### @type {String} (optional) required token type
// #### @value {String|Array} (optional) required token value or values
// Checks if token match type and value
//
function matchToken(token, type, value) {
  return (!type || token.type === type) &&
         (!value || (
           Array.isArray(value) ?
               value.indexOf(token.value) !== -1
               :
               token.value === value
         ));
}

//
// ### function token (type, value)
// #### @type {String} (optional) required token type
// #### @value {String|Array} (optional) required token value, or values
// #### @space {Boolean} (optional) do not parse spaces automatically
// #### @optional {Boolean} (optional) is that token optional?
// Demand token (may throw error)
//
Parser.prototype.token = function token(type, value, space, optional) {
  var token = this.tokens.length ? this.tokens.shift() : this.lexer.token();

  // End of file
  if (!token) {
    if (this.state === 'empty' || optional && type === 'space') {
      this.active = false;
      return token;
    } else {
      throw new Error('Unexpected end of file, ' + type + ' expected');
    }
  }

  // Push token to staging if we was matching optionally
  if (optional) this.stagingTokens.push(token);

  // Check if token matches our conditions
  if (matchToken(token, type, value)) {
    // Skip space automatically
    if (!space && type !== 'space') {
      if (this.tokens.length) {
        if (this.tokens[0].type === 'space') this.tokens.shift();
      } else {
        this.lexer.trim();
      }
    }

    return token;
  } else {
    if (optional) {
      this.fail();
      return false;
    } else {
      this.unexpected(token, type, value);
    }
  }
};

//
// ### function optional (type, value)
// #### @type {String} (optional) required token type
// #### @value {String} (optional) required token value
// #### @space {Boolean} (optional) do not parse spaces automatically
// Look ahead, wrapper for .token()
//
Parser.prototype.optional = function optional(type, value, space) {
  return this.token(type, value, space, true);
};

//
// ### function commit ()
// Removes all tokens from staging history
// Call it after .optional() if you matched
//
Parser.prototype.commit = function commit() {
  this.stagingTokens = [];
  return true;
};

//
// ### function fail ()
// Adds tokens from stage to actual history
// Call it after .optional() if you haven't matched
//
Parser.prototype.fail = function fail() {
  this.tokens = this.tokens.concat(this.stagingTokens);
  this.stagingTokens = [];
  return true;
};

//
// ### function unexpected (token, type, value)
// #### @token {Object} Source token
// #### @type {String} Expected type
// #### @value {String} Expected value
// Throws pretty error
//
Parser.prototype.unexpected = function unexpected(token, type, value) {
  throw new Error('Expected [type: ' + type + ' value: ' + value + '] ' +
                  'token, but found [type: ' + token.type + ' value: ' +
                  token.value + ']');
};

//
// ### function push (node)
// #### @node {Array} AST Node
// Pushes node into AST tree and stack
//
Parser.prototype.push = function push(node) {
  this.current.push(node);
  this.stack.push(node);
  this.current = node;
};

//
// ### function wrap (node)
// #### @node {Array} AST Node
// Wraps curent node into passed one
//
Parser.prototype.wrap = function wrap(node) {
  var wrapped = node.concat([this.current]);
  this.stack[this.stack.length - 1] = wrapped;
  return this.current = wrapped;
}

//
// ### function pop ()
// Pops node from stack
//
Parser.prototype.pop = function pop() {
  var result = this.stack.pop();

  this.current = this.stack[this.stack.length - 1];

  return result;
};
<commit_msg>[parser] we're implementing small subset of ometa<commit_after>var parser = exports;

var ometajs = require('../ometajs');

//
// ### function Parser (code)
// #### @code {String} input source code
// Parser's constructor
//
function Parser(code) {
  this.code = code;
  this.lexer = ometajs.lexer.create(code);
  this.state = 'empty';
  this.active = true;

  // State information needed for AST creation
  this.ast = ['topLevel', []];
  this.current = this.ast[1];
  this.stack = [this.ast[1]];

  // Tokens history for look-ahead
  this.tokens = [];
  this.stagingTokens = [];
}

//
// ### function create (code)
// #### @code {String} input source code
// Returns Parser's instance
//
parser.create = function create(code) {
  return new Parser(code);
};

//
// ### function execute ()
// Returns AST of source code
//
Parser.prototype.execute = function execute() {
  while (this.active) {
    this.parseGrammar();
  }

  return this.ast;
};

//
// ### function parseGrammar ()
// Parser's routine
//
Parser.prototype.parseGrammar = function parseGrammar() {
  // ometa %GrammarName%
  if (!this.token('keyword', 'ometa')) return;
  this.state = 'grammar';
  this.push(['grammar', this.token('name').value]);

  // Nested grammars, <: %GrammarName%
  this.push(
    this.optional('punc', '<:') && this.commit() ?
        this.token('name').value
        :
        null
  );
  this.pop();

  // Prepare for rules
  this.token('punc', '{');
  this.push([]);

  this.parseUntil('punc', '}', function parseRules() {
    this.parseRule();
  });
  this.commit();

  this.pop();
  this.pop();

  this.state = 'empty';
};

//
// ### function parseRule ()
// Parser's routine
//
Parser.prototype.parseRule = function parseRule() {
  // Handle grammar end
  if (this.optional('punc', '}') && this.commmit()) {
    // Leave rules and grammar
    this.pop();
    this.pop();

    // Wait for next grammar
    return;
  }

  var name;

  // Rule name
  if (name = this.optional('name')) {
    this.commit();
    this.push(['rule', name.value]);
  } else {
    this.push(['rule', null]);
  }

  // Parse rule's expressions
  var end = this.parseUntil('punc', ['}', ','], function parseExpressions() {
    var end;

    // Parse left expression
    end = this.parseUntil('punc', ['=', ',', '}'], function parseLeft() {
      this.parseExpression('left');
      this.pop();
    });

    // Parse right expression
    if (matchToken(end, 'punc', '=')) {
      this.commit();
      end = this.parseUntil('punc', [',', '}'], function parseRight() {
        this.parseExpression('right');
        this.pop();
      });
    }

    this.fail();
  });

  if (end.value === ',') {
    // Continue parsing next rule
    this.commit();
  } else {
    // Let others parse '}'
    this.fail();
  }

  this.pop();
};

//
// ### function parseExpression (type)
// #### @type {String} left, right, interleave, parens
// Parser's routine
//
Parser.prototype.parseExpression = function parseExpression(type) {
  if (type === 'left') {
    var arg;

    // :name
    if (this.optional('punc', ':', true) && this.commit()) {
      arg = this.token('name');
      this.push(['arg', null, [], arg.value]);
    // rule(...args...) or rule(...args...):name
    } else if (arg = this.optional('name', null, true)) {
      this.commit();
      this.push(['arg', arg.value]);

      // Parse arguments
      this.push([]);
      if (this.optional('punc', '(')) {
        this.commit();
        this.parseUntil('punc', ')', function() {
          this.parseHostExpression();
          this.pop();
          if (this.optional('punc', ',')) this.commit();
        });
        this.commit();
      }
      this.pop();

      // Parse name
      if (this.optional('punc', ':', true) && this.commit()) {
        this.push(this.token('name').value);
      } else {
        this.token('space');
        this.push(null);
      }
      this.pop();
    // -> { javascript body }
    } else if (this.optional('punc', '->') && this.commit()) {
      this.push(['body']);
      this.parseHostExpression();
      this.pop();
    }
  } else if (type === 'right') {
    // Parse multiple choices for a rule's right side
    this.branch('choice', 'punc', '|', function parseChoices() {
      if (this.optional('punc', '(')) {
        this.commit();
        this.parseExpression('left');
        this.token('punc', ')');
      } else {
        this.parseExpression('left');
      }
    });
  }
};

//
// ### function parseHostExpression ()
// Parser's routine
//
Parser.prototype.parseHostExpression = function parseHostExpression() {
  var token,
      depth = 0,
      dived = false,
      code = [];

  for (;;) {
    token = this.optional(null, null, true)

    if (matchToken(token, 'punc', ['{', '(', '['])) {
      depth++;
      dived = true;
    } else if (matchToken(token, 'punc', ['}', ')', ']'])) {
      depth--;
      dived = true;
    }

    if (dived && depth < 0 || depth <= 0 && matchToken(token, 'punc', ',')) {
      this.fail();
      break;
    }

    this.commit();

    code.push(
      (token.type === 'string' || token.type === 'token') ?
        JSON.stringify(token.value)
        :
        token.value
    );
  }

  this.push(code.join(''));
};

//
// ### function branch (op, type, value, parse)
// #### @op {String}
// #### @type {String}
// #### @value {String|Array}
// #### @parse {Function}
// Parser's helper
//
Parser.prototype.branch = function branch(op, type, value, parse) {
  var token;
  do {
    if (token) {
      // Wrap previous expression into a branch
      this.wrap([op, token.value]);
      // Commit token
      this.commit();
    }
    parse.call(this);
  } while (this.active && (token = this.optional(type, value)));
  this.fail();
};

//
// ### function parseUntil (type, value, parse)
// #### @type {String}
// #### @value {String|Array}
// #### @parse {Function}
// Parser's helper
//
Parser.prototype.parseUntil = function parseUntil(type, value, parse) {
  var end;
  while (this.active && !(end = this.optional(type, value))) {
    parse.call(this);
  }

  return end;
};

//
// ### function matchToken (token, type, value)
// #### @type {String} (optional) required token type
// #### @value {String|Array} (optional) required token value or values
// Checks if token match type and value
//
function matchToken(token, type, value) {
  return (!type || token.type === type) &&
         (!value || (
           Array.isArray(value) ?
               value.indexOf(token.value) !== -1
               :
               token.value === value
         ));
}

//
// ### function token (type, value)
// #### @type {String} (optional) required token type
// #### @value {String|Array} (optional) required token value, or values
// #### @space {Boolean} (optional) do not parse spaces automatically
// #### @optional {Boolean} (optional) is that token optional?
// Demand token (may throw error)
//
Parser.prototype.token = function token(type, value, space, optional) {
  var token = this.tokens.length ? this.tokens.shift() : this.lexer.token();

  // End of file
  if (!token) {
    if (this.state === 'empty' || optional && type === 'space') {
      this.active = false;
      return token;
    } else {
      throw new Error('Unexpected end of file, ' + type + ' expected');
    }
  }

  // Push token to staging if we was matching optionally
  if (optional) this.stagingTokens.push(token);

  // Check if token matches our conditions
  if (matchToken(token, type, value)) {
    // Skip space automatically
    if (!space && type !== 'space') {
      if (this.tokens.length) {
        if (this.tokens[0].type === 'space') this.tokens.shift();
      } else {
        this.lexer.trim();
      }
    }

    return token;
  } else {
    if (optional) {
      this.fail();
      return false;
    } else {
      this.unexpected(token, type, value);
    }
  }
};

//
// ### function optional (type, value)
// #### @type {String} (optional) required token type
// #### @value {String} (optional) required token value
// #### @space {Boolean} (optional) do not parse spaces automatically
// Look ahead, wrapper for .token()
//
Parser.prototype.optional = function optional(type, value, space) {
  return this.token(type, value, space, true);
};

//
// ### function commit ()
// Removes all tokens from staging history
// Call it after .optional() if you matched
//
Parser.prototype.commit = function commit() {
  this.stagingTokens = [];
  return true;
};

//
// ### function fail ()
// Adds tokens from stage to actual history
// Call it after .optional() if you haven't matched
//
Parser.prototype.fail = function fail() {
  this.tokens = this.tokens.concat(this.stagingTokens);
  this.stagingTokens = [];
  return true;
};

//
// ### function unexpected (token, type, value)
// #### @token {Object} Source token
// #### @type {String} Expected type
// #### @value {String} Expected value
// Throws pretty error
//
Parser.prototype.unexpected = function unexpected(token, type, value) {
  throw new Error('Expected [type: ' + type + ' value: ' + value + '] ' +
                  'token, but found [type: ' + token.type + ' value: ' +
                  token.value + ']');
};

//
// ### function push (node)
// #### @node {Array} AST Node
// Pushes node into AST tree and stack
//
Parser.prototype.push = function push(node) {
  this.current.push(node);
  this.stack.push(node);
  this.current = node;
};

//
// ### function wrap (node)
// #### @node {Array} AST Node
// Wraps curent node into passed one
//
Parser.prototype.wrap = function wrap(node) {
  var wrapped = node.concat([this.current]);
  this.stack[this.stack.length - 1] = wrapped;
  return this.current = wrapped;
}

//
// ### function pop ()
// Pops node from stack
//
Parser.prototype.pop = function pop() {
  var result = this.stack.pop();

  this.current = this.stack[this.stack.length - 1];

  return result;
};
<|endoftext|>


<commit_before>/**
* A draw.io plugin for parsing a sitemap XML or spreadsheet into
* a sitemap diagram showing the root with their children sites.
* Author: eduardomourar@gmail.com
* Company: Crossover Marketing
* Created: 2015-12-21
*/
Draw.loadPlugin(function(ui) {
    /* Finding assigned keys:
      * Open javascript console
      * Draw.valueOf()
      * Traverse to: Object > loadPlugin > <function scope>
                    > ui > keyHandler > controlShiftKeys
      * The number here is ASCII character code
    */

    // Adds resources for actions
    mxResources.parse('fromSitemap=From Sitemap');
    mxResources.parse('fromSitemapXmlFile=From Sitemap XML File');

    // Adds action : fromSitemap
    ui.actions.addAction('fromSitemap', function() {
    	ui.showDialog(new InsertSitemap(ui).container, 620, 420, true, true);
    	ui.dialog.container.style.overflow = 'auto';
    }, null, null, '');

    ui.keyHandler.bindAction(81, !0, 'fromSitemap', !0);

    // Adds action : fromSitemapXmlFile
    ui.actions.addAction('fromSitemapXmlFile', function() {
    	ui.showDialog(new ParseDialog(ui).container, 620, 420, true, true);
    	ui.dialog.container.style.overflow = 'auto';
    }, null, null, '');

    ui.keyHandler.bindAction(81, !0, 'fromSitemapXmlFile', !0);

    var uiMenus = ui.menus;

    // Adds menu
    ui.menubar.addMenu('Sitemap', function(menu, parent) {
       uiMenus.addMenuItem(menu, 'fromSitemap');
       //uiMenus.addMenuItem(menu, 'fromSitemapXmlFile');
    });

	/* Replaces import from menu to add new menu item
	uiMenus.put("importFrom", new Menu(mxUtils.bind(uiMenus, function(menu, parent) {
		uiMenus.addMenuItems(menu, "googleDrive dropbox oneDrive - url - fromSitemapXmlFile".split(" "), parent)
	})));

	// Replaces insert menu to add new menu item
	uiMenus.put("insert", new Menu(mxUtils.bind(uiMenus, function(menu, parent) {
        uiMenus.addMenuItems(menu, "insertText insertRectangle insertEllipse - insertLink insertImage - ".split(" "), parent)
        uiMenus.addMenuItems(menu, "horizontalFlow verticalFlow - horizontalTree verticalTree - organic circle - fromText  - fromSitemapText".split(" "), parent);
	})));*/

    // Reorders menubar
    ui.menubar.container
      .insertBefore(ui.menubar.container.lastChild,
                    ui.menubar.container.lastChild.previousSibling.previousSibling);

    // Displays status message
    ui.editor.setStatus('ParseSitemap plugin loaded successfully!');

    /**
	 * Constructs a new dialog for sitemap insert.
	 */
	function InsertSitemap(editorUi) {
		function parse(text) {
			var lines = text.split('\n');
			var vertices = new Object();
			var cells = [];

			function getOrCreateVertex(id) {
				var newVertex = vertices[id];

				if (newVertex == null) {
					var label = id.match(/\/([^\/]+)\/[^\/]+$/);
					newVertex = new mxCell(label, new mxGeometry(0, 0, 80, 30));
					newVertex.vertex = true;
					newVertex.setAttribute('link', id + '/');
					vertices[id] = newVertex;
					cells.push(newVertex);
				}

				return newVertex;
			};

			for (var i = 0; i < lines.length; i++) {
				if (lines[i].charAt(0) != ';') {

					var values = lines[i].split('/'),
						len = values.length;

					if (!values[len - 1]) {
						values.slice(0, -1);
					}

					if (len > 1) {
						var target = getOrCreateVertex(values.join('/'));
						values.slice(0, -1);
						var source = getOrCreateVertex(values.join('/'));

						var newEdge = new mxCell('', new mxGeometry());
						newEdge.edge = true;
						source.insertEdge(newEdge, true);
						target.insertEdge(newEdge, false);
						cells.push(newEdge);
					}
				}
			}

			if (cells.length > 0) {
				var graph = editorUi.editor.graph;

				graph.getModel().beginUpdate();
				try {
					cells = graph.importCells(cells);

					for (var i = 0; i < cells.length; i++) {
						if (graph.getModel().isVertex(cells[i])) {
							var size = graph.getPreferredSizeForCell(cells[i]);
							cells[i].geometry.width = Math.max(cells[i].geometry.width, size.width);
							cells[i].geometry.height = Math.max(cells[i].geometry.height, size.height);
						}
					}

					var layout = new mxFastOrganicLayout(graph);
					layout.disableEdgeStyle = false;
					layout.forceConstant = 120;
					layout.execute(graph.getDefaultParent());

					graph.moveCells(cells, 20, 20);
				}
				finally {
					graph.getModel().endUpdate();
				}
			}
		};

		var div = document.createElement('div');
		div.style.textAlign = 'right';

		var textarea = document.createElement('textarea');
		textarea.style.width = '600px';
		textarea.style.height = '374px';

		textarea.value = ';example\nhttp://www.chrisplaw.com/bus-accidents/\nhttp://www.chrisplaw.com/car-accidents/\nhttp://www.chrisplaw.com/car-accidents/compensation/\nhttp://www.chrisplaw.com/car-accidents/what-do-i-need-to-do/\n';
		div.appendChild(textarea);

		// Enables dropping files
		if (fileSupport) {
			function handleDrop(evt) {
			    evt.stopPropagation();
			    evt.preventDefault();

			    if (evt.dataTransfer.files.length > 0) {
			    	var file = evt.dataTransfer.files[0];

					var reader = new FileReader();
					reader.onload = function(e) { textarea.value = e.target.result; };
					reader.readAsText(file);
	    		}
			};

			function handleDragOver(evt) {
				evt.stopPropagation();
				evt.preventDefault();
			};

			// Setup the dnd listeners.
			textarea.addEventListener('dragover', handleDragOver, false);
			textarea.addEventListener('drop', handleDrop, false);
		}

		div.appendChild(mxUtils.button(mxResources.get("insert"), function() {
			parse(textarea.value);
			editorUi.hideDialog();
		}));

		div.appendChild(mxUtils.button(mxResources.get('cancel'), function() {
			evt.confirm(mxResources.get("areYouSure"), function() {
                editorUi.hideDialog();
            });
		}));

		this.container = div;
	};

});
<commit_msg>Release 0.2<commit_after>/**
* A draw.io plugin for parsing a sitemap XML or spreadsheet into
* a sitemap diagram showing the root with their children sites.
* Author: eduardomourar@gmail.com
* Company: Crossover Marketing
* Created: 2015-12-21
*/
Draw.loadPlugin(function(ui) {
    /* Finding assigned keys:
      * Open javascript console
      * Draw.valueOf()
      * Traverse to: Object > loadPlugin > <function scope>
                    > ui > keyHandler > controlShiftKeys
      * The number here is ASCII character code
    */

    // Adds resources for actions
    mxResources.parse('fromSitemap=Insert from Sitemap');
    mxResources.parse('fromSitemapXmlFile=From Sitemap XML File');

    // Adds action : fromSitemap
    ui.actions.addAction('fromSitemap', function() {
    	ui.showDialog(new InsertSitemap(ui).container, 620, 420, true, true);
    	ui.dialog.container.style.overflow = 'auto';
    }, null, null, '');

    ui.keyHandler.bindAction(81, !0, 'fromSitemap', !0);

    // Adds action : fromSitemapXmlFile
    ui.actions.addAction('fromSitemapXmlFile', function() {
    	ui.showDialog(new ParseDialog(ui).container, 620, 420, true, true);
    	ui.dialog.container.style.overflow = 'auto';
    }, null, null, '');

    ui.keyHandler.bindAction(81, !0, 'fromSitemapXmlFile', !0);

    var uiMenus = ui.menus;

    // Adds menu
    ui.menubar.addMenu('Sitemap', function(menu, parent) {
       uiMenus.addMenuItem(menu, 'fromSitemap');
       //uiMenus.addMenuItem(menu, 'fromSitemapXmlFile');
    });

	/* Replaces import from menu to add new menu item
	uiMenus.put("importFrom", new Menu(mxUtils.bind(uiMenus, function(menu, parent) {
		uiMenus.addMenuItems(menu, "googleDrive dropbox oneDrive - url - fromSitemapXmlFile".split(" "), parent)
	})));

	// Replaces insert menu to add new menu item
	uiMenus.put("insert", new Menu(mxUtils.bind(uiMenus, function(menu, parent) {
        uiMenus.addMenuItems(menu, "insertText insertRectangle insertEllipse - insertLink insertImage - ".split(" "), parent)
        uiMenus.addMenuItems(menu, "horizontalFlow verticalFlow - horizontalTree verticalTree - organic circle - fromText  - fromSitemapText".split(" "), parent);
	})));*/

    // Reorders menubar
    ui.menubar.container
      .insertBefore(ui.menubar.container.lastChild,
                    ui.menubar.container.lastChild.previousSibling.previousSibling);

    // Displays status message
    ui.editor.setStatus('ParseSitemap plugin loaded successfully!');

    /**
	 * Constructs a new dialog for sitemap insert.
	 */
	function InsertSitemap(editorUi) {
		function parse(text) {
			var lines = text.split('\n');
			var vertices = new Object();
			var cells = [];

			function getOrCreateVertex(id) {
				var newVertex = vertices[id];

				if (newVertex == null) {
					var label = id.match(/\/([^\/]+)[\/]?$/);
					newVertex = new mxCell(label[1], new mxGeometry(0, 0, 80, 30),  id + '/');
					newVertex.vertex = true;
					vertices[id] = newVertex;
					cells.push(newVertex);
				}

				return newVertex;
			};

			for (var i = 0; i < lines.length; i++) {
				if (lines[i].charAt(0) != ';') {

					var values = lines[i].split('/');

					if (!values[values.length - 1]) {
						values = values.slice(0, -1);
					}

					if (values.length > 1) {
						var target = getOrCreateVertex(values.join('/'));
						values = values.slice(0, -1);
						if (values.length > 2) {
							var source = getOrCreateVertex(values.join('/'));

							var newEdge = new mxCell('', new mxGeometry());
							newEdge.edge = true;
							source.insertEdge(newEdge, true);
							target.insertEdge(newEdge, false);
							cells.push(newEdge);
						}
					}
				}
			}

			if (cells.length > 0) {
				var graph = editorUi.editor.graph;

				graph.getModel().beginUpdate();
				try {
					cells = graph.importCells(cells);

					for (var i = 0; i < cells.length; i++) {
						if (graph.getModel().isVertex(cells[i])) {
							var size = graph.getPreferredSizeForCell(cells[i]);
							graph.setLinkForCell(cells[i], cells[i].getStyle());
							cells[i].setStyle = null;
							cells[i].geometry.width = Math.max(cells[i].geometry.width, size.width);
							cells[i].geometry.height = Math.max(cells[i].geometry.height, size.height);
						}
					}

					var layout = new mxCompactTreeLayout(graph, false);
					layout.disableEdgeStyle = false;
					layout.forceConstant = 120;
					layout.execute(graph.getDefaultParent());

					graph.moveCells(cells, 20, 20);
				}
				finally {
					graph.getModel().endUpdate();
				}
			}
		};

		var div = document.createElement('div');
		div.style.textAlign = 'right';

		var textarea = document.createElement('textarea');
		textarea.style.width = '600px';
		textarea.style.height = '374px';

		textarea.value = ';example\nhttp://www.chrisplaw.com/bus-accidents/\nhttp://www.chrisplaw.com/car-accidents/\nhttp://www.chrisplaw.com/car-accidents/compensation/\nhttp://www.chrisplaw.com/car-accidents/what-do-i-need-to-do/\n';
		div.appendChild(textarea);

		// Enables dropping files
		if (fileSupport) {
			function handleDrop(evt) {
			    evt.stopPropagation();
			    evt.preventDefault();

			    if (evt.dataTransfer.files.length > 0) {
			    	var file = evt.dataTransfer.files[0];

					var reader = new FileReader();
					reader.onload = function(e) { textarea.value = e.target.result; };
					reader.readAsText(file);
	    		}
			};

			function handleDragOver(evt) {
				evt.stopPropagation();
				evt.preventDefault();
			};

			// Setup the dnd listeners.
			textarea.addEventListener('dragover', handleDragOver, false);
			textarea.addEventListener('drop', handleDrop, false);
		}

		div.appendChild(mxUtils.button(mxResources.get("insert"), function() {
			parse(textarea.value);
			editorUi.hideDialog();
		}));

		div.appendChild(mxUtils.button(mxResources.get('cancel'), function() {
			editorUi.hideDialog();
		}));

		this.container = div;
	};
});
<|endoftext|>


<commit_before>var creep_assattacker = {

    /** @param {Creep} creep **/
    run: function(creep) {

        var healerSquad = creep.pos.findInRange(FIND_MY_CREEPS, 2, {
            filter: (mCreep) => (mCreep.memory.priority == "asshealer")
        });
        var closeFoe = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {
            filter: (eCreep) => (!Memory.whiteList.includes(eCreep.owner.username))
        });
        if (closeFoe) {
            //This attack will be overridden if attacking a structure
            creep.attack(closeFoe);
        }

        if (healerSquad.length && healerSquad.length < 2) {
            if (Game.flags["RallyHere"] && Game.flags["RallyHere"].pos.roomName != creep.pos.roomName) {
                //Probably in a new room, hold.
                if (creep.pos.x == 0 || creep.pos.x == 49 || creep.pos.y == 0 || creep.pos.y == 49) {
                    var xTarget = 1;
                    var yTarget = 1;
                    if (creep.pos.x == 49) {
                        xTarget = 48;
                    }
                    if (creep.pos.y = 49) {
                        yTarget = 48;
                    }
                    creep.moveTo(xTarget, yTarget);
                }
            } else {
                if (!creep.memory.getOutOfStartRoom) {
                    creep.moveTo(Game.flags["RallyHere"]);
                } else {
                    creep.moveTo(Game.flags["Assault"]);
                }
            }
        } else if (healerSquad.length && healerSquad.length == 2) {
            creep.memory.getOutOfStartRoom = true;

            if (Game.flags["Assault"] && Game.flags["Assault"].pos.roomName != creep.pos.roomName) {
                creep.moveTo(new RoomPosition(25, 25, Game.flags["Assault"].pos.roomName));
            } else {
                //In target room
                var eTowers = creep.room.find(FIND_HOSTILE_STRUCTURES, {
                    filter: (structure) => (structure.structureType == STRUCTURE_TOWER)
                });
                if (eTowers.length) {
                    creep.moveTo(eTowers[0]);
                    creep.attack(eTowers[0]);
                } else {
                    var eSpawns = creep.room.find(FIND_HOSTILE_SPAWNS)
                    if (eSpawns.length) {
                        creep.moveTo(eSpawns[0]);
                        creep.attack(eSpawns[0]);
                    } else {
                        var eStructures = creep.room.find(FIND_HOSTILE_STRUCTURES)
                        if (eStructures.length) {
                            creep.moveTo(eStructures[0]);
                            creep.attack(eStructures[0]);
                        } else if (closeFoe) {
                            creep.moveTo(closeFoe);
                        }
                    }
                }
            }
        } else {
            if (Game.flags["RallyHere"]) {
                creep.moveTo(Game.flags["RallyHere"]);
            }
        }

    }

};

module.exports = creep_assattacker;<commit_msg>good shit<commit_after>var creep_assattacker = {

    /** @param {Creep} creep **/
    run: function(creep) {

        var healerSquad = creep.pos.findInRange(FIND_MY_CREEPS, 2, {
            filter: (mCreep) => (mCreep.memory.priority == "asshealer")
        });
        var closeFoe = creep.pos.findClosestByRange(FIND_HOSTILE_CREEPS, {
            filter: (eCreep) => (!Memory.whiteList.includes(eCreep.owner.username))
        });
        if (closeFoe) {
            //This attack will be overridden if attacking a structure
            creep.attack(closeFoe);
        }

        if (healerSquad.length && healerSquad.length < 2) {
            if (Game.flags["RallyHere"] && Game.flags["RallyHere"].pos.roomName != creep.pos.roomName) {
                //Probably in a new room, hold.
                if (creep.pos.x == 0 || creep.pos.x == 49 || creep.pos.y == 0 || creep.pos.y == 49) {
                    var xTarget = 1;
                    var yTarget = 1;
                    if (creep.pos.x == 49) {
                        xTarget = 48;
                    }
                    if (creep.pos.y = 49) {
                        yTarget = 48;
                    }
                    creep.moveTo(xTarget, yTarget);
                }
            } else {
                if (!creep.memory.getOutOfStartRoom) {
                    creep.moveTo(Game.flags["RallyHere"]);
                } else {
                    creep.moveTo(Game.flags["Assault"]);
                }
            }
        } else if (healerSquad.length && healerSquad.length == 2) {
            creep.memory.getOutOfStartRoom = true;

            if (Game.flags["Assault"] && Game.flags["Assault"].pos.roomName != creep.pos.roomName) {
                creep.moveTo(new RoomPosition(25, 25, Game.flags["Assault"].pos.roomName));
            } else {
                //In target room
                var eTowers = creep.room.find(FIND_HOSTILE_STRUCTURES, {
                    filter: (structure) => (structure.structureType == STRUCTURE_TOWER)
                });
                if (eTowers.length) {
                    creep.moveTo(eTowers[0], {
                        ignoreDestructibleStructures: true
                    });
                    creep.attack(eTowers[0]);
                } else {
                    var eSpawns = creep.room.find(FIND_HOSTILE_SPAWNS)
                    if (eSpawns.length) {
                        creep.moveTo(eSpawns[0], {
                            ignoreDestructibleStructures: true
                        });
                        creep.attack(eSpawns[0]);
                    } else {
                        var eStructures = creep.room.find(FIND_HOSTILE_STRUCTURES)
                        if (eStructures.length) {
                            creep.moveTo(eStructures[0], {
                                ignoreDestructibleStructures: true
                            });
                            creep.attack(eStructures[0]);
                        } else if (closeFoe) {
                            creep.moveTo(closeFoe);
                        }
                    }
                }
            }
        } else {
            if (Game.flags["RallyHere"]) {
                creep.moveTo(Game.flags["RallyHere"]);
            }
        }

    }

};

module.exports = creep_assattacker;<|endoftext|>


<commit_before>#!/usr/bin/env node
var fs = require("fs");
var net = require("net");
var tls = require("tls");
var path = require("path");
var url = require("url");
var util = require("util");

var mkdirp = require('mkdirp');
var async = require("async");
var dmp_module = require("diff_match_patch");
var DMP = new dmp_module.diff_match_patch();
var open_url = require("open");
var optimist = require("optimist");
var _ = require("lodash");

var lib = require("./lib");
var log = lib.log;
var api = lib.api;

log.set_log_level("log");

var parse_url = function (workspace_url) {
  var parsed_url,
    re = /\/r\/([\-\@\+\.\w]+)\/([\-\w]+)/,
    res;
  try {
    parsed_url = url.parse(workspace_url);
    res = parsed_url.path.match(re);
  } catch (e) {
    log.error('The workspace must be a valid url:', workspace_url);
    process.exit(1);
  }
  return {
    host: parsed_url.hostname,
    port: parsed_url.protocol === "http" ? 3148 : 3448,
    klass: parsed_url.protocol === "http" ? net : tls,
    owner: res && res[1],
    secure: parsed_url.protocol === "https",
    workspace: res && res[2]
  };
};

var to_browser_url = function (secure, hostname, owner, workspace_name) {
  var protocol = secure ? "https" : "http";
  return util.format("%s://%s/r/%s/%s/", protocol, hostname, owner, workspace_name);
};

var parse_floorc = function () {
  var floorc = {},
    floorc_path,
    floorc_lines;

  try {
    floorc_path = path.join(process.env[(process.platform === "win32") ? "USERPROFILE" : "HOME"], ".floorc");
    /*jslint stupid: true */
    floorc_lines = fs.readFileSync(floorc_path, "utf-8").split("\n");
    /*jslint stupid: false */
    _.each(floorc_lines, function (line) {
      var space,
        key,
        value;
      /*jslint regexp: true */
      if (line.match(/^\s*#.*/)) {
        return;
      }
      /*jslint regexp: false */
      space = line.indexOf(" ");
      key = line.slice(0, space).toLowerCase();
      value = line.slice(space + 1);
      floorc[key] = value;
    });
  } catch (e) {
    log.error("no ~/.floorc file was found");
  }
  return floorc;
};

var parse_dot_floo = function () {
  var floo_file,
    parsed_url = {},
    data = lib.utils.load_floo();

  parsed_url = data.url ? parse_url(data.url) : {};

  return parsed_url;
};

var parse_args = function (floorc) {
  var parsed_url = parse_dot_floo();

  return optimist
    .usage('Usage: $0 --join [url] --share -o [owner] -w [workspace] --read-only --verbose [path_to_sync]')
    .default('H', parsed_url.host || 'floobits.com')
    .default('p', 3448)
    .describe('join', "The URL of the workspace to join (cannot be used with share).")
    .describe('share', 'Creates a new workspace if possible. Otherwise, it will sync local files to the existing workspace.')
    .describe('w', 'The Floobits Workspace.')
    .default('w', parsed_url.workspace)
    .describe('o', 'The owner of the Workspace. Defaults to the .floo file\'s owner or your ~/.floorc username.')
    .default('o', parsed_url.owner || floorc.username)
    .describe('read-only', 'Will not send patches for local modifications (Always enabled for OS X).')
    .describe('H', 'Host to connect to. For debugging/development. Defaults to floobits.com.')
    .describe('p', 'Port to use. For debugging/development. Defaults to 3448.')
    .demand(['H', 'p'])
    .argv;
};

exports.run = function () {
  var cwd = process.cwd(),
    floorc = parse_floorc(),
    floo_file,
    data,
    parsed_url,
    series = [function (cb) { cb(); }],
    raw_hooks = {},
    args = parse_args(floorc),
    _path;

  if (args._.length === 0) {
    _path = process.cwd();
  } else if (args._.length === 1) {
    _path = args._[0];
  } else {
    throw new Error("Invalid arguments. Only one path is allowed.");
  }

  if (args.verbose) {
    log.set_log_level("debug");
  }

  if (args.help || args.h) {
    optimist.showHelp();
    process.exit(0);
  }

  args.o = args.o || floorc.username;
  if (args.share && args.share === true) {
    args.share = path.basename(process.cwd());
  }
  args.w = args.share || args.w;

  if (args.join) {
    parsed_url = parse_url(args.join);
    args.w = parsed_url.workspace;
    args.o = parsed_url.owner;
  }

  if (!args.w) {
    optimist.showHelp();
    log.error('I need a workspace name.');
    process.exit(0);
  }

  if (args.share) {
    series.push(api.create.bind(api, args.H, floorc.username, args.o, floorc.secret, args.w, args.perms));
  }

  if (!args['read-only']) {
    series.push(open_url.bind(null, to_browser_url(args.p === 3448, args.H, args.o, args.w)));
  }

  async.series(series, function (err) {
    var floo_conn;

    if (err) {
      return log.error(err);
    }

    mkdirp.sync(_path);
    floo_conn = new lib.FlooConnection(_path, floorc, args);
    floo_conn.connect();
  });
};
<commit_msg>Better arg stuff<commit_after>#!/usr/bin/env node
var fs = require("fs");
var net = require("net");
var tls = require("tls");
var path = require("path");
var url = require("url");
var util = require("util");

var mkdirp = require('mkdirp');
var async = require("async");
var dmp_module = require("diff_match_patch");
var DMP = new dmp_module.diff_match_patch();
var open_url = require("open");
var optimist = require("optimist");
var _ = require("lodash");

var lib = require("./lib");
var log = lib.log;
var api = lib.api;

log.set_log_level("log");

var parse_url = function (workspace_url) {
  var parsed_url,
    re = /\/r\/([\-\@\+\.\w]+)\/([\-\w]+)/,
    res;
  try {
    parsed_url = url.parse(workspace_url);
    res = parsed_url.path.match(re);
  } catch (e) {
    log.error('The workspace must be a valid url:', workspace_url);
    process.exit(1);
  }
  return {
    host: parsed_url.hostname,
    port: parsed_url.protocol === "http" ? 3148 : 3448,
    klass: parsed_url.protocol === "http" ? net : tls,
    owner: res && res[1],
    secure: parsed_url.protocol === "https",
    workspace: res && res[2]
  };
};

var to_browser_url = function (secure, hostname, owner, workspace_name) {
  var protocol = secure ? "https" : "http";
  return util.format("%s://%s/r/%s/%s/", protocol, hostname, owner, workspace_name);
};

var parse_floorc = function () {
  var floorc = {},
    floorc_path,
    floorc_lines;

  try {
    floorc_path = path.join(process.env[(process.platform === "win32") ? "USERPROFILE" : "HOME"], ".floorc");
    /*jslint stupid: true */
    floorc_lines = fs.readFileSync(floorc_path, "utf-8").split("\n");
    /*jslint stupid: false */
    _.each(floorc_lines, function (line) {
      var space,
        key,
        value;
      /*jslint regexp: true */
      if (line.match(/^\s*#.*/)) {
        return;
      }
      /*jslint regexp: false */
      space = line.indexOf(" ");
      key = line.slice(0, space).toLowerCase();
      value = line.slice(space + 1);
      floorc[key] = value;
    });
  } catch (e) {
    log.error("no ~/.floorc file was found");
  }
  return floorc;
};

var parse_dot_floo = function () {
  var floo_file,
    parsed_url = {},
    data = lib.utils.load_floo();

  parsed_url = data.url ? parse_url(data.url) : {};

  return parsed_url;
};

var parse_args = function (floorc) {
  var parsed_url = parse_dot_floo();

  return optimist
    .usage('Usage: $0 --join [url] --share -o [owner] -w [workspace] --read-only --verbose [path_to_sync]')
    .default('H', parsed_url.host || 'floobits.com')
    .default('p', 3448)
    .describe('join', "The URL of the workspace to join (cannot be used with --share).")
    .describe('share', 'Creates a new workspace if possible. Otherwise, it will sync local files to the existing workspace.')
    .boolean('share')
    .describe('w', 'The Floobits Workspace.')
    .default('w', parsed_url.workspace)
    .describe('o', 'The owner of the Workspace. Defaults to the .floo file\'s owner or your ~/.floorc username.')
    .default('o', parsed_url.owner || floorc.username)
    .describe('read-only', 'Will not send patches for local modifications (Always enabled for OS X).')
    .describe('H', 'Host to connect to. For debugging/development. Defaults to floobits.com.')
    .describe('p', 'Port to use. For debugging/development. Defaults to 3448.')
    .describe('verbose', 'Enable debugging output.')
    .demand(['H', 'p'])
    .argv;
};

exports.run = function () {
  var cwd = process.cwd(),
    floorc = parse_floorc(),
    floo_file,
    data,
    parsed_url,
    series = [function (cb) { cb(); }],
    raw_hooks = {},
    args = parse_args(floorc),
    _path;

  if (args._.length === 0) {
    _path = cwd;
  } else if (args._.length === 1) {
    _path = args._[0];
  } else {
    throw new Error("Invalid arguments. Only one path is allowed.");
  }
  _path = path.resolve(_path);
  _path = path.normalize(_path);

  if (args.verbose) {
    log.set_log_level("debug");
  }

  if (args.help || args.h) {
    optimist.showHelp();
    process.exit(0);
  }

  args.o = args.o || floorc.username;
  if (args.share && args.share === true) {
    args.share = _path;
  }
  args.w = args.share || args.w;

  if (args.join) {
    parsed_url = parse_url(args.join);
    args.w = parsed_url.workspace;
    args.o = parsed_url.owner;
  }

  if (!args.w) {
    optimist.showHelp();
    log.error('I need a workspace name.');
    process.exit(0);
  }

  if (args.share) {
    series.push(api.create.bind(api, args.H, floorc.username, args.o, floorc.secret, args.w, args.perms));
  }

  if (!args['read-only']) {
    series.push(open_url.bind(null, to_browser_url(args.p === 3448, args.H, args.o, args.w)));
  }

  async.series(series, function (err) {
    var floo_conn;

    if (err) {
      return log.error(err);
    }

    mkdirp.sync(_path);
    floo_conn = new lib.FlooConnection(_path, floorc, args);
    floo_conn.connect();
  });
};
<|endoftext|>


<commit_before>'use strict';

var node_path   = require('path');
var node_url    = require('url');
var lang        = require('../util/lang');
var pkg_helper  = require('../util/package');
var async       = require('async');

exports.shorthands = {
  c: 'cwd',
  r: 'recursive'
};

exports.options = {

  // Indicates that user want to save something into package.json
  // _save: {
  //   type: Boolean,
  //   enumerable: false,
  //   default: false
  // },

  recursive: {
    type: Boolean,
    info: 'install all dependencies recursively. If `false`, cortex will only download the current module.',
    default: true
  },

  cwd: {
    type: node_path,
    info: 'current working directory.',
    // `cortex install` could be executed anywhere
    default: process.cwd(),
    setter: function(cwd) {
      var done = this.async();
      // if not inside a project, returns null
      pkg_helper.repo_root(this.get('cwd'), function (cwd) {
        done(null, cwd);
      });
    }
  },

  // if --save --save-async, --save-async will be ignored
  save: {
    type: Boolean,
    info: 'package will appear in your "cortex.dependencies" of package.json.',
    validator: save_check_package
  },

  'save-async': {
    type: Boolean,
    info: 'package will appear in your "cortex.asyncDependencies" of package.json.',
    validator: save_check_package
  },

  'save-dev': {
    type: Boolean,
    info: 'package will appear in your "cortex.devDependencies" of package.json.',
    validator: save_check_package
  },

  clone: {
    type: Boolean,
    info: 'try to clone the package repo down to the workspace.',
    default: false
  },

  production: {
    type: Boolean,
    info: 'ignore "devDependencies". Only works when not explicitly specify module to install',
    default: false
  },

  modules: {
    // command line type: String
    // programmatical type: Array.<string>
    info: 'modules to install. if not specified, cortex will read them from your package.json. if you install a module without version, cortex will try to install the latest one.',
    setter: function(modules) {
      var done = this.async();
      var remain = this.get('_') || [];

      exports._get_modules({
        remain: remain,
        cwd: this.get('cwd'),
        save: this.get('_save'),
        production: this.get('production'),
        modules: modules

      }, done);
    }
  }
};

function save_check_package(save) {
  var done = this.async();

  // if --save, package.json must exists
  if (save) {
    var cwd = this.get('cwd');

    // 'cortex install' might be called inside a subtle directory of the project.
    if (cwd === null) {
      return done('package.json not found, could not save dependencies');
    }

    this.set('cwd', cwd);
    // options._save: internal use
    this.set('_save', true);
  }

  done(null);
}

// @param {Object} options
// - pkg
// - cwd
// - save
// - remain
exports._get_modules = function(options, callback) {
  var parsed_modules = [];

  // Invalid value
  // ```
  // cortex install --modules
  // ```
  if (options.modules === true) {
    return callback({
      code: 'EINVALID',
      message: 'invalid value of option --modules, which must be specified.',
      data: {
        option: 'modules'
      }
    });
  }

  // 1.
  // Install modules which explicitly defined in option --modules
  // ```
  // #　could be executed anywhere
  // cortex install --modules ajax,lang
  // ```
  if (options.modules) {
    parsed_modules = options.modules.split(/\s*,\s*/);
  }

  // 2.
  // Install modules in argv.remain
  // ```
  // #　could be executed anywhere
  // cortex install ajax lang
  // ```

  // Object `remain` might be a mocked argv object,
  // so, be careful, and do some tests
  if (!parsed_modules.length && options.remain.length) {
    parsed_modules = options.remain;
  }

  if (options.save) {
    // if --save or --save-async,
    // there must inside a repo, or we will not be able to save dependencies
    if (!parsed_modules.length) {
      return callback({
        code: 'ENONETOSAVE',
        message: 'if --save, you must specify the modules to install.'
      });
    }
    // else we should check the modules

  } else {
    if (parsed_modules.length) {
      return callback(null, exports._santitize_modules(parsed_modules));
    }
    // else we will fetch modules from dependencies
  }

  // 3.
  // Install modules from dependencies of package.json,
  // ```
  // # in this case, must executed inside a repo
  // cortex install
  // ```

  if (cwd === null) {
    if (options.save) {
      return callback({
        code: 'ECOULDNOTSAVE',
        message: 'Directory "' + cwd + '" is not inside a repo, could not save dependencies.',
        data: {
          cwd: cwd
        }
      });

    } else {
      return callback({
        code: 'ENOTAREPO',
        message: 'Directory "' + cwd + '" is not inside a repo, could not fetch dependencies.',
        data: {
          cwd: cwd
        }
      });
    }
  }

  exports._get_pkg(cwd, function(err, pkg) {
    if (err) {
      return callback(err);
    }

    // Including all versions
    var deps_map = exports._get_all_deps(pkg, options.production);

    // We will not check `cortex install`
    if (!parsed_modules.length) {

      // If `deps_map` is an empty object, we will allow this.
      // Users might exec `cortex install` inside a repo which has no deps.
      return callback(null, exports._make_deps_array(deps_map));
    }

    // if --save, we should not install more than one version of a certain module
    var allow_duplicate_versions = !options.save;

    exports._check_modules(parsed_modules, pkg, function(err) {
      if (err) {
        return callback(err);
      }

      callback(null, exports._santitize_modules(parsed_modules));

    }, allow_duplicate_versions);
  });
};

exports._get_pkg = function(cwd, callback) {
  pkg_helper.get_original_package(cwd, callback);
};

exports._get_all_deps = function(pkg, production) {
  var deps_obj = {};

  var keys = ['dependencies', 'asyncDependencies'];
  // When user executes `cortex install --production`,
  // cortex will not install devDependencies
  if (!production) {
    keys.push('devDependencies');
  }

  // But cortex will not install
  // 'asyncDependencies' and 'devDependencies' recursively which handled by neuropil.
  keys.forEach(function(key) {
    lang.mix(deps_obj, pkg[key]);
  });

  return deps_obj;
};

exports._make_deps_array = function(map) {
  var deps = [];

  // -> ['a@0.0.2']
  Object.keys(map).forEach(function(name) {
    deps.push(name + '@' + map[name]);
  });

  return deps;
};

exports._santitize_modules = function(modules) {
  return modules.map(function(module) {
    var splitted = module.split('@');
    return splitted[0] + '@' + (splitted[1] || 'latest');
  });
};

exports._check_modules = function(modules, pkg, callback, allow_duplicate_versions) {
  if (allow_duplicate_versions) {
    // prohibited: a a
    // allow: a@0.0.1 a@0.0.2
    exports._check_duplicate_modules(modules, callback);
  } else {
    // prohibited: a@0.0.1 a@0.0.2
    // prohibited: a a
    // allow: a@0.0.1 b
    exports._check_duplicate_versions(modules, pkg, callback);
  }
};

// There should be no duplicate modules.
// There should be no duplicate versions of a same module
exports._check_duplicate_versions = function(modules, pkg, callback) {
  var map = {};

  var pkg_name = pkg.name;

  // if no error
  var pass = !modules.some(function(module) {
    var name = module.split('@')[0];

    if (pkg_name === name) {
      return~ callback('You should not install a module "' + name + '" into itself.');

    } else if (!(name in map)) {
      map[name] = true;

    } else {
      return~ callback(
        'With the "--save" option, ' + 'installing more than one version of the module "' + name + '" is prohibited.'
      );
    }
  });

  if (pass) {
    callback(null);
  }
};

// There should be no duplicate modules.
exports._check_duplicate_modules = function(modules, callback) {
  var map = {};

  // if no error
  var pass = !modules.some(function(module) {
    if (!(module in map)) {
      map[module] = true;

    } else {
      return~ callback('Duplicate installation of module "' + module + '".');
    }
  });

  if (pass) {
    callback(null);
  }
};

exports.info = 'Install specified modules or install modules from package.json';

exports.usage = [
  '{{name}} install <module>[,<modules>[,...]]',
  '{{name}} install [options]'
];<commit_msg>#303: option/install: fixes a reference error.<commit_after>'use strict';

var node_path   = require('path');
var node_url    = require('url');
var lang        = require('../util/lang');
var pkg_helper  = require('../util/package');
var async       = require('async');

exports.shorthands = {
  c: 'cwd',
  r: 'recursive'
};

exports.options = {

  // Indicates that user want to save something into package.json
  // _save: {
  //   type: Boolean,
  //   enumerable: false,
  //   default: false
  // },

  recursive: {
    type: Boolean,
    info: 'install all dependencies recursively. If `false`, cortex will only download the current module.',
    default: true
  },

  cwd: {
    type: node_path,
    info: 'current working directory.',
    // `cortex install` could be executed anywhere
    default: process.cwd(),
    setter: function(cwd) {
      var done = this.async();
      // if not inside a project, returns null
      pkg_helper.repo_root(this.get('cwd'), function (cwd) {
        done(null, cwd);
      });
    }
  },

  // if --save --save-async, --save-async will be ignored
  save: {
    type: Boolean,
    info: 'package will appear in your "cortex.dependencies" of package.json.',
    validator: save_check_package
  },

  'save-async': {
    type: Boolean,
    info: 'package will appear in your "cortex.asyncDependencies" of package.json.',
    validator: save_check_package
  },

  'save-dev': {
    type: Boolean,
    info: 'package will appear in your "cortex.devDependencies" of package.json.',
    validator: save_check_package
  },

  clone: {
    type: Boolean,
    info: 'try to clone the package repo down to the workspace.',
    default: false
  },

  production: {
    type: Boolean,
    info: 'ignore "devDependencies". Only works when not explicitly specify module to install',
    default: false
  },

  modules: {
    // command line type: String
    // programmatical type: Array.<string>
    info: 'modules to install. if not specified, cortex will read them from your package.json. if you install a module without version, cortex will try to install the latest one.',
    setter: function(modules) {
      var done = this.async();
      var remain = this.get('_') || [];

      exports._get_modules({
        remain: remain,
        cwd: this.get('cwd'),
        save: this.get('_save'),
        production: this.get('production'),
        modules: modules

      }, done);
    }
  }
};

function save_check_package(save) {
  var done = this.async();

  // if --save, package.json must exists
  if (save) {
    var cwd = this.get('cwd');

    // 'cortex install' might be called inside a subtle directory of the project.
    if (cwd === null) {
      return done('package.json not found, could not save dependencies');
    }

    this.set('cwd', cwd);
    // options._save: internal use
    this.set('_save', true);
  }

  done(null);
}

// @param {Object} options
// - pkg
// - cwd
// - save
// - remain
exports._get_modules = function(options, callback) {
  var parsed_modules = [];

  // Invalid value
  // ```
  // cortex install --modules
  // ```
  if (options.modules === true) {
    return callback({
      code: 'EINVALID',
      message: 'invalid value of option --modules, which must be specified.',
      data: {
        option: 'modules'
      }
    });
  }

  // 1.
  // Install modules which explicitly defined in option --modules
  // ```
  // #　could be executed anywhere
  // cortex install --modules ajax,lang
  // ```
  if (options.modules) {
    parsed_modules = options.modules.split(/\s*,\s*/);
  }

  // 2.
  // Install modules in argv.remain
  // ```
  // #　could be executed anywhere
  // cortex install ajax lang
  // ```

  // Object `remain` might be a mocked argv object,
  // so, be careful, and do some tests
  if (!parsed_modules.length && options.remain.length) {
    parsed_modules = options.remain;
  }

  if (options.save) {
    // if --save or --save-async,
    // there must inside a repo, or we will not be able to save dependencies
    if (!parsed_modules.length) {
      return callback({
        code: 'ENONETOSAVE',
        message: 'if --save, you must specify the modules to install.'
      });
    }
    // else we should check the modules

  } else {
    if (parsed_modules.length) {
      return callback(null, exports._santitize_modules(parsed_modules));
    }
    // else we will fetch modules from dependencies
  }

  // 3.
  // Install modules from dependencies of package.json,
  // ```
  // # in this case, must executed inside a repo
  // cortex install
  // ```

  var cwd = options.cwd;
  if (cwd === null) {
    if (options.save) {
      return callback({
        code: 'ECOULDNOTSAVE',
        message: 'Directory "' + cwd + '" is not inside a repo, could not save dependencies.',
        data: {
          cwd: cwd
        }
      });

    } else {
      return callback({
        code: 'ENOTAREPO',
        message: 'Directory "' + cwd + '" is not inside a repo, could not fetch dependencies.',
        data: {
          cwd: cwd
        }
      });
    }
  }

  exports._get_pkg(cwd, function(err, pkg) {
    if (err) {
      return callback(err);
    }

    // Including all versions
    var deps_map = exports._get_all_deps(pkg, options.production);

    // We will not check `cortex install`
    if (!parsed_modules.length) {

      // If `deps_map` is an empty object, we will allow this.
      // Users might exec `cortex install` inside a repo which has no deps.
      return callback(null, exports._make_deps_array(deps_map));
    }

    // if --save, we should not install more than one version of a certain module
    var allow_duplicate_versions = !options.save;

    exports._check_modules(parsed_modules, pkg, function(err) {
      if (err) {
        return callback(err);
      }

      callback(null, exports._santitize_modules(parsed_modules));

    }, allow_duplicate_versions);
  });
};

exports._get_pkg = function(cwd, callback) {
  pkg_helper.get_original_package(cwd, callback);
};

exports._get_all_deps = function(pkg, production) {
  var deps_obj = {};

  var keys = ['dependencies', 'asyncDependencies'];
  // When user executes `cortex install --production`,
  // cortex will not install devDependencies
  if (!production) {
    keys.push('devDependencies');
  }

  // But cortex will not install
  // 'asyncDependencies' and 'devDependencies' recursively which handled by neuropil.
  keys.forEach(function(key) {
    lang.mix(deps_obj, pkg[key]);
  });

  return deps_obj;
};

exports._make_deps_array = function(map) {
  var deps = [];

  // -> ['a@0.0.2']
  Object.keys(map).forEach(function(name) {
    deps.push(name + '@' + map[name]);
  });

  return deps;
};

exports._santitize_modules = function(modules) {
  return modules.map(function(module) {
    var splitted = module.split('@');
    return splitted[0] + '@' + (splitted[1] || 'latest');
  });
};

exports._check_modules = function(modules, pkg, callback, allow_duplicate_versions) {
  if (allow_duplicate_versions) {
    // prohibited: a a
    // allow: a@0.0.1 a@0.0.2
    exports._check_duplicate_modules(modules, callback);
  } else {
    // prohibited: a@0.0.1 a@0.0.2
    // prohibited: a a
    // allow: a@0.0.1 b
    exports._check_duplicate_versions(modules, pkg, callback);
  }
};

// There should be no duplicate modules.
// There should be no duplicate versions of a same module
exports._check_duplicate_versions = function(modules, pkg, callback) {
  var map = {};

  var pkg_name = pkg.name;

  // if no error
  var pass = !modules.some(function(module) {
    var name = module.split('@')[0];

    if (pkg_name === name) {
      return~ callback('You should not install a module "' + name + '" into itself.');

    } else if (!(name in map)) {
      map[name] = true;

    } else {
      return~ callback(
        'With the "--save" option, ' + 'installing more than one version of the module "' + name + '" is prohibited.'
      );
    }
  });

  if (pass) {
    callback(null);
  }
};

// There should be no duplicate modules.
exports._check_duplicate_modules = function(modules, callback) {
  var map = {};

  // if no error
  var pass = !modules.some(function(module) {
    if (!(module in map)) {
      map[module] = true;

    } else {
      return~ callback('Duplicate installation of module "' + module + '".');
    }
  });

  if (pass) {
    callback(null);
  }
};

exports.info = 'Install specified modules or install modules from package.json';

exports.usage = [
  '{{name}} install <module>[,<modules>[,...]]',
  '{{name}} install [options]'
];<|endoftext|>


<commit_before>import { retrieve, insert, amend, partialAmend, deactivate } from './assets.js'
import Asset from '../../assets/Asset/asset.js'

describe('assets util functions', () => {
  describe('retrieve', () => {
    it('should', () => {
      // retrieve('1', '4bd2cfd84d154eef9b70f24262609a4b', (error, result) => {
      //   if (!error) {
      //     console.log(result)
      //   }
      // })
      const asset = new Asset({
        assetManagerId: '1',
        fungible: true,
        assetId:'test_asset',
        description: 'testThomasAssetAmended'
      })
      // amend(asset, '1', 'test_asset', (error, result) => {
      //   if (error) {
      //     console.log(error)
      //   } else {
      //     console.log(result)
      //   }
      // })
    })
  })
})
<commit_msg>Add tests for utils/assets<commit_after>import { retrieve, insert, amend, partialAmend, deactivate } from './assets.js'
import Asset from '../../assets/Asset/asset.js'

let token = process.env.API_TOKEN

describe('utils/assets', () => {
  describe('retrieve', () => {
    test('with promise', callback => {
      let promise = retrieve({token, AMId: 1})
      expect(promise).toBeInstanceOf(Promise)
      promise.then(assets => {
        expect(Array.isArray(assets)).toBeTruthy()
        expect(assets[0]).toBeInstanceOf(Asset)
        callback()
      })
    })
  })

  describe('insert', () => {
    test('with promise', () => {
      let promise = insert({token}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
  })

  describe('amend', () => {
    test('with promise', () => {
      let promise = amend({token}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
  })

  describe('partialAmend', () => {
    test('with promise', () => {
      let promise = partialAmend({token}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
  })

  describe('deactivate', () => {
    test('with promise', () => {
      let promise = deactivate({token}).catch(error => {})
      expect(promise).toBeInstanceOf(Promise)
    })
  })
})
<|endoftext|>


<commit_before>'use strict';

// core
var path = require('path');
// npm
var async = require('async');
var cheerio = require('cheerio');
var mongoose = require('mongoose');
var request = require('request');
// wuw
var utils = require('./wuw_utils');

// how many weeks should we parse?
var weeksToParse = 3;

// mongodb
var mongohost='localhost:27017';
var mongodb=process.env.WUWDB || 'wuw';
var mongoConnection='mongodb://' + mongohost + '/' + mongodb;

// running as module or standalone?
var standalone = !module.parent;
var scriptName = path.basename(module.filename, path.extname(module.filename));

// parsing
var parse = function(html, cb) {
    // create models from our schemas
    var Dish = require('./models/model_dish');

    // init cheerio with our html
    var $ = cheerio.load(html);
    var fullWeekDom = $('body div.print-content div div.view-content div ul');
    var fullWeek = $('.node-type-canteen_menu');

    // parse each week of food
    async.each(fullWeek, function(dayPlan, daycb) {

        dayPlan = dayPlan.parent;
        var curDate = $(dayPlan).find('span.date-day-numeric').html().trim();
        var curDateArr = curDate.split('.');
        var intDate = curDateArr[1] + '/' + curDateArr[0] + '/' + curDateArr[2];
        var i = 0;
        async.each($(dayPlan).find('td.speiseangebotbody'), function(e, dishcb) {

            // split main dishes from the side dishes & sweets
            if(i !== 6 && i !== 7) {

                // create dish from our Model
                var curDish = new Dish();
                curDish.dishName = $(e).find('span.name').text();
                curDish.shortCat = i;
                curDish.date = Date.parse(intDate);
                curDish.date.setHours(12);
                var additiveNumber = $(e).find('span.additive_number');

                // get the price
                var prices = $(e).first().contents().filter(function() {
                    return this.type === 'text';
                }).text().trim().split('€: ');
                prices = prices[1].trim();
                prices = prices.split(" / ");

                // if prices exists, split to internal and external
                if (prices.length === 2) {
                    curDish.priceInternal = prices[0].replace(',', '.');
                    curDish.priceExternal = prices[1].replace(',', '.');
                }

                // prepare attributes, allergens & additives
                if(additiveNumber) {
                    $(additiveNumber).each(function(i, e) {
                        // split to single strings/numbers
                        var adds = $(e).html().split(',');
                        // allergens
                        if(i === 0) {
                            adds.forEach(function(add) {
                                curDish.shortAllerg.push(add);
                            });
                        // additives
                        } else if(i === 1) {
                            adds.forEach(function(add) {
                                curDish.shortAdd.push(add);
                            });
                        }
                    });
                }

                // save to database
                curDish.save(function (err, dish, numAffected) {
                    if (err) {
                        console.log(err);
                    }
                    dishcb();
                });

            // side dishes & sweets
            // } else if (i === 6 || i === 7) {
            //     console.log($(e));
            } else {
                dishcb();
            }

            i++;
        }, function(){
            // day done
            daycb();
        });

    }, function() {
        // week done
        cb();
    });
};

// get the calendar week
Object.defineProperty(Date.prototype, 'getWeek', {
    value: function() {
        var determinedate = new Date();
        determinedate.setFullYear(this.getFullYear(), this.getMonth(), this.getDate());
        var D = determinedate.getDay();
        if(D === 0) { D = 7; }
        determinedate.setDate(determinedate.getDate() + (4 - D));
        var YN = determinedate.getFullYear();
        var ZBDoCY = Math.floor((determinedate.getTime() - new Date(YN, 0, 1, -6)) / 86400000);
        var WN = 1 + Math.floor(ZBDoCY / 7);
        return WN;
    }
});

// create urls including the calendar week which we want to parse
var createUrls = function() {
    var urls = [];
    for(var i = 0; i < weeksToParse; i++) {
        // get date to parse
        var today = new Date();
        var currentWeek = (today.getWeek() + i) % 53;
        var currentYear = today.getFullYear();
        // assemble datestring & url
        var currWeek = currentYear + '-W' + currentWeek;
        var url = 'https://www.studierendenwerk-stuttgart.de/print/gastronomie/speiseangebot/' + currWeek;
        urls.push(url);
    }
    return urls;
};

var startParser = function() {
    // connect to mongodb (if not already)
    if(mongoose.connection.readyState === 0) {
        mongoose.connect(mongoConnection);
    }

    // create model from our schema (needed for drop)
    var Dish = require('./models/model_dish');

    // create the urls to parse
    var urls = createUrls();

    console.log('[' + (new Date()) + '] ' + scriptName + ': started with { weeksToParse: ' + weeksToParse + ' }');
    // simple progress display if run as standalone
    if (standalone) { process.stdout.write(' '); }

    // drop current collection to get a fresh result
    mongoose.connection.collections.dishes.drop(function(err) {
        if(err) { console.log(err); }

        // parse every url (max. 5 parallel, dont fuck the studentenwerk)
        async.eachLimit(urls, 5, function(url, cb) {
            request(url, function(error, response, html) {
                if(!error) {
                    // parse html with all dishes for choosen date
                    parse(html, function() {
                        // simple progress display if run as standalone
                        if (standalone) { process.stdout.write(' *'); }
                        cb();
                    });
                }
            });
        }, function() {
            // disconnect mongodb if run as standalone
            if (standalone) {
                process.stdout.write('\n');
                mongoose.disconnect();
            }

            console.log('[' + (new Date()) + '] ' + scriptName + ': completed successfully');
        });
    });
};

// immediately start parsing if run as standalone
if (standalone) { startParser(); }

module.exports = { startParser: startParser, parse: parse };
<commit_msg>mensa: more robust price parsing<commit_after>'use strict';

// core
var path = require('path');
// npm
var async = require('async');
var cheerio = require('cheerio');
var mongoose = require('mongoose');
var request = require('request');
// wuw
var utils = require('./wuw_utils');

// how many weeks should we parse?
var weeksToParse = 3;

// mongodb
var mongohost='localhost:27017';
var mongodb=process.env.WUWDB || 'wuw';
var mongoConnection='mongodb://' + mongohost + '/' + mongodb;

// running as module or standalone?
var standalone = !module.parent;
var scriptName = path.basename(module.filename, path.extname(module.filename));

// parsing
var parse = function(html, cb) {
    // create models from our schemas
    var Dish = require('./models/model_dish');

    // init cheerio with our html
    var $ = cheerio.load(html);
    var fullWeekDom = $('body div.print-content div div.view-content div ul');
    var fullWeek = $('.node-type-canteen_menu');

    // parse each week of food
    async.each(fullWeek, function(dayPlan, daycb) {

        dayPlan = dayPlan.parent;
        var curDate = $(dayPlan).find('span.date-day-numeric').html().trim();
        var curDateArr = curDate.split('.');
        var intDate = curDateArr[1] + '/' + curDateArr[0] + '/' + curDateArr[2];
        var i = 0;
        async.each($(dayPlan).find('td.speiseangebotbody'), function(e, dishcb) {

            // split main dishes from the side dishes & sweets
            if(i !== 6 && i !== 7) {

                // create dish from our Model
                var curDish = new Dish();
                curDish.dishName = $(e).find('span.name').text();
                curDish.shortCat = i;
                curDish.date = Date.parse(intDate);
                curDish.date.setHours(12);
                var additiveNumber = $(e).find('span.additive_number');

                // get the price
                var prices = $(e).first().contents().filter(function() {
                    return this.type === 'text';
                }).text().trim().split('€: ');
                prices = prices[1].trim();
                prices = prices.split(" / ");

                // if prices exists, split to internal and external
                if (prices.length === 2) {
                    var priceInternal = prices[0].replace(',', '.');
                    var priceExternal = prices[1].replace(',', '.');

                    if (isNaN(priceInternal)) {
                        Console.e("price internal is not a number");
                    }

                    if (isNaN(priceExternal)) {
                        priceExternal = priceExternal.split(" ")[0];
                    }
                    curDish.priceInternal = priceInternal;
                    curDish.priceExternal = priceExternal;
                }

                // prepare attributes, allergens & additives
                if (additiveNumber) {
                    $(additiveNumber).each(function(i, e) {
                        // split to single strings/numbers
                        var adds = $(e).html().split(',');
                        // allergens
                        if (i === 0) {
                            adds.forEach(function(add) {
                                curDish.shortAllerg.push(add);
                            });
                        // additives
                        } else if(i === 1) {
                            adds.forEach(function(add) {
                                if (!isNaN(add)) {
                                    curDish.shortAdd.push(add);
                                }

                            });
                        }
                    });
                }

                // save to database
                curDish.save(function (err, dish, numAffected) {
                    if (err) {
                        console.log(err);
                    }
                    dishcb();
                });

            // side dishes & sweets
            // } else if (i === 6 || i === 7) {
            //     console.log($(e));
            } else {
                dishcb();
            }

            i++;
        }, function(){
            // day done
            daycb();
        });

    }, function() {
        // week done
        cb();
    });
};

// get the calendar week
Object.defineProperty(Date.prototype, 'getWeek', {
    value: function() {
        var determinedate = new Date();
        determinedate.setFullYear(this.getFullYear(), this.getMonth(), this.getDate());
        var D = determinedate.getDay();
        if(D === 0) { D = 7; }
        determinedate.setDate(determinedate.getDate() + (4 - D));
        var YN = determinedate.getFullYear();
        var ZBDoCY = Math.floor((determinedate.getTime() - new Date(YN, 0, 1, -6)) / 86400000);
        var WN = 1 + Math.floor(ZBDoCY / 7);
        return WN;
    }
});

// create urls including the calendar week which we want to parse
var createUrls = function() {
    var urls = [];
    for(var i = 0; i < weeksToParse; i++) {
        // get date to parse
        var today = new Date();
        var currentWeek = (today.getWeek() + i) % 53;
        var currentYear = today.getFullYear();
        // assemble datestring & url
        var currWeek = currentYear + '-W' + currentWeek;
        var url = 'https://www.studierendenwerk-stuttgart.de/print/gastronomie/speiseangebot/' + currWeek;
        urls.push(url);
    }
    return urls;
};

var startParser = function() {
    // connect to mongodb (if not already)
    if(mongoose.connection.readyState === 0) {
        mongoose.connect(mongoConnection);
    }

    // create model from our schema (needed for drop)
    var Dish = require('./models/model_dish');

    // create the urls to parse
    var urls = createUrls();

    console.log('[' + (new Date()) + '] ' + scriptName + ': started with { weeksToParse: ' + weeksToParse + ' }');
    // simple progress display if run as standalone
    if (standalone) { process.stdout.write(' '); }

    // drop current collection to get a fresh result
    mongoose.connection.collections.dishes.drop(function(err) {
        if(err) { console.log(err); }

        // parse every url (max. 5 parallel, dont fuck the studentenwerk)
        async.eachLimit(urls, 5, function(url, cb) {
            request(url, function(error, response, html) {
                if(!error) {
                    // parse html with all dishes for choosen date
                    parse(html, function() {
                        // simple progress display if run as standalone
                        if (standalone) { process.stdout.write(' *'); }
                        cb();
                    });
                }
            });
        }, function() {
            // disconnect mongodb if run as standalone
            if (standalone) {
                process.stdout.write('\n');
                mongoose.disconnect();
            }

            console.log('[' + (new Date()) + '] ' + scriptName + ': completed successfully');
        });
    });
};

// immediately start parsing if run as standalone
if (standalone) { startParser(); }

module.exports = { startParser: startParser, parse: parse };
<|endoftext|>


<commit_before>/*****************************************************************************/
/*                          Main JS for whileaway                            */
/*****************************************************************************/

$(document).ready(function(){
    // Form UI fixes

    $('#section').change(function() {
    	option_val = $('#section > option:selected').text();
    	$('#section-span').html(option_val);
    	$('#section').width($('#section-span').width());
    });

    $('#section').change();

    $('#date').change(function() {
    	option_val = $('#date > option:selected').val();
    	$('#date-span').html(option_val);
    	$('#date').width($('#date-span').width());
    });

    $('#date').change();

    window.onresize = function() {
    	$('#section').change();
    	$('#date').change();
    	inputWidth();
    }

    function inputWidth() {
    	$('#number-span').html($('#number').val());
    	$('#number').css('width', $('#number-span').width());
    }

    inputWidth();

    $('#number').bind('keyup input paste', inputWidth);

    window.onresize = function() {
    	$('#keyword').change();
    	$('#date').change();
    	inputWidth();
    }

    // prevent page reload on enter
    $('#form').submit(function(event) {
        event.preventDefault();
    });

    // Fetching and displaying stories
    getNews();

    // onchange of input fields, call getNews()
    $('#number').bind('keyup input paste', function(){getNews();});
    $('#date').change(function(){getNews();});
    $('#keyword').change(function(){getNews();});
});

function getNews(){
	amount = $('#number').val();
	scope = $('#date option:selected').val();
	section = $('#section option:selected').val();
    // keyword $('#keyword').val()
    keyword = '';

	try {
        keyword = $.trim(keyword);
		validate(amount, scope, section, keyword);

        // make asynchronous request
        getGuardianNews(amount, scope, section, keyword);
	} catch (e) {
		alert(e); // To-Do: Error handling
		return;
	}
}

function handleGuardianNews(news){
	str = '
';
	$.each(news, function(index, story) {
		headline = story[0];
		link = story[1];
		date = story[2];
		// summary = story[3];

		// str += '
' + headline + ' (more…, ' + date.f('d MMM yyyy HH:mm') + ')
';
        str += '
';
		str += '' + headline + '';
        str += '

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
';
        str += '<time datetime="' + date.toJSON() + '"> ' + date.f('d MMM') + '</time> // ';
        str += 'Read more';
        str += '

';
	});
	str += '
';
	$('#headlines').html(str);

    // display summary on headline click
    $('.headline > a').click(function(e){
        e.preventDefault();
        $(this).next('div').toggle(300);
    });
}

function validate(amount, scope, section, keyword) {
	scopes = ['days', 'weeks', 'months'];
	if (scopes.indexOf(scope) < 0) {
		throw 'Invalid scope';
	}

	if (isNaN(amount)) {
		throw 'Invalid amount';
	}

    sections = ['world', 'uk-news', 'football', 'film', 'business', 'politics'];
    if (sections.indexOf(section) < 0) {
        throw 'Invalid section';
    }
}
<commit_msg>Keyword -> section bug<commit_after>/*****************************************************************************/
/*                          Main JS for whileaway                            */
/*****************************************************************************/

$(document).ready(function(){
    // Form UI fixes

    $('#section').change(function() {
    	option_val = $('#section > option:selected').text();
    	$('#section-span').html(option_val);
    	$('#section').width($('#section-span').width());
    });

    $('#section').change();

    $('#date').change(function() {
    	option_val = $('#date > option:selected').val();
    	$('#date-span').html(option_val);
    	$('#date').width($('#date-span').width());
    });

    $('#date').change();

    window.onresize = function() {
    	$('#section').change();
    	$('#date').change();
    	inputWidth();
    }

    function inputWidth() {
    	$('#number-span').html($('#number').val());
    	$('#number').css('width', $('#number-span').width());
    }

    inputWidth();

    $('#number').bind('keyup input paste', inputWidth);

    window.onresize = function() {
    	$('#keyword').change();
    	$('#date').change();
    	inputWidth();
    }

    // prevent page reload on enter
    $('#form').submit(function(event) {
        event.preventDefault();
    });

    // Fetching and displaying stories
    getNews();

    // onchange of input fields, call getNews()
    $('#number').bind('keyup input paste', function(){getNews();});
    $('#date').change(function(){getNews();});
    $('#section').change(function(){getNews();});
});

function getNews(){
	amount = $('#number').val();
	scope = $('#date option:selected').val();
	section = $('#section option:selected').val();
    // keyword $('#keyword').val()
    keyword = '';

	try {
        keyword = $.trim(keyword);
		validate(amount, scope, section, keyword);

        // make asynchronous request
        getGuardianNews(amount, scope, section, keyword);
	} catch (e) {
		alert(e); // To-Do: Error handling
		return;
	}
}

function handleGuardianNews(news){
	str = '
';
	$.each(news, function(index, story) {
		headline = story[0];
		link = story[1];
		date = story[2];
		// summary = story[3];

		// str += '
' + headline + ' (more…, ' + date.f('d MMM yyyy HH:mm') + ')
';
        str += '
';
		str += '' + headline + '';
        str += '

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
';
        str += '<time datetime="' + date.toJSON() + '"> ' + date.f('d MMM') + '</time> // ';
        str += 'Read more';
        str += '

';
	});
	str += '
';
	$('#headlines').html(str);

    // display summary on headline click
    $('.headline > a').click(function(e){
        e.preventDefault();
        $(this).next('div').toggle(300);
    });
}

function validate(amount, scope, section, keyword) {
	scopes = ['days', 'weeks', 'months'];
	if (scopes.indexOf(scope) < 0) {
		throw 'Invalid scope';
	}

	if (isNaN(amount)) {
		throw 'Invalid amount';
	}

    sections = ['world', 'uk-news', 'football', 'film', 'business', 'politics'];
    if (sections.indexOf(section) < 0) {
        throw 'Invalid section';
    }
}
<|endoftext|>