<commit_before>if(typeof(define) !== 'function') {
  var define = require('amdefine')(module);
}

define(['requirejs'], function(requirejs) {
  var suites = [];

  var util;

  global.localStorage = require('localStorage');

  function stubWidgetView() {
    var calls = [], results = {};
    return util.extend(
      // stub state
      { _calls: calls, _results: results },
      // event emitter
      util.getEventEmitter('connect', 'disconnect', 'sync', 'reconnect'),
      // method stubs
      ['display',
       'setState',
       'redirectTo',
       'setUserAddress',
       'getLocation',
       'setLocation'
      ].reduce(function(stubs, method) {
        stubs[method] = function() {
          calls.push({
            method: method,
            args: util.toArray(arguments)
          });
          return results[method];
        };
        return stubs;
      }, {})
    );
  }

  function argEq(expected, actual) {
    for(var i=0;i<expected.length;i++) {
      if(expected[i] !== actual[i]) {
        return false;
      }
    }
    return true;
  }

  function expectCall(test, object, methodName, args) {
    for(var i=0;i<object._calls.length;i++) {
      var call = object._calls[i];
      if(call.method === methodName) {
        if((! args) || argEq(args, call.args)) {
          return test.assertAnd(true, true);
        }
      }
    }
    return test.assertAnd(true, false);
  }

  suites.push({
    name: "widget.js tests",
    desc: "widget controller implementation",
    setup: function(env) {
      var _this = this;
      requirejs([
        './src/lib/util',
        './src/lib/widget',
        './src/lib/sync',
        './src/lib/wireClient',
        './src/lib/baseClient',
        './src/lib/getputdelete',
        './src/lib/webfinger'
      ], function(_util, widget, sync, wireClient, baseClient, getputdelete, webfinger) {
        util = _util;
        env.widget = widget;
        env.view = stubWidgetView();
        env.widget.setView(env.view);
        env.sync = sync;
        env.wireClient = wireClient;
        env.baseClient = baseClient;
        env.getputdelete = getputdelete;
        env.webfinger = webfinger;

        env.origGetStorageInfo = env.webfinger.getStorageInfo;
        env.webfinger.getStorageInfo = function() {
          var promise = util.getPromise();
          env.fakefinger.push({
            args: util.toArray(arguments),
            promise: promise
          });
          return promise;
        }

        env.fakeRemoteStorage = {
          claimedModules: { foo: 'rw' }
        };

        env.view._results['getLocation'] = 'http://test.host/';
        _this.result(true);
      });
    },

    takedown: function(env, test) {
      env.webfinger.getStorageInfo = env.origGetStorageInfo;
      test.result(true);
    },

    beforeEach: function(env, test) {
      env.fakefinger = [];
      test.result(true);
    },

    afterEach: function(env, test) {
      // clean up event handlers after each test
      env.sync.reset();
      env.wireClient.reset();
      env.baseClient.reset();
      test.result(true);
    },

    tests: [

      {
        desc: "widget.display sets up event handlers on the view",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          this.assertAnd(env.view.hasHandler('connect'), true);
          this.assertAnd(env.view.hasHandler('sync'), true);
          this.assertAnd(env.view.hasHandler('disconnect'), true);
          this.assert(env.view.hasHandler('reconnect'), true);
        }
      },

      {
        desc: "widget.display sets up event handlers on sync, wireClient and baseClient",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          this.assertAnd(env.sync.hasHandler('busy'), true);
          this.assertAnd(env.sync.hasHandler('ready'), true);
          this.assertAnd(env.sync.hasHandler('error'), true);
          this.assertAnd(env.sync.hasHandler('timeout'), true);
          this.assertAnd(env.wireClient.hasHandler('connected'), true);
          this.assertAnd(env.wireClient.hasHandler('disconnected'), true);
          this.assert(env.baseClient.hasHandler('error'), true);
        }
      },

      {
        desc: "widget.display strips all params from the fragment",
        run: function(env) {
          env.view._results['getLocation'] = 'http://test.host/#abc=def&remotestorage=foo@bar.baz';
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          expectCall(this, env.view, 'setLocation', ['http://test.host/#']) &&
            expectCall(this, env.view, 'setUserAddress', ['foo@bar.baz']) &&
            this.result(true);
        }
      },

      {
        desc: "forwards sync busy / ready state to the view",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          env.sync.emit('busy');
          if(! expectCall(this, env.view, 'setState', ['busy'])) {
            return;
          }
          env.sync.emit('ready');
          if(! expectCall(this, env.view, 'setState', ['connected'])) {
            return;
          }
          this.result(true);
        }
      },

      {
        desc: "forwards wireClient connected / disconnected state to the view",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          // FIXME: won't work, because 'initialSync' causes errors
          // env.wireClient.emit('connected');
          // if(! expectCall(this, env.view, 'setState', ['connected'])) {
          //   return;
          // }
          env.wireClient.emit('disconnected');
          if(! expectCall(this, env.view, 'setState', ['initial'])) {
            return;
          }
          this.result(true);
        }
      },

      {
        desc: "increases timeout for webfinger and getputdelete, when 'timeout' event is fired from sync",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          // initially set to 1s
          env.getputdelete.setTimeout(1000);
          env.webfinger.setTimeout(1000);
          env.sync.emit('timeout');
          util.nextTick(function() {
            test.assertAnd(env.getputdelete.getTimeout(), 1500);
            test.assert(env.webfinger.getTimeout(), 1500);
          });
        }
      },

      {
        desc: "adjusts timeout on webfinger 'timeout' error",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          env.getputdelete.setTimeout(1000);
          env.webfinger.setTimeout(1000);
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            var storageInfoReq = env.fakefinger.shift();
            test.assertTypeAnd(storageInfoReq, 'object', "expected webfinger.getStoageInfo to have been called!");
            test.assertAnd(storageInfoReq.args[0], 'foo@bar.baz');
            storageInfoReq.promise.reject('timeout');
            util.nextTick(function() {
              test.assertAnd(env.getputdelete.getTimeout(), 1500);
              test.assert(env.webfinger.getTimeout(), 1500);
            });
          });
        }
      },

      {
        desc: "#display() redirects correctly after the webfinger discovery",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              // the result from getLocation
              test.assertAnd(params.redirect_uri, 'http://test.host/');
              // determined through env.fakeRemoteStorage
              test.assertAnd(params.scope, 'foo:rw');
              test.assertAnd(params.response_type, 'token');
              test.done();
            }, 150);
          });
        }
      },

      {
        desc: "#display() allows overriding the redirect_uri through options",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {
            redirectUri: 'http://other/place'
          });
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              test.assert(params.redirect_uri, 'http://other/place');
            }, 150);
          });
        }
      },

      {
        desc: "a redirect_uri containing a fragment strips the fragment before setting the parameter",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {
            redirectUri: 'http://other/place#foo'
          });
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              test.assert(params.redirect_uri, 'http://other/place');
            }, 150);
          });
        }
      },

      {
        desc: "a redirect_uri containing a fragment sets the 'state' parameter to the fragment",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {
            redirectUri: 'http://other/place#foo'
          });
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              test.assert(params.state, 'foo');
            }, 150);
          });
        }
      },

      {
        desc: "#display() recovers the fragment from the 'state' parameter",
        run: function(env, test) {
          env.view._results['getLocation'] = 'http://test.host/#abc=def&remotestorage=foo@bar.baz&state=foobar';
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          expectCall(test, env.view, 'setLocation', ['http://test.host/#foobar']);
          test.done();
        }
      },

    ]
  });

  return suites;
});
<commit_msg>repaired widget test<commit_after>if(typeof(define) !== 'function') {
  var define = require('amdefine')(module);
}

define(['requirejs'], function(requirejs) {
  var suites = [];

  var util;

  global.localStorage = require('localStorage');

  function stubWidgetView() {
    var calls = [], results = {};
    return util.extend(
      // stub state
      { _calls: calls, _results: results },
      // event emitter
      util.getEventEmitter('connect', 'disconnect', 'sync', 'reconnect'),
      // method stubs
      ['display',
       'setState',
       'redirectTo',
       'setUserAddress',
       'getLocation',
       'setLocation'
      ].reduce(function(stubs, method) {
        stubs[method] = function() {
          calls.push({
            method: method,
            args: util.toArray(arguments)
          });
          return results[method];
        };
        return stubs;
      }, {})
    );
  }

  function argEq(expected, actual) {
    for(var i=0;i<expected.length;i++) {
      if(expected[i] !== actual[i]) {
        return false;
      }
    }
    return true;
  }

  function expectCall(test, object, methodName, args) {
    for(var i=0;i<object._calls.length;i++) {
      var call = object._calls[i];
      if(call.method === methodName) {
        if((! args) || argEq(args, call.args)) {
          return test.assertAnd(true, true);
        }
      }
    }
    return test.assertAnd(true, false);
  }

  suites.push({
    name: "widget.js tests",
    desc: "widget controller implementation",
    setup: function(env) {
      var _this = this;
      requirejs([
        './src/lib/util',
        './src/lib/widget',
        './src/lib/sync',
        './src/lib/wireClient',
        './src/lib/baseClient',
        './src/lib/getputdelete',
        './src/lib/webfinger',
        './src/lib/access'
      ], function(_util, widget, sync, wireClient, baseClient, getputdelete, webfinger, Access) {
        util = _util;
        env.widget = widget;
        env.view = stubWidgetView();
        env.widget.setView(env.view);
        env.sync = sync;
        env.wireClient = wireClient;
        env.baseClient = baseClient;
        env.getputdelete = getputdelete;
        env.webfinger = webfinger;
        env.Access = Access;

        env.origGetStorageInfo = env.webfinger.getStorageInfo;
        env.webfinger.getStorageInfo = function() {
          var promise = util.getPromise();
          env.fakefinger.push({
            args: util.toArray(arguments),
            promise: promise
          });
          return promise;
        }

        env.fakeRemoteStorage = {
          access: new env.Access()
        };

        env.fakeRemoteStorage.access.claim('foo', 'rw');

        env.view._results['getLocation'] = 'http://test.host/';
        _this.result(true);
      });
    },

    takedown: function(env, test) {
      env.webfinger.getStorageInfo = env.origGetStorageInfo;
      test.result(true);
    },

    beforeEach: function(env, test) {
      env.fakefinger = [];
      test.result(true);
    },

    afterEach: function(env, test) {
      // clean up event handlers after each test
      env.sync.reset();
      env.wireClient.reset();
      env.baseClient.reset();
      test.result(true);
    },

    tests: [

      {
        desc: "widget.display sets up event handlers on the view",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          this.assertAnd(env.view.hasHandler('connect'), true);
          this.assertAnd(env.view.hasHandler('sync'), true);
          this.assertAnd(env.view.hasHandler('disconnect'), true);
          this.assert(env.view.hasHandler('reconnect'), true);
        }
      },

      {
        desc: "widget.display sets up event handlers on sync, wireClient and baseClient",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          this.assertAnd(env.sync.hasHandler('busy'), true);
          this.assertAnd(env.sync.hasHandler('ready'), true);
          this.assertAnd(env.sync.hasHandler('error'), true);
          this.assertAnd(env.sync.hasHandler('timeout'), true);
          this.assertAnd(env.wireClient.hasHandler('connected'), true);
          this.assertAnd(env.wireClient.hasHandler('disconnected'), true);
          this.assert(env.baseClient.hasHandler('error'), true);
        }
      },

      {
        desc: "widget.display strips all params from the fragment",
        run: function(env) {
          env.view._results['getLocation'] = 'http://test.host/#abc=def&remotestorage=foo@bar.baz';
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          expectCall(this, env.view, 'setLocation', ['http://test.host/#']) &&
            expectCall(this, env.view, 'setUserAddress', ['foo@bar.baz']) &&
            this.result(true);
        }
      },

      {
        desc: "forwards sync busy / ready state to the view",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          env.sync.emit('busy');
          if(! expectCall(this, env.view, 'setState', ['busy'])) {
            return;
          }
          env.sync.emit('ready');
          if(! expectCall(this, env.view, 'setState', ['connected'])) {
            return;
          }
          this.result(true);
        }
      },

      {
        desc: "forwards wireClient connected / disconnected state to the view",
        run: function(env) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          // FIXME: won't work, because 'initialSync' causes errors
          // env.wireClient.emit('connected');
          // if(! expectCall(this, env.view, 'setState', ['connected'])) {
          //   return;
          // }
          env.wireClient.emit('disconnected');
          if(! expectCall(this, env.view, 'setState', ['initial'])) {
            return;
          }
          this.result(true);
        }
      },

      {
        desc: "increases timeout for webfinger and getputdelete, when 'timeout' event is fired from sync",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          // initially set to 1s
          env.getputdelete.setTimeout(1000);
          env.webfinger.setTimeout(1000);
          env.sync.emit('timeout');
          util.nextTick(function() {
            test.assertAnd(env.getputdelete.getTimeout(), 1500);
            test.assert(env.webfinger.getTimeout(), 1500);
          });
        }
      },

      {
        desc: "adjusts timeout on webfinger 'timeout' error",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          env.getputdelete.setTimeout(1000);
          env.webfinger.setTimeout(1000);
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            var storageInfoReq = env.fakefinger.shift();
            test.assertTypeAnd(storageInfoReq, 'object', "expected webfinger.getStoageInfo to have been called!");
            test.assertAnd(storageInfoReq.args[0], 'foo@bar.baz');
            storageInfoReq.promise.reject('timeout');
            util.nextTick(function() {
              test.assertAnd(env.getputdelete.getTimeout(), 1500);
              test.assert(env.webfinger.getTimeout(), 1500);
            });
          });
        }
      },

      {
        desc: "#display() redirects correctly after the webfinger discovery",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              // the result from getLocation
              test.assertAnd(params.redirect_uri, 'http://test.host/');
              // determined through env.fakeRemoteStorage
              test.assertAnd(params.scope, 'foo:rw');
              test.assertAnd(params.response_type, 'token');
              test.done();
            }, 150);
          });
        }
      },

      {
        desc: "#display() allows overriding the redirect_uri through options",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {
            redirectUri: 'http://other/place'
          });
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              test.assert(params.redirect_uri, 'http://other/place');
            }, 150);
          });
        }
      },

      {
        desc: "a redirect_uri containing a fragment strips the fragment before setting the parameter",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {
            redirectUri: 'http://other/place#foo'
          });
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              test.assert(params.redirect_uri, 'http://other/place');
            }, 150);
          });
        }
      },

      {
        desc: "a redirect_uri containing a fragment sets the 'state' parameter to the fragment",
        run: function(env, test) {
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {
            redirectUri: 'http://other/place#foo'
          });
          env.view.emit('connect', 'foo@bar.baz');
          util.nextTick(function() {
            env.fakefinger.shift().promise.fulfill({
              rel: 'remotestorage',
              type: 'remotestorage-00',
              href: 'http://local.dev/storage/me',
              properties: {
                'auth-method': '',
                'auth-endpoint': 'http://local.dev/auth/me'
              }
            });
            setTimeout(function() {
              var redirectCall = env.view._calls.pop();
              test.assertAnd(redirectCall.method, 'redirectTo');
              test.assertAnd(redirectCall.args.length, 1);
              var url = redirectCall.args[0];
              test.assertAnd(url.split('?')[0], 'http://local.dev/auth/me');
              var params = {};
              url.split('?')[1].split('&').forEach(function(part) {
                var kv = part.split('=').map(decodeURIComponent);
                params[kv[0]] = kv[1];
              });
              test.assert(params.state, 'foo');
            }, 150);
          });
        }
      },

      {
        desc: "#display() recovers the fragment from the 'state' parameter",
        run: function(env, test) {
          env.view._results['getLocation'] = 'http://test.host/#abc=def&remotestorage=foo@bar.baz&state=foobar';
          env.widget.display(env.fakeRemoteStorage, 'remotestorage-connect', {});
          expectCall(test, env.view, 'setLocation', ['http://test.host/#foobar']);
          test.done();
        }
      }

    ]
  });

  return suites;
});
<|endoftext|>


<commit_before>'use strict';

(function () {
  angular.module('google-maps').

  factory('googleMapsUtils', [function() {

    var counter = 0;
    function getCount() {
      return counter++;
    }

    /**
     * @param {Object} a jQuery/angular element
     * @return a unique id for the given element (as long as you don't use
     * integers for html id attributes)
     */
    function getMapId(elm) {
      var id = elm.attr('id') || elm.data('id');
      if (!id) {
        id = getCount();
        elm.data('id', id);
      }
      return id;
    }

    /**
     * Check if two floating point numbers are equal.
     * @return true if f1 and f2 are 'very close'
     */
    function floatEqual (f1, f2) {
      return (Math.abs(f1 - f2) < 0.000001);
    }

    /**
     * @param {google.maps.LatLng} l1
     * @param {google.maps.LatLng} l2
     * @return {boolean} true if l1 and l2 are 'very close'. If either are null
     * or not google.maps.LatLng objects returns false.
     */
    function latLngEqual(l1, l2) {
      if (!(l1 instanceof google.maps.LatLng &&
            l2 instanceof google.maps.LatLng)) {
        return false;
      }
      return floatEqual(l1.lat(), l2.lat()) && floatEqual(l1.lng(), l2.lng());
    }

    /**
     * @param {google.maps.LatLng} latLng
     * @return {Object} object literal with 'lat' and 'lng' properties
     */
    function latLngToObj(latLng) {
      if (!(latLng instanceof google.maps.LatLng))
        throw 'latLng not a google.maps.LatLng';

      return {
        lat: latLng.lat(),
        lng: latLng.lng()
      };
    }

    /**
     * @param {google.maps.LatLng} latLng
     * @return true if either lat or lng of latLng is null or isNaN
     */
    function isLatLngNullOrNaN(latLng) {
      if (latLng == null) {
        return false;
      }
      var isNull = (latLng.lat() == null || latLng.lng() == null);
      var isNotaN =  isNaN(latLng.lat()) || isNaN(latLng.lng());
      return isNull || isNotaN;
    }

    return {
      getMapId: getMapId,
      latLngEqual: latLngEqual,
      latLngToObj: latLngToObj,
      isLatLngNullOrNaN: isLatLngNullOrNaN
    }
  }]);
})();
<commit_msg>Added object to google.maps converter functions and cleaned up rest.<commit_after>'use strict';

(function () {
  angular.module('google-maps').

  factory('googleMapsUtils', [function() {

    var counter = 0;
    function getCount() {
      return counter++;
    }

    /**
     * @param {Object} a jQuery/angular element
     * @return a unique id for the given element (as long as you don't use
     * integers for html id attributes)
     */
    function getMapId(elm) {
      var id = elm.attr('id') || elm.data('id');
      if (!id) {
        id = getCount();
        elm.data('id', id);
      }
      return id;
    }

    /**
     * Check if two floating point numbers are equal.
     * @return true if f1 and f2 are 'very close'
     */
    function floatEqual (f1, f2) {
      return (Math.abs(f1 - f2) < 0.000001);
    }

    /**
     * @param {google.maps.LatLng} l1
     * @param {google.maps.LatLng} l2
     * @return {boolean} true if l1 and l2 are 'very close'. If either are null
     * or not google.maps.LatLng objects returns false.
     */
    function latLngEqual(l1, l2) {
      if (!(l1 instanceof google.maps.LatLng &&
            l2 instanceof google.maps.LatLng)) {
        return false;
      }
      return floatEqual(l1.lat(), l2.lat()) && floatEqual(l1.lng(), l2.lng());
    }

    /**
     * @param {google.maps.LatLngBounds} b1
     * @param {google.maps.LatLngBounds} b2
     * @return {boolean} true if b1 and b2 are 'very close'. If either are null
     * or not google.maps.LatLngBounds objects returns false.
     */
    function boundsEqual(b1, b2) {
      if (!(b1 instanceof google.maps.LatLngBounds &&
            b2 instanceof google.maps.LatLngBounds)) {
        return false;
      }
      var sw1 = b1.getSouthWest();
      var sw2 = b2.getSouthWest();
      var ne1 = b1.getNorthEast();
      var ne2 = b2.getNorthEast();

      return latLngEqual(sw1, sw2) && latLngEqual(ne1 && ne2);
    }

    /**
     * @param {google.maps.LatLng} latLng
     * @return {Object} object literal with 'lat' and 'lng' properties.
     * @throw if latLng not instanceof google.maps.LatLng
     */
    function latLngToObj(latLng) {
      if (!(latLng instanceof google.maps.LatLng))
        throw 'latLng not a google.maps.LatLng';

      return {
        lat: latLng.lat(),
        lng: latLng.lng()
      };
    }

    /**
     * @param {Object} obj of the form { lat: 40, lng: -120 }
     * @return {google.maps.LatLng} returns null if problems with obj (null,
     * NaN, etc.)
     */
    function objToLatLng(obj) {
      if (obj != null) {
        var lat = obj.lat;
        var lng = obj.lng;
        var ok = !(lat == null || lng == null) && !(isNaN(lat) ||
            isNaN(lng));
        if (ok) {
          return new google.maps.LatLng(lat, lng);
        }
      }
      return null;
    }

    /**
     * @param {google.maps.LatLngBounds} bounds
     * @return {Object} object literal of the form {
     *    southWest: {lat: 40, lng: -120},
     *    northEast: {lat: 40, lng: -120}
     *  }
     * @throw if bounds not instanceof google.maps.LatLngBounds
     */
    function boundsToObj(bounds) {
      if (!(bounds instanceof google.maps.LatLngBounds)) {
        throw 'bounds not a google.maps.LatLngBounds';
      }
      var sw = bounds.getSouthWest();
      var ne = bounds.getNorthEast();
      return {
        southWest: {
          lat: sw.lat(),
          lng: sw.lng()
        },
        northEast: {
          lat: ne.lat(),
          lng: ne.lng()
        }
      };
    }

    /**
     * @param {Object} obj literal of the form {
     *    southWest: {lat: 40, lng: -120},
     *    northEast: {lat: 40, lng: -120}
     *  }
     * @return {google.maps.LatLngBounds} returns null if problems with obj
     * (null, NaN, etc.)
     */
    function objToBounds(obj) {
      if (obj != null && obj.southWest && obj.northEast) {
        var values = [obj.southWest.lat, obj.southWest.lng,
          obj.northEast.lat, obj.northEast.lng];
        var ok = true;
        angular.forEach(values, function(value, i) {
          if (value == null || isNaN(value))
            ok = false;
        });
        if (ok) {
          return new google.maps.LatLngBounds(
            new google.maps.LatLng(values[0], values[1]),
            new google.maps.LatLng(values[2], values[3]));
        }
      }
      return null;
    }

    /**
     * @param {google.maps.LatLng} latLng
     * @return true if either lat or lng of latLng is null or isNaN
     */
    function isLatLngNullOrNaN(latLng) {
      if (latLng == null) {
        return false;
      }
      var isNull = (latLng.lat() == null || latLng.lng() == null);
      var isNotaN =  isNaN(latLng.lat()) || isNaN(latLng.lng());
      return isNull || isNotaN;
    }

    return {
      getMapId: getMapId,
      latLngEqual: latLngEqual,
      boundsEqual: boundsEqual,
      latLngToObj: latLngToObj,
      objToLatLng: objToLatLng,
      boundsToObj: boundsToObj,
      objToBounds: objToBounds,
      isLatLngNullOrNaN: isLatLngNullOrNaN
    }
  }]);
})();
<|endoftext|>


<commit_before>var $pg =  $pg || {};

//it is necessary to determine which pole of the DNA...
//sequence is to the left and which is to the right...
//the default is 5'-DNAHERE-3'.
//if not oriented properly..
// primers won't function for PCR
/*" By convention, if the base sequence of a single strand of DNA is given,
 the left end of the this is 5' end, while the right end of the
  this is the 3' end."
AND
"All known DNA replication systems require a free 3' hydroxyl group
 before synthesis can be initiated"
*/

//returns the complement of the param 'this' as this is presented. i.e.
//  passed   = "ATTTTAGCGATCCC"
// f_seq is for "forward sequence"

$pg.genComplement = function(seq) {
  var complement = "";
  var decoder = {
    "T": "A",
    "A": "T",
    "C": "G",
    "G": "C"
  };
  for (var i = 0; i < seq.length; i++) {
    complement += decoder[seq[i]];
  }
  return complement;
};

//returns substring from beginning of seq (in 5'-to-3' format)
//Forward primer is oriented the same as original this.
//if param 'forward' is true(default), primer is generated directly from sequence
//if param 'forward' is false, primer is generated as a reverse primer
$pg.genPrimer = function(seq , primerStart, primerLength, isForward) {
  isForward = isForward ? true : false;
  if (isForward){
    return seq.substring(primerStart, primerStart + primerLength);
  }
  else {
    var primer = seq.substring(seq.length-primerStart, seq.length - (primerStart+primerLength))
    //gets substring from end of seq then returns complement in (3'-to-5' format)

    primer = $pg.genComplement(primer);
    //Reverse primer must be oriented 5'-to-3' prior to chemical evaluation
    return $pg.seqReverse(primer);
  }
};
//returnes the reverse of a sequence
//(turns 3'-to-5' around to show 5'-to-3')
// used to turn reverse
$pg.seqReverse = function(seq) {
  return seq.split("").reverse().join("");
};

//function to generate a pseudo random DNA primergen (non-degenerate bases)
$pg.genRandomSeq = function(seqLength) {
  var dnaBases = ["A", "T", "G", "C"];
  var ampSeqPlus = "";
  for (var i = 0; i < seqLength; i++) {
    ampSeqPlus = ampSeqPlus + dnaBases[Math.floor(Math.random() * dnaBases.length) ];
    }
  return ampSeqPlus;
};

$pg.Sequence = function(sequence, orientation, seqName) {
  this.sequence = sequence;
  this.seqLength = sequence.length;
  this.seqName = seqName;
  // orientation refers to the sequence being oriented in a 5'-to-3' fashion
  // by default, all functions should return 5'-to-3' sequences by default except,
  // of course, the seqReverse() function.
  this.orientation = orientation;

  //function that validates this integrity
  //only A,G,T, and C bases => true
  //bases other than A,G,T, or C => false
  this.seqIntegrityCheck = function () {
    var checker = 0;
    checker = this.sequence.search(/[~ATGC]/);
    if (checker === 0) {
      return true;
    }
    else
      {
        return false;
      }
  };
  this.integrity = this.seqIntegrityCheck();

  //counts bases... returns number of bases.
  this.baseCount = function(seq, nucleotide) {
    return seq.split(nucleotide).length - 1;
  };

  this.sumA = this.baseCount(this.sequence, "A");
  this.sumT = this.baseCount(this.sequence, "T");
  this.sumG = this.baseCount(this.sequence, "G");
  this.sumC = this.baseCount(this.sequence, "C");

  // finds GC content of this
  //should return a number between 0 and 1.
  // e.g. given "GGCC" => 1.0
        //given "GATC" => 0.5
        //given "CCCC" => 1.0
        //given "AATC" => 0.25
  this.calcGCContent = function(seq, sumG, sumC) {
    return (sumG + sumC) / seq.length;
      };
  this.gcContent = this.calcGCContent(this.sequence, this.sumG, this.sumC);
};

$pg.Chemistry = function() {
  //R is the ideal gas constant and is equal to 1.987 cal / (K * mole).
  //the difference between degrees Kelvin and Celsius is 273.15 degrees.
  //Calculate the melting temp of oligos (read: primers) in Celcius
  //References:
      //Sugimoto et al., (1996) Nucl. Acids Res. 24:4501-4505
      //Breslauer et al., (1986) Proc. Nat. Acad. Sci. 83:3746-50
      // In Sugimoto's "Improved thermodynamic parameters and helix initiation factor to predict stability of DNA duplexes"

  //values:
  //deltaG
  //deltaH
  //deltaS

// All experiments were conducted in a buffer including 1 M NaCl, 10 mM Na2HPO4 and 1 mM Na2EDTA (pH 7.0)
//  1 M NaCl buffer is concentrationNaCl so found meltingTemp data is for 1 M NaCl (monovalent)

//10 kinds of nearest-neighbor sequences of Watson–Crick base pairs described:
//dAA/dTT, dAT/dAT, dCG/dCG, dCT/dAG, dGA/dTC, dGC/dGC, dGG/dCC, dGT/dAC, dTA/dTA

// (deltaGof(37) = 3.4 kcal/mol) this means that measurements of deltaG were taken at 37 degrees Celsius
//  a free energy change at37degreesC (deltaG(37)) of the helix formation consist of three terms:
// (i) a free energy change for helix propagation as a sum of each subsequent base pair
// (ii) a free energy change for helix initiation
// (iii) a free energy change of an entropy effect when the duplex is composed of self-complementary strands

  this.calcMeltingTempCelsius = function() {
    var IDEALGASCONST = 1.987;
    var enthalpy;
    var concentration_Primers;
    var entropy;
    var meltingTemp = enthalpy / (entropy + IDEALGASCONST * log(concentration_Primers)) -273.15;
    return meltingTemp;
    };
  this.invMonovalentTemp = function() {

  };
  this.invDivalentTemp = function() {};
  this.calcWallaceTemp = function() {};
};

$pg.DataTables = function(){

//TABLE 1
/*dAA –8.0 –21.9 –1.2
dTT
dAT –5.6 –15.2 –0.9
dTA
dTA –6.6 –18.4 –0.9
dAT
dCA –8.2 –21.0 –1.7
dGT
dCT –6.6 –16.4 –1.5
dGA
dGA –8.8 –23.5 –1.5
dCT
dGT –9.4 –25.5 –1.5
dCA
dCG –11.8 –29.0 –2.8
dGC
dGC –10.5 –26.4 –2.3
dCG
dGG –10.9 –28.4 –2.1
dCC
initiation 0.6 –9.0 3.4
self-complementary 0.0 –1.4 0.4
non-self-complementary 0.0 0.0 0.*/
  this.TABLE1 =[
                  ['dAA', '-8.0',  '-21.9', '-1.2', 'dTT'],
                  ['dAT', '-5.6',  '-15.2', '-0.9', 'dTA'],
                  ['dTA', '-6.6',  '-18.4', '-0.9', 'dAT'],
                  ['dCA', '-8.2',  '-21.0', '-1.7', 'dGT'],
                  ['dCT', '-6.6',  '-16.4', '-1.5', 'dGA'],
                  ['dGA', '-8.8',  '-23.5', '-1.5', 'dCT'],
                  ['dGT', '-9.4', ' -25.5', '-1.5', 'dCA'],
                  ['dCG', '-11.8', '-29.0', '-2.8', 'dGC'],
                  ['dGC', '-10.5', '-26.4', '-2.3', 'dCG'],
                  ['dGG', '-10.9', '-28.4', '-2.1', 'dCC'],
                  ['initiation', '0.6', '-9.0', '3.4'],
                  ['self-complementary', '0.0' ,'1.4', '0.4'],
                  ['non-self-complementary', '0.0', '0.0', '0.0']];

  this.makeObjectFromTableOne = function(table) {
    var superObject = {};
    for (var i =0;i < table.length ; i++) {
      var masterkey = table[i][0] + (table[i][4]) ? (table[i][4]) : "";
      superObject[masterkey] = {
        deltaH: parseFloat(table[i][1]),
        deltaS: parseFloat(myTextArray[i][2]),
        deltaG: parseFloat(myTextArray[i][3]),
      };
    }
      return superObject;
  };
  this.nearestNeighborTable = makeObjectFromTableOne(this.TABLE1);
};

var seqs = {};
seqs.csaSeq = new $pg.Sequence($pg.genRandomSeq(64), true, 'CandidateSequence');
seqs.forwardPrimer = new $pg.Sequence($pg.genPrimer(seqs.csaSeq.sequence, 0, 21, true), true, 'forwardPrimer');
seqs.reversePrimer = new $pg.Sequence($pg.genPrimer(seqs.csaSeq.sequence, 0, 20, false), true, 'reversePrimer');

var doNothing;<commit_msg>fixed a few missing semicolons, and corrected makeTableOne() key name generation<commit_after>var $pg =  $pg || {};

//it is necessary to determine which pole of the DNA...
//sequence is to the left and which is to the right...
//the default is 5'-DNAHERE-3'.
//if not oriented properly..
// primers won't function for PCR
/*" By convention, if the base sequence of a single strand of DNA is given,
 the left end of the this is 5' end, while the right end of the
  this is the 3' end."
AND
"All known DNA replication systems require a free 3' hydroxyl group
 before synthesis can be initiated"
*/

//returns the complement of the param 'this' as this is presented. i.e.
//  passed   = "ATTTTAGCGATCCC"
// f_seq is for "forward sequence"

$pg.genComplement = function(seq) {
  var complement = "";
  var decoder = {
    "T": "A",
    "A": "T",
    "C": "G",
    "G": "C"
  };
  for (var i = 0; i < seq.length; i++) {
    complement += decoder[seq[i]];
  }
  return complement;
};

//returns substring from beginning of seq (in 5'-to-3' format)
//Forward primer is oriented the same as original this.
//if param 'forward' is true(default), primer is generated directly from sequence
//if param 'forward' is false, primer is generated as a reverse primer
$pg.genPrimer = function(seq , primerStart, primerLength, isForward) {
  isForward = isForward ? true : false;
  if (isForward){
    return seq.substring(primerStart, primerStart + primerLength);
  }
  else {
    var primer = seq.substring(seq.length-primerStart, seq.length - (primerStart+primerLength));
    //gets substring from end of seq then returns complement in (3'-to-5' format)

    primer = $pg.genComplement(primer);
    //Reverse primer must be oriented 5'-to-3' prior to chemical evaluation
    return $pg.seqReverse(primer);
  }
};
//returnes the reverse of a sequence
//(turns 3'-to-5' around to show 5'-to-3')
// used to turn reverse
$pg.seqReverse = function(seq) {
  return seq.split("").reverse().join("");
};

//function to generate a pseudo random DNA primergen (non-degenerate bases)
$pg.genRandomSeq = function(seqLength) {
  var dnaBases = ["A", "T", "G", "C"];
  var ampSeqPlus = "";
  for (var i = 0; i < seqLength; i++) {
    ampSeqPlus = ampSeqPlus + dnaBases[Math.floor(Math.random() * dnaBases.length) ];
    }
  return ampSeqPlus;
};

$pg.Sequence = function(sequence, orientation, seqName) {
  this.sequence = sequence;
  this.seqLength = sequence.length;
  this.seqName = seqName;
  // orientation refers to the sequence being oriented in a 5'-to-3' fashion
  // by default, all functions should return 5'-to-3' sequences by default except,
  // of course, the seqReverse() function.
  this.orientation = orientation;

  //function that validates this integrity
  //only A,G,T, and C bases => true
  //bases other than A,G,T, or C => false
  this.seqIntegrityCheck = function () {
    var checker = 0;
    checker = this.sequence.search(/[~ATGC]/);
    if (checker === 0) {
      return true;
    }
    else
      {
        return false;
      }
  };
  this.integrity = this.seqIntegrityCheck();

  //counts bases... returns number of bases.
  this.baseCount = function(seq, nucleotide) {
    return seq.split(nucleotide).length - 1;
  };

  this.sumA = this.baseCount(this.sequence, "A");
  this.sumT = this.baseCount(this.sequence, "T");
  this.sumG = this.baseCount(this.sequence, "G");
  this.sumC = this.baseCount(this.sequence, "C");

  // finds GC content of this
  //should return a number between 0 and 1.
  // e.g. given "GGCC" => 1.0
        //given "GATC" => 0.5
        //given "CCCC" => 1.0
        //given "AATC" => 0.25
  this.calcGCContent = function(seq, sumG, sumC) {
    return (sumG + sumC) / seq.length;
      };
  this.gcContent = this.calcGCContent(this.sequence, this.sumG, this.sumC);
};

$pg.Chemistry = function() {
  //R is the ideal gas constant and is equal to 1.987 cal / (K * mole).
  //the difference between degrees Kelvin and Celsius is 273.15 degrees.
  //Calculate the melting temp of oligos (read: primers) in Celcius
  //References:
      //Sugimoto et al., (1996) Nucl. Acids Res. 24:4501-4505
      //Breslauer et al., (1986) Proc. Nat. Acad. Sci. 83:3746-50
      // In Sugimoto's "Improved thermodynamic parameters and helix initiation factor to predict stability of DNA duplexes"

  //values:
  //deltaG
  //deltaH
  //deltaS

// All experiments were conducted in a buffer including 1 M NaCl, 10 mM Na2HPO4 and 1 mM Na2EDTA (pH 7.0)
//  1 M NaCl buffer is concentrationNaCl so found meltingTemp data is for 1 M NaCl (monovalent)

//10 kinds of nearest-neighbor sequences of Watson–Crick base pairs described:
//dAA/dTT, dAT/dAT, dCG/dCG, dCT/dAG, dGA/dTC, dGC/dGC, dGG/dCC, dGT/dAC, dTA/dTA

// (deltaGof(37) = 3.4 kcal/mol) this means that measurements of deltaG were taken at 37 degrees Celsius
//  a free energy change at37degreesC (deltaG(37)) of the helix formation consist of three terms:
// (i) a free energy change for helix propagation as a sum of each subsequent base pair
// (ii) a free energy change for helix initiation
// (iii) a free energy change of an entropy effect when the duplex is composed of self-complementary strands

  this.calcMeltingTempCelsius = function() {
    var IDEALGASCONST = 1.987;
    var enthalpy;
    var concentration_Primers;
    var entropy;
    var meltingTemp = enthalpy / (entropy + IDEALGASCONST * Math.log(concentration_Primers)) -273.15;
    return meltingTemp;
    };
  this.invMonovalentTemp = function() {

  };
  this.invDivalentTemp = function() {};
  this.calcWallaceTemp = function() {};
};

$pg.dataTables = {};

//TABLE 1
/*dAA –8.0 –21.9 –1.2
dTT
dAT –5.6 –15.2 –0.9
dTA
dTA –6.6 –18.4 –0.9
dAT
dCA –8.2 –21.0 –1.7
dGT
dCT –6.6 –16.4 –1.5
dGA
dGA –8.8 –23.5 –1.5
dCT
dGT –9.4 –25.5 –1.5
dCA
dCG –11.8 –29.0 –2.8
dGC
dGC –10.5 –26.4 –2.3
dCG
dGG –10.9 –28.4 –2.1
dCC
initiation 0.6 –9.0 3.4
self-complementary 0.0 –1.4 0.4
non-self-complementary 0.0 0.0 0.*/
$pg.dataTables.TABLE1 =[
                  ['dAA', '-8.0',  '-21.9', '-1.2', 'dTT'],
                  ['dAT', '-5.6',  '-15.2', '-0.9', 'dTA'],
                  ['dTA', '-6.6',  '-18.4', '-0.9', 'dAT'],
                  ['dCA', '-8.2',  '-21.0', '-1.7', 'dGT'],
                  ['dCT', '-6.6',  '-16.4', '-1.5', 'dGA'],
                  ['dGA', '-8.8',  '-23.5', '-1.5', 'dCT'],
                  ['dGT', '-9.4', ' -25.5', '-1.5', 'dCA'],
                  ['dCG', '-11.8', '-29.0', '-2.8', 'dGC'],
                  ['dGC', '-10.5', '-26.4', '-2.3', 'dCG'],
                  ['dGG', '-10.9', '-28.4', '-2.1', 'dCC'],
                  ['initiation', '0.6', '-9.0', '3.4'],
                  ['self-complementary', '0.0' ,'1.4', '0.4'],
                  ['non-self-complementary', '0.0', '0.0', '0.0']];

$pg.makeTableOne = function(table) {
    var superObject = {};
    for (var i =0;i < table.length ; i++) {
      var masterkey = table[i][0] + (table[i][4] || "");
      superObject[masterkey] = {
        deltaH: parseFloat(table[i][1]),
        deltaS: parseFloat(table[i][2]),
        deltaG: parseFloat(table[i][3]),
      };
    }
      return superObject;
  };
$pg.dataTables.nearestNeighborTable = $pg.makeTableOne($pg.dataTables.TABLE1);

var seqs = {};
seqs.csaSeq = new $pg.Sequence($pg.genRandomSeq(64), true, 'CandidateSequence');
seqs.forwardPrimer = new $pg.Sequence($pg.genPrimer(seqs.csaSeq.sequence, 0, 21, true), true, 'forwardPrimer');
seqs.reversePrimer = new $pg.Sequence($pg.genPrimer(seqs.csaSeq.sequence, 0, 20, false), true, 'reversePrimer');
<|endoftext|>


<commit_before>import {CrudItem} from 'widget/crudItem'
import {Layout} from 'widget/layout'
import {ListItem} from 'widget/listItem'
import {Panel} from 'widget/panel/panel'
import {activatable} from 'widget/activation/activatable'
import {activator} from 'widget/activation/activator'
import {compose} from 'compose'
import {msg} from 'translate'
import React from 'react'
import styles from './addImageLayerSource.module.css'

export class AddImageLayerSource extends React.Component {
    render() {
        return (
            <React.Fragment>
                <AddImageLayerSourcePanel/>
            </React.Fragment>
        )
    }
}

class _AddImageLayerSourcePanel extends React.Component {
    render() {
        const {activatable: {deactivate}} = this.props
        return (
            <Panel type='modal' className={styles.panel}>
                <Panel.Header title={msg('map.layout.addImageLayerSource.title')}/>
                <Panel.Content>
                    {this.renderOptions()}
                </Panel.Content>
                <Panel.Buttons>
                    <Panel.Buttons.Main>
                        <Panel.Buttons.Close
                            keybinding='Escape'
                            onClick={deactivate}
                        />
                    </Panel.Buttons.Main>
                </Panel.Buttons>
            </Panel>
        )
    }

    renderOptions() {
        return (
            <Layout type='vertical' spacing='tight'>
                {this.renderRecipeButton()}
                {this.renderAssetButton()}
                {this.renderPlanetButton()}
            </Layout>
        )
    }

    renderRecipeButton() {
        return (
            <ListItem onClick={() => this.selectRecipe()}>
                <CrudItem
                    title={msg('imageLayerSources.Recipe.label')}
                    description={msg('map.layout.addImageLayerSource.types.Recipe.description')}
                />
            </ListItem>
        )
    }

    renderAssetButton() {
        return (
            <ListItem onClick={() => this.selectAsset()}>
                <CrudItem
                    title={msg('imageLayerSources.Asset.label')}
                    description={msg('map.layout.addImageLayerSource.types.Asset.description')}
                />
            </ListItem>
        )
    }

    renderPlanetButton() {
        return (
            <ListItem onClick={() => this.selectPlanet()}>
                <CrudItem
                    title={msg('imageLayerSources.Planet.label')}
                    description={msg('map.layout.addImageLayerSource.types.Planet.description')}
                />
            </ListItem>
        )
    }

    selectRecipe() {
        const {activator: {activatables: {selectRecipe}}} = this.props
        selectRecipe.activate()
    }

    selectAsset() {
        const {activator: {activatables: {selectAsset}}} = this.props
        selectAsset.activate()
    }

    selectPlanet() {
        const {activator: {activatables: {selectPlanet}}} = this.props
        selectPlanet.activate()
    }
}

const policy = () => ({
    _: 'allow',
    selectRecipe: 'allow-then-deactivate',
    selectAsset: 'allow-then-deactivate',
    selectPlanet: 'allow-then-deactivate'
})

const AddImageLayerSourcePanel = compose(
    _AddImageLayerSourcePanel,
    activatable({id: 'addImageLayerSource', policy, alwaysAllow: true}),
    activator('mapLayout', 'selectRecipe', 'selectAsset', 'selectPlanet')
)
<commit_msg>Cleanup.<commit_after>import {CrudItem} from 'widget/crudItem'
import {Layout} from 'widget/layout'
import {ListItem} from 'widget/listItem'
import {Panel} from 'widget/panel/panel'
import {activatable} from 'widget/activation/activatable'
import {activator} from 'widget/activation/activator'
import {compose} from 'compose'
import {msg} from 'translate'
import React from 'react'
import styles from './addImageLayerSource.module.css'

export class AddImageLayerSource extends React.Component {
    render() {
        return (
            <React.Fragment>
                <AddImageLayerSourcePanel/>
            </React.Fragment>
        )
    }
}

class _AddImageLayerSourcePanel extends React.Component {
    constructor(props) {
        super(props)
        this.selectRecipe = this.selectRecipe.bind(this)
        this.selectAsset = this.selectAsset.bind(this)
        this.selectPlanet = this.selectPlanet.bind(this)
    }

    render() {
        const {activatable: {deactivate}} = this.props
        return (
            <Panel type='modal' className={styles.panel}>
                <Panel.Header title={msg('map.layout.addImageLayerSource.title')}/>
                <Panel.Content>
                    {this.renderOptions()}
                </Panel.Content>
                <Panel.Buttons>
                    <Panel.Buttons.Main>
                        <Panel.Buttons.Close
                            keybinding='Escape'
                            onClick={deactivate}
                        />
                    </Panel.Buttons.Main>
                </Panel.Buttons>
            </Panel>
        )
    }

    renderOptions() {
        return (
            <Layout type='vertical' spacing='tight'>
                {this.renderRecipeButton()}
                {this.renderAssetButton()}
                {this.renderPlanetButton()}
            </Layout>
        )
    }

    renderRecipeButton() {
        return (
            <ListItem onClick={this.selectRecipe}>
                <CrudItem
                    title={msg('imageLayerSources.Recipe.label')}
                    description={msg('map.layout.addImageLayerSource.types.Recipe.description')}
                />
            </ListItem>
        )
    }

    renderAssetButton() {
        return (
            <ListItem onClick={this.selectAsset}>
                <CrudItem
                    title={msg('imageLayerSources.Asset.label')}
                    description={msg('map.layout.addImageLayerSource.types.Asset.description')}
                />
            </ListItem>
        )
    }

    renderPlanetButton() {
        return (
            <ListItem onClick={this.selectPlanet}>
                <CrudItem
                    title={msg('imageLayerSources.Planet.label')}
                    description={msg('map.layout.addImageLayerSource.types.Planet.description')}
                />
            </ListItem>
        )
    }

    selectRecipe() {
        const {activator: {activatables: {selectRecipe}}} = this.props
        selectRecipe.activate()
    }

    selectAsset() {
        const {activator: {activatables: {selectAsset}}} = this.props
        selectAsset.activate()
    }

    selectPlanet() {
        const {activator: {activatables: {selectPlanet}}} = this.props
        selectPlanet.activate()
    }
}

const policy = () => ({
    _: 'allow',
    selectRecipe: 'allow-then-deactivate',
    selectAsset: 'allow-then-deactivate',
    selectPlanet: 'allow-then-deactivate'
})

const AddImageLayerSourcePanel = compose(
    _AddImageLayerSourcePanel,
    activatable({id: 'addImageLayerSource', policy, alwaysAllow: true}),
    activator('mapLayout', 'selectRecipe', 'selectAsset', 'selectPlanet')
)
<|endoftext|>


<commit_before>define([
  'intern!object',
  'intern/chai!assert',
  'oe_dojo/ErrorUtils'
], function (
  registerSuite,
  assert,
  ErrorUtils
) {

  registerSuite({
    name: 'ErrorUtils',

    'parseError msg and title error': function() {
      var errorMsgTitle = {title: 'Incorrecte Token', message: 'Het aangeboden SSO token is niet geldig'};
      // msg and title error
      assert.deepEqual(ErrorUtils.parseError(errorMsgTitle), errorMsgTitle,
        'parseError should return the given error with message and title');
    },

    'parseError unformatted error': function() {
      var errorNoFormat = 'Het aangeboden SSO token is ongeldig';
      // unformatted error (string)
      assert.deepEqual(ErrorUtils.parseError(errorNoFormat),
        {message: 'Het aangeboden SSO token is ongeldig', title: 'Er is een fout opgetreden'},
        'parseError should return the given unformatted error as message of the returned error object');
    },

    'parseError formatted error': function() {
      var errorFormatted = {
        response: {
          text: '{"message": "Het aangeboden SSO token is incorrect", "errors": ["error 1", "error 2"]}'
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorFormatted),
        {title: 'Het aangeboden SSO token is incorrect', message: '-error 1
-error 2
'},
        'parseError should return the parsed and formatted error');
    },

    'parseError formatted error without message': function() {
      var errorFormatted = {
        response: {
          text: '{"errors": ["error 1", "error 2"]}'
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorFormatted),
        {title: 'Er is een fout opgetreden', message: '-error 1
-error 2
'},
        'parseError should return the parsed and formatted error with the default title');
    },

    'parseError formatted error with empty errors array': function() {
      var errorFormatted = {
        response: {
          text: '{"message": "Het aangeboden SSO token is incorrect", "errors": []}'
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorFormatted),
        {title: 'Er is een fout opgetreden', message: 'Het aangeboden SSO token is incorrect'},
        'parseError should return an error with the default title and the error message');
    },

    'error during json parsing': function() {
      var errorHtml = {
        response: {
          text: ''
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorHtml),
        {title: 'Er is een fout opgetreden', message: 'Het formaat van de foutmelding is onleesbaar'},
        'parseError should return a default error telling the error format is incorrect');
    },

  });
});<commit_msg>remove trailing comma<commit_after>define([
  'intern!object',
  'intern/chai!assert',
  'oe_dojo/ErrorUtils'
], function (
  registerSuite,
  assert,
  ErrorUtils
) {

  registerSuite({
    name: 'ErrorUtils',

    'parseError msg and title error': function() {
      var errorMsgTitle = {title: 'Incorrecte Token', message: 'Het aangeboden SSO token is niet geldig'};
      // msg and title error
      assert.deepEqual(ErrorUtils.parseError(errorMsgTitle), errorMsgTitle,
        'parseError should return the given error with message and title');
    },

    'parseError unformatted error': function() {
      var errorNoFormat = 'Het aangeboden SSO token is ongeldig';
      // unformatted error (string)
      assert.deepEqual(ErrorUtils.parseError(errorNoFormat),
        {message: 'Het aangeboden SSO token is ongeldig', title: 'Er is een fout opgetreden'},
        'parseError should return the given unformatted error as message of the returned error object');
    },

    'parseError formatted error': function() {
      var errorFormatted = {
        response: {
          text: '{"message": "Het aangeboden SSO token is incorrect", "errors": ["error 1", "error 2"]}'
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorFormatted),
        {title: 'Het aangeboden SSO token is incorrect', message: '-error 1
-error 2
'},
        'parseError should return the parsed and formatted error');
    },

    'parseError formatted error without message': function() {
      var errorFormatted = {
        response: {
          text: '{"errors": ["error 1", "error 2"]}'
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorFormatted),
        {title: 'Er is een fout opgetreden', message: '-error 1
-error 2
'},
        'parseError should return the parsed and formatted error with the default title');
    },

    'parseError formatted error with empty errors array': function() {
      var errorFormatted = {
        response: {
          text: '{"message": "Het aangeboden SSO token is incorrect", "errors": []}'
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorFormatted),
        {title: 'Er is een fout opgetreden', message: 'Het aangeboden SSO token is incorrect'},
        'parseError should return an error with the default title and the error message');
    },

    'error during json parsing': function() {
      var errorHtml = {
        response: {
          text: ''
        }
      };
      assert.deepEqual(ErrorUtils.parseError(errorHtml),
        {title: 'Er is een fout opgetreden', message: 'Het formaat van de foutmelding is onleesbaar'},
        'parseError should return a default error telling the error format is incorrect');
    }

  });
});<|endoftext|>


<commit_before>import { Strategy } from 'passport-google-oauth20'

// ===================================================================

export const configurationSchema = {
  type: 'object',
  properties: {
    callbackURL: {
      type: 'string',
      description: 'Must be exactly the same as specified on the Google developer console.'
    },
    clientID: {
      type: 'string'
    },
    clientSecret: {
      type: 'string'
    },
    scope: {
      default: 'https://www.googleapis.com/auth/plus.login',
      description: 'Note that changing this value will break existing users.',
      enum: [ 'https://www.googleapis.com/auth/plus.login', 'email' ],
      enumNames: [ 'Google+ name', 'Simple email address' ]
    }
  },
  required: ['callbackURL', 'clientID', 'clientSecret']
}

// ===================================================================

class AuthGoogleXoPlugin {
  constructor ({ xo }) {
    this._conf = null
    this._xo = xo
  }

  configure (conf) {
    this._conf = conf
  }

  load () {
    const conf = this._conf
    const xo = this._xo

    xo.registerPassportStrategy(new Strategy(conf, async (accessToken, refreshToken, profile, done) => {
      try {
        done(null, await xo.registerUser(
          'google',
          conf.scope === 'email'
            ? profile.emails[0].value
            : profile.displayName
        ))
      } catch (error) {
        done(error.message)
      }
    }))
  }
}

// ===================================================================

export default opts => new AuthGoogleXoPlugin(opts)
<commit_msg>fix: ensure a scope is used<commit_after>import { Strategy } from 'passport-google-oauth20'

// ===================================================================

export const configurationSchema = {
  type: 'object',
  properties: {
    callbackURL: {
      type: 'string',
      description: 'Must be exactly the same as specified on the Google developer console.'
    },
    clientID: {
      type: 'string'
    },
    clientSecret: {
      type: 'string'
    },
    scope: {
      default: 'https://www.googleapis.com/auth/plus.login',
      description: 'Note that changing this value will break existing users.',
      enum: [ 'https://www.googleapis.com/auth/plus.login', 'email' ],
      enumNames: [ 'Google+ name', 'Simple email address' ]
    }
  },
  required: ['callbackURL', 'clientID', 'clientSecret']
}

// ===================================================================

class AuthGoogleXoPlugin {
  constructor ({ xo }) {
    this._conf = null
    this._xo = xo
  }

  configure (conf) {
    this._conf = conf
  }

  load () {
    const conf = {
      // TODO: find a better way to inject default values
      scope: configurationSchema.properties.scope.default,
      ...this._conf
    }
    const xo = this._xo

    xo.registerPassportStrategy(new Strategy(conf, async (accessToken, refreshToken, profile, done) => {
      try {
        done(null, await xo.registerUser(
          'google',
          conf.scope === 'email'
            ? profile.emails[0].value
            : profile.displayName
        ))
      } catch (error) {
        done(error.message)
      }
    }))
  }
}

// ===================================================================

export default opts => new AuthGoogleXoPlugin(opts)
<|endoftext|>


<commit_before>const chalk = require('chalk')
const chromahash = require('./')

const words =
  'hello there how are you doing today and what other ' +
  'wonderful things can we accomplish today ' +
  'we seem to not be able to generate different enough colors'

words.split(' ').forEach(w => {
  const hex = '#' + chromahash(w)
  console.log(hex, chalk.bgHex(hex)(w))
})
<commit_msg>use random english words for example<commit_after>const words = require('an-array-of-english-words')
const chalk = require('chalk')
const chromahash = require('./')

Array(20)
  .fill()
  .forEach(() => {
    const rand = Math.floor(Math.random() * 250000)
    const word = words[rand]
    const hex = '#' + chromahash(word)
    console.log(hex, chalk.bgHex(hex)(word))
  })
<|endoftext|>


<commit_before>var check_for_call = function() {
    var url = "../check_call_received/";
    $.post(url,
        {
            number: $("#number").val()
        },
        function(json) {

            if(json && json.status) {
                var statusText = $("#auth_status");

                switch(json.status) {
                    case "waiting":
                        statusText.text("Waiting for your call");
                        window.setTimeout("check_for_call()",1000);
                    break;

                    case "received":
                        statusText.text("Thank you! Your telephone number has been authenticated.");
                        $("#next").show();
                        $("#auth_spinner").hide();
                    break;

                    case "failed":
                        statusText.text("Sorry, the authentication of your telephone number failed. Please try again.");
                        $("#next").hide();
                        $("#auth_spinner").hide();

                    break;
                }
            }
        },
        "json");
};
$(#next).hide();
$(document).ready(check_for_call);

<commit_msg>yet another bug removed<commit_after>var check_for_call = function() {
    var url = "../check_call_received/";
    $.post(url,
        {
            number: $("#number").val()
        },
        function(json) {

            if(json && json.status) {
                var statusText = $("#auth_status");

                switch(json.status) {
                    case "waiting":
                        statusText.text("Waiting for your call");
                        window.setTimeout("check_for_call()",1000);
                    break;

                    case "received":
                        statusText.text("Thank you! Your telephone number has been authenticated.");
                        $("#next").show();
                        $("#auth_spinner").hide();
                    break;

                    case "failed":
                        statusText.text("Sorry, the authentication of your telephone number failed. Please try again.");
                        $("#next").hide();
                        $("#auth_spinner").hide();

                    break;
                }
            }
        },
        "json");
};
$("#next").hide();
$(document).ready(check_for_call);

<|endoftext|>


<commit_before>import React from 'react';
import { interpolate } from 'd3-interpolate';
import * as Easing from 'd3-ease';

class Motion extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.move = this.move.bind(this);
        this.state = {items: []};
    }
    componentWillReceiveProps() {
        // cancelAnimationFrame(this.moveId);
        this.moveId = requestAnimationFrame(this.move);
    }
    componentDidMount() {
        this.moveId = requestAnimationFrame(this.move)
    }
    componentWillUnmount() {
        cancelAnimationFrame(this.moveId);
    }
    move() {
        this.setState(({items: prevItems}) => {
            var {data, enter, leave, update, getKey, onRest} = this.props;
            var dataByKey = data.reduce((acc, item) => ({...acc, [getKey(item)]: item}), {});
            var itemsByKey = prevItems.reduce((acc, item) => ({...acc, [item.key]: item}), {});
            var tick = performance.now();
            var items = prevItems
                .map(item => {
                    var end = !dataByKey[item.key] ? leave(item.data) : update(dataByKey[item.key]);
                    var equal = this.areEqual(item.end, end);
                    var rest = equal && item.progress === 1;
                    var progress = equal ? Math.min(item.progress + ((tick - item.tick) / 500), 1) : 0;
                    var interpolators = equal ? item.interpolators : this.getInterpolators(item.style, end);
                    var style = this.interpolateStyle(interpolators, end, progress);
                    if (rest && !item.rest) {
                        onRest(item.data, item.key);
                    }
                    return {key: item.key, data: item.data, style, end, interpolators, progress, tick, rest};
                })
                .filter(item => !item.rest || dataByKey[item.key])
                .concat(data
                    .filter(item => !itemsByKey[getKey(item)])
                    .map(item => {
                        var style = enter(item);
                        var end = update(item);
                        var interpolators = this.getInterpolators(style, end);
                        return {key: getKey(item), data: item, style, end, interpolators, progress: 0, tick, rest: false};
                    })
                );
            if (items.filter(({rest}) => !rest).length !== 0)
                this.moveId = requestAnimationFrame(this.move);
            return {items};
        })
    }
    areEqual(from, to) {
        if (Object.keys(from).length !== Object.keys(to).length)
            return false;
        for(var key in from) {
            if (from[key] !== to[key])
                return false;
        }
        return true;
    }
    getInterpolators(start, end) {
        var interpolators = {};
        for(var key in start)
            interpolators[key] = interpolate(start[key], end[key]);
        return interpolators;
    }
    interpolateStyle(interpolators, end, progress) {
        var style = {};
        for(var key in end)
            style[key] = interpolators[key](Easing.easeLinear(progress))
        return style;
    }
    render() {
        return this.props.children(this.state.items);
    }
}

export default Motion;
<commit_msg>Requested at most one animation frame<commit_after>import React from 'react';
import { interpolate } from 'd3-interpolate';
import * as Easing from 'd3-ease';

class Motion extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.move = this.move.bind(this);
        this.state = {items: []};
    }
    componentWillReceiveProps() {
        if (!this.moveId)
            this.moveId = requestAnimationFrame(this.move);
    }
    componentDidMount() {
        this.moveId = requestAnimationFrame(this.move)
    }
    componentWillUnmount() {
        cancelAnimationFrame(this.moveId);
    }
    move() {
        this.setState(({items: prevItems}) => {
            var {data, enter, leave, update, getKey, onRest} = this.props;
            var dataByKey = data.reduce((acc, item) => ({...acc, [getKey(item)]: item}), {});
            var itemsByKey = prevItems.reduce((acc, item) => ({...acc, [item.key]: item}), {});
            var tick = performance.now();
            var items = prevItems
                .map(item => {
                    var end = !dataByKey[item.key] ? leave(item.data) : update(dataByKey[item.key]);
                    var equal = this.areEqual(item.end, end);
                    var rest = equal && item.progress === 1;
                    var progress = equal ? Math.min(item.progress + ((tick - item.tick) / 500), 1) : 0;
                    var interpolators = equal ? item.interpolators : this.getInterpolators(item.style, end);
                    var style = this.interpolateStyle(interpolators, end, progress);
                    if (rest && !item.rest) {
                        onRest(item.data, item.key);
                    }
                    return {key: item.key, data: item.data, style, end, interpolators, progress, tick, rest};
                })
                .filter(item => !item.rest || dataByKey[item.key])
                .concat(data
                    .filter(item => !itemsByKey[getKey(item)])
                    .map(item => {
                        var style = enter(item);
                        var end = update(item);
                        var interpolators = this.getInterpolators(style, end);
                        return {key: getKey(item), data: item, style, end, interpolators, progress: 0, tick, rest: false};
                    })
                );
            this.moveId = null;
            if (items.filter(({rest}) => !rest).length !== 0)
                this.moveId = requestAnimationFrame(this.move);
            return {items};
        })
    }
    areEqual(from, to) {
        if (Object.keys(from).length !== Object.keys(to).length)
            return false;
        for(var key in from) {
            if (from[key] !== to[key])
                return false;
        }
        return true;
    }
    getInterpolators(start, end) {
        var interpolators = {};
        for(var key in start)
            interpolators[key] = interpolate(start[key], end[key]);
        return interpolators;
    }
    interpolateStyle(interpolators, end, progress) {
        var style = {};
        for(var key in end)
            style[key] = interpolators[key](Easing.easeLinear(progress))
        return style;
    }
    render() {
        return this.props.children(this.state.items);
    }
}

export default Motion;
<|endoftext|>


<commit_before>/**
 * Data set explorer, based on jsPlumb
 */
var DATASET_EXPLORER = function() {

//    var dynamicAnchors = [
//                          [0, 0.2, -1, 0], [0, 0.5, -1, 0], [0, 0.8, -1, 0], // left
//                          [0.2, 1, 0, 1],  [0.5, 1, 0, 1],  [0.8, 1, 0, 1],  // top
//                          [1, 0.2, 1, 0],  [1, 0.5, 1, 0],  [1, 0.8, 1, 0],  // right
//                          [0.2, 0, 0, -1], [0.5, 0, 0, -1], [0.8, 0, 0, -1]  // bottom
//                          ];

    // Structure is {nodeid: {element:jqueryelt, visible:boolean}}
    var nodeState = {};

    // Structure is {srcid : {destid: {names:[name1,...], visible:boolean}}}
    var linkState = {};
    var invLinkState = {};

    jsPlumb.importDefaults({
        PaintStyle : {
            lineWidth:2,
            strokeStyle: '#456'
        },
        ConnectionsDetachable : false,
        Connector : [ "Bezier",  { curviness: 40 } ],
        Endpoints : [["Dot", {radius:2}], "Blank"],
        ConnectionOverlays : [ [ "Arrow", { location:1, id:"arrow", length:9, width:8  } ] ],
        Anchor : "Continuous"
    });

    var linksFor = function(src) {
        var dests = linkState[src];
        if (dests === undefined) {
            dests = {};
            linkState[src] = dests;
        }
        return dests;
    };

    var invLinksFor = function(src) {
        var dests = invLinkState[src];
        if (dests === undefined) {
            dests = {};
            invLinkState[src] = dests;
        }
        return dests;
    };

    var register = function(src, dest, name) {
        var links = linksFor(src);
        var l = links[dest];
        if (l === undefined) {
            l = {names:[name], visible:false};
            links[dest] = l;
        } else if ($.inArray(name, l.names) === -1) {
            l.names.push( name );
        }
        invLinksFor(dest)[src] = l;
    };

    var findNode = function(id) {
        return $(".node[data-id='" + id + "']");
    };

    var registerNode = function(nodeid, label) {
        nodeState[nodeid] = {element: findNode(nodeid), visible: true, label: label};
    };

    var hideNode = function(nodeid) {
        var state = nodeState[nodeid];
        state.element.hide();
        state.visible = false;
    };

    var showNode = function(nodeid) {
        var state = nodeState[nodeid];
        state.element.show();
        state.visible = true;
    };

    var nodeFor = function(id) {
        var state = nodeState[id];
        if (state === undefined) {
            return undefined;
        } else {
            return state.element;
        }
    };

    var randomPlacement = function(current, toplace) {
        var angle = Math.random() * 2 * Math.PI;
        var yoffset = 180 * Math.sin(angle);
        var xoffset = 180 * Math.cos(angle);
        var position = nodeFor(current).offset();
        position.left = position.left + xoffset;
        position.top = position.top + yoffset;
        nodeFor(toplace).offset(position);
    };

    var addConnection = function(src, target) {
        var link = linksFor(src)[target];
        if (link !== undefined && !link.visible) {
            var linkName = link.names.join();
            jsPlumb.connect({
                source: nodeFor( src ),
                target: nodeFor( target ),
                overlays: [ ["Label", {label:linkName, location:0.7, id:"label", cssClass:"link-label"}] ]
            });
            link.visible = true;
        }
    };

    var addConnections = function(src, target) {
        addConnection(src, target);
        addConnection(target, src);
    };

    var addDirectionalConnections = function(outbound, src, target) {
        if (outbound) {
            addConnection(src, target);
        } else {
            addConnection(target, src);
        }
    };

    var removeConnections = function(src) {
        jsPlumb.detachAllConnections( nodeFor(src) );
        $.each(linksFor(src), function(target, state){ state.visible = false;  });
        $.each(invLinksFor(src), function(target, state){ state.visible = false;  });
    };

    var addNodeFn = function(outbound) {
        return function(event) {
            var node = $(event.currentTarget).attr('data-node');
            var links = outbound ? linksFor(node) : invLinksFor(node);
            $.each(links, function(linkedDS, state){
                var targetNode = nodeFor(linkedDS);
                if (targetNode === undefined) {
                    $.get('/ui/dataset-browse-element?uri=' + linkedDS, function(data){
                        $("#canvas").append(data);
                        initElement();
                        randomPlacement(node, linkedDS);
//                        addConnections(node, linkedDS);
                        addDirectionalConnections(outbound, node, linkedDS);
                    });
                } else {
                    showNode(linkedDS);
//                    addConnections( node, linkedDS);
                    addDirectionalConnections(outbound, node, linkedDS);
                }
            });
            return false;
        };
    };

    var initElement = function() {
        $(".popinfo").popover();

        jsPlumb.draggable($(".node"));

        $(".add-out").unbind().click( addNodeFn(true) );
        $(".add-in").unbind().click( addNodeFn(false) );

        $(".close-node").unbind().click(function(event){
            var nodeURI = $(event.currentTarget).attr('data-node');
            removeConnections( nodeURI );
            hideNode(nodeURI);
            return false;
        });
    };

    var scaling = 4;   // Scaling springy coordinates to screen coordinates, no longer used
    var maxIter = 100; // Force termination after this many iterations
    var iterStep = 2;  // 1 + number of iteration steps to skip animating

    var relayout = function() {
        // Set up springy clone of graph
        var graph = new Springy.Graph();
        $.each(nodeState, function(nodeID, state){
            if (state.visible) {
                state.springyNode = graph.newNode(state);
            }
        });
        $.each(linkState, function(src, links){
            $.each(links, function(target, state){
                if (state.visible) {
                    graph.newEdge( nodeState[src].springyNode, nodeState[target].springyNode );
                }
            });
        });

        var width = $("#canvas").width();
        var height = $("#canvas").height();

        var layout = new Springy.Layout.ForceDirected(
                graph,
                400.0, // Spring stiffness
                400.0, // Node repulsion
                0.25  // Damping
              );

        // calculate bounding box of graph layout.. with ease-in
        var currentBB = layout.getBoundingBox();
        var targetBB = {bottomleft: new Springy.Vector(-2, -2), topright: new Springy.Vector(2, 2)};

        // auto adjusting bounding box
        Springy.requestAnimationFrame(function adjust() {
            targetBB = layout.getBoundingBox();
            // current gets 20% closer to target every iteration
            currentBB = {
                bottomleft: currentBB.bottomleft.add( targetBB.bottomleft.subtract(currentBB.bottomleft)
                    .divide(10)),
                topright: currentBB.topright.add( targetBB.topright.subtract(currentBB.topright)
                    .divide(10))
            };

            Springy.requestAnimationFrame(adjust);
        });

        // convert to/from screen coordinates
        var toScreen = function(p) {
            var size = currentBB.topright.subtract(currentBB.bottomleft);
            var sx = p.subtract(currentBB.bottomleft).divide(size.x).x * width;
            var sy = p.subtract(currentBB.bottomleft).divide(size.y).y * height;
            return {left: sx, top: sy};
        };

        var fromScreen = function(s) {
            var size = currentBB.topright.subtract(currentBB.bottomleft);
            var px = (s.x / width) * size.x + currentBB.bottomleft.x;
            var py = (s.y / height) * size.y + currentBB.bottomleft.y;
            return new Springy.Vector(px, py);
        };

        var iter = 0;

        var renderer = new Springy.Renderer(
                layout,
                function clear() {
                    iter += 1;
                    if (iter > maxIter) {
                        renderer.stop();
                    }
                },
                function drawEdge(edge, p1, p2) { },
                function drawNode(node, p) {
                    if (iter % iterStep === 0) {
                        node.data.element.offset( toScreen(p) );
                        jsPlumb.repaint(node.data.element);
                    }
                }
              );
        renderer.start();
    };

    // Return the public variables/functions for this module
    return {
        register : register,
        registerNode : registerNode,
        initElement : initElement,
        relayout : relayout
    };

}(); // "revealing module" pattern

jsPlumb.bind("ready", function() {
    DATASET_EXPLORER.initElement();
    $("#relayout").click( DATASET_EXPLORER.relayout );
});

<commit_msg>Increase layout timeout<commit_after>/**
 * Data set explorer, based on jsPlumb
 */
var DATASET_EXPLORER = function() {

//    var dynamicAnchors = [
//                          [0, 0.2, -1, 0], [0, 0.5, -1, 0], [0, 0.8, -1, 0], // left
//                          [0.2, 1, 0, 1],  [0.5, 1, 0, 1],  [0.8, 1, 0, 1],  // top
//                          [1, 0.2, 1, 0],  [1, 0.5, 1, 0],  [1, 0.8, 1, 0],  // right
//                          [0.2, 0, 0, -1], [0.5, 0, 0, -1], [0.8, 0, 0, -1]  // bottom
//                          ];

    // Structure is {nodeid: {element:jqueryelt, visible:boolean}}
    var nodeState = {};

    // Structure is {srcid : {destid: {names:[name1,...], visible:boolean}}}
    var linkState = {};
    var invLinkState = {};

    jsPlumb.importDefaults({
        PaintStyle : {
            lineWidth:2,
            strokeStyle: '#456'
        },
        ConnectionsDetachable : false,
        Connector : [ "Bezier",  { curviness: 40 } ],
        Endpoints : [["Dot", {radius:2}], "Blank"],
        ConnectionOverlays : [ [ "Arrow", { location:1, id:"arrow", length:9, width:8  } ] ],
        Anchor : "Continuous"
    });

    var linksFor = function(src) {
        var dests = linkState[src];
        if (dests === undefined) {
            dests = {};
            linkState[src] = dests;
        }
        return dests;
    };

    var invLinksFor = function(src) {
        var dests = invLinkState[src];
        if (dests === undefined) {
            dests = {};
            invLinkState[src] = dests;
        }
        return dests;
    };

    var register = function(src, dest, name) {
        var links = linksFor(src);
        var l = links[dest];
        if (l === undefined) {
            l = {names:[name], visible:false};
            links[dest] = l;
        } else if ($.inArray(name, l.names) === -1) {
            l.names.push( name );
        }
        invLinksFor(dest)[src] = l;
    };

    var findNode = function(id) {
        return $(".node[data-id='" + id + "']");
    };

    var registerNode = function(nodeid, label) {
        nodeState[nodeid] = {element: findNode(nodeid), visible: true, label: label};
    };

    var hideNode = function(nodeid) {
        var state = nodeState[nodeid];
        state.element.hide();
        state.visible = false;
    };

    var showNode = function(nodeid) {
        var state = nodeState[nodeid];
        state.element.show();
        state.visible = true;
    };

    var nodeFor = function(id) {
        var state = nodeState[id];
        if (state === undefined) {
            return undefined;
        } else {
            return state.element;
        }
    };

    var randomPlacement = function(current, toplace) {
        var angle = Math.random() * 2 * Math.PI;
        var yoffset = 180 * Math.sin(angle);
        var xoffset = 180 * Math.cos(angle);
        var position = nodeFor(current).offset();
        position.left = position.left + xoffset;
        position.top = position.top + yoffset;
        nodeFor(toplace).offset(position);
    };

    var addConnection = function(src, target) {
        var link = linksFor(src)[target];
        if (link !== undefined && !link.visible) {
            var linkName = link.names.join();
            jsPlumb.connect({
                source: nodeFor( src ),
                target: nodeFor( target ),
                overlays: [ ["Label", {label:linkName, location:0.7, id:"label", cssClass:"link-label"}] ]
            });
            link.visible = true;
        }
    };

    var addConnections = function(src, target) {
        addConnection(src, target);
        addConnection(target, src);
    };

    var addDirectionalConnections = function(outbound, src, target) {
        if (outbound) {
            addConnection(src, target);
        } else {
            addConnection(target, src);
        }
    };

    var removeConnections = function(src) {
        jsPlumb.detachAllConnections( nodeFor(src) );
        $.each(linksFor(src), function(target, state){ state.visible = false;  });
        $.each(invLinksFor(src), function(target, state){ state.visible = false;  });
    };

    var addNodeFn = function(outbound) {
        return function(event) {
            var node = $(event.currentTarget).attr('data-node');
            var links = outbound ? linksFor(node) : invLinksFor(node);
            $.each(links, function(linkedDS, state){
                var targetNode = nodeFor(linkedDS);
                if (targetNode === undefined) {
                    $.get('/ui/dataset-browse-element?uri=' + linkedDS, function(data){
                        $("#canvas").append(data);
                        initElement();
                        randomPlacement(node, linkedDS);
//                        addConnections(node, linkedDS);
                        addDirectionalConnections(outbound, node, linkedDS);
                    });
                } else {
                    showNode(linkedDS);
//                    addConnections( node, linkedDS);
                    addDirectionalConnections(outbound, node, linkedDS);
                }
            });
            return false;
        };
    };

    var initElement = function() {
        $(".popinfo").popover();

        jsPlumb.draggable($(".node"));

        $(".add-out").unbind().click( addNodeFn(true) );
        $(".add-in").unbind().click( addNodeFn(false) );

        $(".close-node").unbind().click(function(event){
            var nodeURI = $(event.currentTarget).attr('data-node');
            removeConnections( nodeURI );
            hideNode(nodeURI);
            return false;
        });
    };

    var scaling = 4;   // Scaling springy coordinates to screen coordinates, no longer used
    var maxIter = 200; // Force termination after this many iterations
    var iterStep = 2;  // 1 + number of iteration steps to skip animating

    var relayout = function() {
        // Set up springy clone of graph
        var graph = new Springy.Graph();
        $.each(nodeState, function(nodeID, state){
            if (state.visible) {
                state.springyNode = graph.newNode(state);
            }
        });
        $.each(linkState, function(src, links){
            $.each(links, function(target, state){
                if (state.visible) {
                    graph.newEdge( nodeState[src].springyNode, nodeState[target].springyNode );
                }
            });
        });

        var width = $("#canvas").width();
        var height = $("#canvas").height();

        var layout = new Springy.Layout.ForceDirected(
                graph,
                400.0, // Spring stiffness
                400.0, // Node repulsion
                0.25  // Damping
              );

        // calculate bounding box of graph layout.. with ease-in
        var currentBB = layout.getBoundingBox();
        var targetBB = {bottomleft: new Springy.Vector(-2, -2), topright: new Springy.Vector(2, 2)};

        // auto adjusting bounding box
        Springy.requestAnimationFrame(function adjust() {
            targetBB = layout.getBoundingBox();
            // current gets 20% closer to target every iteration
            currentBB = {
                bottomleft: currentBB.bottomleft.add( targetBB.bottomleft.subtract(currentBB.bottomleft)
                    .divide(10)),
                topright: currentBB.topright.add( targetBB.topright.subtract(currentBB.topright)
                    .divide(10))
            };

            Springy.requestAnimationFrame(adjust);
        });

        // convert to/from screen coordinates
        var toScreen = function(p) {
            var size = currentBB.topright.subtract(currentBB.bottomleft);
            var sx = p.subtract(currentBB.bottomleft).divide(size.x).x * width;
            var sy = p.subtract(currentBB.bottomleft).divide(size.y).y * height;
            return {left: sx, top: sy};
        };

        var fromScreen = function(s) {
            var size = currentBB.topright.subtract(currentBB.bottomleft);
            var px = (s.x / width) * size.x + currentBB.bottomleft.x;
            var py = (s.y / height) * size.y + currentBB.bottomleft.y;
            return new Springy.Vector(px, py);
        };

        var iter = 0;

        var renderer = new Springy.Renderer(
                layout,
                function clear() {
                    iter += 1;
                    if (iter > maxIter) {
                        renderer.stop();
                    }
                },
                function drawEdge(edge, p1, p2) { },
                function drawNode(node, p) {
                    if (iter % iterStep === 0) {
                        node.data.element.offset( toScreen(p) );
                        jsPlumb.repaint(node.data.element);
                    }
                }
              );
        renderer.start();
    };

    // Return the public variables/functions for this module
    return {
        register : register,
        registerNode : registerNode,
        initElement : initElement,
        relayout : relayout
    };

}(); // "revealing module" pattern

jsPlumb.bind("ready", function() {
    DATASET_EXPLORER.initElement();
    $("#relayout").click( DATASET_EXPLORER.relayout );
});

<|endoftext|>


<commit_before>"use strict";
/* global describe, it */

const expect = require("chai").expect;
const urlTransform = require("../src/urlTransform");

describe("urlTransform", function() {
  it("check null params", function() {
    expect(urlTransform()).to.eql("");
    expect(urlTransform(null)).to.eql("");
    expect(urlTransform("")).to.eql("");
    expect(urlTransform("/test")).to.eql("/test");
  });

  it("check replace path", function() {
    expect(urlTransform("/test/:id", {id: 1})).to.eql("/test/1");
    expect(urlTransform("/test/:id/hey/:id", {id: 1})).to.eql("/test/1/hey/1");
  });

  it("check replace path with hostname", function() {
    expect(urlTransform("http://localhost:1234/test/:id", {id: 1})).to.eql("http://localhost:1234/test/1");
    expect(urlTransform("http://localhost:1234/test/:id/hey/:id", {id: 1})).to.eql("http://localhost:1234/test/1/hey/1");
  });

  it("check optional params path", function() {
    expect(urlTransform("/test/:id", {id: 1})).to.eql("/test/1");
    expect(urlTransform("/test/(:id)", {id: 1})).to.eql("/test/1");
    expect(urlTransform("/test/(:id)")).to.eql("/test/");
  });

  it("check non-pretty params in path", function() {
    expect(urlTransform("/test/(:id)", {id1: 1})).to.eql("/test/?id1=1");
    expect(urlTransform("/test/?hello=1&(:id)", {id1: 1})).to.eql("/test/?hello=1&id1=1");
    expect(urlTransform("/test/?hello=2(:id)", {id1: 1})).to.eql("/test/?hello=2&id1=1");
  });

  it("check clean params", function() {
    expect(urlTransform("/test/:id")).to.eql("/test/");
    expect(urlTransform("/test/:id/")).to.eql("/test//");
    expect(urlTransform("/test/(:id)")).to.eql("/test/");
  });
});
<commit_msg>Add: additional test examples<commit_after>"use strict";
/* global describe, it */

const expect = require("chai").expect;
const urlTransform = require("../src/urlTransform");

describe("urlTransform", function() {
  it("check null params", function() {
    expect(urlTransform()).to.eql("");
    expect(urlTransform(null)).to.eql("");
    expect(urlTransform("")).to.eql("");
    expect(urlTransform("/test")).to.eql("/test");
  });

  it("check replace path", function() {
    expect(urlTransform("/test/:id", {id: 1})).to.eql("/test/1");
    expect(urlTransform("/test/:id/hey/:id", {id: 1})).to.eql("/test/1/hey/1");
  });

  it("check replace path with hostname", function() {
    expect(urlTransform("http://localhost:1234/test/:id", {id: 1})).to.eql("http://localhost:1234/test/1");
    expect(urlTransform("http://localhost:1234/test/:id/hey/:id", {id: 1})).to.eql("http://localhost:1234/test/1/hey/1");
    expect(urlTransform("http://localhost:1234/test/:id/hey/:id?hello=1", {id: 1})).to.eql("http://localhost:1234/test/1/hey/1?hello=1");
    expect(urlTransform("http://localhost:1234/test/:id/hey/:id?hello=1&world=2", {id: 1})).to.eql("http://localhost:1234/test/1/hey/1?hello=1&world=2");
  });

  it("check optional params path", function() {
    expect(urlTransform("/test/:id", {id: 1})).to.eql("/test/1");
    expect(urlTransform("/test/(:id)", {id: 1})).to.eql("/test/1");
    expect(urlTransform("/test/(:id)")).to.eql("/test/");
  });

  it("check non-pretty params in path", function() {
    expect(urlTransform("/test/(:id)", {id1: 1})).to.eql("/test/?id1=1");
    expect(urlTransform("/test/?hello=1&(:id)", {id1: 1})).to.eql("/test/?hello=1&id1=1");
    expect(urlTransform("/test/?hello=2(:id)", {id1: 1})).to.eql("/test/?hello=2&id1=1");
  });

  it("check clean params", function() {
    expect(urlTransform("/test/:id")).to.eql("/test/");
    expect(urlTransform("/test/:id/")).to.eql("/test//");
    expect(urlTransform("/test/(:id)")).to.eql("/test/");
  });
});
<|endoftext|>