<commit_before>if (! window.XOSLIB_LOADED ) {
    window.XOSLIB_LOADED=true;

    SLIVER_API = "/plstackapi/slivers/";
    SLICE_API = "/plstackapi/slices/";
    SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
    SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
    SLICEROLE_API = "/plstackapi/slice_roles/";
    NODE_API = "/plstackapi/nodes/";
    SITE_API = "/plstackapi/sites/";
    USER_API = "/plstackapi/users/";
    USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
    DEPLOYMENT_API = "/plstackapi/deployments/";
    IMAGE_API = "/plstackapi/images/";
    NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
    NETWORK_API = "/plstackapi/networks/";
    NETWORKSLIVER_API = "/plstackapi/networkslivers/";
    SERVICE_API = "/plstackapi/services/";

    SLICEPLUS_API = "/xoslib/slicesplus/";

    XOSModel = Backbone.Model.extend({
        /* from backbone-tastypie.js */
        //idAttribute: 'resource_uri',

        /* from backbone-tastypie.js */
        url: function() {
                    var url = this.attributes.resource_uri;

                    if (!url) {
                        url = this.urlRoot + this.id;
                    }

                    if (!url) {
                        // XXX I'm not sure this does anything useful
                        url = ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
                        url = url || this.urlRoot;
                    }

                    // remove any existing query parameters
                    url && ( url.indexOf("?") > -1 ) && ( url = url.split("?")[0] );

                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

            listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            }
    });

    XOSCollection = Backbone.Collection.extend({
        objects: function() {
                    return this.models.map(function(element) { return element.attributes; });
                 },

        initialize: function(){
          this.sortVar = 'name';
          this.sortOrder = 'asc';
        },

        relatedCollections: [],
        foreignCollections: [],

        simpleComparator: function( model ){
          parts=this.sortVar.split(".");
          result = model.get(parts[0]);
          for (index=1; index<parts.length; ++index) {
              result=result[parts[index]];
          }
          return result;
        },

        comparator: function (left, right) {
            var l = this.simpleComparator(left);
            var r = this.simpleComparator(right);

            if (l === void 0) return -1;
            if (r === void 0) return 1;

            if (this.sortOrder=="desc") {
                return l < r ? 1 : l > r ? -1 : 0;
            } else {
                return l < r ? -1 : l > r ? 1 : 0;
            }
        },

        startPolling: function() {
            if (!this._polling) {
                var collection=this;
                setInterval(function() { collection.fetch(); }, 10000);
                this._polling=true;
                this.fetch();
            }
        },

        maybeFetch: function(options){
                // Helper function to fetch only if this collection has not been fetched before.
            if(this._fetched){
                    // If this has already been fetched, call the success, if it exists
                options.success && options.success();
                console.log("alreadyFetched");
                return;
            }

                // when the original success function completes mark this collection as fetched
            var self = this,
            successWrapper = function(success){
                return function(){
                    self._fetched = true;
                    success && success.apply(this, arguments);
                };
            };
            options.success = successWrapper(options.success);
            console.log("call fetch");
            this.fetch(options);
        },

        getOrFetch: function(id, options){
                // Helper function to use this collection as a cache for models on the server
            var model = this.get(id);

            if(model){
                options.success && options.success(model);
                return;
            }

            model = new this.model({
                resource_uri: id
            });

            model.fetch(options);
        },

        filterBy: function(fieldName, value) {
             filtered = this.filter(function(obj) {
                 return obj.get(fieldName) == value;
                 });
             return new this.constructor(filtered);
        },

        /* from backbone-tastypie.js */
        url: function( models ) {
                    var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
                    // (set to 'resource_uri') contains the model's id.
                    if ( models && models.length ) {
                            var ids = _.map( models, function( model ) {
                                            var parts = _.compact( model.id.split('/') );
                                            return parts[ parts.length - 1 ];
                                    });
                            url += 'set/' + ids.join(';') + '/';
                    }

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

        listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            },
    });

    function xoslib() {
        // basic REST
        this.sliver = XOSModel.extend({ urlRoot: SLIVER_API });
        this.sliverCollection = XOSCollection.extend({ urlRoot: SLIVER_API,
                                                       relatedCollections: {"networkSlivers": "sliver"},
                                                       foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
                                                       model: this.sliver});
        this.slivers = new this.sliverCollection();

        this.slice = XOSModel.extend({ urlRoot: SLICE_API });
        this.sliceCollection = XOSCollection.extend({ urlRoot: SLICE_API,
                                                       relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice"},
                                                       foreignCollections: ["services", "sites"],
                                                       model: this.slice});
        this.slices = new this.sliceCollection();

        this.sliceDeployment = XOSModel.extend({ urlRoot: SLICEDEPLOYMENT_API });
        this.sliceDeploymentCollection = XOSCollection.extend({ urlRoot: SLICEDEPLOYMENT_API,
                                                       foreignCollections: ["slices", "deployments"],
                                                       model: this.slice});
        this.sliceDeployments = new this.sliceDeploymentCollection();

        this.slicePrivilege = XOSModel.extend({ urlRoot: SLICEPRIVILEGE_API });
        this.slicePrivilegeCollection = XOSCollection.extend({ urlRoot: SLICEPRIVILEGE_API,
                                                       foreignCollections: ["slices", "users", "sliceRoles"],
                                                       model: this.slice});
        this.slicePrivileges = new this.slicePrivilegeCollection();

        this.sliceRole = XOSModel.extend({ urlRoot: SLICEROLE_API });
        this.sliceRoleCollection = XOSCollection.extend({ urlRoot: SLICEROLE_API,
                                                       model: this.slice});
        this.sliceRoles = new this.sliceRoleCollection();

        this.node = XOSModel.extend({ urlRoot: NODE_API });
        this.nodeCollection = XOSCollection.extend({ urlRoot: NODE_API,
                                                       foreignCollections: ["sites", "deployments"],
                                                       model: this.node});
        this.nodes = new this.nodeCollection();

        this.site = XOSModel.extend({ urlRoot: SITE_API });
        this.siteCollection = XOSCollection.extend({ urlRoot: SITE_API,
                                                       model: this.site});
        this.sites = new this.siteCollection();

        this.user = XOSModel.extend({ urlRoot: USER_API });
        this.userCollection = XOSCollection.extend({ urlRoot: USER_API,
                                                       relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
                                                       foreignCollections: ["sites"],
                                                       model: this.user});
        this.users = new this.userCollection();

        this.userDeployment = XOSModel.extend({ urlRoot: USER_API });
        this.userDeploymentCollection = XOSCollection.extend({ urlRoot: USERDEPLOYMENT_API,
                                                       foreignCollections: ["users","deployments"],
                                                       model: this.user});
        this.userDeployments = new this.userDeploymentCollection();

        this.deployment = XOSModel.extend({ urlRoot: DEPLOYMENT_API });
        this.deploymentCollection = XOSCollection.extend({ urlRoot: DEPLOYMENT_API,
                                                           model: this.deployment});
        this.deployments = new this.deploymentCollection();

        this.image = XOSModel.extend({ urlRoot: IMAGE_API });
        this.imageCollection = XOSCollection.extend({ urlRoot: IMAGE_API,
                                                           model: this.image});
        this.images = new this.imageCollection();

        this.networkTemplate = XOSModel.extend({ urlRoot: NETWORKTEMPLATE_API });
        this.networkTemplateCollection = XOSCollection.extend({ urlRoot: NETWORKTEMPLATE_API,
                                                           model: this.networkTemplate});
        this.networkTemplates = new this.networkTemplateCollection();

        this.network = XOSModel.extend({ urlRoot: NETWORK_API });
        this.networkCollection = XOSCollection.extend({ urlRoot: NETWORK_API,
                                                           foreignCollections: ["slices", "networkTemplates"],
                                                           model: this.network});
        this.networks = new this.networkCollection();

        this.networkSliver = XOSModel.extend({ urlRoot: NETWORKSLIVER_API });
        this.networkSliverCollection = XOSCollection.extend({ urlRoot: NETWORKSLIVER_API,
                                                           model: this.networkSliver});
        this.networkSlivers = new this.networkSliverCollection();

        this.service = XOSModel.extend({ urlRoot: SERVICE_API });
        this.serviceCollection = XOSCollection.extend({ urlRoot: SERVICE_API,
                                                       model: this.service});
        this.services = new this.serviceCollection();

        // enhanced REST
        this.slicePlus = XOSModel.extend({ urlRoot: SLICEPLUS_API, relatedCollections: {'slivers': "slice"} });
        this.slicePlusCollection = XOSCollection.extend({ urlRoot: SLICEPLUS_API,
                                                          model: this.slicePlus});
        this.slicesPlus = new this.slicePlusCollection();

        this.listObjects = function() { return ["slivers", "slices", "nodes", "sites", "users", "deployments"]; };
    };

    xos = new xoslib();

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    (function() {
      var _sync = Backbone.sync;
      Backbone.sync = function(method, model, options){
        options.beforeSend = function(xhr){
          var token = getCookie("csrftoken");
          xhr.setRequestHeader('X-CSRFToken', token);
        };
        return _sync(method, model, options);
      };
    })();
}
<commit_msg>add networkDeployment to xoslib<commit_after>if (! window.XOSLIB_LOADED ) {
    window.XOSLIB_LOADED=true;

    SLIVER_API = "/plstackapi/slivers/";
    SLICE_API = "/plstackapi/slices/";
    SLICEDEPLOYMENT_API = "/plstackapi/slice_deployments/";
    SLICEPRIVILEGE_API = "/plstackapi/slice_privileges/";
    SLICEROLE_API = "/plstackapi/slice_roles/";
    NODE_API = "/plstackapi/nodes/";
    SITE_API = "/plstackapi/sites/";
    USER_API = "/plstackapi/users/";
    USERDEPLOYMENT_API = "/plstackapi/user_deployments/";
    DEPLOYMENT_API = "/plstackapi/deployments/";
    IMAGE_API = "/plstackapi/images/";
    NETWORKTEMPLATE_API = "/plstackapi/networktemplates/";
    NETWORKDEPLOYMENT_API = "/plstackapi/networkdeployments/";
    NETWORK_API = "/plstackapi/networks/";
    NETWORKSLIVER_API = "/plstackapi/networkslivers/";
    SERVICE_API = "/plstackapi/services/";

    SLICEPLUS_API = "/xoslib/slicesplus/";

    XOSModel = Backbone.Model.extend({
        /* from backbone-tastypie.js */
        //idAttribute: 'resource_uri',

        /* from backbone-tastypie.js */
        url: function() {
                    var url = this.attributes.resource_uri;

                    if (!url) {
                        url = this.urlRoot + this.id;
                    }

                    if (!url) {
                        // XXX I'm not sure this does anything useful
                        url = ( _.isFunction( this.collection.url ) ? this.collection.url() : this.collection.url );
                        url = url || this.urlRoot;
                    }

                    // remove any existing query parameters
                    url && ( url.indexOf("?") > -1 ) && ( url = url.split("?")[0] );

                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

            listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            }
    });

    XOSCollection = Backbone.Collection.extend({
        objects: function() {
                    return this.models.map(function(element) { return element.attributes; });
                 },

        initialize: function(){
          this.sortVar = 'name';
          this.sortOrder = 'asc';
        },

        relatedCollections: [],
        foreignCollections: [],

        simpleComparator: function( model ){
          parts=this.sortVar.split(".");
          result = model.get(parts[0]);
          for (index=1; index<parts.length; ++index) {
              result=result[parts[index]];
          }
          return result;
        },

        comparator: function (left, right) {
            var l = this.simpleComparator(left);
            var r = this.simpleComparator(right);

            if (l === void 0) return -1;
            if (r === void 0) return 1;

            if (this.sortOrder=="desc") {
                return l < r ? 1 : l > r ? -1 : 0;
            } else {
                return l < r ? -1 : l > r ? 1 : 0;
            }
        },

        startPolling: function() {
            if (!this._polling) {
                var collection=this;
                setInterval(function() { collection.fetch(); }, 10000);
                this._polling=true;
                this.fetch();
            }
        },

        maybeFetch: function(options){
                // Helper function to fetch only if this collection has not been fetched before.
            if(this._fetched){
                    // If this has already been fetched, call the success, if it exists
                options.success && options.success();
                console.log("alreadyFetched");
                return;
            }

                // when the original success function completes mark this collection as fetched
            var self = this,
            successWrapper = function(success){
                return function(){
                    self._fetched = true;
                    success && success.apply(this, arguments);
                };
            };
            options.success = successWrapper(options.success);
            console.log("call fetch");
            this.fetch(options);
        },

        getOrFetch: function(id, options){
                // Helper function to use this collection as a cache for models on the server
            var model = this.get(id);

            if(model){
                options.success && options.success(model);
                return;
            }

            model = new this.model({
                resource_uri: id
            });

            model.fetch(options);
        },

        filterBy: function(fieldName, value) {
             filtered = this.filter(function(obj) {
                 return obj.get(fieldName) == value;
                 });
             return new this.constructor(filtered);
        },

        /* from backbone-tastypie.js */
        url: function( models ) {
                    var url = this.urlRoot || ( models && models.length && models[0].urlRoot );
                    url && ( url += ( url.length > 0 && url.charAt( url.length - 1 ) === '/' ) ? '' : '/' );

                    // Build a url to retrieve a set of models. This assume the last part of each model's idAttribute
                    // (set to 'resource_uri') contains the model's id.
                    if ( models && models.length ) {
                            var ids = _.map( models, function( model ) {
                                            var parts = _.compact( model.id.split('/') );
                                            return parts[ parts.length - 1 ];
                                    });
                            url += 'set/' + ids.join(';') + '/';
                    }

                    url && ( url += "?no_hyperlinks=1" );

                    return url;
            },

        listMethods: function() {
                var res = [];
                for(var m in this) {
                    if(typeof this[m] == "function") {
                        res.push(m)
                    }
                }
                return res;
            },
    });

    function xoslib() {
        // basic REST
        this.sliver = XOSModel.extend({ urlRoot: SLIVER_API });
        this.sliverCollection = XOSCollection.extend({ urlRoot: SLIVER_API,
                                                       relatedCollections: {"networkSlivers": "sliver"},
                                                       foreignCollections: ["slices", "deployments", "images", "nodes", "users"],
                                                       model: this.sliver});
        this.slivers = new this.sliverCollection();

        this.slice = XOSModel.extend({ urlRoot: SLICE_API });
        this.sliceCollection = XOSCollection.extend({ urlRoot: SLICE_API,
                                                       relatedCollections: {"slivers": "slice", "sliceDeployments": "slice", "slicePrivileges": "slice"},
                                                       foreignCollections: ["services", "sites"],
                                                       model: this.slice});
        this.slices = new this.sliceCollection();

        this.sliceDeployment = XOSModel.extend({ urlRoot: SLICEDEPLOYMENT_API });
        this.sliceDeploymentCollection = XOSCollection.extend({ urlRoot: SLICEDEPLOYMENT_API,
                                                       foreignCollections: ["slices", "deployments"],
                                                       model: this.slice});
        this.sliceDeployments = new this.sliceDeploymentCollection();

        this.slicePrivilege = XOSModel.extend({ urlRoot: SLICEPRIVILEGE_API });
        this.slicePrivilegeCollection = XOSCollection.extend({ urlRoot: SLICEPRIVILEGE_API,
                                                       foreignCollections: ["slices", "users", "sliceRoles"],
                                                       model: this.slice});
        this.slicePrivileges = new this.slicePrivilegeCollection();

        this.sliceRole = XOSModel.extend({ urlRoot: SLICEROLE_API });
        this.sliceRoleCollection = XOSCollection.extend({ urlRoot: SLICEROLE_API,
                                                       model: this.slice});
        this.sliceRoles = new this.sliceRoleCollection();

        this.node = XOSModel.extend({ urlRoot: NODE_API });
        this.nodeCollection = XOSCollection.extend({ urlRoot: NODE_API,
                                                       foreignCollections: ["sites", "deployments"],
                                                       model: this.node});
        this.nodes = new this.nodeCollection();

        this.site = XOSModel.extend({ urlRoot: SITE_API });
        this.siteCollection = XOSCollection.extend({ urlRoot: SITE_API,
                                                       model: this.site});
        this.sites = new this.siteCollection();

        this.user = XOSModel.extend({ urlRoot: USER_API });
        this.userCollection = XOSCollection.extend({ urlRoot: USER_API,
                                                       relatedCollections: {"slicePrivileges": "user", "slices": "owner", "userDeployments": "user"},
                                                       foreignCollections: ["sites"],
                                                       model: this.user});
        this.users = new this.userCollection();

        this.userDeployment = XOSModel.extend({ urlRoot: USER_API });
        this.userDeploymentCollection = XOSCollection.extend({ urlRoot: USERDEPLOYMENT_API,
                                                       foreignCollections: ["users","deployments"],
                                                       model: this.user});
        this.userDeployments = new this.userDeploymentCollection();

        this.deployment = XOSModel.extend({ urlRoot: DEPLOYMENT_API });
        this.deploymentCollection = XOSCollection.extend({ urlRoot: DEPLOYMENT_API,
                                                           model: this.deployment});
        this.deployments = new this.deploymentCollection();

        this.image = XOSModel.extend({ urlRoot: IMAGE_API });
        this.imageCollection = XOSCollection.extend({ urlRoot: IMAGE_API,
                                                           model: this.image});
        this.images = new this.imageCollection();

        this.networkTemplate = XOSModel.extend({ urlRoot: NETWORKTEMPLATE_API });
        this.networkTemplateCollection = XOSCollection.extend({ urlRoot: NETWORKTEMPLATE_API,
                                                           model: this.networkTemplate});
        this.networkTemplates = new this.networkTemplateCollection();

        this.network = XOSModel.extend({ urlRoot: NETWORK_API });
        this.networkCollection = XOSCollection.extend({ urlRoot: NETWORK_API,
                                                           relatedCollections: {"networkDeployments": "network", "networkSlivers": "network"},
                                                           foreignCollections: ["slices", "networkTemplates"],
                                                           model: this.network});
        this.networks = new this.networkCollection();

        this.networkSliver = XOSModel.extend({ urlRoot: NETWORKSLIVER_API });
        this.networkSliverCollection = XOSCollection.extend({ urlRoot: NETWORKSLIVER_API,
                                                           model: this.networkSliver});
        this.networkSlivers = new this.networkSliverCollection();

        this.networkDeployment = XOSModel.extend({ urlRoot: NETWORKDEPLOYMENT_API });
        this.networkDeploymentCollection = XOSCollection.extend({ urlRoot: NETWORKDEPLOYMENT_API,
                                                           model: this.networkDeployment});
        this.networkDeployments = new this.networkDeploymentCollection();

        this.service = XOSModel.extend({ urlRoot: SERVICE_API });
        this.serviceCollection = XOSCollection.extend({ urlRoot: SERVICE_API,
                                                       model: this.service});
        this.services = new this.serviceCollection();

        // enhanced REST
        this.slicePlus = XOSModel.extend({ urlRoot: SLICEPLUS_API, relatedCollections: {'slivers': "slice"} });
        this.slicePlusCollection = XOSCollection.extend({ urlRoot: SLICEPLUS_API,
                                                          model: this.slicePlus});
        this.slicesPlus = new this.slicePlusCollection();

        this.listObjects = function() { return ["slivers", "slices", "nodes", "sites", "users", "deployments"]; };
    };

    xos = new xoslib();

    function getCookie(name) {
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }

    (function() {
      var _sync = Backbone.sync;
      Backbone.sync = function(method, model, options){
        options.beforeSend = function(xhr){
          var token = getCookie("csrftoken");
          xhr.setRequestHeader('X-CSRFToken', token);
        };
        return _sync(method, model, options);
      };
    })();
}
<|endoftext|>


<commit_before>import {Rx} from '@cycle/core';
import marked from 'marked';

// https://github.com/vic/awesome-cyclejs/pull/8#issuecomment-148759962
export default function makeMarkdownDriver(renderer = marked) {
  return function markdownDriver(request$) {
    return request$.flatMap(raw => {
      Rx.Observable.fromCallback(marked)(raw);
    })
  }
}
<commit_msg>mistake<commit_after>import {Rx} from '@cycle/core';
import marked from 'marked';

// https://github.com/vic/awesome-cyclejs/pull/8#issuecomment-148759962
export default function makeMarkdownDriver(renderer = marked) {
  return function markdownDriver(request$) {
    return request$.flatMap(raw => {
      Rx.Observable.fromCallback(renderer)(raw);
    })
  }
}
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc.
 *
 * 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.
 */

describe('SegmentIndex', /** @suppress {accessControls} */ function() {
  describe('find', function() {
    it('finds the correct references', function() {
      var actual1 = makeReference(0, 0, 10, uri(0));
      var actual2 = makeReference(1, 10, 20, uri(10));
      var actual3 = makeReference(2, 20, 30, uri(20));

      var index, pos1, pos2, pos3;

      // One reference.
      index = new shaka.media.SegmentIndex([actual1]);
      pos1 = index.find(5);
      expect(pos1).toBe(actual1.position);

      // Two references.
      index = new shaka.media.SegmentIndex([actual1, actual2]);
      pos1 = index.find(5);
      pos2 = index.find(15);
      expect(pos1).toBe(actual1.position);
      expect(pos2).toBe(actual2.position);

      // Three references.
      index = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      pos1 = index.find(5);
      pos2 = index.find(15);
      pos3 = index.find(25);
      expect(pos1).toBe(actual1.position);
      expect(pos2).toBe(actual2.position);
      expect(pos3).toBe(actual3.position);
    });

    it('works if time == first start time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(10);
      expect(pos).toBe(actual.position);
    });

    it('works with two references if time == second start time', function() {
      var actual1 = makeReference(1, 10, 20, uri(10));
      var actual2 = makeReference(2, 20, 30, uri(20));
      var index = new shaka.media.SegmentIndex([actual1, actual2]);

      var pos = index.find(20);
      expect(pos).toBe(actual2.position);
    });

    it('returns null if time < first start time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(5);
      expect(pos).toBeNull();
    });

    it('returns null if time == last end time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(20);
      expect(pos).toBeNull();
    });

    it('returns null if time > last end time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(21);
      expect(pos).toBeNull();
    });

    it('returns null if time is within a gap', function() {
      var actual1 = makeReference(1, 10, 20, uri(10));
      var actual2 = makeReference(2, 25, 30, uri(25));
      var index = new shaka.media.SegmentIndex([actual1, actual2]);

      var pos = index.find(23);
      expect(pos).toBeNull();
    });
  });

  describe('get', function() {
    var actual1, actual2, actual3;

    beforeEach(function() {
      actual1 = makeReference(0, 0, 10, uri(0));
      actual2 = makeReference(1, 10, 20, uri(10));
      actual3 = makeReference(2, 20, 30, uri(20));
    });

    it('returns the correct references', function() {
      var index, r1, r2, r3;

      // One reference.
      index = new shaka.media.SegmentIndex([actual1]);
      r1 = index.get(0);
      expect(r1).toEqual(actual1);

      // Two references.
      index = new shaka.media.SegmentIndex([actual1, actual2]);
      r1 = index.get(0);
      r2 = index.get(1);
      expect(r1).toEqual(actual1);
      expect(r2).toEqual(actual2);

      // Three references.
      index = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      r1 = index.get(0);
      r2 = index.get(1);
      r3 = index.get(2);
      expect(r1).toEqual(actual1);
      expect(r2).toEqual(actual2);
      expect(r3).toEqual(actual3);

      // Two references with offset.
      index = new shaka.media.SegmentIndex([actual2, actual3]);
      r2 = index.get(1);
      r3 = index.get(2);
      expect(r2).toEqual(actual2);
      expect(r3).toEqual(actual3);

      // One reference with offset.
      index = new shaka.media.SegmentIndex([actual3]);
      r3 = index.get(2);
      expect(r3).toEqual(actual3);
    });

    it('returns null with zero references', function() {
      var index = new shaka.media.SegmentIndex([]);
      expect(index.get(0)).toBeNull();
    });

    it('returns null if position < 0', function() {
      var index = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      expect(index.get(-1)).toBeNull();
    });

    it('returns null for unknown positions', function() {
      var index1 = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      expect(index1.get(3)).toBeNull();

      var index2 = new shaka.media.SegmentIndex([actual2, actual3]);
      expect(index2.get(0)).toBeNull();
    });
  });

  describe('merge', function() {
    it('three references into zero references', function() {
      var index1 = new shaka.media.SegmentIndex([]);

      var references2 = [
        makeReference(0, 0, 10, uri(0)),
        makeReference(1, 10, 20, uri(10)),
        makeReference(2, 20, 30, uri(20))
      ];

      index1.merge(references2);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_).toEqual(references2);
    });

    it('zero references into three references', function() {
      var references1 = [
        makeReference(0, 0, 10, uri(0)),
        makeReference(1, 10, 20, uri(10)),
        makeReference(2, 20, 30, uri(20))
      ];
      var index1 = new shaka.media.SegmentIndex(references1);

      index1.merge([]);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_).toEqual(references1);
    });

    it('one reference into one reference at end', function() {
      var references1 = [makeReference(1, 10, 20, uri(10))];
      var index1 = new shaka.media.SegmentIndex(references1);

      var references2 = [makeReference(2, 20, 30, uri(20))];

      index1.merge(references2);
      expect(index1.references_.length).toBe(2);
      expect(index1.references_[0]).toEqual(references1[0]);
      expect(index1.references_[1]).toEqual(references2[0]);
    });

    it('one reference into two references at end', function() {
      var references1 = [
        makeReference(1, 10, 20, uri(10)),
        makeReference(2, 20, 30, uri(20))
      ];
      var index1 = new shaka.media.SegmentIndex(references1);

      var references2 = [makeReference(3, 30, 40, uri(30))];

      index1.merge(references2);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_[0]).toEqual(references1[0]);
      expect(index1.references_[1]).toEqual(references1[1]);
      expect(index1.references_[2]).toEqual(references2[0]);
    });

    it('two references into one reference at end', function() {
      var references1 = [makeReference(2, 20, 30, uri(20))];
      var index1 = new shaka.media.SegmentIndex(references1);

      var references2 = [
        makeReference(3, 30, 40, uri(30)),
        makeReference(4, 40, 50, uri(40))
      ];

      index1.merge(references2);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_[0]).toEqual(references1[0]);
      expect(index1.references_[1]).toEqual(references2[0]);
      expect(index1.references_[2]).toEqual(references2[1]);
    });
  });

  describe('evict', function() {
    var actual1, actual2, actual3, index1;

    beforeEach(function() {
      actual1 = makeReference(0, 0, 10, uri(0));
      actual2 = makeReference(1, 10, 20, uri(10));
      actual3 = makeReference(2, 20, 30, uri(20));
      index1 = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
    });

    it('no segments', function() {
      index1.evict(5);
      expect(index1.references_.length).toBe(3);
    });

    it('one segment (edge)', function() {
      index1.evict(10);

      expect(index1.references_.length).toBe(2);
      expect(index1.references_[0]).toEqual(actual2);
      expect(index1.references_[1]).toEqual(actual3);
    });

    it('one segment', function() {
      index1.evict(11);

      expect(index1.references_.length).toBe(2);
      expect(index1.references_[0]).toEqual(actual2);
      expect(index1.references_[1]).toEqual(actual3);
    });

    it('two segments (edge)', function() {
      index1.evict(20);

      expect(index1.references_.length).toBe(1);
      expect(index1.references_[0]).toEqual(actual3);
    });

    it('two segments', function() {
      index1.evict(21);

      expect(index1.references_.length).toBe(1);
      expect(index1.references_[0]).toEqual(actual3);
    });

    it('three segments (edge)', function() {
      index1.evict(30);
      expect(index1.references_.length).toBe(0);
    });

    it('three segments', function() {
      index1.evict(31);
      expect(index1.references_.length).toBe(0);
    });
  });

  /**
   * Creates a new SegmentReference.
   *
   * @param {number} position
   * @param {number} startTime
   * @param {number} endTime
   * @param {string} uri
   * @return {!shaka.media.SegmentReference}
   */
  function makeReference(position, startTime, endTime, uri) {
    return new shaka.media.SegmentReference(
        position, startTime, endTime, [uri], 0, null);
  }

  /**
   * Creates a URI string.
   *
   * @param {string|number} x
   */
  function uri(x) {
    return 'http://example.com/video_' + x + '.m4s';
  }
});

<commit_msg>Reproduce issue with merging last segment in a period<commit_after>/**
 * @license
 * Copyright 2016 Google Inc.
 *
 * 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.
 */

describe('SegmentIndex', /** @suppress {accessControls} */ function() {
  describe('find', function() {
    it('finds the correct references', function() {
      var actual1 = makeReference(0, 0, 10, uri(0));
      var actual2 = makeReference(1, 10, 20, uri(10));
      var actual3 = makeReference(2, 20, 30, uri(20));

      var index, pos1, pos2, pos3;

      // One reference.
      index = new shaka.media.SegmentIndex([actual1]);
      pos1 = index.find(5);
      expect(pos1).toBe(actual1.position);

      // Two references.
      index = new shaka.media.SegmentIndex([actual1, actual2]);
      pos1 = index.find(5);
      pos2 = index.find(15);
      expect(pos1).toBe(actual1.position);
      expect(pos2).toBe(actual2.position);

      // Three references.
      index = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      pos1 = index.find(5);
      pos2 = index.find(15);
      pos3 = index.find(25);
      expect(pos1).toBe(actual1.position);
      expect(pos2).toBe(actual2.position);
      expect(pos3).toBe(actual3.position);
    });

    it('works if time == first start time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(10);
      expect(pos).toBe(actual.position);
    });

    it('works with two references if time == second start time', function() {
      var actual1 = makeReference(1, 10, 20, uri(10));
      var actual2 = makeReference(2, 20, 30, uri(20));
      var index = new shaka.media.SegmentIndex([actual1, actual2]);

      var pos = index.find(20);
      expect(pos).toBe(actual2.position);
    });

    it('returns null if time < first start time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(5);
      expect(pos).toBeNull();
    });

    it('returns null if time == last end time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(20);
      expect(pos).toBeNull();
    });

    it('returns null if time > last end time', function() {
      var actual = makeReference(1, 10, 20, uri(10));
      var index = new shaka.media.SegmentIndex([actual]);

      var pos = index.find(21);
      expect(pos).toBeNull();
    });

    it('returns null if time is within a gap', function() {
      var actual1 = makeReference(1, 10, 20, uri(10));
      var actual2 = makeReference(2, 25, 30, uri(25));
      var index = new shaka.media.SegmentIndex([actual1, actual2]);

      var pos = index.find(23);
      expect(pos).toBeNull();
    });
  });

  describe('get', function() {
    var actual1, actual2, actual3;

    beforeEach(function() {
      actual1 = makeReference(0, 0, 10, uri(0));
      actual2 = makeReference(1, 10, 20, uri(10));
      actual3 = makeReference(2, 20, 30, uri(20));
    });

    it('returns the correct references', function() {
      var index, r1, r2, r3;

      // One reference.
      index = new shaka.media.SegmentIndex([actual1]);
      r1 = index.get(0);
      expect(r1).toEqual(actual1);

      // Two references.
      index = new shaka.media.SegmentIndex([actual1, actual2]);
      r1 = index.get(0);
      r2 = index.get(1);
      expect(r1).toEqual(actual1);
      expect(r2).toEqual(actual2);

      // Three references.
      index = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      r1 = index.get(0);
      r2 = index.get(1);
      r3 = index.get(2);
      expect(r1).toEqual(actual1);
      expect(r2).toEqual(actual2);
      expect(r3).toEqual(actual3);

      // Two references with offset.
      index = new shaka.media.SegmentIndex([actual2, actual3]);
      r2 = index.get(1);
      r3 = index.get(2);
      expect(r2).toEqual(actual2);
      expect(r3).toEqual(actual3);

      // One reference with offset.
      index = new shaka.media.SegmentIndex([actual3]);
      r3 = index.get(2);
      expect(r3).toEqual(actual3);
    });

    it('returns null with zero references', function() {
      var index = new shaka.media.SegmentIndex([]);
      expect(index.get(0)).toBeNull();
    });

    it('returns null if position < 0', function() {
      var index = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      expect(index.get(-1)).toBeNull();
    });

    it('returns null for unknown positions', function() {
      var index1 = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
      expect(index1.get(3)).toBeNull();

      var index2 = new shaka.media.SegmentIndex([actual2, actual3]);
      expect(index2.get(0)).toBeNull();
    });
  });

  describe('merge', function() {
    it('three references into zero references', function() {
      var index1 = new shaka.media.SegmentIndex([]);

      var references2 = [
        makeReference(0, 0, 10, uri(0)),
        makeReference(1, 10, 20, uri(10)),
        makeReference(2, 20, 30, uri(20))
      ];

      index1.merge(references2);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_).toEqual(references2);
    });

    it('zero references into three references', function() {
      var references1 = [
        makeReference(0, 0, 10, uri(0)),
        makeReference(1, 10, 20, uri(10)),
        makeReference(2, 20, 30, uri(20))
      ];
      var index1 = new shaka.media.SegmentIndex(references1);

      index1.merge([]);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_).toEqual(references1);
    });

    it('one reference into one reference at end', function() {
      var references1 = [makeReference(1, 10, 20, uri(10))];
      var index1 = new shaka.media.SegmentIndex(references1);

      var references2 = [makeReference(2, 20, 30, uri(20))];

      index1.merge(references2);
      expect(index1.references_.length).toBe(2);
      expect(index1.references_[0]).toEqual(references1[0]);
      expect(index1.references_[1]).toEqual(references2[0]);
    });

    it('one reference into two references at end', function() {
      var references1 = [
        makeReference(1, 10, 20, uri(10)),
        makeReference(2, 20, 30, uri(20))
      ];
      var index1 = new shaka.media.SegmentIndex(references1);

      var references2 = [makeReference(3, 30, 40, uri(30))];

      index1.merge(references2);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_[0]).toEqual(references1[0]);
      expect(index1.references_[1]).toEqual(references1[1]);
      expect(index1.references_[2]).toEqual(references2[0]);
    });

    it('two references into one reference at end', function() {
      var references1 = [makeReference(2, 20, 30, uri(20))];
      var index1 = new shaka.media.SegmentIndex(references1);

      var references2 = [
        makeReference(3, 30, 40, uri(30)),
        makeReference(4, 40, 50, uri(40))
      ];

      index1.merge(references2);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_[0]).toEqual(references1[0]);
      expect(index1.references_[1]).toEqual(references2[0]);
      expect(index1.references_[2]).toEqual(references2[1]);
    });

    it('last live stream reference when period change', function() {
      var references1 = [
        makeReference(1, 10, 20, uri(10)),
        makeReference(2, 20, 30, uri(20)),
        makeReference(3, 30, 49.987, uri(30)),
      ];
      var index1 = new shaka.media.SegmentIndex(references1);

      // when period is changed, fitSegmentReference will
      // expand last segment to the start of the next the period
      var references2 = [
        makeReference(2, 20, 30, uri(20)),
        makeReference(3, 30, 50, uri(30))
      ];

      index1.merge(references2);
      expect(index1.references_.length).toBe(3);
      expect(index1.references_[0]).toEqual(references1[0]);
      expect(index1.references_[1]).toEqual(references2[0]);
      expect(index1.references_[2]).toEqual(references2[1]);
    });
  });

  describe('evict', function() {
    var actual1, actual2, actual3, index1;

    beforeEach(function() {
      actual1 = makeReference(0, 0, 10, uri(0));
      actual2 = makeReference(1, 10, 20, uri(10));
      actual3 = makeReference(2, 20, 30, uri(20));
      index1 = new shaka.media.SegmentIndex([actual1, actual2, actual3]);
    });

    it('no segments', function() {
      index1.evict(5);
      expect(index1.references_.length).toBe(3);
    });

    it('one segment (edge)', function() {
      index1.evict(10);

      expect(index1.references_.length).toBe(2);
      expect(index1.references_[0]).toEqual(actual2);
      expect(index1.references_[1]).toEqual(actual3);
    });

    it('one segment', function() {
      index1.evict(11);

      expect(index1.references_.length).toBe(2);
      expect(index1.references_[0]).toEqual(actual2);
      expect(index1.references_[1]).toEqual(actual3);
    });

    it('two segments (edge)', function() {
      index1.evict(20);

      expect(index1.references_.length).toBe(1);
      expect(index1.references_[0]).toEqual(actual3);
    });

    it('two segments', function() {
      index1.evict(21);

      expect(index1.references_.length).toBe(1);
      expect(index1.references_[0]).toEqual(actual3);
    });

    it('three segments (edge)', function() {
      index1.evict(30);
      expect(index1.references_.length).toBe(0);
    });

    it('three segments', function() {
      index1.evict(31);
      expect(index1.references_.length).toBe(0);
    });
  });

  /**
   * Creates a new SegmentReference.
   *
   * @param {number} position
   * @param {number} startTime
   * @param {number} endTime
   * @param {string} uri
   * @return {!shaka.media.SegmentReference}
   */
  function makeReference(position, startTime, endTime, uri) {
    return new shaka.media.SegmentReference(
        position, startTime, endTime, [uri], 0, null);
  }

  /**
   * Creates a URI string.
   *
   * @param {string|number} x
   */
  function uri(x) {
    return 'http://example.com/video_' + x + '.m4s';
  }
});

<|endoftext|>


<commit_before>/** Class representing camicroscope core instance **/
// proposal:
// test:
// constructor
// load on each component

class CaMic{
  /**
  *
  * create a camic core instance
  * @param divId - the div id to inject openseadragon into
  * @param slideQuery - query parameters for the slide to load; first result taken
  * @param [slideQuery.id] - the object id for the slide; takes precedence
  * @param [slideQuery.slide] - the given name for the slide, regex supported
  * @param [slideQuery.location] - the slide source location/filename
  * @property slideQuery - the slide id
  * @property options - the options extend from OpenSeadragon
  *
  */
  constructor(divId, slideQuery, options){
    Loading.open(document.body, 'CaMicroscope is initializing...');
    // initalize viewer
    this.setting = {
      id: divId,
      prefixUrl: "images/",
      constrainDuringPan:true,
      // -- navigator setting
      showNavigationControl:false,
      showNavigator: true,
      navigatorAutoFade: false,
      navigatorPosition: "BOTTOM_RIGHT",
      zoomPerClick: 1,
      animationTime: 0.01,
      maxZoomPixelRatio: 1,
      visibilityRatio: 1,
      springStiffness:0.0001,

      /* extension */
      hasZoomControl:true,
      hasDrawLayer:true,
      hasLayerManager:true,
      hasScalebar:true,
      hasMeasurementTool:true,
      hasPatchManager:true,
      hasHeatmap:false
    }
    extend(this.setting, options);

    this.viewer = new OpenSeadragon.Viewer(this.setting);

    this.slideQuery = slideQuery;
    this.slideId = slideQuery.id
    // initalize store
    this.store = new Store();
    // load image
    // set overlay thing
    this.viewer.addOnceHandler('open',this.init.bind(this));
  }

  /**
   * initialize the CAMIC and the dependenced components
   */
  init(){
    this.viewer.controls.bottomright.style.zIndex = 600;

    this.viewer.addOnceHandler('tile-loaded', function(){
      // the first tile loaded
      Loading.close();
      // set zoom and pan
      if(this.setting.states){
        const states = this.setting.states;
        let x = states.x;
        let y = states.y;

        if((!states.coordinate)&& states.coordinate!=='image' ){
         const size = this.viewer.world.getItemAt(0).source.dimensions;
         x = Math.round(x*size.x);
         y = Math.round(y*size.y);
        }

        var pt = new OpenSeadragon.Point(x, y); // x, y should in the image coordinate system
        pt = this.viewer.viewport.imageToViewportCoordinates(pt);
        this.viewer.viewport.zoomTo(states.z, pt);
        this.viewer.viewport.panTo(pt, true);

        //set a position mark
        if(states.hasMark){
          // create a mark
          const div = document.createElement('div');
          const mark = document.createElement('div');
          mark.style.transform = 'translate3d(-50%, -50%, 0)';
          mark.style.display = 'flex';
          mark.style.width = '20px';
          mark.style.height = '20px';
          mark.style.border = '2px red solid';
          mark.style.alignItems = 'center';
          mark.style.borderRadius='50%';
          mark.style.textAlign = 'center';
          const center = document.createElement('div');
          center.style.borderRadius = '50%';
          center.style.margin = '0 auto';
          center.style.width = '4px';
          center.style.height = '4px';
          center.style.backgroundColor = 'red';
          mark.appendChild(center);
          div.appendChild(mark);
          this.viewer.addOverlay({
          element: div,
          location: pt,
          checkResize: false
          });
        }

      }
    }.bind(this));

    // create draw pulgin
    this.createCanvasDraw();
    this.createOverlayers();

    // change navigator style
    if(this.setting.showNavigator){
      const nav = this.viewer.element.querySelector('.navigator');
      nav.style.backgroundColor = '#365f9c';
      nav.style.opacity = 1;
    }

    this.createZoomControl();
    this.createMeasurementTool(this.mpp);
    this.createPatchManager();
    this.createHeatmap();
  }
  /**
  * Change which image is staged, used loadImg to load it.
  */
  setImg(slideId){
    this.layers.resetAll();
    this.slideId = slideId;
  }
  /**
  * Loads the staged image
  */
  loadImg(func){
    // loads current image
    // if id is set, use id
    var slidePromise;
    if(this.slideQuery.hasOwnProperty('id') && this.slideQuery.id){
      slidePromise = this.store.getSlide(this.slideQuery.id)
    }
    else {
      slidePromise = this.store.findSlide(this.slideQuery.name, this.slideQuery.location)
    }
    slidePromise
      .then((x)=>{
        if(!x || !OpenSeadragon.isArray(x) || !x.length || !x[0].location){
          redirect($D.pages.table,`Can't find the slide information`);
          return;
        }
        this.slideId = x[0]["_id"]["$oid"]
        this.slideName = x[0]['name']
        this.study = x[0]['study']
        this.specimen = x[0]['study']
        this.viewer.open("./img/Slide/"+ x[0]["_id"]["$oid"] + ".dzi");
        // set scalebar
        this.createScalebar(x[0].mpp)
        var imagingHelper = new OpenSeadragonImaging.ImagingHelper({
          viewer: this.viewer
        });

        imagingHelper.setMaxZoom(1);
        if(func && typeof func === 'function') func.call(null,x[0]);
        Loading.text.textContent = `loading slide's tiles...`;
        this.mpp = x[0].mpp;

      })
      .catch(e=>{
        Loading.close();
        //$UI.message.addError('loadImg Error');
        console.error(e);

        if(func && typeof func === 'function') func.call(null,{hasError:true,message:e});
      })
  }
  /**
   * set up a zoom control functionality on the image
   */
  createZoomControl(){
    if(!this.setting.hasZoomControl || !this.viewer.cazoomctrl) return;
    this.viewer.cazoomctrl({
      position:"BOTTOM_RIGHT",
      autoFade: false
    });
  }
  /**
   * set up a canvas Draw functionality on the image
   */
  createCanvasDraw(){
    if(!this.setting.hasDrawLayer || !this.viewer.canvasDraw) return;
    this.viewer.canvasDraw();
    // create style context menu for draw
    this.drawContextmenu = new __.SimpleContextMenu(
      this.viewer.container,
      {}
    );

    // add event to hook up
    this.drawContextmenu.addHandler('style-changed',function(e){
      this.viewer.canvasDrawInstance.style = e.style;
      this.viewer.canvasDrawInstance.drawMode = e.model;
    }.bind(this));

    // this.drawContextmenu.addHandler('undo',function(e){
    //   this.viewer.canvasDrawInstance.undo();
    // }.bind(this));

    // this.drawContextmenu.addHandler('redo',function(e){
    //   this.viewer.canvasDrawInstance.redo();
    // }.bind(this));

    this.drawContextmenu.addHandler('clear',function(e){
      if(this.viewer.canvasDrawInstance._draws_data_.length == 0) return;
      if(confirm("Do you want to clear all markups?")) this.viewer.canvasDrawInstance.clear();
    }.bind(this));

    // this.drawContextmenu.addHandler('draw-mode-changed',function(e){
    //   this.viewer.canvasDrawInstance.drawMode = e.mode;
    // }.bind(this));

    //this.drawContextmenu.addHandler('draw',draw);
  }

  /**
   * set up a overlay manage on the image
   */
  createOverlayers(){
    if(!this.setting.hasLayerManager || !this.viewer.overlaysManager) return;
    this.viewer.overlaysManager();
  }

  /**
  * Set up a scalebar on the image
  * @param {number} mpp - microns per pixel of image
  */
  createScalebar(mpp){
    if(!this.setting.hasScalebar || !this.viewer.scalebar) return;
    try {
      this.viewer.scalebar({
              type: OpenSeadragon.ScalebarType.MAP,
              pixelsPerMeter: (1 / (parseFloat(mpp) * 0.000001)),
              xOffset: 5,
              yOffset: 10,
              stayInsideImage: true,
              color: "rgb(150,150,150)",
              fontColor: "rgb(100,100,100)",
              backgroundColor: "rgba(255,255,255,0.5)",
              barThickness: 2
          });
      } catch (ex) {
          console.log("scalebar err: ", ex.message);
      }
  }

  createMeasurementTool(mpp){
    if(!this.setting.hasMeasurementTool || !this.viewer.measurementTool) return;
    this.viewer.measurementTool({
      mpp:{
        x:mpp,
        y:mpp,
      }
    });
  }

  createPatchManager(){
    if(!this.setting.hasPatchManager || !this.viewer.createPatchManager) return;
    this.viewer.createPatchManager({});
  }

  createHeatmap(){
    if(!this.setting.hasHeatmap || !this.viewer.createHeatmap) return;
    this.viewer.createHeatmap({});
  }

  /**
   * Function to destroy the instance of CaMic and clean up everything created by CaMic.
   *
   * Example:
   * var camic = CaMic({
   *   [...]
   * });
   *
   * //when you are done with the camic:
   * camic.destroy();
   * camic = null; //important
   *
   */
  destroy(){
    // destroy CanvasDraw's instance if exists
    if(this.viewer.canvasDrawInstance){
      this.viewer.canvasDrawInstance.destroy();
      this.viewer.canvasDrawInstance = null;
    }

    // destroy CaZoomControl's instance if exists
    if(this.viewer.cazoomctrlInstance){
      this.viewer.cazoomctrlInstance.destroy();
      this.viewer.cazoomctrlInstance = null;
    }

    // destroy OverlayManager's instance if exists
    if(this.viewer.omanager){
      this.viewer.omanager.destroy();
      this.viewer.omanager = null;
    }

    // destroy Scalebar's instance if exists
    if(this.viewer.scalebarInstance){
      for(const key in this.viewer.scalebarInstance){
        this.viewer.scalebarInstance[key] = null;
      }
      this.viewer.scalebarInstance;
    }

    // destroy viewer if exists
    this.viewer.destroy();
    this.viewer = null;
  }
}
<commit_msg>fix specimen get<commit_after>/** Class representing camicroscope core instance **/
// proposal:
// test:
// constructor
// load on each component

class CaMic{
  /**
  *
  * create a camic core instance
  * @param divId - the div id to inject openseadragon into
  * @param slideQuery - query parameters for the slide to load; first result taken
  * @param [slideQuery.id] - the object id for the slide; takes precedence
  * @param [slideQuery.slide] - the given name for the slide, regex supported
  * @param [slideQuery.location] - the slide source location/filename
  * @property slideQuery - the slide id
  * @property options - the options extend from OpenSeadragon
  *
  */
  constructor(divId, slideQuery, options){
    Loading.open(document.body, 'CaMicroscope is initializing...');
    // initalize viewer
    this.setting = {
      id: divId,
      prefixUrl: "images/",
      constrainDuringPan:true,
      // -- navigator setting
      showNavigationControl:false,
      showNavigator: true,
      navigatorAutoFade: false,
      navigatorPosition: "BOTTOM_RIGHT",
      zoomPerClick: 1,
      animationTime: 0.01,
      maxZoomPixelRatio: 1,
      visibilityRatio: 1,
      springStiffness:0.0001,

      /* extension */
      hasZoomControl:true,
      hasDrawLayer:true,
      hasLayerManager:true,
      hasScalebar:true,
      hasMeasurementTool:true,
      hasPatchManager:true,
      hasHeatmap:false
    }
    extend(this.setting, options);

    this.viewer = new OpenSeadragon.Viewer(this.setting);

    this.slideQuery = slideQuery;
    this.slideId = slideQuery.id
    // initalize store
    this.store = new Store();
    // load image
    // set overlay thing
    this.viewer.addOnceHandler('open',this.init.bind(this));
  }

  /**
   * initialize the CAMIC and the dependenced components
   */
  init(){
    this.viewer.controls.bottomright.style.zIndex = 600;

    this.viewer.addOnceHandler('tile-loaded', function(){
      // the first tile loaded
      Loading.close();
      // set zoom and pan
      if(this.setting.states){
        const states = this.setting.states;
        let x = states.x;
        let y = states.y;

        if((!states.coordinate)&& states.coordinate!=='image' ){
         const size = this.viewer.world.getItemAt(0).source.dimensions;
         x = Math.round(x*size.x);
         y = Math.round(y*size.y);
        }

        var pt = new OpenSeadragon.Point(x, y); // x, y should in the image coordinate system
        pt = this.viewer.viewport.imageToViewportCoordinates(pt);
        this.viewer.viewport.zoomTo(states.z, pt);
        this.viewer.viewport.panTo(pt, true);

        //set a position mark
        if(states.hasMark){
          // create a mark
          const div = document.createElement('div');
          const mark = document.createElement('div');
          mark.style.transform = 'translate3d(-50%, -50%, 0)';
          mark.style.display = 'flex';
          mark.style.width = '20px';
          mark.style.height = '20px';
          mark.style.border = '2px red solid';
          mark.style.alignItems = 'center';
          mark.style.borderRadius='50%';
          mark.style.textAlign = 'center';
          const center = document.createElement('div');
          center.style.borderRadius = '50%';
          center.style.margin = '0 auto';
          center.style.width = '4px';
          center.style.height = '4px';
          center.style.backgroundColor = 'red';
          mark.appendChild(center);
          div.appendChild(mark);
          this.viewer.addOverlay({
          element: div,
          location: pt,
          checkResize: false
          });
        }

      }
    }.bind(this));

    // create draw pulgin
    this.createCanvasDraw();
    this.createOverlayers();

    // change navigator style
    if(this.setting.showNavigator){
      const nav = this.viewer.element.querySelector('.navigator');
      nav.style.backgroundColor = '#365f9c';
      nav.style.opacity = 1;
    }

    this.createZoomControl();
    this.createMeasurementTool(this.mpp);
    this.createPatchManager();
    this.createHeatmap();
  }
  /**
  * Change which image is staged, used loadImg to load it.
  */
  setImg(slideId){
    this.layers.resetAll();
    this.slideId = slideId;
  }
  /**
  * Loads the staged image
  */
  loadImg(func){
    // loads current image
    // if id is set, use id
    var slidePromise;
    if(this.slideQuery.hasOwnProperty('id') && this.slideQuery.id){
      slidePromise = this.store.getSlide(this.slideQuery.id)
    }
    else {
      slidePromise = this.store.findSlide(this.slideQuery.name, this.slideQuery.location)
    }
    slidePromise
      .then((x)=>{
        if(!x || !OpenSeadragon.isArray(x) || !x.length || !x[0].location){
          redirect($D.pages.table,`Can't find the slide information`);
          return;
        }
        this.slideId = x[0]["_id"]["$oid"]
        this.slideName = x[0]['name']
        this.study = x[0]['study']
        this.specimen = x[0]['specimen']
        this.viewer.open("./img/Slide/"+ x[0]["_id"]["$oid"] + ".dzi");
        // set scalebar
        this.createScalebar(x[0].mpp)
        var imagingHelper = new OpenSeadragonImaging.ImagingHelper({
          viewer: this.viewer
        });

        imagingHelper.setMaxZoom(1);
        if(func && typeof func === 'function') func.call(null,x[0]);
        Loading.text.textContent = `loading slide's tiles...`;
        this.mpp = x[0].mpp;

      })
      .catch(e=>{
        Loading.close();
        //$UI.message.addError('loadImg Error');
        console.error(e);

        if(func && typeof func === 'function') func.call(null,{hasError:true,message:e});
      })
  }
  /**
   * set up a zoom control functionality on the image
   */
  createZoomControl(){
    if(!this.setting.hasZoomControl || !this.viewer.cazoomctrl) return;
    this.viewer.cazoomctrl({
      position:"BOTTOM_RIGHT",
      autoFade: false
    });
  }
  /**
   * set up a canvas Draw functionality on the image
   */
  createCanvasDraw(){
    if(!this.setting.hasDrawLayer || !this.viewer.canvasDraw) return;
    this.viewer.canvasDraw();
    // create style context menu for draw
    this.drawContextmenu = new __.SimpleContextMenu(
      this.viewer.container,
      {}
    );

    // add event to hook up
    this.drawContextmenu.addHandler('style-changed',function(e){
      this.viewer.canvasDrawInstance.style = e.style;
      this.viewer.canvasDrawInstance.drawMode = e.model;
    }.bind(this));

    // this.drawContextmenu.addHandler('undo',function(e){
    //   this.viewer.canvasDrawInstance.undo();
    // }.bind(this));

    // this.drawContextmenu.addHandler('redo',function(e){
    //   this.viewer.canvasDrawInstance.redo();
    // }.bind(this));

    this.drawContextmenu.addHandler('clear',function(e){
      if(this.viewer.canvasDrawInstance._draws_data_.length == 0) return;
      if(confirm("Do you want to clear all markups?")) this.viewer.canvasDrawInstance.clear();
    }.bind(this));

    // this.drawContextmenu.addHandler('draw-mode-changed',function(e){
    //   this.viewer.canvasDrawInstance.drawMode = e.mode;
    // }.bind(this));

    //this.drawContextmenu.addHandler('draw',draw);
  }

  /**
   * set up a overlay manage on the image
   */
  createOverlayers(){
    if(!this.setting.hasLayerManager || !this.viewer.overlaysManager) return;
    this.viewer.overlaysManager();
  }

  /**
  * Set up a scalebar on the image
  * @param {number} mpp - microns per pixel of image
  */
  createScalebar(mpp){
    if(!this.setting.hasScalebar || !this.viewer.scalebar) return;
    try {
      this.viewer.scalebar({
              type: OpenSeadragon.ScalebarType.MAP,
              pixelsPerMeter: (1 / (parseFloat(mpp) * 0.000001)),
              xOffset: 5,
              yOffset: 10,
              stayInsideImage: true,
              color: "rgb(150,150,150)",
              fontColor: "rgb(100,100,100)",
              backgroundColor: "rgba(255,255,255,0.5)",
              barThickness: 2
          });
      } catch (ex) {
          console.log("scalebar err: ", ex.message);
      }
  }

  createMeasurementTool(mpp){
    if(!this.setting.hasMeasurementTool || !this.viewer.measurementTool) return;
    this.viewer.measurementTool({
      mpp:{
        x:mpp,
        y:mpp,
      }
    });
  }

  createPatchManager(){
    if(!this.setting.hasPatchManager || !this.viewer.createPatchManager) return;
    this.viewer.createPatchManager({});
  }

  createHeatmap(){
    if(!this.setting.hasHeatmap || !this.viewer.createHeatmap) return;
    this.viewer.createHeatmap({});
  }

  /**
   * Function to destroy the instance of CaMic and clean up everything created by CaMic.
   *
   * Example:
   * var camic = CaMic({
   *   [...]
   * });
   *
   * //when you are done with the camic:
   * camic.destroy();
   * camic = null; //important
   *
   */
  destroy(){
    // destroy CanvasDraw's instance if exists
    if(this.viewer.canvasDrawInstance){
      this.viewer.canvasDrawInstance.destroy();
      this.viewer.canvasDrawInstance = null;
    }

    // destroy CaZoomControl's instance if exists
    if(this.viewer.cazoomctrlInstance){
      this.viewer.cazoomctrlInstance.destroy();
      this.viewer.cazoomctrlInstance = null;
    }

    // destroy OverlayManager's instance if exists
    if(this.viewer.omanager){
      this.viewer.omanager.destroy();
      this.viewer.omanager = null;
    }

    // destroy Scalebar's instance if exists
    if(this.viewer.scalebarInstance){
      for(const key in this.viewer.scalebarInstance){
        this.viewer.scalebarInstance[key] = null;
      }
      this.viewer.scalebarInstance;
    }

    // destroy viewer if exists
    this.viewer.destroy();
    this.viewer = null;
  }
}
<|endoftext|>


<commit_before>describe("Presenter", function(){
  var self = this;
  var presenter;
  var data;

  beforeEach(function() {
    presenter = new Presenter(self);
    data = {items: [{id:1,name:"Joe", age:23, salary:3000},
                    {id:2,name:"Jim", age:33, salary:5000},
                    {id:3,name:"Mike", age:28, salary:3300},
                    {id:4,name:"Bruno", age:27, salary:4100}],
            errors:[],
            isSuccess: false,
    };
  });

  describe("when data has been loaded", function() {
    it("should have right number of persons", function() {
      var expected = 4;
      presenter.load(data);
      console.log(presenter);
      var vmo = presenter.getVMO();
      expect(vmo.items.length).toEqual(expected);
    });
  });

});
<commit_msg>Add more tests<commit_after>var Error = function(msg) {
  this.msg = msg;
};

describe("Presenter", function(){
  var self = this;
  var presenter;
  var data;
  var receivedAction;
  self.handleAction = function(action) {
    receivedAction = action;
  };

  beforeEach(function() {
    presenter = new Presenter(self);
    data = {items: [{id:1,name:"Joe", age:23, salary:3000},
                    {id:2,name:"Jim", age:33, salary:5000},
                    {id:3,name:"Mike", age:28, salary:3300},
                    {id:4,name:"Bruno", age:27, salary:4100}],
            errors:[],
            isSuccess: false,
    };
    receivedAction = null;
  });

  describe("when data has been loaded", function() {
    it("should have right number of persons", function() {
      var expected = 4;
      presenter.load(data);
      var vmo = presenter.getVMO();
      expect(vmo.items.length).toEqual(expected);
    });
  });

  describe("when delete action is performed", function() {
    beforeEach(function() {
      presenter.load(data);
    });

    it("the REMOVE action should be called with right parameters", function() {
      presenter.sendAction({action:'REMOVE',params: {id: 3}});
      expect(receivedAction.action).toEqual('REMOVE');
      expect(receivedAction.params.id).toEqual(3);
    });
  });

  describe("when update action is performed", function() {
    beforeEach(function() {
      presenter.load(data);
    });

    it("the Update action should be called with right parameters", function() {
      presenter.sendAction({action:'UPDATE',params: {data:{id:1,name:"Joe", age:55, salary:300}}});
      expect(receivedAction.action).toEqual('UPDATE');
      expect(receivedAction.params.data.id).toEqual(1);
      expect(receivedAction.params.data.name).toEqual("Joe");
      expect(receivedAction.params.data.age).toEqual(55);
      expect(receivedAction.params.data.salary).toEqual(300);
    });
  });
});
<|endoftext|>


<commit_before>/* global fetch */
const {
  Environment,
  Network,
  RecordSource,
  Store
} = require('relay-runtime')
const cognitoAuth = require('./js/utils/cognito-auth')

// Fetches the results of an operation (query/mutation/etc)
// and return its results as a Promise.
function fetchQuery (
  operation,
  variables,
  cacheConfig,
  uploadables
) {
  // TODO: mock user token here on dev
  return cognitoAuth.getUserIdToken().then((userIdToken) => {
    // Add Authorization header if user has a token.
    const headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }
    if (userIdToken) {
      headers['Authorization'] = userIdToken
    }

    return fetch(process.env.GRAPHQL_ENDPOINT, {
      method: 'POST',
      headers: headers,
      body: JSON.stringify({
        query: operation.text, // GraphQL text from input
        variables
      })
    }).then(response => {
      return response.json()
        // .then((responseJSON) => {
        //   // Temporary fix to force passing errors on to the
        //   // QueryRenderer.
        //   // https://github.com/facebook/relay/issues/1913
        //   if (responseJSON.errors && responseJSON.errors.length > 0) {
        //     responseJSON.data = null
        //     return responseJSON
        //   }
        //   return responseJSON
        // })
    })
  }).catch((err) => {
    console.log(err)
  })
}

// Create a network layer from the fetch function
const network = Network.create(fetchQuery)

const source = new RecordSource()
const store = new Store(source)

export default new Environment({
  network,
  store
})
<commit_msg>Debugging.<commit_after>/* global fetch */
const {
  Environment,
  Network,
  RecordSource,
  Store
} = require('relay-runtime')
const cognitoAuth = require('./js/utils/cognito-auth')

// Fetches the results of an operation (query/mutation/etc)
// and return its results as a Promise.
function fetchQuery (
  operation,
  variables,
  cacheConfig,
  uploadables
) {
  // TODO: mock user token here on dev
  return cognitoAuth.getUserIdToken().then((userIdToken) => {
    // Add Authorization header if user has a token.
    const headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }
    if (userIdToken) {
      headers['Authorization'] = userIdToken
    }

    return fetch(process.env.GRAPHQL_ENDPOINT, {
      method: 'POST',
      headers: headers,
      body: JSON.stringify({
        query: operation.text, // GraphQL text from input
        variables
      })
    }).then(response => {
      return response.json()
        .then((responseJSON) => {
          // Temporary fix to force passing errors on to the
          // QueryRenderer.
          // https://github.com/facebook/relay/issues/1913
          if (responseJSON.errors && responseJSON.errors.length > 0) {
            console.log('relay-env errors', responseJSON.errors)
            responseJSON.data = null
            return responseJSON
          }
          return responseJSON
        })
    })
  }).catch((err) => {
    console.log(err)
  })
}

// Create a network layer from the fetch function
const network = Network.create(fetchQuery)

const source = new RecordSource()
const store = new Store(source)

export default new Environment({
  network,
  store
})
<|endoftext|>


<commit_before>var exec = require('child_process').exec
exec('docker run -p 127.0.0.1:7001:4001 -p 127.0.0.1:2379:2379 --rm quay.io/coreos/etcd:v2.2.0 --name reconfigure-etcd -name reconfigure-etcd',
function () {
    require('proof')(2, require('cadence')(prove))
    function prove (async, assert) {
        var wrapper = require('../../reconfigure/wrapper')
        var wrap = new wrapper('127.0.0.1', '2379')
        async(function () {
            wrap.initialize(async())
            // this creates a `reconfigure` directory which will cause
            //a 'Not a file' error from `etcd` next time this is run.
        }, function () {
            console.log(arguments)
            wrap.mkdir('/test', async())
        }, function () {
            wrap.set('/test/blegh', 'haha', async())
        }, function (set) {
            assert(set.node.key, '/reconfigure/test/blegh', 'key set')
            wrap.get('/test/blegh', async())
        }, function (key) {
            assert(key.node.value, 'haha', 'retrieved monitored value')
            exec('docker kill reconfigure-etcd',
            function () {console.log(arguments)})
            exec('docker rm reconfigure-etcd',
            function () {console.log(arguments)})
        })
    }
})
<commit_msg>Connect to dockerized `etcd` for testing.<commit_after>require('proof')(2, require('cadence')(prove))
function prove (async, assert) {
    var wrapper = require('../../reconfigure/wrapper')
    var exec = require('child_process').exec
    var ip = '0.0.0.0' // /[^0-9]*\([0-9.]*\).*/\1/.exec(process.env.DOCKER_HOST) << doesn't work
    var wrap = new wrapper(ip, '2379')
    async([
        async(function () {
            exec('docker kill reconfigure-etcd', async())
        }, function () {
            exec('docker rm reconfigure-etcd', async())
        })
    ], function () {
        exec('docker run --rm -p 4001:4001 -p 2380:2380 -p 2379:2379 \
             --name reconfigure-etcd quay.io/coreos/etcd \
             -name reconfigure-etcd \
             -advertise-client-urls http://' + ip + ':2379,http://' + ip + ':4001 \
             -listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \
             -initial-advertise-peer-urls http://' + ip + ':2380 \
             -listen-peer-urls http://0.0.0.0:2380 \
             -initial-cluster-token etcd-cluster-1 \
             -initial-cluster etcd0=http://' + ip + ':2380 \
             -initial-cluster-state new', async())
    }, function () {
        console.log(arguments)
        wrap.initialize(async())
    }, function () {
        wrap.mkdir('/test', async())
    }, function () {
        wrap.set('/test/blegh', 'haha', async())
    }, function (set) {
        assert(set.node.key, '/reconfigure/test/blegh', 'key set')
        wrap.get('/test/blegh', async())
    }, function (key) {
        assert(key.node.value, 'haha', 'retrieved monitored value')
    })
}
/*
function () {console.log(arguments)})
function () {console.log(arguments)})
*/
<|endoftext|>


<commit_before>'use strict';
/**
 * Adwords Service Object
 * This object acts as many adwords objects
 */

const _ = require('underscore');
const soap = require('soap');
const async = require('async');
const AdwordsAuth = require('./auth');
const AdwordsConstants = require('./constants');

class AdwordsService {

    /**
     * @inheritDoc
     */
    constructor(credentials, serviceDescriptor) {
        this.credentials = credentials;
        this.auth = new AdwordsAuth(credentials);
        this.serviceDescriptor = serviceDescriptor;
        this.registerServiceDescriptorMethods(this.serviceDescriptor.methods);
    }

    /**
     * Attaches a function to the current service object
     * This is sort of like using the "Proxy.create" method
     * but have to wait till it is finalized in ES6
     * @access protected
     * @param methods {array} an array of string method names
     */
    registerServiceDescriptorMethods(methods) {
        for (var index in methods) {
            var method = methods[index];
            this[method] = this.callServiceMethod(method);
        }
    }

    /**
     * Helper method to call the service properly
     * @access private
     * @param method {string} the method name for the service
     * @return {function} returns a service call method to invoke.
     */
    callServiceMethod(method) {
        return _.bind(function() {
            this.callService(method, arguments[0] || [], arguments[1] || function() {}, true);
        }, this);
    }

    /**
     * The bread and butter method that calls the adwords service.
     * This method should never be called directly
     * @access protected
     * @param method {string} the method to call e.g. `get` or `mutate`
     * @param payload {object} the request object to send to adwords
     * @param callback {function}
     * @param shouldRetry {boolean} should retry if there is an oAuth error
     */
    callService(method, payload, callback, shouldRetry) {
        async.parallel([
            this.getClient.bind(this),
            this.getAccessToken.bind(this)
        ], (error) => {
            if (error) {
                return callback(error);
            }

            this.client.setSecurity(
                new soap.BearerSecurity(this.credentials.access_token)
            );

            this.client[method](payload, this.parseResponse((error, response) => {
                if (error
                    && shouldRetry
                    && -1 !== error.toString().indexOf(AdwordsConstants.OAUTH_ERROR)) {
                        this.credentials.access_token = null;
                        return this.callService(method, payload, callback, false);
                }
                callback(error, response);
            }));
        });
    }

    /**
     * Parses the response from adwords
     * @access protected
     * @param callback
     * @return {function} a function that returns a parsed response
     */
    parseResponse(callback) {
        return function(error, response) {
            callback(error, (response && response.rval) || response);
        }
    }

    /**
     * Helper method to get the SOAP client
     * @access protected
     * @param callback {function} returns a function with error, soapclient and meta data
     */
    getClient(callback) {
        if (this.client && this.clientDetails) {
            return callback(null, this.client, this.clientDetails);
        }

        soap.createClient(this.serviceDescriptor.wsdl, (error, client) => {
            if (error) {
                return callback(error);
            }

            this.client = client;
            this.client.on('request', (request) => this.log('request', request));
            this.client.on('response', (response) => this.log('response', response));
            this.client.on('soapError', (error) => this.log('soapError', error));

            var clientDetails = {};
            clientDetails.description = this.client.describe();
            clientDetails.namespace = 'ns1';
            clientDetails.name = _.keys(clientDetails.description)[0];
            clientDetails.port = _.keys(clientDetails.description[clientDetails.name])[0];
            clientDetails.methods = _.keys(clientDetails.description[clientDetails.name][clientDetails.port]);
            this.clientDetails = clientDetails;

            this.client.addSoapHeader({
                RequestHeader: {
                    developerToken: this.credentials.developerToken,
                    userAgent: this.credentials.userAgent,
                    clientCustomerId: this.credentials.clientCustomerId,
                    validateOnly: !!this.credentials.validateOnly
                }
            },
            this.clientDetails.name,
            this.clientDetails.namespace,
            this.serviceDescriptor.xmlns);

            return callback(null, this.client, this.clientDetails);
        })

    }

    /**
     * Gets an access token
     * @access protected
     * @param callback {function}
     */
    getAccessToken(callback) {
        if (this.credentials.access_token) {
            return callback(null, this.credentials.access_token);
        }

        this.auth.refreshAccessToken(this.credentials.refresh_token, (error, tokens) => {
            if (error) {
                return callback(error);
            }
            this.credentials.access_token = tokens.access_token;
            callback(null, this.credentials.access_token);
        });
    }

    /**
     * Helper method to log all the soap calls
     * @access private
     */
    log() {
        if (this.credentials.debug) {
            console.log(arguments);
        }
    }

}

module.exports = AdwordsService;
<commit_msg>Make field clientCustomerId optional in RequestHeader<commit_after>'use strict';
/**
 * Adwords Service Object
 * This object acts as many adwords objects
 */

const _ = require('underscore');
const soap = require('soap');
const async = require('async');
const AdwordsAuth = require('./auth');
const AdwordsConstants = require('./constants');

class AdwordsService {

    /**
     * @inheritDoc
     */
    constructor(credentials, serviceDescriptor) {
        this.credentials = credentials;
        this.auth = new AdwordsAuth(credentials);
        this.serviceDescriptor = serviceDescriptor;
        this.registerServiceDescriptorMethods(this.serviceDescriptor.methods);
    }

    /**
     * Attaches a function to the current service object
     * This is sort of like using the "Proxy.create" method
     * but have to wait till it is finalized in ES6
     * @access protected
     * @param methods {array} an array of string method names
     */
    registerServiceDescriptorMethods(methods) {
        for (var index in methods) {
            var method = methods[index];
            this[method] = this.callServiceMethod(method);
        }
    }

    /**
     * Helper method to call the service properly
     * @access private
     * @param method {string} the method name for the service
     * @return {function} returns a service call method to invoke.
     */
    callServiceMethod(method) {
        return _.bind(function() {
            this.callService(method, arguments[0] || [], arguments[1] || function() {}, true);
        }, this);
    }

    /**
     * The bread and butter method that calls the adwords service.
     * This method should never be called directly
     * @access protected
     * @param method {string} the method to call e.g. `get` or `mutate`
     * @param payload {object} the request object to send to adwords
     * @param callback {function}
     * @param shouldRetry {boolean} should retry if there is an oAuth error
     */
    callService(method, payload, callback, shouldRetry) {
        async.parallel([
            this.getClient.bind(this),
            this.getAccessToken.bind(this)
        ], (error) => {
            if (error) {
                return callback(error);
            }

            this.client.setSecurity(
                new soap.BearerSecurity(this.credentials.access_token)
            );

            this.client[method](payload, this.parseResponse((error, response) => {
                if (error
                    && shouldRetry
                    && -1 !== error.toString().indexOf(AdwordsConstants.OAUTH_ERROR)) {
                        this.credentials.access_token = null;
                        return this.callService(method, payload, callback, false);
                }
                callback(error, response);
            }));
        });
    }

    /**
     * Parses the response from adwords
     * @access protected
     * @param callback
     * @return {function} a function that returns a parsed response
     */
    parseResponse(callback) {
        return function(error, response) {
            callback(error, (response && response.rval) || response);
        }
    }

    /**
     * Helper method to get the SOAP client
     * @access protected
     * @param callback {function} returns a function with error, soapclient and meta data
     */
    getClient(callback) {
        if (this.client && this.clientDetails) {
            return callback(null, this.client, this.clientDetails);
        }

        soap.createClient(this.serviceDescriptor.wsdl, (error, client) => {
            if (error) {
                return callback(error);
            }

            this.client = client;
            this.client.on('request', (request) => this.log('request', request));
            this.client.on('response', (response) => this.log('response', response));
            this.client.on('soapError', (error) => this.log('soapError', error));

            var clientDetails = {};
            clientDetails.description = this.client.describe();
            clientDetails.namespace = 'ns1';
            clientDetails.name = _.keys(clientDetails.description)[0];
            clientDetails.port = _.keys(clientDetails.description[clientDetails.name])[0];
            clientDetails.methods = _.keys(clientDetails.description[clientDetails.name][clientDetails.port]);
            this.clientDetails = clientDetails;

            var header = {
                RequestHeader: {
                    developerToken: this.credentials.developerToken,
                    userAgent: this.credentials.userAgent,
                    validateOnly: !!this.credentials.validateOnly
                }
            };

            if (this.credentials.clientCustomerId) {
                header.RequestHeader.clientCustomerId = this.credentials.clientCustomerId;
            }

            this.client.addSoapHeader(header,
            this.clientDetails.name,
            this.clientDetails.namespace,
            this.serviceDescriptor.xmlns);

            return callback(null, this.client, this.clientDetails);
        })

    }

    /**
     * Gets an access token
     * @access protected
     * @param callback {function}
     */
    getAccessToken(callback) {
        if (this.credentials.access_token) {
            return callback(null, this.credentials.access_token);
        }

        this.auth.refreshAccessToken(this.credentials.refresh_token, (error, tokens) => {
            if (error) {
                return callback(error);
            }
            this.credentials.access_token = tokens.access_token;
            callback(null, this.credentials.access_token);
        });
    }

    /**
     * Helper method to log all the soap calls
     * @access private
     */
    log() {
        if (this.credentials.debug) {
            console.log(arguments);
        }
    }

}

module.exports = AdwordsService;
<|endoftext|>


<commit_before>/**
 * The TiledLayer is the visual tiled layer that actually displays on the screen
 *
 * This class will be created by the TiledMap, there shouldn't be a reason to
 * create an instance on your own.
 *
 * @module gf
 * @class TiledLayer
 * @extends Layer
 * @constructor
 * @param layer {Object} All the settings for the layer
 */
//see: https://github.com/GoodBoyDigital/pixi.js/issues/48
gf.TiledLayer = function(layer) {
    gf.Layer.call(this, layer);

    /**
     * The tile IDs of the tilemap
     *
     * @property name
     * @type Uint32Array
     */
    this.tiles = new Uint32Array(layer.data);

    /**
     * The sprite pool for rendering tiles
     *
     * @property tilePool
     * @type Array
     */
    this.spritePool = [];

    //translate some tiled properties to our inherited properties
    this.position.x = layer.x;
    this.position.y = layer.y;
    this.alpha = layer.opacity;
};

gf.inherits(gf.TiledLayer, gf.Layer, {
    /**
     * Creates all the tile sprites needed to display the layer
     *
     * @method renderTiles
     */
    renderTiles: function(startX, startY, numX, numY) {
        for(var x = startX; x < numX; ++x) {
            for(var y = startY; y < numY; ++y) {
                var id = (x + (y * this.size.x)),
                    tile = this.tiles[id],
                    set = this.parent.getTileset(tile);

                if(!set) continue;

                var spr = this.getTileSprite(tile, set);

                spr.position.x = x * this.parent.tileSize.x;
                spr.position.y = y * this.parent.tileSize.y;
                //spr.scale = this.scale;
                //spr.rotation = this.rotation;
                //spr.alpha = this.alpha;
                this.addChild(spr);
            }
        }
    },
    /**
     * Creates the sprite for a tile utilizing a pool for the sprites
     *
     * @method getTileSprite
     * @param tileId {Number} The id of the tile to get a sprite for
     * @param TiledTileset {tileset} The tileset to get the texture from
     * @return {PIXI.Sprite} The sprite to display
     */
    getTileSprite: function(id, tileset) {
        return this.spritePool.pop() || new PIXI.Sprite(tileset.getTileTexture(id));
    },
    /**
     * Frees a sprite back into the pool
     *
     * @method freeTileSprite
     * @param sprite {PIXI.Sprite} The sprite to release to the pool
     */
    freeTileSprite: function(spr) {
        this.spritePool.push(spr);
    },
    /**
     * Transforms an x,y coord into the index of a tile in the tiles array
     *
     * @method getTileIndex
     * @param x {Number|Vector} The x coord to transform, if a vector is passed it's x/y is used and the y param is ignored
     * @param y {Number} The y coord to transform
     * @return {Number}
     */
    getTileIndex: function(x, y) {
        x = x instanceof gf.Vector ? x.x : x;
        y = x instanceof gf.Vector ? x.y : y;

        //convert the position from units to tiles
        x = ~~(x / this.parent.tileSize.x);
        y = ~~(y / this.parent.tileSize.y);

        //calculate index of this tile
        return (x + (y * this.size.x));
    },
    /**
     * Transforms an x,y coord into the TiledTileset tile id
     *
     * @method getTileId
     * @param x {Number|Vector} The x coord to transform, if a vector is passed it's x/y is used and the y param is ignored
     * @param y {Number} The y coord to transform
     * @return {Number}
     */
    getTileId: function(x, y) {
        return this.tiles[this.getTileIndex(x, y)];
    }
});
<commit_msg>implement layer pan, smarter sprite cache<commit_after>/**
 * The TiledLayer is the visual tiled layer that actually displays on the screen
 *
 * This class will be created by the TiledMap, there shouldn't be a reason to
 * create an instance on your own.
 *
 * @module gf
 * @class TiledLayer
 * @extends Layer
 * @constructor
 * @param layer {Object} All the settings for the layer
 */
//see: https://github.com/GoodBoyDigital/pixi.js/issues/48
gf.TiledLayer = function(layer) {
    gf.Layer.call(this, layer);

    /**
     * The tile IDs of the tilemap
     *
     * @property name
     * @type Uint32Array
     */
    this.tiles = new Uint32Array(layer.data);

    /**
     * The sprite pool for rendering tiles
     *
     * @property tilePool
     * @type Array
     */
    this.sprites = [];

    //translate some tiled properties to our inherited properties
    this.position.x = layer.x;
    this.position.y = layer.y;
    this.alpha = layer.opacity;

    this._panDelta = new gf.Vector(0, 0);
    this._rendered = new PIXI.Rectangle(0, 0, 0, 0);
};

gf.inherits(gf.TiledLayer, gf.Layer, {
    /**
     * Creates all the tile sprites needed to display the layer
     *
     * @method renderTiles
     */
    renderTiles: function(startX, startY, numX, numY) {
        //add a 1 tile buffer around the viewport
        if(startX >= 1) startX -= 1;
        if(startX + numX < this.size.x) numX += 1;

        if(startY >= 1) startY -= 1;
        if(startY + numY < this.size.y) numY += 1;

        for(var x = startX; x < numX; ++x) {
            for(var y = startY; y < numY; ++y) {
                this.moveTileSprite(x, y, x, y);
            }
        }

        this._rendered.x = startX;
        this._rendered.y = startY;
        this._rendered.width = numX;
        this._rendered.height = numY;
        this._rendered.left = this._rendered.x;
        this._rendered.right = this._rendered.x + this._rendered.width;
        this._rendered.top = this._rendered.y;
        this._rendered.bottom = this._rendered.y + this._rendered.height;
    },
    /**
     * Creates the sprite for a tile and caches it in a position
     *
     * @method getTileSprite
     * @param tileX {Number} The x coord of the tile in units of tiles (not pixels)
     * @param tileY {Number} The y coord of the tile in units of tiles (not pixels)
     * @return {PIXI.Sprite} The sprite to display
     */
    getTileSprite: function(tileX, tileY) {
        if(this.sprites[tileX] && this.sprites[tileY])
            return this.sprites[tileX][tileY];

        if(!this.sprites[tileX]) this.sprites[tileX] = [];

        var id = (tileX + (tileY * this.size.x)),
            tile = this.tiles[id],
            set = this.parent.getTileset(tile);

        if(set) {
            this.sprites[tileX][tileY] = new PIXI.Sprite(set.getTileTexture(tile));
            this.addChild(this.sprites[tileX][tileY]);
        }

        return this.sprites[x][y];
    },
    moveTileSprite: function(fromTileX, fromTileY, toTileX, toTileY) {
        var spr = this.getTileSprite(fromTileX, fromTileY),
            id = (toTileX + (toTileY * this.size.x)),
            tile = this.tiles[id],
            set = this.parent.getTileset(tile);

        if(set) spr.texture = set.getTileTexture(tile);
        spr.position.x = toTileX * this.parent.tileSize.x;
        spr.position.y = toTileY * this.parent.tileSize.y;

        //move the sprite in the pool
        this.sprites[fromTileX][fromTileY] = null;
        this.sprites[toTileX][toTileY] = spr;

        return spr;
    },
    /**
     * Transforms an x,y coord into the index of a tile in the tiles array
     *
     * @method getTileIndex
     * @param x {Number|Vector} The x coord to transform, if a vector is passed it's x/y is used and the y param is ignored
     * @param y {Number} The y coord to transform
     * @return {Number}
     */
    getTileIndex: function(x, y) {
        x = x instanceof gf.Vector ? x.x : x;
        y = x instanceof gf.Vector ? x.y : y;

        //convert the position from units to tiles
        x = Math.floor(x / this.parent.tileSize.x);
        y = Math.floor(y / this.parent.tileSize.y);

        //calculate index of this tile
        return (x + (y * this.size.x));
    },
    /**
     * Transforms an x,y coord into the TiledTileset tile id
     *
     * @method getTileId
     * @param x {Number|Vector} The x coord to transform, if a vector is passed it's x/y is used and the y param is ignored
     * @param y {Number} The y coord to transform
     * @return {Number}
     */
    getTileId: function(x, y) {
        return this.tiles[this.getTileIndex(x, y)];
    },
    /**
     * Pans the layer around, rendering stuff if necessary
     *
     * @method pan
     * @param dx {Number|Point} The x amount to pan, if a Point is passed the dy param is ignored
     * @param dy {Number} The y ammount to pan
     * @return {Layer} Returns itself for chainability
     */
    pan: function(dx, dy) {
        this._panDelta.x += dx;
        this._panDelta.y += dy;1

        //moved 1 tile right
        if(this._panDelta.x >= this.parent.tileSize.x) {
            //free all the far left tiles back to the pool, and render the right tiles
            for(i = 0; i < this._rendered.numY; ++i) {
                this.moveTileSprite(
                    this._rendered.x,       this._rendered.y + i,
                    this._rendered.right + 1,   this._rendered.y + i
                );
            }
            this._rendered.x++;
        }
        //moved 1 tile left
        else if(this._panDelta.x <= -this.parent.tileSize.x) {
            //free all the far right tiles back to the pool, and render the left tiles
            for(i = 0; i < this._rendered.numY; ++i) {
                this.moveTileSprite(
                    this._rendered.right, this._rendered.y + i,
                    this._rendered.x - 1, this._rendered.y + i
                );
            }
            this._rendered.x--;
        }

        //moved 1 tile down
        if(this._panDelta.y >= this.parent.tileSize.y) {
            //free all the far top tiles back to the pool, and render the bottom tiles
            for(i = 0; i < this._rendered.numX; ++i) {
                this.moveTileSprite(
                    this._rendered.x + i, this._rendered.y,
                    this._rendered.x + i, this._rendered.bottom + 1
                );
            }
            this._rendered.y++;
        }
        //moved 1 tile up
        else if(this._panDelta.y <= -this.parent.tileSize.y) {
            //free all the far bottom tiles back to the pool, and render the top tiles
            for(i = 0; i < this._rendered.numX; ++i) {
                this.moveTileSprite(
                    this._rendered.x + i, this._rendered.bottom,
                    this._rendered.x + i, this._rendered.y - 1,
                );
            }
            this._rendered.y--;
        }

        this._rendered.left = this._rendered.x;
        this._rendered.right = this._rendered.x + this._rendered.width;
        this._rendered.top = this._rendered.y;
        this._rendered.bottom = this._rendered.y + this._rendered.height;
    }
});
<|endoftext|>