<commit_before>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var _ = require('lodash');

/*
 * post process to hook through SGs not direct to images if sgs exist
 * currenly assumes just 1 or 0 security groups
 */
module.exports = function postProcessing (system) {

  return function postProcessing(config, result, cb) {
    var containers = result.topology.containers;
    var elbs = _.filter(containers, function(container) { return container.type === 'aws-elb'; });
    var machines = _.filter(containers, function(container) { return container.type === 'aws-ami'; });
    var isAutoscaling = function(container) { return container.type === 'aws-autoscaling'; };
    var autoScalingGroups = _.filter(containers,  isAutoscaling);
    var newContains;

    _.each(machines, function(machine) {
      if (machine.specific && machine.specific.securityGroups && machine.specific.securityGroups.length > 0) {
        var sg = _.find(containers, function(c) { return c.nativeId === machine.specific.securityGroups[0].GroupId; });
        if (sg) {
          machine.containedBy = sg.id;
          containers[sg.id].contains.push(machine.id);
        }
        else {
          machine.containedBy = machine.specific.securityGroups[0].GroupId;
          containers[machine.specific.securityGroups[0].GroupId].contains.push(machine.id);
        }
      }
    });

    _.forEach(elbs, function(elb) {
      newContains = [];
      _.forEach(elb.contains, function(instanceId) {
        if (containers[instanceId]) {
          if (containers[instanceId].containedBy) {
            newContains.push(containers[instanceId].containedBy);
            containers[containers[instanceId].containedBy].containedBy = elb.id;
          }
          else {
            newContains.push(instanceId);
            containers[instanceId].containedBy = elb.id;
          }
        }
      });
      elb.contains = _.uniq(newContains);
    });

    _.forEach(containers, function(cont) {
      if (!cont.containedBy) {
        cont.containedBy = cont.id;
      }
    });

    _.forEach(autoScalingGroups, function (cont) {
      var newContains = [];
      var systemAwsAutoScaling = _.filter(system.topology.containers, isAutoscaling);
      var systemAwsAutoScalingContains = systemAwsAutoScaling[0].contains[0];

      _.forEach(cont.contains, function (instanceId) {

        var container = containers[instanceId];
        container.id = container.id.replace('i-', systemAwsAutoScalingContains + '-');
        delete containers[instanceId];

        containers[container.id] = container;

        var containedBys = _.filter(containers, function (container) { return container.containedBy === instanceId;});
        _.forEach(containedBys, function (cont) {
          cont.containedBy = container.id;
        });

        newContains.push(container.id);

      });

      cont.contains = newContains;
    });

    cb();
  };
};

<commit_msg>Add awsSg handling<commit_after>/*
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

'use strict';

var _ = require('lodash');

/*
 * post process to hook through SGs not direct to images if sgs exist
 * currenly assumes just 1 or 0 security groups
 */
module.exports = function postProcessing (system) {

  function handleAutoScalingGroups (result) {
    var containers = result.topology.containers;
    var isAutoscaling = function(container) { return container.type === 'aws-autoscaling'; };
    var autoScalingGroups = _.filter(containers,  isAutoscaling);

    _.forEach(autoScalingGroups, function (cont) {
      var newContains = [];
      var sysContainers = system.topology.containers;
      var sysAwsAutoScalings = _.filter(sysContainers, isAutoscaling);

      _.forEach(sysAwsAutoScalings, function (sysAwsAutoScaling) {
        var sysAwsAutoScalingParent = sysContainers[sysAwsAutoScaling.containedBy];

        // if there is a security group container in the system we should
        // add it also in the analyzer result
        // ie: system contains   elb -> sg -> autoscaling
        //     analyzer returns  elb -> autoscaling
        //
        if (sysAwsAutoScalingParent.type === 'aws-sg') {
          var awsAutoScaling = containers[sysAwsAutoScaling.id];
          var awsAutoScalingParent = containers[awsAutoScaling.containedBy];

          var awsSg = containers[sysAwsAutoScalingParent.id];

          // Remove AutoScaling child
          _.remove(awsAutoScalingParent.contains, function (ele) {
            return ele === awsAutoScaling.id;
          });

          awsAutoScalingParent.contains.push(sysAwsAutoScalingParent.id);
          awsAutoScaling.containedBy = sysAwsAutoScalingParent.id;
          awsSg.containedBy = awsAutoScalingParent.id;
          awsSg.contains = _(awsSg.contains).push(awsAutoScaling.id).uniq().value();

        }
      });

      // The autoscaling is supposed to have a single AMachine child
      var sysAwsAutoScalingChild = sysAwsAutoScalings[0].contains[0];
      _.forEach(cont.contains, function (instanceId) {

        var container = containers[instanceId];
        container.id = container.id.replace('i-', sysAwsAutoScalingChild + '-');
        delete containers[instanceId];

        containers[container.id] = container;

        var containedBys = _.filter(containers, function (container) { return container.containedBy === instanceId;});
        _.forEach(containedBys, function (cont) {
          cont.containedBy = container.id;
        });

        newContains.push(container.id);

      });

      cont.contains = newContains;
    });
  }

  return function postProcessing(config, result, cb) {
    var containers = result.topology.containers;
    var elbs = _.filter(containers, function(container) { return container.type === 'aws-elb'; });
    var machines = _.filter(containers, function(container) { return container.type === 'aws-ami'; });
    var newContains;

    _.each(machines, function(machine) {
      if (machine.specific && machine.specific.securityGroups && machine.specific.securityGroups.length > 0) {
        var sg = _.find(containers, function(c) { return c.nativeId === machine.specific.securityGroups[0].GroupId; });
        if (sg) {
          machine.containedBy = sg.id;
          containers[sg.id].contains.push(machine.id);
        }
        else {
          machine.containedBy = machine.specific.securityGroups[0].GroupId;
          containers[machine.specific.securityGroups[0].GroupId].contains.push(machine.id);
        }
      }
    });

    _.forEach(elbs, function(elb) {
      newContains = [];
      _.forEach(elb.contains, function(instanceId) {
        if (containers[instanceId]) {
          if (containers[instanceId].containedBy) {
            newContains.push(containers[instanceId].containedBy);
            containers[containers[instanceId].containedBy].containedBy = elb.id;
          }
          else {
            newContains.push(instanceId);
            containers[instanceId].containedBy = elb.id;
          }
        }
      });
      elb.contains = _.uniq(newContains);
    });

    _.forEach(containers, function(cont) {
      if (!cont.containedBy) {
        cont.containedBy = cont.id;
      }
    });

    handleAutoScalingGroups(result);

    cb();
  };
};

<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
//  Copyright (C) 2013  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// WidgetModel, WidgetView, and WidgetManager
//============================================================================
/**
 * Base Widget classes
 * @module IPython
 * @namespace IPython
 * @submodule widget
 */

"use strict";

// Use require.js 'define' method so that require.js is intelligent enough to
// syncronously load everything within this file when it is being 'required'
// elsewhere.
define(["components/underscore/underscore-min",
         "components/backbone/backbone-min",
        ], function(){

    // Only run once on a notebook.
    if (IPython.notebook.widget_manager == undefined) {

        //--------------------------------------------------------------------
        // WidgetModel class
        //--------------------------------------------------------------------
        var WidgetModel = Backbone.Model.extend({
            constructor: function(comm_manager, comm, widget_view_types) {
                this.comm_manager = comm_manager;
                this.widget_view_types = widget_view_types;
                this.pending_msgs = 0;
                this.msg_throttle = 3;
                this.msg_buffer = {};
                this.views = {};

                // Remember comm associated with the model.
                this.comm = comm;
                comm.model = this;

                // Hook comm messages up to model.
                comm.on_close($.proxy(this.handle_comm_closed, this));
                comm.on_msg($.proxy(this.handle_comm_msg, this));

                return Backbone.Model.apply(this);
            },

            update_other_views: function(caller) {
                this.last_modified_view = caller;
                this.save(this.changedAttributes(), {patch: true});

                for (var output_area in this.views) {
                    var views = this.views[output_area];
                    for (var view_index in views) {
                        var view = views[view_index];
                        if (view !== caller) {
                            view.update();
                        }
                    }
                }
            },

            handle_status: function (output_area, msg) {
                //execution_state : ('busy', 'idle', 'starting')
                if (msg.content.execution_state=='idle') {

                    // Send buffer if this message caused another message to be
                    // throttled.
                    if (this.msg_throttle == this.pending_msgs &&
                        this.msg_buffer.length > 0) {

                        var output_area = this._get_msg_output_area(msg);
                        var callbacks = this._make_callbacks(output_area);
                        var data = {sync_method: 'patch', sync_data: this.msg_buffer};
                        comm.send(data, callbacks);
                        this.msg_buffer = {};
                    } else {

                        // Only decrease the pending message count if the buffer
                        // doesn't get flushed (sent).
                        --this.pending_msgs;
                    }
                }
            },

            // Custom syncronization logic.
            handle_sync: function (method, options) {
                var model_json = this.toJSON();

                // Only send updated state if the state hasn't been changed
                // during an update.
                if (!this.updating) {
                    if (this.pending_msgs >= this.msg_throttle) {
                        // The throttle has been exceeded, buffer the current msg so
                        // it can be sent once the kernel has finished processing
                        // some of the existing messages.
                        if (method=='patch') {
                            for (var attr in options.attrs) {
                                this.msg_buffer[attr] = options.attrs[attr];
                            }
                        } else {
                            this.msg_buffer = $.extend({}, model_json); // Copy
                        }

                    } else {
                        // We haven't exceeded the throttle, send the message like
                        // normal.  If this is a patch operation, just send the
                        // changes.
                        var send_json = model_json;
                        if (method=='patch') {
                            send_json = {};
                            for (var attr in options.attrs) {
                                send_json[attr] = options.attrs[attr];
                            }
                        }

                        var data = {sync_method: method, sync_data: send_json};
                        var output_area = this.last_modified_view.output_area;
                        var callbacks = this._make_callbacks(output_area);
                        this.comm.send(data, callbacks);
                        this.pending_msgs++;
                    }
                }

                // Since the comm is a one-way communication, assume the message
                // arrived.
                return model_json;
            },

            // Handle incomming comm msg.
            handle_comm_msg: function (msg) {
                var method = msg.content.data.method;
                switch (method){
                    case 'display':

                        // Try to get the cell index.
                        var output_area = this._get_output_area(msg.parent_header.msg_id);
                        if (output_area == null) {
                            console.log("Could not determine where the display" +
                                " message was from.  Widget will not be displayed")
                        } else {
                            this.display_view(msg.content.data.view_name,
                            msg.content.data.parent,
                            output_area);
                        }
                        break;
                    case 'update':
                        this.handle_update(msg.content.data.state);
                        break;
                }
            },

            // Handle when a widget is updated via the python side.
            handle_update: function (state) {
                this.updating = true;
                try {
                    for (var key in state) {
                        if (state.hasOwnProperty(key)) {
                            if (key == "_css"){
                                this.css = state[key];
                            } else {
                                this.set(key, state[key]);
                            }
                        }
                    }
                    this.id = this.comm.comm_id;
                    this.save();
                } finally {
                    this.updating = false;
                }
            },

            // Handle when a widget is closed.
            handle_comm_closed: function (msg) {
                for (var output_area in this.views) {
                    var views = this.views[output_area];
                    for (var view_index in views) {
                        var view = views[view_index];
                        view.remove();
                    }
                }
            },

            // Create view that represents the model.
            display_view: function (view_name, parent_comm_id, output_area) {
                var new_views = [];

                var displayed = false;
                if (parent_comm_id != undefined) {
                    var parent_comm = this.comm_manager.comms[parent_comm_id];
                    var parent_model = parent_comm.model;
                    var parent_views = parent_model.views[output_area];
                    for (var parent_view_index in parent_views) {
                        var parent_view = parent_views[parent_view_index];
                        if (parent_view.display_child != undefined) {
                            var view = this._create_view(view_name, output_area);
                            new_views.push(view);
                            parent_view.display_child(view);
                            displayed = true;
                        }
                    }
                }

                if (!displayed) {
                    // No parent view is defined or exists.  Add the view's
                    // element to cell's widget div.
                    var view = this._create_view(view_name, output_area);
                    new_views.push(view);
                    this._get_widget_area_element(output_area, true)
                        .append(view.$el);

                }

                for (var view_index in new_views) {
                    var view = new_views[view_index];
                    view.update();
                }
            },

            // Create a view
            _create_view: function (view_name, output_area) {
                var view = new this.widget_view_types[view_name]({model: this});
                view.render();
                if (this.views[output_area]==undefined) {
                    this.views[output_area] = []
                }
                this.views[output_area].push(view);
                view.output_area = output_area;

                // Handle when the view element is remove from the page.
                var that = this;
                view.$el.on("remove", function(){
                    var index = that.views[output_area].indexOf(view);
                    if (index > -1) {
                        that.views[output_area].splice(index, 1);
                    }
                    view.remove(); // Clean-up view
                    if (that.views[output_area].length()==0) {
                        delete that.views[output_area];
                    }

                    // Close the comm if there are no views left.
                    if (that.views.length()==0) {
                        that.comm.close();
                    }
                });
                return view;
            },

            // Build a callback dict.
            _make_callbacks: function (output_area) {
                var callbacks = {};
                if (output_area != null) {
                    var that = this;
                    callbacks = {
                        iopub : {
                            output : $.proxy(output_area.handle_output, output_area),
                            clear_output : $.proxy(output_area.handle_clear_output, output_area),
                            status : function(msg){
                                that.handle_status(output_area, msg);
                            },
                            get_output_area : function() {
                                if (that.last_modified_view != undefined &&
                                    that.last_modified_view.output_area != undefined) {
                                    return that.last_modified_view.output_area;
                                } else {
                                    return null
                                }
                            },
                        },
                    };
                }
                return callbacks;
            },

            // Get the output area corresponding to the msg_id.
            // output_area is an instance of
            _get_output_area: function (msg_id) {

                // First, guess cell.execute triggered
                var cells = IPython.notebook.get_cells();
                for (var cell_index in cells) {
                    if (cells[cell_index].last_msg_id == msg_id) {
                        var cell = IPython.notebook.get_cell(cell_index)
                        return cell.output_area;
                    }
                }

                // Second, guess widget triggered
                var callbacks = this.comm_manager.kernel.get_callbacks_for_msg(msg_id)
                if (callbacks != undefined && callbacks.iopub != undefined && callbacks.iopub.get_output_area != undefined) {
                    var output_area = callbacks.iopub.get_output_area();
                    if (output_area != null) {
                        return output_area;
                    }
                }

                // Not triggered by a widget or a cell
                return null;
            },

            // Gets widget output area (as a JQuery element) from the
            // output_area (Ipython.OutputArea instance)
            _get_widget_area_element: function (output_area, show) {
                var widget_area = output_area.element
                    .parent() // output_wrapper
                    .parent() // cell
                    .find('.widget-area');
                if (show) { widget_area.show(); }
                return widget_area.find('.widget-subarea');
            },

        });

        //--------------------------------------------------------------------
        // WidgetView class
        //--------------------------------------------------------------------
        var WidgetView = Backbone.View.extend({

            initialize: function() {
                this.visible = true;
                this.model.on('change',this.update,this);
                this._add_class_calls = this.model.get('_add_class')[0];
                this._remove_class_calls = this.model.get('_remove_class')[0];
            },

            update: function() {
                if (this.model.get('visible') != undefined) {
                    if (this.visible != this.model.get('visible')) {
                        this.visible = this.model.get('visible');
                        if (this.visible) {
                            this.$el.show();
                        } else {
                            this.$el.hide();
                        }
                    }
                }

                if (this.model.css != undefined) {
                    for (var selector in this.model.css) {
                        if (this.model.css.hasOwnProperty(selector)) {

                            // Apply the css traits to all elements that match the selector.
                            var elements = this.get_selector_element(selector);
                            if (elements.length > 0) {
                                var css_traits = this.model.css[selector];
                                for (var css_key in css_traits) {
                                    if (css_traits.hasOwnProperty(css_key)) {
                                        elements.css(css_key, css_traits[css_key]);
                                    }
                                }
                            }
                        }
                    }
                }

                var add_class = this.model.get('_add_class');
                if (add_class != undefined){
                    var add_class_calls = add_class[0];
                    if (add_class_calls > this._add_class_calls) {
                        this._add_class_calls = add_class_calls;
                        var elements = this.get_selector_element(add_class[1]);
                        if (elements.length > 0) {
                            elements.addClass(add_class[2]);
                        }
                    }
                }

                var remove_class = this.model.get('_remove_class');
                if (remove_class != undefined){
                    var remove_class_calls = remove_class[0];
                    if (remove_class_calls > this._remove_class_calls) {
                        this._remove_class_calls = remove_class_calls;
                        var elements = this.get_selector_element(remove_class[1]);
                        if (elements.length > 0) {
                            elements.removeClass(remove_class[2]);
                        }
                    }
                }
            },

            get_selector_element: function(selector) {
                // Get the elements via the css selector.  If the selector is
                // blank, apply the style to the $el_to_style element.  If
                // the $el_to_style element is not defined, use apply the
                // style to the view's element.
                var elements = this.$el.find(selector);
                if (selector=='') {
                    if (this.$el_to_style == undefined) {
                        elements = this.$el;
                    } else {
                        elements = this.$el_to_style;
                    }
                }
                return elements;
            },
        });

        //--------------------------------------------------------------------
        // WidgetManager class
        //--------------------------------------------------------------------
        var WidgetManager = function(comm_manager){
            this.comm_manager = comm_manager;
            this.widget_model_types = {};
            this.widget_view_types = {};

            var that = this;
            Backbone.sync = function(method, model, options, error) {
                var result = model.handle_sync(method, options);
                if (options.success) {
                  options.success(result);
                }
            };
        }

        WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
            // Register the widget with the comm manager.  Make sure to pass this object's context
            // in so `this` works in the call back.
            this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));
            this.widget_model_types[widget_model_name] = widget_model_type;
        }

        WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
            this.widget_view_types[widget_view_name] = widget_view_type;
        }

        WidgetManager.prototype.handle_com_open = function (comm, msg) {
            var widget_type_name = msg.content.target_name;
            var widget_model = new this.widget_model_types[widget_type_name](this.comm_manager, comm, this.widget_view_types);
        }

        //--------------------------------------------------------------------
        // Init code
        //--------------------------------------------------------------------
        IPython.WidgetManager = WidgetManager;
        IPython.WidgetModel = WidgetModel;
        IPython.WidgetView = WidgetView;

        IPython.notebook.widget_manager = new WidgetManager(IPython.notebook.kernel.comm_manager);

    };
});
<commit_msg>Fixed comment in widget.js<commit_after>//----------------------------------------------------------------------------
//  Copyright (C) 2013  The IPython Development Team
//
//  Distributed under the terms of the BSD License.  The full license is in
//  the file COPYING, distributed as part of this software.
//----------------------------------------------------------------------------

//============================================================================
// WidgetModel, WidgetView, and WidgetManager
//============================================================================
/**
 * Base Widget classes
 * @module IPython
 * @namespace IPython
 * @submodule widget
 */

"use strict";

// Use require.js 'define' method so that require.js is intelligent enough to
// syncronously load everything within this file when it is being 'required'
// elsewhere.
define(["components/underscore/underscore-min",
         "components/backbone/backbone-min",
        ], function(){

    // Only run once on a notebook.
    if (IPython.notebook.widget_manager == undefined) {

        //--------------------------------------------------------------------
        // WidgetModel class
        //--------------------------------------------------------------------
        var WidgetModel = Backbone.Model.extend({
            constructor: function(comm_manager, comm, widget_view_types) {
                this.comm_manager = comm_manager;
                this.widget_view_types = widget_view_types;
                this.pending_msgs = 0;
                this.msg_throttle = 3;
                this.msg_buffer = {};
                this.views = {};

                // Remember comm associated with the model.
                this.comm = comm;
                comm.model = this;

                // Hook comm messages up to model.
                comm.on_close($.proxy(this.handle_comm_closed, this));
                comm.on_msg($.proxy(this.handle_comm_msg, this));

                return Backbone.Model.apply(this);
            },

            update_other_views: function(caller) {
                this.last_modified_view = caller;
                this.save(this.changedAttributes(), {patch: true});

                for (var output_area in this.views) {
                    var views = this.views[output_area];
                    for (var view_index in views) {
                        var view = views[view_index];
                        if (view !== caller) {
                            view.update();
                        }
                    }
                }
            },

            handle_status: function (output_area, msg) {
                //execution_state : ('busy', 'idle', 'starting')
                if (msg.content.execution_state=='idle') {

                    // Send buffer if this message caused another message to be
                    // throttled.
                    if (this.msg_throttle == this.pending_msgs &&
                        this.msg_buffer.length > 0) {

                        var output_area = this._get_msg_output_area(msg);
                        var callbacks = this._make_callbacks(output_area);
                        var data = {sync_method: 'patch', sync_data: this.msg_buffer};
                        comm.send(data, callbacks);
                        this.msg_buffer = {};
                    } else {

                        // Only decrease the pending message count if the buffer
                        // doesn't get flushed (sent).
                        --this.pending_msgs;
                    }
                }
            },

            // Custom syncronization logic.
            handle_sync: function (method, options) {
                var model_json = this.toJSON();

                // Only send updated state if the state hasn't been changed
                // during an update.
                if (!this.updating) {
                    if (this.pending_msgs >= this.msg_throttle) {
                        // The throttle has been exceeded, buffer the current msg so
                        // it can be sent once the kernel has finished processing
                        // some of the existing messages.
                        if (method=='patch') {
                            for (var attr in options.attrs) {
                                this.msg_buffer[attr] = options.attrs[attr];
                            }
                        } else {
                            this.msg_buffer = $.extend({}, model_json); // Copy
                        }

                    } else {
                        // We haven't exceeded the throttle, send the message like
                        // normal.  If this is a patch operation, just send the
                        // changes.
                        var send_json = model_json;
                        if (method=='patch') {
                            send_json = {};
                            for (var attr in options.attrs) {
                                send_json[attr] = options.attrs[attr];
                            }
                        }

                        var data = {sync_method: method, sync_data: send_json};
                        var output_area = this.last_modified_view.output_area;
                        var callbacks = this._make_callbacks(output_area);
                        this.comm.send(data, callbacks);
                        this.pending_msgs++;
                    }
                }

                // Since the comm is a one-way communication, assume the message
                // arrived.
                return model_json;
            },

            // Handle incomming comm msg.
            handle_comm_msg: function (msg) {
                var method = msg.content.data.method;
                switch (method){
                    case 'display':

                        // Try to get the cell index.
                        var output_area = this._get_output_area(msg.parent_header.msg_id);
                        if (output_area == null) {
                            console.log("Could not determine where the display" +
                                " message was from.  Widget will not be displayed")
                        } else {
                            this.display_view(msg.content.data.view_name,
                            msg.content.data.parent,
                            output_area);
                        }
                        break;
                    case 'update':
                        this.handle_update(msg.content.data.state);
                        break;
                }
            },

            // Handle when a widget is updated via the python side.
            handle_update: function (state) {
                this.updating = true;
                try {
                    for (var key in state) {
                        if (state.hasOwnProperty(key)) {
                            if (key == "_css"){
                                this.css = state[key];
                            } else {
                                this.set(key, state[key]);
                            }
                        }
                    }
                    this.id = this.comm.comm_id;
                    this.save();
                } finally {
                    this.updating = false;
                }
            },

            // Handle when a widget is closed.
            handle_comm_closed: function (msg) {
                for (var output_area in this.views) {
                    var views = this.views[output_area];
                    for (var view_index in views) {
                        var view = views[view_index];
                        view.remove();
                    }
                }
            },

            // Create view that represents the model.
            display_view: function (view_name, parent_comm_id, output_area) {
                var new_views = [];

                var displayed = false;
                if (parent_comm_id != undefined) {
                    var parent_comm = this.comm_manager.comms[parent_comm_id];
                    var parent_model = parent_comm.model;
                    var parent_views = parent_model.views[output_area];
                    for (var parent_view_index in parent_views) {
                        var parent_view = parent_views[parent_view_index];
                        if (parent_view.display_child != undefined) {
                            var view = this._create_view(view_name, output_area);
                            new_views.push(view);
                            parent_view.display_child(view);
                            displayed = true;
                        }
                    }
                }

                if (!displayed) {
                    // No parent view is defined or exists.  Add the view's
                    // element to cell's widget div.
                    var view = this._create_view(view_name, output_area);
                    new_views.push(view);
                    this._get_widget_area_element(output_area, true)
                        .append(view.$el);

                }

                for (var view_index in new_views) {
                    var view = new_views[view_index];
                    view.update();
                }
            },

            // Create a view
            _create_view: function (view_name, output_area) {
                var view = new this.widget_view_types[view_name]({model: this});
                view.render();
                if (this.views[output_area]==undefined) {
                    this.views[output_area] = []
                }
                this.views[output_area].push(view);
                view.output_area = output_area;

                // Handle when the view element is remove from the page.
                var that = this;
                view.$el.on("remove", function(){
                    var index = that.views[output_area].indexOf(view);
                    if (index > -1) {
                        that.views[output_area].splice(index, 1);
                    }
                    view.remove(); // Clean-up view
                    if (that.views[output_area].length()==0) {
                        delete that.views[output_area];
                    }

                    // Close the comm if there are no views left.
                    if (that.views.length()==0) {
                        that.comm.close();
                    }
                });
                return view;
            },

            // Build a callback dict.
            _make_callbacks: function (output_area) {
                var callbacks = {};
                if (output_area != null) {
                    var that = this;
                    callbacks = {
                        iopub : {
                            output : $.proxy(output_area.handle_output, output_area),
                            clear_output : $.proxy(output_area.handle_clear_output, output_area),
                            status : function(msg){
                                that.handle_status(output_area, msg);
                            },
                            get_output_area : function() {
                                if (that.last_modified_view != undefined &&
                                    that.last_modified_view.output_area != undefined) {
                                    return that.last_modified_view.output_area;
                                } else {
                                    return null
                                }
                            },
                        },
                    };
                }
                return callbacks;
            },

            // Get the output area corresponding to the msg_id.
            // output_area is an instance of Ipython.OutputArea
            _get_output_area: function (msg_id) {

                // First, guess cell.execute triggered
                var cells = IPython.notebook.get_cells();
                for (var cell_index in cells) {
                    if (cells[cell_index].last_msg_id == msg_id) {
                        var cell = IPython.notebook.get_cell(cell_index)
                        return cell.output_area;
                    }
                }

                // Second, guess widget triggered
                var callbacks = this.comm_manager.kernel.get_callbacks_for_msg(msg_id)
                if (callbacks != undefined && callbacks.iopub != undefined && callbacks.iopub.get_output_area != undefined) {
                    var output_area = callbacks.iopub.get_output_area();
                    if (output_area != null) {
                        return output_area;
                    }
                }

                // Not triggered by a widget or a cell
                return null;
            },

            // Gets widget output area (as a JQuery element) from the
            // output_area (Ipython.OutputArea instance)
            _get_widget_area_element: function (output_area, show) {
                var widget_area = output_area.element
                    .parent() // output_wrapper
                    .parent() // cell
                    .find('.widget-area');
                if (show) { widget_area.show(); }
                return widget_area.find('.widget-subarea');
            },

        });

        //--------------------------------------------------------------------
        // WidgetView class
        //--------------------------------------------------------------------
        var WidgetView = Backbone.View.extend({

            initialize: function() {
                this.visible = true;
                this.model.on('change',this.update,this);
                this._add_class_calls = this.model.get('_add_class')[0];
                this._remove_class_calls = this.model.get('_remove_class')[0];
            },

            update: function() {
                if (this.model.get('visible') != undefined) {
                    if (this.visible != this.model.get('visible')) {
                        this.visible = this.model.get('visible');
                        if (this.visible) {
                            this.$el.show();
                        } else {
                            this.$el.hide();
                        }
                    }
                }

                if (this.model.css != undefined) {
                    for (var selector in this.model.css) {
                        if (this.model.css.hasOwnProperty(selector)) {

                            // Apply the css traits to all elements that match the selector.
                            var elements = this.get_selector_element(selector);
                            if (elements.length > 0) {
                                var css_traits = this.model.css[selector];
                                for (var css_key in css_traits) {
                                    if (css_traits.hasOwnProperty(css_key)) {
                                        elements.css(css_key, css_traits[css_key]);
                                    }
                                }
                            }
                        }
                    }
                }

                var add_class = this.model.get('_add_class');
                if (add_class != undefined){
                    var add_class_calls = add_class[0];
                    if (add_class_calls > this._add_class_calls) {
                        this._add_class_calls = add_class_calls;
                        var elements = this.get_selector_element(add_class[1]);
                        if (elements.length > 0) {
                            elements.addClass(add_class[2]);
                        }
                    }
                }

                var remove_class = this.model.get('_remove_class');
                if (remove_class != undefined){
                    var remove_class_calls = remove_class[0];
                    if (remove_class_calls > this._remove_class_calls) {
                        this._remove_class_calls = remove_class_calls;
                        var elements = this.get_selector_element(remove_class[1]);
                        if (elements.length > 0) {
                            elements.removeClass(remove_class[2]);
                        }
                    }
                }
            },

            get_selector_element: function(selector) {
                // Get the elements via the css selector.  If the selector is
                // blank, apply the style to the $el_to_style element.  If
                // the $el_to_style element is not defined, use apply the
                // style to the view's element.
                var elements = this.$el.find(selector);
                if (selector=='') {
                    if (this.$el_to_style == undefined) {
                        elements = this.$el;
                    } else {
                        elements = this.$el_to_style;
                    }
                }
                return elements;
            },
        });

        //--------------------------------------------------------------------
        // WidgetManager class
        //--------------------------------------------------------------------
        var WidgetManager = function(comm_manager){
            this.comm_manager = comm_manager;
            this.widget_model_types = {};
            this.widget_view_types = {};

            var that = this;
            Backbone.sync = function(method, model, options, error) {
                var result = model.handle_sync(method, options);
                if (options.success) {
                  options.success(result);
                }
            };
        }

        WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
            // Register the widget with the comm manager.  Make sure to pass this object's context
            // in so `this` works in the call back.
            this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this));
            this.widget_model_types[widget_model_name] = widget_model_type;
        }

        WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
            this.widget_view_types[widget_view_name] = widget_view_type;
        }

        WidgetManager.prototype.handle_com_open = function (comm, msg) {
            var widget_type_name = msg.content.target_name;
            var widget_model = new this.widget_model_types[widget_type_name](this.comm_manager, comm, this.widget_view_types);
        }

        //--------------------------------------------------------------------
        // Init code
        //--------------------------------------------------------------------
        IPython.WidgetManager = WidgetManager;
        IPython.WidgetModel = WidgetModel;
        IPython.WidgetView = WidgetView;

        IPython.notebook.widget_manager = new WidgetManager(IPython.notebook.kernel.comm_manager);

    };
});
<|endoftext|>


<commit_before>/*
   Copyright 2016 Sergi Vladykin (https://github.com/svladykin)

   Version 1.0

   The latest version can be found at https://github.com/NashornTools

   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
*/

var NnClassLoader = (function () {

var DEBUG = java.lang.Boolean.getBoolean('NnClassLoader.debug');

var MAVEN_VERSION = '3.3.9';
var MAVEN_MD5 = 'e7ebd0b8d6811b42a5dad91fb27fe9b4';
var MAVERN_URLS = [
	'http://www-us.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'http://www-eu.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'https://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
];

var Class = java.lang.Class;
var URL = java.net.URL;
var File = java.io.File;
var Files = java.nio.file.Files;
var SCO = java.nio.file.StandardCopyOption;
var System = java.lang.System;
var Thread = java.lang.Thread;

var JAVA_VERSION = System.getProperty("java.specification.version");

var StaticClass = Java.type(JAVA_VERSION === '1.8' ? 'jdk.internal.dynalink.beans.StaticClass' : 'jdk.dynalink.beans.StaticClass');

var WORK_DIR = path(System.getProperty("user.home"), '.mvn_js');
var MVN = path(WORK_DIR, 'mvn-' + MAVEN_VERSION);
var MVN_HOME = path(MVN, 'apache-maven-' + MAVEN_VERSION);
var MVN_LIB = path(MVN_HOME , 'lib');
var MVN_BOOT = path(MVN_HOME, 'boot');

function path() {
	var args = Array.prototype.slice.call(arguments); // Convert to array.

	return args.join(File.separator);
}

function debug(str) {
	if (DEBUG)
		System.out.println(str);
}

function file(pathStr) {
	return new File(pathStr);
}

function isDefined(o) {
	return typeof(o) !== 'undefined';
}

function isObject(o) { // Will return true for arrays as well.
	return typeof(o) === 'object';
}

function download(url, filePath) {
	var tmpFile = file(filePath + '.tmp');
	var input = null;

	try {
		input = new URL(url).openConnection().getInputStream();

		tmpFile.createNewFile();

		Files.copy(input, tmpFile.toPath(), SCO.REPLACE_EXISTING);
	}
	catch (e) {
		rm(tmpFile);

		throw e;
	}
	finally {
		if (input != null)
			input.close();
	}

	Files.move(tmpFile.toPath(), file(filePath).toPath(), SCO.REPLACE_EXISTING, SCO.ATOMIC_MOVE);
}

function rm(f) {
	if (!f.exists())
		return;

	if (f.isDirectory()) {
		for each (var c in f.listFiles())
			rm(c);
	}
	if (!f.delete())
		throw "Failed to delete file: " + f;
}

function unzip(zipFilePath, destDirectory) {
	var ZipInputStream = java.util.zip.ZipInputStream;
	var ZipEntry = java.util.zip.ZipEntry;

	var destDir = file(destDirectory);

	if (!destDir.exists())
		destDir.mkdir();

	var zipIn = new ZipInputStream(Files.newInputStream(file(zipFilePath).toPath()));

	try {
		var entry = zipIn.getNextEntry();

		while (entry != null) {
			var filePath = destDirectory + File.separator + entry.getName();
			if (!entry.isDirectory())
				Files.copy(zipIn, file(filePath).toPath(), SCO.REPLACE_EXISTING);
			else
				file(filePath).mkdir();

			zipIn.closeEntry();
			entry = zipIn.getNextEntry();
		}
	}
	finally {
		zipIn.close();
	}
}

function md5(filePath) {
	var MessageDigest = java.security.MessageDigest;
	var DigestInputStream = java.security.DigestInputStream;

	var md = MessageDigest.getInstance("MD5");
	var stream = new DigestInputStream(Files.newInputStream(file(filePath).toPath()), md);

	while(stream.read() != -1);

	return bytesToHex(md.digest());
}

function bytesToHex(b) {
	var Integer = java.lang.Integer;

	var res = '';

	for (var i = 0; i < b.length; i++)
		res += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);

	return res;
}

function withOkLock(fun) {
	var ok = file(path(WORK_DIR, ".ok-" + MAVEN_VERSION));

	if (ok.exists())
		return;

	var workDir = file(WORK_DIR);

	workDir.mkdirs();

	if (!workDir.exists())
		throw "Failed to create directory: " + WORK_DIR;

	var lockFile = file(path(WORK_DIR, ".lock"));

	var RandomAccessFile = java.io.RandomAccessFile;
	var OverlappingFileLockException = java.nio.channels.OverlappingFileLockException;

	var raf = new RandomAccessFile(lockFile, "rw");

	try {
		var lock = null;

		do {
			try {
				lock = raf.getChannel().lock();
			}
			catch(e if e instanceof OverlappingFileLockException) {
				Thread.sleep(50);
			}
		}
		while (lock === null);

		try {
			// Wait a bit inside of the lock before the double checking to allow the file system to catch up.
			// We need it because file systems have different and usually very wonky concurrent visibility guaranties.
			Thread.sleep(50);

			if (ok.exists())
				return;

			fun();

			ok.createNewFile();
		}
		finally {
			lock.release();
		}
	}
	finally {
		raf.close();
	}
}

function installMaven() {
	var mvnZipPath = MVN + '.zip';
	var zip = file(mvnZipPath);

	var i = 0;

	while (!zip.exists() || md5(mvnZipPath) !== MAVEN_MD5) {
		try {
			if (i >= MAVERN_URLS.length)
				break; // No more URLs.

			var url = MAVERN_URLS[i++];

			debug("Downloading maven from: " + url);

			download(url, mvnZipPath);

			debug("Download complete, running checksum.");

			var md5hash = md5(mvnZipPath);

			if (md5hash === MAVEN_MD5)
				break; // Success.
			else
				throw "Checksum error in " + mvnZipPath + ", expected: " + MAVEN_MD5 + ", actual: " + md5hash;
		}
		catch(e) {
			if (isDefined(e.printStackTrace)) {
				if (DEBUG)
					e.printStackTrace();
			}
			else
				debug("Error: " + e);

			rm(zip);
		}
	}

	if (!zip.exists())
		throw "Failed to download Maven.";

	debug("Unzipping maven into: " + MVN);

	rm(file(MVN));

	unzip(mvnZipPath, MVN);

	debug("Maven sucessfully installed.");
}

function parseMavenDependency(dep) {
	var arr = dep.split(':');
	var res = {};

	res.version = arr.pop();
	res.artifactId = arr.pop();
	res.groupId = arr.pop();

	return res;
}

function generatePomXmlFile(cfg) {
	var dependenciesXml = '';
	for each(var dep in cfg.maven) {
		var d = parseMavenDependency(dep);

		dependenciesXml += '' +
'		<dependency>\n' +
'			<groupId>' + d.groupId + '</groupId>\n' +
'			<artifactId>' + d.artifactId + '</artifactId>\n' +
'			<version>' + d.version + '</version>\n' +
'		</dependency>\n';
	}

	var pomXml = '' +
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<project>\n' +
'	<modelVersion>4.0.0</modelVersion>\n' +
'	<groupId>nashorn.tools</groupId>\n' +
'	<artifactId>tmp</artifactId>\n' +
'	<packaging>pom</packaging>\n' +
'	<version>1.0-SNAPSHOT</version>\n' +
'	<name>tmp</name>\n' +
'	<dependencies>\n' +
		dependenciesXml +
'	</dependencies>\n' +
'</project>\n';

	debug("Generating pom.xml:\n" + pomXml);

	var pom = Files.createTempFile('pom-', '.xml').toAbsolutePath();
	Files.write(pom, pomXml.toString().getBytes('UTF-8'));

	return pom.toFile();
}

function readTextFile(filePath, charset) {
	var Charset = java.nio.charset.Charset;

	var lines = Files.readAllLines(file(filePath).toPath(), Charset.forName(charset));
	var contents = Java.from(lines).join('\n');

	debug("Contents of file '" + filePath + "':\n" + contents);

	return contents;
}

function debugPrintStream() {
	if (DEBUG)
		return System.out;

	var PrintStream = java.io.PrintStream;

	return new PrintStream(function(b) {}, true, 'UTF-8'); // /dev/null
}

function setContextClassLoader(ldr) {
	var th = Thread.currentThread();

	var oldLdr = th.getContextClassLoader();

	th.setContextClassLoader(ldr);

	return oldLdr;
}

function collectMavenDependencies(cfg, urls) {
	withOkLock(installMaven);

	var cp = null;

	var mvnTmp = Files.createTempDirectory("mvn-js-tmpdir-").toFile();

	try {
		// Set system properties for Maven.
		System.setProperty("maven.multiModuleProjectDirectory", mvnTmp.getCanonicalPath())
		System.setProperty("maven.home", file(MVN_HOME).getCanonicalPath());
		System.setProperty("classworlds.conf", file(path(MVN_HOME, 'bin', 'm2.conf')).getCanonicalPath());

		var L = new NnClassLoader({dirs:[MVN_LIB, MVN_BOOT]});

		debug("Maven CLI classpath: " + L.getUrls());

		// Temporary set context class loader to Maven.
		var oldLdr = setContextClassLoader(L.getJavaClassLoader());

		try {
			var MavenCli = L.type('org.apache.maven.cli.MavenCli');

			var cli = new MavenCli();

			var cpFile = Files.createTempFile('cp-', '.txt').toFile();

			try {
				var pomFile = generatePomXmlFile(cfg);

				try {
					var printStream = debugPrintStream();

					var mvnArgs = ['-f', pomFile.getCanonicalPath(), "-Dmdep.outputFile=" + cpFile.getCanonicalPath(),
						'dependency:go-offline', 'dependency:build-classpath', 'verify'];

					if (DEBUG)
						mvnArgs = ['--debug', '--errors'].concat(mvnArgs);

					var exitCode = cli.doMain(mvnArgs, mvnTmp.getCanonicalPath(), printStream, printStream);

					if (exitCode !== 0)
						throw "Exit code of maven " + exitCode;

					cp = readTextFile(cpFile.getCanonicalPath(), 'UTF-8');
				}
				finally {
					rm(pomFile);
				}
			}
			finally {
				rm(cpFile);
			}
		}
		finally {
			setContextClassLoader(oldLdr);
		}
	}
	finally {
		rm(mvnTmp);
	}

	if (cp !== null) {
		cp = cp.trim();

		for each(var jar in cp.split(File.pathSeparator))
			urls.add(toURL(file(jar)));
	}
}

function loadType(className, ldr) {
	var cls = Class.forName(className, true, ldr);
	return StaticClass.forClass(cls);
}

function toURL(f) {
	return f.getCanonicalFile().toURI().toURL();
}

function scanDirForJars(f, filter, urls) {
	if (!f.exists())
		return;
	if (f.isDirectory()) {
		if (filter(f)) {
			for each (var x in f.listFiles())
				scanDirForJars(x, filter, urls);
		}
	}
	else if (f.isFile() && f.getName().toLowerCase().endsWith('.jar') && filter(f))
		urls.add(toURL(f));
}

function collectAllJarUrls(cfg) {
	if (!isObject(cfg))
		throw "Class loader configuration object is not provided.\nFor example: new NnClassLoader({jars:['/myapp/bla.jar'], urls:['http://.../bla.jar']})";

	var HashSet = java.util.HashSet;
	var UrlArray = Java.type('java.net.URL[]');

	var urls = new HashSet();

	if (isObject(cfg.urls)) {
		for each (var url in cfg.urls)
			urls.add(new URL(url));
	}

	if (isObject(cfg.jars)) {
		for each (var jar in cfg.jars) {
			var f = file(jar);

			if (f.isFile())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.dirs)) {
		var filter = isDefined(cfg.filter) ? cfg.filter : function(f) {return true;};

		for each (var dir in cfg.dirs)
			scanDirForJars(file(dir), filter, urls);
	}

	if (isObject(cfg.classes)) {
		for each (var dir in cfg.classes) {
			var f = file(dir);

			if (f.isDirectory())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.maven))
		collectMavenDependencies(cfg, urls);

	return urls.toArray(new UrlArray(0));
}

function NnClassLoader(cfg) {
	var URLClassLoader = java.net.URLClassLoader;

	var jarUrls = collectAllJarUrls(cfg);
	var ldr = isObject(cfg.parent) ?
		new URLClassLoader(jarUrls, cfg.parent):
		new URLClassLoader(jarUrls);

	this.type = function(className) {
		return loadType(className, ldr);
	}

	this.getUrls = function() {
		var res = [];

		for each (var url in jarUrls)
			res.push(url.toString());

		return res;
	}

	this.getJavaClassLoader = function() {
		return ldr;
	}
}

return NnClassLoader;
})();
<commit_msg>Bump version<commit_after>/*
   Copyright 2016 Sergi Vladykin (https://github.com/svladykin)

   Version 1.2

   The latest version can be found at https://github.com/NashornTools

   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
*/

var NnClassLoader = (function () {

var DEBUG = java.lang.Boolean.getBoolean('NnClassLoader.debug');

var MAVEN_VERSION = '3.3.9';
var MAVEN_MD5 = 'e7ebd0b8d6811b42a5dad91fb27fe9b4';
var MAVERN_URLS = [
	'http://www-us.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'http://www-eu.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
	'https://archive.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.zip',
];

var Class = java.lang.Class;
var URL = java.net.URL;
var File = java.io.File;
var Files = java.nio.file.Files;
var SCO = java.nio.file.StandardCopyOption;
var System = java.lang.System;
var Thread = java.lang.Thread;

var JAVA_VERSION = System.getProperty("java.specification.version");

var StaticClass = Java.type(JAVA_VERSION === '1.8' ? 'jdk.internal.dynalink.beans.StaticClass' : 'jdk.dynalink.beans.StaticClass');

var WORK_DIR = path(System.getProperty("user.home"), '.mvn_js');
var MVN = path(WORK_DIR, 'mvn-' + MAVEN_VERSION);
var MVN_HOME = path(MVN, 'apache-maven-' + MAVEN_VERSION);
var MVN_LIB = path(MVN_HOME , 'lib');
var MVN_BOOT = path(MVN_HOME, 'boot');

function path() {
	var args = Array.prototype.slice.call(arguments); // Convert to array.

	return args.join(File.separator);
}

function debug(str) {
	if (DEBUG)
		System.out.println(str);
}

function file(pathStr) {
	return new File(pathStr);
}

function isDefined(o) {
	return typeof(o) !== 'undefined';
}

function isObject(o) { // Will return true for arrays as well.
	return typeof(o) === 'object';
}

function download(url, filePath) {
	var tmpFile = file(filePath + '.tmp');
	var input = null;

	try {
		input = new URL(url).openConnection().getInputStream();

		tmpFile.createNewFile();

		Files.copy(input, tmpFile.toPath(), SCO.REPLACE_EXISTING);
	}
	catch (e) {
		rm(tmpFile);

		throw e;
	}
	finally {
		if (input != null)
			input.close();
	}

	Files.move(tmpFile.toPath(), file(filePath).toPath(), SCO.REPLACE_EXISTING, SCO.ATOMIC_MOVE);
}

function rm(f) {
	if (!f.exists())
		return;

	if (f.isDirectory()) {
		for each (var c in f.listFiles())
			rm(c);
	}
	if (!f.delete())
		throw "Failed to delete file: " + f;
}

function unzip(zipFilePath, destDirectory) {
	var ZipInputStream = java.util.zip.ZipInputStream;
	var ZipEntry = java.util.zip.ZipEntry;

	var destDir = file(destDirectory);

	if (!destDir.exists())
		destDir.mkdir();

	var zipIn = new ZipInputStream(Files.newInputStream(file(zipFilePath).toPath()));

	try {
		var entry = zipIn.getNextEntry();

		while (entry != null) {
			var filePath = destDirectory + File.separator + entry.getName();
			if (!entry.isDirectory())
				Files.copy(zipIn, file(filePath).toPath(), SCO.REPLACE_EXISTING);
			else
				file(filePath).mkdir();

			zipIn.closeEntry();
			entry = zipIn.getNextEntry();
		}
	}
	finally {
		zipIn.close();
	}
}

function md5(filePath) {
	var MessageDigest = java.security.MessageDigest;
	var DigestInputStream = java.security.DigestInputStream;

	var md = MessageDigest.getInstance("MD5");
	var stream = new DigestInputStream(Files.newInputStream(file(filePath).toPath()), md);

	while(stream.read() != -1);

	return bytesToHex(md.digest());
}

function bytesToHex(b) {
	var Integer = java.lang.Integer;

	var res = '';

	for (var i = 0; i < b.length; i++)
		res += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);

	return res;
}

function withOkLock(fun) {
	var ok = file(path(WORK_DIR, ".ok-" + MAVEN_VERSION));

	if (ok.exists())
		return;

	var workDir = file(WORK_DIR);

	workDir.mkdirs();

	if (!workDir.exists())
		throw "Failed to create directory: " + WORK_DIR;

	var lockFile = file(path(WORK_DIR, ".lock"));

	var RandomAccessFile = java.io.RandomAccessFile;
	var OverlappingFileLockException = java.nio.channels.OverlappingFileLockException;

	var raf = new RandomAccessFile(lockFile, "rw");

	try {
		var lock = null;

		do {
			try {
				lock = raf.getChannel().lock();
			}
			catch(e if e instanceof OverlappingFileLockException) {
				Thread.sleep(50);
			}
		}
		while (lock === null);

		try {
			// Wait a bit inside of the lock before the double checking to allow the file system to catch up.
			// We need it because file systems have different and usually very wonky concurrent visibility guaranties.
			Thread.sleep(50);

			if (ok.exists())
				return;

			fun();

			ok.createNewFile();
		}
		finally {
			lock.release();
		}
	}
	finally {
		raf.close();
	}
}

function installMaven() {
	var mvnZipPath = MVN + '.zip';
	var zip = file(mvnZipPath);

	var i = 0;

	while (!zip.exists() || md5(mvnZipPath) !== MAVEN_MD5) {
		try {
			if (i >= MAVERN_URLS.length)
				break; // No more URLs.

			var url = MAVERN_URLS[i++];

			debug("Downloading maven from: " + url);

			download(url, mvnZipPath);

			debug("Download complete, running checksum.");

			var md5hash = md5(mvnZipPath);

			if (md5hash === MAVEN_MD5)
				break; // Success.
			else
				throw "Checksum error in " + mvnZipPath + ", expected: " + MAVEN_MD5 + ", actual: " + md5hash;
		}
		catch(e) {
			if (isDefined(e.printStackTrace)) {
				if (DEBUG)
					e.printStackTrace();
			}
			else
				debug("Error: " + e);

			rm(zip);
		}
	}

	if (!zip.exists())
		throw "Failed to download Maven.";

	debug("Unzipping maven into: " + MVN);

	rm(file(MVN));

	unzip(mvnZipPath, MVN);

	debug("Maven sucessfully installed.");
}

function parseMavenDependency(dep) {
	var arr = dep.split(':');
	var res = {};

	res.version = arr.pop();
	res.artifactId = arr.pop();
	res.groupId = arr.pop();

	return res;
}

function generatePomXmlFile(cfg) {
	var dependenciesXml = '';
	for each(var dep in cfg.maven) {
		var d = parseMavenDependency(dep);

		dependenciesXml += '' +
'		<dependency>\n' +
'			<groupId>' + d.groupId + '</groupId>\n' +
'			<artifactId>' + d.artifactId + '</artifactId>\n' +
'			<version>' + d.version + '</version>\n' +
'		</dependency>\n';
	}

	var pomXml = '' +
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<project>\n' +
'	<modelVersion>4.0.0</modelVersion>\n' +
'	<groupId>nashorn.tools</groupId>\n' +
'	<artifactId>tmp</artifactId>\n' +
'	<packaging>pom</packaging>\n' +
'	<version>1.0-SNAPSHOT</version>\n' +
'	<name>tmp</name>\n' +
'	<dependencies>\n' +
		dependenciesXml +
'	</dependencies>\n' +
'</project>\n';

	debug("Generating pom.xml:\n" + pomXml);

	var pom = Files.createTempFile('pom-', '.xml').toAbsolutePath();
	Files.write(pom, pomXml.toString().getBytes('UTF-8'));

	return pom.toFile();
}

function readTextFile(filePath, charset) {
	var Charset = java.nio.charset.Charset;

	var lines = Files.readAllLines(file(filePath).toPath(), Charset.forName(charset));
	var contents = Java.from(lines).join('\n');

	debug("Contents of file '" + filePath + "':\n" + contents);

	return contents;
}

function debugPrintStream() {
	if (DEBUG)
		return System.out;

	var PrintStream = java.io.PrintStream;

	return new PrintStream(function(b) {}, true, 'UTF-8'); // /dev/null
}

function setContextClassLoader(ldr) {
	var th = Thread.currentThread();

	var oldLdr = th.getContextClassLoader();

	th.setContextClassLoader(ldr);

	return oldLdr;
}

function collectMavenDependencies(cfg, urls) {
	withOkLock(installMaven);

	var cp = null;

	var mvnTmp = Files.createTempDirectory("mvn-js-tmpdir-").toFile();

	try {
		// Set system properties for Maven.
		System.setProperty("maven.multiModuleProjectDirectory", mvnTmp.getCanonicalPath())
		System.setProperty("maven.home", file(MVN_HOME).getCanonicalPath());
		System.setProperty("classworlds.conf", file(path(MVN_HOME, 'bin', 'm2.conf')).getCanonicalPath());

		var L = new NnClassLoader({dirs:[MVN_LIB, MVN_BOOT]});

		debug("Maven CLI classpath: " + L.getUrls());

		// Temporary set context class loader to Maven.
		var oldLdr = setContextClassLoader(L.getJavaClassLoader());

		try {
			var MavenCli = L.type('org.apache.maven.cli.MavenCli');

			var cli = new MavenCli();

			var cpFile = Files.createTempFile('cp-', '.txt').toFile();

			try {
				var pomFile = generatePomXmlFile(cfg);

				try {
					var printStream = debugPrintStream();

					var mvnArgs = ['-f', pomFile.getCanonicalPath(), "-Dmdep.outputFile=" + cpFile.getCanonicalPath(),
						'dependency:go-offline', 'dependency:build-classpath', 'verify'];

					if (DEBUG)
						mvnArgs = ['--debug', '--errors'].concat(mvnArgs);

					var exitCode = cli.doMain(mvnArgs, mvnTmp.getCanonicalPath(), printStream, printStream);

					if (exitCode !== 0)
						throw "Exit code of maven " + exitCode;

					cp = readTextFile(cpFile.getCanonicalPath(), 'UTF-8');
				}
				finally {
					rm(pomFile);
				}
			}
			finally {
				rm(cpFile);
			}
		}
		finally {
			setContextClassLoader(oldLdr);
		}
	}
	finally {
		rm(mvnTmp);
	}

	if (cp !== null) {
		cp = cp.trim();

		for each(var jar in cp.split(File.pathSeparator))
			urls.add(toURL(file(jar)));
	}
}

function loadType(className, ldr) {
	var cls = Class.forName(className, true, ldr);
	return StaticClass.forClass(cls);
}

function toURL(f) {
	return f.getCanonicalFile().toURI().toURL();
}

function scanDirForJars(f, filter, urls) {
	if (!f.exists())
		return;
	if (f.isDirectory()) {
		if (filter(f)) {
			for each (var x in f.listFiles())
				scanDirForJars(x, filter, urls);
		}
	}
	else if (f.isFile() && f.getName().toLowerCase().endsWith('.jar') && filter(f))
		urls.add(toURL(f));
}

function collectAllJarUrls(cfg) {
	if (!isObject(cfg))
		throw "Class loader configuration object is not provided.\nFor example: new NnClassLoader({jars:['/myapp/bla.jar'], urls:['http://.../bla.jar']})";

	var HashSet = java.util.HashSet;
	var UrlArray = Java.type('java.net.URL[]');

	var urls = new HashSet();

	if (isObject(cfg.urls)) {
		for each (var url in cfg.urls)
			urls.add(new URL(url));
	}

	if (isObject(cfg.jars)) {
		for each (var jar in cfg.jars) {
			var f = file(jar);

			if (f.isFile())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.dirs)) {
		var filter = isDefined(cfg.filter) ? cfg.filter : function(f) {return true;};

		for each (var dir in cfg.dirs)
			scanDirForJars(file(dir), filter, urls);
	}

	if (isObject(cfg.classes)) {
		for each (var dir in cfg.classes) {
			var f = file(dir);

			if (f.isDirectory())
				urls.add(toURL(f));
		}
	}

	if (isObject(cfg.maven))
		collectMavenDependencies(cfg, urls);

	return urls.toArray(new UrlArray(0));
}

function NnClassLoader(cfg) {
	var URLClassLoader = java.net.URLClassLoader;

	var jarUrls = collectAllJarUrls(cfg);
	var ldr = isObject(cfg.parent) ?
		new URLClassLoader(jarUrls, cfg.parent):
		new URLClassLoader(jarUrls);

	this.type = function(className) {
		return loadType(className, ldr);
	}

	this.getUrls = function() {
		var res = [];

		for each (var url in jarUrls)
			res.push(url.toString());

		return res;
	}

	this.getJavaClassLoader = function() {
		return ldr;
	}
}

return NnClassLoader;
})();
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var Base = require('./base')
  , utils = require('../utils')
  , Progress = require('../browser/progress');

/**
 * Expose `Doc`.
 */

exports = module.exports = HTML;

/**
 * Stats template.
 */

var statsTemplate = '
'
  + '
<canvas width="50" height="50"></canvas>
'
  + '
passes: 0
'
  + '
failures: 0
'
  + '
duration: 0s
'
  + '
';

/**
 * Initialize a new `Doc` reporter.
 *
 * @param {Runner} runner
 * @api public
 */

function HTML(runner) {
  Base.call(this, runner);

  // TODO: clean up

  var self = this
    , stats = this.stats
    , total = runner.total
    , root = $('#mocha')
    , stack = [root]
    , stat = $(statsTemplate).appendTo(root)
    , canvas = stat.find('canvas').get(0)
    , ctx, progress

  if (canvas.getContext) {
    ctx = canvas.getContext('2d');
    progress = new Progress;
  }

  if (!root.length) return error('#mocha div missing, add it to your document');

  if (progress) {
    progress.size(50);
  }

  runner.on('suite', function(suite){
    if (suite.root) return;

    // suite
    var el = $('

' + suite.title + '

');

    // container
    stack[0].append(el);
    stack.unshift($('
'));
    el.append(stack[0]);
  });

  runner.on('suite end', function(suite){
    if (suite.root) return;
    stack.shift();
  });

  runner.on('fail', function(test, err){
    if (err.uncaught) runner.emit('test end', test);
  });

  runner.on('test end', function(test){
    // TODO: add to stats
    var percent = stats.tests / total * 100 | 0;

    if (progress) {
      // update progress bar
      progress.update(percent).draw(ctx);
    }

    // update stats
    var ms = new Date - stats.start;
    stat.find('.passes em').text(stats.passes);
    stat.find('.failures em').text(stats.failures);
    stat.find('.duration em').text((ms / 1000).toFixed(2));

    // test
    if (test.passed) {
      var el = $('

' + test.title + '

')
    } else if (test.pending) {
      var el = $('

' + test.title + '

')
    } else {
      var el = $('

' + test.title + '

');
      var str = test.err.stack || test.err;

      // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
      // check for the result of the stringifying.
      if ('[object Error]' == str) {
        str = test.err.message;
      }

      var err = $('
' + str + '
');
      el.append(err);
    }

    // toggle code
    el.find('h2').toggle(function(){
      pre.slideDown('fast');
    }, function(){
      pre.slideUp('fast');
    });

    // code
    // TODO: defer
    if (!test.pending) {
      var code = utils.escape(clean(test.fn.toString()));
      var pre = $('
' + code + '
');
      pre.appendTo(el).hide();
    }
    stack[0].append(el);
  });
}

function error(msg) {
  $('
' + msg + '
').appendTo('body');
}

/**
 * Strip the function definition from `str`,
 * and re-indent for pre whitespace.
 */

function clean(str) {
  str = str
    .replace(/^function *\(.*\) *{/, '')
    .replace(/\s+\}$/, '');

  var spaces = str.match(/^\n?( *)/)[1].length
    , re = new RegExp('^ {' + spaces + '}', 'gm');

  str = str
    .replace(re, '')
    .replace(/^\s+/, '');

  return str;
}
<commit_msg>Fixed: escape strings in HTML reporter. Closes #164<commit_after>
/**
 * Module dependencies.
 */

var Base = require('./base')
  , utils = require('../utils')
  , Progress = require('../browser/progress')
  , escape = utils.escape;

/**
 * Expose `Doc`.
 */

exports = module.exports = HTML;

/**
 * Stats template.
 */

var statsTemplate = '
'
  + '
<canvas width="50" height="50"></canvas>
'
  + '
passes: 0
'
  + '
failures: 0
'
  + '
duration: 0s
'
  + '
';

/**
 * Initialize a new `Doc` reporter.
 *
 * @param {Runner} runner
 * @api public
 */

function HTML(runner) {
  Base.call(this, runner);

  // TODO: clean up

  var self = this
    , stats = this.stats
    , total = runner.total
    , root = $('#mocha')
    , stack = [root]
    , stat = $(statsTemplate).appendTo(root)
    , canvas = stat.find('canvas').get(0)
    , ctx, progress

  if (canvas.getContext) {
    ctx = canvas.getContext('2d');
    progress = new Progress;
  }

  if (!root.length) return error('#mocha div missing, add it to your document');

  if (progress) {
    progress.size(50);
  }

  runner.on('suite', function(suite){
    if (suite.root) return;

    // suite
    var el = $('

' + suite.title + '

');

    // container
    stack[0].append(el);
    stack.unshift($('
'));
    el.append(stack[0]);
  });

  runner.on('suite end', function(suite){
    if (suite.root) return;
    stack.shift();
  });

  runner.on('fail', function(test, err){
    if (err.uncaught) runner.emit('test end', test);
  });

  runner.on('test end', function(test){
    // TODO: add to stats
    var percent = stats.tests / total * 100 | 0;

    if (progress) {
      // update progress bar
      progress.update(percent).draw(ctx);
    }

    // update stats
    var ms = new Date - stats.start;
    stat.find('.passes em').text(stats.passes);
    stat.find('.failures em').text(stats.failures);
    stat.find('.duration em').text((ms / 1000).toFixed(2));

    // test
    if (test.passed) {
      var el = $('

' + escape(test.title) + '

')
    } else if (test.pending) {
      var el = $('

' + escape(test.title) + '

')
    } else {
      var el = $('

' + escape(test.title) + '

');
      var str = test.err.stack || test.err;

      // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
      // check for the result of the stringifying.
      if ('[object Error]' == str) str = test.err.message;

      var err = $('
' + escape(str) + '
');
      el.append(err);
    }

    // toggle code
    el.find('h2').toggle(function(){
      pre.slideDown('fast');
    }, function(){
      pre.slideUp('fast');
    });

    // code
    // TODO: defer
    if (!test.pending) {
      var code = escape(clean(test.fn.toString()));
      var pre = $('
' + code + '
');
      pre.appendTo(el).hide();
    }
    stack[0].append(el);
  });
}

function error(msg) {
  $('
' + msg + '
').appendTo('body');
}

/**
 * Strip the function definition from `str`,
 * and re-indent for pre whitespace.
 */

function clean(str) {
  str = str
    .replace(/^function *\(.*\) *{/, '')
    .replace(/\s+\}$/, '');

  var spaces = str.match(/^\n?( *)/)[1].length
    , re = new RegExp('^ {' + spaces + '}', 'gm');

  str = str
    .replace(re, '')
    .replace(/^\s+/, '');

  return str;
}
<|endoftext|>