<commit_before>import { reduce, isFinite, isString } from "lodash"

class ValidatorAssertions {
  invalid(fields, error)
  {
    return {
      valid: false,
      fields,
      error
    }
  }

  isNumber(value)
  {
    return isFinite(value)
  }

  isString(value)
  {
    return isString(value) && value !== ""
  }

  hasValue(value)
  {
    if (value === undefined)
      return false

    if (value === null)
      return false

    if (typeof (value) === "number" && isNaN(value))
      return false

    return true
  }
}

const validatorAssertions = new ValidatorAssertions()

export default class BaseValidator {

  constructor(module = null)
  {
    this._ruleMap = []
    this.module = module
  }

  injectStore(store)
  {
    this._store = store
  }

  /*
   * Add rule to validator. name {string} is the rule's name to find it in debugging mode.
   * validatorFunction {function(state)} is the validator function given global state as
   * first parameter.
   *
   * The return value should be either null if the rule don't apply or everything is valid.
   * Otherwise it should call this.valid(fields, error) as return value where fields is
   * an array of strings with the fields validated and error is a string describing technical
   * what was validated and failed.
   *
   * The idea behind this technical error string is that it should be a key in i18n to translate
   * to a good user readable error message.
   *
   * The validatorFunction is called in context of ValidatorAssertions, so every function in there
   * is callable via this.functionName().
   */
  rule(name, validatorFunction)
  {
    this._ruleMap.push({
      name,
      validatorFunction
    })
  }

  isValid()
  {
    const state = this._store.state

    return reduce(
      this._ruleMap.map(
        (rule) =>
        {
          const valid = rule.validatorFunction.call(validatorAssertions, state)

          if (valid && valid.valid === false)
            return {
              name: rule.name,
              fields: valid.fields,
              error: valid.error
            }

          return true
        }
      ),
      (all, thisRule) =>
      {
        if (thisRule === true)
          return all

        if (all === true)
          return [ thisRule ]

        return all.concat(thisRule)
      },
      true
    )
  }

}
<commit_msg>Add properties mapping of rules<commit_after>import { reduce, isFinite, isString } from "lodash"

class ValidatorAssertions {
  invalid(fields, error)
  {
    return {
      valid: false,
      fields,
      error
    }
  }

  isNumber(value)
  {
    return isFinite(value)
  }

  isString(value)
  {
    return isString(value) && value !== ""
  }

  hasValue(value)
  {
    if (value === undefined)
      return false

    if (value === null)
      return false

    if (typeof (value) === "number" && isNaN(value))
      return false

    return true
  }
}

const validatorAssertions = new ValidatorAssertions()

export default class BaseValidator {

  constructor(module = null)
  {
    this._ruleMap = []
    this._propertiesMap = {}
    this.module = module
  }

  injectStore(store)
  {
    this._store = store
  }

  getProperties()
  {
    return Object.keys(this._propertiesMap)
  }

  getRulesByProperty(property)
  {
    return this._propertiesMap[property]
  }

  /*
   * Add rule to validator. name {string} is the rule's name to find it in debugging mode.
   * properties {array(string)} is a list of properties that are validated with this rule.
   * validatorFunction {function(state)} is the validator function given global state as
   * first parameter.
   *
   * The return value should be either null if the rule don't apply or everything is valid.
   * Otherwise it should call this.valid(fields, error) as return value where fields is
   * an array of strings with the fields validated and error is a string describing technical
   * what was validated and failed.
   *
   * The idea behind this technical error string is that it should be a key in i18n to translate
   * to a good user readable error message.
   *
   * The validatorFunction is called in context of ValidatorAssertions, so every function in there
   * is callable via this.functionName().
   */
  rule(name, properties, validatorFunction)
  {
    this._ruleMap.push({
      name,
      properties,
      validatorFunction
    })

    const propertiesMap = this._propertiesMap
    properties.forEach((prop) =>
    {
      if (!propertiesMap[prop])
        propertiesMap[prop] = []

      propertiesMap[prop] = {
        name,
        validatorFunction
      }
    })
  }

  isValid()
  {
    const state = this._store.state

    return reduce(
      this._ruleMap.map(
        (rule) =>
        {
          const valid = rule.validatorFunction.call(validatorAssertions, state)

          if (valid && valid.valid === false)
            return {
              name: rule.name,
              fields: valid.fields,
              error: valid.error
            }

          return true
        }
      ),
      (all, thisRule) =>
      {
        if (thisRule === true)
          return all

        if (all === true)
          return [ thisRule ]

        return all.concat(thisRule)
      },
      true
    )
  }

}
<|endoftext|>


<commit_before>InboxSDK.load('1', 'sdk_Hackotron-BE_a4e83dfe8a').then(function(sdk){

	// the SDK has been loaded, now do something with it!
	sdk.Compose.registerComposeViewHandler(function(composeView){

		// a compose view has come into existence, do something with it!
		composeView.addButton({
			title: "My Nifty Button!",
			iconUrl: 'http://s12.postimg.org/6da0b7cnx/Logomakr_19_MEHn.png',
			onClick: function(event) {

				//window.alert(event.composeView.getHTMLContent())

				var html = '
'+
'

	'+
'	'+
'

	'+
'
'+
'
'+
'	'+
''+
'	'+
'
This email has been sent to you securely using Egress Switch
'+
'
'+
'
'+
'

	'+
'	  '+
'
If you have Switch installed, simply open the attachment.
'+
'
Alternatively, forward this email to [[READEROPENEMAIL]] or visit Switch Web Access.
'+
'	  	'+
'
'+
'
'+
'
Regular user? Download our free desktop or mobile apps.
'+
'	'+
'
Having problems accessing the email? Click Here

'+
'	'+
'	'+
'
'+
'
'+
' '+
'
Confidentiality Notice: This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender.
'+
'	'+
'
'+
'
'+
' '+
'
© Copyright 2007-2011 Egress Software Technologies Ltd.
'+
' 	'+
'
';

				//var blob = new Blob([event.composeView.getHTMLContent()], {type : 'application/octet-binary', name:"ecrypted.switch",fileName:"ecrypted.switch",file:"ecrypted.switch",file:"ecrypted.switch"});
				var blob = new File([event.composeView.getHTMLContent()],"ecrypted.switch",{type : 'application/octet-binary'})
				event.composeView.setBodyHTML(html);
				event.composeView.attachFiles([blob]);
				//event.composeView.insertTextIntoBodyAtCursor('Hello World!');
			},
		});
		composeView.on('presending', function(event) {
			// Cancel sending event
			event.cancel();
		});

	});

}

);
<commit_msg>put in a console log that mentions the presending event is triggered<commit_after>InboxSDK.load('1', 'sdk_Hackotron-BE_a4e83dfe8a').then(function(sdk){

	// the SDK has been loaded, now do something with it!
	sdk.Compose.registerComposeViewHandler(function(composeView){

		// a compose view has come into existence, do something with it!
		composeView.addButton({
			title: "My Nifty Button!",
			iconUrl: 'http://s12.postimg.org/6da0b7cnx/Logomakr_19_MEHn.png',
			onClick: function(event) {

				//window.alert(event.composeView.getHTMLContent())

				var html = '
'+
'

	'+
'	'+
'

	'+
'
'+
'
'+
'	'+
''+
'	'+
'
This email has been sent to you securely using Egress Switch
'+
'
'+
'
'+
'

	'+
'	  '+
'
If you have Switch installed, simply open the attachment.
'+
'
Alternatively, forward this email to [[READEROPENEMAIL]] or visit Switch Web Access.
'+
'	  	'+
'
'+
'
'+
'
Regular user? Download our free desktop or mobile apps.
'+
'	'+
'
Having problems accessing the email? Click Here

'+
'	'+
'	'+
'
'+
'
'+
' '+
'
Confidentiality Notice: This email and any files transmitted with it are confidential and intended solely for the use of the individual or entity to whom they are addressed. If you have received this email in error please notify the sender.
'+
'	'+
'
'+
'
'+
' '+
'
© Copyright 2007-2011 Egress Software Technologies Ltd.
'+
' 	'+
'
';

				//var blob = new Blob([event.composeView.getHTMLContent()], {type : 'application/octet-binary', name:"ecrypted.switch",fileName:"ecrypted.switch",file:"ecrypted.switch",file:"ecrypted.switch"});
				var blob = new File([event.composeView.getHTMLContent()],"ecrypted.switch",{type : 'application/octet-binary'})
				event.composeView.setBodyHTML(html);
				event.composeView.attachFiles([blob]);
				//event.composeView.insertTextIntoBodyAtCursor('Hello World!');
			},
		});
		composeView.on('presending', function(event) {
			window.console("this is pre-sending event");
			event.cancel();
		});

	});

}

);
<|endoftext|>


<commit_before>/* Class: LemmaPOSTagset

   Class representing a LemmaPOS tagset.
 */
var LemmaPOSTagset = new Class({
    Extends: Tagset,
    classname: 'Lemma-Tag',
    optgroup: null,
    eventString: 'change:relay(select.et-select-lemmapos)',

    /* Constructor: Tagset

       Instantiate a new LemmaPOSTagset.

       Parameters:
         data - A data object containing tagset information.
     */
    initialize: function(data) {
        this.parent(data);
    },

    /* Function: processTags

       Defines a list of tags for this tagset and preprocesses it, building
       <optgroup> elements for all tags.
     */
    processTags: function(tags) {
        this.parent(tags);
        this.optgroup = this.generateOptgroupFor(this.tags);
    },

    /* Function: buildTemplate

       Update an editor line template for this tagset.  Fills the <select>
       element with the pre-generated <optgroup> containing all lemmaPOS tags,
       if possible.

       Parameters:
         td - Table cell element to update
     */
    buildTemplate: function(td) {
        var elem = td.getElement('select');
        if (elem !== null) {
            elem.empty();
            if(this.processed)
                elem.grab(this.optgroup.clone());
        }
    },

    /* Function: handleEvent

       A specialization of the default handler that works with <select>
       elements.
     */
    handleEvent: function(event, target) {
        return {cls: this.class, value: target.getSelected()[0].get('value')};
    },

    /* Function: fill

       Fill the approriate elements in a <tr> with annotation from a token data
       object.

       Parameters:
         tr - Table row to fill
         data - An object possibly containing annotations ({anno_pos: ...} etc.)
     */
    fill: function(tr, data) {
        var ref = this;
        var pos = tr.getElement('.editTable_lemmapos select');
        if(pos !== null) {
            pos.getElements('.lineSuggestedTag').destroy();
            pos.grab(new Element('option', {
                text: (typeof(data.anno_lemmapos) === "undefined")
                          ? '' : data.anno_lemmapos,
                value: data.anno_lemmapos,
                selected: 'selected',
                class: 'lineSuggestedTag'
            }), 'top');
        }
    },

    /* Function: update

       Triggered method to call whenever an annotation changes.

       Parameters:
         tr - Table row where the change happened
         data - An object possibly containing annotations ({anno_pos: ...}),
                in the state *before* the update
         changes - An object containing any changed values *after* the update
         cls - Tagset class of the annotation
         value - New value of the annotation
     */
    update: function(tr, data, changes, cls, value) {
        if (cls === "lemmapos")
            changes.anno_lemmapos = value;
    }
});
<commit_msg>LemmaPOS now pre-selects a tag if it's empty and POS changes.<commit_after>/* Class: LemmaPOSTagset

   Class representing a LemmaPOS tagset.
 */
var LemmaPOSTagset = new Class({
    Extends: Tagset,
    classname: 'Lemma-Tag',
    optgroup: null,
    eventString: 'change:relay(select.et-select-lemmapos)',

    /* Constructor: Tagset

       Instantiate a new LemmaPOSTagset.

       Parameters:
         data - A data object containing tagset information.
     */
    initialize: function(data) {
        this.parent(data);
    },

    /* Function: processTags

       Defines a list of tags for this tagset and preprocesses it, building
       <optgroup> elements for all tags.
     */
    processTags: function(tags) {
        this.parent(tags);
        this.optgroup = this.generateOptgroupFor(this.tags);
    },

    /* Function: buildTemplate

       Update an editor line template for this tagset.  Fills the <select>
       element with the pre-generated <optgroup> containing all lemmaPOS tags,
       if possible.

       Parameters:
         td - Table cell element to update
     */
    buildTemplate: function(td) {
        var elem = td.getElement('select');
        if (elem !== null) {
            elem.empty();
            if(this.processed)
                elem.grab(this.optgroup.clone());
        }
    },

    /* Function: handleEvent

       A specialization of the default handler that works with <select>
       elements.
     */
    handleEvent: function(event, target) {
        return {cls: this.class, value: target.getSelected()[0].get('value')};
    },

    /* Function: fill

       Fill the approriate elements in a <tr> with annotation from a token data
       object.

       Parameters:
         tr - Table row to fill
         data - An object possibly containing annotations ({anno_pos: ...} etc.)
     */
    fill: function(tr, data) {
        var ref = this;
        var pos = tr.getElement('.editTable_lemmapos select');
        if(pos !== null) {
            pos.getElements('.lineSuggestedTag').destroy();
            pos.grab(new Element('option', {
                text: (typeof(data.anno_lemmapos) === "undefined")
                          ? '' : data.anno_lemmapos,
                value: data.anno_lemmapos,
                selected: 'selected',
                class: 'lineSuggestedTag'
            }), 'top');
        }
    },

    /* Function: update

       Triggered method to call whenever an annotation changes.

       Parameters:
         tr - Table row where the change happened
         data - An object possibly containing annotations ({anno_pos: ...}),
                in the state *before* the update
         changes - An object containing any changed values *after* the update
         cls - Tagset class of the annotation
         value - New value of the annotation
     */
    update: function(tr, data, changes, cls, value) {
        if (cls === "lemmapos") {
            changes.anno_lemmapos = value;
        } else if (cls === "pos" && !data.anno_lemmapos) {
            // try to "pre-select" a reasonable tag
            if (this.tags.contains(value)) {
                changes.anno_lemmapos = value;
                this.fill(tr, changes);
            } else {
                for(var i=0; i<this.tags.length; i++) {
                    if (value.indexOf(this.tags[i]) === 0) {
                        changes.anno_lemmapos = this.tags[i];
                        this.fill(tr, changes);
                        break;
                    }
                }
            }
        }
    }
});
<|endoftext|>


<commit_before>require( [ 'include/main', 'util/main' ], function() {} );<commit_msg>Convert UTC time to local format, fixes #3<commit_after>require( [ 'jquery', 'include/main', 'util/main' ], function( $ )
{
	// Replace UTC time string with local date format
	$( '.meta .date' ).each( function()
	{
		var date = new Date( $( this ).html() );
		$( this ).html( date.toLocaleString() );
	} );
} );<|endoftext|>


<commit_before>var geom = require("geoscript/geom");
var jts = Packages.com.vividsolutions.jts;
var SimpleFeatureBuilder = Packages.org.geotools.feature.simple.SimpleFeatureBuilder;
var util = require("geoscript/util");
var nutil = require("util");
var Schema = require("geoscript/feature/schema").Schema;

/** api: (define)
 *  module = feature
 *  class = Feature
 */
var Feature = util.extend(Object, {

    /** private: property[cache]
     *  ``Object``
     *  Cache for setters & getters.
     */
    cache: null,

    /** private: property[geometryName]
     *  ``String``
     *  Name for the default geometry property.
     */
    geometryName: null,

    /** api: property[schema]
     *  :class:`feature.Schema`
     *  The feature schema.
     */
    schema: null,

    /** api: property[id]
     *  ``String``
     *  The feature identifier.
     */
    id: null,

    /** api: constructor
     *  .. class:: Feature
     *
     *      :arg config: ``Object`` Configuration object.
     *
     *      Create a new feature.
     */
    constructor: function Feature(config) {
        this.cache = {};
        if (config) {
            if (config.schema) {
                this.schema = config.schema;
            } else {
                this.schema = Schema.fromValues(config.values);
            }

            var builder = new SimpleFeatureBuilder(this.schema._schema);
            var value, defaultGeom;
            for (var name in config.values) {
                value = config.values[name];
                if (value instanceof geom.Geometry) {
                    if (!defaultGeom) {
                        // TODO: confirm default geom is always first one set
                        defaultGeom = value;
                    }
                    value = value._geometry;
                }
                builder.set(name, value);
            }
            if (defaultGeom) {
                // cache the default geometry
                this.cache.geometry = defaultGeom;
            }
            this._feature = builder.buildFeature(config.id);
            this.init();
        }
    },

    /** private: method[init]
     *  Called after feature has _feature and schema properties.
     */
    init: function() {
        this.id = this._feature.identifier.toString();
        var geomProp = this._feature.getDefaultGeometryProperty();
        if (geomProp) {
            this.geometryName = String(geomProp.getName());
        }
    },

    /** api: property[geometry]
     *  :class:`geom.Geometry`
     *  The default geometry (if any) for the feature.  Will be ``undefined``
     *  if the feature does not have a geometry.
     */
    get geometry() {
        if (this.cache.geometry == null) {
            var _geometry = this._feature.getDefaultGeometry();
            if (_geometry) {
                this.cache.geometry = geom.Geometry.from_(_geometry); // may be undefined
            }
        }
        return this.cache.geometry;
    },
    set geometry(geometry) {
        this._feature.setDefaultGeometry(geometry._geometry);
        this.cache.geometry = geometry;
    },

    /** api: method[set]
     *  :arg name: ``String`` Attribute name.
     *  :arg value: ``String`` Attribute value.
     *
     *  Set a feature attribute.
     */
    set: function(name, value) {
        if (value instanceof geom.Geometry) {
            if (name === this.geometryName) {
                this.geometry = value;
            }
            value = value._geometry;
        }
        this._feature.setAttribute(name, value);
    },

    /** api: method[get]
     *  :arg name: ``String`` Attribute name.
     *
     *  Get an attribute value.
     */
    get: function(name) {
        var value;
        if (name === this.geometryName) {
            value = this.geometry;
        } else {
            value = this._feature.getAttribute(name);
            if (value instanceof jts.geom.Geometry) {
                value = geom.Geometry.from_(value);
            } else if (value instanceof java.lang.Number) {
                value = Number(value);
            } else {
                value = String(value);
            }
        }
        return value;
    },

    /** api: property[values]
     *  ``Object``
     *  An object with all the feature property names and values.  Used for
     *  property access only.  Use :meth:`set` to set property values.
     */
    get values() {
        var values = {};
        if (this.schema) {
            this.schema.fieldNames.forEach(function(name) {
                values[name] = this.get(name);
            }, this);
        }
        return values;
    },

    /** api: property[json]
     *  ``String``
     *  The JSON representation of the feature (see http://geojson.org).
     */
    get json() {
        return JSON.encode(this.config);
    },

    /** private: property[config]
     *  ``Object``
     */
    get config() {
        var values = this.values;
        var properties = {}, val;
        for (var name in values) {
            val = values[name];
            if (typeof val === "number" ||
                typeof val === "string" ||
                val === null) {
                properties[name] = val;
            }
        }
        return {
            type: "Feature",
            geometry: this.geometry.config,
            properties: properties
        };
    },

    /** private: method[toFullString]
     */
    toFullString: function() {
        var values = this.values;
        for (var name in values) {
            if (values[name] instanceof geom.Geometry) {
                values[name] = values[name].toString();
            }
        }
        return nutil.repr(values);
    }

});

/** private: staticmethod[from_]
 *  :arg _feature: ``org.geotools.feature.simple.SimpleFeatureImpl``
 *  :arg _schema: ``org.geotools.feature.simple.SimpleFeatureTypeImpl`` Optional schema.
 *  :returns: :class:`Feature`
 *
 *  Create a feature from corresponding GeoTools parts.
 */
Feature.from_ = function(_feature, _schema) {
    var feature = new Feature();
    feature._feature = _feature;
    feature.schema = Schema.from_(_schema || _feature.type);
    feature.init();
    return feature;
};

/** api: example
 *  Sample code to create a new feature:
 *
 *  .. code-block:: javascript
 *
 *      var city = new feature.Feature({
 *          values: {
 *              location: new geom.Point([-110, 45]),
 *              name: "Metropolis"
 *          }
 *      });
 *      city.get("name"); // "Metropolis"
 *      city.get("location"); // <Point POINT (-110 45)>
 */

exports.Feature = Feature;
<commit_msg>Workaround for different handling of java values on different systems (see #4).<commit_after>var geom = require("geoscript/geom");
var jts = Packages.com.vividsolutions.jts;
var SimpleFeatureBuilder = Packages.org.geotools.feature.simple.SimpleFeatureBuilder;
var util = require("geoscript/util");
var nutil = require("util");
var Schema = require("geoscript/feature/schema").Schema;

/** api: (define)
 *  module = feature
 *  class = Feature
 */
var Feature = util.extend(Object, {

    /** private: property[cache]
     *  ``Object``
     *  Cache for setters & getters.
     */
    cache: null,

    /** private: property[geometryName]
     *  ``String``
     *  Name for the default geometry property.
     */
    geometryName: null,

    /** api: property[schema]
     *  :class:`feature.Schema`
     *  The feature schema.
     */
    schema: null,

    /** api: property[id]
     *  ``String``
     *  The feature identifier.
     */
    id: null,

    /** api: constructor
     *  .. class:: Feature
     *
     *      :arg config: ``Object`` Configuration object.
     *
     *      Create a new feature.
     */
    constructor: function Feature(config) {
        this.cache = {};
        if (config) {
            if (config.schema) {
                this.schema = config.schema;
            } else {
                this.schema = Schema.fromValues(config.values);
            }

            var builder = new SimpleFeatureBuilder(this.schema._schema);
            var value, defaultGeom;
            for (var name in config.values) {
                value = config.values[name];
                if (value instanceof geom.Geometry) {
                    if (!defaultGeom) {
                        // TODO: confirm default geom is always first one set
                        defaultGeom = value;
                    }
                    value = value._geometry;
                }
                builder.set(name, value);
            }
            if (defaultGeom) {
                // cache the default geometry
                this.cache.geometry = defaultGeom;
            }
            this._feature = builder.buildFeature(config.id);
            this.init();
        }
    },

    /** private: method[init]
     *  Called after feature has _feature and schema properties.
     */
    init: function() {
        this.id = this._feature.identifier.toString();
        var geomProp = this._feature.getDefaultGeometryProperty();
        if (geomProp) {
            this.geometryName = String(geomProp.getName());
        }
    },

    /** api: property[geometry]
     *  :class:`geom.Geometry`
     *  The default geometry (if any) for the feature.  Will be ``undefined``
     *  if the feature does not have a geometry.
     */
    get geometry() {
        if (this.cache.geometry == null) {
            var _geometry = this._feature.getDefaultGeometry();
            if (_geometry) {
                this.cache.geometry = geom.Geometry.from_(_geometry); // may be undefined
            }
        }
        return this.cache.geometry;
    },
    set geometry(geometry) {
        this._feature.setDefaultGeometry(geometry._geometry);
        this.cache.geometry = geometry;
    },

    /** api: method[set]
     *  :arg name: ``String`` Attribute name.
     *  :arg value: ``String`` Attribute value.
     *
     *  Set a feature attribute.
     */
    set: function(name, value) {
        if (value instanceof geom.Geometry) {
            if (name === this.geometryName) {
                this.geometry = value;
            }
            value = value._geometry;
        }
        this._feature.setAttribute(name, value);
    },

    /** api: method[get]
     *  :arg name: ``String`` Attribute name.
     *
     *  Get an attribute value.
     */
    get: function(name) {
        var value;
        if (name === this.geometryName) {
            value = this.geometry;
        } else {
            value = this._feature.getAttribute(name);
            if (value instanceof jts.geom.Geometry) {
                value = geom.Geometry.from_(value);
            } else if (typeof value !== "string" && typeof value !== "number") {
                if (value instanceof java.lang.Number) {
                    value = Number(value);
                } else {
                    value = String(value);
                }
            }
        }
        return value;
    },

    /** api: property[values]
     *  ``Object``
     *  An object with all the feature property names and values.  Used for
     *  property access only.  Use :meth:`set` to set property values.
     */
    get values() {
        var values = {};
        if (this.schema) {
            this.schema.fieldNames.forEach(function(name) {
                values[name] = this.get(name);
            }, this);
        }
        return values;
    },

    /** api: property[json]
     *  ``String``
     *  The JSON representation of the feature (see http://geojson.org).
     */
    get json() {
        return JSON.encode(this.config);
    },

    /** private: property[config]
     *  ``Object``
     */
    get config() {
        var values = this.values;
        var properties = {}, val;
        for (var name in values) {
            val = values[name];
            if (typeof val === "number" ||
                typeof val === "string" ||
                val === null) {
                properties[name] = val;
            }
        }
        return {
            type: "Feature",
            geometry: this.geometry.config,
            properties: properties
        };
    },

    /** private: method[toFullString]
     */
    toFullString: function() {
        var values = this.values;
        for (var name in values) {
            if (values[name] instanceof geom.Geometry) {
                values[name] = values[name].toString();
            }
        }
        return nutil.repr(values);
    }

});

/** private: staticmethod[from_]
 *  :arg _feature: ``org.geotools.feature.simple.SimpleFeatureImpl``
 *  :arg _schema: ``org.geotools.feature.simple.SimpleFeatureTypeImpl`` Optional schema.
 *  :returns: :class:`Feature`
 *
 *  Create a feature from corresponding GeoTools parts.
 */
Feature.from_ = function(_feature, _schema) {
    var feature = new Feature();
    feature._feature = _feature;
    feature.schema = Schema.from_(_schema || _feature.type);
    feature.init();
    return feature;
};

/** api: example
 *  Sample code to create a new feature:
 *
 *  .. code-block:: javascript
 *
 *      var city = new feature.Feature({
 *          values: {
 *              location: new geom.Point([-110, 45]),
 *              name: "Metropolis"
 *          }
 *      });
 *      city.get("name"); // "Metropolis"
 *      city.get("location"); // <Point POINT (-110 45)>
 */

exports.Feature = Feature;
<|endoftext|>


<commit_before>import { reduce, isFinite, isString } from "lodash"

class ValidatorAssertions {
  invalid(fields, error)
  {
    return {
      valid: false,
      fields,
      error
    }
  }

  isNumber(value)
  {
    return isFinite(value)
  }

  isString(value)
  {
    return isString(value) && value !== ""
  }

  hasValue(value)
  {
    if (value === undefined)
      return false

    if (value === null)
      return false

    if (typeof (value) === "number" && isNaN(value))
      return false

    return true
  }
}

const validatorAssertions = new ValidatorAssertions()

export default class BaseValidator {

  constructor(module = null)
  {
    this._ruleMap = []
    this._propertiesMap = {}
    this.module = module
  }

  injectStore(store)
  {
    this._store = store
  }

  getProperties()
  {
    return Object.keys(this._propertiesMap)
  }

  getRulesByProperty(property)
  {
    return this._propertiesMap[property]
  }

  /*
   * Add rule to validator. name {string} is the rule's name to find it in debugging mode.
   * properties {array(string)} is a list of properties that are validated with this rule.
   * validatorFunction {function(state)} is the validator function given global state as
   * first parameter.
   *
   * The return value should be either null if the rule don't apply or everything is valid.
   * Otherwise it should call this.valid(fields, error) as return value where fields is
   * an array of strings with the fields validated and error is a string describing technical
   * what was validated and failed.
   *
   * The idea behind this technical error string is that it should be a key in i18n to translate
   * to a good user readable error message.
   *
   * The validatorFunction is called in context of ValidatorAssertions, so every function in there
   * is callable via this.functionName().
   */
  rule(name, properties, validatorFunction)
  {
    this._ruleMap.push({
      name,
      properties,
      validatorFunction
    })

    const propertiesMap = this._propertiesMap
    properties.forEach((prop) =>
    {
      if (!propertiesMap[prop])
        propertiesMap[prop] = []

      propertiesMap[prop] = {
        name,
        validatorFunction
      }
    })
  }

  isValid()
  {
    const state = this._store.state

    return reduce(
      this._ruleMap.map(
        (rule) =>
        {
          const valid = rule.validatorFunction.call(validatorAssertions, state)

          if (valid && valid.valid === false)
            return {
              name: rule.name,
              fields: valid.fields,
              error: valid.error
            }

          return true
        }
      ),
      (all, thisRule) =>
      {
        if (thisRule === true)
          return all

        if (all === true)
          return [ thisRule ]

        return all.concat(thisRule)
      },
      true
    )
  }

}
<commit_msg>Fix array typo<commit_after>import { reduce, isFinite, isString } from "lodash"

class ValidatorAssertions {
  invalid(fields, error)
  {
    return {
      valid: false,
      fields,
      error
    }
  }

  isNumber(value)
  {
    return isFinite(value)
  }

  isString(value)
  {
    return isString(value) && value !== ""
  }

  hasValue(value)
  {
    if (value === undefined)
      return false

    if (value === null)
      return false

    if (typeof (value) === "number" && isNaN(value))
      return false

    return true
  }
}

const validatorAssertions = new ValidatorAssertions()

export default class BaseValidator {

  constructor(module = null)
  {
    this._ruleMap = []
    this._propertiesMap = {}
    this.module = module
  }

  injectStore(store)
  {
    this._store = store
  }

  getProperties()
  {
    return Object.keys(this._propertiesMap)
  }

  getRulesByProperty(property)
  {
    return this._propertiesMap[property]
  }

  /*
   * Add rule to validator. name {string} is the rule's name to find it in debugging mode.
   * properties {array(string)} is a list of properties that are validated with this rule.
   * validatorFunction {function(state)} is the validator function given global state as
   * first parameter.
   *
   * The return value should be either null if the rule don't apply or everything is valid.
   * Otherwise it should call this.valid(fields, error) as return value where fields is
   * an array of strings with the fields validated and error is a string describing technical
   * what was validated and failed.
   *
   * The idea behind this technical error string is that it should be a key in i18n to translate
   * to a good user readable error message.
   *
   * The validatorFunction is called in context of ValidatorAssertions, so every function in there
   * is callable via this.functionName().
   */
  rule(name, properties, validatorFunction)
  {
    this._ruleMap.push({
      name,
      properties,
      validatorFunction
    })

    const propertiesMap = this._propertiesMap
    properties.forEach((prop) =>
    {
      if (!propertiesMap[prop])
        propertiesMap[prop] = []

      propertiesMap[prop].push({
        name,
        validatorFunction
      })
    })
  }

  isValid()
  {
    const state = this._store.state

    return reduce(
      this._ruleMap.map(
        (rule) =>
        {
          const valid = rule.validatorFunction.call(validatorAssertions, state)

          if (valid && valid.valid === false)
            return {
              name: rule.name,
              fields: valid.fields,
              error: valid.error
            }

          return true
        }
      ),
      (all, thisRule) =>
      {
        if (thisRule === true)
          return all

        if (all === true)
          return [ thisRule ]

        return all.concat(thisRule)
      },
      true
    )
  }

}
<|endoftext|>


<commit_before>(function() {
  'use strict';

  angular
    .module('static')
    .factory('AuthService', AuthService);

    /** @ngInject */
    function AuthService ($rootScope, $http, $httpParamSerializerJQLike, $state, $localStorage, AUTH_EVENTS, apiHost, Session, toastr) {

      return {
        login: login,
        logout: logout,
        getCurrentUser: getCurrentUser,
        isAuthenticated: isAuthenticated,
      };

      function isAuthenticated () {

        return !!Session.user;
      }

      function login (credentials) {

        return $http({
          method: 'POST',
          url: apiHost + '/login/',
          data: $httpParamSerializerJQLike(credentials),
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
        .then(loginSuccess)
        .catch(loginError);

        function loginSuccess (data) {

          // Deserialize the return:
          var key = data.data.key;
          var user = data.data.user;

          // Create Session
          Session.create(key, user);

          // Emit event
          $rootScope.$emit(AUTH_EVENTS.loginSuccess);

          // Show Success Toast and Redirect
          toastr.success('Logged In');
          $state.go('main');

          return user;
        }

        function loginError (error) {

          // Emit event
          $rootScope.$emit(AUTH_EVENTS.loginFailure);

          // Show Error Toast
          toastr.error(JSON.stringify(error));
        }
      }

      function logout () {

        // Construct payload for sending token back with logout
        var payload = {
          token: Session.token
        };

        return $http({
          method: 'POST',
          url: apiHost + '/logout/',
          data: $httpParamSerializerJQLike(payload),
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
        .then(logoutSuccess)
        .catch(logoutError);

        function logoutSuccess (data) {

          // Destroy Session
          Session.destroy();

          // Emit Event
          $rootScope.$emit(AUTH_EVENTS.logoutSuccess);

          // Show Toast and Redirect
          toastr.info('Logged Out');
          $state.go('login');
        }

        function logoutError (error) {

          // Show Error Toast
          toastr.error(JSON.stringify(error));
        }
      }

      function getCurrentUser () {

        // First, check if there's an existing Session
        if (!!Session.user) {

          // Emit Event
          $rootScope.$emit(AUTH_EVENTS.getCurrentUserSuccess);

          // Yes? Return this user
          return Session.user;
        }

        // If no, check if there's a token to retrieve the user
        else if (!!$localStorage._mendelToken) {

          // Set Authorization Header with Token
          $http.defaults.headers.common['Authorization'] = 'Token ' + $localStorage._mendelToken;

          // Get User info from endpoint
          $http({
            method: 'GET',
            url: apiHost + '/user/'
          })
          .then(getCurrentUserSuccess)
          .catch(getCurrentUserError);
        }

        // Otherwise, we're not authenticated
        else {

          // Emit Event
          $rootScope.$emit(AUTH_EVENTS.notAuthenticated);

          return null;
        }

        function getCurrentUserSuccess (data) {

          // Deserialize the return:
          var user = data.data;

          // (Creating a Session also requires the token):
          var key = $localStorage._mendelToken;

          // Create Session
          Session.create(key, user);

          // Emit Event
          $rootScope.$emit(AUTH_EVENTS.getCurrentUserSuccess);

          return user;
        }

        function getCurrentUserError (error) {

          // Destroy Session
          Session.destroy();
          // (Clears any invalid tokens from localStorage)

          // Emit Event
          $rootScope.$emit(AUTH_EVENTS.getCurrentUserFailed);

          // Show Error Toast
          toastr.error(JSON.stringify(error));

          return null;
        }
      }
    }
  })();<commit_msg>(use $broadcast, not $emit 🙄😑)<commit_after>(function() {
  'use strict';

  angular
    .module('static')
    .factory('AuthService', AuthService);

    /** @ngInject */
    function AuthService ($rootScope, $http, $httpParamSerializerJQLike, $state, $localStorage, AUTH_EVENTS, apiHost, Session, toastr) {

      return {
        login: login,
        logout: logout,
        getCurrentUser: getCurrentUser,
        isAuthenticated: isAuthenticated,
      };

      function isAuthenticated () {

        return !!Session.user;
      }

      function login (credentials) {

        return $http({
          method: 'POST',
          url: apiHost + '/login/',
          data: $httpParamSerializerJQLike(credentials),
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
        .then(loginSuccess)
        .catch(loginError);

        function loginSuccess (data) {

          // Deserialize the return:
          var key = data.data.key;
          var user = data.data.user;

          // Create Session
          Session.create(key, user);

          // Broadcast event
          $rootScope.$broadcast(AUTH_EVENTS.loginSuccess);

          // Show Success Toast and Redirect
          toastr.success('Logged In');
          $state.go('main');

          return user;
        }

        function loginError (error) {

          // Broadcast event
          $rootScope.$broadcast(AUTH_EVENTS.loginFailure);

          // Show Error Toast
          toastr.error(JSON.stringify(error));
        }
      }

      function logout () {

        // Construct payload for sending token back with logout
        var payload = {
          token: Session.token
        };

        return $http({
          method: 'POST',
          url: apiHost + '/logout/',
          data: $httpParamSerializerJQLike(payload),
          headers: {'Content-Type': 'application/x-www-form-urlencoded'}
        })
        .then(logoutSuccess)
        .catch(logoutError);

        function logoutSuccess (data) {

          // Destroy Session
          Session.destroy();

          // Broadcast Event
          $rootScope.$broadcast(AUTH_EVENTS.logoutSuccess);

          // Show Toast and Redirect
          toastr.info('Logged Out');
          $state.go('login');
        }

        function logoutError (error) {

          // Show Error Toast
          toastr.error(JSON.stringify(error));
        }
      }

      function getCurrentUser () {

        // First, check if there's an existing Session
        if (!!Session.user) {

          // Broadcast Event
          $rootScope.$broadcast(AUTH_EVENTS.getCurrentUserSuccess);

          // Yes? Return this user
          return Session.user;
        }

        // If no, check if there's a token to retrieve the user
        else if (!!$localStorage._mendelToken) {

          // Set Authorization Header with Token
          $http.defaults.headers.common['Authorization'] = 'Token ' + $localStorage._mendelToken;

          // Get User info from endpoint
          $http({
            method: 'GET',
            url: apiHost + '/user/'
          })
          .then(getCurrentUserSuccess)
          .catch(getCurrentUserError);
        }

        // Otherwise, we're not authenticated
        else {

          // Broadcast Event
          $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);

          return null;
        }

        function getCurrentUserSuccess (data) {

          // Deserialize the return:
          var user = data.data;

          // (Creating a Session also requires the token):
          var key = $localStorage._mendelToken;

          // Create Session
          Session.create(key, user);

          // Broadcast Event
          $rootScope.$broadcast(AUTH_EVENTS.getCurrentUserSuccess);

          return user;
        }

        function getCurrentUserError (error) {

          // Destroy Session
          Session.destroy();
          // (Clears any invalid tokens from localStorage)

          // Broadcast Event
          $rootScope.$broadcast(AUTH_EVENTS.getCurrentUserFailed);
          $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);

          // Show Error Toast
          toastr.error(JSON.stringify(error));

          return null;
        }
      }
    }
  })();<|endoftext|>


<commit_before>// Load in our dependencies
var assert = require('assert');

// Start our tests
describe('A basic operation', function () {
  it('asserts without errors', function () {
    assert.strictEqual(1 + 1, 2);
  });
});
<commit_msg>Simplified success test<commit_after>// Start our tests
describe('A basic operation', function () {
  it('asserts without errors', function () {
    if (1 + 1 !== 2) {
      throw new Error('1 + 1 is not equal to 2');
    }
  });
});
<|endoftext|>


<commit_before>/**
 *  \details © 2011  Open Ximdex Evolution SL [http://www.ximdex.org]
 *
 *  Ximdex a Semantic Content Management System (CMS)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published
 *  by the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  See the Affero GNU General Public License for more details.
 *  You should have received a copy of the Affero GNU General Public License
 *  version 3 along with Ximdex (see LICENSE file).
 *
 *  If not, visit http://gnu.org/licenses/agpl-3.0.html.
 *
 *  @author Ximdex DevTeam <dev@ximdex.com>
 *  @version $Revision$
 */
angular.module('ximdex.common.service')//Abstraction for server communications. TODO: Expose to client a REST like interface
    .factory('xUrlHelper', ['$window', function($window) {
        return {
            baseUrl: function() {
                return $window.X.restUrl;
            },
            getAction: function(params){
                var timestamp = new Date().getTime();
                var actionUrl = this.baseUrl()+'?noCacheVar='+timestamp+'&action='+params.action+'&method='+params.method;
                if (params.id) {
                    actionUrl+='&nodeid='+params.id+'&nodes[]='+params.id;
                } else if (params.IDParent) {
                    actionUrl+='&nodeid='+params.IDParent+'&nodes[]='+params.IDParent;
                }
                return actionUrl;
            }
        }
    }]);
<commit_msg>Adding module param to angular service<commit_after>/**
 *  \details © 2011  Open Ximdex Evolution SL [http://www.ximdex.org]
 *
 *  Ximdex a Semantic Content Management System (CMS)
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as published
 *  by the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  See the Affero GNU General Public License for more details.
 *  You should have received a copy of the Affero GNU General Public License
 *  version 3 along with Ximdex (see LICENSE file).
 *
 *  If not, visit http://gnu.org/licenses/agpl-3.0.html.
 *
 *  @author Ximdex DevTeam <dev@ximdex.com>
 *  @version $Revision$
 */
angular.module('ximdex.common.service')//Abstraction for server communications. TODO: Expose to client a REST like interface
    .factory('xUrlHelper', ['$window', function($window) {
        return {
            baseUrl: function() {
                return $window.X.restUrl;
            },
            getAction: function(params){
                var timestamp = new Date().getTime();
                var actionUrl = this.baseUrl()+'?noCacheVar='+timestamp+'&action='+params.action+'&method='+params.method;
                if (params.id) {
                    actionUrl+='&nodeid='+params.id+'&nodes[]='+params.id;
                } else if (params.IDParent) {
                    actionUrl+='&nodeid='+params.IDParent+'&nodes[]='+params.IDParent;
                }
                if (params.module){
                    actionUrl+='&mod='+params.module;
                }
                return actionUrl;
            }
        }
    }]);
<|endoftext|>


<commit_before>var colors;
var winningColor;
var numOfGuesses = 6;
var colorRange = "Full"; // 0 = full, 1 = david
var background = window.getComputedStyle(document.querySelector("body"), null).getPropertyValue("background-color");
var possibleGuesses = document.querySelectorAll(".colorGuess");
var messageDisplay = document.querySelector("#message");
var resetButton = document.getElementById("reset");
var modeButtons = document.querySelectorAll(".modeButton");
var rangeButtons = document.querySelectorAll(".rangeButton");

init();

function init() {
    for (var i = 0; i < possibleGuesses.length; i++) {
        possibleGuesses[i].addEventListener("click", setGuess);
    }

    for (i = 0; i < modeButtons.length; i++) {
        modeButtons[i].addEventListener("click", changeMode);
    }

    for (i = 0; i < rangeButtons.length; i++) {
        rangeButtons[i].addEventListener("click", changeRange);
    }

    resetButton.addEventListener("click", function() {
        messageDisplay.textContent = "";
        this.textContent = "New Colors";
        document.querySelector("h1").style.background = "steelblue";
        setColors(numOfGuesses);
    });

    setColors(numOfGuesses);
}

function setGuess() {
    if (this.style.background === winningColor) {
        messageDisplay.textContent = "Correct!";
        resetButton.textContent = "Play again";
        changeAllColors(winningColor);
        document.querySelector("h1").style.background = winningColor;
    } else {
        messageDisplay.textContent = "Try Again";
        this.style.background = background;
    }
}

function setColors(num) {
    colors = generateRandomColors(num);
    winningColor = colors[Math.floor(Math.random() * colors.length)];
    document.getElementById("colorToGuess").textContent = winningColor;
    for (var i = 0; i < possibleGuesses.length; i++) {
        if (colors[i]) {
            possibleGuesses[i].style.display = "block";
            possibleGuesses[i].style.background = colors[i];
        } else {
            possibleGuesses[i].style.display = "none";
        }
    }
}

function changeAllColors(color) {
    for (var i = 0; i < possibleGuesses.length; i++) {
        possibleGuesses[i].style.background = color;
    }
}

function generateRandomColors(num) {
    var arr = [];
    arr.push(randomColor());
    for (var i = 1; i < num; i++) {
        if (colorRange === "Full") {
            arr.push(randomColor());
        } else {
            arr.push(closeRandomColor(arr[i - 1]));
        }
    }
    arr = shuffleColors(arr);
    return arr;
}

function randomColor() {
    var r = Math.floor(Math.random() * 255);
    var g = Math.floor(Math.random() * 255);
    var b = Math.floor(Math.random() * 255);
    return "rgb(" + r + ", " + g + ", " + b + ")";
}

function closeRandomColor(str) {
    var rgb = str.match(/\d+/g);
    for (var i = 0; i < rgb.length; i++) {
        rgb[i] = Number(rgb[i]);
        var variance = Math.floor(Math.random() * 60) * (Math.random() < 0.5 ? -1 : 1);
        console.log(rgb[i] + "+" + variance);

        if (rgb[i] + variance > 255 || rgb[i] + variance < 0) {
            rgb[i] = rgb[i] - variance;
        } else {
            rgb[i] = rgb[i] + variance;
        }
    }
    return "rgb(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ")";
}

//Using Durstenfeld shuffle algorithm.
function shuffleColors(arr) {
    for (var i = arr.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    return arr;
}

function changeMode() {
    document.querySelector(".mode").innerHTML = this.textContent + " ";
    setModeOptions(this.textContent);
    resetText();
}

function setModeOptions(str) {
    if (str === "Easy") {
        numOfGuesses = 3;
        document.querySelector(".mode").innerHTML = "Easy

";
        document.querySelector("#container").style.maxWidth = "600px";
    } else if (str === "Hard") {
        numOfGuesses = 6;
        document.querySelector(".mode").innerHTML = "Hard

";
        document.querySelector("#container").style.maxWidth = "600px";
    } else {
        numOfGuesses = 16;
        document.querySelector(".mode").innerHTML = "Hardest

";
        document.querySelector("#container").style.maxWidth = "800px";
    }
}

function changeRange() {
    if (this.textContent === "Full") {
        document.querySelector(".range").innerHTML = "Full Colors

";
    } else {
        document.querySelector(".range").innerHTML = "Close Colors

";
    }
    colorRange = this.textContent;
    resetText();
}

function resetText() {
    resetButton.textContent = "New Colors";
    messageDisplay.textContent = "";
    document.querySelector("h1").style.background = "steelblue";
    setColors(numOfGuesses);
}
<commit_msg>Refactor so functions are declared before called<commit_after>var colors;
var winningColor;
var numOfGuesses = 6;
var colorRange = "Full"; // 0 = full, 1 = david
var background = window.getComputedStyle(document.querySelector("body"), null).getPropertyValue("background-color");
var possibleGuesses = document.querySelectorAll(".colorGuess");
var messageDisplay = document.querySelector("#message");
var resetButton = document.getElementById("reset");
var modeButtons = document.querySelectorAll(".modeButton");
var rangeButtons = document.querySelectorAll(".rangeButton");

function changeAllColors(color) {
    for (var i = 0; i < possibleGuesses.length; i++) {
        possibleGuesses[i].style.background = color;
    }
}

function setGuess() {
    if (this.style.background === winningColor) {
        messageDisplay.textContent = "Correct!";
        resetButton.textContent = "Play again";
        changeAllColors(winningColor);
        document.querySelector("h1").style.background = winningColor;
    } else {
        messageDisplay.textContent = "Try Again";
        this.style.background = background;
    }
}

function setModeOptions(str) {
    if (str === "Easy") {
        numOfGuesses = 3;
        document.querySelector(".mode").innerHTML = "Easy

";
        document.querySelector("#container").style.maxWidth = "600px";
    } else if (str === "Hard") {
        numOfGuesses = 6;
        document.querySelector(".mode").innerHTML = "Hard

";
        document.querySelector("#container").style.maxWidth = "600px";
    } else {
        numOfGuesses = 16;
        document.querySelector(".mode").innerHTML = "Hardest

";
        document.querySelector("#container").style.maxWidth = "800px";
    }
}

function resetText() {
    resetButton.textContent = "New Colors";
    messageDisplay.textContent = "";
    document.querySelector("h1").style.background = "steelblue";
    setColors(numOfGuesses);
}

function changeMode() {
    document.querySelector(".mode").innerHTML = this.textContent + " ";
    setModeOptions(this.textContent);
    resetText();
}

function changeRange() {
    if (this.textContent === "Full") {
        document.querySelector(".range").innerHTML = "Full Colors

";
    } else {
        document.querySelector(".range").innerHTML = "Close Colors

";
    }
    colorRange = this.textContent;
    resetText();
}

function randomColor() {
    var r = Math.floor(Math.random() * 255);
    var g = Math.floor(Math.random() * 255);
    var b = Math.floor(Math.random() * 255);
    return "rgb(" + r + ", " + g + ", " + b + ")";
}

function closeRandomColor(str) {
    var rgb = str.match(/\d+/g);
    for (var i = 0; i < rgb.length; i++) {
        rgb[i] = Number(rgb[i]);
        var variance = Math.floor(Math.random() * 60) * (Math.random() < 0.5 ? -1 : 1);
        console.log(rgb[i] + "+" + variance);

        if (rgb[i] + variance > 255 || rgb[i] + variance < 0) {
            rgb[i] = rgb[i] - variance;
        } else {
            rgb[i] = rgb[i] + variance;
        }
    }
    return "rgb(" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ")";
}

//Using Durstenfeld shuffle algorithm.
function shuffleColors(arr) {
    for (var i = arr.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    return arr;
}

function generateRandomColors(num) {
    var arr = [];
    arr.push(randomColor());
    for (var i = 1; i < num; i++) {
        if (colorRange === "Full") {
            arr.push(randomColor());
        } else {
            arr.push(closeRandomColor(arr[i - 1]));
        }
    }
    arr = shuffleColors(arr);
    return arr;
}

function setColors(num) {
    colors = generateRandomColors(num);
    winningColor = colors[Math.floor(Math.random() * colors.length)];
    document.getElementById("colorToGuess").textContent = winningColor;
    for (var i = 0; i < possibleGuesses.length; i++) {
        if (colors[i]) {
            possibleGuesses[i].style.display = "block";
            possibleGuesses[i].style.background = colors[i];
        } else {
            possibleGuesses[i].style.display = "none";
        }
    }
}

function init() {
    for (var i = 0; i < possibleGuesses.length; i++) {
        possibleGuesses[i].addEventListener("click", setGuess);
    }

    for (i = 0; i < modeButtons.length; i++) {
        modeButtons[i].addEventListener("click", changeMode);
    }

    for (i = 0; i < rangeButtons.length; i++) {
        rangeButtons[i].addEventListener("click", changeRange);
    }

    resetButton.addEventListener("click", function() {
        messageDisplay.textContent = "";
        this.textContent = "New Colors";
        document.querySelector("h1").style.background = "steelblue";
        setColors(numOfGuesses);
    });

    setColors(numOfGuesses);
}

init();
<|endoftext|>


<commit_before>/**
 * Here, we're setting up a map between Bugzilla product and GitHub repo in the user's storage.
 */
var productMap = {};
chrome.storage.sync.get('productMap', function (obj) {
	if (obj && obj.productMap) {
		productMap = obj.productMap;
	}
});

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
	switch (request.message) {
		/* This will reinitialize the plugin when the extension button is pressed */
		case "clicked_browser_action":
			init();
			break;
		/* This will reinitialize the plugin when the tab is updated */
		case "tab_updated":
			chrome.storage.sync.get('productMap', function (obj) {
				if (obj && obj.productMap) {
					productMap = obj.productMap;
				}
				init();
			});
			break;
	}
});

function init() {
	"use strict";
	// This object will be used to interact with Bugzilla
	var bugzilla = new Bugzilla();

	// Check the URL to determine if we're in Bugzilla or GitHub
	if (location.href.indexOf("bugzilla") > -1) {
		// We're in Bugzilla

		var url = $('#cf_pull_request_number').val();

		if (url && url.length) {
			var urlArray = url.split('/');
			var pr = urlArray[urlArray.length - 1];

			/* This will put the pull request # as a link next to the bug title */
			if (url) {
				var $bugTitle = $('#summary_alias_container');

				if ($($bugTitle[0].previousSibling).is("A")) {
					$($bugTitle[0].previousSibling).remove();
				}

				$bugTitle[0].previousSibling.textContent = " - ";

				$bugTitle.before(
					$("")
						.attr({
							"href": url
						})
						.html('[#' + pr + ']')
				);
			}
		}
	}
	else if (location.href.indexOf("github") > -1) {
		// We're in GitHub

		var repo = location.href.replace(/.*.com\//, '').split('/')[1];

		var REGEX = /^\[(\d+)\]|^(\d+)|^Bug\s*(\d+)/; // for example, matches [83508], 83508, Bug83508 or Bug 83508
		var $issueTitle = $('.js-issue-title');
		var bugUrl = "https://bugzilla.dtec.com/show_bug.cgi?id=";

		if ($issueTitle.length) {
			var matches = $issueTitle.html().match(REGEX);

			if (matches && matches.length) {
				var bugId = matches[0].match(/\d+/)[0];
				bugUrl += bugId;

				/* This will turn the bug number into a link to the bug */
				$issueTitle.html(
					$issueTitle.html().replace(REGEX, '[' + bugId + ']')
				);

				/* This will put a section on the side of the page for displaying info from Bugzilla */
				$("#partial-discussion-sidebar").prepend(
						$("
")
							.addClass("discussion-sidebar-item sidebar-dit-bugzilla")
							.append(
								$("
")
									.addClass("discussion-sidebar-heading")
									.html("Bugzilla ")
									.append(
										$("")
											.attr("href", bugUrl)
											.html("[" + bugId + "]")
									)
							)
							.append(
								$("
")
									.html(
										$('
')
											.html("Loading...")
									)
							)
				);

				/* Put Bugzilla bug info into side section */
				bugzilla.getBug(bugId).done(function(response) {
					var bugInfo = response[0].bugs[0];

					$(".sidebar-dit-bugzilla div")
						.html(
							$('
')
								.html("Status: " + bugInfo.status)
						)
						.append(
							$('
')
								.html("Resolution: " + bugInfo.resolution)
						)
						.append(
							$('
')
								.html("LOE: " + bugInfo.estimated_time)
						)
						.append(
							$('
')
								.html("Charge Code: " + bugInfo.cf_chargecode)
						)
						.append(
							$('
')
								.html("Assignee: " + bugInfo.assigned_to)
						)
						.append(
							$('
')
								.html("QA Contact: " + bugInfo.qa_contact)
						);
				});

				/* This will modify the comment form to allow entering Hours Worked and update Bugzilla with the comment */
				$("#workTime").remove();
				$("#partial-new-comment-form-actions button")
					.last()
						.after(
							$("")
								.text("Hours Worked")
								.attr({
									for: "workTime"
								})
								.css({
									float: "right",
									padding: "7px 0"
								})
						)
						.after(
							$("<input>")
								.attr({
									name: "workTime",
									id: "workTime",
									type: "number",
									step: "0.5"
								})
								.css({
									width: "2.5em",
									float: "right",
									margin: "5px"
								})
						);

				$("body")
					/* Syncs comments with the bug in Bugzilla */
					.off("click.DITBugzillaGitHub", "#partial-new-comment-form-actions button")
					.on("click.DITBugzillaGitHub", "#partial-new-comment-form-actions button", function() {
						bugzilla.addComment(bugId, $("#new_comment_field").val(), $("#workTime").val());
					})

					/* Syncs line comments with the bug in Bugzilla */
					.off("click.DITBugzillaGitHub", ".js-inline-comment-form button[type='submit']")
					.on("click.DITBugzillaGitHub", ".js-inline-comment-form button[type='submit']", function() {
						var $form = $(this).closest("form");
						var comment = $form.find("textarea").val();
						var line = $form.find("[name='line']").val();
						var path = $form.find("[name='path']").val();
						bugzilla.addComment(bugId, path + " line " + line + ": " + comment, 0);
					})

					/* Updates the code status in Bugzilla when merging a pull request */
					.off("click.DITBugzillaGitHub", "button[type='submit'].js-merge-commit-button")
					.on("click.DITBugzillaGitHub", "button[type='submit'].js-merge-commit-button", function() {
						var newCodeStatus;
						var comment = "Merged pull request " + $(".gh-header-number").html();
						var mergeTarget = $(".current-branch").eq(0).children().html();

						if (mergeTarget === "master") {
							newCodeStatus = "Merged to master/trunk";
							comment += " to master.";
						}
						else {
							newCodeStatus = "Merged to parent branch";
							comment += " to parent branch.";
						}

						bugzilla.updateBug(bugId, {"cf_codestatus": newCodeStatus, "comment": {"body": comment}});
					});
			}
		}

		if (repo && repo.length > 0 && !productMap[repo] && $("#productMapSelector").length === 0) {
			$("body").before(
				$("
")
					.attr({id: "productMapSelector"})
					.addClass("commit-tease")
					.html(
						$("")
							.attr({src: chrome.extension.getURL("icon.png")})
							.css({height: '1.5em', margin: '0 5px', 'vertical-align': 'text-bottom'})
					)
					.append("Bugzilla product not set.  Loading products...")
			);

			bugzilla.getProducts().done(function(response) {
				var products = response[0].products.sort(function(a, b) {
					return (a.name  b.name ? 1 : 0));
				});
				$("div#productMapSelector")
					.html(
						$("")
							.attr({src: chrome.extension.getURL("icon.png")})
							.css({height: '1.5em', margin: '0 5px', 'vertical-align': 'text-bottom'})
					)
					.append("Please choose the Bugzilla product this repo is associated with:")
					.append(
						$("<select>")
							.addClass("form-control input-sm")
							.css("margin", "0 5px")
							.append("<option>")
							.append(
								$.map(products, function(el, i) {
									return $("<option>").val(el.name).html(el.name);
								})
							)
					)
					.append(
						$("<button>")
							.html("OK")
							.addClass("btn btn-sm btn-primary")
							.click(function() {
								var selectedProduct = $(this).prev().val();
								productMap[repo] = {
									name: selectedProduct
								};
								chrome.storage.sync.set({productMap: productMap}, function(obj) {
									$("#productMapSelector").remove();
								});
							})
					)
					.append(
						$("<button>")
							.html("Cancel")
							.addClass("btn btn-sm")
							.css("margin", "0 5px")
							.click(function() {
								$("#productMapSelector").remove();
							})
					);
			});
		}

		function syncIssues() {
			chrome.storage.local.get('bugs', function(obj) {
				var bugs = obj.bugs[repo] || [];
				var $spans = $("a[href$='/issues']:not([href^='/issues'])").children("span");
				var numTotal = bugs.length;
				if ($spans.eq(0).html() === "Issues") {
					var numIssues = parseInt($spans.eq(1).html(), 10);
					if (productMap[repo]) {
						productMap[repo].numIssues = numIssues;
					}
					numTotal += numIssues;
					$spans.eq(0).html("Issues/Bugs");
				}
				else if (productMap[repo]) {
					numTotal += productMap[repo].numIssues;
				}

				$spans.eq(1).html(numTotal);
			});
		}

		syncIssues();

		$("body")
			/* Lists bugs from Bugzilla in the Issues section */
			.off("click.DITBugzillaGitHub", "a[href$='/issues']:not([href^='/issues'])")
			.on("click.DITBugzillaGitHub", "a[href$='/issues']:not([href^='/issues'])", function() {
				if (!productMap[repo]) {
					return;
				}
				bugzilla.searchBugs({
					product: [productMap[repo].name],
					status: ['NEW','ASSIGNED','REOPENED']
				})
				.done(function(response) {
					var bugs = response[0].bugs;

					if (bugs.length > 0) {
						// Make sure the issues list is not empty
						$("div.blankslate")
							.hide()
							.after(
								$('
')
							);

						// Update the numbers
						var bugStruct = {};
						bugStruct[repo] = bugs;
						chrome.storage.local.set({bugs: bugStruct}, function() {
							syncIssues();
						});
					}

					var $ul = $("ul.table-list-issues");

					$.each(response[0].bugs, function(){
						$ul.append(
							$('
')
								.append('')
								.append('
')
								.append(
									$('
')
										.append(
											$('')
												.append('[' + this.id + '] ' + this.summary)
										)
										.append(
											$('
')
												.append('Bug reported <time datetime="' + this.creation_time + '" is="relative-time"></time> by ' + this.creator + '')
												.append(
													$('')
														.append(
															$('')
																.append('<svg aria-hidden="true" class="octicon octicon-milestone" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M8 2H6V0h2v2z m4 5H2c-0.55 0-1-0.45-1-1V4c0-0.55 0.45-1 1-1h10l2 2-2 2zM8 4H6v2h2V4z m-2 12h2V8H6v8z"></path></svg>')
																.append(' ' + this.target_milestone + '')
          												)
          										)
										)
								)
								.append('
')
								.append('
')
						);
					});
				});
			})
	}
}<commit_msg>[MISC] making product selector sticky<commit_after>/**
 * Here, we're setting up a map between Bugzilla product and GitHub repo in the user's storage.
 */
var productMap = {};
chrome.storage.sync.get('productMap', function (obj) {
	if (obj && obj.productMap) {
		productMap = obj.productMap;
	}
});

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
	switch (request.message) {
		/* This will reinitialize the plugin when the extension button is pressed */
		case "clicked_browser_action":
			init();
			break;
		/* This will reinitialize the plugin when the tab is updated */
		case "tab_updated":
			chrome.storage.sync.get('productMap', function (obj) {
				if (obj && obj.productMap) {
					productMap = obj.productMap;
				}
				init();
			});
			break;
	}
});

function init() {
	"use strict";
	// This object will be used to interact with Bugzilla
	var bugzilla = new Bugzilla();

	// Check the URL to determine if we're in Bugzilla or GitHub
	if (location.href.indexOf("bugzilla") > -1) {
		// We're in Bugzilla

		var url = $('#cf_pull_request_number').val();

		if (url && url.length) {
			var urlArray = url.split('/');
			var pr = urlArray[urlArray.length - 1];

			/* This will put the pull request # as a link next to the bug title */
			if (url) {
				var $bugTitle = $('#summary_alias_container');

				if ($($bugTitle[0].previousSibling).is("A")) {
					$($bugTitle[0].previousSibling).remove();
				}

				$bugTitle[0].previousSibling.textContent = " - ";

				$bugTitle.before(
					$("")
						.attr({
							"href": url
						})
						.html('[#' + pr + ']')
				);
			}
		}
	}
	else if (location.href.indexOf("github") > -1) {
		// We're in GitHub

		var repo = location.href.replace(/.*.com\//, '').split('/')[1];

		var REGEX = /^\[(\d+)\]|^(\d+)|^Bug\s*(\d+)/; // for example, matches [83508], 83508, Bug83508 or Bug 83508
		var $issueTitle = $('.js-issue-title');
		var bugUrl = "https://bugzilla.dtec.com/show_bug.cgi?id=";

		if ($issueTitle.length) {
			var matches = $issueTitle.html().match(REGEX);

			if (matches && matches.length) {
				var bugId = matches[0].match(/\d+/)[0];
				bugUrl += bugId;

				/* This will turn the bug number into a link to the bug */
				$issueTitle.html(
					$issueTitle.html().replace(REGEX, '[' + bugId + ']')
				);

				/* This will put a section on the side of the page for displaying info from Bugzilla */
				$("#partial-discussion-sidebar").prepend(
						$("
")
							.addClass("discussion-sidebar-item sidebar-dit-bugzilla")
							.append(
								$("
")
									.addClass("discussion-sidebar-heading")
									.html("Bugzilla ")
									.append(
										$("")
											.attr("href", bugUrl)
											.html("[" + bugId + "]")
									)
							)
							.append(
								$("
")
									.html(
										$('
')
											.html("Loading...")
									)
							)
				);

				/* Put Bugzilla bug info into side section */
				bugzilla.getBug(bugId).done(function(response) {
					var bugInfo = response[0].bugs[0];

					$(".sidebar-dit-bugzilla div")
						.html(
							$('
')
								.html("Status: " + bugInfo.status)
						)
						.append(
							$('
')
								.html("Resolution: " + bugInfo.resolution)
						)
						.append(
							$('
')
								.html("LOE: " + bugInfo.estimated_time)
						)
						.append(
							$('
')
								.html("Charge Code: " + bugInfo.cf_chargecode)
						)
						.append(
							$('
')
								.html("Assignee: " + bugInfo.assigned_to)
						)
						.append(
							$('
')
								.html("QA Contact: " + bugInfo.qa_contact)
						);
				});

				/* This will modify the comment form to allow entering Hours Worked and update Bugzilla with the comment */
				$("#workTime").remove();
				$("#partial-new-comment-form-actions button")
					.last()
						.after(
							$("")
								.text("Hours Worked")
								.attr({
									for: "workTime"
								})
								.css({
									float: "right",
									padding: "7px 0"
								})
						)
						.after(
							$("<input>")
								.attr({
									name: "workTime",
									id: "workTime",
									type: "number",
									step: "0.5"
								})
								.css({
									width: "2.5em",
									float: "right",
									margin: "5px"
								})
						);

				$("body")
					/* Syncs comments with the bug in Bugzilla */
					.off("click.DITBugzillaGitHub", "#partial-new-comment-form-actions button")
					.on("click.DITBugzillaGitHub", "#partial-new-comment-form-actions button", function() {
						bugzilla.addComment(bugId, $("#new_comment_field").val(), $("#workTime").val());
					})

					/* Syncs line comments with the bug in Bugzilla */
					.off("click.DITBugzillaGitHub", ".js-inline-comment-form button[type='submit']")
					.on("click.DITBugzillaGitHub", ".js-inline-comment-form button[type='submit']", function() {
						var $form = $(this).closest("form");
						var comment = $form.find("textarea").val();
						var line = $form.find("[name='line']").val();
						var path = $form.find("[name='path']").val();
						bugzilla.addComment(bugId, path + " line " + line + ": " + comment, 0);
					})

					/* Updates the code status in Bugzilla when merging a pull request */
					.off("click.DITBugzillaGitHub", "button[type='submit'].js-merge-commit-button")
					.on("click.DITBugzillaGitHub", "button[type='submit'].js-merge-commit-button", function() {
						var newCodeStatus;
						var comment = "Merged pull request " + $(".gh-header-number").html();
						var mergeTarget = $(".current-branch").eq(0).children().html();

						if (mergeTarget === "master") {
							newCodeStatus = "Merged to master/trunk";
							comment += " to master.";
						}
						else {
							newCodeStatus = "Merged to parent branch";
							comment += " to parent branch.";
						}

						bugzilla.updateBug(bugId, {"cf_codestatus": newCodeStatus, "comment": {"body": comment}});
					});
			}
		}

		if (repo && repo.length > 0 && !productMap[repo] && $("#productMapSelector").length === 0) {
			$("body").before(
				$("
")
					.attr({id: "productMapSelector"})
					.addClass("commit-tease js-sticky")
					.css("z-index", 10)
					.html(
						$("")
							.attr({src: chrome.extension.getURL("icon.png")})
							.css({height: '1.5em', margin: '0 5px', 'vertical-align': 'text-bottom'})
					)
					.append("Bugzilla product not set.  Loading products...")
			);

			bugzilla.getProducts().done(function(response) {
				var products = response[0].products.sort(function(a, b) {
					return (a.name  b.name ? 1 : 0));
				});
				$("div#productMapSelector")
					.html(
						$("")
							.attr({src: chrome.extension.getURL("icon.png")})
							.css({height: '1.5em', margin: '0 5px', 'vertical-align': 'text-bottom'})
					)
					.append("Please choose the Bugzilla product this repo is associated with:")
					.append(
						$("<select>")
							.addClass("form-control input-sm")
							.css("margin", "0 5px")
							.append("<option>")
							.append(
								$.map(products, function(el, i) {
									return $("<option>").val(el.name).html(el.name);
								})
							)
					)
					.append(
						$("<button>")
							.html("OK")
							.addClass("btn btn-sm btn-primary")
							.click(function() {
								var selectedProduct = $(this).prev().val();
								productMap[repo] = {
									name: selectedProduct
								};
								chrome.storage.sync.set({productMap: productMap}, function(obj) {
									$("#productMapSelector").remove();
								});
							})
					)
					.append(
						$("<button>")
							.html("Cancel")
							.addClass("btn btn-sm")
							.css("margin", "0 5px")
							.click(function() {
								$("#productMapSelector").remove();
							})
					);
			});
		}

		function syncIssues() {
			chrome.storage.local.get('bugs', function(obj) {
				var bugs = obj.bugs[repo] || [];
				var $spans = $("a[href$='/issues']:not([href^='/issues'])").children("span");
				var numTotal = bugs.length;
				if ($spans.eq(0).html() === "Issues") {
					var numIssues = parseInt($spans.eq(1).html(), 10);
					if (productMap[repo]) {
						productMap[repo].numIssues = numIssues;
					}
					numTotal += numIssues;
					$spans.eq(0).html("Issues/Bugs");
				}
				else if (productMap[repo]) {
					numTotal += productMap[repo].numIssues;
				}

				$spans.eq(1).html(numTotal);
			});
		}

		syncIssues();

		$("body")
			/* Lists bugs from Bugzilla in the Issues section */
			.off("click.DITBugzillaGitHub", "a[href$='/issues']:not([href^='/issues'])")
			.on("click.DITBugzillaGitHub", "a[href$='/issues']:not([href^='/issues'])", function() {
				if (!productMap[repo]) {
					return;
				}
				bugzilla.searchBugs({
					product: [productMap[repo].name],
					status: ['NEW','ASSIGNED','REOPENED']
				})
				.done(function(response) {
					var bugs = response[0].bugs;

					if (bugs.length > 0) {
						// Make sure the issues list is not empty
						$("div.blankslate")
							.hide()
							.after(
								$('
')
							);

						// Update the numbers
						var bugStruct = {};
						bugStruct[repo] = bugs;
						chrome.storage.local.set({bugs: bugStruct}, function() {
							syncIssues();
						});
					}

					var $ul = $("ul.table-list-issues");

					$.each(response[0].bugs, function(){
						$ul.append(
							$('
')
								.append('')
								.append('
')
								.append(
									$('
')
										.append(
											$('')
												.append('[' + this.id + '] ' + this.summary)
										)
										.append(
											$('
')
												.append('Bug reported <time datetime="' + this.creation_time + '" is="relative-time"></time> by ' + this.creator + '')
												.append(
													$('')
														.append(
															$('')
																.append('<svg aria-hidden="true" class="octicon octicon-milestone" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M8 2H6V0h2v2z m4 5H2c-0.55 0-1-0.45-1-1V4c0-0.55 0.45-1 1-1h10l2 2-2 2zM8 4H6v2h2V4z m-2 12h2V8H6v8z"></path></svg>')
																.append(' ' + this.target_milestone + '')
          												)
          										)
										)
								)
								.append('
')
								.append('
')
						);
					});
				});
			})
	}
}<|endoftext|>


<commit_before>'use strict';

var Stream = require('stream');
var Path = require('path');
var gutil = require('gulp-util');
var readLine = require('linebyline');

function gulTtranslationToolSrt(options)
{

    options.mode = options.mode || 'toXML';

    var stream = new Stream.Transform({objectMode: true}),
        lastWasTextLine = false;

    function parsePath(path)
    {
        var extname = Path.extname(path);
        return {
            dirname: Path.dirname(path),
            basename: Path.basename(path, extname),
            extname: extname
        };
    }

    function returnNewFile(originalFile, extension, options, content, callback)
    {
        var parsedPath,
            basename,
            newFile,
            newFilePath;

        parsedPath = parsePath(originalFile.relative);

        switch (true)
        {
            case (typeof options.name === 'string' && options.name.length > 0):
                basename = options.name;
                break;
            case (typeof options.name === 'function'):
                basename = options.name(parsedPath.basename);
                break;
            default:
                basename = parsedPath.basename;
                break;
        }

        newFilePath = Path.join(parsedPath.dirname, basename + extension);

        newFile = new gutil.File({
            contents: new Buffer(content),
            path: Path.join('./', newFilePath)
        });

        // RETURN NEW FILE
        callback(null, newFile);

    }

    stream._transform = function (file, unused, callback) {

        var newFileExtension,
            newFileBuffer = '',
            readLineTool;

        switch (options.mode.toLowerCase())
        {
            case 'tosrt':
                // region TO SRT
                newFileExtension = '.srt';

                readLineTool = readLine(file.path);
                readLineTool.on('line', function (line, lineCount, byteCount) {

                    var myregexp,
                        match;

                    myregexp = /^\s*<text id="(\d+)" time="(\d\d:\d\d:\d\d,\d\d\d --# \d\d:\d\d:\d\d,\d\d\d)"><!\[CDATA\[(.*)\]\]><\/text>$/g;
                    match = myregexp.exec(line);

                    while (match !== null && match.length === 4)
                    {
                        newFileBuffer += match[1] + '\r\n';
                        newFileBuffer += match[2].replace(/--#/g, '-->') + '\r\n';
                        newFileBuffer += match[3].replace(/]]>
<!\[CDATA\[/g, '\r\n') + '\r\n';
                        newFileBuffer += '\r\n';

                        match = myregexp.exec(line);
                    }

                }).on('error', function () {

                    callback(new Error('gulp-translation-tool-srt | readline error'), undefined);

                }).on('end', function () {

                    returnNewFile(file, newFileExtension, options, newFileBuffer, callback);

                });
                break;
            // endregion

            case 'toxml':
            default:
                // region TO XML
                newFileExtension = '.xml';
                newFileBuffer += '<?xml version="1.0" encoding="utf-8"?>\r\n<languageData>\r\n\t<group name="' + parsePath(file.relative).basename + '">';

                readLineTool = readLine(file.path);
                readLineTool.on('line', function (line, lineCount, byteCount) {
                    switch (true)
                    {
                        case /^\s*(\d+)\s*$/.test(line):
                            // ID
                            newFileBuffer += '\r\n\t\t<text id="' + line.replace(/^\s*(\d+)\s*$/, '$1') + '"'; // Start <text/> node
                            lastWasTextLine = false;
                            break;
                        case /^(\d\d:\d\d:\d\d,\d\d\d --> \d\d:\d\d:\d\d,\d\d\d)\s*$/.test(line):
                            // TIME
                            newFileBuffer += ' time="' + line.replace(/^(\d\d:\d\d:\d\d,\d\d\d --> \d\d:\d\d:\d\d,\d\d\d)\s*$/, '$1').replace(/-->/g, '--#') + '"><![CDATA['; // Write Time
                            lastWasTextLine = false;
                            break;
                        case /^\s*$/.test(line):
                            // EMPTY
                            if (lastWasTextLine === true)
                            {
                                newFileBuffer += ']]></text>';// Close <text/> node
                                lastWasTextLine = false;
                            }
                            break;
                        default:
                            // TEXT
                            if (/"><!\[CDATA\[$/.test(newFileBuffer))
                            {
                                newFileBuffer += ''; // Close <text_>_ node
                            } else
                            {
                                newFileBuffer += ']]>
<![CDATA['; // new line
                            }
                            newFileBuffer += line;
                            lastWasTextLine = true;
                            break;
                    }

                }).on('error', function () {

                    callback(new Error('gulp-translation-tool-srt | readline error'), undefined);

                }).on('end', function () {
                    if (!/]]><\/text>$/.test(newFileBuffer))
                    {
                        newFileBuffer += ']]></text>';// Close <text/> node
                    }
                    newFileBuffer += '\r\n\t</group>\r\n</languageData>'; // END

                    lastWasTextLine = false;

                    returnNewFile(file, newFileExtension, options, newFileBuffer, callback);

                });

                break;
            // endregion
        }

    };

    return stream;
}

module.exports = gulTtranslationToolSrt;
<commit_msg>Clean up TT [BR]<commit_after>'use strict';

var Stream = require('stream');
var Path = require('path');
var gutil = require('gulp-util');
var readLine = require('linebyline');

function gulTtranslationToolSrt(options)
{

    options = options || {};
    options.mode = options.mode || 'toXML';

    var stream = new Stream.Transform({objectMode: true}),
        lastWasTextLine = false;

    function parsePath(path)
    {
        var extname = Path.extname(path);
        return {
            dirname: Path.dirname(path),
            basename: Path.basename(path, extname),
            extname: extname
        };
    }

    function returnNewFile(originalFile, extension, options, content, callback)
    {
        var parsedPath,
            basename,
            newFile,
            newFilePath;

        parsedPath = parsePath(originalFile.relative);

        switch (true)
        {
            case (typeof options.name === 'string' && options.name.length > 0):
                basename = options.name;
                break;
            case (typeof options.name === 'function'):
                basename = options.name(parsedPath.basename);
                break;
            default:
                basename = parsedPath.basename;
                break;
        }

        newFilePath = Path.join(parsedPath.dirname, basename + extension);

        newFile = new gutil.File({
            contents: new Buffer(content),
            path: Path.join('./', newFilePath)
        });

        // RETURN NEW FILE
        callback(null, newFile);

    }

    stream._transform = function (file, unused, callback) {

        var newFileExtension,
            newFileBuffer = '',
            readLineTool;

        switch (options.mode.toLowerCase())
        {
            case 'tosrt':
                // region TO SRT
                newFileExtension = '.srt';

                readLineTool = readLine(file.path);
                readLineTool.on('line', function (line, lineCount, byteCount) {

                    var myregexp,
                        match;

                    myregexp = /^\s*<text id="(\d+)" time="(\d\d:\d\d:\d\d,\d\d\d --# \d\d:\d\d:\d\d,\d\d\d)"><!\[CDATA\[(.*)\]\]><\/text>$/g;
                    match = myregexp.exec(line);

                    while (match !== null && match.length === 4)
                    {
                        newFileBuffer += match[1] + '\r\n';
                        newFileBuffer += match[2].replace(/--#/g, '-->') + '\r\n';
                        newFileBuffer += match[3].replace(/]]>
<!\[CDATA\[/g, '\r\n').replace(/\[BR\]/g, '') + '\r\n';
                        newFileBuffer += '\r\n';

                        match = myregexp.exec(line);
                    }

                }).on('error', function () {

                    callback(new Error('gulp-translation-tool-srt | readline error'), undefined);

                }).on('end', function () {

                    returnNewFile(file, newFileExtension, options, newFileBuffer, callback);

                });
                break;
            // endregion

            case 'toxml':
            default:
                // region TO XML
                newFileExtension = '.xml';
                newFileBuffer += '<?xml version="1.0" encoding="utf-8"?>\r\n<languageData>\r\n\t<group name="' + parsePath(file.relative).basename + '">';

                readLineTool = readLine(file.path);
                readLineTool.on('line', function (line, lineCount, byteCount) {
                    switch (true)
                    {
                        case /^\s*(\d+)\s*$/.test(line):
                            // ID
                            newFileBuffer += '\r\n\t\t<text id="' + line.replace(/^\s*(\d+)\s*$/, '$1') + '"'; // Start <text/> node
                            lastWasTextLine = false;
                            break;
                        case /^(\d\d:\d\d:\d\d,\d\d\d --> \d\d:\d\d:\d\d,\d\d\d)\s*$/.test(line):
                            // TIME
                            newFileBuffer += ' time="' + line.replace(/^(\d\d:\d\d:\d\d,\d\d\d --> \d\d:\d\d:\d\d,\d\d\d)\s*$/, '$1').replace(/-->/g, '--#') + '"><![CDATA['; // Write Time
                            lastWasTextLine = false;
                            break;
                        case /^\s*$/.test(line):
                            // EMPTY
                            if (lastWasTextLine === true)
                            {
                                newFileBuffer += ']]></text>';// Close <text/> node
                                lastWasTextLine = false;
                            }
                            break;
                        default:
                            // TEXT
                            if (/"><!\[CDATA\[$/.test(newFileBuffer))
                            {
                                newFileBuffer += ''; // Close <text_>_ node
                            } else
                            {
                                newFileBuffer += ']]>
<![CDATA['; // new line
                            }
                            newFileBuffer += line;
                            lastWasTextLine = true;
                            break;
                    }

                }).on('error', function () {

                    callback(new Error('gulp-translation-tool-srt | readline error'), undefined);

                }).on('end', function () {
                    if (!/]]><\/text>$/.test(newFileBuffer))
                    {
                        newFileBuffer += ']]></text>';// Close <text/> node
                    }
                    newFileBuffer += '\r\n\t</group>\r\n</languageData>'; // END

                    lastWasTextLine = false;

                    returnNewFile(file, newFileExtension, options, newFileBuffer, callback);

                });

                break;
            // endregion
        }

    };

    return stream;
}

module.exports = gulTtranslationToolSrt;
<|endoftext|>


<commit_before>const test = require('tape')
const { handleMessages } = require('./utils')
const canvasApi = require('../../canvasApi')
const randomstring = require('randomstring')
const promisify = require('promisify')

async function createCourse (sisCourseId) {
  const ACCOUNT_ID = 14
  const course = {
    name: `Integration test ${sisCourseId}`,
    course_code: 'Integration test',
    sis_course_id: sisCourseId
  }

  const canvasCourse = await canvasApi.createCourse({course}, ACCOUNT_ID)
  await canvasApi.createDefaultSection(canvasCourse)

  return canvasCourse
}

async function createUser () {
  const kthId = `v${randomstring.generate(7)}`
  const email = `${kthId}@kth.se`
  await canvasApi.createUser({
    pseudonym: {
      unique_id: kthId,
      sis_user_id: kthId,
      skip_registration: true,
      send_confirmation: false
    },
    user: {
      name: 'Integration test',
      sortable_name: 'Integration test'
    },
    communication_channel: {
      type: 'email',
      address: email,
      skip_confirmation: true
    },
    enable_sis_reactivation: false
  })

  return kthId
}

test('should enroll an assistant in an existing course in canvas', async t => {
  t.plan(1)

  // Create the "existing course" and the "assistant" in Canvas
  // Course code should be 6 characters long
  const courseCode = 'A' + randomstring.generate(5)
  const assistantId = await createUser()
  const canvasCourse = await createCourse(courseCode + 'VT171')

  const message = {
    ugClass: 'group',
    ug1Name: `edu.courses.SF.${courseCode}.20171.1.assistants`,
    member: [assistantId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)
  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, assistantId)
})

test('should enroll an employee in Miljöutbildningen and Canvas at KTH', async t => {
  t.plan(2)
  const muId = 5014 // Miljöutbildningen
  const ckId = 85 // Canvas at KTH

  // Create the "employee" in Canvas
  const employeeId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: 'app.katalog3.A',
    member: [employeeId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  const muEnrollments = await canvasApi.get(`courses/${muId}/enrollments?sis_section_id[]=app.katalog3.A.section1`)
  const ckEnrollments = await canvasApi.get(`courses/${ckId}/enrollments?sis_section_id[]=app.katalog3.A.section2`)

  t.ok(
    muEnrollments.find(e => e.user.sis_user_id === employeeId),
    `The user ${employeeId} is not correctly enrolled in Miljöutbildningen`
  )

  t.ok(
    ckEnrollments.find(e => e.user.sis_user_id === employeeId),
    `The user ${employeeId} is not correctly enrolled in Canvas at KTH`
  )
})

test('should enroll a re-registered student in an existing course in Canvas', async t => {
  t.plan(1)
  const cc0 = 'A' + randomstring.generate(1)
  const cc1 = randomstring.generate(4)

  const canvasCourse = await createCourse(cc0 + cc1 + 'VT173')
  const studentId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: `ladok2.kurser.${cc0}.${cc1}.omregistrerade_20171`,
    member: [studentId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, studentId)
})

test('should enroll a student in an existing course', async t => {
  t.plan(1)
  const cc0 = 'A' + randomstring.generate(1)
  const cc1 = randomstring.generate(4)

  const canvasCourse = await createCourse(cc0 + cc1 + 'VT171')
  const studentId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: `ladok2.kurser.${cc0}.${cc1}.registrerade_20171.1`,
    member: [studentId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, studentId)
})

test('should not enroll an antagen', async t => {
  t.plan(1)
  const cc0 = 'A' + randomstring.generate(1)
  const cc1 = randomstring.generate(4)

  const canvasCourse = await createCourse(cc0 + cc1 + 'VT181')
  const studentId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: `ladok2.kurser.${cc0}.${cc1}.antagna_20181.1`,
    member: [studentId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  await promisify(setTimeout)(5000)
  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, studentId)
})
<commit_msg>Fix dependency of promisify<commit_after>const test = require('tape')
const { handleMessages } = require('./utils')
const canvasApi = require('../../canvasApi')
const randomstring = require('randomstring')
const { promisify } = require('util')

async function createCourse (sisCourseId) {
  const ACCOUNT_ID = 14
  const course = {
    name: `Integration test ${sisCourseId}`,
    course_code: 'Integration test',
    sis_course_id: sisCourseId
  }

  const canvasCourse = await canvasApi.createCourse({course}, ACCOUNT_ID)
  await canvasApi.createDefaultSection(canvasCourse)

  return canvasCourse
}

async function createUser () {
  const kthId = `v${randomstring.generate(7)}`
  const email = `${kthId}@kth.se`
  await canvasApi.createUser({
    pseudonym: {
      unique_id: kthId,
      sis_user_id: kthId,
      skip_registration: true,
      send_confirmation: false
    },
    user: {
      name: 'Integration test',
      sortable_name: 'Integration test'
    },
    communication_channel: {
      type: 'email',
      address: email,
      skip_confirmation: true
    },
    enable_sis_reactivation: false
  })

  return kthId
}

test('should enroll an assistant in an existing course in canvas', async t => {
  t.plan(1)

  // Create the "existing course" and the "assistant" in Canvas
  // Course code should be 6 characters long
  const courseCode = 'A' + randomstring.generate(5)
  const assistantId = await createUser()
  const canvasCourse = await createCourse(courseCode + 'VT171')

  const message = {
    ugClass: 'group',
    ug1Name: `edu.courses.SF.${courseCode}.20171.1.assistants`,
    member: [assistantId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)
  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, assistantId)
})

test('should enroll an employee in Miljöutbildningen and Canvas at KTH', async t => {
  t.plan(2)
  const muId = 5014 // Miljöutbildningen
  const ckId = 85 // Canvas at KTH

  // Create the "employee" in Canvas
  const employeeId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: 'app.katalog3.A',
    member: [employeeId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  const muEnrollments = await canvasApi.get(`courses/${muId}/enrollments?sis_section_id[]=app.katalog3.A.section1`)
  const ckEnrollments = await canvasApi.get(`courses/${ckId}/enrollments?sis_section_id[]=app.katalog3.A.section2`)

  t.ok(
    muEnrollments.find(e => e.user.sis_user_id === employeeId),
    `The user ${employeeId} is not correctly enrolled in Miljöutbildningen`
  )

  t.ok(
    ckEnrollments.find(e => e.user.sis_user_id === employeeId),
    `The user ${employeeId} is not correctly enrolled in Canvas at KTH`
  )
})

test('should enroll a re-registered student in an existing course in Canvas', async t => {
  t.plan(1)
  const cc0 = 'A' + randomstring.generate(1)
  const cc1 = randomstring.generate(4)

  const canvasCourse = await createCourse(cc0 + cc1 + 'VT173')
  const studentId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: `ladok2.kurser.${cc0}.${cc1}.omregistrerade_20171`,
    member: [studentId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, studentId)
})

test('should enroll a student in an existing course', async t => {
  t.plan(1)
  const cc0 = 'A' + randomstring.generate(1)
  const cc1 = randomstring.generate(4)

  const canvasCourse = await createCourse(cc0 + cc1 + 'VT171')
  const studentId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: `ladok2.kurser.${cc0}.${cc1}.registrerade_20171.1`,
    member: [studentId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, studentId)
})

test('should not enroll an antagen', async t => {
  t.plan(1)
  const cc0 = 'A' + randomstring.generate(1)
  const cc1 = randomstring.generate(4)

  const canvasCourse = await createCourse(cc0 + cc1 + 'VT181')
  const studentId = await createUser()

  const message = {
    ugClass: 'group',
    ug1Name: `ladok2.kurser.${cc0}.${cc1}.antagna_20181.1`,
    member: [studentId]
  }

  const [{resp}] = await handleMessages(message)
  await canvasApi.pollUntilSisComplete(resp.id)

  await promisify(setTimeout)(5000)
  const enrollments = await canvasApi.getEnrollments(canvasCourse.id)
  t.equal(enrollments[0].sis_user_id, studentId)
})
<|endoftext|>