<commit_before>import { computed, observable, autorun } from 'mobx';
import path from 'path';
import normalizeUrl from 'normalize-url';

const debug = require('debug')('Franz:Service');

export default class Service {
  id = '';

  recipe = '';

  webview = null;

  timer = null;

  events = {};

  isAttached = false;

  @observable isActive = false; // Is current webview active

  @observable name = '';

  @observable unreadDirectMessageCount = 0;

  @observable unreadIndirectMessageCount = 0;

  @observable order = 99;

  @observable isEnabled = true;

  @observable isMuted = false;

  @observable team = '';

  @observable customUrl = '';

  @observable isNotificationEnabled = true;

  @observable isBadgeEnabled = true;

  @observable isIndirectMessageBadgeEnabled = true;

  @observable iconUrl = '';

  @observable hasCustomUploadedIcon = false;

  @observable hasCrashed = false;

  @observable isDarkModeEnabled = false;

  @observable spellcheckerLanguage = null;

  @observable isFirstLoad = true;

  @observable isLoading = true;

  @observable isError = false;

  @observable errorMessage = '';

  constructor(data, recipe) {
    if (!data) {
      console.error('Service config not valid');
      return null;
    }

    if (!recipe) {
      console.error('Service recipe not valid');
      return null;
    }

    this.id = data.id || this.id;
    this.name = data.name || this.name;
    this.team = data.team || this.team;
    this.customUrl = data.customUrl || this.customUrl;
    // this.customIconUrl = data.customIconUrl || this.customIconUrl;
    this.iconUrl = data.iconUrl || this.iconUrl;

    this.order = data.order !== undefined
      ? data.order : this.order;

    this.isEnabled = data.isEnabled !== undefined
      ? data.isEnabled : this.isEnabled;

    this.isNotificationEnabled = data.isNotificationEnabled !== undefined
      ? data.isNotificationEnabled : this.isNotificationEnabled;

    this.isBadgeEnabled = data.isBadgeEnabled !== undefined
      ? data.isBadgeEnabled : this.isBadgeEnabled;

    this.isIndirectMessageBadgeEnabled = data.isIndirectMessageBadgeEnabled !== undefined
      ? data.isIndirectMessageBadgeEnabled : this.isIndirectMessageBadgeEnabled;

    this.isMuted = data.isMuted !== undefined ? data.isMuted : this.isMuted;

    this.isDarkModeEnabled = data.isDarkModeEnabled !== undefined ? data.isDarkModeEnabled : this.isDarkModeEnabled;

    this.hasCustomUploadedIcon = data.hasCustomIcon !== undefined ? data.hasCustomIcon : this.hasCustomUploadedIcon;

    this.proxy = data.proxy !== undefined ? data.proxy : this.proxy;

    this.spellcheckerLanguage = data.spellcheckerLanguage !== undefined ? data.spellcheckerLanguage : this.spellcheckerLanguage;

    this.recipe = recipe;

    autorun(() => {
      if (!this.isEnabled) {
        this.webview = null;
        this.isAttached = false;
        this.unreadDirectMessageCount = 0;
        this.unreadIndirectMessageCount = 0;
      }
    });
  }

  @computed get shareWithWebview() {
    return {
      spellcheckerLanguage: this.spellcheckerLanguage,
      isDarkModeEnabled: this.isDarkModeEnabled,
    };
  }

  @computed get url() {
    if (this.recipe.hasCustomUrl && this.customUrl) {
      let url;
      try {
        url = normalizeUrl(this.customUrl, { stripWWW: false });
      } catch (err) {
        console.error(`Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`);
      }

      if (typeof this.recipe.buildUrl === 'function') {
        url = this.recipe.buildUrl(url);
      }

      return url;
    }

    if (this.recipe.hasTeamId && this.team) {
      return this.recipe.serviceURL.replace('{teamId}', this.team);
    }

    return this.recipe.serviceURL;
  }

  @computed get icon() {
    if (this.iconUrl) {
      return this.iconUrl;
    }

    return path.join(this.recipe.path, 'icon.svg');
  }

  @computed get hasCustomIcon() {
    return Boolean(this.iconUrl);
  }

  @computed get iconPNG() {
    return path.join(this.recipe.path, 'icon.png');
  }

  @computed get userAgent() {
    let userAgent = window.navigator.userAgent;
    if (typeof this.recipe.overrideUserAgent === 'function') {
      userAgent = this.recipe.overrideUserAgent();
    }

    return userAgent;
  }

  initializeWebViewEvents({ handleIPCMessage, openWindow }) {
    this.webview.addEventListener('ipc-message', e => handleIPCMessage({
      serviceId: this.id,
      channel: e.channel,
      args: e.args,
    }));

    this.webview.addEventListener('new-window', (event, url, frameName, options) => openWindow({
      event,
      url,
      frameName,
      options,
    }));

    this.webview.addEventListener('did-start-loading', () => {
      this.hasCrashed = false;
      this.isLoading = true;
      this.isError = false;
    });

    const didLoad = () => {
      this.isLoading = false;

      if (!this.isError) {
        this.isFirstLoad = false;
      }
    };

    this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this));
    this.webview.addEventListener('did-navigate', didLoad.bind(this));

    this.webview.addEventListener('did-fail-load', (event) => {
      debug('Service failed to load', this.name, event);
      if (event.isMainFrame && event.errorCode !== -27 && event.errorCode !== -3) {
        this.isError = true;
        this.errorMessage = event.errorDescription;
        this.isLoading = false;
      }
    });

    this.webview.addEventListener('crashed', () => {
      debug('Service crashed', this.name);
      this.hasCrashed = true;
    });
  }

  initializeWebViewListener() {
    if (this.webview && this.recipe.events) {
      Object.keys(this.recipe.events).forEach((eventName) => {
        const eventHandler = this.recipe[this.recipe.events[eventName]];
        if (typeof eventHandler === 'function') {
          this.webview.addEventListener(eventName, eventHandler);
        }
      });
    }
  }

  resetMessageCount() {
    this.unreadDirectMessageCount = 0;
    this.unreadIndirectMessageCount = 0;
  }
}
<commit_msg>fix(App): Ignore network changed error<commit_after>import { computed, observable, autorun } from 'mobx';
import path from 'path';
import normalizeUrl from 'normalize-url';

const debug = require('debug')('Franz:Service');

export default class Service {
  id = '';

  recipe = '';

  webview = null;

  timer = null;

  events = {};

  isAttached = false;

  @observable isActive = false; // Is current webview active

  @observable name = '';

  @observable unreadDirectMessageCount = 0;

  @observable unreadIndirectMessageCount = 0;

  @observable order = 99;

  @observable isEnabled = true;

  @observable isMuted = false;

  @observable team = '';

  @observable customUrl = '';

  @observable isNotificationEnabled = true;

  @observable isBadgeEnabled = true;

  @observable isIndirectMessageBadgeEnabled = true;

  @observable iconUrl = '';

  @observable hasCustomUploadedIcon = false;

  @observable hasCrashed = false;

  @observable isDarkModeEnabled = false;

  @observable spellcheckerLanguage = null;

  @observable isFirstLoad = true;

  @observable isLoading = true;

  @observable isError = false;

  @observable errorMessage = '';

  constructor(data, recipe) {
    if (!data) {
      console.error('Service config not valid');
      return null;
    }

    if (!recipe) {
      console.error('Service recipe not valid');
      return null;
    }

    this.id = data.id || this.id;
    this.name = data.name || this.name;
    this.team = data.team || this.team;
    this.customUrl = data.customUrl || this.customUrl;
    // this.customIconUrl = data.customIconUrl || this.customIconUrl;
    this.iconUrl = data.iconUrl || this.iconUrl;

    this.order = data.order !== undefined
      ? data.order : this.order;

    this.isEnabled = data.isEnabled !== undefined
      ? data.isEnabled : this.isEnabled;

    this.isNotificationEnabled = data.isNotificationEnabled !== undefined
      ? data.isNotificationEnabled : this.isNotificationEnabled;

    this.isBadgeEnabled = data.isBadgeEnabled !== undefined
      ? data.isBadgeEnabled : this.isBadgeEnabled;

    this.isIndirectMessageBadgeEnabled = data.isIndirectMessageBadgeEnabled !== undefined
      ? data.isIndirectMessageBadgeEnabled : this.isIndirectMessageBadgeEnabled;

    this.isMuted = data.isMuted !== undefined ? data.isMuted : this.isMuted;

    this.isDarkModeEnabled = data.isDarkModeEnabled !== undefined ? data.isDarkModeEnabled : this.isDarkModeEnabled;

    this.hasCustomUploadedIcon = data.hasCustomIcon !== undefined ? data.hasCustomIcon : this.hasCustomUploadedIcon;

    this.proxy = data.proxy !== undefined ? data.proxy : this.proxy;

    this.spellcheckerLanguage = data.spellcheckerLanguage !== undefined ? data.spellcheckerLanguage : this.spellcheckerLanguage;

    this.recipe = recipe;

    autorun(() => {
      if (!this.isEnabled) {
        this.webview = null;
        this.isAttached = false;
        this.unreadDirectMessageCount = 0;
        this.unreadIndirectMessageCount = 0;
      }
    });
  }

  @computed get shareWithWebview() {
    return {
      spellcheckerLanguage: this.spellcheckerLanguage,
      isDarkModeEnabled: this.isDarkModeEnabled,
    };
  }

  @computed get url() {
    if (this.recipe.hasCustomUrl && this.customUrl) {
      let url;
      try {
        url = normalizeUrl(this.customUrl, { stripWWW: false });
      } catch (err) {
        console.error(`Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`);
      }

      if (typeof this.recipe.buildUrl === 'function') {
        url = this.recipe.buildUrl(url);
      }

      return url;
    }

    if (this.recipe.hasTeamId && this.team) {
      return this.recipe.serviceURL.replace('{teamId}', this.team);
    }

    return this.recipe.serviceURL;
  }

  @computed get icon() {
    if (this.iconUrl) {
      return this.iconUrl;
    }

    return path.join(this.recipe.path, 'icon.svg');
  }

  @computed get hasCustomIcon() {
    return Boolean(this.iconUrl);
  }

  @computed get iconPNG() {
    return path.join(this.recipe.path, 'icon.png');
  }

  @computed get userAgent() {
    let userAgent = window.navigator.userAgent;
    if (typeof this.recipe.overrideUserAgent === 'function') {
      userAgent = this.recipe.overrideUserAgent();
    }

    return userAgent;
  }

  initializeWebViewEvents({ handleIPCMessage, openWindow }) {
    this.webview.addEventListener('ipc-message', e => handleIPCMessage({
      serviceId: this.id,
      channel: e.channel,
      args: e.args,
    }));

    this.webview.addEventListener('new-window', (event, url, frameName, options) => openWindow({
      event,
      url,
      frameName,
      options,
    }));

    this.webview.addEventListener('did-start-loading', () => {
      this.hasCrashed = false;
      this.isLoading = true;
      this.isError = false;
    });

    const didLoad = () => {
      this.isLoading = false;

      if (!this.isError) {
        this.isFirstLoad = false;
      }
    };

    this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this));
    this.webview.addEventListener('did-navigate', didLoad.bind(this));

    this.webview.addEventListener('did-fail-load', (event) => {
      debug('Service failed to load', this.name, event);
      if (event.isMainFrame && event.errorCode !== -21 && event.errorCode !== -3) {
        this.isError = true;
        this.errorMessage = event.errorDescription;
        this.isLoading = false;
      }
    });

    this.webview.addEventListener('crashed', () => {
      debug('Service crashed', this.name);
      this.hasCrashed = true;
    });
  }

  initializeWebViewListener() {
    if (this.webview && this.recipe.events) {
      Object.keys(this.recipe.events).forEach((eventName) => {
        const eventHandler = this.recipe[this.recipe.events[eventName]];
        if (typeof eventHandler === 'function') {
          this.webview.addEventListener(eventName, eventHandler);
        }
      });
    }
  }

  resetMessageCount() {
    this.unreadDirectMessageCount = 0;
    this.unreadIndirectMessageCount = 0;
  }
}
<|endoftext|>


<commit_before>/**
 * Tatoeba Project, free collaborative creation of multilingual corpuses project
 * Copyright (C) 2010  HO Ngoc Phuong Trang <tranglich@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/>.
 */

$(document).ready(function() {
    $('.audioAvailable').click(function() {
       var audioURL = $(this).attr('href');

       $('#audioPlayer').html(
            '<object type="audio/mpeg" data="'+ audioURL +'" width="0" height="0">'
            + '<param name="src" value="'+ audioURL +'" />'
            + '</object>'
       );
    });
});<commit_msg>added a fallback on a flashplayer for people who don't have a browser which support the mp3 object directly<commit_after>/**
 * Tatoeba Project, free collaborative creation of multilingual corpuses project
 * Copyright (C) 2010  HO Ngoc Phuong Trang <tranglich@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/>.
 */

$(document).ready(function() {
    $('.audioAvailable').click(function() {
       var audioURL = $(this).attr('href');

       $('#audioPlayer').html(
            '<object data="'+ audioURL +'" type="audio/mpeg" data="'+ audioURL +'" width="0" height="0">'+
                '<param name="src" value="'+ audioURL +'" />' +
                '<object '+
                    'type="application/x-shockwave-flash" '+
                    'data="http://static.tatoeba.org/dewplayer-mini.swf?autostart=1&mp3='+audioURL +'" '+
                    'width="0" '+
                    'height="0" '+
                '>'+
                    '<param name="movie" value="http://static.tatoeba.org/dewplayer-mini.swf?autostart=1&mp3='+audioURL +'" />'+
                '</object>'+
            '</object>'
       );
    });
});
<|endoftext|>


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

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

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import {
	DATE_RANGE_OFFSET,
	MODULES_ANALYTICS,
} from '../../../datastore/constants';
import { CORE_USER } from '../../../../../googlesitekit/datastore/user/constants';
import { CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { Grid, Row, Cell } from '../../../../../material-components/layout';
import PreviewBlock from '../../../../../components/PreviewBlock';
import DataBlock from '../../../../../components/DataBlock';
import Sparkline from '../../../../../components/Sparkline';
import whenActive from '../../../../../util/when-active';
import { calculateChange } from '../../../../../util';
import parseDimensionStringToDate from '../../../util/parseDimensionStringToDate';
import { isZeroReport } from '../../../util';
const { useSelect } = Data;
// const { useSelect, useDispatch } = Data;

function useWidgetReport() {
	return useSelect( ( select ) => {
		const dates = select( CORE_USER ).getDateRangeDates( {
			offsetDays: DATE_RANGE_OFFSET,
			compare: true,
		} );

		const url = select( CORE_SITE ).getCurrentEntityURL();

		// eslint-disable-next-line no-console
		console.log( 'entity URL', url );

		const args = {
			...dates,
			dimensions: [ 'ga:date' ],
			// dimensions: [ 'ga:pagePath' ],
			// dimensions: [ 'ga:hostname' ],
			metrics: [
				{
					expression: 'ga:pageviews',
					alias: 'Pageviews',
				},
				{
					expression: 'ga:uniquePageviews',
					alias: 'Unique Pageviews',
				},
				{
					expression: 'ga:bounceRate',
					alias: 'Bounce Rate',
				},
				{
					expression: 'ga:avgSessionDuration',
					alias: 'Session Duration',
				},
			],
			url,
			// orderby: [
			// 	{
			// 		fieldName: 'ga:pageviews',
			// 		sortOrder: 'DESCENDING',
			// 	},
			// ],
			// limit: 10,
		};

		const report = select( MODULES_ANALYTICS ).getReport( args );

		const error = select(
			MODULES_ANALYTICS
		).getErrorForSelector( 'getReport', [ args ] );

		const isLoading = ! select(
			MODULES_ANALYTICS
		).hasFinishedResolution( 'getReport', [ args ] );

		return {
			report,
			error,
			isLoading,
		};
	} );
}

function DashboardOverallPageMetricsWidget( {
	// Widget,
	WidgetReportZero,
	WidgetReportError,
} ) {
	const isGatheringData = useSelect( ( select ) =>
		select( MODULES_ANALYTICS ).isGatheringData()
	);

	// eslint-disable-next-line no-console
	console.log( 'isGatheringData', isGatheringData );

	const { report, isLoading, error } = useWidgetReport();

	// eslint-disable-next-line no-console
	console.log( 'report, isLoading, error', report, isLoading, error );

	if ( isLoading || isGatheringData === undefined ) {
		return <PreviewBlock width="100%" height="202px" />;
	}

	if ( error ) {
		return <WidgetReportError moduleSlug="analytics" error={ error } />;
	}

	if ( isGatheringData && isZeroReport( report ) ) {
		return <WidgetReportZero moduleSlug="analytics" />;
	}

	const sparkLineData = [
		[
			{ type: 'date', label: 'Day' },
			{ type: 'number', label: 'Pageviews' },
		],
	];

	const { totals = [], rows = [] } = report?.[ 0 ]?.data || {};

	// We only want half the date range, having `multiDateRange` in the query doubles the range.
	for ( let i = Math.ceil( rows.length / 2 ); i < rows.length; i++ ) {
		const { values } = rows[ i ].metrics[ 0 ];
		const dateString = rows[ i ].dimensions[ 0 ];
		const date = parseDimensionStringToDate( dateString );
		sparkLineData.push( [ date, values[ 0 ] ] );
	}

	const lastMonth = totals[ 0 ]?.values || [];
	const previousMonth = totals[ 1 ]?.values || [];
	const pageviews = lastMonth[ 0 ] || 0;
	const pageviewsChange = calculateChange(
		previousMonth[ 0 ] || 0,
		lastMonth[ 0 ] || 0
	);

	const serviceURL = 'http://foo.com';

	// content-drilldown ?
	// trafficsources-overview ?

	return (
		<Grid>
			{ /* TODO: Do we need the title/subtitle? If so, fix CSS classes. */ }
			<Row>
				<Cell className="googlesitekit-widget-area-header" size={ 12 }>

						{ __( 'Overall Page Metrics', 'google-site-kit' ) }

						{ __(
							'Overall page metrics, subtitle.',
							'google-site-kit'
						) }

				</Cell>
			</Row>
			<Row>
				{ /* <Cell lgSize={ 7 } mdSize={ 8 }> */ }
				<Cell size={ 3 }>
					<DataBlock
						// className="overview-goals-completed"
						title={ __( 'Pageviews', 'google-site-kit' ) }
						datapoint={ pageviews }
						change={ pageviewsChange }
						changeDataUnit="%"
						source={ {
							name: _x(
								'Analytics',
								'Service name',
								'google-site-kit'
							),
							link: serviceURL,
							external: true,
						} }
						sparkline={
							<Sparkline
								data={ sparkLineData }
								change={ pageviewsChange }
							/>
						}
					/>
				</Cell>
				<Cell size={ 3 }>TODO: UNIQUE PAGEVIEWS</Cell>
				<Cell size={ 3 }>TODO: BOUNCE RATE</Cell>
				<Cell size={ 3 }>TODO: SESSION DURATION</Cell>
			</Row>
		</Grid>
	);
}

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

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

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import {
	DATE_RANGE_OFFSET,
	MODULES_ANALYTICS,
} from '../../../datastore/constants';
import { CORE_USER } from '../../../../../googlesitekit/datastore/user/constants';
import { CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { Grid, Row, Cell } from '../../../../../material-components/layout';
import PreviewBlock from '../../../../../components/PreviewBlock';
import DataBlock from '../../../../../components/DataBlock';
import Sparkline from '../../../../../components/Sparkline';
import whenActive from '../../../../../util/when-active';
import { calculateChange } from '../../../../../util';
import parseDimensionStringToDate from '../../../util/parseDimensionStringToDate';
import { isZeroReport } from '../../../util';
const { useSelect } = Data;
// const { useSelect, useDispatch } = Data;

function useWidgetReport() {
	return useSelect( ( select ) => {
		const dates = select( CORE_USER ).getDateRangeDates( {
			offsetDays: DATE_RANGE_OFFSET,
			compare: true,
		} );

		const url = select( CORE_SITE ).getCurrentEntityURL();

		// eslint-disable-next-line no-console
		console.log( 'entity URL', url );

		const args = {
			...dates,
			dimensions: [ 'ga:date' ],
			// dimensions: [ 'ga:pagePath' ],
			// dimensions: [ 'ga:hostname' ],
			metrics: [
				{
					expression: 'ga:pageviews',
					alias: 'Pageviews',
				},
				{
					expression: 'ga:uniquePageviews',
					alias: 'Unique Pageviews',
				},
				{
					expression: 'ga:bounceRate',
					alias: 'Bounce Rate',
				},
				{
					expression: 'ga:avgSessionDuration',
					alias: 'Session Duration',
				},
			],
			url,
			// orderby: [
			// 	{
			// 		fieldName: 'ga:pageviews',
			// 		sortOrder: 'DESCENDING',
			// 	},
			// ],
			// limit: 10,
		};

		const report = select( MODULES_ANALYTICS ).getReport( args );

		const error = select(
			MODULES_ANALYTICS
		).getErrorForSelector( 'getReport', [ args ] );

		const isLoading = ! select(
			MODULES_ANALYTICS
		).hasFinishedResolution( 'getReport', [ args ] );

		return {
			report,
			error,
			isLoading,
		};
	} );
}

function DashboardOverallPageMetricsWidget( {
	// Widget,
	WidgetReportZero,
	WidgetReportError,
} ) {
	const isGatheringData = useSelect( ( select ) =>
		select( MODULES_ANALYTICS ).isGatheringData()
	);

	// eslint-disable-next-line no-console
	console.log( 'isGatheringData', isGatheringData );

	const { report, isLoading, error } = useWidgetReport();

	// eslint-disable-next-line no-console
	console.log( 'report, isLoading, error', report, isLoading, error );

	if ( isLoading || isGatheringData === undefined ) {
		return <PreviewBlock width="100%" height="202px" />;
	}

	if ( error ) {
		return <WidgetReportError moduleSlug="analytics" error={ error } />;
	}

	if ( isGatheringData && isZeroReport( report ) ) {
		return <WidgetReportZero moduleSlug="analytics" />;
	}

	const sparkLineData = {
		pageviews: [
			[
				{ type: 'date', label: 'Day' },
				{ type: 'number', label: 'Pageviews' },
			],
		],
		uniquePageviews: [
			[
				{ type: 'date', label: 'Day' },
				{ type: 'number', label: 'Unique Pageviews' },
			],
		],
		bounceRate: [
			[
				{ type: 'date', label: 'Day' },
				{ type: 'number', label: 'Bounce Rate' },
			],
		],
		sessionDuration: [
			[
				{ type: 'date', label: 'Day' },
				{ type: 'number', label: 'Session Duration' },
			],
		],
	};

	const { totals = [], rows = [] } = report?.[ 0 ]?.data || {};

	// // We only want half the date range, having `multiDateRange` in the query doubles the range.
	// for ( let i = Math.ceil( rows.length / 2 ); i < rows.length; i++ ) {
	for ( let i = 0; i < rows.length; i++ ) {
		const { values } = rows[ i ].metrics[ 0 ];
		const dateString = rows[ i ].dimensions[ 0 ];
		const date = parseDimensionStringToDate( dateString );

		Object.values( sparkLineData ).forEach( ( sparkLine, index ) => {
			sparkLine.push( [ date, values[ index ] ] );
		} );
	}

	const lastMonth = totals[ 0 ]?.values || [];
	const previousMonth = totals[ 1 ]?.values || [];

	const totalsData = Object.keys( sparkLineData ).reduce(
		( data, metric, index ) => {
			data[ metric ] = {
				total: lastMonth[ index ] || 0,
				totalChange: calculateChange(
					previousMonth[ index ] || 0,
					lastMonth[ index ] || 0
				),
			};
			return data;
		},
		{}
	);

	// Object.values( sparkLineData ).forEach( ( sparkLine, index ) => {
	// 	const pageviews = lastMonth[ 0 ] || 0;
	// 	const pageviewsChange = calculateChange(
	// 		previousMonth[ 0 ] || 0,
	// 		lastMonth[ 0 ] || 0
	// 	);
	// } );

	const serviceURL = 'http://foo.com';

	// content-drilldown ?
	// trafficsources-overview ?

	return (
		<Grid>
			{ /* TODO: Do we need the title/subtitle? If so, fix CSS classes. */ }
			<Row>
				<Cell className="googlesitekit-widget-area-header" size={ 12 }>

						{ __( 'Overall Page Metrics', 'google-site-kit' ) }

						{ __(
							'Overall page metrics, subtitle.',
							'google-site-kit'
						) }

				</Cell>
			</Row>
			<Row>
				{ /* <Cell lgSize={ 7 } mdSize={ 8 }> */ }
				<Cell size={ 3 }>
					<DataBlock
						// className="overview-goals-completed"
						title={ __( 'Pageviews', 'google-site-kit' ) }
						datapoint={ totalsData.pageviews.total }
						change={ totalsData.pageviews.totalChange }
						changeDataUnit="%"
						source={ {
							name: _x(
								'Analytics',
								'Service name',
								'google-site-kit'
							),
							link: serviceURL,
							external: true,
						} }
						sparkline={
							<Sparkline
								data={ sparkLineData.pageviews }
								change={ totalsData.pageviews.totalChange }
							/>
						}
					/>
				</Cell>
				<Cell size={ 3 }>TODO: UNIQUE PAGEVIEWS</Cell>
				<Cell size={ 3 }>TODO: BOUNCE RATE</Cell>
				<Cell size={ 3 }>TODO: SESSION DURATION</Cell>
			</Row>
		</Grid>
	);
}

export default whenActive( { moduleName: 'analytics' } )(
	DashboardOverallPageMetricsWidget
);
<|endoftext|>


<commit_before>tQuery.registerStatic('createSimpleMaze', function(opts){
	return new tQuery.SimpleMaze(opts);
});

tQuery.registerStatic('SimpleMaze', function(opts){
	// handle parameters
	opts	= tQuery.extend(opts, {
		squareW		: 1,
		squareH		: 1,
		squareD		: 1,
		enableCeiling	: true,
		enableGround	: true
	});

	var mazeMap	= opts.map;
	var mapD	= mazeMap.length;
	var mapW	= mazeMap[0].length;

	// TODO sanitize input
	// - opts.map especially

	this._container	= tQuery.createObject3D();
	var textureUrl	= tQuery.SimpleMaze.baseUrl+"../assets/images/water.jpg";
	// GROUND
	if( opts.enableGround ){
		var material	= new THREE.MeshBasicMaterial({
			color	: 0xFF5588,
			map	: THREE.ImageUtils.loadTexture( textureUrl )
		});
		this._ground	= tQuery.createPlane(material)
			.geometry()
				.rotateX(-Math.PI/2)
				.scaleBy(opts.squareW*mapW, 1, opts.squareD*mapD)
				.computeAll()
				.back()
			.addTo(this._container);
	}

	// ceiling
	if( opts.enableCeiling ){
		var material	= new THREE.MeshBasicMaterial({
			color	: 0x8855FF,
			map	: THREE.ImageUtils.loadTexture( textureUrl )
		});
		this._ceiling	= tQuery.createPlane(material)
			.geometry()
				.rotateX(Math.PI/2)
				.scaleBy(opts.squareW*mapW, 1, opts.squareD*mapD)
				.translateY(opts.squareH)
				.computeAll()
				.back()
			.addTo(this._container)
	}

	// CUBES
	var material	= new THREE.MeshBasicMaterial({
		color	: 0x88FF55,
		map	: THREE.ImageUtils.loadTexture( textureUrl )
	});
	// TODO one should merge all those cubes
	for(var z = 0; z < mapD; z++){
		for(var x = 0; x < mapW; x++){
			var value	= mazeMap[z].charCodeAt(x);
			// keep only walls
			if( value !== '*'.charCodeAt(0) )	continue;
			// TODO
			// - merge all those cubes, no upper/lower face
			tQuery.createCube(material).addTo(this._container)
				.geometry()
					.scaleBy(opts.squareW, opts.squareH, opts.squareD)
					.translateY(opts.squareH/2)
					.computeAll()
					.back()
				.translateX((x-mapW/2 + 0.5) * opts.squareW)
				.translateZ((z-mapD/2 + 0.5) * opts.squareW);
		}
	}
});

tQuery.SimpleMaze.baseUrl	= "../../../plugins/simplemaze/";

tQuery.SimpleMaze.prototype.container	= function(){
	return this._container;
}

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Emulate tQuery.Object3D.addTo
*/
tQuery.SimpleMaze.prototype.addTo	= function(object3D){
	this.container().addTo(object3D);
	return this;
}

/**
 * Emulate tQuery.Object3D.removeFrom
*/
tQuery.SimpleMaze.prototype.removeFrom	= function(object3D){
	this.container().removeFrom(object3D);
	return this;
};
<commit_msg>renamed ground as floor<commit_after>tQuery.registerStatic('createSimpleMaze', function(opts){
	return new tQuery.SimpleMaze(opts);
});

tQuery.registerStatic('SimpleMaze', function(opts){
	// handle parameters
	opts	= tQuery.extend(opts, {
		squareW		: 1,
		squareH		: 1,
		squareD		: 1,
		enableCeiling	: true,
		enableFloor	: true
	});

	var mazeMap	= opts.map;
	var mapD	= mazeMap.length;
	var mapW	= mazeMap[0].length;

	// TODO sanitize input
	// - opts.map especially

	this._container	= tQuery.createObject3D();
	var textureUrl	= tQuery.SimpleMaze.baseUrl+"../assets/images/water.jpg";
	// FLOOR
	if( opts.enableFloor ){
		var material	= new THREE.MeshBasicMaterial({
			color	: 0xFF5588,
			map	: THREE.ImageUtils.loadTexture( textureUrl )
		});
		this._floor	= tQuery.createPlane(material)
			.geometry()
				.rotateX(-Math.PI/2)
				.scaleBy(opts.squareW*mapW, 1, opts.squareD*mapD)
				.computeAll()
				.back()
			.addTo(this._container);
	}

	// ceiling
	if( opts.enableCeiling ){
		var material	= new THREE.MeshBasicMaterial({
			color	: 0x8855FF,
			map	: THREE.ImageUtils.loadTexture( textureUrl )
		});
		this._ceiling	= tQuery.createPlane(material)
			.geometry()
				.rotateX(Math.PI/2)
				.scaleBy(opts.squareW*mapW, 1, opts.squareD*mapD)
				.translateY(opts.squareH)
				.computeAll()
				.back()
			.addTo(this._container)
	}

	// CUBES
	var material	= new THREE.MeshBasicMaterial({
		color	: 0x88FF55,
		map	: THREE.ImageUtils.loadTexture( textureUrl )
	});
	// TODO one should merge all those cubes
	for(var z = 0; z < mapD; z++){
		for(var x = 0; x < mapW; x++){
			var value	= mazeMap[z].charCodeAt(x);
			// keep only walls
			if( value !== '*'.charCodeAt(0) )	continue;
			// TODO
			// - merge all those cubes, no upper/lower face
			tQuery.createCube(material).addTo(this._container)
				.geometry()
					.scaleBy(opts.squareW, opts.squareH, opts.squareD)
					.translateY(opts.squareH/2)
					.computeAll()
					.back()
				.translateX((x-mapW/2 + 0.5) * opts.squareW)
				.translateZ((z-mapD/2 + 0.5) * opts.squareW);
		}
	}
});

tQuery.SimpleMaze.baseUrl	= "../../../plugins/simplemaze/";

tQuery.SimpleMaze.prototype.container	= function(){
	return this._container;
}

//////////////////////////////////////////////////////////////////////////////////
//										//
//////////////////////////////////////////////////////////////////////////////////

/**
 * Emulate tQuery.Object3D.addTo
*/
tQuery.SimpleMaze.prototype.addTo	= function(object3D){
	this.container().addTo(object3D);
	return this;
}

/**
 * Emulate tQuery.Object3D.removeFrom
*/
tQuery.SimpleMaze.prototype.removeFrom	= function(object3D){
	this.container().removeFrom(object3D);
	return this;
};
<|endoftext|>


<commit_before>var OrderModel = require('../models/m_order');

var OrderCollection = Backbone.Collection.extend({
  model: OrderModel,
  url: "/api/users/self/orders"
});

module.exports = OrderCollection;
<commit_msg>Change URL so it matches json-server<commit_after>var OrderModel = require('../models/m_order');

var OrderCollection = Backbone.Collection.extend({
  model: OrderModel,
  url: "/api/orders"
});

module.exports = OrderCollection;
<|endoftext|>


<commit_before>// Karma configuration
// Generated on Thu Aug 11 2016 15:00:14 GMT+0200 (CEST)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine','fixture'],

    // list of files / patterns to load in the browser
    files: [
        {pattern: 'bower_components/crossfilter/crossfilter.js', included: true},
        {pattern: 'bower_components/d3/d3.js', included: true},
        {pattern: 'bower_components/moment/moment.js', included: true},
        {pattern: 'dist/punchcards.js', included: true},
        {pattern: 'test/**/*.unit.js', included: true},
        {pattern: 'test/html/*.fixture.html', included: true},
        {pattern: 'test/json/*.fixture.json', included: true},
        {pattern: 'test/**/*.dom.js', included: true}
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
        '**/*.html': ['html2js'],
        '**/*.json': ['json_fixtures'],
        'dist/punchcards.js': ['coverage']
    },

    // I think this next property is a custom field (not part of the default
    // karma configuration, but it is needed by the json fixtures preprocessor.
    jsonFixturesPreprocessor: {
      variableName: '__json__'
    },

    // This is also a custom property AFAICT.
    coverageReporter: {
      // specify a common output directory
      dir: './sites/coverage',
      reporters: [
        { type: 'json', subdir: '.', file: 'coverage.json' }
      ]
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress', 'coverage'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<commit_msg>moved all fixtures into 1 directory --apparently that's a requirement of karma-fixture<commit_after>// Karma configuration
// Generated on Thu Aug 11 2016 15:00:14 GMT+0200 (CEST)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',

    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine','fixture'],

    // list of files / patterns to load in the browser
    files: [
        {pattern: 'bower_components/crossfilter/crossfilter.js', included: true},
        {pattern: 'bower_components/d3/d3.js', included: true},
        {pattern: 'bower_components/moment/moment.js', included: true},
        {pattern: 'dist/punchcards.js', included: true},
        {pattern: 'test/**/*.unit.js', included: true},
        {pattern: 'test/fixtures/*.fixture.html', included: true},
        {pattern: 'test/fixtures/*.fixture.json', included: true},
        {pattern: 'test/**/*.dom.js', included: true}
    ],

    // list of files to exclude
    exclude: [
    ],

    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
        '**/*.html': ['html2js'],
        '**/*.json': ['json_fixtures'],
        'dist/punchcards.js': ['coverage']
    },

    // I think this next property is a custom field (not part of the default
    // karma configuration, but it is needed by the json fixtures preprocessor.
    jsonFixturesPreprocessor: {
      variableName: '__json__'
    },

    // This is also a custom property AFAICT.
    coverageReporter: {
      // specify a common output directory
      dir: './sites/coverage',
      reporters: [
        { type: 'json', subdir: '.', file: 'coverage.json' }
      ]
    },

    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress', 'coverage'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,

    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true,

    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  })
}
<|endoftext|>


<commit_before>import thinky   from '../thinky';

let type = thinky.type;

let Article = thinky.createModel('Article', {
    id        : type.string().optional(), // Optional => not specified in bodies but generated by RethinkDB
    name      : String,
    stock     : Number,
    alcohol   : type.number().default(0), // Alcohol amount (Alcool unit or just article maximum sells)
    createdAt : type.date().default(new Date()),
    editedAt  : Date,
    isRemoved : type.boolean().default(false),
    // Force Thinky to show thoses additional fields that would be cut by enforce_extra
    categoryId: type.string().optional(),
    pointId   : type.string().optional()
}, {
    enforce_missing: true,
    enforce_extra  : 'remove',
    enforce_type   : 'strict'
});

Article.pre('save', function (next) {
    this.editedAt = new Date();
    next();
});

Article.ensureIndex('name');
Article.ensureIndex('createdAt');
Article.ensureIndex('editedAt');

Article.associate = models => {
    models.Article.belongsTo(models.Category, 'category', 'categoryId', 'id');
    models.Article.belongsTo(models.Point, 'point', 'pointId', 'id');
    // n:n instead of 1:n to allow one set containing multiple times the same article
    models.Article.hasAndBelongsToMany(models.Set, 'sets', 'id', 'id');
    // n:n instead of 1:n to allow one promotion containing multiple times the same article
    models.Article.hasAndBelongsToMany(models.Promotion, 'promotion', 'id', 'id');
    models.Article.hasAndBelongsToMany(models.Purchase, 'purchases', 'id', 'id');
    models.Article.hasAndBelongsToMany(models.Price, 'prices', 'id', 'id');
};

export default Article;
<commit_msg>Point 1:n Article -> Point n:n Articles<commit_after>import thinky   from '../thinky';

let type = thinky.type;

let Article = thinky.createModel('Article', {
    id        : type.string().optional(), // Optional => not specified in bodies but generated by RethinkDB
    name      : String,
    stock     : Number,
    alcohol   : type.number().default(0), // Alcohol amount (Alcool unit or just article maximum sells)
    createdAt : type.date().default(new Date()),
    editedAt  : Date,
    isRemoved : type.boolean().default(false),
    // Force Thinky to show thoses additional fields that would be cut by enforce_extra
    categoryId: type.string().optional(),
    pointId   : type.string().optional()
}, {
    enforce_missing: true,
    enforce_extra  : 'remove',
    enforce_type   : 'strict'
});

Article.pre('save', function (next) {
    this.editedAt = new Date();
    next();
});

Article.ensureIndex('name');
Article.ensureIndex('createdAt');
Article.ensureIndex('editedAt');

Article.associate = models => {
    models.Article.belongsTo(models.Category, 'category', 'categoryId', 'id');
    models.Article.hasAndBelongsToMany(models.Point, 'points', 'id', 'id');
    // n:n instead of 1:n to allow one set containing multiple times the same article
    models.Article.hasAndBelongsToMany(models.Set, 'sets', 'id', 'id');
    // n:n instead of 1:n to allow one promotion containing multiple times the same article
    models.Article.hasAndBelongsToMany(models.Promotion, 'promotion', 'id', 'id');
    models.Article.hasAndBelongsToMany(models.Purchase, 'purchases', 'id', 'id');
    models.Article.hasAndBelongsToMany(models.Price, 'prices', 'id', 'id');
};

export default Article;
<|endoftext|>


<commit_before>/*
 (c) 2013, Vladimir Agafonkin
 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
 https://github.com/mourner/rbush
*/

(function () { 'use strict';

function rbush(maxEntries, format) {

    // allow constructing RBush trees without "new"
    // jshint newcap: false, validthis: true

    if (!(this instanceof rbush)) { return new rbush(maxEntries, format); }

    this._maxEntries = Math.max(4, maxEntries || 9);
    this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));

    this._initFormat(format);

    this.clear();
}

rbush.prototype = {

    search: function (bbox) {

        var node = this.data,
            result = [];

        if (!this._intersects(bbox, node.bbox)) { return result; }

        var nodesToSearch = [],
            i, len, child, childBBox;

        while (node) {
            for (i = 0, len = node.children.length; i < len; i++) {
                child = node.children[i];
                childBBox = node.leaf ? this._toBBox(child) : child.bbox;

                if (this._intersects(bbox, childBBox)) {
                    (node.leaf ? result : nodesToSearch).push(child);
                }
            }

            node = nodesToSearch.pop();
        }

        return result;
    },

    load: function (data) {
        if (!(data && data.length)) { return this; }

        if (data.length < this._minEntries) {
            for (var i = 0, len = data.length; i < len; i++) {
                this.insert(data[i]);
            }
            return this;
        }

        // recursively build the tree with the given data from stratch using OMT algorithm
        var node = this._build(data.slice(), 0);
        this._calcBBoxes(node, true);

        if (!this.data.children.length) {
            // save as is if tree is empty
            this.data = node;

        } else if (this.data.height === node.height) {
            // split root if trees have the same height
            this._splitRoot(this.data, node);

        } else {
            if (this.data.height < node.height) {
                // swap trees if inserted one is bigger
                var tmpNode = this.data;
                this.data = node;
                node = tmpNode;
            }

            // insert the small tree into the large tree at appropriate level
            this._insert(node, this.data.height - node.height - 1, true);
        }

        return this;
    },

    insert: function (item) {
        if (item) {
            this._insert(item, this.data.height - 1);
        }
        return this;
    },

    clear: function () {
        this.data = {
            children: [],
            leaf: true,
            bbox: this._infinite(),
            height: 1
        };
        return this;
    },

    remove: function (item) {
        if (!item) { return this; }

        var node = this.data,
            bbox = this._toBBox(item),
            path = [],
            indexes = [],
            i, parent, index, goingUp;

        // depth-first iterative tree traversal
        while (node || path.length) {

            if (!node) { // go up
                node = path.pop();
                parent = path[path.length - 1];
                i = indexes.pop();
                goingUp = true;
            }

            if (node.leaf) { // check current node
                index = node.children.indexOf(item);

                if (index !== -1) {
                    // item found, remove the item and condense tree upwards
                    node.children.splice(index, 1);
                    path.push(node);
                    this._condense(path);
                    return this;
                }
            }

            if (!goingUp && !node.leaf && this._intersects(bbox, node.bbox)) { // go down
                path.push(node);
                indexes.push(i);
                i = 0;
                parent = node;
                node = node.children[0];

            } else if (parent) { // go right
                i++;
                node = parent.children[i];
                goingUp = false;

            } else { // nothing found
                node = null;
            }
        }

        return this;
    },

    toJSON: function () { return this.data; },

    fromJSON: function (data) {
        this.data = data;
        return this;
    },

    _build: function (items, level, height) {

        var N = items.length,
            M = this._maxEntries;

        if (N <= M) {
            return {
                children: items,
                leaf: true,
                height: 1
            };
        }

        if (!level) {
            // target height of the bulk-loaded tree
            height = Math.ceil(Math.log(N) / Math.log(M));

            // target number of root entries to maximize storage utilization
            M = Math.ceil(N / Math.pow(M, height - 1));

            items.sort(this._compareMinX);
        }

        // TODO eliminate recursion?

        var node = {
            children: [],
            height: height
        };

        var N1 = Math.ceil(N / M) * Math.ceil(Math.sqrt(M)),
            N2 = Math.ceil(N / M),
            compare = level % 2 === 1 ? this._compareMinX : this._compareMinY,
            i, j, slice, sliceLen, childNode;

        // split the items into M mostly square tiles
        for (i = 0; i < N; i += N1) {
            slice = items.slice(i, i + N1).sort(compare);

            for (j = 0, sliceLen = slice.length; j < sliceLen; j += N2) {
                // pack each entry recursively
                childNode = this._build(slice.slice(j, j + N2), level + 1, height - 1);
                node.children.push(childNode);
            }
        }

        return node;
    },

    _chooseSubtree: function (bbox, node, level, path) {

        var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;

        while (true) {
            path.push(node);

            if (node.leaf || path.length - 1 === level) { break; }

            minArea = minEnlargement = Infinity;

            for (i = 0, len = node.children.length; i < len; i++) {
                child = node.children[i];
                area = this._area(child.bbox);
                enlargement = this._enlargedArea(bbox, child.bbox) - area;

                // choose entry with the least area enlargement
                if (enlargement < minEnlargement) {
                    minEnlargement = enlargement;
                    minArea = area < minArea ? area : minArea;
                    targetNode = child;

                } else if (enlargement === minEnlargement) {
                    // otherwise choose one with the smallest area
                    if (area < minArea) {
                        minArea = area;
                        targetNode = child;
                    }
                }
            }

            node = targetNode;
        }

        return node;
    },

    _insert: function (item, level, isNode, root) {

        var bbox = isNode ? item.bbox : this._toBBox(item),
            insertPath = [];

        // find the best node for accommodating the item, saving all nodes along the path too
        var node = this._chooseSubtree(bbox, root || this.data, level, insertPath),
            splitOccured;

        // put the item into the node
        node.children.push(item);
        this._extend(node.bbox, bbox);

        // split on node overflow; propagate upwards if necessary
        do {
            splitOccured = false;
            if (insertPath[level].children.length > this._maxEntries) {
                this._split(insertPath, level);
                splitOccured = true;
                level--;
            }
        } while (level >= 0 && splitOccured);

        // adjust bboxes along the insertion path
        this._adjustParentBBoxes(bbox, insertPath, level);
    },

    // split overflowed node into two
    _split: function (insertPath, level) {

        var node = insertPath[level],
            M = node.children.length,
            m = this._minEntries;

        this._chooseSplitAxis(node, m, M);

        var newNode = {
            children: node.children.splice(this._chooseSplitIndex(node, m, M)),
            height: node.height
        };

        if (node.leaf) {
            newNode.leaf = true;
        }

        this._calcBBoxes(node);
        this._calcBBoxes(newNode);

        if (level) {
            insertPath[level - 1].children.push(newNode);
        } else {
            this._splitRoot(node, newNode);
        }
    },

    _splitRoot: function (node, newNode) {
        // split root node
        this.data = {};
        this.data.children = [node, newNode];
        this.data.height = node.height + 1;
        this._calcBBoxes(this.data);
    },

    _chooseSplitIndex: function (node, m, M) {

        var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;

        minOverlap = minArea = Infinity;

        for (i = m; i <= M - m; i++) {
            bbox1 = this._distBBox(node, 0, i);
            bbox2 = this._distBBox(node, i, M);

            overlap = this._intersectionArea(bbox1, bbox2);
            area = this._area(bbox1) + this._area(bbox2);

            // choose distribution with minimum overlap
            if (overlap < minOverlap) {
                minOverlap = overlap;
                index = i;

                minArea = area < minArea ? area : minArea;

            } else if (overlap === minOverlap) {
                // otherwise choose distribution with minimum area
                if (area < minArea) {
                    minArea = area;
                    index = i;
                }
            }
        }

        return index;
    },

    // sorts node children by the best axis for split
    _chooseSplitAxis: function (node, m, M) {

        var compareMinX = node.leaf ? this._compareMinX : this._compareNodeMinX,
            compareMinY = node.leaf ? this._compareMinY : this._compareNodeMinY,
            xMargin = this._allDistMargin(node, m, M, compareMinX),
            yMargin = this._allDistMargin(node, m, M, compareMinY);

        // if total distributions margin value is minimal for x, sort by minX,
        // otherwise it's already sorted by minY

        if (xMargin < yMargin) {
            node.children.sort(compareMinX);
        }
    },

    // total margin of all possible split distributions where each node is at least m full
    _allDistMargin: function (node, m, M, compare) {

        node.children.sort(compare);

        var leftBBox = this._distBBox(node, 0, m),
            rightBBox = this._distBBox(node, M - m, M),
            margin = this._margin(leftBBox) + this._margin(rightBBox),
            i, child;

        for (i = m; i < M - m; i++) {
            child = node.children[i];
            this._extend(leftBBox, node.leaf ? this._toBBox(child) : child.bbox);
            margin += this._margin(leftBBox);
        }

        for (i = M - m - 1; i >= 0; i--) {
            child = node.children[i];
            this._extend(rightBBox, node.leaf ? this._toBBox(child) : child.bbox);
            margin += this._margin(rightBBox);
        }

        return margin;
    },

    // min bounding rectangle of node children from k to p-1
    _distBBox: function (node, k, p) {
        var bbox = this._infinite();

        for (var i = k, child; i < p; i++) {
            child = node.children[i];
            this._extend(bbox, node.leaf ? this._toBBox(child) : child.bbox);
        }

        return bbox;
    },

    _calcBBoxes: function (node, recursive) {
        // TODO eliminate recursion
        node.bbox = this._infinite();

        for (var i = 0, len = node.children.length, child; i < len; i++) {
            child = node.children[i];

            if (node.leaf) {
                this._extend(node.bbox, this._toBBox(child));
            } else {
                if (recursive) {
                    this._calcBBoxes(child, recursive);
                }
                this._extend(node.bbox, child.bbox);
            }
        }
    },

    _adjustParentBBoxes: function (bbox, path, level) {
        // adjust bboxes along the given tree path
        for (var i = level; i >= 0; i--) {
            this._extend(path[i].bbox, bbox);
        }
    },

    _condense: function (path) {
        // go through the path, removing empty nodes and updating bboxes
        for (var i = path.length - 1, parent; i >= 0; i--) {
            if (i > 0 && path[i].children.length === 0) {
                parent = path[i - 1].children;
                parent.splice(parent.indexOf(path[i]), 1);
            } else {
                this._calcBBoxes(path[i]);
            }
        }
    },

    _intersects: function (a, b) {
        return b[0] <= a[2] &&
               b[1] <= a[3] &&
               b[2] >= a[0] &&
               b[3] >= a[1];
    },

    _extend: function (a, b) {
        a[0] = Math.min(a[0], b[0]);
        a[1] = Math.min(a[1], b[1]);
        a[2] = Math.max(a[2], b[2]);
        a[3] = Math.max(a[3], b[3]);
        return a;
    },

    _area:   function (a) { return (a[2] - a[0]) * (a[3] - a[1]); },
    _margin: function (a) { return (a[2] - a[0]) + (a[3] - a[1]); },

    _enlargedArea: function (a, b) {
        return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) *
               (Math.max(b[3], a[3]) - Math.min(b[1], a[1]));
    },

    _intersectionArea: function (a, b) {
        var minX = Math.max(a[0], b[0]),
            minY = Math.max(a[1], b[1]),
            maxX = Math.min(a[2], b[2]),
            maxY = Math.min(a[3], b[3]);

        return Math.max(0, maxX - minX) *
               Math.max(0, maxY - minY);
    },

    _infinite: function () { return [Infinity, Infinity, -Infinity, -Infinity]; },

    _compareNodeMinX: function (a, b) { return a.bbox[0] - b.bbox[0]; },
    _compareNodeMinY: function (a, b) { return a.bbox[1] - b.bbox[1]; },

    _initFormat: function (format) {
        // data format (minX, minY, maxX, maxY accessors)
        format = format || ['[0]', '[1]', '[2]', '[3]'];

        // uses eval-type function compilation instead of just accepting a toBBox function
        // because the algorithms are very sensitive to sorting functions performance,
        // so they should be dead simple and without inner calls

        // jshint evil: true

        var compareArr = ['return a', ' - b', ';'];

        this._compareMinX = new Function('a', 'b', compareArr.join(format[0]));
        this._compareMinY = new Function('a', 'b', compareArr.join(format[1]));

        this._toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
    }
};

if (typeof module !== 'undefined') {
    module.exports = rbush;
} else {
    window.rbush = rbush;
}

})();
<commit_msg>remove unnecessary comment<commit_after>/*
 (c) 2013, Vladimir Agafonkin
 RBush, a JavaScript library for high-performance 2D spatial indexing of points and rectangles.
 https://github.com/mourner/rbush
*/

(function () { 'use strict';

function rbush(maxEntries, format) {

    // jshint newcap: false, validthis: true
    if (!(this instanceof rbush)) { return new rbush(maxEntries, format); }

    this._maxEntries = Math.max(4, maxEntries || 9);
    this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));

    this._initFormat(format);

    this.clear();
}

rbush.prototype = {

    search: function (bbox) {

        var node = this.data,
            result = [];

        if (!this._intersects(bbox, node.bbox)) { return result; }

        var nodesToSearch = [],
            i, len, child, childBBox;

        while (node) {
            for (i = 0, len = node.children.length; i < len; i++) {
                child = node.children[i];
                childBBox = node.leaf ? this._toBBox(child) : child.bbox;

                if (this._intersects(bbox, childBBox)) {
                    (node.leaf ? result : nodesToSearch).push(child);
                }
            }

            node = nodesToSearch.pop();
        }

        return result;
    },

    load: function (data) {
        if (!(data && data.length)) { return this; }

        if (data.length < this._minEntries) {
            for (var i = 0, len = data.length; i < len; i++) {
                this.insert(data[i]);
            }
            return this;
        }

        // recursively build the tree with the given data from stratch using OMT algorithm
        var node = this._build(data.slice(), 0);
        this._calcBBoxes(node, true);

        if (!this.data.children.length) {
            // save as is if tree is empty
            this.data = node;

        } else if (this.data.height === node.height) {
            // split root if trees have the same height
            this._splitRoot(this.data, node);

        } else {
            if (this.data.height < node.height) {
                // swap trees if inserted one is bigger
                var tmpNode = this.data;
                this.data = node;
                node = tmpNode;
            }

            // insert the small tree into the large tree at appropriate level
            this._insert(node, this.data.height - node.height - 1, true);
        }

        return this;
    },

    insert: function (item) {
        if (item) {
            this._insert(item, this.data.height - 1);
        }
        return this;
    },

    clear: function () {
        this.data = {
            children: [],
            leaf: true,
            bbox: this._infinite(),
            height: 1
        };
        return this;
    },

    remove: function (item) {
        if (!item) { return this; }

        var node = this.data,
            bbox = this._toBBox(item),
            path = [],
            indexes = [],
            i, parent, index, goingUp;

        // depth-first iterative tree traversal
        while (node || path.length) {

            if (!node) { // go up
                node = path.pop();
                parent = path[path.length - 1];
                i = indexes.pop();
                goingUp = true;
            }

            if (node.leaf) { // check current node
                index = node.children.indexOf(item);

                if (index !== -1) {
                    // item found, remove the item and condense tree upwards
                    node.children.splice(index, 1);
                    path.push(node);
                    this._condense(path);
                    return this;
                }
            }

            if (!goingUp && !node.leaf && this._intersects(bbox, node.bbox)) { // go down
                path.push(node);
                indexes.push(i);
                i = 0;
                parent = node;
                node = node.children[0];

            } else if (parent) { // go right
                i++;
                node = parent.children[i];
                goingUp = false;

            } else { // nothing found
                node = null;
            }
        }

        return this;
    },

    toJSON: function () { return this.data; },

    fromJSON: function (data) {
        this.data = data;
        return this;
    },

    _build: function (items, level, height) {

        var N = items.length,
            M = this._maxEntries;

        if (N <= M) {
            return {
                children: items,
                leaf: true,
                height: 1
            };
        }

        if (!level) {
            // target height of the bulk-loaded tree
            height = Math.ceil(Math.log(N) / Math.log(M));

            // target number of root entries to maximize storage utilization
            M = Math.ceil(N / Math.pow(M, height - 1));

            items.sort(this._compareMinX);
        }

        // TODO eliminate recursion?

        var node = {
            children: [],
            height: height
        };

        var N1 = Math.ceil(N / M) * Math.ceil(Math.sqrt(M)),
            N2 = Math.ceil(N / M),
            compare = level % 2 === 1 ? this._compareMinX : this._compareMinY,
            i, j, slice, sliceLen, childNode;

        // split the items into M mostly square tiles
        for (i = 0; i < N; i += N1) {
            slice = items.slice(i, i + N1).sort(compare);

            for (j = 0, sliceLen = slice.length; j < sliceLen; j += N2) {
                // pack each entry recursively
                childNode = this._build(slice.slice(j, j + N2), level + 1, height - 1);
                node.children.push(childNode);
            }
        }

        return node;
    },

    _chooseSubtree: function (bbox, node, level, path) {

        var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;

        while (true) {
            path.push(node);

            if (node.leaf || path.length - 1 === level) { break; }

            minArea = minEnlargement = Infinity;

            for (i = 0, len = node.children.length; i < len; i++) {
                child = node.children[i];
                area = this._area(child.bbox);
                enlargement = this._enlargedArea(bbox, child.bbox) - area;

                // choose entry with the least area enlargement
                if (enlargement < minEnlargement) {
                    minEnlargement = enlargement;
                    minArea = area < minArea ? area : minArea;
                    targetNode = child;

                } else if (enlargement === minEnlargement) {
                    // otherwise choose one with the smallest area
                    if (area < minArea) {
                        minArea = area;
                        targetNode = child;
                    }
                }
            }

            node = targetNode;
        }

        return node;
    },

    _insert: function (item, level, isNode, root) {

        var bbox = isNode ? item.bbox : this._toBBox(item),
            insertPath = [];

        // find the best node for accommodating the item, saving all nodes along the path too
        var node = this._chooseSubtree(bbox, root || this.data, level, insertPath),
            splitOccured;

        // put the item into the node
        node.children.push(item);
        this._extend(node.bbox, bbox);

        // split on node overflow; propagate upwards if necessary
        do {
            splitOccured = false;
            if (insertPath[level].children.length > this._maxEntries) {
                this._split(insertPath, level);
                splitOccured = true;
                level--;
            }
        } while (level >= 0 && splitOccured);

        // adjust bboxes along the insertion path
        this._adjustParentBBoxes(bbox, insertPath, level);
    },

    // split overflowed node into two
    _split: function (insertPath, level) {

        var node = insertPath[level],
            M = node.children.length,
            m = this._minEntries;

        this._chooseSplitAxis(node, m, M);

        var newNode = {
            children: node.children.splice(this._chooseSplitIndex(node, m, M)),
            height: node.height
        };

        if (node.leaf) {
            newNode.leaf = true;
        }

        this._calcBBoxes(node);
        this._calcBBoxes(newNode);

        if (level) {
            insertPath[level - 1].children.push(newNode);
        } else {
            this._splitRoot(node, newNode);
        }
    },

    _splitRoot: function (node, newNode) {
        // split root node
        this.data = {};
        this.data.children = [node, newNode];
        this.data.height = node.height + 1;
        this._calcBBoxes(this.data);
    },

    _chooseSplitIndex: function (node, m, M) {

        var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;

        minOverlap = minArea = Infinity;

        for (i = m; i <= M - m; i++) {
            bbox1 = this._distBBox(node, 0, i);
            bbox2 = this._distBBox(node, i, M);

            overlap = this._intersectionArea(bbox1, bbox2);
            area = this._area(bbox1) + this._area(bbox2);

            // choose distribution with minimum overlap
            if (overlap < minOverlap) {
                minOverlap = overlap;
                index = i;

                minArea = area < minArea ? area : minArea;

            } else if (overlap === minOverlap) {
                // otherwise choose distribution with minimum area
                if (area < minArea) {
                    minArea = area;
                    index = i;
                }
            }
        }

        return index;
    },

    // sorts node children by the best axis for split
    _chooseSplitAxis: function (node, m, M) {

        var compareMinX = node.leaf ? this._compareMinX : this._compareNodeMinX,
            compareMinY = node.leaf ? this._compareMinY : this._compareNodeMinY,
            xMargin = this._allDistMargin(node, m, M, compareMinX),
            yMargin = this._allDistMargin(node, m, M, compareMinY);

        // if total distributions margin value is minimal for x, sort by minX,
        // otherwise it's already sorted by minY

        if (xMargin < yMargin) {
            node.children.sort(compareMinX);
        }
    },

    // total margin of all possible split distributions where each node is at least m full
    _allDistMargin: function (node, m, M, compare) {

        node.children.sort(compare);

        var leftBBox = this._distBBox(node, 0, m),
            rightBBox = this._distBBox(node, M - m, M),
            margin = this._margin(leftBBox) + this._margin(rightBBox),
            i, child;

        for (i = m; i < M - m; i++) {
            child = node.children[i];
            this._extend(leftBBox, node.leaf ? this._toBBox(child) : child.bbox);
            margin += this._margin(leftBBox);
        }

        for (i = M - m - 1; i >= 0; i--) {
            child = node.children[i];
            this._extend(rightBBox, node.leaf ? this._toBBox(child) : child.bbox);
            margin += this._margin(rightBBox);
        }

        return margin;
    },

    // min bounding rectangle of node children from k to p-1
    _distBBox: function (node, k, p) {
        var bbox = this._infinite();

        for (var i = k, child; i < p; i++) {
            child = node.children[i];
            this._extend(bbox, node.leaf ? this._toBBox(child) : child.bbox);
        }

        return bbox;
    },

    _calcBBoxes: function (node, recursive) {
        // TODO eliminate recursion
        node.bbox = this._infinite();

        for (var i = 0, len = node.children.length, child; i < len; i++) {
            child = node.children[i];

            if (node.leaf) {
                this._extend(node.bbox, this._toBBox(child));
            } else {
                if (recursive) {
                    this._calcBBoxes(child, recursive);
                }
                this._extend(node.bbox, child.bbox);
            }
        }
    },

    _adjustParentBBoxes: function (bbox, path, level) {
        // adjust bboxes along the given tree path
        for (var i = level; i >= 0; i--) {
            this._extend(path[i].bbox, bbox);
        }
    },

    _condense: function (path) {
        // go through the path, removing empty nodes and updating bboxes
        for (var i = path.length - 1, parent; i >= 0; i--) {
            if (i > 0 && path[i].children.length === 0) {
                parent = path[i - 1].children;
                parent.splice(parent.indexOf(path[i]), 1);
            } else {
                this._calcBBoxes(path[i]);
            }
        }
    },

    _intersects: function (a, b) {
        return b[0] <= a[2] &&
               b[1] <= a[3] &&
               b[2] >= a[0] &&
               b[3] >= a[1];
    },

    _extend: function (a, b) {
        a[0] = Math.min(a[0], b[0]);
        a[1] = Math.min(a[1], b[1]);
        a[2] = Math.max(a[2], b[2]);
        a[3] = Math.max(a[3], b[3]);
        return a;
    },

    _area:   function (a) { return (a[2] - a[0]) * (a[3] - a[1]); },
    _margin: function (a) { return (a[2] - a[0]) + (a[3] - a[1]); },

    _enlargedArea: function (a, b) {
        return (Math.max(b[2], a[2]) - Math.min(b[0], a[0])) *
               (Math.max(b[3], a[3]) - Math.min(b[1], a[1]));
    },

    _intersectionArea: function (a, b) {
        var minX = Math.max(a[0], b[0]),
            minY = Math.max(a[1], b[1]),
            maxX = Math.min(a[2], b[2]),
            maxY = Math.min(a[3], b[3]);

        return Math.max(0, maxX - minX) *
               Math.max(0, maxY - minY);
    },

    _infinite: function () { return [Infinity, Infinity, -Infinity, -Infinity]; },

    _compareNodeMinX: function (a, b) { return a.bbox[0] - b.bbox[0]; },
    _compareNodeMinY: function (a, b) { return a.bbox[1] - b.bbox[1]; },

    _initFormat: function (format) {
        // data format (minX, minY, maxX, maxY accessors)
        format = format || ['[0]', '[1]', '[2]', '[3]'];

        // uses eval-type function compilation instead of just accepting a toBBox function
        // because the algorithms are very sensitive to sorting functions performance,
        // so they should be dead simple and without inner calls

        // jshint evil: true

        var compareArr = ['return a', ' - b', ';'];

        this._compareMinX = new Function('a', 'b', compareArr.join(format[0]));
        this._compareMinY = new Function('a', 'b', compareArr.join(format[1]));

        this._toBBox = new Function('a', 'return [a' + format.join(', a') + '];');
    }
};

if (typeof module !== 'undefined') {
    module.exports = rbush;
} else {
    window.rbush = rbush;
}

})();
<|endoftext|>


<commit_before>winstonApp.directive('facebook', ['$http', function($http) {
		return {
			scope: {
				shares: '='
			},
			transclude: true,
			template: '
' +
				'
' +
				'
' +
				'
' +
				'<button type="button">' +
				'' +
				'</button>' +
				'
' +
				'Share' +
				'
' +
				'
' +
				'
' +
				'
' +
				'
' +
				'' +
				'
' +
				'
<s></s>
' +
				'
',
			link: function(scope, element, attr) {
				attr.$observe('url', function() {
					if (attr.shares && attr.url) {
						$http.get('https://api.facebook.com/method/links.getStats?urls=' + attr.url + '&format=json').success(function(res) {
							var count = res[0] ? res[0].total_count.toString() : 0;
							var decimal = '';
							if (count.length > 6) {
								if (count.slice(-6, -5) != "0") {
									decimal = '.' + count.slice(-6, -5);
								}
								count = count.slice(0, -6);
								count = count + decimal + 'M';
							} else if (count.length > 3) {
								if (count.slice(-3, -2) != "0") {
									decimal = '.' + count.slice(-3, -2);
								}
								count = count.slice(0, -3);
								count = count + decimal + 'k';
							}
							scope.shares = count;
						}).error(function() {
							scope.shares = 0;
						});
					}
					element.unbind();
					element.bind('click', function(e) {
						FB.ui({
							method: 'share',
							href: attr.url
						});
						e.preventDefault();
					});
				});
			}
		};
	}]);

<commit_msg>fix: remove the evil redefined fbDirective<commit_after><|endoftext|>


<commit_before>module.exports = function(config) {
    config.set({
        logLevel: 'LOG_DEBUG',

        reporters: ['spec'],

        singleRun : true,
        autoWatch : false,

        frameworks: [
            'mocha',
            'browserify'
        ],

        files: [
            'test/*.js'
        ],

        preprocessors: {
            'test/*.js': ['browserify']
        },

        browserify: {
            debug: true
        }
    });
};
<commit_msg>Only including spec files for now<commit_after>module.exports = function(config) {
    config.set({
        logLevel: 'LOG_DEBUG',

        reporters: ['spec'],

        singleRun : true,
        autoWatch : false,

        frameworks: [
            'mocha',
            'browserify'
        ],

        files: [
            'test/*.spec.js'
        ],

        preprocessors: {
            'test/*.spec.js': ['browserify']
        },

        browserify: {
            debug: true
        }
    });
};
<|endoftext|>


<commit_before>/* eslint-env node */
'use strict';

module.exports = function(environment) {
  let ENV = {
    modulePrefix: 'ember-loopback-customers-demo',
    environment,
    rootURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      },
      EXTEND_PROTOTYPES: {
        // Prevent Ember Data from overriding Date.parse.
        Date: false
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};
<commit_msg>chore(config): exclude prototype extensions<commit_after>/* eslint-env node */
'use strict';

module.exports = function(environment) {
  let ENV = {
    modulePrefix: 'ember-loopback-customers-demo',
    environment,
    rootURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      },
      EXTEND_PROTOTYPES: false
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Text,
  Button,
  TouchableOpacity,
  Easing,
  Animated,
  Image,
  Vibration,
  Alert
} from 'react-native';
import * as Colors from './Colors';
import { BakinBaconApi } from './BakinBaconApi';
import { BaconOptimizer, StaticOptimizer } from './BaconOptimizer';
import { PushService } from './push/PushService';
import { Notifications } from 'expo';

const defaultDuration = 10;

var StateVars = { duration: defaultDuration };

export class BaconTimerScreen extends Component {
    static navigationOptions = {
        title: "Bakin' Bacon Timer",
        tabBarLabel: 'Timer',
        headerStyle: {backgroundColor: Colors.primary },
        headerTitleStyle: { color: Colors.titleColor },
        headerLeft: null
    };

    componentWillMount() {
      PushService.Register();

      // Handle notifications that are received or selected while the app
      // is open. If the app was closed and then opened by tapping the
      // notification (rather than just tapping the app icon to open it),
      // this function will fire on the next tick after the app starts
      // with the notification data.
      this._notificationSubscription = Notifications.addListener(() => this.props.navigation.navigate('Feedback'));
    }

    constructor(props) {
      super(props);
      this.baconOptimizer = new StaticOptimizer(10);
      //this.baconOptimizer = new BaconOptimizer();
      this.state = {
        timeleft: StateVars.duration,
        timer: null,
        running: false
      };
      this.spinValue = new Animated.Value(0);
      this.api = new BakinBaconApi();
      this.api.getBaconBits(this.handleBaconBits.bind(this));
    }

    render() {
        const onPressControl = this.onPressControl.bind(this);
        return (
            <View style={styles.container}>
                <Text style={styles.timerText}>{this.timeLeft()}</Text>
                <Image
                    style={ this.getPigImageRotationStyle() }
                    source={require('./images/pig.png')}
                />
                <TouchableOpacity
                    style={ styles.controlContainer }
                    onPress={onPressControl}
                    >
                    {this.controlImage()}
                </TouchableOpacity>
            </View>
        );
    }

    handleBaconBits(bacon_bits) {
      let duration = this.baconOptimizer.optimize(bacon_bits);
      StateVars.duration = duration;
      this.setState({timeleft: duration});
    }

    getPigImageRotationStyle(){
        var rotation = this.degreeRotation();
        return {
            height:156,
            width: 156,
            transform: [{ rotate: rotation}]
        };
     }

    alertUser() {
        Vibration.vibrate([0, 200, 400, 600, 0, 100, 300, 500, 0, 200, 400, 500, 0, 100, 300, 500, 0, 200, 400, 600]);
        Alert.alert('Finished',
            'Go eat your perfect bacon.',
            [
                {text: 'OK', onPress: () => {
                    Vibration.cancel();
                }}
            ],
            { cancelable: false }
        )
    }

    setTimer() {
        if( this.state.running) {
            this._interval = setInterval(() => {
                if(this.state.timeleft > 0 ) {
                    this.setState({timeleft: this.state.timeleft - 1});
                }
                else
                {
                    clearInterval(this._interval);
                    this.alertUser();
                    this.api.postBaconMade(() => {console.log('we made bacon!')});
                }
            }, 1000);
        } else {
            clearInterval(this._interval);
            this.setState({timeleft: StateVars.duration});
        }
    }

    async toggleRunning() {
        await this.setState({running: !this.state.running});
        this.setTimer();
    }

    onPressControl() {
        this.toggleRunning();
    }

    timeLeft() {
        var minutes = Math.floor(this.state.timeleft / 60);
        var seconds = this.state.timeleft % 60;
        return (minutes == 0 ? "0" : minutes) + ":" + (seconds == 0 ? "00" : (seconds < 10) ? "0" + seconds : seconds);
    }

    degreeRotation() {
        var rotation = 180 * ((StateVars.duration - this.state.timeleft) / StateVars.duration);
        return rotation + "deg";
    }

    controlImage() {
        if (this.state.running) {
            return (
                    <Image
                        style={ styles.controlImage }
                        source={require('./images/bacon_reset.png')}
                    />
                )
        }
        return (
            <Image
                    style={ styles.controlImage }
                    source={require('./images/bacon_play.png')}
                />
            )
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: Colors.backgroundColor,
    alignItems: 'center'
  },
  timerText: {
      fontSize: 72,
      textAlign: 'center',
      margin: 10,
      marginBottom: 20,
      marginTop: 30,
  },
  button: {
      height: 60,
      justifyContent: 'center',
      alignItems: 'center',
  },
  imageContainer: {
    height:156,
    width: 156,
    borderRadius: 64,
  },
  pig: {
    height:156,
    width: 156
  },
  controlContainer: {
    height:96,
    width: 96,
    borderRadius: 48,
    marginTop: 40,
  },
  controlImage: {
    height:96,
    width: 96,
    borderRadius: 48
  },
});

exports.StateVars = StateVars;
<commit_msg>use actual bacon optimizer<commit_after>import React, { Component } from 'react';
import {
  StyleSheet,
  View,
  Text,
  Button,
  TouchableOpacity,
  Easing,
  Animated,
  Image,
  Vibration,
  Alert
} from 'react-native';
import * as Colors from './Colors';
import { BakinBaconApi } from './BakinBaconApi';
import { BaconOptimizer, StaticOptimizer } from './BaconOptimizer';
import { PushService } from './push/PushService';
import { Notifications } from 'expo';

const defaultDuration = 10;

var StateVars = { duration: defaultDuration };

export class BaconTimerScreen extends Component {
    static navigationOptions = {
        title: "Bakin' Bacon Timer",
        tabBarLabel: 'Timer',
        headerStyle: {backgroundColor: Colors.primary },
        headerTitleStyle: { color: Colors.titleColor },
        headerLeft: null
    };

    componentWillMount() {
      PushService.Register();

      // Handle notifications that are received or selected while the app
      // is open. If the app was closed and then opened by tapping the
      // notification (rather than just tapping the app icon to open it),
      // this function will fire on the next tick after the app starts
      // with the notification data.
      this._notificationSubscription = Notifications.addListener(() => this.props.navigation.navigate('Feedback'));
    }

    constructor(props) {
      super(props);
      //this.baconOptimizer = new StaticOptimizer(10);
      this.baconOptimizer = new BaconOptimizer();
      this.state = {
        timeleft: StateVars.duration,
        timer: null,
        running: false
      };
      this.spinValue = new Animated.Value(0);
      this.api = new BakinBaconApi();
      this.api.getBaconBits(this.handleBaconBits.bind(this));
    }

    render() {
        const onPressControl = this.onPressControl.bind(this);
        return (
            <View style={styles.container}>
                <Text style={styles.timerText}>{this.timeLeft()}</Text>
                <Image
                    style={ this.getPigImageRotationStyle() }
                    source={require('./images/pig.png')}
                />
                <TouchableOpacity
                    style={ styles.controlContainer }
                    onPress={onPressControl}
                    >
                    {this.controlImage()}
                </TouchableOpacity>
            </View>
        );
    }

    handleBaconBits(bacon_bits) {
      let duration = this.baconOptimizer.optimize(bacon_bits);
      StateVars.duration = duration;
      this.setState({timeleft: duration});
    }

    getPigImageRotationStyle(){
        var rotation = this.degreeRotation();
        return {
            height:156,
            width: 156,
            transform: [{ rotate: rotation}]
        };
     }

    alertUser() {
        Vibration.vibrate([0, 200, 400, 600, 0, 100, 300, 500, 0, 200, 400, 500, 0, 100, 300, 500, 0, 200, 400, 600]);
        Alert.alert('Finished',
            'Go eat your perfect bacon.',
            [
                {text: 'OK', onPress: () => {
                    Vibration.cancel();
                }}
            ],
            { cancelable: false }
        )
    }

    setTimer() {
        if( this.state.running) {
            this._interval = setInterval(() => {
                if(this.state.timeleft > 0 ) {
                    this.setState({timeleft: this.state.timeleft - 1});
                }
                else
                {
                    clearInterval(this._interval);
                    this.alertUser();
                    this.api.postBaconMade(() => {console.log('we made bacon!')});
                }
            }, 1000);
        } else {
            clearInterval(this._interval);
            this.setState({timeleft: StateVars.duration});
        }
    }

    async toggleRunning() {
        await this.setState({running: !this.state.running});
        this.setTimer();
    }

    onPressControl() {
        this.toggleRunning();
    }

    timeLeft() {
        var minutes = Math.floor(this.state.timeleft / 60);
        var seconds = this.state.timeleft % 60;
        return (minutes == 0 ? "0" : minutes) + ":" + (seconds == 0 ? "00" : (seconds < 10) ? "0" + seconds : seconds);
    }

    degreeRotation() {
        var rotation = 180 * ((StateVars.duration - this.state.timeleft) / StateVars.duration);
        return rotation + "deg";
    }

    controlImage() {
        if (this.state.running) {
            return (
                    <Image
                        style={ styles.controlImage }
                        source={require('./images/bacon_reset.png')}
                    />
                )
        }
        return (
            <Image
                    style={ styles.controlImage }
                    source={require('./images/bacon_play.png')}
                />
            )
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: Colors.backgroundColor,
    alignItems: 'center'
  },
  timerText: {
      fontSize: 72,
      textAlign: 'center',
      margin: 10,
      marginBottom: 20,
      marginTop: 30,
  },
  button: {
      height: 60,
      justifyContent: 'center',
      alignItems: 'center',
  },
  imageContainer: {
    height:156,
    width: 156,
    borderRadius: 64,
  },
  pig: {
    height:156,
    width: 156
  },
  controlContainer: {
    height:96,
    width: 96,
    borderRadius: 48,
    marginTop: 40,
  },
  controlImage: {
    height:96,
    width: 96,
    borderRadius: 48
  },
});

exports.StateVars = StateVars;
<|endoftext|>


<commit_before>kernel.module.manager = def(
  [
    kernel.fp.array,
    kernel.fp.object,
    kernel.module.loader,
    kernel.module.fetcher
  ],

  function (ar, obj, loader, fetcher) {
    var create = function (modulator, onerror) {
      var blueprints = {};  // id -> {id: string, dependencies: [string], definition: function}
      var modules = {};     // id -> module
      var fetcherer = fetcher.create(modulator, function (id) {
        return blueprints[id] !== undefined;
      });

      var define = function (id, dependencies, definition) {
        if (blueprints[id] !== undefined)
          onerror("Define error: module '" + id + "' is already defined");
        else
          blueprints[id] = {
            id: id,
            dependencies: dependencies,
            definition: definition
          };
      };

      var require = function (ids, callback) {
        var onsuccess = function () {
          var instances = ar.map(ids, demand);
          callback.apply(null, instances);
        };

        var oncontinue = function () {
          var deps = obj.map(blueprints, function (k, v) {
            return v.dependencies;
          });
          loader.load(deps, fetcherer, oncontinue, onsuccess, onerror);
        };

        oncontinue();
      };

      // Instantiates a module and all of its dependencies.
      var demand = function (id) {
        if (modules[id] !== undefined)
          return modules[id];
        if (blueprints[id] === undefined)
          throw "module '" + id + "' is not defined";
        var blueprint = blueprints[id];
        var args = ar.map(blueprint.dependencies, demand);  // Instantiate dependencies
        var result = blueprint.definition.apply(null, args);  // Instantiate self
        modules[id] = result;
        return result;
      };

      return {
        define: define,
        require: require,
        demand: demand
      };
    };

    return {
      create: create
    };
  }
);
<commit_msg>Hook up manager to new analyser API.<commit_after>kernel.module.manager = def(
  [
    kernel.fp.array,
    kernel.fp.object,
    kernel.module.loader,
    kernel.module.fetcher
  ],

  function (ar, obj, loader, fetcher) {
    var create = function (modulator, onerror) {
      var blueprints = {};  // id -> {id: string, dependencies: [string], definition: function}
      var modules = {};     // id -> module
      var fetcherer = fetcher.create(modulator, function (id) {
        return blueprints[id] !== undefined;
      });

      var define = function (id, dependencies, definition) {
        if (blueprints[id] !== undefined)
          onerror("Define error: module '" + id + "' is already defined");
        else
          blueprints[id] = {
            id: id,
            dependencies: dependencies,
            definition: definition
          };
      };

      var require = function (ids, callback) {
        var onsuccess = function () {
          var instances = ar.map(ids, demand);
          callback.apply(null, instances);
        };

        var oncontinue = function () {
          var deps = obj.map(blueprints, function (k, v) {
            return v.dependencies;
          });
          loader.load(ids, deps, fetcherer, oncontinue, onsuccess, onerror);
        };

        oncontinue();
      };

      // Instantiates a module and all of its dependencies.
      var demand = function (id) {
        if (modules[id] !== undefined)
          return modules[id];
        if (blueprints[id] === undefined)
          throw "module '" + id + "' is not defined";
        var blueprint = blueprints[id];
        var args = ar.map(blueprint.dependencies, demand);  // Instantiate dependencies
        var result = blueprint.definition.apply(null, args);  // Instantiate self
        modules[id] = result;
        return result;
      };

      return {
        define: define,
        require: require,
        demand: demand
      };
    };

    return {
      create: create
    };
  }
);
<|endoftext|>


<commit_before>
beforeEach(function() {
	this.array = [0, 2, 4, 6, 8, 10, 12, 14];
});

it("Should accept a function with three parameters: the value of the element, the index of the element and the object being traversed", function() {
	var array = this.array;

	array.some(function(value, index, object) {
		expect(object).to.be(array);
		expect(object[index]).to.be(value);
		return false;
	});
});

it("Should accept an optional 'this' argument as its second argument which becomes the 'this' value for the function argument", function() {
	var mockThis = { foo: "bar" };
	var array = this.array;

	array.some(function(value) {
		expect(this).to.be(mockThis);
		expect(this.foo).to.be(mockThis.foo);
		return false;
	}, mockThis);
});

it("Should pass a reference to the array as the third parameter to the function argument", function() {
	var array = [10];

	array.some(function(value, index, object) {
		object[0] = 100;
		return false;
	});

	expect(array[0]).to.be(100);
});

it("Should not iterate over elements appended to the array after the call to some.  The range is fixed before the first call to the callback", function() {
	var array = [1, 2, 3, 4, 5, 6];
	var visited = [];

	array.some(function(value, index, object) {
		array.push(index);
		visited[index] = value;
		return false;
	});

	expect(visited).to.eql([1, 2, 3, 4, 5, 6]);

	// Expect the original array to be the same for the first 6 elements, with
	// the additional 0, 1, .. 5 appended (the indices of the first 6 elements
	// in the range covered by some at the start of its invocation
	expect(array).to.eql([1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5]);
});
<commit_msg>Should return false if the array is empty<commit_after>
beforeEach(function() {
	this.array = [0, 2, 4, 6, 8, 10, 12, 14];
});

it("Should accept a function with three parameters: the value of the element, the index of the element and the object being traversed", function() {
	var array = this.array;

	array.some(function(value, index, object) {
		expect(object).to.be(array);
		expect(object[index]).to.be(value);
		return false;
	});
});

it("Should accept an optional 'this' argument as its second argument which becomes the 'this' value for the function argument", function() {
	var mockThis = { foo: "bar" };
	var array = this.array;

	array.some(function(value) {
		expect(this).to.be(mockThis);
		expect(this.foo).to.be(mockThis.foo);
		return false;
	}, mockThis);
});

it("Should pass a reference to the array as the third parameter to the function argument", function() {
	var array = [10];

	array.some(function(value, index, object) {
		object[0] = 100;
		return false;
	});

	expect(array[0]).to.be(100);
});

it("Should not iterate over elements appended to the array after the call to some.  The range is fixed before the first call to the callback", function() {
	var array = [1, 2, 3, 4, 5, 6];
	var visited = [];

	array.some(function(value, index, object) {
		array.push(index);
		visited[index] = value;
		return false;
	});

	expect(visited).to.eql([1, 2, 3, 4, 5, 6]);

	// Expect the original array to be the same for the first 6 elements, with
	// the additional 0, 1, .. 5 appended (the indices of the first 6 elements
	// in the range covered by some at the start of its invocation
	expect(array).to.eql([1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5]);
});

it("Should return false if the array is empty", function() {
	var a = [];
	expect(a.some(function(value) { return true; })).to.be(false);
});
<|endoftext|>