<commit_before>/*********************************************************************
 *
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Worcester Polytechnic Institute
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Worcester Polytechnic Institute nor the
 *     names of its contributors may be used to endorse or promote
 *     products derived from this software without specific prior
 *     written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS 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
 *  COPYRIGHT OWNER OR CONTRIBUTORS 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.
 *
 *   Author: Russell Toris
 *  Version: October 9, 2012
 *
 *   AMDfied by Jihoon
 *   Version : Oct 05, 2012
 *
 *********************************************************************/

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else {
    root.MjpegCanvas = factory();
  }
}
    (
        this,
        function() {
          var MjpegCanvas = function(options) {
            var mjpegCanvas = this;
            options = options || {};
            mjpegCanvas.host = options.host;
            mjpegCanvas.port = options.port || 8080;
            mjpegCanvas.topic = options.topic;
            mjpegCanvas.label = options.label;
            mjpegCanvas.defaultStream = options.defaultStream || 0;
            mjpegCanvas.quality = options.quality;
            mjpegCanvas.canvasID = options.canvasID;
            mjpegCanvas.width = options.width;
            mjpegCanvas.height = options.height;

            // current streaming topic
            var curStream = null;
            var img = null;

            // grab the canvas
            var canvas = document.getElementById(mjpegCanvas.canvasID);
            var context = canvas.getContext('2d');

            var createImage = function() {
              // create the image to hold the stream
              img = new Image();
              var src = 'http://' + mjpegCanvas.host + ':' + mjpegCanvas.port
                  + '/stream?topic=' + curStream;
              // check for various options
              if (mjpegCanvas.width > 0) {
                src += '?width=' + mjpegCanvas.width;
              }
              if (mjpegCanvas.width > 0) {
                src += '?height=' + mjpegCanvas.height;
              }
              if (mjpegCanvas.quality > 0) {
                src += '?quality=' + mjpegCanvas.quality;
              }
              img.src = src;
            };

            // check if the topics is a list or single topic
            if (mjpegCanvas.topic instanceof Array) {
              // check the labels
              if (!(mjpegCanvas.label && mjpegCanvas.label instanceof Array && mjpegCanvas.label.length == mjpegCanvas.topic.length)) {
                mjpegCanvas.label = null;
              }

              // start the stream with the first topic
              curStream = mjpegCanvas.topic[mjpegCanvas.defaultStream];

              // button options
              context.globalAlpha = 0.66;
              var buttonMargin = 10;
              var buttonPadding = 5;
              var buttonHeight = 25;
              var buttonWidth = 55;
              var buttonColor = 'black';
              var buttonStrokeSize = 5;
              var buttonStrokeColor = 'blue';
              var editFont = '16pt Verdana';
              var editColor = 'white';

              // menu div
              var menu = document.createElement('div');
              document.getElementsByTagName('body')[0].appendChild(menu);
              menu.style.display = 'none';

              // create the mouseovers
              var mouseEnter = false;
              var menuOpen = false;
              canvas.addEventListener('mouseenter', function(e) {
                mouseEnter = true;
              }, false);
              canvas.addEventListener('mouseleave', function(e) {
                mouseEnter = false;
              }, false);
              canvas
                  .addEventListener(
                      'click',
                      function(e) {
                        // create a unique ID
                        var id = (new Date()).getTime();

                        var offsetLeft = 0;
                        var offsetTop = 0;
                        var element = canvas;
                        while (element && !isNaN(element.offsetLeft)
                            && !isNaN(element.offsetTop)) {
                          offsetLeft += element.offsetLeft - element.scrollLeft;
                          offsetTop += element.offsetTop - element.scrollTop;
                          element = element.offsetParent;
                        }

                        var x = e.pageX - offsetLeft;
                        var y = e.pageY - offsetTop;
                        var height = canvas.getAttribute('height');
                        var width = canvas.getAttribute('width');

                        // check if we are in the 'edit' button
                        if (x < (buttonWidth + buttonMargin)
                            && x > buttonMargin
                            && y > (height - (buttonHeight + buttonMargin))
                            && y < height - buttonMargin) {
                          menuOpen = true;

                          // create the menu
                          var html = '
Camera Streams

<form>Stream<select name="stream" id="stream-'
                              + id + '" required>';
                          for ( var i = 0; i < mjpegCanvas.topic.length; i++) {
                            // check if this is the selected option
                            var selected = '';
                            if (mjpegCanvas.topic[i] === curStream) {
                              var selected = 'selected="selected"';
                            }
                            html += '<option value="' + mjpegCanvas.topic[i]
                                + '" ' + selected + '>';
                            // check for a label
                            if (mjpegCanvas.label) {
                              html += mjpegCanvas.label[i];
                            } else {
                              html += mjpegCanvas.topic[i];
                            }
                            html += '</option>';
                          }
                          html += '</select></form>
<button id="button-'
                              + id + '">Close</button>';

                          // display the menu
                          menu.innerHTML = html;
                          menu.style.position = 'absolute';
                          menu.style.top = offsetTop + 'px';
                          menu.style.left = offsetLeft + 'px';
                          menu.style.width = width + 'px';
                          menu.style.display = 'block';

                          // dropdown change listener
                          var select = document.getElementById('stream-' + id);
                          select
                              .addEventListener(
                                  'click',
                                  function() {
                                    var stream = select.options[select.selectedIndex].value;
                                    // make sure it is a new stream
                                    if (stream !== curStream) {
                                      curStream = stream;
                                      img = null;
                                      createImage();
                                      // emit an event for the change
                                      mjpegCanvas.emit('change', stream);
                                    }
                                  }, false);

                          // create the event listener for the close
                          var button = document.getElementById('button-' + id);
                          button.addEventListener('click', function(e) {
                            // close the menu
                            menuOpen = false;
                            menu.style.display = 'none';
                          }, false);
                        }
                      }, false);
            } else {
              curStream = mjpegCanvas.topic;
            }

            // a function to draw the image onto the canvas
            function draw(img) {
              // grab the current sizes of the canvas
              var width = canvas.getAttribute('width');
              var height = canvas.getAttribute('height');

              // grab the drawing context and draw the image
              if (img) {
                context.drawImage(img, 0, 0, width, height);
              } else {
                context.clearRect(0, 0, width, height);
              }

              if (mouseEnter && !menuOpen) {
                // create the "swap" button
                context.globalAlpha = 0.66;
                context.beginPath();
                context.rect(buttonMargin, height
                    - (buttonHeight + buttonMargin), buttonWidth, buttonHeight);
                context.fillStyle = buttonColor;
                context.fill();
                context.lineWidth = buttonStrokeSize;
                context.strokeStyle = buttonStrokeColor;
                context.stroke();

                // draw the text on the button
                context.font = editFont;
                context.fillStyle = editColor;
                context.fillText('Edit', buttonMargin + buttonPadding, height
                    - (buttonMargin + buttonPadding));
              }

              if (menuOpen) {
                // create the white box
                context.globalAlpha = 0.66;
                context.beginPath();
                context.rect(0, 0, width, height);
                context.fillStyle = 'white';
                context.fill();
              }
              context.globalAlpha = 1;
            }

            // grab the initial stream
            createImage();

            // redraw the image every 100 ms
            setInterval(function() {
              draw(img);
            }, 100);
          };
          MjpegCanvas.prototype.__proto__ = EventEmitter2.prototype;
          return MjpegCanvas;
        }));
<commit_msg>showMenus option added to always show the menus<commit_after>/*********************************************************************
 *
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2012, Worcester Polytechnic Institute
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Worcester Polytechnic Institute nor the
 *     names of its contributors may be used to endorse or promote
 *     products derived from this software without specific prior
 *     written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS 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
 *  COPYRIGHT OWNER OR CONTRIBUTORS 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.
 *
 *   Author: Russell Toris
 *  Version: October 9, 2012
 *
 *   AMDfied by Jihoon
 *   Version : Oct 05, 2012
 *
 *********************************************************************/

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define([], factory);
  } else {
    root.MjpegCanvas = factory();
  }
}
    (
        this,
        function() {
          var MjpegCanvas = function(options) {
            var mjpegCanvas = this;
            options = options || {};
            mjpegCanvas.host = options.host;
            mjpegCanvas.port = options.port || 8080;
            mjpegCanvas.topic = options.topic;
            mjpegCanvas.label = options.label;
            mjpegCanvas.defaultStream = options.defaultStream || 0;
            mjpegCanvas.quality = options.quality;
            mjpegCanvas.canvasID = options.canvasID;
            mjpegCanvas.width = options.width;
            mjpegCanvas.height = options.height;
            mjpegCanvas.showMenus = options.showMenus;

            // current streaming topic
            var curStream = null;
            var img = null;

            // grab the canvas
            var canvas = document.getElementById(mjpegCanvas.canvasID);
            var context = canvas.getContext('2d');

            var createImage = function() {
              // create the image to hold the stream
              img = new Image();
              var src = 'http://' + mjpegCanvas.host + ':' + mjpegCanvas.port
                  + '/stream?topic=' + curStream;
              // check for various options
              if (mjpegCanvas.width > 0) {
                src += '?width=' + mjpegCanvas.width;
              }
              if (mjpegCanvas.width > 0) {
                src += '?height=' + mjpegCanvas.height;
              }
              if (mjpegCanvas.quality > 0) {
                src += '?quality=' + mjpegCanvas.quality;
              }
              img.src = src;
            };

            // check if the topics is a list or single topic
            if (mjpegCanvas.topic instanceof Array) {
              // check the labels
              if (!(mjpegCanvas.label && mjpegCanvas.label instanceof Array && mjpegCanvas.label.length == mjpegCanvas.topic.length)) {
                mjpegCanvas.label = null;
              }

              // start the stream with the first topic
              curStream = mjpegCanvas.topic[mjpegCanvas.defaultStream];

              // button options
              context.globalAlpha = 0.66;
              var buttonMargin = 10;
              var buttonPadding = 5;
              var buttonHeight = 25;
              var buttonWidth = 55;
              var buttonColor = 'black';
              var buttonStrokeSize = 5;
              var buttonStrokeColor = 'blue';
              var editFont = '16pt Verdana';
              var editColor = 'white';

              // menu div
              var menu = document.createElement('div');
              document.getElementsByTagName('body')[0].appendChild(menu);
              menu.style.display = 'none';

              // create the mouseovers
              var mouseEnter = false;
              var menuOpen = false;
              canvas.addEventListener('mouseenter', function(e) {
                mouseEnter = true;
              }, false);
              canvas.addEventListener('mouseleave', function(e) {
                mouseEnter = true;
              }, false);
              canvas
                  .addEventListener(
                      'click',
                      function(e) {
                        // create a unique ID
                        var id = (new Date()).getTime();

                        var offsetLeft = 0;
                        var offsetTop = 0;
                        var element = canvas;
                        while (element && !isNaN(element.offsetLeft)
                            && !isNaN(element.offsetTop)) {
                          offsetLeft += element.offsetLeft - element.scrollLeft;
                          offsetTop += element.offsetTop - element.scrollTop;
                          element = element.offsetParent;
                        }

                        var x = e.pageX - offsetLeft;
                        var y = e.pageY - offsetTop;
                        var height = canvas.getAttribute('height');
                        var width = canvas.getAttribute('width');

                        // check if we are in the 'edit' button
                        if (x < (buttonWidth + buttonMargin)
                            && x > buttonMargin
                            && y > (height - (buttonHeight + buttonMargin))
                            && y < height - buttonMargin) {
                          menuOpen = true;

                          // create the menu
                          var html = '
Camera Streams

<form>Stream<select name="stream" id="stream-'
                              + id + '" required>';
                          for ( var i = 0; i < mjpegCanvas.topic.length; i++) {
                            // check if this is the selected option
                            var selected = '';
                            if (mjpegCanvas.topic[i] === curStream) {
                              var selected = 'selected="selected"';
                            }
                            html += '<option value="' + mjpegCanvas.topic[i]
                                + '" ' + selected + '>';
                            // check for a label
                            if (mjpegCanvas.label) {
                              html += mjpegCanvas.label[i];
                            } else {
                              html += mjpegCanvas.topic[i];
                            }
                            html += '</option>';
                          }
                          html += '</select></form>
<button id="button-'
                              + id + '">Close</button>';

                          // display the menu
                          menu.innerHTML = html;
                          menu.style.position = 'absolute';
                          menu.style.top = offsetTop + 'px';
                          menu.style.left = offsetLeft + 'px';
                          menu.style.width = width + 'px';
                          menu.style.display = 'block';

                          // dropdown change listener
                          var select = document.getElementById('stream-' + id);
                          select
                              .addEventListener(
                                  'click',
                                  function() {
                                    var stream = select.options[select.selectedIndex].value;
                                    // make sure it is a new stream
                                    if (stream !== curStream) {
                                      curStream = stream;
                                      img = null;
                                      createImage();
                                      // emit an event for the change
                                      mjpegCanvas.emit('change', stream);
                                    }
                                  }, false);

                          // create the event listener for the close
                          var button = document.getElementById('button-' + id);
                          button.addEventListener('click', function(e) {
                            // close the menu
                            menuOpen = false;
                            menu.style.display = 'none';
                          }, false);
                        }
                      }, false);
            } else {
              curStream = mjpegCanvas.topic;
            }

            // a function to draw the image onto the canvas
            function draw(img) {
              // grab the current sizes of the canvas
              var width = canvas.getAttribute('width');
              var height = canvas.getAttribute('height');

              // grab the drawing context and draw the image
              if (img) {
                context.drawImage(img, 0, 0, width, height);
              } else {
                context.clearRect(0, 0, width, height);
              }

              if ((mouseEnter || mjpegCanvas.showMenus) && !menuOpen) {
                // create the "swap" button
                context.globalAlpha = 0.66;
                context.beginPath();
                context.rect(buttonMargin, height
                    - (buttonHeight + buttonMargin), buttonWidth, buttonHeight);
                context.fillStyle = buttonColor;
                context.fill();
                context.lineWidth = buttonStrokeSize;
                context.strokeStyle = buttonStrokeColor;
                context.stroke();

                // draw the text on the button
                context.font = editFont;
                context.fillStyle = editColor;
                context.fillText('Edit', buttonMargin + buttonPadding, height
                    - (buttonMargin + buttonPadding));
              }

              if (menuOpen) {
                // create the white box
                context.globalAlpha = 0.66;
                context.beginPath();
                context.rect(0, 0, width, height);
                context.fillStyle = 'white';
                context.fill();
              }
              context.globalAlpha = 1;
            }

            // grab the initial stream
            createImage();

            // redraw the image every 100 ms
            setInterval(function() {
              draw(img);
            }, 100);
          };
          MjpegCanvas.prototype.__proto__ = EventEmitter2.prototype;
          return MjpegCanvas;
        }));
<|endoftext|>


<commit_before>//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HERE BEGINETH THE SCRIPT
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(function(global) {
    "use strict";
    var dom = {};
    var tags = [
        "div", "p", "table", "tr", "td", "th", "tbody", "thead", "tfoot", "span", "ul", "ol", "li",
        "a", "select", "option", "input", "button", "h1", "h2", "h3", "h4", "textarea", "label"
    ];

    // helper functions
    function mkArr(obj) {
        return (!!obj ? (Array.isArray(obj) ? obj : [obj]) : []);
    }

    function cfgElem(elem, attrs) {
        var prop;
        for (prop in attrs) {
            if (attrs.hasOwnProperty(prop)) {
                if (prop === "className" || prop === "innerHTML" || prop === "name" || prop === "title") {
                    elem[prop] = attrs[prop];
                } else {
                    elem.setAttribute(prop, attrs[prop]);
                }
            }
        }
        return elem;
    }

    function mkChildren(elem, children) {
        children.forEach(function(child) {
            if (typeof child === "string") {
                elem.appendChild(document.createTextNode(child));
            } else {
                elem.appendChild(child);
            }
        });
        return elem;
    }

    // helper
    // naive shallow mixin function. good enough for now
    function merge(dest) {
        var args = Array.prototype.slice.call(arguments, 1);

        args.forEach(function(obj) {
            var prop;
            for (prop in obj) {
                if (obj.hasOwnProperty(prop)) {
                    dest[prop] = obj[prop];
                }
            }
        });

        return dest;
    }

    // the meaty part:
    dom.el = function(tag, cfg) {
        cfg = cfg || {};
        return function(attrs, children) {
            var elem = (typeof tag === "string" ? document.createElement(tag) : tag);

            // sanity
            if (Array.isArray(attrs) || typeof attrs === "string" || attrs instanceof HTMLElement) {
                children = mkArr(attrs);
                attrs = cfg;
            } else {
                children = mkArr(children);
                attrs = merge({}, cfg, attrs);
            }

            return mkChildren(cfgElem(elem, attrs), children);
        };
    };

    dom.addAll = function(ctx) {
        ctx = ctx || global;
        tags.forEach(function(tag) {
            ctx[tag] = dom.el(tag);
        });
        return ctx;
    };

    dom.addAll(dom);

    global.dom = dom;

}(this));

<commit_msg>test for HTMLElement or duck-type<commit_after>//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HERE BEGINETH THE SCRIPT
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(function(global) {
    "use strict";
    var dom = {};
    var tags = [
        "div", "p", "table", "tr", "td", "th", "tbody", "thead", "tfoot", "span", "ul", "ol", "li",
        "a", "select", "option", "input", "button", "h1", "h2", "h3", "h4", "textarea", "label"
    ];

    // helper functions
    function mkArr(obj) {
        return (!!obj ? (Array.isArray(obj) ? obj : [obj]) : []);
    }

    function cfgElem(elem, attrs) {
        var prop;
        for (prop in attrs) {
            if (attrs.hasOwnProperty(prop)) {
                if (prop === "className" || prop === "innerHTML" || prop === "name" || prop === "title") {
                    elem[prop] = attrs[prop];
                } else {
                    elem.setAttribute(prop, attrs[prop]);
                }
            }
        }
        return elem;
    }

    function mkChildren(elem, children) {
        children.forEach(function(child) {
            if (typeof child === "string") {
                elem.appendChild(document.createTextNode(child));
            } else {
                elem.appendChild(child);
            }
        });
        return elem;
    }

    // helper
    // naive shallow mixin function. good enough for now
    function merge(dest) {
        var args = Array.prototype.slice.call(arguments, 1);

        args.forEach(function(obj) {
            var prop;
            for (prop in obj) {
                if (obj.hasOwnProperty(prop)) {
                    dest[prop] = obj[prop];
                }
            }
        });
        return dest;
    }

    function isElem(obj) {
        return obj instanceof HTMLElement || obj.nodeType === 1 || obj.nodeType === 3;
    }

    // the meaty part:
    dom.el = function(tag, cfg) {
        cfg = cfg || {};
        return function(attrs, children) {
            var elem = (typeof tag === "string" ? document.createElement(tag) : tag);

            // sanity
            if (Array.isArray(attrs) || typeof attrs === "string" || isElem(attrs)) {
                children = mkArr(attrs);
                attrs = cfg;
            } else {
                children = mkArr(children);
                attrs = merge({}, cfg, attrs);
            }
            return mkChildren(cfgElem(elem, attrs), children);
        };
    };

    dom.addAll = function(ctx) {
        ctx = ctx || global;
        tags.forEach(function(tag) {
            ctx[tag] = dom.el(tag);
        });
        return ctx;
    };
    dom.addAll(dom);

    global.dom = dom;

}(this));

<|endoftext|>


<commit_before>import {_FEATURE} from './feature';

let shadowPoly = window.ShadowDOMPolyfill || null;

/**
* Represents the core APIs of the DOM.
*/
export const _DOM = {
  Element: Element,
  NodeList: NodeList,
  SVGElement: SVGElement,
  boundary: 'aurelia-dom-boundary',
  addEventListener(eventName: string, callback: Function, capture?: boolean): void {
    document.addEventListener(eventName, callback, capture);
  },
  removeEventListener(eventName: string, callback: Function, capture?: boolean): void {
    document.removeEventListener(eventName, callback, capture);
  },
  adoptNode(node: Node) {
    return document.adoptNode(node, true);//TODO: what is does the true mean? typo?
  },
  createAttribute(name: string): Attr {
    return document.createAttribute(name);
  },
  createElement(tagName: string): Element {
    return document.createElement(tagName);
  },
  createTextNode(text) {
    return document.createTextNode(text);
  },
  createComment(text) {
    return document.createComment(text);
  },
  createDocumentFragment(): DocumentFragment {
    return document.createDocumentFragment();
  },
  createTemplateElement(): HTMLTemplateElement {
    let template = document.createElement('template');
    return _FEATURE.ensureHTMLTemplateElement(template);
  },
  createMutationObserver(callback: Function): MutationObserver {
    return new (window.MutationObserver || window.WebKitMutationObserver)(callback);
  },
  createCustomEvent(eventType: string, options: Object): CustomEvent {
    return new window.CustomEvent(eventType, options);
  },
  dispatchEvent(evt): void {
    document.dispatchEvent(evt);
  },
  getComputedStyle(element: Element) {
    return window.getComputedStyle(element);
  },
  getElementById(id: string): Element {
    return document.getElementById(id);
  },
  querySelectorAll(query: string) {
    return document.querySelectorAll(query);
  },
  nextElementSibling(element: Node): Element {
    if (element.nextElementSibling) { return element.nextElementSibling; }
    do { element = element.nextSibling; }
    while (element && element.nodeType !== 1);
    return element;
  },
  createTemplateFromMarkup(markup: string): Element {
    let parser = document.createElement('div');
    parser.innerHTML = markup;

    let temp = parser.firstElementChild;
    if (!temp || temp.nodeName !== 'TEMPLATE') {
      throw new Error('Template markup must be wrapped in a <template> element e.g. <template> <!-- markup here --> </template>');
    }

    return _FEATURE.ensureHTMLTemplateElement(temp);
  },
  appendNode(newNode: Node, parentNode?: Node): void {
    (parentNode || document.body).appendChild(newNode);
  },
  replaceNode(newNode: Node, node: Node, parentNode?: Node): void {
    if (node.parentNode) {
      node.parentNode.replaceChild(newNode, node);
    } else if (shadowPoly !== null) { //HACK: IE template element and shadow dom polyfills not quite right...
      shadowPoly.unwrap(parentNode).replaceChild(
        shadowPoly.unwrap(newNode),
        shadowPoly.unwrap(node)
        );
    } else { //HACK: same as above
      parentNode.replaceChild(newNode, node);
    }
  },
  removeNode(node: Node, parentNode?: Node): void {
    if (node.parentNode) {
      node.parentNode.removeChild(node);
    } else if (parentNode) {
      if (shadowPoly !== null) { //HACK: IE template element and shadow dom polyfills not quite right...
        shadowPoly.unwrap(parentNode).removeChild(shadowPoly.unwrap(node));
      } else { //HACK: same as above
        parentNode.removeChild(node);
      }
    }
  },
  injectStyles(styles: string, destination?: Element, prepend?: boolean, id?: string): Node {
    if (id) {
      let oldStyle = document.getElementById(id);
      if (oldStyle) {
        let isStyleTag = oldStyle.tagName.toLowerCase() === 'style';

        if (isStyleTag) {
          oldStyle.innerHTML = styles;
          return;
        }

        throw new Error('The provided id does not indicate a style tag.');
      }
    }

    let node = document.createElement('style');
    node.innerHTML = styles;
    node.type = 'text/css';

    if (id) {
      node.id = id;
    }

    destination = destination || document.head;

    if (prepend && destination.childNodes.length > 0) {
      destination.insertBefore(node, destination.childNodes[0]);
    } else {
      destination.appendChild(node);
    }

    return node;
  }
};
<commit_msg>chore(dom): implement pal changes (#30)<commit_after>import { _FEATURE } from './feature';

let shadowPoly = window.ShadowDOMPolyfill || null;

/**
* Represents the core APIs of the DOM.
*/
export const _DOM = {
  Element: Element,
  NodeList: NodeList,
  SVGElement: SVGElement,
  boundary: 'aurelia-dom-boundary',
  addEventListener(eventName: string, callback: EventListenerOrEventListenerObject, capture?: boolean): void {
    document.addEventListener(eventName, callback, capture);
  },
  removeEventListener(eventName: string, callback: EventListenerOrEventListenerObject, capture?: boolean): void {
    document.removeEventListener(eventName, callback, capture);
  },
  adoptNode(node: Node) {
    return document.adoptNode(node);
  },
  createAttribute(name: string): Attr {
    return document.createAttribute(name);
  },
  createElement(tagName: string): Element {
    return document.createElement(tagName);
  },
  createTextNode(text) {
    return document.createTextNode(text);
  },
  createComment(text) {
    return document.createComment(text);
  },
  createDocumentFragment(): DocumentFragment {
    return document.createDocumentFragment();
  },
  createTemplateElement(): HTMLTemplateElement {
    let template = document.createElement('template');
    return _FEATURE.ensureHTMLTemplateElement(template);
  },
  createMutationObserver(callback: Function): MutationObserver {
    return new (window.MutationObserver || window.WebKitMutationObserver)(callback);
  },
  createCustomEvent<T = any>(eventType: string, options?: CustomEventInit<T>): CustomEvent<T> {
    return new window.CustomEvent(eventType, options);
  },
  dispatchEvent(evt): void {
    document.dispatchEvent(evt);
  },
  getComputedStyle(element: Element) {
    return window.getComputedStyle(element);
  },
  getElementById(id: string): Element {
    return document.getElementById(id);
  },
  querySelector(query: string) {
    return document.querySelector(query);
  },
  querySelectorAll(query: string) {
    return document.querySelectorAll(query);
  },
  nextElementSibling(element: Node): Element {
    if (element.nextElementSibling) { return element.nextElementSibling; }
    do { element = element.nextSibling; }
    while (element && element.nodeType !== 1);
    return element;
  },
  createTemplateFromMarkup(markup: string): HTMLTemplateElement {
    let parser = document.createElement('div');
    parser.innerHTML = markup;

    let temp = parser.firstElementChild;
    if (!temp || temp.nodeName !== 'TEMPLATE') {
      throw new Error('Template markup must be wrapped in a <template> element e.g. <template> <!-- markup here --> </template>');
    }

    return _FEATURE.ensureHTMLTemplateElement(temp);
  },
  appendNode(newNode: Node, parentNode?: Node): void {
    (parentNode || document.body).appendChild(newNode);
  },
  replaceNode(newNode: Node, node: Node, parentNode?: Node): void {
    if (node.parentNode) {
      node.parentNode.replaceChild(newNode, node);
    } else if (shadowPoly !== null) { //HACK: IE template element and shadow dom polyfills not quite right...
      shadowPoly.unwrap(parentNode).replaceChild(
        shadowPoly.unwrap(newNode),
        shadowPoly.unwrap(node)
      );
    } else { //HACK: same as above
      parentNode.replaceChild(newNode, node);
    }
  },
  removeNode(node: Node, parentNode?: Node): void {
    if (node.parentNode) {
      node.parentNode.removeChild(node);
    } else if (parentNode) {
      if (shadowPoly !== null) { //HACK: IE template element and shadow dom polyfills not quite right...
        shadowPoly.unwrap(parentNode).removeChild(shadowPoly.unwrap(node));
      } else { //HACK: same as above
        parentNode.removeChild(node);
      }
    }
  },
  injectStyles(styles: string, destination?: Element, prepend?: boolean, id?: string): Node {
    if (id) {
      let oldStyle = document.getElementById(id);
      if (oldStyle) {
        let isStyleTag = oldStyle.tagName.toLowerCase() === 'style';

        if (isStyleTag) {
          oldStyle.innerHTML = styles;
          return;
        }

        throw new Error('The provided id does not indicate a style tag.');
      }
    }

    let node = document.createElement('style');
    node.innerHTML = styles;
    node.type = 'text/css';

    if (id) {
      node.id = id;
    }

    destination = destination || document.head;

    if (prepend && destination.childNodes.length > 0) {
      destination.insertBefore(node, destination.childNodes[0]);
    } else {
      destination.appendChild(node);
    }

    return node;
  }
};
<|endoftext|>


<commit_before>import Viz from "viz.js/viz";
import * as d3 from "d3-selection";
import {extractAllElementsData, extractElementData, createElementWithAttributes} from "./element";
import {convertToPathData} from "./svg";
import {pathTweenPoints} from "./tweening";
import {isEdgeElement} from "./data";
import {getEdgeTitle} from "./data";

export function initViz() {
    // force JIT compilation of Viz.js
    if (this._worker == null) {
        Viz("");
        this._dispatch.call("initEnd", this);
    } else {
        var vizURL = this._vizURL;
        var graphvizInstance = this;
        this._worker.onmessage = function(event) {
            graphvizInstance._dispatch.call("initEnd", this);
        };
        if (!vizURL.match(/^https?:\/\/|^\/\//i)) {
            // Local URL. Prepend with local domain to be usable in web worker
            vizURL = document.location.protocol + '//' + document.location.host + '/' + vizURL;
        }
        this._worker.postMessage({dot: "", vizURL: vizURL});
    }
}

export default function(src, callback) {

    var graphvizInstance = this;
    var worker = this._worker;
    var engine = this._engine;
    var images = this._images;
    var totalMemory = this._totalMemory;
    var keyMode = this._keyMode;
    var tweenPaths = this._tweenPaths;
    var tweenShapes = this._tweenShapes;
    var tweenPrecision = this._tweenPrecision;
    var growEnteringEdges = this._growEnteringEdges;
    var dictionary = {};
    var prevDictionary = this._dictionary || {};
    var nodeDictionary = {};
    var prevNodeDictionary = this._nodeDictionary || {};

    function setKey(datum, index) {
        var tag = datum.tag;
        if (keyMode == 'index') {
            datum.key = index;
        } else if (tag[0] != '#') {
            if (keyMode == 'id') {
                datum.key = datum.attributes.id;
            } else if (keyMode == 'title') {
                var title = datum.children.find(function (childData) {
                    return childData.tag == 'title';
                });
                if (title) {
                    datum.key = title.children[0].text;
                }
            }
        }
        if (datum.key == null) {
            if (tweenShapes) {
                if (tag == 'ellipse' || tag == 'polygon') {
                    tag = 'path';
                }
            }
            datum.key = tag + '-' + index;
        }
    }

    function setId(datum, parentData) {
        var id = (parentData ? parentData.id + '.' : '') + datum.key;
        datum.id = id;
    }

    function addToDictionary(datum) {
        dictionary[datum.id] = datum;
    }

    function calculateAlternativeShapeData(datum, prevDatum) {
        if (tweenShapes && datum.id in prevDictionary) {
            if ((prevDatum.tag == 'polygon' || prevDatum.tag == 'ellipse' || prevDatum.tag == 'path') && (prevDatum.tag != datum.tag || datum.tag == 'polygon')) {
                if (prevDatum.tag != 'path') {
                    datum.alternativeOld = convertToPathData(prevDatum, datum);
                }
                if (datum.tag != 'path') {
                    datum.alternativeNew = convertToPathData(datum, prevDatum);
                }
            }
        }
    }

    function calculatePathTweenPoints(datum, prevDatum) {
        if (tweenPaths && prevDatum && (prevDatum.tag == 'path' || (datum.alternativeOld && datum.alternativeOld.tag == 'path'))) {
            var attribute_d = (datum.alternativeNew || datum).attributes.d;
            if (datum.alternativeOld) {
                var oldNode = createElementWithAttributes(datum.alternativeOld);
            } else {
                var oldNode = createElementWithAttributes(prevDatum);
            }
            (datum.alternativeOld || (datum.alternativeOld = {})).points = pathTweenPoints(oldNode, attribute_d, tweenPrecision);
        }
    }

    function postProcessDataPass1Local(datum, index=0, parentData) {
        setKey(datum, index);
        setId(datum, parentData);
        var id = datum.id;
        var prevDatum = prevDictionary[id];
        addToDictionary(datum);
        calculateAlternativeShapeData(datum, prevDatum);
        calculatePathTweenPoints(datum, prevDatum);
        var childTagIndexes = {};
        datum.children.forEach(function (childData) {
            var childTag = childData.tag;
            if (childTag == 'ellipse' || childTag == 'polygon') {
                childTag = 'path';
            }
            if (childTagIndexes[childTag] == null) {
                childTagIndexes[childTag] = 0;
            }
            var childIndex = childTagIndexes[childTag]++;
            postProcessDataPass1Local(childData, childIndex, datum);
        });
    }

    function addToNodeDictionary(datum) {
        var tag = datum.tag;
        if (growEnteringEdges && datum.parent) {
            if (datum.parent.attributes.class == 'node') {
                if (tag == 'title') {
                    var child = datum.children[0];
                    var nodeId = child.text;
                    nodeDictionary[nodeId] = datum.parent;
                }
            }
        }
    }

    function extractGrowingEdgesData(datum) {
        var id = datum.id;
        var tag = datum.tag;
        var prevDatum = prevDictionary[id];
        if (growEnteringEdges && !prevDatum && datum.parent) {
            if (isEdgeElement(datum)) {
                if (tag == 'path' || tag == 'polygon') {
                    if (tag == 'polygon') {
                        var path = datum.parent.children.find(function (e) {
                            return e.tag == 'path';
                        });
                        datum.totalLength = path.totalLength;
                    }
                    var title = getEdgeTitle(datum);
                    var child = title.children[0];
                    var nodeIds = child.text.split('->');
                    if (nodeIds.length != 2) {
                        nodeIds = child.text.split('--');
                    }
                    var startNodeId = nodeIds[0];
                    var startNode = nodeDictionary[startNodeId];
                    var prevStartNode = prevNodeDictionary[startNodeId];
                    if (prevStartNode) {
                        var i = startNode.children.findIndex(function (element, index) {
                            return element.tag == 'g';
                        });
                        if (i >= 0) {
                            var j = startNode.children[i].children.findIndex(function (element, index) {
                                return element.tag == 'a';
                            });
                            startNode = startNode.children[i].children[j];
                        }
                        var i = prevStartNode.children.findIndex(function (element, index) {
                            return element.tag == 'g';
                        });
                        if (i >= 0) {
                            var j = prevStartNode.children[i].children.findIndex(function (element, index) {
                                return element.tag == 'a';
                            });
                            prevStartNode = prevStartNode.children[i].children[j];
                        }
                        var startShapes = startNode.children;
                        for (var i = 0; i < startShapes.length; i++) {
                            if (startShapes[i].tag == 'polygon' || startShapes[i].tag == 'ellipse' || startShapes[i].tag == 'path') {
                                var startShape = startShapes[i];
                                break;
                            }
                        }
                        var prevStartShapes = prevStartNode.children;
                        for (var i = 0; i < prevStartShapes.length; i++) {
                            if (prevStartShapes[i].tag == 'polygon' || prevStartShapes[i].tag == 'ellipse' || prevStartShapes[i].tag == 'path') {
                                var prevStartShape = prevStartShapes[i];
                                break;
                            }
                        }
                        datum.offset = {
                            x: prevStartShape.center.x - startShape.center.x,
                            y: prevStartShape.center.y - startShape.center.y,
                        }
                    }
                }
            }
        }
    }

    function postProcessDataPass2Global(datum) {
        addToNodeDictionary(datum);
        extractGrowingEdgesData(datum);
        datum.children.forEach(function (childData) {
            postProcessDataPass2Global(childData);
        });
    }

    this._dispatch.call("start", this);
    this._busy = true;
    this._dispatch.call("layoutStart", this);
    var vizOptions = {
        format: "svg",
        engine: engine,
        images: images,
        totalMemory: totalMemory,
    };
    if (this._worker) {
        worker.postMessage({
            dot: src,
            options: vizOptions,
        });

        worker.onmessage = function(event) {
            switch (event.data.type) {
            case "done":
                return layoutDone.call(graphvizInstance, event.data.svg);
            case "error":
                if (graphvizInstance._onerror) {
                    graphvizInstance._onerror(event.data.error);
                } else {
                    throw event.data.error
                }
                break;
            }
        };
    } else {
        try {
            var svgDoc = Viz(src, vizOptions);
        }
        catch(error) {
            if (graphvizInstance._onerror) {
                graphvizInstance._onerror(error.message);
                return this;
            } else {
                throw error.message
            }
        }
        layoutDone.call(this, svgDoc);
    }

    function layoutDone(svgDoc) {
        this._dispatch.call("layoutEnd", this);

        var newDoc = d3.select(document.createDocumentFragment())
            .append('div');

        var parser = new window.DOMParser();
        var doc = parser.parseFromString(svgDoc, "image/svg+xml");

        newDoc
            .append(function() {
                return doc.documentElement;
            });

        var newSvg = newDoc
          .select('svg');

        var data = extractAllElementsData(newSvg);
        this._dispatch.call('dataExtractEnd', this);
        postProcessDataPass1Local(data);
        this._dispatch.call('dataProcessPass1End', this);
        postProcessDataPass2Global(data);
        this._dispatch.call('dataProcessPass2End', this);
        this._data = data;
        this._dictionary = dictionary;
        this._nodeDictionary = nodeDictionary;

        this._extractData = function (element, childIndex, parentData) {
            var data = extractAllElementsData(element);
            postProcessDataPass1Local(data, childIndex, parentData);
            postProcessDataPass2Global(data);
            return data;
        }
        this._busy = false;
        this._dispatch.call('dataProcessEnd', this);
        if (callback) {
            callback.call(this);
        }
        if (this._queue.length > 0) {
            var job = this._queue.shift();
            job.call(this);
        }
    }

    return this;
};
<commit_msg>Handle relative pathnames for local websites<commit_after>import Viz from "viz.js/viz";
import * as d3 from "d3-selection";
import {extractAllElementsData, extractElementData, createElementWithAttributes} from "./element";
import {convertToPathData} from "./svg";
import {pathTweenPoints} from "./tweening";
import {isEdgeElement} from "./data";
import {getEdgeTitle} from "./data";

export function initViz() {
    // force JIT compilation of Viz.js
    if (this._worker == null) {
        Viz("");
        this._dispatch.call("initEnd", this);
    } else {
        var vizURL = this._vizURL;
        var graphvizInstance = this;
        this._worker.onmessage = function(event) {
            graphvizInstance._dispatch.call("initEnd", this);
        };
        if (!vizURL.match(/^https?:\/\/|^\/\//i)) {
            // Local URL. Prepend with local domain to be usable in web worker
            vizURL = (new window.URL(vizURL, document.location.href)).href;
        }
        this._worker.postMessage({dot: "", vizURL: vizURL});
    }
}

export default function(src, callback) {

    var graphvizInstance = this;
    var worker = this._worker;
    var engine = this._engine;
    var images = this._images;
    var totalMemory = this._totalMemory;
    var keyMode = this._keyMode;
    var tweenPaths = this._tweenPaths;
    var tweenShapes = this._tweenShapes;
    var tweenPrecision = this._tweenPrecision;
    var growEnteringEdges = this._growEnteringEdges;
    var dictionary = {};
    var prevDictionary = this._dictionary || {};
    var nodeDictionary = {};
    var prevNodeDictionary = this._nodeDictionary || {};

    function setKey(datum, index) {
        var tag = datum.tag;
        if (keyMode == 'index') {
            datum.key = index;
        } else if (tag[0] != '#') {
            if (keyMode == 'id') {
                datum.key = datum.attributes.id;
            } else if (keyMode == 'title') {
                var title = datum.children.find(function (childData) {
                    return childData.tag == 'title';
                });
                if (title) {
                    datum.key = title.children[0].text;
                }
            }
        }
        if (datum.key == null) {
            if (tweenShapes) {
                if (tag == 'ellipse' || tag == 'polygon') {
                    tag = 'path';
                }
            }
            datum.key = tag + '-' + index;
        }
    }

    function setId(datum, parentData) {
        var id = (parentData ? parentData.id + '.' : '') + datum.key;
        datum.id = id;
    }

    function addToDictionary(datum) {
        dictionary[datum.id] = datum;
    }

    function calculateAlternativeShapeData(datum, prevDatum) {
        if (tweenShapes && datum.id in prevDictionary) {
            if ((prevDatum.tag == 'polygon' || prevDatum.tag == 'ellipse' || prevDatum.tag == 'path') && (prevDatum.tag != datum.tag || datum.tag == 'polygon')) {
                if (prevDatum.tag != 'path') {
                    datum.alternativeOld = convertToPathData(prevDatum, datum);
                }
                if (datum.tag != 'path') {
                    datum.alternativeNew = convertToPathData(datum, prevDatum);
                }
            }
        }
    }

    function calculatePathTweenPoints(datum, prevDatum) {
        if (tweenPaths && prevDatum && (prevDatum.tag == 'path' || (datum.alternativeOld && datum.alternativeOld.tag == 'path'))) {
            var attribute_d = (datum.alternativeNew || datum).attributes.d;
            if (datum.alternativeOld) {
                var oldNode = createElementWithAttributes(datum.alternativeOld);
            } else {
                var oldNode = createElementWithAttributes(prevDatum);
            }
            (datum.alternativeOld || (datum.alternativeOld = {})).points = pathTweenPoints(oldNode, attribute_d, tweenPrecision);
        }
    }

    function postProcessDataPass1Local(datum, index=0, parentData) {
        setKey(datum, index);
        setId(datum, parentData);
        var id = datum.id;
        var prevDatum = prevDictionary[id];
        addToDictionary(datum);
        calculateAlternativeShapeData(datum, prevDatum);
        calculatePathTweenPoints(datum, prevDatum);
        var childTagIndexes = {};
        datum.children.forEach(function (childData) {
            var childTag = childData.tag;
            if (childTag == 'ellipse' || childTag == 'polygon') {
                childTag = 'path';
            }
            if (childTagIndexes[childTag] == null) {
                childTagIndexes[childTag] = 0;
            }
            var childIndex = childTagIndexes[childTag]++;
            postProcessDataPass1Local(childData, childIndex, datum);
        });
    }

    function addToNodeDictionary(datum) {
        var tag = datum.tag;
        if (growEnteringEdges && datum.parent) {
            if (datum.parent.attributes.class == 'node') {
                if (tag == 'title') {
                    var child = datum.children[0];
                    var nodeId = child.text;
                    nodeDictionary[nodeId] = datum.parent;
                }
            }
        }
    }

    function extractGrowingEdgesData(datum) {
        var id = datum.id;
        var tag = datum.tag;
        var prevDatum = prevDictionary[id];
        if (growEnteringEdges && !prevDatum && datum.parent) {
            if (isEdgeElement(datum)) {
                if (tag == 'path' || tag == 'polygon') {
                    if (tag == 'polygon') {
                        var path = datum.parent.children.find(function (e) {
                            return e.tag == 'path';
                        });
                        datum.totalLength = path.totalLength;
                    }
                    var title = getEdgeTitle(datum);
                    var child = title.children[0];
                    var nodeIds = child.text.split('->');
                    if (nodeIds.length != 2) {
                        nodeIds = child.text.split('--');
                    }
                    var startNodeId = nodeIds[0];
                    var startNode = nodeDictionary[startNodeId];
                    var prevStartNode = prevNodeDictionary[startNodeId];
                    if (prevStartNode) {
                        var i = startNode.children.findIndex(function (element, index) {
                            return element.tag == 'g';
                        });
                        if (i >= 0) {
                            var j = startNode.children[i].children.findIndex(function (element, index) {
                                return element.tag == 'a';
                            });
                            startNode = startNode.children[i].children[j];
                        }
                        var i = prevStartNode.children.findIndex(function (element, index) {
                            return element.tag == 'g';
                        });
                        if (i >= 0) {
                            var j = prevStartNode.children[i].children.findIndex(function (element, index) {
                                return element.tag == 'a';
                            });
                            prevStartNode = prevStartNode.children[i].children[j];
                        }
                        var startShapes = startNode.children;
                        for (var i = 0; i < startShapes.length; i++) {
                            if (startShapes[i].tag == 'polygon' || startShapes[i].tag == 'ellipse' || startShapes[i].tag == 'path') {
                                var startShape = startShapes[i];
                                break;
                            }
                        }
                        var prevStartShapes = prevStartNode.children;
                        for (var i = 0; i < prevStartShapes.length; i++) {
                            if (prevStartShapes[i].tag == 'polygon' || prevStartShapes[i].tag == 'ellipse' || prevStartShapes[i].tag == 'path') {
                                var prevStartShape = prevStartShapes[i];
                                break;
                            }
                        }
                        datum.offset = {
                            x: prevStartShape.center.x - startShape.center.x,
                            y: prevStartShape.center.y - startShape.center.y,
                        }
                    }
                }
            }
        }
    }

    function postProcessDataPass2Global(datum) {
        addToNodeDictionary(datum);
        extractGrowingEdgesData(datum);
        datum.children.forEach(function (childData) {
            postProcessDataPass2Global(childData);
        });
    }

    this._dispatch.call("start", this);
    this._busy = true;
    this._dispatch.call("layoutStart", this);
    var vizOptions = {
        format: "svg",
        engine: engine,
        images: images,
        totalMemory: totalMemory,
    };
    if (this._worker) {
        worker.postMessage({
            dot: src,
            options: vizOptions,
        });

        worker.onmessage = function(event) {
            switch (event.data.type) {
            case "done":
                return layoutDone.call(graphvizInstance, event.data.svg);
            case "error":
                if (graphvizInstance._onerror) {
                    graphvizInstance._onerror(event.data.error);
                } else {
                    throw event.data.error
                }
                break;
            }
        };
    } else {
        try {
            var svgDoc = Viz(src, vizOptions);
        }
        catch(error) {
            if (graphvizInstance._onerror) {
                graphvizInstance._onerror(error.message);
                return this;
            } else {
                throw error.message
            }
        }
        layoutDone.call(this, svgDoc);
    }

    function layoutDone(svgDoc) {
        this._dispatch.call("layoutEnd", this);

        var newDoc = d3.select(document.createDocumentFragment())
            .append('div');

        var parser = new window.DOMParser();
        var doc = parser.parseFromString(svgDoc, "image/svg+xml");

        newDoc
            .append(function() {
                return doc.documentElement;
            });

        var newSvg = newDoc
          .select('svg');

        var data = extractAllElementsData(newSvg);
        this._dispatch.call('dataExtractEnd', this);
        postProcessDataPass1Local(data);
        this._dispatch.call('dataProcessPass1End', this);
        postProcessDataPass2Global(data);
        this._dispatch.call('dataProcessPass2End', this);
        this._data = data;
        this._dictionary = dictionary;
        this._nodeDictionary = nodeDictionary;

        this._extractData = function (element, childIndex, parentData) {
            var data = extractAllElementsData(element);
            postProcessDataPass1Local(data, childIndex, parentData);
            postProcessDataPass2Global(data);
            return data;
        }
        this._busy = false;
        this._dispatch.call('dataProcessEnd', this);
        if (callback) {
            callback.call(this);
        }
        if (this._queue.length > 0) {
            var job = this._queue.shift();
            job.call(this);
        }
    }

    return this;
};
<|endoftext|>


<commit_before>const LRU = cjsRequire('lru-cache')
const { IndexedCramFile, CraiIndex } = cjsRequire('@gmod/cram/src')
const { CramSizeLimitError } = cjsRequire('@gmod/cram/src/errors')

const { Buffer } = cjsRequire('buffer')

const cramIndexedFilesCache = LRU(5)

define( [
            'dojo/_base/declare',
            'JBrowse/Errors',
            'JBrowse/Store/SeqFeature',
            'JBrowse/Store/DeferredStatsMixin',
            'JBrowse/Store/DeferredFeaturesMixin',
            'JBrowse/Store/SeqFeature/GlobalStatsEstimationMixin',
            'JBrowse/Model/XHRBlob',
            'JBrowse/Model/SimpleFeature',
        ],
        function(
            declare,
            Errors,
            SeqFeatureStore,
            DeferredStatsMixin,
            DeferredFeaturesMixin,
            GlobalStatsEstimationMixin,
            XHRBlob,
            SimpleFeature,
        ) {

// wrapper class to make old JBrowse *Blob data access classes work with
// the new-style filehandle API expected by the cram code

class BlobWrapper {
    constructor(oldStyleBlob) {
        this.blob = oldStyleBlob
    }

    read(buffer, offset = 0, length, position) {
        return new Promise((resolve,reject) => {
            this.blob.read(
                position,
                length,
                dataArrayBuffer => {
                    const data = Buffer.from(dataArrayBuffer)
                    data.copy(buffer, offset)
                    resolve()
                },
                reject,
            )
        })
    }

    readFile() {
        return new Promise((resolve, reject) => {
            this.blob.fetch( dataArrayBuffer => {
                resolve(Buffer.from(dataArrayBuffer))
            }, reject)
        })
    }

    stat() {
        return new Promise((resolve, reject) => {
            this.blob.stat(resolve, reject)
        })
    }

    toString() {
        return ( this.blob.url  ? this.blob.url :
                 this.blob.blob ? this.blob.blob.name : undefined ) || undefined;
    }
}

return declare( [ SeqFeatureStore, DeferredStatsMixin, DeferredFeaturesMixin, GlobalStatsEstimationMixin ],

/**
 * @lends JBrowse.Store.SeqFeature.CRAM
 */
{
    /**
     * Data backend for reading feature data directly from a
     * web-accessible CRAM file.
     *
     * @constructs
     */
    constructor: function( args ) {

        let dataBlob
        if (args.cram)
            dataBlob = new BlobWrapper(args.cram)
        else if (args.urlTemplate)
            dataBlob = new BlobWrapper(new XHRBlob(this.resolveUrl(args.urlTemplate || 'data.cram')))
        else throw new Error('must provide either `cram` or `urlTemplate`')

        let indexBlob
        if (args.crai)
            indexBlob = new BlobWrapper(args.crai)
        else if (args.craiUrlTemplate)
            indexBlob = new BlobWrapper(new XHRBlob(this.resolveUrl(args.craiUrlTemplate)))
        else if (args.urlTemplate)
            indexBlob = new BlobWrapper(new XHRBlob(this.resolveUrl(args.urlTemplate+'.crai')))
        else throw new Error('no index provided, must provide a CRAM index')

        this.source = dataBlob.toString().match( /\/([^/\#\?]+)($|[\#\?])/ )[1]

        // LRU-cache the CRAM object so we don't have to re-download the
        // index when we switch chromosomes
        const cacheKey = `data: ${dataBlob}, index: ${indexBlob}`
        this.cram = cramIndexedFilesCache.get(cacheKey)
        if (!this.cram) {
            this.cram = new IndexedCramFile({
                cramFilehandle: dataBlob,
                index: new CraiIndex({filehandle: indexBlob}),
                seqFetch: this._seqFetch.bind(this),
                checkSequenceMD5: false,
            })

            cramIndexedFilesCache.set(cacheKey, this.cram)
        }

        // pre-download the index before running the statistics estimation so that the stats
        // estimation doesn't time out
        this.cram.hasDataForReferenceSequence(0)
            .then(() => this.cram.cram.getSamHeader())
            .then(samHeader => {
                this._setSamHeader(samHeader)
            })
            .then(() => {
                this._deferred.features.resolve({success:true});
            })
            .then(() => this._estimateGlobalStats())
            .then(stats => {
                this.globalStats = stats;
                this._deferred.stats.resolve({success:true});
            })
            .catch(err => {
                this._deferred.features.reject(err)
                this._deferred.stats.reject(err)
            })

        this.storeTimeout = args.storeTimeout || 3000;
    },

    // process the parsed SAM header from the cram file
    _setSamHeader(samHeader) {
        this._samHeader = {}

        // use the @SQ lines in the header to figure out the
        // mapping between ref seq ID numbers and names
        const refSeqIdToName = []
        const refSeqNameToId = {}
        const sqLines = samHeader.filter(l => l.tag === 'SQ')
        sqLines.forEach((sqLine, seqId) => {
            sqLine.data.forEach(item => {
                if (item.tag === 'SN') {
                    // this is the seq name
                    const seqName = item.value
                    refSeqNameToId[seqName] = seqId
                    refSeqIdToName[seqId] = seqName
                }
            })
        })
        if (refSeqIdToName.length) {
            this._samHeader.refSeqIdToName = refSeqIdToName
            this._samHeader.refSeqNameToId = refSeqNameToId
        }
    },

    _refNameToId(refName) {
        // use info from the SAM header if possible, but fall back to using
        // the ref seq order from when the browser's refseqs were loaded
        if (this._samHeader.refSeqNameToId)
            return this._samHeader.refSeqNameToId[refName]
        else
            return this.browser.getRefSeqNumber(refName)
    },

    _refIdToName(refId) {
        // use info from the SAM header if possible, but fall back to using
        // the ref seq order from when the browser's refseqs were loaded
        if (this._samHeader.refSeqIdToName) {
            return this._samHeader.refSeqIdToName[refId]
        } else {
            let ref = this.browser.getRefSeqById(refId)
            return ref ? ref.name : undefined
        }
    },

    _getRefSeqStore() {
        return new Promise((resolve,reject) => {
            this.browser.getStore('refseqs',resolve,reject)
        })
    },

    // used by the CRAM backend to fetch a region of the underlying reference
    // sequence.  needed for some of its calculations
    async _seqFetch(seqId, start, end) {
        start -= 1 // convert from 1-based closed to interbase

        const refSeqStore = await this._getRefSeqStore()
        if (!refSeqStore) return undefined
        const refName = this._refIdToName(seqId)
        if (!refName) return undefined

        const seqChunks = await new Promise((resolve,reject) => {
            let features = []
            refSeqStore.getFeatures(
                {ref: refName, start: start-1, end},
                f => features.push(f),
                () => resolve(features),
                reject
            )
        })

        const trimmed = []
        seqChunks
        .sort((a,b) => a.get('start') - b.get('start'))
        .forEach( (chunk,i) => {
            let chunkStart = chunk.get('start')
            let chunkEnd = chunk.get('end')
            let trimStart = Math.max(start - chunkStart, 0)
            let trimEnd = Math.min(end - chunkStart, chunkEnd-chunkStart)
            let trimLength = trimEnd - trimStart
            let chunkSeq = chunk.get('seq') || chunk.get('residues')
            trimmed.push(chunkSeq.substr(trimStart,trimLength))
        })

        const sequence = trimmed.join('')
        if (sequence.length !== (end-start))
            throw new Error('sequence fetch sanity check failed')
        return sequence
    },

    /**
     * Interrogate whether a store has data for a given reference
     * sequence.  Calls the given callback with either true or false.
     *
     * Implemented as a binary interrogation because some stores are
     * smart enough to regularize reference sequence names, while
     * others are not.
     */
    hasRefSeq: function( seqName, callback, errorCallback ) {
        seqName = this.browser.regularizeReferenceName( seqName );
        const refSeqNumber = this._refNameToId(seqName)
        if (refSeqNumber === undefined) callback(false)

        this._deferred.stats
        .then(() => this.cram.hasDataForReferenceSequence(refSeqNumber))
        .then(callback, errorCallback)
    },

    // called by getFeatures from the DeferredFeaturesMixin
    _getFeatures: function( query, featCallback, endCallback, errorCallback ) {
        //this.bam.fetch( query.ref ? query.ref : this.refSeq.name, query.start, query.end, featCallback, endCallback, errorCallback );
        const seqName = query.ref || this.refSeq.name
        const refSeqNumber = this._refNameToId(seqName)
        if (refSeqNumber === undefined) {
            endCallback()
            return
        }

        this.cram.getRecordsForRange(refSeqNumber, query.start + 1, query.end)
            .then(records => {
                for (let i = 0; i < records.length; i+= 1) {
                    featCallback(this._cramRecordToFeature(records[i]))
                }

                endCallback()
            })
            .catch(err => {
                // map the CramSizeLimitError to JBrowse Errors.DataOverflow
                if (err instanceof CramSizeLimitError) {
                    err = new Errors.DataOverflow(err)
                }

                errorCallback(err)
            })
    },

    _cramRecordToFeature(record) {
        const data = {
            name: record.readName,
            start: record.alignmentStart-1,
            end: record.alignmentStart+record.lengthOnRef-1,
            cram_read_features: record.readFeatures,
            type: 'match',
            MQ: record.mappingQuality,
            flags: `0x${record.flags.toString(16)}`,
            cramFlags: `0x${record.cramFlags.toString(16)}`,
            strand: record.isReverseComplemented() ? -1 : 1,
            qual: (record.qualityScores || []).map(q => q+33).join(' '),
            seq: record.readBases,
            seq_id: this._refIdToName(record.sequenceId),

            qc_failed: record.isFailedQc(),
            secondary_alignment: record.isSecondary(),
            supplementary_alignment: record.isSupplementary(),
            multi_segment_template: record.isPaired(),
            multi_segment_all_correctly_aligned: record.isProperlyPaired(),
            multi_segment_next_segment_unmapped: record.isMateUnmapped(),
            multi_segment_first: record.isRead1(),
            multi_segment_last: record.isRead2(),
            multi_segment_next_segment_reversed: record.isMateReverseComplemented(),
            unmapped: record.isSegmentUnmapped(),
            next_seq_id: record.mate ? this._refIdToName(record.mate.sequenceId) : undefined,
            next_segment_position: record.mate
                ? ( this._refIdToName(record.mate.sequenceId)+':'+record.mate.alignmentStart) : undefined,
        }
        Object.assign(data,record.tags || {})
        return new SimpleFeature({
            data,
            id: record.uniqueId
        })
    },

    saveStore: function() {
        return {
            urlTemplate: this.config.bam.url,
            baiUrlTemplate: this.config.bai.url
        };
    }

});
});
<commit_msg>improve seq fetching error message<commit_after>const LRU = cjsRequire('lru-cache')
const { IndexedCramFile, CraiIndex } = cjsRequire('@gmod/cram/src')
const { CramSizeLimitError } = cjsRequire('@gmod/cram/src/errors')

const { Buffer } = cjsRequire('buffer')

const cramIndexedFilesCache = LRU(5)

define( [
            'dojo/_base/declare',
            'JBrowse/Errors',
            'JBrowse/Store/SeqFeature',
            'JBrowse/Store/DeferredStatsMixin',
            'JBrowse/Store/DeferredFeaturesMixin',
            'JBrowse/Store/SeqFeature/GlobalStatsEstimationMixin',
            'JBrowse/Model/XHRBlob',
            'JBrowse/Model/SimpleFeature',
        ],
        function(
            declare,
            Errors,
            SeqFeatureStore,
            DeferredStatsMixin,
            DeferredFeaturesMixin,
            GlobalStatsEstimationMixin,
            XHRBlob,
            SimpleFeature,
        ) {

// wrapper class to make old JBrowse *Blob data access classes work with
// the new-style filehandle API expected by the cram code

class BlobWrapper {
    constructor(oldStyleBlob) {
        this.blob = oldStyleBlob
    }

    read(buffer, offset = 0, length, position) {
        return new Promise((resolve,reject) => {
            this.blob.read(
                position,
                length,
                dataArrayBuffer => {
                    const data = Buffer.from(dataArrayBuffer)
                    data.copy(buffer, offset)
                    resolve()
                },
                reject,
            )
        })
    }

    readFile() {
        return new Promise((resolve, reject) => {
            this.blob.fetch( dataArrayBuffer => {
                resolve(Buffer.from(dataArrayBuffer))
            }, reject)
        })
    }

    stat() {
        return new Promise((resolve, reject) => {
            this.blob.stat(resolve, reject)
        })
    }

    toString() {
        return ( this.blob.url  ? this.blob.url :
                 this.blob.blob ? this.blob.blob.name : undefined ) || undefined;
    }
}

return declare( [ SeqFeatureStore, DeferredStatsMixin, DeferredFeaturesMixin, GlobalStatsEstimationMixin ],

/**
 * @lends JBrowse.Store.SeqFeature.CRAM
 */
{
    /**
     * Data backend for reading feature data directly from a
     * web-accessible CRAM file.
     *
     * @constructs
     */
    constructor: function( args ) {

        let dataBlob
        if (args.cram)
            dataBlob = new BlobWrapper(args.cram)
        else if (args.urlTemplate)
            dataBlob = new BlobWrapper(new XHRBlob(this.resolveUrl(args.urlTemplate || 'data.cram')))
        else throw new Error('must provide either `cram` or `urlTemplate`')

        let indexBlob
        if (args.crai)
            indexBlob = new BlobWrapper(args.crai)
        else if (args.craiUrlTemplate)
            indexBlob = new BlobWrapper(new XHRBlob(this.resolveUrl(args.craiUrlTemplate)))
        else if (args.urlTemplate)
            indexBlob = new BlobWrapper(new XHRBlob(this.resolveUrl(args.urlTemplate+'.crai')))
        else throw new Error('no index provided, must provide a CRAM index')

        this.source = dataBlob.toString().match( /\/([^/\#\?]+)($|[\#\?])/ )[1]

        // LRU-cache the CRAM object so we don't have to re-download the
        // index when we switch chromosomes
        const cacheKey = `data: ${dataBlob}, index: ${indexBlob}`
        this.cram = cramIndexedFilesCache.get(cacheKey)
        if (!this.cram) {
            this.cram = new IndexedCramFile({
                cramFilehandle: dataBlob,
                index: new CraiIndex({filehandle: indexBlob}),
                seqFetch: this._seqFetch.bind(this),
                checkSequenceMD5: false,
            })

            cramIndexedFilesCache.set(cacheKey, this.cram)
        }

        // pre-download the index before running the statistics estimation so that the stats
        // estimation doesn't time out
        this.cram.hasDataForReferenceSequence(0)
            .then(() => this.cram.cram.getSamHeader())
            .then(samHeader => {
                this._setSamHeader(samHeader)
            })
            .then(() => {
                this._deferred.features.resolve({success:true});
            })
            .then(() => this._estimateGlobalStats())
            .then(stats => {
                this.globalStats = stats;
                this._deferred.stats.resolve({success:true});
            })
            .catch(err => {
                this._deferred.features.reject(err)
                this._deferred.stats.reject(err)
            })

        this.storeTimeout = args.storeTimeout || 3000;
    },

    // process the parsed SAM header from the cram file
    _setSamHeader(samHeader) {
        this._samHeader = {}

        // use the @SQ lines in the header to figure out the
        // mapping between ref seq ID numbers and names
        const refSeqIdToName = []
        const refSeqNameToId = {}
        const sqLines = samHeader.filter(l => l.tag === 'SQ')
        sqLines.forEach((sqLine, seqId) => {
            sqLine.data.forEach(item => {
                if (item.tag === 'SN') {
                    // this is the seq name
                    const seqName = item.value
                    refSeqNameToId[seqName] = seqId
                    refSeqIdToName[seqId] = seqName
                }
            })
        })
        if (refSeqIdToName.length) {
            this._samHeader.refSeqIdToName = refSeqIdToName
            this._samHeader.refSeqNameToId = refSeqNameToId
        }
    },

    _refNameToId(refName) {
        // use info from the SAM header if possible, but fall back to using
        // the ref seq order from when the browser's refseqs were loaded
        if (this._samHeader.refSeqNameToId)
            return this._samHeader.refSeqNameToId[refName]
        else
            return this.browser.getRefSeqNumber(refName)
    },

    _refIdToName(refId) {
        // use info from the SAM header if possible, but fall back to using
        // the ref seq order from when the browser's refseqs were loaded
        if (this._samHeader.refSeqIdToName) {
            return this._samHeader.refSeqIdToName[refId]
        } else {
            let ref = this.browser.getRefSeqById(refId)
            return ref ? ref.name : undefined
        }
    },

    _getRefSeqStore() {
        return new Promise((resolve,reject) => {
            this.browser.getStore('refseqs',resolve,reject)
        })
    },

    // used by the CRAM backend to fetch a region of the underlying reference
    // sequence.  needed for some of its calculations
    async _seqFetch(seqId, start, end) {
        start -= 1 // convert from 1-based closed to interbase

        const refSeqStore = await this._getRefSeqStore()
        if (!refSeqStore) return undefined
        const refName = this._refIdToName(seqId)
        if (!refName) return undefined

        const seqChunks = await new Promise((resolve,reject) => {
            let features = []
            refSeqStore.getFeatures(
                {ref: refName, start: start-1, end},
                f => features.push(f),
                () => resolve(features),
                reject
            )
        })

        const trimmed = []
        seqChunks
        .sort((a,b) => a.get('start') - b.get('start'))
        .forEach( (chunk,i) => {
            let chunkStart = chunk.get('start')
            let chunkEnd = chunk.get('end')
            let trimStart = Math.max(start - chunkStart, 0)
            let trimEnd = Math.min(end - chunkStart, chunkEnd-chunkStart)
            let trimLength = trimEnd - trimStart
            let chunkSeq = chunk.get('seq') || chunk.get('residues')
            trimmed.push(chunkSeq.substr(trimStart,trimLength))
        })

        const sequence = trimmed.join('')
        if (sequence.length !== (end-start))
            throw new Error(`sequence fetch failed: fetching ${
                (start-1).toLocaleString()}-${end.toLocaleString()
                } only returned ${
                    sequence.length.toLocaleString()
                } bases, but should have returned ${
                    (end-start).toLocaleString()
                }`)
        return sequence
    },

    /**
     * Interrogate whether a store has data for a given reference
     * sequence.  Calls the given callback with either true or false.
     *
     * Implemented as a binary interrogation because some stores are
     * smart enough to regularize reference sequence names, while
     * others are not.
     */
    hasRefSeq: function( seqName, callback, errorCallback ) {
        seqName = this.browser.regularizeReferenceName( seqName );
        const refSeqNumber = this._refNameToId(seqName)
        if (refSeqNumber === undefined) callback(false)

        this._deferred.stats
        .then(() => this.cram.hasDataForReferenceSequence(refSeqNumber))
        .then(callback, errorCallback)
    },

    // called by getFeatures from the DeferredFeaturesMixin
    _getFeatures: function( query, featCallback, endCallback, errorCallback ) {
        //this.bam.fetch( query.ref ? query.ref : this.refSeq.name, query.start, query.end, featCallback, endCallback, errorCallback );
        const seqName = query.ref || this.refSeq.name
        const refSeqNumber = this._refNameToId(seqName)
        if (refSeqNumber === undefined) {
            endCallback()
            return
        }

        this.cram.getRecordsForRange(refSeqNumber, query.start + 1, query.end)
            .then(records => {
                for (let i = 0; i < records.length; i+= 1) {
                    featCallback(this._cramRecordToFeature(records[i]))
                }

                endCallback()
            })
            .catch(err => {
                // map the CramSizeLimitError to JBrowse Errors.DataOverflow
                if (err instanceof CramSizeLimitError) {
                    err = new Errors.DataOverflow(err)
                }

                errorCallback(err)
            })
    },

    _cramRecordToFeature(record) {
        const data = {
            name: record.readName,
            start: record.alignmentStart-1,
            end: record.alignmentStart+record.lengthOnRef-1,
            cram_read_features: record.readFeatures,
            type: 'match',
            MQ: record.mappingQuality,
            flags: `0x${record.flags.toString(16)}`,
            cramFlags: `0x${record.cramFlags.toString(16)}`,
            strand: record.isReverseComplemented() ? -1 : 1,
            qual: (record.qualityScores || []).map(q => q+33).join(' '),
            seq: record.readBases,
            seq_id: this._refIdToName(record.sequenceId),

            qc_failed: record.isFailedQc(),
            secondary_alignment: record.isSecondary(),
            supplementary_alignment: record.isSupplementary(),
            multi_segment_template: record.isPaired(),
            multi_segment_all_correctly_aligned: record.isProperlyPaired(),
            multi_segment_next_segment_unmapped: record.isMateUnmapped(),
            multi_segment_first: record.isRead1(),
            multi_segment_last: record.isRead2(),
            multi_segment_next_segment_reversed: record.isMateReverseComplemented(),
            unmapped: record.isSegmentUnmapped(),
            next_seq_id: record.mate ? this._refIdToName(record.mate.sequenceId) : undefined,
            next_segment_position: record.mate
                ? ( this._refIdToName(record.mate.sequenceId)+':'+record.mate.alignmentStart) : undefined,
        }
        Object.assign(data,record.tags || {})
        return new SimpleFeature({
            data,
            id: record.uniqueId
        })
    },

    saveStore: function() {
        return {
            urlTemplate: this.config.bam.url,
            baiUrlTemplate: this.config.bai.url
        };
    }

});
});
<|endoftext|>


<commit_before>class DiscordEventListener {
    constructor(client, server, channelName) {
        this.client      = client;
        this.server      = server;
        this.channelName = channelName;
    }

    listen() {
        this.channel = this.server.channels.get('name', this.channelName);
        if (this.channel === null || this.channel === undefined) {
            return this.client.createChannel(this.server, this.channelName, 'text', (error, channel) => {
                if (error) {
                    return console.log(`Could not create channel in ${this.server.name}: ${this.channelName}`);
                }

                this.addListeners();
            });
        }

        this.addListeners();
    }

    addListeners() {
        this.client.on('ready', client => this.logEvent('Bot is ready'));

        this.client.on('channelCreated', this.onChannel.bind(this, 'created'));
        this.client.on('channelDeleted', this.onChannel.bind(this, 'deleted'));
        this.client.on('channelUpdated', this.onChannel.bind(this, 'updated'));

        this.client.on('serverNewMember', this.onServerUser.bind(this, 'new'));
        this.client.on('serverMemberRemoved', this.onServerUser.bind(this, 'removed'));

        this.client.on('userBanned', this.onUser.bind(this, 'ban'));
        this.client.on('userUnbanned', this.onUser.bind(this, 'unban'));

        //this.client.on('voiceJoin', this.onVoice.bind(this, 'voice_join'));
        //this.client.on('voiceLeave', this.onVoice.bind(this, 'voice_leave'));

        // Commented out until the presence update is better
        //this.client.on('presence', this.onUserPresence.bind(this));
    }

    logEvent(message) {
        this.client.sendMessage(this.channel, message);
    }

    onChannel(type, channel, updatedChannel) {
        if (channel.server === undefined) {
            return;
        }

        if (channel.server.id !== this.server.id) {
            return;
        }

        if (type !== 'updated') {
            return this.logEvent(`Channel ${type}: \`${channel.name}\``);
        }

        if (channel.name !== updatedChannel.name) {
            this.logEvent(`Channel name changed: \`${channel.name}\` -> \`${updatedChannel.name}\``);
        }
    }

    onServerUser(type, server, user) {
        if (server.id !== this.server.id) {
            return;
        }

        this.logEvent(`${user.username} has ${type === 'new' ? 'joined' : 'left'} the server.`);
    }

    onUser(type, user, server) {
        if (server.id !== this.server.id) {
            return;
        }

        this.logEvent(`${user.username} has been ${type}ned`);
    }

    onVoice(type, user, channel) {
        if (channel.server.id !== this.server.id) {
            return;
        }

        this.logEvent(
            `${user.username} has ${type === 'voice_join' ? 'joined' : 'left'} the voice channel:  ${channel.name}.`
        );
    }

    onUserPresence(user, status, game) {
        if (server.id !== this.server.id) {
            return;
        }

    }
}

module.exports = DiscordEventListener;<commit_msg>Returning false on voice<commit_after>class DiscordEventListener {
    constructor(client, server, channelName) {
        this.client      = client;
        this.server      = server;
        this.channelName = channelName;
    }

    listen() {
        this.channel = this.server.channels.get('name', this.channelName);
        if (this.channel === null || this.channel === undefined) {
            return this.client.createChannel(this.server, this.channelName, 'text', (error, channel) => {
                if (error) {
                    return console.log(`Could not create channel in ${this.server.name}: ${this.channelName}`);
                }

                this.addListeners();
            });
        }

        this.addListeners();
    }

    addListeners() {
        this.client.on('ready', client => this.logEvent('Bot is ready'));

        this.client.on('channelCreated', this.onChannel.bind(this, 'created'));
        this.client.on('channelDeleted', this.onChannel.bind(this, 'deleted'));
        this.client.on('channelUpdated', this.onChannel.bind(this, 'updated'));

        this.client.on('serverNewMember', this.onServerUser.bind(this, 'new'));
        this.client.on('serverMemberRemoved', this.onServerUser.bind(this, 'removed'));

        this.client.on('userBanned', this.onUser.bind(this, 'ban'));
        this.client.on('userUnbanned', this.onUser.bind(this, 'unban'));

        //this.client.on('voiceJoin', this.onVoice.bind(this, 'voice_join'));
        //this.client.on('voiceLeave', this.onVoice.bind(this, 'voice_leave'));

        // Commented out until the presence update is better
        //this.client.on('presence', this.onUserPresence.bind(this));
    }

    logEvent(message) {
        this.client.sendMessage(this.channel, message);
    }

    onChannel(type, channel, updatedChannel) {
        if (channel.server === undefined) {
            return;
        }

        if (channel.server.id !== this.server.id) {
            return;
        }

        if (type !== 'updated') {
            return this.logEvent(`Channel ${type}: \`${channel.name}\``);
        }

        if (channel.name !== updatedChannel.name) {
            this.logEvent(`Channel name changed: \`${channel.name}\` -> \`${updatedChannel.name}\``);
        }
    }

    onServerUser(type, server, user) {
        if (server.id !== this.server.id) {
            return;
        }

        this.logEvent(`${user.username} has ${type === 'new' ? 'joined' : 'left'} the server.`);
    }

    onUser(type, user, server) {
        if (server.id !== this.server.id) {
            return;
        }

        this.logEvent(`${user.username} has been ${type}ned`);
    }

    onVoice(type, user, channel) {
        return;
        if (channel.server.id !== this.server.id) {
            return;
        }

        this.logEvent(
            `${user.username} has ${type === 'voice_join' ? 'joined' : 'left'} the voice channel:  ${channel.name}.`
        );
    }

    onUserPresence(user, status, game) {
        if (server.id !== this.server.id) {
            return;
        }

    }
}

module.exports = DiscordEventListener;<|endoftext|>


<commit_before>import mat4 from 'gl-mat4'
import bunny from 'bunny'

// /per model data
let triMat = mat4.identity([]) // create([])
mat4.translate(triMat, triMat, [1, 10, 20])

const triData = {
  geometry: {
    positions: /* [
      2, 2, 0,
      1, 2, -2,
      0, 1, -2
    ],*/
    new Float32Array([ // works too!
      2, 2, 0,
      1, 2, -2,
      0, 1, -2
    ])
  },
  transforms: {
    pos: [0, 0, 0],
    rot: [0, 0, 0],
    sca: [1, 1, 1]
  },

  visuals: {
    color: [1, 0, 0, 0.5],
    type: 'mesh'
  }

}

const bunnyGeom = Object.assign({}, bunny, {id: '0'})

const bunnyData = {
  id: 'b0',
  geometry: bunnyGeom, // in truth I do not see cases where bounds would change independantly of geometry, but we might
  // have bounds WITHOUT geometry

  bounds: {
    dia: 40,
    min: [9, 10, 0],
    max: [15, 10, 4]
  },

  transforms: {
    pos: [0, 0, 0],
    rot: [0, 0, 0],
    sca: [1, 1, 1]
  },

  visuals: {
    color: [1, 1, 0, 0.5],
    type: 'mesh'
  },

  meta: {
    selected: true,
    pickable: true
  }

}

const bunnyData2 = {
  id: 'b1',
  geometry: bunnyGeom,
  transforms: {
    pos: [0, 0, 0],
    rot: [0, 0, 0],
    sca: [1, 1, -1]
  },

  visuals: {
    color: [0, 1, 1, 0.5],
    visible: true,
    type: 'mesh'
  },

  meta: {
    selected: false,
    pickable: true
  }
}

const bunnyData3 = {
  id: 'b2',
  geometry: bunnyGeom,
  transforms: {
    pos: [10, -12.989, 3],
    rot: [0, 0, 0],
    sca: [1, 1, 1]
  },
  visuals: {
    color: [1, 1, 0, 0.5],
    type: 'mesh'
  },

  meta: {
    selected: false,
    pickable: true
  }
}

const sceneData = {
  cameras: [
    {
      pos: [75, 75, 145], // [100,-100,100]
      up: [0, 0, 1],
      lens: {
        fov: 45,
        near: 0.1,
        far: 20000
      }
    }
  ],
  controls: [ //not in use !!! see orbitControls.js directly
    {
      up: [0, 0, 1],
      rotateSpeed: 0.2,
      panSpeed: 2.0,
      zoomSpeed: 2.0,
      autoRotate: {
        enabled: false,
        speed: 0.2
      },
      enabled: true
    }
  ],
  // lighting data
  lights: [
    {position: [100, 100, 200], color: [0.8, 0.6, 0.6], intensity: 0.4},
    {position: [-100, -200, 100], color: [0.75, 0.7, 0.7], intensity: 0.4},
    {position: [100, 200, -210], color: [0.9, 0.9, 0.9], intensity: 0.4},
    {position: [-100, -210, -200], color: [0.7, 0.7, 0.8], intensity: 0.4}
  ]
}

export { bunnyData, bunnyData2, bunnyData3, sceneData }
<commit_msg>chore(test data): minor changes to testData (object colors, selections etc)<commit_after>import mat4 from 'gl-mat4'
import bunny from 'bunny'

// /per model data
let triMat = mat4.identity([]) // create([])
mat4.translate(triMat, triMat, [1, 10, 20])

const triData = {
  geometry: {
    positions: /* [
      2, 2, 0,
      1, 2, -2,
      0, 1, -2
    ],*/
    new Float32Array([ // works too!
      2, 2, 0,
      1, 2, -2,
      0, 1, -2
    ])
  },
  transforms: {
    pos: [0, 0, 0],
    rot: [0, 0, 0],
    sca: [1, 1, 1]
  },

  visuals: {
    color: [1, 0, 0, 0.5],
    type: 'mesh'
  }

}

const bunnyGeom = Object.assign({}, bunny, {id: '0'})

const bunnyData = {
  id: 'b0',
  geometry: bunnyGeom, // in truth I do not see cases where bounds would change independantly of geometry, but we might
  // have bounds WITHOUT geometry

  bounds: {
    dia: 40,
    min: [9, 10, 0],
    max: [15, 10, 4]
  },

  transforms: {
    pos: [0, 0, 0],
    rot: [0, 0, 0],
    sca: [1, 1, 1]
  },

  visuals: {
    color: [0.02, 0.7, 1, 1], // 07a9ff [1, 1, 0, 0.5],
    type: 'mesh'
  },

  meta: {
    selected: false,
    pickable: true
  }

}

const bunnyData2 = {
  id: 'b1',
  geometry: bunnyGeom,
  transforms: {
    pos: [0, 0, 0],
    rot: [0, 0, 0],
    sca: [1, 1, -1]
  },

  visuals: {
    color: [0, 1, 1, 0.5],
    visible: true,
    type: 'mesh'
  },

  meta: {
    selected: false,
    pickable: true
  }
}

const bunnyData3 = {
  id: 'b2',
  geometry: bunnyGeom,
  transforms: {
    pos: [10, -12.989, 3],
    rot: [0, 0, 0],
    sca: [1, 1, 1]
  },
  visuals: {
    color: [1, 1, 0, 0.5],
    type: 'mesh'
  },

  meta: {
    selected: true,
    pickable: true
  }
}

const sceneData = {
  cameras: [
    {
      pos: [75, 75, 145], // [100,-100,100]
      up: [0, 0, 1],
      lens: {
        fov: 45,
        near: 0.1,
        far: 20000
      }
    }
  ],
  controls: [ //not in use !!! see orbitControls.js directly
    {
      up: [0, 0, 1],
      rotateSpeed: 0.2,
      panSpeed: 2.0,
      zoomSpeed: 2.0,
      autoRotate: {
        enabled: false,
        speed: 0.2
      },
      enabled: true
    }
  ],
  // lighting data
  lights: [
    {position: [100, 100, 200], color: [0.8, 0.6, 0.6], intensity: 0.4},
    {position: [-100, -200, 100], color: [0.75, 0.7, 0.7], intensity: 0.4},
    {position: [100, 200, -210], color: [0.9, 0.9, 0.9], intensity: 0.4},
    {position: [-100, -210, -200], color: [0.7, 0.7, 0.8], intensity: 0.4}
  ]
}

export { bunnyData, bunnyData2, bunnyData3, sceneData }
<|endoftext|>