<commit_before>(function(fin) {
    'use strict';
    const poolSize = 3;

    /**
     * Manages a pool of OpenFin windows. The pool is used for performance improvements,
     * as there is an overhead to creating new windows.
     * When a window is taken from the pool a new one is created and added.
     */
    class FreeWindowPool {
        constructor($q, configService) {
            this.pool = [];
            this.$q = $q;
            this.configService = configService;

            for (var i = 0; i < poolSize; i++) {
                this._fillPool();
            }
        }

        _fillPool() {
            var deferred = this.$q.defer();
            this.pool.push({ promise: deferred.promise, window: new fin.desktop.Window(
                    this.configService.getWindowConfig(),
                    () => { deferred.resolve(); }
                )
            });
        }

        fetch() {
            var pooledWindow = this.pool.shift();
            this._fillPool();

            return pooledWindow;
        }
    }

    /**
     * Keeps an internal count and cache of the number of main application windows open.
     * The count is used to know when the last window has been closed, to close the application.
     */
    class WindowTracker {
        constructor() {
            this.openWindows = {};
            this.mainWindowsCache = [];
            this.windowsOpen = 0;
        }

        add(_window) {
            this.mainWindowsCache.unshift(_window);
            this.addWindowStateWatchers(_window);
            this.windowsOpen++;
        }

        addWindowStateWatchers(_window) {
            var focusEvent = this.onFocus(_window);
            var minimiseEvent = this.onMinimise(_window);
            _window.addEventListener('focused', focusEvent);
            _window.addEventListener('minimized', minimiseEvent);

            _window.addEventListener('closed', () => {
                _window.removeEventListener('focused', focusEvent);
                _window.removeEventListener('minimized', minimiseEvent);
            });
        }

        onFocus(_window) {
            return () => {
                this.mainWindowsCache.splice(this.mainWindowsCache.indexOf(_window), 1);
                this.mainWindowsCache.unshift(_window);
            };
        }

        onMinimise(_window) {
            return () => {
                this.mainWindowsCache.splice(this.mainWindowsCache.indexOf(_window), 1);
                this.mainWindowsCache.push(_window);
            };
        }

        addTearout(name, _window) {
            if (!this.openWindows[name]) {
                this.openWindows[name] = [].concat(_window);
            } else {
                this.openWindows[name].push(_window);
            }
        }

        dispose(_window, closedCb) {
            var parent = this.openWindows[_window.name];
            if (parent) {
                // Close all the OpenFin tearout windows associated with the closing parent.
                parent.forEach((child) => child.close());
            }

            if (this.windowsOpen !== 1) {
                closedCb();
            }

            delete this.openWindows[_window.name];
            var index = this.mainWindowsCache.indexOf(_window);
            this.mainWindowsCache.splice(index, 1);

            this.windowsOpen--;

            if (this.windowsOpen === 0) {
                // This was the last open window; close the application.
                window.close();
            }
        }

        getMainWindows() {
            return this.mainWindowsCache;
        }
    }

    /**
     * Class to determine whether a stored tearout window is overlapping
     * a different main window, and allow moving stocks between windows.
     */
    class DragService {
        constructor(storeService, geometryService, windowTracker, tearoutWindow, $q, openFinWindow) {
            this.storeService = storeService;
            this.geometryService = geometryService;
            this.windowTracker = windowTracker;
            this.tearoutWindow = tearoutWindow;
            this.$q = $q;
            this.openFinWindow = openFinWindow;
            this.otherInstance = null;
        }

        overThisInstance(selector) {
            var nativeWindow = this.openFinWindow.getNativeWindow();
            var element = nativeWindow.document.querySelector(selector || 'body');
            var over = this.geometryService.elementIntersect(this.tearoutWindow, nativeWindow, element);

            if (over) {
                this.clearOtherInstance();
            }
            return over;
        }

        updateIntersections(selector, cb) {
            var mainWindows = this.windowTracker.getMainWindows(),
                result = false,
                promises = [];

            var filteredWindows = mainWindows.filter((mw) => mw.name !== this.openFinWindow.name);
            filteredWindows.forEach((mainWindow) => {
                var deferred = this.$q.defer();
                promises.push(deferred.promise);
                mainWindow.getState((state) => {
                    var nativeWindow = mainWindow.getNativeWindow();
                    var element = nativeWindow.document.querySelector(selector || 'body');

                    if (!result && state !== 'minimized' && this.geometryService.elementIntersect(this.tearoutWindow, nativeWindow, element)) {
                        this.setOtherInstance(mainWindow);
                        result = true;
                    }

                    deferred.resolve();
                });
            });

            this.$q.all(promises).then(() => {
                if (cb) {
                    cb();
                }

                if (!result) {
                    this.clearOtherInstance();
                }
            });
        }

        overAnotherInstance(selector, cb) {
            this.updateIntersections(selector, () => {
                if (cb) {
                    cb(this.otherInstance !== null);
                }
            });
        }

        setOtherInstance(newInstance) {
            if (this.otherInstance !== newInstance) {
                this.messageOtherInstance('dragout');
                this.otherInstance = newInstance;
                this.messageOtherInstance('dragin');
            }
        }

        clearOtherInstance() {
            this.setOtherInstance(null);
        }

        destroy() {
            this.clearOtherInstance();
        }

        messageOtherInstance(message) {
            if (this.otherInstance) {
                var event = new Event(message);
                this.otherInstance.getNativeWindow().dispatchEvent(event);
            }
        }

        moveToOtherInstance(stock) {
            this.storeService.open(this.otherInstance.name).add(stock);
            this.otherInstance.bringToFront();
        }
    }

    /**
     * Class that creates and governs OpenFin windows.
     */
    class WindowCreationService {
        constructor($rootScope, storeService, geometryService, $q, configService) {
            this.storeService = storeService;
            this.geometryService = geometryService;
            this.$q = $q;
            this.configService = configService;
            this.windowTracker = new WindowTracker();
            this.firstName = true;
            this.pool = null;
            this.closedWindowsListeners = [];

            $rootScope.$on('closedWindowChange', () => this.notifyClosedWindowListeners());

            this.ready(() => { this.pool = new FreeWindowPool($q, configService); });
        }

        createMainWindow(name, isCompact, successCb) {
            var windowCreatedCb = (newWindow) => {
                newWindow.getNativeWindow().windowService = this;
                newWindow.getNativeWindow().storeService = this.storeService;

                this.windowTracker.add(newWindow);

                if (successCb) {
                    successCb(newWindow);
                }

                this.storeService.open(newWindow.name).openWindow();

                newWindow.show();
                newWindow.bringToFront();
                this.snapToScreenBounds(newWindow);
            };

            var mainWindow;
            if (name) {
                mainWindow = new fin.desktop.Window(
                    isCompact ?
                        this.configService.getCompactConfig(name) :
                        this.configService.getWindowConfig(name),
                    () => {
                        windowCreatedCb(mainWindow);
                    }
                );
            } else {
                var poolWindow = this.pool.fetch();
                mainWindow = poolWindow.window;
                if (isCompact) {
                    this.updateOptions(poolWindow.window, true);
                    poolWindow.window.resizeTo(230, 500, 'top-right');
                }

                poolWindow.promise.then(() => {
                    windowCreatedCb(mainWindow);
                });
            }

            var closedEvent = (e) => {
                this.windowTracker.dispose(mainWindow, () => {
                    this.storeService.open(mainWindow.name).closeWindow();
                    mainWindow.removeEventListener('closed', closedEvent);
                });
            };

            mainWindow.addEventListener('closed', closedEvent);
        }

        addClosedWindowListener(listener) {
            this.closedWindowsListeners.push(listener);
        }

        removeClosedWindowListener(listener) {
            this.closedWindowsListeners.splice(this.closedWindowsListeners.indexOf(listener), 1);
        }

        notifyClosedWindowListeners() {
            this.closedWindowsListeners.forEach((listener) => listener());
        }

        getTargetMonitor(x, y, callback) {
            fin.desktop.System.getMonitorInfo((info) => {
                var monitors = info.nonPrimaryMonitors.concat(info.primaryMonitor);
                let closestMonitor = monitors[0];
                let closestDistance = Number.MAX_VALUE;

                for (var monitor of monitors) {

                    let monitorRect = monitor.monitorRect;

                    // If the window's top-left is within the monitor's bounds, use that + stop
                    if (x >= monitorRect.left && x <= monitorRect.right &&
                            y >= monitorRect.top && y <= monitorRect.bottom) {

                        callback(monitor);
                        return;

                    } else {

                        // Otherwise, keep track of the closest, and if the window is not
                        // within any monitor bounds, use the closest.
                        var midX = monitorRect.left + monitorRect.right / 2;
                        var midY = monitorRect.top + monitorRect.bottom / 2;
                        var distance = Math.pow(midX - x, 2) + Math.pow(midY - y, 2);
                        if (distance < closestDistance) {
                            closestDistance = distance;
                            closestMonitor = monitor;
                        }

                    }
                }
                callback(closestMonitor);
            });
        }

        snapToScreenBounds(targetWindow) {
            targetWindow.getBounds((bounds) => {
                this.getTargetMonitor(bounds.left, bounds.top, (monitor) => {

                    let availableRect = monitor.availableRect;

                    if (bounds.top < availableRect.top) {
                        bounds.top = availableRect.top;
                    } else if (bounds.top + bounds.height > availableRect.bottom) {
                        bounds.top = availableRect.bottom - bounds.height;
                    }

                    targetWindow.setBounds(bounds.left, bounds.top, bounds.width, bounds.height);
                });
            });
        }

        createTearoutWindow(parentName) {
            var tearoutWindow = new fin.desktop.Window(this.configService.getTearoutConfig());

            this.windowTracker.addTearout(parentName, tearoutWindow);

            return tearoutWindow;
        }

        updateOptions(_window, isCompact) {
            if (isCompact) {
                _window.updateOptions({
                    resizable: false,
                    minHeight: 500,
                    minWidth: 230,
                    maximizable: false
                });
            } else {
                _window.updateOptions({
                    resizable: true,
                    minHeight: 510,
                    minWidth: 918,
                    maximizable: true
                });
            }
        }

        ready(cb) {
            fin.desktop.main(cb);
        }

        getWindow(name) {
            return this.windowTracker.getMainWindows().filter((w) => w.name === name)[0];
        }

        registerDrag(tearoutWindow, openFinWindow) {
            return new DragService(
                this.storeService,
                this.geometryService,
                this.windowTracker,
                tearoutWindow,
                this.$q,
                openFinWindow);
        }
    }
    WindowCreationService.$inject = ['$rootScope', 'storeService', 'geometryService', '$q', 'configService'];

    angular.module('stockflux.window')
        .service('windowCreationService', WindowCreationService);
}(fin));
<commit_msg>Only shunt window on top edge<commit_after>(function(fin) {
    'use strict';
    const poolSize = 3;

    /**
     * Manages a pool of OpenFin windows. The pool is used for performance improvements,
     * as there is an overhead to creating new windows.
     * When a window is taken from the pool a new one is created and added.
     */
    class FreeWindowPool {
        constructor($q, configService) {
            this.pool = [];
            this.$q = $q;
            this.configService = configService;

            for (var i = 0; i < poolSize; i++) {
                this._fillPool();
            }
        }

        _fillPool() {
            var deferred = this.$q.defer();
            this.pool.push({ promise: deferred.promise, window: new fin.desktop.Window(
                    this.configService.getWindowConfig(),
                    () => { deferred.resolve(); }
                )
            });
        }

        fetch() {
            var pooledWindow = this.pool.shift();
            this._fillPool();

            return pooledWindow;
        }
    }

    /**
     * Keeps an internal count and cache of the number of main application windows open.
     * The count is used to know when the last window has been closed, to close the application.
     */
    class WindowTracker {
        constructor() {
            this.openWindows = {};
            this.mainWindowsCache = [];
            this.windowsOpen = 0;
        }

        add(_window) {
            this.mainWindowsCache.unshift(_window);
            this.addWindowStateWatchers(_window);
            this.windowsOpen++;
        }

        addWindowStateWatchers(_window) {
            var focusEvent = this.onFocus(_window);
            var minimiseEvent = this.onMinimise(_window);
            _window.addEventListener('focused', focusEvent);
            _window.addEventListener('minimized', minimiseEvent);

            _window.addEventListener('closed', () => {
                _window.removeEventListener('focused', focusEvent);
                _window.removeEventListener('minimized', minimiseEvent);
            });
        }

        onFocus(_window) {
            return () => {
                this.mainWindowsCache.splice(this.mainWindowsCache.indexOf(_window), 1);
                this.mainWindowsCache.unshift(_window);
            };
        }

        onMinimise(_window) {
            return () => {
                this.mainWindowsCache.splice(this.mainWindowsCache.indexOf(_window), 1);
                this.mainWindowsCache.push(_window);
            };
        }

        addTearout(name, _window) {
            if (!this.openWindows[name]) {
                this.openWindows[name] = [].concat(_window);
            } else {
                this.openWindows[name].push(_window);
            }
        }

        dispose(_window, closedCb) {
            var parent = this.openWindows[_window.name];
            if (parent) {
                // Close all the OpenFin tearout windows associated with the closing parent.
                parent.forEach((child) => child.close());
            }

            if (this.windowsOpen !== 1) {
                closedCb();
            }

            delete this.openWindows[_window.name];
            var index = this.mainWindowsCache.indexOf(_window);
            this.mainWindowsCache.splice(index, 1);

            this.windowsOpen--;

            if (this.windowsOpen === 0) {
                // This was the last open window; close the application.
                window.close();
            }
        }

        getMainWindows() {
            return this.mainWindowsCache;
        }
    }

    /**
     * Class to determine whether a stored tearout window is overlapping
     * a different main window, and allow moving stocks between windows.
     */
    class DragService {
        constructor(storeService, geometryService, windowTracker, tearoutWindow, $q, openFinWindow) {
            this.storeService = storeService;
            this.geometryService = geometryService;
            this.windowTracker = windowTracker;
            this.tearoutWindow = tearoutWindow;
            this.$q = $q;
            this.openFinWindow = openFinWindow;
            this.otherInstance = null;
        }

        overThisInstance(selector) {
            var nativeWindow = this.openFinWindow.getNativeWindow();
            var element = nativeWindow.document.querySelector(selector || 'body');
            var over = this.geometryService.elementIntersect(this.tearoutWindow, nativeWindow, element);

            if (over) {
                this.clearOtherInstance();
            }
            return over;
        }

        updateIntersections(selector, cb) {
            var mainWindows = this.windowTracker.getMainWindows(),
                result = false,
                promises = [];

            var filteredWindows = mainWindows.filter((mw) => mw.name !== this.openFinWindow.name);
            filteredWindows.forEach((mainWindow) => {
                var deferred = this.$q.defer();
                promises.push(deferred.promise);
                mainWindow.getState((state) => {
                    var nativeWindow = mainWindow.getNativeWindow();
                    var element = nativeWindow.document.querySelector(selector || 'body');

                    if (!result && state !== 'minimized' && this.geometryService.elementIntersect(this.tearoutWindow, nativeWindow, element)) {
                        this.setOtherInstance(mainWindow);
                        result = true;
                    }

                    deferred.resolve();
                });
            });

            this.$q.all(promises).then(() => {
                if (cb) {
                    cb();
                }

                if (!result) {
                    this.clearOtherInstance();
                }
            });
        }

        overAnotherInstance(selector, cb) {
            this.updateIntersections(selector, () => {
                if (cb) {
                    cb(this.otherInstance !== null);
                }
            });
        }

        setOtherInstance(newInstance) {
            if (this.otherInstance !== newInstance) {
                this.messageOtherInstance('dragout');
                this.otherInstance = newInstance;
                this.messageOtherInstance('dragin');
            }
        }

        clearOtherInstance() {
            this.setOtherInstance(null);
        }

        destroy() {
            this.clearOtherInstance();
        }

        messageOtherInstance(message) {
            if (this.otherInstance) {
                var event = new Event(message);
                this.otherInstance.getNativeWindow().dispatchEvent(event);
            }
        }

        moveToOtherInstance(stock) {
            this.storeService.open(this.otherInstance.name).add(stock);
            this.otherInstance.bringToFront();
        }
    }

    /**
     * Class that creates and governs OpenFin windows.
     */
    class WindowCreationService {
        constructor($rootScope, storeService, geometryService, $q, configService) {
            this.storeService = storeService;
            this.geometryService = geometryService;
            this.$q = $q;
            this.configService = configService;
            this.windowTracker = new WindowTracker();
            this.firstName = true;
            this.pool = null;
            this.closedWindowsListeners = [];

            $rootScope.$on('closedWindowChange', () => this.notifyClosedWindowListeners());

            this.ready(() => { this.pool = new FreeWindowPool($q, configService); });
        }

        createMainWindow(name, isCompact, successCb) {
            var windowCreatedCb = (newWindow) => {
                newWindow.getNativeWindow().windowService = this;
                newWindow.getNativeWindow().storeService = this.storeService;

                this.windowTracker.add(newWindow);

                if (successCb) {
                    successCb(newWindow);
                }

                this.storeService.open(newWindow.name).openWindow();

                newWindow.show();
                newWindow.bringToFront();
                this.snapToScreenBounds(newWindow);
            };

            var mainWindow;
            if (name) {
                mainWindow = new fin.desktop.Window(
                    isCompact ?
                        this.configService.getCompactConfig(name) :
                        this.configService.getWindowConfig(name),
                    () => {
                        windowCreatedCb(mainWindow);
                    }
                );
            } else {
                var poolWindow = this.pool.fetch();
                mainWindow = poolWindow.window;
                if (isCompact) {
                    this.updateOptions(poolWindow.window, true);
                    poolWindow.window.resizeTo(230, 500, 'top-right');
                }

                poolWindow.promise.then(() => {
                    windowCreatedCb(mainWindow);
                });
            }

            var closedEvent = (e) => {
                this.windowTracker.dispose(mainWindow, () => {
                    this.storeService.open(mainWindow.name).closeWindow();
                    mainWindow.removeEventListener('closed', closedEvent);
                });
            };

            mainWindow.addEventListener('closed', closedEvent);
        }

        addClosedWindowListener(listener) {
            this.closedWindowsListeners.push(listener);
        }

        removeClosedWindowListener(listener) {
            this.closedWindowsListeners.splice(this.closedWindowsListeners.indexOf(listener), 1);
        }

        notifyClosedWindowListeners() {
            this.closedWindowsListeners.forEach((listener) => listener());
        }

        getTargetMonitor(x, y, callback) {
            fin.desktop.System.getMonitorInfo((info) => {
                var monitors = info.nonPrimaryMonitors.concat(info.primaryMonitor);
                let closestMonitor = monitors[0];
                let closestDistance = Number.MAX_VALUE;

                for (var monitor of monitors) {

                    let monitorRect = monitor.monitorRect;

                    // If the window's top-left is within the monitor's bounds, use that + stop
                    if (x >= monitorRect.left && x <= monitorRect.right &&
                            y >= monitorRect.top && y <= monitorRect.bottom) {

                        callback(monitor);
                        return;

                    } else {

                        // Otherwise, keep track of the closest, and if the window is not
                        // within any monitor bounds, use the closest.
                        var midX = monitorRect.left + monitorRect.right / 2;
                        var midY = monitorRect.top + monitorRect.bottom / 2;
                        var distance = Math.pow(midX - x, 2) + Math.pow(midY - y, 2);
                        if (distance < closestDistance) {
                            closestDistance = distance;
                            closestMonitor = monitor;
                        }

                    }
                }
                callback(closestMonitor);
            });
        }

        snapToScreenBounds(targetWindow) {
            targetWindow.getBounds((bounds) => {
                this.getTargetMonitor(bounds.left, bounds.top, (monitor) => {

                    let availableRect = monitor.availableRect;

                    if (bounds.top < availableRect.top) {
                        bounds.top = availableRect.top;
                    }

                    targetWindow.setBounds(bounds.left, bounds.top, bounds.width, bounds.height);
                });
            });
        }

        createTearoutWindow(parentName) {
            var tearoutWindow = new fin.desktop.Window(this.configService.getTearoutConfig());

            this.windowTracker.addTearout(parentName, tearoutWindow);

            return tearoutWindow;
        }

        updateOptions(_window, isCompact) {
            if (isCompact) {
                _window.updateOptions({
                    resizable: false,
                    minHeight: 500,
                    minWidth: 230,
                    maximizable: false
                });
            } else {
                _window.updateOptions({
                    resizable: true,
                    minHeight: 510,
                    minWidth: 918,
                    maximizable: true
                });
            }
        }

        ready(cb) {
            fin.desktop.main(cb);
        }

        getWindow(name) {
            return this.windowTracker.getMainWindows().filter((w) => w.name === name)[0];
        }

        registerDrag(tearoutWindow, openFinWindow) {
            return new DragService(
                this.storeService,
                this.geometryService,
                this.windowTracker,
                tearoutWindow,
                this.$q,
                openFinWindow);
        }
    }
    WindowCreationService.$inject = ['$rootScope', 'storeService', 'geometryService', '$q', 'configService'];

    angular.module('stockflux.window')
        .service('windowCreationService', WindowCreationService);
}(fin));
<|endoftext|>


<commit_before><commit_msg>support single and double quotes<commit_after><|endoftext|>


<commit_before>
define (['jquery', 'facebook', 'LastFMProxy'], function ($, facebook, LastFMProxy) {

    // Stats object for every artist (associative array)
    var artistStats = [];

    // Number of artists liked by the user
    var artistCount = 0;

    // Number of artist already analyzed
    var analyzedArtistCount = 0;

    function getArtists(callback) {
        FB.init({
            appId      : '1468034890110746',
            xfbml      : true,
            status     : true,
            cookie     : true,
            version    : 'v2.1'
        });

        FB.login(function () {
            FB.api(
                "/me/music",
                function (response) {
                      artistCount = response.data.length || 0;
                      callback(response.data || []);

            });
        }, {scope: 'user_likes'});
    }

    // Progress & status
    function showModal (title, text) {
        $('#modalTitle').text(title);
        $('#modalText').text(text);
        $('#myModal').modal('show');
    }

    function showError (){
        $('#loading').hide();
        $('#title').text($('#error-title').val());
        $('#status').text($('#error-status').val());
    }

    function updateProgress () {
        analyzedArtistCount++;
        var percent = analyzedArtistCount / artistCount;
        var progress = percent*100;
        $('#appProgress').css('width', progress + '%');
        console.log('Total: ' + artistCount + ' Analyzed: ' + analyzedArtistCount + ' Percent: ' + percent + ' Progress: ' + progress);
    }

    function artistCallback (artist) {
        var initialStatus = $('#initial-status').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function albumCallback (artist) {
         var initialStatus = $('#initial-status-album').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function fanCallback (artist) {
        var initialStatus = $('#initial-status-fan').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function tagCallback (artist) {
        var initialStatus = $('#initial-status-tag').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function similarCallback (artist) {
        var initialStatus = $('#initial-status-similar').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    // Get stats one by one recursively and call a callback when finished
    function getStats (artists, callback) {

        // Race end: empty array
        if (artists.length === 0) {
            callback();
            return;
        }

        // Pop an artist from array
        var artist = artists.pop();

        // Get stats for the popped artist and then continue
        LastFMProxy.getStats(artist.id, artist.name, artistCallback, albumCallback, fanCallback, tagCallback, similarCallback, function (stats) {
            updateProgress();
            artistStats[artist.name] = stats;
            getStats(artists, callback);

        });
    }

    // DOM callbacks
    $(document).ready(function () {

        // Get user artists
        getArtists(function (artists) {

            // If no artist likes show message
            if (artists.length === 0) {
                showError();
                return;
            }

            // Else get stats one by one
            getStats(artists, function () {
                console.log('Finished getting stats!! :D');
                console.log(artistStats);
            });

        }); // Get user
    }); // End document ready
}); // End module<commit_msg>Si hay demasiados artistas coger 20<commit_after>
define (['jquery', 'facebook', 'LastFMProxy'], function ($, facebook, LastFMProxy) {

    // Stats object for every artist (associative array)
    var artistStats = [];

    // Number of artists liked by the user
    var artistCount = 0;

    // Number of artist already analyzed
    var analyzedArtistCount = 0;

    function getArtists(callback) {
        FB.init({
            appId      : '1468034890110746',
            xfbml      : true,
            status     : true,
            cookie     : true,
            version    : 'v2.1'
        });

        FB.login(function () {
            FB.api(
                "/me/music",
                function (response) {
                      artistCount = response.data.length || 0;
                      callback(response.data || []);

            });
        }, {scope: 'user_likes'});
    }

    // Progress & status
    function showModal (title, text) {
        $('#modalTitle').text(title);
        $('#modalText').text(text);
        $('#myModal').modal('show');
    }

    function showError (){
        $('#loading').hide();
        $('#title').text($('#error-title').val());
        $('#status').text($('#error-status').val());
    }

    function updateProgress () {
        analyzedArtistCount++;
        var percent = analyzedArtistCount / artistCount;
        var progress = percent*100;
        $('#appProgress').css('width', progress + '%');
        console.log('Total: ' + artistCount + ' Analyzed: ' + analyzedArtistCount + ' Percent: ' + percent + ' Progress: ' + progress);
    }

    function artistCallback (artist) {
        var initialStatus = $('#initial-status').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function albumCallback (artist) {
         var initialStatus = $('#initial-status-album').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function fanCallback (artist) {
        var initialStatus = $('#initial-status-fan').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function tagCallback (artist) {
        var initialStatus = $('#initial-status-tag').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    function similarCallback (artist) {
        var initialStatus = $('#initial-status-similar').val();
        $('#status').text(initialStatus + ' ' + artist + '...');
    }

    // Get stats one by one recursively and call a callback when finished
    function getStats (artists, callback) {

        // Race end: empty array
        if (artists.length === 0) {
            callback();
            return;
        }

        // Pop an artist from array
        var artist = artists.pop();

        // Get stats for the popped artist and then continue
        LastFMProxy.getStats(artist.id, artist.name, artistCallback, albumCallback, fanCallback, tagCallback, similarCallback, function (stats) {
            updateProgress();
            artistStats[artist.name] = stats;
            getStats(artists, callback);

        });
    }

    // DOM callbacks
    $(document).ready(function () {

        // Get user artists
        getArtists(function (artists) {

            var MAX_ARTISTS = 10;

            // If no artist likes show message
            if (artists.length === 0) {
                showError();
                return;
            }

            if (artists.length > MAX_ARTISTS) {
                showModal('Too many cooks', 'Try with less cooks');
                artists = artists.splice(0,MAX_ARTISTS);
            }

            // Else get stats one by one
            getStats(artists, function () {
                console.log('Finished getting stats!! :D');
                console.log(artistStats);
            });

        }); // Get user
    }); // End document ready
}); // End module<|endoftext|>


<commit_before>//Read http://lodash.com/docs#template to understand what is "${whatever}" is.
//TLDR: do not change ids inside of ${...}

//Value can be a string or function that will return a string

define(function (require, exports, module){
    module.exports = {
        downloads: 'Загрузки',
        hide: 'Скрыть',
        more: 'ещё',
        oneMoreVersion: '
... и ещё одна версия.
',
        sortby: 'Сортировать по ...',
        author: 'Автор',
        update: 'Обновление',
        trending: 'Тренд', //0.3.0
        name: 'Название',
        daily: 'загрузок за день', //0.3.0
        stars: 'Звёзды', //0.4.0
        forks: 'Форки', //0.4.0
        themes: 'Темы', //0.5.0

        /*BADGES - 0.3.2*/
        badgeAdobe: 'Adobe',
        badgeAdobeTitle: 'Расширение от Adobe',

        badge100k: '100 тыс. загрузок',
        badge100kTitle: 'Первое расширение, набравщее 100 тыс. загрузок',

        badgeTop: 'Лучшее',
        badgeTopTitle: 'Самое популярное расширение',

        badgeTrend: 'Трендовое',
        badgeTrendTitle: 'Самое трендовое расширение',

        badgeNew: 'Новое',
        badgeNewTitle: 'Новое расширение',

        badgeStarsTitle: 'Самое популярное расширение на GitHub`е', //0.4.0
        badgeForksTitle: 'Расширение, больше всего раз форкнутое на GitHub`е', //0.4.0

        themeTitle: 'Тема для Brackets',
        /*END of BADGES*/

        onlineTitle: 'Количество пользователей, которые используют это расширение сейчас. Нажмите, чтобы узнать как это число вычисляется.', //0.5.0
        maxUsersTitle: 'Общее количество пользователей, использующих это расширение.', //0.5.0

        //Detailed info about ##
        'click-more': 'Подробная информация о', //0.3.0

        //Online for ## days, ## downloads per day
        statusTemplate: '
В сети ${days} дней, ${daily} ${str_daily}, ${dpd} загрузок за день
',

        //v ## from ## - ## downloads

        versionTemplate: '
v ${version} от ${date} - ${downloads} загрузок
',

        //... and ## more versions
        moreVersionsTemplate: '
... и ещё ${count} версий
',

        //0.5.4
        colorDark: 'тёмная',
        colorLight: 'светлая'
    }
});
<commit_msg>Russian translation regards 6.0 changes<commit_after>//Read http://lodash.com/docs#template to understand what is "${whatever}" is.
//TLDR: do not change ids inside of ${...}

//Value can be a string or function that will return a string

define(function (require, exports, module){
    module.exports = {
        downloads: 'Загрузки',
        hide: 'Скрыть',
        more: 'ещё',
        oneMoreVersion: '
... и ещё одна версия.
',
        sortby: 'Сортировать по ...',
        author: 'Автор',
        update: 'Обновление',
        trending: 'Тренд', //0.3.0
        name: 'Название',
        daily: 'загрузок за день', //0.3.0
        stars: 'Звёзды', //0.4.0
        forks: 'Форки', //0.4.0
        themes: 'Темы', //0.5.0

        /*BADGES - 0.3.2*/
        badgeAdobe: 'Adobe',
        badgeAdobeTitle: 'Расширение от Adobe',

        badge100k: '100 тыс. загрузок',
        badge100kTitle: 'Первое расширение, набравщее 100 тыс. загрузок',

        badgeTop: 'Лучшее',
        badgeTopTitle: 'Самое популярное расширение',

        badgeTrend: 'Трендовое',
        badgeTrendTitle: 'Самое трендовое расширение',

        badgeNew: 'Новое',
        badgeNewTitle: 'Новое расширение',

        badgeStarsTitle: 'Самое популярное расширение на GitHub`е', //0.4.0
        badgeForksTitle: 'Расширение, больше всего раз форкнутое на GitHub`е', //0.4.0

        themeTitle: 'Тема для Brackets',
        /*END of BADGES*/

        onlineTitle: 'Количество пользователей, которые используют это расширение сейчас. Нажмите, чтобы узнать как это число вычисляется.', //0.5.0
        maxUsersTitle: 'Общее количество пользователей, использующих это расширение.', //0.5.0

        //Detailed info about ##
        'click-more': 'Подробная информация о', //0.3.0

        //Online for ## days, ## downloads per day
        statusTemplate: '
В сети ${days} дней, ${daily} ${str_daily}, ${dpd} загрузок за день
',

        //v ## from ## - ## downloads

        versionTemplate: '
v ${version} от ${date} - ${downloads} загрузок
',

        //... and ## more versions
        moreVersionsTemplate: '
... и ещё ${count} версий
',

        //0.5.4
        colorDark: 'тёмная',
        colorLight: 'светлая',

        //0.6.0
        click_for_more: 'Нажмите, чтобы узнать больше.'
    }
});
<|endoftext|>


<commit_before>$(document).ready(getposts);
function getposts(){
	console.log("loading");
	$.get("entries.json", function( data ) {
		var posts = [];
		var data = data['entries'];
		$.each(data, function(key, value) {
			console.log(key + ' -- ' + value);
			var date = value['date'];
			var title = value['title'];
			var post = value['text'];
			console.log(date + ' - ' + title + ' - ' + post);
			//posts.push("

" + data[key] + "
")
		});
	});
}<commit_msg>upadte<commit_after>$(document).ready(getposts);
function getposts(){
	console.log("loading");
	$.get("entries.json", function( data ) {
		var posts = "";
		var data = data['entries'];
		$.each(data, function(key, value) {
			console.log(key + ' -- ' + value);
			var date = value['date'];
			var title = value['title'];
			var post = value['text'];
			console.log(date + ' - ' + title + ' - ' + post);
			posts += "

" + post + "

" + title + "

" + text + "

";
		});

		$('#blog').html(posts);
	});
}<|endoftext|>


<commit_before>(function(Lazy) {

  function NodeSequence(source) {
    this.source = source;
  }

  NodeSequence.prototype = new Lazy.ArrayLikeSequence();

  NodeSequence.prototype.get = function(i) {
    return this.source[i];
  };

  NodeSequence.prototype.length = function() {
    return this.source.length;
  };

  NodeSequence.prototype.flatten = function() {
    return new FlattenedNodeSequence(this.source);
  };

  NodeSequence.prototype.on = function(eventName) {
    return new EventSequence(this.source, eventName);
  };

  function FlattenedNodeSequence(source) {
    this.source = source;
  }

  FlattenedNodeSequence.prototype = new Lazy.Sequence();

  /**
   * Iterates over all of a DOM node's descendents (its children, and their
   * children, etc.) and executes a function for each descendent.
   *
   * @param {function(Node):*} fn The function to call on each descendent.
   */
  FlattenedNodeSequence.prototype.each = function(fn) {
    var i    = 0,
        done = false;

    Lazy(this.source).each(function(child) {
      if (fn(child, i++) === false) {
        return false;
      }

      Lazy(child.children).flatten().each(function(descendent) {
        if (fn(descendent, i++) === false) {
          done = true;
          return false;
        }
      });

      if (done) {
        return false;
      }
    });
  };

  function EventSequence(element, eventName) {
    this.element = element;
    this.eventName = eventName;
  }

  EventSequence.prototype = new Lazy.Sequence();

  /**
   * Handles every event in this sequence.
   *
   * @param {function(Event):*} fn The function to call on each event in the
   *     sequence. Return false from the function to stop handling the events.
   */
  EventSequence.prototype.each = function(fn) {
    var element = this.element,
        eventName = this.eventName;

    var listener = function(e) {
      if (fn(e) === false) {
        element.removeEventListener(eventName, listener);
      }
    };

    this.element.addEventListener(this.eventName, listener);
  };

  /**
   * Creates a {@link Sequence} from the specified DOM events triggered on the
   * given element. This sequence works asynchronously, so synchronous methods
   * such as {@code indexOf}, {@code any}, and {@code toArray} won't work.
   *
   * @param {Element} element The DOM element to capture events from.
   * @param {string} eventName The name of the event type (e.g., 'keypress')
   *     that will make up this sequence.
   * @return {Sequence} The sequence of events.
   */
  Lazy.events = Lazy.deprecate(
    "Lazy.events is deprecated. Use Lazy('selector').on('event') instead",
    function(element, eventName) {
      return new EventSequence(element, eventName);
    }
  );

  /**
   * A `StreamingHttpSequence` is a {@link StreamLikeSequence} comprising the
   * chunks of data that are streamed in response to an HTTP request.
   *
   * @param {string} url The URL of the HTTP request.
   * @constructor
   */
  function StreamingHttpSequence(url) {
    this.url = url;
  }

  StreamingHttpSequence.prototype = new Lazy.StreamLikeSequence();

  StreamingHttpSequence.prototype.each = function each(fn) {
    var request = new XMLHttpRequest(),
        index   = 0,
        aborted = false;

    request.open("GET", this.url);

    var listener = function listener(data) {
      if (!aborted) {
        data = request.responseText.substring(index);
        if (fn(data) === false) {
          request.removeEventListener("progress", listener, false);
          request.abort();
          aborted = true;
        }
        index += data.length;
      }
    };

    request.addEventListener("progress", listener, false);

    request.send();
  };

  /*
   * Add support for `Lazy(NodeList)` and `Lazy(HTMLCollection)`.
   */
  Lazy.extensions || (Lazy.extensions = []);

  Lazy.extensions.push(function(source) {
    if (source instanceof NodeList || source instanceof HTMLCollection) {
      return new NodeSequence(source);
    }
  });

}(window.Lazy));
<commit_msg>renamed NodeSequence to DomSequence<commit_after>(function(Lazy) {

  function DomSequence(source) {
    this.source = source;
  }

  DomSequence.prototype = new Lazy.ArrayLikeSequence();

  DomSequence.prototype.get = function(i) {
    return this.source[i];
  };

  DomSequence.prototype.length = function() {
    return this.source.length;
  };

  DomSequence.prototype.flatten = function() {
    return new FlattenedDomSequence(this.source);
  };

  DomSequence.prototype.on = function(eventName) {
    return new DomEventSequence(this.source, eventName);
  };

  function FlattenedDomSequence(source) {
    this.source = source;
  }

  FlattenedDomSequence.prototype = new Lazy.Sequence();

  /**
   * Iterates over all of a DOM node's descendents (its children, and their
   * children, etc.) and executes a function for each descendent.
   *
   * @param {function(Node):*} fn The function to call on each descendent.
   */
  FlattenedDomSequence.prototype.each = function(fn) {
    var i    = 0,
        done = false;

    Lazy(this.source).each(function(child) {
      if (fn(child, i++) === false) {
        return false;
      }

      Lazy(child.children).flatten().each(function(descendent) {
        if (fn(descendent, i++) === false) {
          done = true;
          return false;
        }
      });

      if (done) {
        return false;
      }
    });
  };

  function DomEventSequence(element, eventName) {
    this.element = element;
    this.eventName = eventName;
  }

  DomEventSequence.prototype = new Lazy.Sequence();

  /**
   * Handles every event in this sequence.
   *
   * @param {function(Event):*} fn The function to call on each event in the
   *     sequence. Return false from the function to stop handling the events.
   */
  DomEventSequence.prototype.each = function(fn) {
    var element = this.element,
        eventName = this.eventName;

    var listener = function(e) {
      if (fn(e) === false) {
        element.removeEventListener(eventName, listener);
      }
    };

    this.element.addEventListener(this.eventName, listener);
  };

  /**
   * Creates a {@link Sequence} from the specified DOM events triggered on the
   * given element. This sequence works asynchronously, so synchronous methods
   * such as {@code indexOf}, {@code any}, and {@code toArray} won't work.
   *
   * @param {Element} element The DOM element to capture events from.
   * @param {string} eventName The name of the event type (e.g., 'keypress')
   *     that will make up this sequence.
   * @return {Sequence} The sequence of events.
   */
  Lazy.events = Lazy.deprecate(
    "Lazy.events is deprecated. Use Lazy('selector').on('event') instead",
    function(element, eventName) {
      return new DomEventSequence(element, eventName);
    }
  );

  /**
   * A `StreamingHttpSequence` is a {@link StreamLikeSequence} comprising the
   * chunks of data that are streamed in response to an HTTP request.
   *
   * @param {string} url The URL of the HTTP request.
   * @constructor
   */
  function StreamingHttpSequence(url) {
    this.url = url;
  }

  StreamingHttpSequence.prototype = new Lazy.StreamLikeSequence();

  StreamingHttpSequence.prototype.each = function each(fn) {
    var request = new XMLHttpRequest(),
        index   = 0,
        aborted = false;

    request.open("GET", this.url);

    var listener = function listener(data) {
      if (!aborted) {
        data = request.responseText.substring(index);
        if (fn(data) === false) {
          request.removeEventListener("progress", listener, false);
          request.abort();
          aborted = true;
        }
        index += data.length;
      }
    };

    request.addEventListener("progress", listener, false);

    request.send();
  };

  /*
   * Add support for `Lazy(NodeList)` and `Lazy(HTMLCollection)`.
   */
  Lazy.extensions || (Lazy.extensions = []);

  Lazy.extensions.push(function(source) {
    if (source instanceof NodeList || source instanceof HTMLCollection) {
      return new DomSequence(source);
    }
  });

}(window.Lazy));
<|endoftext|>


<commit_before>$(function() {
  var FADE_TIME = 150; // ms
  var TYPING_TIMER_LENGTH = 400; // ms
  var COLORS = [
    '#e21400', '#91580f', '#f8a700', '#f78b00',
    '#58dc00', '#287b00', '#a8f07a', '#4ae8c4',
    '#3b88eb', '#3824aa', '#a700ff', '#d300e7'
  ];

  // Initialize variables
  var $window = $(window);
  var $usernameInput = $('.usernameInput'); // Input for username
  var $messages = $('.messages'); // Messages area
  var $inputMessage = $('.inputMessage'); // Input message input box

  var $loginPage = $('.login.page'); // The login page
  var $chatPage = $('.chat.page'); // The chatroom page

  // Prompt for setting a username
  var username;
  var connected = false;
  var typing = false;
  var lastTypingTime;
  var $currentInput = $usernameInput.focus();

  var socket = io();

  function addParticipantsMessage (data) {
    var message = '';
    if (data.numUsers === 1) {
      message += "there's 1 participant";
    } else {
      message += "there are " + data.numUsers + " participants";
    }
    log(message);
  }

  // Sets the client's username
  function setUsername () {
    username = cleanInput($usernameInput.val().trim());

    // If the username is valid
    if (username) {
      $loginPage.fadeOut();
      $chatPage.show();
      $loginPage.off('click');
      $currentInput = $inputMessage.focus();

      // Tell the server your username
      socket.emit('add user', username);
    }
  }

  // Sends a chat message
  function sendMessage () {
    var message = $inputMessage.val();
    // Prevent markup from being injected into the message
    message = cleanInput(message);
    // if there is a non-empty message and a socket connection
    if (message && connected) {
      $inputMessage.val('');
      addChatMessage({
        username: username,
        message: message
      });
      // tell server to execute 'new message' and send along one parameter
      socket.emit('new message', message);
    }
  }

  // Log a message
  function log (message, options) {
    var $el = $('
').addClass('log').text(message);
    addMessageElement($el, options);
  }

  // Adds the visual chat message to the message list
  function addChatMessage (data, options) {
    // Don't fade the message in if there is an 'X was typing'
    var $typingMessages = getTypingMessages(data);
    options = options || {};
    if ($typingMessages.length !== 0) {
      options.fade = false;
      $typingMessages.remove();
    }

    var $usernameDiv = $('')
      .text(data.username)
      .css('color', getUsernameColor(data.username));
    var $messageBodyDiv = $('')
      .text(data.message);

    var typingClass = data.typing ? 'typing' : '';
    var $messageDiv = $('
')
      .data('username', data.username)
      .addClass(typingClass)
      .append($usernameDiv, $messageBodyDiv);

    addMessageElement($messageDiv, options);
  }

  // Adds the visual chat typing message
  function addChatTyping (data) {
    data.typing = true;
    data.message = 'is typing';
    addChatMessage(data);
  }

  // Removes the visual chat typing message
  function removeChatTyping (data) {
    getTypingMessages(data).fadeOut(function () {
      $(this).remove();
    });
  }

  // Adds a message element to the messages and scrolls to the bottom
  // el - The element to add as a message
  // options.fade - If the element should fade-in (default = true)
  // options.prepend - If the element should prepend
  //   all other messages (default = false)
  function addMessageElement (el, options) {
    var $el = $(el);

    // Setup default options
    if (!options) {
      options = {};
    }
    if (typeof options.fade === 'undefined') {
      options.fade = true;
    }
    if (typeof options.prepend === 'undefined') {
      options.prepend = false;
    }

    // Apply options
    if (options.fade) {
      $el.hide().fadeIn(FADE_TIME);
    }
    if (options.prepend) {
      $messages.prepend($el);
    } else {
      $messages.append($el);
    }
    $messages[0].scrollTop = $messages[0].scrollHeight;
  }

  // Prevents input from having injected markup
  function cleanInput (input) {
    return $('
').text(input).text();
  }

  // Updates the typing event
  function updateTyping () {
    if (connected) {
      if (!typing) {
        typing = true;
        socket.emit('typing');
      }
      lastTypingTime = (new Date()).getTime();

      setTimeout(function () {
        var typingTimer = (new Date()).getTime();
        var timeDiff = typingTimer - lastTypingTime;
        if (timeDiff >= TYPING_TIMER_LENGTH && typing) {
          socket.emit('stop typing');
          typing = false;
        }
      }, TYPING_TIMER_LENGTH);
    }
  }

  // Gets the 'X is typing' messages of a user
  function getTypingMessages (data) {
    return $('.typing.message').filter(function (i) {
      return $(this).data('username') === data.username;
    });
  }

  // Gets the color of a username through our hash function
  function getUsernameColor (username) {
    // Compute hash code
    var hash = 7;
    for (var i = 0; i < username.length; i++) {
       hash = username.charCodeAt(i) + (hash << 5) - hash;
    }
    // Calculate color
    var index = Math.abs(hash % COLORS.length);
    return COLORS[index];
  }

  // Keyboard events

  $window.keydown(function (event) {
    // Auto-focus the current input when a key is typed
    if (!(event.ctrlKey || event.metaKey || event.altKey)) {
      $currentInput.focus();
    }
    // When the client hits ENTER on their keyboard
    if (event.which === 13) {
      if (username) {
        sendMessage();
        socket.emit('stop typing');
        typing = false;
      } else {
        setUsername();
      }
    }
  });

  $inputMessage.on('input', function() {
    updateTyping();
  });

  // Click events

  // Focus input when clicking anywhere on login page
  $loginPage.click(function () {
    $currentInput.focus();
  });

  // Focus input when clicking on the message input's border
  $inputMessage.click(function () {
    $inputMessage.focus();
  });

  // Socket events

  // Whenever the server emits 'login', log the login message
  socket.on('login', function (data) {
    connected = true;
    // Display the welcome message
    var message = "Welcome to Socket.IO Chat – ";
    log(message, {
      prepend: true
    });
    addParticipantsMessage(data);
  });

  // Whenever the server emits 'new message', update the chat body
  socket.on('new message', function (data) {
    addChatMessage(data);
  });

  // Whenever the server emits 'user joined', log it in the chat body
  socket.on('user joined', function (data) {
    log(data.username + ' joined');
    addParticipantsMessage(data);
  });

  // Whenever the server emits 'user left', log it in the chat body
  socket.on('user left', function (data) {
    log(data.username + ' left');
    addParticipantsMessage(data);
    removeChatTyping(data);
  });

  // Whenever the server emits 'typing', show the typing message
  socket.on('typing', function (data) {
    addChatTyping(data);
  });

  // Whenever the server emits 'stop typing', kill the typing message
  socket.on('stop typing', function (data) {
    removeChatTyping(data);
  });

  socket.on('disconnect', function () {
    log('you have been disconnected');
  });

  socket.on('reconnect', function () {
    log('you have been reconnected');
    if (username) {
      socket.emit('add user', username);
    }
  });

  socket.on('reconnect_error', function () {
    log('attempt to reconnect has failed');
  });

});
<commit_msg>:skull: Remove unescesary example file<commit_after><|endoftext|>


<commit_before>import JobExecutor from '../job-executor'
import { Jobs } from '../models/job'
import {
  GenericError,
  NoSuchObject
} from '../api-errors'

// ===================================================================

class NoSuchJob extends NoSuchObject {
  constructor (id) {
    super(id, 'job')
  }
}

// ===================================================================

export default class {
  constructor (xo) {
    this._executor = new JobExecutor(xo)
    this._jobs = new Jobs({
      connection: xo._redis,
      prefix: 'xo:job',
      indexes: ['user_id', 'key']
    })
  }

  async getAllJobs () {
    return /* await */ this._jobs.get()
  }

  async getJob (id) {
    const job = await this._jobs.first(id)
    if (!job) {
      throw new NoSuchJob(id)
    }

    return job.properties
  }

  async createJob (userId, job) {
    // TODO: use plain objects
    const job_ = await this._jobs.create(userId, job)
    return job_.properties
  }

  async updateJob (job) {
    return /* await */ this._jobs.save(job)
  }

  async removeJob (id) {
    return /* await */ this._jobs.remove(id)
  }

  async runJobSequence (idSequence) {
    const notFound = []
    for (const id of idSequence) {
      let job
      try {
        job = await this.getJob(id)
      } catch (error) {
        if (error instanceof NoSuchJob) {
          notFound.push(id)
        } else {
          throw error
        }
      }
      if (job) {
        await this._executor.exec(job)
      }
    }
    if (notFound.length > 0) {
      throw new GenericError(`The following jobs were not found: ${notFound.join()}`)
    }
  }
}
<commit_msg>fix(job.set): protects userId from modification (#329)<commit_after>import assign from 'lodash.assign'
import JobExecutor from '../job-executor'
import { Jobs } from '../models/job'
import {
  GenericError,
  NoSuchObject
} from '../api-errors'

// ===================================================================

class NoSuchJob extends NoSuchObject {
  constructor (id) {
    super(id, 'job')
  }
}

// ===================================================================

export default class {
  constructor (xo) {
    this._executor = new JobExecutor(xo)
    this._jobs = new Jobs({
      connection: xo._redis,
      prefix: 'xo:job',
      indexes: ['user_id', 'key']
    })
  }

  async getAllJobs () {
    return /* await */ this._jobs.get()
  }

  async getJob (id) {
    const job = await this._jobs.first(id)
    if (!job) {
      throw new NoSuchJob(id)
    }

    return job.properties
  }

  async createJob (userId, job) {
    // TODO: use plain objects
    const job_ = await this._jobs.create(userId, job)
    return job_.properties
  }

  async updateJob ({id, type, name, key, method, paramsVector}) {
    const oldJob = await this.getJob(id)
    assign(oldJob, {type, name, key, method, paramsVector})
    return /* await */ this._jobs.save(oldJob)
  }

  async removeJob (id) {
    return /* await */ this._jobs.remove(id)
  }

  async runJobSequence (idSequence) {
    const notFound = []
    for (const id of idSequence) {
      let job
      try {
        job = await this.getJob(id)
      } catch (error) {
        if (error instanceof NoSuchJob) {
          notFound.push(id)
        } else {
          throw error
        }
      }
      if (job) {
        await this._executor.exec(job)
      }
    }
    if (notFound.length > 0) {
      throw new GenericError(`The following jobs were not found: ${notFound.join()}`)
    }
  }
}
<|endoftext|>


<commit_before>require('moonstone');

/**
* Contains the declaration for the {@link module:moonstone/DateTimePickerBase~DateTimePickerBase} kind.
* @module moonstone/DateTimePickerBase
*/

var
	kind = require('enyo/kind'),
	Control = require('enyo/Control'),
	Signals = require('enyo/Signals');

var
	ilib = require('enyo-ilib'),
	dateFactory = require('enyo-ilib/DateFactory'),
	DateFmt = require('enyo-ilib/DateFmt'),
	Locale = require('enyo-ilib/Locale');

var
	ExpandableListItem = require('../ExpandableListItem');

/**
* Fires when the picker's value changes.
*
* @event module:moonstone/DateTimePickerBase~DateTimePickerBase#onChange
* @type {Object}
* @property {String} name - The name of this control.
* @property {Date} value - A standard JavaScript {@glossary Date} object representing
* the picker's current value.
* @public
*/

/**
* {@link module:moonstone/DateTimePickerBase~DateTimePickerBase} is a base kind implementing
* fuctionality shared by {@link module:moonstone/DatePicker~DatePicker} and
* {@link module:moonstone/TimePicker~TimePicker}. It is not intended to be used directly.
*
* @class DateTimePickerBase
* @extends module:moonstone/ExpandableListItem~ExpandableListItem
* @ui
* @protected
*/

module.exports = kind(
	/** @lends module:moonstone/DateTimePickerBase~DateTimePickerBase.prototype */ {

	/**
	* @private
	*/
	name: 'moon.DateTimePickerBase',

	/**
	* @private
	*/
	kind: ExpandableListItem,

	/**
	* @private
	*/
	defaultKind: Control,

	/**
	* @private
	*/
	classes: 'moon-date-picker',

	/**
	* @private
	*/
	events: {

		/**
		* {@link module:moonstone/DateTimePickerBase~DateTimePickerBase#onChange}
		*/
		onChange: ''
	},

	/**
	* @private
	* @lends module:moonstone/DateTimePickerBase~DateTimePickerBase.prototype
	*/
	published: {

		/**
		* Text to be displayed as the current value if no item is currently selected.
		*
		* @type {String}
		* @default ''
		* @public
		*/
		noneText: '',

		/**
		* This property will be __private__ in the future and is deprecated as a __public__
		* property. It is used internally and _should not be used otherwise_.
		*
		* This is an [iLib]{@glossary ilib} Locale instance. Setting this directly may have
		* unexpected results. This class will automatically respond to application locale
		* changes that use the {@link module:enyo/i18n#updateLocale} method.
		*
		* @deprecated
		* @type {Locale}
		* @default null
		* @public
		*/
		locale: null,

		/**
		* The value of the picker, expressed as a standard JavaScript {@glossary Date}
		* object.
		*
		* @type {Date}
		* @default null
		* @public
		*/
		value: null,

		/**
		* If `true`, the picker will use a 12-hour clock (this value is ignored when
		* `iLib` is loaded, since the meridiem will be set by the current locale).
		*
		* @type {Boolean}
		* @default false
		* @public
		*/
		meridiemEnable: false
	},

	/**
	* Set in subkind.
	*
	* @private
	*/
	iLibFormatType: null,

	/**
	* Set in subkind.
	*
	* @private
	*/
	defaultOrdering: null,

	/**
	* @private
	*/
	drawerComponents: [
		{name: 'client', kind: Control, classes: 'moon-date-time-picker-client', onSpotlightLeft:'closePicker', onSpotlightSelect: 'closePicker'},
		{kind: Signals, onlocalechange: 'handleLocaleChangeEvent'}
	],

	computed: {
		'currentValueText': ['value', 'noneText']
	},

	/**
	* @private
	*/
	initComponents: function () {
		ExpandableListItem.prototype.initComponents.apply(this, arguments);
		this.initDefaults();
		this.$.drawer.addClass('indented');
	},

	/**
	* @private
	*/
	initILib: function () {
		this.locale = new Locale();
		var fmtParams = {
			type: this.iLibFormatType,
			useNative: false,
			timezone: 'local',
			length: 'full',
			date: 'dmwy'
		};

		fmtParams.locale = this.locale;
		this.iLibLocale = ilib.getLocale();
		this._tf = new DateFmt(fmtParams);
	},

	/**
	* @private
	*/
	initDefaults: function () {
		this.initILib();
		this.setupPickers(this._tf.getTemplate());
	},

	/**
	* @private
	*/
	setupPickers: function (ordering) {
		// implement in subkind
	},

	/**
	* @private
	*/
	formatValue: function () {
		// implement in subkind
	},

	/**
	* @fires module:moonstone/DateTimePickerBase~DateTimePickerBase#onChange
	* @private
	*/
	valueChanged: function (inOld) {
		this.syncingPickers = true;
		this.setChildPickers(inOld);
		this.syncingPickers = false;
		this.doChange({name:this.name, value:this.value});
	},

	/**
	* @private
	*/
	setChildPickers: function (inOld) {
		// implement in subkind
	},

	/**
	* If no item is selected, sets [noneText]{@link module:moonstone/DateTimePickerBase~DateTimePickerBase#noneText}
	* as current value.
	*
	* @private
	*/
	currentValueText: function () {
		return this.value ? this.formatValue() : this.noneText;
	},

	/**
	* @private
	*/
	currentValueShowing: function () {
		return true;
	},

	/**
	* When [open]{@link module:moonstone/ExpandableListItem~ExpandableListItem#open} changes, shows/hides the current value.
	*
	* @private
	*/
	openChanged: function () {
		ExpandableListItem.prototype.openChanged.apply(this, arguments);
		var pickers = this.pickers,
			i, p;
		if (pickers && this.open) {
			for (i = 0; i < pickers.length; i++) {
				p = pickers[i];
				if (p.getClientControls().length > 0) {
					p = p.getClientControls()[0];
				}
				p.reflow();
			}
		}
	},

	/**
	* @private
	*/
	expandContract: function () {
		if (!this.open) {
			// if currently closed and handling the back key, keep track of the initial value in
			// case we need to restore this value
			if (this.allowBackKey) this._initialValue = this.value && new Date(this.value.getTime());

			// if currently closed and without a value, set it to now before opening
			if (!this.value) this.set('value', new Date());
		}
		ExpandableListItem.prototype.expandContract.apply(this, arguments);
	},

	/**
	* @private
	*/
	closePicker: function (inSender, inEvent) {
		/**
		* If select/enter is pressed on any date picker item or the left key is pressed on the
		* first item, close the drawer
		*/
		if (inEvent.type == 'onSpotlightSelect' ||
			this.$.client.children[0].id == inEvent.originator.id) {
			this.expandContract();
			return true;
		}
	},

	/**
	* @private
	*/
	handleLocaleChangeEvent: function () {
		// We've received a localechange event from the system, which means either the system
		// locale or the timezone may have changed.
		if (ilib.getLocale() !== this.iLibLocale) {
			// We're using iLib locale, and it has changed, so we'll rebuild the child pickers
			// entirely
			this.refresh();
		} else {
			// We don't care about the iLib locale or it hasn't changed, but timezone might have
			// changed, so we'll just update the child pickers
			this.setChildPickers();
		}
		this.notify('currentValueText');
	},

	/**
	* @private
	*/
	refresh: function () {
		this.destroyClientControls();
		this.pickers = null;
		delete this._tf;
		if (this.value) {
			this.localeValue = dateFactory({unixtime: this.value.getTime(), timezone: 'local'});
		}
		this.set('open', false);
		this.initDefaults();
		this.render();
	},

	/**
	* @private
	*/
	backKeyHandler: function () {
		if (this.open) this.set('value', this._initialValue);
		ExpandableListItem.prototype.backKeyHandler.apply(this, arguments);
	}
});
<commit_msg>ENYO-3142: Prevent event firing at create time.<commit_after>require('moonstone');

/**
* Contains the declaration for the {@link module:moonstone/DateTimePickerBase~DateTimePickerBase} kind.
* @module moonstone/DateTimePickerBase
*/

var
	kind = require('enyo/kind'),
	Control = require('enyo/Control'),
	Signals = require('enyo/Signals');

var
	ilib = require('enyo-ilib'),
	dateFactory = require('enyo-ilib/DateFactory'),
	DateFmt = require('enyo-ilib/DateFmt'),
	Locale = require('enyo-ilib/Locale');

var
	ExpandableListItem = require('../ExpandableListItem');

/**
* Fires when the picker's value changes.
*
* @event module:moonstone/DateTimePickerBase~DateTimePickerBase#onChange
* @type {Object}
* @property {String} name - The name of this control.
* @property {Date} value - A standard JavaScript {@glossary Date} object representing
* the picker's current value.
* @public
*/

/**
* {@link module:moonstone/DateTimePickerBase~DateTimePickerBase} is a base kind implementing
* fuctionality shared by {@link module:moonstone/DatePicker~DatePicker} and
* {@link module:moonstone/TimePicker~TimePicker}. It is not intended to be used directly.
*
* @class DateTimePickerBase
* @extends module:moonstone/ExpandableListItem~ExpandableListItem
* @ui
* @protected
*/

module.exports = kind(
	/** @lends module:moonstone/DateTimePickerBase~DateTimePickerBase.prototype */ {

	/**
	* @private
	*/
	name: 'moon.DateTimePickerBase',

	/**
	* @private
	*/
	kind: ExpandableListItem,

	/**
	* @private
	*/
	defaultKind: Control,

	/**
	* @private
	*/
	classes: 'moon-date-picker',

	/**
	* @private
	*/
	events: {

		/**
		* {@link module:moonstone/DateTimePickerBase~DateTimePickerBase#onChange}
		*/
		onChange: ''
	},

	/**
	* @private
	* @lends module:moonstone/DateTimePickerBase~DateTimePickerBase.prototype
	*/
	published: {

		/**
		* Text to be displayed as the current value if no item is currently selected.
		*
		* @type {String}
		* @default ''
		* @public
		*/
		noneText: '',

		/**
		* This property will be __private__ in the future and is deprecated as a __public__
		* property. It is used internally and _should not be used otherwise_.
		*
		* This is an [iLib]{@glossary ilib} Locale instance. Setting this directly may have
		* unexpected results. This class will automatically respond to application locale
		* changes that use the {@link module:enyo/i18n#updateLocale} method.
		*
		* @deprecated
		* @type {Locale}
		* @default null
		* @public
		*/
		locale: null,

		/**
		* The value of the picker, expressed as a standard JavaScript {@glossary Date}
		* object.
		*
		* @type {Date}
		* @default null
		* @public
		*/
		value: null,

		/**
		* If `true`, the picker will use a 12-hour clock (this value is ignored when
		* `iLib` is loaded, since the meridiem will be set by the current locale).
		*
		* @type {Boolean}
		* @default false
		* @public
		*/
		meridiemEnable: false
	},

	/**
	* Set in subkind.
	*
	* @private
	*/
	iLibFormatType: null,

	/**
	* Set in subkind.
	*
	* @private
	*/
	defaultOrdering: null,

	/**
	* @private
	*/
	drawerComponents: [
		{name: 'client', kind: Control, classes: 'moon-date-time-picker-client', onSpotlightLeft:'closePicker', onSpotlightSelect: 'closePicker'},
		{kind: Signals, onlocalechange: 'handleLocaleChangeEvent'}
	],

	computed: {
		'currentValueText': ['value', 'noneText']
	},

	/**
	* @private
	*/
	initComponents: function () {
		ExpandableListItem.prototype.initComponents.apply(this, arguments);
		this.initDefaults();
		this.$.drawer.addClass('indented');
	},

	/**
	* @private
	*/
	initILib: function () {
		this.locale = new Locale();
		var fmtParams = {
			type: this.iLibFormatType,
			useNative: false,
			timezone: 'local',
			length: 'full',
			date: 'dmwy'
		};

		fmtParams.locale = this.locale;
		this.iLibLocale = ilib.getLocale();
		this._tf = new DateFmt(fmtParams);
	},

	/**
	* @private
	*/
	initDefaults: function () {
		this.initILib();
		this.setupPickers(this._tf.getTemplate());
	},

	/**
	* @private
	*/
	setupPickers: function (ordering) {
		// implement in subkind
	},

	/**
	* @private
	*/
	formatValue: function () {
		// implement in subkind
	},

	/**
	* @fires module:moonstone/DateTimePickerBase~DateTimePickerBase#onChange
	* @private
	*/
	valueChanged: function (inOld) {
		this.syncingPickers = true;
		this.setChildPickers(inOld);
		this.syncingPickers = false;
		if (this.generated) this.doChange({name:this.name, value:this.value});
	},

	/**
	* @private
	*/
	setChildPickers: function (inOld) {
		// implement in subkind
	},

	/**
	* If no item is selected, sets [noneText]{@link module:moonstone/DateTimePickerBase~DateTimePickerBase#noneText}
	* as current value.
	*
	* @private
	*/
	currentValueText: function () {
		return this.value ? this.formatValue() : this.noneText;
	},

	/**
	* @private
	*/
	currentValueShowing: function () {
		return true;
	},

	/**
	* When [open]{@link module:moonstone/ExpandableListItem~ExpandableListItem#open} changes, shows/hides the current value.
	*
	* @private
	*/
	openChanged: function () {
		ExpandableListItem.prototype.openChanged.apply(this, arguments);
		var pickers = this.pickers,
			i, p;
		if (pickers && this.open) {
			for (i = 0; i < pickers.length; i++) {
				p = pickers[i];
				if (p.getClientControls().length > 0) {
					p = p.getClientControls()[0];
				}
				p.reflow();
			}
		}
	},

	/**
	* @private
	*/
	expandContract: function () {
		if (!this.open) {
			// if currently closed and handling the back key, keep track of the initial value in
			// case we need to restore this value
			if (this.allowBackKey) this._initialValue = this.value && new Date(this.value.getTime());

			// if currently closed and without a value, set it to now before opening
			if (!this.value) this.set('value', new Date());
		}
		ExpandableListItem.prototype.expandContract.apply(this, arguments);
	},

	/**
	* @private
	*/
	closePicker: function (inSender, inEvent) {
		/**
		* If select/enter is pressed on any date picker item or the left key is pressed on the
		* first item, close the drawer
		*/
		if (inEvent.type == 'onSpotlightSelect' ||
			this.$.client.children[0].id == inEvent.originator.id) {
			this.expandContract();
			return true;
		}
	},

	/**
	* @private
	*/
	handleLocaleChangeEvent: function () {
		// We've received a localechange event from the system, which means either the system
		// locale or the timezone may have changed.
		if (ilib.getLocale() !== this.iLibLocale) {
			// We're using iLib locale, and it has changed, so we'll rebuild the child pickers
			// entirely
			this.refresh();
		} else {
			// We don't care about the iLib locale or it hasn't changed, but timezone might have
			// changed, so we'll just update the child pickers
			this.setChildPickers();
		}
		this.notify('currentValueText');
	},

	/**
	* @private
	*/
	refresh: function () {
		this.destroyClientControls();
		this.pickers = null;
		delete this._tf;
		if (this.value) {
			this.localeValue = dateFactory({unixtime: this.value.getTime(), timezone: 'local'});
		}
		this.set('open', false);
		this.initDefaults();
		this.render();
	},

	/**
	* @private
	*/
	backKeyHandler: function () {
		if (this.open) this.set('value', this._initialValue);
		ExpandableListItem.prototype.backKeyHandler.apply(this, arguments);
	}
});
<|endoftext|>