<commit_before>/*
Copyright (c) 2011, Chris Umbel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

var util = require('util'),
    SingularPluralInflector = require('./singular_plural_inflector'),
    FormSet = require('./form_set');

function attach() {
    var inflector = this;

    String.prototype.singularizePresentVerb = function() {
        return inflector.singularize(this);
    }

    String.prototype.pluralizePresentVerb = function() {
        return inflector.pluralize(this);
    }
}

var VerbInflector = function() {
    this.ambiguous = [
        'will'
    ];

    this.attach = attach;

    this.customPluralForms = [];
    this.customSingularForms = [];
    this.singularForms = new FormSet();
    this.pluralForms = new FormSet();

    this.addIrregular("am", "are");
    this.addIrregular("is", "are");
    this.addIrregular("was", "were");

    this.singularForms.regularForms.push([/ed$/i, 'ed']);
    this.singularForms.regularForms.push([/ss$/i, 'sses']);
    this.singularForms.regularForms.push([/x$/i, 'xes']);
    this.singularForms.regularForms.push([/(h|z|o)$/i, '$1es']);
    this.singularForms.regularForms.push([/$zz/i, 'zzes']);
    this.singularForms.regularForms.push([/$/i, 's']);

    this.pluralForms.regularForms.push([/sses$/i, 'ss']);
    this.pluralForms.regularForms.push([/xes$/i, 'x']);
    this.pluralForms.regularForms.push([/([cs])hes$/i, '$1h']);
    this.pluralForms.regularForms.push([/zzes$/i, 'zz']);
    this.pluralForms.regularForms.push([/([^h|z|o|i])es$/i, '$1e']);
    this.pluralForms.regularForms.push([/ies$/i, 'y']);//flies->fly
    this.pluralForms.regularForms.push([/e?s$/i, '']);
};

util.inherits(VerbInflector, SingularPluralInflector);

module.exports = VerbInflector;
<commit_msg>fixed the singular form inflector for y->ies<commit_after>/*
Copyright (c) 2011, Chris Umbel

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

var util = require('util'),
    SingularPluralInflector = require('./singular_plural_inflector'),
    FormSet = require('./form_set');

function attach() {
    var inflector = this;

    String.prototype.singularizePresentVerb = function() {
        return inflector.singularize(this);
    }

    String.prototype.pluralizePresentVerb = function() {
        return inflector.pluralize(this);
    }
}

var VerbInflector = function() {
    this.ambiguous = [
        'will'
    ];

    this.attach = attach;

    this.customPluralForms = [];
    this.customSingularForms = [];
    this.singularForms = new FormSet();
    this.pluralForms = new FormSet();

    this.addIrregular("am", "are");
    this.addIrregular("is", "are");
    this.addIrregular("was", "were");

    this.singularForms.regularForms.push([/ed$/i, 'ed']);
    this.singularForms.regularForms.push([/ss$/i, 'sses']);
    this.singularForms.regularForms.push([/x$/i, 'xes']);
    this.singularForms.regularForms.push([/(h|z|o)$/i, '$1es']);
    this.singularForms.regularForms.push([/$zz/i, 'zzes']);
    this.singularForms.regularForms.push([/([^a|e|i|o|u])y$/i, '$1ies']);
    this.singularForms.regularForms.push([/$/i, 's']);

    this.pluralForms.regularForms.push([/sses$/i, 'ss']);
    this.pluralForms.regularForms.push([/xes$/i, 'x']);
    this.pluralForms.regularForms.push([/([cs])hes$/i, '$1h']);
    this.pluralForms.regularForms.push([/zzes$/i, 'zz']);
    this.pluralForms.regularForms.push([/([^h|z|o|i])es$/i, '$1e']);
    this.pluralForms.regularForms.push([/ies$/i, 'y']);//flies->fly
    this.pluralForms.regularForms.push([/e?s$/i, '']);
};

util.inherits(VerbInflector, SingularPluralInflector);

module.exports = VerbInflector;
<|endoftext|>


<commit_before>/**
 * Created by momchillgorchev on 20/10/15.
 */

Template.statusCard.events({

    /**
     * Reload single card
     */
    'click .card__reload': function(e, t){
        e.preventDefault();

        // Cache elements
        var trigger = $(e.currentTarget),
            parent = trigger.closest('.card'),
            cardId = parent.attr('data-itemid'),
            serviceUrl = parent.find('.service__link').attr('href'),
            icon = trigger.find('i');

        // Rotate the icon
        icon.addClass('rotating');
        //log(cardId);

        // Build data
        var reqData = {
            _id: cardId,
            url: serviceUrl
        };

        // Call the server and handle response
        Meteor.call('checkSingleService', reqData, function(err, res){
            if(err){
                Materialize.toast('Error: '+ err.message , 3000);
            } else {
                Materialize.toast('Service was successfully refreshed' , 3000);
                icon.removeClass('rotating');
            }
        });
    },

    /**
     * Delete service
     */
    'click .delete__service-btn': function(e,t){
        e.preventDefault();

        // Cache elements
        var trigger = $(e.currentTarget),
            parent = trigger.closest('.card'),
            cardId = parent.attr('data-itemid'),
            serviceName = parent.find('.service__link').html();

        // Confirm with the user
        if(confirm('Are you sure you want to delete this service?')){
            // Call server and handle result
            Meteor.call('deleteEndpoint', cardId, function(err, res){
                if(err){
                    Materialize.toast('[Error] operation unsuccessful', 3000);
                } else {
                    Materialize.toast('[ '+ serviceName +' ] deleted!', 3000);
                    Session.set('EpsCount', Endpoints.find().count());
                }
            });
        }
    }

});<commit_msg>Save new order after deleting an item<commit_after>/**
 * Created by momchillgorchev on 20/10/15.
 */

Template.statusCard.events({

    /**
     * Reload single card
     */
    'click .card__reload': function(e, t){
        e.preventDefault();

        // Cache elements
        var trigger = $(e.currentTarget),
            parent = trigger.closest('.card'),
            cardId = parent.attr('data-itemid'),
            serviceUrl = parent.find('.service__link').attr('href'),
            icon = trigger.find('i');

        // Rotate the icon
        icon.addClass('rotating');
        //log(cardId);

        // Build data
        var reqData = {
            _id: cardId,
            url: serviceUrl
        };

        // Call the server and handle response
        Meteor.call('checkSingleService', reqData, function(err, res){
            if(err){
                Materialize.toast('Error: '+ err.message , 3000);
            } else {
                Materialize.toast('Service was successfully refreshed' , 3000);
                icon.removeClass('rotating');
            }
        });
    },

    /**
     * Delete service
     */
    'click .delete__service-btn': function(e,t){
        e.preventDefault();

        // Cache elements
        var trigger = $(e.currentTarget),
            parent = trigger.closest('.card'),
            cardId = parent.attr('data-itemid'),
            serviceName = parent.find('.service__link').html();

        // Confirm with the user
        if(confirm('Are you sure you want to delete this service?')){
            // Call server and handle result
            Meteor.call('deleteEndpoint', cardId, function(err, res){
                if(err){
                    Materialize.toast('[Error] operation unsuccessful', 3000);
                } else {
                    Materialize.toast('[ '+ serviceName +' ] deleted!', 3000);
                    Session.set('EpsCount', Endpoints.find().count());

                    // Save new order of elements
                    //
                    // Cache elements
                    var cards = $('.card'),
                        newOrderList = [];

                    // Iterate and match the store the itemId with the
                    // corresponding position
                    for(var i = 0, count = cards.length; i < count; i++){

                        var current = cards[i];

                        // Push to an array to be sent to the server
                        newOrderList.push({
                            itemId: current.getAttribute('data-itemid'),
                            newOrder: count - i
                        });
                    }

                    // Call the service with the prepared data
                    Meteor.call('updateEndpointsOrder', newOrderList, function(err, res){

                        // Display the result in a toast and hide the buttons
                        if(err || res.error){
                            Materialize.toast('Error: '+ err.message , 3000);
                        } else {
                            Materialize.toast('Services order saved!' , 3000);
                        }
                    });
                }
            });
        }
    }

});<|endoftext|>


<commit_before>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     440
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v441 c/o Travis<commit_after>// ==UserScript==
// @author      Robert Slifka (github @rslifka)
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2017-2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepage    https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        Fate of All Fools
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @version     441
// ==/UserScript==
<|endoftext|>


<commit_before>// Copyright 2017-2020, University of Colorado Boulder

/**
 * Content for a KeyboardHelpDialog that describes how to use sliders.
 *
 * @author Jesse Greenberg
 */

import merge from '../../../../phet-core/js/merge.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import HBox from '../../../../scenery/js/nodes/HBox.js';
import sceneryPhet from '../../sceneryPhet.js';
import sceneryPhetStrings from '../../sceneryPhetStrings.js';
import TextKeyNode from '../TextKeyNode.js';
import KeyboardHelpIconFactory from './KeyboardHelpIconFactory.js';
import KeyboardHelpSection from './KeyboardHelpSection.js';

class SliderKeyboardHelpSection extends KeyboardHelpSection {

  /**
   * @param {Object} [options]
   */
  constructor( options ) {

    options = merge( {

      // heading string for this content
      headingString: sceneryPhetStrings.keyboardHelpDialog.sliderControls,

      // verb used to describe the movement of the slider
      verbString: sceneryPhetStrings.keyboardHelpDialog.adjust,

      // name to call the slider (lowercase), default to "slider"
      sliderString: sceneryPhetStrings.keyboardHelpDialog.slider,

      maximumString: sceneryPhetStrings.keyboardHelpDialog.maximum,
      minimumString: sceneryPhetStrings.keyboardHelpDialog.minimum
    }, options );

    const keyboardHelpDialogVerbSliderString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.verbSliderPattern, {
      verb: options.verbString,
      slider: options.sliderString
    } );
    const keyboardHelpDialogVerbInSmallerStepsString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.verbInSmallerStepsPattern, {
      verb: options.verbString
    } );
    const keyboardHelpDialogVerbInLargerStepsString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.verbInLargerStepsPattern, {
      verb: options.verbString
    } );

    const keyboardHelpDialogDefaultStepsString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.defaultStepsDescriptionPattern, {
      verb: options.verbString,
      slider: options.sliderString
    } );
    const keyboardHelpDialogSmallerStepsString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.smallerStepsDescriptionPattern, {
      verb: options.verbString
    } );
    const keyboardHelpDialogLargerStepsString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.largerStepsDescriptionPattern, {
      verb: options.verbString
    } );

    const jumpToMinimumString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.jumpToMinimumPattern, {
      minimum: options.minimumString
    } );
    const jumpToMaximumString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.jumpToMaximumPattern, {
      maximum: options.maximumString
    } );
    const jumpToMinimumDescriptionString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.jumpToMinimumDescriptionPattern, {
      minimum: options.minimumString
    } );
    const jumpToMaximumDescriptionString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.jumpToMaximumDescriptionPattern, {
      maximum: options.maximumString
    } );

    // 'Move sliders' content
    const adjustSliderLeftRightIcon = KeyboardHelpIconFactory.leftRightArrowKeysRowIcon();
    const adjustSliderUpDownIcon = KeyboardHelpIconFactory.upDownArrowKeysRowIcon();
    const adjustSliderIcon = KeyboardHelpIconFactory.iconOrIcon( adjustSliderLeftRightIcon, adjustSliderUpDownIcon );
    const adjustSliderRow = KeyboardHelpSection.labelWithIcon( keyboardHelpDialogVerbSliderString, adjustSliderIcon, keyboardHelpDialogDefaultStepsString );

    // 'move in smaller steps' content
    const smallStepsLeftRightIcon = KeyboardHelpIconFactory.leftRightArrowKeysRowIcon();
    const smallStepsUpDownIcon = KeyboardHelpIconFactory.upDownArrowKeysRowIcon();

    const shiftPlusLeftRightIcon = KeyboardHelpIconFactory.shiftPlusIcon( smallStepsLeftRightIcon );
    const shiftPlusUpDownIcon = KeyboardHelpIconFactory.shiftPlusIcon( smallStepsUpDownIcon );

    const adjustSliderInSmallerStepsRow = KeyboardHelpSection.labelWithIconList( keyboardHelpDialogVerbInSmallerStepsString,
      [ shiftPlusLeftRightIcon, shiftPlusUpDownIcon ], keyboardHelpDialogSmallerStepsString );

    // 'move in larger steps' content
    const pageUpKeyNode = TextKeyNode.pageUp();
    const pageDownKeyNode = TextKeyNode.pageDown();
    const pageUpPageDownIcon = new HBox( {
      children: [ pageUpKeyNode, pageDownKeyNode ],
      spacing: KeyboardHelpIconFactory.DEFAULT_ICON_SPACING
    } );
    const adjustInLargerStepsRow = KeyboardHelpSection.labelWithIcon( keyboardHelpDialogVerbInLargerStepsString, pageUpPageDownIcon, keyboardHelpDialogLargerStepsString );

    // 'move to minimum value' content
    const homeKeyNode = TextKeyNode.home();
    const jumpToMinimumRow = KeyboardHelpSection.labelWithIcon( jumpToMinimumString, homeKeyNode, jumpToMinimumDescriptionString );

    // 'move to maximum value' content
    const endKeyNode = TextKeyNode.end();
    const jumpToMaximumRow = KeyboardHelpSection.labelWithIcon( jumpToMaximumString, endKeyNode, jumpToMaximumDescriptionString );

    // assemble final content for KeyboardHelpSection
    const content = [ adjustSliderRow, adjustSliderInSmallerStepsRow, adjustInLargerStepsRow, jumpToMinimumRow, jumpToMaximumRow ];

    super( options.headingString, content, options );
  }
}

sceneryPhet.register( 'SliderKeyboardHelpSection', SliderKeyboardHelpSection );
export default SliderKeyboardHelpSection;<commit_msg>add arrowKeysIconDisplay options, https://github.com/phetsims/ratio-and-proportion/issues/82<commit_after>// Copyright 2017-2020, University of Colorado Boulder

/**
 * Content for a KeyboardHelpDialog that describes how to use sliders.
 *
 * @author Jesse Greenberg
 */

import validate from '../../../../axon/js/validate.js';
import Enumeration from '../../../../phet-core/js/Enumeration.js';
import merge from '../../../../phet-core/js/merge.js';
import StringUtils from '../../../../phetcommon/js/util/StringUtils.js';
import HBox from '../../../../scenery/js/nodes/HBox.js';
import sceneryPhet from '../../sceneryPhet.js';
import sceneryPhetStrings from '../../sceneryPhetStrings.js';
import TextKeyNode from '../TextKeyNode.js';
import KeyboardHelpIconFactory from './KeyboardHelpIconFactory.js';
import KeyboardHelpSection from './KeyboardHelpSection.js';

const ArrowKeysIconDisplay = Enumeration.byKeys( [ 'UP_DOWN', 'LEFT_RIGHT', 'BOTH' ] );

class SliderKeyboardHelpSection extends KeyboardHelpSection {

  /**
   * @param {Object} [options]
   */
  constructor( options ) {

    options = merge( {

      // {ArrowKeysIconDisplay} - Whether to show up/down, left/right or both sets of keyboard help icons to cue the
      // slider interaction.
      arrowKeyIconDisplay: ArrowKeysIconDisplay.BOTH,

      // heading string for this content
      headingString: sceneryPhetStrings.keyboardHelpDialog.sliderControls,

      // verb used to describe the movement of the slider
      verbString: sceneryPhetStrings.keyboardHelpDialog.adjust,

      // name to call the slider (lowercase), default to "slider"
      sliderString: sceneryPhetStrings.keyboardHelpDialog.slider,

      maximumString: sceneryPhetStrings.keyboardHelpDialog.maximum,
      minimumString: sceneryPhetStrings.keyboardHelpDialog.minimum
    }, options );

    validate( options.arrowKeyIconDisplay, { valueType: ArrowKeysIconDisplay } );

    const keyboardHelpDialogVerbSliderString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.verbSliderPattern, {
      verb: options.verbString,
      slider: options.sliderString
    } );
    const keyboardHelpDialogVerbInSmallerStepsString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.verbInSmallerStepsPattern, {
      verb: options.verbString
    } );
    const keyboardHelpDialogVerbInLargerStepsString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.verbInLargerStepsPattern, {
      verb: options.verbString
    } );

    const keyboardHelpDialogDefaultStepsString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.defaultStepsDescriptionPattern, {
      verb: options.verbString,
      slider: options.sliderString
    } );
    const keyboardHelpDialogSmallerStepsString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.smallerStepsDescriptionPattern, {
      verb: options.verbString
    } );
    const keyboardHelpDialogLargerStepsString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.largerStepsDescriptionPattern, {
      verb: options.verbString
    } );

    const jumpToMinimumString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.jumpToMinimumPattern, {
      minimum: options.minimumString
    } );
    const jumpToMaximumString = StringUtils.fillIn( sceneryPhetStrings.keyboardHelpDialog.jumpToMaximumPattern, {
      maximum: options.maximumString
    } );
    const jumpToMinimumDescriptionString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.jumpToMinimumDescriptionPattern, {
      minimum: options.minimumString
    } );
    const jumpToMaximumDescriptionString = StringUtils.fillIn( sceneryPhetStrings.a11y.keyboardHelpDialog.slider.jumpToMaximumDescriptionPattern, {
      maximum: options.maximumString
    } );

    // 'Move sliders' content

    const shiftPlusLeftRightIcon = KeyboardHelpIconFactory.shiftPlusIcon( KeyboardHelpIconFactory.leftRightArrowKeysRowIcon() );
    const shiftPlusUpDownIcon = KeyboardHelpIconFactory.shiftPlusIcon( KeyboardHelpIconFactory.upDownArrowKeysRowIcon() );

    let adjustSliderIcon = null;
    let adjustSliderSmallerStepsIcons = null;

    switch( options.arrowKeyIconDisplay ) {
      case ArrowKeysIconDisplay.LEFT_RIGHT:
        adjustSliderIcon = KeyboardHelpIconFactory.leftRightArrowKeysRowIcon();
        adjustSliderSmallerStepsIcons = [ shiftPlusLeftRightIcon ];
        break;
      case ArrowKeysIconDisplay.UP_DOWN:
        adjustSliderIcon = KeyboardHelpIconFactory.upDownArrowKeysRowIcon();
        adjustSliderSmallerStepsIcons = [ shiftPlusUpDownIcon ];
        break;
      default:
        assert && assert( options.arrowKeyIconDisplay === ArrowKeysIconDisplay.BOTH, 'unsupported arrowKeyIconDisplay' );
        adjustSliderIcon = KeyboardHelpIconFactory.iconOrIcon( KeyboardHelpIconFactory.leftRightArrowKeysRowIcon(), KeyboardHelpIconFactory.upDownArrowKeysRowIcon() );
        adjustSliderSmallerStepsIcons = [ shiftPlusLeftRightIcon, shiftPlusUpDownIcon ];
    }
    const adjustSliderRow = KeyboardHelpSection.labelWithIcon( keyboardHelpDialogVerbSliderString, adjustSliderIcon, keyboardHelpDialogDefaultStepsString );

    const adjustSliderInSmallerStepsRow = KeyboardHelpSection.labelWithIconList( keyboardHelpDialogVerbInSmallerStepsString,
      adjustSliderSmallerStepsIcons, keyboardHelpDialogSmallerStepsString );

    // 'move in larger steps' content
    const pageUpKeyNode = TextKeyNode.pageUp();
    const pageDownKeyNode = TextKeyNode.pageDown();
    const pageUpPageDownIcon = new HBox( {
      children: [ pageUpKeyNode, pageDownKeyNode ],
      spacing: KeyboardHelpIconFactory.DEFAULT_ICON_SPACING
    } );
    const adjustInLargerStepsRow = KeyboardHelpSection.labelWithIcon( keyboardHelpDialogVerbInLargerStepsString, pageUpPageDownIcon, keyboardHelpDialogLargerStepsString );

    // 'move to minimum value' content
    const homeKeyNode = TextKeyNode.home();
    const jumpToMinimumRow = KeyboardHelpSection.labelWithIcon( jumpToMinimumString, homeKeyNode, jumpToMinimumDescriptionString );

    // 'move to maximum value' content
    const endKeyNode = TextKeyNode.end();
    const jumpToMaximumRow = KeyboardHelpSection.labelWithIcon( jumpToMaximumString, endKeyNode, jumpToMaximumDescriptionString );

    // assemble final content for KeyboardHelpSection
    const content = [ adjustSliderRow, adjustSliderInSmallerStepsRow, adjustInLargerStepsRow, jumpToMinimumRow, jumpToMaximumRow ];

    super( options.headingString, content, options );
  }
}

// @public - for use in defining a component-specific option.
SliderKeyboardHelpSection.ArrowKeysIconDisplay = ArrowKeysIconDisplay;

sceneryPhet.register( 'SliderKeyboardHelpSection', SliderKeyboardHelpSection );
export default SliderKeyboardHelpSection;<|endoftext|>


<commit_before>/*
 @author Zakai Hamilton
 @component StorageDropBox
 */

screens.storage.dropbox = function StorageDropBox(me, packages) {
    const { core } = packages;
    me.init = function () {
        require("es6-promise").polyfill();
        me.dropbox = require("dropbox").Dropbox;
        me.fs = require("fs");
        me.https = require("https");
    };
    me.getService = async function () {
        if (me.handle) {
            return me.handle;
        }
        var fetch = require("isomorphic-fetch");
        var keys = await core.private.keys("dropbox");
        me.handle = new me.dropbox({ accessToken: keys["access-token"], fetch: fetch });
        return me.handle;
    };
    me.fixPath = function (path) {
        if (path === "/") {
            return "";
        }
        return path;
    };
    me.list = function (path) {
        return me.getChildren(path);
    };
    me.getChildren = async function (path, recursive = false) {
        me.log("requesting items for path: " + path + " recursive: " + recursive);
        var entries = [];
        var service = await me.getService();
        await me.iterate(service, entries, path, null, recursive);
        me.log("returning " + entries.length + " items for path: " + path + " recursive: " + recursive);
        return entries;
    };
    me.iterate = async function (service, entries, path, cursor, recursive) {
        var method = cursor ? "filesListFolderContinue" : "filesListFolder";
        path = me.fixPath(path);
        var response = await service[method]({ path: path });
        entries.push(...response.entries);
        if (response.has_more) {
            await me.iterate(service, entries, path, response.cursor, recursive);
        } else if (recursive) {
            for (let item of response.entries) {
                if (item[".tag"] !== "folder") {
                    continue;
                }
                await me.iterate(service, entries, item.path_lower, null, recursive);
            }
        }
    };
    me.createFolder = async function (path) {
        var service = await me.getService();
        path = me.fixPath(path);
        var folderRef = service.filesCreateFolder({ path: path, autorename: false });
        return folderRef;
    };
    me.downloadData = async function (path) {
        var service = await me.getService();
        path = me.fixPath(path);
        var result = await service.filesGetTemporaryLink({ path: path });
        var body = "";
        return new Promise((resolve, reject) => {
            me.https.get(result.link, res => {
                res.on("data", function (chunk) {
                    body += chunk;
                });
                res.on("close", function () {
                    resolve(body);
                });
                res.on("error", function (e) {
                    reject(e);
                });
            });
        });
    };
    me.uploadData = async function (path, data) {
        var service = await me.getService();
        path = me.fixPath(path);
        var response = await service.filesUpload({ path: path, contents: data });
        return response;
    };
    me.metadata = async function (path) {
        var service = await me.getService();
        path = me.fixPath(path);
        var response = service.filesGetMetadata({ path: path });
        return response;
    };
    me.copyFile = async function (source, target) {
        var service = await me.getService();
        var from_path = me.fixPath(source);
        var to_path = me.fixPath(target);
        var response = await service.filesCopy({
            from_path,
            to_path
        });
        return response;
    };
    me.downloadFile = async function (from, to) {
        var path = me.fixPath(from);
        return new Promise(async (resolve, reject) => {
            var service = await me.getService();
            var result = await service.filesGetTemporaryLink({
                path
            });
            const req = me.https.get(result.link, res => {
                res.pipe(me.fs.createWriteStream(to));
            });
            req.on("close", resolve);
            req.on("error", reject);
        });
    };
    me.uploadFile = async function (from, to, progressCallback) {
        var service = await me.getService();
        var fileSize = await core.file.size(from);
        var fileSession = core.file.open(from);
        var cursor = { session_id: null, offset: 0 };
        return new Promise((resolve, reject) => {
            const chunkSize = 8 * 1000 * 1000;
            core.file.read(fileSession, async data => {
                if (!data) {
                    return;
                }
                if (progressCallback) {
                    progressCallback(cursor.offset, fileSize);
                }
                if (cursor.offset + data.length >= fileSize) {
                    if (cursor.offset) {
                        var commit = { path: to, mode: "overwrite", mute: false };
                        try {
                            let result = await service.filesUploadSessionFinish({
                                cursor: cursor,
                                commit: commit,
                                contents: data
                            });
                            me.log("finished uploading in parts: " + to + " size: " + core.string.formatBytes(fileSize) + " result: " + result);
                            resolve();
                        }
                        catch (err) {
                            me.log("failed to upload in parts: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                            reject(err);
                        }
                    }
                    else {
                        try {
                            let result = await service.filesUpload({
                                path: to,
                                contents: data
                            });
                            me.log("finished uploading: " + to + " size: " + core.string.formatBytes(fileSize) + " result: " + JSON.stringify(result));
                            resolve();
                        }
                        catch (err) {
                            me.log("failed to upload: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                            reject(err);
                        }
                    }
                    return;
                }
                else if (cursor.offset) {
                    core.file.pause(fileSession);
                    try {
                        await service.filesUploadSessionAppendV2({
                            cursor: cursor,
                            close: false,
                            contents: data
                        });
                    }
                    catch (err) {
                        me.log("failed to upload: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                        reject(err);
                        return;
                    }
                    cursor.offset += data.length;
                    core.file.resume(fileSession);
                    me.log("uploading " + to + ":" + core.string.formatBytes(cursor.offset) + " / " + core.string.formatBytes(fileSize));
                }
                else {
                    core.file.pause(fileSession);
                    try {
                        var response = await service.filesUploadSessionStart({
                            close: false,
                            contents: data
                        });
                    }
                    catch (err) {
                        me.log("failed to upload: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                        reject(err);
                        return;
                    }
                    cursor.session_id = response.session_id;
                    cursor.offset += data.length;
                    core.file.resume(fileSession);
                    me.log("uploading " + to + ":" + core.string.formatBytes(cursor.offset) + " / " + core.string.formatBytes(fileSize));
                }
            }, chunkSize);
        });
    };
    return "server";
};
<commit_msg>bug fix<commit_after>/*
 @author Zakai Hamilton
 @component StorageDropBox
 */

screens.storage.dropbox = function StorageDropBox(me, packages) {
    const { core } = packages;
    me.init = async function () {
        require("es6-promise").polyfill();
        me.dropbox = require("dropbox").Dropbox;
        me.fs = require("fs");
        me.https = require("https");
        me.keys = await core.private.keys("dropbox");
    };
    me.getService = async function () {
        if (me.handle) {
            return me.handle;
        }
        var fetch = require("isomorphic-fetch");
        me.handle = new me.dropbox({ accessToken: me.keys["access-token"], fetch: fetch });
        return me.handle;
    };
    me.fixPath = function (path) {
        if (path === "/") {
            return "";
        }
        return path;
    };
    me.list = function (path) {
        return me.getChildren(path);
    };
    me.getChildren = async function (path, recursive = false) {
        me.log("requesting items for path: " + path + " recursive: " + recursive);
        var entries = [];
        var service = await me.getService();
        await me.iterate(service, entries, path, null, recursive);
        me.log("returning " + entries.length + " items for path: " + path + " recursive: " + recursive);
        return entries;
    };
    me.iterate = async function (service, entries, path, cursor, recursive) {
        var method = cursor ? "filesListFolderContinue" : "filesListFolder";
        path = me.fixPath(path);
        var response = await service[method]({ path: path });
        entries.push(...response.entries);
        if (response.has_more) {
            await me.iterate(service, entries, path, response.cursor, recursive);
        } else if (recursive) {
            for (let item of response.entries) {
                if (item[".tag"] !== "folder") {
                    continue;
                }
                await me.iterate(service, entries, item.path_lower, null, recursive);
            }
        }
    };
    me.createFolder = async function (path) {
        var service = await me.getService();
        path = me.fixPath(path);
        var folderRef = service.filesCreateFolder({ path: path, autorename: false });
        return folderRef;
    };
    me.downloadData = async function (path) {
        var service = await me.getService();
        path = me.fixPath(path);
        var result = await service.filesGetTemporaryLink({ path: path });
        var body = "";
        return new Promise((resolve, reject) => {
            me.https.get(result.link, res => {
                res.on("data", function (chunk) {
                    body += chunk;
                });
                res.on("close", function () {
                    resolve(body);
                });
                res.on("error", function (e) {
                    reject(e);
                });
            });
        });
    };
    me.uploadData = async function (path, data) {
        var service = await me.getService();
        path = me.fixPath(path);
        var response = await service.filesUpload({ path: path, contents: data });
        return response;
    };
    me.metadata = async function (path) {
        var service = await me.getService();
        path = me.fixPath(path);
        var response = service.filesGetMetadata({ path: path });
        return response;
    };
    me.copyFile = async function (source, target) {
        var service = await me.getService();
        var from_path = me.fixPath(source);
        var to_path = me.fixPath(target);
        var response = await service.filesCopy({
            from_path,
            to_path
        });
        return response;
    };
    me.downloadFile = async function (from, to) {
        var path = me.fixPath(from);
        return new Promise(async (resolve, reject) => {
            var service = await me.getService();
            var result = await service.filesGetTemporaryLink({
                path
            });
            const req = me.https.get(result.link, res => {
                res.pipe(me.fs.createWriteStream(to));
            });
            req.on("close", resolve);
            req.on("error", reject);
        });
    };
    me.uploadFile = async function (from, to, progressCallback) {
        var service = await me.getService();
        var fileSize = await core.file.size(from);
        var fileSession = core.file.open(from);
        var cursor = { session_id: null, offset: 0 };
        return new Promise((resolve, reject) => {
            const chunkSize = 8 * 1000 * 1000;
            core.file.read(fileSession, async data => {
                if (!data) {
                    return;
                }
                if (progressCallback) {
                    progressCallback(cursor.offset, fileSize);
                }
                if (cursor.offset + data.length >= fileSize) {
                    if (cursor.offset) {
                        var commit = { path: to, mode: "overwrite", mute: false };
                        try {
                            let result = await service.filesUploadSessionFinish({
                                cursor: cursor,
                                commit: commit,
                                contents: data
                            });
                            me.log("finished uploading in parts: " + to + " size: " + core.string.formatBytes(fileSize) + " result: " + result);
                            resolve();
                        }
                        catch (err) {
                            me.log("failed to upload in parts: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                            reject(err);
                        }
                    }
                    else {
                        try {
                            let result = await service.filesUpload({
                                path: to,
                                contents: data
                            });
                            me.log("finished uploading: " + to + " size: " + core.string.formatBytes(fileSize) + " result: " + JSON.stringify(result));
                            resolve();
                        }
                        catch (err) {
                            me.log("failed to upload: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                            reject(err);
                        }
                    }
                    return;
                }
                else if (cursor.offset) {
                    core.file.pause(fileSession);
                    try {
                        await service.filesUploadSessionAppendV2({
                            cursor: cursor,
                            close: false,
                            contents: data
                        });
                    }
                    catch (err) {
                        me.log("failed to upload: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                        reject(err);
                        return;
                    }
                    cursor.offset += data.length;
                    core.file.resume(fileSession);
                    me.log("uploading " + to + ":" + core.string.formatBytes(cursor.offset) + " / " + core.string.formatBytes(fileSize));
                }
                else {
                    core.file.pause(fileSession);
                    try {
                        var response = await service.filesUploadSessionStart({
                            close: false,
                            contents: data
                        });
                    }
                    catch (err) {
                        me.log("failed to upload: " + to + " size: " + core.string.formatBytes(fileSize) + " err: " + JSON.stringify(err));
                        reject(err);
                        return;
                    }
                    cursor.session_id = response.session_id;
                    cursor.offset += data.length;
                    core.file.resume(fileSession);
                    me.log("uploading " + to + ":" + core.string.formatBytes(cursor.offset) + " / " + core.string.formatBytes(fileSize));
                }
            }, chunkSize);
        });
    };
    return "server";
};
<|endoftext|>


<commit_before>import {_} from 'lodash';
import Runner from './runner.js';

import {magicVersions} from '../configs/magic_versions.js';
import {magicDataModels} from './tests/files/data_models/data_models.js';

/**This class upgrades the json data from its current model to the next model if a newer model is available
 * It can optionally upgrade the model several times until it reaches a maxVersion*/
export default class extends Runner {

  constructor({LocalState}) {
    super('UPGRADE_CONTRIBUTION', {LocalState});
  }

  upgrade(jsonOld, maxVersion) {

    // Initialize the upgrading state.
    this.table = undefined;
    this.rowNumber = undefined;
    this.column = undefined;

    // Check for a valid input.
    if (_.isEmpty(jsonOld)) {
      this._appendWarning('The first argument (MagIC contribution in JSON format) is empty.');
      return jsonOld;
    }

    // Check that the maximum MagIC data model version to upgrade to is valid (maxVersion is in magicVersions).
    if (maxVersion && _.indexOf(magicVersions, maxVersion) === -1) {
      let strVersions = magicVersions.map((str) => { return `"${str}"`; }).join(', ');
      this._appendError(`The second argument (maximum MagIC data model version), "${maxVersion}", is invalid. ` +
                        `Expected one of: ${strVersions}.`);
      return jsonOld;
    }

    // Look for the old MagIC data model version.
    let oldVersion;
    if(!jsonOld || !jsonOld['contribution']) {
      this._appendError('Failed to find the "contribution" table.');
      return jsonOld;
    }
    if (jsonOld['contribution']) {
      if (jsonOld['contribution'].length !== 1) {
        this._appendError('The "contribution" table does not have exactly one row.');
        return jsonOld;
      }
      if (!jsonOld['contribution'][0]['magic_version']) {
        this._appendError('The "contribution" table does not include the "magic_version" column.');
        return jsonOld;
      }
      this.contributionTable = 'contribution';//GGG not sure what this is here for, seems to be unused
      oldVersion = jsonOld['contribution'][0]['magic_version'];
    }

    // Check that the old MagIC data model version is valid (oldVersion is in magicVersions).
    if (_.indexOf(magicVersions, oldVersion) === -1) {
      const strVersions = magicVersions.map((str) => { return `"${str}"`; }).join(", ");
      this._appendError(`MagIC data model version ${oldVersion} is invalid. Expected one of: ${strVersions}.`);
      return jsonOld;
    }

    // Check if the maxVersion has been reached.
    if (oldVersion === maxVersion) return jsonOld;

    // Check that there is a newer MagIC data model to use.
    if (_.indexOf(magicVersions, oldVersion) === magicVersions.length - 1) return jsonOld;
    const newVersion = magicVersions[_.indexOf(magicVersions, oldVersion) + 1];
    const oldModel = magicDataModels[oldVersion];
    const newModel = magicDataModels[newVersion];

    // UPGRADE THE CONTRIBUTION
    let upgradeMap = this.getUpgradeMap(newModel);
    let jsonNew = {};
    for (let oldTable in jsonOld) {

      // Check that the old table is defined in the old data model.
      if (!oldModel['tables'][oldTable]) {
        this._appendError(`Table "${oldTable}" is not defined in magic data model version ${oldVersion}.`);
        continue;
      }

      if (!jsonNew[oldTable]) jsonNew[oldTable] = [];

      for (let oldRow of jsonOld[oldTable]) {

        let newRow = {};
        for (let oldColumn in oldRow) {

          // Check that the old column is defined in the old data model.
          if (!oldModel['tables'][oldTable]['columns'][oldColumn]) {
            console.log(`VERSION? 1`);
            this._appendError(`Column "${oldColumn}" in table "${oldTable}" is not defined in magic data model ${oldVersion}.`);
            continue;
          }

          // Check that the old table and column are defined in the new data model.
          if (!upgradeMap[oldTable] || !upgradeMap[oldTable][oldColumn]) {
            console.log(`VERSION? 2`);
            this._appendWarning(`Column "${oldColumn}" in table "${oldTable}" was deleted in MagIC data model version ${newVersion}.`);
            continue;
          }
          console.log(`VERSION? ${oldTable}: ${oldColumn}: ${newVersion}`);

          // Upgrade the version number
          if (oldTable === 'contribution' && oldColumn === 'magic_version') {

            newRow[oldColumn] = newVersion;
            continue;
          }

          // TODO: this doesn't handle changes in table names properly yet
          for (let newTableColumn in upgradeMap[oldTable][oldColumn]) {
            //if (!jsonNew[newTableColumn.table]) jsonNew[newTableColumn.table] = [];
            newRow[newTableColumn.column] = oldRow[oldColumn];
          }
        }

        // TODO: this doesn't handle changes in table names properly yet
        jsonNew[oldTable].push(newRow);

      }
    }

    console.log("old: ", JSON.stringify(jsonOld, null, 1));
//    console.log("old: ", jsonOld);
    console.log("new: ", JSON.stringify(jsonNew, null, 1));

    /*GGG Reintroduce recursion when we are building reasonable upgraded versions.*/
    return jsonNew;
    // Recursively upgrade the contribution.
   //return this.upgrade(jsonNew, maxVersion);

  }

  //newModel is the "more recent" of the two models involved in the upgrade process. It is the model we are upgrading the JSON object to.
  //The upgradeMap is "forward looking" from perspecitve of the "less recent" (or "current") model in that it shows the path from the less recent model to the "more recent".
  getUpgradeMap(newModel) {

    let upgradeMap = {};

    for (let newTableName in newModel.tables) {//this gets the STRING name of the property into 'table'
      let newTableObject = newModel.tables[newTableName];//this on the other hand, gets the whole table object
//console.log(`TABLE: ${newTableName}`);
      let mappingArray = [];
      for (let newColumnName in newTableObject.columns)
      {
        //let currentColumnsObj = newTableObject.columns;
        let currentColumnObj = newTableObject.columns[newColumnName];
        let prevColArray = currentColumnObj.previous_columns;

        if((prevColArray == undefined) || prevColArray.length==0) {
          continue;
        }

          if (prevColArray &&
              prevColArray.length === 1) {
            let previousColTableName = prevColArray[0].table;
            let previousColumnName = prevColArray[0].column;
            let tableColMapping = {[previousColumnName]:mappingArray};

            //console.log(JSON.stringify(tableColMapping));

            //TEST FOR TABLE/COLUMNS WITH NO CHANGES
            if(newColumnName == previousColumnName && newTableName == previousColTableName){

              tableColMapping[previousColumnName].push({table:newTableName,column:newColumnName});
              _.set(upgradeMap,previousColTableName,tableColMapping);
              //console.log(`NO CHANGE in table and column with no change detected. table:${newTableName}. Column name = ${newColumnName}` );
              continue;
            }

            //TEST FOR RENAMED TABLES OR COLUMNS
            if ((newTableName != previousColTableName) || (newColumnName != previousColumnName)) {
              //console.log(`RENAMED table or column detected. Previous table name : ${previousColTableName} New table: ${newTableName}.` );
              //console.log(`Previous column name = ${previousColumnName}. New column name = ${newColumnName}` );
              tableColMapping[previousColumnName].push({table:newTableName,column:newColumnName});
              _.set(upgradeMap,previousColTableName,tableColMapping);
              continue;
            }

            /*//TEST FOR RENAMED (POTENTIALLY SPLIT) COLUMNS
            if(newColumnName != previousColumnName)
            {
              //console.log(`RENAMED (potentially a split) column  detected in table ${newTableName}. Previous column name = ${previousColumnName}. New column name = ${newColumnName}` );
              tableColMapping[previousColumnName].push({table:newTableName,column:newColumnName});
              _.set(upgradeMap,previousColTableName,tableColMapping);
            }*/
          }

          //TEST FOR MERGED COLUMNS...If there is more than one previous column, that indicates a MERGE to this version
           if (prevColArray && (prevColArray.length > 1))
          {
            upgradeMap[newTableName] = {};
           //console.log("MERGED column detected in table " +newTableName);

            for(let prevColIdx in prevColArray)
            {
              let tmpPreviousColTableName = prevColArray[prevColIdx].table;
              let tmpPreviousColumnName = prevColArray[prevColIdx].column;//:${tmpPreviousColumnName}
              upgradeMap[newTableName][tmpPreviousColumnName] = [{table:newTableName, column:newColumnName}];
            }
          }
      }
    }

    console.log(`Upgrade Map ${JSON.stringify(upgradeMap)}`);
    return upgradeMap;
  }
}

//GGG THIS IS THE OLD SPLIT COL SOLUTION, holding onto it for a bit as i might want to copy some
/*let prevColKey = previousColTableName + previousColumnName;
 if (previousTableColumnMap.has(prevColKey)) // If we have seen this "previous column" before
 {
 console.log("SPLIT of previous column detcted: " + previousColTableName + "  " + previousColumnName);
 let newColName1 = previousTableColumnMap.get(prevColKey);
 _.set(upgradeMap[newTableName],previousColumnName,[{table:newTableName,column:newColName1},{table:newTableName,column:newColumnName}]);
 continue; //if it is a split column, it isn't any other kind of column
 }
 else {previousTableColumnMap.set(prevColKey, newColumnName);}//keep track that we have seen this previous table+column combination
 */<commit_msg>Fixes several shortcomings of the upgradeMap functionality. I believe failures are related to bad table/column names in the test suite which Rupert is going to address. Regardless, all the 7 failures are related to the exact same line of code.<commit_after>import {_} from 'lodash';
import Runner from './runner.js';

import {magicVersions} from '../configs/magic_versions.js';
import {magicDataModels} from './tests/files/data_models/data_models.js';

/**This class upgrades the json data from its current model to the next model if a newer model is available
 * It can optionally upgrade the model several times until it reaches a maxVersion*/
export default class extends Runner {

  constructor({LocalState}) {
    super('UPGRADE_CONTRIBUTION', {LocalState});
  }

  upgrade(jsonOld, maxVersion) {

    // Initialize the upgrading state.
    this.table = undefined;
    this.rowNumber = undefined;
    this.column = undefined;

    // Check for a valid input.
    if (_.isEmpty(jsonOld)) {
      this._appendWarning('The first argument (MagIC contribution in JSON format) is empty.');
      return jsonOld;
    }

    // Check that the maximum MagIC data model version to upgrade to is valid (maxVersion is in magicVersions).
    if (maxVersion && _.indexOf(magicVersions, maxVersion) === -1) {
      let strVersions = magicVersions.map((str) => { return `"${str}"`; }).join(', ');
      this._appendError(`The second argument (maximum MagIC data model version), "${maxVersion}", is invalid. ` +
                        `Expected one of: ${strVersions}.`);
      return jsonOld;
    }

    // Look for the old MagIC data model version.
    let oldVersion;
    if(!jsonOld || !jsonOld['contribution']) {
      this._appendError('Failed to find the "contribution" table.');
      return jsonOld;
    }
    if (jsonOld['contribution']) {
      if (jsonOld['contribution'].length !== 1) {
        this._appendError('The "contribution" table does not have exactly one row.');
        return jsonOld;
      }
      if (!jsonOld['contribution'][0]['magic_version']) {
        this._appendError('The "contribution" table does not include the "magic_version" column.');
        return jsonOld;
      }
      this.contributionTable = 'contribution';//GGG not sure what this is here for, seems to be unused
      oldVersion = jsonOld['contribution'][0]['magic_version'];
    }

    // Check that the old MagIC data model version is valid (oldVersion is in magicVersions).
    if (_.indexOf(magicVersions, oldVersion) === -1) {
      const strVersions = magicVersions.map((str) => { return `"${str}"`; }).join(", ");
      this._appendError(`MagIC data model version ${oldVersion} is invalid. Expected one of: ${strVersions}.`);
      return jsonOld;
    }

    // Check if the maxVersion has been reached.
    if (oldVersion === maxVersion) return jsonOld;

    // Check that there is a newer MagIC data model to use.
    if (_.indexOf(magicVersions, oldVersion) === magicVersions.length - 1) return jsonOld;
    const newVersion = magicVersions[_.indexOf(magicVersions, oldVersion) + 1];
    const oldModel = magicDataModels[oldVersion];
    const newModel = magicDataModels[newVersion];

    // UPGRADE THE CONTRIBUTION
    let upgradeMap = this.getUpgradeMap(newModel);
    let jsonNew = {};
    for (let oldTable in jsonOld) {

      // Check that the old table is defined in the old data model.
      if (!oldModel['tables'][oldTable]) {
        this._appendError(`Table "${oldTable}" is not defined in magic data model version ${oldVersion}.`);
        continue;
      }

      if (!jsonNew[oldTable]) jsonNew[oldTable] = [];

      for (let oldRow of jsonOld[oldTable]) {

        let newRow = {};
        for (let oldColumn in oldRow) {

          // Check that the old column is defined in the old data model.
          if (!oldModel['tables'][oldTable]['columns'][oldColumn]) {
            console.log(`VERSION? 1`);
            this._appendError(`Column "${oldColumn}" in table "${oldTable}" is not defined in magic data model ${oldVersion}.`);
            continue;
          }

          // Check that the old table and column are defined in the new data model.
          if (!upgradeMap[oldTable] || !upgradeMap[oldTable][oldColumn]) {
            console.log(`VERSION? 2`);
            this._appendWarning(`Column "${oldColumn}" in table "${oldTable}" was deleted in MagIC data model version ${newVersion}.`);
            continue;
          }
          console.log(`VERSION? ${oldTable}: ${oldColumn}: ${newVersion}`);

          // Upgrade the version number
          if (oldTable === 'contribution' && oldColumn === 'magic_version') {

            newRow[oldColumn] = newVersion;
            continue;
          }

          // TODO: this doesn't handle changes in table names properly yet
          for (let newTableColumn in upgradeMap[oldTable][oldColumn]) {
            //if (!jsonNew[newTableColumn.table]) jsonNew[newTableColumn.table] = [];
            newRow[newTableColumn.column] = oldRow[oldColumn];
          }
        }

        // TODO: this doesn't handle changes in table names properly yet
        jsonNew[oldTable].push(newRow);

      }
    }

    console.log("old: ", JSON.stringify(jsonOld, null, 1));
//    console.log("old: ", jsonOld);
    console.log("new: ", JSON.stringify(jsonNew, null, 1));

    /*GGG Reintroduce recursion when we are building reasonable upgraded versions.*/
    return jsonNew;
    // Recursively upgrade the contribution.
   //return this.upgrade(jsonNew, maxVersion);

  }

  //newModel is the "more recent" of the two models involved in the upgrade process. It is the model we are upgrading the JSON object to.
  //The upgradeMap is "forward looking" from perspecitve of the "less recent" (or "current") model in that it shows the path from the less recent model to the "more recent".
  getUpgradeMap(newModel) {

    let upgradeMap = {};

    for (let newTableName in newModel.tables) {//this gets the STRING name of the property into 'table'
      let newTableObject = newModel.tables[newTableName];//this on the other hand, gets the whole table object

      for (let newColumnName in newTableObject.columns)
      {
        let tableColMapping = [];
        let currentColumnObj = newTableObject.columns[newColumnName];
        let prevColArray = currentColumnObj.previous_columns;

        if((prevColArray == undefined) || prevColArray.length==0) {
          continue;
        }

          if (prevColArray &&
              prevColArray.length === 1) {
            let previousColTableName = prevColArray[0].table;
            let previousColumnName = prevColArray[0].column;
            if(!upgradeMap[previousColTableName])                     upgradeMap[previousColTableName] = {};
            if(!upgradeMap[previousColTableName][previousColumnName]) upgradeMap[previousColTableName][previousColumnName] = [];

            //TEST FOR TABLE/COLUMNS WITH NO CHANGES
            if(newColumnName == previousColumnName && newTableName == previousColTableName){
              upgradeMap[previousColTableName][previousColumnName].push({table:newTableName,column:newColumnName});
              //console.log(`NO CHANGE in table and column with no change detected. table:${newTableName}. Column name = ${newColumnName}` );
              continue;
            }

            //TEST FOR RENAMED TABLES OR COLUMNS
            if ((newTableName != previousColTableName) || (newColumnName != previousColumnName)) {
              //console.log(`RENAMED table or column detected. Previous table name : ${previousColTableName} New table: ${newTableName}.` );
              //console.log(`Previous column name = ${previousColumnName}. New column name = ${newColumnName}` );
              upgradeMap[previousColTableName][previousColumnName].push({table:newTableName,column:newColumnName});
              continue;
            }
          }

          //TEST FOR MERGED COLUMNS...If there is more than one previous column, that indicates a MERGE to this version
           if (prevColArray && (prevColArray.length > 1))
          {
            for(let prevColIdx in prevColArray)
            {
              let tmpPreviousColumnName = prevColArray[prevColIdx].column;
              let tmpPreviousColTableName  = prevColArray[prevColIdx].table;

              //console.log(`${JSON.stringify(upgradeMap)}`);
              console.log(`prevTab: ${tmpPreviousColTableName}:  prevCol: ${tmpPreviousColumnName}`  );
              //console.log(`json: ${JSON.stringify(upgradeMap[tmpPreviousColTableName][tmpPreviousColumnName])}`);
              if(!upgradeMap[tmpPreviousColTableName] || upgradeMap[tmpPreviousColTableName]==undefined)
                upgradeMap[tmpPreviousColumnName] = {};
              if(!upgradeMap[tmpPreviousColTableName][tmpPreviousColumnName] || upgradeMap[tmpPreviousColTableName][tmpPreviousColumnName]==undefined)
                upgradeMap[tmpPreviousColTableName][tmpPreviousColumnName] = [];

              upgradeMap[tmpPreviousColTableName][tmpPreviousColumnName].push([{table:newTableName, column:newColumnName}]);
            }
          }
      }
    }

   // console.log(`Upgrade Map ${JSON.stringify(upgradeMap)}`);
    return upgradeMap;
  }
}

//GGG THIS IS THE OLD SPLIT COL SOLUTION, holding onto it for a bit as i might want to copy some
/*let prevColKey = previousColTableName + previousColumnName;
 if (previousTableColumnMap.has(prevColKey)) // If we have seen this "previous column" before
 {
 console.log("SPLIT of previous column detcted: " + previousColTableName + "  " + previousColumnName);
 let newColName1 = previousTableColumnMap.get(prevColKey);
 _.set(upgradeMap[newTableName],previousColumnName,[{table:newTableName,column:newColName1},{table:newTableName,column:newColumnName}]);
 continue; //if it is a split column, it isn't any other kind of column
 }
 else {previousTableColumnMap.set(prevColKey, newColumnName);}//keep track that we have seen this previous table+column combination
 */
/*//TEST FOR RENAMED (POTENTIALLY SPLIT) COLUMNS
 if(newColumnName != previousColumnName)
 {
 //console.log(`RENAMED (potentially a split) column  detected in table ${newTableName}. Previous column name = ${previousColumnName}. New column name = ${newColumnName}` );
 tableColMapping[previousColumnName].push({table:newTableName,column:newColumnName});
 _.set(upgradeMap,previousColTableName,tableColMapping);
 }*/<|endoftext|>


<commit_before>// ==UserScript==
// @author      rslifka
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepageURL https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        FateOfAllFools - DIM Customization
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @updateURL   https://openuserjs.org/meta/rslifka/FateOfAllFools_-_DIM_Customization.meta.js
// @version     581
// ==/UserScript==
<commit_msg>AUTO-CREATED Release Artifact v582 c/o Travis<commit_after>// ==UserScript==
// @author      rslifka
// @connect     docs.google.com
// @connect     rslifka.github.io
// @copyright   2018, Robert Slifka (https://github.com/rslifka/fate_of_all_fools)
// @description Enhancements to the Destiny Item Manager
// @grant       GM_addStyle
// @grant       GM_getResourceText
// @grant       GM_getValue
// @grant       GM_log
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @homepageURL https://github.com/rslifka/fate_of_all_fools
// @license     MIT; https://raw.githubusercontent.com/rslifka/fate_of_all_fools/master/LICENSE.txt
// @match       https://*.destinyitemmanager.com/*
// @name        FateOfAllFools - DIM Customization
// @require     https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.js
// @resource    fateOfAllFoolsCSS https://rslifka.github.io/fate_of_all_fools/fateOfAllFools.css
// @run-at      document-start
// @supportURL  https://github.com/rslifka/fate_of_all_fools/issues
// @updateURL   https://openuserjs.org/meta/rslifka/FateOfAllFools_-_DIM_Customization.meta.js
// @version     582
// ==/UserScript==
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

/**
 * Competitor Schema
 */
var CompetitorSchema = new Schema({
  created: {
      type: Date,
      default: Date.now
  },
  gender: {
    type: String,
    required: true,
    trim: true
  },
  name: {
    type: String,
    required: true,
    trim: true
  },
  firstname: {
    type: String,
    required: true,
    trim: true
  },
  address: {
    type: String,
    required: true,
    trim: true
  },
  zip: {
    type: Number,
    required: true,
    trim: true
  },
  location: {
    type: String,
    required: true,
    trim: true
  },
  society: {
    type: String,
    required: false,
    trim: true
  },
  email: {
    type: String,
    required: true,
    trim: true
  },
  birthdate: {
    type: Date,
    required: true,
    trim: true
  },
  startnr: {
    type: String,
    required: false,
    trim: true
  },
  startnrfetched: {
    type: Boolean,
    required: true,
    default: false
  },
  user: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  results: {
  	type: [DisciplineResultSchema]
  }
});

var DisciplineResultSchema = new Schema({
  disciplineId: {
  	type: Schema.ObjectId,
  	required: true,
  	trim: true
  },
  result: {
    type: String,
    required: false,
    trim: true
  }
});

/**
 * Validations
 */
// ArticleSchema.path('title').validate(function(title) {
  // return !!title;
// }, 'Title cannot be blank');
//
// ArticleSchema.path('content').validate(function(content) {
  // return !!content;
// }, 'Content cannot be blank');

/**
 * Statics
 */
CompetitorSchema.statics.load = function(id, cb) {
  this.findOne({
    _id: id
  }).populate('user', 'name username').exec(cb);
};

mongoose.model('Competitor', CompetitorSchema);
<commit_msg>Schema Reihenfolge korrigiert<commit_after>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

var DisciplineResultSchema = new Schema({
  disciplineId: {
    type: Schema.ObjectId,
    required: true,
    trim: true
  },
  result: {
    type: String,
    required: false,
    trim: true
  }
});

/**
 * Competitor Schema
 */
var CompetitorSchema = new Schema({
  created: {
      type: Date,
      default: Date.now
  },
  gender: {
    type: String,
    required: true,
    trim: true
  },
  name: {
    type: String,
    required: true,
    trim: true
  },
  firstname: {
    type: String,
    required: true,
    trim: true
  },
  address: {
    type: String,
    required: true,
    trim: true
  },
  zip: {
    type: Number,
    required: true,
    trim: true
  },
  location: {
    type: String,
    required: true,
    trim: true
  },
  society: {
    type: String,
    required: false,
    trim: true
  },
  email: {
    type: String,
    required: true,
    trim: true
  },
  birthdate: {
    type: Date,
    required: true,
    trim: true
  },
  startnr: {
    type: String,
    required: false,
    trim: true
  },
  startnrfetched: {
    type: Boolean,
    required: true,
    default: false
  },
  user: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  results: {
  	type: [DisciplineResultSchema]
  }
});

/**
 * Validations
 */
// ArticleSchema.path('title').validate(function(title) {
  // return !!title;
// }, 'Title cannot be blank');
//
// ArticleSchema.path('content').validate(function(content) {
  // return !!content;
// }, 'Content cannot be blank');

/**
 * Statics
 */
CompetitorSchema.statics.load = function(id, cb) {
  this.findOne({
    _id: id
  }).populate('user', 'name username').exec(cb);
};

mongoose.model('Competitor', CompetitorSchema);
<|endoftext|>


<commit_before>define(['marionette',
        'views/imageviewer',
        'modules/dc/models/distl',
        'modules/dc/models/grid',
        'modules/dc/collections/gridmap',
        'heatmap',
        'tpl!templates/types/em/dc/overview.html'
    ], function(Marionette, ImageViewer, DISTL, GridInfo, GridMap,
        HeatMap,
        template) {

    var Overview = ImageViewer.extend({
        template: template,

        events: {
            'click canvas': 'onClick',
        },

        initialize: function(options) {
            this.draw = _.debounce(this.draw, 10)
            this.listenTo(options.imagestatuses, 'sync', this.getModel, this)
            this.pm = options.pm

            this.distl = new DISTL({ id: this.pm.get('ID'), nimg: this.pm.get('NUMIMG'), pm: this.pm })
            this.listenTo(this.distl, 'change', this.draw, this)

            this.grid = new GridInfo({ id: this.pm.get('ID') })

            var self = this
            this.gridFetched = false
            this.grid.fetch().done(function() {
                self.gridFetched = true
            })

            this.gridmap = new GridMap()
            this.gridmap.queryParams.id = this.pm.get('ID')
            this.listenTo(this.gridmap, 'change', this.draw, this)

            this.ready = []
            this.ready.push(this.gridmap.fetch())
            this.ready.push(this.distl.fetch())

            this.current = 1
            this.hasSnapshot = false
        },

        onDomRefresh: function() {
            Overview.__super__.onDomRefresh.call(this)

            this.heatmap = new HeatMap.create({
                container: this.$el[0],
                maxOpacity: .4,
            })
        },

        getModel: function() {
            var m = this.getOption('imagestatuses').findWhere({ ID: this.pm.get('ID') })
            if (m.get('SNS').length) {
                if (m.get('SNS')[0] && this.hasSnapshot == false) {
                    this.img.load(app.apiurl+'/image/id/'+this.pm.get('ID')+'/f/1')
                    this.showProgressBar()
                }
            }
        },

        onImageLoaded: function() {
            Overview.__super__.onImageLoaded.call(this)
            this.hasSnapshot = true
        },

        draw: function() {
            Overview.__super__.draw.call(this)

            this.heatmap._renderer.shadowCtx.setTransform(this.scalef,0,0,this.scalef,this.offsetx,this.offsety)
            this.drawObjects()
        },

        // plot movie positions
        drawObjects: function() {

            var m = this.scalef > 1 ? 1: 1/this.scalef
            var w = 10*m
            this.ctx.lineWidth = this.scalef > 1 ? 1 : 1/this.scalef

            var dvs = this.distl.get('data')
            var data = []
            this.gridmap.each(function(p) {
                var x = p.get('POSITIONX')/parseFloat(this.grid.get('PIXELSPERMICRONX'))
                var y = p.get('POSITIONY')/parseFloat(this.grid.get('PIXELSPERMICRONY'))

                this.ctx.strokeStyle = this.current == p.get('IMAGENUMBER') ? 'green' : 'red'

                this.ctx.beginPath()
                this.ctx.moveTo(x-w,y)
                this.ctx.lineTo(x+w,y)
                this.ctx.stroke()
                this.ctx.beginPath()
                this.ctx.moveTo(x,y-w)
                this.ctx.lineTo(x,y+w)
                this.ctx.stroke()

                if (dvs[3].length) {
                    _.each(dvs[3], function(dv) {
                        if (dv[0] == p.get('IMAGENUMBER')) data.push({
                            x: x, y: y,
                            value: dv[1],
                            // radius: radius
                        })
                    }, this)
                }

            }, this)

            // plot distl data
            if (data.length) {
                this.heatmap.setData({
                    // max: max,
                    data: data
                })
            }
        },

        onClick: function(e) {
            var current = this._nearest(this.getScaledXY(e))

            if (current != this.current) {
                this.current = current
                this.trigger('current', current)
                this.draw()
            }

        },

        _nearest: function(pos) {
            var distances = this.gridmap.map(function(m) {
                return Math.sqrt(
                    Math.pow(pos.x - ( parseFloat(m.get('POSITIONX'))/parseFloat(this.grid.get('PIXELSPERMICRONX')) ), 2) +
                    Math.pow(pos.y - ( parseFloat(m.get('POSITIONY'))/parseFloat(this.grid.get('PIXELSPERMICRONY')) ), 2))
            }, this)

            var min = _.min(distances)
            if (min < 30/this.scalef) {
                var id = distances.indexOf(min)
                var im = this.gridmap.at(id)
                return im.get('IMAGENUMBER')
            }
        },

        onDestroy: function() {
            this.distl.stop()
            this.gridmap.stop()
        },

    })

    return Overview

})<commit_msg>fix rendering heatmap on top of a scalable canvas<commit_after>define(['marionette',
        'views/imageviewer',
        'modules/dc/models/distl',
        'modules/dc/models/grid',
        'modules/dc/collections/gridmap',
        'heatmap',
        'tpl!templates/types/em/dc/overview.html'
    ], function(Marionette, ImageViewer, DISTL, GridInfo, GridMap,
        HeatMap,
        template) {

    var Overview = ImageViewer.extend({
        template: template,

        events: {
            'click canvas': 'onClick',
        },

        initialize: function(options) {
            this.draw = _.debounce(this.draw, 10)
            this.listenTo(options.imagestatuses, 'sync', this.getModel, this)
            this.pm = options.pm

            this.distl = new DISTL({ id: this.pm.get('ID'), nimg: this.pm.get('NUMIMG'), pm: this.pm })
            this.listenTo(this.distl, 'change', this.draw, this)

            this.grid = new GridInfo({ id: this.pm.get('ID') })

            var self = this
            this.gridFetched = false
            this.grid.fetch().done(function() {
                self.gridFetched = true
            })

            this.gridmap = new GridMap()
            this.gridmap.queryParams.id = this.pm.get('ID')
            this.listenTo(this.gridmap, 'change', this.draw, this)

            this.ready = []
            this.ready.push(this.gridmap.fetch())
            this.ready.push(this.distl.fetch())

            this.current = 1
            this.hasSnapshot = false
        },

        onDomRefresh: function() {
            Overview.__super__.onDomRefresh.call(this)

            this.heatmap = new HeatMap.create({
                container: this.$el[0],
                maxOpacity: .4,
            })
        },

        getModel: function() {
            var m = this.getOption('imagestatuses').findWhere({ ID: this.pm.get('ID') })
            if (m.get('SNS').length) {
                if (m.get('SNS')[0] && this.hasSnapshot == false) {
                    this.img.load(app.apiurl+'/image/id/'+this.pm.get('ID')+'/f/1')
                    this.showProgressBar()
                }
            }
        },

        onImageLoaded: function() {
            Overview.__super__.onImageLoaded.call(this)
            this.hasSnapshot = true
        },

        draw: function() {
            Overview.__super__.draw.call(this)

            this.heatmap._renderer.shadowCtx.setTransform(this.scalef,0,0,this.scalef,this.offsetx,this.offsety)
            this.heatmap._renderer.shadowCtx.clearRect(0,0,this.width/this.scalef, this.height/this.scalef)
            this.drawObjects()
        },

        // plot movie positions
        drawObjects: function() {

            var m = this.scalef > 1 ? 1: 1/this.scalef
            var w = 10*m
            this.ctx.lineWidth = this.scalef > 1 ? 1 : 1/this.scalef

            var dvs = this.distl.get('data')
            var data = []
            this.gridmap.each(function(p) {
                var x = p.get('POSITIONX')/parseFloat(this.grid.get('PIXELSPERMICRONX'))
                var y = p.get('POSITIONY')/parseFloat(this.grid.get('PIXELSPERMICRONY'))

                this.ctx.strokeStyle = this.current == p.get('IMAGENUMBER') ? 'green' : 'red'

                this.ctx.beginPath()
                this.ctx.moveTo(x-w,y)
                this.ctx.lineTo(x+w,y)
                this.ctx.stroke()
                this.ctx.beginPath()
                this.ctx.moveTo(x,y-w)
                this.ctx.lineTo(x,y+w)
                this.ctx.stroke()

                if (dvs[3].length) {
                    _.each(dvs[3], function(dv) {
                        if (dv[0] == p.get('IMAGENUMBER')) data.push({
                            x: x, y: y,
                            value: dv[1],
                            // radius: radius
                        })
                    }, this)
                }

            }, this)

            // plot distl data
            if (data.length) {
                this.heatmap.setData({
                    // max: max,
                    data: data
                })
            }
        },

        onClick: function(e) {
            var current = this._nearest(this.getScaledXY(e))

            if (current != this.current) {
                this.current = current
                this.trigger('current', current)
                this.draw()
            }

        },

        _nearest: function(pos) {
            var distances = this.gridmap.map(function(m) {
                return Math.sqrt(
                    Math.pow(pos.x - ( parseFloat(m.get('POSITIONX'))/parseFloat(this.grid.get('PIXELSPERMICRONX')) ), 2) +
                    Math.pow(pos.y - ( parseFloat(m.get('POSITIONY'))/parseFloat(this.grid.get('PIXELSPERMICRONY')) ), 2))
            }, this)

            var min = _.min(distances)
            if (min < 30/this.scalef) {
                var id = distances.indexOf(min)
                var im = this.gridmap.at(id)
                return im.get('IMAGENUMBER')
            }
        },

        onDestroy: function() {
            this.distl.stop()
            this.gridmap.stop()
        },

    })

    return Overview

})<|endoftext|>


<commit_before>angular.module('socially').directive('partiesList', function () {
  return {
    restrict: 'E',
    templateUrl: 'client/parties/parties-list/parties-list.html',
    controllerAs: 'partiesList',
    controller: function ($scope, $reactive) {
      $reactive(this).attach($scope);

      this.newParty = {};
      this.perPage = 3;
      this.page = 1;
      this.sort = {
        name: 1
      };
      this.orderProperty = '1';
      this.searchText = '';

      this.helpers({
        parties: () => {
          return Parties.find({}, { sort : this.getReactively('sort') });
        },
        users: () => {
          return Meteor.users.find({});
        },
        partiesCount: () => {
          return Counts.get('numberOfParties');
        },
        isLoggedIn: () => {
          return Meteor.userId() !== null;
        }
      });

      this.subscribe('users');

      this.subscribe('parties', () => {
        return [
          {
            limit: parseInt(this.perPage),
            skip: parseInt((this.getReactively('page') - 1) * this.perPage),
            sort: this.getReactively('sort')
          },
          this.getReactively('searchText')
        ]
      });

      this.addParty = () => {
        this.newParty.owner = Meteor.user()._id;
        Parties.insert(this.newParty);
        this.newParty = {};
      };

      this.removeParty = (party) => {
        Parties.remove({_id: party._id});
      };

      this.pageChanged = (newPage) => {
        this.page = newPage;
      };

      this.updateSort = () => {
        this.sort = {
          name: parseInt(this.orderProperty)
        }
      };

      this.getPartyCreator = function(party){
        if (!party) {
          return '';
        }

        let owner = Meteor.users.findOne(party.owner);

        if (!owner) {
          return 'nobody';
        }

        if (Meteor.userId() !== null && owner._id === Meteor.userId()) {
          return 'me';
        }

        return owner;
      };

      this.rsvp = (partyId, rsvp) => {
        Meteor.call('rsvp', partyId, rsvp, (error) => {
          if (error) {
            console.log('Oops, unable to rsvp!');
          }
          else {
            console.log('RSVP Done!');
          }
        });
      };

      this.getUserById = (userId) => {
        return Meteor.users.findOne(userId);
      };

      this.outstandingInvitations = (party) => {
        return _.filter(this.users, (user) => {
          return (_.contains(party.invited, user._id) && !_.findWhere(party.rsvps, {user: user._id}));
        });
      };
    }
  }
});<commit_msg>Step 15.7: Add currentUserId helper<commit_after>angular.module('socially').directive('partiesList', function () {
  return {
    restrict: 'E',
    templateUrl: 'client/parties/parties-list/parties-list.html',
    controllerAs: 'partiesList',
    controller: function ($scope, $reactive) {
      $reactive(this).attach($scope);

      this.newParty = {};
      this.perPage = 3;
      this.page = 1;
      this.sort = {
        name: 1
      };
      this.orderProperty = '1';
      this.searchText = '';

      this.helpers({
        parties: () => {
          return Parties.find({}, { sort : this.getReactively('sort') });
        },
        users: () => {
          return Meteor.users.find({});
        },
        partiesCount: () => {
          return Counts.get('numberOfParties');
        },
        isLoggedIn: () => {
          return Meteor.userId() !== null;
        },
        currentUserId: () => {
          return Meteor.userId();
        }
      });

      this.subscribe('users');

      this.subscribe('parties', () => {
        return [
          {
            limit: parseInt(this.perPage),
            skip: parseInt((this.getReactively('page') - 1) * this.perPage),
            sort: this.getReactively('sort')
          },
          this.getReactively('searchText')
        ]
      });

      this.addParty = () => {
        this.newParty.owner = Meteor.user()._id;
        Parties.insert(this.newParty);
        this.newParty = {};
      };

      this.removeParty = (party) => {
        Parties.remove({_id: party._id});
      };

      this.pageChanged = (newPage) => {
        this.page = newPage;
      };

      this.updateSort = () => {
        this.sort = {
          name: parseInt(this.orderProperty)
        }
      };

      this.getPartyCreator = function(party){
        if (!party) {
          return '';
        }

        let owner = Meteor.users.findOne(party.owner);

        if (!owner) {
          return 'nobody';
        }

        if (Meteor.userId() !== null && owner._id === Meteor.userId()) {
          return 'me';
        }

        return owner;
      };

      this.rsvp = (partyId, rsvp) => {
        Meteor.call('rsvp', partyId, rsvp, (error) => {
          if (error) {
            console.log('Oops, unable to rsvp!');
          }
          else {
            console.log('RSVP Done!');
          }
        });
      };

      this.getUserById = (userId) => {
        return Meteor.users.findOne(userId);
      };

      this.outstandingInvitations = (party) => {
        return _.filter(this.users, (user) => {
          return (_.contains(party.invited, user._id) && !_.findWhere(party.rsvps, {user: user._id}));
        });
      };
    }
  }
});<|endoftext|>


<commit_before>'use strict';

const electron = require('electron');
const Positioner = require('electron-positioner');
const {app, dialog, ipcMain, Tray, BrowserWindow, Menu} = electron;
const appRoot = require('app-root-path');
const ServersManager = require('./servers-manager');
const path = require('path');

let windows = [];
let trayIcon = null;
let contextMenu = null;
let serversManager = new ServersManager();

function startApp() {
  if (app.dock) {
    app.dock.setIcon(path.join(__dirname, '../../assets/icons/tray-icon.png'));
    app.dock.hide();
  }
  trayIcon = new Tray(path.join(appRoot.toString(), '/assets/icons/tray-icon.png'));
  trayIcon.setPressedImage(path.join(appRoot.toString(), '/assets/icons/tray-icon-active.png'));
  /*
  serversManager.addServer({
    path: 'C:/benjamin/test',
    port: '7070'
  });
  serversManager.addServer({
    path: '/autre/serveur/de/test',
    port: '8081'
  });
  */
  updateMenu();
  trayIcon.on('click', () => trayIcon.popUpContextMenu(contextMenu));
  //openAddServerDialog();
}

function updateMenu() {
  const activeServers = serversManager.servers.filter(s => s.isActive === true);
  const stoppedServers = serversManager.servers.filter(s => s.isActive === false);
  let menuTemplate =
  [
    {
      label: 'Add a server',
      click: openAddServerDialog,
    }, {
      type: 'separator'
    }, {
      label: 'Enabled servers',
      enabled: false
    }
  ];
  for (let server of activeServers) {
    menuTemplate.push({
      label: server.path,
      sublabel: server.port,
      submenu: getServerSubMenu(server)
    });
  }
  menuTemplate.push({
    type: 'separator'
  });
  menuTemplate.push({
    label: 'Stopped servers',
    enabled: false
  });
  for (let server of stoppedServers) {
    menuTemplate.push({
      label: server.path,
      sublabel: server.port,
      submenu: getServerSubMenu(server)
    });
  }
  menuTemplate.push({
    type: 'separator'
  });
  menuTemplate.push({
    label: 'Quit',
    role: 'quit'
  });

  contextMenu = Menu.buildFromTemplate(menuTemplate);
  trayIcon.setContextMenu(contextMenu);
}

function getServerSubMenu(server) {
  let serverSubMenuTemplate = [
    {
      label: server.isActive ? 'Running on port ' + server.port : 'Will run on port ' + server.port,
      enabled: false
    },
    {
      label: server.isActive ? 'Stop the server' : 'Start the server',
      click: server.isActive ? () => stopServer(server) : () => startServer(server)
    }, {
      label: 'Delete the server',
      click: () => removeServer(server)
    }
  ];
  return Menu.buildFromTemplate(serverSubMenuTemplate);
}

function stopServer(server) {
  server.stop();
  updateMenu();
}

function startServer(server) {
  server.start();
  updateMenu();
}

function removeServer(server) {
  serversManager.removeServer(server);
  updateMenu();
}

function openAddServerDialog() {
  let addServerWindow = new BrowserWindow({
    title: 'Add a server',
    width: 250,
    height: 330,
    resizable: false,
    autoHideMenuBar: true,
    icon: path.join(__dirname, '/assets/icons/tray-icon.png')
  });
  addServerWindow.loadURL('file:' + appRoot.toString() + '/views/add-server.html');
  addServerWindow.focus();
  //addServerWindow.openDevTools();
}

app.on('window-all-closed', e => {
  e.preventDefault();
});

app.on('ready', startApp);

ipcMain.on('add-server', (event, arg) => {
  try {
    serversManager.addServer(arg);
    updateMenu();
    event.sender.send('server-added');
  } catch (exception) {
    console.log(exception);
    event.sender.send('server-not-added', {message: exception.message, icon: path.join(appRoot.toString(), '/assets/icons/tray-icon@4x.png')});
  }
});
<commit_msg>Remove useless code and comments<commit_after>'use strict';

const electron = require('electron');
const {app, dialog, ipcMain, Tray, BrowserWindow, Menu} = electron;
const appRoot = require('app-root-path');
const ServersManager = require('./servers-manager');
const path = require('path');

let windows = [];
let trayIcon = null;
let contextMenu = null;
let serversManager = new ServersManager();

function startApp() {
  if (app.dock) {
    app.dock.setIcon(path.join(__dirname, '../../assets/icons/tray-icon.png'));
    app.dock.hide();
  }
  trayIcon = new Tray(path.join(appRoot.toString(), '/assets/icons/tray-icon.png'));
  trayIcon.setPressedImage(path.join(appRoot.toString(), '/assets/icons/tray-icon-active.png'));

  updateMenu();
  trayIcon.on('click', () => trayIcon.popUpContextMenu(contextMenu));

}

function updateMenu() {
  const activeServers = serversManager.servers.filter(s => s.isActive === true);
  const stoppedServers = serversManager.servers.filter(s => s.isActive === false);
  let menuTemplate =
  [
    {
      label: 'Add a server',
      click: openAddServerDialog,
    }, {
      type: 'separator'
    }, {
      label: 'Enabled servers',
      enabled: false
    }
  ];
  for (let server of activeServers) {
    menuTemplate.push({
      label: server.path,
      sublabel: server.port,
      submenu: getServerSubMenu(server)
    });
  }
  menuTemplate.push({
    type: 'separator'
  });
  menuTemplate.push({
    label: 'Stopped servers',
    enabled: false
  });
  for (let server of stoppedServers) {
    menuTemplate.push({
      label: server.path,
      sublabel: server.port,
      submenu: getServerSubMenu(server)
    });
  }
  menuTemplate.push({
    type: 'separator'
  });
  menuTemplate.push({
    label: 'Quit',
    role: 'quit'
  });

  contextMenu = Menu.buildFromTemplate(menuTemplate);
  trayIcon.setContextMenu(contextMenu);
}

function getServerSubMenu(server) {
  let serverSubMenuTemplate = [
    {
      label: server.isActive ? 'Running on port ' + server.port : 'Will run on port ' + server.port,
      enabled: false
    },
    {
      label: server.isActive ? 'Stop the server' : 'Start the server',
      click: server.isActive ? () => stopServer(server) : () => startServer(server)
    }, {
      label: 'Delete the server',
      click: () => removeServer(server)
    }
  ];
  return Menu.buildFromTemplate(serverSubMenuTemplate);
}

function stopServer(server) {
  server.stop();
  updateMenu();
}

function startServer(server) {
  server.start();
  updateMenu();
}

function removeServer(server) {
  serversManager.removeServer(server);
  updateMenu();
}

function openAddServerDialog() {
  let addServerWindow = new BrowserWindow({
    title: 'Add a server',
    width: 250,
    height: 330,
    resizable: false,
    autoHideMenuBar: true,
    icon: path.join(__dirname, '/assets/icons/tray-icon.png')
  });
  addServerWindow.loadURL('file:' + appRoot.toString() + '/views/add-server.html');
  addServerWindow.focus();
}

app.on('window-all-closed', e => {
  e.preventDefault();
});

app.on('ready', startApp);

ipcMain.on('add-server', (event, arg) => {
  try {
    serversManager.addServer(arg);
    updateMenu();
    event.sender.send('server-added');
  } catch (exception) {
    console.log(exception);
    event.sender.send('server-not-added', {message: exception.message, icon: path.join(appRoot.toString(), '/assets/icons/tray-icon@4x.png')});
  }
});
<|endoftext|>


<commit_before>// This code is injected into every webpage that is opened
// it saves the last clicked element so passcodes knows where to put the password
// after it has been generated

// Target Element Tracker
var __passcodes__target = null;
document.addEventListener("mousedown", function(event){
    //right click
    if(event.button == 2) {
        __passcodes__target = event.target;
    }
}, true);

// Request Listener
chrome.extension.onRequest.addListener(
	function(request, sender, sendResponse) {

		// the remove subdomain function is used to return the domain to the popup
		function removeSubdomain () {
			var url = document.URL;
			var splitSlashes = url.split('/');
			if (splitSlashes.length > 1) url = splitSlashes[2];
			var domainParts = url.split('.');
			var domain = url;
			if (domainParts.length > 1) {
				domain = domainParts[domainParts.length-2];
				//alert (domain);
				if (domain == 'co') {
					domain = domainParts[domainParts.length-3];
				}
			}
			return domain.toLowerCase();
		}
		console.log("got message");

		// Get Target Request
		// The get target request returns the domain / url of the active tab
		if(request.request == "__passcod.es__getTarget") {
			sendResponse({responce:removeSubdomain()});
			console.log("HELLO");
		}

		// Set Target Request
		// The set target request is passed the password, genereated from the popup
		// it then inserted into the editable area that was last selected
		if (request.request == "__passcod.es__setTarget") {
			var text = request.password;

			// run all code here
			var txtarea = __passcodes__target;
		    var scrollPos = txtarea.scrollTop;
		    var strPos = 0;
	    	strPos = txtarea.selectionStart;

		    var front = (txtarea.value).substring(0,strPos);
		    var back = (txtarea.value).substring(strPos,txtarea.value.length);

		    txtarea.value=front+text+back;
		    strPos = strPos + text.length;

	        txtarea.selectionStart = strPos;
	        txtarea.selectionEnd = strPos;
	        txtarea.focus();
		    txtarea.scrollTop = scrollPos;
		}

	}
);<commit_msg>added more comments to functions<commit_after>// This code is injected into every webpage that is opened
// it saves the last clicked element so passcodes knows where to put the password
// after it has been generated

/*************************** TARGET ELEMENT LISTENER **************************\
| This listsner checks for every right click (context menu opening click) on   |
| the page and saves the element that was last clicked as the target for       |
| passcodes                                                                    |
\******************************************************************************/
var __passcodes__target = null;
document.addEventListener("mousedown", function(event){
    // Check right click
    if(event.button == 2) {
        __passcodes__target = event.target;
    }
}, true);

/****************************** REQUEST LISTENER ******************************\
| This request listener waits for requests from the passcodes popup. The       |
| first request it recieves is the 'getTarget' request which returns the       |
| domain of the current tab after passing it through the removeSubdomain       |
| function. The second request it recieves is the 'setTarget' request which    |
| is also bundled with the generated password that the page will insert into   |
| the passcodes target.                                                        |
\******************************************************************************/
chrome.extension.onRequest.addListener(
	function(request, sender, sendResponse) {

		// the remove subdomain function is used to return the domain to the popup
		function removeSubdomain () {
			var url = document.URL;
			var splitSlashes = url.split('/');
			if (splitSlashes.length > 1) url = splitSlashes[2];
			var domainParts = url.split('.');
			var domain = url;
			if (domainParts.length > 1) {
				domain = domainParts[domainParts.length-2];
				//alert (domain);
				if (domain == 'co') {
					domain = domainParts[domainParts.length-3];
				}
			}
			return domain.toLowerCase();
		}
		console.log("got message");

		// Get Target Request
		// The get target request returns the domain / url of the active tab
		if(request.request == "__passcod.es__getTarget") {
			sendResponse({responce:removeSubdomain()});
			console.log("HELLO");
		}

		// Set Target Request
		// The set target request is passed the password, genereated from the popup
		// it then inserted into the editable area that was last selected
		if (request.request == "__passcod.es__setTarget") {
			var text = request.password;

			// run all code here
			var txtarea = __passcodes__target;
		    var scrollPos = txtarea.scrollTop;
		    var strPos = 0;
	    	strPos = txtarea.selectionStart;

		    var front = (txtarea.value).substring(0,strPos);
		    var back = (txtarea.value).substring(strPos,txtarea.value.length);

		    txtarea.value=front+text+back;
		    strPos = strPos + text.length;

	        txtarea.selectionStart = strPos;
	        txtarea.selectionEnd = strPos;
	        txtarea.focus();
		    txtarea.scrollTop = scrollPos;
		}

	}
);<|endoftext|>