<commit_before>/*
 * Copyright 2014 WebFilings, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define(function(require) {
    'use strict';

    var requestAnimFrame = require('wf-js-common/requestAnimationFrame');

    /**
     * Creates a new ScrollBar with the given ScrollList and options.
     *
     * @classdesc
     *
     * A ScrollBar provides a UI based on the traditional browser scrollbar
     * for users to scroll the ScrollList.
     *
     * @name ScrollBar
     * @constructor
     *
     * @param {ScrollList} scrollList
     *        The ScrollList that the ScrollBar is constructed for
     *
     * @param {HTMLElement} parent
     *        The parent element for the ScrollBar to be created within
     *
     * @param {Object} options
     *        An object with optional classes and ids to be placed on the
     *        scrollbarEL and scrollbarContainerEL.
     *
     */

    var ScrollBar = function (scrollList, parent, options) {
        var offset;
        var that = this;

        // Set the scrollList
        if (scrollList === undefined) {
            throw new Error('ScrollBar#ScrollBar: scrollList is required');
        }
        else {
            this._scrollList = scrollList;
        }

        // Set the parent
        if (parent === undefined) {
            throw new Error('ScrollBar#ScrollBar: parent is required.');
        }
        else {
            this._parent = parent;
        }

        // Set the options
        this._options = options;

        // Set the layout
        this._layout = scrollList.getLayout();

        // Set the number of items
        this._TOTAL_ITEMS = scrollList._items.length;

        // Set the viewportHeight
        this._viewportHeight = this._layout.getViewportSize().height;

        // Set the virtualHeight
        this._virtualHeight = this._layout.getSize().height;

        // Set up the DOM and set the scrollbar and scrollbarContainer elements
        this._elements = this.setUpDOM();

        // Set the average object height
        this._avgObjHeight = this._virtualHeight/this._TOTAL_ITEMS;

        // Set scrollbarScrolling to initially false
        this._scrollbarScrolling = false;

        // Set clickOffset to null
        this._clickOffset = null;

        // Set the initial scale
        this._scale = this._scrollList._scaleTranslator._map.getCurrentTransformState().scale;

        // Set the effective viewport.
        // This is an expression of a relatioinship between the height of the viewport
        // and the height of the document that you see through the viewport
        this._effectiveViewport = this._viewportHeight * (1 / this._scale);

        // Set the effective virtual height.
        this._effectiveVirtualHeight = this._virtualHeight * (1 / this._scale);

        // Set the initial scrollbar height
        this._scrollbarHeight = this.calculateScrollBarHeight(that);

        // Get the initial position, in case it's not at 0, and set the scrollbar position and page number
        requestAnimFrame(function() {
            that.placeScrollBar(that, that._elements.scrollbar);
        });

        // Match the scroll bar positioning to the users scrolling
        this._scrollList.getListMap().onTranslationChanged(function() {
            if (that._scrollbarScrolling) {
                return;
            }
            requestAnimFrame(function() {
                that.placeScrollBar(that, that._elements.scrollbar);
            });
        });

        // Make necessary adjustments when the users zooms in or out
        this._scrollList.getListMap().onScaleChanged(function() {
            that._scale = that._scrollList._scaleTranslator._map.getCurrentTransformState().scale;
            that._effectiveVirtualHeight = that._layout.getSize().height * that._scale;
            that._effectiveViewport = that._viewportHeight * (1 / that._scale);
            that._scrollbarHeight = that.calculateScrollBarHeight(that);
            that._elements.scrollbar.style.height = that._scrollbarHeight + 'px';
            that._effectiveViewport = that._viewportHeight * (1 / that._scrollList._scaleTranslator._map.getCurrentTransformState().scale);
        });

        // Attach handlers for scrolling the ScrollBar
        this._elements.scrollbar.addEventListener('mousedown', function(event) {
            offset = that._elements.scrollbar.offsetTop + that._elements.scrollbarContainer.offsetTop;
            that._clickOffset = event.clientY - offset + that._elements.scrollbarContainer.offsetTop;
            that._scrollbarScrolling = true;

            that._mouseupHandler = function () {
                that.stopUpdatingScrollbar(that);
            };

            that._mousemoveHandler = function (e) {
                that.updateScrollBar(e, that, that._clickOffset);
            };

            document.addEventListener('mousemove', that._mousemoveHandler);

            document.addEventListener('mouseup', that._mouseupHandler);
        });

    };

    ScrollBar.prototype = {
        setUpDOM: function () {
            // Create the scrollbar's container
            var scrollbarContainerEL = document.createElement('div');
            var scrollbarEL = document.createElement('div');

            // Set the given classes and ids scrollbar and it's container
            if ( this._options.scrollbarId ) {
                scrollbarEL.setAttribute('id', this._options.scrollbarId);
            }
            if ( this._options.scrollbarClass ) {
                scrollbarEL.classNames += this._options.scrollbarClass;
            }
            if ( this._options.scrollbarContainerId ) {
                scrollbarContainerEL.setAttribute('id', this._options.scrollbarContainerId);
            }
            if ( this._options.scrollbarContainerClass) {
                scrollbarContainerEL.classnames += this._options.scrollbarContainerClass;
            }

            // Append the scrollbar and it's parent container to the given parent element
            scrollbarContainerEL.appendChild(scrollbarEL);
            this._parent.appendChild(scrollbarContainerEL);

            // Set the container height to the viewport height
            scrollbarContainerEL.style.height = this._viewportHeight + 'px';
            // Set the scrollbar height
            scrollbarEL.style.height = this._scrollbarHeight + 'px';

            return {scrollbar: scrollbarEL, scrollbarContainer: scrollbarContainerEL};
        },

        // Position the scrollbar based on the current position of the ScrollList
        placeScrollBar: function (that) {
            var currentPosition = that._layout.getVisiblePosition().top;
            var availableScrollbarHeight = that._viewportHeight - that._scrollbarHeight;
            var scrollableVirtualHeight = that._virtualHeight - that._effectiveViewport;
            var translatedPosition = availableScrollbarHeight / scrollableVirtualHeight * currentPosition;
            that._elements.scrollbar.style.top = translatedPosition + 'px';
        },

        updateScrollBar: function (event, that, clickOffset) {
            // Don't go past the window bounds
            var scrollbarPos = Math.max(0, event.clientY - clickOffset);
            scrollbarPos = Math.min(scrollbarPos, that._viewportHeight - that._scrollbarHeight);
            that._elements.scrollbar.style.top = scrollbarPos + 'px';
            var offset = (that._viewportHeight/that._avgObjHeight)/2;

            // Use the ratio of scrollbar position inside the scrolling area to calculate
            // the current item we should be interested in.
            var positionOfInterest = ((scrollbarPos) / (that._viewportHeight - that._scrollbarHeight)) * (that._virtualHeight);

            // Ensure that positionOfInterest isn't undefined.
            if (!positionOfInterest) {
                positionOfInterest = 0;
            }
            console.log(positionOfInterest);
            that._scrollList.scrollToPosition({
                y: positionOfInterest
            });
        },

        stopUpdatingScrollbar: function (that) {
            that._clickOffset = undefined;
            document.removeEventListener('mousemove', that._mousemoveHandler);
            that._scrollbarScrolling = false;
            that.removeDocumentEventWatching(that);
        },

        removeDocumentEventWatching: function (that) {
            document.removeEventListener('mouseup', that._mouseupHandler);
        },

        calculateScrollBarHeight: function (that) {
            // Calculate the size of the scrollbar depending on the virtual height
            // The scrollbar shouldn't be shorter than MIN_HEIGHT
            var MIN_HEIGHT = 16;
            var height =  Math.max(MIN_HEIGHT, (that._effectiveViewport / that._effectiveVirtualHeight) * that._effectiveViewport);
            return height;
        }
    };

    return ScrollBar;

});
<commit_msg>Update placeScrollBar function to more accurately asses the height of the effective viewport when the scale doesn't equal 1<commit_after>/*
 * Copyright 2014 WebFilings, LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define(function(require) {
    'use strict';

    var requestAnimFrame = require('wf-js-common/requestAnimationFrame');

    /**
     * Creates a new ScrollBar with the given ScrollList and options.
     *
     * @classdesc
     *
     * A ScrollBar provides a UI based on the traditional browser scrollbar
     * for users to scroll the ScrollList.
     *
     * @name ScrollBar
     * @constructor
     *
     * @param {ScrollList} scrollList
     *        The ScrollList that the ScrollBar is constructed for
     *
     * @param {HTMLElement} parent
     *        The parent element for the ScrollBar to be created within
     *
     * @param {Object} options
     *        An object with optional classes and ids to be placed on the
     *        scrollbarEL and scrollbarContainerEL.
     *
     * @param {number} options.min_height
     *        The minimum height, in pixes, of the ScrollBar
     *        If not provided, the min_height will default to 16px
     *
     */

    var ScrollBar = function (scrollList, parent, options) {
        var offset;
        var that = this;

        // Set the scrollList
        if (scrollList === undefined) {
            throw new Error('ScrollBar#ScrollBar: scrollList is required');
        }
        else {
            this._scrollList = scrollList;
        }

        // Set the parent
        if (parent === undefined) {
            throw new Error('ScrollBar#ScrollBar: parent is required.');
        }
        else {
            this._parent = parent;
        }

        // Set the options
        this._options = options;

        // Set the layout
        this._layout = scrollList.getLayout();

        // Set the number of items
        this._TOTAL_ITEMS = scrollList._items.length;

        // Set the viewportHeight
        this._viewportHeight = this._layout.getViewportSize().height;

        // Set the virtualHeight
        this._virtualHeight = this._layout.getSize().height;

        // Set up the DOM and set the scrollbar and scrollbarContainer elements
        this._elements = this.setUpDOM();

        // Set the average object height
        this._avgObjHeight = this._virtualHeight/this._TOTAL_ITEMS;

        // Set scrollbarScrolling to initially false
        this._scrollbarScrolling = false;

        // Set clickOffset to null
        this._clickOffset = null;

        // Set the initial scale
        this._scale = this._scrollList._scaleTranslator._map.getCurrentTransformState().scale;

        // Set the effective virtual height.
        this._effectiveVirtualHeight = this._virtualHeight * (1 / this._scale);

        // Set the initial scrollbar height
        this._scrollbarHeight = this.calculateScrollBarHeight(that);

        // Get the initial position, in case it's not at 0, and set the scrollbar position and page number
        requestAnimFrame(function() {
            that.placeScrollBar(that, that._elements.scrollbar);
        });

        // Match the scroll bar positioning to the users scrolling
        this._scrollList.getListMap().onTranslationChanged(function() {
            if (that._scrollbarScrolling) {
                return;
            }
            requestAnimFrame(function() {
                that.placeScrollBar(that, that._elements.scrollbar);
            });
        });

        // Make necessary adjustments when the users zooms in or out
        this._scrollList.getListMap().onScaleChanged(function() {
            that._scale = that._scrollList._scaleTranslator._map.getCurrentTransformState().scale;
            that._effectiveVirtualHeight = that._layout.getSize().height * that._scale;
            that._scrollbarHeight = that.calculateScrollBarHeight(that);
            that._elements.scrollbar.style.height = that._scrollbarHeight + 'px';
        });

        // Attach handlers for scrolling the ScrollBar
        this._elements.scrollbar.addEventListener('mousedown', function(event) {
            offset = that._elements.scrollbar.offsetTop + that._elements.scrollbarContainer.offsetTop;
            that._clickOffset = event.clientY - offset + that._elements.scrollbarContainer.offsetTop;
            that._scrollbarScrolling = true;

            that._mouseupHandler = function () {
                that.stopUpdatingScrollbar(that);
            };

            that._mousemoveHandler = function (e) {
                that.updateScrollBar(e, that, that._clickOffset);
            };

            document.addEventListener('mousemove', that._mousemoveHandler);

            document.addEventListener('mouseup', that._mouseupHandler);
        });

    };

    ScrollBar.prototype = {
        setUpDOM: function () {
            // Create the scrollbar's container
            var scrollbarContainerEL = document.createElement('div');
            var scrollbarEL = document.createElement('div');

            // Set the given classes and ids scrollbar and it's container
            if ( this._options.scrollbarId ) {
                scrollbarEL.setAttribute('id', this._options.scrollbarId);
            }
            if ( this._options.scrollbarClass ) {
                scrollbarEL.classNames += this._options.scrollbarClass;
            }
            if ( this._options.scrollbarContainerId ) {
                scrollbarContainerEL.setAttribute('id', this._options.scrollbarContainerId);
            }
            if ( this._options.scrollbarContainerClass) {
                scrollbarContainerEL.classnames += this._options.scrollbarContainerClass;
            }

            // Append the scrollbar and it's parent container to the given parent element
            scrollbarContainerEL.appendChild(scrollbarEL);
            this._parent.appendChild(scrollbarContainerEL);

            // Set the container height to the viewport height
            scrollbarContainerEL.style.height = this._viewportHeight + 'px';
            // Set the scrollbar height
            scrollbarEL.style.height = this._scrollbarHeight + 'px';

            return {scrollbar: scrollbarEL, scrollbarContainer: scrollbarContainerEL};
        },

        // Position the scrollbar based on the current position of the ScrollList
        placeScrollBar: function (that) {
            var currentPosition = that._layout.getVisiblePosition().top;
            var availableScrollbarHeight = that._viewportHeight - that._scrollbarHeight;
            var scrollableVirtualHeight = that._virtualHeight - (that._layout.getVisiblePosition().bottom - that._layout.getVisiblePosition().top);
            var translatedPosition = availableScrollbarHeight / scrollableVirtualHeight * currentPosition;
            that._elements.scrollbar.style.top = translatedPosition + 'px';
        },

        updateScrollBar: function (event, that, clickOffset) {
            // Don't go past the window bounds
            var scrollbarPos = Math.max(0, event.clientY - clickOffset);
            scrollbarPos = Math.min(scrollbarPos, that._viewportHeight - that._scrollbarHeight);
            that._elements.scrollbar.style.top = scrollbarPos + 'px';
            var offset = (that._viewportHeight/that._avgObjHeight)/2;

            // Use the ratio of scrollbar position inside the scrolling area to calculate
            // the current item we should be interested in.
            var positionOfInterest = ((scrollbarPos) / (that._viewportHeight - that._scrollbarHeight)) * (that._virtualHeight);

            // Ensure that positionOfInterest isn't undefined.
            if (!positionOfInterest) {
                positionOfInterest = 0;
            }

            that._scrollList.scrollToPosition({
                y: positionOfInterest
            });
        },

        stopUpdatingScrollbar: function (that) {
            that._clickOffset = undefined;
            document.removeEventListener('mousemove', that._mousemoveHandler);
            that._scrollbarScrolling = false;
            that.removeDocumentEventWatching(that);
        },

        removeDocumentEventWatching: function (that) {
            document.removeEventListener('mouseup', that._mouseupHandler);
        },

        calculateScrollBarHeight: function (that) {
            // Calculate the size of the scrollbar depending on the virtual height
            // The scrollbar shouldn't be shorter than MIN_HEIGHT
            var MIN_HEIGHT = that._options.min_height || 16;
            var height =  Math.max(MIN_HEIGHT, (that._viewportHeight / that._effectiveVirtualHeight) * that._viewportHeight);
            return height;
        }
    };

    return ScrollBar;

});
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React, { Fragment } from 'react';
import AUtextInput from '@gov.au/text-inputs';

/**
 * The Search Results component
 *
 * @disable-docs
 */
const SearchResults = ( page ) => {

	return (

{ page.heading }

 results for [query]

								<form className="search__searchbox" role="search" autoComplete="off" action="/search" method="get">
									<input type="search" className="au-text-input round--left" name="q" id="search-input" placeholder="Digital Guides"/>
									<button type="submit" className="au-btn icon icon--search--dark round--right" id="search-btn">Search</button>
								</form>

	);
}

SearchResults.propTypes = {
	/**
	 * _body: (partials)(4)
	 */
	_body: PropTypes.node.isRequired,
};

SearchResults.defaultProps = {};

export default SearchResults;
<commit_msg>Add new span for displaying search query<commit_after>import PropTypes from 'prop-types';
import React, { Fragment } from 'react';
import AUtextInput from '@gov.au/text-inputs';

/**
 * The Search Results component
 *
 * @disable-docs
 */
const SearchResults = ( page ) => {

	return (

{ page.heading }

 results for

								<form className="search__searchbox" role="search" autoComplete="off" action="/search" method="get">
									<input type="search" className="au-text-input round--left" name="q" id="search-input" placeholder="Digital Guides"/>
									<button type="submit" className="au-btn icon icon--search--dark round--right" id="search-btn">Search</button>
								</form>

	);
}

SearchResults.propTypes = {
	/**
	 * _body: (partials)(4)
	 */
	_body: PropTypes.node.isRequired,
};

SearchResults.defaultProps = {};

export default SearchResults;
<|endoftext|>


<commit_before>import { Component, EventEmitter, ElementRef, Optional } from '@angular/core'; //eslint-disable-line
import { CORE_DIRECTIVES, NgControl, NgModel } from '@angular/common';

@Component({
    selector: 'novo-tiles',
    inputs: [
        'name',
        'options',
        'required'
    ],
    outputs: [
        'changed'
    ],
    directives: [
        CORE_DIRECTIVES
    ],
    template: `

                    {{ option.label || option}}

                <input [hidden]="true" [name]="name" type="radio" [value]="option.checked || option" [attr.id]="name + i">

    `
})
export class Tiles {
    validators:Array = [];
    _options:Array = [];
    value:any = null;
    activeTile:any = null;
    changed:EventEmitter = new EventEmitter;

    constructor(@Optional() model:NgControl, element:ElementRef) {
        this.element = element;
        this.model = model || new NgModel();
        this.model.valueAccessor = this;
    }

    ngOnInit() {
        this.name = this.name || '';

        if (this.control) {
            this.control.updateValue(this.value);
        }
        if (this.options && this.options.length && !this.options[0].value) {
            this._options = this.options.map((x) => {
                let item = { value: x, label: x, checked: this.value === x };
                return item;
            });
        } else {
            this._options = this.options.map((x) => {
                x.checked = this.value === x.value;
                if (x.checked) {
                    this.setTile(x);
                }
                return x;
            });
        }
    }

	/**
     * @name select
     *
     * @param event
     * @param item
     */
    select(event, item) {
        if (event) {
            event.stopPropagation();
            event.preventDefault();
        }
        for (let option of this._options) {
            option.checked = false;
        }
        item.checked = !item.checked;
        this.changed.emit(item.value);
        this.model.viewToModelUpdate(item.value);
        this.setTile(item);
    }

    setTile(item) {
        if (item) {
            this.activeTile = item.value;
            this.moveTile();
        }
    }

    moveTile() {
        setTimeout(() => {
            let ind = this.element.nativeElement.querySelector('.active-indicator');
            let el = this.element.nativeElement.querySelector('.tile.active');
            let w = el.clientWidth;
            let left = el.offsetLeft;

            // These style adjustments need to occur in this order. TODO: Remove this and use ngAnimate2 - @asibilia
            setTimeout(() => {
                ind.style.width = `${w + 4}px`;
                setTimeout(() => {
                    ind.style.transform = `translateX(${left}px)`;
                    setTimeout(() => {
                        ind.style.opacity = '1';
                    });
                });
            });
        });
    }

    // ValueAccessor Functions
    writeValue(value) {
        this.value = value;
    }

    registerOnChange(fn) {
        this.onChange = fn;
    }

    registerOnTouched(fn) {
        this.onTouched = fn;
    }
}

export const NOVO_TILES_ELEMENTS = [Tiles];
<commit_msg>fix(tiles): fix for no defaults (#114)<commit_after>import { Component, EventEmitter, ElementRef, Optional } from '@angular/core'; //eslint-disable-line
import { CORE_DIRECTIVES, NgControl, NgModel } from '@angular/common';

@Component({
    selector: 'novo-tiles',
    inputs: [
        'name',
        'options',
        'required'
    ],
    outputs: [
        'changed'
    ],
    directives: [
        CORE_DIRECTIVES
    ],
    template: `

                    {{ option.label || option}}

                <input [hidden]="true" [name]="name" type="radio" [value]="option.checked || option" [attr.id]="name + i">

    `
})
export class Tiles {
    validators:Array = [];
    _options:Array = [];
    value:any = null;
    activeTile:any = null;
    changed:EventEmitter = new EventEmitter;

    constructor(@Optional() model:NgControl, element:ElementRef) {
        this.element = element;
        this.model = model || new NgModel();
        this.model.valueAccessor = this;
    }

    ngOnInit() {
        this.name = this.name || '';

        if (this.control) {
            this.control.updateValue(this.value);
        }
        if (this.options && this.options.length && (this.options[0].value === undefined || this.options[0].value === null)) {
            this._options = this.options.map((x) => {
                let item = { value: x, label: x, checked: this.value === x };
                return item;
            });
        } else {
            this._options = this.options.map((x) => {
                x.checked = this.value === x.value;
                if (x.checked) {
                    this.setTile(x);
                }
                return x;
            });
        }
    }

	/**
     * @name select
     *
     * @param event
     * @param item
     */
    select(event, item) {
        if (event) {
            event.stopPropagation();
            event.preventDefault();
        }
        for (let option of this._options) {
            option.checked = false;
        }
        item.checked = !item.checked;
        this.changed.emit(item.value);
        this.model.viewToModelUpdate(item.value);
        this.setTile(item);
    }

    setTile(item) {
        if (item) {
            this.activeTile = item.value;
            this.moveTile();
        }
    }

    moveTile() {
        setTimeout(() => {
            let ind = this.element.nativeElement.querySelector('.active-indicator');
            let el = this.element.nativeElement.querySelector('.tile.active');
            let w = el.clientWidth;
            let left = el.offsetLeft;

            // These style adjustments need to occur in this order. TODO: Remove this and use ngAnimate2 - @asibilia
            setTimeout(() => {
                ind.style.width = `${w + 4}px`;
                setTimeout(() => {
                    ind.style.transform = `translateX(${left}px)`;
                    setTimeout(() => {
                        ind.style.opacity = '1';
                    });
                });
            });
        });
    }

    // ValueAccessor Functions
    writeValue(value) {
        this.value = value;
    }

    registerOnChange(fn) {
        this.onChange = fn;
    }

    registerOnTouched(fn) {
        this.onTouched = fn;
    }
}

export const NOVO_TILES_ELEMENTS = [Tiles];
<|endoftext|>


<commit_before>/**
 *
 */

"use strict";

var _ = require('lodash');

var Blink1 = require('node-blink1');

var tinycolor = require('tinycolor2');

var config = require('../configuration');

var log = require('../logger');
var util = require('../utils');

// globals because we are a singleton
var listeners = {};

// blink1 devices currently opened
// one entry per blink1, with always at least one entry
// entry 0 is 'default' entry when no blink1 is plugged in
// format is
var blink1s = []; // collection of opened blink1s
    // {   serial: '12345678',
    //     device: new Blink1()
    // }
// var blink1IdOpen = 0;

// one entry per blink1, with always at least one entry
// entry 0 is 'default' entry when no blink1 is plugged in
var currentState = new Array(8);  // 8 is max number of blink1s allowed
currentState[0] =
	{
		colors: new Array(18), // replaces "currentColor", 18 element array, one per LEDs
		millis: 100, // replaces "currentMillis"
		ledn:0 // replaces curerntLedN
	};
currentState[0].colors.fill( tinycolor('#000000'));
currentState.fill( currentState[0] ); // hmmmm
var lastState = _.clone( currentState ); // FIXME: what am I using lastState for?

var Blink1Service = {
	toyEnable: false,
	toyTimer:null,
	conf: {},
	start: function() {
		listeners = {}; // erase previous listeners
		Blink1Service.scanForDevices();
	},
	reloadConfig: function() {
		log.msg("Blink1Service.reloadConfig");
        this.conf = config.readSettings('blink1Service') || {};
		Blink1Service._removeAllDevices();
		Blink1Service.scanForDevices();
	},
	scanForDevices: function() {
		log.msg("Blink1Service.scanForDevices");
		// initial population of any already-plugged in devices
		var serials = Blink1.devices();
        serials.sort();
		serials.map( function(s) {
			Blink1Service._addDevice(s);
		});

		log.msg("Blink1Service.scanForDevices: done. serials:", serials);
		if( serials.length === 0 ) { // no blink1s, look for insertion events
			if( this.conf.deviceRescan ) {
				setTimeout( this.scanForDevices.bind(this), 5000);  // look again in 5 secs
			}
		}
	},
    _addDevice: function(serialnumber) {
        log.msg("Blink1Service._addDevice:", serialnumber);
        var olddev = _.find( blink1s, {serial:serialnumber} );
        if( !olddev ) {
            log.msg("Blink1Service._addDevice: new serial ", serialnumber);
            blink1s.push( { serial: serialnumber, device: null, toSetup:true } );
        }
        // set up all devices at once
        // we wait 500msec because it was failing without it
        setTimeout( Blink1Service._setupFoundDevices, 500);
    },
    _setupFoundDevices: function() {
        log.msg("Blink1Service._setupFoundDevices", blink1s);
        blink1s.map( function(b1) {
            if( !b1.device ) {
                log.msg("Blink1Service._setupFoundDevice: opening ",b1.serial);
                b1.device = new Blink1(b1.serial);
            }
        });
        Blink1Service.notifyChange();
    },
    _removeDevice: function(serialnumber) {
    	log.msg("Blink1Service._removeDevice: current devices:", blink1s);
        var olds = _.remove( blink1s, {serial:serialnumber} );
        olds.forEach( function(b1) {
            if( b1.device ) {
                b1.device.close();
                b1.device = null;
            }
        });
        setTimeout( this.scanForDevices.bind(this), 5000);
    },
	_removeAllDevices: function() {
		log.msg("Blink1Service._removeAllDevices");
        blink1s.forEach( function(b1) {
            if( b1.device ) {
                b1.device.close();
                b1.device = null;
            }
        });
        blink1s = [ ]; //{serial: '', device: null } ]; // startup state
		log.msg("Blink1Service._removeAllDevices: done");
        // FIXME: notify?
	},

	// private function, accesses hardware
    _fadeToRGB: function( millis, r,g,b, ledn, blink1_id ) {
        var id = (blink1_id) ? blink1_id : 0; // FIXME: maybe is serial

        if( blink1s[id] && blink1s[id].device ) {
            try {
				blink1s[id].device.fadeToRGB( millis, r, g, b, ledn );
			} catch(err) {
				log.msg('Blink1Service._fadeToRGB: error', err);
				this._removeDevice( blink1s[id].serial );
			}
        }
    },

	// begin public functions

	getAllSerials: function() {
		return blink1s.map(function(b1) { return b1.serial; });
	},
    // FIXME: support multiple blink1s
	isConnected: function() {
        // return (blink1serials.length > 0);
        var isConnected = false;
        blink1s.map( function(b1) {
            if( b1.device ) { isConnected = true; }
        });
        return isConnected;
	},
    // FIXME: support multiple blink1s
	serialNumber: function() {
		if( this.isConnected() ) {
			return blink1s[0].serial;
		}
		return '';
	},
    // FIXME: support multiple blink1s
	serialNumberForDisplay: function() {
		return (this.isConnected()) ? this.serialNumber() : '-';
	},
	// FIXME: fix and call this blink1Id or something
	iftttKey: function() {  // FIXME:
		var s = this.serialNumber() || '00000000';
		var k = this.hostId() + s;
		return k;
	},
	hostId: function() {
		var id = config.readSettings('hostId');
		if( !id ) {
			id = util.generateRandomHostId();
			this.setHostId(id);
		}
		return id;
	},
	setHostId: function(id) {
		config.saveSettings( 'hostId', id);
		// this.notifyChange();
	},

    // FIXME: support multiple blink1s
	setCurrentLedN: function(n) {
		currentState[0].ledn = n;
		this.notifyChange();
	},
    // FIXME: support multiple blink1s
	getCurrentLedN: function() {
		return currentState[0].ledn;
	},
    // FIXME: support multiple blink1s
	setCurrentMillis: function(m) {
		currentState[0].millis = m;
		this.notifyChange();
	},
    // FIXME: support multiple blink1s
	getCurrentMillis: function() {
		return currentState[0].millis;
	},
    // FIXME: support multiple blink1s
	getCurrentColor: function() { // FIXME
		// var ledn = (currentLedN>0) ? currentLedN-1 : currentLedN;
		var curledn = currentState[0].ledn;
		curledn = (curledn>0) ? curledn-1 : curledn;
		return currentState[0].colors[ curledn ];
	},
	getCurrentColors: function() {
		// return currentColors;
		return currentState[0].colors;
	},
	// main entry point for this service, sets currentColor & currentLedN
	// 'color' arg is a tinycolor() color or hextring ('#ff00ff')
	// if color is a hexstring, it will get converted to tinycolor
	// ledn is 1-index into color array, and ledn=0 means "all leds"
    // blink1_id is index into blink1s array (but should also be by serialnumber)
    // FIXME: currentState[0] will be currentState[blink1_id]
    //
	fadeToColor: function( millis, color, ledn, blink1_id) {
		var id = blink1_id || 0;
		ledn = ledn || 0;
		if( typeof color === 'string' ) {
			color = tinycolor( color ); // FIXME: must be better way
		}

		var colors = _.clone(currentState[id].colors);
		// handle special meaning: ledn=0 -> all LEDs
		if( ledn === 0 ) { colors.fill( color );
		} else {           colors[ledn-1] = color;	}

		lastState[id] = currentState[id];
		currentState[id] = {ledn: ledn, millis: millis, colors };

		// FIXME: how to make sure 'color' is a tinycolor object? color.isValid?
		log.msg("Blink1Service.fadeToColor:"+id+":", millis,ledn, color.toHexString());
                //, typeof color, (color instanceof String) );
		var crgb = color.toRgb();

		// divide currentMillis by two to make it appear more responsive
		// by having blink1 be at destination color for half the time
		this._fadeToRGB( millis/2, crgb.r, crgb.g, crgb.b, ledn, id);

		this.notifyChange();
	},

	off: function() {
		this.toyEnable = false;
		this.fadeToColor(0, '#000000', 0); // 0 = all leds
	},
	colorCycleStart: function() {
		this.toyEnable = true;
		this.colorCycleDo();
	},
	colorCycleStop: function() {
		this.toyEnable = false;
		clearTimeout( this.toyTimer );
	},
	colorCycleDo: function() {
		log.msg("Blink1Service.colorCycleDo");
		if( !this.toyEnable ) { return; }
		this.fadeToColor( 100, tinycolor.random(), 0 );
		this.toyTimer = setTimeout(this.colorCycleDo.bind(this), 300);
	},

	addChangeListener: function(callback, callername) {
		listeners[callername] = callback;
		// console.log("Blink1Service: addChangelistener", listeners );
	},
	removeChangeListener: function(callername) {
		log.msg("Blink1Service.removeChangelistener: removing", callername);
		delete listeners[callername];
		// log.msg("Blink1Service.removeChangelistener", listeners );
	},
	removeAllListeners: function() {
		_.keys( listeners, function(callername) {
			this.removeChangelistener(callername);
		});
	},
	notifyChange: function() {
		_.forIn( listeners, function(callback) {
			// currentColor and currentColors are tinycolor objects
			// callback( Blink1Service.getCurrentColor(), currentColors, currentLedN, currentMillis);
            callback( Blink1Service.getCurrentColor(), currentState[0].colors, currentState[0].ledn, currentState[0].millis );
		});
	},

};

module.exports = Blink1Service;

// _closeCurrentDevice: function()	{
// 	log.msg('Blink1Service._closeCurrentDevice: closing blink1');
// 	if( blink1 ) {
// 		blink1.close();
// 		blink1 = null;
// 	}
// },
<commit_msg>fix device rescan<commit_after>/**
 *
 */

"use strict";

var _ = require('lodash');

var Blink1 = require('node-blink1');

var tinycolor = require('tinycolor2');

var config = require('../configuration');

var log = require('../logger');
var util = require('../utils');

// globals because we are a singleton
var listeners = {};

// blink1 devices currently opened
// one entry per blink1, with always at least one entry
// entry 0 is 'default' entry when no blink1 is plugged in
// format is
var blink1s = []; // collection of opened blink1s
    // {   serial: '12345678',
    //     device: new Blink1()
    // }
// var blink1IdOpen = 0;

// one entry per blink1, with always at least one entry
// entry 0 is 'default' entry when no blink1 is plugged in
var currentState = new Array(8);  // 8 is max number of blink1s allowed
currentState[0] =
	{
		colors: new Array(18), // replaces "currentColor", 18 element array, one per LEDs
		millis: 100, // replaces "currentMillis"
		ledn:0 // replaces curerntLedN
	};
currentState[0].colors.fill( tinycolor('#000000'));
currentState.fill( currentState[0] ); // hmmmm
var lastState = _.clone( currentState ); // FIXME: what am I using lastState for?

var Blink1Service = {
	toyEnable: false,
	toyTimer:null,
	conf: {},
	start: function() {
		listeners = {}; // erase previous listeners
		this.reloadConfig();
	},
	reloadConfig: function() {
		log.msg("Blink1Service.reloadConfig");
        this.conf = config.readSettings('blink1Service') || {};
		Blink1Service._removeAllDevices();
		Blink1Service.scanForDevices();
	},
	scanForDevices: function() {
		// log.msg("Blink1Service.scanForDevices");
		// initial population of any already-plugged in devices
		var serials = Blink1.devices();
        serials.sort();
		serials.map( function(s) {
			Blink1Service._addDevice(s);
		});

		log.msg("Blink1Service.scanForDevices: done. serials:", serials);
		if( serials.length === 0 ) { // no blink1s, look for insertion events
			if( this.conf.deviceRescan ) {
				setTimeout( this.scanForDevices.bind(this), 5000);  // look again in 5 secs
			}
		}
	},
    _addDevice: function(serialnumber) {
        log.msg("Blink1Service._addDevice:", serialnumber);
        var olddev = _.find( blink1s, {serial:serialnumber} );
        if( !olddev ) {
            log.msg("Blink1Service._addDevice: new serial ", serialnumber);
            blink1s.push( { serial: serialnumber, device: null, toSetup:true } );
        }
        // set up all devices at once
        // we wait 500msec because it was failing without it
        setTimeout( Blink1Service._setupFoundDevices, 500);
    },
    _setupFoundDevices: function() {
        log.msg("Blink1Service._setupFoundDevices", blink1s);
        blink1s.map( function(b1) {
            if( !b1.device ) {
                log.msg("Blink1Service._setupFoundDevice: opening ",b1.serial);
                b1.device = new Blink1(b1.serial);
            }
        });
        Blink1Service.notifyChange();
    },
    _removeDevice: function(serialnumber) {
    	log.msg("Blink1Service._removeDevice: current devices:", blink1s);
        var olds = _.remove( blink1s, {serial:serialnumber} );
        olds.forEach( function(b1) {
            if( b1.device ) {
                b1.device.close();
                b1.device = null;
            }
        });
        setTimeout( this.scanForDevices.bind(this), 5000);
    },
	_removeAllDevices: function() {
		log.msg("Blink1Service._removeAllDevices");
        blink1s.forEach( function(b1) {
            if( b1.device ) {
                b1.device.close();
                b1.device = null;
            }
        });
        blink1s = [ ]; //{serial: '', device: null } ]; // startup state
		log.msg("Blink1Service._removeAllDevices: done");
        // FIXME: notify?
	},

	// private function, accesses hardware
    _fadeToRGB: function( millis, r,g,b, ledn, blink1_id ) {
        var id = (blink1_id) ? blink1_id : 0; // FIXME: maybe is serial

        if( blink1s[id] && blink1s[id].device ) {
            try {
				blink1s[id].device.fadeToRGB( millis, r, g, b, ledn );
			} catch(err) {
				log.msg('Blink1Service._fadeToRGB: error', err);
				this._removeDevice( blink1s[id].serial );
			}
        }
    },

	// begin public functions

	getAllSerials: function() {
		return blink1s.map(function(b1) { return b1.serial; });
	},
    // FIXME: support multiple blink1s
	isConnected: function() {
        // return (blink1serials.length > 0);
        var isConnected = false;
        blink1s.map( function(b1) {
            if( b1.device ) { isConnected = true; }
        });
        return isConnected;
	},
    // FIXME: support multiple blink1s
	serialNumber: function() {
		if( this.isConnected() ) {
			return blink1s[0].serial;
		}
		return '';
	},
    // FIXME: support multiple blink1s
	serialNumberForDisplay: function() {
		return (this.isConnected()) ? this.serialNumber() : '-';
	},
	// FIXME: fix and call this blink1Id or something
	iftttKey: function() {  // FIXME:
		var s = this.serialNumber() || '00000000';
		var k = this.hostId() + s;
		return k;
	},
	hostId: function() {
		var id = config.readSettings('hostId');
		if( !id ) {
			id = util.generateRandomHostId();
			this.setHostId(id);
		}
		return id;
	},
	setHostId: function(id) {
		config.saveSettings( 'hostId', id);
		// this.notifyChange();
	},

    // FIXME: support multiple blink1s
	setCurrentLedN: function(n) {
		currentState[0].ledn = n;
		this.notifyChange();
	},
    // FIXME: support multiple blink1s
	getCurrentLedN: function() {
		return currentState[0].ledn;
	},
    // FIXME: support multiple blink1s
	setCurrentMillis: function(m) {
		currentState[0].millis = m;
		this.notifyChange();
	},
    // FIXME: support multiple blink1s
	getCurrentMillis: function() {
		return currentState[0].millis;
	},
    // FIXME: support multiple blink1s
	getCurrentColor: function() { // FIXME
		// var ledn = (currentLedN>0) ? currentLedN-1 : currentLedN;
		var curledn = currentState[0].ledn;
		curledn = (curledn>0) ? curledn-1 : curledn;
		return currentState[0].colors[ curledn ];
	},
	getCurrentColors: function() {
		// return currentColors;
		return currentState[0].colors;
	},
	// main entry point for this service, sets currentColor & currentLedN
	// 'color' arg is a tinycolor() color or hextring ('#ff00ff')
	// if color is a hexstring, it will get converted to tinycolor
	// ledn is 1-index into color array, and ledn=0 means "all leds"
    // blink1_id is index into blink1s array (but should also be by serialnumber)
    // FIXME: currentState[0] will be currentState[blink1_id]
    //
	fadeToColor: function( millis, color, ledn, blink1_id) {
		var id = blink1_id || 0;
		ledn = ledn || 0;
		if( typeof color === 'string' ) {
			color = tinycolor( color ); // FIXME: must be better way
		}

		var colors = _.clone(currentState[id].colors);
		// handle special meaning: ledn=0 -> all LEDs
		if( ledn === 0 ) { colors.fill( color );
		} else {           colors[ledn-1] = color;	}

		lastState[id] = currentState[id];
		currentState[id] = {ledn: ledn, millis: millis, colors };

		// FIXME: how to make sure 'color' is a tinycolor object? color.isValid?
		log.msg("Blink1Service.fadeToColor:"+id+":", millis,ledn, color.toHexString());
                //, typeof color, (color instanceof String) );
		var crgb = color.toRgb();

		// divide currentMillis by two to make it appear more responsive
		// by having blink1 be at destination color for half the time
		this._fadeToRGB( millis/2, crgb.r, crgb.g, crgb.b, ledn, id);

		this.notifyChange();
	},

	off: function() {
		this.toyEnable = false;
		this.fadeToColor(0, '#000000', 0); // 0 = all leds
	},
	colorCycleStart: function() {
		this.toyEnable = true;
		this.colorCycleDo();
	},
	colorCycleStop: function() {
		this.toyEnable = false;
		clearTimeout( this.toyTimer );
	},
	colorCycleDo: function() {
		log.msg("Blink1Service.colorCycleDo");
		if( !this.toyEnable ) { return; }
		this.fadeToColor( 100, tinycolor.random(), 0 );
		this.toyTimer = setTimeout(this.colorCycleDo.bind(this), 300);
	},

	addChangeListener: function(callback, callername) {
		listeners[callername] = callback;
		// console.log("Blink1Service: addChangelistener", listeners );
	},
	removeChangeListener: function(callername) {
		log.msg("Blink1Service.removeChangelistener: removing", callername);
		delete listeners[callername];
		// log.msg("Blink1Service.removeChangelistener", listeners );
	},
	removeAllListeners: function() {
		_.keys( listeners, function(callername) {
			this.removeChangelistener(callername);
		});
	},
	notifyChange: function() {
		_.forIn( listeners, function(callback) {
			// currentColor and currentColors are tinycolor objects
			// callback( Blink1Service.getCurrentColor(), currentColors, currentLedN, currentMillis);
            callback( Blink1Service.getCurrentColor(), currentState[0].colors, currentState[0].ledn, currentState[0].millis );
		});
	},

};

module.exports = Blink1Service;

// _closeCurrentDevice: function()	{
// 	log.msg('Blink1Service._closeCurrentDevice: closing blink1');
// 	if( blink1 ) {
// 		blink1.close();
// 		blink1 = null;
// 	}
// },
<|endoftext|>


<commit_before>/* eslint-disable unicorn/no-process-exit */

// Native
import fs from 'fs'
import path from 'path'
import { spawnSync } from 'child_process'
import zlib from 'zlib'

// Packages
import onDeath from 'death'
import fetch from 'node-fetch'
import retry from 'async-retry'
import which from 'which-promise'
import readPkg from 'read-pkg'

// Utilities
import plusxSync from './chmod'
import {
  disableProgress,
  enableProgress,
  info,
  showProgress,
  warn
} from './log'

fetch.Promise = Promise
global.Promise = Promise
let { platform } = process
if (detectAlpine()) platform = 'alpine'

const packageDir = path.join(__dirname, '..', '..')
const packageJSON = readPkg.sync(packageDir)

const now = path.join(__dirname, 'now')
const targetWin32 = path.join(__dirname, 'now.exe')
const target = platform === 'win32' ? targetWin32 : now
const partial = target + '.partial'
const backup = target + '.' + packageJSON.version + '.backup'

const platformToName = {
  alpine: 'now-alpine',
  darwin: 'now-macos',
  linux: 'now-linux',
  win32: 'now-win.exe'
}

function detectAlpine () {
  if (platform !== 'linux') return false
  // https://github.com/sass/node-sass/issues/1589#issuecomment-265292579
  const ldd = spawnSync('ldd', [ process.execPath ]).stdout.toString()
  return /\bmusl\b/.test(ldd)
}

async function download() {
  try {
    fs.writeFileSync(
      now,
      '#!/usr/bin/env node\n' +
        'console.log("Please wait until the \'now\' installation completes!")\n'
    )
  } catch (err) {
    if (err.code === 'EACCES') {
      warn(
        'Please try installing Now CLI again with the `--unsafe-perm` option.'
      )
      info('Example: `npm i -g --unsafe-perm now`')

      process.exit()
    }

    throw err
  }

  onDeath(() => {
    fs.writeFileSync(
      now,
      '#!/usr/bin/env node\n' +
        'console.log("The \'now\' installation did not complete successfully.")\n' +
        'console.log("Please run \'npm i -g now\' to reinstall!")\n'
    )
    process.exit()
  })

  info('For the source code, check out: https://github.com/zeit/now-cli')

  // Print an empty line
  console.log('')

  await retry(async () => {
    console.log('Downloading Now CLI ' + packageJSON.version + '. Please wait...')

    try {
      const name = platformToName[platform]
      const url = `https://cdn.zeit.co/releases/now-cli/${packageJSON.version}/${name}`
      const resp = await fetch(url, { compress: false })

      if (resp.status !== 200) {
        throw new Error(resp.statusText + ' ' + url)
      }

      const ws = fs.createWriteStream(partial)

      await new Promise((resolve, reject) => {
        let bytesRead = 0

        resp.body
          .on('error', reject)
          .on('data', chunk => {
            bytesRead += chunk.length
          })

        const encoding = resp.headers.get('content-encoding')

        if (encoding && encoding === 'gzip') {
          const gunzip = zlib.createGunzip()

          gunzip
            .on('error', reject)

          resp.body.pipe(gunzip).pipe(ws)
        } else {
          resp.body.pipe(ws)
        }

        ws
          .on('error', reject)
          .on('close', () => {
            resolve()
          })
      })
    } finally {
      disableProgress()
    }
  }, {
    retries: 500,
    onRetry: (err) => console.error(err)
  })

  fs.renameSync(partial, target)
  fs.writeFileSync(backup, fs.readFileSync(target))
}

function modifyGitBashFile (content) {
  return (
    '#!/bin/sh\n' +
      'basedir=$(dirname "$(echo "$0" | sed -e \'s,\\\\,/,g\')")\n' +
      '\n' +
      'case `uname` in\n' +
      '    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;\n' +
      'esac\n' +
      '\n' +
    content.replace(
      'download/dist/now"', 'download/dist/now.exe"'));
}

async function main() {
  if (fs.existsSync(backup)) {
    fs.writeFileSync(target, fs.readFileSync(backup))
  } else {
    await download()
  }

  if (platform === 'win32') {
    try {
      fs.writeFileSync(now, '')
      // Workaround for https://github.com/npm/cmd-shim/pull/25
      const globalPath = path.dirname(await which('npm'))
      let gitBashFile = path.join(globalPath, 'now')
      if (!fs.existsSync(gitBashFile)) {
        gitBashFile = path.join(process.env.APPDATA, 'npm/now');
      }

      fs.writeFileSync(
        gitBashFile, modifyGitBashFile(fs.readFileSync(gitBashFile, 'utf8'))
      )
    } catch (err) {
      if (err.code !== 'ENOENT') {
        // Not a problem. only git cmd will not work
        console.error(err)
      }
    }
  } else {
    plusxSync(now)
  }
}

main().catch(err => {
  console.error(err)
  process.exit(2)
})
<commit_msg>Remove broken function call<commit_after>/* eslint-disable unicorn/no-process-exit */

// Native
import fs from 'fs'
import path from 'path'
import { spawnSync } from 'child_process'
import zlib from 'zlib'

// Packages
import onDeath from 'death'
import fetch from 'node-fetch'
import retry from 'async-retry'
import which from 'which-promise'
import readPkg from 'read-pkg'

// Utilities
import plusxSync from './chmod'
import {
  disableProgress,
  enableProgress,
  info,
  showProgress,
  warn
} from './log'

fetch.Promise = Promise
global.Promise = Promise
let { platform } = process
if (detectAlpine()) platform = 'alpine'

const packageDir = path.join(__dirname, '..', '..')
const packageJSON = readPkg.sync(packageDir)

const now = path.join(__dirname, 'now')
const targetWin32 = path.join(__dirname, 'now.exe')
const target = platform === 'win32' ? targetWin32 : now
const partial = target + '.partial'
const backup = target + '.' + packageJSON.version + '.backup'

const platformToName = {
  alpine: 'now-alpine',
  darwin: 'now-macos',
  linux: 'now-linux',
  win32: 'now-win.exe'
}

function detectAlpine () {
  if (platform !== 'linux') return false
  // https://github.com/sass/node-sass/issues/1589#issuecomment-265292579
  const ldd = spawnSync('ldd', [ process.execPath ]).stdout.toString()
  return /\bmusl\b/.test(ldd)
}

async function download() {
  try {
    fs.writeFileSync(
      now,
      '#!/usr/bin/env node\n' +
        'console.log("Please wait until the \'now\' installation completes!")\n'
    )
  } catch (err) {
    if (err.code === 'EACCES') {
      warn(
        'Please try installing Now CLI again with the `--unsafe-perm` option.'
      )
      info('Example: `npm i -g --unsafe-perm now`')

      process.exit()
    }

    throw err
  }

  onDeath(() => {
    fs.writeFileSync(
      now,
      '#!/usr/bin/env node\n' +
        'console.log("The \'now\' installation did not complete successfully.")\n' +
        'console.log("Please run \'npm i -g now\' to reinstall!")\n'
    )
    process.exit()
  })

  info('For the source code, check out: https://github.com/zeit/now-cli')

  // Print an empty line
  console.log('')

  await retry(async () => {
    console.log('Downloading Now CLI ' + packageJSON.version + '. Please wait...')

    try {
      const name = platformToName[platform]
      const url = `https://cdn.zeit.co/releases/now-cli/${packageJSON.version}/${name}`
      const resp = await fetch(url, { compress: false })

      if (resp.status !== 200) {
        throw new Error(resp.statusText + ' ' + url)
      }

      const ws = fs.createWriteStream(partial)

      await new Promise((resolve, reject) => {
        let bytesRead = 0

        resp.body
          .on('error', reject)
          .on('data', chunk => {
            bytesRead += chunk.length
          })

        const encoding = resp.headers.get('content-encoding')

        if (encoding && encoding === 'gzip') {
          const gunzip = zlib.createGunzip()

          gunzip
            .on('error', reject)

          resp.body.pipe(gunzip).pipe(ws)
        } else {
          resp.body.pipe(ws)
        }

        ws
          .on('error', reject)
          .on('close', () => {
            resolve()
          })
      })
    }
  }, {
    retries: 500,
    onRetry: (err) => console.error(err)
  })

  fs.renameSync(partial, target)
  fs.writeFileSync(backup, fs.readFileSync(target))
}

function modifyGitBashFile (content) {
  return (
    '#!/bin/sh\n' +
      'basedir=$(dirname "$(echo "$0" | sed -e \'s,\\\\,/,g\')")\n' +
      '\n' +
      'case `uname` in\n' +
      '    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;\n' +
      'esac\n' +
      '\n' +
    content.replace(
      'download/dist/now"', 'download/dist/now.exe"'));
}

async function main() {
  if (fs.existsSync(backup)) {
    fs.writeFileSync(target, fs.readFileSync(backup))
  } else {
    await download()
  }

  if (platform === 'win32') {
    try {
      fs.writeFileSync(now, '')
      // Workaround for https://github.com/npm/cmd-shim/pull/25
      const globalPath = path.dirname(await which('npm'))
      let gitBashFile = path.join(globalPath, 'now')
      if (!fs.existsSync(gitBashFile)) {
        gitBashFile = path.join(process.env.APPDATA, 'npm/now');
      }

      fs.writeFileSync(
        gitBashFile, modifyGitBashFile(fs.readFileSync(gitBashFile, 'utf8'))
      )
    } catch (err) {
      if (err.code !== 'ENOENT') {
        // Not a problem. only git cmd will not work
        console.error(err)
      }
    }
  } else {
    plusxSync(now)
  }
}

main().catch(err => {
  console.error(err)
  process.exit(2)
})
<|endoftext|>


<commit_before>import { InsertInlineNodeCommand as SubstanceInsertInlineNodeCommand } from 'substance'

/**
  Reusable command implementation for inserting inline nodes.

  @class InsertInlineNodeCommand

  @example

  Define a custom command.

  ```
  class AddXRefCommand extends InsertInlineNodeCommand {
    createNode(tx) {
      let refType = this.config.refType
      let xref = tx.createElement('xref').attr('publication-type', 'journal')
      xref.attr('ref-type', refType)
      xref.attr('rid', '')
      return xref
    }
  }
  ```

  Register it in your app using the configurator.

  ```
  config.addCommand('add-xref', AddXRefCommand, { nodeType: 'xref' })
  ```
*/

class InsertInlineNodeCommand extends SubstanceInsertInlineNodeCommand {

  /**
    Insert new inline node at the current selection
  */
  execute(params) {
    let state = this.getCommandState(params)
    if (state.disabled) return
    let editorSession = this._getEditorSession(params)
    editorSession.transaction((tx) => {
      let node = this.createNode(tx, params)
      tx.insertInlineNode(node)
    })
  }

  createNode(tx) { // eslint-disable-line
    throw new Error('This method is abstract')
  }

}

export default InsertInlineNodeCommand
<commit_msg>Improve UI flow for adding cross references.<commit_after>import { InsertInlineNodeCommand as SubstanceInsertInlineNodeCommand } from 'substance'

/**
  Reusable command implementation for inserting inline nodes.

  @class InsertInlineNodeCommand

  @example

  Define a custom command.

  ```
  class AddXRefCommand extends InsertInlineNodeCommand {
    createNode(tx) {
      let refType = this.config.refType
      let xref = tx.createElement('xref').attr('publication-type', 'journal')
      xref.attr('ref-type', refType)
      xref.attr('rid', '')
      return xref
    }
  }
  ```

  Register it in your app using the configurator.

  ```
  config.addCommand('add-xref', AddXRefCommand, { nodeType: 'xref' })
  ```
*/

class InsertInlineNodeCommand extends SubstanceInsertInlineNodeCommand {

  /**
    Insert new inline node at the current selection
  */
  execute(params) {
    let state = this.getCommandState(params)
    if (state.disabled) return
    let editorSession = this._getEditorSession(params)
    editorSession.transaction((tx) => {
      let node = this.createNode(tx, params)
      tx.insertInlineNode(node)
      this.setSelection(tx, node)
    })
  }

  createNode(tx) { // eslint-disable-line
    throw new Error('This method is abstract')
  }

  setSelection(tx, node) {
    if(node.isPropertyAnnotation()) {
      tx.selection = {
        type: 'property',
        path: node.getPath(),
        startOffset: node.startOffset,
        endOffset: node.endOffset
      }
    }
  }

}

export default InsertInlineNodeCommand
<|endoftext|>


<commit_before>"use strict";

var ejs = require("ejs");

module.exports = function(options, imports, register) {

    imports["connect.render"].registerEngine("ejs", createView);

    ejs.filters.JSONToJS = function(obj, indent) {
        return JSON.stringify(obj, null, indent).replace(/<\/?script|[\u2028\u2029]/g, function(a) {
            var h =  a.charCodeAt(0).toString(16);
            return (h.length == 2 ? "\\x" : "\\u") + h + a.substr(1);
        });
    };

    var helper = {
        timeSpan: function(ts) {
            var sec = 1000;
            var min = 60 * sec;
            var hour = 60 * min;

            return pad(~~(ts / hour)) + ":" + pad(~~((ts % hour) / min)) + ":" + pad(~~((ts % min) / sec));

            function pad(d) {
                if (d < 10)
                    return "0" + d;
                else
                    return d;
            }
        },
        timeSpanSince: function(ts) {
            return helper.timeSpan(Date.now() - ts);
        }
    };

    function createView(path, callback) {
        return callback(null, function(res, options, callback) {
            options.helper = helper;
            ejs.renderFile(path, options, function(err, template) {
                if (err) return callback(err);

                callback(null, {
                    headers: {"Content-Type": "text/html"},
                    body: template
                });
            });
        });
    }

    register(null, {
        "connect.render.ejs": {
            addHelper: function(name, helper) {
                helper[name] = helper;
            }
        }
    });
};<commit_msg>fix escaping of uppercase script tags in JSONToJS<commit_after>"use strict";

var ejs = require("ejs");

module.exports = function(options, imports, register) {

    imports["connect.render"].registerEngine("ejs", createView);

    ejs.filters.JSONToJS = function(obj, indent) {
        return JSON.stringify(obj, null, indent).replace(/<\/?script|[\u2028\u2029]/ig, function(a) {
            var h =  a.charCodeAt(0).toString(16);
            return (h.length == 2 ? "\\x" : "\\u") + h + a.substr(1);
        });
    };

    var helper = {
        timeSpan: function(ts) {
            var sec = 1000;
            var min = 60 * sec;
            var hour = 60 * min;

            return pad(~~(ts / hour)) + ":" + pad(~~((ts % hour) / min)) + ":" + pad(~~((ts % min) / sec));

            function pad(d) {
                if (d < 10)
                    return "0" + d;
                else
                    return d;
            }
        },
        timeSpanSince: function(ts) {
            return helper.timeSpan(Date.now() - ts);
        }
    };

    function createView(path, callback) {
        return callback(null, function(res, options, callback) {
            options.helper = helper;
            ejs.renderFile(path, options, function(err, template) {
                if (err) return callback(err);

                callback(null, {
                    headers: {"Content-Type": "text/html"},
                    body: template
                });
            });
        });
    }

    register(null, {
        "connect.render.ejs": {
            addHelper: function(name, helper) {
                helper[name] = helper;
            }
        }
    });
};<|endoftext|>


<commit_before>import PropTypes from 'prop-types'
import React, {useEffect, useMemo} from 'react'
import {reduxForm} from 'redux-form'
import {intlShape} from 'react-intl'
import {form} from 'tocco-app-extensions'
import styled from 'styled-components'

import SubGrid from '../../util/detailView/fromFieldFactories/subGrid'
import ErrorBox from '../ErrorBox'
import SaveButton from './SaveButton'

const StyledForm = styled.form`
  display: contents;
`

const DetailForm = props => {
  useEffect(() => {
    props.fireTouched(props.dirty)
  }, [props.dirty])

  const customActions = useMemo(() => (
    {
      save: () => <SaveButton intl={props.intl} submitting={props.submitting} mode={props.mode}/>
    }
  ), [props.submitting, props.mode])

  const focusErrorFields = () => {
    const firstErrorField = form.formErrorsUtil.getFirstErrorField(props.formErrors)
    if (firstErrorField) {
      const element = document.getElementById(form.getFieldId(props.form, firstErrorField))
      if (element) {
        document.getElementById(form.getFieldId(props.form, firstErrorField)).focus()
      }
    }
  }

  const save = () => {
    if (props.valid) {
      props.submitForm()
    } else if (props.formErrors) {
      showErrors()
    }
  }

  const handleSubmit = event => {
    event.preventDefault()
    save()
  }

  const handleKeyPress = event => {
    if (event.key === 'Enter' && event.target.tagName !== 'TEXTAREA') {
      event.preventDefault() // disable save on enter key down
    }
  }

  const showErrors = event => {
    if (event) {
      event.preventDefault()
    }

    props.touchAllFields()
    focusErrorFields()
  }

  return (
    <StyledForm
      onSubmit={handleSubmit}
      onKeyDown={handleKeyPress}
    >
      <form.FormBuilder
        entity={props.entity}
        model={props.entityModel}
        formName={props.form}
        formDefinition={props.formDefinition}
        formValues={props.formValues}
        fieldMappingType={props.formDefinition.readOnly ? 'readonly' : 'editable'}
        mode={props.mode}
        componentMapping={{[form.componentTypes.SUB_TABLE]: SubGrid}}
        customActions={customActions}
      />
      {!props.valid && props.anyTouched && <ErrorBox formErrors={props.formErrors} showErrors={showErrors}/>}
    </StyledForm>
  )
}

DetailForm.propTypes = {
  intl: intlShape.isRequired,
  mode: PropTypes.oneOf(['update', 'create']),
  entityModel: PropTypes.object.isRequired,
  submitForm: PropTypes.func.isRequired,
  formDefinition: PropTypes.object.isRequired,
  entity: PropTypes.object.isRequired,
  form: PropTypes.string.isRequired,
  touch: PropTypes.func.isRequired,
  formValues: PropTypes.object,
  submitting: PropTypes.bool,
  formErrors: PropTypes.object,
  valid: PropTypes.bool,
  dirty: PropTypes.bool,
  lastSave: PropTypes.number,
  fireTouched: PropTypes.func.isRequired,
  touchAllFields: PropTypes.func.isRequired,
  anyTouched: PropTypes.bool
}

export default reduxForm({
  form: 'detailForm',
  destroyOnUnmount: false
})(DetailForm)
<commit_msg>refactor(entity-detail): change height rendering of form<commit_after>import PropTypes from 'prop-types'
import React, {useEffect, useMemo} from 'react'
import {reduxForm} from 'redux-form'
import {intlShape} from 'react-intl'
import {form} from 'tocco-app-extensions'
import styled from 'styled-components'

import SubGrid from '../../util/detailView/fromFieldFactories/subGrid'
import ErrorBox from '../ErrorBox'
import SaveButton from './SaveButton'

const StyledForm = styled.form`
  display: flex;
  flex-direction: column;
  flex: 1;
`

const DetailForm = props => {
  useEffect(() => {
    props.fireTouched(props.dirty)
  }, [props.dirty])

  const customActions = useMemo(() => (
    {
      save: () => <SaveButton intl={props.intl} submitting={props.submitting} mode={props.mode}/>
    }
  ), [props.submitting, props.mode])

  const focusErrorFields = () => {
    const firstErrorField = form.formErrorsUtil.getFirstErrorField(props.formErrors)
    if (firstErrorField) {
      const element = document.getElementById(form.getFieldId(props.form, firstErrorField))
      if (element) {
        document.getElementById(form.getFieldId(props.form, firstErrorField)).focus()
      }
    }
  }

  const save = () => {
    if (props.valid) {
      props.submitForm()
    } else if (props.formErrors) {
      showErrors()
    }
  }

  const handleSubmit = event => {
    event.preventDefault()
    save()
  }

  const handleKeyPress = event => {
    if (event.key === 'Enter' && event.target.tagName !== 'TEXTAREA') {
      event.preventDefault() // disable save on enter key down
    }
  }

  const showErrors = event => {
    if (event) {
      event.preventDefault()
    }

    props.touchAllFields()
    focusErrorFields()
  }

  return <StyledForm
    onSubmit={handleSubmit}
    onKeyDown={handleKeyPress}
  >
    <form.FormBuilder
      entity={props.entity}
      model={props.entityModel}
      formName={props.form}
      formDefinition={props.formDefinition}
      formValues={props.formValues}
      fieldMappingType={props.formDefinition.readOnly ? 'readonly' : 'editable'}
      mode={props.mode}
      componentMapping={{[form.componentTypes.SUB_TABLE]: SubGrid}}
      customActions={customActions}
    />
    {!props.valid && props.anyTouched && <ErrorBox formErrors={props.formErrors} showErrors={showErrors}/>}
  </StyledForm>
}

DetailForm.propTypes = {
  intl: intlShape.isRequired,
  mode: PropTypes.oneOf(['update', 'create']),
  entityModel: PropTypes.object.isRequired,
  submitForm: PropTypes.func.isRequired,
  formDefinition: PropTypes.object.isRequired,
  entity: PropTypes.object.isRequired,
  form: PropTypes.string.isRequired,
  touch: PropTypes.func.isRequired,
  formValues: PropTypes.object,
  submitting: PropTypes.bool,
  formErrors: PropTypes.object,
  valid: PropTypes.bool,
  dirty: PropTypes.bool,
  lastSave: PropTypes.number,
  fireTouched: PropTypes.func.isRequired,
  touchAllFields: PropTypes.func.isRequired,
  anyTouched: PropTypes.bool
}

export default reduxForm({
  form: 'detailForm',
  destroyOnUnmount: false
})(DetailForm)
<|endoftext|>


<commit_before>/**
 *
 * PluginCard
 *
 */
/* eslint-disable */
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Button, PopUpWarning } from 'strapi-helper-plugin';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Wrapper from './Wrapper';

const PLUGINS_WITH_CONFIG = ['content-manager', 'email', 'upload'];

/* eslint-disable react/no-unused-state */
class PluginCard extends React.Component {
  state = {
    boostrapCol: 'col-lg-4',
    showModalAutoReload: false,
    showModalEnv: false,
  };

  componentDidMount() {
    // Listen window resize.
    window.addEventListener('resize', this.setBoostrapCol);
    this.setBoostrapCol();
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.setBoostrapCol);
  }

  setBoostrapCol = () => {
    let boostrapCol = 'col-lg-4';

    if (window.innerWidth > 1680) {
      boostrapCol = 'col-lg-3';
    }

    if (window.innerWidth > 2300) {
      boostrapCol = 'col-lg-2';
    }

    this.setState({ boostrapCol });
  };

  handleClick = () => {
    if (this.props.plugin.id !== 'support-us') {
      this.props.history.push({
        pathname: this.props.history.location.pathname,
        hash: `${this.props.plugin.id}::description`,
      });
    } else {
      this.aTag.click();
    }
  };

  handleClickSettings = e => {
    const settingsPath =
      this.props.plugin.id === 'content-manager'
        ? '/plugins/content-manager/ctm-configurations/models'
        : `/plugins/${this.props.plugin.id}/configurations/${this.props.currentEnvironment}`;

    e.preventDefault();
    e.stopPropagation();

    this.props.history.push(settingsPath);
  };

  handleDownloadPlugin = e => {
    const {
      autoReload,
      currentEnvironment,
      downloadPlugin,
      history: { push },
      isAlreadyInstalled,
      plugin: { id },
    } = this.props;

    if (!autoReload) {
      this.setState({ showModalAutoReload: true });
    } else if (currentEnvironment !== 'development') {
      this.setState({ showModalEnv: true });
    } else if (!isAlreadyInstalled) {
      downloadPlugin(e);
    } else {
      push('/list-plugins');
    }
  };

  render() {
    const buttonClass = !this.props.isAlreadyInstalled
      ? 'primary'
      : 'secondary';
    const buttonLabel = this.props.isAlreadyInstalled
      ? 'app.components.PluginCard.Button.label.install'
      : 'app.components.PluginCard.Button.label.download';

    // Display settings link for a selection of plugins.
    const settingsComponent = PLUGINS_WITH_CONFIG.includes(
      this.props.plugin.id
    ) && (

        <FontAwesomeIcon icon="cog" />
        <FormattedMessage id="app.components.PluginCard.settings" />

    );

    const descriptions = {
      short:
        this.props.plugin.id === 'support-us' ? (
          <FormattedMessage id={this.props.plugin.description.short} />
        ) : (
          this.props.plugin.description.short
        ),
      long:
        this.props.plugin.id === 'support-us' ? (
          <FormattedMessage
            id={
              this.props.plugin.description.long ||
              this.props.plugin.description.short
            }
          />
        ) : (
          this.props.plugin.description.long ||
          this.props.plugin.description.short
        ),
    };

    return (
      <Wrapper className={this.state.boostrapCol}>

              {this.props.plugin.name}{' '}

                  window.open(
                    `https://github.com/strapi/strapi/tree/master/packages/strapi-plugin-${this.props.plugin.id}`,
                    '_blank'
                  )
                }
              />

{descriptions.long}

 e.stopPropagation()}>

              <Button
                className={`${buttonClass} button`}
                label={buttonLabel}
                onClick={this.handleDownloadPlugin}
              />
               {
                  this.aTag = a;
                }}
                target="_blank"
              >

            {this.props.isAlreadyInstalled ? (
              settingsComponent
            ) : (

                <FormattedMessage
                  id={`app.components.PluginCard.compatible${
                    this.props.plugin.id === 'support-us' ? 'Community' : ''
                  }`}
                />

            )}

        <PopUpWarning
          content={{
            message:
              'app.components.PluginCard.PopUpWarning.install.impossible.autoReload.needed',
            title:
              'app.components.PluginCard.PopUpWarning.install.impossible.title',
            confirm:
              'app.components.PluginCard.PopUpWarning.install.impossible.confirm',
          }}
          isOpen={this.state.showModalAutoReload}
          onlyConfirmButton
          onConfirm={() => this.setState({ showModalAutoReload: false })}
          popUpWarningType="warning"
        />
        <PopUpWarning
          content={{
            message:
              'app.components.PluginCard.PopUpWarning.install.impossible.environment',
            title:
              'app.components.PluginCard.PopUpWarning.install.impossible.title',
            confirm:
              'app.components.PluginCard.PopUpWarning.install.impossible.confirm',
          }}
          isOpen={this.state.showModalEnv}
          onlyConfirmButton
          onConfirm={() => this.setState({ showModalEnv: false })}
          popUpWarningType="warning"
        />
      </Wrapper>
    );
  }
}

PluginCard.defaultProps = {
  isAlreadyInstalled: false,
  plugin: {
    description: '',
    id: '',
    name: '',
    price: 0,
    ratings: 5,
  },
};

PluginCard.propTypes = {
  currentEnvironment: PropTypes.string.isRequired,
  downloadPlugin: PropTypes.func.isRequired,
  history: PropTypes.object.isRequired,
  isAlreadyInstalled: PropTypes.bool,
  plugin: PropTypes.object,
};

export default PluginCard;
<commit_msg>Fixes #4908<commit_after>/**
 *
 * PluginCard
 *
 */
/* eslint-disable */
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Button, PopUpWarning } from 'strapi-helper-plugin';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Wrapper from './Wrapper';

const PLUGINS_WITH_CONFIG = ['email', 'upload'];

/* eslint-disable react/no-unused-state */
class PluginCard extends React.Component {
  state = {
    boostrapCol: 'col-lg-4',
    showModalAutoReload: false,
    showModalEnv: false,
  };

  componentDidMount() {
    // Listen window resize.
    window.addEventListener('resize', this.setBoostrapCol);
    this.setBoostrapCol();
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.setBoostrapCol);
  }

  setBoostrapCol = () => {
    let boostrapCol = 'col-lg-4';

    if (window.innerWidth > 1680) {
      boostrapCol = 'col-lg-3';
    }

    if (window.innerWidth > 2300) {
      boostrapCol = 'col-lg-2';
    }

    this.setState({ boostrapCol });
  };

  handleClick = () => {
    if (this.props.plugin.id !== 'support-us') {
      this.props.history.push({
        pathname: this.props.history.location.pathname,
        hash: `${this.props.plugin.id}::description`,
      });
    } else {
      this.aTag.click();
    }
  };

  handleClickSettings = e => {
    const settingsPath = `/plugins/${this.props.plugin.id}/configurations/${this.props.currentEnvironment}`;

    e.preventDefault();
    e.stopPropagation();

    this.props.history.push(settingsPath);
  };

  handleDownloadPlugin = e => {
    const {
      autoReload,
      currentEnvironment,
      downloadPlugin,
      history: { push },
      isAlreadyInstalled,
      plugin: { id },
    } = this.props;

    if (!autoReload) {
      this.setState({ showModalAutoReload: true });
    } else if (currentEnvironment !== 'development') {
      this.setState({ showModalEnv: true });
    } else if (!isAlreadyInstalled) {
      downloadPlugin(e);
    } else {
      push('/list-plugins');
    }
  };

  render() {
    const buttonClass = !this.props.isAlreadyInstalled
      ? 'primary'
      : 'secondary';
    const buttonLabel = this.props.isAlreadyInstalled
      ? 'app.components.PluginCard.Button.label.install'
      : 'app.components.PluginCard.Button.label.download';

    // Display settings link for a selection of plugins.
    const settingsComponent = PLUGINS_WITH_CONFIG.includes(
      this.props.plugin.id
    ) && (

        <FontAwesomeIcon icon="cog" />
        <FormattedMessage id="app.components.PluginCard.settings" />

    );

    const descriptions = {
      short:
        this.props.plugin.id === 'support-us' ? (
          <FormattedMessage id={this.props.plugin.description.short} />
        ) : (
          this.props.plugin.description.short
        ),
      long:
        this.props.plugin.id === 'support-us' ? (
          <FormattedMessage
            id={
              this.props.plugin.description.long ||
              this.props.plugin.description.short
            }
          />
        ) : (
          this.props.plugin.description.long ||
          this.props.plugin.description.short
        ),
    };

    return (
      <Wrapper className={this.state.boostrapCol}>

              {this.props.plugin.name}{' '}

                  window.open(
                    `https://github.com/strapi/strapi/tree/master/packages/strapi-plugin-${this.props.plugin.id}`,
                    '_blank'
                  )
                }
              />

{descriptions.long}

 e.stopPropagation()}>

              <Button
                className={`${buttonClass} button`}
                label={buttonLabel}
                onClick={this.handleDownloadPlugin}
              />
               {
                  this.aTag = a;
                }}
                target="_blank"
              >

            {this.props.isAlreadyInstalled ? (
              settingsComponent
            ) : (

                <FormattedMessage
                  id={`app.components.PluginCard.compatible${
                    this.props.plugin.id === 'support-us' ? 'Community' : ''
                  }`}
                />

            )}

        <PopUpWarning
          content={{
            message:
              'app.components.PluginCard.PopUpWarning.install.impossible.autoReload.needed',
            title:
              'app.components.PluginCard.PopUpWarning.install.impossible.title',
            confirm:
              'app.components.PluginCard.PopUpWarning.install.impossible.confirm',
          }}
          isOpen={this.state.showModalAutoReload}
          onlyConfirmButton
          onConfirm={() => this.setState({ showModalAutoReload: false })}
          popUpWarningType="warning"
        />
        <PopUpWarning
          content={{
            message:
              'app.components.PluginCard.PopUpWarning.install.impossible.environment',
            title:
              'app.components.PluginCard.PopUpWarning.install.impossible.title',
            confirm:
              'app.components.PluginCard.PopUpWarning.install.impossible.confirm',
          }}
          isOpen={this.state.showModalEnv}
          onlyConfirmButton
          onConfirm={() => this.setState({ showModalEnv: false })}
          popUpWarningType="warning"
        />
      </Wrapper>
    );
  }
}

PluginCard.defaultProps = {
  isAlreadyInstalled: false,
  plugin: {
    description: '',
    id: '',
    name: '',
    price: 0,
    ratings: 5,
  },
};

PluginCard.propTypes = {
  currentEnvironment: PropTypes.string.isRequired,
  downloadPlugin: PropTypes.func.isRequired,
  history: PropTypes.object.isRequired,
  isAlreadyInstalled: PropTypes.bool,
  plugin: PropTypes.object,
};

export default PluginCard;
<|endoftext|>


<commit_before>
import { isString, isEmpty } from 'lodash'
import Expression from './base'

/**
 * @class SubQueryExpression
 */
export default class SubQuery extends Expression {

  /**
   *
   * @param {Query|Literal} query
   * @constructor
   */
  constructor(query) {
    super()

    this.columns = []
    this.query = query
    this._isCTE = false
  }

  /**
   *
   * @param {String} table
   * @param {Array} columns
   */
  as(table, ...columns) {
    this.columns = columns

    return super.as(table)
  }

  /**
   *
   * @param {Boolean} flag
   * @returns {SubQuery}
   */
  isCTE(flag = true) {
    this._isCTE = flag
    return this
  }

  /**
   *
   * @param {Compiler} compiler
   * @returns {String}
   */
  compile(compiler) {
    let table = compiler.quote(this.alias)
    let query = `(${this.query.compile(compiler)})`

    if (! isEmpty(this.columns) ) {
      let columns = this.columns.map(value => compiler.quote(value))

      table += `(${columns.join(', ')})`
    }

    return this._isCTE ? `${table} as ${query}` : `${query} as ${table}`
  }

  /**
   *
   * @param {Any} expr
   * @returns {Boolean}
   */
  isEqual(expr) {
    if ( isString(expr) )
      return expr === this.alias

    return super.isEqual() || (
      expr instanceof SubQuery && expr.alias === this.alias
    )
  }

}<commit_msg>Fix displaying the sub query name if not available<commit_after>
import { isString, isEmpty } from 'lodash'
import Expression from './base'

/**
 * @class SubQueryExpression
 */
export default class SubQuery extends Expression {

  /**
   *
   * @param {Query|Literal} query
   * @constructor
   */
  constructor(query) {
    super()

    this.columns = []
    this.query = query
    this._isCTE = false
  }

  /**
   *
   * @param {String} name
   * @param {Array} columns
   */
  as(name, ...columns) {
    this.columns = columns

    return super.as(name)
  }

  /**
   *
   * @param {Boolean} flag
   * @returns {SubQuery}
   */
  isCTE(flag = true) {
    this._isCTE = flag
    return this
  }

  /**
   *
   * @param {Compiler} compiler
   * @returns {String}
   */
  compile(compiler) {
    let query = `(${this.query.compile(compiler)})`

    if (! this.alias ) return query

    let name = compiler.quote(this.alias)

    if (! isEmpty(this.columns) ) {
      let columns = this.columns.map(value => compiler.quote(value))

      name += `(${columns.join(', ')})`
    }

    return this._isCTE ? `${name} as ${query}` : `${query} as ${name}`
  }

  /**
   *
   * @param {Any} expr
   * @returns {Boolean}
   */
  isEqual(expr) {
    if ( isString(expr) )
      return expr === this.alias

    return super.isEqual() || (
      expr instanceof SubQuery && expr.alias === this.alias
    )
  }

}<|endoftext|>


<commit_before><commit_msg>just a blank text cell extension placeholder<commit_after>/*
  backgrid
  http://github.com/wyuenho/backgrid

  Copyright (c) 2012 Jimmy Yuen Ho Wong
  Licensed under the MIT @license.
*/

<|endoftext|>


<commit_before>import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('ember-kalendae', 'Integration | Component | ember kalendae', {
  integration: true
});

test('it allows block usage', function(assert) {
  assert.expect(1);

  this.render(hbs`
    {{#ember-kalendae}}
      template block text
    {{/ember-kalendae}}
  `);
  assert.ok(this.$().text().trim().indexOf('template block text') >= 0);
});

test('it initialises correctly without any config', function(assert) {
  assert.expect(1);

  this.set('kalendae', null);
  this.render(hbs`{{ember-kalendae instanceAPI=(action (mut kalendae))}}`);

  // it should initialise to today
  assert.equal(
    this.get('kalendae').getSelected(),
    new Date().toISOString().slice(0,10)
  );
});

test('it passes mode through to kalendae correctly', function(assert) {
  assert.expect(1);

  this.set('mode', 'range');

  this.render(hbs`
    {{ember-kalendae
      instanceAPI=(action (mut kalendae))
      mode=mode
    }}`
  );

  assert.equal(
    this.get('kalendae').settings.mode,
    this.get('mode')
  );
});

test('it passes months through to kalendae correctly', function(assert) {
  assert.expect(1);

  this.set('months', '2');

  this.render(hbs`
    {{ember-kalendae
      instanceAPI=(action (mut kalendae))
      months=months
    }}`
  );

  assert.equal(
    this.get('kalendae').settings.months,
    this.get('months')
  );
});
<commit_msg>=it passes it passes weekStart through to kalendae correctly<commit_after>import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('ember-kalendae', 'Integration | Component | ember kalendae', {
  integration: true
});

test('it allows block usage', function(assert) {
  assert.expect(1);

  this.render(hbs`
    {{#ember-kalendae}}
      template block text
    {{/ember-kalendae}}
  `);
  assert.ok(this.$().text().trim().indexOf('template block text') >= 0);
});

test('it initialises correctly without any config', function(assert) {
  assert.expect(1);

  this.set('kalendae', null);
  this.render(hbs`{{ember-kalendae instanceAPI=(action (mut kalendae))}}`);

  // it should initialise to today
  assert.equal(
    this.get('kalendae').getSelected(),
    new Date().toISOString().slice(0,10)
  );
});

test('it passes mode through to kalendae correctly', function(assert) {
  assert.expect(1);

  this.set('mode', 'range');

  this.render(hbs`
    {{ember-kalendae
      instanceAPI=(action (mut kalendae))
      mode=mode
    }}`
  );

  assert.equal(
    this.get('kalendae').settings.mode,
    this.get('mode')
  );
});

test('it passes months through to kalendae correctly', function(assert) {
  assert.expect(1);

  this.set('months', '2');

  this.render(hbs`
    {{ember-kalendae
      instanceAPI=(action (mut kalendae))
      months=months
    }}`
  );

  assert.equal(
    this.get('kalendae').settings.months,
    this.get('months')
  );
});

test('it passes weekStart through to kalendae correctly', function(assert) {
  assert.expect(1);

  this.set('weekStart', '2');

  this.render(hbs`
    {{ember-kalendae
      instanceAPI=(action (mut kalendae))
      weekStart=weekStart
    }}`
  );

  assert.equal(
    this.get('kalendae').settings.weekStart,
    this.get('weekStart')
  );
});
<|endoftext|>


<commit_before>(function() {
  'use strict';

  var page = require('webpage').create();
  var args = require('system').args;
  var params = {};
  var regexp = /^([^=]+)=([^$]+)/;

  args.forEach(function(arg) {
    var parts = arg.match(regexp);
    if (!parts) { return; }
    params[parts[1]] = parts[2];
  });

  var usage = "url=<url> png=<filename> width=<width> height=<height> cookiename=<cookiename> sessionid=<sessionid> domain=<domain>";

  if (!params.url || !params.png || !params.cookiename || ! params.sessionid || !params.domain) {
    console.log(usage);
    phantom.exit();
  }

  phantom.addCookie({
    'name': params.cookiename,
    'value': params.sessionid,
    'domain': params.domain
  });

  page.viewportSize = {
    width: params.width || '800',
    height: params.height || '400'
  };

  var tries = 0;

  page.open(params.url, function (status) {
    // console.log('Loading a web page: ' + params.url + ' status: ' + status);

    function checkIsReady() {
      var canvas = page.evaluate(function() {
        if (!window.angular) { return false; }
        var body = window.angular.element(document.body);   // 1
        if (!body.scope) { return false; }

        var rootScope = body.scope();
        if (!rootScope) {return false;}
        if (!rootScope.performance) { return false; }
        var panelsToLoad = window.angular.element('div.panel').length;
        return rootScope.performance.panelsRendered >= panelsToLoad;
      });

      if (canvas || tries === 1000) {
        var bb = page.evaluate(function () {
          return document.getElementsByClassName("main-view")[0].getBoundingClientRect();
        });

        page.clipRect = {
          top:    bb.top,
          left:   bb.left,
          width:  bb.width,
          height: bb.height
        };
        page.render(params.png);
        phantom.exit();
      }
      else {
        tries++;
        setTimeout(checkIsReady, 10);
      }
    }

    setTimeout(checkIsReady, 200);
  });
})();
<commit_msg>fix(render): fixed issue with image renderer caused by disabling angular debug info<commit_after>(function() {
  'use strict';

  var page = require('webpage').create();
  var args = require('system').args;
  var params = {};
  var regexp = /^([^=]+)=([^$]+)/;

  args.forEach(function(arg) {
    var parts = arg.match(regexp);
    if (!parts) { return; }
    params[parts[1]] = parts[2];
  });

  var usage = "url=<url> png=<filename> width=<width> height=<height> cookiename=<cookiename> sessionid=<sessionid> domain=<domain>";

  if (!params.url || !params.png || !params.cookiename || ! params.sessionid || !params.domain) {
    console.log(usage);
    phantom.exit();
  }

  phantom.addCookie({
    'name': params.cookiename,
    'value': params.sessionid,
    'domain': params.domain
  });

  page.viewportSize = {
    width: params.width || '800',
    height: params.height || '400'
  };

  var tries = 0;

  page.open(params.url, function (status) {
    // console.log('Loading a web page: ' + params.url + ' status: ' + status);

    function checkIsReady() {
      var canvas = page.evaluate(function() {
        if (!window.angular) { return false; }
        var body = window.angular.element(document.body);
        if (!body.scope) { return false; }

        var rootScope = body.injector().get('$rootScope');
        if (!rootScope) {return false;}
        if (!rootScope.performance) { return false; }
        var panelsToLoad = window.angular.element('div.panel').length;
        return rootScope.performance.panelsRendered >= panelsToLoad;
      });

      if (canvas || tries === 1000) {
        var bb = page.evaluate(function () {
          return document.getElementsByClassName("main-view")[0].getBoundingClientRect();
        });

        page.clipRect = {
          top:    bb.top,
          left:   bb.left,
          width:  bb.width,
          height: bb.height
        };
        page.render(params.png);
        phantom.exit();
      }
      else {
        tries++;
        setTimeout(checkIsReady, 10);
      }
    }

    setTimeout(checkIsReady, 200);
  });
})();
<|endoftext|>


<commit_before>const parse = require('../parse')

/**
 * @module fantastic-bits/parse
 */
module.exports = {turnInfo}

function turnInfo (readline) {
  return parse.entities(readline, 'id', 'type', 'x', 'y', 'vx', 'vy', 'state')
    .map(entity => Object.assign(entity, {
      position: {x: entity.x, y: entity.y},
      velocity: {x: entity.vx, y: entity.vy},
      hasSnaffle: entity.state === 1,
      isWizard: entity.type === 'WIZARD',
      isOpponent: entity.type === 'OPPONENT_WIZARD',
      isSnaffle: entity.type === 'SNAFFLE',
      isBludger: entity.type === 'BLUDGER'
    }))
    .map(entity => Object.assign(entity, {
      isPlayer: entity.isWizard || entity.isOpponent,
      isBall: entity.isSnaffle || entity.isBludger,
      maxThrust: entity.isWizard ? 150 : undefined,
      maxThrowingForce: entity.isWizard ? 500 : undefined
    }))
    .map(entity => Object.assign(entity, {
      snaffle: entity.isWizard ? entities.find(other => other.x === entity.x && other.y === entity.y) : undefined
    }))
    .reduce((entities, entity) => {
      entities.all.push(entity)
      if (entity.isPlayer) entities.players.push(entity)
      if (entity.isWizard) entities.wizards.push(entity)
      if (entity.isOpponent) entities.opponents.push(entity)
      if (entity.isBall) entities.balls.push(entity)
      if (entity.isSnaffle) entities.snaffles.push(entity)
      if (entity.isBludger) entities.bludgers.push(entity)
      return entities
    }, {
      all: [],
      players: [],
      wizards: [],
      opponents: [],
      balls: [],
      snaffles: [],
      bludgers: []
    })
}
<commit_msg>fix(fantastic-bits/parse): entities is not defined<commit_after>const parse = require('../parse')

/**
 * @module fantastic-bits/parse
 */
module.exports = {turnInfo}

function turnInfo (readline) {
  return parse.entities(readline, 'id', 'type', 'x', 'y', 'vx', 'vy', 'state')
    .map(entity => Object.assign(entity, {
      position: {x: entity.x, y: entity.y},
      velocity: {x: entity.vx, y: entity.vy},
      hasSnaffle: entity.state === 1,
      isWizard: entity.type === 'WIZARD',
      isOpponent: entity.type === 'OPPONENT_WIZARD',
      isSnaffle: entity.type === 'SNAFFLE',
      isBludger: entity.type === 'BLUDGER'
    }))
    .map(entity => Object.assign(entity, {
      isPlayer: entity.isWizard || entity.isOpponent,
      isBall: entity.isSnaffle || entity.isBludger,
      maxThrust: entity.isWizard ? 150 : undefined,
      maxThrowingForce: entity.isWizard ? 500 : undefined
    }))
    .map((entity, _, entities) => Object.assign(entity, {
      snaffle: entity.isWizard ? entities.find(other => other.x === entity.x && other.y === entity.y) : undefined
    }))
    .reduce((entities, entity) => {
      entities.all.push(entity)
      if (entity.isPlayer) entities.players.push(entity)
      if (entity.isWizard) entities.wizards.push(entity)
      if (entity.isOpponent) entities.opponents.push(entity)
      if (entity.isBall) entities.balls.push(entity)
      if (entity.isSnaffle) entities.snaffles.push(entity)
      if (entity.isBludger) entities.bludgers.push(entity)
      return entities
    }, {
      all: [],
      players: [],
      wizards: [],
      opponents: [],
      balls: [],
      snaffles: [],
      bludgers: []
    })
}
<|endoftext|>


<commit_before>/*
 * Supports loading System.register via script tag injection
 */

import { systemJSPrototype } from '../system-core';
import { hasDocument, baseUrl, resolveUrl } from '../common';

const systemRegister = systemJSPrototype.register;
systemJSPrototype.register = function (deps, declare) {
  systemRegister.call(this, deps, declare);
};

systemJSPrototype.instantiate = function (url, firstParentUrl) {
  const loader = this;
  return new Promise(function (resolve, reject) {
    let err;

    function windowErrorListener(evt) {
      if (evt.filename === url)
        err = evt.error;
    }

    window.addEventListener('error', windowErrorListener);

    const script = document.createElement('script');
    script.charset = 'utf-8';
    script.async = true;
    script.crossOrigin = 'anonymous';
    script.addEventListener('error', function () {
      window.removeEventListener('error', windowErrorListener);
      reject(Error('Error loading ' + url + (firstParentUrl ? ' from ' + firstParentUrl : '')));
    });
    script.addEventListener('load', function () {
      window.removeEventListener('error', windowErrorListener);
      document.head.removeChild(script);
      // Note that if an error occurs that isn't caught by this if statement,
      // that getRegister will return null and a "did not instantiate" error will be thrown.
      if (err) {
        reject(err);
      }
      else {
        resolve(loader.getRegister());
      }
    });
    script.src = url;
    document.head.appendChild(script);
  });
};

if (hasDocument) {
  window.addEventListener('DOMContentLoaded', loadScriptModules);
  loadScriptModules();
}

function loadScriptModules() {
  document.querySelectorAll('script[type=systemjs-module]').forEach(function (script) {
    if (script.src) {
      System.import(script.src.slice(0, 7) === 'import:' ? script.src.slice(7) : resolveUrl(script.src, baseUrl));
    }
  });
}<commit_msg>Replace querySelectorAll.forEach with Array.prototype.forEach (#2033)<commit_after>/*
 * Supports loading System.register via script tag injection
 */

import { systemJSPrototype } from '../system-core';
import { hasDocument, baseUrl, resolveUrl } from '../common';

const systemRegister = systemJSPrototype.register;
systemJSPrototype.register = function (deps, declare) {
  systemRegister.call(this, deps, declare);
};

systemJSPrototype.instantiate = function (url, firstParentUrl) {
  const loader = this;
  return new Promise(function (resolve, reject) {
    let err;

    function windowErrorListener(evt) {
      if (evt.filename === url)
        err = evt.error;
    }

    window.addEventListener('error', windowErrorListener);

    const script = document.createElement('script');
    script.charset = 'utf-8';
    script.async = true;
    script.crossOrigin = 'anonymous';
    script.addEventListener('error', function () {
      window.removeEventListener('error', windowErrorListener);
      reject(Error('Error loading ' + url + (firstParentUrl ? ' from ' + firstParentUrl : '')));
    });
    script.addEventListener('load', function () {
      window.removeEventListener('error', windowErrorListener);
      document.head.removeChild(script);
      // Note that if an error occurs that isn't caught by this if statement,
      // that getRegister will return null and a "did not instantiate" error will be thrown.
      if (err) {
        reject(err);
      }
      else {
        resolve(loader.getRegister());
      }
    });
    script.src = url;
    document.head.appendChild(script);
  });
};

if (hasDocument) {
  window.addEventListener('DOMContentLoaded', loadScriptModules);
  loadScriptModules();
}

function loadScriptModules() {
  Array.prototype.forEach.call(
    document.querySelectorAll('script[type=systemjs-module]'), function (script) {
      if (script.src) {
        System.import(script.src.slice(0, 7) === 'import:' ? script.src.slice(7) : resolveUrl(script.src, baseUrl));
      }
    });
}<|endoftext|>


<commit_before>/*jslint node: true */
/*global module, require, Number*/
'use strict';
var newCallback = require('./../construct/newCallback.js'),
    isValidName = require('./../bool/isValidName.js');
Number.isInteger = Number.isInteger || function(value) {     // isInteger: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
        return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
    };
/**
 * This internal method is used to extract a specific state, view, or layer from within a {@link ScapeObject} 'array' based on a
 * 'key' and 'metaProperty' pairing.
 *
 * @function fetchFromScape
 * @memberof socioscapes
 * @param {Number} key - An integer value that corresponds to an entry in the 'array' argument.
 * @param {Object} metaProperty - The property in the '.meta' member that we are trying to match to (usually 'name').
 * @param {Object} array - The {@link ScapeObject} array that contains the state, view, or layer we are looking for.
 * @return this {Object}
 */
function fetchFromScape(key, metaProperty, array) {
    var callback = newCallback(arguments),
        myKey = false;
    if (array) {
        if (Number.isInteger(key)) {
            myKey = (array[key]) ? array[key]:false;
        } else if (isValidName(key)) {
            for (var i = 0; i < array.length; i++) {
                if (key === array[i].meta[metaProperty]) {
                    myKey = array[i];
                }
            }
        }
    }
    callback(myKey);
    return myKey;
}
module.exports = fetchFromScape;<commit_msg>fixed jsdoc variable type<commit_after>/*jslint node: true */
/*global module, require, Number*/
'use strict';
var newCallback = require('./../construct/newCallback.js'),
    isValidName = require('./../bool/isValidName.js');
/**
 * This internal method is used to extract a specific state, view, or layer from within a {@link ScapeObject} 'array' based on a
 * 'key' and 'metaProperty' pairing.
 *
 * @function fetchFromScape
 * @memberof socioscapes
 * @param {(number|string)} key - An integer value that corresponds to an entry in the 'array' argument or a string that
 * corresponds to a metaProperty value.
 * @param {Object} metaProperty - The property in the '.meta' member that we are trying to match to (usually 'name').
 * @param {Object} array - The {@link ScapeObject} array that contains the state, view, or layer we are looking for.
 * @return this {Object}
 */
Number.isInteger = Number.isInteger || function(value) {     // isInteger: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger
        return typeof value === "number" && isFinite(value) && Math.floor(value) === value;
    };
function fetchFromScape(key, metaProperty, array) {
    var callback = newCallback(arguments),
        myKey = false;
    if (array) {
        if (Number.isInteger(key)) {
            myKey = (array[key]) ? array[key]:false;
        } else if (isValidName(key)) {
            for (var i = 0; i < array.length; i++) {
                if (key === array[i].meta[metaProperty]) {
                    myKey = array[i];
                }
            }
        }
    }
    callback(myKey);
    return myKey;
}
module.exports = fetchFromScape;<|endoftext|>