<commit_before>"use strict";
/*global alert: true, ODSA */
/*global sweep */
(function ($) {
  var comp = function(a, b) {
    return a - b;
  };

  var Bintree = function (jsav, xrange, yrange) {

    // Enum for the node type
    // stored in node.NodeType
    var NT = {
      INTERNAL : 0,
      EMPTYEXT : 1,
      FULLEXT  : 2
    };

    // This is the JSAV base data structure, a binary tree.
    this.tree = jsav.ds.binarytree({nodegap: 10});
    // This is the root of the tree
    this.root = this.tree.root('');

    console.log("I'm making a new Bintree object. root = ", this.root);
    // Set the root as an empty node
    this.root.NodeType = NT.EMPTYEXT;

    // Don't forget to refresh the tree layout
    this.tree.layout();

    // Getter function for the root
    this.getRoot = function () {
      console.log("getRoot: ", this.root);
      return this.root;
    };

    // Tests to see if the tree is empty
    this.isEmpty = function () {
      var returning = (this.root.NodeType === NT.EMPTYEXT);
      console.log("Bintree isEmpty test: ", returning);
      return (returning);
    };

    // Helper function for creating a new internal node

    this.newInteralNode = function() {
      var ret = this.tree.newNode('');
      ret.NodeType = NT.INTERNAL;
      return ret;
    }

    this.newEmptyExtNode = function() {
      var ret = this.tree.newNode('');
      ret.NodeType = NT.EMPTYEXT;
      return ret;
    }

    // calling function for insertion
    this.add = function(INx, INy, INrec, Bx, By, Bwid, Bhgt, level) {
      this.root = this.insert(this.root, INx, INy, INrec, Bx, By, Bwid, Bhgt, level);
      this.tree.layout();
    }

    // returns a node!
    this.insert = function(rt, INx, INy, INrec, Bx, By, Bwid, Bhgt, level) {

      jsav.step();
      this.tree.layout();
      console.log("Bintree insert: BEGIN: ", INrec, ", Level: ", level, ", rt Type: ", rt.NodeType);

      if (rt.NodeType === NT.EMPTYEXT) {
        console.log("insert: encountered empty leaf node: insert data and return")
        jsav.umsg("Insert: Encountered an empty leaf node: Now insert data and return!");
        console.log("Bintree insert: (LEAF) Value = ", INrec);

        var temp = this.tree.newNode(INrec);

        temp.x = INx;
        temp.y = INy;

        temp.NodeType = NT.FULLEXT;
        return temp;
      }

      // If the entry is a full leaf
      if (rt.NodeType === NT.FULLEXT) {
        console.log("insert: is a leaf and not empty: ", INrec, rt);

        // Create the new nodes and set them as
        var tp = this.newInteralNode();
        var tpl = this.newEmptyExtNode();
        var tpr = this.newEmptyExtNode();
        tp.left(tpl);
        tp.right(tpr);

        // DEBUG
        console.log("tp: " + tp.NodeType + "| left: " + tp.left().NodeType + "| right: " + tp.right().NodeType);

        // Insert the old data
        tp = this.insert(tp, rt.x, rt.y, rt.value(), Bx, By, Bwid, Bhgt, level);

        // Insert new data
        tp = this.insert(tp, INx, INy, INrec, Bx, By, Bwid, Bhgt, level);

        // Debug line
        console.log("Finished inserting data for the leaf subtree");

        this.tree.layout();

        // Return the new subtree to replace the leaf node
        return tp;
      }

      // If it isn't a leaf, then we have an internal node to insert into
      if (level % 2 == 0) // Branch on X
      {
        if (rt.x < (Bx + Bwid/2)) // Insert left
        {

          console.log("Branch on X, Insert Left: ", rt.left().NodeType);
          jsav.umsg("Branch on X, Insert Left");
          rt.left(this.insert(rt.left(), INx, INy, INrec, Bx, By, Bwid/2, Bhgt, level+1));
        }
        else
        {

          console.log("Branch on X, Insert Right: ", rt.right().NodeType);
          jsav.umsg("Branch on X, Insert Right");
          rt.right(this.insert(rt.right(), INx, INy, INrec, Bx + Bwid/2, By, Bwid/2, Bhgt, level+1));
        }
      }

      else // Branch on Y
      {
        if (rt.y < (By + Bhgt/2)) // Insert left
        {

          console.log("Branch on Y, Insert Left: ", rt.left().NodeType);
          jsav.umsg("Branch on Y, Insert Left");
          rt.left(this.insert(rt.left(), INx, INy, INrec, Bx, By, Bwid, Bhgt/2, level+1));
        }
        else
        {

          console.log("Branch on Y, Insert Right: ", rt.right().NodeType);
          jsav.umsg("Branch on Y, Insert Right");
          rt.right(this.insert(rt.right(), INx, INy, INrec, Bx, By + Bhgt/2, Bwid, Bhgt/2, level+1));
        }
      }

      this.tree.layout();
      return rt;
    } // insert

    this.delete = function (rt, INx, INy, Bx, By, Bwid, Bhgt, level) {
      console.assert( !(rt.leaf == true && rt.empty == true), "Cannot be an empty leaf during delete");

      if (rt.leaf) {
        if (rt.x == INx && rt.y == INy)
        {
          var temp = tree.newNode('');
          temp.leaf = true;
          temp.empty = true;
          return temp;
        }
        // else ERROR: THIS IS IMPOSSIBLE;
      };

      // We have an internal node
      if (level % 2 == 0) // Branch on X
      {
        if (INx < (Bx + Bwid/2)) // delete left
        {
          console.log("Branch on X, Delete Left");
          rt.left(delete(rt.left(), INx, INy, Bx, By, Bwid/2, Bhgt, level+1));
        }
        else
        {
          console.log("Branch on X, Delete Right");
          rt.right(delete(rt.right(), INx, INy, Bx + Bwid/2, By, Bwid/2, Bhgt, level+1));
        }
      }

      else // Branch on Y
      {
        if (INy < (By + Bhgt/2)) // Insert left
        {
          rt.left(delete(rt.left(), INx, INy, Bx, By, Bwid, Bhgt/2, level+1));
        }
        else
          rt.right(delete(rt.right(), INx, INy, Bx, By + Bhgt/2, Bwid, Bhgt/2, level+1));
      }

      tree.layout();

      // Now, check to see if there should be a merge
      if ((rt.left().leaf == true && rt.left().empty == true) && (rt.right().leaf))
      {
        return rt.right();
      }
      if ((rt.left().leaf) && (rt.right().leaf && rt.left.empty))
      {
        return rt.left();
      }

      // Otherwise, return just the rt subtree without a merge
      return rt;

    } // delete

  } // bintree

  var arr;

  // check query parameters from URL
  var params = JSAV.utils.getQueryParameter();
  if ("increments" in params) { // set value of increments if it is a param
    $('#increments').val(params.increments).prop("disabled", true);
  }

  // create a new settings panel and specify the link to show it
  var settings = new JSAV.utils.Settings($(".jsavsettings"));
  // add the layout setting preference
  var arrayLayout = settings.add("layout",
    {"type": "select", "options": {"bar": "Bar", "array": "Array"},
     "label": "Array layout: ", "value": "bar"});

  // Initialize the arraysize dropdown list
  ODSA.AV.initArraySize(5, 16, 8);

  // Process help button: Give a full help page for this activity
  // We might give them another HTML page to look at.
  function help() {
    window.open("bintreeHelpAV.html", 'helpwindow');
  }

  // Process About button: Pop up a message with an Alert
  function about() {
    alert("Bintree Visualization\nWritten by Anthony Rinaldi and Cliff Shaffer\nCreated as part of the OpenDSA hypertextbook project\nFor more information, see http://algoviz.org/OpenDSA\nSource and development history available at\nhttps://github.com/cashaffer/OpenDSA\nCompiled with JSAV library version " + JSAV.version());
  }

  // Execute the "Run" button function
  function runIt() {

    ODSA.AV.reset(true);

    var jsav = new JSAV($('.avcontainer'));

    jsav.umsg("Let's get started");
    console.log("Setup the Bintree");
    var bint = new Bintree(jsav, 200, 200);
    console.log("I just made a new Bintree, and bint.root is: ", bint.getRoot());
    bint.isEmpty();
    jsav.displayInit();

    jsav.step();

    // Setup the tree
    jsav.umsg("Step 1: insert node with value \"A\" @ 100, 100");

    // rt, INx, INy, INrec, Bx, By, Bwid, Bhgt, level
    console.log("Let's call insert. bint.root is now: ", bint.getRoot());
    bint.add(100, 100, "A", 100, 100, 200, 200, 0);
    bint.isEmpty();

    jsav.step();

    // Insert another object
    jsav.umsg("Step 2: insert node with value \"B\" @ 50, 50");
    // rt, INx, INy, INrec, Bx, By, Bwid, Bhgt, level
    console.log("Let's call insert. bint.root is now: ", bint.getRoot());
    bint.add(50, 50, "B", 100, 100, 200, 200, 0);

    jsav.step();

    jsav.umsg("Step 2: insert node with value \"C\" @ 175, 175");
    //bint.add(175, 175, "C", 100, 100, 200, 200, 0);

    jsav.step();

  // Done
    jsav.umsg("All Done!");

    jsav.recorded(); // mark the end

  }

  // Connect action callbacks to the HTML entities
  $('#help').click(help);
  $('#about').click(about);
  $('#run').click(runIt);
  $('#reset').click(ODSA.AV.reset);

}(jQuery));<commit_msg>Fixed recursion problem in bintreeAV<commit_after>"use strict";
/*global alert: true, ODSA */
/*global sweep */
(function ($) {
  var comp = function(a, b) {
    return a - b;
  };

  var Bintree = function (jsav, xrange, yrange) {

    // Enum for the node type
    // stored in node.NodeType
    var NT = {
      INTERNAL : 0,
      EMPTYEXT : 1,
      FULLEXT  : 2
    };

    // This is the JSAV base data structure, a binary tree.
    this.tree = jsav.ds.binarytree({nodegap: 10});
    // This is the root of the tree
    this.tree.root('');

    console.log("I'm making a new Bintree object. root = ", this.tree.root());
    // Set the root as an empty node
    this.tree.root().NodeType = NT.EMPTYEXT;

    // Don't forget to refresh the tree layout
    this.tree.layout();

    // Getter function for the root
    this.getRoot = function () {
      console.log("getRoot: ", this.tree.root());
      return this.tree.root();
    };

    // Tests to see if the tree is empty
    this.isEmpty = function () {
      var returning = (this.tree.root().NodeType === NT.EMPTYEXT);
      console.log("Bintree isEmpty test: ", returning);
      return (returning);
    };

    // Helper function for creating a new internal node

    this.newInteralNode = function() {
      var ret = this.tree.newNode('');
      ret.NodeType = NT.INTERNAL;
      return ret;
    }

    this.newEmptyExtNode = function() {
      var ret = this.tree.newNode('');
      ret.NodeType = NT.EMPTYEXT;
      return ret;
    }

    // calling function for insertion
    this.add = function(INx, INy, INrec) {
      this.tree.root(this.insert(this.tree.root(), INx, INy, INrec, 0, 0, xrange, yrange, 0));
      this.tree.layout();
    }

    // returns a node!
    this.insert = function(rt, INx, INy, INrec, Bx, By, Bwid, Bhgt, level) {

      jsav.step();
      this.tree.layout();
      console.log("Bintree insert: BEGIN: ", INrec, ", Level: ", level, ", rt Type: ", rt.NodeType);

      if (rt.NodeType === NT.EMPTYEXT) {
        console.log("insert: encountered empty leaf node: insert data and return")
        jsav.umsg("Insert: Encountered an empty leaf node: Now insert data and return!");
        console.log("Bintree insert: (LEAF) Value = ", INrec);

        //var strtmp = INrec  + "|" + INx + "|" + INys;

        var temp = this.tree.newNode(INrec);

        temp.x = INx;
        temp.y = INy;

        temp.NodeType = NT.FULLEXT;
        return temp;
      }

      // If the entry is a full leaf
      if (rt.NodeType === NT.FULLEXT) {
        console.log("insert: is a leaf and not empty: ", INrec, rt);

        // Create the new nodes and set them as
        var tp = this.newInteralNode();
        var tpl = this.newEmptyExtNode();
        var tpr = this.newEmptyExtNode();
        tp.left(tpl);
        tp.right(tpr);

        // DEBUG
        console.log("tp: " + tp.NodeType + "| left: " + tp.left().NodeType + "| right: " + tp.right().NodeType);

        // Insert new data
        tp = this.insert(tp, INx, INy, INrec, Bx, By, Bwid, Bhgt, level);

        // Insert the old data
        if (tp.left().NodeType === NT.EMPTYEXT)
        {
          // Insert the old data to the left
          tp.left(this.insert(tp.left(), rt.x, rt.y, rt.value(), Bx, By, Bwid, Bhgt, level+1));
        }
        else
        {
          // Insert the old data to the right
          tp.right(this.insert(tp.right(), rt.x, rt.y, rt.value(), Bx, By, Bwid, Bhgt, level+1));
        }

        // Debug line
        console.log("Finished inserting data for the leaf subtree");

        this.tree.layout();

        // Return the new subtree to replace the leaf node
        return tp;
      }

      // If it isn't a leaf, then we have an internal node to insert into
      if (level % 2 == 0) // Branch on X
      {
        if (rt.x < (Bx + Bwid/2)) // Insert left
        {

          console.log("Branch on X, Insert Left: ", rt.left().NodeType);
          jsav.umsg("Branch on X, Insert Left");
          rt.left(this.insert(rt.left(), INx, INy, INrec, Bx, By, Bwid/2, Bhgt, level+1));
        }
        else
        {

          console.log("Branch on X, Insert Right: ", rt.right().NodeType);
          jsav.umsg("Branch on X, Insert Right");
          rt.right(this.insert(rt.right(), INx, INy, INrec, Bx + Bwid/2, By, Bwid/2, Bhgt, level+1));
        }
      }

      else // Branch on Y
      {
        if (rt.y < (By + Bhgt/2)) // Insert left
        {

          console.log("Branch on Y, Insert Left: ", rt.left().NodeType);
          jsav.umsg("Branch on Y, Insert Left");
          rt.left(this.insert(rt.left(), INx, INy, INrec, Bx, By, Bwid, Bhgt/2, level+1));
        }
        else
        {

          console.log("Branch on Y, Insert Right: ", rt.right().NodeType);
          jsav.umsg("Branch on Y, Insert Right");
          rt.right(this.insert(rt.right(), INx, INy, INrec, Bx, By + Bhgt/2, Bwid, Bhgt/2, level+1));
        }
      }

      this.tree.layout();
      return rt;
    } // insert

  } // bintree

  var arr;

  // check query parameters from URL
  var params = JSAV.utils.getQueryParameter();
  if ("increments" in params) { // set value of increments if it is a param
    $('#increments').val(params.increments).prop("disabled", true);
  }

  // create a new settings panel and specify the link to show it
  var settings = new JSAV.utils.Settings($(".jsavsettings"));
  // add the layout setting preference
  var arrayLayout = settings.add("layout",
    {"type": "select", "options": {"bar": "Bar", "array": "Array"},
     "label": "Array layout: ", "value": "bar"});

  // Initialize the arraysize dropdown list
  ODSA.AV.initArraySize(5, 16, 8);

  // Process help button: Give a full help page for this activity
  // We might give them another HTML page to look at.
  function help() {
    window.open("bintreeHelpAV.html", 'helpwindow');
  }

  // Process About button: Pop up a message with an Alert
  function about() {
    alert("Bintree Visualization\nWritten by Anthony Rinaldi and Cliff Shaffer\nCreated as part of the OpenDSA hypertextbook project\nFor more information, see http://algoviz.org/OpenDSA\nSource and development history available at\nhttps://github.com/cashaffer/OpenDSA\nCompiled with JSAV library version " + JSAV.version());
  }

  // Execute the "Run" button function
  function runIt() {

    ODSA.AV.reset(true);

    var jsav = new JSAV($('.avcontainer'));

    jsav.umsg("Let's get started");
    console.log("Setup the Bintree");
    var bint = new Bintree(jsav, 200, 200);
    console.log("I just made a new Bintree, and bint.root is: ", bint.getRoot());
    bint.isEmpty();
    jsav.displayInit();

    jsav.step();

    // Setup the tree
    jsav.umsg("Step 1: insert node with value \"A\" @ 125, 125");

    // rt, INx, INy, INrec, Bx, By, Bwid, Bhgt, level
    console.log("Let's call insert. bint.root is now: ", bint.getRoot());
    bint.add(125, 125, "A");
    bint.isEmpty();

    jsav.step();

    // Insert another object
    jsav.umsg("Step 2: insert node with value \"B\" @ 50, 50");
    // rt, INx, INy, INrec, Bx, By, Bwid, Bhgt, level
    console.log("Let's call insert. bint.root is now: ", bint.getRoot());
    bint.add(50, 50, "B");

    jsav.step();

    jsav.umsg("Step 2: insert node with value \"C\" @ 175, 175");
    bint.add(175, 175, "C");

    jsav.step();

  // Done
    jsav.umsg("All Done!");

    jsav.recorded(); // mark the end

  }

  // Connect action callbacks to the HTML entities
  $('#help').click(help);
  $('#about').click(about);
  $('#run').click(runIt);
  $('#reset').click(ODSA.AV.reset);

}(jQuery));<|endoftext|>


<commit_before>var browsers = []
  , inifile = "./browscap.ini"

exports.setIni = function(filename) {
  inifile = filename

  // Re-parse if parsed before
  if (browsers.length) {
    browsers = parse(filename)
  }
}

function parse(filename) {
  var current = {}
    , browserArray = []
    , patternIndex = []

  require('fs')
    .readFileSync(filename, 'ascii')
    .split(/[\r\n]+/)
    .forEach(function(line) {
      // Skip comments and blank lines
      if (/^\s*(;|$)/.test(line)) {
        return
      }

      if (line[0] == '[') {
        var pattern = line.slice(1, -1)

        // Convert the pattern into a proper regex
        current = {
          __regex__: new RegExp('^'
            + pattern.replace(/\./g, '\\.')
                     .replace(/\(/g, '\\(')
                     .replace(/\)/g, '\\)')
                     .replace(/\//g, '\\/')
                     .replace(/\-/g, '\\-')
                     .replace(/\*/g, '.*')
                     .replace(/\?/g, '.?')
            + '$')
        }

        browserArray.push(current) // Push new browser object onto array
        patternIndex.push(pattern) // Push pattern onto pattern index
      } else {
        var parts = line.split('=')
          , name = parts[0]
          , value = parts[1]

        if (name == 'Browser' && value[0] == '"' && value.slice(-1) == '"') {
          value = value.slice(1, -1)
        }

        if (name != 'Parent') {
          current[name] = value
        } else {
          // Copy properties from the parent's entry
          var i = patternIndex.indexOf(value)
          for (var key in browserArray[i]) {
            if (key != '__regex__' && key != 'Parent') {
              current[key] = browserArray[i][key]
            }
          }
        }
      }
    })

  return browserArray
}

exports.getBrowser = function(userAgent) {
  if (!browsers.length) {
    browsers = parse(inifile)
  }

  // Test user agent against each browser regex
  for (var i = 0; i < browsers.length; i++) {
    if (browsers[i].__regex__.test(userAgent)) {
      return browsers[i]
    }
  }
}
<commit_msg>minor double quotes fix. should be all nice and sexy now<commit_after>var browsers = []
  , inifile = './browscap.ini'

exports.setIni = function(filename) {
  inifile = filename

  // Re-parse if parsed before
  if (browsers.length) {
    browsers = parse(filename)
  }
}

function parse(filename) {
  var current = {}
    , browserArray = []
    , patternIndex = []

  require('fs')
    .readFileSync(filename, 'ascii')
    .split(/[\r\n]+/)
    .forEach(function(line) {
      // Skip comments and blank lines
      if (/^\s*(;|$)/.test(line)) {
        return
      }

      if (line[0] == '[') {
        var pattern = line.slice(1, -1)

        // Convert the pattern into a proper regex
        current = {
          __regex__: new RegExp('^'
            + pattern.replace(/\./g, '\\.')
                     .replace(/\(/g, '\\(')
                     .replace(/\)/g, '\\)')
                     .replace(/\//g, '\\/')
                     .replace(/\-/g, '\\-')
                     .replace(/\*/g, '.*')
                     .replace(/\?/g, '.?')
            + '$')
        }

        browserArray.push(current) // Push new browser object onto array
        patternIndex.push(pattern) // Push pattern onto pattern index
      } else {
        var parts = line.split('=')
          , name = parts[0]
          , value = parts[1]

        if (name == 'Browser' && value[0] == '"' && value.slice(-1) == '"') {
          value = value.slice(1, -1)
        }

        if (name != 'Parent') {
          current[name] = value
        } else {
          // Copy properties from the parent's entry
          var i = patternIndex.indexOf(value)
          for (var key in browserArray[i]) {
            if (key != '__regex__' && key != 'Parent') {
              current[key] = browserArray[i][key]
            }
          }
        }
      }
    })

  return browserArray
}

exports.getBrowser = function(userAgent) {
  if (!browsers.length) {
    browsers = parse(inifile)
  }

  // Test user agent against each browser regex
  for (var i = 0; i < browsers.length; i++) {
    if (browsers[i].__regex__.test(userAgent)) {
      return browsers[i]
    }
  }
}
<|endoftext|>


<commit_before>/*
Copyright 2012 Twitter, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * This module defines the Graph view which generates horizontal DAG view of Workflow jobs.
 */
define(['jquery', 'd3', 'colorbrewer', '../core', './core'], function(
  $, d3, colorbrewer, Ambrose, Views
) {
  // Graph ctor
  var Graph = Views.Graph = function(workflow, container, params) {
    return new Views.Graph.fn.init(workflow, container, params);
  }

  /**
   * Graph prototype.
   */
  Graph.fn = Graph.prototype = {
    /**
     * Constructor.
     *
     * @param workflow the Workflow instance to bind to.
     * @param container the DOM element in which to render the view.
     * @param params extra parameters.
     */
    init: function(workflow, container, params) {
      var self = this;
      this.workflow = workflow;
      this.container = container = $(container);

      // define default params and override with user supplied params
      var params = this.params = $.extend(true, {
        colors: {
          running: d3.rgb(98, 196, 98),
          selected: d3.rgb(98, 98, 196),
          mouseover: d3.rgb(98, 98, 196).brighter(),
        },
        palettes: {
          queued: colorbrewer.Greys,
          complete: colorbrewer.Greens,
          failed: colorbrewer.Reds,
        },
        dimensions: {
          padding: 20,
        },
      }, params);

      this.resetView();

      // bind event workflow handlers
      workflow.on('jobsLoaded', function(event, jobs) {
        self.handleJobsLoaded(jobs);
      });
      workflow.on('jobStarted jobProgress jobCompleted jobFailed', function(event, job) {
        self.handleJobsUpdated([job], 350);
      });
      workflow.on('jobSelected jobMouseOver', function(event, job, prev) {
        self.handleJobsUpdated($.grep([prev, job], Ambrose.notNull));
      });
    },

    resetView: function() {
      // initialize dimensions
      var container = this.container;
      var dim = this.dimensions = {};
      var width = dim.width = container.width();
      var height = dim.height = container.height();
      var padding = this.params.dimensions.padding;

      // create canvas and supporting d3 objects
      this.svg = d3.select(container.empty().get(0))
        .append('svg:svg')
        .attr('width', width)
        .attr('height', height);
      var xs = this.xs = d3.scale.linear().range([0, width]);
      var ys = this.ys = d3.scale.linear().range([0, height]);
      this.projection = function(d) { return [xs(d.x), ys(d.y)]; };
    },

    handleJobsLoaded: function(jobs) {
      // compute node x,y coords
      var graph = this.workflow.graph;
      var groups = graph.topologicalGroups;
      var groupCount = groups.length;
      var groupDelta = 1 / groupCount;
      var groupOffset = groupDelta / 2;
      // var edges = this.edges = [];
      $.each(groups, function(i, group) {
        var x = i * groupDelta + groupOffset;
        var nodeCount = group.length;
        var nodeDelta = 1 / nodeCount;
        var nodeOffset = nodeDelta / 2;
        $.each(group, function(j, node) {
          node.x = x;
          node.y = j * nodeDelta + nodeOffset;
          var edges = node.edges = [];
          $.each(node.parents || [], function(p, parent) {
            edges.push({ source: node, target: parent });
          });
        });
      });

      var g = this.selectNodeGroups(jobs);
      this.removeNodeGroups(g);
      this.createNodeGroups(g);
      this.updateNodeGroups(g);
    },

    handleJobsUpdated: function(jobs, duration) {
      this.updateNodeGroups(this.selectNodeGroups(jobs), duration);
    },

    selectNodeGroups: function(jobs) {
      var nodes = $.map(jobs, function(job) { return job.node; });
      return this.svg.selectAll('g.node').data(nodes, function(node) { return node.id; });
    },

    removeNodeGroups: function(g) {
      g.exit().remove();
    },

    createNodeGroups: function(g) {
      var self = this;
      var xs = this.xs;
      var ys = this.ys;
      var projection = this.projection;
      g = g.enter().append('svg:g').attr('class', 'node');
      g.each(function(node, i) {
        d3.select(this).selectAll('path.edge').data(node.edges).enter()
          .append('svg:path').attr('class', 'edge')
          .attr('d', function diagonal(edge, i) {
            var p0 = edge.source,
            p3 = edge.target,
            m = (p0.x + p3.x) / 2,
            p = [p0, {x: m, y: p0.y}, {x: m, y: p3.y}, p3],
            p = p.map(projection);
            return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
          });
      });
      g.append('svg:circle')
        .attr('cx', function(d) { return xs(d.x); })
        .attr('cy', function(d) { return ys(d.y); })
        .attr('r', 8);
    },

    updateNodeGroups: function(g, duration) {},

  };

  // bind prototype to ctor
  Graph.fn.init.prototype = Graph.fn;
  return Graph;
});
<commit_msg>Makes graph view awesome<commit_after>/*
Copyright 2012 Twitter, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * This module defines the Graph view which generates horizontal DAG view of Workflow jobs.
 */
define(['jquery', 'd3', 'colorbrewer', '../core', './core'], function(
  $, d3, colorbrewer, Ambrose, Views
) {
  // utility functions
  function isPseudo(node) { return node.pseudo; }
  function isReal(node) { return !(node.pseudo); };

  // Graph ctor
  var Graph = Views.Graph = function(workflow, container, params) {
    return new Views.Graph.fn.init(workflow, container, params);
  }

  /**
   * Graph prototype.
   */
  Graph.fn = Graph.prototype = {
    /**
     * Constructor.
     *
     * @param workflow the Workflow instance to bind to.
     * @param container the DOM element in which to render the view.
     * @param params extra parameters.
     */
    init: function(workflow, container, params) {
      var self = this;
      this.workflow = workflow;
      this.container = container = $(container);

      // define default params and override with user supplied params
      var params = this.params = $.extend(true, {
        colors: {
          running: d3.rgb(98, 196, 98).brighter(),
          complete: d3.rgb(98, 196, 98),
          failed: d3.rgb(196, 98, 98),
          mouseover: d3.rgb(98, 98, 196).brighter(),
          selected: d3.rgb(98, 98, 196),
        },
        palettes: {
          queued: colorbrewer.Greys,
          complete: colorbrewer.Greens,
          failed: colorbrewer.Reds,
        },
        dimensions: {
          padding: 20,
        },
      }, params);

      this.resetView();

      // bind event workflow handlers
      workflow.on('jobsLoaded', function(event, jobs) {
        self.handleJobsLoaded(jobs);
      });
      workflow.on('jobStarted jobProgress jobCompleted jobFailed', function(event, job) {
        self.handleJobsUpdated([job], 350);
      });
      workflow.on('jobSelected jobMouseOver', function(event, job, prev) {
        self.handleJobsUpdated($.grep([prev, job], Ambrose.notNull));
      });
    },

    resetView: function() {
      // initialize dimensions
      var container = this.container;
      var dim = this.dimensions = {};
      var width = dim.width = container.width();
      var height = dim.height = container.height();
      var padding = this.params.dimensions.padding;

      // create canvas and supporting d3 objects
      this.svg = d3.select(container.empty().get(0))
        .append('svg:svg')
        .attr('width', width)
        .attr('height', height);
      var xs = this.xs = d3.scale.linear().range([0, width]);
      var ys = this.ys = d3.scale.linear().range([0, height]);
      this.projection = function(d) { return [xs(d.x), ys(d.y)]; };
    },

    handleJobsLoaded: function(jobs) {
      // compute node x,y coords
      var graph = this.workflow.graph;
      var groups = graph.topologicalGroups;
      var groupCount = groups.length;
      var groupDelta = 1 / groupCount;
      var groupOffset = groupDelta / 2;
      // var edges = this.edges = [];
      $.each(groups, function(i, group) {
        var x = i * groupDelta + groupOffset;
        var nodeCount = group.length;
        var nodeDelta = 1 / nodeCount;
        var nodeOffset = nodeDelta / 2;
        $.each(group, function(j, node) {
          node.x = x;
          node.y = j * nodeDelta + nodeOffset;
          var edges = node.edges = [];
          $.each(node.parents || [], function(p, parent) {
            edges.push({ source: node, target: parent });
          });
        });
      });

      var graph = this.workflow.graph;
      var nodes = graph.nodes.concat(graph.pseudoNodes).sort(function(a, b) {
        return b.topologicalGroupIndex - a.topologicalGroupIndex;
      });
      var g = this.selectNodeGroups(nodes);
      this.removeNodeGroups(g);
      this.createNodeGroups(g);
      this.updateNodeGroups(g);
    },

    handleJobsUpdated: function(jobs, duration) {
      var nodes = $.map(jobs, function(job) { return job.node; });
      this.updateNodeGroups(this.selectNodeGroups(nodes), duration);
    },

    selectNodeGroups: function(nodes) {
      return this.svg.selectAll('g.node').data(nodes, function(node) { return node.id; });
    },

    removeNodeGroups: function(g) {
      g.exit().remove();
    },

    createNodeGroups: function(g) {
      var self = this;
      var xs = this.xs;
      var ys = this.ys;
      var projection = this.projection;
      g = g.enter().append('svg:g').attr('class', function(node) {
        return node.pseudo ? 'pseudo' : 'node';
      });
      g.each(function(node, i) {
        d3.select(this).selectAll('path.edge').data(node.edges).enter()
          .append('svg:path').attr('class', 'edge')
          .attr('d', function diagonal(edge, i) {
            var p0 = edge.source,
            p3 = edge.target,
            m = (p0.x + p3.x) / 2,
            p = [p0, {x: m, y: p0.y}, {x: m, y: p3.y}, p3],
            p = p.map(projection);
            return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
          });
      });
      var c = g.append('svg:circle')
        .attr('cx', function(d) { return xs(d.x); })
        .attr('cy', function(d) { return ys(d.y); })
        .attr('r', 8);
      c.filter(isReal)
        .on('mouseover', function(node) { self.workflow.mouseOverJob(node.data); })
        .on('mouseout', function(node) { self.workflow.mouseOverJob(null); })
        .on('click', function(node) { self.workflow.selectJob(node.data); });
    },

    updateNodeGroups: function(g, duration) {
      var colors = this.params.colors;
      var fill = function(node) {
        var job = node.data;
        var status = job.status;
        if (job.mouseover) return colors.mouseover;
        if (job.selected) return colors.selected;
        if (status == 'RUNNING') return colors.running;
        if (status == 'COMPLETE') return colors.complete;
        if (status == 'FAILED') return colors.failed;
        return '#555';
      };
      g.selectAll('g.node circle').attr('fill', fill);
    },
  };

  // bind prototype to ctor
  Graph.fn.init.prototype = Graph.fn;
  return Graph;
});
<|endoftext|>


<commit_before>// ==UserScript==
// @name        Redirect to up to date documentation
// @namespace   sieradzki.it
// @description Detects if currently viewed online documentation page is the most recent version available, and if not, redirects user to the latest version.
// @version     1.0.0
// @match       *://docs.oracle.com/*
// @match       *://wiki.eclipse.org/Jetty*
// @match       *://www.postgresql.org/docs/*
// @match       *://docs.spring.io/*
// ==/UserScript==

(function () {
	'use strict';

	var documentations = {
		javaSE: {
			currentVersion: '8',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.oracle\.com\/javase\/([0-9\.]+)\/docs\/api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				url = url.replace(/\/javase\/([0-9\.]+)\/docs\/api\//, '/javase/' + this.currentVersion + '/docs/api/');
				return url.replace(/%2[8-9]|\(|\)/g, '-');
			}
		},
		javaEE: {
			currentVersion: '7',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.oracle\.com\/javaee\/([0-9\.]+)\/api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/javaee\/([0-9\.]+)\/api\//, '/javaee/' + this.currentVersion + '/api/');
			}
		},
		jetty: {
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/wiki\.eclipse\.org\/Jetty/);
				var messageBoxLinks =
					document.querySelectorAll('div.messagebox a[href^="http://www.eclipse.org/jetty/documentation"]');
				return matches !== null && messageBoxLinks !== null && messageBoxLinks.length === 2;
			},
			rewriteUrl: function () {
				return document.querySelectorAll('div.messagebox a[href^="http://www.eclipse.org/jetty/documentation"]')[1].href;
			}
		},
		postgreSQL: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/www\.postgresql\.org\/docs\/([0-9\.]+)\/(static|interactive)\//);
				return matches !== null && matches[2] !== this.currentVersion && matches[2] !== 'devel';
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.]+)\//, '/docs/' + this.currentVersion + '/');
			}
		},
		springFramework: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.spring\.io\/spring\/docs\/([0-9\.A-Zx\-]+)\/(javadoc\-)?api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.A-Zx\-]+)\/(javadoc\-)?api\//, '/docs/' + this.currentVersion +
					'/javadoc-api/');
			}
		},
		springSecurity: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.spring\.io\/spring\-security\/site\/docs\/([0-9\.A-Zx\-]+)\/apidocs\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/site\/docs\/([0-9\.A-Zx\-]+)\/apidocs\//, '/site/docs/' + this.currentVersion +
					'/apidocs/');
			}
		},
		springSocial: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.spring\.io\/spring\-social\/docs\/([0-9\.A-Zx\-]+)\/api(docs)?\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.A-Zx\-]+)\/api(docs)?\//, '/docs/' + this.currentVersion +
					'/apidocs/');
			}
		}
	};

	var DocumentationRedirect = function () {

		for (var key in documentations) {
			if (documentations.hasOwnProperty(key)) {
				if (documentations[key].isDocumentationPageOutdated(window.location.href)) {
					var rewrittenUrl = documentations[key].rewriteUrl(window.location.href);

					this.ifPageExists(rewrittenUrl, function (url) {
						window.location.replace(url);
					});

					break;
				}
			}
		}
	};

	DocumentationRedirect.prototype.ifPageExists = function (url, callback) {

		GM_xmlhttpRequest({
			method: 'HEAD',
			url: url,
			'onload': function (response) {
				if (response.status < 400) {
					callback(url);
				}
			}
		});
	};

	window.DocumentationRedirect = new DocumentationRedirect();
})();
<commit_msg>Add documentation to code<commit_after>// ==UserScript==
// @name        Redirect to up to date documentation
// @namespace   sieradzki.it
// @description Detects if currently viewed online documentation page is the most recent version available, and if not, redirects user to the latest version.
// @version     1.0.0
// @match       *://docs.oracle.com/*
// @match       *://wiki.eclipse.org/Jetty*
// @match       *://www.postgresql.org/docs/*
// @match       *://docs.spring.io/*
// ==/UserScript==

(function () {
	'use strict';

	var documentations = {
		javaSE: {
			currentVersion: '8',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.oracle\.com\/javase\/([0-9\.]+)\/docs\/api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				url = url.replace(/\/javase\/([0-9\.]+)\/docs\/api\//, '/javase/' + this.currentVersion + '/docs/api/');
				return url.replace(/%2[8-9]|\(|\)/g, '-');
			}
		},
		javaEE: {
			currentVersion: '7',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.oracle\.com\/javaee\/([0-9\.]+)\/api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/javaee\/([0-9\.]+)\/api\//, '/javaee/' + this.currentVersion + '/api/');
			}
		},
		jetty: {
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/wiki\.eclipse\.org\/Jetty/);
				var messageBoxLinks =
					document.querySelectorAll('div.messagebox a[href^="http://www.eclipse.org/jetty/documentation"]');
				return matches !== null && messageBoxLinks !== null && messageBoxLinks.length === 2;
			},
			rewriteUrl: function () {
				return document.querySelectorAll('div.messagebox a[href^="http://www.eclipse.org/jetty/documentation"]')[1].href;
			}
		},
		postgreSQL: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/www\.postgresql\.org\/docs\/([0-9\.]+)\/(static|interactive)\//);
				return matches !== null && matches[2] !== this.currentVersion && matches[2] !== 'devel';
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.]+)\//, '/docs/' + this.currentVersion + '/');
			}
		},
		springFramework: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.spring\.io\/spring\/docs\/([0-9\.A-Zx\-]+)\/(javadoc\-)?api\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.A-Zx\-]+)\/(javadoc\-)?api\//, '/docs/' + this.currentVersion +
					'/javadoc-api/');
			}
		},
		springSecurity: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.spring\.io\/spring\-security\/site\/docs\/([0-9\.A-Zx\-]+)\/apidocs\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/site\/docs\/([0-9\.A-Zx\-]+)\/apidocs\//, '/site/docs/' + this.currentVersion +
					'/apidocs/');
			}
		},
		springSocial: {
			currentVersion: 'current',
			isDocumentationPageOutdated: function (url) {
				var matches = url.match(/^http(s)?:\/\/docs\.spring\.io\/spring\-social\/docs\/([0-9\.A-Zx\-]+)\/api(docs)?\//);
				return matches !== null && matches[2] !== this.currentVersion;
			},
			rewriteUrl: function (url) {
				return url.replace(/\/docs\/([0-9\.A-Zx\-]+)\/api(docs)?\//, '/docs/' + this.currentVersion +
					'/apidocs/');
			}
		}
	};

	var DocumentationRedirect = function () {

		for (var key in documentations) {
			if (documentations.hasOwnProperty(key)) {
				if (documentations[key].isDocumentationPageOutdated(window.location.href)) {
					var rewrittenUrl = documentations[key].rewriteUrl(window.location.href);

					// In newer version of documentation e.g. current viewed class could be permanently deleted, so
					// redirection should only occur when we are sure that target page exists
					this.ifPageExists(rewrittenUrl, function (url) {
						window.location.replace(url);
					});

					break;
				}
			}
		}
	};

	/**
	 * @private
	 */
	DocumentationRedirect.prototype.ifPageExists = function (url, callback) {

		GM_xmlhttpRequest({
			method: 'HEAD',
			url: url,
			'onload': function (response) {
				if (response.status < 400) {
					callback(url);
				}
			}
		});
	};

	window.DocumentationRedirect = new DocumentationRedirect();
})();
<|endoftext|>


<commit_before>function getRemovableChildren(node) {
    let nodes = node.successors().filter((i, ele) => {
        let eleNodes = ele.incomers().filter((i, ele) => ele.isNode());
        if (eleNodes.length === 1) {
            return true;
        } else {
            // Check if this node connects to target. If it does then it is connected
            // to multiple nodes at the same level as target and we cannot hide it.
            let hasTargetAsParent = false;
            eleNodes.forEach(e => {
                if (e.data('id') === node.data('id')) {
                    hasTargetAsParent = true;
                }

            });
            return !hasTargetAsParent;
        }
    });

    return nodes.union(nodes.connectedEdges());
}

class MCProcessesWorkflowGraphComponentController {
    /*@ngInject*/
    constructor(processGraph, workflowService, mcbus, experimentsAPI, $stateParams, mcstate, $filter,
                $mdDialog, mcshow, workflowState, cyGraph) {
        this.cy = null;
        this.processGraph = processGraph;
        this.workflowService = workflowService;
        this.mcbus = mcbus;
        this.mcstate = mcstate;
        this.myName = 'MCProcessesWorkflowGraph';
        this.projectId = $stateParams.project_id;
        this.experimentId = $stateParams.experiment_id;
        this.experimentsAPI = experimentsAPI;
        this.$filter = $filter;
        this.$mdDialog = $mdDialog;
        this.mcshow = mcshow;
        this.removedNodes = null;
        this.navigator = null;
        this.workflowState = workflowState;
        this.cyGraph = cyGraph;
        this.hiddenNodes = [];
    }

    $onInit() {
        // To preserve this binding pass this.allProcessesGraph bound to an arrow function. Arrow
        // functions lexically scope, so this in the arrow function is the this for
        // MCProcessesWorkflowGraphComponentController
        let cb = (processes) => {
            this.processes = processes;
            this.allProcessesGraph();
        };

        this.mcbus.subscribe('PROCESSES$CHANGE', this.myName, cb);
        this.mcbus.subscribe('PROCESS$ADD', this.myName, (process) => {
            let node = this.processGraph.createProcessNode(process);
            this.cy.add(node);
            let edges = this.processGraph.createConnectingEdges(process, this.processes);
            console.log('edges', edges);
            if (edges.length) {
                this.cy.add(edges);
            }
            this.processes.push(process);
        });
        this.mcbus.subscribe('PROCESS$DELETE', this.myName, (process) => console.log('PROCESS$DELETE', process));
        this.mcbus.subscribe('EDGE$ADD', this.myName, (source, target) => console.log('EDGE$ADD', source, target));
        this.mcbus.subscribe('EDGE$DELETE', this.myName, (source, target) => console.log('EDGE$DELETE', source, target));

        let searchcb = (search) => {
            if (search === '') {
                if (this.removedNodes !== null) {
                    this.removedNodes.restore();
                    this.cy.layout({name: 'dagre', fit: true});
                }
                return;
            }
            this.removedNodes = null;
            let matches = this.$filter('filter')(this.processes.plain(), search);
            if (!matches.length) {
                return;
            }
            let matchesById = _.indexBy(matches, 'id');
            let matchingNodes = this.cy.nodes().filter((i, ele) => {
                let processId = ele.data('details').id;
                return (!(processId in matchesById));

            });
            this.removedNodes = this.cy.remove(matchingNodes.union(matchingNodes.connectedEdges()));
            this.cy.layout({name: 'dagre', fit: true});
        };

        this.mcbus.subscribe('WORKFLOW$RESTOREHIDDEN', this.myName, () => {
            if (this.hiddenNodes.length) {
                this.hiddenNodes.restore();
                this.hiddenNodes = [];
            }
        });

        this.mcstate.subscribe('WORKFLOW$SEARCH', this.myName, searchcb);
        this.mcbus.subscribe('WORKFLOW$RESET', this.myName, () => this.allProcessesGraph());
        this.mcbus.subscribe('WORKFLOW$NAVIGATOR', this.myName, () => {
            if (this.navigator === null) {
                this.navigator = this.cy.navigator();
            } else {
                this.navigator.destroy();
                this.navigator = null;
            }
        });

        this.mcbus.subscribe('WORKFLOW$FILTER$BYSAMPLES', this.myName, (samples) => {
            if (!samples.length) {
                return;
            }

            let matchingProcesses = [];
            samples.forEach(sample => {
                let matches = this.$filter('filter')(this.processes.plain(), sample.id);
                matchingProcesses = matchingProcesses.concat(matches.map(p => ({id: p.id, seen: false})));
            });

            let matchesById = _.indexBy(matchingProcesses, 'id');
            let matchingNodes = this.cy.nodes().filter((i, ele) => {
                let processId = ele.data('details').id;
                return (!(processId in matchesById));

            });
            this.removedNodes = this.cy.remove(matchingNodes.union(matchingNodes.connectedEdges()));
            this.cy.layout({name: 'dagre', fit: true});
        });
    }

    $onDestroy() {
        this.mcbus.leave('PROCESSES$CHANGE', this.myName);
        this.mcbus.leave('WORKFLOW$RESTOREHIDDEN', this.myName);
        this.mcstate.leave('WORKFLOW$SEARCH', this.myName);
        this.mcbus.leave('WORKFLOW$RESET', this.myName);
        this.mcbus.leave('PROCESS$ADD', this.myName);
        this.mcbus.leave('PROCESS$DELETE', this.myName);
        this.mcbus.leave('EDGE$ADD', this.myName);
        this.mcbus.leave('EDGE$DELETE', this.myName);
        if (this.navigator !== null) {
            this.navigator.destroy();
        }
    }

    // This method will be called implicitly when the component is loaded.
    $onChanges(changes) {
        if (changes.processes) {
            this.processes = changes.processes.currentValue;
        }
        if (changes.highlightProcesses) {
            this.highlightProcesses = changes.highlightProcesses.currentValue;
        }
        this.allProcessesGraph();
    }

    allProcessesGraph() {
        let g = this.processGraph.build(this.processes, this.highlightProcesses);
        this.samples = g.samples;
        this.cy = this.cyGraph.createGraph(g.elements, 'processesGraph');
        this.cyGraph.setOnClickForExperiment(this.cy, this.projectId, this.experimentId);

        this.ctxMenu = this.setupContextMenus();
        let completeFN = (source, target, addedEntities) => {
            let sourceProcess = source.data('details');
            let targetProcess = target.data('details');
            if (sourceProcess.output_samples.length === 1) {
                this.workflowService.addSamplesToProcess(this.projectId, this.experimentId, targetProcess, sourceProcess.output_samples).then(
                    (process) => {
                        this.replaceProcess(process);
                        target.data('details', process);
                    }
                );
            } else {
                this.workflowService.chooseSamplesFromSource(sourceProcess).then(
                    (samples) => {
                        if (!samples.length) {
                            // No samples brought over, delete edge
                            addedEntities[0].remove();
                        } else {
                            this.workflowService.addSamplesToProcess(this.projectId, this.experimentId, targetProcess, samples).then(
                                (process) => {
                                    this.replaceProcess(process);
                                    target.data('details', process);
                                }
                            );
                        }
                    }
                );
            }
        };
        this.cyGraph.addEdgeHandles(this.cy, completeFN);
    }

    replaceProcess(process) {
        let i = _.findIndex(this.processes, p => p.id === process.id);
        if (i !== -1) {
            this.processes.splice(i, 1);
            this.processes.push(process);
        }
    }

    setupContextMenus() {
        let options = {
            menuItems: [
                {
                    id: 'details',
                    title: 'Show Details',
                    selector: 'node, edge',
                    hasTrailingDivider: true,
                    onClickFunction: (event) => this._showDetails(event)
                },
                {
                    id: 'clone-process',
                    title: 'Clone Process',
                    selector: 'node',
                    onClickFunction: (event) => this._cloneProcess(event)
                },
                {
                    id: 'add-child',
                    title: 'Add Child',
                    selector: 'node',
                    onClickFunction: (event) => this._addChild(event)
                },
                {
                    id: 'delete-process',
                    title: 'Delete Process',
                    selector: 'node',
                    hasTrailingDivider: true,
                    onClickFunction: (event) => this._deleteProcess(event)
                },
                {
                    id: 'collapse',
                    title: 'Collapse',
                    selector: 'node',
                    onClickFunction: event => this._collapseNode(event)
                },
                {
                    id: 'expand',
                    title: 'Expand',
                    selector: 'node',
                    onClickFunction: event => this._expandNode(event)
                },
                {
                    id: 'hide',
                    title: 'Hide',
                    selector: 'node',
                    onClickFunction: event => this._hideNode(event)
                },
                {
                    id: 'hide-others',
                    title: 'Hide Others',
                    selector: 'node',
                    onClickFunction: event => this._hideOtherNodes(event)
                }
            ]
        };
        this.cy.contextMenus(options);
    }

    _showDetails(event) {
        let target = event.cyTarget;
        if (target.isNode()) {
            let process = this.getProcessFromEvent(event);
            this.experimentsAPI.getProcessForExperiment(this.projectId, this.experimentId, process.id).then(
                p => this.mcshow.processDetailsDialog(p, false).then(
                    updatedProcess => target.data('name', updatedProcess.name)
                )
            );
        }
    }

    _cloneProcess(event) {
        let process = this.getProcessFromEvent(event);
        this.workflowService.cloneProcess(this.projectId, this.experimentId, process);
    }

    _deleteProcess(event) {
        let process = this.getProcessFromEvent(event);
        this.workflowService.deleteNodeAndProcess(this.projectId, this.experimentId, process.id);
    }

    _collapseNode(event) {
        let target = event.cyTarget;
        let nodes = getRemovableChildren(target);
        if (nodes.length) {
            let name = target.data('name');
            target.data('name', `+ ${name}`);
            target.data('collapsed', nodes);
            this.cy.remove(nodes);
        }
    }

    _expandNode(event) {
        let target = event.cyTarget;
        let collapsed = target.data('collapsed');
        if (collapsed) {
            collapsed.restore();
            let name = target.data('name').substring(1);
            target.data('name', name);
            target.data('collapsed', null);
        }
    }

    _hideNode(event) {
        let target = event.cyTarget;
        let nodes = getRemovableChildren(target);
        nodes = nodes.union(target);
        let hidden = this.cy.remove(nodes);
        if (this.hiddenNodes.length) {
            this.hiddenNodes = this.hiddenNodes.union(hidden);
        } else {
            this.hiddenNodes = hidden;
        }
    }

    _hideOtherNodes(event) {
        let target = event.cyTarget;
        let nodesToKeep = getRemovableChildren(target).union(target);
        let nodesToRemove = nodesToKeep.absoluteComplement();
        let hidden = this.cy.remove(nodesToRemove);
        if (this.hiddenNodes.length) {
            this.hiddenNodes = this.hiddenNodes.union(hidden);
        } else {
            this.hiddenNodes = hidden;
        }
    }

    _addChild(event) {
        let process = this.getProcessFromEvent(event);
        this.$mdDialog.show({
            templateUrl: 'app/project/experiments/experiment/components/workflow/mc-process-templates-dialog.html',
            controller: SelectProcessTemplateDialogController,
            controllerAs: '$ctrl',
            bindToController: true,
            multiple: true,
            locals: {
                parentProcess: process
            }
        });
    }

    getProcessFromEvent(event) {
        let target = event.cyTarget;
        let processId = target.data('id');
        let process = this.processes.filter((p) => p.id === processId)[0];
        process.hasChildren = (target.outgoers().length > 0);
        return process;
    }

}

class SelectProcessTemplateDialogController {
    /*@ngInject*/
    constructor($stateParams, $mdDialog, workflowService) {
        this.$mdDialog = $mdDialog;
        this.projectId = $stateParams.project_id;
        this.experimentId = $stateParams.experiment_id;
        this.workflowService = workflowService;
        this.keepOpen = false;
    }

    addSelectedProcessTemplate(templateId) {
        this.workflowService.addChildProcessFromTemplate(templateId, this.projectId, this.experimentId,
            this.parentProcess, this.keepOpen)
    }

    done() {
        this.$mdDialog.hide();
    }

}

angular.module('materialscommons').component('mcProcessesWorkflowGraph', {
    templateUrl: 'app/project/experiments/experiment/components/workflow/mc-processes-workflow-graph.html',
    controller: MCProcessesWorkflowGraphComponentController,
    bindings: {
        processes: '<',
        highlightProcesses: '<'
    }
});
<commit_msg>Remove console.log<commit_after>function getRemovableChildren(node) {
    let nodes = node.successors().filter((i, ele) => {
        let eleNodes = ele.incomers().filter((i, ele) => ele.isNode());
        if (eleNodes.length === 1) {
            return true;
        } else {
            // Check if this node connects to target. If it does then it is connected
            // to multiple nodes at the same level as target and we cannot hide it.
            let hasTargetAsParent = false;
            eleNodes.forEach(e => {
                if (e.data('id') === node.data('id')) {
                    hasTargetAsParent = true;
                }

            });
            return !hasTargetAsParent;
        }
    });

    return nodes.union(nodes.connectedEdges());
}

class MCProcessesWorkflowGraphComponentController {
    /*@ngInject*/
    constructor(processGraph, workflowService, mcbus, experimentsAPI, $stateParams, mcstate, $filter,
                $mdDialog, mcshow, workflowState, cyGraph) {
        this.cy = null;
        this.processGraph = processGraph;
        this.workflowService = workflowService;
        this.mcbus = mcbus;
        this.mcstate = mcstate;
        this.myName = 'MCProcessesWorkflowGraph';
        this.projectId = $stateParams.project_id;
        this.experimentId = $stateParams.experiment_id;
        this.experimentsAPI = experimentsAPI;
        this.$filter = $filter;
        this.$mdDialog = $mdDialog;
        this.mcshow = mcshow;
        this.removedNodes = null;
        this.navigator = null;
        this.workflowState = workflowState;
        this.cyGraph = cyGraph;
        this.hiddenNodes = [];
    }

    $onInit() {
        // To preserve this binding pass this.allProcessesGraph bound to an arrow function. Arrow
        // functions lexically scope, so this in the arrow function is the this for
        // MCProcessesWorkflowGraphComponentController
        let cb = (processes) => {
            this.processes = processes;
            this.allProcessesGraph();
        };

        this.mcbus.subscribe('PROCESSES$CHANGE', this.myName, cb);
        this.mcbus.subscribe('PROCESS$ADD', this.myName, (process) => {
            let node = this.processGraph.createProcessNode(process);
            this.cy.add(node);
            let edges = this.processGraph.createConnectingEdges(process, this.processes);
            if (edges.length) {
                this.cy.add(edges);
            }
            this.processes.push(process);
        });
        this.mcbus.subscribe('PROCESS$DELETE', this.myName, (process) => console.log('PROCESS$DELETE', process));
        this.mcbus.subscribe('EDGE$ADD', this.myName, (source, target) => console.log('EDGE$ADD', source, target));
        this.mcbus.subscribe('EDGE$DELETE', this.myName, (source, target) => console.log('EDGE$DELETE', source, target));

        let searchcb = (search) => {
            if (search === '') {
                if (this.removedNodes !== null) {
                    this.removedNodes.restore();
                    this.cy.layout({name: 'dagre', fit: true});
                }
                return;
            }
            this.removedNodes = null;
            let matches = this.$filter('filter')(this.processes.plain(), search);
            if (!matches.length) {
                return;
            }
            let matchesById = _.indexBy(matches, 'id');
            let matchingNodes = this.cy.nodes().filter((i, ele) => {
                let processId = ele.data('details').id;
                return (!(processId in matchesById));

            });
            this.removedNodes = this.cy.remove(matchingNodes.union(matchingNodes.connectedEdges()));
            this.cy.layout({name: 'dagre', fit: true});
        };

        this.mcbus.subscribe('WORKFLOW$RESTOREHIDDEN', this.myName, () => {
            if (this.hiddenNodes.length) {
                this.hiddenNodes.restore();
                this.hiddenNodes = [];
            }
        });

        this.mcstate.subscribe('WORKFLOW$SEARCH', this.myName, searchcb);
        this.mcbus.subscribe('WORKFLOW$RESET', this.myName, () => this.allProcessesGraph());
        this.mcbus.subscribe('WORKFLOW$NAVIGATOR', this.myName, () => {
            if (this.navigator === null) {
                this.navigator = this.cy.navigator();
            } else {
                this.navigator.destroy();
                this.navigator = null;
            }
        });

        this.mcbus.subscribe('WORKFLOW$FILTER$BYSAMPLES', this.myName, (samples) => {
            if (!samples.length) {
                return;
            }

            let matchingProcesses = [];
            samples.forEach(sample => {
                let matches = this.$filter('filter')(this.processes.plain(), sample.id);
                matchingProcesses = matchingProcesses.concat(matches.map(p => ({id: p.id, seen: false})));
            });

            let matchesById = _.indexBy(matchingProcesses, 'id');
            let matchingNodes = this.cy.nodes().filter((i, ele) => {
                let processId = ele.data('details').id;
                return (!(processId in matchesById));

            });
            this.removedNodes = this.cy.remove(matchingNodes.union(matchingNodes.connectedEdges()));
            this.cy.layout({name: 'dagre', fit: true});
        });
    }

    $onDestroy() {
        this.mcbus.leave('PROCESSES$CHANGE', this.myName);
        this.mcbus.leave('WORKFLOW$RESTOREHIDDEN', this.myName);
        this.mcstate.leave('WORKFLOW$SEARCH', this.myName);
        this.mcbus.leave('WORKFLOW$RESET', this.myName);
        this.mcbus.leave('PROCESS$ADD', this.myName);
        this.mcbus.leave('PROCESS$DELETE', this.myName);
        this.mcbus.leave('EDGE$ADD', this.myName);
        this.mcbus.leave('EDGE$DELETE', this.myName);
        if (this.navigator !== null) {
            this.navigator.destroy();
        }
    }

    // This method will be called implicitly when the component is loaded.
    $onChanges(changes) {
        if (changes.processes) {
            this.processes = changes.processes.currentValue;
        }
        if (changes.highlightProcesses) {
            this.highlightProcesses = changes.highlightProcesses.currentValue;
        }
        this.allProcessesGraph();
    }

    allProcessesGraph() {
        let g = this.processGraph.build(this.processes, this.highlightProcesses);
        this.samples = g.samples;
        this.cy = this.cyGraph.createGraph(g.elements, 'processesGraph');
        this.cyGraph.setOnClickForExperiment(this.cy, this.projectId, this.experimentId);

        this.ctxMenu = this.setupContextMenus();
        let completeFN = (source, target, addedEntities) => {
            let sourceProcess = source.data('details');
            let targetProcess = target.data('details');
            if (sourceProcess.output_samples.length === 1) {
                this.workflowService.addSamplesToProcess(this.projectId, this.experimentId, targetProcess, sourceProcess.output_samples).then(
                    (process) => {
                        this.replaceProcess(process);
                        target.data('details', process);
                    }
                );
            } else {
                this.workflowService.chooseSamplesFromSource(sourceProcess).then(
                    (samples) => {
                        if (!samples.length) {
                            // No samples brought over, delete edge
                            addedEntities[0].remove();
                        } else {
                            this.workflowService.addSamplesToProcess(this.projectId, this.experimentId, targetProcess, samples).then(
                                (process) => {
                                    this.replaceProcess(process);
                                    target.data('details', process);
                                }
                            );
                        }
                    }
                );
            }
        };
        this.cyGraph.addEdgeHandles(this.cy, completeFN);
    }

    replaceProcess(process) {
        let i = _.findIndex(this.processes, p => p.id === process.id);
        if (i !== -1) {
            this.processes.splice(i, 1);
            this.processes.push(process);
        }
    }

    setupContextMenus() {
        let options = {
            menuItems: [
                {
                    id: 'details',
                    title: 'Show Details',
                    selector: 'node, edge',
                    hasTrailingDivider: true,
                    onClickFunction: (event) => this._showDetails(event)
                },
                {
                    id: 'clone-process',
                    title: 'Clone Process',
                    selector: 'node',
                    onClickFunction: (event) => this._cloneProcess(event)
                },
                {
                    id: 'add-child',
                    title: 'Add Child',
                    selector: 'node',
                    onClickFunction: (event) => this._addChild(event)
                },
                {
                    id: 'delete-process',
                    title: 'Delete Process',
                    selector: 'node',
                    hasTrailingDivider: true,
                    onClickFunction: (event) => this._deleteProcess(event)
                },
                {
                    id: 'collapse',
                    title: 'Collapse',
                    selector: 'node',
                    onClickFunction: event => this._collapseNode(event)
                },
                {
                    id: 'expand',
                    title: 'Expand',
                    selector: 'node',
                    onClickFunction: event => this._expandNode(event)
                },
                {
                    id: 'hide',
                    title: 'Hide',
                    selector: 'node',
                    onClickFunction: event => this._hideNode(event)
                },
                {
                    id: 'hide-others',
                    title: 'Hide Others',
                    selector: 'node',
                    onClickFunction: event => this._hideOtherNodes(event)
                }
            ]
        };
        this.cy.contextMenus(options);
    }

    _showDetails(event) {
        let target = event.cyTarget;
        if (target.isNode()) {
            let process = this.getProcessFromEvent(event);
            this.experimentsAPI.getProcessForExperiment(this.projectId, this.experimentId, process.id).then(
                p => this.mcshow.processDetailsDialog(p, false).then(
                    updatedProcess => target.data('name', updatedProcess.name)
                )
            );
        }
    }

    _cloneProcess(event) {
        let process = this.getProcessFromEvent(event);
        this.workflowService.cloneProcess(this.projectId, this.experimentId, process);
    }

    _deleteProcess(event) {
        let process = this.getProcessFromEvent(event);
        this.workflowService.deleteNodeAndProcess(this.projectId, this.experimentId, process.id);
    }

    _collapseNode(event) {
        let target = event.cyTarget;
        let nodes = getRemovableChildren(target);
        if (nodes.length) {
            let name = target.data('name');
            target.data('name', `+ ${name}`);
            target.data('collapsed', nodes);
            this.cy.remove(nodes);
        }
    }

    _expandNode(event) {
        let target = event.cyTarget;
        let collapsed = target.data('collapsed');
        if (collapsed) {
            collapsed.restore();
            let name = target.data('name').substring(1);
            target.data('name', name);
            target.data('collapsed', null);
        }
    }

    _hideNode(event) {
        let target = event.cyTarget;
        let nodes = getRemovableChildren(target);
        nodes = nodes.union(target);
        let hidden = this.cy.remove(nodes);
        if (this.hiddenNodes.length) {
            this.hiddenNodes = this.hiddenNodes.union(hidden);
        } else {
            this.hiddenNodes = hidden;
        }
    }

    _hideOtherNodes(event) {
        let target = event.cyTarget;
        let nodesToKeep = getRemovableChildren(target).union(target);
        let nodesToRemove = nodesToKeep.absoluteComplement();
        let hidden = this.cy.remove(nodesToRemove);
        if (this.hiddenNodes.length) {
            this.hiddenNodes = this.hiddenNodes.union(hidden);
        } else {
            this.hiddenNodes = hidden;
        }
    }

    _addChild(event) {
        let process = this.getProcessFromEvent(event);
        this.$mdDialog.show({
            templateUrl: 'app/project/experiments/experiment/components/workflow/mc-process-templates-dialog.html',
            controller: SelectProcessTemplateDialogController,
            controllerAs: '$ctrl',
            bindToController: true,
            multiple: true,
            locals: {
                parentProcess: process
            }
        });
    }

    getProcessFromEvent(event) {
        let target = event.cyTarget;
        let processId = target.data('id');
        let process = this.processes.filter((p) => p.id === processId)[0];
        process.hasChildren = (target.outgoers().length > 0);
        return process;
    }

}

class SelectProcessTemplateDialogController {
    /*@ngInject*/
    constructor($stateParams, $mdDialog, workflowService) {
        this.$mdDialog = $mdDialog;
        this.projectId = $stateParams.project_id;
        this.experimentId = $stateParams.experiment_id;
        this.workflowService = workflowService;
        this.keepOpen = false;
    }

    addSelectedProcessTemplate(templateId) {
        this.workflowService.addChildProcessFromTemplate(templateId, this.projectId, this.experimentId,
            this.parentProcess, this.keepOpen)
    }

    done() {
        this.$mdDialog.hide();
    }

}

angular.module('materialscommons').component('mcProcessesWorkflowGraph', {
    templateUrl: 'app/project/experiments/experiment/components/workflow/mc-processes-workflow-graph.html',
    controller: MCProcessesWorkflowGraphComponentController,
    bindings: {
        processes: '<',
        highlightProcesses: '<'
    }
});
<|endoftext|>


<commit_before>/*
    Agora Forum Software
    Copyright (C) 2018 Gregory Sartucci
    License: AGPL-3.0, Check file LICENSE
*/

Template.mainReply.getParents();

Template.mainReply.onCreated(function() {
    this.errorMessage = new ReactiveVar();
});

Template.mainReply.onRendered(function() {
    let instance = this;
    let target;

    let titleInput = $('#main-reply-title');
    let contentInput = $('#main-reply-textarea');

    this.submitButton = null;

    this.submitted = false;

    let hasContent = function() {
        return titleInput.val().length > 0 || contentInput.val().length > 0;
    };

    let hasEdit = function() {
        let title = target.title === undefined ? "" : target.title;
        return titleInput.val() != title || contentInput.val() != target.content;
    };

    let submitReply = function(event) {
        if (instance.submitted) return;
        let post = {
            title: titleInput.val(),
            content: contentInput.val(),
            target: target._id
        };

        Meteor.call("insertPost", post, function(error) {
            if (error) {
                //Display error message to user.
                instance.errorMessage.set(error.reason);
            }
            else {
                //Don't delete user's work unless it posts successfully.
                instance.parent.replyTarget.set();
            }
        });
        instance.submitted = true;
    };

    let submitEdit = function(event) {
        if (instance.submitted) return;

        let post = {
            title: titleInput.val(),
            content: contentInput.val()
        };

        Meteor.call("editPost", target._id, post, function(error) {
            if (error) {
                //Display error message to user.
                instance.errorMessage.set(error.reason);
            }
            else {
                //Don't delete user's work unless it posts successfully.
                instance.parent.editTarget.set();
            }
        });
        instance.submitted = true;
    };

    let cancelReply = function(event) {
        if (!hasContent() || confirm('You have an unfinished post. Are you sure you want to cancel?')) {
            instance.parent.replyTarget.set();
        }
    };

    let cancelEdit = function(event) {
        if (!hasEdit() || confirm('You have an unfinished edit. Are you sure you want to cancel?')) {
            instance.parent.editTarget.set();
        }
    };

    let exitReply = function(event) {
        if (hasContent())
            return "You have an unfinished post. Are you sure you want to close the page?";
    };

    let exitEdit = function(event) {
        if (hasEdit())
            return "You have an unfinished edit. Are you sure you want to close the page?";
    };

    if (this.parent.replyTarget.get()) {
        target = this.parent.replyTarget.get();

        this.submitButton = submitReply;

        $('#main-reply-submit-button').click(this.submitButton);
        $('#main-reply-cancel-button').click(cancelReply);
        $(window).on('beforeunload', exitReply);
    } else if (this.parent.editTarget.get()) {
        target = this.parent.editTarget.get();

        titleInput.val(target.title);
        contentInput.val(target.content);

        this.submitButton = submitEdit;

        $('#main-reply-submit-button').click(this.submitButton);
        $('#main-reply-cancel-button').click(cancelEdit);
        $(window).on('beforeunload', exitEdit);
    }
});

Template.mainReply.helpers({
    errorMessage: function() {
        return Template.instance().errorMessage.get();
    }
});

Template.mainReply.events({
    'mousedown, touchstart, mousemove, touchmove, mouseup, touchend, wheel': function(event, instance) {
        if (instance.parent.camera.isDragging()) {
            //Prevents interaction while dragging.
            event.preventDefault();
        }
        else {
            //Prevent events from passing through posts into the WebGL canvas.
            event.stopImmediatePropagation();
        }
    },
    'keydown, keyup': function(event) {
        event.stopImmediatePropagation();

        if (event.ctrlKey && event.key == "Enter")
            Template.instance().submitButton();

    }
});

Template.mainReply.onDestroyed(function() {
    $(window).off('beforeunload');
});
<commit_msg>Fixed reply box lockup on error.<commit_after>/*
    Agora Forum Software
    Copyright (C) 2018 Gregory Sartucci
    License: AGPL-3.0, Check file LICENSE
*/

Template.mainReply.getParents();

Template.mainReply.onCreated(function() {
    this.errorMessage = new ReactiveVar();
});

Template.mainReply.onRendered(function() {
    let instance = this;
    let target;

    let titleInput = $('#main-reply-title');
    let contentInput = $('#main-reply-textarea');

    this.submitButton = null;

    this.submitted = false;

    let hasContent = function() {
        return titleInput.val().length > 0 || contentInput.val().length > 0;
    };

    let hasEdit = function() {
        let title = target.title === undefined ? "" : target.title;
        return titleInput.val() != title || contentInput.val() != target.content;
    };

    let submitReply = function(event) {
        if (instance.submitted) return;
        let post = {
            title: titleInput.val(),
            content: contentInput.val(),
            target: target._id
        };

        Meteor.call("insertPost", post, function(error) {
            if (error) {
                //Display error message to user.
                instance.errorMessage.set(error.reason);
            }
            else {
                //Don't delete user's work unless it posts successfully.
                instance.parent.replyTarget.set();
                instance.submitted = true;
            }
        });
    };

    let submitEdit = function(event) {
        if (instance.submitted) return;

        let post = {
            title: titleInput.val(),
            content: contentInput.val()
        };

        Meteor.call("editPost", target._id, post, function(error) {
            if (error) {
                //Display error message to user.
                instance.errorMessage.set(error.reason);
            }
            else {
                //Don't delete user's work unless it posts successfully.
                instance.parent.editTarget.set();
            }
        });
        instance.submitted = true;
    };

    let cancelReply = function(event) {
        if (!hasContent() || confirm('You have an unfinished post. Are you sure you want to cancel?')) {
            instance.parent.replyTarget.set();
        }
    };

    let cancelEdit = function(event) {
        if (!hasEdit() || confirm('You have an unfinished edit. Are you sure you want to cancel?')) {
            instance.parent.editTarget.set();
        }
    };

    let exitReply = function(event) {
        if (hasContent())
            return "You have an unfinished post. Are you sure you want to close the page?";
    };

    let exitEdit = function(event) {
        if (hasEdit())
            return "You have an unfinished edit. Are you sure you want to close the page?";
    };

    if (this.parent.replyTarget.get()) {
        target = this.parent.replyTarget.get();

        this.submitButton = submitReply;

        $('#main-reply-submit-button').click(this.submitButton);
        $('#main-reply-cancel-button').click(cancelReply);
        $(window).on('beforeunload', exitReply);
    } else if (this.parent.editTarget.get()) {
        target = this.parent.editTarget.get();

        titleInput.val(target.title);
        contentInput.val(target.content);

        this.submitButton = submitEdit;

        $('#main-reply-submit-button').click(this.submitButton);
        $('#main-reply-cancel-button').click(cancelEdit);
        $(window).on('beforeunload', exitEdit);
    }
});

Template.mainReply.helpers({
    errorMessage: function() {
        return Template.instance().errorMessage.get();
    }
});

Template.mainReply.events({
    'mousedown, touchstart, mousemove, touchmove, mouseup, touchend, wheel': function(event, instance) {
        if (instance.parent.camera.isDragging()) {
            //Prevents interaction while dragging.
            event.preventDefault();
        }
        else {
            //Prevent events from passing through posts into the WebGL canvas.
            event.stopImmediatePropagation();
        }
    },
    'keydown, keyup': function(event) {
        event.stopImmediatePropagation();

        if (event.ctrlKey && event.key == "Enter")
            Template.instance().submitButton();

    }
});

Template.mainReply.onDestroyed(function() {
    $(window).off('beforeunload');
});
<|endoftext|>


<commit_before>import Ember from 'ember';

export default Ember.Controller.extend({
  actions: {
    assign: function(todo) {
      todo.set("status_code", 2);
    }
  },
  unassigned: function() {
    return this.get("model").filter(function(model) {
      return model.status_code === 1;
    });
  }.property("model.@each.status_code"),
  assigned: function() {
    return this.get("model").filter(function(model) {
      return model.status_code === 2;
   });
  }.property("model.@each.status_code")
});
<commit_msg>step; inject currentRouteName<commit_after>import Ember from 'ember';

export default Ember.Controller.extend({
  application: Ember.inject.controller(),
  isActiveRoute: Ember.computed.equal("application.currentRouteName", "todos.index"),
  actions: {
    assign: function(todo) {
      todo.set("status_code", 2);
    }
  },
  unassigned: function() {
    return this.get("model").filter(function(model) {
      return model.status_code === 1;
    });
  }.property("model.@each.status_code"),
  assigned: function() {
    return this.get("model").filter(function(model) {
      return model.status_code === 2;
   });
  }.property("model.@each.status_code")
});
<|endoftext|>


<commit_before>'use strict';

process.on('unhandledRejection', function (e) {
    throw e;
});

const bluebird = require('bluebird');
const co = require('co');
const OCLE = require('openchemlib-extended');
const chemcalc = require('chemcalc');
const mfUtil = require('../src/node_modules/mf');

const mongo = require('../src/node_modules/mongo');

let db;
let done = 0; // we may change this value and some records will be skipped
co(function*() {
    db = yield mongo.connect();
    console.log('connected to MongoDB');
    const collection = db.collection('data');
    const cursor = collection.find().skip(done);
    while (yield cursor.hasNext()) {
        if (done % 100000 === 0) {
            console.log(new Date(), done);
        }
        const doc = yield cursor.next();
        const mol = OCLE.Molecule.fromIDCode(doc.ocl.id, doc.ocl.coord);
        const mf = mol.getMF().parts.join('.');

        const toSet = {
            mf: mf
        };

        try {
            const chemcalcMF = chemcalc.analyseMF(mf);
            toSet.em = chemcalcMF.em;
            toSet.mw= chemcalcMF.mw;
            toSet.unsat= chemcalcMF.unsaturation;
            toSet.charge= chemcalcMF.charge;
            toSet.atom= mfUtil.getAtoms(chemcalcMF);
            yield collection.findOneAndUpdate({
                _id: doc._id
            }, {
                $set: toSet
            });
        } catch (e) {
            console.log('Remove fields for',doc._id);
            yield collection.findOneAndUpdate({
                _id: doc._id
            }, {
                $unset: {em:'', mw:'', unsat:'', charge:'', atom:''}
            });
        }

        done++;
    }
}).catch(function (e) {
    console.log('error');
    console.log(e);
    console.error(e);
}).then(function () {
    console.log('closing DB');
    if (db) db.close();
});
<commit_msg>Add addCursorFlag('noCursorTimeout',true) to prevent timeout<commit_after>'use strict';

process.on('unhandledRejection', function (e) {
    throw e;
});

const bluebird = require('bluebird');
const co = require('co');
const OCLE = require('openchemlib-extended');
const chemcalc = require('chemcalc');
const mfUtil = require('../src/node_modules/mf');

const mongo = require('../src/node_modules/mongo');

let db;
let done = 0; // we may change this value and some records will be skipped
co(function*() {
    db = yield mongo.connect();
    console.log('connected to MongoDB');
    const collection = db.collection('data');
    const cursor = collection.find().addCursorFlag('noCursorTimeout',true).skip(done);
    while (yield cursor.hasNext()) {
        if (done % 100000 === 0) {
            console.log(new Date(), done);
        }
        const doc = yield cursor.next();
        const mol = OCLE.Molecule.fromIDCode(doc.ocl.id, doc.ocl.coord);
        const mf = mol.getMF().parts.join('.');

        const toSet = {
            mf: mf
        };

        try {
            const chemcalcMF = chemcalc.analyseMF(mf);
            toSet.em = chemcalcMF.em;
            toSet.mw= chemcalcMF.mw;
            toSet.unsat= chemcalcMF.unsaturation;
            toSet.charge= chemcalcMF.charge;
            toSet.atom= mfUtil.getAtoms(chemcalcMF);
            yield collection.findOneAndUpdate({
                _id: doc._id
            }, {
                $set: toSet
            });
        } catch (e) {
            console.log('Remove fields for',doc._id);
            yield collection.findOneAndUpdate({
                _id: doc._id
            }, {
                $unset: {em:'', mw:'', unsat:'', charge:'', atom:''}
            });
        }

        done++;
    }
}).catch(function (e) {
    console.log('error');
    console.log(e);
    console.error(e);
}).then(function () {
    console.log('closing DB');
    if (db) db.close();
});
<|endoftext|>


<commit_before>var path = require('path'),
	fs = require('fs'),
	wrench = require('wrench'),
	DOMParser = require("xmldom").DOMParser,
	XMLSerializer = require("xmldom").XMLSerializer,
	_ = require('../../lib/alloy/underscore')._,
	U = require('../../utils'),
	CONST = require('../../common/constants'),
	logger = require('../../common/logger'),
	alloyRoot = path.join(__dirname,'..', '..');

function createPlugin(rootDir) {
	var plugins = path.join(rootDir,"plugins");
	U.ensureDir(plugins);

	var alloyPluginDir = path.join(plugins,"ti.alloy");
	U.ensureDir(alloyPluginDir);

	var alloyPlugin = path.join(alloyPluginDir,"plugin.py");
	var pi = path.join(alloyRoot,"plugin","plugin.py");

	U.copyFileSync(pi,alloyPlugin);
	logger.info('Deployed ti.alloy plugin to '+alloyPlugin);
}

function installPlugin(dir)
{
	createPlugin(dir);

	var tiapp = path.join(dir,'tiapp.xml');
	if (path.existsSync(tiapp))
	{
		var xml = fs.readFileSync(tiapp);
		var doc = new DOMParser().parseFromString(String(xml));
		var plugins = doc.documentElement.getElementsByTagName("plugins");
		var found = false;

		if (plugins.length > 0)
		{
			var items = plugins.item(0).getElementsByTagName('plugin');
			if (items.length > 0)
			{
				for (var c=0;c<items.length;c++)
				{
					var plugin = items.item(c);
					var name = U.XML.getNodeText(plugin);
					if (name == 'ti.alloy')
					{
						found = true;
						break;
					}
				}
			}
		}

		if (!found)
		{
			var node = doc.createElement('plugin');
			node.setAttribute('version','1.0');
			var text = doc.createTextNode('ti.alloy');
			node.appendChild(text);

			var pna = null;

			// install the plugin into tiapp.xml
			if (plugins.length == 0)
			{
				var pn = doc.createElement('plugins');
				doc.documentElement.appendChild(pn);
				doc.documentElement.appendChild(doc.createTextNode("\n"));
				pna = pn;
			}
			else
			{
				pna = plugins.item(0);
			}

			pna.appendChild(node);
			pna.appendChild(doc.createTextNode("\n"));

			var serializer = new XMLSerializer();
			var newxml = serializer.serializeToString(doc);

			fs.writeFileSync(tiapp,newxml,'utf-8');
			logger.info("Installed 'ti.alloy' plugin to "+tiapp);
		}
	}
}

function newproject(args, program) {
	var dirs = ['controllers','styles','views','models','migrations','config','assets','lib','vendor'],
		templateDir = path.join(alloyRoot,'template'),
		defaultDir = path.join(templateDir,'default'),
		INDEX_XML  = fs.readFileSync(path.join(defaultDir,'index.'+CONST.FILE_EXT.VIEW),'utf8'),
		INDEX_JSON = fs.readFileSync(path.join(defaultDir,'index.'+CONST.FILE_EXT.STYLE),'utf8'),
		INDEX_C    = fs.readFileSync(path.join(defaultDir,'index.'+CONST.FILE_EXT.CONTROLLER),'utf8'),
		README     = fs.readFileSync(path.join(templateDir, 'README'),'utf8'),
		defaultConfig = {},
		projectPath, appPath, tmpPath, alloyJmkTemplate, cfg;

	// validate args
	if (!_.isArray(args) || args.length === 0) {
		U.die("\"alloy new\" requires an [OUTPUT_DIR]");
	}

	// get app path, create if necessary
	projectPath = args[0];
	appPath = path.join(projectPath,'app');
	if (path.existsSync(appPath)) {
		if (!program.force) {
			U.die("Directory already exists at: " + appPath);
		} else {
			wrench.rmdirSyncRecursive(appPath);
		}
	}
	wrench.mkdirSyncRecursive(appPath, 0777);

	// create alloy app directories
	for (var c = 0; c < dirs.length; c++) {
		tmpPath = path.join(appPath, dirs[c]);
		if (!path.existsSync(tmpPath)) {
			wrench.mkdirSyncRecursive(tmpPath, 0777);
		}
	}

	// create default view, controller, style, and config.
	fs.writeFileSync(path.join(appPath,'views','index.'+CONST.FILE_EXT.VIEW),INDEX_XML,'utf-8');
	fs.writeFileSync(path.join(appPath,'styles','index.'+CONST.FILE_EXT.STYLE),INDEX_JSON,'utf-8');
	fs.writeFileSync(path.join(appPath,'controllers','index.'+CONST.FILE_EXT.CONTROLLER),INDEX_C,'utf-8');
	fs.writeFileSync(path.join(appPath,'alloy.'+CONST.FILE_EXT.CONFIG),U.stringifyJSON(defaultConfig),'utf-8');
	fs.writeFileSync(path.join(appPath,'README'),README,'utf-8');

	// copy in any modules
	wrench.copyDirSyncRecursive(path.join(alloyRoot,'modules'), projectPath, {preserve:true});

	// TODO: remove this once the this is merged: https://github.com/appcelerator/titanium_mobile/pull/2610
	U.installModule(projectPath, {
		id: 'ti.physicalSizeCategory',
		platform: 'android',
		version: '1.0'
	});

	// write the build file
	alloyJmkTemplate = fs.readFileSync(path.join(templateDir,'alloy.jmk'), 'utf8');
	fs.writeFileSync(path.join(appPath,'alloy.jmk'), alloyJmkTemplate,'utf-8');

	// write the project config file
	cfg = {global:{}, "env:development":{}, "env:test":{}, "env:production":{}, "os:ios":{}, "os:android":{}};
	fs.writeFileSync(path.join(appPath,"config.json"), U.stringifyJSON(cfg),'utf-8');

	// install the plugin
	installPlugin(projectPath);

	logger.info('Generated new project at: ' + appPath);
}

module.exports = newproject;<commit_msg>reduced the number of new project folders<commit_after>var path = require('path'),
	fs = require('fs'),
	wrench = require('wrench'),
	DOMParser = require("xmldom").DOMParser,
	XMLSerializer = require("xmldom").XMLSerializer,
	_ = require('../../lib/alloy/underscore')._,
	U = require('../../utils'),
	CONST = require('../../common/constants'),
	logger = require('../../common/logger'),
	alloyRoot = path.join(__dirname,'..', '..');

function createPlugin(rootDir) {
	var plugins = path.join(rootDir,"plugins");
	U.ensureDir(plugins);

	var alloyPluginDir = path.join(plugins,"ti.alloy");
	U.ensureDir(alloyPluginDir);

	var alloyPlugin = path.join(alloyPluginDir,"plugin.py");
	var pi = path.join(alloyRoot,"plugin","plugin.py");

	U.copyFileSync(pi,alloyPlugin);
	logger.info('Deployed ti.alloy plugin to '+alloyPlugin);
}

function installPlugin(dir)
{
	createPlugin(dir);

	var tiapp = path.join(dir,'tiapp.xml');
	if (path.existsSync(tiapp))
	{
		var xml = fs.readFileSync(tiapp);
		var doc = new DOMParser().parseFromString(String(xml));
		var plugins = doc.documentElement.getElementsByTagName("plugins");
		var found = false;

		if (plugins.length > 0)
		{
			var items = plugins.item(0).getElementsByTagName('plugin');
			if (items.length > 0)
			{
				for (var c=0;c<items.length;c++)
				{
					var plugin = items.item(c);
					var name = U.XML.getNodeText(plugin);
					if (name == 'ti.alloy')
					{
						found = true;
						break;
					}
				}
			}
		}

		if (!found)
		{
			var node = doc.createElement('plugin');
			node.setAttribute('version','1.0');
			var text = doc.createTextNode('ti.alloy');
			node.appendChild(text);

			var pna = null;

			// install the plugin into tiapp.xml
			if (plugins.length == 0)
			{
				var pn = doc.createElement('plugins');
				doc.documentElement.appendChild(pn);
				doc.documentElement.appendChild(doc.createTextNode("\n"));
				pna = pn;
			}
			else
			{
				pna = plugins.item(0);
			}

			pna.appendChild(node);
			pna.appendChild(doc.createTextNode("\n"));

			var serializer = new XMLSerializer();
			var newxml = serializer.serializeToString(doc);

			fs.writeFileSync(tiapp,newxml,'utf-8');
			logger.info("Installed 'ti.alloy' plugin to "+tiapp);
		}
	}
}

function newproject(args, program) {
	//var dirs = ['controllers','styles','views','models','migrations','config','assets','lib','vendor'],
	var dirs = ['controllers','styles','views','models','assets'],
		templateDir = path.join(alloyRoot,'template'),
		defaultDir = path.join(templateDir,'default'),
		INDEX_XML  = fs.readFileSync(path.join(defaultDir,'index.'+CONST.FILE_EXT.VIEW),'utf8'),
		INDEX_JSON = fs.readFileSync(path.join(defaultDir,'index.'+CONST.FILE_EXT.STYLE),'utf8'),
		INDEX_C    = fs.readFileSync(path.join(defaultDir,'index.'+CONST.FILE_EXT.CONTROLLER),'utf8'),
		README     = fs.readFileSync(path.join(templateDir, 'README'),'utf8'),
		defaultConfig = {},
		projectPath, appPath, tmpPath, alloyJmkTemplate, cfg;

	// validate args
	if (!_.isArray(args) || args.length === 0) {
		U.die("\"alloy new\" requires an [OUTPUT_DIR]");
	}

	// get app path, create if necessary
	projectPath = args[0];
	appPath = path.join(projectPath,'app');
	if (path.existsSync(appPath)) {
		if (!program.force) {
			U.die("Directory already exists at: " + appPath);
		} else {
			wrench.rmdirSyncRecursive(appPath);
		}
	}
	wrench.mkdirSyncRecursive(appPath, 0777);

	// create alloy app directories
	for (var c = 0; c < dirs.length; c++) {
		tmpPath = path.join(appPath, dirs[c]);
		if (!path.existsSync(tmpPath)) {
			wrench.mkdirSyncRecursive(tmpPath, 0777);
		}
	}

	// create default view, controller, style, and config.
	fs.writeFileSync(path.join(appPath,'views','index.'+CONST.FILE_EXT.VIEW),INDEX_XML,'utf-8');
	fs.writeFileSync(path.join(appPath,'styles','index.'+CONST.FILE_EXT.STYLE),INDEX_JSON,'utf-8');
	fs.writeFileSync(path.join(appPath,'controllers','index.'+CONST.FILE_EXT.CONTROLLER),INDEX_C,'utf-8');
	fs.writeFileSync(path.join(appPath,'alloy.'+CONST.FILE_EXT.CONFIG),U.stringifyJSON(defaultConfig),'utf-8');
	fs.writeFileSync(path.join(appPath,'README'),README,'utf-8');

	// copy in any modules
	wrench.copyDirSyncRecursive(path.join(alloyRoot,'modules'), projectPath, {preserve:true});

	// TODO: remove this once the this is merged: https://github.com/appcelerator/titanium_mobile/pull/2610
	U.installModule(projectPath, {
		id: 'ti.physicalSizeCategory',
		platform: 'android',
		version: '1.0'
	});

	// write the build file
	alloyJmkTemplate = fs.readFileSync(path.join(templateDir,'alloy.jmk'), 'utf8');
	fs.writeFileSync(path.join(appPath,'alloy.jmk'), alloyJmkTemplate,'utf-8');

	// write the project config file
	cfg = {global:{}, "env:development":{}, "env:test":{}, "env:production":{}, "os:ios":{}, "os:android":{}};
	fs.writeFileSync(path.join(appPath,"config.json"), U.stringifyJSON(cfg),'utf-8');

	// install the plugin
	installPlugin(projectPath);

	logger.info('Generated new project at: ' + appPath);
}

module.exports = newproject;<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import Immutable from 'immutable';
import {registerReducer} from '../reducers';
import {registerActionCreators} from '../actions';

require('./panel.scss');

const TOGGLE_PANEL = 'TOGGLE_PANEL';
const PANEL_DRAGGING_START = 'PANEL_DRAGGING_START';
const PANEL_DRAGGING_STOP = 'PANEL_DRAGGING_STOP';

const initialState = Immutable.fromJS({details: {dragging: false}});

function togglePanel(id) {
  return {
    type: TOGGLE_PANEL,
    id,
  };
}

function startDragging(id) {
  return {
    type: PANEL_DRAGGING_START,
    id,
  };
}

function stopDragging(id) {
  return {
    type: PANEL_DRAGGING_STOP,
    id,
  };
}

function panel(state = initialState, action) {
  switch (action.type) {
  case TOGGLE_PANEL:
    return state.update(action.id, v => !v);
  case PANEL_DRAGGING_START:
    return state.update(action.id, v => v.set('dragging', true));
  case PANEL_DRAGGING_STOP:
    return state.update(action.id, v => v.set('dragging', false));
  default:
    return state;
  }
}

registerReducer('panel', panel);
registerActionCreators({togglePanel, startDragging, stopDragging});

export default class Panel extends React.Component {

  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    const node = ReactDOM.findDOMNode(this);
    this.onMouseMove = (e) => {
      const panelProps = this.props.panel.get(this.props.id);

      if (panelProps.get('dragging')) {
        const styles = window.getComputedStyle(node);
        const height = styles.height.replace('px', '');

        const newHeight = height - e.movementY;
        this.setState({height: newHeight});
      }
    };
    document.addEventListener('mousemove', (e) => this.onMouseMove(e));
    document.addEventListener('mouseup', () => this.onMouseUp());
  }

  componentWillUnmount() {
    document.removeEventListener('mousemove', this.onMouseMove);
    document.removeEventListener('mouseup', this.onMouseUp);
  }

  onMouseUp() {
    this.props.actions.stopDragging(this.props.id);
  }

  render() {
    const height = this.state.height;
    const style = height
                ? {height: height}
                : {};

    return (

 this.props.actions.startDragging(this.props.id)}
           onClick={() => this.props.actions.togglePanel(this.props.id)}>

          {this.props.children}

);
  }
}

Panel.propTypes = {
  id: React.PropTypes.string.isRequired,
  panel: React.PropTypes.object,
  actions: React.PropTypes.object,
  children: React.PropTypes.node.isRequired,
};
<commit_msg>Resizing of panel used through reducers<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import Immutable from 'immutable';
import {registerReducer} from '../reducers';
import {registerActionCreators} from '../actions';

require('./panel.scss');

const TOGGLE_PANEL = 'TOGGLE_PANEL';
const PANEL_DRAGGING_START = 'PANEL_DRAGGING_START';
const PANEL_DRAGGING_STOP = 'PANEL_DRAGGING_STOP';
const PANEL_DRAGGING = 'PANEL_DRAGGING';

const initialState = Immutable.fromJS({details: {dragging: false}});

function togglePanel(id) {
  return {
    type: TOGGLE_PANEL,
    id,
  };
}

function startDragging(id) {
  return {
    type: PANEL_DRAGGING_START,
    id,
  };
}

function stopDragging(id) {
  return {
    type: PANEL_DRAGGING_STOP,
    id,
  };
}

function panelDragging(id, height) {
  return {
    type: PANEL_DRAGGING,
    id,
    height,
  };
}

function panel(state = initialState, action) {
  switch (action.type) {
  case TOGGLE_PANEL:
    return state;
  case PANEL_DRAGGING_START:
    return state.update(action.id, v => v.set('dragging', true));
  case PANEL_DRAGGING_STOP:
    return state.update(action.id, v => v.set('dragging', false));
  case PANEL_DRAGGING:
    return state.update(action.id, v => v.set('height', action.height));
  default:
    return state;
  }
}

registerReducer('panel', panel);
registerActionCreators({togglePanel, startDragging, stopDragging, panelDragging});

export default class Panel extends React.Component {

  constructor(props) {
    super(props);
    this.state = {};
  }

  componentDidMount() {
    const node = ReactDOM.findDOMNode(this);
    this.onMouseMove = (e) => {
      const panelProps = this.props.panel.get(this.props.id);

      if (panelProps.get('dragging')) {
        const styles = window.getComputedStyle(node);
        const height = styles.height.replace('px', '');

        const newHeight = height - e.movementY;
        this.props.actions.panelDragging(this.props.id, newHeight);
      }
    };

    document.addEventListener('mousemove', (e) => this.onMouseMove(e));
    document.addEventListener('mouseup', () => this.onMouseUp());
  }

  componentWillUnmount() {
    document.removeEventListener('mousemove', this.onMouseMove);
    document.removeEventListener('mouseup', this.onMouseUp);
  }

  onMouseUp() {
    this.props.actions.stopDragging(this.props.id);
  }

  startDragging(e, id) {
    e.preventDefault();
    this.props.actions.startDragging(id);
  }

  render() {
    const panelProps = this.props.panel.get(this.props.id);
    const style = panelProps && panelProps.has('height')
                ? {height: panelProps.get('height')}
                : {};

    return (

 this.startDragging(e, this.props.id)}
           onDoubleClick={() => this.props.actions.togglePanel(this.props.id)}>

          {this.props.children}

);
  }
}

Panel.propTypes = {
  id: React.PropTypes.string.isRequired,
  panel: React.PropTypes.object,
  actions: React.PropTypes.object,
  children: React.PropTypes.node.isRequired,
};
<|endoftext|>