<commit_before>'use strict'

module.exports = {
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
      experimentalObjectRestSpread: true,
    },
  },
  env: {
    es6: true,
    node: true,
  },
  plugins: [
    'import',
    'promise',
    'unicorn',
  ],
  rules: {
    'accessor-pairs': 'error',
    'array-bracket-spacing': ['error', 'never'],
    'array-callback-return': 'error',
    'arrow-parens': ['error', 'as-needed'],
    'arrow-spacing': ['error', {before: true, after: true}],
    'block-scoped-var': 'error',
    'block-spacing': ['error', 'always'],
    'brace-style': ['error', '1tbs', {allowSingleLine: false}],
    'capitalized-comments': 'off',
    'comma-dangle': ['error', 'always-multiline'],
    'comma-spacing': ['error', {before: false, after: true}],
    'comma-style': ['error', 'last'],
    'computed-property-spacing': ['error', 'never'],
    'constructor-super': 'error',
    'default-case': 'error',
    'dot-location': ['error', 'property'],
    'dot-notation': 'error',
    'eol-last': 'error',
    'func-call-spacing': ['error', 'never'],
    'func-name-matching': 'error',
    'func-names': ['error', 'never'],
    'generator-star-spacing': ['error', 'both'],
    'guard-for-in': 'error',
    'handle-callback-err': 'warn',

    'import/default': 'error',
    'import/export': 'error',
    'import/extensions': ['error', {js: 'never', json: 'never', jsx: 'never'}],
    'import/first': 'error',
    'import/named': 'error',
    'import/namespace': ['error', {allowComputed: true}],
    'import/no-absolute-path': 'error',
    'import/no-webpack-loader-syntax': 'error',
    'import/newline-after-import': 'error',
    'import/no-amd': 'error',
    'import/no-duplicates': 'error',
    'import/no-extraneous-dependencies': 'error',
    'import/no-mutable-exports': 'error',
    'import/no-named-as-default-member': 'error',
    'import/no-named-as-default': 'error',
    'import/no-unresolved': ['error', {commonjs: true}],
    'import/order': ['error', {groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index']}],
    'import/prefer-default-export': 'error',
    'import/no-unassigned-import': 'off',

    'jsx-quotes': 'error',
    'key-spacing': ['error', {beforeColon: false, afterColon: true}],
    'keyword-spacing': 'error',
    'linebreak-style': ['error', 'unix'],
    'max-depth': 'warn',
    'max-nested-callbacks': ['warn', 4],
    'max-params': ['warn', {max: 4}],
    'max-statements-per-line': 'error',
    'new-cap': ['error', {newIsCap: true, capIsNew: true}],
    'new-parens': 'error',
    'no-alert': 'error',
    'no-array-constructor': 'error',
    'no-await-in-loop': 'error',
    'no-caller': 'error',
    'no-case-declarations': 'error',
    'no-class-assign': 'error',
    'no-compare-neg-zero': 'error',
    'no-cond-assign': 'error',
    'no-console': 'error',
    'no-const-assign': 'error',
    'no-constant-condition': 'error',
    'no-control-regex': 'error',
    'no-debugger': 'error',
    'no-delete-var': 'error',
    'no-div-regex': 'error',
    'no-dupe-args': 'error',
    'no-dupe-class-members': 'error',
    'no-dupe-keys': 'error',
    'no-duplicate-case': 'error',
    'no-else-return': 'off',
    'no-empty': ['error', {allowEmptyCatch: true}],
    'no-empty-character-class': 'error',
    'no-empty-pattern': 'error',
    'no-eq-null': 'error',
    'no-eval': 'error',
    'no-ex-assign': 'error',
    'no-extend-native': 'error',
    'no-extra-bind': 'error',
    'no-extra-boolean-cast': 'error',
    'no-extra-label': 'error',
    'no-extra-parens': ['error', 'all', {nestedBinaryExpressions: false, ignoreJSX: 'all'}],
    'no-extra-semi': 'error',
    'no-fallthrough': 'error',
    'no-floating-decimal': 'error',
    'no-func-assign': 'error',
    'no-global-assign': 'error',
    'no-implicit-coercion': 'error',
    'no-implicit-globals': 'error',
    'no-implied-eval': 'error',
    'no-inner-declarations': 'error',
    'no-invalid-regexp': 'error',
    'no-irregular-whitespace': 'error',
    'no-iterator': 'error',
    'no-label-var': 'error',
    'no-labels': 'error',
    'no-lone-blocks': 'error',
    'no-lonely-if': 'error',
    'no-loop-func': 'error',
    'no-mixed-operators': 'error',
    'no-mixed-requires': ['error', {grouping: true, allowCall: true}],
    'no-mixed-spaces-and-tabs': 'error',
    'no-multi-assign': 'error',
    'no-multi-spaces': 'error',
    'no-multi-str': 'error',
    'no-multiple-empty-lines': ['error', {max: 1}],
    'no-negated-condition': 'error',
    'no-new': 'error',
    'no-new-func': 'error',
    'no-new-object': 'error',
    'no-new-require': 'error',
    'no-new-symbol': 'error',
    'no-new-wrappers': 'error',
    'no-obj-calls': 'error',
    'no-octal': 'error',
    'no-octal-escape': 'error',
    'no-path-concat': 'error',
    'no-proto': 'error',
    'no-prototype-builtins': 'error',
    'no-redeclare': 'error',
    'no-regex-spaces': 'error',
    'no-restricted-globals': ['error', 'event'],
    'no-restricted-syntax': ['error', 'WithStatement'],
    'no-return-assign': 'off',
    'no-return-await': 'error',
    'no-script-url': 'error',
    'no-self-assign': ['error', {props: true}],
    'no-self-compare': 'error',
    'no-sequences': 'error',
    'no-shadow-restricted-names': 'error',
    'no-sparse-arrays': 'error',
    'no-template-curly-in-string': 'error',
    'no-this-before-super': 'error',
    'no-throw-literal': 'error',
    'no-trailing-spaces': 'error',
    'no-undef': ['error', {typeof: true}],
    'no-undef-init': 'error',
    'no-unexpected-multiline': 'error',
    'no-unmodified-loop-condition': 'error',
    'no-unneeded-ternary': 'error',
    'no-unreachable': 'error',
    'no-unsafe-finally': 'error',
    'no-unsafe-negation': 'error',
    'no-unused-expressions': 'error',
    'no-unused-labels': 'error',
    'no-unused-vars': ['error', {ignoreRestSiblings: true}],
    'no-use-before-define': ['error', 'nofunc'],
    'no-useless-call': 'error',
    'no-useless-computed-key': 'error',
    'no-useless-concat': 'error',
    'no-useless-constructor': 'error',
    'no-useless-escape': 'error',
    'no-useless-rename': 'error',
    'no-useless-return': 'error',
    'no-var': 'error',
    'no-void': 'error',
    'no-warning-comments': 'warn',
    'no-whitespace-before-property': 'error',
    'no-with': 'error',
    'object-curly-spacing': ['error', 'never'],
    'object-shorthand': ['error', 'always'],
    'one-var': ['error', {initialized: 'never', uninitialized: 'always'}],
    'one-var-declaration-per-line': 'error',
    'operator-assignment': ['error', 'always'],
    'operator-linebreak': ['error', 'after'],
    'padded-blocks': ['error', 'never'],
    'prefer-arrow-callback': 'error',
    'prefer-const': ['error', {destructuring: 'all'}],
    'prefer-numeric-literals': 2,
    'prefer-promise-reject-errors': 'error',

    'promise/always-return': 'warn',
    'promise/no-return-wrap': 'error',
    'promise/param-names': 'error',
    'promise/catch-or-return': 'error',
    'promise/no-native': 'off',
    'promise/no-nesting': 'warn',
    'promise/no-promise-in-callback': 'warn',
    'promise/no-callback-in-promise': 'warn',
    'promise/avoid-new': 'warn',

    'quote-props': ['error', 'as-needed'],
    'require-yield': 'error',
    'rest-spread-spacing': ['error', 'never'],
    'semi-spacing': ['error', {before: false, after: true}],
    'space-before-blocks': ['error', 'always'],
    'space-before-function-paren': ['error', {anonymous: 'always', named: 'never', asyncArrow: 'always'}],
    'space-in-parens': ['error', 'never'],
    'space-infix-ops': 'error',
    'space-unary-ops': 'error',
    'spaced-comment': ['error', 'always', {block: {balanced: true}}],
    'symbol-description': 'error',
    'template-curly-spacing': 'error',
    'template-tag-spacing': ['error', 'never'],

    'unicode-bom': ['error', 'never'],
    'unicorn/explicit-length-check': 'off',
    'unicorn/filename-case': ['warn', {case: 'kebabCase'}],
    'unicorn/catch-error-name': ['error', {name: 'err'}],
    'unicorn/no-abusive-eslint-disable': 'error',
    'unicorn/no-process-exit': 'error',
    'unicorn/throw-new-error': 'error',
    'unicorn/number-literal-case': 'error',
    'unicorn/escape-case': 'error',
    'unicorn/no-array-instanceof': 'error',
    'unicorn/no-new-buffer': 'error',
    'unicorn/no-hex-escape': 'error',
    'unicorn/custom-error-definition': 'error',
    'unicorn/prefer-starts-ends-with': 'error',
    'unicorn/prefer-type-error': 'error',

    'use-isnan': 'error',
    'valid-typeof': ['error', {requireStringLiterals: true}],
    'wrap-iife': ['error', 'inside', {functionPrototypeMethods: true}],
    'yield-star-spacing': ['error', 'both'],

    camelcase: ['error', {properties: 'always'}],
    complexity: ['warn', 10],
    curly: 'error',
    eqeqeq: 'error',
    indent: ['error', 2, {SwitchCase: 1, MemberExpression: 1, CallExpression: {arguments: 1}}],
    quotes: ['error', 'single', {allowTemplateLiterals: true}],
    radix: 'error',
    semi: ['error', 'never'],
    yoda: 'error',
  },
}
<commit_msg>fix: de-noise promise rules<commit_after>'use strict'

module.exports = {
  parser: 'babel-eslint',
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
      experimentalObjectRestSpread: true,
    },
  },
  env: {
    es6: true,
    node: true,
  },
  plugins: [
    'import',
    'promise',
    'unicorn',
  ],
  rules: {
    'accessor-pairs': 'error',
    'array-bracket-spacing': ['error', 'never'],
    'array-callback-return': 'error',
    'arrow-parens': ['error', 'as-needed'],
    'arrow-spacing': ['error', {before: true, after: true}],
    'block-scoped-var': 'error',
    'block-spacing': ['error', 'always'],
    'brace-style': ['error', '1tbs', {allowSingleLine: false}],
    'capitalized-comments': 'off',
    'comma-dangle': ['error', 'always-multiline'],
    'comma-spacing': ['error', {before: false, after: true}],
    'comma-style': ['error', 'last'],
    'computed-property-spacing': ['error', 'never'],
    'constructor-super': 'error',
    'default-case': 'error',
    'dot-location': ['error', 'property'],
    'dot-notation': 'error',
    'eol-last': 'error',
    'func-call-spacing': ['error', 'never'],
    'func-name-matching': 'error',
    'func-names': ['error', 'never'],
    'generator-star-spacing': ['error', 'both'],
    'guard-for-in': 'error',
    'handle-callback-err': 'warn',

    'import/default': 'error',
    'import/export': 'error',
    'import/extensions': ['error', {js: 'never', json: 'never', jsx: 'never'}],
    'import/first': 'error',
    'import/named': 'error',
    'import/namespace': ['error', {allowComputed: true}],
    'import/no-absolute-path': 'error',
    'import/no-webpack-loader-syntax': 'error',
    'import/newline-after-import': 'error',
    'import/no-amd': 'error',
    'import/no-duplicates': 'error',
    'import/no-extraneous-dependencies': 'error',
    'import/no-mutable-exports': 'error',
    'import/no-named-as-default-member': 'error',
    'import/no-named-as-default': 'error',
    'import/no-unresolved': ['error', {commonjs: true}],
    'import/order': ['error', {groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index']}],
    'import/prefer-default-export': 'error',
    'import/no-unassigned-import': 'off',

    'jsx-quotes': 'error',
    'key-spacing': ['error', {beforeColon: false, afterColon: true}],
    'keyword-spacing': 'error',
    'linebreak-style': ['error', 'unix'],
    'max-depth': 'warn',
    'max-nested-callbacks': ['warn', 4],
    'max-params': ['warn', {max: 4}],
    'max-statements-per-line': 'error',
    'new-cap': ['error', {newIsCap: true, capIsNew: true}],
    'new-parens': 'error',
    'no-alert': 'error',
    'no-array-constructor': 'error',
    'no-await-in-loop': 'error',
    'no-caller': 'error',
    'no-case-declarations': 'error',
    'no-class-assign': 'error',
    'no-compare-neg-zero': 'error',
    'no-cond-assign': 'error',
    'no-console': 'error',
    'no-const-assign': 'error',
    'no-constant-condition': 'error',
    'no-control-regex': 'error',
    'no-debugger': 'error',
    'no-delete-var': 'error',
    'no-div-regex': 'error',
    'no-dupe-args': 'error',
    'no-dupe-class-members': 'error',
    'no-dupe-keys': 'error',
    'no-duplicate-case': 'error',
    'no-else-return': 'off',
    'no-empty': ['error', {allowEmptyCatch: true}],
    'no-empty-character-class': 'error',
    'no-empty-pattern': 'error',
    'no-eq-null': 'error',
    'no-eval': 'error',
    'no-ex-assign': 'error',
    'no-extend-native': 'error',
    'no-extra-bind': 'error',
    'no-extra-boolean-cast': 'error',
    'no-extra-label': 'error',
    'no-extra-parens': ['error', 'all', {nestedBinaryExpressions: false, ignoreJSX: 'all'}],
    'no-extra-semi': 'error',
    'no-fallthrough': 'error',
    'no-floating-decimal': 'error',
    'no-func-assign': 'error',
    'no-global-assign': 'error',
    'no-implicit-coercion': 'error',
    'no-implicit-globals': 'error',
    'no-implied-eval': 'error',
    'no-inner-declarations': 'error',
    'no-invalid-regexp': 'error',
    'no-irregular-whitespace': 'error',
    'no-iterator': 'error',
    'no-label-var': 'error',
    'no-labels': 'error',
    'no-lone-blocks': 'error',
    'no-lonely-if': 'error',
    'no-loop-func': 'error',
    'no-mixed-operators': 'error',
    'no-mixed-requires': ['error', {grouping: true, allowCall: true}],
    'no-mixed-spaces-and-tabs': 'error',
    'no-multi-assign': 'error',
    'no-multi-spaces': 'error',
    'no-multi-str': 'error',
    'no-multiple-empty-lines': ['error', {max: 1}],
    'no-negated-condition': 'error',
    'no-new': 'error',
    'no-new-func': 'error',
    'no-new-object': 'error',
    'no-new-require': 'error',
    'no-new-symbol': 'error',
    'no-new-wrappers': 'error',
    'no-obj-calls': 'error',
    'no-octal': 'error',
    'no-octal-escape': 'error',
    'no-path-concat': 'error',
    'no-proto': 'error',
    'no-prototype-builtins': 'error',
    'no-redeclare': 'error',
    'no-regex-spaces': 'error',
    'no-restricted-globals': ['error', 'event'],
    'no-restricted-syntax': ['error', 'WithStatement'],
    'no-return-assign': 'off',
    'no-return-await': 'error',
    'no-script-url': 'error',
    'no-self-assign': ['error', {props: true}],
    'no-self-compare': 'error',
    'no-sequences': 'error',
    'no-shadow-restricted-names': 'error',
    'no-sparse-arrays': 'error',
    'no-template-curly-in-string': 'error',
    'no-this-before-super': 'error',
    'no-throw-literal': 'error',
    'no-trailing-spaces': 'error',
    'no-undef': ['error', {typeof: true}],
    'no-undef-init': 'error',
    'no-unexpected-multiline': 'error',
    'no-unmodified-loop-condition': 'error',
    'no-unneeded-ternary': 'error',
    'no-unreachable': 'error',
    'no-unsafe-finally': 'error',
    'no-unsafe-negation': 'error',
    'no-unused-expressions': 'error',
    'no-unused-labels': 'error',
    'no-unused-vars': ['error', {ignoreRestSiblings: true}],
    'no-use-before-define': ['error', 'nofunc'],
    'no-useless-call': 'error',
    'no-useless-computed-key': 'error',
    'no-useless-concat': 'error',
    'no-useless-constructor': 'error',
    'no-useless-escape': 'error',
    'no-useless-rename': 'error',
    'no-useless-return': 'error',
    'no-var': 'error',
    'no-void': 'error',
    'no-warning-comments': 'warn',
    'no-whitespace-before-property': 'error',
    'no-with': 'error',
    'object-curly-spacing': ['error', 'never'],
    'object-shorthand': ['error', 'always'],
    'one-var': ['error', {initialized: 'never', uninitialized: 'always'}],
    'one-var-declaration-per-line': 'error',
    'operator-assignment': ['error', 'always'],
    'operator-linebreak': ['error', 'after'],
    'padded-blocks': ['error', 'never'],
    'prefer-arrow-callback': 'error',
    'prefer-const': ['error', {destructuring: 'all'}],
    'prefer-numeric-literals': 2,
    'prefer-promise-reject-errors': 'error',

    'promise/always-return': 'warn',
    'promise/no-return-wrap': 'error',
    'promise/param-names': 'error',
    'promise/catch-or-return': 'error',
    'promise/no-native': 'off',
    'promise/no-nesting': 'off',
    'promise/no-promise-in-callback': 'off',
    'promise/no-callback-in-promise': 'off',
    'promise/avoid-new': 'off',

    'quote-props': ['error', 'as-needed'],
    'require-yield': 'error',
    'rest-spread-spacing': ['error', 'never'],
    'semi-spacing': ['error', {before: false, after: true}],
    'space-before-blocks': ['error', 'always'],
    'space-before-function-paren': ['error', {anonymous: 'always', named: 'never', asyncArrow: 'always'}],
    'space-in-parens': ['error', 'never'],
    'space-infix-ops': 'error',
    'space-unary-ops': 'error',
    'spaced-comment': ['error', 'always', {block: {balanced: true}}],
    'symbol-description': 'error',
    'template-curly-spacing': 'error',
    'template-tag-spacing': ['error', 'never'],

    'unicode-bom': ['error', 'never'],
    'unicorn/explicit-length-check': 'off',
    'unicorn/filename-case': ['warn', {case: 'kebabCase'}],
    'unicorn/catch-error-name': ['error', {name: 'err'}],
    'unicorn/no-abusive-eslint-disable': 'error',
    'unicorn/no-process-exit': 'error',
    'unicorn/throw-new-error': 'error',
    'unicorn/number-literal-case': 'error',
    'unicorn/escape-case': 'error',
    'unicorn/no-array-instanceof': 'error',
    'unicorn/no-new-buffer': 'error',
    'unicorn/no-hex-escape': 'error',
    'unicorn/custom-error-definition': 'error',
    'unicorn/prefer-starts-ends-with': 'error',
    'unicorn/prefer-type-error': 'error',

    'use-isnan': 'error',
    'valid-typeof': ['error', {requireStringLiterals: true}],
    'wrap-iife': ['error', 'inside', {functionPrototypeMethods: true}],
    'yield-star-spacing': ['error', 'both'],

    camelcase: ['error', {properties: 'always'}],
    complexity: ['warn', 10],
    curly: 'error',
    eqeqeq: 'error',
    indent: ['error', 2, {SwitchCase: 1, MemberExpression: 1, CallExpression: {arguments: 1}}],
    quotes: ['error', 'single', {allowTemplateLiterals: true}],
    radix: 'error',
    semi: ['error', 'never'],
    yoda: 'error',
  },
}
<|endoftext|>


<commit_before>
/**
 * socket.io
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

(function (exports, io) {

  /**
   * Expose constructor.
   */

  exports.Socket = Socket;

  /**
   * Create a new `Socket.IO client` which can establish a persisent
   * connection with a Socket.IO enabled server.
   *
   * @api public
   */

  function Socket (options) {
    this.options = {
        port: 80
      , secure: false
      , host: document ? document.domain : false
      , document: document
      , resource: 'socket.io'
      , transports: io.transports
      , 'connect timeout': 10000
      , 'try multiple transports': true
      , 'reconnect': true
      , 'reconnection delay': 500
      , 'reopen delay': 3000
      , 'max reconnection attempts': 10
      , 'sync disconnect on unload': true
      , 'auto connect': true
    };

    io.util.merge(this.options, options);

    this.connected = false;
    this.open = false;
    this.connecting = false;
    this.reconnecting = false;
    this.namespaces = {};
    this.buffer = [];

    if (this.options['sync disconnect on unload']) {
      var self = this;

      io.util.on(window, 'beforeunload', function () {
        self.disconnect(true);
      }, false);
    }

    if (this.options['auto connect']) {
      this.connect();
    }
};

  /**
   * Apply EventEmitter mixin.
   */

  io.util.mixin(Socket, io.EventEmitter);

  /**
   * Returns a namespace listener/emitter for this socket
   *
   * @api public
   */

  Socket.prototype.of = function (name) {
    if (!this.namespaces[name]) {
      this.namespaces[name] = new io.SocketNamespace(this, name);

      if (name !== '') {
        this.namespaces[name].packet({ type: 'connect' });
      }
    }

    return this.namespaces[name];
  };

  /**
   * Emits the given event to the Socket and all namespaces
   *
   * @api private
   */

  Socket.prototype.publish = function(){
    this.emit.apply(this, arguments);

    for (var namespace in this.namespaces) {
      namespace = this.of(namespace);
      namespace.$emit.apply(namespace, arguments);
    }
  };

  /**
   * Performs the handshake
   *
   * @api private
   */

  function empty () { };

  Socket.prototype.handshake = function (fn) {
    var self = this
      , options = this.options;

    function complete (data) {
      if (data instanceof Error) {
        self.onError(data.message);
      } else {
        fn.apply(null, data.split(':'));
      }
    };

    var url = [
        'http' + (options.secure ? 's' : '' ) + '://' + options.host + ':' + options.port
      , this.options.resource
      , io.protocol
      , '?t=' + + new Date
    ].join('/');

    if (this.isXDomain()) {
      var insertAt = document.getElementsByTagName('script')[0]
        , script = document.createElement('SCRIPT');

      script.src = url + '&jsonp=' + io.j.length;
      insertAt.parentNode.insertBefore(script, insertAt);

      io.j.push(function (data) {
        complete(data);
        script.parentNode.removeChild(script);
      });
    } else {
      var xhr = io.util.request();

      xhr.open('GET', url);
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          xhr.onreadystatechange = empty;

          if (xhr.status == 200) {
            complete(xhr.responseText);
          } else {
            !self.reconnecting && self.onError(xhr.responseText);
          }
        }
      };
      xhr.send(null);
    }
  };

  /**
   * Find an available transport based on the options supplied in the constructor.
   *
   * @api private
   */

  Socket.prototype.getTransport = function (override) {
    var transports = override || this.transports, match;

    for (var i = 0, transport; transport = transports[i]; i++) {
      if (io.Transport[transport]
        && io.Transport[transport].check(this)
        && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
        return new io.Transport[transport](this, this.sessionid);
      }
    }

    return null;
  };

  /**
   * Connects to the server.
   *
   * @param {Function} [fn] Callback.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.connect = function (fn) {
    if (this.connecting) {
      return this;
    }

    var self = this;

    this.handshake(function (sid, close, heartbeat, transports) {
      self.sessionid = sid;
      self.closeTimeout = close;
      self.heartbeatTimeout = heartbeat;
      self.transports = io.util.intersect(transports.split(','), self.options.transports);
      self.transport = self.getTransport();

      if (!self.transport) {
        return;
      }

      self.connecting = true;
      self.publish('connecting', self.transport.name);

      self.transport.open();

      if (self.options.connectTimeout) {
        self.connectTimeoutTimer = setTimeout(function () {
          if (!self.connected) {
            if (self.options['try multiple transports']){
              if (!self.remainingTransports) {
                self.remainingTransports = self.transports.slice(0);
              }

              var transports = self.remainingTransports;

              while (transports.length > 0 && transports.splice(0,1)[0] !=
                self.transport.name) {}

              if (transports.length) {
                self.transport = self.getTransport(transports);
                self.connect();
              }
            }

            if (!self.remainingTransports || self.remainingTransports.length == 0) {
              self.publish('connect_failed');
            }
          }

          if(self.remainingTransports && self.remainingTransports.length == 0) {
            delete self.remainingTransports;
          }
        }, self.options['connect timeout']);
      }

      if (fn && typeof fn == 'function') {
        self.once('connect', fn);
      }
    });

    return this;
  };

  /**
   * Sends a message.
   *
   * @param {Mixed} data The data that needs to be send to the Socket.IO server.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.packet = function (data) {
    if (this.open) {
      this.transport.packet(data);
    } else {
      this.buffer.push(data);
    }

    return this;
  };

  /**
   * Disconnect the established connect.
   *
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.disconnect = function (sync) {
    if (this.connected) {
      if (this.open) {
        this.of('').packet({ type: 'disconnect' });
      }

      // ensure disconnection
      var xhr = io.util.request();
      xhr.open('GET', this.resource + '/' + io.protocol + '/' + this.sessionid);

      if (sync) {
        xhr.sync = true;
      }

      // handle disconnection immediately
      this.onDisconnect();
    }

    return this;
  };

  /**
   * Check if we need to use cross domain enabled transports. Cross domain would
   * be a different port or different domain name.
   *
   * @returns {Boolean}
   * @api private
   */

  Socket.prototype.isXDomain = function () {
    var locPort = window.location.port || 80;
    return this.options.host !== document.domain || this.options.port != locPort;
  };

  /**
   * Called upon handshake.
   *
   * @api private
   */

  Socket.prototype.onConnect = function(){
    this.connected = true;
    this.connecting = false;
    this.publish('connect');
  };

  /**
   * Called when the transport opens
   *
   * @api private
   */

  Socket.prototype.onOpen = function () {
    this.open = true;

    if (this.buffer.length) {
      for (var i = 0, l = this.buffer.length; i < l; i++) {
        this.packet(this.buffer[i]);
      }

      this.buffer = [];
    }
  };

  /**
   * Called when the transport closes.
   *
   * @api private
   */

  Socket.prototype.onClose = function () {
    this.open = false;
  };

  /**
   * Called when the transport first opens a connection
   *
   * @param text
   */

  Socket.prototype.onPacket = function (packet) {
    this.of(packet.endpoint).onPacket(packet);
  };

  /**
   * Handles an error.
   *
   * @api private
   */

  Socket.prototype.onError = function (err) {
    this.publish('error', err);
  };

  /**
   * Called when the transport disconnects.
   *
   * @api private
   */

  Socket.prototype.onDisconnect = function (reason) {
    var wasConnected = this.connected;

    this.connected = false;
    this.connecting = false;
    this.open = false;

    if (wasConnected) {
      this.transport.clearTimeouts();

      this.publish('disconnect', reason);

      if (this.options.reconnect && !this.reconnecting) {
        this.reconnect();
      }
    }
  };

  /**
   * Called upon reconnection.
   *
   * @api private
   */

  Socket.prototype.reconnect = function () {
    this.reconnecting = true;
    this.reconnectionAttempts = 0;
    this.reconnectionDelay = this.options['reconnection delay'];

    var self = this
      , maxAttempts = this.options['max reconnection attempts']
      , tryMultiple = this.options['try multiple transports']

    function reset () {
      if (self.connected) {
        self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
      }

      self.removeListener('connect_failed', maybeReconnect);
      self.removeListener('connect', maybeReconnect);

      self.reconnecting = false;

      delete self.reconnectionAttempts;
      delete self.reconnectionDelay;
      delete self.reconnectionTimer;
      delete self.redoTransports;

      self.options['try multiple transports'] = tryMultiple;
    };

    function maybeReconnect () {
      if (!self.reconnecting) {
        return;
      }

      if (self.connected) {
        return reset();
      };

      if (self.connecting && self.reconnecting) {
        return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
      }

      if (self.reconnectionAttempts++ >= maxAttempts) {
        if (!self.redoTransports) {
          self.on('connect_failed', maybeReconnect);
          self.options['try multiple transports'] = true;
          self.transport = self.getTransport();
          self.redoTransports = true;
          self.connect();
        } else {
          self.publish('reconnect_failed');
          reset();
        }
      } else {
        self.reconnectionDelay *= 2; // exponential back off
        self.connect();
        self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
        self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
      }
    };

    this.options['try multiple transports'] = false;
    this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);

    this.on('connect', maybeReconnect);
  };

})(
    'undefined' != typeof io ? io : module.exports
  , 'undefined' != typeof io ? io : module.parent.exports
);
<commit_msg>Removed option.host, it should be provided by default in the constructor<commit_after>
/**
 * socket.io
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

(function (exports, io) {

  /**
   * Expose constructor.
   */

  exports.Socket = Socket;

  /**
   * Create a new `Socket.IO client` which can establish a persisent
   * connection with a Socket.IO enabled server.
   *
   * @api public
   */

  function Socket (options) {
    this.options = {
        port: 80
      , secure: false
      , document: document
      , resource: 'socket.io'
      , transports: io.transports
      , 'connect timeout': 10000
      , 'try multiple transports': true
      , 'reconnect': true
      , 'reconnection delay': 500
      , 'reopen delay': 3000
      , 'max reconnection attempts': 10
      , 'sync disconnect on unload': true
      , 'auto connect': true
    };

    io.util.merge(this.options, options);

    this.connected = false;
    this.open = false;
    this.connecting = false;
    this.reconnecting = false;
    this.namespaces = {};
    this.buffer = [];

    if (this.options['sync disconnect on unload']) {
      var self = this;

      io.util.on(window, 'beforeunload', function () {
        self.disconnect(true);
      }, false);
    }

    if (this.options['auto connect']) {
      this.connect();
    }
};

  /**
   * Apply EventEmitter mixin.
   */

  io.util.mixin(Socket, io.EventEmitter);

  /**
   * Returns a namespace listener/emitter for this socket
   *
   * @api public
   */

  Socket.prototype.of = function (name) {
    if (!this.namespaces[name]) {
      this.namespaces[name] = new io.SocketNamespace(this, name);

      if (name !== '') {
        this.namespaces[name].packet({ type: 'connect' });
      }
    }

    return this.namespaces[name];
  };

  /**
   * Emits the given event to the Socket and all namespaces
   *
   * @api private
   */

  Socket.prototype.publish = function(){
    this.emit.apply(this, arguments);

    for (var namespace in this.namespaces) {
      namespace = this.of(namespace);
      namespace.$emit.apply(namespace, arguments);
    }
  };

  /**
   * Performs the handshake
   *
   * @api private
   */

  function empty () { };

  Socket.prototype.handshake = function (fn) {
    var self = this
      , options = this.options;

    function complete (data) {
      if (data instanceof Error) {
        self.onError(data.message);
      } else {
        fn.apply(null, data.split(':'));
      }
    };

    var url = [
        'http' + (options.secure ? 's' : '' ) + '://' + options.host + ':' + options.port
      , this.options.resource
      , io.protocol
      , '?t=' + + new Date
    ].join('/');

    if (this.isXDomain()) {
      var insertAt = document.getElementsByTagName('script')[0]
        , script = document.createElement('SCRIPT');

      script.src = url + '&jsonp=' + io.j.length;
      insertAt.parentNode.insertBefore(script, insertAt);

      io.j.push(function (data) {
        complete(data);
        script.parentNode.removeChild(script);
      });
    } else {
      var xhr = io.util.request();

      xhr.open('GET', url);
      xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
          xhr.onreadystatechange = empty;

          if (xhr.status == 200) {
            complete(xhr.responseText);
          } else {
            !self.reconnecting && self.onError(xhr.responseText);
          }
        }
      };
      xhr.send(null);
    }
  };

  /**
   * Find an available transport based on the options supplied in the constructor.
   *
   * @api private
   */

  Socket.prototype.getTransport = function (override) {
    var transports = override || this.transports, match;

    for (var i = 0, transport; transport = transports[i]; i++) {
      if (io.Transport[transport]
        && io.Transport[transport].check(this)
        && (!this.isXDomain() || io.Transport[transport].xdomainCheck())) {
        return new io.Transport[transport](this, this.sessionid);
      }
    }

    return null;
  };

  /**
   * Connects to the server.
   *
   * @param {Function} [fn] Callback.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.connect = function (fn) {
    if (this.connecting) {
      return this;
    }

    var self = this;

    this.handshake(function (sid, close, heartbeat, transports) {
      self.sessionid = sid;
      self.closeTimeout = close;
      self.heartbeatTimeout = heartbeat;
      self.transports = io.util.intersect(transports.split(','), self.options.transports);
      self.transport = self.getTransport();

      if (!self.transport) {
        return;
      }

      self.connecting = true;
      self.publish('connecting', self.transport.name);

      self.transport.open();

      if (self.options.connectTimeout) {
        self.connectTimeoutTimer = setTimeout(function () {
          if (!self.connected) {
            if (self.options['try multiple transports']){
              if (!self.remainingTransports) {
                self.remainingTransports = self.transports.slice(0);
              }

              var transports = self.remainingTransports;

              while (transports.length > 0 && transports.splice(0,1)[0] !=
                self.transport.name) {}

              if (transports.length) {
                self.transport = self.getTransport(transports);
                self.connect();
              }
            }

            if (!self.remainingTransports || self.remainingTransports.length == 0) {
              self.publish('connect_failed');
            }
          }

          if(self.remainingTransports && self.remainingTransports.length == 0) {
            delete self.remainingTransports;
          }
        }, self.options['connect timeout']);
      }

      if (fn && typeof fn == 'function') {
        self.once('connect', fn);
      }
    });

    return this;
  };

  /**
   * Sends a message.
   *
   * @param {Mixed} data The data that needs to be send to the Socket.IO server.
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.packet = function (data) {
    if (this.open) {
      this.transport.packet(data);
    } else {
      this.buffer.push(data);
    }

    return this;
  };

  /**
   * Disconnect the established connect.
   *
   * @returns {io.Socket}
   * @api public
   */

  Socket.prototype.disconnect = function (sync) {
    if (this.connected) {
      if (this.open) {
        this.of('').packet({ type: 'disconnect' });
      }

      // ensure disconnection
      var xhr = io.util.request();
      xhr.open('GET', this.resource + '/' + io.protocol + '/' + this.sessionid);

      if (sync) {
        xhr.sync = true;
      }

      // handle disconnection immediately
      this.onDisconnect();
    }

    return this;
  };

  /**
   * Check if we need to use cross domain enabled transports. Cross domain would
   * be a different port or different domain name.
   *
   * @returns {Boolean}
   * @api private
   */

  Socket.prototype.isXDomain = function () {
    var locPort = window.location.port || 80;
    return this.options.host !== document.domain || this.options.port != locPort;
  };

  /**
   * Called upon handshake.
   *
   * @api private
   */

  Socket.prototype.onConnect = function(){
    this.connected = true;
    this.connecting = false;
    this.publish('connect');
  };

  /**
   * Called when the transport opens
   *
   * @api private
   */

  Socket.prototype.onOpen = function () {
    this.open = true;

    if (this.buffer.length) {
      for (var i = 0, l = this.buffer.length; i < l; i++) {
        this.packet(this.buffer[i]);
      }

      this.buffer = [];
    }
  };

  /**
   * Called when the transport closes.
   *
   * @api private
   */

  Socket.prototype.onClose = function () {
    this.open = false;
  };

  /**
   * Called when the transport first opens a connection
   *
   * @param text
   */

  Socket.prototype.onPacket = function (packet) {
    this.of(packet.endpoint).onPacket(packet);
  };

  /**
   * Handles an error.
   *
   * @api private
   */

  Socket.prototype.onError = function (err) {
    this.publish('error', err);
  };

  /**
   * Called when the transport disconnects.
   *
   * @api private
   */

  Socket.prototype.onDisconnect = function (reason) {
    var wasConnected = this.connected;

    this.connected = false;
    this.connecting = false;
    this.open = false;

    if (wasConnected) {
      this.transport.clearTimeouts();

      this.publish('disconnect', reason);

      if (this.options.reconnect && !this.reconnecting) {
        this.reconnect();
      }
    }
  };

  /**
   * Called upon reconnection.
   *
   * @api private
   */

  Socket.prototype.reconnect = function () {
    this.reconnecting = true;
    this.reconnectionAttempts = 0;
    this.reconnectionDelay = this.options['reconnection delay'];

    var self = this
      , maxAttempts = this.options['max reconnection attempts']
      , tryMultiple = this.options['try multiple transports']

    function reset () {
      if (self.connected) {
        self.publish('reconnect', self.transport.name, self.reconnectionAttempts);
      }

      self.removeListener('connect_failed', maybeReconnect);
      self.removeListener('connect', maybeReconnect);

      self.reconnecting = false;

      delete self.reconnectionAttempts;
      delete self.reconnectionDelay;
      delete self.reconnectionTimer;
      delete self.redoTransports;

      self.options['try multiple transports'] = tryMultiple;
    };

    function maybeReconnect () {
      if (!self.reconnecting) {
        return;
      }

      if (self.connected) {
        return reset();
      };

      if (self.connecting && self.reconnecting) {
        return self.reconnectionTimer = setTimeout(maybeReconnect, 1000);
      }

      if (self.reconnectionAttempts++ >= maxAttempts) {
        if (!self.redoTransports) {
          self.on('connect_failed', maybeReconnect);
          self.options['try multiple transports'] = true;
          self.transport = self.getTransport();
          self.redoTransports = true;
          self.connect();
        } else {
          self.publish('reconnect_failed');
          reset();
        }
      } else {
        self.reconnectionDelay *= 2; // exponential back off
        self.connect();
        self.publish('reconnecting', self.reconnectionDelay, self.reconnectionAttempts);
        self.reconnectionTimer = setTimeout(maybeReconnect, self.reconnectionDelay);
      }
    };

    this.options['try multiple transports'] = false;
    this.reconnectionTimer = setTimeout(maybeReconnect, this.reconnectionDelay);

    this.on('connect', maybeReconnect);
  };

})(
    'undefined' != typeof io ? io : module.exports
  , 'undefined' != typeof io ? io : module.parent.exports
);
<|endoftext|>


<commit_before>function sum(a) {
    var s = 0;
    for (var i = 0; i < a.length; i++) s += a[i];
    return s;
}

function degToRad(a) {
    return Math.PI / 180 * a;
}

function meanAngleDeg(a) {
    return 180 / Math.PI * Math.atan2(
        sum(a.map(degToRad).map(Math.sin)) / a.length,
        sum(a.map(degToRad).map(Math.cos)) / a.length
    );
}

function createBoxPlot(data, element, plottype) {
    var mode = get_current_mode();
    var layout = {};
    switch (mode) {
        case "single-crystal-group":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "single-crystal":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "two-crystal-groups":

            switch (plottype) {

                case "angles":
                    var rows = getDateFromTable(1, [1, 10, 11, 13, 15, 17, 19, 21, 12, 14, 16, 18, 20, 22]);
                    var pos_titles = [];
                    var pair_titles = [];
                    var values = [];
                    var pair_values = [];
                    for (var i = 0; i < rows.length; i++) {
                        title = rows[i][0].split("-");
                        if (!pos_titles.includes(title[0])) {
                            values.push(rows[i].slice(2, 8));
                            pos_titles.push(title[0]);
                        }
                        if (!pos_titles.includes(title[1])) {
                            values.push(rows[i].slice(8));
                            pos_titles.push(title[1]);
                        }
                        if (!pair_titles.includes(rows[i][0])) {
                            pair_values.push(rows[i][1]);
                            pair_titles.push(rows[i][0]);
                        }
                    }

                    var y = Array(values.length).fill('Angles')

                    var trace1 = {
                        y: pair_values,
                        name: 'Distance Ca Å',
                        type: 'box',
                        boxmean: false,
                        text: pair_titles
                    };

                    var trace2 = {
                        y: getColumn(values, 0),
                        name: 'Distance to 7TM axis',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace3 = {
                        y: getColumn(values, 1),
                        name: 'Rotation (Ca angle)',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace4 = {
                        y: getColumn(values, 2),
                        name: 'Rotamer',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace5 = {
                        y: getColumn(values, 3),
                        name: 'SASA',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace6 = {
                        y: getColumn(values, 4),
                        name: 'RSA',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace7 = {
                        y: getColumn(values, 5),
                        name: 'Presence',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var data = [trace1, trace2, trace3, trace4, trace5, trace6, trace7];

                    var layout = {
                        title: 'Grouped barplot of various residue data.',
                        xaxis: {
                            // title: 'Angles',
                            zeroline: false
                        },
                        // grid: {rows: 1, columns: 6, pattern: 'independent'},
                        boxmode: 'group'
                    };

                    break;
                default:
                    var rows = getDateFromTable(1, [1, 2, 3, 4]);

                    var text_array = getColumn(rows, 0);
                    var y0 = getColumn(rows, 1);
                    var y1 = getColumn(rows, 2);
                    var y2 = getColumn(rows, 3);

                    var trace1 = {
                        y: y0,
                        type: 'box',
                        text: text_array,
                        name: 'Set 1',
                        boxpoints: 'all',
                        jitter: 0.3,
                        pointpos: -1.8
                    };

                    var trace2 = {
                        y: y1,
                        type: 'box',
                        text: text_array,
                        name: 'Set 2',
                        boxpoints: 'all',
                        jitter: 0.3,
                        pointpos: -1.8
                    };

                    var trace3 = {
                        y: y2,
                        type: 'box',
                        text: text_array,
                        name: 'Diff',
                        boxpoints: 'all',
                        jitter: 0.3,
                        pointpos: -1.8
                    };

                    var data = [trace1, trace2, trace3];
                    var layout = {
                        title: 'Occurance (%) of contact interaction in each set and the difference',
                        xaxis: {
                            // title: 'Angles',
                            zeroline: false
                        },
                        // grid: {rows: 1, columns: 6, pattern: 'independent'},
                        boxmode: 'group'
                    };
            }

            break;
    }

    Plotly.newPlot(element, data, layout);

}

function createBoxPlotResidue(gn, element, plottype, data_type, limit_pdbs = false, aa = false) {
    console.log("createBoxPlotResidue",gn,data_type);
    var mode = get_current_mode();
    var layout = {};
    data = two_sets_data['all_angles'][gn];
    switch (mode) {
        case "single-crystal-group":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "single-crystal":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "two-crystal-groups":

            switch (plottype) {

                case "angles":

                    x = [];
                    ys = {};
                    ys1 = {};
                    ys2 = {};
                    pdbs = [];
                    pos = '';
                        pdbs_shown = []
                    if (!two_sets_data['normalized']) {
                        var temp_two_sets_pdbs1 = two_sets_pdbs1;
                        var temp_two_sets_pdbs2 = two_sets_pdbs2;
                        pdbs = temp_two_sets_pdbs1.concat(temp_two_sets_pdbs2);
                        // If only use a subset of pdbs.
                        if (limit_pdbs) pdbs = limit_pdbs;
                        pdbs.forEach(function(pdb) {
                            pdb = pdb.toUpperCase();
                            let d = data[pdb];
                            if (d.length > 0) {
                                pos = d[0];
                                pdbs_shown.push(pdb)
                                if (temp_two_sets_pdbs1.includes(pdb)) {
                                    x.push('Set 1');
                                } else if (temp_two_sets_pdbs2.includes(pdb)) {
                                    x.push('Set 2');
                                }
                                for (var i = 2; i < d.length; i++) {
                                    if (!ys[i - 2]) {
                                        ys[i - 2] = [];
                                        ys1[i - 2] = [];
                                        ys2[i - 2] = [];
                                    }
                                    ys[i - 2].push(d[i]);

                                    if (temp_two_sets_pdbs1.includes(pdb))
                                        ys1[i - 2].push(d[i]);

                                    if (temp_two_sets_pdbs2.includes(pdb))
                                        ys2[i - 2].push(d[i]);
                                }
                            }
                        });

                    } else if (two_sets_data['normalized']) {
                        temp_two_sets_pdbs1 = two_sets_data['pfs1'];
                        temp_two_sets_pdbs2 = two_sets_data['pfs2'];

                        pdbs = temp_two_sets_pdbs1.concat(temp_two_sets_pdbs2);

                        temp_two_sets_pdbs1.forEach(function(pdb) {
                            pdb = pdb.toUpperCase();
                            let d = two_sets_data['all_angles_set1'][gn][pdb];
                            if (d.length > 0) {
                                pos = d[0];
                                pdbs_shown.push(pdb)
                                x.push('Set 1');
                                for (var i = 2; i < d.length; i++) {
                                    if (!ys[i - 2]) {
                                        ys[i - 2] = [];
                                        ys1[i - 2] = [];
                                        ys2[i - 2] = [];
                                    }
                                    ys[i - 2].push(d[i]);
                                    ys1[i - 2].push(d[i]);
                                }
                            }
                        });

                        temp_two_sets_pdbs2.forEach(function(pdb) {
                            pdb = pdb.toUpperCase();
                            let d = two_sets_data['all_angles_set2'][gn][pdb];
                            if (d.length > 0) {
                                pos = d[0];
                                pdbs_shown.push(pdb)
                                x.push('Set 2');
                                for (var i = 2; i < d.length; i++) {
                                    if (!ys[i - 2]) {
                                        ys[i - 2] = [];
                                        ys1[i - 2] = [];
                                        ys2[i - 2] = [];
                                    }
                                    ys[i - 2].push(d[i]);
                                    ys2[i - 2].push(d[i]);
                                }
                            }
                        });

                    }

                    if (aa) pos = pos + " " + aa;

                    names = [['core_distance',false], ['a_angle',true], ['outer_angle',true], ['tau',true], ['phi',true], ['psi',true], ['sasa',false], ['rsa',false], ['theta',true], ['hse',false], ['dssp',false], ['tau_angle', true]]

                    // name_index = Math.floor((cell_index - 6) / 2);
                    name_index = {
                        7: 'core_distance',
                        8: 'core_distance',
                        9: 'a_angle',
                        10: 'a_angle',
                        11: 'outer_angle',
                        12: 'outer_angle',
                        13: 'sasa',
                        14: 'sasa',
                        15: 'rsa',
                        16: 'rsa'
                    };

                    // console.log(cell_index,name_index,name_index[cell_index]);
                    // console.log(ys1,ys2);
                    var traces = [];
                    is_angle = true;
                    for (const key in ys) {
                        if (data_type != names[key][0]) continue;
                        is_angle = names[key][1]
                        new_x = []
                        for (var i = 0; i < x.length; i++) {
                            new_x.push(names[key][0] + "<br>" + x[i]);
                        }
                        visible_trace = 'legendonly';
                        if (data_type == names[key][0]) visible_trace = true;
                        // console.log(data_type,'is_angle',is_angle)
                        if (names[key][1] == true) {
                            mean1 = meanAngleDeg(ys1[key]);
                            mean2 = meanAngleDeg(ys2[key]);
                            traces = [{
                                    type: "scatterpolar",
                                    mode: "markers",
                                    r: Array(ys1[key].length).fill(1),
                                    theta: ys1[key],
                                    name: "Set 1",
                                    marker: {
                                        color: "#8090c7",
                                        symbol: "circle",
                                        size: 15
                                    },
                                    opacity: 0.8,
                                },
                                {
                                    type: "scatterpolar",
                                    mode: "lines",
                                    r: [0, 0.9],
                                    theta: [0, mean1],
                                    name: "Set 1 mean",
                                    line: {
                                        color: "#8090c7",
                                        width: 5,
                                    },
                                },
                                {
                                    type: "scatterpolar",
                                    mode: "markers",
                                    r: Array(ys2[key].length).fill(1),
                                    theta: ys2[key],
                                    name: "Set 2",
                                    marker: {
                                        color: "red",
                                        symbol: "circle",
                                        size: 15
                                    },
                                    opacity: 0.8,
                                    subplot: "polar2"
                                },
                                {
                                    type: "scatterpolar",
                                    mode: "lines",
                                    r: [0, 0.9],
                                    theta: [0, mean2],
                                    name: "Set 2 mean",
                                    line: {
                                        color: "red",
                                        width: 5,
                                    },
                                    subplot: "polar2"
                                }];

                        } else {
                            trace = {
                                y: ys[key],
                                x: new_x,
                                name: names[key][0],
                                type: 'box',
                                boxmean: true,
                                // boxpoints: 'all',
                                text: pdbs_shown,
                                jitter: 0.5,
                                whiskerwidth: 0.2,
                                fillcolor: 'cls',
                                marker: {
                                    size: 2
                                },
                                line: {
                                    width: 1
                                },
                                visible: visible_trace
                            };
                            // Only show one data type on a chart.
                            traces.push(trace);

                        }
                    }

                    var data = traces;
                    if (is_angle == true) {

                        var layout = {
                            title: 'Angles data for position ' + pos,
                            polar: {
                                radialaxis: {
                                    //autorange: true,
                                    showgrid: true,
                                    zeroline: false,
                                    showline: false,
                                    autotick: true,
                                    ticks: '',
                                    showticklabels: false,
                                    range: [0, 1.1]

                                },
                                angularaxis: {
                                    tickfont: {
                                        size: 8
                                    }
                                }
                                },
                            polar2: {
                                radialaxis: {
                                    //autorange: true,
                                    showgrid: true,
                                    zeroline: false,
                                    showline: false,
                                    autotick: true,
                                    ticks: '',
                                    showticklabels: false,
                                    range: [0, 1.1]

                                },
                                angularaxis: {
                                    tickfont: {
                                        size: 8
                                    }
                                }
                                }
                        }
                    } else {
                        var layout = {
                            title: 'Angles data for position ' + pos,
                            // xaxis: {
                            //     zeroline: false
                            // },
                            xaxis: {
                                showgrid: false,
                                zeroline: false,
                            },
                            yaxis: {
                                zeroline: false
                            },
                            // boxmode: 'group'
                        };
                    }
                    break;
                default:
            }

            break;
    }
    Plotly.newPlot(element, data, layout, { showLink: true }); //editable: true,
}

function getDateFromTable(browser_tab, columns) {
    var mode = get_current_mode();
    var mode_tab = mode + "-tab";
    var tab_id = "#" + mode_tab + " .browser-table-" + browser_tab;
    console.log(tab_id);
    var rows = [];
    if ($.fn.DataTable.isDataTable(tab_id)) {
        var table = $(tab_id).DataTable();
        table.rows({
            filter: 'applied'
        }).data().each(function(i) {
            var temp = [];
            columns.forEach(function(c, ii) {
                temp.push(i[c]);
            });
            rows.push(temp);
        })
    }
    return rows;

}

function getColumn(anArray, columnNumber) {
    return anArray.map(function(row) {
        return row[columnNumber];
    });
}
<commit_msg>js lint<commit_after>function sum(a) {
    var s = 0;
    for (var i = 0; i < a.length; i++) s += a[i];
    return s;
}

function degToRad(a) {
    return Math.PI / 180 * a;
}

function meanAngleDeg(a) {
    return 180 / Math.PI * Math.atan2(
        sum(a.map(degToRad).map(Math.sin)) / a.length,
        sum(a.map(degToRad).map(Math.cos)) / a.length
    );
}

function createBoxPlot(data, element, plottype) {
    var mode = get_current_mode();
    var layout = {};
    switch (mode) {
        case "single-crystal-group":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "single-crystal":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "two-crystal-groups":

            switch (plottype) {

                case "angles":
                    var rows = getDateFromTable(1, [1, 10, 11, 13, 15, 17, 19, 21, 12, 14, 16, 18, 20, 22]);
                    var pos_titles = [];
                    var pair_titles = [];
                    var values = [];
                    var pair_values = [];
                    for (var i = 0; i < rows.length; i++) {
                        title = rows[i][0].split("-");
                        if (!pos_titles.includes(title[0])) {
                            values.push(rows[i].slice(2, 8));
                            pos_titles.push(title[0]);
                        }
                        if (!pos_titles.includes(title[1])) {
                            values.push(rows[i].slice(8));
                            pos_titles.push(title[1]);
                        }
                        if (!pair_titles.includes(rows[i][0])) {
                            pair_values.push(rows[i][1]);
                            pair_titles.push(rows[i][0]);
                        }
                    }

                    var y = Array(values.length).fill('Angles')

                    var trace1 = {
                        y: pair_values,
                        name: 'Distance Ca Å',
                        type: 'box',
                        boxmean: false,
                        text: pair_titles
                    };

                    var trace2 = {
                        y: getColumn(values, 0),
                        name: 'Distance to 7TM axis',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace3 = {
                        y: getColumn(values, 1),
                        name: 'Rotation (Ca angle)',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace4 = {
                        y: getColumn(values, 2),
                        name: 'Rotamer',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace5 = {
                        y: getColumn(values, 3),
                        name: 'SASA',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace6 = {
                        y: getColumn(values, 4),
                        name: 'RSA',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var trace7 = {
                        y: getColumn(values, 5),
                        name: 'Presence',
                        type: 'box',
                        boxmean: false,
                        text: pos_titles
                    };

                    var data = [trace1, trace2, trace3, trace4, trace5, trace6, trace7];

                    var layout = {
                        title: 'Grouped barplot of various residue data.',
                        xaxis: {
                            // title: 'Angles',
                            zeroline: false
                        },
                        // grid: {rows: 1, columns: 6, pattern: 'independent'},
                        boxmode: 'group'
                    };

                    break;
                default:
                    var rows = getDateFromTable(1, [1, 2, 3, 4]);

                    var text_array = getColumn(rows, 0);
                    var y0 = getColumn(rows, 1);
                    var y1 = getColumn(rows, 2);
                    var y2 = getColumn(rows, 3);

                    var trace1 = {
                        y: y0,
                        type: 'box',
                        text: text_array,
                        name: 'Set 1',
                        boxpoints: 'all',
                        jitter: 0.3,
                        pointpos: -1.8
                    };

                    var trace2 = {
                        y: y1,
                        type: 'box',
                        text: text_array,
                        name: 'Set 2',
                        boxpoints: 'all',
                        jitter: 0.3,
                        pointpos: -1.8
                    };

                    var trace3 = {
                        y: y2,
                        type: 'box',
                        text: text_array,
                        name: 'Diff',
                        boxpoints: 'all',
                        jitter: 0.3,
                        pointpos: -1.8
                    };

                    var data = [trace1, trace2, trace3];
                    var layout = {
                        title: 'Occurance (%) of contact interaction in each set and the difference',
                        xaxis: {
                            // title: 'Angles',
                            zeroline: false
                        },
                        // grid: {rows: 1, columns: 6, pattern: 'independent'},
                        boxmode: 'group'
                    };
            }

            break;
    }

    Plotly.newPlot(element, data, layout);

}

function createBoxPlotResidue(gn, element, plottype, data_type, limit_pdbs = false, aa = false) {
    console.log("createBoxPlotResidue", gn, data_type);
    var mode = get_current_mode();
    var layout = {};
    data = two_sets_data['all_angles'][gn];
    switch (mode) {
        case "single-crystal-group":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "single-crystal":

            var data = [{
                y: [0, 1, 1, 2, 3, 5, 8, 13, 21],
                boxpoints: 'all',
                jitter: 0.3,
                pointpos: -1.8,
                type: 'box',
                text: ['Text A', 'Text B', 'Text C', 'Text D', 'Text E'],
            }];

            break;
        case "two-crystal-groups":

            switch (plottype) {

                case "angles":

                    x = [];
                    ys = {};
                    ys1 = {};
                    ys2 = {};
                    pdbs = [];
                    pos = '';
                    pdbs_shown = []
                    if (!two_sets_data['normalized']) {
                        var temp_two_sets_pdbs1 = two_sets_pdbs1;
                        var temp_two_sets_pdbs2 = two_sets_pdbs2;
                        pdbs = temp_two_sets_pdbs1.concat(temp_two_sets_pdbs2);
                        // If only use a subset of pdbs.
                        if (limit_pdbs) pdbs = limit_pdbs;
                        pdbs.forEach(function (pdb) {
                            pdb = pdb.toUpperCase();
                            let d = data[pdb];
                            if (d.length > 0) {
                                pos = d[0];
                                pdbs_shown.push(pdb)
                                if (temp_two_sets_pdbs1.includes(pdb)) {
                                    x.push('Set 1');
                                } else if (temp_two_sets_pdbs2.includes(pdb)) {
                                    x.push('Set 2');
                                }
                                for (var i = 2; i < d.length; i++) {
                                    if (!ys[i - 2]) {
                                        ys[i - 2] = [];
                                        ys1[i - 2] = [];
                                        ys2[i - 2] = [];
                                    }
                                    ys[i - 2].push(d[i]);

                                    if (temp_two_sets_pdbs1.includes(pdb))
                                        ys1[i - 2].push(d[i]);

                                    if (temp_two_sets_pdbs2.includes(pdb))
                                        ys2[i - 2].push(d[i]);
                                }
                            }
                        });

                    } else if (two_sets_data['normalized']) {
                        temp_two_sets_pdbs1 = two_sets_data['pfs1'];
                        temp_two_sets_pdbs2 = two_sets_data['pfs2'];

                        pdbs = temp_two_sets_pdbs1.concat(temp_two_sets_pdbs2);

                        temp_two_sets_pdbs1.forEach(function (pdb) {
                            pdb = pdb.toUpperCase();
                            let d = two_sets_data['all_angles_set1'][gn][pdb];
                            if (d.length > 0) {
                                pos = d[0];
                                pdbs_shown.push(pdb)
                                x.push('Set 1');
                                for (var i = 2; i < d.length; i++) {
                                    if (!ys[i - 2]) {
                                        ys[i - 2] = [];
                                        ys1[i - 2] = [];
                                        ys2[i - 2] = [];
                                    }
                                    ys[i - 2].push(d[i]);
                                    ys1[i - 2].push(d[i]);
                                }
                            }
                        });

                        temp_two_sets_pdbs2.forEach(function (pdb) {
                            pdb = pdb.toUpperCase();
                            let d = two_sets_data['all_angles_set2'][gn][pdb];
                            if (d.length > 0) {
                                pos = d[0];
                                pdbs_shown.push(pdb)
                                x.push('Set 2');
                                for (var i = 2; i < d.length; i++) {
                                    if (!ys[i - 2]) {
                                        ys[i - 2] = [];
                                        ys1[i - 2] = [];
                                        ys2[i - 2] = [];
                                    }
                                    ys[i - 2].push(d[i]);
                                    ys2[i - 2].push(d[i]);
                                }
                            }
                        });

                    }

                    if (aa) pos = pos + " " + aa;

                    names = [['core_distance', false], ['a_angle', true], ['outer_angle', true], ['tau', true], ['phi', true], ['psi', true], ['sasa', false], ['rsa', false], ['theta', true], ['hse', false], ['dssp', false], ['tau_angle', true]]

                    // name_index = Math.floor((cell_index - 6) / 2);
                    name_index = {
                        7: 'core_distance',
                        8: 'core_distance',
                        9: 'a_angle',
                        10: 'a_angle',
                        11: 'outer_angle',
                        12: 'outer_angle',
                        13: 'sasa',
                        14: 'sasa',
                        15: 'rsa',
                        16: 'rsa'
                    };

                    // console.log(cell_index,name_index,name_index[cell_index]);
                    // console.log(ys1,ys2);
                    var traces = [];
                    is_angle = true;
                    for (const key in ys) {
                        if (data_type != names[key][0]) continue;
                        is_angle = names[key][1]
                        new_x = []
                        for (var i = 0; i < x.length; i++) {
                            new_x.push(names[key][0] + "<br>" + x[i]);
                        }
                        visible_trace = 'legendonly';
                        if (data_type == names[key][0]) visible_trace = true;
                        // console.log(data_type,'is_angle',is_angle)
                        if (names[key][1] == true) {
                            mean1 = meanAngleDeg(ys1[key]);
                            mean2 = meanAngleDeg(ys2[key]);
                            traces = [{
                                type: "scatterpolar",
                                mode: "markers",
                                r: Array(ys1[key].length).fill(1),
                                theta: ys1[key],
                                name: "Set 1",
                                marker: {
                                    color: "#8090c7",
                                    symbol: "circle",
                                    size: 15
                                },
                                opacity: 0.8,
                            },
                            {
                                type: "scatterpolar",
                                mode: "lines",
                                r: [0, 0.9],
                                theta: [0, mean1],
                                name: "Set 1 mean",
                                line: {
                                    color: "#8090c7",
                                    width: 5,
                                },
                            },
                            {
                                type: "scatterpolar",
                                mode: "markers",
                                r: Array(ys2[key].length).fill(1),
                                theta: ys2[key],
                                name: "Set 2",
                                marker: {
                                    color: "red",
                                    symbol: "circle",
                                    size: 15
                                },
                                opacity: 0.8,
                                subplot: "polar2"
                            },
                            {
                                type: "scatterpolar",
                                mode: "lines",
                                r: [0, 0.9],
                                theta: [0, mean2],
                                name: "Set 2 mean",
                                line: {
                                    color: "red",
                                    width: 5,
                                },
                                subplot: "polar2"
                            }];

                        } else {
                            trace = {
                                y: ys[key],
                                x: new_x,
                                name: names[key][0],
                                type: 'box',
                                boxmean: true,
                                // boxpoints: 'all',
                                text: pdbs_shown,
                                jitter: 0.5,
                                whiskerwidth: 0.2,
                                fillcolor: 'cls',
                                marker: {
                                    size: 2
                                },
                                line: {
                                    width: 1
                                },
                                visible: visible_trace
                            };
                            // Only show one data type on a chart.
                            traces.push(trace);

                        }
                    }

                    var data = traces;
                    if (is_angle == true) {

                        var layout = {
                            title: 'Angles data for position ' + pos,
                            polar: {
                                radialaxis: {
                                    //autorange: true,
                                    showgrid: true,
                                    zeroline: false,
                                    showline: false,
                                    autotick: true,
                                    ticks: '',
                                    showticklabels: false,
                                    range: [0, 1.1]

                                },
                                angularaxis: {
                                    tickfont: {
                                        size: 8
                                    }
                                }
                            },
                            polar2: {
                                radialaxis: {
                                    //autorange: true,
                                    showgrid: true,
                                    zeroline: false,
                                    showline: false,
                                    autotick: true,
                                    ticks: '',
                                    showticklabels: false,
                                    range: [0, 1.1]

                                },
                                angularaxis: {
                                    tickfont: {
                                        size: 8
                                    }
                                }
                            }
                        }
                    } else {
                        var layout = {
                            title: 'Angles data for position ' + pos,
                            // xaxis: {
                            //     zeroline: false
                            // },
                            xaxis: {
                                showgrid: false,
                                zeroline: false,
                            },
                            yaxis: {
                                zeroline: false
                            },
                            // boxmode: 'group'
                        };
                    }
                    break;
                default:
            }

            break;
    }
    Plotly.newPlot(element, data, layout, { showLink: true }); //editable: true,
}

function getDateFromTable(browser_tab, columns) {
    var mode = get_current_mode();
    var mode_tab = mode + "-tab";
    var tab_id = "#" + mode_tab + " .browser-table-" + browser_tab;
    console.log(tab_id);
    var rows = [];
    if ($.fn.DataTable.isDataTable(tab_id)) {
        var table = $(tab_id).DataTable();
        table.rows({
            filter: 'applied'
        }).data().each(function (i) {
            var temp = [];
            columns.forEach(function (c, ii) {
                temp.push(i[c]);
            });
            rows.push(temp);
        })
    }
    return rows;

}

function getColumn(anArray, columnNumber) {
    return anArray.map(function (row) {
        return row[columnNumber];
    });
}
<|endoftext|>


<commit_before>var _ = require('lodash');
var UniSocketServer = require('unisocket');

var logging = require('omega-logger');

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

var logger = logging.loggerFor(module);

function errorToJSON(error)
{
    var ret = _.assign({severity: error}, _.pick(error, 'message', 'stack', 'type'), error);
    logger.warn("Returning error message:", logger.dump(ret));
    return ret;
} // end errorToJSON

function sqlChannelHandler(channel)
{
    //logger.info("Client connected to the 'sql' channel.", logger.dump(channel));
    logger.info("Client connected to the 'sql' channel.");
    var connection;

    var onError = channel.emit.bind(channel, 'error');
    var onRow = channel.emit.bind(channel, 'row');

    function disconnect()
    {
        if(connection)
        {
            connection.removeListener('error', onError);
            connection.removeListener('row', onRow);

            connection.close();

            connection = undefined;
        } // end if
    } // end disconnect

    channel
        /**
         * Connect to the given database.
         *
         * @todo Document parameters.
         */
        .on('connect', function(connectionInfo, callback)
        {
            logger.info("'sql' channel got 'connect': %s", logger.dump(connectionInfo));

            disconnect();

            sql.connect(connectionInfo)
                .then(function(conn)
                {
                    connection = conn;

                    connection.on('error', onError);
                    connection.on('row', onRow);

                    callback();
                })
                .catch(function(error)
                {
                    logger.warn("Returning error to client:", error);
                    callback(errorToJSON(error));
                });
        }) // end 'connect' handler

        /**
         * Execute a query on the current database connection.
         *
         * @fires Connection#row
         *
         * @param {Connection#QueryDef} queryDef - the definition of the query to run
         * @param {function(err, {rows: number, affected: number})} callback - called with an error on failure, or
         *          query statistics on success
         */
        .on('query', function(queryDef, callback)
        {
            logger.info("'sql' channel got 'query': %s", logger.dump(queryDef));

            if(!connection)
            {
                return callback({message: "Not connected!", hint: "You need to connect to a database first."});
            } // end if

            connection
                .query(queryDef)
                .catch(function(error)
                {
                    callback(errorToJSON(error));
                })
                .nodeify(callback);
        }) // end 'query' handler

        /**
         * Close the current connection.
         *
         * @todo Document parameters.
         */
        .on('disconnect', function(callback)
        {
            logger.info("'sql' channel got 'disconnect'.");

            disconnect();
            callback();
        }); // end 'disconnect' handler

    return true;
} // end sqlChannelHandler

module.exports = {
    attach: function(server)
    {
        new UniSocketServer()
            .attach(server)
            .on('connection', function(client)
            {
                //logger.info("Client connected.", logger.dump(client));
                logger.info("Client connected.");

                client
                    .on('foo', function()
                    {
                        logger.info("Got 'foo' from client.");
                    })
                    .on('bar', function(callback)
                    {
                        logger.info("Got 'bar' from client; responding.");
                        callback('bleh');
                    });
            }) // end 'connection' handler
            .channel('sql', sqlChannelHandler);
    } // end attach
};
<commit_msg>Reorganized, and stuff.<commit_after>var _ = require('lodash');
var UniSocketServer = require('unisocket');

var logging = require('omega-logger');

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

var logger = logging.loggerFor(module);

function errorToJSON(error)
{
    var ret = _.assign({severity: error}, _.pick(error, 'message', 'stack', 'type'), error);
    logger.warn("Returning error message:", logger.dump(ret));
    return ret;
} // end errorToJSON

function onConnection(client)
{
    //logger.info("Client connected.", logger.dump(client));
    logger.info("Client connected.");

    client
        .on('foo', function()
        {
            logger.info("Got 'foo' from client.");
        })
        .on('bar', function(callback)
        {
            logger.info("Got 'bar' from client; responding.");
            callback('bleh');
        });
} // end onConnection

function sqlChannelHandler(channel)
{
    //logger.info("Client connected to the 'sql' channel.", logger.dump(channel));
    logger.info("Client connected to the 'sql' channel.");
    var connection;

    var onError = channel.emit.bind(channel, 'error');
    var onRow = channel.emit.bind(channel, 'row');

    function disconnectDB()
    {
        if(connection)
        {
            connection.removeListener('error', onError);
            connection.removeListener('row', onRow);

            connection.close();

            connection = undefined;
        } // end if
    } // end disconnectDB

    /**
     * Connect to the given database.
     *
     * @todo Document parameters.
     */
    function onConnect(connectionInfo, callback)
    {
        logger.info("'sql' channel got 'connect': %s", logger.dump(connectionInfo));

        disconnectDB();

        sql.connect(connectionInfo)
            .then(function(conn)
            {
                connection = conn;

                connection.on('error', onError);
                connection.on('row', onRow);

                callback();
            })
            .catch(function(error)
            {
                logger.warn("Returning error to client:", error);
                callback(errorToJSON(error));
            });
    } // end onConnect

    /**
     * Execute a query on the current database connection.
     *
     * @fires Connection#row
     *
     * @param {Connection#QueryDef} queryDef - the definition of the query to run
     * @param {function(err, {rows: number, affected: number})} callback - called with an error on failure, or
     *          query statistics on success
     */
    function onQuery(queryDef, callback)
    {
        logger.info("'sql' channel got 'query': %s", logger.dump(queryDef));

        if(!connection)
        {
            return callback({message: "Not connected!", hint: "You need to connect to a database first."});
        } // end if

        connection
            .query(queryDef)
            .catch(function(error)
            {
                callback(errorToJSON(error));
            })
            .nodeify(callback);
    } // end onQuery

    /**
     * Close the current connection.
     *
     * @todo Document parameters.
     */
    function onDisconnect(callback)
    {
        logger.info("'sql' channel got 'disconnect'.");

        disconnectDB();
        callback();
    } // end onDisconnect

    channel
        .on('connect', onConnect)
        .on('query', onQuery)
        .on('disconnect', onDisconnect);

    return true;
} // end sqlChannelHandler

module.exports = {
    attach: function(server)
    {
        new UniSocketServer()
            .attach(server)
            .on('connection', onConnection)
            .channel('sql', sqlChannelHandler);
    } // end attach
};
<|endoftext|>