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

import {getMode} from './mode';
import {exponentialBackoff} from './exponential-backoff';
import {isLoadErrorMessage} from './event-helper';
import {USER_ERROR_SENTINEL, isUserErrorMessage} from './log';
import {makeBodyVisible} from './style-installer';
import {urls} from './config';
import {isProxyOrigin} from './url';

/**
 * @const {string}
 */
const CANCELLED = 'CANCELLED';

/**
 * The threshold for throttling load errors. Currently at 0.1%.
 * @const {number}
 */
const LOAD_ERROR_THRESHOLD = 1e-3;

/**
 * Collects error messages, so they can be included in subsequent reports.
 * That allows identifying errors that might be caused by previous errors.
 */
let accumulatedErrorMessages = self.AMPErrors || [];
// Use a true global, to avoid multi-module inclusion issues.
self.AMPErrors = accumulatedErrorMessages;

/**
 * A wrapper around our exponentialBackoff, to lazy initialize it to avoid an
 * un-DCE'able side-effect.
 * @param {function()} work the function to execute after backoff
 * @return {number} the setTimeout id
 */
let globalExponentialBackoff = function(work) {
  // Set globalExponentialBackoff as the lazy-created function. JS Vooodoooo.
  globalExponentialBackoff = exponentialBackoff(1.5);
  return globalExponentialBackoff(work);
};

/**
 * Reports an error. If the error has an "associatedElement" property
 * the element is marked with the -amp-element-error and displays
 * the message itself. The message is always send to the console.
 * If the error has a "messageArray" property, that array is logged.
 * This way one gets the native fidelity of the console for things like
 * elements instead of stringification.
 * @param {*} error
 * @param {!Element=} opt_associatedElement
 * @return {!Error}
 */
export function reportError(error, opt_associatedElement) {
  // Convert error to the expected type.
  let isValidError;
  if (error) {
    if (error.message !== undefined) {
      isValidError = true;
    } else {
      const origError = error;
      error = new Error(String(origError));
      error.origError = origError;
    }
  } else {
    error = new Error('Unknown error');
  }
  // Report if error is not an expected type.
  if (!isValidError && getMode().localDev) {
    setTimeout(function() {
      const rethrow = new Error(
          '_reported_ Error reported incorrectly: ' + error);
      throw rethrow;
    });
  }

  if (error.reported) {
    return /** @type {!Error} */ (error);
  }
  error.reported = true;

  // Update element.
  const element = opt_associatedElement || error.associatedElement;
  if (element && element.classList) {
    element.classList.add('-amp-error');
    if (getMode().development) {
      element.classList.add('-amp-element-error');
      element.setAttribute('error-message', error.message);
    }
  }

  // Report to console.
  if (self.console) {
    if (error.messageArray) {
      (console.error || console.log).apply(console,
          error.messageArray);
    } else {
      if (element) {
        (console.error || console.log).call(console,
            element.tagName + '#' + element.id, error.message);
      } else if (!getMode().minified) {
        (console.error || console.log).call(console, error.stack);
      } else {
        (console.error || console.log).call(console, error.message);
      }
    }
  }
  if (element && element.dispatchCustomEventForTesting) {
    element.dispatchCustomEventForTesting('amp:error', error.message);
  }

  // 'call' to make linter happy. And .call to make compiler happy
  // that expects some @this.
  reportErrorToServer['call'](undefined, undefined, undefined, undefined,
      undefined, error);
  return /** @type {!Error} */ (error);
}

/**
 * Returns an error for a cancellation of a promise.
 * @return {!Error}
 */
export function cancellation() {
  return new Error(CANCELLED);
}

/**
 * Install handling of global unhandled exceptions.
 * @param {!Window} win
 */
export function installErrorReporting(win) {
  win.onerror = /** @type {!Function} */ (reportErrorToServer);
  win.addEventListener('unhandledrejection', event => {
    if (event.reason && event.reason.message === CANCELLED) {
      event.preventDefault();
      return;
    }
    reportError(event.reason || new Error('rejected promise ' + event));
  });
}

/**
 * Signature designed, so it can work with window.onerror
 * @param {string|undefined} message
 * @param {string|undefined} filename
 * @param {string|undefined} line
 * @param {string|undefined} col
 * @param {*|undefined} error
 * @this {!Window|undefined}
 */
function reportErrorToServer(message, filename, line, col, error) {
  // Make an attempt to unhide the body.
  if (this && this.document) {
    makeBodyVisible(this.document);
  }
  if (getMode().localDev || getMode().development || getMode().test) {
    return;
  }
  let hasNonAmpJs = false;
  try {
    hasNonAmpJs = detectNonAmpJs(self);
  } catch (ignore) {
    // Ignore errors during error report generation.
  }
  if (hasNonAmpJs && Math.random() > 0.01) {
    // Only report 1% of errors on pages with non-AMP JS.
    // These errors can almost never be acted upon, but spikes such as
    // due to buggy browser extensions may be helpful to notify authors.
    return;
  }
  const url = getErrorReportUrl(message, filename, line, col, error,
      hasNonAmpJs);
  globalExponentialBackoff(() => {
    if (url) {
      new Image().src = url;
    }
  });
}

/**
 * Signature designed, so it can work with window.onerror
 * @param {string|undefined} message
 * @param {string|undefined} filename
 * @param {string|undefined} line
 * @param {string|undefined} col
 * @param {*|undefined} error
 * @param {boolean} hasNonAmpJs
 * @return {string|undefined} The URL
 * visibleForTesting
 */
export function getErrorReportUrl(message, filename, line, col, error,
    hasNonAmpJs) {
  let expected = false;
  if (error) {
    if (error.message) {
      message = error.message;
    } else {
      // This should never be a string, but sometimes it is.
      message = String(error);
    }
    // An "expected" error is still an error, i.e. some features are disabled
    // or not functioning fully because of it. However, it's an expected
    // error. E.g. as is the case with some browser API missing (storage).
    // Thus, the error can be classified differently by log aggregators.
    // The main goal is to monitor that an "expected" error doesn't deteriorate
    // over time. It's impossible to completely eliminate it.
    if (error.expected) {
      expected = true;
    }
  }
  if (!message) {
    message = 'Unknown error';
  }
  if (/_reported_/.test(message)) {
    return;
  }
  if (message == CANCELLED) {
    return;
  }

  // Load errors are always "expected".
  if (isLoadErrorMessage(message)) {
    expected = true;

    // Throttle load errors.
    if (Math.random() > LOAD_ERROR_THRESHOLD) {
      return;
    }
  }

  // This is the App Engine app in
  // ../tools/errortracker
  // It stores error reports via https://cloud.google.com/error-reporting/
  // for analyzing production issues.
  let url = urls.errorReporting +
      '?v=' + encodeURIComponent('$internalRuntimeVersion$') +
      '&noAmp=' + (hasNonAmpJs ? 1 : 0) +
      '&m=' + encodeURIComponent(message.replace(USER_ERROR_SENTINEL, '')) +
      '&a=' + (isUserErrorMessage(message) ? 1 : 0);
  if (expected) {
    // Errors are tagged with "ex" ("expected") label to allow loggers to
    // classify these errors as benchmarks and not exceptions.
    url += '&ex=1';
  }
  if (self.context && self.context.location) {
    url += '&3p=1';
  }
  if (self.AMP_CONFIG && self.AMP_CONFIG.canary) {
    url += '&ca=1';
  }
  if (self.location.ancestorOrigins && self.location.ancestorOrigins[0]) {
    url += '&or=' + encodeURIComponent(self.location.ancestorOrigins[0]);
  }
  if (self.viewerState) {
    url += '&vs=' + encodeURIComponent(self.viewerState);
  }
  // Is embedded?
  if (self.parent && self.parent != self) {
    url += '&iem=1';
  }

  if (self.AMP && self.AMP.viewer) {
    const resolvedViewerUrl = self.AMP.viewer.getResolvedViewerUrl();
    const messagingOrigin = self.AMP.viewer.maybeGetMessagingOrigin();
    if (resolvedViewerUrl) {
      url += `&rvu=${encodeURIComponent(resolvedViewerUrl)}`;
    }
    if (messagingOrigin) {
      url += `&mso=${encodeURIComponent(messagingOrigin)}`;
    }
  }

  if (error) {
    const tagName = error && error.associatedElement
      ? error.associatedElement.tagName
      : 'u';  // Unknown
    url += '&el=' + encodeURIComponent(tagName) +
        '&s=' + encodeURIComponent(error.stack || '');
    error.message += ' _reported_';
  } else {
    url += '&f=' + encodeURIComponent(filename || '') +
        '&l=' + encodeURIComponent(line || '') +
        '&c=' + encodeURIComponent(col || '');
  }
  url += '&r=' + encodeURIComponent(self.document.referrer);
  url += '&ae=' + encodeURIComponent(accumulatedErrorMessages.join(','));
  accumulatedErrorMessages.push(message);
  url += '&fr=' + encodeURIComponent(self.location.originalHash
      || self.location.hash);

  return url;
}

/**
 * Returns true if it appears like there is non-AMP JS on the
 * current page.
 * @param {!Window} win
 * @visibleForTesting
 */
export function detectNonAmpJs(win) {
  const scripts = win.document.querySelectorAll('script[src]');
  for (let i = 0; i < scripts.length; i++) {
    if (!isProxyOrigin(scripts[i].src.toLowerCase())) {
      return true;
    }
  }
  return false;
}

export function resetAccumulatedErrorMessagesForTesting() {
  accumulatedErrorMessages = [];
}
<commit_msg>Do not extend backoff reporting useless errors (#6565)<commit_after>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {getMode} from './mode';
import {exponentialBackoff} from './exponential-backoff';
import {isLoadErrorMessage} from './event-helper';
import {USER_ERROR_SENTINEL, isUserErrorMessage} from './log';
import {makeBodyVisible} from './style-installer';
import {urls} from './config';
import {isProxyOrigin} from './url';

/**
 * @const {string}
 */
const CANCELLED = 'CANCELLED';

/**
 * The threshold for throttling load errors. Currently at 0.1%.
 * @const {number}
 */
const LOAD_ERROR_THRESHOLD = 1e-3;

/**
 * Collects error messages, so they can be included in subsequent reports.
 * That allows identifying errors that might be caused by previous errors.
 */
let accumulatedErrorMessages = self.AMPErrors || [];
// Use a true global, to avoid multi-module inclusion issues.
self.AMPErrors = accumulatedErrorMessages;

/**
 * A wrapper around our exponentialBackoff, to lazy initialize it to avoid an
 * un-DCE'able side-effect.
 * @param {function()} work the function to execute after backoff
 * @return {number} the setTimeout id
 */
let reportingBackoff = function(work) {
  // Set reportingBackoff as the lazy-created function. JS Vooodoooo.
  reportingBackoff = exponentialBackoff(1.5);
  return reportingBackoff(work);
};

/**
 * Reports an error. If the error has an "associatedElement" property
 * the element is marked with the -amp-element-error and displays
 * the message itself. The message is always send to the console.
 * If the error has a "messageArray" property, that array is logged.
 * This way one gets the native fidelity of the console for things like
 * elements instead of stringification.
 * @param {*} error
 * @param {!Element=} opt_associatedElement
 * @return {!Error}
 */
export function reportError(error, opt_associatedElement) {
  // Convert error to the expected type.
  let isValidError;
  if (error) {
    if (error.message !== undefined) {
      isValidError = true;
    } else {
      const origError = error;
      error = new Error(String(origError));
      error.origError = origError;
    }
  } else {
    error = new Error('Unknown error');
  }
  // Report if error is not an expected type.
  if (!isValidError && getMode().localDev) {
    setTimeout(function() {
      const rethrow = new Error(
          '_reported_ Error reported incorrectly: ' + error);
      throw rethrow;
    });
  }

  if (error.reported) {
    return /** @type {!Error} */ (error);
  }
  error.reported = true;

  // Update element.
  const element = opt_associatedElement || error.associatedElement;
  if (element && element.classList) {
    element.classList.add('-amp-error');
    if (getMode().development) {
      element.classList.add('-amp-element-error');
      element.setAttribute('error-message', error.message);
    }
  }

  // Report to console.
  if (self.console) {
    if (error.messageArray) {
      (console.error || console.log).apply(console,
          error.messageArray);
    } else {
      if (element) {
        (console.error || console.log).call(console,
            element.tagName + '#' + element.id, error.message);
      } else if (!getMode().minified) {
        (console.error || console.log).call(console, error.stack);
      } else {
        (console.error || console.log).call(console, error.message);
      }
    }
  }
  if (element && element.dispatchCustomEventForTesting) {
    element.dispatchCustomEventForTesting('amp:error', error.message);
  }

  // 'call' to make linter happy. And .call to make compiler happy
  // that expects some @this.
  reportErrorToServer['call'](undefined, undefined, undefined, undefined,
      undefined, error);
  return /** @type {!Error} */ (error);
}

/**
 * Returns an error for a cancellation of a promise.
 * @return {!Error}
 */
export function cancellation() {
  return new Error(CANCELLED);
}

/**
 * Install handling of global unhandled exceptions.
 * @param {!Window} win
 */
export function installErrorReporting(win) {
  win.onerror = /** @type {!Function} */ (reportErrorToServer);
  win.addEventListener('unhandledrejection', event => {
    if (event.reason && event.reason.message === CANCELLED) {
      event.preventDefault();
      return;
    }
    reportError(event.reason || new Error('rejected promise ' + event));
  });
}

/**
 * Signature designed, so it can work with window.onerror
 * @param {string|undefined} message
 * @param {string|undefined} filename
 * @param {string|undefined} line
 * @param {string|undefined} col
 * @param {*|undefined} error
 * @this {!Window|undefined}
 */
function reportErrorToServer(message, filename, line, col, error) {
  // Make an attempt to unhide the body.
  if (this && this.document) {
    makeBodyVisible(this.document);
  }
  if (getMode().localDev || getMode().development || getMode().test) {
    return;
  }
  let hasNonAmpJs = false;
  try {
    hasNonAmpJs = detectNonAmpJs(self);
  } catch (ignore) {
    // Ignore errors during error report generation.
  }
  if (hasNonAmpJs && Math.random() > 0.01) {
    // Only report 1% of errors on pages with non-AMP JS.
    // These errors can almost never be acted upon, but spikes such as
    // due to buggy browser extensions may be helpful to notify authors.
    return;
  }
  const url = getErrorReportUrl(message, filename, line, col, error,
      hasNonAmpJs);
  if (url) {
    reportingBackoff(() => {
      new Image().src = url;
    });
  }
}

/**
 * Signature designed, so it can work with window.onerror
 * @param {string|undefined} message
 * @param {string|undefined} filename
 * @param {string|undefined} line
 * @param {string|undefined} col
 * @param {*|undefined} error
 * @param {boolean} hasNonAmpJs
 * @return {string|undefined} The URL
 * visibleForTesting
 */
export function getErrorReportUrl(message, filename, line, col, error,
    hasNonAmpJs) {
  let expected = false;
  if (error) {
    if (error.message) {
      message = error.message;
    } else {
      // This should never be a string, but sometimes it is.
      message = String(error);
    }
    // An "expected" error is still an error, i.e. some features are disabled
    // or not functioning fully because of it. However, it's an expected
    // error. E.g. as is the case with some browser API missing (storage).
    // Thus, the error can be classified differently by log aggregators.
    // The main goal is to monitor that an "expected" error doesn't deteriorate
    // over time. It's impossible to completely eliminate it.
    if (error.expected) {
      expected = true;
    }
  }
  if (!message) {
    message = 'Unknown error';
  }
  if (/_reported_/.test(message)) {
    return;
  }
  if (message == CANCELLED) {
    return;
  }

  // Load errors are always "expected".
  if (isLoadErrorMessage(message)) {
    expected = true;

    // Throttle load errors.
    if (Math.random() > LOAD_ERROR_THRESHOLD) {
      return;
    }
  }

  // This is the App Engine app in
  // ../tools/errortracker
  // It stores error reports via https://cloud.google.com/error-reporting/
  // for analyzing production issues.
  let url = urls.errorReporting +
      '?v=' + encodeURIComponent('$internalRuntimeVersion$') +
      '&noAmp=' + (hasNonAmpJs ? 1 : 0) +
      '&m=' + encodeURIComponent(message.replace(USER_ERROR_SENTINEL, '')) +
      '&a=' + (isUserErrorMessage(message) ? 1 : 0);
  if (expected) {
    // Errors are tagged with "ex" ("expected") label to allow loggers to
    // classify these errors as benchmarks and not exceptions.
    url += '&ex=1';
  }
  if (self.context && self.context.location) {
    url += '&3p=1';
  }
  if (self.AMP_CONFIG && self.AMP_CONFIG.canary) {
    url += '&ca=1';
  }
  if (self.location.ancestorOrigins && self.location.ancestorOrigins[0]) {
    url += '&or=' + encodeURIComponent(self.location.ancestorOrigins[0]);
  }
  if (self.viewerState) {
    url += '&vs=' + encodeURIComponent(self.viewerState);
  }
  // Is embedded?
  if (self.parent && self.parent != self) {
    url += '&iem=1';
  }

  if (self.AMP && self.AMP.viewer) {
    const resolvedViewerUrl = self.AMP.viewer.getResolvedViewerUrl();
    const messagingOrigin = self.AMP.viewer.maybeGetMessagingOrigin();
    if (resolvedViewerUrl) {
      url += `&rvu=${encodeURIComponent(resolvedViewerUrl)}`;
    }
    if (messagingOrigin) {
      url += `&mso=${encodeURIComponent(messagingOrigin)}`;
    }
  }

  if (error) {
    const tagName = error && error.associatedElement
      ? error.associatedElement.tagName
      : 'u';  // Unknown
    url += '&el=' + encodeURIComponent(tagName) +
        '&s=' + encodeURIComponent(error.stack || '');
    error.message += ' _reported_';
  } else {
    url += '&f=' + encodeURIComponent(filename || '') +
        '&l=' + encodeURIComponent(line || '') +
        '&c=' + encodeURIComponent(col || '');
  }
  url += '&r=' + encodeURIComponent(self.document.referrer);
  url += '&ae=' + encodeURIComponent(accumulatedErrorMessages.join(','));
  accumulatedErrorMessages.push(message);
  url += '&fr=' + encodeURIComponent(self.location.originalHash
      || self.location.hash);

  return url;
}

/**
 * Returns true if it appears like there is non-AMP JS on the
 * current page.
 * @param {!Window} win
 * @visibleForTesting
 */
export function detectNonAmpJs(win) {
  const scripts = win.document.querySelectorAll('script[src]');
  for (let i = 0; i < scripts.length; i++) {
    if (!isProxyOrigin(scripts[i].src.toLowerCase())) {
      return true;
    }
  }
  return false;
}

export function resetAccumulatedErrorMessagesForTesting() {
  accumulatedErrorMessages = [];
}
<|endoftext|>


<commit_before>import { KING, QUEEN, KNIGHT, BISHOP, ROOK, PAWN } from './brands';
import { Point } from './point'

export class Board {

	constructor(files=8, ranks=8, boardArr) {
		this.files = files;
		this.ranks = ranks;
		this.storage = createStorage(files, ranks);
		this.pieces = new Set();
		this.pieces[KING] = new Set();
		this.pieces[QUEEN] = new Set();
		this.pieces[KNIGHT] = new Set();
		this.pieces[BISHOP] = new Set();
		this.pieces[ROOK] = new Set();
		this.pieces[PAWN] = new Set();
		if (boardArr != null) {
			this.decorate(boardArr);
		}
	}

	map(fn) {
		return new Board(this.ranks, this.files, this.storage.map((rank, i) =>
			rank.map((piece, j) => fn(piece, new Point(j, i)))));
	}

	forEach(fn) {
		// TODO: make this work like #map(), use this abstraction everywhere.
		return this.storage.forEach(fn);
	}

	getPieces(brand) {
		return brand == null ? this.pieces : this.pieces[brand];
	}

	getPieceCoords(piece) {
		for (var i = 0, iLen = this.storage.length; i < iLen; i++) {
			const rank = this.storage[i];
			for (var j = 0, jLen = rank.length; j < jLen; j++) {
				const p = rank[j];
				if (p === piece) {
					return new Point(j, i);
				}
			}
		}
		return null;
	}

	getPieceByCoords({ x, y }, rotated=false) {
		const rank = this.storage[rotated ? this.ranks - y - 1 : y];
		return rank == null ? null : rank[rotated ? this.files - x - 1 : x];
	}

	placePiece(piece, { x: file, y: rank }) {
		this.storage[rank][file] = piece;
		this.pieces.add(piece);
		this.pieces[piece.brand].add(piece);
	}

	decorate(board) {
		board.forEach((rank, i) => {
			rank.forEach((file, j) => {
				const piece = board[i][j];
				if (piece != null) {
					this.placePiece(piece, new Point(j, i));
				}
			});
		});
	}
}

function createStorage(ranks=8, files=8) {
	// ugly imperative way to create a board:
	const board = [];
	for (var i = 0; i < ranks; i++) {
		const rank = [];
		for (var j = 0; j < files; j++) {
			rank.push(null);
		}
		board.push(rank);
	}
	return board;
}
<commit_msg>board: remove temporary kludge<commit_after>import { KING, QUEEN, KNIGHT, BISHOP, ROOK, PAWN } from './brands';
import { Point } from './point'

export class Board {

	constructor(files=8, ranks=8, boardArr) {
		this.files = files;
		this.ranks = ranks;
		this.storage = createStorage(files, ranks);
		this.pieces = new Set();
		this.pieces[KING] = new Set();
		this.pieces[QUEEN] = new Set();
		this.pieces[KNIGHT] = new Set();
		this.pieces[BISHOP] = new Set();
		this.pieces[ROOK] = new Set();
		this.pieces[PAWN] = new Set();
		if (boardArr != null) {
			this.decorate(boardArr);
		}
	}

	map(fn) {
		return new Board(this.ranks, this.files, this.storage.map((rank, i) =>
			rank.map((piece, j) => fn(piece, new Point(j, i)))));
	}

	getPieces(brand) {
		return brand == null ? this.pieces : this.pieces[brand];
	}

	getPieceCoords(piece) {
		for (var i = 0, iLen = this.storage.length; i < iLen; i++) {
			const rank = this.storage[i];
			for (var j = 0, jLen = rank.length; j < jLen; j++) {
				const p = rank[j];
				if (p === piece) {
					return new Point(j, i);
				}
			}
		}
		return null;
	}

	getPieceByCoords({ x, y }, rotated=false) {
		const rank = this.storage[rotated ? this.ranks - y - 1 : y];
		return rank == null ? null : rank[rotated ? this.files - x - 1 : x];
	}

	placePiece(piece, { x: file, y: rank }) {
		this.storage[rank][file] = piece;
		this.pieces.add(piece);
		this.pieces[piece.brand].add(piece);
	}

	decorate(board) {
		board.forEach((rank, i) => {
			rank.forEach((file, j) => {
				const piece = board[i][j];
				if (piece != null) {
					this.placePiece(piece, new Point(j, i));
				}
			});
		});
	}
}

function createStorage(ranks=8, files=8) {
	// ugly imperative way to create a board:
	const board = [];
	for (var i = 0; i < ranks; i++) {
		const rank = [];
		for (var j = 0; j < files; j++) {
			rank.push(null);
		}
		board.push(rank);
	}
	return board;
}
<|endoftext|>


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

'use strict';

var incrgrubbs = require( './../lib' );

var data;
var opts;
var acc;
var i;

// Define a data set (8 mass spectrometer measurements of a uranium isotope; see Tietjen and Moore. 1972. "Some Grubbs-Type Statistics for the Detection of Several Outliers".)
data = [ 199.31, 199.53, 200.19, 200.82, 201.92, 201.95, 202.18, 245.57 ];

// Create a new accumulator:
opts = {
	'init': data.length,
	'alternative': 'two-sided'
};
acc = incrgrubbs( opts );

// Update the accumulator:
for ( i = 0; i < data.length; i++ ) {
	acc( data[ i ] );
}

// Print the test results:
console.log( acc().print() );
<commit_msg>Add missing punctuation<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

var incrgrubbs = require( './../lib' );

var data;
var opts;
var acc;
var i;

// Define a data set (8 mass spectrometer measurements of a uranium isotope; see Tietjen and Moore. 1972. "Some Grubbs-Type Statistics for the Detection of Several Outliers".):
data = [ 199.31, 199.53, 200.19, 200.82, 201.92, 201.95, 202.18, 245.57 ];

// Create a new accumulator:
opts = {
	'init': data.length,
	'alternative': 'two-sided'
};
acc = incrgrubbs( opts );

// Update the accumulator:
for ( i = 0; i < data.length; i++ ) {
	acc( data[ i ] );
}

// Print the test results:
console.log( acc().print() );
<|endoftext|>


<commit_before>var devtoolsPort = [];
var notifId = '';
chrome.runtime.onConnect.addListener(function(port){
	devtoolsPort.push(port);
});

var debug = (chrome.runtime.id == 'ikbablmmjldhamhcldjjigniffkkjgpo' ? false : true);

function addBlocking(){
	removeBlocking();
	if (chrome.declarativeWebRequest)
		chrome.declarativeWebRequest.onRequest.addRules([{
			id: 'dataslayerBlocking',
			conditions: [
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'google-analytics.com', pathPrefix: '/collect', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'google-analytics.com', pathPrefix: '/__utm.gif', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'stats.g.doubleclick.net', pathPrefix: '/__utm.gif', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'doubleclick.net', pathPrefix: '/activity', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { pathPrefix: '/b/ss', queryContains: 'AQB=1', schemes: ['http','https'] },
				})
				],
			actions: [
				new chrome.declarativeWebRequest.RedirectToTransparentImage()
			]}]);
}

function removeBlocking(){
	if (chrome.declarativeWebRequest)
		chrome.declarativeWebRequest.onRequest.removeRules(['dataslayerBlocking']);
}

chrome.storage.sync.get(null,function(items){
	if (items.hasOwnProperty('blockTags')&&items.blockTags===true) addBlocking();
	else removeBlocking();
});

chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
	if (debug) console.log(message);
	if ((message.type=='dataslayer_gtm_push')||((message.type=='dataslayer_gtm')||(message.type=='dataslayer_tlm'))){
		message.tabID=sender.tab.id;
		devtoolsPort.forEach(function(v,i,x){
			try{v.postMessage(message);}catch(e){console.log(e);}
		});
	}
	else if ((message.type=='dataslayer_pageload')||(message.type=='dataslayer_opened')){
		chrome.tabs.executeScript(message.tabID,{ file: 'content.js', runAt: 'document_idle' });
	}
	else if (message.type=='dataslayer_refresh'){
		chrome.tabs.sendMessage(message.tabID,{ask: 'refresh'});
	}
	else if (message.type=='dataslayer_unload')
		chrome.tabs.executeScript(message.tabID,{ code: 'document.head.removeChild(document.getElementById(\'dataslayer_script\'));', runAt: "document_idle" });
	else if (message.type=='dataslayer_loadsettings'){
		if (message.data.blockTags)
			addBlocking();
		else
			removeBlocking();
		devtoolsPort.forEach(function(v,i,x){
			v.postMessage(message);
		});
	}
});

chrome.runtime.onInstalled.addListener(function(details){
	if (details.reason=='install')
		chrome.tabs.create({url:'chrome-extension://'+chrome.runtime.id+'/options.html#install',active:true});
	else if ((details.reason=='update')&&(!debug))
		{chrome.notifications.create('', {type:'basic',title:'dataslayer', message:'dataslayer has been updated to version '+chrome.runtime.getManifest().version+'.\nClick here to see what\'s new.',iconUrl: 'i128.png'},function(notificationId){notifId=notificationId;});
				chrome.notifications.onClicked.addListener(function(notificationId){if (notificationId==notifId) chrome.tabs.create({url:'chrome-extension://'+chrome.runtime.id+'/options.html#whatsnew',active:true});});}
});<commit_msg>rename debug flag to avoid ns conflicts<commit_after>var devtoolsPort = [];
var notifId = '';
chrome.runtime.onConnect.addListener(function(port){
	devtoolsPort.push(port);
});

var dsDebug = (chrome.runtime.id == 'ikbablmmjldhamhcldjjigniffkkjgpo' ? false : true);

function addBlocking(){
	removeBlocking();
	if (chrome.declarativeWebRequest)
		chrome.declarativeWebRequest.onRequest.addRules([{
			id: 'dataslayerBlocking',
			conditions: [
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'google-analytics.com', pathPrefix: '/collect', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'google-analytics.com', pathPrefix: '/__utm.gif', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'stats.g.doubleclick.net', pathPrefix: '/__utm.gif', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { hostSuffix: 'doubleclick.net', pathPrefix: '/activity', schemes: ['http','https'] },
				}),
				new chrome.declarativeWebRequest.RequestMatcher({
					url: { pathPrefix: '/b/ss', queryContains: 'AQB=1', schemes: ['http','https'] },
				})
				],
			actions: [
				new chrome.declarativeWebRequest.RedirectToTransparentImage()
			]}]);
}

function removeBlocking(){
	if (chrome.declarativeWebRequest)
		chrome.declarativeWebRequest.onRequest.removeRules(['dataslayerBlocking']);
}

chrome.storage.sync.get(null,function(items){
	if (items.hasOwnProperty('blockTags')&&items.blockTags===true) addBlocking();
	else removeBlocking();
});

chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
	if (dsDebug) console.log(message);
	if ((message.type=='dataslayer_gtm_push')||((message.type=='dataslayer_gtm')||(message.type=='dataslayer_tlm'))){
		message.tabID=sender.tab.id;
		devtoolsPort.forEach(function(v,i,x){
			try{v.postMessage(message);}catch(e){console.log(e);}
		});
	}
	else if ((message.type=='dataslayer_pageload')||(message.type=='dataslayer_opened')){
		chrome.tabs.executeScript(message.tabID,{ file: 'content.js', runAt: 'document_idle' });
	}
	else if (message.type=='dataslayer_refresh'){
		chrome.tabs.sendMessage(message.tabID,{ask: 'refresh'});
	}
	else if (message.type=='dataslayer_unload')
		chrome.tabs.executeScript(message.tabID,{ code: 'document.head.removeChild(document.getElementById(\'dataslayer_script\'));', runAt: "document_idle" });
	else if (message.type=='dataslayer_loadsettings'){
		if (message.data.blockTags)
			addBlocking();
		else
			removeBlocking();
		devtoolsPort.forEach(function(v,i,x){
			v.postMessage(message);
		});
	}
});

chrome.runtime.onInstalled.addListener(function(details){
	if (details.reason=='install')
		chrome.tabs.create({url:'chrome-extension://'+chrome.runtime.id+'/options.html#install',active:true});
	else if ((details.reason=='update')&&(!dsDebug))
		{chrome.notifications.create('', {type:'basic',title:'dataslayer', message:'dataslayer has been updated to version '+chrome.runtime.getManifest().version+'.\nClick here to see what\'s new.',iconUrl: 'i128.png'},function(notificationId){notifId=notificationId;});
				chrome.notifications.onClicked.addListener(function(notificationId){if (notificationId==notifId) chrome.tabs.create({url:'chrome-extension://'+chrome.runtime.id+'/options.html#whatsnew',active:true});});}
});<|endoftext|>


<commit_before>/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code orignated from
 * Dean Edwards' addEvent library.
 */
jQuery.event = {

	// Bind an event to an element
	// Original by Dean Edwards
	add: function(element, type, handler, data) {
		// For whatever reason, IE has trouble passing the window object
		// around, causing it to be cloned in the process
		if ( jQuery.browser.msie && element.setInterval != undefined )
			element = window;

		// Make sure that the function being executed has a unique ID
		if ( !handler.guid )
			handler.guid = this.guid++;

		// if data is passed, bind to handler
		if( data != undefined ) {
        	// Create temporary function pointer to original handler
			var fn = handler;

			// Create unique handler function, wrapped around original handler
			handler = function() {
				// Pass arguments and context to original handler
				return fn.apply(this, arguments);
			};

			// Store data in unique handler
			handler.data = data;

			// Set the guid of unique handler to the same of original handler, so it can be removed
			handler.guid = fn.guid;
		}

		// Namespaced event handlers
		var parts = type.split(".");
		type = parts[0];
		handler.type = parts[1];

		// Init the element's event structure
		var events = jQuery.data(element, "events") || jQuery.data(element, "events", {});

		var handle = jQuery.data(element, "handle") || jQuery.data(element, "handle", function(){
			// returned undefined or false
			var val;

			// Handle the second event of a trigger and when
			// an event is called after a page has unloaded
			if ( typeof jQuery == "undefined" || jQuery.event.triggered )
				return val;

			val = jQuery.event.handle.apply(element, arguments);

			return val;
		});

		// Get the current list of functions bound to this event
		var handlers = events[type];

		// Init the event handler queue
		if (!handlers) {
			handlers = events[type] = {};

			// And bind the global event handler to the element
			if (element.addEventListener)
				element.addEventListener(type, handle, false);
			else
				element.attachEvent("on" + type, handle);
		}

		// Add the function to the element's handler list
		handlers[handler.guid] = handler;

		// Keep track of which events have been used, for global triggering
		this.global[type] = true;
	},

	guid: 1,
	global: {},

	// Detach an event or set of events from an element
	remove: function(element, type, handler) {
		var events = jQuery.data(element, "events"), ret, index;

		// Namespaced event handlers
		if ( typeof type == "string" ) {
			var parts = type.split(".");
			type = parts[0];
		}

		if ( events ) {
			// type is actually an event object here
			if ( type && type.type ) {
				handler = type.handler;
				type = type.type;
			}

			if ( !type ) {
				for ( type in events )
					this.remove( element, type );

			} else if ( events[type] ) {
				// remove the given handler for the given type
				if ( handler )
					delete events[type][handler.guid];

				// remove all handlers for the given type
				else
					for ( handler in events[type] )
						// Handle the removal of namespaced events
						if ( !parts[1] || events[type][handler].type == parts[1] )
							delete events[type][handler];

				// remove generic event handler if no more handlers exist
				for ( ret in events[type] ) break;
				if ( !ret ) {
					if (element.removeEventListener)
						element.removeEventListener(type, jQuery.data(element, "handle"), false);
					else
						element.detachEvent("on" + type, jQuery.data(element, "handle"));
					ret = null;
					delete events[type];
				}
			}

			// Remove the expando if it's no longer used
			for ( ret in events ) break;
			if ( !ret ) {
				jQuery.removeData( element, "events" );
				jQuery.removeData( element, "handle" );
			}
		}
	},

	trigger: function(type, data, element, donative, extra) {
		// Clone the incoming data, if any
		data = jQuery.makeArray(data || []);

		// Handle a global trigger
		if ( !element ) {
			// Only trigger if we've ever bound an event for it
			if ( this.global[type] )
				jQuery("*").add([window, document]).trigger(type, data);

		// Handle triggering a single element
		} else {
			var val, ret, fn = jQuery.isFunction( element[ type ] || null ),
				// Check to see if we need to provide a fake event, or not
				event = !data[0] || !data[0].preventDefault;

			// Pass along a fake event
			if ( event )
				data.unshift( this.fix({ type: type, target: element }) );

			// Enforce the right trigger type
			data[0].type = type;

			// Trigger the event
			if ( jQuery.isFunction( jQuery.data(element, "handle") ) )
				val = jQuery.data(element, "handle").apply( element, data );

			// Handle triggering native .onfoo handlers
			if ( !fn && element["on"+type] && element["on"+type].apply( element, data ) === false )
				val = false;

			// Extra functions don't get the custom event object
			if ( event )
				data.shift();

			// Handle triggering of extra function
			if ( extra && extra.apply( element, data ) === false )
				val = false;

			// Trigger the native events (except for clicks on links)
			if ( fn && donative !== false && val !== false && !(jQuery.nodeName(element, 'a') && type == "click") ) {
				this.triggered = true;
				element[ type ]();
			}

			this.triggered = false;
		}

		return val;
	},

	handle: function(event) {
		// returned undefined or false
		var val;

		// Empty object is for triggered events with no data
		event = jQuery.event.fix( event || window.event || {} );

		// Namespaced event handlers
		var parts = event.type.split(".");
		event.type = parts[0];

		var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
		args.unshift( event );

		for ( var j in handlers ) {
			var handler = handlers[j];
			// Pass in a reference to the handler function itself
			// So that we can later remove it
			args[0].handler = handler;
			args[0].data = handler.data;

			// Filter the functions by class
			if ( !parts[1] || handler.type == parts[1] ) {
				var ret = handler.apply( this, args );

				if ( val !== false )
					val = ret;

				if ( ret === false ) {
					event.preventDefault();
					event.stopPropagation();
				}
			}
		}

		// Clean up added properties in IE to prevent memory leak
		if (jQuery.browser.msie)
			event.target = event.preventDefault = event.stopPropagation =
				event.handler = event.data = null;

		return val;
	},

	fix: function(event) {
		// store a copy of the original event object
		// and clone to set read-only properties
		var originalEvent = event;
		event = jQuery.extend({}, originalEvent);

		// add preventDefault and stopPropagation since
		// they will not work on the clone
		event.preventDefault = function() {
			// if preventDefault exists run it on the original event
			if (originalEvent.preventDefault)
				originalEvent.preventDefault();
			// otherwise set the returnValue property of the original event to false (IE)
			originalEvent.returnValue = false;
		};
		event.stopPropagation = function() {
			// if stopPropagation exists run it on the original event
			if (originalEvent.stopPropagation)
				originalEvent.stopPropagation();
			// otherwise set the cancelBubble property of the original event to true (IE)
			originalEvent.cancelBubble = true;
		};

		// Fix target property, if necessary
		if ( !event.target )
			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either

		// check if target is a textnode (safari)
		if ( event.target.nodeType == 3 )
			event.target = originalEvent.target.parentNode;

		// Add relatedTarget, if necessary
		if ( !event.relatedTarget && event.fromElement )
			event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;

		// Calculate pageX/Y if missing and clientX/Y available
		if ( event.pageX == null && event.clientX != null ) {
			var doc = document.documentElement, body = document.body;
			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
			event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc.clientLeft || 0);
		}

		// Add which for key events
		if ( !event.which && (event.charCode || event.keyCode) )
			event.which = event.charCode || event.keyCode;

		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
		if ( !event.metaKey && event.ctrlKey )
			event.metaKey = event.ctrlKey;

		// Add which for click: 1 == left; 2 == middle; 3 == right
		// Note: button is not normalized, so don't use it
		if ( !event.which && event.button )
			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));

		return event;
	}
};

jQuery.fn.extend({
	bind: function( type, data, fn ) {
		return type == "unload" ? this.one(type, data, fn) : this.each(function(){
			jQuery.event.add( this, type, fn || data, fn && data );
		});
	},

	one: function( type, data, fn ) {
		return this.each(function(){
			jQuery.event.add( this, type, function(event) {
				jQuery(this).unbind(event);
				return (fn || data).apply( this, arguments);
			}, fn && data);
		});
	},

	unbind: function( type, fn ) {
		return this.each(function(){
			jQuery.event.remove( this, type, fn );
		});
	},

	trigger: function( type, data, fn ) {
		return this.each(function(){
			jQuery.event.trigger( type, data, this, true, fn );
		});
	},

	triggerHandler: function( type, data, fn ) {
		if ( this[0] )
			return jQuery.event.trigger( type, data, this[0], false, fn );
	},

	toggle: function() {
		// Save reference to arguments for access in closure
		var args = arguments;

		return this.click(function(event) {
			// Figure out which function to execute
			this.lastToggle = 0 == this.lastToggle ? 1 : 0;

			// Make sure that clicks stop
			event.preventDefault();

			// and execute the function
			return args[this.lastToggle].apply( this, [event] ) || false;
		});
	},

	hover: function(fnOver, fnOut) {

		// A private function for handling mouse 'hovering'
		function handleHover(event) {
			// Check if mouse(over|out) are still within the same parent element
			var parent = event.relatedTarget;

			// Traverse up the tree
			while ( parent && parent != this ) try { parent = parent.parentNode; } catch(error) { parent = this; };

			// If we actually just moused on to a sub-element, ignore it
			if ( parent == this ) return false;

			// Execute the right function
			return (event.type == "mouseover" ? fnOver : fnOut).apply(this, [event]);
		}

		// Bind the function to the two event listeners
		return this.mouseover(handleHover).mouseout(handleHover);
	},

	ready: function(fn) {
		// Attach the listeners
		bindReady();

		// If the DOM is already ready
		if ( jQuery.isReady )
			// Execute the function immediately
			fn.apply( document, [jQuery] );

		// Otherwise, remember the function for later
		else
			// Add the function to the wait list
			jQuery.readyList.push( function() { return fn.apply(this, [jQuery]); } );

		return this;
	}
});

jQuery.extend({
	/*
	 * All the code that makes DOM Ready work nicely.
	 */
	isReady: false,
	readyList: [],

	// Handle when the DOM is ready
	ready: function() {
		// Make sure that the DOM is not already loaded
		if ( !jQuery.isReady ) {
			// Remember that the DOM is ready
			jQuery.isReady = true;

			// If there are functions bound, to execute
			if ( jQuery.readyList ) {
				// Execute all of them
				jQuery.each( jQuery.readyList, function(){
					this.apply( document );
				});

				// Reset the list of functions
				jQuery.readyList = null;
			}
			// Remove event listener to avoid memory leak
			if ( document.removeEventListener )
				document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );
		}
	}
});

jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
	"mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
	"submit,keydown,keypress,keyup,error").split(","), function(i, name){

	// Handle event binding
	jQuery.fn[name] = function(fn){
		return fn ? this.bind(name, fn) : this.trigger(name);
	};
});

var readyBound = false;

function bindReady(){
	if ( readyBound ) return;
	readyBound = true;

	// Mozilla, Opera and webkit nightlies currently support this event
	if ( document.addEventListener )
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", jQuery.ready, false );

	// If Safari or IE is used
	// Continually check to see if the document is ready
	if  (jQuery.browser.msie || jQuery.browser.safari ) (function(){
		try {
			// If IE is used, use the trick by Diego Perini
			// http://javascript.nwbox.com/IEContentLoaded/
			if ( jQuery.browser.msie || document.readyState != "loaded" && document.readyState != "complete" )
				document.documentElement.doScroll("left");
		} catch( error ) {
			return setTimeout( arguments.callee, 0 );
		}

		// and execute any waiting functions
		jQuery.ready();
	})();

	// A fallback to window.onload, that will always work
	jQuery.event.add( window, "load", jQuery.ready );
}

// Prevent memory leaks in IE
// And prevent errors on refresh with events like mouseover
// Window isn't included so as not to unbind existing unload events
jQuery(window).bind("unload", function() {
	jQuery("*").add(document).unbind();
});
<commit_msg>Fixed #1970 by returning true instead of false when the mouse moves over a sub-element.  The side effect is the event will not stop default behavior and will propagate which it didn't used to.  I could find no compelling reason to stop those things from happening.<commit_after>/*
 * A number of helper functions used for managing events.
 * Many of the ideas behind this code orignated from
 * Dean Edwards' addEvent library.
 */
jQuery.event = {

	// Bind an event to an element
	// Original by Dean Edwards
	add: function(element, type, handler, data) {
		// For whatever reason, IE has trouble passing the window object
		// around, causing it to be cloned in the process
		if ( jQuery.browser.msie && element.setInterval != undefined )
			element = window;

		// Make sure that the function being executed has a unique ID
		if ( !handler.guid )
			handler.guid = this.guid++;

		// if data is passed, bind to handler
		if( data != undefined ) {
			// Create temporary function pointer to original handler
			var fn = handler;

			// Create unique handler function, wrapped around original handler
			handler = function() {
				// Pass arguments and context to original handler
				return fn.apply(this, arguments);
			};

			// Store data in unique handler
			handler.data = data;

			// Set the guid of unique handler to the same of original handler, so it can be removed
			handler.guid = fn.guid;
		}

		// Namespaced event handlers
		var parts = type.split(".");
		type = parts[0];
		handler.type = parts[1];

		// Init the element's event structure
		var events = jQuery.data(element, "events") || jQuery.data(element, "events", {});

		var handle = jQuery.data(element, "handle") || jQuery.data(element, "handle", function(){
			// returned undefined or false
			var val;

			// Handle the second event of a trigger and when
			// an event is called after a page has unloaded
			if ( typeof jQuery == "undefined" || jQuery.event.triggered )
				return val;

			val = jQuery.event.handle.apply(element, arguments);

			return val;
		});

		// Get the current list of functions bound to this event
		var handlers = events[type];

		// Init the event handler queue
		if (!handlers) {
			handlers = events[type] = {};

			// And bind the global event handler to the element
			if (element.addEventListener)
				element.addEventListener(type, handle, false);
			else
				element.attachEvent("on" + type, handle);
		}

		// Add the function to the element's handler list
		handlers[handler.guid] = handler;

		// Keep track of which events have been used, for global triggering
		this.global[type] = true;
	},

	guid: 1,
	global: {},

	// Detach an event or set of events from an element
	remove: function(element, type, handler) {
		var events = jQuery.data(element, "events"), ret, index;

		// Namespaced event handlers
		if ( typeof type == "string" ) {
			var parts = type.split(".");
			type = parts[0];
		}

		if ( events ) {
			// type is actually an event object here
			if ( type && type.type ) {
				handler = type.handler;
				type = type.type;
			}

			if ( !type ) {
				for ( type in events )
					this.remove( element, type );

			} else if ( events[type] ) {
				// remove the given handler for the given type
				if ( handler )
					delete events[type][handler.guid];

				// remove all handlers for the given type
				else
					for ( handler in events[type] )
						// Handle the removal of namespaced events
						if ( !parts[1] || events[type][handler].type == parts[1] )
							delete events[type][handler];

				// remove generic event handler if no more handlers exist
				for ( ret in events[type] ) break;
				if ( !ret ) {
					if (element.removeEventListener)
						element.removeEventListener(type, jQuery.data(element, "handle"), false);
					else
						element.detachEvent("on" + type, jQuery.data(element, "handle"));
					ret = null;
					delete events[type];
				}
			}

			// Remove the expando if it's no longer used
			for ( ret in events ) break;
			if ( !ret ) {
				jQuery.removeData( element, "events" );
				jQuery.removeData( element, "handle" );
			}
		}
	},

	trigger: function(type, data, element, donative, extra) {
		// Clone the incoming data, if any
		data = jQuery.makeArray(data || []);

		// Handle a global trigger
		if ( !element ) {
			// Only trigger if we've ever bound an event for it
			if ( this.global[type] )
				jQuery("*").add([window, document]).trigger(type, data);

		// Handle triggering a single element
		} else {
			var val, ret, fn = jQuery.isFunction( element[ type ] || null ),
				// Check to see if we need to provide a fake event, or not
				event = !data[0] || !data[0].preventDefault;

			// Pass along a fake event
			if ( event )
				data.unshift( this.fix({ type: type, target: element }) );

			// Enforce the right trigger type
			data[0].type = type;

			// Trigger the event
			if ( jQuery.isFunction( jQuery.data(element, "handle") ) )
				val = jQuery.data(element, "handle").apply( element, data );

			// Handle triggering native .onfoo handlers
			if ( !fn && element["on"+type] && element["on"+type].apply( element, data ) === false )
				val = false;

			// Extra functions don't get the custom event object
			if ( event )
				data.shift();

			// Handle triggering of extra function
			if ( extra && extra.apply( element, data ) === false )
				val = false;

			// Trigger the native events (except for clicks on links)
			if ( fn && donative !== false && val !== false && !(jQuery.nodeName(element, 'a') && type == "click") ) {
				this.triggered = true;
				element[ type ]();
			}

			this.triggered = false;
		}

		return val;
	},

	handle: function(event) {
		// returned undefined or false
		var val;

		// Empty object is for triggered events with no data
		event = jQuery.event.fix( event || window.event || {} );

		// Namespaced event handlers
		var parts = event.type.split(".");
		event.type = parts[0];

		var handlers = jQuery.data(this, "events") && jQuery.data(this, "events")[event.type], args = Array.prototype.slice.call( arguments, 1 );
		args.unshift( event );

		for ( var j in handlers ) {
			var handler = handlers[j];
			// Pass in a reference to the handler function itself
			// So that we can later remove it
			args[0].handler = handler;
			args[0].data = handler.data;

			// Filter the functions by class
			if ( !parts[1] || handler.type == parts[1] ) {
				var ret = handler.apply( this, args );

				if ( val !== false )
					val = ret;

				if ( ret === false ) {
					event.preventDefault();
					event.stopPropagation();
				}
			}
		}

		// Clean up added properties in IE to prevent memory leak
		if (jQuery.browser.msie)
			event.target = event.preventDefault = event.stopPropagation =
				event.handler = event.data = null;

		return val;
	},

	fix: function(event) {
		// store a copy of the original event object
		// and clone to set read-only properties
		var originalEvent = event;
		event = jQuery.extend({}, originalEvent);

		// add preventDefault and stopPropagation since
		// they will not work on the clone
		event.preventDefault = function() {
			// if preventDefault exists run it on the original event
			if (originalEvent.preventDefault)
				originalEvent.preventDefault();
			// otherwise set the returnValue property of the original event to false (IE)
			originalEvent.returnValue = false;
		};
		event.stopPropagation = function() {
			// if stopPropagation exists run it on the original event
			if (originalEvent.stopPropagation)
				originalEvent.stopPropagation();
			// otherwise set the cancelBubble property of the original event to true (IE)
			originalEvent.cancelBubble = true;
		};

		// Fix target property, if necessary
		if ( !event.target )
			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either

		// check if target is a textnode (safari)
		if ( event.target.nodeType == 3 )
			event.target = originalEvent.target.parentNode;

		// Add relatedTarget, if necessary
		if ( !event.relatedTarget && event.fromElement )
			event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;

		// Calculate pageX/Y if missing and clientX/Y available
		if ( event.pageX == null && event.clientX != null ) {
			var doc = document.documentElement, body = document.body;
			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
			event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc.clientLeft || 0);
		}

		// Add which for key events
		if ( !event.which && (event.charCode || event.keyCode) )
			event.which = event.charCode || event.keyCode;

		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
		if ( !event.metaKey && event.ctrlKey )
			event.metaKey = event.ctrlKey;

		// Add which for click: 1 == left; 2 == middle; 3 == right
		// Note: button is not normalized, so don't use it
		if ( !event.which && event.button )
			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));

		return event;
	}
};

jQuery.fn.extend({
	bind: function( type, data, fn ) {
		return type == "unload" ? this.one(type, data, fn) : this.each(function(){
			jQuery.event.add( this, type, fn || data, fn && data );
		});
	},

	one: function( type, data, fn ) {
		return this.each(function(){
			jQuery.event.add( this, type, function(event) {
				jQuery(this).unbind(event);
				return (fn || data).apply( this, arguments);
			}, fn && data);
		});
	},

	unbind: function( type, fn ) {
		return this.each(function(){
			jQuery.event.remove( this, type, fn );
		});
	},

	trigger: function( type, data, fn ) {
		return this.each(function(){
			jQuery.event.trigger( type, data, this, true, fn );
		});
	},

	triggerHandler: function( type, data, fn ) {
		if ( this[0] )
			return jQuery.event.trigger( type, data, this[0], false, fn );
	},

	toggle: function() {
		// Save reference to arguments for access in closure
		var args = arguments;

		return this.click(function(event) {
			// Figure out which function to execute
			this.lastToggle = 0 == this.lastToggle ? 1 : 0;

			// Make sure that clicks stop
			event.preventDefault();

			// and execute the function
			return args[this.lastToggle].apply( this, [event] ) || false;
		});
	},

	hover: function(fnOver, fnOut) {

		// A private function for handling mouse 'hovering'
		function handleHover(event) {
			// Check if mouse(over|out) are still within the same parent element
			var parent = event.relatedTarget;

			// Traverse up the tree
			while ( parent && parent != this ) try { parent = parent.parentNode; } catch(error) { parent = this; };

			// If we actually just moused on to a sub-element, ignore it
			if ( parent == this )
				return true;

			// Execute the right function
			return (event.type == "mouseover" ? fnOver : fnOut).apply(this, [event]);
		}

		// Bind the function to the two event listeners
		return this.mouseover(handleHover).mouseout(handleHover);
	},

	ready: function(fn) {
		// Attach the listeners
		bindReady();

		// If the DOM is already ready
		if ( jQuery.isReady )
			// Execute the function immediately
			fn.apply( document, [jQuery] );

		// Otherwise, remember the function for later
		else
			// Add the function to the wait list
			jQuery.readyList.push( function() { return fn.apply(this, [jQuery]); } );

		return this;
	}
});

jQuery.extend({
	/*
	 * All the code that makes DOM Ready work nicely.
	 */
	isReady: false,
	readyList: [],

	// Handle when the DOM is ready
	ready: function() {
		// Make sure that the DOM is not already loaded
		if ( !jQuery.isReady ) {
			// Remember that the DOM is ready
			jQuery.isReady = true;

			// If there are functions bound, to execute
			if ( jQuery.readyList ) {
				// Execute all of them
				jQuery.each( jQuery.readyList, function(){
					this.apply( document );
				});

				// Reset the list of functions
				jQuery.readyList = null;
			}
			// Remove event listener to avoid memory leak
			if ( document.removeEventListener )
				document.removeEventListener( "DOMContentLoaded", jQuery.ready, false );
		}
	}
});

jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
	"mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
	"submit,keydown,keypress,keyup,error").split(","), function(i, name){

	// Handle event binding
	jQuery.fn[name] = function(fn){
		return fn ? this.bind(name, fn) : this.trigger(name);
	};
});

var readyBound = false;

function bindReady(){
	if ( readyBound ) return;
	readyBound = true;

	// Mozilla, Opera and webkit nightlies currently support this event
	if ( document.addEventListener )
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", jQuery.ready, false );

	// If Safari or IE is used
	// Continually check to see if the document is ready
	if  (jQuery.browser.msie || jQuery.browser.safari ) (function(){
		try {
			// If IE is used, use the trick by Diego Perini
			// http://javascript.nwbox.com/IEContentLoaded/
			if ( jQuery.browser.msie || document.readyState != "loaded" && document.readyState != "complete" )
				document.documentElement.doScroll("left");
		} catch( error ) {
			return setTimeout( arguments.callee, 0 );
		}

		// and execute any waiting functions
		jQuery.ready();
	})();

	// A fallback to window.onload, that will always work
	jQuery.event.add( window, "load", jQuery.ready );
}

// Prevent memory leaks in IE
// And prevent errors on refresh with events like mouseover
// Window isn't included so as not to unbind existing unload events
jQuery(window).bind("unload", function() {
	jQuery("*").add(document).unbind();
});
<|endoftext|>


<commit_before>// Global and init scripts for whole SPA
pageModel = {
    currentPage: ko.observable('home_page'),
    currentRisk: ko.observable(''),
    currentCost: ko.observable(''),
    timeline: timelineModel,
    status: statusModel,
    map: charactersModel,
    register: registerModel,
    login: loginModel,
    passwordChange: passwordChangeModel,
    passwordRecover: passwordRecoverModel,
    incident: incidentModel
};

var policyUpdate = [];
var policies_array = {};

$(function () {

    $('.target').change(function(){
        window.id_elem = $(this).closest($(".qn")).attr('id');
    });

    console.log("Private decoration initialized...");
});

function clearProfile() {
    $(".profile_table").each(function () {    //clear table
        this.remove();
    });
    $('#chartContainer').empty();           //clear graph
}

$(function(){
    ko.applyBindings(pageModel);

    pageModel.currentPage.subscribe(function (currentPage) {
        switch (currentPage) {
            case 'profile_page':
                clearProfile();
                get_profile();
                break;
            case 'policy_page':
                submitAlternativesRequest();
                break;
            case 'score_page':
                initScore();
                break;
        }
    });
});<commit_msg>graphs fix attempt<commit_after>// Global and init scripts for whole SPA
pageModel = {
    currentPage: ko.observable('home_page'),
    currentRisk: ko.observable(''),
    currentCost: ko.observable(''),
    timeline: timelineModel,
    status: statusModel,
    map: charactersModel,
    register: registerModel,
    login: loginModel,
    passwordChange: passwordChangeModel,
    passwordRecover: passwordRecoverModel,
    incident: incidentModel
};

var policyUpdate = [];
var policies_array = {};

$(function () {

    $('.target').change(function(){
        window.id_elem = $(this).closest($(".qn")).attr('id');
    });

    console.log("Private decoration initialized...");
});

function clearProfile() {
    $(".profile_table").each(function () {    //clear table
        this.remove();
    });
    $('#chartContainer').empty();           //clear graph
}

$(function(){
    ko.applyBindings(pageModel);

    pageModel.currentPage.subscribe(function (currentPage) {
        switch (currentPage) {
            case 'profile_page':
                clearProfile();
                get_profile();
                break;
            case 'policy_page':
                //submitAlternativesRequest(); //commented out, as it is called anyways by retrieving of the stored policy
                break;
            case 'score_page':
                initScore();
                break;
        }
    });
});<|endoftext|>


<commit_before>/**
 *
 * Sortable table component for dragonfly.
 *
 * Component is configured by a tabledef object. A tabledef
 * contains a map describing all the columns, and optional
 * functions used for getting values, sorting and rendering.
 * An example looks like this:
 *
 * var tabledef = {
 *         columns: {
 *
 */
function SortableTable(tabledef, data, cols, sortby, reversed)
{
  this._init = function()
  {
    if (!cols || !cols.length) {
      cols = [];
      for (var key in tabledef.columns) { cols.push(key) }
    }

    for (var key in tabledef.columns)
    {
      var col = tabledef.columns[key];
      if (!col.getter)
      {
        col.getter = this._prop_getter(key);
      }

      if (!col.renderer)
      {
        col.renderer = col.getter;
      }

      if (!col.sorter)
      {
        col.sorter = this._prop_sorter(col.getter);
      }
    }

    this.tabledef = tabledef;
    this.data = data;
    this.columns = cols;
    this.sortby = sortby || cols[0];
    this.reversed = !!reversed;
    this.groupby = null;
    this._elem = null;
    this.objectid = ObjectRegistry.get_instance().set_object(this);
    this._init_handlers();
  }

  this._init_handlers = function()
  {
    if (!eventHandlers.click["sortable-table-sort"])
    {
      eventHandlers.click["sortable-table-sort"] = this._sort_handler;
    }
  }

  this._sort_handler = function(evt, target)
  {
    var table = target.parentNode.parentNode;
    var obj = ObjectRegistry.get_instance().get_object(table.getAttribute("data-object-id"));
    obj.sort(target.getAttribute("data-column-id"));
    table.re_render(obj.render());
  }

  this._default_sorters = {
    "number": function(getter) { return function(a, b) { return b-a; } }
  }

  this.render = function()
  {
      return templates.sortable_table(this.tabledef, this.data, this.objectid,
                                      this.columns, this.groupby, this.sortby,
                                      this.reversed);
  };

  this._prop_getter = function(name)
  {
    return function(obj) { return obj[name]; }
  }

  this._prop_sorter = function(getter)
  {
    return function(a, b)
    {
      a = getter(a);
      b = getter(b);
      if (a > b) { return 1 }
      else if (a < b) { return -1 }
      else { return 0 }
    }
  }

  this.sort = function(col)
  {
    if (col == this.sortby) {
      this.reversed = !this.reversed;
    }
    else
    {
      this.sortby = col;
    }
  };

  this.group = function(group)
  {
    if (!group || !this.tabledef.groups || !(group in this.tabledef.groups))
    {
      this.groupby = null;
    }
    else
    {
      this.groupby = group;
    }
  }

  this._init();
}

window.templates = window.templates || {};

templates.sortable_table = function(tabledef, data, objectid, cols, groupby, sortby, reversed)
{
  return ["table",
          templates.sortable_table_header(tabledef, cols, sortby, reversed),
          templates.sortable_table_body(tabledef, data, cols, groupby, sortby, reversed),
          "class", "sortable-table",
          "data-object-id", objectid
         ]
}

templates.sortable_table_header = function(tabledef, cols, sortby, reversed)
{
  return ["tr",
           cols.map(function(c) {
            return ["th",
                    tabledef.columns[c].label,
                    "class", (sortby==c ? "sort-column" : "") + (reversed ? " reversed" : ""),
                    "data-column-id", c,
                    "handler", "sortable-table-sort",
                   ]
          }),
          "class", "header"
          ];
}

templates.sortable_table_body = function(tabledef, data, cols, groupby, sortby, reversed)
{
  var groups = {};

  if (groupby)
  {
    var grouper = tabledef.groups[groupby].grouper;
    data.forEach(function(e) {
      var g = grouper(e);
      if (g in groups) { groups[g].push(e) }
      else { groups[g] = [e] }
    });
  }
  else
  {
    groups = {nogroup:data};
  }

  var groupnames = [];
  for (var key in groups) { groupnames.push(key) }

  render_group_headers = groupnames.length > 1;
  return groupnames.map(function(g) {
      return templates.sortable_table_group(tabledef, g,
                                            render_group_headers,
                                            groups[g], cols, sortby,
                                            reversed)
  });
}

templates.sortable_table_group = function(tabledef, groupname, render_header, data, cols, sortby, reversed)
{
  var sorter = tabledef.columns[sortby].sorter;
  data.sort(sorter);
  if (reversed) { data.reverse() }
  var tpl = [];

  if (render_header) {
    tpl.push(["tr",
              ["th", groupname,
               "colspan", String(cols.length),
               "class", "sortable-table-group-header"],
              "class", "header"
             ]);
  }

  return tpl.concat(data.map(function(item) {
    return templates.sortable_table_row(tabledef, item, cols)
  }));
}

templates.sortable_table_row = function(tabledef, item, cols)
{
  return ["tr",
          cols.map(function(col) {
            return ["td", tabledef.columns[col].renderer(item, tabledef.columns[col].getter)];
          })
         ];
}
<commit_msg>Removed old (unreferenced) sortabletable.js<commit_after><|endoftext|>


<commit_before>ObjType = {
    Number: 0,
    String: 1,
    CodeBlock: 2,
    Array: 3
}

var Obj = function(){
    this.type = ObjType.Number;
    this.string = "";
    this.num = ""; //maybe strictly integer?
    this.array = [];
};

function newString(string){
    var o = new Obj();
    o.type = ObjType.String;
    o.string = string;
    return o;
}

function newNumber(n){
    var o = new Obj();
    o.type = ObjType.Number;
    o.num = n;
    return o;
}

function newCodeBlock(string){
    var o = new Obj();
    o.type = ObjType.CodeBlock;
    o.string = string;
    return o;
}

var events = [];

//flags
var fcb=false,fs=false;

var buffer = "";

/**
 * Parses O code into AST
 */
function parse(code){
    events = [];
    fcb=false,fs=false;
    buffer = "";
    for(var i = 0; i < code.length; i++){
        var c = code.charAt(i);
        if(fcb && !fs){
            if(c == "}"){
                fcb = false;
                events.push(newCodeBlock(buffer));
                buffer = "";
                continue;
            }
            buffer += c;
        }
        if(fs && !fcb) {
            if(c == "\""){
                fs = false;
                events.push(newString(buffer));
                buffer = "";
                continue;
            }
            buffer += c;
        }
        else if(c.match(/[1-9A-F]/)){
            console.log(c);
            events.push(newNumber(c));
        }
        else if(c == "{"){
            fcb = true;
        }
        else if(c == "\""){
            fs = true;
        }
    }
    var ex = explain(events);
    return ex;
}

var maxWidth = 0;

function getMaxWidth() {
    return maxWidth;
}

function explain(events) {
    maxWidth = 0;
    e = "";
    //console.log(events)
    for(var i = 0; i < events.length; i++){
        var o = events[i];
        if(o instanceof Obj){
            if(o.type == ObjType.Number){
                var s = o.num + " Push " + o.num + " to the stack\n";
                if(maxWidth < s.length) maxWidth = s.length;
                e += s;
            }
            if(o.type == ObjType.String){
                var s = "\"" + o.string + "\" Push string to the stack\n";
                if(maxWidth < s.length) maxWidth = s.length;
                e += s;
            }
            if(o.type == ObjType.CodeBlock){
                var s = "{" + o.string + "} Push string to the stack\n";
                if(maxWidth < s.length) maxWidth = s.length;
                e += s;
            }
        }
    }
    return e;
}<commit_msg>Support for operator explanations<commit_after>operators = {
    'o': "Pop the stack and output",
    'p': "Pop the stack and print with new line"
}

ObjType = {
    Number: 0,
    String: 1,
    CodeBlock: 2,
    Array: 3
}

var Obj = function(){
    this.type = ObjType.Number;
    this.string = "";
    this.num = ""; //maybe strictly integer?
    this.array = [];
};

function newString(string){
    var o = new Obj();
    o.type = ObjType.String;
    o.string = string;
    return o;
}

function newNumber(n){
    var o = new Obj();
    o.type = ObjType.Number;
    o.num = n;
    return o;
}

function newCodeBlock(string){
    var o = new Obj();
    o.type = ObjType.CodeBlock;
    o.string = string;
    return o;
}

EventType = {
    ObjectEvent: 0,
    StringEvent: 1
}
var Event = function(){}

function eventString(c, s){
    var e = new Event();
    e.string = s;
    e.c = c;
    e.type = EventType.StringEvent;
    return e;
}

function eventObj(o){
    var e = new Event();
    e.object = o;
    e.type = EventType.ObjectEvent;
    return e;
}

var events = [];

//flags
var fcb=false,fs=false;

var buffer = "";

/**
 * Parses O code into AST
 */
function parse(code){
    events = [];
    fcb=false,fs=false;
    buffer = "";
    for(var i = 0; i < code.length; i++){
        var c = code.charAt(i);
        if(fcb && !fs){
            if(c == "}"){
                fcb = false;
                events.push(eventObj(newCodeBlock(buffer)));
                buffer = "";
                continue;
            }
            buffer += c;
        }
        if(fs && !fcb) {
            if(c == "\""){
                fs = false;
                events.push(eventObj(newString(buffer)));
                buffer = "";
                continue;
            }
            buffer += c;
        }
        else if(c.match(/[1-9A-F]/)){
            events.push(eventObj(newNumber(c)));
        }
        else if(c == "{"){
            fcb = true;
        }
        else if(c == "\""){
            fs = true;
        }
        else if(c == "J" || c == "K"){
            events.push(eventString(c, "Assign to variable " + c));
        }
        //normal operators
        else if(c in operators){
            events.push(eventString(c, operators[c]));
        }
    }
    var ex = explain(events);
    return ex;
}

var maxWidth = 0, spaces = 0;

function getMaxWidth() {
    return maxWidth;
}

function getSpaces(i) {
    var s = "", j = 0;
    while(j<i){s+= " ";j++;}
    return s;
}

function explain(events) {
    maxWidth = 0;
    spaces = 1;
    e = "";
    for(var i = 0; i < events.length; i++){
        var event = events[i];
        if(event.type == EventType.ObjectEvent){
            var o = event.object;
            if(o.type == ObjType.Number){
                var g = o.num.length;
                var s = o.num + getSpaces(spaces-g) +  " Push " + o.num + " to the stack\n";
                if(maxWidth < s.length) maxWidth = s.length;
                e += s;
            }
            if(o.type == ObjType.String){
                var g = o.string.length + 2/*quotes*/;
                if(spaces < g) spaces = g;
                var s = "\"" + o.string + "\"" + getSpaces(spaces-g) +  " Push string to the stack\n";
                if(maxWidth < s.length) maxWidth = s.length;
                e += s;
            }
            if(o.type == ObjType.CodeBlock){
                var g = o.string.length + 2/*brackets*/;
                var s = "{" + o.string + "}" + getSpaces(spaces-g) +  " Push codeblock to the stack\n";
                if(maxWidth < s.length) maxWidth = s.length;
                e += s;
            }
        }
        else if(event.type == EventType.StringEvent){
            var s = event.string;
            var g = s.length;
            if(maxWidth < g) maxWidth = g;
            e += event.c + getSpaces(spaces) + s + "\n";
        }
    }
    return e;
}<|endoftext|>


<commit_before>/*
events - a fast, flexible event system for javascript

------------------------------------------------------------------------
This file is loosely based on Dean Edwards's addEvent implementation and
modified to work with non-HTMLElement targets and custom event types
------------------------------------------------------------------------

event.add(targetObj, evName, handlerFunc)
event.listen(targetObj, evName, handlerFunc)
  add an event listener to targetObj. the listener function should take
  3 arguments, the event target, the event type, and a data object

event.oneTimer(targetObj, evName, handlerFunc)
  add an event listener to targetObj (like add/listen), but have it be
  automatically removed after the first call

event.remove(targetObj, [evName[, handlerFunc]])
event.unlisten(targetObj, evName, handlerFunc)
  undo an add

event.dispatch(targetObj, evName, data)
  trigger an event yourself. the 3 arguments will be passed straight to
  any active handler functions.
*/

/*global TJP*/
//context:browser
//context:console

TJP.event = TJP.event || {};

var fixEvent = function(target) {
  target.preventDefault = fixEvent.preventDefault;
  target.stopPropagation = fixEvent.stopPropagation;
  return target;
};
fixEvent.preventDefault = function() { this.returnValue = false; };
fixEvent.stopPropagation = function() { this.cancelBubble = true; };

var
  guid = 1,
  hguid = 1,
  events = {},
  handleEvent = function(target, type, data) {
    var i, rv = true, hs, errors = [];
    try {
      target = target || fixEvent(((this.ownerDocument || this.document ||
              this).parentWindow || window).event || {type: type});
    } catch (err) { target = fixEvent({type: type}); }
    hs = (events[target.__hguid] ? events[target.__hguid][type] : {}) || {};
    for (i in hs) {
      this.handleEvent = hs[i];
      try {
        if (this.handleEvent(target, type, data) === false) rv = false;
      } catch(e) { errors.push(e); }
    }
    delete this.handleEvent;
    if (errors.length) throw errors[0];
    return rv;
  };

TJP.event.add = TJP.event.listen = function(target, type, handler) {
  if (!handler.__guid) handler.__guid = guid++;
  if (!target.__hguid) target.__hguid = hguid++;
  if (!events[target.__hguid]) events[target.__hguid] = {};
  var handlers = events[target.__hguid][type];
  if (!handlers) {
    handlers = events[target.__hguid][type] = {};
    if (target["on" + type]) handlers[0] = target["on" + type];
  }
  handlers[handler.__guid] = handler;
  target["on" + type] = function(data) {
    this.handleEvent = handleEvent;
    return this.handleEvent(target, type, data);
  };
};

TJP.event.remove = TJP.event.unlisten = function(target, type, handler) {
  if (type === undefined)
    delete events[target.__hguid];
  else if (handler === undefined && events[target.__hguid])
    delete events[target.__hguid][type]
  else if (events[target.__hguid] && events[target.__hguid][type])
    delete events[target.__hguid][type][handler.__guid];
};

TJP.event.oneTimer = function(target, type, handler) {
  TJP.event.add(target, type, function(target, type, data) {
    TJP.event.remove(target, type, arguments.callee);
    return handler(target, type, data);
  });
};

TJP.event.dispatch = function(target, type, data) {
  if (target["on" + type]) return target["on" + type](data);
};
<commit_msg>event.nTimer - like oneTimer but configurable number of runs<commit_after>/*
events - a fast, flexible event system for javascript

------------------------------------------------------------------------
This file is loosely based on Dean Edwards's addEvent implementation and
modified to work with non-HTMLElement targets and custom event types
------------------------------------------------------------------------

event.add(targetObj, evName, handlerFunc)
event.listen(targetObj, evName, handlerFunc)
  add an event listener to targetObj. the listener function should take
  3 arguments, the event target, the event type, and a data object

event.oneTimer(targetObj, evName, handlerFunc)
  add an event listener to targetObj (like add/listen), but have it be
  automatically removed after the first call

event.nTimer(n, targetObj, evName, handlerFunc)
  add an event listener to targetObj (like add/listen), but have it be
  automatically removed after the nth call

event.remove(targetObj, [evName[, handlerFunc]])
event.unlisten(targetObj, evName, handlerFunc)
  undo an add

event.dispatch(targetObj, evName, data)
  trigger an event yourself. the 3 arguments will be passed straight to
  any active handler functions.
*/

/*global TJP*/
//context:browser
//context:console

TJP.event = TJP.event || {};

var fixEvent = function(target) {
  target.preventDefault = fixEvent.preventDefault;
  target.stopPropagation = fixEvent.stopPropagation;
  return target;
};
fixEvent.preventDefault = function() { this.returnValue = false; };
fixEvent.stopPropagation = function() { this.cancelBubble = true; };

var
  guid = 1,
  hguid = 1,
  events = {},
  handleEvent = function(target, type, data) {
    var i, rv = true, hs, errors = [];
    try {
      target = target || fixEvent(((this.ownerDocument || this.document ||
              this).parentWindow || window).event || {type: type});
    } catch (err) { target = fixEvent({type: type}); }
    hs = (events[target.__hguid] ? events[target.__hguid][type] : {}) || {};
    for (i in hs) {
      this.handleEvent = hs[i];
      try {
        if (this.handleEvent(target, type, data) === false) rv = false;
      } catch(e) { errors.push(e); }
    }
    delete this.handleEvent;
    if (errors.length) throw errors[0];
    return rv;
  };

TJP.event.add = TJP.event.listen = function(target, type, handler) {
  if (!handler.__guid) handler.__guid = guid++;
  if (!target.__hguid) target.__hguid = hguid++;
  if (!events[target.__hguid]) events[target.__hguid] = {};
  var handlers = events[target.__hguid][type];
  if (!handlers) {
    handlers = events[target.__hguid][type] = {};
    if (target["on" + type]) handlers[0] = target["on" + type];
  }
  handlers[handler.__guid] = handler;
  target["on" + type] = function(data) {
    this.handleEvent = handleEvent;
    return this.handleEvent(target, type, data);
  };
};

TJP.event.remove = TJP.event.unlisten = function(target, type, handler) {
  if (type === undefined)
    delete events[target.__hguid];
  else if (handler === undefined && events[target.__hguid])
    delete events[target.__hguid][type]
  else if (events[target.__hguid] && events[target.__hguid][type])
    delete events[target.__hguid][type][handler.__guid];
};

TJP.event.oneTimer = function(target, type, handler) {
  TJP.event.add(target, type, function(target, type, data) {
    TJP.event.remove(target, type, arguments.callee);
    return handler(target, type, data);
  });
};

TJP.event.nTimer = function(n, target, type, handler) {
  TJP.event.add(target, type, function(target, type, data) {
    if (--n <= 0)
      TJP.event.remove(target, type, arguments.callee);
    return handler(target, type, data);
  });
};

TJP.event.dispatch = function(target, type, data) {
  if (target["on" + type]) return target["on" + type](data);
};
<|endoftext|>