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

// Bootstrap Support, discarded after use
var Bootstrap = {

  // Temporary collection of models to be updated later.
  models: [],

  start: function() {
    global.MODEL = Bootstrap.MODEL.bind(Bootstrap);
  },

  protoFactory: function() {
    var m = this;
    /* Create or Update a Prototype from a psedo-Model definition. */
    var proto = global[m.name];

    if ( ! proto ) {
      proto = m.extends ? Object.create(global[m.extends]) : {};
      global[m.name] = proto;
    }

    if ( ! proto.model_ ) proto.model_ = m;

    if ( m.axioms ) {
      for ( var i = 0 ; i < m.axioms.length ; i++ ) {
        var a = m.axioms[i];
        a.install && a.install.call(a, proto);
      }
    }

    if ( m.methods ) {
      for ( var i = 0 ; i < m.methods.length ; i++ ) {
        var meth = m.methods[i];
        proto[meth.name] = meth.code;
      }
    }

    if ( global.Property && m.properties ) {
      for ( var i = 0 ; i < m.properties.length ; i++ ) {
        var p = m.properties[i];
        var t = p.type ? global[p.type + 'Property'] : Property;
        var prop = t.create(p);
        prop.install(proto);
      }
    }

    return proto;
  },

  // Bootstrap Model definition which records incomplete models
  // so they can be patched at the end of the bootstrap process.
  MODEL: function(m) {
    this.protoFactory.call(m);
    this.models.push(m);
  },

  updateModels: function() {
    var models = this.models;

    for ( var i = 0 ; i < models.length ; i++ ) {
      var m = models[i];
      var proto = global[m.name];

      if ( m.properties ) {
        for ( var j = 0 ; j < m.properties.length ; j++ ) {
          var p = m.properties[j];
          Property.install.call(p, proto);
        }
      }
    }

    for ( var i = 0 ; i < models.length ; i++ ) {
      var m = models[i];
      var proto = global[m.name];

      if ( m.properties ) {
        for ( var j = 0 ; j < m.properties.length ; j++ ) {
          var p = m.properties[j];
          if ( p.type ) {
            var propType = global[p.type + 'Property'];
            if ( propType ) {
              console.log('Updating: ', i, m.name, p.name, p.type);
              propType.install.call(p, proto);
            } else {
              console.warn('Unknown Property type: ', p.type);
            }
          }
        }
      }
    }
  },

  end: function() {
    Bootstrap.updateModels();

    global.CLASS = global.MODEL = function(m) {
      var model = Model.create(m);
      var proto = model.proto;
      global[m.name] = proto;
      return proto;
    }
  }
};

Bootstrap.start();

MODEL({
  name: 'FObject',
  extends: null,

  documentation: 'Base model for model hierarchy.',

  methods: [
    {
      name: 'create',
      code: function(args) {
        var obj = Object.create(this);
        obj.instance_ = {};

        // TODO: lookup if valid method names
        for ( var key in args ) obj[key] = args[key];

        return obj;
      }
    },
    {
      name: 'toString',
      code: function() {
        // Distinguish between prototypes and instances.
        return this.model_.name + (this.instance_ ? '' : 'Proto')
      }
    }
  ],

  // TODO: insert core/FObject.js functionality

  // TODO: insert EventService and PropertyChangeSupport here
});

MODEL({
  name: 'Model',
  extends: 'FObject', // Don't remove, isn't the default yet.

  documentation: 'Class/Prototype description.',

  properties: [
    {
      name: 'name'
    },
    {
      name: 'extends',
      defaultValue: 'FObject'
    },
    {
      // type: 'Array',
      name: 'axioms',
      factory: function() { return []; }
    },
    {
      type: 'Array',
      subType: 'Property',
      name: 'properties',
      adaptArrayElement: function(o) {
        var t = this.type ? global[this.type + 'Property'] : Property;
        return t.create(o);
      }
    },
    {
      type: 'Array',
      subType: 'Method',
      name: 'methods',
      // TODO: this shouldn't be needed
      adapt: function(_, a, prop) {
        if ( ! a ) return [];
        return a.map(prop.adaptArrayElement.bind(prop));
      },
      adaptArrayElement: function(e) {
        if ( typeof e === 'function' ) {
          console.assert(e.name, 'Method must be named');
          return Method.create({name: e.name, code: e});
        }
        return e;
      }
    },
    {
      name: 'proto',
      factory: Bootstrap.protoFactory
    }
  ]
});

MODEL({
  name: 'Property',
  extends: 'FObject',

  properties: [
    {
      name: 'name'
    },
    {
      name: 'type'
    },
    {
      name: 'defaultValue'
    },
    {
      name: 'factory'
    },
    {
      name: 'adapt'
    },
    {
      name: 'preSet'
    },
    {
      name: 'postSet'
    },
    {
      name: 'expression'
      // TODO: implement
    }
  ],

  methods: [
    {
      name: 'install',
      code: function(proto) {
        /*
          Install a property onto a prototype from a Property definition.
          (Property is 'this').
        */
        proto[constantize(this.name)] = this;

        var prop            = this;
        var name            = this.name;
        var adapt           = this.adapt
        var preSet          = this.preSet;
        var postSet         = this.postSet;
        var getter          = this.getter;
        var setter          = this.setter;
        var factory         = this.factory;
        var hasDefaultValue = this.hasOwnProperty('defaultValue');
        var defaultValue    = this.defaultValue;

        /* Future: needs events and slot support first.
           var slotName        = name + '$';
           Object.defineProperty(proto, slotName, {
           get: function propSlotGetter() {
           return this.getSlot(name);
           },
           set: function propSlotSetter(value) {
           value.link.link(this.getSlot(name));
           },
           configurable: true
           });
        */

        Object.defineProperty(proto, name, {
          get: function propGetter() {
            if ( getter ) return getter.call(this);

            if ( ( hasDefaultValue || factory ) &&
                 ! this.instance_.hasOwnProperty(name) )
            {
              if ( hasDefaultValue ) return defaultValue;

              var value = factory.call(this);
              this.instance_[name] = value;
              return value;
            }

            return this.instance_[name];
          },
          set: function propSetter(newValue) {
            if ( setter ) {
              setter.call(this, newValue);
              return;
            }

            // TODO: add logic to not trigger factory
            var oldValue = this[name];

            if ( adapt )  newValue = adapt.call(this, oldValue, newValue, prop);

            if ( preSet ) newValue = preSet.call(this, oldValue, newValue, prop);

            this.instance_[name] = newValue;

            // TODO: fire property change event

            // TODO: call global setter

            if ( postSet ) postSet.call(this, oldValue, newValue, prop);
          },
          configurable: true
        });
      }
    }
  ]
});

MODEL({
  name: 'Method',
  extends: 'FObject',

  properties: [
    {
      name: 'name'
    },
    {
      name: 'code'
    }
  ],

  methods: [
    {
      name: 'install',
      code: function(proto) { proto[this.name] = this.code; }
    }
  ]
});

MODEL({
  name: 'StringProperty',
  extends: 'Property',

  properties: [
    {
      name: 'defaultValue',
      defaultValue: ''
    },
    {
      name: 'preSet',
      defaultValue: function(_, a) {
        return a ? a.toString() : '';
      }
    }
  ]
});

MODEL({
  name: 'ArrayProperty',
  extends: 'Property',

  properties: [
    {
      name: 'factory',
      defaultValue: function() { return []; }
    },
    {
      name: 'subType'
    },
    {
      name: 'preSet',
      defaultValue: function(_, a, prop) {
        var proto = global[prop.subType];
        // TODO: loop for performance
        return a.map(function(p) { return proto.create(p); });
      }
    },
    {
      name: 'adapt',
      defaultValue: function(_, a, prop) {
        if ( ! a ) return [];
        return a.map(prop.adaptArrayElement.bind(prop));
      }
    },
    {
      name: 'adaptArrayElement',
      defaultValue: function(o) {
        return global[this.subType].create(o);
      }
    }
  ]
});

MODEL({
  name: 'AxiomArrayProperty',
  extends: 'ArrayProperty',

  properties: [
    {
      name: 'postSet',
      defaultValue: function(_, a) { this.axioms.push.apply(this.axioms, a); }
    }
  ]
});

Bootstrap.end();
Bootstrap = null;

MODEL({
  name: 'Constant',
  extends: 'FObject', // This line shouldn't be needed.

  properties: [
    {
      name: 'name'
    },
    {
      name: 'value'
    }
  ],

  methods: [
    {
      name: 'install',
      code: function(proto) { proto[constantize(this.name)] = this.value; }
    }
  ]
});

MODEL({
  name: 'Model',

  properties: [
    {
      type: 'AxiomArray',
      subType: 'Constant',
      name: 'constants'
    }
  ]
});

/*
  Notes:

  remove create from regular objects
  acreate or afromJSON

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

// Bootstrap Support, discarded after use
var Bootstrap = {

  // Temporary collection of models to be updated later.
  models: [],

  start: function() {
    global.MODEL = Bootstrap.MODEL.bind(Bootstrap);
  },

  protoFactory: function() {
    var m = this;
    /* Create or Update a Prototype from a psedo-Model definition. */
    var proto = global[m.name];

    if ( ! proto ) {
      proto = m.extends ? Object.create(global[m.extends]) : {};
      global[m.name] = proto;
    }

    if ( ! proto.model_ ) proto.model_ = m;

    if ( m.axioms ) {
      for ( var i = 0 ; i < m.axioms.length ; i++ ) {
        var a = m.axioms[i];
        a.install && a.install.call(a, proto);
      }
    }

    if ( m.methods ) {
      for ( var i = 0 ; i < m.methods.length ; i++ ) {
        var meth = m.methods[i];
        proto[meth.name] = meth.code;
      }
    }

    if ( global.Property && m.properties ) {
      for ( var i = 0 ; i < m.properties.length ; i++ ) {
        var p = m.properties[i];
        var t = p.type ? global[p.type + 'Property'] : Property;
        var prop = t.create(p);
        prop.install(proto);
      }
    }

    return proto;
  },

  // Bootstrap Model definition which records incomplete models
  // so they can be patched at the end of the bootstrap process.
  MODEL: function(m) {
    this.protoFactory.call(m);
    this.models.push(m);
  },

  updateModels: function() {
    var models = this.models;

    for ( var i = 0 ; i < models.length ; i++ ) {
      var m = models[i];
      var proto = global[m.name];

      if ( m.properties ) {
        for ( var j = 0 ; j < m.properties.length ; j++ ) {
          var p = m.properties[j];
          Property.install.call(p, proto);
        }
      }
    }

    for ( var i = 0 ; i < models.length ; i++ ) {
      var m = models[i];
      var proto = global[m.name];

      if ( m.properties ) {
        for ( var j = 0 ; j < m.properties.length ; j++ ) {
          var p = m.properties[j];
          if ( p.type ) {
            var propType = global[p.type + 'Property'];
            if ( propType ) {
              console.log('Updating: ', i, m.name, p.name, p.type);
              propType.install.call(p, proto);
            } else {
              console.warn('Unknown Property type: ', p.type);
            }
          }
        }
      }
    }
  },

  end: function() {
    Bootstrap.updateModels();

    global.CLASS = global.MODEL = function(m) {
      var model = Model.create(m);
      var proto = model.proto;
      global[m.name] = proto;
      return proto;
    }

    global.Bootstrap = null;
  }
};

Bootstrap.start();

MODEL({
  name: 'FObject',
  extends: null,

  documentation: 'Base model for model hierarchy.',

  methods: [
    {
      name: 'create',
      code: function(args) {
        var obj = Object.create(this);
        obj.instance_ = {};

        // TODO: lookup if valid method names
        for ( var key in args ) obj[key] = args[key];

        return obj;
      }
    },
    {
      name: 'toString',
      code: function() {
        // Distinguish between prototypes and instances.
        return this.model_.name + (this.instance_ ? '' : 'Proto')
      }
    }
  ],

  // TODO: insert core/FObject.js functionality

  // TODO: insert EventService and PropertyChangeSupport here
});

MODEL({
  name: 'Model',
  extends: 'FObject', // Don't remove, isn't the default yet.

  documentation: 'Class/Prototype description.',

  properties: [
    {
      name: 'name'
    },
    {
      name: 'extends',
      defaultValue: 'FObject'
    },
    {
      // type: 'Array',
      name: 'axioms',
      factory: function() { return []; }
    },
    {
      type: 'Array',
      subType: 'Property',
      name: 'properties',
      adaptArrayElement: function(o) {
        var t = this.type ? global[this.type + 'Property'] : Property;
        return t.create(o);
      }
    },
    {
      type: 'Array',
      subType: 'Method',
      name: 'methods',
      // TODO: this shouldn't be needed
      adapt: function(_, a, prop) {
        if ( ! a ) return [];
        return a.map(prop.adaptArrayElement.bind(prop));
      },
      adaptArrayElement: function(e) {
        if ( typeof e === 'function' ) {
          console.assert(e.name, 'Method must be named');
          return Method.create({name: e.name, code: e});
        }
        return e;
      }
    },
    {
      name: 'proto',
      factory: Bootstrap.protoFactory
    }
  ]
});

MODEL({
  name: 'Property',
  extends: 'FObject',

  properties: [
    {
      name: 'name'
    },
    {
      name: 'type'
    },
    {
      name: 'defaultValue'
    },
    {
      name: 'factory'
    },
    {
      name: 'adapt'
    },
    {
      name: 'preSet'
    },
    {
      name: 'postSet'
    },
    {
      name: 'expression'
      // TODO: implement
    }
  ],

  methods: [
    {
      name: 'install',
      code: function(proto) {
        /*
          Install a property onto a prototype from a Property definition.
          (Property is 'this').
        */
        proto[constantize(this.name)] = this;

        var prop            = this;
        var name            = this.name;
        var adapt           = this.adapt
        var preSet          = this.preSet;
        var postSet         = this.postSet;
        var getter          = this.getter;
        var setter          = this.setter;
        var factory         = this.factory;
        var hasDefaultValue = this.hasOwnProperty('defaultValue');
        var defaultValue    = this.defaultValue;

        /* Future: needs events and slot support first.
           var slotName        = name + '$';
           Object.defineProperty(proto, slotName, {
           get: function propSlotGetter() {
           return this.getSlot(name);
           },
           set: function propSlotSetter(value) {
           value.link.link(this.getSlot(name));
           },
           configurable: true
           });
        */

        Object.defineProperty(proto, name, {
          get: function propGetter() {
            if ( getter ) return getter.call(this);

            if ( ( hasDefaultValue || factory ) &&
                 ! this.instance_.hasOwnProperty(name) )
            {
              if ( hasDefaultValue ) return defaultValue;

              var value = factory.call(this);
              this.instance_[name] = value;
              return value;
            }

            return this.instance_[name];
          },
          set: function propSetter(newValue) {
            if ( setter ) {
              setter.call(this, newValue);
              return;
            }

            // TODO: add logic to not trigger factory
            var oldValue = this[name];

            if ( adapt )  newValue = adapt.call(this, oldValue, newValue, prop);

            if ( preSet ) newValue = preSet.call(this, oldValue, newValue, prop);

            this.instance_[name] = newValue;

            // TODO: fire property change event

            // TODO: call global setter

            if ( postSet ) postSet.call(this, oldValue, newValue, prop);
          },
          configurable: true
        });
      }
    }
  ]
});

MODEL({
  name: 'Method',
  extends: 'FObject',

  properties: [
    {
      name: 'name'
    },
    {
      name: 'code'
    }
  ],

  methods: [
    {
      name: 'install',
      code: function(proto) { proto[this.name] = this.code; }
    }
  ]
});

MODEL({
  name: 'StringProperty',
  extends: 'Property',

  properties: [
    {
      name: 'defaultValue',
      defaultValue: ''
    },
    {
      name: 'preSet',
      defaultValue: function(_, a) {
        return a ? a.toString() : '';
      }
    }
  ]
});

MODEL({
  name: 'ArrayProperty',
  extends: 'Property',

  properties: [
    {
      name: 'factory',
      defaultValue: function() { return []; }
    },
    {
      name: 'subType'
    },
    {
      name: 'preSet',
      defaultValue: function(_, a, prop) {
        var proto = global[prop.subType];
        // TODO: loop for performance
        return a.map(function(p) { return proto.create(p); });
      }
    },
    {
      name: 'adapt',
      defaultValue: function(_, a, prop) {
        if ( ! a ) return [];
        return a.map(prop.adaptArrayElement.bind(prop));
      }
    },
    {
      name: 'adaptArrayElement',
      defaultValue: function(o) {
        return global[this.subType].create(o);
      }
    }
  ]
});

// TODO: Why does this need to be in the Bootstrap?
MODEL({
  name: 'AxiomArrayProperty',
  extends: 'ArrayProperty',

  properties: [
    {
      name: 'postSet',
      defaultValue: function(_, a) { this.axioms.push.apply(this.axioms, a); }
    }
  ]
});

Bootstrap.end();

MODEL({
  name: 'Constant',
  extends: 'FObject', // This line shouldn't be needed.

  properties: [
    {
      name: 'name'
    },
    {
      name: 'value'
    }
  ],

  methods: [
    {
      name: 'install',
      code: function(proto) { proto[constantize(this.name)] = this.value; }
    }
  ]
});

MODEL({
  name: 'Model',

  properties: [
    {
      type: 'AxiomArray',
      subType: 'Constant',
      name: 'constants'
    }
  ]
});

/*
  Notes:

  remove create from regular objects
  acreate or afromJSON

  TODO:
  - property overriding
*/
<|endoftext|>


<commit_before>/*
  THIS FILE WAS AUTOGENERATED BY mode_highlight_rules.tmpl.js (UUID: 958518BC-799F-477A-99F9-5B28EBF230F6) */

define(function(require, exports, module) {
"use strict";

var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;

var DartHighlightRules = function() {

    var constantLanguage = "true|false|null";
    var variableLanguage = "this|super";
    var keywordControl = "try|catch|finally|throw|break|case|continue|default|do|else|for|if|in|return|switch|while|new";
    var keywordDeclaration = "abstract|class|extends|external|factory|implements|get|native|operator|set|typedef|with";
    var storageModifier = "static|final|const";
    var storageType = "void|bool|num|int|double|dynamic|var|String";

    var keywordMapper = this.createKeywordMapper({
        "constant.language.dart": constantLanguage,
        "variable.language.dart": variableLanguage,
        "keyword.control.dart": keywordControl,
        "keyword.declaration.dart": keywordDeclaration,
        "storage.modifier.dart": storageModifier,
        "storage.type.primitive.dart": storageType
    }, "identifier");

    var stringfill = {
        token : "string",
        regex : ".+"
    };

    // regexp must not have capturing parentheses. Use (?:) instead.
    // regexps are ordered -> the first match is used

    this.$rules =
        {
    "start": [
        {
            token : "comment",
            regex : /\/\/.*$/
        },
        {
            token : "comment", // multi line comment
            regex : /\/\*/,
            next : "comment"
        },
        {
            token: ["meta.preprocessor.script.dart"],
            regex: "^(#!.*)$"
        },
        {
            token: "keyword.other.import.dart",
            regex: "(?:\\b)(?:library|import|part|of)(?:\\b)"
        },
        {
            token : ["keyword.other.import.dart", "text"],
            regex : "(?:\\b)(prefix)(\\s*:)"
        },
        {
            regex: "\\bas\\b",
            token: "keyword.cast.dart"
        },
        {
            regex: "\\?|:",
            token: "keyword.control.ternary.dart"
        },
        {
            regex: "(?:\\b)(is\\!?)(?:\\b)",
            token: ["keyword.operator.dart"]
        },
        {
            regex: "(<<|>>>?|~|\\^|\\||&)",
            token: ["keyword.operator.bitwise.dart"]
        },
        {
            regex: "((?:&|\\^|\\||<<|>>>?)=)",
            token: ["keyword.operator.assignment.bitwise.dart"]
        },
        {
            regex: "(===?|!==?|<=?|>=?)",
            token: ["keyword.operator.comparison.dart"]
        },
        {
            regex: "((?:[+*/%-]|\\~)=)",
            token: ["keyword.operator.assignment.arithmetic.dart"]
        },
        {
            regex: "=",
            token: "keyword.operator.assignment.dart"
        },
        {
            token : "string",
            regex : "'''",
            next : "qdoc"
        },
        {
            token : "string",
            regex : '"""',
            next : "qqdoc"
        },
        {
            token : "string",
            regex : "'",
            next : "qstring"
        },
        {
            token : "string",
            regex : '"',
            next : "qqstring"
        },
        {
            regex: "(\\-\\-|\\+\\+)",
            token: ["keyword.operator.increment-decrement.dart"]
        },
        {
            regex: "(\\-|\\+|\\*|\\/|\\~\\/|%)",
            token: ["keyword.operator.arithmetic.dart"]
        },
        {
            regex: "(!|&&|\\|\\|)",
            token: ["keyword.operator.logical.dart"]
        },
        {
            token : "constant.numeric", // hex
            regex : "0[xX][0-9a-fA-F]+\\b"
        },
        {
            token : "constant.numeric", // float
            regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
        },
        {
            token : keywordMapper,
            regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
        }
    ],
    "comment" : [
        {
            token : "comment", // closing comment
            regex : ".*?\\*\\/",
            next : "start"
        }, {
            token : "comment", // comment spanning whole line
            regex : ".+"
        }
    ],
    "qdoc" : [
        {
            token : "string",
            regex : ".*?'''",
            next : "start"
        }, stringfill],

    "qqdoc" : [
        {
            token : "string",
            regex : '.*?"""',
            next : "start"
        }, stringfill],

    "qstring" : [
        {
            token : "string",
            regex : "[^\\\\']*(?:\\\\.[^\\\\']*)*'",
            next : "start"
        }, stringfill],

    "qqstring" : [
        {
            token : "string",
            regex : '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"',
            next : "start"
        }, stringfill]
}

};

oop.inherits(DartHighlightRules, TextHighlightRules);

exports.DartHighlightRules = DartHighlightRules;
});
<commit_msg>dart_highlight_rules : add `assert` to `keywordControl`<commit_after>/*
  THIS FILE WAS AUTOGENERATED BY mode_highlight_rules.tmpl.js (UUID: 958518BC-799F-477A-99F9-5B28EBF230F6) */

define(function(require, exports, module) {
"use strict";

var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;

var DartHighlightRules = function() {

    var constantLanguage = "true|false|null";
    var variableLanguage = "this|super";
    var keywordControl = "try|catch|finally|throw|assert|break|case|continue|default|do|else|for|if|in|return|switch|while|new";
    var keywordDeclaration = "abstract|class|extends|external|factory|implements|get|native|operator|set|typedef|with";
    var storageModifier = "static|final|const";
    var storageType = "void|bool|num|int|double|dynamic|var|String";

    var keywordMapper = this.createKeywordMapper({
        "constant.language.dart": constantLanguage,
        "variable.language.dart": variableLanguage,
        "keyword.control.dart": keywordControl,
        "keyword.declaration.dart": keywordDeclaration,
        "storage.modifier.dart": storageModifier,
        "storage.type.primitive.dart": storageType
    }, "identifier");

    var stringfill = {
        token : "string",
        regex : ".+"
    };

    // regexp must not have capturing parentheses. Use (?:) instead.
    // regexps are ordered -> the first match is used

    this.$rules =
        {
    "start": [
        {
            token : "comment",
            regex : /\/\/.*$/
        },
        {
            token : "comment", // multi line comment
            regex : /\/\*/,
            next : "comment"
        },
        {
            token: ["meta.preprocessor.script.dart"],
            regex: "^(#!.*)$"
        },
        {
            token: "keyword.other.import.dart",
            regex: "(?:\\b)(?:library|import|part|of)(?:\\b)"
        },
        {
            token : ["keyword.other.import.dart", "text"],
            regex : "(?:\\b)(prefix)(\\s*:)"
        },
        {
            regex: "\\bas\\b",
            token: "keyword.cast.dart"
        },
        {
            regex: "\\?|:",
            token: "keyword.control.ternary.dart"
        },
        {
            regex: "(?:\\b)(is\\!?)(?:\\b)",
            token: ["keyword.operator.dart"]
        },
        {
            regex: "(<<|>>>?|~|\\^|\\||&)",
            token: ["keyword.operator.bitwise.dart"]
        },
        {
            regex: "((?:&|\\^|\\||<<|>>>?)=)",
            token: ["keyword.operator.assignment.bitwise.dart"]
        },
        {
            regex: "(===?|!==?|<=?|>=?)",
            token: ["keyword.operator.comparison.dart"]
        },
        {
            regex: "((?:[+*/%-]|\\~)=)",
            token: ["keyword.operator.assignment.arithmetic.dart"]
        },
        {
            regex: "=",
            token: "keyword.operator.assignment.dart"
        },
        {
            token : "string",
            regex : "'''",
            next : "qdoc"
        },
        {
            token : "string",
            regex : '"""',
            next : "qqdoc"
        },
        {
            token : "string",
            regex : "'",
            next : "qstring"
        },
        {
            token : "string",
            regex : '"',
            next : "qqstring"
        },
        {
            regex: "(\\-\\-|\\+\\+)",
            token: ["keyword.operator.increment-decrement.dart"]
        },
        {
            regex: "(\\-|\\+|\\*|\\/|\\~\\/|%)",
            token: ["keyword.operator.arithmetic.dart"]
        },
        {
            regex: "(!|&&|\\|\\|)",
            token: ["keyword.operator.logical.dart"]
        },
        {
            token : "constant.numeric", // hex
            regex : "0[xX][0-9a-fA-F]+\\b"
        },
        {
            token : "constant.numeric", // float
            regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
        },
        {
            token : keywordMapper,
            regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
        }
    ],
    "comment" : [
        {
            token : "comment", // closing comment
            regex : ".*?\\*\\/",
            next : "start"
        }, {
            token : "comment", // comment spanning whole line
            regex : ".+"
        }
    ],
    "qdoc" : [
        {
            token : "string",
            regex : ".*?'''",
            next : "start"
        }, stringfill],

    "qqdoc" : [
        {
            token : "string",
            regex : '.*?"""',
            next : "start"
        }, stringfill],

    "qstring" : [
        {
            token : "string",
            regex : "[^\\\\']*(?:\\\\.[^\\\\']*)*'",
            next : "start"
        }, stringfill],

    "qqstring" : [
        {
            token : "string",
            regex : '[^\\\\"]*(?:\\\\.[^\\\\"]*)*"',
            next : "start"
        }, stringfill]
}

};

oop.inherits(DartHighlightRules, TextHighlightRules);

exports.DartHighlightRules = DartHighlightRules;
});
<|endoftext|>


<commit_before>var
  _ = require('lodash'),
  q = require('q'),
  async = require('async'),
  vm = require('vm'),
  BadRequestError = require('../../errors/badRequestError'),
  RequestObject = require('../requestObject'),
  InternalError = require('../../errors/internalError'),
  ParseError = require('../../errors/parseError'),
  Sandbox = require('../../sandbox'),
  internalIndex = require('rc')('kuzzle').internalIndex;

function Role () {
  this.controllers = {};
  this.closures = {};
}

function doesIndexExist(requestObject, indexes) {
  return indexes && indexes[requestObject.index] !== undefined;
}

function doesCollectionExist(requestObject, indexes) {
  return indexes && _.includes(indexes[requestObject.index], requestObject.collection);
}

function isInternalIndexAllowed(restrictions) {
  var
    isAllowed = false;

  async.some(restrictions, (restriction, callback) => {
      callback(restriction.index === internalIndex);
  }, result => {
    isAllowed = result;
  });
  return isAllowed;
}

/**
 * @param requestObject
 * @param context - user's context
 * @param restrictions - role's restrictions on indexes/collections
 * @param {Kuzzle} kuzzle
 *
 * @returns {Promise}
 */
Role.prototype.isActionAllowed = function (requestObject, context, restrictions, kuzzle) {
  var
    controllerRights,
    actionRights,
    path = [];

  // explicit actions on internalIndex must be denied if no explicit restriction on internalIndex is set:
  if (requestObject.index === internalIndex && !isInternalIndexAllowed(restrictions)) {
    return q(false);
  }

  if (this.controllers === undefined) {
    return q(false);
  }

  if (this.controllers[requestObject.controller] !== undefined) {
    controllerRights = this.controllers[requestObject.controller];
    path.push(requestObject.controller);
  }
  else if (this.controllers['*'] !== undefined) {
    controllerRights = this.controllers['*'];
    path.push('*');
  }
  else {
    return q(false);
  }

  if (controllerRights.actions === undefined) {
    return q(false);
  }

  if (controllerRights.actions[requestObject.action] !== undefined) {
    actionRights = controllerRights.actions[requestObject.action];
    path.push(requestObject.action);
  }
  else if (controllerRights.actions['*'] !== undefined) {
    actionRights = controllerRights.actions['*'];
    path.push('*');
  }
  else {
    return q(false);
  }

  if (_.isBoolean(actionRights) || _.isObject(actionRights)) {
    // the role configuration is an object with a function in attribute `test`. We assume it can be (almost) safely run
    // as it should have previously been validated during creation.

    return executeClosure.call(this, kuzzle, path, actionRights, requestObject, context)
    .then(actionRights => {
      if (! actionRights) {
        return q(false);
      }
      // the role configuration is true. We check if it matches restrictions on indexes/collections.
      return checkRestrictions(requestObject, restrictions);
    });
  }

  return q.reject(new InternalError('Invalid rights given for role ' + this._id + '(' + path.join('/') + ') : ' + actionRights));
};

/**
 * @param {Object} context
 * @returns {*}
 */
Role.prototype.validateDefinition = function (context) {
  var
    deferred = q.defer(),
    promises = [];

  if (!_.isObject(this.controllers)) {
    return q.reject(new BadRequestError('The "controllers" definition must be an object'));
  }
  if (_.isEmpty(this.controllers)) {
    return q.reject(new BadRequestError('The "controllers" definition cannot be empty'));
  }

  Object.keys(this.controllers).every(controllerKey => {
    var controllerRights = this.controllers[controllerKey];

    if (!_.isObject(controllerRights)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. Must be an object'));
      return false;
    }
    if (_.isEmpty(controllerRights)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. Cannot be empty'));
      return false;
    }
    if (controllerRights.actions === undefined) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. `actions` attribute missing'));
      return false;
    }
    if (!_.isObject(controllerRights.actions)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. `actions` attribute must be an object'));
      return false;
    }
    if (_.isEmpty(controllerRights.actions)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. `actions` attribute cannot be empty'));
      return false;
    }

    Object.keys(controllerRights.actions).every(actionKey => {
      var actionRights = controllerRights.actions[actionKey];

      if (!_.isBoolean(actionRights) && !_.isObject(actionRights)) {
        deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey, actionKey] + '. Must be a boolean or an object'));
        return false;
      }

      if (_.isObject(actionRights) && actionRights.test) {

        promises.push((function () {
          var
            sandBox = new Sandbox();

          return sandBox.run({
            sandbox: {
              requestObject: {
                index: 'index',
                collection: 'collection',
                controller: 'controller',
                action: 'action',
                data: {
                  _id: -1,
                  body: {
                    a: true
                  }
                }
              },
              context: {
                connection: {type: context.connection.type},
                token: context.token
              },
              $currentUserId: -1,
              args: {}
            },
            code: '(function (requestObject, context, $currentUserId, args) { ' + actionRights.test + '\nreturn false;\n})(requestObject, context, $currentUserId, args)'
          })
          .then(result => {
            var error;

            if (result.result !== undefined && _.isBoolean(result.result)) {
              return q(result.result);
            }

            error = new BadRequestError('Invalid definition for '+ [controllerKey, actionKey] + '. Error executing function');
            error.detail = result.err;

            return q.reject(error);
          });
        })());
      }

      return true;
    });

    return true;
  });

  if (promises.length > 0) {
    q.all(promises)
      .then(() => {
        deferred.resolve(true);
      })
      .catch(error => {
        deferred.reject(error);
      });
  }
  else {
    deferred.resolve(true);
  }

  return deferred.promise;
};

module.exports = Role;

/**
 * @param {RequestObject} the requestObject
 * @param {Array} restrictions list
 * @returns {Promise} resolves to a Boolean value
 */
function checkRestrictions(requestObject, restrictions) {
  var isAllowed = false;

  // If no restrictions, we allow the action:
  if (_.isEmpty(restrictions)) {
    return q(true);
  }

  // If the request's action does not refer to an index, restrictions are useless for this action (=> ignore them):
  if (!requestObject.index || requestObject.index === null || requestObject.index === undefined) {
    return q(true);
  }

  async.some(restrictions, (restriction, callback) => {
      callback(checkIndexRestriction(requestObject, restriction));
  }, result => {
    isAllowed = result;
  });

  return q(isAllowed);
}

/**
 * @param {RequestObject} requestObject
 * @param {Object} a restriction object on an index
 * @returns {Boolean}
 */
function checkIndexRestriction(requestObject, restriction) {
  if (restriction.index !== requestObject.index) {
    return false;
  }

  // if no collections given on the restriction, the action is allowed for all collections:
  if (_.isEmpty(restriction.collections)) {
    return true;
  }

  // If the request's action does not refer to a collcetion, the restriction is useless for this action (=> ignored):
  if (!requestObject.collection || requestObject.collection === null || requestObject.collection === undefined ) {
    return true;
  }

  return _.includes(restriction.collections, requestObject.collection);
}

/**
 * @param {Kuzzle} kuzzle
 * @param {Array} path
 * @param {Object} actionRights
 * @param {RequestObject} requestObject
 * @param {Object} context
 * @returns {Promise}
 */
function executeClosure (kuzzle, path, actionRights, requestObject, context) {
  var
    sandboxContext,
    sandboxScript,
    error,
    argsDefinitions = {},
    message;

  if (_.isBoolean(actionRights)) {
    return q(actionRights);
  }

  if(! _.isString(actionRights.test)) {
    error = new ParseError('Error parsing rights for role ' + this._id + ' (' + path.join('/') + ') :' + actionRights);
    error.details = 'Missing or malformed "test" attribute (string requised)';
    return q.reject(error);
  }

  if (this.closures[path] === undefined) {
    this.closures[path] = {};
  }

  if (actionRights.args && !_.isEmpty(actionRights.args) && !this.closures[path].getArgsDefinitions) {
    try {
      /* jshint evil: true */
      /* eslint-disable no-eval */
      this.closures[path].getArgsDefinitions = global.eval('(function (requestObject) {return ' +
        JSON
          .stringify(actionRights.args)
          .replace(/"\$(requestObject\.data\.[a-zA-Z0-9_\-.]*[a-zA-Z0-9])"/g, '$1')
          .replace('"$currentId"', 'requestObject.data._id') +
        ';})');
      /* jshint evil: false */
      /* eslint-enable no-eval */
    }
    catch (err) {
      error = new ParseError('Error parsing rights for role ' + this._id + ' (' + path.join('/') + ') :' + actionRights);
      error.details = err;

      return q.reject(error);
    }
  }

  if (this.closures[path].getArgsDefinitions) {
    argsDefinitions = this.closures[path].getArgsDefinitions(requestObject);
  }

  return buildArgsForContext.call(kuzzle, argsDefinitions)
    .then(args => {
      var sandboxContextObject = {
        $requestObject: requestObject,
        context: context,
        $currentUserId: context.token.user._id,
        args: args
      };

      sandboxContext = vm.createContext(sandboxContextObject);

      if (!this.closures[path].test) {
        try {
          sandboxScript = new vm.Script('(function ($requestObject, context, $currentUserId, args) { ' +
            actionRights.test +
            '\nreturn false;\n })($requestObject, context, $currentUserId, args)');

          this.closures[path].test = sandboxScript;
        }
        catch (err) {
          message = `Error parsing closure rights for role ${this._id} (${path.join('/')}): ${actionRights}`;

          kuzzle.pluginsManager.trigger('log:error', message);
          error = new ParseError(message);
          error.details = err;

          return q.reject(error);
        }
      }

      return this.closures[path].test.runInContext(sandboxContext);
    })
    .then(result => {
      if (! _.isBoolean(result) ) {
        message = `Error during executing rights action closure (${path.join('/')}): ${actionRights}`;

        kuzzle.pluginsManager.trigger('log:error', message);
        error = new ParseError(message);
        error.details = `Closure result is not a boolean value: ${result}`;

        return q.reject(error);
      }
      return q(result);
    })
    .catch((err) => {
      message = `Error during executing rights action closure (${path.join('/')}): ${err.message}`;

      kuzzle.pluginsManager.trigger('log:error', message);
      error = new ParseError(message);
      error.details = err;

      return q.reject(error);
    });
}

/**
 *
 * @param argsDefinitions
 * @returns {Promise}
 */
function buildArgsForContext (argsDefinitions) {
  if (!_.isEmpty(argsDefinitions)) {
    return buildClosureArgs.call(this, argsDefinitions);
  }

  return q({});
}

/**
 * @param {Object} argsDefinitions
 * @returns {Promise}
 */
function buildClosureArgs (argsDefinitions) {
  var
    deferred = q.defer(),
    argsFunctions = {};

  // Build the object that will be passed to parallel
  _.forEach(argsDefinitions, (argDefinition, argName) => {
    argsFunctions[argName] = factoryFunctionClosure.call(this, argName, argDefinition);
  });

  async.parallel(argsFunctions, (error, results) => {
    if (error) {
      // In case we have an error we want to return an empty object because the error can come from readEngine
      return deferred.resolve({});
    }

    deferred.resolve(results);
  });

  return deferred.promise;
}

/**
 * Return a function built for async.parallel with the right action on readEngine
 * @param {String} argName - the argument name set by user (i.e.: document, documents...)
 * @param {Object} argDefinition - definition set by user. Like {collection: 'messages', index: 'chat', action: { get: '$currentId' }}
 * @returns {Function} the function that will execute a get/mget/search on readEngine
 */
function factoryFunctionClosure (argName, argDefinition) {
  var methodName;

  if (!argDefinition.collection || !argDefinition.index || !argDefinition.action || _.isEmpty(argDefinition.action)) {
    this.pluginsManager.trigger('log:error', `Bad format in closure rights for ${argName}`);
    return callback => callback(null, {});
  }

  methodName = Object.keys(argDefinition.action)[0];

  if (['get', 'mget', 'search'].indexOf(methodName) === -1) {
    this.pluginsManager.trigger('log:error', `Try to use an unauthorized function (${methodName}) in closure rights check`);
    return callback => callback(null, {});
  }

  return callback => {
    var requestObject = new RequestObject({
      controller: 'read',
      action: methodName,
      collection: argDefinition.collection,
      index: argDefinition.index
    });

    if (methodName === 'mget') {
      requestObject.data = {
        body: {
          ids: argDefinition.action[methodName]
        }
      };
    }
    else if (methodName === 'search') {
      requestObject.data = {
        body: argDefinition.action[methodName]
      };
    }
    else if (methodName === 'get') {
      requestObject.data = {
        id: argDefinition.action[methodName]
      };
    }

    this.services.list.readEngine[methodName](requestObject)
      .then(response => {
        if (response.hits) {
          return callback(null, response.hits.map(document => {
            return {content: document._source, id: document._id};
          }));
        }

        callback(null, {content: response._source, id: response._id});
      })
      .catch((e) => {
        this.pluginsManager.trigger('log:error', `Error during readEngine execution for ${methodName} with ${JSON.stringify(argDefinition)}: ${e.message}`);
        return callback(null, {});
      });
  };
}
<commit_msg>small refactoring...<commit_after>var
  _ = require('lodash'),
  q = require('q'),
  async = require('async'),
  vm = require('vm'),
  BadRequestError = require('../../errors/badRequestError'),
  RequestObject = require('../requestObject'),
  InternalError = require('../../errors/internalError'),
  ParseError = require('../../errors/parseError'),
  Sandbox = require('../../sandbox'),
  internalIndex = require('rc')('kuzzle').internalIndex;

function Role () {
  this.controllers = {};
  this.closures = {};
}

function doesIndexExist(index, indexes) {
  return indexes && indexes[index] !== undefined;
}

function doesCollectionExist(index, collection, indexes) {
  return doesIndexExist(index, indexes) && _.includes(indexes[index], collection);
}

/**
 * @param requestObject
 * @param context - user's context
 * @param restrictions - role's restrictions on indexes/collections
 * @param {Kuzzle} kuzzle
 *
 * @returns {Promise}
 */
Role.prototype.isActionAllowed = function (requestObject, context, restrictions, kuzzle) {
  var
    controllerRights,
    actionRights,
    path = [];

  // explicit actions on internalIndex must be denied if no explicit restriction on internalIndex is set:
  if (requestObject.index === internalIndex && !isInternalIndexAllowed(restrictions)) {
    return q(false);
  }

  if (this.controllers === undefined) {
    return q(false);
  }

  if (this.controllers[requestObject.controller] !== undefined) {
    controllerRights = this.controllers[requestObject.controller];
    path.push(requestObject.controller);
  }
  else if (this.controllers['*'] !== undefined) {
    controllerRights = this.controllers['*'];
    path.push('*');
  }
  else {
    return q(false);
  }

  if (controllerRights.actions === undefined) {
    return q(false);
  }

  if (controllerRights.actions[requestObject.action] !== undefined) {
    actionRights = controllerRights.actions[requestObject.action];
    path.push(requestObject.action);
  }
  else if (controllerRights.actions['*'] !== undefined) {
    actionRights = controllerRights.actions['*'];
    path.push('*');
  }
  else {
    return q(false);
  }

  if (_.isBoolean(actionRights) || _.isObject(actionRights)) {
    // the role configuration is an object with a function in attribute `test`. We assume it can be (almost) safely run
    // as it should have previously been validated during creation.

    return executeClosure.call(this, kuzzle, path, actionRights, requestObject, context)
    .then(actionRights => {
      if (! actionRights) {
        return q(false);
      }
      // the role configuration is true. We check if it matches restrictions on indexes/collections.
      return checkRestrictions(requestObject, restrictions);
    });
  }

  return q.reject(new InternalError('Invalid rights given for role ' + this._id + '(' + path.join('/') + ') : ' + actionRights));
};

/**
 * @param {Object} context
 * @returns {*}
 */
Role.prototype.validateDefinition = function (context) {
  var
    deferred = q.defer(),
    promises = [];

  if (!_.isObject(this.controllers)) {
    return q.reject(new BadRequestError('The "controllers" definition must be an object'));
  }
  if (_.isEmpty(this.controllers)) {
    return q.reject(new BadRequestError('The "controllers" definition cannot be empty'));
  }

  Object.keys(this.controllers).every(controllerKey => {
    var controllerRights = this.controllers[controllerKey];

    if (!_.isObject(controllerRights)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. Must be an object'));
      return false;
    }
    if (_.isEmpty(controllerRights)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. Cannot be empty'));
      return false;
    }
    if (controllerRights.actions === undefined) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. `actions` attribute missing'));
      return false;
    }
    if (!_.isObject(controllerRights.actions)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. `actions` attribute must be an object'));
      return false;
    }
    if (_.isEmpty(controllerRights.actions)) {
      deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey] + '. `actions` attribute cannot be empty'));
      return false;
    }

    Object.keys(controllerRights.actions).every(actionKey => {
      var actionRights = controllerRights.actions[actionKey];

      if (!_.isBoolean(actionRights) && !_.isObject(actionRights)) {
        deferred.reject(new BadRequestError('Invalid definition for ' + [controllerKey, actionKey] + '. Must be a boolean or an object'));
        return false;
      }

      if (_.isObject(actionRights) && actionRights.test) {

        promises.push((function () {
          var
            sandBox = new Sandbox();

          return sandBox.run({
            sandbox: {
              requestObject: {
                index: 'index',
                collection: 'collection',
                controller: 'controller',
                action: 'action',
                data: {
                  _id: -1,
                  body: {
                    a: true
                  }
                }
              },
              context: {
                connection: {type: context.connection.type},
                token: context.token
              },
              $currentUserId: -1,
              args: {}
            },
            code: '(function (requestObject, context, $currentUserId, args) { ' + actionRights.test + '\nreturn false;\n})(requestObject, context, $currentUserId, args)'
          })
          .then(result => {
            var error;

            if (result.result !== undefined && _.isBoolean(result.result)) {
              return q(result.result);
            }

            error = new BadRequestError('Invalid definition for '+ [controllerKey, actionKey] + '. Error executing function');
            error.detail = result.err;

            return q.reject(error);
          });
        })());
      }

      return true;
    });

    return true;
  });

  if (promises.length > 0) {
    q.all(promises)
      .then(() => {
        deferred.resolve(true);
      })
      .catch(error => {
        deferred.reject(error);
      });
  }
  else {
    deferred.resolve(true);
  }

  return deferred.promise;
};

module.exports = Role;

function isInternalIndexAllowed(restrictions) {
  var
    isAllowed = false;

  async.some(restrictions, (restriction, callback) => {
      callback(restriction.index === internalIndex);
  }, result => {
    isAllowed = result;
  });
  return isAllowed;
}

/**
 * @param {RequestObject} the requestObject
 * @param {Array} restrictions list
 * @returns {Promise} resolves to a Boolean value
 */
function checkRestrictions(requestObject, restrictions) {
  var isAllowed = false;

  // If no restrictions, we allow the action:
  if (_.isEmpty(restrictions)) {
    return q(true);
  }

  // If the request's action does not refer to an index, restrictions are useless for this action (=> ignore them):
  if (!requestObject.index || requestObject.index === null || requestObject.index === undefined) {
    return q(true);
  }

  async.some(restrictions, (restriction, callback) => {
      callback(checkIndexRestriction(requestObject, restriction));
  }, result => {
    isAllowed = result;
  });

  return q(isAllowed);
}

/**
 * @param {RequestObject} requestObject
 * @param {Object} a restriction object on an index
 * @returns {Boolean}
 */
function checkIndexRestriction(requestObject, restriction) {
  if (restriction.index !== requestObject.index) {
    return false;
  }

  // if no collections given on the restriction, the action is allowed for all collections:
  if (_.isEmpty(restriction.collections)) {
    return true;
  }

  // If the request's action does not refer to a collcetion, the restriction is useless for this action (=> ignored):
  if (!requestObject.collection || requestObject.collection === null || requestObject.collection === undefined ) {
    return true;
  }

  return _.includes(restriction.collections, requestObject.collection);
}

/**
 * @param {Kuzzle} kuzzle
 * @param {Array} path
 * @param {Object} actionRights
 * @param {RequestObject} requestObject
 * @param {Object} context
 * @returns {Promise}
 */
function executeClosure (kuzzle, path, actionRights, requestObject, context) {
  var
    sandboxContext,
    sandboxScript,
    error,
    argsDefinitions = {},
    message;

  if (_.isBoolean(actionRights)) {
    return q(actionRights);
  }

  if(! _.isString(actionRights.test)) {
    error = new ParseError('Error parsing rights for role ' + this._id + ' (' + path.join('/') + ') :' + actionRights);
    error.details = 'Missing or malformed "test" attribute (string requised)';
    return q.reject(error);
  }

  if (this.closures[path] === undefined) {
    this.closures[path] = {};
  }

  if (actionRights.args && !_.isEmpty(actionRights.args) && !this.closures[path].getArgsDefinitions) {
    try {
      /* jshint evil: true */
      /* eslint-disable no-eval */
      this.closures[path].getArgsDefinitions = global.eval('(function (requestObject) {return ' +
        JSON
          .stringify(actionRights.args)
          .replace(/"\$(requestObject\.data\.[a-zA-Z0-9_\-.]*[a-zA-Z0-9])"/g, '$1')
          .replace('"$currentId"', 'requestObject.data._id') +
        ';})');
      /* jshint evil: false */
      /* eslint-enable no-eval */
    }
    catch (err) {
      error = new ParseError('Error parsing rights for role ' + this._id + ' (' + path.join('/') + ') :' + actionRights);
      error.details = err;

      return q.reject(error);
    }
  }

  if (this.closures[path].getArgsDefinitions) {
    argsDefinitions = this.closures[path].getArgsDefinitions(requestObject);
  }

  return buildArgsForContext.call(kuzzle, argsDefinitions)
    .then(args => {
      var sandboxContextObject = {
        $requestObject: requestObject,
        context: context,
        $currentUserId: context.token.user._id,
        args: args
      };

      sandboxContext = vm.createContext(sandboxContextObject);

      if (!this.closures[path].test) {
        try {
          sandboxScript = new vm.Script('(function ($requestObject, context, $currentUserId, args) { ' +
            actionRights.test +
            '\nreturn false;\n })($requestObject, context, $currentUserId, args)');

          this.closures[path].test = sandboxScript;
        }
        catch (err) {
          message = `Error parsing closure rights for role ${this._id} (${path.join('/')}): ${actionRights}`;

          kuzzle.pluginsManager.trigger('log:error', message);
          error = new ParseError(message);
          error.details = err;

          return q.reject(error);
        }
      }

      return this.closures[path].test.runInContext(sandboxContext);
    })
    .then(result => {
      if (! _.isBoolean(result) ) {
        message = `Error during executing rights action closure (${path.join('/')}): ${actionRights}`;

        kuzzle.pluginsManager.trigger('log:error', message);
        error = new ParseError(message);
        error.details = `Closure result is not a boolean value: ${result}`;

        return q.reject(error);
      }
      return q(result);
    })
    .catch((err) => {
      message = `Error during executing rights action closure (${path.join('/')}): ${err.message}`;

      kuzzle.pluginsManager.trigger('log:error', message);
      error = new ParseError(message);
      error.details = err;

      return q.reject(error);
    });
}

/**
 *
 * @param argsDefinitions
 * @returns {Promise}
 */
function buildArgsForContext (argsDefinitions) {
  if (!_.isEmpty(argsDefinitions)) {
    return buildClosureArgs.call(this, argsDefinitions);
  }

  return q({});
}

/**
 * @param {Object} argsDefinitions
 * @returns {Promise}
 */
function buildClosureArgs (argsDefinitions) {
  var
    deferred = q.defer(),
    argsFunctions = {};

  // Build the object that will be passed to parallel
  _.forEach(argsDefinitions, (argDefinition, argName) => {
    argsFunctions[argName] = factoryFunctionClosure.call(this, argName, argDefinition);
  });

  async.parallel(argsFunctions, (error, results) => {
    if (error) {
      // In case we have an error we want to return an empty object because the error can come from readEngine
      return deferred.resolve({});
    }

    deferred.resolve(results);
  });

  return deferred.promise;
}

/**
 * Return a function built for async.parallel with the right action on readEngine
 * @param {String} argName - the argument name set by user (i.e.: document, documents...)
 * @param {Object} argDefinition - definition set by user. Like {collection: 'messages', index: 'chat', action: { get: '$currentId' }}
 * @returns {Function} the function that will execute a get/mget/search on readEngine
 */
function factoryFunctionClosure (argName, argDefinition) {
  var methodName;

  if (!argDefinition.collection || !argDefinition.index || !argDefinition.action || _.isEmpty(argDefinition.action)) {
    this.pluginsManager.trigger('log:error', `Bad format in closure rights for ${argName}`);
    return callback => callback(null, {});
  }

  methodName = Object.keys(argDefinition.action)[0];

  if (['get', 'mget', 'search'].indexOf(methodName) === -1) {
    this.pluginsManager.trigger('log:error', `Try to use an unauthorized function (${methodName}) in closure rights check`);
    return callback => callback(null, {});
  }

  return callback => {
    var requestObject = new RequestObject({
      controller: 'read',
      action: methodName,
      collection: argDefinition.collection,
      index: argDefinition.index
    });

    if (methodName === 'mget') {
      requestObject.data = {
        body: {
          ids: argDefinition.action[methodName]
        }
      };
    }
    else if (methodName === 'search') {
      requestObject.data = {
        body: argDefinition.action[methodName]
      };
    }
    else if (methodName === 'get') {
      requestObject.data = {
        id: argDefinition.action[methodName]
      };
    }

    this.services.list.readEngine[methodName](requestObject)
      .then(response => {
        if (response.hits) {
          return callback(null, response.hits.map(document => {
            return {content: document._source, id: document._id};
          }));
        }

        callback(null, {content: response._source, id: response._id});
      })
      .catch((e) => {
        this.pluginsManager.trigger('log:error', `Error during readEngine execution for ${methodName} with ${JSON.stringify(argDefinition)}: ${e.message}`);
        return callback(null, {});
      });
  };
}
<|endoftext|>


<commit_before>function Request(req){
    this.__request__ = req;
}

const requestPrototype = {
    get method () {
        return this.__request__.method.toUpperCase();
    },

    get protocol () {
        return this.__request__.connection.encrypted? 'https' : 'http';
    },

    get host () {
        return this.__request__.headers.host.toLowerCase();
    },

    get path () {
        return this.__request__.url.replace(/^\/|\/$/g, '').toLowerCase();
    },

    get url () {
        return `${this.protocol}://${this.host}/${this.path}`;
    },

    get headers () {
        return this.__request__.headers;
    },

    get ip (){
        return this.__request__.headers['x-forwarded-for']
            || this.__request__.connection.remoteAddress
            || this.__request__.socket.remoteAddress
            || this.__request__.connection.socket.remoteAddress;
    },

    cookies: {},

    body: {},

    session: null

};

Object.getOwnPropertyNames(requestPrototype).forEach(function(propertyName){
    Object.defineProperty(Request.prototype, propertyName, Object.getOwnPropertyDescriptor(requestPrototype, propertyName));
});

/*** Request interceptors ***/
const interceptorsSet = new Set();

Request.addInterceptor = function (interceptorFunction){
    interceptorsSet.add(interceptorFunction);
};

Request.getInterceptors = function (){
    return interceptorsSet;
};

module.exports = Request;<commit_msg>Fix normalizing url<commit_after>const url                       = require('url');

function Request(req){
    this.__request__ = req;
}

const requestPrototype = {
    get method () {
        return this.__request__.method.toUpperCase();
    },

    get protocol () {
        return this.__request__.connection.encrypted? 'https' : 'http';
    },

    get host () {
        return this.__request__.headers.host.toLowerCase();
    },

    get path () {
        const requestUrl = url.parse(this.__request__.url);
        return (requestUrl.pathname.replace(/^\/|\/$/g, '') + requestUrl.search).toLowerCase();
    },

    get url () {
        return `${this.protocol}://${this.host}/${this.path}`;
    },

    get headers () {
        return this.__request__.headers;
    },

    get ip (){
        return this.__request__.headers['x-forwarded-for']
            || this.__request__.connection.remoteAddress
            || this.__request__.socket.remoteAddress
            || this.__request__.connection.socket.remoteAddress;
    },

    cookies: {},

    body: {},

    session: null

};

Object.getOwnPropertyNames(requestPrototype).forEach(function(propertyName){
    Object.defineProperty(Request.prototype, propertyName, Object.getOwnPropertyDescriptor(requestPrototype, propertyName));
});

/*** Request interceptors ***/
const interceptorsSet = new Set();

Request.addInterceptor = function (interceptorFunction){
    interceptorsSet.add(interceptorFunction);
};

Request.getInterceptors = function (){
    return interceptorsSet;
};

module.exports = Request;<|endoftext|>


<commit_before>var readJsonLocation = "/reads/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd;
var referenceStringLocation = "/reference/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd;
var refContainer = d3.select("#area1")
    .append("svg")
    .attr("width", width)
    .attr("height", 50);

d3.json(referenceStringLocation, function(error, data) {
    refContainer.selectAll("rect").data(data)
    .enter()
        .append("g")
        .append("rect")
            .attr("x", function(d, i) {
                return i/(readRegEnd-readRegStart) * width;
            })
            .attr("y", 30)
            .attr("fill", function(d, i) {
                if (d.reference === "G") {
                    return '#296629'; //DARK GREEN
                } else if (d.reference === "C") {
                    return '#CC2900'; //RED
                } else if (d.reference === "A") {
                    return '#0066FF'; //BLUE
                } else {
                    return '#FF6600'; //ORANGE
                }
            })
            .attr("width", function(d) {
                return Math.max(1, width/(readRegEnd-readRegStart));
            })
            .attr("height", 10)
            .on("mouseover", function(d) {
                div.transition()
                    .duration(200)
                    .style("opacity", .9);
                div.html(d.reference)
                    .style("left", (d3.event.pageX - 10) + "px")
                    .style("top", (d3.event.pageY - 30) + "px");
            })
});

var svgContainer = d3.select("body")
    .append("svg")
    .attr("height", (height+base))
    .attr("width", width);

d3.select("h2")
    .append("span")
    .text(readRegStart + "-" + readRegEnd);

d3.json(readJsonLocation,function(error, data) {
    data.forEach(function(d) {
        d.readName = d.readName;
        d.start = +d.start;
        d.end = +d.end;
        d.track = +d.track;
    });

    // Add the rectangles
    svgContainer.selectAll("rect").data(data)
        .enter()
            .append("g")
            .append("rect")
                .attr("x", (function(d) { return (d.start-readRegStart)/(readRegEnd-readRegStart) * width; }))
                .attr("y", (function(d) { return height - trackHeight * (d.track+1); }))
                .attr("width", (function(d) { return Math.max(1,(d.end-d.start)*(width/(readRegEnd-readRegStart))); }))
                .attr("height", (trackHeight-2))
                .attr("fill", "steelblue")
                .on("mouseover", function(d) {
                    div.transition()
                    .duration(200)
                    .style("opacity", .9);
                    div .html(d.readName)
                    .style("left", (d3.event.pageX) + "px")
                    .style("top", (d3.event.pageY - 28) + "px");
                })
                .on("mouseout", function(d) {
                    div.transition()
                    .duration(500)
                    .style("opacity", 0);
                });
});

// Create the scale for the axis
var axisScale = d3.scale.linear()
    .domain([readRegStart, readRegEnd])
    .range([0, width]);

// Create the axis
var xAxis = d3.svg.axis()
   .scale(axisScale)
   .ticks(5);

// Add the axis to the container
svgContainer.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(0, " + height + ")")
    .call(xAxis);

// Try to move very far left
function moveVeryFarLeft() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart));
    var newEnd = Math.max(newStart, readRegEnd - (readRegEnd-readRegStart));
    update(newStart, newEnd);
}

// Try to move far left
function moveFarLeft() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart)/2);
    var newEnd = Math.max(newStart, readRegEnd - (readRegEnd-readRegStart)/2);
    update(newStart, newEnd);
}

// Try to move left
function moveLeft() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart)/4);
    var newEnd = Math.max(newStart, readRegEnd - (readRegEnd-readRegStart)/4);
    update(newStart, newEnd);
}

 // Try to move right
 function moveRight() {
     var newStart = readRegStart + (readRegEnd-readRegStart)/4;
     var newEnd = readRegEnd + (readRegEnd-readRegStart)/4;
     update(newStart, newEnd);
 }

// Try to move far right
function moveFarRight() {
    var newStart = readRegStart + (readRegEnd-readRegStart)/2;
    var newEnd = readRegEnd + (readRegEnd-readRegStart)/2;
    update(newStart, newEnd);
}

// Try to move very far right
function moveVeryFarRight() {
    var newStart = readRegStart + (readRegEnd-readRegStart);
    var newEnd = readRegEnd + (readRegEnd-readRegStart);
    update(newStart, newEnd);
}

// Try to zoom in
function zoomIn() {
    var newStart = readRegStart + (readRegEnd-readRegStart)/4;
    var newEnd = readRegEnd - (readRegEnd-readRegStart)/4;
    update(newStart, newEnd);
}

// Try to zoom out
function zoomOut() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart)/2);
    var newEnd = readRegEnd - (readRegEnd-readRegStart)/2;
    update(newStart, newEnd);
}

// Redirect based on form input
function checkForm(form) {
    var newStart = Math.max(0, form.start.value);
    var newEnd = Math.max(newStart, form.end.value);
    form.reset();
    update(newStart, newEnd);
}

function update(newStart, newEnd) {
    readRegStart = newStart;
    readRegEnd = newEnd;
    readJsonLocation = ("/reads/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd);
    var numTracks = 0;
    var referenceStringLocation = "/reference/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd;

    //Updating Reference
    var refContainer = d3.select("#area1")
        .append("svg")
        .attr("width", width)
        .attr("height", 50);

    d3.json(referenceStringLocation, function(error, data) {
        refContainer.selectAll("rect").data(data)
        .enter()
            .append("g")
            .append("rect")
                .attr("x", function(d, i) {
                    return i/(readRegEnd-readRegStart) * width;
                })
                .attr("y", 30)
                .attr("fill", function(d, i) {
                    if (d.reference === "G") {
                        return '#296629'; //DARK GREEN
                    } else if (d.reference === "C") {
                        return '#CC2900'; //RED
                    } else if (d.reference === "A") {
                        return '#0066FF'; //BLUE
                    } else {
                        return '#FF6600'; //ORANGE
                    }
                })
                .attr("width", function(d) {
                    return Math.max(1, width/(readRegEnd-readRegStart));
                })
                .attr("height", 10)
                .on("mouseover", function(d) {
                    div.transition()
                        .duration(200)
                        .style("opacity", .9);
                    div.html(d.reference)
                        .style("left", (d3.event.pageX - 10) + "px")
                        .style("top", (d3.event.pageY - 30) + "px");
                });
    });

    //Updating
    d3.json(readJsonLocation, function(error, data) {
        data.forEach(function(d) {
            d.readName = d.readName;
            d.start = +d.start;
            d.end = +d.end;
            if (d.track > numTracks) { numTracks = d.track; }
        });

        d3.select("h2")
          .select("span")
          .text(readRegStart + "-" + readRegEnd);

        height = (numTracks+1) * trackHeight;

        // Change dimensions of the SVG container
        var svgContainer = d3.select("svg")
            .attr("height", (height+base));

        // Remove old content
        svgContainer.selectAll("g").remove();

        // Add the rectangles
    svgContainer.selectAll("rect").data(data)
        .enter()
            .append("g")
            .append("rect")
                .attr("x", (function(d) { return (d.start-readRegStart)/(readRegEnd-readRegStart) * width; }))
                .attr("y", (function(d) { return height - trackHeight * (d.track+1); }))
                .attr("width", (function(d) { return Math.max(1,(d.end-d.start)*(width/(readRegEnd-readRegStart))); }))
                .attr("height", (trackHeight-2))
                .attr("fill", "steelblue")
                .on("mouseover", function(d) {
                    div.transition()
                    .duration(200)
                    .style("opacity", .9);
                    div .html(d.readName)
                    .style("left", (d3.event.pageX) + "px")
                    .style("top", (d3.event.pageY - 28) + "px");
                })
                .on("mouseout", function(d) {
                    div.transition()
                    .duration(500)
                    .style("opacity", 0);
                });

        // Recreate the scale for the axis
        var axisScale = d3.scale.linear()
            .domain([readRegStart, readRegEnd])
            .range([0, width]);

        // Recreate the axis
        var xAxis = d3.svg.axis()
           .scale(axisScale)
           .ticks(5);

        // Add the axis to the container
        svgContainer.append("g")
            .attr("class", "axis")
            .attr("transform", "translate(0, " + height + ")")
            .call(xAxis);
    });
}

// // Hover box for reads
var div = d3.select("body")
    .append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);<commit_msg>reference successfully updates<commit_after>var readJsonLocation = "/reads/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd;
var referenceStringLocation = "/reference/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd;
var refContainer = d3.select("#area1")
    .append("svg")
    .attr("width", width)
    .attr("height", 50);

d3.json(referenceStringLocation, function(error, data) {
    refContainer.selectAll("rect").data(data)
    .enter()
        .append("g")
        .append("rect")
            .attr("x", function(d, i) {
                return i/(readRegEnd-readRegStart) * width;
            })
            .attr("y", 30)
            .attr("fill", function(d, i) {
                if (d.reference === "G") {
                    return '#296629'; //DARK GREEN
                } else if (d.reference === "C") {
                    return '#CC2900'; //RED
                } else if (d.reference === "A") {
                    return '#0066FF'; //BLUE
                } else {
                    return '#FF6600'; //ORANGE
                }
            })
            .attr("width", function(d) {
                return Math.max(1, width/(readRegEnd-readRegStart));
            })
            .attr("height", 10)
            .on("mouseover", function(d) {
                div.transition()
                    .duration(200)
                    .style("opacity", .9);
                div.html(d.reference)
                    .style("left", (d3.event.pageX - 10) + "px")
                    .style("top", (d3.event.pageY - 30) + "px");
            })
});

var svgContainer = d3.select("body")
    .append("svg")
    .attr("height", (height+base))
    .attr("width", width);

d3.select("h2")
    .append("span")
    .text(readRegStart + "-" + readRegEnd);

d3.json(readJsonLocation,function(error, data) {
    data.forEach(function(d) {
        d.readName = d.readName;
        d.start = +d.start;
        d.end = +d.end;
        d.track = +d.track;
    });

    // Add the rectangles
    svgContainer.selectAll("rect").data(data)
        .enter()
            .append("g")
            .append("rect")
                .attr("x", (function(d) { return (d.start-readRegStart)/(readRegEnd-readRegStart) * width; }))
                .attr("y", (function(d) { return height - trackHeight * (d.track+1); }))
                .attr("width", (function(d) { return Math.max(1,(d.end-d.start)*(width/(readRegEnd-readRegStart))); }))
                .attr("height", (trackHeight-2))
                .attr("fill", "steelblue")
                .on("mouseover", function(d) {
                    div.transition()
                    .duration(200)
                    .style("opacity", .9);
                    div .html(d.readName)
                    .style("left", (d3.event.pageX) + "px")
                    .style("top", (d3.event.pageY - 28) + "px");
                })
                .on("mouseout", function(d) {
                    div.transition()
                    .duration(500)
                    .style("opacity", 0);
                });
});

// Create the scale for the axis
var axisScale = d3.scale.linear()
    .domain([readRegStart, readRegEnd])
    .range([0, width]);

// Create the axis
var xAxis = d3.svg.axis()
   .scale(axisScale)
   .ticks(5);

// Add the axis to the container
svgContainer.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(0, " + height + ")")
    .call(xAxis);

// Try to move very far left
function moveVeryFarLeft() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart));
    var newEnd = Math.max(newStart, readRegEnd - (readRegEnd-readRegStart));
    update(newStart, newEnd);
}

// Try to move far left
function moveFarLeft() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart)/2);
    var newEnd = Math.max(newStart, readRegEnd - (readRegEnd-readRegStart)/2);
    update(newStart, newEnd);
}

// Try to move left
function moveLeft() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart)/4);
    var newEnd = Math.max(newStart, readRegEnd - (readRegEnd-readRegStart)/4);
    update(newStart, newEnd);
}

 // Try to move right
 function moveRight() {
     var newStart = readRegStart + (readRegEnd-readRegStart)/4;
     var newEnd = readRegEnd + (readRegEnd-readRegStart)/4;
     update(newStart, newEnd);
 }

// Try to move far right
function moveFarRight() {
    var newStart = readRegStart + (readRegEnd-readRegStart)/2;
    var newEnd = readRegEnd + (readRegEnd-readRegStart)/2;
    update(newStart, newEnd);
}

// Try to move very far right
function moveVeryFarRight() {
    var newStart = readRegStart + (readRegEnd-readRegStart);
    var newEnd = readRegEnd + (readRegEnd-readRegStart);
    update(newStart, newEnd);
}

// Try to zoom in
function zoomIn() {
    var newStart = readRegStart + (readRegEnd-readRegStart)/4;
    var newEnd = readRegEnd - (readRegEnd-readRegStart)/4;
    update(newStart, newEnd);
}

// Try to zoom out
function zoomOut() {
    var newStart = Math.max(0, readRegStart - (readRegEnd-readRegStart)/2);
    var newEnd = readRegEnd - (readRegEnd-readRegStart)/2;
    update(newStart, newEnd);
}

// Redirect based on form input
function checkForm(form) {
    var newStart = Math.max(0, form.start.value);
    var newEnd = Math.max(newStart, form.end.value);
    form.reset();
    update(newStart, newEnd);
}

function update(newStart, newEnd) {
    readRegStart = newStart;
    readRegEnd = newEnd;
    readJsonLocation = ("/reads/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd);
    var numTracks = 0;
    var referenceStringLocation = "/reference/" + readRefName + "?start=" + readRegStart + "&end=" + readRegEnd;

    refContainer.selectAll("g").remove();

    d3.json(referenceStringLocation, function(error, data) {
        refContainer.selectAll("rect").data(data)
        .enter()
            .append("g")
            .append("rect")
                .attr("x", function(d, i) {
                    return i/(readRegEnd-readRegStart) * width;
                })
                .attr("y", 30)
                .attr("fill", function(d, i) {
                    if (d.reference === "G") {
                        return '#296629'; //DARK GREEN
                    } else if (d.reference === "C") {
                        return '#CC2900'; //RED
                    } else if (d.reference === "A") {
                        return '#0066FF'; //BLUE
                    } else {
                        return '#FF6600'; //ORANGE
                    }
                })
                .attr("width", function(d) {
                    return Math.max(1, width/(readRegEnd-readRegStart));
                })
                .attr("height", 10)
                .on("mouseover", function(d) {
                    div.transition()
                        .duration(200)
                        .style("opacity", .9);
                    div.html(d.reference)
                        .style("left", (d3.event.pageX - 10) + "px")
                        .style("top", (d3.event.pageY - 30) + "px");
                });
    });

    //Updating
    d3.json(readJsonLocation, function(error, data) {
        data.forEach(function(d) {
            d.readName = d.readName;
            d.start = +d.start;
            d.end = +d.end;
            if (d.track > numTracks) { numTracks = d.track; }
        });

        d3.select("h2")
          .select("span")
          .text(readRegStart + "-" + readRegEnd);

        height = (numTracks+1) * trackHeight;

        // Change dimensions of the SVG container
        svgContainer.attr("height", (height+base));

        // Remove old content
        svgContainer.selectAll("g").remove();

        // Add the rectangles
        svgContainer.selectAll("rect").data(data)
            .enter()
                .append("g")
                .append("rect")
                    .attr("x", (function(d) { return (d.start-readRegStart)/(readRegEnd-readRegStart) * width; }))
                    .attr("y", (function(d) { return height - trackHeight * (d.track+1); }))
                    .attr("width", (function(d) { return Math.max(1,(d.end-d.start)*(width/(readRegEnd-readRegStart))); }))
                    .attr("height", (trackHeight-2))
                    .attr("fill", "steelblue")
                    .on("mouseover", function(d) {
                        div.transition()
                        .duration(200)
                        .style("opacity", .9);
                        div .html(d.readName)
                        .style("left", (d3.event.pageX) + "px")
                        .style("top", (d3.event.pageY - 28) + "px");
                    })
                    .on("mouseout", function(d) {
                        div.transition()
                        .duration(500)
                        .style("opacity", 0);
                    });

        // Recreate the scale for the axis
        var axisScale = d3.scale.linear()
            .domain([readRegStart, readRegEnd])
            .range([0, width]);

        // Recreate the axis
        var xAxis = d3.svg.axis()
           .scale(axisScale)
           .ticks(5);

        // Add the axis to the container
        svgContainer.append("g")
            .attr("class", "axis")
            .attr("transform", "translate(0, " + height + ")")
            .call(xAxis);
    });
}

// // Hover box for reads
var div = d3.select("body")
    .append("div")
    .attr("class", "tooltip")
    .style("opacity", 0);<|endoftext|>


<commit_before>
/*** MAIN FUNCTION ***/
function camxes_postprocessing(parse_tree) {
    /* Pruning morphology nodes. */
    parse_tree = remove_morphology(parse_tree);
    /* Removing every nodes except for those in the following whitelist. */
    var wanted_nodes = ["dot_star", "sentence", "selbri", "sumti", "prenex"];
    parse_tree = simplify_parse_tree(parse_tree, wanted_nodes);
    /* Building and retreiving the marking game string. */
    return marking_game_format(parse_tree);
}

function simplify_parse_tree(pt, nl) {
    if (is_string(pt)) return pt;
    if (!is_array(pt)) throw "ERROR";
    if (pt.length == 0) return null;
    var no_label = is_array(pt[0]);
    var i = no_label ? 0 : 1;
    while (i < pt.length) {
        if (is_array(pt[i])) {
            var v = simplify_parse_tree(pt[i], nl);
            pt = pt.slice(0, i).concat(v, pt.slice(i + 1));
            if (v == []) i--;
        }
        i++;
    }
    if (no_label) return pt;
    else if (among(pt[0], nl)) return [pt];
    else if (pt.length == 1) return [];
    else return pt.slice(1);
}

function marking_game_format(pt) {
    var s = ""  // Output string
    var i = 0;  // String index
    var b = ""; // Bracket pair
    while (i < pt.length) {
        if (is_string(pt[i])) {
            if (i == 0) {
                b = bracket_from_nodename(pt[i]);
            } else {
                if (s != "") s += " ";
                s += pt[i];
            }
        } else if (is_array(pt[i])) {
            if (s != "") s += " ";
            s += marking_game_format(pt[i]);
        }
        i++;
    }
    if (b.length >= 2)
        s = b[0] + s + b[1];
    return s;
}

function bracket_from_nodename(nodename) {
    switch (nodename) {
        case "prenex":   return "⟦⟧";
        case "sentence": return "{}";
        case "sumti":    return "[]";
        case "selbri":   return "<>";
        default:         return "";
    }
}

// ====== MORPHOLOGY REMOVAL ====== //

/*
 * remove_morphology(parse_tree)
 *
 * This function takes a parse tree, and joins the expressions of the following
 * nodes:
 * "cmevla", "gismu_2", "lujvo", "fuhivla", "spaces"
 * as well as any selmaho node (e.g. "KOhA").
 *
 * (This is essentially a copy of process_parse_tree.js.)
 */

function remove_morphology(pt) {
    if (pt.length < 1) return [];
    var i;
    /* Sometimes nodes have no label and have instead an array as their first
       element. */
    if (is_array(pt[0])) i = 0;
    else { // The first element is a label (node name).
        // Let's check if this node is a candidate for our pruning.
        if (is_target_node(pt)) {
            /* We join recursively all the terminal elements (letters) in this
             * node and its child nodes, and put the resulting string in the #1
             * slot of the array; afterwards we delete all the remaining elements
             * (their terminal values have been concatenated into pt[1]). */
            pt[1] = join_expr(pt);
            // If pt[1] contains an empty string, let's delete it as well:
            pt.splice((pt[1] == "") ? 1 : 2);
            return pt;
        }
        i = 1;
    }
    /* If we've reached here, then this node is not a target for pruning, so let's
       do recursion into its child nodes. */
    while (i < pt.length) {
        remove_morphology(pt[i]);
        i++;
    }
    return pt;
}

/* Checks whether the argument node is a target for pruning. */
function is_target_node(n) {
    return (among(n[0], ["cmevla", "gismu", "lujvo", "fuhivla", "initial_spaces", "ga_clause", "gu_clause"])
            || is_selmaho(n[0]));
}

/* This function returns the string resulting from the recursive concatenation of
 * all the leaf elements of the parse tree argument (except node names). */
function join_expr(n) {
    if (n.length < 1) return "";
    var s = "";
    var i = is_array(n[0]) ? 0 : 1;
    while (i < n.length) {
        s += is_string(n[i]) ? n[i] : join_expr(n[i]);
        i++;
    }
    return s;
}

function among(v, s) {
    var i = 0;
    while (i < s.length) if (s[i++] == v) return true;
    return false;
}

function is_selmaho(v) {
    if (!is_string(v)) return false;
    return (0 == v.search(/^[IUBCDFGJKLMNPRSTVXZ]?([AEIOUY]|(AI|EI|OI|AU))(h([AEIOUY]|(AI|EI|OI|AU)))*$/g));
}

/* ================== */
/* ===  Routines  === */
/* ================== */

function prettify_brackets(str) {
	var open_brackets = ["(", "[", "{", "<"];
	var close_brackets = [")", "]", "}", ">"];
	var brackets_number = 4;
//	var numset = ['0','1','2','3','4','5','6','7','8','9'];
	var numset = ['\u2070','\u00b9','\u00b2','\u00b3','\u2074',
	              '\u2075','\u2076','\u2077','\u2078','\u2079'];
	var i = 0;
	var floor = 0;
	while (i < str.length) {
		if (str[i] == '[') {
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, open_brackets[n] + num);
			floor++;
		} else if (str[i] == ']') {
			floor--;
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, num + close_brackets[n]);
		}
		i++;
	}
	return str;
}

function str_print_uint(val, charset) {
	// 'charset' must be a character array.
	var radix = charset.length;
	var str = "";
	val -= val % 1;  // No float allowed
	while (val >= 1) {
		str = charset[val % radix] + str;
		val /= radix;
		val -= val % 1;
	}
	return str;
}

function str_replace(str, pos, len, sub) {
	if (pos < str.length) {
		if (pos + len >= str.length) len -= pos + len - str.length;
		return str.substring(0, pos) + sub + str.substring(pos + len);
	} else return str;
}

function is_string(v) {
    return $.type(v) === "string";
}

function is_array(v) {
    return $.type(v) === "array";
}

if (typeof module !== 'undefined')
    module.exports.postprocessing = camxes_postprocessing;

<commit_msg>marking_game_postproc.js: Making is_string and is_array not dependent on jQuery; adding 'text' to the node whitelist; making marking_game_format() not add a space at the end of each node's string.<commit_after>
/*** MAIN FUNCTION ***/
function camxes_postprocessing(parse_tree) {
    /* Pruning morphology nodes. */
    parse_tree = remove_morphology(parse_tree);
    /* Removing every nodes except for those in the following whitelist. */
    var wanted_nodes = ["text", "dot_star", "sentence", "selbri", "sumti", "prenex"];
    // We included "text" so the outermost array also begins with a node name.
    parse_tree = simplify_parse_tree(parse_tree, wanted_nodes);
    /* Building and retreiving the marking game string. */
    return marking_game_format(parse_tree);
}

function simplify_parse_tree(pt, nl) {
    if (is_string(pt)) return pt;
    if (!is_array(pt)) throw "ERROR";
    if (pt.length == 0) return null;
    var no_label = is_array(pt[0]);
    var i = no_label ? 0 : 1;
    while (i < pt.length) {
        if (is_array(pt[i])) {
            var v = simplify_parse_tree(pt[i], nl);
            pt = pt.slice(0, i).concat(v, pt.slice(i + 1));
            if (v == []) i--;
        }
        i++;
    }
    if (no_label) return pt;
    else if (among(pt[0], nl)) return [pt];
    else if (pt.length == 1) return [];
    else return pt.slice(1);
}

function marking_game_format(pt) {
    var s = ""  // Output string
    var i = 0;  // String index
    var b = ""; // Bracket pair
    while (i < pt.length) {
        if (is_string(pt[i])) {
            if (i == 0) {
                b = bracket_from_nodename(pt[i]);
            } else {
                if (s != "") s += " ";
                s += pt[i];
            }
        } else if (is_array(pt[i])) {
            if (s != "") s += " ";
            s += marking_game_format(pt[i]);
        }
        i++;
    }
    if (b.length >= 2)
        s = b[0] + s + b[1];
    if (s.length > 0 && s[s.length - 1] == ' ')
        s = s.substring(0, s.length - 1);
    return s;
}

function bracket_from_nodename(nodename) {
    switch (nodename) {
        case "prenex":   return "⟦⟧";
        case "sentence": return "{}";
        case "sumti":    return "[]";
        case "selbri":   return "<>";
        default:         return "";
    }
}

// ====== MORPHOLOGY REMOVAL ====== //

/*
 * remove_morphology(parse_tree)
 *
 * This function takes a parse tree, and joins the expressions of the following
 * nodes:
 * "cmevla", "gismu_2", "lujvo", "fuhivla", "spaces"
 * as well as any selmaho node (e.g. "KOhA").
 *
 * (This is essentially a copy of process_parse_tree.js.)
 */

function remove_morphology(pt) {
    if (pt.length < 1) return [];
    var i;
    /* Sometimes nodes have no label and have instead an array as their first
       element. */
    if (is_array(pt[0])) i = 0;
    else { // The first element is a label (node name).
        // Let's check if this node is a candidate for our pruning.
        if (is_target_node(pt)) {
            /* We join recursively all the terminal elements (letters) in this
             * node and its child nodes, and put the resulting string in the #1
             * slot of the array; afterwards we delete all the remaining elements
             * (their terminal values have been concatenated into pt[1]). */
            pt[1] = join_expr(pt);
            // If pt[1] contains an empty string, let's delete it as well:
            pt.splice((pt[1] == "") ? 1 : 2);
            return pt;
        }
        i = 1;
    }
    /* If we've reached here, then this node is not a target for pruning, so let's
       do recursion into its child nodes. */
    while (i < pt.length) {
        remove_morphology(pt[i]);
        i++;
    }
    return pt;
}

/* Checks whether the argument node is a target for pruning. */
function is_target_node(n) {
    return (among(n[0], ["cmevla", "gismu", "lujvo", "fuhivla", "initial_spaces", "ga_clause", "gu_clause"])
            || is_selmaho(n[0]));
}

/* This function returns the string resulting from the recursive concatenation of
 * all the leaf elements of the parse tree argument (except node names). */
function join_expr(n) {
    if (n.length < 1) return "";
    var s = "";
    var i = is_array(n[0]) ? 0 : 1;
    while (i < n.length) {
        s += is_string(n[i]) ? n[i] : join_expr(n[i]);
        i++;
    }
    return s;
}

function among(v, s) {
    var i = 0;
    while (i < s.length) if (s[i++] == v) return true;
    return false;
}

function is_selmaho(v) {
    if (!is_string(v)) return false;
    return (0 == v.search(/^[IUBCDFGJKLMNPRSTVXZ]?([AEIOUY]|(AI|EI|OI|AU))(h([AEIOUY]|(AI|EI|OI|AU)))*$/g));
}

/* ================== */
/* ===  Routines  === */
/* ================== */

function prettify_brackets(str) {
	var open_brackets = ["(", "[", "{", "<"];
	var close_brackets = [")", "]", "}", ">"];
	var brackets_number = 4;
//	var numset = ['0','1','2','3','4','5','6','7','8','9'];
	var numset = ['\u2070','\u00b9','\u00b2','\u00b3','\u2074',
	              '\u2075','\u2076','\u2077','\u2078','\u2079'];
	var i = 0;
	var floor = 0;
	while (i < str.length) {
		if (str[i] == '[') {
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, open_brackets[n] + num);
			floor++;
		} else if (str[i] == ']') {
			floor--;
			var n = floor % brackets_number;
			var num = (floor && !n) ?
				str_print_uint(floor / brackets_number, numset) : "";
			str = str_replace(str, i, 1, num + close_brackets[n]);
		}
		i++;
	}
	return str;
}

function str_print_uint(val, charset) {
	// 'charset' must be a character array.
	var radix = charset.length;
	var str = "";
	val -= val % 1;  // No float allowed
	while (val >= 1) {
		str = charset[val % radix] + str;
		val /= radix;
		val -= val % 1;
	}
	return str;
}

function str_replace(str, pos, len, sub) {
	if (pos < str.length) {
		if (pos + len >= str.length) len -= pos + len - str.length;
		return str.substring(0, pos) + sub + str.substring(pos + len);
	} else return str;
}

function is_string(v) {
    return Object.prototype.toString.call(v) === '[object String]';
}

function is_array(v) {
    return Object.prototype.toString.call(v) === '[object Array]';
}

if (typeof module !== 'undefined')
    module.exports.postprocessing = camxes_postprocessing;

<|endoftext|>


<commit_before>/* global define, require, window */
var addonName = 'ivy-tabs';

define('ember', ['exports'], function(__exports__) {
  __exports__['default'] = window.Ember;
});

var index = addonName + '/index';
define(addonName, ['exports'], function(__exports__) {
  var library = require(index);
  Object.keys(lf).forEach(function(key) {
    __exports__[key] = library[key];
  });
});

// Glue library to a global var
window.IvyTabs = require(index);

// Register library items in the container
var shim = addonName + '-shim';
window.Ember.Application.initializer({
  name: shim,

  initialize: function(container) {
    require(shim).initialize(container);
  }
});
<commit_msg>Fix variable reference in glue.js.<commit_after>/* global define, require, window */
var addonName = 'ivy-tabs';

define('ember', ['exports'], function(__exports__) {
  __exports__['default'] = window.Ember;
});

var index = addonName + '/index';
define(addonName, ['exports'], function(__exports__) {
  var library = require(index);
  Object.keys(library).forEach(function(key) {
    __exports__[key] = library[key];
  });
});

// Glue library to a global var
window.IvyTabs = require(index);

// Register library items in the container
var shim = addonName + '-shim';
window.Ember.Application.initializer({
  name: shim,

  initialize: function(container) {
    require(shim).initialize(container);
  }
});
<|endoftext|>