<commit_before>'use babel';

import HRKV from './highlight-registered-keyword-view';
import RFC, { Configs, EditorState } from './read-from-configcson';
import { getOnlySecond } from './utility';
import { CompositeDisposable, File as AtomFile } from 'atom';

export default {
  config: {
    patternsFilePath: {
      type: 'string',
      description: 'Specify the CSON file that describing patterns.',
      'default': ''
    },
    delay: {
      type: 'integer',
      description: 'delay time for update(ms)',
      'default': 1500,
      minimum: 0,
      maximum: 5000
    },
    disableUpdate: {
      type: 'boolean',
      description: 'If set this, updating of highlight will be disabled',
      'default': false
    },
    autoMark: {
      type: 'boolean',
      description: 'If set this, highlights all editors automatically',
      'default': false
    }
  },

  initalize() {
    this.name = 'highlight-registered-keyword';
    this.kInitRange = [[Infinity, 0], [0, 0]];
    this.kInvalidate = 'never'; // never or inside

    this.subscriptions = null;
    this.editorStates = [];
    this.timerId = null;  //Timer ID
    this.changedRange = this.kInitRange;  //shallow copy

    this.configs = new Configs();

    this.patternsFile = null;  //監視対象のファイル
    this.fileSubscription = null; //監視対象のファイルのsubscription
  },

  activate() {
    this.initalize();

    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'highlight-registered-keyword:markAll': () => this.markAll(),
      'highlight-registered-keyword:unmarkAll': () => this.unmarkAll(),
      'highlight-registered-keyword:mark': () => this.markActive(),
      'highlight-registered-keyword:unmark': () => this.unmarkActive(),
      'highlight-registered-keyword:show': () => this.show(),
      'highlight-registered-keyword:open': () => this.open(),
      'highlight-registered-keyword:settings': () => this.settings()
    }));

    atom.workspace.addOpener(
      (uri) => {
        if(uri === this.name + '://ValidConfigs') {
          let view = new HRKV();

          view.makeElement(this.configs);
          return view;
        }
        return null;
      }
    );

    this.getConfigs();
    RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
  },

  getConfigs() {
    this.configs.patternsFilePath = atom.config.get(this.name + '.patternsFilePath');
    this.configs.delay = atom.config.get(this.name + '.delay');
    this.configs.disableUpdate = atom.config.get(this.name + '.disableUpdate');
    this.configs.autoMark = atom.config.get(this.name + '.autoMark');

    this.subscriptions.add(atom.workspace.observeTextEditors(this.getTextEditors()));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.patternsFilePath', this.getPatternsFilePath()));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.delay', this.getChangedConfig('delay')));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.autoMark', this.getChangedConfig('autoMark')));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.disableUpdate', this.getDisableUpdate()));
  },

  deactivate() {
    this.subscriptions.dispose();
    this.disposeAllEditorSubscriptions();
    this.unmarkAllEditors(null, true);
    if( this.timerId !== null) {
      clearTimeout(this.timerId);
    }
  },

  /*
  //commands
  */
  markAll() {
    this.unmarkAllEditors(null, false);
    this.markAllEditors(null);
  },
  unmarkAll() {
    this.unmarkAllEditors(null, true);
  },
  markActive() {
    let editorState = this.getActiveEditorState();

    if(editorState === null) {
      return;
    }
    this.unmarkEditor(editorState, editorState.editor.getBuffer().getRange(), null, false);
    this.markEditor(editorState, editorState.editor.getBuffer().getRange(), null);
  },
  unmarkActive() {
    let editorState = this.getActiveEditorState();

    if(editorState === null) {
      return;
    }
    this.unmarkEditor(editorState, editorState.editor.getBuffer().getRange(), null, true);
  },

  show() {
    atom.workspace.open(this.name + '://ValidConfigs');
  },

  open () {
    atom.workspace.open(this.configs.patternsFilePath);
  },
  /*
  read() {
    RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
  },
  //*/
  settings() {
    atom.workspace.open('atom://config/packages/' + this.name);
  },

  getActiveEditorState() {
    let editor = atom.workspace.getActiveTextEditor();

    if(editor === '') {
      return null;
    }
    for(let editorState of this.editorStates) {
      if(editorState.editor.id === editor.id) {
        return editorState;
      }
    }
    return null;
  },

  /*
  mark / unmark
  */
  mark(editor, pattern, range) {
    if(pattern.disable) {
      return;
    }
    editor.scanInBufferRange(pattern.pattern, range,
      (result) => {
        let marker = editor.markBufferRange(result.range, {invalidate: this.kInvalidate, class: pattern.class});

        editor.decorateMarker(marker, {type: 'highlight', class: pattern.class});
      }
    );
  },

  markEditor(editorState, range, patterns) {
    if(editorState.marked === true) {
      return;
    }
    let target = [];

    if(patterns !== null) {
      target = patterns;
    } else {
      target = this.configs.patterns;
    }

    for(let pattern of target) {
      this.mark(editorState.editor, pattern, range);
    }
    editorState.marked = true;
    this.setEditorDidChange(editorState);
  },

  markAllEditors(patterns) {
    for(let i = 0; i < this.editorStates.length; ++i) { //for...of
      this.markEditor(this.editorStates[i], this.editorStates[i].editor.getBuffer().getRange(), patterns)
    }
  },

  unmark(editor, pattern, range) {
    if(pattern.disable) {
      return;
    }
    let markers = [];

    markers = editor.findMarkers({containedInBufferRange: range, class: pattern.class})
    for(let i = 0; i < markers.length; ++i ){
      markers[i].destroy()
    }
  },

  unmarkEditor(editorState, range, patterns, doDispose) {
    if(editorState.marked === false) {
      return;
    }
    let target = [];

    if(patterns !== null) {
      target = patterns;
    } else {
      target = this.configs.patterns;
    }

    for(let pattern of target) {
      this.unmark(editorState.editor, pattern, range);
    }
    editorState.marked = false;
    if(doDispose === true) {
      this.disposeEditorSubscription(editorState);
    }
  },

  unmarkAllEditors(patterns, doDispose) {
    for(let i = 0; i < this.editorStates.length; ++i) {
      this.unmarkEditor(this.editorStates[i], this.editorStates[i].editor.getBuffer().getRange(), patterns, doDispose);
    }
  },

  //既にmarkedのEditorのみRemarkする
  remarkAllEditors(patterns) {
    for(let i = 0; i < this.editorStates.length; ++i){
      if(this.editorStates[i].marked) {
        let range = this.editorStates[i].editor.getBuffer().getRange();

        this.unmarkEditor(this.editorStates[i], range, getOnlySecond(patterns, this.configs.patterns), false);
        this.markEditor(this.editorStates[i], range, getOnlySecond(this.configs.patterns, patterns));
      }
    }
  },

  //
  getChangedRange(evt) {
    let minR = 0, maxR = 0;

    minR = Math.min(evt.oldRange.start.row, evt.oldRange.end.row,
      evt.newRange.start.row, evt.newRange.end.row, this.changedRange[0][0]);
    maxR = Math.max(evt.oldRange.start.row, evt.oldRange.end.row,
      evt.newRange.start.row, evt.newRange.end.row, this.changedRange[1][0]);

    this.changedRange = [[minR, 0], [maxR, 0]];
    return this.changedRange;
  },

  //実際の範囲を調べずに+-1をしているが問題ない様だ
  //shallow copy
  getMarkRange(range) {
    let markRange = range;

    --markRange[0][0];
    ++markRange[1][0];
    return markRange;
  },

  change(editorState) {
    return (range) => {
      if(this.configs.disableUpdate === true){
        return;
      }
      range = this.getMarkRange(range);
      this.unmarkEditor(editorState, range, null, false);
      this.markEditor(editorState, range, null);
      this.changedRange = this.kInitRange;  //shallow copy
      this.timerId = null;
    };
  },

  setTimer(editorState) {
    return (evt) => {
      if( this.timerId !== null) {
        clearTimeout(this.timerId);
        if(this.configs.disableUpdate === true){
          return;
        }
      }
      this.timerId = setTimeout(this.change(editorState), this.configs.delay, this.getChangedRange(evt));
    }
  },

  //
  setEditorDidChange(editorState) {
    if(editorState.marked === true && editorState.subscription === null) {
      editorState.subscription = editorState.editor.getBuffer().onDidChange(this.setTimer(editorState));
    }
  },

  //全てのEditorを監視対象から外す
  disposeAllEditorSubscriptions() {
    for(let editorState of this.editorStates) {
      this.disposeEditorSubscription(editorState);
    }
  },
  //1つのEditorを監視対象から外す
  disposeEditorSubscription(editorState) {
    if(editorState.subscription === null) {
      return;
    }
    editorState.subscription.dispose();
    editorState.subscription = null;
  },

  onEditorDidDestroy(editorState) {
    return () => {
      this.disposeEditorSubscription(editorState);
      this.editorStates.splice(this.editorStates.indexOf(editorState), 1);
    }
  },

  getTextEditors() {
    return (editor) => {
      if(!editor) {
        return;
      }
      let editorState = new EditorState(editor);

      editor.onDidDestroy(this.onEditorDidDestroy(editorState));
      this.editorStates.push(editorState);
      if(this.configs.autoMark) {
        this.unmarkEditor(editorState, editor.getBuffer().getRange(), null);
        this.markEditor(editorState, editor.getBuffer().getRange(), null);
      }
    };
  },

  /*
  config
  */

  getChangedConfig(property){
    return (evt) => {
      this.configs[property] = evt.newValue;
    };
  },

  getPatternsFilePath() {
    return (evt) => {
      this.configs.patternsFilePath = evt.newValue;
      RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
    }
  },

  getDisableUpdate() {
    return (evt) => {
      this.configs.disableUpdate = evt.newValue;
      this.checkDisableUpdate();
    };
  },

  checkDisableUpdate() {
    if(this.configs.disableUpdate === true) {
      this.disposeAllEditorSubscriptions();
      if( this.timerId !== null) {
        clearTimeout(this.timerId);
      }
      return;
    }
    for(let editorState of this.editorStates) {
      this.setEditorDidChange(editorState);
    }
  },

  setPatterns() {
    return (patterns) => {
      this.remarkAllEditors(patterns);
      this.configs.patterns = patterns;
      this.patternsFile = new AtomFile(this.configs.patternsFilePath);
      this.fileSubscription = this.patternsFile.onDidChange(this.readPatternsFile());
    };
  },

  setFileInvalid() {
    return (err) => {
      if(err[1] === 0) {
        atom.notifications.addError('Cannot read file from patternsFilePath', {detail: err[0], dissmiss: false});
      }
      if(err[1] === 1) {
        atom.notifications.addError('patternsFile is not valid cson file', {detail: err[0], dissmiss: false});
      }
    }
  },

  //ファイルが変更されると2回呼び出されるので、ファイルの中身を調べないといけない
  readPatternsFile() {
    var oldCache = '';

    return () => {
      if(oldCache === this.patternsFile.cachedContent) {
        return;
      }
      oldCache = this.patternsFile.cachedContent;
      RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
    };
  },

  fileDispose() {
    if(this.fileSubscription) {
      this.fileSubscription.dispose();
      this.patternsFile = null;
      this.fileSubscription = null;
    }
  }
};
<commit_msg>fix bug.<commit_after>'use babel';

import HRKV from './highlight-registered-keyword-view';
import RFC, { Configs, EditorState } from './read-from-configcson';
import { getOnlySecond } from './utility';
import { CompositeDisposable, File as AtomFile } from 'atom';

export default {
  config: {
    patternsFilePath: {
      type: 'string',
      description: 'Specify the CSON file that describing patterns.',
      'default': ''
    },
    delay: {
      type: 'integer',
      description: 'delay time for update(ms)',
      'default': 1500,
      minimum: 0,
      maximum: 5000
    },
    disableUpdate: {
      type: 'boolean',
      description: 'If set this, updating of highlight will be disabled',
      'default': false
    },
    autoMark: {
      type: 'boolean',
      description: 'If set this, highlights all editors automatically',
      'default': false
    }
  },

  initalize() {
    this.name = 'highlight-registered-keyword';
    this.kInitRange = [[Infinity, 0], [0, 0]];
    this.kInvalidate = 'never'; // never or inside

    this.subscriptions = null;
    this.editorStates = [];
    this.timerId = null;  //Timer ID
    this.changedRange = this.kInitRange;  //shallow copy

    this.configs = new Configs();

    this.patternsFile = null;  //監視対象のファイル
    this.fileSubscription = null; //監視対象のファイルのsubscription
  },

  activate() {
    this.initalize();

    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'highlight-registered-keyword:markAll': () => this.markAll(),
      'highlight-registered-keyword:unmarkAll': () => this.unmarkAll(),
      'highlight-registered-keyword:mark': () => this.markActive(),
      'highlight-registered-keyword:unmark': () => this.unmarkActive(),
      'highlight-registered-keyword:show': () => this.show(),
      'highlight-registered-keyword:open': () => this.open(),
      'highlight-registered-keyword:settings': () => this.settings()
    }));

    atom.workspace.addOpener(
      (uri) => {
        if(uri === this.name + '://ValidConfigs') {
          let view = new HRKV();

          view.makeElement(this.configs);
          return view;
        }
        return null;
      }
    );

    this.getConfigs();
    RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
  },

  getConfigs() {
    this.configs.patternsFilePath = atom.config.get(this.name + '.patternsFilePath');
    this.configs.delay = atom.config.get(this.name + '.delay');
    this.configs.disableUpdate = atom.config.get(this.name + '.disableUpdate');
    this.configs.autoMark = atom.config.get(this.name + '.autoMark');

    this.subscriptions.add(atom.workspace.observeTextEditors(this.getTextEditors()));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.patternsFilePath', this.getPatternsFilePath()));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.delay', this.getChangedConfig('delay')));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.autoMark', this.getChangedConfig('autoMark')));
    this.subscriptions.add(atom.config.onDidChange(this.name + '.disableUpdate', this.getDisableUpdate()));
  },

  deactivate() {
    this.subscriptions.dispose();
    this.disposeAllEditorSubscriptions();
    this.unmarkAllEditors(null, true);
    if( this.timerId !== null) {
      clearTimeout(this.timerId);
    }
  },

  /*
  //commands
  */
  markAll() {
    this.unmarkAllEditors(null, false);
    this.markAllEditors(null);
  },
  unmarkAll() {
    this.unmarkAllEditors(null, true);
  },
  markActive() {
    let editorState = this.getActiveEditorState();

    if(editorState === null) {
      return;
    }
    this.unmarkEditor(editorState, editorState.editor.getBuffer().getRange(), null, false);
    this.markEditor(editorState, editorState.editor.getBuffer().getRange(), null);
  },
  unmarkActive() {
    let editorState = this.getActiveEditorState();

    if(editorState === null) {
      return;
    }
    this.unmarkEditor(editorState, editorState.editor.getBuffer().getRange(), null, true);
  },

  show() {
    atom.workspace.open(this.name + '://ValidConfigs');
  },

  open () {
    atom.workspace.open(this.configs.patternsFilePath);
  },
  /*
  read() {
    RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
  },
  //*/
  settings() {
    atom.workspace.open('atom://config/packages/' + this.name);
  },

  getActiveEditorState() {
    let editor = atom.workspace.getActiveTextEditor();

    if(editor === '') {
      return null;
    }
    for(let editorState of this.editorStates) {
      if(editorState.editor.id === editor.id) {
        return editorState;
      }
    }
    return null;
  },

  /*
  mark / unmark
  */
  mark(editor, pattern, range) {
    if(pattern.disable) {
      return;
    }
    editor.scanInBufferRange(pattern.pattern, range,
      (result) => {
        let marker = editor.markBufferRange(result.range, {invalidate: this.kInvalidate, class: pattern.class});

        editor.decorateMarker(marker, {type: 'highlight', class: pattern.class});
      }
    );
  },

  markEditor(editorState, range, patterns) {
    if(editorState.marked === true) {
      return;
    }
    let target = [];

    if(patterns !== null) {
      target = patterns;
    } else {
      target = this.configs.patterns;
    }

    for(let pattern of target) {
      this.mark(editorState.editor, pattern, range);
    }
    editorState.marked = true;
    this.setEditorDidChange(editorState);
  },

  markAllEditors(patterns) {
    for(let i = 0; i < this.editorStates.length; ++i) { //for...of
      this.markEditor(this.editorStates[i], this.editorStates[i].editor.getBuffer().getRange(), patterns)
    }
  },

  unmark(editor, pattern, range) {
    if(pattern.disable) {
      return;
    }
    let markers = [];

    markers = editor.findMarkers({containedInBufferRange: range, class: pattern.class})
    for(let i = 0; i < markers.length; ++i ){
      markers[i].destroy()
    }
  },

  unmarkEditor(editorState, range, patterns, doDispose) {
    if(editorState.marked === false) {
      return;
    }
    let target = [];

    if(patterns !== null) {
      target = patterns;
    } else {
      target = this.configs.patterns;
    }

    for(let pattern of target) {
      this.unmark(editorState.editor, pattern, range);
    }
    editorState.marked = false;
    if(doDispose === true) {
      this.disposeEditorSubscription(editorState);
    }
  },

  unmarkAllEditors(patterns, doDispose) {
    for(let i = 0; i < this.editorStates.length; ++i) {
      this.unmarkEditor(this.editorStates[i], this.editorStates[i].editor.getBuffer().getRange(), patterns, doDispose);
    }
  },

  //既にmarkedのEditorのみRemarkする
  remarkAllEditors(patterns) {
    for(let i = 0; i < this.editorStates.length; ++i){
      if(this.editorStates[i].marked) {
        let range = this.editorStates[i].editor.getBuffer().getRange();

        this.unmarkEditor(this.editorStates[i], range, getOnlySecond(patterns, this.configs.patterns), false);
        this.markEditor(this.editorStates[i], range, getOnlySecond(this.configs.patterns, patterns));
      }
    }
  },

  //
  getChangedRange(evt) {
    let minR = 0, maxR = 0;

    minR = Math.min(evt.oldRange.start.row, evt.oldRange.end.row,
      evt.newRange.start.row, evt.newRange.end.row, this.changedRange[0][0]);
    maxR = Math.max(evt.oldRange.start.row, evt.oldRange.end.row,
      evt.newRange.start.row, evt.newRange.end.row, this.changedRange[1][0]);

    this.changedRange = [[minR, 0], [maxR, 0]];
    return this.changedRange;
  },

  //+1は問題ないが、-1は0以下にしてはいけない
  getMarkRange(range, lastRow) {
    let markRange = [[0, 0], [0, 0]];
    markRange[0][0] = range[0][0] - 1 < 0 ? 0 : range[0][0] - 1;
    markRange[1][0] = range[1][0] + 1 > lastRow + 1 ? lastRow + 1: range[1][0] + 1;
    return markRange;
  },

  change(editorState) {
    return (range) => {
      if(this.configs.disableUpdate === true){
        return;
      }
      let markRange = this.getMarkRange(range, editorState.editor.getBuffer().getLastRow());
      this.unmarkEditor(editorState, markRange, null, false);
      this.markEditor(editorState, markRange, null);
      this.changedRange = this.kInitRange;  //shallow copy
      this.timerId = null;
    };
  },

  setTimer(editorState) {
    return (evt) => {
      if( this.timerId !== null) {
        clearTimeout(this.timerId);
        if(this.configs.disableUpdate === true){
          return;
        }
      }
      this.timerId = setTimeout(this.change(editorState), this.configs.delay, this.getChangedRange(evt));
    }
  },

  //
  setEditorDidChange(editorState) {
    if(editorState.marked === true && editorState.subscription === null) {
      editorState.subscription = editorState.editor.getBuffer().onDidChange(this.setTimer(editorState));
    }
  },

  //全てのEditorを監視対象から外す
  disposeAllEditorSubscriptions() {
    for(let editorState of this.editorStates) {
      this.disposeEditorSubscription(editorState);
    }
  },
  //1つのEditorを監視対象から外す
  disposeEditorSubscription(editorState) {
    if(editorState.subscription === null) {
      return;
    }
    editorState.subscription.dispose();
    editorState.subscription = null;
  },

  onEditorDidDestroy(editorState) {
    return () => {
      this.disposeEditorSubscription(editorState);
      this.editorStates.splice(this.editorStates.indexOf(editorState), 1);
    }
  },

  getTextEditors() {
    return (editor) => {
      if(!editor) {
        return;
      }
      let editorState = new EditorState(editor);

      editor.onDidDestroy(this.onEditorDidDestroy(editorState));
      this.editorStates.push(editorState);
      if(this.configs.autoMark) {
        this.unmarkEditor(editorState, editor.getBuffer().getRange(), null);
        this.markEditor(editorState, editor.getBuffer().getRange(), null);
      }
    };
  },

  /*
  config
  */

  getChangedConfig(property){
    return (evt) => {
      this.configs[property] = evt.newValue;
    };
  },

  getPatternsFilePath() {
    return (evt) => {
      this.configs.patternsFilePath = evt.newValue;
      RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
    }
  },

  getDisableUpdate() {
    return (evt) => {
      this.configs.disableUpdate = evt.newValue;
      this.checkDisableUpdate();
    };
  },

  checkDisableUpdate() {
    if(this.configs.disableUpdate === true) {
      this.disposeAllEditorSubscriptions();
      if( this.timerId !== null) {
        clearTimeout(this.timerId);
      }
      return;
    }
    for(let editorState of this.editorStates) {
      this.setEditorDidChange(editorState);
    }
  },

  setPatterns() {
    return (patterns) => {
      this.remarkAllEditors(patterns);
      this.configs.patterns = patterns;
      this.patternsFile = new AtomFile(this.configs.patternsFilePath);
      this.fileSubscription = this.patternsFile.onDidChange(this.readPatternsFile());
    };
  },

  setFileInvalid() {
    return (err) => {
      if(err[1] === 0) {
        atom.notifications.addError('Cannot read file from patternsFilePath', {detail: err[0], dissmiss: false});
      }
      if(err[1] === 1) {
        atom.notifications.addError('patternsFile is not valid cson file', {detail: err[0], dissmiss: false});
      }
    }
  },

  //ファイルが変更されると2回呼び出されるので、ファイルの中身を調べないといけない
  readPatternsFile() {
    var oldCache = '';

    return () => {
      if(oldCache === this.patternsFile.cachedContent) {
        return;
      }
      oldCache = this.patternsFile.cachedContent;
      RFC.readFromConfigFile(this.configs.patternsFilePath, this.name, this.setPatterns(), this.setFileInvalid());
    };
  },

  fileDispose() {
    if(this.fileSubscription) {
      this.fileSubscription.dispose();
      this.patternsFile = null;
      this.fileSubscription = null;
    }
  }
};
<|endoftext|>


<commit_before>/**
 * force-directed-layout.js
 *
 * This module contains logic for performing the force-directed layout
 * algorithm on a graph.
 *
 * @author John O'Brien.
 */

var Graph = require('./../model/graph');
var Vertex = require('./../model/vertex');
var Port = require('./../model/port');
var Edge = require('./../model/edge');
var CardinalPortPosition = require('./../model/cardinalPortPosition');
var change = false;
//ideal length
var iLength = 100;
//force strength
var forceStr = 1.0/3.0;
//stretching force
var stretchForce  = 0.70;
var vertices;
var mGraph;

//Based partially on https://code.google.com/p/jung/source/browse/branches/guava/jung/jung-algorithms/src/main/java/edu/uci/ics/jung/algorithms/layout/SpringLayout.java?r=19

function layOutGraph(graph) {
	mGraph = graph;
	vertices = graph.get('vertices');
	var edgeList = graph.get('edges');
	var runner = true;
	//var loopCount =0;
	while(runner){
		//console.log('loop count is: '+loopCount+'\n');
		change = false;

		for(var i=0;i<edgeList.length;i++){
			springForce(edgeList[i]);
		}
		if(change === false){
			runner = false;
		}
		//loopCount++;
	}
	//defaulting all ports that do not have a position
	for(var j=0;j < vertices.length; j++){
		var inputs = vertices[j].get('inputs');
		var outputs = vertices[j].get('outputs');

		for(var h =0; h < inputs.length; h++){

			if(inputs[h].get('position') === null){
				inputs[h].set('position', new cardinalPortPosition('E', 50));
			}

		}
		for(h =0;h < outputs.length; h++){
			if(outputs[h].get('position') === null){
				outputs[h].set('position', new cardinalPortPosition('W', 50));
			}
		}
	}
	for(var b=0;b<vertices.length; b++){
		console.log(vertices[b].get('position').x+','+vertices[b].get('position').y);
	}
}

function springForce(edge){
	//vertex to
	var vt = mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	//vertex from
	var vf = mGraph.getVertexById(edge.get('from').get('ownerVertexId'));
	//x distance between them
	var xL = edgeXLength(edge);
	//y distance between them
	var yL = edgeYLength(edge);
	//straight line edge length
	var length = edgeLength(edge);
	//checks for both pined
	if(vt.get('isPinned') ===true && vf.get('isPinned')===true){
		return;
	}

	//hacky solution for length being 0
	if(length === 0){
		length = 0.0001;
	}
	//repulsion force calculation
	var force = forceStr * (iLength - length) / length;
	force = force * Math.pow(stretchForce, (vt.get('inputs').length + vt.get('outputs').length + vf.get('inputs').length + vf.get('outputs').length - 4));

	//repulsion change in x
	var cx = force * xL;
	//repulsion change in y
	var cy = force * yL;
	//attraction x
	var dx;
	//attraction y
	var dy;
	//math for min length
	if(length < 1){
		dx = Math.random()*10+1;
		dy = Math.random()*10+1;
	} else {
		dx = xL/(length*length);
		dy = yL/(length*length);
	}

	var len = dx * dx + dy * dy;
	//ensures length is positive
	if(len>0){
		len = Math.sqrt(len);
		dx = dx / len;
		dy = dy / len;
	}
	//repulsion minus attraction
	cx = cx - dx;
	cy = cy - dy;
	if(vt.get('isPinned') ===false && vf.get('isPinned')===false){
		vt.set('position', {'x': (vt.get('position').x+cx),'y': (vt.get('position').y+cy)});
		vf.set('position', {'x':vf.get('position').x-cx, 'y':vf.get('position').y-cy});

		if(cx > 1 || cy > 1){
			change = true;
		}
	}else if(vt.get('isPinned') ===true){
		vf.set('position', {'x':vf.get('position').x-cx-cx, 'y':vf.get('position').y-cy-cy});

		if(cx > 1 || cy > 1){
			change = true;
		}

	}else if(vf.get('isPinned')===true){
		vt.set('position', {'x': (vt.get('position').x+cx),'y': (vt.get('position').y+cy)});

		if(cx > 1 || cy > 1){
			change = true;
		}
	}
}
/* not yet implemented
function portPositioning(edge){
	var vt = mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	var vf = mGraph.getVertexById(edge.get('from').get('ownerVertexId'));
	var xL = edgeXLength(edge);
	var yL = edgeYLength(edge);

}*/

//calculates edge length
function edgeLength(edge){
	to=mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	from=mGraph.getVertexById(edge.get('from').get('ownerVertexId'));

	if('null' !=to.get('position').x&&'null' !=to.get('position').y&&'null' !=from.get('position').x&& 'null' != from.get('position').y){
		//pythag theorem
		var x = to.get('position').x - from.get('position').x;
		var y = to.get('position').y - from.get('position').y;

		var c = x*x+y*y;
		return Math.sqrt(c);
	}else{
	//@todo add error checking
	//on fail return 0 length
		return 0;

	}

}

function edgeXLength(edge){
	to=mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	from=mGraph.getVertexById(edge.get('from').get('ownerVertexId'));

	if('null' !=to.get('position').x&&'null' !=from.get('position').x){
		var x = to.get('position').x - from.get('position').x;
		return x;
	}else{
	//@todo add error checking
	//on fail return 0 length
		return 0;

	}

}

function edgeYLength(edge){
	to=mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	from=mGraph.getVertexById(edge.get('from').get('ownerVertexId'));

	if('null' !=to.get('position').y&&'null' !=from.get('position').y){
		var y = to.get('position').y - from.get('position').y;
		return y;
	}else{
	//@todo add error checking
	//on fail return 0 length
		return 0;

	}

}
module.exports = layOutGraph;<commit_msg>value tweak<commit_after>/**
 * force-directed-layout.js
 *
 * This module contains logic for performing the force-directed layout
 * algorithm on a graph.
 *
 * @author John O'Brien.
 */

var Graph = require('./../model/graph');
var Vertex = require('./../model/vertex');
var Port = require('./../model/port');
var Edge = require('./../model/edge');
var CardinalPortPosition = require('./../model/cardinalPortPosition');
var change = false;
//ideal length
var iLength = 250;
//force strength
var forceStr = 1.0/3.0;
//stretching force
var stretchForce  = 0.70;
var vertices;
var mGraph;

//Based partially on https://code.google.com/p/jung/source/browse/branches/guava/jung/jung-algorithms/src/main/java/edu/uci/ics/jung/algorithms/layout/SpringLayout.java?r=19

function layOutGraph(graph) {
	mGraph = graph;
	vertices = graph.get('vertices');
	var edgeList = graph.get('edges');
	var runner = true;
	//var loopCount =0;
	while(runner){
		//console.log('loop count is: '+loopCount+'\n');
		change = false;

		for(var i=0;i<edgeList.length;i++){
			springForce(edgeList[i]);
		}
		if(change === false){
			runner = false;
		}
		//loopCount++;
	}
	//defaulting all ports that do not have a position
	for(var j=0;j < vertices.length; j++){
		var inputs = vertices[j].get('inputs');
		var outputs = vertices[j].get('outputs');

		for(var h =0; h < inputs.length; h++){

			if(inputs[h].get('position') === null){
				inputs[h].set('position', new cardinalPortPosition('E', 50));
			}

		}
		for(h =0;h < outputs.length; h++){
			if(outputs[h].get('position') === null){
				outputs[h].set('position', new cardinalPortPosition('W', 50));
			}
		}
	}
	for(var b=0;b<vertices.length; b++){
		console.log(vertices[b].get('position').x+','+vertices[b].get('position').y);
	}
}

function springForce(edge){
	//vertex to
	var vt = mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	//vertex from
	var vf = mGraph.getVertexById(edge.get('from').get('ownerVertexId'));
	//x distance between them
	var xL = edgeXLength(edge);
	//y distance between them
	var yL = edgeYLength(edge);
	//straight line edge length
	var length = edgeLength(edge);
	//checks for both pined
	if(vt.get('isPinned') ===true && vf.get('isPinned')===true){
		return;
	}

	//hacky solution for length being 0
	if(length === 0){
		length = 0.0001;
	}
	//repulsion force calculation
	var force = forceStr * (iLength - length) / length;
	force = force * Math.pow(stretchForce, (vt.get('inputs').length + vt.get('outputs').length + vf.get('inputs').length + vf.get('outputs').length - 4));

	//repulsion change in x
	var cx = force * xL;
	//repulsion change in y
	var cy = force * yL;
	//attraction x
	var dx;
	//attraction y
	var dy;
	//math for min length
	if(length < 1){
		dx = Math.random()*10+1;
		dy = Math.random()*10+1;
	} else {
		dx = xL/(length*length);
		dy = yL/(length*length);
	}

	var len = dx * dx + dy * dy;
	//ensures length is positive
	if(len>0){
		len = Math.sqrt(len);
		dx = dx / len;
		dy = dy / len;
	}
	//repulsion minus attraction
	cx = cx - dx;
	cy = cy - dy;
	if(vt.get('isPinned') ===false && vf.get('isPinned')===false){
		vt.set('position', {'x': (vt.get('position').x+cx),'y': (vt.get('position').y+cy)});
		vf.set('position', {'x':vf.get('position').x-cx, 'y':vf.get('position').y-cy});

		if(cx > 1 || cy > 1){
			change = true;
		}
	}else if(vt.get('isPinned') ===true){
		vf.set('position', {'x':vf.get('position').x-cx-cx, 'y':vf.get('position').y-cy-cy});

		if(cx > 1 || cy > 1){
			change = true;
		}

	}else if(vf.get('isPinned')===true){
		vt.set('position', {'x': (vt.get('position').x+cx),'y': (vt.get('position').y+cy)});

		if(cx > 1 || cy > 1){
			change = true;
		}
	}
}
/* not yet implemented
function portPositioning(edge){
	var vt = mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	var vf = mGraph.getVertexById(edge.get('from').get('ownerVertexId'));
	var xL = edgeXLength(edge);
	var yL = edgeYLength(edge);

}*/

//calculates edge length
function edgeLength(edge){
	to=mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	from=mGraph.getVertexById(edge.get('from').get('ownerVertexId'));

	if('null' !=to.get('position').x&&'null' !=to.get('position').y&&'null' !=from.get('position').x&& 'null' != from.get('position').y){
		//pythag theorem
		var x = to.get('position').x - from.get('position').x;
		var y = to.get('position').y - from.get('position').y;

		var c = x*x+y*y;
		return Math.sqrt(c);
	}else{
	//@todo add error checking
	//on fail return 0 length
		return 0;

	}

}

function edgeXLength(edge){
	to=mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	from=mGraph.getVertexById(edge.get('from').get('ownerVertexId'));

	if('null' !=to.get('position').x&&'null' !=from.get('position').x){
		var x = to.get('position').x - from.get('position').x;
		return x;
	}else{
	//@todo add error checking
	//on fail return 0 length
		return 0;

	}

}

function edgeYLength(edge){
	to=mGraph.getVertexById(edge.get('to').get('ownerVertexId'));
	from=mGraph.getVertexById(edge.get('from').get('ownerVertexId'));

	if('null' !=to.get('position').y&&'null' !=from.get('position').y){
		var y = to.get('position').y - from.get('position').y;
		return y;
	}else{
	//@todo add error checking
	//on fail return 0 length
		return 0;

	}

}
module.exports = layOutGraph;<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var constants = require('constants');
var net = require('net');
var tls = require('tls');
var thrift = require('./thrift');
var log = require('./log');

var TBufferedTransport = require('./buffered_transport');
var TBinaryProtocol = require('./binary_protocol');
var InputBufferUnderrunError = require('./input_buffer_underrun_error');

var createClient = require('./create_client');

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

var Connection = exports.Connection = function(stream, options) {
  var self = this;
  EventEmitter.call(this);

  this.seqId2Service = {};
  this.connection = stream;
  this.ssl = (stream.encrypted);
  this.options = options || {};
  this.transport = this.options.transport || TBufferedTransport;
  this.protocol = this.options.protocol || TBinaryProtocol;
  this.offline_queue = [];
  this.connected = false;
  this.initialize_retry_vars();

  this._debug = this.options.debug || false;
  if (this.options.max_attempts &&
      !isNaN(this.options.max_attempts) &&
      this.options.max_attempts > 0) {
     this.max_attempts = +this.options.max_attempts;
  }
  this.retry_max_delay = null;
  if (this.options.retry_max_delay !== undefined &&
      !isNaN(this.options.retry_max_delay) &&
      this.options.retry_max_delay > 0) {
     this.retry_max_delay = this.options.retry_max_delay;
  }
  this.connect_timeout = false;
  if (this.options.connect_timeout &&
      !isNaN(this.options.connect_timeout) &&
      this.options.connect_timeout > 0) {
     this.connect_timeout = +this.options.connect_timeout;
  }

  this.connection.addListener(this.ssl ? "secureConnect" : "connect", function() {
    self.connected = true;

    this.setTimeout(self.options.timeout || 0);
    this.setNoDelay();
    this.frameLeft = 0;
    this.framePos = 0;
    this.frame = null;
    self.initialize_retry_vars();
    self.flush_offline_queue();

    self.emit("connect");
  });

  this.connection.addListener("error", function(err) {
    // Only emit the error if no-one else is listening on the connection
    // or if someone is listening on us, because Node turns unhandled
    // 'error' events into exceptions.
    if (self.connection.listeners('error').length === 1 ||
        self.listeners('error').length > 0) {
      self.emit("error", err);
    }
  });

  // Add a close listener
  this.connection.addListener("close", function() {
    self.connection_gone(); // handle close event. try to reconnect
  });

  this.connection.addListener("timeout", function() {
    self.emit("timeout");
  });

  this.connection.addListener("data", self.transport.receiver(function(transport_with_data) {
    var message = new self.protocol(transport_with_data);
    try {
      while (true) {
        var header = message.readMessageBegin();
        var dummy_seqid = header.rseqid * -1;
        var client = self.client;
        //The Multiplexed Protocol stores a hash of seqid to service names
        //  in seqId2Service. If the SeqId is found in the hash we need to
        //  lookup the appropriate client for this call.
        //  The connection.client object is a single client object when not
        //  multiplexing, when using multiplexing it is a service name keyed
        //  hash of client objects.
        //NOTE: The 2 way interdependencies between protocols, transports,
        //  connections and clients in the Node.js implementation are irregular
        //  and make the implementation difficult to extend and maintain. We
        //  should bring this stuff inline with typical thrift I/O stack
        //  operation soon.
        //  --ra
        var service_name = self.seqId2Service[header.rseqid];
        if (service_name) {
          client = self.client[service_name];
        }
        /*jshint -W083 */
        client._reqs[dummy_seqid] = function(err, success){
          transport_with_data.commitPosition();

          var callback = client._reqs[header.rseqid];
          delete client._reqs[header.rseqid];
          if (service_name) {
            delete self.seqId2Service[header.rseqid];
          }
          if (callback) {
            callback(err, success);
          }
        };
        /*jshint +W083 */

        if(client['recv_' + header.fname]) {
          client['recv_' + header.fname](message, header.mtype, dummy_seqid);
        } else {
          delete client._reqs[dummy_seqid];
          self.emit("error",
                    new thrift.TApplicationException(thrift.TApplicationExceptionType.WRONG_METHOD_NAME,
                             "Received a response to an unknown RPC function"));
        }
      }
    }
    catch (e) {
      if (e instanceof InputBufferUnderrunError) {
        transport_with_data.rollbackPosition();
      }
      else {
        self.emit('error', e);
      }
    }
  }));
};
util.inherits(Connection, EventEmitter);

Connection.prototype.end = function() {
  this.connection.end();
};

Connection.prototype.destroy = function() {
  this.connection.destroy();
};

Connection.prototype.initialize_retry_vars = function () {
  this.retry_timer = null;
  this.retry_totaltime = 0;
  this.retry_delay = 150;
  this.retry_backoff = 1.7;
  this.attempts = 0;
};

Connection.prototype.flush_offline_queue = function () {
  var self = this;
  var offline_queue = this.offline_queue;

  // Reset offline queue
  this.offline_queue = [];
  // Attempt to write queued items
  offline_queue.forEach(function(data) {
    self.write(data);
  });
};

Connection.prototype.write = function(data) {
  if (!this.connected) {
    this.offline_queue.push(data);
    return;
  }
  this.connection.write(data);
};

Connection.prototype.connection_gone = function () {
  var self = this;
  this.connected = false;

  // If a retry is already in progress, just let that happen
  if (this.retry_timer) {
    return;
  }
  // We cannot reconnect a secure socket.
  if (!this.max_attempts || this.ssl) {
    self.emit("close");
    return;
  }

  if (this.retry_max_delay !== null && this.retry_delay >= this.retry_max_delay) {
    this.retry_delay = this.retry_max_delay;
  } else {
    this.retry_delay = Math.floor(this.retry_delay * this.retry_backoff);
  }

  log.debug("Retry connection in " + this.retry_delay + " ms");

  if (this.max_attempts && this.attempts >= this.max_attempts) {
    this.retry_timer = null;
    console.error("thrift: Couldn't get thrift connection after " + this.max_attempts + " attempts.");
    self.emit("close");
    return;
  }

  this.attempts += 1;
  this.emit("reconnecting", {
    delay: self.retry_delay,
    attempt: self.attempts
  });

  this.retry_timer = setTimeout(function () {
    if (self.connection.destroyed) {
      self.retry_timer = null;
      return;
    }

    log.debug("Retrying connection...");

    self.retry_totaltime += self.retry_delay;

    if (self.connect_timeout && self.retry_totaltime >= self.connect_timeout) {
       self.retry_timer = null;
       console.error("thrift: Couldn't get thrift connection after " + self.retry_totaltime + "ms.");
       self.emit("close");
       return;
    }

    if (self.path !== undefined) {
      self.connection.connect(self.path);
    } else {
      self.connection.connect(self.port, self.host);
    }
    self.retry_timer = null;
  }, this.retry_delay);
};

exports.createConnection = function(host, port, options) {
  var stream = net.createConnection(port, host);
  var connection = new Connection(stream, options);
  connection.host = host;
  connection.port = port;

  return connection;
};

exports.createUDSConnection = function(path, options) {
  var stream = net.createConnection(path);
  var connection = new Connection(stream, options);
  connection.path = path;

  return connection;
};

exports.createSSLConnection = function(host, port, options) {
  if (!('secureProtocol' in options) && !('secureOptions' in options)) {
    options.secureProtocol = "SSLv23_method";
    options.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3;
  }

  var stream = tls.connect(port, host, options);
  var connection = new Connection(stream, options);
  connection.host = host;
  connection.port = port;

  return connection;
};

exports.createClient = createClient;

var child_process = require('child_process');
var StdIOConnection = exports.StdIOConnection = function(command, options) {
  var command_parts = command.split(' ');
  command = command_parts[0];
  var args = command_parts.splice(1,command_parts.length -1);
  var child = this.child = child_process.spawn(command,args);

  var self = this;
  EventEmitter.call(this);

  this.connection = child.stdin;
  this.options = options || {};
  this.transport = this.options.transport || TBufferedTransport;
  this.protocol = this.options.protocol || TBinaryProtocol;
  this.offline_queue = [];

  if (log.getLogLevel() === 'debug') {
    this.child.stderr.on('data', function (err) {
      log.debug(err.toString(), 'CHILD ERROR');
    });

    this.child.on('exit', function (code,signal) {
      log.debug(code + ':' + signal, 'CHILD EXITED');
    });
  }

  this.frameLeft = 0;
  this.framePos = 0;
  this.frame = null;
  this.connected = true;

  self.flush_offline_queue();

  this.connection.addListener("error", function(err) {
    self.emit("error", err);
  });

  // Add a close listener
  this.connection.addListener("close", function() {
    self.emit("close");
  });

  child.stdout.addListener("data", self.transport.receiver(function(transport_with_data) {
    var message = new self.protocol(transport_with_data);
    try {
      var header = message.readMessageBegin();
      var dummy_seqid = header.rseqid * -1;
      var client = self.client;
      client._reqs[dummy_seqid] = function(err, success){
        transport_with_data.commitPosition();

        var callback = client._reqs[header.rseqid];
        delete client._reqs[header.rseqid];
        if (callback) {
          callback(err, success);
        }
      };
      client['recv_' + header.fname](message, header.mtype, dummy_seqid);
    }
    catch (e) {
      if (e instanceof InputBufferUnderrunError) {
        transport_with_data.rollbackPosition();
      }
      else {
        throw e;
      }
    }
  }));
};

util.inherits(StdIOConnection, EventEmitter);

StdIOConnection.prototype.end = function() {
  this.connection.end();
};

StdIOConnection.prototype.flush_offline_queue = function () {
  var self = this;
  var offline_queue = this.offline_queue;

  // Reset offline queue
  this.offline_queue = [];
  // Attempt to write queued items
  offline_queue.forEach(function(data) {
    self.write(data);
  });
};

StdIOConnection.prototype.write = function(data) {
  if (!this.connected) {
    this.offline_queue.push(data);
    return;
  }
  this.connection.write(data);
};

exports.createStdIOConnection = function(command,options){
  return new StdIOConnection(command,options);
};

exports.createStdIOClient = createClient;
<commit_msg>THRIFT-4844: createConnection ignores connect_timeout option<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.
 */
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var constants = require('constants');
var net = require('net');
var tls = require('tls');
var thrift = require('./thrift');
var log = require('./log');

var TBufferedTransport = require('./buffered_transport');
var TBinaryProtocol = require('./binary_protocol');
var InputBufferUnderrunError = require('./input_buffer_underrun_error');

var createClient = require('./create_client');

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

var Connection = exports.Connection = function(stream, options) {
  var self = this;
  EventEmitter.call(this);

  this.seqId2Service = {};
  this.connection = stream;
  this.ssl = (stream.encrypted);
  this.options = options || {};
  this.transport = this.options.transport || TBufferedTransport;
  this.protocol = this.options.protocol || TBinaryProtocol;
  this.offline_queue = [];
  this.connected = false;
  this.initialize_retry_vars();

  this._debug = this.options.debug || false;
  if (this.options.max_attempts &&
      !isNaN(this.options.max_attempts) &&
      this.options.max_attempts > 0) {
     this.max_attempts = +this.options.max_attempts;
  }
  this.retry_max_delay = null;
  if (this.options.retry_max_delay !== undefined &&
      !isNaN(this.options.retry_max_delay) &&
      this.options.retry_max_delay > 0) {
     this.retry_max_delay = this.options.retry_max_delay;
  }
  this.connect_timeout = false;
  if (this.options.connect_timeout &&
      !isNaN(this.options.connect_timeout) &&
      this.options.connect_timeout > 0) {
     this.connect_timeout = +this.options.connect_timeout;
  }

  this.connection.addListener(this.ssl ? "secureConnect" : "connect", function() {
    self.connected = true;

    this.setTimeout(self.options.timeout || 0);
    this.setNoDelay();
    this.frameLeft = 0;
    this.framePos = 0;
    this.frame = null;
    self.initialize_retry_vars();
    self.flush_offline_queue();

    self.emit("connect");
  });

  this.connection.addListener("error", function(err) {
    // Only emit the error if no-one else is listening on the connection
    // or if someone is listening on us, because Node turns unhandled
    // 'error' events into exceptions.
    if (self.connection.listeners('error').length === 1 ||
        self.listeners('error').length > 0) {
      self.emit("error", err);
    }
  });

  // Add a close listener
  this.connection.addListener("close", function() {
    self.connection_gone(); // handle close event. try to reconnect
  });

  this.connection.addListener("timeout", function() {
    self.emit("timeout");
  });

  this.connection.addListener("data", self.transport.receiver(function(transport_with_data) {
    var message = new self.protocol(transport_with_data);
    try {
      while (true) {
        var header = message.readMessageBegin();
        var dummy_seqid = header.rseqid * -1;
        var client = self.client;
        //The Multiplexed Protocol stores a hash of seqid to service names
        //  in seqId2Service. If the SeqId is found in the hash we need to
        //  lookup the appropriate client for this call.
        //  The connection.client object is a single client object when not
        //  multiplexing, when using multiplexing it is a service name keyed
        //  hash of client objects.
        //NOTE: The 2 way interdependencies between protocols, transports,
        //  connections and clients in the Node.js implementation are irregular
        //  and make the implementation difficult to extend and maintain. We
        //  should bring this stuff inline with typical thrift I/O stack
        //  operation soon.
        //  --ra
        var service_name = self.seqId2Service[header.rseqid];
        if (service_name) {
          client = self.client[service_name];
        }
        /*jshint -W083 */
        client._reqs[dummy_seqid] = function(err, success){
          transport_with_data.commitPosition();

          var callback = client._reqs[header.rseqid];
          delete client._reqs[header.rseqid];
          if (service_name) {
            delete self.seqId2Service[header.rseqid];
          }
          if (callback) {
            callback(err, success);
          }
        };
        /*jshint +W083 */

        if(client['recv_' + header.fname]) {
          client['recv_' + header.fname](message, header.mtype, dummy_seqid);
        } else {
          delete client._reqs[dummy_seqid];
          self.emit("error",
                    new thrift.TApplicationException(thrift.TApplicationExceptionType.WRONG_METHOD_NAME,
                             "Received a response to an unknown RPC function"));
        }
      }
    }
    catch (e) {
      if (e instanceof InputBufferUnderrunError) {
        transport_with_data.rollbackPosition();
      }
      else {
        self.emit('error', e);
      }
    }
  }));
};
util.inherits(Connection, EventEmitter);

Connection.prototype.end = function() {
  this.connection.end();
};

Connection.prototype.destroy = function() {
  this.connection.destroy();
};

Connection.prototype.initialize_retry_vars = function () {
  this.retry_timer = null;
  this.retry_totaltime = 0;
  this.retry_delay = 150;
  this.retry_backoff = 1.7;
  this.attempts = 0;
};

Connection.prototype.flush_offline_queue = function () {
  var self = this;
  var offline_queue = this.offline_queue;

  // Reset offline queue
  this.offline_queue = [];
  // Attempt to write queued items
  offline_queue.forEach(function(data) {
    self.write(data);
  });
};

Connection.prototype.write = function(data) {
  if (!this.connected) {
    this.offline_queue.push(data);
    return;
  }
  this.connection.write(data);
};

Connection.prototype.connection_gone = function () {
  var self = this;
  this.connected = false;

  // If a retry is already in progress, just let that happen
  if (this.retry_timer) {
    return;
  }
  // We cannot reconnect a secure socket.
  if (!this.max_attempts || this.ssl) {
    self.emit("close");
    return;
  }

  if (this.retry_max_delay !== null && this.retry_delay >= this.retry_max_delay) {
    this.retry_delay = this.retry_max_delay;
  } else {
    this.retry_delay = Math.floor(this.retry_delay * this.retry_backoff);
  }

  log.debug("Retry connection in " + this.retry_delay + " ms");

  if (this.max_attempts && this.attempts >= this.max_attempts) {
    this.retry_timer = null;
    console.error("thrift: Couldn't get thrift connection after " + this.max_attempts + " attempts.");
    self.emit("close");
    return;
  }

  this.attempts += 1;
  this.emit("reconnecting", {
    delay: self.retry_delay,
    attempt: self.attempts
  });

  this.retry_timer = setTimeout(function () {
    if (self.connection.destroyed) {
      self.retry_timer = null;
      return;
    }

    log.debug("Retrying connection...");

    self.retry_totaltime += self.retry_delay;

    if (self.connect_timeout && self.retry_totaltime >= self.connect_timeout) {
       self.retry_timer = null;
       console.error("thrift: Couldn't get thrift connection after " + self.retry_totaltime + "ms.");
       self.emit("close");
       return;
    }

    if (self.path !== undefined) {
      self.connection.connect(self.path);
    } else {
      self.connection.connect(self.port, self.host);
    }
    self.retry_timer = null;
  }, this.retry_delay);
};

exports.createConnection = function(host, port, options) {
  var stream = net.createConnection( {
    port: port,
    host: host,
    timeout: options.connect_timeout || options.timeout || 0
  });
  var connection = new Connection(stream, options);
  connection.host = host;
  connection.port = port;

  return connection;
};

exports.createUDSConnection = function(path, options) {
  var stream = net.createConnection(path);
  var connection = new Connection(stream, options);
  connection.path = path;

  return connection;
};

exports.createSSLConnection = function(host, port, options) {
  if (!('secureProtocol' in options) && !('secureOptions' in options)) {
    options.secureProtocol = "SSLv23_method";
    options.secureOptions = constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3;
  }

  var stream = tls.connect(port, host, options);
  var connection = new Connection(stream, options);
  connection.host = host;
  connection.port = port;

  return connection;
};

exports.createClient = createClient;

var child_process = require('child_process');
var StdIOConnection = exports.StdIOConnection = function(command, options) {
  var command_parts = command.split(' ');
  command = command_parts[0];
  var args = command_parts.splice(1,command_parts.length -1);
  var child = this.child = child_process.spawn(command,args);

  var self = this;
  EventEmitter.call(this);

  this.connection = child.stdin;
  this.options = options || {};
  this.transport = this.options.transport || TBufferedTransport;
  this.protocol = this.options.protocol || TBinaryProtocol;
  this.offline_queue = [];

  if (log.getLogLevel() === 'debug') {
    this.child.stderr.on('data', function (err) {
      log.debug(err.toString(), 'CHILD ERROR');
    });

    this.child.on('exit', function (code,signal) {
      log.debug(code + ':' + signal, 'CHILD EXITED');
    });
  }

  this.frameLeft = 0;
  this.framePos = 0;
  this.frame = null;
  this.connected = true;

  self.flush_offline_queue();

  this.connection.addListener("error", function(err) {
    self.emit("error", err);
  });

  // Add a close listener
  this.connection.addListener("close", function() {
    self.emit("close");
  });

  child.stdout.addListener("data", self.transport.receiver(function(transport_with_data) {
    var message = new self.protocol(transport_with_data);
    try {
      var header = message.readMessageBegin();
      var dummy_seqid = header.rseqid * -1;
      var client = self.client;
      client._reqs[dummy_seqid] = function(err, success){
        transport_with_data.commitPosition();

        var callback = client._reqs[header.rseqid];
        delete client._reqs[header.rseqid];
        if (callback) {
          callback(err, success);
        }
      };
      client['recv_' + header.fname](message, header.mtype, dummy_seqid);
    }
    catch (e) {
      if (e instanceof InputBufferUnderrunError) {
        transport_with_data.rollbackPosition();
      }
      else {
        throw e;
      }
    }
  }));
};

util.inherits(StdIOConnection, EventEmitter);

StdIOConnection.prototype.end = function() {
  this.connection.end();
};

StdIOConnection.prototype.flush_offline_queue = function () {
  var self = this;
  var offline_queue = this.offline_queue;

  // Reset offline queue
  this.offline_queue = [];
  // Attempt to write queued items
  offline_queue.forEach(function(data) {
    self.write(data);
  });
};

StdIOConnection.prototype.write = function(data) {
  if (!this.connected) {
    this.offline_queue.push(data);
    return;
  }
  this.connection.write(data);
};

exports.createStdIOConnection = function(command,options){
  return new StdIOConnection(command,options);
};

exports.createStdIOClient = createClient;
<|endoftext|>


<commit_before>/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS207: Consider shorter variations of null checks
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */
const Metrics = require('metrics-sharelatex')
Metrics.initialize('contacts')

const Settings = require('settings-sharelatex')
const logger = require('logger-sharelatex')
const express = require('express')
const bodyParser = require('body-parser')
const Errors = require('./app/js/Errors')
const HttpController = require('./app/js/HttpController')

const Path = require('path')

logger.initialize('contacts')
if (Metrics.event_loop != null) {
  Metrics.event_loop.monitor(logger)
}

const app = express()

app.use(Metrics.http.monitor(logger))

Metrics.injectMetricsRoute(app)

app.get('/user/:user_id/contacts', HttpController.getContacts)
app.post(
  '/user/:user_id/contacts',
  bodyParser.json({ limit: '2mb' }),
  HttpController.addContact
)

app.get('/status', (req, res) => res.send('contacts is alive'))

app.use(function(error, req, res, next) {
  logger.error({ err: error }, 'request errored')
  if (error instanceof Errors.NotFoundError) {
    return res.send(404)
  } else {
    return res.send(500, 'Oops, something went wrong')
  }
})

const { port } = Settings.internal.contacts
const { host } = Settings.internal.contacts

if (!module.parent) {
  // Called directly
  app.listen(port, host, function(error) {
    if (error != null) {
      throw error
    }
    return logger.info(`contacts starting up, listening on ${host}:${port}`)
  })
}

module.exports = app
<commit_msg>Remove unused variable<commit_after>/*
 * decaffeinate suggestions:
 * DS102: Remove unnecessary code created because of implicit returns
 * DS207: Consider shorter variations of null checks
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 */
const Metrics = require('metrics-sharelatex')
Metrics.initialize('contacts')

const Settings = require('settings-sharelatex')
const logger = require('logger-sharelatex')
const express = require('express')
const bodyParser = require('body-parser')
const Errors = require('./app/js/Errors')
const HttpController = require('./app/js/HttpController')

logger.initialize('contacts')
if (Metrics.event_loop != null) {
  Metrics.event_loop.monitor(logger)
}

const app = express()

app.use(Metrics.http.monitor(logger))

Metrics.injectMetricsRoute(app)

app.get('/user/:user_id/contacts', HttpController.getContacts)
app.post(
  '/user/:user_id/contacts',
  bodyParser.json({ limit: '2mb' }),
  HttpController.addContact
)

app.get('/status', (req, res) => res.send('contacts is alive'))

app.use(function(error, req, res, next) {
  logger.error({ err: error }, 'request errored')
  if (error instanceof Errors.NotFoundError) {
    return res.send(404)
  } else {
    return res.send(500, 'Oops, something went wrong')
  }
})

const { port } = Settings.internal.contacts
const { host } = Settings.internal.contacts

if (!module.parent) {
  // Called directly
  app.listen(port, host, function(error) {
    if (error != null) {
      throw error
    }
    return logger.info(`contacts starting up, listening on ${host}:${port}`)
  })
}

module.exports = app
<|endoftext|>


<commit_before>var contentType = require('node-lib').content_type.ext;
var VirusScan = require('../../utils/VirusScan');
var FSService = require('../local/FSService');

var async = require('async');
var AWS = require('aws-sdk');
var uuid = require('node-uuid');
var fs = require('fs');
var tmp = require('tmp');

var writeQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

var readQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

var removeQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

var deleteQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

function S3Service(config) {
	this.getConfig = function () {
		return config;
	};
	AWS.config.update({
		region: config.region,
		accessKeyId: config.accessKeyId,
		secretAccessKey: config.secretAccessKey
	});
	var s3 = new AWS.S3();
	this.getS3 = function () {
		return s3;
	};
}

S3Service.prototype.addToWriteQueue = function (params, callback) {
	writeQueue.push(function (callback) {
		this.getS3().client.putObject(params, callback);
	}, callback);
};

S3Service.prototype.addToReadQueue = function (params, callback) {
	readQueue.push(function (callback) {
		this.getS3().client.getObject(params, callback);
	}, callback);
};

S3Service.prototype.addToRemoveQueue = function (params, callback) {
	removeQueue.push(function (callback) {
		this.getS3().client.deleteObject(params, callback);
	}, callback);
};

S3Service.prototype.addToDeleteQueue = function (params, callback) {
	deleteQueue.push(function (callback) {
		this.getS3().client.deleteObjects(params, callback);
	}, callback);
};

S3Service.prototype.bucketInitialization = function () {
	var self = this;
	var bucketNames = [];
	if (this.getConfig().s3BucketName) bucketNames.push(this.getConfig().s3BucketName);
	if (this.getConfig().s3SecuredBucketName) bucketNames.push(this.getConfig().s3SecuredBucketName);

	this.getS3().client.listBuckets(function (err, data) {
		if (err) {
			console.log(err);
		} else {
			bucketNames.forEach(function (bucketName) {
				if (data.Buckets.filter(function (bucket) {
					return bucket.Name == bucketName;
				}).length === 0) {
					self.getS3().client.createBucket({
						Bucket: bucketName
					}, function (err, data) {
						if (err) {
							console.log(err);
						} else console.log("Successfully created S3 " + bucketName + " bucket");
					});
				} else {
					console.log("S3 bucket " + bucketName + " connected...");
				}
			});
		}
	});
};

S3Service.prototype.writeFileToS3 = function (base64data, originalFilename, extension, secure, callback) {
	var name = uuid.v4();
	var filename = extension ? name + "." + extension : name;

	console.log("write file to S3: ", originalFilename);

	this.addToWriteQueue({
		Bucket: secure ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName,
		Key: filename,
		Body: new Buffer(base64data, 'base64'),
		ContentType: contentType.getContentType(extension),
		ContentDisposition: 'attachment; filename="' + originalFilename || filename + '"'
	}, function (err) {
		callback(err, filename);
	});
};

S3Service.prototype.readFileFromS3 = function (filename, secureOrBucket, callback) {
	var bucket;
	if (typeof secureOrBucket == "string") {
		bucket = secureOrBucket;
	} else {
		bucket = secureOrBucket ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName;
	}

	this.addToReadQueue({
		Bucket: bucket,
		Key: filename
	}, callback);
};

S3Service.prototype.removeFileFromS3 = function (filename, secure, callback) {
	this.addToRemoveQueue({
		Bucket: secure ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName,
		Key: filename
	}, callback);
};

S3Service.prototype.removeFilesFromS3 = function (filenames, secure, callback) {
	if (!filenames.length) {
		return callback(new SGError('NO_FILENAMES'));
	}
	var objects = [];
	filenames.forEach(function (filename) {
		objects.push({
			Key: filename
		});
	});

	this.addToDeleteQueue({
		Bucket: secure ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName,
		Delete: {
			Objects: objects
		}
	}, callback);
};

S3Service.prototype.uploadThenDeleteLocalFile = function (filepath, originalFilename, extension, secure, callback) {
	var self = this;
	//Scan for viruses
	VirusScan.launchFileScan(filepath, function (err, msg) {
		if (err) {
			//An error occured (might be a virus)
			console.log(msg);
			fs.unlink(filepath);
			return callback(err);
		}
		//No virus detected
		FSService.readThenDeleteLocalFile(filepath, function (err, data) {
			if (err) {
				return callback(err);
			}
			self.writeFileToS3(new Buffer(data, 'binary').toString('base64'), originalFilename, extension, secure, function (err, filename) {
				if (err) {
					return callback(err);
				}

				callback(err, self.getConfig().s3StaticURL + "/" + (secure ? self.getConfig().s3SecuredBucketName : self.getConfig().s3BucketName) + "/" + filename);
			});
		});
	});
};

S3Service.prototype.getFileFromS3AndWriteItToFileSystem = function (filename, bucket, callback) {
	this.readFileFromS3(filename, bucket, function (err, data) {
		if (err) {
			return callback(err);
		}

		FSService.writeDataToFileSystem(filename, data.Body, function (err, filepath) {
			if (err) {
				return callback(err);
			}

			console.log("filepath", filepath);

			VirusScan.launchFileScan(filepath, function (err, msg) {
				if (err) {
					//An error occured (might be a virus)
					console.log(msg);
					// TODO delete file on S3
					fs.unlink(filepath);
					return callback(err);
				}

				callback(null, filepath);
			});
		});
	});
};

exports.getConfig = function () {
	// TODO for each attr in AWS
	return {
		region: config.AWS.region,
		accessKeyId: config.AWS.accessKeyId,
		secretAccessKey: config.AWS.secretAccessKey,
		s3StaticURL: config.AWS.s3StaticURL,
		s3BucketName: config.AWS.s3BucketName,
		s3SecuredBucketName: config.AWS.s3SecuredBucketName,
		sesFromEmail: config.AWS.sesFromEmail,
		sesSender: config.AWS.sesSender
	};
};

exports.getSecuredFilepath = function (filename, config) {
	var knox = require('knox');
	var s3Client = knox.createClient({
		key: config.accessKeyId,
		secret: config.secretAccessKey,
		bucket: config.s3SecuredBucketName
	});

	var expires = new Date();
	expires.setMinutes(expires.getMinutes() + 30);
	return s3Client.signedUrl(filename, expires);
};

exports.S3Service = S3Service;<commit_msg>WIP test<commit_after>var contentType = require('node-lib').content_type.ext;
var VirusScan = require('../../utils/VirusScan');
var FSService = require('../local/FSService');

var async = require('async');
var AWS = require('aws-sdk');
var uuid = require('node-uuid');
var fs = require('fs');
var tmp = require('tmp');

var writeQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

var readQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

var removeQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

var deleteQueue = async.queue(function (task, callback) {
	task(callback);
}, 3);

function S3Service(config) {
	this.getConfig = function () {
		return config;
	};
	AWS.config.update({
		region: config.region,
		accessKeyId: config.accessKeyId,
		secretAccessKey: config.secretAccessKey
	});
	var s3 = new AWS.S3();
	this.getS3 = function () {
		return s3;
	};
}

S3Service.prototype.addToWriteQueue = function (params, callback) {
	writeQueue.push(function (callback) {
		this.getS3().client.putObject(params, callback);
	}, callback);
};

S3Service.prototype.addToReadQueue = function (params, callback) {
	readQueue.push(function (callback) {
		this.getS3().client.getObject(params, callback);
	}, callback);
};

S3Service.prototype.addToRemoveQueue = function (params, callback) {
	removeQueue.push(function (callback) {
		this.getS3().client.deleteObject(params, callback);
	}, callback);
};

S3Service.prototype.addToDeleteQueue = function (params, callback) {
	deleteQueue.push(function (callback) {
		this.getS3().client.deleteObjects(params, callback);
	}, callback);
};

S3Service.prototype.bucketInitialization = function () {
	var self = this;
	var bucketNames = [];
	if (this.getConfig().s3BucketName) bucketNames.push(this.getConfig().s3BucketName);
	if (this.getConfig().s3SecuredBucketName) bucketNames.push(this.getConfig().s3SecuredBucketName);

	this.getS3().client.listBuckets(function (err, data) {
		if (err) {
			console.log(err);
		} else {
			bucketNames.forEach(function (bucketName) {
				if (data.Buckets.filter(function (bucket) {
					return bucket.Name == bucketName;
				}).length === 0) {
					self.getS3().client.createBucket({
						Bucket: bucketName
					}, function (err, data) {
						if (err) {
							console.log(err);
						} else console.log("Successfully created S3 " + bucketName + " bucket");
					});
				} else {
					console.log("S3 bucket " + bucketName + " connected...");
				}
			});
		}
	});
};

S3Service.prototype.writeFileToS3 = function (base64data, originalFilename, extension, secure, callback) {
	var name = uuid.v4();
	var filename = extension ? name + "." + extension : name;

	console.log("write file to S3: ", originalFilename);

	this.addToWriteQueue({
		Bucket: secure ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName,
		Key: filename,
		Body: new Buffer(base64data, 'base64'),
		ContentType: contentType.getContentType(extension),
		ContentDisposition: 'attachment; filename="' + originalFilename || filename + '"'
	}, function (err) {
		callback(err, filename);
	});
};

S3Service.prototype.readFileFromS3 = function (filename, secureOrBucket, callback) {
	var bucket;
	if (typeof secureOrBucket == "string") {
		bucket = secureOrBucket;
	} else {
		bucket = secureOrBucket ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName;
	}

	this.addToReadQueue({
		Bucket: bucket,
		Key: filename
	}, callback);
};

S3Service.prototype.removeFileFromS3 = function (filename, secure, callback) {
	this.addToRemoveQueue({
		Bucket: secure ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName,
		Key: filename
	}, callback);
};

S3Service.prototype.removeFilesFromS3 = function (filenames, secure, callback) {
	if (!filenames.length) {
		return callback(new SGError('NO_FILENAMES'));
	}
	var objects = [];
	filenames.forEach(function (filename) {
		objects.push({
			Key: filename
		});
	});

	this.addToDeleteQueue({
		Bucket: secure ? this.getConfig().s3SecuredBucketName : this.getConfig().s3BucketName,
		Delete: {
			Objects: objects
		}
	}, callback);
};

S3Service.prototype.uploadThenDeleteLocalFile = function (filepath, originalFilename, extension, secure, callback) {
	var self = this;
	//Scan for viruses
	VirusScan.launchFileScan(filepath, function (err, msg) {
		if (err) {
			//An error occured (might be a virus)
			console.log(msg);
			fs.unlink(filepath);
			return callback(err);
		}
		//No virus detected
		FSService.readThenDeleteLocalFile(filepath, function (err, data) {
			if (err) {
				return callback(err);
			}
			self.writeFileToS3(new Buffer(data, 'binary').toString('base64'), originalFilename, extension, secure, function (err, filename) {
				if (err) {
					return callback(err);
				}

				callback(err, self.getConfig().s3StaticURL + "/" + (secure ? self.getConfig().s3SecuredBucketName : self.getConfig().s3BucketName) + "/" + filename);
			});
		});
	});
};

S3Service.prototype.getFileFromS3AndWriteItToFileSystem = function (filename, bucket, callback) {
	this.readFileFromS3(filename, bucket, function (err, data) {
		if (err) {
			return callback(err);
		}

		FSService.writeDataToFileSystem(filename, data.Body, function (err, filepath) {
			if (err) {
				return callback(err);
			}

			console.log("filepath", filepath);

			VirusScan.launchFileScan(filepath, function (err, msg) {
				if (err) {
					//An error occured (might be a virus)
					console.log(msg);
					// TODO delete file on S3
					fs.unlink(filepath);
					return callback(err);
				}

				callback(null, filepath);
			});
		});
	});
};

exports.getSecuredFilepath = function (filename, config) {
	var knox = require('knox');
	var s3Client = knox.createClient({
		key: config.accessKeyId,
		secret: config.secretAccessKey,
		bucket: config.s3SecuredBucketName
	});

	var expires = new Date();
	expires.setMinutes(expires.getMinutes() + 30);
	return s3Client.signedUrl(filename, expires);
};

exports.S3Service = S3Service;<|endoftext|>