<commit_before>/*!
 * tingle.js
 * @author  robin_parisi
 * @version 0.8.0
 * @url
 */
(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(factory);
    } else if (typeof exports === 'object') {
        module.exports = factory();
    } else {
        root.tingle = factory();
    }
}(this, function() {

    /* ----------------------------------------------------------- */
    /* == modal */
    /* ----------------------------------------------------------- */

    var body = document.querySelector('body');
    var transitionEvent = whichTransitionEvent();

    /**
     * Modal constructor
     */
    function Modal(options) {
        this.modal;
        this.modalCloseBtn;
        this.modalWrapper;
        this.modalBox;
        this.modalBoxContent
        this.modalBoxFooter;
        this.modalContent;
        var defaults = {
            onClose: null,
            onOpen: null,
            stickyFooter: false,
            footer: false,
            cssClass: []
        }

        // extends config
        this.opts = extend({}, defaults, options);

        // init modal
        this.init();

    }

    /**
     * Init modal
     */
    Modal.prototype.init = function() {
        if (this.modal) {
            return;
        }

        _build.call(this);
        _bindEvents.call(this);

        // insert modal in dom
        document.body.insertBefore(this.modal, document.body.firstChild);

        if (this.opts.footer) {
            this.addFooter();
        }
    };

    /**
     * Destroy modal: unbind events and remove from dom
     */
    Modal.prototype.destroy = function() {
        if (this.modal === null) {
            return;
        }
        _unbindEvents.call(this);

        // remove modal from dom
        this.modal.parentNode.removeChild(this.modal);

        this.modal = null;
    };

    /**
     * Open modal
     */
    Modal.prototype.open = function(options) {

        this.modal.style.display = null;

        // prevent double scroll
        body.classList.add('tingle-enabled');

        // sticky footer
        this.setStickyFooter(this.opts.stickyFooter);

        // show modal
        this.modal.classList.add('tingle-modal--visible');

        // onOpen event
        var self = this;

        if (transitionEvent) {
            this.modal.addEventListener(transitionEvent, function handler() {
                if (typeof self.opts.onOpen === 'function') {
                    self.opts.onOpen.call(self);
                }

                // detach event after transition end (so it doesn't fire multiple onOpen)
                self.modal.removeEventListener(transitionEvent, handler, false);

            }, false);
        }

        // check if modal is bigger than screen height
        _checkOverflow.call(this);

    };

    /**
     * Close modal
     */
    Modal.prototype.close = function(e) {

        this.modal.style.display = 'none';
        body.classList.remove('tingle-enabled');

        this.modal.classList.remove('tingle-modal--visible');

        // on close callback
        if (typeof this.opts.onClose === "function") {
            this.opts.onClose.call(this);
        }
    };

    /**
     * Set content
     */
    Modal.prototype.setContent = function(content) {
        // check type of content : String or Node
        if (typeof content === 'string') {
            this.modalBoxContent.innerHTML = content;
        } else {
            this.modalBoxContent.innerHTML = "";
            this.modalBoxContent.appendChild(content);
        }
    };

    Modal.prototype.getContent = function() {
        return this.modalBoxContent;
    };

    Modal.prototype.addFooter = function() {
        // add footer to modal
        _buildFooter.call(this);
    }

    Modal.prototype.setFooterContent = function(content) {
        // set footer content
        this.modalBoxFooter.innerHTML = content;
    };

    Modal.prototype.getFooterContent = function() {
        return this.modalBoxFooter;
    };

    Modal.prototype.setStickyFooter = function(isSticky) {

        // if the modal is smaller than the viewport height, we don't need sticky
        if (!this.isOverflow()) {
            isSticky = false;
        }

        if (isSticky) {
            if (this.modalBox.contains(this.modalBoxFooter)) {
                this.modalBox.removeChild(this.modalBoxFooter);
                this.modal.appendChild(this.modalBoxFooter);
                this.modalBoxFooter.classList.add('tingle-modal-box__footer--sticky');
                _recalculateFooterPosition.call(this);
                this.modalBoxContent.style['padding-bottom'] = this.modalBoxFooter.clientHeight + 20 + 'px';
                bind(this.modalBoxFooter, 'click', _catchEvent);
            }
        } else if (this.modalBoxFooter) {
            if (!this.modalBox.contains(this.modalBoxFooter)) {
                this.modal.removeChild(this.modalBoxFooter);
                this.modalBox.appendChild(this.modalBoxFooter);
                this.modalBoxFooter.style.width = 'auto';
                this.modalBoxFooter.style.left = '';
                this.modalBoxContent.style['padding-bottom'] = '';
                this.modalBoxFooter.classList.remove('tingle-modal-box__footer--sticky');
            }
        }
    }

    Modal.prototype.addFooterBtn = function(label, cssClass, callback) {
        var btn = document.createElement("button");

        // set label
        btn.innerHTML = label;

        // bind callback
        btn.addEventListener('click', callback);

        if (typeof cssClass === 'string' && cssClass.length) {
            // add classes to btn
            cssClass.split(" ").forEach(function(item) {
                btn.classList.add(item);
            });
        }

        this.modalBoxFooter.appendChild(btn);

        return btn;
    }

    Modal.prototype.resize = function() {
        console.warn('Resize is deprecated and will be removed in version 1.0');
    };

    Modal.prototype.isOverflow = function() {
        var viewportHeight = window.innerHeight;
        var modalHeight = this.modalBox.clientHeight;

        var isOverflow = modalHeight < viewportHeight ? false : true;
        return isOverflow;
    }

    /* ----------------------------------------------------------- */
    /* == private methods */
    /* ----------------------------------------------------------- */

    function _checkOverflow() {
        // only if the modal is currently shown
        if (this.modal.classList.contains('tingle-modal--visible')) {
            if (this.isOverflow()) {
                this.modal.classList.add('tingle-modal--overflow');
            } else {
                this.modal.classList.remove('tingle-modal--overflow');
            }

            // TODO: remove offset
            //_offset.call(this);
            if (!this.isOverflow() && this.opts.stickyFooter) {
                this.setStickyFooter(false);
            } else if (this.isOverflow() && this.opts.stickyFooter) {
                _recalculateFooterPosition.call(this);
                this.setStickyFooter(true);
            }
        }
    };

    function _recalculateFooterPosition() {
        if (!this.modalBoxFooter) {
            return;
        }
        this.modalBoxFooter.style.width = this.modalBox.clientWidth + 'px';
        this.modalBoxFooter.style.left = this.modalBox.offsetLeft + 'px';
    }

    function _build() {
        this.modal = create('div', 'tingle-modal');
        this.modal.style.display = 'none';

        // custom class
        this.opts.cssClass.forEach(function(item) {
            if (typeof item === 'string') {
                this.modal.classList.add(item);
            }
        }, this);

        this.modalCloseBtn = create('button', 'tingle-modal__close');
        this.modalCloseBtn.innerHTML = '×';

        this.modalBox = create('div', 'tingle-modal-box');
        this.modalBoxContent = create('div', 'tingle-modal-box__content');
        this.modalBox.appendChild(this.modalBoxContent);

        this.modal.appendChild(this.modalCloseBtn);
        this.modal.appendChild(this.modalBox);

    };

    function _buildFooter() {
        this.modalBoxFooter = create('div', 'tingle-modal-box__footer');
        this.modalBox.appendChild(this.modalBoxFooter);
    }

    function _bindEvents() {
        bind(this.modalCloseBtn, 'click', this.close.bind(this));
        bind(this.modal, 'click', this.close.bind(this));
        bind(this.modalBox, 'click', _catchEvent);
        window.addEventListener('resize', _checkOverflow.bind(this));
    };

    /**
     * Avoid closing the modal when a click is trigger inside
     */
    function _catchEvent(e) {
        e.stopPropagation();
    };

    function _unbindEvents() {
        unbind(this.modalCloseBtn, 'click', this.close.bind(this));
        unbind(this.modal, 'click', this.close.bind(this));
        unbind(this.modalBox, 'click', _catchEvent);

    };

    /* ----------------------------------------------------------- */
    /* == confirm */
    /* ----------------------------------------------------------- */

    // coming soon

    /* ----------------------------------------------------------- */
    /* == alert */
    /* ----------------------------------------------------------- */

    // coming soon

    /* ----------------------------------------------------------- */
    /* == helpers */
    /* ----------------------------------------------------------- */

    function extend() {
        for (var i = 1; i < arguments.length; i++) {
            for (var key in arguments[i]) {
                if (arguments[i].hasOwnProperty(key)) {
                    arguments[0][key] = arguments[i][key];
                }
            }
        }
        return arguments[0];
    }

    function isNodeList(el) {
        return (typeof el.length != 'undefined' && typeof el.item != 'undefined');
    }

    function bind(el, event, callback) {

        if (isNodeList(el)) {
            [].forEach.call(el, function(el) {
                el.addEventListener(event, callback);
            })
        } else {
            el.addEventListener(event, callback);
        }
    }

    function unbind(el, event, callback) {
        if (isNodeList(el)) {
            [].forEach.call(el, function(el) {
                el.removeEventListener(event, callback);
            })
        } else {
            el.removeEventListener(event, callback);
        }
    }

    function create(element, cssClass) {
        var element = document.createElement(element);
        if (cssClass) {
            element.classList.add(cssClass);
        }
        return element;
    }

    function whichTransitionEvent() {
        var t;
        var el = document.createElement('tingle-test-transition');
        var transitions = {
            'transition': 'transitionend',
            'OTransition': 'oTransitionEnd',
            'MozTransition': 'transitionend',
            'WebkitTransition': 'webkitTransitionEnd'
        }

        for (t in transitions) {
            if (el.style[t] !== undefined) {
                return transitions[t];
            }
        }
    }

    /* ----------------------------------------------------------- */
    /* == return */
    /* ----------------------------------------------------------- */

    return {
        modal: Modal
    };

}));
<commit_msg>Internet Explorer friendly property removal<commit_after>/*!
 * tingle.js
 * @author  robin_parisi
 * @version 0.8.0
 * @url
 */
(function(root, factory) {
    if (typeof define === 'function' && define.amd) {
        define(factory);
    } else if (typeof exports === 'object') {
        module.exports = factory();
    } else {
        root.tingle = factory();
    }
}(this, function() {

    /* ----------------------------------------------------------- */
    /* == modal */
    /* ----------------------------------------------------------- */

    var body = document.querySelector('body');
    var transitionEvent = whichTransitionEvent();

    /**
     * Modal constructor
     */
    function Modal(options) {
        this.modal;
        this.modalCloseBtn;
        this.modalWrapper;
        this.modalBox;
        this.modalBoxContent
        this.modalBoxFooter;
        this.modalContent;
        var defaults = {
            onClose: null,
            onOpen: null,
            stickyFooter: false,
            footer: false,
            cssClass: []
        }

        // extends config
        this.opts = extend({}, defaults, options);

        // init modal
        this.init();

    }

    /**
     * Init modal
     */
    Modal.prototype.init = function() {
        if (this.modal) {
            return;
        }

        _build.call(this);
        _bindEvents.call(this);

        // insert modal in dom
        document.body.insertBefore(this.modal, document.body.firstChild);

        if (this.opts.footer) {
            this.addFooter();
        }
    };

    /**
     * Destroy modal: unbind events and remove from dom
     */
    Modal.prototype.destroy = function() {
        if (this.modal === null) {
            return;
        }
        _unbindEvents.call(this);

        // remove modal from dom
        this.modal.parentNode.removeChild(this.modal);

        this.modal = null;
    };

    /**
     * Open modal
     */
    Modal.prototype.open = function(options) {

        if (this.modal.style.removeProperty) {
			this.modal.style.removeProperty('display');
		} else {
			this.modal.style.removeAttribute('display');
		}

        // prevent double scroll
        body.classList.add('tingle-enabled');

        // sticky footer
        this.setStickyFooter(this.opts.stickyFooter);

        // show modal
        this.modal.classList.add('tingle-modal--visible');

        // onOpen event
        var self = this;

        if (transitionEvent) {
            this.modal.addEventListener(transitionEvent, function handler() {
                if (typeof self.opts.onOpen === 'function') {
                    self.opts.onOpen.call(self);
                }

                // detach event after transition end (so it doesn't fire multiple onOpen)
                self.modal.removeEventListener(transitionEvent, handler, false);

            }, false);
        }

        // check if modal is bigger than screen height
        _checkOverflow.call(this);

    };

    /**
     * Close modal
     */
    Modal.prototype.close = function(e) {

        this.modal.style.display = 'none';
        body.classList.remove('tingle-enabled');

        this.modal.classList.remove('tingle-modal--visible');

        // on close callback
        if (typeof this.opts.onClose === "function") {
            this.opts.onClose.call(this);
        }
    };

    /**
     * Set content
     */
    Modal.prototype.setContent = function(content) {
        // check type of content : String or Node
        if (typeof content === 'string') {
            this.modalBoxContent.innerHTML = content;
        } else {
            this.modalBoxContent.innerHTML = "";
            this.modalBoxContent.appendChild(content);
        }
    };

    Modal.prototype.getContent = function() {
        return this.modalBoxContent;
    };

    Modal.prototype.addFooter = function() {
        // add footer to modal
        _buildFooter.call(this);
    }

    Modal.prototype.setFooterContent = function(content) {
        // set footer content
        this.modalBoxFooter.innerHTML = content;
    };

    Modal.prototype.getFooterContent = function() {
        return this.modalBoxFooter;
    };

    Modal.prototype.setStickyFooter = function(isSticky) {

        // if the modal is smaller than the viewport height, we don't need sticky
        if (!this.isOverflow()) {
            isSticky = false;
        }

        if (isSticky) {
            if (this.modalBox.contains(this.modalBoxFooter)) {
                this.modalBox.removeChild(this.modalBoxFooter);
                this.modal.appendChild(this.modalBoxFooter);
                this.modalBoxFooter.classList.add('tingle-modal-box__footer--sticky');
                _recalculateFooterPosition.call(this);
                this.modalBoxContent.style['padding-bottom'] = this.modalBoxFooter.clientHeight + 20 + 'px';
                bind(this.modalBoxFooter, 'click', _catchEvent);
            }
        } else if (this.modalBoxFooter) {
            if (!this.modalBox.contains(this.modalBoxFooter)) {
                this.modal.removeChild(this.modalBoxFooter);
                this.modalBox.appendChild(this.modalBoxFooter);
                this.modalBoxFooter.style.width = 'auto';
                this.modalBoxFooter.style.left = '';
                this.modalBoxContent.style['padding-bottom'] = '';
                this.modalBoxFooter.classList.remove('tingle-modal-box__footer--sticky');
            }
        }
    }

    Modal.prototype.addFooterBtn = function(label, cssClass, callback) {
        var btn = document.createElement("button");

        // set label
        btn.innerHTML = label;

        // bind callback
        btn.addEventListener('click', callback);

        if (typeof cssClass === 'string' && cssClass.length) {
            // add classes to btn
            cssClass.split(" ").forEach(function(item) {
                btn.classList.add(item);
            });
        }

        this.modalBoxFooter.appendChild(btn);

        return btn;
    }

    Modal.prototype.resize = function() {
        console.warn('Resize is deprecated and will be removed in version 1.0');
    };

    Modal.prototype.isOverflow = function() {
        var viewportHeight = window.innerHeight;
        var modalHeight = this.modalBox.clientHeight;

        var isOverflow = modalHeight < viewportHeight ? false : true;
        return isOverflow;
    }

    /* ----------------------------------------------------------- */
    /* == private methods */
    /* ----------------------------------------------------------- */

    function _checkOverflow() {
        // only if the modal is currently shown
        if (this.modal.classList.contains('tingle-modal--visible')) {
            if (this.isOverflow()) {
                this.modal.classList.add('tingle-modal--overflow');
            } else {
                this.modal.classList.remove('tingle-modal--overflow');
            }

            // TODO: remove offset
            //_offset.call(this);
            if (!this.isOverflow() && this.opts.stickyFooter) {
                this.setStickyFooter(false);
            } else if (this.isOverflow() && this.opts.stickyFooter) {
                _recalculateFooterPosition.call(this);
                this.setStickyFooter(true);
            }
        }
    };

    function _recalculateFooterPosition() {
        if (!this.modalBoxFooter) {
            return;
        }
        this.modalBoxFooter.style.width = this.modalBox.clientWidth + 'px';
        this.modalBoxFooter.style.left = this.modalBox.offsetLeft + 'px';
    }

    function _build() {
        this.modal = create('div', 'tingle-modal');
        this.modal.style.display = 'none';

        // custom class
        this.opts.cssClass.forEach(function(item) {
            if (typeof item === 'string') {
                this.modal.classList.add(item);
            }
        }, this);

        this.modalCloseBtn = create('button', 'tingle-modal__close');
        this.modalCloseBtn.innerHTML = '×';

        this.modalBox = create('div', 'tingle-modal-box');
        this.modalBoxContent = create('div', 'tingle-modal-box__content');
        this.modalBox.appendChild(this.modalBoxContent);

        this.modal.appendChild(this.modalCloseBtn);
        this.modal.appendChild(this.modalBox);

    };

    function _buildFooter() {
        this.modalBoxFooter = create('div', 'tingle-modal-box__footer');
        this.modalBox.appendChild(this.modalBoxFooter);
    }

    function _bindEvents() {
        bind(this.modalCloseBtn, 'click', this.close.bind(this));
        bind(this.modal, 'click', this.close.bind(this));
        bind(this.modalBox, 'click', _catchEvent);
        window.addEventListener('resize', _checkOverflow.bind(this));
    };

    /**
     * Avoid closing the modal when a click is trigger inside
     */
    function _catchEvent(e) {
        e.stopPropagation();
    };

    function _unbindEvents() {
        unbind(this.modalCloseBtn, 'click', this.close.bind(this));
        unbind(this.modal, 'click', this.close.bind(this));
        unbind(this.modalBox, 'click', _catchEvent);

    };

    /* ----------------------------------------------------------- */
    /* == confirm */
    /* ----------------------------------------------------------- */

    // coming soon

    /* ----------------------------------------------------------- */
    /* == alert */
    /* ----------------------------------------------------------- */

    // coming soon

    /* ----------------------------------------------------------- */
    /* == helpers */
    /* ----------------------------------------------------------- */

    function extend() {
        for (var i = 1; i < arguments.length; i++) {
            for (var key in arguments[i]) {
                if (arguments[i].hasOwnProperty(key)) {
                    arguments[0][key] = arguments[i][key];
                }
            }
        }
        return arguments[0];
    }

    function isNodeList(el) {
        return (typeof el.length != 'undefined' && typeof el.item != 'undefined');
    }

    function bind(el, event, callback) {

        if (isNodeList(el)) {
            [].forEach.call(el, function(el) {
                el.addEventListener(event, callback);
            })
        } else {
            el.addEventListener(event, callback);
        }
    }

    function unbind(el, event, callback) {
        if (isNodeList(el)) {
            [].forEach.call(el, function(el) {
                el.removeEventListener(event, callback);
            })
        } else {
            el.removeEventListener(event, callback);
        }
    }

    function create(element, cssClass) {
        var element = document.createElement(element);
        if (cssClass) {
            element.classList.add(cssClass);
        }
        return element;
    }

    function whichTransitionEvent() {
        var t;
        var el = document.createElement('tingle-test-transition');
        var transitions = {
            'transition': 'transitionend',
            'OTransition': 'oTransitionEnd',
            'MozTransition': 'transitionend',
            'WebkitTransition': 'webkitTransitionEnd'
        }

        for (t in transitions) {
            if (el.style[t] !== undefined) {
                return transitions[t];
            }
        }
    }

    /* ----------------------------------------------------------- */
    /* == return */
    /* ----------------------------------------------------------- */

    return {
        modal: Modal
    };

}));
<|endoftext|>


<commit_before>import Span from './span';
import SpanContext from './span_context';
import * as Constants from './constants';
import * as Functions from './functions';
import * as Noop from './noop';

/**
 * Tracer is the entry-point between the instrumentation API and the tracing
 * implementation.
 *
 * The default object acts as a no-op implementation.
 *
 * Note to implementators: derived classes can choose to directly implement the
 * methods in the "OpenTracing API methods" section, or optionally the subset of
 * underscore-prefixed methods to pick up the argument checking and handling
 * automatically from the base class.
 */
export default class Tracer {

    // ---------------------------------------------------------------------- //
    // OpenTracing API methods
    // ---------------------------------------------------------------------- //

    /**
     * Starts and returns a new Span representing a logical unit of work.
     *
     * For example:
     *
     *     // Start a new (parentless) root Span:
     *     var parent = Tracer.startSpan('DoWork');
     *
     *     // Start a new (child) Span:
     *     var child = Tracer.startSpan('Subroutine', {
     *         reference: Tracer.childOf(parent.context()),
     *     });
     *
     * @param {string} name - the name of the operation.
     * @param {object} [fields] - the fields to set on the newly created span.
     * @param {string} [fields.operationName] - the name to use for the newly
     *        created span. Required if called with a single argument.
     * @param {SpanContext} [fields.childOf] - a parent SpanContext (or Span,
     *        for convenience) that the newly-started span will be the child of
     *        (per REFERENCE_CHILD_OF). If specified, `fields.references` must
     *        be unspecified.
     * @param {array} [fields.references] - an array of Reference instances,
     *        each pointing to a causal parent SpanContext. If specified,
     *        `fields.childOf` must be unspecified.
     * @param {object} [fields.tags] - set of key-value pairs which will be set
     *        as tags on the newly created Span. Ownership of the object is
     *        passed to the created span for efficiency reasons (the caller
     *        should not modify this object after calling startSpan).
     * @param {number} [fields.startTime] - a manually specified start time for
     *        the created Span object. The time should be specified in
     *        milliseconds as Unix timestamp. Decimal value are supported
     *        to represent time values with sub-millisecond accuracy.
     * @return {Span} - a new Span object.
     */
    startSpan(name, fields) {
        // Debug-only runtime checks on the arguments
        if (process.env.NODE_ENV === 'debug') {
            if (arguments.length > 2) {
                throw new Error('Invalid number of arguments.');
            }
            if (typeof name !== 'string') {
                throw new Error('argument expected to be a string');
            }
            if (name.length === 0) {
                throw new Error('operation name cannot be length zero');
            }
            if (fields && fields.childOf && fields.references) {
                throw new Error('At most one of `childOf` and ' +
                        '`references` may be specified');
            }
            if (fields && fields.childOf && !(
                        fields.childOf instanceof Span ||
                        fields.childOf instanceof SpanContext)) {
                throw new Error('childOf must be a Span or SpanContext instance');
            }
        }

        // Convert fields.childOf to fields.references as needed.
        fields = fields || {};
        if (fields.childOf) {
            // Convert from a Span or a SpanContext into a Reference.
            let childOf = Functions.childOf(fields.childOf);
            if (fields.references) {
                fields.references.push(childOf);
            } else {
                fields.references = [childOf];
            }
            delete(fields.childOf);
        }
        return this._startSpan(name, fields);
    }

    /**
     * Injects the given SpanContext instance for cross-process propagation
     * within `carrier`. The expected type of `carrier` depends on the value of
     * `format.
     *
     * OpenTracing defines a common set of `format` values (see
     * FORMAT_TEXT_MAP, FORMAT_HTTP_HEADERS, and FORMAT_BINARY), and each has
     * an expected carrier type.
     *
     * Consider this pseudocode example:
     *
     *     var clientSpan = ...;
     *     ...
     *     // Inject clientSpan into a text carrier.
     *     var headersCarrier = {};
     *     Tracer.inject(clientSpan.context(), Tracer.FORMAT_HTTP_HEADERS, headersCarrier);
     *     // Incorporate the textCarrier into the outbound HTTP request header
     *     // map.
     *     Object.assign(outboundHTTPReq.headers, headersCarrier);
     *     // ... send the httpReq
     *
     * @param  {SpanContext} spanContext - the SpanContext to inject into the
     *         carrier object. As a convenience, a Span instance may be passed
     *         in instead (in which case its .context() is used for the
     *         inject()).
     * @param  {string} format - the format of the carrier.
     * @param  {any} carrier - see the documentation for the chosen `format`
     *         for a description of the carrier object.
     */
    inject(spanContext, format, carrier) {
        // Debug-only runtime checks on the arguments
        if (process.env.NODE_ENV === 'debug') {
            if (arguments.length !== 3) {
                throw new Error('Invalid number of arguments.');
            }
            if (!(spanContext instanceof SpanContext || spanContext instanceof Span)) {
                throw new Error('first argument must be a SpanContext or Span instance');
            }
            if (typeof format !== 'string') {
                throw new Error(`format expected to be a string. Found: ${typeof format}`);
            }
            if (format === Constants.FORMAT_TEXT_MAP && typeof carrier !== 'object') {
                throw new Error('Unexpected carrier object for FORMAT_TEXT_MAP');
            }
            if (format === Constants.FORMAT_HTTP_HEADERS && typeof carrier !== 'object') {
                throw new Error('Unexpected carrier object for FORMAT_HTTP_HEADERS');
            }
            if (format === Constants.FORMAT_BINARY && typeof carrier !== 'object') {
                throw new Error('Unexpected carrier object for FORMAT_BINARY');
            }
        }

        // Allow the user to pass a Span instead of a SpanContext
        if (spanContext instanceof Span) {
            spanContext = spanContext.context();
        }
        return this._inject(spanContext, format, carrier);
    }

    /**
     * Returns a SpanContext instance extracted from `carrier` in the given
     * `format`.
     *
     * OpenTracing defines a common set of `format` values (see
     * FORMAT_TEXT_MAP, FORMAT_HTTP_HEADERS, and FORMAT_BINARY), and each has
     * an expected carrier type.
     *
     * Consider this pseudocode example:
     *
     *     // Use the inbound HTTP request's headers as a text map carrier.
     *     var headersCarrier = inboundHTTPReq.headers;
     *     var wireCtx = Tracer.extract(Tracer.FORMAT_HTTP_HEADERS, headersCarrier);
     *     var serverSpan = Tracer.startSpan('...', { childOf : wireCtx });
     *
     * @param  {string} format - the format of the carrier.
     * @param  {any} carrier - the type of the carrier object is determined by
     *         the format.
     * @return {SpanContext}
     *         The extracted SpanContext, or null if no such SpanContext could
     *         be found in `carrier`
     */
    extract(format, carrier) {
        // Debug-only runtime checks on the arguments
        if (process.env.NODE_ENV === 'debug') {
            if (arguments.length !== 2) {
                throw new Error('Invalid number of arguments.');
            }
            if (typeof format !== 'string' || !format.length) {
                throw new Error('format is expected to be a string of non-zero length');
            }
            if (format === Constants.FORMAT_TEXT_MAP && !(typeof carrier === 'object')) {
                throw new Error('Unexpected carrier object for FORMAT_TEXT_MAP');
            }
            if (format === Constants.FORMAT_HTTP_HEADERS && !(typeof carrier === 'object')) {
                throw new Error('Unexpected carrier object for FORMAT_HTTP_HEADERS');
            }
            if (format === Constants.FORMAT_BINARY) {
                if (carrier.buffer !== undefined && typeof carrier.buffer !== 'object') {
                    throw new Error('Unexpected carrier object for FORMAT_BINARY');
                }
            }
        }
        return this._extract(format, carrier);
    }

    // ---------------------------------------------------------------------- //
    // Derived classes can choose to implement the below
    // ---------------------------------------------------------------------- //

    // NOTE: the input to this method is *always* an associative array. The
    // public-facing startSpan() method normalizes the arguments so that
    // all N implementations do not need to worry about variations in the call
    // signature.
    //
    // The default behavior returns a no-op span.
    _startSpan(name, fields) {
        return Noop.span;
    }

    // The default behavior is a no-op.
    _inject(spanContext, format, carrier) {
    }

    // The default behavior is to return null.
    _extract(format, carrier) {
        return Noop.spanContext;
    }
}
<commit_msg>Simplify startSpan example<commit_after>import Span from './span';
import SpanContext from './span_context';
import * as Constants from './constants';
import * as Functions from './functions';
import * as Noop from './noop';

/**
 * Tracer is the entry-point between the instrumentation API and the tracing
 * implementation.
 *
 * The default object acts as a no-op implementation.
 *
 * Note to implementators: derived classes can choose to directly implement the
 * methods in the "OpenTracing API methods" section, or optionally the subset of
 * underscore-prefixed methods to pick up the argument checking and handling
 * automatically from the base class.
 */
export default class Tracer {

    // ---------------------------------------------------------------------- //
    // OpenTracing API methods
    // ---------------------------------------------------------------------- //

    /**
     * Starts and returns a new Span representing a logical unit of work.
     *
     * For example:
     *
     *     // Start a new (parentless) root Span:
     *     var parent = Tracer.startSpan('DoWork');
     *
     *     // Start a new (child) Span:
     *     var child = Tracer.startSpan('Subroutine', {
     *         childOf: parent.context(),
     *     });
     *
     * @param {string} name - the name of the operation.
     * @param {object} [fields] - the fields to set on the newly created span.
     * @param {string} [fields.operationName] - the name to use for the newly
     *        created span. Required if called with a single argument.
     * @param {SpanContext} [fields.childOf] - a parent SpanContext (or Span,
     *        for convenience) that the newly-started span will be the child of
     *        (per REFERENCE_CHILD_OF). If specified, `fields.references` must
     *        be unspecified.
     * @param {array} [fields.references] - an array of Reference instances,
     *        each pointing to a causal parent SpanContext. If specified,
     *        `fields.childOf` must be unspecified.
     * @param {object} [fields.tags] - set of key-value pairs which will be set
     *        as tags on the newly created Span. Ownership of the object is
     *        passed to the created span for efficiency reasons (the caller
     *        should not modify this object after calling startSpan).
     * @param {number} [fields.startTime] - a manually specified start time for
     *        the created Span object. The time should be specified in
     *        milliseconds as Unix timestamp. Decimal value are supported
     *        to represent time values with sub-millisecond accuracy.
     * @return {Span} - a new Span object.
     */
    startSpan(name, fields) {
        // Debug-only runtime checks on the arguments
        if (process.env.NODE_ENV === 'debug') {
            if (arguments.length > 2) {
                throw new Error('Invalid number of arguments.');
            }
            if (typeof name !== 'string') {
                throw new Error('argument expected to be a string');
            }
            if (name.length === 0) {
                throw new Error('operation name cannot be length zero');
            }
            if (fields && fields.childOf && fields.references) {
                throw new Error('At most one of `childOf` and ' +
                        '`references` may be specified');
            }
            if (fields && fields.childOf && !(
                        fields.childOf instanceof Span ||
                        fields.childOf instanceof SpanContext)) {
                throw new Error('childOf must be a Span or SpanContext instance');
            }
        }

        // Convert fields.childOf to fields.references as needed.
        fields = fields || {};
        if (fields.childOf) {
            // Convert from a Span or a SpanContext into a Reference.
            let childOf = Functions.childOf(fields.childOf);
            if (fields.references) {
                fields.references.push(childOf);
            } else {
                fields.references = [childOf];
            }
            delete(fields.childOf);
        }
        return this._startSpan(name, fields);
    }

    /**
     * Injects the given SpanContext instance for cross-process propagation
     * within `carrier`. The expected type of `carrier` depends on the value of
     * `format.
     *
     * OpenTracing defines a common set of `format` values (see
     * FORMAT_TEXT_MAP, FORMAT_HTTP_HEADERS, and FORMAT_BINARY), and each has
     * an expected carrier type.
     *
     * Consider this pseudocode example:
     *
     *     var clientSpan = ...;
     *     ...
     *     // Inject clientSpan into a text carrier.
     *     var headersCarrier = {};
     *     Tracer.inject(clientSpan.context(), Tracer.FORMAT_HTTP_HEADERS, headersCarrier);
     *     // Incorporate the textCarrier into the outbound HTTP request header
     *     // map.
     *     Object.assign(outboundHTTPReq.headers, headersCarrier);
     *     // ... send the httpReq
     *
     * @param  {SpanContext} spanContext - the SpanContext to inject into the
     *         carrier object. As a convenience, a Span instance may be passed
     *         in instead (in which case its .context() is used for the
     *         inject()).
     * @param  {string} format - the format of the carrier.
     * @param  {any} carrier - see the documentation for the chosen `format`
     *         for a description of the carrier object.
     */
    inject(spanContext, format, carrier) {
        // Debug-only runtime checks on the arguments
        if (process.env.NODE_ENV === 'debug') {
            if (arguments.length !== 3) {
                throw new Error('Invalid number of arguments.');
            }
            if (!(spanContext instanceof SpanContext || spanContext instanceof Span)) {
                throw new Error('first argument must be a SpanContext or Span instance');
            }
            if (typeof format !== 'string') {
                throw new Error(`format expected to be a string. Found: ${typeof format}`);
            }
            if (format === Constants.FORMAT_TEXT_MAP && typeof carrier !== 'object') {
                throw new Error('Unexpected carrier object for FORMAT_TEXT_MAP');
            }
            if (format === Constants.FORMAT_HTTP_HEADERS && typeof carrier !== 'object') {
                throw new Error('Unexpected carrier object for FORMAT_HTTP_HEADERS');
            }
            if (format === Constants.FORMAT_BINARY && typeof carrier !== 'object') {
                throw new Error('Unexpected carrier object for FORMAT_BINARY');
            }
        }

        // Allow the user to pass a Span instead of a SpanContext
        if (spanContext instanceof Span) {
            spanContext = spanContext.context();
        }
        return this._inject(spanContext, format, carrier);
    }

    /**
     * Returns a SpanContext instance extracted from `carrier` in the given
     * `format`.
     *
     * OpenTracing defines a common set of `format` values (see
     * FORMAT_TEXT_MAP, FORMAT_HTTP_HEADERS, and FORMAT_BINARY), and each has
     * an expected carrier type.
     *
     * Consider this pseudocode example:
     *
     *     // Use the inbound HTTP request's headers as a text map carrier.
     *     var headersCarrier = inboundHTTPReq.headers;
     *     var wireCtx = Tracer.extract(Tracer.FORMAT_HTTP_HEADERS, headersCarrier);
     *     var serverSpan = Tracer.startSpan('...', { childOf : wireCtx });
     *
     * @param  {string} format - the format of the carrier.
     * @param  {any} carrier - the type of the carrier object is determined by
     *         the format.
     * @return {SpanContext}
     *         The extracted SpanContext, or null if no such SpanContext could
     *         be found in `carrier`
     */
    extract(format, carrier) {
        // Debug-only runtime checks on the arguments
        if (process.env.NODE_ENV === 'debug') {
            if (arguments.length !== 2) {
                throw new Error('Invalid number of arguments.');
            }
            if (typeof format !== 'string' || !format.length) {
                throw new Error('format is expected to be a string of non-zero length');
            }
            if (format === Constants.FORMAT_TEXT_MAP && !(typeof carrier === 'object')) {
                throw new Error('Unexpected carrier object for FORMAT_TEXT_MAP');
            }
            if (format === Constants.FORMAT_HTTP_HEADERS && !(typeof carrier === 'object')) {
                throw new Error('Unexpected carrier object for FORMAT_HTTP_HEADERS');
            }
            if (format === Constants.FORMAT_BINARY) {
                if (carrier.buffer !== undefined && typeof carrier.buffer !== 'object') {
                    throw new Error('Unexpected carrier object for FORMAT_BINARY');
                }
            }
        }
        return this._extract(format, carrier);
    }

    // ---------------------------------------------------------------------- //
    // Derived classes can choose to implement the below
    // ---------------------------------------------------------------------- //

    // NOTE: the input to this method is *always* an associative array. The
    // public-facing startSpan() method normalizes the arguments so that
    // all N implementations do not need to worry about variations in the call
    // signature.
    //
    // The default behavior returns a no-op span.
    _startSpan(name, fields) {
        return Noop.span;
    }

    // The default behavior is a no-op.
    _inject(spanContext, format, carrier) {
    }

    // The default behavior is to return null.
    _extract(format, carrier) {
        return Noop.spanContext;
    }
}
<|endoftext|>


<commit_before>const cheerio = require("cheerio");
const phantom = require("phantom");

// Scrape tranding page of YouTube in a given language, and insert video IDs to
// the given database. This function returns a promise.
module.exports = function(lang, db) {

    // findIDs parse a given html and find video IDs.
    function findIDs(html) {
        const $ = cheerio.load(html);
        $(".yt-lockup-video").each((_, elem) => {
            const id = $(elem).attr("data-context-item-id");
            db.ids.find({
                id: id
            }, (err, docs) => {
                if (err) {
                    console.error(err);
                }
                if (docs.length == 0) {
                    db.ids.insert({
                        id: id
                    });
                    console.log(id);
                }
            })
        });
    }

    return phantom.create().then((instance) => {

        return instance.createPage().then((page) => {

            // Open the trending page, then check how many items loaded.
            // If no items are loaded, wait 1000msec and then try checking again.
            // Otherwise, read innerHTML of a tree.
            return page.open(`https://www.youtube.com/feed/trending?gl=${lang}`).then((status) => {

                return new Promise((resolve, reject) => {

                    function checkLoading() {
                        page.evaluate(() => {
                            return document.getElementsByClassName("expanded-shelf-content-item").length;
                        }).then((res) => {
                            if (res != 0) {
                                resolve();
                            } else {
                                setTimeout(checkLoading, 1000);
                            }
                        }).catch((err) => {
                            reject(err);
                        })
                    }
                    checkLoading();

                });

            }).then(() => {
                return page.evaluate(() => {
                    return document.getElementsByClassName("expanded-shelf")[0].innerHTML;
                });
            }).then((html) => {
                findIDs(html);
                page.close();
            });

        }).then(() => {
            instance.exit();
        }).catch((err) => {
            console.error(err);
            instance.exit();
            return Promise.reject(err);
        });

    });

}
<commit_msg>trends function returns a Promise.<commit_after>const cheerio = require("cheerio");
const phantom = require("phantom");

// Scrape tranding page of YouTube in a given language, and insert video IDs to
// the given database. This function returns a promise.
module.exports = function(lang, db) {

    // findIDs parse a given html and find video IDs. This function returns a
    // promise.
    function findIDs(html) {

        const $ = cheerio.load(html);
        const promises = [];
        $(".yt-lockup-video").each((_, elem) => {

            promises.push(new Promise((resolve, reject) => {

                const id = $(elem).attr("data-context-item-id");
                db.ids.find({
                    id: id
                }, (err, docs) => {
                    if (err) {
                        console.error(err);
                        reject(err);
                        return
                    }
                    if (docs.length == 0) {
                        db.ids.insert({
                            id: id
                        });
                        console.log(`Insert a new video ID: ${id}`);
                    }
                    resolve();
                });

            }));

        });
        return Promise.all(promises);

    }

    return phantom.create().then((instance) => {

        return instance.createPage().then((page) => {

            // Open the trending page, then check how many items loaded.
            // If no items are loaded, wait 1000msec and then try checking again.
            // Otherwise, read innerHTML of a tree.
            return page.open(`https://www.youtube.com/feed/trending?gl=${lang}`).then((status) => {

                return new Promise((resolve, reject) => {

                    function checkLoading() {
                        page.evaluate(() => {
                            return document.getElementsByClassName("expanded-shelf-content-item").length;
                        }).then((res) => {
                            if (res != 0) {
                                resolve();
                            } else {
                                setTimeout(checkLoading, 1000);
                            }
                        }).catch((err) => {
                            reject(err);
                        })
                    }
                    checkLoading();

                });

            }).then(() => {
                return page.evaluate(() => {
                    return document.getElementsByClassName("expanded-shelf")[0].innerHTML;
                });
            }).then((html) => {
                page.close();
                return findIDs(html);
            });

        }).then(() => {
            instance.exit();
        }).catch((err) => {
            console.error(err);
            instance.exit();
            return Promise.reject(err);
        });

    });

}
<|endoftext|>


<commit_before>ngDefine('cockpit.filters.shorten', function(module) {

  var ShortenFilter = function() {
    return function(input, length) {
      return input.length > length ? input.substring(0, length) : input;
    };
  };

  module.filter('shorten', ShortenFilter);
});<commit_msg>improve(cockpit): show dots to indicate a shortend id<commit_after>ngDefine('cockpit.filters.shorten', function(module) {

  var ShortenFilter = function() {
    return function(input, length) {
      return input.length > length ? input.substring(0, length) + '...' : input;
    };
  };

  module.filter('shorten', ShortenFilter);
});<|endoftext|>


<commit_before>'use strict'
const slapp = require('../slackSetup.js').slapp
const getRadius = require('../radius.js').getRadius
const tinyurl = require('tinyurl');
const request = require('request')
const where = require('node-where')

// route functions
const snapsByGeo = require('./routes/snapsByGeoRoute.js').snapsByGeo
const routeFuncs = require('./routes/routesIndex.js')
const yes = require('./routes/yes.js').yes
const addressToGeo = require('./routes/addressToGeo.js').addressToGeo
const appDl = require('./routes/appDlRoute.js').appDl
const teamSettings = require('../teamSettings.js').teamSettings

const notify = require('./notifySlash.js').notify

let newTeam = false

//db imports
const firebase    = require('../firebaseSetup.js'),
      db = firebase.db,
      snaps = firebase.snaps,
      tags = firebase.tags,
      users = firebase.users,
      slackDb = firebase.slackDb

let jayBtns={
  text: "",
  attachments: [{
    text: 'How can I help?',
    fallback: 'Where to today?',
    callback_id: 'jaywalk_callback',
    color: 'good',
    actions: [
      {
        name: 'answer',
        text: 'Find deals',
        type: 'button',
        value: 'address'
      },{
        name: 'answer',
        text: 'Settings',
        type: 'button',
        value: 'settings'
      },{
        name: 'answer',
        text: 'Download app',
        type: 'button',
        value: 'app'
      }
    ]
  }]
}

let newTeamCallback = (newOld,msg,state)=>{
  msg.say({text:newOld})
}

 //text:`Welcom to Jaywalk! To get better results, please enter the address or your buisness name and city.`
const jaywalk = function() {
  let state = { requested: Date.now() }
  let teamId = ''
  let teamInfo = {}
  let answer

  slapp.command('/jaywalk', (msg, text) => {
    teamInfo = slackDb
      .child(msg.body.team_id)
      .once("value")
      .then(function(obj){
        if(obj.val()==null){
          newTeam=true
          newTeamCallback(newTeam,msg)
        }else{
          newTeam=false
          newTeamCallback(newTeam,msg,state)
          teamInfo = obj.val()
        }
      })
      // .then(function(){ // wait for database check for new users
      //   console.log('.then',newTeam)
      //   if(newTeam==true){

      //     msg.route('setup', state,30)
      //   }else if (newTeam==false){
      //     msg.route('main', state,30)
      //   }
      // })
  })

// slapp.action('jaywalk_callback', 'answer', (msg, value) => {

  .route('requestToDatabase', (msg, state) => {
    if(msg.body.actions==undefined){      // try callback then remove this
      msg.route('requestToDatabase', state, 30)
    }else{
      answer = msg.body.actions[0].value
      if(answer == 'app'){
        appDl(teamInfo,msg,state)
      }else if(answer == 'address'){
        yes(teamInfo,msg,state)
        //https://jaywalk-geo.herokuapp.com/geoloc.htm
        // .route('handleGeoLoc', state, 60)
      }else if(answer == 'settings'){
        teamSettings(teamInfo,msg,state)
      }else if(answer == 'notifications'){
        notify(teamInfo,msg,state)
      }else{ //handle error
        return msg
          .say("Whoops, you just have to pick a button...")
          .say('Click a button!')
          .route('requestToDatabase', state, 60)
      }
    } //end else(actions undefined checker)
  }) //end .route('requestToDatabase')
  // }) //end callback
  .route('main', (msg,state) => {
    msg
      .say(jayBtns)
      .route('requestToDatabase', state, 30)
  })//end .route(main)
  .route('setup', (msg,state) => {
    let teamObj={
      team_id: msg.body.team_id,
      team_name: msg.body.team_domain,
      location:"",
      lat:"",
      lng:"",
      slack_token: msg.body.token, //given at auth
      bot_token: "ahjsabjklsdbjkl",
      webhook: "msg.body.incoming_webhook", //given at auth
      channel_id: "msg.body.channel_id",
      channel_name: "msg.body.channel_name",}
    teamInfo.team_id = msg.body.team_id
    slackDb.child(msg.body.team_id).set(teamObj)
    msg.say({text:'setup mode goes here'})
  })//end .route(setup)
  .route('relaventAsk', (msg,state) => {
    msg.say({text: 'relaventAsk'})
    routeFuncs.relaventAsk(msg,state)
  })//end .route(relaventAsk)
  .route('address_geo', (msg,state) => {
    let text = (msg.body.event && msg.body.event.text) || ''
    where.is(text,function(err,result){
      /*
        result.get('')=>
        address,streetNumber, street,streetAddress,city,region,
        regionCode, postalCode, country, countryCode, lat, lng
      */
      if (result) {
        let lat = result.get('lat')
        let lng = result.get('lng')
        snapsByGeo(lat,lng,msg,state)
      }
    })
  })
}
module.exports = {
  jaywalk:jaywalk(),
  jayBtns:jayBtns
}

<commit_msg>route from callback<commit_after>'use strict'
const slapp = require('../slackSetup.js').slapp
const getRadius = require('../radius.js').getRadius
const tinyurl = require('tinyurl');
const request = require('request')
const where = require('node-where')

// route functions
const snapsByGeo = require('./routes/snapsByGeoRoute.js').snapsByGeo
const routeFuncs = require('./routes/routesIndex.js')
const yes = require('./routes/yes.js').yes
const addressToGeo = require('./routes/addressToGeo.js').addressToGeo
const appDl = require('./routes/appDlRoute.js').appDl
const teamSettings = require('../teamSettings.js').teamSettings

const notify = require('./notifySlash.js').notify

let newTeam = false

//db imports
const firebase    = require('../firebaseSetup.js'),
      db = firebase.db,
      snaps = firebase.snaps,
      tags = firebase.tags,
      users = firebase.users,
      slackDb = firebase.slackDb

let jayBtns={
  text: "",
  attachments: [{
    text: 'How can I help?',
    fallback: 'Where to today?',
    callback_id: 'jaywalk_callback',
    color: 'good',
    actions: [
      {
        name: 'answer',
        text: 'Find deals',
        type: 'button',
        value: 'address'
      },{
        name: 'answer',
        text: 'Settings',
        type: 'button',
        value: 'settings'
      },{
        name: 'answer',
        text: 'Download app',
        type: 'button',
        value: 'app'
      }
    ]
  }]
}

let newTeamCallback = (newOld,msg,state)=>{
  if(newTeam==true){
    msg.route('setup', state,30)
  }else if (newTeam==false){
    msg.route('main', state,30)
  }
}

 //text:`Welcom to Jaywalk! To get better results, please enter the address or your buisness name and city.`
const jaywalk = function() {
  let state = { requested: Date.now() }
  let teamId = ''
  let teamInfo = {}
  let answer

  slapp.command('/jaywalk', (msg, text) => {
    teamInfo = slackDb
      .child(msg.body.team_id)
      .once("value")
      .then(function(obj){
        if(obj.val()==null){
          newTeam=true
          newTeamCallback(newTeam,msg)
        }else{
          newTeam=false
          newTeamCallback(newTeam,msg,state)
          teamInfo = obj.val()
        }
      })
      // .then(function(){ // wait for database check for new users
      //   console.log('.then',newTeam)

      // })
  })

// slapp.action('jaywalk_callback', 'answer', (msg, value) => {

  .route('requestToDatabase', (msg, state) => {
    if(msg.body.actions==undefined){      // try callback then remove this
      msg.route('requestToDatabase', state, 30)
    }else{
      answer = msg.body.actions[0].value
      if(answer == 'app'){
        appDl(teamInfo,msg,state)
      }else if(answer == 'address'){
        yes(teamInfo,msg,state)
        //https://jaywalk-geo.herokuapp.com/geoloc.htm
        // .route('handleGeoLoc', state, 60)
      }else if(answer == 'settings'){
        teamSettings(teamInfo,msg,state)
      }else if(answer == 'notifications'){
        notify(teamInfo,msg,state)
      }else{ //handle error
        return msg
          .say("Whoops, you just have to pick a button...")
          .say('Click a button!')
          .route('requestToDatabase', state, 60)
      }
    } //end else(actions undefined checker)
  }) //end .route('requestToDatabase')
  // }) //end callback
  .route('main', (msg,state) => {
    msg
      .say(jayBtns)
      .route('requestToDatabase', state, 30)
  })//end .route(main)
  .route('setup', (msg,state) => {
    let teamObj={
      team_id: msg.body.team_id,
      team_name: msg.body.team_domain,
      location:"",
      lat:"",
      lng:"",
      slack_token: msg.body.token, //given at auth
      bot_token: "ahjsabjklsdbjkl",
      webhook: "msg.body.incoming_webhook", //given at auth
      channel_id: "msg.body.channel_id",
      channel_name: "msg.body.channel_name",}
    teamInfo.team_id = msg.body.team_id
    slackDb.child(msg.body.team_id).set(teamObj)
    msg.say({text:'setup mode goes here'})
  })//end .route(setup)
  .route('relaventAsk', (msg,state) => {
    msg.say({text: 'relaventAsk'})
    routeFuncs.relaventAsk(msg,state)
  })//end .route(relaventAsk)
  .route('address_geo', (msg,state) => {
    let text = (msg.body.event && msg.body.event.text) || ''
    where.is(text,function(err,result){
      /*
        result.get('')=>
        address,streetNumber, street,streetAddress,city,region,
        regionCode, postalCode, country, countryCode, lat, lng
      */
      if (result) {
        let lat = result.get('lat')
        let lng = result.get('lng')
        snapsByGeo(lat,lng,msg,state)
      }
    })
  })
}
module.exports = {
  jaywalk:jaywalk(),
  jayBtns:jayBtns
}

<|endoftext|>


<commit_before>'use strict'
const slapp = require('../slackSetup.js').slapp
const getRadius = require('../radius.js').getRadius
const tinyurl = require('tinyurl');
const request = require('request')
const where = require('node-where')

// route functions
const snapsByGeo = require('./routes/snapsByGeoRoute.js').snapsByGeo
const routeFuncs = require('./routes/routesIndex.js')
const yes = require('./routes/yes.js').yes
const addressToGeo = require('./routes/addressToGeo.js').addressToGeo
const appDl = require('./routes/appDlRoute.js').appDl
const teamSettings = require('../teamSettings.js').teamSettings

const notify = require('./notifySlash.js').notify

//db imports
const firebase    = require('../firebaseSetup.js'),
      db = firebase.db,
      snaps = firebase.snaps,
      tags = firebase.tags,
      users = firebase.users,
      slackDb = firebase.slackDb

let jayBtns={
  text: "",
  attachments: [{
    text: 'How can I help?',
    fallback: 'Where to today?',
    callback_id: 'jaywalk_callback',
    color: 'good',
    actions: [
      {
        name: 'answer',
        text: 'Find deals',
        type: 'button',
        value: 'address'
      },{
        name: 'answer',
        text: 'Settings',
        type: 'button',
        value: 'settings'
      },{
        name: 'answer',
        text: 'Download app',
        type: 'button',
        value: 'app'
      }
    ]
  }]
}
 //text:`Welcom to Jaywalk! To get better results, please enter the address or your buisness name and city.`
const jaywalk = function() {
  let state = { requested: Date.now() }
  let teamId = ''
  let teamInfo = {}
  let answer

  slapp.command('/jaywalk', (msg, text) => {
    teamInfo = slackDb
      .child(msg.body.team_id)
      .once("value")
      .then(function(obj){
        if(obj.val()==null){
          // console.log(msg)
          let teamObj={
            team_id: msg.body.team_id,
            team_name: msg.body.team_domain,
            location:"",
            lat:"",
            lng:"",
            slack_token: msg.body.token, //given at auth
            bot_token: "ahjsabjklsdbjkl",
            webhook: "msg.body.incoming_webhook", //given at auth
            channel_id: "msg.body.channel_id",
            channel_name: "msg.body.channel_name",}
          teamInfo.team_id = msg.body.team_id
          slackDb.child(msg.body.team_id).set(teamObj)
          return msg.route('relaventAsk', state,60)
          // return teamInfo
        }else{
          return teamInfo = obj.val()
        }
      })
    msg
      .say(jayBtns)
      .route('requestToDatabase', state, 60)
  })

// slapp.action('jaywalk_callback', 'answer', (msg, value) => {

  .route('requestToDatabase', (msg, state) => {
    if(msg.body.actions==undefined){      // try callback then remove this
      msg.route('requestToDatabase', state, 60)
    }else{
      answer = msg.body.actions[0].value
      if(answer == 'app'){
        appDl(teamInfo,msg,state)
      }else if(answer == 'address'){
        yes(teamInfo,msg,state)
        //https://jaywalk-geo.herokuapp.com/geoloc.htm
        // .route('handleGeoLoc', state, 60)
      }else if(answer == 'settings'){
        teamSettings(teamInfo,msg,state)
      }else if(answer == 'notifications'){
        notify(teamInfo,msg,state)
      }else{ //handle error
        return msg
          .say("Whoops, you just have to pick a button...")
          .say('Click a button!')
          .route('requestToDatabase', state, 60)
      }
    } //end else(actions undefined checker)
  }) //end .route('requestToDatabase')
  // }) //end callback
  .route('relaventAsk', (msg,state) => {
    msg.say({text: 'relaventAsk'})
    routeFuncs.relaventAsk(msg,state)
  })//end .route(relaventAsk)
  .route('address_geo', (msg,state) => {
    let text = (msg.body.event && msg.body.event.text) || ''
    where.is(text,function(err,result){
      /*
        result.get('')=>
        address,streetNumber, street,streetAddress,city,region,
        regionCode, postalCode, country, countryCode, lat, lng
      */
      if (result) {
        let lat = result.get('lat')
        let lng = result.get('lng')
        snapsByGeo(lat,lng,msg,state)
      }
    })
  })
}
module.exports = {
  jaywalk:jaywalk(),
  jayBtns:jayBtns
}

<commit_msg>routing<commit_after>'use strict'
const slapp = require('../slackSetup.js').slapp
const getRadius = require('../radius.js').getRadius
const tinyurl = require('tinyurl');
const request = require('request')
const where = require('node-where')

// route functions
const snapsByGeo = require('./routes/snapsByGeoRoute.js').snapsByGeo
const routeFuncs = require('./routes/routesIndex.js')
const yes = require('./routes/yes.js').yes
const addressToGeo = require('./routes/addressToGeo.js').addressToGeo
const appDl = require('./routes/appDlRoute.js').appDl
const teamSettings = require('../teamSettings.js').teamSettings

const notify = require('./notifySlash.js').notify

//db imports
const firebase    = require('../firebaseSetup.js'),
      db = firebase.db,
      snaps = firebase.snaps,
      tags = firebase.tags,
      users = firebase.users,
      slackDb = firebase.slackDb

let jayBtns={
  text: "",
  attachments: [{
    text: 'How can I help?',
    fallback: 'Where to today?',
    callback_id: 'jaywalk_callback',
    color: 'good',
    actions: [
      {
        name: 'answer',
        text: 'Find deals',
        type: 'button',
        value: 'address'
      },{
        name: 'answer',
        text: 'Settings',
        type: 'button',
        value: 'settings'
      },{
        name: 'answer',
        text: 'Download app',
        type: 'button',
        value: 'app'
      }
    ]
  }]
}
 //text:`Welcom to Jaywalk! To get better results, please enter the address or your buisness name and city.`
const jaywalk = function() {
  let state = { requested: Date.now() }
  let teamId = ''
  let teamInfo = {}
  let answer

  slapp.command('/jaywalk', (msg, text) => {
    teamInfo = slackDb
      .child(msg.body.team_id)
      .once("value")
      .then(function(obj){
        if(obj.val()==null){
          // console.log(msg)
          let teamObj={
            team_id: msg.body.team_id,
            team_name: msg.body.team_domain,
            location:"",
            lat:"",
            lng:"",
            slack_token: msg.body.token, //given at auth
            bot_token: "ahjsabjklsdbjkl",
            webhook: "msg.body.incoming_webhook", //given at auth
            channel_id: "msg.body.channel_id",
            channel_name: "msg.body.channel_name",}
          teamInfo.team_id = msg.body.team_id
          slackDb.child(msg.body.team_id).set(teamObj)
          return msg.route('relaventAsk', state,60)
          // return teamInfo
        }else{
          return teamInfo = obj.val()
        }
      })
    // msg
    //   .say(jayBtns)
    //   .route('requestToDatabase', state, 60)
  })

// slapp.action('jaywalk_callback', 'answer', (msg, value) => {

  .route('requestToDatabase', (msg, state) => {
    if(msg.body.actions==undefined){      // try callback then remove this
      msg.route('requestToDatabase', state, 60)
    }else{
      answer = msg.body.actions[0].value
      if(answer == 'app'){
        appDl(teamInfo,msg,state)
      }else if(answer == 'address'){
        yes(teamInfo,msg,state)
        //https://jaywalk-geo.herokuapp.com/geoloc.htm
        // .route('handleGeoLoc', state, 60)
      }else if(answer == 'settings'){
        teamSettings(teamInfo,msg,state)
      }else if(answer == 'notifications'){
        notify(teamInfo,msg,state)
      }else{ //handle error
        return msg
          .say("Whoops, you just have to pick a button...")
          .say('Click a button!')
          .route('requestToDatabase', state, 60)
      }
    } //end else(actions undefined checker)
  }) //end .route('requestToDatabase')
  // }) //end callback
  .route('relaventAsk', (msg,state) => {
    msg.say({text: 'relaventAsk'})
    routeFuncs.relaventAsk(msg,state)
  })//end .route(relaventAsk)
  .route('address_geo', (msg,state) => {
    let text = (msg.body.event && msg.body.event.text) || ''
    where.is(text,function(err,result){
      /*
        result.get('')=>
        address,streetNumber, street,streetAddress,city,region,
        regionCode, postalCode, country, countryCode, lat, lng
      */
      if (result) {
        let lat = result.get('lat')
        let lng = result.get('lng')
        snapsByGeo(lat,lng,msg,state)
      }
    })
  })
}
module.exports = {
  jaywalk:jaywalk(),
  jayBtns:jayBtns
}

<|endoftext|>


<commit_before><commit_msg>Rename variables<commit_after><|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name Key
 * @namespace
 */
var Key = this.Key = new function() {
	// TODO: Make sure the keys are called the same as in Scriptographer
	// Missing: tab, cancel, clear, page-down, page-up, comma, minus, period,
	// slash, etc etc etc.

	var keys = {
		8: 'backspace',
		13: 'enter',
		16: 'shift',
		17: 'control',
		18: 'option',
		19: 'pause',
		20: 'caps-lock',
		27: 'escape',
		32: 'space',
		35: 'end',
		36: 'home',
		37: 'left',
		38: 'up',
		39: 'right',
		40: 'down',
		46: 'delete',
		91: 'command',
		93: 'command', // WebKit right command button
		224: 'command'  // Gecko command button
	},

	// Use Base.merge to convert into a Base object, for #toString()
	modifiers = Base.merge({
		shift: false,
		control: false,
		option: false,
		command: false,
		capsLock: false
	}),

	// Since only keypress gets proper keyCodes that are actually representing
	// characters, we need to perform a little trickery here to use these codes
	// in onKeyDown/Up: keydown is used to store the downCode and handle
	// modifiers and special keys such as arrows, space, etc, keypress fires the
	// actual onKeyDown event and maps the keydown keyCode to the keypress
	// charCode so keyup can do the right thing too.
	charCodeMap = {}, // keyCode -> charCode mappings for pressed keys
	keyMap = {}, // Map for currently pressed keys
	downCode; // The last keyCode from keydown

	function handleKey(down, keyCode, charCode, event) {
		var character = String.fromCharCode(charCode),
			key = keys[keyCode] || character.toLowerCase(),
			type = down ? 'keydown' : 'keyup',
			view = View._focused,
			scope = view && view.isVisible() && view._scope,
			tool = scope && scope.tool;
		keyMap[key] = down;
		if (tool && tool.responds(type)) {
			// Call the onKeyDown or onKeyUp handler if present
			tool.fire(type, new KeyEvent(down, key, character, event));
			if (view)
				view.draw(true);
		}
	}

	DomEvent.add(document, {
		keydown: function(event) {
			var code = event.which || event.keyCode;
			// If the keyCode is in keys, it needs to be handled by keydown and
			// not in keypress after (arrows for example wont be triggering
			// a keypress, but space would).
			var key = keys[code], name;
			if (key) {
				// Detect modifiers and mark them as pressed
				if ((name = Base.camelize(key)) in modifiers)
					modifiers[name] = true;
				// No char code for special keys, but mark as pressed
				charCodeMap[code] = 0;
				handleKey(true, code, null, event);
				// Do not set downCode as we handled it already. Space would
				// be handled twice otherwise, once here, once in keypress.
			} else {
				downCode = code;
			}
		},

		keypress: function(event) {
			if (downCode != null) {
				var code = event.which || event.keyCode;
				// Link the downCode from keydown with the code form keypress,
				// so keyup can retrieve that code again.
				charCodeMap[downCode] = code;
				handleKey(true, downCode, code, event);
				downCode = null;
			}
		},

		keyup: function(event) {
			var code = event.which || event.keyCode,
				key = keys[code], name;
			// Detect modifiers and mark them as released
			if (key && (name = Base.camelize(key)) in modifiers)
				modifiers[name] = false;
			if (charCodeMap[code] != null) {
				handleKey(false, code, charCodeMap[code], event);
				delete charCodeMap[code];
			}
		}
	});

	return /** @lends Key */{
		modifiers: modifiers,

		/**
		 * Checks whether the specified key is pressed.
		 *
		 * @param {String} key One of: 'backspace', 'enter', 'shift', 'control',
		 * 'option', 'pause', 'caps-lock', 'escape', 'space', 'end', 'home',
		 * 'left', 'up', 'right', 'down', 'delete', 'command'
		 * @return {Boolean} {@true if the key is pressed}
		 *
		 * @example
		 * // Whenever the user clicks, create a circle shaped path. If the
		 * // 'a' key is pressed, fill it with red, otherwise fill it with blue:
		 * function onMouseDown(event) {
		 * 	var path = new Path.Circle(event.point, 10);
		 * 	if(Key.isDown('a')) {
		 * 		path.fillColor = 'red';
		 * 	} else {
		 * 		path.fillColor = 'blue';
		 * 	}
		 * }
		 */
		isDown: function(key) {
			return !!keyMap[key];
		}
	};
};<commit_msg>Fix white-space in code example.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

/**
 * @name Key
 * @namespace
 */
var Key = this.Key = new function() {
	// TODO: Make sure the keys are called the same as in Scriptographer
	// Missing: tab, cancel, clear, page-down, page-up, comma, minus, period,
	// slash, etc etc etc.

	var keys = {
		8: 'backspace',
		13: 'enter',
		16: 'shift',
		17: 'control',
		18: 'option',
		19: 'pause',
		20: 'caps-lock',
		27: 'escape',
		32: 'space',
		35: 'end',
		36: 'home',
		37: 'left',
		38: 'up',
		39: 'right',
		40: 'down',
		46: 'delete',
		91: 'command',
		93: 'command', // WebKit right command button
		224: 'command'  // Gecko command button
	},

	// Use Base.merge to convert into a Base object, for #toString()
	modifiers = Base.merge({
		shift: false,
		control: false,
		option: false,
		command: false,
		capsLock: false
	}),

	// Since only keypress gets proper keyCodes that are actually representing
	// characters, we need to perform a little trickery here to use these codes
	// in onKeyDown/Up: keydown is used to store the downCode and handle
	// modifiers and special keys such as arrows, space, etc, keypress fires the
	// actual onKeyDown event and maps the keydown keyCode to the keypress
	// charCode so keyup can do the right thing too.
	charCodeMap = {}, // keyCode -> charCode mappings for pressed keys
	keyMap = {}, // Map for currently pressed keys
	downCode; // The last keyCode from keydown

	function handleKey(down, keyCode, charCode, event) {
		var character = String.fromCharCode(charCode),
			key = keys[keyCode] || character.toLowerCase(),
			type = down ? 'keydown' : 'keyup',
			view = View._focused,
			scope = view && view.isVisible() && view._scope,
			tool = scope && scope.tool;
		keyMap[key] = down;
		if (tool && tool.responds(type)) {
			// Call the onKeyDown or onKeyUp handler if present
			tool.fire(type, new KeyEvent(down, key, character, event));
			if (view)
				view.draw(true);
		}
	}

	DomEvent.add(document, {
		keydown: function(event) {
			var code = event.which || event.keyCode;
			// If the keyCode is in keys, it needs to be handled by keydown and
			// not in keypress after (arrows for example wont be triggering
			// a keypress, but space would).
			var key = keys[code], name;
			if (key) {
				// Detect modifiers and mark them as pressed
				if ((name = Base.camelize(key)) in modifiers)
					modifiers[name] = true;
				// No char code for special keys, but mark as pressed
				charCodeMap[code] = 0;
				handleKey(true, code, null, event);
				// Do not set downCode as we handled it already. Space would
				// be handled twice otherwise, once here, once in keypress.
			} else {
				downCode = code;
			}
		},

		keypress: function(event) {
			if (downCode != null) {
				var code = event.which || event.keyCode;
				// Link the downCode from keydown with the code form keypress,
				// so keyup can retrieve that code again.
				charCodeMap[downCode] = code;
				handleKey(true, downCode, code, event);
				downCode = null;
			}
		},

		keyup: function(event) {
			var code = event.which || event.keyCode,
				key = keys[code], name;
			// Detect modifiers and mark them as released
			if (key && (name = Base.camelize(key)) in modifiers)
				modifiers[name] = false;
			if (charCodeMap[code] != null) {
				handleKey(false, code, charCodeMap[code], event);
				delete charCodeMap[code];
			}
		}
	});

	return /** @lends Key */{
		modifiers: modifiers,

		/**
		 * Checks whether the specified key is pressed.
		 *
		 * @param {String} key One of: 'backspace', 'enter', 'shift', 'control',
		 * 'option', 'pause', 'caps-lock', 'escape', 'space', 'end', 'home',
		 * 'left', 'up', 'right', 'down', 'delete', 'command'
		 * @return {Boolean} {@true if the key is pressed}
		 *
		 * @example
		 * // Whenever the user clicks, create a circle shaped path. If the
		 * // 'a' key is pressed, fill it with red, otherwise fill it with blue:
		 * function onMouseDown(event) {
		 * 	var path = new Path.Circle(event.point, 10);
		 * 	if (Key.isDown('a')) {
		 * 		path.fillColor = 'red';
		 * 	} else {
		 * 		path.fillColor = 'blue';
		 * 	}
		 * }
		 */
		isDown: function(key) {
			return !!keyMap[key];
		}
	};
};<|endoftext|>


<commit_before>import classNames from 'classnames'
import { html } from 'snabbdom-jsx'
import { div, button, li, ul, h2, span, section} from '@cycle/dom'
// import {merge} from 'most'
import * as most from 'most'
import xs from 'xstream'
const {of, merge, combine} = xs
import {domEvent, fromMost, toMost, makeStateAndReducers$, makeDefaultReducer, mergeReducers, imitateXstream} from '../utils/cycle'
import isolate from '@cycle/isolate'

import PrintSettings from './printSettings'
import MaterialSetup from './materialSetup'
import Viewer from './viewer'

import * as R from 'ramda'

import {actions as printSettingsActions} from './printSettings'

import {printerInfos} from '../utils/queries'
import {queryEndpoint} from '../core/umc'

// query printer for infos
// => get printhead & material infos
// => get transformation matrix of active object
// => upload file & start print
// => provide controls to pause/resume abort print

const init = makeDefaultReducer({})
const PrevStep = (state, input) => ({ ...state, currentStep: Math.max(state.currentStep - 1, 0) })
const NextStep = (state, input) => {
  const activePrinter = R.find(R.propEq('id', state.activePrinterId))(state.printers)
  if (activePrinter && activePrinter.hasOwnProperty('infos')) {
    return {...state, currentStep: Math.min(state.currentStep + 1, state.steps.length - 1)}
  }
  return state
}
const StartPrint = (state, input) => ({ ...state, printStatus: 'startRequested' })

const ClaimPrinter = (state, input) => {
  console.log('ClaimPrinter', input)
  const index = R.findIndex(R.propEq('id', state.activePrinterId))(state.printers)

  if (index !== -1) {
    const activePrinter = state.printers[index]
    const printers = R.update(index, {...activePrinter, claimed: input}, state.printers)
    state = { ...state, printers }
  }
  return state
}

const SelectPrinter = (state, input) => {
  console.log('SelectPrinter', input)
  // FIXME: activePrinter is a computed property how do we deal with it ?
  // const activePrinter = R.find(R.propEq('id', state.activePrinterId))(state.printers)
  state = { ...state, activePrinterId: input }
  console.log('state', state)
  return state
}

const SetPrinters = (state, input) => {
  console.log('SetPrinters', input)
  state = { ...state, printers: input }
  return state
}

const SetActivePrinterInfos = (state, input) => {
  console.log('SetActivePrinterInfos', input)
  const index = R.findIndex(R.propEq('id', state.activePrinterId))(state.printers)

  if (index !== -1) {
    const activePrinter = state.printers[index]
    const printers = R.update(index, {...activePrinter, infos: input}, state.printers)
    state = { ...state, printers }
  }
  return state
}

const actions = {
  init, PrevStep, NextStep, StartPrint,

  ClaimPrinter,
  SetPrinters,
  SetActivePrinterInfos,

  SelectPrinter

}

// our main view
const view = ([state, printSettings, materialSetup, viewer]) => {
  if (!state.hasOwnProperty('t')) return null // FIXME : bloody hack
  // console.log('state')
  const {steps, currentStep} = state

  const printers = ul('.printersList', state.printers
    .map(function (printer) {
      const isSelected = state.activePrinterId === printer.id
      const isClaimed = printer.claimed
      const classes = classNames({'.selected': isSelected, '.printerL': true})
      return li(classes, {attrs: {'data-id': printer.id}}, [printer.name, isClaimed ? span('.claimed', 'claimed') : button('.claim', {attrs: {'data-id': printer.id}}, 'claim')])
    })
  )
  const printerSetup = section('', [
    state.printers.length > 0 ? div('Select printer', [printers]) : span('please wait, fetching printers ...')
  ])

  const stepContents = [
    printerSetup,
    materialSetup,
    printSettings
  ]
  const activePrinter = R.find(R.propEq('id', state.activePrinterId))(state.printers)
  // console.log(activePrinter, state.activePrinter)
  const prevStepUi = currentStep > 0 ? button('.PrevStep', 'Previous step') : ''
  const nextStepUi = (currentStep < steps.length - 1 && activePrinter && activePrinter.infos) ? button('.NextStep', 'Next step') : ''
  const startPrintUi = currentStep === steps.length - 1 ? button('.StartPrint', 'Start Print') : ''

  //
{t('app_name')}

  return

      {viewer}

{steps[currentStep].name} {prevStepUi}{nextStepUi}{startPrintUi}

      {stepContents[currentStep]}

}

function App (sources) {
  const _domEvent = domEvent.bind(null, sources)
  const PrevStep$ = _domEvent('.PrevStep', 'click')
  const NextStep$ = _domEvent('.NextStep', 'click')
  const StartPrint$ = _domEvent('.StartPrint', 'click')

  // FIXME: switch to drivers

  const SetPrinters$ = most.merge(
    imitateXstream(_domEvent('.RefreshPrintersList', 'click')),
    most.of(null)
  ).flatMap(function (_) {
    const allPrinters$ = queryEndpoint('/printers').map(x => x.response)
      .map(printers => printers.map(printer => ({...printer, claimed: undefined})))
    const claimedPrinters$ = queryEndpoint('/printers/claimed').map(x => x.response)
      .map(printers => printers.map(printer => ({...printer, claimed: true})))

    return most.combineArray(function (claimedPrinters, allPrinters) {
      let printers = claimedPrinters
      function addItem (item) {
        const found = R.find(x => x.id === item.id && x.name === item.name)(printers)// R.propEq('id', item.id)
        if (found) {
          if (found.claimed === undefined) {
            found.claimed = false
          }
        } else {
          item.claimed = false
          printers.push(item)
        }
      }
      allPrinters.forEach(addItem)
      return printers
    }, [claimedPrinters$, allPrinters$])
  })

  // fetch data for the selectedprinter
  const SelectPrinter$ = _domEvent('.printerL', 'click').map(x => (x.currentTarget.dataset.id))

  function claimPrinter (id) {
    return queryEndpoint(`/printers/${id}/claim`, {method: 'POST'})
      .flatMapError(error => most.of({error: error}))// TODO: dispatch errors
  }

  const SetActivePrinterInfos$ = imitateXstream(SelectPrinter$)
    .flatMap(function (id) {
      const infos$ = queryEndpoint(`/printers/${id}/info`)// .flatMapError(error => most.of({error: error}))// TODO: dispatch errors
        .flatMapError(error => {
          /* if (error.error === 'client not authorized') {
          } */
          return most.of(undefined)
        })
      return infos$
      // const variant$ = queryEndpoint(`/printers/${id}/system/variant`)
    })
    .filter(x => x !== undefined)
    .map(x => x.response)

  const ClaimPrinter$ = imitateXstream(_domEvent('.claim', 'click')).map(x => (x.currentTarget.dataset.id))
    .flatMap(claimPrinter)
    .map(x => R.has('error'))

    /* .map(function(data){
      if('error' in data){
        if(data.error.error === 'client not authorized'){
          console.log('printer not claimed')
          return queryEndpoint(`/printers/${id}/claim`, {method: 'POST'})
            .flatMapError(error => most.of({error: error}))// TODO: dispatch errors
        }
        console.log('error', data)
      }
      return data
      //.filter(x => x != undefined)
      //.map(x => x.response)
    })
    .map(function(foo){
      console.log('here', foo)
      return foo
    }) */

  /* const SetCameraImage$ = toMost(SelectPrinter$)
    .flatMap(function(id){
      return queryEndpoint(`/printers/${id}/camera`,{'Content-Type': 'image/jpeg'}).map(x => x.response)
    })
    .forEach(function(data){
      console.log('got image')
      console.log(data)
    }) */
    // .forEach(x=>console.log('printerInfos',x))

    // .tap(x=>console.log('printerInfos',x))

  // FIXME: temp workarounds
  const SetQualityPreset$ = _domEvent('.SetQualityPreset', 'click').map(x => (x.currentTarget.dataset.index))
  const ToggleBrim$ = _domEvent('.ToggleBrim', 'click').map(x => x.target.value)
  const ToggleSupport$ = _domEvent('.ToggleSupport', 'click').map(x => x.target.value)

  const actions$ = {
    PrevStep$,
    NextStep$,
    StartPrint$,

    ClaimPrinter$: fromMost(ClaimPrinter$),
    SetPrinters$: fromMost(SetPrinters$),
    SetActivePrinterInfos$: fromMost(SetActivePrinterInfos$),

    SelectPrinter$,

    SetQualityPreset$,
    ToggleBrim$,
    ToggleSupport$
  }

  toMost(StartPrint$).forEach(x => console.log('StartPrint'))

  const {state$, reducer$} = makeStateAndReducers$(actions$, {...actions, ...printSettings}, sources)

  // sub components
  const printSettings = PrintSettings(sources)
  const materialSetup = MaterialSetup(sources)
  const viewer = isolate(Viewer, 'viewer')(sources)

  const _reducer$ = merge(reducer$, ...[viewer].map(x => x.onion))

  const vdom$ = xs.combine(state$, printSettings.DOM, materialSetup.DOM, viewer.DOM)
    .map((items) => view(items))

  return {
    DOM: vdom$,
    onion: _reducer$
  }
}

export default App
<commit_msg>feat(unclaim): added basics for unclaiming printers: - moved out claim/unclaim helpers - modified ui to add buttons for unclaiming<commit_after>import classNames from 'classnames'
import { html } from 'snabbdom-jsx'
import { div, button, li, ul, h2, span, section} from '@cycle/dom'
// import {merge} from 'most'
import * as most from 'most'
import xs from 'xstream'
const {of, merge, combine} = xs
import {domEvent, fromMost, toMost, makeStateAndReducers$, makeDefaultReducer, mergeReducers, imitateXstream} from '../utils/cycle'
import isolate from '@cycle/isolate'

import PrintSettings from './printSettings'
import MaterialSetup from './materialSetup'
import MonitorPrint from './monitorPrint'
import Viewer from './viewer'

import * as R from 'ramda'

import {actions as printSettingsActions} from './printSettings'

import {printerInfos} from '../utils/queries'
import {queryEndpoint, claimPrinter, unclaimPrinter} from '../core/umc'

// query printer for infos
// => get printhead & material infos
// => get transformation matrix of active object
// => upload file & start print
// => provide controls to pause/resume abort print

const init = makeDefaultReducer({})
const PrevStep = (state, input) => ({ ...state, currentStep: Math.max(state.currentStep - 1, 0) })
const NextStep = (state, input) => {
  const activePrinter = R.find(R.propEq('id', state.activePrinterId))(state.printers)
  if (activePrinter && activePrinter.hasOwnProperty('infos')) {
    return {...state, currentStep: Math.min(state.currentStep + 1, state.steps.length - 1)}
  }
  return state
}
const StartPrint = (state, input) => ({ ...state, printStatus: 'startRequested' })

const ClaimPrinter = (state, input) => {
  console.log('ClaimPrinter', input)
  const index = R.findIndex(R.propEq('id', state.activePrinterId))(state.printers)

  if (index !== -1) {
    const activePrinter = state.printers[index]
    const printers = R.update(index, {...activePrinter, claimed: input}, state.printers)
    state = { ...state, printers }
  }
  return state
}

const SelectPrinter = (state, input) => {
  console.log('SelectPrinter', input)
  // FIXME: activePrinter is a computed property how do we deal with it ?
  // const activePrinter = R.find(R.propEq('id', state.activePrinterId))(state.printers)
  state = { ...state, activePrinterId: input }
  console.log('state', state)
  return state
}

const SetPrinters = (state, input) => {
  console.log('SetPrinters', input)
  state = { ...state, printers: input }
  return state
}

const SetActivePrinterInfos = (state, input) => {
  console.log('SetActivePrinterInfos', input)
  const index = R.findIndex(R.propEq('id', state.activePrinterId))(state.printers)

  if (index !== -1) {
    const activePrinter = state.printers[index]
    const printers = R.update(index, {...activePrinter, infos: input}, state.printers)
    state = { ...state, printers }
  }
  return state
}

const actions = {
  init, PrevStep, NextStep, StartPrint,

  ClaimPrinter,
  SetPrinters,
  SetActivePrinterInfos,

  SelectPrinter

}

// our main view
const view = ([state, printSettings, materialSetup, viewer, monitorPrint]) => {
  if (!state.hasOwnProperty('t')) return null // FIXME : bloody hack
  // console.log('state')
  const {steps, currentStep} = state

  const printers = ul('.printersList', state.printers
    .map(function (printer) {
      const isSelected = state.activePrinterId === printer.id
      const isClaimed = printer.claimed
      const classes = classNames({'.selected': isSelected, '.printerL': true})
      return li(classes, {attrs: {'data-id': printer.id}}, [
        printer.name, isClaimed ?
          button('.unClaim .claimed', {attrs: {'data-id': printer.id}}, 'unClaim') :
          button('.claim', {attrs: {'data-id': printer.id}}, 'claim')
      ])
    })
  )
  const printerSetup = section('', [
    state.printers.length > 0 ? div('Select printer', [printers]) : span('please wait, fetching printers ...')
  ])

  const stepContents = [
    printerSetup,
    materialSetup,
    printSettings,
    monitorPrint
  ]
  const activePrinter = R.find(R.propEq('id', state.activePrinterId))(state.printers)
  // console.log(activePrinter, state.activePrinter)
  const prevStepUi = currentStep > 0 ? button('.PrevStep', 'Previous step') : ''
  const nextStepUi = (currentStep < steps.length - 1 && activePrinter && activePrinter.infos) ? button('.NextStep', 'Next step') : ''
  const startPrintUi = currentStep === steps.length - 1 ? button('.StartPrint', 'Start Print') : ''

  //
{t('app_name')}

  return

      {viewer}

{steps[currentStep].name} {prevStepUi}{nextStepUi}{startPrintUi}

      {stepContents[currentStep]}

}

function App (sources) {
  const _domEvent = domEvent.bind(null, sources)
  const PrevStep$ = _domEvent('.PrevStep', 'click')
  const NextStep$ = _domEvent('.NextStep', 'click')
  const StartPrint$ = _domEvent('.StartPrint', 'click')

  // FIXME: switch to drivers

  const SetPrinters$ = most.merge(
    imitateXstream(_domEvent('.RefreshPrintersList', 'click')),
    most.of(null)
  ).flatMap(function (_) {
    const allPrinters$ = queryEndpoint('/printers').map(x => x.response)
      .map(printers => printers.map(printer => ({...printer, claimed: undefined})))
    const claimedPrinters$ = queryEndpoint('/printers/claimed').map(x => x.response)
      .map(printers => printers.map(printer => ({...printer, claimed: true})))

    return most.combineArray(function (claimedPrinters, allPrinters) {
      let printers = claimedPrinters
      function addItem (item) {
        const found = R.find(x => x.id === item.id && x.name === item.name)(printers)// R.propEq('id', item.id)
        if (found) {
          if (found.claimed === undefined) {
            found.claimed = false
          }
        } else {
          item.claimed = false
          printers.push(item)
        }
      }
      allPrinters.forEach(addItem)
      return printers
    }, [claimedPrinters$, allPrinters$])
  })

  // fetch data for the selectedprinter
  const SelectPrinter$ = _domEvent('.printerL', 'click').map(x => (x.currentTarget.dataset.id))

  const SetActivePrinterInfos$ = imitateXstream(SelectPrinter$)
    /* .combine(function(id, state){
      const activePrinter = R.findIndex(R.propEq('id', id))(state.printers)
      if(activePrinter && activePrinter.claimed){
        return id
      }
      return undefined
    },state$)
    .filter(x=>x!== undefined) */
    .flatMap(function (id) {
      const infos$ = queryEndpoint(`/printers/${id}/info`)// .flatMapError(error => most.of({error: error}))// TODO: dispatch errors
        .flatMapError(error => {
          /* if (error.error === 'client not authorized') {
          } */
          return most.of(undefined)
        })
      return infos$
      // const variant$ = queryEndpoint(`/printers/${id}/system/variant`)
    })
    .filter(x => x !== undefined)
    .map(x => x.response)

  const ClaimPrinter$ = imitateXstream(_domEvent('.claim', 'click')).map(x => (x.currentTarget.dataset.id))
    .flatMap(claimPrinter)
    .map(!R.has('error'))

  const UnClaimPrinter$ = imitateXstream(_domEvent('.unClaim', 'click')).map(x => (x.currentTarget.dataset.id))
    .flatMap(unclaimPrinter)
    .map(R.has('error'))

    /* .map(function(data){
      if('error' in data){
        if(data.error.error === 'client not authorized'){
          console.log('printer not claimed')
          return queryEndpoint(`/printers/${id}/claim`, {method: 'POST'})
            .flatMapError(error => most.of({error: error}))// TODO: dispatch errors
        }
        console.log('error', data)
      }
      return data
      //.filter(x => x != undefined)
      //.map(x => x.response)
    })
    .map(function(foo){
      console.log('here', foo)
      return foo
    }) */

  /* const SetCameraImage$ = toMost(SelectPrinter$)
    .flatMap(function(id){
      return queryEndpoint(`/printers/${id}/camera`,{'Content-Type': 'image/jpeg'}).map(x => x.response)
    })
    .forEach(function(data){
      console.log('got image')
      console.log(data)
    }) */
    // .forEach(x=>console.log('printerInfos',x))

    // .tap(x=>console.log('printerInfos',x))

  // FIXME: temp workarounds
  const SetQualityPreset$ = _domEvent('.SetQualityPreset', 'click').map(x => (x.currentTarget.dataset.index))
  const ToggleBrim$ = _domEvent('.ToggleBrim', 'click').map(x => x.target.value)
  const ToggleSupport$ = _domEvent('.ToggleSupport', 'click').map(x => x.target.value)

  const actions$ = {
    PrevStep$,
    NextStep$,
    StartPrint$,

    ClaimPrinter$: fromMost(ClaimPrinter$),
    UnClaimPrinter$: fromMost(UnClaimPrinter$),
    SetPrinters$: fromMost(SetPrinters$),
    SetActivePrinterInfos$: fromMost(SetActivePrinterInfos$),

    SelectPrinter$,

    // print setting actions
    SetQualityPreset$,
    ToggleBrim$,
    ToggleSupport$
  }

  toMost(StartPrint$).forEach(x => console.log('StartPrint'))

  const {state$, reducer$} = makeStateAndReducers$(actions$, {...actions, ...printSettings}, sources)

  // sub components
  const printSettings = PrintSettings(sources)
  const materialSetup = MaterialSetup(sources)
  const viewer = isolate(Viewer, 'viewer')(sources)
  const monitorPrint = MonitorPrint(sources)

  const _reducer$ = merge(reducer$, ...[viewer].map(x => x.onion))

  const vdom$ = xs.combine(state$, printSettings.DOM, materialSetup.DOM, viewer.DOM, monitorPrint.DOM)
    .map((items) => view(items))

  return {
    DOM: vdom$,
    onion: _reducer$
  }
}

export default App
<|endoftext|>


<commit_before><commit_msg>use webkit transform instead<commit_after><|endoftext|>