<commit_before>import { isArray, isObject, isFunction, isDate } from './_';

export const evalFn = (fn, args) => (isFunction(fn) ? fn(args) : fn);

export const pageIsValid = page => !!(page && page.month && page.year);

export const pageIsBeforePage = (page, comparePage) => {
  if (!pageIsValid(page) || !pageIsValid(comparePage)) return false;
  if (page.year === comparePage.year) return page.month < comparePage.month;
  return page.year < comparePage.year;
};

export const pageIsAfterPage = (page, comparePage) => {
  if (!pageIsValid(page) || !pageIsValid(comparePage)) return false;
  if (page.year === comparePage.year) return page.month > comparePage.month;
  return page.year > comparePage.year;
};

export const pageIsBetweenPages = (page, fromPage, toPage) =>
  (page || false) &&
  !pageIsBeforePage(page, fromPage) &&
  !pageIsAfterPage(page, toPage);

export const pageForDate = date => {
  if (!date) return null;
  return {
    month: date.getMonth() + 1,
    year: date.getFullYear(),
  };
};

export const addPages = ({ month, year }, count) => {
  const incr = count > 0 ? 1 : -1;
  for (let i = 0; i < Math.abs(count); i++) {
    month += incr;
    if (month > 12) {
      month = 1;
      year++;
    } else if (month < 1) {
      month = 12;
      year--;
    }
  }
  return {
    month,
    year,
  };
};

export const pageForThisMonth = () => pageForDate(new Date());

export const pageForNextMonth = () => addPages(pageForThisMonth(), 1);

export const pageForPrevMonth = () => addPages(pageForThisMonth(), -1);

export const getMaxPage = (...args) =>
  args.reduce((prev, curr) => {
    if (!prev) return curr;
    if (!curr) return prev;
    return pageIsAfterPage(curr, prev) ? curr : prev;
  });

export function datesAreEqual(a, b) {
  const aIsDate = isDate(a);
  const bIsDate = isDate(b);
  if (!aIsDate && !bIsDate) return true;
  if (aIsDate !== bIsDate) return false;
  return a.getTime() === b.getTime();
}

export const arrayHasItems = array => isArray(array) && array.length;

export const findAncestor = (el, fn) => {
  if (!el) return null;
  if (fn && fn(el)) return el;
  return findAncestor(el.parentElement, fn);
};

export const elementHasAncestor = (el, ancestor) =>
  !!findAncestor(el, e => e === ancestor);

export const elementPositionInAncestor = (el, ancestor) => {
  let top = 0;
  let left = 0;
  do {
    top += el.offsetTop || 0;
    left += el.offsetLeft || 0;
    el = el.offsetParent;
  } while (el && el !== ancestor);
  return {
    top,
    left,
  };
};

export const mixinOptionalProps = (source, target, props) => {
  const assigned = [];
  props.forEach(p => {
    const name = p.name || p.toString();
    const mixin = p.mixin;
    const validate = p.validate;
    if (Object.prototype.hasOwnProperty.call(source, name)) {
      const value = validate ? validate(source[name]) : source[name];
      target[name] = mixin && isObject(value) ? { ...mixin, ...value } : value;
      assigned.push(name);
    }
  });
  return {
    target,
    assigned: assigned.length ? assigned : null,
  };
};

export const on = (element, event, handler) => {
  if (element && event && handler) {
    document.addEventListener
      ? element.addEventListener(event, handler, false)
      : element.attachEvent(`on${event}`, handler);
  }
};

export const off = (element, event, handler) => {
  if (element && event) {
    document.removeEventListener
      ? element.removeEventListener(event, handler, false)
      : element.detachEvent(`on${event}`, handler);
  }
};

export const elementContains = (element, child) =>
  !!element && !!child && (element === child || element.contains(child));

export const onSpaceOrEnter = (event, handler) => {
  if (event.key === ' ' || event.key === 'Enter') {
    handler(event);
    event.preventDefault();
  }
};

/* eslint-disable no-bitwise */

export const createGuid = () => {
  function S4() {
    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  }
  return `${S4() + S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
};

export function hash(str) {
  let hashcode = 0;
  let i = 0;
  let chr;
  if (str.length === 0) return hashcode;
  for (i = 0; i < str.length; i++) {
    chr = str.charCodeAt(i);
    hashcode = (hashcode << 5) - hashcode + chr;
    hashcode |= 0; // Convert to 32bit integer
  }
  return hashcode;
}

/* eslint-enable no-bitwise */
<commit_msg>Remove legacy browser method support<commit_after>import { isArray, isObject, isFunction, isDate } from './_';

export const evalFn = (fn, args) => (isFunction(fn) ? fn(args) : fn);

export const pageIsValid = page => !!(page && page.month && page.year);

export const pageIsBeforePage = (page, comparePage) => {
  if (!pageIsValid(page) || !pageIsValid(comparePage)) return false;
  if (page.year === comparePage.year) return page.month < comparePage.month;
  return page.year < comparePage.year;
};

export const pageIsAfterPage = (page, comparePage) => {
  if (!pageIsValid(page) || !pageIsValid(comparePage)) return false;
  if (page.year === comparePage.year) return page.month > comparePage.month;
  return page.year > comparePage.year;
};

export const pageIsBetweenPages = (page, fromPage, toPage) =>
  (page || false) &&
  !pageIsBeforePage(page, fromPage) &&
  !pageIsAfterPage(page, toPage);

export const pageForDate = date => {
  if (!date) return null;
  return {
    month: date.getMonth() + 1,
    year: date.getFullYear(),
  };
};

export const addPages = ({ month, year }, count) => {
  const incr = count > 0 ? 1 : -1;
  for (let i = 0; i < Math.abs(count); i++) {
    month += incr;
    if (month > 12) {
      month = 1;
      year++;
    } else if (month < 1) {
      month = 12;
      year--;
    }
  }
  return {
    month,
    year,
  };
};

export const pageForThisMonth = () => pageForDate(new Date());

export const pageForNextMonth = () => addPages(pageForThisMonth(), 1);

export const pageForPrevMonth = () => addPages(pageForThisMonth(), -1);

export const getMaxPage = (...args) =>
  args.reduce((prev, curr) => {
    if (!prev) return curr;
    if (!curr) return prev;
    return pageIsAfterPage(curr, prev) ? curr : prev;
  });

export function datesAreEqual(a, b) {
  const aIsDate = isDate(a);
  const bIsDate = isDate(b);
  if (!aIsDate && !bIsDate) return true;
  if (aIsDate !== bIsDate) return false;
  return a.getTime() === b.getTime();
}

export const arrayHasItems = array => isArray(array) && array.length;

export const findAncestor = (el, fn) => {
  if (!el) return null;
  if (fn && fn(el)) return el;
  return findAncestor(el.parentElement, fn);
};

export const elementHasAncestor = (el, ancestor) =>
  !!findAncestor(el, e => e === ancestor);

export const elementPositionInAncestor = (el, ancestor) => {
  let top = 0;
  let left = 0;
  do {
    top += el.offsetTop || 0;
    left += el.offsetLeft || 0;
    el = el.offsetParent;
  } while (el && el !== ancestor);
  return {
    top,
    left,
  };
};

export const mixinOptionalProps = (source, target, props) => {
  const assigned = [];
  props.forEach(p => {
    const name = p.name || p.toString();
    const mixin = p.mixin;
    const validate = p.validate;
    if (Object.prototype.hasOwnProperty.call(source, name)) {
      const value = validate ? validate(source[name]) : source[name];
      target[name] = mixin && isObject(value) ? { ...mixin, ...value } : value;
      assigned.push(name);
    }
  });
  return {
    target,
    assigned: assigned.length ? assigned : null,
  };
};

export const on = (element, event, handler) => {
  if (element && event && handler) {
    element.addEventListener(event, handler, false);
  }
};

export const off = (element, event, handler) => {
  if (element && event) {
    element.removeEventListener(event, handler, false);
  }
};

export const elementContains = (element, child) =>
  !!element && !!child && (element === child || element.contains(child));

export const onSpaceOrEnter = (event, handler) => {
  if (event.key === ' ' || event.key === 'Enter') {
    handler(event);
    event.preventDefault();
  }
};

/* eslint-disable no-bitwise */

export const createGuid = () => {
  function S4() {
    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  }
  return `${S4() + S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
};

export function hash(str) {
  let hashcode = 0;
  let i = 0;
  let chr;
  if (str.length === 0) return hashcode;
  for (i = 0; i < str.length; i++) {
    chr = str.charCodeAt(i);
    hashcode = (hashcode << 5) - hashcode + chr;
    hashcode |= 0; // Convert to 32bit integer
  }
  return hashcode;
}

/* eslint-enable no-bitwise */
<|endoftext|>


<commit_before>import Color from "color";

/*ctx - canvas context
 sx - offsetX, sy - offetY
returns rgbNumber*/
export function getColor(ctx, sx, sy) {
    return Color(ctx.getImageData(sx,sy,1,1).data).rgbNumber();
}

/**
 * @param {number} x X coordinate of game cell.
 * @param {number} y Y coordinate of game cell.
 * @returns {array} Coordinates
 */
export function getNeighborsCoord(x, y) {
    let firstRowY = y - 10; // top left vertex y coordinate for first row cells
    let thirdRowX = y + 10;
    return [
            [x - 10, firstRowY],
            [x, firstRowY],
            [x + 10, firstRowY],
            [x - 10, y],
            [x + 10, y],
            [x - 10, thirdRowX],
            [x, thirdRowX],
            [x + 10, thirdRowX]
           ]
}

/**
 * @returns {array} Top left vertex coordinates for every cell on game grid.
 */
export function getCellCoordinates() {

    const CELL_LENGTH = 10;
    let canvas = document.getElementById("game-grid");
    let coordinates = [];

    for(let sx = 1; sx < canvas.width; sx += CELL_LENGTH) {
        for(let sy = 1; sy < canvas.height; sy += CELL_LENGTH) {
            coordinates.push([sx, sy])
        }
    }
    return coordinates;
}

/**
 * @param {array} coordinates Top left vertex coordinates for every cell on game grid
 * @returns {array} 6% of all cells to be drawn on the grid randomly
 */
export function getCellCoordinatesToDraw(coordinates) {
    let cellToDraw = coordinates.length * 0.06 // 6% cell to be drawn
    let coordinatesToDraw = [];

    for (let i = 0; i < cellToDraw; i += 1) {
        coordinatesToDraw.push(coordinates[Math.floor(Math.random()*coordinates.length)]);
    }

    return coordinatesToDraw;
}

export function drawCells(coordinatesToDraw) {
    let canvas = document.getElementById("game-grid");
    let ctx = canvas.getContext("2d");

    ctx.fillStyle = "yellow";
    for (let coordinates of coordinatesToDraw) {
        ctx.fillRect(...coordinates, 10, 10)
    }
}
<commit_msg>Add documentation<commit_after>import Color from "color";

/*ctx - canvas context
 sx - offsetX, sy - offetY
returns rgbNumber*/
export function getColor(ctx, sx, sy) {
    return Color(ctx.getImageData(sx,sy,1,1).data).rgbNumber();
}

/**
 * @param {number} x X coordinate of game cell.
 * @param {number} y Y coordinate of game cell.
 * @returns {array} Coordinates
 */
export function getNeighborsCoord(x, y) {
    let firstRowY = y - 10; // top left vertex y coordinate for first row cells
    let thirdRowX = y + 10;
    return [
            [x - 10, firstRowY],
            [x, firstRowY],
            [x + 10, firstRowY],
            [x - 10, y],
            [x + 10, y],
            [x - 10, thirdRowX],
            [x, thirdRowX],
            [x + 10, thirdRowX]
           ]
}

/**
 * @returns {array} Top left vertex coordinates for every cell on game grid.
 */
export function getCellCoordinates() {

    const CELL_LENGTH = 10;
    let canvas = document.getElementById("game-grid");
    let coordinates = [];

    for(let sx = 1; sx < canvas.width; sx += CELL_LENGTH) {
        for(let sy = 1; sy < canvas.height; sy += CELL_LENGTH) {
            coordinates.push([sx, sy])
        }
    }
    return coordinates;
}

/**
 * @param {array} coordinates Top left vertex coordinates for every cell on game grid
 * @returns {array} 6% of all cells to be drawn on the grid randomly
 */
export function getCellCoordinatesToDraw(coordinates) {
    let cellToDraw = coordinates.length * 0.06 // 6% cell to be drawn
    let coordinatesToDraw = [];

    for (let i = 0; i < cellToDraw; i += 1) {
        coordinatesToDraw.push(coordinates[Math.floor(Math.random()*coordinates.length)]);
    }

    return coordinatesToDraw;
}

/**
 * @param {array} coordinatesToDraw X,Y pairs of top left vertices on grid
 * Function draws squares on game board
 */
export function drawCells(coordinatesToDraw) {
    let canvas = document.getElementById("game-grid");
    let ctx = canvas.getContext("2d");

    ctx.fillStyle = "yellow";
    for (let coordinates of coordinatesToDraw) {
        ctx.fillRect(...coordinates, 10, 10)
    }
}
<|endoftext|>


<commit_before>import path from 'path';
import yaml from 'js-yaml';
import lodash from 'lodash';
import requirePackageName from 'require-package-name';
import { evaluate } from '.';

function parse(content) {
  try {
    return JSON.parse(content);
  } catch (error) {
    // not JSON format
  }

  try {
    return yaml.safeLoad(content);
  } catch (error) {
    // not YAML format
  }

  try {
    return evaluate(`module.exports = ${content}`);
  } catch (error) {
    // not valid JavaScript code
  }

  // parse fail, return nothing
  return {};
}

function wrapToArray(obj) {
  if (!obj) {
    return [];
  }
  if (lodash.isArray(obj)) {
    return obj;
  }

  return [obj];
}

function isLinterConfigAnAbsolutePath(specifier) {
  return path.isAbsolute(specifier);
}

function isLinterConfigARelativePath(specifier) {
  return lodash.startsWith(specifier, './') || lodash.startsWith(specifier, '../');
}

function isLinterConfigFromAPlugin(specifier) {
  return lodash.startsWith(specifier, 'plugin:');
}

function isLinterConfigFromAScopedModule(specifier) {
  return lodash.startsWith(specifier, '@');
}

function isLinterConfigFromAFullyQualifiedModuleName(specifier, prefix) {
  return lodash.startsWith(specifier, prefix);
}

function resolvePresetPackage(flavour, preset, rootDir) {
  // inspired from https://github.com/eslint/eslint/blob/5b4a94e26d0ef247fe222dacab5749805d9780dd/lib/config/config-file.js#L347
  if (isLinterConfigAnAbsolutePath(preset)) {
    return preset;
  }
  if (isLinterConfigARelativePath(preset)) {
    return path.resolve(rootDir, preset);
  }

  const { prefix, specifier } = (
    isLinterConfigFromAPlugin(preset)
      ? { prefix: `${flavour}-plugin-`, specifier: preset.substring(preset.indexOf(':') + 1) }
      : { prefix: `${flavour}-config-`, specifier: preset }
  );

  if (isLinterConfigFromAScopedModule(specifier)) {
    const scope = specifier.substring(0, specifier.indexOf('/'));
    const module = specifier.substring(specifier.indexOf('/') + 1);

    if (isLinterConfigFromAFullyQualifiedModuleName(module, prefix)) {
      return specifier;
    }
    return `${scope}/${prefix}${module}`;
  }
  if (isLinterConfigFromAFullyQualifiedModuleName(specifier, prefix)) {
    return specifier;
  }
  return `${prefix}${specifier}`;
}

function loadConfig(preset, rootDir) {
  const presetPath = path.isAbsolute(preset)
    ? preset
    : path.resolve(rootDir, 'node_modules', preset);

  try {
    return require(presetPath); // eslint-disable-line global-require
  } catch (error) {
    return {}; // silently return nothing
  }
}

function checkConfig(flavour, config, rootDir) {
  const parser = wrapToArray(config.parser);
  const plugins = wrapToArray(config.plugins).map(plugin => `${flavour}-plugin-${plugin}`);

  const presets = wrapToArray(config.extends)
    .filter(preset => preset !== `${flavour}:recommended`)
    .map(preset => resolvePresetPackage(flavour, preset, rootDir));

  const presetPackages = presets
    .filter(preset => !path.isAbsolute(preset))
    .map(requirePackageName);

  const presetDeps = lodash(presets)
    .map(preset => loadConfig(preset, rootDir))
    .map(presetConfig => checkConfig(flavour, presetConfig, rootDir))
    .flatten()
    .value();

  return lodash.union(parser, plugins, presetPackages, presetDeps);
}

export default function parseLinter(flavour, content, filename, deps, rootDir) {
  const basename = path.basename(filename);
  const filenameRegex = new RegExp(`^\\.${flavour}rc(\\.json|\\.js|\\.yml|\\.yaml)?$`);
  if (filenameRegex.test(basename)) {
    const config = parse(content);
    return checkConfig(flavour, config, rootDir);
  }

  return [];
}
<commit_msg>Improve regex in `parseLinter()` to accept `tslint.json` (#284)<commit_after>import path from 'path';
import yaml from 'js-yaml';
import lodash from 'lodash';
import requirePackageName from 'require-package-name';
import { evaluate } from '.';

function parse(content) {
  try {
    return JSON.parse(content);
  } catch (error) {
    // not JSON format
  }

  try {
    return yaml.safeLoad(content);
  } catch (error) {
    // not YAML format
  }

  try {
    return evaluate(`module.exports = ${content}`);
  } catch (error) {
    // not valid JavaScript code
  }

  // parse fail, return nothing
  return {};
}

function wrapToArray(obj) {
  if (!obj) {
    return [];
  }
  if (lodash.isArray(obj)) {
    return obj;
  }

  return [obj];
}

function isLinterConfigAnAbsolutePath(specifier) {
  return path.isAbsolute(specifier);
}

function isLinterConfigARelativePath(specifier) {
  return lodash.startsWith(specifier, './') || lodash.startsWith(specifier, '../');
}

function isLinterConfigFromAPlugin(specifier) {
  return lodash.startsWith(specifier, 'plugin:');
}

function isLinterConfigFromAScopedModule(specifier) {
  return lodash.startsWith(specifier, '@');
}

function isLinterConfigFromAFullyQualifiedModuleName(specifier, prefix) {
  return lodash.startsWith(specifier, prefix);
}

function resolvePresetPackage(flavour, preset, rootDir) {
  // inspired from https://github.com/eslint/eslint/blob/5b4a94e26d0ef247fe222dacab5749805d9780dd/lib/config/config-file.js#L347
  if (isLinterConfigAnAbsolutePath(preset)) {
    return preset;
  }
  if (isLinterConfigARelativePath(preset)) {
    return path.resolve(rootDir, preset);
  }

  const { prefix, specifier } = (
    isLinterConfigFromAPlugin(preset)
      ? { prefix: `${flavour}-plugin-`, specifier: preset.substring(preset.indexOf(':') + 1) }
      : { prefix: `${flavour}-config-`, specifier: preset }
  );

  if (isLinterConfigFromAScopedModule(specifier)) {
    const scope = specifier.substring(0, specifier.indexOf('/'));
    const module = specifier.substring(specifier.indexOf('/') + 1);

    if (isLinterConfigFromAFullyQualifiedModuleName(module, prefix)) {
      return specifier;
    }
    return `${scope}/${prefix}${module}`;
  }
  if (isLinterConfigFromAFullyQualifiedModuleName(specifier, prefix)) {
    return specifier;
  }
  return `${prefix}${specifier}`;
}

function loadConfig(preset, rootDir) {
  const presetPath = path.isAbsolute(preset)
    ? preset
    : path.resolve(rootDir, 'node_modules', preset);

  try {
    return require(presetPath); // eslint-disable-line global-require
  } catch (error) {
    return {}; // silently return nothing
  }
}

function checkConfig(flavour, config, rootDir) {
  const parser = wrapToArray(config.parser);
  const plugins = wrapToArray(config.plugins).map(plugin => `${flavour}-plugin-${plugin}`);

  const presets = wrapToArray(config.extends)
    .filter(preset => preset !== `${flavour}:recommended`)
    .map(preset => resolvePresetPackage(flavour, preset, rootDir));

  const presetPackages = presets
    .filter(preset => !path.isAbsolute(preset))
    .map(requirePackageName);

  const presetDeps = lodash(presets)
    .map(preset => loadConfig(preset, rootDir))
    .map(presetConfig => checkConfig(flavour, presetConfig, rootDir))
    .flatten()
    .value();

  return lodash.union(parser, plugins, presetPackages, presetDeps);
}

export default function parseLinter(flavour, content, filename, deps, rootDir) {
  const basename = path.basename(filename);
  const filenameRegex = new RegExp(`^\\.?${flavour}(rc)?(\\.json|\\.js|\\.yml|\\.yaml)?$`);
  if (filenameRegex.test(basename)) {
    const config = parse(content);
    return checkConfig(flavour, config, rootDir);
  }

  return [];
}
<|endoftext|>


<commit_before>/* @flow strict-local */
import type { Scope, SeverityType, EventHint } from '@sentry/react-native';
import { getCurrentHub, Severity, withScope as withScopeImpl } from '@sentry/react-native';

import type { JSONable } from './jsonable';
import objectEntries from './objectEntries';
import config from '../config';

/** Type of "extras" intended for Sentry. */
// This type should be exact, but cannot be until Flow v0.111.0. (See note in
// `jsonable.js`.)
type Extras = { +[key: string]: JSONable };

// Wrapper for `Sentry.withScope`, allowing callbacks to return values.
function withScope<R>(callback: Scope => R): R {
  let ret: R;
  withScopeImpl(scope => {
    ret = callback(scope);
  });
  // Flow can't know that `ret` has actually been initialized
  return ((ret: $FlowFixMe): R);
}

/**
 * Log an event (a string or Error) at some arbitrary severity.
 *
 * The error will be logged to Sentry, including a stack trace. The stack trace
 * is taken from `err` if an `Error` object, and otherwise synthesized from the
 * call site.
 *
 * Returns a Sentry event_id, although this is not expected to be useful.
 */
const logToSentry = (event: string | Error, level: SeverityType, extras: Extras): string => {
  let message: string;
  let hint: EventHint;

  if (event instanceof Error) {
    // eslint-disable-next-line prefer-destructuring
    message = event.message;
    hint = { originalException: event };
  } else {
    // Synthesize the event's stack trace. (The static API does this for us, at
    // least sometimes; but we're calling in at one level lower.)
    message = event;
    try {
      throw new Error(event);
    } catch (err) {
      hint = { syntheticException: err };
    }
  }

  return withScope(scope => {
    scope.setExtras(extras);

    // The static API's `captureException` doesn't allow passing strings, and its
    // counterpart `captureMessage` doesn't allow passing stacktraces.
    // Fortunately, the quasi-internal "Hub" API exists, and is reasonably
    // well-documented:
    //
    // https://docs.sentry.io/development/sdk-dev/unified-api/#hub
    //
    // (There is a `captureEvent` method that allows both explicitly; but it also
    // expects a great deal of other information which we would have to
    // synthesize, and which has no user-facing documentation.)
    return getCurrentHub().captureMessage(message, level, hint);
  });
};

type LogParams = {|
  consoleMethod: mixed => void,
  severity: SeverityType,
|};
type LogFunction = (event: string | Error, extras?: Extras) => void;

const makeLogFunction = ({ consoleMethod, severity }: LogParams): LogFunction => {
  const toConsole = consoleMethod.bind(console);

  return (event: string | Error, extras: Extras = {}) => {
    logToSentry(event, severity, extras);

    if (config.enableErrorConsoleLogging) {
      toConsole(event);

      const data = objectEntries(extras)
        .map(([key, value]) => `    ${key}: ${JSON.stringify(value)}`)
        .join('\n');

      if (data) {
        toConsole(data);
      }
    }
  };
};

/* eslint-disable no-console */

// Notes on the behavior of `console.error`, `console.warn`, `console.log`:
//
// * When debugging JS: all display in the Chrome dev console, and not in
//   the Android system log.
//   * `error` and `warn` produce a nice expando-hidden stack trace, in
//     addition to formatting their arguments.
//   * `log` just formats the arguments.
//   * An `Error` argument formats with its embedded stack trace.  (As just
//     text, with no spiffy expando.)
//
// * In a debug build, whether debugging JS or not:
//   * `error` pops up the RN error red-screen.
//   * `warn` could pop up an RN yellow-box, but we've set
//     `console.disableYellowBox` so it doesn't.
//
// * On Android, on both debug and release builds, except when debugging JS:
//   * All of `error`, `warn`, `log` go to the system log (for `adb logcat`).
//   * An `Error` argument formats with (the name + message and) just the
//     single source location where it was created, no stack trace.

/**
 * Log an error at "error" severity.
 *
 * The error will be logged to Sentry and/or the console as appropriate.
 *
 * In a debug build, this pops up the RN error red-screen.  This is
 * appropriate when the condition should never happen and definitely
 * represents a bug.  For conditions that can happen without a bug (e.g. a
 * failure to reach the server), consider `logging.warn`.
 *
 * @param event A string describing the nature of the event to be logged, or an
 *   exception whose `.message` is such a string. Related events should have
 *   identical such strings, when feasible.
 * @param extras Diagnostic data which may differ between separate occurrences
 *   of the event.
 *
 * See also:
 *  * `logging.warn` for logging at lower severity
 */
export const error: (event: string | Error, extras?: Extras) => void = makeLogFunction({
  consoleMethod: console.error,
  severity: Severity.Error,
});

/**
 * Log an event at "warning" severity.
 *
 * The event will be logged to Sentry and/or the console as appropriate.
 *
 * In the JS debugging console, this produces a yellow-highlighted warning,
 * but no popup interruption.  This makes it appropriate for conditions
 * which have an inevitable background rate.  For conditions which
 * definitely represent a bug in the app, consider `logging.error` instead.
 *
 * @param event A string describing the nature of the event to be logged, or an
 *   exception whose `.message` is such a string. Related events should have
 *   identical such strings, when feasible.
 * @param extras Diagnostic data which may differ between separate occurrences
 *   of the event.
 *
 * See also:
 *  * `logging.error` for logging at higher severity
 */
export const warn: (event: string | Error, extras?: Extras) => void = makeLogFunction({
  consoleMethod: console.warn,
  severity: Severity.Warning,
});
<commit_msg>logging [nfc]: convert ordinary comment to docstring<commit_after>/* @flow strict-local */
import type { Scope, SeverityType, EventHint } from '@sentry/react-native';
import { getCurrentHub, Severity, withScope as withScopeImpl } from '@sentry/react-native';

import type { JSONable } from './jsonable';
import objectEntries from './objectEntries';
import config from '../config';

/** Type of "extras" intended for Sentry. */
// This type should be exact, but cannot be until Flow v0.111.0. (See note in
// `jsonable.js`.)
type Extras = { +[key: string]: JSONable };

/** Wrapper for `Sentry.withScope`, allowing callbacks to return values. */
function withScope<R>(callback: Scope => R): R {
  let ret: R;
  withScopeImpl(scope => {
    ret = callback(scope);
  });
  // Flow can't know that `ret` has actually been initialized
  return ((ret: $FlowFixMe): R);
}

/**
 * Log an event (a string or Error) at some arbitrary severity.
 *
 * The error will be logged to Sentry, including a stack trace. The stack trace
 * is taken from `err` if an `Error` object, and otherwise synthesized from the
 * call site.
 *
 * Returns a Sentry event_id, although this is not expected to be useful.
 */
const logToSentry = (event: string | Error, level: SeverityType, extras: Extras): string => {
  let message: string;
  let hint: EventHint;

  if (event instanceof Error) {
    // eslint-disable-next-line prefer-destructuring
    message = event.message;
    hint = { originalException: event };
  } else {
    // Synthesize the event's stack trace. (The static API does this for us, at
    // least sometimes; but we're calling in at one level lower.)
    message = event;
    try {
      throw new Error(event);
    } catch (err) {
      hint = { syntheticException: err };
    }
  }

  return withScope(scope => {
    scope.setExtras(extras);

    // The static API's `captureException` doesn't allow passing strings, and its
    // counterpart `captureMessage` doesn't allow passing stacktraces.
    // Fortunately, the quasi-internal "Hub" API exists, and is reasonably
    // well-documented:
    //
    // https://docs.sentry.io/development/sdk-dev/unified-api/#hub
    //
    // (There is a `captureEvent` method that allows both explicitly; but it also
    // expects a great deal of other information which we would have to
    // synthesize, and which has no user-facing documentation.)
    return getCurrentHub().captureMessage(message, level, hint);
  });
};

type LogParams = {|
  consoleMethod: mixed => void,
  severity: SeverityType,
|};
type LogFunction = (event: string | Error, extras?: Extras) => void;

const makeLogFunction = ({ consoleMethod, severity }: LogParams): LogFunction => {
  const toConsole = consoleMethod.bind(console);

  return (event: string | Error, extras: Extras = {}) => {
    logToSentry(event, severity, extras);

    if (config.enableErrorConsoleLogging) {
      toConsole(event);

      const data = objectEntries(extras)
        .map(([key, value]) => `    ${key}: ${JSON.stringify(value)}`)
        .join('\n');

      if (data) {
        toConsole(data);
      }
    }
  };
};

/* eslint-disable no-console */

// Notes on the behavior of `console.error`, `console.warn`, `console.log`:
//
// * When debugging JS: all display in the Chrome dev console, and not in
//   the Android system log.
//   * `error` and `warn` produce a nice expando-hidden stack trace, in
//     addition to formatting their arguments.
//   * `log` just formats the arguments.
//   * An `Error` argument formats with its embedded stack trace.  (As just
//     text, with no spiffy expando.)
//
// * In a debug build, whether debugging JS or not:
//   * `error` pops up the RN error red-screen.
//   * `warn` could pop up an RN yellow-box, but we've set
//     `console.disableYellowBox` so it doesn't.
//
// * On Android, on both debug and release builds, except when debugging JS:
//   * All of `error`, `warn`, `log` go to the system log (for `adb logcat`).
//   * An `Error` argument formats with (the name + message and) just the
//     single source location where it was created, no stack trace.

/**
 * Log an error at "error" severity.
 *
 * The error will be logged to Sentry and/or the console as appropriate.
 *
 * In a debug build, this pops up the RN error red-screen.  This is
 * appropriate when the condition should never happen and definitely
 * represents a bug.  For conditions that can happen without a bug (e.g. a
 * failure to reach the server), consider `logging.warn`.
 *
 * @param event A string describing the nature of the event to be logged, or an
 *   exception whose `.message` is such a string. Related events should have
 *   identical such strings, when feasible.
 * @param extras Diagnostic data which may differ between separate occurrences
 *   of the event.
 *
 * See also:
 *  * `logging.warn` for logging at lower severity
 */
export const error: (event: string | Error, extras?: Extras) => void = makeLogFunction({
  consoleMethod: console.error,
  severity: Severity.Error,
});

/**
 * Log an event at "warning" severity.
 *
 * The event will be logged to Sentry and/or the console as appropriate.
 *
 * In the JS debugging console, this produces a yellow-highlighted warning,
 * but no popup interruption.  This makes it appropriate for conditions
 * which have an inevitable background rate.  For conditions which
 * definitely represent a bug in the app, consider `logging.error` instead.
 *
 * @param event A string describing the nature of the event to be logged, or an
 *   exception whose `.message` is such a string. Related events should have
 *   identical such strings, when feasible.
 * @param extras Diagnostic data which may differ between separate occurrences
 *   of the event.
 *
 * See also:
 *  * `logging.error` for logging at higher severity
 */
export const warn: (event: string | Error, extras?: Extras) => void = makeLogFunction({
  consoleMethod: console.warn,
  severity: Severity.Warning,
});
<|endoftext|>


<commit_before>
var minimongo = require("minimongo");
var IndexedDb = minimongo.IndexedDb;
var LocalDb = minimongo.LocalStorageDb;
var self;

var DataBase = function () {
	self=this;
	this.db = new LocalDb({ namespace: "game" });

	if (!this.db.levels) {
		this.db.addCollection('levels');
		this.db.levels.upsert({level:1});
	}

}

DataBase.prototype.getAllLevelsCleared = function (callback) {
	console.log(this.db);

	return this.db.levels.find({},{});
};

DataBase.prototype.saveLevel = function(level) {

	this.db.levels.upsert({level:level});
};

module.exports = DataBase;<commit_msg>Updated storage to use depot and added score functions as well.<commit_after>//var depot = require('depot');

var self;

var DataBase = function (collection) {
	self=this;

	this.db = depot(collection);
	console.log(this.db);

}

DataBase.prototype.getAllLevelsCleared = function (callback) {
	var self = this;
	var defaultLevel = {level:1, unlocked:Date.now()};
	var levels = this.db.all();

	console.log(levels);

	if (levels.length === 0) {
		this.db.save(defaultLevel);
		levels.push(defaultLevel);
	}

	return levels;

};

DataBase.prototype.saveLevel = function(level) {

	this.db.save({level:level, unlocked:Date.now()});
};

DataBase.prototype.getTopScores = function () {
	var scores = this.db.all();

	scores.sort(function (score1, score2) {
		return score1.score >= score2.score ? 1: -1;
	});

	return scores.slice(0,9);
}

DataBase.prototype.saveScore = function (score) {
	this.db.save({score:score, recorded:Date.now()});
};

module.exports = DataBase;<|endoftext|>


<commit_before>import PIDController from './node-pid-controller';

export default class VelocityModel {

  constructor({
    P = 100,
    D = 10,
    dt = 0,
    min = -Infinity,
    max = Infinity,
    start = 0,
    circular = false,
  }) {
    this.dt = dt;
    this.min = min;
    this.max = max;
    this.circular = circular;
    this.interval = this.max - this.min;
    this.halfInterval = this.interval / 2;
    // this.maxVelocity = (args && args.maxVelocity) || 0.5; // TODO: ??
    // this.dt2 = 0.5 * dt * dt;
    this.v = 0;
    this.pos = start;
    this.PID = new PIDController(P, 0, D, dt);
  }

  update(deltaT) {
    // TODO: introduce optional friction somehow?
    const dt = deltaT || this.dt;
    const force = this.PID.update(this.pos);
    this.v += force * dt;
    this.pos += this.v * dt;// + this.dt2*force;
    if (this.circular) {
      if (!this.inside(this.PID.target)) {
        // if we are in the state of a target outside the interval,
        // check if this.pos also is outside now => correct both
        if (this.pos < this.min) {
          this.PID.setTarget(this.PID.target + this.interval);
          this.pos += this.interval;
        } else if (this.pos > this.max) {
          this.PID.setTarget(this.PID.target - this.interval);
          this.pos -= this.interval;
        }
      }
    } else {
      if (this.pos < this.min) {
        this.v = 0;
        this.pos = this.min;
      }
      if (this.pos > this.max) {
        this.v = 0;
        this.pos = this.max;
      }
    }
    return this.pos;
  }

  inside(pos) {
    return pos < this.max && pos > this.min;
  }

  setTarget(target) {
    if (this.circular) {
      let t = target;
      if (target > this.max) {
        t = this.min + ((target - this.max) % this.interval);
      } else if (target < this.min) {
        t = this.max - ((this.min - target) % this.interval);
      }
      const error = t - this.pos;
      const absError = Math.abs(error);
      if (absError < this.interval - absError) {
        this.PID.setTarget(this.pos + error);
      } else {
        this.PID.setTarget(this.pos + Math.sign(-error) * (this.interval - absError));
      }
    } else {
      this.PID.setTarget(target);
    }
  }

  reset() {
    this.v = 0;
    this.PID.reset();
  }
}
<commit_msg>I and maxV<commit_after>import PIDController from './node-pid-controller';

export default class VelocityModel {

  constructor({
    P = 100,
    I = 0,
    D = 10,
    dt = 0,
    min = -Infinity,
    max = Infinity,
    start = 0,
    circular = false,
    maxV = Infinity,
  }) {
    this.dt = dt;
    this.min = min;
    this.max = max;
    this.maxV = maxV;
    this.circular = circular;
    this.interval = this.max - this.min;
    this.halfInterval = this.interval / 2;
    // this.maxVelocity = (args && args.maxVelocity) || 0.5; // TODO: ??
    // this.dt2 = 0.5 * dt * dt;
    this.v = 0;
    this.pos = start;
    this.PID = new PIDController(P, I, D, dt);
  }

  update(deltaT) {
    // TODO: introduce optional friction somehow?
    const dt = deltaT || this.dt;
    const force = this.PID.update(this.pos);
    this.v += force * dt;// + this.dt2*force;
    if (Math.abs(this.v) > this.maxV) {
      this.v = this.maxV * this.v / Math.abs(this.v);
    }
    this.pos += this.v * dt;
    if (this.circular) {
      if (!this.inside(this.PID.target)) {
        // if we are in the state of a target outside the interval,
        // check if this.pos also is outside now => correct both
        if (this.pos < this.min) {
          this.PID.setTarget(this.PID.target + this.interval);
          this.pos += this.interval;
        } else if (this.pos > this.max) {
          this.PID.setTarget(this.PID.target - this.interval);
          this.pos -= this.interval;
        }
      }
    } else {
      if (this.pos < this.min) {
        this.v = 0;
        this.pos = this.min;
      }
      if (this.pos > this.max) {
        this.v = 0;
        this.pos = this.max;
      }
    }
    return this.pos;
  }

  inside(pos) {
    return pos < this.max && pos > this.min;
  }

  setTarget(target) {
    if (this.circular) {
      let t = target;
      if (target > this.max) {
        t = this.min + ((target - this.max) % this.interval);
      } else if (target < this.min) {
        t = this.max - ((this.min - target) % this.interval);
      }
      const error = t - this.pos;
      const absError = Math.abs(error);
      if (absError < this.interval - absError) {
        this.PID.setTarget(this.pos + error);
      } else {
        this.PID.setTarget(this.pos + Math.sign(-error) * (this.interval - absError));
      }
    } else {
      this.PID.setTarget(target);
    }
  }

  reset() {
    this.v = 0;
    this.PID.reset();
  }
}
<|endoftext|>


<commit_before>import {ViewResources} from './view-resources';
import {ViewFactory} from './view-factory';
import {BindingLanguage} from './binding-language';
import {ViewCompileInstruction, BehaviorInstruction, TargetInstruction} from './instructions';
import {inject} from 'aurelia-dependency-injection';
import {DOM, FEATURE} from 'aurelia-pal';

let nextInjectorId = 0;
function getNextInjectorId() {
  return ++nextInjectorId;
}

function configureProperties(instruction, resources) {
  let type = instruction.type;
  let attrName = instruction.attrName;
  let attributes = instruction.attributes;
  let property;
  let key;
  let value;

  let knownAttribute = resources.mapAttribute(attrName);
  if (knownAttribute && attrName in attributes && knownAttribute !== attrName) {
    attributes[knownAttribute] = attributes[attrName];
    delete attributes[attrName];
  }

  for (key in attributes) {
    value = attributes[key];

    if (value !== null && typeof value === 'object') {
      property = type.attributes[key];

      if (property !== undefined) {
        value.targetProperty = property.name;
      } else {
        value.targetProperty = key;
      }
    }
  }
}

let lastAUTargetID = 0;
function getNextAUTargetID() {
  return (++lastAUTargetID).toString();
}

function makeIntoInstructionTarget(element) {
  let value = element.getAttribute('class');
  let auTargetID = getNextAUTargetID();

  element.setAttribute('class', (value ? value += ' au-target' : 'au-target'));
  element.setAttribute('au-target-id', auTargetID);

  return auTargetID;
}

/**
* Compiles html templates, dom fragments and strings into ViewFactory instances, capable of instantiating Views.
*/
@inject(BindingLanguage, ViewResources)
export class ViewCompiler {
  /**
  * Creates an instance of ViewCompiler.
  * @param bindingLanguage The default data binding language and syntax used during view compilation.
  * @param resources The global resources used during compilation when none are provided for compilation.
  */
  constructor(bindingLanguage: BindingLanguage, resources: ViewResources) {
    this.bindingLanguage = bindingLanguage;
    this.resources = resources;
  }

  /**
  * Compiles an html template, dom fragment or string into ViewFactory instances, capable of instantiating Views.
  * @param source The template, fragment or string to compile.
  * @param resources The view resources used during compilation.
  * @param compileInstruction A set of instructions that customize how compilation occurs.
  * @return The compiled ViewFactory.
  */
  compile(source: Element|DocumentFragment|string, resources?: ViewResources, compileInstruction?: ViewCompileInstruction): ViewFactory {
    resources = resources || this.resources;
    compileInstruction = compileInstruction || ViewCompileInstruction.normal;
    source = typeof source === 'string' ? DOM.createTemplateFromMarkup(source) : source;

    let content;
    let part;
    let cacheSize;

    if (source.content) {
      part = source.getAttribute('part');
      cacheSize = source.getAttribute('view-cache');
      content = DOM.adoptNode(source.content);
    } else {
      content = source;
    }

    compileInstruction.targetShadowDOM = compileInstruction.targetShadowDOM && FEATURE.shadowDOM;
    resources._onBeforeCompile(content, resources, compileInstruction);

    let instructions = {};
    this._compileNode(content, resources, instructions, source, 'root', !compileInstruction.targetShadowDOM);
    content.insertBefore(DOM.createComment('<view>'), content.firstChild);
    content.appendChild(DOM.createComment('</view>'));

    let factory = new ViewFactory(content, instructions, resources);

    factory.surrogateInstruction = compileInstruction.compileSurrogate ? this._compileSurrogate(source, resources) : null;
    factory.part = part;

    if (cacheSize) {
      factory.setCacheSize(cacheSize);
    }

    resources._onAfterCompile(factory);

    return factory;
  }

  _compileNode(node, resources, instructions, parentNode, parentInjectorId, targetLightDOM) {
    switch (node.nodeType) {
    case 1: //element node
      return this._compileElement(node, resources, instructions, parentNode, parentInjectorId, targetLightDOM);
    case 3: //text node
      //use wholeText to retrieve the textContent of all adjacent text nodes.
      let expression = resources.getBindingLanguage(this.bindingLanguage).parseText(resources, node.wholeText);
      if (expression) {
        let marker = DOM.createElement('au-marker');
        let auTargetID = makeIntoInstructionTarget(marker);
        (node.parentNode || parentNode).insertBefore(marker, node);
        node.textContent = ' ';
        instructions[auTargetID] = TargetInstruction.contentExpression(expression);
        //remove adjacent text nodes.
        while (node.nextSibling && node.nextSibling.nodeType === 3) {
          (node.parentNode || parentNode).removeChild(node.nextSibling);
        }
      } else {
        //skip parsing adjacent text nodes.
        while (node.nextSibling && node.nextSibling.nodeType === 3) {
          node = node.nextSibling;
        }
      }
      return node.nextSibling;
    case 11: //document fragment node
      let currentChild = node.firstChild;
      while (currentChild) {
        currentChild = this._compileNode(currentChild, resources, instructions, node, parentInjectorId, targetLightDOM);
      }
      break;
    default:
      break;
    }

    return node.nextSibling;
  }

  _compileSurrogate(node, resources) {
    let attributes = node.attributes;
    let bindingLanguage = resources.getBindingLanguage(this.bindingLanguage);
    let knownAttribute;
    let property;
    let instruction;
    let i;
    let ii;
    let attr;
    let attrName;
    let attrValue;
    let info;
    let type;
    let expressions = [];
    let expression;
    let behaviorInstructions = [];
    let values = {};
    let hasValues = false;
    let providers = [];

    for (i = 0, ii = attributes.length; i < ii; ++i) {
      attr = attributes[i];
      attrName = attr.name;
      attrValue = attr.value;

      info = bindingLanguage.inspectAttribute(resources, attrName, attrValue);
      type = resources.getAttribute(info.attrName);

      if (type) { //do we have an attached behavior?
        knownAttribute = resources.mapAttribute(info.attrName); //map the local name to real name
        if (knownAttribute) {
          property = type.attributes[knownAttribute];

          if (property) { //if there's a defined property
            info.defaultBindingMode = property.defaultBindingMode; //set the default binding mode

            if (!info.command && !info.expression) { // if there is no command or detected expression
              info.command = property.hasOptions ? 'options' : null; //and it is an optons property, set the options command
            }
          }
        }
      }

      instruction = bindingLanguage.createAttributeInstruction(resources, node, info, undefined, type);

      if (instruction) { //HAS BINDINGS
        if (instruction.alteredAttr) {
          type = resources.getAttribute(instruction.attrName);
        }

        if (instruction.discrete) { //ref binding or listener binding
          expressions.push(instruction);
        } else { //attribute bindings
          if (type) { //templator or attached behavior found
            instruction.type = type;
            configureProperties(instruction, resources);

            if (type.liftsContent) { //template controller
              throw new Error('You cannot place a template controller on a surrogate element.');
            } else { //attached behavior
              behaviorInstructions.push(instruction);
            }
          } else { //standard attribute binding
            expressions.push(instruction.attributes[instruction.attrName]);
          }
        }
      } else { //NO BINDINGS
        if (type) { //templator or attached behavior found
          instruction = BehaviorInstruction.attribute(attrName, type);
          instruction.attributes[resources.mapAttribute(attrName)] = attrValue;

          if (type.liftsContent) { //template controller
            throw new Error('You cannot place a template controller on a surrogate element.');
          } else { //attached behavior
            behaviorInstructions.push(instruction);
          }
        } else if (attrName !== 'id' && attrName !== 'part' && attrName !== 'replace-part') {
          hasValues = true;
          values[attrName] = attrValue;
        }
      }
    }

    if (expressions.length || behaviorInstructions.length || hasValues) {
      for (i = 0, ii = behaviorInstructions.length; i < ii; ++i) {
        instruction = behaviorInstructions[i];
        instruction.type.compile(this, resources, node, instruction);
        providers.push(instruction.type.target);
      }

      for (i = 0, ii = expressions.length; i < ii; ++i) {
        expression =  expressions[i];
        if (expression.attrToRemove !== undefined) {
          node.removeAttribute(expression.attrToRemove);
        }
      }

      return TargetInstruction.surrogate(providers, behaviorInstructions, expressions, values);
    }

    return null;
  }

  _compileElement(node, resources, instructions, parentNode, parentInjectorId, targetLightDOM) {
    let tagName = node.tagName.toLowerCase();
    let attributes = node.attributes;
    let expressions = [];
    let expression;
    let behaviorInstructions = [];
    let providers = [];
    let bindingLanguage = resources.getBindingLanguage(this.bindingLanguage);
    let liftingInstruction;
    let viewFactory;
    let type;
    let elementInstruction;
    let elementProperty;
    let i;
    let ii;
    let attr;
    let attrName;
    let attrValue;
    let instruction;
    let info;
    let property;
    let knownAttribute;
    let auTargetID;
    let injectorId;

    if (tagName === 'content') {
      if (targetLightDOM) {
        auTargetID = makeIntoInstructionTarget(node);
        instructions[auTargetID] = TargetInstruction.contentSelector(node, parentInjectorId);
      }
      return node.nextSibling;
    } else if (tagName === 'template') {
      viewFactory = this.compile(node, resources);
      viewFactory.part = node.getAttribute('part');
    } else {
      type = resources.getElement(tagName);
      if (type) {
        elementInstruction = BehaviorInstruction.element(node, type);
        behaviorInstructions.push(elementInstruction);
      }
    }

    for (i = 0, ii = attributes.length; i < ii; ++i) {
      attr = attributes[i];
      attrName = attr.name;
      attrValue = attr.value;
      info = bindingLanguage.inspectAttribute(resources, attrName, attrValue);
      type = resources.getAttribute(info.attrName);
      elementProperty = null;

      if (type) { //do we have an attached behavior?
        knownAttribute = resources.mapAttribute(info.attrName); //map the local name to real name
        if (knownAttribute) {
          property = type.attributes[knownAttribute];

          if (property) { //if there's a defined property
            info.defaultBindingMode = property.defaultBindingMode; //set the default binding mode

            if (!info.command && !info.expression) { // if there is no command or detected expression
              info.command = property.hasOptions ? 'options' : null; //and it is an optons property, set the options command
            }
          }
        }
      } else if (elementInstruction) { //or if this is on a custom element
        elementProperty = elementInstruction.type.attributes[info.attrName];
        if (elementProperty) { //and this attribute is a custom property
          info.defaultBindingMode = elementProperty.defaultBindingMode; //set the default binding mode
        }
      }

      if (elementProperty) {
        instruction = bindingLanguage.createAttributeInstruction(resources, node, info, elementInstruction);
      } else {
        instruction = bindingLanguage.createAttributeInstruction(resources, node, info, undefined, type);
      }

      if (instruction) { //HAS BINDINGS
        if (instruction.alteredAttr) {
          type = resources.getAttribute(instruction.attrName);
        }

        if (instruction.discrete) { //ref binding or listener binding
          expressions.push(instruction);
        } else { //attribute bindings
          if (type) { //templator or attached behavior found
            instruction.type = type;
            configureProperties(instruction, resources);

            if (type.liftsContent) { //template controller
              instruction.originalAttrName = attrName;
              liftingInstruction = instruction;
              break;
            } else { //attached behavior
              behaviorInstructions.push(instruction);
            }
          } else if (elementProperty) { //custom element attribute
            elementInstruction.attributes[info.attrName].targetProperty = elementProperty.name;
          } else { //standard attribute binding
            expressions.push(instruction.attributes[instruction.attrName]);
          }
        }
      } else { //NO BINDINGS
        if (type) { //templator or attached behavior found
          instruction = BehaviorInstruction.attribute(attrName, type);
          instruction.attributes[resources.mapAttribute(attrName)] = attrValue;

          if (type.liftsContent) { //template controller
            instruction.originalAttrName = attrName;
            liftingInstruction = instruction;
            break;
          } else { //attached behavior
            behaviorInstructions.push(instruction);
          }
        } else if (elementProperty) { //custom element attribute
          elementInstruction.attributes[attrName] = attrValue;
        }

        //else; normal attribute; do nothing
      }
    }

    if (liftingInstruction) {
      liftingInstruction.viewFactory = viewFactory;
      node = liftingInstruction.type.compile(this, resources, node, liftingInstruction, parentNode);
      auTargetID = makeIntoInstructionTarget(node);
      instructions[auTargetID] = TargetInstruction.lifting(parentInjectorId, liftingInstruction);
    } else {
      if (expressions.length || behaviorInstructions.length) {
        injectorId = behaviorInstructions.length ? getNextInjectorId() : false;

        for (i = 0, ii = behaviorInstructions.length; i < ii; ++i) {
          instruction = behaviorInstructions[i];
          instruction.type.compile(this, resources, node, instruction, parentNode);
          providers.push(instruction.type.target);
        }

        for (i = 0, ii = expressions.length; i < ii; ++i) {
          expression =  expressions[i];
          if (expression.attrToRemove !== undefined) {
            node.removeAttribute(expression.attrToRemove);
          }
        }

        auTargetID = makeIntoInstructionTarget(node);
        instructions[auTargetID] = TargetInstruction.normal(
          injectorId,
          parentInjectorId,
          providers,
          behaviorInstructions,
          expressions,
          elementInstruction
        );
      }

      if (elementInstruction && elementInstruction.skipContentProcessing) {
        return node.nextSibling;
      }

      let currentChild = node.firstChild;
      while (currentChild) {
        currentChild = this._compileNode(currentChild, resources, instructions, node, injectorId || parentInjectorId, targetLightDOM);
      }
    }

    return node.nextSibling;
  }
}
<commit_msg>feat(view-compiler): implement as-element<commit_after>import {ViewResources} from './view-resources';
import {ViewFactory} from './view-factory';
import {BindingLanguage} from './binding-language';
import {ViewCompileInstruction, BehaviorInstruction, TargetInstruction} from './instructions';
import {inject} from 'aurelia-dependency-injection';
import {DOM, FEATURE} from 'aurelia-pal';

let nextInjectorId = 0;
function getNextInjectorId() {
  return ++nextInjectorId;
}

function configureProperties(instruction, resources) {
  let type = instruction.type;
  let attrName = instruction.attrName;
  let attributes = instruction.attributes;
  let property;
  let key;
  let value;

  let knownAttribute = resources.mapAttribute(attrName);
  if (knownAttribute && attrName in attributes && knownAttribute !== attrName) {
    attributes[knownAttribute] = attributes[attrName];
    delete attributes[attrName];
  }

  for (key in attributes) {
    value = attributes[key];

    if (value !== null && typeof value === 'object') {
      property = type.attributes[key];

      if (property !== undefined) {
        value.targetProperty = property.name;
      } else {
        value.targetProperty = key;
      }
    }
  }
}

let lastAUTargetID = 0;
function getNextAUTargetID() {
  return (++lastAUTargetID).toString();
}

function makeIntoInstructionTarget(element) {
  let value = element.getAttribute('class');
  let auTargetID = getNextAUTargetID();

  element.setAttribute('class', (value ? value += ' au-target' : 'au-target'));
  element.setAttribute('au-target-id', auTargetID);

  return auTargetID;
}

/**
* Compiles html templates, dom fragments and strings into ViewFactory instances, capable of instantiating Views.
*/
@inject(BindingLanguage, ViewResources)
export class ViewCompiler {
  /**
  * Creates an instance of ViewCompiler.
  * @param bindingLanguage The default data binding language and syntax used during view compilation.
  * @param resources The global resources used during compilation when none are provided for compilation.
  */
  constructor(bindingLanguage: BindingLanguage, resources: ViewResources) {
    this.bindingLanguage = bindingLanguage;
    this.resources = resources;
  }

  /**
  * Compiles an html template, dom fragment or string into ViewFactory instances, capable of instantiating Views.
  * @param source The template, fragment or string to compile.
  * @param resources The view resources used during compilation.
  * @param compileInstruction A set of instructions that customize how compilation occurs.
  * @return The compiled ViewFactory.
  */
  compile(source: Element|DocumentFragment|string, resources?: ViewResources, compileInstruction?: ViewCompileInstruction): ViewFactory {
    resources = resources || this.resources;
    compileInstruction = compileInstruction || ViewCompileInstruction.normal;
    source = typeof source === 'string' ? DOM.createTemplateFromMarkup(source) : source;

    let content;
    let part;
    let cacheSize;

    if (source.content) {
      part = source.getAttribute('part');
      cacheSize = source.getAttribute('view-cache');
      content = DOM.adoptNode(source.content);
    } else {
      content = source;
    }

    compileInstruction.targetShadowDOM = compileInstruction.targetShadowDOM && FEATURE.shadowDOM;
    resources._onBeforeCompile(content, resources, compileInstruction);

    let instructions = {};
    this._compileNode(content, resources, instructions, source, 'root', !compileInstruction.targetShadowDOM);
    content.insertBefore(DOM.createComment('<view>'), content.firstChild);
    content.appendChild(DOM.createComment('</view>'));

    let factory = new ViewFactory(content, instructions, resources);

    factory.surrogateInstruction = compileInstruction.compileSurrogate ? this._compileSurrogate(source, resources) : null;
    factory.part = part;

    if (cacheSize) {
      factory.setCacheSize(cacheSize);
    }

    resources._onAfterCompile(factory);

    return factory;
  }

  _compileNode(node, resources, instructions, parentNode, parentInjectorId, targetLightDOM) {
    switch (node.nodeType) {
    case 1: //element node
      return this._compileElement(node, resources, instructions, parentNode, parentInjectorId, targetLightDOM);
    case 3: //text node
      //use wholeText to retrieve the textContent of all adjacent text nodes.
      let expression = resources.getBindingLanguage(this.bindingLanguage).parseText(resources, node.wholeText);
      if (expression) {
        let marker = DOM.createElement('au-marker');
        let auTargetID = makeIntoInstructionTarget(marker);
        (node.parentNode || parentNode).insertBefore(marker, node);
        node.textContent = ' ';
        instructions[auTargetID] = TargetInstruction.contentExpression(expression);
        //remove adjacent text nodes.
        while (node.nextSibling && node.nextSibling.nodeType === 3) {
          (node.parentNode || parentNode).removeChild(node.nextSibling);
        }
      } else {
        //skip parsing adjacent text nodes.
        while (node.nextSibling && node.nextSibling.nodeType === 3) {
          node = node.nextSibling;
        }
      }
      return node.nextSibling;
    case 11: //document fragment node
      let currentChild = node.firstChild;
      while (currentChild) {
        currentChild = this._compileNode(currentChild, resources, instructions, node, parentInjectorId, targetLightDOM);
      }
      break;
    default:
      break;
    }

    return node.nextSibling;
  }

  _compileSurrogate(node, resources) {
    let attributes = node.attributes;
    let bindingLanguage = resources.getBindingLanguage(this.bindingLanguage);
    let knownAttribute;
    let property;
    let instruction;
    let i;
    let ii;
    let attr;
    let attrName;
    let attrValue;
    let info;
    let type;
    let expressions = [];
    let expression;
    let behaviorInstructions = [];
    let values = {};
    let hasValues = false;
    let providers = [];

    for (i = 0, ii = attributes.length; i < ii; ++i) {
      attr = attributes[i];
      attrName = attr.name;
      attrValue = attr.value;

      info = bindingLanguage.inspectAttribute(resources, attrName, attrValue);
      type = resources.getAttribute(info.attrName);

      if (type) { //do we have an attached behavior?
        knownAttribute = resources.mapAttribute(info.attrName); //map the local name to real name
        if (knownAttribute) {
          property = type.attributes[knownAttribute];

          if (property) { //if there's a defined property
            info.defaultBindingMode = property.defaultBindingMode; //set the default binding mode

            if (!info.command && !info.expression) { // if there is no command or detected expression
              info.command = property.hasOptions ? 'options' : null; //and it is an optons property, set the options command
            }
          }
        }
      }

      instruction = bindingLanguage.createAttributeInstruction(resources, node, info, undefined, type);

      if (instruction) { //HAS BINDINGS
        if (instruction.alteredAttr) {
          type = resources.getAttribute(instruction.attrName);
        }

        if (instruction.discrete) { //ref binding or listener binding
          expressions.push(instruction);
        } else { //attribute bindings
          if (type) { //templator or attached behavior found
            instruction.type = type;
            configureProperties(instruction, resources);

            if (type.liftsContent) { //template controller
              throw new Error('You cannot place a template controller on a surrogate element.');
            } else { //attached behavior
              behaviorInstructions.push(instruction);
            }
          } else { //standard attribute binding
            expressions.push(instruction.attributes[instruction.attrName]);
          }
        }
      } else { //NO BINDINGS
        if (type) { //templator or attached behavior found
          instruction = BehaviorInstruction.attribute(attrName, type);
          instruction.attributes[resources.mapAttribute(attrName)] = attrValue;

          if (type.liftsContent) { //template controller
            throw new Error('You cannot place a template controller on a surrogate element.');
          } else { //attached behavior
            behaviorInstructions.push(instruction);
          }
        } else if (attrName !== 'id' && attrName !== 'part' && attrName !== 'replace-part') {
          hasValues = true;
          values[attrName] = attrValue;
        }
      }
    }

    if (expressions.length || behaviorInstructions.length || hasValues) {
      for (i = 0, ii = behaviorInstructions.length; i < ii; ++i) {
        instruction = behaviorInstructions[i];
        instruction.type.compile(this, resources, node, instruction);
        providers.push(instruction.type.target);
      }

      for (i = 0, ii = expressions.length; i < ii; ++i) {
        expression =  expressions[i];
        if (expression.attrToRemove !== undefined) {
          node.removeAttribute(expression.attrToRemove);
        }
      }

      return TargetInstruction.surrogate(providers, behaviorInstructions, expressions, values);
    }

    return null;
  }

  _compileElement(node, resources, instructions, parentNode, parentInjectorId, targetLightDOM) {
    let tagName = node.tagName.toLowerCase();
    let attributes = node.attributes;
    let expressions = [];
    let expression;
    let behaviorInstructions = [];
    let providers = [];
    let bindingLanguage = resources.getBindingLanguage(this.bindingLanguage);
    let liftingInstruction;
    let viewFactory;
    let type;
    let elementInstruction;
    let elementProperty;
    let i;
    let ii;
    let attr;
    let attrName;
    let attrValue;
    let instruction;
    let info;
    let property;
    let knownAttribute;
    let auTargetID;
    let injectorId;

    if (tagName === 'content') {
      if (targetLightDOM) {
        auTargetID = makeIntoInstructionTarget(node);
        instructions[auTargetID] = TargetInstruction.contentSelector(node, parentInjectorId);
      }
      return node.nextSibling;
    } else if (tagName === 'template') {
      viewFactory = this.compile(node, resources);
      viewFactory.part = node.getAttribute('part');
    } else {
      type = resources.getElement(node.getAttribute('as-element') || tagName);
      if (type) {
        elementInstruction = BehaviorInstruction.element(node, type);
        behaviorInstructions.push(elementInstruction);
      }
    }

    for (i = 0, ii = attributes.length; i < ii; ++i) {
      attr = attributes[i];
      attrName = attr.name;
      attrValue = attr.value;
      info = bindingLanguage.inspectAttribute(resources, attrName, attrValue);
      type = resources.getAttribute(info.attrName);
      elementProperty = null;

      if (type) { //do we have an attached behavior?
        knownAttribute = resources.mapAttribute(info.attrName); //map the local name to real name
        if (knownAttribute) {
          property = type.attributes[knownAttribute];

          if (property) { //if there's a defined property
            info.defaultBindingMode = property.defaultBindingMode; //set the default binding mode

            if (!info.command && !info.expression) { // if there is no command or detected expression
              info.command = property.hasOptions ? 'options' : null; //and it is an optons property, set the options command
            }
          }
        }
      } else if (elementInstruction) { //or if this is on a custom element
        elementProperty = elementInstruction.type.attributes[info.attrName];
        if (elementProperty) { //and this attribute is a custom property
          info.defaultBindingMode = elementProperty.defaultBindingMode; //set the default binding mode
        }
      }

      if (elementProperty) {
        instruction = bindingLanguage.createAttributeInstruction(resources, node, info, elementInstruction);
      } else {
        instruction = bindingLanguage.createAttributeInstruction(resources, node, info, undefined, type);
      }

      if (instruction) { //HAS BINDINGS
        if (instruction.alteredAttr) {
          type = resources.getAttribute(instruction.attrName);
        }

        if (instruction.discrete) { //ref binding or listener binding
          expressions.push(instruction);
        } else { //attribute bindings
          if (type) { //templator or attached behavior found
            instruction.type = type;
            configureProperties(instruction, resources);

            if (type.liftsContent) { //template controller
              instruction.originalAttrName = attrName;
              liftingInstruction = instruction;
              break;
            } else { //attached behavior
              behaviorInstructions.push(instruction);
            }
          } else if (elementProperty) { //custom element attribute
            elementInstruction.attributes[info.attrName].targetProperty = elementProperty.name;
          } else { //standard attribute binding
            expressions.push(instruction.attributes[instruction.attrName]);
          }
        }
      } else { //NO BINDINGS
        if (type) { //templator or attached behavior found
          instruction = BehaviorInstruction.attribute(attrName, type);
          instruction.attributes[resources.mapAttribute(attrName)] = attrValue;

          if (type.liftsContent) { //template controller
            instruction.originalAttrName = attrName;
            liftingInstruction = instruction;
            break;
          } else { //attached behavior
            behaviorInstructions.push(instruction);
          }
        } else if (elementProperty) { //custom element attribute
          elementInstruction.attributes[attrName] = attrValue;
        }

        //else; normal attribute; do nothing
      }
    }

    if (liftingInstruction) {
      liftingInstruction.viewFactory = viewFactory;
      node = liftingInstruction.type.compile(this, resources, node, liftingInstruction, parentNode);
      auTargetID = makeIntoInstructionTarget(node);
      instructions[auTargetID] = TargetInstruction.lifting(parentInjectorId, liftingInstruction);
    } else {
      if (expressions.length || behaviorInstructions.length) {
        injectorId = behaviorInstructions.length ? getNextInjectorId() : false;

        for (i = 0, ii = behaviorInstructions.length; i < ii; ++i) {
          instruction = behaviorInstructions[i];
          instruction.type.compile(this, resources, node, instruction, parentNode);
          providers.push(instruction.type.target);
        }

        for (i = 0, ii = expressions.length; i < ii; ++i) {
          expression =  expressions[i];
          if (expression.attrToRemove !== undefined) {
            node.removeAttribute(expression.attrToRemove);
          }
        }

        auTargetID = makeIntoInstructionTarget(node);
        instructions[auTargetID] = TargetInstruction.normal(
          injectorId,
          parentInjectorId,
          providers,
          behaviorInstructions,
          expressions,
          elementInstruction
        );
      }

      if (elementInstruction && elementInstruction.skipContentProcessing) {
        return node.nextSibling;
      }

      let currentChild = node.firstChild;
      while (currentChild) {
        currentChild = this._compileNode(currentChild, resources, instructions, node, injectorId || parentInjectorId, targetLightDOM);
      }
    }

    return node.nextSibling;
  }
}
<|endoftext|>


<commit_before>/*jshint multistr:true */

this.recline = this.recline || {};
this.recline.View = this.recline.View || {};

(function($, my) {
// turn off unnecessary logging from VMM Timeline
VMM.debug = false;

// ## Timeline
//
// Timeline view using http://timeline.verite.co/
my.Timeline = Backbone.View.extend({
  tagName:  'div',

  template: ' \

 \

 \

 \
  ',

  // These are the default (case-insensitive) names of field that are used if found.
  // If not found, the user will need to define these fields on initialization
  startFieldNames: ['date','startdate', 'start', 'start-date'],
  endFieldNames: ['end','endDate'],
  elementId: '#vmm-timeline-id',

  initialize: function(options) {
    var self = this;
    this.el = $(this.el);
    this.timeline = new VMM.Timeline();
    this._timelineIsInitialized = false;
    this.bind('view:show', function() {
      // only call _initTimeline once view in DOM as Timeline uses $ internally to look up element
      if (self._timelineIsInitialized === false) {
        self._initTimeline();
      }
    });
    this.model.fields.bind('reset', function() {
      self._setupTemporalField();
    });
    this.model.currentRecords.bind('all', function() {
      self.reloadData();
    });
    var stateData = _.extend({
        startField: null,
        endField: null
      },
      options.state
    );
    this.state = new recline.Model.ObjectState(stateData);
    this._setupTemporalField();
    this.render();
    // can only call _initTimeline once view in DOM as Timeline uses $
    // internally to look up element
    if ($(this.elementId).length > 0) {
      this._initTimeline();
    }
  },

  render: function() {
    var tmplData = {};
    var htmls = Mustache.render(this.template, tmplData);
    this.el.html(htmls);
  },

  _initTimeline: function() {
    var $timeline = this.el.find(this.elementId);
    // set width explicitly o/w timeline goes wider that screen for some reason
    var width = Math.max(this.el.width(), this.el.find('.recline-timeline').width());
    if (width) {
      $timeline.width(width);
    }
    var config = {};
    var data = this._timelineJSON();
    this.timeline.init(data, this.elementId, config);
    this._timelineIsInitialized = true
  },

  reloadData: function() {
    if (this._timelineIsInitialized) {
      var data = this._timelineJSON();
      this.timeline.reload(data);
    }
  },

  // Convert record to JSON for timeline
  //
  // Designed to be overridden in client apps
  convertRecord: function(record, fields) {
    return this._convertRecord(record, fields);
  },

  // Internal method to generate a Timeline formatted entry
  _convertRecord: function(record, fields) {
    var start = this._parseDate(record.get(this.state.get('startField')));
    var end = this._parseDate(record.get(this.state.get('endField')));
    if (start) {
      var tlEntry = {
        "startDate": start,
        "endDate": end,
        "headline": String(record.get('title') || ''),
        "text": record.get('description') || record.summary()
      };
      return tlEntry;
    } else {
      return null;
    }
  },

  _timelineJSON: function() {
    var self = this;
    var out = {
      'timeline': {
        'type': 'default',
        'headline': '',
        'date': [
        ]
      }
    };
    this.model.currentRecords.each(function(record) {
      var newEntry = self.convertRecord(record, self.fields);
      if (newEntry) {
        out.timeline.date.push(newEntry);
      }
    });
    // if no entries create a placeholder entry to prevent Timeline crashing with error
    if (out.timeline.date.length === 0) {
      var tlEntry = {
        "startDate": '2000,1,1',
        "headline": 'No data to show!'
      };
      out.timeline.date.push(tlEntry);
    }
    return out;
  },

  _parseDate: function(date) {
    if (!date) {
      return null;
    }
    var out = date.trim();
    out = out.replace(/(\d)th/g, '$1');
    out = out.replace(/(\d)st/g, '$1');
    out = out.trim() ? moment(out) : null;
    if (out.toDate() == 'Invalid Date') {
      return null;
    } else {
      // fix for moment weirdness around date parsing and time zones
      // moment('1914-08-01').toDate() => 1914-08-01 00:00 +01:00
      // which in iso format (with 0 time offset) is 31 July 1914 23:00
      // meanwhile native new Date('1914-08-01') => 1914-08-01 01:00 +01:00
      out = out.subtract('minutes', out.zone());
      return out.toDate();
    }
  },

  _setupTemporalField: function() {
    this.state.set({
      startField: this._checkField(this.startFieldNames),
      endField: this._checkField(this.endFieldNames)
    });
  },

  _checkField: function(possibleFieldNames) {
    var modelFieldNames = this.model.fields.pluck('id');
    for (var i = 0; i < possibleFieldNames.length; i++){
      for (var j = 0; j < modelFieldNames.length; j++){
        if (modelFieldNames[j].toLowerCase() == possibleFieldNames[i].toLowerCase())
          return modelFieldNames[j];
      }
    }
    return null;
  }
});

})(jQuery, recline.View);
<commit_msg>[bugfix,timeline][xs]: but VMM.debug = false inside guard for VMM being defined.<commit_after>/*jshint multistr:true */

this.recline = this.recline || {};
this.recline.View = this.recline.View || {};

(function($, my) {
// turn off unnecessary logging from VMM Timeline
if (typeof VMM !== 'undefined') {
  VMM.debug = false;
}

// ## Timeline
//
// Timeline view using http://timeline.verite.co/
my.Timeline = Backbone.View.extend({
  tagName:  'div',

  template: ' \

 \

 \

 \
  ',

  // These are the default (case-insensitive) names of field that are used if found.
  // If not found, the user will need to define these fields on initialization
  startFieldNames: ['date','startdate', 'start', 'start-date'],
  endFieldNames: ['end','endDate'],
  elementId: '#vmm-timeline-id',

  initialize: function(options) {
    var self = this;
    this.el = $(this.el);
    this.timeline = new VMM.Timeline();
    this._timelineIsInitialized = false;
    this.bind('view:show', function() {
      // only call _initTimeline once view in DOM as Timeline uses $ internally to look up element
      if (self._timelineIsInitialized === false) {
        self._initTimeline();
      }
    });
    this.model.fields.bind('reset', function() {
      self._setupTemporalField();
    });
    this.model.currentRecords.bind('all', function() {
      self.reloadData();
    });
    var stateData = _.extend({
        startField: null,
        endField: null
      },
      options.state
    );
    this.state = new recline.Model.ObjectState(stateData);
    this._setupTemporalField();
    this.render();
    // can only call _initTimeline once view in DOM as Timeline uses $
    // internally to look up element
    if ($(this.elementId).length > 0) {
      this._initTimeline();
    }
  },

  render: function() {
    var tmplData = {};
    var htmls = Mustache.render(this.template, tmplData);
    this.el.html(htmls);
  },

  _initTimeline: function() {
    var $timeline = this.el.find(this.elementId);
    // set width explicitly o/w timeline goes wider that screen for some reason
    var width = Math.max(this.el.width(), this.el.find('.recline-timeline').width());
    if (width) {
      $timeline.width(width);
    }
    var config = {};
    var data = this._timelineJSON();
    this.timeline.init(data, this.elementId, config);
    this._timelineIsInitialized = true
  },

  reloadData: function() {
    if (this._timelineIsInitialized) {
      var data = this._timelineJSON();
      this.timeline.reload(data);
    }
  },

  // Convert record to JSON for timeline
  //
  // Designed to be overridden in client apps
  convertRecord: function(record, fields) {
    return this._convertRecord(record, fields);
  },

  // Internal method to generate a Timeline formatted entry
  _convertRecord: function(record, fields) {
    var start = this._parseDate(record.get(this.state.get('startField')));
    var end = this._parseDate(record.get(this.state.get('endField')));
    if (start) {
      var tlEntry = {
        "startDate": start,
        "endDate": end,
        "headline": String(record.get('title') || ''),
        "text": record.get('description') || record.summary()
      };
      return tlEntry;
    } else {
      return null;
    }
  },

  _timelineJSON: function() {
    var self = this;
    var out = {
      'timeline': {
        'type': 'default',
        'headline': '',
        'date': [
        ]
      }
    };
    this.model.currentRecords.each(function(record) {
      var newEntry = self.convertRecord(record, self.fields);
      if (newEntry) {
        out.timeline.date.push(newEntry);
      }
    });
    // if no entries create a placeholder entry to prevent Timeline crashing with error
    if (out.timeline.date.length === 0) {
      var tlEntry = {
        "startDate": '2000,1,1',
        "headline": 'No data to show!'
      };
      out.timeline.date.push(tlEntry);
    }
    return out;
  },

  _parseDate: function(date) {
    if (!date) {
      return null;
    }
    var out = date.trim();
    out = out.replace(/(\d)th/g, '$1');
    out = out.replace(/(\d)st/g, '$1');
    out = out.trim() ? moment(out) : null;
    if (out.toDate() == 'Invalid Date') {
      return null;
    } else {
      // fix for moment weirdness around date parsing and time zones
      // moment('1914-08-01').toDate() => 1914-08-01 00:00 +01:00
      // which in iso format (with 0 time offset) is 31 July 1914 23:00
      // meanwhile native new Date('1914-08-01') => 1914-08-01 01:00 +01:00
      out = out.subtract('minutes', out.zone());
      return out.toDate();
    }
  },

  _setupTemporalField: function() {
    this.state.set({
      startField: this._checkField(this.startFieldNames),
      endField: this._checkField(this.endFieldNames)
    });
  },

  _checkField: function(possibleFieldNames) {
    var modelFieldNames = this.model.fields.pluck('id');
    for (var i = 0; i < possibleFieldNames.length; i++){
      for (var j = 0; j < modelFieldNames.length; j++){
        if (modelFieldNames[j].toLowerCase() == possibleFieldNames[i].toLowerCase())
          return modelFieldNames[j];
      }
    }
    return null;
  }
});

})(jQuery, recline.View);
<|endoftext|>


<commit_before>import {filter, find} from 'lodash'

window.usa = {lat: 37.09024, lng: -95.712891};
window.defaultLocation = usa;
window.originalHeight;

window.mapView = {
    settings: {
        zoomLevel: {city: 14, country: 3},
        images: {
            currentLocation: 'google_marker_blue_icon.png',
            place : 'google_marker_red_icon.png',
            selected : 'google_marker_green_icon.png'
        }
    },
    lastKnownLocation: defaultLocation,
    initMap: (places) => {
        //Create the map first (Don't wait for location)
        mapView.createMap();

        //Center map once location is obtained
        buildfire.geo.getCurrentPosition({}, (err, position) => {
            if(!err && position && position.coords){
                mapView.lastKnownLocation = {lat: position.coords.latitude, lng: position.coords.longitude};

                //window.map.setCenter(mapView.lastKnownLocation);
                //window.map.setZoom(mapView.settings.zoomLevel.city);

                mapView.addMarker(map, mapView.lastKnownLocation, mapView.settings.images.currentLocation);
            }
        });

        //TODO: If there is only one entry, it returns an object (not an array)
        if(places && places.length){
            places.forEach((place) => {
                mapView.addMarker(map, place, mapView.settings.images.place);
            });

            let clusterOptions = {
                gridSize: 53,
                styles: [
                    {
                        textColor: 'white',
                        url: 'https://czi3m2qn.cloudimg.io/s/width/53/https://app.buildfire.com/app/media/google_marker_blue_icon2.png',
                        height: 53,
                        width: 53
                    }
                ],
                maxZoom: 15
            };

            // Add a marker clusterer to manage the markers.
            new MarkerClusterer(map, app.state.markers, clusterOptions);

            map.fitBounds(app.state.bounds);
        }
    },
    updateMap: (newPlaces) => {
        //Add new markers
        newPlaces.forEach((place) => {
            mapView.addMarker(map, place, mapView.settings.images.place);
        });
    },
    filterMap: (preFilteredPlaces, postfilteredPlaces) => {
        //Find places that were filtered (to be removed)
        let removedPlaces = filter(preFilteredPlaces, (preFilteredPlace) => { return !find(postfilteredPlaces, preFilteredPlace)});

        removedPlaces.forEach((removedPlace) => {
            console.error('Removed Place', removedPlace, app.state.markers);
        });

        //Find places that were added back
        let addedPlaces = filter(postfilteredPlaces, (postFilteredPlace) => { return !find(preFilteredPlaces, postFilteredPlace)});

        console.error('addedPlaces', addedPlaces);
    },
    centerMap: () => { window.map.setCenter(mapView.lastKnownLocation) },
    addMarker: (map, place, iconType) => {
        let marker = new google.maps.Marker({
            position: place.address,
            map: map,
            icon: mapView.createMarker(iconType)
        });

        if(place.address){
            let lat = place.address.lat,
                lng = place.address.lng;

            app.state.markers.push(marker);
            app.state.bounds.extend({lat, lng});

            marker.addListener('click', () => {mapView.markerClick(place, marker)});
        }
    },
    markerClick: (place, marker) => {
        //Show the location as selected
        marker.setIcon(mapView.createMarker(mapView.settings.images.selected));

        place.marker = marker;

        app.state.selectedPlace.unshift(place);

        //Mark the other locations as not selected
        if(app.state.selectedPlace.length > 1 && app.state.selectedPlace[1].marker){
            app.state.selectedPlace[1].marker.setIcon(mapView.createMarker(mapView.settings.images.place));
        }

        let locationDetails = document.getElementById('locationDetails');
        let titleDiv = locationDetails.querySelector('#name');
        let addressDiv = locationDetails.querySelector('#address');
        let distanceDiv = locationDetails.querySelector('#distance');
        let closeDiv = locationDetails.querySelector('#close');
        let arrowDiv = locationDetails.querySelector('#arrow');

        titleDiv.innerHTML = place.title;

        addressDiv.innerHTML = place.address.name;

        if((typeof place.distance !== 'undefined')){
            distanceDiv.innerHTML = place.distance;
            distanceDiv.style.paddingRight = '5px';
            arrowDiv.style.visibility = 'visible';
        }

        closeDiv.innerHTML = '&times';

        locationDetails.onclick = e => {
            e.preventDefault();
            router.navigate(app.settings.viewStates.detail);
        };

        closeDiv.onclick = e => {
            e.stopPropagation();

            titleDiv.innerHTML = '';
            distanceDiv.innerHTML = '';
            closeDiv.innerHTML = '';
            locationDetails.style.height = 0;
            app.views.mapView.style.height = `${originalHeight}px`;

            //Un-select location
            app.state.selectedPlace[0]
                .marker.setIcon(mapView.createMarker(mapView.settings.images.place));
            app.state.selectedPlace.shift();
        };

        locationDetails.style.cursor = 'pointer';

        const detailsSize = 100;

        locationDetails.style.height = `${detailsSize}px`;

        if(app.views.mapView.getBoundingClientRect().height === originalHeight){
            let newHeight = originalHeight - detailsSize;
            app.views.mapView.style.height = `${newHeight}px`;
        }
    },
    createMarker:(imageType) => {
        const iconBaseUrl = 'https://app.buildfire.com/app/media/';

        return {
            url: iconBaseUrl + imageType,
            // This marker is 20 pixels wide by 20 pixels high.
            scaledSize: new google.maps.Size(20, 20),
            // The origin for this image is (0, 0).
            origin: new google.maps.Point(0, 0),
            // The anchor for this image is at the center of the circle
            anchor: new google.maps.Point(10, 10)
        };
    },
    createMap: () =>{
        let mapTypeId = google.maps.MapTypeId.ROADMAP,
            zoomPosition = google.maps.ControlPosition.RIGHT_TOP;

        let zoomTo = (mapView.lastKnownLocation != defaultLocation) ? mapView.settings.zoomLevel.city : mapView.settings.zoomLevel.country,
            centerOn = (mapView.lastKnownLocation != defaultLocation) ? mapView.lastKnownLocation : defaultLocation ;

        let options = {
            streetViewControl: false,
            mapTypeControl: false,
            fullscreenControl: false,
            zoom: zoomTo,
            center: centerOn,
            mapTypeId: mapTypeId,
            zoomControlOptions: {
                position: zoomPosition
            }
        };

        window.map = new google.maps.Map(document.getElementById('googleMap'), options);

        app.state.bounds = new google.maps.LatLngBounds();

        let filterDiv = document.getElementById('mapFilter');
        let centerDiv = document.getElementById('mapCenter');

        new CenterControl(centerDiv);
        new FilterControl(filterDiv);

        window.originalHeight = (app.views.mapView) ? app.views.mapView.getBoundingClientRect().height: 0;
    }
};<commit_msg>WIP filtering refactor<commit_after>import {filter, find} from 'lodash'

window.usa = {lat: 37.09024, lng: -95.712891};
window.defaultLocation = usa;
window.originalHeight;

window.mapView = {
    settings: {
        zoomLevel: {city: 14, country: 3},
        images: {
            currentLocation: 'google_marker_blue_icon.png',
            place : 'google_marker_red_icon.png',
            selected : 'google_marker_green_icon.png'
        }
    },
    lastKnownLocation: defaultLocation,
    initMap: (places) => {
        //Create the map first (Don't wait for location)
        mapView.createMap();

        //Center map once location is obtained
        buildfire.geo.getCurrentPosition({}, (err, position) => {
            if(!err && position && position.coords){
                mapView.lastKnownLocation = {lat: position.coords.latitude, lng: position.coords.longitude};

                //window.map.setCenter(mapView.lastKnownLocation);
                //window.map.setZoom(mapView.settings.zoomLevel.city);

                mapView.addMarker(map, mapView.lastKnownLocation, mapView.settings.images.currentLocation);
            }
        });

        //TODO: If there is only one entry, it returns an object (not an array)
        if(places && places.length){
            places.forEach((place) => {
                mapView.addMarker(map, place, mapView.settings.images.place);
            });

            let clusterOptions = {
                gridSize: 53,
                styles: [
                    {
                        textColor: 'white',
                        url: 'https://czi3m2qn.cloudimg.io/s/width/53/https://app.buildfire.com/app/media/google_marker_blue_icon2.png',
                        height: 53,
                        width: 53
                    }
                ],
                maxZoom: 15
            };

            // Add a marker clusterer to manage the markers.
            new MarkerClusterer(map, app.state.markers, clusterOptions);

            map.fitBounds(app.state.bounds);
        }
    },
    updateMap: (newPlaces) => {
        //Add new markers
        newPlaces.forEach((place) => {
            mapView.addMarker(map, place, mapView.settings.images.place);
        });
    },
    filterMap: (preFilteredPlaces, postfilteredPlaces) => {
        //Find places that were filtered (to be removed)
        let removedPlaces = filter(preFilteredPlaces, (preFilteredPlace) => { return !find(postfilteredPlaces, preFilteredPlace)});

        removedPlaces.filter((removedPlace) => {
            app.state.markers.forEach((marker) =>{
                let lat = marker.getPosition().lat(),
                    lng = marker.getPosition().lng();

                const isMatch  = (removedPlace.address.lat === lat && removedPlace.address.lng === lng);

                if(isMatch){
                    console.error('Removed', removedPlace.title);
                    marker.setMap(null);
                    marker = null;
                    //TODO: Need to deal with marker clusters
                }

                return !isMatch;
            })

        });

        //Find places that were added back
        let addedPlaces = filter(postfilteredPlaces, (postFilteredPlace) => { return !find(preFilteredPlaces, postFilteredPlace)});

        //console.error('addedPlaces', addedPlaces);
    },
    centerMap: () => { window.map.setCenter(mapView.lastKnownLocation) },
    addMarker: (map, place, iconType) => {
        let marker = new google.maps.Marker({
            position: place.address,
            map: map,
            icon: mapView.createMarker(iconType)
        });

        if(place.address){
            let lat = place.address.lat,
                lng = place.address.lng;

            app.state.markers.push(marker);
            app.state.bounds.extend({lat, lng});

            marker.addListener('click', () => {mapView.markerClick(place, marker)});
        }
    },
    markerClick: (place, marker) => {
        //Show the location as selected
        marker.setIcon(mapView.createMarker(mapView.settings.images.selected));

        place.marker = marker;

        app.state.selectedPlace.unshift(place);

        //Mark the other locations as not selected
        if(app.state.selectedPlace.length > 1 && app.state.selectedPlace[1].marker){
            app.state.selectedPlace[1].marker.setIcon(mapView.createMarker(mapView.settings.images.place));
        }

        let locationDetails = document.getElementById('locationDetails');
        let titleDiv = locationDetails.querySelector('#name');
        let addressDiv = locationDetails.querySelector('#address');
        let distanceDiv = locationDetails.querySelector('#distance');
        let closeDiv = locationDetails.querySelector('#close');
        let arrowDiv = locationDetails.querySelector('#arrow');

        titleDiv.innerHTML = place.title;

        addressDiv.innerHTML = place.address.name;

        if((typeof place.distance !== 'undefined')){
            distanceDiv.innerHTML = place.distance;
            distanceDiv.style.paddingRight = '5px';
            arrowDiv.style.visibility = 'visible';
        }

        closeDiv.innerHTML = '&times';

        locationDetails.onclick = e => {
            e.preventDefault();
            router.navigate(app.settings.viewStates.detail);
        };

        closeDiv.onclick = e => {
            e.stopPropagation();

            titleDiv.innerHTML = '';
            distanceDiv.innerHTML = '';
            closeDiv.innerHTML = '';
            locationDetails.style.height = 0;
            app.views.mapView.style.height = `${originalHeight}px`;

            //Un-select location
            app.state.selectedPlace[0]
                .marker.setIcon(mapView.createMarker(mapView.settings.images.place));
            app.state.selectedPlace.shift();
        };

        locationDetails.style.cursor = 'pointer';

        const detailsSize = 100;

        locationDetails.style.height = `${detailsSize}px`;

        if(app.views.mapView.getBoundingClientRect().height === originalHeight){
            let newHeight = originalHeight - detailsSize;
            app.views.mapView.style.height = `${newHeight}px`;
        }
    },
    createMarker:(imageType) => {
        const iconBaseUrl = 'https://app.buildfire.com/app/media/';

        return {
            url: iconBaseUrl + imageType,
            // This marker is 20 pixels wide by 20 pixels high.
            scaledSize: new google.maps.Size(20, 20),
            // The origin for this image is (0, 0).
            origin: new google.maps.Point(0, 0),
            // The anchor for this image is at the center of the circle
            anchor: new google.maps.Point(10, 10)
        };
    },
    createMap: () =>{
        let mapTypeId = google.maps.MapTypeId.ROADMAP,
            zoomPosition = google.maps.ControlPosition.RIGHT_TOP;

        let zoomTo = (mapView.lastKnownLocation != defaultLocation) ? mapView.settings.zoomLevel.city : mapView.settings.zoomLevel.country,
            centerOn = (mapView.lastKnownLocation != defaultLocation) ? mapView.lastKnownLocation : defaultLocation ;

        let options = {
            streetViewControl: false,
            mapTypeControl: false,
            fullscreenControl: false,
            zoom: zoomTo,
            center: centerOn,
            mapTypeId: mapTypeId,
            zoomControlOptions: {
                position: zoomPosition
            }
        };

        window.map = new google.maps.Map(document.getElementById('googleMap'), options);

        app.state.bounds = new google.maps.LatLngBounds();

        let filterDiv = document.getElementById('mapFilter');
        let centerDiv = document.getElementById('mapCenter');

        new CenterControl(centerDiv);
        new FilterControl(filterDiv);

        window.originalHeight = (app.views.mapView) ? app.views.mapView.getBoundingClientRect().height: 0;
    }
};<|endoftext|>


<commit_before>//= require ember
//= require ember-data

Frabjous.Presence = DS.Model.extend({
  from:      DS.attr('jidString'),
  to:        DS.attr('jidString'),
  type:      DS.attr('string'),
  status:    DS.attr('string'),
  show:      DS.attr('string'),
  subject:   DS.attr('string'),
  priority:  DS.attr('number'),
  contact:   DS.belongsTo('Frabjous.Contact'),
  didLoad: function(){
    var contact;
    var type              = Frabjous.Contact;
    var contact_id        = this.get('from').toString();
    var contact_client_id = Frabjous.Store.clientIdForId(type, contact_id);

    if( Ember.none(contact_client_id) ){
      // No contact exists, so create one
      Frabjous.Store.load(type,{jid: this.get('from'), _presence_history:[this.get('id')]});
      contact = Frabjous.Store.find(type,contact_id);
    }else{
      // Update contact
      contact = Frabjous.Store.find(type,contact_id);
      contact.get('_presence_history').addObject(this);
    }

    this.set('contact',contact);
  }
});

Frabjous.Contact.reopen({
  // Allows me to override the ordering in XEP-0203, I don't like this method
  _presence_history: DS.hasMany('Frabjous.Presence'),
  presence: function(){
    return this.get('presence_history').get('lastObject');
  }.property('presence_history')
});

Frabjous.Parser.register("Presence", function(stanza){

  if( stanza.is_presence() ){
    var parsed = {};
    parsed.id       = stanza.id();
    parsed.from     = stanza.from();
    parsed.to       = stanza.to();
    parsed.type     = stanza.type();
    parsed.show     = stanza.root().find('show').text();
    parsed.status   = stanza.root().find('status').text();
    parsed.priority = parseInt(stanza.root().find('priority').text(),10) || 0;
    parsed.frabjous_type = Frabjous.Presence;
    return parsed;
  }

});<commit_msg>Fix: Make presence class work without xep-0203<commit_after>//= require ember
//= require ember-data
//= require ./contact

Frabjous.Presence = DS.Model.extend({
  from:      DS.attr('jidString'),
  to:        DS.attr('jidString'),
  type:      DS.attr('string'),
  status:    DS.attr('string'),
  show:      DS.attr('string'),
  subject:   DS.attr('string'),
  priority:  DS.attr('number'),
  contact:   DS.belongsTo('Frabjous.Contact'),
  didLoad: function(){
    var contact;
    var type              = Frabjous.Contact;
    var contact_id        = this.get('from').toString();
    var contact_client_id = Frabjous.Store.clientIdForId(type, contact_id);

    if( Ember.none(contact_client_id) ){
      // No contact exists, so create one
      Frabjous.Store.load(type,{jid: this.get('from'), _presence_history:[this.get('id')]});
      contact = Frabjous.Store.find(type,contact_id);
    }else{
      // Update contact
      contact = Frabjous.Store.find(type,contact_id);
      contact.get('_presence_history').addObject(this);
    }

    this.set('contact',contact);
  }
});

Frabjous.Contact.reopen({
  // Allows me to override the ordering in XEP-0203, I don't like this method
  _presence_history: DS.hasMany('Frabjous.Presence'),
  presence_history: function(){ return this.get('_presence_history'); }.property('_presence_history'),
  presence: function(){
    return this.get('presence_history').get('lastObject');
  }.property('presence_history')
});

Frabjous.Parser.register("Presence", function(stanza){

  if( stanza.is_presence() ){
    var parsed = {};
    parsed.id       = stanza.id();
    parsed.from     = stanza.from();
    parsed.to       = stanza.to();
    parsed.type     = stanza.type();
    parsed.show     = stanza.root().find('show').text();
    parsed.status   = stanza.root().find('status').text();
    parsed.priority = parseInt(stanza.root().find('priority').text(),10) || 0;
    parsed.frabjous_type = Frabjous.Presence;
    return parsed;
  }

});<|endoftext|>