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

'use strict';

(function() {
  if (!('fetch' in window)) {
    return;  // basic feature detection: from Mobile Safari 10.3+
  }

  const capableDisplayModes = ['standalone', 'fullscreen', 'minimal-ui'];
  const defaultSplashColor = '#f8f9fa';
  const defaultSplashTextSize = 24;
  const idealSplashIconSize = 128;
  const minimumSplashIconSize = 48;
  const splashIconPadding = 32;

  const isSafari = (navigator.vendor && navigator.vendor.indexOf('Apple') !== -1);
  const isEdge = (navigator.userAgent && navigator.userAgent.indexOf('Edge') !== -1);
  const isEdgePWA = (typeof Windows !== 'undefined');

  function setup() {
    const manifestEl = document.head.querySelector('link[rel="manifest"]');
    const manifestHref = manifestEl ? manifestEl.href : '';
    const hrefFactory = buildHrefFactory([manifestHref, window.location]);

    Promise.resolve()
        .then(() => {
          if (!manifestHref) {
            throw `can't find <link rel="manifest" href=".." />'`;
          }
          const opts = /** @type {!RequestInit} */ ({});
          if (manifestHref.crossOrigin === 'use-credentials') {
            opts.credentials = 'include';
          }
          return window.fetch(manifestHref, opts);
        })
        .then((response) => response.json())
        .then((data) => process(data, hrefFactory))
        .catch((err) => console.warn('pwacompat.js error', err));
  }

  /**
   * @param {!Array<string>} options
   * @return {function(string): string}
   */
  function buildHrefFactory(options) {
    for (let i = 0; i < options.length; ++i) {
      const opt = options[i];
      try {
        new URL('', opt);
        return (part) => (new URL(part, opt)).toString();
      } catch (e) {}
    }
    return (part) => part;
  }

  function push(localName, attr) {
    const node = document.createElement(localName);
    for (const k in attr) {
      node.setAttribute(k, attr[k]);
    }
    document.head.appendChild(node);
    return node;
  }

  function meta(name, content) {
    if (content) {
      if (content === true) {
        content = 'yes';
      }
      push('meta', {name, content});
    }
  }

  /**
   * @param {!Object<string, (string|*)>} manifest
   * @param {function(string): string} urlFactory
   */
  function process(manifest, urlFactory) {
    const icons = manifest['icons'] || [];
    icons.sort((a, b) => parseInt(b.sizes, 10) - parseInt(a.sizes, 10));  // largest first
    const appleTouchIcons = icons.map((icon) => {
      // create icons as byproduct
      const attr = {'rel': 'icon', 'href': urlFactory(icon['src']), 'sizes': icon['sizes']};
      push('link', attr);
      if (isSafari) {
        attr['rel'] = 'apple-touch-icon';
        return push('link', attr);
      }
    });

    const display = manifest['display'];
    const isCapable = capableDisplayModes.indexOf(display) !== -1;
    meta('mobile-web-app-capable', isCapable);
    updateThemeColorRender(/** @type {string} */ (manifest['theme_color']) || 'black');

    if (isEdge) {
      // TODO(samthor): This could support IE9+'s "pinned sites" feature.
      meta('application-name', manifest['short_name']);
      meta('msapplication-tooltip', manifest['description']);
      meta('msapplication-starturl', manifest['start_url'] || '/');
      meta('msapplication-TileColor', manifest['theme_color']);
    }

    // nb: we check, but this won't override any _earlier_ (in DOM order) theme-color
    if (!document.head.querySelector('[name="theme-color"]')) {
      meta('theme-color', manifest['theme_color']);
    }

    // TODO(samthor): We don't detect QQ or UC, we just set the vars anyway.
    const orientation = simpleOrientationFor(manifest['orientation']);
    meta('x5-orientation', orientation);      // QQ
    meta('screen-orientation', orientation);  // UC
    if (display === 'fullscreen') {
      meta('x5-fullscreen', 'true');  // QQ
      meta('full-screen', 'yes');     // UC
    } else if (isCapable) {
      meta('x5-page-mode', 'app');         // QQ
      meta('browsermode', 'application');  // UC
    }

    if (!isSafari) {
      return;  // the rest of this file is for Safari
    }

    const backgroundIsLight = shouldUseLightForeground(
        /** @type {string} */ (manifest['background_color']) || defaultSplashColor);
    const title = manifest['name'] || manifest['short_name'] || document.title;

    // Add related iTunes app from manifest.
    const itunes = findAppleId(manifest['related_applications']);
    itunes && meta('apple-itunes-app', `app-id=${itunes}`);

    // General iOS meta tags.
    meta('apple-mobile-web-app-capable', isCapable);
    meta('apple-mobile-web-app-title', title);

    function splashFor({width, height}, orientation, icon) {
      const ratio = window.devicePixelRatio;
      const ctx = contextForCanvas({width: width * ratio, height: height * ratio});

      ctx.scale(ratio, ratio);
      ctx.fillStyle = manifest['background_color'] || defaultSplashColor;
      ctx.fillRect(0, 0, width, height);
      ctx.translate(width / 2, (height - splashIconPadding) / 2);

      ctx.font = `${defaultSplashTextSize}px HelveticaNeue-CondensedBold`;
      ctx.fillStyle = backgroundIsLight ? 'white' : 'black';
      const textWidth = ctx.measureText(title).width;

      if (icon) {
        // nb: on Chrome, we need the image >=48px, use the big layout >=80dp, ideal is >=128dp
        let iconWidth = (icon.width / ratio);
        let iconHeight = (icon.height / ratio);
        if (iconHeight > idealSplashIconSize) {
          // clamp to 128px height max
          iconWidth /= (iconHeight / idealSplashIconSize);
          iconHeight = idealSplashIconSize;
        }

        if (iconWidth >= minimumSplashIconSize && iconHeight >= minimumSplashIconSize) {
          ctx.drawImage(icon, iconWidth / -2, iconHeight / -2, iconWidth, iconHeight);
          ctx.translate(0, iconHeight / 2 + splashIconPadding);
        }
      }
      ctx.fillText(title, textWidth / -2, 0);

      const generatedSplash = document.createElement('link');
      generatedSplash.setAttribute('rel', 'apple-touch-startup-image');
      generatedSplash.setAttribute('media', `(orientation: ${orientation})`);
      generatedSplash.setAttribute('href', ctx.canvas.toDataURL());

      return generatedSplash;
    }

    const previous = new Set();
    function updateSplash(applicationIcon) {
      const portrait = splashFor(window.screen, 'portrait', applicationIcon);
      const landscape = splashFor({
        width: window.screen.height,
        height: window.screen.width,
      }, 'landscape', applicationIcon);

      previous.forEach((prev) => prev.remove());

      document.head.appendChild(portrait);
      document.head.appendChild(landscape);
      previous.add(portrait);
      previous.add(landscape);
    }
    updateSplash(null);

    // fetch the largest icon to generate a splash screen
    if (!appleTouchIcons.length) {
      return;
    }
    const icon = appleTouchIcons[0];
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      updateSplash(img);

      // also check and redraw icon
      if (!manifest['background_color']) {
        return;
      }
      const redrawn = updateTransparent(img, manifest['background_color']);
      if (redrawn === null) {
        return;  // the rest probably aren't interesting either
      }
      icon.href = redrawn;

      // fetch and fix all remaining icons
      appleTouchIcons.slice(1).forEach((icon) => {
        const img = new Image();
        img.crossOrigin = 'anonymous';
        img.onload = () => {
          const redrawn = updateTransparent(img, manifest['background_color'], true);
          icon.href = redrawn;
        };
        img.src = icon.href;
      });

    };
    img.src = icon.href;
  }

  function findAppleId(related) {
    let itunes;
    (related || [])
        .filter((app) => app['platform'] === 'itunes')
        .forEach((app) => {
          if (app['id']) {
            itunes = app['id'];
          } else {
            const match = app['url'].match(/id(\d+)/);
            if (match) {
              itunes = match[1];
            }
          }
        });
    return itunes;
  }

  function simpleOrientationFor(v) {
    v = String(v || '');
    const prefix = v.substr(0, 3);
    if (prefix === 'por') {
      return 'portrait';
    } else if (prefix === 'lan') {
      return 'landscape';
    }
    return '';
  }

  /**
   * @param {string} color
   */
  function updateThemeColorRender(color) {
    if (!(isSafari || isEdgePWA)) {
      return;
    }

    const themeIsLight = shouldUseLightForeground(color);
    if (isSafari) {
      // nb. Safari 11.3+ gives a deprecation warning about this meta tag.
      // TODO(samthor): Potentially set black-translucent in 'fullscreen'.
      meta('apple-mobile-web-app-status-bar-style', themeIsLight ? 'black' : 'default');
    } else {
      // Edge PWA
      const t = getEdgeTitleBar();
      if (t === null) {
        console.debug('UWP no titleBar')
        return;
      }
      t.foregroundColor = colorToWindowsRGBA(themeIsLight ? 'black' : 'white');
      t.backgroundColor = colorToWindowsRGBA(color);
    }
  }

  /**
   * @return {?ApplicationViewTitleBar}
   */
  function getEdgeTitleBar() {
    try {
      return Windows.UI.ViewManagement.ApplicationView.getForCurrentView().titleBar;
    } catch (e) {
      return null;
    }
  }

  /**
   * The Windows titlebar APIs expect an object of {r, g, b, a}.
   *
   * @param {string} color
   * @return {WindowsColor}
   */
  function colorToWindowsRGBA(color) {
    const data = readColor(color);
    return /** @type {WindowsColor} */ ({
      'r': data[0],
      'g': data[1],
      'b': data[2],
      'a': data[3],
    });
  }

  /**
   * @param {string} color
   * @return {!Uint8ClampedArray}
   */
  function readColor(color) {
    const c = contextForCanvas();
    c.fillStyle = color;
    c.fillRect(0, 0, 1, 1);
    return c.getImageData(0, 0, 1, 1).data;
  }

  /**
   * @param {string} color
   * @return {boolean}
   */
  function shouldUseLightForeground(color) {
    const pixelData = readColor(color);

    // From https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/util/ColorUtils.java
    const data = pixelData.map((v) => {
      const f = v / 255;
      return (f < 0.03928) ? f / 12.92 : Math.pow((f + 0.055) / 1.055, 2.4);
    });
    const lum = 0.2126 * data[0] + 0.7152 * data[1] + 0.0722 * data[2];
    const contrast = Math.abs((1.05) / (lum + 0.05));
    return contrast > 3;
  }

  function updateTransparent(image, background, force=false) {
    const context = contextForCanvas(image);
    context.drawImage(image, 0, 0);

    // look for transparent pixel in top-left
    // TODO: Chrome actually checks the four corners for some cases.
    if (!force) {
      const imageData = context.getImageData(0, 0, 1, 1);
      if (imageData.data[3] == 255) {
        return null;
      }
    }

    context.globalCompositeOperation = 'destination-over';  // only replace transparent areas
    context.fillStyle = background;
    context.fillRect(0, 0, image.width, image.height);
    return context.canvas.toDataURL();
  }

  function contextForCanvas({width, height} = {width: 1, height: 1}) {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    return canvas.getContext('2d');
  }

  // actually run PWACompat here
  if (document.readyState === 'complete') {
    setup();
  } else {
    window.addEventListener('load', setup);
  }
}());
<commit_msg>only run complex Safari stuff on Mobile Safari<commit_after>/*
 * Copyright 2018 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

'use strict';

(function() {
  if (!('fetch' in window)) {
    return;  // basic feature detection: from Mobile Safari 10.3+
  }

  const capableDisplayModes = ['standalone', 'fullscreen', 'minimal-ui'];
  const defaultSplashColor = '#f8f9fa';
  const defaultSplashTextSize = 24;
  const idealSplashIconSize = 128;
  const minimumSplashIconSize = 48;
  const splashIconPadding = 32;

  const userAgent = navigator.userAgent || '';
  const isSafari = (navigator.vendor && navigator.vendor.indexOf('Apple') !== -1);
  const isSafariMobile = isSafari && (userAgent.indexOf('Mobile/') !== -1);
  const isEdge = (userAgent.indexOf('Edge') !== -1);
  const isEdgePWA = (typeof Windows !== 'undefined');

  function setup() {
    const manifestEl = document.head.querySelector('link[rel="manifest"]');
    const manifestHref = manifestEl ? manifestEl.href : '';
    const hrefFactory = buildHrefFactory([manifestHref, window.location]);

    Promise.resolve()
        .then(() => {
          if (!manifestHref) {
            throw `can't find <link rel="manifest" href=".." />'`;
          }
          const opts = /** @type {!RequestInit} */ ({});
          if (manifestHref.crossOrigin === 'use-credentials') {
            opts.credentials = 'include';
          }
          return window.fetch(manifestHref, opts);
        })
        .then((response) => response.json())
        .then((data) => process(data, hrefFactory))
        .catch((err) => console.warn('pwacompat.js error', err));
  }

  /**
   * @param {!Array<string>} options
   * @return {function(string): string}
   */
  function buildHrefFactory(options) {
    for (let i = 0; i < options.length; ++i) {
      const opt = options[i];
      try {
        new URL('', opt);
        return (part) => (new URL(part, opt)).toString();
      } catch (e) {}
    }
    return (part) => part;
  }

  function push(localName, attr) {
    const node = document.createElement(localName);
    for (const k in attr) {
      node.setAttribute(k, attr[k]);
    }
    document.head.appendChild(node);
    return node;
  }

  function meta(name, content) {
    if (content) {
      if (content === true) {
        content = 'yes';
      }
      push('meta', {name, content});
    }
  }

  /**
   * @param {!Object<string, (string|*)>} manifest
   * @param {function(string): string} urlFactory
   */
  function process(manifest, urlFactory) {
    const icons = manifest['icons'] || [];
    icons.sort((a, b) => parseInt(b.sizes, 10) - parseInt(a.sizes, 10));  // largest first
    const appleTouchIcons = icons.map((icon) => {
      // create icons as byproduct
      const attr = {'rel': 'icon', 'href': urlFactory(icon['src']), 'sizes': icon['sizes']};
      push('link', attr);
      if (isSafariMobile) {
        attr['rel'] = 'apple-touch-icon';
        return push('link', attr);
      }
    });

    const display = manifest['display'];
    const isCapable = capableDisplayModes.indexOf(display) !== -1;
    meta('mobile-web-app-capable', isCapable);
    updateThemeColorRender(/** @type {string} */ (manifest['theme_color']) || 'black');

    if (isEdge) {
      // TODO(samthor): This could support IE9+'s "pinned sites" feature.
      meta('application-name', manifest['short_name']);
      meta('msapplication-tooltip', manifest['description']);
      meta('msapplication-starturl', manifest['start_url'] || '/');
      meta('msapplication-TileColor', manifest['theme_color']);
    }

    // nb: we check, but this won't override any _earlier_ (in DOM order) theme-color
    if (!document.head.querySelector('[name="theme-color"]')) {
      meta('theme-color', manifest['theme_color']);
    }

    // TODO(samthor): We don't detect QQ or UC, we just set the vars anyway.
    const orientation = simpleOrientationFor(manifest['orientation']);
    meta('x5-orientation', orientation);      // QQ
    meta('screen-orientation', orientation);  // UC
    if (display === 'fullscreen') {
      meta('x5-fullscreen', 'true');  // QQ
      meta('full-screen', 'yes');     // UC
    } else if (isCapable) {
      meta('x5-page-mode', 'app');         // QQ
      meta('browsermode', 'application');  // UC
    }

    if (!isSafariMobile) {
      return;  // the rest of this file is for Safari
    }

    const backgroundIsLight = shouldUseLightForeground(
        /** @type {string} */ (manifest['background_color']) || defaultSplashColor);
    const title = manifest['name'] || manifest['short_name'] || document.title;

    // Add related iTunes app from manifest.
    const itunes = findAppleId(manifest['related_applications']);
    itunes && meta('apple-itunes-app', `app-id=${itunes}`);

    // General iOS meta tags.
    meta('apple-mobile-web-app-capable', isCapable);
    meta('apple-mobile-web-app-title', title);

    function splashFor({width, height}, orientation, icon) {
      const ratio = window.devicePixelRatio;
      const ctx = contextForCanvas({width: width * ratio, height: height * ratio});

      ctx.scale(ratio, ratio);
      ctx.fillStyle = manifest['background_color'] || defaultSplashColor;
      ctx.fillRect(0, 0, width, height);
      ctx.translate(width / 2, (height - splashIconPadding) / 2);

      if (icon) {
        // nb: on Chrome, we need the image >=48px, use the big layout >=80dp, ideal is >=128dp
        let iconWidth = (icon.width / ratio);
        let iconHeight = (icon.height / ratio);
        if (iconHeight > idealSplashIconSize) {
          // clamp to 128px height max
          iconWidth /= (iconHeight / idealSplashIconSize);
          iconHeight = idealSplashIconSize;
        }

        if (iconWidth >= minimumSplashIconSize && iconHeight >= minimumSplashIconSize) {
          ctx.drawImage(icon, iconWidth / -2, iconHeight / -2, iconWidth, iconHeight);
          ctx.translate(0, iconHeight / 2 + splashIconPadding);
        }
      }

      ctx.fillStyle = backgroundIsLight ? 'white' : 'black';
      ctx.font = `${defaultSplashTextSize}px HelveticaNeue-CondensedBold`;
      const textWidth = ctx.measureText(title).width;
      ctx.fillText(title, textWidth / -2, 0);

      const generatedSplash = document.createElement('link');
      generatedSplash.setAttribute('rel', 'apple-touch-startup-image');
      generatedSplash.setAttribute('media', `(orientation: ${orientation})`);
      generatedSplash.setAttribute('href', ctx.canvas.toDataURL());

      return generatedSplash;
    }

    const previous = new Set();
    function updateSplash(applicationIcon) {
      const portrait = splashFor(window.screen, 'portrait', applicationIcon);
      const landscape = splashFor({
        width: window.screen.height,
        height: window.screen.width,
      }, 'landscape', applicationIcon);

      previous.forEach((prev) => prev.remove());

      document.head.appendChild(portrait);
      document.head.appendChild(landscape);
      previous.add(portrait);
      previous.add(landscape);
    }
    updateSplash(null);

    // fetch the largest icon to generate a splash screen
    if (!appleTouchIcons.length) {
      return;
    }
    const icon = appleTouchIcons[0];
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      updateSplash(img);

      // also check and redraw icon
      if (!manifest['background_color']) {
        return;
      }
      const redrawn = updateTransparent(img, manifest['background_color']);
      if (redrawn === null) {
        return;  // the rest probably aren't interesting either
      }
      icon.href = redrawn;

      // fetch and fix all remaining icons
      appleTouchIcons.slice(1).forEach((icon) => {
        const img = new Image();
        img.crossOrigin = 'anonymous';
        img.onload = () => {
          const redrawn = updateTransparent(img, manifest['background_color'], true);
          icon.href = redrawn;
        };
        img.src = icon.href;
      });

    };
    img.src = icon.href;
  }

  function findAppleId(related) {
    let itunes;
    (related || [])
        .filter((app) => app['platform'] === 'itunes')
        .forEach((app) => {
          if (app['id']) {
            itunes = app['id'];
          } else {
            const match = app['url'].match(/id(\d+)/);
            if (match) {
              itunes = match[1];
            }
          }
        });
    return itunes;
  }

  function simpleOrientationFor(v) {
    v = String(v || '');
    const prefix = v.substr(0, 3);
    if (prefix === 'por') {
      return 'portrait';
    } else if (prefix === 'lan') {
      return 'landscape';
    }
    return '';
  }

  /**
   * @param {string} color
   */
  function updateThemeColorRender(color) {
    if (!(isSafariMobile || isEdgePWA)) {
      return;
    }

    const themeIsLight = shouldUseLightForeground(color);
    if (isSafariMobile) {
      // nb. Safari 11.3+ gives a deprecation warning about this meta tag.
      // TODO(samthor): Potentially set black-translucent in 'fullscreen'.
      meta('apple-mobile-web-app-status-bar-style', themeIsLight ? 'black' : 'default');
    } else {
      // Edge PWA
      const t = getEdgeTitleBar();
      if (t === null) {
        console.debug('UWP no titleBar')
        return;
      }
      t.foregroundColor = colorToWindowsRGBA(themeIsLight ? 'black' : 'white');
      t.backgroundColor = colorToWindowsRGBA(color);
    }
  }

  /**
   * @return {?ApplicationViewTitleBar}
   */
  function getEdgeTitleBar() {
    try {
      return Windows.UI.ViewManagement.ApplicationView.getForCurrentView().titleBar;
    } catch (e) {
      return null;
    }
  }

  /**
   * The Windows titlebar APIs expect an object of {r, g, b, a}.
   *
   * @param {string} color
   * @return {WindowsColor}
   */
  function colorToWindowsRGBA(color) {
    const data = readColor(color);
    return /** @type {WindowsColor} */ ({
      'r': data[0],
      'g': data[1],
      'b': data[2],
      'a': data[3],
    });
  }

  /**
   * @param {string} color
   * @return {!Uint8ClampedArray}
   */
  function readColor(color) {
    const c = contextForCanvas();
    c.fillStyle = color;
    c.fillRect(0, 0, 1, 1);
    return c.getImageData(0, 0, 1, 1).data;
  }

  /**
   * @param {string} color
   * @return {boolean}
   */
  function shouldUseLightForeground(color) {
    const pixelData = readColor(color);

    // From https://cs.chromium.org/chromium/src/chrome/android/java/src/org/chromium/chrome/browser/util/ColorUtils.java
    const data = pixelData.map((v) => {
      const f = v / 255;
      return (f < 0.03928) ? f / 12.92 : Math.pow((f + 0.055) / 1.055, 2.4);
    });
    const lum = 0.2126 * data[0] + 0.7152 * data[1] + 0.0722 * data[2];
    const contrast = Math.abs((1.05) / (lum + 0.05));
    return contrast > 3;
  }

  function updateTransparent(image, background, force=false) {
    const context = contextForCanvas(image);
    context.drawImage(image, 0, 0);

    // look for transparent pixel in top-left
    // TODO: Chrome actually checks the four corners for some cases.
    if (!force) {
      const imageData = context.getImageData(0, 0, 1, 1);
      if (imageData.data[3] == 255) {
        return null;
      }
    }

    context.globalCompositeOperation = 'destination-over';  // only replace transparent areas
    context.fillStyle = background;
    context.fillRect(0, 0, image.width, image.height);
    return context.canvas.toDataURL();
  }

  function contextForCanvas({width, height} = {width: 1, height: 1}) {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    return canvas.getContext('2d');
  }

  // actually run PWACompat here
  if (document.readyState === 'complete') {
    setup();
  } else {
    window.addEventListener('load', setup);
  }
}());
<|endoftext|>


<commit_before>'use babel'

import {Point, CompositeDisposable} from 'atom'
import {diffLines} from 'diff'
import MarkerIndex from 'marker-index'
import temp from 'temp'

class ReviewCommentTracker {
  constructor (editor) {
    this.editor = editor
    this.invalidComments = new Map
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.editor.onDidStopChanging(() => {
      let invalidComments = this.invalidComments
      this.invalidComments = new Map
      invalidComments.forEach(({fileContents, rowInFileContents}, id) => {
        this.track(id, fileContents, rowInFileContents)
      })
    }))
  }

  destroy () {
    this.subscriptions.dispose()
  }

  track (id, fileContents, rowInFileContents) {
    let index = new MarkerIndex()
    index.insert(id, {row: rowInFileContents, column: 0}, {row: rowInFileContents + 1, column: 0})
    index.setExclusive(id, true)
    let currentRow = 0
    for (let change of diffLines(fileContents, this.editor.getText())) {
      if (change.added) {
        let {inside} = index.splice({row: currentRow, column: 0}, {row: 0, column: 0}, {row: change.count, column: 0})
        if (inside.has(id)) {
          this.invalidComments.set(id, {fileContents, rowInFileContents})
          return
        }
        currentRow += change.count
      } else if (change.removed) {
        let {inside} = index.splice({row: currentRow, column: 0}, {row: change.count, column: 0}, {row: 0, column: 0})
        if (inside.has(id)) {
          this.invalidComments.set(id, {fileContents, rowInFileContents})
          return
        }
      } else {
        currentRow += change.count
      }
    }

    let marker = this.editor.markBufferRange(index.getRange(id), {reversed: true, invalidate: 'inside'})
    let subscription = marker.onDidChange(({isValid}) => {
      if (!isValid) {
        this.invalidComments.set(id, {fileContents, rowInFileContents})
        marker.destroy()
        subscription.dispose()
      }
    })
    this.editor.decorateMarker(marker, {type: 'block', position: 'after'})
  }
}

describe('ReviewCommentTracker', () => {
  let editor, foo

  beforeEach(() => {
    editor = atom.workspace.buildTextEditor()
    foo = new ReviewCommentTracker(editor)
  })

  it("adds a decoration on the same row when the buffers' contents match", () => {
    editor.setText('abc\ndef\nghi')

    foo.track(1, 'abc\ndef\nghi', 1)

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([1, 0])
  })

  it("adds a decoration on a translated row in the current buffer corresponding to row in the original buffer", () => {
    editor.setText('def\nghi\nABC\nDEF\nlmn\nopq\nrst')

    foo.track(1, 'abc\ndef\nghi\nlmn\nopq\nrst', 3)

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([4, 0])

    editor.setCursorBufferPosition([4, 0])
    editor.insertNewline()

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([5, 0])
  })

  it("doesn't add a decoration when the comment position doesn't exist anymore, and adds it back on save if it becomes valid again", () => {
    editor.setText('def\nABC\nDEF\nghi\nGHI\nJKL\nMNO\nopq\nrst')

    foo.track(1, 'abc\ndef\nghi\nlmn\nopq\nrst', 3)

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    editor.setSelectedBufferRange([[6, 0], [6, 3]])
    editor.insertText('lmn')
    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([6, 0])
  })

  it("removes decorations as soon as they become invalid and adds them back on save if they become valid again", () => {
    editor.setText('def\nghi\nABC\nDEF\nlmn\nopq\nrst')

    foo.track(1, 'abc\ndef\nghi\nlmn\nopq\nrst', 3)
    editor.setCursorBufferPosition([4, 0])
    editor.deleteLine()

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    editor.undo()
    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([4, 0])

    editor.redo()

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    editor.undo()
    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([4, 0])
  })
})
<commit_msg>Implement `trackCommentsForCommitId`<commit_after>'use babel'

import {Range, CompositeDisposable} from 'atom'
import {diffLines} from 'diff'
import MarkerIndex from 'marker-index'
import temp from 'temp'

class ReviewCommentTracker {
  constructor (editor) {
    this.editor = editor
    this.invalidCommentsByCommitId = new Map()
    this.contentsByCommitId = new Map()
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(this.editor.onDidStopChanging(() => {
      let invalidCommentsByCommitId = this.invalidCommentsByCommitId
      this.invalidCommentsByCommitId = new Map()
      for (let [commitId, rowsByCommentId] of invalidCommentsByCommitId) {
        this.trackCommentsForCommitId(commitId, this.contentsByCommitId.get(commitId), rowsByCommentId)
      }
    }))
  }

  destroy () {
    this.subscriptions.dispose()
  }

  trackCommentsForCommitId (commitId, bufferContents, rowsByCommentId) {
    let index = new MarkerIndex()
    for (let [id, row] of rowsByCommentId) {
      index.insert(id, {row: row, column: 0}, {row: row + 1, column: 0})
      index.setExclusive(id, true)
    }

    let currentRow = 0
    for (let change of diffLines(bufferContents, this.editor.getText())) {
      if (change.added) {
        let {inside} = index.splice({row: currentRow, column: 0}, {row: 0, column: 0}, {row: change.count, column: 0})
        for (let id of inside) {
          this.invalidate(commitId, bufferContents, id, rowsByCommentId.get(id))
          index.delete(id)
        }

        currentRow += change.count
      } else if (change.removed) {
        let {inside} = index.splice({row: currentRow, column: 0}, {row: change.count, column: 0}, {row: 0, column: 0})
        for (let id of inside) {
          this.invalidate(commitId, bufferContents, id, rowsByCommentId.get(id))
          index.delete(id)
        }
      } else {
        currentRow += change.count
      }
    }

    let rangesByCommentId = index.dump()
    for (let _id of Object.keys(rangesByCommentId)) {
      let id = parseInt(_id)
      let range = Range.fromObject(rangesByCommentId[id])
      let marker = this.editor.markBufferRange(range, {reversed: true, invalidate: 'inside'})
      let subscription = marker.onDidChange(({isValid}) => {
        if (!isValid) {
          this.invalidate(commitId, bufferContents, id, rowsByCommentId.get(id))
          marker.destroy()
          subscription.dispose()
        }
      })
      this.editor.decorateMarker(marker, {type: 'block', position: 'after'})
    }
  }

  track (id, fileContents, rowInFileContents) {
    // throw new Error("Don't use this interface. Use trackCommentsForCommitId()")
    let map = new Map()
    map.set(id, rowInFileContents)
    this.trackCommentsForCommitId(1234, fileContents, map)
  }

  invalidate (commitId, bufferContents, id, row) {
    if (!this.contentsByCommitId.has(commitId)) {
      this.contentsByCommitId.set(commitId, bufferContents)
    }

    if (!this.invalidCommentsByCommitId.has(commitId)) {
      this.invalidCommentsByCommitId.set(commitId, new Map())
    }

    this.invalidCommentsByCommitId.get(commitId).set(id, row)
  }
}

describe('ReviewCommentTracker', () => {
  let editor, foo

  beforeEach(() => {
    editor = atom.workspace.buildTextEditor()
    foo = new ReviewCommentTracker(editor)
  })

  it("adds a decoration on the same row when the buffers' contents match", () => {
    editor.setText('abc\ndef\nghi')

    foo.track(1, 'abc\ndef\nghi', 1)

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([1, 0])
  })

  it("adds a decoration on a translated row in the current buffer corresponding to row in the original buffer", () => {
    editor.setText('def\nghi\nABC\nDEF\nlmn\nopq\nrst')

    foo.track(1, 'abc\ndef\nghi\nlmn\nopq\nrst', 3)

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([4, 0])

    editor.setCursorBufferPosition([4, 0])
    editor.insertNewline()

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([5, 0])
  })

  it("doesn't add a decoration when the comment position doesn't exist anymore, and adds it back on save if it becomes valid again", () => {
    editor.setText('def\nABC\nDEF\nghi\nGHI\nJKL\nMNO\nopq\nrst')

    foo.track(1, 'abc\ndef\nghi\nlmn\nopq\nrst', 3)

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    editor.setSelectedBufferRange([[6, 0], [6, 3]])
    editor.insertText('lmn')
    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([6, 0])
  })

  it("removes decorations as soon as they become invalid and adds them back on save if they become valid again", () => {
    editor.setText('def\nghi\nABC\nDEF\nlmn\nopq\nrst')

    foo.track(1, 'abc\ndef\nghi\nlmn\nopq\nrst', 3)
    editor.setCursorBufferPosition([4, 0])
    editor.deleteLine()

    let decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    editor.undo()
    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([4, 0])

    editor.redo()

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(0)

    editor.undo()
    advanceClock(editor.buffer.stoppedChangingDelay)

    decorations = editor.getDecorations({type: 'block'})
    expect(decorations.length).toBe(1)
    expect(decorations[0].getMarker().getHeadBufferPosition()).toEqual([4, 0])
  })
})
<|endoftext|>


<commit_before>import Raku from '../src/Raku'
import { expect } from 'chai'

const raku = new Raku()

describe('client handle', () => {
  describe('bucket', () => {
    it('should be set to the default bucket, "default"', () => {
      expect(raku.bucket).to.eql(Raku.DEFAULT_BUCKET)
    })

    it('set the bucket state', () => {
      raku.bucket = 'wow'
      expect(raku.bucket).to.eql('wow')
    })

  }) // describe bucket

  describe('aliases', () => {
    it('set() should be an alias to put()', () => {
      expect(raku.set).to.eql(raku.put)
    })
  }) // describe aliases
}) // describe client handle

describe('put/get', () => {
  it('should be able to save integers', () => {
    raku.bucket = 'default' //Raku.DEFAULT_BUCKET
    return raku.put('x', 43)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(43)
      })
  })

  it('should be able to save decimal numbers', () => {
    return raku.put('x', 43.99)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(43.99)
      })
  })

  it('should be able to save strings', () => {
    return raku.put('x', 'hello')
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql('hello')
      })
  })

  it('should be able to save arrays', () => {
    return raku.put('x', ['hello', 42])
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(['hello', 42])
      })
  })

  it('should be able to save associative arrays', () => {
    return raku.put('x', {'x': 'yes', '0': ['z', 2, 3], 'hello': 42})
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql({'x': 'yes', '0': ['z', 2, 3], 'hello': 42})
      })
  })

  it('should be able to save null', () => {
    return raku.put('x', null)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(null)
      })
  })

  it('NOTE: undefined is saved as null', () => {
    return raku.put('x', null)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(null)
      })
  })

  it('should be able to save an empty associative array', () => {
    return raku.put('x', {})
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql({})
      })
  })

  it('should be able to save an empty array', () => {
    return raku.put('x', [])
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql([])
      })
  })

  it('should be able to save 0 normally', () => {
    return raku.put('x', 0)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(0)
      })
  })

  it('should be able to save false normally', () => {
    return raku.put('x', false)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(false )
      })
  })

}) // describe create (put)

describe('delete (del)', () => {

  it('should throw an error if the key  doesn\'t exist', () => {
    return raku.del('this-key-does-not-exist')
      .then( x => {
        expect(x).to.eql(null)
      })
  })

  it('should delete existing keys', () => {
    return
      raku.put('x', 'asdf')
      .then( () => raku.get('x') )
      .then( x => {
          expect(x).to.eql('asdf')
        })
      .then( () => raku.del('x') )
      .then( () => raku.get('x') )
      .then( x => {
          expect(x).to.eql(null)
        })
  }) // it
}) // describe

describe('get/set using non-default bucket state', () => {
  beforeEach(() => {
    raku.bucket = 'test_bucket2'
  })

  afterEach( () => {
    raku.bucket = Raku.DEFAULT_BUCKET
  })

  it('changing buckets should set a value in the new bucket', () => {
    const VALUE = 500
    return raku.set('x', VALUE)
      .then( () => VALUE )
      .then( () => raku.bget('test_bucket2', 'x') )
      .then( value => {
        expect(value).to.eql(VALUE)
      })
  })
})

describe('bset/bget', () => {
  it('should get the value at (bucket, key)', () => {
    raku.bucket = 'test_walrus'
    return raku.bset('test_walrus', 'x42', 42)
      raku.bget('test_walrus', 'x42')
      .then( val => {
        expect(val).to.eql(42)
      })
  })
})

describe('bdel', () => {
  it('should delete the value at (bucket, key)', () => {
    return raku.bset('test_mighty_mouse', 'x500', 500)
      .then( () => raku.bget('test_mighty_mouse', 'x500') )
      .then( val => {
        console.log('val:', val)
        expect(val).to.eql(500)
      })
      .then( () => raku.bdel('test_mighty_mouse', 'x500') )
      raku.bget('test_mighty_mouse', 'x500')
      .then( val => {
        expect(val).to.eql(null)
      })
  })
})

<commit_msg>removed console.log from test.<commit_after>import Raku from '../src/Raku'
import { expect } from 'chai'

const raku = new Raku()

describe('client handle', () => {
  describe('bucket', () => {
    it('should be set to the default bucket, "default"', () => {
      expect(raku.bucket).to.eql(Raku.DEFAULT_BUCKET)
    })

    it('set the bucket state', () => {
      raku.bucket = 'wow'
      expect(raku.bucket).to.eql('wow')
    })

  }) // describe bucket

  describe('aliases', () => {
    it('set() should be an alias to put()', () => {
      expect(raku.set).to.eql(raku.put)
    })
  }) // describe aliases
}) // describe client handle

describe('put/get', () => {
  it('should be able to save integers', () => {
    raku.bucket = 'default' //Raku.DEFAULT_BUCKET
    return raku.put('x', 43)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(43)
      })
  })

  it('should be able to save decimal numbers', () => {
    return raku.put('x', 43.99)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(43.99)
      })
  })

  it('should be able to save strings', () => {
    return raku.put('x', 'hello')
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql('hello')
      })
  })

  it('should be able to save arrays', () => {
    return raku.put('x', ['hello', 42])
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(['hello', 42])
      })
  })

  it('should be able to save associative arrays', () => {
    return raku.put('x', {'x': 'yes', '0': ['z', 2, 3], 'hello': 42})
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql({'x': 'yes', '0': ['z', 2, 3], 'hello': 42})
      })
  })

  it('should be able to save null', () => {
    return raku.put('x', null)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(null)
      })
  })

  it('NOTE: undefined is saved as null', () => {
    return raku.put('x', null)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(null)
      })
  })

  it('should be able to save an empty associative array', () => {
    return raku.put('x', {})
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql({})
      })
  })

  it('should be able to save an empty array', () => {
    return raku.put('x', [])
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql([])
      })
  })

  it('should be able to save 0 normally', () => {
    return raku.put('x', 0)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(0)
      })
  })

  it('should be able to save false normally', () => {
    return raku.put('x', false)
      .then( () => raku.get('x') )
      .then( x => {
        expect(x).to.eql(false )
      })
  })

}) // describe create (put)

describe('delete (del)', () => {

  it('should throw an error if the key  doesn\'t exist', () => {
    return raku.del('this-key-does-not-exist')
      .then( x => {
        expect(x).to.eql(null)
      })
  })

  it('should delete existing keys', () => {
    return
      raku.put('x', 'asdf')
      .then( () => raku.get('x') )
      .then( x => {
          expect(x).to.eql('asdf')
        })
      .then( () => raku.del('x') )
      .then( () => raku.get('x') )
      .then( x => {
          expect(x).to.eql(null)
        })
  }) // it
}) // describe

describe('get/set using non-default bucket state', () => {
  beforeEach(() => {
    raku.bucket = 'test_bucket2'
  })

  afterEach( () => {
    raku.bucket = Raku.DEFAULT_BUCKET
  })

  it('changing buckets should set a value in the new bucket', () => {
    const VALUE = 500
    return raku.set('x', VALUE)
      .then( () => VALUE )
      .then( () => raku.bget('test_bucket2', 'x') )
      .then( value => {
        expect(value).to.eql(VALUE)
      })
  })
})

describe('bset/bget', () => {
  it('should get the value at (bucket, key)', () => {
    raku.bucket = 'test_walrus'
    return raku.bset('test_walrus', 'x42', 42)
      raku.bget('test_walrus', 'x42')
      .then( val => {
        expect(val).to.eql(42)
      })
  })
})

describe('bdel', () => {
  it('should delete the value at (bucket, key)', () => {
    raku.bucket = 'default'
    return raku.bset('test_mighty_mouse', 'x500', 500)
      .then( () => raku.bget('test_mighty_mouse', 'x500') )
      .then( val => {
        expect(val).to.eql(500)
      })
      .then( () => raku.bdel('test_mighty_mouse', 'x500') )
      raku.bget('test_mighty_mouse', 'x500')
      .then( val => {
        expect(val).to.eql(null)
      })
  })
})

<|endoftext|>


<commit_before>(function(module) {
  function Inspection (options) {
    Object.keys(options).forEach(function(element, index, keys){
      this[element] = options[element];
    },this);
  }
  Inspection.current =[];
  Inspection.names =[];

  Inspection.createTable = function(callback) {
    webDB.execute(
      'CREATE TABLE IF NOT EXISTS recentInspect (' +
      'id INTEGER PRIMARY KEY, ' +
      'name VARCHAR(255), ' +
      'inspection_date DATETIME, ' +
      'inspection_score INTEGER, ' +
      'address VARCHAR(255), ' +
      'city VARCHAR(255), ' +
      'zip_code VARCHAR(255), ' +
      'phone VARCHAR(255), ' +
      'latitude DECIMAL(18,12), ' +
      'longitude DECIMAL(18,12));',
      callback
    );
  };
  Inspection.buildNames = function (anything) {
    $.get('/data/resource/gkhn-e8mn.json?$select=name&$group=name&$order=name&$limit=50000')
    .done(function(data, message, xhr) {
      Inspection.names = data.map(function(element){
        return element.name;
      });
      console.log('generated array for inspeciton.names');
      anything();
    });
  };

  Inspection.prototype.insertData = function(callback) {
    webDB.execute(
      [
        {
          'sql': 'INSERT INTO recentInspect (name, inspection_date, inspection_score, address, city, zip_code, phone, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);',
          'data': [this.name, this.inspection_date, this.inspection_score, this.address, this. city, this.zip_code, this.phone, this.latitude, this.longitude],
        }
      ],
      callback
    );
  };

  Inspection.requestInspectionData = function(place, callback) {

    $.get('/data/resource/gkhn-e8mn.json?$select=name,inspection_date,inspection_score,address,city,zip_code,phone,latitude,longitude&$order=inspection_date%20DESC&inspection_type=Routine%20Inspection/Field%20Review&$q=' + place + '&$limit=1')
      .done(function(data, message, xhr) {
        Inspection.current = data;
        data.forEach(function (item) {
          var total = new Inspection(item);
          console.log('item:' + item);
          //cache the data into the currently empty array
          total.insertData();
        });

        $('#report-card').empty().append(inspectionView.displayResults(Inspection.current[0])).show().siblings().hide();
        inspectionView.filterResults(Inspection.current[0]);
        mapView.updateMap();
      }).done(callback);
  };

  Inspection.with = function(attr) {
    console.log('inspection function');
    return Inspection.current.filter(function(inspection){
      return inspection[attr];
      console.log(Inspection.current);
    });
  };

  Inspection.inputOptions = function() {
    $('#search-input').autocomplete({
      source: Inspection.names,
      minLength: 3
    });
  };

  // $('.restaurant-search').on('submit', function(event) {
  //   event.preventDefault();
  //   var restName = $('#search-input').val();
  //   restName = restName.replace(/[^\w\s]/gi, ' ');
  //   console.log('This is the restName:' + restName);
  //   Inspection.requestInspectionData(restName, Inspection.with);
  //   historyInit.requestHistoryData(restName);
  // });

  module.Inspection = Inspection;
})(window);
<commit_msg>date truncated on inspection.js and database<commit_after>(function(module) {
  function Inspection (options) {
    Object.keys(options).forEach(function(element, index, keys){
      this[element] = options[element];
    },this);
  }
  Inspection.current =[];
  Inspection.names =[];

  Inspection.createTable = function(callback) {
    webDB.execute(
      'CREATE TABLE IF NOT EXISTS recentInspect (' +
      'id INTEGER PRIMARY KEY, ' +
      'name VARCHAR(255), ' +
      'inspection_date DATETIME, ' +
      'inspection_score INTEGER, ' +
      'address VARCHAR(255), ' +
      'city VARCHAR(255), ' +
      'zip_code VARCHAR(255), ' +
      'phone VARCHAR(255), ' +
      'latitude DECIMAL(18,12), ' +
      'longitude DECIMAL(18,12));',
      callback
    );
  };
  Inspection.buildNames = function (anything) {
    $.get('/data/resource/gkhn-e8mn.json?$select=name&$group=name&$order=name&$limit=50000')
    .done(function(data, message, xhr) {
      Inspection.names = data.map(function(element){
        return element.name;
      });
      console.log('generated array for inspeciton.names');
      anything();
    });
  };

  Inspection.prototype.insertData = function(callback) {
    webDB.execute(
      [
        {
          'sql': 'INSERT INTO recentInspect (name, inspection_date, inspection_score, address, city, zip_code, phone, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);',
          'data': [this.name, this.inspection_date, this.inspection_score, this.address, this. city, this.zip_code, this.phone, this.latitude, this.longitude],
        }
      ],
      callback
    );
  };

  Inspection.requestInspectionData = function(place, callback) {
    $.get('/data/resource/gkhn-e8mn.json?$select=name,inspection_date,inspection_score,address,city,zip_code,phone,latitude,longitude&$order=inspection_date%20DESC&inspection_type=Routine%20Inspection/Field%20Review&$q=' + place + '&$limit=1')
      .done(function(data, message, xhr) {
        Inspection.current = data;
        Inspection.current.forEach(function (item) {
          var total = new Inspection(item);
          total.inspection_date = total.inspection_date.substring(0, 10);
          //store search into database
          total.insertData();
        });

        $('#report-card').empty().append(inspectionView.displayResults(Inspection.current[0])).show().siblings().hide();
        inspectionView.filterResults(Inspection.current[0]);
        mapView.updateMap();
      }).done(callback);
  };

  Inspection.with = function(attr) {
    console.log('inspection function');
    return Inspection.current.filter(function(inspection){
      return inspection[attr];
      console.log(Inspection.current);
    });
  };

  Inspection.inputOptions = function() {
    $('#search-input').autocomplete({
      source: Inspection.names,
      minLength: 3
    });
  };

  module.Inspection = Inspection;
})(window);
<|endoftext|>


<commit_before>// ----------------------------------------------------------------------------

// npm
var test = require('tape');
var nock = require('nock');

// local
var Route53 = require('../nice-route53.js');

// ----------------------------------------------------------------------------

// create the mock server and client for Route53
var route53 = nock('https://route53.amazonaws.com');
var r53 = new Route53({
    accessKeyId     : 'xxx',
    secretAccessKey : 'xxx',
});

test.only('delRecord.js: delRecord() for an existing record', function(t) {
    // firstly, mock the GetHostedZone
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9')
        .replyWithFile(200, __dirname + '/GetHostedZoneResponse.xml')
    ;

    // then, mock the ListResourceRecordSetsResponse
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ListResourceRecordSetResponse-1.xml')
    ;

    // then, mock the ChangeResourceRecordSets
    route53
        .post('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ChangeResourceRecordSetsResponse-1.xml')
    ;

    route53
        .post('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ChangeResourceRecordSetsResponse-1.xml')
    ;

    // delete a record
    var args = {
        zoneId : 'Z1PA6795UKMFR9',
        name   : 'example.com',
        type   : 'A',
        ttl    : 600,
    };
    r53.delRecord(args, function(err, changeInfo) {
        t.equal(err, null, 'There is no error');

        t.equal(changeInfo.changeId, 'C2682N5HXP0BZ4', 'changeId is correct');
        t.equal(changeInfo.status, 'PENDING', 'Change is PENDING');
        t.equal(changeInfo.submittedAt, '2012-10-09T06:12:42.058Z', 'SubmittedAt date is the same');

        t.end();
    });

});

test("delRecord.js: delRecord() for a record that doesn't exist", function(t) {
    // firstly, mock the GetHostedZone
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9')
        .replyWithFile(200, __dirname + '/GetHostedZoneResponse.xml')
    ;

    // then, mock the ListResourceRecordSetsResponse
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ListResourceRecordSetResponse-1.xml')
    ;

    // then, mock the ChangeResourceRecordSets
    route53
        .post('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ChangeResourceRecordSetsResponse-1.xml')
    ;

    // delete a record
    var args = {
        zoneId : 'Z1PA6795UKMFR9',
        name   : 'non-existing.example.com',
        type   : 'A',
        ttl    : 600,
    };
    r53.delRecord(args, function(err, changeInfo) {
        t.ok(err, 'There is an error');
        t.equal(changeInfo, undefined, 'There is no changeInfo');

        t.equal(err.type, 'NiceRoute53-Client', 'it is a client error');
        t.equal(err.code, 'RecordNotFound', 'we cannot find this record');
        t.equal(err.msg, 'The record you asked to delete could not be found.', 'msg is correct');

        t.end();
    });

});

// ----------------------------------------------------------------------------
<commit_msg>removed duplicated code<commit_after>// ----------------------------------------------------------------------------

// npm
var test = require('tape');
var nock = require('nock');

// local
var Route53 = require('../nice-route53.js');

// ----------------------------------------------------------------------------

// create the mock server and client for Route53
var route53 = nock('https://route53.amazonaws.com');
var r53 = new Route53({
    accessKeyId     : 'xxx',
    secretAccessKey : 'xxx',
});

test.only('delRecord.js: delRecord() for an existing record', function(t) {
    // firstly, mock the GetHostedZone
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9')
        .replyWithFile(200, __dirname + '/GetHostedZoneResponse.xml')
    ;

    // then, mock the ListResourceRecordSetsResponse
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ListResourceRecordSetResponse-1.xml')
    ;

    // then, mock the ChangeResourceRecordSets
    route53
        .post('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ChangeResourceRecordSetsResponse-1.xml')
    ;

    // delete a record
    var args = {
        zoneId : 'Z1PA6795UKMFR9',
        name   : 'example.com',
        type   : 'A',
        ttl    : 600,
    };
    r53.delRecord(args, function(err, changeInfo) {
        t.equal(err, null, 'There is no error');

        t.equal(changeInfo.changeId, 'C2682N5HXP0BZ4', 'changeId is correct');
        t.equal(changeInfo.status, 'PENDING', 'Change is PENDING');
        t.equal(changeInfo.submittedAt, '2012-10-09T06:12:42.058Z', 'SubmittedAt date is the same');

        t.end();
    });

});

test("delRecord.js: delRecord() for a record that doesn't exist", function(t) {
    // firstly, mock the GetHostedZone
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9')
        .replyWithFile(200, __dirname + '/GetHostedZoneResponse.xml')
    ;

    // then, mock the ListResourceRecordSetsResponse
    route53
        .get('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ListResourceRecordSetResponse-1.xml')
    ;

    // then, mock the ChangeResourceRecordSets
    route53
        .post('/2013-04-01/hostedzone/Z1PA6795UKMFR9/rrset')
        .replyWithFile(200, __dirname + '/ChangeResourceRecordSetsResponse-1.xml')
    ;

    // delete a record
    var args = {
        zoneId : 'Z1PA6795UKMFR9',
        name   : 'non-existing.example.com',
        type   : 'A',
        ttl    : 600,
    };
    r53.delRecord(args, function(err, changeInfo) {
        t.ok(err, 'There is an error');
        t.equal(changeInfo, undefined, 'There is no changeInfo');

        t.equal(err.type, 'NiceRoute53-Client', 'it is a client error');
        t.equal(err.code, 'RecordNotFound', 'we cannot find this record');
        t.equal(err.msg, 'The record you asked to delete could not be found.', 'msg is correct');

        t.end();
    });

});

// ----------------------------------------------------------------------------
<|endoftext|>


<commit_before>
import { generateUUID } from '../UUID';
import SelectionBuilder from '../SelectionBuilder';

// ----------------------------------------------------------------------------
// Internal helpers
// ----------------------------------------------------------------------------

let generation = 0;

function setInitialGenerationNumber(genNum) {
  generation = genNum;
}

// ----------------------------------------------------------------------------
// Public builder method
// ----------------------------------------------------------------------------

function annotation(selection, score, weight = 1, rationale = '', name = '') {
  generation++;
  return {
    id: generateUUID(),
    generation,
    selection,
    score,
    weight,
    rationale,
    name,
  };
}

// ----------------------------------------------------------------------------

function update(annotationObject, changeSet) {
  const updatedAnnotation = Object.assign({}, annotationObject, changeSet);

  let changeDetected = false;
  Object.keys(updatedAnnotation).forEach(key => {
    if (updatedAnnotation[key] !== annotationObject[key]) {
      changeDetected = true;
    }
  });

  if (changeDetected) {
    generation++;
    updatedAnnotation.generation = generation;
  }

  return updatedAnnotation;
}

// ----------------------------------------------------------------------------

function fork(annotationObj) {
  const id = generateUUID();
  generation++;
  return Object.assign({}, annotationObj, { generation, id });
}

// ----------------------------------------------------------------------------

function markModified(annotationObject) {
  generation++;
  return Object.assign({}, annotationObject, { generation });
}

// ----------------------------------------------------------------------------
// Exposed object
// ----------------------------------------------------------------------------

const EMPTY_ANNOTATION = annotation(SelectionBuilder.EMPTY_SELECTION, 0);

export default {
  annotation,
  update,
  markModified,
  fork,
  setInitialGenerationNumber,
  EMPTY_ANNOTATION,
};
<commit_msg>fix(AnnotationBuilder): Add helper function to update readOnly flag of an annotation<commit_after>
import { generateUUID } from '../UUID';
import SelectionBuilder from '../SelectionBuilder';

// ----------------------------------------------------------------------------
// Internal helpers
// ----------------------------------------------------------------------------

let generation = 0;

function setInitialGenerationNumber(genNum) {
  generation = genNum;
}

// ----------------------------------------------------------------------------
// Public builder method
// ----------------------------------------------------------------------------

function annotation(selection, score, weight = 1, rationale = '', name = '') {
  generation++;
  return {
    id: generateUUID(),
    generation,
    selection,
    score,
    weight,
    rationale,
    name,
  };
}

// ----------------------------------------------------------------------------

function update(annotationObject, changeSet) {
  const updatedAnnotation = Object.assign({}, annotationObject, changeSet);

  let changeDetected = false;
  Object.keys(updatedAnnotation).forEach(key => {
    if (updatedAnnotation[key] !== annotationObject[key]) {
      changeDetected = true;
    }
  });

  if (changeDetected) {
    generation++;
    updatedAnnotation.generation = generation;
  }

  return updatedAnnotation;
}

// ----------------------------------------------------------------------------

function updateReadOnlyFlag(annotationToEdit, readOnlyFields) {
  if (!annotationToEdit || !annotationToEdit.selection || !readOnlyFields) {
    return;
  }

  annotationToEdit.readOnly = SelectionBuilder.hasField(annotationToEdit.selection, readOnlyFields);
}

// ----------------------------------------------------------------------------

function fork(annotationObj) {
  const id = generateUUID();
  generation++;
  return Object.assign({}, annotationObj, { generation, id });
}

// ----------------------------------------------------------------------------

function markModified(annotationObject) {
  generation++;
  return Object.assign({}, annotationObject, { generation });
}

// ----------------------------------------------------------------------------
// Exposed object
// ----------------------------------------------------------------------------

const EMPTY_ANNOTATION = annotation(SelectionBuilder.EMPTY_SELECTION, 0);

export default {
  annotation,
  EMPTY_ANNOTATION,
  fork,
  markModified,
  setInitialGenerationNumber,
  update,
  updateReadOnlyFlag,
};
<|endoftext|>


<commit_before>var questions = [
  "Worin besteht das Problem?",
  "Wann tritt das Problem auf?",
  "Welche Ressourcen habe ich momentan zur Verfügung um das Problem zu lösen?",
  "Welche Menschen können mir dabei helfen, das Problem zu lösen?",
  "Wann habe ich das letzte Mal intensiv über dieses Problem nachgedacht?",
  "Auf welche Ressourcen würden mich andere hinweisen?",
  "Was würde ich mir raten, wenn ich Berater wär?",
  "Was müsste ich tun, um eine Lösung des Problems zu verhindern?",
  "Wer konnte mir bei meinem letzten Problem helfen?",
  "Welchen Nutzen habe ich von dem Problem?",
  "Was wäre der nächste Schritt, den ich gehen könnte, um das Problem zu lösen?",
  "Wie würde es sein, wenn das Problem gelöst wäre?",
  "Für wen würde sich etwas ändern, wenn das Problem gelöst wäre?",
  "Wer ist alles von dem Problem betroffen?",
  "Was würde passieren, wenn ich das Problem nicht angehen würde?",
  "Wann habe ich mich das letzte Mal bei einem Menschen für etwas bedankt?",
  "Wann war ich das letzte Mal an der frischen Luft unterwegs?",
  "Welche Frage stelle ich mir eigentlich gerade?",
  "Wie schlimm ist mein altuelles Problem?",
  "Was treibt mich an?",
  "Warum bin ich auf dieser Seite?",
  "Unter welchen Bedingungen kann ich am besten über etwas nachdenken?",
  "Was würde mir ein Kollege jetzt raten?",
  "Welcher Lösungsansatz hat sich bei dem letzten Problem bewährt?",
  "In welchem Augenblick ist mein Problem entstanden?",
  "Wen könnte ich um Rat bitten?",
  "Warum ist das Problem da?",
  "Bin ich am richtigen Problem dran oder nur an einem Symptom?",
  "Kenne ich das Spielfeld gut, in dem ich mich befinde?",
  "Für welches Problem suche ich gerade nach einer Lösung?",
  "Bin ich auf dem richtigen Weg?",
  "Was muss ich mir noch aneigenen, um mein Problem zu lösen?",
  "Sage ich zu oft \"Ich versuche ...\" anstatt zu sagen: \"Ich werde ...\"?",
  "Übernehme ich die Verantwortung für mein Handeln und Nichthandeln?",
  "Bin ich ausgeschlafen genug für das, was ich mir vornehme?",
  "Bin ich bei der Sache?",
  "Bin ich konzentriert?",
  "Welches Risiko bin ich bereit einzugehen?",
  "Welche längerfristigen Folgen hat mein Tun?",
  "Was tue ich am liebsten?",
  "Passt meine aktuelle Aufgabe zu meiner eigenen Lebensvision?",
  "Was muss zunächst abgeschlossen oder erledigt werden?",
  "Habe ich noch offene Kommunikation?",
  "Was hilft mir neue Sichtweisen zu entwickeln?",
  "Welchen Beitrag könnte ich jetzt dringend gebrauchen? Wie komme ich daran?",
  "Was brauche ich?",
  "Was hindert mich gerade?",
  "Auf was könnte ich am leichtesten verzichten?"
]
<commit_msg>Add some more questions.<commit_after>var questions = [
  "Worin besteht das Problem?",
  "Wann tritt das Problem auf?",
  "Welche Ressourcen habe ich momentan zur Verfügung um das Problem zu lösen?",
  "Welche Menschen können mir dabei helfen, das Problem zu lösen?",
  "Wann habe ich das letzte Mal intensiv über dieses Problem nachgedacht?",
  "Auf welche Ressourcen würden mich andere hinweisen?",
  "Was würde ich mir raten, wenn ich Berater wär?",
  "Was müsste ich tun, um eine Lösung des Problems zu verhindern?",
  "Wer konnte mir bei meinem letzten Problem helfen?",
  "Welchen Nutzen habe ich von dem Problem?",
  "Was wäre der nächste Schritt, den ich gehen könnte, um das Problem zu lösen?",
  "Wie würde es sein, wenn das Problem gelöst wäre?",
  "Für wen würde sich etwas ändern, wenn das Problem gelöst wäre?",
  "Wer ist alles von dem Problem betroffen?",
  "Was würde passieren, wenn ich das Problem nicht angehen würde?",
  "Wann habe ich mich das letzte Mal bei einem Menschen für etwas bedankt?",
  "Wann war ich das letzte Mal an der frischen Luft unterwegs?",
  "Welche Frage stelle ich mir eigentlich gerade?",
  "Wie schlimm ist mein altuelles Problem?",
  "Was treibt mich an?",
  "Warum bin ich auf dieser Seite?",
  "Unter welchen Bedingungen kann ich am besten über etwas nachdenken?",
  "Was würde mir ein Kollege jetzt raten?",
  "Welcher Lösungsansatz hat sich bei dem letzten Problem bewährt?",
  "In welchem Augenblick ist mein Problem entstanden?",
  "Wen könnte ich um Rat bitten?",
  "Warum ist das Problem da?",
  "Bin ich am richtigen Problem dran oder nur an einem Symptom?",
  "Kenne ich das Spielfeld gut, in dem ich mich befinde?",
  "Für welches Problem suche ich gerade nach einer Lösung?",
  "Bin ich auf dem richtigen Weg?",
  "Was muss ich mir noch aneigenen, um mein Problem zu lösen?",
  "Sage ich zu oft \"Ich versuche ...\" anstatt zu sagen: \"Ich werde ...\"?",
  "Übernehme ich die Verantwortung für mein Handeln und Nichthandeln?",
  "Bin ich ausgeschlafen genug für das, was ich mir vornehme?",
  "Bin ich bei der Sache?",
  "Bin ich konzentriert?",
  "Welches Risiko bin ich bereit einzugehen?",
  "Welche längerfristigen Folgen hat mein Tun?",
  "Was tue ich am liebsten?",
  "Passt meine aktuelle Aufgabe zu meiner eigenen Lebensvision?",
  "Was muss zunächst abgeschlossen oder erledigt werden?",
  "Habe ich noch offene Kommunikation?",
  "Was hilft mir neue Sichtweisen zu entwickeln?",
  "Welchen Beitrag könnte ich jetzt dringend gebrauchen? Wie komme ich daran?",
  "Was brauche ich?",
  "Was hindert mich gerade?",
  "Auf was könnte ich am leichtesten verzichten?",
  "Woran erkenne ich, dass ich mein Problem gelöst habe?",
  "Was passiert, wenn ich einfach abwarte und nichts tue?",
  "Wie kann ich meine Ergebnisse messen?",
  "Wer kontrolliert, ob ich meine Arbeit gut mache?",
  "Was gibt mir Rückmeldung?",
  "Wie engagiert bin ich?",
  "Wie kann ich nach der Lösung verhindern, dass das Problem erneut auftritt?",
  "Wer weiß von dem Problem?",
  "Weiß ich alles über mein Problem?",
  "Weiß ich genug über mein Problem, um es lösen zu können?",
  "Wie kann ich mein Verhalten ändern, dass sich das Problem von selbst löst?",
  "Ist das Problem an dem ich arbeite auch mein Problem?",
  "Wessen Problem löse ich gerade?",
  "Welche Fragen habe ich mir noch nicht gestellt?",
  "Bin ich ehrlich zu mir?",
  "Löse ich gerade das wichtigste Problem?",
  "Was tue ich, wenn das Problem gelöst ist?",
  "Kann ich meine Fortschritte messen?",
  "Wann werde ich auf diese Seite das nächste mal zurückkehren?",
  "Wie wichtig ist eine gute Frage für mich?",
  "Wie lange dauert es, bis mein Handeln Wirkung zeigt?",
  "Was ist mein Ziel?",
  "Worauf will ich hinaus?",
  "Was verändert sich in meiner Umgebung, wenn ich fertig bin?",
  "Habe ich bereits begonnen?",
  "Wann werde ich beginnen?",
  "An welchem Ort erziele ich die besten Ergebnisse?",
  "Werde ich serenize.me weiterempfehlen?",
  "Wie überzeuge ich andere Mitsteiter für mein Problem?",
  "Gibt es Konkurenz?",
  "Welche Warum-Frage kommt mir als erste in den Sinn?",
  "Weiß ich, wie ich vorgehen muss?",
  "Wissen meine Mitsteiter oder Kollegen genau, was zu tun ist?",
  "Bin ich unsicher?",
  "Wie unsicher bin ich?",
  "Bin ich sicher, dass ich das Richtige tue?",
  "Was verschafft mir Sicherheit, das Richtige zu tun?",
  "Habe ich bereits ein änhliches Problem gelöst?",
  "Wie bin ich in bisherigen Situationen vorgegangen?",
  "Habe ich Spaß an der Lösung?",
  "Habe ich Spaß an dem Problem?",
  "Bekomme ich an Anerkennung für meine Arbeit?",
  "Erkenne ich die Arbeit der anderen an?",
  "Wie perfekt soll die Lösung sein?",
  "Kann ich in meiner Umgebung klar denken?",
  "Was fehlt mir, um klar zu denken?",
  "Welche Fähigkeiten fehlen mir zu Lösung des Problems?",
  "Welches Wissen fehlt mir zur Lösung des Problems?",
  "Handelt es sich um ein Problem?",
  "Gibt es etwas, das wichtiger ist und ich zunächst erledigen sollte?",
  "Bin ich ein Feuerlöscher?",
  "Habe ich einen coolen Kopf?",
  "Weiß ich bei jedem Schritt bereits schon den nächsten Schritt?",
  "Kenne ich meinen Weg?",
  "Habe ich ein Ziel?",
  "Habe ich mein Problem schon einmal aufgeschrieben?",
  "Werde ich bei der Lösung des Problems etwas neues lernen?",
  "Muss ich noch etwas lernen, bevor ich das Problem lösen kann?",
  "Kenne ich die Definition der Begriffe genau, die ich verwende?",
  "Schafft meine Lösung mehr Freiheit für Menschen?",
  "Ist das, was ich tue aus meiner Sicht eher gut oder schlecht?",
  "Tue ich mir etwas Gutes, nachdem ich das Problem gelöst habe?",
  "Tut mir die Lösung des Problems gut?",
  "Wie schaffe ich es, dass ich das Problem gerne löse?",
  "Welche Eigenschaften fehlen mir zur Lösung des Problems?",
  "Welche Eigenschaften haben andere, die mir helfen könnten?",
  "Wie groß ist mein Einfluss auf das Problem?",
  "Bin ich ausreichend vernetzt um das Problem mit anderen zu lösen?",
  "Bekomme ich genügend Rückhalt aus meiner Umgebung?",
  "Gibt es Werkzeuge, die mir bei der Lösung des Problems helfen?",
  "Welche Werkzeuge helfen bei der Lösung meines Problems?",
  "Was möchte ich alles erreichen? Bin ich auf dem richtigen Weg?"
]
<|endoftext|>


<commit_before>/*global eio,listen,request,expect*/

/**
 * Test dependencies.
 */

var net = require('net')
  , http = require('http');

/**
 * Tests.
 */

describe('engine', function () {

  it('should expose protocol number', function () {
    expect(eio.protocol).to.be.a('number');
  });

  describe('listen', function () {
    it('should open a http server that returns 501', function (done) {
      var server = listen(function (port) {
        request.get('http://localhost:%d/'.s(port), function (res) {
          expect(res.status).to.be(501);
          done();
        });
      });
    });
  });

  describe('attach()', function () {
    it('should return an engine.Server', function () {
      var server = http.createServer()
        , engine = eio.attach(server);

      expect(engine).to.be.an(eio.Server);
    });

    it('should attach engine to an http server', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var uri = 'http://localhost:%d/engine.io/default/'.s(server.address().port);
        request.get(uri, function (res) {
          expect(res.status).to.be(500);
          server.once('close', done);
          server.close();
        });
      });
    });

    it('should respond to flash policy requests', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-request/>\0');
        client.setEncoding('ascii');
        client.on('data', function (data) {
          expect(data).to.contain('<allow-access-from');
          client.end();
          done();
        });
      });
    });

    it('should not respond to borked flash policy requests', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-req>\0');
        client.setEncoding('ascii');
        client.on('data', function () {
          done(new Error('Should not respond'));
        });
        setTimeout(done, 20);
      });
    });

    it('should not respond to flash policy requests when policyFile:false', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server, { policyFile: false });

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-req>\0');
        client.setEncoding('ascii');
        client.on('data', function (data) {
          done(new Error('Should not fire'));
        });
        setTimeout(done, 20);
      });
    });

    it('should not respond to flash policy requests when no flashsocket', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server, { transports: ['xhr-polling', 'websocket'] });

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-req>\0');
        client.setEncoding('ascii');
        client.on('data', function (data) {
          done(new Error('Should not fire'));
        });
        setTimeout(done, 20);
      });
    });

    it('should destroy upgrades not handled by engine', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.setEncoding('ascii');
        client.write([
            'GET / HTTP/1.1'
          , 'Upgrade: IRC/6.9'
          , '', ''
        ].join('\r\n'));

        var check = setTimeout(function () {
          done(new Error('Client should have ended'));
        }, 20);

        client.on('end', function () {
          clearTimeout(check);
          done();
        });
      });
    });

    it('should not destroy unhandled upgrades with destroyUpgrade:false', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server, { destroyUpgrade: false });

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.on('connect', function () {
          client.setEncoding('ascii');
          client.write([
              'GET / HTTP/1.1'
            , 'Upgrade: IRC/6.9'
            , '', ''
          ].join('\r\n'));

          var check = setTimeout(function () {
            client.removeListener('end', onEnd);
            done();
          }, 20);

          function onEnd () {
            done(new Error('Client should not end'));
          }

          client.on('end', onEnd);
        });
      });
    });

    it('should preserve original request listeners', function (done) {
      var listeners = 0
        , server = http.createServer(function (req, res) {
            expect(req && res).to.be.ok();
            listeners++;
          });

      server.on('request', function (req, res) {
        expect(req && res).to.be.ok();
        res.writeHead(200);
        res.end('');
        listeners++;
      });

      eio.attach(server);

      server.listen(function () {
        var port = server.address().port;
        request.get('http://localhost:%d/engine.io/default/'.s(port), function (res) {
          expect(res.status).to.be(500);
          request.get('http://localhost:%d/test'.s(port), function (res) {
            expect(res.status).to.be(200);
            expect(listeners).to.eql(2);
            server.once('close', done);
            server.close();
          });
        });
      });
    });
  });

});
<commit_msg>test: added test to avoid out-of-date client `version`<commit_after>/*global eio,listen,request,expect*/

/**
 * Test dependencies.
 */

var net = require('net')
  , http = require('http');

/**
 * Tests.
 */

describe('engine', function () {

  it('should expose protocol number', function () {
    expect(eio.protocol).to.be.a('number');
  });

  it('should be the same version as client', function(){
    expect(eio.protocol).to.be.a('number');
    var version = require('../package').version;
    expect(version).to.be(require('engine.io-client').version);
  });

  describe('listen', function () {
    it('should open a http server that returns 501', function (done) {
      var server = listen(function (port) {
        request.get('http://localhost:%d/'.s(port), function (res) {
          expect(res.status).to.be(501);
          done();
        });
      });
    });
  });

  describe('attach()', function () {
    it('should return an engine.Server', function () {
      var server = http.createServer()
        , engine = eio.attach(server);

      expect(engine).to.be.an(eio.Server);
    });

    it('should attach engine to an http server', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var uri = 'http://localhost:%d/engine.io/default/'.s(server.address().port);
        request.get(uri, function (res) {
          expect(res.status).to.be(500);
          server.once('close', done);
          server.close();
        });
      });
    });

    it('should respond to flash policy requests', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-request/>\0');
        client.setEncoding('ascii');
        client.on('data', function (data) {
          expect(data).to.contain('<allow-access-from');
          client.end();
          done();
        });
      });
    });

    it('should not respond to borked flash policy requests', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-req>\0');
        client.setEncoding('ascii');
        client.on('data', function () {
          done(new Error('Should not respond'));
        });
        setTimeout(done, 20);
      });
    });

    it('should not respond to flash policy requests when policyFile:false', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server, { policyFile: false });

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-req>\0');
        client.setEncoding('ascii');
        client.on('data', function (data) {
          done(new Error('Should not fire'));
        });
        setTimeout(done, 20);
      });
    });

    it('should not respond to flash policy requests when no flashsocket', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server, { transports: ['xhr-polling', 'websocket'] });

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.write('<policy-file-req>\0');
        client.setEncoding('ascii');
        client.on('data', function (data) {
          done(new Error('Should not fire'));
        });
        setTimeout(done, 20);
      });
    });

    it('should destroy upgrades not handled by engine', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server);

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.setEncoding('ascii');
        client.write([
            'GET / HTTP/1.1'
          , 'Upgrade: IRC/6.9'
          , '', ''
        ].join('\r\n'));

        var check = setTimeout(function () {
          done(new Error('Client should have ended'));
        }, 20);

        client.on('end', function () {
          clearTimeout(check);
          done();
        });
      });
    });

    it('should not destroy unhandled upgrades with destroyUpgrade:false', function (done) {
      var server = http.createServer()
        , engine = eio.attach(server, { destroyUpgrade: false });

      server.listen(function () {
        var client = net.createConnection(server.address().port);
        client.on('connect', function () {
          client.setEncoding('ascii');
          client.write([
              'GET / HTTP/1.1'
            , 'Upgrade: IRC/6.9'
            , '', ''
          ].join('\r\n'));

          var check = setTimeout(function () {
            client.removeListener('end', onEnd);
            done();
          }, 20);

          function onEnd () {
            done(new Error('Client should not end'));
          }

          client.on('end', onEnd);
        });
      });
    });

    it('should preserve original request listeners', function (done) {
      var listeners = 0
        , server = http.createServer(function (req, res) {
            expect(req && res).to.be.ok();
            listeners++;
          });

      server.on('request', function (req, res) {
        expect(req && res).to.be.ok();
        res.writeHead(200);
        res.end('');
        listeners++;
      });

      eio.attach(server);

      server.listen(function () {
        var port = server.address().port;
        request.get('http://localhost:%d/engine.io/default/'.s(port), function (res) {
          expect(res.status).to.be(500);
          request.get('http://localhost:%d/test'.s(port), function (res) {
            expect(res.status).to.be(200);
            expect(listeners).to.eql(2);
            server.once('close', done);
            server.close();
          });
        });
      });
    });
  });

});
<|endoftext|>