<commit_before>"use strict";

// Karma
module.exports = function(config) {
	config.set({

		// base path that will be used to resolve all patterns (eg. files, exclude)
		basePath: '',

		// frameworks to use
		// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
		frameworks: ['jasmine'],

		// list of files / patterns to load in the browser
		files: [
			//'app/bower_components/jquery/jquery.js',
			'app/bower_components/angular/angular.js',
			'app/bower_components/angular-route/angular-route.js',
			'app/bower_components/angular-mocks/angular-mocks.js',
			//'app/bower_components/angular-resource/angular-resource.js',
			//'app/bower_components/angular-sanitize/angular-sanitize.js',
			//'app/bower_components/angular-cookies/angular-cookies.js',
			//'app/bower_components/underscore/underscore.js',
			'app/app.js',
			'app/Model/*.js',
			'app/View/*.js',
			'app/Controller/*.js',
			'test/unit/Model/*.js',
			'test/unit/Controller/*.js',
			'test/unit/View/*.js'
		],

		// list of files to exclude
		exclude: [

		],

		// preprocess matching files before serving them to the browser
		// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
		preprocessors: {
			// source files, that you wanna generate coverage for
			// do not include tests or libraries
			// (these files will be instrumented by Istanbul)
			'app/app.js': ['coverage'],
			'app/Model/*.js': ['coverage'],
			'app/View/*.js': ['coverage'],
			'app/Controllers/*.js': ['coverage']
		},

		// test results reporter to use
		// possible values: 'dots', 'progress'
		// available reporters: https://npmjs.org/browse/keyword/karma-reporter
		reporters: ['progress', 'junit', 'coverage'],

		junitReporter: {
			outputFile: '../gh-pages/reports-frontend/test-result.xml'
		},

		// configure the reporter
		coverageReporter: {
			reporters:[
				{
					type: 'html',
					dir: '../gh-pages/reports-frontend/coverage',
					suite: 'frontend'
				}
			],
		},

		// web server port
		port: 15077,

		// enable / disable colors in the output (reporters and logs)
		colors: true,

		// level of logging
		// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
		logLevel: config.LOG_DEBUG,

		// enable / disable watching file and executing tests whenever any file changes
		autoWatch: false,

		// start these browsers
		// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
		browsers: ['PhantomJS'],

		// Continuous Integration mode
		// if true, Karma captures browsers, runs the tests and exits
		singleRun: true
	});
};<commit_msg>modify karma.conf.js<commit_after>"use strict";

// Karma
module.exports = function(config) {
	config.set({

		// base path that will be used to resolve all patterns (eg. files, exclude)
		basePath: '',

		// frameworks to use
		// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
		frameworks: ['jasmine'],

		// list of files / patterns to load in the browser
		files: [
			//'app/bower_components/jquery/jquery.js',
			'app/bower_components/angular/angular.js',
			'app/bower_components/angular-mocks/angular-mocks.js',
			'app/bower_components/angular-resource/angular-resource.js',
			'app/bower_components/angular-route/angular-route.js',
			'app/bower_components/angular-sanitize/angular-sanitize.js',
			'app/bower_components/angular-cookies/angular-cookies.js',
			//'app/bower_components/underscore/underscore.js',
			'app/app.js',
			'app/Model/*.js',
			'app/View/*.js',
			'app/Controller/*.js',
			'test/unit/Model/*.js',
			'test/unit/Controller/*.js',
			'test/unit/View/*.js'
		],

		// list of files to exclude
		exclude: [

		],

		// preprocess matching files before serving them to the browser
		// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
		preprocessors: {
			// source files, that you wanna generate coverage for
			// do not include tests or libraries
			// (these files will be instrumented by Istanbul)
			'app/app.js': ['coverage'],
			'app/Model/*.js': ['coverage'],
			'app/View/*.js': ['coverage'],
			'app/Controllers/*.js': ['coverage']
		},

		// test results reporter to use
		// possible values: 'dots', 'progress'
		// available reporters: https://npmjs.org/browse/keyword/karma-reporter
		reporters: ['progress', 'junit', 'coverage'],

		junitReporter: {
			outputFile: '../gh-pages/reports-frontend/test-result.xml'
		},

		// configure the reporter
		coverageReporter: {
			reporters:[
				{
					type: 'html',
					dir: '../gh-pages/reports-frontend/coverage',
					suite: 'frontend'
				}
			],
		},

		// web server port
		port: 15077,

		// enable / disable colors in the output (reporters and logs)
		colors: true,

		// level of logging
		// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
		logLevel: config.LOG_DEBUG,

		// enable / disable watching file and executing tests whenever any file changes
		autoWatch: false,

		// start these browsers
		// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
		browsers: ['PhantomJS'],

		// Continuous Integration mode
		// if true, Karma captures browsers, runs the tests and exits
		singleRun: true
	});
};<|endoftext|>


<commit_before>const gulp = require('gulp');
const config = require('../config.js');

const connect = require('gulp-connect');
const runSequence = require('run-sequence');
const RevAll = require('gulp-rev-all');

gulp.task('dist-rev-assets', function() {
  const revAll = new RevAll({
    dontRenameFile: [
      '.json',
      'favicon.ico',
      /static\/addon\/*/,
      /static\/locales\/*/,
      '.html'
    ],
    dontUpdateReference: [
      /static\/addon\/*/,
      /.*\.json/,
      'favicon.ico'
    ]
  });
  return gulp.src(config.DEST_PATH + '**')
    .pipe(revAll.revision())
    .pipe(gulp.dest(config.DIST_PATH));
});

gulp.task('dist-build', done =>
  runSequence('clean', 'build', 'dist-rev-assets', done));

gulp.task('dist-watch', ['watch'], () =>
  gulp.watch(config.DEST_PATH + '**/*', ['dist-rev-assets']));

gulp.task('dist-server', () => connect.server({
  root: config.DIST_PATH,
  livereload: false,
  host: '0.0.0.0',
  port: config.SERVER_PORT
}));

gulp.task('dist', ['dist-build', 'dist-watch', 'dist-server']);
<commit_msg>Copy thumbnail-*.png to dist/ for deployment<commit_after>const gulp = require('gulp');
const config = require('../config.js');

const connect = require('gulp-connect');
const runSequence = require('run-sequence');
const RevAll = require('gulp-rev-all');

gulp.task('dist-rev-assets', function() {
  const revAll = new RevAll({
    dontRenameFile: [
      '.json',
      'favicon.ico',
      /static\/addon\/*/,
      /static\/locales\/*/,
      '.html'
    ],
    dontUpdateReference: [
      /static\/addon\/*/,
      /.*\.json/,
      'favicon.ico'
    ]
  });
  return gulp.src(config.DEST_PATH + '**')
    .pipe(revAll.revision())
    .pipe(gulp.dest(config.DIST_PATH));
});

gulp.task('dist-thumbnail-images', () => {
  gulp.src(config.DEST_PATH + 'static/images/thumbnail-*.png')
    .pipe(gulp.dest(config.DIST_PATH + 'static/images'));
});

gulp.task('dist-build', done =>
  runSequence('clean', 'build', 'dist-rev-assets', 'dist-thumbnail-images', done));

gulp.task('dist-watch', ['watch'], () =>
  gulp.watch(config.DEST_PATH + '**/*', ['dist-rev-assets']));

gulp.task('dist-server', () => connect.server({
  root: config.DIST_PATH,
  livereload: false,
  host: '0.0.0.0',
  port: config.SERVER_PORT
}));

gulp.task('dist', ['dist-build', 'dist-watch', 'dist-server']);
<|endoftext|>


<commit_before>// Purple Extension Adapter, part of the Purple project
// Copyright 2011 Google Inc.
// see Purple/license.txt for BSD license
// johnjbarton@google.com

var WebAppManager = (function () {

  var WebAppManager = {
    purpleTargetID: 6565259,
  };

  WebAppManager.getHistoryOfURLs = function() {
    var history = [];
    var nURLs = window.localStorage.length;
    for (var i = 0; i < nURLs; i++) {
      history.push(window.localStorage.key(i));
    }
    return history;
  };

  WebAppManager.updateHistory = function(url) {
    window.localStorage.setItem(url, "");
  };

  WebAppManager.loadTargetApp = function(url) {
    // random int between purple and 2 * purple
    var targetID = Math.floor(WebAppManager.purpleTargetID * (Math.random() + 1.0) );
    var createData = {
      url: url,
//      tabId: WebAppManager.purpleTargetID,
      focused: false,
      type: 'normal',
    };
    chrome.windows.create(createData, function onCreated(win) {
      console.log("created window for web app "+url, win);
      WebAppManager.updateHistory(url);
    });
  };
  return WebAppManager;
}());

function loadWebApp(event) {
  var urlInput = document.getElementById('webAppURL');
  var url = urlInput.value;
  WebAppManager.loadTargetApp(url);
}

function wireButton(event) {
  window.removeEventListener('load', wireButton, false);
  var button = document.getElementById('loadWebApp');
  button.addEventListener('click', loadWebApp, true);
  var history = WebAppManager.getHistoryOfURLs();
  if (history.length) {
    var urlInput = document.getElementById('webAppURL');
    urlInput.value = WebAppManager.history[history.length - 1];
  }
}

window.addEventListener('load', wireButton, false);
<commit_msg>add thePurple dynamically in background<commit_after>// Purple Extension Adapter, part of the Purple project
// Copyright 2011 Google Inc.
// see Purple/license.txt for BSD license
// johnjbarton@google.com

var WebAppManager = (function () {

  var WebAppManager = {
    purpleTargetID: 6565259,
  };

  WebAppManager.getHistoryOfURLs = function() {
    var history = [];
    var nURLs = window.localStorage.length;
    for (var i = 0; i < nURLs; i++) {
      history.push(window.localStorage.key(i));
    }
    return history;
  };

  WebAppManager.updateHistory = function(url) {
    window.localStorage.setItem(url, "");
  };

  WebAppManager.loadTargetApp = function(url) {
    // random int between purple and 2 * purple
    var targetID = Math.floor(WebAppManager.purpleTargetID * (Math.random() + 1.0) );
    var createData = {
      url: url,
//      tabId: WebAppManager.purpleTargetID,
      focused: false,
      type: 'normal',
    };
    console.log("Calling windows.create for "+url, createData);
    chrome.windows.create(createData, function onCreated(win) {
      console.log("created window for web app "+url, win);
      WebAppManager.updateHistory(url);
    });
    console.log("Called windows.create for "+url, createData);
  };
  return WebAppManager;
}());

function loadWebApp(event) {
  var urlInput = document.getElementById('webAppURL');
  var url = urlInput.value;
  WebAppManager.loadTargetApp(url);
  turnOnPurple();
  return false;
}

function turnOnPurple() {
  var intro = document.getElementById('intro');
  intro.style.display = 'none';
  var thePurple = document.getElementById('thePurple');
  thePurple.style.display = 'block';
}

function wireButton() {
  var button = document.getElementById('loadWebApp');
  button.addEventListener('click', loadWebApp, true);
  var history = WebAppManager.getHistoryOfURLs();
  if (history.length) {
    var urlInput = document.getElementById('webAppURL');
    urlInput.value = history[history.length - 1];
  }
}

function appendPurple() {
  var iframe = document.createElement('iframe');
  iframe.setAttribute('id', 'thePurple');
  iframe.setAttribute('src', "http://orionhub.org/file/Fu/purple.html");
  iframe.setAttribute('style', 'display: none;'); // don't show while loading
  document.body.appendChild(iframe);
}

function onWindowLoad(event) {
  window.removeEventListener('load', onWindowLoad, false);
  wireButton();
  appendPurple();
}

window.addEventListener('load', onWindowLoad, false);

<|endoftext|>


<commit_before>!function(e){"use strict";e.module("pipHelp",["pipHelp.Service","pipHelp.Page"])}(window.angular),function(e){try{e=angular.module("pipHelp.Templates")}catch(t){e=angular.module("pipHelp.Templates",[])}e.run(["$templateCache",function(e){e.put("help_page/help_page.html",'<md-toolbar class="pip-appbar-ext"></md-toolbar><pip-document width="800" min-height="400">
<md-list class="pip-menu pip-simple-list hide-xs" pip-selected="selected.tabIndex" pip-selected-watch="selected.navId" pip-select="onNavigationSelect($event.id)"><md-list-item class="pip-simple-list-item pip-selectable" ng-repeat="tab in tabs track by tab.state" md-ink-ripple="" pip-id="{{::tab.state }}">
{{::tab.title | translate}}
</md-list-item></md-list>
<pip-dropdown class="hide-gt-xs" pip-actions="tabs" pip-dropdown-select="onDropdownSelect" pip-active-index="selected.tabIndex"></pip-dropdown>

{{::\'ERROR_400\' | translate}}
</pip-document>')}])}(),function(e,t){"use strict";e.module("pipHelp.Service",["pipState"]).provider("pipHelp",["pipAuthStateProvider",function(i){function a(e){return"help."+e}function n(){return t.clone(c,!0)}function p(){return t.clone(t.find(c,function(e){return e.state===r}),!0)}function s(n){var p;if(o(n),p=t.find(c,function(e){return e.state===a(n.state)}))throw new Error('Tab with state name "'+n.state+'" is already registered');c.push({state:a(n.state),title:n.title,access:n.access||e.noop,visible:n.visible||!0,stateConfig:t.clone(n.stateConfig,!0)}),i.state(a(n.state),n.stateConfig),t.isUndefined(r)&&1===c.length&&l(n.state)}function l(e){var n,p;if(n=t.find(c,function(t){return t.state===a(e)}),!n)throw p=new Error('Tab with state name "'+e+'" is not registered');r=a(e),i.redirect("help",a(e))}function o(e){if(!e||!t.isObject(e))throw new Error("Invalid object");if(!e.state||""===e.state)throw new Error("Tab should have valid Angular UI router state name");if(e.access&&!t.isFunction(e.access))throw new Error('"access" should be a function');if(!e.stateConfig||!t.isObject(e.stateConfig))throw new Error("Invalid state configuration object")}var r,c=[];this.addTab=s,this.setDefaultTab=l,this.getTabs=n,this.getDefaultTab=p,this.$get=function(){return{getTabs:n,getDefaultTab:p,addTab:s,setDefaultTab:l}}}])}(window.angular,window._),function(e,t){"use strict";function i(e){e.state("help",{url:"/help",auth:!1,controller:"pipHelpPageController",templateUrl:"help_page/help_page.html"})}function a(i,a,n,p,s){function l(e){r(e.state)}function o(){p.showMenuNavIcon(),p.showTitleText("Help"),p.showShadowSm(),p.showLocalActions(null,[])}function r(e){c(e),a.selected.tab&&n.go(e)}function c(e){a.selected.tab=t.find(a.tabs,function(t){return t.state===e}),a.selected.tabIndex=t.indexOf(a.tabs,a.selected.tab),a.selected.tabId=e}a.tabs=t.filter(s.getTabs(),function(t){if(t.visible&&(t.access===e.noop||t.access(i.$user,t)))return t}),a.selected={},c("help"!==n.current.name?n.current.name:s.getDefaultTab().state),o(),a.onNavigationSelect=r,a.onDropdownSelect=l}i.$inject=["pipStateProvider"],a.$inject=["$rootScope","$scope","$state","pipAppBar","pipHelp"],e.module("pipHelp.Page",["pipState","pipHelp.Service","pipAppBar","pipSelected","pipTranslate","pipHelp.Templates"]).config(i).controller("pipHelpPageController",a)}(window.angular,window._);<commit_msg>Updated submodules<commit_after>!function(e){"use strict";e.module("pipHelp",["pipHelp.Service","pipHelp.Page"])}(window.angular),function(e){try{e=angular.module("pipHelp.Templates")}catch(t){e=angular.module("pipHelp.Templates",[])}e.run(["$templateCache",function(e){e.put("help_page/help_page.html",'<md-toolbar class="pip-appbar-ext"></md-toolbar><pip-document width="800" min-height="400">
<md-list class="pip-menu pip-simple-list hide-xs" pip-selected="selected.tabIndex" pip-selected-watch="selected.navId" pip-select="onNavigationSelect($event.id)"><md-list-item class="pip-simple-list-item pip-selectable" ng-repeat="tab in tabs track by tab.state" md-ink-ripple="" pip-id="{{::tab.state }}">
{{::tab.title | translate}}
</md-list-item></md-list>
<pip-dropdown class="hide-gt-xs" pip-actions="tabs" pip-dropdown-select="onDropdownSelect" pip-active-index="selected.tabIndex"></pip-dropdown>

{{::\'ERROR_400\' | translate}}
</pip-document>')}])}(),function(e,t){"use strict";function i(e){e.state("help",{url:"/help",auth:!1,controller:"pipHelpPageController",templateUrl:"help_page/help_page.html"})}function a(i,a,n,p,s){function l(e){r(e.state)}function o(){p.showMenuNavIcon(),p.showTitleText("Help"),p.showShadowSm(),p.showLocalActions(null,[])}function r(e){c(e),a.selected.tab&&n.go(e)}function c(e){a.selected.tab=t.find(a.tabs,function(t){return t.state===e}),a.selected.tabIndex=t.indexOf(a.tabs,a.selected.tab),a.selected.tabId=e}a.tabs=t.filter(s.getTabs(),function(t){if(t.visible&&(t.access===e.noop||t.access(i.$user,t)))return t}),a.selected={},c("help"!==n.current.name?n.current.name:s.getDefaultTab().state),o(),a.onNavigationSelect=r,a.onDropdownSelect=l}i.$inject=["pipStateProvider"],a.$inject=["$rootScope","$scope","$state","pipAppBar","pipHelp"],e.module("pipHelp.Page",["pipState","pipHelp.Service","pipAppBar","pipSelected","pipTranslate","pipHelp.Templates"]).config(i).controller("pipHelpPageController",a)}(window.angular,window._),function(e,t){"use strict";e.module("pipHelp.Service",["pipState"]).provider("pipHelp",["pipAuthStateProvider",function(i){function a(e){return"help."+e}function n(){return t.clone(c,!0)}function p(){return t.clone(t.find(c,function(e){return e.state===r}),!0)}function s(n){var p;if(o(n),p=t.find(c,function(e){return e.state===a(n.state)}))throw new Error('Tab with state name "'+n.state+'" is already registered');c.push({state:a(n.state),title:n.title,access:n.access||e.noop,visible:n.visible||!0,stateConfig:t.clone(n.stateConfig,!0)}),i.state(a(n.state),n.stateConfig),t.isUndefined(r)&&1===c.length&&l(n.state)}function l(e){var n,p;if(n=t.find(c,function(t){return t.state===a(e)}),!n)throw p=new Error('Tab with state name "'+e+'" is not registered');r=a(e),i.redirect("help",a(e))}function o(e){if(!e||!t.isObject(e))throw new Error("Invalid object");if(!e.state||""===e.state)throw new Error("Tab should have valid Angular UI router state name");if(e.access&&!t.isFunction(e.access))throw new Error('"access" should be a function');if(!e.stateConfig||!t.isObject(e.stateConfig))throw new Error("Invalid state configuration object")}var r,c=[];this.addTab=s,this.setDefaultTab=l,this.getTabs=n,this.getDefaultTab=p,this.$get=function(){return{getTabs:n,getDefaultTab:p,addTab:s,setDefaultTab:l}}}])}(window.angular,window._);<|endoftext|>


<commit_before>let a = require("./anotherModule");
let fetch = require("whatwg-fetch").fetch;
let _ = require("lodash");

fetch('/users.html').then(() => console.log(arguments));

_.pick({});

console.log(a);<commit_msg>checked promises<commit_after>let a = require("./anotherModule");
let fetch = require("whatwg-fetch").fetch;
let pick = require("lodash/pick");
let Promise = require("promise-polyfill");

fetch('/users.html').then(() => console.log(arguments));

pick({});

Promise.resolve({test: "test"}).then((res) => console.log(res));

console.log(a);<|endoftext|>


<commit_before>'use strict';

var d3 = require('d3');
var $ = require('jquery');
var Backbone = require('backbone');
Backbone.$ = $;

var FlowGraph = Backbone.View.extend({

    tagName: 'section',

    /**
     * Graph constructor
     * @param options
     */
    initialize: function (options) {
        this.title = options.title;
        this.width = options.width || 1200;
        this.height = options.height || 500;
        this.numberFormatter = options.numberFormatter || d3.format(",.2f");
        this.collection.on('flows:add', this.onAddFlows, this);
    },

    /**
     * Renders graph
     * @returns {FlowGraph}
     */
    render: function () {
        this.$el.empty();

        if (this.title) {
            var header = document.createElement('h2');
            $(header).text(this.title);
            this.el.appendChild(header);
        }

        this.force = d3.layout.force()
            .gravity(.05)
            .distance(240)
            .size([this.width, this.height])
            .linkDistance(240)
            .charge(-300);
        this.nodes = this.force.nodes();
        this.links = this.force.links();

        var svg = d3.select(this.el).append("svg:svg")
            .attr("width", this.width)
            .attr("height", this.height)
            .attr("pointer-events", "all")
            .attr("viewBox", "0 0 " + this.width + " " + this.height)
            .attr("perserveAspectRatio","xMinYMid");

        svg.append("svg:defs").selectAll("marker")
                .data(["end"])
            .enter().append("svg:marker")
                .attr("id", "end")
                .attr("viewBox", "-10 -5 10 10")
                .attr("refX", -15)
                .attr("refY", -1.5)
                .attr("markerWidth", 6)
                .attr("markerHeight", 6)
                .attr("orient", "auto")
            .append("svg:path")
                .attr("d", "M0,5L-10,0L0,-5");

        this.svg = svg.append('svg:g');

        this.collection.forEach(function(edgeData) {
            this.addEdge(edgeData);
        }, this);

        this.update();
        return this;
    },

    /**
     * Check that node exists or creates a new one
     * @param name
     * @returns Object
     */
    ensureNode: function(name) {
        for (var i = 0; i < this.nodes.length; i++) {
            if (name == this.nodes[i].name) {
                return this.nodes[i];
            }
        }

        var node = {name: name};
        this.nodes.push(node);
        return node;
    },

    /**
     * Adds new edge to the graph
     * @param data
     */
    addEdge: function (data) {
        var edge = {
            source: this.ensureNode(data.get('source')),
            target: this.ensureNode(data.get('target')),
            value: this.numberFormatter(data.get('from')) + ' => ' + this.numberFormatter(data.get('to'))
        };

        for (var i = 0; i < this.links.length; i++) {
            if (edge.source.name == this.links[i].source.name && edge.target.name == this.links[i].target.name) {
                this.svg.selectAll("#label-" + edge.source.name + "-" + edge.target.name)
                    .text(edge.value);
                return;
            }
        }

        this.links.push(edge);
    },

    /**
     * Event occurs when new flows are added to collection.
     * @param flows
     */
    onAddFlows: function(flows) {
        flows.forEach(function(edgeData) {
            this.addEdge(edgeData);
        }, this);

        this.update();
    },

    /**
     * Updates graph view.
     */
    update: function() {
        /**
         * I've found initial code in the Internet, although I have to rework it significantly.
         * Unfortunately it (and source scripts too) does not work in IE properly.
         * Anyway, big thanks for the initial code to:
         *
         * mbostock http://bl.ocks.org/mbostock
         * @see http://bl.ocks.org/mbostock/1153292
         *
         * nrabinowitz http://stackoverflow.com/users/380487/nrabinowitz
         * @see http://stackoverflow.com/questions/18316056/d3-js-force-layout-edge-label-placement-rotation
         *
         * Rahul Rout http://stackoverflow.com/users/1482500/rahul-rout
         * @see http://stackoverflow.com/questions/11400241/updating-links-on-a-force-directed-graph-from-dynamic-json-data
         */
        var link = this.svg.selectAll("path.link").data(this.links);

        link.enter().append("svg:path")
            .attr("class", "link")
            .attr("marker-start", function(d) { return "url(#end)"; });

        link.enter().append("svg:path")
            .attr("id", function(d) { return d.source.name + "-" + d.target.name; })
            .attr("class", "text");

        var linkPath = this.svg.selectAll("path.link").data(this.links);
        var textPath = this.svg.selectAll("path.text").data(this.links);

        var node = this.svg.selectAll("g.node").data(this.nodes);

        var nodeEnter = node.enter().append("svg:g")
            .attr("class", "node")
            .call(this.force.drag);

        var circle = nodeEnter.append("svg:circle").attr("r", 6);

        var text = nodeEnter.append("svg:g");
        // A copy of the text with a thick white stroke for legibility.
        text.append("svg:text")
            .attr("x", 8)
            .attr("y", ".31em")
            .attr("class", "shadow")
            .text(function(d) { return d.name; });
        text.append("svg:text")
            .attr("x", 8)
            .attr("y", ".31em")
            .text(function(d) { return d.name; });

        var pathLabel = this.svg.selectAll(".path-label")
            .data(this.links)
            .enter().append("svg:text")
                .attr("class", "path-label")
                .append("svg:textPath")
                    .attr("startOffset", "50%")
                    .attr("text-anchor", "middle")
                    .attr("id", function(d) { return "label-" + d.source.name + "-" + d.target.name; })
                    .attr("xlink:href", function(d) { return "#" + d.source.name + "-" + d.target.name; })
                    .style("fill", "#000")
                    .style("font-family", "Arial")
                    .text(function(d) { return d.value; });

        function arcPath(leftHand, d) {
            var start = leftHand ? d.source : d.target,
                end = leftHand ? d.target : d.source,
                dx = end.x - start.x,
                dy = end.y - start.y,
                dr = Math.sqrt(dx * dx + dy * dy),
                sweep = leftHand ? 0 : 1;
            return "M" + start.x + "," + start.y + "A" + dr + "," + dr + " 0 0," + sweep + " " + end.x + "," + end.y;
        }

        // Use elliptical arc path segments to doubly-encode directionality.
        this.force.on("tick", function () {
            linkPath.attr("d", function(d) {
                return arcPath(false, d);
            });

            textPath.attr("d", function(d) {
                return arcPath(d.source.x < d.target.x, d);
            });

            node.attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
            });

            link.attr("x1", function(d) { return d.source.x; })
                .attr("y1", function(d) { return d.source.y; })
                .attr("x2", function(d) { return d.target.x; })
                .attr("y2", function(d) { return d.target.y; });
        });

        this.force.start();
    }
});

module.exports = FlowGraph;
<commit_msg>Increase distance<commit_after>'use strict';

var d3 = require('d3');
var $ = require('jquery');
var Backbone = require('backbone');
Backbone.$ = $;

var FlowGraph = Backbone.View.extend({

    tagName: 'section',

    /**
     * Graph constructor
     * @param options
     */
    initialize: function (options) {
        this.title = options.title;
        this.width = options.width || 1200;
        this.height = options.height || 500;
        this.numberFormatter = options.numberFormatter || d3.format(",.2f");
        this.collection.on('flows:add', this.onAddFlows, this);
    },

    /**
     * Renders graph
     * @returns {FlowGraph}
     */
    render: function () {
        this.$el.empty();

        if (this.title) {
            var header = document.createElement('h2');
            $(header).text(this.title);
            this.el.appendChild(header);
        }

        this.force = d3.layout.force()
            .gravity(.05)
            .distance(360)
            .size([this.width, this.height])
            .linkDistance(360)
            .charge(-300);
        this.nodes = this.force.nodes();
        this.links = this.force.links();

        var svg = d3.select(this.el).append("svg:svg")
            .attr("width", this.width)
            .attr("height", this.height)
            .attr("pointer-events", "all")
            .attr("viewBox", "0 0 " + this.width + " " + this.height)
            .attr("perserveAspectRatio","xMinYMid");

        svg.append("svg:defs").selectAll("marker")
                .data(["end"])
            .enter().append("svg:marker")
                .attr("id", "end")
                .attr("viewBox", "-10 -5 10 10")
                .attr("refX", -15)
                .attr("refY", -1.5)
                .attr("markerWidth", 6)
                .attr("markerHeight", 6)
                .attr("orient", "auto")
            .append("svg:path")
                .attr("d", "M0,5L-10,0L0,-5");

        this.svg = svg.append('svg:g');

        this.collection.forEach(function(edgeData) {
            this.addEdge(edgeData);
        }, this);

        this.update();
        return this;
    },

    /**
     * Check that node exists or creates a new one
     * @param name
     * @returns Object
     */
    ensureNode: function(name) {
        for (var i = 0; i < this.nodes.length; i++) {
            if (name == this.nodes[i].name) {
                return this.nodes[i];
            }
        }

        var node = {name: name};
        this.nodes.push(node);
        return node;
    },

    /**
     * Adds new edge to the graph
     * @param data
     */
    addEdge: function (data) {
        var edge = {
            source: this.ensureNode(data.get('source')),
            target: this.ensureNode(data.get('target')),
            value: this.numberFormatter(data.get('from')) + ' => ' + this.numberFormatter(data.get('to'))
        };

        for (var i = 0; i < this.links.length; i++) {
            if (edge.source.name == this.links[i].source.name && edge.target.name == this.links[i].target.name) {
                this.svg.selectAll("#label-" + edge.source.name + "-" + edge.target.name)
                    .text(edge.value);
                return;
            }
        }

        this.links.push(edge);
    },

    /**
     * Event occurs when new flows are added to collection.
     * @param flows
     */
    onAddFlows: function(flows) {
        flows.forEach(function(edgeData) {
            this.addEdge(edgeData);
        }, this);

        this.update();
    },

    /**
     * Updates graph view.
     */
    update: function() {
        /**
         * I've found initial code in the Internet, although I have to rework it significantly.
         * Unfortunately it (and source scripts too) does not work in IE properly.
         * Anyway, big thanks for the initial code to:
         *
         * mbostock http://bl.ocks.org/mbostock
         * @see http://bl.ocks.org/mbostock/1153292
         *
         * nrabinowitz http://stackoverflow.com/users/380487/nrabinowitz
         * @see http://stackoverflow.com/questions/18316056/d3-js-force-layout-edge-label-placement-rotation
         *
         * Rahul Rout http://stackoverflow.com/users/1482500/rahul-rout
         * @see http://stackoverflow.com/questions/11400241/updating-links-on-a-force-directed-graph-from-dynamic-json-data
         */
        var link = this.svg.selectAll("path.link").data(this.links);

        link.enter().append("svg:path")
            .attr("class", "link")
            .attr("marker-start", function(d) { return "url(#end)"; });

        link.enter().append("svg:path")
            .attr("id", function(d) { return d.source.name + "-" + d.target.name; })
            .attr("class", "text");

        var linkPath = this.svg.selectAll("path.link").data(this.links);
        var textPath = this.svg.selectAll("path.text").data(this.links);

        var node = this.svg.selectAll("g.node").data(this.nodes);

        var nodeEnter = node.enter().append("svg:g")
            .attr("class", "node")
            .call(this.force.drag);

        var circle = nodeEnter.append("svg:circle").attr("r", 6);

        var text = nodeEnter.append("svg:g");
        // A copy of the text with a thick white stroke for legibility.
        text.append("svg:text")
            .attr("x", 8)
            .attr("y", ".31em")
            .attr("class", "shadow")
            .text(function(d) { return d.name; });
        text.append("svg:text")
            .attr("x", 8)
            .attr("y", ".31em")
            .text(function(d) { return d.name; });

        var pathLabel = this.svg.selectAll(".path-label")
            .data(this.links)
            .enter().append("svg:text")
                .attr("class", "path-label")
                .append("svg:textPath")
                    .attr("startOffset", "50%")
                    .attr("text-anchor", "middle")
                    .attr("id", function(d) { return "label-" + d.source.name + "-" + d.target.name; })
                    .attr("xlink:href", function(d) { return "#" + d.source.name + "-" + d.target.name; })
                    .style("fill", "#000")
                    .style("font-family", "Arial")
                    .text(function(d) { return d.value; });

        function arcPath(leftHand, d) {
            var start = leftHand ? d.source : d.target,
                end = leftHand ? d.target : d.source,
                dx = end.x - start.x,
                dy = end.y - start.y,
                dr = Math.sqrt(dx * dx + dy * dy),
                sweep = leftHand ? 0 : 1;
            return "M" + start.x + "," + start.y + "A" + dr + "," + dr + " 0 0," + sweep + " " + end.x + "," + end.y;
        }

        // Use elliptical arc path segments to doubly-encode directionality.
        this.force.on("tick", function () {
            linkPath.attr("d", function(d) {
                return arcPath(false, d);
            });

            textPath.attr("d", function(d) {
                return arcPath(d.source.x < d.target.x, d);
            });

            node.attr("transform", function(d) {
                return "translate(" + d.x + "," + d.y + ")";
            });

            link.attr("x1", function(d) { return d.source.x; })
                .attr("y1", function(d) { return d.source.y; })
                .attr("x2", function(d) { return d.target.x; })
                .attr("y2", function(d) { return d.target.y; });
        });

        this.force.start();
    }
});

module.exports = FlowGraph;
<|endoftext|>


<commit_before>export default function readImages(document, data, progress) {

	return new Promise(resolve => {

		let urls = [];

		data.forEach(({data: image}) => {
			if (image.img && image.img.src) {
				urls.push(image.img.src);
			}
			if (image.img && image.img.srcset) {
				image.img.srcset.forEach(({src}) => {
					urls.push(src);
				});
			}
			image.sources.forEach(({srcset}) => {
				srcset.forEach(({src}) => {
					urls.push(src);
				});
			});
		});

		urls = urls.filter((url, index) => urls.indexOf(url) === index);

		let images = {};

		urls.forEach(url => {
			let image = {
				url: resolveUrl(document, url),
			};
			let element = new Image();
			element.src = image.url;
			image.element = element;
			images[url] = image;
		});

		function step(startTime = Date.now()) {

			progress(Object.keys(images).reduce(
				(count, key) => count + (images[key].element ? 0 : 1),
				0
			) / (Object.keys(images).length || 1));

			let currentImage;

			Object.keys(images).forEach(key => {
				if (images[key].element && images[key].element.complete) {
					currentImage = images[key];
				}
			});

			if (currentImage) {
				readImage(currentImage);
				if (!currentImage.hash && currentImage.element.src.split('/')[2] !== 'crossorigin.me') {
					currentImage.element = new Image();
					currentImage.element.crossOrigin = 'anonymous';
					currentImage.element.src = 'https://crossorigin.me/' + currentImage.url;
				}
				else {
					delete currentImage.element;
				}
			}

			if (Object.keys(images).reduce((done, key) => done && !images[key].element, true)) {
				progress(1);
				finish();
				return;
			}

			if (!currentImage) {
				setTimeout(step, 16);
				return;
			}

			// Don’t force the main thread to go under 30 fps
			if (Date.now() - startTime > 1000 / 30) {
				setTimeout(step, 0);
				return;
			}

			step(startTime);

		}

		step();

		function finish() {

			data.forEach(image => {
				image.images = {};
				if (image.data.img && image.data.img.src) {
					image.images[image.data.img.src] = images[image.data.img.src];
				}
				if (image.data.img && image.data.img.srcset) {
					image.data.img.srcset.forEach(({src}) => {
						image.images[src] = images[src];
					});
				}
				image.data.sources.forEach(({srcset}) => {
					srcset.forEach(({src}) => {
						image.images[src] = images[src];
					});
				});
			});

			resolve();

		}

	});

}

function resolveUrl(document, url) {
	let link = document.createElement('a');
	link.href = url;
	return link.href + '';
}

function readImage(image) {
	image.size = image.size || {
		width: image.element.naturalWidth,
		height: image.element.naturalHeight,
	};
	image.type = image.type || image.url.split('#')[0].split('?')[0].split('.').pop().toLowerCase();
	if (image.type === 'jpg') {
		image.type = 'jpeg';
	}
	image.hash = image.hash || getImageHash(image.element);
}

function getImageHash(image) {

	const size = 8;
	const depth = 16;

	let data;
	try {
		data = Array.from(
			stepDownResize(image, size).getImageData(0, 0, size, size).data
		).reduce(
			(str, val) => str + Math.floor(val * (depth / 256)).toString(depth),
			''
		);
	}
	catch (e) {
		data = false;
	}
	return data;
}

function stepDownResize(image, targetSize) {

	const imageSize = Math.max(image.naturalWidth || 0, image.naturalHeight || 0, targetSize);
	let size = targetSize;
	while (size * 2 < imageSize) {
		size *= 2;
	}

	const canvas = document.createElement('canvas');
	canvas.width = canvas.height = size;
	const ctx = canvas.getContext('2d');
	ctx.drawImage(image, 0, 0, size, size);

	while (size >= targetSize) {
		ctx.drawImage(
			canvas,
			0, 0, size, size,
			0, 0, size / 2, size / 2
		);
		size /= 2;
	}

	return ctx;

}
<commit_msg>Only load CORS-failed images via proxy<commit_after>export default function readImages(document, data, progress) {

	return new Promise(resolve => {

		let urls = [];

		data.forEach(({data: image}) => {
			if (image.img && image.img.src) {
				urls.push(image.img.src);
			}
			if (image.img && image.img.srcset) {
				image.img.srcset.forEach(({src}) => {
					urls.push(src);
				});
			}
			image.sources.forEach(({srcset}) => {
				srcset.forEach(({src}) => {
					urls.push(src);
				});
			});
		});

		urls = urls.filter((url, index) => urls.indexOf(url) === index);

		let images = {};

		urls.forEach(url => {
			let image = {
				url: resolveUrl(document, url),
			};
			let element = new Image();
			element.src = image.url;
			image.element = element;
			images[url] = image;
		});

		function step(startTime = Date.now()) {

			progress(Object.keys(images).reduce(
				(count, key) => count + (images[key].element ? 0 : 1),
				0
			) / (Object.keys(images).length || 1));

			let currentImage;

			Object.keys(images).forEach(key => {
				if (images[key].element && images[key].element.complete) {
					currentImage = images[key];
				}
			});

			if (currentImage) {
				readImage(currentImage);
				if (currentImage.hash === null && currentImage.element.src.split('/')[2] !== 'crossorigin.me') {
					currentImage.element = new Image();
					currentImage.element.crossOrigin = 'anonymous';
					currentImage.element.src = 'https://crossorigin.me/' + currentImage.url;
				}
				else {
					delete currentImage.element;
				}
			}

			if (Object.keys(images).reduce((done, key) => done && !images[key].element, true)) {
				progress(1);
				finish();
				return;
			}

			if (!currentImage) {
				setTimeout(step, 16);
				return;
			}

			// Don’t force the main thread to go under 30 fps
			if (Date.now() - startTime > 1000 / 30) {
				setTimeout(step, 0);
				return;
			}

			step(startTime);

		}

		step();

		function finish() {

			data.forEach(image => {
				image.images = {};
				if (image.data.img && image.data.img.src) {
					image.images[image.data.img.src] = images[image.data.img.src];
				}
				if (image.data.img && image.data.img.srcset) {
					image.data.img.srcset.forEach(({src}) => {
						image.images[src] = images[src];
					});
				}
				image.data.sources.forEach(({srcset}) => {
					srcset.forEach(({src}) => {
						image.images[src] = images[src];
					});
				});
			});

			resolve();

		}

	});

}

function resolveUrl(document, url) {
	let link = document.createElement('a');
	link.href = url;
	return link.href + '';
}

function readImage(image) {
	image.size = image.size || {
		width: image.element.naturalWidth,
		height: image.element.naturalHeight,
	};
	image.type = image.type || image.url.split('#')[0].split('?')[0].split('.').pop().toLowerCase();
	if (image.type === 'jpg') {
		image.type = 'jpeg';
	}
	image.hash = image.hash || getImageHash(image.element);
}

function getImageHash(image) {

	const size = 8;
	const depth = 16;

	let data;
	try {
		data = Array.from(
			stepDownResize(image, size).getImageData(0, 0, size, size).data
		).reduce(
			(str, val) => str + Math.floor(val * (depth / 256)).toString(depth),
			''
		);
	}
	catch (e) {
		// Check for security error because of tainted canvas
		if (e.code === 18) {
			data = null;
		}
	}
	return data;
}

function stepDownResize(image, targetSize) {

	const imageSize = Math.max(image.naturalWidth || 0, image.naturalHeight || 0, targetSize);
	let size = targetSize;
	while (size * 2 < imageSize) {
		size *= 2;
	}

	const canvas = document.createElement('canvas');
	canvas.width = canvas.height = size;
	const ctx = canvas.getContext('2d');
	ctx.drawImage(image, 0, 0, size, size);

	while (size >= targetSize) {
		ctx.drawImage(
			canvas,
			0, 0, size, size,
			0, 0, size / 2, size / 2
		);
		size /= 2;
	}

	return ctx;

}
<|endoftext|>


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

// TODO: Should have a GUID 'id' instead of name, since now
// you can't have two properties with the same name but
// different parents.
foam.CLASS({
  package: 'com.google.flow',
  name: 'Property',

  ids: [ 'name' ],

  properties: [
    {
      class: 'String',
      name: 'name'
    },
    {
      name: 'value',
      cloneProperty: function(o, m) {
        m[this.name ] = o.cls_.create({
          x:      o.x,
          y:      o.y,
          width:  o.width,
          height: o.height,
          radius: o.radius,
          border: o.radius,
          color:  o.color
        });
      }
    }
  ],
  actions: [
    {
      name: 'deleteRow',
      label: 'X',
      code: function deleteRow(X) {
        X.properties.remove(X.data);
      }
    }
  ]
});

// TODO(adamvy): Remove the need to store this relationship globally.
var relationship = foam.RELATIONSHIP({
  name: 'children',
  inverseName: 'parent',
  cadinality: '1:*',
  sourceModel: 'com.google.flow.Property',
  targetModel: 'com.google.flow.Property',
  targetDAOKey: 'properties'
});

foam.CLASS({
  package: 'com.google.flow',
  name: 'FLOW',
  extends: 'foam.u2.Element',

  implements: [
    'foam.mlang.Expressions',
    'foam.memento.MementoMgr'
  ],

  requires: [
    'com.google.flow.Halo',
    'com.google.flow.Property',
    'foam.dao.EasyDAO',
    'foam.graphics.Box',
    'foam.graphics.CView',
    'foam.graphics.Circle',
    'foam.physics.Physical',
    'foam.physics.PhysicsEngine',
    'foam.u2.PopupView',
    'foam.u2.TableView',
    'foam.util.Timer',
    'foam.u2.view.TreeView',
    'com.google.flow.DetailPropertyView'
  ],

  exports: [
    'timer',
    'as data',
    'properties',
    'scope'
  ],

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
      body { overflow: hidden; user-select: none; font-family: 'Roboto', sans-serif; color: #444; }
      ^ { display: flex; }
      ^ > * { padding-left: 16px; padding-right: 16px; }
      ^tools, ^properties, ^sheet { box-shadow: 3px 3px 6px 0 gray; height: 100%; }
      ^sheet { width: 100%; overflow-y: auto; }
      ^tools thead, ^properties thead { display: none }
      ^tools tr { height: 30px }
      .foam-u2-TableView { border-collapse: collapse; }
      .foam-u2-TableView td { padding-left: 6px; }
      .foam-u2-TableView-selected { outline: 1px solid red; }
      ^ canvas { border: none; }
      ^ .foam-u2-ActionView { margin: 10px; }
      ^properties .foam-u2-view-TreeViewRow { position: relative; }
      ^properties .foam-u2-ActionView, ^properties .foam-u2-ActionView:hover { background: white; padding: 0; position: absolute; right: 2px; border: none; margin: 6px 0 0 0; }
      .foam-u2-Tabs { padding-top: 0 !important; }
      input[type="range"] { width: 150px; height: 15px; }
      input[type="color"] { width: 22px; }
      */}
    })
  ],

  properties: [
    {
      name: 'scope',
      factory: function() { return {a:42}; },
      documentation: 'Scope to run reactive formulas in.'
    },
    {
      name: 'physics',
      factory: function() {
        return this.PhysicsEngine.create({
          bounceOnWalls: true,
          bounds: this.canvas
        });
      }
    },
    {
      name: 'timer',
      factory: function() {
        return this.Timer.create();
      }
    },
    'feedback_',
    'currentTool',
    {
      class: 'foam.dao.DAOProperty',
      name: 'tools',
      view: {
        class: 'foam.u2.TableView',
        columns: [ foam.core.Model.NAME ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'foam.core.Model',
          daoType: 'ARRAY'
        });
        dao.put(com.google.flow.Box.model_);
        dao.put(com.google.flow.Circle.model_);
        dao.put(com.google.flow.Text.model_);
        dao.put(com.google.flow.Clock.model_);
        dao.put(com.google.flow.Mushroom.model_);
        dao.put(com.google.foam.demos.robot.Robot.model_);
        dao.put(com.google.flow.Desk.model_);
        dao.put(com.google.flow.DuplexDesk.model_);
        dao.put(com.google.flow.Desks.model_);
        dao.put(com.google.flow.Gate.model_);
        dao.put(foam.audio.Speak.model_);
        dao.put(foam.audio.Beep.model_);
        dao.put(com.google.flow.Cursor.model_);
        return dao;
      }
    },
    {
      name: 'value',
      view: { class: 'com.google.flow.ReactiveDetailView', showActions: true }
//      view: { class: 'foam.u2.DetailView', showActions: true }
    },
    {
      name: 'selected',
      postSet: function(o, n) { this.value = n && n.value; }
    },
    {
      name: 'properties',
      view: {
        class: 'foam.u2.view.TreeView',
        relationship: relationship,
        startExpanded: true,
        formatter: function() {
          var X = this.__subSubContext__;
          this.start('span').add(X.data.name).end().
            start('span').nbsp().style({ display: 'inline-block', width: '50px' }).end().
            start('span').add(com.google.flow.Property.DELETE_ROW).end();
        }
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'com.google.flow.Property',
          guid: true,
          seqProperty: this.Property.NAME,
//          daoType: 'MDAO'
          daoType: 'ARRAY'
        });

        var p;

        p = this.Property.create({name: 'canvas1', value: this.canvas});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        p = this.Property.create({name: 'timer', value: this.timer, parent: 'canvas1'});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        p = this.Property.create({name: 'physics', value: this.physics, parent: 'canvas1' });
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        this.scope.canvas1 = this.canvas;
        this.scope.physics = this.physics;
        this.scope.timer   = this.timer;
        this.scope.cycle   = this.timer.cycle.bind(this.timer);

        return dao;
      }
    },
    {
      name: 'canvas',
      factory: function() {
        return this.Box.create({autoRepaint: true, width: 600, height: 600, color: '#f3f3f3'});
//        return this.Box.create({autoRepaint: true, width: 900, height: 870, color: '#f3f3f3'});
      }
    },
    'mouseTarget'
  ],

  methods: [

    function initE() {
      this.timer.start();

      this.properties.on.put.sub(this.onPropertyPut);
      this.properties.on.remove.sub(this.onPropertyRemove);

      var halo = this.Halo.create();
      halo.selected$.linkFrom(this.selected$);

      this.memento$.sub(function() {
        var m = this.memento;
        if ( this.feedback_ ) return;
        this.properties.skip(2).removeAll();
        if ( m ) {
          for ( var i = 0 ; i < m.length ; i++ ) {
            var p = m[i];
            this.addProperty(p.value, p.name, null, p.parent);
          }
        }
        this.selected = null;
      }.bind(this));

      this.
          cssClass(this.myCls()).
          start('div').
            cssClass(this.myCls('tools')).
            start(this.TOOLS, {selection$: this.currentTool$}).end().
          end().
          start('center').
            start(foam.u2.Tabs).
              start(foam.u2.Tab, {label: 'canvas1'}).
                start(this.canvas).
//                  on('click',       this.onClick).
                  on('mousedown',   this.onMouseDown).
                  on('mouseup',     this.onMouseUp).
                  on('mousemove',   this.onMouseMove).
                  on('contextmenu', this.onRightClick).
                end().
              end().
              start(foam.u2.Tab, {label: '+'}).
              end().
            end().
            start(this.BACK,  {label: 'Undo'}).end().
            start(this.FORTH, {label: 'Redo'}).end().
          end().
          start('div').
            cssClass(this.myCls('properties')).
            start(this.PROPERTIES, {selection$: this.selected$}).end().
          end().
          start(this.VALUE).
            cssClass(this.myCls('sheet')).
            show(this.slot(function(selected) { return !!selected; })).
          end();
    },

    function addProperty(value, opt_name, opt_i, opt_parent) {
      var self = this;
      if ( ! opt_name ) {
        var i = opt_i || 1;
        var prefix = value.cls_.name.toLowerCase();
        this.properties.find(prefix + i).then(function (o) {
          self.addProperty(value, null, i+1, opt_parent);
        }).catch(function(x) {
          self.addProperty(value, prefix+i, null, opt_parent);
        });
      } else {
        var p = this.Property.create({
          name: opt_name,
          value: value
        });
        if ( opt_parent ) p.parent = opt_parent;
        value.setPrivate_('lpp_', p);
        this.properties.put(p);
        this.selected = p;
      }
    },

    function updateMemento() {
      this.properties.skip(2).select().then(function(s) {
//        console.log('*************** updateMemento: ', s.a.length);
        this.feedback_ = true;
//        this.memento = foam.Array.clone(s.a);
        this.feedback_ = false;
      }.bind(this));
    }
  ],

  listeners: [
    function onPropertyPut(_, _, _, p) {
      var o = p.value;

      this.scope[p.name] = p.value;
      if ( this.CView.isInstance(o) ) {
        if ( ! p.parent || p.parent === 'canvas1' ) {
          this.canvas.add(o);

          if ( this.Physical.isInstance(o) ) {
            this.physics.add(o);
          }
        } else {
          this.properties.find(p.parent).then(function(p2) {
            // Adjust position of object so that it stays in its current
            // location. TODO: something better with transforms as this
            // probably doesn't work with scaling and rotation.
            var parent = p2.value;
            while ( parent ) {
              o.x -= parent.x;
              o.y -= parent.y;
              parent = parent.parent;
            }

            p2.value.add(o);
          });
        }
      }
    },

    function onPropertyRemove(_, _, _, p) {
      var o = p.value;

      delete this.scope[p.name];

      if ( p === this.selected ) this.selected = null;

      if ( this.CView.isInstance(o) ) {
        if ( ! p.parent ) {
          this.canvas.remove(o);

          if ( this.Physical.isInstance(o) ) {
            this.physics.remove(o);
          }
        } else {
          this.properties.find(p.parent).then(function(p2) {
            p2.value.remove(o);
          });
        }
      }
    },

    function onMouseDown(evt) {
      this.onClick(evt);
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);
      if ( c === this.canvas ) {
        this.mouseTarget = null;
      } else {
        console.log('mouseDown: ', c && c.cls_.name);
        this.mouseTarget = c;
        if ( c && c.onMouseDown ) c.onMouseDown(evt);
      }
    },

    function onMouseUp(evt) {
      this.mouseTarget = null;
    },

    function onMouseMove(evt) {
      if ( this.mouseTarget && this.mouseTarget.onMouseMove ) this.mouseTarget.onMouseMove(evt);
    },

    function onClick(evt) {
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);

      if ( this.Halo.isInstance(c) ) return;

      if ( c === this.canvas ) {
        var tool = this.currentTool;
        if ( ! tool ) return;
        var cls = this.lookup(tool.id);
        var o = cls.create({x: x, y: y}, this.__subContext__);
        var p = this.addProperty(o, null, null, 'canvas1');
        this.updateMemento();
      } else {
        for ( ; c !== this.canvas ; c = c.parent ) {
          var p = c.getPrivate_('lpp_');
          if ( p ) {
            this.selected = p;
            break;
          }
        }
      }
    },

    function onRightClick(evt) {
      evt.preventDefault();
      if ( ! this.selected ) return;
    }
  ]
});
<commit_msg>FLOW: Fix bug wasn't removing from physics.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// TODO: Should have a GUID 'id' instead of name, since now
// you can't have two properties with the same name but
// different parents.
foam.CLASS({
  package: 'com.google.flow',
  name: 'Property',

  ids: [ 'name' ],

  properties: [
    {
      class: 'String',
      name: 'name'
    },
    {
      name: 'value',
      cloneProperty: function(o, m) {
        m[this.name ] = o.cls_.create({
          x:      o.x,
          y:      o.y,
          width:  o.width,
          height: o.height,
          radius: o.radius,
          border: o.radius,
          color:  o.color
        });
      }
    }
  ],
  actions: [
    {
      name: 'deleteRow',
      label: 'X',
      code: function deleteRow(X) {
        X.properties.remove(X.data);
      }
    }
  ]
});

// TODO(adamvy): Remove the need to store this relationship globally.
var relationship = foam.RELATIONSHIP({
  name: 'children',
  inverseName: 'parent',
  cadinality: '1:*',
  sourceModel: 'com.google.flow.Property',
  targetModel: 'com.google.flow.Property',
  targetDAOKey: 'properties'
});

foam.CLASS({
  package: 'com.google.flow',
  name: 'FLOW',
  extends: 'foam.u2.Element',

  implements: [
    'foam.mlang.Expressions',
    'foam.memento.MementoMgr'
  ],

  requires: [
    'com.google.flow.Halo',
    'com.google.flow.Property',
    'foam.dao.EasyDAO',
    'foam.graphics.Box',
    'foam.graphics.CView',
    'foam.graphics.Circle',
    'foam.physics.Physical',
    'foam.physics.PhysicsEngine',
    'foam.u2.PopupView',
    'foam.u2.TableView',
    'foam.util.Timer',
    'foam.u2.view.TreeView',
    'com.google.flow.DetailPropertyView'
  ],

  exports: [
    'timer',
    'as data',
    'properties',
    'scope'
  ],

  axioms: [
    foam.u2.CSS.create({
      code: function() {/*
      body { overflow: hidden; user-select: none; font-family: 'Roboto', sans-serif; color: #444; }
      ^ { display: flex; }
      ^ > * { padding-left: 16px; padding-right: 16px; }
      ^tools, ^properties, ^sheet { box-shadow: 3px 3px 6px 0 gray; height: 100%; }
      ^sheet { width: 100%; overflow-y: auto; }
      ^tools thead, ^properties thead { display: none }
      ^tools tr { height: 30px }
      .foam-u2-TableView { border-collapse: collapse; }
      .foam-u2-TableView td { padding-left: 6px; }
      .foam-u2-TableView-selected { outline: 1px solid red; }
      ^ canvas { border: none; }
      ^ .foam-u2-ActionView { margin: 10px; }
      ^properties .foam-u2-view-TreeViewRow { position: relative; }
      ^properties .foam-u2-ActionView, ^properties .foam-u2-ActionView:hover { background: white; padding: 0; position: absolute; right: 2px; border: none; margin: 6px 0 0 0; }
      .foam-u2-Tabs { padding-top: 0 !important; }
      input[type="range"] { width: 150px; height: 15px; }
      input[type="color"] { width: 22px; }
      */}
    })
  ],

  properties: [
    {
      name: 'scope',
      factory: function() { return {a:42}; },
      documentation: 'Scope to run reactive formulas in.'
    },
    {
      name: 'physics',
      factory: function() {
        return this.PhysicsEngine.create({
          bounceOnWalls: true,
          bounds: this.canvas
        });
      }
    },
    {
      name: 'timer',
      factory: function() {
        return this.Timer.create();
      }
    },
    'feedback_',
    'currentTool',
    {
      class: 'foam.dao.DAOProperty',
      name: 'tools',
      view: {
        class: 'foam.u2.TableView',
        columns: [ foam.core.Model.NAME ]
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'foam.core.Model',
          daoType: 'ARRAY'
        });
        dao.put(com.google.flow.Box.model_);
        dao.put(com.google.flow.Circle.model_);
        dao.put(com.google.flow.Text.model_);
        dao.put(com.google.flow.Clock.model_);
        dao.put(com.google.flow.Mushroom.model_);
        dao.put(com.google.foam.demos.robot.Robot.model_);
        dao.put(com.google.flow.Desk.model_);
        dao.put(com.google.flow.DuplexDesk.model_);
        dao.put(com.google.flow.Desks.model_);
        dao.put(com.google.flow.Gate.model_);
        dao.put(foam.audio.Speak.model_);
        dao.put(foam.audio.Beep.model_);
        dao.put(com.google.flow.Cursor.model_);
        return dao;
      }
    },
    {
      name: 'value',
      view: { class: 'com.google.flow.ReactiveDetailView', showActions: true }
//      view: { class: 'foam.u2.DetailView', showActions: true }
    },
    {
      name: 'selected',
      postSet: function(o, n) { this.value = n && n.value; }
    },
    {
      name: 'properties',
      view: {
        class: 'foam.u2.view.TreeView',
        relationship: relationship,
        startExpanded: true,
        formatter: function() {
          var X = this.__subSubContext__;
          this.start('span').add(X.data.name).end().
            start('span').nbsp().style({ display: 'inline-block', width: '50px' }).end().
            start('span').add(com.google.flow.Property.DELETE_ROW).end();
        }
      },
      factory: function() {
        var dao = foam.dao.EasyDAO.create({
          of: 'com.google.flow.Property',
          guid: true,
          seqProperty: this.Property.NAME,
//          daoType: 'MDAO'
          daoType: 'ARRAY'
        });

        var p;

        p = this.Property.create({name: 'canvas1', value: this.canvas});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        p = this.Property.create({name: 'timer', value: this.timer, parent: 'canvas1'});
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        p = this.Property.create({name: 'physics', value: this.physics, parent: 'canvas1' });
        this.physics.setPrivate_('lpp_', p);
        dao.put(p);

        this.scope.canvas1 = this.canvas;
        this.scope.physics = this.physics;
        this.scope.timer   = this.timer;
        this.scope.cycle   = this.timer.cycle.bind(this.timer);

        return dao;
      }
    },
    {
      name: 'canvas',
      factory: function() {
        return this.Box.create({autoRepaint: true, width: 600, height: 600, color: '#f3f3f3'});
//        return this.Box.create({autoRepaint: true, width: 900, height: 870, color: '#f3f3f3'});
      }
    },
    'mouseTarget'
  ],

  methods: [

    function initE() {
      this.timer.start();

      this.properties.on.put.sub(this.onPropertyPut);
      this.properties.on.remove.sub(this.onPropertyRemove);

      var halo = this.Halo.create();
      halo.selected$.linkFrom(this.selected$);

      this.memento$.sub(function() {
        var m = this.memento;
        if ( this.feedback_ ) return;
        this.properties.skip(2).removeAll();
        if ( m ) {
          for ( var i = 0 ; i < m.length ; i++ ) {
            var p = m[i];
            this.addProperty(p.value, p.name, null, p.parent);
          }
        }
        this.selected = null;
      }.bind(this));

      this.
          cssClass(this.myCls()).
          start('div').
            cssClass(this.myCls('tools')).
            start(this.TOOLS, {selection$: this.currentTool$}).end().
          end().
          start('center').
            start(foam.u2.Tabs).
              start(foam.u2.Tab, {label: 'canvas1'}).
                start(this.canvas).
//                  on('click',       this.onClick).
                  on('mousedown',   this.onMouseDown).
                  on('mouseup',     this.onMouseUp).
                  on('mousemove',   this.onMouseMove).
                  on('contextmenu', this.onRightClick).
                end().
              end().
              start(foam.u2.Tab, {label: '+'}).
              end().
            end().
            start(this.BACK,  {label: 'Undo'}).end().
            start(this.FORTH, {label: 'Redo'}).end().
          end().
          start('div').
            cssClass(this.myCls('properties')).
            start(this.PROPERTIES, {selection$: this.selected$}).end().
          end().
          start(this.VALUE).
            cssClass(this.myCls('sheet')).
            show(this.slot(function(selected) { return !!selected; })).
          end();
    },

    function addProperty(value, opt_name, opt_i, opt_parent) {
      var self = this;
      if ( ! opt_name ) {
        var i = opt_i || 1;
        var prefix = value.cls_.name.toLowerCase();
        this.properties.find(prefix + i).then(function (o) {
          self.addProperty(value, null, i+1, opt_parent);
        }).catch(function(x) {
          self.addProperty(value, prefix+i, null, opt_parent);
        });
      } else {
        var p = this.Property.create({
          name: opt_name,
          value: value
        });
        if ( opt_parent ) p.parent = opt_parent;
        value.setPrivate_('lpp_', p);
        this.properties.put(p);
        this.selected = p;
      }
    },

    function updateMemento() {
      this.properties.skip(2).select().then(function(s) {
//        console.log('*************** updateMemento: ', s.a.length);
        this.feedback_ = true;
//        this.memento = foam.Array.clone(s.a);
        this.feedback_ = false;
      }.bind(this));
    }
  ],

  listeners: [
    function onPropertyPut(_, _, _, p) {
      var o = p.value;

      this.scope[p.name] = p.value;
      if ( this.CView.isInstance(o) ) {
        if ( ! p.parent || p.parent === 'canvas1' ) {
          this.canvas.add(o);

          if ( this.Physical.isInstance(o) ) {
            this.physics.add(o);
          }
        } else {
          this.properties.find(p.parent).then(function(p2) {
            // Adjust position of object so that it stays in its current
            // location. TODO: something better with transforms as this
            // probably doesn't work with scaling and rotation.
            var parent = p2.value;
            while ( parent ) {
              o.x -= parent.x;
              o.y -= parent.y;
              parent = parent.parent;
            }

            p2.value.add(o);
          });
        }
      }
    },

    function onPropertyRemove(_, _, _, p) {
      var o = p.value;

      delete this.scope[p.name];

      if ( p === this.selected ) this.selected = null;

      if ( this.CView.isInstance(o) ) {
        if ( ! p.parent || p.parent === 'canvas1' ) {
          this.canvas.remove(o);

          if ( this.Physical.isInstance(o) ) {
            this.physics.remove(o);
          }
        } else {
          this.properties.find(p.parent).then(function(p2) {
            p2.value.remove(o);
          });
        }
      }
    },

    function onMouseDown(evt) {
      this.onClick(evt);
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);
      if ( c === this.canvas ) {
        this.mouseTarget = null;
      } else {
        console.log('mouseDown: ', c && c.cls_.name);
        this.mouseTarget = c;
        if ( c && c.onMouseDown ) c.onMouseDown(evt);
      }
    },

    function onMouseUp(evt) {
      this.mouseTarget = null;
    },

    function onMouseMove(evt) {
      if ( this.mouseTarget && this.mouseTarget.onMouseMove ) this.mouseTarget.onMouseMove(evt);
    },

    function onClick(evt) {
      var x = evt.offsetX, y = evt.offsetY;
      var c = this.canvas.findFirstChildAt(x, y);

      if ( this.Halo.isInstance(c) ) return;

      if ( c === this.canvas ) {
        var tool = this.currentTool;
        if ( ! tool ) return;
        var cls = this.lookup(tool.id);
        var o = cls.create({x: x, y: y}, this.__subContext__);
        var p = this.addProperty(o, null, null, 'canvas1');
        this.updateMemento();
      } else {
        for ( ; c !== this.canvas ; c = c.parent ) {
          var p = c.getPrivate_('lpp_');
          if ( p ) {
            this.selected = p;
            break;
          }
        }
      }
    },

    function onRightClick(evt) {
      evt.preventDefault();
      if ( ! this.selected ) return;
    }
  ]
});
<|endoftext|>


<commit_before>import { getApiKey, gw2 } from '../gw2'

// shows achievement progress
export function achievement(room, message) {
    const achievementId = message.text.split(' ', 3)[1];

    const users = [{ id: message.fromUser.id, name: message.fromUser.username }];
    message.mentions.forEach(user => users.push({ id: user.userId, name: user.screenName }));

    gw2.achievements().get(achievementId).then(achievement => {
        Promise.all(
            users.map(user => getApiKey(user.id)
                .then(apiKey => gw2.authenticate(apiKey).account().achievements().get(achievementId))
                .then(progress => ({ user, progress }))
                .catch(error => ({ user })))
        ).then(users => {
            room.send(
                `**${achievement.name}**  \n${achievement.description}\n\n`
                + users.map(user =>
                    user.progress
                        ? `@${user.user.name}'s progress: ${user.progress.current}/${user.progress.max}`
                        : `@${user.user.name}'s progress: Missing API key or wrong permissions.`
                ).join('\n  '));
        });
    }).catch(error => room.send(`Oah! Quaggan couldn't connect to the GW2 Api (${error}).`));
}
<commit_msg>use p-map because my server apparently is missing Promise.all<commit_after>import { getApiKey, gw2 } from '../gw2'
import pMap from 'p-map';

// shows achievement progress
export function achievement(room, message) {
    const achievementId = message.text.split(' ', 3)[1];

    const users = [{ id: message.fromUser.id, name: message.fromUser.username }];
    message.mentions.forEach(user => users.push({ id: user.userId, name: user.screenName }));

    gw2.achievements().get(achievementId).then(achievement => {
        pMap(users, user =>
            getApiKey(user.id)
                .then(apiKey => gw2.authenticate(apiKey).account().achievements().get(achievementId))
                .then(progress => ({ user, progress }))
                .catch(error => ({ user }))
        ).then(users => {
            room.send(
                `**${achievement.name}**  \n${achievement.description}\n\n`
                + users.map(user =>
                    user.progress
                        ? `@${user.user.name}'s progress: ${user.progress.current}/${user.progress.max}`
                        : `@${user.user.name}'s progress: Missing API key or wrong permissions.`
                ).join('\n  '));
        });
    }).catch(error => room.send(`Oah! Quaggan couldn't connect to the GW2 Api (${error}).`));
}
<|endoftext|>


<commit_before>const Card = require('../../card/card')
const { Command } = require('discord.js-commando')
const Discord = require('discord.js')

const winston = require('winston')

class FlavorCommand extends Command {
    constructor(client) {
        super(client, {
            name: 'flavor',
            aliases: ['f', 'flavor-text'],
            group: 'card',
            memberName: 'flavor',
            description: 'Displays card text and flavor text.',
            examples: [
                'flavor devolve',
                'f small time recruits'
            ],
            args: [
                {
                    key: 'cardName',
                    prompt: 'what card are you searching for?\n',
                    type: 'string'
                }
            ]
        })
    }

    async run(msg, args) {
        if (msg.channel.type !== 'dm' && !msg.channel.permissionsFor(this.client.user).hasPermission('SEND_MESSAGES')) { return }

        if (!msg.channel.typing) { msg.channel.startTyping() }
        const card = await Card.findByName(args.cardName).catch(winston.error)
        return (card ?
            msg.embed(new Discord.RichEmbed()
                .setTitle(card.name)
                .setDescription(card.description)
                .setURL(card.url)
                .setColor(card.classColor)
                .addField('Text', card.text)
                .addField('Flavor', card.flavor)) :
            msg.reply(`sorry, I couldn't find a card with a name like '${args.cardName}'`)
        ).then(m => { if (m.channel.typing) { m.channel.stopTyping() } })
        .catch(winston.error)
    }
}

module.exports = FlavorCommand
<commit_msg>Check for ability to embed links, use text if not<commit_after>const Card = require('../../card/card')
const { Command } = require('discord.js-commando')
const Discord = require('discord.js')

const winston = require('winston')

class FlavorCommand extends Command {
    constructor(client) {
        super(client, {
            name: 'flavor',
            aliases: ['f', 'flavor-text'],
            group: 'card',
            memberName: 'flavor',
            description: 'Displays card text and flavor text.',
            examples: [
                'flavor devolve',
                'f small time recruits'
            ],
            args: [
                {
                    key: 'cardName',
                    prompt: 'what card are you searching for?\n',
                    type: 'string'
                }
            ]
        })
    }

    async run(msg, args) {
        if (msg.channel.type !== 'dm' && !msg.channel.permissionsFor(this.client.user).hasPermission('SEND_MESSAGES')) { return }

        if (!msg.channel.typing) { msg.channel.startTyping() }
        const card = await Card.findByName(args.cardName).catch(winston.error)
        return (card ?
            msg.embed(new Discord.RichEmbed()
        if (msg.channel.type !== 'dm' && !msg.channel.permissionsFor(this.client.user).hasPermission('EMBED_LINKS')) {
            return msg.say(`**${card.name}**\n${card.description}\n**Text**\n${card.text}\n**Flavor**\n${card.flavor}\n${card.url}`).catch(winston.error)
        }
                .setTitle(card.name)
                .setDescription(card.description)
                .setURL(card.url)
                .setColor(card.classColor)
                .addField('Text', card.text)
                .addField('Flavor', card.flavor)) :
            msg.reply(`sorry, I couldn't find a card with a name like '${args.cardName}'`)
        ).then(m => { if (m.channel.typing) { m.channel.stopTyping() } })
        .catch(winston.error)
    }
}

module.exports = FlavorCommand
<|endoftext|>


<commit_before>import classNames from 'classnames'
import isString from 'lodash/isString'
import React from 'react'
import ReactDOM from 'react-dom'

import Component from '../base-component'
import getPosition from './get-position'
import propTypes from '../prop-types'

import styles from './index.css'

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

let instance

export class TooltipViewer extends Component {
  constructor () {
    super()

    if (instance) {
      throw new Error('Tooltip viewer is a singleton!')
    }
    instance = this
    this.state.place = 'top'
  }

  render () {
    const {
      className,
      content,
      place,
      show,
      style
    } = this.state

    return (

        {content}

    )
  }
}

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

@propTypes({
  children: propTypes.element,
  className: propTypes.string,
  content: propTypes.element,
  style: propTypes.object,
  tagName: propTypes.string
})
export default class Tooltip extends Component {
  componentDidMount () {
    this._addListeners()
  }

  componentWillUnmount () {
    this._removeListeners()
  }

  componentWillReceiveProps (props) {
    if (props.children !== this.props.children) {
      this._removeListeners()
    }
  }

  componentDidUpdate (prevProps) {
    if (prevProps.children !== this.props.children) {
      this._addListeners()
    }
  }

  _addListeners () {
    const node = this._node = ReactDOM.findDOMNode(this)

    node.addEventListener('mouseenter', this._showTooltip)
    node.addEventListener('mouseleave', this._hideTooltip)
    node.addEventListener('mousemove', this._updateTooltip)
  }

  _removeListeners () {
    const node = this._node

    if (!node) {
      return
    }

    node.removeEventListener('mouseenter', this._showTooltip)
    node.removeEventListener('mouseleave', this._hideTooltip)
    node.removeEventListener('mousemove', this._updateTooltip)

    this._node = null
  }

  _showTooltip = () => {
    const { props } = this

    instance.setState({
      className: props.className,
      content: props.content,
      show: true,
      style: props.style
    })
  }

  _hideTooltip = () => {
    instance.setState({ show: false })
  }

  _updateTooltip = event => {
    const node = ReactDOM.findDOMNode(instance)
    const result = getPosition(event, event.currentTarget, node, instance.state.place, 'solid', {})

    if (result.isNewState) {
      return instance.setState(result.newState, () => this._updateTooltip(event))
    }

    const { position } = result
    node.style.left = `${position.left}px`
    node.style.top = `${position.top}px`
  }

  render () {
    const { children } = this.props

    if (!children) {
      return
    }

    if (isString(children)) {
      return {children}
    }

    return children
  }
}
<commit_msg>fix(Tooltip): better PropTypes<commit_after>import classNames from 'classnames'
import isString from 'lodash/isString'
import React from 'react'
import ReactDOM from 'react-dom'

import Component from '../base-component'
import getPosition from './get-position'
import propTypes from '../prop-types'

import styles from './index.css'

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

let instance

export class TooltipViewer extends Component {
  constructor () {
    super()

    if (instance) {
      throw new Error('Tooltip viewer is a singleton!')
    }
    instance = this
    this.state.place = 'top'
  }

  render () {
    const {
      className,
      content,
      place,
      show,
      style
    } = this.state

    return (

        {content}

    )
  }
}

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

@propTypes({
  children: propTypes.oneOfType([
    propTypes.element,
    propTypes.string
  ]),
  className: propTypes.string,
  content: propTypes.node,
  style: propTypes.object,
  tagName: propTypes.string
})
export default class Tooltip extends Component {
  componentDidMount () {
    this._addListeners()
  }

  componentWillUnmount () {
    this._removeListeners()
  }

  componentWillReceiveProps (props) {
    if (props.children !== this.props.children) {
      this._removeListeners()
    }
  }

  componentDidUpdate (prevProps) {
    if (prevProps.children !== this.props.children) {
      this._addListeners()
    }
  }

  _addListeners () {
    const node = this._node = ReactDOM.findDOMNode(this)

    node.addEventListener('mouseenter', this._showTooltip)
    node.addEventListener('mouseleave', this._hideTooltip)
    node.addEventListener('mousemove', this._updateTooltip)
  }

  _removeListeners () {
    const node = this._node

    if (!node) {
      return
    }

    node.removeEventListener('mouseenter', this._showTooltip)
    node.removeEventListener('mouseleave', this._hideTooltip)
    node.removeEventListener('mousemove', this._updateTooltip)

    this._node = null
  }

  _showTooltip = () => {
    const { props } = this

    instance.setState({
      className: props.className,
      content: props.content,
      show: true,
      style: props.style
    })
  }

  _hideTooltip = () => {
    instance.setState({ show: false })
  }

  _updateTooltip = event => {
    const node = ReactDOM.findDOMNode(instance)
    const result = getPosition(event, event.currentTarget, node, instance.state.place, 'solid', {})

    if (result.isNewState) {
      return instance.setState(result.newState, () => this._updateTooltip(event))
    }

    const { position } = result
    node.style.left = `${position.left}px`
    node.style.top = `${position.top}px`
  }

  render () {
    const { children } = this.props

    if (!children) {
      return
    }

    if (isString(children)) {
      return {children}
    }

    return children
  }
}
<|endoftext|>


<commit_before>import { generateLiveApiInstance } from '../../common/appId';
import { getTokenList } from '../../common/utils/storageManager';

const euCountries = [
    'it',
    'de',
    'fr',
    'lu',
    'gr',
    'es',
    'sk',
    'lt',
    'nl',
    'at',
    'bg',
    'si',
    'cy',
    'be',
    'ro',
    'hr',
    'pt',
    'pl',
    'lv',
    'ee',
    'cz',
    'fi',
    'hu',
    'dk',
    'se',
    'ie',
    'gb',
    'mt',
];

export const isEuCountry = country => euCountries.includes(country);

export const isUKCountry = country => country === 'gb';

/* eslint-disable camelcase */
export const moveToDeriv = async () => {
    const api = generateLiveApiInstance();
    console.log('api:', api);
    const { website_status } = await api.send({ website_status: 1 });
    const { clients_country } = website_status;
    const tokenList = getTokenList();
    const landingCompanyName = tokenList.map(token => token.loginInfo.landing_company_name);

    if (!tokenList.length) {
        if (isEuCountry(clients_country) || isUKCountry(clients_country)) {
            window.location.replace('https://binary.com/move-to-deriv');
        }
    }

    if (
        (landingCompanyName.length === 1 &&
            landingCompanyName.includes('virtual') &&
            (isEuCountry(clients_country) || isUKCountry(clients_country))) ||
        landingCompanyName.includes('maltainvest') ||
            landingCompanyName.includes('malta') || landingCompanyName.includes('iom')
    ) {
        window.location.replace('https://binary.com/move-to-deriv');
    }
};
<commit_msg>Added condition<commit_after>import { generateLiveApiInstance } from '../../common/appId';
import { getTokenList } from '../../common/utils/storageManager';

const euCountries = [
    'it',
    'de',
    'fr',
    'lu',
    'gr',
    'es',
    'sk',
    'lt',
    'nl',
    'at',
    'bg',
    'si',
    'cy',
    'be',
    'ro',
    'hr',
    'pt',
    'pl',
    'lv',
    'ee',
    'cz',
    'fi',
    'hu',
    'dk',
    'se',
    'ie',
    'gb',
    'mt',
];

export const isEuCountry = country => euCountries.includes(country);

export const isUKCountry = country => country === 'gb';

/* eslint-disable camelcase */
export const moveToDeriv = async () => {
    const api = generateLiveApiInstance();
    console.log('api:', api);
    const { website_status } = await api.send({ website_status: 1 });
    const { clients_country } = website_status;
    const tokenList = getTokenList();
    const landingCompanyName = tokenList.map(token => token.loginInfo.landing_company_name);

    if (!tokenList.length) {
        if (isEuCountry(clients_country) || isUKCountry(clients_country)) {
            window.location.replace('https://binary.com/move-to-deriv');
        }
    }

    if (
        (landingCompanyName.length === 1 &&
            landingCompanyName.includes('virtual') &&
            (isEuCountry(clients_country) ||
                isUKCountry(clients_country) ||
                isEuCountry(localStorage.getItem('residence')) || isUKCountry(localStorage.getItem('residence')))) ||
        landingCompanyName.includes('maltainvest') ||
            landingCompanyName.includes('malta') ||
            landingCompanyName.includes('iom')
    ) {
        window.location.replace('https://binary.com/move-to-deriv');
    }
};
<|endoftext|>


<commit_before>import events  from './../helpers/Events.js';
import css     from './../helpers/Stylesheets.js';

/**
 * @module Maple
 * @submodule Component
 * @link https://github.com/Wildhoney/Maple.js
 * @author Adam Timberlake
 */
export default class Component {

    /**
     * @constructor
     * @param {Boolean} debug
     * @return {Component}
     */
    constructor(debug) {
        this.components = [];
        this.debug      = debug || false;
    }

    /**
     * @method getImports
     * @return {Array}
     */
    getImports() {

        let importDocuments = document.querySelectorAll('link[rel="import"]');

        return this.toArray(importDocuments).map((importDocument) => {

            return new Promise((resolve, reject) => {
                importDocument.addEventListener('load', event => resolve(event.path[0]));
            });

        });

    }

    /**
     * @method findImport
     * @param {String} className
     * @return {Object}
     */
    findImport(className) {

        return this.linkElements.filter((linkElement) => {

            let regExp = new RegExp(`${className}\/(?:.+?)\.html`, 'i');

            if (linkElement.href.match(regExp)) {
                return true;
            }

        })[0];

    }

    /**
     * @method findScripts
     * @param {Object} importDocument
     * @return {Array}
     */
    findScripts(importDocument) {
        let templateElement = importDocument.querySelector('template');
        return this.toArray(templateElement.content.querySelectorAll('script[type="text/javascript"]'));
    }

    /**
     * @method toArray
     * @param {*} arrayLike
     * @return {Array}
     */
    toArray(arrayLike) {
        return Array.prototype.slice.apply(arrayLike);
    }

    /**
     * @method registerCustomElement
     * @param {String} className
     * @param {Object} component
     * @param {String} modulePath
     * @return {void}
     */
    registerCustomElement(className, component, modulePath) {

        let elementName = className.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
        this.log(`Adding custom element "${elementName}"`);
        let prototype   = Object.create(HTMLElement.prototype, {

            /**
             * @property createdCallback
             * @type {Object}
             */
            createdCallback: {

                /**
                 * @method value
                 * @return {void}
                 */
                value: function value() {

                    this.innerHTML = '';

                    let rendered       = React.createElement(component),
                        contentElement = document.createElement('content'),
                        shadowRoot     = this.createShadowRoot();

                    css.associate(modulePath, shadowRoot);
                    shadowRoot.appendChild(contentElement);
                    events.delegate(contentElement, React.render(rendered, contentElement));

                }

            }

        });

        document.registerElement(elementName, {
            prototype: prototype
        });

    }

    /**
     * @method log
     * @param {String} message
     * @return {void}
     */
    log(message) {

        if (this.debug) {
            console.info(`Maple.js: ${message}.`);
        }

    }

    /**
     * @method delegate
     * @param {Array} modules
     * @return {void}
     */
    register(...modules) {

        Promise.all(this.getImports()).then((linkElements) => {

            this.linkElements = linkElements;

            modules.forEach((name) => {

                name = {
                    camelcase:  name,
                    underscore: name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
                };

                let importDocument = this.findImport(name.underscore),
                    scriptElements = this.findScripts(importDocument.import),
                    modulePath     = importDocument.getAttribute('href').split('/').slice(0, -1).join('/');

                this.log(`Registering module "${name.camelcase}" with path "${modulePath}"`);

                scriptElements.forEach((scriptElement) => {

                    let scriptSrc  = scriptElement.getAttribute('src').split('.').slice(0, -1).join('/'),
                        scriptPath = `${modulePath}/${scriptSrc}`;

                    System.import(scriptPath).then((Component) => {

                        let className = Component.default.toString().match(/(?:function|class)\s*([a-z]+)/i)[1];
                        let component = this.components[className] = Component.default;
                        this.registerCustomElement(className, component, modulePath);

                    });

                });

            });

        });

    }

}<commit_msg>Linting fix<commit_after>import events  from './../helpers/Events.js';
import css     from './../helpers/Stylesheets.js';

/**
 * @module Maple
 * @submodule Component
 * @link https://github.com/Wildhoney/Maple.js
 * @author Adam Timberlake
 */
export default class Component {

    /**
     * @constructor
     * @param {Boolean} debug
     * @return {Component}
     */
    constructor(debug) {
        this.components = [];
        this.debug      = debug || false;
    }

    /**
     * @method getImports
     * @return {Array}
     */
    getImports() {

        let importDocuments = document.querySelectorAll('link[rel="import"]');

        return this.toArray(importDocuments).map((importDocument) => {

            return new Promise((resolve) => {
                importDocument.addEventListener('load', event => resolve(event.path[0]));
            });

        });

    }

    /**
     * @method findImport
     * @param {String} className
     * @return {Object}
     */
    findImport(className) {

        return this.linkElements.filter((linkElement) => {

            let regExp = new RegExp(`${className}\/(?:.+?)\.html`, 'i');

            if (linkElement.href.match(regExp)) {
                return true;
            }

        })[0];

    }

    /**
     * @method findScripts
     * @param {Object} importDocument
     * @return {Array}
     */
    findScripts(importDocument) {
        let templateElement = importDocument.querySelector('template');
        return this.toArray(templateElement.content.querySelectorAll('script[type="text/javascript"]'));
    }

    /**
     * @method toArray
     * @param {*} arrayLike
     * @return {Array}
     */
    toArray(arrayLike) {
        return Array.prototype.slice.apply(arrayLike);
    }

    /**
     * @method registerCustomElement
     * @param {String} className
     * @param {Object} component
     * @param {String} modulePath
     * @return {void}
     */
    registerCustomElement(className, component, modulePath) {

        let elementName = className.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
        this.log(`Adding custom element "${elementName}"`);
        let prototype   = Object.create(HTMLElement.prototype, {

            /**
             * @property createdCallback
             * @type {Object}
             */
            createdCallback: {

                /**
                 * @method value
                 * @return {void}
                 */
                value: function value() {

                    this.innerHTML = '';

                    let rendered       = React.createElement(component),
                        contentElement = document.createElement('content'),
                        shadowRoot     = this.createShadowRoot();

                    css.associate(modulePath, shadowRoot);
                    shadowRoot.appendChild(contentElement);
                    events.delegate(contentElement, React.render(rendered, contentElement));

                }

            }

        });

        document.registerElement(elementName, {
            prototype: prototype
        });

    }

    /**
     * @method log
     * @param {String} message
     * @return {void}
     */
    log(message) {

        if (this.debug) {
            console.info(`Maple.js: ${message}.`);
        }

    }

    /**
     * @method delegate
     * @param {Array} modules
     * @return {void}
     */
    register(...modules) {

        Promise.all(this.getImports()).then((linkElements) => {

            this.linkElements = linkElements;

            modules.forEach((name) => {

                name = {
                    camelcase:  name,
                    underscore: name.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
                };

                let importDocument = this.findImport(name.underscore),
                    scriptElements = this.findScripts(importDocument.import),
                    modulePath     = importDocument.getAttribute('href').split('/').slice(0, -1).join('/');

                this.log(`Registering module "${name.camelcase}" with path "${modulePath}"`);

                scriptElements.forEach((scriptElement) => {

                    let scriptSrc  = scriptElement.getAttribute('src').split('.').slice(0, -1).join('/'),
                        scriptPath = `${modulePath}/${scriptSrc}`;

                    System.import(scriptPath).then((Component) => {

                        let className = Component.default.toString().match(/(?:function|class)\s*([a-z]+)/i)[1];
                        let component = this.components[className] = Component.default;
                        this.registerCustomElement(className, component, modulePath);

                    });

                });

            });

        });

    }

}<|endoftext|>


<commit_before>var ns = {};
var xml2js = require('xml2js');

/*
	guarantees to return an object with given args being set to null if not present, other args returned as is
*/
ns.checkParams = function (params, names) {
	if (typeof params == "undefined" || params == null) {
		params = {};
	}
	if (typeof params != 'object') {
		throw new Error("Bad params. Object with named parameters must be passed.");
	}
	for(var i=0; i < names.length; i++) {
		var argName = names[i];
		if (typeof params[argName] == 'undefined') {
			params[argName] = null;
		}
	}
	return params;
}

ns.getFirstLevelByName = function (xmlObj, localName) {
	var result = [];
	for(var i=0; i<xmlObj.childNodes.length; i++) {
		var child = xmlObj.childNodes[i];
		if (child.localName && child.localName == localName) {
			result.push(child);
		}
	}
	return result;
};

ns.addAttributes = function (jsObj, attributes) {
	jsObj.$ = attributes;
};

ns.parseString = function (string, fn) {
	var parser = new xml2js.Parser({
		//tagNameProcessors: [xml2js.processors.stripPrefix],
		attrValueProcessors: [xml2js.processors.parseNumbers, xml2js.processors.parseBooleans]
	});
	parser.parseString(string, fn);
};

ns.parseStringKeepPrefix = function (string, fn) {
	var parser = new xml2js.Parser({
		attrValueProcessors: [xml2js.processors.parseNumbers, xml2js.processors.parseBooleans]
	});
	parser.parseString(string, fn);
};

ns.buildString = function (obj) {
	var xmlString =  new xml2js.Builder({
		headless: true,
		renderOpts: {pretty: false}
	}).buildObject(obj);

	/* 	dirty hack needed to solve the newline char encoding problem
		xml2js doesn't encode \n as
 we need to do it manually
	*/
	var re = /<label text="((.|\n+)+?)"/gm;
	var xmlString_correctLabel = xmlString.replace(re, function(match, p1, p2) {
		return '<label text="'+p1.replace(/\n/g, "
")+'"';
	});
	return xmlString_correctLabel;
};

module.exports = ns;<commit_msg>discard tagname prefixes only for standard sbgn<commit_after>var ns = {};
var xml2js = require('xml2js');

/*
	guarantees to return an object with given args being set to null if not present, other args returned as is
*/
ns.checkParams = function (params, names) {
	if (typeof params == "undefined" || params == null) {
		params = {};
	}
	if (typeof params != 'object') {
		throw new Error("Bad params. Object with named parameters must be passed.");
	}
	for(var i=0; i < names.length; i++) {
		var argName = names[i];
		if (typeof params[argName] == 'undefined') {
			params[argName] = null;
		}
	}
	return params;
}

ns.getFirstLevelByName = function (xmlObj, localName) {
	var result = [];
	for(var i=0; i<xmlObj.childNodes.length; i++) {
		var child = xmlObj.childNodes[i];
		if (child.localName && child.localName == localName) {
			result.push(child);
		}
	}
	return result;
};

ns.addAttributes = function (jsObj, attributes) {
	jsObj.$ = attributes;
};

ns.parseString = function (string, fn) {
	var parser = new xml2js.Parser({
		tagNameProcessors: [ns.removePrefixForSbgnTags],
		attrValueProcessors: [xml2js.processors.parseNumbers, xml2js.processors.parseBooleans]
	});
	parser.parseString(string, fn);
};

ns.removePrefixForSbgnTags = function (name){
	var sbgnTags = new Set([
		"arc",
		"arcgroup",
		"bbox",
		"callout",
		"clone",
		"end",
		"entity",
		"extension",
		"glyph",
		"label",
		"map",
		"next",
		"notes",
		"point",
		"port",
		"sbgn",
		"start",
		"sate"
	]);

	if(name.indexOf(":") !== -1) { // some prefix found
		var tmp = name.split(":");
		var tagName = tmp[tmp.length - 1];
		if(sbgnTags.has(tagName)) {
			// this is a standard sbgn element, we don't want a prefix
			return tagName;
		}
	}
	return name;
}

ns.parseStringKeepPrefix = function (string, fn) {
	var parser = new xml2js.Parser({
		attrValueProcessors: [xml2js.processors.parseNumbers, xml2js.processors.parseBooleans]
	});
	parser.parseString(string, fn);
};

ns.buildString = function (obj) {
	var xmlString =  new xml2js.Builder({
		headless: true,
		renderOpts: {pretty: false}
	}).buildObject(obj);

	/* 	dirty hack needed to solve the newline char encoding problem
		xml2js doesn't encode \n as
 we need to do it manually
	*/
	var re = /<label text="((.|\n+)+?)"/gm;
	var xmlString_correctLabel = xmlString.replace(re, function(match, p1, p2) {
		return '<label text="'+p1.replace(/\n/g, "
")+'"';
	});
	return xmlString_correctLabel;
};

module.exports = ns;<|endoftext|>