<commit_before>//URL RegEx from https://gist.github.com/dperini/729294
//http://mathiasbynens.be/demo/url-regex

//@export SchemaRegEx
SchemaRegEx = {
    Email: /^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$/,
    Url: /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i
};

//@export SimpleSchema
SimpleSchema = function(schema) {
    var self = this;
    self._schema = schema || {};
};

//@export check
check = function(/*arguments*/) {
    var args = _.toArray(arguments), invalidFields;
    if (args && _.isObject(args[0]) && args[1] instanceof SimpleSchema) {
        invalidFields = args[1].validate(args[0]);
        if (!!invalidFields.length && Match) {
            throw new Match.Error("One or more properties do not match the schema.");
        }
        return;
    }
    check.apply(null, arguments);
};

//validates doc against self._schema and returns an array of error objects
SimpleSchema.prototype.validate = function(doc) {
    var self = this, invalidFields = [];
    var isSetting = "$set" in doc;
    var isUnsetting = "$unset" in doc;

    //all fields must pass validation check
    _.each(self._schema, function(def, fieldName) {
        var fieldValue;
        var fieldLabel = def.label || fieldName;

        //first check unsetting
        if (isUnsetting && fieldName in doc.$unset) {
            fieldValue = doc.$unset[fieldName];
            if (fieldValue === void 0 || fieldValue === null || (typeof fieldValue === "string" && fieldValue.length === 0)) {
                if (!def.optional) {
                    invalidFields.push({name: fieldName, message: fieldLabel + " is required"});
                } //else it's valid, and no need to perform further checks on this field
            }
        }

        //next check setting or inserting
        if (isSetting) {
            fieldValue = doc.$set[fieldName];
        } else {
            fieldValue = doc[fieldName];
        }

        invalidFields = _.union(invalidFields, validateOne(def, fieldName, fieldLabel, fieldValue, isSetting));
    });

    return invalidFields;
};

//returns doc with all properties that are not in the schema removed
SimpleSchema.prototype.filter = function(doc) {
    //TODO make sure this works with descendent objects
    var newDoc, self = this;
    if ("$set" in doc) {
        //for $set, filter only that obj
        newDoc = doc;
        newDoc.$set = _.pick(doc.$set, _.keys(self._schema));
    } else {
        newDoc = _.pick(doc, _.keys(self._schema));
    }
    return newDoc;
};

//automatic type conversion to match desired type, if possible
SimpleSchema.prototype.autoTypeConvert = function(doc) {
    var self = this;
    _.each(self._schema, function(def, fieldName) {
        if (fieldName in doc) {
            if (_.isArray(doc[fieldName])) {
                for (var i = 0, ln = doc[fieldName].length; i < ln; i++) {
                    doc[fieldName][i] = typeconvert(doc[fieldName][i], def.type[0]); //typeconvert
                }
            } else {
                doc[fieldName] = typeconvert(doc[fieldName], def.type); //typeconvert
            }
        } else if ("$set" in doc && fieldName in doc.$set) {
            if (_.isArray(doc[fieldName])) {
                for (var i = 0, ln = doc[fieldName].length; i < ln; i++) {
                    doc.$set[fieldName][i] = typeconvert(doc.$set[fieldName][i], def.type[0]); //typeconvert
                }
            } else {
                doc.$set[fieldName] = typeconvert(doc.$set[fieldName], def.type); //typeconvert
            }
        }
    });
    return doc;
};

var validateOne = function(def, fieldName, fieldLabel, fieldValue, isSetting) {
    var invalidFields = [];
    //when inserting required fields, fieldValue must not be undefined, null, or an empty string
    //when updating ($setting) required fields, fieldValue can be undefined, but may not be null or an empty string
    if ((!isSetting && fieldValue === void 0) || fieldValue === null || (typeof fieldValue === "string" && fieldValue.length === 0)) {
        if (!def.optional) {
            invalidFields.push({name: fieldName, message: fieldLabel + " is required"});
        } //else it's valid, and no need to perform further checks on this field
        return invalidFields;
    }

    //if we got to this point and fieldValue is undefined, no more checking is necessary for this field
    if (fieldValue === void 0) {
        return invalidFields;
    }

    if (def.type === String) {
        if (typeof fieldValue !== "string") {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a string"});
        } else if (def.regEx && !def.regEx.test(fieldValue)) {
            invalidFields.push({name: fieldName, message: fieldLabel + " " + def.regExMessage});
        } else if (def.max && def.max < fieldValue.length) {
            invalidFields.push({name: fieldName, message: fieldLabel + " cannot exceed " + def.max + " characters"});
        } else if (def.min && def.min > fieldValue.length) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be at least " + def.min + " characters"});
        }
    } else if (def.type === Number) {
        if (typeof fieldValue !== "number") {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a number"});
        } else if (def.max && def.max < fieldValue) {
            invalidFields.push({name: fieldName, message: fieldLabel + " cannot exceed " + def.max});
        } else if (def.min && def.min > fieldValue) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be at least " + def.min});
        } else if (!def.decimal && fieldValue.toString().indexOf(".") > -1) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be an integer"});
        }
    } else if (def.type === Boolean) {
        if (typeof fieldValue !== "boolean") {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a boolean"});
        }
    } else if (def.type instanceof Function) {
        if (!(fieldValue instanceof def.type)) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a " + def.type.name});
        }
        if (def.type === Date) {
            if (_.isDate(def.min) && def.min.getTime() > fieldValue.getTime()) {
                invalidFields.push({name: fieldName, message: fieldLabel + " must be on or after " + dateToFieldDateString(def.min)});
            } else if (_.isDate(def.max) && def.max.getTime() < fieldValue.getTime()) {
                invalidFields.push({name: fieldName, message: fieldLabel + " must be on or before " + dateToFieldDateString(def.max)});
            }
        }
    }

    //if it's an array, loop through it and call validateOne recursively
    if (_.isArray(def.type)) {
        if (!_.isArray(fieldValue)) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be an array"});
        } else if (def.min && fieldValue.length < def.min) {
            invalidFields.push({name: fieldName, message: "You must specify at least " + def.min + " values"});
        } else if (def.max && fieldValue.length > def.max) {
            invalidFields.push({name: fieldName, message: "You cannot specify more than " + def.max + " values"});
        } else {
            //if it's an array with the right number of values, etc., then we need to go through them all and
            //validate each value in the array
            var childDef = _.clone(def), loopVal;
            childDef.type = def.type[0]; //strip array off of type
            //min and max only apply to the array
            if ("min" in childDef) {
                delete childDef.min;
            }
            if ("max" in childDef) {
                delete childDef.max;
            }
            for (var i = 0, ln = fieldValue.length; i < ln; i++) {
                loopVal = fieldValue[i];
                invalidFields = _.union(invalidFields, validateOne(childDef, fieldName, fieldLabel, loopVal, isSetting));
                if (invalidFields.length) {
                    break;
                }
            }
        }
    } else {
        //check to make sure the value is allowed
        //this is the last thing we want to do for all data types, except for arrays
        if (def.allowedValues) {
            if (!_.contains(def.allowedValues, fieldValue)) {
                invalidFields.push({name: fieldName, message: fieldValue + " is not an allowed value"});
            }
        } else if (def.valueIsAllowed && def.valueIsAllowed instanceof Function) {
            if (!def.valueIsAllowed(fieldValue)) {
                invalidFields.push({name: fieldName, message: fieldValue + " is not an allowed value"});
            }
        }
    }

    return invalidFields;
};

var dateToFieldDateString = function(date) {
    var m = (date.getUTCMonth() + 1);
    if (m < 10) {
        m = "0" + m;
    }
    var d = date.getUTCDate();
    if (d < 10) {
        d = "0" + d;
    }
    return date.getUTCFullYear() + '-' + m + '-' + d;
};

var typeconvert = function(value, type) {
    if (type === String) {
        if (typeof value !== "string") {
            return value.toString();
        }
        return value;
    }
    if (type === Number) {
        if (typeof value === "string") {
            //try to convert numeric strings to numbers
            var floatVal = parseFloat(value);
            if (!isNaN(floatVal)) {
                return floatVal;
            } else {
                return value; //leave string; will fail validation
            }
        }
        return value;
    }
    return value;
};<commit_msg>minor logic tweak<commit_after>//URL RegEx from https://gist.github.com/dperini/729294
//http://mathiasbynens.be/demo/url-regex

//@export SchemaRegEx
SchemaRegEx = {
    Email: /^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$/,
    Url: /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:\/[^\s]*)?$/i
};

//@export SimpleSchema
SimpleSchema = function(schema) {
    var self = this;
    self._schema = schema || {};
};

//@export check
check = function(/*arguments*/) {
    var args = _.toArray(arguments), invalidFields;
    if (args && _.isObject(args[0]) && args[1] instanceof SimpleSchema) {
        invalidFields = args[1].validate(args[0]);
        if (invalidFields.length && Match) {
            throw new Match.Error("One or more properties do not match the schema.");
        }
        return;
    }
    check.apply(null, arguments);
};

//validates doc against self._schema and returns an array of error objects
SimpleSchema.prototype.validate = function(doc) {
    var self = this, invalidFields = [];
    var isSetting = "$set" in doc;
    var isUnsetting = "$unset" in doc;

    //all fields must pass validation check
    _.each(self._schema, function(def, fieldName) {
        var fieldValue;
        var fieldLabel = def.label || fieldName;

        //first check unsetting
        if (isUnsetting && fieldName in doc.$unset) {
            fieldValue = doc.$unset[fieldName];
            if (fieldValue === void 0 || fieldValue === null || (typeof fieldValue === "string" && fieldValue.length === 0)) {
                if (!def.optional) {
                    invalidFields.push({name: fieldName, message: fieldLabel + " is required"});
                } //else it's valid, and no need to perform further checks on this field
            }
        }

        //next check setting or inserting
        if (isSetting) {
            fieldValue = doc.$set[fieldName];
        } else {
            fieldValue = doc[fieldName];
        }

        invalidFields = _.union(invalidFields, validateOne(def, fieldName, fieldLabel, fieldValue, isSetting));
    });

    return invalidFields;
};

//returns doc with all properties that are not in the schema removed
SimpleSchema.prototype.filter = function(doc) {
    //TODO make sure this works with descendent objects
    var newDoc, self = this;
    if ("$set" in doc) {
        //for $set, filter only that obj
        newDoc = doc;
        newDoc.$set = _.pick(doc.$set, _.keys(self._schema));
    } else {
        newDoc = _.pick(doc, _.keys(self._schema));
    }
    return newDoc;
};

//automatic type conversion to match desired type, if possible
SimpleSchema.prototype.autoTypeConvert = function(doc) {
    var self = this;
    _.each(self._schema, function(def, fieldName) {
        if (fieldName in doc) {
            if (_.isArray(doc[fieldName])) {
                for (var i = 0, ln = doc[fieldName].length; i < ln; i++) {
                    doc[fieldName][i] = typeconvert(doc[fieldName][i], def.type[0]); //typeconvert
                }
            } else {
                doc[fieldName] = typeconvert(doc[fieldName], def.type); //typeconvert
            }
        } else if ("$set" in doc && fieldName in doc.$set) {
            if (_.isArray(doc[fieldName])) {
                for (var i = 0, ln = doc[fieldName].length; i < ln; i++) {
                    doc.$set[fieldName][i] = typeconvert(doc.$set[fieldName][i], def.type[0]); //typeconvert
                }
            } else {
                doc.$set[fieldName] = typeconvert(doc.$set[fieldName], def.type); //typeconvert
            }
        }
    });
    return doc;
};

var validateOne = function(def, fieldName, fieldLabel, fieldValue, isSetting) {
    var invalidFields = [];
    //when inserting required fields, fieldValue must not be undefined, null, or an empty string
    //when updating ($setting) required fields, fieldValue can be undefined, but may not be null or an empty string
    if ((!isSetting && fieldValue === void 0) || fieldValue === null || (typeof fieldValue === "string" && fieldValue.length === 0)) {
        if (!def.optional) {
            invalidFields.push({name: fieldName, message: fieldLabel + " is required"});
        } //else it's valid, and no need to perform further checks on this field
        return invalidFields;
    }

    //if we got to this point and fieldValue is undefined, no more checking is necessary for this field
    if (fieldValue === void 0) {
        return invalidFields;
    }

    if (def.type === String) {
        if (typeof fieldValue !== "string") {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a string"});
        } else if (def.regEx && !def.regEx.test(fieldValue)) {
            invalidFields.push({name: fieldName, message: fieldLabel + " " + def.regExMessage});
        } else if (def.max && def.max < fieldValue.length) {
            invalidFields.push({name: fieldName, message: fieldLabel + " cannot exceed " + def.max + " characters"});
        } else if (def.min && def.min > fieldValue.length) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be at least " + def.min + " characters"});
        }
    } else if (def.type === Number) {
        if (typeof fieldValue !== "number") {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a number"});
        } else if (def.max && def.max < fieldValue) {
            invalidFields.push({name: fieldName, message: fieldLabel + " cannot exceed " + def.max});
        } else if (def.min && def.min > fieldValue) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be at least " + def.min});
        } else if (!def.decimal && fieldValue.toString().indexOf(".") > -1) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be an integer"});
        }
    } else if (def.type === Boolean) {
        if (typeof fieldValue !== "boolean") {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a boolean"});
        }
    } else if (def.type instanceof Function) {
        if (!(fieldValue instanceof def.type)) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be a " + def.type.name});
        }
        if (def.type === Date) {
            if (_.isDate(def.min) && def.min.getTime() > fieldValue.getTime()) {
                invalidFields.push({name: fieldName, message: fieldLabel + " must be on or after " + dateToFieldDateString(def.min)});
            } else if (_.isDate(def.max) && def.max.getTime() < fieldValue.getTime()) {
                invalidFields.push({name: fieldName, message: fieldLabel + " must be on or before " + dateToFieldDateString(def.max)});
            }
        }
    }

    //if it's an array, loop through it and call validateOne recursively
    if (_.isArray(def.type)) {
        if (!_.isArray(fieldValue)) {
            invalidFields.push({name: fieldName, message: fieldLabel + " must be an array"});
        } else if (def.min && fieldValue.length < def.min) {
            invalidFields.push({name: fieldName, message: "You must specify at least " + def.min + " values"});
        } else if (def.max && fieldValue.length > def.max) {
            invalidFields.push({name: fieldName, message: "You cannot specify more than " + def.max + " values"});
        } else {
            //if it's an array with the right number of values, etc., then we need to go through them all and
            //validate each value in the array
            var childDef = _.clone(def), loopVal;
            childDef.type = def.type[0]; //strip array off of type
            //min and max only apply to the array
            if ("min" in childDef) {
                delete childDef.min;
            }
            if ("max" in childDef) {
                delete childDef.max;
            }
            for (var i = 0, ln = fieldValue.length; i < ln; i++) {
                loopVal = fieldValue[i];
                invalidFields = _.union(invalidFields, validateOne(childDef, fieldName, fieldLabel, loopVal, isSetting));
                if (invalidFields.length) {
                    break;
                }
            }
        }
    } else {
        //check to make sure the value is allowed
        //this is the last thing we want to do for all data types, except for arrays
        if (def.allowedValues) {
            if (!_.contains(def.allowedValues, fieldValue)) {
                invalidFields.push({name: fieldName, message: fieldValue + " is not an allowed value"});
            }
        } else if (def.valueIsAllowed && def.valueIsAllowed instanceof Function) {
            if (!def.valueIsAllowed(fieldValue)) {
                invalidFields.push({name: fieldName, message: fieldValue + " is not an allowed value"});
            }
        }
    }

    return invalidFields;
};

var dateToFieldDateString = function(date) {
    var m = (date.getUTCMonth() + 1);
    if (m < 10) {
        m = "0" + m;
    }
    var d = date.getUTCDate();
    if (d < 10) {
        d = "0" + d;
    }
    return date.getUTCFullYear() + '-' + m + '-' + d;
};

var typeconvert = function(value, type) {
    if (type === String) {
        if (typeof value !== "string") {
            return value.toString();
        }
        return value;
    }
    if (type === Number) {
        if (typeof value === "string") {
            //try to convert numeric strings to numbers
            var floatVal = parseFloat(value);
            if (!isNaN(floatVal)) {
                return floatVal;
            } else {
                return value; //leave string; will fail validation
            }
        }
        return value;
    }
    return value;
};<|endoftext|>


<commit_before>/**
* Copyright 2016 PT Inovação e Sistemas SA
* Copyright 2016 INESC-ID
* Copyright 2016 QUOBIS NETWORKS SL
* Copyright 2016 FRAUNHOFER-GESELLSCHAFT ZUR FOERDERUNG DER ANGEWANDTEN FORSCHUNG E.V
* Copyright 2016 ORANGE SA
* Copyright 2016 Deutsche Telekom AG
* Copyright 2016 Apizee
* Copyright 2016 TECHNISCHE UNIVERSITAT BERLIN
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

// Service Framework
import IdentityManager from 'service-framework/dist/IdentityManager';
import Discovery from 'service-framework/dist/Discovery';
import {Syncher} from 'service-framework/dist/Syncher';

// Utils
import {divideURL} from '../utils/utils';
import Search from '../utils/Search';

// Internals
import { communicationObject, CommunicationStatus, communicationChildren } from './communication';
import ChatController from './ChatController';
import { UserInfo } from './UserInfo';

/**
* Hyperty Group Chat Manager API (HypertyChat)
* @author Vitor Silva [vitor-t-silva@telecom.pt]
* @version 0.1.0
*/
class GroupChatManager {

  constructor(hypertyURL, bus, configuration) {
    if (!hypertyURL) throw new Error('[GroupChatManager.constructor] The hypertyURL is a needed parameter');
    if (!bus) throw new Error('[GroupChatManager.constructor] The MiniBus is a needed parameter');
    if (!configuration) throw new Error('[GroupChatManager.constructor] The configuration is a needed parameter');

    let _this = this;
    let syncher = new Syncher(hypertyURL, bus, configuration);

    let domain = divideURL(hypertyURL).domain;
    let discovery = new Discovery(hypertyURL, configuration.runtimeURL, bus);
    let identityManager = new IdentityManager(hypertyURL, configuration.runtimeURL, bus);

    _this._objectDescURL = 'hyperty-catalogue://catalogue.' + domain + '/.well-known/dataschema/Communication';

    _this._reportersControllers = {};
    _this._observersControllers = {};

    _this._hypertyURL = hypertyURL;
    _this._bus = bus;
    _this._syncher = syncher;
    _this._domain = domain;

    _this.discovery = discovery;
    _this.identityManager = identityManager;

    _this.search = new Search(discovery, identityManager);

    _this.communicationObject = communicationObject;

    _this.communicationChildren = communicationChildren;

    console.log('[GroupChatManager] Discover ', discovery);
    console.log('[GroupChatManager] Identity Manager ', identityManager);

    syncher.resumeReporters({store: true}).then((reporters) => {

      let reportersList = Object.keys(reporters);

      if (reportersList.length  > 0) {

      Object.keys(reporters).forEach((dataObjectReporterURL) => {
        console.log('[GroupChatManager.resumeReporters] ', dataObjectReporterURL);
        // create a new chatController but first get identity
        _this.search.myIdentity().then((identity) => {
          let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, identity, _this);
          chatController.dataObjectReporter = reporters[dataObjectReporterURL];

          // Save the chat controllers by dataObjectReporterURL
          this._reportersControllers[dataObjectReporterURL] = chatController;

          _this._resumeInterworking(chatController.dataObjectReporter);

          if (_this._onResumeReporter) _this._onResumeReporter(this._reportersControllers);
        });
      });
    }

    }).catch((reason) => {
      console.info('[GroupChatManager.resumeReporters] ', reason);
    });

    syncher.resumeObservers({store: true}).then((observers) => {
      console.log('[GroupChatManager] resuming observers : ', observers, _this, _this._onResume);

      let observersList = Object.keys(observers);
      if (observersList.length  > 0) {
        observersList.forEach((dataObjectObserverURL) => {

        console.log('[GroupChatManager].syncher.resumeObservers ', dataObjectObserverURL);
        // create a new chatController but first get indentity
        this.search.myIdentity().then((identity) => {
          let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, identity, _this);
          chatController.dataObjectObserver = observers[dataObjectObserverURL];

          // Save the chat controllers by dataObjectReporterURL
          this._observersControllers[dataObjectObserverURL] = chatController;
          if (_this._onResumeObserver) _this._onResumeObserver(this._observersControllers);
        });
      });
      }
    }).catch((reason) => {
      console.info('[GroupChatManager] Resume Observer | ', reason);
    });

    syncher.onNotification(function(event) {

      if (event.type === 'create') {

        // TODO: replace the 100 for Message.Response
        event.ack(100);

        if (_this._onInvitation) { _this._onInvitation(event); }
      }

      if (event.type === 'delete') {
        // TODO: replace the 200 for Message.Response
        event.ack(200);

        _this._observersControllers[event.url].closeEvent = event;

        delete _this._observersControllers[event.url];

        _this._observersControllers.closeEvent = event;

        _this.communicationObject = communicationObject;

        for (let url in this._reportersControllers) {
          this._reportersControllers[url].closeEvent(event);
        }

        for (let url in this._observersControllers) {
          this._observersControllers[url].closeEvent(event);
        }

      }

    });

  }

  /**
   * This function is used to resume interworking Stubs for participants from legacy chat services
   * @param  {Communication}              communication Communication data object
   */

  _resumeInterworking(communication) {

    let _this = this;

    if (communication.data.participants) {

      let participants = communication.data.participants;
      let objectUrl = communication.url;
      let schemaUrl = communication.schema;
      let name = communication.name;

      console.log('[GroupChatManager._resumeInterworking for] ', participants);

      Object.keys(participants).forEach((participant) => {

        let user = participants[participant].identity.userProfile.userURL.split('://');

        if (user[0] !== 'user') {

          console.log('[GroupChatManager._resumeInterworking for] ', participant);

          user = user[0] + '://' + user[1].split('/')[1];

          let msg = {
              type: 'create', from: _this._hypertyURL, to: user,
              body: { resource: objectUrl, schema: schemaUrl, value: communication.metadata }
            };

          _this._bus.postMessage(msg, () => {
          });
        }

      });
    }
  }

  /**
   * This function is used to create a new Group Chat providing the name and the identifiers of users to be invited.
   * @param  {string}                     name  Is a string to identify the Group Chat
   * @param  {array<URL.userURL>}         users Array of users to be invited to join the Group Chat. Users are identified with reTHINK User URL, like this format user://<ipddomain>/<user-identifier>
   * @return {<Promise>ChatController}    A ChatController object as a Promise.
   */
  create(name, users, domains) {

    let _this = this;
    let syncher = _this._syncher;

    return new Promise((resolve, reject) => {

      _this.communicationObject = communicationObject;
      _this.communicationObject.cseq = 1;
      _this.communicationObject.startingTime = new Date().toJSON();
      _this.communicationObject.status =  CommunicationStatus.OPEN;

      let myIdentity;

      _this.search.myIdentity().then((identity) => {
        myIdentity = identity;
        console.log('[GroupChatManager.create ] My Identity', identity);
        let url = _this.communicationObject.reporter;

        let userInfo = new UserInfo(_this._hypertyURL, _this._domain, identity);

        // Add my identity
        _this.communicationObject.participants[identity.userURL] = userInfo;

        console.log('[GroupChatManager.create ] participants: ', _this.communicationObject.participants);
        console.log('[GroupChatManager.create ] communicationObject', _this.communicationObject);
        console.info('[GroupChatManager.create] searching ' + users + ' at domain ' + domains);

        let usersSearch = _this.search.users(users, domains, ['comm'], ['chat']);
        console.log('[GroupChatManager] usersSearch->', usersSearch);
        return usersSearch;
      }).then((hypertiesIDs) => {
        let selectedHyperties = hypertiesIDs.map((hyperty) => {
          return hyperty.hypertyID;
        });

        console.info('[GroupChatManager] ---------------------- Syncher Create ---------------------- \n');
        console.info('[GroupChatManager] Selected Hyperties: !!! ', selectedHyperties);
        console.info(`Have ${selectedHyperties.length} users;`);

        return syncher.create(_this._objectDescURL, selectedHyperties, _this.communicationObject, true, false, name, {}, {resources: ['chat']});

      }).catch((reason) => {
        console.log('[GroupChatManager] MyIdentity Error:', reason);
        return reject(reason);
      }).then(function(dataObjectReporter) {

        console.info('[GroupChatManager] 3. Return Create Data Object Reporter', dataObjectReporter);
        let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, myIdentity, _this);

        resolve(chatController);

        /*dataObjectReporter.data.url = dataObjectReporter.url;
        dataObjectReporter.data.cseq += 1;
        dataObjectReporter.lastModified = new Date().toJSON();*/

        chatController.dataObjectReporter = dataObjectReporter;

        _this._reportersControllers[dataObjectReporter.url] = chatController;

      }).catch(function(reason) {
        reject(reason);
      });
    });

  }

  /**
   * This function is used to handle notifications about incoming invitations to join a Group Chat.
   * @param  {Function} CreateEvent The CreateEvent fired by the Syncher when an invitaion is received
   */
  onInvitation(callback) {
    let _this = this;
    _this._onInvitation = callback;
  }

  onResumeReporter(callback) {
    let _this = this;
    _this._onResumeReporter = callback;
  }

  onResumeObserver(callback) {
    let _this = this;
    _this._onResumeObserver = callback;
  }

  /**
   * This function is used to join a Group Chat.
   * @param  {URL.CommunicationURL} invitationURL  The Communication URL of the Group Chat to join that is provided in the invitation event
   * @return {<Promise>ChatController}             It returns the ChatController object as a Promise
   */
  join(invitationURL) {
    let _this = this;
    let syncher = _this._syncher;

    return new Promise(function(resolve, reject) {
      let myIdentity;
      console.info('[GroupChatManager] ------------------------ Syncher subscribe ---------------------- \n');
      console.info('invitationURL', invitationURL);
      _this.search.myIdentity().then((identity) => {
          myIdentity = identity;
          return syncher.subscribe(_this._objectDescURL, invitationURL, true, false);

      }).then(function(dataObjectObserver) {
        console.info('Data Object Observer: ', dataObjectObserver);

        let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, myIdentity, _this);
        resolve(chatController);

        chatController.dataObjectObserver = dataObjectObserver;

        _this._observersControllers[dataObjectObserver.url] = chatController;

      }).catch(function(reason) {
        reject(reason);
      });
    });

  }

}

export default function activate(hypertyURL, bus, configuration) {

  return {
    name: 'GroupChatManager',
    instance: new GroupChatManager(hypertyURL, bus, configuration)
  };

}
<commit_msg>GroupChatManagerDemo updated to save received files to disk (ongoing)<commit_after>/**
* Copyright 2016 PT Inovação e Sistemas SA
* Copyright 2016 INESC-ID
* Copyright 2016 QUOBIS NETWORKS SL
* Copyright 2016 FRAUNHOFER-GESELLSCHAFT ZUR FOERDERUNG DER ANGEWANDTEN FORSCHUNG E.V
* Copyright 2016 ORANGE SA
* Copyright 2016 Deutsche Telekom AG
* Copyright 2016 Apizee
* Copyright 2016 TECHNISCHE UNIVERSITAT BERLIN
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

// Service Framework
import IdentityManager from 'service-framework/dist/IdentityManager';
import Discovery from 'service-framework/dist/Discovery';
import {Syncher} from 'service-framework/dist/Syncher';

// Utils
import {divideURL} from '../utils/utils';
import Search from '../utils/Search';

// Internals
import { communicationObject, CommunicationStatus, communicationChildren } from './communication';
import ChatController from './ChatController';
import { UserInfo } from './UserInfo';

/**
* Hyperty Group Chat Manager API (HypertyChat)
* @author Vitor Silva [vitor-t-silva@telecom.pt]
* @version 0.1.0
*/
class GroupChatManager {

  constructor(hypertyURL, bus, configuration) {
    if (!hypertyURL) throw new Error('[GroupChatManager.constructor] The hypertyURL is a needed parameter');
    if (!bus) throw new Error('[GroupChatManager.constructor] The MiniBus is a needed parameter');
    if (!configuration) throw new Error('[GroupChatManager.constructor] The configuration is a needed parameter');

    let _this = this;
    let syncher = new Syncher(hypertyURL, bus, configuration);

    let domain = divideURL(hypertyURL).domain;
    let discovery = new Discovery(hypertyURL, configuration.runtimeURL, bus);
    let identityManager = new IdentityManager(hypertyURL, configuration.runtimeURL, bus);

    _this._objectDescURL = 'hyperty-catalogue://catalogue.' + domain + '/.well-known/dataschema/Communication';

    _this._reportersControllers = {};
    _this._observersControllers = {};

    _this._hypertyURL = hypertyURL;
    _this._bus = bus;
    _this._syncher = syncher;
    _this._domain = domain;

    _this.discovery = discovery;
    _this.identityManager = identityManager;

    _this.search = new Search(discovery, identityManager);

    _this.communicationObject = communicationObject;

    _this.communicationChildren = communicationChildren;

    console.log('[GroupChatManager] Discover ', discovery);
    console.log('[GroupChatManager] Identity Manager ', identityManager);

    syncher.resumeReporters({store: true}).then((reporters) => {

      let reportersList = Object.keys(reporters);

      if (reportersList.length  > 0) {

      Object.keys(reporters).forEach((dataObjectReporterURL) => {
        console.log('[GroupChatManager.resumeReporters]: ', dataObjectReporterURL);
        // create a new chatController but first get identity
        _this.search.myIdentity().then((identity) => {
          let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, identity, _this);
          chatController.dataObjectReporter = reporters[dataObjectReporterURL];

          // Save the chat controllers by dataObjectReporterURL
          this._reportersControllers[dataObjectReporterURL] = chatController;

          _this._resumeInterworking(chatController.dataObjectReporter);

          if (_this._onResumeReporter) _this._onResumeReporter(this._reportersControllers);
        });
      });
    }

    }).catch((reason) => {
      console.info('[GroupChatManager.resumeReporters] ', reason);
    });

    syncher.resumeObservers({store: true}).then((observers) => {
      console.log('[GroupChatManager] resuming observers : ', observers, _this, _this._onResume);

      let observersList = Object.keys(observers);
      if (observersList.length  > 0) {
        observersList.forEach((dataObjectObserverURL) => {

        console.log('[GroupChatManager].syncher.resumeObservers ', dataObjectObserverURL);
        // create a new chatController but first get indentity
        this.search.myIdentity().then((identity) => {
          let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, identity, _this);
          chatController.dataObjectObserver = observers[dataObjectObserverURL];

          // Save the chat controllers by dataObjectReporterURL
          this._observersControllers[dataObjectObserverURL] = chatController;
          if (_this._onResumeObserver) _this._onResumeObserver(this._observersControllers);
        });
      });
      }
    }).catch((reason) => {
      console.info('[GroupChatManager] Resume Observer | ', reason);
    });

    syncher.onNotification(function(event) {

      if (event.type === 'create') {

        // TODO: replace the 100 for Message.Response
        event.ack(100);

        if (_this._onInvitation) { _this._onInvitation(event); }
      }

      if (event.type === 'delete') {
        // TODO: replace the 200 for Message.Response
        event.ack(200);

        _this._observersControllers[event.url].closeEvent = event;

        delete _this._observersControllers[event.url];

        _this._observersControllers.closeEvent = event;

        _this.communicationObject = communicationObject;

        for (let url in this._reportersControllers) {
          this._reportersControllers[url].closeEvent(event);
        }

        for (let url in this._observersControllers) {
          this._observersControllers[url].closeEvent(event);
        }

      }

    });

  }

  /**
   * This function is used to resume interworking Stubs for participants from legacy chat services
   * @param  {Communication}              communication Communication data object
   */

  _resumeInterworking(communication) {

    let _this = this;

    if (communication.data.participants) {

      let participants = communication.data.participants;
      let objectUrl = communication.url;
      let schemaUrl = communication.schema;
      let name = communication.name;

      console.log('[GroupChatManager._resumeInterworking for] ', participants);

      Object.keys(participants).forEach((participant) => {

        let user = participants[participant].identity.userProfile.userURL.split('://');

        if (user[0] !== 'user') {

          console.log('[GroupChatManager._resumeInterworking for] ', participant);

          user = user[0] + '://' + user[1].split('/')[1];

          let msg = {
              type: 'create', from: _this._hypertyURL, to: user,
              body: { resource: objectUrl, schema: schemaUrl, value: communication.metadata }
            };

          _this._bus.postMessage(msg, () => {
          });
        }

      });
    }
  }

  /**
   * This function is used to create a new Group Chat providing the name and the identifiers of users to be invited.
   * @param  {string}                     name  Is a string to identify the Group Chat
   * @param  {array<URL.userURL>}         users Array of users to be invited to join the Group Chat. Users are identified with reTHINK User URL, like this format user://<ipddomain>/<user-identifier>
   * @return {<Promise>ChatController}    A ChatController object as a Promise.
   */
  create(name, users, domains) {

    let _this = this;
    let syncher = _this._syncher;

    return new Promise((resolve, reject) => {

      _this.communicationObject = communicationObject;
      _this.communicationObject.cseq = 1;
      _this.communicationObject.startingTime = new Date().toJSON();
      _this.communicationObject.status =  CommunicationStatus.OPEN;

      let myIdentity;

      _this.search.myIdentity().then((identity) => {
        myIdentity = identity;
        console.log('[GroupChatManager.create ] My Identity', identity);
        let url = _this.communicationObject.reporter;

        let userInfo = new UserInfo(_this._hypertyURL, _this._domain, identity);

        // Add my identity
        _this.communicationObject.participants[identity.userURL] = userInfo;

        console.log('[GroupChatManager.create ] participants: ', _this.communicationObject.participants);
        console.log('[GroupChatManager.create ] communicationObject', _this.communicationObject);
        console.info('[GroupChatManager.create] searching ' + users + ' at domain ' + domains);

        let usersSearch = _this.search.users(users, domains, ['comm'], ['chat']);
        console.log('[GroupChatManager] usersSearch->', usersSearch);
        return usersSearch;
      }).then((hypertiesIDs) => {
        let selectedHyperties = hypertiesIDs.map((hyperty) => {
          return hyperty.hypertyID;
        });

        console.info('[GroupChatManager] ---------------------- Syncher Create ---------------------- \n');
        console.info('[GroupChatManager] Selected Hyperties: !!! ', selectedHyperties);
        console.info(`Have ${selectedHyperties.length} users;`);

        return syncher.create(_this._objectDescURL, selectedHyperties, _this.communicationObject, true, false, name, {}, {resources: ['chat']});

      }).catch((reason) => {
        console.log('[GroupChatManager] MyIdentity Error:', reason);
        return reject(reason);
      }).then(function(dataObjectReporter) {

        console.info('[GroupChatManager] 3. Return Create Data Object Reporter', dataObjectReporter);
        let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, myIdentity, _this);

        resolve(chatController);

        /*dataObjectReporter.data.url = dataObjectReporter.url;
        dataObjectReporter.data.cseq += 1;
        dataObjectReporter.lastModified = new Date().toJSON();*/

        chatController.dataObjectReporter = dataObjectReporter;

        _this._reportersControllers[dataObjectReporter.url] = chatController;

      }).catch(function(reason) {
        reject(reason);
      });
    });

  }

  /**
   * This function is used to handle notifications about incoming invitations to join a Group Chat.
   * @param  {Function} CreateEvent The CreateEvent fired by the Syncher when an invitaion is received
   */
  onInvitation(callback) {
    let _this = this;
    _this._onInvitation = callback;
  }

  onResumeReporter(callback) {
    let _this = this;
    _this._onResumeReporter = callback;
  }

  onResumeObserver(callback) {
    let _this = this;
    _this._onResumeObserver = callback;
  }

  /**
   * This function is used to join a Group Chat.
   * @param  {URL.CommunicationURL} invitationURL  The Communication URL of the Group Chat to join that is provided in the invitation event
   * @return {<Promise>ChatController}             It returns the ChatController object as a Promise
   */
  join(invitationURL) {
    let _this = this;
    let syncher = _this._syncher;

    return new Promise(function(resolve, reject) {
      let myIdentity;
      console.info('[GroupChatManager] ------------------------ Syncher subscribe ---------------------- \n');
      console.info('invitationURL', invitationURL);
      _this.search.myIdentity().then((identity) => {
          myIdentity = identity;
          return syncher.subscribe(_this._objectDescURL, invitationURL, true, false);

      }).then(function(dataObjectObserver) {
        console.info('Data Object Observer: ', dataObjectObserver);

        let chatController = new ChatController(syncher, _this.discovery, _this._domain, _this.search, myIdentity, _this);
        resolve(chatController);

        chatController.dataObjectObserver = dataObjectObserver;

        _this._observersControllers[dataObjectObserver.url] = chatController;

      }).catch(function(reason) {
        reject(reason);
      });
    });

  }

}

export default function activate(hypertyURL, bus, configuration) {

  return {
    name: 'GroupChatManager',
    instance: new GroupChatManager(hypertyURL, bus, configuration)
  };

}
<|endoftext|>


<commit_before>/**

==================
 OverlayZ v0.2.3
==================

A very simple, yet customizable jQuery overlay.

 License
---------

The MIT License (MIT)

Copyright © 2013-2015 Joshua D. Burns <https://github.com/JDBurnZ>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/

(function($) {
	$.overlayz = function(arg) {
		var arg_datatype = typeof arg;
		if(arg_datatype == 'string') {
			// If a string is passed, return an overlay with a
			// corresponding alias. If no overlay is found, returns
			// undefined.
			return $.overlayz._alias.lookup(arg);
		} else if(arg_datatype == 'object') {
			// If an object is passed, instantiate and return a new
			// overlay.
			return $.overlayz._new(arg);
		}
		// If some other data-type is passed other than string or object,
		// returns undefined.
	}

	// Mechanism for handling and storing overlays with aliases.
	$.overlayz._alias = {
		'overlays': {
			// Aliased overlays are stored within this object. Key is the
			// alias of the overlay, value is a reference to the instance
			// of the overlay itself.
		},
		'lookup': function(alias) {
			if(alias in $.overlayz._alias.overlays) {
				return $.overlayz._alias.overlays[alias];
			}
		},
		'add': function(alias, $overlay) {
			$.overlayz._alias.overlays[alias] = $overlay;
		},
		'remove': function(alias) {
			if(alias in this.overlays) {
				delete this.overlays[alias];
			}
		}
	};

	$.overlayz._new = function(options) {
		var $overlayz = $('

')
				.css($.overlayz._css.main) // Apply default CSS.
				.hide() // Hide overlay by default.
				.appendTo(document.body) // Add overlay to DOM .
				.append(
					$('

')
						.css($.overlayz._css.container)
						.append(
							$('

')
								.css($.overlayz._css.cell)
								.append(
									$('

')
										.css($.overlayz._css.body)
								)
								.append(
									$('
×
')
										.css($.overlayz._css.close)
								)
						)
				);

		$overlayz.overlayz = {
			'body': (
				$overlayz
					.children('.overlayz-container')
					.children('.overlayz-cell')
					.children('.overlayz-body')
			),
			'css': function(css) {
				if('main' in css) {
					$overlayz.css(css.main);
				}
				if('container' in css) {
					$overlayz
						.children('.overlayz-container')
						.css(css.container);
				}
				if('cell' in css) {
					$overlayz
						.children('.overlayz-container')
						.children('.overlayz-cell')
						.css(css.cell);
				}
				if('close' in css) {
					$overlayz
						.children('.overlayz-container')
						.children('.overlayz-cell')
						.children('.overlayz-close')
						.css(css.close)
				}
				if('body' in css) {
					$overlayz
						.children('.overlayz-container')
						.children('.overlayz-cell')
						.children('.overlayz-body')
						.css(css.body);
				}
				return $overlayz;
			},
			'html': html = function(body) {
				$overlayz
					.children('.overlayz-container')
					.children('.overlayz-cell')
					.children('.overlayz-body')
					.html(body);
				return $overlayz;
			},
			'close': function(animation, speed, callback) {
				if(animation == false) {
					$overlayz.hide();
				} else {
					if(speed == undefined) {
						speed = 'fast';
					}
					if(animation == undefined) {
						animation = 'fadeOut';
					}
					if(callback == undefined) {
						$overlayz[animation](speed);
					} else {
						$overlayz[animation](speed, callback);
					}
				}
				return $overlayz;
			},
			'remove': function() {
				if(this.alias != undefined) {
					$.overlayz._alias.remove(this.alias);
				}
				$overlayz.remove();
			}
		};

		// If CSS parameters have been specified, apply them to the overlay.
		if('css' in options) {
			$overlayz.overlayz.css(options.css);
		}

		// If HTML parameters have been specified, apply them to the
		// overlay.
		if('html' in options) {
			$overlayz.overlayz.html(options.html);
		}

		// If the overlay has an alias specified, add it to our lookup
		// table.
		if('alias' in options) {
			$overlayz.overlayz.alias = options.alias;
			$.overlayz._alias.add(options.alias, $overlayz);
		}

		// When the escape key is pressed, close the overlay if it is displayed.
		$(document.body).on('keydown.overlayz-close', function(event) {
			if(event.keyCode == 27 && $overlayz.is(':visible')) {
				$overlayz.overlayz.close('fadeOut', 'fast');
			}
		});

		// When the user clicks outside of the overlay body and onto the faded out
		// background, automatically close hte overlay.
		$overlayz.on('click.overlayz-close-faded', '.overlayz-cell', function(event) {
			if($overlayz.is(':visible') && $(event.target).hasClass('overlayz-cell')) {
				$overlayz.overlayz.close('fadeOut', 'fast');
			}
		});

		// When the "Close" icon is pressed on the overlay, close it.
		$overlayz.on('click.overlayz-close-icon', '.overlayz-close', function(event) {
			if($overlayz.is(':visible')) {
				$overlayz.overlayz.close('fadeOut', 'fast');
			}
		});

		return $overlayz;
	}

	// Defines the default formatting of the overlays.
	$.overlayz._css = {
		'main': { // Outermost element required to be block element for
		          // animations to work properly.
			'display':          'block',
			'position':         'fixed',
			'top':              '0',
			'left':             '0',
			'width':            '100%',
			'height':           '100%',
			'max-height':       '100%',
		},
		'container': {
			'display':          'table',
			'top':              '0',
			'left':             '0',
			'width':            '100%',
			'height':           '100%',
			'max-height':       '100%',
			'background-color': 'rgba(0, 0, 0, 0.6)',
			'padding':          '0',
			'margin':           '0'
		},
		'cell': { // Provides vertical alignment.
			'display':        'table-cell',
			'vertical-align': 'middle'
		},
		'close': {
			'border': '1px solid #a00000',
			'border-radius': '3px',
			'background-color': 'rgb(204, 0, 0)',
			'color': '#fff',
			'cursor': 'pointer',
			'font-size': '29px',
			'font-weight': 'bold',
			'height': '29px',
			'line-height': '29px',
			'position': 'absolute',
			'right': '8px',
			'text-align': 'center',
			'top': '8px',
			'width': '28px',
		},
		'body': {
			'display':          'block',
			'width':            '25%',
			'height':           '250px',
			'margin':           'auto',
			'padding':          '12px',
			'border':           '1px solid #ccc',
			'background-color': 'rgba(255, 255, 255, 1)',
			'text-align':       'left'
		}
	}
})(jQuery);
<commit_msg>Closing the overlay now removes it from the DOM.<commit_after>/**

==================
 OverlayZ v0.2.3
==================

A very simple, yet customizable jQuery overlay.

 License
---------

The MIT License (MIT)

Copyright © 2013-2015 Joshua D. Burns <https://github.com/JDBurnZ>

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

*/

(function($) {
	$.overlayz = function(arg) {
		var arg_datatype = typeof arg;
		if(arg_datatype == 'string') {
			// If a string is passed, return an overlay with a
			// corresponding alias. If no overlay is found, returns
			// undefined.
			return $.overlayz._alias.lookup(arg);
		} else if(arg_datatype == 'object') {
			// If an object is passed, instantiate and return a new
			// overlay.
			return $.overlayz._new(arg);
		}
		// If some other data-type is passed other than string or object,
		// returns undefined.
	}

	// Mechanism for handling and storing overlays with aliases.
	$.overlayz._alias = {
		'overlays': {
			// Aliased overlays are stored within this object. Key is the
			// alias of the overlay, value is a reference to the instance
			// of the overlay itself.
		},
		'lookup': function(alias) {
			if(alias in $.overlayz._alias.overlays) {
				return $.overlayz._alias.overlays[alias];
			}
		},
		'add': function(alias, $overlay) {
			$.overlayz._alias.overlays[alias] = $overlay;
		},
		'remove': function(alias) {
			if(alias in this.overlays) {
				delete this.overlays[alias];
			}
		}
	};

	$.overlayz._new = function(options) {
		var $overlayz = $('

')
				.css($.overlayz._css.main) // Apply default CSS.
				.hide() // Hide overlay by default.
				.appendTo(document.body) // Add overlay to DOM .
				.append(
					$('

')
						.css($.overlayz._css.container)
						.append(
							$('

')
								.css($.overlayz._css.cell)
								.append(
									$('

')
										.css($.overlayz._css.body)
								)
								.append(
									$('
×
')
										.css($.overlayz._css.close)
								)
						)
				);

		$overlayz.overlayz = {
			'body': (
				$overlayz
					.children('.overlayz-container')
					.children('.overlayz-cell')
					.children('.overlayz-body')
			),
			'css': function(css) {
				if('main' in css) {
					$overlayz.css(css.main);
				}
				if('container' in css) {
					$overlayz
						.children('.overlayz-container')
						.css(css.container);
				}
				if('cell' in css) {
					$overlayz
						.children('.overlayz-container')
						.children('.overlayz-cell')
						.css(css.cell);
				}
				if('close' in css) {
					$overlayz
						.children('.overlayz-container')
						.children('.overlayz-cell')
						.children('.overlayz-close')
						.css(css.close)
				}
				if('body' in css) {
					$overlayz
						.children('.overlayz-container')
						.children('.overlayz-cell')
						.children('.overlayz-body')
						.css(css.body);
				}
				return $overlayz;
			},
			'html': html = function(body) {
				$overlayz
					.children('.overlayz-container')
					.children('.overlayz-cell')
					.children('.overlayz-body')
					.html(body);
				return $overlayz;
			},
			'close': function(animation, speed, callback) {
				if(animation == false) {
					$overlayz.hide();
					$overlayz.remove();
				} else {
					if(callback === undefined) {
						callback = function() {
							$overlayz.remove();
						};
					}
					if(speed == undefined) {
						speed = 'fast';
					}
					if(animation == undefined) {
						animation = 'fadeOut';
					}
					if(callback == undefined) {
						$overlayz[animation](speed);
					} else {
						$overlayz[animation](speed, callback);
					}
				}
				return $overlayz;
			},
			'remove': function() {
				if(this.alias != undefined) {
					$.overlayz._alias.remove(this.alias);
				}
				$overlayz.remove();
			}
		};

		// If CSS parameters have been specified, apply them to the overlay.
		if('css' in options) {
			$overlayz.overlayz.css(options.css);
		}

		// If HTML parameters have been specified, apply them to the
		// overlay.
		if('html' in options) {
			$overlayz.overlayz.html(options.html);
		}

		// If the overlay has an alias specified, add it to our lookup
		// table.
		if('alias' in options) {
			$overlayz.overlayz.alias = options.alias;
			$.overlayz._alias.add(options.alias, $overlayz);
		}

		// When the escape key is pressed, close the overlay if it is displayed.
		$(document.body).on('keydown.overlayz-close', function(event) {
			if(event.keyCode == 27 && $overlayz.is(':visible')) {
				$overlayz.overlayz.close('fadeOut', 'fast');
			}
		});

		// When the user clicks outside of the overlay body and onto the faded out
		// background, automatically close hte overlay.
		$overlayz.on('click.overlayz-close-faded', '.overlayz-cell', function(event) {
			if($overlayz.is(':visible') && $(event.target).hasClass('overlayz-cell')) {
				$overlayz.overlayz.close('fadeOut', 'fast');
			}
		});

		// When the "Close" icon is pressed on the overlay, close it.
		$overlayz.on('click.overlayz-close-icon', '.overlayz-close', function(event) {
			if($overlayz.is(':visible')) {
				$overlayz.overlayz.close('fadeOut', 'fast');
			}
		});

		return $overlayz;
	}

	// Defines the default formatting of the overlays.
	$.overlayz._css = {
		'main': { // Outermost element required to be block element for
		          // animations to work properly.
			'display':          'block',
			'position':         'fixed',
			'top':              '0',
			'left':             '0',
			'width':            '100%',
			'height':           '100%',
			'max-height':       '100%',
		},
		'container': {
			'display':          'table',
			'top':              '0',
			'left':             '0',
			'width':            '100%',
			'height':           '100%',
			'max-height':       '100%',
			'background-color': 'rgba(0, 0, 0, 0.6)',
			'padding':          '0',
			'margin':           '0'
		},
		'cell': { // Provides vertical alignment.
			'display':        'table-cell',
			'vertical-align': 'middle'
		},
		'close': {
			'border': '1px solid #a00000',
			'border-radius': '3px',
			'background-color': 'rgb(204, 0, 0)',
			'color': '#fff',
			'cursor': 'pointer',
			'font-size': '29px',
			'font-weight': 'bold',
			'height': '29px',
			'line-height': '29px',
			'position': 'absolute',
			'right': '8px',
			'text-align': 'center',
			'top': '8px',
			'width': '28px',
		},
		'body': {
			'display':          'block',
			'width':            '25%',
			'height':           '250px',
			'margin':           'auto',
			'padding':          '12px',
			'border':           '1px solid #ccc',
			'background-color': 'rgba(255, 255, 255, 1)',
			'text-align':       'left'
		}
	}
})(jQuery);
<|endoftext|>


<commit_before>/*jshint -W030 */
/* global
 DEBUG:true
 */

DEBUG = !!process.env.VELOCITY_DEBUG;

(function () {
  'use strict';

  if (process.env.NODE_ENV !== 'development' || !process.env.IS_MIRROR) {
    DEBUG && console.log('[velocity] Not adding mirror-registrar because NODE_ENV is',
      process.env.NODE_ENV, 'and IS_MIRROR is', !!process.env.IS_MIRROR);
    return;
  }

  // between this line and the velocity/parentHandshake, is the time the mirror
  // starts initializing and is ready
  console.log('[velocity] Starting mirror on port', process.env.MIRROR_PORT);

  Meteor.methods({

    /**
     * Meteor method: velocity/isMirror
     * Exposes the IS_MIRROR flag to mirror clients
     *
     * @method velocity/isMirror
     * @for Meteor.methods
     */
    'velocity/isMirror': function () {
      return !!process.env.IS_MIRROR;
    },

    /**
     * Meteor method: velocity/parentHandshake
     * This is the best indicator of the mirror's ready status, so it's used to inform the user
     * when there may be delays
     *
     * @method velocity/parentHandshake
     * @for Meteor.methods
     */
    'velocity/parentHandshake': function () {
      console.log('[velocity] Established connection with Velocity.');
    }
  });

  //////////////////////////////////////////////////////////////////////
  // This code will run inside a mirror and connects the mirror to
  // velocity via ddp once the mirror starts. Velocity will then
  // inform frameworks this mirror is ready.
  //
  Meteor.startup(function () {

    if (!process.env.HANDSHAKE) {
      DEBUG && console.log('[velocity] Mirror', process.env.MIRROR_PORT , 'configured not to handshake');
      return;
    }

    DEBUG && console.log('[velocity] Mirror started. Connecting via DDP to parent');

    var velocityConnection = DDP.connect(process.env.PARENT_URL);
    velocityConnection.onReconnect = function () {
      DEBUG && console.log('[velocity] Mirror connected to parent. Registering mirror...');
      velocityConnection.call('velocity/mirrors/register', {
        framework: process.env.FRAMEWORK,
        port: process.env.MIRROR_PORT,
        host: process.env.HOST
      }, function (error) {
        if (error) {
          console.error(
            '[velocity] Could not connect to parent via DDP. ' +
            'Please restart your app and try again. ' +
            'If this happens often please report it as issue to velocity:core.',
            error
          );
        }
        // Disconnect because we no longer need the connection
        velocityConnection.disconnect();
      });
    };

  });

})();
<commit_msg>remove duplicate 'velocity/isMirror' meteor method<commit_after>/*jshint -W030 */
/* global
 DEBUG:true
 */

DEBUG = !!process.env.VELOCITY_DEBUG;

(function () {
  'use strict';

  if (process.env.NODE_ENV !== 'development' || !process.env.IS_MIRROR) {
    DEBUG && console.log('[velocity] Not adding mirror-registrar because NODE_ENV is',
      process.env.NODE_ENV, 'and IS_MIRROR is', !!process.env.IS_MIRROR);
    return;
  }

  // between this line and the velocity/parentHandshake, is the time the mirror
  // starts initializing and is ready
  console.log('[velocity] Starting mirror on port', process.env.MIRROR_PORT);

  Meteor.methods({

    /**
     * Meteor method: velocity/parentHandshake
     * This is the best indicator of the mirror's ready status, so it's used to inform the user
     * when there may be delays
     *
     * @method velocity/parentHandshake
     * @for Meteor.methods
     */
    'velocity/parentHandshake': function () {
      console.log('[velocity] Established connection with Velocity.');
    }

  });

  //////////////////////////////////////////////////////////////////////
  // This code will run inside a mirror and connects the mirror to
  // velocity via ddp once the mirror starts. Velocity will then
  // inform frameworks this mirror is ready.
  //
  Meteor.startup(function () {

    if (!process.env.HANDSHAKE) {
      DEBUG && console.log('[velocity] Mirror', process.env.MIRROR_PORT , 'configured not to handshake');
      return;
    }

    DEBUG && console.log('[velocity] Mirror started. Connecting via DDP to parent');

    var velocityConnection = DDP.connect(process.env.PARENT_URL);
    velocityConnection.onReconnect = function () {
      DEBUG && console.log('[velocity] Mirror connected to parent. Registering mirror...');
      velocityConnection.call('velocity/mirrors/register', {
        framework: process.env.FRAMEWORK,
        port: process.env.MIRROR_PORT,
        host: process.env.HOST
      }, function (error) {
        if (error) {
          console.error(
            '[velocity] Could not connect to parent via DDP. ' +
            'Please restart your app and try again. ' +
            'If this happens often please report it as issue to velocity:core.',
            error
          );
        }
        // Disconnect because we no longer need the connection
        velocityConnection.disconnect();
      });
    };

  });

})();
<|endoftext|>


<commit_before>'use strict';

var assign = require('../../helpers/assign');

var hasSymbols = require('has-symbols')();
var hasBigInts = require('has-bigints')();

var coercibleObject = { valueOf: function () { return 3; }, toString: function () { return 42; } };
var coercibleFnObject = {
	valueOf: function () { return function valueOfFn() {}; },
	toString: function () { return 42; }
};
var valueOfOnlyObject = { valueOf: function () { return 4; }, toString: function () { return {}; } };
var toStringOnlyObject = { valueOf: function () { return {}; }, toString: function () { return 7; } };
var uncoercibleObject = { valueOf: function () { return {}; }, toString: function () { return {}; } };
var uncoercibleFnObject = {
	valueOf: function () { return function valueOfFn() {}; },
	toString: function () { return function toStrFn() {}; }
};
var objects = [{}, coercibleObject, coercibleFnObject, toStringOnlyObject, valueOfOnlyObject];
var nullPrimitives = [undefined, null];
var nonIntegerNumbers = [-1.3, 0.2, 1.8, 1 / 3];
var integerNumbers = [1, 7, 42, 1e17];
var zeroes = [0, -0];
var infinities = [Infinity, -Infinity];
var numbers = zeroes.concat([42], infinities, nonIntegerNumbers);
var strings = ['', 'foo', 'a\uD83D\uDCA9c'];
var booleans = [true, false];
var symbols = hasSymbols ? [Symbol.iterator, Symbol('foo')] : [];
var bigints = hasBigInts ? [BigInt(42), BigInt(0)] : [];
var nonSymbolPrimitives = [].concat(nullPrimitives, booleans, strings, numbers, bigints);
var nonNumberPrimitives = [].concat(nullPrimitives, booleans, strings, symbols);
var nonNullPrimitives = [].concat(booleans, strings, numbers, symbols, bigints);
var nonUndefinedPrimitives = [].concat(null, nonNullPrimitives);
var nonStrings = [].concat(nullPrimitives, booleans, numbers, symbols, objects, bigints);
var primitives = [].concat(nullPrimitives, nonNullPrimitives);
var nonPropertyKeys = [].concat(nullPrimitives, booleans, numbers, objects);
var propertyKeys = [].concat(strings, symbols);
var nonBooleans = [].concat(nullPrimitives, strings, symbols, numbers, objects);
var falsies = [].concat(nullPrimitives, false, '', 0, -0, NaN);
var truthies = [].concat(true, 'foo', 42, symbols, objects);
var timestamps = [].concat(0, 946713600000, 1546329600000);
var nonFunctions = [].concat(primitives, objects, [42]);
var nonArrays = [].concat(nonFunctions);
var nonBigInts = [].concat(nonNumberPrimitives, numbers);

var descriptors = {
	configurable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Configurable]]': true });
	},
	nonConfigurable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Configurable]]': false });
	},
	enumerable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Enumerable]]': true });
	},
	nonEnumerable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Enumerable]]': false });
	},
	writable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Writable]]': true });
	},
	nonWritable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Writable]]': false });
	}
};

module.exports = {
	booleans: booleans,
	coercibleFnObject: coercibleFnObject,
	coercibleObject: coercibleObject,
	falsies: falsies,
	hasSymbols: hasSymbols,
	infinities: infinities,
	integerNumbers: integerNumbers,
	nonArrays: nonArrays,
	nonBigInts: nonBigInts,
	nonBooleans: nonBooleans,
	nonFunctions: nonFunctions,
	nonIntegerNumbers: nonIntegerNumbers,
	nonNullPrimitives: nonNullPrimitives,
	nonNumberPrimitives: nonNumberPrimitives,
	nonNumbers: nonNumberPrimitives.concat(objects),
	nonPropertyKeys: nonPropertyKeys,
	nonStrings: nonStrings,
	nonSymbolPrimitives: nonSymbolPrimitives,
	nonUndefinedPrimitives: nonUndefinedPrimitives,
	nullPrimitives: nullPrimitives,
	numbers: numbers,
	objects: objects,
	primitives: primitives,
	propertyKeys: propertyKeys,
	strings: strings,
	symbols: symbols,
	timestamps: timestamps,
	toStringOnlyObject: toStringOnlyObject,
	truthies: truthies,
	uncoercibleFnObject: uncoercibleFnObject,
	uncoercibleObject: uncoercibleObject,
	valueOfOnlyObject: valueOfOnlyObject,
	zeroes: zeroes,
	bothDescriptor: function () {
		return { '[[Get]]': function () {}, '[[Value]]': true };
	},
	bothDescriptorWritable: function () {
		return descriptors.writable({ '[[Get]]': function () {} });
	},
	accessorDescriptor: function (value) {
		return descriptors.enumerable(descriptors.configurable({
			'[[Get]]': function get() { return value; }
		}));
	},
	mutatorDescriptor: function () {
		return descriptors.enumerable(descriptors.configurable({
			'[[Set]]': function () {}
		}));
	},
	dataDescriptor: function (value) {
		return descriptors.nonWritable({
			'[[Value]]': arguments.length > 0 ? value : 42
		});
	},
	genericDescriptor: function () {
		return descriptors.configurable(descriptors.nonEnumerable());
	},
	descriptors: descriptors
};
<commit_msg>[Tests] add `v.nonConstructorFunctions`<commit_after>'use strict';

var assign = require('../../helpers/assign');

var hasSymbols = require('has-symbols')();
var hasBigInts = require('has-bigints')();
var arrowFunctions = require('make-arrow-function').list();
var generatorFunctions = require('make-generator-function')();
var asyncFunctions = require('make-async-function').list();

var coercibleObject = { valueOf: function () { return 3; }, toString: function () { return 42; } };
var coercibleFnObject = {
	valueOf: function () { return function valueOfFn() {}; },
	toString: function () { return 42; }
};
var valueOfOnlyObject = { valueOf: function () { return 4; }, toString: function () { return {}; } };
var toStringOnlyObject = { valueOf: function () { return {}; }, toString: function () { return 7; } };
var uncoercibleObject = { valueOf: function () { return {}; }, toString: function () { return {}; } };
var uncoercibleFnObject = {
	valueOf: function () { return function valueOfFn() {}; },
	toString: function () { return function toStrFn() {}; }
};
var objects = [{}, coercibleObject, coercibleFnObject, toStringOnlyObject, valueOfOnlyObject];
var nullPrimitives = [undefined, null];
var nonIntegerNumbers = [-1.3, 0.2, 1.8, 1 / 3];
var integerNumbers = [1, 7, 42, 1e17];
var zeroes = [0, -0];
var infinities = [Infinity, -Infinity];
var numbers = zeroes.concat([42], infinities, nonIntegerNumbers);
var strings = ['', 'foo', 'a\uD83D\uDCA9c'];
var booleans = [true, false];
var symbols = hasSymbols ? [Symbol.iterator, Symbol('foo')] : [];
var bigints = hasBigInts ? [BigInt(42), BigInt(0)] : [];
var nonSymbolPrimitives = [].concat(nullPrimitives, booleans, strings, numbers, bigints);
var nonNumberPrimitives = [].concat(nullPrimitives, booleans, strings, symbols);
var nonNullPrimitives = [].concat(booleans, strings, numbers, symbols, bigints);
var nonUndefinedPrimitives = [].concat(null, nonNullPrimitives);
var nonStrings = [].concat(nullPrimitives, booleans, numbers, symbols, objects, bigints);
var primitives = [].concat(nullPrimitives, nonNullPrimitives);
var nonPropertyKeys = [].concat(nullPrimitives, booleans, numbers, objects);
var propertyKeys = [].concat(strings, symbols);
var nonBooleans = [].concat(nullPrimitives, strings, symbols, numbers, objects);
var falsies = [].concat(nullPrimitives, false, '', 0, -0, NaN);
var truthies = [].concat(true, 'foo', 42, symbols, objects);
var timestamps = [].concat(0, 946713600000, 1546329600000);
var nonFunctions = [].concat(primitives, objects, [42]);
var nonArrays = [].concat(nonFunctions);
var nonBigInts = [].concat(nonNumberPrimitives, numbers);
var nonConstructorFunctions = [].concat(arrowFunctions, generatorFunctions, asyncFunctions);

var descriptors = {
	configurable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Configurable]]': true });
	},
	nonConfigurable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Configurable]]': false });
	},
	enumerable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Enumerable]]': true });
	},
	nonEnumerable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Enumerable]]': false });
	},
	writable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Writable]]': true });
	},
	nonWritable: function (descriptor) {
		return assign(assign({}, descriptor), { '[[Writable]]': false });
	}
};

module.exports = {
	booleans: booleans,
	coercibleFnObject: coercibleFnObject,
	coercibleObject: coercibleObject,
	falsies: falsies,
	hasSymbols: hasSymbols,
	infinities: infinities,
	integerNumbers: integerNumbers,
	nonArrays: nonArrays,
	nonBigInts: nonBigInts,
	nonBooleans: nonBooleans,
	nonFunctions: nonFunctions,
	arrowFunctions: arrowFunctions,
	generatorFunctions: generatorFunctions,
	asyncFunctions: asyncFunctions,
	nonConstructorFunctions: nonConstructorFunctions,
	nonIntegerNumbers: nonIntegerNumbers,
	nonNullPrimitives: nonNullPrimitives,
	nonNumberPrimitives: nonNumberPrimitives,
	nonNumbers: nonNumberPrimitives.concat(objects),
	nonPropertyKeys: nonPropertyKeys,
	nonStrings: nonStrings,
	nonSymbolPrimitives: nonSymbolPrimitives,
	nonUndefinedPrimitives: nonUndefinedPrimitives,
	nullPrimitives: nullPrimitives,
	numbers: numbers,
	objects: objects,
	primitives: primitives,
	propertyKeys: propertyKeys,
	strings: strings,
	symbols: symbols,
	timestamps: timestamps,
	toStringOnlyObject: toStringOnlyObject,
	truthies: truthies,
	uncoercibleFnObject: uncoercibleFnObject,
	uncoercibleObject: uncoercibleObject,
	valueOfOnlyObject: valueOfOnlyObject,
	zeroes: zeroes,
	bothDescriptor: function () {
		return { '[[Get]]': function () {}, '[[Value]]': true };
	},
	bothDescriptorWritable: function () {
		return descriptors.writable({ '[[Get]]': function () {} });
	},
	accessorDescriptor: function (value) {
		return descriptors.enumerable(descriptors.configurable({
			'[[Get]]': function get() { return value; }
		}));
	},
	mutatorDescriptor: function () {
		return descriptors.enumerable(descriptors.configurable({
			'[[Set]]': function () {}
		}));
	},
	dataDescriptor: function (value) {
		return descriptors.nonWritable({
			'[[Value]]': arguments.length > 0 ? value : 42
		});
	},
	genericDescriptor: function () {
		return descriptors.configurable(descriptors.nonEnumerable());
	},
	descriptors: descriptors
};
<|endoftext|>


<commit_before>var querystring = require('querystring');
var Promise = require('bluebird');

var util = require('./util');
var config = require('./config');
var Request = require('./Request');

var reqCountMap = {};
paramError = new Error('缺少参数');
promiseError = new Error('`getRequestCount`和`saveRequestCount`必须是 function');

function check(option) {
  if (option &&
    (option.getRequestCount || option.saveRequestCount) &&
    (!util.isFunction(option.getRequestCount) || !util.isFunction(option.saveRequestCount))) {
    throw promiseError;
  }
}

/**
 * 请求数的读取操作
 * @param token 商店 token
 * @type {null|Function}
 */
var getReqCountHandle = function (token) {
  return reqCountMap[token];
};

/**
 * 请求数的保存操作
 * @param token 商店 token
 * @param count 需要保存的请求数
 * @type {null|Function}
 */
var saveReqCountHandle = function (token, count) {
  reqCountMap[token] = count;
  return reqCountMap[token];
};

var reqCountWrap = function (token, fn) {
  return function () {
    // arguments 转成数组
    var args = Array.prototype.slice.call(arguments);
    // 插入 token
    args.unshift(token);
    return Promise.cast(fn.call(null, args));
  };
};

/**
 * 初始化
 * @param {string} token
 * @param option
 * @constructor
 */
var Api = function (token, option) {
  if (arguments.length < 1) {
    throw paramError;
  }
  check(option);

  this.token = token;
  this.host = (option && option.host) || config.apiHost;
  // 存取请求数的回调函数
  this.getRequestCount = option && option.getRequestCount || getReqCountHandle;
  this.saveRequestCount = option && option.saveRequestCount || saveReqCountHandle;
  // 请求实例
  this._request = new Request({
    protocol: (option && option.protocol) || config.httpProtocol,
    getRequestCount: reqCountWrap(this.token, this.getRequestCount),
    saveRequestCount: reqCountWrap(this.token, this.saveRequestCount),
  });
};

Api.prototype = {
  /**
   * 发送 GET 请求
   * @param {string} path
   * @param {Object} [query]
   */
  get: function (path, query) {
    if (arguments.length < 1) {
      throw paramError;
    }
    return this.request('GET', query ? path + '?' + querystring.stringify(query) : path, null);
  },
  /**
   * 发送 PUT 请求
   * @param {string} path
   * @param {Object} data
   */
  put: function (path, data) {
    if (arguments.length < 2) {
      throw paramError;
    }
    return this.request('PUT', path, data);
  },
  /**
   * 发送 POST 请求
   * @param {string} path
   * @param {Object} data
   */
  post: function (path, data) {
    if (arguments.length < 2) {
      throw paramError;
    }
    return this.request('POST', path, data);
  },
  /**
   * 发送 DELETE 请求
   * @param {string} path
   * @param {Function} callback
   */
  delete: function (path) {
    if (arguments.length < 1) {
      throw paramError;
    }
    return this.request('DELETE', path, null);
  },
  /**
   * @param {string} method
   * @param {string} path
   * @param {Object} [params]
   * @param {Function} callback
   */
  request: function (method, path, params) {
    return this._request.request({
      hostname: this.host,
      path: '/v1/' + path,
      method: method,
      headers: {
        'Content-Type': 'application/json',
        'X-API-ACCESS-TOKEN': this.token
      }
    }, params);
  }
};

module.exports = Api;
<commit_msg>添加函数注释；<commit_after>var querystring = require('querystring');
var Promise = require('bluebird');

var util = require('./util');
var config = require('./config');
var Request = require('./Request');

var reqCountMap = {};
paramError = new Error('缺少参数');
promiseError = new Error('`getRequestCount`和`saveRequestCount`必须是 function');

function check(option) {
  if (option &&
    (option.getRequestCount || option.saveRequestCount) &&
    (!util.isFunction(option.getRequestCount) || !util.isFunction(option.saveRequestCount))) {
    throw promiseError;
  }
}

/**
 * 请求数的读取操作
 * @param token 商店 token
 * @type {null|Function}
 */
var getReqCountHandle = function (token) {
  return reqCountMap[token];
};

/**
 * 请求数的保存操作
 * @param token 商店 token
 * @param count 需要保存的请求数
 * @type {null|Function}
 */
var saveReqCountHandle = function (token, count) {
  reqCountMap[token] = count;
  return reqCountMap[token];
};

/**
 * 包装 token 函数
 * @param token
 * @param fn
 * @returns {function()}
 */
var reqCountWrap = function (token, fn) {
  return function () {
    // arguments 转成数组
    var args = Array.prototype.slice.call(arguments);
    // 插入 token
    args.unshift(token);
    return Promise.cast(fn.call(null, args));
  };
};

/**
 * 初始化
 * @param {string} token
 * @param {object} option
 * @param {string} protocol 可选，'http'或者'https',默认'https'
 * @param {string} host 可选，开发 API 接口域名,默认'api.youhaosuda.com'
 * @param {function} option.getRequestCount 获取请求数函数
 * @param {function} option.saveRequestCount 存储请求数函数
 * @constructor
 */
var Api = function (token, option) {
  if (arguments.length < 1) {
    throw paramError;
  }
  check(option);

  this.token = token;
  this.host = (option && option.host) || config.apiHost;
  // 存取请求数的回调函数
  this.getRequestCount = option && option.getRequestCount || getReqCountHandle;
  this.saveRequestCount = option && option.saveRequestCount || saveReqCountHandle;
  // 请求实例
  this._request = new Request({
    protocol: (option && option.protocol) || config.httpProtocol,
    getRequestCount: reqCountWrap(this.token, this.getRequestCount),
    saveRequestCount: reqCountWrap(this.token, this.saveRequestCount),
  });
};

Api.prototype = {
  /**
   * 发送 GET 请求
   * @param path
   * @param query
   * @returns {Object<Promise>}
   */
  get: function (path, query) {
    if (arguments.length < 1) {
      throw paramError;
    }
    return this.request('GET', query ? path + '?' + querystring.stringify(query) : path, null);
  },
  /**
   * 发送 PUT 请求
   * @param path
   * @param data
   * @returns {Object<Promise>}
   */
  put: function (path, data) {
    if (arguments.length < 2) {
      throw paramError;
    }
    return this.request('PUT', path, data);
  },
  /**
   * 发送 POST 请求
   * @param path
   * @param data
   * @returns {Object<Promise>}
   */
  post: function (path, data) {
    if (arguments.length < 2) {
      throw paramError;
    }
    return this.request('POST', path, data);
  },
  /**
   * 发送 DELETE 请求
   * @param {string} path
   * @returns {Object<Promise>}
   */
  delete: function (path) {
    if (arguments.length < 1) {
      throw paramError;
    }
    return this.request('DELETE', path, null);
  },
  /**
   *
   * @param method
   * @param path
   * @param params
   * @returns {Object<Promise>}
   */
  request: function (method, path, params) {
    return this._request.request({
      hostname: this.host,
      path: '/v1/' + path,
      method: method,
      headers: {
        'Content-Type': 'application/json',
        'X-API-ACCESS-TOKEN': this.token
      }
    }, params);
  }
};

module.exports = Api;
<|endoftext|>


<commit_before>var copyrightCampaign = function(options) {
    options = typeof options !== 'undefined' ? options : {};
    function setDefaultOption(option, value) {
        options[option] = typeof options[option] !== 'undefined' ? options[option] : value;
    }

    setDefaultOption(options, {});
    setDefaultOption("onCampaignDayOnly", true);
    setDefaultOption("showOnlyOnce", true);
    setDefaultOption("title", 'Järkeä
tekijänoikeuslakiin?');
    setDefaultOption("bigText", 'Allekirjoita kansalaisaloite kohtuullisemman tekijänoikeuslain puolesta.');
    setDefaultOption("smallText", 'Katso myös: Internetin musta päivä 23.4.');

    console.log(options);

    var today = new Date();
    if (!(today.getDate() == 23 && today.getMonth() == 3) && options["onCampaignDayOnly"]) {
        return;
    }

    if (typeof jQuery === "undefined") {
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type","text/javascript");
        script_tag.setAttribute("src",
          "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js");
        script_tag.onload = main; // Run main() once jQuery has loaded
        script_tag.onreadystatechange = function () { // Same thing but for IE
          if (this.readyState == 'complete' || this.readyState == 'loaded') main();
        }
        document.getElementsByTagName("head")[0].appendChild(script_tag);
    } else {
        main();
    }

    function main() {
        $(document).ready(function (e) {
            $("head").prepend("<link href='http://fonts.googleapis.com/css?family=Open+Sans:800|Gentium+Book+Basic' rel='stylesheet' type='text/css'>");

            var widgetStyle = '';

            $("head").prepend(widgetStyle);

            var widgetElement = '

Sulje

'+options.title+'

'+options.bigText+'

'+options.smallText+'

Sulje

Code by SC5

';
            $(document.body).append(widgetElement);

            function hideBox() {
                $("#copyright-campaign-box").hide();
                if(options["showOnlyOnce"] && typeof(Storage)!=="undefined") {
                    localStorage.boxClosed = true;
                }
            }

            if(options["showOnlyOnce"] && typeof(Storage)!=="undefined" && localStorage.boxClosed) {
                hideBox();
            }

            $(".close-copyright-campaign-box").click(function(e) {
                hideBox();
            });

            $(document).keyup(function(e) {
                if (e.keyCode == 27) {
                    hideBox();
                }
            });
        });
    }
};<commit_msg>Change breakpoint<commit_after>var copyrightCampaign = function(options) {
    options = typeof options !== 'undefined' ? options : {};
    function setDefaultOption(option, value) {
        options[option] = typeof options[option] !== 'undefined' ? options[option] : value;
    }

    setDefaultOption(options, {});
    setDefaultOption("onCampaignDayOnly", true);
    setDefaultOption("showOnlyOnce", true);
    setDefaultOption("title", 'Järkeä
tekijänoikeuslakiin?');
    setDefaultOption("bigText", 'Allekirjoita kansalaisaloite kohtuullisemman tekijänoikeuslain puolesta.');
    setDefaultOption("smallText", 'Katso myös: Internetin musta päivä 23.4.');

    console.log(options);

    var today = new Date();
    if (!(today.getDate() == 23 && today.getMonth() == 3) && options["onCampaignDayOnly"]) {
        return;
    }

    if (typeof jQuery === "undefined") {
        var script_tag = document.createElement('script');
        script_tag.setAttribute("type","text/javascript");
        script_tag.setAttribute("src",
          "http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js");
        script_tag.onload = main; // Run main() once jQuery has loaded
        script_tag.onreadystatechange = function () { // Same thing but for IE
          if (this.readyState == 'complete' || this.readyState == 'loaded') main();
        }
        document.getElementsByTagName("head")[0].appendChild(script_tag);
    } else {
        main();
    }

    function main() {
        $(document).ready(function (e) {
            $("head").prepend("<link href='http://fonts.googleapis.com/css?family=Open+Sans:800|Gentium+Book+Basic' rel='stylesheet' type='text/css'>");

            var widgetStyle = '';

            $("head").prepend(widgetStyle);

            var widgetElement = '

Sulje

'+options.title+'

'+options.bigText+'

'+options.smallText+'

Sulje

Code by SC5

';
            $(document.body).append(widgetElement);

            function hideBox() {
                $("#copyright-campaign-box").hide();
                if(options["showOnlyOnce"] && typeof(Storage)!=="undefined") {
                    localStorage.boxClosed = true;
                }
            }

            if(options["showOnlyOnce"] && typeof(Storage)!=="undefined" && localStorage.boxClosed) {
                hideBox();
            }

            $(".close-copyright-campaign-box").click(function(e) {
                hideBox();
            });

            $(document).keyup(function(e) {
                if (e.keyCode == 27) {
                    hideBox();
                }
            });
        });
    }
};<|endoftext|>


<commit_before>import React, { Component } from 'react';
import '../css/css.js';
import WelcomeSearch from './Welcome-Search.js'
import Key from '../apikey.js';
import WeatherObject from './WeatherObject.js';
import Sustained from './Sustained.js';
import Current from './Current.js';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.url = '';
    this.state = {
      initialSearchValue: '',
      weather: {},
    };
    this.setState = this.setState.bind(this);
    this.getCurrentWeather = this.getCurrentWeather.bind(this);
  }

  componentDidMount() {
    // this.getCurrentWeather();
  }

  render() {
    return (

          {/* <WelcomeSearch
              setAppState={this.setState}
              getCurrentWeather={this.getCurrentWeather}
              initialSearchValue={this.state.initialSearchValue}/> */}
              <Sustained
                weather={this.state.weather}
                setAppState={this.setState}
                initialSearchValue={this.state.initialSearchValue}
                getCurrentWeather={this.getCurrentWeather}/>
              <Current
                weather={this.state.weather} />

    );
  }

  setURL() {
    this.url = `http://api.wunderground.com/api/${Key}/conditions/hourly/forecast10day/q/${this.state.initialSearchValue}.json`;
  }

  getData() {
    fetch(this.url)
      .then(data => data.json())
      .then(parsedData => new WeatherObject(parsedData))
      .then(weatherObj => {this.setState({ weather: weatherObj })
                          console.log(this.state.weather);
    })
      .catch(error => "error");
  }

  getCurrentWeather() {
    this.setURL();
    this.getData();
    // .welcome-screen display: none;
    //  use this.state.searchInput to make API call
    // display sustained content and current forecast
  }
}
<commit_msg>turned on component did mount<commit_after>import React, { Component } from 'react';
import '../css/css.js';
import WelcomeSearch from './Welcome-Search.js'
import Key from '../apikey.js';
import WeatherObject from './WeatherObject.js';
import Sustained from './Sustained.js';
import Current from './Current.js';

export default class App extends Component {
  constructor(props) {
    super(props);
    this.url = '';
    this.state = {
      initialSearchValue: '',
      weather: {},
    };
    this.setState = this.setState.bind(this);
    this.getCurrentWeather = this.getCurrentWeather.bind(this);
  }

  componentDidMount() {
    this.getCurrentWeather();
  }

  render() {
    return (

          {/* <WelcomeSearch
              setAppState={this.setState}
              getCurrentWeather={this.getCurrentWeather}
              initialSearchValue={this.state.initialSearchValue}/> */}
              <Sustained
                weather={this.state.weather}
                setAppState={this.setState}
                initialSearchValue={this.state.initialSearchValue}
                getCurrentWeather={this.getCurrentWeather}/>
              <Current
                weather={this.state.weather} />

    );
  }

  setURL() {
    this.url = `http://api.wunderground.com/api/${Key}/conditions/hourly/forecast10day/q/${this.state.initialSearchValue}.json`;
  }

  getData() {
    fetch(this.url)
      .then(data => data.json())
      .then(parsedData => new WeatherObject(parsedData))
      .then(weatherObj => {this.setState({ weather: weatherObj })
                          console.log(this.state.weather);
    })
      .catch(error => "error");
  }

  getCurrentWeather() {
    this.setURL();
    this.getData();
    // .welcome-screen display: none;
    //  use this.state.searchInput to make API call
    // display sustained content and current forecast
  }
}
<|endoftext|>