<commit_before>/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

import { FrontSide, BackSide, DoubleSide, RGBAFormat, NearestFilter, PCFShadowMap, RGBADepthPacking, NoBlending } from '../../constants.js';
import { WebGLRenderTarget } from '../WebGLRenderTarget.js';
import { MeshDepthMaterial } from '../../materials/MeshDepthMaterial.js';
import { MeshDistanceMaterial } from '../../materials/MeshDistanceMaterial.js';
import { Vector4 } from '../../math/Vector4.js';
import { Vector3 } from '../../math/Vector3.js';
import { Vector2 } from '../../math/Vector2.js';
import { Matrix4 } from '../../math/Matrix4.js';
import { Frustum } from '../../math/Frustum.js';

function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {

	var _frustum = new Frustum(),
		_projScreenMatrix = new Matrix4(),

		_shadowMapSize = new Vector2(),
		_maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ),

		_lookTarget = new Vector3(),
		_lightPositionWorld = new Vector3(),

		_MorphingFlag = 1,
		_SkinningFlag = 2,

		_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,

		_depthMaterials = new Array( _NumberOfMaterialVariants ),
		_distanceMaterials = new Array( _NumberOfMaterialVariants ),

		_materialCache = {};

	var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };

	var cubeDirections = [
		new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
		new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
	];

	var cubeUps = [
		new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
		new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),	new Vector3( 0, 0, - 1 )
	];

	var cube2DViewPorts = [
		new Vector4(), new Vector4(), new Vector4(),
		new Vector4(), new Vector4(), new Vector4()
	];

	// init

	for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {

		var useMorphing = ( i & _MorphingFlag ) !== 0;
		var useSkinning = ( i & _SkinningFlag ) !== 0;

		var depthMaterial = new MeshDepthMaterial( {

			depthPacking: RGBADepthPacking,

			morphTargets: useMorphing,
			skinning: useSkinning

		} );

		_depthMaterials[ i ] = depthMaterial;

		//

		var distanceMaterial = new MeshDistanceMaterial( {

			morphTargets: useMorphing,
			skinning: useSkinning

		} );

		_distanceMaterials[ i ] = distanceMaterial;

	}

	//

	var scope = this;

	this.enabled = false;

	this.autoUpdate = true;
	this.needsUpdate = false;

	this.type = PCFShadowMap;

	this.render = function ( lights, scene, camera ) {

		if ( scope.enabled === false ) return;
		if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;

		if ( lights.length === 0 ) return;

		var currentRenderTarget = _renderer.getRenderTarget();

		var _state = _renderer.state;

		// Set GL state for depth map.
		_state.setBlending( NoBlending );
		_state.buffers.color.setClear( 1, 1, 1, 1 );
		_state.buffers.depth.setTest( true );
		_state.setScissorTest( false );

		// render depth map

		var faceCount;

		for ( var i = 0, il = lights.length; i < il; i ++ ) {

			var light = lights[ i ];
			var shadow = light.shadow;
			var isPointLight = light && light.isPointLight;

			if ( shadow === undefined ) {

				console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
				continue;

			}

			var shadowCamera = shadow.camera;

			_shadowMapSize.copy( shadow.mapSize );
			_shadowMapSize.min( _maxShadowMapSize );

			if ( isPointLight ) {

				var vpWidth = _shadowMapSize.x;
				var vpHeight = _shadowMapSize.y;

				// These viewports map a cube-map onto a 2D texture with the
				// following orientation:
				//
				//  xzXZ
				//   y Y
				//
				// X - Positive x direction
				// x - Negative x direction
				// Y - Positive y direction
				// y - Negative y direction
				// Z - Positive z direction
				// z - Negative z direction

				// positive X
				cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
				// negative X
				cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
				// positive Z
				cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
				// negative Z
				cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
				// positive Y
				cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
				// negative Y
				cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );

				_shadowMapSize.x *= 4.0;
				_shadowMapSize.y *= 2.0;

			}

			if ( shadow.map === null ) {

				var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };

				shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
				shadow.map.texture.name = light.name + ".shadowMap";

				shadowCamera.updateProjectionMatrix();

			}

			if ( shadow.isSpotLightShadow ) {

				shadow.update( light );

			}

			var shadowMap = shadow.map;
			var shadowMatrix = shadow.matrix;

			_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
			shadowCamera.position.copy( _lightPositionWorld );

			if ( isPointLight ) {

				faceCount = 6;

				// for point lights we set the shadow matrix to be a translation-only matrix
				// equal to inverse of the light's position

				shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );

			} else {

				faceCount = 1;

				_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
				shadowCamera.lookAt( _lookTarget );
				shadowCamera.updateMatrixWorld();

				// compute shadow matrix

				shadowMatrix.set(
					0.5, 0.0, 0.0, 0.5,
					0.0, 0.5, 0.0, 0.5,
					0.0, 0.0, 0.5, 0.5,
					0.0, 0.0, 0.0, 1.0
				);

				shadowMatrix.multiply( shadowCamera.projectionMatrix );
				shadowMatrix.multiply( shadowCamera.matrixWorldInverse );

			}

			var currentRenderTarget = _renderer.getRenderTarget();

			_renderer.setRenderTarget( shadowMap );
			_renderer.clear();

			// render shadow map for each cube face (if omni-directional) or
			// run a single pass if not

			for ( var face = 0; face < faceCount; face ++ ) {

				if ( isPointLight ) {

					_lookTarget.copy( shadowCamera.position );
					_lookTarget.add( cubeDirections[ face ] );
					shadowCamera.up.copy( cubeUps[ face ] );
					shadowCamera.lookAt( _lookTarget );
					shadowCamera.updateMatrixWorld();

					var vpDimensions = cube2DViewPorts[ face ];
					_state.viewport( vpDimensions );

				}

				// update camera matrices and frustum

				_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
				_frustum.setFromMatrix( _projScreenMatrix );

				// set object matrices & frustum culling

				renderObject( scene, camera, shadowCamera, isPointLight );

			}

		}

		scope.needsUpdate = false;

		_renderer.setRenderTarget( currentRenderTarget );

	};

	function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {

		var geometry = object.geometry;

		var result = null;

		var materialVariants = _depthMaterials;
		var customMaterial = object.customDepthMaterial;

		if ( isPointLight ) {

			materialVariants = _distanceMaterials;
			customMaterial = object.customDistanceMaterial;

		}

		if ( ! customMaterial ) {

			var useMorphing = false;

			if ( material.morphTargets ) {

				if ( geometry && geometry.isBufferGeometry ) {

					useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;

				} else if ( geometry && geometry.isGeometry ) {

					useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;

				}

			}

			if ( object.isSkinnedMesh && material.skinning === false ) {

				console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );

			}

			var useSkinning = object.isSkinnedMesh && material.skinning;

			var variantIndex = 0;

			if ( useMorphing ) variantIndex |= _MorphingFlag;
			if ( useSkinning ) variantIndex |= _SkinningFlag;

			result = materialVariants[ variantIndex ];

		} else {

			result = customMaterial;

		}

		if ( _renderer.localClippingEnabled &&
				material.clipShadows === true &&
				material.clippingPlanes.length !== 0 ) {

			// in this case we need a unique material instance reflecting the
			// appropriate state

			var keyA = result.uuid, keyB = material.uuid;

			var materialsForVariant = _materialCache[ keyA ];

			if ( materialsForVariant === undefined ) {

				materialsForVariant = {};
				_materialCache[ keyA ] = materialsForVariant;

			}

			var cachedMaterial = materialsForVariant[ keyB ];

			if ( cachedMaterial === undefined ) {

				cachedMaterial = result.clone();
				materialsForVariant[ keyB ] = cachedMaterial;

			}

			result = cachedMaterial;

		}

		result.visible = material.visible;
		result.wireframe = material.wireframe;

		result.side = ( material.shadowSide != null ) ? material.shadowSide : shadowSide[ material.side ];

		result.clipShadows = material.clipShadows;
		result.clippingPlanes = material.clippingPlanes;
		result.clipIntersection = material.clipIntersection;

		result.wireframeLinewidth = material.wireframeLinewidth;
		result.linewidth = material.linewidth;

		if ( isPointLight && result.isMeshDistanceMaterial ) {

			result.referencePosition.copy( lightPositionWorld );
			result.nearDistance = shadowCameraNear;
			result.farDistance = shadowCameraFar;

		}

		return result;

	}

	function renderObject( object, camera, shadowCamera, isPointLight ) {

		if ( object.visible === false ) return;

		var visible = object.layers.test( camera.layers );

		if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {

			if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {

				object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );

				var geometry = _objects.update( object );
				var material = object.material;

				if ( Array.isArray( material ) ) {

					var groups = geometry.groups;

					for ( var k = 0, kl = groups.length; k < kl; k ++ ) {

						var group = groups[ k ];
						var groupMaterial = material[ group.materialIndex ];

						if ( groupMaterial && groupMaterial.visible ) {

							var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
							_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );

						}

					}

				} else if ( material.visible ) {

					var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
					_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );

				}

			}

		}

		var children = object.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			renderObject( children[ i ], camera, shadowCamera, isPointLight );

		}

	}

}

export { WebGLShadowMap };
<commit_msg>after confusing myself this should be it<commit_after>/**
 * @author alteredq / http://alteredqualia.com/
 * @author mrdoob / http://mrdoob.com/
 */

import { FrontSide, BackSide, DoubleSide, RGBAFormat, NearestFilter, PCFShadowMap, RGBADepthPacking, NoBlending } from '../../constants.js';
import { WebGLRenderTarget } from '../WebGLRenderTarget.js';
import { MeshDepthMaterial } from '../../materials/MeshDepthMaterial.js';
import { MeshDistanceMaterial } from '../../materials/MeshDistanceMaterial.js';
import { Vector4 } from '../../math/Vector4.js';
import { Vector3 } from '../../math/Vector3.js';
import { Vector2 } from '../../math/Vector2.js';
import { Matrix4 } from '../../math/Matrix4.js';
import { Frustum } from '../../math/Frustum.js';

function WebGLShadowMap( _renderer, _objects, maxTextureSize ) {

	var _frustum = new Frustum(),
		_projScreenMatrix = new Matrix4(),

		_shadowMapSize = new Vector2(),
		_maxShadowMapSize = new Vector2( maxTextureSize, maxTextureSize ),

		_lookTarget = new Vector3(),
		_lightPositionWorld = new Vector3(),

		_MorphingFlag = 1,
		_SkinningFlag = 2,

		_NumberOfMaterialVariants = ( _MorphingFlag | _SkinningFlag ) + 1,

		_depthMaterials = new Array( _NumberOfMaterialVariants ),
		_distanceMaterials = new Array( _NumberOfMaterialVariants ),

		_materialCache = {};

	var shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide };

	var cubeDirections = [
		new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
		new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
	];

	var cubeUps = [
		new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
		new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),	new Vector3( 0, 0, - 1 )
	];

	var cube2DViewPorts = [
		new Vector4(), new Vector4(), new Vector4(),
		new Vector4(), new Vector4(), new Vector4()
	];

	// init

	for ( var i = 0; i !== _NumberOfMaterialVariants; ++ i ) {

		var useMorphing = ( i & _MorphingFlag ) !== 0;
		var useSkinning = ( i & _SkinningFlag ) !== 0;

		var depthMaterial = new MeshDepthMaterial( {

			depthPacking: RGBADepthPacking,

			morphTargets: useMorphing,
			skinning: useSkinning

		} );

		_depthMaterials[ i ] = depthMaterial;

		//

		var distanceMaterial = new MeshDistanceMaterial( {

			morphTargets: useMorphing,
			skinning: useSkinning

		} );

		_distanceMaterials[ i ] = distanceMaterial;

	}

	//

	var scope = this;

	this.enabled = false;

	this.autoUpdate = true;
	this.needsUpdate = false;

	this.type = PCFShadowMap;

	this.render = function ( lights, scene, camera ) {

		if ( scope.enabled === false ) return;
		if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;

		if ( lights.length === 0 ) return;

		var currentRenderTarget = _renderer.getRenderTarget();

		var _state = _renderer.state;

		// Set GL state for depth map.
		_state.setBlending( NoBlending );
		_state.buffers.color.setClear( 1, 1, 1, 1 );
		_state.buffers.depth.setTest( true );
		_state.setScissorTest( false );

		// render depth map

		var faceCount;

		for ( var i = 0, il = lights.length; i < il; i ++ ) {

			var light = lights[ i ];
			var shadow = light.shadow;
			var isPointLight = light && light.isPointLight;

			if ( shadow === undefined ) {

				console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
				continue;

			}

			var shadowCamera = shadow.camera;

			_shadowMapSize.copy( shadow.mapSize );
			_shadowMapSize.min( _maxShadowMapSize );

			if ( isPointLight ) {

				var vpWidth = _shadowMapSize.x;
				var vpHeight = _shadowMapSize.y;

				// These viewports map a cube-map onto a 2D texture with the
				// following orientation:
				//
				//  xzXZ
				//   y Y
				//
				// X - Positive x direction
				// x - Negative x direction
				// Y - Positive y direction
				// y - Negative y direction
				// Z - Positive z direction
				// z - Negative z direction

				// positive X
				cube2DViewPorts[ 0 ].set( vpWidth * 2, vpHeight, vpWidth, vpHeight );
				// negative X
				cube2DViewPorts[ 1 ].set( 0, vpHeight, vpWidth, vpHeight );
				// positive Z
				cube2DViewPorts[ 2 ].set( vpWidth * 3, vpHeight, vpWidth, vpHeight );
				// negative Z
				cube2DViewPorts[ 3 ].set( vpWidth, vpHeight, vpWidth, vpHeight );
				// positive Y
				cube2DViewPorts[ 4 ].set( vpWidth * 3, 0, vpWidth, vpHeight );
				// negative Y
				cube2DViewPorts[ 5 ].set( vpWidth, 0, vpWidth, vpHeight );

				_shadowMapSize.x *= 4.0;
				_shadowMapSize.y *= 2.0;

			}

			if ( shadow.map === null ) {

				var pars = { minFilter: NearestFilter, magFilter: NearestFilter, format: RGBAFormat };

				shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );
				shadow.map.texture.name = light.name + ".shadowMap";

				shadowCamera.updateProjectionMatrix();

			}

			if ( shadow.isSpotLightShadow ) {

				shadow.update( light );

			}

			var shadowMap = shadow.map;
			var shadowMatrix = shadow.matrix;

			_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
			shadowCamera.position.copy( _lightPositionWorld );

			if ( isPointLight ) {

				faceCount = 6;

				// for point lights we set the shadow matrix to be a translation-only matrix
				// equal to inverse of the light's position

				shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );

			} else {

				faceCount = 1;

				_lookTarget.setFromMatrixPosition( light.target.matrixWorld );
				shadowCamera.lookAt( _lookTarget );
				shadowCamera.updateMatrixWorld();

				// compute shadow matrix

				shadowMatrix.set(
					0.5, 0.0, 0.0, 0.5,
					0.0, 0.5, 0.0, 0.5,
					0.0, 0.0, 0.5, 0.5,
					0.0, 0.0, 0.0, 1.0
				);

				shadowMatrix.multiply( shadowCamera.projectionMatrix );
				shadowMatrix.multiply( shadowCamera.matrixWorldInverse );

			}

			_renderer.setRenderTarget( shadowMap );
			_renderer.clear();

			// render shadow map for each cube face (if omni-directional) or
			// run a single pass if not

			for ( var face = 0; face < faceCount; face ++ ) {

				if ( isPointLight ) {

					_lookTarget.copy( shadowCamera.position );
					_lookTarget.add( cubeDirections[ face ] );
					shadowCamera.up.copy( cubeUps[ face ] );
					shadowCamera.lookAt( _lookTarget );
					shadowCamera.updateMatrixWorld();

					var vpDimensions = cube2DViewPorts[ face ];
					_state.viewport( vpDimensions );

				}

				// update camera matrices and frustum

				_projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
				_frustum.setFromMatrix( _projScreenMatrix );

				// set object matrices & frustum culling

				renderObject( scene, camera, shadowCamera, isPointLight );

			}

		}

		scope.needsUpdate = false;

		_renderer.setRenderTarget( currentRenderTarget );

	};

	function getDepthMaterial( object, material, isPointLight, lightPositionWorld, shadowCameraNear, shadowCameraFar ) {

		var geometry = object.geometry;

		var result = null;

		var materialVariants = _depthMaterials;
		var customMaterial = object.customDepthMaterial;

		if ( isPointLight ) {

			materialVariants = _distanceMaterials;
			customMaterial = object.customDistanceMaterial;

		}

		if ( ! customMaterial ) {

			var useMorphing = false;

			if ( material.morphTargets ) {

				if ( geometry && geometry.isBufferGeometry ) {

					useMorphing = geometry.morphAttributes && geometry.morphAttributes.position && geometry.morphAttributes.position.length > 0;

				} else if ( geometry && geometry.isGeometry ) {

					useMorphing = geometry.morphTargets && geometry.morphTargets.length > 0;

				}

			}

			if ( object.isSkinnedMesh && material.skinning === false ) {

				console.warn( 'THREE.WebGLShadowMap: THREE.SkinnedMesh with material.skinning set to false:', object );

			}

			var useSkinning = object.isSkinnedMesh && material.skinning;

			var variantIndex = 0;

			if ( useMorphing ) variantIndex |= _MorphingFlag;
			if ( useSkinning ) variantIndex |= _SkinningFlag;

			result = materialVariants[ variantIndex ];

		} else {

			result = customMaterial;

		}

		if ( _renderer.localClippingEnabled &&
				material.clipShadows === true &&
				material.clippingPlanes.length !== 0 ) {

			// in this case we need a unique material instance reflecting the
			// appropriate state

			var keyA = result.uuid, keyB = material.uuid;

			var materialsForVariant = _materialCache[ keyA ];

			if ( materialsForVariant === undefined ) {

				materialsForVariant = {};
				_materialCache[ keyA ] = materialsForVariant;

			}

			var cachedMaterial = materialsForVariant[ keyB ];

			if ( cachedMaterial === undefined ) {

				cachedMaterial = result.clone();
				materialsForVariant[ keyB ] = cachedMaterial;

			}

			result = cachedMaterial;

		}

		result.visible = material.visible;
		result.wireframe = material.wireframe;

		result.side = ( material.shadowSide != null ) ? material.shadowSide : shadowSide[ material.side ];

		result.clipShadows = material.clipShadows;
		result.clippingPlanes = material.clippingPlanes;
		result.clipIntersection = material.clipIntersection;

		result.wireframeLinewidth = material.wireframeLinewidth;
		result.linewidth = material.linewidth;

		if ( isPointLight && result.isMeshDistanceMaterial ) {

			result.referencePosition.copy( lightPositionWorld );
			result.nearDistance = shadowCameraNear;
			result.farDistance = shadowCameraFar;

		}

		return result;

	}

	function renderObject( object, camera, shadowCamera, isPointLight ) {

		if ( object.visible === false ) return;

		var visible = object.layers.test( camera.layers );

		if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {

			if ( object.castShadow && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {

				object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );

				var geometry = _objects.update( object );
				var material = object.material;

				if ( Array.isArray( material ) ) {

					var groups = geometry.groups;

					for ( var k = 0, kl = groups.length; k < kl; k ++ ) {

						var group = groups[ k ];
						var groupMaterial = material[ group.materialIndex ];

						if ( groupMaterial && groupMaterial.visible ) {

							var depthMaterial = getDepthMaterial( object, groupMaterial, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
							_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );

						}

					}

				} else if ( material.visible ) {

					var depthMaterial = getDepthMaterial( object, material, isPointLight, _lightPositionWorld, shadowCamera.near, shadowCamera.far );
					_renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );

				}

			}

		}

		var children = object.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			renderObject( children[ i ], camera, shadowCamera, isPointLight );

		}

	}

}

export { WebGLShadowMap };
<|endoftext|>


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

/**
 * WordPress dependencies
 */
import apiFetch from '@wordpress/api-fetch';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import { STORE_NAME } from './index';
import {
	createTestRegistry,
	muteConsole,
	subscribeUntil,
	unsubscribeFromAll,
} from 'tests/js/utils';
import * as fixtures from './__fixtures__';

describe( 'modules/analytics properties', () => {
	let apiFetchSpy;
	let registry;
	let store;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	beforeEach( () => {
		registry = createTestRegistry();
		store = registry.stores[ STORE_NAME ].store;

		apiFetchSpy = jest.spyOn( { apiFetch }, 'apiFetch' );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
		apiFetchSpy.mockRestore();
	} );

	describe( 'actions', () => {
		describe( 'createProperty', () => {
			it( 'creates a property and adds it to the store ', async () => {
				const accountID = fixtures.createProperty.accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.

				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/create-property/
					)
					.mockResponse(
						JSON.stringify( fixtures.createProperty ),
						{ status: 200 }
					);

				registry.dispatch( STORE_NAME ).createProperty( accountID );
				// Ensure the proper parameters were passed.
				expect( JSON.parse( fetch.mock.calls[ 0 ][ 1 ].body ) ).toMatchObject(
					{ accountID }
				);

				muteConsole( 'error' );
				await subscribeUntil( registry,
					() => (
						registry.select( STORE_NAME ).getProperties( accountID )
					),
				);

				const properties = registry.select( STORE_NAME ).getProperties( accountID );
				expect( properties ).toMatchObject( [ fixtures.createProperty ] );
			} );

			it( 'sets isDoingCreateProperty ', async () => {
				const accountID = fixtures.createProperty.accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.

				registry.dispatch( STORE_NAME ).fetchCreateProperty( accountID );
				expect( registry.select( STORE_NAME ).isDoingCreateProperty( accountID ) ).toEqual( true );
			} );

			it( 'dispatches an error if the request fails ', async () => {
				const accountID = fixtures.createProperty.accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.
				const response = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};

				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/create-property/
					)
					.mockResponse(
						JSON.stringify( response ),
						{ status: 500 }
					);

				muteConsole( 'error' );
				registry.dispatch( STORE_NAME ).createProperty( accountID );

				await subscribeUntil( registry,
					() => (
						registry.select( STORE_NAME ).getError()
					),
				);

				expect( registry.select( STORE_NAME ).getError() ).toMatchObject( response );

				// Ignore the request fired by the `getProperties` selector.
				muteConsole( 'error' );
				const properties = registry.select( STORE_NAME ).getProperties( accountID );
				// No properties should have been added yet, as the property creation
				// failed.
				expect( properties ).toEqual( undefined );
			} );
		} );
	} );

	describe( 'selectors', () => {
		describe( 'getProperties', () => {
			it( 'uses a resolver to make a network request', async () => {
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/properties-profiles/
					)
					.mockResponseOnce(
						JSON.stringify( fixtures.propertiesProfiles ),
						{ status: 200 }
					);

				const accountID = fixtures.propertiesProfiles.properties[ 0 ].accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.
				const propertyID = fixtures.propertiesProfiles.profiles[ 0 ].webPropertyId; // Capitalization rule exception: `webPropertyId` is a property of an API returned value.

				const initialProperties = registry.select( STORE_NAME ).getProperties( accountID );

				// Ensure the proper parameters were passed.
				expect( fetch.mock.calls[ 0 ][ 0 ] ).toMatchQueryParameters(
					{ accountID }
				);

				expect( initialProperties ).toEqual( undefined );
				await subscribeUntil( registry,
					() => (
						registry.select( STORE_NAME ).getProperties( accountID ) !== undefined
					),
				);

				const properties = registry.select( STORE_NAME ).getProperties( accountID );

				expect( fetch ).toHaveBeenCalledTimes( 1 );

				// Profiles should also have been received by this action.
				muteConsole( 'error' );
				const profiles = registry.select( STORE_NAME ).getProfiles( accountID, propertyID );

				expect( properties ).toEqual( fixtures.propertiesProfiles.properties );
				expect( properties ).toHaveLength( 17 );
				expect( profiles ).toEqual( fixtures.propertiesProfiles.profiles );
			} );

			it( 'does not make a network request if properties for this account are already present', async () => {
				const testAccountID = fixtures.profiles[ 0 ].accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.

				// Load data into this store so there are matches for the data we're about to select,
				// even though the selector hasn't fulfilled yet.
				registry.dispatch( STORE_NAME ).receiveProperties( fixtures.propertiesProfiles.properties );

				const properties = registry.select( STORE_NAME ).getProperties( testAccountID );

				await subscribeUntil( registry, () => registry
					.select( STORE_NAME )
					.hasFinishedResolution( 'getProperties', [ testAccountID ] )
				);

				expect( fetch ).not.toHaveBeenCalled();
				expect( properties ).toEqual( fixtures.propertiesProfiles.properties );
				expect( properties ).toHaveLength( 17 );
			} );

			it( 'dispatches an error if the request fails', async () => {
				const response = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};
				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/properties-profiles/
					)
					.mockResponse(
						JSON.stringify( response ),
						{ status: 500 }
					);

				const fakeAccountID = '777888999';
				muteConsole( 'error' );
				registry.select( STORE_NAME ).getProperties( fakeAccountID );
				await subscribeUntil( registry,
					// TODO: We may want a selector for this, but for now this is fine
					// because it's internal-only.
					() => store.getState().isFetchingPropertiesProfiles[ fakeAccountID ] === false,
				);

				expect( fetch ).toHaveBeenCalledTimes( 1 );

				const properties = registry.select( STORE_NAME ).getProperties( fakeAccountID );
				expect( properties ).toEqual( undefined );
			} );
		} );
	} );
} );
<commit_msg>Update createProperty test to prevent unnecessary fetch error.<commit_after>/**
 * modules/analytics data store: properties tests.
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * WordPress dependencies
 */
import apiFetch from '@wordpress/api-fetch';

/**
 * Internal dependencies
 */
import API from 'googlesitekit-api';
import { STORE_NAME } from './index';
import {
	createTestRegistry,
	muteConsole,
	subscribeUntil,
	unsubscribeFromAll,
} from 'tests/js/utils';
import * as fixtures from './__fixtures__';

describe( 'modules/analytics properties', () => {
	let apiFetchSpy;
	let registry;
	let store;

	beforeAll( () => {
		API.setUsingCache( false );
	} );

	beforeEach( () => {
		registry = createTestRegistry();
		store = registry.stores[ STORE_NAME ].store;

		apiFetchSpy = jest.spyOn( { apiFetch }, 'apiFetch' );
	} );

	afterAll( () => {
		API.setUsingCache( true );
	} );

	afterEach( () => {
		unsubscribeFromAll( registry );
		apiFetchSpy.mockRestore();
	} );

	describe( 'actions', () => {
		describe( 'createProperty', () => {
			it( 'creates a property and adds it to the store ', async () => {
				const accountID = fixtures.createProperty.accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.

				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/create-property/
					)
					.mockResponse(
						JSON.stringify( fixtures.createProperty ),
						{ status: 200 }
					);

				registry.dispatch( STORE_NAME ).createProperty( accountID );
				// Ensure the proper parameters were passed.
				expect( JSON.parse( fetch.mock.calls[ 0 ][ 1 ].body ) ).toMatchObject(
					{ accountID }
				);

				await subscribeUntil( registry,
					() => registry.select( STORE_NAME ).isDoingCreateProperty( accountID ) === false
				);

				const properties = registry.select( STORE_NAME ).getProperties( accountID );
				expect( properties ).toMatchObject( [ fixtures.createProperty ] );
			} );

			it( 'sets isDoingCreateProperty ', async () => {
				const accountID = fixtures.createProperty.accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.

				registry.dispatch( STORE_NAME ).fetchCreateProperty( accountID );
				expect( registry.select( STORE_NAME ).isDoingCreateProperty( accountID ) ).toEqual( true );
			} );

			it( 'dispatches an error if the request fails ', async () => {
				const accountID = fixtures.createProperty.accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.
				const response = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};

				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/create-property/
					)
					.mockResponse(
						JSON.stringify( response ),
						{ status: 500 }
					);

				muteConsole( 'error' );
				registry.dispatch( STORE_NAME ).createProperty( accountID );

				await subscribeUntil( registry,
					() => (
						registry.select( STORE_NAME ).getError()
					),
				);

				expect( registry.select( STORE_NAME ).getError() ).toMatchObject( response );

				// Ignore the request fired by the `getProperties` selector.
				muteConsole( 'error' );
				const properties = registry.select( STORE_NAME ).getProperties( accountID );
				// No properties should have been added yet, as the property creation
				// failed.
				expect( properties ).toEqual( undefined );
			} );
		} );
	} );

	describe( 'selectors', () => {
		describe( 'getProperties', () => {
			it( 'uses a resolver to make a network request', async () => {
				fetch
					.doMockOnceIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/properties-profiles/
					)
					.mockResponseOnce(
						JSON.stringify( fixtures.propertiesProfiles ),
						{ status: 200 }
					);

				const accountID = fixtures.propertiesProfiles.properties[ 0 ].accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.
				const propertyID = fixtures.propertiesProfiles.profiles[ 0 ].webPropertyId; // Capitalization rule exception: `webPropertyId` is a property of an API returned value.

				const initialProperties = registry.select( STORE_NAME ).getProperties( accountID );

				// Ensure the proper parameters were passed.
				expect( fetch.mock.calls[ 0 ][ 0 ] ).toMatchQueryParameters(
					{ accountID }
				);

				expect( initialProperties ).toEqual( undefined );
				await subscribeUntil( registry,
					() => (
						registry.select( STORE_NAME ).getProperties( accountID ) !== undefined
					),
				);

				const properties = registry.select( STORE_NAME ).getProperties( accountID );

				expect( fetch ).toHaveBeenCalledTimes( 1 );

				// Profiles should also have been received by this action.
				muteConsole( 'error' );
				const profiles = registry.select( STORE_NAME ).getProfiles( accountID, propertyID );

				expect( properties ).toEqual( fixtures.propertiesProfiles.properties );
				expect( properties ).toHaveLength( 17 );
				expect( profiles ).toEqual( fixtures.propertiesProfiles.profiles );
			} );

			it( 'does not make a network request if properties for this account are already present', async () => {
				const testAccountID = fixtures.profiles[ 0 ].accountId; // Capitalization rule exception: `accountId` is a property of an API returned value.

				// Load data into this store so there are matches for the data we're about to select,
				// even though the selector hasn't fulfilled yet.
				registry.dispatch( STORE_NAME ).receiveProperties( fixtures.propertiesProfiles.properties );

				const properties = registry.select( STORE_NAME ).getProperties( testAccountID );

				await subscribeUntil( registry, () => registry
					.select( STORE_NAME )
					.hasFinishedResolution( 'getProperties', [ testAccountID ] )
				);

				expect( fetch ).not.toHaveBeenCalled();
				expect( properties ).toEqual( fixtures.propertiesProfiles.properties );
				expect( properties ).toHaveLength( 17 );
			} );

			it( 'dispatches an error if the request fails', async () => {
				const response = {
					code: 'internal_server_error',
					message: 'Internal server error',
					data: { status: 500 },
				};
				fetch
					.doMockIf(
						/^\/google-site-kit\/v1\/modules\/analytics\/data\/properties-profiles/
					)
					.mockResponse(
						JSON.stringify( response ),
						{ status: 500 }
					);

				const fakeAccountID = '777888999';
				muteConsole( 'error' );
				registry.select( STORE_NAME ).getProperties( fakeAccountID );
				await subscribeUntil( registry,
					// TODO: We may want a selector for this, but for now this is fine
					// because it's internal-only.
					() => store.getState().isFetchingPropertiesProfiles[ fakeAccountID ] === false,
				);

				expect( fetch ).toHaveBeenCalledTimes( 1 );

				const properties = registry.select( STORE_NAME ).getProperties( fakeAccountID );
				expect( properties ).toEqual( undefined );
			} );
		} );
	} );
} );
<|endoftext|>


<commit_before>/* Osmium
 * Copyright (C) 2012, 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

osmium_orig_anchor = null;
osmium_selected_tabs = [];
osmium_available_tabs = [];
osmium_tab_ul_count = 0;

osmium_tabify = function(ul, selected) {
	if(osmium_orig_anchor === null) {
		if(window.location.hash) {
			osmium_orig_anchor = window.location.hash.substring(1).split(",");
		} else {
			osmium_orig_anchor = [];
		}
	}

	ul.data('tab_ul_index', osmium_tab_ul_count++);

	var tabs = [];
	var i = 0;
	var selected_pref = 0;

	ul.find('li > a').each(function() {
		var t = $(this);
		var href = t.attr('href');
		if(href.substring(0, 1) != '#') return;
		t.parent().addClass('anchor');
		tabs.push(href.substring(1));
		++i;
	});

	for(var j = 0; j < osmium_orig_anchor.length; ++j) {
		var index = $.inArray(osmium_orig_anchor[j], tabs);
		if(index !== -1) {
			/* Got one of our tabs in hash */
			if(selected_pref < 1) {
				selected = index;
				selected_pref = 1;
			}
			osmium_orig_anchor.splice(j, 1);

			/* Don't break here, as this choice may be overridden by a
			 * "true" anchor in another tab */
		} else {
			if(selected_pref >= 2) continue; /* Already found */

			/* Not one of our tabs, see if it is an anchor in one of our tabs */
			var target = $('#' + osmium_orig_anchor[j]);
			if(target.length === 0) continue;
			target = target.parent();
			do {
				var id = target.prop('id');
				var index;
				if(id && ((index = $.inArray(id, tabs)) !== -1)) {
					/* Found one of our tabs as parent */
					selected = index;
					selected_pref = 2;
					break;
				}
				target = target.parent();
			} while("length" in target && target.length !== 0);
		}
	}

	i = 0;
	ul.find('li.anchor').each(function() {
		var t = $(this);
		var href = t.children('a').attr('href');
		var tget = $(href).addClass('notarget');

		if(i !== selected) {
			tget.hide();
		} else {
			t.addClass('active');
		}
		++i;
	});

	osmium_available_tabs.push(tabs);
	osmium_selected_tabs.push(tabs[selected]);
	ul.find('li.anchor').on('click', osmium_tab_click);

	for(i = 0; i < osmium_orig_anchor.length; ++i) {
		var target = $("#" + osmium_orig_anchor[i]);
		if(target.length === 0) continue;
		if(!target.is(":visible")) continue;
		$(window).scrollTop(target.offset().top);
		return;
	}

	$(window).scrollTop(0);
};

osmium_tab_click = function(e) {
	var li = $(this);
	var ul_index = li.parent().data('tab_ul_index');
	var tabnames = osmium_available_tabs[ul_index];
	var want = li.children('a').blur().attr('href').substring(1);

	for(var i = 0; i < tabnames.length; ++i) {
		if(tabnames[i] === want) {
			$("#" + want).fadeIn(250);
		} else {
			$("#" + tabnames[i]).hide();
		}
	}

	li.parent().children('li.active').removeClass('active');
	li.addClass('active');

	osmium_selected_tabs[ul_index] = want;

	if(window.history && window.history.replaceState) {
		window.history.replaceState(null, null, '#' + osmium_selected_tabs.join(','));
	}

	e.preventDefault();
	e.stopPropagation();
	return false;
};
<commit_msg>Fix: don't insert duplicate tab sets.<commit_after>/* Osmium
 * Copyright (C) 2012, 2013 Romain "Artefact2" Dalmaso <artefact2@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

osmium_orig_anchor = null;
osmium_selected_tabs = [];
osmium_available_tabs = [];
osmium_tab_ul_count = 0;

osmium_tabify = function(ul, selected) {
	if(osmium_orig_anchor === null) {
		if(window.location.hash) {
			osmium_orig_anchor = window.location.hash.substring(1).split(",");
		} else {
			osmium_orig_anchor = [];
		}
	}

	var tabs = [];
	var i = 0;
	var selected_pref = 0;

	ul.find('li > a').each(function() {
		var t = $(this);
		var href = t.attr('href');
		if(href.substring(0, 1) != '#') return;
		t.parent().addClass('anchor');
		tabs.push(href.substring(1));
		++i;
	});

	for(var j = 0; j < osmium_orig_anchor.length; ++j) {
		var index = $.inArray(osmium_orig_anchor[j], tabs);
		if(index !== -1) {
			/* Got one of our tabs in hash */
			if(selected_pref < 1) {
				selected = index;
				selected_pref = 1;
			}
			osmium_orig_anchor.splice(j, 1);

			/* Don't break here, as this choice may be overridden by a
			 * "true" anchor in another tab */
		} else {
			if(selected_pref >= 2) continue; /* Already found */

			/* Not one of our tabs, see if it is an anchor in one of our tabs */
			var target = $('#' + osmium_orig_anchor[j]);
			if(target.length === 0) continue;
			target = target.parent();
			do {
				var id = target.prop('id');
				var index;
				if(id && ((index = $.inArray(id, tabs)) !== -1)) {
					/* Found one of our tabs as parent */
					selected = index;
					selected_pref = 2;
					break;
				}
				target = target.parent();
			} while("length" in target && target.length !== 0);
		}
	}

	i = 0;
	ul.find('li.anchor').each(function() {
		var t = $(this);
		var href = t.children('a').attr('href');
		var tget = $(href).addClass('notarget');

		if(i !== selected) {
			tget.hide();
		} else {
			t.addClass('active');
		}
		++i;
	});

	var found = false;
	for(i = 0; i < osmium_available_tabs.length; ++i) {
		if($.inArray(tabs[selected], osmium_available_tabs[i]) !== -1) {
			ul.data('tab_ul_index', i);
			found = true;
			break;
		}
	}
	if(!found) {
		osmium_available_tabs.push(tabs);
		osmium_selected_tabs.push(tabs[selected]);
		ul.data('tab_ul_index', osmium_tab_ul_count++);
	}

	ul.find('li.anchor').on('click', osmium_tab_click);

	for(i = 0; i < osmium_orig_anchor.length; ++i) {
		var target = $("#" + osmium_orig_anchor[i]);
		if(target.length === 0) continue;
		if(!target.is(":visible")) continue;
		$(window).scrollTop(target.offset().top);
		return;
	}

	$(window).scrollTop(0);
};

osmium_tab_click = function(e) {
	var li = $(this);
	var ul_index = li.parent().data('tab_ul_index');
	var tabnames = osmium_available_tabs[ul_index];
	var want = li.children('a').blur().attr('href').substring(1);

	for(var i = 0; i < tabnames.length; ++i) {
		if(tabnames[i] === want) {
			$("#" + want).fadeIn(250);
		} else {
			$("#" + tabnames[i]).hide();
		}
	}

	li.parent().children('li.active').removeClass('active');
	li.addClass('active');

	osmium_selected_tabs[ul_index] = want;

	if(window.history && window.history.replaceState) {
		window.history.replaceState(null, null, '#' + osmium_selected_tabs.join(','));
	}

	e.preventDefault();
	e.stopPropagation();
	return false;
};
<|endoftext|>


<commit_before>/**
 * Created by zhouyong on 15-1-8.
 */
var privilegeRuleFactory = new PrivilegeRuleFactory();

function strategy_one(){
    var itemOnSale = privilegeRuleFactory.item_on_sale(9.5);
    var branOnSale = privilegeRuleFactory.brand_on_sale(9.0);
    itemOnSale.relevance('可口可乐350Ml');
    branOnSale.relevance('可口可乐');
    itemOnSale.conflicts.push('brandOnSale-self');
    branOnSale.conflicts.push('itemOnSale-other');
}

function strategy_two(){
    var itemOnSale = privilegeRuleFactory.item_on_sale(9.5);
    var branOnSale = privilegeRuleFactory.brand_on_sale(9.0);
    itemOnSale.relevance('可口可乐350Ml');
    branOnSale.relevance('可口可乐');
    itemOnSale.conflicts.push('brandOnSale-other');
    branOnSale.conflicts.push('itemOnSale-self');
    var itemOnReduce = privilegeRuleFactory.item_on_reduce('100-2');
    itemOnReduce.relevance('康师傅');
    itemOnReduce.rule = '100-5';
    itemOnReduce.relevance('云山荔枝');
}

function strategy_three(){

}

function strategy_four(){

}

function printInventory(input_barCodes){

}
<commit_msg>fix some bug<commit_after>/**
 * Created by zhouyong on 15-1-8.
 */
var privilegeRuleFactory = new PrivilegeRuleFactory();

function strategy_one(){
    var itemOnSale = privilegeRuleFactory.item_on_sale(9.5);
    var brandOnSale = privilegeRuleFactory.brand_on_sale(9.0);
    itemOnSale.conflicts.push('brandOnSale-self');
    brandOnSale.conflicts.push('itemOnSale-other');
    itemOnSale.relevance('可口可乐350Ml');
    brandOnSale.relevance('可口可乐');
}

function strategy_two(){
    var itemOnSale = privilegeRuleFactory.item_on_sale(9.5);
    var brandOnSale = privilegeRuleFactory.brand_on_sale(9.0);
    itemOnSale.conflicts.push('brandOnSale-other');
    brandOnSale.conflicts.push('itemOnSale-self');
    itemOnSale.relevance('可口可乐350Ml');
    brandOnSale.relevance('可口可乐');
    var itemOnReduce = privilegeRuleFactory.item_on_reduce('100-2');
    itemOnReduce.relevance('康师傅');
    itemOnReduce.rule = '100-5';
    itemOnReduce.relevance('云山荔枝');
}

function strategy_three(){

}

function strategy_four(){

}

function printInventory(input_barCodes){

}
<|endoftext|>


<commit_before>require('ember-autosuggest/~tests/test_helper');

var get = Ember.get,
    set = Ember.set,
    precompileTemplate = Ember.Handlebars.compile;

var App, find, click, fillIn, visit;

var indexController, controller, component, source;

module("AutoSuggestComponent", {
  setup: function(){
    Ember.$('').appendTo('head');
    Ember.$('').appendTo('head');
    Ember.$('

').appendTo('body');

    indexController = Ember.ArrayController.extend({
      init: function(){
        this._super.apply(this, arguments);
        set(this, 'content',  Ember.A([
          Ember.Object.create({id: 1, name: "Bob Hoskins"}),
          Ember.Object.create({id: 2, name: "Michael Collins"}),
          Ember.Object.create({id: 3, name: "Paul Cowan"}),
        ]));

        set(this, 'tags', Ember.ArrayProxy.create({content: Ember.A()}));
      }
    });

    Ember.run(function() {
      App = Ember.Application.create({
        rootElement: '#ember-testing'
      });

      Ember.TEMPLATES.application = precompileTemplate(
        "{{outlet}}"
      );

      Ember.TEMPLATES.index = precompileTemplate(
        "
" +
        "
" +
        "    {{auto-suggest source=controller destination=tags}}" +
        "
" +
        "
"
      );

      App.AutoSuggestComponent = window.AutoSuggestComponent;
      App.IndexController = indexController;

      App.Router.map(function() {
        this.route('index', {path: '/'});
      });

      App.setupForTesting();
    });

    Ember.run(function(){
      App.advanceReadiness();
    });

    App.injectTestHelpers();

    find = window.find;
    click = window.click;
    fillIn = window.fillIn;
    visit = window.visit;

    // FIXME: Is there a cleaner way of getting the instances
    controller = App.__container__.lookup('controller:index');
    component = App.__container__.lookup('component:autoSuggest');
  },
  teardown: function(){
    Ember.run(function(){
      get(controller, 'tags').clear();
    });
    App.removeTestHelpers();
    Ember.$('#ember-testing-container, #ember-testing').remove();
    Ember.run(App, App.destroy);
    App = null;
  }
});

test("autosuggest DOM elements are setup", function(){
  expect(4);

  visit('/').then(function() {
    ok(Ember.$('div.autosuggest'), "autosuggest component in view");
    ok(Ember.$('input.autosuggest').length, "suggestion input in DOM.");
    ok(Ember.$('ul.selections').length, "selections ul in DOM");
    equal(Ember.$('ul.suggestions').is(':visible'), false, "results ul is initially not displayed");
  });
});

test("a no results message is displayed when no match is found", function(){
  expect(3);

  visit('/').then(function(){
    equal(Ember.$('ul.suggestions').is(':visible'), false, "precon - results ul is initially not displayed");
  })
  .fillIn('input.autosuggest', 'xxxx').then(function(){
    ok(Ember.$('ul.suggestions').is(':visible'), "results ul is displayed.");
    equal(find('.results .suggestions .no-results').html(), "No Results.", "No results message is displayed.");
  });
});

test("Search results should be filtered", function(){
  expect(4);

  equal(get(controller, 'length'), 3, "precon - 3 possible selections exist");

  visit('/').then(function(){
    equal(Ember.$('ul.suggestions').is(':visible'), false, "precon - results ul is initially not displayed");
  })
  .fillIn('input.autosuggest', 'Paul').then(function(){
    var el = find('.results .suggestions li.result');
    equal(el.length, 1, "1 search result exists");
    equal(el.first().text(), "Paul Cowan", "1 search result is visible.");
  });
});

test("A selection can be added", function(){
  expect(6);

  equal(get(controller, 'tags.length'), 0, "precon - no selections have been added.");
  visit('/')
  .fillIn('input.autosuggest', 'Paul')
  .click('.results .suggestions li.result').then(function(){
    equal(get(controller, 'tags.length'), 1, "1 selection has been added.");
    var el = find('.selections li.selection');
    equal(el.length, 1, "1 selection element has been added");
    equal(el.first().text(), "Paul Cowan", "Correct text displayed in element.");
    var suggestions = find('.results .suggestions li.result');
    equal(suggestions.length, 0, "No suggestions are visible.");
    var noResults = find('.suggestions .no-results');
    equal(noResults.is(':visible'), false, "No results message is not displayed.");
  });
});

test("Don't display a suggestion that has been selected", function(){
  expect(3);

  visit('/')
  .fillIn('input.autosuggest', 'Paul')
  .click('.results .suggestions li.result').then(function(){
    var el = find('.selections li.selection');
    equal(el.length, 1, "precon - 1 selection element has been added");
  }).fillIn('input.autosuggest', 'Paul').then(function(){
    var suggestions = find('.results .suggestions li.result');
    equal(suggestions.length, 0, "no suggestion for selected item.");
    equal(find('.results .suggestions .no-results').html(), "No Results.", "No results message is displayed.");
  });
});
<commit_msg>test grammaer<commit_after>require('ember-autosuggest/~tests/test_helper');

var get = Ember.get,
    set = Ember.set,
    precompileTemplate = Ember.Handlebars.compile;

var App, find, click, fillIn, visit;

var indexController, controller, component, source;

module("AutoSuggestComponent", {
  setup: function(){
    Ember.$('').appendTo('head');
    Ember.$('').appendTo('head');
    Ember.$('

').appendTo('body');

    indexController = Ember.ArrayController.extend({
      init: function(){
        this._super.apply(this, arguments);
        set(this, 'content',  Ember.A([
          Ember.Object.create({id: 1, name: "Bob Hoskins"}),
          Ember.Object.create({id: 2, name: "Michael Collins"}),
          Ember.Object.create({id: 3, name: "Paul Cowan"}),
        ]));

        set(this, 'tags', Ember.ArrayProxy.create({content: Ember.A()}));
      }
    });

    Ember.run(function() {
      App = Ember.Application.create({
        rootElement: '#ember-testing'
      });

      Ember.TEMPLATES.application = precompileTemplate(
        "{{outlet}}"
      );

      Ember.TEMPLATES.index = precompileTemplate(
        "
" +
        "
" +
        "    {{auto-suggest source=controller destination=tags}}" +
        "
" +
        "
"
      );

      App.AutoSuggestComponent = window.AutoSuggestComponent;
      App.IndexController = indexController;

      App.Router.map(function() {
        this.route('index', {path: '/'});
      });

      App.setupForTesting();
    });

    Ember.run(function(){
      App.advanceReadiness();
    });

    App.injectTestHelpers();

    find = window.find;
    click = window.click;
    fillIn = window.fillIn;
    visit = window.visit;

    // FIXME: Is there a cleaner way of getting the instances
    controller = App.__container__.lookup('controller:index');
    component = App.__container__.lookup('component:autoSuggest');
  },
  teardown: function(){
    Ember.run(function(){
      get(controller, 'tags').clear();
    });
    App.removeTestHelpers();
    Ember.$('#ember-testing-container, #ember-testing').remove();
    Ember.run(App, App.destroy);
    App = null;
  }
});

test("autosuggest DOM elements are setup", function(){
  expect(4);

  visit('/').then(function() {
    ok(Ember.$('div.autosuggest'), "autosuggest component in view");
    ok(Ember.$('input.autosuggest').length, "suggestion input in DOM.");
    ok(Ember.$('ul.selections').length, "selections ul in DOM");
    equal(Ember.$('ul.suggestions').is(':visible'), false, "results ul is initially not displayed");
  });
});

test("a no results message is displayed when no match is found", function(){
  expect(3);

  visit('/').then(function(){
    equal(Ember.$('ul.suggestions').is(':visible'), false, "precon - results ul is initially not displayed");
  })
  .fillIn('input.autosuggest', 'xxxx').then(function(){
    ok(Ember.$('ul.suggestions').is(':visible'), "results ul is displayed.");
    equal(find('.results .suggestions .no-results').html(), "No Results.", "No results message is displayed.");
  });
});

test("Search results should be filtered", function(){
  expect(4);

  equal(get(controller, 'length'), 3, "precon - 3 possible selections exist");

  visit('/').then(function(){
    equal(Ember.$('ul.suggestions').is(':visible'), false, "precon - results ul is initially not displayed");
  })
  .fillIn('input.autosuggest', 'Paul').then(function(){
    var el = find('.results .suggestions li.result');
    equal(el.length, 1, "1 search result exists");
    equal(el.first().text(), "Paul Cowan", "1 search result is visible.");
  });
});

test("A selection can be added", function(){
  expect(6);

  equal(get(controller, 'tags.length'), 0, "precon - no selections have been added.");
  visit('/')
  .fillIn('input.autosuggest', 'Paul')
  .click('.results .suggestions li.result').then(function(){
    equal(get(controller, 'tags.length'), 1, "1 selection has been added.");
    var el = find('.selections li.selection');
    equal(el.length, 1, "1 selection element has been added");
    equal(el.first().text(), "Paul Cowan", "Correct text displayed in element.");
    var suggestions = find('.results .suggestions li.result');
    equal(suggestions.length, 0, "No suggestions are visible.");
    var noResults = find('.suggestions .no-results');
    equal(noResults.is(':visible'), false, "No results message is not displayed.");
  });
});

test("Don't display a suggestion that has already been selected", function(){
  expect(3);

  visit('/')
  .fillIn('input.autosuggest', 'Paul')
  .click('.results .suggestions li.result').then(function(){
    var el = find('.selections li.selection');
    equal(el.length, 1, "precon - 1 selection element has been added");
  }).fillIn('input.autosuggest', 'Paul').then(function(){
    var suggestions = find('.results .suggestions li.result');
    equal(suggestions.length, 0, "no suggestion for selected item.");
    equal(find('.results .suggestions .no-results').html(), "No Results.", "No results message is displayed.");
  });
});
<|endoftext|>


<commit_before>"use strict";
var environment = require("./environment");
var path = require("path");
var urljoin = require("url-join");
var Bluebird = require("bluebird");
var fs = Bluebird.promisifyAll(require("fs-extra"));
var MemoryStream = require("memory-stream");
var request = require("request");
var zlib = require("zlib");
var tar = require("tar");
var crypto = require("crypto");
var _ = require("lodash");
var CMLog = require("./cmLog");
var TargetOptions = require("./targetOptions");

function downloadTo(url, result, calculateSum) {
    var shasum = calculateSum ? crypto.createHash('sha256') : null;
    return new Bluebird(function (resolve, reject) {
        request
            .get(url)
            .on('error', function (err) { reject(err); })
            .on('data', function (chunk) {
                if (shasum) {
                    shasum.update(chunk);
                }
            })
            .pipe(result);

        result.once("finish", function () { resolve(shasum ? shasum.digest('hex') : undefined); });
    });
}

function testSum(sums, sum, fPath) {
    var serverSum = _.first(sums.filter(function (s) { return s.getPath === fPath; }));
    if (serverSum && serverSum.sum === sum) {
        return;
    }
    throw new Error("SHA sum of file '" + fPath + "' mismatch!");
}

function Dist(options) {
    this.options = options || {};
    this.log = new CMLog(this.options);
    this.targetOptions = new TargetOptions(this.options);
}

// Props
Object.defineProperties(Dist.prototype, {
    internalPath: {
        get: function () {
            return path.join(
                environment.home,
                ".cmake-js",
                (this.targetOptions.runtime) + "-" + this.targetOptions.architecture,
                "v" + this.targetOptions.runtimeVersion);
        }
    },
    externalPath: {
        get: function () {
            switch (this.targetOptions.runtime) {
                case "node":
                    return "http://nodejs.org/dist/v" + this.targetOptions.runtimeVersion + "/";
                case "iojs":
                    return "https://iojs.org/dist/v" + this.targetOptions.runtimeVersion + "/";
                case "nw":
                    return "http://node-webkit.s3.amazonaws.com/v" + this.targetOptions.runtimeVersion + "/";
                case "electron":
                    return "http://atom.io/download/atom-shell/v"+this.targetOptions.runtimeVersion+"/";
                default:
                    throw new Error("Unknown runtime '" + this.targetOptions.runtime + "'!");
            }
        }
    },
    downloaded: {
        get: function () {
            var result = false;
            try {
                var stat = fs.lstatSync(this.internalPath);
                if (stat.isDirectory()) {
                    stat = fs.lstatSync(path.join(this.internalPath, "src/node.h"));
                    if (!stat.isDirectory()) {
                        stat = fs.lstatSync(path.join(this.internalPath, "deps/v8/include/v8.h"));
                        result = !stat.isDirectory();
                    }
                }
            }
            catch (e) {
                _.noop(e);
            }
            return result;
        }
    },
    winLibDir: {
        get: function () {
            if (this.targetOptions.runtime === "nw") {
                return path.join(this.internalPath, (this.targetOptions.isX64 ? "x64" : ""));
            }
            else {
                return path.join(this.internalPath, (this.targetOptions.isX64 ? "win-x64" : "win-x86"));
            }
        }
    },
    winLibPath: {
        get: function () {
            return path.join(this.winLibDir, this.targetOptions.runtime + ".lib");
        }
    }
});

// Methods
Dist.prototype.ensureDownloaded = function () {
    if (!this.downloaded) {
        return this.download();
    }
    return Bluebird.resolve();
};

Dist.prototype.download = function () {
    var log = this.log;
    var self = this;
    log.info("DIST", "Downloading distribution files.");
    return fs.mkdirpAsync(self.internalPath)
        .then(function () {
            return self._downloadShaSums()
                .then(function (sums) {
                    return Bluebird.all([self._downloadLib(sums), self._downloadTar(sums)]);
                });
        });
};

Dist.prototype._downloadShaSums = function () {
    var self = this;
    if (self.targetOptions.runtime === "node" || self.targetOptions.runtime === "iojs") {
        var result = new MemoryStream();
        var sumUrl = urljoin(self.externalPath, "SHASUMS256.txt");
        var log = this.log;
        log.http("DIST", "\t- " + sumUrl);
        return downloadTo(sumUrl, result, false)
            .then(function () {
                return result.toString()
                    .split("\n")
                    .map(function (line) {
                        var parts = line.split(/\s+/);
                        return {
                            getPath: parts[1],
                            sum: parts[0]
                        };
                    })
                    .filter(function (i) { return i.getPath && i.sum; });
            });
    }
    else {
        return Bluebird.resolve(null);
    }
};

Dist.prototype._downloadTar = function (sums) {
    var log = this.log;
    var self = this;
    var gunzip = zlib.createGunzip();
    var extracter = new tar.Extract({
        path: self.internalPath,
        strip: 1,
        filter: function () {
            if (this.path === self.internalPath) {
                return true;
            }
            var ext = path.extname(this.path);
            return ext && ext.toLowerCase() === ".h";
        }
    });
    var fn;
    if (self.targetOptions.runtime === "nw") {
        fn = "nw-headers-v" + self.targetOptions.runtimeVersion + ".tar.gz";
    }
    else if (self.targetOptions.runtime === "electron") {
        fn =  "node" + "-v" + self.targetOptions.runtimeVersion + ".tar.gz";
    }
    else {
        fn = self.targetOptions.runtime + "-v" + self.targetOptions.runtimeVersion + ".tar.gz";
    }
    var tarUrl = urljoin(self.externalPath, fn);
    log.http("DIST", "\t- " + tarUrl);

    return new Bluebird(function (resolve, reject) {
        var shasum = crypto.createHash('sha256');
        extracter.once("end", function () {
            try {
                if (sums) {
                    testSum(sums, shasum.digest('hex'), fn);
                }
                resolve();
            }
            catch (e) {
                reject(e);
            }
        });
        extracter.once("error", function (err) { reject(err); });
        request
            .get(tarUrl)
            .on('error', function (err) { reject(err); })
            .on('data', function (chunk) { shasum.update(chunk); })
            .pipe(gunzip)
            .pipe(extracter);
    });
};

Dist.prototype._downloadLib = function (sums) {
    var log = this.log;
    var self = this;
    if (!environment.isWin) {
        return Bluebird.resolve();
    }

    var subDir;
    var fn = self.targetOptions.runtime + ".lib";
    if (self.targetOptions.runtime === "nw") {
        subDir = self.targetOptions.isX64 ? "x64" : "";
    }
    else {
        subDir = self.targetOptions.isX64 ? "win-x64" : "win-x86";
    }
    var fPath = subDir ? urljoin(subDir, fn) : fn;
    var libUrl = urljoin(self.externalPath, fPath);
    log.http("DIST", "\t- " + libUrl);

    return fs.mkdirpAsync(path.join(self.internalPath, subDir))
        .then(function () {
            var result = fs.createWriteStream(path.join(self.internalPath, fPath));
            return downloadTo(libUrl, result, true)
                .then(function (sum) {
                    if (sums) {
                        testSum(sums, sum, fPath);
                    }
                });
        });
};

module.exports = Dist;
<commit_msg>Support downloading node.lib for electro<commit_after>"use strict";
var environment = require("./environment");
var path = require("path");
var urljoin = require("url-join");
var Bluebird = require("bluebird");
var fs = Bluebird.promisifyAll(require("fs-extra"));
var MemoryStream = require("memory-stream");
var request = require("request");
var zlib = require("zlib");
var tar = require("tar");
var crypto = require("crypto");
var _ = require("lodash");
var CMLog = require("./cmLog");
var TargetOptions = require("./targetOptions");

function downloadTo(url, result, calculateSum) {
    var shasum = calculateSum ? crypto.createHash('sha256') : null;
    return new Bluebird(function (resolve, reject) {
        request
            .get(url)
            .on('error', function (err) { reject(err); })
            .on('data', function (chunk) {
                if (shasum) {
                    shasum.update(chunk);
                }
            })
            .pipe(result);

        result.once("finish", function () { resolve(shasum ? shasum.digest('hex') : undefined); });
    });
}

function testSum(sums, sum, fPath) {
    var serverSum = _.first(sums.filter(function (s) { return s.getPath === fPath; }));
    if (serverSum && serverSum.sum === sum) {
        return;
    }
    throw new Error("SHA sum of file '" + fPath + "' mismatch!");
}

function Dist(options) {
    this.options = options || {};
    this.log = new CMLog(this.options);
    this.targetOptions = new TargetOptions(this.options);
}

// Props
Object.defineProperties(Dist.prototype, {
    internalPath: {
        get: function () {
            return path.join(
                environment.home,
                ".cmake-js",
                (this.targetOptions.runtime) + "-" + this.targetOptions.architecture,
                "v" + this.targetOptions.runtimeVersion);
        }
    },
    externalPath: {
        get: function () {
            switch (this.targetOptions.runtime) {
                case "node":
                    return "http://nodejs.org/dist/v" + this.targetOptions.runtimeVersion + "/";
                case "iojs":
                    return "https://iojs.org/dist/v" + this.targetOptions.runtimeVersion + "/";
                case "nw":
                    return "http://node-webkit.s3.amazonaws.com/v" + this.targetOptions.runtimeVersion + "/";
                case "electron":
                    return "http://atom.io/download/atom-shell/v"+this.targetOptions.runtimeVersion+"/";
                default:
                    throw new Error("Unknown runtime '" + this.targetOptions.runtime + "'!");
            }
        }
    },
    downloaded: {
        get: function () {
            var result = false;
            try {
                var stat = fs.lstatSync(this.internalPath);
                if (stat.isDirectory()) {
                    stat = fs.lstatSync(path.join(this.internalPath, "src/node.h"));
                    if (!stat.isDirectory()) {
                        stat = fs.lstatSync(path.join(this.internalPath, "deps/v8/include/v8.h"));
                        result = !stat.isDirectory();
                    }
                }
            }
            catch (e) {
                _.noop(e);
            }
            return result;
        }
    },
    winLibDir: {
        get: function () {
            if (this.targetOptions.runtime === "nw") {
                return path.join(this.internalPath, (this.targetOptions.isX64 ? "x64" : ""));
            }
            else {
                return path.join(this.internalPath, (this.targetOptions.isX64 ? "win-x64" : "win-x86"));
            }
        }
    },
    winLibPath: {
        get: function () {
            return path.join(this.winLibDir, this.targetOptions.runtime + ".lib");
        }
    }
});

// Methods
Dist.prototype.ensureDownloaded = function () {
    if (!this.downloaded) {
        return this.download();
    }
    return Bluebird.resolve();
};

Dist.prototype.download = function () {
    var log = this.log;
    var self = this;
    log.info("DIST", "Downloading distribution files.");
    return fs.mkdirpAsync(self.internalPath)
        .then(function () {
            return self._downloadShaSums()
                .then(function (sums) {
                    return Bluebird.all([self._downloadLib(sums), self._downloadTar(sums)]);
                });
        });
};

Dist.prototype._downloadShaSums = function () {
    var self = this;
    if (self.targetOptions.runtime === "node" || self.targetOptions.runtime === "iojs") {
        var result = new MemoryStream();
        var sumUrl = urljoin(self.externalPath, "SHASUMS256.txt");
        var log = this.log;
        log.http("DIST", "\t- " + sumUrl);
        return downloadTo(sumUrl, result, false)
            .then(function () {
                return result.toString()
                    .split("\n")
                    .map(function (line) {
                        var parts = line.split(/\s+/);
                        return {
                            getPath: parts[1],
                            sum: parts[0]
                        };
                    })
                    .filter(function (i) { return i.getPath && i.sum; });
            });
    }
    else {
        return Bluebird.resolve(null);
    }
};

Dist.prototype._downloadTar = function (sums) {
    var log = this.log;
    var self = this;
    var gunzip = zlib.createGunzip();
    var extracter = new tar.Extract({
        path: self.internalPath,
        strip: 1,
        filter: function () {
            if (this.path === self.internalPath) {
                return true;
            }
            var ext = path.extname(this.path);
            return ext && ext.toLowerCase() === ".h";
        }
    });
    var fn;
    if (self.targetOptions.runtime === "nw") {
        fn = "nw-headers-v" + self.targetOptions.runtimeVersion + ".tar.gz";
    }
    else if (self.targetOptions.runtime === "electron") {
        fn =  "node" + "-v" + self.targetOptions.runtimeVersion + ".tar.gz";
    }
    else {
        fn = self.targetOptions.runtime + "-v" + self.targetOptions.runtimeVersion + ".tar.gz";
    }
    var tarUrl = urljoin(self.externalPath, fn);
    log.http("DIST", "\t- " + tarUrl);

    return new Bluebird(function (resolve, reject) {
        var shasum = crypto.createHash('sha256');
        extracter.once("end", function () {
            try {
                if (sums) {
                    testSum(sums, shasum.digest('hex'), fn);
                }
                resolve();
            }
            catch (e) {
                reject(e);
            }
        });
        extracter.once("error", function (err) { reject(err); });
        request
            .get(tarUrl)
            .on('error', function (err) { reject(err); })
            .on('data', function (chunk) { shasum.update(chunk); })
            .pipe(gunzip)
            .pipe(extracter);
    });
};

Dist.prototype._downloadLib = function (sums) {
    var log = this.log;
    var self = this;
    if (!environment.isWin) {
        return Bluebird.resolve();
    }

    var subDir;
    var fn = self.targetOptions.runtime + ".lib";
    if (self.targetOptions.runtime === "nw") {
        subDir = self.targetOptions.isX64 ? "x64" : "";
    }
    else if (self.targetOptions.runtime === "electron") {
        fn = "node.lib";
        subDir = self.targetOptions.isX64 ? "x64" : "";
    }
    else {
        subDir = self.targetOptions.isX64 ? "win-x64" : "win-x86";
    }
    var fPath = subDir ? urljoin(subDir, fn) : fn;
    var libUrl = urljoin(self.externalPath, fPath);
    log.http("DIST", "\t- " + libUrl);

    return fs.mkdirpAsync(path.join(self.internalPath, subDir))
        .then(function () {
            var result = fs.createWriteStream(path.join(self.internalPath, fPath));
            return downloadTo(libUrl, result, true)
                .then(function (sum) {
                    if (sums) {
                        testSum(sums, sum, fPath);
                    }
                });
        });
};

module.exports = Dist;
<|endoftext|>


<commit_before>/*jslint browser: true*/

( function() {

	'use strict';

	$.widget( "vui.vui_moreless", {

		options: {
			height: '4em',
			lineHeight: 'normal',
			title: {
				more: "more",
				less: "less"
			},
			color: '#FAFAFA'
		},

		_$moreblur: null,
		_$moreless: null,
		_$morelink: null,
		pollingVariable: null,

		_accessibileButton: function( title, iconClass ) {
			var me = this;
			me._$morelink.empty();
			me._$morelink.append( '' );
			if( !this.options.accessible ) {
				me._$morelink.attr( 'aria-hidden', 'true' );
				me._$morelink.append( title );
			} else {
				me._$morelink.attr( 'aria-role', 'button' );
				title = $( '' + title + '' );
				me._$morelink.append( title );
			}
		},

		_create: function() {
			var me = this;

			me._$moreless = $( this.element );
			me._$morelink = $( '
' );
			me._$moreless.after(  me._$morelink );

			me.options.title.more = me._$moreless.attr( 'data-moreless-moretitle' ) !== undefined ? me._$moreless.attr( 'data-moreless-moretitle' ) : me.options.title.more;
			me.options.title.less = me._$moreless.attr( 'data-moreless-lesstitle' ) !== undefined ? me._$moreless.attr( 'data-moreless-lesstitle' ) : me.options.title.less;
			me.options.accessible = me._$moreless.attr( 'data-moreless-accessible' ) !== undefined && me._$moreless.attr( 'data-moreless-accessible' ) !== "False"? true : false;
			me.options.color = me._$moreless.attr( 'data-moreless-blurcolor' ) !== undefined ? me._$moreless.attr( 'data-moreless-blurcolor' ) : me.options.color;

			var lineHeight =  me._$moreless.attr( 'data-moreless-lineHeight' ) !== undefined ? me._$moreless.attr( 'data-moreless-lineHeight' ) : me.options.lineHeight;
			me._$moreless.css( 'line-height', lineHeight );

			var $breakafter =  me._$moreless.find( '.vui-moreless-breakafter' );
			var height = 0;

			if( $breakafter.length ) {
				$breakafter = $( $breakafter[0] );
				//determine hieght based on bottom on node with breakafter class
				height = ( $breakafter.position().top - me._$moreless.position().top ) + $breakafter.get( 0 ).scrollHeight;

			} else {
				height = me._$moreless.attr( 'data-moreless-height' ) !== undefined ? me._$moreless.attr( 'data-moreless-height' ) : me.options.height;

				if( height.indexOf( '%' ) > -1 ) { //convert percent to px to prevent loss of transition
					height = parseInt( ( me._$moreless.get( 0 ).scrollHeight * ( parseInt( height, 10 ) / 100 ) ) + 0.5, 10 );
				}

				me._$moreblur = $( '
');
				me.BlurColor( me.options.color );
				me._$moreless.after( me._$moreblur );
			}

			me._$moreless.height( height );

			me._accessibileButton( me.options.title.more, 'vui-icon-moreless-chevron-down' );

			me._$morelink.on( 'click', function( e ) {
				me._switchMoreLess( height );
			} );

			me._$morelink.on( 'keypress', function( e ) {
				var keyCode = e.keyCode || e.which;

				if( keyCode === 13 ) {
					me._switchMoreLess( height );
				}
			} );

			var isTab = false;

			$( document ).keydown( function( e ) {
				var keyCode = e.keyCode || e.which;

				if( keyCode === 9 ) {
					isTab = true;
				} else {
					isTab = false;
				}
			} );

			me._$moreless.focusin( function( event ) {
				if( ! me._$moreless.hasClass( 'vui-moreless-more' ) && isTab ) {
					me._$moreless.get( 0 ).scrollTop = 0;
					me._$morelink.focus();
					isTab = false;
				}
			});

			var moreLessHeight = parseInt(height, 10);
			me._startPolling(125, moreLessHeight);
		},

		_hexToRgb: function( inHex) {
			if( inHex.indexOf('#') > -1 ) {
				inHex = inHex.substring(1);
			}
			// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
			if (inHex.length === 3) {
				var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
				inHex = inHex.replace(shorthandRegex, function (m, r, g, b) {
					return r + r + g + g + b + b;
				} );
			}

			var bigint = parseInt( inHex, 16);
			var r = (bigint >> 16) & 255;
			var g = (bigint >> 8) & 255;
			var b = bigint & 255;

			return {
				red: r,
				green: g,
				blue: b
			};
		},

		_startPolling: function (timeout, morelessHeight) {
			var me = this;

			me._fixMoreLess(morelessHeight);

			me.pollingVariable = setTimeout(
				function() {
					me._startPolling(
						timeout < 10000 ? timeout * 2 : timeout,
						morelessHeight
					);
				},
				timeout
			);
		},

		_fixMoreLess: function (morelessHeight) {
			var me = this;

			if (me._$moreless.hasClass('vui-moreless-more')) {
				return;
			}

			me._hideShowMore(morelessHeight);
			me._showShowMore(morelessHeight);
		},

		_hideShowMore: function (morelessHeight) {
			var me = this;

			var scrollHeight = me._$moreless.get(0).scrollHeight;
			var childrenHeight = me._$moreless.children().height();

			// we use the children's height instead of the scroll height because on page load,
			// the scroll height will be equal to the moreless height if the control is present
			// if they are equal then the control will stay in its same state, not changing anything
			// therefore we calculate the childrens height and use that the first time
			// we can't use the children's height everytime because it messes up when we use break after

			var h = scrollHeight == morelessHeight ? childrenHeight : scrollHeight;

			if (me._$moreless &&
				h < morelessHeight) {

				me._$moreless.height( h );
				me._$morelink.css( 'display', 'none' );

				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'none' );
				}
			} else if (me._$moreless &&
				h != me._$moreless.height()) {

				me._$moreless.height(h);
			}
		},

		_showShowMore: function(morelessHeight) {
			var me = this;

			var scrollHeight = me._$moreless.get(0).scrollHeight;
			var childrenHeight = me._$moreless.children().height();

			var h = scrollHeight == morelessHeight ? childrenHeight : scrollHeight;

			if (me._$moreless &&
				h >= morelessHeight) {

				me._$moreless.height(morelessHeight);
				me._$morelink.css( 'display', 'inherit' );

				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'inherit' );
				}
			}
		},

		_switchMoreLess: function( inHeight ) {
			var me = this;

			if (!me._$moreless.hasClass('vui-moreless-transition-effect')) {
				me._$moreless.addClass('vui-moreless-transition-effect');
			}

			if( me._$moreless.hasClass( 'vui-moreless-more' ) ) {
				me._$moreless.removeClass( 'vui-moreless-more' );
				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'block' );
				}
				me._$moreless.css( 'height', inHeight );
				me._accessibileButton(  me.options.title.more, 'vui-icon-moreless-chevron-down' );
				me._$moreless.trigger( 'vui-moreless-collapse' );
			} else {
				me._$moreless.addClass( 'vui-moreless-more' );
				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'none' );
				}
				me._$moreless.css( 'height',  me._$moreless.get( 0 ).scrollHeight );
				me._accessibileButton( this.options.title.less, 'vui-icon-moreless-chevron-up' );
				me._$moreless.trigger( 'vui-moreless-expand' );
			}
		},

		_destroy: function () {
			var me = this;
			if (me.pollingVariable !== null) {
				clearInterval(me.pollingVariable);
			}

			me.pollingVariable = false;
		},

		BlurColor: function( inColor ) {
			var me = this;
			if( me._$moreblur !== null ) {
				var rgba0 = 'rgba( 250, 250, 250, 0)';
				var rgba1 = 'rgba( 250, 250, 250, 1)';

				if( inColor.indexOf( '#' ) > -1 ) {
					var rgb = me._hexToRgb( inColor );
					rgba0 = 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ', 0)';
					rgba1 = 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ', 1)';
				}
				var moz = '-moz-linear-gradient(top, ' + rgba0 + ' 0%, '+ rgba1 + ' 100%)';
				var webkit1 = '-webkit-gradient(linear, left top, left bottom, color-stop(0%, ' + rgba0 + '), color-stop(100%, '+ rgba1 + '))'; /* Chrome,Safari4+ */
				var webkit2 = '-webkit-linear-gradient(top, ' + rgba0 + ' 0%, ' + rgba1 + '100%)'; /* Chrome10+,Safari5.1+ */
				var o = '-o-linear-gradient(top, ' + rgba0 + ' 0%, ' + rgba1 + ' 100%)'; /* Opera 11.10+ */
				var ms = '-ms-linear-gradient(top, ' + rgba0 + ' 0%, '+ rgba1 + ' 100%)';/* IE10+ */
				var general = 'linear-gradient(to bottom, ' + rgba0 + ' 0%, ' + rgba1 + ' 100%)';/* W3C */

				me._$moreblur.css( { 'background': 'transparent' } )
					.css( { 'background': moz } )
					.css( { 'background': webkit1 } )
					.css( { 'background': webkit2 } )
					.css( { 'background': o } )
					.css( { 'background': ms } )
					.css( { 'background': general } );
			}
		},

		isExpanded: function( node ) {
			return $( node ).hasClass( 'vui-moreless-more' );
		},

		Refresh: function( inColor ){
			if( inColor !== null ) {
				this.BlurColor( inColor );
			}
			this._fixMoreLess();
		}

	} );

} )();
<commit_msg>Updating focus behavior in case when control is collapsed<commit_after>/*jslint browser: true*/

( function() {

	'use strict';

	$.widget( "vui.vui_moreless", {

		options: {
			height: '4em',
			lineHeight: 'normal',
			title: {
				more: "more",
				less: "less"
			},
			color: '#FAFAFA'
		},

		_$moreblur: null,
		_$moreless: null,
		_$morelink: null,
		pollingVariable: null,

		_accessibileButton: function( title, iconClass ) {
			var me = this;
			me._$morelink.empty();
			me._$morelink.append( '' );
			if( !this.options.accessible ) {
				me._$morelink.attr( 'aria-hidden', 'true' );
				me._$morelink.append( title );
			} else {
				me._$morelink.attr( 'aria-role', 'button' );
				title = $( '' + title + '' );
				me._$morelink.append( title );
			}
		},

		_create: function() {
			var me = this;

			me._$moreless = $( this.element );
			me._$morelink = $( '
' );
			me._$moreless.after(  me._$morelink );

			me.options.title.more = me._$moreless.attr( 'data-moreless-moretitle' ) !== undefined ? me._$moreless.attr( 'data-moreless-moretitle' ) : me.options.title.more;
			me.options.title.less = me._$moreless.attr( 'data-moreless-lesstitle' ) !== undefined ? me._$moreless.attr( 'data-moreless-lesstitle' ) : me.options.title.less;
			me.options.accessible = me._$moreless.attr( 'data-moreless-accessible' ) !== undefined && me._$moreless.attr( 'data-moreless-accessible' ) !== "False"? true : false;
			me.options.color = me._$moreless.attr( 'data-moreless-blurcolor' ) !== undefined ? me._$moreless.attr( 'data-moreless-blurcolor' ) : me.options.color;

			var lineHeight =  me._$moreless.attr( 'data-moreless-lineHeight' ) !== undefined ? me._$moreless.attr( 'data-moreless-lineHeight' ) : me.options.lineHeight;
			me._$moreless.css( 'line-height', lineHeight );

			var $breakafter =  me._$moreless.find( '.vui-moreless-breakafter' );
			var height = 0;

			if( $breakafter.length ) {
				$breakafter = $( $breakafter[0] );
				//determine hieght based on bottom on node with breakafter class
				height = ( $breakafter.position().top - me._$moreless.position().top ) + $breakafter.get( 0 ).scrollHeight;

			} else {
				height = me._$moreless.attr( 'data-moreless-height' ) !== undefined ? me._$moreless.attr( 'data-moreless-height' ) : me.options.height;

				if( height.indexOf( '%' ) > -1 ) { //convert percent to px to prevent loss of transition
					height = parseInt( ( me._$moreless.get( 0 ).scrollHeight * ( parseInt( height, 10 ) / 100 ) ) + 0.5, 10 );
				}

				me._$moreblur = $( '
');
				me.BlurColor( me.options.color );
				me._$moreless.after( me._$moreblur );
			}

			me._$moreless.height( height );

			me._accessibileButton( me.options.title.more, 'vui-icon-moreless-chevron-down' );

			me._$morelink.on( 'click', function( e ) {
				me._switchMoreLess( height );
			} );

			me._$morelink.on( 'keypress', function( e ) {
				var keyCode = e.keyCode || e.which;

				if( keyCode === 13 ) {
					me._switchMoreLess( height );
				}
			} );

			var isTab = false;
			var isShift = false;

			$( document ).keydown( function( e ) {
				var keyCode = e.keyCode || e.which;

				isTab = keyCode === 9;
				isShift = e.shiftKey;
			} );

			me._$moreless.focusin( function( event ) {
				if( ! me._$moreless.hasClass( 'vui-moreless-more' ) && isTab ) {
				    me._$moreless.get(0).scrollTop = 0;

				    if (isShift) {
				        var previousElements = me._$moreless.parent().prevAll().find(':tabbable').get().reverse();

				        if (previousElements.length > 0) {
				            previousElements[0].focus();
				        }

				        isShift = false;

				    } else {
				        me._$morelink.focus();
				    }

				    isTab = false;
				}
			});

			var moreLessHeight = parseInt(height, 10);
			me._startPolling(125, moreLessHeight);
		},

		_hexToRgb: function( inHex) {
			if( inHex.indexOf('#') > -1 ) {
				inHex = inHex.substring(1);
			}
			// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
			if (inHex.length === 3) {
				var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
				inHex = inHex.replace(shorthandRegex, function (m, r, g, b) {
					return r + r + g + g + b + b;
				} );
			}

			var bigint = parseInt( inHex, 16);
			var r = (bigint >> 16) & 255;
			var g = (bigint >> 8) & 255;
			var b = bigint & 255;

			return {
				red: r,
				green: g,
				blue: b
			};
		},

		_startPolling: function (timeout, morelessHeight) {
			var me = this;

			me._fixMoreLess(morelessHeight);

			me.pollingVariable = setTimeout(
				function() {
					me._startPolling(
						timeout < 10000 ? timeout * 2 : timeout,
						morelessHeight
					);
				},
				timeout
			);
		},

		_fixMoreLess: function (morelessHeight) {
			var me = this;

			if (me._$moreless.hasClass('vui-moreless-more')) {
				return;
			}

			me._hideShowMore(morelessHeight);
			me._showShowMore(morelessHeight);
		},

		_hideShowMore: function (morelessHeight) {
			var me = this;

			var scrollHeight = me._$moreless.get(0).scrollHeight;
			var childrenHeight = me._$moreless.children().height();

			// we use the children's height instead of the scroll height because on page load,
			// the scroll height will be equal to the moreless height if the control is present
			// if they are equal then the control will stay in its same state, not changing anything
			// therefore we calculate the childrens height and use that the first time
			// we can't use the children's height everytime because it messes up when we use break after

			var h = scrollHeight == morelessHeight ? childrenHeight : scrollHeight;

			if (me._$moreless &&
				h < morelessHeight) {

				me._$moreless.height( h );
				me._$morelink.css( 'display', 'none' );

				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'none' );
				}
			} else if (me._$moreless &&
				h != me._$moreless.height()) {

				me._$moreless.height(h);
			}
		},

		_showShowMore: function(morelessHeight) {
			var me = this;

			var scrollHeight = me._$moreless.get(0).scrollHeight;
			var childrenHeight = me._$moreless.children().height();

			var h = scrollHeight == morelessHeight ? childrenHeight : scrollHeight;

			if (me._$moreless &&
				h >= morelessHeight) {

				me._$moreless.height(morelessHeight);
				me._$morelink.css( 'display', 'inherit' );

				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'inherit' );
				}
			}
		},

		_switchMoreLess: function( inHeight ) {
			var me = this;

			if (!me._$moreless.hasClass('vui-moreless-transition-effect')) {
				me._$moreless.addClass('vui-moreless-transition-effect');
			}

			if( me._$moreless.hasClass( 'vui-moreless-more' ) ) {
				me._$moreless.removeClass( 'vui-moreless-more' );
				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'block' );
				}
				me._$moreless.css( 'height', inHeight );
				me._accessibileButton(  me.options.title.more, 'vui-icon-moreless-chevron-down' );
				me._$moreless.trigger( 'vui-moreless-collapse' );
			} else {
				me._$moreless.addClass( 'vui-moreless-more' );
				if( me._$moreblur ) {
					me._$moreblur.css( 'display', 'none' );
				}
				me._$moreless.css( 'height',  me._$moreless.get( 0 ).scrollHeight );
				me._accessibileButton( this.options.title.less, 'vui-icon-moreless-chevron-up' );
				me._$moreless.trigger( 'vui-moreless-expand' );
			}
		},

		_destroy: function () {
			var me = this;
			if (me.pollingVariable !== null) {
				clearInterval(me.pollingVariable);
			}

			me.pollingVariable = false;
		},

		BlurColor: function( inColor ) {
			var me = this;
			if( me._$moreblur !== null ) {
				var rgba0 = 'rgba( 250, 250, 250, 0)';
				var rgba1 = 'rgba( 250, 250, 250, 1)';

				if( inColor.indexOf( '#' ) > -1 ) {
					var rgb = me._hexToRgb( inColor );
					rgba0 = 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ', 0)';
					rgba1 = 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ', 1)';
				}
				var moz = '-moz-linear-gradient(top, ' + rgba0 + ' 0%, '+ rgba1 + ' 100%)';
				var webkit1 = '-webkit-gradient(linear, left top, left bottom, color-stop(0%, ' + rgba0 + '), color-stop(100%, '+ rgba1 + '))'; /* Chrome,Safari4+ */
				var webkit2 = '-webkit-linear-gradient(top, ' + rgba0 + ' 0%, ' + rgba1 + '100%)'; /* Chrome10+,Safari5.1+ */
				var o = '-o-linear-gradient(top, ' + rgba0 + ' 0%, ' + rgba1 + ' 100%)'; /* Opera 11.10+ */
				var ms = '-ms-linear-gradient(top, ' + rgba0 + ' 0%, '+ rgba1 + ' 100%)';/* IE10+ */
				var general = 'linear-gradient(to bottom, ' + rgba0 + ' 0%, ' + rgba1 + ' 100%)';/* W3C */

				me._$moreblur.css( { 'background': 'transparent' } )
					.css( { 'background': moz } )
					.css( { 'background': webkit1 } )
					.css( { 'background': webkit2 } )
					.css( { 'background': o } )
					.css( { 'background': ms } )
					.css( { 'background': general } );
			}
		},

		isExpanded: function( node ) {
			return $( node ).hasClass( 'vui-moreless-more' );
		},

		Refresh: function( inColor ){
			if( inColor !== null ) {
				this.BlurColor( inColor );
			}
			this._fixMoreLess();
		}

	} );

} )();
<|endoftext|>


<commit_before>var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var blogSchema = mongoose.Schema({
    authorId: {
        type: Schema.Types.ObjectId,
    },
    title: {
        type: String
    },
    subtitle: {
        type: String
    },
    content: {
        type: String
    }
});

module.exports = mongoose.model('Post', blogSchema);<commit_msg>adds authorName to schema<commit_after>var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var blogSchema = mongoose.Schema({
    authorId: {
        type: Schema.Types.ObjectId,
    },
    authorName: {
        type: String
    },
    title: {
        type: String
    },
    subtitle: {
        type: String
    },
    content: {
        type: String
    }
});

module.exports = mongoose.model('Post', blogSchema);<|endoftext|>