<commit_before>#!/usr/bin/env node

/*!
 * random-cli
 * node.js Command Line Interface to select randomly from given list or range
 * https://github.com/juanbrujo/random-cli
 * 2015 Jorge Epuñan | @csslab
 * License: MIT
 */

var program = require('commander');
var crypto 	= require("crypto");
var path    = require('path');
var pkg     = require(path.join(__dirname, '../package.json'));

function range(val) {
  var firstNum = parseInt(val.split('..')[0]);
  var lastNum = parseInt(val.split('..')[1]);

  return Math.floor( Math.random() * ( lastNum - firstNum + 1 ) + firstNum );
}

function list(val) {
  var newList = [];
  var values = val.split(',');

  values.forEach(function(l){
  	newList.push(l);
  });

  return newList[Math.floor(Math.random() * newList.length)]
}

function password(val) {
	var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP1234567890";
  var result = "";
  for (var x = 0; x < val; x++) {
      var i = Math.floor(Math.random() * chars.length);
      result += chars.charAt(i);
  }

  return result;
}

program
  .version(pkg.version)
  .usage('[options] <file ...>')
  .option('-r, --range <a>..<b>', 'A range', range)
  .option('-l, --list <items>', 'A list', list)
  .option('-p, --password <length>', 'Length', password)
  .parse(process.argv);

if(program.range) {
	console.log(' ✔  Random from range: %j', program.range);
}

if(program.list) {
	console.log(' ✔  Random from list: %j', program.list);
}

if(program.password) {
	console.log(' ✔  Random password: %j', program.password);
}

<commit_msg>Multiple results<commit_after>#!/usr/bin/env node

/*!
* random-cli
* node.js Command Line Interface to select randomly from given list or range
* https://github.com/juanbrujo/random-cli
* 2015 Jorge Epuñan | @csslab
* License: MIT
*/

var program = require('commander');
var crypto 	= require("crypto");
var path    = require('path');
var pkg     = require(path.join(__dirname, '../package.json'));
var howMany  = 1;

function range(val) {
  var firstNum = parseInt(val.split('..')[0]);
  var lastNum = parseInt(val.split('..')[1]);

  return Math.floor( Math.random() * ( lastNum - firstNum + 1 ) + firstNum );
}

function list(val) {
  var newList = [];
  var values = val.split(',');

  values.forEach(function(l){
    newList.push(l);
  });

  return newList[Math.floor(Math.random() * newList.length)];
}

function amount(val) {
  howMany = val;
}

function password(val) {
  var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP1234567890";
  var result = "";
  for (var x = 0; x < val; x++) {
    var i = Math.floor(Math.random() * chars.length);
    result += chars.charAt(i);
  }

  return result;
}

program
.version(pkg.version)
.usage('[options] <file ...>')
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-p, --password <length>', 'Length', password)
.option('-a, --amount <amount>', 'Amount of Items', amount);

var values = { range: [], list: [], password: [] };

for(var i = 1; i <= howMany; i++) {
  program.parse(process.argv);

  if(program.range) { values.range.push(program.range); }
  if(program.list) { values.list.push(program.list); }
  if(program.password) { values.password.push(program.password); }
}

if(Boolean(values.range.length)) {
  console.log(' ✔  Random from range: %j', values.range);
}

if(Boolean(values.list.length)) {
  console.log(' ✔  Random from list: %j', values.list);
}

if(Boolean(values.password.length)) {
  console.log(' ✔  Random passwords: %j', values.password);
}
<|endoftext|>


<commit_before>/*
 * Given an array of fromCollective Ids(field FromCollectiveId from Transactions model),
 * This script creates refund transactions.
 * We also mark all those transactions Orders
 * from status 'ACTIVE' to status 'CANCELLED'
 *  1) Refund transactions
 *  2) Mark Orders as cancelled
 *  3) Get transactions ORders and Mark the order Subscriptions of orders as isActive False and deactivedAt now()
 */
import Promise from 'bluebird';
import debug from 'debug';
import models from '../server/models';
import * as libPayments from '../server/lib/payments';

const fromCollectiveIds = process.env.FROM_COLLECTIVE_IDS || [23461];
const debugRefund = debug('refundTransactions');

async function refundTransaction(transaction) {
  // find the kind of payment method type
  const paymentMethod = libPayments.findPaymentMethodProvider(transaction.PaymentMethod);
  // look for the Stripe Connected Account
  const stripeAccounts = await models.ConnectedAccount.findAll({
    where: {
      CollectiveId: transaction.HostCollectiveId,
      service: 'stripe',
    },
  });
  debugRefund(`stripeAccounts: ${JSON.stringify(stripeAccounts, null, 2)}`);
  // If it's credit card then we will refund
  if (transaction.PaymentMethod && transaction.PaymentMethod.type === 'creditcard') {
    debugRefund('refunding transaction.', transaction);
    try {
      // try to do both stripe and database refunds
      const refundTransactions = await paymentMethod.refundTransaction(transaction, { id: 18520 });
      debugRefund(`Stripe refundTransactions: ${JSON.stringify(refundTransactions, null, 2)}`);
    } catch (error) {
      // Error means stripe has already refunded
      debugRefund(`STRIPE error meaning it was already refund...trying to refund only on our database:`);
      try {
        const refundTransactions = await paymentMethod.refundTransactionOnlyInDatabase(transaction, { id: 18520 });
        debugRefund(`Database ONLY refundTransactions: ${JSON.stringify(refundTransactions, null, 2)}`);
      } catch (error) {
        // throwing error on purpose to stop everything if something unexpected happens..
        console.error(error);
        throw error;
      }
    }
  }
  const order = transaction.Order;
  // We mark then Active Orders as CANCELLED and deactivated their subscriptions
  if (order && order.status === 'ACTIVE' && order.SubscriptionId) {
    order.status = 'CANCELLED';
    await order.save();
    debugRefund('updating subscription to be deactived');

    // if the order has a subscription, mark it with isActive as false and deactivedAt now.
    if (order.SubscriptionId) {
      const subscription = await models.Subscription.findById(order.SubscriptionId);
      subscription.isActive = false;
      subscription.deactivatedAt = new Date();
      await subscription.save();
    }
  }
  return models.Transaction.findById(transaction.id);
}

async function run() {
  const transactions = await models.Transaction.findAll({
    where: {
      FromCollectiveId: fromCollectiveIds,
      type: 'CREDIT',
      RefundTransactionId: null,
    },
    include: [models.Order, models.PaymentMethod],
  });
  try {
    const mapResult = await Promise.map(transactions, refundTransaction);
    debugRefund(`Script finished successfully,
      mapResult(tip: result transactions need to have RefundTransactionId set):
      ${JSON.stringify(mapResult, null, 2)}`);
    process.exit(0);
  } catch (error) {
    debugRefund('Error executing script', error);
    process.exit(1);
  }
}

run();
<commit_msg>feat(scripts): improving logging on refund transactions script<commit_after>/*
 * Given an array of fromCollective Ids(field FromCollectiveId from Transactions model),
 * This script creates refund transactions.
 * We also mark all those transactions Orders
 * from status 'ACTIVE' to status 'CANCELLED'
 *  1) Refund transactions
 *  2) Mark Orders as cancelled
 *  3) Get transactions ORders and Mark the order Subscriptions of orders as isActive False and deactivedAt now()
 */
import Promise from 'bluebird';
import debug from 'debug';
import models from '../server/models';
import * as libPayments from '../server/lib/payments';

const fromCollectiveIds = process.env.FROM_COLLECTIVE_IDS || [23461];
const debugRefund = debug('refundTransactions');

async function refundTransaction(transaction) {
  // find the kind of payment method type
  const paymentMethod = libPayments.findPaymentMethodProvider(transaction.PaymentMethod);
  // look for the Stripe Connected Account
  const stripeAccounts = await models.ConnectedAccount.findAll({
    where: {
      CollectiveId: transaction.HostCollectiveId,
      service: 'stripe',
    },
  });
  debugRefund(`stripeAccounts: ${JSON.stringify(stripeAccounts, null, 2)}`);
  // If it's credit card then we will refund
  if (transaction.PaymentMethod && transaction.PaymentMethod.type === 'creditcard') {
    debugRefund('refunding transaction.', transaction);
    try {
      // try to do both stripe and database refunds
      const refundTransactions = await paymentMethod.refundTransaction(transaction, { id: 18520 });
      debugRefund(`Stripe refundTransactions: ${JSON.stringify(refundTransactions, null, 2)}`);
    } catch (error) {
      // Error means stripe has already refunded
      debugRefund(`STRIPE error meaning it was already refund...trying to refund only on our database:`);
      try {
        const refundTransactions = await paymentMethod.refundTransactionOnlyInDatabase(transaction, { id: 18520 });
        debugRefund(`Database ONLY refundTransactions: ${JSON.stringify(refundTransactions, null, 2)}`);
      } catch (error) {
        // throwing error on purpose to stop everything if something unexpected happens..
        console.error(error);
        throw error;
      }
    }
  }
  const order = transaction.Order;
  // We mark then Active Orders as CANCELLED and deactivated their subscriptions
  if (order && order.status === 'ACTIVE' && order.SubscriptionId) {
    order.status = 'CANCELLED';
    await order.save();
    debugRefund('updating subscription to be deactived');

    // if the order has a subscription, mark it with isActive as false and deactivedAt now.
    if (order.SubscriptionId) {
      const subscription = await models.Subscription.findById(order.SubscriptionId);
      subscription.isActive = false;
      subscription.deactivatedAt = new Date();
      await subscription.save();
    }
  }
  return models.Transaction.findById(transaction.id);
}

async function run() {
  debugRefund(`Running refund scripts to get Transactions with the following FromCollectiveId:
    ${JSON.stringify(fromCollectiveIds, null, 2)}`);
  const transactions = await models.Transaction.findAll({
    where: {
      FromCollectiveId: fromCollectiveIds,
      type: 'CREDIT',
      RefundTransactionId: null,
    },
    include: [models.Order, models.PaymentMethod],
  });
  try {
    debugRefund(`Trying to refund ${(transactions && transactions.length) || 0} transactions...`);
    const mapResult = await Promise.map(transactions, refundTransaction);
    debugRefund(`Script finished successfully,
      mapResult(tip: result transactions need to have RefundTransactionId set):
      ${JSON.stringify(mapResult, null, 2)}`);
    process.exit(0);
  } catch (error) {
    debugRefund('Error executing script', error);
    process.exit(1);
  }
}

run();
<|endoftext|>


<commit_before>define([
		'goo/renderer/Material',
		'goo/renderer/MeshData',
		'goo/renderer/shaders/ShaderLib',
		'goo/math/Vector3'
	],
	function (Material,
			  MeshData,
			  ShaderLib) {
		'use strict';

		/**
		 * used internally to render a batch of lines all with the same color
		 * @param {LineRenderSystem} lineRenderSystemOwner
		 * @param {string} colorStr
		 */
		function LineRenderer(lineRenderSystemOwner, colorStr) {
			this.lineRenderSystemOwner = lineRenderSystemOwner;

			//convert string to array
			var colorArr = JSON.parse(colorStr);

			this._material = new Material(ShaderLib.simpleColored);
			this._material.uniforms.color = colorArr;

			this._meshData = new MeshData(MeshData.defaultMap([MeshData.POSITION]), this.MAX_NUM_LINES * 2, 0);
			this._meshData.indexModes = ['Lines'];

			this._vertices = this._meshData.getAttributeBuffer(MeshData.POSITION);

			//create an empty entity used solely for running the simpleColored shader
			this._entity = this.lineRenderSystemOwner.world.createEntity(this._meshData, this._material).addToWorld();
			this._entity.meshRendererComponent.cullMode = 'Never';

			this._numRenderingLines = 0;
			this._meshData.vertexCount = 0;
		}

		LineRenderer.prototype.MAX_NUM_LINES = 170000;

		LineRenderer.prototype.update = function () {
			if (this._numRenderingLines !== 0 || this._meshData.vertexCount !== 0) {
				this._meshData.vertexCount = Math.min(this._numRenderingLines, this.MAX_NUM_LINES) * 2;
				this._meshData.setVertexDataUpdated();
			}
			this._numRenderingLines = 0;
		};

		LineRenderer.prototype.remove = function () {
			this._entity.removeFromWorld();

			this._meshData.destroy(this.lineRenderSystemOwner.world.gooRunner.renderer.context);
		};

		LineRenderer.prototype.addLine = function (start, end) {
			//no need to continue if we already reached MAX_NUM_LINES
			if (this._numRenderingLines >= this.MAX_NUM_LINES) {
				return;
			}

			for (var i = 0; i < 3; i++) {
				this._vertices[this._numRenderingLines * 6 + i] = start.data[i];
				this._vertices[this._numRenderingLines * 6 + 3 + i] = end.data[i];
			}

			this._numRenderingLines++;
		};

		return LineRenderer;
	});<commit_msg>fix jsdoc and replace color strings with color Vector3's. rename addLine to _addLine since its a private method<commit_after>define([
		'goo/renderer/Material',
		'goo/renderer/MeshData',
		'goo/renderer/shaders/ShaderLib',
		'goo/math/Vector3'
	],
	function (Material,
			  MeshData,
			  ShaderLib) {
		'use strict';

		/**
		 * Used internally to render a batch of lines all with the same color
		 * @param {LineRenderSystem} lineRenderSystemOwner
		 * @param {Vector3} color
		 */
		function LineRenderer(lineRenderSystemOwner, color) {
			this.lineRenderSystemOwner = lineRenderSystemOwner;

			this._material = new Material(ShaderLib.simpleColored);
			this._material.uniforms.color = [color.x, color.y, color.z];

			this._meshData = new MeshData(MeshData.defaultMap([MeshData.POSITION]), this.MAX_NUM_LINES * 2, 0);
			this._meshData.indexModes = ['Lines'];

			this._vertices = this._meshData.getAttributeBuffer(MeshData.POSITION);

			//create an empty entity used solely for running the simpleColored shader
			this._entity = this.lineRenderSystemOwner.world.createEntity(this._meshData, this._material).addToWorld();
			this._entity.meshRendererComponent.cullMode = 'Never';

			this._numRenderingLines = 0;
			this._meshData.vertexCount = 0;
		}

		LineRenderer.prototype.MAX_NUM_LINES = 170000;

		LineRenderer.prototype.update = function () {
			if (this._numRenderingLines !== 0 || this._meshData.vertexCount !== 0) {
				this._meshData.vertexCount = Math.min(this._numRenderingLines, this.MAX_NUM_LINES) * 2;
				this._meshData.setVertexDataUpdated();
			}
			this._numRenderingLines = 0;
		};

		LineRenderer.prototype.remove = function () {
			this._entity.removeFromWorld();

			this._meshData.destroy(this.lineRenderSystemOwner.world.gooRunner.renderer.context);
		};

		/**
		 * Used internally to add a line to the LineRenderer to be rendered next frame.
		 * @param {Vector3} start
		 * @param {Vector3} end
		 */
		LineRenderer.prototype._addLine = function (start, end) {
			//no need to continue if we already reached MAX_NUM_LINES
			if (this._numRenderingLines >= this.MAX_NUM_LINES) {
				return;
			}

			for (var i = 0; i < 3; i++) {
				this._vertices[this._numRenderingLines * 6 + i] = start.data[i];
				this._vertices[this._numRenderingLines * 6 + 3 + i] = end.data[i];
			}

			this._numRenderingLines++;
		};

		return LineRenderer;
	});<|endoftext|>


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

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { sanitizeHTML } from '../../util/sanitize';
import Link from '../Link';
import { useSelect } from '@wordpress/data';
import { STORE_NAME as CORE_SITE } from '../../googlesitekit/datastore/site/constants';

const ERROR_INVALID_HOSTNAME = 'invalid_hostname';
const ERROR_FETCH_FAIL = 'check_fetch_failed';
const ERROR_TOKEN_MISMATCH = 'setup_token_mismatch';
const ERROR_GOOGLE_API_CONNECTION_FAIL = 'google_api_connection_fail';
const ERROR_AMP_CDN_RESTRICTED = 'amp_cdn_restricted';
const ERROR_WP_PRE_V5 = 'wp_pre_v5';

export const AMP_PROJECT_TEST_URL = 'https://cdn.ampproject.org/v0.js';

const helperCTA = ( developerPlugin ) => {
	const { installed, active, installURL, activateURL, configureURL } = developerPlugin;

	if ( ! installed && installURL ) {
		return {
			'aria-label': __( 'Install the helper plugin', 'google-site-kit' ),
			children: __( 'Install', 'google-site-kit' ),
			href: installURL,
			external: false,
		};
	}
	if ( installed && ! active && activateURL ) {
		return {
			'aria-label': __( 'Activate the helper plugin', 'google-site-kit' ),
			children: __( 'Activate', 'google-site-kit' ),
			href: activateURL,
			external: false,
		};
	}
	if ( installed && active && configureURL ) {
		return {
			'aria-label': __( 'Configure the helper plugin', 'google-site-kit' ),
			children: __( 'Configure', 'google-site-kit' ),
			href: configureURL,
			external: false,
		};
	}
	return {
		'aria-label': __( 'Learn how to install and use the helper plugin', 'google-site-kit' ),
		children: __( 'Learn how', 'google-site-kit' ),
		href: 'https://sitekit.withgoogle.com/documentation/using-site-kit-on-a-staging-environment/',
		external: true,
	};
};

export default function CompatibilityErrorNotice( props ) {
	const { error } = props;
	const developerPlugin = useSelect( ( select ) => select( CORE_SITE ).getDeveloperPluginState() ) || {};
	const { installed } = developerPlugin;

	switch ( error ) {
		case ERROR_INVALID_HOSTNAME:
		case ERROR_FETCH_FAIL:
			return (

					{ ! installed && __( 'Looks like this may be a staging environment. If so, you’ll need to install a helper plugin and verify your production site in Search Console.', 'google-site-kit' ) }
					{ installed && __( 'Looks like this may be a staging environment and you already have the helper plugin. Before you can use Site Kit, please make sure you’ve provided the necessary credentials in the Authentication section and verified your production site in Search Console.', 'google-site-kit' ) }
					{ ' ' }
					<Link
						{ ...helperCTA( developerPlugin ) }
						inherit
					/>

			);
		case ERROR_TOKEN_MISMATCH:
			return (

					{ __( 'Looks like you may be using a caching plugin which could interfere with setup. Please deactivate any caching plugins before setting up Site Kit. You may reactivate them once setup has been completed.', 'google-site-kit' ) }

			);
		case ERROR_GOOGLE_API_CONNECTION_FAIL:
			return (
				<p dangerouslySetInnerHTML={ sanitizeHTML(
					`
						${ __( 'Looks like your site is having a technical issue with requesting data from Google services.', 'google-site-kit' ) }

						${ sprintf(
						/* translators: %1$s: Support Forum URL, %2$s: Error message */ // eslint-disable-line indent
						__( 'To get more help, ask a question on our support forum and include the text of the original error message: %2$s', 'google-site-kit' ), // eslint-disable-line indent
						'https://wordpress.org/support/plugin/google-site-kit/', // eslint-disable-line indent
						`<br/>${ error }` // eslint-disable-line indent
					) /* eslint-disable-line indent */ }
						`,
					{
						ALLOWED_TAGS: [ 'a', 'br' ],
						ALLOWED_ATTR: [ 'href' ],
					}
				) } />
			);
		case ERROR_AMP_CDN_RESTRICTED:
			return (
				<p dangerouslySetInnerHTML={ sanitizeHTML(
					`
						${ __( 'Looks like the AMP CDN is restricted in your region, which could interfere with setup on the Site Kit service.', 'google-site-kit' ) }

						${ sprintf(
						/* translators: %1$s: Support Forum URL, %2$s: Error message */ // eslint-disable-line indent
						__( 'To get more help, ask a question on our support forum and include the text of the original error message: %2$s', 'google-site-kit' ), // eslint-disable-line indent
						'https://wordpress.org/support/plugin/google-site-kit/', // eslint-disable-line indent
						`<br/>${ error }` // eslint-disable-line indent
					) /* eslint-disable-line indent */ }
						`,
					{
						ALLOWED_TAGS: [ 'a', 'br' ],
						ALLOWED_ATTR: [ 'href' ],
					}
				) } />
			);
		case ERROR_WP_PRE_V5:
			return (

					{ __( 'Looks like you’re using a version of WordPress that’s older than 5.0. You can still install and use Site Kit, but some of its features might not work (for example translations).', 'google-site-kit' ) }

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

/**
 * WordPress dependencies
 */
import { __, sprintf } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { sanitizeHTML } from '../../util/sanitize';
import Link from '../Link';
import { useSelect } from '@wordpress/data';
import { STORE_NAME as CORE_SITE } from '../../googlesitekit/datastore/site/constants';

const ERROR_INVALID_HOSTNAME = 'invalid_hostname';
const ERROR_FETCH_FAIL = 'check_fetch_failed';
const ERROR_TOKEN_MISMATCH = 'setup_token_mismatch';
const ERROR_GOOGLE_API_CONNECTION_FAIL = 'google_api_connection_fail';
const ERROR_AMP_CDN_RESTRICTED = 'amp_cdn_restricted';
const ERROR_WP_PRE_V5 = 'wp_pre_v5';

export const AMP_PROJECT_TEST_URL = 'https://cdn.ampproject.org/v0.js';

const helperCTA = ( developerPlugin ) => {
	const { installed, active, installURL, activateURL, configureURL } = developerPlugin;

	if ( ! installed && installURL ) {
		return {
			'aria-label': __( 'Install the helper plugin', 'google-site-kit' ),
			children: __( 'Install', 'google-site-kit' ),
			href: installURL,
			external: false,
		};
	}
	if ( installed && ! active && activateURL ) {
		return {
			'aria-label': __( 'Activate the helper plugin', 'google-site-kit' ),
			children: __( 'Activate', 'google-site-kit' ),
			href: activateURL,
			external: false,
		};
	}
	if ( installed && active && configureURL ) {
		return {
			'aria-label': __( 'Configure the helper plugin', 'google-site-kit' ),
			children: __( 'Configure', 'google-site-kit' ),
			href: configureURL,
			external: false,
		};
	}
	return {
		'aria-label': __( 'Learn how to install and use the helper plugin', 'google-site-kit' ),
		children: __( 'Learn how', 'google-site-kit' ),
		href: 'https://sitekit.withgoogle.com/documentation/using-site-kit-on-a-staging-environment/',
		external: true,
	};
};

export default function CompatibilityErrorNotice( props ) {
	const { error } = props;
	const developerPlugin = useSelect( ( select ) => select( CORE_SITE ).getDeveloperPluginState() ) || {};
	const { installed } = developerPlugin;

	switch ( error ) {
		case ERROR_INVALID_HOSTNAME:
		case ERROR_FETCH_FAIL:
			return (

					{ ! installed && __( 'Looks like this may be a staging environment. If so, you’ll need to install a helper plugin and verify your production site in Search Console.', 'google-site-kit' ) }
					{ installed && __( 'Looks like this may be a staging environment and you already have the helper plugin. Before you can use Site Kit, please make sure you’ve provided the necessary credentials in the Authentication section and verified your production site in Search Console.', 'google-site-kit' ) }
					{ ' ' }
					<Link
						{ ...helperCTA( developerPlugin ) }
						inherit
					/>

			);
		case ERROR_TOKEN_MISMATCH:
			return (

					{ __( 'Looks like you may be using a caching plugin which could interfere with setup. Please deactivate any caching plugins before setting up Site Kit. You may reactivate them once setup has been completed.', 'google-site-kit' ) }

			);
		case ERROR_GOOGLE_API_CONNECTION_FAIL:
			return (
				<p dangerouslySetInnerHTML={ sanitizeHTML(
					`
						${ __( 'Looks like your site is having a technical issue with requesting data from Google services.', 'google-site-kit' ) }

						${ sprintf(
						/* translators: %1$s: Support Forum URL, %2$s: Error message */ // eslint-disable-line indent
						__( 'To get more help, ask a question on our support forum and include the text of the original error message: %2$s', 'google-site-kit' ), // eslint-disable-line indent
						'https://wordpress.org/support/plugin/google-site-kit/', // eslint-disable-line indent
						`<br/>${ error }` // eslint-disable-line indent
					) /* eslint-disable-line indent */ }
						`,
					{
						ALLOWED_TAGS: [ 'a', 'br' ],
						ALLOWED_ATTR: [ 'href' ],
					}
				) } />
			);
		case ERROR_AMP_CDN_RESTRICTED:
			return (
				<p dangerouslySetInnerHTML={ sanitizeHTML(
					`
						${ __( 'Looks like the AMP CDN is restricted in your region, which could interfere with setup on the Site Kit service.', 'google-site-kit' ) }

						${ sprintf(
						/* translators: %1$s: Support Forum URL, %2$s: Error message */ // eslint-disable-line indent
						__( 'To get more help, ask a question on our support forum and include the text of the original error message: %2$s', 'google-site-kit' ), // eslint-disable-line indent
						'https://wordpress.org/support/plugin/google-site-kit/', // eslint-disable-line indent
						`<br/>${ error }` // eslint-disable-line indent
					) /* eslint-disable-line indent */ }
						`,
					{
						ALLOWED_TAGS: [ 'a', 'br' ],
						ALLOWED_ATTR: [ 'href' ],
					}
				) } />
			);
		case ERROR_WP_PRE_V5:
			return (

					{ __( 'Looks like you’re using a version of WordPress that’s older than 5.0. You can still install and use Site Kit, but some of its features might not work (for example translations).', 'google-site-kit' ) }

			);
	}
}
<|endoftext|>


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

/**
 * Internal dependencies
 */
import {
	createTestRegistry,
	muteFetch,
} from '../../../../../tests/js/utils';
import { createCacheKey } from '../../api';
import { setItem } from '../../api/cache';
import { STORE_NAME } from './constants';

describe( 'core/user surveys', () => {
	let registry;

	beforeEach( () => {
		registry = createTestRegistry();
	} );

	const survey = {
		survey_payload: 'foo',
		session: {
			session_id: 'bar',
			session_token: '1234',
		},
	};
	const surveyTriggerEndpoint = /^\/google-site-kit\/v1\/core\/user\/data\/survey-trigger/;
	const surveyEventEndpoint = /^\/google-site-kit\/v1\/core\/user\/data\/survey-event/;

	describe( 'actions', () => {
		describe( 'triggerSurvey', () => {
			it( 'throws an error when parameters are missing or incorrect', () => {
				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey();
				} ).toThrow( 'triggerID is required and must be a string' );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'coolSurvey', false );
				} ).toThrow( 'options must be an object' );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'warmSurvey', { ttl: 'a' } );
				} ).toThrow( 'options.ttl must be a number' );
			} );

			it( 'does not throw when called with only a triggerID', async () => {
				muteFetch( surveyTriggerEndpoint );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'adSenseSurvey' );
				} ).not.toThrow();
			} );

			it( 'does not throw when called with a numeric ttl', () => {
				muteFetch( surveyTriggerEndpoint );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'analyticsSurvey', { ttl: 1 } );
				} ).not.toThrow();
			} );

			it( 'makes network requests to endpoints', async () => {
				muteFetch( surveyTriggerEndpoint );

				await registry.dispatch( STORE_NAME ).triggerSurvey( 'optimizeSurvey' );

				expect( fetchMock ).toHaveFetched( surveyTriggerEndpoint, {
					body: {
						data: { triggerID: 'optimizeSurvey' },
					},
				} );
			} );

			it( 'does not fetch if there is a cache value present for the trigger ID', async () => {
				await setItem(
					createCacheKey( 'core', 'user', 'survey-trigger', { triggerID: 'optimizeSurvey' } ),
					{} // Any value will due for now.
				);

				await registry.dispatch( STORE_NAME ).triggerSurvey( 'optimizeSurvey' );

				expect( fetchMock ).not.toHaveFetched();
			} );
		} );

		describe( 'sendSurveyEvent', () => {
			it( 'throws an error when parameters are missing or incorrect', () => {
				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent();
				} ).toThrow( 'eventID is required and must be a string' );

				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent( 'dismiss_survey', 'answer_question' );
				} ).toThrow( 'eventData must be an object' );
			} );

			it( 'does not throw an error when parameters are correct', () => {
				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent( 'dismiss_survey' );
				} ).not.toThrow();

				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent( 'answer_question', { foo: 'bar' } );
				} ).not.toThrow();
			} );

			it( 'makes network requests to endpoints', async () => {
				muteFetch( surveyEventEndpoint );

				// Survey events are only sent if there is a current survey.
				registry.dispatch( STORE_NAME ).receiveTriggerSurvey( survey, { triggerID: 'optimizeSurvey' } );
				// Send a survey event.
				await registry.dispatch( STORE_NAME ).sendSurveyEvent( 'answer_question', { foo: 'bar' } );

				expect( fetchMock ).toHaveFetched( surveyEventEndpoint, {
					body: {
						data: {
							event: { answer_question: { foo: 'bar' } },
							session: survey.session,
						},
					},
				} );
			} );
		} );
	} );

	describe( 'selectors', () => {
		describe( 'getCurrentSurvey', () => {
			it( 'returns null when no current survey is set', async () => {
				expect( registry.select( STORE_NAME ).getCurrentSurvey() ).toBeNull();
			} );

			it( 'returns the current survey when it is set', () => {
				registry.dispatch( STORE_NAME ).receiveTriggerSurvey( survey, { triggerID: 'optimizeSurvey' } );

				expect(
					registry.select( STORE_NAME ).getCurrentSurvey()
				).toEqual( survey.survey_payload );
			} );
		} );

		describe( 'getCurrentSurveySession', () => {
			it( 'returns null when no current survey session is set', async () => {
				expect(
					registry.select( STORE_NAME ).getCurrentSurveySession()
				).toBeNull();
			} );

			it( 'returns the current survey session when set', () => {
				registry.dispatch( STORE_NAME ).receiveTriggerSurvey( survey, { triggerID: 'optimizeSurvey' } );

				expect(
					registry.select( STORE_NAME ).getCurrentSurveySession()
				).toEqual( survey.session );
			} );
		} );
	} );
} );
<commit_msg>Add js test.<commit_after>/**
 * `core/user` data store: Surveys tests.
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import {
	createTestRegistry,
	muteFetch,
} from '../../../../../tests/js/utils';
import { createCacheKey } from '../../api';
import { setItem, setSelectedStorageBackend } from '../../api/cache';
import { STORE_NAME } from './constants';

describe( 'core/user surveys', () => {
	let registry;

	beforeEach( () => {
		registry = createTestRegistry();
	} );

	const survey = {
		survey_payload: 'foo',
		session: {
			session_id: 'bar',
			session_token: '1234',
		},
	};
	const surveyTriggerEndpoint = /^\/google-site-kit\/v1\/core\/user\/data\/survey-trigger/;
	const surveyEventEndpoint = /^\/google-site-kit\/v1\/core\/user\/data\/survey-event/;

	describe( 'actions', () => {
		describe( 'triggerSurvey', () => {
			it( 'throws an error when parameters are missing or incorrect', () => {
				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey();
				} ).toThrow( 'triggerID is required and must be a string' );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'coolSurvey', false );
				} ).toThrow( 'options must be an object' );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'warmSurvey', { ttl: 'a' } );
				} ).toThrow( 'options.ttl must be a number' );
			} );

			it( 'does not throw when called with only a triggerID', async () => {
				muteFetch( surveyTriggerEndpoint );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'adSenseSurvey' );
				} ).not.toThrow();
			} );

			it( 'does not throw when called with a numeric ttl', () => {
				muteFetch( surveyTriggerEndpoint );

				expect( () => {
					registry.dispatch( STORE_NAME ).triggerSurvey( 'analyticsSurvey', { ttl: 1 } );
				} ).not.toThrow();
			} );

			it( 'makes network requests to endpoints', async () => {
				muteFetch( surveyTriggerEndpoint );

				await registry.dispatch( STORE_NAME ).triggerSurvey( 'optimizeSurvey' );

				expect( fetchMock ).toHaveFetched( surveyTriggerEndpoint, {
					body: {
						data: { triggerID: 'optimizeSurvey' },
					},
				} );
			} );

			it( 'does not fetch if there is a cache value present for the trigger ID', async () => {
				await setItem(
					createCacheKey( 'core', 'user', 'survey-trigger', { triggerID: 'optimizeSurvey' } ),
					{} // Any value will due for now.
				);

				await registry.dispatch( STORE_NAME ).triggerSurvey( 'optimizeSurvey' );

				expect( fetchMock ).not.toHaveFetched();
			} );

			it( 'should cache survey for provided ttl', async () => {
				let ttl;
				const triggerID = 'optimizeSurvey';

				setSelectedStorageBackend( {
					getItem: () => undefined,
					setItem: ( _, options ) => {
						try {
							ttl = JSON.parse( options )?.ttl;
						} catch {
						}
					},
				} );

				fetchMock.postOnce( surveyTriggerEndpoint, { body: { triggerID } } );

				await registry.dispatch( STORE_NAME ).triggerSurvey( triggerID, { ttl: 500 } );
				expect( ttl ).toBe( 500 );
			} );
		} );

		describe( 'sendSurveyEvent', () => {
			it( 'throws an error when parameters are missing or incorrect', () => {
				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent();
				} ).toThrow( 'eventID is required and must be a string' );

				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent( 'dismiss_survey', 'answer_question' );
				} ).toThrow( 'eventData must be an object' );
			} );

			it( 'does not throw an error when parameters are correct', () => {
				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent( 'dismiss_survey' );
				} ).not.toThrow();

				expect( () => {
					registry.dispatch( STORE_NAME ).sendSurveyEvent( 'answer_question', { foo: 'bar' } );
				} ).not.toThrow();
			} );

			it( 'makes network requests to endpoints', async () => {
				muteFetch( surveyEventEndpoint );

				// Survey events are only sent if there is a current survey.
				registry.dispatch( STORE_NAME ).receiveTriggerSurvey( survey, { triggerID: 'optimizeSurvey' } );
				// Send a survey event.
				await registry.dispatch( STORE_NAME ).sendSurveyEvent( 'answer_question', { foo: 'bar' } );

				expect( fetchMock ).toHaveFetched( surveyEventEndpoint, {
					body: {
						data: {
							event: { answer_question: { foo: 'bar' } },
							session: survey.session,
						},
					},
				} );
			} );
		} );
	} );

	describe( 'selectors', () => {
		describe( 'getCurrentSurvey', () => {
			it( 'returns null when no current survey is set', async () => {
				expect( registry.select( STORE_NAME ).getCurrentSurvey() ).toBeNull();
			} );

			it( 'returns the current survey when it is set', () => {
				registry.dispatch( STORE_NAME ).receiveTriggerSurvey( survey, { triggerID: 'optimizeSurvey' } );

				expect(
					registry.select( STORE_NAME ).getCurrentSurvey()
				).toEqual( survey.survey_payload );
			} );
		} );

		describe( 'getCurrentSurveySession', () => {
			it( 'returns null when no current survey session is set', async () => {
				expect(
					registry.select( STORE_NAME ).getCurrentSurveySession()
				).toBeNull();
			} );

			it( 'returns the current survey session when set', () => {
				registry.dispatch( STORE_NAME ).receiveTriggerSurvey( survey, { triggerID: 'optimizeSurvey' } );

				expect(
					registry.select( STORE_NAME ).getCurrentSurveySession()
				).toEqual( survey.session );
			} );
		} );
	} );
} );
<|endoftext|>


<commit_before>/* eslint-env jest */
import reducer from '../street'
import * as actions from '../../actions/street'

describe('street reducer', () => {
  it('should return the initial state', () => {
    expect(reducer(undefined, {})).toEqual({
      segments: []
    })
  })

  it('should handle ADD_SEGMENT', () => {
    // Add a segment at index 0 from initial state
    expect(
      reducer(undefined, actions.addSegment(0, { type: 'foo' }))
    ).toEqual({
      segments: [
        { type: 'foo' }
      ]
    })

    // Insert a segment at index 0 for an existing street
    expect(
      reducer({
        segments: [
          { type: 'foo' }
        ]
      }, actions.addSegment(0, { type: 'bar' }))
    ).toEqual({
      segments: [
        { type: 'bar' },
        { type: 'foo' }
      ]
    })

    // Insert a segment at index 1 for an existing street
    expect(
      reducer({
        segments: [
          { type: 'foo' }
        ]
      }, actions.addSegment(1, { type: 'bar' }))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'bar' }
      ]
    })

    // Insert a segment at index 1 for an existing street
    expect(
      reducer({
        segments: [
          { type: 'foo' },
          { type: 'baz' }
        ]
      }, actions.addSegment(1, { type: 'bar' }))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        { type: 'baz' }
      ]
    })
  })

  it('should handle REMOVE_SEGMENT', () => {
    const existingStreet = {
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        { type: 'baz' },
        { type: 'qux' }
      ]
    }

    // Removes a segment at index 1 from an existing street
    expect(
      reducer({...existingStreet}, actions.removeSegment(1))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'baz' },
        { type: 'qux' }
      ]
    })

    // Removes a segment at index 0 from an existing street
    expect(
      reducer({...existingStreet}, actions.removeSegment(0))
    ).toEqual({
      segments: [
        { type: 'bar' },
        { type: 'baz' },
        { type: 'qux' }
      ]
    })

    // Returns existing street if a removed segment is out of bounds
    expect(
      reducer({...existingStreet}, actions.removeSegment(8))
    ).toEqual(existingStreet)
  })

  it('should handle MOVE_SEGMENT', () => {
    const existingStreet = {
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        { type: 'baz' }
      ]
    }

    // Moves a segment at index 0 to index 1 on an existing street
    expect(
      reducer({...existingStreet}, actions.moveSegment(0, 1))
    ).toEqual({
      segments: [
        { type: 'bar' },
        { type: 'foo' },
        { type: 'baz' }
      ]
    })

    // Moves a segment at index 2 to index 0 on an existing street
    expect(
      reducer({...existingStreet}, actions.moveSegment(2, 0))
    ).toEqual({
      segments: [
        { type: 'baz' },
        { type: 'foo' },
        { type: 'bar' }
      ]
    })

    // moves a segment to the end if desired index is out of bounds
    expect(
      reducer({...existingStreet}, actions.moveSegment(1, 8))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'baz' },
        { type: 'bar' }
      ]
    })
  })

  it('should handle CHANGE_SEGMENT_WIDTH', () => {
    const existingStreet = {
      segments: [
        { type: 'foo', width: 1 },
        { type: 'bar', width: 2 },
        { type: 'baz', width: 3 }
      ]
    }

    // Changes a segment width
    expect(
      reducer({...existingStreet}, actions.changeSegmentWidth(0, 20))
    ).toEqual({
      segments: [
        { type: 'foo', width: 20 },
        { type: 'bar', width: 2 },
        { type: 'baz', width: 3 }
      ]
    })
  })

  it('should handle CHANGE_SEGMENT_VARIANT', () => {
    const existingStreet = {
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        {
          type: 'drive-lane',
          variantString: 'inbound|car',
          variant: {
            direction: 'inbound',
            'car-type': 'car'
          }
        }
      ]
    }

    expect(
      reducer({...existingStreet}, actions.changeSegmentVariant(2, 'direction', 'outbound'))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        {
          type: 'drive-lane',
          variantString: 'outbound|car',
          variant: {
            direction: 'outbound',
            'car-type': 'car'
          }
        }
      ]
    })
  })

  it('should handle ADD_LOCATION', () => {
    const location = {
      latlng: [0, 0],
      label: 'test street',
      hierarchy: {
        country: 'country',
        locality: 'locality',
        neighbourhood: 'neighbourhood',
        street: 'street'
      },
      geometryId: null,
      intersectionId: null
    }

    expect(
      reducer({}, actions.addLocation(location))
    ).toEqual({
      location: location
    })
  })

  describe('CLEAR_LOCATION', () => {
    it('sets street.location to be null and clears original street name if userUpdated was false', () => {
      const existingStreet = {
        name: 'test street',
        userUpdated: false,
        location: {
          latlng: [0, 0],
          label: 'test street',
          hierarchy: {
            country: 'country',
            locality: 'locality',
            neighbourhood: 'neighbourhood',
            street: 'street'
          },
          geometryId: null,
          intersectionId: null
        }
      }

      expect(
        reducer({...existingStreet}, actions.clearLocation())
      ).toEqual({
        name: 'Unnamed St',
        userUpdated: false,
        location: null
      })
    })
  })

  describe('SAVE_STREET_NAME', () => {
    it('renames street name if user updated and sets userUpdated to true', () => {
      const existingStreet = {
        name: 'street name',
        userUpdated: false
      }

      expect(
        reducer({...existingStreet}, actions.saveStreetName('new street name', true))
      ).toEqual({
        name: 'new street name',
        userUpdated: true
      })
    })

    it('does not rename street if not user updated and userUpdate is true', () => {
      const existingStreet = {
        name: 'street name',
        userUpdated: true
      }

      expect(
        reducer({...existingStreet}, actions.saveStreetName('new street name', false))
      ).toEqual({
        name: 'street name',
        userUpdated: true
      })
    })

    it('renames street if userUpdated is false', () => {
      const existingStreet = {
        name: 'street name',
        userUpdated: false
      }

      expect(
        reducer({...existingStreet}, actions.saveStreetName('new street name', false))
      ).toEqual({
        name: 'new street name',
        userUpdated: false
      })
    })
  })

  describe('buildings', () => {
    describe('ADD_BUILDING_FLOOR', () => {
      it('adds a floor on the left building', () => {
        const existingStreet = {
          leftBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('left'))
        ).toEqual({
          leftBuildingHeight: 2
        })
      })

      it('adds a floor on the right building', () => {
        const existingStreet = {
          rightBuildingHeight: 19
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('right'))
        ).toEqual({
          rightBuildingHeight: 20
        })
      })

      it('will not increase a building height past maximum', () => {
        const existingStreet = {
          rightBuildingHeight: 20
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('right'))
        ).toEqual({
          rightBuildingHeight: 20
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('middle'))
        ).toEqual(existingStreet)
      })
    })

    describe('REMOVE_BUILDING_FLOOR', () => {
      it('removes a floor on the left building', () => {
        const existingStreet = {
          leftBuildingHeight: 2
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('left'))
        ).toEqual({
          leftBuildingHeight: 1
        })
      })

      it('removes a floor on the right building', () => {
        const existingStreet = {
          rightBuildingHeight: 19
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('right'))
        ).toEqual({
          rightBuildingHeight: 18
        })
      })

      it('will not decrease a building height past minimum', () => {
        const existingStreet = {
          leftBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('left'))
        ).toEqual({
          leftBuildingHeight: 1
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('middle'))
        ).toEqual(existingStreet)
      })
    })

    describe('SET_BUILDING_FLOOR_VALUE', () => {
      it('sets a floor value on the left building', () => {
        const existingStreet = {
          leftBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', 3))
        ).toEqual({
          leftBuildingHeight: 3
        })
      })

      it('sets a floor value on the right building', () => {
        const existingStreet = {
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 1))
        ).toEqual({
          rightBuildingHeight: 1
        })
      })

      it('will clamp a value to minimum', () => {
        const existingStreet = {
          leftBuildingHeight: 20
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', 0))
        ).toEqual({
          leftBuildingHeight: 1
        })
      })

      it('will clamp a value to maximum', () => {
        const existingStreet = {
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 1000))
        ).toEqual({
          rightBuildingHeight: 20
        })
      })

      it('refuses to set a value that is NaN', () => {
        const existingStreet = {
          rightBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', NaN))
        ).toEqual({
          rightBuildingHeight: 5
        })
      })

      it('refuses to set a value that is falsy', () => {
        const existingStreet = {
          leftBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', null))
        ).toEqual({
          leftBuildingHeight: 5
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', false))
        ).toEqual({
          leftBuildingHeight: 5
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', ''))
        ).toEqual({
          leftBuildingHeight: 5
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left'))
        ).toEqual({
          leftBuildingHeight: 5
        })
      })

      it('parses integer values from non-integer input', () => {
        const existingStreet = {
          rightBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 4.5))
        ).toEqual({
          rightBuildingHeight: 4
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', '9'))
        ).toEqual({
          rightBuildingHeight: 9
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', '6 floors'))
        ).toEqual({
          rightBuildingHeight: 6
        })
      })

      it('does not set a value if integer value cannot be parsed from non-integer input', () => {
        const existingStreet = {
          leftBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 'foo'))
        ).toEqual({
          leftBuildingHeight: 5
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('middle'))
        ).toEqual(existingStreet)
      })
    })

    describe('SET_BUILDING_VARIANT', () => {
      it('sets a variant on the left building', () => {
        const existingStreet = {
          leftBuildingVariant: 'wide'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', 'narrow'))
        ).toEqual({
          leftBuildingVariant: 'narrow'
        })
      })

      it('sets a floor value on the right building', () => {
        const existingStreet = {
          rightBuildingVariant: 'narrow'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('right', 'wide'))
        ).toEqual({
          rightBuildingVariant: 'wide'
        })
      })

      it('refuses to set a value that is falsy', () => {
        const existingStreet = {
          leftBuildingVariant: 'waterfront'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', null))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', false))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', ''))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left'))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingVariant: 'fence',
          rightBuildingVariant: 'parking'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingVariant: 'fence',
          rightBuildingVariant: 'parking'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('middle'))
        ).toEqual(existingStreet)
      })
    })
  })
})
<commit_msg>updated street.test.js to reflect use of object latlng<commit_after>/* eslint-env jest */
import reducer from '../street'
import * as actions from '../../actions/street'

describe('street reducer', () => {
  it('should return the initial state', () => {
    expect(reducer(undefined, {})).toEqual({
      segments: []
    })
  })

  it('should handle ADD_SEGMENT', () => {
    // Add a segment at index 0 from initial state
    expect(
      reducer(undefined, actions.addSegment(0, { type: 'foo' }))
    ).toEqual({
      segments: [
        { type: 'foo' }
      ]
    })

    // Insert a segment at index 0 for an existing street
    expect(
      reducer({
        segments: [
          { type: 'foo' }
        ]
      }, actions.addSegment(0, { type: 'bar' }))
    ).toEqual({
      segments: [
        { type: 'bar' },
        { type: 'foo' }
      ]
    })

    // Insert a segment at index 1 for an existing street
    expect(
      reducer({
        segments: [
          { type: 'foo' }
        ]
      }, actions.addSegment(1, { type: 'bar' }))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'bar' }
      ]
    })

    // Insert a segment at index 1 for an existing street
    expect(
      reducer({
        segments: [
          { type: 'foo' },
          { type: 'baz' }
        ]
      }, actions.addSegment(1, { type: 'bar' }))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        { type: 'baz' }
      ]
    })
  })

  it('should handle REMOVE_SEGMENT', () => {
    const existingStreet = {
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        { type: 'baz' },
        { type: 'qux' }
      ]
    }

    // Removes a segment at index 1 from an existing street
    expect(
      reducer({...existingStreet}, actions.removeSegment(1))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'baz' },
        { type: 'qux' }
      ]
    })

    // Removes a segment at index 0 from an existing street
    expect(
      reducer({...existingStreet}, actions.removeSegment(0))
    ).toEqual({
      segments: [
        { type: 'bar' },
        { type: 'baz' },
        { type: 'qux' }
      ]
    })

    // Returns existing street if a removed segment is out of bounds
    expect(
      reducer({...existingStreet}, actions.removeSegment(8))
    ).toEqual(existingStreet)
  })

  it('should handle MOVE_SEGMENT', () => {
    const existingStreet = {
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        { type: 'baz' }
      ]
    }

    // Moves a segment at index 0 to index 1 on an existing street
    expect(
      reducer({...existingStreet}, actions.moveSegment(0, 1))
    ).toEqual({
      segments: [
        { type: 'bar' },
        { type: 'foo' },
        { type: 'baz' }
      ]
    })

    // Moves a segment at index 2 to index 0 on an existing street
    expect(
      reducer({...existingStreet}, actions.moveSegment(2, 0))
    ).toEqual({
      segments: [
        { type: 'baz' },
        { type: 'foo' },
        { type: 'bar' }
      ]
    })

    // moves a segment to the end if desired index is out of bounds
    expect(
      reducer({...existingStreet}, actions.moveSegment(1, 8))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'baz' },
        { type: 'bar' }
      ]
    })
  })

  it('should handle CHANGE_SEGMENT_WIDTH', () => {
    const existingStreet = {
      segments: [
        { type: 'foo', width: 1 },
        { type: 'bar', width: 2 },
        { type: 'baz', width: 3 }
      ]
    }

    // Changes a segment width
    expect(
      reducer({...existingStreet}, actions.changeSegmentWidth(0, 20))
    ).toEqual({
      segments: [
        { type: 'foo', width: 20 },
        { type: 'bar', width: 2 },
        { type: 'baz', width: 3 }
      ]
    })
  })

  it('should handle CHANGE_SEGMENT_VARIANT', () => {
    const existingStreet = {
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        {
          type: 'drive-lane',
          variantString: 'inbound|car',
          variant: {
            direction: 'inbound',
            'car-type': 'car'
          }
        }
      ]
    }

    expect(
      reducer({...existingStreet}, actions.changeSegmentVariant(2, 'direction', 'outbound'))
    ).toEqual({
      segments: [
        { type: 'foo' },
        { type: 'bar' },
        {
          type: 'drive-lane',
          variantString: 'outbound|car',
          variant: {
            direction: 'outbound',
            'car-type': 'car'
          }
        }
      ]
    })
  })

  it('should handle ADD_LOCATION', () => {
    const location = {
      latlng: { lat: 0, lng: 0 },
      label: 'test street',
      hierarchy: {
        country: 'country',
        locality: 'locality',
        neighbourhood: 'neighbourhood',
        street: 'street'
      },
      geometryId: null,
      intersectionId: null
    }

    expect(
      reducer({}, actions.addLocation(location))
    ).toEqual({
      location: location
    })
  })

  describe('CLEAR_LOCATION', () => {
    it('sets street.location to be null and clears original street name if userUpdated was false', () => {
      const existingStreet = {
        name: 'test street',
        userUpdated: false,
        location: {
          latlng: { lat: 0, lng: 0 },
          label: 'test street',
          hierarchy: {
            country: 'country',
            locality: 'locality',
            neighbourhood: 'neighbourhood',
            street: 'street'
          },
          geometryId: null,
          intersectionId: null
        }
      }

      expect(
        reducer({...existingStreet}, actions.clearLocation())
      ).toEqual({
        name: 'Unnamed St',
        userUpdated: false,
        location: null
      })
    })
  })

  describe('SAVE_STREET_NAME', () => {
    it('renames street name if user updated and sets userUpdated to true', () => {
      const existingStreet = {
        name: 'street name',
        userUpdated: false
      }

      expect(
        reducer({...existingStreet}, actions.saveStreetName('new street name', true))
      ).toEqual({
        name: 'new street name',
        userUpdated: true
      })
    })

    it('does not rename street if not user updated and userUpdate is true', () => {
      const existingStreet = {
        name: 'street name',
        userUpdated: true
      }

      expect(
        reducer({...existingStreet}, actions.saveStreetName('new street name', false))
      ).toEqual({
        name: 'street name',
        userUpdated: true
      })
    })

    it('renames street if userUpdated is false', () => {
      const existingStreet = {
        name: 'street name',
        userUpdated: false
      }

      expect(
        reducer({...existingStreet}, actions.saveStreetName('new street name', false))
      ).toEqual({
        name: 'new street name',
        userUpdated: false
      })
    })
  })

  describe('buildings', () => {
    describe('ADD_BUILDING_FLOOR', () => {
      it('adds a floor on the left building', () => {
        const existingStreet = {
          leftBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('left'))
        ).toEqual({
          leftBuildingHeight: 2
        })
      })

      it('adds a floor on the right building', () => {
        const existingStreet = {
          rightBuildingHeight: 19
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('right'))
        ).toEqual({
          rightBuildingHeight: 20
        })
      })

      it('will not increase a building height past maximum', () => {
        const existingStreet = {
          rightBuildingHeight: 20
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('right'))
        ).toEqual({
          rightBuildingHeight: 20
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.addBuildingFloor('middle'))
        ).toEqual(existingStreet)
      })
    })

    describe('REMOVE_BUILDING_FLOOR', () => {
      it('removes a floor on the left building', () => {
        const existingStreet = {
          leftBuildingHeight: 2
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('left'))
        ).toEqual({
          leftBuildingHeight: 1
        })
      })

      it('removes a floor on the right building', () => {
        const existingStreet = {
          rightBuildingHeight: 19
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('right'))
        ).toEqual({
          rightBuildingHeight: 18
        })
      })

      it('will not decrease a building height past minimum', () => {
        const existingStreet = {
          leftBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('left'))
        ).toEqual({
          leftBuildingHeight: 1
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.removeBuildingFloor('middle'))
        ).toEqual(existingStreet)
      })
    })

    describe('SET_BUILDING_FLOOR_VALUE', () => {
      it('sets a floor value on the left building', () => {
        const existingStreet = {
          leftBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', 3))
        ).toEqual({
          leftBuildingHeight: 3
        })
      })

      it('sets a floor value on the right building', () => {
        const existingStreet = {
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 1))
        ).toEqual({
          rightBuildingHeight: 1
        })
      })

      it('will clamp a value to minimum', () => {
        const existingStreet = {
          leftBuildingHeight: 20
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', 0))
        ).toEqual({
          leftBuildingHeight: 1
        })
      })

      it('will clamp a value to maximum', () => {
        const existingStreet = {
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 1000))
        ).toEqual({
          rightBuildingHeight: 20
        })
      })

      it('refuses to set a value that is NaN', () => {
        const existingStreet = {
          rightBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', NaN))
        ).toEqual({
          rightBuildingHeight: 5
        })
      })

      it('refuses to set a value that is falsy', () => {
        const existingStreet = {
          leftBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', null))
        ).toEqual({
          leftBuildingHeight: 5
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', false))
        ).toEqual({
          leftBuildingHeight: 5
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left', ''))
        ).toEqual({
          leftBuildingHeight: 5
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('left'))
        ).toEqual({
          leftBuildingHeight: 5
        })
      })

      it('parses integer values from non-integer input', () => {
        const existingStreet = {
          rightBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 4.5))
        ).toEqual({
          rightBuildingHeight: 4
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', '9'))
        ).toEqual({
          rightBuildingHeight: 9
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', '6 floors'))
        ).toEqual({
          rightBuildingHeight: 6
        })
      })

      it('does not set a value if integer value cannot be parsed from non-integer input', () => {
        const existingStreet = {
          leftBuildingHeight: 5
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('right', 'foo'))
        ).toEqual({
          leftBuildingHeight: 5
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingHeight: 1,
          rightBuildingHeight: 1
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingFloorValue('middle'))
        ).toEqual(existingStreet)
      })
    })

    describe('SET_BUILDING_VARIANT', () => {
      it('sets a variant on the left building', () => {
        const existingStreet = {
          leftBuildingVariant: 'wide'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', 'narrow'))
        ).toEqual({
          leftBuildingVariant: 'narrow'
        })
      })

      it('sets a floor value on the right building', () => {
        const existingStreet = {
          rightBuildingVariant: 'narrow'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('right', 'wide'))
        ).toEqual({
          rightBuildingVariant: 'wide'
        })
      })

      it('refuses to set a value that is falsy', () => {
        const existingStreet = {
          leftBuildingVariant: 'waterfront'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', null))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', false))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left', ''))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('left'))
        ).toEqual({
          leftBuildingVariant: 'waterfront'
        })
      })

      it('does nothing if position is not provided', () => {
        const existingStreet = {
          leftBuildingVariant: 'fence',
          rightBuildingVariant: 'parking'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant())
        ).toEqual(existingStreet)
      })

      it('does nothing if an unknown position is provided', () => {
        const existingStreet = {
          leftBuildingVariant: 'fence',
          rightBuildingVariant: 'parking'
        }

        expect(
          reducer({...existingStreet}, actions.setBuildingVariant('middle'))
        ).toEqual(existingStreet)
      })
    })
  })
})
<|endoftext|>


<commit_before>const config = require('./core/shared/config');

module.exports = {
    name: config.get('logging:name'),
    env: config.get('env'),
    path: config.get('logging:path') || config.getContentPath('logs'),
    domain: config.get('url'),
    mode: config.get('logging:mode'),
    level: config.get('logging:level'),
    transports: config.get('logging:transports'),
    metrics: {
        transports: config.get('logging:metrics:transports'),
        metadata: {
            // Undefined if unavailable
            siteId: config.get('hostSettings:siteId'),
            domain: config.get('url')
        }
    },
    gelf: config.get('logging:gelf'),
    loggly: config.get('logging:loggly'),
    elasticsearch: config.get('logging:elasticsearch'),
    rotation: config.get('logging:rotation')
};
<commit_msg>Added ghost-version to metrics<commit_after>const config = require('./core/shared/config');
const ghostVersion = require('@tryghost/version');

module.exports = {
    name: config.get('logging:name'),
    env: config.get('env'),
    path: config.get('logging:path') || config.getContentPath('logs'),
    domain: config.get('url'),
    mode: config.get('logging:mode'),
    level: config.get('logging:level'),
    transports: config.get('logging:transports'),
    metrics: {
        transports: config.get('logging:metrics:transports'),
        metadata: {
            // Undefined if unavailable
            siteId: config.get('hostSettings:siteId'),
            domain: config.get('url'),
            version: ghostVersion.safe
        }
    },
    gelf: config.get('logging:gelf'),
    loggly: config.get('logging:loggly'),
    elasticsearch: config.get('logging:elasticsearch'),
    rotation: config.get('logging:rotation')
};
<|endoftext|>


<commit_before>/*
 * Handles duration processing display
 *
 * It process `Contract.durations()` and display them according to
 * the current `Contract.form()` and `Contract.barriers()`
 *
 * It also populate expiry type select box i.e Durations and Endtime select
 *
 */

var Durations = (function(){
    'use strict';

    var trading_times = {};
    var expiry_time = '';

    var displayDurations = function(startType) {
        var durations = Contract.durations();
        if (durations === false) {
            document.getElementById('expiry_row').style.display = 'none';
            return false;
        }

        var target = document.getElementById('duration_units'),
            formName = Contract.form(),
            barrierCategory = Contract.barrier(),
            fragment = document.createDocumentFragment(), durationContainer = {};

        while (target && target.firstChild) {
            target.removeChild(target.firstChild);
        }

        for (var key in durations) {
            if (durations.hasOwnProperty(key)) {
                for (var form in durations[key][formName]) {
                    if (durations[key][formName].hasOwnProperty(form)) {
                        var obj = {};
                        if (barrierCategory) {
                            obj = durations[key][formName][barrierCategory];
                        } else {
                            obj = durations[key][formName][form];
                        }
                        for (var type in obj) {
                            if (obj.hasOwnProperty(type)) {
                                if (startType) {
                                    if (startType === type) {
                                        if(!durationContainer.hasOwnProperty(startType)) {
                                            durationContainer[key] = obj[startType];
                                        }
                                    }
                                } else {
                                    if(!durationContainer.hasOwnProperty(type)) {
                                        durationContainer[key] = obj[type];
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        var duration_list = {};
        for (var duration in durationContainer) {
            if(durationContainer.hasOwnProperty(duration)) {
                var min = durationContainer[duration]['min_contract_duration'],
                    textMapping = durationTextValueMappings(min);

                var option, content;
                if (duration === 'intraday') {
                    switch (textMapping['value']) {
                        case 's':
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            option = document.createElement('option');
                            content = document.createTextNode(Content.localize().textDurationMinutes);
                            option.setAttribute('value', 'm');
                            option.setAttribute('data-minimum', 1);
                            option.setAttribute('selected', 'selected');
                            option.appendChild(content);
                            duration_list['m']=option;
                            option = document.createElement('option');
                            content = document.createTextNode(Content.localize().textDurationHours);
                            option.setAttribute('value', 'h');
                            option.setAttribute('data-minimum', 1);
                            option.appendChild(content);
                            duration_list['h']=option;
                            break;
                        case 'm':
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.setAttribute('selected', 'selected');
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            option = document.createElement('option');
                            content = document.createTextNode(Content.localize().textDurationHours);
                            option.setAttribute('value', 'h');
                            option.setAttribute('data-minimum', 1);
                            option.appendChild(content);
                            duration_list['h']=option;
                            break;
                        case 'h':
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            break;
                        default :
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            break;
                    }
                } else if (duration === 'daily') {
                    option = document.createElement('option');
                    content = document.createTextNode(textMapping['text']);
                    option.setAttribute('value', textMapping['value']);
                    option.setAttribute('data-minimum', textMapping['min']);
                    option.appendChild(content);
                    duration_list[textMapping['value']]=option;
                } else if (duration === 'tick') {
                    option = document.createElement('option');
                    content = document.createTextNode(textMapping['text']);
                    option.setAttribute('value', textMapping['value']);
                    option.setAttribute('data-minimum', textMapping['min']);
                    option.appendChild(content);
                    duration_list[textMapping['value']]=option;
                }
            }
        }
        var list = Object.keys(duration_list).sort(function(a,b){
            if(durationOrder(a)>durationOrder(b)){
                return 1;
            }
            else{
                return -1;
            }
        });
        for(var k=0; k<list.length; k++){
            var d = list[k];
            if(duration_list.hasOwnProperty(d)){
                target.appendChild(duration_list[d]);
            }
        }

        durationPopulate();
    };

    var durationTextValueMappings = function(str) {
        var mapping = {
            s : Content.localize().textDurationSeconds,
            m : Content.localize().textDurationMinutes,
            h : Content.localize().textDurationHours,
            d : Content.localize().textDurationDays,
            t : Content.localize().textDurationTicks
        };

        var arry = str ? str.toString().match(/[a-zA-Z]+|[0-9]+/g) : [],
            obj = {};

        if (arry.length > 1) {
            obj['value'] = arry[1];
            obj['text'] = mapping[arry[1]];
            obj['min'] = arry[0];
        } else {
            obj['value'] = 't';
            obj['text'] = mapping['t'];
            obj['min'] = arry[0];
        }

        return obj;
    };

    var durationPopulate = function() {
        var unit = document.getElementById('duration_units');
        if (isVisible(unit)) {
            var unitValue = unit.options[unit.selectedIndex].getAttribute('data-minimum');
            document.getElementById('duration_amount').value = unitValue;
            document.getElementById('duration_minimum').textContent = unitValue;
            displayExpiryType(unit.value);
        } else {
            displayExpiryType();
        }

        // jquery for datepicker
        var amountElement = $('#duration_amount');
        if (unit.value === 'd') {
            amountElement.datepicker({
                onSelect: function() {
                    var date = $(this).datepicker('getDate');
                    var today = new Date();
                    var dayDiff = Math.ceil((date - today) / (1000 * 60 * 60 * 24));
                    amountElement.val(dayDiff);
                    amountElement.trigger('change');
                }
            });
        } else {
            amountElement.datepicker("destroy");
        }

        // we need to call it here as for days we need to show absolute barriers
        Barriers.display();
    };

    var displayExpiryType = function(unit) {
        var target = document.getElementById('expiry_type'),
            fragment = document.createDocumentFragment();

        var current_selected = target.value || 'duration',
            id = current_selected,
            hideId = (current_selected === 'duration') ? 'endtime' : 'duration';

        id = document.getElementById('expiry_type_' + id);
        if (id) {
            id.style.display = 'flex';
        }
        // need to hide the non selected one
        hideId = document.getElementById('expiry_type_' + hideId);
        if (hideId) {
            hideId.style.display = 'none';
        }

        while (target && target.firstChild) {
            target.removeChild(target.firstChild);
        }

        var option = document.createElement('option'),
            content = document.createTextNode(Content.localize().textDuration);

        option.setAttribute('value', 'duration');
        if (current_selected === 'duration') {
            option.setAttribute('selected', 'selected');
        }
        option.appendChild(content);
        fragment.appendChild(option);

        if (unit !== 't') {
            option = document.createElement('option');
            content = document.createTextNode(Content.localize().textEndTime);
            option.setAttribute('value', 'endtime');
            if (current_selected === 'endtime') {
                option.setAttribute('selected', 'selected');
            }
            option.appendChild(content);
            fragment.appendChild(option);
        }
        target.appendChild(fragment);
    };

    var processTradingTimesAnswer = function(response){
        if(!trading_times.hasOwnProperty(response.echo_req.trading_times) && response.hasOwnProperty('trading_times') && response.trading_times.hasOwnProperty('markets')){
            for(var i=0; i<response.trading_times.markets.length; i++){
                var submarkets = response.trading_times.markets[i].submarkets;
                if(submarkets){
                    for(var j=0; j<submarkets.length; j++){
                        var symbols = submarkets[j].symbols;
                        if(symbols){
                            for(var k=0; k<symbols.length; k++){
                                var symbol = symbols[k];
                                if(!trading_times[response.echo_req.trading_times]){
                                    trading_times[response.echo_req.trading_times] = {};
                                }
                                trading_times[response.echo_req.trading_times][symbol.symbol] = symbol.times.close;
                            }
                        }
                    }
                }
            }
        }
    };

    return {
        display: displayDurations,
        populate: durationPopulate,
        setTime: function(time){ expiry_time = time; },
        getTime: function(){ return expiry_time; },
        processTradingTimesAnswer: processTradingTimesAnswer,
        trading_times: function(){ return trading_times; }
    };
})();

<commit_msg>duration_datepicker_fix<commit_after>/*
 * Handles duration processing display
 *
 * It process `Contract.durations()` and display them according to
 * the current `Contract.form()` and `Contract.barriers()`
 *
 * It also populate expiry type select box i.e Durations and Endtime select
 *
 */

var Durations = (function(){
    'use strict';

    var trading_times = {};
    var expiry_time = '';

    var displayDurations = function(startType) {
        var durations = Contract.durations();
        if (durations === false) {
            document.getElementById('expiry_row').style.display = 'none';
            return false;
        }

        var target = document.getElementById('duration_units'),
            formName = Contract.form(),
            barrierCategory = Contract.barrier(),
            fragment = document.createDocumentFragment(), durationContainer = {};

        while (target && target.firstChild) {
            target.removeChild(target.firstChild);
        }

        for (var key in durations) {
            if (durations.hasOwnProperty(key)) {
                for (var form in durations[key][formName]) {
                    if (durations[key][formName].hasOwnProperty(form)) {
                        var obj = {};
                        if (barrierCategory) {
                            obj = durations[key][formName][barrierCategory];
                        } else {
                            obj = durations[key][formName][form];
                        }
                        for (var type in obj) {
                            if (obj.hasOwnProperty(type)) {
                                if (startType) {
                                    if (startType === type) {
                                        if(!durationContainer.hasOwnProperty(startType)) {
                                            durationContainer[key] = obj[startType];
                                        }
                                    }
                                } else {
                                    if(!durationContainer.hasOwnProperty(type)) {
                                        durationContainer[key] = obj[type];
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        var duration_list = {};
        for (var duration in durationContainer) {
            if(durationContainer.hasOwnProperty(duration)) {
                var min = durationContainer[duration]['min_contract_duration'],
                    textMapping = durationTextValueMappings(min);

                var option, content;
                if (duration === 'intraday') {
                    switch (textMapping['value']) {
                        case 's':
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            option = document.createElement('option');
                            content = document.createTextNode(Content.localize().textDurationMinutes);
                            option.setAttribute('value', 'm');
                            option.setAttribute('data-minimum', 1);
                            option.setAttribute('selected', 'selected');
                            option.appendChild(content);
                            duration_list['m']=option;
                            option = document.createElement('option');
                            content = document.createTextNode(Content.localize().textDurationHours);
                            option.setAttribute('value', 'h');
                            option.setAttribute('data-minimum', 1);
                            option.appendChild(content);
                            duration_list['h']=option;
                            break;
                        case 'm':
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.setAttribute('selected', 'selected');
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            option = document.createElement('option');
                            content = document.createTextNode(Content.localize().textDurationHours);
                            option.setAttribute('value', 'h');
                            option.setAttribute('data-minimum', 1);
                            option.appendChild(content);
                            duration_list['h']=option;
                            break;
                        case 'h':
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            break;
                        default :
                            option = document.createElement('option');
                            content = document.createTextNode(textMapping['text']);
                            option.setAttribute('value', textMapping['value']);
                            option.setAttribute('data-minimum', textMapping['min']);
                            option.appendChild(content);
                            duration_list[textMapping['value']]=option;
                            break;
                    }
                } else if (duration === 'daily') {
                    option = document.createElement('option');
                    content = document.createTextNode(textMapping['text']);
                    option.setAttribute('value', textMapping['value']);
                    option.setAttribute('data-minimum', textMapping['min']);
                    option.appendChild(content);
                    duration_list[textMapping['value']]=option;
                } else if (duration === 'tick') {
                    option = document.createElement('option');
                    content = document.createTextNode(textMapping['text']);
                    option.setAttribute('value', textMapping['value']);
                    option.setAttribute('data-minimum', textMapping['min']);
                    option.appendChild(content);
                    duration_list[textMapping['value']]=option;
                }
            }
        }
        var list = Object.keys(duration_list).sort(function(a,b){
            if(durationOrder(a)>durationOrder(b)){
                return 1;
            }
            else{
                return -1;
            }
        });
        for(var k=0; k<list.length; k++){
            var d = list[k];
            if(duration_list.hasOwnProperty(d)){
                target.appendChild(duration_list[d]);
            }
        }

        durationPopulate();
    };

    var durationTextValueMappings = function(str) {
        var mapping = {
            s : Content.localize().textDurationSeconds,
            m : Content.localize().textDurationMinutes,
            h : Content.localize().textDurationHours,
            d : Content.localize().textDurationDays,
            t : Content.localize().textDurationTicks
        };

        var arry = str ? str.toString().match(/[a-zA-Z]+|[0-9]+/g) : [],
            obj = {};

        if (arry.length > 1) {
            obj['value'] = arry[1];
            obj['text'] = mapping[arry[1]];
            obj['min'] = arry[0];
        } else {
            obj['value'] = 't';
            obj['text'] = mapping['t'];
            obj['min'] = arry[0];
        }

        return obj;
    };

    var durationPopulate = function() {
        var unit = document.getElementById('duration_units');
        if (isVisible(unit)) {
            var unitValue = unit.options[unit.selectedIndex].getAttribute('data-minimum');
            document.getElementById('duration_amount').value = unitValue;
            document.getElementById('duration_minimum').textContent = unitValue;
            displayExpiryType(unit.value);
        } else {
            displayExpiryType();
        }

        // jquery for datepicker
        var amountElement = $('#duration_amount');
        if (unit.value === 'd') {
            var tomorrow = new Date();
            tomorrow.setDate(tomorrow.getDate() + 1);

            amountElement.datepicker({
                minDate: tomorrow,
                onSelect: function() {
                    var date = $(this).datepicker('getDate');
                    var today = new Date();
                    var dayDiff = Math.ceil((date - today) / (1000 * 60 * 60 * 24));
                    amountElement.val(dayDiff);
                    amountElement.trigger('change');
                }
            });
        } else {
            amountElement.datepicker("destroy");
        }

        // we need to call it here as for days we need to show absolute barriers
        Barriers.display();
    };

    var displayExpiryType = function(unit) {
        var target = document.getElementById('expiry_type'),
            fragment = document.createDocumentFragment();

        var current_selected = target.value || 'duration',
            id = current_selected,
            hideId = (current_selected === 'duration') ? 'endtime' : 'duration';

        id = document.getElementById('expiry_type_' + id);
        if (id) {
            id.style.display = 'flex';
        }
        // need to hide the non selected one
        hideId = document.getElementById('expiry_type_' + hideId);
        if (hideId) {
            hideId.style.display = 'none';
        }

        while (target && target.firstChild) {
            target.removeChild(target.firstChild);
        }

        var option = document.createElement('option'),
            content = document.createTextNode(Content.localize().textDuration);

        option.setAttribute('value', 'duration');
        if (current_selected === 'duration') {
            option.setAttribute('selected', 'selected');
        }
        option.appendChild(content);
        fragment.appendChild(option);

        if (unit !== 't') {
            option = document.createElement('option');
            content = document.createTextNode(Content.localize().textEndTime);
            option.setAttribute('value', 'endtime');
            if (current_selected === 'endtime') {
                option.setAttribute('selected', 'selected');
            }
            option.appendChild(content);
            fragment.appendChild(option);
        }
        target.appendChild(fragment);
    };

    var processTradingTimesAnswer = function(response){
        if(!trading_times.hasOwnProperty(response.echo_req.trading_times) && response.hasOwnProperty('trading_times') && response.trading_times.hasOwnProperty('markets')){
            for(var i=0; i<response.trading_times.markets.length; i++){
                var submarkets = response.trading_times.markets[i].submarkets;
                if(submarkets){
                    for(var j=0; j<submarkets.length; j++){
                        var symbols = submarkets[j].symbols;
                        if(symbols){
                            for(var k=0; k<symbols.length; k++){
                                var symbol = symbols[k];
                                if(!trading_times[response.echo_req.trading_times]){
                                    trading_times[response.echo_req.trading_times] = {};
                                }
                                trading_times[response.echo_req.trading_times][symbol.symbol] = symbol.times.close;
                            }
                        }
                    }
                }
            }
        }
    };

    return {
        display: displayDurations,
        populate: durationPopulate,
        setTime: function(time){ expiry_time = time; },
        getTime: function(){ return expiry_time; },
        processTradingTimesAnswer: processTradingTimesAnswer,
        trading_times: function(){ return trading_times; }
    };
})();

<|endoftext|>