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

/**
 * External dependencies
 */
import { storiesOf } from '@storybook/react';

/**
 * WordPress dependencies
 */
import { removeAllFilters, addFilter } from '@wordpress/hooks';

/**
 * Internal dependencies
 */
import SetupWrapper from '../assets/js/components/setup/setup-wrapper';
import { SetupMain as AnalyticsSetup } from '../assets/js/modules/analytics/components/setup/index';
import { fillFilterWithComponent } from '../assets/js/util';
import * as fixtures from '../assets/js/modules/analytics/datastore/__fixtures__';

import { STORE_NAME, ACCOUNT_CREATE, PROFILE_CREATE, PROVISIONING_SCOPE } from '../assets/js/modules/analytics/datastore/constants';
import { STORE_NAME as CORE_SITE, AMP_MODE_SECONDARY } from '../assets/js/googlesitekit/datastore/site/constants';
import { STORE_NAME as CORE_USER } from '../assets/js/googlesitekit/datastore/user/constants';
import { STORE_NAME as CORE_MODULES } from '../assets/js/googlesitekit/modules/datastore/constants';
import { createBuildAndReceivers } from '../assets/js/modules/tagmanager/datastore/__factories__/utils';
import { WithTestRegistry } from '../tests/js/utils';
import { generateGtmPropertyStory } from './utils/analytics';

function filterAnalyticsSetup() {
	global._googlesitekitLegacyData.setup.moduleToSetup = 'analytics';

	removeAllFilters( 'googlesitekit.ModuleSetup-analytics' );
	addFilter(
		'googlesitekit.ModuleSetup-analytics',
		'googlesitekit.AnalyticsModuleSetup',
		fillFilterWithComponent( AnalyticsSetup )
	);
}

function Setup( props ) {
	return (
		<WithTestRegistry { ...props }>
			<SetupWrapper />
		</WithTestRegistry>
	);
}

function generateGtmPropertyStoryCallback( permission, useExistingTag = false ) {
	return generateGtmPropertyStory( {
		Component: Setup,
		permission,
		useExistingTag,
	} );
}

storiesOf( 'Analytics Module/Setup', module )
	.add( 'Loading', () => {
		filterAnalyticsSetup();

		const setupRegistry = ( registry ) => {
			registry.dispatch( STORE_NAME ).receiveGetSettings( {} );
			registry.dispatch( STORE_NAME ).receiveGetExistingTag( null );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Start', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Start (with matched property)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles, matchedProperty } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveMatchedProperty( matchedProperty );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create new view', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const { accountId, webPropertyId } = profiles[ 0 ];
		const { internalWebPropertyId } = properties.find( ( property ) => webPropertyId === property.id );
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: accountId,
				propertyID: webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).setSettings( {
				accountID: accountId,
				propertyID: webPropertyId,
				internalWebPropertyID: internalWebPropertyId,
				profileID: PROFILE_CREATE,
				anonymizeIP: true,
				useSnippet: true,
				trackingDisabled: [ 'loggedinUsers' ],
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account Legacy (no accounts)', () => {
		filterAnalyticsSetup();

		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( [] );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account Legacy (new account option)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetSettings( {
				accountID: ACCOUNT_CREATE,
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account (scope not granted)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( CORE_SITE ).receiveSiteInfo( {
				usingProxy: true,
				referenceSiteURL: 'http://example.com',
				timezone: 'America/Detroit',
				siteName: 'My Site Name',
			} );
			dispatch( CORE_USER ).receiveGetAuthentication( {
				authenticated: true,
				requiredScopes: [],
				grantedScopes: [],
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetSettings( {
				accountID: ACCOUNT_CREATE,
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account (scope granted)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( CORE_SITE ).receiveSiteInfo( {
				usingProxy: true,
				referenceSiteURL: 'http://example.com',
				timezone: 'America/Detroit',
				siteName: 'My Site Name',
			} );
			dispatch( CORE_USER ).receiveGetAuthentication( {
				authenticated: true,
				requiredScopes: [],
				grantedScopes: [ PROVISIONING_SCOPE ],
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetSettings( {
				accountID: ACCOUNT_CREATE,
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Existing Tag w/ access', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const existingTag = {
			accountID: properties[ 0 ].accountId,
			propertyID: properties[ 0 ].id,
		};

		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( existingTag.propertyID );
			dispatch( STORE_NAME ).receiveGetTagPermission( {
				accountID: existingTag.accountID,
				permission: true,
			}, { propertyID: existingTag.propertyID } );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Existing Tag w/o access', () => {
		filterAnalyticsSetup();

		const existingTag = {
			accountID: '12345678',
			propertyID: 'UA-12345678-1',
		};
		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( existingTag.propertyID );
			dispatch( STORE_NAME ).receiveGetTagPermission( {
				accountID: existingTag.accountID,
				permission: false,
			}, { propertyID: existingTag.propertyID } );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'No Tag, GTM property w/ access', generateGtmPropertyStoryCallback( true ) )
	.add( 'No Tag, GTM property w/o access', generateGtmPropertyStoryCallback( false ) )
	.add( 'Existing Tag, GTM property w/ access', generateGtmPropertyStoryCallback( true, true ) )
	.add( 'Existing Tag, GTM property w/o access', generateGtmPropertyStoryCallback( false, true ) )
;
<commit_msg>Remove unused vars.<commit_after>/**
 * Analytics Setup stories.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import { storiesOf } from '@storybook/react';

/**
 * WordPress dependencies
 */
import { removeAllFilters, addFilter } from '@wordpress/hooks';

/**
 * Internal dependencies
 */
import SetupWrapper from '../assets/js/components/setup/setup-wrapper';
import { SetupMain as AnalyticsSetup } from '../assets/js/modules/analytics/components/setup/index';
import { fillFilterWithComponent } from '../assets/js/util';
import * as fixtures from '../assets/js/modules/analytics/datastore/__fixtures__';

import { STORE_NAME, ACCOUNT_CREATE, PROFILE_CREATE, PROVISIONING_SCOPE } from '../assets/js/modules/analytics/datastore/constants';
import { STORE_NAME as CORE_SITE } from '../assets/js/googlesitekit/datastore/site/constants';
import { STORE_NAME as CORE_USER } from '../assets/js/googlesitekit/datastore/user/constants';
import { WithTestRegistry } from '../tests/js/utils';
import { generateGtmPropertyStory } from './utils/analytics';

function filterAnalyticsSetup() {
	global._googlesitekitLegacyData.setup.moduleToSetup = 'analytics';

	removeAllFilters( 'googlesitekit.ModuleSetup-analytics' );
	addFilter(
		'googlesitekit.ModuleSetup-analytics',
		'googlesitekit.AnalyticsModuleSetup',
		fillFilterWithComponent( AnalyticsSetup )
	);
}

function Setup( props ) {
	return (
		<WithTestRegistry { ...props }>
			<SetupWrapper />
		</WithTestRegistry>
	);
}

function generateGtmPropertyStoryCallback( permission, useExistingTag = false ) {
	return generateGtmPropertyStory( {
		Component: Setup,
		permission,
		useExistingTag,
	} );
}

storiesOf( 'Analytics Module/Setup', module )
	.add( 'Loading', () => {
		filterAnalyticsSetup();

		const setupRegistry = ( registry ) => {
			registry.dispatch( STORE_NAME ).receiveGetSettings( {} );
			registry.dispatch( STORE_NAME ).receiveGetExistingTag( null );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Start', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Start (with matched property)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles, matchedProperty } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveMatchedProperty( matchedProperty );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create new view', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const { accountId, webPropertyId } = profiles[ 0 ];
		const { internalWebPropertyId } = properties.find( ( property ) => webPropertyId === property.id );
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: accountId,
				propertyID: webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).setSettings( {
				accountID: accountId,
				propertyID: webPropertyId,
				internalWebPropertyID: internalWebPropertyId,
				profileID: PROFILE_CREATE,
				anonymizeIP: true,
				useSnippet: true,
				trackingDisabled: [ 'loggedinUsers' ],
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account Legacy (no accounts)', () => {
		filterAnalyticsSetup();

		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( [] );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account Legacy (new account option)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetSettings( {
				accountID: ACCOUNT_CREATE,
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account (scope not granted)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( CORE_SITE ).receiveSiteInfo( {
				usingProxy: true,
				referenceSiteURL: 'http://example.com',
				timezone: 'America/Detroit',
				siteName: 'My Site Name',
			} );
			dispatch( CORE_USER ).receiveGetAuthentication( {
				authenticated: true,
				requiredScopes: [],
				grantedScopes: [],
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetSettings( {
				accountID: ACCOUNT_CREATE,
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Create Account (scope granted)', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( CORE_SITE ).receiveSiteInfo( {
				usingProxy: true,
				referenceSiteURL: 'http://example.com',
				timezone: 'America/Detroit',
				siteName: 'My Site Name',
			} );
			dispatch( CORE_USER ).receiveGetAuthentication( {
				authenticated: true,
				requiredScopes: [],
				grantedScopes: [ PROVISIONING_SCOPE ],
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( null );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetSettings( {
				accountID: ACCOUNT_CREATE,
			} );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Existing Tag w/ access', () => {
		filterAnalyticsSetup();

		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const existingTag = {
			accountID: properties[ 0 ].accountId,
			propertyID: properties[ 0 ].id,
		};

		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( existingTag.propertyID );
			dispatch( STORE_NAME ).receiveGetTagPermission( {
				accountID: existingTag.accountID,
				permission: true,
			}, { propertyID: existingTag.propertyID } );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'Existing Tag w/o access', () => {
		filterAnalyticsSetup();

		const existingTag = {
			accountID: '12345678',
			propertyID: 'UA-12345678-1',
		};
		const { accounts, properties, profiles } = fixtures.accountsPropertiesProfiles;
		const setupRegistry = ( { dispatch } ) => {
			dispatch( STORE_NAME ).receiveGetSettings( {} );
			dispatch( STORE_NAME ).receiveGetAccounts( accounts );
			dispatch( STORE_NAME ).receiveGetProperties( properties, { accountID: properties[ 0 ].accountId } );
			dispatch( STORE_NAME ).receiveGetProfiles( profiles, {
				accountID: properties[ 0 ].accountId,
				propertyID: profiles[ 0 ].webPropertyId,
			} );
			dispatch( STORE_NAME ).receiveGetExistingTag( existingTag.propertyID );
			dispatch( STORE_NAME ).receiveGetTagPermission( {
				accountID: existingTag.accountID,
				permission: false,
			}, { propertyID: existingTag.propertyID } );
		};

		return <Setup callback={ setupRegistry } />;
	} )
	.add( 'No Tag, GTM property w/ access', generateGtmPropertyStoryCallback( true ) )
	.add( 'No Tag, GTM property w/o access', generateGtmPropertyStoryCallback( false ) )
	.add( 'Existing Tag, GTM property w/ access', generateGtmPropertyStoryCallback( true, true ) )
	.add( 'Existing Tag, GTM property w/o access', generateGtmPropertyStoryCallback( false, true ) )
;
<|endoftext|>


<commit_before>var _ = require('lodash');
var crossfilter = require('crossfilter');
var d3 = window.d3;
var EventEmitter = require('events').EventEmitter;

d3.chart('Brush', {
  initialize: function() {
    var chart = this;

    this.width = this.base.attr('width');
    this.height = this.base.attr('height');

    this.base.append('g').attr('id', 'brushMainGroup');
  },
  emitter: function(emitter) {
    if (!arguments.length) { return this._emitter; }
    this._emitter = emitter;
    return this;
  },
  initialExtent: function(initialExtent) {
    if (!arguments.length) { return this._initialExtent; }
    this._initialExtent = initialExtent;
    return this;
  },
  margins: function(margins) {
    if (!arguments.length) { return this._margins; }
    this._margins = margins;
    return this;
  },
  setExtent: function(newExtent) {
    this.brushHandleGroup.call(this.brush.extent(newExtent));
    this.fixBrushHandlers(this.brushHandleGroup);
    return this;
  },
  xScale: function(xScale) {
    if (!arguments.length) { return this._xScale; }
    var w = this.width;
    var mainMargins = this.margins().main;
    this._xScale = xScale.range([
      mainMargins.left,
      w - mainMargins.right
    ]);
    this.makeBrush();
    var domainAxis = d3.svg.axis()
      .scale(xScale)
      .orient('top')
      .ticks(d3.time.month.utc, 1)
      .tickFormat(d3.time.format.utc('%b'));
    this.base.append('g')
      .attr({
        id: 'domainAxis',
        transform: 'translate(0,' + mainMargins.top + ')'
      })
      .call(domainAxis);
    return this;
  },
  makeBrush: function() {
    var chart = this, emitter = this.emitter();
    function brushed() {
      var MS_IN_24 = 86400000;
      var origExtent = chart.brush.extent(), newExtent;
      // preserve width of handle on drag
      if (d3.event.mode === 'move') {
        var s = d3.time.day.utc.round(origExtent[0]),
          e = d3.time.day.utc.offset(s, Math.round((origExtent[1] - origExtent[0])/MS_IN_24));
        newExtent = [s, e];
      }
      // on resize, round to midnights
      else {
        newExtent = origExtent.map(d3.time.day.utc.round);

        // if empty when rounded, use floor & ceil instead
        // i.e., enforce min of 1 day
        if (newExtent[0] >= newExtent[1]) {
          newExtent[0] = d3.time.day.utc.floor(origExtent[0]);
          newExtent[1] = d3.time.day.utc.floor(origExtent[1]);
        }
      }
      emitter.emit('brushed', [newExtent[0].toISOString(), newExtent[1].toISOString()]);
      d3.select(this).call(chart.brush.extent(newExtent));
      chart.fixBrushHandlers(d3.select(this));
    }

    var xScale = this.xScale();
    var initial = chart.initialExtent();

    var extentDates = [Date.parse(initial[0]), Date.parse(initial[1])];

    this.brush = d3.svg.brush()
      .x(xScale)
      .extent(extentDates)
      .on('brush', brushed);

    this.brushHandleGroup = this.base.append('g')
      .attr('id', 'brushHandleGroup')
      .call(this.brush);

    this.fixBrushHandlers(this.brushHandleGroup);

    var mainMargins = this.margins().main;

    this.brushHandleGroup.select('rect.background')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: 10,
        ry: 10
      })
      .style('visibility', 'visible');

    this.brushHandleGroup.select('rect.extent')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: 10,
        ry: 10
      });
  },
  fixBrushHandlers: function(brushNode) {
    var oldMousedown = brushNode.on('mousedown.brush');
    brushNode.on('mousedown.brush', function() {
      brushNode.on('mouseup.brush', function() {
        clearHandlers();
      });

      brushNode.on('mousemove.brush', function() {
        clearHandlers();
        oldMousedown.call(this);
      });

      function clearHandlers() {
        brushNode.on('mousemove.brush', null);
        brushNode.on('mouseup.brush', null);
      }
    });
  },
  remove: function() {
    this.base.remove();
    return this;
  }
});

var chart;

module.exports = {
  create: function(el, dateDomain, opts) {
    opts = opts || {};
    var defaults = {
      baseMargin: opts.baseMargin || 10,
      brushHeight: el.offsetHeight,
      initialExtent: [d3.time.day.utc.offset(new Date(dateDomain[1]), -14), new Date(dateDomain[1])]
    };
    defaults.margins = {
      main: {
        top: defaults.baseMargin + 11,
        right: defaults.baseMargin,
        bottom: defaults.baseMargin - 5,
        left: defaults.baseMargin
      }
    };
    _.defaults(opts, defaults);

    var xScale = d3.time.scale.utc()
      .domain([
        d3.time.day.utc.floor(new Date(dateDomain[0])),
        d3.time.day.utc.ceil(new Date(dateDomain[1]))
      ]);

    chart = d3.select(el)
      .append('svg')
      .attr({
        width: el.offsetWidth,
        height: opts.brushHeight
      })
      .chart('Brush')
      .emitter(this.emitter)
      .initialExtent(opts.initialExtent)
      .margins(opts.margins)
      .xScale(xScale);

    return this;
  },
  getCurrentDay: function() {
    return new Date(chart.brush.extent()[1].valueOf() - 864e5/2);
  },
  emitter: new EventEmitter(),
  render: function(data, opts) {
    opts = opts || {};
    var defaults = {};
    _.defaults(opts, defaults);

    chart.draw();

    return this;
  },
  setExtent: function(newExtent) {
    chart.setExtent(newExtent);
  },
  destroy: function() {
    chart.remove();

    return this;
  }
};<commit_msg>when select larger domain at left edge, expand domain rightwards instead of leftwards (off the scale)<commit_after>var _ = require('lodash');
var crossfilter = require('crossfilter');
var d3 = window.d3;
var EventEmitter = require('events').EventEmitter;

d3.chart('Brush', {
  initialize: function() {
    var chart = this;

    this.width = this.base.attr('width');
    this.height = this.base.attr('height');

    this.base.append('g').attr('id', 'brushMainGroup');
  },
  emitter: function(emitter) {
    if (!arguments.length) { return this._emitter; }
    this._emitter = emitter;
    return this;
  },
  initialExtent: function(initialExtent) {
    if (!arguments.length) { return this._initialExtent; }
    this._initialExtent = initialExtent;
    return this;
  },
  margins: function(margins) {
    if (!arguments.length) { return this._margins; }
    this._margins = margins;
    return this;
  },
  setExtent: function(newExtent) {
    var xScale = this.xScale();
    var scaleDomain = xScale.domain();
    if (newExtent[0] < scaleDomain[0]) {
      var extentSize = (newExtent[1] - newExtent[0])/862e5;
      var s = d3.time.day.utc.floor(scaleDomain[0]);
      newExtent = [s, d3.time.day.utc.offset(s, extentSize)];
    }
    this.brushHandleGroup.call(this.brush.extent(newExtent));
    this.fixBrushHandlers(this.brushHandleGroup);
    return this;
  },
  xScale: function(xScale) {
    if (!arguments.length) { return this._xScale; }
    var w = this.width;
    var mainMargins = this.margins().main;
    this._xScale = xScale.range([
      mainMargins.left,
      w - mainMargins.right
    ]);
    this.makeBrush();
    var domainAxis = d3.svg.axis()
      .scale(xScale)
      .orient('top')
      .ticks(d3.time.month.utc, 1)
      .tickFormat(d3.time.format.utc('%b'));
    this.base.append('g')
      .attr({
        id: 'domainAxis',
        transform: 'translate(0,' + mainMargins.top + ')'
      })
      .call(domainAxis);
    return this;
  },
  makeBrush: function() {
    var chart = this, emitter = this.emitter();
    function brushed() {
      var MS_IN_24 = 86400000;
      var origExtent = chart.brush.extent(), newExtent;
      // preserve width of handle on drag
      if (d3.event.mode === 'move') {
        var s = d3.time.day.utc.round(origExtent[0]),
          e = d3.time.day.utc.offset(s, Math.round((origExtent[1] - origExtent[0])/MS_IN_24));
        newExtent = [s, e];
      }
      // on resize, round to midnights
      else {
        newExtent = origExtent.map(d3.time.day.utc.round);

        // if empty when rounded, use floor & ceil instead
        // i.e., enforce min of 1 day
        if (newExtent[0] >= newExtent[1]) {
          newExtent[0] = d3.time.day.utc.floor(origExtent[0]);
          newExtent[1] = d3.time.day.utc.floor(origExtent[1]);
        }
      }
      emitter.emit('brushed', [newExtent[0].toISOString(), newExtent[1].toISOString()]);
      d3.select(this).call(chart.brush.extent(newExtent));
      chart.fixBrushHandlers(d3.select(this));
    }

    var xScale = this.xScale();
    var initial = chart.initialExtent();

    var extentDates = [Date.parse(initial[0]), Date.parse(initial[1])];

    this.brush = d3.svg.brush()
      .x(xScale)
      .extent(extentDates)
      .on('brush', brushed);

    this.brushHandleGroup = this.base.append('g')
      .attr('id', 'brushHandleGroup')
      .call(this.brush);

    this.fixBrushHandlers(this.brushHandleGroup);

    var mainMargins = this.margins().main;

    this.brushHandleGroup.select('rect.background')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: 10,
        ry: 10
      })
      .style('visibility', 'visible');

    this.brushHandleGroup.select('rect.extent')
      .attr({
        height: this.height - mainMargins.top - mainMargins.bottom,
        transform: 'translate(0,' + mainMargins.top + ')',
        rx: 10,
        ry: 10
      });
  },
  fixBrushHandlers: function(brushNode) {
    var oldMousedown = brushNode.on('mousedown.brush');
    brushNode.on('mousedown.brush', function() {
      brushNode.on('mouseup.brush', function() {
        clearHandlers();
      });

      brushNode.on('mousemove.brush', function() {
        clearHandlers();
        oldMousedown.call(this);
      });

      function clearHandlers() {
        brushNode.on('mousemove.brush', null);
        brushNode.on('mouseup.brush', null);
      }
    });
  },
  remove: function() {
    this.base.remove();
    return this;
  }
});

var chart;

module.exports = {
  create: function(el, dateDomain, opts) {
    opts = opts || {};
    var defaults = {
      baseMargin: opts.baseMargin || 10,
      brushHeight: el.offsetHeight,
      initialExtent: [d3.time.day.utc.offset(new Date(dateDomain[1]), -14), new Date(dateDomain[1])]
    };
    defaults.margins = {
      main: {
        top: defaults.baseMargin + 11,
        right: defaults.baseMargin,
        bottom: defaults.baseMargin - 5,
        left: defaults.baseMargin
      }
    };
    _.defaults(opts, defaults);

    var xScale = d3.time.scale.utc()
      .domain([
        d3.time.day.utc.floor(new Date(dateDomain[0])),
        d3.time.day.utc.ceil(new Date(dateDomain[1]))
      ]);

    chart = d3.select(el)
      .append('svg')
      .attr({
        width: el.offsetWidth,
        height: opts.brushHeight
      })
      .chart('Brush')
      .emitter(this.emitter)
      .initialExtent(opts.initialExtent)
      .margins(opts.margins)
      .xScale(xScale);

    return this;
  },
  getCurrentDay: function() {
    return new Date(chart.brush.extent()[1].valueOf() - 864e5/2);
  },
  emitter: new EventEmitter(),
  render: function(data, opts) {
    opts = opts || {};
    var defaults = {};
    _.defaults(opts, defaults);

    chart.draw();

    return this;
  },
  setExtent: function(newExtent) {
    chart.setExtent(newExtent);
  },
  destroy: function() {
    chart.remove();

    return this;
  }
};<|endoftext|>


<commit_before>defineSuite([
        'Scene/Cesium3DTile',
        'Core/Cartesian3',
        'Core/clone',
        'Core/Color',
        'Core/HeadingPitchRoll',
        'Core/Math',
        'Core/Matrix3',
        'Core/Matrix4',
        'Core/Rectangle',
        'Core/Transforms',
        'Scene/Cesium3DTileRefine',
        'Scene/TileBoundingRegion',
        'Scene/TileOrientedBoundingBox',
        'Specs/createScene'
    ], function(
        Cesium3DTile,
        Cartesian3,
        clone,
        Color,
        HeadingPitchRoll,
        CesiumMath,
        Matrix3,
        Matrix4,
        Rectangle,
        Transforms,
        Cesium3DTileRefine,
        TileBoundingRegion,
        TileOrientedBoundingBox,
        createScene) {
    'use strict';

    var tileWithBoundingSphere = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume : {
            sphere: [0.0, 0.0, 0.0, 5.0]
        }
    };

    var tileWithContentBoundingSphere = {
        geometricError : 1,
        refine : 'REPLACE',
        content : {
            url : '0/0.b3dm',
            boundingVolume : {
                sphere: [0.0, 0.0, 1.0, 5.0]
            }
        },
        children : [],
        boundingVolume : {
            sphere: [0.0, 0.0, 1.0, 5.0]
        }
    };

    var tileWithBoundingRegion = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume: {
            region : [-1.2, -1.2, 0.0, 0.0, -30, -34]
        }
    };

    var tileWithContentBoundingRegion = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        content : {
            url : '0/0.b3dm',
            boundingVolume : {
                region : [-1.2, -1.2, 0, 0, -30, -34]
            }
        },
        boundingVolume: {
            region : [-1.2, -1.2, 0, 0, -30, -34]
        }
    };

    var tileWithBoundingBox = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume: {
            box : [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
        }
    };

    var tileWithContentBoundingBox = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        content : {
            url : '0/0.b3dm',
            boundingVolume : {
                box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0]
            }
        },
        boundingVolume: {
            box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0]
        }
    };

    var tileWithViewerRequestVolume = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume: {
            box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0]
        },
        viewerRequestVolume : {
            box : [0.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0]
        }
    };

    var mockTileset = {
        debugShowBoundingVolume : true,
        debugShowViewerRequestVolume : true,
        modelMatrix : Matrix4.IDENTITY,
        _geometricError : 2,
        _min : { centerZDepth: -1, dynamicSSEDistance: 1 },
        _max : { centerZDepth:  1, dynamicSSEDistance: 64 },
        _heatMapVariable: 'dynamicSSEDistance'
    };

    var centerLongitude = -1.31968;

    var scene;
    beforeEach(function() {
        scene = createScene();
        scene.frameState.passes.render = true;
    });

    afterEach(function() {
        scene.destroyForSpecs();
    });   var centerLatitude = 0.698874;

    function getTileTransform(longitude, latitude) {
        var transformCenter = Cartesian3.fromRadians(longitude, latitude, 0.0);
        var hpr = new HeadingPitchRoll();
        var transformMatrix = Transforms.headingPitchRollToFixedFrame(transformCenter, hpr);
        return Matrix4.pack(transformMatrix, new Array(16));
    }

    it('destroys', function() {
        var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
        expect(tile.isDestroyed()).toEqual(false);
        tile.destroy();
        expect(tile.isDestroyed()).toEqual(true);
    });

    it('throws if boundingVolume is undefined', function() {
        var tileWithoutBoundingVolume = clone(tileWithBoundingSphere, true);
        delete tileWithoutBoundingVolume.boundingVolume;
        expect(function() {
            return new Cesium3DTile(mockTileset, '/some_url', tileWithoutBoundingVolume, undefined);
        }).toThrowRuntimeError();
    });

    it('throws if boundingVolume does not contain a sphere, region, or box', function() {
        var tileWithoutBoundingVolume = clone(tileWithBoundingSphere, true);
        delete tileWithoutBoundingVolume.boundingVolume.sphere;
        expect(function() {
            return new Cesium3DTile(mockTileset, '/some_url', tileWithoutBoundingVolume, undefined);
        }).toThrowRuntimeError();
    });

    it('logs deprecation warning if refine is lowercase', function() {
        spyOn(Cesium3DTile, '_deprecationWarning');
        var header = clone(tileWithBoundingSphere, true);
        header.refine = 'replace';
        var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
        expect(tile.refine).toBe(Cesium3DTileRefine.REPLACE);
        expect(Cesium3DTile._deprecationWarning).toHaveBeenCalled();
    });

    it('logs deprecation warning if geometric error is undefined', function() {
        spyOn(Cesium3DTile, '_deprecationWarning');

        var geometricErrorMissing = clone(tileWithBoundingSphere, true);
        delete geometricErrorMissing.geometricError;

        var parent = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
        var child = new Cesium3DTile(mockTileset, '/some_url', geometricErrorMissing, parent);
        expect(child.geometricError).toBe(parent.geometricError);
        expect(child.geometricError).toBe(1);

        var tile = new Cesium3DTile(mockTileset, '/some_url', geometricErrorMissing, undefined);
        expect(tile.geometricError).toBe(mockTileset._geometricError);
        expect(tile.geometricError).toBe(2);

        expect(Cesium3DTile._deprecationWarning.calls.count()).toBe(2);
    });

    describe('bounding volumes', function() {
        it('returns the tile bounding volume if the content bounding volume is undefined', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
            expect(tile.boundingVolume).toBeDefined();
            expect(tile.contentBoundingVolume).toBe(tile.boundingVolume);
        });

        it('can have a bounding sphere', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
            var radius = tileWithBoundingSphere.boundingVolume.sphere[3];
            expect(tile.boundingVolume).toBeDefined();
            expect(tile.boundingVolume.boundingVolume.radius).toEqual(radius);
            expect(tile.boundingVolume.boundingVolume.center).toEqual(Cartesian3.ZERO);
        });

        it('can have a content bounding sphere', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingSphere, undefined);
            var radius = tileWithContentBoundingSphere.content.boundingVolume.sphere[3];
            expect(tile.contentBoundingVolume).toBeDefined();
            expect(tile.contentBoundingVolume.boundingVolume.radius).toEqual(radius);
            expect(tile.contentBoundingVolume.boundingVolume.center).toEqual(new Cartesian3(0.0, 0.0, 1.0));
        });

        it('can have a bounding region', function() {
            var box = tileWithBoundingRegion.boundingVolume.region;
            var rectangle = new Rectangle(box[0], box[1], box[2], box[3]);
            var minimumHeight = tileWithBoundingRegion.boundingVolume.region[4];
            var maximumHeight = tileWithBoundingRegion.boundingVolume.region[5];
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined);
            var tbr = new TileBoundingRegion({rectangle: rectangle, minimumHeight: minimumHeight, maximumHeight: maximumHeight});
            expect(tile.boundingVolume).toBeDefined();
            expect(tile.boundingVolume).toEqual(tbr);
        });

        it('can have a content bounding region', function() {
            var region = tileWithContentBoundingRegion.content.boundingVolume.region;
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingRegion, undefined);
            expect(tile.contentBoundingVolume).toBeDefined();
            var tbb = new TileBoundingRegion({
                rectangle: new Rectangle(region[0], region[1], region[2], region[3]),
                minimumHeight: region[4],
                maximumHeight: region[5]
            });
            expect(tile.contentBoundingVolume).toEqual(tbb);
        });

        it('can have an oriented bounding box', function() {
            var box = tileWithBoundingBox.boundingVolume.box;
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox, undefined);
            expect(tile.boundingVolume).toBeDefined();
            var center = new Cartesian3(box[0], box[1], box[2]);
            var halfAxes = Matrix3.fromArray(box, 3);
            var obb = new TileOrientedBoundingBox(center, halfAxes);
            expect(tile.boundingVolume).toEqual(obb);
        });

        it('can have a content oriented bounding box', function() {
            var box = tileWithContentBoundingBox.boundingVolume.box;
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingBox, undefined);
            expect(tile.contentBoundingVolume).toBeDefined();
            var center = new Cartesian3(box[0], box[1], box[2]);
            var halfAxes = Matrix3.fromArray(box, 3);
            var obb = new TileOrientedBoundingBox(center, halfAxes);
            expect(tile.contentBoundingVolume).toEqual(obb);
        });

        it('tile transform affects bounding sphere', function() {
            var header = clone(tileWithContentBoundingSphere, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingSphere = tile.boundingVolume.boundingVolume;
            var contentBoundingSphere = tile.contentBoundingVolume.boundingVolume;

            var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0);
            expect(boundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON4);
            expect(boundingSphere.radius).toEqual(5.0); // No change

            expect(contentBoundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON4);
            expect(contentBoundingSphere.radius).toEqual(5.0); // No change
        });

        it('tile transform affects oriented bounding box', function() {
            var header = clone(tileWithContentBoundingBox, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingBox = tile.boundingVolume.boundingVolume;
            var contentBoundingBox = tile.contentBoundingVolume.boundingVolume;

            var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0);
            expect(boundingBox.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7);
            expect(contentBoundingBox.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7);
        });

        it('tile transform does not affect bounding region', function() {
            var header = clone(tileWithContentBoundingRegion, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingRegion = tile.boundingVolume;
            var contentBoundingRegion = tile.contentBoundingVolume;

            var region = header.boundingVolume.region;
            var rectangle = Rectangle.unpack(region);
            expect(boundingRegion.rectangle).toEqual(rectangle);
            expect(contentBoundingRegion.rectangle).toEqual(rectangle);
        });

        it('tile transform affects viewer request volume', function() {
            var header = clone(tileWithViewerRequestVolume, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var requestVolume = tile._viewerRequestVolume.boundingVolume;
            var requestVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0);
            expect(requestVolume.center).toEqualEpsilon(requestVolumeCenter, CesiumMath.EPSILON7);
        });

        it('tile transform changes', function() {
            var mockTileset = {
                modelMatrix : Matrix4.IDENTITY
            };
            var header = clone(tileWithBoundingSphere, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingSphere = tile.boundingVolume.boundingVolume;

            // Check the original transform
            var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude);
            expect(boundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7);

            // Change the transform
            var newLongitude = -1.012;
            var newLatitude = 0.698874;
            tile.transform = getTileTransform(newLongitude, newLatitude);
            tile.updateTransform();

            // Check the new transform
            var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude);
            expect(boundingSphere.center).toEqualEpsilon(newCenter, CesiumMath.EPSILON7);
        });
    });

    fdescribe('debug bounding volumes', function() {
        it('can be a bounding region', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugBoundingVolume).toBeDefined();
        });

        it('can be an oriented bounding box', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugBoundingVolume).toBeDefined();
        });

        it('can be a bounding sphere', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugBoundingVolume).toBeDefined();
        });

        it('creates debug bounding volume for viewer request volume', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithViewerRequestVolume, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugViewerRequestVolume).toBeDefined();
        });
    });

    fdescribe('heat map colorize', function() {
        it('has expected color', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined);
            tile._centerZDepth = (mockTileset._max.centerZDepth + mockTileset._min.centerZDepth) / 2; // In the middle of the min max window
            tile.update(mockTileset, scene.frameState);
            var expectedColor = new Color(0, 1, 0, 1); // Green is in the middle
            var tileColor = tile.color;
            var diff = new Color (
                                  Math.abs(expectedColor.red   - tileColor.red),
                                  Math.abs(expectedColor.green - tileColor.green),
                                  Math.abs(expectedColor.blue  - tileColor.blue)
            );

            var threshold = 0.01;
            expect(diff.red).toBeLessThan(threshold);
            expect(diff.green).toBeLessThan(threshold);
            expect(diff.blue).toBeLessThan(threshold);
        });
    });
}, 'WebGL');
<commit_msg>didn't save<commit_after>defineSuite([
        'Scene/Cesium3DTile',
        'Core/Cartesian3',
        'Core/clone',
        'Core/Color',
        'Core/HeadingPitchRoll',
        'Core/Math',
        'Core/Matrix3',
        'Core/Matrix4',
        'Core/Rectangle',
        'Core/Transforms',
        'Scene/Cesium3DTileRefine',
        'Scene/TileBoundingRegion',
        'Scene/TileOrientedBoundingBox',
        'Specs/createScene'
    ], function(
        Cesium3DTile,
        Cartesian3,
        clone,
        Color,
        HeadingPitchRoll,
        CesiumMath,
        Matrix3,
        Matrix4,
        Rectangle,
        Transforms,
        Cesium3DTileRefine,
        TileBoundingRegion,
        TileOrientedBoundingBox,
        createScene) {
    'use strict';

    var tileWithBoundingSphere = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume : {
            sphere: [0.0, 0.0, 0.0, 5.0]
        }
    };

    var tileWithContentBoundingSphere = {
        geometricError : 1,
        refine : 'REPLACE',
        content : {
            url : '0/0.b3dm',
            boundingVolume : {
                sphere: [0.0, 0.0, 1.0, 5.0]
            }
        },
        children : [],
        boundingVolume : {
            sphere: [0.0, 0.0, 1.0, 5.0]
        }
    };

    var tileWithBoundingRegion = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume: {
            region : [-1.2, -1.2, 0.0, 0.0, -30, -34]
        }
    };

    var tileWithContentBoundingRegion = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        content : {
            url : '0/0.b3dm',
            boundingVolume : {
                region : [-1.2, -1.2, 0, 0, -30, -34]
            }
        },
        boundingVolume: {
            region : [-1.2, -1.2, 0, 0, -30, -34]
        }
    };

    var tileWithBoundingBox = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume: {
            box : [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]
        }
    };

    var tileWithContentBoundingBox = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        content : {
            url : '0/0.b3dm',
            boundingVolume : {
                box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0]
            }
        },
        boundingVolume: {
            box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0]
        }
    };

    var tileWithViewerRequestVolume = {
        geometricError : 1,
        refine : 'REPLACE',
        children : [],
        boundingVolume: {
            box : [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0]
        },
        viewerRequestVolume : {
            box : [0.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0]
        }
    };

    var mockTileset = {
        debugShowBoundingVolume : true,
        debugShowViewerRequestVolume : true,
        modelMatrix : Matrix4.IDENTITY,
        _geometricError : 2,
        _min : { centerZDepth: -1, dynamicSSEDistance: 1 },
        _max : { centerZDepth:  1, dynamicSSEDistance: 64 },
        _heatMapVariable: 'dynamicSSEDistance'
    };

    var centerLongitude = -1.31968;

    var scene;
    beforeEach(function() {
        scene = createScene();
        scene.frameState.passes.render = true;
    });

    afterEach(function() {
        scene.destroyForSpecs();
    });   var centerLatitude = 0.698874;

    function getTileTransform(longitude, latitude) {
        var transformCenter = Cartesian3.fromRadians(longitude, latitude, 0.0);
        var hpr = new HeadingPitchRoll();
        var transformMatrix = Transforms.headingPitchRollToFixedFrame(transformCenter, hpr);
        return Matrix4.pack(transformMatrix, new Array(16));
    }

    it('destroys', function() {
        var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
        expect(tile.isDestroyed()).toEqual(false);
        tile.destroy();
        expect(tile.isDestroyed()).toEqual(true);
    });

    it('throws if boundingVolume is undefined', function() {
        var tileWithoutBoundingVolume = clone(tileWithBoundingSphere, true);
        delete tileWithoutBoundingVolume.boundingVolume;
        expect(function() {
            return new Cesium3DTile(mockTileset, '/some_url', tileWithoutBoundingVolume, undefined);
        }).toThrowRuntimeError();
    });

    it('throws if boundingVolume does not contain a sphere, region, or box', function() {
        var tileWithoutBoundingVolume = clone(tileWithBoundingSphere, true);
        delete tileWithoutBoundingVolume.boundingVolume.sphere;
        expect(function() {
            return new Cesium3DTile(mockTileset, '/some_url', tileWithoutBoundingVolume, undefined);
        }).toThrowRuntimeError();
    });

    it('logs deprecation warning if refine is lowercase', function() {
        spyOn(Cesium3DTile, '_deprecationWarning');
        var header = clone(tileWithBoundingSphere, true);
        header.refine = 'replace';
        var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
        expect(tile.refine).toBe(Cesium3DTileRefine.REPLACE);
        expect(Cesium3DTile._deprecationWarning).toHaveBeenCalled();
    });

    it('logs deprecation warning if geometric error is undefined', function() {
        spyOn(Cesium3DTile, '_deprecationWarning');

        var geometricErrorMissing = clone(tileWithBoundingSphere, true);
        delete geometricErrorMissing.geometricError;

        var parent = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
        var child = new Cesium3DTile(mockTileset, '/some_url', geometricErrorMissing, parent);
        expect(child.geometricError).toBe(parent.geometricError);
        expect(child.geometricError).toBe(1);

        var tile = new Cesium3DTile(mockTileset, '/some_url', geometricErrorMissing, undefined);
        expect(tile.geometricError).toBe(mockTileset._geometricError);
        expect(tile.geometricError).toBe(2);

        expect(Cesium3DTile._deprecationWarning.calls.count()).toBe(2);
    });

    describe('bounding volumes', function() {
        it('returns the tile bounding volume if the content bounding volume is undefined', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
            expect(tile.boundingVolume).toBeDefined();
            expect(tile.contentBoundingVolume).toBe(tile.boundingVolume);
        });

        it('can have a bounding sphere', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
            var radius = tileWithBoundingSphere.boundingVolume.sphere[3];
            expect(tile.boundingVolume).toBeDefined();
            expect(tile.boundingVolume.boundingVolume.radius).toEqual(radius);
            expect(tile.boundingVolume.boundingVolume.center).toEqual(Cartesian3.ZERO);
        });

        it('can have a content bounding sphere', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingSphere, undefined);
            var radius = tileWithContentBoundingSphere.content.boundingVolume.sphere[3];
            expect(tile.contentBoundingVolume).toBeDefined();
            expect(tile.contentBoundingVolume.boundingVolume.radius).toEqual(radius);
            expect(tile.contentBoundingVolume.boundingVolume.center).toEqual(new Cartesian3(0.0, 0.0, 1.0));
        });

        it('can have a bounding region', function() {
            var box = tileWithBoundingRegion.boundingVolume.region;
            var rectangle = new Rectangle(box[0], box[1], box[2], box[3]);
            var minimumHeight = tileWithBoundingRegion.boundingVolume.region[4];
            var maximumHeight = tileWithBoundingRegion.boundingVolume.region[5];
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined);
            var tbr = new TileBoundingRegion({rectangle: rectangle, minimumHeight: minimumHeight, maximumHeight: maximumHeight});
            expect(tile.boundingVolume).toBeDefined();
            expect(tile.boundingVolume).toEqual(tbr);
        });

        it('can have a content bounding region', function() {
            var region = tileWithContentBoundingRegion.content.boundingVolume.region;
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingRegion, undefined);
            expect(tile.contentBoundingVolume).toBeDefined();
            var tbb = new TileBoundingRegion({
                rectangle: new Rectangle(region[0], region[1], region[2], region[3]),
                minimumHeight: region[4],
                maximumHeight: region[5]
            });
            expect(tile.contentBoundingVolume).toEqual(tbb);
        });

        it('can have an oriented bounding box', function() {
            var box = tileWithBoundingBox.boundingVolume.box;
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox, undefined);
            expect(tile.boundingVolume).toBeDefined();
            var center = new Cartesian3(box[0], box[1], box[2]);
            var halfAxes = Matrix3.fromArray(box, 3);
            var obb = new TileOrientedBoundingBox(center, halfAxes);
            expect(tile.boundingVolume).toEqual(obb);
        });

        it('can have a content oriented bounding box', function() {
            var box = tileWithContentBoundingBox.boundingVolume.box;
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithContentBoundingBox, undefined);
            expect(tile.contentBoundingVolume).toBeDefined();
            var center = new Cartesian3(box[0], box[1], box[2]);
            var halfAxes = Matrix3.fromArray(box, 3);
            var obb = new TileOrientedBoundingBox(center, halfAxes);
            expect(tile.contentBoundingVolume).toEqual(obb);
        });

        it('tile transform affects bounding sphere', function() {
            var header = clone(tileWithContentBoundingSphere, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingSphere = tile.boundingVolume.boundingVolume;
            var contentBoundingSphere = tile.contentBoundingVolume.boundingVolume;

            var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0);
            expect(boundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON4);
            expect(boundingSphere.radius).toEqual(5.0); // No change

            expect(contentBoundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON4);
            expect(contentBoundingSphere.radius).toEqual(5.0); // No change
        });

        it('tile transform affects oriented bounding box', function() {
            var header = clone(tileWithContentBoundingBox, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingBox = tile.boundingVolume.boundingVolume;
            var contentBoundingBox = tile.contentBoundingVolume.boundingVolume;

            var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0);
            expect(boundingBox.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7);
            expect(contentBoundingBox.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7);
        });

        it('tile transform does not affect bounding region', function() {
            var header = clone(tileWithContentBoundingRegion, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingRegion = tile.boundingVolume;
            var contentBoundingRegion = tile.contentBoundingVolume;

            var region = header.boundingVolume.region;
            var rectangle = Rectangle.unpack(region);
            expect(boundingRegion.rectangle).toEqual(rectangle);
            expect(contentBoundingRegion.rectangle).toEqual(rectangle);
        });

        it('tile transform affects viewer request volume', function() {
            var header = clone(tileWithViewerRequestVolume, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var requestVolume = tile._viewerRequestVolume.boundingVolume;
            var requestVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude, 1.0);
            expect(requestVolume.center).toEqualEpsilon(requestVolumeCenter, CesiumMath.EPSILON7);
        });

        it('tile transform changes', function() {
            var mockTileset = {
                modelMatrix : Matrix4.IDENTITY
            };
            var header = clone(tileWithBoundingSphere, true);
            header.transform = getTileTransform(centerLongitude, centerLatitude);
            var tile = new Cesium3DTile(mockTileset, '/some_url', header, undefined);
            var boundingSphere = tile.boundingVolume.boundingVolume;

            // Check the original transform
            var boundingVolumeCenter = Cartesian3.fromRadians(centerLongitude, centerLatitude);
            expect(boundingSphere.center).toEqualEpsilon(boundingVolumeCenter, CesiumMath.EPSILON7);

            // Change the transform
            var newLongitude = -1.012;
            var newLatitude = 0.698874;
            tile.transform = getTileTransform(newLongitude, newLatitude);
            tile.updateTransform();

            // Check the new transform
            var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude);
            expect(boundingSphere.center).toEqualEpsilon(newCenter, CesiumMath.EPSILON7);
        });
    });

    describe('debug bounding volumes', function() {
        it('can be a bounding region', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugBoundingVolume).toBeDefined();
        });

        it('can be an oriented bounding box', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingBox, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugBoundingVolume).toBeDefined();
        });

        it('can be a bounding sphere', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingSphere, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugBoundingVolume).toBeDefined();
        });

        it('creates debug bounding volume for viewer request volume', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithViewerRequestVolume, undefined);
            tile.update(mockTileset, scene.frameState);
            expect(tile._debugViewerRequestVolume).toBeDefined();
        });
    });

    describe('heat map colorize', function() {
        it('has expected color', function() {
            var tile = new Cesium3DTile(mockTileset, '/some_url', tileWithBoundingRegion, undefined);
            tile._centerZDepth = (mockTileset._max.centerZDepth + mockTileset._min.centerZDepth) / 2; // In the middle of the min max window
            tile.update(mockTileset, scene.frameState);
            var expectedColor = new Color(0, 1, 0, 1); // Green is in the middle
            var tileColor = tile.color;
            var diff = new Color (
                                  Math.abs(expectedColor.red   - tileColor.red),
                                  Math.abs(expectedColor.green - tileColor.green),
                                  Math.abs(expectedColor.blue  - tileColor.blue)
            );

            var threshold = 0.01;
            expect(diff.red).toBeLessThan(threshold);
            expect(diff.green).toBeLessThan(threshold);
            expect(diff.blue).toBeLessThan(threshold);
        });
    });
}, 'WebGL');
<|endoftext|>


<commit_before>const lib = require("../lib");
const fs = require("fs");
const path = require("path");

const diskSize = Math.floor(Math.random() * 1E11);
const freeSpace = Math.floor(Math.random() * diskSize);

// Note: all fields MUST be in lowercase!
const processes = JSON.parse(fs.readFileSync(path.join(__dirname, "processes.json"), "utf8"));
const tables = {
	antivirusproduct: [],
	win32_computersystemproduct: [],
	win32_logicaldisk: [{ // dirty patch by @ALange
		deviceid: "C:",
		drivetype: 3,
		freespace: freeSpace,
		size: diskSize,
		volumeserialnumber: "B55B4A40",
	}],
	win32_operatingsystem: [{
		version: "5.3",
		caption: "Windows XP"
	}],
	win32_process: processes
};

Object.keys(tables).forEach(name => {
	if (/[A-Z]/.test(name))
		lib.kill("Internal error: non-lowercase table name");
	tables[name].forEach(row => Object.keys(row).forEach(label => {
		if (/[A-Z]/.test(label))
			lib.kill("Internal error: non-lowercase property");
	}));
});

function getTable(_tableName) {
	const tableName = _tableName.toLowerCase();
	if (tableName === "win32_process")
		lib.info("Script tried to read the list of processes");
	lib.verbose(`Script tried to read table ${tableName}`);
	if (!(tableName in tables))
		lib.kill("Table ${tableName} not implemented!");
	// Proxify everything
	return tables[tableName].map(row => new Proxy(row, {
		get(target, _prop) {
			const prop = _prop.toLowerCase();
			if (prop in target) return target[prop];
			lib.kill(`${tableName}.${prop} not implemented!`);
		},
	}));
}

module.exports.GetObject = function(name) {
/*
	name = name.toLowerCase();
	name = name.replace(/{impersonationlevel=impersonate}/g, "");
	switch (name) {
		case "winmgmts:":
			// ...
		case "winmgmts:\\\\localhost\\root\\securitycenter":
		case "winmgmts:\\\\localhost\\root\\securitycenter2":
			// ...
		default:
			lib.kill(`GetObject(${name}) not implemented!`);
	}
*/
	return new Proxy({
		InstancesOf: getTable,
		ExecQuery: query => {
			// TODO: implement actual SQL
			const parts = query.match(/^select +(\*|(?:\w+, *)*(?:\w+)) +from +(\w+)/i);
			if (!parts)
				lib.kill(`Not implemented: query "${query}"`);
			// For now, fields are ignored.
			// const fields = parts[1];
			const tableName = parts[2].toLowerCase();
			return getTable(tableName);
		},
	}, {
		get(target, name) {
			if (name in target) return target[name];
			lib.kill(`WMI.GetObject.${name} not implemented!`);
		},
	});
};<commit_msg>Add some WMI objects (fixes #55)<commit_after>const lib = require("../lib");
const fs = require("fs");
const path = require("path");

const diskSize = Math.floor(Math.random() * 1E11);
const freeSpace = Math.floor(Math.random() * diskSize);

// Note: all fields MUST be in lowercase!
const processes = JSON.parse(fs.readFileSync(path.join(__dirname, "processes.json"), "utf8"));
const tables = {
	antivirusproduct: [],
	win32_computersystemproduct: [],
	win32_logicaldisk: [{ // dirty patch by @ALange
		deviceid: "C:",
		drivetype: 3,
		freespace: freeSpace,
		size: diskSize,
		volumeserialnumber: "B55B4A40",
	}],
	win32_operatingsystem: [{
		version: "5.3",
		caption: "Windows XP"
	}],
	win32_process: processes,
};

const classes = {
	win32_process: new Proxy(processes, {
		get(target, _prop) {
			const prop = _prop.toLowerCase();
			if (prop in target) return target[prop];
			if (prop === "create")
				return command => {
					lib.logIOC("CommandExec", command, "The script executed a command.");
					lib.logSnippet(lib.getUUID(), {as: "command"}, command);
				}
			lib.kill(`Win32_Process.${prop} not implemented!`);
		},
	}),
	win32_processstartup: new Proxy({
		spawninstance_: () => {}
	}, {
		get(target, _prop) {
			const prop = _prop.toLowerCase();
			if (prop in target) return target[prop];
			lib.kill(`Win32_Process.${prop} not implemented!`);
		},
	})
}

Object.keys(tables).forEach(name => {
	if (/[A-Z]/.test(name))
		lib.kill("Internal error: non-lowercase table name");
	tables[name].forEach(row => Object.keys(row).forEach(label => {
		if (/[A-Z]/.test(label))
			lib.kill("Internal error: non-lowercase property");
	}));
});

function getTable(_tableName) {
	const tableName = _tableName.toLowerCase();
	if (tableName === "win32_process")
		lib.info("Script tried to read the list of processes");
	lib.verbose(`Script tried to read table ${tableName}`);
	if (!(tableName in tables))
		lib.kill(`Table ${tableName} not implemented!`);
	// Proxify everything
	return tables[tableName].map(row => new Proxy(row, {
		get(target, _prop) {
			const prop = _prop.toLowerCase();
			if (prop in target) return target[prop];
			lib.kill(`${tableName}.${prop} not implemented!`);
		},
	}));
}

module.exports.GetObject = function(name) {
/*
	name = name.toLowerCase();
	name = name.replace(/{impersonationlevel=impersonate}/g, "");
	switch (name) {
		case "winmgmts:":
			// ...
		case "winmgmts:\\\\localhost\\root\\securitycenter":
		case "winmgmts:\\\\localhost\\root\\securitycenter2":
			// ...
		default:
			lib.kill(`GetObject(${name}) not implemented!`);
	}
*/
	return new Proxy({
		InstancesOf: getTable,
		ExecQuery: query => {
			// TODO: implement actual SQL
			const parts = query.match(/^select +(\*|(?:\w+, *)*(?:\w+)) +from +(\w+)/i);
			if (!parts)
				lib.kill(`Not implemented: query "${query}"`);
			// For now, fields are ignored.
			// const fields = parts[1];
			const tableName = parts[2].toLowerCase();
			return getTable(tableName);
		},
		Get: className => {
			const _class = classes[className.toLowerCase()];
			if (!_class)
				lib.kill(`Not implemented: WMI.Get(${className})`);
			return _class;
		},
	}, {
		get(target, name) {
			if (name in target) return target[name];
			lib.kill(`WMI.GetObject.${name} not implemented!`);
		},
	});
};<|endoftext|>


<commit_before>const fireEvent = require("../../test/helpers").fireEvent

describe('su-checkbox-options', function () {
  let tag
  let spyOnClick = sinon.spy()

  beforeEach(function () {
    $('body').append('<su-checkbox>Make my profile visible</su-checkbox>')
    tag = riot.mount('su-checkbox', {
      check: true
    })[0]
    tag.on('click', spyOnClick)
    this.clock = sinon.useFakeTimers()
  })

  afterEach(function () {
    spyOnClick.reset()
    this.clock.restore()
    tag.unmount()
  })

  it('is mounted', function () {
    tag.isMounted.should.be.true
  })

  it('default checked', function () {
    tag.checked.should.equal(true)
  })

  it('click checkbox', function () {
    tag.checked.should.equal(true)

    $('su-checkbox input').click()
    spyOnClick.should.have.been.calledOnce
    tag.checked.should.equal(false)

    $('su-checkbox input').click()
    spyOnClick.should.have.been.calledTwice
    tag.checked.should.equal(true)
  })

  /*
  it('click label', function () {
    tag.checked.should.equal(true)

    fireEvent($('su-checkbox label')[0], 'click')
    spyOnClick.should.have.been.calledOnce
    tag.checked.should.equal(false)

    fireEvent($('su-checkbox label')[0], 'click')
    spyOnClick.should.have.been.calledTwice
    tag.checked.should.equal(true)
  })
  */

  it('update checked', function () {
    tag.checked.should.equal(true)

    tag.checked = false
    tag.checked.should.equal(false)

    tag.checked = true
    tag.checked.should.equal(true)

    spyOnClick.should.have.been.callCount(0)
  })
})
<commit_msg>Add test for su-checkbox<commit_after>const fireEvent = require("../../test/helpers").fireEvent

describe('su-checkbox-options', function () {
  let tag
  let spyOnClick = sinon.spy()
  let mount = opts => {
    tag = riot.mount('su-checkbox', opts)[0]
    tag.on('click', spyOnClick)
  }

  beforeEach(function () {
    $('body').append('<su-checkbox>Make my profile visible</su-checkbox>')
  })

  afterEach(function () {
    spyOnClick.reset()
    tag.unmount()
  })

  it('is mounted', function () {
    mount()
    tag.isMounted.should.be.true
  })

  it('click checkbox', function () {
    mount({ check: true })
    tag.checked.should.equal(true)

    $('su-checkbox input').click()
    spyOnClick.should.have.been.calledOnce
    tag.checked.should.equal(false)

    $('su-checkbox input').click()
    spyOnClick.should.have.been.calledTwice
    tag.checked.should.equal(true)
  })

  it('readonly', function () {
    mount({ class: 'read-only' })
    tag.checked.should.equal(false)

    $('su-checkbox input').click()
    tag.checked.should.equal(false)
    spyOnClick.should.have.been.callCount(0)
  })

  it('disabled', function () {
    mount({ class: 'disabled' })
    tag.checked.should.equal(false)

    $('su-checkbox input').click()
    tag.checked.should.equal(false)
    spyOnClick.should.have.been.callCount(0)
  })

  it('update checked', function () {
    mount({ check: true })
    tag.checked.should.equal(true)

    tag.checked = false
    tag.checked.should.equal(false)

    tag.checked = true
    tag.checked.should.equal(true)

    spyOnClick.should.have.been.callCount(0)
  })
})
<|endoftext|>


<commit_before>// LICENSE : MIT
"use strict";
var assert = require("power-assert");
describe("PassTest", function () {
    it("is passed", function () {
        var object = {
            name: "Tom object"
        };
        assert.deepEqual(object, {
            name: "Tom object"
        });
    });
});<commit_msg>chore(example): transparent empowerment of assert module<commit_after>// LICENSE : MIT
"use strict";
var assert = require("assert");
describe("PassTest", function () {
    it("is passed", function () {
        var object = {
            name: "Tom object"
        };
        assert.deepEqual(object, {
            name: "Tom object"
        });
    });
});
<|endoftext|>


<commit_before>/* @flow */

import _ from 'lodash';

/**
 * Sets specific properties of a specific state to specific values and prevents
 * unnecessary state changes.
 *
 * @param {Object} target - The state on which the specified properties are to
 * be set.
 * @param {Object} source - The map of properties to values which are to be set
 * on the specified target.
 * @returns {Object} The specified target if the values of the specified
 * properties equal the specified values; otherwise, a new state constructed
 * from the specified target by setting the specified properties to the
 * specified values.
 */
export function assign(target: Object, source: Object) {
    let t = target;

    for (const property in source) { // eslint-disable-line guard-for-in
        t = set(t, property, source[property], t === target);
    }

    return t;
}

/**
 * Determines whether {@code a} equals {@code b} according to deep comparison
 * (which makes sense for Redux and its state definition).
 *
 * @param {*} a - The value to compare to {@code b}.
 * @param {*} b - The value to compare to {@code a}.
 * @returns {boolean} True if {@code a} equals {@code b} (according to deep
 * comparison); false, otherwise.
 */
export function equals(a: any, b: any) {
    return _.isEqual(a, b);
}

/**
 * Sets a specific property of a specific state to a specific value. Prevents
 * unnecessary state changes (when the specified {@code value} is equal to the
 * value of the specified {@code property} of the specified {@code state}).
 *
 * @param {Object} state - The (Redux) state from which a new state is to be
 * constructed by setting the specified {@code property} to the specified
 * {@code value}.
 * @param {string} property - The property of {@code state} which is to be
 * assigned the specified {@code value} (in the new state).
 * @param {*} value - The value to assign to the specified {@code property}.
 * @returns {Object} The specified {@code state} if the value of the specified
 * {@code property} equals the specified <tt>value/tt>; otherwise, a new state
 * constructed from the specified {@code state} by setting the specified
 * {@code property} to the specified {@code value}.
 */
export function set(state: Object, property: string, value: any) {
    return _set(state, property, value, /* copyOnWrite */ true);
}

/* eslint-disable max-params */

/**
 * Sets a specific property of a specific state to a specific value. Prevents
 * unnecessary state changes (when the specified {@code value} is equal to the
 * value of the specified {@code property} of the specified {@code state}).
 *
 * @param {Object} state - The (Redux) state from which a state is to be
 * constructed by setting the specified {@code property} to the specified
 * {@code value}.
 * @param {string} property - The property of {@code state} which is to be
 * assigned the specified {@code value}.
 * @param {*} value - The value to assign to the specified {@code property}.
 * @param {boolean} copyOnWrite - If the specified {@code state} is to not be
 * modified, {@code true}; otherwise, {@code false}.
 * @returns {Object} The specified {@code state} if the value of the specified
 * {@code property} equals the specified <tt>value/tt> or {@code copyOnWrite}
 * is truthy; otherwise, a new state constructed from the specified
 * {@code state} by setting the specified {@code property} to the specified
 * {@code value}.
 */
function _set(
        state: Object,
        property: string,
        value: any,
        copyOnWrite: boolean) {
    // Delete state properties that are to be set to undefined. (It is a matter
    // of personal preference, mostly.)
    if (typeof value === 'undefined'
            && Object.prototype.hasOwnProperty.call(state, property)) {
        const newState = copyOnWrite ? { ...state } : state;

        if (delete newState[property]) {
            return newState;
        }
    }

    if (state[property] !== value) {
        if (copyOnWrite) {
            return {
                ...state,
                [property]: value
            };
        }

        state[property] = value;
    }

    return state;
}

/* eslint-enable max-params */

/**
 * Returns redux state from the specified {@code stateful} which is presumed to
 * be related to the redux state (e.g. the redux store, the redux
 * {@code getState} function).
 *
 * @param {Function|Object} stateful - The entity such as the redux store or the
 * redux {@code getState} function from which the redux state is to be
 * returned.
 * @returns {Object} The redux state.
 */
export function toState(stateful: Function | Object) {
    if (stateful) {
        if (typeof stateful === 'function') {
            return stateful();
        }

        const { getState } = stateful;

        if (typeof getState === 'function') {
            return getState();
        }
    }

    return stateful;
}
<commit_msg>fix(redux/functions): fix typo<commit_after>/* @flow */

import _ from 'lodash';

/**
 * Sets specific properties of a specific state to specific values and prevents
 * unnecessary state changes.
 *
 * @param {Object} target - The state on which the specified properties are to
 * be set.
 * @param {Object} source - The map of properties to values which are to be set
 * on the specified target.
 * @returns {Object} The specified target if the values of the specified
 * properties equal the specified values; otherwise, a new state constructed
 * from the specified target by setting the specified properties to the
 * specified values.
 */
export function assign(target: Object, source: Object) {
    let t = target;

    for (const property in source) { // eslint-disable-line guard-for-in
        t = _set(t, property, source[property], t === target);
    }

    return t;
}

/**
 * Determines whether {@code a} equals {@code b} according to deep comparison
 * (which makes sense for Redux and its state definition).
 *
 * @param {*} a - The value to compare to {@code b}.
 * @param {*} b - The value to compare to {@code a}.
 * @returns {boolean} True if {@code a} equals {@code b} (according to deep
 * comparison); false, otherwise.
 */
export function equals(a: any, b: any) {
    return _.isEqual(a, b);
}

/**
 * Sets a specific property of a specific state to a specific value. Prevents
 * unnecessary state changes (when the specified {@code value} is equal to the
 * value of the specified {@code property} of the specified {@code state}).
 *
 * @param {Object} state - The (Redux) state from which a new state is to be
 * constructed by setting the specified {@code property} to the specified
 * {@code value}.
 * @param {string} property - The property of {@code state} which is to be
 * assigned the specified {@code value} (in the new state).
 * @param {*} value - The value to assign to the specified {@code property}.
 * @returns {Object} The specified {@code state} if the value of the specified
 * {@code property} equals the specified <tt>value/tt>; otherwise, a new state
 * constructed from the specified {@code state} by setting the specified
 * {@code property} to the specified {@code value}.
 */
export function set(state: Object, property: string, value: any) {
    return _set(state, property, value, /* copyOnWrite */ true);
}

/* eslint-disable max-params */

/**
 * Sets a specific property of a specific state to a specific value. Prevents
 * unnecessary state changes (when the specified {@code value} is equal to the
 * value of the specified {@code property} of the specified {@code state}).
 *
 * @param {Object} state - The (Redux) state from which a state is to be
 * constructed by setting the specified {@code property} to the specified
 * {@code value}.
 * @param {string} property - The property of {@code state} which is to be
 * assigned the specified {@code value}.
 * @param {*} value - The value to assign to the specified {@code property}.
 * @param {boolean} copyOnWrite - If the specified {@code state} is to not be
 * modified, {@code true}; otherwise, {@code false}.
 * @returns {Object} The specified {@code state} if the value of the specified
 * {@code property} equals the specified <tt>value/tt> or {@code copyOnWrite}
 * is truthy; otherwise, a new state constructed from the specified
 * {@code state} by setting the specified {@code property} to the specified
 * {@code value}.
 */
function _set(
        state: Object,
        property: string,
        value: any,
        copyOnWrite: boolean) {
    // Delete state properties that are to be set to undefined. (It is a matter
    // of personal preference, mostly.)
    if (typeof value === 'undefined'
            && Object.prototype.hasOwnProperty.call(state, property)) {
        const newState = copyOnWrite ? { ...state } : state;

        if (delete newState[property]) {
            return newState;
        }
    }

    if (state[property] !== value) {
        if (copyOnWrite) {
            return {
                ...state,
                [property]: value
            };
        }

        state[property] = value;
    }

    return state;
}

/* eslint-enable max-params */

/**
 * Returns redux state from the specified {@code stateful} which is presumed to
 * be related to the redux state (e.g. the redux store, the redux
 * {@code getState} function).
 *
 * @param {Function|Object} stateful - The entity such as the redux store or the
 * redux {@code getState} function from which the redux state is to be
 * returned.
 * @returns {Object} The redux state.
 */
export function toState(stateful: Function | Object) {
    if (stateful) {
        if (typeof stateful === 'function') {
            return stateful();
        }

        const { getState } = stateful;

        if (typeof getState === 'function') {
            return getState();
        }
    }

    return stateful;
}
<|endoftext|>


<commit_before>
Ui.Element.extend('Ui.Image',
/**@lends Ui.Image#*/
{
	src: undefined,
	loaddone: false,
	naturalWidth: undefined,
	naturalHeight: undefined,
	imageDrawing: undefined,
	setSrcLock: false,

	/**
	 * @constructs
	 * @class
	 * @extends Ui.Element
	 */
	constructor: function(config) {
		this.addEvents('ready', 'error');
		// no context menu
		this.connect(this.imageDrawing, 'contextmenu', function(event) {
			event.preventDefault();
		});

		this.connect(this.imageDrawing, 'load', this.onImageLoad);
		this.connect(this.imageDrawing, 'error', this.onImageError);
	},

	/**
	* Get the URL of the image
	*/
	getSrc: function() {
		return this.src;
	},

	/**
	* Set the URL of the image. When the image is loaded,
	* ready event is fired and getIsReady return true.
	*/
	setSrc: function(src) {
		if(src === undefined)
			throw('Image src cant be undefined');

		this.setSrcLock = true;
		this.loaddone = false;
		this.naturalWidth = undefined;
		this.naturalHeight = undefined;
		this.src = src;
		this.imageDrawing.setAttribute('src', src);
		this.setSrcLock = false;
	},

	/**
	* Return the natural width of the image as defined
	* in the image file. Return undefined if the image is
	* not ready
	*/
	getNaturalWidth: function() {
		return this.naturalWidth;
	},

	/**
	* Return the natural height of the image as defined
	* in the image file. Return undefined if the image is
	* not ready
	*/
	getNaturalHeight: function() {
		return this.naturalHeight;
	},

	/**
	* Return true if the image is loaded
	*/
	getIsReady: function() {
		return this.loaddone;
	},

	/**#@+
	* @private
	*/

	onImageError: function(event) {
		this.fireEvent('error', this);
	},

	onImageLoad: function(event) {
		if((event.target !== undefined) && (event.target !== null) && (event.target.naturalWidth !== undefined) && (event.target.naturalHeight !== undefined)) {
			this.loaddone = true;
			this.naturalWidth = event.target.naturalWidth;
			this.naturalHeight = event.target.naturalHeight;
			this.fireEvent('ready', this);
			this.invalidateMeasure();
		}
		else {
			if(this.setSrcLock)
				new Core.DelayedTask({ delay: 0, scope: this, callback: this.onImageDelayReady });
			else
				this.onImageDelayReady();
		}
	},

	onAppReady: function() {
		this.disconnect(Ui.App.current, 'ready', this.onAppReady);
		this.onImageDelayReady();
	},

	onIEDragStart: function(event) {
		event.defaultPrevented = true;
		event.returnValue = false;
		return false;
	},

	onImageDelayReady: function() {
		if(!Ui.App.current.getIsReady())
			this.connect(Ui.App.current, 'ready', this.onAppReady);
		else {
			this.loaddone = true;
			if((document.body === undefined) || (document.body === null)) {
				var body = document.createElement('body');
				document.body = body;
			}
			var imgClone = document.createElement('img');
			imgClone.setAttribute('src', this.src);
			document.body.appendChild(imgClone);
			this.naturalWidth = imgClone.width;
			this.naturalHeight = imgClone.height;
			document.body.removeChild(imgClone);
			this.fireEvent('ready', this);
			this.invalidateMeasure();
		}
	}

	/**#@-*/
},
/**@lends Ui.Image#*/
{
	renderDrawing: function() {
		this.imageDrawing = document.createElement('img');
		this.imageDrawing.style.position = 'absolute';
		this.imageDrawing.style.top = '0px';
		this.imageDrawing.style.left = '0px';
		this.imageDrawing.style.width = '0px';
		this.imageDrawing.style.height = '0px';
		this.imageDrawing.setAttribute('draggable', false);
		if(navigator.isWebkit) {
			// no text selection
			this.imageDrawing.style.webkitUserSelect = 'none';
			// no context menu
			this.imageDrawing.style.webkitTouchCallout = 'none';
		}
		else if(navigator.isGecko)
			this.imageDrawing.style.MozUserSelect = 'none';
		else if(navigator.isIE) {
			this.connect(this.imageDrawing, 'selectstart', function(event) { event.preventDefault(); });
			// disable drag & drop for IE < 9
			if('attachEvent' in this.imageDrawing)
				this.imageDrawing.attachEvent('ondragstart', this.onIEDragStart);
		}
		return this.imageDrawing;
	},

	measureCore: function(width, height) {
		if(!this.loaddone)
			return { width: 0, height: 0 };
		var size;
		if(this.getWidth() === undefined) {
			if(this.getHeight() === undefined)
				size = { width: this.naturalWidth, height: this.naturalHeight };
			else {
				var fixedHeight = this.getHeight() - (this.getMarginTop() + this.getMarginBottom());
				size = { width: (this.naturalWidth*fixedHeight)/this.naturalHeight, height: fixedHeight };
			}
		}
		else {
			if(this.getHeight() === undefined) {
				var fixedWidth = this.getWidth() - (this.getMarginLeft() + this.getMarginRight());
				size = { width: fixedWidth, height: (this.naturalHeight*fixedWidth)/this.naturalWidth };
			}
			else
				size = { width: 0, height: 0 };
		}
		return size;
	},

	arrangeCore: function(width, height) {
		if(this.imageDrawing !== undefined) {
			this.imageDrawing.style.width = width+'px';
			this.imageDrawing.style.height = height+'px';
		}
	}
});
<commit_msg>correct a bug in Ui.Image. When image is cached, the load event might never raises<commit_after>
Ui.Element.extend('Ui.Image',
/**@lends Ui.Image#*/
{
	src: undefined,
	loaddone: false,
	naturalWidth: undefined,
	naturalHeight: undefined,
	imageDrawing: undefined,
	setSrcLock: false,

	/**
	 * @constructs
	 * @class
	 * @extends Ui.Element
	 */
	constructor: function(config) {
		this.addEvents('ready', 'error');
		// no context menu
		this.connect(this.imageDrawing, 'contextmenu', function(event) {
			event.preventDefault();
		});

		this.connect(this.imageDrawing, 'load', this.onImageLoad);
		this.connect(this.imageDrawing, 'error', this.onImageError);
	},

	/**
	* Get the URL of the image
	*/
	getSrc: function() {
		return this.src;
	},

	/**
	* Set the URL of the image. When the image is loaded,
	* ready event is fired and getIsReady return true.
	*/
	setSrc: function(src) {
		if(src === undefined)
			throw('Image src cant be undefined');

		this.setSrcLock = true;
		this.loaddone = false;
		this.naturalWidth = undefined;
		this.naturalHeight = undefined;
		this.src = src;
		this.imageDrawing.setAttribute('src', src);
		if((this.imageDrawing.complete === true) && (this.loaddone !== true)) {
			this.loaddone = true;
			this.naturalWidth = this.imageDrawing.naturalWidth;
			this.naturalHeight = this.imageDrawing.naturalHeight;
			this.fireEvent('ready', this);
			this.invalidateMeasure();
		}
		this.setSrcLock = false;
	},

	/**
	* Return the natural width of the image as defined
	* in the image file. Return undefined if the image is
	* not ready
	*/
	getNaturalWidth: function() {
		return this.naturalWidth;
	},

	/**
	* Return the natural height of the image as defined
	* in the image file. Return undefined if the image is
	* not ready
	*/
	getNaturalHeight: function() {
		return this.naturalHeight;
	},

	/**
	* Return true if the image is loaded
	*/
	getIsReady: function() {
		return this.loaddone;
	},

	/**#@+
	* @private
	*/

	onImageError: function(event) {
		this.fireEvent('error', this);
	},

	onImageLoad: function(event) {
		if((event.target !== undefined) && (event.target !== null) && (event.target.naturalWidth !== undefined) && (event.target.naturalHeight !== undefined)) {
			this.loaddone = true;
			this.naturalWidth = event.target.naturalWidth;
			this.naturalHeight = event.target.naturalHeight;
			this.fireEvent('ready', this);
			this.invalidateMeasure();
		}
		else {
			if(this.setSrcLock)
				new Core.DelayedTask({ delay: 0, scope: this, callback: this.onImageDelayReady });
			else
				this.onImageDelayReady();
		}
	},

	onAppReady: function() {
		this.disconnect(Ui.App.current, 'ready', this.onAppReady);
		this.onImageDelayReady();
	},

	onIEDragStart: function(event) {
		event.defaultPrevented = true;
		event.returnValue = false;
		return false;
	},

	onImageDelayReady: function() {
		if(!Ui.App.current.getIsReady())
			this.connect(Ui.App.current, 'ready', this.onAppReady);
		else {
			this.loaddone = true;
			if((document.body === undefined) || (document.body === null)) {
				var body = document.createElement('body');
				document.body = body;
			}
			var imgClone = document.createElement('img');
			imgClone.setAttribute('src', this.src);
			document.body.appendChild(imgClone);
			this.naturalWidth = imgClone.width;
			this.naturalHeight = imgClone.height;
			document.body.removeChild(imgClone);
			this.fireEvent('ready', this);
			this.invalidateMeasure();
		}
	}

	/**#@-*/
},
/**@lends Ui.Image#*/
{
	renderDrawing: function() {
		this.imageDrawing = document.createElement('img');
		this.imageDrawing.style.position = 'absolute';
		this.imageDrawing.style.top = '0px';
		this.imageDrawing.style.left = '0px';
		this.imageDrawing.style.width = '0px';
		this.imageDrawing.style.height = '0px';
		this.imageDrawing.setAttribute('draggable', false);
		if(navigator.isWebkit) {
			// no text selection
			this.imageDrawing.style.webkitUserSelect = 'none';
			// no context menu
			this.imageDrawing.style.webkitTouchCallout = 'none';
		}
		else if(navigator.isGecko)
			this.imageDrawing.style.MozUserSelect = 'none';
		else if(navigator.isIE) {
			this.connect(this.imageDrawing, 'selectstart', function(event) { event.preventDefault(); });
			// disable drag & drop for IE < 9
			if('attachEvent' in this.imageDrawing)
				this.imageDrawing.attachEvent('ondragstart', this.onIEDragStart);
		}
		return this.imageDrawing;
	},

	measureCore: function(width, height) {
		if(!this.loaddone)
			return { width: 0, height: 0 };
		var size;
		if(this.getWidth() === undefined) {
			if(this.getHeight() === undefined)
				size = { width: this.naturalWidth, height: this.naturalHeight };
			else {
				var fixedHeight = this.getHeight() - (this.getMarginTop() + this.getMarginBottom());
				size = { width: (this.naturalWidth*fixedHeight)/this.naturalHeight, height: fixedHeight };
			}
		}
		else {
			if(this.getHeight() === undefined) {
				var fixedWidth = this.getWidth() - (this.getMarginLeft() + this.getMarginRight());
				size = { width: fixedWidth, height: (this.naturalHeight*fixedWidth)/this.naturalWidth };
			}
			else
				size = { width: 0, height: 0 };
		}
		return size;
	},

	arrangeCore: function(width, height) {
		if(this.imageDrawing !== undefined) {
			this.imageDrawing.style.width = width+'px';
			this.imageDrawing.style.height = height+'px';
		}
	}
});
<|endoftext|>