<commit_before>/** The synchronization client configuration
 *
 * @module core/config
 * @flow
 */

const fs = require('fs')
const fse = require('fs-extra')
const _ = require('lodash')
const path = require('path')

const { hideOnWindows } = require('./utils/fs')
const logger = require('./utils/logger')

const log = logger({
  component: 'Config'
})

/*::
export type WatcherType = 'atom' | 'chokidar'
export type SyncMode = 'full' | 'pull' | 'push'
type FileConfig = Object
*/

const INVALID_CONFIG_ERROR = 'InvalidConfigError'
const INVALID_CONFIG_MESSAGE = 'Invalid client configuration'
function InvalidConfigError() {
  this.name = INVALID_CONFIG_ERROR
  this.message = INVALID_CONFIG_MESSAGE
}

// Config can keep some configuration parameters in a JSON file,
// like the devices credentials or the mount path
class Config {
  /*::
  configPath: string
  dbPath: string
  fileConfig: FileConfig
  */

  // Create config file if it doesn't exist.
  constructor(basePath /*: string */) {
    this.configPath = path.join(basePath, 'config.json')
    fse.ensureFileSync(this.configPath)
    this.dbPath = path.join(basePath, 'db')
    fse.ensureDirSync(this.dbPath)
    hideOnWindows(basePath)

    this.fileConfig = this.read()
  }

  // Read the configuration from disk
  read() /*: FileConfig */ {
    if (fse.existsSync(this.tmpConfigPath)) {
      const tmpConfig = loadOrDeleteFile(this.tmpConfigPath)

      if (_.size(tmpConfig) > 0) {
        this._moveTmpConfig()
        return tmpConfig
      }
    }

    return loadOrDeleteFile(this.configPath)
  }

  // Reset the configuration
  reset() {
    this.fileConfig = Object.create(null)
    this.clear()
    this.persist()
  }

  // Save configuration to file system.
  persist() {
    this._writeTmpConfig(this.toJSON())
    this._moveTmpConfig()
  }

  _writeTmpConfig(config /*: string */) {
    fse.ensureFileSync(this.tmpConfigPath)
    fse.writeFileSync(this.tmpConfigPath, config)
  }

  _moveTmpConfig() {
    if (fs.copyFileSync && fs.constants.COPYFILE_FICLONE) {
      fs.copyFileSync(this.tmpConfigPath, this.configPath)
    } else {
      // Fallback for old node versions
      fse.copySync(this.tmpConfigPath, this.configPath)
    }
    fse.unlinkSync(this.tmpConfigPath)
  }

  // Transform the config to a JSON string
  toJSON() /*: string */ {
    return JSON.stringify(this.fileConfig, null, 2)
  }

  // Get the tmp config path associated with the current config path
  get tmpConfigPath() /*: string */ {
    return this.configPath + '.tmp'
  }

  // Get the path on the local file system of the synchronized folder
  get syncPath() /*: string */ {
    return this.fileConfig.path
  }

  // Set the path on the local file system of the synchronized folder
  set syncPath(path /*: string */) {
    this.fileConfig.path = path
  }

  // Return the URL of the cozy instance
  get cozyUrl() /*: string */ {
    return this.fileConfig.url
  }

  // Set the URL of the cozy instance
  set cozyUrl(url /*: string */) {
    this.fileConfig.url = url
  }

  get gui() /*: * */ {
    return this.fileConfig.gui || {}
  }

  // Return true if a device has been configured
  isValid() /*: bool */ {
    return !!(this.fileConfig.creds && this.cozyUrl)
  }

  // Return the name of the registered client
  get deviceName() /*: ?string */ {
    return _.get(this, 'config.creds.client.clientName', '')
  }

  // Return config related to the OAuth client
  get client() /*: * */ {
    if (!this.fileConfig.creds) {
      throw new Error(`Device not configured`)
    }
    return this.fileConfig.creds.client
  }

  get version() /*: ?string */ {
    return _.get(this, 'config.creds.client.softwareVersion')
  }

  get permissions() /*: * */ {
    const scope = _.get(this, 'config.creds.token.scope')
    return scope ? scope.split(' ') : []
  }

  // Set the remote configuration
  set client(options /*: * */) {
    this.fileConfig.creds = { client: options }
    this.persist()
  }

  get watcherType() /*: WatcherType */ {
    return watcherType(this.fileConfig)
  }

  // Set the pull, push or full mode for this device
  // It will throw an exception if the mode is not compatible with the last
  // mode used!
  saveMode(mode /*: SyncMode */) {
    const old = this.fileConfig.mode
    if (old === mode) {
      return true
    } else if (old) {
      throw new Error(
        `Once you set mode to "${old}", you cannot switch to "${mode}"`
      )
    }
    this.fileConfig.mode = mode
    this.persist()
  }

  // Implement the Storage interface for cozy-client-js oauth

  save(key /*: string */, value /*: * */) {
    this.fileConfig[key] = value
    if (key === 'creds') {
      // Persist the access token after it has been refreshed
      this.persist()
    }
    return Promise.resolve(value)
  }

  load(key /*: string */) /*: Promise<*> */ {
    return Promise.resolve(this.fileConfig[key])
  }

  delete(key /*: string */) /*: Promise<*> */ {
    const deleted = delete this.fileConfig[key]
    return Promise.resolve(deleted)
  }

  clear() /*: Promise<void> */ {
    delete this.fileConfig.creds
    delete this.fileConfig.state
    return Promise.resolve()
  }
}

function load(dir /*: string */) /*: Config */ {
  return new Config(dir)
}

/** Load raw config from a JSON file.
 *
 * When file is invalid, delete it and return an empty object.
 */
function loadOrDeleteFile(configPath /*: string */) /*: FileConfig */ {
  try {
    const content = fs.readFileSync(configPath, 'utf8')
    if (content === '') return {}
    return JSON.parse(content)
  } catch (e) {
    if (e instanceof SyntaxError) {
      log.error(`Could not read config file at ${configPath}:`, e)
      fse.unlinkSync(configPath)
      return {}
    } else {
      throw e
    }
  }
}

/** Detect which local watcher will be used. */
function watcherType(
  fileConfig /*: FileConfig */ = {},
  { env, platform } /*: * */ = process
) /*: WatcherType */ {
  return (
    fileWatcherType(fileConfig) ||
    environmentWatcherType(env) ||
    platformDefaultWatcherType(platform)
  )
}

function fileWatcherType(fileConfig /*: FileConfig */) /*: ?WatcherType */ {
  return validateWatcherType(fileConfig.watcherType)
}

function environmentWatcherType(
  env /*: * */ = process.env
) /*: ?WatcherType */ {
  const { COZY_FS_WATCHER } = env
  return validateWatcherType(COZY_FS_WATCHER)
}

function platformDefaultWatcherType(
  platform /*: string */ = process.platform
) /*: WatcherType */ {
  if (platform === 'darwin') {
    return 'chokidar'
  }
  return 'atom'
}

function validateWatcherType(watcherType /*: ?string */) /*: ?WatcherType */ {
  if (watcherType === 'atom' || watcherType === 'chokidar') {
    return watcherType
  } else {
    if (watcherType) log.warn({ watcherType }, 'Invalid watcher type')
    return null
  }
}

module.exports = {
  INVALID_CONFIG_ERROR,
  InvalidConfigError,
  Config,
  environmentWatcherType,
  load,
  loadOrDeleteFile,
  platformDefaultWatcherType,
  watcherType
}
<commit_msg>core/config: Fix getters using lodash _.get<commit_after>/** The synchronization client configuration
 *
 * @module core/config
 * @flow
 */

const fs = require('fs')
const fse = require('fs-extra')
const _ = require('lodash')
const path = require('path')

const { hideOnWindows } = require('./utils/fs')
const logger = require('./utils/logger')

const log = logger({
  component: 'Config'
})

/*::
export type WatcherType = 'atom' | 'chokidar'
export type SyncMode = 'full' | 'pull' | 'push'
type FileConfig = Object
*/

const INVALID_CONFIG_ERROR = 'InvalidConfigError'
const INVALID_CONFIG_MESSAGE = 'Invalid client configuration'
function InvalidConfigError() {
  this.name = INVALID_CONFIG_ERROR
  this.message = INVALID_CONFIG_MESSAGE
}

// Config can keep some configuration parameters in a JSON file,
// like the devices credentials or the mount path
class Config {
  /*::
  configPath: string
  dbPath: string
  fileConfig: FileConfig
  */

  // Create config file if it doesn't exist.
  constructor(basePath /*: string */) {
    this.configPath = path.join(basePath, 'config.json')
    fse.ensureFileSync(this.configPath)
    this.dbPath = path.join(basePath, 'db')
    fse.ensureDirSync(this.dbPath)
    hideOnWindows(basePath)

    this.fileConfig = this.read()
  }

  // Read the configuration from disk
  read() /*: FileConfig */ {
    if (fse.existsSync(this.tmpConfigPath)) {
      const tmpConfig = loadOrDeleteFile(this.tmpConfigPath)

      if (_.size(tmpConfig) > 0) {
        this._moveTmpConfig()
        return tmpConfig
      }
    }

    return loadOrDeleteFile(this.configPath)
  }

  // Reset the configuration
  reset() {
    this.fileConfig = Object.create(null)
    this.clear()
    this.persist()
  }

  // Save configuration to file system.
  persist() {
    this._writeTmpConfig(this.toJSON())
    this._moveTmpConfig()
  }

  _writeTmpConfig(config /*: string */) {
    fse.ensureFileSync(this.tmpConfigPath)
    fse.writeFileSync(this.tmpConfigPath, config)
  }

  _moveTmpConfig() {
    if (fs.copyFileSync && fs.constants.COPYFILE_FICLONE) {
      fs.copyFileSync(this.tmpConfigPath, this.configPath)
    } else {
      // Fallback for old node versions
      fse.copySync(this.tmpConfigPath, this.configPath)
    }
    fse.unlinkSync(this.tmpConfigPath)
  }

  // Transform the config to a JSON string
  toJSON() /*: string */ {
    return JSON.stringify(this.fileConfig, null, 2)
  }

  // Get the tmp config path associated with the current config path
  get tmpConfigPath() /*: string */ {
    return this.configPath + '.tmp'
  }

  // Get the path on the local file system of the synchronized folder
  get syncPath() /*: string */ {
    return this.fileConfig.path
  }

  // Set the path on the local file system of the synchronized folder
  set syncPath(path /*: string */) {
    this.fileConfig.path = path
  }

  // Return the URL of the cozy instance
  get cozyUrl() /*: string */ {
    return this.fileConfig.url
  }

  // Set the URL of the cozy instance
  set cozyUrl(url /*: string */) {
    this.fileConfig.url = url
  }

  get gui() /*: * */ {
    return this.fileConfig.gui || {}
  }

  // Return true if a device has been configured
  isValid() /*: bool */ {
    return !!(this.fileConfig.creds && this.cozyUrl)
  }

  // Return the name of the registered client
  get deviceName() /*: ?string */ {
    return _.get(this.fileConfig, 'creds.client.clientName', '')
  }

  // Return config related to the OAuth client
  get client() /*: * */ {
    if (!this.fileConfig.creds) {
      throw new Error(`Device not configured`)
    }
    return this.fileConfig.creds.client
  }

  get version() /*: ?string */ {
    return _.get(this.fileConfig, 'creds.client.softwareVersion')
  }

  get permissions() /*: * */ {
    const scope = _.get(this.fileConfig, 'creds.token.scope')
    return scope ? scope.split(' ') : []
  }

  // Set the remote configuration
  set client(options /*: * */) {
    this.fileConfig.creds = { client: options }
    this.persist()
  }

  get watcherType() /*: WatcherType */ {
    return watcherType(this.fileConfig)
  }

  // Set the pull, push or full mode for this device
  // It will throw an exception if the mode is not compatible with the last
  // mode used!
  saveMode(mode /*: SyncMode */) {
    const old = this.fileConfig.mode
    if (old === mode) {
      return true
    } else if (old) {
      throw new Error(
        `Once you set mode to "${old}", you cannot switch to "${mode}"`
      )
    }
    this.fileConfig.mode = mode
    this.persist()
  }

  // Implement the Storage interface for cozy-client-js oauth

  save(key /*: string */, value /*: * */) {
    this.fileConfig[key] = value
    if (key === 'creds') {
      // Persist the access token after it has been refreshed
      this.persist()
    }
    return Promise.resolve(value)
  }

  load(key /*: string */) /*: Promise<*> */ {
    return Promise.resolve(this.fileConfig[key])
  }

  delete(key /*: string */) /*: Promise<*> */ {
    const deleted = delete this.fileConfig[key]
    return Promise.resolve(deleted)
  }

  clear() /*: Promise<void> */ {
    delete this.fileConfig.creds
    delete this.fileConfig.state
    return Promise.resolve()
  }
}

function load(dir /*: string */) /*: Config */ {
  return new Config(dir)
}

/** Load raw config from a JSON file.
 *
 * When file is invalid, delete it and return an empty object.
 */
function loadOrDeleteFile(configPath /*: string */) /*: FileConfig */ {
  try {
    const content = fs.readFileSync(configPath, 'utf8')
    if (content === '') return {}
    return JSON.parse(content)
  } catch (e) {
    if (e instanceof SyntaxError) {
      log.error(`Could not read config file at ${configPath}:`, e)
      fse.unlinkSync(configPath)
      return {}
    } else {
      throw e
    }
  }
}

/** Detect which local watcher will be used. */
function watcherType(
  fileConfig /*: FileConfig */ = {},
  { env, platform } /*: * */ = process
) /*: WatcherType */ {
  return (
    fileWatcherType(fileConfig) ||
    environmentWatcherType(env) ||
    platformDefaultWatcherType(platform)
  )
}

function fileWatcherType(fileConfig /*: FileConfig */) /*: ?WatcherType */ {
  return validateWatcherType(fileConfig.watcherType)
}

function environmentWatcherType(
  env /*: * */ = process.env
) /*: ?WatcherType */ {
  const { COZY_FS_WATCHER } = env
  return validateWatcherType(COZY_FS_WATCHER)
}

function platformDefaultWatcherType(
  platform /*: string */ = process.platform
) /*: WatcherType */ {
  if (platform === 'darwin') {
    return 'chokidar'
  }
  return 'atom'
}

function validateWatcherType(watcherType /*: ?string */) /*: ?WatcherType */ {
  if (watcherType === 'atom' || watcherType === 'chokidar') {
    return watcherType
  } else {
    if (watcherType) log.warn({ watcherType }, 'Invalid watcher type')
    return null
  }
}

module.exports = {
  INVALID_CONFIG_ERROR,
  InvalidConfigError,
  Config,
  environmentWatcherType,
  load,
  loadOrDeleteFile,
  platformDefaultWatcherType,
  watcherType
}
<|endoftext|>


<commit_before>jasmine.getFixtures().fixturesPath = 'specs/fixtures';

describe('Settings initialization', function() {
  beforeEach(function() {
    loadFixtures('example.html');
  });

  it('default settings', function() {
    var dtr = $('#map-canvas').drawTheRoute();

    expect(dtr.settings.zoom).toEqual(14);
    expect(dtr.settings.center).toEqual([-15.7941454, -47.88254789999996]);
    expect(dtr.settings.attachToRoad).toEqual(true);
    expect(dtr.settings.lineColor).toEqual('#FF0000');
    expect(dtr.settings.nodes).toEqual([]);
  });

  it('can receive settings', function() {
    var dtr = $('#map-canvas').drawTheRoute({
      zoom: 10,
      center: [-14.44, -47.88],
      attachToRoad: false,
      lineColor: 'blue',
      nodes: [
        [-15.79,-47.89],[-15.70,-47.87]
      ],
    });

    expect(dtr.settings.zoom).toEqual(10);
    expect(dtr.settings.center).toEqual([-14.44, -47.88]);
    expect(dtr.settings.attachToRoad).toEqual(false);
    expect(dtr.settings.lineColor).toEqual('blue');
    expect(dtr.settings.nodes).toEqual([[-15.79,-47.89],[-15.70,-47.87]]);
  });
});

describe('Google Maps Objects Initialization', function () {
  beforeEach(function() {
    loadFixtures('example.html');

    this.dtr = $('#map-canvas').drawTheRoute();
  });

  it('with default map center object', function () {
    expect(this.dtr.map.center.k).toEqual(-15.7941454);
    expect(this.dtr.map.center.B).toEqual(-47.88254789999996);
  });

  it('with default map zoom object (delegated to settings#zoom)', function () {
    expect(this.dtr.map.zoom).toEqual(14);
  });

  it('has map mapTypeId', function () {
    expect(this.dtr.map.zoom).toEqual(14);
  });

  it('has directionsService object', function () {
    expect(this.dtr.directionsService).toEqual(jasmine.any(Object));
  });

  it('has directionsDisplay object', function () {
    expect(this.dtr.directionsDisplay).toEqual(jasmine.any(Object));
  });

  it('has markers list', function () {
    expect(this.dtr.markers).toEqual([]);
  });
});

describe('Nodes object functions', function () {
  beforeEach(function() {
    loadFixtures('example.html');

    this.dtr = $('#map-canvas').drawTheRoute();

    this.dtr.nodes.elements = [1, 3, 4];
  });

  describe('last', function () {
    it('without params', function () {
      expect(this.dtr.nodes.last()).toEqual(4);
    });

    it('with params', function () {
      expect(this.dtr.nodes.last(2)).toEqual(3);
    });
  });

  it('first', function () {
    expect(this.dtr.nodes.first()).toEqual(1);
  });

  it('all', function () {
    expect(this.dtr.nodes.all()).toEqual([1, 3, 4]);
  });

  it('waypoints', function () {
    expect(this.dtr.nodes.waypoints()).toEqual([3, 4]);
  });

  it('push', function () {
    this.dtr.nodes.push(10);

    expect(this.dtr.nodes.elements).toEqual([1, 3, 4, 10]);
  });

  it('pop', function () {
    this.dtr.nodes.pop();

    expect(this.dtr.nodes.elements).toEqual([1, 3]);
  });
});
<commit_msg>general lint fixes<commit_after>/*global jasmine*/
/*global it*/
/*global describe*/
/*global beforeEach*/
/*global expect*/
/*global loadFixtures*/

jasmine.getFixtures().fixturesPath = 'specs/fixtures';

describe('Settings initialization', function () {
  beforeEach(function () {
    loadFixtures('example.html');
  });

  it('default settings', function () {
    var dtr = $('#map-canvas').drawTheRoute();

    expect(dtr.settings.zoom).toEqual(14);
    expect(dtr.settings.center).toEqual([-15.7941454, -47.88254789999996]);
    expect(dtr.settings.attachToRoad).toEqual(true);
    expect(dtr.settings.lineColor).toEqual('#FF0000');
    expect(dtr.settings.nodes).toEqual([]);
  });

  it('can receive settings', function () {
    var dtr = $('#map-canvas').drawTheRoute({
      zoom: 10,
      center: [-14.44, -47.88],
      attachToRoad: false,
      lineColor: 'blue',
      nodes: [
        [-15.79, -47.89], [-15.70, -47.87]
      ],
    });

    expect(dtr.settings.zoom).toEqual(10);
    expect(dtr.settings.center).toEqual([-14.44, -47.88]);
    expect(dtr.settings.attachToRoad).toEqual(false);
    expect(dtr.settings.lineColor).toEqual('blue');
    expect(dtr.settings.nodes).toEqual([[-15.79, -47.89], [-15.70, -47.87]]);
  });
});

describe('Google Maps Objects Initialization', function () {
  beforeEach(function () {
    loadFixtures('example.html');

    this.dtr = $('#map-canvas').drawTheRoute();
  });

  it('with default map center object', function () {
    expect(this.dtr.map.center.k).toEqual(-15.7941454);
    expect(this.dtr.map.center.B).toEqual(-47.88254789999996);
  });

  it('with default map zoom object (delegated to settings#zoom)', function () {
    expect(this.dtr.map.zoom).toEqual(14);
  });

  it('has map mapTypeId', function () {
    expect(this.dtr.map.zoom).toEqual(14);
  });

  it('has directionsService object', function () {
    expect(this.dtr.directionsService).toEqual(jasmine.any(Object));
  });

  it('has directionsDisplay object', function () {
    expect(this.dtr.directionsDisplay).toEqual(jasmine.any(Object));
  });

  it('has markers list', function () {
    expect(this.dtr.markers).toEqual([]);
  });
});

describe('Nodes object functions', function () {
  beforeEach(function () {
    loadFixtures('example.html');

    this.dtr = $('#map-canvas').drawTheRoute();

    this.dtr.nodes.elements = [1, 3, 4];
  });

  describe('last', function () {
    it('without params', function () {
      expect(this.dtr.nodes.last()).toEqual(4);
    });

    it('with params', function () {
      expect(this.dtr.nodes.last(2)).toEqual(3);
    });
  });

  it('first', function () {
    expect(this.dtr.nodes.first()).toEqual(1);
  });

  it('all', function () {
    expect(this.dtr.nodes.all()).toEqual([1, 3, 4]);
  });

  it('waypoints', function () {
    expect(this.dtr.nodes.waypoints()).toEqual([3, 4]);
  });

  it('push', function () {
    this.dtr.nodes.push(10);

    expect(this.dtr.nodes.elements).toEqual([1, 3, 4, 10]);
  });

  it('pop', function () {
    this.dtr.nodes.pop();

    expect(this.dtr.nodes.elements).toEqual([1, 3]);
  });
});
<|endoftext|>


<commit_before>/**
 * @fileoverview Interprets a given command and calls workspace controller_.functions.
 * @author david.liang@wisc.edu (David Liang)
 * @author pandori@wisc.edu (Sahib Pandori)
 */
'use strict';

goog.provide('SpeechBlocks.Interpreter');

goog.require('SpeechBlocks.Predecessor');
goog.require('SpeechBlocks.StatementInput')
goog.require('SpeechBlocks.Successor');
goog.require('SpeechBlocks.Translation');
goog.require('SpeechBlocks.ValueInput');
goog.require('goog.structs.Map');

/**
 * Constructs an interpreter that takes actions as input and controls the Blockly Workspace.
 * @param {!SpeechBlocks.Controller} controller The Blockly Workspace controller.
 * @constructor
 */
SpeechBlocks.Interpreter = function(controller) {
    /** @private @const */
    this.controller_ = controller;

    /** @private {!goog.structs.Map<string, string>} */
    this.blockTypeMap_ = new goog.structs.Map();
    this.createBlockTypeMap_();

    /** @private {!Array<string>} */
    this.blockTypes_ = controller.blockXmlMap_.keys_.slice()
}

/** @private */
SpeechBlocks.Interpreter.prototype.createBlockTypeMap_ = function() {
    this.blockTypeMap_.set('if', 'controls_if');
    this.blockTypeMap_.set('comparison', 'logic_compare');
    this.blockTypeMap_.set('repeat', 'controls_repeat_ext');
    this.blockTypeMap_.set('number', 'math_number');
    this.blockTypeMap_.set('math', 'math_arithmetic');
    this.blockTypeMap_.set('arithmetic', 'math_arithmetic');
    this.blockTypeMap_.set('text', 'text');
    this.blockTypeMap_.set('print', 'text_print');
    this.blockTypeMap_.set('set', 'variables_set');
    this.blockTypeMap_.set('variable', 'variables_get');
    this.blockTypeMap_.set('turn', 'turtle_turn_internal');
    this.blockTypeMap_.set('move', 'turtle_move_internal');
    this.blockTypeMap_.set('pen', 'turtle_pen');
    this.blockTypeMap_.set('repeat', 'turtle_repeat_internal');
    this.blockTypeMap_.set('color', 'turtle_colour_internal');
    this.blockTypeMap_.set('step', 'turtle_step');
}

/**
 * Interprets a given command by calling the corresponding action function.
 * @param {Object} command Command object from parser.
 * @public
 */
SpeechBlocks.Interpreter.prototype.interpret = function(command) {
    this.controller_.closeMenu()
    switch (command.action) {
        case 'run':
            this.run_();
            break;

        case 'add':
            this.addBlock_(command);
            break;

        case 'move':
            this.moveBlock_(command);
            break;

        case 'modify':
            this.modifyBlock_(command);
            break;

        case 'delete':
            this.deleteBlock_(command.blockId.toString());
            break;

        case 'undo':
            this.controller_.undo();
            break;

        case 'redo':
            this.controller_.redo();
            break;

        case 'menu':
            this.menuAction_(command);
            break;
    }
};

/**
 * Compiles the Blockly code into JavaScript and runs it.
 * @private
 */
SpeechBlocks.Interpreter.prototype.run_ = function() {
    document.getElementById('runButton').click();
};

/**
 * Adds a specified block. Can be added to aspecific place.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.addBlock_ = function(command) {
    if (!this.blockTypes_.includes(this.blockTypeMap_.get(command.type))) {
        throw 'Block type ' + this.blockTypes_.toString() + 'not available';
    }

    command.blockId = this.controller_.addBlock(
        this.blockTypeMap_.get(command.type),
        this.controller_.layout.getNewPosition_());
};

/**
 * Moves a specified block.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.moveBlock_ = function(command) {
    command.blockId = command.blockId.toString();
    if (!this.isBlockIdValid_(command.blockId)) {
        throw 'Block ' + command.blockId.toString() + ' does not exist!';
    }

    // Handle cases where target is not a block.
    if (command.where == 'trash') {
        this.deleteBlock_(command.blockId);
        return;
    } else if (command.where == 'away') {
        this.controller_.disconnectBlock(command.blockId);
        return;
    }

    // Handle cases where target is a block.
    command.where.blockId = command.where.blockId.toString();
    if (command.where.blockId == null ||
        !this.isBlockIdValid_(command.where.blockId)) {
        throw 'Block ' + command.where.blockId + ' does not exist!';
    }
    var wheres = []
    try {
        wheres = this.getWheres_(command);
    } catch (e) {
        console.log(e);
        return;
    }
    for (var i = 0; i < wheres.length; i++) {
        try {
            this.controller_.moveBlock(command.blockId, wheres[i]);
        } catch (e) {
            console.log(e);
            continue;
        }
        break;
    }
};

/**
 * Returns a list of potential wheres.
 */
SpeechBlocks.Interpreter.prototype.getWheres_ = function(command) {
    command.where.blockId = command.where.blockId.toString();
    if (command.where.blockId == null ||
        !this.isBlockIdValid_(command.where.blockId)) {
        throw 'Block ' + command.where.blockId + ' does not exist or not given!';
    }

    var wheres = [];
    switch (command.where.position) {
        case 'below':
            wheres.push(new SpeechBlocks.Successor(command.where.blockId));
            break;

        case 'above':
            wheres.push(new SpeechBlocks.Predecessor(command.where.blockId));
            break;

        case 'lhs':
        case 'rhs':
        case 'top':
        case 'to the right of':
            var inputList = this.controller_.getBlockValueInputs(command.where.blockId);
            if (inputList.length == 0) {
                throw 'Block ' + command.where.blockId + ' has no value inputs!';
            } else if (command.where.position == 'rhs' ||
                command.where.position == 'to the right of') {
                wheres.push(new SpeechBlocks.ValueInput(command.where.blockId, inputList[inputList.length - 1]));
            } else if (command.where.position == 'lhs' ||
                command.where.position == 'top') {
                wheres.push(new SpeechBlocks.ValueInput(command.where.blockId, inputList[0]));
            }
            break;

        case 'inside':
            // TODO: We should be handling case-by-case scenarios, where we check if the
            // "where" block has value or statement inputs, as well as if the "to place" block
            // has a previous/output connections.
            var inputList = this.controller_.getBlockValueInputs(command.where.blockId);
            var statementList = this.controller_.getBlockStatementInputs(command.where.blockId);
            for (var i = 0; i < inputList.length; i++) {
                wheres.push(new SpeechBlocks.ValueInput(command.where.blockId, inputList[i]));
            }
            for (var i = 0; i < statementList.length; i++) {
                wheres.push(new SpeechBlocks.StatementInput(command.where.blockId, statementList[statementList.length - 1]));
            }
            break;
    }

    return wheres;
}

/**
 * Modifies a specified block.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.modifyBlock_ = function(command) {
    command.blockId = command.blockId.toString();
    if (!this.isBlockIdValid_(command.blockId)) {
        throw 'Block ' + command.blockId + ' does not exist!';
    }

    // We look for the field the user mentioned
    var fields = this.controller_.getFieldsForBlock(command.blockId).getKeys();
    var fieldIndex;
    if (command.ordinal) {
        switch (command.ordinal) {
            case 'first':
                fieldIndex = 0;
                break;
            case 'second':
                fieldIndex = 1;
                break;
            case 'third':
                fieldIndex = 2;
                break;
        }
    } else {
        // Otherwise we try to match by type
        var fieldValuesMap = this.controller_.getFieldValuesForBlock(command.blockId);
        var valueType = typeof(command.value);
        if (valueType == "string") {
            for (var i = 0; i < fieldValuesMap.keys_.length; i++) {
                if (this.controller_.isFieldValueValid(command.blockId, fieldValuesMap.keys_[i], command.value) && valueType == typeof(fieldValuesMap.get(fieldValuesMap.keys_[i]))) {
                    fieldIndex = i;
                    break;
                }
            }
        } else if (valueType == "number") {
            command.value += "";
            for (var i = 0; i < fieldValuesMap.keys_.length; i++) {
                if (!this.controller_.isFieldValueValid(command.blockId, fieldValuesMap.keys_[i], command.value) || isNaN(parseInt(fieldValuesMap.get(fieldValuesMap.keys_[i])))) {
                    continue;
                } else {
                    fieldIndex = i;
                    break;
                }
            }
        }
        if (!fieldIndex) {
            console.log("Couldn't determine which field to modify");
            return;
        }
    }

    var block = SpeechBlocks.BlockUtils.getBlock(command.blockId, SpeechGames.workspace);
    var value = $("#synonyms synonym[type='" + block.type + "'][field='" + fields[fieldIndex] + "'][alias='" + command.value + "']").attr("property") || command.value;
    var dropdowns = this.getDropdownValues_(block, fields[fieldIndex]);
    if(dropdowns.length > 0) {
        var synonyms = $("#synonyms synonym[type='" + block.type + "'][field='" + fields[fieldIndex] + "']").map(function() { return $(this).attr("alias") }).toArray()
        if(synonyms.length > 0) {
            if(synonyms.indexOf(command.value) < 0) {
                var msg = "Sorry, I didn't understand '" + command.value + "'. You can say " + synonyms.map(function(x) { return "'" + x + "'" }).join(" or ") + " here.";
                throw new SpeechBlocks.UserError(msg);
            }
        } else {
            if(dropdowns.indexOf(String(value)) < 0) {
                var msg = "Sorry, I didn't understand '" + command.value + "'. You can say " + dropdowns.map(function(x) { return "'" + x + "'" }).join(" or ") + " here.";
                throw new SpeechBlocks.UserError(msg);
            }
        }
    }
    this.controller_.setBlockField(command.blockId, fields[fieldIndex], value);
};

SpeechBlocks.Interpreter.prototype.getDropdownValues_ = function(block, field) {
  for (var i = 0; i < block.inputList.length; i++) {
    var inputList = block.inputList[i];
    for (var j = 0; j < inputList.fieldRow.length; j++) {
      if (inputList.fieldRow[j].name == field) {
        if (inputList.fieldRow[j] instanceof Blockly.FieldDropdown) {
          return inputList.fieldRow[j].menuGenerator_.map(function(x){ return x[1] });
        } else {
          return [];
        }
      }
    }
  }
  return [];
};

/**
 * Delete a specified block.
 * @param {string} blockId The ID of the block to delete.
 * @private
 */
SpeechBlocks.Interpreter.prototype.deleteBlock_ = function(blockId) {
    if (blockId == 'all') {
        this.controller_.removeAllBlocks();
    } else if (this.isBlockIdValid_(blockId)) {
        this.controller_.removeBlock(blockId);
    }
};

/**
 * Checks to see if a block Id is valid.
 * @param {string} blockId as string.
 * @private
 */
SpeechBlocks.Interpreter.prototype.isBlockIdValid_ = function(blockId) {
    return this.controller_.getAllBlockIds().contains(blockId);
};

/**
 * Opens or closes a specified menu.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.menuAction_ = function(command) {
    if (command.actionType == 'open') {
        this.controller_.openMenu(command.menu);
    } else if (command.actionType == 'close') {
        this.controller_.closeMenu();
    }
};
<commit_msg>with previous commit<commit_after>/**
 * @fileoverview Interprets a given command and calls workspace controller_.functions.
 * @author david.liang@wisc.edu (David Liang)
 * @author pandori@wisc.edu (Sahib Pandori)
 */
'use strict';

goog.provide('SpeechBlocks.Interpreter');

goog.require('SpeechBlocks.Predecessor');
goog.require('SpeechBlocks.StatementInput')
goog.require('SpeechBlocks.Successor');
goog.require('SpeechBlocks.Translation');
goog.require('SpeechBlocks.ValueInput');
goog.require('goog.structs.Map');

/**
 * Constructs an interpreter that takes actions as input and controls the Blockly Workspace.
 * @param {!SpeechBlocks.Controller} controller The Blockly Workspace controller.
 * @constructor
 */
SpeechBlocks.Interpreter = function(controller) {
    /** @private @const */
    this.controller_ = controller;

    /** @private {!goog.structs.Map<string, string>} */
    this.blockTypeMap_ = new goog.structs.Map();
    this.createBlockTypeMap_();

    /** @private {!Array<string>} */
    this.blockTypes_ = controller.blockXmlMap_.keys_.slice()
}

/** @private */
SpeechBlocks.Interpreter.prototype.createBlockTypeMap_ = function() {
    this.blockTypeMap_.set('if', 'controls_if');
    this.blockTypeMap_.set('comparison', 'logic_compare');
    this.blockTypeMap_.set('repeat', 'controls_repeat_ext');
    this.blockTypeMap_.set('number', 'math_number');
    this.blockTypeMap_.set('math', 'math_arithmetic');
    this.blockTypeMap_.set('arithmetic', 'math_arithmetic');
    this.blockTypeMap_.set('text', 'text');
    this.blockTypeMap_.set('print', 'text_print');
    this.blockTypeMap_.set('set', 'variables_set');
    this.blockTypeMap_.set('variable', 'variables_get');
    this.blockTypeMap_.set('turn', 'turtle_turn_internal');
    this.blockTypeMap_.set('move', 'turtle_move');
    this.blockTypeMap_.set('pen', 'turtle_pen');
    this.blockTypeMap_.set('repeat', 'turtle_repeat_internal');
    this.blockTypeMap_.set('color', 'turtle_colour_internal');
    this.blockTypeMap_.set('step', 'turtle_step');
}

/**
 * Interprets a given command by calling the corresponding action function.
 * @param {Object} command Command object from parser.
 * @public
 */
SpeechBlocks.Interpreter.prototype.interpret = function(command) {
    this.controller_.closeMenu()
    switch (command.action) {
        case 'run':
            this.run_();
            break;

        case 'add':
            this.addBlock_(command);
            break;

        case 'move':
            this.moveBlock_(command);
            break;

        case 'modify':
            this.modifyBlock_(command);
            break;

        case 'delete':
            this.deleteBlock_(command.blockId.toString());
            break;

        case 'undo':
            this.controller_.undo();
            break;

        case 'redo':
            this.controller_.redo();
            break;

        case 'menu':
            this.menuAction_(command);
            break;
    }
};

/**
 * Compiles the Blockly code into JavaScript and runs it.
 * @private
 */
SpeechBlocks.Interpreter.prototype.run_ = function() {
    document.getElementById('runButton').click();
};

/**
 * Adds a specified block. Can be added to aspecific place.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.addBlock_ = function(command) {
    if (!this.blockTypes_.includes(this.blockTypeMap_.get(command.type))) {
        throw 'Block type ' + this.blockTypes_.toString() + 'not available';
    }

    command.blockId = this.controller_.addBlock(
        this.blockTypeMap_.get(command.type),
        this.controller_.layout.getNewPosition_());
};

/**
 * Moves a specified block.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.moveBlock_ = function(command) {
    command.blockId = command.blockId.toString();
    if (!this.isBlockIdValid_(command.blockId)) {
        throw 'Block ' + command.blockId.toString() + ' does not exist!';
    }

    // Handle cases where target is not a block.
    if (command.where == 'trash') {
        this.deleteBlock_(command.blockId);
        return;
    } else if (command.where == 'away') {
        this.controller_.disconnectBlock(command.blockId);
        return;
    }

    // Handle cases where target is a block.
    command.where.blockId = command.where.blockId.toString();
    if (command.where.blockId == null ||
        !this.isBlockIdValid_(command.where.blockId)) {
        throw 'Block ' + command.where.blockId + ' does not exist!';
    }
    var wheres = []
    try {
        wheres = this.getWheres_(command);
    } catch (e) {
        console.log(e);
        return;
    }
    for (var i = 0; i < wheres.length; i++) {
        try {
            this.controller_.moveBlock(command.blockId, wheres[i]);
        } catch (e) {
            console.log(e);
            continue;
        }
        break;
    }
};

/**
 * Returns a list of potential wheres.
 */
SpeechBlocks.Interpreter.prototype.getWheres_ = function(command) {
    command.where.blockId = command.where.blockId.toString();
    if (command.where.blockId == null ||
        !this.isBlockIdValid_(command.where.blockId)) {
        throw 'Block ' + command.where.blockId + ' does not exist or not given!';
    }

    var wheres = [];
    switch (command.where.position) {
        case 'below':
            wheres.push(new SpeechBlocks.Successor(command.where.blockId));
            break;

        case 'above':
            wheres.push(new SpeechBlocks.Predecessor(command.where.blockId));
            break;

        case 'lhs':
        case 'rhs':
        case 'top':
        case 'to the right of':
            var inputList = this.controller_.getBlockValueInputs(command.where.blockId);
            if (inputList.length == 0) {
                throw 'Block ' + command.where.blockId + ' has no value inputs!';
            } else if (command.where.position == 'rhs' ||
                command.where.position == 'to the right of') {
                wheres.push(new SpeechBlocks.ValueInput(command.where.blockId, inputList[inputList.length - 1]));
            } else if (command.where.position == 'lhs' ||
                command.where.position == 'top') {
                wheres.push(new SpeechBlocks.ValueInput(command.where.blockId, inputList[0]));
            }
            break;

        case 'inside':
            // TODO: We should be handling case-by-case scenarios, where we check if the
            // "where" block has value or statement inputs, as well as if the "to place" block
            // has a previous/output connections.
            var inputList = this.controller_.getBlockValueInputs(command.where.blockId);
            var statementList = this.controller_.getBlockStatementInputs(command.where.blockId);
            for (var i = 0; i < inputList.length; i++) {
                wheres.push(new SpeechBlocks.ValueInput(command.where.blockId, inputList[i]));
            }
            for (var i = 0; i < statementList.length; i++) {
                wheres.push(new SpeechBlocks.StatementInput(command.where.blockId, statementList[statementList.length - 1]));
            }
            break;
    }

    return wheres;
}

/**
 * Modifies a specified block.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.modifyBlock_ = function(command) {
    command.blockId = command.blockId.toString();
    if (!this.isBlockIdValid_(command.blockId)) {
        throw 'Block ' + command.blockId + ' does not exist!';
    }

    // We look for the field the user mentioned
    var fields = this.controller_.getFieldsForBlock(command.blockId).getKeys();
    var fieldIndex;
    if (command.ordinal) {
        switch (command.ordinal) {
            case 'first':
                fieldIndex = 0;
                break;
            case 'second':
                fieldIndex = 1;
                break;
            case 'third':
                fieldIndex = 2;
                break;
        }
    } else {
        // Otherwise we try to match by type
        var fieldValuesMap = this.controller_.getFieldValuesForBlock(command.blockId);
        var valueType = typeof(command.value);
        if (valueType == "string") {
            for (var i = 0; i < fieldValuesMap.keys_.length; i++) {
                if (this.controller_.isFieldValueValid(command.blockId, fieldValuesMap.keys_[i], command.value) && valueType == typeof(fieldValuesMap.get(fieldValuesMap.keys_[i]))) {
                    fieldIndex = i;
                    break;
                }
            }
        } else if (valueType == "number") {
            command.value += "";
            for (var i = 0; i < fieldValuesMap.keys_.length; i++) {
                if (!this.controller_.isFieldValueValid(command.blockId, fieldValuesMap.keys_[i], command.value) || isNaN(parseInt(fieldValuesMap.get(fieldValuesMap.keys_[i])))) {
                    continue;
                } else {
                    fieldIndex = i;
                    break;
                }
            }
        }
        if (!fieldIndex) {
            console.log("Couldn't determine which field to modify");
            return;
        }
    }

    var block = SpeechBlocks.BlockUtils.getBlock(command.blockId, SpeechGames.workspace);
    var value = $("#synonyms synonym[type='" + block.type + "'][field='" + fields[fieldIndex] + "'][alias='" + command.value + "']").attr("property") || command.value;
    var dropdowns = this.getDropdownValues_(block, fields[fieldIndex]);
    if (dropdowns.length > 0) {
        var synonyms = $("#synonyms synonym[type='" + block.type + "'][field='" + fields[fieldIndex] + "']").map(function() { return $(this).attr("alias") }).toArray()
        if (synonyms.length > 0) {
            if (synonyms.indexOf(command.value) < 0) {
                var msg = "Sorry, I didn't understand '" + command.value + "'. You can say " + synonyms.map(function(x) { return "'" + x + "'" }).join(" or ") + " here.";
                throw new SpeechBlocks.UserError(msg);
            }
        } else {
            if (dropdowns.indexOf(String(value)) < 0) {
                var msg = "Sorry, I didn't understand '" + command.value + "'. You can say " + dropdowns.map(function(x) { return "'" + x + "'" }).join(" or ") + " here.";
                throw new SpeechBlocks.UserError(msg);
            }
        }
    }
    this.controller_.setBlockField(command.blockId, fields[fieldIndex], value);
};

SpeechBlocks.Interpreter.prototype.getDropdownValues_ = function(block, field) {
    for (var i = 0; i < block.inputList.length; i++) {
        var inputList = block.inputList[i];
        for (var j = 0; j < inputList.fieldRow.length; j++) {
            if (inputList.fieldRow[j].name == field) {
                if (inputList.fieldRow[j] instanceof Blockly.FieldDropdown) {
                    return inputList.fieldRow[j].menuGenerator_.map(function(x) { return x[1] });
                } else {
                    return [];
                }
            }
        }
    }
    return [];
};

/**
 * Delete a specified block.
 * @param {string} blockId The ID of the block to delete.
 * @private
 */
SpeechBlocks.Interpreter.prototype.deleteBlock_ = function(blockId) {
    if (blockId == 'all') {
        this.controller_.removeAllBlocks();
    } else if (this.isBlockIdValid_(blockId)) {
        this.controller_.removeBlock(blockId);
    }
};

/**
 * Checks to see if a block Id is valid.
 * @param {string} blockId as string.
 * @private
 */
SpeechBlocks.Interpreter.prototype.isBlockIdValid_ = function(blockId) {
    return this.controller_.getAllBlockIds().contains(blockId);
};

/**
 * Opens or closes a specified menu.
 * @param {Object} command Command object from parser.
 * @private
 */
SpeechBlocks.Interpreter.prototype.menuAction_ = function(command) {
    if (command.actionType == 'open') {
        this.controller_.openMenu(command.menu);
    } else if (command.actionType == 'close') {
        this.controller_.closeMenu();
    }
};<|endoftext|>


<commit_before>var fs = require('fs.extra');
exports.ngneer = {
    copySinglePageApp: function(flavour){
        var src = process.env.NODE_PATH + '/ngneer/templates/' + flavour + '/index.html',
            dest = process.cwd() + '/index.html';
        fs.copy(src, dest, console.log);
        console.log('Your', flavour, 'application has been created.');
        console.log('\t', dest);
    },
    vanilla: function(){
        this.copySinglePageApp('vanilla');
    },
    ipa: function(){
        this.copySinglePageApp('ipa');
    }
};<commit_msg>why use console.log as callback, no reason really<commit_after>var fs = require('fs.extra');
exports.ngneer = {
    copySinglePageApp: function(flavour){
        var src = process.env.NODE_PATH + '/ngneer/templates/' + flavour + '/index.html',
            dest = process.cwd() + '/index.html';
        fs.copy(src, dest);
        console.log('Your', flavour, 'application has been created.');
        console.log('\t', dest);
    },
    vanilla: function(){
        this.copySinglePageApp('vanilla');
    },
    ipa: function(){
        this.copySinglePageApp('ipa');
    }
};<|endoftext|>


<commit_before>/**
 * Simple logger (using both file and console)
 */
module.exports = function(logFile, params) {
	var colors = require('ansicolors'),
		fs = require('fs'),
		beVerbose = params.beVerbose === true,
		beSilent = params.beSilent === true,
		stream;

	if (logFile !== '') {
		// use an absolute path
		logFile = fs.absolute(logFile);
		log("Logging to " + logFile);

		// set up a stream to be used for logging
		stream = fs.open(logFile, 'w');
	}

	function echo(msg) {
		if (!beSilent) {
			console.log(msg);
		}
	}

	function log(msg) {
		var ts = (new Date()).toJSON().substr(11, 12);

		// format a message
		msg = (typeof msg === 'object') ? JSON.stringify(msg) : msg;

		// log to the console (--verbose)
		if (beVerbose) {
			echo(ts + ' ' + colors.brightBlack(msg));
		}

		// log to the file (--log)
		if (stream) {
			stream.writeLine(ts + ': ' + msg);
			stream.flush();
		}
	}

	// public interface
	this.echo = echo;
	this.log = log;
};
<commit_msg>logger: trim messages<commit_after>/**
 * Simple logger (using both file and console)
 */
module.exports = function(logFile, params) {
	var colors = require('ansicolors'),
		fs = require('fs'),
		beVerbose = params.beVerbose === true,
		beSilent = params.beSilent === true,
		stream;

	if (logFile !== '') {
		// use an absolute path
		logFile = fs.absolute(logFile);
		log("Logging to " + logFile);

		// set up a stream to be used for logging
		stream = fs.open(logFile, 'w');
	}

	function echo(msg) {
		if (!beSilent) {
			console.log(msg);
		}
	}

	function log(msg) {
		var ts = (new Date()).toJSON().substr(11, 12);

		// format a message
		msg = (typeof msg === 'object') ? JSON.stringify(msg) : msg.toString().trim();

		// log to the console (--verbose)
		if (beVerbose) {
			echo(ts + ' ' + colors.brightBlack(msg));
		}

		// log to the file (--log)
		if (stream) {
			stream.writeLine(ts + ': ' + msg);
			stream.flush();
		}
	}

	// public interface
	this.echo = echo;
	this.log = log;
};
<|endoftext|>


<commit_before>var request = require('request');
var ee = require('events').EventEmitter;
var util = require('util');
var qs = require('querystring');

var Omegle = function()
	{
		ee.call(this);
		var useragent = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0';
		var url = 'http://front1.omegle.com';
		var gotID = false;
		var isConnected = false;
		var _this = this;
		var lastEvent = 'aaa';
		this.id='';
		var typing = false;
		var randID = function(){
			var charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
			var str='';
			for(i=0; i<8; ++i)
				str+=charset.charAt(Math.floor((Math.random() * (charset.length+1))));
			return str;
		}

		var getResponse = function(path, data, callback, method='POST'){
			var qsArr = ['/status','/start'];
			var options = {
			  url: url+path,
			  headers: {
				'User-Agent': useragent,
				'Connection': 'keep-alive',
				'Referer' : 'http://www.omegle.com',
				'Origin' :'http://www.omegle.com',
				'Host' : url,
				'Content-Type': 'application/x-www-form-urlencoded',
				'Content-Length' : 0
			  },
			  method: method
			};
			if (qsArr.indexOf(path)>-1)
			{
				options['qs'] = data;
			}
			else
			{
				options.headers['Content-Length'] = qs.stringify(data).length;
				options['form'] = qs.stringify(data);
			}

			request(options, function (error, response, body) {
			  if (!error && response.statusCode == 200) {
				//if(path=='/events')console.log(options.qs)
				return callback(body,null);
			  }
			  else
			  {
				//console.log('Error: '+ path +'\t'+error);
				return callback(false,error);
			  }
			});
		}

		this.connect=function(){
			this.updateServer();
			var data = {
				rcs: 1,
				firstevents: 1,
				lang: 'en',
				randid: randID(),
				spid:''
				};
			getResponse('/start',data, function(body,error){
				if(body)
				{
					_this.id=JSON.parse(body).clientID;
					gotID = true;
					_this.emit('gotID', _this.id);
					emitEvents(JSON.parse(body).events)
					_this.getEvents();
				}
				else
					_this.emit('omerror', 'connect(): '+error);
			});
		}

		this.getEvents=function(){
			var data={id:_this.id};

			getResponse('/events',data, function(events,error){
				if(events)
				{
					var ev = JSON.parse(events);
					//console.log('Events: '+ev);
					emitEvents(ev);
					if(gotID)
						_this.getEvents();
				}
				else
				{
					_this.emit('omerror', 'getEvents(): '+error);
					if(gotID)
						_this.getEvents();
				}
			});
		}

		var emitEvents = function(ev){

			for(i=0;i<ev.length;++i)
			{
				var currentEvent = ev[i][0];
				lastEvent = currentEvent;
				if(currentEvent=='waiting')
					_this.emit('waiting');
				else if(currentEvent=='connected')
				{
					isConnected = true;
					_this.emit('connected');
				}
				else if(currentEvent=='error')
				{
					isConnected = false;
					gotID = false;
					_this.emit('error', ev[i][1]);
				}
				else if(currentEvent=='connectionDied')
				{
					isConnected = false;
					gotID = false;
					_this.emit('connectionDied');
				}
				else if(currentEvent=='antinudeBanned')
				{
					isConnected = false;
					gotID = false;
					_this.emit('antinudeBanned');
				}
				else if(currentEvent=='typing')
				{
					typing = true;
					_this.emit('typing');
				}
				else if(currentEvent=='stoppedTyping')
					_this.emit('stoppedTyping');
				else if(currentEvent=='gotMessage')
				{
					if(typing)
						_this.emit('stoppedTyping');
					_this.emit('gotMessage',ev[i][1]);
				}
				else if(currentEvent=='strangerDisconnected')
				{
					isConnected = false;
					gotID = false;
					_this.emit('strangerDisconnected');
				}

			}

		}

		this.updateServer=function(){
			getResponse('/status',{nocache:Math.random(),randid:randID()},function(statusBody,error){
				if(statusBody)
				{
					url='http://'+JSON.parse(statusBody).servers[0];
					_this.emit('serverUpdated', url);
				}
				else
				{
					_this.emit('omerror', 'updateServer(): '+ error);
				}
			},'GET');
		}

		this.send = function(msg){
			if(gotID&&isConnected)
			{
				var data={msg:msg,id:_this.id};
				getResponse('/send',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'send(): '+ body);
					}
					else
						_this.emit('omerror', 'send(): '+error);
				});
			}
			else
			{
				_this.emit('omerror', 'send(): Not connected to '+(gotID?'a stranger yet.':'the server.'));
			}
		}

		this.startTyping = function(){
			if(gotID&&isConnected)
			{
				var data={id:_this.id};
				getResponse('/typing',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Couldn\'t send the typing event. Response from server: '+ body);
					}
					else
						_this.emit('omerror', error);
				});
			}
			else
				_this.emit('omerror', 'Couldn\'t send the typing event. Not connected to '+(gotID?'a stranger yet.':'the server.'));
		}

		this.stopTyping = function(){
			if(gotID&&isConnected)
			{
				var data={id:_this.id};
				getResponse('/stoppedtyping',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Couldn\'t send the stoppedtyping event. Response from server: '+ body);
					}
					else
						_this.emit('omerror', error);
				});
			}
			else
				_this.emit('omerror', 'Couldn\'t send the stoppedtyping event. Not connected to '+(gotID?'a stranger yet.':'the server.'));
		}

		this.stopLookingForCommonLikes = function(callback){
			if(lastEvent=='waiting')
			{
				var data={id:_this.id};
				getResponse('/stoplookingforcommonlikes',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Something went wrong. Response from server: '+ body);
					}
					else
						_this.emit('omerror', error);

					if(callback)
						callback(body);
				});
			}
			else
				_this.emit('omerror','stopLookingForCommonLikes: ' + lastEvent +  (isConnected?'Already connected to a stranger':'Current event is not \'waiting\'. Current event: '+lastEvent));
		}

		this.slfcl = this.stopLookingForCommonLikes;

		this.disconnect = function(){
			if(gotID&&isConnected)
			{
				var data={id:_this.id};
				getResponse('/disconnect',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Couldn\'t send the disconnect event. Response from server: '+ body);
						isConnected = false;
						gotID = false;
					}
					else
						_this.emit('omerror', error);
				});
			}
			else
				_this.emit('omerror', 'Couldn\'t send the disconnect event. Not connected to '+(gotID?'a stranger yet.':'the server.'));
		}

	}

util.inherits(Omegle, ee);

module.exports = Omegle;<commit_msg>Added reCAPTCHA related events<commit_after>var request = require('request');
var ee = require('events').EventEmitter;
var util = require('util');
var qs = require('querystring');

var Omegle = function()
	{
		ee.call(this);
		var useragent = 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0';
		var url = 'http://front1.omegle.com';
		var gotID = false;
		var isConnected = false;
		var _this = this;
		var lastEvent = 'aaa';
		this.id='';
		var typing = false;
		var randID = function(){
			var charset='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
			var str='';
			for(i=0; i<8; ++i)
				str+=charset.charAt(Math.floor((Math.random() * (charset.length+1))));
			return str;
		}

		var getResponse = function(path, data, callback, method='POST'){
			var qsArr = ['/status','/start'];
			var options = {
			  url: url+path,
			  headers: {
				'User-Agent': useragent,
				'Connection': 'keep-alive',
				'Referer' : 'http://www.omegle.com',
				'Origin' :'http://www.omegle.com',
				'Host' : url,
				'Content-Type': 'application/x-www-form-urlencoded',
				'Content-Length' : 0
			  },
			  method: method
			};
			if (qsArr.indexOf(path)>-1)
			{
				options['qs'] = data;
			}
			else
			{
				options.headers['Content-Length'] = qs.stringify(data).length;
				options['form'] = qs.stringify(data);
			}

			request(options, function (error, response, body) {
			  if (!error && response.statusCode == 200) {
				//if(path=='/events')console.log(options.qs)
				return callback(body,null);
			  }
			  else
			  {
				//console.log('Error: '+ path +'\t'+error);
				return callback(false,error);
			  }
			});
		}

		this.connect=function(){
			this.updateServer();
			var data = {
				rcs: 1,
				firstevents: 1,
				lang: 'en',
				randid: randID(),
				spid:''
				};
			getResponse('/start',data, function(body,error){
				if(body)
				{
					_this.id=JSON.parse(body).clientID;
					gotID = true;
					_this.emit('gotID', _this.id);
					emitEvents(JSON.parse(body).events)
					_this.getEvents();
				}
				else
					_this.emit('omerror', 'connect(): '+error);
			});
		}

		this.getEvents=function(){
			var data={id:_this.id};

			getResponse('/events',data, function(events,error){
				if(events)
				{
					var ev = JSON.parse(events);
					//console.log('Events: '+ev);
					emitEvents(ev);
					if(gotID)
						_this.getEvents();
				}
				else
				{
					_this.emit('omerror', 'getEvents(): '+error);
					if(gotID)
						_this.getEvents();
				}
			});
		}

		var emitEvents = function(ev){

			for(i=0;i<ev.length;++i)
			{
				var currentEvent = ev[i][0];
				lastEvent = currentEvent;
				if(currentEvent=='waiting')
					_this.emit('waiting');
				else if(currentEvent=='connected')
				{
					isConnected = true;
					_this.emit('connected');
				}
				else if(currentEvent=='error')
				{
					isConnected = false;
					gotID = false;
					_this.emit('error', ev[i][1]);
				}
				else if(currentEvent=='connectionDied')
				{
					isConnected = false;
					gotID = false;
					_this.emit('connectionDied');
				}
				else if(currentEvent=='antinudeBanned')
				{
					isConnected = false;
					gotID = false;
					_this.emit('antinudeBanned');
				}
				else if(currentEvent=='typing')
				{
					typing = true;
					_this.emit('typing');
				}
				else if(currentEvent=='stoppedTyping')
					_this.emit('stoppedTyping');
				else if(currentEvent=='gotMessage')
				{
					if(typing)
						_this.emit('stoppedTyping');
					for(j = 1; j<ev[i].length; ++j)
						_this.emit('gotMessage',ev[i][j]);
				}
				else if(currentEvent=='strangerDisconnected')
				{
					isConnected = false;
					gotID = false;
					_this.emit('strangerDisconnected');
				}
				else if(currentEvent=='recaptchaRequired')
				{
					_this.emit('recaptchaRequired','https://www.google.com/recaptcha/api/image?c='+ev[i][1]);
				}
				else if(currentEvent=='recaptchaRejected')
				{
					_this.emit('recaptchaRejected','https://www.google.com/recaptcha/api/image?c='+ev[i][1]);
				}
			}

		}

		this.updateServer=function(){
			getResponse('/status',{nocache:Math.random(),randid:randID()},function(statusBody,error){
				if(statusBody)
				{
					url='http://'+JSON.parse(statusBody).servers[0];
					_this.emit('serverUpdated', url);
				}
				else
				{
					_this.emit('omerror', 'updateServer(): '+ error);
				}
			},'GET');
		}

		this.send = function(msg){
			if(gotID&&isConnected)
			{
				var data={msg:msg,id:_this.id};
				getResponse('/send',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'send(): '+ body);
					}
					else
						_this.emit('omerror', 'send(): '+error);
				});
			}
			else
			{
				_this.emit('omerror', 'send(): Not connected to '+(gotID?'a stranger yet.':'the server.'));
			}
		}

		this.startTyping = function(){
			if(gotID&&isConnected)
			{
				var data={id:_this.id};
				getResponse('/typing',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Couldn\'t send the typing event. Response from server: '+ body);
					}
					else
						_this.emit('omerror', error);
				});
			}
			else
				_this.emit('omerror', 'Couldn\'t send the typing event. Not connected to '+(gotID?'a stranger yet.':'the server.'));
		}

		this.stopTyping = function(){
			if(gotID&&isConnected)
			{
				var data={id:_this.id};
				getResponse('/stoppedtyping',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Couldn\'t send the stoppedtyping event. Response from server: '+ body);
					}
					else
						_this.emit('omerror', error);
				});
			}
			else
				_this.emit('omerror', 'Couldn\'t send the stoppedtyping event. Not connected to '+(gotID?'a stranger yet.':'the server.'));
		}

		this.stopLookingForCommonLikes = function(callback){
			if(lastEvent=='waiting')
			{
				var data={id:_this.id};
				getResponse('/stoplookingforcommonlikes',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Something went wrong. Response from server: '+ body);
					}
					else
						_this.emit('omerror', error);

					if(callback)
						callback(body);
				});
			}
			else
				_this.emit('omerror','stopLookingForCommonLikes: ' + lastEvent +  (isConnected?'Already connected to a stranger':'Current event is not \'waiting\'. Current event: '+lastEvent));
		}

		this.slfcl = this.stopLookingForCommonLikes;

		this.disconnect = function(){
			if(gotID&&isConnected)
			{
				var data={id:_this.id};
				getResponse('/disconnect',data, function(body,error){
					if(body)
					{
						if(body!='win')
							_this.emit('omerror', 'Couldn\'t send the disconnect event. Response from server: '+ body);
						isConnected = false;
						gotID = false;
					}
					else
						_this.emit('omerror', error);
				});
			}
			else
				_this.emit('omerror', 'Couldn\'t send the disconnect event. Not connected to '+(gotID?'a stranger yet.':'the server.'));
		}

	}

util.inherits(Omegle, ee);

module.exports = Omegle;<|endoftext|>


<commit_before>import React from 'react'
import { findDOMNode } from 'react-dom'
import { Seed } from 'react-seeds'

function sizeTextAreaToFit(el) {
	const { style } = el
	style.height = '1px'

	const measuredHeight = `${el.scrollHeight}px`
	style.height = measuredHeight
	style.resize = 'none'
}

export default React.createClass({
	setElement(component) {
		const el = findDOMNode(component)

		this.el = el

		if (el != null) { // null when unmounting
			sizeTextAreaToFit(el)
		}
	},

	onChange(event) {
		const el = event.target

		sizeTextAreaToFit(el)

		const value = el.value
		this.props.onChange(value)
	},

	render() {
		return (
			<Seed Component='textarea'
				ref={ this.setElement }
				{ ...this.props }
				onChange={ this.onChange }
			/>
		)
	},

	componentDidUpdate() {
		if (this.el) {
			sizeTextAreaToFit(this.el)
		}
	}
})
<commit_msg>Fix size-to-fit height of <Field><commit_after>import React from 'react'
import { findDOMNode } from 'react-dom'
import { Seed } from 'react-seeds'

function sizeTextAreaToFit(el) {
	const { style } = el
	style.height = '1px'

	const measuredHeight = `${ el.scrollHeight + el.offsetHeight - el.clientHeight }px`
	style.height = measuredHeight
	style.resize = 'none'
}

export default React.createClass({
	setElement(component) {
		const el = findDOMNode(component)

		this.el = el

		if (el != null) { // null when unmounting
			sizeTextAreaToFit(el)
		}
	},

	onChange(event) {
		const el = event.target

		sizeTextAreaToFit(el)

		const value = el.value
		this.props.onChange(value)
	},

	render() {
		return (
			<Seed Component='textarea'
				ref={ this.setElement }
				{ ...this.props }
				onChange={ this.onChange }
			/>
		)
	},

	componentDidUpdate() {
		if (this.el) {
			sizeTextAreaToFit(this.el)
		}
	}
})
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.dao',
  name: 'SQLException',
  extends: 'foam.core.Exception'
});

foam.CLASS({
  refines: 'foam.mlang.predicate.AbstractPredicate',

  methods: [
    function sqlValue(argName) {
      var arg = this[argName];
      var v = arg.toSQL ? arg.toSQL() :
        arg.toString ? arg.toString() :
        arg;

      if ( v === undefined || v === null )
        throw this.SQLException.create({message: this.cls_.name + '.' + argName +': '+ v});

      return v;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.Constant',
  methods: [
    function toSQL() {
      if ( isNaN(this.value) ) {
        var v = this.value.toString().toLowerCase();
        if (v === 'true' || v === 'yes') return 1;
        if (v === 'false' || v === 'no') return 0;
        return this.value.toString();
      }

      if ( this.value === true ) return 1;

      if ( this.value === false ) return 0;

      return this.value;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.True',
  methods: [
    function toSQL() { return '( 1 = 1 )'; }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.False',
  methods: [
    function toSQL() { return '( 1 <> 1 )'; }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Unary',
  requires: [ 'foam.dao.SQLException' ],
  methods: [
    function toSQL() {
      throw this.SQLException.create({message: this.cls_.name + '.toSQL() not implemented'});
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Binary',
  requires: [ 'foam.dao.SQLException' ],
  methods: [
    function toSQL() {
      throw this.SQLException.create({message: this.cls_.name + '.toSQL() not implemented'});
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Has',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' IS NOT NULL';
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Not',
  methods: [
    function toSQL() { return 'NOT ('+ this.arg1.toSQL()+')'; }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Eq',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      var values = this.SQLSupport.create().values(this);

      return values.v2 === null ?
          values.v1 + ' IS NULL' :
          values.v1 + " = " + values.v2 ;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Neq',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      return this.arg2 === null ?
        this.sqlValue('arg1') + ' IS NOT NULL' :
        this.sqlValue('arg1') + " <> " + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Gt',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' > ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Gte',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' >= ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Lt',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' < ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Lte',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' <= ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.And',
  methods: [
    // AND has a higher precedence than OR so doesn't need paranthesis
    function toSQL() {
      var s = '';
      for ( var i = 0 ; i < this.args.length ; i++ ) {
        var a = this.args[i];
        s += a.toSQL();
        if ( i < this.args.length - 1 )
        s += ' AND ';
      }
      return s;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Or',
  methods: [
    function toSQL() {
      var s = ' ( ';
      for ( var i = 0 ; i < this.args.length ; i++ ) {
        var a = this.args[i];
        s += a.toSQL();
        if ( i < this.args.length - 1 )
        s += ' OR ';
      }
      s += ' ) ';
      return s;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.In',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      var s = this.sqlValue('arg1');
      s += ' IN ( \'';
      if ( Array.isArray(this.arg2) ) {
        s += this.arg2.join('\', \'');
      } else {
        s += this.sqlValue('arg2');
      }
      s += '\')';
      return s;
    }
  ]
});

foam.CLASS({
  refines: 'foam.core.Date',
  methods: [
    function toSQL() {
      var v1 = this.value || 0;
      return new Date(v1).toISOString();
    }
  ]
});
<commit_msg>SQL - sqlValue handle this[argName] returning null/undefined.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.dao',
  name: 'SQLException',
  extends: 'foam.core.Exception'
});

foam.CLASS({
  refines: 'foam.mlang.predicate.AbstractPredicate',

  methods: [
    function sqlValue(argName) {
      var arg = this[argName];
      var v = arg && arg.toSQL ? arg.toSQL() :
        arg && arg.toString ? arg.toString() :
        arg;

      if ( v === undefined || v === null )
        throw this.SQLException.create({message: this.cls_.name + '.' + argName +': '+ v});

      return v;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.Constant',
  methods: [
    function toSQL() {
      if ( isNaN(this.value) ) {
        var v = this.value.toString().toLowerCase();
        if (v === 'true' || v === 'yes') return 1;
        if (v === 'false' || v === 'no') return 0;
        return this.value.toString();
      }

      if ( this.value === true ) return 1;

      if ( this.value === false ) return 0;

      return this.value;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.True',
  methods: [
    function toSQL() { return '( 1 = 1 )'; }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.False',
  methods: [
    function toSQL() { return '( 1 <> 1 )'; }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Unary',
  requires: [ 'foam.dao.SQLException' ],
  methods: [
    function toSQL() {
      throw this.SQLException.create({message: this.cls_.name + '.toSQL() not implemented'});
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Binary',
  requires: [ 'foam.dao.SQLException' ],
  methods: [
    function toSQL() {
      throw this.SQLException.create({message: this.cls_.name + '.toSQL() not implemented'});
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Has',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' IS NOT NULL';
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Not',
  methods: [
    function toSQL() { return 'NOT ('+ this.arg1.toSQL()+')'; }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Eq',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      var values = this.SQLSupport.create().values(this);

      return values.v2 === null ?
          values.v1 + ' IS NULL' :
          values.v1 + " = " + values.v2 ;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Neq',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      return this.arg2 === null ?
        this.sqlValue('arg1') + ' IS NOT NULL' :
        this.sqlValue('arg1') + " <> " + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Gt',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' > ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Gte',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' >= ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Lt',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' < ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Lte',
  requires: [
    'foam.mlang.predicate.SQLSupport',
    'foam.dao.SQLException'
  ],
  methods: [
    function toSQL() {
      return this.sqlValue('arg1') + ' <= ' + this.sqlValue('arg2');
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.And',
  methods: [
    // AND has a higher precedence than OR so doesn't need paranthesis
    function toSQL() {
      var s = '';
      for ( var i = 0 ; i < this.args.length ; i++ ) {
        var a = this.args[i];
        s += a.toSQL();
        if ( i < this.args.length - 1 )
        s += ' AND ';
      }
      return s;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.Or',
  methods: [
    function toSQL() {
      var s = ' ( ';
      for ( var i = 0 ; i < this.args.length ; i++ ) {
        var a = this.args[i];
        s += a.toSQL();
        if ( i < this.args.length - 1 )
        s += ' OR ';
      }
      s += ' ) ';
      return s;
    }
  ]
});

foam.CLASS({
  refines: 'foam.mlang.predicate.In',
  requires: [ 'foam.mlang.predicate.SQLSupport' ],
  methods: [
    function toSQL() {
      var s = this.sqlValue('arg1');
      s += ' IN ( \'';
      if ( Array.isArray(this.arg2) ) {
        s += this.arg2.join('\', \'');
      } else {
        s += this.sqlValue('arg2');
      }
      s += '\')';
      return s;
    }
  ]
});

foam.CLASS({
  refines: 'foam.core.Date',
  methods: [
    function toSQL() {
      var v1 = this.value || 0;
      return new Date(v1).toISOString();
    }
  ]
});
<|endoftext|>