<commit_before>define([
    'jquery',
    'base/utils',
    'base/component',
    'smartpicker'
], function($, utils, Component, SmartPicker) {

    var picker;

    var PickerGeo = Component.extend({
        init: function(parent, options) {
            this._super(parent, options);
        },

        postRender: function() {
            var _this = this;
            //instantiate a new geoMult picker
            picker = new SmartPicker('mult', 'geo-picker', {
                contentData: {
                    text: "Select the countries",
                    options: [{
                        value: "swe",
                        name: "Sweden"
                    }, {
                        value: "nor",
                        name: "Norway"
                    }, {
                        value: "fin",
                        name: "Finland"
                    }, ]
                },
                width: 320,
                confirmButton: "OK",
                //what to do after user selects a country
                onSet: function(selected) {
                    //extract the value only
                    var countries = _.map(selected.selected, function(country) {
                        return country.value;
                    });
                    //pass the selected countries to state
                    _this.selectCountries(countries);
                }
            });
        },

        //TODO: this should be separated from the buttonlist (it was hardcoded)
        //pass a list of countries to the state
        selectCountries: function(countriesArr) {
            var state = {
                show: {
                    'geo': countriesArr,
                    'geo.categories': ['country']
                },
            };
            this.setState(state);
        },

        show: function() {
            picker.show();
        },

        update: function() {

        }

    });

    return PickerGeo;
});<commit_msg>Init query for country names<commit_after>define([
    'jquery',
    'base/utils',
    'base/component',
    'base/model',
    'smartpicker'
], function($, utils, Component, Model, SmartPicker) {

    var picker,
        countries;

    var PickerGeo = Component.extend({
        init: function(parent, options) {
            this._super(parent, options);
        },

        postRender: function() {
            var _this = this;

            //load countries and then initialize pickers
            this.loadCountries().then(function(country_list) {
                _this.initializePicker(country_list);
            });
        },

        //load list of countries
        loadCountries: function() {
            var defer = $.Deferred(),
                language = this.model.get("language"),
                query = this.getQuery(),
                countries = new Model();

            //set the correct source
            countries.setSource(this.data);

            //load data and resolve the defer when it's done
            $.when(
                countries.load(query, language, {})
            ).done(function() {
                var country_list = [{
                        value: "swe",
                        name: "Sweden"
                    }, {
                        value: "nor",
                        name: "Norway"
                    }, {
                        value: "fin",
                        name: "Finland"
                    }, ];
                defer.resolve(country_list);
            });

            return defer;

        },

        //initialize picker with list of countries
        initializePicker: function(country_list) {
            //instantiate a new geoMult picker
            picker = new SmartPicker('mult', 'geo-picker', {
                contentData: {
                    text: "Select the countries",
                    options: country_list || []
                },
                width: 320,
                confirmButton: "OK",
                //what to do after user selects a country
                onSet: function(selected) {
                    //extract the value only
                    var countries = _.map(selected.selected, function(country) {
                        return country.value;
                    });
                    //pass the selected countries to state
                    _this.selectCountries(countries);
                }
            });
        },

        //pass a list of countries to the state
        selectCountries: function(countriesArr) {
            var state = {
                show: {
                    'geo': countriesArr,
                    'geo.categories': ['country']
                },
            };
            this.setState(state);
        },

        show: function() {
            if (picker && picker.show) {
                picker.show();
            }
        },

        update: function() {

        },

        getQuery: function() {
          return "";
        }

    });

    return PickerGeo;
});<|endoftext|>


<commit_before>import { RoomsService } from '../../services/roomsService';

export class RoomsList {

  rooms = [];

  static inject() { return [RoomsService]; }
  constructor(roomsService) {
    this.rooms = roomsService.getRooms();
  }
}
<commit_msg>Uses inject decorator for the service<commit_after>import { inject } from 'aurelia-framework';
import { RoomsService } from '../../services/roomsService';

@inject(RoomsService)
export class RoomsList {

  rooms = [];

  constructor(roomsService) {
    this.rooms = roomsService.getRooms();
  }
}
<|endoftext|>


<commit_before>import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { debounce, isEmpty, map } from 'lodash';

import FlexContainer from 'primitives/container/flex-container';
import EntityTooltips from 'components/entity-tooltips';
import CondensedPrintable from 'components/printables/condensed-printable';
import ExpandedPrintable from 'components/printables/expanded-printable';
import TopLevelEntityModal from 'components/top-level-entity-modal';
import ProfileModal from 'components/profile-modal';
import HexMap from 'components/hex-map';
import Navigation from 'components/navigation';

import ExportTypes from 'constants/export-types';
import hexGenerator from 'utils/hex/generator';
import { coordinateKey } from 'utils/common';
import Loading from './loading';
import Error from './error';

import './style.css';

const calcNavWidth = () => (window.innerWidth > 1500 ? 200 : 75);
const calcWidth = () => {
  let width = window.innerWidth - 75;
  if (window.innerWidth > 1200) {
    width -= 450;
  } else if (window.innerWidth > 700) {
    width -= 375;
  }
  return width;
};

export default class SectorMap extends Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
    renderSector: PropTypes.bool.isRequired,
    hasLoaded: PropTypes.bool.isRequired,
    topLevelEntities: PropTypes.shape().isRequired,
    sector: PropTypes.shape({
      rows: PropTypes.number,
      columns: PropTypes.number,
    }),
    generateSector: PropTypes.func.isRequired,
    toSafeRoute: PropTypes.func.isRequired,
    location: PropTypes.shape({
      pathname: PropTypes.string.isRequired,
    }).isRequired,
    routeParams: PropTypes.shape().isRequired,
    exportType: PropTypes.string.isRequired,
    isPrinting: PropTypes.bool.isRequired,
  };

  static defaultProps = {
    sector: {},
  };

  state = {
    height: window.innerHeight,
    width: calcWidth(),
  };

  componentWillMount() {
    const splitPath = this.props.location.pathname.split('/');
    if (
      splitPath.length > 5 ||
      (splitPath[4] || splitPath[2] || '').length !== 20
    ) {
      this.props.toSafeRoute(this.props.routeParams.sector);
    }
  }

  componentDidMount() {
    window.addEventListener('resize', this.onResize);
  }

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

  onResize = debounce(() => {
    this.setState({
      height: window.innerHeight,
      width: calcWidth(),
    });
  }, 100);

  renderTooltips(hexData) {
    if (!this.props.renderSector) {
      return null;
    }
    return (
      <EntityTooltips
        leftOffset={calcNavWidth()}
        hexes={map(this.props.topLevelEntities, entity => ({
          ...entity,
          ...hexData.find(
            ({ hexKey }) => coordinateKey(entity.x, entity.y) === hexKey,
          ),
        }))}
      />
    );
  }

  renderPrintable(printable) {
    if (!this.props.isPrinting) {
      return null;
    }
    if (this.props.exportType === ExportTypes.expanded.key) {
      return <ExpandedPrintable printable={printable} />;
    }
    return <CondensedPrintable printable={printable} />;
  }

  render() {
    if (!this.props.hasLoaded) {
      return <Loading />;
    } else if (isEmpty(this.props.sector)) {
      return <Error generateSector={this.props.generateSector} />;
    }

    const { hexes, printable } = hexGenerator({
      renderSector: true,
      height: this.state.height,
      width: this.state.width,
      rows: this.props.sector.rows,
      columns: this.props.sector.columns,
    });

    return (
      <Fragment>
        <FlexContainer className="SectorMap" direction="row">
          {this.renderTooltips(hexes)}
          <Navigation />
          <HexMap
            width={this.state.width}
            height={this.state.height}
            hexes={hexes}
            isSector
          />

{this.props.children}

        </FlexContainer>
        {this.renderPrintable(printable)}
        <TopLevelEntityModal />
        <ProfileModal />
      </Fragment>
    );
  }
}
<commit_msg>Center canvas when screen width is greater than 1500<commit_after>import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { debounce, isEmpty, map } from 'lodash';

import FlexContainer from 'primitives/container/flex-container';
import EntityTooltips from 'components/entity-tooltips';
import CondensedPrintable from 'components/printables/condensed-printable';
import ExpandedPrintable from 'components/printables/expanded-printable';
import TopLevelEntityModal from 'components/top-level-entity-modal';
import ProfileModal from 'components/profile-modal';
import HexMap from 'components/hex-map';
import Navigation from 'components/navigation';

import ExportTypes from 'constants/export-types';
import hexGenerator from 'utils/hex/generator';
import { coordinateKey } from 'utils/common';
import Loading from './loading';
import Error from './error';

import './style.css';

const calcNavWidth = () => (window.innerWidth > 1500 ? 200 : 75);
const calcWidth = () => {
  let width = window.innerWidth - 75;
  if (window.innerWidth > 1500) {
    width -= 575;
  } else if (window.innerWidth > 1200) {
    width -= 450;
  } else if (window.innerWidth > 700) {
    width -= 375;
  }
  return width;
};

export default class SectorMap extends Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
    renderSector: PropTypes.bool.isRequired,
    hasLoaded: PropTypes.bool.isRequired,
    topLevelEntities: PropTypes.shape().isRequired,
    sector: PropTypes.shape({
      rows: PropTypes.number,
      columns: PropTypes.number,
    }),
    generateSector: PropTypes.func.isRequired,
    toSafeRoute: PropTypes.func.isRequired,
    location: PropTypes.shape({
      pathname: PropTypes.string.isRequired,
    }).isRequired,
    routeParams: PropTypes.shape().isRequired,
    exportType: PropTypes.string.isRequired,
    isPrinting: PropTypes.bool.isRequired,
  };

  static defaultProps = {
    sector: {},
  };

  state = {
    height: window.innerHeight,
    width: calcWidth(),
  };

  componentWillMount() {
    const splitPath = this.props.location.pathname.split('/');
    if (
      splitPath.length > 5 ||
      (splitPath[4] || splitPath[2] || '').length !== 20
    ) {
      this.props.toSafeRoute(this.props.routeParams.sector);
    }
  }

  componentDidMount() {
    window.addEventListener('resize', this.onResize);
  }

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

  onResize = debounce(() => {
    this.setState({
      height: window.innerHeight,
      width: calcWidth(),
    });
  }, 100);

  renderTooltips(hexData) {
    if (!this.props.renderSector) {
      return null;
    }
    return (
      <EntityTooltips
        leftOffset={calcNavWidth()}
        hexes={map(this.props.topLevelEntities, entity => ({
          ...entity,
          ...hexData.find(
            ({ hexKey }) => coordinateKey(entity.x, entity.y) === hexKey,
          ),
        }))}
      />
    );
  }

  renderPrintable(printable) {
    if (!this.props.isPrinting) {
      return null;
    }
    if (this.props.exportType === ExportTypes.expanded.key) {
      return <ExpandedPrintable printable={printable} />;
    }
    return <CondensedPrintable printable={printable} />;
  }

  render() {
    if (!this.props.hasLoaded) {
      return <Loading />;
    } else if (isEmpty(this.props.sector)) {
      return <Error generateSector={this.props.generateSector} />;
    }

    const { hexes, printable } = hexGenerator({
      renderSector: true,
      height: this.state.height,
      width: this.state.width,
      rows: this.props.sector.rows,
      columns: this.props.sector.columns,
    });

    return (
      <Fragment>
        <FlexContainer className="SectorMap" direction="row">
          {this.renderTooltips(hexes)}
          <Navigation />
          <HexMap
            width={this.state.width}
            height={this.state.height}
            hexes={hexes}
            isSector
          />

{this.props.children}

        </FlexContainer>
        {this.renderPrintable(printable)}
        <TopLevelEntityModal />
        <ProfileModal />
      </Fragment>
    );
  }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016, University of Colorado Boulder

/**
 * Initializes phet globals that are used by all simulations, including assertions and query-parameters.
 * See https://github.com/phetsims/phetcommon/issues/23
 * This file must be loaded before requirejs is started up, and this file cannot be loaded as an AMD module.
 * The easiest way to do this is via a <script> tag in your HTML file.
 *
 * PhET Simulations can be launched with query parameters which enable certain features.  To use a query parameter,
 * provide the full URL of the simulation and append a question mark (?) then the query parameter (and optionally its
 * value assignment).  For instance:
 * http://www.colorado.edu/physics/phet/dev/html/reactants-products-and-leftovers/1.0.0-dev.13/reactants-products-and-leftovers_en.html?dev
 *
 * Here is an example of a value assignment:
 * http://www.colorado.edu/physics/phet/dev/html/reactants-products-and-leftovers/1.0.0-dev.13/reactants-products-and-leftovers_en.html?webgl=false
 *
 * To use multiple query parameters, specify the question mark before the first query parameter, then ampersands (&)
 * between other query parameters.  Here is an example of multiple query parameters:
 * http://www.colorado.edu/physics/phet/dev/html/reactants-products-and-leftovers/1.0.0-dev.13/reactants-products-and-leftovers_en.html?dev&showPointerAreas&webgl=false
 *
 * For more on query parameters in general, see http://en.wikipedia.org/wiki/Query_string
 * For details on common-code query parameters, see QUERY_PARAMETERS_SCHEMA below.
 * For sim-specific query parameters (if there are any), see *QueryParameters.js in the simulation's repository.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Chris Malley (PixelZoom, Inc.)
 */
(function() {
  'use strict';

  // Schema that describes query parameters for PhET common code.
  // These query parameters are available via global phet.chipper.queryParameters.
  var QUERY_PARAMETERS_SCHEMA = {

    // Whether accessibility features are enabled or not.  Use this option to render the Parallel DOM for
    // keyboard navigation and screen reader based auditory descriptions.
    accessibility: { type: 'flag' },

    /**
     * Master volume control for the simulation (for Vibe sounds).
     * 1.0 is unity volume, 2.0 is double volume, etc.
     */
    audioVolume: {
      type: 'number',
      defaultValue: 1,
      isValidValue: function( value ) { return value >= 0; }
    },

    /**
     * specifies the brand that should be used in requirejs mode
     */
    brand: {
      type: 'string',
      defaultValue: 'adapted-from-phet',
      validValues: [ 'phet', 'phet-io', 'adapted-from-phet' ]
    },

    /**
     * When present, will trigger changes that are more similar to the build environment.
     * Right now, this includes computing higher-resolution mipmaps for the mipmap plugin.
     */
    buildCompatible: { type: 'flag' },

    /**
     * enables cache busting in requirejs mode.
     */
    cacheBuster: {
      type: 'boolean',
      defaultValue: true
    },

    /**
     * The color profile used at startup, relevant only for sims that support multiple color profiles.
     * Such sims are required to have a 'default' profile.  If a sim supports a 'project mode' then
     * it should also have a 'projector' profile.  Other profile names are not currently standardized.
     */
    colorProfile: {
      type: 'string',
      defaultValue: 'default'
    },

    /**
     * enables developer-only features, such as showing the layout bounds
     */
    dev: { type: 'flag' },

    /**
     * enables assertions
     */
    ea: { type: 'flag' },

    /**
     * Enables all assertions, as above but with more time-consuming checks
     */
    eall: { type: 'flag' },

    /**
     * Randomly sends mouse events to sim.
     */
    fuzzMouse: { type: 'flag' },

    /**
     * if fuzzMouse=true, this is the average number of mouse events to synthesize per frame.
     */
    fuzzRate: {
      type: 'number',
      defaultValue: 100,
      isValidValue: function( value ) { return value > 0; }
    },

    /**
     * When a simulation is run from the PhET iOS app, it should set this flag. It alters statistics that the sim sends
     * to Google Analytics and potentially other sources in the future.
     */
    'phet-app': { type: 'flag' },

    /**
     * When a simulation is run from the PhET Android app, it should set this flag. It alters statistics that the sim sends
     * to Google Analytics and potentially other sources in the future.
     */
    'phet-android-app': { type: 'flag' },

    /**
     * Launches the game-up-camera code which delivers images to requests in BrainPOP/Game Up/SnapThought
     */
    gameUp: { type: 'flag' },

    /**
     * Enables logging for game-up-camera, see gameUp
     */
    gameUpLogging: { type: 'flag' },

    /**
     * test with a specific locale
     */
    locale: {
      type: 'string',
      defaultValue: 'en'
    },

    /**
     * plays event logging back from the server, provide an optional name for the session
     */
    playbackInputEventLog: { type: 'flag' },

    /**
     * Fires a post-message when the sim is about to change to another URL
     */
    postMessageOnBeforeUnload: { type: 'flag' },

    /**
     * passes errors to test-sims
     */
    postMessageOnError: { type: 'flag' },

    /**
     * triggers a post-message that fires when the sim finishes loading, currently used by aqua test-sims
     */
    postMessageOnLoad: { type: 'flag' },

    /**
     * shows profiling information for the sim
     */
    profiler: { type: 'flag' },

    /**
     * adds a menu item that will open a window with a QR code with the URL of the simulation
     */
    qrCode: { type: 'flag' },

    /**
     * enables input event logging, provide an optional name for the session, log is available via PhET menu
     */
    recordInputEventLog: { type: 'flag' },

    /**
     * Specify a renderer for the Sim's rootNode to use.
     */
    rootRenderer: {
      type: 'string',
      defaultValue: null,
      validValues: [ null, 'canvas', 'svg', 'dom', 'webgl' ] // see Node.setRenderer
    },

    /**
     * Array of one or more logs to enable in scenery 0.2+, delimited with commas.
     * For example: ?sceneryLog=Display,Drawable,WebGLBlock results in [ 'Display', 'Drawable', 'WebGLBlock' ]
     */
    sceneryLog: {
      type: 'array',
      elementSchema: {
        type: 'string'
      },
      defaultValue: null
    },

    /**
     * Scenery logs will be output to a string instead of the window
     */
    sceneryStringLog: { type: 'flag' },

    /**
     * Indicates the screen that will be initially selected on the home screen.
     * If showHomeScreen is false, go immediately to this screen.
     * Like query parameter 'screens', the value is 1-based; e.g. 'screenIndex=2' selects the 2nd screen.
     * Use this query parameter only with multi-screen sims.
     */
    screenIndex: {
      type: 'number',
      defaultValue: 1
    },

    /**
     * Specifies the set of screens that appear in the sim, and their order.  Uses 1-based (not zero-based) and ","
     * delimited string such as "1,3,4" to get the 1st, 3rd and 4th screen.
     */
    screens: {
      type: 'array',
      elementSchema: {
        type: 'number'
      },
      defaultValue: null
    },

    /**
     * Displays an overlay of the current bounds of each CanvasNode
     */
    showCanvasNodeBounds: { type: 'flag' },

    /**
     * Displays an overlay of the current bounds of each scenery.FittedBlock
     */
    showFittedBlockBounds: { type: 'flag' },

    /**
     * if false, go immediately to screenIndex
     */
    showHomeScreen: {
      type: 'boolean',
      defaultValue: true
    },

    /**
     * Shows pointer areas as dashed lines. touchAreas are red, mouseAreas are blue.
     */
    showPointerAreas: { type: 'flag' },

    /**
     * Displays a semi-transparent cursor indicator for the location of each active pointer on the screen.
     */
    showPointers: { type: 'flag' },

    /**
     * Shows the visible bounds in ScreenView.js, for debugging the layout outside of the "dev" bounds
     */
    showVisibleBounds: { type: 'flag' },

    /**
     * override strings, value is JSON that is identical to string.json files
     */
    strings: {
      type: 'string',
      defaultValue: null
    },

    /**
     * Sets a string used for various i18n test.  The values are:
     *
     * double: duplicates all of the translated strings which will allow to see (a) if all strings
     *   are translated and (b) whether the layout can accommodate longer strings from other languages.
     *   Note this is a heuristic rule that does not cover all cases.
     *
     * long: an exceptionally long string will be substituted for all strings. Use this to test for layout problems.
     *
     * rtl: a string that tests RTL (right-to-left) capabilities will be substituted for all strings
     *
     * xss: tests for security issues related to https://github.com/phetsims/special-ops/issues/18,
     *   and running a sim should NOT redirect to another page. Preferably should be used for built versions or
     *   other versions where assertions are not enabled (brackets can cause issues for SubSupText, etc.)
     *
     * none|null: the normal translated string will be shown
     *
     * {string}: if any other string provided, that string will be substituted everywhere. This facilitates testing
     *   specific cases, like whether the word 'vitesse' would substitute for 'speed' well.  Also, using "/u20" it
     *   will show whitespace for all of the strings, making it easy to identify non-translated strings.
     */
    stringTest: {
      type: 'string',
      defaultValue: null
    },

    /**
     * Enables WebGL rendering. See https://github.com/phetsims/scenery/issues/289
     */
    webgl: {
      type: 'boolean',
      defaultValue: true
    }
  };

  // Initialize query parameters, see docs above
  (function() {

    // Create the attachment point for all PhET globals
    window.phet = window.phet || {};
    window.phet.chipper = window.phet.chipper || {};

    // Read query parameters
    window.phet.chipper.queryParameters = QueryStringMachine.getAll( QUERY_PARAMETERS_SCHEMA );

    /**
     * Gets the cache buster args based on the provided query parameters.  By default it is:
     * ?bust=<number>
     * But this can be omitted if ?cacheBuster=false is provided
     * See https://github.com/phetsims/joist/issues/196
     * @returns {string}
     */
    window.phet.chipper.getCacheBusterArgs = function() {
      return phet.chipper.queryParameters.cacheBuster ? ('bust=' + Date.now()) : '';
    };

    /**
     * Gets the name of brand to use, which determines which logo to show in the navbar as well as what options
     * to show in the PhET menu and what text to show in the About dialog.
     * See https://github.com/phetsims/brand/issues/11
     * @returns {string}
     */
    window.phet.chipper.brand = window.phet.chipper.brand || phet.chipper.queryParameters.brand || 'adapted-from-phet';

    /**
     * Maps an input string to a final string, accommodating tricks like doubleStrings.
     * This function is used to modify all strings in a sim when the stringTest query parameter is used.
     * The stringTest query parameter and its options are documented in the query parameter docs above.
     * It is used in string.js and sim.html.
     * @param string - the string to be mapped
     * @param stringTest - the value of the stringTest query parameter
     * @returns {string}
     */
    window.phet.chipper.mapString = function( string, stringTest ) {
      return stringTest === null ? string :
             stringTest === 'double' ? string + ':' + string :
             stringTest === 'long' ? '12345678901234567890123456789012345678901234567890' :
             stringTest === 'rtl' ? '\u202b\u062a\u0633\u062a (\u0632\u0628\u0627\u0646)\u202c' :
             stringTest === 'xss' ? string + '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NkYGD4DwABCQEBtxmN7wAAAABJRU5ErkJggg==" onload="window.location.href=atob(\'aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUQ==\')" />' :
             stringTest === 'none' ? string :

               //In the fallback case, supply whatever string was given in the query parameter value
             stringTest;
    };

    // If locale was provided as a query parameter, then change the locale used by Google Analytics.
    if ( QueryStringMachine.containsKey( 'locale' ) ) {
      window.phet.chipper.locale = phet.chipper.queryParameters.locale;
    }
  }());

  // Create a random seed in the preload code that can be used to make sure playback simulations use the same seed
  // See Random.js
  // @public (writeable by phet-io) can be overwritten for replicable playback in phet-io.
  window.phet.chipper.randomSeed = Math.random();

  /**
   * Enables or disables assertions in common libraries using query parameters.
   * There are two types of assertions: basic and slow. Enabling slow assertions will adversely impact performance.
   * 'ea' enables basic assertions, 'eall' enables basic and slow assertions.
   * Must be run before RequireJS, and assumes that assert.js and query-parameters.js has been run.
   */
  (function() {

    // TODO: separate this logic out into a more common area?
    var isProduction = $( 'meta[name=phet-sim-level]' ).attr( 'content' ) === 'production';

    var enableAllAssertions = !isProduction && phet.chipper.queryParameters.eall; // enables all assertions (basic and slow)
    var enableBasicAssertions = enableAllAssertions || ( !isProduction && phet.chipper.queryParameters.ea );  // enables basic assertions

    if ( enableBasicAssertions ) {
      window.assertions.enableAssert();
    }
    if ( enableAllAssertions ) {
      window.assertions.enableAssertSlow();
    }

    // Communicate sim errors to joist/tests/test-sims.html
    if ( phet.chipper.queryParameters.postMessageOnError ) {
      window.addEventListener( 'error', function( a, b, c, d, e ) {
        var message = '';
        var stack = '';
        if ( a && a.message ) {
          message = a.message;
        }
        if ( a && a.error && a.error.stack ) {
          stack = a.error.stack;
        }
        window.parent && window.parent.postMessage( JSON.stringify( {
          type: 'error',
          url: window.location.href,
          message: message,
          stack: stack
        } ), '*' );
      } );
    }

    if ( phet.chipper.queryParameters.postMessageOnBeforeUnload ) {
      window.addEventListener( 'beforeunload', function( e ) {
        window.parent && window.parent.postMessage( JSON.stringify( {
          type: 'beforeUnload'
        } ), '*' );
      } );
    }
  }());
}());
<commit_msg>Using RichText instead of alternatives, see https://github.com/phetsims/scenery-phet/issues/300<commit_after>// Copyright 2015-2016, University of Colorado Boulder

/**
 * Initializes phet globals that are used by all simulations, including assertions and query-parameters.
 * See https://github.com/phetsims/phetcommon/issues/23
 * This file must be loaded before requirejs is started up, and this file cannot be loaded as an AMD module.
 * The easiest way to do this is via a <script> tag in your HTML file.
 *
 * PhET Simulations can be launched with query parameters which enable certain features.  To use a query parameter,
 * provide the full URL of the simulation and append a question mark (?) then the query parameter (and optionally its
 * value assignment).  For instance:
 * http://www.colorado.edu/physics/phet/dev/html/reactants-products-and-leftovers/1.0.0-dev.13/reactants-products-and-leftovers_en.html?dev
 *
 * Here is an example of a value assignment:
 * http://www.colorado.edu/physics/phet/dev/html/reactants-products-and-leftovers/1.0.0-dev.13/reactants-products-and-leftovers_en.html?webgl=false
 *
 * To use multiple query parameters, specify the question mark before the first query parameter, then ampersands (&)
 * between other query parameters.  Here is an example of multiple query parameters:
 * http://www.colorado.edu/physics/phet/dev/html/reactants-products-and-leftovers/1.0.0-dev.13/reactants-products-and-leftovers_en.html?dev&showPointerAreas&webgl=false
 *
 * For more on query parameters in general, see http://en.wikipedia.org/wiki/Query_string
 * For details on common-code query parameters, see QUERY_PARAMETERS_SCHEMA below.
 * For sim-specific query parameters (if there are any), see *QueryParameters.js in the simulation's repository.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 * @author Chris Malley (PixelZoom, Inc.)
 */
(function() {
  'use strict';

  // Schema that describes query parameters for PhET common code.
  // These query parameters are available via global phet.chipper.queryParameters.
  var QUERY_PARAMETERS_SCHEMA = {

    // Whether accessibility features are enabled or not.  Use this option to render the Parallel DOM for
    // keyboard navigation and screen reader based auditory descriptions.
    accessibility: { type: 'flag' },

    /**
     * Master volume control for the simulation (for Vibe sounds).
     * 1.0 is unity volume, 2.0 is double volume, etc.
     */
    audioVolume: {
      type: 'number',
      defaultValue: 1,
      isValidValue: function( value ) { return value >= 0; }
    },

    /**
     * specifies the brand that should be used in requirejs mode
     */
    brand: {
      type: 'string',
      defaultValue: 'adapted-from-phet',
      validValues: [ 'phet', 'phet-io', 'adapted-from-phet' ]
    },

    /**
     * When present, will trigger changes that are more similar to the build environment.
     * Right now, this includes computing higher-resolution mipmaps for the mipmap plugin.
     */
    buildCompatible: { type: 'flag' },

    /**
     * enables cache busting in requirejs mode.
     */
    cacheBuster: {
      type: 'boolean',
      defaultValue: true
    },

    /**
     * The color profile used at startup, relevant only for sims that support multiple color profiles.
     * Such sims are required to have a 'default' profile.  If a sim supports a 'project mode' then
     * it should also have a 'projector' profile.  Other profile names are not currently standardized.
     */
    colorProfile: {
      type: 'string',
      defaultValue: 'default'
    },

    /**
     * enables developer-only features, such as showing the layout bounds
     */
    dev: { type: 'flag' },

    /**
     * enables assertions
     */
    ea: { type: 'flag' },

    /**
     * Enables all assertions, as above but with more time-consuming checks
     */
    eall: { type: 'flag' },

    /**
     * Randomly sends mouse events to sim.
     */
    fuzzMouse: { type: 'flag' },

    /**
     * if fuzzMouse=true, this is the average number of mouse events to synthesize per frame.
     */
    fuzzRate: {
      type: 'number',
      defaultValue: 100,
      isValidValue: function( value ) { return value > 0; }
    },

    /**
     * When a simulation is run from the PhET iOS app, it should set this flag. It alters statistics that the sim sends
     * to Google Analytics and potentially other sources in the future.
     */
    'phet-app': { type: 'flag' },

    /**
     * When a simulation is run from the PhET Android app, it should set this flag. It alters statistics that the sim sends
     * to Google Analytics and potentially other sources in the future.
     */
    'phet-android-app': { type: 'flag' },

    /**
     * Launches the game-up-camera code which delivers images to requests in BrainPOP/Game Up/SnapThought
     */
    gameUp: { type: 'flag' },

    /**
     * Enables logging for game-up-camera, see gameUp
     */
    gameUpLogging: { type: 'flag' },

    /**
     * test with a specific locale
     */
    locale: {
      type: 'string',
      defaultValue: 'en'
    },

    /**
     * plays event logging back from the server, provide an optional name for the session
     */
    playbackInputEventLog: { type: 'flag' },

    /**
     * Fires a post-message when the sim is about to change to another URL
     */
    postMessageOnBeforeUnload: { type: 'flag' },

    /**
     * passes errors to test-sims
     */
    postMessageOnError: { type: 'flag' },

    /**
     * triggers a post-message that fires when the sim finishes loading, currently used by aqua test-sims
     */
    postMessageOnLoad: { type: 'flag' },

    /**
     * shows profiling information for the sim
     */
    profiler: { type: 'flag' },

    /**
     * adds a menu item that will open a window with a QR code with the URL of the simulation
     */
    qrCode: { type: 'flag' },

    /**
     * enables input event logging, provide an optional name for the session, log is available via PhET menu
     */
    recordInputEventLog: { type: 'flag' },

    /**
     * Specify a renderer for the Sim's rootNode to use.
     */
    rootRenderer: {
      type: 'string',
      defaultValue: null,
      validValues: [ null, 'canvas', 'svg', 'dom', 'webgl' ] // see Node.setRenderer
    },

    /**
     * Array of one or more logs to enable in scenery 0.2+, delimited with commas.
     * For example: ?sceneryLog=Display,Drawable,WebGLBlock results in [ 'Display', 'Drawable', 'WebGLBlock' ]
     */
    sceneryLog: {
      type: 'array',
      elementSchema: {
        type: 'string'
      },
      defaultValue: null
    },

    /**
     * Scenery logs will be output to a string instead of the window
     */
    sceneryStringLog: { type: 'flag' },

    /**
     * Indicates the screen that will be initially selected on the home screen.
     * If showHomeScreen is false, go immediately to this screen.
     * Like query parameter 'screens', the value is 1-based; e.g. 'screenIndex=2' selects the 2nd screen.
     * Use this query parameter only with multi-screen sims.
     */
    screenIndex: {
      type: 'number',
      defaultValue: 1
    },

    /**
     * Specifies the set of screens that appear in the sim, and their order.  Uses 1-based (not zero-based) and ","
     * delimited string such as "1,3,4" to get the 1st, 3rd and 4th screen.
     */
    screens: {
      type: 'array',
      elementSchema: {
        type: 'number'
      },
      defaultValue: null
    },

    /**
     * Displays an overlay of the current bounds of each CanvasNode
     */
    showCanvasNodeBounds: { type: 'flag' },

    /**
     * Displays an overlay of the current bounds of each scenery.FittedBlock
     */
    showFittedBlockBounds: { type: 'flag' },

    /**
     * if false, go immediately to screenIndex
     */
    showHomeScreen: {
      type: 'boolean',
      defaultValue: true
    },

    /**
     * Shows pointer areas as dashed lines. touchAreas are red, mouseAreas are blue.
     */
    showPointerAreas: { type: 'flag' },

    /**
     * Displays a semi-transparent cursor indicator for the location of each active pointer on the screen.
     */
    showPointers: { type: 'flag' },

    /**
     * Shows the visible bounds in ScreenView.js, for debugging the layout outside of the "dev" bounds
     */
    showVisibleBounds: { type: 'flag' },

    /**
     * override strings, value is JSON that is identical to string.json files
     */
    strings: {
      type: 'string',
      defaultValue: null
    },

    /**
     * Sets a string used for various i18n test.  The values are:
     *
     * double: duplicates all of the translated strings which will allow to see (a) if all strings
     *   are translated and (b) whether the layout can accommodate longer strings from other languages.
     *   Note this is a heuristic rule that does not cover all cases.
     *
     * long: an exceptionally long string will be substituted for all strings. Use this to test for layout problems.
     *
     * rtl: a string that tests RTL (right-to-left) capabilities will be substituted for all strings
     *
     * xss: tests for security issues related to https://github.com/phetsims/special-ops/issues/18,
     *   and running a sim should NOT redirect to another page. Preferably should be used for built versions or
     *   other versions where assertions are not enabled.
     *
     * none|null: the normal translated string will be shown
     *
     * {string}: if any other string provided, that string will be substituted everywhere. This facilitates testing
     *   specific cases, like whether the word 'vitesse' would substitute for 'speed' well.  Also, using "/u20" it
     *   will show whitespace for all of the strings, making it easy to identify non-translated strings.
     */
    stringTest: {
      type: 'string',
      defaultValue: null
    },

    /**
     * Enables WebGL rendering. See https://github.com/phetsims/scenery/issues/289
     */
    webgl: {
      type: 'boolean',
      defaultValue: true
    }
  };

  // Initialize query parameters, see docs above
  (function() {

    // Create the attachment point for all PhET globals
    window.phet = window.phet || {};
    window.phet.chipper = window.phet.chipper || {};

    // Read query parameters
    window.phet.chipper.queryParameters = QueryStringMachine.getAll( QUERY_PARAMETERS_SCHEMA );

    /**
     * Gets the cache buster args based on the provided query parameters.  By default it is:
     * ?bust=<number>
     * But this can be omitted if ?cacheBuster=false is provided
     * See https://github.com/phetsims/joist/issues/196
     * @returns {string}
     */
    window.phet.chipper.getCacheBusterArgs = function() {
      return phet.chipper.queryParameters.cacheBuster ? ('bust=' + Date.now()) : '';
    };

    /**
     * Gets the name of brand to use, which determines which logo to show in the navbar as well as what options
     * to show in the PhET menu and what text to show in the About dialog.
     * See https://github.com/phetsims/brand/issues/11
     * @returns {string}
     */
    window.phet.chipper.brand = window.phet.chipper.brand || phet.chipper.queryParameters.brand || 'adapted-from-phet';

    /**
     * Maps an input string to a final string, accommodating tricks like doubleStrings.
     * This function is used to modify all strings in a sim when the stringTest query parameter is used.
     * The stringTest query parameter and its options are documented in the query parameter docs above.
     * It is used in string.js and sim.html.
     * @param string - the string to be mapped
     * @param stringTest - the value of the stringTest query parameter
     * @returns {string}
     */
    window.phet.chipper.mapString = function( string, stringTest ) {
      return stringTest === null ? string :
             stringTest === 'double' ? string + ':' + string :
             stringTest === 'long' ? '12345678901234567890123456789012345678901234567890' :
             stringTest === 'rtl' ? '\u202b\u062a\u0633\u062a (\u0632\u0628\u0627\u0646)\u202c' :
             stringTest === 'xss' ? string + '<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NkYGD4DwABCQEBtxmN7wAAAABJRU5ErkJggg==" onload="window.location.href=atob(\'aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1kUXc0dzlXZ1hjUQ==\')" />' :
             stringTest === 'none' ? string :

               //In the fallback case, supply whatever string was given in the query parameter value
             stringTest;
    };

    // If locale was provided as a query parameter, then change the locale used by Google Analytics.
    if ( QueryStringMachine.containsKey( 'locale' ) ) {
      window.phet.chipper.locale = phet.chipper.queryParameters.locale;
    }
  }());

  // Create a random seed in the preload code that can be used to make sure playback simulations use the same seed
  // See Random.js
  // @public (writeable by phet-io) can be overwritten for replicable playback in phet-io.
  window.phet.chipper.randomSeed = Math.random();

  /**
   * Enables or disables assertions in common libraries using query parameters.
   * There are two types of assertions: basic and slow. Enabling slow assertions will adversely impact performance.
   * 'ea' enables basic assertions, 'eall' enables basic and slow assertions.
   * Must be run before RequireJS, and assumes that assert.js and query-parameters.js has been run.
   */
  (function() {

    // TODO: separate this logic out into a more common area?
    var isProduction = $( 'meta[name=phet-sim-level]' ).attr( 'content' ) === 'production';

    var enableAllAssertions = !isProduction && phet.chipper.queryParameters.eall; // enables all assertions (basic and slow)
    var enableBasicAssertions = enableAllAssertions || ( !isProduction && phet.chipper.queryParameters.ea );  // enables basic assertions

    if ( enableBasicAssertions ) {
      window.assertions.enableAssert();
    }
    if ( enableAllAssertions ) {
      window.assertions.enableAssertSlow();
    }

    // Communicate sim errors to joist/tests/test-sims.html
    if ( phet.chipper.queryParameters.postMessageOnError ) {
      window.addEventListener( 'error', function( a, b, c, d, e ) {
        var message = '';
        var stack = '';
        if ( a && a.message ) {
          message = a.message;
        }
        if ( a && a.error && a.error.stack ) {
          stack = a.error.stack;
        }
        window.parent && window.parent.postMessage( JSON.stringify( {
          type: 'error',
          url: window.location.href,
          message: message,
          stack: stack
        } ), '*' );
      } );
    }

    if ( phet.chipper.queryParameters.postMessageOnBeforeUnload ) {
      window.addEventListener( 'beforeunload', function( e ) {
        window.parent && window.parent.postMessage( JSON.stringify( {
          type: 'beforeUnload'
        } ), '*' );
      } );
    }
  }());
}());
<|endoftext|>


<commit_before>/*!
 * jQuery Mobile v@VERSION
 * http://jquerymobile.com/
 *
 * Copyright 2010, jQuery Project
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */

(function( $, window, undefined ) {

	//jQuery.mobile configurable options
	$.extend( $.mobile, {

		//namespace used framework-wide for data-attrs. Default is no namespace
		ns: "",

		//define the url parameter used for referencing widget-generated sub-pages.
		//Translates to to example.html&ui-page=subpageIdentifier
		//hash segment before &ui-page= is used to make Ajax request
		subPageUrlKey: "ui-page",

		//anchor links with a data-rel, or pages with a  data-role, that match these selectors will be untrackable in history
		//(no change in URL, not bookmarkable)
		nonHistorySelectors: "dialog",

		//class assigned to page currently in view, and during transitions
		activePageClass: "ui-page-active",

		//class used for "active" button state, from CSS framework
		activeBtnClass: "ui-btn-active",

		//automatically handle clicks and form submissions through Ajax, when same-domain
		ajaxEnabled: true,

		//automatically load and show pages based on location.hash
		hashListeningEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle link clicks through Ajax, when possible
		ajaxLinksEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle form submissions through Ajax, when possible
		ajaxFormsEnabled: true,

		//set default transition - 'none' for no transitions
		defaultTransition: "slide",

		//show loading message during Ajax requests
		//if false, message will not appear, but loading classes will still be toggled on html el
		loadingMessage: "loading",

		//error response message - appears when an Ajax page request fails
		pageLoadErrorMessage: "Error Loading Page",

		//configure meta viewport tag's content attr:
		//note: this feature is deprecated in A4 in favor of adding
		//the meta viewport element directly in the markup
		metaViewportContent: "width=device-width, minimum-scale=1, maximum-scale=1",

		//support conditions that must be met in order to proceed
		//default enhanced qualifications are media query support OR IE 7+
		gradeA: function(){
			return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
		},

		//TODO might be useful upstream in jquery itself ?
		keyCode: {
			ALT: 18,
			BACKSPACE: 8,
			CAPS_LOCK: 20,
			COMMA: 188,
			COMMAND: 91,
			COMMAND_LEFT: 91, // COMMAND
			COMMAND_RIGHT: 93,
			CONTROL: 17,
			DELETE: 46,
			DOWN: 40,
			END: 35,
			ENTER: 13,
			ESCAPE: 27,
			HOME: 36,
			INSERT: 45,
			LEFT: 37,
			MENU: 93, // COMMAND_RIGHT
			NUMPAD_ADD: 107,
			NUMPAD_DECIMAL: 110,
			NUMPAD_DIVIDE: 111,
			NUMPAD_ENTER: 108,
			NUMPAD_MULTIPLY: 106,
			NUMPAD_SUBTRACT: 109,
			PAGE_DOWN: 34,
			PAGE_UP: 33,
			PERIOD: 190,
			RIGHT: 39,
			SHIFT: 16,
			SPACE: 32,
			TAB: 9,
			UP: 38,
			WINDOWS: 91 // COMMAND
		},

		//scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
		silentScroll: function( ypos ) {
			ypos = ypos || 0;
			// prevent scrollstart and scrollstop events
			$.event.special.scrollstart.enabled = false;

			setTimeout(function() {
				window.scrollTo( 0, ypos );
				$(document).trigger( "silentscroll", { x: 0, y: ypos });
			},20);

			setTimeout(function() {
				$.event.special.scrollstart.enabled = true;
			}, 150 );
		}
	});

	//mobile version of data and removeData and hasData methods
	//ensures all data is set and retrieved using jQuery Mobile's data namespace
  $.fn.jqmData = function( prop, value ){
    return this.data( prop ? $.mobile.ns + prop : prop, value );
  };

  $.jqmData = function( elem, prop, value ){
    return $.data( elem, prop && $.mobile.ns + prop, value );
  };

  $.fn.jqmRemoveData = function( prop ){
    return this.removeData( $.mobile.ns + prop );
  };

  $.jqmRemoveData = function( elem, prop ){
    return $.removeData( elem, prop && $.mobile.ns + prop );
  };

  $.jqmHasData = function( elem, prop ){
    return $.hasData( elem, prop && $.mobile.ns + prop );
  };

	// Monkey-patching Sizzle to filter the :jqmData selector
	var oldFind = $.find;

	$.find = function( selector, context, ret, extra ) {
		selector = selector.replace(/:jqmData\(([^)]*)\)/g, "[data-" + ($.mobile.ns || "") + "$1]");

		return oldFind.call( this, selector, context, ret, extra );
	};

	$.extend( $.find, oldFind );

	$.find.matches = function( expr, set ) {
		return $.find( expr, null, null, set );
	};

	$.find.matchesSelector = function( node, expr ) {
		return $.find( expr, null, null, [node] ).length > 0;
	};
})( jQuery, this );
<commit_msg>followup to previous change, this time for dynamically appended meta viewport tags.<commit_after>/*!
 * jQuery Mobile v@VERSION
 * http://jquerymobile.com/
 *
 * Copyright 2010, jQuery Project
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 */

(function( $, window, undefined ) {

	//jQuery.mobile configurable options
	$.extend( $.mobile, {

		//namespace used framework-wide for data-attrs. Default is no namespace
		ns: "",

		//define the url parameter used for referencing widget-generated sub-pages.
		//Translates to to example.html&ui-page=subpageIdentifier
		//hash segment before &ui-page= is used to make Ajax request
		subPageUrlKey: "ui-page",

		//anchor links with a data-rel, or pages with a  data-role, that match these selectors will be untrackable in history
		//(no change in URL, not bookmarkable)
		nonHistorySelectors: "dialog",

		//class assigned to page currently in view, and during transitions
		activePageClass: "ui-page-active",

		//class used for "active" button state, from CSS framework
		activeBtnClass: "ui-btn-active",

		//automatically handle clicks and form submissions through Ajax, when same-domain
		ajaxEnabled: true,

		//automatically load and show pages based on location.hash
		hashListeningEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle link clicks through Ajax, when possible
		ajaxLinksEnabled: true,

		// TODO: deprecated - remove at 1.0
		//automatically handle form submissions through Ajax, when possible
		ajaxFormsEnabled: true,

		//set default transition - 'none' for no transitions
		defaultTransition: "slide",

		//show loading message during Ajax requests
		//if false, message will not appear, but loading classes will still be toggled on html el
		loadingMessage: "loading",

		//error response message - appears when an Ajax page request fails
		pageLoadErrorMessage: "Error Loading Page",

		//configure meta viewport tag's content attr:
		//note: this feature is deprecated in A4 in favor of adding
		//the meta viewport element directly in the markup
		metaViewportContent: "width=device-width, initial-scale=1",

		//support conditions that must be met in order to proceed
		//default enhanced qualifications are media query support OR IE 7+
		gradeA: function(){
			return $.support.mediaquery || $.mobile.browser.ie && $.mobile.browser.ie >= 7;
		},

		//TODO might be useful upstream in jquery itself ?
		keyCode: {
			ALT: 18,
			BACKSPACE: 8,
			CAPS_LOCK: 20,
			COMMA: 188,
			COMMAND: 91,
			COMMAND_LEFT: 91, // COMMAND
			COMMAND_RIGHT: 93,
			CONTROL: 17,
			DELETE: 46,
			DOWN: 40,
			END: 35,
			ENTER: 13,
			ESCAPE: 27,
			HOME: 36,
			INSERT: 45,
			LEFT: 37,
			MENU: 93, // COMMAND_RIGHT
			NUMPAD_ADD: 107,
			NUMPAD_DECIMAL: 110,
			NUMPAD_DIVIDE: 111,
			NUMPAD_ENTER: 108,
			NUMPAD_MULTIPLY: 106,
			NUMPAD_SUBTRACT: 109,
			PAGE_DOWN: 34,
			PAGE_UP: 33,
			PERIOD: 190,
			RIGHT: 39,
			SHIFT: 16,
			SPACE: 32,
			TAB: 9,
			UP: 38,
			WINDOWS: 91 // COMMAND
		},

		//scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
		silentScroll: function( ypos ) {
			ypos = ypos || 0;
			// prevent scrollstart and scrollstop events
			$.event.special.scrollstart.enabled = false;

			setTimeout(function() {
				window.scrollTo( 0, ypos );
				$(document).trigger( "silentscroll", { x: 0, y: ypos });
			},20);

			setTimeout(function() {
				$.event.special.scrollstart.enabled = true;
			}, 150 );
		}
	});

	//mobile version of data and removeData and hasData methods
	//ensures all data is set and retrieved using jQuery Mobile's data namespace
  $.fn.jqmData = function( prop, value ){
    return this.data( prop ? $.mobile.ns + prop : prop, value );
  };

  $.jqmData = function( elem, prop, value ){
    return $.data( elem, prop && $.mobile.ns + prop, value );
  };

  $.fn.jqmRemoveData = function( prop ){
    return this.removeData( $.mobile.ns + prop );
  };

  $.jqmRemoveData = function( elem, prop ){
    return $.removeData( elem, prop && $.mobile.ns + prop );
  };

  $.jqmHasData = function( elem, prop ){
    return $.hasData( elem, prop && $.mobile.ns + prop );
  };

	// Monkey-patching Sizzle to filter the :jqmData selector
	var oldFind = $.find;

	$.find = function( selector, context, ret, extra ) {
		selector = selector.replace(/:jqmData\(([^)]*)\)/g, "[data-" + ($.mobile.ns || "") + "$1]");

		return oldFind.call( this, selector, context, ret, extra );
	};

	$.extend( $.find, oldFind );

	$.find.matches = function( expr, set ) {
		return $.find( expr, null, null, set );
	};

	$.find.matchesSelector = function( node, expr ) {
		return $.find( expr, null, null, [node] ).length > 0;
	};
})( jQuery, this );
<|endoftext|>


<commit_before>'use strict' /* @flow */

import React from 'react'
import ReactCSS from 'reactcss'

import SliderSwatch from './SliderSwatch'

export class SliderSwatches extends ReactCSS.Component {

  constructor() {
    super()

    this.handleClick = this.handleClick.bind(this)
  }

  classes(): any {
    return {
      'default': {
        swatches: {
          marginRight: '-4px',
          marginTop: '20px',
        },
        swatch: {
          width: '19.65%',
          marginRight: '1px',
          float: 'left',
        },
        clear: {
          clear: 'both',
        },
      },
    }
  }

  handleClick(data: any) {
    this.props.onClick(data)
  }

  render(): any {
    return (

          <SliderSwatch {...this.props} offset=".80" active={ Math.round(this.props.hsl.l * 100) / 100 == .80 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } first />

          <SliderSwatch {...this.props} offset=".65" active={ Math.round(this.props.hsl.l * 100) / 100 == .65 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } />

          <SliderSwatch {...this.props} offset=".50" active={ Math.round(this.props.hsl.l * 100) / 100 == .50 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } />

          <SliderSwatch {...this.props} offset=".35" active={ Math.round(this.props.hsl.l * 100) / 100 == .35 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } />

          <SliderSwatch {...this.props} offset=".20" active={ Math.round(this.props.hsl.l * 100) / 100 == .20 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } last />

    )
  }

}

export default SliderSwatches
<commit_msg>Fix sliderSwatches styles breaking on small widths<commit_after>'use strict' /* @flow */

import React from 'react'
import ReactCSS from 'reactcss'

import SliderSwatch from './SliderSwatch'

export class SliderSwatches extends ReactCSS.Component {

  constructor() {
    super()

    this.handleClick = this.handleClick.bind(this)
  }

  classes(): any {
    return {
      'default': {
        swatches: {
          marginTop: '20px',
        },
        swatch: {
          boxSizing: 'border-box',
          width: '20%',
          paddingRight: '1px',
          float: 'left',
        },
        clear: {
          clear: 'both',
        },
      },
    }
  }

  handleClick(data: any) {
    this.props.onClick(data)
  }

  render(): any {
    return (

          <SliderSwatch {...this.props} offset=".80" active={ Math.round(this.props.hsl.l * 100) / 100 == .80 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } first />

          <SliderSwatch {...this.props} offset=".65" active={ Math.round(this.props.hsl.l * 100) / 100 == .65 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } />

          <SliderSwatch {...this.props} offset=".50" active={ Math.round(this.props.hsl.l * 100) / 100 == .50 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } />

          <SliderSwatch {...this.props} offset=".35" active={ Math.round(this.props.hsl.l * 100) / 100 == .35 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } />

          <SliderSwatch {...this.props} offset=".20" active={ Math.round(this.props.hsl.l * 100) / 100 == .20 && Math.round(this.props.hsl.s * 100) / 100 == .50 } onClick={ this.handleClick } last />

    )
  }

}

export default SliderSwatches
<|endoftext|>


<commit_before>(function($) {
    $.fn.placekitten = function() {
       this.find('img').each(function(i,img) {
           var w = img.width;
           var h = img.height;
           if (w && h) {
               var src =  'http://placekitten.com/'+w+'/'+h;
               img.src = src;
           }
       });
    };
})(jQuery);
<commit_msg>Added replacement of css background images on anchors and divs<commit_after>(function($) {
    $.fn.placekitten = function() {
		    this.find('img,a,div').each( function(i,element) {
    		    switch(element.nodeName) {
        		    case 'IMG':
            		    var w=element.width;
                    var h=element.height;

                    if(w&&h) {
                	    var src='http://placekitten.com/'+w+'/'+h;
                      element.src=src;
                  	}
                    break;
								case 'A':
                case 'DIV':
                		var background = $(element).css("background-image");
                    if(background.indexOf('url(') > -1) {
                    		var w = $(element).width();
                        var h = $(element).height();
                        $(element).css("background-image", "url(http://placekitten.com/"+w+"/"+h+")");
                    }
                    break;
                }
            });
		};
})(jQuery);
<|endoftext|>


<commit_before>import React from "react";
import { infoPanelStyles } from "../../../globalStyles";
import { prettyString } from "../../../util/stringHelpers";
import { numericToCalendar } from "../../../util/dateHelpers";
import { getTipColorAttribute } from "../../../util/colorHelpers";

const infoLineJSX = (item, value) => (

      {item + " "}

      {value}

);

const infoBlockJSX = (item, values) => (

      {item}

    {values.map((k) => (

        {k}

    ))}

);

const getBranchDivJSX = (d) =>

{infoLineJSX("Divergence:", prettyString(d.attr.div.toExponential(3)))}
;

const getBranchTimeJSX = (d, temporalConfidence) => {
  const date = d.attr.date || numericToCalendar(d.attr.num_date);
  let dateRange = false;
  if (temporalConfidence) {
    dateRange = [
      numericToCalendar(d.attr.num_date_confidence[0]),
      numericToCalendar(d.attr.num_date_confidence[1])
    ];
  }
  if (dateRange && dateRange[0] !== dateRange[1]) {
    return (

        {infoLineJSX("Inferred Date:", date)}

        {infoLineJSX("Date Confidence Interval:", `(${dateRange[0]}, ${dateRange[1]})`)}

    );
  }
  return (
{infoLineJSX("Date:", date)}
);
};

/**
 * Display information about the colorBy, potentially in a table with confidences
 * @param  {node} d branch node currently highlighted
 * @param  {bool} colorByConfidence should these (colorBy conf) be displayed, if applicable?
 * @param  {string} colorBy must be a key of d.attr
 * @return {JSX} to be displayed
 */
const displayColorBy = (d, distanceMeasure, temporalConfidence, colorByConfidence, colorBy) => {
  if (colorBy.slice(0, 2) === "gt") {
    return null; /* muts ahave already been displayed */
  }
  if (colorBy === "num_date") {
    /* if colorBy is date and branch lengths are divergence we should still show node date */
    return (colorBy !== distanceMeasure) ? getBranchTimeJSX(d, temporalConfidence) : null;
  }
  if (colorByConfidence === true) {
    const lkey = colorBy + "_confidence";
    if (Object.keys(d.attr).indexOf(lkey) === -1) {
      console.error("Error - couldn't find confidence vals for ", lkey);
      return null;
    }
    const vals = Object.keys(d.attr[lkey])
      .sort((a, b) => d.attr[lkey][a] > d.attr[lkey][b] ? -1 : 1)
      .slice(0, 4)
      .map((v) => `${prettyString(v)} (${(100 * d.attr[lkey][v]).toFixed(0)}%)`);
    return infoBlockJSX(`${prettyString(colorBy)} (confidence):`, vals);
  }
  return infoLineJSX(prettyString(colorBy), prettyString(d.attr[colorBy]));
};

/**
 * Currently not used - implement when augur outputs frequencies
 * @param  {node} d branch node currently highlighted
 * @return {JSX} to be displayed (or null)
 */
// const getFrequenciesJSX = (d) => {
//   if (d.frequency !== undefined) {
//     const disp = "Frequency: " + (100 * d.frequency).toFixed(1) + "%";
//     return (
{disp}
);
//   }
//   return null;
// };

/**
 * Display AA / NT mutations in JSX
 * @param  {node} d branch node currently highlighted
 * @param  {string} mutType "AA" or "nuc"
 * @return {JSX} to be displayed (or null)
 */
const getMutationsJSX = (d, mutType) => {
  /* mutations are stored at:
  NUCLEOTIDE: d.muts = list of strings
  AMINO ACID: d.aa_muts = dict of proteins -> list of strings
  */
  if (mutType === "nuc") {
    if (typeof d.muts !== "undefined" && d.muts.length) {
      const nDisplay = 9; // max number of mutations to display
      const nGapDisp = 4; // max number of gaps/Ns to display

      // gather muts with N/-
      const ngaps = d.muts.filter((mut) => {
        return mut.slice(-1) === "N" || mut.slice(-1) === "-"
          || mut.slice(0, 1) === "N" || mut.slice(0, 1) === "-";
      });
      const gapLen = ngaps.length; // number of mutations that exist with N/-

      // gather muts without N/-
      const nucs = d.muts.filter((mut) => {
        return mut.slice(-1) !== "N" && mut.slice(-1) !== "-"
          && mut.slice(0, 1) !== "N" && mut.slice(0, 1) !== "-";
      });
      const nucLen = nucs.length; // number of mutations that exist without N/-

      let m = nucs.slice(0, Math.min(nDisplay, nucLen)).join(", ");
      m += nucLen > nDisplay ? " + " + (nucLen - nDisplay) + " more" : "";
      let mGap = ngaps.slice(0, Math.min(nGapDisp, gapLen)).join(", ");
      mGap += gapLen > nGapDisp ? " + " + (gapLen - nGapDisp) + " more" : "";

      if (gapLen === 0) {
        return infoLineJSX("Nucleotide mutations:", m);
      }
      if (nucLen === 0) {
        return infoLineJSX("Gap/N mutations:", mGap);
      }
      return (

          {infoLineJSX("Nucleotide mutations:", m)}

          {infoLineJSX("Gap/N mutations:", mGap)}

      );

    }
    return infoLineJSX("No nucleotide mutations", "");
  } else if (typeof d.aa_muts !== "undefined") {
    /* calculate counts */
    const prots = Object.keys(d.aa_muts);
    const counts = {};
    for (const prot of prots) {
      counts[prot] = d.aa_muts[prot].length;
    }
    /* are there any AA mutations? */
    if (prots.map((k) => counts[k]).reduce((a, b) => a + b, 0)) {
      const nDisplay = 3; // number of mutations to display per protein
      const nProtsToDisplay = 7; // max number of proteins to display
      let protsSeen = 0;
      const m = [];
      prots.forEach((prot) => {
        if (counts[prot] && protsSeen < nProtsToDisplay) {
          let x = prot + ":\u00A0\u00A0" + d.aa_muts[prot].slice(0, Math.min(nDisplay, counts[prot])).join(", ");
          if (counts[prot] > nDisplay) {
            x += " + " + (counts[prot] - nDisplay) + " more";
          }
          m.push(x);
          protsSeen++;
          if (protsSeen === nProtsToDisplay) {
            m.push(`(protein mutations truncated)`);
          }
        }
      });
      return infoBlockJSX("AA mutations:", m);
    }
    return infoLineJSX("No amino acid mutations", "");
  }
  console.warn("Error parsing mutations for branch", d.strain);
  return null;
};

const getBranchDescendents = (n) => {
  if (n.fullTipCount === 1) {
    return {infoLineJSX("Branch leading to", n.strain)}
;
  }
  return {infoLineJSX("Number of descendants:", n.fullTipCount)}
;
};

const getPanelStyling = (d, panelDims) => {
  const xOffset = 10;
  const yOffset = 10;
  const width = 200;

  /* this adjusts the x-axis for the right tree in dual tree view */
  const xPos = d.that.params.orientation[0] === -1 ?
    panelDims.width / 2 + panelDims.spaceBetweenTrees + d.xTip :
    d.xTip;
  const yPos = d.yTip;
  const styles = {
    container: {
      position: "absolute",
      width,
      padding: "10px",
      borderRadius: 10,
      zIndex: 1000,
      pointerEvents: "none",
      fontFamily: infoPanelStyles.panel.fontFamily,
      fontSize: 14,
      lineHeight: 1,
      fontWeight: infoPanelStyles.panel.fontWeight,
      color: infoPanelStyles.panel.color,
      backgroundColor: infoPanelStyles.panel.backgroundColor,
      wordWrap: "break-word",
      wordBreak: "break-word"
    }
  };
  if (xPos < panelDims.width * 0.6) {
    styles.container.left = xPos + xOffset;
  } else {
    styles.container.right = panelDims.width - xPos + xOffset;
  }
  if (yPos < panelDims.height * 0.55) {
    styles.container.top = yPos + 4 * yOffset;
  } else {
    styles.container.bottom = panelDims.height - yPos + yOffset;
  }
  return styles;
};

const tipDisplayColorByInfo = (d, colorBy, distanceMeasure, temporalConfidence, mutType, colorScale) => {
  if (colorBy === "num_date") {
    if (distanceMeasure === "num_date") return null;
    return getBranchTimeJSX(d.n, temporalConfidence);
  }
  if (colorBy.slice(0, 2) === "gt") {
    const key = mutType === "nuc" ?
      "Nucleotide at pos " + colorBy.replace("gt-", "").replace("nuc_", "") :
      "Amino Acid at " + colorBy.replace("gt-", "").replace("_", " site ");
    const state = getTipColorAttribute(d.n, colorScale);
    return infoLineJSX(key + ":", state);
  }
  return infoLineJSX(prettyString(colorBy) + ":", prettyString(d.n.attr[colorBy]));
};

const displayVaccineInfo = (d) => {
  if (d.n.vaccineDate) {
    return (

        {infoLineJSX("Vaccine strain:", d.n.vaccineDate)}

    );
  }
  return null;
};

/* the actual component - a pure function, so we can return early if needed */
const HoverInfoPanel = ({mutType, temporalConfidence, distanceMeasure,
  hovered, colorBy, colorByConfidence, colorScale, panelDims}) => {

  if (!hovered) return null;

  const tip = hovered.type === ".tip";
  const d = hovered.d;
  const styles = getPanelStyling(d, panelDims);
  let inner;
  if (tip) {
    inner = (

        {displayVaccineInfo(d)}
        {tipDisplayColorByInfo(d, colorBy, distanceMeasure, temporalConfidence, mutType, colorScale)}
        {distanceMeasure === "div" ? getBranchDivJSX(d.n) : getBranchTimeJSX(d.n, temporalConfidence)}

    );
  } else {
    inner = (

        {getBranchDescendents(d.n)}
        {/* getFrequenciesJSX(d.n, mutType) */}
        {getMutationsJSX(d.n, mutType)}
        {distanceMeasure === "div" ? getBranchDivJSX(d.n) : getBranchTimeJSX(d.n, temporalConfidence)}
        {displayColorBy(d.n, distanceMeasure, temporalConfidence, colorByConfidence, colorBy)}

    );
  }
  return (

          {tip ? d.n.strain : null}

        {inner}

          {tip ? "Click on tip to display more info" : "Click to zoom into clade"}

  );
};

export default HoverInfoPanel;
<commit_msg>Allow nodes with missing confidence values<commit_after>import React from "react";
import { infoPanelStyles } from "../../../globalStyles";
import { prettyString } from "../../../util/stringHelpers";
import { numericToCalendar } from "../../../util/dateHelpers";
import { getTipColorAttribute } from "../../../util/colorHelpers";

const infoLineJSX = (item, value) => (

      {item + " "}

      {value}

);

const infoBlockJSX = (item, values) => (

      {item}

    {values.map((k) => (

        {k}

    ))}

);

const getBranchDivJSX = (d) =>

{infoLineJSX("Divergence:", prettyString(d.attr.div.toExponential(3)))}
;

const getBranchTimeJSX = (d, temporalConfidence) => {
  const date = d.attr.date || numericToCalendar(d.attr.num_date);
  let dateRange = false;
  if (temporalConfidence && d.attr.num_date_confidence) {
    dateRange = [
      numericToCalendar(d.attr.num_date_confidence[0]),
      numericToCalendar(d.attr.num_date_confidence[1])
    ];
  }
  if (dateRange && dateRange[0] !== dateRange[1]) {
    return (

        {infoLineJSX("Inferred Date:", date)}

        {infoLineJSX("Date Confidence Interval:", `(${dateRange[0]}, ${dateRange[1]})`)}

    );
  }
  return (
{infoLineJSX("Date:", date)}
);
};

/**
 * Display information about the colorBy, potentially in a table with confidences
 * @param  {node} d branch node currently highlighted
 * @param  {bool} colorByConfidence should these (colorBy conf) be displayed, if applicable?
 * @param  {string} colorBy must be a key of d.attr
 * @return {JSX} to be displayed
 */
const displayColorBy = (d, distanceMeasure, temporalConfidence, colorByConfidence, colorBy) => {
  if (colorBy.slice(0, 2) === "gt") {
    return null; /* muts ahave already been displayed */
  }
  if (colorBy === "num_date") {
    /* if colorBy is date and branch lengths are divergence we should still show node date */
    return (colorBy !== distanceMeasure) ? getBranchTimeJSX(d, temporalConfidence) : null;
  }
  if (colorByConfidence === true) {
    const lkey = colorBy + "_confidence";
    if (Object.keys(d.attr).indexOf(lkey) === -1) {
      console.error("Error - couldn't find confidence vals for ", lkey);
      return null;
    }
    const vals = Object.keys(d.attr[lkey])
      .sort((a, b) => d.attr[lkey][a] > d.attr[lkey][b] ? -1 : 1)
      .slice(0, 4)
      .map((v) => `${prettyString(v)} (${(100 * d.attr[lkey][v]).toFixed(0)}%)`);
    return infoBlockJSX(`${prettyString(colorBy)} (confidence):`, vals);
  }
  return infoLineJSX(prettyString(colorBy), prettyString(d.attr[colorBy]));
};

/**
 * Currently not used - implement when augur outputs frequencies
 * @param  {node} d branch node currently highlighted
 * @return {JSX} to be displayed (or null)
 */
// const getFrequenciesJSX = (d) => {
//   if (d.frequency !== undefined) {
//     const disp = "Frequency: " + (100 * d.frequency).toFixed(1) + "%";
//     return (
{disp}
);
//   }
//   return null;
// };

/**
 * Display AA / NT mutations in JSX
 * @param  {node} d branch node currently highlighted
 * @param  {string} mutType "AA" or "nuc"
 * @return {JSX} to be displayed (or null)
 */
const getMutationsJSX = (d, mutType) => {
  /* mutations are stored at:
  NUCLEOTIDE: d.muts = list of strings
  AMINO ACID: d.aa_muts = dict of proteins -> list of strings
  */
  if (mutType === "nuc") {
    if (typeof d.muts !== "undefined" && d.muts.length) {
      const nDisplay = 9; // max number of mutations to display
      const nGapDisp = 4; // max number of gaps/Ns to display

      // gather muts with N/-
      const ngaps = d.muts.filter((mut) => {
        return mut.slice(-1) === "N" || mut.slice(-1) === "-"
          || mut.slice(0, 1) === "N" || mut.slice(0, 1) === "-";
      });
      const gapLen = ngaps.length; // number of mutations that exist with N/-

      // gather muts without N/-
      const nucs = d.muts.filter((mut) => {
        return mut.slice(-1) !== "N" && mut.slice(-1) !== "-"
          && mut.slice(0, 1) !== "N" && mut.slice(0, 1) !== "-";
      });
      const nucLen = nucs.length; // number of mutations that exist without N/-

      let m = nucs.slice(0, Math.min(nDisplay, nucLen)).join(", ");
      m += nucLen > nDisplay ? " + " + (nucLen - nDisplay) + " more" : "";
      let mGap = ngaps.slice(0, Math.min(nGapDisp, gapLen)).join(", ");
      mGap += gapLen > nGapDisp ? " + " + (gapLen - nGapDisp) + " more" : "";

      if (gapLen === 0) {
        return infoLineJSX("Nucleotide mutations:", m);
      }
      if (nucLen === 0) {
        return infoLineJSX("Gap/N mutations:", mGap);
      }
      return (

          {infoLineJSX("Nucleotide mutations:", m)}

          {infoLineJSX("Gap/N mutations:", mGap)}

      );

    }
    return infoLineJSX("No nucleotide mutations", "");
  } else if (typeof d.aa_muts !== "undefined") {
    /* calculate counts */
    const prots = Object.keys(d.aa_muts);
    const counts = {};
    for (const prot of prots) {
      counts[prot] = d.aa_muts[prot].length;
    }
    /* are there any AA mutations? */
    if (prots.map((k) => counts[k]).reduce((a, b) => a + b, 0)) {
      const nDisplay = 3; // number of mutations to display per protein
      const nProtsToDisplay = 7; // max number of proteins to display
      let protsSeen = 0;
      const m = [];
      prots.forEach((prot) => {
        if (counts[prot] && protsSeen < nProtsToDisplay) {
          let x = prot + ":\u00A0\u00A0" + d.aa_muts[prot].slice(0, Math.min(nDisplay, counts[prot])).join(", ");
          if (counts[prot] > nDisplay) {
            x += " + " + (counts[prot] - nDisplay) + " more";
          }
          m.push(x);
          protsSeen++;
          if (protsSeen === nProtsToDisplay) {
            m.push(`(protein mutations truncated)`);
          }
        }
      });
      return infoBlockJSX("AA mutations:", m);
    }
    return infoLineJSX("No amino acid mutations", "");
  }
  console.warn("Error parsing mutations for branch", d.strain);
  return null;
};

const getBranchDescendents = (n) => {
  if (n.fullTipCount === 1) {
    return {infoLineJSX("Branch leading to", n.strain)}
;
  }
  return {infoLineJSX("Number of descendants:", n.fullTipCount)}
;
};

const getPanelStyling = (d, panelDims) => {
  const xOffset = 10;
  const yOffset = 10;
  const width = 200;

  /* this adjusts the x-axis for the right tree in dual tree view */
  const xPos = d.that.params.orientation[0] === -1 ?
    panelDims.width / 2 + panelDims.spaceBetweenTrees + d.xTip :
    d.xTip;
  const yPos = d.yTip;
  const styles = {
    container: {
      position: "absolute",
      width,
      padding: "10px",
      borderRadius: 10,
      zIndex: 1000,
      pointerEvents: "none",
      fontFamily: infoPanelStyles.panel.fontFamily,
      fontSize: 14,
      lineHeight: 1,
      fontWeight: infoPanelStyles.panel.fontWeight,
      color: infoPanelStyles.panel.color,
      backgroundColor: infoPanelStyles.panel.backgroundColor,
      wordWrap: "break-word",
      wordBreak: "break-word"
    }
  };
  if (xPos < panelDims.width * 0.6) {
    styles.container.left = xPos + xOffset;
  } else {
    styles.container.right = panelDims.width - xPos + xOffset;
  }
  if (yPos < panelDims.height * 0.55) {
    styles.container.top = yPos + 4 * yOffset;
  } else {
    styles.container.bottom = panelDims.height - yPos + yOffset;
  }
  return styles;
};

const tipDisplayColorByInfo = (d, colorBy, distanceMeasure, temporalConfidence, mutType, colorScale) => {
  if (colorBy === "num_date") {
    if (distanceMeasure === "num_date") return null;
    return getBranchTimeJSX(d.n, temporalConfidence);
  }
  if (colorBy.slice(0, 2) === "gt") {
    const key = mutType === "nuc" ?
      "Nucleotide at pos " + colorBy.replace("gt-", "").replace("nuc_", "") :
      "Amino Acid at " + colorBy.replace("gt-", "").replace("_", " site ");
    const state = getTipColorAttribute(d.n, colorScale);
    return infoLineJSX(key + ":", state);
  }
  return infoLineJSX(prettyString(colorBy) + ":", prettyString(d.n.attr[colorBy]));
};

const displayVaccineInfo = (d) => {
  if (d.n.vaccineDate) {
    return (

        {infoLineJSX("Vaccine strain:", d.n.vaccineDate)}

    );
  }
  return null;
};

/* the actual component - a pure function, so we can return early if needed */
const HoverInfoPanel = ({mutType, temporalConfidence, distanceMeasure,
  hovered, colorBy, colorByConfidence, colorScale, panelDims}) => {

  if (!hovered) return null;

  const tip = hovered.type === ".tip";
  const d = hovered.d;
  const styles = getPanelStyling(d, panelDims);
  let inner;
  if (tip) {
    inner = (

        {displayVaccineInfo(d)}
        {tipDisplayColorByInfo(d, colorBy, distanceMeasure, temporalConfidence, mutType, colorScale)}
        {distanceMeasure === "div" ? getBranchDivJSX(d.n) : getBranchTimeJSX(d.n, temporalConfidence)}

    );
  } else {
    inner = (

        {getBranchDescendents(d.n)}
        {/* getFrequenciesJSX(d.n, mutType) */}
        {getMutationsJSX(d.n, mutType)}
        {distanceMeasure === "div" ? getBranchDivJSX(d.n) : getBranchTimeJSX(d.n, temporalConfidence)}
        {displayColorBy(d.n, distanceMeasure, temporalConfidence, colorByConfidence, colorBy)}

    );
  }
  return (

          {tip ? d.n.strain : null}

        {inner}

          {tip ? "Click on tip to display more info" : "Click to zoom into clade"}

  );
};

export default HoverInfoPanel;
<|endoftext|>


<commit_before>var Channel = function(options) {
  this.options = options || {};

  this.url = this.options.host || 'ws://' + document.location.host + '/websocket';
  this.connected = false;
};

Channel.prototype = {
  connect: function() {
    this.socket = new WebSocket(this.url);

    this.socket.onopen    = this.onOpen.bind(this);
    this.socket.onclose   = this.onClose.bind(this);
    this.socket.onmessage = this.onMessage.bind(this);
    this.socket.onerror   = this.onError.bind(this);
  },

  disconnect: function() {
    this.socket.close();
  },

  send: function(message) {
    console.log(message);
    this.socket.send(JSON.stringify(message));
  },

  onOpen: function() {
    this.connected = true;
  },

  onClose: function() {
    console.log('Close', arguments);
  },

  onError: function() {
    console.log('Error', arguments);
  },

  onMessage: function(message) {
    response = JSON.parse(message.data);
    this.options.onMessage(response);
  }
};

var MetaModel = function(application, storage) {
  this.application = application;
  this.clients   = ko.observable(0);
  this.requests  = ko.observable(0);
  this.min_time  = ko.observable(0);
  this.max_time  = ko.observable(0);
  this.mean_time = ko.observable(0);

  this.min_time.subscribe(function(value) {
    storage.min.push(value);
  });
  this.max_time.subscribe(function(value) {
    storage.max.push(value);
  });
  this.mean_time.subscribe(function(value) {
    storage.arithmetic_mean.push(value);
  });

};
MetaModel.prototype = {
  reset: function() {
    this.clients(0);
    this.requests(0);
    this.min_time(0);
    this.max_time(0);
    this.mean_time(0);
  }
};

var Chart = function(storage) {
  this.storage = storage;
  this.context = cubism.context()
      .serverDelay(5000)
      .clientDelay(5000)
      .step(1e3)
      .size(960);

  this.min  = this.diagram("Min",  "min");
  this.max  = this.diagram("Max",  "max");
  this.mean = this.diagram("Mean", "arithmetic_mean");
};

Chart.prototype = {
  diagram: function(name, key) {
    var storage = this.storage;
    return this.context.metric(function(start, stop, step, callback) {
      start = +start;
      stop  = +stop;

      if(storage[key]) {
        storage[key] = storage[key].slice((start - stop) / step);
        callback(null, storage[key]);
      }
    }, name);
  },

  render: function() {
    d3.select(".diagram").call(function(div) {
      div.append("div")
         .attr("class", "axis")
         .call(this.context.axis().orient("top"));

      div.selectAll(".horizon")
         .data([this.min, this.max, this.mean])
         .enter()
         .append("div")
         .attr("class", "horizon")
         .call(this.context.horizon().extent([-20, 20]));

      div.append("div")
         .attr("class", "rule")
         .call(this.context.rule());
    }.bind(this));
  }
};

var Application = function(storage) {
  this.meta = new MetaModel(this, storage);

  this.channel = new Channel({
    onMessage: this.update.bind(this)
  });
  this.channel.connect();

  this.chart = new Chart(storage);
  this.chart.render();
};

Application.prototype = {
  update: function(message) {
    if(message.requests) {
      this.meta.requests(message.requests)
    }

    if(message.clients) {
      this.meta.clients(message.clients)
    }

    if(message.request_time) {
      this.meta.min_time(message.request_time.min / 1000)
      this.meta.max_time(message.request_time.max / 1000)
      this.meta.mean_time(message.request_time.arithmetic_mean / 1000)
    }
  },
  boom: function(){
    this.application.channel.send({ action: 'add_worker' });
  }
};

$(function(){
  var storage = {
    min: [],
    max: [],
    arithmetic_mean: []
  };

  var application = new Application(storage);
  ko.applyBindings(application);
});
<commit_msg>Added numeric observer extender<commit_after>ko.extenders.numeric = function(target, precision) {
    var result = ko.computed({
        read: target,
        write: function(newValue) {
            var current = target(),
                roundingMultiplier = Math.pow(10, precision),
                newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
                valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;

            if (valueToWrite !== current) {
                target(valueToWrite);
            } else {
                if (newValue !== current) {
                    target.notifySubscribers(valueToWrite);
                }
            }
        }
    });
    result(target());
    return result;
};

var Channel = function(options) {
  this.options = options || {};

  this.url = this.options.host || 'ws://' + document.location.host + '/websocket';
  this.connected = false;
};

Channel.prototype = {
  connect: function() {
    this.socket = new WebSocket(this.url);

    this.socket.onopen    = this.onOpen.bind(this);
    this.socket.onclose   = this.onClose.bind(this);
    this.socket.onmessage = this.onMessage.bind(this);
    this.socket.onerror   = this.onError.bind(this);
  },

  disconnect: function() {
    this.socket.close();
  },

  send: function(message) {
    console.log(message);
    this.socket.send(JSON.stringify(message));
  },

  onOpen: function() {
    this.connected = true;
  },

  onClose: function() {
    console.log('Close', arguments);
  },

  onError: function() {
    console.log('Error', arguments);
  },

  onMessage: function(message) {
    response = JSON.parse(message.data);
    this.options.onMessage(response);
  }
};

var MetaModel = function(application, storage) {
  this.application = application;
  this.clients   = ko.observable(0);
  this.requests  = ko.observable(0);
  this.min_time  = ko.observable(0).extend({ numeric: 2 });
  this.max_time  = ko.observable(0).extend({ numeric: 2 });
  this.mean_time = ko.observable(0).extend({ numeric: 2 });

  this.min_time.subscribe(function(value) {
    storage.min.push(value);
  });
  this.max_time.subscribe(function(value) {
    storage.max.push(value);
  });
  this.mean_time.subscribe(function(value) {
    storage.arithmetic_mean.push(value);
  });

};
MetaModel.prototype = {
  reset: function() {
    this.clients(0);
    this.requests(0);
    this.min_time(0);
    this.max_time(0);
    this.mean_time(0);
  }
};

var Chart = function(storage) {
  this.storage = storage;
  this.context = cubism.context()
      .serverDelay(5000)
      .clientDelay(5000)
      .step(1e3)
      .size(960);

  this.min  = this.diagram("Min",  "min");
  this.max  = this.diagram("Max",  "max");
  this.mean = this.diagram("Mean", "arithmetic_mean");
};

Chart.prototype = {
  diagram: function(name, key) {
    var storage = this.storage;
    return this.context.metric(function(start, stop, step, callback) {
      start = +start;
      stop  = +stop;

      if(storage[key]) {
        storage[key] = storage[key].slice((start - stop) / step);
        callback(null, storage[key]);
      }
    }, name);
  },

  render: function() {
    d3.select(".diagram").call(function(div) {
      div.append("div")
         .attr("class", "axis")
         .call(this.context.axis().orient("top"));

      div.selectAll(".horizon")
         .data([this.min, this.max, this.mean])
         .enter()
         .append("div")
         .attr("class", "horizon")
         .call(this.context.horizon().extent([-20, 20]));

      div.append("div")
         .attr("class", "rule")
         .call(this.context.rule());
    }.bind(this));
  }
};

var Application = function(storage) {
  this.meta = new MetaModel(this, storage);

  this.channel = new Channel({
    onMessage: this.update.bind(this)
  });
  this.channel.connect();

  this.chart = new Chart(storage);
  this.chart.render();
};

Application.prototype = {
  update: function(message) {
    if(message.requests) {
      this.meta.requests(message.requests)
    }

    if(message.clients) {
      this.meta.clients(message.clients)
    }

    if(message.request_time) {
      this.meta.min_time(message.request_time.min / 1000)
      this.meta.max_time(message.request_time.max / 1000)
      this.meta.mean_time(message.request_time.arithmetic_mean / 1000)
    }
  },
  boom: function(){
    this.application.channel.send({ action: 'add_worker' });
  }
};

$(function(){
  var storage = {
    min: [],
    max: [],
    arithmetic_mean: []
  };

  var application = new Application(storage);
  ko.applyBindings(application);
});
<|endoftext|>