<commit_before>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        var directives = {};
        var self = this;
        this.$el = document.querySelector(_el);
        this.components = opts.components;
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        /**
        * Converts attributes into key-value pairs
        * @param {Node} node
        * @return {Object} Key-Value pairs of Attributes
        */
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        /**
        * Compiles a template with given data
        * @param {String} template
        * @param {Object} data
        * @return {String} Template with data rendered
        */
        var compileTemplate = function(template, data) {
          var code = template,
              re = /{{([.]?\w+)}}/gi;
          code.replace(re, function(match, p) {
            code = code.replace(match, "` + data." + p + " + `");
          });
          var compile = new Function("data", "var out = `" + code + "`; return out");
          return compile(data);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        /**
        * Turns Custom Components into their Corresponding Templates
        */
        this.componentsToHTML = function() {
          for(var component in this.components) {
            var componentsFound = document.getElementsByTagName(component);
            for(var i = 0; i < componentsFound.length; i++) {
              componentsFound[i].outerHTML = this.components[component].template;
            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Makes an AJAX Request
        * @param {String} method
        * @param {String} url
        * @param {Object} params
        * @param {Function} cb
        */
        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        // Call a method defined in _methods
        this.method = function(method) {
          _methods[method]();
        }

        // Directive Initialization
        this.directive = function(name, action) {
          directives["m-" + name] = action;
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        // Build the DOM with $data
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  directive(el.node, compiledProperty, el);
                }

                el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        // Initialize
        this.componentsToHTML();
        this.createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<commit_msg>comment method<commit_after>"use strict";
(function(window) {
    function Moon(opts) {
        var _el = opts.el;
        var _data = opts.data;
        var _methods = opts.methods;
        var directives = {};
        var self = this;
        this.$el = document.querySelector(_el);
        this.components = opts.components;
        this.dom = {type: this.$el.nodeName, children: [], node: this.$el};

        // Change state when $data is changed
        Object.defineProperty(this, '$data', {
            get: function() {
                return _data;
            },
            set: function(value) {
                _data = value;
                this.build(this.dom.children);
            }
        });

        /**
        * Converts attributes into key-value pairs
        * @param {Node} node
        * @return {Object} Key-Value pairs of Attributes
        */
        var extractAttrs = function(node) {
          var attrs = {};
          if(!node.attributes) return attrs;
          var rawAttrs = node.attributes;
          for(var i = 0; i < rawAttrs.length; i++) {
            attrs[rawAttrs[i].name] = rawAttrs[i].value
          }

          return attrs;
        }

        /**
        * Compiles a template with given data
        * @param {String} template
        * @param {Object} data
        * @return {String} Template with data rendered
        */
        var compileTemplate = function(template, data) {
          var code = template,
              re = /{{([.]?\w+)}}/gi;
          code.replace(re, function(match, p) {
            code = code.replace(match, "` + data." + p + " + `");
          });
          var compile = new Function("data", "var out = `" + code + "`; return out");
          return compile(data);
        }

        /**
        * Creates an object to be used in a Virtual DOM
        * @param {String} type
        * @param {Array} children
        * @param {String} val
        * @param {Object} props
        * @param {Node} node
        * @return {Object} Object usable in Virtual DOM
        */
        this.createElement = function(type, children, val, props, node) {
          return {type: type, children: children, val: val, props: props, node: node};
        }

        /**
        * Create Elements Recursively For all Children
        * @param {Array} children
        * @return {Array} Array of elements usable in Virtual DOM
        */
        this.recursiveChildren = function(children) {
          var recursiveChildrenArr = [];
          for(var i = 0; i < children.length; i++) {
            var child = children[i];
            recursiveChildrenArr.push(this.createElement(child.nodeName, this.recursiveChildren(child.childNodes), child.textContent, extractAttrs(child), child));
          }
          return recursiveChildrenArr;
        }

        /**
        * Creates Virtual DOM
        * @param {Node} node
        */
        this.createVirtualDOM = function(node) {
          var vdom = this.createElement(node.nodeName, this.recursiveChildren(node.childNodes), node.textContent, extractAttrs(node), node);
          this.dom = vdom;
        }

        /**
        * Turns Custom Components into their Corresponding Templates
        */
        this.componentsToHTML = function() {
          for(var component in this.components) {
            var componentsFound = document.getElementsByTagName(component);
            for(var i = 0; i < componentsFound.length; i++) {
              componentsFound[i].outerHTML = this.components[component].template;
            }
          }
        }

        /**
        * Sets Value in Data
        * @param {String} key
        * @param {String} val
        */
        this.set = function(key, val) {
          this.$data[key] = val;
          this.build(this.dom.children);
        }

        /**
        * Gets Value in Data
        * @param {String} key
        * @return {String} Value of key in data
        */
        this.get = function(key) {
          return this.$data[key];
        }

        /**
        * Makes an AJAX Request
        * @param {String} method
        * @param {String} url
        * @param {Object} params
        * @param {Function} cb
        */
        this.ajax = function(method, url, params, cb) {
          var xmlHttp = new XMLHttpRequest();
          method = method.toUpperCase();
          if(typeof params === "function") {
            cb = params;
          }
          var urlParams = "?";
          if(method === "POST") {
            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            for(var param in params) {
              urlParams += param + "=" + params[param] + "&";
            }
          }
          xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
            cb(JSON.parse(xmlHttp.responseText));
          }
          xmlHttp.open(method, url, true);
          xmlHttp.send(method === "POST" ? urlParams : null);
        }

        /**
        * Calls a method
        * @param {String} method
        */
        this.method = function(method) {
          _methods[method]();
        }

        // Directive Initialization
        this.directive = function(name, action) {
          directives["m-" + name] = action;
        }

        // Default Directives
        directives["m-if"] = function(el, val, vdom) {
          var evaluated = new Function("return " + val);
          if(!evaluated()) {
            el.textContent = "";
          } else {
            el.textContent = compileTemplate(vdom.val, self.$data);
          }
        }

        // Build the DOM with $data
        this.build = function(children) {
          for(var i = 0; i < children.length; i++) {
            var el = children[i];

            if(el.type === "#text") {
              el.node.textContent = compileTemplate(el.val, this.$data);
            } else if(el.props) {
              for(var prop in el.props) {
                var propVal = el.props[prop];
                var compiledProperty = compileTemplate(propVal, this.$data);
                var directive = directives[prop];
                if(directive) {
                  directive(el.node, compiledProperty, el);
                }

                el.node.setAttribute(prop, compiledProperty);
              }
            }

            this.build(el.children);
          }
        }

        // Initialize
        this.componentsToHTML();
        this.createVirtualDOM(this.$el);
        this.build(this.dom.children);
    }

    window.Moon = Moon;
    window.$ = function(el) {
      el = document.querySelectorAll(el);
      return el.length === 1 ? el[0] : el;
    }

})(window);
<|endoftext|>


<commit_before>/**
 * This is the first script called by the performance answer distribution page.
 */

require(['vendor/domReady!', 'load/init-page'], function(doc, page) {
    'use strict';

    require(['underscore', 'views/data-table-view', 'views/discrete-bar-view'],
            function (_, DataTableView, DiscreteBarView) {

                var courseModel = page.models.courseModel,
                    answerField = 'answer_value',
                    answerColumn = {key: answerField, title: gettext('Answer'), type:'hasNull'},
                    tableColumns = [
                        answerColumn,
                        {key: 'correct', title: gettext('Correct'), type: 'bool'},
                        {key: 'count', title: gettext('Submission Count'), type: 'number', className: 'text-right'}
                    ];

                // answers are stored either the numeric or string fields
                if (courseModel.get('answerType') === 'numeric') {
                    answerColumn.type = 'number';
                }

                // randomized problems have a random seeds field that differentiates rows
                if (courseModel.get('isRandom')) {
                    // only show the variant column for randomized problems
                    tableColumns.push({
                        key: 'variant', title: gettext('Variant'), type: 'number', className: 'text-right'
                    });
                }

                new DiscreteBarView({
                    el: '#performance-chart-view',
                    model: courseModel,
                    modelAttribute: 'answerDistributionLimited',
                    dataType: 'count',
                    truncateXTicks: true,
                    trends: [{
                        title: function(index) {
                            if (courseModel.get('answerDistributionLimited')[index].correct) {
                                return 'Correct';
                            } else {
                                return 'Incorrect';
                            }
                        },
                        color: function (bar, index) {
                            // green bars represent bars with the correct answer
                            if (courseModel.get('answerDistributionLimited')[index].correct) {
                                return '#4BB4FB';
                            } else {
                                return '#CA0061';
                            }
                        }
                    }],
                    x: { key: answerField },
                    y: { key: 'count' },
                    // Translators: <%=value%> will be replaced by a student response to a question asked in a course.
                    interactiveTooltipHeaderTemplate: _.template(gettext('Answer: <%=value%>'))
                });

                new DataTableView({
                    el: '[data-role=performance-table]',
                    model: courseModel,
                    modelAttribute: 'answerDistribution',
                    columns: tableColumns,
                    sorting: ['-count'],
                    replaceZero: '-'
                });

            });
});
<commit_msg>Add missing gettext<commit_after>/**
 * This is the first script called by the performance answer distribution page.
 */

require(['vendor/domReady!', 'load/init-page'], function(doc, page) {
    'use strict';

    require(['underscore', 'views/data-table-view', 'views/discrete-bar-view'],
            function (_, DataTableView, DiscreteBarView) {

                var courseModel = page.models.courseModel,
                    answerField = 'answer_value',
                    answerColumn = {key: answerField, title: gettext('Answer'), type:'hasNull'},
                    tableColumns = [
                        answerColumn,
                        {key: 'correct', title: gettext('Correct'), type: 'bool'},
                        {key: 'count', title: gettext('Submission Count'), type: 'number', className: 'text-right'}
                    ];

                // answers are stored either the numeric or string fields
                if (courseModel.get('answerType') === 'numeric') {
                    answerColumn.type = 'number';
                }

                // randomized problems have a random seeds field that differentiates rows
                if (courseModel.get('isRandom')) {
                    // only show the variant column for randomized problems
                    tableColumns.push({
                        key: 'variant', title: gettext('Variant'), type: 'number', className: 'text-right'
                    });
                }

                new DiscreteBarView({
                    el: '#performance-chart-view',
                    model: courseModel,
                    modelAttribute: 'answerDistributionLimited',
                    dataType: 'count',
                    truncateXTicks: true,
                    trends: [{
                        title: function(index) {
                            if (courseModel.get('answerDistributionLimited')[index].correct) {
                                return gettext('Correct');
                            } else {
                                return gettext('Incorrect');
                            }
                        },
                        color: function (bar, index) {
                            // green bars represent bars with the correct answer
                            if (courseModel.get('answerDistributionLimited')[index].correct) {
                                return '#4BB4FB';
                            } else {
                                return '#CA0061';
                            }
                        }
                    }],
                    x: { key: answerField },
                    y: { key: 'count' },
                    // Translators: <%=value%> will be replaced by a student response to a question asked in a course.
                    interactiveTooltipHeaderTemplate: _.template(gettext('Answer: <%=value%>'))
                });

                new DataTableView({
                    el: '[data-role=performance-table]',
                    model: courseModel,
                    modelAttribute: 'answerDistribution',
                    columns: tableColumns,
                    sorting: ['-count'],
                    replaceZero: '-'
                });

            });
});
<|endoftext|>


<commit_before>
/*
 * Copyright (c) Burak Arslan (burak.arslan-qx@arskom.com.tr).
 * 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 Arskom Consultancy Ltd. 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 ''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
 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

qx.Class.define("soap.WsdlCache", {extend: qx.core.Object
    ,properties: {
         _name   : {check: "String"}
        ,_client : {check: "soap.Client"}
        ,_params : {check: "soap.Parameters"}
        ,_simple : {check: "Boolean", init:false}
    }

    ,statics : {
        nsmap: new Object()
    }

    ,construct: function(node) {
        var ctx = this;
        var get_elts = qx.xml.Element.getElementsByTagNameNS;
        var _ns_wsdl = "http://schemas.xmlsoap.org/wsdl/";

        ctx.methods = new Object();
        ctx.messages = new Array();
        ctx.schema = new Object();
        ctx.__target_namespace = node.documentElement.getAttribute(
                                                             "targetNamespace");
        ctx.prefix_map = new Object();

        qx.log.Logger.debug("New service: " + ctx.__target_namespace);

        if (qx.core.Variant.isSet("qx.client", "mshtml")) {
            this.definitions = node.childNodes[1];
        }
        else {
            this.definitions = node.childNodes[0];
        }

        var port_type_node = get_elts(node, _ns_wsdl, 'portType')[0];
        var types_node = get_elts(node, _ns_wsdl, 'types')[0];

        this.__decode_methods(port_type_node);
        this.__decode_schemas(types_node);
    }

    ,members: {
         __cache: null
        ,__target_namespace : null
        ,methods : null
        ,messages : null
        ,schema : null
        ,definitions : null

        ,__decode_schemas : function(types_node) {
            var schema_node = null;
            var ctx = this;
            for (var i=0, l=types_node.childNodes.length; i<l; ++i) {
                schema_node = types_node.childNodes[i];
                var schema_tns = schema_node.getAttribute("targetNamespace");
                var schema_key = schema_tns;

                qx.log.Logger.debug("        new namespace: '" + schema_tns + "'");

                var schema = ctx.schema[schema_key];
                if (! schema) {
                    ctx.schema[schema_key] = new Object();

                    schema = ctx.schema[schema_key];
                    schema.simple = new Object();
                    schema.element = new Object();
                    schema.complex = new Object();
                }

                var cn = schema_node.childNodes;
                for (var j=0, k = cn.length; j<k; ++j) {
                    var tn;
                    if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                        tn = cn[j].baseName;
                    }
                    else {
                        tn = cn[j].localName;
                    }

                    var elt = this.__type_from_node(cn[j], schema_tns);
                    if (tn == "element") {
                        schema.element[elt.name] = elt
                    }
                    else if (tn == "import") {

                    }
                    else if (tn == "simpleType") {
                        this.__decode_simple_type(cn[j],elt);
                    }
                    else if (tn == "complexType") {
                        this.__decode_complex_type(cn[j],elt);
                    }
                }
            }
            // fill schema
            if (schema_node == null) {
                ctx.schema = null;
            }
        }
        ,__decode_methods : function(port_type_node) {
            var methods = this.methods;
            var cn = port_type_node.childNodes;
            for (var i=0, l=cn.length; i<l; ++i) {
                var method_name = cn[i].getAttribute("name");
                methods[method_name] = new Object();

                var method = methods[method_name];
                for (var j=0, k=cn[i].childNodes.length; j<k; ++j) {
                    var method_node = cn[i].childNodes[j];

                    var tn
                    if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                        tn = method_node.baseName;
                    }
                    else {
                        tn = method_node.localName;
                    }

                    method.input = new Object();
                    method.input.name = null;
                    method.input.message = null;

                    method.output = new Object();
                    method.output.name = null;
                    method.output.message = null;

                    if (tn == "input" || tn == "output") {
                        method[tn] = new Object();
                        method[tn].name = method_node.getAttribute("name");
                        method[tn].message = method_node.getAttribute("message");
                    }
                }
            }
        }

        ,__decode_sequence : function(node, elt) {
            var first_node = node.firstChild;
            if (! first_node) {
                return;
            }

            var child;
            var min_occurs = first_node.getAttribute("minOccurs");
            var max_occurs = first_node.getAttribute("maxOccurs");
            if (first_node.nextSibling == null && min_occurs != null
                                               && max_occurs != null) { // it's an array
                elt.is_array = true;
                elt.min_occurs = min_occurs;
                elt.max_occurs = max_occurs;

                child = this.__type_from_node(first_node);

                elt.children = new Object();
                elt.children[child.name] = child;
                elt.children[0] = child;
            }
            else {
                var order=0;
                elt.children = new Object();

                for (var n=first_node; n!=null; n=n.nextSibling) {
                    child = this.__type_from_node(n);

                    elt.children[child.name] = child;
                    elt.children[order] = child;

                    ++order;
                }
            }
        }

        ,__decode_complex_type : function(node, elt) {
            var first_node = node.firstChild;
            if (! first_node) {
                return;
            }

            var tn;
            if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                tn = first_node.baseName;
            }
            else {
                tn = first_node.localName;
            }

            if (tn == 'sequence') {
                this.__decode_sequence(first_node, elt);
            }
            if (tn == 'complexContent') {
                this.__decode_complex_content(first_node, elt);
            }

            this.schema[elt.ns].complex[elt.name] = elt
        }

        ,__decode_complex_content : function(node, elt) {
            var first_node = node.firstChild;
            if (! first_node) {
                return;
            }

            var tn;
            if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                tn = first_node.baseName;
            }
            else {
                tn = first_node.localName;
            }

            if (tn == 'extension') {
                var type_qname = first_node.getAttribute("base");
                var type_local = type_qname.split(":")[1];
                var type_ns = this.type_qname_to_ns(node, type_qname);

                elt.base = type_local;
                elt.base_ns = type_ns;

                if (first_node.firstChild) {
                    this.__decode_sequence(first_node.firstChild, elt);
                }
            }
        }

        ,__decode_simple_type : function(node, elt) {
            this.schema[elt.ns].simple[elt.name] = elt

            for (var n = node.firstChild; n; n=n.nextSibling) {
                var nn;
                if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                    nn = n.baseName;
                }
                else {
                    nn = n.localName;
                }

                if (nn == 'restriction') {
                    elt.base = n.getAttribute("base");
                    elt.base_ns = this.type_qname_to_ns(n,elt.base);
                    elt.restrictions = new Object();
                    for (var r = n.firstChild; r != null; r=r.nextSibling) {
                        // TODO: fill restrictions
                    }
                }
            }
        }

        ,__type_from_node: function(node, ns) {
            var elt = new Object();

            elt.type = node.getAttribute("type");
            elt.name = node.getAttribute("name");
            if (ns) {
                elt.ns = ns;
            }

            if (elt.type) {
                elt.ns = this.type_qname_to_ns(node, elt.type);
            }
            else {
                elt.ns = node.parentNode.getAttribute("targetNamespace")
            }

            elt.base = null;

            return elt;
        }

        ,type_qname_to_ns: function(node, type_qname) {
            if (! type_qname) {
                return null;
            }
            var type_defn = type_qname.split(":");
            var retval;

            if (type_defn.length > 0) {
                retval = this.prefix_map[type_defn[0]];

                if (! retval) {
                    var tnode = node;
                    while (! retval) {
                        if (! tnode.getAttribute) {
                            return retval;
                        }

                        retval = tnode.getAttribute("xmlns:" + type_defn[0]);
                        tnode = tnode.parentNode;
                    }

                    if (retval) {
                        this.prefix_map[type_defn[0]] = retval;
                        soap.WsdlCache.nsmap[retval] = type_defn[0];
                    }
                }
            }

            return retval;
        }

        ,get_target_namespace: function() {
            return this.__target_namespace;
        }

        ,__get_simple_base : function(child) {
            var retval;
            var type_l = child.type.split(":")[1];
            var simple_type_ns = this.schema[child.ns]

            if (simple_type_ns) {
                var simple_type = simple_type_ns.simple[type_l];

                if (simple_type) {
                    while (simple_type.base != null) {
                        var base_ns = this.schema[simple_type.base_ns]
                        if (base_ns) {
                            var base_l = simple_type.base.split(":")[1];
                            simple_type = base_ns.simple[base_l];

                            qx.core.Assert.assertNotUndefined(simple_type,
                                    "Simple Type " +
                                    "'{" + simple_type.base_ns + "}'" +
                                    " '" + simple_type.base + "' " +
                                    "does not exist");
                        }
                        else {
                            base_ns = null;
                            break;
                        }
                    }

                    if (base_ns) {
                        retval = simple_type.type.split(":")[1];
                    }
                    else {
                        retval = simple_type.base.split(":")[1];
                    }

                    retval = soap.Client.TYPE_MAP[retval];
                }
            }

            return retval;
        }

        ,get_type_defn: function(object_namespace, object_name) {
            var retval;

            var schema = this.schema[object_namespace];
            if (schema) {
                retval = schema.complex[object_name];
            }

            return retval;
        }

        ,has_object: function(object_namespace, object_name) {
            if (this.get_type_defn(object_namespace, object_name)) {
                return true;
            }
            return false;
        }

        ,get_class_map: function(object_namespace, object_name) {
            var ctx=this;
            var retval;

            if (! object_namespace) {
                object_namespace = ctx.__target_namespace;
            }

            if (! object_name) {
                throw new Error("object_name must be defined!");
            }

            var type = this.get_type_defn(object_namespace, object_name)
            if (! type) {
                qx.log.Logger.debug("object not found: {"+object_namespace + "}"
                                                            + object_name + "");

                return retval;
            }

            qx.log.Logger.debug("creating object: {" + object_namespace + "}"
                                                            + object_name + "");

            var children = type.children;
            var extend = qx.core.Object;
            if (type.base) {
                extend = this.get_class(type.base_ns, type.base);
                qx.log.Logger.debug("base: " + type.base_ns + "." + type.base);
            }

            retval = {
                extend: extend,
                properties: {},
                statics: {
                    TYPE_DEFINITION: type
                }
            };

            // get the props
            var props = retval.properties;
            for (var k in children) {
                var child = children[k];
                var prop_name = "_" + child.name;
                if ( (! (prop_name in props))
                                && children.hasOwnProperty(k)
                                && isNaN(k) ) {

                    var type_l = child.type.split(":")[1];

                    var prop_type;
                    if (child.is_array) {
                        prop_type = "Array";
                    }
                    else {
                        prop_type = soap.Client.TYPE_MAP[type_l];
                    }

                    if (! prop_type) {
                        prop_type = this.__get_simple_base(child);
                    }

                    if (! prop_type) {
                        prop_type = "Object";
                    }

                    var prop_def = {"check": prop_type, init: null,
                                                             nullable: true}

                    qx.log.Logger.debug(object_name + "." + prop_name
                                             + " is a '" + prop_type + "'");

                    props[prop_name] = prop_def;
                }
            }

            return retval;
        }

        ,get_class: function(object_namespace, object_name) {
            var ctx=this;

            if (! object_name) {
                throw new Error("object_name must be defined!");
            }

            var class_name = object_namespace + "." + object_name;
            var clazz = qx.Class.getByName(class_name);

            if (! clazz) {
                var class_map = this.get_class_map(object_namespace, object_name);
                if (class_map) {
                    clazz = qx.Class.define(class_name, class_map);
                }
            }

            return clazz;
        }

        ,get_object: function(object_namespace, object_name) {
            var clazz = this.get_class(object_namespace, object_name);
            var retval;

            if (clazz) {
                retval = new clazz();
            }

            return retval;
        }

        ,get_table: function(method_name) {
            // methodun dondurdugu veri tipini alır.
            var method_input = this.schema.complex[method_name];
            if (! method_input) {
                throw new Error("Method named '" + method_name +
                                                  "' is not exposed via wsdl.");
            }

            var class_map = {extend: arskom.ui.Table};
        }

        ,get_form: function(object_namespace, object_name) {
            var class_map = this.get_class_map(object_namespace, object_name);
            var props = class_map.properties;
            var form = new qx.ui.form.Form();
            var pd = this.self(arguments).PRIMITIVE_DEFAULTS;

            for (var key in props) {
                if (props.hasOwnProperty(key)) {
                    var name = key.slice(1);
                    var type = props[key].check;

                    if (type in pd) {
                        var wgt = new pd[type]();
                        form.add(wgt, name);
                    }
                }
            }

            return form;
        }

        ,get_form_widget: function(object_namespace, object_name) {
            var form = this.get_form(object_namespace, object_name);
            var retval = new qx.ui.form.renderer.Single(form);
            return retval;
        }
    }
});
<commit_msg>cleaned some debug statements.<commit_after>
/*
 * Copyright (c) Burak Arslan (burak.arslan-qx@arskom.com.tr).
 * 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 Arskom Consultancy Ltd. 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 ''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
 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

qx.Class.define("soap.WsdlCache", {extend: qx.core.Object
    ,properties: {
         _name   : {check: "String"}
        ,_client : {check: "soap.Client"}
        ,_params : {check: "soap.Parameters"}
        ,_simple : {check: "Boolean", init:false}
    }

    ,statics : {
        nsmap: new Object()
    }

    ,construct: function(node) {
        var ctx = this;
        var get_elts = qx.xml.Element.getElementsByTagNameNS;
        var _ns_wsdl = "http://schemas.xmlsoap.org/wsdl/";

        ctx.methods = new Object();
        ctx.messages = new Array();
        ctx.schema = new Object();
        ctx.__target_namespace = node.documentElement.getAttribute(
                                                             "targetNamespace");
        ctx.prefix_map = new Object();

        qx.log.Logger.debug("New service: " + ctx.__target_namespace);

        if (qx.core.Variant.isSet("qx.client", "mshtml")) {
            this.definitions = node.childNodes[1];
        }
        else {
            this.definitions = node.childNodes[0];
        }

        var port_type_node = get_elts(node, _ns_wsdl, 'portType')[0];
        var types_node = get_elts(node, _ns_wsdl, 'types')[0];

        this.__decode_methods(port_type_node);
        this.__decode_schemas(types_node);
    }

    ,members: {
         __cache: null
        ,__target_namespace : null
        ,methods : null
        ,messages : null
        ,schema : null
        ,definitions : null

        ,__decode_schemas : function(types_node) {
            var schema_node = null;
            var ctx = this;
            for (var i=0, l=types_node.childNodes.length; i<l; ++i) {
                schema_node = types_node.childNodes[i];
                var schema_tns = schema_node.getAttribute("targetNamespace");
                var schema_key = schema_tns;

                qx.log.Logger.debug("        new namespace: '" + schema_tns + "'");

                var schema = ctx.schema[schema_key];
                if (! schema) {
                    ctx.schema[schema_key] = new Object();

                    schema = ctx.schema[schema_key];
                    schema.simple = new Object();
                    schema.element = new Object();
                    schema.complex = new Object();
                }

                var cn = schema_node.childNodes;
                for (var j=0, k = cn.length; j<k; ++j) {
                    var tn;
                    if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                        tn = cn[j].baseName;
                    }
                    else {
                        tn = cn[j].localName;
                    }

                    var elt = this.__type_from_node(cn[j], schema_tns);
                    if (tn == "element") {
                        schema.element[elt.name] = elt
                    }
                    else if (tn == "import") {

                    }
                    else if (tn == "simpleType") {
                        this.__decode_simple_type(cn[j],elt);
                    }
                    else if (tn == "complexType") {
                        this.__decode_complex_type(cn[j],elt);
                    }
                }
            }
            // fill schema
            if (schema_node == null) {
                ctx.schema = null;
            }
        }
        ,__decode_methods : function(port_type_node) {
            var methods = this.methods;
            var cn = port_type_node.childNodes;
            for (var i=0, l=cn.length; i<l; ++i) {
                var method_name = cn[i].getAttribute("name");
                methods[method_name] = new Object();

                var method = methods[method_name];
                for (var j=0, k=cn[i].childNodes.length; j<k; ++j) {
                    var method_node = cn[i].childNodes[j];

                    var tn
                    if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                        tn = method_node.baseName;
                    }
                    else {
                        tn = method_node.localName;
                    }

                    method.input = new Object();
                    method.input.name = null;
                    method.input.message = null;

                    method.output = new Object();
                    method.output.name = null;
                    method.output.message = null;

                    if (tn == "input" || tn == "output") {
                        method[tn] = new Object();
                        method[tn].name = method_node.getAttribute("name");
                        method[tn].message = method_node.getAttribute("message");
                    }
                }
            }
        }

        ,__decode_sequence : function(node, elt) {
            var first_node = node.firstChild;
            if (! first_node) {
                return;
            }

            var child;
            var min_occurs = first_node.getAttribute("minOccurs");
            var max_occurs = first_node.getAttribute("maxOccurs");
            if (first_node.nextSibling == null && min_occurs != null
                                               && max_occurs != null) { // it's an array
                elt.is_array = true;
                elt.min_occurs = min_occurs;
                elt.max_occurs = max_occurs;

                child = this.__type_from_node(first_node);

                elt.children = new Object();
                elt.children[child.name] = child;
                elt.children[0] = child;
            }
            else {
                var order=0;
                elt.children = new Object();

                for (var n=first_node; n!=null; n=n.nextSibling) {
                    child = this.__type_from_node(n);

                    elt.children[child.name] = child;
                    elt.children[order] = child;

                    ++order;
                }
            }
        }

        ,__decode_complex_type : function(node, elt) {
            var first_node = node.firstChild;
            if (! first_node) {
                return;
            }

            var tn;
            if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                tn = first_node.baseName;
            }
            else {
                tn = first_node.localName;
            }

            if (tn == 'sequence') {
                this.__decode_sequence(first_node, elt);
            }
            if (tn == 'complexContent') {
                this.__decode_complex_content(first_node, elt);
            }

            this.schema[elt.ns].complex[elt.name] = elt
        }

        ,__decode_complex_content : function(node, elt) {
            var first_node = node.firstChild;
            if (! first_node) {
                return;
            }

            var tn;
            if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                tn = first_node.baseName;
            }
            else {
                tn = first_node.localName;
            }

            if (tn == 'extension') {
                var type_qname = first_node.getAttribute("base");
                var type_local = type_qname.split(":")[1];
                var type_ns = this.type_qname_to_ns(node, type_qname);

                elt.base = type_local;
                elt.base_ns = type_ns;

                if (first_node.firstChild) {
                    this.__decode_sequence(first_node.firstChild, elt);
                }
            }
        }

        ,__decode_simple_type : function(node, elt) {
            this.schema[elt.ns].simple[elt.name] = elt

            for (var n = node.firstChild; n; n=n.nextSibling) {
                var nn;
                if (qx.core.Variant.isSet("qx.client", "mshtml")) {
                    nn = n.baseName;
                }
                else {
                    nn = n.localName;
                }

                if (nn == 'restriction') {
                    elt.base = n.getAttribute("base");
                    elt.base_ns = this.type_qname_to_ns(n,elt.base);
                    elt.restrictions = new Object();
                    for (var r = n.firstChild; r != null; r=r.nextSibling) {
                        // TODO: fill restrictions
                    }
                }
            }
        }

        ,__type_from_node: function(node, ns) {
            var elt = new Object();

            elt.type = node.getAttribute("type");
            elt.name = node.getAttribute("name");
            if (ns) {
                elt.ns = ns;
            }

            if (elt.type) {
                elt.ns = this.type_qname_to_ns(node, elt.type);
            }
            else {
                elt.ns = node.parentNode.getAttribute("targetNamespace")
            }

            elt.base = null;

            return elt;
        }

        ,type_qname_to_ns: function(node, type_qname) {
            if (! type_qname) {
                return null;
            }
            var type_defn = type_qname.split(":");
            var retval;

            if (type_defn.length > 0) {
                retval = this.prefix_map[type_defn[0]];

                if (! retval) {
                    var tnode = node;
                    while (! retval) {
                        if (! tnode.getAttribute) {
                            return retval;
                        }

                        retval = tnode.getAttribute("xmlns:" + type_defn[0]);
                        tnode = tnode.parentNode;
                    }

                    if (retval) {
                        this.prefix_map[type_defn[0]] = retval;
                        soap.WsdlCache.nsmap[retval] = type_defn[0];
                    }
                }
            }

            return retval;
        }

        ,get_target_namespace: function() {
            return this.__target_namespace;
        }

        ,__get_simple_base : function(child) {
            var retval;
            var type_l = child.type.split(":")[1];
            var simple_type_ns = this.schema[child.ns]

            if (simple_type_ns) {
                var simple_type = simple_type_ns.simple[type_l];

                if (simple_type) {
                    while (simple_type.base != null) {
                        var base_ns = this.schema[simple_type.base_ns]
                        if (base_ns) {
                            var base_l = simple_type.base.split(":")[1];
                            simple_type = base_ns.simple[base_l];

                            qx.core.Assert.assertNotUndefined(simple_type,
                                    "Simple Type " +
                                    "'{" + simple_type.base_ns + "}'" +
                                    " '" + simple_type.base + "' " +
                                    "does not exist");
                        }
                        else {
                            base_ns = null;
                            break;
                        }
                    }

                    if (base_ns) {
                        retval = simple_type.type.split(":")[1];
                    }
                    else {
                        retval = simple_type.base.split(":")[1];
                    }

                    retval = soap.Client.TYPE_MAP[retval];
                }
            }

            return retval;
        }

        ,get_type_defn: function(object_namespace, object_name) {
            var retval;

            var schema = this.schema[object_namespace];
            if (schema) {
                retval = schema.complex[object_name];
            }

            return retval;
        }

        ,has_object: function(object_namespace, object_name) {
            if (this.get_type_defn(object_namespace, object_name)) {
                return true;
            }
            return false;
        }

        ,get_class_map: function(object_namespace, object_name) {
            var ctx=this;
            var retval;

            if (! object_namespace) {
                object_namespace = ctx.__target_namespace;
            }

            if (! object_name) {
                throw new Error("object_name must be defined!");
            }

            var type = this.get_type_defn(object_namespace, object_name)
            if (! type) {
                qx.log.Logger.error("object not found: {"+object_namespace + "}"
                                                            + object_name + "");

                return retval;
            }

            var children = type.children;
            var extend = qx.core.Object;
            if (type.base) {
                extend = this.get_class(type.base_ns, type.base);
            }

            retval = {
                extend: extend,
                properties: {},
                statics: {
                    TYPE_DEFINITION: type
                }
            };

            // get the props
            var props = retval.properties;
            for (var k in children) {
                var child = children[k];
                var prop_name = "_" + child.name;
                if ( (! (prop_name in props))
                                && children.hasOwnProperty(k)
                                && isNaN(k) ) {

                    var type_l = child.type.split(":")[1];

                    var prop_type;
                    if (child.is_array) {
                        prop_type = "Array";
                    }
                    else {
                        prop_type = soap.Client.TYPE_MAP[type_l];
                    }

                    if (! prop_type) {
                        prop_type = this.__get_simple_base(child);
                    }

                    if (! prop_type) {
                        prop_type = "Object";
                    }

                    var prop_def = {"check": prop_type, init: null,
                                                             nullable: true}

                    props[prop_name] = prop_def;
                }
            }

            return retval;
        }

        ,get_class: function(object_namespace, object_name) {
            var ctx=this;

            if (! object_name) {
                throw new Error("object_name must be defined!");
            }

            var class_name = object_namespace + "." + object_name;
            var clazz = qx.Class.getByName(class_name);

            if (! clazz) {
                var class_map = this.get_class_map(object_namespace, object_name);
                if (class_map) {
                    clazz = qx.Class.define(class_name, class_map);
                }
            }

            return clazz;
        }

        ,get_object: function(object_namespace, object_name) {
            var clazz = this.get_class(object_namespace, object_name);
            var retval;

            if (clazz) {
                retval = new clazz();
            }

            return retval;
        }

        ,get_table: function(method_name) {
            // methodun dondurdugu veri tipini alır.
            var method_input = this.schema.complex[method_name];
            if (! method_input) {
                throw new Error("Method named '" + method_name +
                                                  "' is not exposed via wsdl.");
            }

            var class_map = {extend: arskom.ui.Table};
        }

        ,get_form: function(object_namespace, object_name) {
            var class_map = this.get_class_map(object_namespace, object_name);
            var props = class_map.properties;
            var form = new qx.ui.form.Form();
            var pd = this.self(arguments).PRIMITIVE_DEFAULTS;

            for (var key in props) {
                if (props.hasOwnProperty(key)) {
                    var name = key.slice(1);
                    var type = props[key].check;

                    if (type in pd) {
                        var wgt = new pd[type]();
                        form.add(wgt, name);
                    }
                }
            }

            return form;
        }

        ,get_form_widget: function(object_namespace, object_name) {
            var form = this.get_form(object_namespace, object_name);
            var retval = new qx.ui.form.renderer.Single(form);
            return retval;
        }
    }
});
<|endoftext|>


<commit_before>import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useHistory } from 'react-router-dom';
import { css } from '@emotion/core';
import { Map, TileLayer, ZoomControl } from 'react-leaflet';
import 'focus-visible';

import config from '../../config.js';
import LocateMapControl from './LocateMapControl';
import ToiletMarkerIcon from './ToiletMarkerIcon';
import AccessibilityIntersection from './AccessibilityIntersection';
import AccessibilityList from './AccessibilityList';

import Box from '../Box';
import Marker from './Marker';
import VisuallyHidden from '../VisuallyHidden';
import { Media } from '../Media';

import crosshair from '../../images/crosshair.svg';

import 'leaflet/dist/leaflet.css';

const KEY_ENTER = 13;

const LooMap = ({
  center,
  zoom,
  minZoom,
  maxZoom,
  onViewportChanged,
  loos,
  staticMap,
  controlsOffset,
  showCrosshair,
  withAccessibilityOverlays,
}) => {
  const mapRef = React.useRef();
  const [intersectingToilets, setIntersectingToilets] = React.useState([]);
  const [
    renderAccessibilityOverlays,
    setRenderAccessibilityOverlays,
  ] = React.useState(false);
  const [announcement, setAnnouncement] = React.useState(null);

  useEffect(() => {
    const { leafletElement } = mapRef.current;
    const map = leafletElement.getContainer();

    // when focused on the map container, Leaflet allows the user to pan the map by using the arrow keys
    // without the application role screen reader software overrides these controls
    //
    // this also avoids the entire main region being announced
    map.setAttribute('role', 'application');
    map.setAttribute('aria-label', 'Map');

    // ensure all map tiles are loaded on Safari
    // https://github.com/neontribe/gbptm/issues/776
    setTimeout(() => {
      leafletElement.invalidateSize();
    }, 400);
  }, []);

  const handleViewportChanged = () => {
    const map = mapRef.current.leafletElement;
    const center = map.getCenter();
    const zoom = map.getZoom();

    const bounds = map.getBounds();
    const radius = parseInt(bounds.getNorthEast().distanceTo(center));

    onViewportChanged({
      center,
      zoom,
      radius,
    });
  };

  const { push } = useHistory();

  const memoizedMarkers = React.useMemo(
    () =>
      loos.map((toilet) => (
        <Marker
          key={toilet.id}
          position={toilet.location}
          zIndexOffset={toilet.isHighlighted ? 1000 : 0}
          icon={
            new ToiletMarkerIcon({
              isHighlighted: toilet.isHighlighted,
              toiletId: toilet.id,
            })
          }
          label={toilet.name || 'Unnamed toilet'}
          onClick={() => {
            if (!staticMap) {
              push(`/loos/${toilet.id}`);
            }
          }}
          onKeyDown={(event) => {
            if (!staticMap && event.originalEvent.keyCode === KEY_ENTER) {
              push(`/loos/${toilet.id}`);
            }
          }}
          keyboard={false}
        />
      )),
    [loos, staticMap, push]
  );

  const keyboardSelectionHandler = React.useCallback(
    (selectionIndex) => {
      const toilet = intersectingToilets[selectionIndex];

      if (!toilet) {
        return;
      }

      setAnnouncement(`${toilet.name || 'Unnamed toilet'} selected`);

      push(`/loos/${toilet.id}`);
    },
    [intersectingToilets, push]
  );

  React.useEffect(() => {
    if (withAccessibilityOverlays && mapRef.current) {
      const map = mapRef.current.leafletElement.getContainer();

      const callback = function (mutationsList) {
        for (let mutation of mutationsList) {
          const focusVisible = mutation.target.dataset.focusVisibleAdded === '';

          if (focusVisible !== renderAccessibilityOverlays) {
            setRenderAccessibilityOverlays(focusVisible);
          }
        }
      };

      const observer = new MutationObserver(callback);

      // only render accessibility overlays when [data="focus-visible-added"] is applied
      //
      // we conditionally render instead of toggling CSS display since we want to avoid AccessibilityList being announced
      // before the map is keyboard focused
      observer.observe(map, { attributes: true });

      return () => {
        observer.disconnect();
      };
    }
  }, [withAccessibilityOverlays, mapRef, renderAccessibilityOverlays]);

  return (
    <Box
      position="relative"
      height="100%"
      width="100%"
      css={
        showCrosshair
          ? css`
              &:after {
                content: url(${crosshair});
                position: absolute;
                top: 50%;
                left: 50%;
                display: block;
                height: 53px;
                width: 52px;
                transform: translate(-50%, -50%);
              }
            `
          : undefined
      }
    >
      <Map
        ref={mapRef}
        center={center}
        zoom={zoom}
        minZoom={minZoom}
        maxZoom={maxZoom}
        onViewportChanged={handleViewportChanged}
        dragging={!staticMap}
        scrollWheelZoom={!staticMap}
        zoomControl={false}
        tap={false}
        css={(theme) => css`
          height: 100%;
          width: 100%;
          position: relative;
          z-index: 0;

          .leaflet-bottom {
            bottom: ${controlsOffset}px;
          }

          .leaflet-bar {
            border: none;
            box-shadow: none;
          }

          a.leaflet-bar-part,
          a.leaflet-control-zoom-in,
          a.leaflet-control-zoom-out {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 40px;
            height: 40px;
            color: ${theme.colors.primary};
            border: 1px solid ${theme.colors.primary};
            border-radius: 20px;

            &:not(:first-of-type) {
              margin-top: 10px;
            }

            &:first-of-type,
            &:last-of-type {
              border-radius: 20px;
            }
          }

          &[data-focus-visible-added] {
            border: 2px solid ${theme.colors.tertiary};
          }

          .leaflet-control [data-focus-visible-added] {
            outline: 2px solid ${theme.colors.tertiary} !important;
            outline-offset: 3px;
          }

          &[data-focus-visible-added] {
            outline-offset: 0;
          }
        `}
      >
        <TileLayer
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          minZoom={minZoom}
          maxZoom={maxZoom}
        />

        {memoizedMarkers}

        <Media greaterThan="md">
          <ZoomControl position="bottomright" />
        </Media>

        <LocateMapControl position="bottomright" />

        {renderAccessibilityOverlays && (
          <>
            <AccessibilityIntersection
              className="accessibility-box"
              toilets={loos}
              bounds={mapRef.current.leafletElement.getBounds().pad(-0.4)}
              onIntersection={setIntersectingToilets}
              onSelection={keyboardSelectionHandler}
              center={center}
            />

            <AccessibilityList
              toilets={intersectingToilets.map((toilet) => toilet.name)}
            />

            <VisuallyHidden>
              <div
                role="status"
                aria-atomic="true"
                aria-live="polite"
                aria-relevant="additions text"
                children={announcement}
              />
            </VisuallyHidden>
          </>
        )}
      </Map>
    </Box>
  );
};

LooMap.propTypes = {
  loos: PropTypes.array,
  center: PropTypes.shape({
    lat: PropTypes.number,
    lng: PropTypes.number,
  }).isRequired,
  zoom: PropTypes.number,
  minZoom: PropTypes.number,
  maxZoom: PropTypes.number,
  staticMap: PropTypes.bool,
  onViewportChanged: PropTypes.func,
  controlsOffset: PropTypes.number,
  showCrosshair: PropTypes.bool,
  withAccessibilityOverlays: PropTypes.bool,
};

LooMap.defaultProps = {
  loos: [],
  zoom: config.initialZoom,
  minZoom: config.minZoom,
  maxZoom: config.maxZoom,
  staticMap: false,
  onViewportChanged: Function.prototype,
  controlsOffset: 0,
  withAccessibilityOverlays: true,
};

export default LooMap;
<commit_msg>fix: avoid invalidateSize error<commit_after>import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { useHistory } from 'react-router-dom';
import { css } from '@emotion/core';
import { Map, TileLayer, ZoomControl } from 'react-leaflet';
import 'focus-visible';

import config from '../../config.js';
import LocateMapControl from './LocateMapControl';
import ToiletMarkerIcon from './ToiletMarkerIcon';
import AccessibilityIntersection from './AccessibilityIntersection';
import AccessibilityList from './AccessibilityList';

import Box from '../Box';
import Marker from './Marker';
import VisuallyHidden from '../VisuallyHidden';
import { Media } from '../Media';

import crosshair from '../../images/crosshair.svg';

import 'leaflet/dist/leaflet.css';

const KEY_ENTER = 13;

const LooMap = ({
  center,
  zoom,
  minZoom,
  maxZoom,
  onViewportChanged,
  loos,
  staticMap,
  controlsOffset,
  showCrosshair,
  withAccessibilityOverlays,
}) => {
  const mapRef = React.useRef();
  const [intersectingToilets, setIntersectingToilets] = React.useState([]);
  const [
    renderAccessibilityOverlays,
    setRenderAccessibilityOverlays,
  ] = React.useState(false);
  const [announcement, setAnnouncement] = React.useState(null);

  useEffect(() => {
    const { leafletElement } = mapRef.current;
    const map = leafletElement.getContainer();

    // when focused on the map container, Leaflet allows the user to pan the map by using the arrow keys
    // without the application role screen reader software overrides these controls
    //
    // this also avoids the entire main region being announced
    map.setAttribute('role', 'application');
    map.setAttribute('aria-label', 'Map');

    // ensure all map tiles are loaded on Safari
    // https://github.com/neontribe/gbptm/issues/776
    setTimeout(() => {
      leafletElement.invalidateSize({
        pan: false,
      });
    }, 400);
  }, []);

  const handleViewportChanged = () => {
    const map = mapRef.current.leafletElement;
    const center = map.getCenter();
    const zoom = map.getZoom();

    const bounds = map.getBounds();
    const radius = parseInt(bounds.getNorthEast().distanceTo(center));

    onViewportChanged({
      center,
      zoom,
      radius,
    });
  };

  const { push } = useHistory();

  const memoizedMarkers = React.useMemo(
    () =>
      loos.map((toilet) => (
        <Marker
          key={toilet.id}
          position={toilet.location}
          zIndexOffset={toilet.isHighlighted ? 1000 : 0}
          icon={
            new ToiletMarkerIcon({
              isHighlighted: toilet.isHighlighted,
              toiletId: toilet.id,
            })
          }
          label={toilet.name || 'Unnamed toilet'}
          onClick={() => {
            if (!staticMap) {
              push(`/loos/${toilet.id}`);
            }
          }}
          onKeyDown={(event) => {
            if (!staticMap && event.originalEvent.keyCode === KEY_ENTER) {
              push(`/loos/${toilet.id}`);
            }
          }}
          keyboard={false}
        />
      )),
    [loos, staticMap, push]
  );

  const keyboardSelectionHandler = React.useCallback(
    (selectionIndex) => {
      const toilet = intersectingToilets[selectionIndex];

      if (!toilet) {
        return;
      }

      setAnnouncement(`${toilet.name || 'Unnamed toilet'} selected`);

      push(`/loos/${toilet.id}`);
    },
    [intersectingToilets, push]
  );

  React.useEffect(() => {
    if (withAccessibilityOverlays && mapRef.current) {
      const map = mapRef.current.leafletElement.getContainer();

      const callback = function (mutationsList) {
        for (let mutation of mutationsList) {
          const focusVisible = mutation.target.dataset.focusVisibleAdded === '';

          if (focusVisible !== renderAccessibilityOverlays) {
            setRenderAccessibilityOverlays(focusVisible);
          }
        }
      };

      const observer = new MutationObserver(callback);

      // only render accessibility overlays when [data="focus-visible-added"] is applied
      //
      // we conditionally render instead of toggling CSS display since we want to avoid AccessibilityList being announced
      // before the map is keyboard focused
      observer.observe(map, { attributes: true });

      return () => {
        observer.disconnect();
      };
    }
  }, [withAccessibilityOverlays, mapRef, renderAccessibilityOverlays]);

  return (
    <Box
      position="relative"
      height="100%"
      width="100%"
      css={
        showCrosshair
          ? css`
              &:after {
                content: url(${crosshair});
                position: absolute;
                top: 50%;
                left: 50%;
                display: block;
                height: 53px;
                width: 52px;
                transform: translate(-50%, -50%);
              }
            `
          : undefined
      }
    >
      <Map
        ref={mapRef}
        center={center}
        zoom={zoom}
        minZoom={minZoom}
        maxZoom={maxZoom}
        onViewportChanged={handleViewportChanged}
        dragging={!staticMap}
        scrollWheelZoom={!staticMap}
        zoomControl={false}
        tap={false}
        css={(theme) => css`
          height: 100%;
          width: 100%;
          position: relative;
          z-index: 0;

          .leaflet-bottom {
            bottom: ${controlsOffset}px;
          }

          .leaflet-bar {
            border: none;
            box-shadow: none;
          }

          a.leaflet-bar-part,
          a.leaflet-control-zoom-in,
          a.leaflet-control-zoom-out {
            display: flex;
            align-items: center;
            justify-content: center;
            width: 40px;
            height: 40px;
            color: ${theme.colors.primary};
            border: 1px solid ${theme.colors.primary};
            border-radius: 20px;

            &:not(:first-of-type) {
              margin-top: 10px;
            }

            &:first-of-type,
            &:last-of-type {
              border-radius: 20px;
            }
          }

          &[data-focus-visible-added] {
            border: 2px solid ${theme.colors.tertiary};
          }

          .leaflet-control [data-focus-visible-added] {
            outline: 2px solid ${theme.colors.tertiary} !important;
            outline-offset: 3px;
          }

          &[data-focus-visible-added] {
            outline-offset: 0;
          }
        `}
      >
        <TileLayer
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
          minZoom={minZoom}
          maxZoom={maxZoom}
        />

        {memoizedMarkers}

        <Media greaterThan="md">
          <ZoomControl position="bottomright" />
        </Media>

        <LocateMapControl position="bottomright" />

        {renderAccessibilityOverlays && (
          <>
            <AccessibilityIntersection
              className="accessibility-box"
              toilets={loos}
              bounds={mapRef.current.leafletElement.getBounds().pad(-0.4)}
              onIntersection={setIntersectingToilets}
              onSelection={keyboardSelectionHandler}
              center={center}
            />

            <AccessibilityList
              toilets={intersectingToilets.map((toilet) => toilet.name)}
            />

            <VisuallyHidden>
              <div
                role="status"
                aria-atomic="true"
                aria-live="polite"
                aria-relevant="additions text"
                children={announcement}
              />
            </VisuallyHidden>
          </>
        )}
      </Map>
    </Box>
  );
};

LooMap.propTypes = {
  loos: PropTypes.array,
  center: PropTypes.shape({
    lat: PropTypes.number,
    lng: PropTypes.number,
  }).isRequired,
  zoom: PropTypes.number,
  minZoom: PropTypes.number,
  maxZoom: PropTypes.number,
  staticMap: PropTypes.bool,
  onViewportChanged: PropTypes.func,
  controlsOffset: PropTypes.number,
  showCrosshair: PropTypes.bool,
  withAccessibilityOverlays: PropTypes.bool,
};

LooMap.defaultProps = {
  loos: [],
  zoom: config.initialZoom,
  minZoom: config.minZoom,
  maxZoom: config.maxZoom,
  staticMap: false,
  onViewportChanged: Function.prototype,
  controlsOffset: 0,
  withAccessibilityOverlays: true,
};

export default LooMap;
<|endoftext|>


<commit_before>var card_width = 300;
var card_height = 186;
var half_card_width = card_width / 2;
var half_card_height = card_height / 2;

var next_outgoing_i = 0; /* the index of the next node that's outgoing */
var next_incoming_i = 0;

/* Which card is currently displayed in the middle of the screen? */
var current_card = null;

/* Height of rendered graph */
var graph_height = null;

var nodes = [];
var cards = [];
var relations = []; // relations are between nodes
var links = []; // links are between cards

var node0 = {
    "summary": "Why a max length of 140 characters? Well, it sure as hell works for Twitter. Seems like just enough to pack some good info into an argument.",
    "outgoing": [],
    "incoming": [node2],
}

var node1 = {
    "summary": "Taxation is theft.",
    "outgoing": [],
    "incoming": [node2],
}

var node2 = {
    "summary": "You pay taxes in exchange for voluntarily living in a country and using its public services.",
    "outgoing": [node0, node1],
    "incoming": [],
}

var link20 = {
    "from": node2,
    "to": node0,
    "type": "support"
}

var link21 = {
    "from": node2,
    "to": node1,
    "type": "oppose"
}

var nodes = [node2, node0, node1];
var relations = [link21, link20];
current_card = node2;

function is_outgoing(node) {
    return current_card.outgoing.indexOf(node) != -1;
}

function currently_displayed(node) {
    return (node == current_card) || is_outgoing(node);
}

function x_pos(node) {
    if (node == current_card) {
        node.i = 0; // doesn't matter for current_card
        return (window.innerWidth / 2) - half_card_width;
    } else if (is_outgoing(node)) {
        if (node.i == null) {
            node.i = next_outgoing_i;
            next_outgoing_i++;
        }
        return node.i * (card_width + 10) + 10;
    } else {
        if (node.previously_current) {
            return window.innerWidth + 10;
        } else if (node.previously_outgoing) {
            return (window.innerWidth / 2) - half_card_width;
        }
    }
}

function y_pos(node) {
    if (node == current_card) {
        return (graph_height / 2) - half_card_height;
    } else if (is_outgoing(node)) {
        return 10;
    } else {
        if (node.previously_current) {
            return (graph_height / 2) - half_card_height;
        } else if (node.previously_outgoing) {
            return -10 - card_height;
        } else {
            console.log(node);
        }
    }
}

function pos2str(pos) {
    return pos[0] + "," + pos[1] + " ";
}

function compute_link_bezier_curve(link) {
    var from = link.from;
    var to = link.to;
    var start_pos = [x_pos(from, from.i) + half_card_width, y_pos(from, from.i)];
    var end_pos = [x_pos(to, to.i) + half_card_width,
                    /* marker-widht is 3, stroke-width is 5 */
                   y_pos(to, to.i) + card_height + (5 * 3)];
    var height = end_pos[1] - start_pos[1];
    var control1 = [start_pos[0], start_pos[1] + (height / 2)];
    var control2 = [end_pos[0], end_pos[1] - (height / 2)];
    return "M" + pos2str(start_pos) + "C" + pos2str(control1)
            + pos2str(control2) + pos2str(end_pos);
}

function reset_globals() {
    for (var i=0; i < nodes.length; i++) {
        node = nodes[i];
        node.i = null;
    }
    next_outgoing_i = 0;
    next_incoming_i = 0;
}

function make_cards() {
    var svg = d3.select("svg#graph");
    cards = svg.selectAll("g").data(nodes);
    new_cards = cards.enter().append("g").classed("argument", true);
    new_cards.append("rect").attr("width", card_width).attr("height", card_height);
    var switch_objects = new_cards.append("switch");
    switch_objects.append("foreignObject").classed("foreign-object", true)
            .attr("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility")
            .attr("width", card_width).attr("height", card_height)
            .append("xhtml:div").classed("summary", true).append("p")
            .classed("summary", true).text(function (d) {
                return d.summary;
            }).attr("xmlns", "http://www.w3.org/1999/xhtml");
    switch_objects.append("text").attr("x", x_pos).attr("y", y_pos)
        .text("Sorry, your browser is not supported.");
    new_cards.on("click", function (d) {
        current_card = d;
        draw_graph();
    })
}

function make_links() {
    var svg = d3.select("svg#graph");
    links = svg.selectAll("path").data(relations);
    links.enter().append("path")
        .attr("class", function(d) {
            return d.type;
        }).attr("d", compute_link_bezier_curve)
        .attr("marker-end", function(d) {
            return "url(#arrow-" + d.type + ")"
        });
}

function draw_graph() {
    reset_globals();
    make_cards();
    make_links();

    var svg = d3.select("svg#graph");
    d3.selectAll("g rect").transition().duration(500).attr("x", x_pos).attr("y", y_pos);
    // http://stackoverflow.com/a/11743721/257583
    d3.selectAll(".foreign-object").transition().duration(500).attr("x", x_pos).attr("y", y_pos);
    for (var i=0; i < nodes.length; i++) {
        node.previously_current = node.previously_outgoing = null;
    }
    cards.each(function (d) {
        if (current_card == d) {
            d.previously_current = true;
        } else if (is_outgoing(d)) {
            d.previously_outgoing = true;
        }
    });
    links.transition().duration(150).attr("opacity", function (d) {
        // if one end of the link is currently displayed, then the other is too
        if (currently_displayed(d.from)) {
            return 1;
        } else {
            return 0;
        }
    })
}

window.onload = function () {
    graph_height = $("#graph").height();
    draw_graph();
}<commit_msg>Can now navigate between cards<commit_after>var card_width = 300;
var card_height = 186;
var half_card_width = card_width / 2;
var half_card_height = card_height / 2;

var next_outgoing_i = 0; /* the index of the next node that's outgoing */
var next_incoming_i = 0;

/* Which card is currently displayed in the middle of the screen? */
var current_card = null;

/* Height of rendered graph */
var graph_height = null;

var nodes = [];
var cards = [];
var relations = []; // relations are between nodes
var links = []; // links are between cards

var node0 = {
    "summary": "Why a max length of 140 characters? Well, it sure as hell works for Twitter. Seems like just enough to pack some good info into an argument.",
    "outgoing": [],
    "incoming": [node2],
}

var node1 = {
    "summary": "Taxation is theft.",
    "outgoing": [],
    "incoming": [node2],
}

var node2 = {
    "summary": "You pay taxes in exchange for voluntarily living in a country and using its public services.",
    "outgoing": [node0, node1],
    "incoming": [],
}

node0.incoming = [node2];
node1.incoming = [node2];

var link20 = {
    "from": node2,
    "to": node0,
    "type": "support"
}

var link21 = {
    "from": node2,
    "to": node1,
    "type": "oppose"
}

var nodes = [node2, node0, node1];
var relations = [link21, link20];
current_card = node2;

function is_outgoing(node) {
    return current_card.outgoing.indexOf(node) != -1;
}

function is_incoming(node) {
    return current_card.incoming.indexOf(node) != -1;
}

function currently_displayed(node) {
    return (node == current_card) || is_outgoing(node) || is_incoming(node);
}

function x_pos(node) {
    if (node == current_card) {
        node.i = 0; // doesn't matter for current_card
        return (window.innerWidth / 2) - half_card_width;
    } else if (is_outgoing(node)) {
        if (node.i == null) {
            node.i = next_outgoing_i;
            next_outgoing_i++;
        }
        return node.i * (card_width + 10) + 10;
    } else if (is_incoming(node)) {
        if (node.i == null) {
            node.i = next_incoming_i;
            next_incoming_i++;
        }
        return node.i * (card_width + 10) + 10;
    } else {
        if (node.previously_current) {
            return window.innerWidth + 10;
        } else if (node.previously_outgoing) {
            return (window.innerWidth / 2) - half_card_width;
        }
    }
}

function y_pos(node) {
    if (node == current_card) {
        return (graph_height / 2) - half_card_height;
    } else if (is_outgoing(node)) {
        return 10;
    } else if (is_incoming(node)) {
        return graph_height - 10 - card_height;
    } else {
        if (node.previously_current) {
            return (graph_height / 2) - half_card_height;
        } else if (node.previously_outgoing) {
            return -10 - card_height;
        } else {
            console.log(node);
        }
    }
}

function pos2str(pos) {
    return pos[0] + "," + pos[1] + " ";
}

function compute_link_bezier_curve(link) {
    var from = link.from;
    var to = link.to;
    var start_pos = [x_pos(from, from.i) + half_card_width, y_pos(from, from.i)];
    var end_pos = [x_pos(to, to.i) + half_card_width,
                    /* marker-widht is 3, stroke-width is 5 */
                   y_pos(to, to.i) + card_height + (5 * 3)];
    var height = end_pos[1] - start_pos[1];
    var control1 = [start_pos[0], start_pos[1] + (height / 2)];
    var control2 = [end_pos[0], end_pos[1] - (height / 2)];
    return "M" + pos2str(start_pos) + "C" + pos2str(control1)
            + pos2str(control2) + pos2str(end_pos);
}

function reset_globals() {
    for (var i=0; i < nodes.length; i++) {
        node = nodes[i];
        node.i = null;
    }
    next_outgoing_i = 0;
    next_incoming_i = 0;
}

function make_cards() {
    var svg = d3.select("svg#graph");
    cards = svg.selectAll("g").data(nodes);
    new_cards = cards.enter().append("g").classed("argument", true);
    new_cards.append("rect").attr("width", card_width).attr("height", card_height);
    var switch_objects = new_cards.append("switch");
    switch_objects.append("foreignObject").classed("foreign-object", true)
            .attr("requiredFeatures", "http://www.w3.org/TR/SVG11/feature#Extensibility")
            .attr("width", card_width).attr("height", card_height)
            .append("xhtml:div").classed("summary", true).append("p")
            .classed("summary", true).text(function (d) {
                return d.summary;
            }).attr("xmlns", "http://www.w3.org/1999/xhtml");
    switch_objects.append("text").attr("x", x_pos).attr("y", y_pos)
        .text("Sorry, your browser is not supported.");
    new_cards.on("click", function (d) {
        current_card = d;
        draw_graph();
    })
}

function make_links() {
    var svg = d3.select("svg#graph");
    links = svg.selectAll("path").data(relations);
    links.enter().append("path")
        .attr("class", function(d) {
            return d.type;
        }).attr("d", compute_link_bezier_curve)
        .attr("marker-end", function(d) {
            return "url(#arrow-" + d.type + ")"
        });
}

function draw_graph() {
    reset_globals();
    make_cards();
    make_links();

    var svg = d3.select("svg#graph");
    d3.selectAll("g rect").transition().duration(500).attr("x", x_pos).attr("y", y_pos);
    // http://stackoverflow.com/a/11743721/257583
    d3.selectAll(".foreign-object").transition().duration(500).attr("x", x_pos).attr("y", y_pos);
    cards.each(function (d) {
        d.previously_current = false;
        d.previously_outgoing = false;

        if (current_card == d) {
            d.previously_current = true;
        } else if (is_outgoing(d)) {
            d.previously_outgoing = true;
        }
    });
    links.transition().duration(150).attr("opacity", function (d) {
        // if one end of the link is currently displayed, then the other is too
        if (currently_displayed(d.from)) {
            return 1;
        } else {
            return 0;
        }
    })
}

window.onload = function () {
    graph_height = $("#graph").height();
    draw_graph();
}<|endoftext|>


<commit_before>var logger;

const exec = require('child_process').exec;
const fs = require('fs');
const path = require('path');
const respawn = require('respawn');
const io = require('socket.io-client');
const events = require('events');

var defaults = {
    port: 8099,
    wspath: '/geovideo'
};

var geomux = function geomux(name, deps) {
    logger= deps.logger;

    logger.info('The geo-mux plugin.');
    var self = this;
    this.deps = deps;
    this.services = {};
    var emitter = new events.EventEmitter();
    var global = deps.globalEventLoop;
    var cockpit = deps.cockpit;
    this.flag_experimentH264 = false;
    this._monitor = null;
    var videoServer = io.connect('http://localhost:' + defaults.port, {
        path: defaults.wspath,
        reconnection: true,
        reconnectionAttempts: Infinity,
        reconnectionDelay: 10
    });
    var cameras = {};
    // ----------------------------
    // Register all other listeners
    cockpit.on('plugin.geomuxp.command', function(camera, command, params) {
        // Forward to geo-video-server
        videoServer.emit('geomux.command', camera, command, params);
    });

    global.withHistory.on('settings-change.videosettings',function(settings){
        if ((flag_experimentH264!==settings.videosettings['use-geoserve']) && (_monitor !== null)){
            this.stop();
            this.start();
        }
        flag_experimentH264=settings.videosettings['use-geoserve'];
    });

    videoServer.on('video-deviceRegistration', function(update) {
        logger.debug('Got device update');
    });
    // Video endpoint announcement
    videoServer.on('geomux.video.announcement', function(camera, channel, info) {
        logger.debug('Announcement info: ' + JSON.stringify(info));
        // Emit message on global event loop to register with the Video plugin
        self.deps.globalEventLoop.emit('CameraRegistration', {
            location: info.txtRecord.cameraLocation,
            videoMimeType: info.txtRecord.videoMimeType,
            resolution: info.txtRecord.resolution,
            framerate: info.txtRecord.framerate,
            wspath: info.txtRecord.wspath,
            relativeServiceUrl: info.txtRecord.relativeServiceUrl,
            sourcePort: info.port,
            sourceAddress: info.addresses[0],
            connectionType: 'socket.io'
        });
    });
    // Channel settings
    videoServer.on('geomux.channel.settings', function(camera, channel, settings) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.settings', settings);
    });

    // Channel health
    videoServer.on('geomux.channel.health', function(camera, channel, health) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.health', health);
    });
    // Channel api
    videoServer.on('geomux.channel.api', function(camera, channel, api) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.api', api);
    });
    // Channel status
    videoServer.on('geomux.channel.status', function(camera, channel, status) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.status', status);
    });
    // Channel error
    videoServer.on('geomux.channel.error', function(camera, channel, error) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.error', error);
    });
    // Upon connecting to video server, set up listeners
    videoServer.on('connect', function() {
        logger.info('Successfully connected to geo-video-server');
        // Tell geo-video-server to start the daemons
        videoServer.emit('geomux.ready');
    });
    // Disconnection
    videoServer.on('disconnect', function() {
        logger.info('Disconnected from video server.');
    });
    // Error
    videoServer.on('error', function(err) {
        logger.error(err,'Video Server Connection Error');
    });
    // Reconnect attempt
    videoServer.on('reconnect', function() {
        logger.info('Attempting to reconnect');
    });
    // Helper function to update local store of cameras and channels
    function UpdateCameraInfo(camera, channel) {
        if (cameras[camera] === undefined) {
            // Create the camera
            cameras[camera] = {};
            // Add the channel
            cameras[camera][channel] = {};
            self.deps.cockpit.emit('plugin.geomuxp.cameraInfo', cameras);
        } else if (cameras[camera][channel] === undefined) {
            // Add the channel
            cameras[camera][channel] = {};
            self.deps.cockpit.emit('plugin.geomuxp.cameraInfo', cameras);
        }
    }
};

geomux.prototype.start = function stop()
{
    logger.info('Stopping geomux program');
    _monitor.stop();
    _monitor = null;
}

// This gets called when plugins are started
geomux.prototype.start = function start()
{
    logger.info('Starting geomux program');
    var geoprogram = '';

    // Figure out which video server to use
    if( process.env.USE_MOCK == 'true' )
    {
      if (process.env.MOCK_VIDEO_TYPE === "GEOMUX")
      {
          geoprogram = require.resolve('geo-video-simulator');
      }
      else
      {
          return;
      }
    }
    else
    {
        // Find the geo-video-server app
        try
        {
            geoprogram = require.resolve('geo-video-server');
        }
        catch (er)
        {
            logger.error('geo-video-server not installed');
            return;
        }
    }

    var launch_options = [];
    if( process.env.USE_MOCK != 'true' ){
        //Don't use platform specific nice in mock mode
        launch_options= launch_options.concat([
        'nice',
        '--19'
        ])
    }

  if (this.flag_experimentH264){
   launch_options = launch_options.concat([
       'geoserve'
   ])
  } else {

    // Create all launch options
   launch_options = launch_options.concat([
        'node',
        geoprogram,
        '--p',
        defaults.port,
        '--w',
        defaults.wspath,
        '--c',
        0,
        '--u',
        process.env.DEV_MODE === 'true' ? ':8099' : ''
   ]);
  }
    const infinite = -1;
    // Set up monitor with specified options
    var monitor = respawn(launch_options, {
        name: 'geomux',
        env: {
            'DEBUG': 'app*,camera*,channel*'
        },
        maxRestarts: infinite,
        sleep: 1000
    });
    monitor.on('exit', function(code, signal) {
        logger.error('Geo-video-server exited. Code: [' + code + '] Signal: [' + signal + ']');
    });
    monitor.on('stdout', function(data) {
        var msg = data.toString('utf-8');
        logger.debug('geo-video-server STDOUT: ' + msg);
    });
    monitor.on('stderr', function(data) {
        var msg = data.toString('utf-8');
        logger.debug('geo-video-server STDERR: ' + msg);
    });
    // Start the monitor
    monitor.start();
    this._monitor = monitor;
};
//Export provides the public interface
module.exports = function(name, deps) {
    return new geomux(name, deps);
};
<commit_msg>fix variable<commit_after>var logger;

const exec = require('child_process').exec;
const fs = require('fs');
const path = require('path');
const respawn = require('respawn');
const io = require('socket.io-client');
const events = require('events');

var defaults = {
    port: 8099,
    wspath: '/geovideo'
};

var geomux = function geomux(name, deps) {
    logger= deps.logger;

    logger.info('The geo-mux plugin.');
    var self = this;
    this.deps = deps;
    this.services = {};
    var emitter = new events.EventEmitter();
    var global = deps.globalEventLoop;
    var cockpit = deps.cockpit;
    this.flag_experimentH264 = false;
    this._monitor = null;
    var videoServer = io.connect('http://localhost:' + defaults.port, {
        path: defaults.wspath,
        reconnection: true,
        reconnectionAttempts: Infinity,
        reconnectionDelay: 10
    });
    var cameras = {};
    // ----------------------------
    // Register all other listeners
    cockpit.on('plugin.geomuxp.command', function(camera, command, params) {
        // Forward to geo-video-server
        videoServer.emit('geomux.command', camera, command, params);
    });

    global.withHistory.on('settings-change.videosettings',function(settings){
        if ((this.flag_experimentH264!==settings.videosettings['use-geoserve']) && (_monitor !== null)){
            this.stop();
            this.start();
        }
        this.flag_experimentH264=settings.videosettings['use-geoserve'];
    });

    videoServer.on('video-deviceRegistration', function(update) {
        logger.debug('Got device update');
    });
    // Video endpoint announcement
    videoServer.on('geomux.video.announcement', function(camera, channel, info) {
        logger.debug('Announcement info: ' + JSON.stringify(info));
        // Emit message on global event loop to register with the Video plugin
        self.deps.globalEventLoop.emit('CameraRegistration', {
            location: info.txtRecord.cameraLocation,
            videoMimeType: info.txtRecord.videoMimeType,
            resolution: info.txtRecord.resolution,
            framerate: info.txtRecord.framerate,
            wspath: info.txtRecord.wspath,
            relativeServiceUrl: info.txtRecord.relativeServiceUrl,
            sourcePort: info.port,
            sourceAddress: info.addresses[0],
            connectionType: 'socket.io'
        });
    });
    // Channel settings
    videoServer.on('geomux.channel.settings', function(camera, channel, settings) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.settings', settings);
    });

    // Channel health
    videoServer.on('geomux.channel.health', function(camera, channel, health) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.health', health);
    });
    // Channel api
    videoServer.on('geomux.channel.api', function(camera, channel, api) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.api', api);
    });
    // Channel status
    videoServer.on('geomux.channel.status', function(camera, channel, status) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.status', status);
    });
    // Channel error
    videoServer.on('geomux.channel.error', function(camera, channel, error) {
        UpdateCameraInfo(camera, channel);
        self.deps.cockpit.emit('plugin.geomuxp.' + camera + '_' + channel + '.error', error);
    });
    // Upon connecting to video server, set up listeners
    videoServer.on('connect', function() {
        logger.info('Successfully connected to geo-video-server');
        // Tell geo-video-server to start the daemons
        videoServer.emit('geomux.ready');
    });
    // Disconnection
    videoServer.on('disconnect', function() {
        logger.info('Disconnected from video server.');
    });
    // Error
    videoServer.on('error', function(err) {
        logger.error(err,'Video Server Connection Error');
    });
    // Reconnect attempt
    videoServer.on('reconnect', function() {
        logger.info('Attempting to reconnect');
    });
    // Helper function to update local store of cameras and channels
    function UpdateCameraInfo(camera, channel) {
        if (cameras[camera] === undefined) {
            // Create the camera
            cameras[camera] = {};
            // Add the channel
            cameras[camera][channel] = {};
            self.deps.cockpit.emit('plugin.geomuxp.cameraInfo', cameras);
        } else if (cameras[camera][channel] === undefined) {
            // Add the channel
            cameras[camera][channel] = {};
            self.deps.cockpit.emit('plugin.geomuxp.cameraInfo', cameras);
        }
    }
};

geomux.prototype.start = function stop()
{
    logger.info('Stopping geomux program');
    _monitor.stop();
    _monitor = null;
}

// This gets called when plugins are started
geomux.prototype.start = function start()
{
    logger.info('Starting geomux program');
    var geoprogram = '';

    // Figure out which video server to use
    if( process.env.USE_MOCK == 'true' )
    {
      if (process.env.MOCK_VIDEO_TYPE === "GEOMUX")
      {
          geoprogram = require.resolve('geo-video-simulator');
      }
      else
      {
          return;
      }
    }
    else
    {
        // Find the geo-video-server app
        try
        {
            geoprogram = require.resolve('geo-video-server');
        }
        catch (er)
        {
            logger.error('geo-video-server not installed');
            return;
        }
    }

    var launch_options = [];
    if( process.env.USE_MOCK != 'true' ){
        //Don't use platform specific nice in mock mode
        launch_options= launch_options.concat([
        'nice',
        '--19'
        ])
    }

  if (this.flag_experimentH264){
   launch_options = launch_options.concat([
       'geoserve'
   ])
  } else {

    // Create all launch options
   launch_options = launch_options.concat([
        'node',
        geoprogram,
        '--p',
        defaults.port,
        '--w',
        defaults.wspath,
        '--c',
        0,
        '--u',
        process.env.DEV_MODE === 'true' ? ':8099' : ''
   ]);
  }
    const infinite = -1;
    // Set up monitor with specified options
    var monitor = respawn(launch_options, {
        name: 'geomux',
        env: {
            'DEBUG': 'app*,camera*,channel*'
        },
        maxRestarts: infinite,
        sleep: 1000
    });
    monitor.on('exit', function(code, signal) {
        logger.error('Geo-video-server exited. Code: [' + code + '] Signal: [' + signal + ']');
    });
    monitor.on('stdout', function(data) {
        var msg = data.toString('utf-8');
        logger.debug('geo-video-server STDOUT: ' + msg);
    });
    monitor.on('stderr', function(data) {
        var msg = data.toString('utf-8');
        logger.debug('geo-video-server STDERR: ' + msg);
    });
    // Start the monitor
    monitor.start();
    this._monitor = monitor;
};
//Export provides the public interface
module.exports = function(name, deps) {
    return new geomux(name, deps);
};
<|endoftext|>