<commit_before>/**
 * AnalyticsDashboardWidgetTopPagesTable 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.
 */

/**
 * External dependencies
 */
import classnames from 'classnames';
import PropTypes from 'prop-types';

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

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { getTimeInSeconds, numFmt } from '../../../../util';
import withData from '../../../../components/higherorder/withData';
import { STORE_NAME, DATE_RANGE_OFFSET } from '../../datastore/constants';
import { CORE_USER } from '../../../../googlesitekit/datastore/user/constants';
import { TYPE_MODULES } from '../../../../components/data';
import PreviewTable from '../../../../components/PreviewTable';
import { getTopPagesReportDataDefaults } from '../../util';
import TableOverflowContainer from '../../../../components/TableOverflowContainer';
import Link from '../../../../components/Link';
import { generateDateRangeArgs } from '../../util/report-date-range-args';
import ReportTable from '../../../../components/ReportTable';

const { useSelect } = Data;

const LegacyAnalyticsDashboardWidgetTopPagesTable = ( props ) => {
	const { data, colspan } = props;

	if ( ! data || ! data.length ) {
		return null;
	}

	if ( ! Array.isArray( data[ 0 ].data.rows ) ) {
		return null;
	}

	return (
		<div className={ classnames(
			'mdc-layout-grid__cell',
			`mdc-layout-grid__cell--span-${ colspan }`
		) }>
			<TableOverflowContainer>
				<ReportTable
					rows={ data[ 0 ].data.rows }
					columns={ tableColumns }
				/>
			</TableOverflowContainer>

	);
};

const tableColumns = [
	{
		title: __( 'Title', 'google-site-kit' ),
		description: __( 'Page Title', 'google-site-kit' ),
		primary: true,
		Component: ( { row } ) => {
			const [ title, url ] = row.dimensions;
			const serviceURL = useSelect( ( select ) => {
				const dateRangeDates = select( CORE_USER ).getDateRangeDates( {
					offsetDays: DATE_RANGE_OFFSET,
				} );
				return select( STORE_NAME ).getServiceReportURL( 'content-drilldown', {
					'explorer-table.plotKeys': '[]',
					'_r.drilldown': `analytics.pagePath:${ url }`,
					...generateDateRangeArgs( dateRangeDates ),
				} );
			} );
			return (
				<Link
					href={ serviceURL }
					external
					inherit
				>
					{ title }
				</Link>
			);
		},
	},
	{
		title: __( 'Pageviews', 'google-site-kit' ),
		description: __( 'Pageviews', 'google-site-kit' ),
		field: 'metrics.0.values.0',
		Component: ( { fieldValue } ) => numFmt( fieldValue, { style: 'decimal' } ),
	},
	{
		title: __( 'Unique Pageviews', 'google-site-kit' ),
		description: __( 'Unique Pageviews', 'google-site-kit' ),
		hideOnMobile: true,
		field: 'metrics.0.values.1',
		Component: ( { fieldValue } ) => numFmt( fieldValue, { style: 'decimal' } ),
	},
	{
		title: __( 'Bounce Rate', 'google-site-kit' ),
		description: __( 'Bounce Rate', 'google-site-kit' ),
		hideOnMobile: true,
		field: 'metrics.0.values.2',
		Component: ( { fieldValue } ) => numFmt( Number( fieldValue ) / 100, '%' ),
	},
];

LegacyAnalyticsDashboardWidgetTopPagesTable.propTypes = {
	data: PropTypes.array,
	colspan: PropTypes.number,
};

LegacyAnalyticsDashboardWidgetTopPagesTable.defaultProps = {
	data: null,
	colspan: 12,
};

export default withData(
	LegacyAnalyticsDashboardWidgetTopPagesTable,
	[
		{
			type: TYPE_MODULES,
			identifier: 'analytics',
			datapoint: 'report',
			data: getTopPagesReportDataDefaults(),
			priority: 1,
			maxAge: getTimeInSeconds( 'day' ),
			context: [ 'Single', 'Dashboard' ],
		},
	],
	<PreviewTable padding />,
	{ createGrid: true }
);
<commit_msg>Move columns into the legacy component.<commit_after>/**
 * AnalyticsDashboardWidgetTopPagesTable 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.
 */

/**
 * External dependencies
 */
import classnames from 'classnames';
import PropTypes from 'prop-types';

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

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { getTimeInSeconds, numFmt } from '../../../../util';
import withData from '../../../../components/higherorder/withData';
import { STORE_NAME, DATE_RANGE_OFFSET } from '../../datastore/constants';
import { CORE_USER } from '../../../../googlesitekit/datastore/user/constants';
import { TYPE_MODULES } from '../../../../components/data';
import PreviewTable from '../../../../components/PreviewTable';
import { getTopPagesReportDataDefaults } from '../../util';
import TableOverflowContainer from '../../../../components/TableOverflowContainer';
import Link from '../../../../components/Link';
import { generateDateRangeArgs } from '../../util/report-date-range-args';
import ReportTable from '../../../../components/ReportTable';

const { useSelect } = Data;

const LegacyAnalyticsDashboardWidgetTopPagesTable = ( props ) => {
	const { data, colspan } = props;

	if ( ! data || ! data.length ) {
		return null;
	}

	if ( ! Array.isArray( data[ 0 ].data.rows ) ) {
		return null;
	}

	const tableColumns = [
		{
			title: __( 'Title', 'google-site-kit' ),
			description: __( 'Page Title', 'google-site-kit' ),
			primary: true,
			Component: ( { row } ) => {
				const [ title, url ] = row.dimensions;
				const serviceURL = useSelect( ( select ) => {
					const dateRangeDates = select( CORE_USER ).getDateRangeDates( {
						offsetDays: DATE_RANGE_OFFSET,
					} );
					return select( STORE_NAME ).getServiceReportURL( 'content-drilldown', {
						'explorer-table.plotKeys': '[]',
						'_r.drilldown': `analytics.pagePath:${ url }`,
						...generateDateRangeArgs( dateRangeDates ),
					} );
				} );
				return (
					<Link
						href={ serviceURL }
						external
						inherit
					>
						{ title }
					</Link>
				);
			},
		},
		{
			title: __( 'Pageviews', 'google-site-kit' ),
			description: __( 'Pageviews', 'google-site-kit' ),
			field: 'metrics.0.values.0',
			Component: ( { fieldValue } ) => numFmt( fieldValue, { style: 'decimal' } ),
		},
		{
			title: __( 'Unique Pageviews', 'google-site-kit' ),
			description: __( 'Unique Pageviews', 'google-site-kit' ),
			hideOnMobile: true,
			field: 'metrics.0.values.1',
			Component: ( { fieldValue } ) => numFmt( fieldValue, { style: 'decimal' } ),
		},
		{
			title: __( 'Bounce Rate', 'google-site-kit' ),
			description: __( 'Bounce Rate', 'google-site-kit' ),
			hideOnMobile: true,
			field: 'metrics.0.values.2',
			Component: ( { fieldValue } ) => numFmt( Number( fieldValue ) / 100, '%' ),
		},
	];

	return (
		<div className={ classnames(
			'mdc-layout-grid__cell',
			`mdc-layout-grid__cell--span-${ colspan }`
		) }>
			<TableOverflowContainer>
				<ReportTable
					rows={ data[ 0 ].data.rows }
					columns={ tableColumns }
				/>
			</TableOverflowContainer>

	);
};

LegacyAnalyticsDashboardWidgetTopPagesTable.propTypes = {
	data: PropTypes.array,
	colspan: PropTypes.number,
};

LegacyAnalyticsDashboardWidgetTopPagesTable.defaultProps = {
	data: null,
	colspan: 12,
};

export default withData(
	LegacyAnalyticsDashboardWidgetTopPagesTable,
	[
		{
			type: TYPE_MODULES,
			identifier: 'analytics',
			datapoint: 'report',
			data: getTopPagesReportDataDefaults(),
			priority: 1,
			maxAge: getTimeInSeconds( 'day' ),
			context: [ 'Single', 'Dashboard' ],
		},
	],
	<PreviewTable padding />,
	{ createGrid: true }
);
<|endoftext|>


<commit_before>enyo.kind({
	name: "moon.sample.AccordionSample",
	classes: "moon enyo-unselectable enyo-fit",
	components: [
		{kind: 'moon.Scroller', classes: "enyo-fill moon-8h", components: [
			{kind: "moon.Divider", content: "Not In Group"},
			{components: [
				{kind: "moon.Accordion", content: "This is an accordion", components: [
					{content: "Item One"},
					{content: "Item Two"}
				]},
				{kind: "moon.Accordion", content: "Pre-expanded accordion", open:true, components: [
					{content: "Item Three"},
					{content: "Item Four"}
				]},
				{kind: "moon.Accordion", content: "This is an lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng title accordion", components: [
					{content: "Looooooooooooooooooooooooooooooooooooong Item One"},
					{content: "Loooooooooooooooooooooooooooooong Item Two"}
				]},
				{kind: "moon.Accordion", content: "Disabled accordion", disabled: true, components: [
					{content: "Item One"},
					{content: "Item Two"}
				]},
			]},
			{classes:"moon-1v"},
			{kind: "moon.Divider", content: "In Group"},
			{kind:"Group", highlander:true, components: [
				{kind: "moon.Accordion", content: "This is a grouped accordion", components: [
					{content: "Item One"},
					{content: "Item Two"}
				]},
				{kind: "moon.Accordion", open:true, content: "This is another grouped accordion", components: [
					{content: "Item Three"},
					{content: "Item Four"}
				]},
				{kind: "moon.Accordion", content: "This is another grouped accordion", components: [
					{content: "Item Five"},
					{content: "Item Six"}
				]},
				{kind: "moon.Accordion", content: "This is another lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng title accordion", components: [
					{content: "Looooooooooooooooooooooooooooooooooooong Item Three"},
					{content: "Loooooooooooooooooooooooooooooong Item Four"}
				]}
			]},
			{classes:"moon-1v"},
			{kind: "moon.Divider", content: "In Group using Grouped Selectable Items"},
			{kind: "Group", groupName:"menuItems", components: [
				{kind:"Group", groupName:"accordions", highlander:true, components: [
					{kind: "moon.Accordion", groupName:"accordions", content: "This is a grouped accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Item One", groupName:"menuItems"},
						{content: "Item Two", groupName:"menuItems"}
					]},
					{kind: "moon.Accordion", groupName:"accordions", open:true, content: "This is another grouped accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Item Three", groupName:"menuItems"},
						{content: "Item Four", groupName:"menuItems"}
					]},
					{kind: "moon.Accordion", groupName:"accordions", content: "This is another grouped accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Item Five", groupName:"menuItems"},
						{content: "Item Six", groupName:"menuItems"}
					]},
					{kind: "moon.Accordion", groupName:"accordions", content: "This is another lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng title accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Looooooooooooooooooooooooooooooooooooong Item Three", groupName:"menuItems"},
						{content: "Loooooooooooooooooooooooooooooong Item Four", groupName:"menuItems"}
					]}
				]}
			]}
		]}
	]
});
<commit_msg>Removing unnecessary comma in the Accordion Sample<commit_after>enyo.kind({
	name: "moon.sample.AccordionSample",
	classes: "moon enyo-unselectable enyo-fit",
	components: [
		{kind: 'moon.Scroller', classes: "enyo-fill moon-8h", components: [
			{kind: "moon.Divider", content: "Not In Group"},
			{components: [
				{kind: "moon.Accordion", content: "This is an accordion", components: [
					{content: "Item One"},
					{content: "Item Two"}
				]},
				{kind: "moon.Accordion", content: "Pre-expanded accordion", open:true, components: [
					{content: "Item Three"},
					{content: "Item Four"}
				]},
				{kind: "moon.Accordion", content: "This is an lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng title accordion", components: [
					{content: "Looooooooooooooooooooooooooooooooooooong Item One"},
					{content: "Loooooooooooooooooooooooooooooong Item Two"}
				]},
				{kind: "moon.Accordion", content: "Disabled accordion", disabled: true, components: [
					{content: "Item One"},
					{content: "Item Two"}
				]}
			]},
			{classes:"moon-1v"},
			{kind: "moon.Divider", content: "In Group"},
			{kind:"Group", highlander:true, components: [
				{kind: "moon.Accordion", content: "This is a grouped accordion", components: [
					{content: "Item One"},
					{content: "Item Two"}
				]},
				{kind: "moon.Accordion", open:true, content: "This is another grouped accordion", components: [
					{content: "Item Three"},
					{content: "Item Four"}
				]},
				{kind: "moon.Accordion", content: "This is another grouped accordion", components: [
					{content: "Item Five"},
					{content: "Item Six"}
				]},
				{kind: "moon.Accordion", content: "This is another lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng title accordion", components: [
					{content: "Looooooooooooooooooooooooooooooooooooong Item Three"},
					{content: "Loooooooooooooooooooooooooooooong Item Four"}
				]}
			]},
			{classes:"moon-1v"},
			{kind: "moon.Divider", content: "In Group using Grouped Selectable Items"},
			{kind: "Group", groupName:"menuItems", components: [
				{kind:"Group", groupName:"accordions", highlander:true, components: [
					{kind: "moon.Accordion", groupName:"accordions", content: "This is a grouped accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Item One", groupName:"menuItems"},
						{content: "Item Two", groupName:"menuItems"}
					]},
					{kind: "moon.Accordion", groupName:"accordions", open:true, content: "This is another grouped accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Item Three", groupName:"menuItems"},
						{content: "Item Four", groupName:"menuItems"}
					]},
					{kind: "moon.Accordion", groupName:"accordions", content: "This is another grouped accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Item Five", groupName:"menuItems"},
						{content: "Item Six", groupName:"menuItems"}
					]},
					{kind: "moon.Accordion", groupName:"accordions", content: "This is another lonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnng title accordion", defaultKind:"moon.SelectableItem", components: [
						{content: "Looooooooooooooooooooooooooooooooooooong Item Three", groupName:"menuItems"},
						{content: "Loooooooooooooooooooooooooooooong Item Four", groupName:"menuItems"}
					]}
				]}
			]}
		]}
	]
});
<|endoftext|>


<commit_before>var tour = new Tour({
  name: 'Tour',
  steps: [{
    element: 'label[title=\'Applications\']',
    title: 'Annotations',
    content: 'Opens the Annotation panel,'+
    ' where you can select which annotation set to view,'+
    ' name that annotation set, add optional notes about'+
    ' the annotation set, save the annotation set, and reset the panel to its original state.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Layers\']',
    title: 'Layer Manager',
    content: 'Opens the Layers Manager panel,'+
    ' where you can select which layers to view.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Home\']',
    title: 'Home',
    content: 'Return to the data table so that'+
    ' you can open another slide.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Draw\']',
    title: 'Draw',
    content: 'Draw thin lines, thick lines, or polygons on the image.'+
    ' To maintain the integrity of measurements, avoid drawing shapes that overlap or intersect one another.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Magnifier\']',
    title: 'Magnifier',
    content: 'The Magnifier works like a magnifying glass and allows'+
    ' you to see the slide at normal magnification (1.0), low magnification (0.5),'+
    ' or high magnification (2.0). Click a magnification level and place the'+
    ' bounding box on the area of the slide you want to magnify.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Measurement\']',
    title: 'Measurement',
    content: 'Drag this tool on the slide to learn the measurement in micrometers.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Share View\']',
    title: 'Share View',
    content: 'Opens a window with a URL to the current presentation state of the'+
    ' slide including the magnification level, layers that are currently open, and your position on the image.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Side By Side Viewer\']',
    title: 'Side By Side Viewer',
    content: 'Shows the Layer Manager panel, the left and right'+
    ' layers, and inset window. For the right and left layer, select which layer you want to view.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Heat Map\']',
    title: 'Heat Map',
    content: 'For a slide with heatmap data, opens the choices of heatmaps available,'+
    ' as well as ways of displaying the heatmaps.'+
    ' The gradient shows all of the values on the selected spectrum for the field you selected.'+
    ' Contains a heatmap edit pen function.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Labeling\']',
    title: 'Labeling',
    content: 'Use this tool to draw a circle or rectangle around a tumor region,'+
    ' measure an area on the slide, download labels, and submit a bug report.'+
    ' The Labeling tool has its own toolbar with tools in the following order from left to right:'+
    ' return to the previous slide, place a square on the slide, place a circle on the slide,'+
    ' measure an area, download labels, and submit a bug report.'+
    ' Click the left arrow at the far right of the toolbar to hide it,'+
    ' then click the right arrow to show it.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Segment\']',
    title: 'Segment',
    content: 'This tool allows you to display, count, and export nuclear segmentations on the image.'+
    ' Clicking this tool opens the following custom toolbar.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Predict\']',
    title: 'Model',
    content: 'Show results from a pre-trained tensorflow compatible model on a ROI of the slide.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Download Slide\']',
    title: 'Download Slide',
    content:
        'Download the slide image to your system',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Bug Report\']',
    title: 'Bug Report',
    content: 'Report a bug or give feedback.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Tutorial\']',
    title: 'Tutorial',
    content: 'Click here to start viewer Tour.',
    placement: 'auto bottom',
    smartPlacement: true,
  }],
  template: '

'+
  '

'+
  '

'+
  '

'+
  '
<button class=\'btn btn-default\' data-role=\'prev\'>'+
  '« Prev</button>|'+
  '<button class=\'btn btn-default\' data-role=\'next\'>Next »</button>
'+
  '

'+
  '<button class=\'btn btn-default\' data-role=\'end\' style=\'margin:auto;\'>End tour</button>

',
  backdrop: true,
});
tour.init();
<commit_msg>improve tour resume UX<commit_after>var tour = new Tour({
  name: 'Tour',
  steps: [{
    element: 'label[title=\'Applications\']',
    title: 'Annotations',
    content: 'Opens the Annotation panel,'+
    ' where you can select which annotation set to view,'+
    ' name that annotation set, add optional notes about'+
    ' the annotation set, save the annotation set, and reset the panel to its original state.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Layers\']',
    title: 'Layer Manager',
    content: 'Opens the Layers Manager panel,'+
    ' where you can select which layers to view.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Home\']',
    title: 'Home',
    content: 'Return to the data table so that'+
    ' you can open another slide.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Draw\']',
    title: 'Draw',
    content: 'Draw thin lines, thick lines, or polygons on the image.'+
    ' To maintain the integrity of measurements, avoid drawing shapes that overlap or intersect one another.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Magnifier\']',
    title: 'Magnifier',
    content: 'The Magnifier works like a magnifying glass and allows'+
    ' you to see the slide at normal magnification (1.0), low magnification (0.5),'+
    ' or high magnification (2.0). Click a magnification level and place the'+
    ' bounding box on the area of the slide you want to magnify.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Measurement\']',
    title: 'Measurement',
    content: 'Drag this tool on the slide to learn the measurement in micrometers.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Share View\']',
    title: 'Share View',
    content: 'Opens a window with a URL to the current presentation state of the'+
    ' slide including the magnification level, layers that are currently open, and your position on the image.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'label[title=\'Side By Side Viewer\']',
    title: 'Side By Side Viewer',
    content: 'Shows the Layer Manager panel, the left and right'+
    ' layers, and inset window. For the right and left layer, select which layer you want to view.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Heat Map\']',
    title: 'Heat Map',
    content: 'For a slide with heatmap data, opens the choices of heatmaps available,'+
    ' as well as ways of displaying the heatmaps.'+
    ' The gradient shows all of the values on the selected spectrum for the field you selected.'+
    ' Contains a heatmap edit pen function.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Labeling\']',
    title: 'Labeling',
    content: 'Use this tool to draw a circle or rectangle around a tumor region,'+
    ' measure an area on the slide, download labels, and submit a bug report.'+
    ' The Labeling tool has its own toolbar with tools in the following order from left to right:'+
    ' return to the previous slide, place a square on the slide, place a circle on the slide,'+
    ' measure an area, download labels, and submit a bug report.'+
    ' Click the left arrow at the far right of the toolbar to hide it,'+
    ' then click the right arrow to show it.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Segment\']',
    title: 'Segment',
    content: 'This tool allows you to display, count, and export nuclear segmentations on the image.'+
    ' Clicking this tool opens the following custom toolbar.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Predict\']',
    title: 'Model',
    content: 'Show results from a pre-trained tensorflow compatible model on a ROI of the slide.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Download Slide\']',
    title: 'Download Slide',
    content:
        'Download the slide image to your system',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Bug Report\']',
    title: 'Bug Report',
    content: 'Report a bug or give feedback.',
    placement: 'auto bottom',
    smartPlacement: true,
  },
  {
    element: 'i[title=\'Tutorial\']',
    title: 'Tutorial',
    content: 'Click here to start viewer Tour.',
    placement: 'auto bottom',
    smartPlacement: true,
  }],
  template: '

'+
  '

'+
  '

'+
  '

'+
  '
<button class=\'btn btn-default\' data-role=\'prev\'>'+
  '« Prev</button>|'+
  '<button class=\'btn btn-default\' data-role=\'next\'>Next »</button>
'+
  '

'+
  '<button class=\'btn btn-default\' data-role=\'end\' style=\'margin:auto;\'>End tour</button>

',
  backdrop: true,
  //resets tour always to resume always from the beginning
  onEnd: function reset(){
    window.localStorage.setItem('Tour_current_step',0);
  }
});
tour.init();
<|endoftext|>


<commit_before>'use strict';

const assert = require('assert');
const TeamValidator = require('../../sim/team-validator');

describe('Team Validator features', function () {
	describe('TeamValidator', function () {
		it('should reject non-existent Pokemon', function () {
			let team = [{species:'nonexistentPokemon', moves:['thunderbolt']}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent items', function () {
			let team = [{species:'pikachu', moves:['thunderbolt'], ability:'static', item:'nonexistentItem'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent abilities', function () {
			let team = [{species:'pikachu', moves:['thunderbolt'], ability:'nonexistentAbility'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent moves', function () {
			let team = [{species:'pikachu', ability:'static', moves:['nonexistentMove']}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent natures', function () {
			let team = [{species:'pikachu', ability:'static', moves:['thunderbolt'], nature:'nonexistentNature'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject invalid happiness values', function () {
			let team = [{species:'pikachu', ability:'static', moves:['thunderbolt'], happiness:'invalidHappinessValue'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should accept legal movesets', function () {
			let team = [{species:'pikachu', ability:'static', moves:['agility', 'protect', 'thunder', 'thunderbolt']}];
			let illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert(!illegal);
		});

		it('should reject illegal movesets', function () {
			let team = [{species:'pikachu', ability:'static', moves:['blastburn', 'frenzyplant', 'hydrocannon', 'dragonascent']}];
			let illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert(illegal);
		});

		it('should accept both ability types for Mega Evolutions', function () {
			// base forme ability
			let team = [{species:'gyaradosmega', item:'gyaradosite', ability:'intimidate', moves:['dragondance', 'crunch', 'waterfall', 'icefang']}];
			let illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert(!illegal);

			// mega forme ability
			team = [{species:'gyaradosmega', item:'gyaradosite', ability:'moldbreaker', moves:['dragondance', 'crunch', 'waterfall', 'icefang']}];
			illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert(!illegal);
		});

		it('should reject newer Pokemon in older gens', function () {
			let team = [{species:'pichu', ability:'static', moves:['thunderbolt']}];
			let illegal = TeamValidator('gen1ou').validateTeam(team);
			assert(illegal);
		});
	});
});
<commit_msg>Add more tests for team validator<commit_after>'use strict';

const assert = require('assert');
const TeamValidator = require('../../sim/team-validator');

describe('Team Validator features', function () {
	describe('TeamValidator', function () {
		it('should reject non-existent Pokemon', function () {
			let team = [{species:'nonexistentPokemon', moves:['thunderbolt']}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent items', function () {
			let team = [{species:'pikachu', moves:['thunderbolt'], ability:'static', item:'nonexistentItem'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent abilities', function () {
			let team = [{species:'pikachu', moves:['thunderbolt'], ability:'nonexistentAbility'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent moves', function () {
			let team = [{species:'pikachu', ability:'static', moves:['nonexistentMove']}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject non-existent natures', function () {
			let team = [{species:'pikachu', ability:'static', moves:['thunderbolt'], nature:'nonexistentNature'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should reject invalid happiness values', function () {
			let team = [{species:'pikachu', ability:'static', moves:['thunderbolt'], happiness:'invalidHappinessValue'}];
			let illegal = TeamValidator('gen7customgame').validateTeam(team);
			assert(illegal);
		});

		it('should accept legal movesets', function () {
			let team = [{species:'pikachu', ability:'static', moves:['agility', 'protect', 'thunder', 'thunderbolt']}];
			let illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert.strictEqual(illegal, false);

			team = [{species:'meowstic', ability:'prankster', moves:['trick', 'magiccoat']}];
			illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert.strictEqual(illegal, false);
		});

		it('should reject illegal movesets', function () {
			let team = [{species:'pikachu', ability:'static', moves:['blastburn', 'frenzyplant', 'hydrocannon', 'dragonascent']}];
			let illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert(illegal);
		});

		it('should reject illegal egg move combinations', function () {
			let team = [{species:'azumarill', ability:'hugepower', moves:['bellydrum', 'aquajet']}];
			let illegal = TeamValidator('gen5ou').validateTeam(team);
			assert(illegal);
		});

		it('should accept both ability types for Mega Evolutions', function () {
			// base forme ability
			let team = [{species:'gyaradosmega', item:'gyaradosite', ability:'intimidate', moves:['dragondance', 'crunch', 'waterfall', 'icefang']}];
			let illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert.strictEqual(illegal, false);

			// mega forme ability
			team = [{species:'gyaradosmega', item:'gyaradosite', ability:'moldbreaker', moves:['dragondance', 'crunch', 'waterfall', 'icefang']}];
			illegal = TeamValidator('gen7anythinggoes').validateTeam(team);
			assert.strictEqual(illegal, false);
		});

		it('should reject newer Pokemon in older gens', function () {
			let team = [{species:'pichu', ability:'static', moves:['thunderbolt']}];
			let illegal = TeamValidator('gen1ou').validateTeam(team);
			assert(illegal);
		});
	});
});
<|endoftext|>


<commit_before>import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';
import { expect } from 'chai'

import FullApp from '../../../src/containers/FullApp';
import SummaryHeader from '../../../src/summary/SummaryHeader';
import TargetedDataSection from '../../../src/summary/TargetedDataSection';
import Button from '../../../src/elements/Button';
import SummaryMetadata from '../../../src/summary/SummaryMetadata';
import VisualizerManager from '../../../src/summary/VisualizerManager';
import TabularNameValuePairsVisualizer from '../../../src/summary/NarrativeNameValuePairsVisualizer';

Enzyme.configure({ adapter: new Adapter() });

describe('UpdateErrors', function () {
    it('should set state.errors to equal the provided argument', function () {
        const wrapper = shallow(<FullApp />);
        const emptyErrors = [];
        wrapper.instance().updateErrors(emptyErrors);
        expect(wrapper.state('errors'))
            .to.be.an('array')
            .and.to.be.empty;

        const newErrors = ["anything", "anything else"];
        wrapper.instance().updateErrors(newErrors);
        expect(wrapper.state('errors'))
            .to.equal(newErrors);
    });
});

describe('setFullAppState', function() {
    it('sets the state on the component', function() {
        const wrapper = shallow(<FullApp />);

        wrapper.instance().setFullAppState('testKey', 'testValue');
        expect(wrapper.state('testKey'))
            .to.eq('testValue');
    });
});

// describe('SummaryHeader', function() {
//     it('View buttons update state', function() {
//         const wrapper = shallow(<SummaryHeader />);

//         // // Initial state
//         // expect(wrapper.state('layout'))
//         //     .to.eq('none');

//         // // Clicking a View button changes the state
//         // const leftView = wrapper.find(Button).find('#left-collapsed-layout-button');
//         // leftView.simulate('click');
//         // expect(wrapper.state('layout'))
//         //   .to.eq('left');
//     });
// });

describe('TargetedDataControl', function() {
    it('noteDisplayMode buttons update state', function() {
        const summaryMetadata = new SummaryMetadata();
        const section = summaryMetadata.hardCodedMetadata["http://snomed.info/sct/408643008"].sections[0];
        let options = [];
        if (section.type === "NameValuePairs") {
            options.push('tabular');
            if (section.narrative) {
                options.push('narrative');
            }
        } else if (section.type === "Events") {
            options.push('timeline');
        }
        const defaultOrTabular = options.length > 0 ? options[0] : 'tabular';

        const visualizerManager = new VisualizerManager()
        const wrapper = shallow(<TargetedDataSection section={section} type={section.type} visualizerManager={visualizerManager} />);

        // Initial state
        expect(wrapper.state('defaultVisualizer'))
            .to.eq(defaultOrTabular);
        expect(wrapper.state('chosenVisualizer'))
            .to.be.null;

        // Clicking the non-default note display button changes the state
        const narrativeIcon = wrapper.find('.right-icons').find(Button).find('#narrative');
        narrativeIcon.simulate('click');
        expect(wrapper.state('chosenVisualizer'))
            .to.eq('narrative');
    });
});
<commit_msg>Fixed failing test<commit_after>import React from 'react';
import Enzyme, { shallow } from 'enzyme';
import Adapter from 'enzyme-adapter-react-15';
import { expect } from 'chai'

import FullApp from '../../../src/containers/FullApp';
import SummaryHeader from '../../../src/summary/SummaryHeader';
import TargetedDataSection from '../../../src/summary/TargetedDataSection';
import Button from '../../../src/elements/Button';
import SummaryMetadata from '../../../src/summary/SummaryMetadata';
import VisualizerManager from '../../../src/summary/VisualizerManager';
import TabularNameValuePairsVisualizer from '../../../src/summary/NarrativeNameValuePairsVisualizer';

Enzyme.configure({ adapter: new Adapter() });

describe('UpdateErrors', function () {
    it('should set state.errors to equal the provided argument', function () {
        const wrapper = shallow(<FullApp />);
        const emptyErrors = [];
        wrapper.instance().updateErrors(emptyErrors);
        expect(wrapper.state('errors'))
            .to.be.an('array')
            .and.to.be.empty;

        const newErrors = ["anything", "anything else"];
        wrapper.instance().updateErrors(newErrors);
        expect(wrapper.state('errors'))
            .to.equal(newErrors);
    });
});

describe('setFullAppState', function() {
    it('sets the state on the component', function() {
        const wrapper = shallow(<FullApp />);

        wrapper.instance().setFullAppState('testKey', 'testValue');
        expect(wrapper.state('testKey'))
            .to.eq('testValue');
    });
});

// describe('SummaryHeader', function() {
//     it('View buttons update state', function() {
//         const wrapper = shallow(<SummaryHeader />);

//         // // Initial state
//         // expect(wrapper.state('layout'))
//         //     .to.eq('none');

//         // // Clicking a View button changes the state
//         // const leftView = wrapper.find(Button).find('#left-collapsed-layout-button');
//         // leftView.simulate('click');
//         // expect(wrapper.state('layout'))
//         //   .to.eq('left');
//     });
// });

describe('TargetedDataControl', function() {
    it('noteDisplayMode buttons update state', function() {
        const summaryMetadata = new SummaryMetadata();
        // Top item is Reason for Visit which has no buttons, so look at second item Summary which is .sections[1]
        const section = summaryMetadata.hardCodedMetadata["http://snomed.info/sct/408643008"].sections[1];
        let options = [];
        if (section.type === "NameValuePairs") {
            options.push('tabular');
            if (section.narrative) {
                options.push('narrative');
            }
        } else if (section.type === "Events") {
            options.push('timeline');
        }
        const defaultOrTabular = options.length > 0 ? options[0] : 'tabular';

        const visualizerManager = new VisualizerManager()
        const wrapper = shallow(<TargetedDataSection section={section} type={section.type} visualizerManager={visualizerManager} />);

        // Initial state
        expect(wrapper.state('defaultVisualizer'))
            .to.eq(defaultOrTabular);
        expect(wrapper.state('chosenVisualizer'))
            .to.be.null;

        // Clicking the non-default note display button changes the state
        const narrativeIcon = wrapper.find('.right-icons').find(Button).find('#narrative');
        narrativeIcon.simulate('click');
        expect(wrapper.state('chosenVisualizer'))
            .to.eq('narrative');
    });
});
<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2015 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

var juju = {components: {}}; // eslint-disable-line no-unused-vars
var testUtils = React.addons.TestUtils;

describe('UserProfileList', () => {

  beforeAll((done) => {
    // By loading this file it adds the component to the juju components.
    YUI().use('user-profile-list', () => { done(); });
  });

  it('renders without data', () => {
    var data = [];
    var count = 0;
    var switchEnv = sinon.stub();
    var output = jsTestUtils.shallowRender(
      <juju.components.UserProfileList
        title="Test List"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}/>);
    var expected = (

          Test List

            {' '} ({count})

        <juju.components.Spinner />

);

    assert.deepEqual(output, expected);
  });

  it('renders with data', () => {
    var data = [{
      uuid: 'abc123',
      ship: 'tardis',
      pilot: 'the dr'
    }, {
      uuid: '123abc',
      ship: 'nebekenezer',
      pilot: 'dozer'
    }];
    var count = 2;
    var switchEnv = sinon.stub();
    var renderer = jsTestUtils.shallowRender(
      <juju.components.UserProfileList
        title="TestList"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}/>, true);
    var output = renderer.getRenderOutput();
    var instance = renderer.getMountedInstance();
    var expected = (

          TestList

            {' '} ({count})

              uuid

              ship

              pilot

              {data[0].uuid}

              {data[0].ship}

              {data[0].pilot}

              {data[1].uuid}

              {data[1].ship}

              {data[1].pilot}

);

    assert.deepEqual(output, expected);
  });

  it('respects key whitelist if supplied', function() {
    var data = [{
      uuid: 'abc123',
      ship: 'tardis',
      pilot: 'the dr'
    }];
    var count = 1;
    var switchEnv = sinon.stub();
    var whitelist = ['uuid', 'ship'];
    var renderer = jsTestUtils.shallowRender(
      <juju.components.UserProfileList
        title="TestList"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}
        whitelist={whitelist}/>, true);
    var output = renderer.getRenderOutput();
    var instance = renderer.getMountedInstance();
    var expected = (

          TestList

            {' '} ({count})

              uuid

              ship

              {data[0].uuid}

              {data[0].ship}

);

    assert.deepEqual(output, expected);
  });

  it('calls to switch envs when clicking on row', function() {
    var data = [{
      uuid: 'abc123',
      ship: 'tardis',
      pilot: 'the dr'
    }];
    var switchEnv = sinon.stub();
    var component = testUtils.renderIntoDocument(
      <juju.components.UserProfileList
        title="TestList"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}/>);
    testUtils.Simulate.click(
      ReactDOM.findDOMNode(component)
              .querySelector('.user-profile-list__item-row'));
    assert.equal(switchEnv.callCount, 1);
    assert.equal(switchEnv.args[0][0], 'abc123');
  });

});
<commit_msg>Updated the user profile list tests<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2015 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

var juju = {components: {}}; // eslint-disable-line no-unused-vars
var testUtils = React.addons.TestUtils;

describe('UserProfileList', () => {

  beforeAll((done) => {
    // By loading this file it adds the component to the juju components.
    YUI().use('user-profile-list', () => { done(); });
  });

  it('renders without data', () => {
    var data = [];
    var count = 0;
    var switchEnv = sinon.stub();
    var output = jsTestUtils.shallowRender(
      <juju.components.UserProfileList
        title="Test List"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}/>);
    var expected = (

          Test List

            {' '} ({count})

        <juju.components.Spinner />

);

    assert.deepEqual(output, expected);
  });

  it('renders with data', () => {
    var data = [{
      uuid: 'abc123',
      ship: 'tardis',
      pilot: 'the dr'
    }, {
      uuid: '123abc',
      ship: 'nebekenezer',
      pilot: 'dozer'
    }];
    var count = 2;
    var switchEnv = sinon.stub();
    var renderer = jsTestUtils.shallowRender(
      <juju.components.UserProfileList
        title="TestList"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}/>, true);
    var output = renderer.getRenderOutput();
    var instance = renderer.getMountedInstance();
    var expected = (

          TestList

            {' '} ({count})

              uuid

              ship

              pilot

              {data[0].uuid}

              {data[0].ship}

              {data[0].pilot}

              {data[1].uuid}

              {data[1].ship}

              {data[1].pilot}

);

    assert.deepEqual(output, expected);
  });

  it('respects key whitelist if supplied', function() {
    var data = [{
      uuid: 'abc123',
      ship: 'tardis',
      pilot: 'the dr'
    }];
    var count = 1;
    var switchEnv = sinon.stub();
    var whitelist = ['uuid', 'ship'];
    var renderer = jsTestUtils.shallowRender(
      <juju.components.UserProfileList
        title="TestList"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}
        whitelist={whitelist}/>, true);
    var output = renderer.getRenderOutput();
    var instance = renderer.getMountedInstance();
    var expected = (

          TestList

            {' '} ({count})

              uuid

              ship

              {data[0].uuid}

              {data[0].ship}

);

    assert.deepEqual(output, expected);
  });

  it('calls to switch envs when clicking on row', function() {
    var data = [{
      uuid: 'abc123',
      ship: 'tardis',
      name: 'the dr'
    }];
    var switchEnv = sinon.stub();
    var component = testUtils.renderIntoDocument(
      <juju.components.UserProfileList
        title="TestList"
        data={data}
        uuidKey="uuid"
        switchEnv={switchEnv}/>);
    testUtils.Simulate.click(
      ReactDOM.findDOMNode(component)
              .querySelector('.user-profile-list__item-row'));
    assert.equal(switchEnv.callCount, 1);
    assert.deepEqual(switchEnv.args[0], ['abc123', 'the dr']);
  });

});
<|endoftext|>


<commit_before>var client = new Dropbox.Client({
	key: config.dropbox
});

client.authenticate({
	interactive: false
}, function (error) {
	if (error) {
		createError({
			error: 'Authentication error',
			api_response: error,
			action: "please log in to Dropbox and try again"
		});
	}
});

function getPref(prefName, callback) {
	if (!window.preferences) { //there aren't cached preferences
		client.readFile("/userdata/preferences.json",
			function (error, data) {
				if (error) { //this assumes the error is that there is no preferences file
					client.writeFile("/userdata/preferences.json", "{}");
					window.preferences = {};
				} else {
					window.preferences = JSON.parse(data);
				}

				callback(window.preferences[prefName]);
			});
	} else { //there are cached preferences
		callback(window.preferences[prefName]);
	}
}

/* this assumes getPref has been called first, which is usually true */

function setPref(prefName, value) {
	window.preferences[prefName] = value;
	client.writeFile("/userdata/preferences.json", JSON.stringify(window.preferences));
}<commit_msg>better error handling when loading preferences<commit_after>var client = new Dropbox.Client({
	key: config.dropbox
});

client.authenticate({
	interactive: false
}, function (error) {
	if (error) {
		createError({
			error: 'Authentication error',
			api_response: error,
			action: "please log in to Dropbox and try again"
		});
	}
});

function getPref(prefName, callback) {
	if (!window.preferences) { //there aren't cached preferences
		client.readFile("/userdata/preferences.json",
			function (error, data) {
				if (error && error.status == Dropbox.ApiError.NOT_FOUND) { //there is no preferences file
					client.writeFile("/userdata/preferences.json", "{}");
					window.preferences = {};
				} else if (error) { //we couldn't load the perferences. Use the defaults instead
					window.preferences = {};
				} else {
					window.preferences = JSON.parse(data);
				}

				callback(window.preferences[prefName]);
			});
	} else { //there are cached preferences
		callback(window.preferences[prefName]);
	}
}

/* this assumes getPref has been called first, which is usually true */

function setPref(prefName, value) {
	window.preferences[prefName] = value;
	client.writeFile("/userdata/preferences.json", JSON.stringify(window.preferences));
}<|endoftext|>


<commit_before>function GloballyPinnedTabs(tabs) {
    this.tabs = tabs;
    this.activeTab = tabs.filter(function(x) { return x.realTab && x.realTab.active; })[0];
}

GloballyPinnedTabs.create = function(serializedTabs) {
    serializedTabs = serializedTabs || [{
        startupUrl: 'https://www.toggl.com/app/timer'
    }, {
        startupUrl: 'https://www.beeminder.com/danielhilgarth'
    }];

    var result = new GloballyPinnedTabs(serializedTabs.map(function(x) {
        return new GloballyPinnedTab(x.startupUrl, x.currentUrl, x.favIconUrl, x.title);
    }));

    var onCloseCallback = function(pinnedTab) {
        result.onPinnedTabClosed(pinnedTab);
    };
    for (var i = 0; i < result.tabs.length; i++)
        result.tabs[i].onCloseCallback = onCloseCallback;

    return result;
};

GloballyPinnedTabs.prototype = {
    serialize: function() {
        return this.tabs.map(GloballyPinnedTab.serialize);
    },

    addTab: function(tab) {
        var self = this;
        var newTab = new GloballyPinnedTab(tab.url, tab.url, tab.favIconUrl, tab.title, function(pinnedTab) {
            self.onPinnedTabClosed(pinnedTab);
        });
        this.tabs.push(newTab);
        Storage.persistData();
        Chrome.getAllWindows(function(windows) { newTab.createTabs(windows); });
    },

    createTabs: function(windows) {
        for (var i = 0; i < this.tabs.length; i++)
            this.tabs[i].createTabs(windows);
    },

    findTab: function(url) {
        return this.tabs.filter(function(x) { return x.startupUrl === url; })[0];
    },

    activateWindow: function(window, callback) {
        if(this.tabs.length === 0) {
            callback();
            return;
        }

        var oldWindowId;
        if(this.tabs[0].realTab)
            oldWindowId = this.tabs[0].realTab.windowId;

        if(oldWindowId === window.id) {
            callback();
            return;
        }

        if(oldWindowId !== undefined) {
            var self = this;
            Chrome.getWindow(oldWindowId, function (oldWindow) {
                self.moveTabs(window, oldWindow, callback);
            });
        }
        else
            this.recreateTabs(window, callback);
    },

    recreateTabs: function(targetWindow, callback) {
        var dummyTabs = this.getDummyTabsForWindow(targetWindow, false);
        var dummyTabIds = dummyTabs.map(function(x) { return x.id; });
        Chrome.removeTabs(dummyTabIds);
        for (var i = 0; i < this.tabs.length; i++)
            this.tabs[i].createRealTab(targetWindow, callback, true); // Bug (callback)
    },

    getDummyTabsForWindow: function(window) {
        var result = {
            foundTabs: [],
            missingTabs: []
        };
        for (var i = 0; i < this.tabs.length; i++) {
            var tab = this.tabs[i];
            var dummyTab = tab.dummyTabs[window.id];
            if(!dummyTab)
                result.missingTabs.push(tab);
            else
                result.foundTabs.push(dummyTab);
        }

        return result;
    },

    moveTabs: function(targetWindow, sourceWindow, callback) {

        var dummyTabs = this.getDummyTabsForWindow(targetWindow);
        var dummyTabIds = [];
        var smallestDummyTabsIndex = 10000;
        var i;
        var tab;
        var tabToActivate;
        for (i = 0; i < dummyTabs.foundTabs.length; i++) {
            tab = dummyTabs.foundTabs[i];
            dummyTabIds.push(tab.id);
            smallestDummyTabsIndex = Math.min(smallestDummyTabsIndex, tab.index);
            if(tab.active) {
                var startupUrl = QueryParameters.getQueryParameters(QueryParameters.getQueryString(tab.url)).startupUrl;
                tabToActivate = this.findTab(startupUrl);
            }
        }

        var realTabIds = [];
        var smallestRealTabsIndex = 10000;
        for (i = 0; i < this.tabs.length; i++) {
            tab = this.tabs[i];
            realTabIds.push(tab.realTab.id);
            smallestRealTabsIndex = Math.min(smallestRealTabsIndex, tab.realTab.index);
        }

        var finished = 0;
        var total = realTabIds.length + dummyTabs.foundTabs.length + dummyTabs.missingTabs.length;
        var self = this;

        var temporaryTabIds = [];

        var callCallback = function() {
            finished++;
            if(finished === total) {
                if(temporaryTabIds.length) {
                    Chrome.removeTabs(temporaryTabIds, function () {
                        if(tabToActivate)
                            tabToActivate.activate(callback);
                        else
                            callback();
                    });
                }
                if(tabToActivate)
                    tabToActivate.activate(callback);
                else
                    callback();
            }
        };

        var performMove = function() {
            Chrome.moveTabs(realTabIds, targetWindow.id, smallestRealTabsIndex, function(tabs) {
                if(dummyTabs.missingTabs.length) {
                    Chrome.getWindow(sourceWindow.id, function(window) {
                        for (i = 0; i < dummyTabs.missingTabs.length; i++) {
                            dummyTabs.missingTabs[i].createTabForWindow(window, callCallback);
                        }
                    })
                }
                for (var i = 0; i < tabs.length; ++i) {
                    self.tabs[i].realTab = tabs[i];
                    Chrome.pinTab(tabs[i].id, callCallback);
                }
            });

            if(dummyTabIds.length) {
                Chrome.moveTabs(dummyTabIds, sourceWindow.id, smallestDummyTabsIndex, function (tabs) {
                    for (var i = 0; i < tabs.length; ++i) {
                        delete self.tabs[i].dummyTabs[targetWindow.id];
                        self.tabs[i].dummyTabs[sourceWindow.id] = tabs[i];
                        Chrome.pinTab(tabs[i].id, callCallback);
                    }
                });
            }
        };

        var createPinnedTabInTargetWindow = function() {
            if(targetWindow.tabs.length === (self.tabs.length - dummyTabs.missingTabs.length)) {
                Chrome.createPinnedTab(targetWindow, 'about:blank', function (tab) {
                    temporaryTabIds.push(tab.id);
                    performMove();
                });
            }
            else
                performMove();
        };

        if(sourceWindow.tabs.length === this.tabs.length) {
            Chrome.createPinnedTab(sourceWindow, 'about:blank', function(tab) {
                temporaryTabIds.push(tab.id);
                createPinnedTabInTargetWindow();
             });
        } else {
            createPinnedTabInTargetWindow();
        }
    },

    updateTab: function(tab) {
        var pinnedTab = this.getTabForIdOfRealTab(tab.id);
        if(pinnedTab) {
            if(pinnedTab.updateRealTab(tab))
                Storage.persistData();
        } else {
            pinnedTab = this.getTabForAnyTabId(tab.id);
            if(pinnedTab)
                pinnedTab.updateDummyTab(tab);
        }
    },

    getTabForIdOfRealTab: function(realTabId) {
        return this.tabs.filter(function(x) { return x.realTab && (x.realTab.id === realTabId); })[0];
    },

    getTabForAnyTabId: function(tabId) {
        return this.tabs.filter(function(x) {
            if (x.realTab && (x.realTab.id === tabId))
                return true;
            for (var key in x.dummyTabs) {
                if (x.dummyTabs[key].id === tabId) {
                    return true;
                }
            }
        })[0];
    },

    handleClosedTab: function(tabId) {
        var tab = this.getTabForAnyTabId(tabId);
        if (tab) {
            if (tab.realTab && (tab.realTab.id === tabId))
                tab.realTab = undefined;
            else {
                for (var key in tab.dummyTabs) {
                    if (tab.dummyTabs[key].id === tabId) {
                        delete tab.dummyTabs[key];
                        break;
                    }
                }
            }
            tab.close();
        }
    },

    handleClosedWindow: function(windowId) {
        for (var i = 0; i < this.tabs.length; i++)
            this.tabs[i].handleClosedWindow(windowId);
    },

    onPinnedTabClosed: function(pinnedTab) {
        this.tabs.remove(pinnedTab);
        Storage.persistData();
    }
};<commit_msg>Fix bugs when closing window<commit_after>function GloballyPinnedTabs(tabs) {
    this.tabs = tabs;
    this.activeTab = tabs.filter(function(x) { return x.realTab && x.realTab.active; })[0];
}

GloballyPinnedTabs.create = function(serializedTabs) {
    serializedTabs = serializedTabs || [{
        startupUrl: 'https://www.toggl.com/app/timer'
    }, {
        startupUrl: 'https://www.beeminder.com/danielhilgarth'
    }];

    var result = new GloballyPinnedTabs(serializedTabs.map(function(x) {
        return new GloballyPinnedTab(x.startupUrl, x.currentUrl, x.favIconUrl, x.title);
    }));

    var onCloseCallback = function(pinnedTab) {
        result.onPinnedTabClosed(pinnedTab);
    };
    for (var i = 0; i < result.tabs.length; i++)
        result.tabs[i].onCloseCallback = onCloseCallback;

    return result;
};

GloballyPinnedTabs.prototype = {
    serialize: function() {
        return this.tabs.map(GloballyPinnedTab.serialize);
    },

    addTab: function(tab) {
        var self = this;
        var newTab = new GloballyPinnedTab(tab.url, tab.url, tab.favIconUrl, tab.title, function(pinnedTab) {
            self.onPinnedTabClosed(pinnedTab);
        });
        this.tabs.push(newTab);
        Storage.persistData();
        Chrome.getAllWindows(function(windows) { newTab.createTabs(windows); });
    },

    createTabs: function(windows) {
        for (var i = 0; i < this.tabs.length; i++)
            this.tabs[i].createTabs(windows);
    },

    findTab: function(url) {
        return this.tabs.filter(function(x) { return x.startupUrl === url; })[0];
    },

    activateWindow: function(window, callback) {
        if(this.tabs.length === 0) {
            callback();
            return;
        }

        var oldWindowId;
        if(this.tabs[0].realTab)
            oldWindowId = this.tabs[0].realTab.windowId;

        if(oldWindowId === window.id) {
            callback();
            return;
        }

        if(oldWindowId !== undefined) {
            var self = this;
            Chrome.getWindow(oldWindowId, function (oldWindow) {
                self.moveTabs(window, oldWindow, callback);
            });
        }
        else
            this.recreateTabs(window, callback);
    },

    recreateTabs: function(targetWindow, callback) {
        var dummyTabs = this.getDummyTabsForWindow(targetWindow, false);
        var dummyTabIds = dummyTabs.foundTabs.map(function(x) { return x.id; });
        Chrome.removeTabs(dummyTabIds);
        for(var i =0;i<dummyTabIds.length;i++)
            delete this.tabs[i].dummyTabs[targetWindow.id];
        var total = this.tabs.length;
        var current = 0;
        var callCallback = function() {
            current++;
            if(total === current)
                callback();
        };
        for (var i = 0; i < this.tabs.length; i++)
            this.tabs[i].createRealTab(targetWindow, callCallback, true);
    },

    getDummyTabsForWindow: function(window) {
        var result = {
            foundTabs: [],
            missingTabs: []
        };
        for (var i = 0; i < this.tabs.length; i++) {
            var tab = this.tabs[i];
            var dummyTab = tab.dummyTabs[window.id];
            if(!dummyTab)
                result.missingTabs.push(tab);
            else
                result.foundTabs.push(dummyTab);
        }

        return result;
    },

    moveTabs: function(targetWindow, sourceWindow, callback) {

        var dummyTabs = this.getDummyTabsForWindow(targetWindow);
        var dummyTabIds = [];
        var smallestDummyTabsIndex = 10000;
        var i;
        var tab;
        var tabToActivate;
        for (i = 0; i < dummyTabs.foundTabs.length; i++) {
            tab = dummyTabs.foundTabs[i];
            dummyTabIds.push(tab.id);
            smallestDummyTabsIndex = Math.min(smallestDummyTabsIndex, tab.index);
            if(tab.active) {
                var startupUrl = QueryParameters.getQueryParameters(QueryParameters.getQueryString(tab.url)).startupUrl;
                tabToActivate = this.findTab(startupUrl);
            }
        }

        var realTabIds = [];
        var smallestRealTabsIndex = 10000;
        for (i = 0; i < this.tabs.length; i++) {
            tab = this.tabs[i];
            realTabIds.push(tab.realTab.id);
            smallestRealTabsIndex = Math.min(smallestRealTabsIndex, tab.realTab.index);
        }

        var finished = 0;
        var total = realTabIds.length + dummyTabs.foundTabs.length + dummyTabs.missingTabs.length;
        var self = this;

        var temporaryTabIds = [];

        var callCallback = function() {
            finished++;
            if(finished === total) {
                if(temporaryTabIds.length) {
                    Chrome.removeTabs(temporaryTabIds, function () {
                        if(tabToActivate)
                            tabToActivate.activate(callback);
                        else
                            callback();
                    });
                }
                if(tabToActivate)
                    tabToActivate.activate(callback);
                else
                    callback();
            }
        };

        var performMove = function() {
            Chrome.moveTabs(realTabIds, targetWindow.id, smallestRealTabsIndex, function(tabs) {
                if(dummyTabs.missingTabs.length) {
                    Chrome.getWindow(sourceWindow.id, function(window) {
                        for (i = 0; i < dummyTabs.missingTabs.length; i++) {
                            dummyTabs.missingTabs[i].createTabForWindow(window, callCallback);
                        }
                    })
                }
                for (var i = 0; i < tabs.length; ++i) {
                    self.tabs[i].realTab = tabs[i];
                    Chrome.pinTab(tabs[i].id, callCallback);
                }
            });

            if(dummyTabIds.length) {
                Chrome.moveTabs(dummyTabIds, sourceWindow.id, smallestDummyTabsIndex, function (tabs) {
                    for (var i = 0; i < tabs.length; ++i) {
                        delete self.tabs[i].dummyTabs[targetWindow.id];
                        self.tabs[i].dummyTabs[sourceWindow.id] = tabs[i];
                        Chrome.pinTab(tabs[i].id, callCallback);
                    }
                });
            }
        };

        var createPinnedTabInTargetWindow = function() {
            if(targetWindow.tabs.length === (self.tabs.length - dummyTabs.missingTabs.length)) {
                Chrome.createPinnedTab(targetWindow, 'about:blank', function (tab) {
                    temporaryTabIds.push(tab.id);
                    performMove();
                });
            }
            else
                performMove();
        };

        if(sourceWindow.tabs.length === this.tabs.length) {
            Chrome.createPinnedTab(sourceWindow, 'about:blank', function(tab) {
                temporaryTabIds.push(tab.id);
                createPinnedTabInTargetWindow();
             });
        } else {
            createPinnedTabInTargetWindow();
        }
    },

    updateTab: function(tab) {
        var pinnedTab = this.getTabForIdOfRealTab(tab.id);
        if(pinnedTab) {
            if(pinnedTab.updateRealTab(tab))
                Storage.persistData();
        } else {
            pinnedTab = this.getTabForAnyTabId(tab.id);
            if(pinnedTab)
                pinnedTab.updateDummyTab(tab);
        }
    },

    getTabForIdOfRealTab: function(realTabId) {
        return this.tabs.filter(function(x) { return x.realTab && (x.realTab.id === realTabId); })[0];
    },

    getTabForAnyTabId: function(tabId) {
        return this.tabs.filter(function(x) {
            if (x.realTab && (x.realTab.id === tabId))
                return true;
            for (var key in x.dummyTabs) {
                if (x.dummyTabs[key].id === tabId) {
                    return true;
                }
            }
        })[0];
    },

    handleClosedTab: function(tabId) {
        var tab = this.getTabForAnyTabId(tabId);
        if (tab) {
            if (tab.realTab && (tab.realTab.id === tabId))
                tab.realTab = undefined;
            else {
                for (var key in tab.dummyTabs) {
                    if (tab.dummyTabs[key].id === tabId) {
                        delete tab.dummyTabs[key];
                        break;
                    }
                }
            }
            tab.close();
        }
    },

    handleClosedWindow: function(windowId) {
        for (var i = 0; i < this.tabs.length; i++)
            this.tabs[i].handleClosedWindow(windowId);
    },

    onPinnedTabClosed: function(pinnedTab) {
        this.tabs.remove(pinnedTab);
        Storage.persistData();
    }
};<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 gm9
 * This software is released under the MIT License.
 * http://opensource.org/licenses/mit-license.php
 */

(function(){
    // import
    var igt = gm9.IngressGlyphTools;
    // レベル毎のグリフシーケンス
    // 小文字は読み方が曖昧な(自信がない)グリフ
    var LEVEL_SEQUENCES = [
        //L0
        [
        ],
        //L1
        [
        ],
        //L2
        [
        ],
        //L3
        [
        ],
        //L4
        [
        ],
        //L5
        [
            ["ACCEPT", "HUMAN", "WEAK"],
            ["ADVANCE", "PURE", "TRUTH"],
            ["ALL", "CIVILIZATION", "CHAOS"],
            ["ATTACK", "SHAPERS", "CHAOS"],
            ["AVOID", "DESTINY", "LIE"],
            ["COURAGE", "DESTINY", "REBEL"],
            ["DESTROY", "IMPURE", "TRUTH"],
            ["DISCOVER", "RESISTANCE", "TRUTH"],
            ["DISCOVER", "SHAPERS", "ENLIGHTENMENT"],
            ["DISCOVER", "SHAPERS", "MESSAGE"],
            ["ESCAPE", "IMPURE", "EVOLUTION"],
            ["FOLLOW", "PURE", "JOURNEY"],
            ["HUMAN", "GAIN", "SAFETY"],
            ["IMPROVE", "HUMAN", "SHAPERS"],
            ["INSIDE", "XM", "TRUTH"],
            ["JOURNEY", "INSIDE", "SOUL"],
            ["LIBERATE", "HUMAN", "FUTURE"],
            ["PEACE", "SIMPLE", "JOURNEY"],
            ["PERFECTION", "PATH", "PEACE"],
            ["PURSUE", "PURE", "BODY"],
            ["QUESTION", "HIDE", "TRUTH"],
            ["RETREAT", "SEARCH", "SAFETY"],
            ["WAR", "DESTROY", "FUTURE"],
            ["XM", "NOURISH", "CIVILIZATION"]
        ],
        //L6
        [
        ],
        //L7
        [
            ["ATTACK", "WEAK", "SHAPERS", "LIE"],
            ["BREATHE", "AGAIN", "JOURNEY", "AGAIN"],
            ["CAPTURE", "FEAR", "DISCOVER", "COURAGE"],
            ["CHANGE", "FUTURE", "CAPTURE", "DESTINY"],
            ["CHANGE", "HUMAN", "POTENTIAL", "USE"],
            ["CHAOS", "barrier", "SHAPERS", "PORTAL"],
            ["CLEAR", "MIND", "OPEN", "MIND"],
            ["CLEARALL", "OPENALL", "DISCOVER", "TRUTH"],
            ["CONTEMPLATE", "COMPLEX", "SHAPERS", "CIVILIZATION"],
            ["COURAGE", "attack", "shapers", "FUTURE"],
            ["CREATE", "DISTANCE", "IMPURE", "PATH"],
            ["CREATE", "FUTURE", "NOT", "WAR"],
            ["DEFEND", "MESSAGE", "ANSWER", "IDEA"],
            ["DESTROY", "DESTINY", "HUMAN", "LIE"],
            ["DETERIORATE", "HUMAN", "WEAK", "REBEL"],
            ["ESCAPE", "SIMPLE", "HUMAN", "FUTURE"],
            ["FOLLOW", "SHAPERS", "PORTAL", "MESSAGE"],
            ["FORGET", "CONFLICT", "ACCEPT", "WAR"],
            ["HARMONY", "PATH", "NOURISH", "PRESENT"],
            ["HELP", "GAIN", "CREATE", "PURSUE"],
            ["HIDE", "IMPURE", "HUMAN", "THOUGHT"],
            ["HUMAN", "HAVE", "IMPURE", "CIVILIZATION"],
            ["HUMAN", "PAST", "PRESENT", "FUTURE"],
            ["HUMAN", "SOUL", "STRONG", "PURE"],
            ["IMPROVE", "BODY", "MIND", "SOUL"],
            ["IMPROVE", "BODY", "PURSUE", "JOURNEY"],
            ["INSIDE", "MIND", "JOURNEY", "PERFECTION"],
            ["JOURNEY", "not", "IMPROVE", "SOUL"],
            ["LEAD", "PURSUE", "REACT", "DEFEND"],
            ["LESS", "SOUL", "MORE", "MIND"],
            ["LESS", "TRUTH", "MORE", "CHAOS"],
            ["LIBERATE", "XM", "PORTAL", "TOGETHER"],
            ["LOSE", "DANGER", "GAIN", "SAFETY"],
            ["PAST", "AGAIN", "PRESENT", "AGAIN"],
            ["PATH", "RESTRAINT", "STRONG", "SAFETY"],
            ["PORTAL", "CHANGE", "CIVILIZATION", "END"],
            ["PORTAL", "DIE", "CIVILIZATION", "DIE"],
            ["QUESTION", "TRUTH", "GAIN", "FUTURE"],
            ["RESTRAINT", "FEAR", "AVOID", "DANGER"],
            ["RESTRAINT", "PATH", "GAIN", "HARMONY"],
            ["SEARCH", "DATA", "DISCOVER", "PATH"],
            ["SEARCH", "TRUTH", "SAVE", "CIVILIZATION"],
            ["SEARCH", "XM", "SAVE", "PORTAL"],
            ["SEE", "TRUTH", "SEE", "FUTURE"],
            ["SHAPERS", "CHAOS", "PURE", "HARM"],
            ["SHAPERS", "MIND", "COMPLEX", "HARMONY"],
            ["SHAPERS", "PAST", "PRESENT", "FUTURE"],
            ["SIMPLE", "CIVILIZATION", "IMPURE", "WEAK"],
            ["SIMPLE", "MESSAGE", "COMPLEX", "IDEA"],
            ["SIMPLE", "TRUTH", "BREATHE", "NATURE"],
            ["SOUL", "REBEL", "HUMAN", "DIE"],
            ["STAY", "TOGETHER", "DEFEND", "TRUTH"],
            ["STRONG", "IDEA", "PURSUE", "TRUTH"],
            ["STRUGGLE", "DEFEND", "SHAPERS", "DANGER"],
            ["STRUGGLE", "IMPROVE", "HUMAN", "SOUL"],
            ["TOGETHER", "DISCOVER", "HARMONY", "EQUAL"],
            ["TRUTH", "IDEA", "DISCOVER", "XM"],
            ["XM", "DIE", "CHAOS", "LIVE"]
        ],
        //L8
        [
            ["advance", "civilization", "pursue", "shapers", "PATH"],
            ["ANSWER", "QUESTION", "DISCOVER", "DIFFICULT", "TRUTH"],
            ["AVOID", "PERFECTION", "STAY", "HUMAN", "SELF"],
            ["avoid", "chaos", "avoid", "shapers", "LIE"],
            ["avoid", "chaos", "repair", "potential", "WAR"],
            ["breathe", "inside", "XM", "lose", "SELF"],
            ["capture", "portal", "defend", "portal", "COURAGE"],
            ["CHAOS", "WAR", "CONFLICT", "DISCOVER", "PEACE"],
            ["civilization", "die", "new", "civilization", "BEGIN"],
            ["clear", "mind", "liberate", "barrier", "BODY"],
            ["clearall", "idea", "past", "present", "FUTURE"],
            ["contemplate", "future", "inside", "shapers", "PATH"],
            ["contemplate", "restraint", "discover", "more", "COURAGE"],
            ["courage", "attack", "shapers", "portal", "TOGETHER"],
            ["create", "pure", "future", "human", "civilization"],
            ["create", "pure", "future", "not", "WAR"],
            ["create", "separate", "path", "end", "journey"],
            ["defend", "destiny", "defend", "human", "CIVILIZATION"],
            ["defend", "human", "civilization", "XM", "MESSAGE"],
            ["defend", "human", "civilization", "portal", "DATA"],
            ["defend", "human", "civilization", "shapers", "LIE"],
            ["defend", "human", "civilization", "shapers", "PORTAL"],
            ["DESTROY", "CIVILIZATION", "END", "CONFLICT", "WAR"],
            ["destroy", "lie", "not", "gain", "SOUL"],
            ["distance", "self", "avoid", "human", "LIE"],
            ["easy", "path", "future", "follow", "SHAPERS"],
            ["end", "old", "civilization", "create", "NEW"],
            ["escape", "body", "journey", "distance", "PRESENT"],
            ["escape", "body", "mind", "self", "WANT"],
            ["forget", "attack", "see", "outside", "harmony"],
            ["forget", "past", "see", "present", "DANGER"],
            ["gain", "truth", "open", "human", "SOUL"],
            ["HARM", "PROGRESS", "PURSUE", "MORE", "WAR"],
            ["help", "enlightened", "capture", "all", "portal"],
            ["HELP", "HUMAN", "CIVILIZATION", "PURSUE", "DESTINY"],
            ["help", "resistance", "capture", "all", "PORTAL"],
            ["hide", "struggle", "advance", "strong", "TOGETHER"],
            ["human", "not", "together", "civilization", "deteriorate"],
            ["human", "shapers", "together", "create", "DESTINY"],
            ["imperfect", "TRUTH", "open", "complex", "ANSWER"],
            ["imperfect", "XM", "message", "human", "CHAOS"],
            ["inside", "mind", "inside", "soul", "HARMONY"],
            ["liberate", "portal", "liberate", "human", "MIND"],
            ["liberate", "self", "liberate", "human", "CIVILIZATION"],
            ["lose", "shapers", "message", "gain", "CHAOS"],
            ["MIND", "BODY", "SOUL", "PURE", "HUMAN"],
            ["more", "data", "gain", "portal", "ADVANCE"],
            ["old", "nature", "less", "strong", "present"],
            ["past", "chaos", "create", "future", "HARMONY"],
            ["past", "path", "create", "future", "JOURNEY"],
            ["portal", "barrier", "defend", "human", "SHAPERS"],
            ["portal", "create", "danger", "pursue", "SAFETY"],
            ["portal", "improve", "human", "future", "CIVILIZATION"],
            ["portal", "potential", "help", "human", "future"],
            ["present", "chaos", "create", "future", "CIVILIZATION"],
            ["PURE", "HUMAN", "FAILURE", "NOW", "CHAOS"],
            ["PURSUE", "CONFLICT", "WAR", "ADVANCE", "CHAOS"],
            ["pursue", "path", "distance", "shapers", "LIE"],
            ["QUESTION", "LESS", "FORGET", "ALL", "LIE"],
            ["REACT", "REBEL", "QUESTION", "SHAPERS", "LIE"],
            ["REBEL", "THOUGHT", "EVOLUTION", "DESTINY", "NOW"],
            ["REPAIR", "PRESENT", "REPAIR", "HUMAN", "SOUL"],
            ["repair", "soul", "less", "human", "HARM"],
            ["save", "human", "civilization", "destroy", "PORTAL"],
            ["search", "destiny", "create", "pure", "future"],
            ["separate", "mind", "body", "discover", "ENLIGHTENMENT"],
            ["separate", "truth", "lie", "shapers", "future"],
            ["SHAPERS", "LEAD", "HUMAN", "COMPLEX", "JOURNEY"],
            ["shapers", "portal", "data", "create", "chaos"],
            ["shapers", "portal", "message", "destroy", "CIVILIZATION"],
            ["shapers", "see", "complex", "path", "DESTINY"],
            ["shapers", "want", "human", "mind", "FUTURE"],
            ["simple", "old", "truth", "journey", "INSIDE"],
            ["simple", "truth", "forget", "easy", "SUCCESS"],
            ["simple", "truth", "shapers", "destroy", "civilization"],
            ["STAY", "STRONG", "TOGETHER", "DEFEND", "RESISTANCE"],
            ["strong", "together", "attack", "together", "CHAOS"],
            ["strong", "together", "attack", "together", "DESTINY"],
            ["use", "mind", "use", "courage", "CHANGE"],
            ["USE", "RESTRAINT", "FOLLOW", "EASY", "PATH"],
            ["want", "truth", "pursue", "difficult", "PATH"],
            ["weak", "human", "destiny", "destroy", "CIVILIZATION"],
            ["XM", "create", "complex", "human", "DESTINY"],
            //["XM", "create", "complex", "shapers", "DESTINY"],
            ["XM", "PATH", "FUTURE", "DESTINY", "HARMONY"]
        ]
    ];

    igt.sequenceDic = {
        getSequences: function(lv){ return LEVEL_SEQUENCES[lv];},
        getSequenceRandom: function(lv){
            var seqs = LEVEL_SEQUENCES[lv];
            return seqs && seqs.length > 0 ? seqs[Math.floor(Math.random() * seqs.length)] : null;
        }
    };
})();
<commit_msg>L8グリフシーケンスの英語読みを二つ修正した。<commit_after>/*
 * Copyright (c) 2014 gm9
 * This software is released under the MIT License.
 * http://opensource.org/licenses/mit-license.php
 */

(function(){
    // import
    var igt = gm9.IngressGlyphTools;
    // レベル毎のグリフシーケンス
    // 小文字は読み方が曖昧な(自信がない)グリフ
    var LEVEL_SEQUENCES = [
        //L0
        [
        ],
        //L1
        [
        ],
        //L2
        [
        ],
        //L3
        [
        ],
        //L4
        [
        ],
        //L5
        [
            ["ACCEPT", "HUMAN", "WEAK"],
            ["ADVANCE", "PURE", "TRUTH"],
            ["ALL", "CIVILIZATION", "CHAOS"],
            ["ATTACK", "SHAPERS", "CHAOS"],
            ["AVOID", "DESTINY", "LIE"],
            ["COURAGE", "DESTINY", "REBEL"],
            ["DESTROY", "IMPURE", "TRUTH"],
            ["DISCOVER", "RESISTANCE", "TRUTH"],
            ["DISCOVER", "SHAPERS", "ENLIGHTENMENT"],
            ["DISCOVER", "SHAPERS", "MESSAGE"],
            ["ESCAPE", "IMPURE", "EVOLUTION"],
            ["FOLLOW", "PURE", "JOURNEY"],
            ["HUMAN", "GAIN", "SAFETY"],
            ["IMPROVE", "HUMAN", "SHAPERS"],
            ["INSIDE", "XM", "TRUTH"],
            ["JOURNEY", "INSIDE", "SOUL"],
            ["LIBERATE", "HUMAN", "FUTURE"],
            ["PEACE", "SIMPLE", "JOURNEY"],
            ["PERFECTION", "PATH", "PEACE"],
            ["PURSUE", "PURE", "BODY"],
            ["QUESTION", "HIDE", "TRUTH"],
            ["RETREAT", "SEARCH", "SAFETY"],
            ["WAR", "DESTROY", "FUTURE"],
            ["XM", "NOURISH", "CIVILIZATION"]
        ],
        //L6
        [
        ],
        //L7
        [
            ["ATTACK", "WEAK", "SHAPERS", "LIE"],
            ["BREATHE", "AGAIN", "JOURNEY", "AGAIN"],
            ["CAPTURE", "FEAR", "DISCOVER", "COURAGE"],
            ["CHANGE", "FUTURE", "CAPTURE", "DESTINY"],
            ["CHANGE", "HUMAN", "POTENTIAL", "USE"],
            ["CHAOS", "barrier", "SHAPERS", "PORTAL"],
            ["CLEAR", "MIND", "OPEN", "MIND"],
            ["CLEARALL", "OPENALL", "DISCOVER", "TRUTH"],
            ["CONTEMPLATE", "COMPLEX", "SHAPERS", "CIVILIZATION"],
            ["COURAGE", "attack", "shapers", "FUTURE"],
            ["CREATE", "DISTANCE", "IMPURE", "PATH"],
            ["CREATE", "FUTURE", "NOT", "WAR"],
            ["DEFEND", "MESSAGE", "ANSWER", "IDEA"],
            ["DESTROY", "DESTINY", "HUMAN", "LIE"],
            ["DETERIORATE", "HUMAN", "WEAK", "REBEL"],
            ["ESCAPE", "SIMPLE", "HUMAN", "FUTURE"],
            ["FOLLOW", "SHAPERS", "PORTAL", "MESSAGE"],
            ["FORGET", "CONFLICT", "ACCEPT", "WAR"],
            ["HARMONY", "PATH", "NOURISH", "PRESENT"],
            ["HELP", "GAIN", "CREATE", "PURSUE"],
            ["HIDE", "IMPURE", "HUMAN", "THOUGHT"],
            ["HUMAN", "HAVE", "IMPURE", "CIVILIZATION"],
            ["HUMAN", "PAST", "PRESENT", "FUTURE"],
            ["HUMAN", "SOUL", "STRONG", "PURE"],
            ["IMPROVE", "BODY", "MIND", "SOUL"],
            ["IMPROVE", "BODY", "PURSUE", "JOURNEY"],
            ["INSIDE", "MIND", "JOURNEY", "PERFECTION"],
            ["JOURNEY", "not", "IMPROVE", "SOUL"],
            ["LEAD", "PURSUE", "REACT", "DEFEND"],
            ["LESS", "SOUL", "MORE", "MIND"],
            ["LESS", "TRUTH", "MORE", "CHAOS"],
            ["LIBERATE", "XM", "PORTAL", "TOGETHER"],
            ["LOSE", "DANGER", "GAIN", "SAFETY"],
            ["PAST", "AGAIN", "PRESENT", "AGAIN"],
            ["PATH", "RESTRAINT", "STRONG", "SAFETY"],
            ["PORTAL", "CHANGE", "CIVILIZATION", "END"],
            ["PORTAL", "DIE", "CIVILIZATION", "DIE"],
            ["QUESTION", "TRUTH", "GAIN", "FUTURE"],
            ["RESTRAINT", "FEAR", "AVOID", "DANGER"],
            ["RESTRAINT", "PATH", "GAIN", "HARMONY"],
            ["SEARCH", "DATA", "DISCOVER", "PATH"],
            ["SEARCH", "TRUTH", "SAVE", "CIVILIZATION"],
            ["SEARCH", "XM", "SAVE", "PORTAL"],
            ["SEE", "TRUTH", "SEE", "FUTURE"],
            ["SHAPERS", "CHAOS", "PURE", "HARM"],
            ["SHAPERS", "MIND", "COMPLEX", "HARMONY"],
            ["SHAPERS", "PAST", "PRESENT", "FUTURE"],
            ["SIMPLE", "CIVILIZATION", "IMPURE", "WEAK"],
            ["SIMPLE", "MESSAGE", "COMPLEX", "IDEA"],
            ["SIMPLE", "TRUTH", "BREATHE", "NATURE"],
            ["SOUL", "REBEL", "HUMAN", "DIE"],
            ["STAY", "TOGETHER", "DEFEND", "TRUTH"],
            ["STRONG", "IDEA", "PURSUE", "TRUTH"],
            ["STRUGGLE", "DEFEND", "SHAPERS", "DANGER"],
            ["STRUGGLE", "IMPROVE", "HUMAN", "SOUL"],
            ["TOGETHER", "DISCOVER", "HARMONY", "EQUAL"],
            ["TRUTH", "IDEA", "DISCOVER", "XM"],
            ["XM", "DIE", "CHAOS", "LIVE"]
        ],
        //L8
        [
            ["advance", "civilization", "pursue", "shapers", "PATH"],
            ["ANSWER", "QUESTION", "DISCOVER", "DIFFICULT", "TRUTH"],
            ["AVOID", "PERFECTION", "STAY", "HUMAN", "SELF"],
            ["avoid", "chaos", "avoid", "shapers", "LIE"],
            ["avoid", "chaos", "repair", "potential", "WAR"],
            ["breathe", "inside", "XM", "lose", "SELF"],
            ["capture", "portal", "defend", "portal", "COURAGE"],
            ["CHAOS", "WAR", "CONFLICT", "DISCOVER", "PEACE"],
            ["civilization", "die", "new", "civilization", "BEGIN"],
            ["clear", "mind", "liberate", "barrier", "BODY"],
            ["clearall", "idea", "past", "present", "FUTURE"],
            ["CONTEMPLATE", "FUTURE", "NOT", "SHAPERS", "PATH"],
            ["contemplate", "restraint", "discover", "more", "COURAGE"],
            ["courage", "attack", "shapers", "portal", "TOGETHER"],
            ["create", "pure", "future", "human", "civilization"],
            ["create", "pure", "future", "not", "WAR"],
            ["create", "separate", "path", "end", "journey"],
            ["defend", "destiny", "defend", "human", "CIVILIZATION"],
            ["defend", "human", "civilization", "XM", "MESSAGE"],
            ["defend", "human", "civilization", "portal", "DATA"],
            ["defend", "human", "civilization", "shapers", "LIE"],
            ["defend", "human", "civilization", "shapers", "PORTAL"],
            ["DESTROY", "CIVILIZATION", "END", "CONFLICT", "WAR"],
            ["destroy", "lie", "not", "gain", "SOUL"],
            ["distance", "self", "avoid", "human", "LIE"],
            ["easy", "path", "future", "follow", "SHAPERS"],
            ["end", "old", "civilization", "create", "NEW"],
            ["escape", "body", "journey", "distance", "PRESENT"],
            ["escape", "body", "mind", "self", "WANT"],
            ["forget", "attack", "see", "outside", "harmony"],
            ["forget", "past", "see", "present", "DANGER"],
            ["gain", "truth", "open", "human", "SOUL"],
            ["HARM", "PROGRESS", "PURSUE", "MORE", "WAR"],
            ["help", "enlightened", "capture", "all", "portal"],
            ["HELP", "HUMAN", "CIVILIZATION", "PURSUE", "DESTINY"],
            ["help", "resistance", "capture", "all", "PORTAL"],
            ["hide", "struggle", "advance", "strong", "TOGETHER"],
            ["human", "not", "together", "civilization", "deteriorate"],
            ["human", "shapers", "together", "create", "DESTINY"],
            ["imperfect", "TRUTH", "open", "complex", "ANSWER"],
            ["imperfect", "XM", "message", "human", "CHAOS"],
            ["inside", "mind", "inside", "soul", "HARMONY"],
            ["liberate", "portal", "liberate", "human", "MIND"],
            ["liberate", "self", "liberate", "human", "CIVILIZATION"],
            ["lose", "shapers", "message", "gain", "CHAOS"],
            ["MIND", "BODY", "SOUL", "PURE", "HUMAN"],
            ["more", "data", "gain", "portal", "ADVANCE"],
            ["old", "nature", "less", "strong", "present"],
            ["past", "chaos", "create", "future", "HARMONY"],
            ["past", "path", "create", "future", "JOURNEY"],
            ["portal", "barrier", "defend", "human", "SHAPERS"],
            ["portal", "create", "danger", "pursue", "SAFETY"],
            ["portal", "improve", "human", "future", "CIVILIZATION"],
            ["portal", "potential", "help", "human", "future"],
            ["present", "chaos", "create", "future", "CIVILIZATION"],
            ["PURE", "HUMAN", "FAILURE", "NOW", "CHAOS"],
            ["PURSUE", "CONFLICT", "WAR", "ADVANCE", "CHAOS"],
            ["pursue", "path", "distance", "shapers", "LIE"],
            ["QUESTION", "LESS", "FORGET", "ALL", "LIE"],
            ["REACT", "REBEL", "QUESTION", "SHAPERS", "LIE"],
            ["REBEL", "THOUGHT", "EVOLUTION", "DESTINY", "NOW"],
            ["REPAIR", "PRESENT", "REPAIR", "HUMAN", "SOUL"],
            ["repair", "soul", "less", "human", "HARM"],
            ["save", "human", "civilization", "destroy", "PORTAL"],
            ["search", "destiny", "create", "pure", "future"],
            ["separate", "mind", "body", "discover", "ENLIGHTENMENT"],
            ["separate", "truth", "lie", "shapers", "future"],
            ["SHAPERS", "LEAD", "HUMAN", "COMPLEX", "JOURNEY"],
            ["shapers", "portal", "data", "create", "chaos"],
            ["shapers", "portal", "message", "destroy", "CIVILIZATION"],
            ["shapers", "see", "complex", "path", "DESTINY"],
            ["shapers", "want", "human", "mind", "FUTURE"],
            ["simple", "old", "truth", "journey", "INSIDE"],
            ["simple", "truth", "forget", "easy", "SUCCESS"],
            ["simple", "truth", "shapers", "destroy", "civilization"],
            ["STAY", "STRONG", "TOGETHER", "DEFEND", "RESISTANCE"],
            ["strong", "together", "attack", "together", "CHAOS"],
            ["STRONG", "TOGETHER", "WAR", "TOGETHER", "DESTINY"],
            ["use", "mind", "use", "courage", "CHANGE"],
            ["USE", "RESTRAINT", "FOLLOW", "EASY", "PATH"],
            ["want", "truth", "pursue", "difficult", "PATH"],
            ["weak", "human", "destiny", "destroy", "CIVILIZATION"],
            ["XM", "create", "complex", "human", "DESTINY"],
            //["XM", "create", "complex", "shapers", "DESTINY"],
            ["XM", "PATH", "FUTURE", "DESTINY", "HARMONY"]
        ]
    ];

    igt.sequenceDic = {
        getSequences: function(lv){ return LEVEL_SEQUENCES[lv];},
        getSequenceRandom: function(lv){
            var seqs = LEVEL_SEQUENCES[lv];
            return seqs && seqs.length > 0 ? seqs[Math.floor(Math.random() * seqs.length)] : null;
        }
    };
})();
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * 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
 *
 *         http://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.
 */

({
    testAttributeSetOnComponents: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isArray(cmp.get("v.componentDefault")));
                },
                function(cmp) {
                    var expected = "setValueChild";
                    var actual = cmp.get("v.componentDefault")[0].get("v.value").trim();
                    $A.test.assertEquals(expected, actual);
                }
            ]
    },
    testAttributeSetOnComponents2: {
        test: function(cmp) {
            var expected = "setValueGrandchild";
            var actual = cmp.get("v.componentDefault2")[0].get("v.value").trim();
            $A.test.assertEquals(expected, actual);
        }
    },
    testAttributeSetOnMap: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isObject(cmp.get("v.mapAttributeWithDefaultValue")));
                },
                function(cmp) {
                    var actual = cmp.get("v.mapAttributeWithDefaultValue");
                    $A.test.assertEquals(2, actual.b);
                    $A.test.assertEquals(3, actual.c);
                }
            ]
    },
    testAttributeSetOnObject: {
        test: [
                function(cmp) {
                    // It's a string because the attribute is of type "Object" which is a base type of String
                    $A.test.assertTrue(typeof cmp.get("v.objAttributeWithDefaultValue") == "string");
                },
                function(cmp) {
                    var actual = cmp.get("v.objAttributeWithDefaultValue");
                    $A.test.assertEquals("['grey','silver','slate']", actual);
                }
            ]
    },
    testAttributeSetOnList: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isArray(cmp.get("v.listAttributeWithDefaultValue")));
                },
                function(cmp) {
                    var actual = cmp.get("v.listAttributeWithDefaultValue");
                    $A.test.assertEquals("grey,silver,slate", actual.join(","));
                }
            ]
    },
    testAttributeSetOnBooleanArray: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isArray(cmp.get("v.arrayAttributeWithDefaultValue")));
                },
                function(cmp) {
                    var actual = cmp.get("v.arrayAttributeWithDefaultValue");
                    $A.test.assertEquals(false, actual[0]);
                    $A.test.assertEquals(true, actual[1]);
                    $A.test.assertEquals(false, actual[2]);
                }
            ]
    },
    testAttributeSetOnLong: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.longDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.longDefaultWithStringPositiveInt");
                    $A.test.assertEquals(456, actual);
                }
            ]
    },
    testAttributeSetOnInteger: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.integerDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.integerDefaultWithStringPositiveInt");
                    $A.test.assertEquals(456, actual);
                }
            ]
    },
    testAttributeSetOnDouble: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.doubleDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.doubleDefaultWithStringPositiveInt");
                    $A.test.assertEquals(456, actual);
                }
            ]
    },
    testAttributeSetOnDecimal: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.decimalDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.decimalDefaultWithStringPositiveInt");
                    $A.test.assertEquals(456.789, actual);
                }
            ]
    },
    testAttributeSetOnDateTime: {
        test: function(cmp) {
            $A.test.assertTrue(cmp.get("v.dateTimeDefaultWithString").indexOf("2015-05-01T") == 0);
        }
    },
    testAttributeSetOnDate: {
        test: function(cmp) {
            $A.test.assertTrue(cmp.get("v.dateDefaultWithString").indexOf("2015-02-05T") == 0);
        }
    },
    testAttributeSetOnString: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isString(cmp.get("v.stringDefaultWithString")));
                },
                function(cmp) {
                    var actual = cmp.get("v.stringDefaultWithString");
                    $A.test.assertEquals("test string2", actual);
                }
            ]
    },
    testAttributeSetOnBoolean: {
        test: [
                function(cmp) {
                    $A.test.assertFalse(cmp.get("v.booleanDefaultWithStringFalse"));
                },
                function(cmp) {
                    $A.test.assertTrue($A.util.isBoolean(cmp.get("v.booleanDefaultWithStringFalse")));
                }
            ]
    }

})<commit_msg>we need to update setValueGrandchildTest.js as well @bug W-2063260@<commit_after>/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * 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
 *
 *         http://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.
 */

({
    testAttributeSetOnComponents: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isArray(cmp.get("v.componentDefault")));
                },
                function(cmp) {
                    var expected = "setValueChild";
                    var actual = cmp.get("v.componentDefault")[0].get("v.value").trim();
                    $A.test.assertEquals(expected, actual);
                }
            ]
    },
    testAttributeSetOnComponents2: {
        test: function(cmp) {
            var expected = "setValueGrandchild";
            var actual = cmp.get("v.componentDefault2")[0].get("v.value").trim();
            $A.test.assertEquals(expected, actual);
        }
    },
    testAttributeSetOnMap: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isObject(cmp.get("v.mapAttributeWithDefaultValue")));
                },
                function(cmp) {
                    var actual = cmp.get("v.mapAttributeWithDefaultValue");
                    $A.test.assertEquals(2, actual.b);
                    $A.test.assertEquals(3, actual.c);
                }
            ]
    },
    testAttributeSetOnObject: {
        test: [
                function(cmp) {
                    // It's a string because the attribute is of type "Object" which is a base type of String
                    $A.test.assertTrue(typeof cmp.get("v.objAttributeWithDefaultValue") == "string");
                },
                function(cmp) {
                    var actual = cmp.get("v.objAttributeWithDefaultValue");
                    $A.test.assertEquals("['grey','silver','slate']", actual);
                }
            ]
    },
    testAttributeSetOnList: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isArray(cmp.get("v.listAttributeWithDefaultValue")));
                },
                function(cmp) {
                    var actual = cmp.get("v.listAttributeWithDefaultValue");
                    $A.test.assertEquals("grey,silver,slate", actual.join(","));
                }
            ]
    },
    testAttributeSetOnBooleanArray: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isArray(cmp.get("v.arrayAttributeWithDefaultValue")));
                },
                function(cmp) {
                    var actual = cmp.get("v.arrayAttributeWithDefaultValue");
                    $A.test.assertEquals(false, actual[0]);
                    $A.test.assertEquals('true', actual[1]);
                    $A.test.assertEquals(true, actual[2]);
                }
            ]
    },
    testAttributeSetOnLong: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.longDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.longDefaultWithStringPositiveInt");
                    $A.test.assertEquals(9007199254740991, actual);
                }
            ]
    },
    testAttributeSetOnInteger: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.integerDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.integerDefaultWithStringPositiveInt");
                    $A.test.assertEquals(2147483647, actual);
                }
            ]
    },
    testAttributeSetOnDouble: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.doubleDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.doubleDefaultWithStringPositiveInt");
                    $A.test.assertEquals(9007199254740991, actual);
                }
            ]
    },
    testAttributeSetOnDecimal: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isNumber(cmp.get("v.decimalDefaultWithStringPositiveInt")));
                },
                function(cmp) {
                    var actual = cmp.get("v.decimalDefaultWithStringPositiveInt");
                    $A.test.assertEquals(9.99999999999999, actual);
                }
            ]
    },
    testAttributeSetOnDateTime: {
        test: function(cmp) {
            $A.test.assertTrue(cmp.get("v.dateTimeDefaultWithString").indexOf("2015-05-01T") == 0);
        }
    },
    testAttributeSetOnDate: {
        test: function(cmp) {
            $A.test.assertTrue(cmp.get("v.dateDefaultWithString").indexOf("2015-02-05T") == 0);
        }
    },
    testAttributeSetOnString: {
        test: [
                function(cmp) {
                    $A.test.assertTrue($A.util.isString(cmp.get("v.stringDefaultWithString")));
                },
                function(cmp) {
                    var actual = cmp.get("v.stringDefaultWithString");
                    $A.test.assertEquals("test string2", actual);
                }
            ]
    },
    testAttributeSetOnBoolean: {
        test: [
                function(cmp) {
                    $A.test.assertFalse(cmp.get("v.booleanDefaultWithStringFalse"));
                },
                function(cmp) {
                    $A.test.assertTrue($A.util.isBoolean(cmp.get("v.booleanDefaultWithStringFalse")));
                }
            ]
    }

})<|endoftext|>