<commit_before>var assert = require("assert");
var path = require("path");
var fs = require("fs");
var hasOwn = Object.hasOwnProperty;
var convertSourceMap = require("convert-source-map");
var meteorBabel = require("./index.js");
var util = require("./util.js");

var Module = module.constructor;
require("reify/lib/runtime").enable(Module.prototype);

var config = {
  sourceMapRootPath: null,
  cacheDirectory: process.env.BABEL_CACHE_DIR,
  allowedDirectories: Object.create(null),
  babelOptions: null
};

function setBabelOptions(options) {
  config.babelOptions = Object.assign({}, options, {
    // Overrides for default options:
    sourceMaps: true
  });
  return exports;
}

// Set default config.babelOptions.
setBabelOptions(require("./options.js").getDefaults({
  nodeMajorVersion: parseInt(process.versions.node)
}));

exports.setBabelOptions = setBabelOptions;

exports.setSourceMapRootPath = function (smrp) {
  config.sourceMapRootPath = smrp;
  return exports;
};

exports.setCacheDirectory = function (dir) {
  config.cacheDirectory = dir;
  return exports;
};

exports.allowDirectory = function (dir) {
  config.allowedDirectories[dir] = true;
  // Sometimes the filename passed to the require.extensions handler is a
  // real path, and thus may not appear to be contained by an allowed
  // directory, even though it should be.
  config.allowedDirectories[fs.realpathSync(dir)] = true;
  return exports;
};

var defaultHandler = require.extensions[".js"];
require.extensions[".js"] = function(module, filename) {
  if (shouldNotTransform(filename)) {
    defaultHandler(module, filename);
  } else {
    module._compile(
      getBabelResult(filename).code,
      filename
    );

    // As of version 0.10.0, the Reify require.extensions[".js"] handler
    // is responsible for running parent setters after the module has
    // finished loading for the first time, so we need to call that method
    // here because we are not calling the defaultHandler.
    module.runSetters();
  }
};

exports.retrieveSourceMap = function(filename) {
  if (shouldNotTransform(filename)) {
    return null;
  }

  const babelCore = require("@babel/core");
  if (typeof babelCore.transformFromAst !== "function") {
    // The retrieveSourceMap function can be called as a result of
    // importing @babel/core for the first time, at a point in time before
    // babelCore.transformFromAst has been defined. The absence of that
    // function will cause meteorBabel.compile to fail if we try to call
    // getBabelResult here. Fortunately, we can just return null instead,
    // which means we couldn't retrieve a source map, which is fine.
    return null;
  }

  var result = getBabelResult(filename);
  var map = null;

  if (result) {
    if (result.map) {
      map = result.map;
    } else {
      var converted = convertSourceMap.fromSource(result.code);
      map = converted && converted.toJSON();
    }
  }

  return map && {
    url: map.file,
    map: map
  } || null;
};

function shouldNotTransform(filename) {
  if (path.resolve(filename) !==
      path.normalize(filename)) {
    // If the filename is not absolute, then it's a file in a core Node
    // module, and should not be transformed.
    return true;
  }

  var dirs = Object.keys(config.allowedDirectories);
  var allowed = dirs.some(function (dir) {
    var relPath = path.relative(dir, filename);
    if (relPath.slice(0, 2) === "..") {
      // Ignore files that are not contained by an allowed directory.
      return false;
    }

    if (relPath.split(path.sep).indexOf("node_modules") >= 0) {
      // Ignore files that are contained by a node_modules directory that
      // is itself contained by the allowed dir.
      return false;
    }

    return true;
  });

  return ! allowed;
}

function getBabelResult(filename) {
  var source = fs.readFileSync(filename, "utf8");

  var babelOptions = {};
  for (var key in config.babelOptions) {
    if (hasOwn.call(config.babelOptions, key)) {
      babelOptions[key] = config.babelOptions[key];
    }
  }

  if (babelOptions.sourceMaps) {
    if (config.sourceMapRootPath) {
      var relativePath = path.relative(
        config.sourceMapRootPath,
        filename
      );

      if (relativePath.slice(0, 2) !== "..") {
        // If the given filename is a path contained within
        // config.sourceMapRootPath, use the relative path but prepend
        // path.sep so that source maps work more reliably.
        filename = path.sep + relativePath;
      }
    }

    babelOptions.sourceFileName = filename;
  }

  babelOptions.filename = filename;

  return meteorBabel.compile(source, babelOptions, {
    cacheDirectory: config.cacheDirectory
  });
}
<commit_msg>Use util.deepClone in require("meteor-babel/register").setBabelOptions.<commit_after>var assert = require("assert");
var path = require("path");
var fs = require("fs");
var hasOwn = Object.hasOwnProperty;
var convertSourceMap = require("convert-source-map");
var meteorBabel = require("./index.js");
var util = require("./util.js");

var Module = module.constructor;
require("reify/lib/runtime").enable(Module.prototype);

var config = {
  sourceMapRootPath: null,
  cacheDirectory: process.env.BABEL_CACHE_DIR,
  allowedDirectories: Object.create(null),
  babelOptions: null
};

function setBabelOptions(options) {
  config.babelOptions = util.deepClone(options);
  // Overrides for default options:
  config.babelOptions.sourceMaps = true;
  return exports;
}

// Set default config.babelOptions.
setBabelOptions(require("./options.js").getDefaults({
  nodeMajorVersion: parseInt(process.versions.node)
}));

exports.setBabelOptions = setBabelOptions;

exports.setSourceMapRootPath = function (smrp) {
  config.sourceMapRootPath = smrp;
  return exports;
};

exports.setCacheDirectory = function (dir) {
  config.cacheDirectory = dir;
  return exports;
};

exports.allowDirectory = function (dir) {
  config.allowedDirectories[dir] = true;
  // Sometimes the filename passed to the require.extensions handler is a
  // real path, and thus may not appear to be contained by an allowed
  // directory, even though it should be.
  config.allowedDirectories[fs.realpathSync(dir)] = true;
  return exports;
};

var defaultHandler = require.extensions[".js"];
require.extensions[".js"] = function(module, filename) {
  if (shouldNotTransform(filename)) {
    defaultHandler(module, filename);
  } else {
    module._compile(
      getBabelResult(filename).code,
      filename
    );

    // As of version 0.10.0, the Reify require.extensions[".js"] handler
    // is responsible for running parent setters after the module has
    // finished loading for the first time, so we need to call that method
    // here because we are not calling the defaultHandler.
    module.runSetters();
  }
};

exports.retrieveSourceMap = function(filename) {
  if (shouldNotTransform(filename)) {
    return null;
  }

  const babelCore = require("@babel/core");
  if (typeof babelCore.transformFromAst !== "function") {
    // The retrieveSourceMap function can be called as a result of
    // importing @babel/core for the first time, at a point in time before
    // babelCore.transformFromAst has been defined. The absence of that
    // function will cause meteorBabel.compile to fail if we try to call
    // getBabelResult here. Fortunately, we can just return null instead,
    // which means we couldn't retrieve a source map, which is fine.
    return null;
  }

  var result = getBabelResult(filename);
  var map = null;

  if (result) {
    if (result.map) {
      map = result.map;
    } else {
      var converted = convertSourceMap.fromSource(result.code);
      map = converted && converted.toJSON();
    }
  }

  return map && {
    url: map.file,
    map: map
  } || null;
};

function shouldNotTransform(filename) {
  if (path.resolve(filename) !==
      path.normalize(filename)) {
    // If the filename is not absolute, then it's a file in a core Node
    // module, and should not be transformed.
    return true;
  }

  var dirs = Object.keys(config.allowedDirectories);
  var allowed = dirs.some(function (dir) {
    var relPath = path.relative(dir, filename);
    if (relPath.slice(0, 2) === "..") {
      // Ignore files that are not contained by an allowed directory.
      return false;
    }

    if (relPath.split(path.sep).indexOf("node_modules") >= 0) {
      // Ignore files that are contained by a node_modules directory that
      // is itself contained by the allowed dir.
      return false;
    }

    return true;
  });

  return ! allowed;
}

function getBabelResult(filename) {
  var source = fs.readFileSync(filename, "utf8");

  var babelOptions = {};
  for (var key in config.babelOptions) {
    if (hasOwn.call(config.babelOptions, key)) {
      babelOptions[key] = config.babelOptions[key];
    }
  }

  if (babelOptions.sourceMaps) {
    if (config.sourceMapRootPath) {
      var relativePath = path.relative(
        config.sourceMapRootPath,
        filename
      );

      if (relativePath.slice(0, 2) !== "..") {
        // If the given filename is a path contained within
        // config.sourceMapRootPath, use the relative path but prepend
        // path.sep so that source maps work more reliably.
        filename = path.sep + relativePath;
      }
    }

    babelOptions.sourceFileName = filename;
  }

  babelOptions.filename = filename;

  return meteorBabel.compile(source, babelOptions, {
    cacheDirectory: config.cacheDirectory
  });
}
<|endoftext|>


<commit_before><commit_msg>add --version cli option<commit_after><|endoftext|>


<commit_before>var express = require('express');
var router = require('./');

var app = express();

app.use('/example', router({
  cacheDir: __dirname + '/cached'
}));

app.listen(3991, function() {
  console.log('listening on 3991');
});

<commit_msg>update example<commit_after>var express = require('express');
var router = require('./');

var app = express();

app.use('/horse', router({
  cacheDir: __dirname + '/cached'
}));

app.listen(3991, function() {
  console.log('listening on 3991');
});

<|endoftext|>


<commit_before>angular
  .module('lnPatterns')
  .controller('lnMAdminBarController', lnMAdminBarController);

lnMAdminBarController.$inject = ['$log', '$rootScope', '$scope', '$cookies', '$timeout', '$element', 'lnMAdminBarService'];

var STATUS = {
  INIT: 0,
  LOADING: 1,
  LOADED: 2
};

function lnMAdminBarController($log, $rootScope, $scope, $cookies, $timeout, $element, lnMAdminBarService) {
  var vm = this;
  var status = STATUS.INIT;
  var loginCookie = '';

  if (vm.lnLoadFromApi) {
    _disableAdminBar();
    _loginCheck();
  } else {
    _enableAdminBar();
  }

  /////////

  function _loginCheck() {
    loginCookie = $cookies.get('wp_admin_bar_user') || '';
    _reviewStatus();
    $timeout(_loginCheck, 5000);
  }

  function _reviewStatus(){
    if (status === STATUS.INIT && loginCookie !== '') {
      _loadData();
    }

    if ((status === STATUS.LOADING || status === STATUS.LOADED) && loginCookie === '') {
      status = STATUS.INIT;
      _disableAdminBar();
    }
  }

  function _loadData() {
    if (lnMAdminBarService.getApiUrl() !== '') {
      status = STATUS.LOADING;

      lnMAdminBarService
        .getAdminBarData()
        .then(_configureAdminBar, _logError);
    }
  }

  function _configureAdminBar(response) {
    if (response.data && status === STATUS.LOADING) {
      status = STATUS.LOADED;

      vm.lnSiteName = response.data.site_name;
      vm.lnUserName = response.data.user_name || loginCookie;
      vm.lnDashboardUrl = response.data.dashboard_url;
      vm.lnLogoutUrl = response.data.logout_url;
      vm.lnEditPageUrl = response.data.edit_page_url;
      vm.lnNewItemTypes = response.data.post_types;
      vm.lnUserNicename = angular.isDefined( response.data.nicename ) ? response.data.nicename : '';
      vm.lnUserDisplayName = angular.isDefined( response.data.display_name ) ? response.data.display_name : '';
      vm.lnUserFirstName = angular.isDefined( response.data.first_name ) ? response.data.first_name : '';
      vm.lnUserLastName = angular.isDefined( response.data.last_name ) ? response.data.last_name : '';

      _enableAdminBar();
    }
  }

  function _logError(error) {
    $log.error('lnMAdminBarService.getAdminBarData() -> error: ', error);
  }

  function _enableAdminBar() {
    vm.adminBarEnabled = true;
    $element.removeClass('ng-hide');
    $rootScope.$broadcast('lnMAdminBarEnabled');
  }

  function _disableAdminBar() {
    vm.adminBarEnabled = false;
    $element.addClass('ng-hide');
    $rootScope.$broadcast('lnMAdminBarDisabled');
  }
}
<commit_msg>Add user email into the response<commit_after>angular
  .module('lnPatterns')
  .controller('lnMAdminBarController', lnMAdminBarController);

lnMAdminBarController.$inject = ['$log', '$rootScope', '$scope', '$cookies', '$timeout', '$element', 'lnMAdminBarService'];

var STATUS = {
  INIT: 0,
  LOADING: 1,
  LOADED: 2
};

function lnMAdminBarController($log, $rootScope, $scope, $cookies, $timeout, $element, lnMAdminBarService) {
  var vm = this;
  var status = STATUS.INIT;
  var loginCookie = '';

  if (vm.lnLoadFromApi) {
    _disableAdminBar();
    _loginCheck();
  } else {
    _enableAdminBar();
  }

  /////////

  function _loginCheck() {
    loginCookie = $cookies.get('wp_admin_bar_user') || '';
    _reviewStatus();
    $timeout(_loginCheck, 5000);
  }

  function _reviewStatus(){
    if (status === STATUS.INIT && loginCookie !== '') {
      _loadData();
    }

    if ((status === STATUS.LOADING || status === STATUS.LOADED) && loginCookie === '') {
      status = STATUS.INIT;
      _disableAdminBar();
    }
  }

  function _loadData() {
    if (lnMAdminBarService.getApiUrl() !== '') {
      status = STATUS.LOADING;

      lnMAdminBarService
        .getAdminBarData()
        .then(_configureAdminBar, _logError);
    }
  }

  function _configureAdminBar(response) {
    if (response.data && status === STATUS.LOADING) {
      status = STATUS.LOADED;

      vm.lnSiteName = response.data.site_name;
      vm.lnUserName = response.data.user_name || loginCookie;
      vm.lnDashboardUrl = response.data.dashboard_url;
      vm.lnLogoutUrl = response.data.logout_url;
      vm.lnEditPageUrl = response.data.edit_page_url;
      vm.lnNewItemTypes = response.data.post_types;
      vm.lnUserNicename = angular.isDefined( response.data.nicename ) ? response.data.nicename : '';
      vm.lnUserDisplayName = angular.isDefined( response.data.display_name ) ? response.data.display_name : '';
      vm.lnUserFirstName = angular.isDefined( response.data.first_name ) ? response.data.first_name : '';
      vm.lnUserLastName = angular.isDefined( response.data.last_name ) ? response.data.last_name : '';
      vm.lnUserEmail = angular.isDefined( response.data.email ) ? response.data.email : '';

      _enableAdminBar();
    }
  }

  function _logError(error) {
    $log.error('lnMAdminBarService.getAdminBarData() -> error: ', error);
  }

  function _enableAdminBar() {
    vm.adminBarEnabled = true;
    $element.removeClass('ng-hide');
    $rootScope.$broadcast('lnMAdminBarEnabled');
  }

  function _disableAdminBar() {
    vm.adminBarEnabled = false;
    $element.addClass('ng-hide');
    $rootScope.$broadcast('lnMAdminBarDisabled');
  }
}
<|endoftext|>


<commit_before>'use strict';

import { Dimensions, Platform } from 'react-native';

const domMutationObserveScript = `
  var MutationObserver =
    window.MutationObserver || window.WebKitMutationObserver;
  var observer = new MutationObserver(updateSize);
  observer.observe(document, {
    subtree: true,
    attributes: true
  });
`;

const updateSizeWithMessage = (element, scalesPageToFit) =>
  `
  var scale = ${scalesPageToFit ? 'screen.width / window.innerWidth' : '1'};
  var lastHeight = 0;
  var heightTheSameTimes = 0;
  var maxHeightTheSameTimes = 5;
  var forceRefreshDelay = 1000;
  var forceRefreshTimeout;

  function updateSize(event) {
    if (
      !window.hasOwnProperty('ReactNativeWebView') ||
      !window.ReactNativeWebView.hasOwnProperty('postMessage')
    ) {
      setTimeout(updateSize, 200);
      return;
    }
    height = ${element}.offsetHeight || document.documentElement.offsetHeight;
    width = ${element}.offsetWidth || document.documentElement.offsetWidth;
    var needScale = width > screen.width;
    window.ReactNativeWebView.postMessage(JSON.stringify({ width: needScale ? width * scale : width, height: needScale ? height * scale : height }));

    // Make additional height checks (required to fix issues wit twitter embeds)
    clearTimeout(forceRefreshTimeout);
    if (lastHeight !== height) {
      heightTheSameTimes = 1;
    } else {
      heightTheSameTimes++;
    }

    lastHeight = height;

    if (heightTheSameTimes <= maxHeightTheSameTimes) {
      forceRefreshTimeout = setTimeout(
        updateSize,
        heightTheSameTimes * forceRefreshDelay
      );
    }
  }
  `;

// add viewport setting to meta
const makeScalePageToFit = (zoomable, scalesPageToFit) =>
  scalesPageToFit || Platform.OS === 'android'
    ? ''
    : `
  var meta = document.createElement("meta");
  meta.setAttribute("name", "viewport");
  meta.setAttribute("content", "width=device-width, user-scalable=${zoomable ? 'yes' : 'no'}");
  document.getElementsByTagName("head")[0].appendChild(meta);
`;

const getBaseScript = ({ style, zoomable, scalesPageToFit }) =>
  `
  ;
  if (!document.getElementById("rnahw-wrapper")) {
    var wrapper = document.createElement('div');
    wrapper.id = 'rnahw-wrapper';
    while (document.body.firstChild instanceof Node) {
      wrapper.appendChild(document.body.firstChild);
    }
    document.body.appendChild(wrapper);
  }
  ${updateSizeWithMessage('wrapper', scalesPageToFit)}
  window.addEventListener('load', updateSize);
  window.addEventListener('resize', updateSize);
  ${domMutationObserveScript}
  ${makeScalePageToFit(zoomable, scalesPageToFit)}
  updateSize();
  `;

const appendFilesToHead = ({ files, script }) =>
  files.reduceRight((combinedScript, file) => {
    const { rel, type, href } = file;
    return `
      var link  = document.createElement('link');
      link.rel  = '${rel}';
      link.type = '${type}';
      link.href = '${href}';
      document.head.appendChild(link);
      ${combinedScript}
    `;
  }, script);

const screenWidth = Dimensions.get('window').width;

const bodyStyle = `
body {
  margin: 0;
  padding: 0;
}
`;

const appendStylesToHead = ({ style, script }) => {
  const currentStyles = style ? bodyStyle + style : bodyStyle;
  // Escape any single quotes or newlines in the CSS with .replace()
  const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
  return `
    var styleElement = document.createElement('style');
    styleElement.innerHTML = '${escaped}';
    document.head.appendChild(styleElement);
    ${script}
  `;
};

const getInjectedSource = ({ html, script }) => `
${html}
<script>
// prevents code colissions with global scope
(() => {
  ${script}
})();
</script>
`;

const getScript = ({ files, customStyle, customScript, style, zoomable, scalesPageToFit }) => {
  let script = getBaseScript({ style, zoomable, scalesPageToFit });
  script = files && files.length > 0 ? appendFilesToHead({ files, script }) : script;
  script = appendStylesToHead({ style: customStyle, script });
  customScript && (script = customScript + script);
  return script;
};

export const getWidth = style => {
  return style && style.width ? style.width : screenWidth;
};

export const isSizeChanged = ({ height, previousHeight, width, previousWidth }) => {
  if (!height || !width) {
    return;
  }
  return height !== previousHeight || width !== previousWidth;
};

export const reduceData = props => {
  const { source } = props;
  const script = getScript(props);
  const { html, baseUrl } = source;
  if (html) {
    return {
      currentSource: { baseUrl, html: getInjectedSource({ html, script }) }
    };
  } else {
    return {
      currentSource: source,
      script
    };
  }
};

export const shouldUpdate = ({ prevProps, nextProps }) => {
  if (!(prevProps && nextProps)) {
    return true;
  }
  for (const prop in nextProps) {
    if (nextProps[prop] !== prevProps[prop]) {
      if (typeof nextProps[prop] === 'object' && typeof prevProps[prop] === 'object') {
        if (
          shouldUpdate({
            prevProps: prevProps[prop],
            nextProps: nextProps[prop]
          })
        ) {
          return true;
        }
      } else {
        return true;
      }
    }
  }
  return false;
};
<commit_msg>using function instead of arrow function for getInjectedSource to fix arrow function not supported problem below android 6.0, https://github.com/iou90/react-native-autoheight-webview/issues/139<commit_after>'use strict';

import { Dimensions, Platform } from 'react-native';

const domMutationObserveScript = `
  var MutationObserver =
    window.MutationObserver || window.WebKitMutationObserver;
  var observer = new MutationObserver(updateSize);
  observer.observe(document, {
    subtree: true,
    attributes: true
  });
`;

const updateSizeWithMessage = (element, scalesPageToFit) =>
  `
  var scale = ${scalesPageToFit ? 'screen.width / window.innerWidth' : '1'};
  var lastHeight = 0;
  var heightTheSameTimes = 0;
  var maxHeightTheSameTimes = 5;
  var forceRefreshDelay = 1000;
  var forceRefreshTimeout;
  var checkPostMessageTimeout;

  function updateSize(event) {
    if (
      !window.hasOwnProperty('ReactNativeWebView') ||
      !window.ReactNativeWebView.hasOwnProperty('postMessage')
    ) {
      checkPostMessageTimeout = setTimeout(updateSize, 200);
      return;
    }
    clearTimeout(checkPostMessageTimeout);
    height = ${element}.offsetHeight || document.documentElement.offsetHeight;
    width = ${element}.offsetWidth || document.documentElement.offsetWidth;
    var needScale = width > screen.width;
    window.ReactNativeWebView.postMessage(JSON.stringify({ width: needScale ? width * scale : width, height: needScale ? height * scale : height }));

    // Make additional height checks (required to fix issues wit twitter embeds)
    clearTimeout(forceRefreshTimeout);
    if (lastHeight !== height) {
      heightTheSameTimes = 1;
    } else {
      heightTheSameTimes++;
    }

    lastHeight = height;

    if (heightTheSameTimes <= maxHeightTheSameTimes) {
      forceRefreshTimeout = setTimeout(
        updateSize,
        heightTheSameTimes * forceRefreshDelay
      );
    }
  }
  `;

// add viewport setting to meta
const makeScalePageToFit = (zoomable, scalesPageToFit) =>
  scalesPageToFit || Platform.OS === 'android'
    ? ''
    : `
  var meta = document.createElement("meta");
  meta.setAttribute("name", "viewport");
  meta.setAttribute("content", "width=device-width, user-scalable=${zoomable ? 'yes' : 'no'}");
  document.getElementsByTagName("head")[0].appendChild(meta);
`;

const getBaseScript = ({ style, zoomable, scalesPageToFit }) =>
  `
  ;
  if (!document.getElementById("rnahw-wrapper")) {
    var wrapper = document.createElement('div');
    wrapper.id = 'rnahw-wrapper';
    while (document.body.firstChild instanceof Node) {
      wrapper.appendChild(document.body.firstChild);
    }
    document.body.appendChild(wrapper);
  }
  ${updateSizeWithMessage('wrapper', scalesPageToFit)}
  window.addEventListener('load', updateSize);
  window.addEventListener('resize', updateSize);
  ${domMutationObserveScript}
  ${makeScalePageToFit(zoomable, scalesPageToFit)}
  updateSize();
  `;

const appendFilesToHead = ({ files, script }) =>
  files.reduceRight((combinedScript, file) => {
    const { rel, type, href } = file;
    return `
      var link  = document.createElement('link');
      link.rel  = '${rel}';
      link.type = '${type}';
      link.href = '${href}';
      document.head.appendChild(link);
      ${combinedScript}
    `;
  }, script);

const screenWidth = Dimensions.get('window').width;

const bodyStyle = `
body {
  margin: 0;
  padding: 0;
}
`;

const appendStylesToHead = ({ style, script }) => {
  const currentStyles = style ? bodyStyle + style : bodyStyle;
  // Escape any single quotes or newlines in the CSS with .replace()
  const escaped = currentStyles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
  return `
    var styleElement = document.createElement('style');
    styleElement.innerHTML = '${escaped}';
    document.head.appendChild(styleElement);
    ${script}
  `;
};

const getInjectedSource = ({ html, script }) => `
${html}
<script>
// prevents code colissions with global scope
(function() {
  ${script}
})();
</script>
`;

const getScript = ({ files, customStyle, customScript, style, zoomable, scalesPageToFit }) => {
  let script = getBaseScript({ style, zoomable, scalesPageToFit });
  script = files && files.length > 0 ? appendFilesToHead({ files, script }) : script;
  script = appendStylesToHead({ style: customStyle, script });
  customScript && (script = customScript + script);
  return script;
};

export const getWidth = style => {
  return style && style.width ? style.width : screenWidth;
};

export const isSizeChanged = ({ height, previousHeight, width, previousWidth }) => {
  if (!height || !width) {
    return;
  }
  return height !== previousHeight || width !== previousWidth;
};

export const reduceData = props => {
  const { source } = props;
  const script = getScript(props);
  const { html, baseUrl } = source;
  if (html) {
    return {
      currentSource: { baseUrl, html: getInjectedSource({ html, script }) }
    };
  } else {
    return {
      currentSource: source,
      script
    };
  }
};

export const shouldUpdate = ({ prevProps, nextProps }) => {
  if (!(prevProps && nextProps)) {
    return true;
  }
  for (const prop in nextProps) {
    if (nextProps[prop] !== prevProps[prop]) {
      if (typeof nextProps[prop] === 'object' && typeof prevProps[prop] === 'object') {
        if (
          shouldUpdate({
            prevProps: prevProps[prop],
            nextProps: nextProps[prop]
          })
        ) {
          return true;
        }
      } else {
        return true;
      }
    }
  }
  return false;
};
<|endoftext|>


<commit_before>
import React, {
    Component,
} from 'react'
import {
    View,
    Text,
    StyleSheet,
    Dimensions,
    ActivityIndicator,
    Modal,
    Alert,
    NativeModules,
} from 'react-native'

import Button from 'react-native-smart-button'
import TimerEnhance from 'react-native-smart-timer-enhance'
import Toast from 'react-native-smart-toast'

class LoadingToast extends Component {

    constructor(props) {
        super(props)
        this.state = {}
    }

    render() {
        return (
            <View style={{ paddingTop: 64, flex: 1, backgroundColor: '#fff',}}>
                <Button
                    onPress={this._showTopToast}
                    touchableType={Button.constants.touchableTypes.fadeContent}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show top
                </Button>

                <Button
                    onPress={this._showCenterToast}
                    touchableType={Button.constants.touchableTypes.highlight}
                    underlayColor={'#C90000'}
                    style={{margin: 10, justifyContent: 'center', height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show center
                </Button>

                <Button
                    onPress={this._showBottomToast}
                    touchableType={Button.constants.touchableTypes.blur}
                    style={{margin: 10, justifyContent: 'center', height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17,  color: 'white'}}

                >
                    show bottom
                </Button>
                <Button
                    onPress={this._showFastToast}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show fast
                </Button>
                <Button
                    onPress={this._showFastToastAndAnimatedHide}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show fast immediate hide
                </Button>
                <Button
                    onPress={this._showImmediateToast}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show immediate
                </Button>
                <Button
                    onPress={this._showImmediateToastAndAnimatedHide}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show immediate animated hide
                </Button>

                <Toast
                    ref={ component => this._toast = component }
                    marginTop={64}>
                    Unable to connect to app store
                </Toast>
            </View>
        )
    }

    _showTopToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.top,
        })
    }

    _showCenterToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
        })
    }

    _showBottomToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.bottom,
        })
    }

    _showFastToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 255,
        })
    }

    _showFastToastAndAnimatedHide = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 255,
            animationEnd : () => {
                this._toast._toastAnimationToggle = this.setTimeout( () => {
                    this._toast.hide({
                        duration: 0,
                        animationEnd: () => {
                            //do sth...
                        }
                    })
                }, 3000)
            }
        })
    }

    _showImmediateToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 0,
        })
    }
    _showImmediateToastAndAnimatedHide = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 0,
            animationEnd : () => {
                this._toast._toastAnimationToggle = this.setTimeout( () => {
                    this._toast.hide({
                        animationEnd: () => {
                            //do sth...
                        }
                    })
                }, 3000)
            }
        })
    }

}

export default TimerEnhance(LoadingToast)<commit_msg>updated usage<commit_after>
import React, {
    Component,
} from 'react'
import {
    View,
    Text,
    StyleSheet,
    Dimensions,
    ActivityIndicator,
    Modal,
    Alert,
    NativeModules,
} from 'react-native'

import Button from 'react-native-smart-button'
import TimerEnhance from 'react-native-smart-timer-enhance'
import Toast from 'react-native-smart-toast'

class LoadingToast extends Component {

    constructor(props) {
        super(props)
        this.state = {}
    }

    render() {
        return (
            <View style={{ paddingTop: 64, flex: 1, backgroundColor: '#fff',}}>
                <Button
                    onPress={this._showTopToast}
                    touchableType={Button.constants.touchableTypes.fadeContent}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show top (顶部显示)
                </Button>

                <Button
                    onPress={this._showCenterToast}
                    touchableType={Button.constants.touchableTypes.highlight}
                    underlayColor={'#C90000'}
                    style={{margin: 10, justifyContent: 'center', height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show center (中心显示)
                </Button>

                <Button
                    onPress={this._showBottomToast}
                    touchableType={Button.constants.touchableTypes.blur}
                    style={{margin: 10, justifyContent: 'center', height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17,  color: 'white'}}

                >
                    show bottom (底部显示)
                </Button>
                <Button
                    onPress={this._showFastToast}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show fast (快速显示)
                </Button>
                <Button
                    onPress={this._showFastToastAndAnimatedHide}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show fast immediate hide
                </Button>
                <Button
                    onPress={this._showImmediateToast}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show immediate (立即显示)
                </Button>
                <Button
                    onPress={this._showImmediateToastAndAnimatedHide}
                    style={{margin: 10, height: 40, backgroundColor: 'red', borderRadius: 3, borderWidth: StyleSheet.hairlineWidth, borderColor: 'red', justifyContent: 'center',}}
                    textStyle={{fontSize: 17, color: 'white'}}
                >
                    show immediate animated hide
                </Button>

                <Toast
                    ref={ component => this._toast = component }
                    marginTop={64}>
                    Unable to connect to apple store
                </Toast>
            </View>
        )
    }

    _showTopToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.top,
        })
    }

    _showCenterToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            children: <View><Text style={{color: 'yellow'}}>Unalbe to download now</Text></View>
        })
    }

    _showBottomToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.bottom,
            children: 'Unalbe to upload now'
        })
    }

    _showFastToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 255,
            children: 'Unable to connect to apple store'
        })
    }

    _showFastToastAndAnimatedHide = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 255,
            children: 'Unable to connect to google store',
            animationEnd : () => {
                this._toast._toastAnimationToggle = this.setTimeout( () => {
                    this._toast.hide({
                        duration: 0,
                        animationEnd: () => {
                            //do sth...
                        }
                    })
                }, 3000)
            }
        })
    }

    _showImmediateToast = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 0,
            children: 'Unable to connect to wifi',
        })
    }
    _showImmediateToastAndAnimatedHide = () => {
        this._toast.show({
            position: Toast.constants.gravity.center,
            duration: 0,
            children: 'Unable to connect to wlan',
            animationEnd : () => {
                this._toast._toastAnimationToggle = this.setTimeout( () => {
                    this._toast.hide({
                        animationEnd: () => {
                            //do sth...
                        }
                    })
                }, 3000)
            }
        })
    }

}

export default TimerEnhance(LoadingToast)<|endoftext|>


<commit_before>"use strict";

jest.dontMock("../index.js");
describe("index", function() {
  it("changes the text after click", function() {
    var index = require("../index");

    expect(index).toBeDefined();
    expect(index.ToastContainer).toBeDefined();
    expect(index.ToastMessage).toBeDefined();
  });
});
<commit_msg>test(index): make sure es2015 works<commit_after>"use strict";

jest.dontMock("../index.js");
describe("index", () => {
  it("changes the text after click", () => {
    const index = require("../index");

    expect(index).toBeDefined();
    expect(index.ToastContainer).toBeDefined();
    expect(index.ToastMessage).toBeDefined();
  });
});
<|endoftext|>


<commit_before>var path    = require('path')
var fs      = require('fs')
var http    = require('http')
var __slice = [].slice

var cadence = require('cadence')
var connect = require('connect')

function httpStatusMessage(statusCode) {
    return statusCode + ' ' + http.STATUS_CODES[statusCode] + '\n'
}

exports.createServer = function (port, directory, probe, callback) {
    var server = http.createServer()

    var routes = exports.routes(directory)
    server.on('request', function (request, response) {
        routes(request, response, function (error, matched) {
            if (error) server.emit('error', error)
            else if (!matched) {
                response.statusCode = 404
                response.setHeader('content-type', 'text/plain; charset=utf8')
                response.end(httpStatusMessage(404), 'utf8')
            }
        })
    })

    server.on('error', nextPort)

    function nextPort (e) {
        if (!probe || e.code != 'EADDRINUSE') callback(e)
        else server.listen(++port, '127.0.0.1')
    }

    server.on('listening', function () {
        server.removeListener('error', nextPort)
        callback(null, server)
    })

    server.listen(port, '127.0.0.1')
}

exports.argvParser = function (cwd, file, args) {
    args = args.slice()
    var url = require('url')
    var object = { method: 'get' }
    var parsed, $

    if ($ = /^(.*?)\/\/(.*)$/.exec(file)) {
        object.directory = path.resolve(cwd, $[1])
        file = $[2]
    } else {
        object.directory = path.resolve(cwd, path.dirname(file))
        file = path.basename(file)
    }

    if (args[0] && /^[a-z]{3,}$/i.test(args[0])) {
        object.method = args.shift().toLowerCase()
    }

    // todo: no. only invoke as intended. do not specify alternate path.
    if (/^\s*\//.test(args[0]) || /^[^=:]+:/.test(args[0])) {
        parsed = url.parse(args.shift(), true)
    } else {
        parsed = url.parse(file, true)
    }

    args.forEach(function (pair) {
        var $ = /^([^=]*)(?:=(.*))$/.exec(pair)
        parsed.query[$[1]] = $[2]
    })

    delete parsed.search

    object.url = url.parse(url.format(parsed), true)

    return object
}

function Register (file) {
    this._file = file
    this._handlers = {}
}

'any get post put delete patch'.split(/\s/).forEach(function (verb) {
    Register.prototype[verb] = function (handler) {
        this._handlers[verb] = handler
        return this
    }
})

function parameterize (program, context) {
    var $ = /^function\s*[^(]*\(([^)]*)\)/.exec(program.toString())
    return $[1].trim().split(/\s*,\s*/).map(function (parameter) {
        return context[parameter]
    })
}

var compiled = []

function raise (statusCode, headers) {
    var error = new Error
    error.statusCode = statusCode
    if (headers) {
        error.headers = headers
    }
    throw error
}

exports.routes = function routes (base) {
    var find = require('avenue')
    var path = require('path')

    var url = require('url')
    var routes = find(base, 'cgi.js')

    routes.forEach(function (route) {
        var file = path.join(base, route.script)
        if (!compiled[file]) {
            try {
                global.on = compiled[file] = new Register(file)
                require(file)
            } finally {
                delete global.on
            }
        }
    })

    var reactor = require('locate')(routes)

    return cadence(function (step, request, response) {
        var method = request.method.toLowerCase()
        var uri = url.parse(request.url, true)
        var found = reactor(uri.pathname).map(function (match) {
            // todo: resolve?
            var script = path.join(base, match.route.script)
            return {
                params: match.params,
                register: compiled[script]
            }
        })
        function middleware () {
            var methods = __slice.call(arguments)
            var callback = methods.pop()
            var called
            if (methods.length) {
                var method = methods.shift()
                method(request, response, function (error) {
                    called = true
                    response.removeListener('headers', callback)
                    if (error) callback(error)
                    else middleware.apply(this, methods.concat(callback))
                })
                response.on('header', function () {
                    if (!called) process.nextTick(function () {
                        middleware.apply(this, methods.concat(callback))
                    })
                    called = true
                })
            } else {
                callback()
            }
        }
        step(function (match) {
            var context = {
                step: step,
                request: request,
                response: response,
                middleware: middleware,
                raise: raise,
                params: match.params
            }
            step(function () {
                if (method == 'post' && request.body && request.body._method) {
                    method = request.body._method.toLowerCase()
                }
                var handler = match.register._handlers[method] ||
                              match.register._handlers.any
                if  (handler) step([function () {
                    handler.apply(context, parameterize(handler, context))
                }, function (errors, error) {
                    if (('statusCode' in error) && !response.headersSent) {
                        var headers = error.headers || {}
                        for (var name in headers) {
                            response.setHeader(name, headers[name])
                        }
                        response.statusCode = error.statusCode
                        response.setHeader('content-type', 'text/html; charset=utf8')
                        response.end(error.body || httpStatusMessage(error.statusCode), 'utf8')
                    } else {
                        throw errors
                    }
                }])
            }, function () {
                if (response.headersSent) step(null, true)
            })
        })(found)
    })
}

// TODO: Probably needs to return an object to shut it down, or an event emitter
// of some kind, so that the caller can handle all errors. A curious case.
exports.once = cadence(function (step, cwd, path, args, stdin) {
    var url = require('url')
    var request = require('request')
    var object = exports.argvParser(cwd, path, args)

    step(function () {
        exports.createServer(8386, object.directory, true, step())
    }, function (server) {
        var parsed = object.url

        parsed.protocol = 'http'
        parsed.hostname = '127.0.0.1'
        parsed.port = server.address().port

        var req = request({
            method: object.method,
            timeout: 1000,
            uri: url.format(parsed),
            // todo: configurable, somehow
            headers: {
                "content-type": "application/x-www-form-urlencoded"
            }
        })

        server.once('error', step(Error))
        req.on('error', step(Error))

        if (object.method != 'get') {
            stdin.pipe(req)
        } else {
            req.end()
        }

        step(function () {
            req.on('response', step(-1))
        }, function (response) {
            step(null, response, server)
            server.close()
        })
    })
})

exports.runner = cadence(function (step, options, stdin, stdout, stderr) {
    var directory
    var location

    if (!options.argv.length) options.abend('path required')

    step(function () {
        location = options.argv.shift()
        step([function () {
            fs.stat(location, step())
        }, /^ENOENT$/, function () {
            options.abend('path not found', location)
        }], function (stat) {
            if (stat.isDirectory() && ! /\/\//.test(location)) {
                step(function () {
                    exports.createServer(8386, path.resolve(process.cwd(), location), true, step())
                }, function (server) {
                    stdout.write('server pid ' + process.pid + ' listening at ' + server.address().port)
                    return server
                })
            } else {
                step(function () {
                    location = location.replace(/\.cgi\.js$/, '')
                    exports.once(process.cwd(), location, options.argv, stdin, step())
                }, function (request) {
                    request.pipe(stdout)
                    request.on('end', step(-1))
                })
            }
        })
    })
})
<commit_msg>Compiled scripts are now stored in an object.<commit_after>var path    = require('path')
var fs      = require('fs')
var http    = require('http')
var __slice = [].slice

var cadence = require('cadence')
var connect = require('connect')

function httpStatusMessage(statusCode) {
    return statusCode + ' ' + http.STATUS_CODES[statusCode] + '\n'
}

exports.createServer = function (port, directory, probe, callback) {
    var server = http.createServer()

    var routes = exports.routes(directory)
    server.on('request', function (request, response) {
        routes(request, response, function (error, matched) {
            if (error) server.emit('error', error)
            else if (!matched) {
                response.statusCode = 404
                response.setHeader('content-type', 'text/plain; charset=utf8')
                response.end(httpStatusMessage(404), 'utf8')
            }
        })
    })

    server.on('error', nextPort)

    function nextPort (e) {
        if (!probe || e.code != 'EADDRINUSE') callback(e)
        else server.listen(++port, '127.0.0.1')
    }

    server.on('listening', function () {
        server.removeListener('error', nextPort)
        callback(null, server)
    })

    server.listen(port, '127.0.0.1')
}

exports.argvParser = function (cwd, file, args) {
    args = args.slice()
    var url = require('url')
    var object = { method: 'get' }
    var parsed, $

    if ($ = /^(.*?)\/\/(.*)$/.exec(file)) {
        object.directory = path.resolve(cwd, $[1])
        file = $[2]
    } else {
        object.directory = path.resolve(cwd, path.dirname(file))
        file = path.basename(file)
    }

    if (args[0] && /^[a-z]{3,}$/i.test(args[0])) {
        object.method = args.shift().toLowerCase()
    }

    // todo: no. only invoke as intended. do not specify alternate path.
    if (/^\s*\//.test(args[0]) || /^[^=:]+:/.test(args[0])) {
        parsed = url.parse(args.shift(), true)
    } else {
        parsed = url.parse(file, true)
    }

    args.forEach(function (pair) {
        var $ = /^([^=]*)(?:=(.*))$/.exec(pair)
        parsed.query[$[1]] = $[2]
    })

    delete parsed.search

    object.url = url.parse(url.format(parsed), true)

    return object
}

function Register (file) {
    this._file = file
    this._handlers = {}
}

'any get post put delete patch'.split(/\s/).forEach(function (verb) {
    Register.prototype[verb] = function (handler) {
        this._handlers[verb] = handler
        return this
    }
})

function parameterize (program, context) {
    var $ = /^function\s*[^(]*\(([^)]*)\)/.exec(program.toString())
    return $[1].trim().split(/\s*,\s*/).map(function (parameter) {
        return context[parameter]
    })
}

var compiled = {}

function raise (statusCode, headers) {
    var error = new Error
    error.statusCode = statusCode
    if (headers) {
        error.headers = headers
    }
    throw error
}

exports.routes = function routes (base) {
    var find = require('avenue')
    var path = require('path')

    var url = require('url')
    var routes = find(base, 'cgi.js')

    routes.forEach(function (route) {
        var file = path.join(base, route.script)
        if (!compiled[file]) {
            try {
                global.on = compiled[file] = new Register(file)
                require(file)
            } finally {
                delete global.on
            }
        }
    })

    var reactor = require('locate')(routes)

    return cadence(function (step, request, response) {
        var method = request.method.toLowerCase()
        var uri = url.parse(request.url, true)
        var found = reactor(uri.pathname).map(function (match) {
            // todo: resolve?
            var script = path.join(base, match.route.script)
            return {
                params: match.params,
                register: compiled[script]
            }
        })
        function middleware () {
            var methods = __slice.call(arguments)
            var callback = methods.pop()
            var called
            if (methods.length) {
                var method = methods.shift()
                method(request, response, function (error) {
                    called = true
                    response.removeListener('headers', callback)
                    if (error) callback(error)
                    else middleware.apply(this, methods.concat(callback))
                })
                response.on('header', function () {
                    if (!called) process.nextTick(function () {
                        middleware.apply(this, methods.concat(callback))
                    })
                    called = true
                })
            } else {
                callback()
            }
        }
        step(function (match) {
            var context = {
                step: step,
                request: request,
                response: response,
                middleware: middleware,
                raise: raise,
                params: match.params
            }
            step(function () {
                if (method == 'post' && request.body && request.body._method) {
                    method = request.body._method.toLowerCase()
                }
                var handler = match.register._handlers[method] ||
                              match.register._handlers.any
                if  (handler) step([function () {
                    handler.apply(context, parameterize(handler, context))
                }, function (errors, error) {
                    if (('statusCode' in error) && !response.headersSent) {
                        var headers = error.headers || {}
                        for (var name in headers) {
                            response.setHeader(name, headers[name])
                        }
                        response.statusCode = error.statusCode
                        response.setHeader('content-type', 'text/html; charset=utf8')
                        response.end(error.body || httpStatusMessage(error.statusCode), 'utf8')
                    } else {
                        throw errors
                    }
                }])
            }, function () {
                if (response.headersSent) step(null, true)
            })
        })(found)
    })
}

// TODO: Probably needs to return an object to shut it down, or an event emitter
// of some kind, so that the caller can handle all errors. A curious case.
exports.once = cadence(function (step, cwd, path, args, stdin) {
    var url = require('url')
    var request = require('request')
    var object = exports.argvParser(cwd, path, args)

    step(function () {
        exports.createServer(8386, object.directory, true, step())
    }, function (server) {
        var parsed = object.url

        parsed.protocol = 'http'
        parsed.hostname = '127.0.0.1'
        parsed.port = server.address().port

        var req = request({
            method: object.method,
            timeout: 1000,
            uri: url.format(parsed),
            // todo: configurable, somehow
            headers: {
                "content-type": "application/x-www-form-urlencoded"
            }
        })

        server.once('error', step(Error))
        req.on('error', step(Error))

        if (object.method != 'get') {
            stdin.pipe(req)
        } else {
            req.end()
        }

        step(function () {
            req.on('response', step(-1))
        }, function (response) {
            step(null, response, server)
            server.close()
        })
    })
})

exports.runner = cadence(function (step, options, stdin, stdout, stderr) {
    var directory
    var location

    if (!options.argv.length) options.abend('path required')

    step(function () {
        location = options.argv.shift()
        step([function () {
            fs.stat(location, step())
        }, /^ENOENT$/, function () {
            options.abend('path not found', location)
        }], function (stat) {
            if (stat.isDirectory() && ! /\/\//.test(location)) {
                step(function () {
                    exports.createServer(8386, path.resolve(process.cwd(), location), true, step())
                }, function (server) {
                    stdout.write('server pid ' + process.pid + ' listening at ' + server.address().port)
                    return server
                })
            } else {
                step(function () {
                    location = location.replace(/\.cgi\.js$/, '')
                    exports.once(process.cwd(), location, options.argv, stdin, step())
                }, function (request) {
                    request.pipe(stdout)
                    request.on('end', step(-1))
                })
            }
        })
    })
})
<|endoftext|>


<commit_before>(function() {
  describe('the main app', function()  {
    it('is currently ok, even without tests', function()  {
      expect(true).toBeTruthy();
    });
  });
})();
<commit_msg>No test right now<commit_after><|endoftext|>


<commit_before>var t = require('./titanic');
var krun = require('./krun');

/*t.addAction(function(done) {
  console.log('action a');
  done();
});
t.addAction(function(done) {
  console.log('action b');
  done();
});
t.addAction(function(done) {
  console.log('action c');
  done();
});*/

t.addAction(function(done) {
  krun()
  .run('kbox down', 20).ok()
  .run('kbox status', 5).ok().expect('down\n')
  .run('kbox up', 30).ok()
  .run('kbox status', 5).ok().expect('up\n')
  .call(function(done) {
    console.log('output -> ' + this.output);
    done();
  })
  .done(done);
});

/*t.addCheck(function(done) {
  console.log('check a');
  done();
});
t.addCheck(function(done) {
  console.log('check b');
  done();
});
t.addCheck(function(done) {
  console.log('check c');
  done();
});*/

t.addCheck(function(done) {
  krun()
  .run('kbox status')
  .ok()
  .expect('up\n')
  .done(done);
});

var restore = function(done) {
  done();
};

var runs = 20;
var cursor = 0;

t.run(
function() {

  cursor += 1;
  return cursor <= runs;

},
restore,
function(err) {

  if (err) {
    throw err;
  }

});
<commit_msg>Cleaning up example.<commit_after>var t = require('./titanic');
var krun = require('./krun');

t.addAction(function(done) {
  krun()
  .run('kbox down', 20).ok()
  .run('kbox status', 5).ok().expect('down\n')
  .run('kbox up', 30).ok()
  .run('kbox status', 5).ok().expect('up\n')
  .call(function(done) {
    console.log('output -> ' + this.output);
    done();
  })
  .done(done);
});

t.addCheck(function(done) {
  krun()
  .run('kbox status')
  .ok()
  .expect('up\n')
  .done(done);
});

var restore = function(done) {
  done();
};

var runs = 20;
var cursor = 0;

t.run(
function() {

  cursor += 1;
  return cursor <= runs;

},
restore,
function(err) {

  if (err) {
    throw err;
  }

});
<|endoftext|>


<commit_before>// Fix for webpack not exporting ES6 module default properly when using global mode of UMD. It ends
// up with someone having to do "PhaserNavmesh.default" instead of "PhaserNavmesh"
module.exports = require("./nav-mesh").default;
<commit_msg>Remove old export hack<commit_after>import NavMesh from "./navmesh";

export default NavMesh;
<|endoftext|>


<commit_before>'use strict'

let utf8 = require('./util').utf8

module.exports = {
  broker: null,
  configuration: null,
  intervalID: -1,

  create: function (broker, configuration) {
    this.broker = broker;
    this.configuration = configuration;
    return true;
  },

  start: function () {
    this.intervalID = setInterval(() => {
      let content = {
        eda: Math.floor(Math.random() * 40) + 10, //random 10-50
        bvp: Math.floor(Math.random() * 20) + 50 //random 50-70
      };
      this.broker.publish({
        properties: { source: 'simulated-device' },
        content: utf8.encode(content)
      });
    }, 500);
  },

  receive: function (message) { },

  destroy: function () {
    if (this.intervalID !== -1)
      clearInterval(this.intervalID)
  }
}
<commit_msg>randomize simulated-device data<commit_after>'use strict'

let utf8 = require('./util').utf8

module.exports = {
  broker: null,
  configuration: null,
  intervalID: -1,

  create: function (broker, configuration) {
    this.broker = broker;
    this.configuration = configuration;
    return true;
  },

  start: function () {
    let devices = ['device00', 'device01', 'device02', 'device03'];
    this.intervalID = setInterval(() => {
      let content = {
        property1: Math.random(),
        property2: Math.random()
      };
      this.broker.publish({
        properties: {
          source: 'simulated-device',
          deviceId: devices[Math.floor(Math.random() * devices.length)]
        },
        content: utf8.encode(content)
      });
    }, 500);
  },

  receive: function (message) { },

  destroy: function () {
    if (this.intervalID !== -1)
      clearInterval(this.intervalID)
  }
}
<|endoftext|>


<commit_before>/*jslint browser: true, undef: true *//*global Ext*/
/**
 * TODO:
 * - Just extend Server and deprecated the other stuff Ajax does? callParent for buildrequest?
 */
Ext.define('Jarvus.proxy.API', {
    extend: 'Ext.data.proxy.Server',
    alias: 'proxy.api',
    requires: [
        'Jarvus.util.API'
    ],

    config: {
        /**
         * @cfg The {Ext.data.Connection} instance that will process requests
         * @required
         */
        connection: 'Jarvus.util.API',

        /**
         * @cfg Whether simple remote filters should be written to params
         */
        writeFilterParams: true,

        headers: null,

        noCache: false,

        directionParam: false,
        filterParam: false,
        groupDirectionParam: false,
        groupParam: false,
        idParam: false,
        limitParam: false,
        pageParam: false,
        sortParam: false,
        startParam: false
    },

    /**
     * Automatically inject "connection" class into requires
     */
    onClassExtended: function(cls, data, hooks) {
        var connection = data.connection || data.config && data.config.connection,
            onBeforeClassCreated;

        if (typeof connection === 'string') {
            onBeforeClassCreated = hooks.onBeforeCreated;

            hooks.onBeforeCreated = function() {
                var me = this,
                    args = arguments;

                Ext.require(connection, function() {
                    onBeforeClassCreated.apply(me, args);
                });
            };
        }
    },

    /**
     * Convert "connection" class into constructor reference
     */
    applyConnection: function(connection) {
        if (typeof connection == 'string') {
            Ext.syncRequire(connection);
            connection = Ext.ClassManager.get(connection);
        }

        return connection;
    },

    getMethod: function(request) {
        switch (request.getAction()) {
            case 'create':
                return 'POST';
            case 'read':
                return 'GET';
            case 'update':
                return 'PATCH';
            case 'destroy':
                return 'DELETE';
        }
    },

    getParams: function(operation) {
        var me = this,
            params = me.callParent(arguments);

        if (me.getWriteFilterParams()) {
            Ext.apply(params, me.getFilterParams(operation));
        }

        return params;
    },

    getFilterParams: function(operation) {
        var action = operation.getAction(),
            isRead = action == 'read',

            filters = isRead && operation.getFilters(),
            filtersLength = (filters && filters.length) || 0,
            filterIndex = 0,
            filter,

            params = {};

        // write filters
        for (; filterIndex < filtersLength; filterIndex++) {
            filter = filters[filterIndex];

            if (filter.getOperator()) {
                Ext.Error.raise('Filter operators are not currently supported on the sparkpoints proxy');
            }

            params[filter.getProperty()] = filter.getValue();
        }

        return params;
    },

    buildRequest: function(operation) {
        var me = this,
            request = me.callParent(arguments),
            params = request.getParams(),
            idParam = me.getIdParam();

        if (!idParam && idParam in params) {
            delete params[idParam];
        }

        request.setMethod(me.getMethod(request));
        request.setHeaders(me.getHeaders(request));
        request.setTimeout(me.getTimeout(request));

        return request;
    },

    doRequest: function(operation) {
        var me = this,
            writer = me.getWriter(),
            request = me.buildRequest(operation);;

        if (writer && operation.allowWrite()) {
            request = writer.write(request);
        }

        request.setCallback(function(options, success, response) {
            if (request === me.lastRequest) {
                me.lastRequest = null;
            }

            me.processResponse(success, operation, request, response);
        });

        return me.sendRequest(request);
    },

    sendRequest: function(request) {
        var me = this;

        request.setRawRequest(me.getConnection().request(Ext.applyIf({
            autoDecode: false,
            failureStatusCodes: [404] // TODO: verify this results in the proper failure method being called in the proxy
        }, request.getCurrentConfig())));

        me.lastRequest = request;

        return request;
    },

    abortLastRequest: function(silent) {
        var lastRequest = this.lastRequest;

        if(lastRequest) {
            lastRequest.options.silenceException = !!silent;
            Ext.Ajax.abort(lastRequest);
        }
    },

    destroy: function() {
        this.lastRequest = null;

        this.callParent();
    }
});
<commit_msg>Eliminate trailing whitespace<commit_after>/*jslint browser: true, undef: true *//*global Ext*/
/**
 * TODO:
 * - Just extend Server and deprecated the other stuff Ajax does? callParent for buildrequest?
 */
Ext.define('Jarvus.proxy.API', {
    extend: 'Ext.data.proxy.Server',
    alias: 'proxy.api',
    requires: [
        'Jarvus.util.API'
    ],

    config: {
        /**
         * @cfg The {Ext.data.Connection} instance that will process requests
         * @required
         */
        connection: 'Jarvus.util.API',

        /**
         * @cfg Whether simple remote filters should be written to params
         */
        writeFilterParams: true,

        headers: null,

        noCache: false,

        directionParam: false,
        filterParam: false,
        groupDirectionParam: false,
        groupParam: false,
        idParam: false,
        limitParam: false,
        pageParam: false,
        sortParam: false,
        startParam: false
    },

    /**
     * Automatically inject "connection" class into requires
     */
    onClassExtended: function(cls, data, hooks) {
        var connection = data.connection || data.config && data.config.connection,
            onBeforeClassCreated;

        if (typeof connection === 'string') {
            onBeforeClassCreated = hooks.onBeforeCreated;

            hooks.onBeforeCreated = function() {
                var me = this,
                    args = arguments;

                Ext.require(connection, function() {
                    onBeforeClassCreated.apply(me, args);
                });
            };
        }
    },

    /**
     * Convert "connection" class into constructor reference
     */
    applyConnection: function(connection) {
        if (typeof connection == 'string') {
            Ext.syncRequire(connection);
            connection = Ext.ClassManager.get(connection);
        }

        return connection;
    },

    getMethod: function(request) {
        switch (request.getAction()) {
            case 'create':
                return 'POST';
            case 'read':
                return 'GET';
            case 'update':
                return 'PATCH';
            case 'destroy':
                return 'DELETE';
        }
    },

    getParams: function(operation) {
        var me = this,
            params = me.callParent(arguments);

        if (me.getWriteFilterParams()) {
            Ext.apply(params, me.getFilterParams(operation));
        }

        return params;
    },

    getFilterParams: function(operation) {
        var action = operation.getAction(),
            isRead = action == 'read',

            filters = isRead && operation.getFilters(),
            filtersLength = (filters && filters.length) || 0,
            filterIndex = 0,
            filter,

            params = {};

        // write filters
        for (; filterIndex < filtersLength; filterIndex++) {
            filter = filters[filterIndex];

            if (filter.getOperator()) {
                Ext.Error.raise('Filter operators are not currently supported on the sparkpoints proxy');
            }

            params[filter.getProperty()] = filter.getValue();
        }

        return params;
    },

    buildRequest: function(operation) {
        var me = this,
            request = me.callParent(arguments),
            params = request.getParams(),
            idParam = me.getIdParam();

        if (!idParam && idParam in params) {
            delete params[idParam];
        }

        request.setMethod(me.getMethod(request));
        request.setHeaders(me.getHeaders(request));
        request.setTimeout(me.getTimeout(request));

        return request;
    },

    doRequest: function(operation) {
        var me = this,
            writer = me.getWriter(),
            request = me.buildRequest(operation);;

        if (writer && operation.allowWrite()) {
            request = writer.write(request);
        }

        request.setCallback(function(options, success, response) {
            if (request === me.lastRequest) {
                me.lastRequest = null;
            }

            me.processResponse(success, operation, request, response);
        });

        return me.sendRequest(request);
    },

    sendRequest: function(request) {
        var me = this;

        request.setRawRequest(me.getConnection().request(Ext.applyIf({
            autoDecode: false,
            failureStatusCodes: [404] // TODO: verify this results in the proper failure method being called in the proxy
        }, request.getCurrentConfig())));

        me.lastRequest = request;

        return request;
    },

    abortLastRequest: function(silent) {
        var lastRequest = this.lastRequest;

        if(lastRequest) {
            lastRequest.options.silenceException = !!silent;
            Ext.Ajax.abort(lastRequest);
        }
    },

    destroy: function() {
        this.lastRequest = null;

        this.callParent();
    }
});
<|endoftext|>


<commit_before>'use strict'
const getIndexInSorted = require('./indexInSortedArray')
const populateWithClientQuery = require('./populate-doc-util')
const liveQueriesMap = require('./live-queries-map')  // mapped by the query stringified
const debug = require('debug')('moonridge:live-query')
var _ = require('lodash')

/**
 * @param {String} qKey
 * @param {Mongoose.Query} mQuery
 * @param {Object} queryMethodsHandledByMoonridge are query methods which are important for branching in the LQ
 *                  syncing logic, we need their arguments accessible on separated object to be able to run
 *                  liveQuerying effectively
 * @returns {Object}
 * @constructor
 * @param {Object} model
 */
function LiveQuery (qKey, mQuery, queryMethodsHandledByMoonridge, model) {
  this.docs = []
  this.listeners = {}
  this.mQuery = mQuery   // mongoose query

  if (this.mQuery.op === 'distinct') {
    this.sync = LiveQuery.prototype.syncDistinct
  }

  this.qKey = qKey
  this.model = model
  this.modelName = model.modelName
  this.indexedByMethods = queryMethodsHandledByMoonridge // serializable client query object
  liveQueriesMap.get(this.model)[qKey] = this

  return this
}

LiveQuery.prototype = {
  destroy: function () {
    delete liveQueriesMap.get(this.model)[this.qKey]
  },
  /**
   *
   * @param {Document.Id} id
   * @returns {Number} -1 when not found
   */
  getIndexById: function (id) {
    id = id.id
    var i = this.docs.length
    while (i--) {
      var doc = this.docs[i]
      if (doc && doc._id.id === id) {
        return i
      }
    }
    return i
  },
  /**
   *
   * @param {Object|Mongoose.Document} doc
   * @param {String} evName
   * @param {Number} resultIndex number, indicates an index where the doc should be inserted, -1 for a document which
   *                 is no longer in the result of the query
   */
  _distributeChange: function (doc, evName, resultIndex) {
    var self = this
    var actuallySend = function () {
      for (var socketId in self.listeners) {
        var listener = self.listeners[socketId]
        var toSend = null

        if (listener.qOpts.count) {
          // we don't need to send a doc when query is a count query
        } else if (self.mQuery.op === 'distinct') {
          toSend = doc
        } else {
          if (evName === 'remove' && doc._id) {
            toSend = doc._id.toString()	// remove needs only _id, which should be always defined
          } else {
            toSend = self.model.moonridgeOpts.dataTransform(doc, 'R', listener.socket)
          }
        }

        debug('sending ', toSend, ' event ', evName, ', pos param ', resultIndex)
        listener.socket.rpc('MR.' + self.modelName + '.' + evName)(listener.clIndex, toSend, resultIndex)
      }
    }

    if (typeof doc.populate === 'function') {
      populateWithClientQuery(doc, this.indexedByMethods.populate, function (err, populated) {
        if (err) {
          throw err
        }
        doc = populated.toObject()
        actuallySend()
      })
    } else {
      actuallySend()
    }
  },
  registerListener: function (opts) {
    const socket = opts.socket
    debug(`listener ${socket.id} registered`)
    this.listeners[socket.id] = opts
  },
  /**
   * removes a socket listener from liveQuery and also destroys the whole liveQuery if no more listeners are present
   * @param socket
   */
  removeListener: function (socket) {
    if (this.listeners[socket.id]) {
      delete this.listeners[socket.id]
      if (Object.keys(this.listeners).length === 0) {
        this.destroy() // this will delete a liveQuery from liveQueries
      }
    } else {
      return new Error('no listener present on LQ ' + this.qKey)
    }
  },
  syncDistinct: function (opts) {
    var self = this

    return this.mQuery.exec(function (err, values) {
      if (err) {
        console.error('err', err)
        throw err
      }
      var syncObj = {}
      syncObj.add = _.difference(values, self.values)
      syncObj.remove = _.difference(self.values, values)
      self.values = values
      debug('reran distinct query with a result: ', values, syncObj)
      self._distributeChange(syncObj, 'distinctSync')
    })
  },
  /**
   * @param {Object} opts sync options
   * @param {Object|String} opts.mongooseDoc a document or an id of it to be synced
   */
  sync: function (opts) {
    var self = this
    var evName = opts.evName

    var doc
    var id

    if (opts.mongooseDoc.toObject) {
      doc = opts.mongooseDoc.toObject()
      id = doc._id
    } else {
      id = opts.mongooseDoc
    }
    var cQindex = this.getIndexById(id) // index of current doc in the query

    if (evName === 'remove' && this.docs[cQindex]) {
      this.docs.splice(cQindex, 1)
      this._distributeChange(doc || id.toString(), evName, cQindex)

      if (this.indexedByMethods.limit) {
        var skip = 0
        if (this.indexedByMethods.skip) {
          skip = this.indexedByMethods.skip[0]
        }
        skip += this.indexedByMethods.limit[0] - 1
        opts.model.find(this.mQuery).lean().skip(skip).limit(1)
          .exec(function (err, docArr) {
            if (err) {
              throw err
            }
            if (docArr.length === 1) {
              var toFillIn = docArr[0]   // first and only document
              if (toFillIn) {
                self.docs.push(toFillIn)
                self._distributeChange(toFillIn, 'add', cQindex)
              }
            }
          }
        )
      } else if (this.indexedByMethods.findOne) {
        this.mQuery.exec(function (err, doc) {
          if (err) {
            throw err
          }
          if (doc) {
            self.docs.push(doc)
            self._distributeChange(doc, 'add', cQindex)
          }
        })
      }
    } else {
      var checkQuery = opts.model.findOne(this.mQuery)
      debug('After ' + evName + ' checking ' + id + ' in a query ' + self.qKey)
      if (!this.indexedByMethods.findOne) {
        checkQuery = checkQuery.where('_id').equals(id)
        if (doc) {
          checkQuery.select('_id')
        }
      }
      checkQuery.exec(function (err, checkedDoc) {
        if (err) {
          throw err
        }
        if (checkedDoc) {   // doc satisfies the query

          if (!doc) {	// this is needed for event which don't get a mongoose object passed at the beginning
            doc = checkedDoc
          }

          if (self.indexedByMethods.populate.length !== 0) {    // needs to populate before send
            doc = checkedDoc
          }
          if (self.indexedByMethods.findOne) {
            self.docs[0] = checkedDoc
            return self._distributeChange(checkedDoc, 'add', 0)
          }
          if (self.indexedByMethods.sort) {
            var sortBy = self.indexedByMethods.sort[0].split(' ')	// check for string is performed on query initialization
            var index
            if (evName === 'create') {
              evName = 'add'
              if (cQindex === -1) {
                index = getIndexInSorted(doc, self.docs, sortBy)
                self.docs.splice(index, 0, doc)
                if (self.indexedByMethods.limit) {
                  if (self.docs.length > self.indexedByMethods.limit[0]) {
                    self.docs.splice(self.docs.length - 1, 1)
                  }
                }
              }
            }
            if (evName === 'update') {
              index = getIndexInSorted(doc, self.docs, sortBy)

              if (cQindex === -1) {
                self.docs.splice(index, 0, doc)    // insert the document
              } else {
                if (cQindex !== index) {
                  if (cQindex < index) {  // if we remove item before, the whole array shifts, so we have to compensate index by 1.
                    self.docs.splice(cQindex, 1)
                    self.docs.splice(index - 1, 0, doc)
                  } else {
                    self.docs.splice(cQindex, 1)
                    self.docs.splice(index, 0, doc)
                  }
                } else {
                  self.docs[index] = doc
                }
              }
            }
            self._distributeChange(doc, evName, index)
          } else {
            if (evName === 'create') {
              self.docs.push(doc)
              self._distributeChange(doc, 'add', cQindex)
            }
            if (evName === 'update') {
              var newIndex = self.docs.push(doc)
              self._distributeChange(doc, evName, newIndex)	// doc wasn't in the result, but after update is
            }
          }
        } else {
          debug('Checked doc ' + id + ' in a query ' + self.qKey + ' was not found')
          if (evName === 'update' && cQindex !== -1) {
            self.docs.splice(cQindex, 1)
            self._distributeChange(doc || id, evName, cQindex)		// doc was in the result, but after update is no longer
          }
        }
      })
    }
  }
}

module.exports = LiveQuery
<commit_msg>fix: when document no longer in query, it now correctly propagates the removal<commit_after>'use strict'
const getIndexInSorted = require('./indexInSortedArray')
const populateWithClientQuery = require('./populate-doc-util')
const liveQueriesMap = require('./live-queries-map')  // mapped by the query stringified
const debug = require('debug')('moonridge:live-query')
var _ = require('lodash')

/**
 * @param {String} qKey
 * @param {Mongoose.Query} mQuery
 * @param {Object} queryMethodsHandledByMoonridge are query methods which are important for branching in the LQ
 *                  syncing logic, we need their arguments accessible on separated object to be able to run
 *                  liveQuerying effectively
 * @returns {Object}
 * @constructor
 * @param {Object} model
 */
function LiveQuery (qKey, mQuery, queryMethodsHandledByMoonridge, model) {
  this.docs = []
  this.listeners = {}
  this.mQuery = mQuery   // mongoose query

  if (this.mQuery.op === 'distinct') {
    this.sync = LiveQuery.prototype.syncDistinct
  }

  this.qKey = qKey
  this.model = model
  this.modelName = model.modelName
  this.indexedByMethods = queryMethodsHandledByMoonridge // serializable client query object
  liveQueriesMap.get(this.model)[qKey] = this

  return this
}

LiveQuery.prototype = {
  destroy: function () {
    delete liveQueriesMap.get(this.model)[this.qKey]
  },
  /**
   *
   * @param {Document.Id} id
   * @returns {Number} -1 when not found
   */
  getIndexById: function (id) {
    id = id.id
    var i = this.docs.length
    while (i--) {
      var doc = this.docs[i]
      if (doc && doc._id.id === id) {
        return i
      }
    }
    return i
  },
  /**
   *
   * @param {Object|Mongoose.Document} doc
   * @param {String} evName
   * @param {Number} resultIndex number, indicates an index where the doc should be inserted, -1 for a document which
   *                 is no longer in the result of the query
   */
  _distributeChange: function (doc, evName, resultIndex) {
    var self = this
    var actuallySend = function () {
      for (var socketId in self.listeners) {
        var listener = self.listeners[socketId]
        var toSend = null

        if (listener.qOpts.count) {
          // we don't need to send a doc when query is a count query
        } else if (self.mQuery.op === 'distinct') {
          toSend = doc
        } else {
          if (evName === 'remove' && doc._id) {
            toSend = doc._id.toString() // remove needs only _id, which should be always defined
          } else {
            toSend = self.model.moonridgeOpts.dataTransform(doc, 'R', listener.socket)
          }
        }

        debug('sending ', toSend, ' event ', evName, ', pos param ', resultIndex)
        listener.socket.rpc('MR.' + self.modelName + '.' + evName)(listener.clIndex, toSend, resultIndex)
      }
    }

    if (typeof doc.populate === 'function') {
      populateWithClientQuery(doc, this.indexedByMethods.populate, function (err, populated) {
        if (err) {
          throw err
        }
        doc = populated.toObject()
        actuallySend()
      })
    } else {
      actuallySend()
    }
  },
  registerListener: function (opts) {
    const socket = opts.socket
    debug(`listener ${socket.id} registered`)
    this.listeners[socket.id] = opts
  },
  /**
   * removes a socket listener from liveQuery and also destroys the whole liveQuery if no more listeners are present
   * @param socket
   */
  removeListener: function (socket) {
    if (this.listeners[socket.id]) {
      delete this.listeners[socket.id]
      if (Object.keys(this.listeners).length === 0) {
        this.destroy() // this will delete a liveQuery from liveQueries
      }
    } else {
      return new Error('no listener present on LQ ' + this.qKey)
    }
  },
  syncDistinct: function (opts) {
    var self = this

    return this.mQuery.exec(function (err, values) {
      if (err) {
        console.error('err', err)
        throw err
      }
      var syncObj = {}
      syncObj.add = _.difference(values, self.values)
      syncObj.remove = _.difference(self.values, values)
      self.values = values
      debug('reran distinct query with a result: ', values, syncObj)
      self._distributeChange(syncObj, 'distinctSync')
    })
  },
  /**
   * @param {Object} opts sync options
   * @param {Object|String} opts.mongooseDoc a document or an id of it to be synced
   */
  sync: function (opts) {
    var self = this
    var evName = opts.evName

    var doc
    var id

    if (opts.mongooseDoc.toObject) {
      doc = opts.mongooseDoc.toObject()
      id = doc._id
    } else {
      id = opts.mongooseDoc
    }
    var cQindex = this.getIndexById(id) // index of current doc in the query

    if (evName === 'remove' && this.docs[cQindex]) {
      this.docs.splice(cQindex, 1)
      this._distributeChange(doc || id.toString(), evName, cQindex)

      if (this.indexedByMethods.limit) {
        var skip = 0
        if (this.indexedByMethods.skip) {
          skip = this.indexedByMethods.skip[0]
        }
        skip += this.indexedByMethods.limit[0] - 1
        opts.model.find(this.mQuery).lean().skip(skip).limit(1)
          .exec(function (err, docArr) {
            if (err) {
              throw err
            }
            if (docArr.length === 1) {
              var toFillIn = docArr[0]   // first and only document
              if (toFillIn) {
                self.docs.push(toFillIn)
                self._distributeChange(toFillIn, 'add', cQindex)
              }
            }
          }
        )
      } else if (this.indexedByMethods.findOne) {
        this.mQuery.exec(function (err, doc) {
          if (err) {
            throw err
          }
          if (doc) {
            self.docs.push(doc)
            self._distributeChange(doc, 'add', cQindex)
          }
        })
      }
    } else {
      var checkQuery = opts.model.findOne(this.mQuery)
      debug('After ' + evName + ' checking ' + id + ' in a query ' + self.qKey)
      if (!this.indexedByMethods.findOne) {
        checkQuery = checkQuery.where('_id').equals(id)
        if (doc) {
          checkQuery.select('_id')
        }
      }
      checkQuery.exec(function (err, checkedDoc) {
        if (err) {
          throw err
        }
        if (checkedDoc) {   // doc satisfies the query

          if (!doc) { // this is needed for event which don't get a mongoose object passed at the beginning
            doc = checkedDoc
          }

          if (self.indexedByMethods.populate.length !== 0) {    // needs to populate before send
            doc = checkedDoc
          }
          if (self.indexedByMethods.findOne) {
            self.docs[0] = checkedDoc
            return self._distributeChange(checkedDoc, 'add', 0)
          }
          if (self.indexedByMethods.sort) {
            var sortBy = self.indexedByMethods.sort[0].split(' ') // check for string is performed on query initialization
            var index
            if (evName === 'create') {
              evName = 'add'
              if (cQindex === -1) {
                index = getIndexInSorted(doc, self.docs, sortBy)
                self.docs.splice(index, 0, doc)
                if (self.indexedByMethods.limit) {
                  if (self.docs.length > self.indexedByMethods.limit[0]) {
                    self.docs.splice(self.docs.length - 1, 1)
                  }
                }
              }
            }
            if (evName === 'update') {
              index = getIndexInSorted(doc, self.docs, sortBy)

              if (cQindex === -1) {
                self.docs.splice(index, 0, doc)    // insert the document
              } else {
                if (cQindex !== index) {
                  if (cQindex < index) {  // if we remove item before, the whole array shifts, so we have to compensate index by 1.
                    self.docs.splice(cQindex, 1)
                    self.docs.splice(index - 1, 0, doc)
                  } else {
                    self.docs.splice(cQindex, 1)
                    self.docs.splice(index, 0, doc)
                  }
                } else {
                  self.docs[index] = doc
                }
              }
            }
            self._distributeChange(doc, evName, index)
          } else {
            if (evName === 'create') {
              self.docs.push(doc)
              self._distributeChange(doc, 'add', cQindex)
            }
            if (evName === 'update') {
              var newIndex = self.docs.push(doc)
              self._distributeChange(doc, evName, newIndex) // doc wasn't in the result, but after update is
            }
          }
        } else {
          debug('Checked doc ' + id + ' in a query ' + self.qKey + ' was not found')
          if (evName === 'update' && cQindex !== -1) {
            self.docs.splice(cQindex, 1)
            self._distributeChange(doc || id, evName, -1)   // doc was in the result, but after update is no longer
          }
        }
      })
    }
  }
}

module.exports = LiveQuery
<|endoftext|>