<commit_before>/**
 * Notification component.
 *
 * Site Kit by Google, Copyright 2019 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 PropTypes from 'prop-types';
import data from 'GoogleComponents/data';
import DataBlock from 'GoogleComponents/data-block';
import Button from 'GoogleComponents/button';
import Warning from 'GoogleComponents/notifications/warning';
import Error from 'GoogleComponents/notifications/error';
import Link from 'GoogleComponents/link';
import SvgIcon from 'GoogleUtil/svg-icon';

import { map } from 'lodash';
/**
 * WordPress dependencies
 */
import { Component, Fragment, createRef } from '@wordpress/element';

class Notification extends Component {
	constructor( props ) {
		super( props );

		this.state = {
			isClosed: false,
		};

		this.cardRef = createRef();

		this.handleDismiss = this.handleDismiss.bind( this );

		if ( 0 < this.props.dismissExpires ) {
			this.expireDismiss();
		}

		if ( this.props.showOnce ) {
			data.setCache( `notification::displayed::${ this.props.id }`, new Date() );
		}
	}

	handleDismiss( e ) {
		const { isClosed } = this.state;
		const card = this.cardRef.current;

		e.preventDefault();

		this.setState( {
			isClosed: ! isClosed,
		} );

		setTimeout( () => {
			data.setCache( `notification::dismissed::${ this.props.id }`, new Date() );
			card.style.display = 'none';

			const event = new Event( 'notificationDismissed' );
			document.dispatchEvent( event );
		}, 350 );
	}

	expireDismiss() {
		const {
			id,
			dismissExpires,
		} = this.props;

		const dismissed = data.getCache( `notification::dismissed::${ id }` );

		if ( dismissed ) {
			const expiration = new Date( dismissed );
			expiration.setSeconds( expiration.getSeconds() + parseInt( dismissExpires, 10 ) );

			if ( expiration < new Date() ) {
				data.deleteCache( `notification::dismissed::${ id }` );
			}
		}
	}

	render() {
		const { isClosed } = this.state;
		const {
			children,
			id,
			title,
			description,
			blockData,
			winImage,
			smallImage,
			format,
			learnMoreURL,
			learnMoreDescription,
			learnMoreLabel,
			ctaLink,
			ctaLabel,
			ctaTarget,
			type,
			dismiss,
			isDismissable,
			logo,
			module,
			moduleName,
			pageIndex,
		} = this.props;

		if ( data.getCache( `notification::dismissed::${ id }` ) ) {
			return null;
		}

		const closedClass = isClosed ? 'is-closed' : 'is-open';
		const inlineLayout = 'large' === format && 'win-stats-increase' === type;

		let layout = 'mdc-layout-grid__cell--span-12';
		if ( 'large' === format ) {
			layout = 'mdc-layout-grid__cell--order-2-phone ' +
				'mdc-layout-grid__cell--order-1-tablet ' +
				'mdc-layout-grid__cell--span-6-tablet ' +
				'mdc-layout-grid__cell--span-8-desktop ';

			if ( inlineLayout ) {
				layout = 'mdc-layout-grid__cell--order-2-phone ' +
						'mdc-layout-grid__cell--order-1-tablet ' +
						'mdc-layout-grid__cell--span-5-tablet ' +
						'mdc-layout-grid__cell--span-8-desktop ';
			}
		} else if ( 'small' === format ) {
			layout = 'mdc-layout-grid__cell--span-11-desktop ' +
				'mdc-layout-grid__cell--span-7-tablet ' +
				'mdc-layout-grid__cell--span-3-phone';
		}

		let icon;
		if ( 'win-warning' === type ) {
			icon = <Warning />;
		} else if ( 'win-error' === type ) {
			icon = <Error />;
		} else {
			icon = '';
		}

		const dataBlockMarkup = (
			<Fragment>
				{ blockData &&

						{
							map( blockData, ( block, i ) => {
								return (
									<div key={ i } className={ `mdc-layout-grid__cell ${ inlineLayout ? 'mdc-layout-grid__cell--span-5-desktop' : 'mdc-layout-grid__cell--span-4-desktop' }` }>

											<DataBlock { ...block } />

								);
							} )
						}

				}
			</Fragment>
		);

		const inlineMarkup = (
			<Fragment>

					{ title }

				{ description &&

							{ description }
							{ learnMoreLabel &&
								<Fragment>
									{ ' ' }
									<Link href={ learnMoreURL } external inherit>
										{ learnMoreLabel }
									</Link>
									{ learnMoreDescription }
								</Fragment>
							}
							{ pageIndex &&
								{ pageIndex }
							}

				}
				{ children }
			</Fragment>
		);

		const logoSVG = module ? <SvgIcon id={ module } height="19" width="19" /> : <SvgIcon id={ 'logo-g' } height="34" width="32" />;

		return (
			<section ref={ this.cardRef } className={ `
				googlesitekit-publisher-win
				${ format ? `googlesitekit-publisher-win--${ format }` : '' }
				${ type ? `googlesitekit-publisher-win--${ type }` : '' }
				${ closedClass ? `googlesitekit-publisher-win--${ closedClass }` : '' }
			` }>

						{ logo &&
							<div className={ `mdc-layout-grid__cell mdc-layout-grid__cell--span-12 ${ inlineLayout ? 'mdc-layout-grid__cell--order-2-phone mdc-layout-grid__cell--order-1-tablet' : '' }` }>

									{ logoSVG }

								{ moduleName &&

										{ moduleName }

								}

						}

						{ smallImage &&

						}

						<div className={ `mdc-layout-grid__cell ${ layout }` }>

							{ inlineLayout ? (

										{ inlineMarkup }

										{ dataBlockMarkup }

							) : (
								<Fragment>
									{ inlineMarkup }
									{ dataBlockMarkup }
								</Fragment>
							) }

							{ ctaLink &&
								<Button href={ ctaLink } target={ ctaTarget }>{ ctaLabel }</Button>
							}

							{ isDismissable && dismiss &&
								<Link onClick={ this.handleDismiss }>
									{ dismiss }
								</Link>
							}

						{ winImage &&

						}

						{ ( 'win-error' === type || 'win-warning' === type ) &&

									{ icon }

						}

		);
	}
}

Notification.propTypes = {
	id: PropTypes.string.isRequired,
	title: PropTypes.string.isRequired,
	description: PropTypes.string,
	learnMoreURL: PropTypes.string,
	learnMoreDescription: PropTypes.string,
	learnMoreLabel: PropTypes.string,
	blockData: PropTypes.array,
	winImage: PropTypes.string,
	smallImage: PropTypes.string,
	format: PropTypes.string,
	ctaLink: PropTypes.string,
	ctaLabel: PropTypes.string,
	type: PropTypes.string,
	dismiss: PropTypes.string,
	isDismissable: PropTypes.bool,
	logo: PropTypes.bool,
	module: PropTypes.string,
	moduleName: PropTypes.string,
	pageIndex: PropTypes.string,
	dismissExpires: PropTypes.number,
	showOnce: PropTypes.bool,
};

Notification.defaultProps = {
	isDismissable: true,
	dismissExpires: 0,
	showOnce: false,
};

export default Notification;
<commit_msg>Add new event handlers to notification component.<commit_after>/**
 * Notification component.
 *
 * Site Kit by Google, Copyright 2019 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 PropTypes from 'prop-types';
import data from 'GoogleComponents/data';
import DataBlock from 'GoogleComponents/data-block';
import Button from 'GoogleComponents/button';
import Warning from 'GoogleComponents/notifications/warning';
import Error from 'GoogleComponents/notifications/error';
import Link from 'GoogleComponents/link';
import SvgIcon from 'GoogleUtil/svg-icon';

import { map } from 'lodash';
/**
 * WordPress dependencies
 */
import { Component, Fragment, createRef } from '@wordpress/element';

class Notification extends Component {
	constructor( props ) {
		super( props );

		this.state = {
			isClosed: false,
		};

		this.cardRef = createRef();

		this.handleDismiss = this.handleDismiss.bind( this );

		if ( 0 < this.props.dismissExpires ) {
			this.expireDismiss();
		}

		if ( this.props.showOnce ) {
			data.setCache( `notification::displayed::${ this.props.id }`, new Date() );
		}
	}

	async handleDismiss( e ) {
		const { isClosed } = this.state;
		const { onDismiss } = this.props;
		const card = this.cardRef.current;

		e.preventDefault();

		this.setState( {
			isClosed: ! isClosed,
		} );

		if ( onDismiss ) {
			await onDismiss( e );
		}

		setTimeout( () => {
			data.setCache( `notification::dismissed::${ this.props.id }`, new Date() );
			card.style.display = 'none';

			const event = new Event( 'notificationDismissed' );
			document.dispatchEvent( event );
		}, 350 );
	}

	expireDismiss() {
		const {
			id,
			dismissExpires,
		} = this.props;

		const dismissed = data.getCache( `notification::dismissed::${ id }` );

		if ( dismissed ) {
			const expiration = new Date( dismissed );
			expiration.setSeconds( expiration.getSeconds() + parseInt( dismissExpires, 10 ) );

			if ( expiration < new Date() ) {
				data.deleteCache( `notification::dismissed::${ id }` );
			}
		}
	}

	render() {
		const { isClosed } = this.state;
		const {
			children,
			id,
			title,
			description,
			blockData,
			winImage,
			smallImage,
			format,
			learnMoreURL,
			learnMoreDescription,
			learnMoreLabel,
			ctaLink,
			ctaLabel,
			ctaTarget,
			type,
			dismiss,
			isDismissable,
			logo,
			module,
			moduleName,
			pageIndex,
			onCTAClick,
		} = this.props;

		if ( data.getCache( `notification::dismissed::${ id }` ) ) {
			return null;
		}

		const closedClass = isClosed ? 'is-closed' : 'is-open';
		const inlineLayout = 'large' === format && 'win-stats-increase' === type;

		let layout = 'mdc-layout-grid__cell--span-12';
		if ( 'large' === format ) {
			layout = 'mdc-layout-grid__cell--order-2-phone ' +
				'mdc-layout-grid__cell--order-1-tablet ' +
				'mdc-layout-grid__cell--span-6-tablet ' +
				'mdc-layout-grid__cell--span-8-desktop ';

			if ( inlineLayout ) {
				layout = 'mdc-layout-grid__cell--order-2-phone ' +
						'mdc-layout-grid__cell--order-1-tablet ' +
						'mdc-layout-grid__cell--span-5-tablet ' +
						'mdc-layout-grid__cell--span-8-desktop ';
			}
		} else if ( 'small' === format ) {
			layout = 'mdc-layout-grid__cell--span-11-desktop ' +
				'mdc-layout-grid__cell--span-7-tablet ' +
				'mdc-layout-grid__cell--span-3-phone';
		}

		let icon;
		if ( 'win-warning' === type ) {
			icon = <Warning />;
		} else if ( 'win-error' === type ) {
			icon = <Error />;
		} else {
			icon = '';
		}

		const dataBlockMarkup = (
			<Fragment>
				{ blockData &&

						{
							map( blockData, ( block, i ) => {
								return (
									<div key={ i } className={ `mdc-layout-grid__cell ${ inlineLayout ? 'mdc-layout-grid__cell--span-5-desktop' : 'mdc-layout-grid__cell--span-4-desktop' }` }>

											<DataBlock { ...block } />

								);
							} )
						}

				}
			</Fragment>
		);

		const inlineMarkup = (
			<Fragment>

					{ title }

				{ description &&

							{ description }
							{ learnMoreLabel &&
								<Fragment>
									{ ' ' }
									<Link href={ learnMoreURL } external inherit>
										{ learnMoreLabel }
									</Link>
									{ learnMoreDescription }
								</Fragment>
							}
							{ pageIndex &&
								{ pageIndex }
							}

				}
				{ children }
			</Fragment>
		);

		const logoSVG = module ? <SvgIcon id={ module } height="19" width="19" /> : <SvgIcon id={ 'logo-g' } height="34" width="32" />;

		return (
			<section ref={ this.cardRef } className={ `
				googlesitekit-publisher-win
				${ format ? `googlesitekit-publisher-win--${ format }` : '' }
				${ type ? `googlesitekit-publisher-win--${ type }` : '' }
				${ closedClass ? `googlesitekit-publisher-win--${ closedClass }` : '' }
			` }>

						{ logo &&
							<div className={ `mdc-layout-grid__cell mdc-layout-grid__cell--span-12 ${ inlineLayout ? 'mdc-layout-grid__cell--order-2-phone mdc-layout-grid__cell--order-1-tablet' : '' }` }>

									{ logoSVG }

								{ moduleName &&

										{ moduleName }

								}

						}

						{ smallImage &&

						}

						<div className={ `mdc-layout-grid__cell ${ layout }` }>

							{ inlineLayout ? (

										{ inlineMarkup }

										{ dataBlockMarkup }

							) : (
								<Fragment>
									{ inlineMarkup }
									{ dataBlockMarkup }
								</Fragment>
							) }

							{ ctaLink &&
								<Button
									href={ ctaLink }
									target={ ctaTarget }
									onClick={ onCTAClick }
								>
									{ ctaLabel }
								</Button>
							}

							{ isDismissable && dismiss &&
								<Link onClick={ this.handleDismiss }>
									{ dismiss }
								</Link>
							}

						{ winImage &&

						}

						{ ( 'win-error' === type || 'win-warning' === type ) &&

									{ icon }

						}

		);
	}
}

Notification.propTypes = {
	id: PropTypes.string.isRequired,
	title: PropTypes.string.isRequired,
	description: PropTypes.string,
	learnMoreURL: PropTypes.string,
	learnMoreDescription: PropTypes.string,
	learnMoreLabel: PropTypes.string,
	blockData: PropTypes.array,
	winImage: PropTypes.string,
	smallImage: PropTypes.string,
	format: PropTypes.string,
	ctaLink: PropTypes.string,
	ctaLabel: PropTypes.string,
	type: PropTypes.string,
	dismiss: PropTypes.string,
	isDismissable: PropTypes.bool,
	logo: PropTypes.bool,
	module: PropTypes.string,
	moduleName: PropTypes.string,
	pageIndex: PropTypes.string,
	dismissExpires: PropTypes.number,
	showOnce: PropTypes.bool,
	onCTAClick: PropTypes.func,
	onDismiss: PropTypes.func,
};

Notification.defaultProps = {
	isDismissable: true,
	dismissExpires: 0,
	showOnce: false,
};

export default Notification;
<|endoftext|>


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

export const STORE_NAME = 'modules/analytics';

// A special Account ID value used for the "Set up a new account" option.
export const ACCOUNT_CREATE = 'account_create';
// A special Property ID value used for the "Set up a new property" option.
export const PROPERTY_CREATE = 'property_create';
// A special Profile ID value used for the "Set up a new profile" option.
export const PROFILE_CREATE = 'profile_create';
<commit_msg>Add account create form ID to constants.<commit_after>/**
 * Analytics Constants.
 *
 * 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.
 */

export const STORE_NAME = 'modules/analytics';

// A special Account ID value used for the "Set up a new account" option.
export const ACCOUNT_CREATE = 'account_create';
// A special Property ID value used for the "Set up a new property" option.
export const PROPERTY_CREATE = 'property_create';
// A special Profile ID value used for the "Set up a new profile" option.
export const PROFILE_CREATE = 'profile_create';
// Form ID for the account creation form.
export const FORM_ACCOUNT_CREATE = 'accountCreate';
<|endoftext|>


<commit_before>/*
 * 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 { TextDecoder, TextEncoder } from 'util';

/**
 * Internal dependencies
 */
import base64Encode from '../base64Encode';

// see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa.
function fromBinary(binary) {
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < bytes.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  return String.fromCharCode(...new Uint16Array(bytes.buffer));
}

// These are not yet available in jsdom environment.
// See https://github.com/facebook/jest/issues/9983.
// See https://github.com/jsdom/jsdom/issues/2524.
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;

describe('base64Encode', () => {
  beforeAll(() => {
    // eslint-disable-next-line jest/prefer-spy-on
    global.btoa = jest.fn().mockImplementation(() => '*encoded*');
  });
  afterAll(() => {
    global.btoa.mockClear();
  });

  it('prefixes encoded content', () => {
    expect(base64Encode('Hello World')).toStartWith('__WEB_STORIES_ENCODED__');
  });

  it('converts Unicode characters', () => {
    // eslint-disable-next-line jest/prefer-spy-on
    global.btoa = jest.fn().mockImplementation(() => 'SABlAGwAbABvACAAPNgN3w==');

    const actual = base64Encode('Hello 🌍');
    expect(actual).toStrictEqual(
      '__WEB_STORIES_ENCODED__SABlAGwAbABvACAAPNgN3w=='
    ); // Hello 🌍
    expect(
      fromBinary(atob(actual.replace('__WEB_STORIES_ENCODED__', '')))
    ).toStrictEqual('Hello 🌍');
  });
});
<commit_msg>Another lint fix<commit_after>/*
 * 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 { TextDecoder, TextEncoder } from 'util';

/**
 * Internal dependencies
 */
import base64Encode from '../base64Encode';

// see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa.
function fromBinary(binary) {
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < bytes.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  return String.fromCharCode(...new Uint16Array(bytes.buffer));
}

// These are not yet available in jsdom environment.
// See https://github.com/facebook/jest/issues/9983.
// See https://github.com/jsdom/jsdom/issues/2524.
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;

describe('base64Encode', () => {
  beforeAll(() => {
    // eslint-disable-next-line jest/prefer-spy-on
    global.btoa = jest.fn().mockImplementation(() => '*encoded*');
  });
  afterAll(() => {
    global.btoa.mockClear();
  });

  it('prefixes encoded content', () => {
    expect(base64Encode('Hello World')).toStartWith('__WEB_STORIES_ENCODED__');
  });

  it('converts Unicode characters', () => {
    // eslint-disable-next-line jest/prefer-spy-on
    global.btoa = jest
      .fn()
      .mockImplementation(() => 'SABlAGwAbABvACAAPNgN3w==');

    const actual = base64Encode('Hello 🌍');
    expect(actual).toStrictEqual(
      '__WEB_STORIES_ENCODED__SABlAGwAbABvACAAPNgN3w=='
    ); // Hello 🌍
    expect(
      fromBinary(atob(actual.replace('__WEB_STORIES_ENCODED__', '')))
    ).toStrictEqual('Hello 🌍');
  });
});
<|endoftext|>


<commit_before>/// <reference types="cypress" />

context('Standard Cart', () => {

    it('Cart Add and Remove', () => {
        cy.loginStandard("v2/cart");
        cy.contains('You have no items in your cart');
        cy.visit("PersonView.php?PersonID=1")
        cy.get("#AddPersonToCart").click();
        cy.visit("v2/cart");
        cy.contains('Cart Functions');
        cy.contains('Church Admin');
        cy.get("#emptyCart").click();
        cy.contains('You have no items in your cart');
    });

});
<commit_msg>closes #4961 by adding family add to cart test<commit_after>/// <reference types="cypress" />

context('Standard Cart', () => {
    beforeEach(() => {

    });

    it('Cart Add and Remove Person', () => {
        cy.loginStandard("v2/cart");
        cy.contains('You have no items in your cart');
        cy.visit("PersonView.php?PersonID=1")
        cy.get("#AddPersonToCart").click();
        cy.visit("v2/cart");
        cy.contains('Cart Functions');
        cy.contains('Church Admin');
        cy.get("#emptyCart").click();
        cy.contains('You have no items in your cart');
    });

    it('Cart Add and Remove Family', () => {
        cy.loginStandard("v2/cart");
        cy.contains('You have no items in your cart');
        cy.visit("v2/family/6")
        cy.get("#AddFamilyToCart").click();
        cy.wait(2000);
        cy.visit("v2/cart");
        cy.contains('Kenzi Dixon');
        cy.contains('Cart Functions');
        cy.get("#emptyCart").click();
        cy.contains('You have no items in your cart');
    });

});
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

import fetchWcl from 'common/fetchWclApi';
import SPELLS from 'common/SPELLS';
import ManaStyles from 'interface/others/ManaStyles';

import PainComponent from './PainComponent';
import PainChart from './PainChart';

class Pain extends React.PureComponent {
  static propTypes = {
    reportCode: PropTypes.string.isRequired,
    actorId: PropTypes.number.isRequired,
    start: PropTypes.number.isRequired,
    end: PropTypes.number.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      pain: null,
      bossHealth: null,
    };
  }

  componentDidMount() {
    this.update();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.reportCode !== this.props.reportCode || prevProps.actorId !== this.props.actorId || prevProps.start !== this.props.start || prevProps.end !== this.props.end) {
      this.update();
    }
  }

  update() {
    this.load(this.props.reportCode, this.props.actorId, this.props.start, this.props.end);
  }

  load(reportCode, actorId, start, end) {
    const painPromise = fetchWcl(`report/tables/resources/${reportCode}`, {
      start,
      end,
      sourceid: actorId,
      abilityid: 118,
    })
      .then(json => {
        this.setState({
          pain: json,
        });
      });

    const bossHealthPromise = fetchWcl(`report/tables/resources/${reportCode}`, {
      start,
      end,
      sourceclass: 'Boss',
      hostility: 1,
      abilityid: 1000,
    })
      .then(json => {
        this.setState({
          bossHealth: json,
        });
      });

    return Promise.all([painPromise, bossHealthPromise]);
  }

  get plot() {
    const { start, end } = this.props;

    const pain = this.state.pain.series[0].data.map(([timestamp, amount]) => {
      const x = Math.max(timestamp, start);
      return {
        x,
        y: amount / 10,
      };
    });

    const wasted = this.state.pain.series[0].events
      .filter(event => event.waste !== undefined)
      .map(({ timestamp, waste }) => ({ x: timestamp, y: waste }));

    const bossData = this.state.bossHealth.series.map((series, i) => {
      const data = series.data.map(([timestamp, health]) => ({ x: timestamp, y: health }));
      return {
        title: `${series.name} Health`,
        borderColor: ManaStyles[`Boss-${i}`].borderColor,
        backgroundColor: ManaStyles[`Boss-${i}`].backgroundColor,
        data,
      };
    });

    return (
      <PainChart
        pain={pain}
        wasted={wasted}
        bossData={bossData}
        startTime={start}
        endTime={end}
      />
    );
  }

  render() {
    if (!this.state.pain || !this.state.bossHealth) {
      return (

          Loading...

      );
    }

    if(!this.state.pain.series[0]) {
      return (

          This pain chart data from Warcraft Logs is corrupted and it cannot be parsed.

      );
    }

    const { start } = this.props;
    const painBySecond = {
      0: 0,
    };
    this.state.pain.series[0].data.forEach((item) => {
      const secIntoFight = Math.floor((item[0] - start) / 1000);
      painBySecond[secIntoFight] = item[1];
    });

    const abilitiesAll = {};
    const categories = {
      generated: 'Pain Generators',
      spent: 'Pain Spenders',
    };

    let lastSecFight = start;
    this.state.pain.series[0].events.forEach((event) => {
      const secIntoFight = Math.floor((event.timestamp - start) / 1000);
      if (event.type === 'cast') {
        const spell = SPELLS[event.ability.guid];
        if (!abilitiesAll[`${event.ability.guid}_spend`]) {
          abilitiesAll[`${event.ability.guid}_spend`] = {
            ability: {
              category: 'Pain Spenders',
              name: (spell === undefined) ? event.ability.name : spell.name,
              spellId: event.ability.guid,
            },
            spent: 0,
            casts: 0,
            created: 0,
            wasted: 0,
          };
        }
        abilitiesAll[`${event.ability.guid}_spend`].casts += 1;
        const lastPain = lastSecFight === secIntoFight ? painBySecond[lastSecFight - 1] : painBySecond[lastSecFight];
        const spendResource = spell !== undefined ? ((spell.painCost !== undefined) ? spell.painCost : (spell.max_pain < lastPain ? spell.max_pain : lastPain)) : 0;
        abilitiesAll[`${event.ability.guid}_spend`].spent += spendResource;
        abilitiesAll[`${event.ability.guid}_spend`].wasted += spell.max_pain !== undefined ? spell.max_pain - spendResource : 0;
      } else if (event.type === 'energize') {
        if (!abilitiesAll[`${event.ability.guid}_gen`]) {
          const spell = SPELLS[event.ability.guid];
          abilitiesAll[`${event.ability.guid}_gen`] = {
            ability: {
              category: 'Pain Generators',
              name: (spell === undefined) ? event.ability.name : spell.name,
              spellId: event.ability.guid,
            },
            spent: 0,
            casts: 0,
            created: 0,
            wasted: 0,
          };
        }
        abilitiesAll[`${event.ability.guid}_gen`].casts += 1;
        abilitiesAll[`${event.ability.guid}_gen`].created += event.resourceChange;
        abilitiesAll[`${event.ability.guid}_gen`].wasted += event.waste;
      }
      if (secIntoFight !== lastSecFight) {
        lastSecFight = secIntoFight;
      }
    });

    const abilities = Object.keys(abilitiesAll).map(key => abilitiesAll[key]);
    abilities.sort((a, b) => {
      if (a.created < b.created) {
        return 1;
      } else if (a.created === b.created) {
        return 0;
      }
      return -1;
    });

    return (
      <>
        {this.plot}
        <PainComponent
          abilities={abilities}
          categories={categories}
        />
      </>
    );
  }
}

export default Pain;

<commit_msg>Factor out update function<commit_after>import React from 'react';
import PropTypes from 'prop-types';

import fetchWcl from 'common/fetchWclApi';
import SPELLS from 'common/SPELLS';
import ManaStyles from 'interface/others/ManaStyles';

import PainComponent from './PainComponent';
import PainChart from './PainChart';

class Pain extends React.PureComponent {
  static propTypes = {
    reportCode: PropTypes.string.isRequired,
    actorId: PropTypes.number.isRequired,
    start: PropTypes.number.isRequired,
    end: PropTypes.number.isRequired,
  };

  constructor(props) {
    super(props);
    this.state = {
      pain: null,
      bossHealth: null,
    };
  }

  componentDidMount() {
    this.load();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.reportCode !== this.props.reportCode || prevProps.actorId !== this.props.actorId || prevProps.start !== this.props.start || prevProps.end !== this.props.end) {
      this.load();
    }
  }

  load() {
    const { reportCode, actorId, start, end } = this.props;
    fetchWcl(`report/tables/resources/${reportCode}`, {
      start,
      end,
      sourceid: actorId,
      abilityid: 118,
    })
      .then(json => {
        this.setState({
          pain: json,
        });
      });

    fetchWcl(`report/tables/resources/${reportCode}`, {
      start,
      end,
      sourceclass: 'Boss',
      hostility: 1,
      abilityid: 1000,
    })
      .then(json => {
        this.setState({
          bossHealth: json,
        });
      });
  }

  get plot() {
    const { start, end } = this.props;

    const pain = this.state.pain.series[0].data.map(([timestamp, amount]) => {
      const x = Math.max(timestamp, start);
      return {
        x,
        y: amount / 10,
      };
    });

    const wasted = this.state.pain.series[0].events
      .filter(event => event.waste !== undefined)
      .map(({ timestamp, waste }) => ({ x: timestamp, y: waste }));

    const bossData = this.state.bossHealth.series.map((series, i) => {
      const data = series.data.map(([timestamp, health]) => ({ x: timestamp, y: health }));
      return {
        title: `${series.name} Health`,
        borderColor: ManaStyles[`Boss-${i}`].borderColor,
        backgroundColor: ManaStyles[`Boss-${i}`].backgroundColor,
        data,
      };
    });

    return (
      <PainChart
        pain={pain}
        wasted={wasted}
        bossData={bossData}
        startTime={start}
        endTime={end}
      />
    );
  }

  render() {
    if (!this.state.pain || !this.state.bossHealth) {
      return (

          Loading...

      );
    }

    if(!this.state.pain.series[0]) {
      return (

          This pain chart data from Warcraft Logs is corrupted and it cannot be parsed.

      );
    }

    const { start } = this.props;
    const painBySecond = {
      0: 0,
    };
    this.state.pain.series[0].data.forEach((item) => {
      const secIntoFight = Math.floor((item[0] - start) / 1000);
      painBySecond[secIntoFight] = item[1];
    });

    const abilitiesAll = {};
    const categories = {
      generated: 'Pain Generators',
      spent: 'Pain Spenders',
    };

    let lastSecFight = start;
    this.state.pain.series[0].events.forEach((event) => {
      const secIntoFight = Math.floor((event.timestamp - start) / 1000);
      if (event.type === 'cast') {
        const spell = SPELLS[event.ability.guid];
        if (!abilitiesAll[`${event.ability.guid}_spend`]) {
          abilitiesAll[`${event.ability.guid}_spend`] = {
            ability: {
              category: 'Pain Spenders',
              name: (spell === undefined) ? event.ability.name : spell.name,
              spellId: event.ability.guid,
            },
            spent: 0,
            casts: 0,
            created: 0,
            wasted: 0,
          };
        }
        abilitiesAll[`${event.ability.guid}_spend`].casts += 1;
        const lastPain = lastSecFight === secIntoFight ? painBySecond[lastSecFight - 1] : painBySecond[lastSecFight];
        const spendResource = spell !== undefined ? ((spell.painCost !== undefined) ? spell.painCost : (spell.max_pain < lastPain ? spell.max_pain : lastPain)) : 0;
        abilitiesAll[`${event.ability.guid}_spend`].spent += spendResource;
        abilitiesAll[`${event.ability.guid}_spend`].wasted += spell.max_pain !== undefined ? spell.max_pain - spendResource : 0;
      } else if (event.type === 'energize') {
        if (!abilitiesAll[`${event.ability.guid}_gen`]) {
          const spell = SPELLS[event.ability.guid];
          abilitiesAll[`${event.ability.guid}_gen`] = {
            ability: {
              category: 'Pain Generators',
              name: (spell === undefined) ? event.ability.name : spell.name,
              spellId: event.ability.guid,
            },
            spent: 0,
            casts: 0,
            created: 0,
            wasted: 0,
          };
        }
        abilitiesAll[`${event.ability.guid}_gen`].casts += 1;
        abilitiesAll[`${event.ability.guid}_gen`].created += event.resourceChange;
        abilitiesAll[`${event.ability.guid}_gen`].wasted += event.waste;
      }
      if (secIntoFight !== lastSecFight) {
        lastSecFight = secIntoFight;
      }
    });

    const abilities = Object.keys(abilitiesAll).map(key => abilitiesAll[key]);
    abilities.sort((a, b) => {
      if (a.created < b.created) {
        return 1;
      } else if (a.created === b.created) {
        return 0;
      }
      return -1;
    });

    return (
      <>
        {this.plot}
        <PainComponent
          abilities={abilities}
          categories={categories}
        />
      </>
    );
  }
}

export default Pain;

<|endoftext|>


<commit_before>(function(window, document, $) { //The function wrapper prevents leaking variables to global space
    'use strict';
    var IC;

    //These lines register the Example object in a plugin namespace that makes
    //referencing the plugin easier when debugging.
    var plugins = namespace('plugins');
    plugins.IC = IC;

    IC = function IC(cockpit) {

      console.log('Loading internet-control plugin in the browser.');

      //instance variables
      this.cockpit = cockpit;
      this.rov = cockpit.rov;
      this.settings = {};

      // for plugin management:
      this.pluginDefaults = {
        name: 'Internet Control', // for the settings
        viewName: 'Internet Control plugin', // for the UI
        canBeDisabled: true, //allow enable/disable
        defaultEnabled: false
      };
      this.enabled=false;
      this.connected = false;
      this.connecting = false;
      this.viewers = 0;
      this.peers = [];

    };

    //private functions and variables (hidden within the function, available via the closure)

    //Adding the public methods using prototype simply groups those methods
    //together outside the parent function definition for easier readability.

    //Called by the plugin-manager to enable a plugin
    IC.prototype.enable = function enable() {
      alert('Internet-control enabled');
      this.listen();
    };

    //Called by the plugin-manager to disable a plugin
    IC.prototype.disable = function disable() {
      alert('Internet-control disabled');
      //TODO: Impliment and unlisten
    };

    //listen gets called by the plugin framework after all of the plugins
    //have loaded.
    IC.prototype.listen = function listen() {
      if (!this.enabled){return;}
      var self = this;

      var statusUpdate=function(){
        var status = {status:'off',stats:{viewers:0,pilots:0,connection:{}},pilots:{}};
        if (self.connecting){
          status.status='starting';
        }
        if (self.connected){
          status.status='streaming';
        }
        status.stats.viewers = self.viewers;

        //TODO: Figure out how to show stats
        /*
        status.stats.connection = self.peers.map(function(item){
          item._pc.getStats(function(res){
            return res.result();
          });
        }).reduce(function(previousValue,currentValue){
          if (previousValue===null){
            return currentValue;
          }
          for (var property in currentValue) {
              if (object.hasOwnProperty(property)) {
                  previousValue[property]=previousValue[property]+currentValue[property];
              }
          }
          return previousValue;
        },null);

        */
        self.cockpit.emit('plugin-internetControl-status',status);
      }
      setInterval(statusUpdate,1000);

      //Response from the getSettings call. Using the withHistory will call the
      //update function with the last copy of this message that had been sent.
      //The settings manager sends a change message for each section when
      //first read in.
      this.rov.withHistory.on('settings-change.ic', function(settings) {
          console.log("Settings changed for IC");
          self.settings = settings.ic;

          //TODO: Move to a pattern that can retry the connection when the setting changes
          $.getScript(self.settings.webRTCSignalServerURI + "/msgpack.min.js");
          $.getScript(self.settings.webRTCSignalServerURI + "/simplepeer.js", function() {
              var _self = self
              var Peer = window.SimplePeer;
              var io = window.io;
              var socket = io(self.settings.webRTCSignalServerURI);
              self.connecting = true;
              var opts = {
//                peerOpts: {
//                  channelConfig: {
//                    ordered: false,
//                    maxRetransmits: 0
//                  }
//                },
                autoUpgrade: false
              }

              var heartbeatInterval = null;
              socket.on('close',function(){
                if (heartbeatInterval!==null){
                  clearInterval(heartbeatInterval);
                }
                self.connected=false;
              });

              var connectionTimeOutTimer=null;
              socket.on('disconnect',function(){
                console.log("disconneted");
                self.connected = false;
              })

              socket.on('reconnect',function(){
                console.log("disconneted");
                self.connected = true;
              })

              socket.on('heartbeat',function(data){
                console.log('Heartbeat: ' + JSON.stringify(data));
              });

              socket.on('connect',function(){
                self.connected = true;
                self.connecting= false;

                //var msgpack = require("msgpack-lite");

                heartbeatInterval=setInterval(function(){
                  if (!self.connected){return;}
                  socket.emit('heartbeat','server');
                },1000);
                var pilot_sender_id = null;

                socket.on('peer-connect-offer',function(peer_id,callback){
                  var p = new Peer();

                  p.withHistory = {
                    on: function(event, fn) {
                      p.on(event, fn);
                    }
                  };

                  p.on('error', function (err) {
                    console.error('error', err)
                  })

                  p.on('signal', function (data) {
                    socket.emit('signal',peer_id, data);
                    console.log('SIGNAL SENT:', JSON.stringify(data))
                  })

                  var onSignalHanlder = function(data,sender_id){
                    if (sender_id !== peer_id){
                      console.error('Invalid sender_id');
                      return;
                    }
                    p.signal(data);
                  };

                  socket.on('signal',onSignalHanlder);

                  callback(true);

                  p.on('connect', function(){
                    _self.viewers++;
                    _self.peers.push(p);
                    //make last person to connect pilot by default
                    pilot_sender_id = peer_id;
                    _self.cockpit.emit('plugin.rovpilot.sendToROVEnabled',false);
//                    var emitter = new EventEmitter2();
                    p.sendemit = function sendemit(){
                      var args = new Array(arguments.length);
                      for(var i = 0; i < args.length; ++i) {
                                  //i is always valid index in the arguments object
                          args[i] = arguments[i];
                      }
                      p.send(msgpack.encode(args));
                      //p.send("THIS IS A STRING!!!!");
                    }

                    //Test data payload sizes
                    for (var i=1;i<=10;i++){
                      var size = Math.pow(2,i);
                      p.sendemit('data-msg',size,new ArrayBuffer(size),'ok');
                    }

                    var onevent = _self.rov.socket.onevent;

                    _self.rov.socket.onevent = function (packet) {
                        var args = packet.data || [];
                        onevent.call (this, packet);    // original call

                        if (p==null) {return;}
                        args = args.filter(function(n){ return n != null });
                        p.sendemit.apply(this,args);
                    };

                    var onAnyHandler = function() {
                      var event = this.event;
                      if (event !== 'newListener') {
                      //  console.log(event);
                        var args = new Array(arguments.length);
                        for(var i = 0; i < args.length; ++i) {
                                    //i is always valid index in the arguments object
                            args[i] = arguments[i];
                        }
                        args.unshift(event);
                        p.sendemit.apply(p,args);
                      }
                    }
                    _self.rov.onAny(onAnyHandler);

                    //Since the video comes in via a different route...
                    const webRTCDataChannelChunkLimit=16*1024; //16KB Chunk Recommendation
                    var videodataHanlder = function(data){
                      var chunk_count = 1;
                      var sliceend=0;
                      var end = 0;
                      while(end<data.byteLength){
                        var sliceend = sliceend+webRTCDataChannelChunkLimit>data.byteLength?data.byteLength:sliceend+webRTCDataChannelChunkLimit
                        var chunk = data.slice(end,sliceend);
                        p.sendemit('x-h264-video.chunk',chunk_count,data.byteLength-sliceend,chunk);
                        chunk_count++;
                        end=sliceend;
                      }
                    }
                    _self.cockpit.on('x-h264-video.data',videodataHanlder);

                    p.on('data',function(data){
                      var msg = msgpack.decode(data);
                      switch(msg[0]){
                        case 'request_Init_Segment':
                          _self.cockpit.emit('request_Init_Segment',function(init){
                              p.sendemit('x-h264-video.init',init);
                          });
                        break;
                      }

                      if (peer_id == pilot_sender_id){
                        switch(msg[0]){
                          case 'throttle':
                          case 'yaw':
                          case 'list':
                          case 'pitch':
                          case 'roll':
                          case 'strafe':
                            _self.rov.emit(msg[0],msg[1]);
                          break;
                          case 'plugin.rovpilot.desiredControlRates':
                          case 'plugin.externalLights.toggle':
                          case 'plugin.externalLights.adjust':
                          case 'plugin.externalLights.set':
                          case 'plugin.laser.set':
                          case 'plugin.lights.toggle':
                          case 'plugin.lights.adjust':
                          case 'plugin.lights.set':
                          case 'plugin.rovpilot.depthHold.set':
                          case 'plugin.rovpilot.headingHold.set':
                            _self.rov.emit.apply(_self.rov,msg);
                          break;
                        }
                      }

                    });

                  p.on('close', function(){
                    _self.viewers--;
                    socket.off('signal',onSignalHanlder);
                    _self.rov.offAny(onAnyHandler);
                    _self.cockpit.off('x-h264-video.data',videodataHanlder);
                    _self.cockpit.emit('plugin.rovpilot.sendToROVEnabled',true);
                    var index = _self.peers.indexOf(p);
                    if (index > -1) {
                      _self.peers.splice(index, 1);
                    }
                    p = null;
                  });

                })
              });

          });

      });
    });
  }

      IC.prototype.inputDefaults = function inputDefaults() {
        var self = this;
        return []
      };

      //headsUpMenuItems is called by the headsup-menu plugin if present.
      IC.prototype.altMenuDefaults = function altMenuDefaults() {
        //TODO: Need to cleanup the interface to the alt-menu
        var self = this;
        var item = {
          label: 'Internet Control',
          callback: function() {
            console.log("Internet Control")
          }
        };
        return item;
      }

      window.Cockpit.plugins.push(IC);

    }(window, document, $));
<commit_msg>Enable UDP connections (#55)<commit_after>(function(window, document, $) { //The function wrapper prevents leaking variables to global space
    'use strict';
    var IC;

    //These lines register the Example object in a plugin namespace that makes
    //referencing the plugin easier when debugging.
    var plugins = namespace('plugins');
    plugins.IC = IC;

    IC = function IC(cockpit) {

      console.log('Loading internet-control plugin in the browser.');

      //instance variables
      this.cockpit = cockpit;
      this.rov = cockpit.rov;
      this.settings = {};

      // for plugin management:
      this.pluginDefaults = {
        name: 'Internet Control', // for the settings
        viewName: 'Internet Control plugin', // for the UI
        canBeDisabled: true, //allow enable/disable
        defaultEnabled: false
      };
      this.enabled=false;
      this.connected = false;
      this.connecting = false;
      this.viewers = 0;
      this.peers = [];

    };

    //private functions and variables (hidden within the function, available via the closure)

    //Adding the public methods using prototype simply groups those methods
    //together outside the parent function definition for easier readability.

    //Called by the plugin-manager to enable a plugin
    IC.prototype.enable = function enable() {
      alert('Internet-control enabled');
      this.listen();
    };

    //Called by the plugin-manager to disable a plugin
    IC.prototype.disable = function disable() {
      alert('Internet-control disabled');
      //TODO: Impliment and unlisten
    };

    //listen gets called by the plugin framework after all of the plugins
    //have loaded.
    IC.prototype.listen = function listen() {
      if (!this.enabled){return;}
      var self = this;

      var statusUpdate=function(){
        var status = {status:'off',stats:{viewers:0,pilots:0,connection:{}},pilots:{}};
        if (self.connecting){
          status.status='starting';
        }
        if (self.connected){
          status.status='streaming';
        }
        status.stats.viewers = self.viewers;

        //TODO: Figure out how to show stats
        /*
        status.stats.connection = self.peers.map(function(item){
          item._pc.getStats(function(res){
            return res.result();
          });
        }).reduce(function(previousValue,currentValue){
          if (previousValue===null){
            return currentValue;
          }
          for (var property in currentValue) {
              if (object.hasOwnProperty(property)) {
                  previousValue[property]=previousValue[property]+currentValue[property];
              }
          }
          return previousValue;
        },null);

        */
        self.cockpit.emit('plugin-internetControl-status',status);
      }
      setInterval(statusUpdate,1000);

      //Response from the getSettings call. Using the withHistory will call the
      //update function with the last copy of this message that had been sent.
      //The settings manager sends a change message for each section when
      //first read in.
      this.rov.withHistory.on('settings-change.ic', function(settings) {
          console.log("Settings changed for IC");
          self.settings = settings.ic;

          //TODO: Move to a pattern that can retry the connection when the setting changes
          $.getScript(self.settings.webRTCSignalServerURI + "/msgpack.min.js");
          $.getScript(self.settings.webRTCSignalServerURI + "/simplepeer.js", function() {
              var _self = self
              var Peer = window.SimplePeer;
              var io = window.io;
              var socket = io(self.settings.webRTCSignalServerURI);
              self.connecting = true;
              var peerOpts= {
                  channelConfig: {
                    ordered: false,
                    maxRetransmits: 0
                  }
                }

              var heartbeatInterval = null;
              socket.on('close',function(){
                if (heartbeatInterval!==null){
                  clearInterval(heartbeatInterval);
                }
                self.connected=false;
              });

              var connectionTimeOutTimer=null;
              socket.on('disconnect',function(){
                console.log("disconneted");
                self.connected = false;
              })

              socket.on('reconnect',function(){
                console.log("disconneted");
                self.connected = true;
              })

              socket.on('heartbeat',function(data){
                console.log('Heartbeat: ' + JSON.stringify(data));
              });

              socket.on('connect',function(){
                self.connected = true;
                self.connecting= false;

                //var msgpack = require("msgpack-lite");

                heartbeatInterval=setInterval(function(){
                  if (!self.connected){return;}
                  socket.emit('heartbeat','server');
                },1000);
                var pilot_sender_id = null;

                socket.on('peer-connect-offer',function(peer_id,callback){
                  var p = new Peer(peerOpts);

                  p.withHistory = {
                    on: function(event, fn) {
                      p.on(event, fn);
                    }
                  };

                  p.on('error', function (err) {
                    console.error('error', err)
                  })

                  p.on('signal', function (data) {
                    socket.emit('signal',peer_id, data);
                    console.log('SIGNAL SENT:', JSON.stringify(data))
                  })

                  var onSignalHanlder = function(data,sender_id){
                    if (sender_id !== peer_id){
                      console.error('Invalid sender_id');
                      return;
                    }
                    p.signal(data);
                  };

                  socket.on('signal',onSignalHanlder);

                  callback(true);

                  p.on('connect', function(){
                    _self.viewers++;
                    _self.peers.push(p);
                    //make last person to connect pilot by default
                    pilot_sender_id = peer_id;
                    _self.cockpit.emit('plugin.rovpilot.sendToROVEnabled',false);
//                    var emitter = new EventEmitter2();
                    p.sendemit = function sendemit(){
                      var args = new Array(arguments.length);
                      for(var i = 0; i < args.length; ++i) {
                                  //i is always valid index in the arguments object
                          args[i] = arguments[i];
                      }
                      p.send(msgpack.encode(args));
                      //p.send("THIS IS A STRING!!!!");
                    }

                    //Test data payload sizes
                    for (var i=1;i<=10;i++){
                      var size = Math.pow(2,i);
                      p.sendemit('data-msg',size,new ArrayBuffer(size),'ok');
                    }

                    var onevent = _self.rov.socket.onevent;

                    _self.rov.socket.onevent = function (packet) {
                        var args = packet.data || [];
                        onevent.call (this, packet);    // original call

                        if (p==null) {return;}
                        args = args.filter(function(n){ return n != null });
                        p.sendemit.apply(this,args);
                    };

                    var onAnyHandler = function() {
                      var event = this.event;
                      if (event !== 'newListener') {
                      //  console.log(event);
                        var args = new Array(arguments.length);
                        for(var i = 0; i < args.length; ++i) {
                                    //i is always valid index in the arguments object
                            args[i] = arguments[i];
                        }
                        args.unshift(event);
                        p.sendemit.apply(p,args);
                      }
                    }
                    _self.rov.onAny(onAnyHandler);

                    //Since the video comes in via a different route...
                    const webRTCDataChannelChunkLimit=16*1024; //16KB Chunk Recommendation
                    var videodataHanlder = function(data){
                      var chunk_count = 1;
                      var sliceend=0;
                      var end = 0;
                      while(end<data.byteLength){
                        var sliceend = sliceend+webRTCDataChannelChunkLimit>data.byteLength?data.byteLength:sliceend+webRTCDataChannelChunkLimit
                        var chunk = data.slice(end,sliceend);
                        p.sendemit('x-h264-video.chunk',chunk_count,data.byteLength-sliceend,chunk);
                        chunk_count++;
                        end=sliceend;
                      }
                    }
                    _self.cockpit.on('x-h264-video.data',videodataHanlder);

                    p.on('data',function(data){
                      var msg = msgpack.decode(data);
                      switch(msg[0]){
                        case 'request_Init_Segment':
                          _self.cockpit.emit('request_Init_Segment',function(init){
                              p.sendemit('x-h264-video.init',init);
                          });
                        break;
                      }

                      if (peer_id == pilot_sender_id){
                        switch(msg[0]){
                          case 'throttle':
                          case 'yaw':
                          case 'list':
                          case 'pitch':
                          case 'roll':
                          case 'strafe':
                            _self.rov.emit(msg[0],msg[1]);
                          break;
                          case 'plugin.rovpilot.desiredControlRates':
                          case 'plugin.externalLights.toggle':
                          case 'plugin.externalLights.adjust':
                          case 'plugin.externalLights.set':
                          case 'plugin.laser.set':
                          case 'plugin.lights.toggle':
                          case 'plugin.lights.adjust':
                          case 'plugin.lights.set':
                          case 'plugin.rovpilot.depthHold.set':
                          case 'plugin.rovpilot.headingHold.set':
                            _self.rov.emit.apply(_self.rov,msg);
                          break;
                        }
                      }

                    });

                  p.on('close', function(){
                    _self.viewers--;
                    socket.off('signal',onSignalHanlder);
                    _self.rov.offAny(onAnyHandler);
                    _self.cockpit.off('x-h264-video.data',videodataHanlder);
                    _self.cockpit.emit('plugin.rovpilot.sendToROVEnabled',true);
                    var index = _self.peers.indexOf(p);
                    if (index > -1) {
                      _self.peers.splice(index, 1);
                    }
                    p = null;
                  });

                })
              });

          });

      });
    });
  }

      IC.prototype.inputDefaults = function inputDefaults() {
        var self = this;
        return []
      };

      //headsUpMenuItems is called by the headsup-menu plugin if present.
      IC.prototype.altMenuDefaults = function altMenuDefaults() {
        //TODO: Need to cleanup the interface to the alt-menu
        var self = this;
        var item = {
          label: 'Internet Control',
          callback: function() {
            console.log("Internet Control")
          }
        };
        return item;
      }

      window.Cockpit.plugins.push(IC);

    }(window, document, $));
<|endoftext|>


<commit_before>'use strict'

import logger from 'winston'
import xpath from 'xpath'
import { DOMParser as Dom } from 'xmldom'
import { promisify } from 'util'

import * as Channels from '../model/channels'
import * as utils from '../utils'

function matchContent (channel, ctx) {
  if (channel.matchContentRegex) {
    return matchRegex(channel.matchContentRegex, ctx.body)
  } else if (channel.matchContentXpath && channel.matchContentValue) {
    return matchXpath(channel.matchContentXpath, channel.matchContentValue, ctx.body)
  } else if (channel.matchContentJson && channel.matchContentValue) {
    return matchJsonPath(channel.matchContentJson, channel.matchContentValue, ctx.body)
  } else if (channel.matchContentXpath || channel.matchContentJson) {
    // if only the match expression is given, deny access
    // this is an invalid channel
    logger.error(`Channel with name '${channel.name}' is invalid as it has a content match expression but no value to match`)
    return false
  } else {
    return true
  }
}

function matchRegex (regexPat, body) {
  const regex = new RegExp(regexPat)
  return regex.test(body.toString())
}

function matchXpath (xpathStr, val, xml) {
  const doc = new Dom().parseFromString(xml.toString())
  const xpathVal = xpath.select(xpathStr, doc).toString()
  return val === xpathVal
}

function matchJsonPath (jsonPath, val, json) {
  const jsonObj = JSON.parse(json.toString())
  const jsonVal = getJSONValByString(jsonObj, jsonPath)
  return val === jsonVal.toString()
}

// taken from http://stackoverflow.com/a/6491621/588776
// readbility improved from the stackoverflow answer
function getJSONValByString (jsonObj, jsonPath) {
  jsonPath = jsonPath.replace(/\[(\w+)\]/g, '.$1')  // convert indexes to properties
  jsonPath = jsonPath.replace(/^\./, '')            // strip a leading dot
  const parts = jsonPath.split('.')
  while (parts.length) {
    const part = parts.shift()
    if (part in jsonObj) {
      jsonObj = jsonObj[part]
    } else {
      return
    }
  }
  return jsonObj
}

function extractContentType (ctHeader) {
  const index = ctHeader.indexOf(';')
  if (index !== -1) {
    return ctHeader.substring(0, index).trim()
  } else {
    return ctHeader.trim()
  }
}

function matchUrlPattern (channel, ctx) {
  const pat = new RegExp(channel.urlPattern)
  return pat.test(ctx.request.path)
}

function matchContentTypes (channel, ctx) {
  if ((channel.matchContentTypes != null ? channel.matchContentTypes.length : undefined) > 0) {
    if (ctx.request.header && ctx.request.header['content-type']) {
      const ct = extractContentType(ctx.request.header['content-type'])
      if (Array.from(channel.matchContentTypes).includes(ct)) {
        return true
      } else {
        // deny access to channel if the content type doesnt match
        return false
      }
    } else {
      // deny access to channel if the content type isnt set
      return false
    }
  } else {
    return true // don't match on content type if this channel doesn't require it
  }
}

// Needs to be mutable for testing
// eslint-disable-next-line
let matchFunctions = [
  matchUrlPattern,
  matchContent,
  matchContentTypes
]

const matchChannel = (channel, ctx) => matchFunctions.every(matchFunc => matchFunc(channel, ctx))

const findMatchingChannel = (channels, ctx) => channels.find(channel => matchChannel(channel, ctx))

const matchRequest = (ctx, done) =>
  utils.getAllChannelsInPriorityOrder((err, channels) => {
    if (err) {
      ctx.response.status = 500
      logger.error('Could not fetch OpenHIM channels', err)
      return done()
    }

    channels = channels.filter(Channels.isChannelEnabled)

    const match = findMatchingChannel(channels, ctx)
    return done(null, match)
  })

export async function koaMiddleware (ctx, next) {
  const matchReq = promisify(matchRequest)
  const match = await matchReq(ctx)

  if (match != null) {
    logger.info(`The channel that matches the request ${ctx.request.path} is: ${match.name}`)
    ctx.matchingChannel = match
  } else {
    logger.info(`No channel matched the request ${ctx.request.path}`)
  }

  await next()
}

// export private functions for unit testing
// note: you cant spy on these method because of this :(
if (process.env.NODE_ENV === 'test') {
  exports.matchContent = matchContent
  exports.matchRegex = matchRegex
  exports.matchXpath = matchXpath
  exports.matchJsonPath = matchJsonPath
  exports.extractContentType = extractContentType
  exports.matchRequest = matchRequest
}
<commit_msg>Add logic for matching the request http method<commit_after>'use strict'

import logger from 'winston'
import xpath from 'xpath'
import { DOMParser as Dom } from 'xmldom'
import { promisify } from 'util'

import * as Channels from '../model/channels'
import * as utils from '../utils'

function matchContent (channel, ctx) {
  if (channel.matchContentRegex) {
    return matchRegex(channel.matchContentRegex, ctx.body)
  } else if (channel.matchContentXpath && channel.matchContentValue) {
    return matchXpath(channel.matchContentXpath, channel.matchContentValue, ctx.body)
  } else if (channel.matchContentJson && channel.matchContentValue) {
    return matchJsonPath(channel.matchContentJson, channel.matchContentValue, ctx.body)
  } else if (channel.matchContentXpath || channel.matchContentJson) {
    // if only the match expression is given, deny access
    // this is an invalid channel
    logger.error(`Channel with name '${channel.name}' is invalid as it has a content match expression but no value to match`)
    return false
  } else {
    return true
  }
}

function matchMethod(channel, ctx) {
  return channel.methods.find(method => ctx.request.method.toUpperCase() === method) ? true : false
}

function matchRegex (regexPat, body) {
  const regex = new RegExp(regexPat)
  return regex.test(body.toString())
}

function matchXpath (xpathStr, val, xml) {
  const doc = new Dom().parseFromString(xml.toString())
  const xpathVal = xpath.select(xpathStr, doc).toString()
  return val === xpathVal
}

function matchJsonPath (jsonPath, val, json) {
  const jsonObj = JSON.parse(json.toString())
  const jsonVal = getJSONValByString(jsonObj, jsonPath)
  return val === jsonVal.toString()
}

// taken from http://stackoverflow.com/a/6491621/588776
// readbility improved from the stackoverflow answer
function getJSONValByString (jsonObj, jsonPath) {
  jsonPath = jsonPath.replace(/\[(\w+)\]/g, '.$1')  // convert indexes to properties
  jsonPath = jsonPath.replace(/^\./, '')            // strip a leading dot
  const parts = jsonPath.split('.')
  while (parts.length) {
    const part = parts.shift()
    if (part in jsonObj) {
      jsonObj = jsonObj[part]
    } else {
      return
    }
  }
  return jsonObj
}

function extractContentType (ctHeader) {
  const index = ctHeader.indexOf(';')
  if (index !== -1) {
    return ctHeader.substring(0, index).trim()
  } else {
    return ctHeader.trim()
  }
}

function matchUrlPattern (channel, ctx) {
  const pat = new RegExp(channel.urlPattern)
  return pat.test(ctx.request.path)
}

function matchContentTypes (channel, ctx) {
  if ((channel.matchContentTypes != null ? channel.matchContentTypes.length : undefined) > 0) {
    if (ctx.request.header && ctx.request.header['content-type']) {
      const ct = extractContentType(ctx.request.header['content-type'])
      if (Array.from(channel.matchContentTypes).includes(ct)) {
        return true
      } else {
        // deny access to channel if the content type doesnt match
        return false
      }
    } else {
      // deny access to channel if the content type isnt set
      return false
    }
  } else {
    return true // don't match on content type if this channel doesn't require it
  }
}

// Needs to be mutable for testing
// eslint-disable-next-line
let matchFunctions = [
  matchUrlPattern,
  matchContent,
  matchMethod,
  matchContentTypes
]

const matchChannel = (channel, ctx) => matchFunctions.every(matchFunc => matchFunc(channel, ctx))

const findMatchingChannel = (channels, ctx) => channels.find(channel => matchChannel(channel, ctx))

const matchRequest = (ctx, done) =>
  utils.getAllChannelsInPriorityOrder((err, channels) => {
    if (err) {
      ctx.response.status = 500
      logger.error('Could not fetch OpenHIM channels', err)
      return done()
    }

    channels = channels.filter(Channels.isChannelEnabled)

    const match = findMatchingChannel(channels, ctx)
    return done(null, match)
  })

export async function koaMiddleware (ctx, next) {
  const matchReq = promisify(matchRequest)
  const match = await matchReq(ctx)

  if (match != null) {
    logger.info(`The channel that matches the request ${ctx.request.path} is: ${match.name}`)
    ctx.matchingChannel = match
  } else {
    logger.info(`No channel matched the request ${ctx.request.path}`)
  }

  await next()
}

// export private functions for unit testing
// note: you cant spy on these method because of this :(
if (process.env.NODE_ENV === 'test') {
  exports.matchContent = matchContent
  exports.matchRegex = matchRegex
  exports.matchXpath = matchXpath
  exports.matchJsonPath = matchJsonPath
  exports.extractContentType = extractContentType
  exports.matchRequest = matchRequest
}
<|endoftext|>


<commit_before>/* global module, __dirname */
'use strict'

const pkg = require('./package.json')
const webpack = require('webpack')
const url = require('url')

const {
	DefinePlugin,
	HotModuleReplacementPlugin,
	LoaderOptionsPlugin,
	NormalModuleReplacementPlugin,
	NamedModulesPlugin,
	optimize: {
		CommonsChunkPlugin,
		UglifyJsPlugin,
	},
} = webpack

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlPlugin = require('./scripts/webpack/html-plugin')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin')

const isCI = Boolean(process.env.CI)
const outputFolder = __dirname + '/build/'

const entries = {
	bfr: 'buffer',
	hanson: './modules/hanson-format',
	common: [
		'debug',
		'delay',
		'listify',
		'ord',
		'p-props',
		'p-series',
		'p-settle',
		'plur',
		'redux',
		'redux-promise',
		'redux-thunk',
		'redux-undo',
		'serialize-error',
		'stabilize',
		'whatwg-fetch',
	],
	react: [
		'classnames',
		'dnd-core',
		'history',
		'react',
		'react-dnd',
		'react-dnd-html5-backend',
		'react-dom',
		'react-modal',
		'react-redux',
		'react-router',
		'react-side-effect',
	],
	yaml: [ 'js-yaml' ],
	idb: [ 'treo', 'idb-range', 'idb-request' ],
	cm: [ 'codemirror' ],
	html: [ 'htmlparser2', 'css-select' ],
}

function config() {
	const isProduction = (process.env.NODE_ENV === 'production')
	const isDevelopment = !isProduction

	let publicPath = '/'
	if (isProduction) {
		// We use "homepage" field to infer "public path" at which the app is served.
		// Webpack needs to know it to put the right

			<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/nhhpgddphdimipafjfiggjnbbmcoklld">

			${isProduction ?
				''
				: ''}

			${context.css ?
				`<link rel="stylesheet" href="${publicPath}${context.css}">`
				: ''}

			${Object.keys(entries)
				.map(k => `<script src="${publicPath}${context[k]}"></script>`)
				.join('\n')}

		`),

		// Ignore the "full" schema in js-yaml's module, because it brings in esprima
		// to support the !!js/function type. We don't use and have no need for it, so
		// tell webpack to ignore it.
		new NormalModuleReplacementPlugin(/schema\/default_full$/, result => {
			result.request = result.request.replace('default_full', 'default_safe')
		}),

		// DefinePlugin makes some variables available to the code.
		new DefinePlugin({
			VERSION: JSON.stringify(pkg.version),
			// APP_BASE is used in react-router, to set its base appropriately
			// across both local dev and gh-pages.
			APP_BASE: JSON.stringify(publicPath),
			'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
		}),

		// Extract the common libraries into a single file so that the chunks
		// don't need to individually bundle them.
		new CommonsChunkPlugin({
			names: [
				...Object.keys(entries),
				'manifest',
			],
			filename: '[name].[hash].js',
			minChunks: Infinity,
		}),

		// Watcher doesn't work well if you mistype casing in a path so we use
		// a plugin that prints an error when you attempt to do this.
		new CaseSensitivePathsPlugin(),

		new LoaderOptionsPlugin({
			options: {
				worker: {
					output: {
						filename: '[hash].worker.js',
						chunkFilename: '[id].[hash].worker.js',
					},
				},
			},
		}),

		new NamedModulesPlugin(),
	]

	if (isProduction) {
		// minify in production
		plugins.push(new UglifyJsPlugin({
			sourceMap: true,
			compress: {
				warnings: false,
				pure_getters: true, // eslint-disable-line camelcase
				screw_ie8: true, // eslint-disable-line camelcase
				unsafe: true,
			},
			mangle: {
				screw_ie8: true, // eslint-disable-line camelcase
			},
			output: {
				comments: false,
				screw_ie8: true, // eslint-disable-line camelcase
			},
		}))
		plugins.push(new ExtractTextPlugin({
			filename: isDevelopment ? 'app.css' : `${pkg.name}.[contenthash].css`,
			allChunks: true,
		}))
		plugins.push(new LoaderOptionsPlugin({
			minimize: true,
		}))
		plugins.push(new DuplicatePackageCheckerPlugin())
	}

	if (isDevelopment) {
		// add dev plugins
		plugins.push(new HotModuleReplacementPlugin())
	}

	const babelLoader = { loader: 'babel-loader', options: { cacheDirectory: !isCI } }
	const babelForNodeModules =  { loader: 'babel-loader', options: { cacheDirectory: !isCI, plugins: [ 'transform-es2015-modules-commonjs' ] } }
	const urlLoader = { loader: 'url-loader', options: { limit: 10000 } }
	const cssLoader = isProduction
		? ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: [ 'css-loader', 'sass-loader' ] })
		: [ 'style-loader', 'css-loader', 'sass-loader' ]

	const module = {
		rules: [
			{
				test: /\.js$/,
				exclude: /node_modules/,
				use: [ babelLoader ],
			},
			{
				test: /\.js$/,
				include: /node_modules[/]p-.*[/].*[.]js$/,
				use: [ babelForNodeModules ],
			},
			{
				test: /\.worker.js$/,
				exclude: /node_modules/,
				use: [ 'worker-loader', babelLoader ],
			},
			{
				test: /\.json$/,
				use: [ 'json-loader' ],
			},
			{
				test: /\.otf|eot|ttf|woff2?$/,
				use: [ urlLoader ],
			},
			{
				test: /\.jpe?g|png|gif$/,
				use: [ urlLoader ],
			},
			{
				test: /\.scss$/,
				use: cssLoader,
			},
		],
	}

	return {
		target: 'web',
		devtool,
		stats,
		entry,
		output,
		devServer,
		node,
		plugins,
		module,
	}
}

module.exports = config
<commit_msg>allow the scss loader to load css files<commit_after>/* global module, __dirname */
'use strict'

const pkg = require('./package.json')
const webpack = require('webpack')
const url = require('url')

const {
	DefinePlugin,
	HotModuleReplacementPlugin,
	LoaderOptionsPlugin,
	NormalModuleReplacementPlugin,
	NamedModulesPlugin,
	optimize: {
		CommonsChunkPlugin,
		UglifyJsPlugin,
	},
} = webpack

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlPlugin = require('./scripts/webpack/html-plugin')
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin')
const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin')

const isCI = Boolean(process.env.CI)
const outputFolder = __dirname + '/build/'

const entries = {
	bfr: 'buffer',
	hanson: './modules/hanson-format',
	common: [
		'debug',
		'delay',
		'listify',
		'ord',
		'p-props',
		'p-series',
		'p-settle',
		'plur',
		'redux',
		'redux-promise',
		'redux-thunk',
		'redux-undo',
		'serialize-error',
		'stabilize',
		'whatwg-fetch',
	],
	react: [
		'classnames',
		'dnd-core',
		'history',
		'react',
		'react-dnd',
		'react-dnd-html5-backend',
		'react-dom',
		'react-modal',
		'react-redux',
		'react-router',
		'react-side-effect',
	],
	yaml: [ 'js-yaml' ],
	idb: [ 'treo', 'idb-range', 'idb-request' ],
	cm: [ 'codemirror' ],
	html: [ 'htmlparser2', 'css-select' ],
}

function config() {
	const isProduction = (process.env.NODE_ENV === 'production')
	const isDevelopment = !isProduction

	let publicPath = '/'
	if (isProduction) {
		// We use "homepage" field to infer "public path" at which the app is served.
		// Webpack needs to know it to put the right

			<link rel="chrome-webstore-item" href="https://chrome.google.com/webstore/detail/nhhpgddphdimipafjfiggjnbbmcoklld">

			${isProduction ?
				''
				: ''}

			${context.css ?
				`<link rel="stylesheet" href="${publicPath}${context.css}">`
				: ''}

			${Object.keys(entries)
				.map(k => `<script src="${publicPath}${context[k]}"></script>`)
				.join('\n')}

		`),

		// Ignore the "full" schema in js-yaml's module, because it brings in esprima
		// to support the !!js/function type. We don't use and have no need for it, so
		// tell webpack to ignore it.
		new NormalModuleReplacementPlugin(/schema\/default_full$/, result => {
			result.request = result.request.replace('default_full', 'default_safe')
		}),

		// DefinePlugin makes some variables available to the code.
		new DefinePlugin({
			VERSION: JSON.stringify(pkg.version),
			// APP_BASE is used in react-router, to set its base appropriately
			// across both local dev and gh-pages.
			APP_BASE: JSON.stringify(publicPath),
			'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
		}),

		// Extract the common libraries into a single file so that the chunks
		// don't need to individually bundle them.
		new CommonsChunkPlugin({
			names: [
				...Object.keys(entries),
				'manifest',
			],
			filename: '[name].[hash].js',
			minChunks: Infinity,
		}),

		// Watcher doesn't work well if you mistype casing in a path so we use
		// a plugin that prints an error when you attempt to do this.
		new CaseSensitivePathsPlugin(),

		new LoaderOptionsPlugin({
			options: {
				worker: {
					output: {
						filename: '[hash].worker.js',
						chunkFilename: '[id].[hash].worker.js',
					},
				},
			},
		}),

		new NamedModulesPlugin(),
	]

	if (isProduction) {
		// minify in production
		plugins.push(new UglifyJsPlugin({
			sourceMap: true,
			compress: {
				warnings: false,
				pure_getters: true, // eslint-disable-line camelcase
				screw_ie8: true, // eslint-disable-line camelcase
				unsafe: true,
			},
			mangle: {
				screw_ie8: true, // eslint-disable-line camelcase
			},
			output: {
				comments: false,
				screw_ie8: true, // eslint-disable-line camelcase
			},
		}))
		plugins.push(new ExtractTextPlugin({
			filename: isDevelopment ? 'app.css' : `${pkg.name}.[contenthash].css`,
			allChunks: true,
		}))
		plugins.push(new LoaderOptionsPlugin({
			minimize: true,
		}))
		plugins.push(new DuplicatePackageCheckerPlugin())
	}

	if (isDevelopment) {
		// add dev plugins
		plugins.push(new HotModuleReplacementPlugin())
	}

	const babelLoader = { loader: 'babel-loader', options: { cacheDirectory: !isCI } }
	const babelForNodeModules =  { loader: 'babel-loader', options: { cacheDirectory: !isCI, plugins: [ 'transform-es2015-modules-commonjs' ] } }
	const urlLoader = { loader: 'url-loader', options: { limit: 10000 } }
	const cssLoader = isProduction
		? ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: [ 'css-loader', 'sass-loader' ] })
		: [ 'style-loader', 'css-loader', 'sass-loader' ]

	const module = {
		rules: [
			{
				test: /\.js$/,
				exclude: /node_modules/,
				use: [ babelLoader ],
			},
			{
				test: /\.js$/,
				include: /node_modules[/]p-.*[/].*[.]js$/,
				use: [ babelForNodeModules ],
			},
			{
				test: /\.worker.js$/,
				exclude: /node_modules/,
				use: [ 'worker-loader', babelLoader ],
			},
			{
				test: /\.json$/,
				use: [ 'json-loader' ],
			},
			{
				test: /\.otf|eot|ttf|woff2?$/,
				use: [ urlLoader ],
			},
			{
				test: /\.jpe?g|png|gif$/,
				use: [ urlLoader ],
			},
			{
				test: /\.s?css$/,
				use: cssLoader,
			},
		],
	}

	return {
		target: 'web',
		devtool,
		stats,
		entry,
		output,
		devServer,
		node,
		plugins,
		module,
	}
}

module.exports = config
<|endoftext|>


<commit_before>export const baseFontSize = 16

export const colors = {
  lightPrimary: '#5EB6FF',
  primary: '#36A4FF',
  darkPrimary: '#2B83CC',

  lightSecondary: '#46CCD6',
  secondary: '#18C0CC',
  darkSecondary: '#1399A3',

  lightestTertiary: '#6F8CA5',
  lightTertiary: '#5E7E9A',
  tertiary: '#4C708F',
  darkTertiary: '#446480',
  darkestTertiary: '#3C5972',

  lightestGrey: '#B4C1CC',
  lightGrey: '#ABB9C6',
  grey: '#A2B2C0',
  darkGrey: '#919FAC',
  darkestGrey: '#818E99',

  accent: '#F4865D',
  darkAccent: '#EF6A39',

  lightAlert: '#F95568',
  alert: '#EF4351',
  darkAlert: '#E8364F',

  background: '#F8F8F8',
  white: '#FFFFFF',
  black: '#000000'
}

export const typography = {
  primary: {
    fontFamily: 'Museo Sans',
    fontWeight: 500,
    src: `url('/assets/fonts/MuseoSans/MuseoSans-900.otf')`
  }
}

export const fonts = {
  primary: 'Museo Sans'
}
<commit_msg>change default background color<commit_after>export const baseFontSize = 16

export const colors = {
  lightPrimary: '#5EB6FF',
  primary: '#36A4FF',
  darkPrimary: '#2B83CC',
  lightSecondary: '#46CCD6',
  secondary: '#18C0CC',
  darkSecondary: '#1399A3',
  lightestTertiary: '#6F8CA5',
  lightTertiary: '#5E7E9A',
  tertiary: '#4C708F',
  darkTertiary: '#446480',
  darkestTertiary: '#3C5972',
  lightestGrey: '#B4C1CC',
  lightGrey: '#ABB9C6',
  grey: '#A2B2C0',
  darkGrey: '#919FAC',
  darkestGrey: '#818E99',
  accent: '#F4865D',
  darkAccent: '#EF6A39',
  lightAlert: '#F95568',
  alert: '#EF4351',
  darkAlert: '#E8364F',
  background: '#F7F9FA',
  white: '#FFFFFF',
  black: '#000000'
}

export const typography = {
  primary: {
    fontFamily: 'Museo Sans',
    fontWeight: 500,
    src: `url('/assets/fonts/MuseoSans/MuseoSans-900.otf')`
  }
}

export const fonts = { primary: 'Museo Sans' }
<|endoftext|>


<commit_before>module.exports = (function(){
    'use strict';

    var crud            = require('./mixins/crud'),
        filterFactory   = require('./search/filterFactory'),
        find            = require('./mixins/find'),
        findDistinct    = require('./mixins/findDistinct'),
        schema          = require('./schemas/content'),
        _               = require('underscore'),
        async           = require('async'),
        mongoose        = require('mongoose'),
        q               = require('q'),
        collectionName  = 'content',
        content = Object.create(crud, {
            model: {value: mongoose.model(collectionName, schema)}
        });

    function buildCollection(key, value, queryRef){
        var obj = {};

        if(value && value instanceof Array && value.length > 0){
            obj['meta.' + key] = {$in: value};
        }
        else if(value && typeof value === 'string' && value.length > 0){
            obj['meta.' + key] = value;
        }

        _.extend(queryRef, obj);
    }

    function buildQuery(nodes, types, filters, options, content){
        var query = {};

        buildCollection('node', nodes, query);
        buildCollection('type', types, query);
        filterFactory.createQuery(filters, query);

        if (options.distinct) {
            query.run = findDistinct.bind(query, nodes, types, filters, options, content);
        } else {
            query.run = find.bind(query, nodes, types, filters, options, content);
        }

        return query;
    }

    content.updateLabelField = function(type, fieldname){
        var deferred = q.defer();

        this.model.update( { 'meta.type': type } , { $set: { 'meta.labelfield': fieldname } } , { multi:true } )
            .exec(function(err, data){
                if(err){
                    deferred.reject(err);
                    return;
                }

                deferred.resolve({result: true});
            });

        return deferred.promise;
    };

    content.query = function(nodes, types, filters, options){
        return buildQuery(nodes, types, filters, options, this).run();
    };

    return content;
})();<commit_msg>Added method to check for valid mongo ids for specific values.<commit_after>module.exports = (function(){
    'use strict';

    var crud            = require('./mixins/crud'),
        filterFactory   = require('./search/filterFactory'),
        find            = require('./mixins/find'),
        findDistinct    = require('./mixins/findDistinct'),
        schema          = require('./schemas/content'),
        _               = require('underscore'),
        async           = require('async'),
        mongoose        = require('mongoose'),
        q               = require('q'),
        collectionName  = 'content',
        content = Object.create(crud, {
            model: {value: mongoose.model(collectionName, schema)}
        });

    function buildCollection(key, value, queryRef){
        var obj = {};

        if(value && value instanceof Array && value.length > 0){
            obj['meta.' + key] = {$in: value};
        }
        else if(value && typeof value === 'string' && value.length > 0){
            obj['meta.' + key] = value;
        }

        _.extend(queryRef, obj);
    }

    function buildQuery(nodes, types, filters, options, content){
        var query = {};
        buildCollection('node', nodes, query);
        buildCollection('type', types, query);
        filterFactory.createQuery(filters, query);

        if (options.distinct) {
            query.run = findDistinct.bind(query, nodes, types, filters, options, content);
        } else {
            query.run = find.bind(query, nodes, types, filters, options, content);
        }

        return query;
    }

    function cleanMongoCollection(collection){
        var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$");

        return _.filter(collection, function(item){
            return checkForHexRegExp.test(item);
        });
    }

    content.updateLabelField = function(type, fieldname){
        var deferred = q.defer();

        this.model.update( { 'meta.type': type } , { $set: { 'meta.labelfield': fieldname } } , { multi:true } )
            .exec(function(err, data){
                if(err){
                    deferred.reject(err);
                    return;
                }

                deferred.resolve({result: true});
            });

        return deferred.promise;
    };

    content.query = function(nodes, types, filters, options){
        return buildQuery(cleanMongoCollection(nodes), cleanMongoCollection(types), filters, options, this).run();
    };

    return content;
})();<|endoftext|>


<commit_before>Package.describe({
  summary: "Serves a Meteor app over HTTP",
  version: '1.2.2-rc.2'
});

Npm.depends({connect: "2.9.0",
             send: "0.1.4",
             useragent: "2.0.7"});

Npm.strip({
  multiparty: ["test/"],
  useragent: ["test/"]
});

Cordova.depends({
  'cordova-plugin-device': '1.0.1',
  'cordova-plugin-legacy-whitelist': '1.1.0',
  // the cordova plugin built by Meteor Core team that "emulates a server" on
  // the mobile device. Serving the files and checking for the HCP updates.
  'com.meteor.cordova-update': 'https://github.com/meteor/com.meteor.cordova-update/tarball/92fe99b7248075318f6446b288995d4381d24cd2'
});

Package.onUse(function (api) {
  api.use(['logging', 'underscore', 'routepolicy', 'boilerplate-generator',
           'webapp-hashing'], 'server');
  api.use(['underscore'], 'client');

  // At response serving time, webapp uses browser-policy if it is loaded. If
  // browser-policy is loaded, then it must be loaded after webapp
  // (browser-policy depends on webapp). So we don't explicitly depend in any
  // way on browser-policy here, but we use it when it is loaded, and it can be
  // loaded after webapp.
  api.export(['WebApp', 'main', 'WebAppInternals'], 'server');
  api.export(['WebApp'], 'client');
  api.addFiles('webapp_server.js', 'server');
  api.addFiles('webapp_client.js', 'client');
});

Package.onTest(function (api) {
  api.use(['tinytest', 'webapp', 'http', 'underscore']);
  api.addFiles('webapp_tests.js', 'server');
  api.addFiles('webapp_client_tests.js', 'client');
});
<commit_msg>Disable iOS 9 App Transport Security until Cordova adds support<commit_after>Package.describe({
  summary: "Serves a Meteor app over HTTP",
  version: '1.2.2-rc.2'
});

Npm.depends({connect: "2.9.0",
             send: "0.1.4",
             useragent: "2.0.7"});

Npm.strip({
  multiparty: ["test/"],
  useragent: ["test/"]
});

Cordova.depends({
  'cordova-plugin-device': '1.0.1',
  'cordova-plugin-legacy-whitelist': '1.1.0',
  // the cordova plugin built by Meteor Core team that "emulates a server" on
  // the mobile device. Serving the files and checking for the HCP updates.
  'com.meteor.cordova-update': 'https://github.com/meteor/com.meteor.cordova-update.git#815f36966f941b153d3979d64a4804064a89c1ba'
});

Package.onUse(function (api) {
  api.use(['logging', 'underscore', 'routepolicy', 'boilerplate-generator',
           'webapp-hashing'], 'server');
  api.use(['underscore'], 'client');

  // At response serving time, webapp uses browser-policy if it is loaded. If
  // browser-policy is loaded, then it must be loaded after webapp
  // (browser-policy depends on webapp). So we don't explicitly depend in any
  // way on browser-policy here, but we use it when it is loaded, and it can be
  // loaded after webapp.
  api.export(['WebApp', 'main', 'WebAppInternals'], 'server');
  api.export(['WebApp'], 'client');
  api.addFiles('webapp_server.js', 'server');
  api.addFiles('webapp_client.js', 'client');
});

Package.onTest(function (api) {
  api.use(['tinytest', 'webapp', 'http', 'underscore']);
  api.addFiles('webapp_tests.js', 'server');
  api.addFiles('webapp_client_tests.js', 'client');
});
<|endoftext|>