<commit_before>/**
 * Parse definitions from Wiktionary Parsoid HTML.
 *
 * English Wiktionary entry layout guide:
 * https://en.wiktionary.org/wiki/Wiktionary:Entry_layout
 */

'use strict';

var domino = require('domino');
var sUtil = require('./util');
var mUtil = require('./mobile-util');
var transforms = require('./transforms');
var parseSection = require('./parseSection');
var languageList = require('../static/languages_list.json');

/* This list has expanded beyond parts of speech to something more like "whatever
   categories of terms the Wiktionary editors decided to include", but we'll
   retain the variable name/response field since this is now what the app expects
   and changing it will require a coordinated service deployment/app release/RESTBase
   cache purge. */
var partsOfSpeech = {
                  /* English */
                  'en':['Abbreviation',
                        'Adjective',
                        'Adverb',
                        'Article',
                        'Conjunction',
                        'Contraction',
                        'Determiner',
                        'Interjection',
                        'Letter',
                        'Noun',
                        'Numeral',
                        'Participle',
                        'Particle',
                        'Phrase',
                        'Prefix',
                        'Preposition',
                        'Pronoun',
                        'Proper noun',
                        'Punctuation mark',
                        'Suffix',
                        'Symbol',
                        'Verb' ],

                  /* French */
                  /* 'fr':['Nom',
                        'Déterminant',
                        'Adjectif',
                        'Pronom',
                        'Verbe',
                        'Adverbe',
                        'Préposition',
                        'Conjunction']
                  */
                };

function stripSpanTags(text) {
    return text.replace(/<\/?span[^>]*>/g, '');
}

function stripItalicTags(text) {
    return text.replace(/<\/?i[^>]*>/g, '');
}

function decodeHTML(text) {
    return text.replace(/</g,'<')
               .replace(/>/g,'>')
               .replace(/&/g,'&')
               .replace(/ /g, ' ');
}

function hasUsageExamples(text, langCode) {
    return langCode === 'en' ? text.indexOf('<dl') > -1 : text.indexOf('<ul') > -1;
}

function getLanguageCode(langName, wikiLangCode) {
    if (langName === "Translingual") {
        return wikiLangCode;
    }
    return languageList[langName];
}

/**
 * This is where the sausage is made.  It seems no two Wiktionaries are
 * formatted the same way, so we'll figure out where they (usually) keep the
 * actual definitions on a wiki-by-wiki basis and pluck them out; this is
 * usually at least *internally* consistent.
 */
function getDefnList(doc, id, wikiLangCode) {
    var defnList;
    switch (wikiLangCode) {
        case 'en':
            defnList = doc.querySelectorAll('div[id=' + id + '] li');
            break;
        //case 'fr':
        //    defnList = doc.querySelector('ol').children;
        //    break;
        default:
            break;
    }
    return defnList;
}

function constructDefinition(element, wikiLangCode) {
    var j, example, examples, defn, currentDefinition = {};

    if (hasUsageExamples(element.innerHTML, wikiLangCode)) {
        currentDefinition.definition = element.innerHTML.substring(0, element.innerHTML.indexOf('<dl')).trim();
        currentDefinition.examples = [];
        examples = wikiLangCode === 'en' ? element.querySelectorAll('dd') : element.querySelectorAll('li');
        for (j = 0; j < examples.length; j++) {
            example = examples[j].innerHTML.trim();
            example = decodeHTML(example);
            example = stripSpanTags(example);
            example = stripItalicTags(example);
            currentDefinition.examples.push(example);
        }
    } else {
        defn = element.innerHTML.trim();
        defn = decodeHTML(defn);
        defn = stripSpanTags(defn);
        defn = stripItalicTags(defn);
        currentDefinition.definition = defn;
    }
    return currentDefinition;
}

/**
 * @param {document} doc the parsed DOM Document of the Parsoid output
 * @return {definitions[]} an array of objects, organized by part of speech,
 * containing definitions (with examples, where available) from Wiktionary
 */
function parse(doc, domain, title) {
    // TODO: update once Parsoid emits section tags, see https://phabricator.wikimedia.org/T114072#1711063
    var i, j,
        definitions = {},
        definitionSection,
        defnList,
        defnLangCode = null,
        header,
        sectionDivs = doc.querySelectorAll('div[id^="section_"]'),
        currentSectionDiv,
        wikiLangCode = domain.split('.')[0];

    // Language-specific transforms
    if (wikiLangCode === 'en') {
        transforms.rmElementsWithSelector(doc, 'ul');
    }

    for (j = 0; j < sectionDivs.length; j++) {
        currentSectionDiv = sectionDivs[j];
        header = mUtil.stripMarkup(currentSectionDiv.title);

        /* Get the language from the first H2 header, and begin iterating over sections.
           Per the English Wiktionary style guide (linked in header above), H2 headings
           are language names. */
        if (currentSectionDiv.className.substring('toclevel_'.length) === "1") {
            defnLangCode = getLanguageCode(header, wikiLangCode);
        }

        /* Parse definitions from part-of-speech sections */
        if (defnLangCode && partsOfSpeech[wikiLangCode].indexOf(header) > -1) {
            definitionSection = {};
            definitionSection.partOfSpeech = header;
            definitionSection.definitions = [];
            defnList = getDefnList(doc, currentSectionDiv.id, wikiLangCode);
            for (i = 0; i < defnList.length; i++) {
                definitionSection.definitions.push(constructDefinition(defnList[i], wikiLangCode));
            }

            if (!definitions[defnLangCode]) {
                definitions[defnLangCode] = [];
            }

            definitions[defnLangCode].push(definitionSection);
        }
    }

    // check if we have something to return or should error out
    if (Object.keys(definitions).length) {
        return definitions;
    }

    throw new sUtil.HTTPError({
        status: 404,
        type: 'not_found',
        title: 'No definition found',
        detail: 'Could not find a definition for \'' + title + '\' on ' + domain + '.'
    });
}

module.exports = parse;
<commit_msg>Wiktionary: Stop restricting language names to those on a static list<commit_after>/**
 * Parse definitions from Wiktionary Parsoid HTML.
 *
 * English Wiktionary entry layout guide:
 * https://en.wiktionary.org/wiki/Wiktionary:Entry_layout
 */

'use strict';

var domino = require('domino');
var sUtil = require('./util');
var mUtil = require('./mobile-util');
var transforms = require('./transforms');
var parseSection = require('./parseSection');
var languageList = require('../static/languages_list.json');

/* This list has expanded beyond parts of speech to something more like "whatever
   categories of terms the Wiktionary editors decided to include", but we'll
   retain the variable name/response field since this is now what the app expects
   and changing it will require a coordinated service deployment/app release/RESTBase
   cache purge. */
var partsOfSpeech = {
                  /* English */
                  'en':['Abbreviation',
                        'Adjective',
                        'Adverb',
                        'Article',
                        'Conjunction',
                        'Contraction',
                        'Determiner',
                        'Interjection',
                        'Letter',
                        'Noun',
                        'Numeral',
                        'Participle',
                        'Particle',
                        'Phrase',
                        'Prefix',
                        'Preposition',
                        'Pronoun',
                        'Proper noun',
                        'Punctuation mark',
                        'Suffix',
                        'Symbol',
                        'Verb' ],

                  /* French */
                  /* 'fr':['Nom',
                        'Déterminant',
                        'Adjectif',
                        'Pronom',
                        'Verbe',
                        'Adverbe',
                        'Préposition',
                        'Conjunction']
                  */
                };

function stripSpanTags(text) {
    return text.replace(/<\/?span[^>]*>/g, '');
}

function stripItalicTags(text) {
    return text.replace(/<\/?i[^>]*>/g, '');
}

function decodeHTML(text) {
    return text.replace(/</g,'<')
               .replace(/>/g,'>')
               .replace(/&/g,'&')
               .replace(/ /g, ' ');
}

function hasUsageExamples(text, langCode) {
    return langCode === 'en' ? text.indexOf('<dl') > -1 : text.indexOf('<ul') > -1;
}

function getLanguageCode(langName, wikiLangCode) {
    if (langName === "Translingual") {
        return wikiLangCode;
    }
    return languageList[langName];
}

/**
 * This is where the sausage is made.  It seems no two Wiktionaries are
 * formatted the same way, so we'll figure out where they (usually) keep the
 * actual definitions on a wiki-by-wiki basis and pluck them out; this is
 * usually at least *internally* consistent.
 */
function getDefnList(doc, id, wikiLangCode) {
    var defnList;
    switch (wikiLangCode) {
        case 'en':
            defnList = doc.querySelectorAll('div[id=' + id + '] li');
            break;
        //case 'fr':
        //    defnList = doc.querySelector('ol').children;
        //    break;
        default:
            break;
    }
    return defnList;
}

function constructDefinition(element, wikiLangCode) {
    var j, example, examples, defn, currentDefinition = {};

    if (hasUsageExamples(element.innerHTML, wikiLangCode)) {
        currentDefinition.definition = element.innerHTML.substring(0, element.innerHTML.indexOf('<dl')).trim();
        currentDefinition.examples = [];
        examples = wikiLangCode === 'en' ? element.querySelectorAll('dd') : element.querySelectorAll('li');
        for (j = 0; j < examples.length; j++) {
            example = examples[j].innerHTML.trim();
            example = decodeHTML(example);
            example = stripSpanTags(example);
            example = stripItalicTags(example);
            currentDefinition.examples.push(example);
        }
    } else {
        defn = element.innerHTML.trim();
        defn = decodeHTML(defn);
        defn = stripSpanTags(defn);
        defn = stripItalicTags(defn);
        currentDefinition.definition = defn;
    }
    return currentDefinition;
}

/**
 * @param {document} doc the parsed DOM Document of the Parsoid output
 * @return {definitions[]} an array of objects, organized by part of speech,
 * containing definitions (with examples, where available) from Wiktionary
 */
function parse(doc, domain, title) {
    // TODO: update once Parsoid emits section tags, see https://phabricator.wikimedia.org/T114072#1711063
    var i, j,
        currentLang,
        definitions = {},
        definitionSection,
        defnList,
        defnLangCode = null,
        header,
        sectionDivs = doc.querySelectorAll('div[id^="section_"]'),
        currentSectionDiv,
        wikiLangCode = domain.split('.')[0];

    // Language-specific transforms
    if (wikiLangCode === 'en') {
        transforms.rmElementsWithSelector(doc, 'ul');
    }

    for (j = 0; j < sectionDivs.length; j++) {
        currentSectionDiv = sectionDivs[j];
        header = mUtil.stripMarkup(currentSectionDiv.title);

        /* Get the language from the first H2 header, and begin iterating over sections.
           Per the English Wiktionary style guide (linked in header above), H2 headings
           are language names. */
        if (currentSectionDiv.className.substring('toclevel_'.length) === "1") {
            currentLang = header;
            defnLangCode = getLanguageCode(header, wikiLangCode) || 'other';
        }

        /* Parse definitions from part-of-speech sections */
        if (partsOfSpeech[wikiLangCode].indexOf(header) > -1) {
            definitionSection = {};
            definitionSection.partOfSpeech = header;
            definitionSection.language = currentLang;
            definitionSection.definitions = [];
            defnList = getDefnList(doc, currentSectionDiv.id, wikiLangCode);
            for (i = 0; i < defnList.length; i++) {
                definitionSection.definitions.push(constructDefinition(defnList[i], wikiLangCode));
            }

            if (!definitions[defnLangCode]) {
                definitions[defnLangCode] = [];
            }

            definitions[defnLangCode].push(definitionSection);
        }
    }

    // check if we have something to return or should error out
    if (Object.keys(definitions).length) {
        return definitions;
    }

    throw new sUtil.HTTPError({
        status: 404,
        type: 'not_found',
        title: 'No definition found',
        detail: 'Could not find a definition for \'' + title + '\' on ' + domain + '.'
    });
}

module.exports = parse;
<|endoftext|>


<commit_before>/**
 * Created by vladi on 25-Jan-17.
 */
import EventListener from './EventListener';
import {
    dispatchEvent,
    getUid,
    BasicEvent,
    addEventListener,
    removeEventListenersByType,
    listenerExists,
    filterRemovedListeners,
    isEventStateUpdated
} from './EventsControl';
class EventException {
    constructor(message) {
        this.message = message;
        this.name = "EventException";
    }
}
export default class Event extends BasicEvent {
    constructor(eventData) {
        super();
        //i don't want to keep the event prototype or constructor for comparing i will create unique id per constructor
        this.constructor.prototype.__listenersList =
            this.constructor.prototype.__listenersList || [];
        this.constructor.prototype._uid =
            this.constructor.prototype._uid || getUid();
        this.constructor.prototype._eventState =
            this.constructor.prototype._eventState || {...(this.constructor.defaultEventState || {})};
        this.constructor.prototype._isDispatching =
            this.constructor.prototype._isDispatching === undefined ? false : this.constructor.prototype._isDispatching;
        this._data = {...(eventData || {})};
        this.updateEventList =
            this.__listenersList =
                this.removeEventListener =
                    this.addEventListener =
                        this._isDispatching =
                            this._eventState =
                                this._uid = undefined;
    }

    get uid() {
        return this.constructor.prototype._uid;
    }

    get eventState() {
        return {...this.constructor.prototype._eventState};
    }

    get eventData() {
        return {...this._data};
    }

    dispatch() {
        if (this.constructor.prototype._isDispatching) {
            throw new EventException("Event-ception - (Event fired withing itself) detected at:" + this.constructor.name);
        }
        this.constructor.prototype._isDispatching = true;
        const eventStateUpdate = this._data && isEventStateUpdated(this.constructor.prototype._eventState, this._data);
        if (eventStateUpdate) {
            this.constructor.prototype._eventState =
                Object.assign(this.constructor.prototype._eventState, this._data);
        }
        dispatchEvent(this, eventStateUpdate);
        this.constructor.prototype._isDispatching = false;
    }

    static updateEventList() {
        this.constructor.prototype.__listenersList =
            filterRemovedListeners(
                this.constructor.prototype.__listenersList || []
            );
    }

    static removeEventListener(eventListener) {
        if (typeof eventListener !== 'object'
            || !EventListener.isPrototypeOf(eventListener)
            || !this.constructor.prototype.__listenersList
            || this.constructor.prototype.__listenersList.indexOf(eventListener.listenerUid) == -1) {
            return;
        }
        eventListener.remove();
    }

    static clearAllDirectEvents() {
        removeEventListenersByType(
            this.uid, this.constructor.prototype.__listenersList || []
        );
        this.constructor.prototype.__listenersList = [];
    }

    static onEventStateUpdated(handler) {
        return this.addEventListener(handler, true);
    }

    static addEventListener(handler, onStateUpdated) {
        if (!handler) {
            return;
        }
        const listenerUid = addEventListener({
            _onStateUpdate: !!onStateUpdated,
            _active: true,
            _eventUid: this.uid,
            _handler: handler
        });
        this.constructor.prototype.__listenersList = this.constructor.prototype.__listenersList || [];
        this.constructor.prototype.__listenersList.push(listenerUid);
        return new EventListener(
            listenerUid,
            this.updateEventList.bind(this)
        );
    }

    static get eventState() {
        return this.prototype._eventState || (new this()).eventState;
    }

    static get uid() {
        return this.prototype._uid || (new this()).uid;
    }
}

<commit_msg>updated events list keep ( although badly ) fixed bugs<commit_after>/**
 * Created by vladi on 25-Jan-17.
 */
import EventListener from './EventListener';
import {
    dispatchEvent,
    getUid,
    BasicEvent,
    addEventListener,
    removeEventListenersByType,
    filterRemovedListeners,
    isEventStateUpdated
} from './EventsControl';
class EventException {
    constructor(message) {
        this.message = message;
        this.name = "EventException";
    }
}
const updateEventList = () => {
    this.__listenersList =
        filterRemovedListeners(
            this.__listenersList || []
        );
};

export default class Event extends BasicEvent {
    constructor(eventData) {
        super();
        //i don't want to keep the event prototype or constructor for comparing i will create unique id per constructor
        this.constructor.prototype._uid =
            this.constructor.prototype._uid || getUid();
        this.constructor.prototype._eventState =
            this.constructor.prototype._eventState || {...(this.constructor.defaultEventState || {})};
        this.constructor.prototype._isDispatching =
            this.constructor.prototype._isDispatching === undefined ? false : this.constructor.prototype._isDispatching;
        this._data = {...(eventData || {})};
        //remove references from Instances
        this.__listenersList =
            this.clearAllDirectEvents =
                this.onEventStateUpdated =
                    this.removeEventListener =
                        this.addEventListener =
                            this._isDispatching =
                                this._eventState =
                                    this._uid = undefined;
    }

    get uid() {
        return this.constructor.prototype._uid;
    }

    get eventState() {
        return {...this.constructor.prototype._eventState};
    }

    get eventData() {
        return {...this._data};
    }

    dispatch() {
        if (this.constructor.prototype._isDispatching) {
            throw new EventException("Event-ception - (Event fired withing itself) detected at:" + this.constructor.name);
        }
        this.constructor.prototype._isDispatching = true;
        const eventStateUpdate = this._data && isEventStateUpdated(this.constructor.prototype._eventState, this._data);
        if (eventStateUpdate) {
            this.constructor.prototype._eventState =
                Object.assign(this.constructor.prototype._eventState, this._data);
        }
        dispatchEvent(this, eventStateUpdate);
        this.constructor.prototype._isDispatching = false;
        return this;
    }

    static removeEventListener(eventListener) {
        if (typeof eventListener !== 'object'
            || !EventListener.isPrototypeOf(eventListener)
            || !this.__listenersList
            || this.__listenersList.indexOf(eventListener.listenerUid) == -1) {
            return;
        }
        eventListener.remove();
    }

    static clearAllDirectEvents() {
        removeEventListenersByType(
            this.uid, this.__listenersList || []
        );
        this.__listenersList = [];
    }

    static onEventStateUpdated(handler) {
        return this.addEventListener(handler, true);
    }

    static addEventListener(handler, onStateUpdated) {
        if (!handler) {
            return;
        }
        const listenerUid = addEventListener({
            _onStateUpdate: !!onStateUpdated,
            _active: true,
            _eventUid: this.uid,
            _handler: handler
        });
        this.__listenersList = this.__listenersList || [];
        this.__listenersList.push(listenerUid);
        return new EventListener(
            listenerUid,
            updateEventList.bind(this)
        );
    }

    static get eventState() {
        return {...(this.prototype._eventState || (new this()).eventState)};
    }

    static get uid() {
        return this.prototype._uid || (new this()).uid;
    }
}

<|endoftext|>


<commit_before>var resourcesSummary = [
  'Automatically create icon and splash screen resources' + ' (beta)'.yellow,
  'Put your images in the ./resources directory, named splash or icon.',
  'Accepted file types are .png, .ai, and .psd.',
  'Icons should be 192x192 px without rounded corners.',
  'Splashscreens should be 2208x2208 px, with the image centered in the middle.\n'
].join('\n\t\t      ');

var TASKS = [
  {
    title: 'start',
    name: 'start',
    summary: 'Starts a new Ionic project in the specified PATH',
    args: {
      '[options]': 'any flags for the command',
      '<PATH>': 'directory for the new project',
      '[template]': 'Template name, ex: tabs, sidemenu, blank\n' +
                    'Codepen url, ex: http://codepen.io/ionic/pen/odqCz\n' +
                    'Defaults to Ionic "tabs" starter template'
    },
    options: {
      '--appname|-a': 'Human readable name for the app (Use quotes around the name)',
      '--id|-i': 'Package name for <widget id> config, ex: com.mycompany.myapp',
      '--no-cordova|-w': 'Create a basic structure without Cordova requirements',
      '--sass|-s': 'Setup the project to use Sass CSS precompiling',
      '--list|-l': 'List starter templates available',
      '--io-app-id': 'The Ionic.io app ID to use'
    },
    module: './ionic/start'
  },
  {
    title: 'serve',
    name: 'serve',
    summary: 'Start a local development server for app dev/testing',
    args: {
      '[options]': ''
    },
    options: {
      '--consolelogs|-c': 'Print app console logs to Ionic CLI',
      '--serverlogs|-s': 'Print dev server logs to Ionic CLI',
      '--port|-p': 'Dev server HTTP port (8100 default)',
      '--livereload-port|-r': 'Live Reload port (35729 default)',
      '--nobrowser|-b': 'Disable launching a browser',
      '--nolivereload|-d': 'Do not start live reload',
      '--noproxy|-x': 'Do not add proxies',
      '--address': 'Use specific address or return with failure',
      '--all|-a': 'Have the server listen on all addresses (0.0.0.0)',
      '--browser|-w': 'Specifies the browser to use (safari, firefox, chrome)',
      '--browseroption|-o': 'Specifies a path to open to (/#/tab/dash)',
      '--lab|-l': 'Test your apps on multiple screen sizes and platform types',
      '--nogulp': 'Disable running gulp during serve',
      '--platform|-t': 'Start serve with a specific platform (ios/android)'
    },
    module: './ionic/serve'
  },
  {
    title: 'platform',
    name: 'platform',
    summary: 'Add platform target for building an Ionic app',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--noresources|-r': 'Do not add default Ionic icons and splash screen resources',
      '--nosave|-e': 'Do not save the platform to the package.json file'
    },
    module: './ionic/cordova'
  },
  {
    title: 'run',
    name: 'run',
    summary: 'Run an Ionic project on a connected device',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--livereload|-l': 'Live reload app dev files from the device' + ' (beta)'.yellow,
      '--port|-p': 'Dev server HTTP port (8100 default, livereload req.)',
      '--livereload-port|-r': 'Live Reload port (35729 default, livereload req.)',
      '--consolelogs|-c': 'Print app console logs to Ionic CLI (livereload req.)',
      '--serverlogs|-s': 'Print dev server logs to Ionic CLI (livereload req.)',
      '--debug|--release': '',
      '--device|--emulator|--target=FOO': ''
    },
    module: './ionic/cordova'
  },
  {
    title: 'emulate',
    name: 'emulate',
    summary: 'Emulate an Ionic project on a simulator or emulator',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--livereload|-l': 'Live reload app dev files from the device' + ' (beta)'.yellow,
      '--port|-p': 'Dev server HTTP port (8100 default, livereload req.)',
      '--livereload-port|-r': 'Live Reload port (35729 default, livereload req.)',
      '--consolelogs|-c': 'Print app console logs to Ionic CLI (livereload req.)',
      '--serverlogs|-s': 'Print dev server logs to Ionic CLI (livereload req.)',
      '--nohooks|-n': 'Do not add default Ionic hooks for Cordova',
      '--debug|--release': '',
      '--device|--emulator|--target=FOO': ''
    },
    module: './ionic/cordova'
  },
  {
    title: 'build',
    name: 'build',
    summary: 'Locally build an Ionic project for a given platform',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--nohooks|-n': 'Do not add default Ionic hooks for Cordova',
    },
    module: './ionic/cordova'
  },
  {
    title: 'plugin add',
    name: 'plugin',
    summary: 'Add a Cordova plugin',
    args: {
      '[options]': '',
      '<SPEC>': 'Can be a plugin ID, a local path, or a git URL.'
    },
    options: {
      '--searchpath <directory>': 'When looking up plugins by ID, look in this directory\n' +
                                  'and subdirectories first for the plugin before\n' +
                                  'looking it up in the registry.',
      '--nosave|-e': 'Do not save the plugin to the package.json file'
    },
    module: './ionic/cordova'
  },
  {
    title: 'prepare',
    name: 'prepare',
    module: './ionic/cordova'
  },
  {
    title: 'compile',
    name: 'compile',
    module: './ionic/cordova'
  },
  {
    title: 'resources',
    name: 'resources',
    summary: resourcesSummary,
    options: {
      '--icon|-i': 'Generate icon resources',
      '--splash|-s': 'Generate splash screen resources'
    },
    module: './ionic/resources/generate'
  },
  {
    title: 'package',
    name: 'package',
    alt: ['pack'],
    summary: 'Package an app using the Ionic Build service' + ' (beta)'.yellow,
    args: {
      '[options]': '',
      '<MODE>': '"debug" or "release"',
      '<PLATFORM>': '"ios" or "android"'
    },
    options: {
      '--android-keystore-file|-k': 'Android keystore file',
      '--android-keystore-alias|-a': 'Android keystore alias',
      '--android-keystore-password|-w': 'Android keystore password',
      '--android-key-password|-r': 'Android key password',
      '--ios-certificate-file|-c': 'iOS certificate file',
      '--ios-certificate-password|-d': 'iOS certificate password',
      '--ios-profile-file|-f': 'iOS profile file',
      '--output|-o': 'Path to save the packaged app',
      '--no-email|-n': 'Do not send a build package email',
      '--clear-signing|-l': 'Clear out all signing data from Ionic server',
      '--email|-e': 'Ionic account email',
      '--password|-p': 'Ionic account password'
    },
    module: './ionic/package'
  },
  {
    title: 'upload',
    name: 'upload',
    summary: 'Upload an app to your Ionic account',
    options: {
      '--email|-e': 'Ionic account email',
      '--password|-p': 'Ionic account password'
    },
    alt: ['up'],
    module: './ionic/upload'
  },
  {
    title: 'share',
    name: 'share',
    summary: 'Share an app with a client, co-worker, friend, or customer',
    args: {
      '<EMAIL>': 'The email to share the app with',
    },
    module: './ionic/share'
  },
  {
    title: 'lib',
    name: 'lib',
    summary: 'Gets Ionic library version or updates the Ionic library',
    args: {
      '[options]': '',
      '[update]': 'Updates the Ionic Framework in www/lib/ionic'
    },
    options: {
      '--version|-v': 'Specific Ionic version\nOtherwise it defaults to the latest version'
    },
    module: './ionic/lib'
  },
  {
    title: 'setup',
    name: 'setup',
    summary: 'Configure the project with a build tool ' + '(beta)'.yellow,
    args: {
      '[sass]': 'Setup the project to use Sass CSS precompiling'
    },
    module: './ionic/setup'
  },
  {
    title: 'login',
    name: 'login',
    module: './ionic/login'
  },
  {
    title: 'address',
    name: 'address',
    module: './ionic/serve'
  },
  {
    title: 'app',
    name: 'app',
    // summary: 'Deploy a new Ionic app version or list versions',
    // options: {
    //   '--versions|-v': 'List recently uploaded versions of this app',
    //   '--deploy|-d': 'Upload the current working copy and mark it as deployed',
    //   '--note|-n': 'Add a note to a deploy',
    //   '--uuid|-u': 'Mark an already uploaded version as deployed'
    // },
    module: './ionic/app'
   },
   {
    title: 'push',
    name: 'push',
    module: './ionic/push'
   },
   {
    title: 'browser',
    name: 'browser',
    summary: 'Add another browser for a platform ' + '(beta)'.yellow,
    args: {
      '<command>': '"add remove rm info versions upgrade list ls revert"',
      '[browser]': 'The browser you wish to add or remove (Crosswalk)'
    },
    options: {
      '--nosave|-n': 'Do not save the platforms and plugins to the package.json file'
    },
    module: './ionic/browser'
  },
  {
    title: 'service add',
    name: 'service',
    summary: 'Add an Ionic service package and install any required plugins',
    args: {
      '[options]': '',
      '<SPEC>': 'Can be a service name or a git url'
    },
    module: './ionic/service'
   },
   {
    title: 'add',
    name: 'add',
    summary: 'Add an Ion, bower component, or addon to the project',
    args: {
      '[name]': 'The name of the ion, bower component, or addon you wish to install'
    },
    module: './ionic/add'
   },
   {
    title: 'remove',
    name: 'remove',
    summary: 'Remove an Ion, bower component, or addon from the project',
    args: {
      '[name]': 'The name of the Ion, bower component, or addon you wish to remove'
    },
    module: './ionic/add',
    alt: ['rm']
   },
   {
    title: 'list',
    name: 'list',
    summary: 'List Ions, bower components, or addons in the project',
    module: './ionic/add',
    alt: ['ls']
   },
   {
    title: 'ions',
    name: 'ions',
    summary: 'List available ions to add to your project',
    module: './ionic/ions'
   },
   {
    title: 'templates',
    name: 'templates',
    summary: 'List available Ionic starter templates',
    module: './ionic/templates'
   },
   {
     title: 'info',
     name: 'info',
     summary: 'List information about the users runtime environment',
     module: './ionic/info'
   },
   {
     title: 'help',
     name: 'help',
     summary: 'Provides help for a certain command',
     args: {
       '[command]': 'The command you desire help with'
     },
     module: './ionic/help'
   },
   {
    title: 'link',
    name: 'link',
    summary: 'Sets your Ionic App ID for your project',
    args: {
      '[appId]': 'The app ID you wish to set for this project'
    },
    options: {
      '--reset|-r': 'This will reset the Ionic App ID'
    },
    module: './ionic/link'
   },
   {

    title: 'hooks',
    name: 'hooks',
    summary: 'Manage your Ionic Cordova hooks',
    args: {
      '[add|remove|permissions|perm]': 'Add, remove, or modify permissions on the default Ionic Cordova hooks'
    },
    module: './ionic/hooks'
  },
  {
    title: 'state',
    name: 'state',
    summary: 'Saves or restores state of your Ionic Application using the package.json file',
    args: {
      '<COMMAND>': '[ save | restore | clear | reset ]'
    },
    options: {
      'save': 'Save the platforms and plugins into package.json',
      'restore': 'Restore the platforms and plugins from package.json',
      'clear': 'Clear the package.json of cordovaPlugins and cordovaPlatforms, as well as clear out the platforms and plugins folders',
      'reset': 'Clear out the platforms and plugins directories, and reinstall plugins and platforms',
      '--plugins': 'Only do operations with plugins',
      '--platforms': 'Only do operations with platforms'
    },
    module: './ionic/state'
   },
   {
    title: 'docs',
    name: 'docs',
    summary: 'Opens up the documentation for Ionic',
    args: {
      '<TOPIC>': 'the topic to view help documentation for. Use "ls" to view all topics'
    },
    module: './ionic/docs'
   }
];

module.exports = TASKS;
<commit_msg>Fix(cliTasks): Add in boolean options for tasks with titles.<commit_after>var resourcesSummary = [
  'Automatically create icon and splash screen resources' + ' (beta)'.yellow,
  'Put your images in the ./resources directory, named splash or icon.',
  'Accepted file types are .png, .ai, and .psd.',
  'Icons should be 192x192 px without rounded corners.',
  'Splashscreens should be 2208x2208 px, with the image centered in the middle.\n'
].join('\n\t\t      ');

var TASKS = [
  {
    title: 'start',
    name: 'start',
    summary: 'Starts a new Ionic project in the specified PATH',
    args: {
      '[options]': 'any flags for the command',
      '<PATH>': 'directory for the new project',
      '[template]': 'Template name, ex: tabs, sidemenu, blank\n' +
                    'Codepen url, ex: http://codepen.io/ionic/pen/odqCz\n' +
                    'Defaults to Ionic "tabs" starter template'
    },
    options: {
      '--appname|-a': 'Human readable name for the app (Use quotes around the name)',
      '--id|-i': 'Package name for <widget id> config, ex: com.mycompany.myapp',
      '--no-cordova|-w': {
        title: 'Create a basic structure without Cordova requirements',
        boolean: true
      },
      '--sass|-s': {
        title: 'Setup the project to use Sass CSS precompiling',
        boolean: true
      },
      '--list|-l': {
        title: 'List starter templates available',
        boolean: true
      },
      '--io-app-id': 'The Ionic.io app ID to use',
      '--template|-t': 'Project starter template'
    },
    module: './ionic/start'
  },
  {
    title: 'serve',
    name: 'serve',
    summary: 'Start a local development server for app dev/testing',
    args: {
      '[options]': ''
    },
    options: {
      '--consolelogs|-c': {
        title: 'Print app console logs to Ionic CLI',
        boolean: true
      },
      '--serverlogs|-s': {
        title: 'Print dev server logs to Ionic CLI',
        boolean: true
      },
      '--port|-p': 'Dev server HTTP port (8100 default)',
      '--livereload-port|-r': 'Live Reload port (35729 default)',
      '--nobrowser|-b': {
        title: 'Disable launching a browser',
        boolean: true
      },
      '--nolivereload|-d': {
        title: 'Do not start live reload',
        boolean: true
      },
      '--noproxy|-x': {
        title: 'Do not add proxies',
        boolean: true
      },
      '--address': 'Use specific address or return with failure',
      '--all|-a': {
        title: 'Have the server listen on all addresses (0.0.0.0)',
        boolean: true
      },
      '--browser|-w': 'Specifies the browser to use (safari, firefox, chrome)',
      '--browseroption|-o': 'Specifies a path to open to (/#/tab/dash)',
      '--lab|-l': {
        title: 'Test your apps on multiple screen sizes and platform types',
        boolean: true
      },
      '--nogulp': {
        title: 'Disable running gulp during serve',
        boolean: true
      },
      '--platform|-t': 'Start serve with a specific platform (ios/android)'
    },
    module: './ionic/serve'
  },
  {
    title: 'platform',
    name: 'platform',
    summary: 'Add platform target for building an Ionic app',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--noresources|-r': {
        title: 'Do not add default Ionic icons and splash screen resources',
        boolean: true
      },
      '--nosave|-e': {
        title: 'Do not save the platform to the package.json file',
        boolean: true
      }
    },
    module: './ionic/cordova'
  },
  {
    title: 'run',
    name: 'run',
    summary: 'Run an Ionic project on a connected device',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--livereload|-l': 'Live reload app dev files from the device' + ' (beta)'.yellow,
      '--port|-p': 'Dev server HTTP port (8100 default, livereload req.)',
      '--livereload-port|-r': 'Live Reload port (35729 default, livereload req.)',
      '--consolelogs|-c': {
        title: 'Print app console logs to Ionic CLI (livereload req.)',
        boolean: true
      },
      '--serverlogs|-s': {
        title: 'Print dev server logs to Ionic CLI (livereload req.)',
        boolean: true
      },
      '--debug|--release': {
        title: '',
        boolean: true
      },
      '--device|--emulator|--target=FOO': ''
    },
    module: './ionic/cordova'
  },
  {
    title: 'emulate',
    name: 'emulate',
    summary: 'Emulate an Ionic project on a simulator or emulator',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--livereload|-l': 'Live reload app dev files from the device' + ' (beta)'.yellow,
      '--port|-p': 'Dev server HTTP port (8100 default, livereload req.)',
      '--livereload-port|-r': 'Live Reload port (35729 default, livereload req.)',
      '--consolelogs|-c': {
        title: 'Print app console logs to Ionic CLI (livereload req.)',
        boolean: true
      },
      '--serverlogs|-s': {
        title: 'Print dev server logs to Ionic CLI (livereload req.)',
        boolean: true
      },
      '--nohooks|-n': {
        title: 'Do not add default Ionic hooks for Cordova',
        boolean: true
      },
      '--debug|--release': {
        title: '',
        boolean: true
      },
      '--device|--emulator|--target=FOO': ''
    },
    module: './ionic/cordova'
  },
  {
    title: 'build',
    name: 'build',
    summary: 'Locally build an Ionic project for a given platform',
    args: {
      '[options]': '',
      '<PLATFORM>': ''
    },
    options: {
      '--nohooks|-n': {
        title: 'Do not add default Ionic hooks for Cordova',
        boolean: true
      }
    },
    module: './ionic/cordova'
  },
  {
    title: 'plugin add',
    name: 'plugin',
    summary: 'Add a Cordova plugin',
    args: {
      '[options]': '',
      '<SPEC>': 'Can be a plugin ID, a local path, or a git URL.'
    },
    options: {
      '--searchpath <directory>': 'When looking up plugins by ID, look in this directory\n' +
                                  'and subdirectories first for the plugin before\n' +
                                  'looking it up in the registry.',
      '--nosave|-e': {
        title: 'Do not save the plugin to the package.json file',
        boolean: true
      }
    },
    module: './ionic/cordova'
  },
  {
    title: 'prepare',
    name: 'prepare',
    module: './ionic/cordova'
  },
  {
    title: 'compile',
    name: 'compile',
    module: './ionic/cordova'
  },
  {
    title: 'resources',
    name: 'resources',
    summary: resourcesSummary,
    options: {
      '--icon|-i': {
        title: 'Generate icon resources',
        boolean: true
      },
      '--splash|-s': {
        title: 'Generate splash screen resources',
        boolean: true
      }
    },
    module: './ionic/resources/generate'
  },
  {
    title: 'package',
    name: 'package',
    alt: ['pack'],
    summary: 'Package an app using the Ionic Build service' + ' (beta)'.yellow,
    args: {
      '[options]': '',
      '<MODE>': '"debug" or "release"',
      '<PLATFORM>': '"ios" or "android"'
    },
    options: {
      '--android-keystore-file|-k': 'Android keystore file',
      '--android-keystore-alias|-a': 'Android keystore alias',
      '--android-keystore-password|-w': 'Android keystore password',
      '--android-key-password|-r': 'Android key password',
      '--ios-certificate-file|-c': 'iOS certificate file',
      '--ios-certificate-password|-d': 'iOS certificate password',
      '--ios-profile-file|-f': 'iOS profile file',
      '--output|-o': 'Path to save the packaged app',
      '--no-email|-n': {
        title: 'Do not send a build package email',
        boolean: true
      },
      '--clear-signing|-l': 'Clear out all signing data from Ionic server',
      '--email|-e': 'Ionic account email',
      '--password|-p': 'Ionic account password'
    },
    module: './ionic/package'
  },
  {
    title: 'upload',
    name: 'upload',
    summary: 'Upload an app to your Ionic account',
    options: {
      '--email|-e': 'Ionic account email',
      '--password|-p': 'Ionic account password',
      '--note': 'The note to signify the upload'
    },
    alt: ['up'],
    module: './ionic/upload'
  },
  {
    title: 'share',
    name: 'share',
    summary: 'Share an app with a client, co-worker, friend, or customer',
    args: {
      '<EMAIL>': 'The email to share the app with',
    },
    module: './ionic/share'
  },
  {
    title: 'lib',
    name: 'lib',
    summary: 'Gets Ionic library version or updates the Ionic library',
    args: {
      '[options]': '',
      '[update]': 'Updates the Ionic Framework in www/lib/ionic'
    },
    options: {
      '--version|-v': 'Specific Ionic version\nOtherwise it defaults to the latest version'
    },
    module: './ionic/lib'
  },
  {
    title: 'setup',
    name: 'setup',
    summary: 'Configure the project with a build tool ' + '(beta)'.yellow,
    args: {
      '[sass]': 'Setup the project to use Sass CSS precompiling'
    },
    module: './ionic/setup'
  },
  {
    title: 'login',
    name: 'login',
    module: './ionic/login'
  },
  {
    title: 'address',
    name: 'address',
    module: './ionic/serve'
  },
  {
    title: 'app',
    name: 'app',
    // summary: 'Deploy a new Ionic app version or list versions',
    // options: {
    //   '--versions|-v': 'List recently uploaded versions of this app',
    //   '--deploy|-d': 'Upload the current working copy and mark it as deployed',
    //   '--note|-n': 'Add a note to a deploy',
    //   '--uuid|-u': 'Mark an already uploaded version as deployed'
    // },
    module: './ionic/app'
   },
   {
    title: 'push',
    name: 'push',
    module: './ionic/push'
   },
   {
    title: 'browser',
    name: 'browser',
    summary: 'Add another browser for a platform ' + '(beta)'.yellow,
    args: {
      '<command>': '"add remove rm info versions upgrade list ls revert"',
      '[browser]': 'The browser you wish to add or remove (Crosswalk)'
    },
    options: {
      '--nosave|-n': {
        title: 'Do not save the platforms and plugins to the package.json file',
        boolean: true
      }
    },
    module: './ionic/browser'
  },
  {
    title: 'service add',
    name: 'service',
    summary: 'Add an Ionic service package and install any required plugins',
    args: {
      '[options]': '',
      '<SPEC>': 'Can be a service name or a git url'
    },
    module: './ionic/service'
   },
   {
    title: 'add',
    name: 'add',
    summary: 'Add an Ion, bower component, or addon to the project',
    args: {
      '[name]': 'The name of the ion, bower component, or addon you wish to install'
    },
    module: './ionic/add'
   },
   {
    title: 'remove',
    name: 'remove',
    summary: 'Remove an Ion, bower component, or addon from the project',
    args: {
      '[name]': 'The name of the Ion, bower component, or addon you wish to remove'
    },
    module: './ionic/add',
    alt: ['rm']
   },
   {
    title: 'list',
    name: 'list',
    summary: 'List Ions, bower components, or addons in the project',
    module: './ionic/add',
    alt: ['ls']
   },
   {
    title: 'ions',
    name: 'ions',
    summary: 'List available ions to add to your project',
    module: './ionic/ions'
   },
   {
    title: 'templates',
    name: 'templates',
    summary: 'List available Ionic starter templates',
    module: './ionic/templates'
   },
   {
     title: 'info',
     name: 'info',
     summary: 'List information about the users runtime environment',
     module: './ionic/info'
   },
   {
     title: 'help',
     name: 'help',
     summary: 'Provides help for a certain command',
     args: {
       '[command]': 'The command you desire help with'
     },
     module: './ionic/help'
   },
   {
    title: 'link',
    name: 'link',
    summary: 'Sets your Ionic App ID for your project',
    args: {
      '[appId]': 'The app ID you wish to set for this project'
    },
    options: {
      '--reset|-r': {
        title: 'This will reset the Ionic App ID',
        boolean: true
      }
    },
    module: './ionic/link'
   },
   {

    title: 'hooks',
    name: 'hooks',
    summary: 'Manage your Ionic Cordova hooks',
    args: {
      '[add|remove|permissions|perm]': 'Add, remove, or modify permissions on the default Ionic Cordova hooks'
    },
    module: './ionic/hooks'
  },
  {
    title: 'state',
    name: 'state',
    summary: 'Saves or restores state of your Ionic Application using the package.json file',
    args: {
      '<COMMAND>': '[ save | restore | clear | reset ]'
    },
    options: {
      'save': 'Save the platforms and plugins into package.json',
      'restore': 'Restore the platforms and plugins from package.json',
      'clear': 'Clear the package.json of cordovaPlugins and cordovaPlatforms, as well as clear out the platforms and plugins folders',
      'reset': 'Clear out the platforms and plugins directories, and reinstall plugins and platforms',
      '--plugins': 'Only do operations with plugins',
      '--platforms': 'Only do operations with platforms'
    },
    module: './ionic/state'
   },
   {
    title: 'docs',
    name: 'docs',
    summary: 'Opens up the documentation for Ionic',
    args: {
      '<TOPIC>': 'the topic to view help documentation for. Use "ls" to view all topics'
    },
    module: './ionic/docs'
   }
];

module.exports = TASKS;
<|endoftext|>


<commit_before>'use strict';

class Balance {
    constructor(request, response){
        this.request = request;
        this.response = response;
        this.currentUser = request.user;
    }

    transfer() {
        if(!this.currentUser){
            this.response.error({message: "Tem que estar logado..."});
            return;
        }

        const cpf = this.request.params.cpf;
        const value = this.request.params.value;
        const sbalance = this.currentUser.get("balance") || 0;

        if(cpf === undefined || value === undefined || value > sbalance){
            this.response.error({message: "Parametros invalidos..."});
            return;
        }

        let query = new Parse.Query(Parse.User);
        query.equalTo("username", cpf);
        query.first().then((user) => {
            user.set("balance", user.get('balance')+parseFloat(value));
            return user.save(null, {useMasterKey:true});
        }).then((user) => {
            return this.currentUser.fetch();
        }).then((user) => {
            user.set("balance", user.get('balance')-parseFloat(value));
            return user.save(null, {useMasterKey:true});
        }).then((user) => {
            this.response.success(user);
        }, (error) => {
            this.response.error(error);
        })
    }

    pay() {
        if(!this.currentUser){
            this.response.error({message: "Tem que estar logado..."});
            return;
        }

        const cpf = this.request.params.cpf;
        const purchase = this.request.params.purchase;
        const sbalance = this.currentUser.get("balance") || 0;
        // value = saldo do cara caso a compra seja efetivada
        const value = sbalance - purchase;

        if (cpf === undefined || purchase === undefined) {
            this.response.error({message: "Parâmetros inválidos!"});
            return;
        }

        if(value < 0){
            this.response.error({message: "Não há saldo suficiente!"});
            return;
        }

        let query = new Parse.Query(Parse.User);
        query.equalTo("username", cpf);

        // Ainda tem que realizar a retirada (balance - value) do saldo do usuário

        // query.first().then((user) => {
        //     user.increment("balance", value);
        //     return user.save();
        // }).then((user) => {
        //     this.currentUser.increment("balance", -value);
        //     return this.currentUser.save();
        // }).then((user) => {
        //     this.response.success(user);
        // }, (error) => {
        //     this.response.error(error);
        // })
    }
}

Parse.Cloud.define('transferBalance', (req, res) => {
    new Balance(req, res).transfer();
});

Parse.Cloud.define('pay', (req, res) => {
    new Balance(req, res).pay();
});<commit_msg>updating user<commit_after>'use strict';

class Balance {
    constructor(request, response){
        this.request = request;
        this.response = response;
        this.currentUser = request.user;
    }

    transfer() {
        if(!this.currentUser){
            this.response.error({message: "Tem que estar logado..."});
            return;
        }

        const cpf = this.request.params.cpf;
        const value = this.request.params.value;
        const sbalance = this.currentUser.get("balance") || 0;

        if(cpf === undefined || value === undefined || value > sbalance){
            this.response.error({message: "Parametros invalidos..."});
            return;
        }

        let query = new Parse.Query(Parse.User);
        query.equalTo("username", cpf);
        query.first().then((user) => {
            user.set("balance", user.get('balance')+parseFloat(value));
            return user.save(null, {useMasterKey:true});
        }).then((user) => {
            return this.currentUser.fetch();
        }).then((user) => {
            user.set("balance", user.get('balance')-parseFloat(value));
            return user.save(null, {useMasterKey:true});
        }).then((user) => {
            this.response.success(user);
        }, (error) => {
            this.response.error(error);
        })
    }

    pay() {
        if(!this.currentUser){
            this.response.error({message: "Tem que estar logado..."});
            return;
        }

        const cpf = this.request.params.cpf;
        const purchase = this.request.params.purchase;
        const sbalance = this.currentUser.get("balance") || 0;

        if (cpf === undefined || purchase === undefined) {
            this.response.error({message: "Parâmetros inválidos!"});
            return;
        }

        const value = sbalance - purchase;
        if(value < 0){
            this.response.error({message: "Não há saldo suficiente!"});
            return;
        }

        let query = new Parse.Query(Parse.User);
        query.equalTo("username", cpf);

        try {
            query.first()
                .then((user) => {
                    user.set("balance", value);
                    return user.save();
                })
                .then((user) => {
                    this.response.success(user);
                }, (error) => {
                    this.response.error(error);
                })
        } catch (Error) {
            this.response.error({message: "Não foi possível realizar operação!"});
            return;
        }
    }
}

Parse.Cloud.define('transferBalance', (req, res) => {
    new Balance(req, res).transfer();
});

Parse.Cloud.define('pay', (req, res) => {
    new Balance(req, res).pay();
});<|endoftext|>


<commit_before>import ExtractBrightnessFilter from './ExtractBrightnessFilter';
import {vertex} from '@tools/fragments';
import fragment from './advanced-bloom.frag';

/**
 * The AdvancedBloomFilter applies a Bloom Effect to an object. Unlike the normal BloomFilter
 * this had some advanced controls for adjusting the look of the bloom. Note: this filter
 * is slower than normal BloomFilter.

 * ![original](../tools/screenshots/dist/original.png)![filter](../tools/screenshots/dist/advanced-bloom.png)
 *
 * @class
 * @extends PIXI.Filter
 * @memberof PIXI.filters
 *
 * @param {object|number} [options] - The optional parameters of advanced bloom filter.
 *                        When options is a number , it will be `options.threshold`.
 * @param {number} [options.threshold=0.5] - Defines how bright a color needs to be to affect bloom.
 * @param {number} [options.bloomScale=1.0] - To adjust the strength of the bloom. Higher values is more intense brightness.
 * @param {number} [options.brightness=1.0] - The brightness, lower value is more subtle brightness, higher value is blown-out.
 * @param {number} [options.blur=8] - Sets the strength of both the blurX and blurY properties simultaneously
 * @param {number} [options.quality=4] - The quality of the blurX & blurY filter.
 * @param {number} [options.kernelSize=5] - The kernelSize of the blurX & blurY filter.Options: 5, 7, 9, 11, 13, 15.
 * @param {number} [options.kawase=null] - The options of the Kawase Blur filter.
 * @param {number} [options.resolution=PIXI.settings.RESOLUTION] - The resolution of the blurX & blurY filter.
 */
export default class AdvancedBloomFilter extends PIXI.Filter {

    constructor(options) {

        super(vertex, fragment);

        if (typeof options === 'number') {
            options = { threshold: options };
        }

        options = Object.assign({
            threshold: 0.5,
            bloomScale: 1.0,
            brightness: 1.0,
            blur: 8,
            quality: 4,
            kernelSize: 5,
            kawase: null,
            resolution: PIXI.settings.RESOLUTION,
        }, options);

        /**
         * To adjust the strength of the bloom. Higher values is more intense brightness.
         *
         * @member {number}
         * @default 1.0
         */
        this.bloomScale = options.bloomScale;

        /**
         * The brightness, lower value is more subtle brightness, higher value is blown-out.
         *
         * @member {number}
         * @default 1.0
         */
        this.brightness = options.brightness;

        const { blur, kawase, quality, resolution, kernelSize } = options;
        const { KawaseBlurFilter, BlurXFilter, BlurYFilter } = PIXI.filters;

        this._blur = blur;
        this._kawase = kawase;
        this._resolution = resolution;

        this._extract = new ExtractBrightnessFilter(options.threshold);
        this._extract.resolution = resolution;

        if (KawaseBlurFilter && kawase) {
            this._kawaseBlur = new KawaseBlurFilter(kawase.kernels, kawase.pixelSize);
            this._kawaseBlur.resolution = resolution;
        }

        this._blurXFilter = new BlurXFilter(blur, quality, resolution, kernelSize);
        this._blurYFilter = new BlurYFilter(blur, quality, resolution, kernelSize);
    }

    /**
     * Override existing apply method in PIXI.Filter
     * @private
     */
    apply(filterManager, input, output, clear, currentState) {

        const brightTarget = filterManager.getRenderTarget(true);
        let bloomTarget;

        this._extract.apply(filterManager, input, brightTarget, true, currentState);

        if (this._kawase && this._kawaseBlur) {
            bloomTarget = filterManager.getRenderTarget(true);
            this._kawaseBlur.apply(filterManager, brightTarget, bloomTarget, true, currentState);
        }
        else {
            this._blurXFilter.apply(filterManager, brightTarget, brightTarget, true, currentState);
            this._blurYFilter.apply(filterManager, brightTarget, brightTarget, true, currentState);
            bloomTarget = brightTarget;
        }

        this.uniforms.bloomScale = this.bloomScale;
        this.uniforms.brightness = this.brightness;
        this.uniforms.bloomTexture = bloomTarget;

        filterManager.applyFilter(this, input, output, clear);

        if (bloomTarget !== brightTarget) {
            filterManager.returnRenderTarget(bloomTarget);
        }
        filterManager.returnRenderTarget(brightTarget);
    }

    /**
     * The resolution of the filter.
     *
     * @member {number}
     */
    get resolution() {
        return this._resolution;
    }
    set resolution(value) {
        this._resolution = value;

        if (this._kawase && this._kawaseBlur) {
            this._kawaseBlur.resolution = value;
        }

        if (this._blurXFilter && this._blurYFilter) {
            this._blurXFilter.resolution = this._blurYFilter.resolution = value;
        }
    }

    /**
     * Defines how bright a color needs to be to affect bloom.
     *
     * @member {number}
     * @default 0.5
     */
    get threshold() {
        return this._extract.threshold;
    }
    set threshold(value) {
        this._extract.threshold = value;
    }

    /**
     * Sets the strength of both the blurX and blurY properties simultaneously
     *
     * @member {number}
     * @default 2
     */
    get blur() {
        return this._blur;
    }
    set blur(value) {
        this._blur = value;
        this._blurXFilter.blur = this._blurYFilter.blur = value;
    }

    /**
     * Sets the options of the Kawase Blur filter
     *
     * @member {object}
     * @default null
     */
    get kawase() {
        return this._kawase;
    }
    set kawase(value) {
        this._kawase = value;

        if (!value || !PIXI.filters.KawaseBlurFilter) {
            return;
        }

        if (!this._kawaseBlur) {
            this._kawaseBlur = new PIXI.filters.KawaseBlurFilter(value.kernels, value.pixelSize);
            this._kawaseBlur.resolution = this._resolution;
        }
        else {
            this._kawaseBlur.kernels = value.kernels;
            this._kawaseBlur.pixelSize = value.pixelSize;
        }
    }
}

// Export to PixiJS namespace
PIXI.filters.AdvancedBloomFilter = AdvancedBloomFilter;
<commit_msg>cosmetic<commit_after>import ExtractBrightnessFilter from './ExtractBrightnessFilter';
import {vertex} from '@tools/fragments';
import fragment from './advanced-bloom.frag';

/**
 * The AdvancedBloomFilter applies a Bloom Effect to an object. Unlike the normal BloomFilter
 * this had some advanced controls for adjusting the look of the bloom. Note: this filter
 * is slower than normal BloomFilter.

 * ![original](../tools/screenshots/dist/original.png)![filter](../tools/screenshots/dist/advanced-bloom.png)
 *
 * @class
 * @extends PIXI.Filter
 * @memberof PIXI.filters
 *
 * @param {object|number} [options] - The optional parameters of advanced bloom filter.
 *                        When options is a number , it will be `options.threshold`.
 * @param {number} [options.threshold=0.5] - Defines how bright a color needs to be to affect bloom.
 * @param {number} [options.bloomScale=1.0] - To adjust the strength of the bloom. Higher values is more intense brightness.
 * @param {number} [options.brightness=1.0] - The brightness, lower value is more subtle brightness, higher value is blown-out.
 * @param {number} [options.blur=8] - Sets the strength of both the blurX and blurY properties simultaneously
 * @param {number} [options.quality=4] - The quality of the blurX & blurY filter.
 * @param {number} [options.kernelSize=5] - The kernelSize of the blurX & blurY filter.Options: 5, 7, 9, 11, 13, 15.
 * @param {number} [options.kawase=null] - The options of the Kawase Blur filter.
 * @param {number} [options.resolution=PIXI.settings.RESOLUTION] - The resolution of the blurX & blurY filter.
 */
export default class AdvancedBloomFilter extends PIXI.Filter {

    constructor(options) {

        super(vertex, fragment);

        if (typeof options === 'number') {
            options = { threshold: options };
        }

        options = Object.assign({
            threshold: 0.5,
            bloomScale: 1.0,
            brightness: 1.0,
            blur: 8,
            quality: 4,
            kernelSize: 5,
            kawase: null,
            resolution: PIXI.settings.RESOLUTION,
        }, options);

        /**
         * To adjust the strength of the bloom. Higher values is more intense brightness.
         *
         * @member {number}
         * @default 1.0
         */
        this.bloomScale = options.bloomScale;

        /**
         * The brightness, lower value is more subtle brightness, higher value is blown-out.
         *
         * @member {number}
         * @default 1.0
         */
        this.brightness = options.brightness;

        const { kawase, blur, quality, kernelSize, resolution } = options;
        const { KawaseBlurFilter, BlurXFilter, BlurYFilter } = PIXI.filters;

        this._kawase = kawase;
        this._blur = blur;
        this._resolution = resolution;

        this._extract = new ExtractBrightnessFilter(options.threshold);
        this._extract.resolution = resolution;

        if (KawaseBlurFilter && kawase) {
            this._kawaseBlur = new KawaseBlurFilter(kawase.kernels, kawase.pixelSize);
            this._kawaseBlur.resolution = resolution;
        }

        this._blurXFilter = new BlurXFilter(blur, quality, resolution, kernelSize);
        this._blurYFilter = new BlurYFilter(blur, quality, resolution, kernelSize);
    }

    /**
     * Override existing apply method in PIXI.Filter
     * @private
     */
    apply(filterManager, input, output, clear, currentState) {

        const brightTarget = filterManager.getRenderTarget(true);
        let bloomTarget;

        this._extract.apply(filterManager, input, brightTarget, true, currentState);

        if (this._kawase && this._kawaseBlur) {
            bloomTarget = filterManager.getRenderTarget(true);
            this._kawaseBlur.apply(filterManager, brightTarget, bloomTarget, true, currentState);
        }
        else {
            this._blurXFilter.apply(filterManager, brightTarget, brightTarget, true, currentState);
            this._blurYFilter.apply(filterManager, brightTarget, brightTarget, true, currentState);
            bloomTarget = brightTarget;
        }

        this.uniforms.bloomScale = this.bloomScale;
        this.uniforms.brightness = this.brightness;
        this.uniforms.bloomTexture = bloomTarget;

        filterManager.applyFilter(this, input, output, clear);

        if (bloomTarget !== brightTarget) {
            filterManager.returnRenderTarget(bloomTarget);
        }
        filterManager.returnRenderTarget(brightTarget);
    }

    /**
     * The resolution of the filter.
     *
     * @member {number}
     */
    get resolution() {
        return this._resolution;
    }
    set resolution(value) {
        this._resolution = value;

        if (this._kawase && this._kawaseBlur) {
            this._kawaseBlur.resolution = value;
        }

        if (this._blurXFilter && this._blurYFilter) {
            this._blurXFilter.resolution = this._blurYFilter.resolution = value;
        }
    }

    /**
     * Defines how bright a color needs to be to affect bloom.
     *
     * @member {number}
     * @default 0.5
     */
    get threshold() {
        return this._extract.threshold;
    }
    set threshold(value) {
        this._extract.threshold = value;
    }

    /**
     * Sets the strength of both the blurX and blurY properties simultaneously
     *
     * @member {number}
     * @default 2
     */
    get blur() {
        return this._blur;
    }
    set blur(value) {
        this._blur = value;
        this._blurXFilter.blur = this._blurYFilter.blur = value;
    }

    /**
     * Sets the options of the Kawase Blur filter
     *
     * @member {object}
     * @default null
     */
    get kawase() {
        return this._kawase;
    }
    set kawase(value) {
        this._kawase = value;

        if (!value || !PIXI.filters.KawaseBlurFilter) {
            return;
        }

        if (!this._kawaseBlur) {
            this._kawaseBlur = new PIXI.filters.KawaseBlurFilter(value.kernels, value.pixelSize);
            this._kawaseBlur.resolution = this._resolution;
        }
        else {
            this._kawaseBlur.kernels = value.kernels;
            this._kawaseBlur.pixelSize = value.pixelSize;
        }
    }
}

// Export to PixiJS namespace
PIXI.filters.AdvancedBloomFilter = AdvancedBloomFilter;
<|endoftext|>


<commit_before>/**
 * Created by Daniel on 2016-04-29.
 */
(function () {
    'use strict';

    angular
      .module('app.robotCycleAnalysis')
      .controller('RobotCycleAnalysisController', RobotCycleAnalysisController);

    RobotCycleAnalysisController.$inject = ['$scope', '$uibModal', 'dashboardService', 'robotCycleAnalysisService', 'eventService', '$interval'];
    /* @ngInject */
    function RobotCycleAnalysisController($scope, $uibModal, dashboardService, robotCycleAnalysisService, eventService, $interval) {
        var activityTypes = ['routines'],
            dateTimeFormat = 'yyyy-MM-dd HH:mm:ss',
            intervalPromise = null,
            liveChartTimeOpened = new Date(),
            liveChartUpdateInterval = 3000,
            minutesSecondsFormat = 'mm:ss',
            timeFormat = 'HH:mm:ss',
            vm = this;

        vm.historicalFromDate = new Date(0);
        vm.liveChartData = [];
        vm.liveChartTooltipContent =
            '{{task.model.name}}
' +
            '' +
            '{{task.model.from.format(\'' + timeFormat + '\')}} - ' +
            '{{task.model.to.format(\'' + timeFormat + '\')}}
' +
            '{{task.model.duration / 1000 | number:0}} s' +
            '';
        vm.liveFromDate = null;
        vm.liveToDate = null;
        vm.registerApi = registerApi;
        vm.removeCycle = removeCycle;
        vm.searchCycles = searchCycles;
        vm.selectWorkCell = selectWorkCell;
        vm.service = robotCycleAnalysisService;
        vm.setLiveChartWidth = setLiveChartWidth;
        vm.setupBus = setupBus;
        vm.taskTooltipContent =
            '{{task.model.name}}
' +
            '' +
            '{{task.model.absoluteTime.from | date:\'' + dateTimeFormat + '\'}} - ' +
            '{{task.model.absoluteTime.to | date:\'' + dateTimeFormat + '\'}}
' +
            '{{task.model.from.format(\'' + minutesSecondsFormat + '\')}} - ' +
            '{{task.model.to.format(\'' + minutesSecondsFormat + '\')}}
' +
            '{{task.model.duration / 1000 | number:0}} s' +
            '';
        vm.toggleLiveChart = toggleLiveChart;
        vm.treeContent =
            '{{row.model.name}}' +
            '';
        vm.widget = $scope.$parent.$parent.$parent.vm.widget;

        activate();

        function activate() {
            if (vm.widget.storage === undefined) {
                vm.widget.storage = {
                    chosenWorkCell: null,
                    ganttData: [],
                    liveChartWidth: 1,
                    showLiveChart: false
                };
            }
            if (vm.widget.storage.chosenWorkCell !== null) {
                setupLiveChart();
                toggleLiveChartTimer();
            }
            $scope.$on('closeRequest', function() {
                eventService.removeListener('Response', onResponse);
                dashboardService.closeWidget(vm.widget.id);
            });
            eventService.addListener('Response', onResponse);
        }

        function addRobotEvent(ev) {
            let activityTypeRow = _.find(vm.liveChartData, function(row) { return row.id === ev.robotId + '-' + ev.activityType; });
            if (ev.isStart) {
                activityTypeRow.tasks.push({
                    color: stringToColor(ev.name),
                    duration: new Date() - new Date(ev.time),
                    from: new Date(ev.time),
                    id: ev.activityId,
                    name: ev.name,
                    running: true,
                    to: new Date()
                });
            } else {
                let activity = _.find(activityTypeRow.tasks, function(task) { return task.id === ev.activityId; });
                if (activity === undefined) {
                    activityTypeRow.tasks.push({
                        color: stringToColor(ev.name),
                        duration: new Date() - liveChartTimeOpened,
                        from: liveChartTimeOpened,
                        id: ev.activityId,
                        name: ev.name,
                        running: false,
                        to: new Date()
                    });
                } else {
                    activity.running = false;
                    activity.to = moment(ev.time);
                    activity.duration = new Date(activity.to) - new Date(activity.from);
                }
            }
        }

        function cycleToGanttRows(cycle) {
            let ganttData = [];
            let cycleRow = {
                children: [],
                duration: new Date(cycle.from) - new Date(cycle.to),
                id: cycle.id,
                name: cycle.id.substring(0, 8),
                tasks: [{
                    absoluteTime: {
                        from: cycle.from,
                        to: cycle.to
                    },
                    duration: new Date(cycle.to) - new Date(cycle.from),
                    from: 0,
                    name: 'Cycle ' + cycle.id.substring(0, 8),
                    to: new Date(cycle.to) - new Date(cycle.from)
                }],
                type: "cycle"
            };
            _.forOwn(cycle.activities, function(activityTypes, robotName) {
                let robotRowId = toRobotRowId(cycle.id, robotName);
                cycleRow.children.push(robotRowId);
                let robotRow = {
                    children: [],
                    id: robotRowId,
                    name: robotName,
                    type: "robot"
                };
                _.forOwn(activityTypes, function(activities, activityType) {
                    let activityTypeRowId = toActivityRowId(cycle.id, robotName, activityType);
                    robotRow.children.push(activityTypeRowId);
                    let activityTypeRow = {
                        id: activityTypeRowId,
                        name: activityType,
                        tasks: [],
                        type: "activityType"
                    };
                    for (let activity of activities) {
                        activityTypeRow.tasks.push({
                            absoluteTime: {
                                from: activity.from,
                                to: activity.to
                            },
                            color: stringToColor(activity.name),
                            duration: new Date(activity.to) - new Date(activity.from),
                            from: new Date(activity.from) - new Date(cycle.from),
                            name: activity.name,
                            to: new Date(activity.to) - new Date(cycle.from)
                        });
                    }
                    ganttData.push(activityTypeRow);
                });
                ganttData.push(robotRow);
            });
            ganttData.push(cycleRow);
            console.log("ganttData: ", ganttData);
            return ganttData;
        }

        function getLongestCycleTime() {
            let longestCycleTime = 0;
            for (let cycleRow of vm.widget.storage.ganttData) {
                if (cycleRow.duration > longestCycleTime)
                    longestCycleTime = cycleRow.duration;
            }
            return longestCycleTime;
        }

        function getRoutineInfo(robotName, robotEvent) {
            let routineNumber = robotEvent.routineNumber;
            let routine = vm.widget.storage.chosenWorkCell.robots[robotName].routines[routineNumber];
            return routineNumber + ": " + routine.name + "\n" + routine.description;
        }

        function onResponse(ev){
            var attrs = ev.attributes;
            if (_.has(attrs, 'robotEvent'))
                if (vm.widget.storage.chosenWorkCell !== null &&
                    attrs.robotEvent.workCellId === vm.widget.storage.chosenWorkCell.id)
                    addRobotEvent(attrs.robotEvent);
        }

        function registerApi(api) {
            api.core.on.ready($scope, function () {
                api.side.setWidth(200);
            });
        }

        function removeCycle(rowId) {
            let row = _.find(vm.widget.storage.ganttData, function(row) { return row.id === rowId; });
            if (row.hasOwnProperty("children")) {
                for (let childRowId of row.children) {
                    removeCycle(childRowId);
                }
            }
            _.remove(vm.widget.storage.ganttData, function(el) {
                return el === row;
            });
        }

        function removeOldLiveTasks() {
            let activityTypeRows = _.filter(vm.liveChartData, function(row) {
                return row.type === 'activityType';
            });
            for (let activityTypeRow of activityTypeRows) {
               _.remove(activityTypeRow.tasks, function (task) {
                   return task.to.isBefore(vm.liveFromDate);
               });
            }
        }

        function searchCycles() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/search-cycle.html',
                controller: 'SearchCycleController',
                controllerAs: 'vm',
                resolve: {
                    workCell: function() {
                        return vm.widget.storage.chosenWorkCell;
                    }
                }
            });

            modalInstance.result.then(function(selectedCycles) {
                for (let cycle of selectedCycles) {
                    let ganttRows = cycleToGanttRows(cycle);
                    vm.widget.storage.ganttData.push(...ganttRows);
                }
            });
        }

        function selectWorkCell() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/select-work-cell.html',
                controller: 'SelectWorkCellController',
                controllerAs: 'vm'
            });

            modalInstance.result.then(function(selectedWorkCell) {
                vm.widget.storage.chosenWorkCell = selectedWorkCell;
                setupLiveChart();
            });
        }

        function setLiveChartWidth() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/set-live-chart-width.html',
                controller: 'SetLiveChartWidthController',
                controllerAs: 'vm',
                resolve: {
                    width: function () {
                        return vm.widget.storage.liveChartWidth;
                    }
                }
            });

            modalInstance.result.then(function(width) {
                vm.widget.storage.liveChartWidth = width;
                updateLiveChartTimeInterval();
            });
        }

        function setupBus() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/setup-bus.html',
                controller: 'SetupBusController',
                controllerAs: 'vm'
            });

            modalInstance.result.then(function(busSettings) {
                robotCycleAnalysisService.setupBus(busSettings);
            });
        }

        function setupLiveChart() {
            updateLiveChartTimeInterval();
            let liveChartData = [];
            for (let robot of vm.widget.storage.chosenWorkCell.robots) {
                let robotRow = {
                    children: [],
                    id: robot.id,
                    name: robot.id,
                    type: 'robot'
                };
                for (let activityType of activityTypes) {
                    let activityTypeRowId = robot.id + '-' + activityType;
                    let activityTypeRow = {
                        id: activityTypeRowId,
                        name: activityType,
                        tasks: [],
                        type: 'activityType'
                    };
                    robotRow.children.push(activityTypeRowId);
                    liveChartData.push(activityTypeRow);
                }
                liveChartData.push(robotRow);
            }
            vm.liveChartData.length = 0;
            vm.liveChartData.push(...liveChartData);
        }

        function stringToColor(str) {
            let hash = 0;
            for (let i = 0; i < str.length; i++) {
                hash = str.charCodeAt(i) + ((hash << 5) - hash);
            }
            let colour = '#';
            for (let i = 0; i < 3; i++) {
                let value = (hash >> (i * 8)) & 0xFF;
                colour += ('00' + value.toString(16)).substr(-2);
            }
            return colour;
        }

        function toActivityRowId(cycleId, robotName, activityType) {
            return cycleId + '-' + robotName + '-' + activityType;
        }

        function toRobotRowId(cycleId, robotName) {
            return cycleId + '-' + robotName;
        }

        function toggleLiveChart() {
            if (vm.widget.storage.showLiveChart) {
                robotCycleAnalysisService.stopLiveWatch(vm.widget.storage.chosenWorkCell.id);
                vm.widget.storage.showLiveChart = false;
            } else {
                liveChartTimeOpened = new Date();
                updateLiveChartTimeInterval();
                robotCycleAnalysisService.startLiveWatch(vm.widget.storage.chosenWorkCell.id);
                vm.widget.storage.showLiveChart = true;
            }
            toggleLiveChartTimer();
        }

        function toggleLiveChartTimer() {
            if (vm.widget.storage.showLiveChart)
                intervalPromise = $interval(updateLiveChart, liveChartUpdateInterval);
            else
                $interval.cancel(intervalPromise);
        }

        function updateLiveChart() {
            updateLiveChartTimeInterval();
            updateRunningActivities();
            removeOldLiveTasks();
        }

        function updateLiveChartTimeInterval() {
            let now = new Date();
            vm.liveFromDate = new Date(now.setSeconds(0) - (vm.widget.storage.liveChartWidth - 1) * 60000);
            vm.liveToDate = now.setSeconds(59);
        }

        function updateRunningActivities() {
            let activityRows = _.filter(vm.liveChartData, { 'type': 'activityType' });
            for (let activityRow of activityRows) {
                let runningActivities = _.filter(activityRow.tasks, { 'isRunning': true });
                for (let runningActivity of runningActivities) {
                    runningActivity.duration = new Date() - new Date(runningActivity.from);
                    runningActivity.to = new Date();
                }
            }
        }
    }
})();
<commit_msg>Fixed that running activities were removed from live chart.<commit_after>/**
 * Created by Daniel on 2016-04-29.
 */
(function () {
    'use strict';

    angular
      .module('app.robotCycleAnalysis')
      .controller('RobotCycleAnalysisController', RobotCycleAnalysisController);

    RobotCycleAnalysisController.$inject = ['$scope', '$uibModal', 'dashboardService', 'robotCycleAnalysisService', 'eventService', '$interval'];
    /* @ngInject */
    function RobotCycleAnalysisController($scope, $uibModal, dashboardService, robotCycleAnalysisService, eventService, $interval) {
        var activityTypes = ['routines'],
            dateTimeFormat = 'yyyy-MM-dd HH:mm:ss',
            intervalPromise = null,
            liveChartTimeOpened = new Date(),
            liveChartUpdateInterval = 3000,
            minutesSecondsFormat = 'mm:ss',
            timeFormat = 'HH:mm:ss',
            vm = this;

        vm.historicalFromDate = new Date(0);
        vm.liveChartData = [];
        vm.liveChartTooltipContent =
            '{{task.model.name}}
' +
            '' +
            '{{task.model.from.format(\'' + timeFormat + '\')}} - ' +
            '{{task.model.to.format(\'' + timeFormat + '\')}}
' +
            '{{task.model.duration / 1000 | number:0}} s' +
            '';
        vm.liveFromDate = null;
        vm.liveToDate = null;
        vm.registerApi = registerApi;
        vm.removeCycle = removeCycle;
        vm.searchCycles = searchCycles;
        vm.selectWorkCell = selectWorkCell;
        vm.service = robotCycleAnalysisService;
        vm.setLiveChartWidth = setLiveChartWidth;
        vm.setupBus = setupBus;
        vm.taskTooltipContent =
            '{{task.model.name}}
' +
            '' +
            '{{task.model.absoluteTime.from | date:\'' + dateTimeFormat + '\'}} - ' +
            '{{task.model.absoluteTime.to | date:\'' + dateTimeFormat + '\'}}
' +
            '{{task.model.from.format(\'' + minutesSecondsFormat + '\')}} - ' +
            '{{task.model.to.format(\'' + minutesSecondsFormat + '\')}}
' +
            '{{task.model.duration / 1000 | number:0}} s' +
            '';
        vm.toggleLiveChart = toggleLiveChart;
        vm.treeContent =
            '{{row.model.name}}' +
            '';
        vm.widget = $scope.$parent.$parent.$parent.vm.widget;

        activate();

        function activate() {
            if (vm.widget.storage === undefined) {
                vm.widget.storage = {
                    chosenWorkCell: null,
                    ganttData: [],
                    liveChartWidth: 1,
                    showLiveChart: false
                };
            }
            if (vm.widget.storage.chosenWorkCell !== null) {
                setupLiveChart();
                toggleLiveChartTimer();
            }
            $scope.$on('closeRequest', function() {
                eventService.removeListener('Response', onResponse);
                dashboardService.closeWidget(vm.widget.id);
            });
            eventService.addListener('Response', onResponse);
        }

        function addRobotEvent(ev) {
            let activityTypeRow = _.find(vm.liveChartData, function(row) { return row.id === ev.robotId + '-' + ev.activityType; });
            if (ev.isStart) {
                activityTypeRow.tasks.push({
                    color: stringToColor(ev.name),
                    duration: new Date() - new Date(ev.time),
                    from: new Date(ev.time),
                    id: ev.activityId,
                    name: ev.name,
                    running: true,
                    to: new Date()
                });
            } else {
                let activity = _.find(activityTypeRow.tasks, function(task) { return task.id === ev.activityId; });
                if (activity === undefined) {
                    activityTypeRow.tasks.push({
                        color: stringToColor(ev.name),
                        duration: new Date() - liveChartTimeOpened,
                        from: liveChartTimeOpened,
                        id: ev.activityId,
                        name: ev.name,
                        running: false,
                        to: new Date()
                    });
                } else {
                    activity.running = false;
                    activity.to = moment(ev.time);
                    activity.duration = new Date(activity.to) - new Date(activity.from);
                }
            }
        }

        function cycleToGanttRows(cycle) {
            let ganttData = [];
            let cycleRow = {
                children: [],
                duration: new Date(cycle.from) - new Date(cycle.to),
                id: cycle.id,
                name: cycle.id.substring(0, 8),
                tasks: [{
                    absoluteTime: {
                        from: cycle.from,
                        to: cycle.to
                    },
                    duration: new Date(cycle.to) - new Date(cycle.from),
                    from: 0,
                    name: 'Cycle ' + cycle.id.substring(0, 8),
                    to: new Date(cycle.to) - new Date(cycle.from)
                }],
                type: "cycle"
            };
            _.forOwn(cycle.activities, function(activityTypes, robotName) {
                let robotRowId = toRobotRowId(cycle.id, robotName);
                cycleRow.children.push(robotRowId);
                let robotRow = {
                    children: [],
                    id: robotRowId,
                    name: robotName,
                    type: "robot"
                };
                _.forOwn(activityTypes, function(activities, activityType) {
                    let activityTypeRowId = toActivityRowId(cycle.id, robotName, activityType);
                    robotRow.children.push(activityTypeRowId);
                    let activityTypeRow = {
                        id: activityTypeRowId,
                        name: activityType,
                        tasks: [],
                        type: "activityType"
                    };
                    for (let activity of activities) {
                        activityTypeRow.tasks.push({
                            absoluteTime: {
                                from: activity.from,
                                to: activity.to
                            },
                            color: stringToColor(activity.name),
                            duration: new Date(activity.to) - new Date(activity.from),
                            from: new Date(activity.from) - new Date(cycle.from),
                            name: activity.name,
                            to: new Date(activity.to) - new Date(cycle.from)
                        });
                    }
                    ganttData.push(activityTypeRow);
                });
                ganttData.push(robotRow);
            });
            ganttData.push(cycleRow);
            console.log("ganttData: ", ganttData);
            return ganttData;
        }

        function getLongestCycleTime() {
            let longestCycleTime = 0;
            for (let cycleRow of vm.widget.storage.ganttData) {
                if (cycleRow.duration > longestCycleTime)
                    longestCycleTime = cycleRow.duration;
            }
            return longestCycleTime;
        }

        function getRoutineInfo(robotName, robotEvent) {
            let routineNumber = robotEvent.routineNumber;
            let routine = vm.widget.storage.chosenWorkCell.robots[robotName].routines[routineNumber];
            return routineNumber + ": " + routine.name + "\n" + routine.description;
        }

        function onResponse(ev){
            var attrs = ev.attributes;
            if (_.has(attrs, 'robotEvent'))
                if (vm.widget.storage.chosenWorkCell !== null &&
                    attrs.robotEvent.workCellId === vm.widget.storage.chosenWorkCell.id)
                    addRobotEvent(attrs.robotEvent);
        }

        function registerApi(api) {
            api.core.on.ready($scope, function () {
                api.side.setWidth(200);
            });
        }

        function removeCycle(rowId) {
            let row = _.find(vm.widget.storage.ganttData, function(row) { return row.id === rowId; });
            if (row.hasOwnProperty("children")) {
                for (let childRowId of row.children) {
                    removeCycle(childRowId);
                }
            }
            _.remove(vm.widget.storage.ganttData, function(el) {
                return el === row;
            });
        }

        function removeOldLiveTasks() {
            let activityTypeRows = _.filter(vm.liveChartData, function(row) {
                return row.type === 'activityType';
            });
            for (let activityTypeRow of activityTypeRows) {
               _.remove(activityTypeRow.tasks, function (task) {
                   return !task.running && task.to.isBefore(vm.liveFromDate);
               });
            }
        }

        function searchCycles() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/search-cycle.html',
                controller: 'SearchCycleController',
                controllerAs: 'vm',
                resolve: {
                    workCell: function() {
                        return vm.widget.storage.chosenWorkCell;
                    }
                }
            });

            modalInstance.result.then(function(selectedCycles) {
                for (let cycle of selectedCycles) {
                    let ganttRows = cycleToGanttRows(cycle);
                    vm.widget.storage.ganttData.push(...ganttRows);
                }
            });
        }

        function selectWorkCell() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/select-work-cell.html',
                controller: 'SelectWorkCellController',
                controllerAs: 'vm'
            });

            modalInstance.result.then(function(selectedWorkCell) {
                vm.widget.storage.chosenWorkCell = selectedWorkCell;
                setupLiveChart();
            });
        }

        function setLiveChartWidth() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/set-live-chart-width.html',
                controller: 'SetLiveChartWidthController',
                controllerAs: 'vm',
                resolve: {
                    width: function () {
                        return vm.widget.storage.liveChartWidth;
                    }
                }
            });

            modalInstance.result.then(function(width) {
                vm.widget.storage.liveChartWidth = width;
                updateLiveChartTimeInterval();
            });
        }

        function setupBus() {
            var modalInstance = $uibModal.open({
                templateUrl: '/app/robot-cycle-analysis/setup-bus.html',
                controller: 'SetupBusController',
                controllerAs: 'vm'
            });

            modalInstance.result.then(function(busSettings) {
                robotCycleAnalysisService.setupBus(busSettings);
            });
        }

        function setupLiveChart() {
            updateLiveChartTimeInterval();
            let liveChartData = [];
            for (let robot of vm.widget.storage.chosenWorkCell.robots) {
                let robotRow = {
                    children: [],
                    id: robot.id,
                    name: robot.id,
                    type: 'robot'
                };
                for (let activityType of activityTypes) {
                    let activityTypeRowId = robot.id + '-' + activityType;
                    let activityTypeRow = {
                        id: activityTypeRowId,
                        name: activityType,
                        tasks: [],
                        type: 'activityType'
                    };
                    robotRow.children.push(activityTypeRowId);
                    liveChartData.push(activityTypeRow);
                }
                liveChartData.push(robotRow);
            }
            vm.liveChartData.length = 0;
            vm.liveChartData.push(...liveChartData);
        }

        function stringToColor(str) {
            let hash = 0;
            for (let i = 0; i < str.length; i++) {
                hash = str.charCodeAt(i) + ((hash << 5) - hash);
            }
            let colour = '#';
            for (let i = 0; i < 3; i++) {
                let value = (hash >> (i * 8)) & 0xFF;
                colour += ('00' + value.toString(16)).substr(-2);
            }
            return colour;
        }

        function toActivityRowId(cycleId, robotName, activityType) {
            return cycleId + '-' + robotName + '-' + activityType;
        }

        function toRobotRowId(cycleId, robotName) {
            return cycleId + '-' + robotName;
        }

        function toggleLiveChart() {
            if (vm.widget.storage.showLiveChart) {
                robotCycleAnalysisService.stopLiveWatch(vm.widget.storage.chosenWorkCell.id);
                vm.widget.storage.showLiveChart = false;
            } else {
                liveChartTimeOpened = new Date();
                updateLiveChartTimeInterval();
                robotCycleAnalysisService.startLiveWatch(vm.widget.storage.chosenWorkCell.id);
                vm.widget.storage.showLiveChart = true;
            }
            toggleLiveChartTimer();
        }

        function toggleLiveChartTimer() {
            if (vm.widget.storage.showLiveChart)
                intervalPromise = $interval(updateLiveChart, liveChartUpdateInterval);
            else
                $interval.cancel(intervalPromise);
        }

        function updateLiveChart() {
            updateLiveChartTimeInterval();
            updateRunningActivities();
            removeOldLiveTasks();
        }

        function updateLiveChartTimeInterval() {
            let now = new Date();
            vm.liveFromDate = new Date(now.setSeconds(0) - (vm.widget.storage.liveChartWidth - 1) * 60000);
            vm.liveToDate = now.setSeconds(59);
        }

        function updateRunningActivities() {
            let activityRows = _.filter(vm.liveChartData, { 'type': 'activityType' });
            for (let activityRow of activityRows) {
                let runningActivities = _.filter(activityRow.tasks, { 'isRunning': true });
                for (let runningActivity of runningActivities) {
                    runningActivity.duration = new Date() - new Date(runningActivity.from);
                    runningActivity.to = new Date();
                }
            }
        }
    }
})();
<|endoftext|>